From: Tobias Girstmair Date: Mon, 26 Apr 2021 07:22:58 +0000 (+0200) Subject: add initialisation code X-Git-Url: https://git.gir.st/Chiptunes-pms150c.git/commitdiff_plain/a43c9c44e1a0426fb11669d5f60237d6acff96c6 add initialisation code prototyped seperately as 06-timer16ivr-v2/main.asm --- diff --git a/bsv.S b/bsv.S index 84370bd..72f58f3 100644 --- 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