Modified version of the mbed library for use with the Nucleo boards.
Dependents: EEPROMWrite Full-Project
Fork of mbed-src by
Diff: targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/usart/usart_interrupt.c
- Revision:
- 613:bc40b8d2aec4
- Parent:
- 612:fba1c7dc54c0
- Child:
- 614:9d86c2ae5de0
--- a/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/usart/usart_interrupt.c Tue Aug 18 15:00:09 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,614 +0,0 @@ -#include "usart_interrupt.h" - -/** - * \internal - * Asynchronous write of a buffer with a given length - * - * \param[in] module Pointer to USART software instance struct - * \param[in] tx_data Pointer to data to be transmitted - * \param[in] length Length of data buffer - * - */ -void _usart_write_buffer( - struct usart_module *const module, - uint8_t *tx_data, - uint16_t length) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - /* Get a pointer to the hardware module instance */ - SercomUsart *const usart_hw = &(module->hw->USART); - - /* Write parameters to the device instance */ - module->remaining_tx_buffer_length = length; - module->tx_buffer_ptr = tx_data; - module->tx_status = STATUS_BUSY; - - /* Enable the Data Register Empty Interrupt */ - usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_DRE; -} - -/** - * \internal - * Asynchronous read of a buffer with a given length - * - * \param[in] module Pointer to USART software instance struct - * \param[in] rx_data Pointer to data to be received - * \param[in] length Length of data buffer - * - */ -void _usart_read_buffer( - struct usart_module *const module, - uint8_t *rx_data, - uint16_t length) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - /* Get a pointer to the hardware module instance */ - SercomUsart *const usart_hw = &(module->hw->USART); - - /* Set length for the buffer and the pointer, and let - * the interrupt handler do the rest */ - module->remaining_rx_buffer_length = length; - module->rx_buffer_ptr = rx_data; - module->rx_status = STATUS_BUSY; - - /* Enable the RX Complete Interrupt */ - usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_RXC; - -#ifdef FEATURE_USART_LIN_SLAVE - /* Enable the break character is received Interrupt */ - if(module->lin_slave_enabled) { - usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_RXBRK; - } -#endif - -#ifdef FEATURE_USART_START_FRAME_DECTION - /* Enable a start condition is detected Interrupt */ - if(module->start_frame_detection_enabled) { - usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_RXS; - } -#endif -} - -/** - * \brief Registers a callback - * - * Registers a callback function which is implemented by the user. - * - * \note The callback must be enabled by \ref usart_enable_callback, - * in order for the interrupt handler to call it when the conditions for - * the callback type are met. - * - * \param[in] module Pointer to USART software instance struct - * \param[in] callback_func Pointer to callback function - * \param[in] callback_type Callback type given by an enum - * - */ -void usart_register_callback( - struct usart_module *const module, - usart_callback_t callback_func, - enum usart_callback callback_type) -{ - /* Sanity check arguments */ - Assert(module); - Assert(callback_func); - - /* Register callback function */ - module->callback[callback_type] = callback_func; - - /* Set the bit corresponding to the callback_type */ - module->callback_reg_mask |= (1 << callback_type); -} - -/** - * \brief Unregisters a callback - * - * Unregisters a callback function which is implemented by the user. - * - * \param[in,out] module Pointer to USART software instance struct - * \param[in] callback_type Callback type given by an enum - * - */ -void usart_unregister_callback( - struct usart_module *const module, - enum usart_callback callback_type) -{ - /* Sanity check arguments */ - Assert(module); - - /* Unregister callback function */ - module->callback[callback_type] = NULL; - - /* Clear the bit corresponding to the callback_type */ - module->callback_reg_mask &= ~(1 << callback_type); -} - -/** - * \brief Asynchronous write a single char - * - * Sets up the driver to write the data given. If registered and enabled, - * a callback function will be called when the transmit is completed. - * - * \param[in] module Pointer to USART software instance struct - * \param[in] tx_data Data to transfer - * - * \returns Status of the operation. - * \retval STATUS_OK If operation was completed - * \retval STATUS_BUSY If operation was not completed, due to the - * USART module being busy - * \retval STATUS_ERR_DENIED If the transmitter is not enabled - */ -enum status_code usart_write_job( - struct usart_module *const module, - const uint16_t *tx_data) -{ - /* Sanity check arguments */ - Assert(module); - Assert(tx_data); - - /* Check if the USART transmitter is busy */ - if (module->remaining_tx_buffer_length > 0) { - return STATUS_BUSY; - } - - /* Check that the transmitter is enabled */ - if (!(module->transmitter_enabled)) { - return STATUS_ERR_DENIED; - } - - /* Call internal write buffer function with length 1 */ - _usart_write_buffer(module, (uint8_t *)tx_data, 1); - - return STATUS_OK; -} - -/** - * \brief Asynchronous read a single char - * - * Sets up the driver to read data from the USART module to the data - * pointer given. If registered and enabled, a callback will be called - * when the receiving is completed. - * - * \param[in] module Pointer to USART software instance struct - * \param[out] rx_data Pointer to where received data should be put - * - * \returns Status of the operation. - * \retval STATUS_OK If operation was completed - * \retval STATUS_BUSY If operation was not completed - */ -enum status_code usart_read_job( - struct usart_module *const module, - uint16_t *const rx_data) -{ - /* Sanity check arguments */ - Assert(module); - Assert(rx_data); - - /* Check if the USART receiver is busy */ - if (module->remaining_rx_buffer_length > 0) { - return STATUS_BUSY; - } - - /* Call internal read buffer function with length 1 */ - _usart_read_buffer(module, (uint8_t *)rx_data, 1); - - return STATUS_OK; -} - -/** - * \brief Asynchronous buffer write - * - * Sets up the driver to write a given buffer over the USART. If registered and - * enabled, a callback function will be called. - * - * \param[in] module Pointer to USART software instance struct - * \param[in] tx_data Pointer do data buffer to transmit - * \param[in] length Length of the data to transmit - * - * \note if using 9-bit data, the array that *tx_data point to should be defined - * as uint16_t array and should be casted to uint8_t* pointer. Because it - * is an address pointer, the highest byte is not discarded. For example: - * \code - #define TX_LEN 3 - uint16_t tx_buf[TX_LEN] = {0x0111, 0x0022, 0x0133}; - usart_write_buffer_job(&module, (uint8_t*)tx_buf, TX_LEN); - \endcode - * - * \returns Status of the operation. - * \retval STATUS_OK If operation was completed successfully. - * \retval STATUS_BUSY If operation was not completed, due to the - * USART module being busy - * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to invalid - * arguments - * \retval STATUS_ERR_DENIED If the transmitter is not enabled - */ -enum status_code usart_write_buffer_job( - struct usart_module *const module, - uint8_t *tx_data, - uint16_t length) -{ - /* Sanity check arguments */ - Assert(module); - Assert(tx_data); - - if (length == 0) { - return STATUS_ERR_INVALID_ARG; - } - - /* Check if the USART transmitter is busy */ - if (module->remaining_tx_buffer_length > 0) { - return STATUS_BUSY; - } - - /* Check that the receiver is enabled */ - if (!(module->transmitter_enabled)) { - return STATUS_ERR_DENIED; - } - - /* Issue internal asynchronous write */ - _usart_write_buffer(module, tx_data, length); - - return STATUS_OK; -} - -/** - * \brief Asynchronous buffer read - * - * Sets up the driver to read from the USART to a given buffer. If registered - * and enabled, a callback function will be called. - * - * \param[in] module Pointer to USART software instance struct - * \param[out] rx_data Pointer to data buffer to receive - * \param[in] length Data buffer length - * - * \note if using 9-bit data, the array that *rx_data point to should be defined - * as uint16_t array and should be casted to uint8_t* pointer. Because it - * is an address pointer, the highest byte is not discarded. For example: - * \code - #define RX_LEN 3 - uint16_t rx_buf[RX_LEN] = {0x0,}; - usart_read_buffer_job(&module, (uint8_t*)rx_buf, RX_LEN); - \endcode - * - * \returns Status of the operation. - * \retval STATUS_OK If operation was completed - * \retval STATUS_BUSY If operation was not completed, due to the - * USART module being busy - * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to invalid - * arguments - * \retval STATUS_ERR_DENIED If the transmitter is not enabled - */ -enum status_code usart_read_buffer_job( - struct usart_module *const module, - uint8_t *rx_data, - uint16_t length) -{ - /* Sanity check arguments */ - Assert(module); - Assert(rx_data); - - if (length == 0) { - return STATUS_ERR_INVALID_ARG; - } - - /* Check that the receiver is enabled */ - if (!(module->receiver_enabled)) { - return STATUS_ERR_DENIED; - } - - /* Check if the USART receiver is busy */ - if (module->remaining_rx_buffer_length > 0) { - return STATUS_BUSY; - } - - /* Issue internal asynchronous read */ - _usart_read_buffer(module, rx_data, length); - - return STATUS_OK; -} - -/** - * \brief Cancels ongoing read/write operation - * - * Cancels the ongoing read/write operation modifying parameters in the - * USART software struct. - * - * \param[in] module Pointer to USART software instance struct - * \param[in] transceiver_type Transfer type to cancel - */ -void usart_abort_job( - struct usart_module *const module, - enum usart_transceiver_type transceiver_type) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - /* Get a pointer to the hardware module instance */ - SercomUsart *const usart_hw = &(module->hw->USART); - - switch(transceiver_type) { - case USART_TRANSCEIVER_RX: - /* Clear the interrupt flag in order to prevent the receive - * complete callback to fire */ - usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXC; - - /* Clear the software reception buffer */ - module->remaining_rx_buffer_length = 0; - - break; - - case USART_TRANSCEIVER_TX: - /* Clear the interrupt flag in order to prevent the receive - * complete callback to fire */ - usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_TXC; - - /* Clear the software reception buffer */ - module->remaining_tx_buffer_length = 0; - - break; - } -} - -/** - * \brief Get status from the ongoing or last asynchronous transfer operation - * - * Returns the error from a given ongoing or last asynchronous transfer operation. - * Either from a read or write transfer. - * - * \param[in] module Pointer to USART software instance struct - * \param[in] transceiver_type Transfer type to check - * - * \return Status of the given job. - * \retval STATUS_OK No error occurred during the last transfer - * \retval STATUS_BUSY A transfer is ongoing - * \retval STATUS_ERR_BAD_DATA The last operation was aborted due to a - * parity error. The transfer could be affected - * by external noise - * \retval STATUS_ERR_BAD_FORMAT The last operation was aborted due to a - * frame error - * \retval STATUS_ERR_OVERFLOW The last operation was aborted due to a - * buffer overflow - * \retval STATUS_ERR_INVALID_ARG An invalid transceiver enum given - */ -enum status_code usart_get_job_status( - struct usart_module *const module, - enum usart_transceiver_type transceiver_type) -{ - /* Sanity check arguments */ - Assert(module); - - /* Variable for status code */ - enum status_code status_code; - - switch(transceiver_type) { - case USART_TRANSCEIVER_RX: - status_code = module->rx_status; - break; - - case USART_TRANSCEIVER_TX: - status_code = module->tx_status; - break; - - default: - status_code = STATUS_ERR_INVALID_ARG; - break; - } - - return status_code; -} - -/** - * \internal - * Handles interrupts as they occur, and it will run callback functions - * which are registered and enabled. - * - * \param[in] instance ID of the SERCOM instance calling the interrupt - * handler. - */ -void _usart_interrupt_handler( - uint8_t instance) -{ - /* Temporary variables */ - uint16_t interrupt_status; - uint16_t callback_status; - uint8_t error_code; - - - /* Get device instance from the look-up table */ - struct usart_module *module - = (struct usart_module *)_sercom_instances[instance]; - - /* Pointer to the hardware module instance */ - SercomUsart *const usart_hw - = &(module->hw->USART); - - /* Wait for the synchronization to complete */ - _usart_wait_for_sync(module); - - /* Read and mask interrupt flag register */ - interrupt_status = usart_hw->INTFLAG.reg; - interrupt_status &= usart_hw->INTENSET.reg; - callback_status = module->callback_reg_mask & - module->callback_enable_mask; - - /* Check if a DATA READY interrupt has occurred, - * and if there is more to transfer */ - if (interrupt_status & SERCOM_USART_INTFLAG_DRE) { - if (module->remaining_tx_buffer_length) { - /* Write value will be at least 8-bits long */ - uint16_t data_to_send = *(module->tx_buffer_ptr); - /* Increment 8-bit pointer */ - (module->tx_buffer_ptr)++; - - if (module->character_size == USART_CHARACTER_SIZE_9BIT) { - data_to_send |= (*(module->tx_buffer_ptr) << 8); - /* Increment 8-bit pointer */ - (module->tx_buffer_ptr)++; - } - /* Write the data to send */ - usart_hw->DATA.reg = (data_to_send & SERCOM_USART_DATA_MASK); - - if (--(module->remaining_tx_buffer_length) == 0) { - /* Disable the Data Register Empty Interrupt */ - usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_DRE; - /* Enable Transmission Complete interrupt */ - usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_TXC; - - } - } else { - usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_DRE; - } - - /* Check if the Transmission Complete interrupt has occurred and - * that the transmit buffer is empty */ - } - - if (interrupt_status & SERCOM_USART_INTFLAG_TXC) { - - /* Disable TX Complete Interrupt, and set STATUS_OK */ - usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_TXC; - module->tx_status = STATUS_OK; - - /* Run callback if registered and enabled */ - if (callback_status & (1 << USART_CALLBACK_BUFFER_TRANSMITTED)) { - (*(module->callback[USART_CALLBACK_BUFFER_TRANSMITTED]))(module); - } - - /* Check if the Receive Complete interrupt has occurred, and that - * there's more data to receive */ - } - - if (interrupt_status & SERCOM_USART_INTFLAG_RXC) { - - if (module->remaining_rx_buffer_length) { - /* Read out the status code and mask away all but the 4 LSBs*/ - error_code = (uint8_t)(usart_hw->STATUS.reg & SERCOM_USART_STATUS_MASK); -#if !SAMD20 - /* CTS status should not be considered as an error */ - if(error_code & SERCOM_USART_STATUS_CTS) { - error_code &= ~SERCOM_USART_STATUS_CTS; - } -#endif - /* Check if an error has occurred during the receiving */ - if (error_code) { - /* Check which error occurred */ - if (error_code & SERCOM_USART_STATUS_FERR) { - /* Store the error code and clear flag by writing 1 to it */ - module->rx_status = STATUS_ERR_BAD_FORMAT; - usart_hw->STATUS.reg |= SERCOM_USART_STATUS_FERR; - } else if (error_code & SERCOM_USART_STATUS_BUFOVF) { - /* Store the error code and clear flag by writing 1 to it */ - module->rx_status = STATUS_ERR_OVERFLOW; - usart_hw->STATUS.reg |= SERCOM_USART_STATUS_BUFOVF; - } else if (error_code & SERCOM_USART_STATUS_PERR) { - /* Store the error code and clear flag by writing 1 to it */ - module->rx_status = STATUS_ERR_BAD_DATA; - usart_hw->STATUS.reg |= SERCOM_USART_STATUS_PERR; - } -#ifdef FEATURE_USART_LIN_SLAVE - else if (error_code & SERCOM_USART_STATUS_ISF) { - /* Store the error code and clear flag by writing 1 to it */ - module->rx_status = STATUS_ERR_PROTOCOL; - usart_hw->STATUS.reg |= SERCOM_USART_STATUS_ISF; - } -#endif -#ifdef FEATURE_USART_COLLISION_DECTION - else if (error_code & SERCOM_USART_STATUS_COLL) { - /* Store the error code and clear flag by writing 1 to it */ - module->rx_status = STATUS_ERR_PACKET_COLLISION; - usart_hw->STATUS.reg |= SERCOM_USART_STATUS_COLL; - } -#endif - - /* Run callback if registered and enabled */ - if (callback_status - & (1 << USART_CALLBACK_ERROR)) { - (*(module->callback[USART_CALLBACK_ERROR]))(module); - } - - } else { - - /* Read current packet from DATA register, - * increment buffer pointer and decrement buffer length */ - uint16_t received_data = (usart_hw->DATA.reg & SERCOM_USART_DATA_MASK); - - /* Read value will be at least 8-bits long */ - *(module->rx_buffer_ptr) = received_data; - /* Increment 8-bit pointer */ - module->rx_buffer_ptr += 1; - - if (module->character_size == USART_CHARACTER_SIZE_9BIT) { - /* 9-bit data, write next received byte to the buffer */ - *(module->rx_buffer_ptr) = (received_data >> 8); - /* Increment 8-bit pointer */ - module->rx_buffer_ptr += 1; - } - - /* Check if the last character have been received */ - if(--(module->remaining_rx_buffer_length) == 0) { - /* Disable RX Complete Interrupt, - * and set STATUS_OK */ - usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_RXC; - module->rx_status = STATUS_OK; - - /* Run callback if registered and enabled */ - if (callback_status - & (1 << USART_CALLBACK_BUFFER_RECEIVED)) { - (*(module->callback[USART_CALLBACK_BUFFER_RECEIVED]))(module); - } - } - } - } else { - /* This should not happen. Disable Receive Complete interrupt. */ - usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_RXC; - } - } - -#ifdef FEATURE_USART_HARDWARE_FLOW_CONTROL - if (interrupt_status & SERCOM_USART_INTFLAG_CTSIC) { - /* Disable interrupts */ - usart_hw->INTENCLR.reg = SERCOM_USART_INTENCLR_CTSIC; - /* Clear interrupt flag */ - usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_CTSIC; - - /* Run callback if registered and enabled */ - if (callback_status & (1 << USART_CALLBACK_CTS_INPUT_CHANGE)) { - (*(module->callback[USART_CALLBACK_CTS_INPUT_CHANGE]))(module); - } - } -#endif - -#ifdef FEATURE_USART_LIN_SLAVE - if (interrupt_status & SERCOM_USART_INTFLAG_RXBRK) { - /* Disable interrupts */ - usart_hw->INTENCLR.reg = SERCOM_USART_INTENCLR_RXBRK; - /* Clear interrupt flag */ - usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXBRK; - - /* Run callback if registered and enabled */ - if (callback_status & (1 << USART_CALLBACK_BREAK_RECEIVED)) { - (*(module->callback[USART_CALLBACK_BREAK_RECEIVED]))(module); - } - } -#endif - -#ifdef FEATURE_USART_START_FRAME_DECTION - if (interrupt_status & SERCOM_USART_INTFLAG_RXS) { - /* Disable interrupts */ - usart_hw->INTENCLR.reg = SERCOM_USART_INTENCLR_RXS; - /* Clear interrupt flag */ - usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXS; - - /* Run callback if registered and enabled */ - if (callback_status & (1 << USART_CALLBACK_START_RECEIVED)) { - (*(module->callback[USART_CALLBACK_START_RECEIVED]))(module); - } - } -#endif -}