Estoy tratando de escribir un controlador completo para el STM32F302 en una placa Nucleo-64. Tengo problemas para superar los primeros pasos y hacer que el hardware configure el Reconocimiento de inicialización. Este controlador se está escribiendo para ejecutarse junto con el marco del sistema operativo mbed si ese detalle es importante, tuve problemas por los cuales el firmware entraría en un estado de error si llamaba al constructor de CAN que proporcionan (es cierto que la placa no es técnicamente compatible bajo mbed OS 5, pero un ingeniero de ST me dijo que esto se debe a la cantidad de RAM estática).
Aquí están los fragmentos de código que son relevantes:
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;
}
Planeo usar el dispositivo en modo Loopback para realizar pruebas, por lo que actualmente no tengo nada conectado externamente. ¿Necesito un bus CAN de dos nodos solo para poner el periférico en modo Init?
Noté que hay una publicación extremadamente similar y probé algunas de las soluciones propuestas aquí: Error de tiempo de espera de inicialización de CAN en STM32F4
Cosas que he probado en HW:
Aparte de conectar un segundo nodo, no estoy seguro de qué hacer desde aquí. Si hay algún truco para estos tableros que no estoy pensando o si se requieren más detalles para diagnosticar el problema, ¡házmelo saber!
Este código está mal:
while(~(MY_CAN_PORT->MSR & CAN_MSR_INAK));
~
no es el operador lógico NOT, sino el operador de complemento bit a bit.
Por lo tanto, esto no significa "mientras que el reconocimiento de inicio no está configurado", sino que significa "mientras 1". Cuando se configura INAK (máscara binaria 0x00000001
), se obtiene 0xFFFFFFFE
y cuando no se configura, se obtiene 0xFFFFFFFF
. Ambos se evalúan como verdadero/1.
¿Seguramente su depurador debería colgar aquí?
Arréglalo usando comparaciones lógicas en su lugar:
while((MY_CAN_PORT->MSR & CAN_MSR_INAK)==0)
;
Tenga en cuenta que la colocación del punto y coma en una línea propia es una buena práctica, de modo que el lector pueda darse cuenta de que se trata de un ciclo vacío intencionalmente y que no se descargó el punto y coma al final de la línea por hábito/accidente. .
shane snover
Lundin