Skip to main content
Eugenia Suarez
Associate III
March 1, 2017
Question

Correct TX CAN frame form using HAL_CAN libraries

  • March 1, 2017
  • 7 replies
  • 2432 views
Posted on March 01, 2017 at 10:47

Hi, 

I'm new using stm32 mcu and HAL libraries, too new developing CAN apps. So I have some questions to do in order to understand a few necessary things before testing an app that will transmit two chars in a infinite loop.

I'm working with discovery kit with smt32l4F6 mcu. I configured CAN controller params via HAL_CAN library. I have noticed that using this library, user can only have access from ID frame field to the end of data field (for transmisions). I must guess that CRC, ACK and EOF fields are configured in HAL lowest layers, independently of user code.

Am I wrong? If not, what does it mean if ESR register contains an 010 error field that indicates 'form error' (according datasheet)? 

If I'm wrong, please, could anyone show me where to fill these fields or how to access them through HAL_CAN driver (of course, from my user code)?

Thanks in advance!

#hal_can #can-frame-fields #stm32l4 #can #can_esr
This topic has been closed for replies.

7 replies

Eugenia Suarez
Associate III
March 6, 2017
Posted on March 06, 2017 at 09:52

Well, if someone has had the same question, I know yet that these fields are added by the hardware and not by user. But I still unknowing the possible causes of 010 code error. 

T J
Senior III
March 6, 2017
Posted on March 06, 2017 at 21:43

did you get it working ?

is it BxCan ?

my code works very well, if you are interested.

are you using CubeMX ?

void CAN_Config(){ CAN_FilterConfTypeDef sFilterConfig; static CanTxMsgTypeDef TxMessage; static CanRxMsgTypeDef RxMessage;
 //##-1- Configure the CAN peripheral #######################################// hcan.Instance = CANx; hcan.pTxMsg = &TxMessage; hcan.pRxMsg = &RxMessage;
 hcan.pTxMsg->RTR = CAN_RTR_DATA; // can be CAN_RTR_DATA or CAN_RTR_REMOTE hcan.pTxMsg->DLC = 8; // between Min_Data = 0 and Max_Data = 0x07 hcan.pTxMsg->StdId = 0x101; // between Min_Data = 0 and Max_Data = 0x1FF hcan.pTxMsg->ExtId = 0x102; // between Min_Data = 0 and Max_Data = 0x1FFFFFFF hcan.pRxMsg->DLC = 8; // between Min_Data = 0 and Max_Data = 0x07 hcan.pRxMsg->StdId = 0x101; // between Min_Data = 0 and Max_Data = 0x1FF hcan.pRxMsg->ExtId = 0x102; // between Min_Data = 0 and Max_Data = 0x1FFFFFFF hcan.pRxMsg->RTR = CAN_RTR_DATA; // can be CAN_RTR_DATA or CAN_RTR_REMOTE 
// hcan.Init.TTCM = DISABLE;// hcan.Init.ABOM = DISABLE;// hcan.Init.AWUM = DISABLE;// hcan.Init.NART = DISABLE;// hcan.Init.RFLM = DISABLE;// hcan.Init.TXFP = DISABLE;// hcan.Init.Mode = CAN_MODE_NORMAL;// hcan.Init.SJW = CAN_SJW_1TQ;// hcan.Init.BS1 = CAN_BS1_6TQ;// hcan.Init.BS2 = CAN_BS2_8TQ;// hcan.Init.Prescaler = 2;
 if (HAL_CAN_Init(&hcan) != HAL_OK) { // Initiliazation Error Error_Handler(); } //##-2- Configure the CAN Filter ########################################### sFilterConfig.FilterNumber = 0; sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; sFilterConfig.FilterIdHigh = 0x100 << 5; //11-bit ID in top bits sFilterConfig.FilterIdLow = 0x0000; sFilterConfig.FilterMaskIdHigh = 0x700 << 5; // resolves as 0x01xx sFilterConfig.FilterMaskIdLow = 0x0000; sFilterConfig.FilterFIFOAssignment = 0; sFilterConfig.FilterActivation = ENABLE;// sFilterConfig.BankNumber = 14; sFilterConfig.BankNumber = 0;
 if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK) { // Filter configuration Error Error_Handler(); sprintf(string,'Can Filter configuration Error

'); console::puts(string); } 
//##-2- Configure the 2nd CAN Filter ########################################### sFilterConfig.FilterNumber = 1; sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; sFilterConfig.FilterIdHigh = 0x500 << 5; //11-bit ID in top bits // command channel sFilterConfig.FilterIdLow = 0x0000; sFilterConfig.FilterMaskIdHigh = 0x700 << 5; // resolves as 0x01xx sFilterConfig.FilterMaskIdLow = 0x0000; sFilterConfig.FilterFIFOAssignment = 1; sFilterConfig.FilterActivation = ENABLE;// sFilterConfig.BankNumber = 14; sFilterConfig.BankNumber = 0;
 if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK) { // Filter configuration Error Error_Handler(); sprintf(string,'Can Filter configuration Error

'); console::puts(string); }
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Eugenia Suarez
Associate III
March 7, 2017
Posted on March 07, 2017 at 15:53

Yes I have used Cube for initialization settings etc. From there I modify a bit the structure and organization of  folders and files according to the policy of my project. 

Now I'm measuring with TX of mcu pinout with the osciloscope in order to see if there is the frame I'm sending, and I can see that. But when I connect these pins to the transceiver and the transceiver to the CAN-USB conector, the CAN controller seems to stop the output frame. It stops of writting frame to these pins. The frame disappears from osc screen. 

Hence, I first will test only looking at the CAN uC pins before connecting. After check this step I will try to understand behavior of controler when it is into network circuit. 

I will get your code for doing some comparition and tests. So thanks a lot. I will comment you the results or doubts if not.

Thank you too much. 

T J
Senior III
March 7, 2017
Posted on March 08, 2017 at 00:18

I use a CanDo unit from the UK.

it is the master and so my code is set to respond, no the initiate canFrames.

maybe you have that problem.

do you have an external master on the bus ?

T J
Senior III
March 7, 2017
Posted on March 08, 2017 at 00:50

This is my Tx code:

void checkCanTxMsgs(void){// this is a non-ordered packet transmitter.
if (!canTxMsgTableEMPTY)
if ((canTxMsgOUT != canTxMsgIN) || canTxMsgTableFULL ) // a non - ordered packet transmitter with an 8 byte payload
if ((CAN->TSR & CAN_TSR_TME0) == CAN_TSR_TME0) // (1) 
{
CAN->sTxMailBox[0].TDTR = canTxMsgLength[canTxMsgOUT];// (2) length
CAN->sTxMailBox[0].TDLR = canTxMsgBottomWord[canTxMsgOUT]; // (3) 4bytes
CAN->sTxMailBox[0].TDHR = canTxMsgTopWord[canTxMsgOUT]; // (3) 4bytes
CAN->sTxMailBox[0].TIR = ((uint32_t)canTxMsgID [canTxMsgOUT] << 21 | CAN_TI0R_TXRQ); // (4)// send it now if the line is idle
// destroy old data to be sure we only transmit fresh data
// not needed
canTxMsgLength[canTxMsgOUT] = 0;
canTxMsgBottomWord[canTxMsgOUT] = 0; 
canTxMsgTopWord[canTxMsgOUT]= 0; 
canTxMsgID [canTxMsgOUT]= 0;

++canTxMsgOUT &=0x0F;// 16 buffer elements
canTxMsgTableFULL = false;
canTxMsgOverrun = false;
//canMsgCounter ++;
}
if ((canTxMsgOUT != canTxMsgIN) || canTxMsgTableFULL) // a non - ordered packet transmitter with an 8 byte payload
if ((CAN->TSR & CAN_TSR_TME1) == CAN_TSR_TME1) // (1) 
{
CAN->sTxMailBox[1].TDTR = canTxMsgLength[canTxMsgOUT];// (2) length
CAN->sTxMailBox[1].TDLR = canTxMsgBottomWord[canTxMsgOUT]; // (3) 4bytes
CAN->sTxMailBox[1].TDHR = canTxMsgTopWord[canTxMsgOUT]; // (3) 4bytes
CAN->sTxMailBox[1].TIR = ((uint32_t) canTxMsgID [canTxMsgOUT] << 21 | CAN_TI1R_TXRQ); // (4)// send it now if the line is idle
// destroy old data to be sure we only transmit fresh data
// not needed
canTxMsgLength[canTxMsgOUT] = 0;
canTxMsgBottomWord[canTxMsgOUT] = 0; 
canTxMsgTopWord[canTxMsgOUT]= 0; 
canTxMsgID [canTxMsgOUT]= 0;

++canTxMsgOUT &=0x0F;// 16 buffer elements
canTxMsgOverrun = false;
canTxMsgTableFULL = false;
//canMsgCounter ++;
}
if ((canTxMsgOUT != canTxMsgIN) || canTxMsgTableFULL) // a non - ordered packet transmitter with an 8 byte payload
if ((CAN->TSR & CAN_TSR_TME2) == CAN_TSR_TME2) // (1) 
{
CAN->sTxMailBox[2].TDTR = canTxMsgLength[canTxMsgOUT];// (2) length
CAN->sTxMailBox[2].TDLR = canTxMsgBottomWord[canTxMsgOUT]; // (3) 4bytes
CAN->sTxMailBox[2].TDHR = canTxMsgTopWord[canTxMsgOUT]; // (3) 4bytes
CAN->sTxMailBox[2].TIR = ((uint32_t) canTxMsgID[canTxMsgOUT] << 21 | CAN_TI2R_TXRQ); // (4)// send it now if the line is idle
// destroy old data to be sure we only transmit fresh data
// not needed
canTxMsgLength[canTxMsgOUT] = 0;
canTxMsgBottomWord[canTxMsgOUT] = 0; 
canTxMsgTopWord[canTxMsgOUT]= 0; 
canTxMsgID [canTxMsgOUT]= 0;

++canTxMsgOUT &=0x0F;// 16 buffer elements
canTxMsgOverrun = false;
canTxMsgTableFULL = false;
//canMsgCounter ++;
}
if (canTxMsgOUT == canTxMsgIN)canTxMsgTableEMPTY = true;
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Eugenia Suarez
Associate III
March 8, 2017
Posted on March 08, 2017 at 10:51

thanks marsh,

but I'm using HAL_CAN_transmit to send data.

Here we have a can-usb janztec converter. The idea is to test it with an app able to send and receive msg. But I have divided this tryal in two parts. 

But I first have thought about checking Tx pin when code is running, without being connected to any can transciever, this means: out of a can net, looking directly to the board pinout. I'm looking at the mcu output directly, on GPIOs configured to be Tx CAN pin with an osc. With the same code sometimes I can see my data on osc screen. But sometimes I can't do. Micro seems to stop having data at this pin randomly.

I'm not sure if it's robustness of my code or hardware influences the cause of this randomly output. I would like to ensure if microcontroller TX  output (my choosen GPIO) musts show data signal independently of having connected to transciever (and can-usb connector i. e.) as you can do when uses gpio for sending serie data through uart, etc. You can see the gpio  states when code runs without having connected anything.

Second part was connecting can-usb converter with the transciever to the TX/RX mcu pins when it ran. But, this is not the main thing now. I need to close the first step/question, before this. 

regards

T J
Senior III
March 8, 2017
Posted on March 08, 2017 at 13:30

hello again,

I had significant trouble to get it working myself.

I had to initialise HAL driver interrupts first, and receive a frame before I could use my simple Tx system which I have shown you.

Have you initialised the HAL canbus system ?

T J
Senior III
March 8, 2017
Posted on March 08, 2017 at 13:45

Have you tried the installed examples ?

________________

Attachments :

Can Examples folders.jpg : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006Hyjb&d=%2Fa%2F0X0000000bD5%2FAJsvgYuC4VC3I_2Rvo8Rd7K8NDohhx9lkmS55wByqDA&asPdf=false
Eugenia Suarez
Associate III
March 8, 2017
Posted on March 08, 2017 at 14:52

The idea is to measure TTL levels form gpio pin dedicated to Tx CAN output of the micro.

There is no example of can for discoverty kit but I get data values from the example of can network.

I get the initialization struct values from the only one example for.. (I don't remember which) platform.

I was debugging and init register updates are fine. When transmission timeout is getting -due obviously there is no transciever connected, hence no receiver- error bit is set un TIR register.

Although this, I think TTL frame levels must be at GPIO mcu pin available whenever transmission app runs. But as I said, sometimes it happens and sometimes it doesn't.

Here my main:

main
{ ... 
App_Task_CAN_reset(); 
App_Task_CAN_init(); 
charBuffer[0]=0x55; 
charBuffer[1]=0x55; 
while (1) { App_Task_CAN_sendData(&charBuffer[0]); } 
}

Send data:

uint8_t App_Task_CAN_sendData(uint8_t* cBuffer) 
{ 
 for (uint8_t index=0; index< DATABTXLONG; index ++) 
 { 
HCAN_Struct.pTxMsg->Data[index]= cBuffer[index]; 
 } //here I pass my app data bytes to the buffer of can struct data field
 
 if (HAL_CAN_Transmit(&HCAN_Struct, TIMEOUT)!=HAL_OK) 
 { 
TaskCan_Error_Handler(); 
 } 
return 0; 
}

init function:

void App_Task_CAN_init(void) 
{ 
static CanTxMsgTypeDef TxMessage; 
static CanRxMsgTypeDef RxMessage; /*configuracion timing para obtener 500kb/s*/
 HCAN_Struct.Instance = CAN1; 
HCAN_Struct.pTxMsg = &TxMessage; 
HCAN_Struct.pRxMsg = &RxMessage; 
HCAN_Struct.Init.Prescaler = 1; 
HCAN_Struct.Init.Mode = CAN_MODE_NORMAL; 
HCAN_Struct.Init.SJW = CAN_SJW_1TQ; 
HCAN_Struct.Init.BS1 = CAN_BS1_6TQ;//segment point at 5% 
HCAN_Struct.Init.BS2 = CAN_BS2_1TQ; 
HCAN_Struct.Init.TTCM = DISABLE;
 HCAN_Struct.Init.ABOM = DISABLE; 
HCAN_Struct.Init.AWUM = DISABLE; 
HCAN_Struct.Init.NART = DISABLE;
 HCAN_Struct.Init.RFLM = DISABLE;//Fifo locked mode disabled 
HCAN_Struct.Init.TXFP = DISABLE;//prioridad de tx por id (más bajo más prioridad) 
if (HAL_CAN_Init(&HCAN_Struct) != HAL_OK) 
{ TaskCan_Error_Handler(); } 
Can_ConfigureFrame(CAN_RTR_DATA, CAN_ID_STD); 
}

Configure frame funct:

 void Can_ConfigureFrame(uint32_t DataFrame, uint32_t standard) 
{ //TX 
HCAN_Struct.pTxMsg->RTR = CAN_RTR_DATA; 
HCAN_Struct.pTxMsg->DLC = DATABTXLONG;//1-9 
HCAN_Struct.pTxMsg->StdId = 0x101; 
HCAN_Struct.pTxMsg->ExtId = 0x102;//29 bits
HCAN_Struct.pTxMsg->IDE = CAN_ID_STD; 
HCAN_Struct.Instance->MCR &= (~(uint32_t)CAN_MCR_DBF);//descongelar el bus caN en modo debug bit --> dbf=0
}

Configure Filter banks:

uint8_t App_Task_CAN_HwFiltersBank(void) 
{ 
for(uint16_t iFilters =0; iFilters < nFILTERS; iFilters ++) 
{ 
HCANFilter_Struct.FilterNumber = 0; //0 - 27 
HCANFilter_Struct.FilterMode = CAN_FILTERMODE_IDLIST; 
HCANFilter_Struct.FilterScale = CAN_FILTERSCALE_32BIT; 
HCANFilter_Struct.FilterIdHigh = 0x100 << 5; //11-bit ID in top bits //MSB of 32b config 
HCANFilter_Struct.FilterIdLow = 0x0000;//LSB of 32b config 
HCANFilter_Struct.FilterMaskIdHigh = 0x700 << 5; // resolves as 0x01xx 
HCANFilter_Struct.FilterMaskIdLow = 0x0000; 
HCANFilter_Struct.FilterFIFOAssignment = 0; 
HCANFilter_Struct.FilterActivation = ENABLE; 
HCANFilter_Struct.BankNumber = 0; 
if (HAL_CAN_ConfigFilter(&HCAN_Struct,&HCANFilter_Struct) != HAL_OK) 
{ TaskCan_Error_Handler(); } 
} 
return 0; 
}

T J
Senior III
March 9, 2017
Posted on March 09, 2017 at 01:22

Actually,

if you have sent one byte from the Can peripheral without a slave connected (without an ACK on the RX pin), I believe you must do one of two things to recover the hardware canbus output state machine

1. power off

2. receive a byte from the bus.

Between power cycles, you only get one chance to see the pin data,

if there is no ACK or no RxByte from the bus, then the canbus state machine inside the processor is locked up.

T J
Senior III
March 9, 2017
Posted on March 09, 2017 at 01:36

there is a simple diode circuit that you can use across several processors running on the TTL side.

________________

Attachments :

SimpleCan Circuit.jpg : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006HypJ&d=%2Fa%2F0X0000000bCu%2FvjhdDghi03b7lcQrQ4Ql.SqY3jfN5gav2Iln5qaube0&asPdf=false
Eugenia Suarez
Associate III
March 9, 2017
Posted on March 09, 2017 at 09:24

Hi Marsh, I have found yesterday two different ways for testing my sw without having connected a transceiver.

  1. One of them is the same that you suggest before.
  2. The other one is to work in mode loop back. Since there is an example for other stm32 platform I think I could try with this example of Tx. In this mode datasheet says that RX doesn't send any ACK but this configuration will allow you to see TTL levels at Tx pin. Being the next step to do the test of my sw into a can net throught a transceiver. 

I really appreciate too much your help and your spent time with my matter. 

I will try with second option and I hope I can report good news about the success of these alternatives. 

Best regards.