2024-01-03 09:59 PM
Hi, so previously on other post I've been getting trouble with Poll Conversion of ADC using STM32F4 Discovery Board. Therefore i decided to use DMA instead.
I made the program using STM32CUBEMX and Keil uVision to read 5 different channels. All data then transmitted via USART.
The problem now is my array (uint16_t adcvalarr[5]) only got the 1st index filled with value. Shown below is the result of transmitted data from Watch window and printf debug window.
Watch Window:
Debug printf viewer (from left to right: iteration number, array[0], array[1], array[2], array[3], array[4])
I have also tried using potentiometer to alter ADC values of each channel but none of it seems to change the value in the array either. Is my ADC fried up or is it just something wrong with my code?
My main.c code is too long so i'll try to put it in the comment instead
===================================================================================
Thanks in advance! Any kind of info/insight will help me greatly.
2024-01-03 10:12 PM
Here's some main parts of my main.c code:
Transmit Data usingUSART
void transmit_data(double_t ii, double_t jj, double_t kk, double_t ll, double_t mm, uint16_t num)
{
sprintf(txData,"%d, %f , %f , %f , %f , %f \n", num, ii, jj, kk, ll, mm);
HAL_UART_Transmit(&huart3, (uint8_t *)txData, strlen(txData), 1000);
++n;
}
ARRAY to hold each CH ADC reading value
uint16_t adcvalarr[5]={0};
// This variable calculate the array length.
// In our case, array size in 5
int adc_channel_count = sizeof(adcvalarr)/sizeof(adcvalarr[0]);
// This flag will help to detect
// the DMA conversion completed or not
uint8_t adc_conv_complete_flag = 0;
main and while loop
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC1_Init();
MX_I2C1_Init();
MX_I2S3_Init();
MX_SPI1_Init();
MX_USB_HOST_Init();
MX_TIM3_Init();
MX_USART3_UART_Init();
MX_TIM4_Init();
MX_DMA_Init();
MX_TIM9_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim3);
// TIM3 CCR3 and CCR2 initialization
TIM3->CCR3 = 0;
TIM3->CCR2 = 0;
//BLINK LED AT STARTUP
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, 1);
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET);
HAL_Delay(500);
n=0;
int i=0;
/* USER CODE END 2 */
while (1)
{
MX_USB_HOST_Process();
// Initialize the DMA conversion
HAL_ADC_Start_DMA(&hadc1, (uint32_t *) adcvalarr , adc_channel_count);
// when adc_conv_complete_flag is set to 1,
// that means DMA conversion is completed
if(adc_conv_complete_flag == 1)
{
transmit_data(adcvalarr[0],adcvalarr[1],adcvalarr[2],adcvalarr[3],adcvalarr[4], n);
printf("%d, %d, %d, %d, %d, %d \n", n,adcvalarr[0],adcvalarr[1],adcvalarr[2],adcvalarr[3],adcvalarr[4]);
// adc_conv_complete_flag variable is set to 0, because,
// we alert this flag variable for new DMA conversion completion
adc_conv_complete_flag = 0;
//BLINK LED AFTER TRANSMITTING DATA
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, 1);
HAL_Delay(50);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_Delay(100);
}
HAL_Delay(100);
} //end while
/* USER CODE END 3 */
}
The ADC initialization
static void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 5;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = 2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
sConfig.Channel = ADC_CHANNEL_3;
sConfig.Rank = 3;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
sConfig.Channel = ADC_CHANNEL_14;
sConfig.Rank = 4;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
sConfig.Channel = ADC_CHANNEL_15;
sConfig.Rank = 5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
DMA Setting
static void MX_DMA_Init(void)
{
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA2_Stream0_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
}
The Conversion Callback if ADC completed it
//TO CHECK IF ADC HAS COMPLETED
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
// I set adc_conv_complete_flag variable to 1 when,
// HAL_ADC_ConvCpltCallback function is call.
adc_conv_complete_flag = 1;
}
2024-01-04 12:41 AM
Hello @dios_kuri,
First of all, make sure your DMA is configured as circular mode and memory address is incremented.
Secondly, it seems your ADC interrupt is triggered at the end of each single conversion. That means, you raised the flag adc_conv_complete_flag after the first conversion.
Let's try by setting ADC EOC selection as follow:
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
Best Regards,
Gwénolé
2024-01-04 06:16 AM - edited 2024-01-04 06:18 AM
Hi @GwenoleB, thanks for your reply.
Sorry i forgot to mention that i already configured circular mode and increment memory address, here i provide a screenshot in case I'm not doing it right. I used Half Word length because i use 12bit ADC mode.
I also have my ADCs Global Interrupt set to Enabled, although it doesn't do much when I change the ADC Global Interrupt setting.
Here are my ADC Parameter settings
Anyway, i tried setting the ADC's EOC as you suggested but the result remains the same...I also tried changing the code so the array get transmitted regardless of the adc_conv_complete_flag condition, to no success either.
2024-01-04 06:28 AM
Read out and check/post content of ADC and relevant DMA registers.
JW
2024-01-04 06:46 AM
Does printf even support doubles here? I would print them as integers instead.
Debug code, see content in adc buffer.
2024-01-05 07:39 PM
Hello, @waclawek.jan.
Thank you for the suggestion. I managed to dig deeper and found this thread that suggest to put DMA init first before ADC init in the void main. The array ends up filled thoroughly, but the reading is still messed up. The read ADC values didnt change when i turned the potentiometer to each pin. It's reading around 1300 when i ground the pin (fluctuatively of course), and my max voltage (when i crank up the potentio, the voltmeter reading is 2.7V with VDD 2.8V) reading just almost 3000 fluctuatively (which should be around 3813 ish). When i pressed reset, it still show messed up values but slightly different (900ish when grounded and 2900 ish on max turn potentiometer).
I am not sure what might caused this
2024-01-05 08:11 PM - edited 2024-01-05 08:12 PM
Hello, @TDK
Do you mean the printf to convert the values to adc buffer? it works just fine. Transmitted data from USART shows several number after the decimal point (works when i transmit my volt and current calculation).
For update, I managed to dig deeper and found this thread that suggest to put DMA init first before ADC init in the void main. The array ends up filled thoroughly, but the reading is still messed up. The read ADC values didnt change when i turned the potentiometer to each pin. It's reading around 1300 when i ground the pin (fluctuatively of course), and my max voltage (when i crank up the potentio, the voltmeter reading is 2.7V with VDD 2.8V) reading just almost 3000 fluctuatively (which should be around 3813 ish). When i pressed reset, it still show messed up values but slightly different (900ish when grounded and 2900 ish on max turn potentiometer).
tl;dr printf double works fine for me. Managed to get the array filled thoroughly but the reading is still messed up.
2024-01-05 08:22 PM
Okay, so it's not printf.
Perhaps your source is high impedance. What resistance is the potentiometer? See if increasing sampling time makes a difference. Try shorting it directly to GND.
2024-01-06 07:18 PM
Hi @TDK. Thank you for keeping up.
Increasing the sampling time to max available (144cycles) does improve its reading on higher voltage level (near the Vdd). When i short it with gnd, however, it still yields result around 800-900ish ADC value. Not quite good.. do you think something might be wrong with my ADC bus itself?
Cheers.