Uart получает правильные байты, но в хаотичном порядке

Использование Atmel studio 7 с микроконтроллером STK600 и 32UC3C

Я дергаю себя за волосы. Я отправляю строки переменного размера по UART каждые 5 секунд. Строка состоит из одной буквы в качестве кода операции, затем следуют два символа, которые сообщают длину следующей строки данных (без нуля никогда не бывает нуля в конце любой из этих строк). В большинстве случаев строка будет иметь размер 3 символа, потому что в ней нет данных ("p00").

После расследования я узнал, что то, что должно было быть "p00", было на самом деле "0p0" или "00p" или (только при первой попытке после перезапуска микро "p00"). Я посмотрел это в представлении памяти отладчика. Затем я запустил hTerm и подтвердил, что данные на самом деле «p00». Итак, через некоторое время hTerm показал мне "p00p00p00p00p00p00p00...", в то время как память моего кольцевого буфера uart читает "p000p000p0p000p0p000p0p0..."

edit: На самом деле «0p0» и «00p» чередуются.

Скорость передачи 9600 бод. Раньше я отправлял только отдельные письма. Так что все шло хорошо.

Это код прерывания приемника: я пробовал разные варианты кода, которые все делали одно и то же по-разному. Но все они показали точно такое же поведение.

lastWebCMDWritePtr относится к типу uint8_t*, как и lastWebCMDRingstartPtr. lastWebCMDRingRXLen относится к типу uint8_t.

__attribute__((__interrupt__))
void UartISR_forWebserver()
{
    *(lastWebCMDWritePtr++) = (uint8_t)((&AVR32_USART0)->rhr & 0x1ff);
    lastWebCMDRingRXLen++;
    if(lastWebCMDWritePtr - lastWebCMDRingstartPtr > lastWebCMDRingBufferSIZE)
    {
        lastWebCMDWritePtr = lastWebCMDRingstartPtr;
    }
// Variation 2:
//  advanceFifo((uint8_t)((&AVR32_USART0)->rhr & 0x1ff));

// Variation 3:
//  if(usart_read_char(&AVR32_USART0, getReadPointer()) == USART_RX_ERROR)
//  {
//      usart_reset_status(&AVR32_USART0);
//  }
//      

};

Я приветствую любые ваши идеи и советы.

С уважением Сомео

P.S. Я поставил тег студии Atmel на случай, если это как-то связано с множеством ошибок отладчика AS.


person anyone    schedule 23.03.2017    source источник
comment
Спасибо, но это не та ошибка, которую я ищу, наверное... ;)   -  person anyone    schedule 23.03.2017
comment
Ну ты пробовал? Ваш код обращается к кольцевому буферу за пределами 1, поэтому ваша очередь, начиная с базового адреса, будет смещена на одно значение.   -  person LPs    schedule 23.03.2017
comment
Отправленные строки не имеют завершающего идентификатора, будь то нулевой символ или '\n' и т. д. Получатель не знает, где начинается одна строка и другая строка заканчивается.   -  person chux - Reinstate Monica    schedule 23.03.2017
comment
Незначительное: хорошая идея @LP может быть записана как if(lastWebCMDWritePtr - lastWebCMDRingstartPtr >= lastWebCMDRingBufferSIZE).   -  person chux - Reinstate Monica    schedule 23.03.2017
comment
Получатель знает, потому что длина строки передается после символа кода операции. Однако на уровне связи UART это также не проблема, потому что за раз передается только один символ. @LPs да, я сделал, и это не было ошибкой. Хотя я этого и желал.   -  person anyone    schedule 23.03.2017
comment
@chux Да, в принципе, для меня на первый взгляд более понятно, используя форму, которую я разместил;)   -  person LPs    schedule 23.03.2017
comment
Для последовательной связи характерно то, что невозможно получать данные в другом порядке, чем они были отправлены. Предположим, что отправитель и получатель согласовывают параметры протокола, единственными альтернативами являются отправка данных в другом порядке, чем вы думаете, или получатель шифрует данные после получения.   -  person John Bollinger    schedule 23.03.2017
comment
Да, я тоже так думаю, поэтому я проверил передачу с помощью внешней программы, и она оказалась правильной. Ошибка должна быть в прерывании или обработке данных. Но я не могу поймать его.   -  person anyone    schedule 23.03.2017
comment
Вы проверяли спецификацию? Вы говорите, что lastWebCMDWritePtr это uint8_t, но, например, для pl011 это должен быть 32-битный указатель. Кроме того, этот адрес может быть помечен как volatile, потому что его семантика не является памятью (чтение (запись (v)) != v). Вы проверили сгенерированный код?   -  person Aif    schedule 23.03.2017
comment
Будьте осторожны с получателем, потому что длина строки передается после символа кода операции. Длина строки равна любой переданной длине. отправка добавленных данных не принуждает совпадать с предыдущей длиной. IOWs, что произойдет, если длина строки будет передана после неправильного вычисления символа кода операции? Что произойдет, если байт будет потерян при передаче? Простое вычисление CRLF в LF может легко все испортить. Я рекомендую начинать/заканчивать каждое сообщение специальным символом, который в других случаях не используется, например < и >.   -  person chux - Reinstate Monica    schedule 23.03.2017
comment
Вы пытались использовать usart_read_char для чтения символа из буфера UART вместо прямого доступа к rhr? Если произошла ошибка связи, содержимое rhr может быть недействительным.   -  person putu    schedule 23.03.2017
comment
Ваши переменные FIFO объявлены volatile?   -  person Attie    schedule 23.03.2017


Ответы (1)


Для получения полной картины необходимо показать, где и как используются lastWebCMDWritePtr, lastWebCMDRingRXLen, lastWebCMDRingstartPtr и lastWebCMDRingBufferSIZE. (на стороне потребления)

Также я бы сначала попробовал более простой ISR без зависимостей от других программных модулей, чтобы исключить аппаратное обеспечение, соответственно. проблема обработки регистрации.

Подход:

#define USART_DEBUG
#define DEBUG_BUF_SIZE 30

__attribute__((__interrupt__))
void UartISR_forWebserver()
{ 
  uint8_t rec_byte;
#ifdef USART_DEBUG  
  static volatile uint8_t usart_debug_buf[DEBUG_BUF_SIZE]; //circular buffer for debugging
  static volatile int usart_debug_buf_index = 0;
#endif      

  rec_byte = (uint8_t)((&AVR32_USART0)->rhr & 0x1ff);

#ifdef USART_DEBUG  
  usart_debug_buf_index = usart_debug_buf_index % DEBUG_BUF_SIZE; 
  usart_debug_buf[usart_debug_buf_index] = rec_byte;
  usart_debug_buf_index++

  if (!(usart_debug_buf_index < DEBUG_BUF_SIZE)) {
    usart_debug_buf_index = 0; //candidate for a breakpoint to see what happened in the past
  }
#endif
  //uart_recfifo_enqueue(rec_byte);

};
person grenix    schedule 23.03.2017
comment
Я узнал это сейчас, это был аппаратный сбой. После замены MCU на новый он заработал как положено. Хотел бы я подумать об этом раньше. - person anyone; 23.03.2017