// From module: SERCOM Callback API #include #include // #include // From module: SERCOM USART - Serial Communications (Callback APIs) #include // #include #include typedef struct _samd2x_uart_t { struct rt_serial_device *serial; struct usart_module *instance; Sercom *com; enum usart_signal_mux_settings mux_setting; uint32_t pinmux_pad0; uint32_t pinmux_pad1; uint32_t pinmux_pad2; uint32_t pinmux_pad3; enum system_interrupt_vector vector; } SAMD2x_UART_T; static struct rt_serial_device _serial3; static struct usart_module _uart3_instance; static SAMD2x_UART_T _uart3 = { &_serial3, &_uart3_instance, SERCOM3, USART_RX_1_TX_0_XCK_1, PINMUX_PA22C_SERCOM3_PAD0, PINMUX_PA23C_SERCOM3_PAD1, PINMUX_UNUSED, PINMUX_UNUSED, SYSTEM_INTERRUPT_MODULE_SERCOM3 }; // static struct rt_serial_device _serial2; // static struct rt_serial_device _serial3; // static struct rt_serial_device _serial4; static rt_err_t _uart_cfg(struct rt_serial_device *serial, struct serial_configure *cfg) { SAMD2x_UART_T *uart; RT_ASSERT(serial != RT_NULL); RT_ASSERT(cfg != RT_NULL); uart = (SAMD2x_UART_T *)serial->parent.user_data; //! [setup_config] struct usart_config config_usart; //! [setup_config] //! [setup_config_defaults] usart_get_config_defaults(&config_usart); //! [setup_config_defaults] config_usart.baudrate = cfg->baud_rate; switch (cfg->data_bits ) { case DATA_BITS_8: config_usart.character_size = USART_CHARACTER_SIZE_8BIT; break; case DATA_BITS_5: config_usart.character_size = USART_CHARACTER_SIZE_5BIT; break; case DATA_BITS_6: config_usart.character_size = USART_CHARACTER_SIZE_6BIT; break; case DATA_BITS_7: config_usart.character_size = USART_CHARACTER_SIZE_7BIT; break; case DATA_BITS_9: config_usart.character_size = USART_CHARACTER_SIZE_9BIT; break; default: config_usart.character_size = USART_CHARACTER_SIZE_8BIT; break; } switch (cfg->parity) { case PARITY_NONE: config_usart.parity = USART_PARITY_NONE; break; case PARITY_EVEN: config_usart.parity = USART_PARITY_EVEN; break; case PARITY_ODD: config_usart.parity = USART_PARITY_ODD; break; default: config_usart.parity = USART_PARITY_NONE; break; } config_usart.stopbits = USART_STOPBITS_1; if (cfg->stop_bits != USART_STOPBITS_1) { config_usart.stopbits = USART_STOPBITS_2; } config_usart.data_order = USART_DATAORDER_LSB; if (cfg->bit_order != BIT_ORDER_LSB) { config_usart.data_order = USART_DATAORDER_MSB; } config_usart.mux_setting = uart->mux_setting; config_usart.pinmux_pad0 = uart->pinmux_pad0; config_usart.pinmux_pad1 = uart->pinmux_pad1; config_usart.pinmux_pad2 = uart->pinmux_pad2; config_usart.pinmux_pad3 = uart->pinmux_pad3; config_usart.receiver_enable = false; config_usart.transmitter_enable = true; while (usart_init(uart->instance, uart->com, &config_usart) != STATUS_OK) { } usart_enable(uart->instance); /* Wait for the synchronization to complete */ _usart_wait_for_sync(uart->instance); return RT_EOK; } static rt_err_t _uart_ctrl(struct rt_serial_device *serial, int cmd, void *arg) { SAMD2x_UART_T *uart; RT_ASSERT(serial != RT_NULL); uart = (SAMD2x_UART_T *)(serial->parent.user_data); switch (cmd) { /* disable interrupt */ case RT_DEVICE_CTRL_CLR_INT: uart->com->USART.INTENCLR.reg = SERCOM_USART_INTFLAG_RXC; usart_disable_transceiver(uart->instance, USART_TRANSCEIVER_RX); system_interrupt_disable(uart->vector); /* Wait for the synchronization to complete */ _usart_wait_for_sync(uart->instance); break; /* enable interrupt */ case RT_DEVICE_CTRL_SET_INT: /* Enable RX interrupt. */ /* Enable the RX Complete Interrupt */ uart->com->USART.INTENSET.reg = SERCOM_USART_INTFLAG_RXC; usart_enable_transceiver(uart->instance, USART_TRANSCEIVER_RX); system_interrupt_enable(uart->vector); /* Wait for the synchronization to complete */ _usart_wait_for_sync(uart->instance); break; default: return -RT_ERROR; } return RT_EOK; } static int _uart_putc(struct rt_serial_device *serial, char c) { SAMD2x_UART_T *uart; RT_ASSERT(serial != RT_NULL); // while (!(uart->com->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) { // } uart = (SAMD2x_UART_T *)(serial->parent.user_data); /* Write data to USART module */ uart->com->USART.DATA.reg = c; while (!(uart->com->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_TXC)) { /* Wait until data is sent */ } return 1; } static int _uart_getc(struct rt_serial_device *serial) { int ch; SAMD2x_UART_T *uart; RT_ASSERT(serial != RT_NULL); uart = (SAMD2x_UART_T *)(serial->parent.user_data); /* Check if USART has new data */ if (!(uart->com->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_RXC)) { /* Return error code */ return -1; } ch = uart->com->USART.DATA.reg & 0x1FF; return ch; } static struct rt_uart_ops _uart_ops = { _uart_cfg, _uart_ctrl, _uart_putc, _uart_getc }; static void uart_int_cb(SAMD2x_UART_T *uart_handle) { /* Temporary variables */ uint16_t interrupt_status; uint8_t error_code; struct usart_module *module = uart_handle->instance; /* Pointer to the hardware module instance */ SercomUsart *const usart_hw = &(module->hw->USART); /* Read and mask interrupt flag register */ interrupt_status = usart_hw->INTFLAG.reg; interrupt_status &= usart_hw->INTENSET.reg; /* Check if the Receive Complete interrupt has occurred, and that * there's more data to receive */ if (interrupt_status & SERCOM_USART_INTFLAG_RXC) { /* 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 #ifdef FEATURE_USART_LIN_MASTER /* TXE status should not be considered as an error */ if(error_code & SERCOM_USART_STATUS_TXE) { error_code &= ~SERCOM_USART_STATUS_TXE; } #endif /* Check if an error has occurred during the receiving */ if (error_code) { /* Check which error occurred */ if (error_code & SERCOM_USART_STATUS_FERR) { /* clear flag by writing 1 to it */ usart_hw->STATUS.reg = SERCOM_USART_STATUS_FERR; } else if (error_code & SERCOM_USART_STATUS_BUFOVF) { /* clear flag by writing 1 to it */ usart_hw->STATUS.reg = SERCOM_USART_STATUS_BUFOVF; } else if (error_code & SERCOM_USART_STATUS_PERR) { /* clear flag by writing 1 to it */ usart_hw->STATUS.reg = SERCOM_USART_STATUS_PERR; } #ifdef FEATURE_USART_LIN_SLAVE else if (error_code & SERCOM_USART_STATUS_ISF) { /* clear flag by writing 1 to it */ usart_hw->STATUS.reg = SERCOM_USART_STATUS_ISF; } #endif #ifdef FEATURE_USART_COLLISION_DECTION else if (error_code & SERCOM_USART_STATUS_COLL) { /* clear flag by writing 1 to it */ usart_hw->STATUS.reg = SERCOM_USART_STATUS_COLL; } #endif } else { rt_hw_serial_isr(uart_handle->serial, RT_SERIAL_EVENT_RX_IND); } } #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; } #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; } #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; } #endif } void SERCOM3_Handler(void) { uart_int_cb(&_uart3); } void uart_init(void) { struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; config.bufsz = 512; _serial3.config = config; _serial3.ops = &_uart_ops; rt_hw_serial_register(&_serial3, "uart3", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, &_uart3); }