1 // From module: SERCOM Callback API
2 #include <samd21.h>
3 #include <sercom.h>
4 // #include <sercom_interrupt.h>
5
6 // From module: SERCOM USART - Serial Communications (Callback APIs)
7 #include <usart.h>
8 // #include <usart_interrupt.h>
9
10 #include <rtdevice.h>
11
12 typedef struct _samd2x_uart_t
13 {
14 struct rt_serial_device *serial;
15 struct usart_module *instance;
16 Sercom *com;
17 enum usart_signal_mux_settings mux_setting;
18 uint32_t pinmux_pad0;
19 uint32_t pinmux_pad1;
20 uint32_t pinmux_pad2;
21 uint32_t pinmux_pad3;
22 enum system_interrupt_vector vector;
23 } SAMD2x_UART_T;
24
25 static struct rt_serial_device _serial3;
26 static struct usart_module _uart3_instance;
27 static SAMD2x_UART_T _uart3 = {
28 &_serial3,
29 &_uart3_instance,
30 SERCOM3,
31 USART_RX_1_TX_0_XCK_1,
32 PINMUX_PA22C_SERCOM3_PAD0,
33 PINMUX_PA23C_SERCOM3_PAD1,
34 PINMUX_UNUSED,
35 PINMUX_UNUSED,
36 SYSTEM_INTERRUPT_MODULE_SERCOM3
37 };
38
39 // static struct rt_serial_device _serial2;
40 // static struct rt_serial_device _serial3;
41 // static struct rt_serial_device _serial4;
42
_uart_cfg(struct rt_serial_device * serial,struct serial_configure * cfg)43 static rt_err_t _uart_cfg(struct rt_serial_device *serial, struct serial_configure *cfg)
44 {
45 SAMD2x_UART_T *uart;
46
47 RT_ASSERT(serial != RT_NULL);
48 RT_ASSERT(cfg != RT_NULL);
49
50 uart = (SAMD2x_UART_T *)serial->parent.user_data;
51 //! [setup_config]
52 struct usart_config config_usart;
53 //! [setup_config]
54 //! [setup_config_defaults]
55 usart_get_config_defaults(&config_usart);
56 //! [setup_config_defaults]
57 config_usart.baudrate = cfg->baud_rate;
58
59 switch (cfg->data_bits )
60 {
61 case DATA_BITS_8:
62 config_usart.character_size = USART_CHARACTER_SIZE_8BIT;
63 break;
64
65 case DATA_BITS_5:
66 config_usart.character_size = USART_CHARACTER_SIZE_5BIT;
67 break;
68
69 case DATA_BITS_6:
70 config_usart.character_size = USART_CHARACTER_SIZE_6BIT;
71 break;
72
73 case DATA_BITS_7:
74 config_usart.character_size = USART_CHARACTER_SIZE_7BIT;
75 break;
76
77 case DATA_BITS_9:
78 config_usart.character_size = USART_CHARACTER_SIZE_9BIT;
79 break;
80
81 default:
82 config_usart.character_size = USART_CHARACTER_SIZE_8BIT;
83 break;
84 }
85
86 switch (cfg->parity)
87 {
88 case PARITY_NONE:
89 config_usart.parity = USART_PARITY_NONE;
90 break;
91
92 case PARITY_EVEN:
93 config_usart.parity = USART_PARITY_EVEN;
94 break;
95
96 case PARITY_ODD:
97 config_usart.parity = USART_PARITY_ODD;
98 break;
99
100 default:
101 config_usart.parity = USART_PARITY_NONE;
102 break;
103 }
104
105 config_usart.stopbits = USART_STOPBITS_1;
106 if (cfg->stop_bits != USART_STOPBITS_1)
107 {
108 config_usart.stopbits = USART_STOPBITS_2;
109 }
110
111 config_usart.data_order = USART_DATAORDER_LSB;
112 if (cfg->bit_order != BIT_ORDER_LSB)
113 {
114 config_usart.data_order = USART_DATAORDER_MSB;
115 }
116
117 config_usart.mux_setting = uart->mux_setting;
118 config_usart.pinmux_pad0 = uart->pinmux_pad0;
119 config_usart.pinmux_pad1 = uart->pinmux_pad1;
120 config_usart.pinmux_pad2 = uart->pinmux_pad2;
121 config_usart.pinmux_pad3 = uart->pinmux_pad3;
122 config_usart.receiver_enable = false;
123 config_usart.transmitter_enable = true;
124
125 while (usart_init(uart->instance, uart->com, &config_usart) != STATUS_OK) {
126 }
127
128 usart_enable(uart->instance);
129 /* Wait for the synchronization to complete */
130 _usart_wait_for_sync(uart->instance);
131
132 return RT_EOK;
133 }
134
_uart_ctrl(struct rt_serial_device * serial,int cmd,void * arg)135 static rt_err_t _uart_ctrl(struct rt_serial_device *serial, int cmd, void *arg)
136 {
137 SAMD2x_UART_T *uart;
138
139 RT_ASSERT(serial != RT_NULL);
140
141 uart = (SAMD2x_UART_T *)(serial->parent.user_data);
142
143 switch (cmd)
144 {
145 /* disable interrupt */
146 case RT_DEVICE_CTRL_CLR_INT:
147 uart->com->USART.INTENCLR.reg = SERCOM_USART_INTFLAG_RXC;
148 usart_disable_transceiver(uart->instance, USART_TRANSCEIVER_RX);
149 system_interrupt_disable(uart->vector);
150 /* Wait for the synchronization to complete */
151 _usart_wait_for_sync(uart->instance);
152 break;
153 /* enable interrupt */
154 case RT_DEVICE_CTRL_SET_INT:
155 /* Enable RX interrupt. */
156 /* Enable the RX Complete Interrupt */
157 uart->com->USART.INTENSET.reg = SERCOM_USART_INTFLAG_RXC;
158 usart_enable_transceiver(uart->instance, USART_TRANSCEIVER_RX);
159 system_interrupt_enable(uart->vector);
160 /* Wait for the synchronization to complete */
161 _usart_wait_for_sync(uart->instance);
162 break;
163
164 default:
165 return -RT_ERROR;
166 }
167
168 return RT_EOK;
169 }
170
_uart_putc(struct rt_serial_device * serial,char c)171 static int _uart_putc(struct rt_serial_device *serial, char c)
172 {
173 SAMD2x_UART_T *uart;
174
175 RT_ASSERT(serial != RT_NULL);
176
177 // while (!(uart->com->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) {
178 // }
179
180 uart = (SAMD2x_UART_T *)(serial->parent.user_data);
181
182 /* Write data to USART module */
183 uart->com->USART.DATA.reg = c;
184
185 while (!(uart->com->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_TXC)) {
186 /* Wait until data is sent */
187 }
188
189 return 1;
190 }
191
_uart_getc(struct rt_serial_device * serial)192 static int _uart_getc(struct rt_serial_device *serial)
193 {
194 int ch;
195 SAMD2x_UART_T *uart;
196
197 RT_ASSERT(serial != RT_NULL);
198
199 uart = (SAMD2x_UART_T *)(serial->parent.user_data);
200
201 /* Check if USART has new data */
202 if (!(uart->com->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_RXC)) {
203 /* Return error code */
204 return -1;
205 }
206
207 ch = uart->com->USART.DATA.reg & 0x1FF;
208
209 return ch;
210 }
211
212 static struct rt_uart_ops _uart_ops = {
213 _uart_cfg,
214 _uart_ctrl,
215 _uart_putc,
216 _uart_getc
217 };
218
uart_int_cb(SAMD2x_UART_T * uart_handle)219 static void uart_int_cb(SAMD2x_UART_T *uart_handle)
220 {
221 /* Temporary variables */
222 uint16_t interrupt_status;
223 uint8_t error_code;
224 struct usart_module *module = uart_handle->instance;
225 /* Pointer to the hardware module instance */
226 SercomUsart *const usart_hw = &(module->hw->USART);
227
228 /* Read and mask interrupt flag register */
229 interrupt_status = usart_hw->INTFLAG.reg;
230 interrupt_status &= usart_hw->INTENSET.reg;
231
232 /* Check if the Receive Complete interrupt has occurred, and that
233 * there's more data to receive */
234 if (interrupt_status & SERCOM_USART_INTFLAG_RXC) {
235 /* Read out the status code and mask away all but the 4 LSBs*/
236 error_code = (uint8_t)(usart_hw->STATUS.reg & SERCOM_USART_STATUS_MASK);
237 #if !SAMD20
238 /* CTS status should not be considered as an error */
239 if(error_code & SERCOM_USART_STATUS_CTS) {
240 error_code &= ~SERCOM_USART_STATUS_CTS;
241 }
242 #endif
243 #ifdef FEATURE_USART_LIN_MASTER
244 /* TXE status should not be considered as an error */
245 if(error_code & SERCOM_USART_STATUS_TXE) {
246 error_code &= ~SERCOM_USART_STATUS_TXE;
247 }
248 #endif
249 /* Check if an error has occurred during the receiving */
250 if (error_code) {
251 /* Check which error occurred */
252 if (error_code & SERCOM_USART_STATUS_FERR) {
253 /* clear flag by writing 1 to it */
254 usart_hw->STATUS.reg = SERCOM_USART_STATUS_FERR;
255 } else if (error_code & SERCOM_USART_STATUS_BUFOVF) {
256 /* clear flag by writing 1 to it */
257 usart_hw->STATUS.reg = SERCOM_USART_STATUS_BUFOVF;
258 } else if (error_code & SERCOM_USART_STATUS_PERR) {
259 /* clear flag by writing 1 to it */
260 usart_hw->STATUS.reg = SERCOM_USART_STATUS_PERR;
261 }
262 #ifdef FEATURE_USART_LIN_SLAVE
263 else if (error_code & SERCOM_USART_STATUS_ISF) {
264 /* clear flag by writing 1 to it */
265 usart_hw->STATUS.reg = SERCOM_USART_STATUS_ISF;
266 }
267 #endif
268 #ifdef FEATURE_USART_COLLISION_DECTION
269 else if (error_code & SERCOM_USART_STATUS_COLL) {
270 /* clear flag by writing 1 to it */
271 usart_hw->STATUS.reg = SERCOM_USART_STATUS_COLL;
272 }
273 #endif
274 } else {
275 rt_hw_serial_isr(uart_handle->serial, RT_SERIAL_EVENT_RX_IND);
276 }
277 }
278
279 #ifdef FEATURE_USART_HARDWARE_FLOW_CONTROL
280 if (interrupt_status & SERCOM_USART_INTFLAG_CTSIC) {
281 /* Disable interrupts */
282 usart_hw->INTENCLR.reg = SERCOM_USART_INTENCLR_CTSIC;
283 /* Clear interrupt flag */
284 usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_CTSIC;
285 }
286 #endif
287
288 #ifdef FEATURE_USART_LIN_SLAVE
289 if (interrupt_status & SERCOM_USART_INTFLAG_RXBRK) {
290 /* Disable interrupts */
291 usart_hw->INTENCLR.reg = SERCOM_USART_INTENCLR_RXBRK;
292 /* Clear interrupt flag */
293 usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXBRK;
294 }
295 #endif
296
297 #ifdef FEATURE_USART_START_FRAME_DECTION
298 if (interrupt_status & SERCOM_USART_INTFLAG_RXS) {
299 /* Disable interrupts */
300 usart_hw->INTENCLR.reg = SERCOM_USART_INTENCLR_RXS;
301 /* Clear interrupt flag */
302 usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXS;
303 }
304 #endif
305 }
306
SERCOM3_Handler(void)307 void SERCOM3_Handler(void)
308 {
309 uart_int_cb(&_uart3);
310 }
311
uart_init(void)312 void uart_init(void)
313 {
314 struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
315
316 config.bufsz = 512;
317 _serial3.config = config;
318 _serial3.ops = &_uart_ops;
319
320 rt_hw_serial_register(&_serial3, "uart3", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, &_uart3);
321 }
322