cancel
Showing results for 
Search instead for 
Did you mean: 

How to transmit more than 8bytes data via basic CAN Bus

USolar
Associate III

Hi all!

I have a problem with transmition/receiving more than 8 bytes of data between two STM32 MCUs via CAN-Network.

I know, it is impossible to transmit more than 8 bytes of data via basic CAN Bus.

I tried to create Command messages System.

CAN Master transmit to CAN Slave command message "RT" (aka "Read Temperatures") and CAN Slave reply 'T' and 7 bytes of data with Temperature values. At that level it is all fine. CAN Master transmitting and then receiving the values. 

Then CAN Master transmits next command message"RP" (aka "Read Pressures") and CAN Slave reply 'P' and 7 bytes of data with Pressure Values. CAN Master, continuously transmitting each command after receiving values from previous command.

At that point starts the problem.

The values are overlapping with each other.

I have a question, is anybody had experience with transmitting/receiving more than 8 bytes of data via basic CAN Bus? Is there some special technic for this?

Thanks in advance.

Below part of my code.

CAN Master:

uint8_t TxData[8];
uint8_t RxData[8];
uint32_t TxMailbox;
uint8_t datacheck=0;
int Td=0;		//****Discharge Temperature*************************
int Ts=0;		//****Suction Temperature***************************
int Tc2=0;		//****Condenser Outlet Temperature******************
int Tih=0;		//****IHX Outlet Temperature************************
int Te1=0;		//****Evaporator Inlet Temperature******************
int Tev=0;		//****Evaporator Temperature************************
int16_t T_MCU;		//****Temperature of Slave Microcontroller
int8_t Temp=0;		//****Temperature of Slave Microcontroller
uint16_t Ps_R=0;	//****Pressure Readings from Slave Microcontroller's ADC
uint16_t Pd_R=0;	//****Pressure Readings from Slave Microcontroller's ADC
float Pd=0.0;
float Psuct=0.0;
 
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ETH_Init(void);
static void MX_USART3_UART_Init(void);
static void MX_USB_OTG_FS_PCD_Init(void);
static void MX_CAN1_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
 
void CAN_Bus_Start_Init(void)
{
	TxData[0]='R';
	TxData[1]='T';
	HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxData, &TxMailbox);
}
 
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData);
	if(RxHeader.StdId==0x103)
	{
		switch(RxData[0])
		{
			case 'T':
				datacheck=1;
			break;
			case 'P':
				datacheck=2;
			break;
		}
	}
}
 
/* USER CODE END 0 */
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
  /* USER CODE END 1 */
  /* MCU Configuration--------------------------------------------------------*/
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
  /* USER CODE BEGIN Init */
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ETH_Init();
  MX_USART3_UART_Init();
  MX_USB_OTG_FS_PCD_Init();
  MX_CAN1_Init();
  /* USER CODE BEGIN 2 */
 
  HAL_CAN_Start(&hcan1);
  //***Activate the Notification**********
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
 
  TxHeader.DLC=8;	//data length
  TxHeader.IDE=CAN_ID_STD;
  TxHeader.RTR=CAN_RTR_DATA;
  TxHeader.StdId=0x767;	//ID
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  ILI9486_Initialization();
  Clear_Screen(0x0000);
  tft_string(10,10,0xFFFF, 0x0000,12,"Discharge Temperature:");
  tft_string(10,30,0xFFFF, 0x0000,12,"Suction Temperature:");
  tft_string(10,50,0xFFFF, 0x0000,12,"Condenser Outlet Temperature:");
  tft_string(10,70,0xFFFF, 0x0000,12,"IHX Outlet Temperature:");
  tft_string(10,90,0xFFFF, 0x0000,12,"Evaporator Inlet Temperature:");
  tft_string(10,110,0xFFFF, 0x0000,12,"Evaporator Temperature:");
  tft_string(10,130,0xFFFF, 0x0000,12,"MCU's Temperature:");
  Write_Command(0x29);	// Display ON
 
  CAN_Bus_Start_Init();
  while (1)
  {//********Defining_Parameters_from_Slave_MCU*************************************
	  switch(datacheck)
	  {
		case 1:
			Td=RxData[1];
			Ts=RxData[2];
			Tc2=RxData[3];
			Tih=RxData[4];
			Te1=RxData[5];
			Tev=RxData[6];
			TxData[0]='R';
			TxData[1]='P';
		break;
		case 2:
			T_MCU=(RxData[2]<<8|RxData[1]);
			Ps_R=(RxData[4]<<8|RxData[3]);
			Pd_R=(RxData[6]<<8|RxData[5]);
 
			Temp=(int8_t)(((V25-(3.3*T_MCU/4095))/Avg_Slope)+25);
			Psuct=(float)(3.3*Ps_R/4095);		//Voltage from Suction Pressure Sensor
			Psuct=(Psuct-0.26)/0.2;				//For Danfoss Pressure Ratiometric Transmitter NSK-BE10I-U169 with 3.3V Supply
 
			Pd=(float)(3.3*Pd_R/4095);			//Voltage from Discharge Pressure Sensor
			Pd=(Pd-0.27)*15.38;					//For Danfoss Pressure Ratiometric Transmitter NSK-BE30I-U169 with 3.3V Supply
			TxData[0]='R';
			TxData[1]='T';
		break;
	  }
		datacheck=0;
		tft_integer(140,10,0x07FF, 0x0000,12,Td, 5);
		tft_integer(140,30,0x07FF, 0x0000,12,Ts, 5);
		tft_integer(200,50,0x07FF, 0x0000,12,Tc2, 5);
		tft_integer(200,70,0x07FF, 0x0000,12,Tih, 5);
		tft_integer(200,90,0x07FF, 0x0000,12,Te1, 5);
		tft_integer(200,110,0x07FF, 0x0000,12,Tev, 5);
		tft_integer(200,130,0x07FF, 0x0000,12,Temp, 5);
 
		tft_float(200,10,0xF800, 0x0000,12,Pd, 6);
		tft_float(200,30,0xF800, 0x0000,12,Psuct, 6);
 
		HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxData, &TxMailbox);
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

9 REPLIES 9

You're going to have to spread the data over multiple packets.

Perhaps use EXTID to create a class of messages, and sequence numbering so you can reassemble packets.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Karl Yamashita
Lead III

Your data is getting overwritten because you have one RxHeader and one RxData. So as you're parsing the data, you get another CAN interrupt and the RxData is written over. So when the stack returns to where your code left off, it is parsing data from the other new data that was received.

How often do you need to update the display? This will determine if you need just a timer callback to request for info or a ring buffer that can hold maybe 2-4 messages.

.

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

Hi Karl!

I'm sorry for such delay, don't have stable connection (working at Sea).

Thank you, for your reply.

I did, as you recommended, the Timer Callback, but I didn't see good result.

What I've observed, that 2nd Byte of first data package and 1st Byte of second data package are overlapping.

Last option left, the Ring Buffer, which I haven't use before.

Also, below the Code with Timer Callback:

/* USER CODE BEGIN PV */
uint8_t TxData[8];
uint8_t RxData[8];
uint8_t Data[15];
uint32_t TxMailbox;
uint8_t datacheck=0;
uint8_t CAN_Request=0;
int Td=0;		//****Discharge Temperature*************************
int Ts=0;		//****Suction Temperature***************************
int Tc2=0;		//****Condenser Outlet Temperature******************
int Tih=0;		//****IHX Outlet Temperature************************
int Te1=0;		//****Evaporator Inlet Temperature******************
int Tev=0;		//****Evaporator Temperature************************
 
int16_t T_MCU;		//****Temperature of Slave Microcontroller
int8_t Temp=0;		//****Temperature of Slave Microcontroller
uint16_t Ps_R=0;	//****Pressure Readings from Slave Microcontroller's ADC
uint16_t Pd_R=0;	//****Pressure Readings from Slave Microcontroller's ADC
float Pd=0.0;
float Psuct=0.0;
 
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ETH_Init(void);
static void MX_USART3_UART_Init(void);
static void MX_USB_OTG_FS_PCD_Init(void);
static void MX_CAN1_Init(void);
static void MX_TIM3_Init(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
 
void CAN_Bus_Start_Init(void)
{
	CAN_Request=1;
}
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData);
	if(RxHeader.StdId==0x103)
	{
		switch(RxData[0])
		{
			case 'T':
				datacheck=1;
				Data[0]=RxData[1];
				Data[1]=RxData[2];
				Data[2]=RxData[3];
				Data[3]=RxData[4];
				Data[4]=RxData[5];
				Data[5]=RxData[6];
			break;
			case 'P':
				datacheck=2;
				Data[6]=RxData[1];
				Data[7]=RxData[2];
				Data[8]=RxData[3];
				Data[9]=RxData[4];
				Data[10]=RxData[5];
				Data[11]=RxData[6]	
			break;
		}
	}
}
 
/* USER CODE END 0 */
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
  /* USER CODE END 1 */
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ETH_Init();
  MX_USART3_UART_Init();
  MX_USB_OTG_FS_PCD_Init();
  MX_CAN1_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
 
  HAL_TIM_Base_Start_IT(&htim3);
 
  HAL_CAN_Start(&hcan1);
  //***Activate the Notification**********
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
 
  TxHeader.DLC=8;	//data length
  TxHeader.IDE=CAN_ID_STD;
  TxHeader.RTR=CAN_RTR_DATA;
  TxHeader.StdId=0x767;	//ID
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  ILI9486_Initialization();
  Clear_Screen(0x0000);
  tft_string(10,10,0xFFFF, 0x0000,12,"Discharge Temperature:");
  tft_string(10,30,0xFFFF, 0x0000,12,"Suction Temperature:");
  tft_string(10,50,0xFFFF, 0x0000,12,"Condenser Outlet Temperature:");
  tft_string(10,70,0xFFFF, 0x0000,12,"IHX Outlet Temperature:");
  tft_string(10,90,0xFFFF, 0x0000,12,"Evaporator Inlet Temperature:");
  tft_string(10,110,0xFFFF, 0x0000,12,"Evaporator Temperature:");
  tft_string(10,130,0xFFFF, 0x0000,12,"MCU's Temperature:");
 
  Write_Command(0x29);	// Display ON
 
  CAN_Bus_Start_Init();
  while (1)
  {
	  //********Defining_Parameters_from_Slave_MCU*************************************
	  switch(datacheck)
	  {
		case 1:
			Td=Data[0];
			Ts=Data[1];
			Tc2=Data[2];
			Tih=Data[3];
			Te1=Data[4];
			Tev=Data[5];
			CAN_Request=1;
		break;
		case 2:
			T_MCU=(Data[7]<<8|Data[6]);
			Ps_R=(Data[9]<<8|Data[8]);
			Pd_R=(Data[11]<<8|Data[10]);
			Temp=(int8_t)(((V25-(3.3*T_MCU/4095))/Avg_Slope)+25);
			Psuct=(float)(3.3*Ps_R/4095);		//Voltage from Suction Pressure Sensor
			Psuct=(Psuct-0.26)/0.2;				//For Danfoss Pressure Ratiometric Transmitter NSK-BE10I-U169 with 3.3V Supply
			Pd=(float)(3.3*Pd_R/4095);			//Voltage from Discharge Pressure Sensor
			Pd=(Pd-0.27)*15.38;					//For Danfoss Pressure Ratiometric Transmitter NSK-BE30I-U169 with 3.3V Supply
			CAN_Request=2;
		break;
	  }
		tft_integer(140,10,0x07FF, 0x0000,12,Td, 5);
		tft_integer(140,30,0x07FF, 0x0000,12,Ts, 5);
		tft_integer(200,50,0x07FF, 0x0000,12,Tc2, 5);
		tft_integer(200,70,0x07FF, 0x0000,12,Tih, 5);
		tft_integer(200,90,0x07FF, 0x0000,12,Te1, 5);
		tft_integer(200,110,0x07FF, 0x0000,12,Tev, 5);
		tft_integer(200,130,0x07FF, 0x0000,12,Temp, 5);
 
		tft_float(200,10,0xF800, 0x0000,12,Pd, 6);
		tft_float(200,30,0xF800, 0x0000,12,Psuct, 6);
 
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
 
/* USER CODE BEGIN 4 */
//********CAN_Bus_Requests**************************************************************************
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim==&htim3)
	{
		  switch(CAN_Request)
		  {
			case 1:
				TxData[0]='R';
				TxData[1]='P';
				HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxData, &TxMailbox);
				HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin);
			break;
			case 2:
				TxData[0]='R';
				TxData[1]='T';
				HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxData, &TxMailbox);
				HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
			break;
		  }
		  //CAN_Request=0;
		  HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
	}
}
//**************************************************************************************************
/* USER CODE END 4 */

datacheck should be volatile, you change it outside of program flow, ie interrupt/callback

You should perhaps flag each packet type differently. Not clear why you inter-stage the data the way you do.

You should definitely queue things, or build with the understanding that you might get multiple messages before the timer dispatches a response.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Lina_DABASINSKAITE
Community manager
Community manager

@Community member​ I Post has been restored.

Sunday, March 12, 2023 10:51 PM

@USolar​ 

Now that I think about it. What you're doing is like a master/slave communication. CAN is message based so the node that you're communicating with should just periodically send the Temperature and Humidity data.

So now instead, your node that is showing the data on a screen, is just receiving the CAN data as it interrupts. You don't have to send a request.

Then your device that is sending the temp/humidity doesn't have to wait for a request message . to send the data. It just sends it periodically, like every 1 second or longer. Temperature and Humidity isn't going to change rapidly so there is no need to have it send data updates any faster.

This should then simplify your FW.


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.

Thank you guys, for advices.

I did, periodical data transmition from CAN Slave to Master. All works fine, the data are getting to the Master.

But, I have another problem.

How to combine the received data to an array in the CAN Master's HAL_CAN_RxFifo0MsgPendingCallback function? Otherwise, the data overlapping.

Karl Yamashita
Lead III

I see you have one message saved to Data 0-5 and another message saved to 6-11. I'm not sure what you mean by overlapping?

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.
USolar
Associate III

Sorry, probably I've used not correct word.

I meant, insted of reading Data 1 I read Data 2.

The same with 2nd message, instead of reading Data 7 I read Data 8.

Karl Yamashita
Lead III

Sounds like the node that is sending isn't sending the bytes in correct order?

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.