Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Time-out в USART
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
athlon64
Процессор 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; //Начинаем отсчёт тайм-аута
}
}
aaarrr
Естественно виснет: прерывание TIMEOUT сбрасывается записью STTTO в US_CR, что в вашем коде не выполняется.
Регистр US_CR предназначен только для записи, "|" смысла не имеет.
athlon64
Спасибо
Исправил на 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);
}
aaarrr
Цитата(athlon64 @ Jun 2 2010, 08:09) *
Куда смотреть?

На оформление прерывания - очень похоже, что никто не пишет в AIC_EOICR. Обертка какая-нибудь в стартапе присутствует?
athlon64
Заметил что если в обработчик таймаута добавить команду чтения из порта байта, то ничего не виснет. 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);
aaarrr
Цитата(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) *
да нет, стандартная инициализация оси и сразу инициализация порта

Это не стартап.
athlon64
После исправления обработчика и ответный пакет перестал отправляться.
Всё оказалось банально.
В обработчике проверял не тот бит.smile.gif AT91C_US_RXRDY вместо AT91C_US_RXBUFF.
Приёмный буфер переполнялся и проц зависал
aaarrr
Это хорошо. Но все равно лучше в обработчике реагировать сразу на все события, чтобы исключить оверхед, когда в CR установлено более одного бита.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.