0
\$\begingroup\$

I am just trying to access the second half of the DMA.

I have the half complete flag enable and working, however I am not entirely sure how to access the second half of the buffer.

What I thought was the way would be enabling the Transfer complete flag as well and do stuff when that flag is detected but it never triggers. Any ideas?

Chip: STM32L43KC

Buffer in question is the short adcValue[2000];

I can access it from 0 - 1000 but not from 1000 - 2000.

Code: Updated

/* USER CODE BEGIN Header */
/**
  **************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  **************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  **************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "custom.h"
char buffer[20];
short adcValue[2000];
int thc = 0;
int tc = 0;

void DMA2_Channel3_IRQHandler(void){

    if (((DMA2->ISR) & (1<<10)) != 0){

        thc = 1;
    } else if (((DMA2->ISR) & (1<<9)) != 0){
        tc = 1;
    }

}


int main(void)
{
    initDebug();
    initADC();
    initDAC();
    initInterrupt();

  while (1)
  {

      if (thc == 1){
          //First Half Output to DAC
          thc = 0;
      }

      if (tc == 1){
          //Second Half Output to DAC
          tc = 0;
      }

  }


}




void printADC(int adcValue){

    sprintf(buffer, "ADC VALUE: [%d]\n\r", adcValue);
}

void initDebug(){

    RCC->APB1ENR1 |= (1<<17); // Enable USART2 Clock
    RCC->AHB1ENR |= (1<<0); // Enable DMA1 Clock
    RCC->AHB2ENR |= (1<<0); //Enable GPIOA Clock
    RCC->CCIPR = (1<<2); //Use the System Clock for USART2

    GPIOA->MODER &= ~(1<<4); //Enable Alt Function for PA_2
    GPIOA->MODER |= (1<<5);
    GPIOA->AFR[0] |= ((1<<10) | (1<<9) | (1<<8)); //Enable USART2_Tx for PA_2

    USART2->CR1 |= (1<<3); //Enable Transmitter
    USART2->CR3 |= (1<<7); //Enable DMA Transmission
    USART2->BRR = 0x1A0; //9600 baudrate

    DMA1_Channel7->CCR |= (1<<13); //Prio Level High
    DMA1_Channel7->CCR |= (1<<7); //MINC
    DMA1_Channel7->CCR |= (1<<5); //Circ
    DMA1_Channel7->CCR |= (1<<4); //DIR
    DMA1_Channel7->CNDTR = 0x14;
    DMA1_Channel7->CMAR = (uint32_t)buffer;
    DMA1_Channel7->CPAR = (uint32_t)&USART2->TDR;
    DMA1_CSELR->CSELR = (1<<25);

    DMA1_Channel7->CCR |= (1<<0);
    USART2->CR1 |= (1<<0); //Enable USART2
}

void initADC(){





    RCC->AHB2ENR |= ((1<<0) | (1<<13)); //Enable: GPIOA Clock & ADC Clock
    RCC->AHB1ENR |= (1<<1); //Enable: DMA2 Clock
    RCC->CCIPR |= ((1<<29) | (1<<28)); //Enable: ADC Clock to be used as System Clock

    GPIOA->MODER |= ((1<<15) | (1<<14)); //Enable: PA_7 Analog Mode

    GPIOA->MODER &= ~(1<<1);

    DMA2_Channel3->CCR |= ((1<<13) | (1<<12)); //Priority: Very High
    DMA2_Channel3->CCR |= (1<<10); //16 Bit Memory Size
    DMA2_Channel3->CCR |= (1<<8); //16 Bit Peripheral Size
    DMA2_Channel3->CCR |= (1<<7); // Enable: Memory Increment Mode
    DMA2_Channel3->CCR |= (1<<5); //Enable: Circular Mode
    DMA2_Channel3->CCR |= (1<<2); //Enable: Half Transfer Complete Flag
    DMA2_Channel3->CCR |= (1<<1); //Enable: Transfer Complete Flag
    DMA2_Channel3->CNDTR = 0x7D0; //Count down from 2000
    DMA2_Channel3->CMAR = (uint32_t)adcValue; //Memory Address
    DMA2_Channel3->CPAR = (uint32_t)&ADC1->DR; //Peripheral Addres

    ADC1->CR &= ~(1<<29); //Disable: Deep Power Mode
    ADC1->CR |= (1<<28); //Enable: Voltage Regulator
    ADC1->CFGR |= (1<<13); //Enable: Continuous Mode
    ADC1->CFGR |= (1<<1); //Enable: DMA Circular Mode
    ADC1->CFGR |= (1<<0); // Enable: DMA2
    ADC1->SMPR2 = (1<<8); //66kHz Sampling
    ADC1->CR |= (1<<31); //Start Calibration
    while(((ADC1->CR) & (1<<31)) != 0); //Wait for Calibration to be done
    ADC1->SQR1 |= ((1<<9) | (1<<8)); //First Seq: Channel 12
    ADC1->CR |= (1<<0); //Enable: ADC
    while(((ADC1->ISR) & (1<<0)) == 0); //Wait for the ADC to be ready
    ADC1->ISR |= (1<<0); //Clear the ARDYFlAG

    DMA2_Channel3->CCR |= (1<<0); //Enable: DMA2
    ADC1->CR |= (1<<2); //Start the ADC
}

void initDAC(){

    RCC->APB1ENR1 |= (1<<29); // Enable Dac
    RCC->AHB2ENR |= (1<<0);
    GPIOA->MODER |= ((1<<9) | (1<<8));
    DAC1->CR |= (1<<0);
}

void initInterrupt(){
    NVIC_EnableIRQ(DMA2_Channel3_IRQn);
    NVIC_SetPriority(DMA2_Channel3_IRQn,0);
}
\$\endgroup\$
1
  • \$\begingroup\$ Comments are not for extended discussion; this conversation has been moved to chat. \$\endgroup\$ – Voltage Spike Jun 10 '20 at 15:38
1
\$\begingroup\$

Okay, so it turns out that for some reason (we still don't know why) the certain interrupt flags were being automatically cleared when exiting the ISR but only under certain versions of code:

For example:

  • when his for-loop that loads the buffered ADC samples into the DAC was inappropriately located within the ISR itself, rather than being located in the main loop and just being flagged by the ISR to run, the half transfer interrupt would trigger but the transfer complete interrupt would not
  • But when everything was stripped out of the ISRs with only GPIO indicator toggles in the ISR, neither ISR would run.

This was sort of letting the OP get away with not manually clearing flags just before exiting the ISR in some places but not in others and it was in these places the code was breaking. He was not manually clearing them because he had circular mode for the DMA enabled and thought that the circular mode on the DMA cleared the interrupts flags for you but it does not. Nevertheless something seemed to be clearing them some of the time.

Manually, and explicitly clearing the appropriate flags before exiting the interrupts allowed both the DMA half-transfer and transfer-complete interrupts to both run.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.