Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
TivaUart.cxx
Go to the documentation of this file.
1
34#include <algorithm>
35
36#include <stdint.h>
37#include <tc_ioctl.h>
38
39#include "inc/hw_types.h"
40#include "inc/hw_memmap.h"
41#include "inc/hw_ints.h"
42#include "inc/hw_uart.h"
43#include "driverlib/rom.h"
44#include "driverlib/rom_map.h"
45#include "driverlib/uart.h"
46#include "driverlib/interrupt.h"
47#include "driverlib/sysctl.h"
48
49#include "TivaDev.hxx"
50
52static TivaUart *instances[8] = {NULL};
53
56
62TivaUart::TivaUart(const char *name, unsigned long base, uint32_t interrupt,
63 uint32_t baud, uint32_t mode, bool hw_fifo, TxEnableMethod tx_enable_assert,
64 TxEnableMethod tx_enable_deassert)
65 : Serial(name)
66 , txEnableAssert_(tx_enable_assert)
67 , txEnableDeassert_(tx_enable_deassert)
68 , base_(base)
69 , interrupt_(interrupt)
70 , baud_(baud)
71 , hwFIFO_(hw_fifo)
72 , uartMode_(mode)
73 , txPending_(false)
74 , nineBit_(false)
75{
76 static_assert(
77 UART_CONFIG_PAR_NONE == 0, "driverlib changed against our assumptions");
78 static_assert(
79 UART_CONFIG_STOP_ONE == 0, "driverlib changed against our assumptions");
80 HASSERT(mode <= 0xFFu);
81
82 switch (base_)
83 {
84 default:
85 HASSERT(0);
86 case UART0_BASE:
87 MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
88 instances[0] = this;
89 break;
90 case UART1_BASE:
91 MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);
92 instances[1] = this;
93 break;
94 case UART2_BASE:
95 MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART2);
96 instances[2] = this;
97 break;
98 case UART3_BASE:
99 MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART3);
100 instances[3] = this;
101 break;
102 case UART4_BASE:
103 MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART4);
104 instances[4] = this;
105 break;
106 case UART5_BASE:
107 MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART5);
108 instances[5] = this;
109 break;
110 case UART6_BASE:
111 MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART6);
112 instances[6] = this;
113 break;
114 case UART7_BASE:
115 MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART7);
116 instances[7] = this;
117 break;
118 }
119
120 MAP_UARTConfigSetExpClk(base_, cm3_cpu_clock_hz, baud_, uartMode_);
121 MAP_UARTTxIntModeSet(base_, UART_TXINT_MODE_EOT);
122 MAP_IntDisable(interrupt_);
123 /* We set the priority so that it is slightly lower than the highest needed
124 * for FreeRTOS compatibility. This will ensure that CAN interrupts take
125 * precedence over UART. */
126 MAP_IntPrioritySet(interrupt_,
127 std::min(0xff, configKERNEL_INTERRUPT_PRIORITY + 0x20));
128 MAP_UARTIntEnable(base_, UART_INT_RX | UART_INT_RT);
129}
130
134{
135 MAP_IntEnable(interrupt_);
136 MAP_UARTEnable(base_);
137 if (hwFIFO_)
138 {
139 MAP_UARTFIFOEnable(base_);
140 }
141 else
142 {
143 MAP_UARTFIFODisable(base_);
144 }
145}
146
150{
151 MAP_IntDisable(interrupt_);
152 MAP_UARTDisable(base_);
153}
154
158{
159 do
160 {
161 uint8_t data = 0;
162 if (txBuf->get(&data, 1))
163 {
164 MAP_UARTCharPutNonBlocking(base_, data);
165
166 }
167 else
168 {
169 break;
170 }
171 }
172 while (MAP_UARTSpaceAvail(base_));
173
174 if (txBuf->pending())
175 {
176 /* more data to send later */
177 MAP_UARTTxIntModeSet(base_, UART_TXINT_MODE_FIFO);
178 }
179 else
180 {
181 /* no more data left to send */
182 MAP_UARTTxIntModeSet(base_, UART_TXINT_MODE_EOT);
183 MAP_UARTIntClear(base_, UART_INT_TX);
184 }
185}
186
190{
191 if (txPending_ == false)
192 {
193 if (txEnableAssert_)
194 {
196 }
197
198 send();
199 txPending_ = true;
200
201 MAP_UARTIntEnable(base_, UART_INT_TX);
203 }
204}
205
209{
210 int woken = false;
211 /* get and clear the interrupt status */
212 unsigned long status = MAP_UARTIntStatus(base_, true);
213 MAP_UARTIntClear(base_, status);
214
218 /* receive charaters as long as we can */
219 while (MAP_UARTCharsAvail(base_))
220 {
221 long data = MAP_UARTCharGetNonBlocking(base_);
222 if (nineBit_)
223 {
224 if (rxBuf->space() < 2)
225 {
226 ++overrunCount;
227 }
228 else
229 {
230 // parity error bit is moved to the ninth bit, then two bytes
231 // are written to the buffer.
232 long bit9 = (data & 0x200) >> 1;
233 data &= 0xff;
234 data |= bit9;
235 rxBuf->put((uint8_t *)&data, 2);
237 }
238 }
239 else if (data >= 0 && data <= 0xff)
240 {
241 if (rxBuf->space() < 1)
242 {
243 ++overrunCount;
244 }
245 else
246 {
247 unsigned char c = data;
248 rxBuf->put(&c, 1);
250 }
251 }
252 }
253 /* transmit a character if we have pending tx data */
254 if (txPending_ && (status & UART_INT_TX))
255 {
256 if (txBuf->pending())
257 {
258 send();
260 }
261 else
262 {
263 /* no more data left to send */
264 HASSERT(MAP_UARTTxIntModeGet(base_) == UART_TXINT_MODE_EOT);
266 {
268 }
269 txPending_ = false;
270 if (txComplete_)
271 {
273 txComplete_ = nullptr;
274 t->notify_from_isr();
275 }
276 MAP_UARTIntDisable(base_, UART_INT_TX);
277 }
278 }
279 os_isr_exit_yield_test(woken);
280}
281
284{
285 MAP_UARTConfigSetExpClk(base_, cm3_cpu_clock_hz, baud_, uartMode_);
286}
287
294int TivaUart::ioctl(File *file, unsigned long int key, unsigned long data)
295{
296 switch (key)
297 {
298 default:
299 return -EINVAL;
300 case TCSBRK:
301 MAP_UARTBreakCtl(base_, true);
302 // need to wait at least two frames here
303 MAP_SysCtlDelay(100 * 26);
304 MAP_UARTBreakCtl(base_, false);
305 MAP_SysCtlDelay(12 * 26);
306 break;
307 case TCPARNONE:
308 uartMode_ &= ~UART_CONFIG_PAR_MASK;
309 uartMode_ |= UART_CONFIG_PAR_NONE;
310 MAP_UARTParityModeSet(base_, UART_CONFIG_PAR_NONE);
311 break;
312 case TCPARODD:
313 uartMode_ &= ~UART_CONFIG_PAR_MASK;
314 uartMode_ |= UART_CONFIG_PAR_ODD;
315 MAP_UARTParityModeSet(base_, UART_CONFIG_PAR_ODD);
316 break;
317 case TCPAREVEN:
318 uartMode_ &= ~UART_CONFIG_PAR_MASK;
319 uartMode_ |= UART_CONFIG_PAR_EVEN;
320 MAP_UARTParityModeSet(base_, UART_CONFIG_PAR_EVEN);
321 break;
322 case TCPARONE:
323 uartMode_ &= ~UART_CONFIG_PAR_MASK;
324 uartMode_ |= UART_CONFIG_PAR_ONE;
325 MAP_UARTParityModeSet(base_, UART_CONFIG_PAR_ONE);
326 break;
327 case TCNINEBITRX:
328 nineBit_ = data != 0;
329 if (!nineBit_)
330 {
331 break;
332 }
333 // fall through
334 case TCPARZERO:
335 uartMode_ &= ~UART_CONFIG_PAR_MASK;
336 uartMode_ |= UART_CONFIG_PAR_ZERO;
337 MAP_UARTParityModeSet(base_, UART_CONFIG_PAR_ZERO);
338 break;
339 case TCSTOPONE:
340 uartMode_ &= ~UART_CONFIG_STOP_MASK;
341 uartMode_ |= UART_CONFIG_STOP_ONE;
342 set_mode();
343 break;
344 case TCSTOPTWO:
345 uartMode_ &= ~UART_CONFIG_STOP_MASK;
346 uartMode_ |= UART_CONFIG_STOP_TWO;
347 set_mode();
348 break;
349 case TCBAUDRATE:
350 baud_ = data;
351 set_mode();
352 break;
353 case TCDRAINNOTIFY:
354 {
355 Notifiable* arg = (Notifiable*)data;
356 {
358 if (txComplete_ != nullptr)
359 {
360 return -EBUSY;
361 }
362 if (txPending_)
363 {
364 txComplete_ = arg;
365 arg = nullptr;
366 }
367 }
368 if (arg)
369 {
370 arg->notify();
371 }
372 break;
373 }
374 }
375
376 return 0;
377}
378
379extern "C" {
383{
384 if (instances[0])
385 {
387 }
388}
389
392void __attribute__((__weak__)) uart1_interrupt_handler(void)
393{
394 if (instances[1])
395 {
397 }
398}
399
402void __attribute__((__weak__)) uart2_interrupt_handler(void)
403{
404 if (instances[2])
405 {
407 }
408}
409
412void __attribute__((__weak__)) uart3_interrupt_handler(void)
413{
414 if (instances[3])
415 {
417 }
418}
421void __attribute__((__weak__)) uart4_interrupt_handler(void)
422{
423 if (instances[4])
424 {
426 }
427}
428
431void __attribute__((__weak__)) uart5_interrupt_handler(void)
432{
433 if (instances[5])
434 {
436 }
437}
438
441void __attribute__((__weak__)) uart6_interrupt_handler(void)
442{
443 if (instances[6])
444 {
446 }
447}
448
451void __attribute__((__weak__)) uart7_interrupt_handler(void)
452{
453 if (instances[7])
454 {
456 }
457}
458
459} // extern C
static CC32xxUart * instances[2]
Instance pointers help us get context from the interrupt handler(s)
static Atomic isr_lock
Critical section lock between ISR and ioctl.
void uart2_interrupt_handler(void)
UART2 interrupt handler.
Definition TivaUart.cxx:402
void uart0_interrupt_handler(void)
UART0 interrupt handler.
Definition TivaUart.cxx:382
void uart6_interrupt_handler(void)
UART6 interrupt handler.
Definition TivaUart.cxx:441
void uart3_interrupt_handler(void)
UART3 interrupt handler.
Definition TivaUart.cxx:412
static Atomic isr_lock
Critical section lock between ISR and ioctl.
Definition TivaUart.cxx:55
void uart7_interrupt_handler(void)
UART7 interrupt handler.
Definition TivaUart.cxx:451
void uart1_interrupt_handler(void)
UART1 interrupt handler.
Definition TivaUart.cxx:392
void uart4_interrupt_handler(void)
UART4 interrupt handler.
Definition TivaUart.cxx:421
static TivaUart * instances[8]
Instance pointers help us get context from the interrupt handler(s)
Definition TivaUart.cxx:52
void uart5_interrupt_handler(void)
UART5 interrupt handler.
Definition TivaUart.cxx:431
See OSMutexLock in os/OS.hxx.
Definition Atomic.hxx:153
Lightweight locking class for protecting small critical sections.
Definition Atomic.hxx:130
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
Specialization of Serial driver for Tiva UART.
Definition TivaDev.hxx:156
uint8_t nineBit_
true if using 9-bit reception
Definition TivaDev.hxx:232
uint8_t hwFIFO_
enable HW FIFO
Definition TivaDev.hxx:229
void tx_char() override
Try and transmit a message.
Definition TivaUart.cxx:189
void disable() override
function to disable device
Definition TivaUart.cxx:149
void interrupt_handler()
handle an interrupt.
Definition TivaUart.cxx:208
void send()
Send data until there is no more space left.
Definition TivaUart.cxx:157
uint8_t uartMode_
uart config (mode) flags
Definition TivaDev.hxx:230
void set_mode()
Sets the port baud rate and mode from the class variables.
Definition TivaUart.cxx:283
void enable() override
function to enable device
Definition TivaUart.cxx:133
uint32_t baud_
desired baud rate
Definition TivaDev.hxx:228
TxEnableMethod txEnableAssert_
function pointer to a method that asserts the transmit enable.
Definition TivaDev.hxx:218
uint32_t interrupt_
interrupt of this device
Definition TivaDev.hxx:227
TxEnableMethod txEnableDeassert_
function pointer to a method that deasserts the transmit enable.
Definition TivaDev.hxx:221
uint32_t base_
base address of this device
Definition TivaDev.hxx:226
TivaUart()
Default constructor.
int ioctl(File *file, unsigned long int key, unsigned long data) override
Request an ioctl transaction.
Definition TivaUart.cxx:294
Notifiable * txComplete_
Notifiable to invoke when the transmit engine has finished operation.
Definition TivaDev.hxx:224
uint8_t txPending_
transmission currently pending
Definition TivaDev.hxx:231
#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