started working on AtMega8515 module C1.

This commit is contained in:
Martin Preuss
2025-05-17 10:50:09 +02:00
parent 5a46db37c1
commit 21c2c60f4f
29 changed files with 1893 additions and 422 deletions

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

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,151 @@
; ***************************************************************************
; 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

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,163 @@
; ***************************************************************************
; 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"
.include "modules/com2/defs.asm"
.include "modules/comproto/defs.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:
#if 0 ; disabled (can't really change clock at runtime)
.if clock == 8000000
ldi r16, (1<<CLKPCE)
ldi r17, 0
out CLKPR, r16
out CLKPR, r17
.endif
.if clock == 1000000
ldi r16, (1<<CLKPCE)
ldi r17, (1<<CLKPS1) | (1<<CLKPS0)
out CLKPR, r16
out CLKPR, r17
.endif
#endif
ret

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

@@ -0,0 +1,108 @@
; ***************************************************************************
; 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
; ---------------------------------------------------------------------------
; 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,231 @@
; ***************************************************************************
; 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. *
; ***************************************************************************
; ***************************************************************************
; Source file for temperature sensor node on AtTiny 84
;
; This is for the full system (i.e. not the boot loader).
;
; All definitions and changes should go into this file.
;
;
; ***************************************************************************
;.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 = 6
.equ NET_BUFFERS_SIZE = 32
.equ PROGRAM_SENSOR_INTERVAL_SECS = 60
.equ PROGRAM_STATS_INTERVAL_MINS = 10
; ---------------------------------------------------------------------------
; 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_LED_SIMPLE
;#define MODULES_NETWORK
;#define MODULES_COMONUART0
;#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 ComOnUart0_AttnChangeIsr ; 2: INT0 External Interrupt Request 0
reti
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
; rjmp ComOnUart0_RxCharIsr ; 10: USART_RXC USART Rx Complete
reti
; rjmp ComOnUart0_TxUdreIsr ; 11: USART_UDRE USART Data Register Empty
reti
; rjmp ComOnUart0_TxCharIsr ; 12: USART_TXC USART Tx Complete
reti
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 = comonuart0_iface

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

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

@@ -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

@@ -281,7 +281,7 @@ ioRawReceiveByte_error:
; @clobbers R16, R22 (R17, R21, X)
ioRawSendPacket:
rcall ioRawAcquireBus
rcall ioRawAcquireBus ; (none)
brcc ioRawSendPacket_lineBusyError
rcall ioRawWaitForOneBitLength ; wait for one bit duration (R22)
@@ -316,47 +316,6 @@ ioRawSendPacket_lineBusyError:
; ---------------------------------------------------------------------------
; @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)
ret
; @end
; ---------------------------------------------------------------------------
; @routine ioRawSendByte
;

View File

@@ -0,0 +1,32 @@
; ***************************************************************************
; 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_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,495 @@
; ***************************************************************************
; 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)
ldi r16, (1<<UART_BIT_UCSZ0) | (1<<UART_BIT_UCSZ1)
sts 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

View File

@@ -33,14 +33,19 @@ ComOnUart0_Init:
rcall comOnUart0SetAttnInput ; (none)
rcall UART_HW_Interface_Init ; (R16, R17, X)
rcall comOnUart0Init ; (R16, R17, X)
rcall comOnUart0Init ; (R16, R17, X)
ldi r16, COMONUART0_IFACENUM
std Y+NET_IFACE_OFFS_IFACENUM, r16
sbi COM_IRQ_ADDR_ATTN, COM_IRQ_BIT_ATTN ; enable pin change irq for ATTN line
in r16, GIMSK ; enable pin change irq PCIE0 or PCIE1
ori r16, (1<<COM_IRQ_GIMSK_ATTN)
out GIMSK, R16
M_IO_READ r16, COM_IRQ_ADDR_ATTN ; enable irq for ATTN line
sbr r16, COM_IRQ_BIT_ATTN
M_IO_WRITE COM_IRQ_ADDR_ATTN, r16
.ifdef COM_IRQ_GIMSK_ATTN
M_IO_READ r16, GIMSK ; enable pin change irq PCIE0 or PCIE1
sbr r16, (1<<COM_IRQ_GIMSK_ATTN)
M_IO_WRITE GIMSK, R16
.endif
ldi r16, (1<<COM_IRQ_GIFR_ATTN) ; clear pending irq by writing 1 to ATTN bit
out GIFR, r16

View File

@@ -120,7 +120,7 @@ l_loop_%:
lds r16, UCSR@0A
sbrs r16, RXC@0
rjmp l_end_%
lds r16, UDR@0
lds r16, USART@0_DATAREG
clr r16
std Y+NET_IFACE_OFFS_READTIMER, r16
rjmp l_loop_%
@@ -146,7 +146,7 @@ l_end_%:
lds r16, UCSR@0A
sbrs r16, RXC@0
rjmp l_end_% ; no data
lds r16, UDR@0 ; r16=received char
lds r16, USART@0_DATAREG ; r16=received char
; check read mode
ldd r17, Y+UART_HW_IFACE_OFFS_READMODE
cpi r17, UART_HW_READMODE_READING
@@ -239,7 +239,7 @@ l_end_%:
lds r16, UCSR@0A
sbrs r16, RXC@0
rjmp l_end_% ; no data
lds r16, UDR@0 ; r16=received char
lds r16, USART@0_DATAREG ; r16=received char
; check read mode
ldd r17, Y+UART_HW_IFACE_OFFS_READMODE
cpi r17, UART_HW_READMODE_READING
@@ -355,7 +355,7 @@ l_end_%:
std Y+UART_HW_IFACE_OFFS_WRITEBUFLEFT, r17
; send byte, reset write timer
sts UDR@0, r16
sts USART@0_DATAREG, r16
clr r16
std Y+NET_IFACE_OFFS_WRITETIMER, r16 ; reset write timer