cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F0 ADC->DMA touble

danielblesener9
Associate II
Posted on March 26, 2014 at 16:54

I have looked over the following code many times. Not sure what the problem is. Any incite? The raw_dma_adc[] array has no values in it during debug.

The code is for a STM32F051K6U6. End goal is to have 5 channels running. GPIO clock for port A has been enabled.

    ///////////////////////ADC

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2| GPIO_Pin_3 | GPIO_Pin_4;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

    ADC_DeInit(ADC1);

    DMA_DeInit(DMA1);

    ADC_InitTypeDef Impac_ADC;

    Impac_ADC.ADC_Resolution = ADC_Resolution_12b;

    Impac_ADC.ADC_ContinuousConvMode = ENABLE;

    Impac_ADC.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;

    Impac_ADC.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_TRGO; //not used

    Impac_ADC.ADC_DataAlign = ADC_DataAlign_Right;

    Impac_ADC.ADC_ScanDirection = ADC_ScanDirection_Backward;

    ADC_Init(ADC1, &Impac_ADC);

    ADC_ChannelConfig(ADC1, ADC_Channel_0, ADC_SampleTime_239_5Cycles);

    ADC_ChannelConfig(ADC1, ADC_Channel_1, ADC_SampleTime_239_5Cycles);

    //Calibrate ADC. This must be done before enabling the ADC. The function has a delay built in to allow for wait for calibration.

    ADC_GetCalibrationFactor(ADC1);

    ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular);

    DMA_InitTypeDef Impac_DMA;

    Impac_DMA.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;

    Impac_DMA.DMA_MemoryBaseAddr = (uint32_t)&raw_dma_adc[0];

    Impac_DMA.DMA_DIR = DMA_DIR_PeripheralSRC;//? //DMA_DIR_PeripheralSRC;

    Impac_DMA.DMA_BufferSize = 2;

    Impac_DMA.DMA_PeripheralInc = DMA_PeripheralInc_Enable;         //Keep incrimenting pointer to ADC buffer as tranfering.

    Impac_DMA.DMA_MemoryInc = DMA_MemoryInc_Enable;                 //Keep incrimenting pointer to DMA mem

    Impac_DMA.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;

    Impac_DMA.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;

    Impac_DMA.DMA_Mode = DMA_Mode_Circular;

    Impac_DMA.DMA_Priority = DMA_Priority_High;

    Impac_DMA.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1, &Impac_DMA);

   

    ADC_DMACmd(ADC1, ENABLE);

   

    ADC_Cmd(ADC1, ENABLE);

   

    DMA_Cmd(DMA1_Channel1, ENABLE);

    ADC_StartOfConversion(ADC1);

15 REPLIES 15
Posted on June 06, 2014 at 14:09

For just four values in to memory, I probably wouldn't use the TC/HT interrupts in this fashion.

The USART output sends 8-bit binary bytes, not sure how helpful that is as the numbers are 12-bit, and an ASCII decimal output would be easier to view on a terminal.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
entwicklung
Associate II
Posted on June 06, 2014 at 15:28

Thanks a lot for your reply. Sure, I forgot to split the bytes. I do it like this:

USART_SendData(USART2,RegularConvData[0]&0xFF);
while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
USART_SendData(USART2,RegularConvData[0]>>8);

I think the problem is, that I'm not sure, where the ADC data is actually stored. I don't think,

RegularConvData[0]

goes to PA4. How to control that? I have to read more at the weekend....
Posted on June 06, 2014 at 16:07

Yes the data should be order in the array, I'm not using the F0 part but I think it's ranked by channel# upward or downward as configured.

Not sure of the merit of using the timer in this case, but it paces the start of the group conversion. You could program the ADC in a continuous mode and it would keep jamming away at top speed. Here's a quick blind adaption to your USART output model.

// STM32 ADC 4 Channel DMA/TIM USART2 STM32F0-Discovery sourcer32@gmail.com
#include ''stm32f0xx.h''
//**************************************************************************************
#define SAMPLES 4
volatile uint16_t RegularConvData[SAMPLES];
void ADC_TIM_DMA_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
/* ADC1 DeInit */
ADC_DeInit(ADC1);
/* ADC1 Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_TIM1, ENABLE);
/* DMA1 clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* TIM2 Configuration */
TIM_DeInit(TIM1);
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 1000000) - 1; // 1 MHz, from 48 MHz
TIM_TimeBaseStructure.TIM_Period = 1000 - 1; // 1 KHz
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* Output Compare PWM Mode configuration */
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; /* low edge by default */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 1;
TIM_OC4Init(TIM1, &TIM_OCInitStructure);
/* TIM1 enable counter */
TIM_Cmd(TIM1, ENABLE);
/* Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
/* DMA1 Channel1 Config */
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&RegularConvData[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = SAMPLES;
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_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
/* DMA1 Channel1 enable */
DMA_Cmd(DMA1_Channel1, ENABLE);
/* ADC DMA request in circular mode */
ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular);
/* Enable ADC_DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Initialize ADC structure */
ADC_StructInit(&ADC_InitStructure);
/* Configure the ADC1 in continous mode withe a resolutuion equal to 12 bits */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC4;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;
ADC_Init(ADC1, &ADC_InitStructure);
/* Convert the ADC_Channnel_0 with 7.5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_4 , ADC_SampleTime_7_5Cycles);
/* Convert the ADC_Channnel_1 with 7.5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_5 , ADC_SampleTime_7_5Cycles);
/* Convert the ADC_Channnel_2 with 7.5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_6 , ADC_SampleTime_7_5Cycles);
/* Convert the ADC_Channnel_3 with 7.5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_7 , ADC_SampleTime_7_5Cycles);
/* ADC Calibration */
ADC_GetCalibrationFactor(ADC1);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Wait the ADCEN flag */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN));
/* ADC1 regular Software Start Conv */
ADC_StartOfConversion(ADC1);
}
//**************************************************************************************
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOA Periph clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/* Configure ADC Channels as analog input - might conflict */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART pins */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_1); // USART2_TX
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_1); // USART2_RX
}
//**************************************************************************************
void USART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
/* USART2 9600 8N1 */
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE);
}
//**************************************************************************************
char USART_GetChar(void)
{
while(USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET); // Wait For input character
return((char)USART_ReceiveData(USART2));
}
//**************************************************************************************
void USART_PutChar(char ch)
{
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); // Wait for holding buffer empty
USART_SendData(USART2, ch);
}
//**************************************************************************************
void USART_PutString(char *s)
{
while(*s)
USART_PutChar(*s++);
}
//**************************************************************************************
void USART_PutDecimal(unsigned int i)
{
char String[16];
char *s = String + sizeof(String);
*--s = 0; // NUL
do
{
*--s = '0' + (char)(i % 10);
i /= 10;
}
while(i);
USART_PutString(s);
}
//**************************************************************************************
int main(void)
{
GPIO_Configuration();
ADC_TIM_DMA_Configuration();
USART_Configuration();
while(1)
{
char ch;
ch = USART_GetChar();
if (ch == '#')
{
USART_PutDecimal(RegularConvData[0]);
USART_PutChar(',');
USART_PutDecimal(RegularConvData[1]);
USART_PutChar(',');
USART_PutDecimal(RegularConvData[2]);
USART_PutChar(',');
USART_PutDecimal(RegularConvData[3]);
USART_PutChar('
');
USART_PutChar('
');
}
}
}
//**************************************************************************************
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d

'', file, line) */
/* Infinite loop */
while (1)
{}
}
#endif

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
entwicklung
Associate II
Posted on June 10, 2014 at 13:38

Thanks again for your reply. The code is working fine.

It seems like the data in the array is arranged like this:

RegularConvData[0]; // PA7
RegularConvData[1]; // PA4
RegularConvData[2]; // PA5
RegularConvData[3]; // PA6

gerhard
Associate II
Posted on June 21, 2016 at 22:08

clive1

I am using STMCubeMX to set up ADC on STM32F051

How can I use the generated code to switch from Channel_0 to Channel_1

I use EOC flag, and it works fine for Channel_0.

Without jumping through hoops to rewrite the code generated by STM32CubeMX, and using the HAL generated code.

Any help appreciated

Posted on June 22, 2016 at 01:37

I'm not providing support for HAL/Cube, sorry.

The STM32 ADC aren't really architected for switching channels on the fly or supporting EOC beyond a single channel. Some parts support an injection mode, but I'm not sufficiently familiar with the F0. Your best model is to do a pair of conversions from a single trigger, using the DMA to flag the EOC (ie TC) and then discarding the unwanted result. This is apt to be less burdensome than reconfiguring the ADC repeatedly.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..