Цитата(Vladimir Prokofiev @ Feb 20 2014, 11:37)

...странное...
Прежде, чем начинать новую тему, поискал, не было ли чего похожего. Оказался здесь. Мой пост есть не столько ответ к ТС сколько нарытая информация к UART STM32F10x.
Предыстория раскопок.
Применяю, естессно, UART широко и с размахом. Возникла тема подключить WiFi-модуль к STM32F103 через UART. Сделал, заработало. Более тщательные тесты обнаружили спорадическую потерю байтов при приеме от WiFi-модуля. Ну, скажем, один байт на каждые полмега.
Прием построен по принципу FIFO в виде аппаратно-независимого драйвера. Полный код приводить не буду, но процедура обработки прерывания в части приема выглядит так:
CODE
/******************************************************************************/
//
// IRQ Handler
//
void bufio_IRQHandler(bufio_FIFO *FIFO)
{
bufio_DRIVER* h = FIFO->HD; // to shorten the script
if (h && h->RI)
{
while (h->RI()) {
// If no more place in the input buffer, no char read out
// from the data register follows, and RI flag stays ON.
// The interrupt will be disabled. As soon as it is reenabled
// in the ReadChar, the interrupt shoots again.
if (bufio_RXBufferReady() && !FIFO->RX.flag)
bufio_StoreChar(FIFO, h->Get());
else {
h->RIE(0); // disable RX interrupt w/o getting the char
break; // from the device; it should keep the RI flag on.
}
}
}
....
h->RI() - это, по сути, чтение SR на предмет RXNE. Ну а h->Get() - чтение DR. Вроде все согласно логике и докам.
Обработчик - это еще не вектор прерывания: тот инкапсулирует вызов обработчика как:
CODE
/******************************************************************************/
//
// USART IRQ Handler
//
/******************************************************************************/
void STDIO_IRQHandler(void)
{
bufio_IRQHandler(&FIFO);
}
Когда я натолкнулся на потерю байтов, я, естественно, начал подозревать переполнение буфера UART, хотя при 115200 бод и 72MHz проца такого быть бы не должно (приоритет прерывания для UART установлен неслабенький). Для поимки жука я выставил ловушку:
CODE
/******************************************************************************/
//
// USART IRQ Handler
//
/******************************************************************************/
void STDIO_IRQHandler(void)
{
if (STDIO_DEVICE->SR & USART_SR_ORE)
__NOP();
bufio_IRQHandler(&FIFO);
}
После чего в ловушку никто не попал, а потери байтов, похоже, прекратились...
Чисто феноменологически, а также из опыта продирания сквозь дебри I2C этого проца, я сделал вывод, что, похоже, прерывание возникает раньше, чем биты, его вызвавшие, появляются в SR. Это, возможно, приводит к тому, что без задержки по причине if() вверху нарушается логика работы основного обработчика. Чтение же (явно лишнее) SR просто так перед дальнейшими действиями приводит UART в чувство после пинка прерывания. Где-то напортачили с синхронизацией регистров и шин. Даже осмелюсь высказать крамольную гипотезу, что обновления SR происходят не от основной частоты, а синхронизируются с baud-частотой.
В общем, оставил я тупое предчтение SR пока. Не люблю я таких work around... А что делать? И кто виноват?
Сообщение отредактировал KnightIgor - Apr 29 2014, 09:33