I am transmitting data from my PIC24H microcontroller over 460Kbaud UART to a bluetooth radio module. Under most conditions, this flow works just fine and the bluetooth module uses CTS and RTS lines to manage flow control when its internal data buffers are full. However, there is a bug of some kind in the bluetooth module that resets it when data is continuously sent to it without any breaks, which happens if my data gets backed up in another bottleneck.
It would be nice if the module worked properly, but that's out of my control. So it seems that my only option is to do some data throttling on my end to make sure I don't exceed the data throughput limits (which I know roughly by experimentation).
My question is how to implement data rate throttling?
My current UART implementation is a RAM circular FIFO buffer 1024 bytes long that the main loop writes data to. A peripheral interrupt is triggered by the PIC when the last byte has been sent out by the UART hardware and my ISR reads the next byte from the buffer and sends it to the UART hardware.
Here's an idea of the source code:
uart_isr.c
//*************** Interrupt Service routine for UART2 Transmission
void __attribute__ ((interrupt,no_auto_psv)) _U2TXInterrupt(void)
{
//the UART2 Tx Buffer is empty (!UART_TX_BUF_FULL()), fill it
//Only if data exists in data buffer (!isTxBufEmpty())
while(!isTxBufEmpty()&& !UART_TX_BUF_FULL()) {
if(BT_CONNECTED)
{ //Transmit next byte of data
U2TXREG = 0xFF & (unsigned int)txbuf[txReadPtr];
txReadPtr = (txReadPtr + 1) % TX_BUFFER_SIZE;
}else{
break;
}
}
IFS1bits.U2TXIF = 0;
}
uart_methods.c
//return false if buffer overrun
BOOL writeStrUART(WORD length, BYTE* writePtr)
{
BOOL overrun = TRUE;
while(length)
{
txbuf[txWritePtr] = *(writePtr);
//increment writePtr
txWritePtr = (txWritePtr + 1) % TX_BUFFER_SIZE;
if(txWritePtr == txReadPtr)
{
//write pointer has caught up to read, increment read ptr
txReadPtr = (txReadPtr + 1) % TX_BUFFER_SIZE;
//Set overrun flag to FALSE
overrun = FALSE;
}
writePtr++;
length--;
}
//Make sure that Data is being transmitted
ensureTxCycleStarted();
return overrun;
}
void ensureTxCycleStarted()
{
WORD oldPtr = 0;
if(IS_UART_TX_IDLE() && !isTxBufEmpty())
{
//write one byte to start UART transmit cycle
oldPtr = txReadPtr;
txReadPtr = (txReadPtr + 1) % TX_BUFFER_SIZE;//Preincrement pointer
//Note: if pointer is incremented after U2TXREG write,
// the interrupt will trigger before the increment
// and the first piece of data will be retransmitted.
U2TXREG = 0xFF & (unsigned int)txbuf[oldPtr];
}
}
Edit
There are two ways that throttling could be implemented as I see it:
Enforce a time delay in between UART byte to be written that puts an upper limit on data throughput.
Keep a running tally of bytes transmitted over a certain time frame and if the maximum number of bytes is exceeded for that timespan create a slightly longer delay before continuing transmission.
Either option would theoretically work, its the implementation I'm wondering about.