Я передаю данные с моего микроконтроллера PIC24H через 460Kbaud UART на Bluetooth-модуль Bluetooth. В большинстве случаев этот поток работает очень хорошо, и модуль bluetooth использует линии CTS и RTS для управления потоком, когда его внутренние буферы данных заполнены. Однако в модуле bluetooth есть какая-то ошибка, которая сбрасывает ее, когда данные непрерывно отправляются на нее без каких-либо перерывов, что происходит, если мои данные будут подкреплены другим узким местом.Как управлять дроссельной передачей UART-передачи PIC24H?
Было бы неплохо, если бы модуль работал правильно, но это не под моим контролем. Поэтому кажется, что мой единственный вариант - сделать некоторые данные для дросселирования на моем конце, чтобы убедиться, что я не превышаю пределы пропускной способности данных (что я знаю примерно по экспериментам).
Мой вопрос в том, как реализовать дросселирование скорости передачи данных?
Моя текущая реализация UART представляет собой кольцевой буфер FIFO RAM длиной 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, который устанавливает верхний предел пропускной способности данных.
Продолжайте выполнение байт, переданных в течение определенного периода времени, и если максимальное количество байтов превышено за это время, создайте немного большую задержку перед продолжением передачи.
Любой вариант теоретически будет работать, его реализация мне интересна.
Опишите, какие «перерывы» требуется модулю для работы ... –
@Ben Jackson было бы здорово, если бы я знал. Это ошибка, а не функция, поэтому она не документирована. В основном он сбрасывается примерно через 3 секунды с постоянной пропускной способностью, даже если он контролируется потоком. В среднем я могу обойтись со скоростью 25 кбит/с. – CodeFusionMobile