23
23
#include <string.h>
24
24
25
25
/* Handy defines */
26
- #define MSG_OBJ_MAX 32
26
+ #define RX_MSG_OBJ_COUNT 31
27
+ #define TX_MSG_OBJ_COUNT 1
27
28
#define DLC_MAX 8
28
29
29
30
#define ID_STD_MASK 0x07FF
56
57
#define CANIFn_CMDMSK_RD (0UL << 7)
57
58
#define CANIFn_CMDREQ_BUSY (1UL << 15)
58
59
60
+ #define CANSTAT_TXOK (1 << 3) // Transmitted a message successfully This bit must be reset by the CPU. It is never reset by the CAN controller.
61
+ #define CANSTAT_RXOK (1 << 4) // Received a message successfully This bit must be reset by the CPU. It is never reset by the CAN controller.
62
+ #define CANSTAT_EPASS (1 << 5) // Error passive
63
+ #define CANSTAT_EWARN (1 << 6) // Warning status
64
+ #define CANSTAT_BOFF (1 << 7) // Busoff status
65
+
59
66
#define CANCNTL_INIT (1 << 0) // Initialization
60
67
#define CANCNTL_IE (1 << 1) // Module interrupt enable
61
68
#define CANCNTL_SIE (1 << 2) // Status change interrupt enable
74
81
static uint32_t can_irq_id = 0 ;
75
82
static can_irq_handler irq_handler ;
76
83
84
+ #define IRQ_ENABLE_TX (1 << 0)
85
+ #define IRQ_ENABLE_RX (1 << 1)
86
+ #define IRQ_ENABLE_EW (1 << 2)
87
+ #define IRQ_ENABLE_EP (1 << 3)
88
+ #define IRQ_ENABLE_BE (1 << 4)
89
+ #define IRQ_ENABLE_STATUS (IRQ_ENABLE_TX | IRQ_ENABLE_RX)
90
+ #define IRQ_ENABLE_ERROR (IRQ_ENABLE_EW | IRQ_ENABLE_EP | IRQ_ENABLE_BE)
91
+ #define IRQ_ENABLE_ANY (IRQ_ENABLE_STATUS | IRQ_ENABLE_ERROR)
92
+ static uint32_t enabled_irqs = 0 ;
93
+
77
94
static inline void can_disable (can_t * obj ) {
78
95
LPC_C_CAN0 -> CANCNTL |= 0x1 ;
79
96
}
@@ -139,7 +156,7 @@ int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t
139
156
}
140
157
}
141
158
142
- if (handle > 0 && handle < 32 ) {
159
+ if (handle > 0 && handle <= 32 ) {
143
160
if (format == CANExtended ) {
144
161
// Mark message valid, Direction = TX, Extended Frame, Set Identifier and mask everything
145
162
LPC_C_CAN0 -> CANIF1_ARB1 = (id & 0xFFFF );
@@ -153,7 +170,7 @@ int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t
153
170
}
154
171
155
172
// Use mask, single message object and set DLC
156
- LPC_C_CAN0 -> CANIF1_MCTRL = CANIFn_MCTRL_UMASK | CANIFn_MCTRL_EOB | CANIFn_MCTRL_RXIE | (DLC_MAX & 0xF );
173
+ LPC_C_CAN0 -> CANIF1_MCTRL = CANIFn_MCTRL_UMASK | CANIFn_MCTRL_EOB | (DLC_MAX & 0xF );
157
174
158
175
// Transfer all fields to message object
159
176
LPC_C_CAN0 -> CANIF1_CMDMSK_W = CANIFn_CMDMSK_WR | CANIFn_CMDMSK_MASK | CANIFn_CMDMSK_ARB | CANIFn_CMDMSK_CTRL ;
@@ -169,7 +186,41 @@ int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t
169
186
}
170
187
171
188
static inline void can_irq () {
172
- irq_handler (can_irq_id , IRQ_RX );
189
+ uint32_t intid = LPC_C_CAN0 -> CANINT & 0xFFFF ;
190
+
191
+ if (intid == 0x8000 ) {
192
+ uint32_t status = LPC_C_CAN0 -> CANSTAT ;
193
+ // Note that since it's impossible to tell which specific status caused
194
+ // the interrupt to fire, this just fires them all.
195
+ // In particular, EWARN is not mutually exclusive with the others and
196
+ // may fire multiple times with other status transitions, including
197
+ // transmit and receive completion (if enabled). Ignoring EWARN with a
198
+ // priority system (i.e. blocking EWARN interrupts if EPASS or BOFF is
199
+ // set) may discard some EWARN interrupts.
200
+ if (status & CANSTAT_BOFF ) {
201
+ if (enabled_irqs & IRQ_ENABLE_BE ) {
202
+ irq_handler (can_irq_id , IRQ_BUS );
203
+ }
204
+ }
205
+ if (status & CANSTAT_EPASS ) {
206
+ if (enabled_irqs & IRQ_ENABLE_EP ) {
207
+ irq_handler (can_irq_id , IRQ_PASSIVE );
208
+ }
209
+ }
210
+ if (status & CANSTAT_EWARN ) {
211
+ if (enabled_irqs & IRQ_ENABLE_EW ) {
212
+ irq_handler (can_irq_id , IRQ_ERROR );
213
+ }
214
+ }
215
+ if ((status & CANSTAT_RXOK ) != 0 ) {
216
+ LPC_C_CAN0 -> CANSTAT &= ~CANSTAT_RXOK ;
217
+ irq_handler (can_irq_id , IRQ_RX );
218
+ }
219
+ if ((status & CANSTAT_TXOK ) != 0 ) {
220
+ LPC_C_CAN0 -> CANSTAT &= ~CANSTAT_TXOK ;
221
+ irq_handler (can_irq_id , IRQ_TX );
222
+ }
223
+ }
173
224
}
174
225
175
226
// Register CAN object's irq handler
@@ -187,13 +238,53 @@ void can_irq_free(can_t *obj) {
187
238
188
239
// Clear or set a irq
189
240
void can_irq_set (can_t * obj , CanIrqType type , uint32_t enable ) {
241
+ uint32_t mask_enable ;
242
+ switch (type ) {
243
+ case IRQ_RX :
244
+ mask_enable = IRQ_ENABLE_RX ;
245
+ break ;
246
+ case IRQ_TX :
247
+ mask_enable = IRQ_ENABLE_TX ;
248
+ break ;
249
+ case IRQ_BUS :
250
+ mask_enable = IRQ_ENABLE_BE ;
251
+ break ;
252
+ case IRQ_PASSIVE :
253
+ mask_enable = IRQ_ENABLE_EP ;
254
+ break ;
255
+ case IRQ_ERROR :
256
+ mask_enable = IRQ_ENABLE_EW ;
257
+ break ;
258
+ default :
259
+ return ;
260
+ }
261
+
262
+ if (enable ) {
263
+ enabled_irqs = enabled_irqs | mask_enable ;
264
+ } else {
265
+ enabled_irqs = enabled_irqs & ~mask_enable ;
266
+ }
267
+
190
268
// Put CAN in Reset Mode and enable interrupt
191
269
can_disable (obj );
192
- if (enable == 0 ) {
193
- LPC_C_CAN0 -> CANCNTL &= ~(1UL << 1 | 1UL << 2 );
270
+ if (!( enabled_irqs & IRQ_ENABLE_ANY ) ) {
271
+ LPC_C_CAN0 -> CANCNTL &= ~(1UL << 1 | 1UL << 2 | 1UL << 3 );
194
272
} else {
195
- LPC_C_CAN0 -> CANCNTL |= 1UL << 1 | 1UL << 2 ;
273
+ LPC_C_CAN0 -> CANCNTL |= 1UL << 1 ;
274
+ // Use status interrupts instead of message interrupts to avoid
275
+ // stomping over potential filter configurations.
276
+ if (enabled_irqs & IRQ_ENABLE_STATUS ) {
277
+ LPC_C_CAN0 -> CANCNTL |= 1UL << 2 ;
278
+ } else {
279
+ LPC_C_CAN0 -> CANCNTL &= ~(1UL << 2 );
280
+ }
281
+ if (enabled_irqs & IRQ_ENABLE_ERROR ) {
282
+ LPC_C_CAN0 -> CANCNTL |= 1UL << 3 ;
283
+ } else {
284
+ LPC_C_CAN0 -> CANCNTL &= ~(1UL << 3 );
285
+ }
196
286
}
287
+
197
288
// Take it out of reset...
198
289
can_enable (obj );
199
290
@@ -280,9 +371,9 @@ int can_config_rxmsgobj(can_t *obj) {
280
371
LPC_C_CAN0 -> CANIF1_ARB2 = 0 ;
281
372
LPC_C_CAN0 -> CANIF1_MCTRL = 0 ;
282
373
283
- for ( i = 0 ; i < MSG_OBJ_MAX ; i ++ ) {
374
+ for ( i = 1 ; i <= RX_MSG_OBJ_COUNT ; i ++ ) {
284
375
// Transfer arb and control fields to message object
285
- LPC_C_CAN0 -> CANIF1_CMDMSK_W = CANIFn_CMDMSK_WR | CANIFn_CMDMSK_ARB | CANIFn_CMDMSK_CTRL | CANIFn_CMDMSK_TXRQST ;
376
+ LPC_C_CAN0 -> CANIF1_CMDMSK_W = CANIFn_CMDMSK_WR | CANIFn_CMDMSK_ARB | CANIFn_CMDMSK_CTRL ;
286
377
287
378
// Start Transfer to given message number
288
379
LPC_C_CAN0 -> CANIF1_CMDREQ = (i & 0x3F );
@@ -297,6 +388,33 @@ int can_config_rxmsgobj(can_t *obj) {
297
388
return 1 ;
298
389
}
299
390
391
+ int can_config_txmsgobj (can_t * obj ) {
392
+ uint16_t i = 0 ;
393
+
394
+ // Make sure the interface is available
395
+ while ( LPC_C_CAN0 -> CANIF1_CMDREQ & CANIFn_CMDREQ_BUSY );
396
+
397
+ // Mark message valid, Direction = TX, Don't care about anything else
398
+ LPC_C_CAN0 -> CANIF1_ARB1 = 0 ;
399
+ LPC_C_CAN0 -> CANIF1_ARB2 = CANIFn_ARB2_DIR ;
400
+ LPC_C_CAN0 -> CANIF1_MCTRL = 0 ;
401
+
402
+ for ( i = RX_MSG_OBJ_COUNT + 1 ; i <= (TX_MSG_OBJ_COUNT + RX_MSG_OBJ_COUNT ); i ++ )
403
+ {
404
+ // Transfer arb and control fields to message object
405
+ LPC_C_CAN0 -> CANIF1_CMDMSK_W = CANIFn_CMDMSK_WR | CANIFn_CMDMSK_ARB | CANIFn_CMDMSK_CTRL ;
406
+ // In a union with CANIF1_CMDMSK_R
407
+
408
+ // Start Transfer to given message number
409
+ LPC_C_CAN0 -> CANIF1_CMDREQ = i & 0x3F ;
410
+
411
+ // Wait until transfer to message ram complete - TODO: maybe not block??
412
+ while ( LPC_C_CAN0 -> CANIF1_CMDREQ & CANIFn_CMDREQ_BUSY );
413
+ }
414
+
415
+ return 1 ;
416
+ }
417
+
300
418
301
419
void can_init (can_t * obj , PinName rd , PinName td ) {
302
420
// Enable power and clock
@@ -320,6 +438,8 @@ void can_init(can_t *obj, PinName rd, PinName td) {
320
438
321
439
// Initialize RX message object
322
440
can_config_rxmsgobj (obj );
441
+ // Initialize TX message object
442
+ can_config_txmsgobj (obj );
323
443
}
324
444
325
445
void can_free (can_t * obj ) {
@@ -345,11 +465,26 @@ int can_frequency(can_t *obj, int f) {
345
465
}
346
466
347
467
int can_write (can_t * obj , CAN_Message msg , int cc ) {
348
- uint16_t msgnum = 0 ;
349
468
350
469
// Make sure controller is enabled
351
470
can_enable (obj );
352
471
472
+ // Find first message object that isn't pending to send
473
+ uint16_t msgnum = 0 ;
474
+ uint32_t txPending = (LPC_C_CAN0 -> CANTXREQ1 & 0xFF ) | (LPC_C_CAN0 -> CANTXREQ2 << 16 );
475
+ uint16_t i = 0 ;
476
+ for (i = RX_MSG_OBJ_COUNT ; i < 32 ; i ++ ) {
477
+ if ((txPending & (1 << i )) == 0 ) {
478
+ msgnum = i + 1 ;
479
+ break ;
480
+ }
481
+ }
482
+
483
+ // If no messageboxes are available, stop and return failure
484
+ if (msgnum == 0 ) {
485
+ return 0 ;
486
+ }
487
+
353
488
// Make sure the interface is available
354
489
while ( LPC_C_CAN0 -> CANIF1_CMDREQ & CANIFn_CMDREQ_BUSY );
355
490
@@ -405,15 +540,15 @@ int can_read(can_t *obj, CAN_Message *msg, int handle) {
405
540
if (handle == 0 ) {
406
541
uint32_t newdata = LPC_C_CAN0 -> CANND1 | (LPC_C_CAN0 -> CANND2 << 16 );
407
542
// Find first free messagebox
408
- for (i = 0 ; i < 32 ; i ++ ) {
543
+ for (i = 0 ; i < RX_MSG_OBJ_COUNT ; i ++ ) {
409
544
if (newdata & (1 << i )) {
410
545
handle = i + 1 ;
411
546
break ;
412
547
}
413
548
}
414
549
}
415
550
416
- if (handle > 0 && handle < 32 ) {
551
+ if (handle > 0 && handle <= 32 ) {
417
552
// Wait until message interface is free
418
553
while ( LPC_C_CAN0 -> CANIF2_CMDREQ & CANIFn_CMDREQ_BUSY );
419
554
@@ -462,6 +597,9 @@ void can_reset(can_t *obj) {
462
597
LPC_SYSCON -> PRESETCTRL1 &= ~(1UL << 7 );
463
598
LPC_C_CAN0 -> CANSTAT = 0 ;
464
599
can_config_rxmsgobj (obj );
600
+ can_config_txmsgobj (obj );
601
+
602
+ can_enable (obj ); // clears a bus-off condition if necessary
465
603
}
466
604
467
605
unsigned char can_rderror (can_t * obj ) {
0 commit comments