• Welcome to Andy's Workshop Forums. Please login or sign up.
 
April 19, 2024, 03:45:17 am

News:

SMF - Just Installed!


stm32f103C8 & timers

Started by mhel, June 10, 2016, 08:14:10 am

Previous topic - Next topic

mhel

June 10, 2016, 08:14:10 am Last Edit: June 10, 2016, 01:43:40 pm by mhel
Hi All,

So I got this medium density stm32f103 72Mhz, and I managed to get something compiled. I used Debug_f1hd_72_8 build, but changed the memory settings
as mentioned in the readme of stm32++. There's a directory f1md but no build configuration for it, it seems identical to the content of f1hd_72_8

I'm using timer3 and timer4 (both 16bit) which according to the clock tree from the docs is connected to APB1, if I'm not mistaken it should be using 36MHz since the APB1 is divided by 1.
Why is the output of this:
timer3.getClock()
is 72MHz?

I setup my input timer the way I did with stm32f4-discovery board.

            _myInputTimer->initialiseTimeBase(
                    0xFFFF,             // Auto-reload
                    72-1,             // Prescaler
                    0,                  // Division
                    TIM_CounterMode_Up  // Counting up
            );

but no go.

I set it up to output instead and measure (with my newly scrounge oscope).

            outputTimer.initialiseTimeBase(
                    0xFFFF,             // Auto-reload
                    72-1,             // Prescaler
                    0,                  // Division
                    TIM_CounterMode_Up  // Counting up
                    );


Now I'm quite new on using an oscilloscope but the magic button :D that says measure frequency says I'm getting 15Hz

It's more likely that I'm misunderstanding the timer setup hence this post.  What settings should I be looking for?

EDIT1:
So I played with SMT32CubeMX, and found out that with PCLK1 is 36MHz but the Timer clock is 72MHz with x2 multiplier as configured in System.c
Still not sure why on stm32f4 the same setup works as expected, but not on this stm32f103.

Andy Brown

If you look again at the clock tree you'll see that the route through to TIM3 includes an x2 multiplier that's active when the ABP1 prescaler = 1. That's how it gets back to 72MHz when the APB1 clock is 36MHz AND the APB1 prescaler = 1. Does that cover your clocking scenario?

Regarding your timer output. Can I see a little more of your timer setup? In particular what are you using for the initCompare() parameters?
It's worse than that, it's physics Jim!

mhel

June 11, 2016, 07:49:38 am #2 Last Edit: June 11, 2016, 07:51:28 am by mhel
(I was typing and it timed out, I wasn't able to login until browser restart clearing cookies didn't fix it)

I kind of figured out the clocking scheme by using the clock configuration from cubemx.
[img=http://s33.postimg.org/jpt561xej/Screenshot_06112016_08_40_48_AM.jpg]

This is my setup

            Timer3<
                    Timer3InternalClockFeature, // clocked from the internal clock
                    TimerChannel1Feature<>,     // we're going to use channel 1
                    TimerChannel2Feature<>,     // we're going to use channel 2
                    Timer3GpioFeature<          // we want to output something to GPIO
                            TIMER_REMAP_NONE,   // the GPIO output will not (cannot for this timer) be remapped
                            TIM3_CH1_OUT,       // we will output channel 1 to GPIO (PA6)
                            TIM3_CH2_OUT        // we will output channel 1 to GPIO (PA7)
                    >
            > outputTimer;

...snipped timebase initialization here....

            outputTimer.TimerChannel1Feature<>::initCompareForPwmOutput(50);
            outputTimer.TimerChannel2Feature<>::initCompareForPwmOutput(50);


This setup however produce the correct frequency:

            outputTimer.setTimeBaseByFrequency(10000000, 10 - 1);

But if I used this initialization I only have 10 counts to play with in the ARR when I capture.
(Note that I'm only testing this setup to check the frequency, I'm actually using the timer4 for the input capture.)
From what I gather I need a free running timer that ticks at 1us, so the captured value of 1000 would equal to 1ms which
is ideal for ease of calculation with the servo pulses of 1 to 2 milliseconds.

So the prescaler of 71 should scale my timer clock to 1Mhz, similarly or exactly the same as the stm32f4 with a prescaler of 167.
What I can't figure out yet is the ARR. Why is it with the F4 I can use the maximum size 65535 for counting, but I can't with the F103?

I should mention that all other stuff (that I needed) seems to be working as expected. I have usart1 working, the capture interrupt.
I could capture but  the result is not what is expected, that's why I believed that my clocking setup might be wrong.

Thanks.



mhel

Reading a bit more, I just found out the Timers used as PWM relies on the ARR for frequency,
so it's not really smart testing my inputcapture clock using the same principle. :-[

mhel

Ok this is somewhat odd I think.

This setup somehow enables CC3S instead of CC4S.

        /**
         * Declare a type for our input timer.
         */
        typedef TimerChannel1Feature<
                TimerChannelICBothEdgesFeature,
                TimerChannelICDirectTiFeature,
//            TimerChannelICPreScaler1Feature,
                TimerChannelICFilterFeature<0>
        > ch1Features;

        typedef TimerChannel2Feature<
                TimerChannelICBothEdgesFeature,
                TimerChannelICDirectTiFeature,
//            TimerChannelICPreScaler1Feature,
                TimerChannelICFilterFeature<0>
        > ch2Features;

        typedef TimerChannel3Feature<
                TimerChannelICBothEdgesFeature,
                TimerChannelICDirectTiFeature,
//            TimerChannelICPreScaler1Feature,
                TimerChannelICFilterFeature<0>
        > ch3Features;

        typedef Timer4<
                Timer4InternalClockFeature, // we'll need this for the frequency calculation
                ch1Features,
                ch2Features,
                ch3Features,
                Timer4InterruptFeature, // we want to use interrupts
                Timer4GpioFeature<    // we want to read something from GPIO
                        TIMER_REMAP_NONE, // the GPIO input wil not be re-mapped
                        TIM4_CH1_IN, // we will read channel 1 from GPIO PB6
                        TIM4_CH2_IN,              // Channel 2 on GPIO PB7
                        TIM4_CH3_IN              // Channel 2 on GPIO PB8
                >
        > MyInputTimer;


Maybe the mistake is staring me in the face and I couldn't see it.

mhel

Hi All,
After a lot of searching, I just found out that the input capture on both edges is not possible with this chip.
I may have to change strategy, or get another chip that can do both edge so as to ease the learning process.

mhel

Hello all,

I'm revisiting this post just to make an update. I have managed to get a working input capture using a pair of timer channels as required capturing pwm input
instead of just a regular input capture. It's much simpler but limited to channel pairs. I use this to capture pwm from an RC receiver. I'm posting it here so googlers may find it.


#ifndef PWMINPUTCAPTURE_H_
#define PWMINPUTCAPTURE_H_

#include "config/stm32plus.h"
#include "config/timer.h"
#include "config/timing.h"

using namespace stm32plus;

/**
* PWM input capture mode on Timers 4 & 3.
*
* PWM input capture uses Timer channel pairs 1 & 2 to capture the signal
* on a single input . Duty cycle is captured on channel 1 and pulse width
* is captured on channel 2.
*
* Timer4 Channel1 is on PB6
* Timer3 Channel1 in on PA6
*
*/

class PWMInputCapture {

  protected:

    /**
     * Declare a type for our input timer.
     */
        typedef TimerChannel1Feature<            // we're going to use channel 1
                TimerChannelICRisingEdgeFeature, // we'll capture rising edge
                TimerChannelICDirectTiFeature,   // direct connection
                TimerChannelICPreScaler1Feature, // prescaler of 1
                TimerChannelICFilterFeature<0>   // no filter
        > ch1Features;
        typedef TimerChannel2Feature<            // we're going to use channel 2
                TimerChanneICFallingEdgeFeature, // we'll capture falling edge
                TimerChannelICDirectTiFeature,   // direct connection
                TimerChannelICPreScaler1Feature, // prescaler of 1
                TimerChannelICFilterFeature<0>   // no filter
        > ch2Features;

        typedef Timer4<
            Timer4InternalClockFeature,         // we'll need this for the frequency calculation
            ch1Features,
            ch2Features,
            Timer4InterruptFeature,           // we want to use interrupts
            Timer4GpioFeature<                // we want to read something from GPIO
              TIMER_REMAP_NONE,               // the GPIO input will not be remapped
              TIM4_CH1_IN                     // we will read channel 1 from GPIO PB6
            >,
            TimerSlaveFeature<
                TIM_TS_TI1FP1,
                TIM_SlaveMode_Reset
                >,
            TimerResetMasterFeature
          > TimerInput1;

        typedef Timer3<
            Timer3InternalClockFeature,         // we'll need this for the frequency calculation
            ch1Features,
            ch2Features,
            Timer3InterruptFeature,           // we want to use interrupts
            Timer3GpioFeature<                // we want to read something from GPIO
              TIMER_REMAP_NONE,               // the GPIO input will not be remapped
              TIM3_CH1_IN                     // we will read channel 1 from GPIO PA6
            >,
            TimerSlaveFeature<
                TIM_TS_TI1FP1,
                TIM_SlaveMode_Reset
                >,
            TimerResetMasterFeature
          > TimerInput2;

    /*
     * The timer needs to be a class member so we can see it from the callback
     */

    TimerInput1 *_TimerInput1;
    TimerInput2 *_TimerInput2;



  public:

    /* These does not have to be an array if only interested in one of the captured value */
    volatile uint16_t _steerCapture[2];
    volatile uint16_t _throttleCapture[2];

    void initialize() {

        /*
         * Declare a new instance of the input capture timer.
         */

        _TimerInput1=new TimerInput1;
        _TimerInput2=new TimerInput2;

        /* Timer4 runs at 36Mhz on APB1
         * This sets up a free running timer that ticks at 1MHz
         */

        _TimerInput1->setTimeBaseByFrequency(1000000, 0xFFFF, TIM_CounterMode_Up);
        _TimerInput2->setTimeBaseByFrequency(1000000, 0xFFFF, TIM_CounterMode_Up);

        /*
         * Insert our subscribtion of the capture interrupts generated by the input timer
         */

        _TimerInput1->TimerInterruptEventSender.insertSubscriber(
            TimerInterruptEventSourceSlot::bind(this,&PWMInputCapture::onSteerInterrupt)
          );
        _TimerInput2->TimerInterruptEventSender.insertSubscriber(
            TimerInterruptEventSourceSlot::bind(this,&PWMInputCapture::onThrottleInterrupt)
          );


        /* Select the TIM4 Input Trigger: TI1FP1 */
//        TIM_SelectInputTrigger(TIM4, TIM_TS_TI1FP1);
        _TimerInput1->enableSlaveFeature();

        /* Select the slave Mode: Reset Mode */
//        TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset);
//        TIM_SelectMasterSlaveMode(TIM4, TIM_MasterSlaveMode_Enable);
        _TimerInput1->enableMasterFeature();

        /* Select the TIM3 Input Trigger: TI1FP1 */
//        TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
        _TimerInput2->enableSlaveFeature();

        /* Select the slave Mode: Reset Mode */
//        TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
//        TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);
        _TimerInput1->enableMasterFeature();

        /*
         * Enable channel 1 interrupts on Timer inputs.
         */

        _TimerInput1->enableInterrupts(TIM_IT_CC1);
        _TimerInput2->enableInterrupts(TIM_IT_CC1);

        /*
         * Enable timers to start the action
         */
        _TimerInput1->enablePeripheral();
        _TimerInput2->enablePeripheral();

    } // Iniatilize


    /*
     * Interrupt callback function. This is called when the input capture
     * event is fired
     */
        void onSteerInterrupt(TimerEventType tet, uint8_t /* timerNumber */) {
            if (tet == TimerEventType::EVENT_COMPARE1) {

                // store the current capture time
//                _steerCapture[0] = TIM_GetCapture1(TIM4); // Period
//                _steerCapture[1] = TIM_GetCapture2(TIM4); // Duty/Width
//                _steerCapture[0] = _TimerInput1->ch1Features::getCapture();
                _steerCapture[1] = _TimerInput1->ch2Features::getCapture();
            }
        } // onInterrupt
    /*
     * Interrupt callback function. This is called when the input capture
     * event is fired
     */
        void onThrottleInterrupt(TimerEventType tet, uint8_t /* timerNumber */) {
            if (tet == TimerEventType::EVENT_COMPARE1) {

                // store the current capture time
//                _throttleCapture[0] = TIM_GetCapture1(TIM3); // Period
//                _throttleCapture[1] = TIM_GetCapture2(TIM3); // Duty/Width
//                  _throttleCapture[0] = _TimerInput2->ch1Features::getCapture();
                  _throttleCapture[1] = _TimerInput2->ch2Features::getCapture();
            }
        } // onInterrupt
}; //

#endif /* PWMInputCapture_H_ */