acvarif 0 June 26, 2016 Posted June 26, 2016 (edited) · Report post Организованы в системе на 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 June 26, 2016 by Acvarif Quote Share this post Link to post Share on other sites More sharing options...
acvarif 0 June 26, 2016 Posted June 26, 2016 (edited) · Report post Немного переделал код. Заработало. #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 June 27, 2016 by Acvarif Quote Share this post Link to post Share on other sites More sharing options...
gridinp 11 June 27, 2016 Posted June 27, 2016 (edited) · Report post в статусе надо ещё проверять 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 June 27, 2016 by gridinp Quote Share this post Link to post Share on other sites More sharing options...
acvarif 0 June 27, 2016 Posted June 27, 2016 · Report post в статусе надо ещё проверять 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. Может кто тоже сталкивался с таким казусом? Quote Share this post Link to post Share on other sites More sharing options...
gridinp 11 June 27, 2016 Posted June 27, 2016 · Report post ну в общем, чтобы по пунктам не обьяснять, смотрите в своем bsp файлы: *_bsp/drivers/src/altera_avalon_uart_*.c в частности функцию altera_avalon_uart_rxirq Quote Share this post Link to post Share on other sites More sharing options...
acvarif 0 June 27, 2016 Posted June 27, 2016 (edited) · Report post ну в общем, чтобы по пунктам не обьяснять, смотрите в своем 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 June 27, 2016 by Acvarif Quote Share this post Link to post Share on other sites More sharing options...
gridinp 11 June 27, 2016 Posted June 27, 2016 · Report post да это про обработку прерываний функция, что нельзя данные забирать, когда ошибка приема а скорость в другом файле, там надо делить частоту на которой uart работает, ну что там думать порт на передачу и осциллографом посмотреть Quote Share this post Link to post Share on other sites More sharing options...
acvarif 0 June 28, 2016 Posted June 28, 2016 · Report post да это про обработку прерываний функция, что нельзя данные забирать, когда ошибка приема а скорость в другом файле, там надо делить частоту на которой uart работает, ну что там думать порт на передачу и осциллографом посмотреть Спасибо. Про прием понятно. Софт установка скорости не работает. Уже не знаю что и думать. Вывел UART_TXD на осциллограф. При #define UART_0_FIXED_BAUD 1 все работает. При #define UART_0_FIXED_BAUD 0 на выходе логическая 1. Ошибка компонента SOPC UART? Quote Share this post Link to post Share on other sites More sharing options...
gridinp 11 June 28, 2016 Posted June 28, 2016 (edited) · Report post а, что вы кладете в делитель? должно быть примерно так: IOWR_ALTERA_AVALON_UART_DIVISOR(UART_BASE, UART_FREQ / 9600 - 1) Edited June 28, 2016 by gridinp Quote Share this post Link to post Share on other sites More sharing options...
arpa-net 0 June 29, 2016 Posted June 29, 2016 · Report post Спасибо. Про прием понятно. Софт установка скорости не работает. Уже не знаю что и думать. Вывел 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); Quote Share this post Link to post Share on other sites More sharing options...
acvarif 0 June 29, 2016 Posted June 29, 2016 · Report post Вот так делитель считается: 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 компонентом? Quote Share this post Link to post Share on other sites More sharing options...
gridinp 11 June 29, 2016 Posted June 29, 2016 · Report post То работает то нет при разной длине входного пакета. Может действительно в Quartus11.0 проблема с Uart компонентом? странно конечно, прежде чем в глубину копать, может попробовать штатным драйвером прием/передачу open("/dev/uart0" ... read, write ioctl - для смены скорости Quote Share this post Link to post Share on other sites More sharing options...
arpa-net 0 June 29, 2016 Posted June 29, 2016 (edited) · Report post Понятно. Так и делаю. 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 June 29, 2016 by arpa-net Quote Share this post Link to post Share on other sites More sharing options...