Author Topic: Padauk: timer16 problem with PMS150C  (Read 1563 times)

0 Members and 1 Guest are viewing this topic.

Offline FrankBussTopic starter

  • Supporter
  • ****
  • Posts: 2368
  • Country: de
    • Frank Buss
Padauk: timer16 problem with PMS150C
« on: May 24, 2022, 06:55:25 am »
I created a simple project which should blink 2 LEDs with 50 ms, and pause 3.6 s between each blink: https://www.frank-buss.de/tmp/blinker.zip

The LED on times are nearly right:



But the pause is wrong, it is shorter than 50 ms instead of 3.6 s. Any idea what I'm doing wrong?

Another question: I noticed that when I use "stopsys" instead of "stopexe", then it still works (with the same wrong timing). But in the datasheet in chapter 5.10., it says STOPSYS stops the ILRC oscillator. Is the datasheet wrong? Would be nice to save a bit more power, if it is reliably to use STOPSYS instead of STOPEXE, and if the timer16 is still running with STOPSYS and triggers the interrupt.

Edit: source code, the rest is just the standard project files:
Code: [Select]
#include "extern.h"

// define LED ports
outLED1 BIT PA.4;
outLED2 BIT PA.6;

// 3.6 seconds = 27900 counts
// for interrupt on bit 15, init with 32768 - 27900 = 4868
WORD TIME36S = 4868;

// 50 ms = 387 counts
// for interrupt on bit 15, init with 32768 - 387 = 32381
WORD TIME50MS = 32381;

void FPPA0 (void)
{
// use internal ILRC clock = 62 kHz
.ADJUST_IC SYSCLK=ILRC

// set pins to output
$ outLED1 Low, Out;
$ outLED2 Low, Out;

// enable interrupts for timer16
$ INTEN T16;

// pre-scaler 4 = 7750 Hz
$ T16M ILRC, /4, BIT15;

// global interrupt enable
engint;

while (1) {
// LED1 on
$ outLED1 High, Out;

// wait 50 ms
stt16 TIME50MS;
stopexe;

// LED1 off
$ outLED1 Low, Out;

// wait 3.6 seconds
stt16 TIME36S;
stopexe;

// LED2 on
$ outLED2 High, Out;

// wait 50 ms
stt16 TIME50MS;
stopexe;

// LED2 off
$ outLED2 Low, Out;

// wait 3.6 seconds
stt16 TIME36S;
stopexe;
}
}

void Interrupt(void)
{
pushaf;

if (Intrq.T16)
{
// T16 Trig
Intrq.T16 = 0;
}

popaf;
}
« Last Edit: May 25, 2022, 03:44:11 am by FrankBuss »
So Long, and Thanks for All the Fish
Electronics, hiking, retro-computing, electronic music etc.: https://www.youtube.com/c/FrankBussProgrammer
 

Offline FrankBussTopic starter

  • Supporter
  • ****
  • Posts: 2368
  • Country: de
    • Frank Buss
Re: Padauk: timer16 problem with PMS150C
« Reply #1 on: May 26, 2022, 04:54:37 am »
I still don't know why it doesn't wait for 3.6 s. But I could use a loop for it, the code below works. I contacted the FAE at Padauk about it, and for the question why stopsys apparently also works, maybe I can improve this, because waking up it so often wastes energy.

So far with 2 LEDs and 470 ohm series resistors, and running at 3 V, it needs about 50 uA average (measured by powering it from a 10,000 uF capacitor, which was discharged from 3 V to 2 V in about 245 s, which I think would be an equivalent resistor of about 60k). This means with a 100 mA coin cell it would blink longer than 2 months.

Code: [Select]
#include "extern.h"

// define LED ports
outLED1 BIT PA.4;
outLED2 BIT PA.6;

// 50 ms: 7750 Hz * 0.05 s = 387 counts
// measured: 250
// for interrupt on bit 15, init with 32768 - 250 = 32518
WORD TIME50MS = 32518;

// wait 50 ms
void wait50()
{
stt16 TIME50MS;
stopexe;
nop;
}

// wait 3.6 s
void wait36()
{
// loop is shorter than 3.6 s / 50 ms, because of wakeup times
BYTE loop = 0;
while (loop < 60) {
wait50();
loop++;
}
}

void FPPA0 (void)
{
// use internal ILRC clock = 62 kHz
.ADJUST_IC SYSCLK=ILRC

// set pins to output
$ outLED1 Low, Out;
$ outLED2 Low, Out;

// enable interrupts for timer16
$ INTEN T16;

// pre-scaler 4 = 7750 Hz
$ T16M ILRC, /4, BIT15;

// global interrupt enable
engint;

// disable watchdog timer
CLKMD.En_WatchDog = 0;

while (1) {
// LED1 on
$ outLED1 High, Out;

// wait 50 ms
wait50();

// LED1 off
$ outLED1 Low, Out;

// wait 3.6 seconds
wait36();

// LED2 on
$ outLED2 High, Out;

// wait 50 ms
wait50();

// LED2 off
$ outLED2 Low, Out;

// wait 3.6 seconds
wait36();
}
}

// interrupt wakes it up from sleep mode
void Interrupt(void)
{
pushaf;
if (Intrq.T16) {
Intrq.T16 = 0;
}
popaf;
}
So Long, and Thanks for All the Fish
Electronics, hiking, retro-computing, electronic music etc.: https://www.youtube.com/c/FrankBussProgrammer
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6225
  • Country: es
Re: Padauk: timer16 problem with PMS150C
« Reply #2 on: May 26, 2022, 02:26:53 pm »
Try increasing the 50ms value and check the output, you might detect something happening over a certain value.
Also, if BIT15 interrupt is triggered by any change in the bit 15, you might be triggering it when loading the counter.
Try disabling T16 interrupt after it's done, and re-enabling it after loading the timer, clearing the interrupt flag first.
Something else might be waking it up, check that, also try using a timer flag, ex. T16_busy.
Code: [Select]
BYTE T16_busy = 0;      // To detect if timer is done
BYTE Other_interrupt= 0;  // To detect if interrupt was triggered by something else

void T16_wait(){
    Intrq.T16 = 0;
    $ INTEN T16;

    T16_busy=1;
    while(T16_busy){  // Sleep until T16 is over, even if waken up
        stopexe;
    }

    $ INTDIS T16;
}

void main(){
  while(1){           // Toggle Led1 50ms, 3.6s low
    $ outLED1 High, Out;
    stt16 TIME50MS;
    T16_wait();
    $ outLED1 Low, Out;
    stt16 TIME36S;
    T16_wait();

    if(Other_interrupt){    // other interrupt detected, enable both leds as a warning signal and stop execution
      $ outLED1 High, Out;
      $ outLED2 High, Out;
      while(1);
    }

  }
}

void Interrupt(void){
pushaf;
if (Intrq.T16){
Intrq.T16 = 0;
                T16_busy = 0;
}
        else{     // Something else caused the interrupt
            Other_interrupt= 1;
        }
popaf;
}

That way, even if it wakes up, it'll inmediately enter sleep again, unless the Timer is done.
If this works, then check other interrupts sources you might have missed.
If it does the same, it suggests that effectively something is wrong with the timer.

Be careful with compiler optimizations, I have no idea how Padauk's works, T16_busy needs to be declared as volatile if any optimization is used.

Also check MISC Register, has a bit to adjust the wake speed between 2048 or 32 clocks, you should adjust your counting value to compensate this.
« Last Edit: May 26, 2022, 02:57:21 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline FrankBussTopic starter

  • Supporter
  • ****
  • Posts: 2368
  • Country: de
    • Frank Buss
Re: Padauk: timer16 problem with PMS150C
« Reply #3 on: May 26, 2022, 03:09:32 pm »
Thanks, good idea. There shouldn't be another enabled interrupt, but this way I could test it. Maybe I'll try it if the FAE doesn't answer. It would probably need even less power if it doesn't have to wakeup all the time.
So Long, and Thanks for All the Fish
Electronics, hiking, retro-computing, electronic music etc.: https://www.youtube.com/c/FrankBussProgrammer
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6225
  • Country: es
Re: Padauk: timer16 problem with PMS150C
« Reply #4 on: May 26, 2022, 03:40:05 pm »
The datasheet is clear about STOPSYS, everything is stopped in this mode, only RAM retention is kept.
The only way to wake it up in this mode is with an external signal.
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline FrankBussTopic starter

  • Supporter
  • ****
  • Posts: 2368
  • Country: de
    • Frank Buss
Re: Padauk: timer16 problem with PMS150C
« Reply #5 on: May 26, 2022, 03:55:05 pm »
You are right, and reset state of PADIER is unexpectedly wake up enabled for all pins, this would explain both problems, because the pins are floating in my circuit, thanks! I should really read datasheets more carefully, especially reset state of registers ::) Will try now to disable it and see what happens.
So Long, and Thanks for All the Fish
Electronics, hiking, retro-computing, electronic music etc.: https://www.youtube.com/c/FrankBussProgrammer
 

Offline FrankBussTopic starter

  • Supporter
  • ****
  • Posts: 2368
  • Country: de
    • Frank Buss
Re: Padauk: timer16 problem with PMS150C
« Reply #6 on: May 26, 2022, 06:10:49 pm »
Ok, I fixed it and verified the stopsys effect, which really doesn't wakeup anymore, if the interrupts on pin change are disabled. I also set all unused pins to input with pullup. Below is the final source code.

The same discharge test with a 10,000 uF capacitor, from 3 V to 2 V, needs now 486 s. So this would probably blink for 4 months. I think this is now very much near the optimal low power consumption for this chip and the given task.

I tried different settings for the sleep time and measured it, and then calculated the next variation with rule of three, which removed the 2048 clocks wakeup offset, and the offset of the program (which also runs pretty slow with the 62 kHz clock). Did cost only a few chips, but they are cheap. Also variations between different ICs are not that big. Typical timing diagram now:



The sleep time can be set to pretty long periods when setting the prescale for the timer to 64.

Code: [Select]
#include "extern.h"

// define LED ports
outLED1 BIT PA.4;
outLED2 BIT PA.6;

// 3.6 seconds: minus 33 ms wakeup time: 3.567 s: 3875 Hz * 3.568 = 13826 counts
//
// measured: 23700 = 7.2 s
// measured: 11850 = 3.659 s
// measured: 11500 = 3.57 s
// for interrupt on bit 15, init with 32768 - 11500 = 21268
WORD TIME36S = 21268;

// 50 ms: minus 33 ms wakeup time: 17 ms: 3875 Hz * 0.017 s = 65 counts
// measured: 40 = 69 ms
// measured: 20 = 59 ms
// measured: 2 = 54 ms
// for interrupt on bit 15, init with 32768 - 2 = 32766
WORD TIME50MS = 32766;

void FPPA0 (void)
{
// use internal ILRC clock = 62 kHz
.ADJUST_IC SYSCLK=ILRC

// configure all pins with input and pull-up resistors
PAC = 0;
PAPH = 0xff;

// enable interrupts for timer16
$ INTEN T16;

// disable all pin wakeup interrupts, which are enabled by default after reset
PADIER = 0;

// pre-scaler 16 = 3875 Hz
$ T16M ILRC, /16, BIT15;

// global interrupt enable
engint;

while (1) {
// LED1 on
$ outLED1 High, Out;

// wait 50 ms
stt16 TIME50MS;
stopexe;
nop;

// LED1 off
$ outLED1 Low, Out;

// wait 3.6 seconds
stt16 TIME36S;
stopexe;
nop;

// LED2 on
$ outLED2 High, Out;

// wait 50 ms
stt16 TIME50MS;
stopexe;
nop;

// LED2 off
$ outLED2 Low, Out;

// wait 3.6 seconds
stt16 TIME36S;
stopexe;
nop;
}
}

void Interrupt(void)
{
pushaf;
if (Intrq.T16) {
Intrq.T16 = 0;
}
popaf;
}
So Long, and Thanks for All the Fish
Electronics, hiking, retro-computing, electronic music etc.: https://www.youtube.com/c/FrankBussProgrammer
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf