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