; *** EEPROM write *** ; Listen to UART expecting tty-escaped "pingpong" (from tools/) communication. ; ; Each of those received bytes is written to the EEPROM, starting at addr 0. ; that byte is then re-read and sent back to the UART, tty-escaped. ; ; Addr selection is done through 2 chained '164, data in/out is done directly ; with PD7:2 for bits 7:2 and PB1:0 for bits 1:0 (PD1 and PD0 are used for ; 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 *** ; ; r0: holds whether last received char was tty-escaped (0 = no, 1=yes) ; r16: generic tmp ; r17: generic tmp ; r20: Byte to send to the "data" SR. Wired to D0-D7. ; r21: "high" byte, to send to the "addr" SR. Wired to A8-15 ; r22: "low" byte, to send to the "addr" SR. Wired to A0-7 ; r23: tmp value to use for sending to the "addr" SR .include "m328Pdef.inc" ; *** Pins *** .equ SRCP = PORTB2 .equ SRDS = PORTB1 .equ FLWE = PORTB3 .equ FLOE = PORTB4 .equ FLCE = PORTB5 ; WARNING: same as LED ; *** Consts *** .equ BAUD_PRESCALE = 103 ; 9600 bauds at 16mhz rjmp main ; *** Code *** ; Waits until a char is read, then put it in R20 ; Perform TTY-escape transparently. uartrd: lds r16, UCSR0A sbrs r16, RXC0 ; RXC0 is set? skip rjmp and fetch char. rjmp uartrd lds r20, UDR0 ; is this the escape char? cpi r20, 0x20 brne uartrd_0 ; escape char ; We "pong" the escape right away. rcall uartwr inc r0 rjmp uartrd uartrd_0: ; should we escape? tst r0 breq uartrd_1 ; yes andi r20, 0x7f uartrd_1: ret ; Sends char in r20 to UART ; Perform TTY-escape transparently. uartwr: lds r16, UCSR0A sbrs r16, UDRE0 ; wait until send buffer is empty rjmp uartwr ; should we escape? tst r0 breq uartwr_0 ; we need to escape ori r20, 0x80 clr r0 uartwr_0: sts UDR0, r20 ret ; send r23 to addr shift register. ; We send highest bits first so that Q7 is the MSB and Q0 is the LSB sendaddr: ldi r16, 8 ; we will loop 8 times cbi PORTB, SRDS sbrc r23, 7 ; if latest bit isn't cleared, set SER_DP high sbi PORTB, SRDS ; toggle SRCP, not waiting between pulses. The CD74AC164 at 5V has a ; 5.9ns CP min pulse width. We can't match that at 16mhz. No need to ; wait. cbi PORTB, SRCP sbi PORTB, SRCP lsl r23 ; shift our data left dec r16 brne sendaddr+1 ; not zero yet? loop! (+1 to avoid reset) ret ; send r20 to EEPROM's I/O7:0 through PD7:2 and PB1:0 writedata: cbi PORTB, FLCE ; addr is latched on WE falling edge cbi PORTB, FLWE ; send bits 7:2 mov r16, r20 andi r16, 0xfc in r17, PORTD andi r17, 0x03 or r16, r17 out PORTD, r16 ; send bits 1:0 mov r16, r20 andi r16, 0x03 in r17, PORTB andi r17, 0xfc or r16, r17 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 ; push r20 to the rom and increase the memory counter nextaddr: ; first, set up addr mov r23, r21 rcall sendaddr mov r23, r22 rcall sendaddr inc r22 brne nextaddr_0 ; no overflow? skip inc r21 nextaddr_0: ret ; wait until I/O7 stops toggling waitio7: cbi PORTB, FLCE cbi PORTB, FLOE nop ; Give the AT28 time to latch nop nop in r16, PIND sbi PORTB, FLOE sbi PORTB, FLCE andi r16, 0xfc cbi PORTB, FLCE cbi PORTB, FLOE nop ; Give the AT28 time to latch nop nop in r17, PIND sbi PORTB, FLOE sbi PORTB, FLCE andi r17, 0xfc cp r16, r17 brne waitio7 ret ; read EEPROM's I/O7:0 through PD7:2 and PB1:0 into r20 readdata: cbi PORTB, FLCE cbi PORTB, FLOE nop ; Give the AT28 time to latch nop nop ; read bits 7:2 in r20, PIND andi r20, 0xfc ; read bits 1:0 in r16, PINB andi r16, 0x03 or r20, r16 sbi PORTB, FLOE sbi PORTB, FLCE ret ; Set PD7:2 and PB1:0 to output ioout: ldi r16, 0xfc ; PD7:2 out DDRD, r16 ldi r16, 0x3f ; PB5:0 (CP, WE, OE and CE too) out DDRB, r16 ret ; Set PD7:2 and PB1:0 to input ioin: ldi r16, 0x03 ; PD7:2 out DDRD, r16 ldi r16, 0x3c ; PB1:0 out DDRB, r16 ret main: ldi r16, low(RAMEND) out SPL, r16 ldi r16, high(RAMEND) out SPH, r16 sbi PORTB, FLWE sbi PORTB, FLOE sbi PORTB, FLCE ; Clear counters and flags clr r0 clr r21 clr r22 ; Setup UART ldi R16, low(BAUD_PRESCALE) sts UBRR0L, r16 ldi r16, high(BAUD_PRESCALE) sts UBRR0H, r16 ldi r16, (1<