AnsweredAssumed Answered

Interleaved ADC

Question asked by John Hite on Feb 23, 2017
Latest reply on Feb 24, 2017 by John Hite

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();
}

Outcomes