Я передаю данные с моего микроконтроллера PIC24H по UART со скоростью 460 кбод на радиомодуль bluetooth. В большинстве случаев этот поток работает просто отлично, и модуль Bluetooth использует линии CTS и RTS для управления контролем потока, когда его внутренние буферы данных заполнены. Однако в модуле bluetooth есть какая-то ошибка, которая сбрасывает его, когда данные непрерывно отправляются на него без каких-либо перерывов, что происходит, если мои данные копируются в другое узкое место.
Было бы неплохо, если бы модуль работал правильно, но это вне моего контроля. Так что, похоже, мой единственный вариант - сделать некоторые данные на своем конце, чтобы убедиться, что я не превышаю предельные значения пропускной способности данных (которые я знаю примерно экспериментально).
Мой вопрос, как реализовать регулирование скорости передачи данных?
Моя текущая реализация UART - это кольцевой буфер FIFO в ОЗУ длиной 1024 байта, в который основной цикл записывает данные. Периферийное прерывание запускается PIC, когда последний байт был отправлен оборудованием UART, и мой ISR считывает следующий байт из буфера и отправляет его на оборудование UART.
Вот идея исходного кода:
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];
}
}
Редактировать
Есть два способа, которыми регулирование могло бы быть реализовано, как я вижу это:
Принудительная задержка между записываемыми байтами UART, которая устанавливает верхний предел пропускной способности данных.
Сохранение текущего количества байтов, переданных за определенный период времени, и, если максимальное число байтов превышено для этого промежутка времени, создайте немного большую задержку перед продолжением передачи.
Теоретически, любой из этих вариантов работает, его реализация мне интересна.