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

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 уже не определяется. Код простейший. Подскажите пожалуйста что в нем не так?

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

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


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

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

#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?

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

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


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

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

 

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

 

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

IOWR_ALTERA_AVALON_UART_DIVISOR(base, div);

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

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


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

в статусе надо ещё проверять 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. Может кто тоже сталкивался с таким казусом?

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


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

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

 

*_bsp/drivers/src/altera_avalon_uart_*.c

 

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

 

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


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

ну в общем, чтобы по пунктам не обьяснять, смотрите в своем 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

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

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


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

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

 

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

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

 

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


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

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

 

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

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

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

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

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


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

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

 

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

 

IOWR_ALTERA_AVALON_UART_DIVISOR(UART_BASE, UART_FREQ / 9600 - 1)

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

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


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

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

Софт установка скорости не работает. Уже не знаю что и думать. Вывел 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);

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


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

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

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 компонентом?

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


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

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

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

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

open("/dev/uart0" ...

read, write

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

 

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


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

Понятно. Так и делаю. 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 корками.

Изменено пользователем arpa-net

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


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

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

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

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

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

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

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

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

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

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