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

时间:2019-07-01 10:11:22

标签: c stm32 dma adc

我正尝试将STM32F411RE DMA与ADC结合使用,以获取3个输入通道/引脚各自的2048个采样。 A0,A1和A2引脚连接到要使用图像处理(傅立叶变换)的传感器。

因此,我使用DMA / ADC用来自3个引脚的所有2048个采样填充adc_buffer[6144],并使用中断来查找该缓冲区何时已满。当缓冲区已满时,应将数据转换为电压并放入正确的bin中(数据进入x,y,z,x,y,z)。

尽管由于某种原因我可以进行所有操作,但我的DMA循环缓冲区未填满数据。在以前的程序中,此方法运行良好,但现在无法进行工作:在程序运行期间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();

}

我怀疑问题出在ADC和DMA的配置上,在这些配置上我几乎找不到文献。有许多示例1 2 3 4,但是由于它们的代码看起来与我的代码相同,因此无法提供补救措施。



作为对Tarick Welling响应的编辑,在CubeMX中生成代码时,我似乎没有获得完整的软件包。特别是我错过了完整的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);
}

尽管如此,尽管我已将CubeMX中的设置配置为可以生成,如下图所示:

CubeMX DMA generation

对于为什么没有在我的CubeMX中生成此代码,而对于其他人来说却显然是,我感到非常困惑。

1 个答案:

答案 0 :(得分:2)

MX_DMA_Init未初始化hdma_adc1。因此无法使用DMA。

hadc1.Init.DMAContinuousRequests = DISABLE;禁用DMA的连续使用,因此它将是一次快照传输。

  

uint32_t DMAContinuousRequests; 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).中                                          此参数可以设置为ENABLE或DISABLE。                                          注意:在连续模式下,必须在循环模式下配置DMA。否则,当达到DMA缓冲区最大指针时,将触发溢出。

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需要初始化以使ADC使用DMA。

这可以通过在DMA Settings选项卡上的ADC配置的Configuration中添加一行来在CubeMX中进行设置: image of a DMA stream added to the ADC 通过选择此DMA传输并在对话框的底部配置其参数,可以设置其他设置。

请注意,ST使用委托初始化的形式。 HAL_ADC_Init调用用户定义的HAL_ADC_MspInit。这是在stm32f4xx_hal_msp.c内部定义的,应将ADC链接到DMA。它应该包含类似于以下内容的行:__HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);