STM32F3 El hardware CAN no ingresa al modo Inicial

1

Estoy tratando de escribir un controlador de metal desnudo para el STM32F302 en un tablero Nucleo-64. Estoy teniendo problemas para superar los primeros pasos y obtener el hardware para configurar el Reconocimiento de inicialización. Este controlador está escrito para ejecutarse junto con el marco del sistema operativo mbed. Si ese detalle es importante, tuve problemas por los cuales el firmware pasaría a un estado de error si llamara al constructor CAN que proporcionan (es cierto que la placa no tiene soporte técnico). 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;
}

Estoy planeando 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 para poner el periférico en modo Inicial?

Noté que hay una publicación extremadamente similar y probé algunas de las soluciones propuestas aquí: Error de tiempo de espera de inicialización CAN en STM32F4

Cosas que he probado en HW:

  • Intenté conectar TX y RX directamente, aunque como no está enviando nada (creo) no debería ser necesario.
  • También intenté vincular CANRX a 3V3 para emular que el bus se encuentre en un estado recesivo para los 11 bits, pero esto tampoco resolvió el problema.
  • Probado en un segundo tablero idéntico.

A falta de conectar un segundo nodo, no estoy seguro de qué hacer desde aquí. Si hay algún truco en estos tableros en los que no estoy pensando o si hay más detalles necesarios para diagnosticar el problema, ¡hágamelo saber!

    
pregunta Shane Snover

1 respuesta

6

Este código es incorrecto:

while(~(MY_CAN_PORT->MSR & CAN_MSR_INAK));

~ es no el operador lógico NO, pero el operador de complemento a nivel de bits!

Así que esto no significa "mientras init ack no está establecido", sino que significa "while 1". Cuando se establece INAK (máscara binaria 0x00000001 ), se obtiene 0xFFFFFFFE y cuando no se establece, se obtiene 0xFFFFFFFF . Ambos evalúan a verdadero / 1.

¿Seguro que tu depurador debería colgar aquí?

Repáralo utilizando 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, por lo que el lector puede decir que esto es intencionalmente un bucle vacío y que no acaba de volcar el punto y coma al final de la línea. hábito / accidente.

    
respondido por el Lundin

Lea otras preguntas en las etiquetas