Padauk: timer16 problem with PMS150C - Page 1
Forum section: electronics / general

author: FrankBuss
author_rank: Unknown
timestamp: May 24, 2022, 06:55:25 am
content: 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.zipThe 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:#include"extern.h"// define LED portsoutLED1 BIT PA.4;outLED2 BIT PA.6;// 3.6 seconds = 27900 counts// for interrupt on bit 15, init with 32768 - 27900 = 4868WORD TIME36S = 4868;// 50 ms = 387 counts// for interrupt on bit 15, init with 32768 - 387 = 32381WORD TIME50MS = 32381;voidFPPA0 (void){// use internal ILRC clock = 62 kHz.ADJUST_ICSYSCLK=ILRC// set pins to output$ outLED1Low, Out;$ outLED2Low, Out;// enable interrupts for timer16$ INTEN T16;// pre-scaler 4 = 7750 Hz$ T16M ILRC, /4, BIT15;// global interrupt enableengint;while (1) {// LED1 on$ outLED1High, Out;// wait 50 msstt16 TIME50MS;stopexe;// LED1 off$ outLED1Low, Out;// wait 3.6 secondsstt16 TIME36S;stopexe;// LED2 on$ outLED2High, Out;// wait 50 msstt16 TIME50MS;stopexe;// LED2 off$ outLED2Low, Out;// wait 3.6 secondsstt16 TIME36S;stopexe;}}void Interrupt(void){pushaf;if (Intrq.T16){//T16 TrigIntrq.T16=0;}popaf;}

author: FrankBuss
author_rank: Unknown
timestamp: May 26, 2022, 04:54:37 am
content: 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:#include "extern.h"// define LED portsoutLED1 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 = 32518WORD TIME50MS = 32518;// wait 50 msvoid wait50(){stt16 TIME50MS;stopexe;nop;}// wait 3.6 svoid wait36(){// loop is shorter than 3.6 s / 50 ms, because of wakeup timesBYTE loop = 0;while (loop < 60) {wait50();loop++;}}void FPPA0 (void){// use internal ILRC clock = 62 kHz.ADJUST_ICSYSCLK=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 enableengint;// disable watchdog timerCLKMD.En_WatchDog = 0;while (1) {// LED1 on$ outLED1 High, Out;// wait 50 mswait50();// LED1 off$ outLED1 Low, Out;// wait 3.6 secondswait36();// LED2 on$ outLED2 High, Out;// wait 50 mswait50();// LED2 off$ outLED2 Low, Out;// wait 3.6 secondswait36();}}// interrupt wakes it up from sleep modevoid Interrupt(void){pushaf;if (Intrq.T16) {Intrq.T16 = 0;}popaf;}

author: DavidAlfa
author_rank: Super Contributor
timestamp: May 26, 2022, 02:26:53 pm
content: 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:BYTE T16_busy = 0; // To detect if timer is doneBYTE Other_interrupt= 0; // To detect if interrupt was triggered by something elsevoid T16_wait(){Intrq.T16 = 0;$ INTEN T16;T16_busy=1;while(T16_busy){ // Sleep until T16 is over, even if waken upstopexe;}$ INTDIS T16;}void main(){while(1){ // Toggle Led1 50ms, 3.6s low$ outLED1High, Out;stt16 TIME50MS;T16_wait();$ outLED1Low, Out;stt16 TIME36S;T16_wait();if(Other_interrupt){ // other interrupt detected, enable both leds as a warning signal and stop execution$ outLED1High, Out;$ outLED2High, Out;while(1);}}}void Interrupt(void){pushaf;if (Intrq.T16){Intrq.T16 = 0;T16_busy = 0;}else{ // Something else caused the interruptOther_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.

author: FrankBuss
author_rank: Unknown
timestamp: May 26, 2022, 03:09:32 pm
content: 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.

author: DavidAlfa
author_rank: Super Contributor
timestamp: May 26, 2022, 03:40:05 pm
content: 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.

author: FrankBuss
author_rank: Unknown
timestamp: May 26, 2022, 03:55:05 pm
content: 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 registersWill try now to disable it and see what happens.

author: FrankBuss
author_rank: Unknown
timestamp: May 26, 2022, 06:10:49 pm
content: 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:#include "extern.h"// define LED portsoutLED1 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 = 21268WORD 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 = 32766WORD TIME50MS = 32766;void FPPA0 (void){// use internal ILRC clock = 62 kHz.ADJUST_IC SYSCLK=ILRC// configure all pins with input and pull-up resistorsPAC = 0;PAPH = 0xff;// enable interrupts for timer16$ INTEN T16;// disable all pin wakeup interrupts, which are enabled by default after resetPADIER = 0;// pre-scaler 16 = 3875 Hz$ T16M ILRC, /16, BIT15;// global interrupt enableengint;while (1) {// LED1 on$ outLED1 High, Out;// wait 50 msstt16 TIME50MS;stopexe;nop;// LED1 off$ outLED1 Low, Out;// wait 3.6 secondsstt16 TIME36S;stopexe;nop;// LED2 on$ outLED2 High, Out;// wait 50 msstt16 TIME50MS;stopexe;nop;// LED2 off$ outLED2 Low, Out;// wait 3.6 secondsstt16 TIME36S;stopexe;nop;}}void Interrupt(void){pushaf;if (Intrq.T16) {Intrq.T16 = 0;}popaf;}