Files
aqhomecontrol/avr/utils.asm
2023-02-04 00:56:59 +01:00

266 lines
6.2 KiB
NASM

; ---------------------------------------------------------------------------
; Utils_WaitNanoSecs waittime_in_ns , cyles_already_used , waitcount_register
;
; cycles already used will be subtracted from the delay
; the waittime resolution is 1 cycle (delay from exact to +1 cycle)
; the maximum delay at 20MHz (50ns/clock) is 38350ns
; waitcount register must specify an immediate register
; taken from https://www.mikrocontroller.net/articles/AVR_Assembler_Makros#Verz%C3%B6gerung_um_X_Nanosekunden
;
.set Osc_Hz = clock ; 1 MHz
.set cycle_time_ns = (1000000000 / Osc_Hz) ; clock duration
.macro Utils_WaitNanoSecs
.set cycles = ((@0 + cycle_time_ns - 1) / cycle_time_ns - @1)
.if (cycles > (255 * 3 + 2))
.error "MACRO Utils_WaitNanoSecs - too many cycles to burn"
.else
.if (cycles > 6)
.set loop_cycles = (cycles / 3)
ldi @2,loop_cycles
dec @2
brne pc-1
.set cycles = (cycles - (loop_cycles * 3))
.endif
.if (cycles > 0)
.if (cycles & 4)
rjmp pc+1
rjmp pc+1
.endif
.if (cycles & 2)
rjmp pc+1
.endif
.if (cycles & 1)
nop
.endif
.endif
.endif
.endmacro
; ---------------------------------------------------------------------------
; Utils_FillSram
;
; IN:
; - x: pointer to SRAM to fill
; - r16: value to fill the SRAM with
; - r17: size of area to fill
; OUT:
; - nothing
; MODIFIED REGISTERS: r17, x
Utils_FillSram:
tst r17
breq Utils_FillSram_end
Utils_FillSram_loop:
st x+, r16
dec r17
brne Utils_FillSram_loop
Utils_FillSram_end:
ret
; ---------------------------------------------------------------------------
; Increment a 32 bit counter at the address given by X.
; IN:
; - X: Address of the 4 byte counter (1. byte is LSB)
; OUT:
; - nothing
; MODIFIED REGISTERS: r18, r19, r20, r21, 22
Utils_IncrementCounter32:
ld r18, x+
ld r19, x+
ld r20, x+
ld r21, x
ldi r22, 1
add r18, r22
clr r22 ; doesn't affect carry flag
adc r19, r22
adc r20, r22
adc r21, r22
st x, r21
st -x, r20
st -x, r19
st -x, r18
ret
; ---------------------------------------------------------------------------
; Increment a 16 bit counter at the address given by X.
; IN:
; - X: Address of the 2 byte counter (1. byte is LSB)
; OUT:
; - nothing
; MODIFIED REGISTERS: r18, r19, 22
Utils_IncrementCounter16:
ld r18, x+
ld r19, x
ldi r22, 1
add r18, r22
clr r22 ; doesn't affect carry flag
adc r19, r22
st x, r19
st -x, r18
ret
; ---------------------------------------------------------------------------
; Utils_ReadEeprom
;
; Read a byte from EEPROM (see example in ATtiny24/44/84 manual p.19).
;
; IN:
; - X: EEPROM Address to read from
; OUT:
; - R16: byte read
; MODIFIED REGISTERS: R16
Utils_ReadEeprom:
sbic EECR, EEPE ; wait for previous write to complete (if any)
rjmp Utils_ReadEeprom
out EEARH, xh ; set EEPROM address
out EEARL, xl
sbi EECR, EERE ; start EEPROM read by writing EERE
in r16, EEDR ; read data from data register
ret
; ---------------------------------------------------------------------------
; Utils_WriteEeprom
;
; Write a byte to EEPROM (see example in ATtiny24/44/84 manual p.18).
;
; IN:
; - R16: byte to write
; - X: EEPROM Address to read from
; OUT:
; - nothing
; MODIFIED REGISTERS: R17
Utils_WriteEeprom:
sbic EECR, EEPE ; wait for previous write to complete (if any)
rjmp Utils_WriteEeprom
ldi r17, (0<<EEPM1) | (0<<EEPM0) ; set programming mode
out EECR, r17
out EEARH, xh ; set EEPROM address
out EEARL, xl
out EEDR, r16 ; write data to data register
sbi EECR, EEMPE ; write logical one to EEMPE
sbi EECR, EEPE ; start EEPROM write by setting EEPE
ret
; ---------------------------------------------------------------------------
; Utils_ReadFlashPageIntoPageBuffer
;
;
; IN:
; - Z: Address to read from (byte address as for LPM!)
; OUT:
; - nothing
; MODIFIED REGISTERS: R0, R1, R15, R16, R20, R24, R25, Z
Utils_ReadFlashPageIntoPageBuffer:
in r15, SREG
cli
ldi r24, LOW(PAGESIZE*2)
ldi r25, HIGH(PAGESIZE*2)
Utils_ReadFlashPageIntoPageBuffer_loop:
lpm r0, Z+ ; read source data from FLASH (low)
lpm r1, Z ; read source data from FLASH (high)
sbiw ZH:ZL, 1 ; rewind Z address for following SPM
ldi r20, (1<<SPMEN) ; enable next SPM, write into temp page buffer
rcall utilsDoSpm ; (R16)
adiw ZH:ZL, 2
sbiw r25:r24, 2 ;use subi for PAGESIZEB<=256
brne Utils_ReadFlashPageIntoPageBuffer_loop
out SREG, r15
ret
; ---------------------------------------------------------------------------
; Utils_EraseFlashPage
;
;
; IN:
; - Z: Address of the page to erase.
; OUT:
; - nothing
; MODIFIED REGISTERS: R0, R1, R15, R16, R18, R19, R20
Utils_EraseFlashPage:
in r15, SREG
cli
ldi r20, (1<<PGERS) + (1<<SPMEN) ; enable next SPM, erase page (R1/R0 ignored)
rcall utilsDoSpm ; (R16)
out SREG, r15
ret
; ---------------------------------------------------------------------------
; Utils_WriteFlashPage
;
;
; IN:
; - Z: Address of the page to erase.
; OUT:
; - nothing
; MODIFIED REGISTERS: R0, R1, R15, R16, R18, R19, R20
Utils_WriteFlashPage:
in r15, SREG
cli
ldi r20, (1<<PGWRT) + (1<<SPMEN) ; enable next SPM, erase page (R1/R0 ignored)
rcall utilsDoSpm ; (R16)
out SREG, r15
ret
; ---------------------------------------------------------------------------
; utilsDoSpm
;
; wait until possible previous SPM finished and then issue another SPM.
;
; IN:
; - R20: value for register SPMCR
; - R0: low value for SPM
; - R1: high value for SPM
; - Z : address for SPM (byte address!)
; OUT:
; - nothing
; REGS: R16
utilsDoSpm:
wait: ; wait for possibly previous SPM to complete
in r16, SPMCSR
sbrc r16, SPMEN
rjmp wait
; SPM timed sequence
out SPMCSR, r20
spm
ret