Files
aqhomecontrol/avr/utils.asm
Martin Preuss 08d6cab1e9 avr: started working on base system vs. main system.
base system will be a base system which can be used to flash and start
the main system.
2023-02-20 23:47:30 +01:00

392 lines
8.5 KiB
NASM

; ***************************************************************************
; macros
; ---------------------------------------------------------------------------
; 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
; ***************************************************************************
; data
.dseg
utilsDataBegin:
utilsSeed: .byte 2
utilsDataEnd:
; ***************************************************************************
; code
.cseg
utilsDateString: .db "%YEAR%-%MONTH%-%DAY%-%HOUR%:%MINUTE%", 0, 0
; ---------------------------------------------------------------------------
; Utils_Init
;
; IN:
; OUT:
; - CFLAG: set if okay, clear on error
; USED: R16, R17, R18, X, Y
Utils_Init:
; preset SRAM data area
ldi xh, HIGH(utilsDataBegin)
ldi xl, LOW(utilsDataBegin)
clr r16
ldi r17, (utilsDataEnd-utilsDataBegin)
rcall Utils_FillSram
; generate initial seed from compile date string
ldi zl, LOW(utilsDateString*2)
ldi zh, HIGH(utilsDateString*2)
ldi r18, 0xe1
ldi r19, 0xac
Utils_Init_l1:
lpm r16, Z+
tst r16
breq Utils_Init_l2
eor r18, r16
lsl r18
rol r19
rjmp Utils_Init_l1
Utils_Init_l2:
sts utilsSeed, r18
sts utilsSeed+1, r19
sec
ret
; ---------------------------------------------------------------------------
; Utils_Fini
;
; IN:
; OUT:
; - CFLAG: set if okay, clear on error
; USED: R16, R17, R18, X, Y
Utils_Fini:
sec
ret
; ---------------------------------------------------------------------------
; 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
#if 0
; ---------------------------------------------------------------------------
; 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
#endif
; ---------------------------------------------------------------------------
; 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_PseudoRandom
;
; Generate a pseudo random number.
; (see https://www.avrfreaks.net/s/topic/a5C3l000000URNfEAO/t119045?comment=P-1021038)
;
; IN:
; OUT:
; - R16: 8 bit pseudo random number
; REGS: R16, R17, R18, R19
Utils_PseudoRandom:
lds r16, utilsSeed
lds r17, utilsSeed+1
ldi r18, 0x9c
ldi r19, 8
Utils_PseudoRandom_step:
lsr r17
ror r16
brcc Utils_PseudoRandom_nomask
eor r17, r18
Utils_PseudoRandom_nomask:
dec r19
brne Utils_PseudoRandom_step
sts utilsSeed, r16
sts utilsSeed+1, r17
ret ; result in r16
; ---------------------------------------------------------------------------
; Utils_ReadUid
;
; Read UID from EEPROM.
;
; IN:
; OUT:
; - R18:R19:R20:R21: UID
; REGS: R16, X
Utils_ReadUid:
push r15
in r15, SREG
cli
ldi xl, LOW(EEPROM_OFFS_UUID)
ldi xh, HIGH(EEPROM_OFFS_UUID)
rcall Utils_ReadEeprom ; (R16)
mov r18, r16
adiw xh:xl, 1
rcall Utils_ReadEeprom ; (R16)
mov r19, r16
adiw xh:xl, 1
rcall Utils_ReadEeprom ; (R16)
mov r20, r16
adiw xh:xl, 1
rcall Utils_ReadEeprom ; (R16)
mov r21, r16
pop r15
out SREG, r15
ret
; ---------------------------------------------------------------------------
; Utils_SetupUid
;
; Reads UID from EEPROM. If not set generate a new one and store it in EEPROM.
;
; IN:
; OUT:
; - CFLAG set if new generated, cleared if there already was one.
; REGS: R15, R16, R18, R19, R20, R21, X
Utils_SetupUid:
in r15, SREG
cli
rcall Utils_ReadUid ; R16, X
mov r16, r18 ; all 0x00?
or r16, r19
or r16, r20
or r16, r21
breq Utils_SetupUid_generate ; yep, go generate one
mov r16, r18 ; all 0xff?
and r16, r19
and r16, r20
and r16, r21
inc r16
breq Utils_SetupUid_generate ; yep, go generate one
out SREG, r15
clc
ret
Utils_SetupUid_generate:
ldi xl, LOW(EEPROM_OFFS_UUID)
ldi xh, HIGH(EEPROM_OFFS_UUID)
rcall Utils_PseudoRandom ; byte 0 (R16, R17, R18, R19)
inc r16
rcall Utils_WriteEeprom ; (R17)
adiw xh:xl, 1
rcall Utils_PseudoRandom ; byte 1
rcall Utils_WriteEeprom
adiw xh:xl, 1
rcall Utils_PseudoRandom ; byte 2
rcall Utils_WriteEeprom
adiw xh:xl, 1
rcall Utils_PseudoRandom ; byte 3
rcall Utils_WriteEeprom
adiw xh:xl, 1
out SREG, r15
sec
ret
; ---------------------------------------------------------------------------
; Get offset and mask for a given bit in a bitfield
; IN:
; - R16: bit to request position for
; OUT:
; - R1: offset into the bitfield to the byte containing the given bit
; - R2: mask for given id (apply to r1)
; USED REGISTERS: r1, r2, r17, Z
Utils_GetPosAndMaskInBitField:
mov r1, r16 ; divide by 8 to get the offset to the byte containing the given module id
lsr r1
lsr r1
lsr r1 ; r1=offset of the byte holding the given bit
mov r2, r16 ; get bit mask for bit position in table byte
ldi r17, 7 ; keep lower 3 bits
and r2, r17
ldi zh, HIGH(utilsModuleBitNumToMaskMap*2)
ldi zl, LOW(utilsModuleBitNumToMaskMap*2)
add zl, r2
brcc Utils_GetPosAndMaskInBitField_noOverflow
inc zh
Utils_GetPosAndMaskInBitField_noOverflow:
lpm r2, z ; r2=mask for bit in byte from bitfield
ret
utilsModuleBitNumToMaskMap:
.db 1, 2, 4, 8, 16, 32, 64, 128