// CAN.c // Runs on MSPM0G3507 // Use FDCAN0 to communicate on CAN bus PA12 and PA13 // Jonathan Valvano // December 11, 2025 // derived from can_to_uart_bridge_LP_MSPM0G3507_nortos_ticlang /* Copyright 2025 by Jonathan W. Valvano, valvano@mail.utexas.edu You may use, edit, run or distribute this file as long as the above copyright notice remains THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. For more information about my classes, my research, and my books, see http://users.ece.utexas.edu/~valvano/ */ // Use TCAN1057AVDRQ1 (not TCAN1057A-Q1, the version with pin 5 nc) // Pin1 TXD ---- CAN_Tx PA12 FD-CAN module 0 transmit // Pin2 Vss ---- ground // Pin3 VCC ---- +5V with 0.1uF cap to ground // Pin4 RXD ---- CAN_Rx PA13 FD-CAN module 0 receive (0 to 3.3V) // Pin5 VIO ---- +3.3V (digital interface supply) // Pin6 CANL ---- to other CANL on network // Pin7 CANH ---- to other CANH on network // Pin8 RS ---- ground, Slope-Control Input (maximum slew rate) // 120 ohm across CANH, CANL on both ends of network #include #include #include "../inc/Clock.h" #include "../RTOS_Labs_common/CAN.h" #include "../RTOS_Labs_common/LaunchPad.h" #include "../RTOS_Labs_common/OS.h" uint32_t CAN_PID,CAN_CREL; // version Sema4_t CanDataAvailable; __STATIC_INLINE uint32_t READ_REG32_RAW(uint32_t addr){ uint32_t regVal = *(volatile uint32_t *) addr; return (regVal); } #define CAN_DEBUG 0 uint32_t objSize4[8] = {4, 5, 6, 7, 8, 10, 14, 18}; typedef struct { /*! Rx FIFO number * One of @ref DL_MCAN_RX_FIFO_NUM */ uint32_t num; /*! Rx FIFO Fill Level */ uint32_t fillLvl; /*! Rx FIFO Get Index */ uint32_t getIdx; /*! Rx FIFO Put Index */ uint32_t putIdx; /*! Rx FIFO Full * 0 = Rx FIFO not full * 1 = Rx FIFO full */ uint32_t fifoFull; /*! Rx FIFO Message Lost */ uint32_t msgLost; } MCAN_RxFIFOStatus_t; /** * @brief Structure for MCAN Rx Buffer element. */ #if CAN_DEBUG typedef struct { // Identifier uint32_t id; // Remote Transmission Request // 0 = Received frame is a data frame // 1 = Received frame is a remote frame uint32_t rtr; // Extended Identifier // 0 = 11-bit standard identifier // 1 = 29-bit extended identifier uint32_t xtd; // Error State Indicator // 0 = Transmitting node is error active // 1 = Transmitting node is error passive uint32_t esi; // Rx Timestamp uint32_t rxts; //Data Length Code // 0-8 = CAN + CAN FD: received frame has 0-8 data bytes uint32_t dlc; // Bit Rat Switching // 0 = Frame received without bit rate switching // 1 = Frame received with bit rate switching uint32_t brs; // FD Format // 0 = Standard frame format // 1 = CAN FD frame format (new DLC-coding and CRC) uint32_t fdf; // Filter Index uint32_t fidx; // Accepted Non-matching Frame // 0 = Received frame matching filter index FIDX // 1 = Received frame did not match any Rx filter element uint32_t anmf; // Data bytes. // Only first dlc number of bytes are valid. uint8_t data[8]; } MCAN_RxBufElement_t; MCAN_RxBufElement_t rxMsg4; #endif // CAN message typedef struct { uint32_t id; // identification of the message uint8_t dlc; // Data Length Code uint8_t data[8]; // Data bytes limited to 8 bytes } CANmsg_t; #define CANFIFOSIZE 8 CANmsg_t CANFIFO[CANFIFOSIZE]; // must be a power of two uint32_t CANGetI = 0; uint32_t CANPutI = 0; volatile uint32_t CanInterruptLine1Status=0; // SYSPLLCLK1 80MHz // bit rate 1Mbps void CAN_Init(void){uint32_t regVal; // assumes Port A has been reset and enabled previously by LaunchPad_Init CANFD0->MCANSS.RSTCTL = 0xB1000003; // reset CAN CANFD0->MCANSS.PWREN = 0x26000001; // enable power Clock_Delay(200); // time for CAN to power up IOMUX->SECCFG.PINCM[PA12INDEX] = (uint32_t) 0x00000085; // PA12 CAN Tx IOMUX->SECCFG.PINCM[PA13INDEX] = (uint32_t) 0x00040086; // PA13 CAN Rx Clock_Delay(1000); // time for CAN to power up // Enables the MCAN functional module clock CANFD0->MCANSS.TI_WRAPPER.MSP.MCANSS_CLKEN = 1; // Clock_Delay(24); // time for CAN to power up // Clock CAN from HFCLK // SYSCTL->SOCLOCK.GENCLKCFG = (SYSCTL->SOCLOCK.GENCLKCFG&~0x00000100); SYSCTL->SOCLOCK.GENCLKCFG |= 0x00000100; // SYSPLLCLK1 // bit 8 0 CANCLK is HFCLK, 1 SYSPLLCLK1 // Clock divide ratio specification. Enables configuring clock divide // settings for the MCAN functional clock input to the MCAN-SS. // 0h (R/W) = Divides input clock by 1 // 1h (R/W) = Divides input clock by 2 // 2h (R/W) = Divides input clock by 4 // 3h (R/W) = Divides input clock by 1 CANFD0->MCANSS.TI_WRAPPER.MSP.MCANSS_CLKDIV = 1; // divide by 2 // Clock_Delay(100); // time for CAN to power up // Get MCANSS Revision ID. (optional FYI only) CAN_PID = CANFD0->MCANSS.TI_WRAPPER.PROCESSORS.MCANSS_REGS.MCANSS_PID; // 31-30 SCHEME R 1h PID Register Scheme // 27-16 MODULE_ID R 8E0h Module Identification Number // 10-8 MAJOR R 1h Major Revision of the MCAN Subsystem // 5-0 MINOR R 1h Minor Revision of the MCAN Subsystem CAN_CREL = CANFD0->MCANSS.MCAN.MCAN_CREL; // core release (optional FYI only) // 31-28 REL R 3h Core Release. One digit, BCD-coded. // 27-24 STEP R 2h Step of Core Release. One digit, BCD-coded. // 23-20 SUBSTEP R 3h Sub-Step of Core Release. One digit, BCD-coded. // 19-16 YEAR R 8h Time Stamp Year. One digit, BCD-coded. // 15-8 MON R 6h Time Stamp Month. Two digits, BCD-coded. // 7-0 DAY R 8h Time Stamp Day. Two digits, BCD-coded. // Wait for Memory initialization to be completed. // bit 1 MEM_INIT_DONE R 0h Memory Initialization Done. // 0 Message RAM initialization is in progress // 1 Message RAM is initialized for use while((CANFD0->MCANSS.TI_WRAPPER.PROCESSORS.MCANSS_REGS.MCANSS_STAT&0x02)==0){}; // Put MCAN in SW initialization mode. // MCAN_CCCR INIT R/W 1h Initialization // 0 Normal Operation // 1 Initialization is started // Note: Due to the synchronization mechanism between the two clock // domains, there may be a delay until the value written to INIT can // be read back. Therefore the programmer has to assure that the // previous value written to INIT has been accepted by reading INIT // before setting INIT to a new value CANFD0->MCANSS.MCAN.MCAN_CCCR |= 0x01; // SW initialization mode while((CANFD0->MCANSS.MCAN.MCAN_CCCR&0x01)==0){}; // Wait while MCAN is not in SW initialization mode // Initialize MCAN module // Configure MCAN wakeup and clock stop controls regVal = CANFD0->MCANSS.TI_WRAPPER.PROCESSORS.MCANSS_REGS.MCANSS_CTRL; regVal |= (1<<4); // wkupReqEnable regVal |= (1<<5); // autoWkupEnable regVal |= (1<<3); // DBGSUSP_FREE emulationEnable CANFD0->MCANSS.TI_WRAPPER.PROCESSORS.MCANSS_REGS.MCANSS_CTRL = regVal; CANFD0->MCANSS.MCAN.MCAN_CCCR |= 0x02; //ProtectedRegAccessUnlock // Configure MCAN mode(FD vs Classic CAN operation) and controls regVal = CANFD0->MCANSS.MCAN.MCAN_CCCR; regVal |= (1<<8); // fdMode, Flexible Datarate Operation Enable regVal |= (1<<9); // brsEnable, Bit Rate Switch Enable regVal &= ~(1<<14); // txpEnable=false, Transmit Pause regVal &= ~(1<<13); // efbi=false, Edge Filtering during Bus Integration regVal &= ~(1<<12); // pxhddisable=0, Protocol Exception Handling Disable regVal &= ~(1<<6); // darEnable=0, Disable Automatic Retransmission CANFD0->MCANSS.MCAN.MCAN_CCCR = regVal; // Configure Transceiver Delay Compensation CANFD0->MCANSS.MCAN.MCAN_TDCR = (6<<8)+ 10; //tdco=6,tdcf=10 // Configure MSG RAM watchdog counter preload value * CANFD0->MCANSS.MCAN.MCAN_RWD = 255; // WDC=wdcPreload=255 // Enable/Disable Transceiver Delay Compensation CANFD0->MCANSS.MCAN.MCAN_DBTP |= (1<<23); // Transmitter Delay Compensation // Configure Bit timings CANFD0->MCANSS.MCAN.MCAN_NBTP = // MCAN Nominal Bit Timing and Prescaler Register (31<<25) // nomSynchJumpWidth Nominal (Re)Synchronization Jump Width |(0<<16) // nomRatePrescalar Nominal Bit Rate Prescaler |(126<<8) // nomTimeSeg1Nominal Time Segment Before Sample Point |(31<<0); // nomTimeSeg2 Nominal Time Segment After Sample Point. CANFD0->MCANSS.MCAN.MCAN_DBTP = // MCAN Data Bit Timing and Prescaler Register (1<<23) // TDC =1 delay compensation |(14<<8) // dataTimeSeg1 |(3<<4) // dataTimeSeg2 |(3<<0); // dataSynchJumpWidth // Configure Message RAM Sections // start end num size // 0 0 0 0 Standard ID Filter List (not used) // 0 0 0 0 Extended ID Filter List (not used) // 448 ??? 2 7(64) Tx Buffers (only uses the first buffer) // 164 172 10 2 Tx EventFIFOs (not used) // 8 368 5 7(64) RxFifo0 (used) // 368 448 5 0(8) RxFifo1 (not used) // 600 672 1 7(64) Rx Buffer (not used) // Configure Message Filters CANFD0->MCANSS.MCAN.MCAN_SIDFC = 0; // MCAN Standard ID Filter Configuration // No standard Message ID filter // No Filter List Standard Start Address CANFD0->MCANSS.MCAN.MCAN_XIDFC = 0; // no Filter List Extended Start Address // No No extended Message ID filter // Configure Rx FIFO 0 section // if (0U != msgRAMConfigParams->rxFIFO0size) { CANFD0->MCANSS.MCAN.MCAN_RXF0C = (0<<31) // F0OM 0 FIFO 0 blocking mode |(0<<24) // F0WM 0 Watermark interrupt disabled |(5<<16) // F0S Rx FIFO 0 number of elements (means you can queue 5 received messages) |(2<<2); // F0SA Rx FIFO 0 Start Address // Configure Rx FIFO0 elements size */ CANFD0->MCANSS.MCAN.MCAN_RXESC = (CANFD0->MCANSS.MCAN.MCAN_RXESC&(~0x07))|7; // F0DS Rx FIFO0 Data Field Size, 111 64 byte data field // Configure Rx FIFO 1 section (not used) CANFD0->MCANSS.MCAN.MCAN_RXF1C = (0<<31) // F1OM 0 FIFO 0 blocking mode |(3<<24) // F1WM 3 Level for Rx FIFO 1 watermark interrupt |(5<<16) // F1S Rx FIFO 1 Size |(368<<2); // F1SA Rx FIFO 1 Start Address // Configure Rx FIFO1 elements size (not used) CANFD0->MCANSS.MCAN.MCAN_RXESC = (CANFD0->MCANSS.MCAN.MCAN_RXESC&(~0x70))|0; // F1DS Rx FIFO 1 Data Field Size 000 8-byte data field // Configure Rx Buffer Start Address (not used) CANFD0->MCANSS.MCAN.MCAN_RXBC = (150<<2); // Rx Buffer Start Address // Configure Rx Buffer elements size (not used) CANFD0->MCANSS.MCAN.MCAN_RXESC = (CANFD0->MCANSS.MCAN.MCAN_RXESC&(~0x700))|0x700; // RBDS Rx Buffer Data Field Size 111 64 byte data field // Configure Tx Event FIFO section CANFD0->MCANSS.MCAN.MCAN_TXEFC = (0<<24) // EFWM Event FIFO Watermark 0 Watermark interrupt disabled |(2<<16) // EFS Event FIFO Size Number of Tx Event FIFO elements |(41<<2); // EFSA Event FIFO Start Address. // TX buffer configuration (uses first buffer at address 448) CANFD0->MCANSS.MCAN.MCAN_TXBC = 112<<2 // TBSA txStartAddr | (2<<16) // TDTB txBufNum, 2 buffers (uses first one) | (10<<24) // TFQS txFIFOSize, 10 fifos | (0<<30); // TFQM, 0 Tx FIFO operation CANFD0->MCANSS.MCAN.MCAN_TXESC = 7; // TBDS, 64 byte data field txBufElemSize // Set Extended ID Mask (does not use extended ID) CANFD0->MCANSS.MCAN.MCAN_XIDAM = 0x1FFFFFFF; // set access lock CANFD0->MCANSS.MCAN.MCAN_CCCR &= ~0x02; // Access lock // Put MCAN into normal mode mode, stop SW initialization mode CANFD0->MCANSS.MCAN.MCAN_CCCR &= ~0x01; while((CANFD0->MCANSS.MCAN.MCAN_CCCR&0x01)==1){}; // wait for normal mode // Initialize semaphore for read OS_InitSemaphore(&CanDataAvailable, 0); } void CAN_EnableInterrupts(uint32_t priority){ // Enable MCAN module Interrupts CANFD0->MCANSS.MCAN.MCAN_IE |= 0x3FEF1201; // MCAN_IE Field Descriptions // 29 ARAE 1 Access to Reserved Address Enable // 28 PEDE 1 Protocol Error in Data Phase Enable // 27 PEAE 1 Protocol Error in Arbitration Phase Enable // 26 WDIE 1 Watchdog Interrupt Enable // 25 BOE 1 Bus_Off Status Enable // 24 EWE 1 Warning Status Enable // 23 EPE 1 Error Passive Enable // 22 ELOE 1 Error Logging Overflow Enable // 21 BEUE 1 Bit Error Uncorrected Enable // 20 BECE 0 Bit Error Corrected Enable // 19 DRXE 1 Message Stored to Dedicated Rx Buffer Enable // 18 TOOE 1 Timeout Occurred Enable // 17 MRAFE 1 Message RAM Access Failure Enable // 16 TSWE 1 Timestamp Wraparound Enable // 15 TEFLE 0 Tx Event FIFO Element Lost Enable // 14 TEFFE 0 Tx Event FIFO Full Enable // 13 TEFWE 0 Tx Event FIFO Watermark Reached Enable // 12 TEFNE 1 Tx Event FIFO New Entry Enable // 11 TFEE 0 Tx FIFO Empty Enable // 10 TCFE 0 Transmission Cancellation Finished Enable // 9 TCE 1 Transmission Completed Enable // 8 HPME 0 High Priority Message Enable // 7 RF1LE 0 Rx FIFO 1 Message Lost Enable // 6 RF1FE 0 Rx FIFO 1 Full Enable // 5 RF1WE 0 Rx FIFO 1 Watermark Reached Enable // 4 RF1NE 0 Rx FIFO 1 New Message Enable // 3 RF0LE 0 Rx FIFO 0 Message Lost Enable // 2 RF0FE 0 Rx FIFO 0 Full Enable // 1 RF0WE 0 Rx FIFO 0 Watermark Reached Enable // 0 RF0NE 1 Rx FIFO 0 New Message Enable (only one used) CANFD0->MCANSS.MCAN.MCAN_ILS |= 0x3FEFFFFF; // select all Line 1 CANFD0->MCANSS.MCAN.MCAN_ILE = 0x02; // line 1 enable // Enable MSPM0 MCAN interrupt CANFD0->MCANSS.TI_WRAPPER.MSP.CPU_INT.ICLR = 0x02; // line 1 clear CANFD0->MCANSS.TI_WRAPPER.MSP.CPU_INT.IMASK |= 0x02; // line 1 enable NVIC->ICPR[0] = (1 << 6); // NVIC_ClearPendingIRQ(6) NVIC->ISER[0] = (1 << 6); // NVIC_EnableIRQ(6) NVIC->IP[1] = (NVIC->IP[1]& (~0x00FF0000))|(priority<<22); // 23 - 22 CANFD0_IRQHandler } __STATIC_INLINE void WRITE_REG32_RAW(uint32_t addr, uint32_t value){ *(volatile uint32_t *) addr = value; return; } // 0 if failure // 1 if ok int CAN_Send(uint32_t id, uint32_t dlc, uint8_t *data){ uint16_t count; uint32_t regVal, loopCnt; uint32_t elemAddr; if(id > 2047) return 1; if(dlc > 8) return 1; // always uses buffer 0 elemAddr = CANFD0->MCANSS.MCAN.MCAN_TXBC&0xFFFC; // bits 15:2, 112*4= 448 regVal = (((uint32_t)(id << 18)) | // 11-bit ID 28:18, ((uint32_t)(0 << 29 )) | // rtr=0 Transmit data frame ((uint32_t)(0 << 30 )) | // xtd=0 11-bit standard identifier ((uint32_t)(0 << 31 ))); // esi=0 ESI bit in CAN FD format depends only on error passive flag WRITE_REG32_RAW(((uint32_t)CANFD0 + (uint32_t) elemAddr), regVal); //448,0, 0x40508000=0 elemAddr += 4U; regVal = (((uint32_t)(dlc << 16 )) | // dlc = data length (0to 8) ((uint32_t)(1 << 20 )) | // brs=1, CAN FD frames transmitted with bit rate switching ((uint32_t)(1 << 21 )) | // fdf=1, Frame transmitted in CAN FD format ((uint32_t)(1 << 23 )) | // efc=1, Store Tx events ((uint32_t)(0xAAU<< 24 ))); // mm = Message Marker WRITE_REG32_RAW(((uint32_t) CANFD0 + (uint32_t) elemAddr), regVal); elemAddr += 4U; loopCnt = 0U; // Framing words out of the payload bytes and writing it to message RAM while ((4U <= (dlc - loopCnt)) && (0U != (dlc - loopCnt))){ regVal = ((uint32_t) data[loopCnt] | ((uint32_t) data[(loopCnt + 1U)] << 8U) | ((uint32_t) data[(loopCnt + 2U)] << 16U) | ((uint32_t) data[(loopCnt + 3U)] << 24U)); WRITE_REG32_RAW(((uint32_t) CANFD0 + (uint32_t) elemAddr), regVal); elemAddr += 4U; loopCnt += 4U; } // Framing a word out of remaining payload bytes and writing it to message RAM if (0U < (dlc - loopCnt)){ regVal = ((uint32_t) data[loopCnt] | ((uint32_t) data[(loopCnt + 1U)] << 8U) | ((uint32_t) data[(loopCnt + 2U)] << 16U) | ((uint32_t) data[(loopCnt + 3U)] << 24U)); WRITE_REG32_RAW(((uint32_t) CANFD0 + (uint32_t) elemAddr), regVal); } regVal = CANFD0->MCANSS.MCAN.MCAN_TXBAR; regVal |= ((uint32_t) 1U << 0); // buffer 0 /* * For writing to TXBAR CCE bit should be '0'. This need not be * reverted because for other qualified writes this is locked state * and can't be written. */ CANFD0->MCANSS.MCAN.MCAN_CCCR &= ~0x02; //Configuration Change Enable CANFD0->MCANSS.MCAN.MCAN_TXBAR = regVal; return 1; // success } void getCANRxFIFOStatus(MCAN_RxFIFOStatus_t *fifoStatus){ uint32_t regVal; regVal = CANFD0->MCANSS.MCAN.MCAN_RXF0S; // 25 RF0L message lost 0 // 24 F0F 1 means full 0 // 21-16 F0PI Rx Putindex 2 // 13-8 F0GI Rx Getindex 1 // 6-0 F0FL Fill level 1 fifoStatus->fillLvl = regVal&0x7F; // HW_GET_FIELD(regVal, MCAN_RXF0S_F0FL); fifoStatus->getIdx = (regVal>>8)&0x3F; // HW_GET_FIELD(regVal, MCAN_RXF0S_F0GI); fifoStatus->putIdx = (regVal>>16)&0x3F; // HW_GET_FIELD(regVal, MCAN_RXF0S_F0PI); fifoStatus->fifoFull = (regVal>>24)&0x01; // HW_GET_FIELD(regVal, MCAN_RXF0S_F0F); fifoStatus->msgLost = (regVal>>25)&0x01; // HW_GET_FIELD(regVal, MCAN_RXF0S_RF0L); } void ReadCANMsgRam(void){ uint32_t startAddr = 0U, elemSize = 0U, elemAddr = 0U; uint32_t idx = 0U; uint32_t regVal, loopCnt; startAddr = CANFD0->MCANSS.MCAN.MCAN_RXF0C&0xFFFC; // F0SA bits 15-2 elemSize = CANFD0->MCANSS.MCAN.MCAN_RXESC&0x07; // F0DS bits 2-0 idx = (CANFD0->MCANSS.MCAN.MCAN_RXF0S>>8)&0x3F; // F0GI, get index is bits 13-0 elemSize = objSize4[elemSize]; elemSize *= 4U; elemAddr = startAddr + (elemSize * idx); // ReadCANMsgRamRaw(elemAddr); regVal = READ_REG32_RAW(((uint32_t) CANFD0 + (uint32_t) elemAddr)); // ID is stored in ID[28:18] CANFIFO[CANPutI].id = (regVal&0x1FFFFFFF) >> 18; #if CAN_DEBUG rxMsg4.id = regVal&0x1FFFFFFF; // 28:0, 29-bit id, 28:18 have standard id rxMsg4.rtr = (regVal>>29)&0x01; // RTR bit 29 (should be 0) rxMsg4.xtd = (regVal>>30)&0x01; // XTD bit 30 (should be 0) rxMsg4.esi = (regVal>>31)&0x01; // ESI bit 31 (should be 0) #endif elemAddr += 4U; regVal = READ_REG32_RAW(((uint32_t) CANFD0 + (uint32_t) elemAddr)); CANFIFO[CANPutI].dlc = (regVal>>16)&0x0F; // DLC data length, bits 19:16 #if CAN_DEBUG rxMsg4.rxts = (regVal>>0)&0x0FF; // RXTS time stamp, bits 15:0 rxMsg4.dlc = (regVal>>16)&0x0F; // DLC data length, bits 19:16 rxMsg4.brs = (regVal>>20)&0x01; // BRS, baud rate shift, bit 20 rxMsg4.fdf = (regVal>>21)&0x01; // FDF, FD format, bit 21, should be 1, CAN FD frame format rxMsg4.fidx = (regVal>>24)&0x7F; // FIDX filter index, bits 30:24 rxMsg4.anmf = (regVal>>31)&0x01; // ANMF bit 31, 0 means matching filter FIDX, 1 means no matching #endif elemAddr += 4U; // first four, only DLC bytes are valid regVal = READ_REG32_RAW(((uint32_t) CANFD0 + (uint32_t) elemAddr)); CANFIFO[CANPutI].data[0] = (uint8_t)(regVal & 0x000000FFU); CANFIFO[CANPutI].data[1] = (uint8_t)((regVal & 0x0000FF00U) >> 8U); CANFIFO[CANPutI].data[2] = (uint8_t)((regVal & 0x00FF0000U) >> 16U); CANFIFO[CANPutI].data[3] = (uint8_t)((regVal & 0xFF000000U) >> 24U); elemAddr += 4U; // second four, only DLC bytes are valid regVal = READ_REG32_RAW(((uint32_t) CANFD0 + (uint32_t) elemAddr)); CANFIFO[CANPutI].data[4] = (uint8_t)(regVal & 0x000000FFU); CANFIFO[CANPutI].data[5] = (uint8_t)((regVal & 0x0000FF00U) >> 8U); CANFIFO[CANPutI].data[6] = (uint8_t)((regVal & 0x00FF0000U) >> 16U); CANFIFO[CANPutI].data[7] = (uint8_t)((regVal & 0xFF000000U) >> 24U); #if CAN_DEBUG for(int i=0; iMCANSS.MCAN.MCAN_RXF0A = rxFS.getIdx; // ack the fifo CanInterruptLine1Status &= ~0x01; //(MCAN_IR_RF0N_MASK); return true; } else{ return false; } } void CANFD0_IRQHandler(void){ bool processFlag; uint16_t count; uint32_t dlc; // IIDX = interrupt index status // 00h = No interrupt pending. // 1h = MCAN Interrupt Line 0 interrupt pending. // 2h = MCAN Interrupt Line 1 interrupt pending. // 3h = Message RAM SEC (Single Error Correction) interrupt pending. // 4h = Message RAM DED (Double Error Detection) interrupt pending. // 5h = External Timestamp Counter Overflow interrupt pending. // 6h = Clock Stop Wake Up interrupt pending. switch (CANFD0->MCANSS.TI_WRAPPER.MSP.CPU_INT.IIDX){ case 2: // DL_MCAN_IIDX_LINE1: // Check MCAN interrupts fired during TX/RX of CAN package CanInterruptLine1Status |= CANFD0->MCANSS.MCAN.MCAN_IR; // should have bit 0, RF0N new message in RxFifo0 CANFD0->MCANSS.MCAN.MCAN_IR = CanInterruptLine1Status; //intrmask=1, MCAN_IR CANFD0->MCANSS.TI_WRAPPER.PROCESSORS.MCANSS_REGS.MCANSS_EOI = 2; // eoi=2, line 1 cleared processFlag = readCANRxMsg(); if(processFlag == true){ GPIOA->DOUTTGL31_0 = 1; OS_Signal(&CanDataAvailable); } break; default: break; } } // Returns true if receive data is available // false if no receive data ready int CAN_CheckMail(void){ return (CANGetI != CANPutI); } // if receive data is ready, gets the data and returns true // if no receive data is ready, returns false int CAN_GetMailNonBlock(uint32_t *id, uint32_t *dlc, uint8_t *data){ if(CANGetI != CANPutI){ *id = CANFIFO[CANGetI].id; *dlc = CANFIFO[CANGetI].dlc; for(int i=0; i<*dlc; i++){ data[i] = CANFIFO[CANGetI].data[i]; } CANGetI = (CANGetI+1)&(CANFIFOSIZE-1); return 1; } return 0; } // if receive data is ready, gets the data // if no receive data is ready, it waits until it is ready void CAN_GetMail(uint32_t *id, uint32_t *dlc, uint8_t *data){ OS_Wait(&CanDataAvailable); // Use semaphore instead of spinning //while(CANGetI == CANPutI){}; *id = CANFIFO[CANGetI].id; *dlc = CANFIFO[CANGetI].dlc; for(int i=0; i<*dlc; i++){ data[i] = CANFIFO[CANGetI].data[i]; } CANGetI = (CANGetI+1)&(CANFIFOSIZE-1); } // 0 if failure // 1 if ok int CAN_SendMessage(uint32_t id, CanMessage_t* command){ int status = CAN_Send(id, 8, (uint8_t*)command); // returns 1 if OK if (status == 1){ return 1; } return 0; } void CAN_ReadMessage(CanMessage_t* message){ uint32_t id, dlc; CAN_GetMail(&id, &dlc, (uint8_t*)message); } int CAN_SetMotors(uint16_t Duty_L, uint16_t Duty_R, int16_t SteeringAngle){ CanMessage_t motorCommand; motorCommand.MessageType = CMD_MOTOR; motorCommand.Field1 = Duty_L; motorCommand.Field2 = Duty_R; motorCommand.Field3 = (uint16_t)SteeringAngle; return CAN_SendMessage(0, &motorCommand); } int CAN_SendOSData(uint16_t jitter){ CanMessage_t OsData; OsData.MessageType = DATA_STATS; OsData.Field1 = jitter; return CAN_SendMessage(0, &OsData); } int CAN_TellCrashed(int16_t steeringAngle){ CanMessage_t CrashEvent; CrashEvent.MessageType = CMD_CRASH; CrashEvent.Field1 = steeringAngle; return CAN_SendMessage(0, &CrashEvent); }