异步状态机代码结构示例:
enum
{
eIDLE = 0,
eSTART,
eWAIT,
eSUCCESS
};
static uint8_t stage = 0;
//启动异步处理
void DoSomethingRequest()
{
if(stage != eIDLE)
{
printf("AsyncMachine is busy!!!,return\n");
return;
}
SomethingReq = TRUE;
}
//异步处理任务
void AsyncMachine()
{
switch(stage)
{
case eIDLE:
if(SomethingReq)
{
stage = eSTART;
printf("A task will be start\n");
}
break;
case eSTART:
do_something();
stage = eWAIT;
printf("do something\n");
break;
case eWAIT:
if(something_state() == OK)
{
stage = eSUCCESS;
}
printf("Wait...\n");
break;
case eSUCCESS:
stage = eIDLE;
printf("task exec success\n");
break;
}
}
通过把阻塞的任务单独分离出来,交给一个状态机子任务来处理。则应用程序只需要调用一个处理请求而无需原地死等,状态机处理完成后,可以异步回调来通知应用程序任务已完成。
下面附上SPI FLASH 同步/异步读写实例。
//SPI状态机状态
typedef enum
{
eFLASH_STATE_IDLE = 0,
eFLASH_STATE_WRITE = 1,
eFLASH_STATE_READ = 2,
eFLASH_STATE_BUSY = 3,
eFLASH_STATE_ERASE_CHIP = 4,
eFLASH_STATE_ERASE = 5,
}FlashState_e;
//SPI设备结构体
typedef struct SpiDevice_s {
SPI_TypeDef *spiHandle;//SPI物理属性
uint8_t *pTxBuffer;//异步发送缓存
uint32_t uTxDstAddr;//异步发送目地地址
uint16_t wTxLen;//异步发送长度
uint16_t wTxOffset; //异步当前缓存已发送偏移
uint8_t *pRxBuffer;
uint32_t uRxSrcAddr;
uint16_t wRxLen;
uint16_t wRxOffset;
void (*pWriteAsyncNotifyCallback)(); //异步写完成回调通知
void (*pEraseChipAsyncNotifyCallback)();//异不擦除回调通知
struct {
FlashState_e eStage;//当前状态机状态
//BOOL bTxBusy:1; //发送忙
BOOL bTxReq:1; //发送请求
BOOL bTxCompleted:1;//发送完成
//BOOL bRxBusy:1; //读忙
BOOL bRxReq:1; //读请求
BOOL bEraseChipReq:1;//擦整片请求
BOOL bEraseSectorReq:1;//擦扇区请求
BOOL bEraseSuccess:1; //擦成功
}tState;
void (*Init)(void);
uint8_t (*EraseChip)(void);//同步擦
void (*Read)(uint8_t* pBuffer,uint32_t uReadAddr,uint16_t wNumByteToRead);//同步读
uint32_t (*WriteByte)(uint8_t Byte, uint32_t uWriteAddr);//同步写字节
uint32_t (*Write)(uint8_t* pBuffer,uint32_t uWriteAddr, uint16_t wNumByteToWrite);//同步写
BOOL (*WriteAsync)(uint8_t* pBuffer,uint32_t uWriteAddr, uint16_t wNumByteToWrite);//异步写
BOOL (*EraseChipAsync)(void);//异步整片擦
BOOL (*EraseAsync)(uint32_t uAddr, uint16_t wlen);//奶步擦
void (*WriteAsyncNotifyCallbackRegister)(void* pfn);//异步写完成回调注册
void (*EraseChipAsyncNotifyCallbackRegister)(void *pfn);//异步擦完成回调注册
}SpiDevice_t;
实例化
SpiDevice_t g_tSpiDevice =
{
SPI2,
g_aTxBuffer,
0,0,0,
g_aRxBuffer,
0,0,0,
0,0,
{0,0},
Spi_Init,
SPI_Flash_Erase_Chip, //ͬ²½ÕûƬ²Á
SPI_Flash_Read, //ͬ²½¶Á
SPI_Flash_WriteByte, //ͬ²½Ð´×Ö½Ú
SPI_Flash_Write, //ͬ²½Ð´
SPI_FlashWriteAsync, //Ò첽д
SPI_FlashEraseChipAsync, //Òì²½ÕûƬ²Á³ý
SPI_FlashEraseAsync,
SPI_WriteAsyncNotifyCallbackRegister,//д״̬Ò첽֪ͨ»Øµ÷
SPI_EraseChipAsyncNotifyCallbackRegister,//²Á³ý״̬Ò첽֪ͨ»Øµ÷
};
//SPI同步操作
/*****************
²Á³ýÒ»¸öÉÈÇø
0~511
******************/
unsigned char SPI_Flash_Erase_Sector(unsigned int Dst_Addr)
{
unsigned char cnt=0;
SPI_FLASH_Write_Enable(); //SET WEL
while((SPI_Flash_Read_SR()&0x2)!=0x2)
{
cnt ++;
if(cnt >200)
return FALSE;
}
SPI_CS_LOW();
SPI_Flash_ReadWrite_Byte(SECTOR_ERASE);
SPI_Flash_ReadWrite_Byte((unsigned char)((Dst_Addr)>>16));
SPI_Flash_ReadWrite_Byte((unsigned char)((Dst_Addr)>>8));
SPI_Flash_ReadWrite_Byte((unsigned char)Dst_Addr);
SPI_CS_HIGH();
SPI_Flash_Wait_Busy();
return TRUE;
}
/*64K Flash¿Õ¼ä²Á³ý*/
unsigned char SPI_Flash_Erase_64k(unsigned int Dst_Addr)
{
unsigned char cnt=0;
SPI_FLASH_Write_Enable(); //SET WEL
while((SPI_Flash_Read_SR()&0x2)!=0x2)
{
cnt ++;
if(cnt >200)
return FALSE;
}
SPI_CS_LOW();
SPI_Flash_ReadWrite_Byte(BLOCK_ERASE_64K);
SPI_Flash_ReadWrite_Byte((unsigned char)((Dst_Addr)>>16));
SPI_Flash_ReadWrite_Byte((unsigned char)((Dst_Addr)>>8));
SPI_Flash_ReadWrite_Byte((unsigned char)Dst_Addr);
SPI_CS_HIGH();
SPI_Flash_Wait_Busy();
return TRUE;
}
/*²Á³ýоƬ*/
unsigned char SPI_Flash_Erase_Chip(void)
{
unsigned char cnt=0;
SPI_FLASH_Write_Enable(); //SET WEL
while((SPI_Flash_Read_SR()&0x2)!=0x2)
{
cnt ++;
if(cnt >200)
return FALSE;
}
SPI_CS_LOW();
SPI_Flash_ReadWrite_Byte(CHIP_ERASE);
SPI_CS_HIGH();
SPI_Flash_Wait_Busy();
return TRUE;
}
/*Ö¸¶¨µØÖ·¶ÁÈ¡Ö¸¶¨³¤¶ÈÊý¾Ý*/
void SPI_Flash_Read(unsigned char* pBuffer,unsigned int ReadAddr,unsigned short int NumByteToRead)
{
unsigned short int index;
SPI_CS_LOW();
SPI_Flash_ReadWrite_Byte(READ_DATA);
/*¸³ÖµµØÖ·*/
SPI_Flash_ReadWrite_Byte((unsigned char)((ReadAddr)>>16));
SPI_Flash_ReadWrite_Byte((unsigned char)((ReadAddr)>>8));
SPI_Flash_ReadWrite_Byte((unsigned char)ReadAddr);
for(index=0;index200)
return FALSE; /*·µ»Øдʧ°Ü*/
}
SPI_CS_LOW();
SPI_Flash_ReadWrite_Byte(PAGE_PRG);
SPI_Flash_ReadWrite_Byte((unsigned char)((WriteAddr)>>16));
SPI_Flash_ReadWrite_Byte((unsigned char)((WriteAddr)>>8));
SPI_Flash_ReadWrite_Byte((unsigned char)WriteAddr);
SPI_Flash_ReadWrite_Byte(Byte);
SPI_CS_HIGH();
SPI_Flash_Wait_Busy();
return TRUE;
}
uint32_t SPI_Flash_Write(unsigned char* pBuffer,unsigned int WriteAddr,unsigned short int NumByteToWrite)
{
unsigned short int pageoffset=PAGE_SIZE-(WriteAddr%PAGE_SIZE); /*¼ÆËã¸ÃÒ³Öл¹ÓжàÉÙÊ£Óà¿Õ¼ä*/
unsigned char cnt=0;
unsigned short int index;
unsigned int pagenum =WriteAddr/PAGE_SIZE; /*±¾´ÎдÈëµÄÒ³Êý*/
unsigned int Addr;
if(pageoffset >= NumByteToWrite) //Ê£Óà¿Õ¼ä´óÓÚҪдµÄÊýÁ¿
{
SPI_FLASH_Write_Enable(); //SET WEL
while((SPI_Flash_Read_SR()&0x2)!=0x2)
{
cnt ++;
if(cnt >200)
return FALSE; /*·µ»Øдʧ°Ü*/
}
SPI_CS_LOW();
SPI_Flash_ReadWrite_Byte(PAGE_PRG);
SPI_Flash_ReadWrite_Byte((unsigned char)((WriteAddr)>>16));
SPI_Flash_ReadWrite_Byte((unsigned char)((WriteAddr)>>8));
SPI_Flash_ReadWrite_Byte((unsigned char)WriteAddr);
for(index=0; index200)
return FALSE; /*·µ»Øдʧ°Ü*/
}
SPI_CS_LOW();
SPI_Flash_ReadWrite_Byte(PAGE_PRG);
SPI_Flash_ReadWrite_Byte((unsigned char)((WriteAddr)>>16));
SPI_Flash_ReadWrite_Byte((unsigned char)((WriteAddr)>>8));
SPI_Flash_ReadWrite_Byte((unsigned char)WriteAddr);
for(index=0; index0)
{
if(NumByteToWrite > PAGE_SIZE) //ÈÔÈ»´óÓÚÒ»Ò³
{
SPI_FLASH_Write_Enable(); //SET WEL
while((SPI_Flash_Read_SR()&0x2)!=0x2)
{
cnt ++;
if(cnt >200)
return FALSE; /*·µ»Øдʧ°Ü*/
}
SPI_CS_LOW();
SPI_Flash_ReadWrite_Byte(PAGE_PRG);
SPI_Flash_ReadWrite_Byte((unsigned char)((Addr)>>16));
SPI_Flash_ReadWrite_Byte((unsigned char)((Addr)>>8));
SPI_Flash_ReadWrite_Byte((unsigned char)Addr);
for(index=0; index200)
return FALSE; /*·µ»Øдʧ°Ü*/
}
SPI_CS_LOW();
SPI_Flash_ReadWrite_Byte(PAGE_PRG);
SPI_Flash_ReadWrite_Byte((unsigned char)((Addr)>>16));
SPI_Flash_ReadWrite_Byte((unsigned char)((Addr)>>8));
SPI_Flash_ReadWrite_Byte((unsigned char)Addr);
for(index=0; indexSPI异步操作
*************************************************************************************************/
/*****************************************************************************************
º¯ÊýÃû³Æ:SPI_FlashWriteAsync异步写请求
º¯ÊýÃèÊö:Ò첽д
ÊäÈë²ÎÊý:
Êä³ö²ÎÊý:
º¯Êý·µ»Ø:
******************************************************************************************/
BOOL SPI_FlashWriteAsync(uint8_t* pBuffer,uint32_t uWriteAddr, uint16_t wNumByteToWrite)
{
if(wNumByteToWrite > FLASH_TX_BUFFER_SIZE)
{
return FALSE;
}
if(g_tSpiDevice.tState.eStage != eFLASH_STATE_IDLE)
{
Debug(eDBUG_LEVEL_ERROR,"[%d]Flash_Write:busy,return\r\n", GetTicks());
return FALSE;
}
memcpy(g_tSpiDevice.pTxBuffer, pBuffer, wNumByteToWrite);
g_tSpiDevice.wTxLen = wNumByteToWrite;
g_tSpiDevice.uTxDstAddr = uWriteAddr;
g_tSpiDevice.wTxOffset = 0;
g_tSpiDevice.tState.bTxReq = TRUE; //请求标志
g_tSpiDevice.tState.bTxCompleted = FALSE;
//g_tSpiDevice.tState.bTxBusy = TRUE;
return TRUE;
}
/*****************************************************************************************
º¯ÊýÃû³Æ:SPI_FlashWriteAsync
º¯ÊýÃèÊö:Òì²½²ÁÕûƬ
ÊäÈë²ÎÊý:
Êä³ö²ÎÊý:
º¯Êý·µ»Ø:
******************************************************************************************/
BOOL SPI_FlashEraseChipAsync(void)
{
//unsigned char cnt=0;
if(g_tSpiDevice.tState.eStage != eFLASH_STATE_IDLE)
{
Debug(eDBUG_LEVEL_ERROR,"[%d]Flash_earse:busy,return\r\n", GetTicks());
return FALSE;
}
g_tSpiDevice.tState.bEraseChipReq = TRUE;
return TRUE;
}
/*****************************************************************************************
º¯ÊýÃû³Æ:异步擦除
º¯ÊýÃèÊö:Òì²½²ÁÖ¸¶¨µØÖ·
ÊäÈë²ÎÊý:
Êä³ö²ÎÊý:
º¯Êý·µ»Ø:
******************************************************************************************/
BOOL SPI_FlashEraseAsync(uint32_t uAddr, uint16_t wlen)
{
//unsigned char cnt=0;
if(g_tSpiDevice.tState.eStage != eFLASH_STATE_IDLE)
{
Debug(eDBUG_LEVEL_ERROR,"[%d]Flash_earse:busy,return\r\n", GetTicks());
return FALSE;
}
g_tSpiDevice.wTxLen = wlen;
g_tSpiDevice.uTxDstAddr = uAddr;
g_tSpiDevice.wTxOffset = 0;
g_tSpiDevice.tState.bEraseSectorReq = TRUE;
return TRUE;
}
//注册完成通知
void SPI_WriteAsyncNotifyCallbackRegister(void *pfn)
{
g_tSpiDevice.pWriteAsyncNotifyCallback = (void (*)())pfn;
}
void SPI_EraseChipAsyncNotifyCallbackRegister(void *pfn)
{
g_tSpiDevice.pEraseChipAsyncNotifyCallback = (void (*)())pfn;
}
//ÅжÏSPI FLASH æ
static BOOL SPI_FlashBusyCheck(void)
{
if((SPI_Flash_Read_SR()&0x01)==0x01)
{
return TRUE;
}
else
{
return FALSE;
}
}
//дһҳ
static BOOL __SPI_FlashWritePage(uint32_t uWriteAddr, uint8_t *pData, uint16_t wWriteLen)
{
uint8_t cnt;
uint16_t index;
SPI_FLASH_Write_Enable(); //SET WEL
while((SPI_Flash_Read_SR()&0x2)!=0x2)
{
cnt ++;
if(cnt >200)
return FALSE; /*·µ»Øдʧ°Ü*/
}
SPI_CS_LOW();
SPI_Flash_ReadWrite_Byte(PAGE_PRG);
SPI_Flash_ReadWrite_Byte((unsigned char)((uWriteAddr)>>16));
SPI_Flash_ReadWrite_Byte((unsigned char)((uWriteAddr)>>8));
SPI_Flash_ReadWrite_Byte((unsigned char)uWriteAddr);
for(index=0; index < wWriteLen; index++)
{
SPI_Flash_ReadWrite_Byte(*(pData+index));
}
SPI_CS_HIGH();
return TRUE;
}
//Ò첽д´¦Àí×ÓÈÎÎñ
static int32_t __SPI_FlashWrite(void)
{
uint16_t wWriteRemainNum = g_tSpiDevice.wTxLen - g_tSpiDevice.wTxOffset;
uint8_t *pData = g_tSpiDevice.pTxBuffer + g_tSpiDevice.wTxOffset;
uint32_t uWriteAddr = g_tSpiDevice.uTxDstAddr + g_tSpiDevice.wTxOffset;
uint16_t wPageRemain = PAGE_SIZE - (uWriteAddr % PAGE_SIZE);
//ÅжÏдÍê³É
if(wWriteRemainNum == 0)
{
//дÍê³É
g_tSpiDevice.tState.bTxCompleted = TRUE;
//g_tSpiDevice.tState.bRxBusy = FALSE;
g_tSpiDevice.tState.bTxReq = FALSE;
g_tSpiDevice.tState.eStage = eFLASH_STATE_IDLE; //дÍê³É ת¿ÕÏÐ
if(g_tSpiDevice.pWriteAsyncNotifyCallback)
{
//TODO Ò첽֪ͨ»Øµ÷ ¹©µ÷ÓÃÕßʵÏÖ
g_tSpiDevice.pWriteAsyncNotifyCallback();
}
return eSUCCESS;
}
//СÓÚһҳʣÓà¿Éд×Ö½Ú
if(wWriteRemainNum <= wPageRemain)
{
__SPI_FlashWritePage(uWriteAddr, pData, wWriteRemainNum);
g_tSpiDevice.wTxOffset += wWriteRemainNum;
//дÍêÊ£Óà
}
else
{
__SPI_FlashWritePage(uWriteAddr, pData, wPageRemain);
g_tSpiDevice.wTxOffset += wPageRemain;
//дһÕûÒ³£¬
}
//Òì²½¶Áæ
g_tSpiDevice.tState.eStage = eFLASH_STATE_BUSY;
return eSUCCESS;
}
//Òì²½¶Áæ×ÓÈÎÎñ
static void __SPI_FlashBusy(void)
{
//¶Áæ ·Ç×èÈû
if(SPI_FlashBusyCheck())
{
return ;
}
//SPIÉϴβÙ×÷ÒÑÍê³É
//TX process
if(g_tSpiDevice.tState.bTxReq == TRUE)
{
g_tSpiDevice.tState.eStage = eFLASH_STATE_WRITE;
}
//RX process
// TODO ²Á³ýÒÑÍê³É
if(g_tSpiDevice.tState.bEraseChipReq == TRUE)
{
g_tSpiDevice.tState.eStage = eFLASH_STATE_ERASE_CHIP;
}
if(g_tSpiDevice.tState.bEraseSectorReq == TRUE)
{
g_tSpiDevice.tState.eStage = eFLASH_STATE_ERASE;
}
}
//Òì²½²Á³ý×ÓÈÎÎñ ÕûƬ
static int32_t __SPI_FlashEraseChip(void)
{
uint8_t cnt = 0;
SPI_FLASH_Write_Enable(); //SET WEL
if(g_tSpiDevice.tState.bEraseSuccess == TRUE)
{
g_tSpiDevice.tState.bEraseSuccess = FALSE;
g_tSpiDevice.tState.bEraseChipReq = FALSE;
g_tSpiDevice.tState.eStage = eFLASH_STATE_IDLE;//дÍê³É ת¿ÕÏÐ
if(g_tSpiDevice.pEraseChipAsyncNotifyCallback)
{
TODO Ò첽֪ͨ»Øµ÷ ¹©µ÷ÓÃÕßʵÏÖ
g_tSpiDevice.pEraseChipAsyncNotifyCallback();
}
return TRUE;
}
while((SPI_Flash_Read_SR()&0x2)!=0x2)
{
cnt ++;
if(cnt >200)
return FALSE;
}
SPI_CS_LOW();
SPI_Flash_ReadWrite_Byte(CHIP_ERASE);
SPI_CS_HIGH();
//SPI_Flash_Wait_Busy();
g_tSpiDevice.tState.eStage = eFLASH_STATE_BUSY;//Òì²½¶Áæ
return TRUE;
}
//Òì²½²Á³ý×ÓÈÎÎñ
static int32_t __SPI_FlashErase(void)
{
uint8_t cnt = 0;
//uint32_t uSectorIdxFirst = g_tSpiDevice.uTxDstAddr/SECTOR_SIZE;
uint32_t uSectorIdxTail = (g_tSpiDevice.uTxDstAddr+g_tSpiDevice.wTxLen)/SECTOR_SIZE;
uint32_t uCurrentSectorIdx = (g_tSpiDevice.uTxDstAddr + g_tSpiDevice.wTxOffset)/SECTOR_SIZE;
if(uCurrentSectorIdx > uSectorIdxTail)
{
g_tSpiDevice.tState.bEraseSectorReq = FALSE;
g_tSpiDevice.tState.bEraseSuccess = TRUE;
g_tSpiDevice.tState.eStage = eFLASH_STATE_IDLE;//дÍê³É ת¿ÕÏÐ
if(g_tSpiDevice.pEraseChipAsyncNotifyCallback)
{
TODO Ò첽֪ͨ»Øµ÷ ¹©µ÷ÓÃÕßʵÏÖ
g_tSpiDevice.pEraseChipAsyncNotifyCallback();
}
return TRUE;
}
SPI_FLASH_Write_Enable(); //SET WEL
while((SPI_Flash_Read_SR()&0x2)!=0x2)
{
cnt ++;
if(cnt >200)
return FALSE;
}
SPI_CS_LOW();
SPI_Flash_ReadWrite_Byte(SECTOR_ERASE);
SPI_Flash_ReadWrite_Byte((unsigned char)((uCurrentSectorIdx*SECTOR_SIZE)>>16));
SPI_Flash_ReadWrite_Byte((unsigned char)((uCurrentSectorIdx*SECTOR_SIZE)>>8));
SPI_Flash_ReadWrite_Byte((unsigned char)(uCurrentSectorIdx*SECTOR_SIZE));
SPI_CS_HIGH();
g_tSpiDevice.wTxOffset += SECTOR_SIZE;
//SPI_Flash_Wait_Busy();
g_tSpiDevice.tState.eStage = eFLASH_STATE_BUSY;//Òì²½¶Áæ
return TRUE;
}
//¿ÕÏд¦Àí×ÓÈÎÎñ
static void __SPI_FlashIdle(void)
{
//Æô¶¯¸÷ÏîÈÎÎñ
if(g_tSpiDevice.tState.bTxReq == TRUE)
{
g_tSpiDevice.tState.eStage = eFLASH_STATE_WRITE;
}
else if(g_tSpiDevice.tState.bRxReq == TRUE)
{
g_tSpiDevice.tState.eStage = eFLASH_STATE_READ;
}
else if(g_tSpiDevice.tState.bEraseChipReq == TRUE)
{
g_tSpiDevice.tState.eStage = eFLASH_STATE_ERASE_CHIP;
}
else if(g_tSpiDevice.tState.bEraseSectorReq == TRUE)
{
g_tSpiDevice.tState.eStage = eFLASH_STATE_ERASE;
}
}
//SPIÒì²½²Ù×÷´¦Àí×ÜÈÎÎñ
void SPI_FlashAsyncProcTask(void)
{
switch(g_tSpiDevice.tState.eStage)
{
case eFLASH_STATE_IDLE:
__SPI_FlashIdle();
break;
case eFLASH_STATE_WRITE:
__SPI_FlashWrite();
break;
case eFLASH_STATE_READ:
//TODO
break;
case eFLASH_STATE_BUSY:
__SPI_FlashBusy();
break;
case eFLASH_STATE_ERASE_CHIP:
__SPI_FlashEraseChip();
break;
case eFLASH_STATE_ERASE:
__SPI_FlashErase();
break;
default:
break;
}
}