2015-11-14 02:22 AM
Hello, I'm trying to communicate with a STM32f4x9 EVAL board and a STM32F429-Discovery board via CAN Bus,
I am using MCP2551 transceiver IC for Discovery board, I know that CAN1 is being used by LCD and CAN2 is used by USB OTG. So I de-soldered the C53 (4k7 uf) capacitor of Discovery board (according to a video onhttps://www.youtube.com/watch?v=4fYoXGiIdDs
), I have tested everything, wirings, HAL configs for CAN, etc.. But I'm getting timeout when I call the HAL_CAN_Transmit function. I am using pure STMCube examples (STM32F4x9_EVAL\Examples\CAN\CAN_Networking), I re-configured the same example for Discovery board, using CAN2 instead of CAN1. Here is my wiring schematic: I did not touch the Eval example, but here is my code for Discovery board:bool CANWorker::init_HAL_CAN()
{
// Placed in MCP file:
GPIO_InitTypeDef GPIO_InitStruct;
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* CAN2 Periph clock enable */
CANx_CLK_ENABLE();
/* Enable GPIO clock ****************************************/
CANx_GPIO_CLK_ENABLE();
/*##-2- Configure peripheral GPIO ##########################################*/
/* CAN2 TX GPIO pin configuration */
GPIO_InitStruct.Pin = CANx_TX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Alternate = CANx_TX_AF;
HAL_GPIO_Init(CANx_TX_GPIO_PORT, &GPIO_InitStruct);
/* CAN2 RX GPIO pin configuration */
GPIO_InitStruct.Pin = CANx_RX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Alternate = CANx_RX_AF;
HAL_GPIO_Init(CANx_TX_GPIO_PORT, &GPIO_InitStruct);
/*##-3- Configure the NVIC #################################################*/
/* NVIC configuration for CAN2 Reception complete interrupt */
HAL_NVIC_SetPriority(CANx_RX_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(CANx_RX_IRQn);
CAN_FilterConfTypeDef sFilterConfig;
static CanTxMsgTypeDef TxMessage;
static CanRxMsgTypeDef RxMessage;
/*##-1- Configure the CAN peripheral #######################################*/
_canHandle.Instance = CAN2;
_canHandle.pTxMsg = &TxMessage;
_canHandle.pRxMsg = &RxMessage;
_canHandle.Init.TTCM = DISABLE;
_canHandle.Init.ABOM = DISABLE;
_canHandle.Init.AWUM = DISABLE;
_canHandle.Init.NART = DISABLE;
_canHandle.Init.RFLM = DISABLE;
_canHandle.Init.TXFP = DISABLE;
_canHandle.Init.Mode = CAN_MODE_NORMAL;
_canHandle.Init.SJW = CAN_SJW_1TQ;
_canHandle.Init.BS1 = CAN_BS1_6TQ;
_canHandle.Init.BS2 = CAN_BS2_8TQ;
_canHandle.Init.Prescaler = 2;
if(HAL_CAN_Init(&_canHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
return false;
}
/*##-2- Configure the CAN Filter ###########################################*/
sFilterConfig.FilterNumber = 14;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = 0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.BankNumber = 14;
if(HAL_CAN_ConfigFilter(&_canHandle, &sFilterConfig) != HAL_OK)
{
/* Filter configuration Error */
Error_Handler();
return false;
}
/*##-3- Configure Transmission process #####################################*/
_canHandle.pTxMsg->StdId = 0x321;
_canHandle.pTxMsg->ExtId = 0x01;
_canHandle.pTxMsg->RTR = CAN_RTR_DATA;
_canHandle.pTxMsg->IDE = CAN_ID_STD;
_canHandle.pTxMsg->DLC = 2;
return true;
}
void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* CanHandle)
{
if ((CanHandle->pRxMsg->StdId == 0x321)&&(CanHandle->pRxMsg->IDE == CAN_ID_STD) && (CanHandle->pRxMsg->DLC == 2))
{
LED_Display(CanHandle->pRxMsg->Data[0]);
ubKeyNumber = CanHandle->pRxMsg->Data[0];
}
/* Receive */
if(HAL_CAN_Receive_IT(CanHandle, CAN_FIFO0) != HAL_OK)
{
/* Reception Error */
//Error_Handler();
}
}
CANWorker::CANWorker ()
{
init_HAL_CAN();
BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_GPIO);
/*##-2- Start the Reception process and enable reception interrupt #########*/
if(HAL_CAN_Receive_IT(&_canHandle, CAN_FIFO0) != HAL_OK)
{
/* Reception Error */
Error_Handler();
}
/* Infinite loop */
while(1)
{
while(BSP_PB_GetState(BUTTON_KEY) == KEY_PRESSED)
{
if(ubKeyNumber == 0x4)
{
ubKeyNumber = 0x00;
}
else
{
LED_Display(++ubKeyNumber);
/* Set the data to be transmitted */
_canHandle.pTxMsg->Data[0] = ubKeyNumber;
_canHandle.pTxMsg->Data[1] = 0xAD;
/*##-3- Start the Transmission process ###############################*/
if(HAL_CAN_Transmit(&_canHandle, 1000) != HAL_OK)
{
/* Transmition Error */
Error_Handler();
}
HAL_Delay(10);
while(BSP_PB_GetState(BUTTON_KEY) != KEY_NOT_PRESSED)
{
}
}
}
}
}
But the ''HAL_CAN_Transmit'' returns timeout, waiting for TransmitMailbox to be sent (Following codes are from : stm32f4xx_hal_can.c
/* Check End of transmission flag */
while(!(__HAL_CAN_TRANSMIT_STATUS(hcan, transmitmailbox)))
{
/* Check for the Timeout */
if(Timeout != HAL_MAX_DELAY)
{
if((Timeout == 0)||((HAL_GetTick() - tickstart ) > Timeout))
{
hcan->State = HAL_CAN_STATE_TIMEOUT;
/* Process unlocked */
__HAL_UNLOCK(hcan);
return HAL_TIMEOUT;
}
}
}
What am I doing wrong? It's not because I use a MCP2551 and the EVAL board is using HVD230 transceiver instead, right?
It seems that the other not does not ACK the sent frame, am I right? What causes this?
#transmission #stm32 #stm32f4 #can #can #error #timeout #can-timeout
2017-12-27 04:56 PM
Yes, I had trouble too...
did you know that the ABOM bit must be set. /*!< Enable or disable the automatic bus-off management.
in the L95616 datasheet, page 5, the RXO pin is definitively going to your STM32 Rx pin...
You must make sure any tranmission stdID is always different from any other source. otherwise the canbus will go into an error state and then you must power cycle your whole network to clear it.
I used port pins to set a different 'ID' for each board, then they use different stdID in the frame.
The issue is that the canbus hardware checks it has the buscontrol as it transmits the stdID, after that, if two devices are using the same stdID then both will succeed past the stdID part of the frame, then if the data is not exactly the same from both transmitters, the canbus will go into fault. Then you must power cycle your whole network to clear it. (there is an error flag for that. Eventually, your code should be able to recover from a bus failed state)
If you can transmit ok onto the canbus, then you can receive it on the dongle ?
2017-12-27 05:13 PM
PA12 is the Tx pin... page 40 of the data sheet.
2017-12-27 05:13 PM
Thanks. I'm using the same code as the eval. I've looked and I have no idea where the CAN 'ID' is set. I don't see it in any of the code so maybe it comes from some hardware jumper or something. So, I would say the the two boards, and maybe even the dongle have the same ID.
I thought the transmitted packet would go to all devices on the bus and that the StdID mask would tell the receiving device(s) if they want to receive the packet. I haven't changed the StdID of the packet (0x321). I've setup the dongle to send a 0x321 packet across the CAN bus and the waveform is identical whether the dongle generates or the Nucleo board generates. The documentation on the Ginkgo USB-CAN Interface adapter and software is horrible so it may not be setup correctly to display anything it sees on the CAN bus...
Another thing I'm not clear on (the short list is what I'm clear on!) is the nomenclature of the transceiver chip (L9616) and Nucleo board. When there is a signal on the CAN bus, the RX0 pin on the L9616 has the decoded TTL level signal. I would have thought that signal should be routed to the RX pin for the Nucleo board (PA12 in my case). That doesn't work. It must be routed to PA11 (CANx_TX_PIN). Maybe CANx_TX_PIN means the pin for incoming data from a CAN transmission. It's just backwards from what I would think which is that the TX pin should have the outgoing data to be transmitted, not the incoming data... So, the RXO line from the transceiver goes to the CAN_TX_PIN and the TX0 line from the transceiver goes to the CAN_RX_PIN on the STM32f303.
I've been working on this thing for days now and I'm not sure I'm much closer than when I started... Maybe we bite the bullet and buy eval boards that have working peripherals and samples..
Thanks for your suggestions.
2017-12-28 12:23 PM
Thanks Nick. What data sheet do you have? I have RM0316. Is there a better one? Anyway, that's my error. I took the Eval sample sources and changed PD0 and PD1 to PA12 and PA11 respectively. I reversed them. So, I changed them in the header file, rebuilt and reflashed and the performance is the same as it was.
I still don't know how to set the CAN bus ID. I haven't found it in docs. Is it a hardware setting on the Nucleo boards? I must say the documentation leaves much to be desired...
FLASH: I was wrong. I am now getting a CAN receive interrupt! And I'm receiving the data that I am transmitting from the USB dongle. I still haven't received anything on the dongle from my Nucleo board. Nor have I received anything on the Nucleo from the other Nucleo. I suspect that's the CAN ID issue we're working on. How do I set the CAN ID?
Maybe there is a light at the end of the tunnel (that isn't a train!).
2017-12-28 12:34 PM
Sorry for the confusion...it takes a while for the understanding to click into place.
it is a message ID.
the higher priority messages are automatically sent first by negotiation across the 'CAN-BUS'
so you must make your messages unique or you will put the bus into an error state.
so I set an address on each board separately, only used a message ID unique to that address.
all the problems stopped after that.
Don't forget, nothing will work while the 'bus' is in that error state, you will need to power cycle all connected devices to be sure its cleared.
2017-12-28 12:37 PM
Data Sheet != Reference Manual
For former describes specific parts, pins and performance, the latter describes more interior functionality across a family of parts
PA11 CAN_RX
PA12 CAN_TX
RM0316 is for the STM32F303 parts, for the F4 parts you'll want RM0090 and the appropriate Data Sheets
2017-12-28 01:22 PM
Thanks Clive. Do you know how to set the CAN device address on a Nucleo board??
2017-12-28 01:30 PM
It is not board specific. The Filter defines the Message ID which are pulled off the wire. These can describe one ID, a range or selection of them, or all of them. You need to stop thinking of this as a MAC or IP address.
2017-12-28 04:11 PM
,
,
Ok. , I think I'm starting to get my mind right... , , I can understand the concept of only 1 device accepting certain packets and no 2 devices may accept the same packet ID. , So we use filters to do this. , For testing, I want the board to only , accept StdMsgID = 0x320 . , So I set the mask and ID both to 0x320 and now I don't recieve the incoming message. , ,I set the ID to 0x320 and the mask to 0x1fffffff and still don't get the packet. , When the mask and ID are both 0x0000 , the packet is received and its StdID is 0x320. , ,Is there any documentation on the filter ID/Mask implementation?
, ,
/* ♯ ♯ -2- Configure the CAN Filter ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ */
,
sFilterConfig.FilterNumber = 0,,
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK,,
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT,,
sFilterConfig.FilterIdHigh = 0x0000,,
sFilterConfig.FilterIdLow = 0x320, , , , , , // works with , 0x0000,
sFilterConfig.FilterIdLow = 0x0000,,
sFilterConfig.FilterMaskIdHigh = 0x1fff, , ,// works with 0x0000,
sFilterConfig.FilterMaskIdLow = 0xffff, , , // works with 0x0000,
sFilterConfig.FilterFIFOAssignment = 0,,
sFilterConfig.FilterActivation = ENABLE,,
sFilterConfig.BankNumber = 14,,
Thanks
2017-12-28 04:19 PM
sFilterConfig.FilterIdLow = 0x0320 << 5;
sFilterConfig.FilterIdLow = 0; sFilterConfig.FilterMaskIdHigh = 0x7ff << 5; sFilterConfig.FilterMaskIdLow = 0;