Så har jag äntligen fått det att fungera. Vetefan varför, men av någon anledning återställdes X till 48 precis innan jag skulle skriva den till minnet. Nu sparar jag X i ett register en stund innan det ska skrivas till minnet.
Fullösning, men vafan.
Nu ska jag bara ha igång så jag kan skriva över flera pages i minnet, få ut vad som finns i minnet endast med ett speciellt kort och tömma minnet med samma speciella kort.
Helst något som visar hur fullt minnet är också.
Kod: Markera allt
.include "tn2313def.inc"
; Define temporary registers
.def Temp = r16
.def Temp2 = r17
.def DelayTime = r18
.def rRETURN =r25 ; return value from functions
.def rSCRATCH =r19
.def rPARAM1 =r20
.def rPARAM2 =r21
.def rLOOPI =r22 ; loop counters
.def rLOOPJ =r23
.def rTICKCOUNT =r24 ; tick count (# of resets/reading)
;.def ZL =r30 ; Already defined in .inc file.
;.def ZH =r31
.equ DelayCount1 = 128
; Define generic port names (change the 'A' to whatever you're using)
.equ LCD_PORT = PORTB
.equ LCD_DDR = DDRB
.equ LCD_PIN = PINB
.equ ee_port = PORTD
.equ ee_ddr = DDRD
.equ ee_pin = PIND
; Define the pin numbers
.equ LCD_E = 1
.equ LCD_RW = 2
.equ LCD_RS = 3
.equ LCD_LIGHT = 0
.equ bSDA = 6
.equ bSCL = 5
.equ mSDA =(1<<bSDA)
.equ mSCL =(1<<bSCL)
; I2C Device addressing
.equ ADDR24LC128 =0b10100010; LC128 address byte (1010 001R)
.equ I2CREAD =0x01 ; read/write bit = read
.equ I2CWRITE =0x00 ; read/write bit = write
.equ MARK =0x7E ; mark value for eeprom
.equ BLANK =0x7F ; blank value for eeprom
.equ MEMSIZE =2048 ; size of eeprom (bytes)
;-----------------------------------------------------------------
;
; Macros
.macro I2CDelay
nop ; delay
nop
nop
nop
nop
nop
nop
nop
.endmacro
.macro incx
push temp
ld temp, x+
pop temp
.endmacro
.org 0x0000
rjmp reset
.org 0x0007
rjmp storedat ;usart rx complete
Reset:
ldi temp, LOW(RAMEND)
out SPL, temp
rcall USART_Init
rcall lcd_init
rcall welcome
ser temp
out ddrb, temp
ldi temp, 0b01110000
out ddrd, temp
; Set up port assignments
ldi TEMP,mSCL ; SCL only output by default
out DDRD,TEMP
out PORTD,TEMP ; All outputs high, input pullups disabled
rcall i2cinit
sei
rjmp main
main:
ldi temp, 'a'
sbis PIND, PIND3
rcall mem_present
sbis PIND, PIND2
rcall mem_clear
rjmp main
mem_present:
rcall lcd_clear
ldi XL, 1
ldi temp, 'b'
rcall lcd_sendchar
rcall readmem
mov temp, rreturn
rcall lcd_sendchar
ldi temp, 'c'
rcall lcd_sendchar
ret
mem_clear:
clr temp
mov XL, temp
mem_clear1:
IncX
clr rparam1
rcall writemem
dec temp
brne mem_clear1
ret
storedat:
cli
rcall lcd_clear
ldi r30, 0x60
clr r31
next:
rcall rcvuart
st z+, temp
rjmp next
rcvuart:
sbis UCSRA, RXC
rjmp rcvuart
in temp, UDR
cpi temp, 32
breq rcvuart
cpi temp, 0x0a
breq storemem
;rcall lcd_sendchar
ret
storemem:
;in temp, spl
;inc temp
;out spl, temp
;rcall welcome
ldi r30, 0x60
clr r31
ldi temp2, 8
rcall lcd_printmem
ldi temp, 0b11000000
rcall lcd_sendcmd
ldi temp2, 5
rcall lcd_printmem
ldi temp, 32
rcall lcd_sendchar
ldi temp2, 5
rcall lcd_printmem
sbi lcd_port, lcd_light
; Store in EEPROM from here
; Get address to continue from
ldi XL, 0x01
rcall readmem
;out UDR, rreturn
mov XL, rreturn
; Address is read and stored in XL, continue with storing to EEPROM from SRAM
ldi ZL, 0x60
clr ZH
ldi temp2, 18
rcall writeloop
; To here
sei
rcall bigdelay
rcall welcome2
reti
;-----------------------------------------------------------------
;
; ReadMem
;
; Reads external memory at X, and increments X
; Byte is returned in register
ReadMem:
rcall I2CStart
ldi rPARAM1,(ADDR24LC128|I2CWRITE)
rcall I2CSendAddress
brne ReadMemError ; No ack!
mov rPARAM1,XL
rcall I2CSendByte
rcall I2CStop
I2CDelay
rcall I2CStart
ldi rPARAM1,(ADDR24LC128|I2CREAD)
rcall I2CSendAddress
brne ReadMemError ; No ack!
ldi rPARAM1,1 ; Don't send ack
rcall I2CReadByte
rcall I2CStop
incx
ret
ReadMemError:
rcall I2CStop
rcall lcd_clear
ldi temp, 'd'
rcall lcd_sendchar
ldi temp2, 100
rcall bigdelay
clr rLOOPI
ReadMemErrorDelay:
dec rLOOPI
brne ReadMemErrorDelay
rjmp ReadMem ; and try again
;-----------------------------------------------------------------
;
; Writeloop
;
; Writes number of bytes as stored in temp2 to EEPROM from SRAM
; and writes ascii code 32 to last address and stores number after
; last in EEPROM addresses 0x00 (low byte) and 0x01 (high byte)
; Assumes beginning address is stored in X and for SRAM in Z
Writeloop:
ld rparam1, z+
mov rscratch, XL
;rcall senduart
rcall writemem
dec temp2
brne writeloop
ldi rparam1, 32
rcall writemem
mov rparam1, XL
ldi XL, 0x01
inc rscratch
inc rscratch
mov rparam1, rscratch
rcall senduart
rcall writemem
ret
senduart:
sbis UCSRA, UDRE
rjmp senduart
nop
nop
nop
out UDR, rscratch
ret
;-----------------------------------------------------------------
;
; WriteMem
;
; Writes rPARAM1 to external memory at X, and increments X
WriteMem:
mov rPARAM2,rPARAM1 ; save value
rcall I2CStart
ldi rPARAM1,(ADDR24LC128|I2CWRITE)
rcall I2CSendAddress
;brne WriteMemError ; No ack!
mov rPARAM1,XL
rcall I2CSendByte
mov rPARAM1,rPARAM2
rcall I2CSendByte
rcall I2CStop
incx
ret
; Increment X by 1
WriteMemError:
rcall I2CStop
rcall lcd_clear
ldi temp, 'e'
rcall lcd_sendchar
ldi temp2, 100
rcall bigdelay
clr rLOOPJ
WriteMemErrorDelay:
dec rLOOPJ
brne WriteMemErrorDelay
mov rPARAM1,rPARAM2 ; restore data value
rjmp WriteMem ; and try again
welcome:
rcall lcd_clear
ldi r30, LOW(wel1*2)
ldi r31, HIGH(wel1*2)
ldi temp2, 12
rcall lcd_printpm
ldi temp, 0b11000000
rcall lcd_sendcmd
ldi r30, LOW(wel2*2)
ldi r31, HIGH(wel2*2)
ldi temp2, 15
rcall lcd_printpm
ret
welcome2:
rcall lcd_clear
ldi r30, LOW(wel1*2)
ldi r31, HIGH(wel1*2)
ldi temp2, 12
rcall lcd_printpm
ldi temp, 0b11000000
rcall lcd_sendcmd
ldi r30, LOW(wel2*2)
ldi r31, HIGH(wel2*2)
ldi temp2, 15
rcall lcd_printpm
ldi temp, 255
sbi lcd_port, lcd_light
rcall bigdelay
cbi lcd_port, lcd_light
ret
wel1:
.db " SK7OL "
wel2:
.db " Aby Radioklubb "
USART_Init:
ldi temp, 0b11111111
out UBRRL, temp
ldi temp, 0b00000010
out UBRRH, temp
ldi temp, (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)
out UCSRB, temp
ldi r16, (3<<UCSZ0)|(1<<USBS)
out UCSRC, temp
ret
USART_Transmit:
; Wait for empty transmit buffer
sbis UCSRA, UDRE
rjmp USART_Transmit
; Put data (r16) into buffer, sends the data
ldi delaytime, 7
rcall delay
out UDR, temp
ret
; *** LCD_Init: Routine to initialize the LCD.
LCD_Init: push Temp
ldi DelayTime, 255
; Put the LCD in 8-bit mode. Even though we want the display to
; operate in 4-bit mode, the only way to guarantee that our commands
; are aligned properly is to initialize in 8-bit. (The user might have
; hit reset between nibbles of a dual 4-bit cycle.)
ldi Temp, 0b00110000
out LCD_PORT, Temp
rcall LCD_PulseE
rcall DELAY
rcall DELAY
; Now it's safe to go into 4-bit mode.
ldi Temp, 0b00100000
out LCD_PORT, Temp
rcall LCD_PulseE
rcall DELAY
rcall DELAY
; *** Send the 'FUNCTION SET' command
; +------ Data: 0 = 4-bit; 1 = 8-bit
; |+----- Lines: 0 = 1; 1 = 2
; ||+---- Font: 0 = 5x8; 1 = 5x11
ldi Temp, 0b00101100
rcall LCD_SendCmd
; *** Send the 'CURSOR/DISPLAY SHIFT' command
; +----- S/C: 0 = cursor; 1 = display
; |+---- R/L: 0 = left; 1 = right
ldi Temp, 0b00010100
rcall LCD_SendCmd
; *** Send the 'DISPLAY ON/OFF' command
; +---- Display: 0 = off; 1 = on
; |+--- Cursor: 0 = off; 1 = on
; ||+-- Blink: 0 = off; 1 = on
ldi Temp, 0b00001100
rcall LCD_SendCmd
; *** Send the 'ENTRY MODE' command
; +--- Direction: 0 = left; 1 = right
; |+-- Shift Dislay: 0 = off; 1 = on
ldi Temp, 0b00000110
rcall LCD_SendCmd
rcall LCD_Clear
pop Temp
ret
; *** LCD_PrintMem: Prints from memory.
; Put the starting memory location in Z (r31:r30)
; Put the number of characters to print in Temp2
; After execution, Z is at the character AFTER the last to be printed
; and Temp2 is zero.
; This function will not wrap if you the string is bigger than the LCD.
LCD_PrintMem: push Temp
LCD_MemRead: ld Temp, Z+
rcall LCD_SendChar
dec Temp2
brne LCD_MemRead
pop Temp
ret
; *** LCD_PrintPM: Prints from program memory
LCD_PrintPM: push r0
push Temp
LCD_PMRead: lpm
mov Temp, r0
rcall LCD_SendChar
adiw r30, 1
dec Temp2
brne LCD_PMRead
pop Temp
pop r0
ret
; *** LCD_Clear: Clears the display and sends the cursor home.
LCD_Clear: push Temp
; *** Clear the display
ldi Temp, 0b00000001
rcall LCD_SendCmd
; *** Send the cursor home
ldi Temp, 0b00000010
rcall LCD_SendCmd
pop Temp
ret
; *** LCD_SendCmd: Routine to write a command to the instruction register.
; The value to be written should be stored in Temp.
; The value is sent 4 bits at a time.
LCD_SendCmd: push Temp
push Temp2
rcall LCD_WaitBusy
mov Temp2, Temp ; Make a backup copy
andi Temp2, 0b11110000 ; Only use the upper nibble
out LCD_PORT, Temp2 ; Send it
rcall LCD_PulseE ; Pulse the enable
swap Temp ; Swap upper/lower nibble
andi Temp, 0b11110000 ; Only use the upper nibble
out LCD_PORT, Temp ; Send it
rcall LCD_PulseE ; Pulse the enable
pop Temp2
pop Temp
ret
; *** LCD_SendChar: Routine to write a character to the data register.
; The value to be written should be stored in Temp.
; The value is sent 4 bits at a time.
LCD_SendChar:
push temp
push temp2
mov Temp2, Temp ; Make a backup copy
rcall LCD_WaitBusy
mov Temp, Temp2 ; Make a backup copy
andi Temp2, 0b11110000 ; Only use the upper nibble
ori Temp2, 0b00001000
out LCD_PORT, Temp2 ; Send it
rcall LCD_PulseE ; Pulse the enable
swap Temp ; Swap upper/lower nibble
andi Temp, 0b11110000 ; Only use the upper nibble
ori Temp, 0b00001000
out LCD_PORT, Temp ; Send it
rcall LCD_PulseE ; Pulse the enable
pop Temp2
pop Temp
ret
; *** LCD_WaitBusy: Wait for the busy flag to go low.
; Waits for the busy flag to go low. Since we're in 4-bit mode,
; the register has to be read twice (for a total of 8 bits). The
; second read is never used.
; If you need more code space, this function could be replaced with
; a simple delay.
LCD_WaitBusy: push Temp
ldi Temp, 0b00001111 ; Disable data bit outputs
out LCD_DDR, Temp
ldi Temp, 0x00 ; Clear all outputs
out LCD_PORT, Temp
LCDWaitLoop: ldi Temp, 0b00000100 ; Enable only read bit
out LCD_PORT, Temp
sbi LCD_PORT, LCD_E ; Raise the Enable signal.
nop
nop
in Temp, LCD_PIN ; Read the current values
cbi LCD_PORT, LCD_E ; Disable the enable signal.
rcall LCD_PulseE ; Pulse the enable (the second nibble is discarded)
sbrc Temp, 7 ; Check busy flag
rjmp LCDWaitLoop
ldi Temp, 0b11111111 ; Enable all outputs
out LCD_DDR, Temp
pop Temp
ret
LCD_PulseE: sbi LCD_PORT, LCD_E
nop
nop
cbi LCD_PORT, LCD_E
ret
;-----------------------------------------------------------------
;
; I2C Routines
;
;-----------------------------------------------------------------
;-----------------------------------------------------------------
;
; I2CInit
; Initialize I2C interface, ports, etc.
I2CInit:
cbi PORTd,bSDA ; Data line always drives low if driven
cbi DDRd,bSDA ; SDA as input to start with - floats high
cbi PORTd,bSCL ; Set SCL low to try and avoid...
sbi DDRd,bSCL ; ...false start transitions
I2CDelay
rjmp I2CStop ; Stop any erroneous transfer
;-----------------------------------------------------------------
;
; I2CStart
; Send I2C start condition
; Assumes SCL and SDA are high to start with.
; Leaves SCL and SDA low
I2CStart:
I2CDelay
sbi DDRd,bSDA ; Drive data line low (start bit)
I2CDelay
cbi PORTd,bSCL ; Clock line low (ready to start)
ret
;-----------------------------------------------------------------
;
; I2CStop
; Send I2C stop condition
; Assumes SCL is low to start with, SDA may be in either state
; Leaves SCL and SDA high
I2CStop:
sbi DDRd,bSDA ; SDA driven low
I2CDelay
sbi PORTd,bSCL ; Clock line high (ready to stop)
I2CDelay
cbi DDRd,bSDA ; Data line floats high (stop bit)
I2CDelay
ret
;-----------------------------------------------------------------
;
; I2CSendByte
; Sends 8 bits of data from rPARAM1 and listens for an ACK at the
; end. Returns Z if ack received, else NZ.
; Assumes a start condition has already been sent, and SDA and SCL
; are low
; Leaves SCL low, SDA not driven.
; Uses rLOOPJ and rPARAM1.
I2CSendAddress:
I2CSendByte:
ldi rLOOPJ,8
I2CSendBits:
add rPARAM1,rPARAM1
brcc I2CSendBits0
cbi DDRd,bSDA ; send 1 (floats high)
rjmp I2CSendBits1
I2CSendBits0:
sbi DDRd,bSDA ; send 0 (drives low)
I2CSendBits1:
I2CDelay
sbi PORTd,bSCL ; clock high
I2CDelay
cbi PORTd,bSCL ; clock low
dec rLOOPJ
brne I2CSendBits
cbi DDRd,bSDA ; stop driving data bus
I2CDelay
sbi PORTd,bSCL ; clock high
I2CDelay
in rPARAM1,PINd ; sample data bus
cbi PORTd,bSCL ; clock low
I2CDelay
andi rPARAM1,mSDA ; check ack bit (z set if OK)
ret
;-----------------------------------------------------------------
;
; I2CReadByte
; Read a byte from the I2C bus and acknowledge
; If rPARAM1 is zero, acknowledge is sent, otherwise not.
; Byte is returned in rRETURN
; Leaves SCL low, I2C bus not driven.
I2CReadByte:
ldi rLOOPJ,8
clr rRETURN
cbi DDRd,bSDA ; release bus (floats high)
I2CReadBits:
sbi PORTd,bSCL ; clock high
I2CDelay
add rRETURN,rRETURN
sbic PINd,bSDA ; if SDA clear, skip increment
inc rRETURN
cbi PORTd,bSCL ; clock low
I2CDelay
dec rLOOPJ
brne I2CReadBits
tst rPARAM1 ; Send an ACK...?
brne I2CReadBitsNack
sbi DDRd,bSDA ; yes... drive data bus low
I2CReadBitsNack:
sbi PORTd,bSCL ; clock high
I2CDelay
cbi PORTd,bSCL ; clock low
I2CDelay
cbi DDRd,bSDA ; release bus (floats high)
ret
bigdelay:
ser delaytime
rcall delay
dec temp2
brne bigdelay
ret
; *** Provide millisecond delay (DelayTicks specifies number of ms)
DELAY: push DelayTime
push r25
ldi r25, DelayCount1
DELAY1: dec r25
brne DELAY1
dec DelayTime
brne DELAY1
pop r25
pop DelayTime
ret