Keeping the Data in Scope

The messages sent typically point to data structures, variables, arrays, tables, etc. However, it is important to realize that the data must remain static until the receiver of the data completes its processing of the data. Once sent, the sender must not touch the sent data. This seems obvious, however it is easy to forget.

One possibility is to use the fixed-size memory partition manager provided with µC/OS-III (see Memory Management API Changes) to dynamically allocate and free memory blocks used to pass the data. The figure below shows an example. For sake of illustration, assume that a device is sending data bytes to the UART in packets using some protocol. In this case, the first byte of a packet is unique and the end-of-packet byte is also unique.

Using Memory Partitions for Message Contents

(1) Here, a UART generates an interrupt when characters are received.

(2) The pseudo-code in the listing below shows what the UART ISR code might look like. There are a lot of details omitted for sake of simplicity. The ISR reads the byte received from the UART and sees if it corresponds to a start of packet. If it is, a buffer is obtained from the memory partition.

(3) The received byte is then placed in the buffer.

(4) If the data received is an end-of-packet byte, you would simply post the address of the buffer to the message queue so that the task can process the received packet.

(5) If the message sent makes the UART task the highest priority task, µC/OS-III will switch to that task at the end of the ISR instead of returning to the interrupted task. The task retrieves the packet from the message queue. Note that the OSQPend() call also returns the number of bytes in the packet and a time stamp indicating when the message was sent.

(6) When the task is finished processing the packet, the buffer is returned to the memory partition it came from by calling OSMemPut().

UART ISR Pseudo-code
          void  UART_ISR (void)
          {
              OS_ERR  err;
           
           
              RxData = Read byte from UART;
              if (RxData == Start of Packet) {               /* See if we need a new buffer      */
                  RxDataPtr = OSMemGet(&UART_MemPool,        /* Yes                              */
                                       &err);
                 *RxDataPtr++ = RxData;
                  RxDataCtr   = 1;
              } if (RxData == End of Packet byte) {          /* See if we got a full packet      */
                 *RxDataPtr++ = RxData;
                  RxDataCtr++;
                  OSQPost((OS_Q      *)&UART_Q,              /* Yes, post to task for processing */
                          (void      *)RxDataPtr,
                          (OS_MSG_SIZE)RxDataCtr,
                          (OS_OPT     )OS_OPT_POST_FIFO,
                          (OS_ERR    *)&err);
                  RxDataPtr = NULL;                         /* Don't point to sent buffer       */
                  RxDataCtr = 0;
              } else; {
                 *RxDataPtr++ = RxData;                      /* Save the byte received           */
                  RxDataCtr++;
             }
          }