Hi everybody,
Could you please help me: i need to use an uart interrupt routine in a RTX code. I've already found some examples for the uart interrupt routine, but i cannot make it work using tasks. Has anybody an example to show me how to use it. Thanks
static void process_uart_irq(int32_t a_uart_source) { int32_t l_bytes ; uint32_t l_now = T3TC ; // guard againt an overflow of interrupts if ( (l_now - s_uart_isr_previous_entry_time[a_uart_source]) < T3_x_MICROSECONDS(20) ) { if (++s_uart_isr_flood[a_uart_source] > UART_ISR_FLOOD_RESET_THRSHOLD) { // reset peripheral reset_uart(a_uart_source) ; s_uart_isr_flood[a_uart_source] = 0 ; } } else { s_uart_isr_flood[a_uart_source] = 0 ; } s_uart_isr_previous_entry_time[a_uart_source] = l_now ; switch ( (*sp_effective_IIR[a_uart_source]>>1) & 0x7) // interogate bits 3:1 to identify interrupt reason { case 0x6: // Character Time-out Indicator (CTI) { if (circular_buffer_enqueue(&g_data_interface.uart_rx_circular_buffer[a_uart_source], *sp_effective_RBR[a_uart_source] ) ) { // buffer full // reset buffer circular_buffer_init(&g_data_interface.uart_rx_circular_buffer[a_uart_source], g_data_interface.uart_rx_circular_buffer[a_uart_source].size) ; } } break ; case 0x2: // Receive Data Available (RDA) { // collect frame characters l_bytes = BLUETOOTH_UART_RX_FIFO_TRIGGER_LEVEL ; do { if (circular_buffer_enqueue(&g_data_interface.uart_rx_circular_buffer[a_uart_source], *sp_effective_RBR[a_uart_source] ) ) { // buffer full // reset buffer circular_buffer_init(&g_data_interface.uart_rx_circular_buffer[a_uart_source], g_data_interface.uart_rx_circular_buffer[a_uart_source].size) ; break ; } } while ( (--l_bytes) > 0) ; } break ;
There is no reason to disable interrupts - notice the usage of a circular buffer (which is emptied somewhere else). The application should be allowed to be interrupted while processing previous received data. You probably never encountered problems but reduced your program's responsiveness.
Notice how the ISR posts data in the buffer and "forgets" about it, greatly reducing ISR overhead.
Disabling the interrupt also increased the chances that you will actually miss a character, if you processing time is too long resulting in hardware buffer overflow. Hardware flow control can help with that, though.
I agree that you can't 'process' the data with the interrupt disabled as this could obviously take too long but I see no reason why you can't have the circular buffer in the task space.
Basically this is how I set it up and this has always worked for communication with terminals and also with machines using defined protocols.
__task void task_uart(void) { for (;;) { os_evt_wait_or(CHAR_READY_EVENT, 0xFFFF); // ADD BYTE TO MESSAGE OR BUFFER OR WHATEVER STRUCTURE NVIC_EnableIRQ(UART_IQRn); //IF ALL DATA IS RECEIVED (Meaning will depend on application) // swap to second receive buffer post message received event... } } void UART_IRQHandler (void) { uint32_t intsrc, tmp; /* Determine the interrupt source */ intsrc = UART_GetIntId(UART_PORT); tmp = intsrc & UART_IIR_INTID_MASK; // Receive Data Available if (tmp & UART_IIR_INTID_RDA) { last_received_char = UART_ReceiveByte(UART_PORT); NVIC_DisableIRQ(UART_IQRn); isr_evt_set (CHAR_READY_EVENT, t_uart); // Send Event Flag to task } NVIC_ClearPendingIRQ(TERNIAL_IQRn); // Clear Interrupt }
Since "isr_evt_set" has a queue behind it (as far as I can remember), there is no risk of missing signals even if your application does not respond fast enough for short bursts of data. Therefore, as long as the queue is big enough (RTX allows setting its size up to a limit (at least, officially), FreeRTOS can offer an arbitrary size and type) there is really no reason to disable the interrupt source. Why did you do it in the first place? Maybe there was some good reason for it that we are not aware of?
One thing here is that it is possible to use a mailbox feature and send received characters as the mailbox "pointer" to the read task. The size of the mailbox obviously controls the number of characters that can be queued this way.
It is also possible to just signal the read task that there are one or more characters available in the incomming circular buffer. The read task then clears this signal when it starts processing data. If the ISR is run during the processing, and inserts more data, then the read task might get accidentaly activated once without any more data avaiable. But that isn't really a problem.
The concept of just flagging existence of data means that there isn't any issue of any queue depth for the RTOS. It's just a question if the read task should freeze or not when it has consumed all data in the ring buffer and then performs a new wait. Has the ISR run during the read process, then the task will not block (but might not find more data). Has the ISR not run during the read process, then the read task will get stuck waiting for a new wakeup signal.