1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2013-05-18     Bernard      The first version for LPC40xx
9  * 2014-07-18     ArdaFu       Port to TM4C129X
10  */
11 
12 #include <rthw.h>
13 #include <rtthread.h>
14 #include <rtdevice.h>
15 
16 #include "board.h"
17 
18 #include "inc/hw_memmap.h"
19 #include "driverlib/sysctl.h"
20 #include "driverlib/gpio.h"
21 #include "driverlib/uart.h"
22 #include "driverlib/pin_map.h"
23 #include "driverlib/interrupt.h"
24 #include "driverlib/rom_map.h"
25 typedef struct hw_uart_device
26 {
27     uint32_t hw_base; // base address
28 }hw_uart_t;
29 
30 #define mUartGetHwPtr(serial) ((hw_uart_t*)(serial->parent.user_data))
31 
hw_configure(struct rt_serial_device * serial,struct serial_configure * cfg)32 static rt_err_t hw_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
33 {
34     uint32_t config = 0;
35     hw_uart_t* uart;
36     RT_ASSERT(serial != RT_NULL);
37     uart = mUartGetHwPtr(serial);
38 
39     MAP_UARTDisable(uart->hw_base);
40     // build UART Configuration parameter structure
41     switch(cfg->data_bits)
42     {
43     case DATA_BITS_9:
44         // enable 9bit address mode and set DATA_BIT_8
45         MAP_UART9BitEnable(uart->hw_base);
46     case DATA_BITS_8:
47         config |= UART_CONFIG_WLEN_8;
48         break;
49     case DATA_BITS_7:
50         config |= UART_CONFIG_WLEN_7;
51         break;
52     case DATA_BITS_6:
53         config |= UART_CONFIG_WLEN_6;
54         break;
55     case DATA_BITS_5:
56         config |= UART_CONFIG_WLEN_5;
57         break;
58     default:
59         RT_ASSERT(0);
60         break;
61     }
62     switch(cfg->parity)
63     {
64     case PARITY_ODD:
65         config |= UART_CONFIG_PAR_ODD;
66         break;
67     case PARITY_EVEN:
68         config |= UART_CONFIG_PAR_EVEN;
69         break;
70     case PARITY_NONE:
71         config |= UART_CONFIG_PAR_NONE;
72         break;
73     default:
74         RT_ASSERT(0);
75         break;
76     }
77     switch(cfg->stop_bits)
78     {
79     case STOP_BITS_1:
80         config |= UART_CONFIG_STOP_ONE;
81         break;
82     case STOP_BITS_2:
83         config |= UART_CONFIG_STOP_TWO;
84         break;
85     default:
86         RT_ASSERT(0);
87         break;
88     }
89 
90     // Initialize UART0 peripheral with given to corresponding parameter
91     MAP_UARTConfigSetExpClk(uart->hw_base, SystemCoreClock, cfg->baud_rate, config);
92     MAP_UARTFIFOEnable(uart->hw_base);
93 
94     // Enable the UART.
95     MAP_UARTEnable(uart->hw_base);
96     return RT_EOK;
97 }
98 
hw_control(struct rt_serial_device * serial,int cmd,void * arg)99 static rt_err_t hw_control(struct rt_serial_device *serial, int cmd, void *arg)
100 {
101     hw_uart_t* uart;
102     RT_ASSERT(serial != RT_NULL);
103     uart = mUartGetHwPtr(serial);
104 
105     switch (cmd)
106     {
107     case RT_DEVICE_CTRL_CLR_INT:
108         /* disable rx irq */
109         MAP_UARTIntDisable(uart->hw_base, UART_INT_RX | UART_INT_RT);
110         break;
111     case RT_DEVICE_CTRL_SET_INT:
112         /* enable rx irq */
113         MAP_UARTIntEnable(uart->hw_base, UART_INT_RX | UART_INT_RT);
114         break;
115     }
116 
117     return RT_EOK;
118 }
119 
hw_putc(struct rt_serial_device * serial,char c)120 static int hw_putc(struct rt_serial_device *serial, char c)
121 {
122     hw_uart_t* uart;
123     RT_ASSERT(serial != RT_NULL);
124     uart = mUartGetHwPtr(serial);
125 
126     MAP_UARTCharPut(uart->hw_base, *((uint8_t *)&c));
127     return 1;
128 }
129 
hw_getc(struct rt_serial_device * serial)130 static int hw_getc(struct rt_serial_device *serial)
131 {
132     hw_uart_t* uart;
133     RT_ASSERT(serial != RT_NULL);
134     uart = mUartGetHwPtr(serial);
135 
136     return MAP_UARTCharGetNonBlocking(uart->hw_base);
137 }
138 
139 static const struct rt_uart_ops hw_uart_ops =
140 {
141     hw_configure,
142     hw_control,
143     hw_putc,
144     hw_getc,
145 };
146 
147 #if defined(RT_USING_UART0)
148 /* UART0 device driver structure */
149 struct rt_serial_device serial0;
150 hw_uart_t uart0 =
151 {
152     UART0_BASE,
153 };
154 
UART0_IRQHandler(void)155 void UART0_IRQHandler(void)
156 {
157     uint32_t intsrc;
158     hw_uart_t *uart = &uart0;
159 
160     /* enter interrupt */
161     rt_interrupt_enter();
162 
163     /* Determine the interrupt source */
164     intsrc = MAP_UARTIntStatus(uart->hw_base, true);
165 
166     // Receive Data Available or Character time-out
167     if (intsrc & (UART_INT_RX | UART_INT_RT))
168     {
169         MAP_UARTIntClear(uart->hw_base, intsrc);
170         rt_hw_serial_isr(&serial0, RT_SERIAL_EVENT_RX_IND);
171     }
172 
173     /* leave interrupt */
174     rt_interrupt_leave();
175 }
176 #endif
177 
rt_hw_uart_init(void)178 int rt_hw_uart_init(void)
179 {
180     hw_uart_t* uart;
181     struct serial_configure config;
182 
183     config.baud_rate = BAUD_RATE_115200;
184     config.bit_order = BIT_ORDER_LSB;
185     config.data_bits = DATA_BITS_8;
186     config.parity    = PARITY_NONE;
187     config.stop_bits = STOP_BITS_1;
188     config.invert    = NRZ_NORMAL;
189     config.bufsz     = RT_SERIAL_RB_BUFSZ;
190 
191 #ifdef RT_USING_UART0
192     uart = &uart0;
193     serial0.ops    = &hw_uart_ops;
194     serial0.config = config;
195 
196     MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
197     MAP_GPIOPinConfigure(GPIO_PA0_U0RX);
198     MAP_GPIOPinConfigure(GPIO_PA1_U0TX);
199 
200     MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
201     MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
202 
203     /* preemption = 1, sub-priority = 1 */
204     //IntPrioritySet(INT_UART0, ((0x01 << 5) | 0x01));
205 
206     /* Enable Interrupt for UART channel */
207       UARTIntRegister(uart->hw_base, UART0_IRQHandler);
208       MAP_IntEnable(INT_UART0);
209       MAP_UARTEnable(uart->hw_base);
210 
211     /* register UART0 device */
212     rt_hw_serial_register(&serial0, "uart0",
213                           RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
214                           uart);
215 #endif
216     return 0;
217 }
218 INIT_BOARD_EXPORT(rt_hw_uart_init);
219