STM32F4 Wie stoppe ich den Triple-Interleaved-Modus?

Ich verwende den dreifach verschachtelten Modus mit DMA in STM32F429 und habe Probleme, ihn zu stoppen.

Es sollte durch gestoppt werden HAL_ADCEx_MultiModeStop_DMA(&hadc1), aber beim Debuggen gibt es HAL_DMA_ERROR_NO_XFEReinen Fehler während HAL_DMA_Abortder Funktion. Ich vermute, es denkt, dass DMA beschäftigt ist, aber ich gebe HAL_ADCEx_MultiModeStop_DMA(&hadc1)in aus HAL_ADC_ConvCpltCallback, was impliziert, dass die Konvertierung abgeschlossen ist (und ich verwende auch den normalen Modus, nicht den Zirkularmodus, sodass keine Übertragungen stattfinden sollten).

Ich starte die Konvertierung per Tastendruck, die erste Konvertierung funktioniert, aber da ADC nicht gestoppt wird, erfolgt die zweite Konvertierung (beim zweiten Tastendruck) nie. Ich habe den kreisförmigen Modus überprüft - er funktioniert gut, die Daten werden ständig aktualisiert.

Ich habe einige Erwähnungen dieses Fehlers im Internet gefunden (wie dies und das , aber nicht viel Hilfe.

Hier ist mein Code, hoffe, dass alles klar ist. Ich habe einige nicht verwandte Dinge wie RCC-Konfiguration, CubeMX-Boilerplate usw. weggelassen.
Ich habe bereits versucht, ADC2 und ADC3 auszuschalten, bevor ich ADC1 gestoppt habe (obwohl sie nach ADC1 gestoppt zu sein scheinen, basierend auf diesem Beispiel. Es ist für STM32F3, aber ich nehme an, es ist ähnlich in F4 auch).
Ich habe versucht, den DMA-Zugriffsmodus 2 zu verwenden, aber aus dem Datenblatt bin ich sicher, dass es der Zugriffsmodus 3 sein muss, da ich eine 8-Bit-Auflösung verwende.
Ich habe auch versucht, zwischen BYTE, HALFWORD und WORD zu wechseln PeriphDataAlignment, MemDataAlignmentaber auch kein Ergebnis.
Es wurde auch versucht, die Hauptfunktion nach einiger Verzögerung einzubauen HAL_ADCEx_MultiModeStop_DMA(&hadc1)(obwohl die Verwendung im Rückruf vielleicht nicht gut ist), aber es ändert nichts.

Ich habe keine Ahnung, was ich tun soll, habe hier und da 5 Stunden lang Code geändert, ohne Ergebnis.

stm32f4xx_hal_msp.c

void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(hadc->Instance==ADC1)
  {
  /* USER CODE BEGIN ADC1_MspInit 0 */

  /* USER CODE END ADC1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_ADC1_CLK_ENABLE();

    /**ADC1 GPIO Configuration    
    PA3     ------> ADC1_IN3 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* Peripheral DMA init*/

    hdma_adc1.Instance = DMA2_Stream0;
    hdma_adc1.Init.Channel = DMA_CHANNEL_0;
    hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_adc1.Init.Mode = DMA_NORMAL;
    hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);

  /* USER CODE BEGIN ADC1_MspInit 1 */

  /* USER CODE END ADC1_MspInit 1 */
  }
  else if(hadc->Instance==ADC2)
  {
  /* USER CODE BEGIN ADC2_MspInit 0 */

  /* USER CODE END ADC2_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_ADC2_CLK_ENABLE();

    /**ADC2 GPIO Configuration    
    PA3     ------> ADC2_IN3 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN ADC2_MspInit 1 */

  /* USER CODE END ADC2_MspInit 1 */
  }
  else if(hadc->Instance==ADC3)
  {
  /* USER CODE BEGIN ADC3_MspInit 0 */

  /* USER CODE END ADC3_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_ADC3_CLK_ENABLE();

    /**ADC3 GPIO Configuration    
    PA3     ------> ADC3_IN3 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN ADC3_MspInit 1 */

  /* USER CODE END ADC3_MspInit 1 */
  }

}

Haupt c

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_hal.h"
#include "usb_device.h"

/* USER CODE BEGIN Includes */
#include "usbd_cdc_if.h"
#define ADC_BUFFER_LENGTH 14
/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;
ADC_HandleTypeDef hadc3;
DMA_HandleTypeDef hdma_adc1;

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
uint8_t ADCBuffer[ADC_BUFFER_LENGTH];
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void Error_Handler(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_ADC3_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
    HAL_ADCEx_MultiModeStop_DMA(&hadc1);
    HAL_ADC_Stop(&hadc3);   // Although it doesn't matter
    HAL_ADC_Stop(&hadc2);   // since prev function returns error
}
/* 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_USB_DEVICE_Init();
    MX_ADC3_Init();
    MX_ADC2_Init();
  MX_ADC1_Init();

  /* USER CODE BEGIN 2 */
    HAL_Delay(1500);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
        if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 1)
        {
            HAL_ADC_Start(&hadc3);
            HAL_ADC_Start(&hadc2);
            HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*) &ADCBuffer, ADC_BUFFER_LENGTH);
            HAL_Delay(500);
        }
  }
  /* USER CODE END 3 */

}

/* ADC1 init function */
static 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_CLOCK_SYNC_PCLK_DIV2;
  hadc1.Init.Resolution = ADC_RESOLUTION_8B;
  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 = DISABLE;
  hadc1.Init.EOCSelection = 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_3;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

        /**Configure the ADC multi-mode 
    */
  multimode.Mode = ADC_TRIPLEMODE_INTERL;
  multimode.DMAAccessMode = ADC_DMAACCESSMODE_3;
  multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }

}

/* ADC2 init function */
static 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_CLOCK_SYNC_PCLK_DIV2;
  hadc2.Init.Resolution = ADC_RESOLUTION_8B;
  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 = DISABLE;
  hadc2.Init.EOCSelection = DISABLE;
  if (HAL_ADC_Init(&hadc2) != 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_3;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

}

/* ADC3 init function */
static void MX_ADC3_Init(void)
{

  ADC_MultiModeTypeDef multimode;
  ADC_ChannelConfTypeDef sConfig;

    /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
    */
  hadc3.Instance = ADC3;
  hadc3.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
  hadc3.Init.Resolution = ADC_RESOLUTION_8B;
  hadc3.Init.ScanConvMode = DISABLE;
  hadc3.Init.ContinuousConvMode = ENABLE;
  hadc3.Init.DiscontinuousConvMode = DISABLE;
  hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc3.Init.NbrOfConversion = 1;
  hadc3.Init.DMAContinuousRequests = DISABLE;
  hadc3.Init.EOCSelection = DISABLE;
  if (HAL_ADC_Init(&hadc3) != 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_3;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != 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);

}

static void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

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

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  None
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler */
  /* User can add his own implementation to report the HAL error return state */
  while(1) 
  {
  }
  /* USER CODE END Error_Handler */ 
}
Das ist das Problem mit HAL. Es ist äußerst schwierig, es in einer komplexeren Konfiguration zum Laufen zu bringen. Probieren Sie die bloßen Register aus, und Sie erhalten die Kontrolle zurück, ohne diese lächerlichen Bibliotheken lesen zu müssen
@ PeterJ_01, ich denke darüber nach. Das einzige, was mich zurückhält, ist, dass ich bezweifle, dass ich einen guten "idiotensicheren" Code machen kann, wie vielleicht werde ich versuchen, einige Register während der Verarbeitung zu ändern, und es wird den Mikrocontroller beschädigen. Obwohl es unwahrscheinlich ist, aber immer noch irgendwie beängstigend. Ich denke, ich muss mich eingehend mit der inneren Konfiguration vertraut machen und versuchen, sie zu implementieren. Nun, ich werde zurückschreiben, wenn ich eine Lösung dafür habe.
registers during processing and it will corrupt the microcontrollerGlauben Sie nicht alles, was Sie im Internet gefunden haben. ICH
Versuchen Sie, den Deaktivierungs-Interrupt von DMA nicht mehr zu verwenden. Wenn Sie die nächsten Daten abrufen möchten, aktivieren Sie ihn einfach.

Antworten (2)

Das ist das Problem mit HAL. Es ist äußerst schwierig, es in einer komplexeren Konfiguration zum Laufen zu bringen. Probieren Sie die nackten Register aus, und Sie erhalten die Kontrolle zurück, ohne diese lächerlichen Bibliotheken lesen zu müssen – PeterJ_01 08 sep. 17 um 23:37 Uhr

HAL_ADCEx_MultiModeStop_DMA setzt den Status auf HAL_ADC_STATE_ERROR_DMA, da die HAL_DMA_Abort-Funktion HAL_DMA_ERROR_NO_XFER zurückgibt. Eine mögliche Lösung besteht darin, dieses Bit durch Aufrufen von CLEAR_BIT zu löschen:

HAL_ADCEx_MultiModeStop_DMA(&hadc1);
CLEAR_BIT(hadc1.State, HAL_ADC_STATE_ERROR_DMA);