I have a situation in which a microcontroller is to perform a large number of ADC conversions and format the results into commands (or data packages) and send these to a PC using the UART. In order to measure continuously while sending data, I created a circular buffer (queue/FIFO-buffer) to store the pending packages, and the microcontroller will then (ideally) empty this queue as fast as the PC will allow.
The microcontroller automatically sends the next command (if any) after an ACK-character (in this case a ‘!’) has been received. The UART Interrupt Handler is like this:
if (ch == '!') // ch is the received character
{
cmd_rx_ack = '!';
cmd_tx_pop_cmd();
}
The function cmd_tx_pop_cmd() is taking one package out of the circular buffer and putting the bytes int a cmd_tx[] array and the length of the package in cmd_tx_length.
In the main loop:
if (cmd_rx_ack == ‘!’)
{
cmd_rx_ack = 0; // Reset ack status
// Transmit the command
if (cmd_tx_length > 0)
{
cmd_tx_transmit();
}
}
The function cmd_tx_transmit() is simply transmitting the bytes in cmd_tx[] one by one (this is done in the main loop since it takes too long time to be done in the UART-handler).
This works fine, if the consumer of the queue (in this case the UART-handler) has higher priority than the producer (a timer that periodically makes the ADC convert and push a data package with the result onto the queue). Earlier I had concurrency problems (see Concurrency issues with circular buffer in embedded program) but now I have another problem:
I want the microcontroller to send the next package in the queue not only when an ACK has been received, but also in the situations listed below:
- The first package to be transmitted
- If the measurements are performed at a speed slower than the time it takes to send a package.
In the first situation, the package is never transmitted since no ACK is received after the package is pushed onto the queue.
In the second situation, the packages are never popped out of the queue for the same reason as in the first situation. (Assume the first package is ACKed and the UART-handler wants to transmit the next one, but the queue is empty at this point in time). In this case, the queue is just getting bigger and bigger and no packages are transmitted.
I can solve the first one by transmitting the first package manually (without the use of the queue) and put the remaining onto the queue. Not a pretty solution, though - but it works... I still need to solve the second problem.
So, I think that the UART-handler is not the right place to do the queue-popping since it cannot take account for the two situations I just mentioned. But I cannot put it in the main loop since it has lowest priority and then concurrency issues become a problem.
What would be a good way to implement this?
Thanks in advance :-)
BTW 1: An ACK is transmitted to the microcontroller if the PC accepted the transmitted package. I have made a special encoding of the packages so their length can be determined. This works just fine and cmd_tx_pop_cmd() will only pop the first package available in the queue. I have tested all this many, many times and it works perfectly, so please do not focus on this part as it is not the problem.
BTW 2: The microcontroller is a Tiva C series TM4C123GH6 as found on the Tiva C Series Launchpad. I am using gcc-arm-none-eabi.