2023-03-13 02:06 AM
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
2023-03-13 02:36 AM
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.
2023-03-13 02:49 AM
+ you need a pullup on Tx line (Tx: 0< 0.5V; 1 Open circuit,) - is it there ?
2023-03-13 03:39 AM
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.
2023-03-13 03:39 AM
I set Tx to pull up and nothing on Rx.
2023-03-13 04:01 AM
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.
2023-03-13 09:34 AM
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
2023-03-13 06:15 PM
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.
2023-03-16 02:09 AM
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?