Handle flash write/read

tjohansen wrote on Friday, July 10, 2009:


Im planing on using a task for reading and writting to my SPI flash. The other tasks can then use this task for the read/write.
The flash task is using a queue for receiving writes or reads commands.
But a big piece of data could be read/write. So I would send a big chunk of data through xQueueSend and xQueueReceive.

1: Is that a good idea or is there a better way of doing this? Maybe  a callback to the calling thread when new data can be send?
2: I could make the calling tasks send smaller chunks of data until they where finished. But then the calling tasks has to control when the reads/writes are done and not the flash task?
3: The flash read/write rutines could be static functions instead. They can then be called by the tasks. Then flash functions are then protected with a semaphore or something so only one task is allowed at a time?

I dont need a filesystem on it. Just the read and write og binary data. Some generel settings, bitmaps and logs.


aturowski wrote on Friday, July 10, 2009:

I think there is better way to do that. Other task will allocate the memory for the buffer and fills it with data. Then other tasks should use queue to send pointers to the buffers and buffers lenghts to be written. Flash task gets pointers and lenghts from queue,  writes the data and frees the buffer.

That way the queue is small and fast and there is no need to copy all data in and from queue. The amount of memory used for transfer data is adapring to the needs, not being fixed at maximum level when you are using queue to send data. There is of course some overhead for allocating/freeing memory, but still it is less than having to copy data to/out of queue.

Hope that help,

tjohansen wrote on Friday, July 10, 2009:

Yes of course. Passign the data as a pointer is a better way.

Is there any preferred way in FreeRTOS to signal the calling thread back, that the write or read is completed? (So the task know when read data is ready)
Could it be done with a tag/callback??

aturowski wrote on Friday, July 10, 2009:

Remember that you have to communicate this information to the other task(s) which can be running on totally different priority than flash task. To let scheduler deal with priorities and task preemption, the best way is use inter-process communication stuff in FreeRTOS - for example queues.

In general almost all real-time applications are event driven. This means that particular task should be woken when there is an event need to be processes by this task.  Personally I prefer following architecture: each task has input queue and task main function blocks on waiting for this queue. If event comes, ISR or other task puts a message into these queue and task is woken if there all higher priority tasks completed their processing. When task is woken, then it processes messages in queues and automatically blocks, if there are no more messages. The example of this architecture you can find in https://freeecu.svn.sourceforge.net/svnroot/freeecu/trunk

Lets assume that your application follows above architecture. The task wanting to write something to flash puts pointer to buffer, buffer lenght and pointer to its own input queue handler into flash task input queue. Flash task does the write, frees the buffer memory and puts information that writing is finished/error etc. in writing task input queue by using handler pointer. The writing task is then woken, knows flash write status and decides, what to do next.

For flash reading the task writes the following to flash task input queue: flash address, read lenght and pointer to handler to its input queue. The flash task is then woken, allocates buffer in memory, does flash read and pass the pointer to buffer to reading task input queue. Reading task is woken, processes the data and frees buffer when done.

This way all tasks priorities are sorted by scheduler, no write/read request is lost, many tasks can write to flash flawlessly.

Hope that helps,

alainm3 wrote on Friday, July 10, 2009:

There is also a different and much simpler way of doing the same thing:

Just make a function to access the SPI with a mutex in it. If another thread wants to read the same SPI, it will automaticaly wait for the first one to complete.

This is much simpler, IF it is acceptable to have that small wait delay…