I’m new in RTOS and want to use it in my project, and hope someone can give me some advice about how to design the firmware driver.
we have a nor flash that used to read/write user data.
When we want to write data(one page, 256Bytes) to flash, the process is
- Read the specified sector(4K Bytes) into buffer
- Erase the sector
- Modify the buffer and write it back to the sector
If we use a blocking function, it will be something like:
uint8_t sector_buf[4096];
void DataFlash_Write(uint32_t addr, uint8_t *data, uint16_t dataLen)
{
while(DataFlash_IsBusy()); // Wait Data Flash ready to operate
Nor_Flash_Read_Sector(sector_buf,addr); // Read(backup) the sector into buffer
while(DataFlash_IsBusy());
Nor_Flash_Erase_Sector(addr); // Erase this sector
while(DataFlash_IsBusy());
//-- Modify sector_buf
while(DataFlash_IsBusy());
Nor_Flash_Write_Sector(sector_buf,addr); // Write Modified data back to the sector
}
If we use non-block function(FreeRTOS Task), it will be a large switch case(State Machine),
and then we can use xQueueSend(…) to read/write data
void DataFlash_Task(void)
{
switch (dataFlashData.state)
{
case DATAFLASH_STATE_INIT:
{
// Do some init
dataFlashData.state = DATAFLASH_STATE_WAIT_CMD;
}
case DATAFLASH_STATE_WAIT_CMD:
{
// Receive cmd from other
xQueueReceive(dataFlashEvtQ, &data_flash_task_data.eventInfo, portMAX_DELAY);
if (data_flash_task_data.eventInfo.type== cmd1)
{
dataFlashData.state = DATAFLASH_STATE_CMD1;
} else if if (data_flash_task_data.eventInfo.type== cmd2)
{
dataFlashData.state = DATAFLASH_STATE_CMD2;
}
...// Other cmd cases
}
case DATAFLASH_STATE_READ_SECTOR:
case DATAFLASH_STATE_ERASE_SECTOR:
case DATAFLASH_STATE_WRITE_SECTOR:
case DATAFLASH_STATE_READY:
... // Other states
}
}
We have many data types that need to save so we split falsh address into several range to operate,
it means the state machine will be very large and complicated.
For some real case, we will need to do something like:
(e.g. read file bock many times from usb drive and write into flash)
uint8_t sector_buf[4096];
void WriteDatatoFlash_type1(void)
{
uint8_t writeBuf[256];
for(int i=0;i<blockNum;i++)
{
while(DataFlash_IsBusy());
DataFlash_ReadSector(addr,sector_buf);
while(DataFlash_IsBusy());
DataFlash_EraseSector(addr);
while(DataFlash_IsBusy());
DataFlash_WritePage(i,readBuf);
}
}
we have many read/write types so it will be to complicated if we use a state machine to control all process.
And because the state machine is async, so we need to use callback to notify one read/write is complete,
when we have many read/write in a loop, it also too complicated to implement the caller function…
I think one benefit we get from FreeRTOS is,
it can do context switching for us so we don’t need to worry about it takes too mach time and affect other tasks?
I use qspi nor flash as example to descript the question, but there are other perpherals act like this, we must wait and check status, do some additional operations(like erase) and finally we can read/write data to it.
I really want to know is, how to write the driver function?
should I need to use a task, receive msg from other task and perform operations?
or I can just implenent a blocking read/write function and let freeRTOS do the context for me?
May someone give me some advice about it?