Обратный вызов DMA возвращает одно и то же значение каждый цикл - PullRequest
0 голосов
/ 04 июля 2019

В настоящее время я работаю с STM32f407G-DISC1 и пытаюсь перехватить буфер с помощью АЦП и обратного вызова DMA.

Генератор частоты подключен к контакту A0, и плата заземлена. Я проверил, что мои провода не были повреждены осциллографом.

Теперь проблема в том, что после настройки моего проекта и его компиляции обратный вызов DMA вызывается каждый раз, когда мой буфер заполняется. Моя проблема заключается в том, что при каждом вызове буфер заполняется одинаковыми значениями.

Я сделал точно такой же проект на доске STM32F401RE. Код примерно такой же, за исключением кода, сгенерированного с помощью CUBEMX. Сначала я подумал, что допустил ошибку в CUBEMX, поэтому я попытался сгенерировать другой проект, используя другой АЦП на плате. Но я получил точно такой же результат. Также я попытался использовать другую доску (у меня их две); Тот же результат.

ADC_HandleTypeDef       hadc1;
volatile uint32_t       ADCValue1[1];

void                    main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  HAL_ADC_Start_DMA(&hadc1, (uint32_t *) ADCValue1, 1);

  while (1) {}
  return;
}

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 = 8;
  RCC_OscInitStruct.PLL.PLLN = 84;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  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_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

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

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_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  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 = 1;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SEQ_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_3CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

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);

}

static void             MX_GPIO_Init(void)
{
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
}

/* This is the callback called each time my buffer is filled */
void DMA2_Stream0_IRQHandler(void)
{
    if ((DMA2->LISR & DMA_LISR_TCIF0) && (DMA2_Stream0->CR & DMA_SxCR_TCIE))
        DMA2->LIFCR = DMA_LIFCR_CTCIF0;  // acknowledge interrupt
    DMA_IRQHandler(); // The function where I want to process my buffer
    return;
/* transmission complete interrupt */
}

void                    DMA_IRQHandler(void)
{
    return;
}

Каждый раз, когда я вхожу в обратный вызов, мой буфер заполняется одинаковыми значениями вместо разных значений.

Если у вас есть идеи ... Если вам нужно больше кода, просто спросите, и я предоставлю его.

Ответы [ 2 ]

1 голос
/ 04 июля 2019

Если код, который вы не удосужились опубликовать, работает правильно, то буфер будет содержать самые последние чтения DMA каждый раз, когда вызывается обработчик прерываний.

Но компилятор не может знать, что буфер модифицирован оборудованием DMA, потому что он не объявлен как volatile.

0 голосов
/ 04 июля 2019

Есть две очевидные проблемы:

  • Буферы DMA всегда должны быть объявлены volatile, иначе компилятор может выполнить странную оптимизацию, если поймет, что переменная не обновляется программным обеспечением. Почему раздувание ST не принимает volatile квалифицированный параметр, это отличный вопрос для ST - возможно, еще одна ошибка в их библиотеках.

  • Объявление функции

    HAL_ADC_Start_DMA (ADC_HandleTypeDef *hadc, uint32_t *pData, uint32_t Length) 
    

    Это означает, что вы, естественно, должны передать uint32_t *, а не что-то еще. Вместо этого вы передаете unsigned short*, который вы превращаете грубой силой в uint32_t*. Это дает 2 ошибки: обратный вызов может записывать за пределами и / или смещаться в вашу 16-битную переменную. И это также строгое нарушение алиасинга .

...