2
\$\begingroup\$

Code here is configuring DMA2 for transferring 160 samples each from two analog channels from ADC1 to memory.

The ADC,DMA,NVIC etc. seem properly configured but for some reason I am getting transfer errors exactly as the ADC is turned on.

More precisely, the TEIF0 flag for DMA2 and OVR flag for ADC1 is raised exactly after ADC_Cmd in the second snippet is called.

When looking for causes for Transfer errors in RM0090 all it states is:

Transfer error: the transfer error interrupt flag (TEIFx) is set when:

– A bus error occurs during a DMA read or a write access

– A write access is requested by software on a memory address register in Double buffer mode whereas the stream is enabled and the current target memory is the one impacted by the write into the memory address register (refer to Section 10.3.9: Double buffer mode)

The definition isn't very informative. A link to a similar issue can be found here: https://www.mikrocontroller.net/topic/389574

is it possible that the issue may be coming from the startup code? The code here was ported from a project that originally uses is compiled on Linux system with GNU makefile. But the same code was successfully compiled and run on the same chip with Keil MDK and all other functionality like LEDs, GPIO ports seems to be running well.

Debugging the code with Keil I also have access to the register values if they're needed.

Timer2 for external triggering of ADC is configured like so:

static void tim2_config(int fs_divisor)
{
  TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;

  /* TIM2 Periph clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  /* Time base configuration */

  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
   TIM_TimeBaseStructure.TIM_Period = fs_divisor - 1;
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

  /* TIM2 TRGO selection */

  TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);

  /* TIM2 enable counter */

  TIM_Cmd(TIM2, ENABLE);
}

The ADC and DMA are then configured like so:

void adc_configure(){
    ADC_InitTypeDef  ADC_init_structure;
    GPIO_InitTypeDef GPIO_initStructre;
    DMA_InitTypeDef  DMA_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // Clock configuration

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1ENR_GPIOAEN,ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

    // Analog pin configuration ADC1->PA1, ADC2->PA2

    GPIO_initStructre.GPIO_Pin =  GPIO_Pin_1 | GPIO_Pin_2;
    GPIO_initStructre.GPIO_Mode = GPIO_Mode_AN;
    GPIO_initStructre.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA,&GPIO_initStructre);

    // ADC structure configuration

    ADC_DeInit();
    ADC_init_structure.ADC_DataAlign = ADC_DataAlign_Left;
    ADC_init_structure.ADC_Resolution = ADC_Resolution_12b;
    ADC_init_structure.ADC_ContinuousConvMode = DISABLE;
    ADC_init_structure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
    ADC_init_structure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
    ADC_init_structure.ADC_NbrOfConversion = 2;
    ADC_init_structure.ADC_ScanConvMode = ENABLE;
    ADC_Init(ADCx,&ADC_init_structure);

    // Select the channel to be read from

    ADC_RegularChannelConfig(ADCx,ADC_Channel_1,1,ADC_SampleTime_144Cycles);
    ADC_RegularChannelConfig(ADCx,ADC_Channel_2,2,ADC_SampleTime_144Cycles);
    //ADC_VBATCmd(ENABLE);

    DMA_DeInit(DMA_STREAMx);
    DMA_InitStructure.DMA_Channel = DMA_CHANNELx;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADCx_DR_ADDRESS;
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)adc_buf;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize = ADC_BUF_SZ;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(DMA_STREAMx, &DMA_InitStructure);

    /* Enable DMA request after last transfer (Single-ADC mode) */

    ADC_DMARequestAfterLastTransferCmd(ADCx, ENABLE);

    /* Enable ADC1 DMA */

    ADC_DMACmd(ADCx, ENABLE);

    /* DMA2_Stream0 enable */

    DMA_Cmd(DMA_STREAMx, ENABLE);

    /* Enable DMA Half & Complete interrupts */

    DMA_ITConfig(DMA2_Stream0,DMA_IT_TC | DMA_IT_HT, ENABLE);

    /* Enable the DMA Stream IRQ Channel */

    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // Enable and start ADC conversion

    ADC_Cmd(ADC1,ENABLE);
    ADC_SoftwareStartConv(ADC1);
}
\$\endgroup\$
2
\$\begingroup\$

Found the solution.

Turns out it was a clocking issue. I tried to check to see what the clocks were set at using:

int main(){
    RCC_ClocksTypeDef * RCC_Clocks;
    RCC_Clocks = malloc(sizeof(RCC_ClocksTypeDef));
    RCC_GetClocksFreq(RCC_Clocks);
    ....

Turned out they weren't set properly. Very simple solution. Shame it cost so much time to figure out!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.