cancel
Showing results for 
Search instead for 
Did you mean: 

Interleaved ADC

John Hite
Associate III
Posted on February 23, 2017 at 00:04

Device: STM32F437

I am using ADC3 channels 5 (rank 1) and 8 (rank 2) in interleaved mode, the input for channel 5 is 0 volts and the input for channel 8 is near upper limit. Trapping after the first interrupt the 32 location array looks correct, counts near zero for the even locations, and high counts for the odd locations. However, on all subsequent occasions the pattern is reversed.

Is there some type of resetting action I need to take after a transfer is complete? I have included some code below so you can see how I have set up the ADC and DMA. I trimmed it down as much as I thought practical but apologize that it is still rather lengthy.

Thanks,

jh

OS_SEM adc_done;

static uint16_t adc3_result[ADC_NUM_READINGS*ADC_NUM_CHANNELS];

static const uint8_t injected_map[4] = {

  ADC_InjectedChannel_1,

  ADC_InjectedChannel_2,

  ADC_InjectedChannel_3,

  ADC_InjectedChannel_4

};

void AnalogTask(void *parg)

{

  OS_ERR err;

  uint8_t spoke;

  uint16_t adcA, adcB, adcInj;

  static chan_data_t aux;  //  Also used for auxiliary data

   AdcInit();

  for(;;) {

 

    AdcMux(0, READING_V, READING_V);  //setup regular and inj chans  

    

    OSTimeDly(OS_CFG_TICK_RATE_HZ/100, OS_OPT_TIME_PERIODIC, &err);

    if (err != OS_ERR_NONE) {

      APP_CATCH('ERROR: AnalogTask()::OSTimeDly() failed');

    }

    

    adcInj=AdcRead(&adcA, &adcB);

    A[spoke] = adcA/16;

    B[spoke] = adcB/16;

  }

}

void AdcInit(void)

{

  ADC_InitTypeDef init;

  NVIC_InitTypeDef nvic;

  OS_ERR err;

  uint8_t i;

 

  OSSemCreate(&adc_done, 'ADC DMA Complete', 0, &err);

  if (err != OS_ERR_NONE) {

    APP_CATCH('ERROR: AdcInit()::OSSemCreate() failed');

  }

 

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);

 

  DMA_DeInit(DMA2_Stream0);

 

  ADC_DeInit();

  ADC_StructInit(&init);

  init.ADC_ScanConvMode = ENABLE;

  init.ADC_ContinuousConvMode = ENABLE;

  init.ADC_NbrOfConversion = ADC_NUM_CHANNELS;

  ADC_Init(ADC3, &init);

  ADC_Cmd(ADC3, ENABLE);  //  DMA to be done later...

 

  //  Base config for Injected channel conversion:

  ADC_InjectedSequencerLengthConfig(ADC3, 4);

  for (i=0; i<4; i++) {

    ADC_SetInjectedOffset(ADC3, injected_map[i], 0);

  }

 

  nvic.NVIC_IRQChannel = DMA2_Stream0_IRQn;

  nvic.NVIC_IRQChannelPreemptionPriority = 1;

  nvic.NVIC_IRQChannelSubPriority = 0;

  nvic.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&nvic);

 

  ADC_DMARequestAfterLastTransferCmd(ADC3, DISABLE);

  DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);

  DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);

}

static const DMA_InitTypeDef dma2 =

{

  DMA_Channel_2,

  ADC3_BASE+0x4C,                       //  ADC3->DR

  (uint32_t)&adc3_result[0],            //Mememory 0 base addre

  DMA_DIR_PeripheralToMemory,           //Direction  DMA_DIR_PeripheralToMemory,DMA_DIR_MemoryToPeripheral,DMA_DIR_MemoryToMemory

  ADC_NUM_READINGS*ADC_NUM_CHANNELS,    //Buffer size         

  DMA_PeripheralInc_Disable,            // Increment or not           

  DMA_MemoryInc_Enable,                 // Increment or not

  DMA_PeripheralDataSize_HalfWord,      //_Byte, _HalfWord, _Word

  DMA_MemoryDataSize_HalfWord,          //Same

  DMA_Mode_Normal,                      //_NOrmal or _Circular

  DMA_Priority_Medium,

  DMA_FIFOMode_Disable,

  DMA_FIFOThreshold_1QuarterFull,

  DMA_MemoryBurst_Single,

  DMA_PeripheralBurst_Single

};

void AdcMux(void)

{

  uint8_t i;

    

  //  Set MUX pins

  GPIO_WriteBit(GPIOD, GPIO_Pin_3, 1);

  GPIO_WriteBit(GPIOD, GPIO_Pin_4, 0);

 

  //  Configure 'core' channels

  ADC_RegularChannelConfig(ADC3, ADC_Channel_5, 1, ADC_SampleTime_480Cycles);

  ADC_RegularChannelConfig(ADC3, ADC_Channel_8, 2, ADC_SampleTime_480Cycles);

 

  //  Configure injected read

  for (i=1; i <= 4; i++) {

    ADC_InjectedChannelConfig(ADC3, ADC_Channel_14),

      i, ADC_SampleTime_480Cycles);  

  }

 

  //  Go ahead and read the injected channels

  ADC_SoftwareStartInjectedConv(ADC3);

}

uint16_t AdcRead(uint16_t *bankA, uint16_t *bankB)

{

  OS_ERR err;

  CPU_TS ts;

  uint32_t i;

  uint16_t inj=0, a=0, b=0;

  uint16_t *result=&adc3_result[0];

  DMA_Init(DMA2_Stream0, (DMA_InitTypeDef*)&dma2);

  DMA_Cmd(DMA2_Stream0, ENABLE);

  ADC_DMACmd(ADC3, ENABLE);

  ADC_SoftwareStartConv(ADC3);

  OSSemPend(&adc_done, 0, OS_OPT_PEND_BLOCKING, &ts, &err);

  if (err != OS_ERR_NONE) {

    APP_CATCH('ERROR: AdcRead()::OSSemPend() failed');

  }

 

  ADC_DMACmd(ADC3, DISABLE);

                  //16

  for (i = 0; i < ADC_NUM_READINGS; i++)

  {

    a += *result++;  

    b += *result++;

    if (i < 4) {

      inj += ADC_GetInjectedConversionValue(ADC3, injected_map[i]);

    }

  }

 

  *bankA=a;

  *bankB=b;

  return inj;

}

void Adc3ISR(void)

{

  OS_ERR err;

  CPU_SR_ALLOC();

 

  CPU_INT_DIS();

  OSIntNestingCtr++;

  CPU_INT_EN();

  if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) == SET)

//if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TC) == SET)

  {

    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);

    OSSemPost(&adc_done, OS_OPT_POST_1, &err);

    if (err != OS_ERR_NONE)

    {

      APP_CATCH('ERROR: Adc3ISR()::OSSemPost() failed');

    }

  }

  OSIntExit();

}
2 REPLIES 2
John Hite
Associate III
Posted on February 24, 2017 at 14:41

I am wondering if the problem is related to the fact that my code disables and re-enables ADC_DMACmd(). This is necessary because the inputs need to be re-configured between sample sets. This is how the enable/disable is done:

  DMA_Init(DMA2_Stream0, (DMA_InitTypeDef*)&dma2);

  DMA_Cmd(DMA2_Stream0, ENABLE);

  ADC_DMACmd(ADC3, ENABLE);

  ADC_SoftwareStartConv(ADC3);

  OSSemPend(&adc_done, 0, OS_OPT_PEND_BLOCKING, &ts, &err);

  if (err != OS_ERR_NONE) {

    APP_CATCH('ERROR: AdcRead()::OSSemPend() failed');

  }

 

  ADC_DMACmd(ADC3, DISABLE);

The examples I have found so far run continuously w/o starting and stopping.

I would appreciate it if you could point me to a sample of interleaved reading that turns the process off and on as we are trying to do.

Thanks,

jh

John Hite
Associate III
Posted on February 24, 2017 at 16:10

Common initialization was missing so I added the following to AdcInit() to eliminate a cause but it made no difference.

  cInit.ADC_Mode = ADC_DualMode_Interl;

  cInit.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;

  cInit.ADC_DMAAccessMode = ADC_DMAAccessMode_1;  

  cInit.ADC_Prescaler = ADC_Prescaler_Div2;

  ADC_CommonInit(&cInit);