cancel
Showing results for 
Search instead for 
Did you mean: 

Voltage Sense with multichannel ADC DMA

YalnizKurt
Associate II

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. 

9 REPLIES 9
Karl Yamashita
Lead II

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

Code Snippet.jpg

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

Thanks a lot✌️

 

#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;
         }

     }
}



 

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

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

Problem is i can not see battery voltage readings on CubeIDE Console. For testing the serial connection between my card and computer, i have used some dummy code. Looks like everything is okey. Then i narrow my code down and commented everything until;

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

 It looks like when i start dma, conversion never completes and there is an infinite loop. Could this be the problem?

LCE
Principal

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...

 

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 🙂

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.



You're not showing enough code. Have no idea where you're calling HAL_ADC_Start_DMA from? What do you mean by infinite loop?

Attach your IOC file so we can see your settings. 

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

Hi, sorry for late response. When i start debugger mode, it constantly loops inside HAL library of DMA function. It takes readings but never skips to incomong line.


Again, thanks for your big interest.