10 #define x r24 //==a1==Mh
19 #define Ml t //mod3 vars
21 #define a1 x //mul_ vars
44 .org 0x0000 ; RESET interrupt
46 .org 0x0002 ; INT0 external interrupt
48 .org 0x0004 ; PCINT0 pin change interrupt
51 .org 0x0008 ; TIM0_OVF interrupt
55 .byte 0x84, 0x9d, 0xb0, 0x69, 0x9d, 0x84, 0x69, 0x58
56 .byte 0x75, 0x8c, 0xb0, 0x69, 0x8c, 0x75, 0x69, 0x58
58 mod3: ; mod3(Mh.Ml) -> t
62 ADC Mh, Mh ; store carry in Mh
101 ADD Xlo, t ; NOTE: can't overflow, since RAMEND == 0x5F
106 ; begin of mulitiplication:
115 ; BRCC skip2 -- this bit is always zero
143 BRCC skip6 ;sbrc t, NNN
158 MOV t, a1 ;;TODO: use a1 in loop: directly
161 main: ; setup routine
162 ; NOTE: clr i0..i2 moved to .ord 0x0
164 CLR acc ; we output a dummy sample before the actual first one
165 LDI Xhi, hi8(FLASHM + notes) ; never changes
166 LDI one, 1 ; mostly for clearing TIM0_OVF bit
170 OUT SPL, x ; init stack ptr
172 OUT PUEB, zero ; disable pullups
174 OUT DDRB, x ; PORTB0:pwm, PORTB2:debug
176 OUT CCP, x ; change protected ioregs
177 OUT CLKPSR, one ; clock prescaler 1/2 (4Mhz)
178 LDI x, 0xa7 ; determined by trial-and-error (->PORTB2)
179 OUT OSCCAL, x ; set oscillator calibration
180 OUT WDTCSR, zero; turn off watchdog
182 ;set timer/counter0 to 8bit fastpwm, non-inverting, no prescaler
187 OUT TIMSK0, one ; enable tim0_ovf
192 SLEEP ; wait for interrupt
196 OUT OCR0AL, acc ; start by outputting a sample, because routine has variable runtime
198 SBI PORTB, 2 ; to measure runtime
345 SWAP acc ; acc<<4, to be passed to OCR0AL
352 cpi i2, 0x78 ; 16m23 -- one loop
356 CBI PORTB, 2 ; end runtime measurement
358 OUT TIFR0, one ; clear pending interrupt (routine takes two intr.cycles)
359 RETI ; reenables interrupts
363 ; To reduce physical size, we won't use a latching power switch. Instead,
364 ; playback will stop after a full iteration (16m23s). Then, a momentary
365 ; button will trigger a RESET, INT0 or PCINT0 interrupt to resume
366 ; playback. Meanwhile, all periphials will be shut down and the clock
367 ; turned off. The watchdog is permanently off to reduce power consumption.
368 ; Note: it is not necessary to switch the clock source from the 8MHz
369 ; oscillator to the 128kHz one, since power-down mode disables the clock
372 ; TODO: if we are using pcint on the audio-out pin, we could instruct the user to short the audio plug to ground to start playback. this would eliminate the button (and associated wiring) completely.
375 ;set all pins as input & enable pullups and disable periphials to conserve energy
381 ldi x, 0x3 ; bit0: disable Timer0, bit1: disable attiny5/10's ADC
387 ; EICRA(0x15)==00: generate INT0 on low level (default, can skip).
388 sbi EIMSK, 0 ; enable INT0
389 ; TODO: the ISR should clear the interrupt raised flag, disable itself, reset DDRB/PUEB/PRR and RETI.
391 ;EIFR(0x14): set to 1 to clear int0 flag
393 /* alternatively, using PCINT:
394 PCICR(0x12): set to 1 to enable pcint0
395 PCIFR(0x11): set to 1 to clear pcint0 flag
396 PCMSK(0x10): PCINT0 mask (lsb: portb0, msb: portb3)
400 ;enter power-down-mode
401 ldi x, 0x05 ; power-down mode:____010_ ; enable:_______1
404 ; NOTE: at this point, only INT0, PCINT0 and RESET can wake up the MCU.
407 ;disable power-down-mode
408 clr x; xxx: should do before sleep-ing