Collapse OS Documentation Browser

doc/hw/avr/code/at28wr.asm

../ at28dump.asm at28wr.asm

; *** 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<<RXEN0) | (1<<TXEN0)
	sts	UCSR0B, r16

loop:
	rcall	uartrd
	rcall	ioout
	rcall	nextaddr
	rcall	writedata
	rcall	ioin
	rcall	waitio7
	rcall	readdata
	rcall	uartwr
	rjmp	loop


Collapse OS and its documentation are created by Virgil Dupras and licensed under the GNU GPL v3.

This documentation browser by James Stanley. Please report bugs on github or to james@incoherency.co.uk.

This page generated at 2024-12-26 21:05:04 from documentation in CollapseOS snapshot 20230427.