PX4 Firmware
PX4 Autopilot Software http://px4.io
uc_kinetis_flexcan.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014, 2018 Pavel Kirienko <pavel.kirienko@gmail.com>
3  * Kinetis Port Author David Sidrane <david_s5@nscdg.com>
4  */
5 
6 #include <cassert>
7 #include <cstring>
8 #include <uavcan_kinetis/can.hpp>
10 #include "internal.hpp"
11 
12 #if UAVCAN_KINETIS_NUTTX
13 # include <nuttx/arch.h>
14 # include <nuttx/irq.h>
15 # include <arch/board/board.h>
16 #else
17 # error "Unknown OS"
18 #endif
19 
20 
21 namespace uavcan_kinetis
22 {
23 extern "C" {
24  static int can0_irq(const int irq, void *, void *args);
25 #if UAVCAN_KINETIS_NUM_IFACES > 1
26  static int can1_irq(const int irq, void *, void *args);
27 #endif
28 }
29 namespace flexcan
30 {
31 const uavcan::uint32_t OSCERCLK = BOARD_EXTAL_FREQ;
32 const uavcan::uint32_t busclck = BOARD_BUS_FREQ;
33 const uavcan::uint8_t CLOCKSEL = 0; // Select OSCERCLK
34 const uavcan::uint32_t canclk = CLOCKSEL ? busclck : OSCERCLK; // Is Clock
35 const uavcan::uint8_t useFIFO = 1; // Fifo is enabled
36 const uavcan::uint32_t numberFIFOFilters = flexcan::CTRL2_RFFN_16MB; // 16 Rx FIFO filters
37 }
38 namespace
39 {
40 
41 CanIface *ifaces[UAVCAN_KINETIS_NUM_IFACES] = {
42  UAVCAN_NULLPTR
43 #if UAVCAN_KINETIS_NUM_IFACES > 1
44  , UAVCAN_NULLPTR
45 #endif
46 };
47 
48 inline void handleTxInterrupt(CanIface *can, uavcan::uint32_t iflags1)
49 {
50  UAVCAN_ASSERT(iface_index < UAVCAN_KINETIS_NUM_IFACES);
51  uavcan::uint64_t utc_usec = clock::getUtcUSecFromCanInterrupt();
52 
53  if (utc_usec > 0) {
54  utc_usec--;
55  }
56 
57  can->handleTxInterrupt(iflags1, utc_usec);
58 }
59 
60 inline void handleRxInterrupt(CanIface *can, uavcan::uint32_t iflags1)
61 {
62  uavcan::uint64_t utc_usec = clock::getUtcUSecFromCanInterrupt();
63 
64  if (utc_usec > 0) {
65  utc_usec--;
66  }
67 
68  can->handleRxInterrupt(iflags1, utc_usec);
69 }
70 
71 } // namespace
72 
73 /*
74  * CanIface::RxQueue
75  */
77 {
78  if (overflow_cnt_ < 0xFFFFFFFF) {
79  overflow_cnt_++;
80  }
81 }
82 
83 void CanIface::RxQueue::push(const uavcan::CanFrame &frame, const uint64_t &utc_usec, uavcan::CanIOFlags flags)
84 {
85  buf_[in_].frame = frame;
86  buf_[in_].utc_usec = utc_usec;
87  buf_[in_].flags = flags;
88  in_++;
89 
90  if (in_ >= capacity_) {
91  in_ = 0;
92  }
93 
94  len_++;
95 
96  if (len_ > capacity_) {
97  len_ = capacity_;
98  registerOverflow();
99  out_++;
100 
101  if (out_ >= capacity_) {
102  out_ = 0;
103  }
104  }
105 }
106 
107 void CanIface::RxQueue::pop(uavcan::CanFrame &out_frame, uavcan::uint64_t &out_utc_usec, uavcan::CanIOFlags &out_flags)
108 {
109  if (len_ > 0) {
110  out_frame = buf_[out_].frame;
111  out_utc_usec = buf_[out_].utc_usec;
112  out_flags = buf_[out_].flags;
113  out_++;
114 
115  if (out_ >= capacity_) {
116  out_ = 0;
117  }
118 
119  len_--;
120 
121  } else {
122  UAVCAN_ASSERT(0);
123  }
124 }
125 
127 {
128  in_ = 0;
129  out_ = 0;
130  len_ = 0;
131  overflow_cnt_ = 0;
132 }
133 
134 /*
135  * CanIface
136  */
137 
138 int CanIface::computeTimings(const uavcan::uint32_t target_bitrate, Timings &out_timings)
139 {
140  if (target_bitrate < 1) {
141  return -ErrInvalidBitRate;
142  }
143 
144  /*
145  * From FlexCAN Bit Timing Calculation by: Petr Stancik TIC
146  * buadrate = 1 / tNBT -The tNBT represents a period of the Nominal Bit Time (NBT).
147  * The NBT is separated into four non-overlaping segments,
148  * SYNC_SEG, PROP_SEG,PHASE_SEG1 and PHASE_SEG2. Each of
149  * these segments is an integer multiple of Time Quantum tQ
150  * tNBT= tQ+PROP_SEG* tQ + PHASE_SEG1* tQ + PHASE_SEG2* tQ = NBT * tQ
151  * tQ = 1/bitrate = 1/[canclk /(PRESDIV+1)].
152  * NBT is 8..25
153  * SYNC_SEG = 1 tQ
154  * PROP_SEG = 1..8 tQ
155  * PHASE1_SEG = 1,2..8 tQ 1..8 for 1 Sample per bit (Spb), 2..8 for 3 Spb
156  * PHASE2_SEG = 1..8
157  *
158  */
159  /*
160  * Hardware configuration
161  */
162 
163  /* Maximize NBT
164  * NBT * Prescaler = canclk / baud rate.
165  *
166  */
167 
168  const uavcan::uint32_t nbt_prescaler = flexcan::canclk / target_bitrate;
169  const int max_quanta_per_bit = 17;
170 
171  /*
172  * Searching for such prescaler value so that the number of quanta per bit is highest.
173  */
174 
175  /* tNBT - tQ = PROP_SEG* tQ + PHASE_SEG1* tQ + PHASE_SEG2* tQ = NBT * tQ - tQ */
176 
177  for (uavcan::uint32_t prescaler = 1; prescaler < 256; prescaler++) {
178  if (prescaler > nbt_prescaler) {
179  return -ErrInvalidBitRate; // No solution
180  }
181 
182  if ((0 == nbt_prescaler % prescaler) && (nbt_prescaler / prescaler) < max_quanta_per_bit) {
183  out_timings.prescaler = prescaler;
184  break;
185  }
186  }
187 
188  const uavcan::uint32_t NBT = nbt_prescaler / out_timings.prescaler;
189 
190  /* Choose a reasonable and some what arbitrary value for Propseg */
191 
192  out_timings.propseg = 5;
193 
194 
195  /* Ideal sampling point = 87.5% given by (SYNC_SEG + PROP_SEG + PHASE_SEG1) / (PHASE_SEG2) */
196 
197  uavcan::uint32_t sp = (7 * NBT) / 8;
198 
199  out_timings.pseg1 = sp - 1 - out_timings.propseg;
200  out_timings.pseg2 = NBT - (1 + out_timings.pseg1 + out_timings.propseg);
201  out_timings.rjw = uavcan::min((uavcan::uint8_t) 4, out_timings.pseg2);
202 
203  return ((out_timings.pseg1 <= 8) && (out_timings.pseg2 <= 8) && (out_timings.propseg <= 8)) ? 0 :
205 }
206 
207 uavcan::int16_t CanIface::send(const uavcan::CanFrame &frame, uavcan::MonotonicTime tx_deadline,
208  uavcan::CanIOFlags flags)
209 {
210  if (frame.isErrorFrame() || frame.dlc > 8) {
211  return -ErrUnsupportedFrame;
212  }
213 
214  /*
215  * Normally we should perform the same check as in @ref canAcceptNewTxFrame(), because
216  * it is possible that the highest-priority frame between select() and send() could have been
217  * replaced with a lower priority one due to TX timeout. But we don't do this check because:
218  *
219  * - It is a highly unlikely scenario.
220  *
221  * - Frames do not timeout on a properly functioning bus. Since frames do not timeout, the new
222  * frame can only have higher priority, which doesn't break the logic.
223  *
224  * - If high-priority frames are timing out in the TX queue, there's probably a lot of other
225  * issues to take care of before this one becomes relevant.
226  *
227  * - It takes CPU time. Not just CPU time, but critical section time, which is expensive.
228  */
229  CriticalSectionLocker lock;
230 
231  /*
232  * Seeking for an empty slot
233  */
234 
235  uavcan::uint32_t mbi = 0;
236 
238  mbi = (can_->ESR2 & flexcan::ESR2_LPTM_MASK) >> flexcan::ESR2_LPTM_SHIFT;
240  }
241 
242  uavcan::uint32_t mb_bit = 1 << (flexcan::NumMBinFiFoAndFilters + mbi);
243 
244  while (mbi < NumTxMesgBuffers) {
245  if (can_->MB[flexcan::NumMBinFiFoAndFilters + mbi].mb.CS.code != flexcan::TxMbDataOrRemote) {
246  can_->IFLAG1 = mb_bit;
247  break;
248  }
249 
250  mb_bit <<= 1;
251  mbi++;
252  }
253 
254  if (mbi == NumTxMesgBuffers) {
255  return 0; // No transmission for you!
256  }
257 
258  peak_tx_mailbox_index_ = uavcan::max(peak_tx_mailbox_index_, (uavcan::uint8_t) mbi); // Statistics
259 
264 
265  if (frame.isExtended()) {
266  cs.ide = 1;
267  mb.ID.ext = frame.id & uavcan::CanFrame::MaskExtID;
268 
269  } else {
270  mb.ID.std = frame.id & uavcan::CanFrame::MaskStdID;
271  }
272 
273  cs.rtr = frame.isRemoteTransmissionRequest();
274 
275  cs.dlc = frame.dlc;
276  mb.data.b0 = frame.data[0];
277  mb.data.b1 = frame.data[1];
278  mb.data.b2 = frame.data[2];
279  mb.data.b3 = frame.data[3];
280  mb.data.b4 = frame.data[4];
281  mb.data.b5 = frame.data[5];
282  mb.data.b6 = frame.data[6];
283  mb.data.b7 = frame.data[7];
284 
285  /*
286  * Registering the pending transmission so we can track its deadline and loopback it as needed
287  */
288  TxItem &txi = pending_tx_[mbi];
289  txi.deadline = tx_deadline;
290  txi.frame = frame;
291  txi.loopback = (flags & uavcan::CanIOFlagLoopback) != 0;
292  txi.abort_on_error = (flags & uavcan::CanIOFlagAbortOnError) != 0;
293  txi.pending = TxItem::busy;
294 
295  mb.CS = cs; // Go.
296  can_->IMASK1 |= mb_bit;
297  return 1;
298 }
299 
300 uavcan::int16_t CanIface::receive(uavcan::CanFrame &out_frame, uavcan::MonotonicTime &out_ts_monotonic,
301  uavcan::UtcTime &out_ts_utc, uavcan::CanIOFlags &out_flags)
302 {
303  out_ts_monotonic = clock::getMonotonic(); // High precision is not required for monotonic timestamps
304  uavcan::uint64_t utc_usec = 0;
305  {
306  CriticalSectionLocker lock;
307 
308  if (rx_queue_.getLength() == 0) {
309  return 0;
310  }
311 
312  rx_queue_.pop(out_frame, utc_usec, out_flags);
313  }
314  out_ts_utc = uavcan::UtcTime::fromUSec(utc_usec);
315  return 1;
316 }
317 
318 uavcan::int16_t CanIface::configureFilters(const uavcan::CanFilterConfig *filter_configs,
319  uavcan::uint16_t num_configs)
320 {
321  if (num_configs <= NumFilters) {
322  CriticalSectionLocker lock;
323  setFreeze(true);
324 
325  if (!waitFreezeAckChange(true)) {
326  return -ErrMcrFRZACKAckNotSet;
327  }
328 
329  volatile flexcan::FilterType *filterBase = reinterpret_cast<volatile
330  flexcan::FilterType *>(&can_->MB[flexcan::
331  FirstFilter].mb);
332 
333  if (num_configs == 0) {
334  // No filters except all
335  for (uint8_t i = 0; i < NumFilters; i++) {
336  volatile flexcan::FilterType &filter = filterBase[i];
337  filter.w = 0; // All Do not care
338  can_->RXIMR[i].w = 0;// All Do not care
339  }
340 
341  can_->RXFGMASK = 0; // All Do not care
342 
343  } else {
344  for (uint8_t i = 0; i < NumFilters; i++) {
345  volatile flexcan::FilterType &filter = filterBase[i];
346  volatile flexcan::FilterType &mask = can_->RXIMR[i];
347 
348  if (i < num_configs) {
349 
350  const uavcan::CanFilterConfig *const cfg = filter_configs + i;
351 
352  if ((cfg->id & uavcan::CanFrame::FlagEFF) || !(cfg->mask & uavcan::CanFrame::FlagEFF)) {
353  filter.ide = 1;
354  filter.ext = cfg->id & uavcan::CanFrame::MaskExtID;
355  mask.ext = cfg->mask & uavcan::CanFrame::MaskExtID;
356 
357  } else {
358  filter.ide = 0;
359  filter.std = cfg->id & uavcan::CanFrame::MaskStdID;
360  mask.std = cfg->mask & uavcan::CanFrame::MaskStdID;
361  }
362 
363  filter.rtr = cfg->id & uavcan::CanFrame::FlagRTR ? 1 : 0;
364 
365  mask.rtr = cfg->mask & uavcan::CanFrame::FlagRTR ? 1 : 0;
366  mask.ide = cfg->mask & uavcan::CanFrame::FlagEFF ? 1 : 0;
367 
368  } else {
369  /* We can not really disable, with out effecting the memory map
370  * of the mail boxes, so set all bits to 1's and all to care
371  */
372  filter.w = 0xffffffff;
373  mask.w = 0xffffffff;
374  }
375  }
376  }
377 
378  setFreeze(false);
379  return waitFreezeAckChange(false) ? 0 : -ErrMcrFRZACKAckNotCleared;
380  }
381 
382  return -ErrFilterNumConfigs;
383 }
384 
385 bool CanIface::waitMCRChange(uavcan::uint32_t mask, bool target_state)
386 {
387  const unsigned Timeout = 1000;
388 
389  for (unsigned wait_ack = 0; wait_ack < Timeout; wait_ack++) {
390  const bool state = (can_->MCR & mask) != 0;
391 
392  if (state == target_state) {
393  return true;
394  }
395 
396  ::up_udelay(10);
397  }
398 
399  return false;
400 }
401 
402 void CanIface::setMCR(uavcan::uint32_t mask, bool target_state)
403 {
404  if (target_state) {
405  can_->MCR |= mask;
406 
407  } else {
408  can_->MCR &= ~mask;
409  }
410 
411 }
412 
413 bool CanIface::waitFreezeAckChange(bool target_state)
414 {
415  return waitMCRChange(flexcan::MCR_FRZACK, target_state);
416 }
417 
418 void CanIface::setFreeze(bool freeze_true)
419 {
420  {
421  CriticalSectionLocker lock;
422 
423  if (freeze_true) {
424  can_->MCR |= flexcan::MCR_FRZ;
425  can_->MCR |= flexcan::MCR_HALT;
426 
427  } else {
428  can_->MCR &= ~flexcan::MCR_HALT;
429  can_->MCR &= ~flexcan::MCR_FRZ;
430 
431  }
432  }
433 }
434 
435 
436 bool CanIface::setEnable(bool enable_true)
437 {
438  setMCR(flexcan::MCR_MDIS, !enable_true);
439  return waitMCRChange(flexcan::MCR_LPMACK, true);
440 }
441 uavcan::int16_t CanIface::doReset(Timings timings)
442 
443 {
444  setMCR(flexcan::MCR_SOFTRST, true);
445 
446  if (!waitMCRChange(flexcan::MCR_SOFTRST, false)) {
447  return -ErrMcrSOFTRSTNotCleared;
448  }
449 
450  uavcan::uint8_t tasd = 25 - (flexcan::canclk * (flexcan::HWMaxMB + 3 -
453  (flexcan::busclck * (1 + timings.pseg1 + timings.pseg2 + timings.propseg)
454  * timings.prescaler);
455 
456  setMCR(flexcan::MCR_SUPV, false);
457 
458  for (int i = 0; i < flexcan::HWMaxMB; i++) {
459  can_->MB[i].mb.CS.w = 0x0;
460  can_->MB[i].mb.ID.w = 0x0;
461  can_->MB[i].mb.data.l = 0x0;
462  can_->MB[i].mb.data.h = 0x0;
463  }
464 
467  (((flexcan::HWMaxMB - 1) << flexcan::MCR_MAXMB_SHIFT) & flexcan::MCR_MAXMB_MASK), true);
468  can_->CTRL2 = flexcan::numberFIFOFilters |
472 
473  for (int i = 0; i < flexcan::HWMaxMB; i++) {
474  can_->RXIMR[i].w = 0x0;
475  }
476 
477  can_->RX14MASK = 0x3FFFFFFF;
478  can_->RX15MASK = 0x3FFFFFFF;
479  can_->RXMGMASK = 0x3FFFFFFF;
480  can_->RXFGMASK = 0x0;
481  return 0;
482 }
483 
484 int CanIface::init(const uavcan::uint32_t bitrate, const OperatingMode mode)
485 {
486 
487  /* Set the module disabled */
488 
489  if (!setEnable(false)) {
490  UAVCAN_KINETIS_LOG("MCR MCR_LPMACK not set");
491  return -ErrMcrLPMAckNotSet;
492  }
493 
494  /* Set the Clock to OSCERCLK or ) */
495 
496  can_->CTRL1 &= ~flexcan::CTRL1_CLKSRC;
497  can_->CTRL1 |= flexcan::CLOCKSEL;
498 
499  /* Set the module enabled */
500 
501  if (!setEnable(true)) {
502  UAVCAN_KINETIS_LOG("MCR MCR_LPMACK not cleared");
503  return -ErrMcrLPMAckNotCleared;
504  }
505 
506  /*
507  * Object state - interrupts are disabled, so it's safe to modify it now
508  */
509 
510  rx_queue_.reset();
511  error_cnt_ = 0;
512  served_aborts_cnt_ = 0;
513  uavcan::fill_n(pending_tx_, NumTxMesgBuffers, TxItem());
514  peak_tx_mailbox_index_ = 0;
515  had_activity_ = false;
516 
517  /*
518  * CAN timings for this bitrate
519  */
520  Timings timings;
521  const int timings_res = computeTimings(bitrate, timings);
522 
523  if (timings_res < 0) {
524  setEnable(false);
525  return timings_res;
526  }
527 
528  UAVCAN_KINETIS_LOG("Timings: prescaler=%u rjw=%u propseg=%u pseg1=%u pseg2=%u",
529  unsigned(timings.prescaler), unsigned(timings.rjw),
530  unsigned(timings.propseg), unsigned(timings.pseg1),
531  unsigned(timings.pseg2));
532  /*
533  * Hardware initialization from reset state
534  */
535 
536 
537  uavcan::int16_t rv = doReset(timings);
538 
539  if (rv != 0) {
540  UAVCAN_KINETIS_LOG("doReset returned %d", rv);
541  return -rv;
542  }
543 
544  uavcan::uint32_t ctl1 = can_->CTRL1;
545  ctl1 |= (timings.prescaler - 1) << flexcan::CTRL1_PRESDIV_SHIFT;
546  ctl1 |= (timings.rjw - 1) << flexcan::CTRL1_RJW_SHIFT;
547  ctl1 |= (timings.pseg1 - 1) << flexcan::CTRL1_PSEG1_SHIFT;
548  ctl1 |= (timings.pseg2 - 1) << flexcan::CTRL1_PSEG2_SHIFT;
549  ctl1 |= flexcan::CTRL1_ERRMSK;
550  ctl1 |= flexcan::CTRL1_TWRNMSK;
551  ctl1 |= flexcan::CTRL1_RWRNMSK;
552  ctl1 |= ((mode == SilentMode) ? flexcan::CTRL1_LOM : 0);
553  ctl1 |= ((timings.propseg - 1) << flexcan::CTRL1_ROPSEG_SHIFT);
554  can_->CTRL1 = ctl1;
555 
556  /*
557  * Default filter configuration
558  */
559  volatile flexcan::FilterType *filterBase = reinterpret_cast<volatile
561  mb);
562 
563  for (uavcan::uint32_t i = 0; i < flexcan::NumHWFilters; i++) {
564  volatile flexcan::FilterType &filter = filterBase[i];
565  filter.w = 0; // All bits do not care
566  }
567 
568  can_->RXFGMASK = 0; // All bits do not care
569 
570  for (uavcan::uint32_t mb = 0; mb < flexcan::HWMaxMB; mb++) {
571  can_->RXIMR[mb].w = 0; // All bits do not care
572  }
573 
574  can_->IFLAG1 = FIFO_IFLAG1 | flexcan::TXMBMask;
575  can_->IMASK1 = FIFO_IFLAG1;
576 
577  setFreeze(false);
578  return waitFreezeAckChange(false) ? 0 : -ErrMcrFRZACKAckNotCleared;
579 }
580 
581 void CanIface::handleTxMailboxInterrupt(uavcan::uint8_t mailbox_index, bool txok, const uavcan::uint64_t utc_usec)
582 {
583  UAVCAN_ASSERT(mailbox_index < NumTxMesgBuffers);
584 
585  had_activity_ = had_activity_ || txok;
586 
587  TxItem &txi = pending_tx_[mailbox_index];
588 
589  if (txi.loopback && txok && txi.pending == TxItem::busy) {
590  rx_queue_.push(txi.frame, utc_usec, uavcan::CanIOFlagLoopback);
591  }
592 
593  txi.pending = TxItem::free;
594 }
595 
596 void CanIface::handleTxInterrupt(uavcan::uint32_t tx_iflags, const uavcan::uint64_t utc_usec)
597 {
598 
599  /* First Process aborts */
600 
601  uavcan::uint32_t aborts = pending_aborts_ & tx_iflags;
602 
603  if (aborts) {
604  uavcan::uint32_t moreAborts = aborts;
605  uavcan::uint32_t bit = 1 << flexcan::NumMBinFiFoAndFilters;
606 
607  for (uavcan::uint32_t mb = 0; moreAborts && mb < NumTxMesgBuffers; mb++) {
608  if (moreAborts & bit) {
609  moreAborts &= ~bit;
610  can_->IFLAG1 = bit;
611  pending_tx_[mb].pending = TxItem::free;
612  served_aborts_cnt_++;
613  }
614 
615  bit <<= 1;
616  }
617 
618  tx_iflags &= ~aborts;
619  pending_aborts_ &= ~aborts;
620 
621  }
622 
623  /* Now Process TX completions */
624 
625  uavcan::uint32_t mbBit = 1 << flexcan::NumMBinFiFoAndFilters;
626 
627  for (uavcan::uint32_t mbi = 0; tx_iflags && mbi < NumTxMesgBuffers; mbi++) {
628  if (tx_iflags & mbBit) {
629  can_->IFLAG1 = mbBit;
630  tx_iflags &= ~mbBit;
631  const bool txok = can_->MB[flexcan::NumMBinFiFoAndFilters + mbi].mb.CS.code != flexcan::TxMbAbort;
632  handleTxMailboxInterrupt(mbi, txok, utc_usec);
633  }
634 
635  mbBit <<= 1;
636  }
637 
638  update_event_.signalFromInterrupt();
639 
640  pollErrorFlagsFromISR();
641 
642 }
643 
644 void CanIface::handleRxInterrupt(uavcan::uint32_t rx_iflags, uavcan::uint64_t utc_usec)
645 {
646  UAVCAN_ASSERT(fifo_index < 2);
647 
648  uavcan::CanFrame frame;
649 
650  if ((rx_iflags & FIFO_IFLAG1) == 0) {
651  UAVCAN_ASSERT(0); // Weird, IRQ is here but no data to read
652  return;
653  }
654 
655  if (rx_iflags & flexcan::CAN_FIFO_OV) {
656  error_cnt_++;
657  can_->IFLAG1 = flexcan::CAN_FIFO_OV;
658  }
659 
660  if (rx_iflags & flexcan::CAN_FIFO_WARN) {
661  fifo_warn_cnt_++;
662  can_->IFLAG1 = flexcan::CAN_FIFO_WARN;
663  }
664 
665  if (rx_iflags & flexcan::CAN_FIFO_NE) {
666  const flexcan::RxFiFoType &rf = can_->MB[flexcan::FiFo].fifo;
667 
668  /*
669  * Read the frame contents
670  */
671 
672  if (rf.CS.ide) {
673  frame.id = uavcan::CanFrame::MaskExtID & rf.ID.ext;
674  frame.id |= uavcan::CanFrame::FlagEFF;
675 
676  } else {
677  frame.id = uavcan::CanFrame::MaskStdID & rf.ID.std;
678  }
679 
680  if (rf.CS.rtr) {
681  frame.id |= uavcan::CanFrame::FlagRTR;
682  }
683 
684  frame.dlc = rf.CS.dlc;
685 
686  frame.data[0] = rf.data.b0;
687  frame.data[1] = rf.data.b1;
688  frame.data[2] = rf.data.b2;
689  frame.data[3] = rf.data.b3;
690  frame.data[4] = rf.data.b4;
691  frame.data[5] = rf.data.b5;
692  frame.data[6] = rf.data.b6;
693  frame.data[7] = rf.data.b7;
694 
695  volatile uavcan::uint32_t idhit = can_->RXFIR;
696  UNUSED(idhit);
697  (void)can_->TIMER;
698  can_->IFLAG1 = flexcan::CAN_FIFO_NE;
699 
700  /*
701  * Store with timeout into the FIFO buffer and signal update event
702  */
703  rx_queue_.push(frame, utc_usec, 0);
704  had_activity_ = true;
705  update_event_.signalFromInterrupt();
706 
707  }
708 
709  pollErrorFlagsFromISR();
710 }
711 
713 {
714  volatile uavcan::uint32_t esr1 = can_->ESR1 & (flexcan::ESR1_STFERR | flexcan::ESR1_FRMERR |
717 
718  if (esr1 != 0) {
719  can_->ESR1 = esr1;
720  error_cnt_++;
721  uavcan::uint32_t pending_aborts = 0;
722 
723  // Begin abort requests
724 
725  for (int i = 0; i < NumTxMesgBuffers; i++) {
726  TxItem &txi = pending_tx_[i];
727  uavcan::uint32_t mbi = flexcan::NumMBinFiFoAndFilters + i;
728  uavcan::uint32_t iflag1 = 1 << mbi;
729 
730  if (txi.pending == TxItem::busy && txi.abort_on_error) {
731  txi.pending = TxItem::abort;
732  can_->IFLAG1 = iflag1;
733  pending_aborts |= iflag1;;
734  can_->MB[mbi].mb.CS.code = flexcan::TxMbAbort;
735  }
736  }
737 
738  pending_aborts_ = pending_aborts;
739  }
740 
741 }
742 
743 void CanIface::discardTimedOutTxMailboxes(uavcan::MonotonicTime current_time)
744 {
745  CriticalSectionLocker lock;
746 
747  for (int mbi = 0; mbi < NumTxMesgBuffers; mbi++) {
748  TxItem &txi = pending_tx_[mbi];
749 
750  if (txi.pending == TxItem::busy && txi.deadline < current_time) {
751  can_->MB[flexcan::NumMBinFiFoAndFilters + mbi].mb.CS.code = flexcan::TxMbAbort;
752  txi.pending = TxItem::abort;
753  error_cnt_++;
754  }
755  }
756 }
757 
758 bool CanIface::canAcceptNewTxFrame(const uavcan::CanFrame &frame) const
759 {
760  /*
761  * We can accept more frames only if the following conditions are satisfied:
762  * - There is at least one TX mailbox free (obvious enough);
763  * - The priority of the new frame is higher than priority of all TX mailboxes.
764  */
765  {
766  if ((can_->ESR2 & (flexcan::ESR2_IMB | flexcan::ESR2_VPS)) == flexcan::ESR2_VPS) {
767  // No Free
768  return false;
769  }
770 
771  }
772 
773  /*
774  * The second condition requires a critical section.
775  */
776  CriticalSectionLocker lock;
777 
778  for (int mbi = 0; mbi < NumTxMesgBuffers; mbi++) {
779  if (pending_tx_[mbi].pending == TxItem::busy && !frame.priorityHigherThan(pending_tx_[mbi].frame)) {
780  return false; // There's a mailbox whose priority is higher or equal the priority of the new frame.
781  }
782  }
783 
784  return true; // This new frame will be added to a free TX mailbox in the next @ref send().
785 }
786 
788 {
789  CriticalSectionLocker lock;
790  return rx_queue_.getLength() == 0;
791 }
792 
793 uavcan::uint64_t CanIface::getErrorCount() const
794 {
795  CriticalSectionLocker lock;
796  return error_cnt_ + rx_queue_.getOverflowCount();
797 }
798 
800 {
801  CriticalSectionLocker lock;
802  return rx_queue_.getLength();
803 }
804 
806 {
807  CriticalSectionLocker lock;
808  const bool ret = had_activity_;
809  had_activity_ = false;
810  return ret;
811 }
812 
813 /*
814  * CanDriver
815  */
816 uavcan::CanSelectMasks CanDriver::makeSelectMasks(const uavcan::CanFrame * (&pending_tx)[uavcan::MaxCanIfaces]) const
817 {
818  uavcan::CanSelectMasks msk;
819 
820  // Iface 0
821  msk.read = if0_.isRxBufferEmpty() ? 0 : 1;
822 
823  if (pending_tx[0] != UAVCAN_NULLPTR) {
824  msk.write = if0_.canAcceptNewTxFrame(*pending_tx[0]) ? 1 : 0;
825  }
826 
827  // Iface 1
828 #if UAVCAN_KINETIS_NUM_IFACES > 1
829 
830  if (!if1_.isRxBufferEmpty()) {
831  msk.read |= 1 << 1;
832  }
833 
834  if (pending_tx[1] != UAVCAN_NULLPTR) {
835  if (if1_.canAcceptNewTxFrame(*pending_tx[1])) {
836  msk.write |= 1 << 1;
837  }
838  }
839 
840 #endif
841  return msk;
842 }
843 
845 {
846 #if UAVCAN_KINETIS_NUM_IFACES == 1
847  return !if0_.isRxBufferEmpty();
848 #elif UAVCAN_KINETIS_NUM_IFACES == 2
849  return !if0_.isRxBufferEmpty() || !if1_.isRxBufferEmpty();
850 #else
851 # error UAVCAN_KINETIS_NUM_IFACES
852 #endif
853 }
854 
855 uavcan::int16_t CanDriver::select(uavcan::CanSelectMasks &inout_masks,
856  const uavcan::CanFrame * (&pending_tx)[uavcan::MaxCanIfaces],
857  const uavcan::MonotonicTime blocking_deadline)
858 {
859  const uavcan::CanSelectMasks in_masks = inout_masks;
860  const uavcan::MonotonicTime time = clock::getMonotonic();
861 
862  if0_.discardTimedOutTxMailboxes(time); // Check TX timeouts - this may release some TX slots
863  {
864  CriticalSectionLocker cs_locker;
865  if0_.pollErrorFlagsFromISR();
866  }
867 
868 #if UAVCAN_KINETIS_NUM_IFACES > 1
869  if1_.discardTimedOutTxMailboxes(time);
870  {
871  CriticalSectionLocker cs_locker;
872  if1_.pollErrorFlagsFromISR();
873  }
874 #endif
875 
876  inout_masks = makeSelectMasks(pending_tx); // Check if we already have some of the requested events
877 
878  if ((inout_masks.read & in_masks.read) != 0 ||
879  (inout_masks.write & in_masks.write) != 0) {
880  return 1;
881  }
882 
883  (void)update_event_.wait(blocking_deadline - time); // Block until timeout expires or any iface updates
884  inout_masks = makeSelectMasks(pending_tx); // Return what we got even if none of the requested events are set
885  return 1; // Return value doesn't matter as long as it is non-negative
886 }
887 
888 
890 {
891  /*
892  * CAN1, CAN2
893  */
894  {
895  CriticalSectionLocker lock;
896  modifyreg32(KINETIS_SIM_SCGC6, 0, SIM_SCGC6_FLEXCAN0);
897 #if UAVCAN_KINETIS_NUM_IFACES > 1
898  modifyreg32(KINETIS_SIM_SCGC3, 0, SIM_SCGC3_FLEXCAN1);
899 #endif
900  }
901 
902  /*
903  * IRQ
904  */
905 #define IRQ_ATTACH(irq, handler) \
906  { \
907  const int res = irq_attach(irq, handler, NULL); \
908  (void)res; \
909  assert(res >= 0); \
910  up_enable_irq(irq); \
911  }
912  IRQ_ATTACH(KINETIS_IRQ_CAN0MB, can0_irq);
913 #if UAVCAN_KINETIS_NUM_IFACES > 1
914  IRQ_ATTACH(KINETIS_IRQ_CAN1MB, can1_irq);
915 #endif
916 #undef IRQ_ATTACH
917 }
918 
919 int CanDriver::init(const uavcan::uint32_t bitrate, const CanIface::OperatingMode mode)
920 {
921  int res = 0;
922 
923  UAVCAN_KINETIS_LOG("Bitrate %lu mode %d", static_cast<unsigned long>(bitrate), static_cast<int>(mode));
924 
925  static bool initialized_once = false;
926 
927  if (!initialized_once) {
928  initialized_once = true;
929  UAVCAN_KINETIS_LOG("First initialization");
930  initOnce();
931  }
932 
933  /*
934  * CAN1
935  */
936  UAVCAN_KINETIS_LOG("Initing iface 0...");
937  ifaces[0] = &if0_; // This link must be initialized first,
938  res = if0_.init(bitrate, mode); // otherwise an IRQ may fire while the interface is not linked yet;
939 
940  if (res < 0) { // a typical race condition.
941  UAVCAN_KINETIS_LOG("Iface 0 init failed %i", res);
942  ifaces[0] = UAVCAN_NULLPTR;
943  goto fail;
944  }
945 
946  /*
947  * CAN2
948  */
949 #if UAVCAN_KINETIS_NUM_IFACES > 1
950  UAVCAN_KINETIS_LOG("Initing iface 1...");
951  ifaces[1] = &if1_; // Same thing here.
952  res = if1_.init(bitrate, mode);
953 
954  if (res < 0) {
955  UAVCAN_KINETIS_LOG("Iface 1 init failed %i", res);
956  ifaces[1] = UAVCAN_NULLPTR;
957  goto fail;
958  }
959 
960 #endif
961 
962  UAVCAN_KINETIS_LOG("CAN drv init OK");
963  UAVCAN_ASSERT(res >= 0);
964  return res;
965 
966 fail:
967  UAVCAN_KINETIS_LOG("CAN drv init failed %i", res);
968  UAVCAN_ASSERT(res < 0);
969  return res;
970 }
971 
972 CanIface *CanDriver::getIface(uavcan::uint8_t iface_index)
973 {
974  if (iface_index < UAVCAN_KINETIS_NUM_IFACES) {
975  return ifaces[iface_index];
976  }
977 
978  return UAVCAN_NULLPTR;
979 }
980 
982 {
983  bool ret = if0_.hadActivity();
984 #if UAVCAN_KINETIS_NUM_IFACES > 1
985  ret |= if1_.hadActivity();
986 #endif
987  return ret;
988 }
989 
990 
991 /*
992  * Interrupt handlers
993  */
994 extern "C"
995 {
996 
997  static int can0_irq(const int irq, void *, void *args)
998  {
999 
1000  CanIface *cif = ifaces[0];
1001  flexcan::CanType *flex = flexcan::Can[0];
1002 
1003  if (cif != UAVCAN_NULLPTR) {
1004  const uavcan::uint32_t FIFO_IFLAG1 = flexcan::CAN_FIFO_NE | flexcan::CAN_FIFO_WARN | flexcan::CAN_FIFO_OV;
1005  uavcan::uint32_t flags = flex->IFLAG1 & FIFO_IFLAG1;
1006 
1007  if (flags) {
1008  handleRxInterrupt(cif, flags);
1009  }
1010 
1011  const uavcan::uint32_t MB_IFLAG1 = flexcan::TXMBMask;
1012  flags = flex->IFLAG1 & MB_IFLAG1;
1013 
1014  if (flags) {
1015  handleTxInterrupt(cif, flags);
1016  }
1017  }
1018 
1019  return 0;
1020  }
1021 
1022 #if UAVCAN_KINETIS_NUM_IFACES > 1
1023 
1024  static int can1_irq(const int irq, void *, void *)
1025  {
1026  CanIface *cif = ifaces[1];
1027  flexcan::CanType *flex = flexcan::Can[1];
1028 
1029  if (cif != UAVCAN_NULLPTR) {
1030  const uavcan::uint32_t FIFO_IFLAG1 = flexcan::CAN_FIFO_NE | flexcan::CAN_FIFO_WARN | flexcan::CAN_FIFO_OV;
1031  uavcan::uint32_t flags = flex->IFLAG1 & FIFO_IFLAG1;
1032 
1033  if (flags) {
1034  handleRxInterrupt(cif, flags);
1035  }
1036 
1037  const uavcan::uint32_t MB_IFLAG1 = flexcan::TXMBMask;
1038  flags = flex->IFLAG1 & MB_IFLAG1;
1039 
1040  if (flags) {
1041  handleTxInterrupt(cif, flags);
1042  }
1043  }
1044 
1045  return 0;
1046  }
1047 
1048 #endif
1049 } // extern "C"
1050 } // namespace uavcan_kinetis
void setFreeze(bool freeze_true)
uavcan::CanSelectMasks makeSelectMasks(const uavcan::CanFrame *(&pending_tx)[uavcan::MaxCanIfaces]) const
This function returns select masks indicating which interfaces are available for read/write.
constexpr unsigned long ESR1_FRMERR
Definition: flexcan.hpp:397
constexpr unsigned long CTRL2_TASD_MASK
Definition: flexcan.hpp:556
int init(const uavcan::uint32_t bitrate, const CanIface::OperatingMode mode)
Returns zero if OK.
bool waitMCRChange(uavcan::uint32_t mask, bool target_state)
constexpr unsigned long MCR_FRZACK
Definition: flexcan.hpp:229
const uavcan::uint32_t canclk
#define UAVCAN_KINETIS_LOG(fmt,...)
Debug output.
Definition: internal.hpp:26
void handleRxInterrupt(uavcan::uint32_t rx_iflags, uavcan::uint64_t utc_usec)
static enum @74 state
virtual uavcan::int16_t send(const uavcan::CanFrame &frame, uavcan::MonotonicTime tx_deadline, uavcan::CanIOFlags flags)
constexpr unsigned long MCR_FRZ
Definition: flexcan.hpp:235
static const uavcan::int16_t ErrMcrFRZACKAckNotSet
MCR_FRZACK bit of the MCR register is not 1.
Definition: can.hpp:26
virtual uavcan::int16_t select(uavcan::CanSelectMasks &inout_masks, const uavcan::CanFrame *(&pending_tx)[uavcan::MaxCanIfaces], uavcan::MonotonicTime blocking_deadline)
constexpr unsigned long CTRL1_ROPSEG_SHIFT
Definition: flexcan.hpp:240
void setMCR(uavcan::uint32_t mask, bool target_state)
constexpr unsigned long MCR_SRXDIS
Definition: flexcan.hpp:222
bool hadActivity()
Whether this iface had at least one successful IO since the previous call of this method...
bool canAcceptNewTxFrame(const uavcan::CanFrame &frame) const
constexpr unsigned long MCR_MAXMB_MASK
Definition: flexcan.hpp:209
constexpr unsigned long MCR_MDIS
Definition: flexcan.hpp:236
void handleTxInterrupt(uavcan::uint32_t tx_iflags, uavcan::uint64_t utc_usec)
constexpr unsigned long CAN_FIFO_NE
Definition: flexcan.hpp:519
bool hadActivity()
Whether at least one iface had at least one successful IO since previous call of this method...
constexpr unsigned long CTRL2_TASD_SHIFT
Definition: flexcan.hpp:555
void discardTimedOutTxMailboxes(uavcan::MonotonicTime current_time)
uavcan::MonotonicTime deadline
Definition: can.hpp:109
constexpr unsigned long CTRL1_RJW_SHIFT
Definition: flexcan.hpp:258
int init(const uavcan::uint32_t bitrate, const OperatingMode mode)
Initializes the hardware CAN controller.
uavcan::uint8_t prescaler
Definition: can.hpp:92
uavcan::MonotonicTime getMonotonic()
Returns current monotonic time since the moment when clock::init() was called.
constexpr unsigned long CTRL1_TWRNMSK
Definition: flexcan.hpp:249
uavcan::uint64_t getUtcUSecFromCanInterrupt()
constexpr unsigned long CTRL1_PSEG1_SHIFT
Definition: flexcan.hpp:256
constexpr unsigned long CTRL1_PSEG2_SHIFT
Definition: flexcan.hpp:254
constexpr unsigned long MCR_IRMQ
Definition: flexcan.hpp:221
constexpr unsigned long ESR1_BIT1ERR
Definition: flexcan.hpp:401
void handleTxMailboxInterrupt(uavcan::uint8_t mailbox_index, bool txok, uavcan::uint64_t utc_usec)
enum uavcan_kinetis::CanIface::TxItem::@26 pending
constexpr unsigned long MCR_SUPV
Definition: flexcan.hpp:228
constexpr unsigned long CTRL1_ERRMSK
Definition: flexcan.hpp:252
static const uavcan::int16_t ErrMcrSOFTRSTNotCleared
MCR_SOFTRST bit of the MCR register is not 0.
Definition: can.hpp:30
Single CAN iface.
Definition: can.hpp:50
virtual uavcan::int16_t receive(uavcan::CanFrame &out_frame, uavcan::MonotonicTime &out_ts_monotonic, uavcan::UtcTime &out_ts_utc, uavcan::CanIOFlags &out_flags)
virtual CanIface * getIface(uavcan::uint8_t iface_index)
constexpr unsigned long ESR2_IMB
Definition: flexcan.hpp:580
const uavcan::uint32_t OSCERCLK
virtual uavcan::uint64_t getErrorCount() const
Total number of hardware failures and other kinds of errors (e.g.
constexpr unsigned long ESR1_CRCERR
Definition: flexcan.hpp:398
const uavcan::uint32_t numberFIFOFilters
constexpr _Tp min(_Tp a, _Tp b)
Definition: Limits.hpp:54
constexpr unsigned long ESR1_ACKERR
Definition: flexcan.hpp:399
const uavcan::uint8_t useFIFO
CanType *const Can[UAVCAN_KINETIS_NUM_IFACES]
CANx register sets.
Definition: flexcan.hpp:198
unsigned getRxQueueLength() const
Returns the number of frames pending in the RX queue.
constexpr unsigned long ESR1_STFERR
Definition: flexcan.hpp:396
void pollErrorFlagsFromISR()
This method is used to count errors and abort transmission on error if necessary. ...
static const uavcan::int16_t ErrMcrLPMAckNotSet
MCR_LPMACK bit of the MCR register is not 1.
Definition: can.hpp:24
uavcan::uint8_t propseg
Definition: can.hpp:96
static const uavcan::int16_t ErrUnsupportedFrame
Frame not supported (e.g. RTR, CAN FD, etc)
Definition: can.hpp:23
static const uavcan::int16_t ErrMcrFRZACKAckNotCleared
MCR_FRZACK bit of the MCR register is not 0.
Definition: can.hpp:27
constexpr _Tp max(_Tp a, _Tp b)
Definition: Limits.hpp:60
constexpr unsigned long CTRL2_RFFN_16MB(1U<< CTRL2_RFFN_SHIFT)
const uavcan::uint32_t busclck
constexpr unsigned long ESR2_LPTM_MASK
Definition: flexcan.hpp:584
uavcan::CanFrame frame
Definition: can.hpp:110
bool waitFreezeAckChange(bool target_state)
int computeTimings(uavcan::uint32_t target_bitrate, Timings &out_timings)
#define UNUSED(x)
Definition: spektrum_rc.cpp:58
constexpr unsigned long MCR_AEN
Definition: flexcan.hpp:218
constexpr unsigned long CTRL1_RWRNMSK
Definition: flexcan.hpp:248
#define IRQ_ATTACH(irq, handler)
static const uavcan::int16_t ErrInvalidBitRate
Bit rate not supported.
Definition: can.hpp:21
constexpr unsigned long CTRL1_LOM
Definition: flexcan.hpp:242
constexpr unsigned long CAN_FIFO_WARN
Definition: flexcan.hpp:521
static int can0_irq(const int irq, void *, void *args)
bool setEnable(bool enable_true)
constexpr unsigned long ESR1_BIT0ERR
Definition: flexcan.hpp:400
constexpr unsigned long MCR_MAXMB_SHIFT
Definition: flexcan.hpp:208
void push(const uavcan::CanFrame &frame, const uint64_t &utc_usec, uavcan::CanIOFlags flags)
static const uavcan::int16_t ErrFilterNumConfigs
Number of filters is more than supported.
Definition: can.hpp:29
uavcan::int16_t doReset(Timings timings)
constexpr unsigned long MCR_SOFTRST
Definition: flexcan.hpp:230
constexpr unsigned long CTRL1_PRESDIV_SHIFT
Definition: flexcan.hpp:260
virtual uavcan::int16_t configureFilters(const uavcan::CanFilterConfig *filter_configs, uavcan::uint16_t num_configs)
constexpr unsigned long MCR_WAKSRC
Definition: flexcan.hpp:224
constexpr unsigned long ESR2_VPS
Definition: flexcan.hpp:581
constexpr unsigned long MCR_RFEN
Definition: flexcan.hpp:234
constexpr unsigned long MCR_WRNEN
Definition: flexcan.hpp:226
constexpr unsigned long MCR_HALT
Definition: flexcan.hpp:233
constexpr unsigned long CTRL2_RRS
Definition: flexcan.hpp:553
constexpr unsigned long MCR_LPMACK
Definition: flexcan.hpp:225
static const uavcan::int16_t ErrMcrLPMAckNotCleared
MCR_LPMACK bit of the MCR register is not 0.
Definition: can.hpp:25
void pop(uavcan::CanFrame &out_frame, uavcan::uint64_t &out_utc_usec, uavcan::CanIOFlags &out_flags)
constexpr unsigned long CTRL1_CLKSRC
Definition: flexcan.hpp:251
constexpr unsigned long CAN_FIFO_OV
Definition: flexcan.hpp:523
mode
Definition: vtol_type.h:76
constexpr unsigned long CTRL2_EACEN
Definition: flexcan.hpp:551
const uavcan::uint8_t CLOCKSEL
bool hasReadableInterfaces() const
Whether there&#39;s at least one interface where receive() would return a frame.
constexpr unsigned long MCR_SLFWAK
Definition: flexcan.hpp:227
constexpr unsigned long ESR2_LPTM_SHIFT
Definition: flexcan.hpp:583