Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
TivaCan.cxx
Go to the documentation of this file.
1
34#include <stdint.h>
35
36#include "can_ioctl.h"
37#include "driverlib/can.h"
38#include "driverlib/interrupt.h"
39#include "driverlib/rom.h"
40#include "driverlib/rom_map.h"
41#include "driverlib/sysctl.h"
42#include "inc/hw_can.h"
43#include "inc/hw_ints.h"
44#include "inc/hw_memmap.h"
45#include "inc/hw_types.h"
46#include "nmranet_config.h"
47
48#include "TivaDev.hxx"
49
51static TivaCan *instances[2] = {NULL};
52
58TivaCan::TivaCan(const char *name, unsigned long base, uint32_t interrupt)
59 : Can(name)
60 , base(base)
61 , interrupt(interrupt)
62 , txPending(false)
63 , canState(CAN_STATE_STOPPED)
64{
65 switch (base)
66 {
67 default:
68 HASSERT(0);
69 case CAN0_BASE:
70 MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);
71 instances[0] = this;
72 break;
73 case CAN1_BASE:
74 MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN1);
75 instances[1] = this;
76 break;
77 }
78
79 MAP_CANInit(base);
80
81 uint32_t ftq = config_nmranet_can_bitrate() * 16;
82 // If this fails, the CAN bit timings do not support this CPU clock. The
83 // CPU clock has to be an even number of MHz.
84 HASSERT(cm3_cpu_clock_hz % ftq == 0);
85
86 /* Nominal 2 MHz quantum clock
87 * SyncSeg = 1 TQ
88 * PropSeg = 7 TQ
89 * PS1 = 4 TQ
90 * PS2 = 4 TQ
91 * Bit total = 16 TQ
92 * Baud = 125 kHz
93 * sample time = (1 TQ + 7 TQ + 4 TQ) / 16 TQ = 75%
94 * SJW = 4 TQ
95 *
96 * Oscillator Tolerance:
97 * 4 / (2 * ((13 * 16) - 4)) = 0.980%
98 * 4 / (20 * 16) = 1.250%
99 * = 0.980%
100 */
101 tCANBitClkParms clk_params = {
102 .ui32SyncPropPhase1Seg = 11, // Sum of PropSeg and PS1 in #TQ
103 .ui32Phase2Seg = 4, // PS2 in #TQ
104 .ui32SJW = 4,
105 .ui32QuantumPrescaler = cm3_cpu_clock_hz / ftq
106 };
107 MAP_CANBitTimingSet(base, &clk_params);
108 MAP_CANIntEnable(base, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);
109
110 tCANMsgObject can_message;
111 can_message.ui32MsgID = 0;
112 can_message.ui32MsgIDMask = 0;
113 can_message.ui32Flags = MSG_OBJ_RX_INT_ENABLE | MSG_OBJ_USE_ID_FILTER;
114 can_message.ui32MsgLen = 8;
115 MAP_CANMessageSet(base, 1, &can_message, MSG_OBJ_TYPE_RX);
116}
117
118//
119// TCAN4550Can::ioctl()
120//
121int TivaCan::ioctl(File *file, unsigned long int key, unsigned long data)
122{
123 if (key == SIOCGCANSTATE)
124 {
125 *((can_state_t *)data) = canState;
126 return 0;
127 }
128 return -EINVAL;
129}
130
134{
135 MAP_CANBitRateSet(base, cm3_cpu_clock_hz, config_nmranet_can_bitrate());
136 MAP_IntEnable(interrupt);
137 // The priority of CAN interrupt is as high as possible while maintaining
138 // FreeRTOS compatibility.
139 MAP_IntPrioritySet(interrupt, configKERNEL_INTERRUPT_PRIORITY);
140 MAP_CANEnable(base);
141 // Wait for a successful RX or TX before moving to CAN_STATE_ACTIVE.
143}
144
148{
150 MAP_IntDisable(interrupt);
151 MAP_CANDisable(base);
152}
153
154/* Try and transmit a message.
155 */
157{
158 if (txPending == false || canState != CAN_STATE_ACTIVE)
159 {
160 struct can_frame *can_frame;
161
162 if (txBuf->data_read_pointer(&can_frame))
163 {
164 /* load the next message to transmit */
165 tCANMsgObject can_message;
166 can_message.ui32MsgID = can_frame->can_id;
167 can_message.ui32MsgIDMask = 0;
168 can_message.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
169 if (can_frame->can_eff)
170 {
171 can_message.ui32Flags |= MSG_OBJ_EXTENDED_ID;
172 }
173 if (can_frame->can_rtr)
174 {
175 can_message.ui32Flags |= MSG_OBJ_REMOTE_FRAME;
176 }
177 can_message.ui32MsgLen = can_frame->can_dlc;
178 /* zero copy data */
179 can_message.pui8MsgData = can_frame->data;
180
181 MAP_CANMessageSet(base, 2, &can_message, MSG_OBJ_TYPE_TX);
182 txPending = true;
183 }
184 }
186 {
187 txBuf->flush();
189 }
190}
191
195{
196 uint32_t status = MAP_CANIntStatus(base, CAN_INT_STS_CAUSE);
198 int woken = false;
199
200 if (status == CAN_INT_INTID_STATUS)
201 {
202 bool cancel_queue = false;
203
204 status = MAP_CANStatusGet(base, CAN_STS_CONTROL);
205 /* some error occured */
206 if (status & CAN_STATUS_BUS_OFF)
207 {
208 /* bus off error condition */
209 ++busOffCount;
211
212 cancel_queue = true;
213
214 /* attempt recovery */
215 MAP_CANEnable(base);
216 }
217 if (status & CAN_STATUS_EWARN)
218 {
219 /* One of the error counters has exceded a value of 96 */
221 }
222 if (status & CAN_STATUS_EPASS)
223 {
224 /* In error passive state */
226 cancel_queue = true;
227 }
228 if (status & CAN_STATUS_LEC_STUFF)
229 {
230 /* bit stuffing error occured */
231 }
232 if (status & CAN_STATUS_LEC_FORM)
233 {
234 /* format error occured in the fixed format part of the message */
235 }
236 if (status & CAN_STATUS_LEC_ACK)
237 {
238 /* a transmit message was not acked */
239 }
240 if (status & CAN_STATUS_LEC_CRC)
241 {
242 /* CRC error detected in received message */
243 }
244
245 if (cancel_queue)
246 {
247 /* flush data in the tx pipeline */
248 txBuf->flush();
249 txPending = false;
251 }
252 }
253 else if (status == 1)
254 {
255 /* rx data received */
257
258 struct can_frame *can_frame;
259 if (rxBuf->data_write_pointer(&can_frame))
260 {
261 /* we have space remaining to buffer up this incoming message */
262 tCANMsgObject can_message;
263 can_message.pui8MsgData = can_frame->data;
264 /* Read a message from CAN and clear the interrupt source */
265 MAP_CANMessageGet(base, 1, &can_message, 1 /* clear interrupt */);
266
267 can_frame->can_id = can_message.ui32MsgID;
268 can_frame->can_rtr = (can_message.ui32Flags & MSG_OBJ_REMOTE_FRAME) ? 1 : 0;
269 can_frame->can_eff = (can_message.ui32Flags & MSG_OBJ_EXTENDED_ID) ? 1 : 0;
270 can_frame->can_err = 0;
271 can_frame->can_dlc = can_message.ui32MsgLen;
272 rxBuf->advance(1);
273 ++numReceivedPackets_;
275
279 if (readableNotify_)
280 {
281 readableNotify_->notify_from_isr();
282 readableNotify_ = nullptr;
283 }
284 }
285 else
286 {
287 /* ran out of space to buffer, flush incoming message */
288 ++overrunCount;
289 tCANMsgObject can_message;
290 can_message.pui8MsgData = can_frame->data;
291 /* Read a message from CAN and clear the interrupt source */
292 MAP_CANMessageGet(base, 1, &can_message, 1 /* clear interrupt */);
293 }
294 }
295 else if (status == 2)
296 {
297 /* tx complete */
298 MAP_CANIntClear(base, 2);
300
301 /* previous (zero copy) message from buffer no longer needed */
302 txBuf->consume(1);
303 ++numTransmittedPackets_;
305
309 if (writableNotify_)
310 {
311 writableNotify_->notify_from_isr();
312 writableNotify_= nullptr;
313 }
314
315 struct can_frame *can_frame;
316
317 if (txBuf->data_read_pointer(&can_frame))
318 {
319 /* load the next message to transmit */
320 tCANMsgObject can_message;
321 can_message.ui32MsgID = can_frame->can_id;
322 can_message.ui32MsgIDMask = 0;
323 can_message.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
324 if (can_frame->can_eff)
325 {
326 can_message.ui32Flags |= MSG_OBJ_EXTENDED_ID;
327 }
328 if (can_frame->can_rtr)
329 {
330 can_message.ui32Flags |= MSG_OBJ_REMOTE_FRAME;
331 }
332 can_message.ui32MsgLen = can_frame->can_dlc;
333 /* zero copy data */
334 can_message.pui8MsgData = can_frame->data;
335
336 MAP_CANMessageSet(base, 2, &can_message, MSG_OBJ_TYPE_TX);
337 }
338 else
339 {
340 /* no more messages pending transmission */
341 txPending = false;
342 }
343 }
344 os_isr_exit_yield_test(woken);
345}
346
347extern "C" {
351{
352 if (instances[0])
353 {
355 }
356}
357
361{
362 if (instances[1])
363 {
365 }
366}
367
368} // extern "C"
static CC32xxUart * instances[2]
Instance pointers help us get context from the interrupt handler(s)
void can0_interrupt_handler(void)
This is the interrupt handler for the can0 device.
Definition TivaCan.cxx:350
static TivaCan * instances[2]
Instance pointers help us get context from the interrupt handler(s)
Definition TivaCan.cxx:51
void can1_interrupt_handler(void)
This is the interrupt handler for the can1 device.
Definition TivaCan.cxx:360
Base class for a CAN device for the Arduino environment.
unsigned int overrunCount
overrun count
unsigned int softErrorCount
soft error count
DeviceBuffer< struct can_frame > * txBuf
transmit buffer
unsigned int busOffCount
bus-off count
DeviceBuffer< struct can_frame > * rxBuf
receive buffer
void flush()
flush all the data out of the buffer and reset the buffer.
size_t advance(size_t items)
Add a number of items to the buffer by advancing the writeIndex.
void signal_condition()
Signal the wakeup condition.
size_t consume(size_t items)
Remove a number of items from the buffer by advancing the readIndex.
void signal_condition_from_isr()
Signal the wakeup condition from an ISR context.
size_t data_write_pointer(T **buf)
Get a reference to the current location in the buffer for write.
size_t data_read_pointer(T **buf)
Get a reference to the current location in the buffer for read.
Notifiable * readableNotify_
This will be notified if the device has data avilable for read.
Definition Devtab.hxx:635
Notifiable * writableNotify_
This will be notified if the device has buffer avilable for write.
Definition Devtab.hxx:637
Specialization of CAN driver for Tiva CAN.
Definition TivaDev.hxx:244
int ioctl(File *file, unsigned long int key, unsigned long data) override
Request an ioctl transaction.
Definition TivaCan.cxx:121
unsigned long interrupt
interrupt of this device
Definition TivaDev.hxx:277
void interrupt_handler()
handle an interrupt.
Definition TivaCan.cxx:194
uint8_t canState
current state of the CAN-bus.
Definition TivaDev.hxx:279
unsigned long base
base address of this device
Definition TivaDev.hxx:276
void enable() override
function to enable device
Definition TivaCan.cxx:133
bool txPending
transmission currently pending
Definition TivaDev.hxx:278
void tx_msg() override
function to try and transmit a message
Definition TivaCan.cxx:156
TivaCan()
Default constructor.
void disable() override
function to disable device
Definition TivaCan.cxx:147
#define CAN_STATE_BUS_OFF
CAN bus off.
#define CAN_STATE_ACTIVE
CAN bus active.
#define SIOCGCANSTATE
Read the CAN state.
uint32_t can_state_t
CAN state type.
#define CAN_STATE_STOPPED
CAN bus stopped.
#define CAN_STATE_BUS_PASSIVE
CAN bus error passive.
#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