|
|
  |
Nios II Uart прерывания по приему байта |
|
|
|
Jun 26 2016, 07:29
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Организованы в системе на 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 - Jun 26 2016, 07:37
|
|
|
|
|
Jun 26 2016, 10:20
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Немного переделал код. Заработало. CODE #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 - Jun 27 2016, 09:26
|
|
|
|
|
Jun 27 2016, 12:17
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(gridinp @ Jun 27 2016, 13:05)  в статусе надо ещё проверять 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. Может кто тоже сталкивался с таким казусом?
|
|
|
|
|
Jun 27 2016, 18:18
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(gridinp @ Jun 27 2016, 16:40)  ну в общем, чтобы по пунктам не обьяснять, смотрите в своем bsp файлы:
*_bsp/drivers/src/altera_avalon_uart_*.c
в частности функцию altera_avalon_uart_rxirq Да, есть такая функция CODE /* * 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 - Jun 27 2016, 18:19
|
|
|
|
|
Jun 28 2016, 11:05
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(gridinp @ Jun 27 2016, 22:46)  да это про обработку прерываний функция, что нельзя данные забирать, когда ошибка приема
а скорость в другом файле, там надо делить частоту на которой uart работает, ну что там думать порт на передачу и осциллографом посмотреть Спасибо. Про прием понятно. Софт установка скорости не работает. Уже не знаю что и думать. Вывел UART_TXD на осциллограф. При #define UART_0_FIXED_BAUD 1 все работает. При #define UART_0_FIXED_BAUD 0 на выходе логическая 1. Ошибка компонента SOPC UART?
|
|
|
|
|
Jun 29 2016, 00:01
|
Группа: Участник
Сообщений: 7
Регистрация: 14-04-16
Пользователь №: 91 285

|
Цитата(Acvarif @ Jun 28 2016, 12:05)  Спасибо. Про прием понятно. Софт установка скорости не работает. Уже не знаю что и думать. Вывел 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);
|
|
|
|
|
Jun 29 2016, 10:28
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(arpa-net @ Jun 29 2016, 03:01)  Вот так делитель считается: 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 компонентом?
|
|
|
|
|
Jun 29 2016, 13:59
|
Частый гость
 
Группа: Участник
Сообщений: 121
Регистрация: 7-04-08
Из: Наро-Фоминск
Пользователь №: 36 543

|
Цитата(Acvarif @ Jun 29 2016, 13:28)  То работает то нет при разной длине входного пакета. Может действительно в Quartus11.0 проблема с Uart компонентом? странно конечно, прежде чем в глубину копать, может попробовать штатным драйвером прием/передачу open("/dev/uart0" ... read, write ioctl - для смены скорости
|
|
|
|
|
Jun 29 2016, 17:48
|
Группа: Участник
Сообщений: 7
Регистрация: 14-04-16
Пользователь №: 91 285

|
Цитата(Acvarif @ Jun 29 2016, 11:28)  Понятно. Так и делаю. 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 - Jun 29 2016, 18:20
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|