简体   繁体   English

我无法使用ADC正确配置STM32F411RE DMA

[英]I cannot configure my STM32F411RE DMA with ADC correctly

I am attempting to use the STM32F411RE DMA with ADC to obtain 2048 samples each for 3 input channels / pins. 我试图将STM32F411RE DMA与ADC结合使用,以获取3个输入通道/引脚各自的2048个样本。 The A0, A1 and A2 pins are connected to a sensor for which image processing (Fourier Transform) is to be used. A0,A1和A2引脚连接到要使用图像处理(傅立叶变换)的传感器。

I thus use the DMA / ADC to fill the adc_buffer[6144] with all the 2048 samples from the 3 pins, using an interrupt to find when this buffer is full. 因此,我使用DMA / ADC用来自3个引脚的所有2048个采样填充adc_buffer[6144] ,并使用中断来查找该缓冲区何时已满。 When the buffer is full the data should be converted to voltages and put into the correct bin (data goes x, y, z, x, y, z). 当缓冲区已满时,应将数据转换为电压并放入正确的仓中(数据进入x,y,z,x,y,z)。

Whilst I have all of that working for some reason my DMA circular buffer does not fill up with data. 尽管由于某种原因我可以进行所有操作,但我的DMA循环缓冲区未填充数据。 In a previous program this worked fine but I can now no longer make this work: adc_buffer remains 0 throughout program run and as such the ISR HAL_ADC_ConvCpltCallback is never triggered. 在以前的程序中,此方法运行良好,但现在无法进行工作:在程序运行期间adc_buffer始终为0,因此从不触发ISR HAL_ADC_ConvCpltCallback


#include "main.h"
#include "arm_const_structs.h"
#include "core_cm4.h"
#include "math.h"
#include "arm_math.h"
#include <stdio.h>
#include <stdbool.h>
#include "main.h"

ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
UART_HandleTypeDef huart2;

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_USART2_UART_Init(void);

float adc_buffer[6144] = {0}; // 2048 samples * 3 channels

/*
 * Interrupt called when the input buffer adc_buffer is full.
 * TO DO: Add   void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)  for double buffering, when conversion is half complete also run Fourier transform
 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if(hadc->Instance == ADC1)  //  if(hadc->Instance == ADC1 && !conversionPaused)
    {
        conversionPaused = 1;   // Temporarily disable the conversion process
        for (int samples= 0; samples < fftLen; samples++)   // Allocates data from the 1 ADC buffer into the 3 separate axis buffers
        {
            Xin[samples] = ((3.3-0)/4096) * adc_buffer[0+3*samples];    // Allocate samples to X array, whilst transforming them into voltage: every 3rd value starting at 0 (0, 3, 6, 9)
            Yin[samples] = ((3.3-0)/4096) * adc_buffer[1+3*samples];    // Allocate samples to X array, whilst transforming them into voltage: every 3rd value starting at 1 (1, 4, 7, 10)
            Zin[samples] = ((3.3-0)/4096) * adc_buffer[2+3*samples];    // Allocate samples to X array, whilst transforming them into voltage: every 3rd value starting at 2 (2, 5, 8, 11)
        }
    }
}

int main(void)
{

    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_ADC1_Init();
    MX_USART2_UART_Init();

    HAL_ADC_Start_IT(&hadc1);
    HAL_ADC_Start_DMA(&hadc1, adc_buffer, bufferLen);   // Maybe DMA and ADC IT are mutually exclusive?

    while (1)
    {
        // Signal processing on Xin, Yin, Zin
    }


/**
  * @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 
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 393;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  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_DIV8;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV8;

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

/**
  * @brief ADC1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_ADC1_Init(void)
{
  ADC_ChannelConfTypeDef sConfig = {0};

  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ENABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;           // Maybe this needs to be set to off for use with the circular buffer?
  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 = 3;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.EOCSelection = DISABLE; //ADC_EOC_SINGLE_CONV
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
  */
  sConfig.Channel = ADC_CHANNEL_0;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = 2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
  */
  sConfig.Channel = ADC_CHANNEL_4;
  sConfig.Rank = 3;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief USART2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{

  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
}

/** 
  * Enable DMA controller clock
  */
static void MX_DMA_Init(void) 
{
  /* DMA controller clock enable */
  __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);
}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{

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

}

I suspect that the problem lies in the configuration of the ADC and DMA, on which I can find little literature. 我怀疑问题出在ADC和DMA的配置上,在这些配置上我几乎找不到文献。 A number of examples 1 2 3 4 are available, but this offers little remedy as their code appears the same as mine. 可以使用许多示例1 2 3 4 ,但是由于它们的代码与我的代码相同,因此几乎没有补救措施。



As an edit to the response by Tarick Welling I do not seem to get the full package when generating my code in CubeMX. 作为Tarick Welling对响应的编辑,在CubeMX中生成代码时,我似乎没有获得完整的软件包。 Particularly I am missing the full MX_DMA_Init() as mine only generates the following: 特别是我缺少完整的MX_DMA_Init()因为我的只会生成以下内容:

static void MX_DMA_Init(void) 
{
  /* DMA controller clock enable */
  __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);
}

However this is despite my settings in CubeMX being configured so that this should be generated, as per the image below: 但是,尽管我在CubeMX中的设置被配置为可以生成,但如下图所示:

CubeMX DMA生成

I am thoroughly confused as to why this code is not being generated in CubeMX for me, whilst for others it apparently is. 我对为什么没有在CubeMX中生成此代码感到困惑,而对于其他人则显然如此。

MX_DMA_Init doesn't initialize hdma_adc1 . MX_DMA_Init不初始化hdma_adc1 So the DMA isn't able to be used. 因此无法使用DMA。

hadc1.Init.DMAContinuousRequests = DISABLE; disables continuous use of the DMA so it will be a single shot transfer. 禁用DMA的连续使用,因此它将是单次传输。

uint32_t DMAContinuousRequests; Specify whether the DMA requests are performed in one shot mode (DMA transfer stops when number of conversions is reached) or in continuous mode (DMA transfer unlimited, whatever number of conversions). Specify whether the DMA requests are performed in one shot mode (DMA transfer stops when number of conversions is reached)还是以continuous mode (DMA transfer unlimited, whatever number of conversions). Specify whether the DMA requests are performed in one shot mode (DMA transfer stops when number of conversions is reached) continuous mode (DMA transfer unlimited, whatever number of conversions). This parameter can be set to ENABLE or DISABLE. 此参数可以设置为ENABLE或DISABLE。 Note: In continuous mode, DMA must be configured in circular mode. 注意:在连续模式下,必须在循环模式下配置DMA。 Otherwise an overrun will be triggered when DMA buffer maximum pointer is reached. 否则,当达到DMA缓冲区最大指针时,将触发溢出。

The ADC isn't initialized to use the DMA so it doesn't even know to use it. ADC没有初始化为使用DMA,因此它甚至都不知道要使用它。

typedef struct
{
  ADC_TypeDef                   *Instance;              /*!< Register base address */

  ADC_InitTypeDef               Init;                   /*!< ADC required parameters */

  DMA_HandleTypeDef             *DMA_Handle;            /*!< Pointer DMA Handler */

  HAL_LockTypeDef               Lock;                   /*!< ADC locking object */

  __IO uint32_t                 State;                  /*!< ADC communication state (bitmap of ADC states) */

  __IO uint32_t                 ErrorCode;              /*!< ADC Error code */
}ADC_HandleTypeDef;

DMA_Handle needs to be initialized for the ADC to use the DMA. 需要初始化DMA_Handle ,ADC才能使用DMA。

This can be set up inside CubeMX by adding a line to DMA Settings of your ADC configuration on the Configuration tab: 可以通过在“ Configuration选项卡上的ADC配置的“ DMA Settings中添加一行来在CubeMX中进行DMA Settings 添加到ADC的DMA流的图像 Further settings can be set by selecting this DMA transfer and configuring its parameters in the bottom part of the dialog. 可以通过选择此DMA传输并在对话框的底部配置其参数来设置其他设置。

Please note that ST makes use of a form of delegated initialization. 请注意,ST使用委托初始化的形式。 HAL_ADC_Init calls a user defined HAL_ADC_MspInit . HAL_ADC_Init调用用户定义的HAL_ADC_MspInit This is defined inside stm32f4xx_hal_msp.c and should link the ADC to the DMA. 这是在stm32f4xx_hal_msp.c内部stm32f4xx_hal_msp.c ,应将ADC链接到DMA。 It should contain a line similar to: __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1); 它应该包含类似于以下内容的行: __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM