Skip to main content
Associate
June 5, 2024
Question

Voltage Sense with multichannel ADC DMA

Hello everyone,

 

I have designed my own card and used F103 uC on it. I want to measure battery voltage with DMA method. I hope to drive BLDC motor with this card one day :) So i need to measure phase voltages and BUS battery voltage. Due to speed issues, i thought DMA would be much better option. 

 

So, forget about the phase voltages first. I just want to sense battey voltage.  I have defined some variables. I have voltage driver on the same line so i need to multiply every array value with multiplier. I eant to write buffer values to data array for true measurement of the voltage. Then i want to send this scaled values to my computer.

 

#define Buffer_Size 5

uint16_t V_BATT_ADC_Buffer[Buffer_Size]={0};
uint16_t V_BATT_ADC_Data[Buffer_Size]={0};
float V_BATT_ADC = 0.0;
float V_BATT = 0.0;
uint8_t V_BATT_Sense_Conv_End = 0;
float multiplier_V_BATT = (3.3/4095)*(100+5.6)/5.6;

 

void multiplyArray(uint16_t *array, size_t size, float multiplier) // Array multiplication function
{
for (size_t i = 0; i < size; i++)
{
array[i] = (uint16_t)(array[i] * multiplier);

}
}

 

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) // Get value with DMA and write it when Conv. Cmp. to other array function
{
if (hadc == &hadc3)
{

for(int i = 0 ; i<Buffer_Size; i++)
{
V_BATT_ADC_Data[i] = V_BATT_ADC_Buffer[i];
}
V_BATT_Sense_Conv_End=1;
}
}

 

int main(void)

....

....

HAL_ADC_Start_DMA(&hadc3, (uint32_t *)V_BATT_ADC_Buffer, Buffer_Size);

 

while(1)
........

........

if(V_BATT_Sense_Conv_End == 1)
{

size_t size = sizeof(V_BATT_ADC_Buffer)/sizeof(V_BATT_ADC_Buffer[0]);
multiplyArray(V_BATT_ADC_Buffer, size, multiplier_V_BATT);

char str[80];
int V_BATT_txlength = sprintf(str, "ADC Value: %d, Battery Voltage Level: %dV\r\n", V_BATT_ADC_Data[0], V_BATT_ADC_Data[1]);
HAL_UART_Transmit(&huart1, (uint8_t*)str, V_BATT_txlength, 100);

HAL_Delay(500);
V_BATT_Sense_Conv_End=0;
}

}

 

As summary, i want to sense battery voltage with dma then write it to an array then multiply this array according to my voltage divider and send it to my computer. I know it is little long but any help would be appreciated. 

This topic has been closed for replies.

9 replies

Karl Yamashita
Principal
June 6, 2024

Use the code sample button so your code is properly formatted for easy reading.

Code Snippet.jpg

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
Associate
June 6, 2024

Thanks a lot:victory_hand:

 

#define Buffer_Size 5


void V_Sense_BATT(void);
void multiplyArray(uint16_t *V_BATT_ADC_Buffer, size_t size, float multiplier);


ADC_HandleTypeDef hadc3;


uint16_t V_BATT_ADC_Buffer[Buffer_Size]={0};
uint16_t V_BATT_ADC_Data[Buffer_Size]={0};
float V_BATT_ADC = 0.0;
float V_BATT = 0.0;
uint8_t V_BATT_Sense_Conv_End = 0;
float multiplier_V_BATT = (3.3/4095)*(100+5.6)/5.6;

static void MX_DMA_Init(void);
static void MX_ADC3_Init(void);

void multiplyArray(uint16_t *array, size_t size, float multiplier)
{
 for (size_t i = 0; i < size; i++)
 {
 array[i] = (uint16_t)(array[i] * multiplier);
 }
}



void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
 if (hadc == &hadc3)
 {

 	for(int i = 0 ; i<Buffer_Size; i++)
 	{
 		V_BATT_ADC_Data[i] = V_BATT_ADC_Buffer[i];
 	}
 	V_BATT_Sense_Conv_End=1;
 }
}


int main(void)
{
 HAL_ADC_Start_DMA(&hadc3, (uint32_t *)V_BATT_ADC_Buffer, Buffer_Size);
 while (1)
 {
 if(V_BATT_Sense_Conv_End == 1)
 {

 	size_t size = sizeof(V_BATT_ADC_Buffer)/sizeof(V_BATT_ADC_Buffer[0]);
 		multiplyArray(V_BATT_ADC_Buffer, size, multiplier_V_BATT);

 	char str[80];
 	 int V_BATT_txlength = sprintf(str, "ADC Data 1: %d, ADC Data 2: %dV\r\n", V_BATT_ADC_Data[0], V_BATT_ADC_Data[1]);
 	 HAL_UART_Transmit(&huart1, (uint8_t*)str, V_BATT_txlength, 100);
 	 HAL_Delay(500);
 	 V_BATT_Sense_Conv_End=0;
 }

 }
}



 

Karl Yamashita
Principal
June 7, 2024

You seem to be transmitting the battery voltage correctly. So I guess i'm not understanding the issue? 

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
LCE
Principal III
June 7, 2024

When using DMA, you should not use the ADC conversion complete, but rather the DMA complete flag / interrupt.

And yes - at least on F7 / H7 - once started with HAL_ADC_Start_DMA() it runs forever unless stopped actively.
I actually like that for power monitoring: ADC / DMA is running constantly in the background, but I only check every few 100 ms by simply checking the ADC DMA buffer. 

You showed only snippets of your main code, correct? Because there's no inits called...

 

Associate
June 7, 2024

Thanks for your reply.



@LCE wrote:

When using DMA, you should not use the ADC conversion complete, but rather the DMA complete flag / interrupt.




So you say i dont have to use;

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)

What should i use instead of that? Can you please elaborate :)

 


@LCE wrote:

 

And yes - at least on F7 / H7 - once started with HAL_ADC_Start_DMA() it runs forever unless stopped actively.
I actually like that for power monitoring: ADC / DMA is running constantly in the background, but I only check every few 100 ms by simply checking the ADC DMA buffer. 

 


Actually i was planning to check battery voltage every 1 seconds  but measure phase voltages like every commutation. So i have to use  conversion end flag for them.

 


@LCE wrote:

You showed only snippets of your main code, correct? Because there's no inits called...

 


Yes :)

LCE
Principal III
June 7, 2024

> What should i use instead of that? Can you please elaborate

Good question...

I think you can also activate DMA complete interrupts and callbacks.

As I said, I don't use these, just check the buffer when needed.