recipes/arduinouno/at28: improve reliability

Previously, it could never write more than a few bytes before pingpong
getting a mismatch error. Now, I can pingpong Collapse OS binary
without a mismatch.
This commit is contained in:
Virgil Dupras 2020-07-28 15:18:26 -04:00
parent bc1cc591ce
commit b8e52707e9
4 changed files with 54 additions and 24 deletions

View File

@ -14,10 +14,10 @@ all: $(TARGET)
@echo Done! @echo Done!
send: $(PROGNAME).hex send: $(PROGNAME).hex
avrdude $(AVRDUDEARGS) -p $(AVRDUDEMCU) -U flash:w:$< avrdude $(AVRDUDEARGS) -p $(AVRDUDEMCU) -U flash:w:$(PROGNAME).hex
$(TARGET): at28wr.asm $(TARGET): $(PROGNAME).asm
$(AVRA) -o $@ at28wr.asm $(AVRA) -o $@ $(PROGNAME).asm
clean: clean:
rm -f $(TARGET) *.S.eep.hex *.S.obj rm -f $(TARGET) *.S.eep.hex *.S.obj

View File

@ -23,6 +23,11 @@ on the Arduino's right side (except for VCC, which needs to be wired).
PD0 and PD1 are not used because they're used for the UART. PD0 and PD1 are not used because they're used for the UART.
AT28 selection pins are pulled up to avoid accidental writes due to their line
floating before Arduino's initialization.
I've put 1uf decoupling caps next to each IC.
## Software ## Software
The software in at28wr.asm listens to the UART and writes every byte it receives The software in at28wr.asm listens to the UART and writes every byte it receives

View File

@ -8,6 +8,17 @@
; with PD7:2 for bits 7:2 and PB1:0 for bits 1:0 (PD1 and PD0 are used for ; with PD7:2 for bits 7:2 and PB1:0 for bits 1:0 (PD1 and PD0 are used for
; UART). ; UART).
; ;
; *** Timing, matching and CE ***
;
; A lot of trial-and-errors went into those NOPs being place to give time for
; latching. All these timing are well, well above maximums given in the specs,
; but when I wasn't going well, well above those specs, I was experiencing
; read/write errors. It seems we live in an imperfect world!
;
; I'm also not sure, in "writedata", whether toggling CE along with WE is
; actually needed, but until I did, I was experiencing random write failures.
; So, we end up with this...
;
; *** Register Usage *** ; *** Register Usage ***
; ;
; r0: holds whether last received char was tty-escaped (0 = no, 1=yes) ; r0: holds whether last received char was tty-escaped (0 = no, 1=yes)
@ -92,6 +103,10 @@ sendaddr:
; send r20 to EEPROM's I/O7:0 through PD7:2 and PB1:0 ; send r20 to EEPROM's I/O7:0 through PD7:2 and PB1:0
writedata: writedata:
cbi PORTB, FLCE
; addr is latched on WE falling edge
cbi PORTB, FLWE
; send bits 7:2 ; send bits 7:2
mov r16, r20 mov r16, r20
andi r16, 0xfc andi r16, 0xfc
@ -106,49 +121,59 @@ writedata:
andi r17, 0xfc andi r17, 0xfc
or r16, r17 or r16, r17
out PORTB, r16 out PORTB, r16
; data is latched on rising edge
sbi PORTB, FLWE
sbi PORTB, FLCE
nop ; Give the AT28 time to latch
nop
nop
ret ret
; push r20 to the rom and increase the memory counter ; push r20 to the rom and increase the memory counter
pushdata: nextaddr:
; first, set up addr ; first, set up addr
mov r23, r21 mov r23, r21
rcall sendaddr rcall sendaddr
mov r23, r22 mov r23, r22
rcall sendaddr rcall sendaddr
inc r22 inc r22
brne pushdata_0 ; no overflow? skip brne nextaddr_0 ; no overflow? skip
inc r21 inc r21
nextaddr_0:
pushdata_0:
; addr is latched on WE falling edge
cbi PORTB, FLWE
; now, lets set up data. Plenty enough instructions to ensure a 100ns
; minimum delay.
rcall writedata
; data is latched on rising edge
sbi PORTB, FLWE
ret ret
; wait until I/O7 stops toggling ; wait until I/O7 stops toggling
waitio7: waitio7:
cbi PORTB, FLCE
cbi PORTB, FLOE cbi PORTB, FLOE
nop ; Give the AT28 time to latch
nop
nop
in r16, PIND in r16, PIND
sbi PORTB, FLOE sbi PORTB, FLOE
sbi PORTB, FLCE
andi r16, 0xfc andi r16, 0xfc
cbi PORTB, FLCE
cbi PORTB, FLOE cbi PORTB, FLOE
nop ; Give the AT28 time to latch
nop
nop
in r17, PIND in r17, PIND
sbi PORTB, FLOE sbi PORTB, FLOE
sbi PORTB, FLCE
andi r17, 0xfc andi r17, 0xfc
cp r16, r17 cp r16, r17
brne waitio7 brne waitio7
ret ret
; read EEPROM's I/O7:0 through PD7:2 and PB1:0 and put result in r20. ; read EEPROM's I/O7:0 through PD7:2 and PB1:0 into r20
readdata: readdata:
cbi PORTB, FLCE
cbi PORTB, FLOE cbi PORTB, FLOE
nop ; Give the AT28 time to latch
nop
nop
; read bits 7:2 ; read bits 7:2
in r20, PIND in r20, PIND
andi r20, 0xfc andi r20, 0xfc
@ -157,13 +182,14 @@ readdata:
andi r16, 0x03 andi r16, 0x03
or r20, r16 or r20, r16
sbi PORTB, FLOE sbi PORTB, FLOE
sbi PORTB, FLCE
ret ret
; Set PD7:2 and PB1:0 to output ; Set PD7:2 and PB1:0 to output
ioout: ioout:
ldi r16, 0xfc ; PD7:2 ldi r16, 0xfc ; PD7:2
out DDRD, r16 out DDRD, r16
ldi r16, 0x3f ; PB5:0 (WE, OE and CE too) ldi r16, 0x3f ; PB5:0 (CP, WE, OE and CE too)
out DDRB, r16 out DDRB, r16
ret ret
@ -181,11 +207,9 @@ main:
ldi r16, high(RAMEND) ldi r16, high(RAMEND)
out SPH, r16 out SPH, r16
; We begin with WE and OE disabled (high), but CE stays enabled (low)
; the whole time.
sbi PORTB, FLWE sbi PORTB, FLWE
sbi PORTB, FLOE sbi PORTB, FLOE
cbi PORTB, FLCE sbi PORTB, FLCE
; Clear counters and flags ; Clear counters and flags
clr r0 clr r0
@ -204,7 +228,8 @@ main:
loop: loop:
rcall uartrd rcall uartrd
rcall ioout rcall ioout
rcall pushdata rcall nextaddr
rcall writedata
rcall ioin rcall ioin
rcall waitio7 rcall waitio7
rcall readdata rcall readdata

View File

@ -12,7 +12,7 @@ properly set up, TTY-wise. You'll probably want to do that with `stty`. The tool
itself takes care of setting the regular stuff (`cs8`, `-parenb`, etc), but you itself takes care of setting the regular stuff (`cs8`, `-parenb`, etc), but you
need to set the speed. Here's an example working on OpenBSD: need to set the speed. Here's an example working on OpenBSD:
$ ( stty 115200 ; ./upload - a000 os.bin ) <>/dev/cuaU0 $ ( stty 115200 raw ; ./upload - a000 os.bin ) <>/dev/cuaU0
To be honest, I'm having a bit of troubles making these tools work as well on To be honest, I'm having a bit of troubles making these tools work as well on
OpenBSD as they do in Linux. But it *does* work. Here are some advices: OpenBSD as they do in Linux. But it *does* work. Here are some advices: