Forum: Mikrocontroller und Digitale Elektronik STM32 DMA Transfer Complete Interrupt


von RH (Gast)


Lesenswert?

Halli zusammen,
ich habe folgendes Problem:

Über einen ADC schreibe ich die Werte mehrerer Channel in den Puffer 
einer DMA mit bekannter Größe. Sobald diese fertig ist möchte ich die 
Daten schnellmöglich berarbeiten. Daher möchte ich mit:

HAL_DMA_RegisterCallback(&DmaHandle, HAL_DMA_XFER_CPLT_CB_ID, 
TransferComplete);

eine Funktion bestimmen, die beim Transfer Complete Interrupt auslöst.

Wenn ich das so mache wird meine Funktion allerdings nicht aufgerufen. 
IRQ des DMA ist aktiviert...
Hier der Code:

//Init der DMA:
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);

}

//in der main Funtkion dann:
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();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_ETH_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_TIM9_Init();
  /* USER CODE BEGIN 2 */
  HAL_DMA_RegisterCallback(&hdma_adc1, HAL_DMA_XFER_CPLT_CB_ID, 
DMA_ISR);

... usw.

Weiß jemand worauf dabei zu achten ist? Ich kann nicht sehen was ich im 
Vergleich zum Beispiel von ST anders mache (DMA_Flash2RAM Beispiel eines 
beliebigen STMF4)

von fgd (Gast)


Lesenswert?

wo ist die passende ISR dazu ?

von RH (Gast)


Lesenswert?

fgd schrieb:
> wo ist die passende ISR dazu ?

Die ISR-Funktion ist wie im Beispiel in der main.c

static void DMA_ISR(DMA_HandleTypeDef *hdma_adc1){

  addCurrentValues();
  toggle++;

}

Die ganze Funktion hab ich der Übersicht zuliebe nicht ausgeschrieben...

von pegel (Gast)


Lesenswert?

RH schrieb:
> Die ganze Funktion hab ich der Übersicht zuliebe nicht ausgeschrieben...

Wäre vielleicht besser gewesen.
So wissen wir nicht, ob Du

HAL_DMA_Start_IT(&DmaHandle,

benutzt hast.

von Johnny B. (johnnyb)


Lesenswert?

RH schrieb:
> Weiß jemand worauf dabei zu achten ist?

Wenn du die HAL verwendest, dann musst Du nur noch folgenden Handler 
hinzufügen, der dann nach erfolgtem DMA-transfer aufgerufen wird:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
 // Dein Code...
}

von RH (Gast)


Lesenswert?

Johnny B. schrieb:
> Wenn du die HAL verwendest, dann musst Du nur noch folgenden Handler
> hinzufügen, der dann nach erfolgtem DMA-transfer aufgerufen wird:
>
> void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
> {
>  // Dein Code...
> }

Aber das wäre dann ja nach conversion der Daten und nicht nach dem 
Transfer der DMA oder irre ich mich da?

von fgd (Gast)


Lesenswert?

RH schrieb:
> fgd schrieb:
>> wo ist die passende ISR dazu ?
>
> Die ISR-Funktion ist wie im Beispiel in der main.c
>
> static void DMA_ISR(DMA_HandleTypeDef *hdma_adc1){
>
>   addCurrentValues();
>   toggle++;
>
> }
>
> Die ganze Funktion hab ich der Übersicht zuliebe nicht ausgeschrieben...

da sollte eigentlich sowas drinstehen:

void DMA2_Stream0_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&DmaHandle);
}

wenn alles initialisiert wurde irgendwo sowas:

HAL_DMA_StartIT(&DmaHandle)

von fgd (Gast)


Lesenswert?

Johnny B. schrieb:
> RH schrieb:
>> Weiß jemand worauf dabei zu achten ist?
>
> Wenn du die HAL verwendest, dann musst Du nur noch folgenden Handler
> hinzufügen, der dann nach erfolgtem DMA-transfer aufgerufen wird:
>
> void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
> {
>  // Dein Code...
> }

normalerweise ja...
Da er aber den DMA auf seine callbacks umbiegt

RH schrieb:
> HAL_DMA_RegisterCallback(&hdma_adc1, HAL_DMA_XFER_CPLT_CB_ID,
> DMA_ISR);
landen die Daten in der funktion DMA_ISR()


Wenn er jedoch die standard ADC funktionen der HAL inkl DMA nutzt...
Dann wäre es aber auch

HAL_ADC_Start_DMA(..)

Dann wären die standardcallbacks

__weak void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hadc);
  /* NOTE : This function Should not be modified, when the callback is 
needed,
            the HAL_ADC_ConvCpltCallback could be implemented in the 
user file
   */
}

__weak void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hadc);
  /* NOTE : This function Should not be modified, when the callback is 
needed,
            the HAL_ADC_ConvHalfCpltCallback could be implemented in the 
user file
   */
}

__weak void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hadc);
  /* NOTE : This function Should not be modified, when the callback is 
needed,
            the HAL_ADC_ErrorCallback could be implemented in the user 
file
   */
}

von Johannes S. (Gast)


Lesenswert?

Und das wird auch mit C und nicht C++ kompiliert? Bei C++ gibt es noch 
die name mangling Falle wenn das extern C vergessen wurde.

von Johnny B. (johnnyb)


Lesenswert?

fgd schrieb:
> Da er aber den DMA auf seine callbacks umbiegt

Ja so ist es. Leider wurde bereits alles "verbastelt".

Also ich würde mit CubeMX nochmals ein frisches Projekt erstellen und 
den ADC und DMA in CubeMX definieren.

Dann brauchts eigentlich nur noch
1
HAL_ADC_Start_DMA(&DmaHandle, ...

Und dieses hinzuzufügen:
1
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
2
{
3
 // Dein Code...
4
}

Den Rest macht die HAL.

: Bearbeitet durch User
von RH (Gast)


Lesenswert?

Johnny B. schrieb:
> Ja so ist es. Leider wurde bereits alles "verbastelt".
>
> Also ich würde mit CubeMX nochmals ein frisches Projekt erstellen und
> den ADC und DMA in CubeMX definieren.
>
> Dann brauchts eigentlich nur noch
> HAL_ADC_Start_DMA(&DmaHandle, ...
>
> Und dieses hinzuzufügen:
> void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
> {
>  // Dein Code...
> }
>
> Den Rest macht die HAL.

Alles klar, ich setze vielleicht nochmal das Projekt neu auf.

Ich hatte vorhin aber mal den 
HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle) Callback in 
meiner Main implementiert. Dieser wird auch aufgerufen allerdings glaube 
ich, dass er direkt nach der fertigen Conversion des ADC auslöst, also 
da wo auch erst die DMA anängt zu arbeiten. Getestet habe ich das indem 
ich eine einzlne ADC-Wandlung gestartet habe und im Anschluss im 
HAL_ADC_ConvCpltCallback() die Werte aus dem DMA-Array in zwei Variablen 
geschrieben habe. DIe Variablen blieben = 0 also muss der Interrupt ja 
ausgelöst worden sein bevor der DMA-Transfer fertig war...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.