Problem with RAM fill routine

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

Hello all,

I am working on a project and am having a little difficulty with it. What the below section of code does is fill up a block of SRAM (32k) with a repeating pattern of 16bit values representing a sine wave. (Example The pattern 1, 2, 3, 4 is put into the ram like: 1, 2, 3, 4, 1, 2, 3, 4, 1, 2.)

I suspect most of my confusion is with the internal locations needing to be multiplied by 2 which I don’t really understand fully yet.

It currently causes the microcontroller to freeze.

I’m wondering if anyone could help me figure this out,

Thanks

;Parameters used:
;X: High and low data
;Y: SRAM Address and Address+1
;Z: Program memory pointer

Init_SRAM:
	clr YH
	clr YL

Restart:
	ldi ZL, LOW(2*Sine_Data)
	ldi ZH, HIGH(2*Sine_Data)

Repeat:
	lpm XH, Z+
	lpm XL, Z
	rcall Write_SRAM
	adiw R30, 0x01

	cpi YH, 0x7F	;SRAM end check
	brne Cont
	cpi YH, 0xFE
	breq Sub_done
	
Cont:
	cpi XH, 0x00	;Data block end check
	brne Repeat
	cpi XL, 0x00
	brne Repeat
	rjmp Restart

Sub_Done:
	rjmp Done

Sine_Data:
.dw 286, 572, 858, 1144, 1429, 1715, 2000, 2286, 2571, 2856, 3141, 3425, 3709, 3993, 4277, 4560, 4843, 5126, 5408, 5690

.....(lots of values)

.dw -5408, -5126, -4843, -4560, -4277, -3993, -3709, -3425, -3141, -2856, -2571, -2286, -2000, -1715, -1429, -1144, -858, -572, -286, 0

A few notes on the program:
The Sub_Done label and jump is used because the breq instruction cannot jump the distance required.
Writing the SRAM involves a routine called Write_SRAM.  This routine works because I have been using it quite extensively over the past few months.  It uses the values contained in X and Y to function as well as arranging the 16bit values in the way I require.
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
;Y: SRAM Address and Address+1
Init_SRAM:
   clr YH
   clr YL 

You probably shouldn't start your sink at 0x0000, since this will write over your registers and, though you won't get that far, your I/O space.
I suspect you want to start at RAMEND+1 (or maybe lower, if you're careful with your stack).

Edit: Fix 8515 dependencies.

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

The multiply by 2 thing is because the Sine_Data label refers to a flash address. The flash is word-addressed to save one bit in jumps and calls. But to be able to access all bytes with LPM, it takes a byte-address. So you multiply by two to convert from word address to byte address.

And about the code (in addition to mckenney's comment):

Shouldn't lpm XL, Z be lpm XL, Z+ ?

Shouldn't adiw R30, 0x01 be adiw R28, 0x02 ? (I assume you want to increase Y here.)
Hmm... maybe Y is incremented in Write_SRAM. Then those two comments should cancel each other.

Shouldn't cpi YH, 0xFE be cpi YL, 0xFE ?

And are you sure that you haven't got a 0 in the middle of your data?

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

mckenney wrote:

;Y: SRAM Address and Address+1
Init_SRAM:
   clr YH
   clr YL 

You probably shouldn't start your sink at 0x0000, since this will write over your registers and, though you won't get that far, your I/O space.
I suspect you want to start at RAMEND+1 (or maybe lower, if you're careful with your stack).

Edit: Fix 8515 dependencies.

Sorry, forgot to add that this program is accessing external SRAM. Dual ported SRAM to be exact, this section of code is just meant to be a initialization for testing and debugging purposes.

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

Henrik G wrote:
The multiply by 2 thing is because the Sine_Data label refers to a flash address. The flash is word-addressed to save one bit in jumps and calls. But to be able to access all bytes with LPM, it takes a byte-address. So you multiply by two to convert from word address to byte address.

And about the code (in addition to mckenney's comment):

Shouldn't lpm XL, Z be lpm XL, Z+ ?

Shouldn't adiw R30, 0x01 be adiw R28, 0x02 ? (I assume you want to increase Y here.)
Hmm... maybe Y is incremented in Write_SRAM. Then those two comments should cancel each other.

Shouldn't cpi YH, 0xFE be cpi YL, 0xFE ?

And are you sure that you haven't got a 0 in the middle of your data?

Just so you know I'm not ignoring you post, I'll get to it in a few hours (morning here). I'll let you know how things turn out.

Thanks,

Will

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

Aside from echoing previous comments about overwriting the registers and IO (RAM address 0 = R0) - perhaps your Write_SRAM routine adjusts the address - this bit won't work:

   cpi YH, 0x7F   ;SRAM end check 
   brne Cont 
   cpi YH, 0xFE 
   breq Sub_done 
    
Cont: 

If you get to the second CPI, YH cannot be equal to 0xFE, so it will ALWAYS execute Cont. Perhaps you meant to write "cpi YL,0xFE"

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

I got my program working for the most part. The is only one problem in my SRAM access routine.

The following code causes entire write process to never complete:

Quote:
st Y, XL
adiw YH:YL, 1
st Y, XH
sbiw YH:YL, 1

The following code works fine (except it doesn't write the LSB of X to the SRAM)

Quote:
;st Y, XL adiw YH:YL, 1
st Y, XH
sbiw YH:YL, 1

I have tried ever other configuration including commenting out the second ST instruction instead of the first and none of them cause problems.

Hmmmmm

Thanks for the help everyone!

Edit: I should probably note that this SRAM access routine has worked for me on this very same hardware without so much as a hiccup until now.

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

I have tried every possible way to get this part to work. It seems it is impossible to do what I want to do, write a high and low byte to the SRAM. Does anyone have another way I can perform this task?

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

Maybe it's time for you to re-post your current source, including Write_SRAM -- there have been a number of suggested changes, and the
only piece of Write_SRAM you've posted is too small to say anything useful about. (OK, you're welcome to leave out most of the data table.)

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

Good idea. Here's the relevant code. I believe there still one other bug (probably obvious) that causes problems in where the data is stored as when I read the SRAM I don't get familiar data.

;Init SRAM.asm

;Parameters used:
;X: High and low data
;Y: SRAM Address and Address+1
;Z: Program memory pointer

Init_SRAM:
	clr YH
	clr YL

Restart:
	ldi ZL, LOW(2*Sine_Data)
	ldi ZH, HIGH(2*Sine_Data)

Repeat:
	lpm XH, Z+
	lpm XL, Z+
	rcall Write_SRAM
	adiw R28, 0x02

	cpi YH, 0x7F	;SRAM end check
	brne Cont
	cpi YL, 0xFE
	breq Sub_Done
	
Cont:
	cpi XH, 0x00	;Database end check
	brne Repeat 
	cpi XL, 0x00
	brne Repeat
	rjmp Restart

Sub_Done:
	rjmp Done

Sine_Data:
.dw 286, 572, 858, 1144, 1429, 1715, 2000, 2286, 2571, 2856, 3141, 3425, 3709, 3993, 4277, 4560, 4843, 5126, 5408, 5690
....
.dw -5408, -5126, -4843, -4560, -4277, -3993, -3709, -3425, -3141, -2856, -2571, -2286, -2000, -1715, -1429, -1144, -858, -572, -286, 0

Done:
	cbi Portb, pstat2
;**Write SRAM**

Write_SRAM:
	cpi XH, 0x05
	brlo Add_OffsetW
			;If accessing external address 0x0500 and up.	


	st Y, XL		;Write LSB into XL
	adiw YH:YL, 1	;Increment
	st Y, XH		;Write MSB into XH
	sbiw YH:YL, 1	;Remove increment

	ret

Add_OffsetW:	;If accessing external address 0x0000 to 0x04FF.
	ldi rmp, (1<<XMM1|1<<XMM0)	
	out SFIOR, rmp	;Mask MSB to 0

	ldi rmp, cSRAMoffset
	add YH, rmp		;Add offset

	st Y, XL		;Write LSB into XL
	adiw YH:YL, 1	;Increment
	st Y, XH		;Write MSB into XH

	sbiw YH:YL, 1	;Remove increment
	ldi rmp, cSRAMoffset
	sub YH, rmp		;Remove offset

	ldi rmp, (0<<XMM1|0<<XMM0)	
	out SFIOR, rmp	;Unmask MSB

	ret

Thanks,

Will

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
   lpm XH, Z+
   lpm XL, Z+

This loads the low byte into XH and high into XL. This isn't intrinsically harmful, but it isn't what Write_SRAM expects.

   cpi XH, 0x05
   brlo Add_OffsetW

This tests the Data high-byte, not the address. The effect is that you're writing over the CPU registers (including Yx in
particular) based on the data in the table. This will (at least) scramble the data, and might be the cause of your loop.

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

mckenney wrote:

   lpm XH, Z+
   lpm XL, Z+

This loads the low byte into XH and high into XL. This isn't intrinsically harmful, but it isn't what Write_SRAM expects.

I don't understand what you mean by this. This part of the program is supposed to move the value contained in the program memory as specified by the Z pointer into the X register which is used to hold the data and Write_SRAM does the task of writing them into the SRAM.

Thank you for your help,

Will

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

Yes, but mckenny's point is the address from program memory is loaded backwards - low byte into XH and high byte into XL. Your comments in Write_SRAM explicitly call XL the low byte and XH the high byte.

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

Quote:
mckenney wrote:
Quote:

 
   lpm XH, Z+ 
   lpm XL, Z+ 
 

This loads the low byte into XH and high into XL. This isn't intrinsically harmful, but it isn't what Write_SRAM expects.

I don't understand what you mean by this. This part of the program is supposed to move the value contained in the program memory as specified by the Z pointer into the X register which is used to hold the data and Write_SRAM does the task of writing them into the SRAM.

This is ok if it does what you expect. It doesn't matter as long as you read bytes the same way as you write them.
However, to understand the storage order, look at https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=22246

C.H.

C. H.
-------------------------------------------------------------------
It's only waste if you don't use it!

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

I just wanted to thank all those who helped me out here. I really appreciate it.

Regards,

Will Le Gros