acvarif 0 26 июня, 2016 Опубликовано 26 июня, 2016 (изменено) · Жалоба Организованы в системе на 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 уже не определяется. Код простейший. Подскажите пожалуйста что в нем не так? Изменено 26 июня, 2016 пользователем Acvarif Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
acvarif 0 26 июня, 2016 Опубликовано 26 июня, 2016 (изменено) · Жалоба Немного переделал код. Заработало. #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? Изменено 27 июня, 2016 пользователем Acvarif Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gridinp 2 27 июня, 2016 Опубликовано 27 июня, 2016 (изменено) · Жалоба в статусе надо ещё проверять ALTERA_AVALON_UART_STATUS_PE_MSK и ALTERA_AVALON_UART_STATUS_FE_MSK очистку флагов надо делать в IOWR_ALTERA_AVALON_UART_CONTROL, хотя может адреса со статусом и совпадают, не помню смена скорости: IOWR_ALTERA_AVALON_UART_DIVISOR(base, div); Изменено 27 июня, 2016 пользователем gridinp Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
acvarif 0 27 июня, 2016 Опубликовано 27 июня, 2016 · Жалоба в статусе надо ещё проверять 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. Может кто тоже сталкивался с таким казусом? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gridinp 2 27 июня, 2016 Опубликовано 27 июня, 2016 · Жалоба ну в общем, чтобы по пунктам не обьяснять, смотрите в своем bsp файлы: *_bsp/drivers/src/altera_avalon_uart_*.c в частности функцию altera_avalon_uart_rxirq Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
acvarif 0 27 июня, 2016 Опубликовано 27 июня, 2016 (изменено) · Жалоба ну в общем, чтобы по пунктам не обьяснять, смотрите в своем 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 Изменено 27 июня, 2016 пользователем Acvarif Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gridinp 2 27 июня, 2016 Опубликовано 27 июня, 2016 · Жалоба да это про обработку прерываний функция, что нельзя данные забирать, когда ошибка приема а скорость в другом файле, там надо делить частоту на которой uart работает, ну что там думать порт на передачу и осциллографом посмотреть Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
acvarif 0 28 июня, 2016 Опубликовано 28 июня, 2016 · Жалоба да это про обработку прерываний функция, что нельзя данные забирать, когда ошибка приема а скорость в другом файле, там надо делить частоту на которой uart работает, ну что там думать порт на передачу и осциллографом посмотреть Спасибо. Про прием понятно. Софт установка скорости не работает. Уже не знаю что и думать. Вывел UART_TXD на осциллограф. При #define UART_0_FIXED_BAUD 1 все работает. При #define UART_0_FIXED_BAUD 0 на выходе логическая 1. Ошибка компонента SOPC UART? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gridinp 2 28 июня, 2016 Опубликовано 28 июня, 2016 (изменено) · Жалоба а, что вы кладете в делитель? должно быть примерно так: IOWR_ALTERA_AVALON_UART_DIVISOR(UART_BASE, UART_FREQ / 9600 - 1) Изменено 28 июня, 2016 пользователем gridinp Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
arpa-net 0 29 июня, 2016 Опубликовано 29 июня, 2016 · Жалоба Спасибо. Про прием понятно. Софт установка скорости не работает. Уже не знаю что и думать. Вывел 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); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
acvarif 0 29 июня, 2016 Опубликовано 29 июня, 2016 · Жалоба Вот так делитель считается: 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 компонентом? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gridinp 2 29 июня, 2016 Опубликовано 29 июня, 2016 · Жалоба То работает то нет при разной длине входного пакета. Может действительно в Quartus11.0 проблема с Uart компонентом? странно конечно, прежде чем в глубину копать, может попробовать штатным драйвером прием/передачу open("/dev/uart0" ... read, write ioctl - для смены скорости Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
arpa-net 0 29 июня, 2016 Опубликовано 29 июня, 2016 (изменено) · Жалоба Понятно. Так и делаю. 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 корками. Изменено 29 июня, 2016 пользователем arpa-net Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться