985 lines
24 KiB
Plaintext
985 lines
24 KiB
Plaintext
|
||
|
||
|
||
MODULE_INFO
|
||
- descr:
|
||
- one MODULE_INFO for every module
|
||
- can share code (e.g. use multiple MODULE_INFOs for different pins in PinOut module)
|
||
- def:
|
||
- name[16]
|
||
- id
|
||
- handlerFunctionAddr()
|
||
- code:
|
||
.equ MODULE_INFO_HANDLER_LO = 0
|
||
.equ MODULE_INFO_HANDLER_HI = 1
|
||
.equ MODULE_INFO_ID = 2
|
||
.equ MODULE_INFO_NAME = 4
|
||
.equ MODULE_INFO_SIZE = 12
|
||
|
||
|
||
SIGNAL_TABLE:
|
||
- descr:
|
||
- one table for every signal a module can emit
|
||
- def:
|
||
- array of SLOT objects (end of array: 0x0000)
|
||
|
||
|
||
SLOT:
|
||
- descr:
|
||
- one SLOT for every module which is waiting for this signal
|
||
- def:
|
||
- MODULE_INFO *modInfoPtr (16 bit)
|
||
- signalIdForCaller (8 bit)
|
||
- signalIdForCallee (8 bit)
|
||
|
||
|
||
|
||
|
||
Initial module:
|
||
- OS
|
||
- sent signals:
|
||
- init
|
||
- fini
|
||
- receivable signals:
|
||
- sleep
|
||
- hardReset
|
||
- softReset
|
||
|
||
|
||
Other modules:
|
||
- Timer
|
||
- sent signals:
|
||
- 1Hz
|
||
- 10Hz
|
||
- 100Hz
|
||
|
||
- PinOut
|
||
- receivable signals:
|
||
- setValue
|
||
- setOnDuration
|
||
- setOffDuration
|
||
- sent signals:
|
||
- none
|
||
|
||
|
||
|
||
|
||
Module_EmitSignal:
|
||
- params:
|
||
- senderId (8 bit) R16
|
||
- signalIdForSender (8 bit, unique in the realm of the sender) R17
|
||
- slotIdForRecipient (8 bit, unique in the realm of the recipient) R18
|
||
- paramLo (8 bit) R26 (YL)
|
||
- paramHi (8 bit) R27 (YH)
|
||
- recipientModule R30 (ZL), R31 (ZH) (16 bit)
|
||
|
||
|
||
Notes:
|
||
- R24 und R25: 16 register (supports ADIW and SBIW)
|
||
- for RAM access: R26-R31 (X, Y, Z)
|
||
- for flash memory access: R0 and Z (R30/31)
|
||
- in INT: use R15 for flags
|
||
- for everything else: R1-R14
|
||
- LDI only for upper 16 regs
|
||
|
||
|
||
Generic signals from OS module:
|
||
- init
|
||
- fini
|
||
- request (REQUEST flag for a module can be set by an interrupt handler to request that the corresponding
|
||
module be called as soon as the event handler loop is reached)
|
||
|
||
|
||
<moduledef name="os" ramSizeNeeded="2"> <!-- 16 bit request mask, maximum 16 modules for now -->
|
||
<signals>
|
||
<signal name="1Hz" />
|
||
</signals>
|
||
|
||
<interrupts>
|
||
<irq id="EXT_INT0" handler="AQOS_Timer_Int0" />
|
||
</interrupts>
|
||
|
||
</moduledef>
|
||
|
||
|
||
|
||
|
||
<moduledef name="timer">
|
||
<signals>
|
||
<signal name="100Hz" />
|
||
<signal name="10Hz" />
|
||
<signal name="1Hz" />
|
||
</signals>
|
||
|
||
<interrupts>
|
||
<irq id="EXT_INT0" handler="AQOS_Timer_Int0" />
|
||
</interrupts>
|
||
|
||
</moduledef>
|
||
|
||
|
||
<moduledef name="togglePort" ramSizeNeeded="2" >
|
||
<depModules>
|
||
<depModule name="timer" />
|
||
</depModules>
|
||
|
||
|
||
<signals>
|
||
<signal name="100Hz" />
|
||
<signal name="10Hz" />
|
||
<signal name="1Hz" />
|
||
</signals>
|
||
|
||
<slots>
|
||
<slot name="timer10Hz" />
|
||
<slot name="setValue" />
|
||
<slot name="setOnDuration" />
|
||
<slot name="setOffDuration" />
|
||
</slots>
|
||
|
||
<connections>
|
||
<connect module="timer" signalId=10Hz" slotId="timer10Hz" />
|
||
</connections>
|
||
|
||
</moduledef>
|
||
|
||
|
||
<moduledef name="inputPinChange" ramSizeNeeded="8"> <!-- current state of ports a..d and change masks -->
|
||
<signals>
|
||
<signal name="aPortChanged" />
|
||
<signal name="bPortChanged" />
|
||
<signal name="cPortChanged" />
|
||
<signal name="dPortChanged" />
|
||
</signals>
|
||
|
||
<interrupts>
|
||
<irq id="PCI0" handler="AQOS_InputPinChange_PCI0" />
|
||
<irq id="PCI1" handler="AQOS_InputPinChange_PCI1" />
|
||
</interrupts>
|
||
|
||
<slots>
|
||
<slot name="request" />
|
||
</slots>
|
||
|
||
|
||
irq handler:
|
||
- for every port:
|
||
- is port change mask 0? -> SET new mask, otherwise OR new mask with old mask
|
||
-> gracefully handling overrun (e.g. a new PIN change before the previous one was handled)
|
||
|
||
req handler:
|
||
- for every port:
|
||
- is port change mask 0? -> emit aPortChanged(currentPortValue, portChangeMask), clear mask
|
||
|
||
</moduledef>
|
||
|
||
|
||
|
||
|
||
File format:
|
||
|
||
IRQ-Table
|
||
|
||
.include "os/rqhandlers.inc"
|
||
.include "timer/irqhandlers.inc"
|
||
.include "toggleport/irqhandlers.inc"
|
||
|
||
|
||
.equ MODULE_ID_OS = 0
|
||
.equ MODULE_ID_TIMER = 1
|
||
.equ MODULE_ID_TOGGLEPORT = 2
|
||
|
||
|
||
.equ TIMER_USE_100Hz = 1
|
||
.equ TIMER_USE_10Hz = 1
|
||
.equ TIMER_USE_10z = 1
|
||
|
||
; in file timer/modinfo.inc
|
||
|
||
; timer module
|
||
modInfoTimer:
|
||
.db "TIMER ", 0 ; name
|
||
.db MODULE_ID_TIMER, 0 ; id, reserved byte (0)
|
||
.dw timerSignalHandler ; handler
|
||
|
||
.equ TIMER_SIG_1HZ = 1
|
||
|
||
.equ TIMER_SLOT_INIT = 0
|
||
.equ TIMER_SLOT_FINI = 1
|
||
|
||
|
||
|
||
; in file toggleport/module.inc
|
||
|
||
; toggleport module
|
||
.equ TOGGLEPORT_SLOT_OS_INIT = 0
|
||
.equ TOGGLEPORT_SLOT_OS_FINI = 1
|
||
.equ TOGGLEPORT_SLOT_TIMER_1HZ = 2
|
||
|
||
|
||
|
||
|
||
; in main source file
|
||
|
||
; signal table for timer
|
||
timerSignalTable:
|
||
.db TIMER_SIG_1HZ, TOGGLEPORT_SLOT_TIMER_1HZ, LOW(modInfoTogglePort), HIGH(modInfoTogglePort)
|
||
.db 0, 0, 0, 0 ; last entry
|
||
|
||
|
||
|
||
|
||
|
||
Assembler:
|
||
- generate automatic list of modified registers
|
||
|
||
|
||
.object test1 {
|
||
.sram {
|
||
Testdata:
|
||
.bytes 16
|
||
}
|
||
|
||
.eprom {
|
||
}
|
||
|
||
.code {
|
||
}
|
||
}
|
||
|
||
|
||
|
||
function test1 {
|
||
ld r16, 10
|
||
l1:
|
||
dec r16
|
||
brne l1
|
||
ret
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
Hardware:
|
||
|
||
AtTiny 84
|
||
=========
|
||
----------
|
||
VCC + 1 14 + GND
|
||
(PCINT8, XTAL1, CLKI) PB0 + 2 13 + PA0 (ADC0, AREF, PCINT0) IN/OUT
|
||
(PCINT9, XTAL2) PB1 + 3 12 + PA1 (ADC1, AIN0, PCINT1) WAN-DATA
|
||
(PCINT11, RESET, dW) PB3 + 4 11 + PA2 (ADC2, AIN1, PCINT2) IN/OUT [LED (red)]
|
||
KEY->IRQ_PCI1 (PCINT10, INT0, OC0A, CKOUT) PB2 + 5 10 + PA3 (ADC3, T0, PCINT3) LED (green)
|
||
WAN-ATTN(PCI0)(PCINT7, ICP1, OC0B, ADC7) PA7 + 6 9 + PA4 (ADC4, USCK, SCL, T1, PCINT4) I2C, SPI
|
||
I2C, SPI (PCINT6, OC1A, SDA, MOSI, DI, ADC6) PA6 + 7 8 + PA5 (ADC5, DO, MISO, OC1B, PCINT5) SPI
|
||
----------
|
||
|
||
|
||
AtTiny 85
|
||
=========
|
||
----------
|
||
(PCINT5, /RESET, ADC0, dW) PB5 + 1 8 + VCC
|
||
WAN-ATTN (PCINT3, XTAL1, CLKI, /OC1B, ADC3) PB3 + 2 7 + PB2 (SCK, USCK, SCL, ADC1, T0, INT0, PCINT2)
|
||
WAN-DATA (PCINT4, XTAL2, CLKO, OC1B, ADC2) PB4 + 3 6 + PB1 (MISO, DO, AIN1, OC0B, OC1A, PCINT1)
|
||
GND + 4 5 + PB0 (MOSI, DI, SDA, AIN0, OC0A, /OC1A, AREF, PCINT0)
|
||
----------
|
||
|
||
|
||
|
||
ADC = ADC Input Channel
|
||
AREF = External Analog Reference
|
||
PCINT = Pin Change Interrupt
|
||
AIN = Analog Comparator Input (0=positive, 1=negative input)
|
||
T0 = Timer/Counter0 Clock Source
|
||
T1 = Timer/Counter1 Clock Source
|
||
USCK = USI Clock (Three Wire Mode)
|
||
SCL = USI Clock (I2C Mode=
|
||
DO = USI Data Output (Three Wire Mode)
|
||
MISO = SPI Master Data Input / Slave Data Output (Three Wire Mode)
|
||
OC0A = Timer/Counter0 Compare Match A Output
|
||
OC0B = Timer/Counter0 Compare Match B Output
|
||
OC1A = Timer/Counter1 Compare Match A Output
|
||
OC1B = Timer/Counter1 Compare Match B Output
|
||
SDA = USI Data Input (I2C Mode)
|
||
MOSI = SPI Data Master Output/Slave Data Input (Three Wire Mode)
|
||
ICP1 = Timer/Counter1 Input Capture Pin
|
||
|
||
|
||
|
||
WAN-ATTN -> irq PCI0
|
||
KEY -> irq PCI1
|
||
PA0 -> in/out1
|
||
PA2 -> in/out2
|
||
PA3 -> LED
|
||
PA4-6: I2C, SPI
|
||
|
||
|
||
|
||
WAN-Communication:
|
||
|
||
WAN-Protocol (UART 9600bps 8N1)
|
||
|
||
|
||
104us pro bit bei 9600bps, about 1040us per byte, about 8.3ms per 8 bytes
|
||
|
||
52us 104us 104us 104us 104us 104us 104us 104us 104us 104us 104us
|
||
INACTIVE START 0 1 2 3 4 5 6 7 STOP INACTIVE
|
||
- DATA ~11111111 00000000 00000000 00000000 11111111 00000000 11111111 00000000 11111111 00000000 11111111 11111111 11~
|
||
- /ACTIVE ~11100000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000 11111111 11~
|
||
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (repeat for every byte)
|
||
|
||
|
||
|
||
Sensors:
|
||
- Erd-Feuchtigkeitssensor:
|
||
https://www.mouser.de/ProductDetail/M5Stack/U019?qs=sGAEpiMZZMu2rInN%2FZRmFkkq%2FqtywxsmOLlgBBfclSVLB6YzCank4Q%3D%3D
|
||
|
||
|
||
- rename WAN -> inc (inter-node-communication)
|
||
- INC messages:
|
||
- 1 byte : dest address [not saved]
|
||
- 1 byte : msg length (not including dest address, msg length and xor byte) [not saved]
|
||
- n bytes: data
|
||
- 1 byte : XOR checksum [not saved]
|
||
|
||
Packet in buffer:
|
||
- 1 byte: buffer length
|
||
- 1 byte: flags
|
||
- 1 byte: dest address
|
||
- 1 byte: msg data
|
||
|
||
|
||
- receivePacket:
|
||
- recv dest address
|
||
- matches?
|
||
- no: finished
|
||
- recv msg size
|
||
- too big?
|
||
- yes: ABORT
|
||
- alloc buffer (msg size +1)
|
||
- error?
|
||
- yes: ABORT
|
||
- write to buffer: size+0x80 (0x80: READ)
|
||
- for every msg size byte: receive byte
|
||
- receive XOR byte
|
||
- check XOR checksum
|
||
- 0?
|
||
- no: ABORT, DeallocBufferBack
|
||
|
||
|
||
|
||
|
||
Infrastructure, what's next
|
||
===========================
|
||
|
||
- build PC module to read and write control messages
|
||
- make WAN code in AVR stable
|
||
- implement command to write debug messages to PC via WAN
|
||
|
||
- node
|
||
- unit (e.g. environment, presence, door, power) [defines per unit type, use uint8_t values]
|
||
- value (e.g. temp, humidity, pressure, light)
|
||
|
||
- addresses:
|
||
- 8-bits total, but:
|
||
- bit 7=0: bit 0-6 contains a node address (i.e. max 127 node devices)
|
||
- bit 7=1, bit 6=0: bits 0-5 contain id of a group:
|
||
- nodes with window/door status
|
||
- nodes with alarm output (e.g. horn, bell or or sms)
|
||
- nodes with environmental readouts (temp, humidity etc.)
|
||
- 240+: special ids
|
||
- 252: timekeeper node
|
||
- 253: id of database node
|
||
- 254: id of a router node to upper layers (e.g. room -> appartement -> floor -> house)
|
||
- 255: broadcast (every node)
|
||
- 0: only unassigned nodes (used when assigning an address)
|
||
|
||
- nodes:
|
||
- database node
|
||
- contains a list of known nodes and their modules and addresses on a bus
|
||
- router node
|
||
- forwards upwards in the hierarchy (e.g. from room to appartement level)
|
||
|
||
- commands:
|
||
- ping
|
||
- announce device
|
||
- used to assign a 8-bit device id on a bus
|
||
- needs a 8-byte serial number for the device
|
||
- assign device id
|
||
- response from a database node to "announce device"
|
||
- announce module
|
||
- make information about a module on a node available to a central node (or other interested nodes)
|
||
- announce value
|
||
- make info about data available
|
||
- value data
|
||
- announce changes in a given module
|
||
- RQ: set value
|
||
- allow to change a value
|
||
- RSP: set value (response to set value request)
|
||
- request value info
|
||
- make the node send the current value of a given module
|
||
- time (date, time, day/night flag)
|
||
|
||
|
||
Bauteile fuer Platine:
|
||
- Widerstaende:
|
||
- 1K fuer LEDs
|
||
- 1K fuer Pull-up (UART lines)
|
||
- 100 Ohm serial inline (UART lines)
|
||
- 4K7/10K fuer Pull-up (I2C lines)
|
||
- Kondensatoren:
|
||
- 10 microF (fuer Spannungsregler)
|
||
- 100nF (Abblockkondensatoren fuer Chips)
|
||
- Chips:
|
||
- HT7333 (3V3 Spannungsregler
|
||
- 74LS21: Dual 4-Port AND Gate (OpenCollector Outputs)
|
||
- 74LS03, 74LS04: Interface for usbserial (OpenCollector Outputs)
|
||
|
||
|
||
|
||
Memory Layout:
|
||
- 0x0000-0x003f: Reset and IRQ vectors
|
||
- 0x0020-0x04ff: base system (1248 words, starting with irq table)
|
||
- 0x0500-end : main system starting with IRQ table (2816 words)
|
||
|
||
|
||
Interrupt-Vektoren:
|
||
- bei aktivem base system:
|
||
- rjmp PC+0x020 (0xc01f)
|
||
- bei aktivem main system:
|
||
- rjmp PC+0x500 (0xc4ff)
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
; with temp1
|
||
; AtTiny84
|
||
; --------
|
||
; VCC 1 14 GND
|
||
; PB0 2 13 PA0
|
||
; PB1 3 12 PA1 COM-DATA
|
||
; /RESET PB3 4 11 PA2
|
||
; KEY1 PB2 5 10 PA3 LED
|
||
; COM_ATTN PA7 6 9 PA4 TWI-SCL
|
||
; TWI-SDA PA6 7 8 PA5
|
||
; --------
|
||
|
||
|
||
|
||
; with temp2
|
||
; AtTiny84
|
||
; --------
|
||
; VCC 1 14 GND
|
||
; PB0 2 13 PA0
|
||
; PB1 3 12 PA1 COM-DATA
|
||
; /RESET PB3 4 11 PA2 OWI
|
||
; KEY1 PB2 5 10 PA3 LED
|
||
; COM_ATTN PA7 6 9 PA4
|
||
; PA6 7 8 PA5
|
||
; --------
|
||
|
||
|
||
|
||
; with pwm
|
||
; AtTiny84
|
||
; --------
|
||
; VCC 1 14 GND
|
||
; PB0 2 13 PA0
|
||
; FAN1-IN PB1 3 12 PA1 COM-DATA
|
||
; /RESET PB3 4 11 PA2 OWI
|
||
; KEY1 PB2 5 10 PA3 LED
|
||
; COM_ATTN PA7 6 9 PA4 FAN2-IN
|
||
; PWM1-OUT PA6 7 8 PA5 PWM2-OUT
|
||
; --------
|
||
|
||
|
||
|
||
; with optic door/window sensors
|
||
; AtTiny84
|
||
; --------
|
||
; VCC 1 14 GND
|
||
; PB0 2 13 PA0 DOOR-ADC1
|
||
; DOOR-ADC2 PB1 3 12 PA1 COM-DATA
|
||
; /RESET PB3 4 11 PA2
|
||
; KEY1 PB2 5 10 PA3 LED
|
||
; COM_ATTN PA7 6 9 PA4 TWI-SCL
|
||
; TWI-SDA PA6 7 8 PA5
|
||
; --------
|
||
|
||
|
||
|
||
; generic node 5
|
||
; AtTiny84
|
||
; --------
|
||
; VCC 1 14 GND
|
||
; PB0 2 13 PA0
|
||
; DOOR-ADC1 PB1 3 12 PA1 COM-DATA
|
||
; /RESET PB3 4 11 PA2
|
||
; PB2 5 10 PA3 LED
|
||
; COM_ATTN PA7 6 9 PA4 TWI-SCL
|
||
; TWI-SDA PA6 7 8 PA5 DOOR-ADC0 (CNY70 Collector)
|
||
; --------
|
||
|
||
|
||
|
||
; AtTiny85
|
||
; --------
|
||
; /RESET PB5 1 8 VCC
|
||
; COM-ATTN PB3 2 7 PB2 TWI-SCL
|
||
; COM-DATA PB4 3 6 PB1 LED
|
||
; GND 4 5 PB0 TWI-SDA
|
||
; --------
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
format of an intel hex file:
|
||
|
||
:02 0000 02 0000 FC
|
||
| | | | |
|
||
| | | | checksum = -(len + addrlow+addrHigh+every_data_byte)
|
||
| addr | data
|
||
length record type (02=extended segment address record)
|
||
|
||
|
||
|
||
:10 0000 00 34 C8 18 95 7E C1 18 95 18 95 18 95 18 95 18 95 A7
|
||
:10 0100 00 02 E0 09 BF 08 95 08 95 FF B6 F8 94 00 27 10 91 02
|
||
|
||
|
||
see https://developer.arm.com/documentation/ka003292/latest
|
||
|
||
record types:
|
||
00 data record;
|
||
01 End of file record. Usually, it is 00000001FF
|
||
02 Extended Segment address record. This indicates segment base address when 16 bits is not enough for addressing memory;
|
||
[ 03 Start segment address record. Indicates initial segment base address.]
|
||
04 Extended Linear Address Record allows 32 bit addressing.
|
||
05 Start Linear Address Record.
|
||
|
||
for record type 2:
|
||
- should be 0 for attiny
|
||
- real address is segment address from record type 2 left-shifted by 4 bits + address in data segments, e.g.:
|
||
adress from data record: 2462
|
||
type 2 address: 1200 <- shift left by 4
|
||
resulting address: 00014462
|
||
|
||
for type 4 (start address of appication):
|
||
- data part contains full 32-bit address
|
||
|
||
|
||
int writehex( FILE *fp, ulong adr, uchar *data, int len )
|
||
|
||
{
|
||
|
||
if( len ){
|
||
|
||
int pruef;
|
||
|
||
fprintf( fp, ":%02X%04lX00", len, adr );
|
||
|
||
pruef = len + (adr & 0xFF) + (adr >> 8);
|
||
|
||
for(; len--; data++){
|
||
|
||
fprintf( fp, "%02X", *data );
|
||
|
||
pruef += *data;
|
||
|
||
}
|
||
|
||
fprintf( fp, "%02X\r\n", -pruef & 0xFF );
|
||
|
||
return 1;
|
||
|
||
}
|
||
|
||
fputs( ":00000001FF\r\n", fp );
|
||
|
||
return 1;
|
||
|
||
}
|
||
|
||
|
||
Das Attiny-Projekt O Der Bootloader 4
|
||
ldi temp, LOW(RAMEND) ; Stackpointer auf RAMEND setzen
|
||
out SPL, temp
|
||
GuckObStarten:
|
||
sbis pinD, DTR ; DTR = 0 bzw. Taster Ta1 geschlossen -> BOOTLOADER,
|
||
; sonst Anwender-Programm
|
||
rjmp Start
|
||
rjmp $079F ; Sprung zum Anwender-Programm
|
||
Start:
|
||
sbi ddrd, LED ; f<>r Anzeige LED
|
||
sbi portD, LED ; Anzeige: LED an D.5 an, wenn Bootloading
|
||
sbis pinD, DTR ; warten bis DTR = 1 bzw. Ta1 offen
|
||
rjmp Start
|
||
|
||
; UART initialisieren:
|
||
sbi UCSRB, 4 ; UCR=UCSRB=0x0B RXEN=Bit4 RX aktivieren
|
||
sbi UCSRB, 3 ; UCR=UCSRB=0x0B UDRE=Bit3 TX aktiv
|
||
ldi uartparam, 4000000/(9600*16)-1 ;Baudrate 9600 einstellen
|
||
out UBRRL, uartparam
|
||
rcall rdcom ; warten auf Startbyte
|
||
cbi portd, LED ; LED an D.5 aus, wenn Startbyte erhalten
|
||
ldi param, 105 ; ACK senden
|
||
rcall wrcom
|
||
MainSchlaufe:
|
||
rcall rdcom
|
||
mov command, param
|
||
B201: ; Block (Page) schreiben
|
||
cpi command, 201
|
||
brne B203
|
||
rcall Schreib_Block
|
||
ldi param, 1 ; ACK Block_Schreiben
|
||
rcall wrcom
|
||
B203: ; Anwender-Programm starten
|
||
cpi command, 203
|
||
brne zurueck ; Wenn keine Zahl zutrifft zum Anfang
|
||
ldi param, 11 ; ACK Ende des Uploads
|
||
rcall wrcom
|
||
rcall warte1ms ; 1 ms warten
|
||
cbi UCSRB, 4 ; RX deaktivieren
|
||
cbi UCSRB, 3 ; TX deaktivieren
|
||
rjmp $03AF
|
||
zurueck:
|
||
rjmp MainSchlaufe
|
||
|
||
|
||
|
||
Schreib_Block:
|
||
ldi r23, PageSize4313
|
||
rcall rdcom ; Block-Adresse vom Master
|
||
mov ZH, r16
|
||
rcall rdcom
|
||
mov ZL, r16
|
||
Loeschen: ; Block loeschen
|
||
ldi r22, 3
|
||
out spmcsr, r22
|
||
spm
|
||
Puffer_Schreib_Schleife: ; alle Woerter des Blocks einzeln in den Puffer
|
||
; r1:r0 uebertragen
|
||
rcall rdcom
|
||
mov r0, r16
|
||
rcall rdcom
|
||
mov r1, r16
|
||
ldi r22, 1 ; Puffer schreiben
|
||
out spmcsr, r22
|
||
spm
|
||
|
||
adiw ZL, 2 ; Flash-Adresse um 1 Word erhoehen
|
||
mov r16, r0 ; ACK fuer die Uebernahme erhoehen
|
||
rcall wrcom
|
||
mov r16, r1
|
||
rcall wrcom
|
||
dec r23
|
||
brne Puffer_Schreib_Schleife ; Ende der Puffer_Schreib_Schleife
|
||
subi ZL, PageSize4313 ; Startwert fuer Page in Z-Register restaurieren, um...
|
||
subi ZL, PageSize4313
|
||
ldi r22, 5 ; ... gesamten Puffer in FLASH schreiben
|
||
out spmcsr, r22
|
||
spm
|
||
ret
|
||
|
||
|
||
|
||
|
||
; temp1, temp2, looplo, loophi, spmcrval
|
||
; in: Z=address in FLASH (byte address like for LPM!)
|
||
; Y=address in RAM
|
||
|
||
.equ PAGESIZEB = PAGESIZE*2 ; PAGESIZEB is page size in BYTES, not words
|
||
|
||
write_page:
|
||
; page erase
|
||
ldi r20, (1<<PGERS) + (1<<SPMEN)
|
||
call do_spm
|
||
|
||
;transfer data from RAM to Flash page buffer
|
||
ldi r18, low(PAGESIZEB) ;init loop variable
|
||
ldi r19, high(PAGESIZEB) ;not required for PAGESIZEB<=256
|
||
|
||
wrloop: ld r0, Y+
|
||
ld r1, Y+
|
||
ldi r20, (1<<SPMEN)
|
||
call do_spm
|
||
adiw ZH:ZL, 2
|
||
sbiw r19:r18, 2 ;use subi for PAGESIZEB<=256
|
||
brne wrloop
|
||
|
||
;execute page write
|
||
subi ZL, low(PAGESIZEB) ;restore pointer
|
||
sbci ZH, high(PAGESIZEB) ;not required for PAGESIZEB<=256
|
||
ldi r20, (1<<PGWRT) + (1<<SPMEN)
|
||
call do_spm
|
||
|
||
;read back and check, optional
|
||
ldi r18, low(PAGESIZEB) ; init loop variable
|
||
ldi r19, high(PAGESIZEB) ; not required for PAGESIZEB<=256
|
||
subi YL, low(PAGESIZEB) ;restore pointer
|
||
sbci YH, high(PAGESIZEB)
|
||
|
||
rdloop:
|
||
lpm r0, Z+
|
||
ld r1, Y+
|
||
cpse r0, r1
|
||
jmp error ; skipped if equal
|
||
sbiw r19:r18, 2 ;use subi for PAGESIZEB<=256
|
||
brne rdloop
|
||
;return
|
||
ret
|
||
|
||
do_spm:
|
||
; input: r20 determines SPM action
|
||
; disable interrupts if enabled, store status
|
||
in r17, SREG
|
||
cli
|
||
;check for previous SPM complete
|
||
wait:
|
||
in r16, SPMCR
|
||
sbrc r16, SPMEN
|
||
rjmp wait
|
||
; SPM timed sequence
|
||
out SPMCR, r20
|
||
spm
|
||
; restore SREG (to enable interrupts if originally enabled)
|
||
out SREG, r17
|
||
ret
|
||
|
||
|
||
|
||
|
||
TODO:
|
||
- Pseudo random:
|
||
- add some dynamics (otherwise nodes with the exact same firmware will have the same sequence of random numbers)
|
||
- read/write FLASH
|
||
- Timer_Run TODO:
|
||
- disable interrupts
|
||
- first handle internal counters and sample into internal flags
|
||
- enable interrupts
|
||
- call handlers (every10s etc) according to flags
|
||
- Serial TODO:
|
||
- work out how to check for ATTN line before sending data
|
||
- add onEveryHour
|
||
- add onEveryDay
|
||
- choose between systems:
|
||
- write correct command into every vector of the low irq table
|
||
- for calling maintenance system: "C:aaaaaa c04f" (low: 4f, high: c0)
|
||
|
||
|
||
|
||
- never flash into the initial irq table (starting at 0!!)
|
||
- that table will be set according to currently active system
|
||
- writeWord:
|
||
- current address pointer: start of page?
|
||
- yes:
|
||
startPage
|
||
- Flash_ReadPageIntoPageBuffer
|
||
- Flash_WriteIntoPage (increments Z)
|
||
- current address pointer: start of page (meaning: next page)
|
||
- yes:
|
||
finishPage
|
||
- z=z-(PAGESIZE*2)
|
||
- Flash_ErasePage (previous page!)
|
||
- Flash_WritePage (previous page!)
|
||
- z=z+(PAGESIZE*2)
|
||
- store address (Z)
|
||
|
||
- setAddress:
|
||
- new address inside current page?
|
||
- yes: only set new address
|
||
- no:
|
||
- finish current page
|
||
- start new page
|
||
- set new address
|
||
|
||
|
||
FlashMsg:
|
||
- start flash
|
||
- set address
|
||
- msg num (2 bytes)
|
||
- address (2 bytes)
|
||
- write bytes
|
||
- msg num (2 bytes)
|
||
- bytes (up to 8)
|
||
- end flash
|
||
|
||
|
||
|
||
msg size in buffer:
|
||
COM_BUFFER_SIZE-3-COM_BUFFER_OFFS_DATA)
|
||
16 -3-1 ; 12 bytes max
|
||
- 4 bytes header (destaddr, msglen, cmd, srcaddr)
|
||
- 1 byte XOR
|
||
- 1 byte flags in buffer
|
||
->6 bytes overhead
|
||
-> 10 usable bytes left
|
||
flash data msg:
|
||
- 2 bytes msg num
|
||
- remaining data bytes: 8
|
||
|
||
|
||
Part list N03:
|
||
- Resistors
|
||
- R1: 100 Ohm
|
||
- R2: 100 Ohm
|
||
- R3: 10K Ohm
|
||
- R4: 1K Ohm
|
||
- R5: 10K Ohm
|
||
- R6: 10K Ohm
|
||
- R7: 120 Ohm (restrict current to 27mA at 3.3V)
|
||
- R8: 220K Ohm
|
||
- Capacitors
|
||
- C1: 10 uF
|
||
- C2: 10 uF
|
||
- C3: 100 nF
|
||
|
||
|
||
Part list N04, N05, N06:
|
||
- Resistors
|
||
- R1: 100 Ohm serial COM_ATTN
|
||
- R2: 100 Ohm serial COM_DATA
|
||
- R3: 10K Ohm pullup reset
|
||
- R4: 1K Ohm serial LED
|
||
- R5: 10K Ohm pullup SDA
|
||
- R6: 10K Ohm pullup SCL
|
||
- R7: 120 Ohm (restrict CNY70 LED current to 27mA at 3.3V)
|
||
- R8: 220K Ohm pullup CNY70 photo transistor
|
||
- Capacitors
|
||
- C1: 10 uF
|
||
- C2: 10 uF
|
||
- C3: 100 nF
|
||
|
||
|
||
|
||
Node header:
|
||
- baseFirmwareVersion (2 bytes)
|
||
- mainFirmwareVersion (2 bytes)
|
||
- modules mask: (2 bytes)
|
||
|
||
Registered firmware modules:
|
||
- 0x01: LED
|
||
- 0x02: SI7021
|
||
- 0x03: CNY70
|
||
- etc.
|
||
|
||
|
||
Next:
|
||
- aqhome:
|
||
- add IPC client
|
||
- add IPC command to set accepted msg groups
|
||
- add IPC command to query nodeinfo database
|
||
- add IPC command for sending value change
|
||
- node (UID, addr?)
|
||
- value id
|
||
- value type
|
||
- new value
|
||
- avr:
|
||
- add firmware header
|
||
- add msg which sends that header
|
||
- value msg: send uid instead of timestamp
|
||
- maybe use fletcher16? (https://en.wikipedia.org/wiki/Fletcher%27s_checksum)
|
||
- or crc8 (https://stackoverflow.com/questions/51752284/how-to-calculate-crc8-in-c)? [use this!]
|
||
|
||
3 4 2 1
|
||
1 2 3 4 1: GND x
|
||
x x x 2: ATTN
|
||
x 3: DATA x
|
||
4: 5V
|
||
|
||
|
||
Gehaeuse:
|
||
- Abstandshalter in Gehaeuse?
|
||
- Platine verkehrt herum einbauen, einschrauben (Abstandshuelsen?)
|
||
- oder: LED und Schalter auf der Rueckseite einbauen, Platine mit Abstandshuelsen einschrauben
|
||
- Deckel an der Wand befestigen
|
||
- Kabel innerhalb der Dose verlegen (sauberere Anschluesse)
|
||
|
||
|
||
Kabel:
|
||
- ROT : 5V
|
||
- SCHWARZ: GND
|
||
- GRUEN : DATA
|
||
- BLAU : ATTN
|
||
|
||
|
||
|
||
Tasmota-Steckdosen melden alle 300s:
|
||
|
||
tele/tasmota/plug01/STATE
|
||
{
|
||
"Time":"1970-01-01T09:01:09",
|
||
"Uptime":"0T09:00:41",
|
||
"UptimeSec":32441,
|
||
"Heap":29,
|
||
"SleepMode":"Dynamic",
|
||
"Sleep":50,
|
||
"LoadAvg":19,
|
||
"MqttCount":1,
|
||
"POWER":"ON",
|
||
"Wifi":{
|
||
"AP":1,
|
||
"SSId":"CAMELOT_IOT",
|
||
"BSSId":"74:DA:38:EF:8B:DC",
|
||
"Channel":4,
|
||
"Mode":"11n",
|
||
"RSSI":98,
|
||
"Signal":-51,
|
||
"LinkCount":1,
|
||
"Downtime":"0T00:00:06"
|
||
}
|
||
}
|
||
|
||
|
||
|
||
tele/tasmota/plug01/SENSOR
|
||
{
|
||
"Time":"1970-01-01T09:01:09",
|
||
"ENERGY": {
|
||
"TotalStartTime":"1970-01-01T00:00:00",
|
||
"Total":0.131,
|
||
"Yesterday":0.000,
|
||
"Today":0.131,
|
||
"Period": 4,
|
||
"Power":49,
|
||
"ApparentPower":55,
|
||
"ReactivePower":25,
|
||
"Factor":0.89,
|
||
"Voltage":232,
|
||
"Current":0.235
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
node 2: no messages received again???
|
||
|
||
rewrite COM:
|
||
- send message:
|
||
- alloc buffer
|
||
- message vorbereiten lassen
|
||
- send message
|
||
- dealloc buffer
|
||
- wenn fehler (z.B. line busy): spaeter alles wiederholen (dann aber durch das anfordernde modul, nicht das COM modul)
|
||
- kein fire and forget mehr!
|
||
- evtl. einen buffer fuer notfall-meldungen
|
||
- reihenfolge aendern bei comInterrupt (counter hinterher erhoehen)
|
||
|
||
|