BlinkenArea - GitList
Repositories
Blog
Wiki
flaneth
Code
Commits
Branches
Tags
Search
Tree:
e8658d5
Branches
Tags
master
flaneth
firmware.dartboard
cf.c
initial commit after making CF identify work
Stefan Schuermans
commited
e8658d5
at 2012-04-15 19:57:57
cf.c
Blame
History
Raw
/* flaneth - flash and ethernet - dartboard mod * version 0.1 date 2008-11-09 * Copyright (C) 2007-2008 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 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 extern inline char CfWriteRegBuf( 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_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" ); // 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; } // set reset CF_RESET_ACT( ); CfInsState = CfInsReset; break; // resetting new compact flash case CfInsReset: // take back reset CF_RESET_IDLE( ); // if compact flash has been removed, set state to none if( ! CF_IS_DETECT( ) ) { CfInsState = CfInsNone; break; } 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; debug_cf_printf( "CF ready" ); } 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 + 1] << 16 | (unsigned long)CfSectorBuffer[CF_ID_OFS_SEC_CNT_32 + 1] << 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_clear( CF_PORT_nRST, CF_BIT_nRST ); // reset pin to LOW 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 enable to LOW 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 }