реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Time-out в USART, аппаратное отлавливание
athlon64
сообщение Jun 1 2010, 13:14
Сообщение #1


Частый гость
**

Группа: Свой
Сообщений: 156
Регистрация: 10-03-10
Из: Уфа
Пользователь №: 55 882



Процессор At91SAM7X512, IDE IAR 5.4, uCOS 2.89
Тайм-аут мне нужен чтобы определять окончание пакета.
С отдельным таймером для отсчитывания тайм-аута всё работает. Интересно использовать именно заложенную в USART аппаратную функцию. Прочитал раздел даташита про USART несколько раз, но всё равно чтото гдето забыл sad.gif
Процессор получает пакет и даже успевает его пульнуть обратно, но по истечении таймаута процессор виснет.


Инициализация USART0:

Код
void ConfigureUsart(unsigned char usart_num)
{
      unsigned int mode = AT91C_US_USMODE_NORMAL
                        | AT91C_US_CLKS_CLOCK
                        | AT91C_US_CHRL_8_BITS
                        | AT91C_US_PAR_NONE
                        | AT91C_US_NBSTOP_1_BIT
                        | AT91C_US_CHMODE_NORMAL;

      PIO_Configure(USART0_pins, PIO_LISTSIZE(USART0_pins));
      // Enable the peripheral clock in the PMC
      PMC_EnablePeripheral(AT91C_ID_US0);
      PMC_EnablePeripheral(AT91C_ID_US0);

      // Configure the USART in the desired mode @9600 bauds
      USART_Configure(AT91C_BASE_US0, mode, 9600, 48000000);

      // Configure the USART interrupt
      IRQ_ConfigureIT(AT91C_ID_US0, 0, USART0_IrqHandler);
      IRQ_EnableIT(AT91C_ID_US0);

      // Enable receiver & transmitter
      USART_SetTransmitterEnabled(AT91C_BASE_US0, 1);
      USART_SetReceiverEnabled(AT91C_BASE_US0, 1);

      // Start receiving data and start timer
      USART_ReadBuffer(AT91C_BASE_US0, &pBuffer, 1);
      AT91C_BASE_US0->US_IER = AT91C_US_RXBUFF | AT91C_US_TIMEOUT;

//------------------------------------------------------------------------------
      // Устанавливаем тайм-аут
      AT91C_BASE_US0->US_RTOR=70u;
    }



Обработчик прерывания:

Код
void USART0_IrqHandler(void)
{
  if ((AT91C_BASE_US0->US_CSR & AT91C_US_TIMEOUT) > 0)  // если прерывание произошло по таймауту
  BSP_LED_Toggle(1);

else  if ((AT91C_BASE_US0->US_CSR & AT91C_US_RXRDY) == 1) { // если прерывание произошло по заполнению буфера

  USART_ReadBuffer(AT91C_BASE_US0, &pBuffer, 1);
  USART_Write(AT91C_BASE_US0,pBuffer,0);
  AT91C_BASE_US0->US_CR =AT91C_BASE_US0->US_CR | AT91C_US_STTTO; //Начинаем отсчёт тайм-аута
}
}


--------------------
Руслан
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jun 1 2010, 13:37
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Естественно виснет: прерывание TIMEOUT сбрасывается записью STTTO в US_CR, что в вашем коде не выполняется.
Регистр US_CR предназначен только для записи, "|" смысла не имеет.
Go to the top of the page
 
+Quote Post
athlon64
сообщение Jun 2 2010, 04:09
Сообщение #3


Частый гость
**

Группа: Свой
Сообщений: 156
Регистрация: 10-03-10
Из: Уфа
Пользователь №: 55 882



Спасибо
Исправил на AT91C_BASE_US0->US_CR = AT91C_US_STTTO; rolleyes.gif
Теперь ответ на каждый пакет приходит нормально и светодиод, который по таймауту должен загораться/гаснуть, отрабатывает верно.

Теперь вопрос скорее по операционке. После приёма по USART первого пакета останавливаются все остальные задачи (опрос по TWI, мигание диодом). Куда смотреть?

Обработчик теперь выглядит так:
Код
void USART0_IrqHandler(void)
{
  if ((AT91C_BASE_US0->US_CSR & AT91C_US_TIMEOUT) > 0) { // если прерывание произошло по таймауту
  BSP_LED_Toggle(1);
  AT91C_BASE_US0->US_CR = AT91C_US_STTTO; //Сбрасываем тайм-аут
  }

else  if ((AT91C_BASE_US0->US_CSR & AT91C_US_RXRDY) == 1) { // если прерывание произошло по заполнению буфера

USART_ReadBuffer(AT91C_BASE_US0, &pBuffer, 1);
USART_Write(AT91C_BASE_US0,pBuffer,0);
}


--------------------
Руслан
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jun 2 2010, 05:19
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(athlon64 @ Jun 2 2010, 08:09) *
Куда смотреть?

На оформление прерывания - очень похоже, что никто не пишет в AIC_EOICR. Обертка какая-нибудь в стартапе присутствует?
Go to the top of the page
 
+Quote Post
athlon64
сообщение Jun 2 2010, 06:33
Сообщение #5


Частый гость
**

Группа: Свой
Сообщений: 156
Регистрация: 10-03-10
Из: Уфа
Пользователь №: 55 882



Заметил что если в обработчик таймаута добавить команду чтения из порта байта, то ничего не виснет. wacko.gif
читается при этом повторно последний байт посылки, а первый байт следующей посылки теряется

Цитата
На оформление прерывания - очень похоже, что никто не пишет в AIC_EOICR. Обертка какая-нибудь в стартапе присутствует

да нет, стандартная инициализация оси и сразу инициализация порта
Код
    BSP_Init();                                                 /* Initialize BSP functions                                 */

    OS_CPU_InitExceptVect();                                    /* Initialize the Vectors at address 0x00                   */
        
#if (OS_TASK_STAT_EN > 0)
    OSStatInit();                                              
#endif
    
    Mem_Init();                                                 /* Initialize Memory Managment Module                       */    
    Math_Init();                                                /* Initialize Mathematical     Module                       */

    BSP_Ser_Init(115200);                                       /* Initialize Serial port                                   */
    APP_TRACE_INFO(("\n\n\r"));

    ConfigureUsart(0);


Сообщение отредактировал athlon64 - Jun 2 2010, 06:37


--------------------
Руслан
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jun 2 2010, 08:11
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(athlon64 @ Jun 2 2010, 10:33) *
Заметил что если в обработчик таймаута добавить команду чтения из порта байта, то ничего не виснет. wacko.gif

Понятно. Прерывание перепишите корректно:
Код
void USART0_IrqHandler(void)
{
  unsigned int status = AT91C_BASE_US0->US_CSR & AT91C_BASE_US0->US_IMR;

  if(status & AT91C_US_TIMEOUT) // если прерывание произошло по таймауту
  {
    BSP_LED_Toggle(1);
    AT91C_BASE_US0->US_CR = AT91C_US_STTTO; //Сбрасываем тайм-аут
  }
  if(status & AT91C_US_RXRDY) // если прерывание произошло по заполнению буфера
  {
    USART_ReadBuffer(AT91C_BASE_US0, &pBuffer, 1);
    USART_Write(AT91C_BASE_US0, pBuffer, 0);
  }
}


Цитата(athlon64 @ Jun 2 2010, 10:33) *
да нет, стандартная инициализация оси и сразу инициализация порта

Это не стартап.
Go to the top of the page
 
+Quote Post
athlon64
сообщение Jun 2 2010, 10:52
Сообщение #7


Частый гость
**

Группа: Свой
Сообщений: 156
Регистрация: 10-03-10
Из: Уфа
Пользователь №: 55 882



После исправления обработчика и ответный пакет перестал отправляться.
Всё оказалось банально.
В обработчике проверял не тот бит.smile.gif AT91C_US_RXRDY вместо AT91C_US_RXBUFF.
Приёмный буфер переполнялся и проц зависал


--------------------
Руслан
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jun 2 2010, 11:02
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Это хорошо. Но все равно лучше в обработчике реагировать сразу на все события, чтобы исключить оверхед, когда в CR установлено более одного бита.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 03:54
Рейтинг@Mail.ru


Страница сгенерированна за 0.01411 секунд с 7
ELECTRONIX ©2004-2016