cancel
Showing results for 
Search instead for 
Did you mean: 

stm32 adc irq

Daniel Fernandez
Associate II
Posted on June 21, 2018 at 19:37

Hi, I have a problem with my code and I dont know where it is. I have a stm 32f100 rb and i am trying to read two values of the adc. If you know how I can solve, teach me please. My code is the next. Thank you

//=============================================================================

#include 'stm32f10x.h'

#include 'antilib_gpio.h'

#include 'antilib_adc.h'

//=============================================================================

// Defines

//=============================================================================

#define LED_BLUE_GPIO GPIOC

#define LED_BLUE_PIN 8

#define LED_GREEN_GPIO GPIOC

#define LED_GREEN_PIN 9

//=============================================================================

// Global variables

//=============================================================================

int AIN[4]; // table for conversions results

//=============================================================================

// main function

//=============================================================================

int main(void)

{

RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;

RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN | RCC_APB2ENR_ADC1EN | RCC_APB2ENR_USART1EN;

RCC->AHBENR |= RCC_AHBENR_DMA1EN;

#if (LED_BLUE_PIN > 7)

LED_BLUE_GPIO->CRH = (LED_BLUE_GPIO->CRH & CONFMASKH(LED_BLUE_PIN)) |

GPIOPINCONFH(LED_BLUE_PIN, GPIOCONF(GPIO_MODE_OUTPUT2MHz, GPIO_CNF_AFIO_PUSHPULL));

#else

LED_BLUE_GPIO->CRL = (LED_BLUE_GPIO->CRL & CONFMASKL(LED_BLUE_PIN)) |

GPIOPINCONFL(LED_BLUE_PIN, GPIOCONF(GPIO_MODE_OUTPUT2MHz, GPIO_CNF_AFIO_PUSHPULL));

#endif

#if (LED_GREEN_PIN > 7)

LED_GREEN_GPIO->CRH = (LED_GREEN_GPIO->CRH & CONFMASKH(LED_GREEN_PIN)) | GPIOPINCONFH(LED_GREEN_PIN, GPIOCONF(GPIO_MODE_OUTPUT2MHz, GPIO_CNF_AFIO_PUSHPULL));

#else

LED_GREEN_GPIO->CRL = (LED_GREEN_GPIO->CRL & CONFMASKL(LED_GREEN_PIN)) | GPIOPINCONFL(LED_GREEN_PIN, GPIOCONF(GPIO_MODE_OUTPUT2MHz, GPIO_CNF_AFIO_PUSHPULL));

#endif

AFIO->MAPR = AFIO_MAPR_TIM3_REMAP; // Full TIM3 remap

TIM3->PSC = 239; // Set prescaler to 24 000 (PSC + 1)

TIM3->ARR = 500; // Auto reload value 500

TIM3->CCR3 = 0; // Start PWM duty for channel 3

TIM3->CCR4 = 0; // Start PWM duty for channel 4

TIM3->CCMR2 = TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 |

TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1; // PWM mode on channel 3 & 4

TIM3->CCER = TIM_CCER_CC4E | TIM_CCER_CC3E; // Enable compare on channel 3 & 4

TIM3->CR1 = TIM_CR1_CEN; // Enable timer

TIM3->DIER = TIM_DIER_UIE; // Enable update interrupt (timer level)

NVIC_EnableIRQ(ADC1_IRQn); // Enable interrupt from ADC1 (NVIC level)

GPIOA->CRL = (GPIOA->CRL & 0xFFFF0000) |

GPIOPINCONFL(0, GPIOCONF(GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG)) |

GPIOPINCONFL(1, GPIOCONF(GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG)) |

GPIOPINCONFL(2, GPIOCONF(GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG)) |

GPIOPINCONFL(3, GPIOCONF(GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG));

ADC1->CR2 = ADC_CR2_ADON | // turn on ADC

ADC_CR2_CONT | // enable continuos mode

ADC_CR2_DMA; // enable DMA mode

ADC1->CR1 = ADC_CR1_SCAN; // enable scan mode

ADC1->SQR1 = ADC_SEQUENCE_LENGTH(3); // four channels in sequence

ADC1->SQR3 = ADC_SEQ1(0) | // channel 0 is first in sequence

ADC_SEQ2(1) | // channel 1 is second in sequence

ADC_SEQ3(2) | // channel 2 is third in sequence

ADC_SEQ4(3) ; // channel 3 is fourth in sequence

ADC1->SMPR2 = ADC_SAMPLE_TIME0(SAMPLE_TIME_239_5) | // sample time for first channel in sequence

ADC_SAMPLE_TIME1(SAMPLE_TIME_239_5) | // sample time for second channel in sequence

ADC_SAMPLE_TIME2(SAMPLE_TIME_239_5) | // sample time for third channel in sequence

ADC_SAMPLE_TIME3(SAMPLE_TIME_239_5) ; // sample time for fourth channel in sequence

DMA1_Channel1->CPAR = (uint32_t)(&(ADC1->DR)); // peripheral (source) address

DMA1_Channel1->CMAR = (uint32_t)AIN; // memory (desination) address

DMA1_Channel1->CNDTR = 4; // 4 transfers

DMA1_Channel1->CCR |= DMA_CCR1_CIRC | // circular mode enable

DMA_CCR1_MINC | // memory increment mode enable

DMA_CCR1_MSIZE_0 | // memory size 16 bits

DMA_CCR1_PSIZE_0; // peripheral size 16 bits

DMA1_Channel1->CCR |= DMA_CCR1_EN ; // Enable channel

ADC1->CR2 |= ADC_CR2_ADON; // Turn on conversion

while (1);

}

//=============================================================================

// adc1 Interrupt Handler

//=============================================================================

void ADC1_IRQHandler(void)

{

if(ADC1->SR & ADC_SR_EOC) // if UIF flag is set

{

ADC1->SR &= ~ADC_SR_EOC; // clear UIF flag

TIM3->CCR3 = AIN[0];

TIM3->CCR4 = AIN[1];

}

}
7 REPLIES 7
Posted on June 21, 2018 at 20:06

Sorry not going to slog through your register level code.

You should use the DMA TC interrupt, or more preferably HT/TC, to determine when a particular run of ADC results has been completed.

https://community.st.com/0D50X00009XkiAHSAZ

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on June 21, 2018 at 22:03

Hello Daniel, the problem I identify in your code is related to not enabling the ADC interrupt into the ADC peripheral. You only enable the interrupt on NVIC. Also you try to use the DMA feature but never enable the DMA interrupt as suggested by Clive in his previous post. If you want to use DMA then you don't need to use the ADC interrupt. Often these operating modes are not used together, just only one.

I suggest you to check for application notes related to ADC + DMA, available at

http://www.st.com

web site. Another suggestion is to use some library to control your peripherals. It can be the Standard Peripheral Library or better try to use STM32CubeMX. You can find more information regarding Cube at:

https://www.st.com/en/development-tools/stm32cubemx.html

 

This utility helps you to create an initial project, ready to test, where you can customize to fit all your needs.

If you have any other question don't hesitate to ask.

Best regards, Yosmany.

Posted on June 23, 2018 at 12:49

Thank you for your answer.

The problem is that I dont know how to use the stm cube and I broke another micro trying the program. I have another problem if i dont use the interrupt on adc, and it is that de second adc that i use give me a value that is not 0 like the first. Because my objective is take this values on adcs and move it to a out in pwm that is connect to the leds. The first work perfect, but the second give me a value and the led is on without any voltage in his imput.

I hope your reply

Posted on June 23, 2018 at 14:21

The cube is very easy to use and necessary for MCUs with many pins and functions all cross mapped.

The cube wont make your program, but it will initialise everything,,,,  mostly.

Which IDE is you choose ?

It is not easy to get started on this equipment.

with the correct IDE you can single step, then you will know where your program is failing.

my code is 1000s of lines long.

you need a print console, easy to use the UART to PC Terminal emulator @ 230400 baud

I tried semihosting once, it was snail's pace maybe 50baud.

1000s of lines before you will know what you are doing.

Daniel Fernandez
Associate II
Posted on July 01, 2018 at 17:58

Hello again, if i want to use a interrupt of the dma how i can do it?? some like this:

//=============================================================================

// STM32VLDISCOVERY tutorial

// Lesson 9. Analog to digital converter (ADC) with direct memory access (DMA)

// Copyright : Radoslaw Kwiecien

//

https://community.st.com/external-link.jspa?url=http%3A%2F%2Fen.radzio.dxp.pl

// e-mail : radek(at)dxp.pl

//=============================================================================

#include 'stm32f10x.h'

#include 'antilib_gpio.h'

#include 'antilib_adc.h'

//=============================================================================

// Defines

//=============================================================================

#define USART_RX_GPIO GPIOA

#define USART_RX_PIN 10

#define USART_TX_GPIO GPIOA

#define USART_TX_PIN 9

#define LED_BLUE_GPIO GPIOC

#define LED_BLUE_PIN 8

#define LED_GREEN_GPIO GPIOC

#define LED_GREEN_PIN 9

//=============================================================================

// Send single char

//=============================================================================

void USART_PutChar(uint8_t ch)

{

while(!(USART1->SR & USART_SR_TXE));

USART1->DR = ch;

}

//=============================================================================

// Send text

//=============================================================================

void USART_PutString(uint8_t * str)

{

while(*str != 0)

{

USART_PutChar(*str);

str++;

}

}

//=============================================================================

// Global variables

//=============================================================================

vu16 AIN[4]; // table for conversions results

char str[32]; // buffer for text

//=============================================================================

// main function

//=============================================================================

int main(void)

{

vu32 dly;

RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN | RCC_APB2ENR_ADC1EN | RCC_APB2ENR_USART1EN;

RCC->AHBENR |= RCC_AHBENR_DMA1EN;

RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;

RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN | RCC_APB2ENR_ADC1EN | RCC_APB2ENR_USART1EN;

RCC->AHBENR |= RCC_AHBENR_DMA1EN;

#if (USART_RX_PIN > 7)

USART_RX_GPIO->CRH = (USART_RX_GPIO->CRH & CONFMASKH(USART_RX_PIN)) | GPIOPINCONFH(USART_RX_PIN, GPIOCONF(GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULLUPDOWN));

#else

USART_RX_GPIO->CRL = (USART_RX_GPIO->CRL & CONFMASKL(USART_RX_PIN)) | GPIOPINCONFL(USART_RX_PIN, GPIOCONF(GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULLUPDOWN));

#endif

#if (USART_TX_PIN > 7)

USART_TX_GPIO->CRH = (USART_TX_GPIO->CRH & CONFMASKH(USART_TX_PIN)) | GPIOPINCONFH(USART_TX_PIN, GPIOCONF(GPIO_MODE_OUTPUT2MHz, GPIO_CNF_AFIO_PUSHPULL));

#else

USART_TX_GPIO->CRL = (USART_TX_GPIO->CRL & CONFMASKL(USART_TX_PIN)) | GPIOPINCONFL(USART_TX_PIN, GPIOCONF(GPIO_MODE_OUTPUT2MHz, GPIO_CNF_AFIO_PUSHPULL));

#endif

#if (LED_BLUE_PIN > 7)

LED_BLUE_GPIO->CRH = (LED_BLUE_GPIO->CRH & CONFMASKH(LED_BLUE_PIN)) |

GPIOPINCONFH(LED_BLUE_PIN, GPIOCONF(GPIO_MODE_OUTPUT2MHz, GPIO_CNF_AFIO_PUSHPULL));

#else

LED_BLUE_GPIO->CRL = (LED_BLUE_GPIO->CRL & CONFMASKL(LED_BLUE_PIN)) |

GPIOPINCONFL(LED_BLUE_PIN, GPIOCONF(GPIO_MODE_OUTPUT2MHz, GPIO_CNF_AFIO_PUSHPULL));

#endif

#if (LED_GREEN_PIN > 7)

LED_GREEN_GPIO->CRH = (LED_GREEN_GPIO->CRH & CONFMASKH(LED_GREEN_PIN)) | GPIOPINCONFH(LED_GREEN_PIN, GPIOCONF(GPIO_MODE_OUTPUT2MHz, GPIO_CNF_AFIO_PUSHPULL));

#else

LED_GREEN_GPIO->CRL = (LED_GREEN_GPIO->CRL & CONFMASKL(LED_GREEN_PIN)) | GPIOPINCONFL(LED_GREEN_PIN, GPIOCONF(GPIO_MODE_OUTPUT2MHz, GPIO_CNF_AFIO_PUSHPULL));

#endif

AFIO->MAPR = AFIO_MAPR_TIM3_REMAP; // Full TIM3 remap

TIM3->PSC = 239; // Set prescaler to 24 000 (PSC + 1)

TIM3->ARR = 500; // Auto reload value 500

TIM3->CCR3 = 0; // Start PWM duty for channel 3

TIM3->CCR4 = 0; // Start PWM duty for channel 4

TIM3->CCMR2 = TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 |

TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1; // PWM mode on channel 3 & 4

TIM3->CCER = TIM_CCER_CC4E | TIM_CCER_CC3E; // Enable compare on channel 3 & 4

TIM3->CR1 = TIM_CR1_CEN; // Enable timer

TIM3->DIER = TIM_DIER_UIE; // Enable update interrupt (timer level)

NVIC_EnableIRQ(DMA1_Channel1_IRQn); // Enable interrupt from ADC1 (NVIC level)

GPIOA->CRL = (GPIOA->CRL & 0xFFFF0000) |

GPIOPINCONFL(0, GPIOCONF(GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG)) |

GPIOPINCONFL(1, GPIOCONF(GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG)) |

GPIOPINCONFL(2, GPIOCONF(GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG)) |

GPIOPINCONFL(3, GPIOCONF(GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG));

ADC1->CR2 = ADC_CR2_ADON | // turn on ADC

ADC_CR2_CONT | // enable continuos mode

ADC_CR2_DMA; // enable DMA mode

ADC1->CR1 = ADC_CR1_SCAN; // enable scan mode

ADC1->SQR1 = ADC_SEQUENCE_LENGTH(3); // four channels in sequence

ADC1->SQR3 = ADC_SEQ1(0) | // channel 0 is first in sequence

ADC_SEQ2(1) | // channel 1 is second in sequence

ADC_SEQ3(2) | // channel 2 is third in sequence

ADC_SEQ4(3) ; // channel 3 is fourth in sequence

ADC1->SMPR2 = ADC_SAMPLE_TIME0(SAMPLE_TIME_239_5) | // sample time for first channel in sequence

ADC_SAMPLE_TIME1(SAMPLE_TIME_239_5) | // sample time for second channel in sequence

ADC_SAMPLE_TIME2(SAMPLE_TIME_239_5) | // sample time for third channel in sequence

ADC_SAMPLE_TIME3(SAMPLE_TIME_239_5) ; // sample time for fourth channel in sequence

DMA1_Channel1->CPAR = (uint32_t)(&(ADC1->DR)); // peripheral (source) address

DMA1_Channel1->CMAR = (uint32_t)AIN; // memory (desination) address

DMA1_Channel1->CNDTR = 4; // 4 transfers

DMA1_Channel1->CCR |= DMA_CCR1_CIRC | // circular mode enable

DMA_CCR1_MINC | // memory increment mode enable

DMA_CCR1_MSIZE_0 | // memory size 16 bits

DMA_CCR1_PSIZE_0; // peripheral size 16 bits

DMA1_Channel1->CCR |= DMA_CCR1_EN ; // Enable channel

ADC1->CR2 |= ADC_CR2_ADON; // Turn on conversion

USART1->CR1 = USART_CR1_UE | USART_CR1_TE;

USART1->BRR = (SystemCoreClock / 115200);

USART_PutString('STM32VLDISCOVERY tutorial lesson 9\r');

while (1);

}

//=============================================================================

// TIM3 Interrupt Handler

//=============================================================================

void DMA1_Channel1_IRQHandler(void)

{

if(DMA1->ISR & DMA_ISR_TCIF1) // if UIF flag is set

{

DMA1->ISR &= ~DMA_ISR_TCIF1; // clear UIF flag

TIM3->CCR3 = AIN[0];

TIM3->CCR4 = AIN[1];

}

}

I haven´t got idea of how use a interrupt here with multi adc, interrupt of dma or adc. But I need, help me please. Thanks

Posted on July 01, 2018 at 18:14

>>I haven´t got idea of how use a interrupt here with multi adc, interrupt of dma or adc. But I need, help me please.

The interrupt tells you when the array contains a new set of values, you can either manage that in the interrupt handler, or flag\semaphore for some other task.

If you can separate yourself from a sequential/linear mindset, you could compute new parameters in the IRQ handler.

One thing to consider is if the interrupt is occurring too frequently, or if you need to double up the buffer so you can inspect the half that is not currently active.

If you are trying to record the samples, consider a much larger buffer to allow time for data to be written to storage media.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on July 02, 2018 at 00:58

Maybe you can get an ADC example running.

Try to find an ADC DMA example for your board.

without the cube, I cannot help, I don't know if your setup is correct,

You could be chasing your tail with a single typo or character out of place or line missing, in the setup.

Do you work for Protel / DXP ?