cancel
Showing results for 
Search instead for 
Did you mean: 

Frustrated with UART&ADC dual mode

ardavantycoon
Associate II
Posted on February 24, 2016 at 13:56

I am really got tired after so many attempt to use this hal drivers for ADC sampling in dual mode and send data over uart. For god sake plz help me. I did whatever user manuals said but still no output.

This is the code:

/**
/* Includes ------------------------------------------------------------------*/
include ''stm32f4xx_hal.h''
/* USER CODE BEGIN Includes */
include <
stdio.h
>
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;
DMA_HandleTypeDef hdma_adc1;
DMA_HandleTypeDef hdma_adc2;
UART_HandleTypeDef huart3;
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
//__IO uint16_t ADC_val[2]={0};
char senddata1[20];
char senddata2[20];
__IO uint32_t ADC_val=0;
__IO uint16_t ADC1_val=0;
__IO uint16_t ADC2_val=0;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_ADC1_Init(void);
static void MX_ADC2_Init(void);
static void MX_USART3_UART_Init(void);
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_ADC2_Init();
MX_USART3_UART_Init();
/* USER CODE BEGIN 2 */
HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)&ADC_val, 2);
//HAL_ADC_Start(&hadc1);
//HAL_ADC_Start(&hadc2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/** System Clock Configuration
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
__PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/* ADC1 init function */
void MX_ADC1_Init(void)
{
ADC_MultiModeTypeDef multimode;
ADC_ChannelConfTypeDef sConfig;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV8;
hadc1.Init.Resolution = ADC_RESOLUTION12b;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.EOCSelection = EOC_SINGLE_CONV;
HAL_ADC_Init(&hadc1);
/**Configure the ADC multi-mode 
*/
multimode.Mode = ADC_DUALMODE_REGSIMULT;
multimode.DMAAccessMode = ADC_DMAACCESSMODE_2;
multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode);
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
*/
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
/* ADC2 init function */
void MX_ADC2_Init(void)
{
ADC_MultiModeTypeDef multimode;
ADC_ChannelConfTypeDef sConfig;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
*/
hadc2.Instance = ADC2;
hadc2.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV8;
hadc2.Init.Resolution = ADC_RESOLUTION12b;
hadc2.Init.ScanConvMode = DISABLE;
hadc2.Init.ContinuousConvMode = ENABLE;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.NbrOfConversion = 1;
hadc2.Init.DMAContinuousRequests = ENABLE;
hadc2.Init.EOCSelection = EOC_SINGLE_CONV;
HAL_ADC_Init(&hadc2);
/**Configure the ADC multi-mode 
*/
multimode.Mode = ADC_DUALMODE_REGSIMULT;
multimode.DMAAccessMode = ADC_DMAACCESSMODE_2;
multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
HAL_ADCEx_MultiModeConfigChannel(&hadc2, &multimode)

;

/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
HAL_ADC_ConfigChannel(&hadc2, &sConfig);
}
/* USART3 init function */
void MX_USART3_UART_Init(void)
{
huart3.Instance = USART3;
huart3.Init.BaudRate = 256000;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart3);
}
/** 
* Enable DMA controller clock
*/
void MX_DMA_Init(void) 
{
/* DMA controller clock enable */
__DMA2_CLK_ENABLE();
/* DMA interrupt init */
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
}
/** Pinout Configuration
*/
void MX_GPIO_Init(void)
{
/* GPIO Ports Clock Enable */
__GPIOA_CLK_ENABLE();
__GPIOB_CLK_ENABLE();
}
/* USER CODE BEGIN 4 */
//void ADC_MultiModeDMAConvCplt(DMA_HandleTypeDef *hdma) {
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){
ADC_val=HAL_ADCEx_MultiModeGetValue(&hadc1);
ADC1_val=(ADC_val)&0xFFFF; //extract lower 16 bit
ADC2_val=(ADC_val>>16)&0xFFFF; //extract higher 16 bit
sprintf(senddata1,''data1:%d'', ADC1_val); 
sprintf(senddata2,''data2:%d'', ADC2_val); 
HAL_UART_Transmit(&huart3, (uint8_t*)&senddata1,20,10000);
HAL_UART_Transmit(&huart3, (uint8_t*)&senddata2,20,10000);
}
/* USER CODE END 4 */
ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d\r\n'', file, line) */
/* USER CODE END 6 */
}
endif
/**
* @}
*/ 
/**
* @}
*/ 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

uart-flag no-hablo-hal usart-adc-multi-mode waste-of-time at-last-i-see-light usart-dma-adc wonder-question
14 REPLIES 14
frame
Associate
Posted on February 26, 2016 at 18:27

I didn't use the ADC dual-mode (or triple mode) yet - IMHO it makes only sense if one needs to achieve a higher sampling frequency, e.g. for motor control applications.

I have applications using two ADCs, but managing ADC trigger and DMA TC interrupt separately. Data rate is ''only'' 1 ksps (for 1 .. 8 channels).

The order of channels in the DMA buffer should be described in the ref. manual. I think there are SPL example, however I never tried.

Posted on February 26, 2016 at 19:41

The examples I have posted use much larger buffers to decimate the interrupt loading, and by using HT (half transfer) and TC (transfer complete) interrupts you are afforded the ability to process/move the data without the circular DMA changing the values underneath you. Provided you can deal with it in the available half buffer window time the data in your current half of the buffer will be static.

If I was recording to a MicroSD card I'd shovel the data to a larger holding buffer in the IRQ, and then flush the data to the card in the foreground

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
ardavantycoon
Associate II
Posted on March 01, 2016 at 14:36

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6fL&d=%2Fa%2F0X0000000bsj%2FMvqwS51ifWbys94HI18rlWOrRffDtOxYWKrIMBzdYUU&asPdf=false
Posted on March 01, 2016 at 14:56

You dig yourself into a hole pretty deep.

Have a large ADC buffer to hold the waveforms.

At HT/TC, memcpy those into a holding buffer, waiting for TXE as you send each byte. This way the data won't change during the transfer.

Ideally do one buffer so you don't transfer discontinuities as you confirm the functionality.

A single channel does not scan. Channels = 1, Scan = Disable

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
ardavantycoon
Associate II
Posted on March 02, 2016 at 07:49

I have change sample cycle from 480 to 28. it works very well till frequency of 1KHz. Above that it start to degrade. I change ADC clock in order to make higher sample rate but it fails, even decreasing ADC clock make it worse! 

Approximately the sample rate is :

(ADC prescaler=8 and prescaler peripheral clock=2)

sample rate= 168MHz/(2*8*28)=375 KHz

1KHz input

0690X00000605MaQAI.png

6KHz inpu

t0690X00000605NEQAY.png

A single channel does not scan. Channels = 1, Scan = Disable

I will turn the scan off.

Ideally do one buffer so you don't transfer discontinuities as you confirm the functionality.

 

I thought this is the way of doing that. DMA interrupt for each ADC transfer and UART send with higher transfer rate than sampling rate.

I set DMA is mode 1. you suggest that I use DMA in mode2?

can you give more insights? or maybe a code example.