ContributionsMost RecentMost LikesSolutionsRe: MCP2515 CANbus implementation in NIOS using alt_avalon_spi_command on 10M50DA Hello Yoda_Altera, Sorry for the delayed response — I was on leave due to some personal work. It turns out that the MCP2515 module I was using was faulty. I purchased a new one, and it’s working correctly now. Also, thank you for pointing out the issue with the read_reg function — I’ve corrected it as per your suggestion. Thanks a lot for your help! and regarding this Utilizing HPS CAN Controller Without DDR i will try later. Best regards, Nitin Re: MCP2515 CANbus implementation in NIOS using alt_avalon_spi_command on 10M50DA Hello Yoda_Altera, I have already tried the write-readback experiment. Here is the code snippet I used: /* Initialization */ int mcp2515_tx_init(void) { DBG("Initializing MCP2515...\n"); /* 1. Software Reset */ uint8_t reset_cmd = MCP_RESET; alt_avalon_spi_command(SPI_BASE, SPI_SLAVE, 1, &reset_cmd, 0, NULL, 0); alt_busy_sleep(5000); // 5ms delay /* 2. Enter Configuration Mode */ write_reg(CANCTRL, 0x80); alt_busy_sleep(100); /* Verify Configuration Mode */ uint8_t mode = read_reg(CANSTAT) & 0xE0; if (mode != 0x80) { DBG("Config Mode Fail: 0x%02X\n", mode); return -1; } /* 3. Set Bit Timing */ write_reg(CNF1, CNF1_VAL); write_reg(CNF2, CNF2_VAL); write_reg(CNF3, CNF3_VAL); DBG("CNF1=0x%02X, CNF2=0x%02X, CNF3=0x%02X\n", read_reg(CNF1), read_reg(CNF2), read_reg(CNF3)); /* 4. Return to Normal Mode */ write_reg(CANCTRL, 0x00); alt_busy_sleep(100); /* Verify Normal Mode */ mode = read_reg(CANSTAT) & 0xE0; if (mode != 0x00) { DBG("Normal Mode Fail: 0x%02X\n", mode); return -1; } return 0; } Currently, the read operation is failing every time after entering configuration mode and also in normal mode. When I try to verify what I have written, it is not matching — even the timing registers CNF1, CNF2, and CNF3 are reading back as 0xFF. Below are the write and read functions I created: /* SPI Command Helper Functions */ static void write_reg(uint8_t addr, uint8_t value) { uint8_t tx_buf[3] = {MCP_WRITE, addr, value}; alt_avalon_spi_command(SPI_BASE, SPI_SLAVE, 3, tx_buf, 0, NULL, 0); } static uint8_t read_reg(uint8_t addr) { uint8_t tx_buf[3] = {MCP_READ, addr, 0xFF}; uint8_t rx_buf[3] = {0}; alt_avalon_spi_command(SPI_BASE, SPI_SLAVE, 3, tx_buf, 3, rx_buf, ALT_AVALON_SPI_COMMAND_MERGE); return rx_buf[2]; } Could you kindly verify if my write and read operations are correct? Regarding my previous doubts: 1. Manual Chip Select Control I want to know if I can use this Macro for chip select: IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(SPI_BASE, SPI_SLAVE_SEL); This is how I used it: /* SPI Transfer with Manual Control */ static void spi_transfer(uint8_t *tx, uint8_t *rx, uint32_t len) { IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(SPI_BASE, SPI_SLAVE_SEL); for (uint32_t i = 0; i < len; i++) { /* Wait for TX Ready */ while (!(IORD_ALTERA_AVALON_SPI_STATUS(SPI_BASE) & ALTERA_AVALON_SPI_STATUS_TRDY_MSK)); /* Send Data */ IOWR_ALTERA_AVALON_SPI_TXDATA(SPI_BASE, tx ? tx[i] : 0xFF); /* Wait for RX Ready */ while (!(IORD_ALTERA_AVALON_SPI_STATUS(SPI_BASE) & ALTERA_AVALON_SPI_STATUS_RRDY_MSK)); /* Capture Received Data (if rx buffer provided) */ if (rx) rx[i] = IORD_ALTERA_AVALON_SPI_RXDATA(SPI_BASE); else (void)IORD_ALTERA_AVALON_SPI_RXDATA(SPI_BASE); /* dummy read */ } /* Wait for Transmission Complete */ while (!(IORD_ALTERA_AVALON_SPI_STATUS(SPI_BASE) & ALTERA_AVALON_SPI_STATUS_TMT_MSK)); IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(SPI_BASE, 0x00); } However, I observed that the chip select is toggling between every 8 bits. To verify logically, I removed the chip select control from the SPI driver and instead controlled it manually using a PIO-based GPIO macro( this line IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(SPI_BASE, SPI_SLAVE_SEL); and the end line where i am writing 0x00 to spi_slave_sel i replaced these two lines with PIO_MACRO) — pulling CS low at the start and high at the end. In that case, the chip select stays low for the entire transaction verified in Logic analyzer but still issue is their. Could you please clarify why this behavior is happening? 2. Utilizing HPS CAN Controller Without DDR Could you also suggest a general procedure to use the HPS CAN controller with a bare-metal program ? i am not asking how to use it with mcp2515 i am seeking help only how to initialize only CAN contorller of HPS by using baremetal program and from internal RAM of HPS?? Thank you very much for your support! Looking forward to your suggestions and corrections. Best regards, Nitin Dogra Re: MCP2515 CANbus implementation in NIOS using alt_avalon_spi_command on 10M50DA Hello Sir, Thank you for your prompt response. This is the timing diagram from my logic analyzer, which confirms that the chip select (CS) line remains low throughout the entire SPI transaction. Each command, address, and data byte is transmitted in 8-bit segments. There's an observed delay of approximately 11.8 µs between bytes, which, according to various sources, is within normal expectations. The SPI clock operates continuously during each 8-bit transfer, and the CS line stays low for the full duration of the transaction, encompassing command, address, and data phases. In my Qsys design, the SPI clock was initially set to 10 MHz but now it is 1 MHz : MCP2515's maximum supported frequency is 10 MHz. Additionally, SPI mode 0,0 has been selected, as supported by the MCP2515. I have two specific concerns: 1. Chip Select Behavior: Initially, I used the macro: IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(SPI_BASE, SPI_SLAVE_SEL); However, this caused the chip select line to toggle every 8 bits. To address this, I switched to using the alt_avalon_spi_command function, which maintains the chip select line low throughout the entire transaction, ensuring proper communication with the MCP2515. 2. Utilizing HPS CAN Controller Without DDR: Our custom Cyclone V SoC board lacks DDR memory, preventing the use of a full-fledged embedded Linux system. I'm considering leveraging the HPS-side CAN controller by writing a bare-metal program that operates from the internal SRAM (approximately 64 KB). Is this approach feasible given the memory constraints? If so, could you provide any sample programs or guidance on implementing this? Now for mcp2515, I believe the software setup is correct, but to rule out hardware issues, I've ordered additional MCP2515. Any insights or sample code you can share would be immensely helpful. Thank you mcp2515 SPI-CAN interfacing Hello, I'm currently working on interfacing the MCP2515 CAN controller with a Nios II processor via SPI. While I can observe SPI transactions on a logic analyzer, I'm not receiving any responses from the MCP2515. Has anyone successfully interfaced the MCP2515 with a Nios II processor? If so, could you share insights or code snippets that might help identify what might be going wrong in my setup? Any guidance or suggestions would be greatly appreciated. Thank you! this is my code : /* Bit Timing for 8MHz crystal @1Mbps */ #define CNF1_VAL 0x03 // BRP=3 (TQ=1µs) #define CNF2_VAL 0x90 // PHSEG1=3, PRSEG=1 #define CNF3_VAL 0x02 // PHSEG2=3 /* SPI Command Helper Functions */ static void write_reg(uint8_t addr, uint8_t value) { uint8_t tx_buf[3] = {MCP_WRITE, addr, value}; alt_avalon_spi_command(SPI_BASE, SPI_SLAVE, 3, tx_buf, 0, NULL, 0); } static uint8_t read_reg(uint8_t addr) { uint8_t tx_buf[3] = {MCP_READ, addr, 0xFF}; uint8_t rx_buf[3] = {0}; alt_avalon_spi_command(SPI_BASE, SPI_SLAVE, 3, tx_buf, 3, rx_buf, ALT_AVALON_SPI_COMMAND_MERGE); return rx_buf[2]; } /* Initialization */ int mcp2515_tx_init(void) { DBG("Initializing MCP2515...\n"); /* 1. Software Reset */ uint8_t reset_cmd = MCP_RESET; alt_avalon_spi_command(SPI_BASE, SPI_SLAVE, 1, &reset_cmd, 0, NULL, 0); alt_busy_sleep(15000); // 5ms delay /* 2. Enter Configuration Mode */ write_reg(CANCTRL, 0x80); alt_busy_sleep(100); /* Verify Configuration Mode */ uint8_t mode = read_reg(CANSTAT) & 0xE0; if(mode != 0x80) { DBG("Config Mode Fail: 0x%02X\n", mode); return -1; } /* Configure TXRTSCTRL (disable RTS functionality) */ write_reg(0x0D, 0x00); // TXRTSCTRL = 0 (digital inputs) /* 3. Set Bit Timing */ write_reg(CNF1, CNF1_VAL); write_reg(CNF2, CNF2_VAL); write_reg(CNF3, CNF3_VAL); DBG("CNF1=0x%02X, CNF2=0x%02X, CNF3=0x%02X\n", read_reg(CNF1), read_reg(CNF2), read_reg(CNF3)); /* 4. Return to Normal Mode */ write_reg(CANCTRL, 0x00); alt_busy_sleep(100); /* Verify Normal Mode */ mode = read_reg(CANSTAT) & 0xE0; if(mode != 0x00) { DBG("Normal Mode Fail: 0x%02X\n", mode); return -1; } DBG("MCP2515 Ready\n"); return 0; } /* CAN Frame Transmission */ static void transmit_frame(uint16_t can_id, uint8_t *data, uint8_t dlc) { /* Check if TXREQ is clear (buffer is free) */ uint8_t txb0ctrl = read_reg(0x30); // Read TXB0CTRL if (txb0ctrl & 0x08) { // TXREQ bit is set DBG("TXB0 busy! Aborting...\n"); return; } uint8_t tx_buffer[13] = { MCP_WRITE, 0x31, // Start at TXB0SIDH (uint8_t)(can_id >> 3), // SIDH (uint8_t)((can_id & 0x07) << 5), // SIDL 0x00, // EID8 0x00, // EID0 (dlc & 0x0F), // DLC // Data starts at TXB0D0 (0x36) 0x36 // TXB0D0 address (auto-increment) }; memcpy(&tx_buffer[7], data, dlc); // Copy data bytes // Single transaction for header + data alt_avalon_spi_command(SPI_BASE, SPI_SLAVE, 7 + dlc, tx_buffer, 0, NULL, 0); // Trigger transmission uint8_t txreq_cmd[] = {MCP_WRITE, 0x30, 0x08}; // Set TXREQ alt_avalon_spi_command(SPI_BASE, SPI_SLAVE, 3, txreq_cmd, 0, NULL, 0); } /* Continuous Transmission */ void mcp2515_continuous_tx(void) { uint8_t data[8] = {0x69}; // Test data DBG("Starting CAN Transmission\n"); while(1) { transmit_frame(0x100, data, 1); alt_busy_sleep(10000); // 10ms delay } } int main(void) { if(mcp2515_tx_init() != 0) return -1; mcp2515_continuous_tx(); return 0; } Re: MCP2515 CANbus implementation in NIOS using alt_avalon_spi_command on 10M50DA Hello, I'm currently working on interfacing the MCP2515 CAN controller with a Nios II processor via SPI. While I can observe SPI transactions on a logic analyzer, I'm not receiving any responses from the MCP2515. Has anyone successfully interfaced the MCP2515 with a Nios II processor? If so, could you share insights or code snippets that might help identify what might be going wrong in my setup? Any guidance or suggestions would be greatly appreciated. Thank you!