This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

TripleMode ADC with DMA-Access

Hello everyone!
I've just picked up a STM32F446 and am currently learning to program it. To be honest: I'm struggling quite hard (coming from very simple processors like the PIC16 - the most advanced I've ever used was a MSP430).
So, here's the thing: For my current project I need to sample 9 analog values every 2 us. My first attempt was with single mode, but that turned out to be too slow. Now I'm trying to get it to work with TripleMode and DMA, which I have failed miserably until now.
The following code immediately produces an overrun on the ADC and the array that should hold the results of the conversion only contains 0x04A8.
What am I missing here? I'm thankful for any kind of help!

/* Private variables ---------------------------------------------------------*/
uint16_t ADCTripleConvertedValue[9];

/* Function Prototypes - System Setup ----------------------------------------*/
void System_Init(void);
void Init_ADCs(void);
void Init_Timer_5(void);

/*-------------- Int Main ----------------------------------------------------*/
int main(void)
{
        System_Init();                                                                                                                                          /* Setup GPIO-Pins, Timers, UART, etc */

        for (int i=0;i<9;i++)
    {
        ADCTripleConvertedValue[i]=i;
    }

        while (1)
        {
                ADC_SoftwareStartConv(ADC1);

                for(uint32_t i = 0; i < 0xFFFF; i++)
        }
}


/*-------------- Setup - functions -------------------------------------------*/
void System_Init()
{
        /* Enable peripheral clocks */
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

        Init_ADCs();
        Init_Timer_5();
}

void Init_Timer_5 ()                            /* ADC-Timer */
{
        TIM_TimeBaseInitTypeDef Timer_Struct;

        Timer_Struct.TIM_Prescaler = 9-1;                                                       /* Runs at 10 MHz */
        Timer_Struct.TIM_Period = 200000;                                                       /* 20 ms */
        Timer_Struct.TIM_CounterMode = TIM_CounterMode_Up;
        Timer_Struct.TIM_ClockDivision = TIM_CKD_DIV1;                          /* No clock division, only prescaler */

        TIM_TimeBaseInit(TIM5, &Timer_Struct);

        TIM_SelectOutputTrigger(TIM5, TIM_TRGOSource_Update);           /* ADC_ExternalTrigConv_T2_TRGO */

        TIM_Cmd(TIM5,ENABLE);
}

Rest of the code in the next post.

Parents
  • void Init_ADCs()
    {
            GPIO_InitTypeDef GPIO_InitStructure;                            /* Structure for GPIO-Setup */
            ADC_CommonInitTypeDef ADC_CommonInitStruct;                     /* Structure, which all ADCs have in common */
            ADC_InitTypeDef ADC_InitStruct;                                         /* Structure, which is different for every ADC */
            NVIC_InitTypeDef NVIC_InitStruct;                                       /* Structure for Interrupt-Setup */
            DMA_InitTypeDef DMA_InitStructure;
    
            /*
             * DMA 2 Channel 0 configuration
             */
            DMA_InitStructure.DMA_Channel = DMA_Channel_0;
            DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC->CDR;                                                               /* Base-Adress of the device used with DMA */
            DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCTripleConvertedValue[0];              /* Destination for the data */
            DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                                                                                         /* Transfer from ADC to memory */
            DMA_InitStructure.DMA_BufferSize = 9;                                                                                                                                                                   /* Total of 9 values to be stored */
            DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                                                        /* Do not increment the ADC-nr (Triple-Mode) */
            DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                                                                         /* Increment the memory-nr */
            DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;             /* Get a 16-Bit value from the ADC */
            DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                                             /* Save as 16-Bit value */
            DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                                                                                                         /* Automatically repeat the DMA-sequence */
            DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                                                                                             /* High priority, doesn't matter since it's the only DMA device working */
            DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                                                                  /* Disable the FIFO-buffer */
            DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
            DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
            DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
            DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    
            DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);
    
            DMA_Cmd(DMA2_Stream0, ENABLE);          /* DMA2_Stream0 enable */
    
            /* DMA-Stuff */
            ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE); /* Enable DMA request after last transfer (multi-ADC mode) */
    
            NVIC_InitStruct.NVIC_IRQChannel = DMA2_Stream0_IRQn;            /* Activate the interrupt */
            NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
            NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
            NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
            NVIC_Init(&NVIC_InitStruct);
    
            /*
                    Overall settings
            */
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;                    /* Analog mode */
            GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;          /* Push-Pull */
            GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  /* No Pull-Up or Pull-Down */
    
            ADC_CommonInitStruct.ADC_Mode = ADC_TripleMode_RegSimult;                                                                               /* TirpleMode mode - All three ADCs work at the same time */
            ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div2;                                                                                /* Minimum Prescaler - 2 */
            ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_1;                                                           /* NO IDEA */
            ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_8Cycles;               /* Delay between 2 sampling phases */
            ADC_CommonInit(&ADC_CommonInitStruct);
    
            ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
            ADC_InitStruct.ADC_ScanConvMode = ENABLE;                                                                                                                                               /* Scan all channels of one ADC at once */
            ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;                                                                                                                        /* Don't automatically repeat the conversion */
            ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;                      /* No external Trigger */
            ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;                                             /* ADC_extrenal_trigger_sources_for_regular_channels_conversion - it shouldn't */
            ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;                                                                                                       /* matter what I put in here, since I'm not using a timer or external interrupt */
            ADC_InitStruct.ADC_NbrOfConversion = 3;                                                                                                                                                 /* to start the conversion */
    
    /*
                    ADC 1
                    CH0  PA0
                    CH1  PA1
                    CH13 PC3
            */
            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
            GPIO_Init(GPIOA, &GPIO_InitStructure);
    
            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
            GPIO_Init(GPIOC, &GPIO_InitStructure);
    
            ADC_Init(ADC1, &ADC_InitStruct);                                                            /* 12-Bit resolution, scan all channels, 3 conversion, etc */
    
            ADC_RegularChannelConfig(ADC1, ADC_Channel_0,  1, ADC_SampleTime_56Cycles);             /* Set the corresponding channels for ADC1 */
            ADC_RegularChannelConfig(ADC1, ADC_Channel_1,  2, ADC_SampleTime_56Cycles);
            ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 3, ADC_SampleTime_56Cycles);
    
            ADC_Cmd(ADC1, ENABLE);  /* Enable ADC1 */
    
            ADC_DMACmd(ADC1, ENABLE); /* Enable ADC1 DMA */
    

    And there's more..

Reply
  • void Init_ADCs()
    {
            GPIO_InitTypeDef GPIO_InitStructure;                            /* Structure for GPIO-Setup */
            ADC_CommonInitTypeDef ADC_CommonInitStruct;                     /* Structure, which all ADCs have in common */
            ADC_InitTypeDef ADC_InitStruct;                                         /* Structure, which is different for every ADC */
            NVIC_InitTypeDef NVIC_InitStruct;                                       /* Structure for Interrupt-Setup */
            DMA_InitTypeDef DMA_InitStructure;
    
            /*
             * DMA 2 Channel 0 configuration
             */
            DMA_InitStructure.DMA_Channel = DMA_Channel_0;
            DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC->CDR;                                                               /* Base-Adress of the device used with DMA */
            DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCTripleConvertedValue[0];              /* Destination for the data */
            DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                                                                                         /* Transfer from ADC to memory */
            DMA_InitStructure.DMA_BufferSize = 9;                                                                                                                                                                   /* Total of 9 values to be stored */
            DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                                                        /* Do not increment the ADC-nr (Triple-Mode) */
            DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                                                                         /* Increment the memory-nr */
            DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;             /* Get a 16-Bit value from the ADC */
            DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                                             /* Save as 16-Bit value */
            DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                                                                                                         /* Automatically repeat the DMA-sequence */
            DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                                                                                             /* High priority, doesn't matter since it's the only DMA device working */
            DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                                                                  /* Disable the FIFO-buffer */
            DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
            DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
            DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
            DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    
            DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);
    
            DMA_Cmd(DMA2_Stream0, ENABLE);          /* DMA2_Stream0 enable */
    
            /* DMA-Stuff */
            ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE); /* Enable DMA request after last transfer (multi-ADC mode) */
    
            NVIC_InitStruct.NVIC_IRQChannel = DMA2_Stream0_IRQn;            /* Activate the interrupt */
            NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
            NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
            NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
            NVIC_Init(&NVIC_InitStruct);
    
            /*
                    Overall settings
            */
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;                    /* Analog mode */
            GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;          /* Push-Pull */
            GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  /* No Pull-Up or Pull-Down */
    
            ADC_CommonInitStruct.ADC_Mode = ADC_TripleMode_RegSimult;                                                                               /* TirpleMode mode - All three ADCs work at the same time */
            ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div2;                                                                                /* Minimum Prescaler - 2 */
            ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_1;                                                           /* NO IDEA */
            ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_8Cycles;               /* Delay between 2 sampling phases */
            ADC_CommonInit(&ADC_CommonInitStruct);
    
            ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
            ADC_InitStruct.ADC_ScanConvMode = ENABLE;                                                                                                                                               /* Scan all channels of one ADC at once */
            ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;                                                                                                                        /* Don't automatically repeat the conversion */
            ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;                      /* No external Trigger */
            ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;                                             /* ADC_extrenal_trigger_sources_for_regular_channels_conversion - it shouldn't */
            ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;                                                                                                       /* matter what I put in here, since I'm not using a timer or external interrupt */
            ADC_InitStruct.ADC_NbrOfConversion = 3;                                                                                                                                                 /* to start the conversion */
    
    /*
                    ADC 1
                    CH0  PA0
                    CH1  PA1
                    CH13 PC3
            */
            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
            GPIO_Init(GPIOA, &GPIO_InitStructure);
    
            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
            GPIO_Init(GPIOC, &GPIO_InitStructure);
    
            ADC_Init(ADC1, &ADC_InitStruct);                                                            /* 12-Bit resolution, scan all channels, 3 conversion, etc */
    
            ADC_RegularChannelConfig(ADC1, ADC_Channel_0,  1, ADC_SampleTime_56Cycles);             /* Set the corresponding channels for ADC1 */
            ADC_RegularChannelConfig(ADC1, ADC_Channel_1,  2, ADC_SampleTime_56Cycles);
            ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 3, ADC_SampleTime_56Cycles);
    
            ADC_Cmd(ADC1, ENABLE);  /* Enable ADC1 */
    
            ADC_DMACmd(ADC1, ENABLE); /* Enable ADC1 DMA */
    

    And there's more..

Children