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.
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
*/