Starting ADC1 by hardware trigger on STM32F103

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

joewa
Posts: 22
Joined: Tue May 13, 2014 10:40 pm

Starting ADC1 by hardware trigger on STM32F103

Post by joewa »

For a motor control application I need to do high speed (as fast as possible) ADC measurements that are exactly in sync with the PWM signal. I wanted to operate ADC1 in circular mode to get a continous stream with 1 MHz. Starting the ADC1 by software does not work because the ADC and the PWM is never in sync because of delay and jitter.

To do this I have the following idea:
The PWM-signal is generated by TIM1. Each time a commutation is detected, TIM3 shall be started at the next period of TIM1. Then TIM3 shall trigger the ADC1 after a fixed time which is always a few periods of TIM1. So TIM3 is the slave of TIM1 and the starter of the ADC1. The circular buffer of ADC1 is sized to be completely filled exactly after one PWM period. So, the PWM period is also set to be an integer multiple of 1 microsecond (here 500 -> 20KHz).

In the first step I wanted to make TIM3 triggering the ADC1 by hardware (which didnt succeed yet). This is the ADC config:

Code: Select all

static const ADCConversionGroup adc_commutate_group = {
      TRUE, // circular
      ADC_COMMUTATE_NUM_CHANNELS, // 1
      adc_commutate_cb, //adccatchcallback,
      NULL, //adccatcherrorcallback,
      0, // ADC_CR1
      ADC_CR2_EXTTRIG | ADC_CR2_EXTSEL_2, // ADC_CR2: use ext event | select Timer3 TRGO event
      0, // ADC_SMPR1
      ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5), // ADC_SMPR2
      ADC_SQR1_NUM_CH(ADC_COMMUTATE_NUM_CHANNELS), // ADC_SQR1
      0, // ADC_SQR2
      ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0) // ADC_SQR3
};

Then I tried to configure TIM3 and start ADC1:

Code: Select all

   TIM3->PSC   = (STM32_TIMCLK1/200)-1; // prescaler to get Timer 1 period as clock cycle for one tick; STM32_TIMCLK1 is 2Mhz
   TIM3->ARR   =  100;  // 100 periods

   TIM3->CR2 = TIM_CR2_MMS_1; // TRGO event is timer update event, e.g. overflow
   TIM3->CR1 = TIM_CR1_CEN | TIM_CR1_OPM; // enable the timer / one pulse mode
   adcStartConversion(&ADCD1, &adc_commutate_group, commutatesamples, ADC_COMMUTATE_BUF_DEPTH);// ADC_COMMUTATE_BUF_DEPTH=500

The ADC-callback is never called and the controller hangs completely when adcStartConversion is called.

Do you have an idea whats wrong up to this point?

Cheers,
Jörg
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Starting ADC1 by hardware trigger on STM32F103

Post by Giovanni »

Hi.

Please enable debug options in chconf.h and see if some assertion is triggered, if so the program will block in port_halt() and you will be able to inspect the stack trace. The global variable dbg_panic_msg will point to an error string too.

Giovanni
joewa
Posts: 22
Joined: Tue May 13, 2014 10:40 pm

Re: Starting ADC1 by hardware trigger on STM32F103

Post by joewa »

Hi Giovanni,

thanks for that hint! This really improves my debugging skills :)
ch. dbg_panic_msg is "adcStartConversionI". And this is the corresponding trace:

Code: Select all

bldc-strip_v2.elf [1]   
   Thread [1] (Suspended : Signal : SIGINT:Interrupt)   
      chSysHalt() at chsys.c:169 0x8002f80   
      adcStartConversionI() at adc.c:183 0x80027e2   
      adcStartConversion() at adc.c:153 0x800277c   
      catchconversion() at obldcadc.c:171 0x800079e   
      tRampMotorTread() at obldc_catchmotor.c:222 0x8000bb0   
      _port_thread_start() at 0x800015a   
      _port_thread_start() at 0x800015a   

I just fixed the crashing problem. I called adcStartConversion with different ADCConversionGroup's in a sequence. When I call adcStopConversion before restarting with a new group it doesnt crash anymore. :)
Last edited by joewa on Mon Sep 22, 2014 11:00 pm, edited 1 time in total.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Starting ADC1 by hardware trigger on STM32F103

Post by Giovanni »

CH_DBG_SYSTEM_STATE_CHECK just finds your error, read the error message pointed by dbg_panic_msg, the code you see there is your problem.

Giovanni
joewa
Posts: 22
Joined: Tue May 13, 2014 10:40 pm

Re: Starting ADC1 by hardware trigger on STM32F103

Post by joewa »

Hmm, when I use CH_DBG_SYSTEM_STATE_CHECK, the system stops much erarlier at pwmStart() with SV#4. But this code always worked fine.
I have set this option to back to FALSE again which pointed me to the adcStartConversion adcStopConversion sequence solution...

However, the main problem is still present: TIM3 obviously never triggers the ADC conversion. The callback is never called. Neither the error callback which I have set now.

I find the timer-triggering stuff I little bit tricky. Do you think I have configured TIM3 correctly? Is it possible that there is some conflict with some chibios background stuff?

Cheers
Jörg
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Starting ADC1 by hardware trigger on STM32F103

Post by Giovanni »

#SV4 means that you are calling a normal function from ISR or callback, only I-Class functions can be called in that context and only within a critical zone.

I recommend reading "kernel concepts" in the documentation, the matter of function classes is addressed there.

Giovanni
joewa
Posts: 22
Joined: Tue May 13, 2014 10:40 pm

Re: Starting ADC1 by hardware trigger on STM32F103

Post by joewa »

Hi Giovanni,

thanks! The chapter about the kernel concepts is really interesting (http://chibios.sourceforge.net/html/concepts.html)!
Nevertheless, it is a little bit weird, because pwmStart() was called from a thread which should be allowed as I understood. After disabling CH_DBG_SYSTEM_STATE_CHECK the programm works fine.

Back to my original problem of triggering the ADC1 by TRGO of TIM3: Do you think there may be some conflicts with the chibios background tasks or maybe I just configured either ADC1 or TIM3 wrong. I am a little bit lost how to debug this at this point.

Jörg
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Starting ADC1 by hardware trigger on STM32F103

Post by Giovanni »

Dear Jörg,

Please don't underestimate what the state checker is trying to tell you, as long errors are caught you are not in a safe state.
The stack trace you posted shows that you are calling adcStartConversion() from something that looks like a callback or, may be, you performed a chSysLock() before.

Without seeing the whole code it is hard to tell what the problem is, is the TIM3 clock enabled? if not it will not run.

Giovanni
joewa
Posts: 22
Joined: Tue May 13, 2014 10:40 pm

Re: Starting ADC1 by hardware trigger on STM32F103

Post by joewa »

Hello Giovanni,

thanks very much for taking the time! The whole code is at Github: https://github.com/joewa/bldc-strip.git But be aware it is still a big mess at the moment...

The state checker first fails when pwmStart() is called in bldc-strip/src/obldcpwm.c from void set_bldc_pwm(int angle, int duty_cycle, int period) this function is only called from a thread and not from a callback.

Regarding TIM3 I was expecting:

Code: Select all

TIM3->CR1 = TIM_CR1_CEN | TIM_CR1_OPM;
does the job?

Jörg
joewa
Posts: 22
Joined: Tue May 13, 2014 10:40 pm

Re: Starting ADC1 by hardware trigger on STM32F103

Post by joewa »

Ok, after few more hours of manual reading and chibios low-level-driver code inspection I still don't have TIM3 running and triggering ADC1...
I guess I have also activated the TIM3 clock now. This is my actual configuration I tried:

Code: Select all

adcStopConversion(&ADCD1);
//Bit definition for RCC_APB1ENR register
//RCC->APB1ENR = RCC->APB1ENR | RCC_APB1ENR_TIM3EN;
rccEnableTIM3(FALSE); // taken from gpt_lld_start in gpt_lld.c
rccResetTIM3();
TIM3->PSC   = (STM32_TIMCLK1/10)-1; // prescaler to get Timer 1 period as clock cycle for one tick
TIM3->ARR   =  100;  // Time constant;  Here: 100 periods
TIM3->EGR   = STM32_TIM_EGR_TG | STM32_TIM_EGR_UG;          // Trigger generation | Update event.
TIM3->CNT   = 0;                         // Reset counter.
TIM3->CR1 = STM32_TIM_CR1_URS | TIM_CR1_CEN | TIM_CR1_OPM; // Only counter overflow/underflow generates an update interrupt or DMA request if enabled | enable the timer | one pulse mode
TIM3->CR2 = TIM_CR2_MMS_1; // TRGO event is timer update event, e.g. overflow
adcStartConversion(&ADCD1, &adc_commutate_group, commutatesamples, ADC_COMMUTATE_BUF_DEPTH);
The ADC1 "adc_commutate_group" is the same as in my first post. Still the ADC callback function is never called. But at this point I find it really hard to debug what is actually working at what does not (because the debugger cannot read TIM3->XXX registers).

If anybody has more ideas how to make this work, please let me know. Of course I will document it here in the end...

Cheers,
Jörg
Post Reply