28.01.2019, 04:27 PM
(Dieser Beitrag wurde zuletzt bearbeitet: 28.01.2019, 04:29 PM von voltwide.)
Um den Stromhunger etwas einzudämmen, würde ich gerne das Hauptprogramm nur mit dem watchdog-irq aufrufen und ansonsten schlafen legen wollen (idle).
Da funkt mir aberTimer1 zwischen und reißt die CPU nach spätesten 10us aus dem Schlaf - und dann bringt das garnichts.
Klar, Timer1Irq ist eine Weckquelle. Und nu?
Habe an den Schlus des Timer1Irq mal ein sleep commando gesetzt - aber danach schläft wirklich alles, auch der Timer.
Hat jemand ne zündende Idee das Aufwecken durch Timer1Irq zu unterbinden?
Da funkt mir aberTimer1 zwischen und reißt die CPU nach spätesten 10us aus dem Schlaf - und dann bringt das garnichts.
Klar, Timer1Irq ist eine Weckquelle. Und nu?
Habe an den Schlus des Timer1Irq mal ein sleep commando gesetzt - aber danach schläft wirklich alles, auch der Timer.
Hat jemand ne zündende Idee das Aufwecken durch Timer1Irq zu unterbinden?
Code:
/* A Very Basic USB/LiIon-Battery-Powered Audio Sine-Wave Test Generator, fast version
created: 2014-01-21
update: 2019-01-28
author: VoltWide
target ATTINY25-20
mcu clock frequency ............... 64/4Mhz PLL
prototype data
output function pwm sine
max output level, peak-peak >90% of Vsupply
pwm sample rate 32MHz/256 = 125khz
pwm mode.....................................................simple, not phase correct
THD vs output frequencies 0.34% @15Hz
0.21% @60Hz
0.27% @250Hz
0.98% @1kHz
3.11% @4kHz
power supply 2.7~5.5V: USB, 3V-LiBatt, 2~3xAA..
power consumption active, no load, 3.6V/10.4~10.6mA
eof battery charge threshold = watchdog disable 4V
UVLO shut down threshold disabled
shut down current consumption <1uA
Conditional WDT timeout shutdown in case Vcc < 4V.
Switch off and on again to restart.
Automatic permanent operation when fed by 5V supply.
Conditional WDT timeout shutdown disabled per DIP-switch.
Unconditional WDT-timeout shutdown by masking GetVcc(), ignoring DIP switch setting.
Vcc is measured across frequ poti (permanent on) against Ref1V1.
Fuse Extended Byte
7 - 1 -
6 - 1 -
5 - 1 -
4 - 1 -
3 - 1 -
2 - 1 -
1 - 1 -
0 - 1 SELFPRGEN self-programming enabled
Fuse High Byte
7 - 1 RSTDISBL ext reset disabled
6 - 1 DWEN DebugWire enabled
5 - 0 SPIEN Serial program and data download
4 - 1 WDTON watchdog timer always on
3 - 1 EESAVE EEPROM preserves chip erase
2 - 1 BODLEVEL2 Brown-out detector trigger level
1 - 1 BODLEVEL1 Brown-out detector trigger level
0 - 1 BODLEVEL0 Brown-out detector trigger level
Fuse Low Byte
7 - 0 CKDIV8 Clock divided by 8 modify 1
6 - 1 CKOUT Clock output enabled default 1
5 - 1 SUT1 Start-up slowly rising Vcc default 1
4 - 0 SUT0 Start-up slowly rising Vcc default 0
3 - 0 CKSEL3 CPU-Clock 16MHz default 0
2 - 0 CKSEL2 CPU-Clock 16MHz default 0
1 - 1 CKSEL1 CPU-Clock 16MHz modify 0
0 - 0 CKSEL0 CPU-Clock 16MHz modify 1
----------------------------------------------------------
lfuse=0xe1
DIP8/SOIC8 multilevel-pinning:
pin1 PB5 PCINT5 /RESET ADC0 dW
pin2 PB3 PCINT3 XTAL1 CLKI /OC1B ADC3
pin3 PB4 PCINT4 XTAL2 CLKO OC1B ADC2
pin4 GND
pin5 PB0 MOSI DI SDA AIN0 OC0A /OC1A AREF PCINT0
pin6 PB1 MISO DO AIN1 OC0B OC1A PCINT1
pin7 PB2 SCK USCK SCL ADC1 T0 INT0 PCINT2
pin8 VCC
*/
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/eeprom.h>
#include <avr/wdt.h>
#include <util/delay.h>
const __flash char SineTab[] = { // 8bit sinewave lookup table
0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,
0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8,
0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5,
0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,
0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc,
0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3,
0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83,
0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51,
0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27,
0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a,
0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23,
0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c,
0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c
};
const __flash uint16_t FqTab[] = {2,8,32,128,512,2048,8192}; //2019-01-25: 4-16-63-250-1k-4k-16k
const int8_t FrequIdxMax = 6; //2018-12-27
// i/o mapping
#define pin1 (1<<PB5)
#define pin2 (1<<PB3)
#define pin3 (1<<PB4)
#define pin5 (1<<PB0)
#define pin6 (1<<PB1)
#define pin7 (1<<PB2)
#define OutPwmMSB pin6
#define OutLSB pin3
#define OutChargeReq pin5
#define OutPoti pin7
#define InVcc pin2
#define InPoti pin3
//input divider Rhi/Rlo=10k/2k2 Cin=0 Vref=1V1 VBattMin=3V VBattMax=4V:
//Vin(max,min) = 0.72/0.54V
//ADCin(maxs,min) =167/125
#define VBattMax 167
#define VBattHyst 5
//1count/64msec - 10000/Min:!!!
#define WDTirqCountDown 1200
//++++++++ global vars
volatile uint16_t Phase16,PhaseOfs16,WDTirqCount; // 2019-01-06
uint8_t PotiResult,VccResult,EmptyBattcount,FrequIdx; //2018-12-27
ISR(TIM1_OVF_vect) { // 2019-01-20 DDS-irq: output next sound sample, wakes up idle mcu!
Phase16 += PhaseOfs16; // 2019-01-23 16bit phase pointer
OCR1A = (SineTab[(Phase16 >> 8)]); // 2019-01-23 update pwm dutoy cycle
//sleep_enable(); // 2018-12-26!!!
//sleep_cpu(); // prevent wake-up here!!!
}
ISR(WDT_vect){ // ca 2x/s: autoclears WDIE, must be set again to avoid wdt-reset
sleep_disable(); // wakeup
WDTirqCount--; // 2019-01-07 shutdown not here, but in main loop
WDTCR |= (1<<WDIE); // continue wdt irq, not wdt reset
}
void Boot(void){
//Timer
PLLCSR = 1<<PLLE; // 2019-01-18 start PLL
//wait 100us!!
TCCR1 = (1<<PWM1A) | (1<<COM1A1) | (1<<CS11); // 2019-01-23 OC1A=MSB, PCK=64Mhz/2->irq_rate=125kHz
GTCCR = (1<<TSM) | (1<<PWM1B) | (1<<COM1B1) | (1<<PSR1); // 2019-01-20 timer1: stop, OC1B=LSB, reset pre-scaler
OCR1C = -1; // 2019-01-20 max pwm cycle
TCNT1 = 0; // 2019-01-20 clear counter
OCR1A = 60; // 2019-01-20 MSB=analog zero!!
OCR1B = 128; // 2019-01-20 LSB=analog zero
TIMSK = (1<<TOIE1); // 2019-01-20 timer1-irq on counter overflow
//Ports
MCUCR |= (1<<PUD); // 2018-12-26 pullup,sleep=off, sleepmode=idle
DDRB = OutPwmMSB | OutChargeReq | OutPoti; // 2019-01-24 output ports
PINB = -1; // 2018-12-26 power reduction of dig input buffers
DIDR0 = (1<<ADC0D) | (1<<ADC1D) | (1<<ADC2D) | (1<<ADC3D); // 2018-12-26 dig inputs=off
PORTB = OutPoti; // 2019-01-25 OutchargRequ=lo
//ADC
ADMUX = (1<<ADLAR) | (1<<MUX1); // 2019-01-26
ACSR = (1<<ACD); // 2018-12-26 comp=off
ADCSRA = 0; // 2018-12-26 ADCen,ADCstart,ADCtrig,ADCirq=off, adcclk=cpuclk/2
ADCSRB = 0; // 2018-12-26 unipolar, polarity=tru,free running
//Misc
PRR = (1<<PRTIM0) | (1<<PRUSI); // 2019-01-26 power timer0,usi=off
PhaseOfs16 = 0; // 2019-01-23
Phase16 = 0;
WDTirqCount = WDTirqCountDown; // 2019-01-06
WDTCR = (1<<WDIE) | (1<<WDE) | (1<<WDP1); // 2019-01-28 Watchdog timer 64msec ticker
MCUSR |= (1<<WDRF); // 2019-01-27 overrides WDE
set_sleep_mode(SLEEP_MODE_IDLE); // 2019-01-28
sleep_enable(); // 2019-01-28
while (!( PLLCSR & (1<<PLOCK))); // 2019-01-24 polling lock PLL
GTCCR &= ~(1<<TSM); // 2019-01-20 start counter(s)
PLLCSR = (1<<PLLE) | (1<<PCKE); // 2019-01-18 link PLL-> timer1 clk
}
void ShutDown(void) {
cli(); // 2018-12-26
ADCSRA = 0; // 2018-12-26 dis ADC???
TCCR1 = 0; // 2019-01-27 disconn sine port from timer, PRIOR! to powersave
MCUSR = 0; // 2019-01-06 clear WDRF
WDTCR |= (1<<WDCE) | (1<<WDE); // 2019-01-06
WDTCR = 0; // 2019-01-06 clear WDE
ADMUX = 0; // 2019-01-06 disable ref1V1
PRR = (1<<PRTIM0) | (1<<PRTIM1) | (1<<PRUSI) | (1<<PRADC); // 2018-12-26 power timer0+1,usi,adc=off
PORTB = 0; // 2018-12-26 LED=off
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // 2018-12-26
sleep_enable(); // 2018-12-26
//sleep_cpu(); // shut down!!!
}
void GetPoti (void) {
ADCSRA |= (1<<ADEN) | (1<<ADSC); // 2018-12-26 start ad-conversion fsample=clk/2 adcirq=off
while (0 == (ADCSRA & (1<<ADIF))); // A/D-conversion
ADCSRA |= (1<<ADIF); // 2019-01-07
PotiResult = ADCH; // bit9..2 , 8bit result
}
void GetFrequ (void) { // 2018-12-26
FrequIdx = PotiResult>>5; // 2018-12-26
if (FrequIdx>FrequIdxMax) FrequIdx=FrequIdxMax; // 2018-12-27
PhaseOfs16 = FqTab[FrequIdx]; // 2018-12-26
}
void GetVcc (void) {
ADCSRA |= (1<<ADEN) | (1<<ADSC); //2019-01-06 start adc fsample=clk/2 adcirq=off
while (0 == (ADCSRA & (1<<ADIF))); //
ADCSRA |= (1<<ADIF); // 2019-01-07
VccResult = ADCH; // bit9..2 , 8bit result
if (VccResult>=VBattMax) WDTirqCount++; // 2019-01-27
if (WDTirqCount>WDTirqCountDown) WDTirqCount = WDTirqCountDown; // 2019-01-28 limited countup
}
//++++++++ Main Program
int main(void) {
Boot();
sei();
for (;;) { // 2019-01-27 1xloop / 64msec WDTirq
PRR &= ~(1<<PRADC); // 2019-01-28 wakeup i/o
PORTB |= OutPoti; // 2019-01-28 wakeup i/o
GetPoti();
ADMUX = (1<<ADLAR) | (1<<REFS1) | (1<<MUX0) | (1<<MUX1);// 2019-01-27 adcref=1V1, result left adj, in=ADC3/PB3/pin2
GetFrequ(); // 2019-01.26
GetVcc(); // 2019-01-27
ADMUX = (1<<ADLAR) | (1<<MUX1); // 2019-01-28 ref-1V1 early turn-off
PORTB &= ~OutPoti; // 2019-01-28 save power
PRR |= (1<<PRADC); // 2019-01-28 save power
if (WDTirqCount==0) ShutDown(); // 2019-01-06
//sleep_cpu(); // 2019-01-28!!!
}
}
/*
changelog ******************************************************
2019-01-06b
GetVcc: UVLO shutdown removed
cpu-load minimized
2019-01-18 PLLclock -> timer1 enabled
2019-01-23 disabled: Timer0, GetVcc, sleep
sineoutput with 16bit phase offset = 256:
61/122/245/357/357Hz @clk div 16/8/4/2/1
PCK/4 works: 245*256*256*4=64MHz & PWMclk=62.7kHz with 62.5kHz measured
PCLK/2 & /1 results in PWMclkmax=125kHz
2019-01-24
fusing the attiny
AVR8-Burn-O-Mat is broken, requires JRE7, but JRE8 is installed
fusing LFuse to E1 with AVRDude immediately without data file works like this:
/usr/bin/avrdude -P usb -c usbtiny -p t25 -U lfuse:w:0xe1:m
Timer1-Clk=32MHz -> fpwm=125kHz
MCU-Clk=16MHz -> firq=125kHz
SineFreqTable: 4-16-62-250-1k-4k-16kHz
added GetPoti(), GetFrequ()
2019-01-26
bugfix: ADC-conversion stayed in endless loop: PRR had turned off ADC power!
no sleep current consumption Icc=11.2mA @3V6 &10k pots ¬ frequ <=1kHz
main idle current consumption Icc=10.2mA @3V6 &10k pots ¬ frequ <=1kHz
output-filter is 4.7mH 10nF + 1k0 12nF
2019-01-27
output filter is 4.7mH 10nF 2k7 4n7||1n0
Watchdog-timeout restored. Now WDT-irq is always running. To avoid timeout-restart on single ADC-spikes,
GetVcc(): hi Vcc voltage 1x increments timeout counter instead of reloading full timeout.
bugfix shutdown: timer1 was not stopped before PRR disable & thus continued working
10Min Watchdog timeout shutdown verified
2019-01-28
GetVcc(): Watchdog timeout countup limited to WDTirqCountDown
10Min Watchdog timeout shutdown verified
THD measurements updated
for instanteneous frequ-poti response: WDTirq speedup from 2ticks/1sec -> 1tick/64ms
Main loop exits sleep mode, wake-up 1/64ms WDTirq
save power: ADC turn-off saves about 0.1mA
save power: frequ-poti turned off outside main
bug: sleep main is terminated by timer1irq, but sleep_cpu on timer1Irq-exit freezes the system
Todo:
turn-off frequ-poti
GetVcc(): measure ref1V1 against Vcc - saves a portbit
250kHz PWM-clk
*/
...mit der Lizenz zum Löten!