AnsweredAssumed Answered

STM32F103 Dual ADC with DMA skips channel

Question asked by Jeroen3 on Nov 3, 2016
Latest reply on Nov 3, 2016 by Clive One
STM32F103RCT6 (GH20P 93 / CHN GH 608)

I'm brave enough to try to master the 
ADC1/2 Combined regular simultaneous + injected simultaneous mode
of the ADC.
However, I've run into a problem. First, my goal:
- I want to sample 6 different channels, 
  = 3 on ADC1 and 3 on ADC2, simultaneous, 
  = triggered on a timer 3, 
  = written to memory using DMA.
...and...
- I want to sample 5 (+vref, temp) channels, 
  = triggered on timer 4, 
  = injected.
  
The good news. The injected channels works fine! This is genius. Hats off to this.

The bad news. The chip skips ADC2 SQ3 once every scan. See image A (bottom). 
The channel is shorted to GND. Should read 0. All other are floating. (demoboard)
Sample 1: IN11 not sampled.
Sample 2: IN11 sampled. 
Sample 3: IN11 not sampled.
Sample 4: IN11 sampled.
End of circular dma buffer.

Below is the adc init. I've learned from the HAL, but removed it. Since it only includes unnecessary rom and time.
And, I need to know the chip inside out.

Am I not using the correct Dual Mode? It seems to work with "Regular simultaneous mode only", but that might kill injected synchronization?

I can't find any code tags.

#define FASTSAMPLE_BUFFER 4
// DMA buffer
volatile ADC_fastsample_t dma_sample_buffer[FASTSAMPLE_BUFFER] __attribute__((aligned (16)));
//volatile ADC_fastsample_t *fsample = (ADC_fastsample_t*)dma_sample_buffer;


/**
 * Initialize analog aquisitions and calculations.
 */
void ADC_init(void){
   
  __HAL_RCC_DMA1_CLK_ENABLE();
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
  
  __HAL_RCC_TIM3_CLK_ENABLE();
  __HAL_RCC_TIM4_CLK_ENABLE();
  
  // Test timer, must change
  #warning TODO: change to correct timers and interval
  // Timers in downcount
  TIM3->PSC = 7200;
  TIM3->CR1 = TIM_CR1_DIR;
  TIM3->ARR = 5000;
  TIM3->CR2 = TIM_CR2_MMS_1;
  
  TIM4->PSC = 7200;
  TIM4->CR1 = TIM_CR1_DIR;
  TIM4->ARR = 10000;
  TIM4->CR2 = TIM_CR2_MMS_1;
  
  __HAL_RCC_ADC1_CLK_ENABLE();
  __HAL_RCC_ADC2_CLK_ENABLE();
    
  // Setup ext triggerss regular on tim3 trgo, injected on tim4 trgo
  // Note: Combined regular simultaneous + injected simultaneous mode 
  ADC1->CR2 = ADC_CR2_ADON | 
              (4<<ADC_CR2_EXTSEL_Pos) | 
              (5<<ADC_CR2_JEXTSEL_Pos) |
              ADC_CR2_CAL | ADC_CR2_ALIGN |
              ADC_CR2_DMA | ADC_CR2_TSVREFE;
  ADC1->CR1 = (1<<ADC_CR1_DUALMOD_Pos) | 
              ADC_CR1_SCAN | ADC_CR1_JEOCIE;




  // Setup slave ADC2. 
  // Note: (J)EXTSEL must be 0b111 Software trigger.
  ADC2->CR2 = ADC_CR2_ADON | 
              (7<<ADC_CR2_EXTSEL_Pos) | 
              (7<<ADC_CR2_JEXTSEL_Pos) |
              ADC_CR2_CAL | ADC_CR2_ALIGN;
  ADC2->CR1 = (1<<ADC_CR1_DUALMOD_Pos) | 
              ADC_CR1_SCAN | ADC_CR1_JEOCIE;
              
  // Regular channels ADC 1
  ADC1->SQR1 = (2<<ADC_SQR1_L_Pos);   // 3 channels (off by one)
  ADC1->SQR2 = 0;
  ADC1->SQR3 =(0 <<ADC_SQR3_SQ1_Pos)| // IN0    
              (2 <<ADC_SQR3_SQ2_Pos)| // IN2    
              (10<<ADC_SQR3_SQ3_Pos)| // IN10   
              (0 <<ADC_SQR3_SQ4_Pos); //
              #warning IN11 does not work somehow
              
  // Regular channels ADC 2
  ADC2->SQR1 = (2<<ADC_SQR1_L_Pos);   // 3 channels
  ADC2->SQR2 = 0;                       
  ADC2->SQR3 =(1 <<ADC_SQR3_SQ1_Pos)| // IN1     
              (3 <<ADC_SQR3_SQ2_Pos)| // IN3     
              (11<<ADC_SQR3_SQ3_Pos)| // IN11    
              (0 <<ADC_SQR3_SQ4_Pos); // 




  /* Notice ADC Inject channel assignments:
   * When less than 4 conversions (n) are assigned, use JSQx blocks from 4 to 4-n.
   * Eg: with 3 injected conversions the order is: JSQ2 -> JSQ3 -> JSQ4
   * However, results are stored in JDR registers in order of conversion.
   * Eg: with 3 injected conversion the assignment is: JSQ2 = JDR1, JSQ3 = JDR2, JSQ3 = JDR3.
   */
  // Injected ADC 1
  ADC1->JSQR =(3 <<ADC_JSQR_JL_Pos)|  // 4 channels (order: 1->2->3->4)
              (12<<ADC_JSQR_JSQ1_Pos)|// IN12     xxx -> JDR1
              (13<<ADC_JSQR_JSQ2_Pos)|// IN13     xxx -> JDR2
              (16<<ADC_JSQR_JSQ3_Pos)|// IN16     TEMP_INT   -> JDR3
              (17<<ADC_JSQR_JSQ4_Pos);// IN17     VREF_INT   -> JDR4 
                                         
  // Injected ADC 2
  ADC2->JSQR =(2 <<ADC_JSQR_JL_Pos)|  // 3 channels (order: 2->3->4)
              (0 <<ADC_JSQR_JSQ1_Pos)|// not used
              (6 <<ADC_JSQR_JSQ2_Pos)|// IN6      xxx -> JDR1
              (7 <<ADC_JSQR_JSQ3_Pos)|// IN7      xxx -> JDR2
              (14<<ADC_JSQR_JSQ4_Pos);// IN14     xxx -> JDR3
              
  // Sampletime registers
  ADC1->SMPR2 = (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR2_SMP1_Pos)| 
                (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR2_SMP2_Pos)| 
                (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR2_SMP3_Pos)| 
                (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR2_SMP4_Pos)| 
                (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR2_SMP5_Pos)| 
                (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR2_SMP6_Pos)| 
                (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR2_SMP7_Pos)|
                (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR2_SMP8_Pos)|
                (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR2_SMP9_Pos);
  ADC1->SMPR1 = (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR1_SMP10_Pos)| 
                (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR1_SMP11_Pos)| 
                (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR1_SMP12_Pos)| 
                (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR1_SMP13_Pos)| 
                (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR1_SMP14_Pos)| 
                (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR1_SMP15_Pos)| 
                (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR1_SMP16_Pos)|                 
                (ADC_SAMPLETIME_71CYCLES_5 << ADC_SMPR1_SMP17_Pos);
  ADC2->SMPR1 = ADC1->SMPR1;
  ADC2->SMPR2 = ADC1->SMPR2;




  // Enable DMA             
  DMA1_Channel1->CNDTR = 3*FASTSAMPLE_BUFFER;
  DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
  DMA1_Channel1->CMAR = (uint32_t)&dma_sample_buffer;
  DMA1_Channel1->CCR =  (2<<DMA_CCR_MSIZE_Pos)|(2<<DMA_CCR_PSIZE_Pos)|
                        DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_EN 
                        | DMA_CCR_HTIE | DMA_CCR_TCIE | DMA_CCR_TEIE;
                        
  // Enable ADC trigger input
  ADC1->CR2 |= ADC_CR2_EXTTRIG | ADC_CR2_JEXTTRIG;
  ADC2->CR2 |= ADC_CR2_EXTTRIG | ADC_CR2_JEXTTRIG;
  // Enable ADC trigger source
  TIM3->CR1 |= (TIM_CR1_CEN);
  TIM4->CR1 |= (TIM_CR1_CEN);  
  // Stop overflowing memory during breakpoints.
  DBGMCU->CR |= DBGMCU_CR_DBG_TIM3_STOP | DBGMCU_CR_DBG_TIM4_STOP;
  
  HAL_NVIC_EnableIRQ(ADC1_2_IRQn);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}

Image A: https://dl.dropboxusercontent.com/s/so4vig7gaf5dref/2016-11-03%2014_23_52-%20STM32F103%20ADC%20sample%20skip.png

Thanks a lot.

Outcomes