cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F407 Discovery w/ 3 Channel ADC and DMA

nicholas23
Associate II
Posted on January 21, 2015 at 17:24

Looking through this forum I have seen the topic of ADCs and DMAs coming up a lot, and I apologize in advance for adding to it. but after reviewing most posts I still have not been able to implement ADC with the DMA.

When trying to read from the memory locations I get a return value of 0, which has me believe that the DMA is not working because values are not being transferred. Moreover, when I just read straight from the ADC1->DR register, I will only ever get a constant value for each runtime which varies between 200- Thank you in advance.

#include ''stm32f4.h''
volatile uint16 adcVal[3];
extern
void
initialise_monitor_handles(
void
); 
/* prototype */
void
ADC_DMA_Init(
void
)
{
RCC->AHB1ENR |= (1<<22); 
/* DMA2 clk Enable*/
DMA2->stream[0].CR &= ~(0x0E000000); 
/* Channel 0 selected */
DMA2->stream[0].CR &= ~(0x01800000); 
/* Memory bust single*/
DMA2->stream[0].CR &= ~(0x00600000); 
/* Peripheral bust single*/
DMA2->stream[0].CR |= (2<<16)| 
/* Priority level High */
(1<<13)| 
/* Memory data size Half-word*/
(1<<11)| 
/* Peripheral data size Half-word*/
(1<<10)| 
/* Memory increment enable */
(0<<9)| 
/* Peripheral increment disable*/
(1<<8); 
/* Circular mode enable*/
DMA2->stream[0].CR &= ~(0x000000C0); 
/* Direction Peripheral to Memory*/
DMA2->stream[0].NDTR = 3; 
/* Number of data items*/
DMA2->stream[0].PAR = (uint32) &ADC1->DR; 
/* Peripheral base address*/
DMA2->stream[0].M0AR = (uint32) &adcVal[0]; 
/* Memory 0 base address*/
DMA2->stream[0].FCR = 0x00000021; 
/* Direct mode and Threshold_HalfFull(Threshold not used) : same as reset value */
DMA2->stream[0].CR |= (1<<0); 
/* DMA2_Stream0 Enable*/
RCC->APB2ENR |= (1<<8); 
/* ADC1 clk enable*/
GPIOA->MODER |= (3<<(12)); 
/* PA6 - Channel6 */
GPIOA->PUPDR &= ~((3<<(12))); 
/* No Pull up and down resistor*/
GPIOC->MODER |= ( 3<<(4)) | (3<<(8) ); 
/* PC2, PC4 - Channel 12,14 */
GPIOC->PUPDR &= ~( (3<<(4)) | (3<<(8)) ); 
/* No Pull up and down resistor*/
ADC1->CR1 = (1<<8); 
/* Scan mode enable in order to read multi channel with single ADC*/
ADC1->CR2 = (1<<0)| 
/* ADC1 power on */
(1<<1)| 
/* Continuous conversion*/
(1<<8)| 
/* DMA access mode enable*/
(1<<9); 
/* Enable the selected ADC DMA request after last transfer */
ADC1->SMPR1 = 0;
ADC1->SMPR2 = 0; 
/* PA3, PA5 3cycle*/
ADC1->SQR1 = (2<<20); 
/* three conversions */
ADC1->SQR2 = 0;
ADC1->SQR3 = (12<<0) | (6<<5) | (14<<10); 
/* 1st: ADC1_IN12, 2nd: ADC1_IN6, 3rd: ADC1_IN14*/
ADCCOMMON->CCR = (1<<16); 
/* fpclk2/4 = 21Mhz */
ADC1->CR2 |= (1<<30);
}
int
main (
void
) {
initialise_monitor_handles();
ADC_DMA_Init();
ADC1->CR2 |= (1<<30);
while
(1)
{
// printf(''%i\n'', ADC1->DR);
printf(
''{%i, %i, %i}\n''
, adcVal[0], adcVal[1], adcVal[2]);
}
return
0;
}

inside my stm32f4.h file I have the following defined:

#define DMA2 ((struct DMA_struct *) 0x40026400)
/* ... */
/* DMA - DMA Controller */
struct
DMA_struct {
volatile uint32 LISR; 
/* Low Interrupt Status register */
volatile uint32 HISR; 
/* High Interrupt Status register */
volatile uint32 LIFCR; 
/* Low Interrupt Flag Clear register */
volatile uint32 HIFCR; 
/* High Interrupt Flag Clear register */
struct
DMAstream_struct stream[8]; 
/* DMA stream registers */
};
/* ... */
/* DMA stream structure, 8 streams per DMA */
struct
DMAstream_struct {
volatile uint32 CR; 
/* Configuration register */
volatile uint32 NDTR; 
/* Number of data register */
volatile uint32 PAR; 
/* Peripheral Address register */
volatile uint32 M0AR; 
/* Memory Address 0 register */
volatile uint32 M1AR; 
/* Memory Address 1 register */
volatile uint32 FCR; 
/* Fifo Control register */
};

#stm32f4-adc-dma
5 REPLIES 5
Posted on January 21, 2015 at 17:41

Looking through this forum I have seen the topic of ADCs and DMAs coming up a lot, and I apologize in advance for adding to it. but after reviewing most posts I still have not been able to implement ADC with the DMA.

And as sad as I am about that, I know there are working examples, and if you chose to break things, that's on you.

You enable the GPIO clocks somewhere?
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
nicholas23
Associate II
Posted on January 22, 2015 at 01:03

nicholas23
Associate II
Posted on January 22, 2015 at 01:05

nicholas23
Associate II
Posted on January 22, 2015 at 01:11

Thank you Clive, you are right in that the GPIO timers were not enabled in the RCC. However nothing has changed. The I am still receiving a 0 value on the memory the DMA is supposed to output to. The value that is the DR register is proportionate to the input signal; however, it is still not changing. My current theory is that somehow I am required to clear the EOC flag, as that seems to be set in the SR register and is not being cleared. I figured that was managed by the DMA though, no? Any thoughts? 

A lot of the examples focus on using the st libraries, and while I see their utility for speed of implementation, they abstract from what is actually happening(and my learning of what is actually happening), which is why I am ''breaking'' them.

Post scriptum: Sorry for the double blank posts, there seems to be some issues posting from a mobile device.

AvaTar
Lead
Posted on January 22, 2015 at 11:05

A lot of the examples focus on using the st libraries, and while I see their utility for speed of implementation, they abstract from what is actually happening(and my learning of what is actually happening), which is why I am ''breaking'' them.

 

That is up to you. However, not an awful lot of people is so deep into register bits, and decoding other's bit-hacking code by the reference manual is tedious.

I would recommend to take a SPL example as reference, debug it, and see what registers/bits it sets and checks in sequence.

My current theory is that somehow I am required to clear the EOC flag, as that seems to be set in the SR register and is not being cleared. I figured that was managed by the DMA though, no?

 

When using DMA, you are not supposed to clear EOC. Instead, it goes into DMA, triggering the next transfer. As mentioned above, I suggest to ''cut out'' the required setup code from an appropriate SPL example.