title: STM32F303: ADC with DMA only works a few times
body: <p>I am currently working with a Nucleo-64 board that has the STM32F303RE chip. For programming I use the Arduino IDE with the STM32 packages. I want to avoid HAL for now because I think it is rather confusing when you have to learn the registers and the library functions at the same time.</p>
  
  <p>I want to be able to sample 4 input signals parallel at 5.1 Msps (max of the F303). My plan was to keep the ADC running. Then, when I want to take the samples, I reset the DMA flags and set the counter (CNDTR-Register) to the ammount of samples I want to capture.</p>
  
  <p>The following part shows my attemp to achieve this. It is basically almost working, but only a limited amount of times. How often it works seems to depend on random sleep values which I enter at certain parts in the programm.
  For example: If I enter a delay of 10ms after the takeSamples()-function, the programm will work for 41 cycles of the main loop - then it gets stuck.</p>
  
  <p>When it gets stuck it does the following: The DMA-CNDTR register only gets reduced by one value, then it just stays there. So the programm is waiting for the register value to become zero, but this never happens. The ADC is sampling the whole time, I can read the ADC data registers just fine.</p>
  
  <p>Does anyone have an idea what could be causing the DMA to stop transfering data after a certain amount of times?</p>
  
  <p>Here are the relevant parts of the program:</p>
  
  <pre><code>void setup() {
    Serial.begin(57600);
  
    // Enable clocks
    RCC-&gt;AHBENR |= (1 &lt;&lt; 17); // GPIOA
    RCC-&gt;AHBENR |= (1 &lt;&lt; 18); // GPIOB
  
    // Set ADC pins to analog input
    GPIOA-&gt;MODER |= (0b11 &lt;&lt; 0); // PA0 for ADC1
    GPIOA-&gt;MODER |= (0b11 &lt;&lt; 8); // PA4 for ADC2
    GPIOB-&gt;MODER |= (0b11 &lt;&lt; 2); // PB1 for ADC3
    GPIOB-&gt;MODER |= (0b11 &lt;&lt; 24); // PB1 for ADC4
  
    initClock();
    DMA_init();
    ADC_init();
  
    // Start conversion
    ADC1-&gt;CR |= (1 &lt;&lt; 2);
    ADC3-&gt;CR |= (1 &lt;&lt; 2);
  }
  
  void initClock()
  {
    FLASH-&gt;ACR |= (0b10 &lt;&lt; 0); // add two wait states
  
    RCC-&gt;CR |= (1 &lt;&lt; 18); // Bypass HSE, use external clock signal from STLink instead
  
    RCC-&gt;CR &amp;= ~(1 &lt;&lt; 24); // turn off PLL
    delay(100);
    RCC-&gt;CFGR |= (0b0000 &lt;&lt; 4); // Do not divide system clock
    RCC-&gt;CFGR |= (0b0111 &lt;&lt; 18);  // PLL multiply = 9
    RCC-&gt;CFGR |= (0b10 &lt;&lt; 15); // use HSE as PLL source
    RCC-&gt;CFGR |= (1 &lt;&lt; 10);  // not divided
    delay(100);
    RCC-&gt;CR |= (1 &lt;&lt; 24); // turn on PLL
    delay(100);
  }
  
  void ADC_init(void) {
  
    RCC-&gt;CFGR2 |= (0b10000 &lt;&lt; 4); // Prescaler
    RCC-&gt;CFGR2 |= (0b10000 &lt;&lt; 9); // Prescaler
    RCC-&gt;AHBENR |= (1 &lt;&lt; 28); // turn on ADC12 clock
    RCC-&gt;AHBENR |= (1 &lt;&lt; 29); // turn on ADC34 clock
  
    // Set ADC clock
    ADC12_COMMON-&gt;CCR |= (0b01 &lt;&lt; 16); // 0b01
    ADC34_COMMON-&gt;CCR |= (0b01 &lt;&lt; 16); // 0b01
  
  
    // disable the ADC
    ADC1-&gt;CR &amp;= ~(1 &lt;&lt; 0);
    ADC2-&gt;CR &amp;= ~(1 &lt;&lt; 0);
    ADC3-&gt;CR &amp;= ~(1 &lt;&lt; 0);
    ADC4-&gt;CR &amp;= ~(1 &lt;&lt; 0);
  
    // enable the ADC voltage regulator
    ADC1-&gt;CR &amp;= ~(1 &lt;&lt; 29);
    ADC2-&gt;CR &amp;= ~(1 &lt;&lt; 29);
    ADC3-&gt;CR &amp;= ~(1 &lt;&lt; 29);
    ADC4-&gt;CR &amp;= ~(1 &lt;&lt; 29);
  
    ADC1-&gt;CR |= (1 &lt;&lt; 28);
    ADC2-&gt;CR |= (1 &lt;&lt; 28);
    ADC3-&gt;CR |= (1 &lt;&lt; 28);
    ADC4-&gt;CR |= (1 &lt;&lt; 28);
  
    // start ADC calibration cycle
    ADC1-&gt;CR |= (1 &lt;&lt; 31);
    // wait for calibration to complete
    while (ADC1-&gt;CR &amp; (1 &lt;&lt; 31));
  
    // start ADC calibration cycle
    ADC2-&gt;CR |= (1 &lt;&lt; 31);
    // wait for calibration to complete
    while (ADC2-&gt;CR &amp; (1 &lt;&lt; 31));
  
    // start ADC calibration cycle
    ADC3-&gt;CR |= (1 &lt;&lt; 31);
    // wait for calibration to complete
    while (ADC3-&gt;CR &amp; (1 &lt;&lt; 31));
  
    // start ADC calibration cycle
    ADC4-&gt;CR |= (1 &lt;&lt; 31);
    // wait for calibration to complete
    while (ADC4-&gt;CR &amp; (1 &lt;&lt; 31));
  
    // enable the ADC
    ADC1-&gt;CR |= (1 &lt;&lt; 0);
    ADC2-&gt;CR |= (1 &lt;&lt; 0);
    ADC3-&gt;CR |= (1 &lt;&lt; 0);
    ADC4-&gt;CR |= (1 &lt;&lt; 0);
  
    while (!(ADC1-&gt;ISR &amp; (1 &lt;&lt; 0)));
    while (!(ADC2-&gt;ISR &amp; (1 &lt;&lt; 0)));
    while (!(ADC3-&gt;ISR &amp; (1 &lt;&lt; 0)));
    while (!(ADC4-&gt;ISR &amp; (1 &lt;&lt; 0)));
  
    // Select ADC Channels
    ADC1-&gt;SQR1 = (1 &lt;&lt; 6);
    ADC2-&gt;SQR1 = (1 &lt;&lt; 6);
    ADC3-&gt;SQR1 = (1 &lt;&lt; 6);
    ADC4-&gt;SQR1 = (3 &lt;&lt; 6);
  
    // Set sampling time for regular group 1
    ADC1-&gt;SMPR1 |= (0b000 &lt;&lt; 3); // 0b000 -&gt; 1.5 clock cycles, shortest available sampling time
    ADC2-&gt;SMPR1 |= (0b000 &lt;&lt; 3);
    ADC3-&gt;SMPR1 |= (0b000 &lt;&lt; 3);
    ADC4-&gt;SMPR1 |= (0b000 &lt;&lt; 3);
  
    // Regular sequence settings
    ADC1-&gt;SQR1 |= (0b0000 &lt;&lt; 0); // One conversion in the regular sequence
    ADC2-&gt;SQR1 |= (0b0000 &lt;&lt; 0);
    ADC3-&gt;SQR1 |= (0b0000 &lt;&lt; 0);
    ADC4-&gt;SQR1 |= (0b0000 &lt;&lt; 0);
  
    // Enable continuous conversion mode
    ADC1-&gt;CFGR |= (1 &lt;&lt; 13); // Master ADC1 + ADC2
    ADC3-&gt;CFGR |= (1 &lt;&lt; 13); // Master ADC3 + ADC4
  
    ADC12_COMMON-&gt;CCR |= (0b00110 &lt;&lt; 0);
    ADC34_COMMON-&gt;CCR |= (0b00110 &lt;&lt; 0);
  
    // DMA mode
    ADC12_COMMON-&gt;CCR |= (0 &lt;&lt; 13); // 0 -&gt; One Shot; 1 -&gt; Circular
    ADC34_COMMON-&gt;CCR |= (0 &lt;&lt; 13);
  
    // DMA mode for 12-bit resolution
    ADC12_COMMON-&gt;CCR |= (0b10 &lt;&lt; 14);
    ADC34_COMMON-&gt;CCR |= (0b10 &lt;&lt; 14);
  }
  
  void DMA_init(void) {
  
    // Enable clocks
    RCC-&gt;AHBENR |= (1 &lt;&lt; 0); // DMA1
    RCC-&gt;AHBENR |= (1 &lt;&lt; 1); // DMA2
  
    // Transfer complete interrupt enable
    DMA1_Channel1-&gt;CCR |= (1 &lt;&lt; 1);
    DMA2_Channel5-&gt;CCR |= (1 &lt;&lt; 1);
  
    // Memory increment mode
    DMA1_Channel1-&gt;CCR |= (1 &lt;&lt; 7);
    DMA2_Channel5-&gt;CCR |= (1 &lt;&lt; 7);
  
    // Peripheral size
    DMA1_Channel1-&gt;CCR |= (0b11 &lt;&lt; 8);
    DMA2_Channel5-&gt;CCR |= (0b11 &lt;&lt; 8);
  
    // Memory size
    DMA1_Channel1-&gt;CCR |= (0b11 &lt;&lt; 10);
    DMA2_Channel5-&gt;CCR |= (0b11 &lt;&lt; 10);
  
    // Number of data to transfer
    DMA1_Channel1-&gt;CNDTR = uint32_t(maxSamples);
    DMA2_Channel5-&gt;CNDTR = uint32_t(maxSamples);
  
    // Peripheral address register
    DMA1_Channel1-&gt;CPAR |= (uint32_t)&amp;ADC12_COMMON-&gt;CDR;
    DMA2_Channel5-&gt;CPAR |= (uint32_t)&amp;ADC34_COMMON-&gt;CDR;
  
    // Memory address register
    DMA1_Channel1-&gt;CMAR |= uint32_t(&amp;dataPoints1232);
    DMA2_Channel5-&gt;CMAR |= uint32_t(&amp;dataPoints3432);
  
    // Reset flags
    DMA1-&gt;IFCR |= 0xFF;
    DMA2-&gt;IFCR |= 0xFF;
  }
  
  void takeSamples(void) {
  
    // Reset flags
    DMA1-&gt;IFCR |= (0b1111111111111111111111111111111 &lt;&lt; 0);
    DMA2-&gt;IFCR |= (0b1111111111111111111111111111111 &lt;&lt; 0);
  
    // Number of data to transfer
    DMA1_Channel1-&gt;CNDTR = uint32_t(maxSamples);
    DMA2_Channel5-&gt;CNDTR = uint32_t(maxSamples);
  
    delay(10); // does not work without this random delay
  
    elapsedTime = micros();
    // Enable DMA
    DMA1_Channel1-&gt;CCR |= (1 &lt;&lt; 0);
    DMA2_Channel5-&gt;CCR |= (1 &lt;&lt; 0);
  
    while ((DMA1_Channel1-&gt;CNDTR &gt; 0) || (DMA2_Channel5-&gt;CNDTR &gt; 0))
    }
  
    elapsedTime = micros() - elapsedTime;
  
    // Reset flags
    DMA1-&gt;IFCR |= (0b1111111111111111111111111111111 &lt;&lt; 0);
    DMA2-&gt;IFCR |= (0b1111111111111111111111111111111 &lt;&lt; 0);;
  
    DMA1_Channel1-&gt;CCR &amp;= ~(1 &lt;&lt; 0);
    DMA2_Channel5-&gt;CCR &amp;= ~(1 &lt;&lt; 0);
  
    // ADC stop conversion
    ADC1-&gt;CR |= (1 &lt;&lt; 4);
    ADC3-&gt;CR |= (1 &lt;&lt; 4);
  
    while ((ADC1-&gt;CR &amp; (1 &lt;&lt; 2)) || (ADC3-&gt;CR &amp; (1 &lt;&lt; 2)));
  
    ADC12_COMMON-&gt;CCR &amp;= ~(0b10 &lt;&lt; 14);
    ADC34_COMMON-&gt;CCR &amp;= ~(0b10 &lt;&lt; 14);
  
    ADC12_COMMON-&gt;CCR |= (0b10 &lt;&lt; 14);
    ADC34_COMMON-&gt;CCR |= (0b10 &lt;&lt; 14);
  
    // ADC start conversion
    ADC1-&gt;CR |= (1 &lt;&lt; 2);
    ADC3-&gt;CR |= (1 &lt;&lt; 2);
  }
  
  void loop() {
    takeSamples();
    Serial.print("Elapsed time: ");
    Serial.println(elapsedTime);
  }
  </code></pre>
  
  <p>I would be really thankfull for any tips or hints regarding this issue!</p>
  
  <p>Greetings
  Benny</p>
  
  <p>EDIT: I also had the same issue with the nucleo-64 with the STM32F401 chip. The STM32F4 Discovery on the other hand worked just fine. There was no issue like that with my F103 flightcontroller-board aswell.</p>