cancel
Showing results for 
Search instead for 
Did you mean: 

UART communication problem. No reception

bvale.2
Associate II

Hello

I am trying to communicate with a Daly BMS in UART. I tried at first with an arduino board where I got the desired frame but when I tried with a custom made STM32F072 board. But during this test I can't get any response from the BMS.

The BMS working perfectly with the module provided and with the arduino, the error can only come from the STM32. The frame to be sent is the following: 0xA5 01 90 08 00 00 00 00 00 00 00 00 7D and should normally answer me: 0xA5 01 90 08 03 8B 00 00 75 30 01 D6 48

and this is my code for the STM32:

uint8_t txBuffer[XFER_BUFFER_LENGTH];
uint8_t rxBuffer[XFER_BUFFER_LENGTH];
 
txBuffer[0] = 0xA5; // Start byte
txBuffer[1] = 0x40; // Host address
txBuffer[3] = 0x08; // Length
 
for (uint8_t i = 4; i < 12; i++){	//remplir les data: 4 à 11
	txBuffer[i] = 0x00;
}
txBuffer[2] = 0x90;
 
uint8_t checksum = 0;
for (uint8_t i = 0; i <= 11; i++){// Calculate the checksum
	checksum += txBuffer[i];
}
txBuffer[12] = checksum;
 
for(int i =0; i< XFER_BUFFER_LENGTH;i++){
	printf("%02x ", txBuffer[i]);
}
 
HAL_UART_Transmit(&huart4, txBuffer, sizeof(txBuffer), HAL_MAX_DELAY);
HAL_Delay(10);
HAL_UART_Receive(&huart4, rxBuffer, 1, HAL_MAX_DELAY);
 
printf("Receive: ");
for(int i = 0; i<XFER_BUFFER_LENGTH; i++){
	printf("%02x ", rxBuffer[i]);
}

I thought I had no answer because of the protocol voltage levels. Here is the BMS data provided by the manufacturer:

Tx: 0< 0.5V; 1 Open circuit,

Rx: 0< 0.5V; 1> 3V

My STM32 operating at 3.3V its high voltage levels should be understood by the BMS. 

I also made a test by sending the frame on the serial port which is used to me as output debug, I received the good frame and the reception went well when I answered by hand.

I can't understand the problem, can you help me?

Thank you in anticipation of your reply.

Valentin

8 REPLIES 8

You don't check for errors returned.

You request a single byte.

You use delays.

You use blocking functions in a sequential fashion.

Suggest you implement something that can handle concurrent reception into a buffer, and clears any pending errors or status that might prevent further reception. ​

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
AScha.3
Chief II

+ you need a pullup on Tx line (Tx: 0< 0.5V; 1 Open circuit,) - is it there ?

If you feel a post has answered your question, please click "Accept as Solution".

Hello

I'm sorry I didn't correct it but the reception of a single byte was to test if I recovered at least one element.

Do you mean that I should go through an interrupt reception? If yes I had tried at the beginning with a code already used but either I did not enter the interrupt or I received only 2 characters.

I will put a copy of this code too.

I set Tx to pull up and nothing on Rx.

char 	rx_data;
int 	rx_index;
 
uint8_t txBuffer[XFER_BUFFER_LENGTH];	// donnée à transmettre au BMS
uint8_t rxBuffer[XFER_BUFFER_LENGTH];	// donnée recu du BMS
 
void setup(){
	memset(rxBuffer, 0, XFER_BUFFER_LENGTH);	// effacer le buffer
 
 
	printf("--- Convertisseur ---\r\n");
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);
 
	txBuffer[0] = 0xA5; // Start byte
	txBuffer[1] = 0x40; // Host address
	txBuffer[3] = 0x08; // Length
	for (uint8_t i = 4; i < 12; i++){	//remplir les data: 4 à 11
		txBuffer[i] = 0x00;
	}
 
	txBuffer[2] = 0x90;
	uint8_t checksum = 0;
	for (uint8_t i = 0; i <= 11; i++){// Calculate the checksum
		checksum += txBuffer[i];
	}
	txBuffer[12] = checksum;
 
 
	printf("envoi: ");
	for(int i =0; i< XFER_BUFFER_LENGTH;i++){
		printf("%02x ", txBuffer[i]);
	}
	printf("\r\n");
	HAL_UART_Transmit(&huart4, txBuffer, sizeof(txBuffer), HAL_MAX_DELAY);
 
 
	//HAL_UART_Receive(&huart4, rxBuffer, XFER_BUFFER_LENGTH, HAL_MAX_DELAY);	// on lance la lecture des octées arrivant
 
	rx_data = 0;
	rx_index = 0;
	HAL_UART_Receive_IT(&huart4, (uint8_t*) &rx_data, 1);	// on lance la lecture des octées arrivant
	/*
	printf("Reception: ");
	for(int i = 0; i<XFER_BUFFER_LENGTH; i++){
		printf("%02x ", rxBuffer[i]);
	}*/
}
 
void UART_CallBack(){
	printf("%02x - %d\r\n", rx_data, rx_index);
 
	if (rx_data != '\n' && rx_index < XFER_BUFFER_LENGTH) {	// on rajoute dans la liste tant que pas '\n'
		rxBuffer[rx_index++] = rx_data;
	} else {	// fin de la trame
		printf("fin \r\n");
 
		rx_index = 0;
		memset(rxBuffer, 0, sizeof(rxBuffer));
		return;
	}
	HAL_UART_Receive_IT(&huart4, (uint8_t*) &rx_data, 1);
}
 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
	if(huart == &huart4){
		UART_CallBack();
	}
}

The answer I get is the following with only 3 bytes:

0x A5 01 30, and the 3rd byte does not match what I should receive.

Karl Yamashita
Lead II

Your buffer routine has some flaws as i was getting the wrong value for byte 3 as well. I'm not even sure why byte 3 is not the correct value as all other bytes were correct?

Also it looks like you're trying to receive binary data but yet you're looking for a LF terminator. If the binary data returns a 0x0A within the data, then it's going to reset your index pointer. Unless you already anticipate it will never do so?

Instead of HAL_UART_Receive_IT use HAL_UARTEx_ReceiveToIdle_DMA. I find that it streamlines the receive process so much easier.

You'll need to enable DMA for the UART Rx.

I ran this code

#include "main.h"
#include "PollingRoutine.h"
 
extern UART_HandleTypeDef huart2;
 
#define XFER_BUFFER_LENGTH 32
uint8_t rxBuffer[XFER_BUFFER_LENGTH];
uint8_t txBuffer[XFER_BUFFER_LENGTH];
 
bool dataRdy = false;
uint32_t sizeReceived;
 
// called before main while loop
void PollingInit(void)
{
	HAL_UARTEx_ReceiveToIdle_DMA(&huart2, (uint8_t*) &rxBuffer, XFER_BUFFER_LENGTH);
}
 
// main while lopp
void PollingRouine(void)
{
	UART_ParseData();
}
 
void UART_ParseData(void)
{
	if(dataRdy)
	{
		dataRdy = false;
 
		// do something with data. For now just transmit it
		memcpy(&txBuffer, &rxBuffer, sizeReceived);
		HAL_UART_Transmit_IT(&huart2, txBuffer, sizeReceived);
	}
}
 
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart->Instance == huart2.Instance)
	{
		dataRdy = true;
		sizeReceived = Size;
		HAL_UARTEx_ReceiveToIdle_DMA(&huart2, (uint8_t*) &rxBuffer, XFER_BUFFER_LENGTH);
	}
}

Blue is what i sent to the STM32 and red is my reply

0693W00000aIpqnQAC.png 

If you find my answers useful, click the accept button so that way others can see the solution.
Karl Yamashita
Lead II

Now that I had more time to look. In your UART_CallBack you are clearing rxBuffer when you receive a LF so your rxBuffer is now empty. Then you use return so HAL_UART_Receive_IT is never called so now you will no longer receive an interrupt. Those two lines should be removed. You can clear rxBuffer after you parsed the data.

void UART_CallBack(){
	printf("%02x - %d\r\n", rx_data, rx_index);
 
	if (rx_data != '\n' && rx_index < XFER_BUFFER_LENGTH) {	// on rajoute dans la liste tant que pas '\n'
		rxBuffer[rx_index++] = rx_data;
	} else {	// fin de la trame
		printf("fin \r\n");
 
		rx_index = 0;
	//	memset(rxBuffer, 0, sizeof(rxBuffer));
	//	return;
	}
	HAL_UART_Receive_IT(&huart4, (uint8_t*) &rx_data, 1);
}

But you still have the issue that if the data contains a 0x0A then the index pointer will reset. You're better off still using the DMA routine I've posted.

If you find my answers useful, click the accept button so that way others can see the solution.

Thanks for the help using the DMA routine I managed to get the right frame from the BMS. I will then keep the DMA in my code.

But do you have any idea how to retrieve a 0x0A value without it resetting the index pointer?