diff --git a/TCAN4550/ti_can.c b/TCAN4550/ti_can.c new file mode 100644 index 0000000..53bf9e3 --- /dev/null +++ b/TCAN4550/ti_can.c @@ -0,0 +1,399 @@ +/// +/// Author: Daniil Bragin +/// Reference: + +#include "ti_can.h" +#include "ti_can_registers.h" +#include +#include + + +void spi_init() +{ + +/** + * TODO: Implement SPI init +*/ + +} + +uint8_t spiRegisterWrite(uint32_t addr, + uint32_t regValue) +{ + + /** + * + * TODO: Implement SPI write operation based on the host MCU + * + */ + + // + + return 0; +} + +uint32_t spiRegisterRead(uint32_t addr) +{ + uint32_t regValue = 0; + + /** + * + * TODO: Implement SPI read operation based on the host MCU + * + */ + + return regValue; +} + +uint8_t initCAN (const BitTimingParams * bTParams, + const TiMRAMParams * MRAM) +{ + + // TODO: Cover edge cases for values in structs + error reporting + + // spi_init(); + + // Standby Mode Check + uint32_t mode = 0; + + mode = spiRegisterRead(MODE_SEL); + + // Standby Mode Check + if ((mode & 0xC0) != STANDBY_MODE) + { + printf("Device not in STANDBY_MODE, MODE: %lu, setting STANDBY_MODE\n", mode & 0xC0); + + mode &= ~CLEAN_MODE; + mode |= STANDBY_MODE; + + spiRegisterWrite(MODE_SEL, mode); + printf("STANDBY_MODE set successfully\n"); + + mode = spiRegisterRead(MODE_SEL); + printf("New device mode: %lX, NEEDED: %X\n", mode & 0xC0, STANDBY_MODE); + } + else + { + printf("Device in STANDBY_MODE, mode: %lX\n", mode); + } + + // Initialization Mode + // TODO: Check whether CSR needs to be written before CCE and INIT + + uint32_t init = spiRegisterRead(CCCR); + + printf("Initial CCCR content: %lX\n", init); + + init &= ~(CAN_CCCR_CCE | CAN_CCCR_INIT); + init |= (CAN_CCCR_CCE | CAN_CCCR_INIT); + init &= ~CAN_CCCR_CSR; + + + uint32_t bit_timing = 0; + uint32_t trans_delay_comp = 0; + + uint8_t prescaler = bTParams -> prescaler; + uint8_t prop_and_phase1 = bTParams -> prop_and_phase1; + uint8_t phase2 = bTParams -> phase2; + uint8_t sync_jump_width = bTParams -> sync_jump_width; + uint8_t tdc = bTParams -> tdc; + + + // FD/BRS & Bit Timing Init Cofiguration + if (CAN_MODE == 0) + { + printf("Device in CAN mode\n"); + spiRegisterWrite(CCCR, init); + + bit_timing = spiRegisterRead(NBTP); + + printf("Initial NBTP content: %lu\n", bit_timing); + + // Reset the NBTP register values + bit_timing &= ~(CAN_NBTP_NSJW_MASK | + CAN_NBTP_NTSEG1_MASK | + CAN_NBTP_NTSEG2_MASK | + CAN_NBTP_NBRP_MASK); + + // Set the NBTP register values based on the provided settings + bit_timing |= CAN_SYNC_JUMP_WIDTH(sync_jump_width); + bit_timing |= CAN_TIME_SEG_1(prop_and_phase1); + bit_timing |= CAN_TIME_SEG_2(phase2); + bit_timing |= CAN_PRESCALER(prescaler); + + printf("Intended NBTP value: %lX\n", bit_timing); + + spiRegisterWrite(NBTP, bit_timing); + + } + else if (CAN_MODE == 1) + { + // Check BRS and FD settings + if (BIT_RATE_SWITCH) init |= CCCR_BRSE; + if (FD) init |= CCCR_FDOE; + + spiRegisterWrite(CCCR, init); + + bit_timing = spiRegisterRead(DBTP); + trans_delay_comp = spiRegisterRead(TDCR); + + // Reset the DBTP register values + bit_timing &= ~(CANFD_DBTP_DSJW_MASK | + CANFD_DBTP_DTSEG1_MASK | + CANFD_DBTP_DTSEG2_MASK | + CANFD_DBTP_DBRP_MASK); + + trans_delay_comp &= ~CANFD_TDCR_TDCO_MASK; + + // Set the DBTP register values based on the provided settings + bit_timing |= CANFD_SYNC_JUMP_WIDTH(sync_jump_width); + bit_timing |= CANFD_TIME_SEG_1_WIDTH(prop_and_phase1); + bit_timing |= CANFD_TIME_SEG_2_WIDTH(phase2); + bit_timing |= CANFD_PRESCALER(prescaler); + + trans_delay_comp |= CANFD_DELAY_COMPENSATION_OFFSET(tdc); + + spiRegisterWrite(DBTP, bit_timing); + + spiRegisterWrite(TDCR, trans_delay_comp); + } + + // Zero out MRAM + + spiRegisterWrite(SIDFC, 0x0); + spiRegisterWrite(XIDFC, 0x0); + spiRegisterWrite(RXF0C, 0x0); + spiRegisterWrite(RXF1C, 0x0); + spiRegisterWrite(RXBC, 0x0); + spiRegisterWrite(RXESC, 0x0); + spiRegisterWrite(TXEFC, 0x0); + spiRegisterWrite(TXBC, 0x0); + spiRegisterWrite(TXESC, 0x0); + + // MRAM Init + + uint32_t sid = spiRegisterRead(SIDFC); + uint32_t xid = spiRegisterRead(XIDFC); + uint32_t rxf0 = spiRegisterRead(RXF0C); + uint32_t rxf1 = spiRegisterRead(RXF1C); + uint32_t rxb = spiRegisterRead(RXBC); + uint32_t rx = spiRegisterRead(RXESC); + uint32_t tx_fifo = spiRegisterRead(TXEFC); + uint32_t txb = spiRegisterRead(TXBC); + uint32_t tx = spiRegisterRead(TXESC); + + sid &= ~(SID_LSS_MASK | + SID_FLSS_MASK); + + sid |= SID_LSS(MRAM -> SID_LSS); + sid |= SID_FLSS(MRAM -> SID_FLSS); + + + xid &= ~(XID_LSE_MASK | + XID_FLSEA_MASK); + + xid |= XID_LSE(MRAM -> XID_LSE); + xid |= XID_FLSEA(MRAM -> XID_FLSEA); + + + rxf0 &= ~(RXF0_F0OM_MASK | + RXF0_F0WM_MASK | + RXF0_F0S_MASK | + RXF0_F0SA_MASK); + + rxf0 |= RXF0_F0OM(MRAM -> RXF0_F0OM); + rxf0 |= RXF0_F0WM(MRAM -> RXF0_F0WM); + rxf0 |= RXF0_F0S(MRAM -> RXF0_F0S); + rxf0 |= RXF0_F0SA(MRAM -> RXF0_F0SA); + + + rxf1 &= ~(RXF1_F1OM_MASK | + RXF1_F1WM_MASK | + RXF1_F1S_MASK | + RXF1_F1SA_MASK); + + rxf1 |= RXF1_F1OM(MRAM -> RXF1_F1OM); + rxf1 |= RXF1_F1WM(MRAM -> RXF1_F1WM); + rxf1 |= RXF1_F1S(MRAM -> RXF1_F1S); + rxf1 |= RXF1_F1SA(MRAM -> RXF1_F1SA); + + + rxb &= ~(RXB_RBSA_MASK); + + rxb |= RXB_RBSA(MRAM -> RXB_RBSA); + + + rx &= ~(RX_RBDS_MASK | + RX_F1DS_MASK | + RX_F0DS_MASK); + + rx |= RX_RBDS(MRAM -> RX_RBDS); + rx |= RX_F1DS(MRAM -> RX_F1DS); + rx |= RX_F0DS(MRAM -> RX_F0DS); + + + tx_fifo &= ~(TXEVF_EFWM_MASK | + TXEVF_EFS_MASK | + TXEVF_EFSA_MASK); + + tx_fifo |= TXEVF_EFWM(MRAM -> TXEVF_EFWM); + tx_fifo |= TXEVF_EFS(MRAM -> TXEVF_EFS); + tx_fifo |= TXEVF_EFSA(MRAM -> TXEVF_EFSA); + + + txb &= ~(TXB_TFQM_MASK | + TXB_TFQS_MASK | + TXB_NDTB_MASK | + TXB_TBSA_MASK); + + txb |= TXB_TFQM(MRAM -> TXB_TFQM); + txb |= TXB_TFQS(MRAM -> TXB_TFQS); + txb |= TXB_NDTB(MRAM -> TXB_NDTB); + txb |= TXB_TBSA(MRAM -> TXB_TBSA); + + + tx &= ~(TX_TBDS_MASK); + + tx |= TX_TBDS(MRAM -> TX_TBDS); + + + spiRegisterWrite(SIDFC, sid); + spiRegisterWrite(XIDFC, xid); + spiRegisterWrite(RXF0C, rxf0); + spiRegisterWrite(RXF1C, rxf1); + spiRegisterWrite(RXBC, rxb); + spiRegisterWrite(RXESC, rx); + spiRegisterWrite(TXEFC, tx_fifo); + spiRegisterWrite(TXBC, txb); + spiRegisterWrite(TXESC, tx); + + + uint32_t selected_mode = spiRegisterRead(MODE_SEL); + + printf("Initial device mode: %lX\n", selected_mode); + + selected_mode &= ~CLEAN_MODE; + selected_mode |= NORMAL_MODE; + + printf("Intended mode: %lX\n", selected_mode); + + spiRegisterWrite(MODE_SEL, selected_mode); + printf("Device in NORMAL_MODE, init_can successful\n"); + + return 0; +} + +uint8_t setSIDFilters(SID_filter * filters, TiMRAMParams * MRAM) +{ + size_t size = (size_t) MRAM -> SID_LSS; + uint32_t * filter_addr = (uint32_t *)MRAM -> SID_FLSS; + uint32_t filter = 0; + + for (size_t i = 0; i < size; i++) + { + filter = 0; + + filter |= SID_SFT (filters[i].SFT); + filter |= SID_SFEC (filters[i].SFEC); + filter |= SID_SFID1 (filters[i].SFID_1); + filter |= SID_SFID2 (filters[i].SFID_2); + + spiRegisterWrite(filter_addr + i * sizeof(uint32_t), filter); + } + + return 0; +} + +uint8_t setXIDFilters(XID_filter * filters, TiMRAMParams * MRAM) +{ + size_t size = (size_t) MRAM -> XID_LSE; + uint32_t filter_addr = MRAM -> XID_FLSEA; + uint64_t filter = 0; // Two words needed for XID + uint32_t filter_1 = 0; + uint32_t filter_2 = 0; + + for (size_t i = 0; i < size; i++) + { + filter = 0; + filter_1 = 0; + filter_2 = 0; + + filter_1 |= XID_EFID2(filters[i].EFID1); + filter_1 |= XID_EFT(filters[i].EFT); + + filter_2 |= XID_EFID2(filters[i].EFID2); + filter_2 |= XID_EFEC(filters[i].EFEC); + + filter |= (filter_1 | filter_2); + + spiRegisterWrite(filter_addr + i, filter); + } + + return 0; +} + +uint8_t sendCAN(TiMRAMParams * MRAM, TXFIFOElement * TXE) +{ + // Check that any TX Buffer is vacant + uint32_t free_level = spiRegisterRead(TXFQS); + + uint32_t tx_buffer_start_addr = MRAM -> TXB_TBSA; + uint32_t tx_buffer_element_size = MRAM -> TX_TBDS + 8; // Additional 8 bytes of header + + + + if (!(TFFL(free_level))) + { + printf("ERROR: No TX BUffers Available, return 1\n"); + return 1; + } + + uint32_t index = TFQPI(free_level); + + uint32_t memory_offset = tx_buffer_start_addr + (tx_buffer_element_size * index); + + + uint32_t word_0 = 0; + uint32_t word_1 = 0; + uint32_t word_2 = 0; + + if (TXE -> ESI) word_0 |= (1 << ESI_SHFT); + if (TXE -> RTR) word_0 |= (1 << RTR_SHFT); + if (TXE -> XTD) + { + word_0 |= (1 << XTD_SHFT); + word_0 |= ((TXE -> ID) << XID_SHFT); + } + else + { + word_0 |= ((TXE -> ID) << SID_SHFT); + } + + spiRegisterWrite(memory_offset, word_0); + + word_1 |= ((TXE -> MM) << MM_SHFT); + + if (TXE -> EFC) word_1 |= (1 << EFC_SHFT); + if (TXE -> FDF) word_1 |= (1 << FDF_SHFT); + if (TXE -> BRS) word_1 |= (1 << BRS_SHFT); + + word_1 |= ((TXE -> DLC) << DLC_SHFT); + + spiRegisterWrite(memory_offset + sizeof(word_0), word_1); + + word_2 |= ( ((TXE -> data_byte_0) << DB0_SHFT) | + ((TXE -> data_byte_1) << DB1_SHFT) | + ((TXE -> data_byte_2) << DB2_SHFT) | + ((TXE -> data_byte_3) << DB3_SHFT) ); + + spiRegisterWrite(memory_offset + sizeof(word_0) + sizeof(word_1), word_2); + + uint32_t add_request = 0; + + add_request |= (1U << index); + + spiRegisterWrite(TXBUF_AR, add_request); + + return 0; +} + diff --git a/TCAN4550/ti_can.h b/TCAN4550/ti_can.h new file mode 100644 index 0000000..97d332c --- /dev/null +++ b/TCAN4550/ti_can.h @@ -0,0 +1,467 @@ +/// ____ ______ __ __ +/// / __ `____ ___ ____ / ____/_ ______ / /_ ____ / / +/// / / / / __ `/ _ `/ __ `/ / / / / / __ `/ __ `/ __ `/ / +/// / /_/ / /_/ / __/ / / / /___/ /_/ / /_/ / / / / /_/ / / +/// `____/ .___/`___/_/ /_/`____/`__, / .___/_/ /_/`__,_/_/ +/// /_/ /____/_/ +/// +/// A low-level driver with the main purpose of helping new hardware revisions or new designs adopt CAN FD +/// without having to port an existing codebase to a new platform. +/// +/// Author: Daniil Bragin +/// Reference: + + +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/////////////////////////////////////////////////////////////////////////////////////////// + +// TODO: Fix naming convention +// Naming convention: +// CAN_NBTP_NSJW_MASK: +// NBTP is a register +// NSJW is a bit +// CAN means that it is meant for CAN +// MASK is its purpose + +/////////////////////////////////////////////////////////////////////////////////////////// + +/// BIT TIMING VALUES + +// FOR CAN +#define NBTP 0x101C + +#define CAN_NBTP_NSJW_SHFT (25U) +#define CAN_NBTP_NSJW_MASK (0x7FU << CAN_NBTP_NSJW_SHFT) +#define CAN_SYNC_JUMP_WIDTH(x) ((uint32_t)(x) << CAN_NBTP_NSJW_SHFT) + +#define CAN_NBTP_NTSEG1_SHFT (8U) +#define CAN_NBTP_NTSEG1_MASK (0xFFU << CAN_NBTP_NTSEG1_SHFT) +#define CAN_TIME_SEG_1(x) ((uint32_t)(x) << CAN_NBTP_NTSEG1_SHFT) + +#define CAN_NBTP_NTSEG2_SHFT (0U) +#define CAN_NBTP_NTSEG2_MASK (0x7FU << CAN_NBTP_NTSEG2_SHFT) +#define CAN_TIME_SEG_2(x) ((uint32_t)(x) << CAN_NBTP_NTSEG2_SHFT) + +#define CAN_NBTP_NBRP_SHFT (24U) +#define CAN_NBTP_NBRP_MASK (0x1U << CAN_NBTP_NBRP_SHFT) +#define CAN_PRESCALER(x) ((uint32_t)(x) << CAN_NBTP_NBRP_SHFT) + +// FOR CAN-FD +#define DBTP 0x100C +#define TDCR 0x1048 // Transmission Delay Compensation Register + +#define CANFD_DBTP_DSJW_SHFT (0U) +#define CANFD_DBTP_DSJW_MASK (0xFU << CANFD_DBTP_DSJW_SHFT) +#define CANFD_SYNC_JUMP_WIDTH(x) ((uint32_t)(x) << CANFD_DBTP_DSJW_SHFT) + +#define CANFD_DBTP_DTSEG1_SHFT (8U) +#define CANFD_DBTP_DTSEG1_MASK (0x1FU << CANFD_DBTP_DTSEG1_SHFT) +#define CANFD_TIME_SEG_1_WIDTH(x) ((uint32_t)(x) << CANFD_DBTP_DTSEG1_SHFT) + +#define CANFD_DBTP_DTSEG2_SHFT (4U) +#define CANFD_DBTP_DTSEG2_MASK (0xFU << CANFD_DBTP_DTSEG2_SHFT) +#define CANFD_TIME_SEG_2_WIDTH(x) ((uint32_t)(x) << CANFD_DBTP_DTSEG2_SHFT) + +#define CANFD_DBTP_DBRP_SHFT (16U) +#define CANFD_DBTP_DBRP_MASK (0xFU << CANFD_DBTP_DBRP_SHFT) +#define CANFD_PRESCALER(x) ((uint32_t)(x) << CANFD_DBTP_DBRP_SHFT) + +#define CANFD_TDCR_TDCO_SHFT (8U) +#define CANFD_TDCR_TDCO_MASK (0x7FU << CANFD_TDCR_TDCO_SHFT) +#define CANFD_DELAY_COMPENSATION_OFFSET(x) ((uint32_t)(x) << CANFD_TDCR_TDCO_SHFT) + +// Bit Timing Parameters +typedef struct +{ + uint8_t prescaler; + uint8_t prop_and_phase1; + uint8_t phase2; + uint8_t sync_jump_width; + uint8_t tdc; +} BitTimingParams; + +/////////////////////////////////////////////////////////////////////////////////////////// + +/// MESSAGE RAM + +// MRAM Registers' Addresses +#define SIDFC 0x1084 // 11-bit Filter (SID Filter) +#define XIDFC 0x1088 // 29-bit Filter (XID Filter) +#define RXF0C 0x10A0 // Rx FIFO 0 +#define RXF1C 0x10B0 // Rx FIFO 1 +#define RXBC 0x10AC // Rx Buffers +#define RXESC 0x10BC // Rx Element Size Config +#define TXEFC 0x10F0 // Tx Event FIFO +#define TXBC 0x10C0 // Tx Buffers +#define TXESC 0x10C8 // Tx Element Size Config + +// MRAM Params Bits + +// SID +#define SID_LSS_SHFT (16U) +#define SID_LSS_MASK (0xFFU << SID_LSS_SHFT) +#define SID_LSS(x) ((uint32_t)(x) << SID_LSS_SHFT) + +#define SID_FLSS_SHFT (0U) +#define SID_FLSS_MASK (0xFFFFU << SID_LSS_SHFT) +#define SID_FLSS(x) ((uint32_t)(x) << SID_FLSS_SHFT) + + +// XID +#define XID_LSE_SHFT (16U) +#define XID_LSE_MASK (0x7FU << XID_LSE_SHFT) +#define XID_LSE(x) ((uint32_t)(x) << XID_LSE_SHFT) + + +#define XID_FLSEA_SHFT (16U) +#define XID_FLSEA_MASK (0xFFFFU << XID_FLSEA_SHFT) +#define XID_FLSEA(x) ((uint32_t)(x) << XID_FLSEA_SHFT) + + +// Rx FIFO 0 +#define RXF0_F0OM_SHFT (31U) +#define RXF0_F0OM_MASK (0x1U << RXF0_F0OM_SHFT) +#define RXF0_F0OM(x) ((uint32_t)(x) << RXF0_F0OM_SHFT) + +#define RXF0_F0WM_SHFT (24U) +#define RXF0_F0WM_MASK (0x7FU << RXF0_F0WM_SHFT) +#define RXF0_F0WM(x) ((uint32_t)(x) << RXF0_F0WM_SHFT) + +#define RXF0_F0S_SHFT (16U) +#define RXF0_F0S_MASK (0x7FU << RXF0_F0S_SHFT) +#define RXF0_F0S(x) ((uint32_t)(x) << RXF0_F0S_SHFT) + +#define RXF0_F0SA_SHFT (0U) +#define RXF0_F0SA_MASK (0xFFFFU << RXF0_F0SA_SHFT) +#define RXF0_F0SA(x) ((uint32_t)(x) << RXF0_F0SA_SHFT) + + +// Rx FIFO 1 +#define RXF1_F1OM_SHFT (31U) +#define RXF1_F1OM_MASK (0x1U << RXF1_F1OM_SHFT) +#define RXF1_F1OM(x) ((uint32_t)(x) << RXF1_F1OM_SHFT) + +#define RXF1_F1WM_SHFT (24U) +#define RXF1_F1WM_MASK (0x7FU << RXF1_F1WM_SHFT) +#define RXF1_F1WM(x) ((uint32_t)(x) << RXF1_F1WM_SHFT) + +#define RXF1_F1S_SHFT (16U) +#define RXF1_F1S_MASK (0x7FU << RXF1_F1S_SHFT) +#define RXF1_F1S(x) ((uint32_t)(x) << RXF1_F1S_SHFT) + +#define RXF1_F1SA_SHFT (0U) +#define RXF1_F1SA_MASK (0xFFFFU << RXF1_F1SA_SHFT) +#define RXF1_F1SA(x) ((uint32_t)(x) << RXF1_F1SA_SHFT) + + +// Rx Buffer +#define RXB_RBSA_SHFT (0U) +#define RXB_RBSA_MASK (0xFFFFU << RXB_RBSA_SHFT) +#define RXB_RBSA(x) ((uint32_t)(x) << RXB_RBSA_SHFT) + + +// Rx Element Size Config +#define RX_RBDS_SHFT (8U) +#define RX_RBDS_MASK (0x7U << RX_RBDS_SHFT) +#define RX_RBDS(x) ((uint32_t)(x) << RX_RBDS_SHFT) + +#define RX_F1DS_SHFT (4U) +#define RX_F1DS_MASK (0x7U << RX_F1DS_SHFT) +#define RX_F1DS(x) ((uint32_t)(x) << RX_F1DS_SHFT) + +#define RX_F0DS_SHFT (0U) +#define RX_F0DS_MASK (0x7U << RX_F0DS_SHFT) +#define RX_F0DS(x) ((uint32_t)(x) << RX_F0DS_SHFT) + + +// Tx Event FIFO Config +#define TXEVF_EFWM_SHFT (24U) +#define TXEVF_EFWM_MASK (0x3FU << TXEVF_EFWM_SHFT) +#define TXEVF_EFWM(x) ((uint32_t)(x) << TXEVF_EFWM_SHFT) + +#define TXEVF_EFS_SHFT (16U) +#define TXEVF_EFS_MASK (0x3FU << TXEVF_EFS_SHFT) +#define TXEVF_EFS(x) ((uint32_t)(x) << TXEVF_EFS_SHFT) + +#define TXEVF_EFSA_SHFT (0U) +#define TXEVF_EFSA_MASK (0xFFFFU << TXEVF_EFSA_SHFT) +#define TXEVF_EFSA(x) ((uint32_t)(x) << TXEVF_EFSA_SHFT) + + +// Tx Buffer Config +#define TXB_TFQM_SHFT (30U) +#define TXB_TFQM_MASK (0x1U << TXB_TFQM_SHFT) +#define TXB_TFQM(x) ((uint32_t)(x) << TXB_TFQM_SHFT) + +#define TXB_TFQS_SHFT (24U) +#define TXB_TFQS_MASK (0x3FU << TXB_TFQS_SHFT) +#define TXB_TFQS(x) ((uint32_t)(x) << TXB_TFQS_SHFT) + +#define TXB_NDTB_SHFT (16U) +#define TXB_NDTB_MASK (0x3FU << TXB_NDTB_SHFT) +#define TXB_NDTB(x) ((uint32_t)(x) << TXB_NDTB_SHFT) + +#define TXB_TBSA_SHFT (0U) +#define TXB_TBSA_MASK (0xFFFFU << TXB_TBSA_SHFT) +#define TXB_TBSA(x) ((uint32_t)(x) << TXB_TBSA_SHFT) + + +// TX Element Size Config +#define TX_TBDS_SHFT (0U) +#define TX_TBDS_MASK (0x7U << TX_TBDS_SHFT) +#define TX_TBDS(x) ((uint32_t)(x) << TX_TBDS_SHFT) + + + +// Message RAM Design Parameters + +// MDS = Maximum Data Size +// BPE = Bytes Per Element +// NOE = Number Of Elements + +typedef struct +{ + // SID + uint32_t SID_LSS; + uint32_t SID_FLSS; + + // XID + uint32_t XID_LSE; + uint32_t XID_FLSEA; + + // Rx FIFO 0 + uint32_t RXF0_F0OM; + uint32_t RXF0_F0WM; + uint32_t RXF0_F0S; + uint32_t RXF0_F0SA; + + // Rx FIFO 1 + uint32_t RXF1_F1OM; + uint32_t RXF1_F1WM; + uint32_t RXF1_F1S; + uint32_t RXF1_F1SA; + + // Rx Buffer + uint32_t RXB_RBSA; + + // Rx Element Size Config + uint32_t RX_RBDS; + uint32_t RX_F1DS; + uint32_t RX_F0DS; + + // Tx Event FIFO Config + uint32_t TXEVF_EFWM; + uint32_t TXEVF_EFS; + uint32_t TXEVF_EFSA; + + // Tx Buffer Config + uint32_t TXB_TFQM; + uint32_t TXB_TFQS; + uint32_t TXB_NDTB; + uint32_t TXB_TBSA; + + // TX Element Size Config + uint32_t TX_TBDS; + +} TiMRAMParams; + +// Filters Configuration: SID and XID (Standard and Extended) + +typedef struct +{ + // In classic mode: SFID_1 = ID, SFID_2 = MASK + + uint16_t SFID_1; + uint16_t SFID_2; + uint8_t SFT; + uint8_t SFEC; + +} SID_filter; + + +// SID Filter Type +#define SID_SFT_SHFT (30U) +#define SID_SFT(x) ((uint32_t)(x) << SID_SFT_SHFT) + +// Options for the SID & XID filter type +#define RANGE_FILTER 0b00U +#define DUAL_ID_FILTER 0b01U +#define CLASSIC_FILTER 0b10U +#define FILTER_ELEMENT_DISABLED 0b11U + +// Standard Element Filter Configuration +#define SID_SFEC_SHFT (27U) +#define SID_SFEC(x) ((uint32_t)(x) << SID_SFEC_SHFT) + +// Options for the element configuration +#define DISABLE_FILTER_ELEMENT 0b000U +#define STORE_RX_FIFO_0 0b001U +#define STORE_RX_FIFO_1 0b010U +#define REJECT_MESSAGE 0b011U +#define SET_AS_PRIO_MSG_DFLT 0b100U +#define SET_AS_PRIO_FIFO_0 0b101U +#define SET_AS_PRIO_FIFO_1 0b110U + +// Store into Rx Buffer or as debug message. If this is used, SFT is ignored and SFID1 is the filter. SFID2[10:9] +// describes where to store message, SFID2[5:0] describes which Rx Buffer to put the message (must be within +// the Rx Buffer configuration +#define STORE_RX_BUF 0b111U + + +#define SID_SFID1_SHFT (16U) +#define SID_SFID1_MASK (0x7FFU) +#define SID_SFID1(x) (((uint32_t)(x) & SID_SFID1_MASK) << SID_SFID1_SHFT) + +#define SID_SFID2_SHFT (0U) +#define SID_SFID2_MASK (0x7FFU) +#define SID_SFID2(x) (((uint32_t)(x) & SID_SFID2_MASK) << SID_SFID2_SHFT) + + +typedef struct +{ + + uint32_t EFID1; + uint32_t EFID2; + uint8_t EFT; // For type use same options as for SID + uint8_t EFEC; + +} XID_filter; + +// Word 0 + +#define XID_EFEC_SHFT (29U) +#define XID_EFEC(x) ((uint32_t)(x) << XID_EFEC_SHFT) + +#define XID_EFID1_SHFT (0U) +#define XID_EFID1_MASK (0x1FFFFFFF) +#define XID_EFID1(x) (((uint32_t)(x) & XID_EFID1_MASK) << XID_EFID1_SHFT) + +// Word 1 + +#define XID_EFT_SHFT (30U) +#define XID_EFT(x) ((uint32_t)(x) << XID_EFT_SHFT) + +#define XID_EFID2_SHFT (0U) +#define XID_EFID2_MASK (0x1FFFFFFF) +#define XID_EFID2(x) (((uint32_t)(x) & XID_EFID2_MASK) << XID_EFID2_SHFT) + + + + +/////////////////////////////////////////////////////////////////////////////////////////// + +/// Device Initialization Mode + +// Device Mode Selection Register Address +#define MODE_SEL 0x0800 + +// Available Device Modes +#define STANDBY_MODE (0b01 << 6U) +#define NORMAL_MODE (0b10 << 6U) +#define CLEAN_MODE (0b11 << 6U) + +// CC Control Register Address +#define CCCR 0x1018 + +// Bits Necessary For Initialization +#define CAN_CCCR_INIT (1U << 0U) +#define CAN_CCCR_CCE (1U << 1U) +#define CAN_CCCR_CSR (1U << 4U) + +/// 0 - CAN, 1 - CAN FD +#define CAN_MODE 0 + +/// 0 - Bit Rate Switching disabled, 1 - enabled +#define BIT_RATE_SWITCH 1 +#define CCCR_BRSE (1U << 9U) + +/// 0 - Flexible Datarate disabled, 1 - enabled +#define FD 1 +#define CCCR_FDOE (1U << 8U) + +/////////////////////////////////////////////////////////////////////////////////////////// + +/// Message Sending + +#define TXFQS 0x10C4 // Tx FIFO/Queue Status register + +#define TXBUF_AR 0x10D0 // Tx Buffer Add Request Register + +// Set on of the bits in TXBUF_AR to request the +// data to be sent from the corresponding TX Buffer + + +#define TFFL_MASK 0x1FU +#define TFFL(reg) ((reg) & TFFL_MASK) + +#define TFQPI_MAKS 0x1F0000 +#define TFQPI(reg) (((reg) & TFQPI_MAKS) >> 16U) + + +typedef struct +{ + // Word 0 + bool ESI; + bool XTD; + bool RTR; + uint16_t ID; + + // Word 1 + uint8_t MM; + bool EFC; + bool FDF; + bool BRS; + uint8_t DLC; + + // Word 2 + uint8_t data_byte_3; + uint8_t data_byte_2; + uint8_t data_byte_1; + uint8_t data_byte_0; + +} TXFIFOElement; + +#define ESI_SHFT 31U +#define XTD_SHFT 30U +#define RTR_SHFT 29U +#define SID_SHFT 18U +#define XID_SHFT 0U + +#define MM_SHFT 24U +#define EFC_SHFT 23U +#define FDF_SHFT 21U +#define BRS_SHFT 20U +#define DLC_SHFT 16U + +#define DB3_SHFT 24U +#define DB2_SHFT 16U +#define DB1_SHFT 8U +#define DB0_SHFT 0U + +#define WORD 0x4U + +#define SPI_WRITE_OPCODE 0x61 +#define SPI_READ_OPCODE 0x41 + +#define LENGTH_BYTE 0x4 + +#define ENDIAN_REGISTER_TEST 0x1004 + +void spi_init(); +uint8_t spiRegisterWrite(uint16_t reg_addr, uint32_t reg_value, uint32_t * pointer); +uint32_t spiRegisterRead(uint16_t reg_addr); +uint8_t initCAN (const BitTimingParams * bTParams, + const TiMRAMParams * MRAM); +uint8_t setSIDFilters(SID_filter * filters, TiMRAMParams * MRAM); +uint8_t setXIDFilters(XID_filter * filters, TiMRAMParams * MRAM); +uint8_t sendCAN(TiMRAMParams * MRAM, TXFIFOElement * TXE); + diff --git a/TCAN4550/ti_can_registers.h b/TCAN4550/ti_can_registers.h new file mode 100644 index 0000000..407ac4f --- /dev/null +++ b/TCAN4550/ti_can_registers.h @@ -0,0 +1,10 @@ +/// +/// Author: Daniil Bragin +/// + +#pragma once + +#include + + +