Jump to content
    

Nios II Uart прерывания по приему байта

Организованы в системе на Nios II прерыывания Uart по приему одного байта на скорости 115200

Байты приходят короткими пакетами по 72 байта с периодом 0.5 сек. Если количество принятых байт равно

72 и первый байт равен 0х55 то Start = 1; В основном цикле main все сбрасывается (uart_count, Start).

...

alt_u8 Start = 0;
alt_u8 buf_uart[256];
alt_u16 uart_count = 0;
...
// Инициализация прерываний по UART
void Uart_irq_init()
{
    // Регистрация обработчика прерываний
    alt_irq_register(UART_0_IRQ, (void*)UART_0_IRQ, uart_isr);
}
...
// прерывания по UART
static void uart_isr(void* context, alt_u32 id)
{
  alt_u32 status;
  // Чтение регистра статуса для определения причины прерываний
  status = IORD_ALTERA_AVALON_UART_STATUS(UART_0_BASE);
  // Очистка всех флагов ошибок
  IOWR_ALTERA_AVALON_UART_STATUS(UART_0_BASE, 0);
  // Процесс чтения irq
  if (status&ALTERA_AVALON_UART_STATUS_RRDY_MSK)
  {
    buf_uart[uart_count] = IORD_ALTERA_AVALON_UART_RXDATA(UART_0_BASE);
    uart_count++;
  }
  if(uart_count == 72 && buf_uart[0] == 0x55)
  {
    Start = 1;
    uart_count = 0;
  }
}

Main

int main (void)
{
    alt_u8 led = 0x2;
    alt_u8 dir = 0;

    Uart_irq_init();
    alt_irq_enabled();

    // главный цикл
  while(1)
  {
    if(Start == 1)
    {
        Start = 0;
        // бегущий светодиод
        if(led & 0x81)
            dir = (dir ^ 0x1);
        if(dir)
            led = led >> 1;
        else
            led = led << 1;
        // запись в PIO_0_BASE (0x00000000) led
        IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, led);
    }
  }
  return 0;
}

 

Данный тест проводится на Циклоне 4 (DE0Nano Terasic). Проблема в том, что если количество байт в пакете небольшое (~40) то все работает нормально. С увеличением количества байт в пекете очевидно сбивается счетчик uart_count и первый синхробайт 0x55 уже не определяется. Код простейший. Подскажите пожалуйста что в нем не так?

Edited by Acvarif

Share this post


Link to post
Share on other sites

Немного переделал код. Заработало.

#include "system.h"
#include "altera_avalon_pio_regs.h"
#include "alt_types.h"
#include "stdio.h"
#include "sys/alt_irq.h"
#include "altera_avalon_uart_regs.h"
#include <unistd.h>
#include <io.h>

//---------------------------------------------------------------------------------------------
// Константы

#define BAUD_RATE 115200

//---------------------------------------------------------------------------------------------
// Объявления функций

void UartIsr(void* context, alt_u16 id);
void InitUart(alt_u32 BaudRate);

//---------------------------------------------------------------------------------------------
// Глобальные переменные

alt_u8 Start = 0;
alt_u8 Buf_uart[256];
alt_u16 Uart_count = 0;

//---------------------------------------------------------------------------------------------
// Функции

//---------------------------------------------------------------------------------------------
// прерывания по UART

void UartIsr(void* context, alt_u16 id)
{
 alt_u16 status;
 // Чтение регистра статуса для определения причины прерываний
 status = IORD_ALTERA_AVALON_UART_STATUS(UART_0_BASE);
 // Процесс чтения irq
 if (status & ALTERA_AVALON_UART_STATUS_RRDY_MSK)
 {
   Buf_uart[uart_count] = IORD_ALTERA_AVALON_UART_RXDATA(UART_0_BASE);
   Uart_count++;
   // Очистка всех флагов ошибок
   IOWR_ALTERA_AVALON_UART_STATUS(UART_0_BASE, 0);
 }
 if(Uart_count >= 72 && Buf_uart[0] == 0x55)
 {
Start = 1;
   Uart_count = 0;
 }
}

//---------------------------------------------------------------------------------------------
// инициализация Uart

void InitUart(alt_u32 BaudRate)
{
alt_u16 context_uart;
alt_u16 divisor;

   divisor = (ALT_CPU_FREQ/BaudRate) + 1;
   IOWR_ALTERA_AVALON_UART_DIVISOR(UART_0_BASE, divisor);
   IOWR_ALTERA_AVALON_UART_CONTROL(UART_0_BASE, ALTERA_AVALON_UART_CONTROL_RRDY_MSK);
// регистрация прерываний UART_0_IRQ
alt_irq_register(UART_0_IRQ, &context_uart, UartIsr);
//	alt_irq_enable (UART_0_IRQ);
}

//---------------------------------------------------------------------------------------------

int main (void)
{
alt_u8 led = 0x2;
alt_u8 dir = 0;

InitUart(BAUD_RATE);
alt_irq_enabled();

   // main while
while(1)
{
	if(Start == 1)
	{
		Start = 0;
		// running led
		if(led & 0x81)
			dir = (dir ^ 0x1);
		if(dir)
			led = led >> 1;
		else
			led = led << 1;
		// write in PIO_0_BASE led
		IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, led);
	}
}
return 0;
}

Далее в SOPC в модуле UART убраз птичку с "Fixed baud rate" для возможности программного назначения частоты бод. Код (или SOPC система) не работает. Можно-ли программно корректировать частоту бод в модуле UART Nios?

Edited by Acvarif

Share this post


Link to post
Share on other sites

в статусе надо ещё проверять ALTERA_AVALON_UART_STATUS_PE_MSK и ALTERA_AVALON_UART_STATUS_FE_MSK

 

очистку флагов надо делать в IOWR_ALTERA_AVALON_UART_CONTROL, хотя может адреса со статусом и совпадают, не помню

 

смена скорости:

IOWR_ALTERA_AVALON_UART_DIVISOR(base, div);

Edited by gridinp

Share this post


Link to post
Share on other sites

в статусе надо ещё проверять ALTERA_AVALON_UART_STATUS_PE_MSK и ALTERA_AVALON_UART_STATUS_FE_MSK

 

очистку флагов надо делать в IOWR_ALTERA_AVALON_UART_CONTROL, хотя может адреса со статусом и совпадают, не помню

 

смена скорости:

IOWR_ALTERA_AVALON_UART_DIVISOR(base, div);

С флагами вроде все нормально. Хотя еще проверю... А вот с установкой скорости все тоже. Не работает.

Код:

alt_u16 context_uart;
    alt_u16 divisor;

    divisor = (ALT_CPU_FREQ/BaudRate) + 1;
    IOWR_ALTERA_AVALON_UART_DIVISOR(UART_0_BASE, divisor);
    IOWR_ALTERA_AVALON_UART_CONTROL(UART_0_BASE, ALTERA_AVALON_UART_CONTROL_RRDY_MSK);

Работатает только при

#define UART_0_FIXED_BAUD 1

Странно. Думал имеется возможность немного корректировать скорость... модуль UART Quartus 11.0 Sp1. Может кто тоже сталкивался с таким казусом?

Share this post


Link to post
Share on other sites

ну в общем, чтобы по пунктам не обьяснять, смотрите в своем bsp файлы:

 

*_bsp/drivers/src/altera_avalon_uart_*.c

 

в частности функцию altera_avalon_uart_rxirq

 

Share this post


Link to post
Share on other sites

ну в общем, чтобы по пунктам не обьяснять, смотрите в своем bsp файлы:

 

*_bsp/drivers/src/altera_avalon_uart_*.c

 

в частности функцию altera_avalon_uart_rxirq

Да, есть такая функция

/*
* altera_avalon_uart_rxirq() is called by altera_avalon_uart_irq() to 
* process a receive interrupt. It transfers the incoming character into 
* the receive circular buffer, and sets the apropriate flags to indicate 
* that there is data ready to be processed.
*/
static void 
altera_avalon_uart_rxirq(altera_avalon_uart_state* sp, alt_u32 status)
{
 alt_u32 next;

 /* If there was an error, discard the data */

 if (status & (ALTERA_AVALON_UART_STATUS_PE_MSK | 
			  ALTERA_AVALON_UART_STATUS_FE_MSK))
 {
return;
 }

 /*
  * In a multi-threaded environment, set the read event flag to indicate
  * that there is data ready. This is only done if the circular buffer was
  * previously empty.
  */

 if (sp->rx_end == sp->rx_start)
 {
ALT_FLAG_POST (sp->events, ALT_UART_READ_RDY, OS_FLAG_SET);
 }

 /* Determine which slot to use next in the circular buffer */

 next = (sp->rx_end + 1) & ALT_AVALON_UART_BUF_MSK;

 /* Transfer data from the device to the circular buffer */

 sp->rx_buf[sp->rx_end] = IORD_ALTERA_AVALON_UART_RXDATA(sp->base);

 sp->rx_end = next;

 next = (sp->rx_end + 1) & ALT_AVALON_UART_BUF_MSK;

 /*
  * If the cicular buffer was full, disable interrupts. Interrupts will be
  * re-enabled when data is removed from the buffer.
  */

 if (next == sp->rx_start)
 {
sp->ctrl &= ~ALTERA_AVALON_UART_CONTROL_RRDY_MSK;
IOWR_ALTERA_AVALON_UART_CONTROL(sp->base, sp->ctrl); 
 }   
}

Находится в файле altera_avalon_uart_init.c

Как она связана с тем, что uart не работает при софт установке скорости бод

#define UART_0_FIXED_BAUD 0

Edited by Acvarif

Share this post


Link to post
Share on other sites

да это про обработку прерываний функция, что нельзя данные забирать, когда ошибка приема

 

а скорость в другом файле, там надо делить частоту на которой uart работает, ну что там думать

порт на передачу и осциллографом посмотреть

 

Share this post


Link to post
Share on other sites

да это про обработку прерываний функция, что нельзя данные забирать, когда ошибка приема

 

а скорость в другом файле, там надо делить частоту на которой uart работает, ну что там думать

порт на передачу и осциллографом посмотреть

Спасибо. Про прием понятно.

Софт установка скорости не работает. Уже не знаю что и думать. Вывел UART_TXD на осциллограф. При #define UART_0_FIXED_BAUD 1 все работает. При #define UART_0_FIXED_BAUD 0 на выходе логическая 1. Ошибка компонента SOPC UART?

Share this post


Link to post
Share on other sites

а, что вы кладете в делитель?

 

должно быть примерно так:

 

IOWR_ALTERA_AVALON_UART_DIVISOR(UART_BASE, UART_FREQ / 9600 - 1)

Edited by gridinp

Share this post


Link to post
Share on other sites

Спасибо. Про прием понятно.

Софт установка скорости не работает. Уже не знаю что и думать. Вывел UART_TXD на осциллограф. При #define UART_0_FIXED_BAUD 1 все работает. При #define UART_0_FIXED_BAUD 0 на выходе логическая 1. Ошибка компонента SOPC UART?

 

Вот так делитель считается:

int divisor = (int) ( UART_FREQ / baud + 0.5);

Share this post


Link to post
Share on other sites

Вот так делитель считается:

int divisor = (int) ( UART_FREQ / baud + 0.5);

Понятно. Так и делаю. Uart не работает. Работает только при

#define UART_0_FIXED_BAUD 1

И вообще странности.

Вот прием по прерыванию

  // Чтение регистра статуса для определения причины прерываний
  status = IORD_ALTERA_AVALON_UART_STATUS(UART_0_BASE);
  // Очистка всех флагов ошибок
  IOWR_ALTERA_AVALON_UART_STATUS(UART_0_BASE, 0);

  // Процесс чтения irq (если байт получен  бит RRDY = 1)
  if (status & ALTERA_AVALON_UART_STATUS_RRDY_MSK)
  {
      // Чтение данных если нет ошибок приема (PE-ошибка бита паритета FE-некоректный стоп бит)
//      if (!(status & (ALTERA_AVALON_UART_STATUS_PE_MSK | ALTERA_AVALON_UART_STATUS_FE_MSK)))
      if (!(status & (ALTERA_AVALON_UART_STATUS_FE_MSK)))
      {
            BufRxUart[UartRxCount] = IORD_ALTERA_AVALON_UART_RXDATA(UART_0_BASE);
            UartRxCount++;
      }
  }

То работает то нет при разной длине входного пакета. Может действительно в Quartus11.0 проблема с Uart компонентом?

Share this post


Link to post
Share on other sites

То работает то нет при разной длине входного пакета. Может действительно в Quartus11.0 проблема с Uart компонентом?

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

драйвером прием/передачу

open("/dev/uart0" ...

read, write

ioctl - для смены скорости

 

Share this post


Link to post
Share on other sites

Понятно. Так и делаю. Uart не работает. Работает только при
#define UART_0_FIXED_BAUD 1

И вообще странности.

Вот прием по прерыванию

  // Чтение регистра статуса для определения причины прерываний
  status = IORD_ALTERA_AVALON_UART_STATUS(UART_0_BASE);
  // Очистка всех флагов ошибок
  IOWR_ALTERA_AVALON_UART_STATUS(UART_0_BASE, 0);

  // Процесс чтения irq (если байт получен  бит RRDY = 1)
  if (status & ALTERA_AVALON_UART_STATUS_RRDY_MSK)
  {
      // Чтение данных если нет ошибок приема (PE-ошибка бита паритета FE-некоректный стоп бит)
//      if (!(status & (ALTERA_AVALON_UART_STATUS_PE_MSK | ALTERA_AVALON_UART_STATUS_FE_MSK)))
      if (!(status & (ALTERA_AVALON_UART_STATUS_FE_MSK)))
      {
            BufRxUart[UartRxCount] = IORD_ALTERA_AVALON_UART_RXDATA(UART_0_BASE);
            UartRxCount++;
      }
  }

То работает то нет при разной длине входного пакета. Может действительно в Quartus11.0 проблема с Uart компонентом?

 

Возможно в 11-м квартусе неправильно генерируется bsp. Я бы вам рекомендовал уставновить quartus 15.1 web edition, он бесплатный. Для вашего hello world вполне сойдет. Попробуйте для начала читать и менять скорость c помощью HAL драйверов. Можете загрузить ваш qsys проект, могу глянуть что не так.

Если ваш altera avalon uart не справляется c приемом, то можете использовать fifo uart с altera wiki:

http://www.alterawiki.com/wiki/FIFOed_Avalon_Uart

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

Edited by arpa-net

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...