Example #1
0
void platform_uart_irq( platform_uart_driver_t* driver )
{
    uint32_t status = usart_get_status( driver->peripheral->peripheral );
    uint32_t mask = usart_get_interrupt_mask( driver->peripheral->peripheral );
    Pdc* pdc_register = usart_get_pdc_base( driver->peripheral->peripheral );

    /* ENDTX flag is set when Tx DMA transfer is done
     */
    if ( ( mask & US_IMR_ENDTX ) && ( status & US_CSR_ENDTX ) )
    {
        pdc_packet_t dma_packet;

        /* ENDTX is cleared when TCR or TNCR is set to a non-zero value, which effectively
         * starts another Tx DMA transaction. To work around this, disable Tx before
         * performing a dummy Tx init.
         */
        pdc_disable_transfer( usart_get_pdc_base( driver->peripheral->peripheral ), PERIPH_PTCR_TXTDIS );

        dma_packet.ul_addr = (uint32_t)0;
        dma_packet.ul_size = (uint32_t)1;

        pdc_tx_init( usart_get_pdc_base( USART1 ), &dma_packet, NULL );

        /* Notifies waiting thread that Tx DMA transfer is complete */
        host_rtos_set_semaphore( &driver->tx_dma_complete, WICED_TRUE );
    }

    /* ENDRX flag is set when RCR is 0. RNPR and RNCR values are then copied into
     * RPR and RCR, respectively, while the Tx tranfer continues. We now need to
     * prepare RNPR and RNCR for the next iteration.
     */
    if ( ( mask & US_IMR_ENDRX ) && ( status & US_CSR_ENDRX ) )
    {
        pdc_register->PERIPH_RNPR = (uint32_t)driver->rx_ring_buffer->buffer;
        pdc_register->PERIPH_RNCR = (uint32_t)driver->rx_ring_buffer->size;
    }

    /* RXRDY interrupt is triggered and flag is set when a new character has been
     * received but not yet read from the US_RHR. When this interrupt executes,
     * the DMA engine already read the character out from the US_RHR and RXRDY flag
     * is no longer asserted. The code below updates the ring buffer parameters
     * to keep them current
     */
    if ( mask & US_CSR_RXRDY )
    {
        driver->rx_ring_buffer->tail = driver->rx_ring_buffer->size - pdc_register->PERIPH_RCR;

        // Notify thread if sufficient data are available
        if ( ( driver->rx_transfer_size > 0 ) && ( ring_buffer_used_space( driver->rx_ring_buffer ) >= driver->rx_transfer_size ) )
        {
            host_rtos_set_semaphore( &driver->rx_dma_complete, WICED_TRUE );
            driver->rx_transfer_size = 0;
        }
    }
}
Example #2
0
void uart_rx_notify(uint8_t port)
{
	Usart* usart = get_usart(port);
	// If UART is open
	if (usart_get_interrupt_mask(usart)
		& US_IMR_RXRDY) {
		// Enable UART TX interrupt to send a new value
		usart_enable_tx(usart);
		usart_enable_interrupt(usart, US_IER_TXRDY);
	}
}
Example #3
0
void uart_rx_notify(uint8_t port)
{
	UNUSED(port);
	// If UART is open
	if (usart_get_interrupt_mask(USART_BASE)
		& US_IMR_RXRDY) {
		// Enable UART TX interrupt to send a new value
		usart_enable_tx(USART_BASE);
		usart_enable_interrupt(USART_BASE, US_IER_TXRDY);
	}
}
Example #4
0
static inline void uart_irq(Usart *const usart, uint32_t index)
{
    MBED_ASSERT(usart != (void*)0);
    uint32_t mask, status;
    /* Read and clear mask. */
    status = usart_get_status(usart);
    mask = usart_get_interrupt_mask(usart);
    status &= mask;

    if (serial_irq_ids[index] != 0) {
        if (status & US_IER_RXRDY) { /*For Receive Complete*/
            if (irq_handler) {
                irq_handler(serial_irq_ids[index], RxIrq);
            }
        }
    }
}
Example #5
0
/*
 * It should be noted that the com test tasks (which use make use of this file)
 * are included to demonstrate queues being used to communicate between tasks
 * and interrupts, and to demonstrate a context switch being performed from
 * inside an interrupt service routine.  The serial driver used here is *not*
 * intended to represent an efficient implementation.  Real applications should
 * make use of the USARTS peripheral DMA channel (PDC).
 */
void USART0_Handler( void )
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
uint8_t ucChar;
uint32_t ulChar;
uint32_t ulUSARTStatus, ulUSARTMask;

	ulUSARTStatus = usart_get_status( serUSART_PORT );
	ulUSARTMask = usart_get_interrupt_mask( serUSART_PORT );
	ulUSARTStatus &= ulUSARTMask;

	if( ( ulUSARTStatus & US_CSR_TXRDY ) != 0UL )
	{
		/* The interrupt was caused by the TX register becoming empty.  Are
		there any more characters to transmit? */
		if( xQueueReceiveFromISR( xCharsForTx, &ucChar, &xHigherPriorityTaskWoken ) == pdTRUE )
		{
			/* A character was retrieved from the queue so can be sent to the
			USART now. */
			usart_putchar( serUSART_PORT, ( uint32_t ) ucChar );
		}
		else
		{
			usart_disable_interrupt( serUSART_PORT, US_IER_TXRDY );
		}
	}

	if( ( ulUSARTStatus & US_CSR_RXRDY ) != 0UL )
	{
		/* A character has been received on the USART, send it to the Rx
		handler task. */
		usart_getchar( serUSART_PORT, &ulChar );
		ucChar = ( uint8_t ) ( ulChar & 0xffUL );
		xQueueSendFromISR( xRxedChars, &ucChar, &xHigherPriorityTaskWoken );
	}

	/* If sending or receiving from a queue has caused a task to unblock, and
	the unblocked task has a priority equal to or higher than the currently
	running task (the task this ISR interrupted), then xHigherPriorityTaskWoken
	will have automatically been set to pdTRUE within the queue send or receive
	function.  portEND_SWITCHING_ISR() will then ensure that this ISR returns
	directly to the higher priority unblocked task. */
	portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}
Example #6
0
int serial_rx_irq_handler_asynch(serial_t *obj)
{
    /* Sanity check arguments */
    MBED_ASSERT(obj);
    uint32_t ul_status, ulmask;

    /* Read USART Status. */
    ul_status = usart_get_status(_USART(obj));
    ulmask = usart_get_interrupt_mask(_USART(obj));
    ul_status &= ulmask;

    if (ul_status & US_CSR_OVRE) { /* Overrun Error */
        usart_disable_interrupt(_USART(obj), US_IDR_OVRE);
        serial_rx_abort_asynch(obj);
        return SERIAL_EVENT_RX_OVERFLOW;
    }
    if (ul_status & US_CSR_FRAME) { /* Framing Error */
        usart_disable_interrupt(_USART(obj), US_IDR_FRAME);
        serial_rx_abort_asynch(obj);
        return SERIAL_EVENT_RX_FRAMING_ERROR;
    }
    if (ul_status & US_CSR_PARE) { /* Parity Error */
        usart_disable_interrupt(_USART(obj), US_IDR_PARE);
        serial_rx_abort_asynch(obj);
        return SERIAL_EVENT_RX_PARITY_ERROR;
    }
    if ((ul_status & (US_IER_RXBUFF | US_IER_CMP)) ==  (US_IER_RXBUFF | US_IER_CMP)) { /* Character match in last character in transfer*/
        usart_disable_interrupt(_USART(obj), US_IDR_CMP);
        serial_rx_abort_asynch(obj);
        return SERIAL_EVENT_RX_COMPLETE|SERIAL_EVENT_RX_CHARACTER_MATCH;
    }
    if (ul_status & US_IER_CMP) { /* Character match */
        usart_disable_interrupt(_USART(obj), US_IDR_CMP);
        if (pSERIAL_S(obj)->events == SERIAL_EVENT_RX_CHARACTER_MATCH) { /*if character match is the only event abort transfer */
            serial_rx_abort_asynch(obj);
        }
        return SERIAL_EVENT_RX_CHARACTER_MATCH;
    }
    if (ul_status & US_IER_RXBUFF) { /* Reception Complete */
        serial_rx_abort_asynch(obj);
        return SERIAL_EVENT_RX_COMPLETE;
    }
    return 0;
}
Example #7
0
int serial_irq_handler_asynch(serial_t *obj)
{
    /* Sanity check arguments */
    MBED_ASSERT(obj);
    uint32_t ul_status, ulmask;

    /* Read USART Status. */
    ul_status = usart_get_status(_USART(obj));
    ulmask = usart_get_interrupt_mask(_USART(obj));

    ul_status &= ulmask;

    if (ul_status & (US_CSR_RXBUFF | US_CSR_OVRE | US_CSR_FRAME | US_CSR_PARE | US_IER_CMP)) {
        return serial_rx_irq_handler_asynch(obj);
    }
    if (ul_status & US_CSR_TXBUFE) {
        return serial_tx_irq_handler_asynch(obj);
    }
    return 0;
}
Example #8
0
void uart_config(uint8_t port, usb_cdc_line_coding_t * cfg)
{
	Usart* usart = get_usart(port);
	uint32_t stopbits, parity, databits;
	uint32_t imr;

	switch (cfg->bCharFormat) {
	case CDC_STOP_BITS_2:
		stopbits = US_MR_NBSTOP_2_BIT;
		break;
	case CDC_STOP_BITS_1_5:
		stopbits = US_MR_NBSTOP_1_5_BIT;
		break;
	case CDC_STOP_BITS_1:
	default:
		// Default stop bit = 1 stop bit
		stopbits = US_MR_NBSTOP_1_BIT;
		break;
	}

	switch (cfg->bParityType) {
	case CDC_PAR_EVEN:
		parity = US_MR_PAR_EVEN;
		break;
	case CDC_PAR_ODD:
		parity = US_MR_PAR_ODD;
		break;
	case CDC_PAR_MARK:
		parity = US_MR_PAR_MARK;
		break;
	case CDC_PAR_SPACE:
		parity = US_MR_PAR_SPACE;
		break;
	default:
	case CDC_PAR_NONE:
		parity = US_MR_PAR_NO;
		break;
	}
	
	switch(cfg->bDataBits) {
	case 5: case 6: case 7:
		databits = cfg->bDataBits - 5;
		break;
	default:
	case 8:
		databits = US_MR_CHRL_8_BIT;
		break;
	}

	// Options for USART.
	usart_options.baudrate = LE32_TO_CPU(cfg->dwDTERate);
	usart_options.char_length = databits;
	usart_options.parity_type = parity;
	usart_options.stop_bits = stopbits;
	usart_options.channel_mode = US_MR_CHMODE_NORMAL;
	imr = usart_get_interrupt_mask(usart);
	usart_disable_interrupt(usart, 0xFFFFFFFF);
	usart_init_rs232(usart, &usart_options,
			sysclk_get_peripheral_hz());
	// Restore both RX and TX
	usart_enable_tx(usart);
	usart_enable_rx(usart);
	usart_enable_interrupt(usart, imr);
}
Example #9
0
/*
 * For internal use only.
 * A common USART interrupt handler that is called for all USART peripherals.
 */
static void local_usart_handler(const portBASE_TYPE usart_index)
{
	portBASE_TYPE higher_priority_task_woken = pdFALSE;
	uint32_t usart_status;
	freertos_pdc_rx_control_t *rx_buffer_definition;

	usart_status = usart_get_status(
			all_usart_definitions[usart_index].peripheral_base_address);
	usart_status &= usart_get_interrupt_mask(
			all_usart_definitions[usart_index].peripheral_base_address);

	rx_buffer_definition = &(rx_buffer_definitions[usart_index]);

	/* Has the PDC completed a transmission? */
	if ((usart_status & US_CSR_ENDTX) != 0UL) {
		usart_disable_interrupt(
				all_usart_definitions[usart_index].peripheral_base_address,
				US_IER_ENDTX);

		/* If the driver is supporting multi-threading, then return the access
		mutex. */
		if (tx_dma_control[usart_index].peripheral_access_mutex != NULL) {
			xSemaphoreGiveFromISR(
					tx_dma_control[usart_index].peripheral_access_mutex,
					&higher_priority_task_woken);
		}

		/* if the sending task supplied a notification semaphore, then
		notify the task that the transmission has completed. */
		if (tx_dma_control[usart_index].transaction_complete_notification_semaphore != NULL) {
			xSemaphoreGiveFromISR(
					tx_dma_control[usart_index].transaction_complete_notification_semaphore,
					&higher_priority_task_woken);
		}
	}

	if ((usart_status & US_CSR_ENDRX) != 0UL) {
		/* It is possible to initialise the peripheral to only use Tx and not Rx.
		Check that Rx has been initialised. */
		configASSERT(rx_buffer_definition->next_byte_to_read);
		configASSERT(rx_buffer_definition->next_byte_to_read !=
				RX_NOT_USED);

		/* Out of DMA buffer, configure the next buffer.  Start by moving
		the DMA buffer start address up to the end of the previously defined
		buffer. */
		rx_buffer_definition->rx_pdc_parameters.ul_addr +=
				rx_buffer_definition->rx_pdc_parameters.ul_size;

		/* If the end of the buffer has been reached, wrap back to the start. */
		if (rx_buffer_definition->rx_pdc_parameters.ul_addr >=
				rx_buffer_definition->past_rx_buffer_end_address)
		{
			rx_buffer_definition->rx_pdc_parameters.ul_addr =
					rx_buffer_definition->rx_buffer_start_address;
		}

		/* Reset the Rx DMA to receive data into whatever free space remains in
		the Rx buffer. */
		configure_rx_dma(usart_index, data_added);

		if (rx_buffer_definition->rx_event_semaphore != NULL) {
			/* Notify that new data is available. */
			xSemaphoreGiveFromISR(
					rx_buffer_definition->rx_event_semaphore,
					&higher_priority_task_woken);
		}
	}

	if ((usart_status & US_IER_TIMEOUT) != 0UL) {
		/* More characters have been placed into the Rx buffer.

		Restart the timeout after more data has been received. */
		usart_start_rx_timeout(all_usart_definitions[usart_index].peripheral_base_address);

		if (rx_buffer_definition->rx_event_semaphore != NULL) {
			/* Notify that new data is available. */
			xSemaphoreGiveFromISR(
					rx_buffer_definition->rx_event_semaphore,
					&higher_priority_task_woken);
		}
	}

	if ((usart_status & SR_ERROR_INTERRUPTS) != 0) {
		/* An error occurred in either a transmission or reception.  Abort, and
		ensure the peripheral access mutex is made available to tasks. */
		usart_reset_status(
				all_usart_definitions[usart_index].peripheral_base_address);
		if (tx_dma_control[usart_index].peripheral_access_mutex != NULL) {
			xSemaphoreGiveFromISR(
					tx_dma_control[usart_index].peripheral_access_mutex,
					&higher_priority_task_woken);
		}
	}

	/* If giving a semaphore caused a task to unblock, and the unblocked task
	has a priority equal to or higher than the currently running task (the task
	this ISR interrupted), then higher_priority_task_woken will have
	automatically been set to pdTRUE within the semaphore function.
	portEND_SWITCHING_ISR() will then ensure that this ISR returns directly to
	the higher priority unblocked task. */
	portEND_SWITCHING_ISR(higher_priority_task_woken);
}