2023-03-09 02:48 PM
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 */
}
2023-03-09 02:56 PM
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.
2023-03-09 11:31 PM
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.
.
2023-03-12 03:41 AM
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 */
2023-03-12 09:17 AM
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.
2023-03-14 01:25 AM
@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.
2023-03-15 08:27 AM
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.
2023-03-15 08:57 AM
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?
2023-03-15 09:53 AM
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.
2023-03-15 10:04 AM
Sounds like the node that is sending isn't sending the bytes in correct order?