1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Email Notes
8 * 2019-07-16 Kevin.Liu kevin.liu.mchp@gmail.com First Release
9 * 2023-09-16 luhuadong luhuadong@163.com support serial v2
10 */
11
12 #include <rtthread.h>
13 #include <rtdevice.h>
14
15 #include <atmel_start.h>
16 #include <board.h>
17
18 /* SAM MCU serial device */
19 static struct rt_serial_device sam_serial;
20
serial_rxcallback(const struct usart_async_descriptor * const io_descr)21 static void serial_rxcallback(const struct usart_async_descriptor *const io_descr)
22 {
23 (void)io_descr;
24
25 /* enter interrupt */
26 rt_interrupt_enter();
27
28 #ifdef RT_USING_SERIAL_V2
29 struct rt_serial_rx_fifo *rx_fifo;
30 uint8_t data;
31
32 rx_fifo = (struct rt_serial_rx_fifo *)sam_serial.serial_rx;
33 RT_ASSERT(rx_fifo != RT_NULL);
34
35 do {
36 ringbuffer_get((struct ringbuffer *const)&io_descr->rx, &data);
37 rt_ringbuffer_putchar_force(&rx_fifo->rb, data);
38 } while (0); // maybe not only one byte
39
40 #endif
41
42 /* Notify Serial driver to process RX data */
43 rt_hw_serial_isr(&sam_serial, RT_SERIAL_EVENT_RX_IND); // or RT_SERIAL_EVENT_RX_DMADONE
44
45 /* leave interrupt */
46 rt_interrupt_leave();
47 }
48
serial_txcallback(const struct usart_async_descriptor * const io_descr)49 static void serial_txcallback(const struct usart_async_descriptor *const io_descr)
50 {
51 (void)io_descr;
52
53 /* enter interrupt */
54 rt_interrupt_enter();
55
56 /* Notify Serial driver to process TX done event */
57 rt_hw_serial_isr(&sam_serial, RT_SERIAL_EVENT_TX_DONE);
58
59 /* leave interrupt */
60 rt_interrupt_leave();
61 }
62
63 /**
64 * @brief Configure serial port
65 *
66 * This function will configure UART baudrate, parity and so on.
67 *
68 * @return RT_EOK.
69 */
serial_configure(struct rt_serial_device * serial,struct serial_configure * cfg)70 static rt_err_t serial_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
71 {
72 struct usart_async_descriptor* desc;
73
74 RT_ASSERT(serial != RT_NULL);
75
76 desc = (struct usart_async_descriptor *)serial->parent.user_data;
77
78 RT_ASSERT(desc != RT_NULL);
79 RT_ASSERT(cfg != RT_NULL);
80
81 usart_async_disable(desc);
82
83 /* Set baudrate */
84 usart_async_set_baud_rate(desc, (const uint32_t)cfg->baud_rate);
85
86 /* Set stop bit */
87 if (cfg->stop_bits == STOP_BITS_1)
88 usart_async_set_stopbits(desc, USART_STOP_BITS_ONE);
89 else if (cfg->stop_bits == STOP_BITS_2)
90 usart_async_set_stopbits(desc, USART_STOP_BITS_TWO);
91
92 if (cfg->bit_order == BIT_ORDER_LSB)
93 usart_async_set_data_order(desc, USART_DATA_ORDER_LSB);
94 else if (cfg->bit_order == BIT_ORDER_MSB)
95 usart_async_set_data_order(desc, USART_DATA_ORDER_MSB);
96
97 /* Set character size */
98 switch (cfg->data_bits)
99 {
100 case DATA_BITS_5:
101 usart_async_set_character_size(desc, USART_CHARACTER_SIZE_5BITS);
102 break;
103 case DATA_BITS_6:
104 usart_async_set_character_size(desc, USART_CHARACTER_SIZE_6BITS);
105 break;
106 case DATA_BITS_7:
107 usart_async_set_character_size(desc, USART_CHARACTER_SIZE_7BITS);
108 break;
109 case DATA_BITS_8:
110 usart_async_set_character_size(desc, USART_CHARACTER_SIZE_8BITS);
111 break;
112 case DATA_BITS_9:
113 usart_async_set_character_size(desc, USART_CHARACTER_SIZE_9BITS);
114 break;
115 default:
116 break;
117 }
118
119 if (cfg->parity == PARITY_NONE)
120 usart_async_set_parity(desc, USART_PARITY_NONE);
121 else if (cfg->parity == PARITY_ODD)
122 usart_async_set_parity(desc, USART_PARITY_ODD);
123 else if (cfg->parity == PARITY_EVEN)
124 usart_async_set_parity(desc, USART_PARITY_EVEN);
125
126 usart_async_enable(desc);
127
128 return RT_EOK;
129 }
130
131 /**
132 * @brief Control serial port
133 *
134 * This function provide UART enable/disable control.
135 *
136 * @return RT_EOK.
137 */
serial_control(struct rt_serial_device * serial,int cmd,void * arg)138 static rt_err_t serial_control(struct rt_serial_device *serial, int cmd, void *arg)
139 {
140 struct usart_async_descriptor* desc;
141
142 RT_ASSERT(serial != RT_NULL);
143 desc = (struct usart_async_descriptor *)serial->parent.user_data;
144
145 RT_ASSERT(desc != RT_NULL);
146
147 switch (cmd)
148 {
149 /* disable interrupt */
150 case RT_DEVICE_CTRL_CLR_INT:
151 usart_async_disable(desc);
152 break;
153 /* enable interrupt */
154 case RT_DEVICE_CTRL_SET_INT:
155 usart_async_enable(desc);
156 break;
157 /* UART config */
158 case RT_DEVICE_CTRL_CONFIG: // RT_SERIAL_RX_NON_BLOCKING or RT_SERIAL_RX_BLOCKING
159 // RT_SERIAL_TX_NON_BLOCKING or RT_SERIAL_TX_BLOCKING
160 break;
161 #ifdef RT_USING_SERIAL_V2
162 case RT_DEVICE_CHECK_OPTMODE:
163 break;
164 #endif
165 default:
166 break;
167 }
168
169 return RT_EOK;
170 }
171
172 /**
173 * @brief Serial sends a char
174 *
175 * This function will send a char to the UART
176 *
177 * @return 1.
178 */
serial_putc(struct rt_serial_device * serial,char c)179 static int serial_putc(struct rt_serial_device *serial, char c)
180 {
181 struct usart_async_descriptor* desc;
182
183 RT_ASSERT(serial != RT_NULL);
184 desc = (struct usart_async_descriptor *)serial->parent.user_data;
185
186 RT_ASSERT(desc != RT_NULL);
187
188 while (usart_async_is_tx_empty(desc) == 0);
189 _usart_async_write_byte(&TARGET_IO.device, (uint8_t)c);
190
191 return 1;
192 }
193
194 /**
195 * @brief Serial gets a char
196 *
197 * This function will get a char from the UART
198 *
199 * @return received char character or -1 if no char received.
200 */
serial_getc(struct rt_serial_device * serial)201 static int serial_getc(struct rt_serial_device *serial)
202 {
203 char c;
204 int ch;
205 struct usart_async_descriptor* desc;
206
207 RT_ASSERT(serial != RT_NULL);
208 desc = (struct usart_async_descriptor *)serial->parent.user_data;
209
210 RT_ASSERT(desc != RT_NULL);
211
212 ch = -1;
213 if (usart_async_is_rx_not_empty(desc))
214 {
215 io_read(&desc->io, (uint8_t *)&c, 1);
216 ch = c & 0xff;
217 }
218
219 return ch;
220 }
221
222 static const struct rt_uart_ops sam_serial_ops =
223 {
224 serial_configure,
225 serial_control,
226 serial_putc,
227 serial_getc,
228 };
229
230 /**
231 * @brief Initialize the UART
232 *
233 * This function initialize the UART
234 *
235 * @return None.
236 */
rt_hw_uart_init(void)237 int rt_hw_uart_init(void)
238 {
239 struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
240 config.baud_rate = DEFAULT_USART_BAUD_RATE;
241
242 sam_serial.ops = &sam_serial_ops;
243 sam_serial.config = config;
244 sam_serial.serial_rx = RT_NULL;
245 sam_serial.serial_tx = RT_NULL;
246 rt_hw_serial_register(&sam_serial, "uart0" /* RT_CONSOLE_DEVICE_NAME */,
247 RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX |
248 RT_DEVICE_FLAG_INT_TX, (void *)&TARGET_IO);
249
250 usart_async_register_callback(&TARGET_IO, USART_ASYNC_TXC_CB, serial_txcallback);
251 usart_async_register_callback(&TARGET_IO, USART_ASYNC_RXC_CB, serial_rxcallback);
252
253 return 0;
254 }
255