Merge branch 'mp-2025_05-uart2'

This commit is contained in:
Martin Preuss
2025-05-24 17:49:44 +02:00
85 changed files with 5798 additions and 513 deletions

View File

@@ -11,3 +11,4 @@ export LD_LIBRARY_PATH="0-build/aqhome/:$LD_LIBRARY_PATH"
# 0-build/apps/aqhomed/aqhomed -l aqhome.log -db aqhome.db -p aqhomed.pid -W /tmp/aqhome/aqhomed -ma 192.168.117.192 -mp 1883 -t 127.0.0.1 --mqttclientid=AQHOMEMQTTLOGTEST1
0-build/apps/aqhome-nodes/aqhome-nodes -N -l aqhome-nodes.log -db aqhome-nodes.db -p aqhome-nodes.pid -t 127.0.0.1 -ba 127.0.0.1 "$@"
#0-build/apps/aqhome-nodes/aqhome-nodes -l aqhome-nodes.log -db aqhome-nodes.db -p aqhome-nodes.pid -t 127.0.0.1 -ba 127.0.0.1 "$@"

View File

@@ -49,7 +49,7 @@ AppDoor_Init:
ldi yl, LOW(appDoorValSchedData)
ldi yh, HIGH(appDoorValSchedData)
rcall ValueScheduler_Init
ldi r16, (1<<VALSCHED_FLAGS_REPEAT1_BIT) ; only repeat report interval for active motion
ldi r16, (1<<VALSCHED_FLAGS_REPEAT1_BIT) ; only repeat report interval for open door
std Y+VALSCHED_OFFS_FLAGS, r16
ret

View File

@@ -53,6 +53,27 @@ AppNetwork_SendRxdStats_end:
; ---------------------------------------------------------------------------
; @routine AppNetwork_SendRxdStats
; @param Y network interface to work with
; @clobbers R16, X (R17, R18, R19, R20, R21, Z)
AppNetwork_SendMemStats:
rcall NET_Buffer_Alloc ; (R16, R17, X)
brcc AppNetwork_SendMemStats_end
push r16
adiw xh:xl, 1
rcall NETMSG_MemStats_Write ; (R16, R17, R18, R19, R20, R21)
sbiw xh:xl, 1
pop r16
rcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
AppNetwork_SendMemStats_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine AppNetwork_SendDevice

View File

@@ -53,11 +53,12 @@ AppReportSensors_Fini:
;
AppReportSensors_OnEverySecond:
in r15, SREG
push r15
in r15, SREG
cli
rcall AppReportSensors_OnEverySecond_noIrqs
out SREG, r15
out SREG, r15
pop r15
ret
AppReportSensors_OnEverySecond_noIrqs:
lds r16, reportSensorTimer

View File

@@ -63,16 +63,20 @@ AppStats_OnEveryMinute_store:
ldi yl, LOW(netInterfaceData)
ldi yh, HIGH(netInterfaceData)
cpi r16, 1
breq AppStats_OnEveryMinute_sendDevice
breq AppStats_OnEveryMinute_sendRxdStats
cpi r16, 2
breq AppStats_OnEveryMinute_sendTxdStats
cpi r16, 3
breq AppStats_OnEveryMinute_sendRxdStats
breq AppStats_OnEveryMinute_sendDevice
cpi r16, 4
breq AppStats_OnEveryMinute_sendMemStats
ret
AppStats_OnEveryMinute_sendTxdStats:
rjmp AppNetwork_SendTxdStats
AppStats_OnEveryMinute_sendRxdStats:
rjmp AppNetwork_SendRxdStats
AppStats_OnEveryMinute_sendMemStats:
rjmp AppNetwork_SendMemStats
AppStats_OnEveryMinute_sendDevice:
rjmp AppNetwork_SendDevice
; @end

View File

@@ -17,10 +17,13 @@
utils_copy_from_flash.asm
utils_copy_sdram.asm
utils_initial_wait.asm
utils_io.asm
utils_wait.asm
utils_wait_fixed.asm
utils_wait_pin.asm
watchdog.asm
list.asm
tree.asm
</extradist>
</gwbuild>

166
avr/common/list.asm Normal file
View File

@@ -0,0 +1,166 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
#ifndef AQH_AVR_COMMON_LIST_H
#define AQH_AVR_COMMON_LIST_H
; ---------------------------------------------------------------------------
; This code implements a simple single-linked list.
; It assumes that the first 2 bytes of an object managed by this code contain
; a 2 byte pointer to the next object.
; ---------------------------------------------------------------------------
; ***************************************************************************
; defs
.equ LIST_OFFS_NEXT_LO = 0
.equ LIST_OFFS_NEXT_HI = 1
.equ LIST_SIZE = 2
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine List_InitObject @global
;
; Reset list object fields.
; @param Y pointer to object
; @clobbers r16
List_InitObject:
clr r16 ; set this->NEXT to NULL
std Y+LIST_OFFS_NEXT_LO, r16
std Y+LIST_OFFS_NEXT_HI, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine List_GetNextObject @global
; @param Y pointer to object
; @return X pointer to parent object
; @clobbers none
List_GetNextObject:
ldd xl, Y+LIST_OFFS_NEXT_LO
ldd xh, Y+LIST_OFFS_NEXT_HI
ret
; @end
; ---------------------------------------------------------------------------
; @routine List_GetLastObject
; @param X pointer to one object in a list
; @return X pointer to last object which has an empty NEXT pointer
; @clobbers r16, r17, X, Y
List_GetLastObject:
clr yl
clr yh
rjmp List_GetPredecessorFor
; @end
; ---------------------------------------------------------------------------
; @routine List_GetPredecessorFor
; @param Y pointer to this object
; @param X pointer to first object in a list
; @return X pointer to object whose NEXT pointer points to the given object (or NULL)
; @clobbers r16, r17, X
List_GetPredecessorFor:
mov r16, xl
or r16, xh
breq List_GetPredecessorFor_ret
ld r16, X+
ld r17, X+
cp r16, yl
brne List_GetPredecessorFor_next
cp r17, yh
breq List_GetLastObject_haveIt
List_GetPredecessorFor_next:
mov xl, r16
mov xh, r17
rjmp List_GetPredecessorFor
List_GetPredecessorFor_haveIt:
sbiw xh:xl, 1
List_GetPredecessorFor_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine List_AddObject
; @param X pointer to first object in a list
; @param Y pointer to object to add
; @clobbers r16, r17, x
List_AddObject:
push yl
push yh
rcall List_GetLastObject ; (r16, r17, X, Y)
pop yh
pop yl
st X+, yl ; WID_OFFS_WNEXT_LO
st X+, yh ; WID_OFFS_WNEXT_HI
ret
; @end
; ---------------------------------------------------------------------------
; @routine List_UnlinkObject
; @param X pointer to first object in a list
; @param Y pointer to object to remove
; @clobbers r16, r17, x
List_UnlinkObject:
push yl
push yh
rcall List_GetPredecessorFor ; (r16, r17, X)
pop yh
pop yl
mov r16, xl
or r16, xh
breq List_UnlinkObject_ret
ldd r16, Y+LIST_OFFS_NEXT_LO ; get this->NEXT
ldd r17, Y+LIST_OFFS_NEXT_HI
st X+, r16 ; store as NEXT in predecessor
st X, r17
clr r16 ; set this->NEXT to NULL
std Y+LIST_OFFS_NEXT_LO, r16
std Y+LIST_OFFS_NEXT_HI, r16
List_UnlinkObject_ret:
ret
; @end
#endif ; AQH_AVR_COMMON_LIST_H

View File

@@ -119,7 +119,7 @@ RingBufferY_Reset:
; @routine RingBufferY_ReadByteGuarded
;
; @return CFLAG on success, cleared on error
; @param r16 byte to write
; @return r16 byte read
; @param Y pointer to start of interface data
; @clobbers R17, R18, X

192
avr/common/tree.asm Normal file
View File

@@ -0,0 +1,192 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
#ifndef AQH_AVR_COMMON_TREE_H
#define AQH_AVR_COMMON_TREE_H
; ***************************************************************************
; defs
.equ TREE_OFFS_LIST = 0
.equ TREE_OFFS_WPARENT_LO = TREE_OFFS_LIST+LIST_SIZE
.equ TREE_OFFS_WPARENT_HI = TREE_OFFS_LIST+LIST_SIZE+1
.equ TREE_OFFS_WCHILD_LO = TREE_OFFS_LIST+LIST_SIZE+2
.equ TREE_OFFS_WCHILD_HI = TREE_OFFS_LIST+LIST_SIZE+3
.equ TREE_SIZE = TREE_OFFS_LIST+LIST_SIZE+4
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine Tree_InitObject @global
; @param Y pointer to object to add
; @clobbers r16
Tree_InitObject:
rcall List_InitObject ; (R16)
clr r16 ; clear this->TREE data
std Y+TREE_OFFS_LIST+TREE_OFFS_WPARENT_LO, r16
std Y+TREE_OFFS_LIST+TREE_OFFS_WPARENT_HI, r16
std Y+TREE_OFFS_LIST+TREE_OFFS_WCHILD_LO, r16
std Y+TREE_OFFS_LIST+TREE_OFFS_WCHILD_HI, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine Tree_GetParentObject @global
; @param Y pointer to object
; @return X pointer to parent object
; @clobbers none
Tree_GetParentObject:
ldd xl, Y+TREE_OFFS_WPARENT_LO
ldd xh, Y+TREE_OFFS_WPARENT_HI
ret
; @end
; ---------------------------------------------------------------------------
; @routine Tree_GetFirstChildObject @global
; @param Y pointer to object
; @return X pointer to first child object
; @clobbers none
Tree_GetFirstChildObject:
ldd xl, Y+TREE_OFFS_WCHILD_LO
ldd xh, Y+TREE_OFFS_WCHILD_HI
ret
; @end
; ---------------------------------------------------------------------------
; @routine Tree_GetObjectBelow @global
; @param Y pointer to object
; @return X pointer to object below (or NULL)
; @clobbers r16
Tree_GetObjectBelow:
push yl
push yh
rcall treeGetObjectBelow
pop yh
pop yl
ret
treeGetObjectBelow:
rcall Tree_GetFirstChildObject
mov r16, xl
or r16, xh
brne treeGetObjectBelow_ret ; got one
rcall List_GetNextObject
mov r16, xl
or r16, xh
brne treeGetObjectBelow_ret ; got one
rcall Tree_GetParentObject
mov r16, xl
or r16, xh
breq treeGetObjectBelow_ret ; no parent
mov yl, xl
mov yh, xh
rjmp treeGetObjectBelow ; try with parent
treeGetObjectBelow_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine Tree_AddChildObject @global
; @param X pointer to parent to add to
; @param Y pointer to object to add
; @clobbers r16, r17, r18, x
Tree_AddChildObject:
std Y+TREE_OFFS_WPARENT_LO, xl ; immediately store parent pointer
std Y+TREE_OFFS_WPARENT_HI, xh
adiw xh:xl, TREE_OFFS_WCHILD_LO
ld r16, X+
ld r17, X
mov r18, r16
or r18, r17
brne Tree_AddChildObject_addToChildList
st X, yh ; no child, set THIS as first
st -X, yl
sbiw xh:xl, WID_OFFS_TREE+TREE_OFFS_WCHILD_LO
ret
Tree_AddChildObject_addToChildList:
mov xl, r16
mov xh, r17
rjmp List_AddObject
; @end
; ---------------------------------------------------------------------------
; @routine Tree_UnlinkObject @global
; @param Y pointer to object to remove
; @clobbers r16, r17, x
Tree_UnlinkObject:
ldd xl, Y+TREE_OFFS_WPARENT_LO
ldd xh, Y+TREE_OFFS_WPARENT_HI
mov r16, xl
or r16, xh
breq Tree_UnlinkObject_ret ; not part of a tree
adiw xh:xl, TREE_OFFS_WCHILD_LO ; get parent's first child to R17:R16
ld r16, X+
ld r17, X
cp r16, yl ; same as THIS?
brne Tree_UnlinkObject_inList ; nope, need to check childList
cp r17, yh
brne Tree_UnlinkObject_inList ; nope, need to check childList
ldd r16, Y+TREE_OFFS_LIST+LIST_OFFS_NEXT_HI ; is first child, set this->NEXT as new first child
st X, r16
ldd r16, Y+TREE_OFFS_LIST+LIST_OFFS_NEXT_LO
st -X, r16
rjmp Tree_UnlinkObject_clrParentAndSibling
Tree_UnlinkObject_inList:
mov xl, r16
mov xh, r17
rcall List_UnlinkObject ; (R16, R17, X)
Tree_UnlinkObject_clrParentAndSibling:
clr r16 ; clear this->PARENT
std Y+TREE_OFFS_LIST+TREE_OFFS_WPARENT_LO, r16
std Y+TREE_OFFS_LIST+TREE_OFFS_WPARENT_HI, r16
std Y+LIST_OFFS_NEXT_LO, r16
std Y+LIST_OFFS_NEXT_HI, r16 ; clear this->NEXT
Tree_UnlinkObject_ret:
ret
; @end
#endif ; AQH_AVR_COMMON_TREE_H

View File

@@ -269,7 +269,11 @@ Utils_IncrementCounter16:
; MODIFIED REGISTERS: R16
Utils_ReadEepromIncr:
.ifdef EEPE
sbic EECR, EEPE ; wait for previous write to complete (if any)
.else
sbic EECR, EEWE ; wait for previous write to complete (if any)
.endif
rjmp Utils_ReadEepromIncr
out EEARH, xh ; set EEPROM address
out EEARL, xl
@@ -293,15 +297,29 @@ Utils_ReadEepromIncr:
; MODIFIED REGISTERS: R17
Utils_WriteEepromIncr:
.ifdef EEPE
sbic EECR, EEPE ; wait for previous write to complete (if any)
.else
sbic EECR, EEWE ; wait for previous write to complete (if any)
.endif
rjmp Utils_WriteEepromIncr
.ifdef EEPM1
ldi r17, (0<<EEPM1) | (0<<EEPM0) ; set programming mode
.endif
out EECR, r17
out EEARH, xh ; set EEPROM address
out EEARL, xl
out EEDR, r16 ; write data to data register
.ifdef EEMPE
sbi EECR, EEMPE ; write logical one to EEMPE
.else
sbi EECR, EEMWE ; write logical one to EEMWE
.endif
.ifdef EEPE
sbi EECR, EEPE ; start EEPROM write by setting EEPE
.else
sbi EECR, EEWE ; start EEPROM write by setting EEWE
.endif
adiw xh:xl, 1
ret

29
avr/common/utils_io.asm Normal file
View File

@@ -0,0 +1,29 @@
; ***************************************************************************
; copyright : (C) 2023 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; M_IO_READ DEST, SRC
.macro M_IO_READ
.if @1 < 64
in @0, @1
.else
lds @0, @1
.endif
.endmacro
; M_IO_WRITE DEST, SRC
.macro M_IO_WRITE
.if @0 < 64
out @0, @1
.else
sts @0, @1
.endif
.endmacro

View File

@@ -53,4 +53,41 @@ Utils_WaitFor100MicroSecs:
; ---------------------------------------------------------------------------
; @routine Utils_WaitFor1MilliSec @global
;
; wait for about 1ms.
;
; @clobbers r22
Utils_WaitFor1MilliSec:
push r21
ldi r21, 10
Utils_WaitFor1MilliSec_loop:
rcall Utils_WaitFor100MicroSecs ; (R22)
dec r21
brne Utils_WaitFor1MilliSec_loop
pop r21
ret
; @end
; ---------------------------------------------------------------------------
; @routine Utils_WaitForMilliSecs @global
;
; wait for given amount of milliseconds
; @param r16 number of millisecs to wait
; @clobbers r22
Utils_WaitForMilliSecs:
rcall Utils_WaitFor100MicroSecs ; (R22)
dec r16
brne Utils_WaitForMilliSecs
ret
; @end

View File

@@ -24,6 +24,7 @@
<subdirs>
all
c01
n16
n21
n22

View File

@@ -9,6 +9,7 @@
hw_tn84.asm
hw_tn85.asm
hw_tn841.asm
hw_m8515.asm
includes.asm
main.asm
modules.asm

View File

@@ -40,7 +40,8 @@
.equ EEPROM_OFFS_SEED = 10 ; 2 bytes
.equ EEPROM_OFFS_REED_CONF = 12 ; 1 byte (plus one byte reserved)
.equ EEPROM_OFFS_OSCCAL_SLOW = 12 ; 1 byte
.equ EEPROM_OFFS_OSCCAL_FAST = 13 ; 1 byte
.equ EEPROM_OFFS_MAL_CONF_ONTIME = 14 ; 2 bytes
.equ EEPROM_OFFS_MAL_CONF_SRC1_ADDR = 16 ; 1 byte

View File

@@ -0,0 +1,158 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; Hardware routine for AtTiny 84 devices
.cseg
; ---------------------------------------------------------------------------
; @routine systemInitHardware
;
systemInitHardware:
; set all ports as inputs and enable internal pull-up resistors
ldi r16, 0xff
clr r17
.ifdef PORTA
out DDRA, r17 ; all input
out PORTA, r16 ; enable pull-up on all
.endif
.ifdef PORTB
out DDRB, r17 ; all input
out PORTB, r16 ; enable pull-up on all
.endif
.ifdef PORTC
out DDRC, r17 ; all input
out PORTC, r16 ; enable pull-up on all
.endif
.ifdef PORTD
out DDRD, r17 ; all input
out PORTD, r16 ; enable pull-up on all
.endif
.ifdef PORTE
out DDRE, r17 ; all input
out PORTE, r16 ; enable pull-up on all
.endif
ret
; @end
; ---------------------------------------------------------------------------
; @routine systemSetSpeed
;
systemSetSpeed:
ret
; @end
; ---------------------------------------------------------------------------
; @routine systemSleep
;
systemSleep:
; only modify SE, SM2, SM1 and SM0
cli
M_IO_READ r16, MCUCR
cbr r16, (1<<SE) | (1<<SM2) | (1<<SM1)
M_IO_WRITE MCUCR, r16
M_IO_READ r16, EMCUCR
cbr r16, (1<<SM0)
M_IO_WRITE EMCUCR, r16
sei ; make sure interrupts really are enabled
M_IO_READ r16, MCUCR ; enable sleep mode
sbr r16, (1<<SE)
M_IO_WRITE MCUCR, r16
sleep ; sleep, wait for interrupt
M_IO_READ r16, MCUCR ; disable sleep mode
cbr r16, (1<<SE)
M_IO_WRITE MCUCR, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine systemSetupTimer0
;
systemSetupTimer0: ; setup timer for IRQ every 100ms
ldi r16, (1<<CS02) | (0<<CS01) | (1<<CS00) | (1<<WGM01) | (0<<WGM00) ; Prescaler 1024, CTC mode
out TCCR0, r16
;
; Settings for clock 1Mhz (default)
; use timer0 with OCR0A=98-1 (irq every 97.65625 millisecs), baseTimerModuleReloadValue 1
;
.if clock == 1000000
; CMP-A interrupt about every 100ms
ldi r16, 98-1 ; (1,000,000/1024)/10 = 97.65625
out OCR0, r16
ldi r16, 1
sts baseTimerModuleReloadValue, r16
sts baseTimerModuleTickCounter, r16
.endif
;
; Settings for clock 8Mhz
; use timer0 with OCR0=78 (irq every 9.984 millisecs), baseTimerModuleReloadValue 10
;
.if clock == 8000000
; CMP interrupt about every 10ms
ldi r16, 78-1
out OCR0, r16
ldi r16, 10
sts baseTimerModuleReloadValue, r16
sts baseTimerModuleTickCounter, r16
.endif
ldi r16, (1<<OCF0) ; clear pending interrupts
.ifdef TIFR0
out TIFR0, r16
.else
out TIFR, r16
.endif
.ifdef TIMSK0
M_IO_READ r16, TIMSK0
sbr r16, (1<<OCIE0) ; Timer/Counter0 Output Compare Match A Interrupt Enable
M_IO_WRITE TIMSK0, r16
.else
M_IO_READ r16, TIMSK
sbr r16, (1<<OCIE0) ; Timer/Counter0 Output Compare Match A Interrupt Enable
M_IO_WRITE TIMSK, r16
.endif
sec
ret
; @end

View File

@@ -85,3 +85,61 @@ systemSleep:
; ---------------------------------------------------------------------------
; @routine systemSetupTimer0
;
systemSetupTimer0: ; setup timer for IRQ every 100ms
ldi r16, (1<<CS02) | (0<<CS01) | (1<<CS00) ; Prescaler 1024
out TCCR0B, r16
ldi r16, (1<<WGM01) | (0<<WGM00) ; CTC mode
out TCCR0A, r16
; Settings for clock 1Mhz (default)
; use timer0 with OCR0A=98-1 (irq every 97.65625 millisecs), baseTimerModuleReloadValue 1
;
.if clock == 1000000
; CMP-A interrupt about every 100ms
ldi r16, 98-1 ; (1,000,000/1024)/10 = 97.65625
out OCR0A, r16
ldi r16, 1
sts baseTimerModuleReloadValue, r16
sts baseTimerModuleTickCounter, r16
.endif
;
; Settings for clock 8Mhz
; use timer0 with OCR0A=78 (irq every 9.984 millisecs), baseTimerModuleReloadValue 10
;
.if clock == 8000000
; CMP-A interrupt about every 10ms
ldi r16, 78-1
out OCR0A, r16
ldi r16, 10
sts baseTimerModuleReloadValue, r16
sts baseTimerModuleTickCounter, r16
.endif
ldi r16, (1<<OCF0A) ; clear pending interrupts
.ifdef TIFR0
out TIFR0, r16
.else
out TIFR, r16
.endif
ldi r16, (1<<OCIE0A) ; Timer/Counter0 Output Compare Match A Interrupt Enable
.ifdef TIMSK0
out TIMSK0, r16
.else
out TIMSK, r16
.endif
sec
ret
; @end

View File

@@ -77,3 +77,61 @@ systemSleep:
; ---------------------------------------------------------------------------
; @routine systemSetupTimer0
;
systemSetupTimer0: ; setup timer for IRQ every 100ms
ldi r16, (1<<CS02) | (0<<CS01) | (1<<CS00) ; Prescaler 1024
out TCCR0B, r16
ldi r16, (1<<WGM01) | (0<<WGM00) ; CTC mode
out TCCR0A, r16
; Settings for clock 1Mhz (default)
; use timer0 with OCR0A=98-1 (irq every 97.65625 millisecs), baseTimerModuleReloadValue 1
;
.if clock == 1000000
; CMP-A interrupt about every 100ms
ldi r16, 98-1 ; (1,000,000/1024)/10 = 97.65625
out OCR0A, r16
ldi r16, 1
sts baseTimerModuleReloadValue, r16
sts baseTimerModuleTickCounter, r16
.endif
;
; Settings for clock 8Mhz
; use timer0 with OCR0A=78 (irq every 9.984 millisecs), baseTimerModuleReloadValue 10
;
.if clock == 8000000
; CMP-A interrupt about every 10ms
ldi r16, 78-1
out OCR0A, r16
ldi r16, 10
sts baseTimerModuleReloadValue, r16
sts baseTimerModuleTickCounter, r16
.endif
ldi r16, (1<<OCF0A) ; clear pending interrupts
.ifdef TIFR0
out TIFR0, r16
.else
out TIFR, r16
.endif
ldi r16, (1<<OCIE0A) ; Timer/Counter0 Output Compare Match A Interrupt Enable
.ifdef TIMSK0
out TIMSK0, r16
.else
out TIMSK, r16
.endif
sec
ret
; @end

View File

@@ -84,4 +84,62 @@ systemSleep:
; ---------------------------------------------------------------------------
; @routine systemSetupTimer0
;
systemSetupTimer0: ; setup timer for IRQ every 100ms
ldi r16, (1<<CS02) | (0<<CS01) | (1<<CS00) ; Prescaler 1024
out TCCR0B, r16
ldi r16, (1<<WGM01) | (0<<WGM00) ; CTC mode
out TCCR0A, r16
; Settings for clock 1Mhz (default)
; use timer0 with OCR0A=98-1 (irq every 97.65625 millisecs), baseTimerModuleReloadValue 1
;
.if clock == 1000000
; CMP-A interrupt about every 100ms
ldi r16, 98-1 ; (1,000,000/1024)/10 = 97.65625
out OCR0A, r16
ldi r16, 1
sts baseTimerModuleReloadValue, r16
sts baseTimerModuleTickCounter, r16
.endif
;
; Settings for clock 8Mhz
; use timer0 with OCR0A=78 (irq every 9.984 millisecs), baseTimerModuleReloadValue 10
;
.if clock == 8000000
; CMP-A interrupt about every 10ms
ldi r16, 78-1
out OCR0A, r16
ldi r16, 10
sts baseTimerModuleReloadValue, r16
sts baseTimerModuleTickCounter, r16
.endif
ldi r16, (1<<OCF0A) ; clear pending interrupts
.ifdef TIFR0
out TIFR0, r16
.else
out TIFR, r16
.endif
ldi r16, (1<<OCIE0A) ; Timer/Counter0 Output Compare Match A Interrupt Enable
.ifdef TIMSK0
out TIMSK0, r16
.else
out TIMSK, r16
.endif
sec
ret
; @end

View File

@@ -11,7 +11,9 @@
.include "devices/all/main.asm"
.include "devices/all/apps.asm"
.include "devices/all/modules.asm"
.include "devices/all/sendvalue.asm"
#ifdef MODULES_NETWORK
.include "devices/all/sendvalue.asm"
#endif
.include "devices/all/data.asm"
.include "common/utils.asm"
@@ -22,6 +24,14 @@
.include "modules/basetimer/main.asm"
#ifdef MODULES_XRAM
.include "modules/xram/main.asm"
#endif
#ifdef MODULES_HEAP
.include "modules/heap/main.asm"
#endif
#ifdef MODULES_NETWORK
.include "common/crc8.asm"
.include "common/m_fixedbuffers.asm"
@@ -47,6 +57,15 @@
.include "modules/uart_bitbang2/lowlevel.asm"
#endif
#ifdef MODULES_UART_HW
.include "modules/uart_hw/defs.asm"
.include "modules/uart_hw/lowlevel.asm"
.include "modules/uart_hw/uart.asm"
.include "modules/uart_hw/attn.asm"
.include "modules/uart_hw/net_uart.asm"
#endif
#ifdef MODULES_COMONUART0
.include "modules/uart_hw/defs.asm"
.include "modules/uart_hw/lowlevel.asm"
@@ -106,6 +125,11 @@
.include "modules/owimaster/main.asm"
#endif
#ifdef MODULES_SPI_HW
.include "modules/spi_hw/main.asm"
#endif
#ifdef MODULES_DS18B20
.include "modules/ds18b20/main2.asm"
#ifdef MODULES_NETWORK
@@ -132,6 +156,26 @@
#endif
#endif
#ifdef MODULES_ILI9341
.include "modules/lcd2/ili9341/defs.asm"
.include "modules/lcd2/ili9341/main.asm"
.include "modules/lcd2/ili9341/io_spi.asm"
.include "modules/lcd2/ili9341/graphops.asm"
.include "modules/lcd2/ili9341/text.asm"
#endif
#ifdef MODULES_FONT_8X8
.include "modules/lcd2/font/defs.asm"
.include "modules/lcd2/font/font8x8.asm"
#endif
#ifdef MODULES_FONT_6X8
.include "modules/lcd2/font/defs.asm"
.include "modules/lcd2/font/font6x8.asm"
#endif
#ifdef APPS_MOTION
.include "modules/f_keepup/main.asm"
.include "modules/valsched/main.asm"
@@ -167,6 +211,7 @@
.include "apps/network/stats.asm"
.include "modules/network/msg/sendstats-w.asm"
.include "modules/network/msg/recvstats-w.asm"
.include "modules/network/msg/memstats-w.asm"
.include "modules/network/msg/device-w.asm"
#endif

View File

@@ -94,6 +94,10 @@ onSystemTimerTick:
rcall UART_BitBang_Every100ms
#endif
#ifdef MODULES_UART_HW
rcall NET_Uart_Every100ms
#endif
#ifdef MODULES_TTYONUART1
rcall TtyOnUart1_Periodically
#endif

View File

@@ -24,6 +24,10 @@
initModules:
rcall BaseTimer_Init ; unconditionally call this
#ifdef MODULES_HEAP
rcall Heap_Init
#endif
#ifdef MODULES_CLOCK
rcall Clock_Init
#endif
@@ -32,6 +36,10 @@ initModules:
rcall Timer_Init
#endif
#ifdef MODULES_XRAM
rcall XRAM_Init
#endif
#ifdef MODULES_LED
ldi zl, LOW(ledA3Flash)
ldi zh, HIGH(ledA3Flash)
@@ -57,6 +65,10 @@ initModules:
rcall UART_BitBang_Init
#endif
#ifdef MODULES_UART_HW
rcall NET_Uart_Init
#endif
#ifdef MODULES_TTYONUART1
rcall TtyOnUart1_Init
#endif
@@ -76,6 +88,11 @@ initModules:
#ifdef MODULES_OWI_MASTER
rcall OwiMaster_Init
#endif
#ifdef MODULES_SPI_HW
rcall SPIHW_Init
#endif
#ifdef MODULES_LCD
rcall LCD_Init
#endif
@@ -127,6 +144,10 @@ initModules:
rcall CCS811_Init
#endif
#ifdef MODULES_ILI9341
rcall ILI9341_Init
#endif
; done
ret
@@ -203,7 +224,9 @@ mainModulesOnPacketReceived:
#endif
#ifdef MODULES_LED_SIMPLE
#ifdef MODULES_NETWORK
rcall LedSimple_OnPacketReceived
#endif
#endif

2
avr/devices/c01/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.eep.hex
*.obj

22
avr/devices/c01/0BUILD Normal file
View File

@@ -0,0 +1,22 @@
<?xml?>
<gwbuild>
<subdirs>
boot
main
</subdirs>
<data dist="true" install="$(datadir)/aqhome/devices/nodes">
aqua_c01.xml
</data>
<extradist>
defs.asm
README
</extradist>
</gwbuild>

10
avr/devices/c01/README Normal file
View File

@@ -0,0 +1,10 @@
C01
===
- Role: Controller with Display
- MCU: AtMega 8515
- Connection: RJ45
- Periphery:
- Display with SPI

View File

@@ -0,0 +1,11 @@
<device name="aqua_c01" driver="nodes">
<manufacturer>AQUA</manufacturer>
<devicetype>N</devicetype>
<deviceversion>1</deviceversion>
<values>
<value name="LEDTIMING" id="0x88" type="actor" dataType="uint16" />
</values>
</device>

View File

@@ -0,0 +1,32 @@
<?xml?>
<gwbuild>
<target type="AvrHexFile" name="c01_boot" >
<includes type="avrasm" >
-I $(builddir)
-I $(srcdir)
-I $(topsrcdir)/avr
-I $(topbuilddir)/avr
</includes>
<sources type="avrasm" >
boot.asm
</sources>
</target>
<subdirs>
</subdirs>
<extradist>
</extradist>
</gwbuild>

View File

@@ -0,0 +1,146 @@
; ***************************************************************************
; Source file for base system node on AtMega 8515
;
; This is for the maintenance system (i.e. the flash loader).
;
; All definitions and changes should go into this file.
; ***************************************************************************
.equ clock=8000000 ; Define the clock frequency
.nolist
.include "include/m8515def.inc" ; Define device ATmega8515
.list
.include "../defs.asm"
.include "defs_all.asm"
.include "common/utils_wait.asm"
.include "common/utils_io.asm"
; ***************************************************************************
; defines
; ---------------------------------------------------------------------------
; generic
.equ NET_BUFFERS_NUM = 6
.equ NET_BUFFERS_SIZE = 32
; ---------------------------------------------------------------------------
; firmware settings
.equ FIRMWARE_VERSION_MAJOR = 0
.equ FIRMWARE_VERSION_MINOR = 0
.equ FIRMWARE_VERSION_PATCHLEVEL = 1
; ---------------------------------------------------------------------------
; LED
.equ LED_DDR = DDRE
.equ LED_PORT = PORTE
.equ LED_PIN = PINE
.equ LED_PINNUM = PORTE2
; ***************************************************************************
; code segment
.cseg
.org 0x0000
; ---------------------------------------------------------------------------
; Reset and interrupt vectors
rjmp main ; 1: Reset vector RESET
reti ; 2: INT0 External Interrupt Request 0
reti ; 3: INT1 External Interrupt Request 1
reti ; 4: TIMER1_CAPT Timer/Counter1 Capture Event
reti ; 5: TIMER1_COMPA Timer/Counter1 Compare Match A
reti ; 6: TIMER1_COMPB Timer/Counter1 Compare Match B
reti ; 7: TIMER1_OVF Timer/Counter1 Overflow
reti ; 8: TIMER0_OVF Timer/Counter0 Overflow
reti ; 9: SPI_STC Serial Transfer Complete
reti ; 10: USART_RXC USART Rx Complete
reti ; 11: USART_UDRE USART Data Register Empty
reti ; 12: USART_TXC USART Tx Complete
reti ; 13: ANA_COMP Analog Comparator
reti ; 14: INT2 External Interrupt Request 2
reti ; 15: TIMER0_COMP Timer/Counter0 Compare Match
reti ; 16: EE_RDY EEPROM Ready
reti ; 17: SPM_RDY Store Program Memory Ready
; ---------------------------------------------------------------------------
; Device Info Block
devInfoBlock: ; 12 bytes
devInfoManufacturer: .db 'A', 'Q', 'U', 'A'
devInfoId: .db DEVICEINFO_ID, 0
devInfoVersion: .db DEVICEINFO_VERSION, DEVICEINFO_REVISION ; version, revision
firmwareVersion: .db FIRMWARE_VARIANT_BOOT, FIRMWARE_VERSION_MAJOR
.db FIRMWARE_VERSION_MINOR, FIRMWARE_VERSION_PATCHLEVEL
firmwareStart:
rjmp main ; will be overwritten when flashing
; ***************************************************************************
; main code
.org BOOTLOADER_ADDR
main:
ldi r16, 0xb0 ; orig: a0
out OSCCAL, r16
rjmp bootLoader ; this routine is in modules/bootloader/main.asm
; ***************************************************************************
; includes
.include "common/utils_wait_fixed.asm"
.include "common/utils_copy_from_flash.asm"
.include "common/utils_copy_sdram.asm"
.include "modules/flash/defs.asm"
.include "modules/flash/eeprom.asm"
.include "modules/flash/io.asm"
.include "modules/flash/io_attn.asm"
.include "modules/flash/io_uart.asm"
.include "modules/flash/io_uart_all_attn.asm"
.include "modules/flash/flash1pmega.asm"
.include "modules/flash/flashxp.asm"
.include "modules/flash/flashprocess.asm"
.include "modules/flash/wait.asm"
.include "modules/bootloader/main.asm"
.include "modules/network/msg/defs.asm"
.include "modules/network/msg/crc.asm"
;.include "common/debug.asm"
systemSetSpeed:
; speed not changeable at runtime on this device
ret

170
avr/devices/c01/defs.asm Normal file
View File

@@ -0,0 +1,170 @@
; ***************************************************************************
; copyright : (C) 2023 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
;
; AtMega8515
; --------
; DEV0 (T0) PB0 1 40 VCC
; DEV1 (T1) PB1 2 39 PA0 (AD0) SRAM
; DEV2 (AIN0) PB2 3 38 PA1 (AD1) SRAM
; D_RES (AIN1) PB3 4 37 PA2 (AD2) SRAM
; SPI (SS) PB4 5 36 PA3 (AD3) SRAM
; SPI (MOSI) PB5 6 35 PA4 (AD4) SRAM
; SPI (MISO) PB6 7 34 PA5 (AD5) SRAM
; SPI (SCK) PB7 8 33 PA6 (AD6) SRAM
; /RESET 9 32 PA7 (AD7) SRAM
; UART (RXD) PD0 10 31 PE0 (INT2)
; UART (TXD) PD1 11 30 PE1 (ALE) SRAM
; ATTN (INT0) PD2 12 29 PE2 (OC1B) LED
; T-IRQ (INT1) PD3 13 28 PC7 (A15) SRAM
; D-DC (XCK) PD4 14 27 PC6 (A14) SRAM
; D_BACKLIGHT (OC1A) PD5 15 26 PC5 (A13) SRAM
; SRAM (/WR) PD6 16 25 PC4 (A12) SRAM
; SRAM (/RD) PD7 17 24 PC3 (A11) SRAM
; XTAL2 18 23 PC2 (A10) SRAM
; XTAL1 19 22 PC1 (A9) SRAM
; GND 20 21 PC0 (A8) SRAM
; --------
;
; ***************************************************************************
.equ BOOTLOADER_ADDR = 0xc00
.equ FIRMWARE_VARIANT_BOOT = 0
.equ FIRMWARE_VARIANT_TEMP_WINDOW = 1
.equ DEVICEINFO_ID = 'C'
.equ DEVICEINFO_VERSION = 1
.equ DEVICEINFO_REVISION = 0
; ---------------------------------------------------------------------------
; LED module
.equ LED_SIMPLE_ONTIME = 1 ; shorter
.equ LED_SIMPLE_OFFTIME = 50 ; longer
.equ LED_SIMPLE_DDR = DDRE
.equ LED_SIMPLE_PORT = PORTE
.equ LED_SIMPLE_PORTIN = PINE
.equ LED_SIMPLE_PINNUM = PORTE2
; ---------------------------------------------------------------------------
; COM module
.equ COM_BIT_LENGTH = 52000 ; 104000ns=9600, 52000ns=19200, 26000ns=38400
.equ COM_HALFBIT_LENGTH = 26000 ; see https://de.wikipedia.org/wiki/Universal_Asynchronous_Receiver_Transmitter
.equ COM_ATTN_DDR = DDRD
.equ COM_ATTN_INPUT = PIND
.equ COM_ATTN_OUTPUT = PORTD
.equ COM_ATTN_PIN = PORTD2
.equ COM_IRQ_ADDR_ATTN = GICR
.equ COM_IRQ_BIT_ATTN = INT0
.equ COM_IRQ_GIFR_ATTN = INTF0
;.equ COM_IRQ_GIMSK_ATTN = PCIE0
; ---------------------------------------------------------------------------
; SPI hardware module
.equ SPIHW_SS_DDR = DDRB
.equ SPIHW_SS_INPUT = PINB
.equ SPIHW_SS_OUTPUT = PORTB
.equ SPIHW_SS_PIN = PORTB4
.equ SPIHW_MOSI_DDR = DDRB
.equ SPIHW_MOSI_INPUT = PINB
.equ SPIHW_MOSI_OUTPUT = PORTB
.equ SPIHW_MOSI_PIN = PORTB5
.equ SPIHW_MISO_DDR = DDRB
.equ SPIHW_MISO_INPUT = PINB
.equ SPIHW_MISO_OUTPUT = PORTB
.equ SPIHW_MISO_PIN = PORTB6
.equ SPIHW_SCK_DDR = DDRB
.equ SPIHW_SCK_INPUT = PINB
.equ SPIHW_SCK_OUTPUT = PORTB
.equ SPIHW_SCK_PIN = PORTB7
.equ SPIHW_SS0_DDR = DDRB
.equ SPIHW_SS0_OUTPUT = PORTB
.equ SPIHW_SS0_INPUT = PORTB
.equ SPIHW_SS0_PIN = PORTB0
.equ SPIHW_SS1_DDR = DDRB
.equ SPIHW_SS1_OUTPUT = PORTB
.equ SPIHW_SS1_INPUT = PORTB
.equ SPIHW_SS1_PIN = PORTB1
.equ SPIHW_SS2_DDR = DDRB
.equ SPIHW_SS2_OUTPUT = PORTB
.equ SPIHW_SS2_INPUT = PORTB
.equ SPIHW_SS2_PIN = PORTB2
; ---------------------------------------------------------------------------
; ILI9341 module
.equ ILI9341_DEVICENUM = 0
.equ ILI9341_DSP_WIDTH = 320
.equ ILI9341_DSP_HEIGHT = 240
.equ ILI9341_RESET_DDR = DDRB
.equ ILI9341_RESET_OUTPUT = PORTB
.equ ILI9341_RESET_INPUT = PORTB
.equ ILI9341_RESET_PIN = PORTB3
.equ ILI9341_DC_DDR = DDRD
.equ ILI9341_DC_OUTPUT = PORTD
.equ ILI9341_DC_INPUT = PORTD
.equ ILI9341_DC_PIN = PORTD4
.equ ILI9341_LED_DDR = DDRD
.equ ILI9341_LED_OUTPUT = PORTD
.equ ILI9341_LED_INPUT = PORTD
.equ ILI9341_LED_PIN = PORTD5
; ---------------------------------------------------------------------------
; ComOnUart module
.equ USART0_DATAREG = UDR
.equ UCSR0A = UCSRA
.equ UCSR0B = UCSRB
.equ UCSR0C = UCSRC
.equ UBRR0L = UBRRL
.equ UBRR0H = UBRRH
.equ UCSZ00 = UCSZ0
.equ UCSZ01 = UCSZ1
.equ UDRE0 = UDRE
.equ RXC0 = RXC
.equ TXC0 = TXC
.equ FE0 = FE
.equ DOR0 = DOR
.equ UPE0 = UPE
.equ RXEN0 = RXEN
.equ TXEN0 = TXEN
.equ USBS0 = USBS
.equ RXCIE0 = RXCIE
.equ UDRIE0 = UDRIE

View File

@@ -0,0 +1,34 @@
<?xml?>
<gwbuild>
<target type="AvrHexFile" name="c01_firmware" >
<includes type="avrasm" >
-I $(builddir)
-I $(srcdir)
-I $(topsrcdir)/avr
-I $(topbuilddir)/avr
</includes>
<sources type="avrasm" >
main.asm
</sources>
</target>
<subdirs>
</subdirs>
<extradist>
data.asm
</extradist>
</gwbuild>

View File

@@ -0,0 +1,14 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
.dseg

View File

@@ -0,0 +1,226 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
;.equ clock=1000000 ; Define the clock frequency
.equ clock=8000000 ; Define the clock frequency
.nolist
.include "include/m8515def.inc" ; Define device ATmega8515
.list
.include "../defs.asm"
.include "./data.asm"
.include "devices/all/defs.asm"
.include "common/utils_wait.asm"
.include "common/utils_io.asm"
; ***************************************************************************
; defines
; ---------------------------------------------------------------------------
; generic
.equ NET_BUFFERS_NUM = 8
.equ NET_BUFFERS_SIZE = 32
; ---------------------------------------------------------------------------
; heap
.equ HEAP_START = 0x260
.equ HEAP_SIZE = 32768-0x260
; ---------------------------------------------------------------------------
; firmware settings including list of modules used
.equ FIRMWARE_VERSION_MAJOR = 0
.equ FIRMWARE_VERSION_MINOR = 0
.equ FIRMWARE_VERSION_PATCHLEVEL = 1
; #define MODULES_TIMER
#define MODULES_CLOCK
#define MODULES_XRAM
#define MODULES_HEAP
#define MODULES_LED_SIMPLE
#define MODULES_NETWORK
;#define MODULES_COMONUART0
#define MODULES_UART_HW
#define MODULES_SPI_HW
#define MODULES_ILI9341
;#define MODULES_FONT_8X8
#define MODULES_FONT_6X8
;#define MODULES_UART_BITBANG
;#define MODULES_TWI_MASTER
;#define MODULES_LCD
;#define LCD_MINIMAL_FONT
;#define MODULES_SI7021
;#define MODULES_SGP30
;#define MODULES_SGP40
;#define MODULES_STATS
;#define MODULES_OWI_MASTER
;#define MODULES_DS18B20
;#define MODULES_MOTION
;#define MODULES_CCS811
#define APPS_NETWORK
;#define APPS_MOTION
;#define APPS_REPORTSENSORS
#define APPS_STATS
; ---------------------------------------------------------------------------
; defines for values
.equ VALUE_ID_SI7021_TEMP = 0x01
.equ VALUE_ID_SI7021_HUM = 0x02
.equ VALUE_ID_ADC = 0x03
;.equ VALUE_ID_DS18B20_TEMP = 0x06
.equ VALUE_ID_MOTION = 0x07
.equ VALUE_ID_SGP40_TVOC = 0x08
.equ VALUE_ID_SGP30_TVOC = 0x09
.equ VALUE_ID_SGP30_CO2 = 0x0a
;.equ VALUE_ID_REED_CONF = 0x81
.equ VALUE_ID_DEBUG = 0x7f
.equ VALUE_ID_LEDSIMPLE_TIMING = 0x88
; ***************************************************************************
; code segment
.cseg
.org 000000
; ---------------------------------------------------------------------------
; Reset and interrupt vectors
rjmp BOOTLOADER_ADDR ; 1: Reset vector RESET
rjmp NetUart_AttnChangeIsr ; 2: INT0 External Interrupt Request 0
reti ; 3: INT1 External Interrupt Request 1
reti ; 4: TIMER1_CAPT Timer/Counter1 Capture Event
reti ; 5: TIMER1_COMPA Timer/Counter1 Compare Match A
reti ; 6: TIMER1_COMPB Timer/Counter1 Compare Match B
reti ; 7: TIMER1_OVF Timer/Counter1 Overflow
reti ; 8: TIMER0_OVF Timer/Counter0 Overflow
reti ; 9: SPI_STC Serial Transfer Complete
reti ; 10: USART_RXC USART Rx Complete
reti ; 11: USART_UDRE USART Data Register Empty
reti ; 12: USART_TXC USART Tx Complete
reti ; 13: ANA_COMP Analog Comparator
reti ; 14: INT2 External Interrupt Request 2
rjmp baseTimerIrqOC0A ; 15: TIMER0_COMP Timer/Counter0 Compare Match
reti ; 16: EE_RDY EEPROM Ready
reti ; 17: SPM_RDY Store Program Memory Ready
devInfoBlock: ; 12 bytes
devInfoManufacturer: .db 'A', 'Q', 'U', 'A'
devInfoId: .db DEVICEINFO_ID, 0
devInfoVersion: .db DEVICEINFO_VERSION, DEVICEINFO_REVISION ; version, revision
firmwareVersion: .db FIRMWARE_VARIANT_TEMP_WINDOW, FIRMWARE_VERSION_MAJOR
.db FIRMWARE_VERSION_MINOR, FIRMWARE_VERSION_PATCHLEVEL
; ---------------------------------------------------------------------------
; @routine firmwareStart @global
firmwareStart:
rjmp main
; @end
; ---------------------------------------------------------------------------
; @routine onSystemStart
onSystemStart:
ret
; @end
; ---------------------------------------------------------------------------
; @routine onMessageReceived
;
; Called on every message received
onMessageReceived:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine onEvery100ms
;
; Called every 100ms. Add your routine calls here. No arguments, no results.
onEvery100ms:
onEverySecond:
onEveryMinute:
onEveryHour:
onEveryDay:
ret
; @end
; ---------------------------------------------------------------------------
; @routine onEveryLoop
;
; Called on every loop (i.e. after awakening from sleep).
;
onEveryLoop:
ret
; @end
; ***************************************************************************
; includes
.include "devices/all/hw_m8515.asm"
.include "devices/all/includes.asm"
.include "common/debug.asm"
; ---------------------------------------------------------------------------
; defines for network interface
.equ netInterfaceData = netUartIface

View File

@@ -5,6 +5,7 @@ N21
- Role: Door sensor with temp and motion detection
- MCU: AtTiny84
- Connection: RJ45
- Predecessor: N16
- Periphery:
- PIR sensor (AMN31112)
- door sensor (TCRT1000)

View File

@@ -97,6 +97,8 @@
;.equ VALUE_ID_REED_CONF = 0x81
.equ VALUE_ID_LEDSIMPLE_TIMING = 0x88
; ***************************************************************************

View File

@@ -27,8 +27,6 @@
; generic
.include "common/utils_wait.asm"
.include "modules/com2/defs.asm"
.include "modules/comproto/defs.asm"

View File

@@ -25,8 +25,6 @@
; generic
.include "common/utils_wait.asm"
.include "modules/com2/defs.asm"
.include "modules/comproto/defs.asm"
@@ -131,6 +129,7 @@ main:
.include "modules/flash/eeprom.asm"
.include "modules/flash/io.asm"
.include "modules/flash/io_uart1.asm"
.include "modules/flash/io_uart_all.asm"
.include "modules/flash/flashxp.asm"
.include "modules/flash/flash4p.asm"
.include "modules/flash/flashprocess.asm"

View File

@@ -77,4 +77,9 @@
.equ OWI_PINNUM = PORTA7
; ---------------------------------------------------------------------------
; ComOnUart module
.equ USART0_DATAREG = UDR0
.equ USART1_DATAREG = UDR1

View File

@@ -32,6 +32,9 @@
.include "../defs.asm"
.include "defs_all.asm"
.include "common/utils_wait.asm"
.include "common/utils_io.asm"
; ***************************************************************************
@@ -41,9 +44,6 @@
; generic
.include "common/utils_wait.asm"
; ---------------------------------------------------------------------------
; firmware settings including list of modules used

View File

@@ -35,6 +35,8 @@
bootloader
f_keepup
valsched
xram
heap
</subdirs>
</gwbuild>

View File

@@ -51,55 +51,7 @@ BaseTimer_Init: ; setup timer for IRQ every 100ms
ldi r17, (baseTimerModuleData_end-baseTimerModuleData)
rcall Utils_FillSram
ldi r16, (1<<CS02) | (0<<CS01) | (1<<CS00) ; Prescaler 1024
out TCCR0B, r16
ldi r16, (1<<WGM01) | (0<<WGM00) ; CTC mode
out TCCR0A, r16
;
; Settings for clock 1Mhz (default)
; use timer0 with OCR0A=98-1 (irq every 97.65625 millisecs), baseTimerModuleReloadValue 1
;
.if clock == 1000000
; CMP-A interrupt about every 100ms
ldi r16, 98-1 ; (1,000,000/1024)/10 = 97.65625
out OCR0A, r16
ldi r16, 1
sts baseTimerModuleReloadValue, r16
sts baseTimerModuleTickCounter, r16
.endif
;
; Settings for clock 8Mhz
; use timer0 with OCR0A=78 (irq every 9.984 millisecs), baseTimerModuleReloadValue 10
;
.if clock == 8000000
; CMP-A interrupt about every 10ms
ldi r16, 78-1
out OCR0A, r16
ldi r16, 10
sts baseTimerModuleReloadValue, r16
sts baseTimerModuleTickCounter, r16
.endif
ldi r16, (1<<OCF0A) ; clear pending interrupts
.ifdef TIFR0
out TIFR0, r16
.else
out TIFR, r16
.endif
ldi r16, (1<<OCIE0A) ; Timer/Counter0 Output Compare Match A Interrupt Enable
.ifdef TIMSK0
out TIMSK0, r16
.else
out TIMSK, r16
.endif
rcall systemSetupTimer0
sec
ret
; @end

View File

@@ -66,13 +66,13 @@ bootLoader:
brcc bootLoader_waitAndRestartBootLoader
; try to start firmware
bootLoader_startFirmware:
ldi r19, 20 ; loop count
ldi r19, 10 ; loop count
ldi r20, 4 ; on time
ldi r21, 1 ; off time
rcall bootLoaderBlinkLed
rjmp firmwareStart
bootLoader_waitAndRestartBootLoader:
ldi r19, 15 ; loop count
ldi r19, 5 ; loop count
ldi r20, 1 ; on time
ldi r21, 8 ; off time
rcall bootLoaderBlinkLed

View File

@@ -12,7 +12,9 @@
io.asm
io_attn.asm
io_bitbang.asm
io_uart.asm
io_uart1.asm
io_uart_all.asm
wait.asm
</extradist>

View File

@@ -21,7 +21,11 @@
; REGS: R16
flashReadEepromIncr:
.ifdef EEPE
sbic EECR, EEPE ; wait for previous write to complete (if any)
.else
sbic EECR, EEWE ; wait for previous write to complete (if any)
.endif
rjmp flashReadEepromIncr
out EEARH, xh ; set EEPROM address
out EEARL, xl

View File

@@ -56,6 +56,17 @@ flash1pWritePages_loop:
; transfer data from temporary page buffer into FLASH memory
ldi r20, (1<<PGWRT) + (1<<SPMEN) ; enable next SPM, write page (R1/R0 ignored)
rcall flashDoSpm ; (R16)
#if 0
.ifdef RWWSRE
flash1pWritePages_endLoop:
in r20, SPMCR
sbrc r20, RWWSB
rjmp flash1pWritePages_endLoop
ldi r20, (1<<RWWSRE) | (1<<SPMEN) ; reenable RWW
rcall flashDoSpm ; (R16)
.endif
#endif
ret
; @end

View File

@@ -0,0 +1,81 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
.equ FLASH_PAGESIZE = (PAGESIZE*2)
; ***************************************************************************
; data
.dseg
flashPageStart: .byte 2
flashPageBuffer: .byte FLASH_PAGESIZE
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; flash1pMegaWritePage
;
; Interrupts must be disabled!
;
; @clobbers r0, r1, r20, r24, r25, X, Z
flash1pMegaWritePage:
lds zl, flashPageStart
lds zh, flashPageStart+1
; copy from SDRAM into MCUs temporary page buffer
ldi xl, LOW(flashPageBuffer)
ldi xh, HIGH(flashPageBuffer)
ldi r24, LOW(PAGESIZE)
flash1pMegaWritePages_loop:
ld r0, X+ ; read source data from buffer (low)
ld r1, X+ ; read source data from buffer (high)
ldi r20, (1<<SPMEN) ; enable next SPM, write R1:R0 into temp page buffer
rcall flashDoSpm ; (R16)
adiw zh:zl, 2
dec r24
brne flash1pMegaWritePages_loop
subi zl, LOW(PAGESIZE*2) ; point back to begin of page
sbci zh, HIGH(PAGESIZE*2)
; transfer data from temporary page buffer into FLASH memory
ldi r20, (1<<PGWRT) + (1<<SPMEN) ; enable next SPM, write page (R1/R0 ignored)
rcall flashDoSpm ; (R16)
rcall flash1pMegaEnableRWW
;flash1pMegaWritePages_endLoop:
; in r20, SPMCR
; sbrc r20, RWWSB
; rjmp flash1pMegaWritePages_endLoop
; ldi r20, (1<<RWWSRE) | (1<<SPMEN) ; reenable RWW
; rcall flashDoSpm ; (R16)
ret
; @end
flash1pMegaEnableRWW:
ldi r20, (1<<RWWSRE) | (1<<SPMEN) ; reenable RWW
rcall flashDoSpm ; (R16)
ret
.equ flashWritePage = flash1pMegaWritePage

View File

@@ -117,6 +117,7 @@ flashProcessHandleFlashStart:
rcall flashWaitFor100ms ; TODO: Shorten wait time!!
clr r16
rcall flashProcessSendFlashResponse ; (R15, R16, R17, R18, R19, R20, R21, R22, X)
sec
flashProcessHandleFlashStart_notMe:
ret
@@ -276,7 +277,7 @@ flashProcessWriteFlashReady:
st X+, r16 ; msg len
ldi r16, NETMSG_CMD_FLASH_READY
st X+, r16 ; msg code
ldi r16, COM2_MAINTENANCE_ADDR
ldi r16, NET_MAINTENANCE_ADDR
st X+, r16 ; src address
; payload

View File

@@ -292,11 +292,19 @@ flashErasePage:
flashDoSpm:
flashDoSpm_wait: ; wait for possibly previous SPM to complete
.ifdef SPMCSR
in r16, SPMCSR
.else
in r16, SPMCR
.endif
sbrc r16, SPMEN
rjmp flashDoSpm_wait
; SPM timed sequence
.ifdef SPMCSR
out SPMCSR, r20
.else
out SPMCR, r20
.endif
spm
ret
; @end

View File

@@ -35,12 +35,12 @@ ioWaitForGivenMsg_loop:
brcc ioWaitForGivenMsg_loopEnd
ldi xl, LOW(flashRecvBuffer)
ldi xh, HIGH(flashRecvBuffer)
adiw xh:xl, COM2_MSG_OFFS_CMD
adiw xh:xl, NETMSG_OFFS_CMD
ld r16, X
sbiw xh:xl, COM2_MSG_OFFS_CMD
sbiw xh:xl, NETMSG_OFFS_CMD
cp r16, r17
breq ioWaitForGivenMsg_gotIt
cpi r16, CPRO_CMD_FLASH_END
cpi r16, NETMSG_CMD_FLASH_END
breq ioWaitForGivenMsg_gotIt
ioWaitForGivenMsg_loopEnd:
mov r16, r17 ; move expected code back to r16

View File

@@ -94,4 +94,45 @@ ioWaitForAttnState1ms_stateReached:
; ---------------------------------------------------------------------------
; @routine ioRawWaitForOneBitLength
;
; wait for one bit length (minus cycles for call and ret).
;
; @clobbers r22
ioRawWaitForOneBitLength:
Utils_WaitNanoSecs COM_BIT_LENGTH, 7, r22 ; wait for one bit duration (minus RCALL/RET)
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawAcquireBus
;
; Reserve bus if free (otherwise return error)
; Expects interrupts to be disabled.
;
; @return CFLAG set if okay (bus acquired), cleared on error
; @clobbers: none
ioRawAcquireBus:
; check for ATTN line: busy?
cbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN as input
cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; disable pullup on ATTN
nop ; needed to sample current input
sbis COM_ATTN_INPUT, COM_ATTN_PIN ; ATTN low?
rjmp ioRawAcquireBus_busy ; jump if it is
sbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN as output
cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; set ATTN low
sec
ret
ioRawAcquireBus_busy:
clc
ret
; @end

View File

@@ -140,7 +140,7 @@ ioRawWaitForValidMsg:
ioRawWaitForValidMsg_attnLow:
ldi xl, LOW(flashRecvBuffer)
ldi xh, HIGH(flashRecvBuffer)
ldi r16, COM2_MAINTENANCE_ADDR
ldi r16, NET_MAINTENANCE_ADDR
ldi r17, FLASH_RECVBUFFER_MAXLEN-3
rcall ioRawReceivePacketIntoBuffer
brcs ioRawWaitForValidMsg_packetReceived
@@ -174,7 +174,6 @@ ioRawWaitForValidMsg_end:
; @param R17 maximum value for accepted msg data (i.e. buffersize minus 3)
; @param X buffer to receive to
; @return CFLAG set if okay (packet received), cleared on error
; @return R16 error code if CFLAG is cleared (COM2_ERROR_NOTFORME, COM2_ERROR_IOERROR, COM2_ERROR_DATAERROR)
; @clobbers: r16, r17, r18, X (r19, r20, r21, r22)
ioRawReceivePacketIntoBuffer:
@@ -183,7 +182,7 @@ ioRawReceivePacketIntoBuffer:
; read destination address
rcall ioRawReceiveByte ; read byte (R16, R17, R20, R21, R22)
pop r17 ; pop from R16 to R17
brcc ioRawReceivePacketIntoBuffer_ioError
brcc ioRawReceivePacketIntoBuffer_error
#ifndef COM_ACCEPT_ALL_DEST ; accept every destination address
; compare destination address (accept "FF" and own address)
cp r16, r17
@@ -197,27 +196,22 @@ ioRawReceivePacketIntoBuffer_acceptAddr:
st X+, r16 ; store dest address, lock buffer
; read msg length
rcall ioRawReceiveByte ; read packet length (R16, R17, R20, R21, R22)
brcc ioRawReceivePacketIntoBuffer_ioError
brcc ioRawReceivePacketIntoBuffer_error
st X+, r16
cp r16, r18 ; (COM2_BUFFER_SIZE-3)
brcc ioRawReceivePacketIntoBuffer_contentError ; packet too long
brcc ioRawReceivePacketIntoBuffer_error ; packet too long
inc r16 ; account for checksum byte
mov r17, r16
ioRawReceivePacketIntoBuffer_loop:
push r17
rcall ioRawReceiveByte ; read byte (R16, R17, R20, R21, R22)
pop r17
brcc ioRawReceivePacketIntoBuffer_ioError
brcc ioRawReceivePacketIntoBuffer_error
st X+, r16
dec r17
brne ioRawReceivePacketIntoBuffer_loop
sec
ret
ioRawReceivePacketIntoBuffer_ioError:
ldi r16, COM2_ERROR_IOERROR
rjmp ioRawReceivePacketIntoBuffer_error
ioRawReceivePacketIntoBuffer_contentError:
ldi r16, COM2_ERROR_DATAERROR
ioRawReceivePacketIntoBuffer_error:
clc
ret
@@ -281,77 +275,29 @@ ioRawReceiveByte_error:
; @clobbers R16, R22 (R17, R21, X)
ioRawSendPacket:
rcall ioRawAcquireBus
brcc ioRawSendPacket_lineBusyError
rcall ioRawAcquireBus ; (none)
brcc ioRawSendPacket_ret
rcall ioRawWaitForOneBitLength ; wait for one bit duration (R22)
rcall ioRawWaitForOneBitLength ; wait for one bit duration (R22)
rcall ioRawWaitForOneBitLength ; wait for one bit duration (R22)
rcall ioRawWaitForOneBitLength ; wait for one bit duration (R22)
adiw xh:xl, COM2_MSG_OFFS_MSGLEN
adiw xh:xl, NETMSG_OFFS_MSGLEN
ld r17, X
sbiw xh:xl, COM2_MSG_OFFS_MSGLEN
inc r17 ; account for dest addr
inc r17 ; account for msglen byte
inc r17 ; account for crc byte
sbiw xh:xl, NETMSG_OFFS_MSGLEN
inc r17 ; account for dest addr
inc r17 ; account for msglen byte
inc r17 ; account for crc byte
ioRawSendPacket_loop:
ld r16, X+
rcall ioRawSendByte ; send byte (R16, R21, R22)
rcall ioRawSendByte ; send byte (R16, R21, R22)
brcc ioRawSendPacket_releaseBusRet
dec r17
brne ioRawSendPacket_loop
sec
ioRawSendPacket_releaseBusRet:
cbi COM_ATTN_DDR, COM_ATTN_PIN ; release ATTN line (by setting direction to IN)
brcc ioRawSendPacket_ioError
; packet successfully sent
ret
ioRawSendPacket_ioError:
ldi r16,COM2_ERROR_COLLISION
ret
ioRawSendPacket_lineBusyError:
ldi r16,COM2_ERROR_BUSY
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawAcquireBus
;
; Reserve bus if free (otherwise return error)
; Expects interrupts to be disabled.
;
; @return CFLAG set if okay (bus acquired), cleared on error
; @clobbers: none
ioRawAcquireBus:
; check for ATTN line: busy?
cbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN as input
cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; disable pullup on ATTN
nop ; needed to sample current input
sbis COM_ATTN_INPUT, COM_ATTN_PIN ; ATTN low?
rjmp ioRawAcquireBus_busy ; jump if it is
sbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN as output
cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; set ATTN low
sec
ret
ioRawAcquireBus_busy:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForOneBitLength
;
; wait for one bit length (minus cycles for call and ret).
;
; @clobbers r22
ioRawWaitForOneBitLength:
Utils_WaitNanoSecs COM_BIT_LENGTH, 7, r22 ; wait for one bit duration (minus RCALL/RET)
cbi COM_ATTN_DDR, COM_ATTN_PIN ; release ATTN line (by setting direction to IN)
ioRawSendPacket_ret:
ret
; @end

View File

@@ -0,0 +1,33 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
.equ UART_REG_UDR = UDR
.equ UART_REG_UCSRA = UCSRA
.equ UART_REG_UCSRB = UCSRB
.equ UART_REG_UCSRC = UCSRC
.equ UART_REG_UBRRL = UBRRL
.equ UART_REG_UBRRH = UBRRH
.equ UART_BIT_USBS = USBS
.equ UART_BIT_UCSZ0 = UCSZ0
.equ UART_BIT_UCSZ1 = UCSZ1
.equ UART_BIT_UDRE = UDRE
.equ UART_BIT_RXC = RXC
.equ UART_BIT_TXC = TXC
.equ UART_BIT_FE = FE
.equ UART_BIT_DOR = DOR
.equ UART_BIT_UPE = UPE
.equ UART_BIT_RXEN = RXEN
.equ UART_BIT_TXEN = TXEN

View File

@@ -8,377 +8,23 @@
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine ioRawInit
; Send a message
;
; @clobbers r16, r17
ioRawInit:
; set baudrate
.if clock == 8000000
ldi r16, 25 ; (19.2Kb/s at 8MHz)
ldi r17, 0
.endif
.if clock == 1000000
ldi r16, 3 ; (19.2Kb/s at 1MHz)
ldi r17, 0
.endif
sts UBRR1H, r17
sts UBRR1L, r16
; set character format (asynchronous USART, 8-bit, one stop bit, no parity)
ldi r16, (3<<UCSZ10)
sts UCSR1C, r16
; enable transceiver
lds r16, UCSR1B
; cbr r16, (1<<UDRIE1) ; disable DRE interrupt
ori r16, (1<<RXEN1) | (1<<TXEN1) ; enable transmit and receive
sts UCSR1B, r16
.ifdef COM_ATTN_PUE
lds r16, COM_ATTN_PUE
cbr r16, COM_ATTN_PIN ; disable pullup on ATTN
sts COM_ATTN_PUE, r16
.endif
ret
;@end
; ---------------------------------------------------------------------------
; @routine ioRawSendMsg
; Send a message
;
; @clobbers r16, r17, X
ioRawSendMsg:
ldi xl, LOW(flashSendBuffer)
ldi xh, HIGH(flashSendBuffer)
rjmp ioRawSendPacket ; (r16, r17, X)
; @end
; ---------------------------------------------------------------------------
; @routine UART_HW_Uart1_RawSendPacket
; Send packet.
;
; @param X buffer to send
; @return CFLAG: set if okay (packet sent), cleared on error
; @clobbers r16, r17, X
ioRawSendPacket:
adiw xh:xl, 1
ld r17, X
sbiw xh:xl, 1
ldi r16, 3 ; add DEST, LEN, CRC bytes
add r17, r16
ioRawSendPacket_loop:
lds r16, UCSR1A
sbrs r16, UDRE1
rjmp ioRawSendPacket_loop
sbr r16, (1<<TXC1)
sts UCSR1A, r16
ld r16, X+
sts UDR1, r16
dec r17
brne ioRawSendPacket_loop
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForValidMsg
; Wait for valid incoming msg
;
; @return CFLAG set if okay (packet received), cleared on error
; @clobbers: r16, r17, r18 (r19, r22, X)
ioRawWaitForValidMsg:
ldi xl, LOW(flashRecvBuffer)
ldi xh, HIGH(flashRecvBuffer)
ldi r18, FLASH_RECVBUFFER_MAXLEN-3 ; maximum accepted msglen byte
ldi r20, 10 ; 10 secs
rjmp ioRecvMsg
; @end
; ---------------------------------------------------------------------------
; @routine ioRecvMsg
;
; Wait for next message, if received check validity.
; On error skip the currently received message.
;
; @return CFLAG set if okay, cleared on error
; @param r18 max accepted msglen size (buffersize-3)
; @param R20 max number of secs to wait for incoming message
; @param X buffer to receive to
; @clobbers (r16, r17, r18, r19, r20, r22)
ioRecvMsg:
rcall ioRawRecvMsg ; (r16, r17, r18, r19, r20, r22)
brcc ioRecvMsg_error
push xl
push xh
rcall NETMSG_CheckMessageInBuffer ; (R16, R17, R18, R19, R20, X)
pop xh
pop xl
brcs ioRecvMsg_end
ioRecvMsg_error:
rcall ioRecvSkipMessage ; skip remainder of the message
clc
ioRecvMsg_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRecvSkipMessage
;
; skip all receiption data until a data pause of about 10ms
;
; @clobbers r16
ioRecvSkipMessage:
ioRecvSkipMessage_loop:
rcall ioRecvFlush ; (r16)
; wait for a data pause of 10ms
rcall ioRawRecvByteWithin10ms ; (r20, r22)
brcs ioRecvSkipMessage_loop
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRecvFlush
;
; flush receiption buffer.
;
; @clobbers r16
ioRecvFlush:
lds r16, UCSR1A ; read status
sbrs r16, RXC1
ret
lds r16, UDR1 ; read data byte
rjmp ioRecvFlush
; @end
; ---------------------------------------------------------------------------
; @routine ioRawRecvMsg
;
; @return CFLAG set if okay, cleared on error
; @param r18 max accepted msglen size (buffersize-3)
; @param R20 max number of secs to wait for incoming message
; @param X buffer to receive to
; @clobbers r16, r17, r19 (r18, r20, r22)
ioRawRecvMsg:
lds r19, UCSR1A
cbr r19, (1<<FE1) | (1<<DOR1) | (1<<UPE1)
sts UCSR1A, r19 ; clear errors
; wait for begin of message
rcall ioRawWaitForDataSeconds ; (r20, r22)
brcc ioRawRecvMsg_end
clr r19 ; bytecounter
; read first two bytes
ldi r17, 2 ; 2 bytes: address byte, msg len
add r19, r17
rcall ioRawRecvBytes ; (r16, r17, r18, r22)
brcc ioRawRecvMsg_error
cp r16, r20 ; check size
brcc ioRawRecvMsg_error
inc r16 ; account for checksum byte
; read remaining bytes including checksum byte
mov r17, r16
add r19, r17
rcall ioRawRecvBytes ; (r16, r17, r18, r22)
brcc ioRawRecvMsg_error
sub xl, r19 ; let X point back to begin of message
sbc xh, r19
add xh, r19
sec
ret
ioRawRecvMsg_error:
clc
ioRawRecvMsg_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawRecvBytes
;
; @return CFLAG set if okay (data available), cleared on error
; @return r16 last byte received
; @param r17 number of bytes to read
; @param x buffer to receive to
; @clobbers r16, r17 (r20, r22)
ioRawRecvBytes:
rcall ioRawRecvByteWithin10ms ; (r20, r22)
brcc ioRawRecvBytes_end
st X+, r16
dec r17
brne ioRawRecvBytes
sec
ioRawRecvBytes_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawRecvByteWithin10ms
;
; Wait up to 10ms for incoming byte and read it.
;
; @return CFLAG set if okay (data available), cleared on error
; @return r16 byte received (if CFLAG set)
; @clobbers: r20, r22
ioRawRecvByteWithin10ms:
rcall ioRawWaitForData10ms ; (R20, R22)
brcc ioRawRecvByteWithin10ms_end
lds r16, UCSR1A ; check for errors
andi r16, (1<<FE1) | (1<<DOR1) | (1<<UPE1)
brne ioRawRecvByteWithin10ms_error
lds r16, UDR1 ; read data byte
sec
ret
ioRawRecvByteWithin10ms_error:
clc
ioRawRecvByteWithin10ms_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForDataSeconds
;
; Wait for incoming data for max 1s
;
; @return CFLAG set if okay (data available), cleared on error
; @param r20 maximum number of seconds to wait
; @clobbers: r20, r22
ioRawWaitForDataSeconds:
ioRawWaitForDataSeconds_loop:
push r20
rcall ioRawWaitForData1s ; (r20, r22)
pop r20
brcs ioRawWaitForDataSeconds_gotit
sbi LED_PIN, LED_PINNUM ; toggle
dec r20
brne ioRawWaitForDataSeconds_loop
clc
ioRawWaitForDataSeconds_gotit:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForData1s
;
; Wait for incoming data for max 1s
;
; @return CFLAG set if okay (data available), cleared on error
; @clobbers: r20, r22
ioRawWaitForData1s:
ldi r20, 100
ioRawWaitForData1s_loop:
push r20
rcall ioRawWaitForData10ms ; (R20, R22)
pop r20
brcs ioRawWaitForData1s_gotit
dec r20
brne ioRawWaitForData1s_loop
clc
ioRawWaitForData1s_gotit:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForData10ms
;
; Wait for incoming data for max 10 milliseconds.
;
; @return CFLAG set if okay (data available), cleared on error
; @clobbers: r20, r22
ioRawWaitForData10ms:
.if clock == 8000000
ldi r20, 80
.endif
.if clock == 1000000
ldi r20, 10
.endif
ioRawWaitForData10ms_loop:
push r20
rcall ioRawWaitForData1000Cycles ; (r20, r22)
pop r20
brcs ioRawWaitForData10ms_gotit
dec r20
brne ioRawWaitForData10ms_loop
clc
ioRawWaitForData10ms_gotit:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForData1000Cycles
;
; Wait for incoming data for max 1000 clock cycles
; (about 1ms at 1MHz, 0.125 at 8MHz)
;
; @return CFLAG set if okay (packet received), cleared on error
; @clobbers: r20, r22
ioRawWaitForData1000Cycles:
ldi r20, 140 ; 1
ioRawWaitForData_loop:
lds r22, UCSR1A ; 2
sbrc r22, RXC1 ; 2/3
rjmp ioRawWaitForData_gotit ; 2
dec r20 ; 1
brne ioRawWaitForData_loop ; 1/2 -> 7 per loop, max about 1000
clc ; 1
ret ; 4
ioRawWaitForData_gotit:
sec ; 1
ret ; 4
; @end
.equ UART_REG_UDR = UDR1
.equ UART_REG_UCSRA = UCSR1A
.equ UART_REG_UCSRB = UCSR1B
.equ UART_REG_UCSRC = UCSR1C
.equ UART_REG_UBRRL = UBRR1L
.equ UART_REG_UBRRH = UBRR1H
.equ UART_BIT_UCSZ0 = UCSZ10
.equ UART_BIT_UDRE = UDRE1
.equ UART_BIT_RXC = RXC1
.equ UART_BIT_TXC = TXC1
.equ UART_BIT_FE = FE1
.equ UART_BIT_DOR = DOR1
.equ UART_BIT_UPE = UPE1
.equ UART_BIT_RXEN = RXEN1
.equ UART_BIT_TXEN = TXEN1

View File

@@ -0,0 +1,387 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine ioRawInit
; Send a message
;
; @clobbers r16, r17
ioRawInit:
; set baudrate
.if clock == 8000000
ldi r16, 25 ; (19.2Kb/s at 8MHz)
ldi r17, 0
.endif
.if clock == 1000000
ldi r16, 3 ; (19.2Kb/s at 1MHz)
ldi r17, 0
.endif
sts UART_REG_UBRRH, r17
sts UART_REG_UBRRL, r16
; set character format (asynchronous USART, 8-bit, one stop bit, no parity)
ldi r16, (3<<UART_BIT_UCSZ0)
sts UART_REG_UCSRC, r16
; enable transceiver
lds r16, UART_REG_UCSRB
; cbr r16, (1<<UDRIE1) ; disable DRE interrupt
ori r16, (1<<UART_BIT_RXEN) | (1<<UART_BIT_TXEN) ; enable transmit and receive
sts UART_REG_UCSRB, r16
.ifdef COM_ATTN_PUE
lds r16, COM_ATTN_PUE
cbr r16, COM_ATTN_PIN ; disable pullup on ATTN
sts COM_ATTN_PUE, r16
.else
cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; disable internal pullup for ATTN
.endif
ret
;@end
; ---------------------------------------------------------------------------
; @routine ioRawSendMsg
; Send a message
;
; @clobbers r16, r17, X
ioRawSendMsg:
ldi xl, LOW(flashSendBuffer)
ldi xh, HIGH(flashSendBuffer)
rjmp ioRawSendPacket ; (r16, r17, X)
; @end
; ---------------------------------------------------------------------------
; @routine UART_HW_Uart1_RawSendPacket
; Send packet.
;
; @param X buffer to send
; @return CFLAG: set if okay (packet sent), cleared on error
; @clobbers r16, r17, X
ioRawSendPacket:
adiw xh:xl, 1
ld r17, X
sbiw xh:xl, 1
ldi r16, 3 ; add DEST, LEN, CRC bytes
add r17, r16
ioRawSendPacket_loop:
lds r16, UART_REG_UCSRA
sbrs r16, UART_BIT_UDRE
rjmp ioRawSendPacket_loop
sbr r16, (1<<UART_BIT_TXC)
sts UART_REG_UCSRA, r16
ld r16, X+
sts UART_REG_UDR, r16
dec r17
brne ioRawSendPacket_loop
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForValidMsg
; Wait for valid incoming msg
;
; @return CFLAG set if okay (packet received), cleared on error
; @clobbers: r16, r17, r18 (r19, r22, X)
ioRawWaitForValidMsg:
ldi xl, LOW(flashRecvBuffer)
ldi xh, HIGH(flashRecvBuffer)
ldi r18, FLASH_RECVBUFFER_MAXLEN-3 ; maximum accepted msglen byte
ldi r20, 10 ; 10 secs
rjmp ioRecvMsg
; @end
; ---------------------------------------------------------------------------
; @routine ioRecvMsg
;
; Wait for next message, if received check validity.
; On error skip the currently received message.
;
; @return CFLAG set if okay, cleared on error
; @param r18 max accepted msglen size (buffersize-3)
; @param R20 max number of secs to wait for incoming message
; @param X buffer to receive to
; @clobbers (r16, r17, r18, r19, r20, r22)
ioRecvMsg:
rcall ioRawRecvMsg ; (r16, r17, r18, r19, r20, r22)
brcc ioRecvMsg_error
push xl
push xh
rcall NETMSG_CheckMessageInBuffer ; (R16, R17, R18, R19, R20, X)
pop xh
pop xl
brcs ioRecvMsg_end
ioRecvMsg_error:
rcall ioRecvSkipMessage ; skip remainder of the message
clc
ioRecvMsg_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRecvSkipMessage
;
; skip all receiption data until a data pause of about 10ms
;
; @clobbers r16
ioRecvSkipMessage:
ioRecvSkipMessage_loop:
rcall ioRecvFlush ; (r16)
; wait for a data pause of 10ms
rcall ioRawRecvByteWithin10ms ; (r20, r22)
brcs ioRecvSkipMessage_loop
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRecvFlush
;
; flush receiption buffer.
;
; @clobbers r16
ioRecvFlush:
lds r16, UART_REG_UCSRA ; read status
sbrs r16, UART_BIT_RXC
ret
lds r16, UART_REG_UDR ; read data byte
rjmp ioRecvFlush
; @end
; ---------------------------------------------------------------------------
; @routine ioRawRecvMsg
;
; @return CFLAG set if okay, cleared on error
; @param r18 max accepted msglen size (buffersize-3)
; @param R20 max number of secs to wait for incoming message
; @param X buffer to receive to
; @clobbers r16, r17, r19 (r18, r20, r22)
ioRawRecvMsg:
lds r19, UART_REG_UCSRA
cbr r19, (1<<UART_BIT_FE) | (1<<UART_BIT_DOR) | (1<<UART_BIT_UPE)
sts UART_REG_UCSRA, r19 ; clear errors
; wait for begin of message
rcall ioRawWaitForDataSeconds ; (r20, r22)
brcc ioRawRecvMsg_end
clr r19 ; bytecounter
; read first two bytes
ldi r17, 2 ; 2 bytes: address byte, msg len
add r19, r17
rcall ioRawRecvBytes ; (r16, r17, r18, r22)
brcc ioRawRecvMsg_error
cp r16, r20 ; check size
brcc ioRawRecvMsg_error
inc r16 ; account for checksum byte
; read remaining bytes including checksum byte
mov r17, r16
add r19, r17
rcall ioRawRecvBytes ; (r16, r17, r18, r22)
brcc ioRawRecvMsg_error
sub xl, r19 ; let X point back to begin of message
sbc xh, r19
add xh, r19
sec
ret
ioRawRecvMsg_error:
clc
ioRawRecvMsg_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawRecvBytes
;
; @return CFLAG set if okay (data available), cleared on error
; @return r16 last byte received
; @param r17 number of bytes to read
; @param x buffer to receive to
; @clobbers r16, r17 (r20, r22)
ioRawRecvBytes:
rcall ioRawRecvByteWithin10ms ; (r20, r22)
brcc ioRawRecvBytes_end
st X+, r16
dec r17
brne ioRawRecvBytes
sec
ioRawRecvBytes_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawRecvByteWithin10ms
;
; Wait up to 10ms for incoming byte and read it.
;
; @return CFLAG set if okay (data available), cleared on error
; @return r16 byte received (if CFLAG set)
; @clobbers: r20, r22
ioRawRecvByteWithin10ms:
rcall ioRawWaitForData10ms ; (R20, R22)
brcc ioRawRecvByteWithin10ms_end
lds r16, UART_REG_UCSRA ; check for errors
andi r16, (1<<UART_BIT_FE) | (1<<UART_BIT_DOR) | (1<<UART_BIT_UPE)
brne ioRawRecvByteWithin10ms_error
lds r16, UART_REG_UDR ; read data byte
sec
ret
ioRawRecvByteWithin10ms_error:
clc
ioRawRecvByteWithin10ms_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForDataSeconds
;
; Wait for incoming data for max 1s
;
; @return CFLAG set if okay (data available), cleared on error
; @param r20 maximum number of seconds to wait
; @clobbers: r20, r22
ioRawWaitForDataSeconds:
ioRawWaitForDataSeconds_loop:
push r20
rcall ioRawWaitForData1s ; (r20, r22)
pop r20
brcs ioRawWaitForDataSeconds_gotit
sbi LED_PIN, LED_PINNUM ; toggle
dec r20
brne ioRawWaitForDataSeconds_loop
clc
ioRawWaitForDataSeconds_gotit:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForData1s
;
; Wait for incoming data for max 1s
;
; @return CFLAG set if okay (data available), cleared on error
; @clobbers: r20, r22
ioRawWaitForData1s:
ldi r20, 100
ioRawWaitForData1s_loop:
push r20
rcall ioRawWaitForData10ms ; (R20, R22)
pop r20
brcs ioRawWaitForData1s_gotit
dec r20
brne ioRawWaitForData1s_loop
clc
ioRawWaitForData1s_gotit:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForData10ms
;
; Wait for incoming data for max 10 milliseconds.
;
; @return CFLAG set if okay (data available), cleared on error
; @clobbers: r20, r22
ioRawWaitForData10ms:
.if clock == 8000000
ldi r20, 80
.endif
.if clock == 1000000
ldi r20, 10
.endif
ioRawWaitForData10ms_loop:
push r20
rcall ioRawWaitForData1000Cycles ; (r20, r22)
pop r20
brcs ioRawWaitForData10ms_gotit
dec r20
brne ioRawWaitForData10ms_loop
clc
ioRawWaitForData10ms_gotit:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForData1000Cycles
;
; Wait for incoming data for max 1000 clock cycles
; (about 1ms at 1MHz, 0.125 at 8MHz)
;
; @return CFLAG set if okay (packet received), cleared on error
; @clobbers: r20, r22
ioRawWaitForData1000Cycles:
ldi r20, 140 ; 1
ioRawWaitForData_loop:
lds r22, UART_REG_UCSRA ; 2
sbrc r22, UART_BIT_RXC ; 2/3
rjmp ioRawWaitForData_gotit ; 2
dec r20 ; 1
brne ioRawWaitForData_loop ; 1/2 -> 7 per loop, max about 1000
clc ; 1
ret ; 4
ioRawWaitForData_gotit:
sec ; 1
ret ; 4
; @end

View File

@@ -0,0 +1,500 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine ioRawInit
; Send a message
;
; @clobbers r16, r17
ioRawInit:
; set baudrate
.if clock == 8000000
ldi r16, 25 ; (19.2Kb/s at 8MHz)
ldi r17, 0
.endif
.if clock == 1000000
ldi r16, 3 ; (19.2Kb/s at 1MHz)
ldi r17, 0
.endif
M_IO_WRITE UART_REG_UBRRH, r17
M_IO_WRITE UART_REG_UBRRL, r16
; set character format (asynchronous USART, 8-bit, one stop bit, no parity)
.ifdef URSEL
ldi r16, (1<<URSEL) | (1<<UART_BIT_USBS) | (3<<UART_BIT_UCSZ0)
.else
ldi r16, (1<<UART_BIT_USBS)|(3<<UART_BIT_UCSZ0)
.endif
; ldi r16, (1<<UART_BIT_UCSZ0) | (1<<UART_BIT_UCSZ1)
M_IO_WRITE UART_REG_UCSRC, r16
cbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN port as input
.ifdef COM_ATTN_PUE
lds r16, COM_ATTN_PUE
cbr r16, COM_ATTN_PIN ; disable pullup on ATTN
sts COM_ATTN_PUE, r16
.else
cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; disable internal pullup for ATTN
.endif
ret
;@end
; ---------------------------------------------------------------------------
; @routine ioRawSendMsg
; Send a message
;
; @clobbers r16, r17, X
ioRawSendMsg:
ldi xl, LOW(flashSendBuffer)
ldi xh, HIGH(flashSendBuffer)
rcall ioRawSendMsgWithAttn
brcc ioRawSendMsg
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawSendMsgWithAttn
;
; @param X buffer to send
; @return CFLAG: set if okay (packet sent), cleared on error
; @clobbers r16, r17 (X)
ioRawSendMsgWithAttn:
ioRawSendMsgWithAttn_loop:
ldi r16, 0xff ; expect ATTN high
ldi r17, 10
rcall ioWaitForAttnState100ms ; wait for up to 1s
brcs ioRawSendMsgWithAttn_attnHigh
ret
ioRawSendMsgWithAttn_attnHigh:
rcall ioRawAcquireBus ; (none)
brcc ioRawSendMsgWithAttn_loop
rcall ioRawWaitForOneBitLength ; wait for one bit duration (R22)
rcall ioRawWaitForOneBitLength ; wait for one bit duration (R22)
rcall ioRawSendMsgHandleTransceiver ; (r16, r17, X)
cbi COM_ATTN_DDR, COM_ATTN_PIN ; release ATTN line (by setting direction to IN)
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawSendMsgHandleTransceiver
; Enable transceiver, send packet, disable transceiver.
;
; @param X buffer to send
; @return CFLAG: set if okay (packet sent), cleared on error
; @clobbers r16 (r17, X)
ioRawSendMsgHandleTransceiver:
; enable transceiver
M_IO_READ r16, UART_REG_UCSRB
sbr r16,(1<<UART_BIT_TXEN) ; enable transmit
M_IO_WRITE UART_REG_UCSRB, r16
rcall ioRawSendMsgDirect
; disable transceiver
M_IO_READ r16, UART_REG_UCSRB
cbr r16,(1<<UART_BIT_TXEN) ; disable transmit
M_IO_WRITE UART_REG_UCSRB, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawSendMsgDirect
; Send packet.
;
; @param X buffer to send
; @return CFLAG: set if okay (packet sent), cleared on error
; @clobbers r16, r17, X
ioRawSendMsgDirect:
adiw xh:xl, 1
ld r17, X ; read msg size
sbiw xh:xl, 1
ldi r16, 3 ; add DEST, LEN, CRC bytes
add r17, r16
ioRawSendMsgDirect_loop:
; wait until transceiver ready
M_IO_READ r16, UART_REG_UCSRA
sbrs r16, UART_BIT_UDRE
rjmp ioRawSendMsgDirect_loop
; clear TXC flag by sending a 1
sbr r16, (1<<UART_BIT_TXC)
M_IO_WRITE UART_REG_UCSRA, r16
; write byte to uart data register
ld r16, X+
M_IO_WRITE UART_REG_UDR, r16
dec r17
brne ioRawSendMsgDirect_loop
; wait until all data send (i.e. send buffer empty and all bits shifted out)
ioRawSendMsgDirect_loopComplete:
M_IO_READ r16, UART_REG_UCSRA
sbrs r16, UART_BIT_TXC
rjmp ioRawSendMsgDirect_loopComplete
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForValidMsg
; Wait for valid incoming msg
;
; @return CFLAG set if okay (packet received), cleared on error
; @clobbers: r16, r17, r18 (r19, r22, X)
ioRawWaitForValidMsg:
ldi r16, 0xff ; expect ATTN high
ldi r17, 100
rcall ioWaitForAttnState100ms ; wait for up to 10s
brcc ioRawWaitForValidMsg_end ; ATTN not high, exit
ldi r16, 0 ; expect ATTN low
ldi r17, 100
rcall ioWaitForAttnState100ms ; wait for up to 10s
brcs ioRawWaitForValidMsg_attnLow
ret
ioRawWaitForValidMsg_attnLow:
ldi xl, LOW(flashRecvBuffer)
ldi xh, HIGH(flashRecvBuffer)
ldi r18, FLASH_RECVBUFFER_MAXLEN-3 ; maximum accepted msglen byte
ldi r20, 10 ; 10 secs
rcall ioRecvMsgHandleReceiver ; (r16, r17, r18, r19, r20, r22)
brcs ioRawWaitForValidMsg_packetReceived
; wait until ATTN is high (up to 10s)
ldi r16, 0xff ; expect ATTN high
ldi r17, 100
rcall ioWaitForAttnState100ms ; wait for up to 10s
clc
ret
ioRawWaitForValidMsg_packetReceived:
ldi r16, 0xff ; expect ATTN high
ldi r17, 100
rcall ioWaitForAttnState100ms ; wait for up to 10s
brcc ioRawWaitForValidMsg_end
ldi xl, LOW(flashRecvBuffer)
ldi xh, HIGH(flashRecvBuffer)
rcall NETMSG_CheckMessageInBuffer
ioRawWaitForValidMsg_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRecvMsgHandleReceiver
;
; Turn receiver on, receive message, turn receiver off.
; @return CFLAG set if okay, cleared on error
; @param r18 max accepted msglen size (buffersize-3)
; @param R20 max number of secs to wait for incoming message
; @param X buffer to receive to
; @clobbers r16 (r17, r18, r19, r20, r22)
ioRecvMsgHandleReceiver:
; enable receiver
M_IO_READ r16, UART_REG_UCSRB
sbr r16,(1<<UART_BIT_RXEN) ; enable receive
M_IO_WRITE UART_REG_UCSRB, r16
rcall ioRecvMsg
M_IO_READ r16, UART_REG_UCSRB
cbr r16,(1<<UART_BIT_RXEN) ; disable receive
M_IO_WRITE UART_REG_UCSRB, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRecvMsg
;
; Wait for next message, if received check validity.
; On error skip the currently received message.
;
; @return CFLAG set if okay, cleared on error
; @param r18 max accepted msglen size (buffersize-3)
; @param R20 max number of secs to wait for incoming message
; @param X buffer to receive to
; @clobbers (r16, r17, r18, r19, r20, r22)
ioRecvMsg:
rcall ioRawRecvMsg ; (r16, r17, r18, r19, r20, r22)
brcc ioRecvMsg_error
push xl
push xh
rcall NETMSG_CheckMessageInBuffer ; (R16, R17, R18, R19, R20, X)
pop xh
pop xl
brcs ioRecvMsg_end
ioRecvMsg_error:
rcall ioRecvSkipMessage ; skip remainder of the message
clc
ioRecvMsg_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRecvSkipMessage
;
; skip all receiption data until a data pause of about 10ms
;
; @clobbers r16
ioRecvSkipMessage:
ioRecvSkipMessage_loop:
rcall ioRecvFlush ; (r16)
; wait for a data pause of 10ms
rcall ioRawRecvByteWithin10ms ; (r20, r22)
brcs ioRecvSkipMessage_loop
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRecvFlush
;
; flush receiption buffer.
;
; @clobbers r16
ioRecvFlush:
M_IO_READ r16, UART_REG_UCSRA ; read status
sbrs r16, UART_BIT_RXC
ret
M_IO_READ r16, UART_REG_UDR ; read data byte
rjmp ioRecvFlush
; @end
; ---------------------------------------------------------------------------
; @routine ioRawRecvMsg
;
; @return CFLAG set if okay, cleared on error
; @param r18 max accepted msglen size (buffersize-3)
; @param R20 max number of secs to wait for incoming message
; @param X buffer to receive to
; @clobbers r16, r17, r19 (r18, r20, r22)
ioRawRecvMsg:
M_IO_READ r19, UART_REG_UCSRA
cbr r19, (1<<UART_BIT_FE) | (1<<UART_BIT_DOR) | (1<<UART_BIT_UPE)
M_IO_WRITE UART_REG_UCSRA, r19 ; clear errors
; wait for begin of message
rcall ioRawWaitForDataSeconds ; (r20, r22)
brcc ioRawRecvMsg_end
clr r19 ; bytecounter
; read first two bytes
ldi r17, 2 ; 2 bytes: address byte, msg len
add r19, r17
rcall ioRawRecvBytes ; (r16, r17, r18, r22)
brcc ioRawRecvMsg_error
cp r16, r20 ; check size
brcc ioRawRecvMsg_error
inc r16 ; account for checksum byte
; read remaining bytes including checksum byte
mov r17, r16
add r19, r17
rcall ioRawRecvBytes ; (r16, r17, r18, r22)
brcc ioRawRecvMsg_error
sub xl, r19 ; let X point back to begin of message
sbc xh, r19
add xh, r19
sec
ret
ioRawRecvMsg_error:
clc
ioRawRecvMsg_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawRecvBytes
;
; @return CFLAG set if okay (data available), cleared on error
; @return r16 last byte received
; @param r17 number of bytes to read
; @param x buffer to receive to
; @clobbers r16, r17 (r20, r22)
ioRawRecvBytes:
rcall ioRawRecvByteWithin10ms ; (r20, r22)
brcc ioRawRecvBytes_end
st X+, r16
dec r17
brne ioRawRecvBytes
sec
ioRawRecvBytes_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawRecvByteWithin10ms
;
; Wait up to 10ms for incoming byte and read it.
;
; @return CFLAG set if okay (data available), cleared on error
; @return r16 byte received (if CFLAG set)
; @clobbers: r20, r22
ioRawRecvByteWithin10ms:
rcall ioRawWaitForData10ms ; (R20, R22)
brcc ioRawRecvByteWithin10ms_end
M_IO_READ r16, UART_REG_UCSRA ; check for errors
andi r16, (1<<UART_BIT_FE) | (1<<UART_BIT_DOR) | (1<<UART_BIT_UPE)
brne ioRawRecvByteWithin10ms_error
M_IO_READ r16, UART_REG_UDR ; read data byte
sec
ret
ioRawRecvByteWithin10ms_error:
clc
ioRawRecvByteWithin10ms_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForDataSeconds
;
; Wait for incoming data for max 1s
;
; @return CFLAG set if okay (data available), cleared on error
; @param r20 maximum number of seconds to wait
; @clobbers: r20, r22
ioRawWaitForDataSeconds:
ioRawWaitForDataSeconds_loop:
push r20
rcall ioRawWaitForData1s ; (r20, r22)
pop r20
brcs ioRawWaitForDataSeconds_gotit
sbi LED_PIN, LED_PINNUM ; toggle
dec r20
brne ioRawWaitForDataSeconds_loop
clc
ioRawWaitForDataSeconds_gotit:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForData1s
;
; Wait for incoming data for max 1s
;
; @return CFLAG set if okay (data available), cleared on error
; @clobbers: r20, r22
ioRawWaitForData1s:
ldi r20, 100
ioRawWaitForData1s_loop:
push r20
rcall ioRawWaitForData10ms ; (R20, R22)
pop r20
brcs ioRawWaitForData1s_gotit
dec r20
brne ioRawWaitForData1s_loop
clc
ioRawWaitForData1s_gotit:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForData10ms
;
; Wait for incoming data for max 10 milliseconds.
;
; @return CFLAG set if okay (data available), cleared on error
; @clobbers: r20, r22
ioRawWaitForData10ms:
.if clock == 8000000
ldi r20, 80
.endif
.if clock == 1000000
ldi r20, 10
.endif
ioRawWaitForData10ms_loop:
push r20
rcall ioRawWaitForData1000Cycles ; (r20, r22)
pop r20
brcs ioRawWaitForData10ms_gotit
dec r20
brne ioRawWaitForData10ms_loop
clc
ioRawWaitForData10ms_gotit:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawWaitForData1000Cycles
;
; Wait for incoming data for max 1000 clock cycles
; (about 1ms at 1MHz, 0.125 at 8MHz)
;
; @return CFLAG set if okay (packet received), cleared on error
; @clobbers: r20, r22
ioRawWaitForData1000Cycles:
ldi r20, 140 ; 1
ioRawWaitForData_loop:
M_IO_READ r22, UART_REG_UCSRA ; 2
sbrc r22, UART_BIT_RXC ; 2/3
rjmp ioRawWaitForData_gotit ; 2
dec r20 ; 1
brne ioRawWaitForData_loop ; 1/2 -> 7 per loop, max about 1000
clc ; 1
ret ; 4
ioRawWaitForData_gotit:
sec ; 1
ret ; 4
; @end

11
avr/modules/heap/0BUILD Normal file
View File

@@ -0,0 +1,11 @@
<?xml?>
<gwbuild>
<extradist>
main.asm
</extradist>
</gwbuild>

317
avr/modules/heap/main.asm Normal file
View File

@@ -0,0 +1,317 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; Needed vars:
; - HEAP_START
; - HEAP_SIZE
.equ HEAP_HEADER_BIT_USED = 1
.dseg
heapPtr: .byte 2
heapUsed: .byte 2
heapFree: .byte 2
heapDblFree: .byte 1
.cseg
; ---------------------------------------------------------------------------
; @routine Heap_Init
Heap_Init:
ldi xl, LOW(HEAP_START)
ldi xh, HIGH(HEAP_START)
ldi r24, LOW((HEAP_SIZE-6) & 0xfffc) ; size minus chunk header, chunk footer, start, end
ldi r25, HIGH((HEAP_SIZE-6) & 0xfffc) ; we allocate multiples of 4 bytes
clr r16
sts heapUsed, r16
sts heapUsed+1, r16
st X+, r16 ; write start header
st X+, r16
sts heapPtr, xl ; store global vars
sts heapPtr+1, xl
sts heapFree, r24
sts heapFree+1, r25
st X+, r24 ; store header of first chunk
st X+, r25
add xl, r24
adc xh, r25
st X+, r24 ; store footer of first chunk
st X+, r25
st X+, r16 ; write end footer
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine heapAllocFirstFit
;
; @param r25:r24 number of bytes to alloc
; @return CFLAG set of okay, cleared otherwise
; @return X start of allocated memory
heapAllocFirstFit:
adiw r25:r24, 3 ; align size to next multiple of 4
andi r24, 0xfc ; mask lower two bits
lds xl, heapPtr
lds xh, heapPtr+1
heapAllocFirstFit_loop:
ld r18, X+ ; read chunk header
ld r19, X+
mov r16, r18 ; heap end reached?
or r16, r19
breq heapAllocFirstFit_memFull
sbrc r17, HEAP_HEADER_BIT_USED
rjmp heapAllocFirstFit_next ; jump if used
; current chunk free, check size
mov r16, r18
mov r17, r19
sub r16, r24
sbc r17, r25 ; r17:r16=remainder
brcs heapAllocFirstFit_next ; too small
rcall heapUseChunk
sec
ret
heapAllocFirstFit_next:
add xl, r18
adc xh, r19
adiw xh:xl, 2 ; skip footer
rjmp heapAllocFirstFit_loop
heapAllocFirstFit_memFull:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine heapAdjustStatsAlloc
;
; @param r25:r24 size of allocated chunk
; @clobbers r16, r17
heapAdjustStatsAlloc:
; adjust heapUsed
lds r16, heapUsed
lds r17, heapUsed+1
add r16, r24
adc r17, r25
sts heapUsed, r16
sts heapUsed+1, r17
; adjust heapFree
lds r16, heapFree
lds r17, heapFree+1
sub r16, r24
sbc r17, r25
sts heapFree, r16
sts heapFree+1, r17
ret
; @end
; ---------------------------------------------------------------------------
; @routine heapAdjustStatsFree
;
; @param r25:r24 size of released chunk
; @clobbers r16, r17
heapAdjustStatsFree:
; adjust heapUsed
lds r16, heapUsed
lds r17, heapUsed+1
sub r16, r24
sbc r17, r25
sts heapUsed, r16
sts heapUsed+1, r17
; adjust heapFree
lds r16, heapFree
lds r17, heapFree+1
add r16, r24
adc r17, r25
sts heapFree, r16
sts heapFree+1, r17
ret
; @end
; ---------------------------------------------------------------------------
; @routine Heap_Free
;
; @param X pointer to previously allocated data
; @clobbers r16, r17, r24, r25, X
Heap_Free:
sbiw xh:xl, 2 ; go back to chunk header
ld r24, X+ ; read allocated size (and USED bit)
ld r25, X+
sbrs r24, HEAP_HEADER_BIT_USED
rjmp Heap_Free_dblFree ; not in use (double free!!)
cbr r24, (1<<HEAP_HEADER_BIT_USED) ; clear USED bit
st -X, r25 ; write back chunk header
st -X, r24 ; X now points to begin of chunk header
push xl
push xh
adiw xh:xl, 2 ; go skip chunk header
add xl, r24 ; skip data
adc xh, r25
st X+, r24 ; write chunk footer
st X+, r25 ; X points to the next chunk header now
rcall heapAdjustStatsFree ; update stats (r16, r17)
rcall heapCoalecseUp ; try to coalecse following chunk with this (r16, r17, r24, r25, X)
pop xh
pop xl
rcall heapCoalecseUp ; try to coalesce this chunk with predecessor (r16, r17, r24, r25, X)
rjmp Heap_Free_ret
Heap_Free_dblFree:
lds r24, heapDblFree
lds r25, heapDblFree+1
adiw r25:r24, 1
breq Heap_Free_ret
sts heapDblFree, r24
sts heapDblFree+1, r25
Heap_Free_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine heapCoalecseUp
;
; @param X pointer to chunk header
; @clobbers r16, r17, r24, r25, X
heapCoalecseUp:
ld r16, X+ ; end of heap reached(header==0x0000)?
ld r17, X
sbiw xh:xl, 1
or r16, r17
breq heapCoalecseUp_ret ; yes, jump
; read footer of preceeding chunk
ld r25, -X
ld r24, -X
; R25:R24=footer of preceeding chunk (i.e. size of previous chunk)
mov r16, r24 ; check: beginning of heap reached (header==0x0000)?
or r16, r25
breq heapCoalecseUp_ret ; yes, jump
sbrc r24, HEAP_HEADER_BIT_USED ; block used?
rjmp heapCoalecseUp_ret ; jump if used
; previous chunk also free, coalesce, X points to current chunk header
ld r16, X+
ld r17, X+
; X now points to beginning of current chunk's data, R17:r16=size of current chunk, R25:R24=size of previous chunk
; to go to start of previous chunk header: sub this chunk header, previous chunk footer, previous chunk header and previous data
sbiw xh:xl, 6
sub xl, r24
sbc xh, r25
; X points now to the beginning of the previous chunk header
; calculate size of new coalecsed chunk: add size of this chunk, size of previous chunk, 1 chunk header and 1 footer which are
; no longer needed now (since the one header and footer of the previous chunk now cover both chunks)
add r24, r16
adc r25, r17
adiw r25:r24, 4
; write new chunk header
st X+, r24
st X+, r25
; skip full data size of the coalesced chunk
add xl, r24
adc xh, r25
; write new chunk footer
st X+, r24
st X+, r25
; X now points to header of following chunk
heapCoalecseUp_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine heapUseChunk
;
; @param r25:r24 wanted size
; @param r17:r16 size of current chunk minus wanted size (remainder)
; @param X points to data of current chunk
; @clobbers
heapUseChunk:
push xh
push xl
tst r17
breq heapUseChunk_split
cpi r16, 8 ; at least 8 bytes left?
brcs heapUseChunk_directAlloc ; nope, use full chunk
heapUseChunk_split:
sbiw xh:xl, 2 ; go back to chunk header
; X points to start of chunk header
mov r18, r24
sbr r18, (1<<HEAP_HEADER_BIT_USED)
st X+, r18 ; set used bit
st X+, r25
add xl, r24
adc xh, r25
; X now points to the start of chunk footer
st X+, r18
st X+, r25
; create chunk header for new free chunk
subi r16, 4 ; sub chunk header and footer from size
sbci r17, 0
andi r16, 0xfc ; clear USED bit
st X+, r16 ; write new chunk header
st X+, r17
add xl, r16
adc xh, r17
st X+, r16 ; write new chunk footer
st X+, r17
; update stats, pop X and return
rjmp heapUseChunk_statsPopRet
heapUseChunk_directAlloc:
ld r17, -X ; load allocated size from chunk header
ld r16, -X
mov r18, r16
sbr r18, (1<<HEAP_HEADER_BIT_USED)
st X, r18 ; set USED bit in chunk header
adiw xh:xl, 2 ; skip chunk header
add xl, r16 ; skip chunk data
adc xh, r17
st X, r18 ; set USED bit in chunk footer
; update stats, pop X and return
heapUseChunk_statsPopRet:
rcall heapAdjustStatsAlloc ; (r16, r17)
pop xh
pop xl
sec
ret
; @end

View File

@@ -0,0 +1,15 @@
<?xml?>
<gwbuild>
<extradist>
defs.asm
font8x8.asm
font6x8.asm
font1.asm
font2.asm
</extradist>
</gwbuild>

View File

@@ -0,0 +1,26 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
#ifndef AVR_MODULES_FONT_DEFS
#define AVR_MODULES_FONT_DEFS
.equ FONT_OFFS_RENDERFN_LOW = 0
.equ FONT_OFFS_RENDERFN_HI = 1
.equ FONT_OFFS_DATASIZE = 2 ; one byte used, one byte reserved
.equ FONT_OFFS_WIDTH = 4
.equ FONT_OFFS_HEIGHT = 5
.equ FONT_OFFS_FIRSTCHAR = 6
.equ FONT_OFFS_NUMCHARS = 7
#endif

View File

@@ -0,0 +1,100 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; This is a font from the project LCD_fonts at
; https://github.com/basti79/LCD-fonts.git
; which in turn is based on a post by Benedikt K. in a forum post on
; https://www.mikrocontroller.net/topic/54860
; ***************************************************************************
; ***************************************************************************
; code
.cseg
font1_8x8:
; header
.dw font8x8MonoRenderCharacter ; renderFn
.db 128, 0 ; needed buffer size
.db 8, 8 ; width, height of chars
.db 32, 64 ; first char, num of chars in font
; data (8x8_horizontal_LSB_2)
.db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ; 0x20
.db 0x0C,0x1E,0x1E,0x0C,0x0C,0x00,0x0C,0x00, ; 0x21
.db 0x36,0x36,0x36,0x00,0x00,0x00,0x00,0x00, ; 0x22
.db 0x36,0x36,0x7F,0x36,0x7F,0x36,0x36,0x00, ; 0x23
.db 0x0C,0x3E,0x03,0x1E,0x30,0x1F,0x0C,0x00, ; 0x24
.db 0x00,0x63,0x33,0x18,0x0C,0x66,0x63,0x00, ; 0x25
.db 0x1C,0x36,0x1C,0x6E,0x3B,0x33,0x6E,0x00, ; 0x26
.db 0x06,0x06,0x03,0x00,0x00,0x00,0x00,0x00, ; 0x27
.db 0x18,0x0C,0x06,0x06,0x06,0x0C,0x18,0x00, ; 0x28
.db 0x06,0x0C,0x18,0x18,0x18,0x0C,0x06,0x00, ; 0x29
.db 0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00, ; 0x2A
.db 0x00,0x0C,0x0C,0x3F,0x0C,0x0C,0x00,0x00, ; 0x2B
.db 0x00,0x00,0x00,0x00,0x00,0x0E,0x0C,0x06, ; 0x2C
.db 0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00, ; 0x2D
.db 0x00,0x00,0x00,0x00,0x00,0x0C,0x0C,0x00, ; 0x2E
.db 0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00, ; 0x2F
.db 0x1E,0x33,0x3B,0x3F,0x37,0x33,0x1E,0x00, ; 0x30
.db 0x0C,0x0F,0x0C,0x0C,0x0C,0x0C,0x3F,0x00, ; 0x31
.db 0x1E,0x33,0x30,0x1C,0x06,0x33,0x3F,0x00, ; 0x32
.db 0x1E,0x33,0x30,0x1C,0x30,0x33,0x1E,0x00, ; 0x33
.db 0x38,0x3C,0x36,0x33,0x7F,0x30,0x30,0x00, ; 0x34
.db 0x3F,0x03,0x1F,0x30,0x30,0x33,0x1E,0x00, ; 0x35
.db 0x1C,0x06,0x03,0x1F,0x33,0x33,0x1E,0x00, ; 0x36
.db 0x3F,0x33,0x30,0x18,0x0C,0x06,0x06,0x00, ; 0x37
.db 0x1E,0x33,0x33,0x1E,0x33,0x33,0x1E,0x00, ; 0x38
.db 0x1E,0x33,0x33,0x3E,0x30,0x18,0x0E,0x00, ; 0x39
.db 0x00,0x00,0x0C,0x0C,0x00,0x0C,0x0C,0x00, ; 0x3A
.db 0x00,0x00,0x0C,0x0C,0x00,0x0E,0x0C,0x06, ; 0x3B
.db 0x18,0x0C,0x06,0x03,0x06,0x0C,0x18,0x00, ; 0x3C
.db 0x00,0x00,0x3F,0x00,0x3F,0x00,0x00,0x00, ; 0x3D
.db 0x06,0x0C,0x18,0x30,0x18,0x0C,0x06,0x00, ; 0x3E
.db 0x1E,0x33,0x30,0x18,0x0C,0x00,0x0C,0x00, ; 0x3F
.db 0x3E,0x63,0x7B,0x7B,0x7B,0x03,0x1E,0x00, ; 0x40
.db 0x0C,0x1E,0x33,0x33,0x3F,0x33,0x33,0x00, ; 0x41
.db 0x3F,0x66,0x66,0x3E,0x66,0x66,0x3F,0x00, ; 0x42
.db 0x3C,0x66,0x03,0x03,0x03,0x66,0x3C,0x00, ; 0x43
.db 0x3F,0x36,0x66,0x66,0x66,0x36,0x3F,0x00, ; 0x44
.db 0x7F,0x46,0x16,0x1E,0x16,0x46,0x7F,0x00, ; 0x45
.db 0x7F,0x46,0x16,0x1E,0x16,0x06,0x0F,0x00, ; 0x46
.db 0x3C,0x66,0x03,0x03,0x73,0x66,0x7C,0x00, ; 0x47
.db 0x33,0x33,0x33,0x3F,0x33,0x33,0x33,0x00, ; 0x48
.db 0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00, ; 0x49
.db 0x78,0x30,0x30,0x30,0x33,0x33,0x1E,0x00, ; 0x4A
.db 0x67,0x66,0x36,0x1E,0x36,0x66,0x67,0x00, ; 0x4B
.db 0x0F,0x06,0x06,0x06,0x46,0x66,0x7F,0x00, ; 0x4C
.db 0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x00, ; 0x4D
.db 0x63,0x67,0x6F,0x7B,0x73,0x63,0x63,0x00, ; 0x4E
.db 0x1C,0x36,0x63,0x63,0x63,0x36,0x1C,0x00, ; 0x4F
.db 0x3F,0x66,0x66,0x3E,0x06,0x06,0x0F,0x00, ; 0x50
.db 0x1E,0x33,0x33,0x33,0x3B,0x1E,0x38,0x00, ; 0x51
.db 0x3F,0x66,0x66,0x3E,0x1E,0x36,0x67,0x00, ; 0x52
.db 0x1E,0x33,0x07,0x1C,0x38,0x33,0x1E,0x00, ; 0x53
.db 0x3F,0x2D,0x0C,0x0C,0x0C,0x0C,0x1E,0x00, ; 0x54
.db 0x33,0x33,0x33,0x33,0x33,0x33,0x3F,0x00, ; 0x55
.db 0x33,0x33,0x33,0x33,0x33,0x1E,0x0C,0x00, ; 0x56
.db 0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00, ; 0x57
.db 0x63,0x63,0x36,0x1C,0x36,0x63,0x63,0x00, ; 0x58
.db 0x33,0x33,0x33,0x1E,0x0C,0x0C,0x1E,0x00, ; 0x59
.db 0x7F,0x33,0x19,0x0C,0x46,0x63,0x7F,0x00, ; 0x5A
.db 0x1E,0x06,0x06,0x06,0x06,0x06,0x1E,0x00, ; 0x5B
.db 0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00, ; 0x5C
.db 0x1E,0x18,0x18,0x18,0x18,0x18,0x1E,0x00, ; 0x5D
.db 0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00, ; 0x5E
.db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF ; 0x5F

View File

@@ -0,0 +1,179 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; This is a font from the project LCD_fonts at
; https://github.com/basti79/LCD-fonts.git
; which in turn is based on a post by Benedikt K. in a forum post on
; https://www.mikrocontroller.net/topic/54860
; ***************************************************************************
; ***************************************************************************
; code
.cseg
font2_6x8:
; header
.dw font6x8MonoRenderCharacter ; renderFn
.db 96, 0 ; needed buffer size
.db 6, 8 ; width, height of chars
.db 32, 65 ; first char, num of chars in font
; data (6x8_horizontal_LSB_2)
font:
.db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ; 0x20
.db 0x08,0x1C,0x1C,0x08,0x08,0x00,0x08,0x00, ; 0x21
.db 0x36,0x36,0x12,0x00,0x00,0x00,0x00,0x00, ; 0x22
.db 0x00,0x14,0x3E,0x14,0x14,0x3E,0x14,0x00, ; 0x23
.db 0x04,0x1C,0x02,0x0C,0x10,0x0E,0x08,0x00, ; 0x24
.db 0x26,0x26,0x10,0x08,0x04,0x32,0x32,0x00, ; 0x25
.db 0x04,0x0A,0x0A,0x04,0x2A,0x12,0x2C,0x00, ; 0x26
.db 0x0C,0x0C,0x04,0x00,0x00,0x00,0x00,0x00, ; 0x27
.db 0x08,0x04,0x04,0x04,0x04,0x04,0x08,0x00, ; 0x28
.db 0x04,0x08,0x08,0x08,0x08,0x08,0x04,0x00, ; 0x29
.db 0x00,0x14,0x1C,0x3E,0x1C,0x14,0x00,0x00, ; 0x2A
.db 0x00,0x08,0x08,0x3E,0x08,0x08,0x00,0x00, ; 0x2B
.db 0x00,0x00,0x00,0x00,0x00,0x0C,0x0C,0x04, ; 0x2C
.db 0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x00, ; 0x2D
.db 0x00,0x00,0x00,0x00,0x00,0x0C,0x0C,0x00, ; 0x2E
.db 0x00,0x20,0x10,0x08,0x04,0x02,0x00,0x00, ; 0x2F
.db 0x1C,0x22,0x32,0x2A,0x26,0x22,0x1C,0x00, ; 0x30
.db 0x08,0x0C,0x08,0x08,0x08,0x08,0x1C,0x00, ; 0x31
.db 0x1C,0x22,0x20,0x18,0x04,0x02,0x3E,0x00, ; 0x32
.db 0x1C,0x22,0x20,0x1C,0x20,0x22,0x1C,0x00, ; 0x33
.db 0x10,0x18,0x14,0x12,0x3E,0x10,0x10,0x00, ; 0x34
.db 0x3E,0x02,0x02,0x1E,0x20,0x22,0x1C,0x00, ; 0x35
.db 0x18,0x04,0x02,0x1E,0x22,0x22,0x1C,0x00, ; 0x36
.db 0x3E,0x20,0x10,0x08,0x04,0x04,0x04,0x00, ; 0x37
.db 0x1C,0x22,0x22,0x1C,0x22,0x22,0x1C,0x00, ; 0x38
.db 0x1C,0x22,0x22,0x3C,0x20,0x10,0x0C,0x00, ; 0x39
.db 0x00,0x00,0x0C,0x0C,0x00,0x0C,0x0C,0x00, ; 0x3A
.db 0x00,0x00,0x0C,0x0C,0x00,0x0C,0x0C,0x04, ; 0x3B
.db 0x10,0x08,0x04,0x02,0x04,0x08,0x10,0x00, ; 0x3C
.db 0x00,0x00,0x3E,0x00,0x00,0x3E,0x00,0x00, ; 0x3D
.db 0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x00, ; 0x3E
.db 0x1C,0x22,0x20,0x18,0x08,0x00,0x08,0x00, ; 0x3F
.db 0x1C,0x22,0x3A,0x2A,0x3A,0x02,0x1C,0x00, ; 0x40
.db 0x1C,0x22,0x22,0x22,0x3E,0x22,0x22,0x00, ; 0x41
.db 0x1E,0x22,0x22,0x1E,0x22,0x22,0x1E,0x00, ; 0x42
.db 0x1C,0x22,0x02,0x02,0x02,0x22,0x1C,0x00, ; 0x43
.db 0x1E,0x22,0x22,0x22,0x22,0x22,0x1E,0x00, ; 0x44
.db 0x3E,0x02,0x02,0x1E,0x02,0x02,0x3E,0x00, ; 0x45
.db 0x3E,0x02,0x02,0x1E,0x02,0x02,0x02,0x00, ; 0x46
.db 0x1C,0x22,0x02,0x3A,0x22,0x22,0x3C,0x00, ; 0x47
.db 0x22,0x22,0x22,0x3E,0x22,0x22,0x22,0x00, ; 0x48
.db 0x1C,0x08,0x08,0x08,0x08,0x08,0x1C,0x00, ; 0x49
.db 0x20,0x20,0x20,0x20,0x22,0x22,0x1C,0x00, ; 0x4A
.db 0x22,0x12,0x0A,0x06,0x0A,0x12,0x22,0x00, ; 0x4B
.db 0x02,0x02,0x02,0x02,0x02,0x02,0x3E,0x00, ; 0x4C
.db 0x22,0x36,0x2A,0x22,0x22,0x22,0x22,0x00, ; 0x4D
.db 0x22,0x26,0x2A,0x32,0x22,0x22,0x22,0x00, ; 0x4E
.db 0x1C,0x22,0x22,0x22,0x22,0x22,0x1C,0x00, ; 0x4F
.db 0x1E,0x22,0x22,0x1E,0x02,0x02,0x02,0x00, ; 0x50
.db 0x1C,0x22,0x22,0x22,0x2A,0x12,0x2C,0x00, ; 0x51
.db 0x1E,0x22,0x22,0x1E,0x12,0x22,0x22,0x00, ; 0x52
.db 0x1C,0x22,0x02,0x1C,0x20,0x22,0x1C,0x00, ; 0x53
.db 0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x00, ; 0x54
.db 0x22,0x22,0x22,0x22,0x22,0x22,0x1C,0x00, ; 0x55
.db 0x22,0x22,0x22,0x22,0x22,0x14,0x08,0x00, ; 0x56
.db 0x22,0x22,0x2A,0x2A,0x2A,0x2A,0x14,0x00, ; 0x57
.db 0x22,0x22,0x14,0x08,0x14,0x22,0x22,0x00, ; 0x58
.db 0x22,0x22,0x22,0x14,0x08,0x08,0x08,0x00, ; 0x59
.db 0x1E,0x10,0x08,0x04,0x02,0x02,0x1E,0x00, ; 0x5A
.db 0x1C,0x04,0x04,0x04,0x04,0x04,0x1C,0x00, ; 0x5B
.db 0x00,0x02,0x04,0x08,0x10,0x20,0x00,0x00, ; 0x5C
.db 0x1C,0x10,0x10,0x10,0x10,0x10,0x1C,0x00, ; 0x5D
.db 0x08,0x14,0x22,0x00,0x00,0x00,0x00,0x00, ; 0x5E
.db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F, ; 0x5F
.db 0x0C,0x0C,0x08,0x00,0x00,0x00,0x00,0x00, ; 0x60
#if 0
.db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ; 0x20
.db 0x20,0x70,0x70,0x20,0x20,0x00,0x20,0x00, ; 0x21
.db 0xD8,0xD8,0x48,0x00,0x00,0x00,0x00,0x00, ; 0x22
.db 0x00,0x50,0xF8,0x50,0x50,0xF8,0x50,0x00, ; 0x23
.db 0x10,0x70,0x08,0x30,0x40,0x38,0x20,0x00, ; 0x24
.db 0x98,0x98,0x40,0x20,0x10,0xC8,0xC8,0x00, ; 0x25
.db 0x10,0x28,0x28,0x10,0xA8,0x48,0xB0,0x00, ; 0x26
.db 0x30,0x30,0x10,0x00,0x00,0x00,0x00,0x00, ; 0x27
.db 0x20,0x10,0x10,0x10,0x10,0x10,0x20,0x00, ; 0x28
.db 0x10,0x20,0x20,0x20,0x20,0x20,0x10,0x00, ; 0x29
.db 0x00,0x50,0x70,0xF8,0x70,0x50,0x00,0x00, ; 0x2A
.db 0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00, ; 0x2B
.db 0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x10, ; 0x2C
.db 0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00, ; 0x2D
.db 0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00, ; 0x2E
.db 0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00, ; 0x2F
.db 0x70,0x88,0xC8,0xA8,0x98,0x88,0x70,0x00, ; 0x30
.db 0x20,0x30,0x20,0x20,0x20,0x20,0x70,0x00, ; 0x31
.db 0x70,0x88,0x80,0x60,0x10,0x08,0xF8,0x00, ; 0x32
.db 0x70,0x88,0x80,0x70,0x80,0x88,0x70,0x00, ; 0x33
.db 0x40,0x60,0x50,0x48,0xF8,0x40,0x40,0x00, ; 0x34
.db 0xF8,0x08,0x08,0x78,0x80,0x88,0x70,0x00, ; 0x35
.db 0x60,0x10,0x08,0x78,0x88,0x88,0x70,0x00, ; 0x36
.db 0xF8,0x80,0x40,0x20,0x10,0x10,0x10,0x00, ; 0x37
.db 0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00, ; 0x38
.db 0x70,0x88,0x88,0xF0,0x80,0x40,0x30,0x00, ; 0x39
.db 0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x00, ; 0x3A
.db 0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x10, ; 0x3B
.db 0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00, ; 0x3C
.db 0x00,0x00,0xF8,0x00,0x00,0xF8,0x00,0x00, ; 0x3D
.db 0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x00, ; 0x3E
.db 0x70,0x88,0x80,0x60,0x20,0x00,0x20,0x00, ; 0x3F
.db 0x70,0x88,0xE8,0xA8,0xE8,0x08,0x70,0x00, ; 0x40
.db 0x70,0x88,0x88,0x88,0xF8,0x88,0x88,0x00, ; 0x41
.db 0x78,0x88,0x88,0x78,0x88,0x88,0x78,0x00, ; 0x42
.db 0x70,0x88,0x08,0x08,0x08,0x88,0x70,0x00, ; 0x43
.db 0x78,0x88,0x88,0x88,0x88,0x88,0x78,0x00, ; 0x44
.db 0xF8,0x08,0x08,0x78,0x08,0x08,0xF8,0x00, ; 0x45
.db 0xF8,0x08,0x08,0x78,0x08,0x08,0x08,0x00, ; 0x46
.db 0x70,0x88,0x08,0xE8,0x88,0x88,0xF0,0x00, ; 0x47
.db 0x88,0x88,0x88,0xF8,0x88,0x88,0x88,0x00, ; 0x48
.db 0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00, ; 0x49
.db 0x80,0x80,0x80,0x80,0x88,0x88,0x70,0x00, ; 0x4A
.db 0x88,0x48,0x28,0x18,0x28,0x48,0x88,0x00, ; 0x4B
.db 0x08,0x08,0x08,0x08,0x08,0x08,0xF8,0x00, ; 0x4C
.db 0x88,0xD8,0xA8,0x88,0x88,0x88,0x88,0x00, ; 0x4D
.db 0x88,0x98,0xA8,0xC8,0x88,0x88,0x88,0x00, ; 0x4E
.db 0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00, ; 0x4F
.db 0x78,0x88,0x88,0x78,0x08,0x08,0x08,0x00, ; 0x50
.db 0x70,0x88,0x88,0x88,0xA8,0x48,0xB0,0x00, ; 0x51
.db 0x78,0x88,0x88,0x78,0x48,0x88,0x88,0x00, ; 0x52
.db 0x70,0x88,0x08,0x70,0x80,0x88,0x70,0x00, ; 0x53
.db 0xF8,0x20,0x20,0x20,0x20,0x20,0x20,0x00, ; 0x54
.db 0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00, ; 0x55
.db 0x88,0x88,0x88,0x88,0x88,0x50,0x20,0x00, ; 0x56
.db 0x88,0x88,0xA8,0xA8,0xA8,0xA8,0x50,0x00, ; 0x57
.db 0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00, ; 0x58
.db 0x88,0x88,0x88,0x50,0x20,0x20,0x20,0x00, ; 0x59
.db 0x78,0x40,0x20,0x10,0x08,0x08,0x78,0x00, ; 0x5A
.db 0x70,0x10,0x10,0x10,0x10,0x10,0x70,0x00, ; 0x5B
.db 0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00, ; 0x5C
.db 0x70,0x40,0x40,0x40,0x40,0x40,0x70,0x00, ; 0x5D
.db 0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00, ; 0x5E
.db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC, ; 0x5F
.db 0x30,0x30,0x20,0x00,0x00,0x00,0x00,0x00, ; 0x60
#endif

View File

@@ -0,0 +1,96 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine font6x8RenderCharacter
; @param R16 character to write
; @param R1:R0 background color
; @param R3:R2 foreground color
; @param Z pointer to font
; @param X pointer to RAM to store data to
; @param r18 char width in pixel
; @param r19 char height in pixel
; @clobbers r16, r17, r24, r25, x
font6x8MonoRenderCharacter:
push zl
push zh
adiw zh:zl, FONT_OFFS_WIDTH
lpm r18, Z+ ; char width in pixels
lpm r19, Z ; char height in pixels
sbiw zh:zl, FONT_OFFS_WIDTH+1
rcall font6x8GetCharPosInFont ; (r16, r17, r24, r25, z)
mov r25, r19 ; height in pixels
font6x8MonoRenderCharacter_loop1:
mov r24, r18 ; width in pixels
lpm r17, Z+
font6x8MonoRenderCharacter_loop2:
lsr r17
brcs font6x8MonoRenderCharacter_writeForeground
st X+, r0
st X+, r1
rjmp font6x8MonoRenderCharacter_loop2end
font6x8MonoRenderCharacter_writeForeground:
st X+, r2
st X+, r3
font6x8MonoRenderCharacter_loop2end:
dec r24
brne font6x8MonoRenderCharacter_loop2
dec r25
brne font6x8MonoRenderCharacter_loop1
pop zh
pop zl
ret
; @end
; ---------------------------------------------------------------------------
; @routine font6x8GetCharPosInFont (same as font8x8GetCharPosInFont!)
; @param R16 character to write
; @param Z pointer to font
; @return Z pointer to begin of char data
; @clobbers r16, r17, r24, r25, z
font6x8GetCharPosInFont:
mov r24, r16
adiw zh:zl, FONT_OFFS_FIRSTCHAR
lpm r24, Z+ ; first char num
lpm r25, Z+ ; num of chars
sub r16, r24
brcs font6x8GetCharPosInFont_ret
cp r16, r25
brcc font6x8GetCharPosInFont_ret
mov r24, r16
clr r25
lsl r24 ; x2
rol r25
lsl r24 ; x4
rol r25
lsl r24 ; x8
rol r25
add zl, r24
adc zh, r25
font6x8GetCharPosInFont_ret:
ret
; @end

View File

@@ -0,0 +1,94 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine font8x8RenderCharacter
; @param R16 character to write
; @param R1:R0 background color
; @param R3:R2 foreground color
; @param Z pointer to font
; @param X pointer to RAM to store data to
; @param r18 char width in pixel
; @param r19 char height in pixel
; @clobbers r17, r24, r25, x
font8x8MonoRenderCharacter:
push zl
push zh
rcall font8x8GetCharPosInFont8x8 ; (r17, r24, r25, z)
ldi r25, 8 ; 8 bytes
font8x8MonoRenderCharacter_loop1:
ldi r24, 8 ; 8 bits
lpm r17, Z+
font8x8MonoRenderCharacter_loop2:
lsr r17
brcs font8x8MonoRenderCharacter_writeForeground
st X+, r0
st X+, r1
rjmp font8x8MonoRenderCharacter_loop2end
font8x8MonoRenderCharacter_writeForeground:
st X+, r2
st X+, r3
font8x8MonoRenderCharacter_loop2end:
dec r24
brne font8x8MonoRenderCharacter_loop2
dec r25
brne font8x8MonoRenderCharacter_loop1
ldi r18, 8
ldi r19, 8
pop zh
pop zl
ret
; @end
; ---------------------------------------------------------------------------
; @routine font8x8GetCharPosInFont8x8
; @param R16 character to write
; @param Z pointer to font
; @return Z pointer to begin of char data
; @clobbers r17, r24, r25, z
font8x8GetCharPosInFont8x8:
mov r24, r16
adiw zh:zl, FONT_OFFS_FIRSTCHAR
lpm r24, Z+ ; first char num
lpm r25, Z+ ; num of chars
sub r16, r24
brcs font8x8GetCharPosInFont8x8_ret
cp r16, r25
brcc font8x8GetCharPosInFont8x8_ret
mov r24, r16
clr r25
lsl r24 ; x2
rol r25
lsl r24 ; x4
rol r25
lsl r24 ; x8
rol r25
add zl, r24
adc zh, r25
font8x8GetCharPosInFont8x8_ret:
ret
; @end

View File

@@ -0,0 +1,11 @@
<?xml?>
<gwbuild>
<extradist>
main.asm
</extradist>
</gwbuild>

View File

@@ -0,0 +1,61 @@
#define ILI9341_FRAMERATE_61_HZ 0x1F
#define ILI9341_FRAMERATE_63_HZ 0x1E
#define ILI9341_FRAMERATE_65_HZ 0x1D
#define ILI9341_FRAMERATE_68_HZ 0x1C
#define ILI9341_FRAMERATE_70_HZ 0x1B
#define ILI9341_FRAMERATE_73_HZ 0x1A
#define ILI9341_FRAMERATE_76_HZ 0x19
#define ILI9341_FRAMERATE_79_HZ 0x18
#define ILI9341_FRAMERATE_83_HZ 0x17
#define ILI9341_FRAMERATE_86_HZ 0x16
#define ILI9341_FRAMERATE_90_HZ 0x15
#define ILI9341_FRAMERATE_95_HZ 0x14
#define ILI9341_FRAMERATE_100_HZ 0x13
#define ILI9341_FRAMERATE_106_HZ 0x12
#define ILI9341_FRAMERATE_112_HZ 0x11
#define ILI9341_FRAMERATE_119_HZ 0x10
#define ILI9341_MADCTL_MY 0x80 ; row address order
#define ILI9341_MADCTL_MX 0x40 ; column address order
#define ILI9341_MADCTL_MV 0x20 ; row/column exchange
#define ILI9341_MADCTL_ML 0x10 ; vertical refresh order
#define ILI9341_MADCTL_RGB 0x00 ; RGB color order
#define ILI9341_MADCTL_BGR 0x08 ; BGR color order
#define ILI9341_MADCTL_MH 0x04 ; horizontal refresh order
#define ILI9341_CMD_CASET 0x2A
#define ILI9341_CMD_PASET 0x2B
#define ILI9341_CMD_RAMWR 0x2C
#define ILI9341_CMD_RAMRD 0x2E
#define ILI9341_CMD_COLORSET 0x2d
#define ILI9341_CMD_SETDSPBRIGHTNESS 0x51
#define ILI9341_CMD_WRITECTLDISPLAY 0x53
.equ WIN_OFFS_BGCOLOR_LOW = 0
.equ WIN_OFFS_BGCOLOR_HIGH = 1
.equ WIN_OFFS_FGCOLOR_LOW = 2
.equ WIN_OFFS_FGCOLOR_HIGH = 3
.equ WIN_OFFS_WIDTH_LOW = 4
.equ WIN_OFFS_WIDTH_HIGH = 5
.equ WIN_OFFS_HEIGHT_LOW = 6
.equ WIN_OFFS_HEIGHT_HIGH = 7
.equ WIN_OFFS_ABS_X_LOW = 8
.equ WIN_OFFS_ABS_X_HIGH = 9
.equ WIN_OFFS_REL_X_LOW = 10
.equ WIN_OFFS_REL_X_HIGH = 11

View File

@@ -0,0 +1,336 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ---------------------------------------------------------------------------
; @routine ili9341SetAddressWindow
;
; @param r5:r4 X0
; @param r7:r6 Y0
; @param r9:r8 W
; @param r11:r10 H
; @clobbers R16, r20, r21
ili9341SetAddressWindow:
; calc XEnd (=X+W-1)
mov r20, r8
mov r21, r9
add r20, r4
adc r21, r5
subi r20, 1
sbci r21, 0
; send column address
ldi r16, ILI9341_CMD_CASET
rcall ili9341SendCommand
; X0
mov r16, r5
rcall ili9341SendData
mov r16, r4
rcall ili9341SendData
; X1
mov r16, r21
rcall ili9341SendData
mov r16, r20
rcall ili9341SendData
; calc YEnd (=Y+H-1)
mov r20, r10
mov r21, r11
add r20, r6
adc r21, r7
subi r20, 1
sbci r21, 0
; send row address
ldi r16, ILI9341_CMD_PASET
rcall ili9341SendCommand
; Y0
mov r16, r7
rcall ili9341SendData
mov r16, r6
rcall ili9341SendData
; Y1
mov r16, r21
rcall ili9341SendData
mov r16, r20
rcall ili9341SendData
ret
; @end
; ---------------------------------------------------------------------------
; @routine ILI9341_FillRect
; @param r3:r2 color
; @param r5:r4 X0
; @param r7:r6 Y0
; @param r9:r8 X1/W
; @param r11:r10 Y1/H
ILI9341_FillRect:
push r15
in r15, SREG
cli
rcall ili9341BeginSpi ; (R16, R17)
rcall ili9341SetAddressWindow ; (R16, r20, r21)
mov r18, r2 ; color
mov r19, r3
mov r22, r10 ; H low
mov r23, r11 ; H high
ldi r16, ILI9341_CMD_RAMWR ; start writing ro RAM
rcall ili9341SendCommand
cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS low
sbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN ; D high (DATA)
ILI9341_FillRect_loopH:
mov r24, r8 ; W low
mov r25, r9 ; W high
ILI9341_FillRect_loopW:
mov r16, r19
rcall SPIHW_MasterTransfer
mov r16, r18
rcall SPIHW_MasterTransfer
sbiw r25:r24, 1
brne ILI9341_FillRect_loopW
mov r24, r22 ; H low
mov r25, r23 ; H high
sbiw r25:r24, 1 ; dec
mov r22, r24 ; save in r23:r22
mov r23, r25
brne ILI9341_FillRect_loopH
sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS high
rcall ili9341EndSpi
out SREG, r15
pop r15
ret
; @end
; ---------------------------------------------------------------------------
; @routine ili9341BitBlit
; @param r5:r4 X (dest)
; @param r7:r6 Y (dest)
; @param r9:r8 W
; @param r11:r10 H
; @param X source data pointer (RAM)
; @clobbers r16, r22, r23, r24, r25, X (r17, r20, r21)
ili9341BitBlit:
push r15
in r15, SREG
cli
rcall ili9341BeginSpi ; (r16, r17)
rcall ili9341SetAddressWindow ; (R16, R20, R21)
ldi r16, ILI9341_CMD_RAMWR ; start writing ro RAM
rcall ili9341SendCommand
mov r22, r10
mov r23, r11
cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS low
sbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN ; D high (DATA)
ili9341BitBlit_loopH:
mov r24, r8
mov r25, r9
ili9341BitBlit_loopW:
ld r18, X+
ld r19, X+
mov r16, r19
rcall SPIHW_MasterTransfer ; (R16)
mov r16, r18
rcall SPIHW_MasterTransfer ; (R16)
sbiw r25:r24, 1
brne ili9341BitBlit_loopW
mov r24, r22
mov r25, r23
sbiw r25:r24, 1
mov r22, r24
mov r23, r25
brne ili9341BitBlit_loopH
sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS high
rcall ili9341EndSpi ; (R16)
out SREG, r15
pop r15
ret
; @end
; ---------------------------------------------------------------------------
; @routine ili9341BitBlitStretch2
; @param r5:r4 X (dest)
; @param r7:r6 Y (dest)
; @param r9:r8 W
; @param r11:r10 H
; @param X source data pointer (RAM)
; @clobbers r16, r22, r23, r24, r25, X (r17, r18, r19, r20, r21)
ili9341BitBlitStretch2:
push r15
in r15, SREG
cli
push r8
push r9
push r10
push r11
; width
lsl r8 ; x2
rol r9
; height
lsl r10 ; x2
rol r11
rcall ili9341BeginSpi ; (r16, r17)
rcall ili9341SetAddressWindow ; (R16, R20, R21)
pop r11
pop r10
pop r9
pop r8
ldi r16, ILI9341_CMD_RAMWR ; start writing ro RAM
rcall ili9341SendCommand
mov r22, r10
mov r23, r11
cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS low
sbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN ; D high (DATA)
ldi r17, 2
ili9341BitBlitStretch2_loopH:
mov r20, xl ; preserve for next run
mov r21, xh
rcall ili9341BitBlitStretchNWriteLine ; (r16, r17, r18, r19, r24, r25, X)
mov xl, r20
mov xh, r21
rcall ili9341BitBlitStretchNWriteLine ; (r16, r17, r18, r19, r24, r25, X)
mov r24, r22
mov r25, r23
sbiw r25:r24, 1
mov r22, r24
mov r23, r25
brne ili9341BitBlitStretch2_loopH
sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS high
rcall ili9341EndSpi ; (R16)
out SREG, r15
pop r15
ret
; @end
; ---------------------------------------------------------------------------
; @routine ili9341BitBlitStretch4
; @param r5:r4 X (dest)
; @param r7:r6 Y (dest)
; @param r9:r8 W
; @param r11:r10 H
; @param X source data pointer (RAM)
; @clobbers r16, r22, r23, r24, r25, X (r17, r20, r21)
ili9341BitBlitStretch4:
push r15
in r15, SREG
cli
push r8
push r9
push r10
push r11
; width
lsl r8 ; x2
rol r9
lsl r8 ; x4
rol r9
; height
lsl r10 ; x2
rol r11
lsl r10 ; x4
rol r11
rcall ili9341BeginSpi ; (r16, r17)
rcall ili9341SetAddressWindow ; (R16, R20, R21)
pop r11
pop r10
pop r9
pop r8
ldi r16, ILI9341_CMD_RAMWR ; start writing ro RAM
rcall ili9341SendCommand
mov r22, r10
mov r23, r11
ldi r17, 4
cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS low
sbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN ; D high (DATA)
ili9341BitBlitStretch4_loopH:
mov r20, xl ; preserve for next run
mov r21, xh
rcall ili9341BitBlitStretchNWriteLine ; (r16, r17, r18, r19, r24, r25, X)
mov xl, r20
mov xh, r21
rcall ili9341BitBlitStretchNWriteLine ; (r16, r17, r18, r19, r24, r25, X)
mov xl, r20
mov xh, r21
rcall ili9341BitBlitStretchNWriteLine ; (r16, r17, r18, r19, r24, r25, X)
mov xl, r20
mov xh, r21
rcall ili9341BitBlitStretchNWriteLine ; (r16, r17, r18, r19, r24, r25, X)
mov r24, r22
mov r25, r23
sbiw r25:r24, 1
mov r22, r24
mov r23, r25
brne ili9341BitBlitStretch4_loopH
sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS high
rcall ili9341EndSpi ; (R16)
out SREG, r15
pop r15
ret
; @end
; ---------------------------------------------------------------------------
; @routine ili9341BitBlitStretchNWriteLine
; @param r9:r8 width
; @param r17 repeat factor
; @param X source position of line
; @clobbers r16, r17, r18, r19, r24, r25, X
ili9341BitBlitStretchNWriteLine:
mov r24, r8
mov r25, r9
ili9341BitBlitStretchNWriteLine_loop1:
ld r18, X+
ld r19, X+
push r17
ili9341BitBlitStretchNWriteLine_loop2:
mov r16, r19
rcall SPIHW_MasterTransfer ; (R16)
mov r16, r18
rcall SPIHW_MasterTransfer ; (R16)
dec r17
brne ili9341BitBlitStretchNWriteLine_loop2
pop r17
sbiw r25:r24, 1
brne ili9341BitBlitStretchNWriteLine_loop1
ret
; @end

View File

@@ -0,0 +1,112 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; generally we use the following parameters here:
; @param r1:r0 background color
; @param r3:r2 foreground color
; @param r5:r4 X0
; @param r7:r6 Y0
; @param r9:r8 X1/W
; @param r11:r10 Y1/H
; ***************************************************************************
; defines
.equ ILI9341_SPIMODE = (0<<SPIHW_MODE_SPEED0_BIT) | \
(0<<SPIHW_MODE_SPEED1_BIT) | \
(1<<SPIHW_MODE_DOUBLESPEED_BIT) | \
(0<<SPIHW_MODE_DATAORDER_BIT) | \
(0<<SPIHW_MODE_CPOL_BIT) | \
(0<<SPIHW_MODE_CPHA_BIT)
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine ILI9341IoInit @global
ILI9341IoInit:
; setup pins
sbi ILI9341_RESET_DDR, ILI9341_RESET_PIN ; RESET= output
sbi ILI9341_RESET_OUTPUT, ILI9341_RESET_PIN ; RESET= high
sbi ILI9341_DC_DDR, ILI9341_DC_PIN ; DC = output
sbi ILI9341_LED_DDR, ILI9341_LED_PIN ; LED = output
cbi ILI9341_LED_OUTPUT, ILI9341_LED_PIN ; LED = low
ret
; @end
; ---------------------------------------------------------------------------
; @routine ili9341BeginSpi
;
; @clobbers r16, r17
ili9341BeginSpi:
ldi r16, ILI9341_SPIMODE
ldi r17, ILI9341_DEVICENUM
rjmp SPIHW_MasterStart ; (R18)
; @end
; ---------------------------------------------------------------------------
; @routine ili9341EndSpi
;
; @clobbers r16
ili9341EndSpi:
rjmp SPIHW_MasterStop ; (R16)
; @end
ili9341SendCommand:
cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS low
cbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN ; D low
nop
rcall SPIHW_MasterTransfer
sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS low
ret
; @end
ili9341SendData:
cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS low
sbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN ; D high
rcall SPIHW_MasterTransfer ; (R16)
sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS low
ret
; @end
; @param r19:18 data
ili9341Send16BitData:
cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS low
sbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN ; D high
mov r16, r19
rcall SPIHW_MasterTransfer ; (R16)
mov r16, r18
rcall SPIHW_MasterTransfer ; (R16)
sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS low
ret
; @end

View File

@@ -0,0 +1,428 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; generally we use the following parameters here:
; @param r1:r0 background color
; @param r3:r2 foreground color
; @param r5:r4 X0
; @param r7:r6 Y0
; @param r9:r8 X1/W
; @param r11:r10 Y1/H
; ***************************************************************************
; data
.dseg
ILI9341_buffer: .byte 128
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine ILI9341_Init @global
ILI9341_Init:
rcall ILI9341IoInit
rcall ILI9341_Reset
rcall ILI9341_LeaveSleepMode
ldi r16, 0xff
rcall ILI9341_SetBacklight
ldi r16, 0xff
mov r3, r16
ldi r16, 0xff
mov r2, r16
rcall ili9341Test5
; 0bRRRRRGGGGGGBBBBB
ldi r16, 0b11111000 ; red
mov r3, r16
ldi r16, 0b00000000 ; red
mov r2, r16
rcall ili9341Test2
; 0bRRRRRGGGGGGBBBBB
ldi r16, 0b00000000
mov r3, r16
ldi r16, 0b00011111 ; blue
mov r2, r16
rcall ili9341Test3
; 0bRRRRRGGGGGGBBBBB
ldi r16, 0b00000111 ; green
mov r3, r16
ldi r16, 0b11100000 ; green
mov r2, r16
rcall ili9341Test4
; set foreground color
ldi r16, 0b11100000 ; green
mov r2, r16
ldi r16, 0b00000111 ; green
mov r3, r16
; set background color
ldi r16, 0b11111111 ; white
mov r0, r16
mov r1, r16
; set Xpos
ldi r16, LOW(100)
mov r4, r16
ldi r16, HIGH(100)
mov r5, r16
; setYpos
ldi r16, LOW(150)
mov r6, r16
ldi r16, HIGH(150)
mov r7, r16
; set font pos
ldi zl, LOW(font2_6x8*2)
ldi zh, HIGH(font2_6x8*2)
; set buffer pos
; ldi xl, LOW(ILI9341_buffer)
; ldi xh, HIGH(ILI9341_buffer)
ldi xl, LOW(0x260)
ldi xh, HIGH(0x260)
; set foreground color
ldi r16, 0b00000000 ; black
mov r2, r16
mov r3, r16
; set character
ldi r16, 'A'
rcall ili9341_WriteCharacterX4At
ldi r16, 'Q'
rcall ili9341_WriteCharacterX4At
ldi r16, 'H'
rcall ili9341_WriteCharacterX4At
ldi r16, 'O'
rcall ili9341_WriteCharacterX4At
ldi r16, 'M'
rcall ili9341_WriteCharacterX4At
ldi r16, 'E'
rcall ili9341_WriteCharacterX4At
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine ILI9341_Fini @global
ILI9341_Fini:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ili9341_SendCommands
;
; @clobbers r16
; Z=byte pointer to command list (as for LPM)
ili9341SendCommands:
rcall ili9341BeginSpi
ili9341SendCommands_loop1:
lpm r16, Z+ ; read command
lpm r18, Z+ ; read number of args
cpi r18, 0xff ; end?
breq ili9341SendCommands_end
rcall ili9341SendCommand
mov r19, r18
andi r19, 1 ; if 1: need to skip filler byte
tst r18
breq ili9341SendCommands_loop1 ; no args, next command
ili9341SendCommands_loop2:
lpm r16, Z+
rcall ili9341SendData ; (R16)
dec r18
brne ili9341SendCommands_loop2
add zl, r19 ; possibly skip filler byte
adc zh, r19
sub zh, r19
rjmp ili9341SendCommands_loop1
ili9341SendCommands_end:
rcall ili9341EndSpi ; (R16)
ret
; @end
; ---------------------------------------------------------------------------
; @routine ILI9341_Reset @global
; @clobbers (R22)
ILI9341_Reset:
cbi ILI9341_RESET_OUTPUT, ILI9341_RESET_PIN
ldi r16, 100
rcall Utils_WaitForMilliSecs
sbi ILI9341_RESET_OUTPUT, ILI9341_RESET_PIN
ldi r16, 50
rcall Utils_WaitForMilliSecs
ldi zl, LOW(ili9341InitCommands*2)
ldi zh, HIGH(ili9341InitCommands*2)
rcall ili9341SendCommands
ldi r16, 120
rcall Utils_WaitForMilliSecs
rcall ili9341BeginSpi
ldi r16, 0x29
rcall ili9341SendCommand
rcall ili9341EndSpi
ldi r16, 120
rcall Utils_WaitForMilliSecs
ret
; @end
; ---------------------------------------------------------------------------
; @routine ILI9341_SetBacklight @global
;
; @param r16 0=off, on otherwise
; @clobbers r16, r17
ILI9341_SetBacklight:
tst r16
brne ILI9341_SetBacklight_on
cbi ILI9341_LED_OUTPUT, ILI9341_LED_PIN
ret
ILI9341_SetBacklight_on:
sbi ILI9341_LED_OUTPUT, ILI9341_LED_PIN
push r16
rcall ili9341BeginSpi
ldi r16, ILI9341_CMD_WRITECTLDISPLAY
rcall ili9341SendCommand
; ldi r16, 0b00100100
ldi r16, 0x24
rcall ili9341SendData
ldi r16, ILI9341_CMD_SETDSPBRIGHTNESS
rcall ili9341SendCommand
pop r16
rcall ili9341SendData
ldi r16, 0xbe
rcall ili9341SendCommand
ldi r16, 0x0f
rcall ili9341SendData
rcall ili9341EndSpi
ret
; @end
ILI9341_LeaveSleepMode:
rcall ili9341BeginSpi
ldi r16, 0x11 ; sleep out
rcall ili9341SendCommand
rcall ili9341EndSpi
ldi r16, 5
rcall Utils_WaitForMilliSecs
ret
; @end
; ---------------------------------------------------------------------------
; @routine ILI9341_FillScreen
;
; @param r17:r16 color
ILI9341_FillScreen:
; TODO
ret
; @end
ili9341Test1:
rcall ili9341BeginSpi
ldi r16, 0x04
cbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN ; D low (send command)
rcall SPIHW_MasterTransfer ; (R16)
sbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN ; D high (send data)
clr r16
; read byte 1
rcall SPIHW_MasterTransfer ; (R16)
; read byte 2
rcall SPIHW_MasterTransfer ; (R16)
; read byte 3
rcall SPIHW_MasterTransfer ; (R16)
; read byte 4
rcall SPIHW_MasterTransfer ; (R16)
rcall ili9341EndSpi ; (R16)
ret
; @param %0 X
; @param %1 Y
; @param %2 W
; @param %3 H
.macro M_ILI9341_FILL_RECT
ldi r16, LOW(@0) ; X0
mov r4, r16
ldi r16, HIGH(@0)
mov r5, r16
ldi r16, LOW(@1) ; Y0
mov r6, r16
ldi r16, HIGH(@1)
mov r7, r16
ldi r16, LOW(@2) ; W
mov r8, r16
ldi r16, HIGH(@2)
mov r9, r16
ldi r16, LOW(@3) ; H
mov r10, r16
ldi r16, HIGH(@3)
mov r11, r16
rcall ILI9341_FillRect
.endmacro
ili9341Test2:
M_ILI9341_FILL_RECT 10, 20, 70, 100
ret
ili9341Test3:
M_ILI9341_FILL_RECT 90, 40, 70, 100
ret
ili9341Test4:
M_ILI9341_FILL_RECT 40, 30, 70, 100
ret
ili9341Test5:
M_ILI9341_FILL_RECT 0, 0, 319, 239
ret
ili9341InitCommands:
; display off
.db 0x28, 0
; PowerCtlA
.db 0xcb, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, 0x00
; PowerCtlB
.db 0xcf, 3, 0x00, 0xC1, 0x30, 0x00
; DriverTimingCtlA
.db 0xe8, 3, 0x85, 0x00, 0x78, 0x00
; DriverTimingCtlB
.db 0xea, 2, 0x00, 0x00
; _PowerSeqCtl
.db 0xed, 4, 0x64, 0x03, 0x12, 0x81
; PumpRatioCtl
.db 0xf7, 1, 0x20, 0x00
; PowerCtl1
.db 0xc0, 1, 0x23, 0x00 ; lookup!
; PowerCtl2
.db 0xc1, 1, 0x10, 0x00 ; lookup!
; VomCtl1
.db 0xc5, 2, 0x3e, 0x28 ; lookup!
; VomCtl2
.db 0xc7, 1, 0x86, 0x00 ; lookup!
; ColMod
.db 0x3A, 1, 0x55, 0x00 ; DPI=16bits/pixel, DBI=16bits/pixel
; FrameRateCtl
.db 0xb1, 2, 0x00, ILI9341_FRAMERATE_79_HZ
; DspFnCtl
.db 0xb6, 3, 0x08, 0x82, 0x27, 0x00
; GammaCurve
.db 0x26, 1, 0x01, 0x00
; PosGamma
.db 0xe0, 15
.db 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1
.db 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, 0x00
; NegGamma
.db 0xe1, 15
.db 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1
.db 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, 0x00
; memory access control (use ILI9341_MADCTL_MV to flip X/Y)
; MMMMBM
; YXVLGH00
.db 0x36, 1, 0b11101000, 0x00
; normal mode on
; .db 0x13, 0
; end
.db 0xff, 0xff
helloWorld: .db "Hello World", 0
.include "modules/lcd2/font/font2.asm"

View File

@@ -0,0 +1,144 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine ili9341_WriteCharacterX1At
; @param R16 character to write
; @param r5:r4 X
; @param r7:r6 Y
; @param r1:r0 background color
; @param r3:r2 foreground color
; @param Z pointer to font (byte address for LPM!)
; @param X pointer to RAM to store data to
; @return r5:r4 new X (advanced by character width)
; @clobbers r16 (r17, r20, r21, r22, r23, r24, r25, X)
ili9341_WriteCharacterX1At:
rcall ili9341FontRenderChar ; (r16, r17, r24, r25, z)
rcall ili9341BitBlit ; (r16, r17, r20, r21, r22, r23, r24, r25, X)
; advance X (add char width to X)
add r4, r8
adc r5, r9
ret
; @end
; ---------------------------------------------------------------------------
; @routine ili9341_WriteCharacterX2At
; @param R16 character to write
; @param r5:r4 X
; @param r7:r6 Y
; @param r1:r0 background color
; @param r3:r2 foreground color
; @param Z pointer to font (byte address for LPM!)
; @param X pointer to RAM to store data to
; @return r5:r4 new X (advanced by character width)
; @clobbers r16 (r17, r18, r19, r20, r21, r22, r23, r24, r25, X)
ili9341_WriteCharacterX2At:
rcall ili9341FontRenderChar ; (r16, r17, r24, r25, z)
rcall ili9341BitBlitStretch2 ; (r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, X)
; advance X (add double char width to X)
lsl r8 ; Wx2
rol r9
add r4, r8 ; add to X
adc r5, r9
ret
; @end
; ---------------------------------------------------------------------------
; @routine ili9341_WriteCharacterX4At
; @param R16 character to write
; @param r5:r4 X
; @param r7:r6 Y
; @param r1:r0 background color
; @param r3:r2 foreground color
; @param Z pointer to font (byte address for LPM!)
; @param X pointer to RAM to store data to
; @return r5:r4 new X (advanced by character width)
; @clobbers r16, r17, r18, r19, r24, r25, x, z
ili9341_WriteCharacterX4At:
rcall ili9341FontRenderChar ; (r16, r17, r24, r25, z)
rcall ili9341BitBlitStretch4 ; (r16, r17, r20, r21, r22, r23, r24, r25, X)
; advance X (add quad char width to X)
lsl r8 ; Wx2
rol r9
lsl r8 ; Wx4
rol r9
add r4, r8 ; add to X
adc r5, r9
ret
; @end
; ---------------------------------------------------------------------------
; @routine ili9341FontRenderChar
; @param R16 character to write
; @param Z pointer to font
; @param X pointer to RAM to store data to
; @return r9:r8 character width in points
; @return r11:r10 character height in points
; @clobbers r16 (r17, r24, r25, z)
ili9341FontRenderChar:
; render character
push xl
push xh
; call render function of the selected font (first word of font is jmp to render function)
rcall ili9341JumpToFontRenderFn ; (r17, r24, r25, x, z)
pop xh
pop xl
; set src width and height
mov r8, r18
clr r9
mov r10, r19
clr r11
ret
; @end
; ---------------------------------------------------------------------------
; @routine ili9341JumpToFontRenderFn
;
; helper function to call function at the beginning of the given font
; @clobbers r17
ili9341JumpToFontRenderFn:
lpm r17, Z+
push r17
lpm r17, Z
push r17
sbiw zh:zl, 1
ret
; @end

View File

@@ -0,0 +1,62 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
#ifndef AQH_AVR_WIN_H
#define AQH_AVR_WIN_H
; tree/list info
.equ WID_OFFS_TREE = 0
; signal handler
.equ WID_OFFS_HANDLERFN_LO = WID_OFFS_TREE+TREE_SIZE
.equ WID_OFFS_HANDLERFN_HI = WID_OFFS_HANDLERFN_LO+1
; widget description
.equ WID_OFFS_WIDGET_INFO = WID_OFFS_HANDLERFN_HI+1
.equ WID_OFFS_OPTIONS1 = WID_OFFS_WIDGET_INFO+0
.equ WID_OFFS_OPTIONS2 = WID_OFFS_WIDGET_INFO+1
.equ WID_OFFS_ABS_X_LO = WID_OFFS_WIDGET_INFO+2
.equ WID_OFFS_ABS_X_HI = WID_OFFS_WIDGET_INFO+3
.equ WID_OFFS_ABS_Y_LO = WID_OFFS_WIDGET_INFO+4
.equ WID_OFFS_ABS_Y_HI = WID_OFFS_WIDGET_INFO+5
.equ WID_OFFS_REL_X_LO = WID_OFFS_WIDGET_INFO+6
.equ WID_OFFS_REL_X_HI = WID_OFFS_WIDGET_INFO+7
.equ WID_OFFS_REL_Y_LO = WID_OFFS_WIDGET_INFO+8
.equ WID_OFFS_REL_Y_HI = WID_OFFS_WIDGET_INFO+9
.equ WID_OFFS_WIDTH_LO = WID_OFFS_WIDGET_INFO+10
.equ WID_OFFS_WIDTH_HI = WID_OFFS_WIDGET_INFO+11
.equ WID_OFFS_HEIGHT_LO = WID_OFFS_WIDGET_INFO+12
.equ WID_OFFS_HEIGHT_HI = WID_OFFS_WIDGET_INFO+13
.equ WID_OFFS_BG_COL_LO = WID_OFFS_WIDGET_INFO+14
.equ WID_OFFS_BG_COL_HI = WID_OFFS_WIDGET_INFO+15
.equ WID_OFFS_FG_COL_LO = WID_OFFS_WIDGET_INFO+16
.equ WID_OFFS_FG_COL_HI = WID_OFFS_WIDGET_INFO+17
.equ WID_OFFS_FONT_LO = WID_OFFS_WIDGET_INFO+18
.equ WID_OFFS_FONT_HI = WID_OFFS_WIDGET_INFO+19
.equ WID_SIZE = WID_OFFS_WIDGET_INFO+20
.equ WID_OPTIONS1_BIT_DIRTY = 0
.equ WID_OPTIONS1_BIT_LAYOUT = 1
.equ WID_OPTIONS1_BIT_STRETCH_X = 2
.equ WID_OPTIONS1_BIT_STRETCH_Y = 3
.equ WID_OPTIONS1_BIT_ALIGN_LEFT = 4
.equ WID_OPTIONS1_BIT_ALIGN_RIGHT = 5
.equ WID_OPTIONS1_BIT_ALIGN_TOP = 6
.equ WID_OPTIONS1_BIT_ALIGN_BOTTOM = 7
#endif ; AQH_AVR_WIN_H

View File

@@ -0,0 +1,18 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ---------------------------------------------------------------------------
; @routine WID_Widget_new @global
WID_Widget_new:

View File

@@ -0,0 +1,11 @@
<?xml?>
<gwbuild>
<extradist>
main.asm
</extradist>
</gwbuild>

View File

@@ -0,0 +1,11 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************

View File

@@ -63,6 +63,10 @@
; ---------------------------------------------------------------------------
; special addresses
.equ NET_MAINTENANCE_ADDR = 0xc1

View File

@@ -35,6 +35,12 @@ NETMSG_MemStats_Write:
st X+, r16
st X+, r16
; stack used
.ifdef MODULES_XRAM
lds r20, xramLastAddress
lds r21, xramLastAddress+1
st X+, r20
st X+, r21
.else
ldi r20, LOW(RAMEND)
ldi r21, HIGH(RAMEND)
in r17, SPL
@@ -43,6 +49,7 @@ NETMSG_MemStats_Write:
in r17, SPH
sbc r21, r17
st X+, r21
.endif
; current buffers used
push xl
push xh

11
avr/modules/spi_hw/0BUILD Normal file
View File

@@ -0,0 +1,11 @@
<?xml?>
<gwbuild>
<extradist>
main.asm
</extradist>
</gwbuild>

202
avr/modules/spi_hw/main.asm Normal file
View File

@@ -0,0 +1,202 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; defines
.equ SPIHW_MODE_SPEED0_BIT = 0 ; 00=CLK/4, 01=CLK/16
.equ SPIHW_MODE_SPEED1_BIT = 1 ; 10=CLK/64, 11=CLK/128
.equ SPIHW_MODE_DOUBLESPEED_BIT = 2 ; 1=double speed from SPIHW_MODE_SPEED0/1_BIT
.equ SPIHW_MODE_DATAORDER_BIT = 3 ; 1=LSB first, 0=MSB first
.equ SPIHW_MODE_CPOL_BIT = 4 ; 0=leading edge rising/trailing edge falling
.equ SPIHW_MODE_CPHA_BIT = 5 ; 0=sample on leading edge, setup on trailing edge
; ***************************************************************************
; data
.dseg
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine SPIHW_Init @global
;
SPIHW_Init:
sbi SPIHW_SS0_DDR, SPIHW_SS0_PIN ; SS0= output
sbi SPIHW_SS1_DDR, SPIHW_SS1_PIN ; SS1= output
sbi SPIHW_SS2_DDR, SPIHW_SS2_PIN ; SS2= output
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine SPIHW_Fini @global
;
SPIHW_Fini:
ret
; @end
; ---------------------------------------------------------------------------
; @routine SPIHW_MasterStart @global
;
; Start SPI hardware master with the given mode (see @ref SPIHW_MODE_SPEED0_BIT
; and others).
; @param r16 mode
; @param r17 device num (0-7)
; @clobbers r17
SPIHW_MasterStart:
; setup pins
sbi SPIHW_SS_DDR, SPIHW_SS_PIN ; SS : output
sbi SPIHW_MOSI_DDR, SPIHW_MOSI_PIN ; MOSI: output
cbi SPIHW_MISO_DDR, SPIHW_MISO_PIN ; MISO: input
sbi SPIHW_SCK_DDR, SPIHW_SCK_PIN ; SCK: output
; select device
sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS high
rcall spiHwSelectDevice ; (none)
; cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS low
; setup SPCR
clr r17
sbrc r16, SPIHW_MODE_DATAORDER_BIT
sbr r17, (1<<DORD)
sbrc r16, SPIHW_MODE_CPOL_BIT
sbr r17, (1<<CPOL)
sbrc r16, SPIHW_MODE_CPHA_BIT
sbr r17, (1<<CPHA)
sbrc r16, SPIHW_MODE_SPEED0_BIT
sbr r17, (1<<SPR0)
sbrc r16, SPIHW_MODE_SPEED1_BIT
sbr r17, (1<<SPR1)
sbr r17, (1<<SPE) | (1<<MSTR)
M_IO_WRITE SPCR, r17
; setup SPSR
clr r17
sbrc r16, SPIHW_MODE_DOUBLESPEED_BIT
sbr r17, (1<<SPI2X)
M_IO_WRITE SPSR, r17
ret
; @end
; ---------------------------------------------------------------------------
; @routine SPIHW_MasterStop @global
;
; Stop SPI hardware master.
; @clobbers r16
SPIHW_MasterStop:
; sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS high
M_IO_READ r16, SPCR
cbr r16, (1<<SPE)
M_IO_WRITE SPCR, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine spiHwSelectDevice
;
; Select given device via SS0-SS2 pins
;
; @param r17=device
; @clobbers none
spiHwSelectDevice:
cbi SPIHW_SS0_OUTPUT, SPIHW_SS0_PIN
sbrc r17, 0
sbi SPIHW_SS0_OUTPUT, SPIHW_SS0_PIN
cbi SPIHW_SS1_OUTPUT, SPIHW_SS1_PIN
sbrc r17, 1
sbi SPIHW_SS1_OUTPUT, SPIHW_SS1_PIN
cbi SPIHW_SS2_OUTPUT, SPIHW_SS2_PIN
sbrc r17, 2
sbi SPIHW_SS2_OUTPUT, SPIHW_SS2_PIN
ret
; @end
; ---------------------------------------------------------------------------
; @routine SPIHW_MasterTransfer @global
;
; Complete transfer sending ony byte and receiving another.
;
; @param r16 byte to send
; @param r16 byte received
; @clobbers none
SPIHW_MasterTransfer:
rcall SPIHW_MasterSendByte
rjmp SPIHW_WaitForTransferComplete
; @end
; ---------------------------------------------------------------------------
; @routine SPIHW_MasterSendByte @global
;
; Send a byte to the SPI interface. Does not wait for result, you need to
; call @ref SPIHW_WaitForTransferComplete to complete the request and to
; get the response.
; This allows for transfers in background so that the caller can do other stuff
; instead of idly waiting for the transfer to complete.
; However, before calling this routine again you MUST call SPIHW_WaitForTransferComplete!
; @param r16 byte to send
; @clobbers none
SPIHW_MasterSendByte:
M_IO_WRITE SPDR, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine SPIHW_WaitForTransferComplete @global
;
; Wait for a transfer to complete and return the byte received.
;
; @return r16 byte received
; @clobbers none
SPIHW_WaitForTransferComplete:
M_IO_READ r16, SPSR
sbrs r16, SPIF
rjmp SPIHW_WaitForTransferComplete
M_IO_READ r16, SPDR
ret
; @end

View File

@@ -0,0 +1,7 @@
This folder contains multiple backends for hardware UART as provided by some AVR devices.
uart.asm: simple UART code blocking for receiption and transmission
net_uart.asm: glue to connect NET interface to uart.asm
uses interrupt for ATTN line, no other interrupts used

View File

@@ -0,0 +1,102 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine ATTN_Init @global
;
; @clobbers R16
ATTN_Init:
.ifdef INT0
.if COM_IRQ_BIT_ATTN == INT0
M_IO_READ r16, MCUCR
cbr r16, (1<<ISC01) | (1<<ISC00)
sbr r16, (1<<ISC01) | (0<<ISC00) ; falling edge of ATTN
; sbr r16, (0<<ISC01) | (0<<ISC00) ; low level triggers
rcall ATTN_SetHighEnableIrq
ret
; @end
; ---------------------------------------------------------------------------
; @routine ATTN_SetLowDisableIrq @global
;
; @clobbers R16
ATTN_SetLowDisableIrq:
.ifdef INT0
.if COM_IRQ_BIT_ATTN == INT0
M_IO_READ r16, COM_IRQ_ADDR_ATTN ; disable irq for ATTN line
cbr r16, (1<<COM_IRQ_BIT_ATTN)
M_IO_WRITE COM_IRQ_ADDR_ATTN, r16
.endif
.endif
sbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN as output
cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; set ATTN low
ret
; @end
; ---------------------------------------------------------------------------
; @routine ATTN_SetHighEnableIrq @global
;
; @clobbers R16
ATTN_SetHighEnableIrq:
cbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN as input
.ifdef COM_ATTN_PUE
cbi COM_ATTN_PUE, COM_ATTN_PIN ; disable pullup on ATTN
.else
cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; disable pullup on ATTN
.endif
.ifdef INT0
.if COM_IRQ_BIT_ATTN == INT0
M_IO_READ r16, COM_IRQ_ADDR_ATTN ; enable irq for ATTN line
sbr r16, (1<<COM_IRQ_BIT_ATTN)
M_IO_WRITE COM_IRQ_ADDR_ATTN, r16
.endif
.endif
ret
; @end
; ---------------------------------------------------------------------------
; @routine ATTN_IsHigh @global
;
; @return CFLAG set if ATTN is high
; @clobbers none
ATTN_IsHigh:
clc
sbic COM_ATTN_INPUT, COM_ATTN_PIN ; ATTN low?
sec ; yes, set CF
ret
; @end

View File

@@ -10,7 +10,7 @@
.equ COMONUART0_IFACENUM = 1
.equ COMONUART0_READ_TIMEOUT = 3
.equ COMONUART0_MSG_INTERVAL = 1
.equ COMONUART0_MSG_INTERVAL = 0

View File

@@ -0,0 +1,273 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; defines
; ***************************************************************************
; data
.dseg
netUartIface: .byte UART_HW_IFACE_SIZE
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine ComOnUart0_Init @global
;
NET_Uart_Init:
ldi yl, LOW(netUartIface)
ldi yh, HIGH(netUartIface)
rcall UART_HW_Interface_Init
rcall UART_Init
rcall ATTN_Init
ret
; @end
; ---------------------------------------------------------------------------
; @routine NET_Uart_Periodically
;
; @clobbers all, !Y
NET_Uart_Every100ms:
ldi yl, LOW(netUartIface)
ldi yh, HIGH(netUartIface)
push r15
in r15, SREG
cli
rcall NET_Interface_Periodically ; (R16)
rcall netUartSendNextPkg
out SREG, r15
pop r15
ret
rjmp NET_Interface_Periodically
; @end
; ---------------------------------------------------------------------------
; @routine netUartSendNextPkg
;
; Check whether there is an outgoing message in interface data
; and send it if possible.
;
; @return CFLAG set if okay, clear on error
; @param Y pointer to start of interface data
; @clobbers R16, R17, R18, R21, R21, R24, R25, X
netUartSendNextPkg:
rcall NET_Interface_PeekNextOutgoingMsgNum ; (R17, R18, X)
brcc netUartSendNextPkg_end
rcall NET_Buffer_Locate ; get pointer to buffer (R17)
brcc netUartSendNextPkg_end
adiw xh:xl, 1 ; skip buffer header
rcall netUartSendPacketWithAttn ; (R16, R17, R21, R22, X)
brcc netUartSendNextPkg_error
rcall NET_Interface_GetNextOutgoingMsgNum ; remove from stack (R17, R18, X)
rcall NET_Buffer_ReleaseByNum ; release buffer (R16, X)
ldi r16, NET_IFACE_OFFS_PACKETSOUT_LOW
rcall NET_Interface_IncCounter16 ; (R24, R25)
sec
rjmp netUartSendNextPkg_end
netUartSendNextPkg_error:
rcall NET_Interface_IncCounter16 ; (R24, R25)
clc
netUartSendNextPkg_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine netUartSendPacket
;
; @param X buffer to send
; @return CFLAG set if okay, cleared on error
; @return R16 error code (if CFLAG cleared)
; @clobbers R16, R17, R22, X
netUartSendPacketWithAttn:
rcall ATTN_IsHigh
ldi r16, NET_IFACE_OFFS_ERR_BUSY_LOW
brcc netUartSendPacketWithAttn_end ; ATTN low, jmp
rcall ATTN_SetLowDisableIrq ; reserve bus (R16)
Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22 ; wait for one bit duration
Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22 ; wait for one bit duration
rcall netUartSendPacket
rcall ATTN_SetHighEnableIrq ; release bus
sec
netUartSendPacketWithAttn_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine netUartSendPacket
;
; @param X buffer to send
; @clobbers R17 (R16, X)
netUartSendPacket:
adiw xh:xl, NETMSG_OFFS_MSGLEN
ld r17, X
inc r17
inc r17
inc r17
sbiw xh:xl, NETMSG_OFFS_MSGLEN
rjmp UART_SendBytes ; (R16, R17, X)
; @end
; ---------------------------------------------------------------------------
; @routine netUartRecvPacket
;
; alloc a buffer, receive message, add message to global list
; @param Y pointer to start of interface data
; @return CFLAG set if okay, cleared on error
; @clobbers R16, R17, R18, R19, R20, R24, R25, X
netUartRecvPacket:
rcall UART_StartRx ; (R16)
rcall NET_Buffer_Alloc ; (R16, R17, X)
brcs netUartRecvPacket_haveBuf
rcall UART_StopRx ; (R16)
ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW
rjmp netUartRecvPacket_incCounterRet
netUartRecvPacket_haveBuf:
push r16
adiw xh:xl, 1
ldd r18, Y+NET_IFACE_OFFS_ADDRESS
ldi r17, NET_BUFFERS_SIZE-1
rcall netUartRecvPacketIntoX ; (R16, R17, R18, R19, R20, R24, R25)
pop r16
brcc netUartRecvPacket_releaseBufRet
rcall NET_AddIncomingMsgNum ; (R17, R18, X)
brcc netUartRecvPacket_releaseBufRet
rcall UART_StopRx ; (R16)
sec
ret
netUartRecvPacket_releaseBufRet:
rcall NET_Buffer_ReleaseByNum ; (R16, X)
ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW
netUartRecvPacket_incCounterRet:
rcall NET_Interface_IncCounter16 ; (R24, R25)
rcall UART_StopRx ; (R16)
netUartRecvPacket_retNc:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine netUartRecvPacketIntoX
;
; @param Y pointer to start of interface data
; @param X pointer buffer (in RAM)
; @param r17 maximum number of bytes to receive
; @param r18 network address to listen to
; @return CFLAG set if okay, cleared on error
; @clobbers R16, R17, R18, R19, R20, R24, R25
netUartRecvPacketIntoX:
push xh
push xl
rcall UART_RecvPacket ; (r16, r17, X)
pop xl
pop xh
brcc netUartRecvPacketIntoX_handleError
push xl
push xh
rcall NETMSG_CheckMessageInBuffer ; (R16, R17, R18, R19, R20, X)
pop xh
pop xl
brcc netUartRecvPacketIntoX_contentError
ldi r16, NET_IFACE_OFFS_PACKETSIN_LOW
rcall NET_Interface_IncCounter16 ; (R24, R25)
sec
ret
netUartRecvPacketIntoX_handleError:
mov r17, r16
cpi r17, UART_ERROR_IO
ldi r16, NET_IFACE_OFFS_ERR_IO_LOW
breq netUartRecvPacketIntoX_incCounterRetNc
cpi r17, UART_ERROR_CONTENT
breq netUartRecvPacketIntoX_contentError
rjmp netUartRecvPacketIntoX_retNc
netUartRecvPacketIntoX_contentError:
ldi r16, NET_IFACE_OFFS_ERR_CONTENT_LOW
netUartRecvPacketIntoX_incCounterRetNc:
rcall NET_Interface_IncCounter16 ; (R24, R25)
netUartRecvPacketIntoX_retNc:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine NetUart_AttnChangeIsr @global @isr
;
; @clobbers none
NetUart_AttnChangeIsr:
push r15
in r15, SREG
push r16
push r17
push r18
push r19
push r20
push r24
push r25
push xl
push xh
push yl
push yh
ldi yl, LOW(netUartIface)
ldi yh, HIGH(netUartIface)
rcall netUartRecvPacket ; (R16, R17, R18, R19, R20, R24, R25, X)
pop yh
pop yl
pop xh
pop xl
pop r25
pop r24
pop r20
pop r19
pop r18
pop r17
pop r16
out SREG, r15
pop r15
reti
; @end

View File

@@ -9,7 +9,7 @@
.equ TTYONUART1_SKIPTIME = 2
.equ TTYONUART1_MSG_INTERVAL = 2
.equ TTYONUART1_MSG_INTERVAL = 0
.equ TTYONUART1_IFACENUM = 2

View File

@@ -0,0 +1,301 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; defines
.equ UART_ERROR_NOTFORME = 1
.equ UART_ERROR_INVALID = 2
.equ UART_ERROR_IO = 3
.equ UART_ERROR_CONTENT = 4
; ***************************************************************************
; code
.cseg
UART_Init:
; set baudrate
.if clock == 8000000
ldi r16, 25 ; (19.2Kb/s at 8MHz)
ldi r17, 0
.endif
.if clock == 1000000
ldi r16, 2 ; (19.2Kb/s at 1MHz)
ldi r17, 0
.endif
M_IO_WRITE UBRRH, r17
M_IO_WRITE UBRRL, r16
; set character format
.ifdef URSEL
ldi r16, (1<<URSEL) | (1<<USBS) | (1<<UCSZ1) | (1<<UCSZ0)
.else
ldi r16, (1<<USBS) | (1<<UCSZ1) | (1<<UCSZ0)
.endif
M_IO_WRITE UCSRC, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_SendBytes @global
;
; @param X pointer data to send (in RAM)
; @param r17 number of bytes to send
; @clobbers R16, R17, X
UART_SendBytes:
tst r17
breq UART_SendBytes_secRet
rcall UART_StartTx ; (R16)
; send bytes
UART_SendBytes_loop1:
M_IO_READ r16, UCSRA
sbrs r16, UDRE
rjmp UART_SendBytes_loop1
ld r16, X+
M_IO_WRITE UDR, r16
dec r17
brne UART_SendBytes_loop1
; wait until all data sent
UART_SendBytes_loop2:
M_IO_READ r16, UCSRA
sbrs r16, TXC
rjmp UART_SendBytes_loop2
rcall UART_StopTx
UART_SendBytes_secRet:
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_RecvPacket @global
;
; @param X pointer buffer (in RAM)
; @param r17 maximum number of bytes to receive
; @param r18 network address to listen to
; @clobbers r16, r17, X
UART_RecvPacket:
cpi r17, 3
brcs UART_RecvPacket_invalid
rcall uartRecvByteWithin10ms ; recv destination address
brcc UART_RecvPacket_ioError
cp r16, r18
breq UART_RecvPacket_forMe
cpi r16, 0xff
breq UART_RecvPacket_forMe
ldi r16, UART_ERROR_NOTFORME
rjmp UART_RecvPacket_clcRet
UART_RecvPacket_forMe:
st X+, r16 ; dest addr
dec r17
rcall uartRecvByteWithin10ms ; msg len (R16)
brcc UART_RecvPacket_ioError
st X+, r16
dec r17
inc r16 ; account for CRC
cp r17, r16
brcs UART_RecvPacket_badMsg
mov r17, r16
UART_RecvPacket_loop:
rcall uartRecvByteWithin10ms ; (R16)
brcc UART_RecvPacket_ioError
st X+, r16
dec r17
brne UART_RecvPacket_loop
sec
ret
UART_RecvPacket_invalid:
ldi r16, UART_ERROR_INVALID
rjmp UART_RecvPacket_clcRet
UART_RecvPacket_badMsg:
ldi r16, UART_ERROR_CONTENT
rjmp UART_RecvPacket_clcRet
UART_RecvPacket_ioError:
ldi r16, UART_ERROR_IO
UART_RecvPacket_clcRet:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine uartRecvByteWithin10ms
;
; Wait up to 10ms for incoming byte and read it.
;
; @return CFLAG set if okay (data available), cleared on error
; @return r16 byte received (if CFLAG set)
; @clobbers: none
uartRecvByteWithin10ms:
push r20
push r22
rcall uartWaitForData10ms ; (R20, R22)
pop r22
pop r20
brcc uartRecvByteWithin10ms_end
M_IO_READ r16, UCSRA ; check for errors
andi r16, (1<<FE) | (1<<DOR)
brne uartRecvByteWithin10ms_error
M_IO_READ r16, UDR ; read data byte
sec
ret
uartRecvByteWithin10ms_error:
clc
uartRecvByteWithin10ms_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine uartWaitForData10ms
;
; Wait for incoming data for max 10 milliseconds.
;
; @return CFLAG set if okay (data available), cleared on error
; @clobbers: r20, r22
uartWaitForData10ms:
.if clock == 8000000
ldi r20, 80
.endif
.if clock == 1000000
ldi r20, 10
.endif
uartWaitForData10ms_loop:
push r20
rcall uartWaitForData1000Cycles ; (r20, r22)
pop r20
brcs uartWaitForData10ms_gotit
dec r20
brne uartWaitForData10ms_loop
clc
uartWaitForData10ms_gotit:
ret
; @end
; ---------------------------------------------------------------------------
; @routine uartWaitForData1000Cycles
;
; Wait for incoming data for max 1000 clock cycles
; (about 1ms at 1MHz, 0.125 at 8MHz)
;
; @return CFLAG set if okay (packet received), cleared on error
; @clobbers: r20, r22
uartWaitForData1000Cycles:
ldi r20, 140 ; 1
uartWaitForData_loop:
M_IO_READ r22, UCSRA ; 2
sbrc r22, RXC ; 2/3
rjmp uartWaitForData_gotit ; 2
dec r20 ; 1
brne uartWaitForData_loop ; 1/2 -> 7 per loop, max about 1000
clc ; 1
ret ; 4
uartWaitForData_gotit:
sec ; 1
ret ; 4
; @end
; ---------------------------------------------------------------------------
; @routine UART_StartRx @global
;
; @clobbers R16
UART_StartRx:
M_IO_READ r16, UCSRA ; clear errors
cbr r16, (1<<FE) | (1<<DOR) | (1<<UPE)
sbr r16, (1<<RXC)
M_IO_WRITE UCSRA, r16
M_IO_READ r16, UCSRB
sbr r16, (1<<RXEN) ; enable receive
M_IO_WRITE UCSRB, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_StopRx @global
;
; @clobbers R16
UART_StopRx:
M_IO_READ r16, UCSRB
cbr r16, (1<<RXCIE | (1<<RXEN)) ; disable RX complete interrupt, disable receive
M_IO_WRITE UCSRB, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_StartTx @global
;
; @param Y pointer to interface data in SRAM (see @ref UART_HW_IFACE_OFFS_STATE)
; @clobbers R16
UART_StartTx:
M_IO_READ r16, UCSRA
sbr r16, (1<<TXC) ; clear TXC interrupt
M_IO_WRITE UCSRA, r16
M_IO_READ r16, UCSRB
sbr r16, (1<<TXEN) ; enable transceive
M_IO_WRITE UCSRB, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_StopTx @global
;
; @param Y pointer to interface data in SRAM (see @ref UART_HW_IFACE_OFFS_STATE)
; @clobbers R16
UART_StopTx:
M_IO_READ r16, UCSRB
cbr r16, (1<<UDRIE) | (1<<TXC) | (1<<TXEN) ; disable TX UDRE and TXC1 interrupt, enable transceive
M_IO_WRITE UCSRB, r16
ret
; @end

11
avr/modules/xram/0BUILD Normal file
View File

@@ -0,0 +1,11 @@
<?xml?>
<gwbuild>
<extradist>
main.asm
</extradist>
</gwbuild>

106
avr/modules/xram/main.asm Normal file
View File

@@ -0,0 +1,106 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; defines
; ***************************************************************************
; data
.dseg
xramLastAddress: .byte 2
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine XRAM_Init @global
;
XRAM_Init:
clr r16
sts xramLastAddress, r16
sts xramLastAddress+1, r16
M_IO_READ r16, MCUCR
sbr r16, (1<<SRE)
M_IO_WRITE MCUCR, r16
rcall xramWritePattern
rcall xramVerifyPattern
ret
; @end
; ---------------------------------------------------------------------------
; @routine XRAM_Fini @global
;
XRAM_Fini:
ret
; @end
; ---------------------------------------------------------------------------
; @routine xramWritePattern
;
; Write a pattern to memory (high byte of address)
xramWritePattern:
ldi xl, LOW(RAMEND+1)
ldi xh, LOW(RAMEND+1)
xramWritePattern_loop:
mov r16, xh
st X, r16
adiw xh:xl, 1
brne xramWritePattern_loop
ret
; @end
; ---------------------------------------------------------------------------
; @routine xramVerifyPattern
;
; Write a pattern to memory (high byte of address)
xramVerifyPattern:
ldi xl, LOW(RAMEND+1)
ldi xh, LOW(RAMEND+1)
xramVerifyPattern_loop:
mov r16, xh
ld r17, X
cp r16, r17
brne xramVerifyPattern_end
adiw xh:xl, 1
brne xramVerifyPattern_loop
xramVerifyPattern_end:
sbiw xh:xl, 1
sts xramLastAddress, xl
sts xramLastAddress+1, xh
ret
; @end

64
flashnode.sh Executable file
View File

@@ -0,0 +1,64 @@
#!/bin/bash
NODE="$1"
if test -z "$NODE"; then
echo "Missing node"
exit 1
fi
case $NODE in
c01)
DEVICE_ARG="-p m8515"
HFUSE_ARG="-U hfuse:w:0xD1:m"
LFUSE_ARG="-U lfuse:w:0xE4:m"
FILE_ARG="-U flash:w:./0-build/avr/devices/c01/boot/c01_boot.hex"
;;
n21)
DEVICE_ARG="-p t84"
HFUSE_ARG="-U hfuse:w:0xD7:m"
LFUSE_ARG=""
EFUSE_ARG="-U efuse:w:0xFE:m"
FILE="-U flash:w:./0-build/avr/devices/n21/boot/n21_boot.hex"
;;
n22)
DEVICE_ARG="-p t85"
HFUSE_ARG="-U hfuse:w:0xD7:m"
LFUSE_ARG=""
EFUSE_ARG="-U efuse:w:0xFE:m"
FILE_ARG="-U flash:w:./0-build/avr/devices/n22/boot/n22_boot.hex"
;;
n23)
DEVICE_ARG="-p t84"
HFUSE_ARG="-U hfuse:w:0xD7:m"
LFUSE_ARG=""
EFUSE_ARG="-U efuse:w:0xFE:m"
FILE_ARG="-U flash:w:./0-build/avr/devices/n21/boot/n21_boot.hex"
;;
n24)
DEVICE_ARG="-p t84"
HFUSE_ARG="-U hfuse:w:0xD7:m"
LFUSE_ARG=""
EFUSE_ARG="-U efuse:w:0xFE:m"
FILE_ARG="-U flash:w:./0-build/avr/devices/n23/boot/n23_boot.hex"
;;
t03)
DEVICE_ARG="-p t841"
HFUSE_ARG="-U hfuse:w:0xD7:m"
LFUSE_ARG=""
EFUSE_ARG="-U efuse:w:0xFE:m"
FILE_ARG="-U flash:w:./0-build/avr/devices/t03/boot/t03_boot.hex"
;;
*)
echo "Unknown node $NODE".
exit 1
;;
esac
echo "avrdude -c stk500 -P /dev/ttyACM0 -B16 $DEVICE_ARG $HFUSE_ARG $LFUSE_ARG $EFUSE_ARG $FILE_ARG"
avrdude -c stk500 -P /dev/ttyACM0 -B16 $DEVICE_ARG $HFUSE_ARG $LFUSE_ARG $EFUSE_ARG $FILE_ARG