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:
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?
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