2017-01-02 10:23 AM
Hi there,
I am trying to get TIM4-CC4 in one-shot mode to trigger ADC1. It seems that TIM4 and CC4 is configured well: if enabled it generates interrupts on TIM_IT_CC4. So I am pretty sure CC4 fires.
I configured ADC1 for external triggering through the Timer 4 CC4 event. I checked various example codes, but still ADC does not seem to start a conversion: I don't get an interrupt at the end of conversion. I am pretty sure the ADC1 interrupt handler is Ok: when starting a converion from software, the interrupt handler is called allright.
I am using the Standard Peripheral Library for the STM32F2xx.
After days of trial and error, checking example software and reading the reference manual, I am out of inspiration :)
There is no way of checking internal signals like CC, TRGI, TRGO, right?
Any way, I absolutely appreciate comments or suggestions!
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
ADC_CommonInitTypeDef ADC_CommonInitStruct;
ADC_InitTypeDef ADC_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
// ======================================================================
// == Configuration of Timer 4 ==
// ======================================================================
// - to be triggered by an rising edge on TIM3 TRGO output
// - after 6.25 us, TIM4 OC4Ref must be set
// - 1us later, the OC4Ref output can drop
// - input capture on Zero Cross Detector input TIM_Ch1, pin D3
// - max counter resolution, clock = 30 Mhz
// - 30000000UL = 30 MHz Timer Clock = HCLK / 4
// - counting up, measure time from zero count
// - Pulse length: CCR register (TIM_OCInitStructure.TIM_Pulse): 6.25E-6 * 30000000 = 187
// - Pulse+Delay length: The ARR register (TIM_TimeBaseStructure.TIM_Period): 7.25E-6 * 30000000 = 217
TIM_TimeBaseStruct.TIM_Period = ((ZCD2PEAKDELAY + ADCSTARTPULSEWIDTH) * TIMCLK);
TIM_TimeBaseStruct.TIM_Prescaler = 1;
TIM_TimeBaseStruct.TIM_ClockDivision = 0;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStruct);
// - One Pulse is a special case of output compare mode
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse = (ZCD2PEAKDELAY * TIMCLK);
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM4, &TIM_OCInitStruct);
// - One single pulse when triggered
TIM_SelectOnePulseMode(TIM4, TIM_OPMode_Single);
// - counter starts when triggered from TIM3 TRGO
TIM_SelectInputTrigger(TIM4, TIM_TS_ITR2);
TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Trigger);
// TIM enable counter
TIM_Cmd(TIM4, ENABLE);
// OC4 can generate interrupt (code removed for clarity and TIM4 timing changes are seen, so probably ok....
// ======================================================================
// == Configuration of ADC ==
// ======================================================================
// - to be triggered by a rising edge of TIM4_Ch4 output
// - sample A0 analog input
// - at EOC, DMA stores the result in memory
// - Single ADC mode
// - Sample at 30MHz clock (prescaler = 2)
// - For now, no DMA
// - No delay between ADC1 and ADC2 required
ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStruct);
// - 12 bits resolution (=> 15 clock cycles = 0.5 us)
// - Single (one channel) scan mode
// - Single scan, not continuous
// - Trigger converion on a rising edge
// - Trigger from TIM4_CC4
// - Right aligned data, no scaling
// - 1 conversion
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStruct.ADC_ScanConvMode = ENABLE;
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T4_CC4;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStruct);
// - Setup A0 input channel as single channel, with highest speed sampling
ADC_RegularChannelConfig(ADC1, PIN_MAP[A0].adc_channel, 1, ADC_SampleTime_15Cycles);
// - For now, disable DMA
ADC_DMARequestAfterLastTransferCmd(ADC1, DISABLE);
ADC_DMACmd(ADC1, DISABLE);
// Temporary: for testing only
NVIC_InitStruct.NVIC_IRQChannel = ADC_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
ADC_ClearITPendingBit(ADC1,ADC_IT_EOC);
ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);
// Enable ADC
ADC_Cmd(ADC1, ENABLE);
#output-compare #adc #tim #spl #stm32f205 #external-trigger #ons-shot2017-01-02 02:47 PM
TIM_OC1Init(TIM4, &TIM_OCInitStruct);
// HOW DOES THIS USE TIM4_CC4 ??2017-01-02 08:22 PM
OMG, that was stupid... it was the remainder of one of my experiments
Changed that to:
TIM_OC4Init(TIM4, &TIM_OCInitStruct);
But still no luck, the ADC is still not triggered...
2017-01-02 10:35 PM
There's a lot missing...
I'll note the Period and Prescaler are N-1, so a prescaler of 1 is DIV2, the TIMCLK is twice the APB clock in this instance.
>>There is no way of checking internal signals like CC, TRGI, TRGO, right?
You can get TIM4_CC4 to a pin, if you don't see a waveform there the ADC isn't going to trigger, work back from there.
You could get the trigger input to reset the counter, with a maximal period you should be able to see by observation that the count doesn't go full cycle.
2017-01-12 01:27 PM
Thanks for your suggestions, Clive!
The TIMCLK being twice the APB clock: This means that the counters are counting at the double speed as the registers are clocked, right? Could that lead to problems?
I have tried to connect the EXTI line 11 to an input pin. Unfortunately I have a WM-N-BM-09 WICED module, where the STM32F205 is mounted below a wifi chip. The GPIO pin connected to the EXI Line 11 is not available for connection.
So I concentrated on trying different external trigger sources: I tried not only TIM5 but also TIM8 which can also be selected as external ADC trigger, both TRGO and CC1, both unsuccessfull. These timers do run properly (I checked by means of an timer interrupt handler, which triggers with the right period).
Since I also am able to start ADC conversions through software (ADC_SoftwareStartConv(ADC1)), including an interrupt handling the EOC, I suspect a missing configuration of the link between a timer and the ADC external trigger circuit.
I have some questions on triggering the ADC from an external source:
I also noticed that the start/trigger registers for the ADC in STM32F2xx differ somewhat from the STM32F1xx.
2017-01-16 12:15 PM
I'm answering based on the STM32L471 chip I'm using since I just spent over a day stumbling through the undocumented bits of hardware trigger setup; it seems to have the same ADC and timer peripherals.
2017-01-16 01:50 PM
The F2/F4 are very similar, they differ from the F1 in numerous ways as ST learned a lot of things, and improved/fixed them in subsequent designs.
You don't have to get triggers to pins, but it helps to see them if you think things are broken.
The TIM, ADC and DMA clocks need to be enabled, I'd generally enable ALL the clocks I need in one subroutine rather than pick my way through them as I initialize specific peripherals. Also usually put all the GPIO stuff in one place.