ATMega1284P ELPM instruction issue

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

This question is in relation to a thread that AlanK2 and I have been exchanging having to do with an ELPM instruction "apparently" loading a byte from an incorrect location.

 

Please see middle of thread starting here:

https://www.avrfreaks.net/comment/2667646#comment-2667646

 

When stepping through the assembler it appears that the RAMPZ and Z registers are correctly loaded but the wrong byte value is loaded into R24 after prog space address 2137 (0x0859).  (the offending statement is in a loop going through code space from 0 to end-of-text to do a CRC calculation).

 

I do not have in-depth knowledge of AVR assembler so there is probably something I don't understand about ELPM and therefore am not checking.

 

Suggestions?

 

Thanks in advance ...

 

Regards,

 

Chuck Hackett

This topic has a solution.
Last Edited: Tue. Apr 9, 2019 - 05:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In doing another test this morning I just did four program reads in a row:

void DumbTest( void )
{
	volatile uint8_t TheByte;
	//for ( uint32_t Address = 2136; Address < 3000; Address++ )
		//TheByte = pgm_read_byte_far( Address );

	TheByte = pgm_read_byte_far( 0x0859 );
	TheByte = pgm_read_byte_far( 0x085A );
	TheByte = pgm_read_byte_far( 0x085B );
	TheByte = pgm_read_byte_far( 0x085C );
}

Which generated:

void DumbTest( void )
{
    6b32:	cf 93       	push	r28
    6b34:	df 93       	push	r29
    6b36:	cd b7       	in	r28, 0x3d	; 61
    6b38:	de b7       	in	r29, 0x3e	; 62
    6b3a:	65 97       	sbiw	r28, 0x15	; 21
    6b3c:	0f b6       	in	r0, 0x3f	; 63
    6b3e:	f8 94       	cli
    6b40:	de bf       	out	0x3e, r29	; 62
    6b42:	0f be       	out	0x3f, r0	; 63
    6b44:	cd bf       	out	0x3d, r28	; 61
	volatile uint8_t TheByte;
	//for ( uint32_t Address = 2136; Address < 3000; Address++ )
		//TheByte = pgm_read_byte_far( Address );

	TheByte = pgm_read_byte_far( 0x0859 );
    6b46:	89 e5       	ldi	r24, 0x59	; 89
    6b48:	98 e0       	ldi	r25, 0x08	; 8
    6b4a:	a0 e0       	ldi	r26, 0x00	; 0
    6b4c:	b0 e0       	ldi	r27, 0x00	; 0
    6b4e:	89 83       	std	Y+1, r24	; 0x01
    6b50:	9a 83       	std	Y+2, r25	; 0x02
    6b52:	ab 83       	std	Y+3, r26	; 0x03
    6b54:	bc 83       	std	Y+4, r27	; 0x04
    6b56:	89 81       	ldd	r24, Y+1	; 0x01
    6b58:	9a 81       	ldd	r25, Y+2	; 0x02
    6b5a:	ab 81       	ldd	r26, Y+3	; 0x03
    6b5c:	bc 81       	ldd	r27, Y+4	; 0x04
    6b5e:	ab bf       	out	0x3b, r26	; 59
    6b60:	fc 01       	movw	r30, r24
    6b62:	87 91       	elpm	r24, Z+
    6b64:	8d 83       	std	Y+5, r24	; 0x05
    6b66:	8d 81       	ldd	r24, Y+5	; 0x05
    6b68:	8d 8b       	std	Y+21, r24	; 0x15
	TheByte = pgm_read_byte_far( 0x085A );
    6b6a:	8a e5       	ldi	r24, 0x5A	; 90
    6b6c:	98 e0       	ldi	r25, 0x08	; 8
    6b6e:	a0 e0       	ldi	r26, 0x00	; 0
    6b70:	b0 e0       	ldi	r27, 0x00	; 0
    6b72:	8e 83       	std	Y+6, r24	; 0x06
    6b74:	9f 83       	std	Y+7, r25	; 0x07
    6b76:	a8 87       	std	Y+8, r26	; 0x08
    6b78:	b9 87       	std	Y+9, r27	; 0x09
    6b7a:	8e 81       	ldd	r24, Y+6	; 0x06
    6b7c:	9f 81       	ldd	r25, Y+7	; 0x07
    6b7e:	a8 85       	ldd	r26, Y+8	; 0x08
    6b80:	b9 85       	ldd	r27, Y+9	; 0x09
    6b82:	ab bf       	out	0x3b, r26	; 59
    6b84:	fc 01       	movw	r30, r24
    6b86:	87 91       	elpm	r24, Z+
    6b88:	8a 87       	std	Y+10, r24	; 0x0a
    6b8a:	8a 85       	ldd	r24, Y+10	; 0x0a
    6b8c:	8d 8b       	std	Y+21, r24	; 0x15
	TheByte = pgm_read_byte_far( 0x085B );
    6b8e:	8b e5       	ldi	r24, 0x5B	; 91
    6b90:	98 e0       	ldi	r25, 0x08	; 8
    6b92:	a0 e0       	ldi	r26, 0x00	; 0
    6b94:	b0 e0       	ldi	r27, 0x00	; 0
    6b96:	8b 87       	std	Y+11, r24	; 0x0b
    6b98:	9c 87       	std	Y+12, r25	; 0x0c
    6b9a:	ad 87       	std	Y+13, r26	; 0x0d
    6b9c:	be 87       	std	Y+14, r27	; 0x0e
    6b9e:	8b 85       	ldd	r24, Y+11	; 0x0b
    6ba0:	9c 85       	ldd	r25, Y+12	; 0x0c
    6ba2:	ad 85       	ldd	r26, Y+13	; 0x0d
    6ba4:	be 85       	ldd	r27, Y+14	; 0x0e
    6ba6:	ab bf       	out	0x3b, r26	; 59
    6ba8:	fc 01       	movw	r30, r24
    6baa:	87 91       	elpm	r24, Z+
    6bac:	8f 87       	std	Y+15, r24	; 0x0f
    6bae:	8f 85       	ldd	r24, Y+15	; 0x0f
    6bb0:	8d 8b       	std	Y+21, r24	; 0x15
	TheByte = pgm_read_byte_far( 0x085C );}
    6bb2:	8c e5       	ldi	r24, 0x5C	; 92
    6bb4:	98 e0       	ldi	r25, 0x08	; 8
    6bb6:	a0 e0       	ldi	r26, 0x00	; 0
    6bb8:	b0 e0       	ldi	r27, 0x00	; 0
    6bba:	88 8b       	std	Y+16, r24	; 0x10
    6bbc:	99 8b       	std	Y+17, r25	; 0x11
    6bbe:	aa 8b       	std	Y+18, r26	; 0x12
    6bc0:	bb 8b       	std	Y+19, r27	; 0x13
    6bc2:	88 89       	ldd	r24, Y+16	; 0x10
    6bc4:	99 89       	ldd	r25, Y+17	; 0x11
    6bc6:	aa 89       	ldd	r26, Y+18	; 0x12
    6bc8:	bb 89       	ldd	r27, Y+19	; 0x13
    6bca:	ab bf       	out	0x3b, r26	; 59
    6bcc:	fc 01       	movw	r30, r24
    6bce:	87 91       	elpm	r24, Z+
    6bd0:	8c 8b       	std	Y+20, r24	; 0x14
    6bd2:	8c 89       	ldd	r24, Y+20	; 0x14
    6bd4:	8d 8b       	std	Y+21, r24	; 0x15
    6bd6:	65 96       	adiw	r28, 0x15	; 21
    6bd8:	0f b6       	in	r0, 0x3f	; 63
    6bda:	f8 94       	cli
    6bdc:	de bf       	out	0x3e, r29	; 62
    6bde:	0f be       	out	0x3f, r0	; 63
    6be0:	cd bf       	out	0x3d, r28	; 61
    6be2:	df 91       	pop	r29
    6be4:	cf 91       	pop	r28
    6be6:	08 95       	ret

The load from 0x0859 loaded the correct value, the others did not.

 

One thing I was curious about (not knowing AVR assembler very well): Why the two "CLI" instructions?  Maybe a hint at what is going wrong?

 

BTW: Global interrupts are off in the SREG.

 

This optimized (-O3) code exhibits the same incorrect fetches but is a bit clearer (and, BTW, the CLIs were gone):

	TheByte = pgm_read_byte_far( 0x0859 );
    6af2:	49 e5       	ldi	r20, 0x59	; 89
    6af4:	58 e0       	ldi	r21, 0x08	; 8
    6af6:	60 e0       	ldi	r22, 0x00	; 0
    6af8:	70 e0       	ldi	r23, 0x00	; 0
    6afa:	6b bf       	out	0x3b, r22	; 59
    6afc:	fa 01       	movw	r30, r20
    6afe:	47 91       	elpm	r20, Z+
    6b00:	4d 83       	std	Y+5, r20	; 0x05
	TheByte = pgm_read_byte_far( 0x085A );
    6b02:	4a e5       	ldi	r20, 0x5A	; 90
    6b04:	58 e0       	ldi	r21, 0x08	; 8
    6b06:	60 e0       	ldi	r22, 0x00	; 0
    6b08:	70 e0       	ldi	r23, 0x00	; 0
    6b0a:	6b bf       	out	0x3b, r22	; 59
    6b0c:	fa 01       	movw	r30, r20
    6b0e:	47 91       	elpm	r20, Z+
    6b10:	4d 83       	std	Y+5, r20	; 0x05
	TheByte = pgm_read_byte_far( 0x085B );
    6b12:	4b e5       	ldi	r20, 0x5B	; 91
    6b14:	58 e0       	ldi	r21, 0x08	; 8
    6b16:	60 e0       	ldi	r22, 0x00	; 0
    6b18:	70 e0       	ldi	r23, 0x00	; 0
    6b1a:	6b bf       	out	0x3b, r22	; 59
    6b1c:	fa 01       	movw	r30, r20
    6b1e:	47 91       	elpm	r20, Z+
    6b20:	4d 83       	std	Y+5, r20	; 0x05
	TheByte = pgm_read_byte_far( 0x085C );
    6b22:	4c e5       	ldi	r20, 0x5C	; 92
    6b24:	58 e0       	ldi	r21, 0x08	; 8
    6b26:	60 e0       	ldi	r22, 0x00	; 0
    6b28:	70 e0       	ldi	r23, 0x00	; 0
    6b2a:	6b bf       	out	0x3b, r22	; 59
    6b2c:	fa 01       	movw	r30, r20
    6b2e:	47 91       	elpm	r20, Z+
    6b30:	4d 83       	std	Y+5, r20	; 0x05

I'm at a loss ...

 

Is there some processor mode I am not aware of causing this?  ... it just doesn't like me? ...

 

Chuck

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

... now ... I assume (I know .. dangerous) that Atmel Studio (via JTAG) is showing me actual program memory not what it thinks is there (i.e.: not the contents of the HEX/ELF file).

 

This is what is at location 0x858 as shown by the lss file:

     858:	8c 01       	movw	r16, r24
     85a:	63 cf       	rjmp	.-314    	; 0x722 <Restart_ProcessRestart+0x7c>
     85c:	0e 94 67 69 	call	0xd2ce	; 0xd2ce <Restart_RestartInfo_init>
  

When the offending code tries to read 0x85A it gets 0x98 instead of 0x63 and 0x85B results in 0x95 instead of 0xCF ...

 

Chuck

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

AS7 caches Flash.
.
BTW why are you messing with pgm_read*() functions when __flash/__memx exist?

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

Easy answer - I was unaware of __memx!  How does __memx work with functions like strcpy, memcpy, etc.?  Is there a documentation with example code for it somewhere?  Thanks!

 

Also, is there a way to make a generic __memx pointer pointing to a specific place in sram or flash?

Last Edited: Sat. Mar 30, 2019 - 01:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ChuckH are you debugging this?  Maybe use a UART to output the value the AVR reads instead of counting on AS7 to debug it.

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

clawson wrote:
AS7 caches Flash.

 

Since I am not changing Flash ... Even if AS7 caches Flash ... it should not change what I'm seeing in AS7 as to what is at a given flash location ... correct? 

 

clawson wrote:
BTW why are you messing with pgm_read*() functions when __flash/__memx exist?

 

Glad to look at another approach but "pgm_read_byte_far()" has been used successfully for a long time and should work.  At the moment I'd rather stick with the devil I know.  It compiles to a few straightforward instructions that should work as far as I can tell (and no one has yet told me differently).  I'd like to understand what's going on here before I switch boats ...

 

alank2 wrote:
ChuckH are you debugging this?  Maybe use a UART to output the value the AVR reads instead of counting on AS7 to debug it.

 

I don't see how that would change anything.  The value returned and stored in "TheByte" should be the same displayed in AS7 or sent out the USART.

 

Tests this morning seem to indicate that my symptom is changing depending on where in flash the test code is executing (i.e.: PC location) ... I realize how far-fetched this sounds ...

 

Hardware is ATMega1284P (hence the ELPM).

 

I will investigate more when after I get back from church ... (maybe praying for enlightenment will help smiley)

 

Regards,

 

(a frustrated) Chuck

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

ChuckH wrote:
Tests this morning seem to indicate that my symptom is changing depending on where in flash the test code is executing (i.e.: PC location) ... I realize how far-fetched this sounds ...

 

BTW: The application is about 78,654 bytes of flash and the test code is executing at around 0x3589 (13,705).

 

Chuck

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

Chuck,

 

One of the reasons I suggest trying it a different way is that sometimes that yields something differentt than expected.  That is why the no loop suggestion, then you can see the exact instructions and registers being loaded.  I was thinking about this right when I woke up today and what if you read the flash back using AS7?  What is in the file?  What if you dump it via UART from the device?  (To be sure you are not looking at some cached value in AS7).  I've prayed many times about projects, especially when they do not make sense!

 

Hope the mystery is solved soon!

 

Alan

 

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

You write :

The load from 0x0859 loaded the correct value, the others did not.

How do you know that ? and how do you know to start at 0x0859 ?

 

Remember that flash is 16 bit so addr of code in flash is NOT the same as data from flash!

 

I have never understood why LPM don't load 16 bit from flash ( then 128K flash (64kx16) could fit a 16 bit pointer)  

 

 

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


Ok, more insight (?) ...

 

I created this:

void DumbTest( void )
{
	volatile uint8_t TheByte;
	TheByte = pgm_read_byte_far( 0x0858 );
	TheByte = pgm_read_byte_far( 0x0859 );
	TheByte = pgm_read_byte_far( 0x085A );
	TheByte = pgm_read_byte_far( 0x085B );
	TheByte = pgm_read_byte_far( 0x085C );
	TheByte = pgm_read_byte_far( 0x085D );
	TheByte = pgm_read_byte_far( 0x085E );
	TheByte = pgm_read_byte_far( 0x085F );
	TheByte = pgm_read_byte_far( 0x0860 );
	TheByte = pgm_read_byte_far( 0x0861 );
	TheByte = pgm_read_byte_far( 0x0862 );
	TheByte = pgm_read_byte_far( 0x0863 );
	TheByte = pgm_read_byte_far( 0x0864 );
	TheByte = pgm_read_byte_far( 0x0865 );
	TheByte = pgm_read_byte_far( 0x4000 );
}

which is shown as this in the LSS file:

    volatile uint8_t TheByte;
    TheByte = pgm_read_byte_far( 0x0858 );
    6aca:	88 e5       	ldi	r24, 0x58	; 88
    6acc:	98 e0       	ldi	r25, 0x08	; 8
    6ace:	a0 e0       	ldi	r26, 0x00	; 0
    6ad0:	b0 e0       	ldi	r27, 0x00	; 0
    6ad2:	ab bf       	out	0x3b, r26	; 59
    6ad4:	fc 01       	movw	r30, r24
    6ad6:	87 91       	elpm	r24, Z+
    6ad8:	89 83       	std	Y+1, r24	; 0x01
    TheByte = pgm_read_byte_far( 0x0859 );
    6ada:	89 e5       	ldi	r24, 0x59	; 89
    6adc:	98 e0       	ldi	r25, 0x08	; 8
    6ade:	a0 e0       	ldi	r26, 0x00	; 0
    6ae0:	b0 e0       	ldi	r27, 0x00	; 0
    6ae2:	ab bf       	out	0x3b, r26	; 59
    6ae4:	fc 01       	movw	r30, r24
    6ae6:	87 91       	elpm	r24, Z+
    6ae8:	89 83       	std	Y+1, r24	; 0x01
    TheByte = pgm_read_byte_far( 0x085A );
    6aea:	8a e5       	ldi	r24, 0x5A	; 90
    6aec:	98 e0       	ldi	r25, 0x08	; 8
    6aee:	a0 e0       	ldi	r26, 0x00	; 0
    6af0:	b0 e0       	ldi	r27, 0x00	; 0
    6af2:	ab bf       	out	0x3b, r26	; 59
    6af4:	fc 01       	movw	r30, r24
    6af6:	87 91       	elpm	r24, Z+
    6af8:	89 83       	std	Y+1, r24	; 0x01
    ...

and, thus in the disassembly window:

	TheByte = pgm_read_byte_far( 0x0858 );
00003565  LDI R24,0x58		Load immediate
00003566  LDI R25,0x08		Load immediate
00003567  LDI R26,0x00		Load immediate
00003568  LDI R27,0x00		Load immediate
00003569  OUT 0x3B,R26		Out to I/O location
0000356A  MOVW R30,R24		Copy register pair
0000356B  ELPM R24,Z+		Extended load program memory and postincrement
0000356C  STD Y+1,R24		Store indirect with displacement
	TheByte = pgm_read_byte_far( 0x0859 );
0000356D  LDI R24,0x59		Load immediate
0000356E  LDI R25,0x08		Load immediate
0000356F  LDI R26,0x00		Load immediate
00003570  LDI R27,0x00		Load immediate
00003571  OUT 0x3B,R26		Out to I/O location
00003572  MOVW R30,R24		Copy register pair
00003573  ELPM R24,Z+		Extended load program memory and postincrement
00003574  STD Y+1,R24		Store indirect with displacement
	TheByte = pgm_read_byte_far( 0x085A );
00003575  LDI R24,0x5A		Load immediate
00003576  LDI R25,0x08		Load immediate
00003577  LDI R26,0x00		Load immediate
00003578  LDI R27,0x00		Load immediate
00003579  OUT 0x3B,R26		Out to I/O location
0000357A  MOVW R30,R24		Copy register pair
0000357B  ELPM R24,Z+		Extended load program memory and postincrement
0000357C  STD Y+1,R24		Store indirect with displacement
...

 

Here is what AS7 shows as the flash contents:

 

so far, so good.  Upon stepping through the statements (at the c-source level) the results are:

	TheByte = pgm_read_byte_far( 0x0858 ); -> 8C
	TheByte = pgm_read_byte_far( 0x0859 ); -> 01
	TheByte = pgm_read_byte_far( 0x085A ); -> 98 **
	TheByte = pgm_read_byte_far( 0x085B ); -> 95 **
	TheByte = pgm_read_byte_far( 0x085C ); -> 98 **
	TheByte = pgm_read_byte_far( 0x085D ); -> 95 **
	TheByte = pgm_read_byte_far( 0x085E ); -> C9
	TheByte = pgm_read_byte_far( 0x085F ); -> 69
	TheByte = pgm_read_byte_far( 0x0860 ); -> 63
	TheByte = pgm_read_byte_far( 0x0861 ); -> E0
	TheByte = pgm_read_byte_far( 0x0862 ); -> 8C
	TheByte = pgm_read_byte_far( 0x0863 ); -> E1
	TheByte = pgm_read_byte_far( 0x0864 ); -> 9D
	TheByte = pgm_read_byte_far( 0x0865 ); -> E0

	TheByte = pgm_read_byte_far( 0x4000 ); -> 58 (correct)

Notice that locations 0x085A thru 0x085D were incorrect.

 

Is there something special about these locations?

 

ATMega1284P, app > 64k, PC of first test line 0x3565.

 

ChuckH wrote:

Tests this morning seem to indicate that my symptom is changing depending on where in flash the test code is executing (i.e.: PC location) ... I realize how far-fetched this sounds ...

 

This comment referred to a case where I added code to a function that was lower in memory which changed the PC location of the test lines to 0x3567

 

The location of the code being read shifted up by 4 bytes:

 

When executing the test code we now get:

	TheByte = pgm_read_byte_far( 0x0858 ); -> 01
	TheByte = pgm_read_byte_far( 0x0859 ); -> 97
	TheByte = pgm_read_byte_far( 0x085A ); -> F1
	TheByte = pgm_read_byte_far( 0x085B ); -> F7
	TheByte = pgm_read_byte_far( 0x085C ); -> 8C
	TheByte = pgm_read_byte_far( 0x085D ); -> 01
	TheByte = pgm_read_byte_far( 0x085E ); -> 98 **
	TheByte = pgm_read_byte_far( 0x085F ); -> 95 **
	TheByte = pgm_read_byte_far( 0x0860 ); -> 98 **
	TheByte = pgm_read_byte_far( 0x0861 ); -> 95 **
	TheByte = pgm_read_byte_far( 0x0862 ); -> CB
	TheByte = pgm_read_byte_far( 0x0863 ); -> 69
	TheByte = pgm_read_byte_far( 0x0864 ); -> 63
	TheByte = pgm_read_byte_far( 0x0865 ); -> E0

So the bytes read in error also moved by 4 bytes !!!!

 

BTW: the location we are reading bytes from is located (shown by the map file) in a function called "Restart_ProcessRestart" which is a naked function that does startup processing for the app.

__attribute__ ((no_instrument_function)) void Restart_ProcessRestart(void) \
__attribute__((naked)) \
__attribute__((section(".init3")));
void Restart_ProcessRestart(void)

It starts at 0x6A6.  At location 0x850 is an rjmp and a call:

 850:	dc 01       	movw	r26, r24
     852:	cb 01       	movw	r24, r22
     854:	8c 01       	movw	r16, r24
     856:	c8 01       	movw	r24, r16
     858:	01 97       	sbiw	r24, 0x01	; 1
     85a:	f1 f7       	brne	.-4      	; 0x858 <Restart_ProcessRestart+0x1b2>
     85c:	8c 01       	movw	r16, r24
     85e:	63 cf       	rjmp	.-314    	; 0x726 <Restart_ProcessRestart+0x80>
     860:	0e 94 cb 69 	call	0xd396	; 0xd396 <Restart_RestartInfo_init>
     864:	63 e0       	ldi	r22, 0x03	; 3
     866:	8c e1       	ldi	r24, 0x1C	; 28
     868:	9d e0       	ldi	r25, 0x0D	; 13
     86a:	0e 94 e4 83 	call	0x107c8	; 0x107c8 <Checksum>
    

Color me more confused than ever ...

 

Any insight would be of great help ... it has to be something obvious that I don't see.

 

This is in preparation for code that does a CRC check of flash ... has anyone gotten that to work on an ATMega1284P?

 

Regards,

 

Chuck

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

sparrow2 wrote:

You write :

The load from 0x0859 loaded the correct value, the others did not.

How do you know that ?

 

As shown by AS7 in the Memory1 window.

 

sparrow2 wrote:
and how do you know to start at 0x0859 ?

 

The flash CRC check was failing.  I located this spot as the problem by doing a 'binary search' in debug (run 0 to loc 5000, bad, ok, run to loc 2500, good, ok, must be between 2500 and 5000, run to 2750 ... yada, yada ..)

 

sparrow2 wrote:
Remember that flash is 16 bit so addr of code in flash is NOT the same as data from flash!

 

??? ATMega1284P has 128k flash so addr is > 16 bit, hence the RAMPZ and ELPM usage rather than LPM ...

 

Chuck

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

sparrow2 wrote:

Remember that flash is 16 bit so addr of code in flash is NOT the same as data from flash!

 

It is half though right?  A word address is half of the byte address?  0x7000 by bytes = 0x3800 by words

 

sparrow2 wrote:

I have never understood why LPM don't load 16 bit from flash ( then 128K flash (64kx16) could fit a 16 bit pointer)  

 

I agree if it is handled in 16 bits words, why not return a 16 bit word with proper addressing.

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

alank2 wrote:
what if you read the flash back using AS7?

 

Never tried that.  I'll have to look up how ...

 

Chuck ( ... off to church ...)

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

ChuckH wrote:

This is in preparation for code that does a CRC check of flash ... has anyone gotten that to work on an ATMega1284P?

 

I tested it on a ATMega1284P and it does not fail on mine.  I padded it to 93K.

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

ChuckH wrote:

Never tried that.  I'll have to look up how ...

 

Programming dialog, just read instead of write...

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

Memory as read back by AS7 is correct !

 

Chuck (running out the door ...)

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

??? ATMega1284P has 128k flash so addr is > 16 bit, hence the RAMPZ and ELPM usage rather than LPM ...

 

 

In Flash you normally have code! on a AVR the code is 16 bit, that is why PC on a 128(4) still only is 16 bit.

Now there is a problem with LPM it only read a byte , so you can't get all 128k byte with a 16 bit pointer that is why you need ELPM. But an instruction in flash addr. 0x1000 will with LPM be placed at 0x2000 (and 0x2001), because it's a byte (pointer). 

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

Regarding the "cli" instructions, I could not duplicate that behavior (w/ avr-gcc 5.4.0), but my guess it is related to the declaration of TheByte as volatile.

If you are curious remove that.  (I don't think it's needed in the context you show.)

 

Are you sure you don't have an interrupt handler mucking with registers?  Can you run with cli() at the beginning?

 

EDIT:   I may be wrong about "cli" instructions.  It is a standard epilog for function calls.  See line starting "in ..." below, from the gcc sources.

 

;; move word (16 bit)

;; Move register $1 to the Stack Pointer register SP.
;; This insn is emit during function prologue/epilogue generation.
;;    $2 =  0: We know that IRQs are off
;;    $2 =  1: We know that IRQs are on
;;    $2 =  2: SP has 8 bits only, IRQ state does not matter
;;    $2 = -1: We don't know anything about IRQ on/off
;; Always write SP via unspec, see PR50063
(define_insn "movhi_sp_r"
  [(set (match_operand:HI 0 "stack_register_operand"                "=q,q,q,q,q")
        (unspec_volatile:HI [(match_operand:HI 1 "register_operand"  "r,r,r,r,r")
                             (match_operand:HI 2 "const_int_operand" "L,P,N,K,LPN")]
                            UNSPECV_WRITE_SP))]
  ""
  "@
        out %B0,%B1\;out %A0,%A1
        cli\;out %B0,%B1\;sei\;out %A0,%A1
        in __tmp_reg__,__SREG__\;cli\;out %B0,%B1\;out __SREG__,__tmp_reg__\;out %A0,%A1
        out %A0,%A1
        out %A0,%A1\;out %B0,%B1"
  [(set_attr "length" "2,4,5,1,2")
   (set_attr "isa" "no_xmega,no_xmega,no_xmega,*,xmega")
   (set_attr "cc" "none")])

 

Last Edited: Sun. Mar 31, 2019 - 03:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


While at church it occured to me to try the access with LPM since (at the moment) the location being accessed is in lower flash memory.

 

Given:

 

 

	TheByte = pgm_read_byte_far( 0x085E );
    6b5e:	8e e5       	ldi	r24, 0x5E	; 94
    6b60:	98 e0       	ldi	r25, 0x08	; 8
    6b62:	a0 e0       	ldi	r26, 0x00	; 0
    6b64:	b0 e0       	ldi	r27, 0x00	; 0
    6b66:	ab bf       	out	0x3b, r26	; 59
    6b68:	fc 01       	movw	r30, r24
    6b6a:	87 91       	elpm	r24, Z+
    6b6c:	89 83       	std	Y+1, r24	; 0x01
	TheByte = pgm_read_byte_near( 0x085E );
    6b6e:	ee e5       	ldi	r30, 0x5E	; 94
    6b70:	f8 e0       	ldi	r31, 0x08	; 8
    6b72:	e4 91       	lpm	r30, Z
    6b74:	e9 83       	std	Y+1, r30	; 0x01

The ELPM and LPM above both load the same (incorrect) value of 0x98 should be 0x63.

 

So, I guess we can rule out an issue with (the more complex) ELPM instruction as the issue exists with LPM ... sigh

 

Chuck

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

Set your "prog" memory window to 42C instead of 858. What do you see there?

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

MattRW wrote:
Are you sure you don't have an interrupt handler mucking with registers?  Can you run with cli() at the beginning?

 

This is right at the beginning of the application.  No interrupt handlers have been enabled (WDT even disabled).  Brownout is enabled, etc. but no restarts are happening. 

 

The locations not being returned incorrectly are in the middle of the function that does .init3 processing.

 

The 'test' function attempting to read the entire flash (this function is located above the problem locations) is being invoked from a function that was invoked by this (naked) .init3 function (in lower flash space).

 

The LPMs fail on 4 successive bytes that are (happen to be??) located within that .init3 function.

 

Through the entire sequence the SREG is 0x22 (i.e.: the I bit is cleared, so no interrupts).

 

I even thought it might be noise, power level, etc. causing the MCU to malfunction but several things eliminated this:

  • Same thing happened on another card (same design, so could be same error cause)
  • It is very predictable (ok, same MCU execution, same noise ...)
  • The address of the effected locations shifted when code was added at an address lower than them in flash 

 

The last one is the one that really has me scratching my head.

 

I know it's due to something stupid on my part (VERY rarely the compiler and rarer still the processor) ... so, please ... tell me what it is and feel free to call me stupid ... PLEASE ! frown

 

Chuck

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


clawson wrote:
Set your "prog" memory window to 42C instead of 858. What do you see there?

 

 

Yup, thought of that too ... this is in the middle of "PROGMEM" strings.

 

BTW: I have TeamViewer screen sharing installed if someone wants to see it 'live' and feel my pain :-)

 

Chuck

 

 

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

What might be interesting is to have it dump every byte to a USART in hex so you can compare every byte against what should be there.  That would tells where it is failing and where it is right on and perhaps that might yield an idea as to why based on where, how long, one failure section, multiple failure sections, etc.

 

I usually add a hex dump function to things:

const char PROGMEM HEX[]="0123456789ABCDEF";

void sendbyte(uint8_t AByte)
  {
    while (!(UCSR0A & _BV(UDRE0)))
      ;
    UDR0=AByte;
  }

void sendstring(char *AString)
  {
    while (*AString)
      {
        sendbyte(*AString);
        AString++;
      }
  }

void sendhexbyte(uint8_t AByte)
  {
    sendbyte(pgm_read_byte(HEX+(AByte>>4)));
    sendbyte(pgm_read_byte(HEX+(AByte&15)));
    //sendbyte(' ');
  }

You can then write a quick tool to convert it from hex2 byte (I can post one if you need one).

 

Then use srec_cat to make a binary file of the hex to compare to (or add this as a post build instruction):

 

srec_cat "$(MSBuildProjectDirectory)\$(Configuration)\$(OutputFileName).hex" -intel -o "$(MSBuildProjectDirectory)\$(Configuration)\$(OutputFileName).bin" -binary

 

 

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

 

While at church it occured to me to try the access with LPM

WHAATT?? You weren't paying attention to the sermon? devil

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

More questions about __flash and __memx - When I use a __memx pointer, it does use elpm:

 

00012b06 <__xload_1>:
   12b06:    57 fd           sbrc    r21, 7
   12b08:    03 c0           rjmp    .+6          ; 0x12b10 <__xload_1+0xa>
   12b0a:    5b bf           out    0x3b, r21    ; 59
   12b0c:    67 91           elpm    r22, Z+
   12b0e:    08 95           ret
   12b10:    60 81           ld    r22, Z
   12b12:    08 95           ret

 

But if I use a __flash pointer, it just uses LPM:

 

    c1=*APointer;
   11e44:    01 96           adiw    r24, 0x01    ; 1
   11e46:    fc 01           movw    r30, r24
   11e48:    84 91           lpm    r24, Z

 

In my test code:

 

const uint8_t __flash mytest[]={ 0xaa, 0xab, 0xac, 0xad };

 

void myfunc(const uint8_t __memx *APointer)

{

code

}

 

main

{

    myfunc(mytest);    //what happens here?  Does it make a __memx pointer out of mytest?  How does it know how to do this?  If I had put a sram structure in here, would it know to make a proper __memx pointer with the bit set for sram?

}

 

If I try to make a pointer with __memx the compiler demands it is const:

 

const uint8_t __memx *ptr1;

 

Why does it do this if it can also point to SRAM?  Can you only read from __memx pointers, even if it points to SRAM?

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


Ok,

 

My app already had code in it that supported IO to a USART used for diagnostic logging so I wrote a function that used pgm_read_byte_far to read all of flash from 0 to __data_load_end.

 

I generated Intel Hex format which was sent to the USART.  I used a terminal program to save the stream to a file which I then compared to the original hex file produced by GCC using "Beyond Compare".  The differences are shown below:

 

There were seven differences covering a wide area and not in a regular pattern (as shown by the red 'difference' marks in the far left column)

 

Of these differences, the first six were all 2-byte runs where the 'new' data (i.e.: the data from memory as read by ELPM) was equal to 0x98 and 0x95.  This seems like too much of a coincidence.

 

Rest assured, I do not have any SPMs in this application. 

 

I dumped the memory several times (debug restart, not AS7 reload) to see if it was consistent, and it was - every dump was identical.

 

I re-loaded the processor with AS7 and dumped it again.  It resulted in an identical dump to the previous ones.

 

It occured to me that, since these boards have been re-flashed many times during development, maybe I 'wore out' the flash.  I then used AS7 to verify the flash memory via the JTAG.  It verified correctly.

 

This application has been running for 1,000s of hours on almost 100 identical boards.  If there were this many memory 'glitches' I think I would have seen applications 'bouncing off the walls' executing garbage instructions from time-to-time as they executed the 'bad' locations.

 

So, the only conclusion I can come to is that the ELPM is loading incorrect data ... I said it, but I still find it hard to believe myself.

 

Late tomorrow I will try shifting code to see if the 6 differences move as they did with my simple line-at-a-time reading of flash.  Then I will try a couple of other boards to see if they show identical or different 'bad spot' patterns.

 

I am very frustrated because I am trying to implement bootloading over the CAN bus but I can't do this until I can CRC the application area so that my bootloader can tell if there is a valid application loaded (i.e.: the CRC verifies correctly).

 

Other than that, I'm at a total loss what to try next ...

 

Hopefully someone has a way to lead me out of this swamp ...

 

Chuck ( ... a very frustrated AVR user ...)

 

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

alank2 wrote:
More questions about __flash and __memx - When I use a __memx pointer, it does use elpm:

 

Can we take the discussion of __flash to a new thread, I'd like to keep this one true-to-subject in case I pass it to others ( ... Microchip perhaps )

 

Thanks,

 

Chuck

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

Sorry about that Chuck; I thought it was the other one!

 

Awesome to see you using Beyond Compare!  Seeing those 6 "notches" in the left side is sure odd.

 

You did say you tried this with different hardware?

 

Very odd!

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

Alan, just to say I made a post about __flash/__memx to continue the discussion there in your thread: https://www.avrfreaks.net/forum/...

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

Thanks clawson; lots of good info in that post.  I appreciate it!

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

Any further update Chuck?

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

alank2 wrote:

Any further update Chuck?

 

Still cannot CRC all of flash correctly.  I have code reading flash and writing it to disk (via USART & Terminal capture program).  I can then compare it to the original hex file.

 

I am trying to narrow down when it happens and it's pattern (what the mismatches are and where they are).

 

I have confirmed that a small test program can read all 128k of the ATMega1284p ... at least when it is all 0xFF (erased) past the little app itself.

 

I am setting up a series of well-documented tests to try to gain as much insight as possible.

 

Chuck

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

An idea Chuck might be to add a __flash structure and fill it with dummy data.

 

This is what I did to increase the size of the flash manually, but you can remove the 32767 and put iin actual data {0x00, 0x00, 0x00}.  You can try to get it to fail where it doesn't match, then try to change the byte that doesn't match since you have control over it in the memory structure.  What happens then?

uint8_t PROGMEM const Waste1[32767] = {0};
uint8_t PROGMEM const Waste2[32767] = {0};

//debug
volatile uint8_t *dummy1;
volatile uint8_t *dummy2;

int main()
  {
    //debug
    dummy1=Waste1;
    dummy2=Waste2;
  }

 

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

A thought I had, but is probably not the reason

since the discrepancies are spread around, but

thought I'd mention it anyway, is perhaps the

bad data is located at the currently executing

code in the flash.  Maybe the hardware can't

simultaneously read the code with E/LPM and

also execute the same code?

 

--Mike

 

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

I don't think that can be it Mike because I've been doing a self test for years without failure where the code executing is definitely part of the code being read...

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Come on gents, instruction 0x9598 is BREAK !!!!

 

When you use the On-Chip debug system, a BREAK is inserted by the debug software to make the CPU enter STOP MODE, so the On-Chip debugger can access the internal resources.

 

So, there are two BREAKS where you expect to find  0x63 0xCF 0x03 0x94.

So, when you quit the debug, the original data is rewriting at those address, then your flash dump shows the right bytes.

 

This is a very common situation, since there is no other way for the debugger to stop the CPU, it *NEEDS* to replace the original bytes at the breakpoint address and insert a BREAK.

 

Disable all debugs, remove Jtags and such, write a small piece of code just do read those 32 bytes from 0x0850 to 0x086F and dump it to LEDS on some port in low speed, so you can write it down and verify... don't need to dump to serial or something like that.  Do it by the hard way.

 

Pretty sure this is the problem, nothing to do with flash failure.

Wagner Lipnharski
Orlando Florida USA

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

wagnerlip wrote:

Come on gents, instruction 0x9598 is BREAK !!!!

 

Nice one!

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

wagnerlip wrote:

Come on gents, instruction 0x9598 is BREAK !!!!

I'm secretly hoping this opcode was chosen to

poke at Microsoft Windows.

 

--Mike

 

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

wagnerlip wrote:

Come on gents, instruction 0x9598 is BREAK !!!!

 

When you use the On-Chip debug system, a BREAK is inserted by the debug software to make the CPU enter STOP MODE, so the On-Chip debugger can access the internal resources.

 

So, there are two BREAKS where you expect to find  0x63 0xCF 0x03 0x94.

So, when you quit the debug, the original data is rewriting at those address, then your flash dump shows the right bytes.

 

This is a very common situation, since there is no other way for the debugger to stop the CPU, it *NEEDS* to replace the original bytes at the breakpoint address and insert a BREAK.

 

Disable all debugs, remove Jtags and such, write a small piece of code just do read those 32 bytes from 0x0850 to 0x086F and dump it to LEDS on some port in low speed, so you can write it down and verify... don't need to dump to serial or something like that.  Do it by the hard way.

 

Pretty sure this is the problem, nothing to do with flash failure.

 

Better start reading the user's guide, page 19.

http://ww1.microchip.com/downloa...

 

It is possible to set several software breakpoints all over the code, the debugger just replace the original instructions on those address with BREAK instruction.

They can be thousands all over the code, even if you don't use them.

 

If you reflash the chip, it will have the original instructions, but as soon you restart the debugger (in this case I think is just the AVR Studio) it will check the software breakpoints table and rewrite them to the chip flash memory.  Note that just installing a single breakpoint makes the debugger to rewrite the whole flash page, and worse, it doesn't check it the writing was successful.

 

I personally don't like this kind of intrusion debugger, the reason is painted all over your post, the debugger is inserting software breakpoints even after you forgot about them, IF, they were created by you, they could be result of a simple mistake or unknown glitch or bug.

 

There are the hardware breakpoints, that does not rewrite the flash (I think), they are faster and don't contaminate the life expand of the memory, but they are limited in quantity.

Can you imagine the havoc you cause, when you use a software breakpoint and then do numerous single-cycle through code?  Even step is a new page erase/write.

 

Fix it, I know you can.

By the way, ChuckH, look at your window northeast direction, you will see me waving from Orlando... cheers.

 

 

 

Wagner Lipnharski
Orlando Florida USA

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

Most of the JTAG CPUs (unlike debugwire) have four address comparators to support 4 h/w breakpoints so it's only if you set 5 or more breakpoints it reverts to doing what debugwire CPUs always have to do and insert BREAKs into the flash (which wears it out). This is just one of the many reasons JTAG is preferable to debugwire (1284 being 40 pin is JTAG).

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

What about using start without debugging?  Does that still insert the breakpoints?  Does one have to clear all breakpoints somehow to make sure none are inserted?

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

They are removed when you stop so a non debug run should find the "normal" code there.

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

avr-mike wrote:

I'm secretly hoping this opcode was chosen to

poke at Microsoft Windows.

 

So the AVR inventors/designers had some kind of time machine?  Or were prescient?

 

I'd think that by now the two main participants in this thread could have calculated that CRC with calculator or pencil and paper.  I'm curious to the resolution on reading flash properly, so that the menu systems in my apps will work (show the desired text strings).

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Sun. Apr 7, 2019 - 11:50 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am hoping ChuckH will be back soon with an update.

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

wagnerlip wrote:

Come on gents, instruction 0x9598 is BREAK !!!!

 

When you use the On-Chip debug system, a BREAK is inserted by the debug software to make the CPU enter STOP MODE, so the On-Chip debugger can access the internal resources.

 

OMG!!! 

 

Wagner - I wish I had read your post 3 days ago!  (for some reason I stopped getting notified of replies).

 

I had done several more tests and was documenting every step of the way ... the last thing I was documenting just now was:

 

The only other activity I can think of that is active is the JTAG interface (I am running under debug).  As a test I deleted all breakpoints except one at the end of the dump function – and all but one of the 0x9598’s were gone!!!!!!!

 

So I did finally find it myself but boy was it a painful journey!

 

I had assumed (there's that word again ..) that breakpoints were supported in the debug interface of the processor hardware and that it was doing an associative address compare to break ... not replacing the instruction!  (I now know that there are two types of breakpoint).

 

I come to Orlando every so often to visit Skycraft Surplus.

 

Would love to meet you over lunch or a beer sometime.

 

Now off to complete the flash CRC stuff and finish the development of my "Bootload-over-CAN" facility that started all this!

 

Regards,

 

Chuck Hackett

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

wagnerlip wrote:

Better start reading the user's guide, page 19.

http://ww1.microchip.com/downloa...

 

... and I'm off to do some (re)reading!!!

 

Chuck

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


ChuckH wrote:

I come to Orlando every so often to visit Skycraft Surplus.

Would love to meet you over lunch or a beer sometime.

 

I was a frequent flyer to Skycraft planet in the 90's.  Very good stuff there. 

I love the smell of old capacitors, wires, motors, transformers and greased bearings at mornings.

No other place you can find military super-high-tech surplus circuit boards and really strange high-quality-precision mechanics.

For the ones that don't know Skycraft store, they have missiles, bombs and torpedos hang on the ceiling, decommissioned, but real ones.

What I miss in there, is a snack and bar counter, customers could stay all day long roaming the long corridors while enjoying a good rocket-fired-steak sandwich and beer.

 

 

 

Wagner Lipnharski
Orlando Florida USA