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