Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
Stm32Can.cxx
Go to the documentation of this file.
1
34#if (!defined(ARDUINO)) || defined(ARDUINO_ARCH_STM32)
35
36#include "Stm32Can.hxx"
37
38#include <stdint.h>
39
40#include "can_ioctl.h"
41
42#include "stm32f_hal_conf.hxx"
43
44#if defined (STM32F072xB) || defined (STM32F091xC)
45
46#include "stm32f0xx_hal_cortex.h"
47#define CAN_IRQN CEC_CAN_IRQn
48
49#define CAN_CLOCK cpu_clock_hz
50
51#elif defined (STM32F103xB)
52
53#include "stm32f1xx_hal_cortex.h"
54#define SPLIT_INT
55#define CAN_TX_IRQN USB_HP_CAN1_TX_IRQn
56#define CAN_IRQN CAN_TX_IRQN
57#define CAN_SECOND_IRQN USB_LP_CAN1_RX0_IRQn
58#define CAN_THIRD_IRQN CAN1_SCE_IRQn
59#define CAN CAN1
60#define CAN_CLOCK (cm3_cpu_clock_hz >> 1)
61
62#elif defined (STM32F303xC) || defined (STM32F303xE)
63
64#include "stm32f3xx_hal_cortex.h"
65#define SPLIT_INT
66#define CAN_TX_IRQN USB_HP_CAN_TX_IRQn
67#define CAN_IRQN CAN_TX_IRQN
68#define CAN_SECOND_IRQN USB_LP_CAN_RX0_IRQn
69#define CAN_THIRD_IRQN CAN_SCE_IRQn
70#define CAN_CLOCK (cm3_cpu_clock_hz >> 1)
71
72#elif defined (STM32L431xx) || defined (STM32L432xx)
73
74#include "stm32l4xx_hal_cortex.h"
75#define SPLIT_INT
76#define CAN_TX_IRQN CAN1_TX_IRQn
77#define CAN_IRQN CAN_TX_IRQN
78#define CAN_SECOND_IRQN CAN1_RX0_IRQn
79#define CAN_THIRD_IRQN CAN1_SCE_IRQn
80#define CAN_CLOCK (cm3_cpu_clock_hz)
81
82#elif defined (STM32F767xx)
83
84#include "stm32f7xx_hal_cortex.h"
85#define SPLIT_INT
86#define CAN CAN1
87#define CAN_TX_IRQN CAN1_TX_IRQn
88#define CAN_IRQN CAN_TX_IRQN
89#define CAN_SECOND_IRQN CAN1_RX0_IRQn
90#define CAN_THIRD_IRQN CAN1_SCE_IRQn
91#define CAN_CLOCK (cm3_cpu_clock_hz >> 2) // 54 MHz, sysclk/4
92
93#else
94#error Dont know what STM32 chip you have.
95#endif
96
97Stm32Can *Stm32Can::instances[1] = {NULL};
98
102Stm32Can::Stm32Can(const char *name)
103 : Can(name)
104 , state_(CAN_STATE_STOPPED)
105{
106 /* only one instance allowed */
107 HASSERT(instances[0] == NULL);
108
109 instances[0] = this;
110
111 /* should already be disabled, but just in case */
112 HAL_NVIC_DisableIRQ(CAN_IRQN);
113
114#if defined (STM32F030x6) || defined (STM32F031x6) || defined (STM32F038xx) \
115 || defined (STM32F030x8) || defined (STM32F030xC) || defined (STM32F042x6) \
116 || defined (STM32F048xx) || defined (STM32F051x8) || defined (STM32F058xx) \
117 || defined (STM32F070x6) || defined (STM32F070xB) || defined (STM32F071xB) \
118 || defined (STM32F072xB) || defined (STM32F078xx) \
119 || defined (STM32F091xC) || defined (STM32F098xx)
120#else
121 /* The priority of CAN interrupt is as high as possible while maintaining
122 * FreeRTOS compatibility.
123 */
124 SetInterruptPriority(CAN_IRQN, configKERNEL_INTERRUPT_PRIORITY);
125
126#ifdef SPLIT_INT
127 HAL_NVIC_DisableIRQ(CAN_SECOND_IRQN);
128 SetInterruptPriority(CAN_SECOND_IRQN, configKERNEL_INTERRUPT_PRIORITY);
129 HAL_NVIC_DisableIRQ(CAN_THIRD_IRQN);
130 SetInterruptPriority(CAN_THIRD_IRQN, configKERNEL_INTERRUPT_PRIORITY);
131#endif
132#endif
133}
134
135#if !defined(ARDUINO)
136//
137// Stm32Can::ioctl()
138//
139int Stm32Can::ioctl(File *file, unsigned long int key, unsigned long data)
140{
141 if (key == SIOCGCANSTATE)
142 {
143 *((can_state_t*)data) = state_;
144 return 0;
145 }
146 return -EINVAL;
147}
148#endif // !ARDUINO
149
153{
154 /* disable sleep, enter init mode */
155 CAN->MCR = CAN_MCR_INRQ;
156
157 /* Time triggered tranmission off
158 * Bus off state is left automatically
159 * Auto-Wakeup mode disabled
160 * automatic re-transmission enabled
161 * receive FIFO not locked on overrun
162 * TX FIFO mode on
163 */
164 CAN->MCR |= (CAN_MCR_ABOM | CAN_MCR_TXFP);
165
166 /* Setup timing.
167 * 125,000 Kbps = 8 usec/bit
168 */
169 CAN->BTR = (CAN_BS1_5TQ | CAN_BS2_2TQ | CAN_SJW_1TQ |
170 ((CAN_CLOCK / 1000000) - 1));
171
172 /* enter normal mode */
173 CAN->MCR &= ~CAN_MCR_INRQ;
174
175 /* Enter filter initialization mode. Filter 0 will be used as a single
176 * 32-bit filter, ID Mask Mode, we accept everything, no mask.
177 */
178 CAN->FMR |= CAN_FMR_FINIT;
179 CAN->FM1R = 0;
180 CAN->FS1R = 0x000000001;
181 CAN->FFA1R = 0;
182 CAN->sFilterRegister[0].FR1 = 0;
183 CAN->sFilterRegister[0].FR2 = 0;
184
185 /* Activeate filter and exit initialization mode. */
186 CAN->FA1R = 0x000000001;
187 CAN->FMR &= ~CAN_FMR_FINIT;
188
190
191 /* enable interrupts */
192 CAN->IER = (CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE); // errors
193 CAN->IER |= (CAN_IER_ERRIE | CAN_IER_FMPIE0); // error + receive
194 HAL_NVIC_EnableIRQ(CAN_IRQN);
195#ifdef SPLIT_INT
196 HAL_NVIC_EnableIRQ(CAN_SECOND_IRQN);
197 HAL_NVIC_EnableIRQ(CAN_THIRD_IRQN);
198#endif
199}
200
204{
205 HAL_NVIC_DisableIRQ(CAN_IRQN);
206#ifdef SPLIT_INT
207 HAL_NVIC_DisableIRQ(CAN_SECOND_IRQN);
208 HAL_NVIC_DisableIRQ(CAN_THIRD_IRQN);
209#endif
210 CAN->IER = 0;
211
213
214 /* disable sleep, enter init mode */
215 CAN->MCR = CAN_MCR_INRQ;
216}
217
218/* Try and transmit a message.
219 */
221{
222 // If we are error passive, the last transmission ended with an error, and
223 // there are no free TX mailboxes, then we flush the input queue. This is a
224 // workaround because the STM32 CAN controller can get stuck in this state
225 // and never get to bus off if the TX attempts end up with no-ack (meaning
226 // the controller is alone on the bus).
227 if ((CAN->ESR & CAN_ESR_EPVF) && ((CAN->ESR & CAN_ESR_LEC_Msk) != 0) &&
228 ((CAN->TSR & (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2)) == 0))
229 {
230 txBuf->flush();
232 return;
233 }
234
235 /* see if we can send anything out */
236 struct can_frame *can_frame;
237
238 size_t msg_count = txBuf->data_read_pointer(&can_frame);
239 unsigned i;
240
241 for (i = 0; i < msg_count; ++i, ++can_frame)
242 {
243 volatile CAN_TxMailBox_TypeDef *mailbox;
244 if (CAN->TSR & CAN_TSR_TME0)
245 {
246 mailbox = CAN->sTxMailBox + 0;
247 }
248 else if (CAN->TSR & CAN_TSR_TME1)
249 {
250 mailbox = CAN->sTxMailBox + 1;
251 }
252 else if (CAN->TSR & CAN_TSR_TME2)
253 {
254 mailbox = CAN->sTxMailBox + 2;
255 }
256 else
257 {
258 /* no empty mailboxes left to fill */
259 break;
260 }
261
262 /* setup frame */
263 if (can_frame->can_eff)
264 {
265 mailbox->TIR = (can_frame->can_id << 3) | CAN_TI0R_IDE;
266 }
267 else
268 {
269 mailbox->TIR = can_frame->can_id << 21;
270 }
271 if (can_frame->can_rtr)
272 {
273 mailbox->TIR |= CAN_TI0R_RTR;
274 }
275 else
276 {
277 mailbox->TDTR = can_frame->can_dlc;
278 mailbox->TDLR = (can_frame->data[0] << 0) |
279 (can_frame->data[1] << 8) |
280 (can_frame->data[2] << 16) |
281 (can_frame->data[3] << 24);
282 mailbox->TDHR = (can_frame->data[4] << 0) |
283 (can_frame->data[5] << 8) |
284 (can_frame->data[6] << 16) |
285 (can_frame->data[7] << 24);
286 }
287
288 /* request transmission */
289 mailbox->TIR |= CAN_TI0R_TXRQ;
290 }
291
292 if (i)
293 {
294 txBuf->consume(i);
296 }
297
298 /* enable transmit interrupt */
299 CAN->IER |= CAN_IER_TMEIE;
300}
301
305{
306 unsigned msg_receive_count = 0;
307
308 while (CAN->RF0R & CAN_RF0R_FMP0)
309 {
310 /* rx data received */
311 struct can_frame *can_frame;
312 size_t msg_count = rxBuf->data_write_pointer(&can_frame);
313 if (msg_count)
314 {
315 if (CAN->sFIFOMailBox[0].RIR & CAN_RI0R_IDE)
316 {
317 /* extended frame */
318 can_frame->can_id = CAN->sFIFOMailBox[0].RIR >> 3;
319 can_frame->can_eff = 1;
320 }
321 else
322 {
323 /* standard frame */
324 can_frame->can_id = CAN->sFIFOMailBox[0].RIR >> 21;
325 can_frame->can_eff = 0;
326 }
327 if (CAN->sFIFOMailBox[0].RIR & CAN_RI0R_RTR)
328 {
329 /* remote frame */
330 can_frame->can_rtr = 1;
331 can_frame->can_dlc = 0;
332 }
333 else
334 {
335 /* data frame */
336 can_frame->can_rtr = 0;
337 can_frame->can_dlc = CAN->sFIFOMailBox[0].RDTR & CAN_RDT0R_DLC;
338 can_frame->data[0] = (CAN->sFIFOMailBox[0].RDLR >> 0) & 0xFF;
339 can_frame->data[1] = (CAN->sFIFOMailBox[0].RDLR >> 8) & 0xFF;
340 can_frame->data[2] = (CAN->sFIFOMailBox[0].RDLR >> 16) & 0xFF;
341 can_frame->data[3] = (CAN->sFIFOMailBox[0].RDLR >> 24) & 0xFF;
342 can_frame->data[4] = (CAN->sFIFOMailBox[0].RDHR >> 0) & 0xFF;
343 can_frame->data[5] = (CAN->sFIFOMailBox[0].RDHR >> 8) & 0xFF;
344 can_frame->data[6] = (CAN->sFIFOMailBox[0].RDHR >> 16) & 0xFF;
345 can_frame->data[7] = (CAN->sFIFOMailBox[0].RDHR >> 24) & 0xFF;
346 }
347 }
348 else
349 {
350 ++overrunCount;
351 }
352 /* release FIFO */
353 CAN->RF0R |= CAN_RF0R_RFOM0;
354 ++msg_receive_count;
355 }
356
357 if (msg_receive_count)
358 {
359 /* advance the "zero copy" buffer by the number of messages received */
360 rxBuf->advance(msg_receive_count);
363 }
364}
365
367{
368 if (CAN->TSR & (CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2))
369 {
370 /* transmit request completed, should be able to send another */
371 struct can_frame *can_frame;
372
373 size_t msg_count = txBuf->data_read_pointer(&can_frame);
374 if (msg_count)
375 {
376 /* try and send some more CAN frames */
377 unsigned i;
378
379 for (i = 0; i < msg_count; ++i, ++can_frame)
380 {
381 volatile CAN_TxMailBox_TypeDef *mailbox;
382 if (CAN->TSR & CAN_TSR_TME0)
383 {
384 mailbox = CAN->sTxMailBox + 0;
385 }
386 else if (CAN->TSR & CAN_TSR_TME1)
387 {
388 mailbox = CAN->sTxMailBox + 1;
389 }
390 else if (CAN->TSR & CAN_TSR_TME2)
391 {
392 mailbox = CAN->sTxMailBox + 2;
393 }
394 else
395 {
396 /* no empty mailboxes left to fill */
397 break;
398 }
399
400 /* setup frame */
401 if (can_frame->can_eff)
402 {
403 mailbox->TIR = (can_frame->can_id << 3) | CAN_TI0R_IDE;
404 }
405 else
406 {
407 mailbox->TIR = can_frame->can_id << 21;
408 }
409 if (can_frame->can_rtr)
410 {
411 mailbox->TIR |= CAN_TI0R_RTR;
412 }
413 else
414 {
415 mailbox->TDTR = can_frame->can_dlc;
416 mailbox->TDLR = (can_frame->data[0] << 0) |
417 (can_frame->data[1] << 8) |
418 (can_frame->data[2] << 16) |
419 (can_frame->data[3] << 24);
420 mailbox->TDHR = (can_frame->data[4] << 0) |
421 (can_frame->data[5] << 8) |
422 (can_frame->data[6] << 16) |
423 (can_frame->data[7] << 24);
424 }
425
426 /* request transmission */
427 mailbox->TIR |= CAN_TI0R_TXRQ;
428 }
429 txBuf->consume(i);
430 }
431 else
432 {
433 /* no more data left to transmit */
434 CAN->IER &= ~CAN_IER_TMEIE;
435 }
438 }
439}
440
441/*
442 * Stm32Can::sce_interrupt_handler()
443 */
445{
446 if (CAN->MSR & CAN_MSR_ERRI)
447 {
448 /* error interrupt has occured */
449 CAN->MSR |= CAN_MSR_ERRI; // clear flag
450
451 bool cancel_queue = false;
452
453 if (CAN->ESR & CAN_ESR_EWGF)
454 {
455 /* error warning condition */
457 }
458 if (CAN->ESR & CAN_ESR_EPVF)
459 {
460 /* error passive condition */
463 cancel_queue = true;
464 }
465 if (CAN->ESR & CAN_ESR_BOFF)
466 {
467 /* bus off error condition */
468 ++busOffCount;
470 cancel_queue = true;
471 }
472 if (cancel_queue)
473 {
474 CAN->TSR |= CAN_TSR_ABRQ2;
475 CAN->TSR |= CAN_TSR_ABRQ1;
476 CAN->TSR |= CAN_TSR_ABRQ0;
477 CAN->IER &= ~CAN_IER_TMEIE;
478 txBuf->flush();
480 }
481 }
482}
483
484extern "C" {
488//----------------------------------------------------------------------------
489//
490// F072xB & F091xC
491//
492//----------------------------------------------------------------------------
493
494#if defined (STM32F072xB) || defined (STM32F091xC)
495void cec_can_interrupt_handler(void)
496{
500}
501#elif defined (STM32F103xB) || defined (STM32F303xC) || defined (STM32F303xE)
502//----------------------------------------------------------------------------
503//
504// F103xB, F303xC and F303E
505//
506//----------------------------------------------------------------------------
507
508void usb_hp_can1_tx_interrupt_handler(void)
509{
511}
512
513void usb_lp_can1_rx0_interrupt_handler(void)
514{
516}
517
518void can1_sce_interrupt_handler(void)
519{
521}
522
523#elif defined(STM32F767xx) || defined(STM32L431xx) || defined(STM32L432xx)
524//----------------------------------------------------------------------------
525//
526// F767xx L431xx & L432xx
527//
528//----------------------------------------------------------------------------
529
530void can1_tx_interrupt_handler(void)
531{
533}
534
535void can1_rx0_interrupt_handler(void)
536{
538}
539
540void can1_sce_interrupt_handler(void)
541{
543}
544
545
546#else
547#error Dont know what STM32 chip you have.
548#endif
549
550} // extern "C"
551
552#endif // !ARDUINO
553
554#if defined(ARDUINO_ARCH_STM32)
555
556#include "stm32_def.h"
557#include "PinAF_STM32F1.h"
558#include <PeripheralPins.h>
559
560void arduino_can_pinmap(PinName tx_pin, PinName rx_pin) {
561 __HAL_RCC_CAN1_CLK_ENABLE();
562 void* can_tx = pinmap_peripheral(tx_pin, PinMap_CAN_TD);
563 void* can_rx = pinmap_peripheral(rx_pin, PinMap_CAN_RD);
564 void* can = pinmap_merge_peripheral(can_tx, can_rx);
565 if (can == NP) {
566 DIE("Could not find CAN peripheral");
567 }
568
569 GPIO_InitTypeDef GPIO_InitStruct;
570
571 GPIO_InitStruct.Pin = STM_GPIO_PIN(tx_pin);
572 auto fn = pinmap_function(tx_pin, PinMap_CAN_TD);
573 GPIO_InitStruct.Mode = STM_PIN_MODE(fn);
574 GPIO_InitStruct.Pull = STM_PIN_PUPD(fn);
575 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
576#ifdef STM32F1xx
577 pin_SetF1AFPin(STM_PIN_AFNUM(fn));
578#else
579 GPIO_InitStruct.Alternate = STM_PIN_AFNUM(fn);
580#endif /* STM32F1xx */
581 HAL_GPIO_Init(set_GPIO_Port_Clock(STM_PORT(tx_pin)), &GPIO_InitStruct);
582
583 GPIO_InitStruct.Pin = STM_GPIO_PIN(rx_pin);
584 fn = pinmap_function(rx_pin, PinMap_CAN_RD);
585 GPIO_InitStruct.Mode = STM_PIN_MODE(fn);
586 GPIO_InitStruct.Pull = STM_PIN_PUPD(fn);
587 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
588#ifdef STM32F1xx
589 pin_SetF1AFPin(STM_PIN_AFNUM(fn));
590#else
591 GPIO_InitStruct.Alternate = STM_PIN_AFNUM(fn);
592#endif /* STM32F1xx */
593 HAL_GPIO_Init(set_GPIO_Port_Clock(STM_PORT(rx_pin)), &GPIO_InitStruct);
594}
595
596extern "C" {
597void USB_HP_CAN_TX_IRQHandler(void)
598{
600}
601
602void USB_LP_CAN_RX0_IRQHandler(void)
603{
605}
606void CEC_CAN_IRQHandler(void)
607{
611}
612void CAN1_TX_IRQHandler(void)
613{
615}
616void CAN1_RX0_IRQHandler(void)
617{
619}
620void CAN1_SCE_IRQHandler(void)
621{
623}
624} // extern "C"
625
626#endif // ARDUINO_ARCH_STM32
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.
Specialization of CAN driver for LPC17xx and LPC40xx CAN.
Definition Stm32Can.hxx:51
int ioctl(File *file, unsigned long int key, unsigned long data) override
Request an ioctl transaction.
Definition Stm32Can.cxx:139
void enable() override
function to enable device
Definition Stm32Can.cxx:152
uint8_t state_
present bus state
Definition Stm32Can.hxx:93
void sce_interrupt_handler()
Handle an interrupt.
Definition Stm32Can.cxx:444
void rx_interrupt_handler()
Handle an interrupt.
Definition Stm32Can.cxx:304
void tx_interrupt_handler()
Handle an interrupt.
Definition Stm32Can.cxx:366
Stm32Can()
Default constructor.
static Stm32Can * instances[1]
Instance pointers help us get context from the interrupt handler(s)
Definition Stm32Can.hxx:97
void disable() override
function to disable device
Definition Stm32Can.cxx:203
void tx_msg() override
function to try and transmit a message
Definition Stm32Can.cxx:220
#define CAN_STATE_BUS_OFF
CAN bus off.
#define CAN_STATE_ACTIVE
CAN bus active.
#define SIOCGCANSTATE
Read the CAN state.
#define CAN_STATE_BUS_WARNING
CAN bus error warning.
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
#define DIE(MSG)
Unconditionally terminates the current process with a message.
Definition macros.h:143
File information.
Definition Devtab.hxx:52