Using EEPROM

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

I have been working on a Morse Code keyer that uses EEPROM to store messages. It has three memories for these messages, and the number of characters to be sent in each message (to a maximum of 39) is stored in a register named index. The number in "index" is supposed to be stored at the last EEPROM position for each message. For example, the first message should store the index number at 0x28 and message 2 should start at 0x29.

This system almost seems to work, but for some reason that I have not been able to figure out, I can't get it to work perfectly. When I go through the program line by line, data entry seems to work fine, but when reading the message back the program does not behave as I would expect. For example, at the section of the program "Msg1:"

Msg1:

ldi temp1, msg1_index ;index address for msg1
out EEAR, temp1 ;EEAR <- (start address - 1)
ldi ZL, 2 ;Z-pointer points to r2
rcall EERead

the value in temp1 is not transferred into EEAR. I don't understand why not.

When a messages has been completely entered a push of a push button should signal the end of message entry. Sometimes this works and sometimes it doesn't. Exceeding the 39 character limit should also cause exit from the message entry but this doesn't seem to work properly - usually part of the message is sent followed by a whole string of zeros (0xff in the EEPROM).

I have included the code for the complete program. I am really stuck at this point - I would certainly appreciate any suggestions regarding how to make the EEPROM message storage work properly.

Thank you.

;This ATtiny2313A programme is for an iambic memory keyer.  Speed is adjusted by 
;changing the external clock frequency.  PB0 (pin 12) is used for the key line.
;PB1 (pin 13 is used for dits, PB2 (pin 14) for dahs.  Grounding PB3, PB4 and PB5
;(pins 15 - 17) sends messages 1, 2 and 3.  To enter a message, ground one of these
;pins and then turn on the power to the 2313 while keeping the pin grounded; i.e. for message 1 
;ground pin 15 (PB3) and turn on the power.  The program will then skip to the data
;entry section of the program for message 1.  At the end of message input a second press of
;the memory button returns the program to normal operation.  As it stands the program includes 
;three messages.  More messages could be added with appropriate adjustments to EEPROM memory locations.

;PD0 and PD1 are used to provide power to a sidetone oscillator.  PD0 for normal operation,
;PD1 for memory input.  

;The messages are written using the following code and programming adapted from
;the Parallax "BASIC Stamp Programming Manual 1.8" available on the internet.    


;In this program, A=decimal 66 or binary 01000010.  0s represent dits and
;1s represent dahs.  Thus, working from left to right, the first two bits of the
;binary number code for dit dah is 01.  the last 3 bits indicate the nuber of elements
;to be sent; in this case two.  Therefore the last three bits are 010.  Note that
;the code for a word space is decimal 0.

;The number of characters in each message is indicated by the variable "Index" (register 18)
;which is stored in the last EEPROM space alloted to each message.  Word spaces count too.

;***************************************************************************
;* 
;* EEWrite_seq (AVR100)
;*
;* This subroutine increments the EEPROM address by one and waits until the 
;* EEPROM is ready for programming. It then programs the EEPROM with 
;* register variable "EEdwr_s".
;*
;* Number of words	:7 + return
;* Number of cycles	:10 + return (if EEPROM is ready)
;* Low Registers used	:1 (EEWtmp)
;* High Registers used:	:1 (EEdwr_s)
;*
;***************************************************************************
;* 
;* EERead_seq (AVR100)
;*
;* This subroutine increments the address stored in EEAR and reads the 
;* EEPROM into the register variable "EEdrd_s".
;*
;* Number of words	:6 + return
;* Number of cycles	:12 + return (if EEPROM is ready)
;* Low Registers used	:2 (EErtmp,EEdrd_s)
;* High Registers used:	:None
;*
;***************************************************************************


.include "tn2313def.inc"


.equ T1 = 16				;Use T1 and T2 to set speed range.  Larger
.equ T2 = 20				;values give slower speeds.

.equ msg1_start = 0xff		;Each msg_start is the actual start address - 1 
.equ msg2_start = 0x28		;EEAR <- (start address - 1)
.equ msg3_start = 0x50		;With the values used here, up to 39 characters can 
							;be entered with the index at position 40.
.equ msg1_index = 0x27		;Each msg_index is the actual index address - 1
.equ msg2_index = 0x4f		;EEAR <- (index address - 1)
.equ msg3_index = 0x77
.equ mem_max = 39			;maximum number of characters that can be entered in a 
							;memory


.def EEwtmp	= r0			;temporary storage of address
.def EErtmp	= r0			;temporary storage of address
.def EEdrd = r1				;result data byte
.def temp1 = r16			;temporary register (used for delay loops)
.def temp2 = r17			;temporary register (used for delay loops)
.def Index = r18			;number of characters to be sent
.def Elements = r19			;number of dits and dahs in character
.def Character = r20		;number representing character to be sent
.def dit_next = r21			;A 1 loaded here causes a dit to be sent as the next element
.def dah_next = r22			;A 1 loaded here causes a dah to be sent as the next element
.def input = r23			;EEPROM data entry register
.def msg_id = r24			;message identifier
.def count_down = r25		;keeps track of how many elements entered

;----------------------------------------------------------------------------------

.cseg
.org 0

	rjmp reset

;----------------------EEPROM Write Sequence -------------------------------------


EEWrite:
	sbic	EECR,EEPE 		;EEWE; if EEWE not clear
	rjmp	EEWrite			;wait more
	in	EEwtmp,EEAR			;get address
	inc	EEwtmp				;increment address
	out	EEAR,EEwtmp			;output address
	out	EEDR,input 			;EEdwr; output data
	sbi EECR,EEMPE
	sbi	EECR,EEPE 			;EEWE;set EEPROM Write strobe
							;This instruction takes 4 clock cycles since
							;it halts the CPU for two clock cycles
	ret

;------------------- EEPROM Read Sequence ------------------------------

EERead:
	in	EErtmp,EEAR			;get address
	inc	EErtmp				;increment address
	out	EEAR,EErtmp			;output address
	sbi	EECR,0 				;EERE; set EEPROM Read strobe
							;This instruction takes 4 clock cycles since
							;it halts the CPU for two clock cycles
	sbi	EECR,EERE			;set EEPROM Read strobe 2nd time
							;This instruction takes 4 clock cycles since
							;it halts the CPU for two clock cycles
	in	EEdrd,EEDR			;get data
	ret

;----------------------------- Delay Loop --------------------------------------

delay:

	ldi temp1, T1				;load temp1 with time T1	
	L1: ldi temp2, T2			;load temp2 with time T2
	L2:							;T1 and T2 set the range for the speed control
		dec temp2				;decrement temp2
		brne L2					;if temp2 not = 0, go to L2
		sbis pinb, 1			;otherwise check PB1, skip next instruction if high but
		ldi dit_next, 1			;if low, load dit_next with 1 (i.e. 0b0000001)
		sbis pinb, 2			;check PB2, skip next instruction if high but otherwise
		ldi dah_next, 1			;if low, load dah_next with 1 (i.e. 0b00000001)
		dec temp1				;decrement temp1
		brne L1					;if temp1 not = 0 go through the whole loop again.  Otherwise
		ret						;return to dits or dahs.

;------------ Delay Loop for Memory ---------------------------------------

Mdelay:							;Memory delay - as for "delay" with slight changes
								;as necessary for proper operation with the messages.
	ldi temp1, T1				
	Loop1: ldi temp2, T2
	Loop2:

		dec temp2
		brne Loop2
		nop						;no op to give same timing as for delay loop
		nop		
		nop	
		dec temp1
		brne Loop1
		ret						;return to dot or dash

;--------------------------------------------------------------------------------

Msg1:
 
	ldi temp1, msg1_index		;index address for msg1 
	out EEAR, temp1				;EEAR <- (start address - 1)
	ldi ZL, 2					;Z-pointer points to r2
	rcall EERead
	st z,EEdrd
	ld index, z
	ldi	temp1, msg1_start		;msg1 address begins at 0
	out	EEAR,temp1				;EEAR <- $ff (start address - 1)
	ldi	ZL,2					;Z-pointer points to r2
	rjmp Fetch_char

Msg2:

	ldi temp1, msg2_index		;index address for msg2
	out EEAR, temp1				;EEAR <- (start address - 1)
	ldi ZL, 2					;Z-pointer points to r2
	rcall EERead
	st z,EEdrd
	ld index, z
	ldi temp1, msg2_start		
	out EEAR, temp1				;EEAR <- (start address - 1)
	ldi ZL, 2					;Z-pointer points to r2
	rjmp Fetch_char

Msg3:

	ldi temp1, msg3_index		;index address for msg3
	out EEAR, temp1				;EEAR <- (start address - 1)
	ldi ZL, 2
	rcall EERead
	st z,EEdrd
	ld index, z
	ldi	temp1, msg3_start		;msg3 start
	out	EEAR,temp1				;EEAR <- (start address - 1)
	ldi	ZL,2					;Z-pointer points to r2
	rjmp Fetch_char

;----------------------- Initialisation -----------------------------------------

reset:

	ldi temp1, RAMEND         	;Initial Stack Pointer
	out SPL,temp1            	;SP = RAMEND
	ldi temp1, 0b00000001		;PB0 (pin 12) output
	out ddrb, temp1
	ldi temp1, 0b11111110		;set pull-up on PB1...PB7
	out portb, temp1
	ldi temp1, 0b00000001		;PD0 (pin 2) output - PD0 is used to turn the 
	out ddrd, temp1				;sidetone on and off, except for the msg entry,
	clr dit_next				;which uses PD1 while PD0 is tristated.
	clr dah_next
	clr index
;To access the message inputs one of the message pins (PB3, PB4 or PB5)
;must be held low when the power to the chip is turned on.  Otherwise
;this section of the program will already be passed before the pin can
;be grounded. 

	in temp1, pinb				;The first 4 lines of code check to see if any
	andi temp1, 0b00111000		;of the msg buttons are pressed.  If not, the 
	cpi temp1, 0b00111000		;program skips to "poll_loop".
	breq poll_loop
	ldi temp1, 0b00000010		;These 2 lines make PD1 an output, instead of
	out ddrd, temp1 			;PD0.  PD0 is tri-stated while the message is
								;entered.  PD1 is used for the sidetone.

;The following 6 lines check to see which one of the 3 message buttons is
;pressed, and then direct the program to the correct message input location.

	sbis pinb, 3				;skip if PB3 (pin 14) is high, otherwise
	rjmp input_msg1				;jump to message input for msg1

	sbis pinb, 4				;msg2 input
	rjmp input_msg2

	sbis pinb, 5				;msg3 input
	rjmp input_msg3

;-------------------------------------------------------------------------
;---------------- Polling Loops ------------------------------------------

;The program loops continuously through the poll loop checking for 
;branching instructions regarding sending messages or dits or dahs.

poll_loop:

;Check to see if a did or dah is stored to be sent.

	sbrc dit_next, 0		;skip if bit 0 in register dit_next is 0
	rjmp dit				;otherwise go to dit and send a dit

	sbrc dah_next, 0		;skip if bit 0 in register dah_next is 0
	rjmp dah				;otherwise go to dah and send a dah

;------------------------ Message Choices ------------------------------------

;Check to see if any of the messages is to be sent.

	sbrc dit_next, 1		;If bit 1 in dit_next is set, this indicates that msg input
	rjmp mem_clr			;is complete

	sbis pinb, 3 			;skip next instruction if PB3 (pin 15) is high. 
	rjmp msg1

	sbis pinb, 4
	rjmp msg2

	sbis pinb, 5
	rjmp msg3

;--------------------- Dit or Dah Choice ------------------------------------------

;Check to see if the dit or dah key is pressed.

	sbis pinb, 1			;skip if PB1 is high
	rjmp dit 				;otherwise, send a dit

	sbis pinb, 2			;skip if PB2 is high
	rjmp dah 				;otherwise, send a dah
	rjmp poll_loop			;continue polling until something happens

;----------------------------------------------------------------------

mem_clr:

	clr dit_next				;bit 1 set sends program to mem_clr - clear dit_next
	in temp1, pinb				;check pinb to see if any of the memory switches are
	andi temp1, 0b00111000		;pressed.  If so, keep looping around until the switch
	cpi temp1, 0b00111000		;is no longer pressed.  Return to poll_loop.
	brne mem_clr

	rjmp poll_loop

;Without this loop in mem-clr, the  program will send a series of 5 dash groups from
;0xff stored in EEPROM as soon as the memory input is complete.  With this loop the 
;program sends the entered message and then reverts to normal keyer operation.

;------------------ Keyer ---------------------------------------------

dit:

	sbi pinb, 0				;toggle PB0 high to key xmttr
	sbi pind, 0				;toggle PD0 high for sidetone
	rcall delay				;delay for 1 dit length
	sbi pinb, 0				;toggle PB0 low - key off
	sbi pind, 0				;toggle PD0 low - turn off sidetone
	rcall delay				;delay for 1 dit length
	clr dit_next			;since a dit has just been sent, clear register dit_next
	rjmp poll_loop 			;return to poll_loop

dah:

	sbi pinb, 0				;toggle PB0 high to key xmttr
	sbi pind, 0				;toggle PD0 high for sidetone
	rcall delay				;delay for 3 dit lengths
	rcall delay
	rcall delay
	sbi pinb, 0				;toggle PB0 low - key off
	sbi pind, 0				;toggle PD0 low - turn off sidetone
	rcall delay				;delay for 1 dit length
	clr dah_next			;since a dah has just been sent, clear register dah_next
	rjmp poll_loop			;return to poll_loop

;------------------------------------------------------------------------------------

poll_loop1:

 	rjmp poll_loop	;needed to reach poll_loop which is otherwise out of reach

;------------------ Morse Memory Program -------------------------------------

Fetch_char:

	rcall EERead				;get EEPROM data
	st	z,EEdrd					;store to SRAM
	ld Character, z+;   		lpm Character, z+ 

Read:

    ldi Elements, 0b00000111		;Check for digits 0, 1 and 2 of the character.
    and Elements, Character		;Logical AND elem & char; results in element.
    cpi Elements, 0				;If character = 0 then a word space will be sent.
    breq Wspace
    cpi Elements, 6				;6 element character ending in dit
    breq adj1
    cpi Elements, 7				;6 element character ending in dah
    breq adj2
    rjmp Key 

adj1:

   andi Character, 0b11111011	;Adjust character to send dit as 6th element.
   rjmp Key

adj2:

    ldi Elements, 6				;Adjust character to send 6 elements with a dah as 6th element.
    rjmp Key

Key:

	in temp1, pinb				;if either dit or dah inputs (PB1 and PB2) are
	andi temp1, 0b00000110		;low then the program will cease sending
	cpi temp1, 6 				;the message and return to the poll loop
	brne poll_loop

    cpi Character, 128			;If character starts with a 1, skip to dah.
    brsh Dash						;otherwise, send a dit
    rjmp Dot

Cspace:							;character space
								
	dec index					;since a complete character has been sent, decrement index 
	breq poll_loop1				;if index now = 0, the message is complete - continue polling
	rcall Mdelay				;delay for 2 dit lengths (3 dit lengths in total)
	rcall Mdelay
	rjmp Fetch_Char 			;Fetch next character to be read

WSpace:							;word space

	dec index					;since a word space counts as a character, decrement index
	breq poll_loop1				;if index now = 0, continue polling
	rcall Mdelay				;delay for 4 dit lengths (5 in total) between words
	rcall Mdelay				;only 4 dit lengths are needed here because one is 
	rcall Mdelay				;already sent on completion of an element.
	rcall Mdelay
	rcall Mdelay
	rjmp Fetch_Char 			;Fetch next character to be read

Shift:

   	lsl Character				;Shift character to left so as to send the
   	dec Elements  				;next element of the character; dec elements
   	brne Key
	rjmp Cspace					;so as to send just the correct # of elements.

Dot:

	sbi pinb, 0					;toggle PB0 high - key xmttr
	sbi pind, 0					;toggle PD0 high - sidetone
	rcall Mdelay				;recall memory delay for 1 dit length
	sbi pinb, 0 				;toggle PB0 low - key off
	sbi pind, 0					;toggle PD0 low - sidetone off
	rcall Mdelay				;recall momory delay for 1 dit lenth
	rjmp Shift					;shift character to left for next element to be sent

Dash:

	sbi pinb, 0					;toggle PB0 high - key
	sbi pind, 0					;toggle PD0 high - sidetone
	rcall Mdelay				;recall memory delay for 3 dit lengths
	rcall Mdelay
	rcall Mdelay
	sbi pinb, 0					;toggle PB0 low - key
	sbi pind, 0					;toggle PD0 low - sidetone
	rcall Mdelay				;recall memory delay for 1 dit length
	rjmp Shift					;shift character to left for next element to be sent

;----------------------- Message Input ------------------------------------------

input_msg1:

	in temp1, pinb				;These four lines of code create a pause -
	andi temp1, 0b00000110		;they cycle through "input_msg1" until either
	cpi temp1, 6				;the dot or dash key is pressed.  Once either key
	breq input_msg1				;is pressed the program moves on to store the message.

;	clr index					;set index to 0 so as keep track of how many
								;characters are in msg1.
	ldi msg_id, 0b00000001		;identifier for msg1 = 0b00000001, see "save"
	ldi temp1, msg1_start		;msg1 start position in EEPROM
	out	EEAR,temp1				;EEAR <- $ff (start address - 1)
	rjmp Write_char

input_msg2:

	in temp1, pinb				;pause - as for "input_msg1"
	andi temp1, 0b00000110
	cpi temp1, 6
	breq input_msg2

;	clr index					;set index to 0
	ldi msg_id, 0b00000010		;msg2 identifier = 0b00000010, see "save"
	ldi temp1, msg2_start			;set starting address for msg2
	out	EEAR,temp1				;EEAR <- (start address - 1)
	rjmp Write_char

input_msg3:

	in temp1, pinb				;pause - as for "input_msg1"
	andi temp1, 0b00000110
	cpi temp1, 6
	breq input_msg3
	
;	clr index					;set index to 0
	ldi msg_id, 0b00000100		;msg3 identifier = 0b00000100, see "save"
	ldi temp1, msg3_start			;set starting address for msg3
	out	EEAR,temp1				;EEAR <- (start address - 1)
	rjmp Write_char

Write_char:

	cpi index, mem_max			;maximum number of characters per msg
	breq save					;save message if max exceeded

	clr elements
	clr input
	clr temp1
	ldi count_down, 7			;1 byte = 8 bits; count_down indicates position
								;within the byte

msg_loop:

	sbrc dit_next, 0			;skip if bit 0 in register dit_next is 0
	rjmp dit_mem				;otherwise go to dit and store a dit

	sbrc dah_next, 0			;skip if bit 0 in register dah_next is 0
	rjmp dah_mem				;otherwise go to dah and store a dah

	sbis pinb, 1				;skip if PB1 is high
	rjmp dit_mem 				;otherwise, store a dit

	sbis pinb, 2				;skip if PB2 is high
	rjmp dah_mem 				;otherwise, store a dah

mshift:							;if neither dit nor dah are to be stored then
								;there are no more elements in the character
	lsl input					;bits must be left shifted to start at most 
	dec count_down				;sig bit position - reached when "count_down" = 0
	brne mshift
	add input, elements			;number of elements in 3 least sig bits, elements in most sig bits 
	breq space					;no elements = 0,  Space between characters
	rcall EEWrite				;save in EEPROM
	inc index					;one more character to be sent, therefore inc. index
	rcall delay
	rcall delay

	rjmp Write_char				;repeat input of character

space:

	rcall EEWrite				;insert a space in the EEPROM and increment index
	inc index
	rjmp wait_loop				;jump to "wait_loop" and loop until more characters
								;are entered or a message button is pressed

save:

	ldi temp1, 0b00000001			;Now that the message has been entered, PD0
	out ddrd, temp1					;is used for the sidetone instead of PD1.  PD1
									;is tri-stated.
																	
	mov input, index				;move index to input for EEPROM write
	sbrc msg_id, 0					;a 1 in 0th bit of msg_id identifies msg1
	rjmp save1

	sbrc msg_id, 1					;a 1 in bit 1 of msg_id identifies msg2
	rjmp save2

	sbrc msg_id, 2					;a 1 in bit 2 of msg_id identifies msg3
	rjmp save3


save1:

	ldi	temp1, msg1_index				;store index for msg1 in EEPROM at msg1_index
	out	EEAR, temp1					
	rcall EEWrite	
	rjmp poll_loop

save2:

	ldi	temp1, msg2_index				;store index for msg2 in EEPROM at msg2_index
	out	EEAR, temp1					
	rcall EEWrite
	rjmp poll_loop

save3:

	ldi	temp1, msg3_index				;store index for msg3 in EEPROM at msg3_index
	out	EEAR, temp1					
	rcall EEWrite
	rjmp poll_loop

;-----------------------

dit_mem:

	sbi pind, 1				;sidetone - on
	lsl input				;a 0 will be shifted one place to the left in "input"
	inc elements			;an element has been added - therefore increment "elements"
	dec count_down			;one element added, one less place to shift left - dec "count_down"
	rcall delay				;delay of one dit length
	sbi pind, 1				;sidetone - off
	rcall delay				;delay of one dit length for space between elements
	clr dit_next			;since a dit has just been stored, clear register dit_next
	rjmp msg_loop			;return to "msg_loop"

dah_mem:

	sbi pind, 1				;sidetone - on
	inc input				;place a 1 in least sig bit location
	lsl input				;shift 1 one place to left
	inc elements			;an element has been added - therefore increment "elements
	dec count_down			;one element added, one less place to shift left - dec "count_down"
	rcall delay				;delay for dah length
	rcall delay
	rcall delay
	sbi pind, 1				;sidetone - off
	rcall delay				;element spacing
	clr dah_next			;since a dah has just been stored, clear register dit_next
	rjmp msg_loop			;return to "msg_loop"

wait_loop:

;With a pause between character entry a space is inserted and the program loops 
;through "wait_loop" until more characters are entered or a memory switch is pressed.
;Memory switch press here indicates the end of memory input.  

;	cpi index, mem_max			;If more than mem_max characters, then save data in
;	breq save					;memory.
	sbis pinb, 1				;Otherwise, check dit and dah inputs; if either
	rjmp Write_char				;is pressed, then go to Write_char to enter data
	sbis pinb, 2				;into EEPROM.
	rjmp Write_char

	in temp1, pinb				;Check to see if any of the msg buttons are pressed. 
	andi temp1, 0b00111000		;If not, loop through wait_loop until either dit or dah 
	cpi temp1, 0b00111000		;or a message button is pressed.
	breq wait_loop
	ldi dit_next, 0b00000010	;If a message button is pressed, load 0b00000010 into
	rjmp save 					;dit_next so that on the return to the poll the new
								;message will be sent.

[/code]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry. I have not got the patience to trawl through your code.
Remember that the 2313 has only got 64 bytes of EEPROM.

I am fairly certain that it will wrap if you put 65 into EAR.

You should be able to simulate your code in Studio.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just curious, why have you written your application in assembler?

Avrisp mk ii
Xplained Atxmega128A1
ATTiny13, Mega328, Mega8 etc.
Pololu USB AVR Programmer
Open Workbench Logic Sniffer
AVR Studio 4 & 5

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for the replies to my questions.

According to the data sheet for the ATtiny2313 it has 128 bytes of EEPROM so I think I should be ok using 40 bytes for each memory.

I'm using assembler because I don't know how to use anything else.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I'm using assembler because I don't know how to use anything else.
That's an EXCELLENT reason. :-)

Pity some people don't understand that. Would the same question been asked if you had written it in BASIC, Pascal, ADA, Forth? :roll:

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I'm using assembler because I don't know how to use anything else.

Quote:
That's an EXCELLENT reason.
:)

+1 I only code in assembler as I don't know how in 'C' myself

Msg1: 

ldi temp1, msg1_index ;index address for msg1 
out EEAR, temp1 ;EEAR <- (start address - 1) 
ldi ZL, 2 ;Z-pointer points to r2 
rcall EERead 

YOu might want to clear ZH and then load ZL. This has nothing to do with not loading eead but I noticed it also you need to put an 'r' in front of '2'

ldi ZL, 2 ;Z-pointer points to r2 

should look like:

ldi ZL,r2 ;Z-pointer points to r2 

The z register does not point to r2, but gets its contents from r2

The code for MSG1 is confusing, you are loading the eear twice with two different numbers. Can you explain why? If you know the actual start address, then load a register with it, then move it to EEAR, and just increment the register n times until all the charachters are loaded.

I don't have time now, but if you pm me the .asm file I will run it tonight for you.

I won't do your homework, but I will see where the error is, and will be better to suggest a solution.

Unless the mighty Samperi hasa already found the boo boo ;)

EDIT:
I re-read through the code and see an error with regardss to loading from program memory

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wrote a system in Assembler once (it was all I knew) for an orthopedic medical device, but the FDA refused to approve our device until the code was written in a high level language. We moved to C. Don't expect to use this code to transmit morse code between medical devices : )

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
ldi ZL, 2 ;Z-pointer points to r2

should look like:
Code:
ldi ZL,r2 ;Z-pointer points to r2


More like this if you actually want to move r2 to ZL and not load 2 into ZL as in your code.
mov   zl,r2  ;move r2 to ZL

Quote:
I wrote a system in Assembler once (it was all I knew) for an orthopedic medical device, but the FDA refused to approve our device until the code was written in a high level language.
That sounds plain stupid.
I used to maintain the code for some medical devices.
All code was written entirely in assembler.
The company never had any problems to pass regulations.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
More like this if you actually want to move r2 to ZL and not load 2 into ZL as in your code.

Correct!! I missed changing the LDI command

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
.equ msg1_start = 0xff		;Each msg_start is the actual start address - 1 
.equ msg1_index = 0x28		;Each msg_index is the actual index address - 1

;----------------------------------------

EEPROM_indexread:

	sbic EECR,EEPE			;Wait for completion of previous write
	rjmp EEPROM_indexread
	out EEARL, temp1 		;Set up address in address register
	sbi EECR,EERE			;Start eeprom read by writing EERE
	in index, EEDR 			;Read data from data register
	ret



;------------------------------------------
Msg1:
 
	ldi temp1, msg1_index		;0x14 = index address for msg1 
	rcall EEPROM_indexread ;EERead
	ldi	temp1, msg1_start		;msg1 address begins at 0
	out	EEAR,temp1				;EEAR <- $ff (start address - 1)
	mov zl, r2;ldi	ZL, 2					;Z-pointer points to r2
	rjmp Fetch_char

You read one byte at ox14, then return to msg1:
You then load the address register with oxFF, but say the message starts at 0x00 but I see nowhere that the code adds or subtraacts one to start at that address

What is with that?

Aalso, asa David noted trawling through your code is a headache. Your subroutines are all over the place. Putting all the subroutines at the end of the code makes for easier debugging

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry about by erroneous comment about eeprom size. 128 bytes is better than 64 but still not very much.

Life is harder in assembly language, but not impossible.

If you structure the program wisely, it can be easy to read too!
e.g.

    .org 0
    rjmp start
    ...                 ; vectors
    .org OVF0addr
    rjmp isr_tim0_ovf
    ...
start:
    rcall init          ; brief explanation
    rcall setup         ; 
loop:
    rcall do_something  ; main logic
    rjmp loop

; purpose     : what subroutine does
; parameters  : what registers or memory
; return      : what values in what registers
; side-effects: what registers are destroyed etc
init:
    ...
    ret

You can use the same comment template for all your subroutines.
Just make sure that you have accurate information.

I always try to make any function short enough to fit on the page. You can always put some sequences into a subroutine, even if it only occurs once. The CALL and RET produce some overhead, but your readability pays for it. You can always use MACROS for some sequences.

AVRs have an 'unlimited' call stack. i.e. you never need worry about nested subroutines. In practice you seldom go more than 5 or 6 deep.

Other makes of certain brain-dead MCUs are only capable of spaghetti due to one-deep or two-deep hardware stacks.
Remember that with AVRs, there is no need to go 'Italian'.

If you tidy up your code and lay it out with some 'structure', you will get some readers. But more importantly you will help yourself.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have done a lot of assembly language (not AVR)

Organising and documenting code is the important point, irrespective of language.

Essential information in a comment header beats verbose descriptions like "skip if PB2 is high ". You have one place to refer to.
You can prettify it how you like.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for the additional comments and suggestions. I am learning from them and am finding them very helpful.

I'm sure that my code organisation could be improved a great deal, as David and Jim have noted. Since I've not had a course in programming, generally I've been using data sheets, AVR application notes and other programs as guides to my own work, and the feedback about program structure really helps. Thank you.

I sent Jim an updated version of the program I had first posted in which I made some changes to try to overcome the problem I was having with getting the correct number of characters played back from the memory. This change includes two new subroutines
EEPROM_indexwrite and EEPROM_indexread that don't increment the EEPROM address.

Quote:
You read one byte at ox14, then return to msg1:
You then load the address register with oxFF, but say the message starts at 0x00 but I see nowhere that the code adds or subtraacts one to start at that address

The comment 0x14 is incorrect - it is left over from one of the many previous trials I made. The actual address is 0x28 (msg1_index) - the last position of the 40 bytes reserved for message 1. In this subroutine, the register "index" is loaded with the index value which should tell the program how many characters to send back. In the next lines of the program (Fetch_char) the characters are read back from EERead. In the EERead subroutine the address is incremented.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you don't need it, then comment it out with a semicolon ';', or detelet it altogether.

I have been running the code and it hits that instruction and executes it. Very frustrating.

That could be part of your problem. You have old code that is not needed mixed in with correct.

Delete or comment out what you don't need and re-assemble and run the new code

Let us know what happens

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
That sounds plain stupid.
I used to maintain the code for some medical devices.
All code was written entirely in assembler.
The company never had any problems to pass regulations.

Curious, this happened in 1991 or 1992 for me.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Jim,

I just finished trying the changes you suggested in your last post.

Quote:

If you don't need it, then comment it out with a semicolon ';', or detelet it altogether.

I have been running the code and it hits that instruction and executes it. Very frustrating.


I was not expecting any change in results because the parts you referred to were commented out with a ; in the program I sent you and in the program I had loaded into the 2313 with which I've been testing the program. Nevertheless, I went ahead and deleted the 0x14, 0x28 and 0x3c entirely in msg1, msg2 and msg3 and, to my surprise and delight, the program now works properly.

I really don't know why it didn't work before. Before I first posted my question I had used the Studio 4 simulator to find the problem. I had noticed some behaviour that I hadn't expected and seemed to be at odds with the code instruction. Whatever the reason, it is really nice to have the keyer working as it should.

Thank you to all of you who took the time to help me. I appreciate the assistance very much.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The code you sent did not have what I posted commented out thats why I brought it to light.

As long as everything is working then GREAT!!

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user