2024-07-27 08:33 AM
i m using an stm 32 microcontroller to read adc channel, this is my approch: discontinuous DMA requests in Normal Mode and single conversion adc for multiple channels, i want the adc channels to be read 20 times in a row, with a frequency of 1Khz using Tim6, and be printed through USART2. when I give the order "sample" in the serial monitor, the tim6 is triggered, and start an stops the DMA and prints the values for 20 times. the Problem is, that i get values that make no sense, but they re the same every time, even when the microcontroller pins are not connected to different signals (from 0V to 3V) or to anything. Here is my code:
------------------------------------------------------------------------------
1. in main.c
-------------------------------------------------------------------------------
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_MultiModeTypeDef multimode = {0};
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
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 = 6;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_6;
sConfig.Rank = ADC_REGULAR_RANK_3;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_7;
sConfig.Rank = ADC_REGULAR_RANK_4;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = ADC_REGULAR_RANK_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_11;
sConfig.Rank = ADC_REGULAR_RANK_6;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
/**
* @brief ADC2 Initialization Function
* @PAram None
* @retval None
*/
static void MX_ADC2_Init(void)
{
/* USER CODE BEGIN ADC2_Init 0 */
/* USER CODE END ADC2_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC2_Init 1 */
/* USER CODE END ADC2_Init 1 */
/** Common config
*/
hadc2.Instance = ADC2;
hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc2.Init.Resolution = ADC_RESOLUTION_12B;
hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc2.Init.ContinuousConvMode = DISABLE;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.NbrOfConversion = 2;
hadc2.Init.DMAContinuousRequests = ENABLE;
hadc2.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc2.Init.LowPowerAutoWait = DISABLE;
hadc2.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
if (HAL_ADC_Init(&hadc2) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_3;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_9;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC2_Init 2 */
/* USER CODE END ADC2_Init 2 */
}
static void MX_TIM6_Init(void)
{
/* USER CODE BEGIN TIM6_Init 0 */
/* USER CODE END TIM6_Init 0 */
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM6_Init 1 */
/* USER CODE END TIM6_Init 1 */
htim6.Instance = TIM6;
htim6.Init.Prescaler = 63;
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
htim6.Init.Period = 999;
htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM6_Init 2 */
/* USER CODE END TIM6_Init 2 */
}
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
/* DMA1_Channel2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_ADC2_Init();
MX_TIM1_Init();
MX_TIM2_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
MX_SPI1_Init();
MX_TIM6_Init();
MX_TIM7_Init();
/* USER CODE BEGIN 2 */
UART_Init(&huart2)
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM6) {
// Timer 6 interrupt triggered
USART_Send_Debug_Message("TIM6 Interrupt Triggered\n");
// Start ADC DMA
StartADC1_DMA();
StartADC2_DMA();
PrintLoggedValues();
// Increment sample counter
sample_counter++;
StopADC1_DMA();
StopADC2_DMA();
if (sample_counter >= 20) {
// Stop Timer 6 after 20 samples
HAL_TIM_Base_Stop_IT(htim);
//StopADC1_DMA();
//StopADC2_DMA();
sample_counter = 0;
}
}
}
------------------------------------------------------------------------------
2.adc.c
------------------------------------------------------------------------------
#include "adc.h"
#include "stm32f3xx_hal_adc.h"
#include <unistd.h>
#define FULL_SCALE 4095.0f
#define VREFINT_CAL 1.2f //(*((uint16_t*) ((uint32_t) 0x1FFFF7BA))) not going to use it because not accurate
#define R1 150000.0f // 150 kΩ
#define R2 2000.0f // 2 kΩ
uint32_t adcValues1[NUM_CHANNELS_ADC1]; // Buffer to store ADC1 values
uint32_t adcValues2[NUM_CHANNELS_ADC2]; // Buffer to store ADC2 values
uint16_t test_array1[40];
uint32_t sample_counter=0;
//First Part: channel Reading
// Function to start ADC1 DMA
void StartADC1_DMA(void) {
USART_Send_Debug_Message("Starting ADC1 DMA\n");
if (HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adcValues1, NUM_CHANNELS_ADC1) != HAL_OK) {
USART_Send_Debug_Message("Error starting ADC1 DMA\n");
Error_Handler();
}
USART_Send_Debug_Message("ADC1 DMA started\n");
}
// Function to start ADC2 DMA
void StartADC2_DMA(void) {
USART_Send_Debug_Message("Starting ADC2 DMA\n");
if (HAL_ADC_Start_DMA(&hadc2, (uint32_t*)adcValues2, NUM_CHANNELS_ADC2) != HAL_OK) {
USART_Send_Debug_Message("Error starting ADC2 DMA\n");
Error_Handler();
}
}
// Function to stop ADC1 DMA
void StopADC1_DMA(void) {
HAL_ADC_Stop_DMA(&hadc1);
USART_Send_Debug_Message("Stopped ADC1 DMA\n");
}
// Function to stop ADC2 DMA
void StopADC2_DMA(void) {
HAL_ADC_Stop_DMA(&hadc2);
USART_Send_Debug_Message("Stopped ADC2 DMA\n");
}
// Function to read DC voltage
float ADC_ReadDCVoltage(void) {
uint32_t adc_voltage_value = adcValues1[0];
float V_DC_Measure_Unit = (3.3f * adc_voltage_value) / FULL_SCALE;
float voltage_DC = V_DC_Measure_Unit / (R2 / (5*R1 + R2));
return voltage_DC;
}
// Function to calculate temperature from ADC value
float ADC_ReadTemperature(void) {
uint32_t adc_temp_value = adcValues1[1];
float V_T_Measure_Unit = (3.3f * adc_temp_value) / FULL_SCALE;
float temperature_C = (V_T_Measure_Unit - 600) / 10;
return temperature_C;
}
// Function to calculate current U from ADC value
float ADC_ReadCurrentU(void) {
uint32_t adc_current_value = adcValues1[2];
float V_IU_Measure_Unit = (3.3f * adc_current_value) / FULL_SCALE;
float current_U = (V_IU_Measure_Unit - 1650) / (-44.0f);
return current_U;
}
// Function to calculate current V from ADC value
float ADC_ReadCurrentV(void) {
uint32_t adc_current_value = adcValues1[3];
float V_IV_Measure_Unit = (3.3f * adc_current_value) / FULL_SCALE;
float current_V = (V_IV_Measure_Unit - 1650) / (-44.0f);
return current_V;
}
// Function to calculate current W from ADC value
float ADC_ReadCurrentW(void) {
uint32_t adc_current_value = adcValues1[4];
float V_IW_Measure_Unit = (3.3f * adc_current_value) / FULL_SCALE ;
float current_W = (V_IW_Measure_Unit - 1650) / (-44.0f);
return current_W;
}
//Function to calculate voltage U from ADC value
float ADC_ReadVoltageU(void) {
uint32_t adc_voltage_value = adcValues2[1];
float V_VU_Measure_Unit = (3.3f * adc_voltage_value) / FULL_SCALE;
float voltage_U = V_VU_Measure_Unit / (R2 / (4*R1 + R2));
return voltage_U;
}
// Function to calculate voltage V from ADC value
float ADC_ReadVoltageV(void) {
uint32_t adc_voltage_value = adcValues1[5];
float V_VV_Measure_Unit = (3.3f * adc_voltage_value) / FULL_SCALE;
float voltage_V = V_VV_Measure_Unit / (R2 / (4*R1 + R2));
return voltage_V;
}
// Function to calculate voltage W from ADC value
float ADC_ReadVoltageW(void) {
uint32_t adc_voltage_value = adcValues2[0];
float V_VW_Measure_Unit = (3.3f * adc_voltage_value) / FULL_SCALE;
float voltage_W = V_VW_Measure_Unit;
return voltage_W;
}
//second Part: Printing
void StartLogging(void) {
USART_Send_Debug_Message("Starting Logging\n");
sample_counter = 0;
// Start Timer 6
if (HAL_TIM_Base_Start_IT(&htim6) != HAL_OK) {
USART_Send_Debug_Message("Error starting TIM6\n");
Error_Handler();
} else {
USART_Send_Debug_Message("TIM6 started successfully\n");
}
}
void PrintLoggedValues(void) {
float IU = ADC_ReadCurrentU();
float IV = ADC_ReadCurrentV();
float IW = ADC_ReadCurrentW();
float VU = ADC_ReadVoltageU();
float VV = ADC_ReadVoltageV();
float VW = ADC_ReadVoltageW();
float DC = ADC_ReadDCVoltage();
float Temp = ADC_ReadTemperature();
char buffer[256];
sprintf(buffer, "IU: %f, IV: %f, IW: %f, VU: %f, VV: %f, VW: %f, DC: %f, Temp: %f\n",
IU, IV, IW, VU, VV, VW, DC, Temp);
USART_Send_Debug_Message(buffer);
}
void test(void){
for (uint32_t j = 0; j < 40; j++) {
test_array1[j] = j;
}
for (uint32_t i = 0; i < 40; i++) {
printf("test1[%lu]: %u\n", i, test_array1[i]);
}
}
int _write(int file, char *data, int len) {
if (file == STDOUT_FILENO || file == STDERR_FILENO) {
HAL_UART_Transmit(&huart2, (uint8_t*)data, len, HAL_MAX_DELAY);
return len;
}
return -1;
}
------------------------------------------------------------------------------
3. adc.h
------------------------------------------------------------------------------
#ifndef INC_ADC_H_
#define INC_ADC_H_
#include "stm32f3xx_hal.h"
#include "stm32f3xx_hal_def.h"
#include "usart.h"
void USART_Send_Debug_Message(const char* message);
// Handles
extern ADC_HandleTypeDef hadc1;
extern ADC_HandleTypeDef hadc2;
extern DMA_HandleTypeDef hdma_adc1;
extern DMA_HandleTypeDef hdma_adc2;
extern TIM_HandleTypeDef htim6;
#define NUM_CHANNELS_ADC1 6
#define NUM_CHANNELS_ADC2 2
// DMA start/stop functions
void StartADC1_DMA(void);
void StartADC2_DMA(void);
void StopADC1_DMA(void);
void StopADC2_DMA(void);
// Buffer to store ADC values
extern uint32_t adcValues1[NUM_CHANNELS_ADC1];
extern uint32_t adcValues2[NUM_CHANNELS_ADC2];
extern uint16_t test_array1[40];
extern uint32_t sample_counter;
float ADC_ReadDCVoltage(void);
float ADC_ReadTemperature(void);
float ADC_ReadCurrentU(void);
float ADC_ReadCurrentV(void);
float ADC_ReadCurrentW(void);
float ADC_ReadVoltageU(void);
float ADC_ReadVoltageV(void);
float ADC_ReadVoltageW(void);
//for sampling
void PrintLoggedValues(void);
void StartLogging(void);
void test(void);
#endif /* INC_ADC_H_ */
------------------------------------------------------------------------------
4. usart.c
------------------------------------------------------------------------------
#include "usart.h"
#include "adc.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
uint8_t rx_buffer[RX_BUFFER_SIZE];
uint8_t rx_data;
void UART_Init(UART_HandleTypeDef *huart)
{
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE); // Enable RX interrupt
HAL_UART_Receive_IT(huart, &rx_data, 1); // Start reception with interrupt
USART_Send_Debug_Message("UART Init complete\n"); // Debug message
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART2)
{
static uint16_t rx_index = 0;
if (rx_data != '\n' && rx_index < RX_BUFFER_SIZE - 1)
{
rx_buffer[rx_index++] = rx_data;
}
else
{
rx_buffer[rx_index] = '\0';
UART_ProcessCommand(huart);
rx_index = 0; // Reset buffer index after processing
}
HAL_UART_Receive_IT(huart, &rx_data, 1); // Re-enable interrupt
}
}
void UART_ProcessCommand(UART_HandleTypeDef *huart) {
if (strncmp((char *)rx_buffer, "sample", 9) == 0) {
StartLogging();
HAL_UART_Transmit(huart, (uint8_t *)"Logging finished\n", 16, HAL_MAX_DELAY);
}
memset(rx_buffer, 0, RX_BUFFER_SIZE); // Clear buffer after processing
}
void USART_Send_Debug_Message(const char* message) {
HAL_UART_Transmit(&huart2, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);
}
2024-07-29 02:36 AM
Hello @johnjones,
Increase ADC sampling time
sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5; // Increase sampling time
Also, for the DMA buffer size
uint32_t adcValues1[NUM_CHANNELS_ADC1 * 20]; // Buffer to store ADC1 values for 20 samples
uint32_t adcValues2[NUM_CHANNELS_ADC2 * 20];
and maybe add some debug messages to trace the flow of execution
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2024-07-29 05:55 AM
Hello Sarra, thanke you for the response 🙂
since the ADC s are being read and printed only once, each time the DMA starts and stops, and since the DMA starts and stops for 20 consecutive times, shouldn t the buffers be equal to the number of channels?
and the next higher sampling time is 61.5 cycles do you think i should choose it?