I'm trying to write a bare metal driver for the STM32F302 on a Nucleo-64 board. I'm having trouble getting past the very first steps and getting the hardware to set the Initialization Acknowledgment. This driver is being written to run side by side with the mbed OS framework if that detail is important, I had issues whereby the firmware would go to an error state if I called the CAN constructor they provide (admittedly the board isn't technically supported under mbed OS 5, but I've been told by an engineer with ST that this is due to the amount of static RAM).
Here's the snippets of code that are relevant:
void can_initialize(unsigned int frequency)
{
// Setup the CAN registers
RCC->APB1ENR &= ~RCC_APB1ENR_USBEN;
RCC->APB1ENR |= RCC_APB1ENR_CANEN;
MY_CAN_PORT->MCR |= CAN_MCR_RESET;
// Set to init mode
can_setMode(CAN_MODE::INIT);
// Enable transmit and receive
MY_CAN_PORT->MSR |= (CAN_MSR_RXM | CAN_MSR_TXM);
// Set the frequency
can_setFrequency(frequency);
}
void can_setMode(CAN_MODE new_mode)
{
switch (new_mode)
{
case CAN_MODE::SLEEP:
MY_CAN_PORT->MCR |= CAN_MCR_SLEEP;
// Wait for acknowledgement from hardware
// SLAK = 1, INAK = 0
while (~(MY_CAN_PORT->MSR & CAN_MSR_SLAK)
|| (MY_CAN_PORT->MSR & CAN_MSR_INAK));
break;
case CAN_MODE::INIT:
MY_CAN_PORT->MCR |= CAN_MCR_INRQ;
if (my_mode == CAN_MODE::SLEEP)
{
MY_CAN_PORT->MCR &= ~CAN_MCR_SLEEP;
}
// Wait for the acknowledgement from hardware
// INAK = 1 indicates initialization mode
while (~(MY_CAN_PORT->MSR & CAN_MSR_INAK));
break;
case CAN_MODE::NORMAL:
// first make sure we aren't in loopback mode
if (MY_CAN_PORT->BTR & CAN_BTR_LBKM)
{
// go to init so we can modify loopback mode
can_setMode(CAN_MODE::INIT);
// clear loopback mode
MY_CAN_PORT->BTR &= ~CAN_BTR_LBKM;
can_setMode(CAN_MODE::NORMAL);
}
MY_CAN_PORT->MCR &= ~(CAN_MCR_INRQ);
// Wait for acknowledgement from hardware
// SLAK = 0, INAK = 0
while ((MY_CAN_PORT->MSR & CAN_MSR_SLAK)
|| (MY_CAN_PORT->MSR & CAN_MSR_INAK));
break;
case CAN_MODE::LOOPBACK:
// go to init so we can modify loopback mode
can_setMode(CAN_MODE::INIT);
// set loopback mode
MY_CAN_PORT->BTR |= CAN_BTR_LBKM;
can_setMode(CAN_MODE::NORMAL);
break;
}
my_mode = new_mode;
}
I'm planning to use the device in Loopback mode for testing so I currently have nothing externally connected. Do I need a two node CAN bus just to put the peripheral in Init mode?
I noted that there's an extremely similar post and I've tried some of the proposed solutions here: CAN Initialization Timeout Error in STM32F4
Things I've Tried in HW:
- I've attempted to connect TX and RX directly, though since it isn't sending anything (I think) that shouldn't be required.
- I've also attempted to tie CANRX to 3V3 in order to emulate the bus being in a recessive state for the 11 bits, but this didn't solve the issue either.
- Tried on a second identical board.
Short of connecting up a second node I'm not sure what to do from here. If there's any tricks to these boards I'm not thinking of or if there are more details required to diagnose the problem let me know!