Перейти к содержанию
    

Простой модуль чтения данных с GPS, из проекта выкинул все, кроме uart драйвера и парсера сообщений UBX. (Ublox gps protocol), STM415 стоит, но софт везде работает с ним как с 215 ( Это не влияет, я это ловил и на настоящих 215 )

 

Настройка порта:

      case USART6_BASE:

       #ifdef USE_IN_UART6_BUFFER  
       UART6_InputBufWR = 0;
       UART6_InputBufRD = 0;
       #endif

       #ifdef USE_OUT_UART6_BUFFER      
       UART6_OutputBufWR = 0;
       UART6_OutputBufRD = 0;
       #endif

       RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE);

       GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_USART6);
       GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_USART6);

       GPIO_Init_Struct.GPIO_Pin = GPIO_Pin_6;
       GPIO_Init_Struct.GPIO_Mode = GPIO_Mode_AF;
       GPIO_Init_Struct.GPIO_Speed = GPIO_Speed_50MHz;
       GPIO_Init_Struct.GPIO_OType = GPIO_OType_PP;
       GPIO_Init_Struct.GPIO_PuPd = GPIO_PuPd_NOPULL;
       GPIO_Init(GPIOC, &GPIO_Init_Struct);

       GPIO_Init_Struct.GPIO_Pin = GPIO_Pin_7;
       GPIO_Init_Struct.GPIO_OType = GPIO_OType_OD;
       GPIO_Init_Struct.GPIO_PuPd = GPIO_PuPd_NOPULL;
       GPIO_Init(GPIOC, &GPIO_Init_Struct);

       #if defined (USE_IN_UART6_BUFFER) || defined (USE_OUT_UART6_BUFFER)
       NVIC_InitStructure.NVIC_IRQChannel = USART6_IRQn;
       NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = UART6_PreemptionPriority;
       NVIC_InitStructure.NVIC_IRQChannelSubPriority = UART6_SubPriority;
       NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
       NVIC_Init(&NVIC_InitStructure);
       #endif
       #ifdef  USE_IN_UART6_BUFFER
       USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);
       //USART_ITConfig(USARTx, USART_IT_ORE, ENABLE);
       #endif

     break;
   }

   USART_Init_Struct.USART_BaudRate = Baudrate;
   USART_Init_Struct.USART_WordLength = USART_WordLength_8b;
   USART_Init_Struct.USART_StopBits = USART_StopBits_1;
   USART_Init_Struct.USART_Parity = USART_Parity_No;        
   USART_Init_Struct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
   USART_Init_Struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
   USART_Init(USARTx, &USART_Init_Struct);

   USART_Cmd(USARTx,ENABLE);

 

Прерывание:

void USART6_IRQHandler(void)
{
 if(USART_GetITStatus(USART6, USART_IT_TXE) != RESET)
 {
   #ifdef USE_OUT_UART6_BUFFER

   if(UART6_out_counter != 0)
   {  
     UART6_out_counter--;
     USART_SendData(USART6,(uint16_t) UART6_OutputBuf[uART6_OutputBufRD]);

     if(UART6_OutputBufRD >= (UART6_OutputBuf_size - 1))
     {
       UART6_OutputBufRD = 0;
     }
     else
     {
       UART6_OutputBufRD++;
     }   
   } else {
     USART_ITConfig(USART6, USART_IT_TXE, DISABLE);
     isTxDone6 = 1;
   #endif
   }
 } else if(USART_GetITStatus(USART6, USART_IT_RXNE) != RESET)
 {
   USART6->SR;    
#ifdef USE_IN_UART6_BUFFER

   uint8_t read_UART;

   read_UART = USART_ReceiveData(USART6);
#ifdef FATFS_ON    
   GPSLOGGER_PushByte( read_UART ); 
#endif



   if(UART6_in_counter < UART6_InputBuf_size)
   {
     UART6_InputBuf[uART6_InputBufWR] = read_UART;

     if(UART6_InputBufWR == (UART6_InputBuf_size - 1))
     {
       UART6_InputBufWR = 0;
     }
     else
     {
       UART6_InputBufWR++;
     }
     UART6_in_counter++;
   }
   #endif
 }else {
   USART6->SR;
   USART6->DR;    
 }

 USART_ClearFlag( USART6, USART_FLAG_CTS | USART_FLAG_LBD | USART_FLAG_RXNE | USART_IT_TC );  
}

 

Ну тык вот, есть странности (скорость 200к). Самый главный вопрос, почему мы иногда попадаем в последний else, выполняя

USART6->SR;

USART6->DR;

 

 

При этом, это должно было быть прерывание RX, НО RXNEIE = 0! Все остальные биты такие-же как и при нормальном прерывании.

 

Еще странность что ORE почти всегда 1.

 

В GPSLOGGER_PushByte есть глобальное разрешение и запрещение прерывания, но функция просто просто байт сохраняет:

inline void GPSLOGGER_PushByte( uint8_t b ){
 __disable_irq();
 if( sizebuf[curBuf] < LOGBUFSIZE ){
   logbuf[ curBuf ][  sizebuf[curBuf] ] = b;
 }
 sizebuf[ curBuf ] ++;
 __enable_irq();
}

Изменено пользователем Vladimir Prokofiev

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У STM-ок это довольно часто бывает - "ложное" (spurious) прерывание. Просто не реагируйте.

И, кстати, вполне возможно одновременное единичное состояние флагов RXNE и TXE. Поэтому второй else - лишний.

Примерно вот так:

    uint16_t status = USARTx->SR;
    uint8_t data = USARTx->DR;
    
    // чистим ошибки
    if (status & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE))
        USARTx->SR = 0;
    
    if (status & USART_SR_RXNE)
    {
        // обрабатываем приём.
    }

    if (status & USART_SR_TXE)
    {
        // обрабатываем передачу.
    }

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В GPSLOGGER_PushByte есть глобальное разрешение и запрещение прерывания, но функция просто просто байт сохраняет:

inline void GPSLOGGER_PushByte( uint8_t b ){
 __disable_irq();
 if( sizebuf[curBuf] < LOGBUFSIZE ){
   logbuf[ curBuf ][  sizebuf[curBuf] ] = b;
 }
 sizebuf[ curBuf ] ++;
 __enable_irq();
}

Кстати, код можно построить так, чтобы не запрещать глобальные прерывания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кстати, код можно построить так, чтобы не запрещать глобальные прерывания.

Подскажите?:)

 

А прерывание судя по всему не лишнее, а настоящее, только с невыставленным флагом RXNEIE. Я воспользовался библиотечной функцией USART_GetITStatus, которая проверяет этот флаг. Если написать как у вас то проблема не заметна. И ошибки CRC пропали :). Про одновременное срабатывание спасибо, не подумал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

...странное...

Прежде, чем начинать новую тему, поискал, не было ли чего похожего. Оказался здесь. Мой пост есть не столько ответ к ТС сколько нарытая информация к UART STM32F10x.

 

Предыстория раскопок.

 

Применяю, естессно, UART широко и с размахом. Возникла тема подключить WiFi-модуль к STM32F103 через UART. Сделал, заработало. Более тщательные тесты обнаружили спорадическую потерю байтов при приеме от WiFi-модуля. Ну, скажем, один байт на каждые полмега.

 

Прием построен по принципу FIFO в виде аппаратно-независимого драйвера. Полный код приводить не буду, но процедура обработки прерывания в части приема выглядит так:

/******************************************************************************/
//
//	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. Вроде все согласно логике и докам.

Обработчик - это еще не вектор прерывания: тот инкапсулирует вызов обработчика как:

/******************************************************************************/
//
//	USART IRQ Handler
//
/******************************************************************************/
void STDIO_IRQHandler(void)
{
   bufio_IRQHandler(&FIFO);
}

 

Когда я натолкнулся на потерю байтов, я, естественно, начал подозревать переполнение буфера UART, хотя при 115200 бод и 72MHz проца такого быть бы не должно (приоритет прерывания для UART установлен неслабенький). Для поимки жука я выставил ловушку:

/******************************************************************************/
//
//	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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Чисто феноменологически, а также из опыта продирания сквозь дебри I2C этого проца, я сделал вывод, что, похоже, прерывание возникает раньше, чем биты, его вызвавшие, появляются в SR. Это, возможно, приводит к тому, что без задержки по причине if() вверху нарушается логика работы основного обработчика. Чтение же (явно лишнее) SR просто так перед дальнейшими действиями приводит UART в чувство после пинка прерывания. Где-то напортачили с синхронизацией регистров и шин. Даже осмелюсь высказать крамольную гипотезу, что обновления SR происходят не от основной частоты, а синхронизируются с baud-частотой.

В общем, оставил я тупое предчтение SR пока. Не люблю я таких work around... А что делать? И кто виноват?

Недавно тоже боролся с потерей байтов в USART у STM32, но проблема была в... компиляторе - при записи в регистр USART->DR

вставлялось фиктивное его чтение (древняя сборка kgp, в последней все нормально).

Нигде в Интернете жалоб на пропажу байт не нашел, эррата тоже пуста.

Если бы прерывание выставлялось раньше флага, то у Вас просто были бы повторные вхождения в прерывание. Флаг же очищается только

чтением из USART->DR.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно слегка упростить:

void STDIO_IRQHandler(void)
{
    STDIO_DEVICE->SR; // dummy read (ИМХО нафиг не надо)
    bufio_IRQHandler(&FIFO);
}

Ничего подобного, о чём вы говорите не наблюдал.

Работаю с UART и с DMA и без оного. Проектов штук 10 сделано. Никаких нареканий.

Вот пример обработчика без DMA:

static INLINE void uart_isr(uart_t* const uart)
{
    uint_fast16_t status = uart->sfr->SR;

    if (status & USART_SR_RXNE)      // if RX data_reg isn't empty (auto-clr by reading data_reg)
    {  
        uart_rx_isr(uart, status);
    }
    else if (status & USART_SR_TXE)  // if TX data_reg is empty (auto-clr by writing data_reg)
    {
        uart_tx_isr(uart);
    }
}

Как видите, никаких двойных чтений статуса.

Читаю строго один раз согласно DS.

 

...древняя сборка kgp, в последней все нормально
Чем же вам оттестированная тысячами пользователей сборка с ланчпада не угодила?

С чего такая тяга к экзотике?

Нигде в Интернете жалоб на пропажу байт не нашел, эррата тоже пуста.
+1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно слегка упростить:

Стремно как-то. Работает пока.

 

Мы тут с коллегой покумекали, почему потеря редко происходит, и почему добавление инструкции ошибку (пока) устранило (может чтение SR и не нужно, достаточно просто задержки). Предположение следующее.

 

Видать, по причине внутреннего поведения UART задержка таки нужна, но в большинстве случаев она как бы присутствует, поскольку на вход в прерывание Cortex нужно 12(?) тактов. Это если оно прерывает синхронный цикл. А вот если происходит прерывание более низкоприоритетного прерывания, то для Cortex процов ARM гордо раскидывает пальцы и говорит, что tail chaining, или как там оно зовется, позволяет оказаться в прерывании вдвое быстрее. Поскольку у меня не программа мигания светодиодами, а устройство с множеством других прерываний (ADC, RTC и прочие периодические процессы), то вполне возможен "збiг обставин" - такое стечение обстоятельств, что прерывается прерывание, и имеем, что имеем. А лишняя инструкция или две (ну так исторически сложилось, что это чтение SR для ловушки), выравнивают шансы.

 

Я почему упомянул и I2C в этой связи: я ловил статусы (комбинации битов) в прерывании I2C, которые не описаны в доке и константах. Причем такие статусы, словно биты не добегали, хотя процессор уже попал в прерывание. А I2C у меня рубает на нулевом приоритете: вы знаете, там в доках требование, чтобы никто не прерывал определенные последовательности действий, вот я так и предотвращаю. А чуть подождешь - и все ОК. Поэтому я укрепляюсь в своей гипотезе, что не все прекрасно в Королевстве Датском, и где-то вагоны бегут впереди паровоза у ST.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Поэтому я укрепляюсь в своей гипотезе, что не все прекрасно в Королевстве Датском, и где-то вагоны бегут впереди паровоза у ST.

Что за камешек? Хотелось бы повторить бяку.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что за камешек? Хотелось бы повторить бяку.

Дык неоднократно поминали всуе: STM32F103, в частности STM32F103RCT6. Конкретно, если это важно, дальше стоит типа GH21E 9U CHN GH 218 на корпусе.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Дык неоднократно поминали всуе: STM32F103, в частности STM32F103RCT6. Конкретно, если это важно, дальше стоит типа GH21E 9U CHN GH 218 на корпусе.

Собрал стендик - ошибка не повторяется:

1. USART1 с частотой 100Гц отправляет поочередно "01234567";

2. USART2 принимает эти символы, и если переданный не совпадает с принятым, то увеличивается счетчик ошибок;

3. В обработчике прерывания USART2 включается и выключается LED1;

4. По спаду сигнала на ножке приемника вызывается прерывание EXTI, в котором включается LED2, происходит задержка

на два интервала символа, LED2 выключается и выходим из прерывания;

5. Приоритет USART2 выше EXTI, т.е. прерывание EXTI вытесняется с использованием tail chaining

(вижу на осциллографе импульс LED1 внутри импульса LED2).

 

Ошибок нет. Может, что-то не так делаю?

//-----------------------------------------------------------------------------
//	void USART2_IRQHandler(void)
//-----------------------------------------------------------------------------
void USART2_IRQHandler(void)
{
BYTE	x;

if(USART2->SR & (1 << USART_SR_RXNE))
{
	// новый символ в приемнике
	x = USART2->DR;

	crx++;

	GPIOB->BSRR = (1 << 0);

	if(x != ('0' + (cnt & 7)))
	{
		WORKLED_bit ^= 1;
		cerror++;
		eflag = 1;
	}

	GPIOB->BSRR = (1 << 0) << 16;
}

if((USART2->SR) & (1 << USART_SR_ORE)) USART2->DR;

}

//-----------------------------------------------------------------------------
//	void EXTI3_IRQHandler(void)
//-----------------------------------------------------------------------------
void EXTI3_IRQHandler(void)
{
volatile int d;
if(EXTI->PR & (1 << 3))
{
	cexti++;

	GPIOB->BSRR = (1 << 1);
	for(d = 0; d < 1000; d++);

	EXTI->PR = (1 << 3);
	GPIOB->BSRR = (1 << 1) << 16;
}
}

 

Добавил строгую проверку последовательности вызовов обработчиков ОТПРАВКА->EXTI->USART2.

Т.е. если перед очередной отправкой не был принят предыдущий символ, то увеличивается счетчик ошибок.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Собрал стендик - ошибка не повторяется:

Ошибок нет. Может, что-то не так делаю?

Спасибо, что подхватили тему и пробуете разобраться.

Что "не так делаю", сказать сложно.

Ну, во-первых, USART_SR_RXNE есть сама маска (0x20), а не номер бита. То есть (1 << USART_SR_RXNE) делать нельзя. Если, конечно, этот символ у Вас не определен как-то иначе, чем в "stm32f10x.h".

Во-вторых, вряд ли стОит ожидать, что ошибку (или странное поведение) можно спровоцировать вне сложной системы, в которую выросла моя. И как я писал, у меня ошибка имела место спорадически, примерно каждые пол-мегабайта. Сегодня же, после вышеописанной заплатки, мы с коллегой наперегонки еще погоняли мегабайты и не обнаружили пока ни одного сбоя.

В-третьих, - и думаю, это самое главное, - источником данных у меня является внешнее устройство, которое асинхронно к UART процессора, а Вы передаете в рамках одного процессора, то есть UART'ы "когерентны" и стабильны. Может jitter, а также разбросы в действительной скорости (baud rate) между двумя устройствами и провоцирует UART на непредвиденное поведение. В конце концов, в доках написано, что UART2 (мой случай) тактируется от 36MHz, и скорость 115200 на самом деле устанавливается с ошибкой (по памяти фактически 115384).

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

С USART_SR_RXNE Вы правы - он у меня определен как номер бита, а не как маска.

По сложности могу усилить и другими блоками, но они будут работать параллельно и вряд ли это окажет влияния.

Можно DMA врубить для усложнения, но насколько я понял, гипотеза была в том, что флаг не успевает за периферией.

Я даже на асме хотел написать обработчик, чтоб было максимально быстрое обращение к USART->SR.

Насчет разброса частоты UART согласен, что ошибка нулевая. Но как мне кажется при допустимом уровне рассогласования все будет работать,

при превышении уровня - все перестанет работать. У меня тоже на тестовой плате USART2 тактруется от 36МГц. На второй стороне у Вас

какое устройство? С какой расчетной частотой? Могу добавить еще одну отладку с "удачным" кварцем на 11.0592МГц, который даст точные

115200. Я за то, что USART у STM32F103 не глючит, хотя в более поздних процах USART заметно поменялся, но это скорее усовершенствование

блока, чем латание дыр. Может все-таки в программе (или компиляторе) проблемы, а может железо сбоит. Заметил, что преобразователь USB-COM TTL

работает стабильнее, если подключать его через последовательные сопротивления (иначе на осциллографе вижу выбросы вверх или вниз аж под 1.5В).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А зачем этот участок кода? Ведь по приходу нового байта статут формируется заново. Или я что-то упустил?

    // чистим ошибки
    if (status & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE))
        USARTx->SR = 0;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

С USART_SR_RXNE Вы правы - он у меня определен как номер бита, а не как маска.

Интересно, зачем. Это же конфликт с CMSIS-согласованным файлом stm32f10x.h

На второй стороне у Вас какое устройство? С какой расчетной частотой?

WiFi-"модем" HLK-RM04. Там внутри Ralink RT5350F и кварц, по которому не видно, сколько MHz. Но еще раз: после добавления заплатки, действие которой заключается либо в задержке, либо в предварительном "тупом" чтении регистра SR, ошибка спорадической потери байтов забилась в угол до такой степени, что мы вчера в течение долгих тестов не смогли ее обнаружить.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...