3 .word ( 0x0260 | 1<<0 | 5<<2 | 1<<7 | 3<<10 )
4 ; reserved_bits | security_off | lvr_1v8 | io_drv_norm | boot_fast
7 notes: .ds 16 ; 0x00 .. 0x0f
12 .even ; make next two bytes word-aligned
19 .even ; SP must be aligned
24 ; aliases for memory locations:
49 ; Calibration Parameters:
50 ; Bitshift Variations calls for an 8kHz sample rate; with an interrupt every
51 ; 512 cycles (the next power of two above the 495 cycles the program needs for
52 ; execution), this gives us a clock speed of 512 * 8khz = 4.096MHz. The MCU
53 ; will be powered by a 3V lithium coin cell. (+10-15ish cycles ivr overhead)
54 calib_freq = 4096000 ; Hz
57 ; cycle count (worst-case)
60 ; sample: 115 + 4*g + 2*mod3 = 495
75 ADD mod3lo, a ; mod3lo = hi+lo
83 AND a, #0xf ; (mod3lo>>4)
84 XCH mod3lo ; a=mod3lo, mod3lo=mod3lo>>4
85 AND a, #0xF ; a=mod3lo&0xf, mod3lo=mod3lo>>4
86 ADD a, mod3lo ; (mod3lo & 0xF)
90 AND a, #0x3 ; a = (mod3lo & 0x3)
92 SR mod3lo ; (mod3lo >> 2)
96 AND a, #0x3 ; a = (mod3lo & 0x3)
98 SR mod3lo ; (mod3lo >> 2)
107 ; notes_ix_hi = always 0
120 ; note: LSB of result (mul0) is not needed for our purposes
194 ; clock setup (no calibration):
195 SET1 clkmd, #4 ; enable IHRC
196 MOV a, #(( 0<<5 | 1<<4 | 0<<3 | 1<<2 | 0<<1 | 0<<0 ))
197 MOV clkmd, a ; switch to IHRC/4, WDT off; keep ILRC on
199 ;; .org 0x46 ; comment out on 2nd iteration
200 ; calibration placeholder:
204 AND a, #( calib_freq )
205 AND a, #( calib_freq>>8 )
206 AND a, #( calib_freq>>16 )
207 AND a, #( calib_freq>>24 )
208 AND a, #( calib_vdd )
209 AND a, #( calib_vdd>>8 )
219 MOV pac, a ; data direction: all output
221 MOV padier, a ; disable pin wakeup
222 MOV pa, a ; PortA data = 0
223 MOV paph, a ; disable all pull-ups
226 ; Since (unlike in the ATTiny4 version) the interrupt timer is not tied
227 ; to the PWM frequency, we can use a much faster clock for PWM. The
228 ; highest "carrier frequency" for the PCM samples we can generate is by
229 ; setting Timer2 to 6 bit, (IHRC/1)/1 mode, giving a frequency of
230 ; (4*4.096MHz)/2^6 = 256kHz.
233 MOV tm2b, a ; pwm duty cycle 50%
234 MOV a, #(( 2<<4 | 3<<2 | 1<<1 | 0<<0 ))
235 MOV tm2c, a ; timer2: IHRC, PA4, PWM, not inverted
236 MOV a, #(( 0<<7 | 1<<5 | 0<<0 ))
237 MOV tm2s, a ; 8bit, /4 prescaler, divide by (0+1)
240 ;mov a, #(( 0<<0 | 1<<3 | 4<<5 )) ; ovf@bit8 (512cy; §9.2.5), clk/4, ihrc
241 MOV a, #(( 1<<0 | 1<<3 | 4<<5 )) ; ovf@bit9 (???cy; §9.2.5), clk/4, ihrc
242 ;XXX: datasheet §5.10.1 says bit8 = 256cycles, 9.2.5 says bit8=512cy
243 ; note: ovf@bit9 causes 4khz isr => we need ovf@bit8.
245 MOV a, #(1<<2) ; enable timer16 int, disable all others
249 SET1 eoscr, #0 ; disable bandgap and lvr
250 SET0 gpcc, #7 ; disable comparator
257 ;rom is not mmapped; must load notes into ram first
285 ;TODO: test i2==0x78 to enter halt()
286 ; Note: usually, this is the place where the MCU is put into some
287 ; sort of low power/sleep mode. But the Padauk's stopexe instruction
288 ; causes the ISR to a) run at greatly reduced frequency (100hz vs
289 ; 1khz for timer16@bit11; probably due to slow wakeup), b)
290 ; double-fire some (20-30%) of the time, c) jitter -50% to +10%. so
291 ; we don't sleep at all between samples (which is only a short time
298 T1SN intrq, #2 ; if intrq.t16 is triggered, skip next
306 ;TODO: send pwm data to timer2
311 ; generate new sample:
312 MOV a, i2; "mov mem,mem"
313 MOV n, a; does not exist
333 MOV tmp_1, a ; fresh tmp_1:
338 OR a, tmp_1 ; tmp_1 done.
366 MOV tmp_1, a ; a saved in tmp_1; fresh a
368 ; shift-divide by six
369 ; note: i2 is max 0x78; so a will <= 20. (breaks vor values >=128)
382 AND a, tmp_1 ; a restored from tmp_1
405 MOV tmp_1, a ; a saved in tmp_1; fresh a
407 ; shift-divide by ten
408 ; note: i2 is max 0x78; so a will <= 12.
421 AND a, tmp_1 ; a restored from tmp_1
428 ; next sample is now ready.