BlinkenArea - GitList
Repositories
Blog
Wiki
flaneth
Code
Commits
Branches
Tags
Search
Tree:
d48e86e
Branches
Tags
master
flaneth
firmware
cf.c
header fix
Stefan Schuermans
commited
d48e86e
at 2012-05-02 18:39:39
cf.c
Blame
History
Raw
/* flaneth - flash and ethernet Copyright (C) 2007-2012 Stefan Schuermans <stefan@schuermans.info> Copyleft: GNU public license V2 - http://www.gnu.org/copyleft/gpl.html a BlinkenArea project - http://www.blinkenarea.org/ */ #include <avr/io.h> #include "bus.h" #include "cf.h" #include "config.h" #include "debug.h" #include "macros.h" #include "status.h" #include "timing.h" // IO pins of compact flash #define CF_DDR_nCD (DDRB) #define CF_PORT_nCD (PORTB) #define CF_PIN_nCD (PINB) #define CF_BIT_nCD (4) #define CF_DDR_nRST (DDRB) #define CF_PORT_nRST (PORTB) #define CF_BIT_nRST (5) #define CF_DDR_RDY (DDRB) #define CF_PORT_RDY (PORTB) #define CF_PIN_RDY (PINB) #define CF_BIT_RDY (7) #define CF_DDR_nCE (DDRB) #define CF_PORT_nCE (PORTB) #define CF_BIT_nCE (6) // special pin commands #define CF_IS_DETECT() (is_bit_clear(CF_PIN_nCD, CF_BIT_nCD)) #define CF_RESET_ACT() (bit_clear(CF_PORT_nRST, CF_BIT_nRST)) #define CF_RESET_IDLE() (bit_set(CF_PORT_nRST, CF_BIT_nRST)) #define CF_IS_READY() (is_bit_set(CF_PIN_RDY, CF_BIT_RDY)) #define CF_CE_ACT() (bit_clear(CF_PORT_nCE, CF_BIT_nCE)) #define CF_CE_IDLE() (bit_set(CF_PORT_nCE, CF_BIT_nCE)) // compact flash registers #define CF_REG_DATA (0x00) #define CF_REG_ERR (0x01) #define CF_REG_SEC_CNT (0x02) #define CF_REG_SEC_NO (0x03) #define CF_REG_CYL_L (0x04) #define CF_REG_CYL_H (0x05) #define CF_REG_HEAD (0x06) #define CF_REG_STATUS (0x07) #define CF_REG_CMD (0x07) // compact flash status bits #define CF_SB_BUSY (7) #define CF_SB_RDY (6) #define CF_SB_DWF (5) #define CF_SB_DSC (4) #define CF_SB_DRQ (3) #define CF_SB_CORR (2) #define CF_SB_IDX (1) #define CF_SB_ERR (0) // compact flash commands #define CF_CMD_IDENTIFY (0xEC) #define CF_CMD_READ_SEC (0x20) #define CF_CMD_WRITE_SEC (0x30) // some number of bytes #define CF_BYTES_AT_ONCE (32) // number of bytes to read/write at once #define CF_BYTES_IDENTIFY (124) // number of bytes to read for identify // interesting locations in identify data #define CF_ID_OFS_ID_16 (0) // CF identifier, 16 bit #define CF_ID_OFS_CAPA_16 (98) // CF capabilities, 16 bit #define CF_ID_OFS_SEC_CNT_32 (120) // number of sectors on CF (in LBA // mode), 32 bit // various CF constants #define CF_ID (0x848A) // identifier of compact flash cards #define CF_CAPA_BIT_LBA (9) // bit number of the LBA bit in the CF // capabilities // timeout value for wait for ready after reset counter (in 20ms steps) #define CF_WAIT_READY_RESET_20_TIMEOUT (50) // 1s // timeout value for wait for ready counter (in 20ms steps) #define CF_WAIT_READY_20_TIMEOUT (4) // 80ms // compact flash insertion state enum CfInsertionState { CfInsNone, // no compact flash inserted CfInsNew, // new compact flash has been inserted, wait for powerup CfInsReset, // resetting new compact flash CfInsWait, // waiting for new compact flash to get ready after reset CfInsReady, // compact flash inserted and ready to work with CfInsError, // compact flash error occured, compact flash deactivated } CfInsState = CfInsNone; // compact flash working state enum CfWorkingState { CfWorkNone, // no compact flash work to do CfWorkIdentify, // identification of compact flash active } CfWorkState = CfWorkNone; // compact flash working step enum CfWorkingStep { CfStepNone, // no step in progress CfStepCmdStatus, // checking command status CfStepDataTransfer, // transferring (reading/writing) data CfStepDataStatus, // checking data status } CfWorkStep = CfStepNone; // number of sectors on compact flash card // - zero if no CF card is present, CF card has not yet been identified or CF // card error occured unsigned long CfSectorCnt = 0; // state of active command unsigned long CfSectorNo = 0; // current sector number of compact flash unsigned short CfNextOffset = 0; // next offset in sector that is // processed (read, written, ...) // wait for ready counter of compact flash // - counts down in 20ms steps // - zero if inactive unsigned char CfWaitReady20 = 0; // sector buffer unsigned char CfSectorBuffer[CF_SECTOR_SIZE]; // (extern) // write a compact flash register (returns 1 if successful or 0 on error) // - returns 0 on success and -1 on error extern inline char CfWriteReg(unsigned char reg, unsigned char val) // force // inlining // by // using // "extern" { if (!CF_IS_DETECT() || !CF_IS_READY()) // check that card is present // and ready return -1; // error BUS_DATA = val; // output value BUS_DATA_DDR = 0xFF; // data port to output BUS_ADDR = reg; // output address CF_CE_ACT(); // set card enable BUS_WRITE_ACT(); // activate write signal nop(); nop(); nop(); nop(); nop(); nop(); BUS_WRITE_IDLE(); // take back write signal CF_CE_IDLE(); // take back card enable BUS_DATA_DDR = 0x00; // data back port to input BUS_DATA = 0x00; // turn off pullups return 0; // success } // write buffer to compact flash register // (returns 1 if successful or 0 on error) // - returns 0 on success and -1 on error // - force inlining by using "extern" extern inline char CfWriteRegBuf(unsigned char reg, unsigned char *p_buf, unsigned short len) { if (!CF_IS_DETECT() || !CF_IS_READY()) // check that card is present // and ready return -1; // error BUS_DATA = *p_buf; // output first value to initialize port status // before switching to output BUS_DATA_DDR = 0xFF; // data port to output BUS_ADDR = reg; // output address CF_CE_ACT(); // set card enable for (; len > 0; p_buf++, len--) { if (!CF_IS_DETECT() || !CF_IS_READY()) // check that card is present // and ready break; BUS_DATA = *p_buf; // output value BUS_WRITE_ACT(); // activate write signal nop(); nop(); nop(); nop(); nop(); nop(); BUS_WRITE_IDLE(); // take back write signal } CF_CE_IDLE(); // take back card enable BUS_DATA_DDR = 0x00; // data back port to input BUS_DATA = 0x00; // turn off pullups return len <= 0 ? 0 : -1; // success if everything has been written } // write constant value to compact flash register multiple times (returns 1 // if successful or 0 on error) // - returns 0 on success and -1 on error extern inline char CfWriteRegConst(unsigned char reg, unsigned char val, unsigned short cnt) // force // inlining // by // using // "extern" { if (!CF_IS_DETECT() || !CF_IS_READY()) // check that card is present // and ready return -1; // error BUS_DATA = val; // output value BUS_DATA_DDR = 0xFF; // data port to output BUS_ADDR = reg; // output address CF_CE_ACT(); // set card enable for (; cnt > 0; cnt--) { if (!CF_IS_DETECT() || !CF_IS_READY()) // check that card is present // and ready break; BUS_WRITE_ACT(); // activate write signal nop(); nop(); nop(); nop(); nop(); nop(); BUS_WRITE_IDLE(); // take back write signal } CF_CE_IDLE(); // take back card enable BUS_DATA_DDR = 0x00; // data back port to input BUS_DATA = 0x00; // turn off pullups return cnt <= 0 ? 0 : -1; // success if everything has been written } // read a compact flash register (returns 1 if successful or 0 on error) // - returns 0 on success and -1 on error extern inline char CfReadReg(unsigned char reg, unsigned char *p_var) // force // inlining // by // using // "extern" { if (!CF_IS_DETECT() || !CF_IS_READY()) // check that card is present // and ready return -1; // error BUS_ADDR = reg; // output address CF_CE_ACT(); // set card enable BUS_READ_ACT(); // activate read signal nop(); nop(); nop(); nop(); nop(); nop(); *p_var = BUS_DATA_IN; // read data BUS_READ_IDLE(); // take back read signal CF_CE_IDLE(); // take back card enable return 0; // success } // read buffer from a compact flash register (returns 1 if successful or 0 on // error) // - returns 0 on success and -1 on error extern inline char CfReadRegBuf(unsigned char reg, unsigned char *p_buf, unsigned short len) // force // inlining // by // using // "extern" { if (!CF_IS_DETECT() || !CF_IS_READY()) // check that card is present // and ready return -1; // error BUS_ADDR = reg; // output address CF_CE_ACT(); // set card enable for (; len > 0; p_buf++, len--) { if (!CF_IS_DETECT() || !CF_IS_READY()) // check that card is present // and ready break; BUS_READ_ACT(); // activate read signal nop(); nop(); nop(); nop(); nop(); nop(); *p_buf = BUS_DATA_IN; // read data BUS_READ_IDLE(); // take back read signal } CF_CE_IDLE(); // take back card enable return len <= 0 ? 0 : -1; // success if everything has been read } // read a compact flash register multiple times and throw away data (returns // 1 if successful or 0 on error) // - returns 0 on success and -1 on error extern inline char CfReadRegMulti(unsigned char reg, unsigned short cnt) // force // inlining // by // using // "extern" { if (!CF_IS_DETECT() || !CF_IS_READY()) // check that card is present // and ready return -1; // error BUS_ADDR = reg; // output address CF_CE_ACT(); // set card enable for (; cnt > 0; cnt--) { if (!CF_IS_DETECT() || !CF_IS_READY()) // check that card is present // and ready break; BUS_READ_ACT(); // activate read signal nop(); nop(); nop(); nop(); nop(); nop(); BUS_READ_IDLE(); // take back read signal } CF_CE_IDLE(); // take back card enable return cnt <= 0 ? 0 : -1; // success if everything has been read } // compact flash work done static void CfDone(void) { debug_cf_printf("CF done (%lu sectors)", CfSectorCnt); // set working state and step to none CfWorkState = CfWorkNone; CfWorkStep = CfStepNone; // reset state of active command CfSectorNo = 0; CfNextOffset = 0; // disable wait for ready counter CfWaitReady20 = 0; } // compact flash error occured static void CfError(void) { debug_cf_printf("CF error"); // set insertion state to error CfInsState = CfInsError; // set working state and step to none CfWorkState = CfWorkNone; CfWorkStep = CfStepNone; // reset all information about CF card CfSectorCnt = 0; // reset state of active command CfSectorNo = 0; CfNextOffset = 0; // disable wait for ready counter CfWaitReady20 = 0; } // process compact flash insertion static void CfProcIns(void) { switch (CfInsState) { // no compact flash inserted case CfInsNone: // if compact flash is detected, set state to new CF if (CF_IS_DETECT()) { CfInsState = CfInsNew; debug_cf_printf("new CF"); break; } break; // new compact flash has been inserted, wait for powerup case CfInsNew: // if compact flash has been removed, set state to none if (!CF_IS_DETECT()) { CfInsState = CfInsNone; break; } CfInsState = CfInsReset; break; // resetting new compact flash case CfInsReset: // set reset, wait, take back reset CF_RESET_ACT(); nop(); nop(); nop(); CF_RESET_IDLE(); debug_cf_printf("CF reset"); // if compact flash has been removed, set state to none if (!CF_IS_DETECT()) { CfInsState = CfInsNone; break; } // wait for CF to become ready CfInsState = CfInsWait; CfWaitReady20 = CF_WAIT_READY_RESET_20_TIMEOUT; break; // waiting for new compact flash to get ready after reset case CfInsWait: // if compact flash has been removed, set state to none if (!CF_IS_DETECT()) { CfInsState = CfInsNone; break; } // if compact flash card is ready, set state to ready if (CF_IS_READY()) { CfInsState = CfInsReady; CfWaitReady20 = 0; debug_cf_printf("CF ready"); break; } // count down timeout CfWaitReady20--; if (CfWaitReady20 <= 0) { debug_cf_printf("timeout waiting for CF ready"); // start over CfInsState = CfInsNone; break; } break; // compact flash inserted and ready to work with case CfInsReady: // do nothing here, card work is done by task procedure // (task will detect CF removal or timeout and set state to error) break; // compact flash error occured, compact flash deactivated case CfInsError: // if compact flash has been removed, set state to none if (!CF_IS_DETECT()) { CfInsState = CfInsNone; debug_cf_printf("CF removed"); } break; } // switch( CfInsState ) } // detect compact flash timeout // - called every 20ms static void CfDetectTimeout20(void) { // only detect CF timeout if insertion state is ready // (otherwise, the insertion processing is still doing some work) if (CfInsState != CfInsReady) return; // wait for ready counter not active if (CfWaitReady20 <= 0) return; // decrement wait for ready counter CfWaitReady20--; // timeout occured if (CfWaitReady20 <= 0) { debug_cf_printf("timeout while waiting for CF ready"); CfError(); } } // continue with identifying compact flash static void CfProcWorkIdentify(void) { unsigned char status = 0; unsigned short len, val16; switch (CfWorkStep) { // no step case CfStepNone: debug_cf_printf("internal error (identify, CfStepNone)"); CfError(); break; // checking command status case CfStepCmdStatus: // read status register CfReadReg(CF_REG_STATUS, &status); // check that BUSY=0, RDY=1, DWF=0, DSC=1, IDX=0, ERR=0 if ((status & (1 << CF_SB_BUSY | 1 << CF_SB_RDY | 1 << CF_SB_DWF | 1 << CF_SB_DSC | 1 << CF_SB_IDX | 1 << CF_SB_ERR)) != (1 << CF_SB_RDY | 1 << CF_SB_DSC)) { debug_cf_printf("unexpected status 0x%02X (identify)", status); CfError(); } // continue with data transfer CfWorkStep = CfStepDataTransfer; CfNextOffset = 0; break; // transferring data case CfStepDataTransfer: // still bytes to read if (CfNextOffset < CF_BYTES_IDENTIFY) { // get number of bytes to read len = CF_BYTES_IDENTIFY - CfNextOffset; if (len > CF_BYTES_AT_ONCE) len = CF_BYTES_AT_ONCE; // read bytes if (CfReadRegBuf(CF_REG_DATA, &CfSectorBuffer[CfNextOffset], len) != 0) { debug_cf_printf ("reading from CF failed (identify, offset 0x%03X, length 0x%02X)", CfNextOffset, len); CfError(); break; } CfNextOffset += len; } // all bytes read if (CfNextOffset >= CF_BYTES_IDENTIFY) { // check identifier val16 = (unsigned short)CfSectorBuffer[CF_ID_OFS_ID_16 + 0] | (unsigned short)CfSectorBuffer[CF_ID_OFS_ID_16 + 1] << 8; if (val16 != CF_ID) { debug_cf_printf("invalid CF identifier: 0x%04X", val16); CfError(); break; } // check if LBA mode is supported val16 = (unsigned short)CfSectorBuffer[CF_ID_OFS_CAPA_16 + 0] | (unsigned short)CfSectorBuffer[CF_ID_OFS_CAPA_16 + 1] << 8; if ((val16 & 1 << CF_CAPA_BIT_LBA) == 0) { debug_cf_printf("CF does not support LBA mode"); CfError(); break; } // get number of sectors on CF CfSectorCnt = (unsigned long)CfSectorBuffer[CF_ID_OFS_SEC_CNT_32 + 0] | (unsigned long)CfSectorBuffer[CF_ID_OFS_SEC_CNT_32 + 1] << 8 | (unsigned long)CfSectorBuffer[CF_ID_OFS_SEC_CNT_32 + 2] << 16 | (unsigned long)CfSectorBuffer[CF_ID_OFS_SEC_CNT_32 + 3] << 24; if (CfSectorCnt <= 0) { debug_cf_printf("CF does not contain any sectors"); CfError(); break; } // done CfDone(); } break; // checking data status case CfStepDataStatus: debug_cf_printf("internal error (identify, CfStepDataStatus)"); CfError(); break; } // switch( CfWorkStep ) } // do normal compact flash work static void CfProcWork(void) { // only do CF processing if insertion state is ready // (otherwise, the insertion processing is still doing some work) if (CfInsState != CfInsReady) return; // compact flash has been removed -> error if (!CF_IS_DETECT()) { debug_cf_printf("CF no more present"); CfError(); return; } // compact flash is not ready if (!CF_IS_READY()) { // wait for ready not active --> error if (CfWaitReady20 <= 0) { debug_cf_printf("CF no more ready"); CfError(); } // do nothing if CF is not ready return; } switch (CfWorkState) { // no compact flash work to do case CfWorkNone: // nothing to do here break; // identification of compact flash active case CfWorkIdentify: CfProcWorkIdentify(); break; } // switch( CfWorkState ) } // identify compact flash // - returns 0 on success, 1 if not idle and -1 on error static char CfIdentify(void) { // check that no command is being worked on if (CfWorkState != CfWorkNone) return 1; debug_cf_printf("CF identify"); // issue identify drive command if (CfWriteReg(CF_REG_CMD, CF_CMD_IDENTIFY) != 0) { CfError(); return -1; } // now identifying compact flash CfWorkState = CfWorkIdentify; CfWorkStep = CfStepCmdStatus; CfNextOffset = 0; CfWaitReady20 = CF_WAIT_READY_20_TIMEOUT; return 0; } // initialize void CfInit(void) // (extern) { // setup ports bit_clear(CF_PORT_nCD, CF_BIT_nCD); // pull-up of card detect pin off // (external pull-up is present) bit_clear(CF_DDR_nCD, CF_BIT_nCD); // card detect pin to input bit_set(CF_PORT_nRST, CF_BIT_nRST); // reset not active bit_set(CF_DDR_nRST, CF_BIT_nRST); // reset pin to output bit_clear(CF_PORT_RDY, CF_BIT_RDY); // pull-up of ready pin pin off // (external pull-up is present) bit_clear(CF_DDR_RDY, CF_BIT_RDY); // ready pin to input bit_set(CF_PORT_nCE, CF_BIT_nCE); // card not enabled bit_set(CF_DDR_nCE, CF_BIT_nCE); // card enable pin to output } // tick procedure - call every 20ms void CfTick20(void) // (extern) { // process compact flash insertion CfProcIns(); // detect compact flash timeout CfDetectTimeout20(); } // task function to do the work - call from main loop void CfTask(void) // (extern) { // do nothing if no CF is inserted if (CfInsState != CfInsReady) return; // compact flash is ready but not yet identified if (CfSectorCnt == 0) { // identify compact flash CfIdentify(); } // do normal compact flash work CfProcWork(); // update status StatusInfoCfPresent = CfInsState == CfInsReady; // report working CF // if insertion state // is ready }