0

I'm using an STM32F469 Discovery board and I'm trying to use the CAN features.

I understand that on this board CAN1 cannot be used at the same time as the touchscreen. Therefore I need to use CAN2, but in order to enable CAN2, CAN1 needs to be enabled.

My code for configuration/callback is as follows:

/* CAN1 Values */
#define CAN1_CLK_ENABLE()         __HAL_RCC_CAN1_CLK_ENABLE()
#define CAN1_GPIO_CLK_ENABLE()    __HAL_RCC_GPIOB_CLK_ENABLE()
#define CAN1_FORCE_RESET()        __HAL_RCC_CAN1_FORCE_RESET()
#define CAN1_RELEASE_RESET()      __HAL_RCC_CAN1_RELEASE_RESET()
#define CAN1_TX_PIN              GPIO_PIN_9
#define CAN1_TX_GPIO_PORT        GPIOB
#define CAN1_TX_AF               GPIO_AF9_CAN1
#define CAN1_RX_PIN              GPIO_PIN_8
#define CAN1_RX_GPIO_PORT        GPIOB
#define CAN1_RX_AF               GPIO_AF9_CAN1
#define CAN1_RX_IRQn             CAN1_RX0_IRQn
#define CAN1_RX_IRQHandler       CAN1_RX0_IRQHandler

/* CAN2 Values */
#define CAN2_CLK_ENABLE()         __HAL_RCC_CAN2_CLK_ENABLE()
#define CAN2_GPIO_CLK_ENABLE()    __HAL_RCC_GPIOB_CLK_ENABLE()
#define CAN2_FORCE_RESET()        __HAL_RCC_CAN2_FORCE_RESET()
#define CAN2_RELEASE_RESET()      __HAL_RCC_CAN2_RELEASE_RESET()
#define CAN2_TX_PIN              GPIO_PIN_13
#define CAN2_TX_GPIO_PORT        GPIOB
#define CAN2_TX_AF               GPIO_AF9_CAN2
#define CAN2_RX_PIN              GPIO_PIN_5
#define CAN2_RX_GPIO_PORT        GPIOB
#define CAN2_RX_AF               GPIO_AF9_CAN2
#define CAN2_RX_IRQn             CAN2_RX0_IRQn
#define CAN2_RX_IRQHandler       CAN2_RX0_IRQHandler

CAN_HandleTypeDef CanHandle1;
CAN_HandleTypeDef CanHandle2;

static uint8_t Message_Data[8];

static void CAN1_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    CAN_FilterConfTypeDef CAN_FilterInitStructure;

    static CanTxMsgTypeDef TxMessage;
    static CanRxMsgTypeDef RxMessage;

    /* CAN1 peripheral clock enable */
    CAN1_CLK_ENABLE();
    CAN1_GPIO_CLK_ENABLE();

    /* CAN1 TX GPIO pin configuration */
    GPIO_InitStruct.Pin = CAN1_TX_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Alternate =  CAN1_TX_AF;

    HAL_GPIO_Init(CAN1_TX_GPIO_PORT, &GPIO_InitStruct);

    /* CAN1 RX GPIO pin configuration */
    GPIO_InitStruct.Pin = CAN1_RX_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Alternate =  CAN1_RX_AF;

    HAL_GPIO_Init(CAN1_RX_GPIO_PORT, &GPIO_InitStruct);

    /* NVIC configuration for CAN1 reception complete interrupt */
    HAL_NVIC_SetPriority(CAN1_RX_IRQn, 1, 0);
    HAL_NVIC_EnableIRQ(CAN1_RX_IRQn);

    CanHandle1.Instance = CAN1;
    CanHandle1.pTxMsg = &TxMessage;
    CanHandle1.pRxMsg = &RxMessage;

    /* CAN peripheral init */
    CanHandle1.Init.TTCM = DISABLE;
    CanHandle1.Init.ABOM = DISABLE;
    CanHandle1.Init.AWUM = DISABLE;
    CanHandle1.Init.NART = DISABLE;
    CanHandle1.Init.RFLM = DISABLE;
    CanHandle1.Init.TXFP = DISABLE;
    CanHandle1.Init.Mode = CAN_MODE_LOOPBACK;
    CanHandle1.Init.SJW = CAN_SJW_1TQ;
    CanHandle1.Init.BS1 = CAN_BS1_6TQ;
    CanHandle1.Init.BS2 = CAN_BS2_8TQ;
    CanHandle1.Init.Prescaler = 2;

    HAL_CAN_Init(&CanHandle1);

    /* CAN filter init */
    CAN_FilterInitStructure.FilterNumber = 0;
    CAN_FilterInitStructure.FilterMode = CAN_FILTERMODE_IDMASK;
    CAN_FilterInitStructure.FilterScale = CAN_FILTERSCALE_32BIT;
    CAN_FilterInitStructure.FilterIdHigh = 0x0000;
    CAN_FilterInitStructure.FilterIdLow = 0x0000;
    CAN_FilterInitStructure.FilterMaskIdHigh = 0x0000;
    CAN_FilterInitStructure.FilterMaskIdLow = 0x0000;
    CAN_FilterInitStructure.FilterFIFOAssignment = 0;
    CAN_FilterInitStructure.FilterActivation = ENABLE;
    CAN_FilterInitStructure.BankNumber = 0;

    HAL_CAN_ConfigFilter(&CanHandle1, &CAN_FilterInitStructure);

    /* Configure transmission */
    CanHandle1.pTxMsg->StdId = 0x7DF;
    CanHandle1.pTxMsg->ExtId = 0x7DF;
    CanHandle1.pTxMsg->RTR = CAN_RTR_DATA;
    CanHandle1.pTxMsg->IDE = CAN_ID_STD;
    CanHandle1.pTxMsg->DLC = 8;
}

static void CAN2_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    CAN_FilterConfTypeDef CAN_FilterInitStructure;

    static CanTxMsgTypeDef TxMessage;
    static CanRxMsgTypeDef RxMessage;

    /* CAN2 peripheral clock enable */
    CAN2_CLK_ENABLE();
    CAN2_GPIO_CLK_ENABLE();

    /* CAN2 TX GPIO pin configuration */
    GPIO_InitStruct.Pin = CAN2_TX_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Alternate =  CAN2_TX_AF;

    HAL_GPIO_Init(CAN2_TX_GPIO_PORT, &GPIO_InitStruct);

    /* CAN2 RX GPIO pin configuration */
    GPIO_InitStruct.Pin = CAN2_RX_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Alternate =  CAN2_RX_AF;

    HAL_GPIO_Init(CAN2_RX_GPIO_PORT, &GPIO_InitStruct);

    /* NVIC configuration for CAN2 reception complete interrupt */
    HAL_NVIC_SetPriority(CAN2_RX_IRQn, 1, 0);
    HAL_NVIC_EnableIRQ(CAN2_RX_IRQn);

    CanHandle2.Instance = CAN2;
    CanHandle2.pTxMsg = &TxMessage;
    CanHandle2.pRxMsg = &RxMessage;

    /* CAN peripheral init */
    CanHandle2.Init.TTCM = DISABLE;
    CanHandle2.Init.ABOM = DISABLE;
    CanHandle2.Init.AWUM = DISABLE;
    CanHandle2.Init.NART = DISABLE;
    CanHandle2.Init.RFLM = DISABLE;
    CanHandle2.Init.TXFP = DISABLE;
    CanHandle2.Init.Mode = CAN_MODE_LOOPBACK;
    CanHandle2.Init.SJW = CAN_SJW_1TQ;
    CanHandle2.Init.BS1 = CAN_BS1_6TQ;
    CanHandle2.Init.BS2 = CAN_BS2_8TQ;
    CanHandle2.Init.Prescaler = 2;

    HAL_CAN_Init(&CanHandle2);

    /* CAN filter init */
    CAN_FilterInitStructure.FilterNumber = 0; //14 enables CAN1;
    CAN_FilterInitStructure.FilterMode = CAN_FILTERMODE_IDMASK;
    CAN_FilterInitStructure.FilterScale = CAN_FILTERSCALE_32BIT;
    CAN_FilterInitStructure.FilterIdHigh = 0x0000;
    CAN_FilterInitStructure.FilterIdLow = 0x0000;
    CAN_FilterInitStructure.FilterMaskIdHigh = 0x0000;
    CAN_FilterInitStructure.FilterMaskIdLow = 0x0000;
    CAN_FilterInitStructure.FilterFIFOAssignment = 0;
    CAN_FilterInitStructure.FilterActivation = ENABLE;
    CAN_FilterInitStructure.BankNumber = 0; // 14 enables CAN1

    HAL_CAN_ConfigFilter(&CanHandle2, &CAN_FilterInitStructure);

    /* Configure transmission */
    CanHandle2.pTxMsg->StdId = 0x7DF;
    CanHandle2.pTxMsg->ExtId = 0x7DF;
    CanHandle2.pTxMsg->RTR = CAN_RTR_DATA;
    CanHandle2.pTxMsg->IDE = CAN_ID_STD;
    CanHandle2.pTxMsg->DLC = 8;
}

void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* CanHandle)
{
    EwBspYellowLedOn();

    Message_Data[0] = CanHandle->pRxMsg->Data[0];
    Message_Data[1] = CanHandle->pRxMsg->Data[1];
    Message_Data[2] = CanHandle->pRxMsg->Data[2];
    Message_Data[3] = CanHandle->pRxMsg->Data[3];
    Message_Data[4] = CanHandle->pRxMsg->Data[4];
    Message_Data[5] = CanHandle->pRxMsg->Data[5];
    Message_Data[6] = CanHandle->pRxMsg->Data[6];
    Message_Data[7] = CanHandle->pRxMsg->Data[7];

    if (HAL_CAN_Receive_IT(CanHandle, CAN_FIFO0) != HAL_OK)
    {
        EwBspRedLedOn();
    }
}

CAN_Transmit_Message(void)
{
    CanHandle2.pTxMsg->StdId = 0x7DF;
    CanHandle2.pTxMsg->ExtId = 0x7DF;
    CanHandle2.pTxMsg->Data[0] = 0x02;
    CanHandle2.pTxMsg->Data[1] = 0x01;
    CanHandle2.pTxMsg->Data[2] = 0x0D;
    CanHandle2.pTxMsg->Data[3] = 0x55;
    CanHandle2.pTxMsg->Data[4] = 0x55;
    CanHandle2.pTxMsg->Data[5] = 0x55;
    CanHandle2.pTxMsg->Data[6] = 0x55;
    CanHandle2.pTxMsg->Data[7] = 0x55;

    if (HAL_CAN_Transmit(&CanHandle, 10) != HAL_OK)
    {
        EwBspOrangeLedOn();
    }

    HAL_Delay(10);
}

I then run the following in my main function to configure the CAN1, CAN2 and the interrupt:

    /* Configure interrupt for CAN transmission */
    CAN1_Config();
    CAN2_Config();
    HAL_CAN_Receive_IT(&CanHandle2, CAN_FIFO0);

And then I run the CAN_Transmit_Message().

When doing this I have verified the message successfully transmits (the orange LED does not turn on), the receive interrupt handler is then executed (yellow LED turns on) and the message is successfully received (red LED does not turn on).

However, on the second transmission of a message (another call to CAN_Transmit_Message()), the transmit once again succeeds, but the receive fails (red LED turns on).

I created this code by following the structure in the CAN_Networking example code, but I cannot figure out why it is failing at the HAL_CAN_Receive_IT function on the second message (after the first message is successfully received).

Note: After reading the stm32f4xx_HAL_CAN library file, I noticed there are two types of receive/transmit:

  1. HAL_CAN_Transmit_IT/HAL_CAN_Receive_IT
  2. HAL_CAN_Transmit/HAL_CAN_Receive

It says that 1. is nonblocking - I take it this means that another interrupt can be triggered whilst this transmit/receive is still running?

In my case I want to make sure that I receive the response data after sending the transmit to request it, so should I use function 2.? I.e. I would call HAL_CAN_Transmit with a suitable timeout, and then after it completes call HAL_CAN_Receive, again with a suitable timeout.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
James Elder
  • 1,583
  • 3
  • 22
  • 34

1 Answers1

1

Do you call HAL_CAN_Receive_IT each time you get a response?

It's one shot. To keep receiving, call it again in your interrupt handler.

From the Reference Manual: When a message has been received, it is available to the software in the FIFO output mailbox. Once the software has handled the message (e.g. read it) the software must release the FIFO output mailbox by means of the RFOM bit in the CAN_RFR register to make the next incoming message available.

HAL_CAN_Receive_IT contains lines that enable the interrupts and release the FIFO...

/* Enable interrupts: */
    /*  - Enable Error warning Interrupt */
    /*  - Enable Error passive Interrupt */
    /*  - Enable Bus-off Interrupt */
    /*  - Enable Last error code Interrupt */
    /*  - Enable Error Interrupt */
    /*  - Enable Transmit mailbox empty Interrupt */
    __HAL_CAN_ENABLE_IT(hcan, CAN_IT_EWG |
                              CAN_IT_EPV |
                              CAN_IT_BOF |
                              CAN_IT_LEC |
                              CAN_IT_ERR |
                              CAN_IT_TME  );   
    /* Process unlocked */
    __HAL_UNLOCK(hcan);

    if (FIFONumber == CAN_FIFO0)
    {
      /* Enable FIFO 0 message pending Interrupt */   
      __HAL_CAN_ENABLE_IT(hcan, CAN_IT_FMP0);
    }
    else
    {
      /* Enable FIFO 1 message pending Interrupt */
      __HAL_CAN_ENABLE_IT(hcan, CAN_IT_FMP1);
    }
DotMPP
  • 21
  • 2
  • What is it supposed to do? Why is it necessary? What is the theory of operation? Please respond by [editing (changing) your answer](https://stackoverflow.com/posts/44853983/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Oct 14 '21 at 01:07