How is the calling code designed?

What is the intended design of higher-level code using the driver? Will it operate on individual characters or bytes as they come in? Or does it make more sense for the higher-level code to batch transfers into blocks/frames of bytes? 

Queue-based drivers are very useful when dealing with unknown amounts (or streams) of data that can come in at any point in time. They are also a very natural fit for code that processes individual bytes—uartPrintOutTask was a good example of this:

 while(1)
{
xQueueReceive(uart2_BytesReceived, &nextByte, portMAX_DELAY);
//do something with the byte received
SEGGER_SYSVIEW_PrintfHost("%c", nextByte);
}

While ring-buffer implementations (such as the one in the preceding code) are perfect for streamed data, other code naturally gravitates toward operating on blocks of data. Say, for example, our high-level code is meant to read in one of the structures defined in Chapter 9Intertask Communication, over a serial port.

The following excerpt is from Chapter_9/MainQueueCompositePassByValue.c:

typedef struct
{
uint8_t redLEDState : 1;
uint8_t blueLEDState : 1;
uint8_t greenLEDState : 1;
uint32_t msDelayTime;
}LedStates_t;

Rather than operate on individual bytes, it is very convenient for the receiving side to pull in an instance of the entire struct at once. The following code is designed to receive an entire copy of LedStates_t from a queue. After the struct is received, it can be operated on by simply referencing members of the struct, such as checking redLEDState, in this example:

LedStates_t nextCmd;
while(1)
{
if(xQueueReceive(ledCmdQueue, &nextCmd, portMAX_DELAY) == pdTRUE)
{
if(nextCmd.redLEDState == 1)
RedLed.On();
else
. . .

This can be accomplished by serializing the data structure and passing it over the communication medium. Our LedStates_t struct can be serialized as a block of 5 bytes. All three red, green, and blue state values can be packed into 3 bits of a byte and the delay time will take 4 bytes:

Serialization is a broad topic in itself. There are trade-offs to be made for portability, ease of use, code fragility, and speed. A discussion on all of these points is outside the scope of this chapter. Details of endianness and the best way of serializing/deserializing this particular data structure have been purposely ignored in the diagram. The main takeaway is that the struct can be represented by a block of 5 bytes.

In this case, it makes sense for the underlying peripheral driver to operate on a buffer of 5 bytes, so a buffer-based approach that groups a transfer into a block of 5 bytes is more natural than a stream of bytes. The following pseudo-code outlines an approach based on the buffer-based driver we wrote in the previous section:

uint8_t ledCmdBuff[5];
startReceiveInt(ledCmdBuff, 5);
//wait for reception to complete
xSemaphoreTake(cmdReceived, portMAX_DELAY);
//populate an led command with data received from the serial port
LedStates_t ledCmd = parseMsg(ledCmdBuff);
//send the command to the queue
xQueueSend(ledCmdQueue, &ledCmd, portMAX_DELAY);

In a situation like the previous one, we have covered two different approaches that can provide efficient implementations:

  • A buffer-based driver (receiving 5 bytes at a time)
  • A stream buffer (the receiving side can be configured to acquire 5 bytes at a time)
FreeRTOS message buffers could also be used instead of a stream buffer to provide a more flexible solution. Message buffers are built on top of stream buffers, but have a more flexible blocking configuration. They allow different message sizes to be configured per receive call, so the same buffer can be used to group receptions into a size of 5 bytes (or any other desired size) each time xMessageBufferReceive is called. With stream buffers, the message size is rigidly defined when creating the stream buffer by setting the xTriggerLevelBytes parameter in xStreamBufferCreate.  Unlike stream buffers, message buffers will only return full messages, not individual bytes.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.171.202