/ src / CANSAME5x.cpp
CANSAME5x.cpp
  1  // Copyright 2020 © Jeff Epler for Adafruit Industries. All rights reserved.
  2  // Licensed under the MIT license. See LICENSE file in the project root for full
  3  // license information.
  4  
  5  #if defined(ADAFRUIT_FEATHER_M4_CAN)
  6  #include <stdint.h>
  7  #include <stdlib.h>
  8  
  9  #include "CANSAME5x.h"
 10  #include "wiring_private.h"
 11  
 12  #define DEBUG_CAN (0)
 13  #if DEBUG_CAN
 14  #define DEBUG_PRINT(...) (Serial.print(__VA_ARGS__), ((void)0))
 15  #define DEBUG_PRINTLN(...) (Serial.println(__VA_ARGS__), ((void)0))
 16  #else
 17  #define DEBUG_PRINT(...) ((void)0)
 18  #define DEBUG_PRINTLN(...) ((void)0)
 19  #endif
 20  
 21  namespace {
 22  #include "CANSAME5x_port.h"
 23  }
 24  
 25  #define hw (reinterpret_cast<Can *>(this->_hw))
 26  #define state (reinterpret_cast<_canSAME5x_state *>(this->_state))
 27  
 28  #define DIV_ROUND(a, b) (((a) + (b) / 2) / (b))
 29  #define DIV_ROUND_UP(a, b) (((a) + (b)-1) / (b))
 30  
 31  #define GCLK_CAN1 GCLK_PCHCTRL_GEN_GCLK1_Val
 32  #define GCLK_CAN0 GCLK_PCHCTRL_GEN_GCLK1_Val
 33  #define ADAFRUIT_ZEROCAN_TX_BUFFER_SIZE (1)
 34  #define ADAFRUIT_ZEROCAN_RX_FILTER_SIZE (1)
 35  #define ADAFRUIT_ZEROCAN_RX_FIFO_SIZE (8)
 36  #define ADAFRUIT_ZEROCAN_MAX_MESSAGE_LENGTH (8)
 37  
 38  namespace {
 39  
 40  template <class T, std::size_t N>
 41  constexpr size_t size(const T (&array)[N]) noexcept {
 42    return N;
 43  }
 44  
 45  // Adapted from ASF3 interrupt_sam_nvic.c:
 46  
 47  volatile unsigned long cpu_irq_critical_section_counter = 0;
 48  volatile unsigned char cpu_irq_prev_interrupt_state = 0;
 49  
 50  void cpu_irq_enter_critical(void) {
 51    if (!cpu_irq_critical_section_counter) {
 52      if (__get_PRIMASK() == 0) { // IRQ enabled?
 53        __disable_irq();          // Disable it
 54        __DMB();
 55        cpu_irq_prev_interrupt_state = 1;
 56      } else {
 57        // Make sure the to save the prev state as false
 58        cpu_irq_prev_interrupt_state = 0;
 59      }
 60    }
 61  
 62    cpu_irq_critical_section_counter++;
 63  }
 64  
 65  void cpu_irq_leave_critical(void) {
 66    // Check if the user is trying to leave a critical section
 67    // when not in a critical section
 68    if (cpu_irq_critical_section_counter > 0) {
 69      cpu_irq_critical_section_counter--;
 70  
 71      // Only enable global interrupts when the counter
 72      // reaches 0 and the state of the global interrupt flag
 73      // was enabled when entering critical state */
 74      if ((!cpu_irq_critical_section_counter) && cpu_irq_prev_interrupt_state) {
 75        __DMB();
 76        __enable_irq();
 77      }
 78    }
 79  }
 80  
 81  // This appears to be a typo (transposition error) in the ASF4 headers
 82  // It's called the "Extended ID Filter Entry"
 83  typedef CanMramXifde CanMramXidfe;
 84  
 85  typedef uint32_t can_filter_t;
 86  
 87  struct _canSAME5x_tx_buf {
 88    CAN_TXBE_0_Type txb0;
 89    CAN_TXBE_1_Type txb1;
 90    __attribute__((aligned(4))) uint8_t data[8];
 91  };
 92  
 93  struct _canSAME5x_rx_fifo {
 94    CAN_RXF0E_0_Type rxf0;
 95    CAN_RXF0E_1_Type rxf1;
 96    __attribute((aligned(4))) uint8_t data[ADAFRUIT_ZEROCAN_MAX_MESSAGE_LENGTH];
 97  } can_rx_fifo_t;
 98  
 99  struct _canSAME5x_state {
100    _canSAME5x_tx_buf tx_buffer[ADAFRUIT_ZEROCAN_TX_BUFFER_SIZE];
101    _canSAME5x_rx_fifo rx_fifo[ADAFRUIT_ZEROCAN_RX_FIFO_SIZE];
102    CanMramSidfe standard_rx_filter[ADAFRUIT_ZEROCAN_RX_FILTER_SIZE];
103    CanMramXifde extended_rx_filter[ADAFRUIT_ZEROCAN_RX_FILTER_SIZE];
104  };
105  
106  // This data must be in the first 64kB of RAM.  The "canram" section
107  // receives special support from the linker file in the Feather M4 CAN's
108  // board support package.
109  __attribute__((section(".canram"))) _canSAME5x_state can_state[2];
110  
111  constexpr uint32_t can_frequency = VARIANT_GCLK1_FREQ;
112  bool compute_nbtp(uint32_t baudrate, CAN_NBTP_Type &result) {
113    uint32_t clocks_per_bit = DIV_ROUND(can_frequency, baudrate);
114    uint32_t clocks_to_sample = DIV_ROUND(clocks_per_bit * 7, 8);
115    uint32_t clocks_after_sample = clocks_per_bit - clocks_to_sample;
116    uint32_t divisor = max(DIV_ROUND_UP(clocks_to_sample, 256),
117                           DIV_ROUND_UP(clocks_after_sample, 128));
118    if (divisor > 32) {
119      return false;
120    }
121    result.bit.NTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 2;
122    result.bit.NTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1;
123    result.bit.NBRP = divisor - 1;
124    result.bit.NSJW = DIV_ROUND(clocks_after_sample, divisor * 4);
125    return true;
126  }
127  
128  EPioType find_pin(const can_function *table, size_t n, int arduino_pin,
129                    int &instance) {
130    if (arduino_pin < 0 || arduino_pin > PINS_COUNT) {
131      return (EPioType)-1;
132    }
133  
134    unsigned port = g_APinDescription[arduino_pin].ulPort;
135    unsigned pin = g_APinDescription[arduino_pin].ulPin;
136    for (size_t i = 0; i < n; i++) {
137      if (table[i].port == port && table[i].pin == pin) {
138        if (instance == -1 || table[i].instance == instance) {
139          DEBUG_PRINT("found #");
140          DEBUG_PRINTLN(i);
141          instance = table[i].instance;
142          return EPioType(table[i].mux);
143        }
144      }
145    }
146    return (EPioType)-1;
147  }
148  
149  } // namespace
150  
151  CANSAME5x::CANSAME5x(uint8_t TX_PIN, uint8_t RX_PIN)
152      : _tx(TX_PIN), _rx(RX_PIN) {}
153  #ifdef PIN_CAN_TX
154  CANSAME5x::CANSAME5x() : _tx(PIN_CAN_TX), _rx(PIN_CAN_RX) {}
155  #else
156  CANSAME5x::CANSAME5x() : _tx(-1) {}
157  #endif
158  
159  CANSAME5x::~CANSAME5x() {}
160  
161  int CANSAME5x::begin(long baudrate) {
162    if (_tx == -1) {
163      return 0;
164    }
165  
166    DEBUG_PRINT("_rx ");
167    DEBUG_PRINT(_rx);
168    DEBUG_PRINT(" ulPort=");
169    DEBUG_PRINT(g_APinDescription[_rx].ulPort);
170    DEBUG_PRINT(" ulPin=");
171    DEBUG_PRINTLN(g_APinDescription[_rx].ulPin);
172  
173    DEBUG_PRINTLN("rx pin table");
174    for (size_t i = 0; i < size(can_rx); i++) {
175      DEBUG_PRINT(i);
176      DEBUG_PRINT(" port=");
177      DEBUG_PRINT(can_rx[i].port);
178      DEBUG_PRINT(" pin=");
179      DEBUG_PRINT(can_rx[i].pin);
180      DEBUG_PRINT(" instance=");
181      DEBUG_PRINTLN(can_rx[i].instance);
182    }
183  
184    DEBUG_PRINT("_tx ");
185    DEBUG_PRINT(_tx);
186    DEBUG_PRINT(" ulPort=");
187    DEBUG_PRINT(g_APinDescription[_tx].ulPort);
188    DEBUG_PRINT(" ulPin=");
189    DEBUG_PRINTLN(g_APinDescription[_tx].ulPin);
190  
191    DEBUG_PRINTLN("tx pin table");
192    for (size_t i = 0; i < size(can_tx); i++) {
193      DEBUG_PRINT(i);
194      DEBUG_PRINT(" port=");
195      DEBUG_PRINT(can_tx[i].port);
196      DEBUG_PRINT(" pin=");
197      DEBUG_PRINT(can_tx[i].pin);
198      DEBUG_PRINT(" instance=");
199      DEBUG_PRINTLN(can_tx[i].instance);
200    }
201  
202    int instance = -1;
203    EPioType tx_function = find_pin(can_tx, size(can_tx), _tx, instance);
204    EPioType rx_function = find_pin(can_rx, size(can_rx), _rx, instance);
205  
206    if (tx_function == EPioType(-1) || rx_function == EPioType(-1) ||
207        instance == -1) {
208      return 0;
209    }
210  
211    CAN_NBTP_Type nbtp;
212    if (!compute_nbtp(baudrate, nbtp)) {
213      return 0;
214    }
215  
216    _idx = instance;
217    _hw = reinterpret_cast<void *>(_idx == 0 ? CAN0 : CAN1);
218    _state = reinterpret_cast<void *>(&can_state[_idx]);
219  
220    memset(state, 0, sizeof(*state));
221  
222    pinPeripheral(_tx, tx_function);
223    pinPeripheral(_rx, rx_function);
224  
225    if (_idx == 0) {
226      GCLK->PCHCTRL[CAN0_GCLK_ID].reg = GCLK_CAN0 | (1 << GCLK_PCHCTRL_CHEN_Pos);
227    } else {
228      GCLK->PCHCTRL[CAN1_GCLK_ID].reg = GCLK_CAN1 | (1 << GCLK_PCHCTRL_CHEN_Pos);
229    }
230    // reset and allow configuration change
231    hw->CCCR.bit.INIT = 1;
232    while (!hw->CCCR.bit.INIT) {
233    }
234    hw->CCCR.bit.CCE = 1;
235  
236    // All TX data has an 8 byte payload (max)
237    {
238      CAN_TXESC_Type esc = {};
239      esc.bit.TBDS = CAN_TXESC_TBDS_DATA8_Val;
240      hw->TXESC.reg = esc.reg;
241    }
242  
243    // Set up TX buffer
244    {
245      CAN_TXBC_Type bc = {};
246      bc.bit.TBSA = (uint32_t)state->tx_buffer;
247      bc.bit.NDTB = ADAFRUIT_ZEROCAN_TX_BUFFER_SIZE;
248      bc.bit.TFQM = 0; // Messages are transmitted in the order submitted
249      hw->TXBC.reg = bc.reg;
250    }
251  
252    // All RX data has an 8 byte payload (max)
253    {
254      CAN_RXESC_Type esc = {};
255      esc.bit.F0DS = CAN_RXESC_F0DS_DATA8_Val;
256      esc.bit.F1DS = CAN_RXESC_F1DS_DATA8_Val;
257      esc.bit.RBDS = CAN_RXESC_RBDS_DATA8_Val;
258      hw->RXESC.reg = esc.reg;
259    }
260  
261    // Set up RX fifo 0
262    {
263      CAN_RXF0C_Type rxf = {};
264      rxf.bit.F0SA = (uint32_t)state->rx_fifo;
265      rxf.bit.F0S = ADAFRUIT_ZEROCAN_RX_FIFO_SIZE;
266      hw->RXF0C.reg = rxf.reg;
267    }
268  
269    // Reject all packets not explicitly requested
270    {
271      CAN_GFC_Type gfc = {};
272      gfc.bit.RRFE = 0;
273      gfc.bit.ANFS = CAN_GFC_ANFS_REJECT_Val;
274      gfc.bit.ANFE = CAN_GFC_ANFE_REJECT_Val;
275      hw->GFC.reg = gfc.reg;
276    }
277  
278    // Initially, receive all standard and extended packets to FIFO 0
279    state->standard_rx_filter[0].SIDFE_0.bit.SFID1 = 0; // ID
280    state->standard_rx_filter[0].SIDFE_0.bit.SFID2 = 0; // mask
281    state->standard_rx_filter[0].SIDFE_0.bit.SFEC = CAN_SIDFE_0_SFEC_STF0M_Val;
282    state->standard_rx_filter[0].SIDFE_0.bit.SFT = CAN_SIDFE_0_SFT_CLASSIC_Val;
283  
284    state->extended_rx_filter[0].XIDFE_0.bit.EFID1 = 0; // ID
285    state->extended_rx_filter[0].XIDFE_0.bit.EFEC = CAN_XIDFE_0_EFEC_STF0M_Val;
286    state->extended_rx_filter[0].XIDFE_1.bit.EFID2 = 0; // mask
287    state->extended_rx_filter[0].XIDFE_1.bit.EFT = CAN_XIDFE_1_EFT_CLASSIC_Val;
288  
289    // Set up standard RX filters
290    {
291      CAN_SIDFC_Type dfc = {};
292      dfc.bit.LSS = ADAFRUIT_ZEROCAN_RX_FILTER_SIZE;
293      dfc.bit.FLSSA = (uint32_t)state->standard_rx_filter;
294      hw->SIDFC.reg = dfc.reg;
295    }
296  
297    // Set up extended RX filters
298    {
299      CAN_XIDFC_Type dfc = {};
300      dfc.bit.LSE = ADAFRUIT_ZEROCAN_RX_FILTER_SIZE;
301      dfc.bit.FLESA = (uint32_t)state->extended_rx_filter;
302      hw->XIDFC.reg = dfc.reg;
303    }
304  
305    // Enable receive IRQ (masked until enabled in NVIC)
306    hw->IE.bit.RF0NE = true;
307    if (_idx == 0) {
308      hw->ILE.bit.EINT0 = true;
309    } else {
310      hw->ILE.bit.EINT1 = true;
311    }
312    hw->ILS.bit.RF0NL = _idx;
313  
314    // Set nominal baud rate
315    hw->NBTP.reg = nbtp.reg;
316  
317    // hardware is ready for use
318    hw->CCCR.bit.CCE = 0;
319    hw->CCCR.bit.INIT = 0;
320    while (hw->CCCR.bit.INIT) {
321    }
322  
323    instances[_idx] = this;
324  
325    return 1;
326  }
327  
328  void CANSAME5x::end() {
329    instances[_idx] = 0;
330    pinMode(_tx, INPUT);
331    pinMode(_rx, INPUT);
332    // reset and disable clock
333    hw->CCCR.bit.INIT = 1;
334    while (!hw->CCCR.bit.INIT) {
335    }
336    if (_idx == 0) {
337      GCLK->PCHCTRL[CAN0_GCLK_ID].reg = 0;
338    } else {
339      GCLK->PCHCTRL[CAN1_GCLK_ID].reg = 0;
340    }
341  }
342  
343  int CANSAME5x::endPacket() {
344    if (!CANControllerClass::endPacket()) {
345      return 0;
346    }
347  
348    bus_autorecover();
349  
350    // TODO wait for TX buffer to free
351  
352    _canSAME5x_tx_buf &buf = state->tx_buffer[0];
353    buf.txb0.bit.ESI = false;
354    buf.txb0.bit.XTD = _txExtended;
355    buf.txb0.bit.RTR = _txRtr;
356    if (_txExtended) {
357      buf.txb0.bit.ID = _txId;
358    } else {
359      buf.txb0.bit.ID = _txId << 18;
360    }
361    buf.txb1.bit.MM = 0;
362    buf.txb1.bit.EFC = 0;
363    buf.txb1.bit.FDF = 0;
364    buf.txb1.bit.BRS = 0;
365    buf.txb1.bit.DLC = _txLength;
366  
367    if (!_txRtr) {
368      memcpy(buf.data, _txData, _txLength);
369    }
370  
371    // TX buffer add request
372    hw->TXBAR.reg = 1;
373  
374    // wait 8ms (hard coded for now) for TX to occur
375    for (int i = 0; i < 8000; i++) {
376      if (hw->TXBTO.reg & 1) {
377        return true;
378      }
379      yield();
380    }
381  
382    return 1;
383  }
384  
385  int CANSAME5x::_parsePacket() {
386    if (!hw->RXF0S.bit.F0FL) {
387      return 0;
388    }
389  
390    int index = hw->RXF0S.bit.F0GI;
391    auto &hw_message = state->rx_fifo[index];
392  
393    _rxExtended = hw_message.rxf0.bit.XTD;
394    _rxRtr = hw_message.rxf0.bit.RTR;
395    _rxDlc = hw_message.rxf1.bit.DLC;
396  
397    if (_rxExtended) {
398      _rxId = hw_message.rxf0.bit.ID;
399    } else {
400      _rxId = hw_message.rxf0.bit.ID >> 18;
401    }
402  
403    if (_rxRtr) {
404      _rxLength = 0;
405    } else {
406      _rxLength = _rxDlc;
407      memcpy(_rxData, hw_message.data, _rxLength);
408    }
409  
410    _rxIndex = 0;
411  
412    hw->RXF0A.bit.F0AI = index;
413  
414    return _rxDlc;
415  }
416  
417  int CANSAME5x::parsePacket() {
418    cpu_irq_enter_critical();
419    bus_autorecover();
420    int result = _parsePacket();
421    cpu_irq_leave_critical();
422    return result;
423  }
424  
425  void CANSAME5x::onReceive(void (*callback)(int)) {
426    CANControllerClass::onReceive(callback);
427  
428    auto irq = _idx == 0 ? CAN0_IRQn : CAN1_IRQn;
429    if (callback) {
430      NVIC_EnableIRQ(irq);
431    } else {
432      NVIC_DisableIRQ(irq);
433    }
434  }
435  
436  void CANSAME5x::handleInterrupt() {
437    uint32_t ir = hw->IR.reg;
438  
439    if (ir & CAN_IR_RF0N) {
440      while (int i = parsePacket())
441        _onReceive(i);
442    }
443  
444    hw->IR.reg = ir;
445  }
446  
447  int CANSAME5x::filter(int id, int mask) {
448    // accept matching standard messages
449    state->standard_rx_filter[0].SIDFE_0.bit.SFID1 = id;
450    state->standard_rx_filter[0].SIDFE_0.bit.SFID2 = mask;
451    state->standard_rx_filter[0].SIDFE_0.bit.SFEC = CAN_SIDFE_0_SFEC_STF0M_Val;
452    state->standard_rx_filter[0].SIDFE_0.bit.SFT = CAN_SIDFE_0_SFT_CLASSIC_Val;
453  
454    // reject all extended messages
455    state->extended_rx_filter[0].XIDFE_0.bit.EFID1 = 0; // ID
456    state->extended_rx_filter[0].XIDFE_0.bit.EFEC = CAN_XIDFE_0_EFEC_REJECT_Val;
457    state->extended_rx_filter[0].XIDFE_1.bit.EFID2 = 0; // mask
458    state->extended_rx_filter[0].XIDFE_1.bit.EFT = CAN_XIDFE_1_EFT_CLASSIC_Val;
459  
460    return 1;
461  }
462  
463  int CANSAME5x::filterExtended(long id, long mask) {
464    // reject all standard messages
465    state->standard_rx_filter[0].SIDFE_0.bit.SFID1 = 0;
466    state->standard_rx_filter[0].SIDFE_0.bit.SFID2 = 0;
467    state->standard_rx_filter[0].SIDFE_0.bit.SFEC = CAN_SIDFE_0_SFEC_REJECT_Val;
468    state->standard_rx_filter[0].SIDFE_0.bit.SFT = CAN_SIDFE_0_SFT_CLASSIC_Val;
469  
470    // accept matching extended messages
471    state->extended_rx_filter[0].XIDFE_0.bit.EFID1 = id;
472    state->extended_rx_filter[0].XIDFE_0.bit.EFEC = CAN_XIDFE_0_EFEC_STF0M_Val;
473    state->extended_rx_filter[0].XIDFE_1.bit.EFID2 = mask;
474    state->extended_rx_filter[0].XIDFE_1.bit.EFT = CAN_XIDFE_1_EFT_CLASSIC_Val;
475  
476    return 1;
477  }
478  
479  int CANSAME5x::observe() {
480    hw->CCCR.bit.INIT = 1;
481    while (!hw->CCCR.bit.INIT) {
482    }
483    hw->CCCR.bit.CCE = 1;
484  
485    hw->CCCR.bit.MON = 1;
486  
487    hw->CCCR.bit.CCE = 0;
488    hw->CCCR.bit.INIT = 0;
489    while (hw->CCCR.bit.INIT) {
490    }
491    return 1;
492  }
493  
494  int CANSAME5x::loopback() {
495    hw->CCCR.bit.INIT = 1;
496    while (!hw->CCCR.bit.INIT) {
497    }
498    hw->CCCR.bit.CCE = 1;
499  
500    hw->CCCR.bit.TEST = 1;
501    hw->TEST.bit.LBCK = 1;
502  
503    hw->CCCR.bit.CCE = 0;
504    hw->CCCR.bit.INIT = 0;
505    while (hw->CCCR.bit.INIT) {
506    }
507    return 1;
508  }
509  
510  int CANSAME5x::sleep() {
511    hw->CCCR.bit.CSR = 1;
512    while (!hw->CCCR.bit.CSA) {
513    }
514    if (_idx == 0) {
515      GCLK->PCHCTRL[CAN0_GCLK_ID].reg = 0;
516    } else {
517      GCLK->PCHCTRL[CAN1_GCLK_ID].reg = 0;
518    }
519    return 1;
520  }
521  
522  int CANSAME5x::wakeup() {
523    if (_idx == 0) {
524      GCLK->PCHCTRL[CAN0_GCLK_ID].reg = GCLK_CAN0 | (1 << GCLK_PCHCTRL_CHEN_Pos);
525    } else {
526      GCLK->PCHCTRL[CAN1_GCLK_ID].reg = GCLK_CAN1 | (1 << GCLK_PCHCTRL_CHEN_Pos);
527    }
528    hw->CCCR.bit.INIT = 0;
529    while (hw->CCCR.bit.INIT) {
530    }
531    return 1;
532  }
533  
534  void CANSAME5x::bus_autorecover() {
535    if (hw->PSR.bit.BO) {
536      DEBUG_PRINTLN("bus autorecovery activated");
537      hw->CCCR.bit.INIT = 0;
538      while (hw->CCCR.bit.INIT) {
539      }
540    }
541  }
542  
543  void CANSAME5x::onInterrupt() {
544    for (int i = 0; i < size(instances); i++) {
545      CANSAME5x *instance = instances[i];
546      if (instance) {
547        instance->handleInterrupt();
548      }
549    }
550  }
551  
552  extern "C" __attribute__((externally_visible)) void CAN0_Handler() {
553    cpu_irq_enter_critical();
554    CANSAME5x::onInterrupt();
555    cpu_irq_leave_critical();
556  }
557  
558  extern "C" __attribute__((externally_visible)) void CAN1_Handler() {
559    cpu_irq_enter_critical();
560    CANSAME5x::onInterrupt();
561    cpu_irq_leave_critical();
562  }
563  
564  CANSAME5x *CANSAME5x::instances[2];
565  
566  CANSAME5x CAN;
567  
568  #endif