add initialisation code
authorTobias Girstmair <tobi@isticktoit.net>
Mon, 26 Apr 2021 07:22:58 +0000 (09:22 +0200)
committerTobias Girstmair <tobi@isticktoit.net>
Mon, 26 Apr 2021 07:22:58 +0000 (09:22 +0200)
prototyped seperately as 06-timer16ivr-v2/main.asm

bsv.S

diff --git a/bsv.S b/bsv.S
index 84370bd75dbee7e8465febed505f7bcf3451a6c1..72f58f3edd5a8dc7db533bf221925f7214c8d538 100644 (file)
--- a/bsv.S
+++ b/bsv.S
@@ -1,6 +1,9 @@
-;.area DATA
+.area FUSE (ABS)
+.org 0x3ff*2
+.word ( 0x0260 | 1<<0 | 5<<2 | 1<<7 | 3<<10 )
+; reserved_bits | security_off | lvr_1v8 | io_drv_norm | boot_fast
+
 .area OSEG (OVR,DATA)
-;.area DATA
 notes: .ds 16  ; 0x00 .. 0x0f
 i0: .ds 1      ; 0x10
 i1: .ds 1      ; 0x11
@@ -12,8 +15,10 @@ tmp_1: .ds 1   ; 0x15
 tmp_hi: .ds 1  ; 0x16
 tmp_lo: .ds 1  ; 0x17
 pwm: .ds 1     ; 0x18
+
+.even ; SP must be aligned
+stack_start: .ds 1
 .area SSEG
-.even ; SP must be aligned? (sdcc does it)
 stack: .ds 1
 
 ; aliases for memory locations:
@@ -24,26 +29,46 @@ mul1 = tmp_lo
 mod3hi = tmp_hi
 mod3lo = tmp_lo
 
+; io addresses
+clkmd = 0x03
+inten = 0x04
+intrq = 0x05
+tm2c = 0x1C
+tm2b = 0x09
+tm2s = 0x17
+t16m  = 0x06
+eoscr = 0x0A
+padier = 0x0D
+pa = 0x10
+pac = 0x11
+paph = 0x12
+misc = 0x1B
+gpcc = 0x1A
+ihrcr = 0x0B
+
+; Calibration Parameters:
+; Bitshift Variations calls for an 8kHz sample rate; with an interrupt every
+; 512 cycles (the next power of two above the 495 cycles the program needs for
+; execution), this gives us a clock speed of 512 * 8khz = 4.096MHz. The MCU
+; will be powered by a 3V lithium coin cell. (+10-15ish cycles ivr overhead)
+calib_freq = 4096000 ; Hz
+calib_vdd  = 3000 ; mV
+
 ; cycle count (worst-case)
 ; mod3:    28
 ; g:       81
 ; sample: 115 + 4*g + 2*mod3 = 495
 
+; portA.4: audio out
+; portA.6: debug pin
+
 
 .area CSEG (CODE,ABS)
-;.area HOME
-;.area HEADER (ABS)
 .org 0x0000
-       ;TODO: 0x0000 must be NOP for autocalib routine
-       ;TODO: move some init stuff here (space for 15 instr.)
        GOTO    init
 
-;.area HOME
-;.area HEADER (ABS)
-.org     0x0020
-       GOTO    sample
-
-;.area CODE
+.org 0x0020
+       GOTO    interrupt
 
 mod3:
        MOV     a, mod3hi
@@ -166,16 +191,70 @@ g:
        RET
 
 init:
-       ; AUTO_INIT_SYSCLOCK() -- 4mhz
-       ; AUTO_CALIBRATE_SYSCLOCK() -- move away w/ goto
-       ; ??: setup fuses (romlocation 0x3ff)
-       ; setup SP (&= 0xfe)
-       ; setup timer2, timer16
+       ; clock setup (no calibration):
+       SET1    clkmd, #4       ; enable IHRC
+       MOV     a, #(( 0<<5 | 1<<4 | 0<<3 | 1<<2 | 0<<1 | 0<<0 ))
+       MOV     clkmd, a        ; switch to IHRC/4, WDT off; keep ILRC on
+
+       ;; .org 0x46 ; comment out on 2nd iteration
+       ; calibration placeholder:
+       AND     a, #'R'
+       AND     a, #'C'
+       AND     a, #1 ; IHRC
+       AND     a, #( calib_freq )
+       AND     a, #( calib_freq>>8 )
+       AND     a, #( calib_freq>>16 )
+       AND     a, #( calib_freq>>24 )
+       AND     a, #( calib_vdd )
+       AND     a, #( calib_vdd>>8 )
+       AND     a, #ihrcr
+       ;; .org 0x5a
+
+       ;stack setup:
+       MOV     a, #stack_start
+       MOV     sp, a
+
+       ; portA setup:
+       MOV     a, #0xff
+       MOV     pac, a          ; data direction: all output
+       MOV     a, #0
+       MOV     padier, a       ; disable pin wakeup
+       MOV     pa, a           ; PortA data = 0
+       MOV     paph, a         ; disable all pull-ups
+
+       ; timer2/pwm setup:
+        ; Since (unlike in the ATTiny4 version) the interrupt timer is not tied
+        ; to the PWM frequency, we can use a much faster clock for PWM. The
+        ; highest "carrier frequency" for the PCM samples we can generate is by
+        ; setting Timer2 to 6 bit, (IHRC/1)/1 mode, giving a frequency of
+        ; (4*4.096MHz)/2^6 = 256kHz.
+       MOV     a, #0x7f
+       MOV     pwm, a
+       MOV     tm2b, a         ; pwm duty cycle 50%
+       MOV     a, #(( 2<<4 | 3<<2 | 1<<1 | 0<<0 ))
+       MOV     tm2c, a         ; timer2: IHRC, PA4, PWM, not inverted
+       MOV     a, #(( 0<<7 | 1<<5 | 0<<0 ))
+       MOV     tm2s, a         ; 8bit, /4 prescaler, divide by (0+1)
+
+       ;timer16/ivr setup
+       ;mov    a, #(( 0<<0 | 1<<3 | 4<<5 ))    ; ovf@bit8 (512cy; §9.2.5), clk/4, ihrc
+       MOV     a, #(( 1<<0 | 1<<3 | 4<<5 ))    ; ovf@bit9 (???cy; §9.2.5), clk/4, ihrc
+       ;XXX: datasheet §5.10.1 says bit8 = 256cycles, 9.2.5 says bit8=512cy
+       ; note: ovf@bit9 causes 4khz isr => we need ovf@bit8.
+       MOV     t16m, a
+       MOV     a, #(1<<2)              ; enable timer16 int, disable all others
+       MOV     inten, a
+
+       ; misc setup:
+       SET1    eoscr, #0       ; disable bandgap and lvr
+       SET0    gpcc, #7        ; disable comparator
+
+       ; memory setup:
        CLEAR   i0
        CLEAR   i1
        CLEAR   i2
 
-       ;rom is not mmapped; must load into ram first
+       ;rom is not mmapped; must load notes into ram first
        MOV     a, #0x84
        MOV     notes+0x0, a
        MOV     notes+0x5, a
@@ -200,17 +279,36 @@ init:
        MOV     notes+0x9, a
        MOV     notes+0xC, a
 
-       ;TODO: setup mcu, timer16, ...
-       ;TODO: freepdk calibration routine
+       ENGINT
 
 loop:
        ;TODO: test i2==0x78 to enter halt()
-       ;TODO: stopsys
+       ; Note: usually, this is the place where the MCU is put into some
+       ; sort of low power/sleep mode. But the Padauk's stopexe instruction
+       ; causes the ISR to a) run at greatly reduced frequency (100hz vs
+       ; 1khz for timer16@bit11; probably due to slow wakeup), b)
+       ; double-fire some (20-30%) of the time, c) jitter -50% to +10%. so
+       ; we don't sleep at all between samples (which is only a short time
+       ; anyways).
        GOTO    loop
 
-sample:
+interrupt:
+       PUSH    af
+       SET1    pa, #3 ;debug2
+       T1SN    intrq, #2       ; if intrq.t16 is triggered, skip next
+       GOTO    ivr_end
+
+       ;clear t16int:
+       SET0    intrq, #2
+
+       SET1    pa, #6          ; debug
+
        ;TODO: send pwm data to timer2
+       MOV     a, pwm
+       ADD     a, #4
+       MOV     tm2b, a
 
+       ; generate new sample:
        MOV     a, i2; "mov mem,mem"
        MOV     n, a; does not exist
        SL      n
@@ -326,10 +424,14 @@ sample:
 
        MOV     a, pwm
        SWAP    a
+       MOV     pwm, a
        ; next sample is now ready.
 
        INC     i0
        ADDC    i1
        ADDC    i2
 
+       SET1    pa, #6          ; debug
+ivr_end:
+       POP     af
        RETI
Imprint / Impressum