Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
CC32xxUart.cxx
Go to the documentation of this file.
1
34#include <algorithm>
35
36#include "inc/hw_types.h"
37#include "inc/hw_memmap.h"
38#include "inc/hw_ints.h"
39#include "inc/hw_uart.h"
40#include "driverlib/rom.h"
41#include "driverlib/rom_map.h"
42#include "driverlib/interrupt.h"
43#include "driverlib/prcm.h"
44#include "driverlib/utils.h"
45#include "freertos/tc_ioctl.h"
47
48#include "CC32xxUart.hxx"
49
51static CC32xxUart *instances[2] = {NULL};
54
65CC32xxUart::CC32xxUart(const char *name, unsigned long base, uint32_t interrupt,
66 uint32_t baud, uint32_t mode, bool hw_fifo,
67 TxEnableMethod tx_enable_assert,
68 TxEnableMethod tx_enable_deassert)
69 : Serial(name)
70 , txEnableAssert_(tx_enable_assert)
71 , txEnableDeassert_(tx_enable_deassert)
72 , base_(base)
73 , interrupt_(interrupt)
74 , baud_(baud)
75 , uartMode_(mode | UART_CONFIG_PAR_NONE)
76 , txPending_(false)
77 , hwFIFO_(hw_fifo)
78 , nineBit_(false)
79{
80 static_assert(
81 UART_CONFIG_PAR_NONE == 0, "driverlib changed against our assumptions");
82 static_assert(
83 UART_CONFIG_STOP_ONE == 0, "driverlib changed against our assumptions");
84 HASSERT(uartMode_ <= 0xFFu);
85
86 switch (base)
87 {
88 default:
89 HASSERT(0);
90 case UARTA0_BASE:
91 MAP_PRCMPeripheralClkEnable(PRCM_UARTA0, PRCM_RUN_MODE_CLK);
92 instances[0] = this;
93 break;
94 case UARTA1_BASE:
95 MAP_PRCMPeripheralClkEnable(PRCM_UARTA1, PRCM_RUN_MODE_CLK);
96 instances[1] = this;
97 break;
98 }
99
100 MAP_UARTConfigSetExpClk(base_, cm3_cpu_clock_hz, baud, uartMode_);
101 MAP_IntDisable(interrupt_);
102 /* We set the priority so that it is slightly lower than the highest needed
103 * for FreeRTOS compatibility. This will ensure that CAN interrupts take
104 * precedence over UART. */
105 MAP_IntPrioritySet(interrupt_,
106 std::min(0xff, configKERNEL_INTERRUPT_PRIORITY + 0x20));
107 MAP_UARTIntEnable(base_, UART_INT_RX | UART_INT_RT);
108}
109
113{
114 MAP_IntEnable(interrupt_);
115 MAP_UARTEnable(base_);
116 if (hwFIFO_)
117 {
118 MAP_UARTFIFOEnable(base_);
119 }
120 else
121 {
122 MAP_UARTFIFODisable(base_);
123 }
124}
125
129{
130 MAP_IntDisable(interrupt_);
131 MAP_UARTDisable(base_);
132}
133
140int CC32xxUart::ioctl(File *file, unsigned long int key, unsigned long data)
141{
142 switch (key)
143 {
144 default:
145 return -EINVAL;
146 case TCSBRK:
147 MAP_UARTBreakCtl(base_, true);
148 // need to wait at least two frames here
149 MAP_UtilsDelay(100 * 26);
150 MAP_UARTBreakCtl(base_, false);
151 MAP_UtilsDelay(12 * 26);
152 break;
153 case TCPARNONE:
154 uartMode_ &= ~UART_CONFIG_PAR_MASK;
155 uartMode_ |= UART_CONFIG_PAR_NONE;
156 MAP_UARTParityModeSet(base_, UART_CONFIG_PAR_NONE);
157 break;
158 case TCPARODD:
159 uartMode_ &= ~UART_CONFIG_PAR_MASK;
160 uartMode_ |= UART_CONFIG_PAR_ODD;
161 MAP_UARTParityModeSet(base_, UART_CONFIG_PAR_ODD);
162 break;
163 case TCPAREVEN:
164 uartMode_ &= ~UART_CONFIG_PAR_MASK;
165 uartMode_ |= UART_CONFIG_PAR_EVEN;
166 MAP_UARTParityModeSet(base_, UART_CONFIG_PAR_EVEN);
167 break;
168 case TCPARONE:
169 uartMode_ &= ~UART_CONFIG_PAR_MASK;
170 uartMode_ |= UART_CONFIG_PAR_ONE;
171 MAP_UARTParityModeSet(base_, UART_CONFIG_PAR_ONE);
172 break;
173 case TCNINEBITRX:
174 nineBit_ = data != 0;
175 if (!nineBit_)
176 {
177 break;
178 }
179 // fall through
180 case TCPARZERO:
181 uartMode_ &= ~UART_CONFIG_PAR_MASK;
182 uartMode_ |= UART_CONFIG_PAR_ZERO;
183 MAP_UARTParityModeSet(base_, UART_CONFIG_PAR_ZERO);
184 break;
185 case TCSTOPONE:
186 uartMode_ &= ~UART_CONFIG_STOP_MASK;
187 uartMode_ |= UART_CONFIG_STOP_ONE;
188 set_mode();
189 break;
190 case TCSTOPTWO:
191 uartMode_ &= ~UART_CONFIG_STOP_MASK;
192 uartMode_ |= UART_CONFIG_STOP_TWO;
193 set_mode();
194 break;
195 case TCBAUDRATE:
196 baud_ = data;
197 set_mode();
198 break;
199 case TCDRAINNOTIFY:
200 {
201 Notifiable* arg = (Notifiable*)data;
202 {
204 if (txComplete_ != nullptr)
205 {
206 return -EBUSY;
207 }
208 if (txPending_)
209 {
210 txComplete_ = arg;
211 arg = nullptr;
212 }
213 }
214 if (arg)
215 {
216 arg->notify();
217 }
218 break;
219 }
220 }
221
222 return 0;
223}
224
227{
228 disable();
229 MAP_UARTConfigSetExpClk(base_, cm3_cpu_clock_hz, baud_, uartMode_);
230 enable();
231}
232
236{
237 do
238 {
239 uint8_t data = 0;
240 if (txBuf->get(&data, 1))
241 {
242 MAP_UARTCharPutNonBlocking(base_, data);
243
244 }
245 else
246 {
247 break;
248 }
249 }
250 while (MAP_UARTSpaceAvail(base_));
251
252 if (txBuf->pending())
253 {
254 /* more data to send later */
255 MAP_UARTTxIntModeSet(base_, UART_TXINT_MODE_FIFO);
256 }
257 else
258 {
259 /* no more data left to send */
260 MAP_UARTTxIntModeSet(base_, UART_TXINT_MODE_EOT);
261 MAP_UARTIntClear(base_, UART_INT_TX);
262 }
263}
264
268{
269 if (txPending_ == false)
270 {
271 if (txEnableAssert_)
272 {
274 }
275
276 send();
277 txPending_ = true;
278
279 MAP_UARTIntEnable(base_, UART_INT_TX);
281 }
282}
283
287{
288 int woken = false;
289 /* get and clear the interrupt status */
290 unsigned long status = MAP_UARTIntStatus(base_, true);
291 MAP_UARTIntClear(base_, status);
292
296 /* receive charaters as long as we can */
297 while (MAP_UARTCharsAvail(base_))
298 {
299 long data = MAP_UARTCharGetNonBlocking(base_);
300 if (nineBit_)
301 {
302 if (rxBuf->space() < 2)
303 {
304 ++overrunCount;
305 }
306 else
307 {
308 // parity error bit is moved to the ninth bit, then two bytes
309 // are written to the buffer.
310 long bit9 = (data & 0x200) >> 1;
311 data &= 0xff;
312 data |= bit9;
313 rxBuf->put((uint8_t *)&data, 2);
315 }
316 }
317 else if (data >= 0 && data <= 0xff)
318 {
319 if (rxBuf->space() < 1)
320 {
321 ++overrunCount;
322 }
323 else
324 {
325 unsigned char c = data;
326 rxBuf->put(&c, 1);
328 }
329 }
330 }
331 /* transmit a character if we have pending tx data */
332 if (txPending_ && (status & UART_INT_TX))
333 {
334 if (txBuf->pending())
335 {
336 send();
338 }
339 else
340 {
341 /* no more data left to send */
342 HASSERT(MAP_UARTTxIntModeGet(base_) == UART_TXINT_MODE_EOT);
344 {
346 }
347 txPending_ = false;
348 if (txComplete_)
349 {
351 txComplete_ = nullptr;
352 t->notify_from_isr();
353 }
354 MAP_UARTIntDisable(base_, UART_INT_TX);
355 }
356 }
357 os_isr_exit_yield_test(woken);
358}
359
360extern "C" {
364{
365 if (instances[0])
366 {
368 }
369}
370
373void __attribute__((__weak__)) uart1_interrupt_handler(void)
374{
375 if (instances[1])
376 {
378 }
379}
380
381} // extern C
static CC32xxUart * instances[2]
Instance pointers help us get context from the interrupt handler(s)
void uart0_interrupt_handler(void)
UART0 interrupt handler.
static Atomic isr_lock
Critical section lock between ISR and ioctl.
void uart1_interrupt_handler(void)
UART1 interrupt handler.
See OSMutexLock in os/OS.hxx.
Definition Atomic.hxx:153
Lightweight locking class for protecting small critical sections.
Definition Atomic.hxx:130
Specialization of Serial driver for CC32xx UART.
uint8_t txPending_
transmission currently pending
void disable() override
function to disable device
Notifiable * txComplete_
Notifiable to invoke when the transmit engine has finished operation.
void tx_char() override
Try and transmit a message.
uint8_t hwFIFO_
true if hardware fifo is to be enabled, else false
CC32xxUart()
Default constructor.
unsigned long base_
base address of this device
TxEnableMethod txEnableAssert_
function pointer to a method that asserts the transmit enable.
void send()
Send data until there is no more space left.
uint32_t interrupt_
interrupt of this device
uint32_t baud_
desired baud rate
void set_mode()
Sets the port baud rate and mode from the class variables.
uint8_t nineBit_
true if using 9-bit reception
uint32_t uartMode_
mode of the UART, 8 or 9 bit, 1 or 2 stop...
TxEnableMethod txEnableDeassert_
function pointer to a method that deasserts the transmit enable.
int ioctl(File *file, unsigned long int key, unsigned long data) override
Request an ioctl transaction.
void enable() override
function to enable device
void interrupt_handler()
handle an interrupt.
size_t space()
Return the number of items for which space is available.
void signal_condition()
Signal the wakeup condition.
size_t pending()
Return the number of items in the queue.
void signal_condition_from_isr()
Signal the wakeup condition from an ISR context.
size_t get(T *buf, size_t items)
remove a number of items from the buffer.
size_t put(const T *buf, size_t items)
Insert a number of items to the buffer.
An object that can schedule itself on an executor to run.
virtual void notify()=0
Generic callback.
Private data for a serial device.
Definition Serial.hxx:46
DeviceBuffer< uint8_t > * rxBuf
receive buffer
Definition Serial.hxx:85
DeviceBuffer< uint8_t > * txBuf
transmit buffer
Definition Serial.hxx:84
unsigned int overrunCount
overrun count
Definition Serial.hxx:86
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
File information.
Definition Devtab.hxx:52
#define TCBAUDRATE
Argument is the desired baud rate for the port.
Definition tc_ioctl.h:61
#define TCDRAINNOTIFY
Argument is a Notifiable* pointer.
Definition tc_ioctl.h:58
#define TCNINEBITRX
Use 9-bit reception mode.
Definition tc_ioctl.h:50
#define TCSTOPTWO
Two stop bits.
Definition tc_ioctl.h:54
#define TCSTOPONE
One stop bit.
Definition tc_ioctl.h:52