CAN bus acknowledgment error

ccanstm32stm32f4

I am using an STM32F429 CAN bus program with TJA1041A as the CAN transceiver. The problem is that the messages are not getting acknowledged, and herewith I am attaching the code for further reference. I am using PCAN-View to see the messages. Are there any faults in this code?

int main(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2, ENABLE);

    // SystemInit();

    GPIO_InitTypeDef GPIO_InitDef;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    GPIO_InitDef.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13;
    GPIO_InitDef.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
    GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_Init(GPIOB, &GPIO_InitDef);

    /* Connect CAN pins to AF */
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_CAN2); // CAN2_RX
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_CAN2); // CAN2_TX

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

    GPIO_InitDef.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
    GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
    GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;

    /* Connect PD5 and PD7 pins for CAN transceiver to enable and
       standby. */

    GPIO_Init(GPIOD, &GPIO_InitDef);
    GPIO_SetBits(GPIOD, GPIO_Pin_5|GPIO_Pin_7);

    RCC_ClocksTypeDef     RCC_Clocks;
    CAN_InitTypeDef       CAN_InitStructure;
    CAN_FilterInitTypeDef CAN_FilterInitStructure;

    RCC_GetClocksFreq(&RCC_Clocks);

    CAN_DeInit(CAN2);

    CAN_StructInit(&CAN_InitStructure);

    /* CAN cell init */
    CAN_InitStructure.CAN_TTCM = DISABLE;
    CAN_InitStructure.CAN_ABOM = DISABLE;
    CAN_InitStructure.CAN_AWUM = DISABLE;
    CAN_InitStructure.CAN_NART = DISABLE;
    CAN_InitStructure.CAN_RFLM = DISABLE;
    CAN_InitStructure.CAN_TXFP = DISABLE;
    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal ;

    /* Quanta 1+14+6 = 21, 21 * 4 = 84, 42000000 / 84 = 5000000 */
    /* CAN Baudrate = 500 kbit/s (CAN clocked at 42 MHz). Prescale = 4 */

    /* Requires a clock with integer division into APB clock */

    CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; // 1 + 6 + 7  = 14,  1 + 14 + 6 = 21,
                                             // 1 + 15 + 5 = 21
    CAN_InitStructure.CAN_BS1 = CAN_BS1_14tq;
    CAN_InitStructure.CAN_BS2 = CAN_BS2_6tq;
    CAN_InitStructure.CAN_Prescaler = 4; // Quanta by Baudrate - 125 kbit/s.

    CAN_Init(CAN2, &CAN_InitStructure);

    /* CAN filter init */
    CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; // IdMask or IdList

    CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_16bit; // 16 or 32

    CAN_FilterInitStructure.CAN_FilterIdHigh      = 0x0000; // Everything, otherwise 11-bit in top bits

    CAN_FilterInitStructure.CAN_FilterIdLow       = 0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0x0000;

    CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0; // Rx
    CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;

    //CAN_FilterInitStructure.CAN_FilterNumber = 0; // CAN1 [ 0..13]

    //CAN_FilterInit(&CAN_FilterInitStructure);

    CAN_FilterInitStructure.CAN_FilterNumber = 14; // CAN2 [14..27]

    CAN_FilterInit(&CAN_FilterInitStructure);
    CAN_ITConfig(CAN2, CAN_IT_FMP0, ENABLE);

    CanTxMsg TxMessage;

    // Transmit */
    TxMessage.StdId = 0x321;
    TxMessage.ExtId = 0x00;
    TxMessage.RTR = CAN_RTR_DATA;
    TxMessage.IDE = CAN_ID_STD;
    TxMessage.DLC = 8;

    TxMessage.Data[0] = 0x02;
    TxMessage.Data[1] = 0x11;
    TxMessage.Data[2] = 0x11;
    TxMessage.Data[3] = 0x11;

    while(1)
    {
        uint32_t i;
        int j = 0;
        uint8_t TransmitMailbox = 0;

        TxMessage.Data[4] = (j >>  0) & 0xFF; // Cycling
        TxMessage.Data[5] = (j >>  8) & 0xFF;
        TxMessage.Data[6] = (j >> 16) & 0xFF;
        TxMessage.Data[7] = (j >> 24) & 0xFF;
        j++;

        TransmitMailbox = CAN_Transmit(CAN2, &TxMessage);

        i = 0;
        while (  (CAN_TransmitStatus(CAN2, TransmitMailbox) != CANTXOK) &&
                 (i != 0xFFFF)
              ) // Wait on transmit
        {
            i++;
            CAN2RX(); // Pump RX
        }
    }
}

Best Answer

If your code is sending a message at all, you should get ACK. Put a scope on the lines and see if the problem is you're not sending, or a electrical problem that prevents the right signal levels.

The two usual mistakes people make to get no ACK is they forget to connect at least one other device to the bus and they forget to put the terminating resistors on the bus. If you want another device to send ACK, there has to be another device. Despite this being blatantly obvious, it is a suprisingly common brain fart according to my observations.

As for the terminators, they are not optional. Yes, they function to reduce reflections from the ends of the bus, and in that sense you could debug a short bus wihtout them. However, they also pull the bus lines together so that the bus is in the recessive state when nothing is actively driving it. This is not optional. This is a lot like the pull-up resistor on a open-collector bus is not optional. The terminators are pull-together resistors instead of pull-up, but can't be omitted for the same reason.