Exemplo n.º 1
0
void UART_Handler(void)
{
    tUartControl *pControl;
	uint32_t ul_status;
	uint8_t c;

	pControl = uart_control[0]; 

	/* Read UART Status. */
	ul_status = uart_get_status(UART);

	if (ul_status & UART_SR_RXRDY)
	{
		uart_read(UART, &c);
		
		/* Check if buffer has more space
		 * If no space, data will be discarded
		 */
		if (str_buf_is_full (&pControl->rx_buffer))
        {
            pControl->rx_buffer.header.err_overflow = 1;
        }
        else
        {
            str_buf_putc (&pControl->rx_buffer, c);
		}
	}
	
	if (ul_status & UART_SR_TXRDY)
	{
		uart_disable_interrupt (UART, UART_IER_TXRDY);

    	while (!str_buf_is_empty (&pControl->tx_buffer))
        {
            c = str_buf_getc (&pControl->tx_buffer);
            uart_write (pControl->uart_def_p, c);
    
            if ( !uart_is_tx_ready (pControl->uart_def_p) )
                break;
        }
        
        /* If there is no more data to send, disable the transmit
            interrupt - else enable it or keep it enabled */
	    if (str_buf_is_empty (&pControl->tx_buffer)) 
        {
		    uart_disable_interrupt (UART, UART_IER_TXRDY);
            pControl->TxIntEnabled = false;
        }
        else
        {
            // Set Tx Interrupt state
            pControl->TxIntEnabled = true;
            uart_enable_interrupt (UART, UART_IER_TXRDY);
        }

	} //
	
}
Exemplo n.º 2
0
/**
 * \brief Interrupt handler for UART interrupt.
 */
void console_uart_irq_handler(void)
{
	/* Get UART status and check if CMP is set */
	if (uart_get_status(CONSOLE_UART) & UART_SR_CMP) {
		cmp_flag = 1;
		/* Disable UART IRQ */
		uart_disable_interrupt(CONSOLE_UART, UART_IDR_CMP);
	}
}
Exemplo n.º 3
0
/**
 * \brief This function closes and disables communication in the specified UART.
 *
 * \param chn  Communication channel [0, 1]
 *
 * \retval true on success.
 * \retval false on failure.
 */
int8_t buart_if_close(uint8_t chn)
{
	if (!buart_chn_open[chn]) {
		return false;
	}

	switch (chn) {
#ifdef CONF_BOARD_UART0
	case 0:
	{
		uart_disable(UART0);
		uart_disable_interrupt(UART0, US_IDR_RXRDY);
		uart_disable_interrupt(UART0, US_IER_ENDRX);

		/* Stop TC */
		if (!buart_chn_open[1]) {
			tc_stop(TC_UART, TC_UART_CHN);
		}

		return true;
	}
	break;
#endif

#ifdef CONF_BOARD_UART1
	case 1:
	{
		uart_disable(UART1);
		uart_disable_interrupt(UART1, US_IDR_RXRDY);
		uart_disable_interrupt(UART1, US_IER_ENDRX);

		/* Stop TC */
		if (!buart_chn_open[0]) {
			tc_stop(TC_UART, TC_UART_CHN);
		}

		return true;
	}
	break;
#endif
	default:
		return false;
	}
}
/*
 * For internal use only.
 * A common UART interrupt handler that is called for all UART peripherals.
 */
static void local_uart_handler(const portBASE_TYPE uart_index)
{
	portBASE_TYPE higher_priority_task_woken = pdFALSE;
	uint32_t uart_status;
	freertos_pdc_rx_control_t *rx_buffer_definition;

	uart_status = uart_get_status(
			all_uart_definitions[uart_index].peripheral_base_address);
	uart_status &= uart_get_interrupt_mask(
			all_uart_definitions[uart_index].peripheral_base_address);

	rx_buffer_definition = &(rx_buffer_definitions[uart_index]);

	/* Has the PDC completed a transmission? */
	if ((uart_status & UART_SR_ENDTX) != 0UL) {
		uart_disable_interrupt(
				all_uart_definitions[uart_index].peripheral_base_address,
				UART_IDR_ENDTX);

		/* If the driver is supporting multi-threading, then return the access
		mutex. */
		if (tx_dma_control[uart_index].peripheral_access_mutex != NULL) {
			xSemaphoreGiveFromISR(
					tx_dma_control[uart_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[uart_index].transaction_complete_notification_semaphore != NULL) {
			xSemaphoreGiveFromISR(
					tx_dma_control[uart_index].transaction_complete_notification_semaphore,
					&higher_priority_task_woken);
		}
	}

	if ((uart_status & UART_SR_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(uart_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);
		}
	}

	/**
	 * Normally the uart_status can't be "0" when the interrupt happened.
	 * It happened only when in PDC mode with TXRDY and RXRDY interrupts since
	 * the flags has been cleared by PDC.
	 * As the TXRDY is never enabled in this service, here we
	 * check the RXRDY interrupt case.
	 */
	if (uart_status == 0UL) {
		/* Character has been placed into the Rx buffer. */
		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 ((uart_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. */
		uart_reset_status(
				all_uart_definitions[uart_index].peripheral_base_address);
		if (tx_dma_control[uart_index].peripheral_access_mutex != NULL) {
			xSemaphoreGiveFromISR(
					tx_dma_control[uart_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);
}
/*
 * For internal use only.
 * Configures the Rx DMA to receive data into free space within the Rx buffer.
 */
static void configure_rx_dma(uint32_t uart_index,
		enum buffer_operations operation_performed)
{
	freertos_pdc_rx_control_t *rx_buffer_definition;

	rx_buffer_definition = &(rx_buffer_definitions[uart_index]);

	/* How much space is there between the start of the DMA buffer and the
	current read pointer?  */

	if (((uint32_t)rx_buffer_definition->next_byte_to_read) ==
			rx_buffer_definition->rx_pdc_parameters.ul_addr) {
		/* The read pointer and the write pointer are equal.  If this function
		was called because data was added to the buffer, then there is no free
		space in the buffer remaining.  If this function was called because data
		was removed from the buffer, then the space remaining is from the write
		pointer up to the end of the buffer. */
		if (operation_performed == data_added) {
			rx_buffer_definition->rx_pdc_parameters.ul_size = 0UL;
		} else {
			rx_buffer_definition->rx_pdc_parameters.ul_size =
				rx_buffer_definition->past_rx_buffer_end_address - rx_buffer_definition->rx_pdc_parameters.ul_addr;
		}
	} else if (((uint32_t)rx_buffer_definition->next_byte_to_read) >
			rx_buffer_definition->rx_pdc_parameters.ul_addr) {
		/* The read pointer is ahead of the write pointer.  The space available
		is up to the write pointer to ensure unread data is not overwritten. */
		rx_buffer_definition->rx_pdc_parameters.ul_size =
			((uint32_t) rx_buffer_definition->next_byte_to_read) - rx_buffer_definition->rx_pdc_parameters.ul_addr;
	} else {
		/* The write pointer is ahead of the read pointer so the space
		available is up to the end of the buffer. */
		rx_buffer_definition->rx_pdc_parameters.ul_size =
			rx_buffer_definition->past_rx_buffer_end_address - rx_buffer_definition->rx_pdc_parameters.ul_addr;
	}

	configASSERT((rx_buffer_definition->rx_pdc_parameters.ul_addr+
			rx_buffer_definition->rx_pdc_parameters.ul_size) <=
			rx_buffer_definition->past_rx_buffer_end_address);

	if (rx_buffer_definition->rx_pdc_parameters.ul_size > 0) {
		/* Restart the DMA to receive into whichever space was calculated
		as remaining.  First clear any characters that might already be in the
		registers. */
		pdc_rx_init(
				all_uart_definitions[uart_index].pdc_base_address, &rx_buffer_definition->rx_pdc_parameters,
				NULL);
		pdc_enable_transfer(
				all_uart_definitions[uart_index].pdc_base_address,
				PERIPH_PTCR_RXTEN);
		uart_enable_interrupt(
				all_uart_definitions[uart_index].peripheral_base_address,
				UART_IER_ENDRX | UART_IER_RXRDY);
	} else {
		/* The write pointer has reached the read pointer.  There is no
		more room so the DMA is not re-enabled until a read has created
		space. */
		uart_disable_interrupt(
				all_uart_definitions[uart_index].peripheral_base_address,
				UART_IDR_ENDRX | UART_IDR_RXRDY);
	}
}
/**
 * \ingroup freertos_uart_peripheral_control_group
 * \brief Initializes the FreeRTOS ASF UART driver for the specified UART
 * port.
 *
 * freertos_uart_serial_init() is an ASF specific FreeRTOS driver function.  It
 * must be called before any other ASF specific FreeRTOS driver functions
 * attempt to access the same UART port.
 *
 * If freertos_driver_parameters->operation_mode equals UART_RS232 then
 * freertos_uart_serial_init() will configure the UART port for standard RS232
 * operation.  If freertos_driver_parameters->operation_mode equals any other
 * value then freertos_uart_serial_init() will not take any action.
 *
 * Other ASF UART functions can be called after freertos_uart_serial_init()
 * has completed successfully.
 *
 * The FreeRTOS ASF driver both installs and handles the UART PDC interrupts.
 * Users do not need to concern themselves with interrupt handling, and must
 * not install their own interrupt handler.
 *
 * This driver is provided with an application note, and an example project that
 * demonstrates the use of this function.
 *
 * \param p_uart    The UART peripheral being initialized.
 * \param uart_parameters    Structure that defines the UART bus and transfer
 *     parameters, such the baud rate and the number of data bits.
 *     sam_uart_opt_t is a standard ASF type (it is not FreeRTOS specific).
 * \param freertos_driver_parameters    Defines the driver behavior.  See the
 *    freertos_peripheral_options_t documentation, and the application note that
 *    accompanies the ASF specific FreeRTOS functions.
 *
 * \return If the initialization completes successfully then a handle that can
 *     be used with FreeRTOS UART read and write functions is returned.  If
 *     the initialisation fails then NULL is returned.
 */
freertos_uart_if freertos_uart_serial_init(Uart *p_uart,
		const sam_uart_opt_t *const uart_parameters,
		const freertos_peripheral_options_t *const freertos_driver_parameters)
{
	portBASE_TYPE uart_index;
	bool is_valid_operating_mode;
	freertos_uart_if return_value;
	const enum peripheral_operation_mode valid_operating_modes[] = {UART_RS232};

	/* Find the index into the all_uart_definitions array that holds details of
	the p_uart peripheral. */
	uart_index = get_pdc_peripheral_details(all_uart_definitions,
			MAX_UARTS,
			(void *) p_uart);

	/* Check the requested operating mode is valid for the peripheral. */
	is_valid_operating_mode = check_requested_operating_mode(
			freertos_driver_parameters->operation_mode,
			valid_operating_modes,
			sizeof(valid_operating_modes) /
			sizeof(enum peripheral_operation_mode));

	/* Don't do anything unless a valid p_uart pointer was used, and a valid
	operating mode was requested. */
	if ((uart_index < MAX_UARTS) && (is_valid_operating_mode == true)) {
		/* This function must be called exactly once per supported UART.  Check it
		has not been called	before. */
		configASSERT(rx_buffer_definitions[uart_index].next_byte_to_read == NULL);

		/* Disable everything before enabling the clock. */
		uart_disable_tx(p_uart);
		uart_disable_rx(p_uart);
		pdc_disable_transfer(all_uart_definitions[uart_index].pdc_base_address,
				(PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS));

		/* Enable the peripheral clock in the PMC. */
		pmc_enable_periph_clk(
				all_uart_definitions[uart_index].peripheral_id);

		switch (freertos_driver_parameters->operation_mode) {
		case UART_RS232:
			/* Call the standard ASF init function. */
			uart_init(p_uart, uart_parameters);
			break;

		default:
			/* Other modes are not currently supported. */
			break;
		}

		/* Disable all the interrupts. */
		uart_disable_interrupt(p_uart, MASK_ALL_INTERRUPTS);

		/* Create any required peripheral access mutexes and transaction complete
		semaphores.  This peripheral is full duplex so only the Tx semaphores
		are created in the following function.  The the Rx semaphores are
		created	separately. */
		create_peripheral_control_semaphores(
				freertos_driver_parameters->options_flags,
				&(tx_dma_control[uart_index]),
				NULL /* The rx structures are not created in this function. */);

		/* Is the driver also going to receive? */
		if (freertos_driver_parameters->receive_buffer != NULL) {
			/* rx_event_semaphore is used to signal the arival of new data.  It
			must be a counting semaphore for the following reason:  If the Rx
			DMA places data at the end of its circular buffer it will give the
			semaphore to indicate the presence of unread data.  If it then
			receives more data, it will write this to the start of the circular
			buffer, then give the semaphore again.  Now, if a task reads data
			out of the same circular buffer, and requests less data than is
			available, but more than is available between the next read pointer
			and the end of the buffer, the actual amount returned will be
			capped to that available up to the end of the buffer only.  If this
			semaphore was a binary semaphore, it would then be 'taken' even
			though, unknown to the reading task, unread and therefore available
			data remained at the beginning of the buffer. */
			rx_buffer_definitions[uart_index].rx_event_semaphore =
					xSemaphoreCreateCounting(portMAX_DELAY, 0);
			configASSERT(rx_buffer_definitions[uart_index].rx_event_semaphore);

			/* The receive buffer is currently empty, so the DMA has control
			over the entire buffer. */
			rx_buffer_definitions[uart_index].rx_pdc_parameters.ul_addr =
					(uint32_t)freertos_driver_parameters->receive_buffer;
			rx_buffer_definitions[uart_index].rx_pdc_parameters.ul_size =
					freertos_driver_parameters->receive_buffer_size;
			pdc_rx_init(
					all_uart_definitions[uart_index].pdc_base_address,
					&(rx_buffer_definitions[uart_index].rx_pdc_parameters),
					NULL);

			/* Set the next byte to read to the start of the buffer as no data
			has yet been read. */
			rx_buffer_definitions[uart_index].next_byte_to_read =
					freertos_driver_parameters->receive_buffer;

			/* Remember the limits of entire buffer. */
			rx_buffer_definitions[uart_index].rx_buffer_start_address =
					rx_buffer_definitions[uart_index].rx_pdc_parameters.ul_addr;
			rx_buffer_definitions[uart_index].past_rx_buffer_end_address =
					rx_buffer_definitions[uart_index].rx_buffer_start_address +
					freertos_driver_parameters->receive_buffer_size;

			/* If the rx driver is to be thread aware, create an access control
			mutex. */
			if ((freertos_driver_parameters->options_flags &
					USE_RX_ACCESS_MUTEX) != 0) {
				rx_buffer_definitions[uart_index].rx_access_mutex =
					xSemaphoreCreateMutex();
				configASSERT(rx_buffer_definitions[uart_index].rx_access_mutex);
			}

			/* Catch the DMA running out of Rx space, and gaps in the
			reception.  These events are both used to signal that there is
			data available in the Rx buffer. */
			uart_enable_interrupt(p_uart, UART_IER_ENDRX | UART_IER_RXRDY);

			/* The Rx DMA is running all the time, so enable it now. */
			pdc_enable_transfer(
					all_uart_definitions[uart_index].pdc_base_address,
					PERIPH_PTCR_RXTEN);
		} else {
			/* next_byte_to_read is used to check to see if this function
			has been called before, so it must be set to something, even if
			it is not going to be used.  The value it is set to is not
			important, provided it is not zero (NULL). */
			rx_buffer_definitions[uart_index].next_byte_to_read = RX_NOT_USED;
		}

		/* Configure and enable the UART interrupt in the interrupt controller. */
		configure_interrupt_controller(all_uart_definitions[uart_index].peripheral_irq,
				freertos_driver_parameters->interrupt_priority);

		/* Error interrupts are always enabled. */
		uart_enable_interrupt(
				all_uart_definitions[uart_index].peripheral_base_address,
				IER_ERROR_INTERRUPTS);

		/* Finally, enable the receiver and transmitter. */
		uart_enable_tx(p_uart);
		uart_enable_rx(p_uart);

		return_value = (freertos_uart_if) p_uart;
	} else {
		return_value = NULL;
	}

	return return_value;
}
Exemplo n.º 7
0
/**
 * \brief This function opens an UART
 *
 * \note Opening of the specified UART implies initializing local variables and
 * opening required hardware with the following configuration:
 * - bauds as specified
 * - 8 bits, no parity, 1 stop bit
 * - enable interrupts
 *
 * \param chn			Communication channel [0, 1]
 * \param bauds			Communication speed in bauds
 *
 * \retval true on success.
 * \retval false on failure.
 */
int8_t buart_if_open(uint8_t chn, uint32_t bauds)
{
#if defined(CONF_BOARD_UART0) || defined(CONF_BOARD_UART1)
	sam_uart_opt_t uart_console_settings;

	/* MCK for UART */
	uart_console_settings.ul_mck = sysclk_get_cpu_hz();
	/* Expected baud rate. */
	uart_console_settings.ul_baudrate = bauds;
	/* Initialize value for UART mode register */
	uart_console_settings.ul_mode = UART_MR_PAR_NO;
#else
	UNUSED(bauds);
#endif

	/* check uart and it is close */
	if (chn >= 2) {
		return false;
	}

	if (buart_chn_open[chn]) {
		return false;
	}

	switch (chn) {
#ifdef CONF_BOARD_UART0
	case 0:
	{
		/* Configure PMC. */
		pmc_enable_periph_clk(ID_UART0);
		/* Configure UART. */
		uart_init(UART0, &uart_console_settings);

		/* Assign buffers to pointers */
		buart_comm_data_0.puc_tq_buf = ptr_tx_uart_buf0;
		buart_comm_data_0.puc_rq_buf = ptr_rx_uart_buf0;
		buart_comm_data_0.us_rq_count = 0;
		buart_comm_data_0.us_rq_idx = 0;
		buart_comm_data_0.us_wq_idx = 0;

		/* Get board UART0 PDC base address and enable receiver and
		 * transmitter. */
		g_p_uart_pdc0 = uart_get_pdc_base(UART0);
		pdc_enable_transfer(g_p_uart_pdc0,
				PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);

		/* Start receiving data and start timer. */
		g_st_uart_rx_packet0.ul_addr = (uint32_t)gs_puc_uart_buf0;
		g_st_uart_rx_packet0.ul_size = UART_BUFFER_SIZE;
		pdc_rx_init(g_p_uart_pdc0, &g_st_uart_rx_packet0, NULL);

		/* Stop transmitting data */
		g_st_uart_tx_packet0.ul_addr = (uint32_t)buart_comm_data_0.puc_tq_buf;
		g_st_uart_tx_packet0.ul_size = 0;
		pdc_tx_init(g_p_uart_pdc0, &g_st_uart_tx_packet0, NULL);

		gs_ul_size_uart_buf0 = UART_BUFFER_SIZE;

		/* Transfer to PDC communication mode, disable RXRDY interrupt
		 * and enable RXBUFF interrupt. */
		uart_disable_interrupt(UART0, UART_IDR_RXRDY);
		uart_enable_interrupt(UART0, UART_IER_RXBUFF);

		/* Enable the receiver and transmitter. */
		uart_enable_tx(UART0);
		uart_enable_rx(UART0);

		/* Configure and enable interrupt of USART. */
		NVIC_SetPriority((IRQn_Type)UART0_IRQn, UART0_PRIO);
		NVIC_EnableIRQ(UART0_IRQn);

		buart_chn_open[chn] = true;
		num_bytes_rx_uart0 = 0;

		/* Configure TC uart */
		_configure_TC_uart();
		tc_start(TC_UART, TC_UART_CHN);
		return true;
	}
	break;
#endif

#ifdef CONF_BOARD_UART1
	case 1:
	{
		/* Configure PMC. */
		pmc_enable_periph_clk(ID_UART1);
		/* Configure UART. */
		uart_init(UART1, &uart_console_settings);

		/* Assign buffers to pointers */
		buart_comm_data_1.puc_tq_buf = ptr_tx_uart_buf1;
		buart_comm_data_1.puc_rq_buf = ptr_rx_uart_buf1;
		buart_comm_data_1.us_rq_count = 0;
		buart_comm_data_1.us_rq_idx = 0;
		buart_comm_data_1.us_wq_idx = 0;

		/* Get board UART1 PDC base address and enable receiver and
		 * transmitter. */
		g_p_uart_pdc1 = uart_get_pdc_base(UART1);
		pdc_enable_transfer(g_p_uart_pdc1,
				PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);

		/* Start receiving data and start timer. */
		g_st_uart_rx_packet1.ul_addr = (uint32_t)gs_puc_uart_buf1;
		g_st_uart_rx_packet1.ul_size = UART_BUFFER_SIZE;
		pdc_rx_init(g_p_uart_pdc1, &g_st_uart_rx_packet1, NULL);

		/* Stop transmitting data */
		g_st_uart_tx_packet1.ul_addr = (uint32_t)buart_comm_data_1.puc_tq_buf;
		g_st_uart_tx_packet1.ul_size = 0;
		pdc_tx_init(g_p_uart_pdc1, &g_st_uart_tx_packet1, NULL);

		gs_ul_size_uart_buf1 = UART_BUFFER_SIZE;

		/* Transfer to PDC communication mode, disable RXRDY interrupt
		 * and enable RXBUFF interrupt. */
		uart_disable_interrupt(UART1, UART_IDR_RXRDY);
		uart_enable_interrupt(UART1, UART_IER_RXBUFF);

		/* Enable the receiver and transmitter. */
		uart_enable_tx(UART1);
		uart_enable_rx(UART1);

		/* Configure and enable interrupt of USART. */
		NVIC_SetPriority((IRQn_Type)UART1_IRQn, UART1_PRIO);
		NVIC_EnableIRQ(UART1_IRQn);

		buart_chn_open[chn] = true;
		num_bytes_rx_uart1 = 0;

		/* Configure TC uart */
		_configure_TC_uart();
		tc_start(TC_UART, TC_UART_CHN);
		return true;
	}
	break;
#endif
	default:
		return false;
	}
}