bigbat 发表于 2024-2-18 12:24

【STM32U5A5ZJ开发板】 ADC DMA测试及UART输出

<p>STM32U5A5ZJ开发板使用的芯片配置有多达3个ADC通道,分别为ADC1、ADC2、ADC4,ADC1通道的采样为14bit,使用超采样技术可以达到16bit,本次测试只使用了ADC4通道配合GPDMA进行采集,ST公司虽然配置了STM32Cube的STM32U5XXX的设置,但是却没有提供HAL库的相关设置只提供了部分较为底层的LL库设置代码。所以需要更加深入的了解芯片的相关设置。</p>

<p>1、芯片的时钟设置。</p>

<p>STM32U5A5ZJ的时钟设置对于较为基础的STM32F系列增加了很多低功耗的设置,本身ST的时钟功能就较为丰富导致设置比较复杂,增加了低功耗以后就又增加了复杂度。希望各位网友有关ST公司较为完整的全面的中文资料请告知。</p>

<p>&nbsp; 本次测试使用外部晶振,所以不涉及低功耗内容。</p>

<p>&nbsp; ADC的时钟也相应的设置为HSE,设置ADC的工作时钟为16MHZ。<em>个人经验:外部时钟似乎能够提高ADC的稳定性,没有严格验证</em></p>

<p>2、ADC通道设置</p>

<p>&nbsp; 本次测试使用ADC4通道配合GPDMA采集,设置为ADC4的IN4通道引脚PC3,</p>

<p> &nbsp;</p>

<p>ADC4通道的设置除了通道设置外还有几个较为重要的设置,</p>

<p>(1)采样率设置,时钟分频设置为1,ADC4通道的工作频率为HSE的16MHZ,采样时间周期为1.5个采样周期,</p>

<p>(2)采样精度,设置为12bit,因为ADC4最高为12bit</p>

<p>(3)ADC4的DMA设置需要转到GPDMA的设置。</p>

<p>&nbsp; 上图为具体的设置。</p>

<p>3、GPDMA设置</p>

<p>DMA通道设置为10,模式为Linked-List,这是一种新的DMA内存模式,传统的DMA只能使用连续的内存块,所以对内存的要求较为严格,因此DMA的长度受到一定的限制。而链接表结构则可以不使用连续的内存空间。但是结构较为复杂。GPDMA的设置为两个重要部分,</p>

<p>(1)工作模式设置,工作模式为连续模式,端口为Port1&nbsp; (2)LINKED链接表设置</p>

<p>除了工作模式外,还需要设置链接表,ST公司提供了链接表的设置工具。链接实际为数据结构中的队列结构。</p>

<p>&nbsp; 找到LINKEDLIST项目,设置GPDMA的各项参数,主要设置:队列名称:ADCQueue,链表数据结构:GPDMA,工作模式:Circular,队列头指针:ADCNode</p>

<p>&nbsp; 指针节点设置。</p>

<p>4、main主程序</p>

<p>程序主要是引入DMA队列控制初始化和ADC工作设置。</p>

<pre>
<code class="language-cpp">/* USER CODE BEGIN Header */
/**
******************************************************************************
* @File : main.c
* @brief : Main program body
******************************************************************************
* @attention *
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include &lt;stdio.h&gt;
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#if defined(__ICCARM__)
/* New definition from EWARM V9, compatible with EWARM8 */
int iar_fputc(int ch);
#define PUTCHAR_PROTOTYPE int putchar(int ch)
#elif defined ( __CC_ARM ) || defined(__ARMCC_VERSION)
/* ARM Compiler 5/6*/
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#elif defined(__GNUC__)
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#endif /* __ICCARM__ */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
uint32_t uhADCxConvertedData_Voltage_mVolt = 0;/* Value of voltage calculated from ADC conversion data (unit: mV) */
/* USER CODE END PM */
#define ADC_CONVERTED_DATA_BUFFER_SIZE   ((uint32_t)32)   /* Size of array aADCxConvertedData[] */
uint32_t aADCxConvertedData;

/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc4;

DMA_HandleTypeDef handle_GPDMA1_Channel10;

UART_HandleTypeDef hlpuart1;
UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void SystemPower_Config(void);
static void MX_GPIO_Init(void);
static void MX_GPDMA1_Init(void);
static void MX_ADC4_Init(void);
static void MX_LPUART1_UART_Init(void);
static void MX_ICACHE_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
* @briefThe application entry point.
* @retval int
*/
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();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* Configure the System Power */
SystemPower_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_GPDMA1_Init();
MX_ADC4_Init();
MX_LPUART1_UART_Init();
MX_ICACHE_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
MX_ADCQueue_Config();
__HAL_LINKDMA(&amp;hadc4, DMA_Handle, handle_GPDMA1_Channel10);
if (HAL_DMAEx_List_LinkQ(&amp;handle_GPDMA1_Channel10, &amp;ADCQueue) != HAL_OK)
{
    Error_Handler();
}
if (HAL_ADC_Start_DMA(&amp;hadc4,
                        (uint32_t *)aADCxConvertedData,
                        (ADC_CONVERTED_DATA_BUFFER_SIZE)
                     ) != HAL_OK)
{
    Error_Handler();
}
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
    /* USER CODE END WHILE */
                HAL_Delay(200);
                for(uint16_t i=0;i&lt;ADC_CONVERTED_DATA_BUFFER_SIZE;i++)
    {
                                uhADCxConvertedData_Voltage_mVolt += aADCxConvertedData;
                }
               
                printf("mVolt=%d \n",uhADCxConvertedData_Voltage_mVolt/ADC_CONVERTED_DATA_BUFFER_SIZE);
                uhADCxConvertedData_Voltage_mVolt = 0;
    /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

/** Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
    Error_Handler();
}

/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMBOOST = RCC_PLLMBOOST_DIV1;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 20;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLLVCIRANGE_1;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&amp;RCC_OscInitStruct) != HAL_OK)
{
    Error_Handler();
}

/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_PCLK3;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV1;

if (HAL_RCC_ClockConfig(&amp;RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
    Error_Handler();
}
}

/**
* @brief Power Configuration
* @retval None
*/
static void SystemPower_Config(void)
{

/*
   * Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral
   */
HAL_PWREx_DisableUCPDDeadBattery();

/*
   * Switch to SMPS regulator instead of LDO
   */
if (HAL_PWREx_ConfigSupply(PWR_SMPS_SUPPLY) != HAL_OK)
{
    Error_Handler();
}
/* USER CODE BEGIN PWR */
/* USER CODE END PWR */
}

/**
* @brief ADC4 Initialization Function
* @param None
* @retval None
*/
static void MX_ADC4_Init(void)
{

/* USER CODE BEGIN ADC4_Init 0 */

/* USER CODE END ADC4_Init 0 */

ADC_ChannelConfTypeDef sConfig = {0};

/* USER CODE BEGIN ADC4_Init 1 */

/* USER CODE END ADC4_Init 1 */

/** Common config
*/
hadc4.Instance = ADC4;
hadc4.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc4.Init.Resolution = ADC_RESOLUTION_12B;
hadc4.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc4.Init.ScanConvMode = ADC4_SCAN_DISABLE;
hadc4.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc4.Init.LowPowerAutoPowerOff = ADC_LOW_POWER_NONE;
hadc4.Init.LowPowerAutoWait = DISABLE;
hadc4.Init.ContinuousConvMode = DISABLE;
hadc4.Init.NbrOfConversion = 1;
hadc4.Init.DiscontinuousConvMode = DISABLE;
hadc4.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc4.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc4.Init.DMAContinuousRequests = DISABLE;
hadc4.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_LOW;
hadc4.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc4.Init.SamplingTimeCommon1 = ADC4_SAMPLETIME_1CYCLE_5;
hadc4.Init.SamplingTimeCommon2 = ADC4_SAMPLETIME_1CYCLE_5;
hadc4.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&amp;hadc4) != HAL_OK)
{
    Error_Handler();
}

/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = ADC4_REGULAR_RANK_1;
sConfig.SamplingTime = ADC4_SAMPLINGTIME_COMMON_1;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&amp;hadc4, &amp;sConfig) != HAL_OK)
{
    Error_Handler();
}
/* USER CODE BEGIN ADC4_Init 2 */

/* USER CODE END ADC4_Init 2 */

}

/**
* @brief GPDMA1 Initialization Function
* @param None
* @retval None
*/
static void MX_GPDMA1_Init(void)
{

/* USER CODE BEGIN GPDMA1_Init 0 */

/* USER CODE END GPDMA1_Init 0 */

/* Peripheral clock enable */
__HAL_RCC_GPDMA1_CLK_ENABLE();

/* USER CODE BEGIN GPDMA1_Init 1 */

/* USER CODE END GPDMA1_Init 1 */
handle_GPDMA1_Channel10.Instance = GPDMA1_Channel10;
handle_GPDMA1_Channel10.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
handle_GPDMA1_Channel10.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
handle_GPDMA1_Channel10.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT1;
handle_GPDMA1_Channel10.InitLinkedList.TransferEventMode = DMA_TCEM_LAST_LL_ITEM_TRANSFER;
handle_GPDMA1_Channel10.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
if (HAL_DMAEx_List_Init(&amp;handle_GPDMA1_Channel10) != HAL_OK)
{
    Error_Handler();
}
if (HAL_DMA_ConfigChannelAttributes(&amp;handle_GPDMA1_Channel10, DMA_CHANNEL_NPRIV) != HAL_OK)
{
    Error_Handler();
}
/* USER CODE BEGIN GPDMA1_Init 2 */

/* USER CODE END GPDMA1_Init 2 */

}

/**
* @brief ICACHE Initialization Function
* @param None
* @retval None
*/
static void MX_ICACHE_Init(void)
{

/* USER CODE BEGIN ICACHE_Init 0 */

/* USER CODE END ICACHE_Init 0 */

/* USER CODE BEGIN ICACHE_Init 1 */

/* USER CODE END ICACHE_Init 1 */

/** Enable instruction cache in 1-way (direct mapped cache)
*/
if (HAL_ICACHE_ConfigAssociativityMode(ICACHE_1WAY) != HAL_OK)
{
    Error_Handler();
}
if (HAL_ICACHE_Enable() != HAL_OK)
{
    Error_Handler();
}
/* USER CODE BEGIN ICACHE_Init 2 */

/* USER CODE END ICACHE_Init 2 */

}

/**
* @brief LPUART1 Initialization Function
* @param None
* @retval None
*/
static void MX_LPUART1_UART_Init(void)
{

/* USER CODE BEGIN LPUART1_Init 0 */

/* USER CODE END LPUART1_Init 0 */

/* USER CODE BEGIN LPUART1_Init 1 */

/* USER CODE END LPUART1_Init 1 */
hlpuart1.Instance = LPUART1;
hlpuart1.Init.BaudRate = 115200;
hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;
hlpuart1.Init.StopBits = UART_STOPBITS_1;
hlpuart1.Init.Parity = UART_PARITY_NONE;
hlpuart1.Init.Mode = UART_MODE_TX_RX;
hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
hlpuart1.FifoMode = UART_FIFOMODE_DISABLE;
if (HAL_UART_Init(&amp;hlpuart1) != HAL_OK)
{
    Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&amp;hlpuart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
    Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&amp;hlpuart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
    Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&amp;hlpuart1) != HAL_OK)
{
    Error_Handler();
}
/* USER CODE BEGIN LPUART1_Init 2 */

/* USER CODE END LPUART1_Init 2 */

}

/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
static void MX_USART1_UART_Init(void)
{

/* USER CODE BEGIN USART1_Init 0 */

/* USER CODE END USART1_Init 0 */

/* USER CODE BEGIN USART1_Init 1 */

/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&amp;huart1) != HAL_OK)
{
    Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&amp;huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
    Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&amp;huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
    Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&amp;huart1) != HAL_OK)
{
    Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */

/* USER CODE END USART1_Init 2 */

}

/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART1 and Loop until the end of transmission */
HAL_UART_Transmit(&amp;huart1, (uint8_t *)&amp;ch, 1, 0xFFFF);

return ch;
}
/* USER CODE END 4 */

/**
* @briefThis function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}

#ifdefUSE_FULL_ASSERT
/**
* @briefReports the name of the source file and the source line number
*         where the assert_param error has occurred.
* @paramfile: pointer to the source file name
* @paramline: 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 /* USE_FULL_ASSERT */
</code></pre>

<p>ADC工作设置</p>

<pre>
<code class="language-cpp">__HAL_LINKDMA(&amp;hadc4, DMA_Handle, handle_GPDMA1_Channel10);
if (HAL_DMAEx_List_LinkQ(&amp;handle_GPDMA1_Channel10, &amp;ADCQueue) != HAL_OK)
{
    Error_Handler();
}
if (HAL_ADC_Start_DMA(&amp;hadc4,
                        (uint32_t *)aADCxConvertedData,
                        (ADC_CONVERTED_DATA_BUFFER_SIZE)
                     ) != HAL_OK)
{
    Error_Handler();
}</code></pre>

<p>首先连接DMA通道10和ADC4的句柄,__HAL_LINKDMA(&amp;hadc4, DMA_Handle, handle_GPDMA1_Channel10);</p>

<p>连接后开始ADC采集,HAL_ADC_Start_DMA(&amp;hadc4,&nbsp;(uint32_t *)aADCxConvertedData,&nbsp;(ADC_CONVERTED_DATA_BUFFER_SIZE)&nbsp;)</p>

<p>ADC为循环模式,工作开始后就可以自动的进行采集。</p>

<p>主程序中每个200毫秒,将采集数据平均后输出。</p>

<p> &nbsp;</p>

<p> &nbsp;</p>

<p>本次测试,可以发现测试的精度较为准确,可以达到1个mV的精度,但是这个精度是我的输出仪器的精度,不是ADC的精度。</p>

lugl4313820 发表于 2024-2-18 17:05

<p>呀大佬的什么数据电源,可以达到这么好的精度,介绍介绍呀。</p>

bigbat 发表于 2024-2-18 17:15

lugl4313820 发表于 2024-2-18 17:05
呀大佬的什么数据电源,可以达到这么好的精度,介绍介绍呀。

<p>简易过程校准仪,就是用来输出各种信号的</p>

lugl4313820 发表于 2024-2-18 19:35

bigbat 发表于 2024-2-18 17:15
简易过程校准仪,就是用来输出各种信号的

<p>这神器贵不贵呀,我特别需要一个输了精准的信号源。</p>
页: [1]
查看完整版本: 【STM32U5A5ZJ开发板】 ADC DMA测试及UART输出