We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hi,
I want to program STM32F103 in which define an array that is completed with ADC value. I need to trigger the ADC with timer and also use DMA. It means that when the array complete, the DMA_IRQ Handler send this array by USART channel. I wrote this code but it doesn't work.
I would be appreciate if you help me to correct this program.
#include "stm32f10x.h" #define ADC1_DR_Address ((uint32_t)0x4001244C) uint16_t array [32]; DMA_InitTypeDef DMA_InitStructure; int main(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); NVIC_InitTypeDef sara3; sara3.NVIC_IRQChannel = DMA1_Channel1_IRQn; sara3.NVIC_IRQChannelPreemptionPriority = 0; sara3.NVIC_IRQChannelSubPriority = 0; sara3.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&sara3); TIM_TimeBaseInitTypeDef Tim_TimeBaseStructure; TIM_TimeBaseStructInit(&Tim_TimeBaseStructure); Tim_TimeBaseStructure.TIM_Period = 9000; Tim_TimeBaseStructure.TIM_Prescaler = 0x0; Tim_TimeBaseStructure.TIM_ClockDivision = 0x0; Tim_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &Tim_TimeBaseStructure); TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); /* TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0x7F; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; TIM_OC1Init(TIM2, &TIM_OCInitStructure); */ ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5); //ADC_SoftwareStartConvCmd(ADC1,ENABLE); DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)array; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 32; 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_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA_InitStructure); USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = 115200; 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(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_ITConfig(USART1, USART_IT_TXE, ENABLE); USART_ClearFlag(USART1,USART_FLAG_TC); DMA_ITConfig (DMA1_Channel1, DMA_IT_TC,ENABLE); DMA_Cmd(DMA1_Channel1, ENABLE); ADC_Cmd(ADC1, ENABLE); ADC_DMACmd(ADC1, ENABLE); USART_Cmd(USART1, ENABLE); TIM_Cmd(TIM2, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); while (1); } void DMA1_Channel1_IRQHandler(void) { uint8_t i = 0; if( DMA_GetITStatus(DMA1_FLAG_TC1) ) { for(i = 0;i < 32 ; i++){ USART_SendData(USART1, (uint8_t) array[i]); while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {} USART_SendData(USART1, (uint8_t) array[i]>> 8); while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {} } DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)array; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 32; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA_InitStructure); ADC_DMACmd(ADC1, ENABLE); DMA_Cmd(DMA1_Channel1, ENABLE); DMA_ClearITPendingBit(DMA1_IT_TC1); DMA_ClearITPendingBit(DMA1_IT_GL1); } }
You don't want it continuous if the timer is supposed to be triggering it.
You select Channel 2 of the timer as the source, but then configure it to interrupt on the Update, rather than do anything to configure Channel 2
The DMA initialization and interrupt clearing in the IRQ doesn't look right, and surely the memory address should increment.
You enable a TIM2 interrupt, but don't configure the NVIC, or have a handler.
You use C++ syntax, w atch the name mangling doesn't break your interrupts.
I could'nt find any in tne posted sourcecode that show's C++ Code. It's native C language that fill's the init structures of stdLibrary functions to initialize the DMA and other hardware.
Well, the topic sounds like a problem with the dma usage. I remember that there is a problem realated to the DMA usage with the STM32F1xx family. The usage of one DMA should be ok, but more than one results in an unexpected state. There is an errata available who describe the details around the dma issue. I had successfully used the DMA transfer mode to readout the ADC1 on STM32F103VC and STM32F407VG.
Good luck to solve the problems and don't foget to report the final results or the solution.
Juppeck
I add some init code that uses the STM32F407 and this show's the setup of 4 ADC1 channels handled by DMA transfer.
#define Num_used_ADC_Channels 5 // how many ADC channels should be handled? // Wieviel ADC-Kanäle sollen ausgelesen werden? !!! #define Num_Of_Used_Buffers Num_used_ADC_Channels // how many memory should be used by DMA ? volatile uint16_t ADCBuffer[Num_Of_Used_Buffers + 2] = { 0x00AA,0,0,0,0,0,0x00BB }; // DMA-Buffer - 5 words enum __ADC_CHAN_BUFF_ORDER__ { CH0 = 1, CH1 = 2, VBAT = 3, TEMP = 4, VREF = 5 }; // Weleche Reihenfolge sollen die ADC Kanöäle gelesen werden? void Init_ADC ( void ) { // ############## ADC ########################################################################################################## // ---------- Configure PB0 and PB1 (ADC Channel1 and ADC Channel2 ) as analog input ------------------ // // GPIOB function block clock enable RCC_APB2PeriphClockCmd ( RCC_APB2Periph_ADC1, ENABLE ); // clock to ADC1 RCC_AHB1PeriphClockCmd ( RCC_AHB1Periph_GPIOB, ENABLE ); // clock to PortB GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; // Init AIN0 / AIN1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; // alternative mode "Analog in" GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init ( GPIOB, &GPIO_InitStructure ); // Init GPIO-PORTA as Analog input // DMA2 Stream0 configuration ------------------------------------------------------------------------------------------------ // // Enable DMA2 clock RCC_AHB1PeriphClockCmd ( RCC_AHB1Periph_DMA2, ENABLE ); DMA_DeInit ( DMA2_Stream0 ); DMA_InitStructure.DMA_Channel = DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) ADC1_DR_Address; // source DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &ADCBuffer[1]; // destination - start to copy by dma at the second element of the array DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // Transfertype DMA_InitStructure.DMA_BufferSize = Num_used_ADC_Channels; // Num of ADC register that should transfered DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Register address is static - no increment. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // auto increment the memory at each transfer DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // transfer size of source register DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // transfer size of destinantion (array) DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // at the end of dma transfer cycle, starts again. DMA_InitStructure.DMA_Priority = DMA_Priority_Low; // system load depended - i decide me to low priority. 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 ( DMA2_Stream0, &DMA_InitStructure ); DMA_Cmd ( DMA2_Stream0, ENABLE ); // ------------------ ADC1 configuration ------------------------------------------------------- // ADC_DeInit(); ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div8; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; ADC_CommonInit(&ADC_CommonInitStructure); // ########################### ADC1 Init ######################################### ADC_InitStructure.ADC_Resolution = RESOLUTION; // Auflösung definiert in ADC1.h ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // dauerhaft lesen und wandeln ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; // ADC_InitStructure.ADC_ExternalTrigConv = 0; // ohne Trigger ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // Conversions are 12 bit - put them in the lower 12 bits of the result ADC_InitStructure.ADC_NbrOfConversion = Num_used_ADC_Channels; // num of adc-channels ADC_Init (ADC1, &ADC_InitStructure); ADC_DMACmd ( ADC1, ENABLE ); // Enable ADC1 DMA // ######### ADC1 regular conversation mode configuration #################################### // ADC , CHANNEL, DMA MemoryOrder, SampleTime // ADC_RegularChannelConfig(ADC1, ADC_Channel_8, CH0, ADC_SampleTime_15Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_9, CH1, ADC_SampleTime_15Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_Vbat, VBAT, ADC_SampleTime_15Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_TempSensor, TEMP, ADC_SampleTime_15Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_Vrefint, VREF, ADC_SampleTime_15Cycles); ADC_VBATCmd ( ENABLE ); // Enable VBAT at channel 18 ADC_TempSensorVrefintCmd ( ENABLE ); // Enable TempSensor and Vrefint at channels 16 and 17 ADC_DMARequestAfterLastTransferCmd ( ADC1, ENABLE ); // Enable DMA request after last transfer (Single-ADC mode) ADC_Cmd ( ADC1, ENABLE ); // Enable ADC1 ADC_SoftwareStartConv ( ADC1 ); // Start ADC1 Software Conversion return; }
take care of the volatile declared array variable
Congratulation on digging up a two month old thread, and then missing all the nuances of the problem. There's a least a dozen problems with the original code, and your solution is to post an example for a different processor which doesn't really address any of the core issues. Nor does it do what the OP wanted on your chosen target.
Sure I could have wasted a bunch of my time correcting and fixing this, but I'd learn nothing, and the OP would miss a learning moment that you can't just cut and paste a bunch of random code together without any thought, or bothering to read the reference manuals.
HEY.
i wanna to read the timer value and put it onto the adc. it must use dma channels 3 or 5. how can i do it? code gotta be working by two days. plz post examples
The world haven't figured out yet how to put the timer value onto the ADC. But if you instead feed it to the DAC, you get a nice sawtooth output.
Quit wasting time trolling on the internets and get busy then.
I guess that nobody want to do the work for you, so you must solve them instead.
Where is the DMA channel declaration?
like: DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)array; <--- this don't works. DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&array;<-- This works - see my example
DMA_InitStructure.DMA_BufferSize = 32; 32 half-word are used as Buffer? ADC_InitStructure.ADC_NbrOfChannel = 1; and just one CHannel should be aquire????
ADC_InitStructure.ADC_NbrOfChannel = 1; one channel needs just DMA_InitStructure.DMA_BufferSize = 1; one memory sized of a half-word buffer
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; <-- not required to fill - you do P2M
// This should used to trigger the conversation by the timer. // ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; // ADC_InitStructure.ADC_ExternalTrigConv = 0;
I don't had looked your code longer because the structure is mystic.