• I want to make use of timer properties beyond that which has been implemented in Espruino. Such things as counting external pulses, shaft encoder input, measure period and frequency, cascading timers for longer counts. The first step is to understand how the timers work and how Espruino uses them.
    First obtain the specification sheet from:
    http://www.espruino.com/datasheets/STM32­F103xC.pdf
    Second obtain the RM0008 Reference manual
    http://www.keil.com/dd/docs/datashts/st/­stm32f10xxx.pdf
    (The link on the Espruino site is broken.)

    From the reference manual memory map Table 3, the locations of the timers were obtained.
    0x4000 0C00 - 0x4000 0FFF TIM5 timer
    0x4000 0800 - 0x4000 0BFF TIM4 timer
    0x4000 0400 - 0x4000 07FF TIM3 timer
    0x4000 0000 - 0x4000 03FF TIM2 timer
    And define the starting addresses:

    var TIM5=0x40000C00;
    var TIM4=0x40000800;
    var TIM3=0x40000400;
    var TIM2=0x40000000;
    
    

    From the reference manual section 15.4 obtain the names and offsets of the timer registers:

    //Timer register offsets
    var CR1=0x0;
    var CR2=0x04;
    var SMCR=0x08;
    var DIER=0x0c;
    var SR=0x10;
    var ERRCW=0x14;
    var CCMR1=0x18;
    var CCMR2=0x1c;
    var CCER=0x20;
    var CNT=0x24;
    var PSC=0x28;
    var ARR=0x2c;
    var CCR1=0x34;
    var CCR2=0x38;
    var CCR3=0x3c;
    var CCR4=0x40;
    var DCR=0x48;
    var DMAR=0x4c;
    
    

    Set up an array containing the names and start addresses of the timers:

    var timers=[{name:"Timer 2",t:TIM2},
                {name:"Timer 3",t:TIM3},
                {name:"Timer 4",t:TIM4},
                {name:"Timer 5",t:TIM5}
               ];
    
    

    From the reference manual section 15.4.1 that defines the bits in control resister 1 we learn that bit 0 enables or disables a timer. Write a function that tests the timers:

    function isTimerEnabled(TIMx){
      var CR1x=peek32(TIMx.t+CR1);
      if(CR1x&1)console.log(TIMx.name+" Enabled");
      else console.log(TIMx.name+" Disabled");
      return CR1x & 1;
    }//end isTimerEnabled
    
    

    And write a function to display the registers of a timer

    function showTimer(TIMx,base){
    //display the timer registers in binary
    console.log("CR1="+peek32(TIMx+CR1).toSt­ring(base));
    console.log("CR2="+peek32(TIMx+CR2).toSt­ring(base));
    console.log("SMCR="+peek32(TIMx+SMCR).to­String(base));
    console.log("DIER="+peek32(TIMx+DIER).to­String(base));
    console.log("SR="+peek32(TIMx+SR).toStri­ng(base));
    console.log("ERRCW="+peek32(TIMx+ERRCW).­toString(base));
    console.log("CCMR1="+peek32(TIMx+CCMR1).­toString(base));
    console.log("CCMR2="+peek32(TIMx+CCMR2).­toString(base));
    
    console.log("CCER="+peek32(TIMx+CCER).to­String(base));
    console.log("CNT="+peek32(TIMx+CNT).toSt­ring(base));
    console.log("PSC="+peek32(TIMx+PSC).toSt­ring(base));
    console.log("ARR="+peek32(TIMx+ARR).toSt­ring(base));
    console.log("CCR1="+peek32(TIMx+CCR1).to­String(base));
    console.log("CCR2="+peek32(TIMx+CCR2).to­String(base));
    console.log("CCR3="+peek32(TIMx+CCR3).to­String(base));
    console.log("CCR4="+peek32(TIMx+CCR4).to­String(base));
    console.log("DCR="+peek32(TIMx+DCR).toSt­ring(base));
    console.log("DMAR="+peek32(TIMx+DMAR).to­String(base));
    }//end showTimer
    
    

    And finally loop through the timer list

    for(var i=0; i in timers;i++){
     if(isTimerEnabled(timers[i])) 
      showTimer(timers[i].t,16);
    }//next i
    analogWrite(A0,0.1,{ freq : 10 }); 
    for(var i=0; i in timers;i++){
     if(isTimerEnabled(timers[i])) 
      showTimer(timers[i].t,16);
    }//next i
    analogWrite(A0,0.5,{ freq : 10 }); // change duty cycle
    for(var i=0; i in timers;i++){
     if(isTimerEnabled(timers[i])) 
      showTimer(timers[i].t,16);
    }//next i
    
    

    Try it with other analogWrite pins


    1 Attachment

  • Great - thanks for posting this! I'll fix the manual link.

    There's a tutorial on how to access a bit more of the timers on the STM32F4 here:
    http://www.espruino.com/STM32+Peripheral­s

    While not immediately applicable, the timers behave in a similar way on the F103 in the original Espruino board, so with the work you've done peeking all the register values, you should be able to get something working pretty quickly.

  • Thanks Gordon.

  • Properties of Timers 2, 3, 4, and 5
    Valid pins for PWM analogWrite:

    analogWrite(A4,0.1,{ freq : 10 });
    
    ERROR: Pin A4 is not capable of PWM Output
    Suitable pins are:
    A0 A1 A2 A3 A6 A7(AF) A8 A9 A10
    A11 B0(AF) B1(AF) B3(AF) B4(AF) B5(AF) B6 B7 B8
    B9 B10(AF) B11(AF) B13 B14 B15 C6(AF) C7(AF) C8(AF)
    C9(AF)
    Or pins with DAC output are:
    A4 A5
    You can also use analogWrite(pin, val, {soft:true}) for Software PWM on this pin
    =undefined
    
    

    Note the AF notation AF = Alternate Function
    Using the attached file isTimerEnabled1.js and modifying the analog Write statements
    Timer 5 uses pins:
    A0, A1, A2, A3 or AF pins
    Timer 4 uses pins:
    B6, B7, B8, B9 or AF pins
    Timer 3 uses pins:
    A6, A8, A9, A10 or AF pins B4, B5, B0
    Timer 2 uses pins:
    Or AF pins B3, B10, B11.
    Pins B1, A7, B13, B14, B15, C6, C7, C8, C9 are not seen by timers 2, 3, 4, or 5 when
    used in a PWM analog Write statement.
    When isTimerEnabled1.js is used with the following analogWrite commands,

    analogWrite(A0,0.1,{ freq : 10 }); 
    analogWrite(A1,0.2,{ freq : 10 }); 
    analogWrite(A2,0.3,{ freq : 10 }); 
    analogWrite(A3,0.4,{ freq : 10 });
    The output:
    >echo(0);
    Timer 2 Disabled
    Timer 3 Disabled
    Timer 4 Disabled
    Timer 5 Enabled
    CR1=81
    CR2=0
    SMCR=0
    DIER=0
    SR=1
    ERRCW=0
    CCMR1=6868
    CCMR2=6868
    CCER=1111
    CNT=1da5
    PSC=6d
    ARR=ffae
    CCR1=1991
    CCR2=3322
    CCR3=4cb4
    CCR4=6645
    DCR=0
    DMAR=81
    
    

    Note the CCR1 thru CCR4 reflect the different duty cycles specified in the analogWrite commands.
    If the analog Write commands are changed to

    analogWrite(A6,0.1,{ freq : 10 }); 
    analogWrite(A8,0.2,{ freq : 10 }); 
    analogWrite(A9,0.3,{ freq : 10 }); 
    analogWrite(A10,0.4,{ freq : 10 });
    The Output:
    >echo(0);
    Timer 2 Disabled
    Timer 3 Enabled
    CR1=81
    CR2=0
    SMCR=0
    DIER=0
    SR=1
    ERRCW=0
    CCMR1=68
    CCMR2=0
    CCER=1
    CNT=16e2
    PSC=6d
    ARR=ffae
    CCR1=1991
    CCR2=0
    CCR3=0
    CCR4=0
    DCR=0
    DMAR=81
    Timer 4 Disabled
    Timer 5 Disabled
    
    

    Note that CCR1 is non zero but CCR2, CCR3, and CCR4 are zero.

    The program PWMflash.js looks for pulses divides them and flashes the red LED.
    I used this to test the PWM properties.

    var FLED=require("flashLED");
    
    var x=new FLED(5);
    
    analogWrite(A0,0.1,{ freq : 10 }); 
    analogWrite(A1,0.1,{ freq : 1 }); 
    setWatch(x.divide, C3,
    { repeat: true, edge:'rising', debounce:1});
    
    /*
    function FLED(a) {
      this.A=a;
      this.count=0;
      this.LEDstate=0;
    }
    
    exports = FLED;
    FLED.prototype.divide = function() {
     this.count++;
     if(this.count<this.A)return;
     this.count=0;
     this.LEDstate=this.LEDstate^1;
     digitalWrite(LED1,this.LEDstate);
    };//divide
    
    exports=FLED;
    
    */
    
    

    While the duty cycles of pins A0, A1, A2, and A3 can be independently altered, they must all use the same frequency. The frequency is that of the last invoked analogWrite PWM command.


    2 Attachments

  • isTimerEnabled3.js has expanded to cover timers 1 thru 14.
    Toffset.xlsx compares the four kinds of timer register offsets over the range of timers 1 thru 14. This was used to build the switch statement in isTimerEnabled3.js
    ESpPinsTimers.xlsx shows the results of scans using isTimerEnabled.js one pin at a time. The procedure used: 1. Disconnect WebIDE, 2. Push reset button, 3. Reconncect WebIDE, 4. Edit analogWrite command line (169..172) in isTimerEnabled and 5. Load and run the program and note the results


    3 Attachments

  • Experiments with timers:
    Experiment 1:
    Setup A0 at 50hz, Duty cycle 20%
    Setup A1 at 50hz, Duty cycle 40%
    Setup A2 at 50hz, Duty cycle 60%
    Setup A3 at 50hz, Duty cycle 80%
    Using isTimerEnabled3.js modify lines 168..172

    analogWrite(A0,0.2,{ freq : 50 }); 
    analogWrite(A1,0.4,{ freq : 50 }); 
    analogWrite(A2,0.6,{ freq : 50 }); 
    analogWrite(A3,0.8,{ freq : 50 });
    Results:
    Timer 5 Enabled
    CR1=81
    CR2=0
    SMCR=0
    DIER=0
    SR=f
    EGR=0
    CCMR1=6868
    CCMR2=6868
    CCER=1111
    CNT=d9ba
    PSC=15
    ARR=ffae
    CCR1=3322
    CCR2=6645
    CCR3=9968
    CCR4=cc8b
    DCR0
    DMAR=81
    
    

    Confirm with scope on pins A0, A1, A2, and A3.
    All outputs are 50 Hz.
    A0 duty cycle is 20%, A1 duty cycle is 40%, A2 duty cycle is 60%, A3 duty cycle is 80%
    Modify the A3 line and change the frequency to 10 hz

    analogWrite(A0,0.2,{ freq : 50 }); 
    analogWrite(A1,0.4,{ freq : 50 }); 
    analogWrite(A2,0.6,{ freq : 50 }); 
    analogWrite(A3,0.8,{ freq : 10 });
    Results:
    Timer 5 Enabled
    CR1=81
    CR2=0
    SMCR=0
    DIER=0
    SR=11
    EGR=0
    CCMR1=6868
    CCMR2=6868
    CCER=1111
    CNT=28fd
    PSC=6d
    ARR=ffae
    CCR1=3322
    CCR2=6645
    CCR3=9968
    CCR4=cc8b
    DCR0
    DMAR=81
    
    

    Use scope on pins A0, A1, A2, and A3 to check frequency and duty cycle.
    All outputs are 10 Hz.
    A0 duty cycle is 20%, A1 duty cycle is 40%, A2 duty cycle is 60%, A3 duty cycle is 80%
    Timer 5 values differ in the PSC registers for each case.
    PSC at 10Hz is x6d, PSC at 50Hz is 0x15, converting to decimal give 109 and 21.
    109/21 ~= 5

    Design consideration:
    If you need PWM outputs with different frequencies, you will need to select pins that use different timers for different frequencies.

  • Using Poke to Do PWM on Pins A0, A1, A2, and A3
    Before trying to configure a timer into other modes of operation using poke commands, it would be useful to configure a timer using a known configuration created by the command analogWrite(A0,0.2,{ freq : 50 });
    A known configuration:
    If we modify isTimerEnabled3.js lines 168 thru 172 to read:

    analogWrite(A0,0.2,{ freq : 50 }); 
    //analogWrite(A1,0.4,{ freq : 50 }); 
    //analogWrite(A2,0.6,{ freq : 50 }); 
    //analogWrite(A3,0.8,{ freq : 10 });
    The output for timer 5 is:
    Timer 5 Enabled
    CR1=81
    CR2=0
    SMCR=0
    DIER=0
    SR=3
    EGR=0
    CCMR1=68
    CCMR2=0
    CCER=1
    CNT=cbe9
    PSC=15
    ARR=ffae
    CCR1=3322
    CCR2=0
    CCR3=0
    CCR4=0
    DCR0
    DMAR=81
    
    

    The attached file PokeA0Timer5a.js contains the code to implement pins A0, A1, A2, A3 on timer 5 using poke commands. Note that either powering the board off or using the reset button will clear the timer settings.
    First setup the pins for alternate function output:

    //setup pins A0, A1, A2, A3
    A0.mode('af_output');
    A1.mode('af_output');
    A2.mode('af_output');
    A3.mode('af_output');
    
    

    Next turn timer 5 on and reset it

    //timer 5 clock
    var RCCbase=0x40021000;
    var APB1ENR=RCCbase+0x1c;
    var APB1RST=RCCbase+0x10;
    var APB2ENR=RCCbase+0x18;
    //turn on timer 5 clock
     poke8(APB1ENR,(peek8(APB1ENR)&0xf7)|0x08­);
    //reset timer 5
     poke8(APB1ENR,(peek8(APB1RST)&0xf7)|0x08­);
     poke8(APB1ENR,(peek8(APB1RST)^0x08));
    
    

    Finally configure timer 5 and enable it

    //disable timer 5
      poke32(TIM5+CR1,0x80);
    //setup timer 5
      poke32(TIM5+ARR,0x0ffae);
    //Setup duty cycle values
      poke32(TIM5+CCR1,0x3322); //A0 duty cycle
      poke32(TIM5+CCR2,0x3322); //A1 duty cycle
      poke32(TIM5+CCR3,0x3322); //A2 duty cycle
      poke32(TIM5+CCR4,0x3322); //A3 duty cycle
    //setup CCMR1 and 2
    //poke32(TIM5+CCMR1,0x68); //A0
      poke32(TIM5+CCMR1,0x6868);//A0,A1
    //poke32(TIM5+CCMR2,0x68);//A3
      poke32(TIM5+CCMR2,0x6868);//A3,A4
    //Setup PSC prescaler
    poke16(TIM5+PSC,0x6d);
    //Connect timer output to pins
    //poke32(TIM5+CCER,0x0001); //A0
    //poke32(TIM5+CCER,0x0011); //A0,A1
    //poke32(TIM5+CCER,0x0111); //A0,A1,A2
    poke32(TIM5+CCER,0x1111); //A0,A1,A2,A3
    //Preload timer
    poke32(TIM5+EGR,1);
    //Enable timer 5
    poke32(TIM5+CR1,0x81); //10Hz
    //poke32(TIM5+CR1,0x41); //5Hz
    //poke32(TIM5+CR1,0x01); //10Hz
    
    

    Note the frequency is determined by the ARR, and PSC registers and can be modified by the CR1 register.
    Additionally the frequency depends on the clock chain see Figure 8 on page 92 of the RM0008 Reference manual. The register APB1 controls the prescaler for timers 2, 3 , 4, 5, 6, 7, 12, 13, and 14. The register APB2 controls the prescaler for timers 1, 8, 9, 10, and 11.

    The CCMR1 and CCMR2 registers configure the CC (capture/compare) pins of the timer as output or input on one of three sources.

    The CCER register configures the polarity and enable that connects to the pins A0..A3.


    1 Attachment

  • **Made a typo in the code for PokeA0Timer5a.js **
    Lines 189 thru 191 should read as follows:

    //reset timer 5
     poke8(APB1RST,(peek8(APB1RST)&0xf7)|0x08­);
     poke8(APB1RST,(peek8(APB1RST)^0x08));
    
    
  • CountT5A1Poke.js
    Program that looks at timer registers to test timer 5 in
    External clock source mode 1 see page 377,378 of RM0008
    Reference manual

    Sets up a PWM on Pin B0, connect to pin A1 channel 2 of timer 5.

    analogWrite(B0,0.5,{ freq : 1000 });
    
    //setup pins A0, A1, A2, A3
    A0.mode('input');
    A1.mode('input');
    A2.mode('input');
    A3.mode('input');
    
    //timer 5 clock
    var RCCbase=0x40021000;
    var APB1ENR=RCCbase+0x1c;
    var APB1RST=RCCbase+0x10;
    var APB2ENR=RCCbase+0x18;
    
    //turn on timer 5 clock
     poke8(APB1ENR,(peek8(APB1ENR)&0xf7)|0x08­);
    
    //reset timer 5
     poke8(APB1RST,(peek8(APB1RST)&0xf7)|0x08­);
     poke8(APB1RST,(peek8(APB1RST)^0x08));
    
    //disable timer 5
      poke32(TIM5+CR1,0x80);
    
    //setup timer 5
    poke16(TIM5+CCMR1,0x0100);
    poke16(TIM5+CCER,0x0000); //0;
    poke16(TIM5+SMCR,0x0067);//0x0067);
    //Preload timer
    poke32(TIM5+EGR,1);
    //Enable timer 5
    poke32(TIM5+CR1,0x81); //10Hz
    
    //Display timers
    for(var i=0; i in timers;i++){
     if(isTimerEnabled(timers[i])) 
      showTimer(timers[i].t,16,i);
    }//next i
    
    console.log("Display Count");
    for(var i=0;i<1000;i++)
      console.log("CNT="+peek32(TIM5+CNT));
    
    

    Try changing the frequency of the PWM on pin B0.


    1 Attachment

  • FreqT5A1.js Measuring Frequency Using Timer 5 and Pin A1
    Uses Pin B0 as a frequency source to test.

    /* 
    FreqT5A1.js
    Frequency measurement using
    Pin A1 on Timer 5
    Use Pin B0 of  Timer3 as a source of square waves to measure
    Connect Pin B0 to Pin A1
    
    zero counter,
    start counter,
    count for timebase ms,
    stop counter,
    display count as frequency in Hz as adjusted by timebase
    repeat
    
    //Now displays timers 1 thru 14
    This was run on an Espruino board
    
    To clear the timer requires the board to be powered down or the reset button
    
    */
    /*
    http://www.keil.com/dd/docs/datashts/st/­stm32f10xxx.pdf
    */
    var TIM5=0x40000C00;
    //Timer register offsets
    var CR1=0x0;
    var CR2=0x04;
    var SMCR=0x08;
    var DIER=0x0c;
    var SR=0x10;
    var EGR=0x14;
    var CCMR1=0x18;
    var CCMR2=0x1c;
    var CCER=0x20;
    var CNT=0x24;
    var PSC=0x28;
    var ARR=0x2c;
    var CCR1=0x34;
    var CCR2=0x38;
    var CCR3=0x3c;
    var CCR4=0x40;
    var DCR=0x48;
    var DMAR=0x4c;
    
    // use B0 as a frequency source to measure
    analogWrite(B0,0.5,{ freq : 1000 });
    
    //setup pin A1 as the counter input
    A1.mode('input');
    
    //timer 5 clock
    var RCCbase=0x40021000;
    var APB1ENR=RCCbase+0x1c;
    var APB1RST=RCCbase+0x10;
    var APB2ENR=RCCbase+0x18;
    
    //turn on timer 5 clock
     poke8(APB1ENR,(peek8(APB1ENR)&0xf7)|0x08­);
    
    //reset timer 5
     poke8(APB1RST,(peek8(APB1RST)&0xf7)|0x08­);
     poke8(APB1RST,(peek8(APB1RST)^0x08));
    
    //disable timer 5
      poke32(TIM5+CR1,0x80);
    
    //setup timer 5
    poke16(TIM5+CCMR1,0x0100);
    poke16(TIM5+CCER,0x0000); 
    poke16(TIM5+SMCR,0x0067);
    poke32(TIM5+CNT,0);
    //Preload timer
    poke32(TIM5+EGR,1);
    //Enable timer 5
    //poke32(TIM5+CR1,0x81); 
    
    var timebase=2000;
    setInterval(function () {
      poke32(TIM5+CR1,0x80);
      console.log("CNT="+peek32(TIM5+CNT)*1000­/timebase +" Hz.");
      poke32(TIM5+CNT,1);
      poke32(TIM5+CR1,0x81);
    }, timebase);
    
    

    1 Attachment

  • That's great - thanks for posting it up!

    I guess these kind of things might actually make quite a neat module so that others can use the functionality more easily.

  • Thanks for the feedback Gordon. It may be a bit premature for a module as there are other examples in the documentation to work through and a need to make the code a bit more generalized. For example the previous code that measures frequency may be more accurate if two timers are chained together, where one does the counting and the other does the time base gating of the first.

  • Powering and Resetting Timers
    So far programs in this project have been aimed at a specific timer and purpose. At this point I want to shift to a more generalized approach.
    To clarify powering a timer consists of turning on the clock to the timer using a bit in either the APB1ENR or APB2ENR registers.
    Resetting a timer consist of setting and resetting a bit in the APB1RSTR or APB2RSTR
    The attached program TimOnOff.js implements these functions.
    If a timer is off and attempts to write to the timer registers, they return zero values when read back. The program loops thru timers 1 to 14 and reports if the timer is on, it then turns on the timer and resets it. It reports if the timer is enabled and then disables the timer.
    It write a unique value to the timer’s CNT counter register and reads it back.
    If the program is run after a fresh power up of the board reports timers 1 thru 8 as off and is able to write and read the CNT register. A subsequent run of the program without a hard reset reports timers 1 thru 8 as on.
    Timers 9, 10, and 11 have been omitted from the disable, write CNT as doing so crashes the Espruino board. The CNT read produces non-zero values. These timers do not report a power on. Additionally if the isTimerEnabled function uses a peek16 command the value returned in bit 0 is different than when a peek32 command is used.
    Timers 12, 13, and 14 do not seem to be present on the Espruino board.
    One of the difficulties is that the RM0008 Reference manual is written to cover a range of ARM chips with different sets of capabilities.
    From the experimental evidence confining future progress should be aimed at timers 1 through 8.

    Output of TimOnOff.js

    Timer 0 out of bounds 1..14
    Timer 0 out of bounds 1..14
    Timer 0 out of bounds 1..14
    Timer 0 out of bounds 1..14
    Timer 0 out of bounds 1..14
    Timer 0 out of bounds 1..14
    Timer 0 out of bounds 1..14
    0
    Timer 0 out of bounds 1..14
    1 is off
    Timer 1 Disabled
    ff01
    1 is on
    2 is off
    Timer 2 Disabled
    ff02
    2 is on
    3 is off
    Timer 3 Disabled
    ff03
    3 is on
    4 is off
    Timer 4 Disabled
    ff04
    4 is on
    5 is off
    Timer 5 Disabled
    ff05
    5 is on
    6 is off
    Timer 6 Disabled
    ff06
    6 is on
    7 is off
    Timer 7 Disabled
    ff07
    7 is on
    8 is off
    Timer 8 Disabled
    ff08
    8 is on
    9 is off
    Timer 9 Enabled
    14c2409
    9 is off
    10 is off
    Timer 10 Enabled
    1502409
    10 is off
    11 is off
    Timer 11 Enabled
    1542409
    11 is off
    12 is off
    Timer 12 Disabled
    0
    12 is off
    13 is off
    Timer 13 Disabled
    0
    13 is off
    14 is off
    Timer 14 Disabled
    0
    14 is off
    Timer 15 out of bounds 1..14
    Timer 15 out of bounds 1..14
    Timer 15 out of bounds 1..14
    Timer 15 out of bounds 1..14
    Timer 15 out of bounds 1..14
    Timer 15 out of bounds 1..14
    Timer 15 out of bounds 1..14
    0
    Timer 15 out of bounds 1..14
    
    

    1 Attachment

  • UpCounter.js A 16bit Up Counter Module
    Place UpCounter.js in the modules folder of your WebIDE project.
    Place the TestUpCounterTXChX.js files in the projects folder
    For timers 1, 2, 4, and 5 pin B0 is used as a signal source for testing.
    For timer 3 Pin A0 is used as a signal source for testing.
    For example running TestUpCounter T5Ch1.js produces the following output.
    Note that the timer input pin is the first thing displayed. For testing connect the signal source pin to the timer input pin. Use ClearInterval() to stop the program.

    >echo(0);
    Pin= A0
    =undefined
    CNT=0.5 Hz.
    CNT=976 Hz.
    CNT=972.5 Hz.
    CNT=1006 Hz.
    CNT=1000 Hz.
    CNT=998 Hz.
    CNT=998.5 Hz.
    CNT=999 Hz.
    CNT=999 Hz.
    CNT=999 Hz.
    CNT=999 Hz.
    >clearInterval();
    =undefined
    >
    
    

    To setup several counters on different timers you only need one instance of UpCounter.

    The file Tremap.xlsx shows the pins associated with the timers. It is possible to remap the pins by writing to the remap register. There are unknown pin assignments marked with a question mark. So far I haven’t located a document that gives the pinout of the timers.
    The timers have four channels. The registers CCMR1 and CCMR2 allow the configuration of the 4 channels. The register SMCR only allows channels 1 and 2 and not 3 and 4.


    7 Attachments

  • This is cool stuff. The timers in modern microcontrollers have so much capability - but they usually just get used for PWM and everything else gets forgotten about.

    I like how you're starting to wrap this into reusable code. Are you planning to make them into modules?

  • Thanks for the encouragement. Making a module makes sense. Since my last post I've managed to chain timer 1 and 2 together to do a 32bit counter. I'm working on making it work using any two timers. Future work is mode 2 counting, a one time pulse timer, chaining the OTP to gate a counter, the capture modes that measure a pulse, encoder mode for a shaft encoder, and finally the motor control mode for timers 1 and 8. Lots of work. Maybe more than one module. The biggest headache is determining the pin out of the timers as it is not well documented.

  • 4Jun2016 UpCounterV1.js
    The previous Upcounter.js has been extended.
    The Pins table has entries for Timer 8 channels added.
    The setupCounter() function has dropped the prescale argument as it is not active.
    A new function has been added. UpCounter.prototype.setupCounter32=funct­ion(Mtim,Mchan,Mfilter,Stim);
    It allows two timers to be chained together to form a 32 bit counter.
    The master timer (Mtim) is used to input an external signal on Mchan (1 or 2) and be filtered by Mfilter. When the Mtim overflows the slave timer (Stim) count is incremented. Mtim acts as a 16 bit prescaler to Stim
    The count value (CNT) from Mtim is the LSB and the CNT value from STM is the MSB part of the count.

    There are 4 internal paths used to chain the timers named ITR0, ITR1, ITR2, and ITR3.
    The array TSvalues is used by the function getTS() to determine the chaining path.
    This is all discussed on page 397 of the RM0008 Reference manual
    15.3.15 Timer synchronization
    Tables 82 and 86
    See attached file TSvalues.xlxs
    RM0008 Reference manual
    http://www.st.com/content/ccc/resource/t­echnical/document/reference_manual/59/b9­/ba/7f/11/af/43/d5/CD00171190.pdf/files/­CD00171190.pdf/jcr:content/translations/­en.CD00171190.pdf
    AN2592
    http://www.st.com/content/ccc/resource/t­echnical/document/application_note/0c/88­/73/b9/d9/7f/4d/70/CD00165509.pdf/files/­CD00165509.pdf/jcr:content/translations/­en.CD00165509.pdf
    AN4013
    http://www.st.com/content/ccc/resource/t­echnical/document/application_note/54/0f­/67/eb/47/34/45/40/DM00042534.pdf/files/­DM00042534.pdf/jcr:content/translations/­en.DM00042534.pdf
    I’m still puzzling about the nature of these inter timer links. Obviously the master timer is the source of the signals. Can a link with one master timer talk to more than one slave timer?
    It is conceivable to connect a master to slave 1 and then have slave 1 act as a master to slave 2. This would make a 48 bit counter possible.

    The Mfilter argument is discussed on pages 342 and 406. Value can range from 0 thru 15 with 0 being no filtering. It inserts a delay that acts as a de-bounce of a noisy signal.
    In sections 14.4.3 TIM1&TIM8 slave mode control register (TIMx_SMCR) and 15.4.3 TIMx slave mode control register (TIMx_SMCR)

    The counters so far are based on pages 377 and 378 of the RM0008 Reference manual
    External clock source mode 1.

    Pages 379 and 380 discuss External clock source mode 2. The problem is associating the ETR to a pin on the Espruino board. This will entail setting up mode 2 and trying all the pins until the one that works for each timer. Using the ETR as an external input allows the timer to operate in gated mode. A second timer can be used to generate a one time pulse to gate the first timer for a more precise measurement of frequency.

    Place UpcounterV1.js in the modules folder of a WebIDE project and the remaining js files in the project folder.
    The reader can test these functions by modifying the timer numbers and channel numbers in the test programs. I encourage readers to try the variations and report any problems. An external connection between the timer3 PWM output on pin B0 and the input pin of the counter is required.


    5 Attachments

  • I guess it should be possible to obtain the memory offsets of the timer registers for specific boards from the Espruino firmware since functions like digitalPulse use them anyway. Any ideas how to do that?

  • There's nothing exposed I'm afraid, however there is a file that'll create the relevant JS to access peripheral registers.

    If you download the Espruino repository then run this file: https://github.com/espruino/Espruino/blo­b/master/scripts/build_js_hardware.js

    It'll give you a bunch of JS for the peripherals that are defined on this line: https://github.com/espruino/Espruino/blo­b/master/scripts/build_js_hardware.js#L1­13

    If you're using the F1 you'll need to change the headers right at the top of the file. I should probably use that and auto-generate modules to access all the on-chip peripherals.

  • Thanks for the advice. When I modify the script to add "TIM" to the peripherals, it does give the correct bit definitions but all the base addresses are null (result attached). What is wrong?


    1 Attachment

  • Try using the latest from GitHub now, and put in TIM1/etc rather than just TIM.

    eg for STM32F4 TIM1 you now get:

    var TIM1 = {
      "a": {
        "CR1": 1073807360,
        "CR2": 1073807364,
        "SMCR": 1073807368,
        "DIER": 1073807372,
        "SR": 1073807376,
        "EGR": 1073807380,
        "CCMR1": 1073807384,
        "CCMR2": 1073807388,
        "CCER": 1073807392,
        "CNT": 1073807396,
        "PSC": 1073807400,
        "ARR": 1073807404,
        "RCR": 1073807408,
        "CCR1": 1073807412,
        "CCR2": 1073807416,
        "CCR3": 1073807420,
        "CCR4": 1073807424,
        "BDTR": 1073807428,
        "DCR": 1073807432,
        "DMAR": 1073807436,
        "OR": 1073807440
      },
      "f": {}
    };
    
    
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Peeking at Espruino Board Timers 2, 3, 4, and 5

Posted by Avatar for ClearMemory041063 @ClearMemory041063

Actions