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