// ------------------------------------------------------------- void CAN_K2X::begin(uint32_t bitrate) { // segment timings from freescale loopback test if ( 250000 == bitrate ) { FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) | FLEXCAN_CTRL_PSEG1(3) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(15)); } else if ( 500000 == bitrate ) { FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) | FLEXCAN_CTRL_PSEG1(3) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(7)); } else if ( 1000000 == bitrate ) { FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(3) | FLEXCAN_CTRL_RJW(0) | FLEXCAN_CTRL_PSEG1(0) | FLEXCAN_CTRL_PSEG2(1) | FLEXCAN_CTRL_PRESDIV(5)); } else // 125000 { FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(2) | FLEXCAN_CTRL_PSEG1(3) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(31)); } FLEXCAN0_RXMGMASK = 0; //enable reception of all messages that fit the mask // if (mask.extended) // { // FLEXCAN0_RXFGMASK = ((mask.rtr ? 1 : 0) << 31) | ((mask.extended ? 1 : 0) << 30) | ((mask.id & FLEXCAN_MB_ID_EXT_MASK) << 1); // } // else // { // FLEXCAN0_RXFGMASK = ((mask.rtr ? 1 : 0) << 31) | ((mask.extended ? 1 : 0) << 30) | (FLEXCAN_MB_ID_IDSTD(mask.id) << 1); // } FLEXCAN0_RXFGMASK = 0; // start the CAN FLEXCAN0_MCR &= ~(FLEXCAN_MCR_HALT); // wait till exit of freeze mode while (FLEXCAN0_MCR & FLEXCAN_MCR_FRZ_ACK); // wait till ready while (FLEXCAN0_MCR & FLEXCAN_MCR_NOT_RDY); //set tx buffers to inactive for (int i = txb; i < txb + txBuffers; i++) { FLEXCAN0_MBn_CS(i) = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_INACTIVE); } }
// ------------------------------------------------------------- FlexCAN::FlexCAN(uint32_t baud) { // set up the pins, 3=PTA12=CAN0_TX, 4=PTA13=CAN0_RX CORE_PIN3_CONFIG = PORT_PCR_MUX(2); CORE_PIN4_CONFIG = PORT_PCR_MUX(2);// | PORT_PCR_PE | PORT_PCR_PS; // select clock source 16MHz xtal OSC0_CR |= OSC_ERCLKEN; SIM_SCGC6 |= SIM_SCGC6_FLEXCAN0; FLEXCAN0_CTRL1 &= ~FLEXCAN_CTRL_CLK_SRC; // enable CAN FLEXCAN0_MCR |= FLEXCAN_MCR_FRZ; FLEXCAN0_MCR &= ~FLEXCAN_MCR_MDIS; while(FLEXCAN0_MCR & FLEXCAN_MCR_LPM_ACK) ; // soft reset FLEXCAN0_MCR ^= FLEXCAN_MCR_SOFT_RST; while(FLEXCAN0_MCR & FLEXCAN_MCR_SOFT_RST) ; // wait for freeze ack while(!(FLEXCAN0_MCR & FLEXCAN_MCR_FRZ_ACK)) ; // disable self-reception FLEXCAN0_MCR |= FLEXCAN_MCR_SRX_DIS; //enable RX FIFO FLEXCAN0_MCR |= FLEXCAN_MCR_FEN; // segment splits and clock divisor based on baud rate if ( 250000 == baud ) { FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(3)); } else if ( 500000 == baud ) { FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(1)); } else if ( 1000000 == baud ) { FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(0) | FLEXCAN_CTRL_PSEG1(1) | FLEXCAN_CTRL_PSEG2(1) | FLEXCAN_CTRL_PRESDIV(1)); } else { // 125000 FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(7)); } // Default mask is allow everything defaultMask.rtr = 0; defaultMask.ext = 0; defaultMask.id = 0; }
// ------------------------------------------------------------- void FlexCAN::begin(uint8_t _baud) { // soft reset can bus reset(); // segment splits and clock divisor based on baud rate switch (_baud){ case (CAN_5KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(3) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(199)); // 5000 baud Prescaler -> 199 Tq -> 16 break; case (CAN_10KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(3) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(99)); // 10000 baud Prescaler -> 99 Tq -> 16 break; case (CAN_20KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(3) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(49)); // 20000 baud Prescaler -> 49 Tq -> 16 break; case (CAN_25KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(3) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(39)); // 25000 baud Prescaler -> 39 Tq -> 16 break; case (CAN_31K25BPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(3) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(31)); // 31250 baud Prescaler -> 31 Tq -> 16 break; case (CAN_33KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(3) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(29)); // 33333 baud Prescaler -> 29 Tq -> 16 break; case (CAN_40KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(3) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(24)); // 40000 baud Prescaler -> 24 Tq -> 16 break; case (CAN_50KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(3) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(19)); // 50000 baud Prescaler -> 19 Tq -> 16 break; case (CAN_80KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) | FLEXCAN_CTRL_PSEG1(3) | FLEXCAN_CTRL_PSEG2(1) | FLEXCAN_CTRL_PRESDIV(19)); // 80000 baud Prescaler -> 19 !!Tq -> 10!! break; case (CAN_83K3BPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(3) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(11)); // 83333 baud Prescaler -> 11 Tq -> 16 break; case (CAN_95KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(2) | FLEXCAN_CTRL_PSEG1(4) | FLEXCAN_CTRL_PSEG2(2) | FLEXCAN_CTRL_PRESDIV(13)); // 95000 baud Prescaler -> 13 !!Tq -> 12!! break; case (CAN_100KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(3) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(9)); // 100000 baud Prescaler -> 9 Tq -> 16 break; case (CAN_125KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(3) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(7)); // 125000 baud Prescaler -> 7 Tq -> 16 break; case (CAN_200KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(3) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(4)); // 200000 baud Prescaler -> 4 Tq -> 16 break; case (CAN_250KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(3) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(3)); // 250000 baud Prescaler -> 3 Tq -> 16 break; case (CAN_500KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(3) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(1)); // 500000 baud Prescaler -> 1 Tq -> 16 break; case (CAN_666KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(2) | FLEXCAN_CTRL_PSEG1(4) | FLEXCAN_CTRL_PSEG2(2) | FLEXCAN_CTRL_PRESDIV(1)); // 666666 baud Prescaler -> 1 !!Tq -> 12!! break; case (CAN_1000KBPS): FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(3) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(0)); // 100000 baud Prescaler -> 0 Tq -> 16 break; default: // 125000 FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(2) | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(7)); // 125000 baud Prescaler -> 7 Tq -> 16 break; } //enable reception of all messages FLEXCAN0_RXMGMASK = 0; FLEXCAN0_RXFGMASK = ((defaultMask.rtr?1:0) << 31) | ((defaultMask.ext?1:0) << 30) | (FLEXCAN_MB_ID_IDSTD(defaultMask.id) << 1); // start the CAN FLEXCAN0_MCR &= ~(FLEXCAN_MCR_HALT); // wait till exit of freeze mode while(FLEXCAN0_MCR & FLEXCAN_MCR_FRZ_ACK); // wait till ready while(FLEXCAN0_MCR & FLEXCAN_MCR_NOT_RDY); //set tx buffers to inactive for (int i = txb; i < txb + txBuffers; i++) { FLEXCAN0_MBn_CS(i) = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_INACTIVE); } }
void FlexCAN::begin (uint32_t baud, const CAN_filter_t &mask, uint8_t txAlt, uint8_t rxAlt) { // set up the pins if (flexcanBase == FLEXCAN0_BASE) { dbg_println ("Begin setup of CAN0"); #if defined(__MK66FX1M0__) || defined(__MK64FX512__) // 3=PTA12=CAN0_TX, 4=PTA13=CAN0_RX (default) // 29=PTB18=CAN0_TX, 30=PTB19=CAN0_RX (alternative) if (txAlt == 1) CORE_PIN29_CONFIG = PORT_PCR_MUX(2); else CORE_PIN3_CONFIG = PORT_PCR_MUX(2); // | PORT_PCR_PE | PORT_PCR_PS; if (rxAlt == 1) CORE_PIN30_CONFIG = PORT_PCR_MUX(2); else CORE_PIN4_CONFIG = PORT_PCR_MUX(2); #else // 3=PTA12=CAN0_TX, 4=PTA13=CAN0_RX (default) // 32=PTB18=CAN0_TX, 25=PTB19=CAN0_RX (alternative) if (txAlt == 1) CORE_PIN32_CONFIG = PORT_PCR_MUX(2); else CORE_PIN3_CONFIG = PORT_PCR_MUX(2); // | PORT_PCR_PE | PORT_PCR_PS; if (rxAlt == 1) CORE_PIN25_CONFIG = PORT_PCR_MUX(2); else CORE_PIN4_CONFIG = PORT_PCR_MUX(2); #endif } #if defined(INCLUDE_FLEXCAN_CAN1) else if (flexcanBase == FLEXCAN1_BASE) { dbg_println("Begin setup of CAN1"); // 33=PTE24=CAN1_TX, 34=PTE25=CAN1_RX (default) // NOTE: Alternative CAN1 pins are not broken out on Teensy 3.6 CORE_PIN33_CONFIG = PORT_PCR_MUX(2); CORE_PIN34_CONFIG = PORT_PCR_MUX(2);// | PORT_PCR_PE | PORT_PCR_PS; } #endif // select clock source 16MHz xtal OSC0_CR |= OSC_ERCLKEN; if (flexcanBase == FLEXCAN0_BASE) { SIM_SCGC6 |= SIM_SCGC6_FLEXCAN0; #if defined(INCLUDE_FLEXCAN_CAN1) } else if (flexcanBase == FLEXCAN1_BASE) { SIM_SCGC3 |= SIM_SCGC3_FLEXCAN1; #endif } FLEXCANb_CTRL1(flexcanBase) &= ~FLEXCAN_CTRL_CLK_SRC; // enable CAN FLEXCANb_MCR (flexcanBase) |= FLEXCAN_MCR_FRZ; FLEXCANb_MCR (flexcanBase) &= ~FLEXCAN_MCR_MDIS; while (FLEXCANb_MCR(flexcanBase) & FLEXCAN_MCR_LPM_ACK) ; // soft reset FLEXCANb_MCR (flexcanBase) ^= FLEXCAN_MCR_SOFT_RST; while (FLEXCANb_MCR (flexcanBase) & FLEXCAN_MCR_SOFT_RST) ; // wait for freeze ack while (!(FLEXCANb_MCR(flexcanBase) & FLEXCAN_MCR_FRZ_ACK)) ; // disable self-reception FLEXCANb_MCR (flexcanBase) |= FLEXCAN_MCR_SRX_DIS; /* now using a system that tries to automatically generate a viable baud setting. Bear these things in mind: - The master clock is 16Mhz - You can freely divide it by anything from 1 to 256 - There is always a start bit (+1) - The rest (prop, seg1, seg2) are specified 1 less than their actual value (aka +1) - This gives the low end bit timing as 5 (1 + 1 + 2 + 1) and the high end 25 (1 + 8 + 8 + 8) A worked example: 16Mhz clock, divisor = 19+1, bit values add up to 16 = 16Mhz / 20 / 16 = 50k baud */ // have to find a divisor that ends up as close to the target baud as possible while keeping the end result between 5 and 25 uint32_t divisor = 0; uint32_t bestDivisor = 0; uint32_t result = 16000000 / baud / (divisor + 1); int error = baud - (16000000 / (result * (divisor + 1))); int bestError = error; while (result > 5) { divisor++; result = 16000000 / baud / (divisor + 1); if (result <= 25) { error = baud - (16000000 / (result * (divisor + 1))); if (error < 0) error *= -1; // if this error is better than we've ever seen then use it - it's the best option if (error < bestError) { bestError = error; bestDivisor = divisor; } // If this is equal to a previously good option then // switch to it but only if the bit time result was in the middle of the range // this biases the output to use the middle of the range all things being equal // Otherwise it might try to use a higher divisor and smaller values for prop, seg1, seg2 // and that's not necessarily the best idea. if ((error == bestError) && (result > 11) && (result < 19)) { bestError = error; bestDivisor = divisor; } } } divisor = bestDivisor; result = 16000000 / baud / (divisor + 1); if ((result < 5) || (result > 25) || (bestError > 300)) { Serial.println ("Abort in CAN begin. Couldn't find a suitable baud config!"); return; } result -= 5; // the bitTimingTable is offset by 5 since there was no reason to store bit timings for invalid numbers uint8_t propSeg = bitTimingTable[result][0]; uint8_t pSeg1 = bitTimingTable[result][1]; uint8_t pSeg2 = bitTimingTable[result][2]; // baud rate debug information dbg_println ("Bit time values:"); dbg_print ("Prop = "); dbg_println (propSeg + 1); dbg_print ("Seg1 = "); dbg_println (pSeg1 + 1); dbg_print ("Seg2 = "); dbg_println (pSeg2 + 1); dbg_print ("Divisor = "); dbg_println (divisor + 1); FLEXCANb_CTRL1 (flexcanBase) = (FLEXCAN_CTRL_PROPSEG(propSeg) | FLEXCAN_CTRL_RJW(1) | FLEXCAN_CTRL_ERR_MSK | FLEXCAN_CTRL_PSEG1(pSeg1) | FLEXCAN_CTRL_PSEG2(pSeg2) | FLEXCAN_CTRL_PRESDIV(divisor)); // enable per-mailbox filtering FLEXCANb_MCR(flexcanBase) |= FLEXCAN_MCR_IRMQ; // now have to set mask and filter for all the Rx mailboxes or they won't receive anything by default. for (uint8_t c = 0; c < NUM_MAILBOXES - numTxMailboxes; c++) { setMask (0, c); setFilter (mask, c); } // start the CAN FLEXCANb_MCR(flexcanBase) &= ~(FLEXCAN_MCR_HALT); // wait till exit of freeze mode while (FLEXCANb_MCR(flexcanBase) & FLEXCAN_MCR_FRZ_ACK) ; // wait till ready while (FLEXCANb_MCR(flexcanBase) & FLEXCAN_MCR_NOT_RDY) ; setNumTxBoxes (2); #if defined(__MK20DX256__) NVIC_SET_PRIORITY (IRQ_CAN_MESSAGE, IRQ_PRIORITY); NVIC_ENABLE_IRQ (IRQ_CAN_MESSAGE); #elif defined(__MK64FX512__) NVIC_SET_PRIORITY (IRQ_CAN0_MESSAGE, IRQ_PRIORITY); NVIC_ENABLE_IRQ (IRQ_CAN0_MESSAGE); #elif defined(__MK66FX1M0__) if (flexcanBase == FLEXCAN0_BASE) { NVIC_SET_PRIORITY (IRQ_CAN0_MESSAGE, IRQ_PRIORITY); NVIC_ENABLE_IRQ (IRQ_CAN0_MESSAGE); } else { NVIC_SET_PRIORITY (IRQ_CAN1_MESSAGE, IRQ_PRIORITY); NVIC_ENABLE_IRQ (IRQ_CAN1_MESSAGE); } #endif // enable interrupt masks for all 16 mailboxes FLEXCANb_IMASK1 (flexcanBase) = 0xFFFF; dbg_println ("CAN initialized properly"); }