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:
- HAL_CAN_Transmit_IT/HAL_CAN_Receive_IT
- 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.