I am trying to scan multiple ADC channels on my STM32H753ZI Nucleo board. I have a TIM2 running at a super slow frequency (2Hz) which triggers the ADC conversions. I have it very slow so that I can see the data printing in real time. I also have a few interrupts running that check for errors in the DMA transmission and an overrun in the ADC conversion. I typically get a "Transfer Error" flag when I first run it. None after that. I also would usually get ADC overrun errors until I set the AUTDLY bit in the CFGR register.

At the moment, I just have two potentiometers connected to ADC3_CH2,CH3 (PF9, PF7). When I print the data being sent over DMA, it is all zeroes. I have looked at this post and took a lot of info from it. Unfortunately, it still does not work. One question among many is why you have to enable the SRAM clock?

My code is posted below. Any help is greatly appreciated.

--EDIT--

The above issue was resolved by moving the location that the value is stored to the SRAM.

However, the data that I am receiving is not totally accurate. Only one of the channels is correct, while the other 2 give junk data. Below is the edited code to reflect changes I have made since the original post.

I think it might be some sort of timing issue or something with the clocks, but I really don't know.

main.c

#include "stm32h7xx.h"
#include "printUSART.h"
#include "timer.h"
#include "dma.h"

int tim_flag = 0;
int dma_flag = 0;

int main(void){

USART3_Init();
DMA_Init();
TIM2_CH1_Init();
TIM2_CH1_Freq_DC(2, 0.5);

printf("Start of Conversions:\n");

while(1){
if(tim_flag == 1){
printf("\nData: %f, %f, %f\n", (val[0] / 65535.0 * 3.3), (val[1] / 65535.0 * 3.3), (val[2] / 65535.0 * 3.3));       // print value in data register
tim_flag = 0;
}

if(dma_flag == 1){
printf("Transfer Error\n");
dma_flag = 0;
}
else if(dma_flag == 2){
//          printf("Transfer Complete\n");
dma_flag = 0;
}

printf("Overrun\n");
}
}
}

void TIM2_IRQHandler(void){
if(TIM2->SR & TIM_SR_UIF){
TIM2->SR &= ~TIM_SR_UIF;
tim_flag = 1;
}
}

}
}

void DMA1_Stream0_IRQHandler(void){
if(DMA1->LISR & DMA_LISR_TEIF0){
DMA1->LIFCR |= DMA_LIFCR_CTEIF0;
dma_flag = 1;
}

if(DMA1->LISR & DMA_LISR_TCIF0){
DMA1->LIFCR |= DMA_LIFCR_CTCIF0;
dma_flag = 2;
}
}


adc.c

/*
*
*  Created on: Jul 1, 2021
*      Author: jeremywolfe
*
*/

RCC->AHB4ENR |= RCC_AHB4ENR_GPIOFEN;                // enable clock for port F

GPIOF->MODER = GPIO_MODER_MODE9_0 | GPIO_MODER_MODE9_1; // setting PF5, 7, 9 as alternate function
GPIOF->MODER = GPIO_MODER_MODE7_0 | GPIO_MODER_MODE7_1;
GPIOF->MODER = GPIO_MODER_MODE5_0 | GPIO_MODER_MODE5_1;

/*  Turning on the ADC (25.4.9) */

}

NVIC_EnableIRQ(ADC3_IRQn);          // enable on the NVIC

}

printf("\nCalibration is complete");
}


dma.c

/*
* dma.c
*
*  Created on: Aug 30, 2021
*      Author: jeremywolfe
*/

#include "dma.h"

uint16_t *val = (uint16_t*)0x30000000;

void DMA_Init(void){

DMA1_Stream0->CR &= ~DMA_SxCR_EN;               // turn off DMA controller
while(DMA1_Stream0->CR & DMA_SxCR_EN){}         // wait until off

RCC->AHB2ENR |= RCC_AHB2ENR_D2SRAM1EN;  // SRAM clock???
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;     // DMA clock

DMA1_Stream0->CR |= DMA_SxCR_TEIE | DMA_SxCR_TCIE;  // interrupts for transfer error and transfer complete
NVIC_EnableIRQ(DMA1_Stream0_IRQn);                  // enable on the NVIC

DMA1_Stream0->M0AR = (uint32_t)(val);               // setting the "val" array as the memory location

DMA1_Stream0->NDTR = 3;                             // 3 datas items

DMAMUX1_Channel0->CCR = 115;                        // DMAMUX 115 (adc3_dma)

DMA1_Stream0->CR |= DMA_SxCR_PL_0 | DMA_SxCR_PL_1;  // set highest priority

// set up DMA settings
// circular mode, peripheral, memory size = 2 bytes, memory increments by 2 bytes every time
DMA1_Stream0->CR |= DMA_SxCR_CIRC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC | DMA_SxCR_MSIZE_0;

DMA1_Stream0->CR |= DMA_SxCR_EN;        // enable the DMA
}
$$$$

• 2 potential problems: #1 is that your val array is located in the DTCM memory block which only the core and MDMA modules can access, and not the 'normal' DMA - so it can't write there. #2 is that reads by the code from your val array are being cached and you're only seeing the 'stale' values from the cache. Aug 31, 2021 at 11:53
• To check if it's a cache issue, try issuing a 'DSB' instruction immediately before you printf the values. Depending on your compiler this could take one of many forms: DSB(), __DSB, asm("DSB"), __asm("DSB") or something similar to that. Note though that this is a bit of a sledgehammer approach because it invalidates the entire data cache and not just the tiny bit for val. Aug 31, 2021 at 11:57
• To check if it's a memory location issue, look at the .map file your compiler should produce after building your project. Find the entry for the val array and check if its address is in the 0x20000000-0x2001ffff DTCM range. If it is then you'll need to move it into a different memory area to be able to use the DMA to write into it. Aug 31, 2021 at 12:01
• @brhans That turned out to be the issue and DMA is now working. However, only one channel is giving correct data with the other one just sending junk. Do you see any issues with my ADC configuration that could be causing this? Aug 31, 2021 at 19:19

Turns out I am really dumb and forgot to put an |= when I simply had an =. This is the code in question:
GPIOF->MODER &= ~0xFFFF;
`