/** * \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; }
uart_send_interrupt() { #ifdef SOS_USE_PREEMPTION HAS_PREEMPTION_SECTION; DISABLE_PREEMPTION(); #endif SOS_MEASUREMENT_IDLE_END(); LED_DBG(LED_GREEN_TOGGLE); //DEBUG("uart_send_interrupt %d %d %d\n", state[TX].state, state[TX].msg_state, // state[TX].hdlc_state); switch (state[TX].state) { case UART_HDLC_START: uart_setByte((state[TX].flags & UART_SOS_MSG_FLAG)?HDLC_SOS_MSG:HDLC_RAW); state[TX].hdlc_state = HDLC_DATA; state[TX].state = UART_PROTOCOL; if (state[TX].flags & UART_CRC_FLAG) { state[TX].crc = crcByte(0, (state[TX].flags & UART_SOS_MSG_FLAG)?HDLC_SOS_MSG:HDLC_RAW); } break; case UART_PROTOCOL: state[TX].state = UART_DATA; if (state[TX].flags & UART_SOS_MSG_FLAG) { state[TX].msg_state = SOS_MSG_TX_HDR; } else { state[TX].msg_state = SOS_MSG_TX_RAW; } // set state and fall through case UART_DATA: switch (state[TX].msg_state) { case SOS_MSG_TX_HDR: uart_send_byte(((uint8_t*)(state[TX].msgHdr))[state[TX].idx]); if ((state[TX].idx == SOS_MSG_HEADER_SIZE) && (state[TX].hdlc_state != HDLC_ESCAPE)) { state[TX].idx = 0; if (state[TX].msgHdr->len != 0) { state[TX].msg_state = SOS_MSG_TX_DATA; } else { state[TX].hdlc_state = HDLC_CRC; state[TX].msg_state = SOS_MSG_TX_CRC_LOW; } } break; case SOS_MSG_TX_DATA: case SOS_MSG_TX_RAW: uart_send_byte(state[TX].buff[state[TX].idx]); if ((state[TX].idx == state[TX].msgLen) && (state[TX].hdlc_state != HDLC_ESCAPE)) { if (state[TX].flags & UART_CRC_FLAG) { state[TX].hdlc_state = HDLC_CRC; state[TX].msg_state = SOS_MSG_TX_CRC_LOW; } else { // no crc state[TX].state = UART_END; uart_setByte(HDLC_FLAG); } } break; case SOS_MSG_TX_CRC_LOW: uart_send_byte((uint8_t)(state[TX].crc)); if (state[TX].hdlc_state != HDLC_ESCAPE) { //! crc was escaped, resend state[TX].msg_state = SOS_MSG_TX_CRC_HIGH; } break; case SOS_MSG_TX_CRC_HIGH: uart_send_byte((uint8_t)(state[TX].crc >> 8)); if (state[TX].hdlc_state != HDLC_ESCAPE) { //! resend low byte state[TX].msg_state = SOS_MSG_TX_END; state[TX].state = UART_HDLC_STOP; } break; default: break; } break; case UART_HDLC_STOP: uart_setByte(HDLC_FLAG); state[TX].state = UART_END; state[TX].msg_state = SOS_MSG_NO_STATE; break; case UART_END: //DEBUG("disable Tx in uart.c\n"); uart_disable_tx(); state[TX].state = UART_IDLE; state[TX].hdlc_state = HDLC_IDLE; uart_send_done(state[TX].flags & ~UART_ERROR_FLAG); //DEBUG("uart_disable_tx\n"); break; default: //DEBUG("In Default...\n"); //DEBUG("disable Tx in uart.c\n"); uart_disable_tx(); state[TX].flags |= UART_ERROR_FLAG; state[TX].state = UART_IDLE; state[TX].hdlc_state = HDLC_IDLE; uart_send_done(state[TX].flags & ~UART_ERROR_FLAG); break; } //DEBUG("end uart_send_interrupt %d %d %d\n", state[TX].state, state[TX].msg_state, // state[TX].hdlc_state); #ifdef SOS_USE_PREEMPTION // enable interrupts because // enabling preemption can cause one to occur ENABLE_GLOBAL_INTERRUPTS(); // enable preemption ENABLE_PREEMPTION(NULL); #endif }