New in writing/reading flash at runtime-need help in debugging in AS 6.2/Simulator

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

Greetings to all colleagues here!

I am currently developing an application in C using ATmega328P and Atmel Studio 6.2 with STK500 (ISP).

In this application, I have a 2D array stored in SRAM that I want to copy in flash memory. EEPROM won't do since the array size is larger than 1024 bytes- actually, it is 1500 bytes. This is the very first time that I am trying my hand on this topic.

I am using code taken from this link that, in fact, uses the functions in boot.h. I have followed the instruction that are presented there.

All I want to do as a starting point is the following:

Have some variable in SRAM copied to flash via a properly sized page buffer, then clear the buffer, then load data from flash into the buffer and check that everything is as they should be.

 

Here are excerpts from my code:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>	// include this header to put look-up table in program (flash) memory

//...

// The following are taken from:
// https://botagar.wordpress.com/2014/11/15/atmega-reading-and-writing-to-flash-memory-during-runtime/
//Declare a buffer in RAM the size of a single page of flash memory
uint8_t flash_page_buffer[SPM_PAGESIZE];
//To keep track of how full the buffer is
uint8_t flash_buffer_index = 0;
//Flag which indicates if the flash page buffer is full
volatile bool flash_page_buffer_full = false;   // I have that volatile to be able to check in debugger
// Current page of flash memory
uint8_t page = 0;

// TEST ONLY
const uint8_t msg0[] = {'T','E','S','T','\0'};

int main(void)
{
    // ...

	// Write data to flash memory
	// Page buffer is filled with the contents of msg0, then 0x00 follow up to element SPM_PAGESIZE-1
	uint8_t i = 0;

	while (flash_page_buffer_full == false)
	{
		do
		{
			flash_page_buffer[flash_buffer_index++] = msg0[i++];
		}
		while (i < sizeof(msg0));

		flash_buffer_index++;
		if (flash_buffer_index >= (SPM_PAGESIZE - 1))	// if flash_page_buffer is full
		{
			flash_page_buffer_full = true;
			flash_buffer_index = 0;	// reset counter
			flash_write_page(page, flash_page_buffer);	// write buffer contents to flash memory
			page++;
		}
	}

	i = 0;
	while(i < sizeof(flash_page_buffer))
		flash_page_buffer[i++] = 0;

    // ... more code follows
}

My project settings are as follows:

Project settings -> All configurations -> Toolchain -> AVR/GNU linker -> Memory settings:
    FLASH segment: .bootloader=0x3C00 (that becomes 0x7800 in makefile, I have checked that)

Project settings -> Active (Debug) -> AVR/GNU C Compiler -> Optimization Level: -O3

Moreover, I have my fuses programmed as follows:

BODLEVEL: Disabled (it is set to 2V7 in the real device)
RSTDISBL: Unchecked
DWEN: Unchecked
SPIEN: Checked
WDTON: Unchecked
EESAVE: Unchecked
BOOTSZ: 2048W_3800
BOOTRST: Unchecked
CKDIV8: Unchecked
CKOUT: Unchecked
SUT_CKSEL: INTRCOSC_8MHZ_6CK_14CK_65MS

(At the time of writing, I realized that I had set BOOTSZ1=0, BOOTSZ=1 (1024W_3C00) instead of BOOTSZ1=1, BOOTSZ=1 (2048W_3800) that I am apparently using at the moment. Is that a bug or is there something I am missing?)

 

However, all I can see using the simulator is that the buffer is filled up with the correct values (array msg0 first, then all 0x00 up to SPM_PAGESIZE-1). After that, I cannot find where my buffer is written to in flash. I am really confused.

 

EDIT: I changed my code so that is easier to check in debugger; instead of copying string "TEST" into flash_page_buffer, I copy numerical values from 0x00 to 0x7F. No difference whatsoever.

I only confirmed that flash_read_page(0, flash_page_buffer) reads from address 0x0000 of flash; contents of flash_page_buffer after executing that are identical to the first 128 bytes of flash, starting from 0x0000. What am I missing here?

 

Any ideas, hints, anyone? Thank you in advance for your precious help.

 

This topic has a solution.
Last Edited: Sun. May 21, 2017 - 09:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You omitted a few important things, like showing us the source code of flash_write_page and telling us what you have done to locate parts of the code in the .bootloader section (.bootloader=0x3C00 in the project settings is not enough).

 

But first of all: why do you try to move the data from RAM to Flash at runtime at all? Is it really runtime generated data not known at compile time?

Stefan Ernst

Last Edited: Fri. May 19, 2017 - 12:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for your reply.

 

Source code for flash_write_page():

void flash_write_page(uint8_t page, uint8_t *buf)
{
	uint32_t addr = (page*SPM_PAGESIZE);
	boot_program_page(addr,buf);
}

(you can check it out in the link I provided above)

which, in turn, calls boot_program_page() that is copied from avr-libc website:

void boot_program_page (uint32_t page, uint8_t *buf)
{
    //This is copy paste from the boot.h GNU website
    uint16_t i;
    uint8_t sreg;
 
    sreg = SREG;
     
    cli(); // Disable interrupts.
     
    eeprom_busy_wait ();
     
    boot_page_erase (page);
    boot_spm_busy_wait ();      // Wait until the memory is erased.
 
    for (i=0; i<SPM_PAGESIZE; i+=2)
    {
        // Set up little-endian word.
        uint16_t w = *buf++;
        w += (*buf++) << 8;
         
        boot_page_fill (page + i, w);
    }
     
    boot_page_write (page);     // Store buffer in flash page.
    boot_spm_busy_wait();       // Wait until the memory is written.
     
    // Re-enable RWW-section again.
    boot_rww_enable ();
 
    // Re-enable interrupts
    sei();
 
    SREG = sreg;
}

Declaration of boot_program_page():

void boot_program_page (uint32_t page, uint8_t *buf) \
__attribute__ ((section (".bootloader")));

 

It turns out that I have done nothing more than .bootloader=0x3C00 in Project Settings. What else should I do to have boot_program_page() relocated in bootloader segment? I am still lacking good command of all related issues...

All I get when looking at prog BOOT_SECTION_3 (starting at byte address 0x7800) is 0xFF, which means that nothing is present in there.

 

The reason for all that fuss is that the data I want to move from SRAM to flash are some kind of calibration data that are known only in runtime. First they are acquired and stored in SRAM, and when everything is ready, they are stored in flash memory and recalled from there afterwards.

 

 

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

gmetaxas wrote:
It turns out that I have done nothing more than .bootloader=0x3C00 in Project Settings. What else should I do to have boot_program_page() relocated in bootloader segment?
I was after the __attribute__ line. You haven't shown it in the first post.

 

gmetaxas wrote:
All I get when looking at prog BOOT_SECTION_3 (starting at byte address 0x7800) is 0xFF, which means that nothing is present in there.
Was the relocation successful?

Have a look at the LSS file to confirm it.

Was the .bootloader section exported to the HEX file?

Have a look at the HEX file to confirm it.

Stefan Ernst

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

Well, the .HEX file does not seem to have the bootloader segment; I cannot trace the data or the bootloader starting address either. There is no sign of 0x7800 anywhere.

As far as the .LSS file, I think the relocation was not successful:

0000027c <flash_write_page>:
	
	SREG = sreg;
}

void flash_write_page(uint8_t page, uint8_t *buf)
{
 27c:	a2 e0       	ldi	r26, 0x02	; 2

...

i.e. there is no sign of ".bootloader" or of 0x7800 either.

As I mentioned earlier, I have no previous experience of all this, so please bear with me... and correct me where I'm doing wrong.

 

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

gmetaxas wrote:
As far as the .LSS file, I think the relocation was not successful:

0000027c <flash_write_page>:
	
	SREG = sreg;
}

void flash_write_page(uint8_t page, uint8_t *buf)
{
 27c:	a2 e0       	ldi	r26, 0x02	; 2

...

But the relocated function is boot_program_page, not flash_write_page.

Stefan Ernst

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

sternst wrote:

But the relocated function is boot_program_page, not flash_write_page.

That' s my point: indeed, boot_program_page is present in the .lss file only at the following point:

 

0000027c <flash_write_page>:
	
	SREG = sreg;
}

void flash_write_page(uint8_t page, uint8_t *buf)
{
 27c:	a2 e0       	ldi	r26, 0x02	; 2
 27e:	b0 e0       	ldi	r27, 0x00	; 0
 280:	e4 e4       	ldi	r30, 0x44	; 68
 282:	f1 e0       	ldi	r31, 0x01	; 1
 284:	0c 94 5f 02 	jmp	0x4be	; 0x4be <__prologue_saves__+0x18>
	uint32_t addr = (page*SPM_PAGESIZE);
 288:	90 e8       	ldi	r25, 0x80	; 128
 28a:	89 9f       	mul	r24, r25
 28c:	80 01       	movw	r16, r0
 28e:	11 24       	eor	r1, r1
{
	//This is copy paste from the boot.h GNU website
	uint16_t i;
	uint8_t sreg;
	
	sreg = SREG;
 290:	ef b6       	in	r14, 0x3f	; 63
	
	cli(); // Disable interrupts.
 292:	f8 94       	cli
	
	eeprom_busy_wait ();
 294:	f9 99       	sbic	0x1f, 1	; 31
 296:	fe cf       	rjmp	.-4      	; 0x294 <flash_write_page+0x18>
	
	boot_page_erase (page);
 298:	83 e0       	ldi	r24, 0x03	; 3
 29a:	f8 01       	movw	r30, r16
 29c:	80 93 57 00 	sts	0x0057, r24
 2a0:	e8 95       	spm
	boot_spm_busy_wait ();      // Wait until the memory is erased.
 2a2:	07 b6       	in	r0, 0x37	; 55
 2a4:	00 fc       	sbrc	r0, 0
 2a6:	fd cf       	rjmp	.-6      	; 0x2a2 <flash_write_page+0x26>
 2a8:	cb 01       	movw	r24, r22
 2aa:	80 58       	subi	r24, 0x80	; 128
 2ac:	9f 4f       	sbci	r25, 0xFF	; 255
 2ae:	db 01       	movw	r26, r22
 2b0:	b8 01       	movw	r22, r16
 2b2:	6a 1b       	sub	r22, r26
 2b4:	7b 0b       	sbc	r23, r27
	{
		// Set up little-endian word.
		volatile uint16_t w = *buf++;
		w += (*buf++) << 8;
		
		boot_page_fill (page + i, w);
 2b6:	ff 24       	eor	r15, r15
 2b8:	f3 94       	inc	r15
	boot_spm_busy_wait ();      // Wait until the memory is erased.
	
	for (i=0; i<SPM_PAGESIZE; i+=2)
	{
		// Set up little-endian word.
		volatile uint16_t w = *buf++;
 2ba:	2c 91       	ld	r18, X
 2bc:	30 e0       	ldi	r19, 0x00	; 0
 2be:	3a 83       	std	Y+2, r19	; 0x02
 2c0:	29 83       	std	Y+1, r18	; 0x01
		w += (*buf++) << 8;
 2c2:	49 81       	ldd	r20, Y+1	; 0x01
 2c4:	5a 81       	ldd	r21, Y+2	; 0x02
 2c6:	11 96       	adiw	r26, 0x01	; 1
 2c8:	2c 91       	ld	r18, X
 2ca:	11 97       	sbiw	r26, 0x01	; 1
 2cc:	30 e0       	ldi	r19, 0x00	; 0
 2ce:	32 2f       	mov	r19, r18
 2d0:	22 27       	eor	r18, r18
 2d2:	24 0f       	add	r18, r20
 2d4:	35 1f       	adc	r19, r21
 2d6:	3a 83       	std	Y+2, r19	; 0x02
 2d8:	29 83       	std	Y+1, r18	; 0x01
		
		boot_page_fill (page + i, w);
 2da:	29 81       	ldd	r18, Y+1	; 0x01
 2dc:	3a 81       	ldd	r19, Y+2	; 0x02
 2de:	fb 01       	movw	r30, r22
 2e0:	ea 0f       	add	r30, r26
 2e2:	fb 1f       	adc	r31, r27
 2e4:	09 01       	movw	r0, r18
 2e6:	f0 92 57 00 	sts	0x0057, r15
 2ea:	e8 95       	spm
 2ec:	11 24       	eor	r1, r1
 2ee:	12 96       	adiw	r26, 0x02	; 2
	eeprom_busy_wait ();
	
	boot_page_erase (page);
	boot_spm_busy_wait ();      // Wait until the memory is erased.
	
	for (i=0; i<SPM_PAGESIZE; i+=2)
 2f0:	a8 17       	cp	r26, r24
 2f2:	b9 07       	cpc	r27, r25
 2f4:	11 f7       	brne	.-60     	; 0x2ba <flash_write_page+0x3e>
		w += (*buf++) << 8;
		
		boot_page_fill (page + i, w);
	}
	
	boot_page_write (page);     // Store buffer in flash page.
 2f6:	85 e0       	ldi	r24, 0x05	; 5
 2f8:	f8 01       	movw	r30, r16
 2fa:	80 93 57 00 	sts	0x0057, r24
 2fe:	e8 95       	spm
	boot_spm_busy_wait();       // Wait until the memory is written.
 300:	07 b6       	in	r0, 0x37	; 55
 302:	00 fc       	sbrc	r0, 0
 304:	fd cf       	rjmp	.-6      	; 0x300 <flash_write_page+0x84>
	
	// Re-enable RWW-section again.
	boot_rww_enable ();
 306:	81 e1       	ldi	r24, 0x11	; 17
 308:	80 93 57 00 	sts	0x0057, r24
 30c:	e8 95       	spm
	
	// Re-enable interrupts
	sei();
 30e:	78 94       	sei
	
	SREG = sreg;
 310:	ef be       	out	0x3f, r14	; 63

void flash_write_page(uint8_t page, uint8_t *buf)
{
	uint32_t addr = (page*SPM_PAGESIZE);
	boot_program_page(addr,buf);
}
 312:	22 96       	adiw	r28, 0x02	; 2
 314:	e6 e0       	ldi	r30, 0x06	; 6
 316:	0c 94 7b 02 	jmp	0x4f6	; 0x4f6 <__epilogue_restores__+0x18>

 

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

The function got inlined.

 

gmetaxas wrote:
Declaration of boot_program_page():

void boot_program_page (uint32_t page, uint8_t *buf) \
__attribute__ ((section (".bootloader")));

You do have that declaration in the same source file as the definition (the actual function) and in front of it, don't you?

Though I don't know whether the compiler is free to inline despite the section attribute, so to be on the safe side change it into __attribute__ ((section(".bootloader"),noinline))

Stefan Ernst

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

Stefan, you were right: there was no trace of ".bootloader" in .lss or .map files. Although the declaration and the definition of boot_program_page() is in separate files (.h and .c, respectively), most probably it got inlined.

Following your suggestion, by explicitly stating that function as not to be inlined, the code worked as expected. First of all, by looking at BOOT_SECTION_3 of program memory, there were some data present; before altering the __attribute__ as stated, all that were present there were 0xff. Second, by stepping over the code, I managed to write and read 128 bytes to and from flash memory, starting at address 0x0000 (page 0).

Thanks a lot for your suggestion that led to working code.

Two more questions:

1. Obviously, writing data to flash page 0 is a really bad idea, since it leads to corruption of the application code. Instead, I should subtract 1500=0x05DC from 2*0x3BFF=0x77FE (1500 bytes before the end of application section that is at 0x77FE) and start writing data from memory address 0x7222 or, better still, from page 13 (since 14*2048=28672=0x7000 < 0x7222) . Are the above correct? (Remember that my target is ATmega328P.)

2. Why on earth did that function get inlined? Is it due to the optimization applied by the avr-gcc compiler? I am asking this because I did not see anything about inlining in many, many threads and posts in this forum that dealt with the same subject: writing and reading flash at run-time.

 

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

Why not simply reserve a __flash array in the C then use that as the address to write to? The only issue you will be to assure SPM page alignment. For that just over allocate the round up the base address to the first whole SPM page. 

Last Edited: Mon. May 22, 2017 - 10:02 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello Cliff, thanks for your suggestion; however, not every word of it is clear to me. For one, I tried declaring a __flash array:

const uint16_t __flash test[A][B]; // A, B are defined constants

The compiler insisted on declaring that as const in order to allocate it into flash memory. After that, I tried using test[0] as the starting address to write data to that array, but without success; nothing was ever written there:

flash_write_page(test[0], flash_page_buffer);  

where array flash_page_buffer is 128 bytes long (one page size for ATmega328P).

Please correct me where things are not right and explain to me about SPM page alignment, because I am not sure I understand that.

A problem that I have now is the following: I use the following function to store data into a certain page of flash memory:

void StoreLUTToFlash(void)
{
	uint16_t k = 0;
	uint8_t page_offset = 0;

	while(k < 2*A*B)
	{
		memcpy((void*)flash_page_buffer, (const void*)(LUTRAM[0]+(k/2)), SPM_PAGESIZE);
		flash_write_page(FLASH_PAGE_FOR_DATA+page_offset, flash_page_buffer);	// write buffer contents to flash memory - the previous page is erased every 2 successive pages
		//boot_program_page((uint32_t)(FLASH_PAGE_FOR_DATA*SPM_PAGESIZE+k), flash_page_buffer);
		k += SPM_PAGESIZE;
		page_offset+=1;
	}
}

(I have already filled LUTRAM with a certain pattern that I can recognize quickly by looking at the memory window in AS6.2.)

The problem is that, every two successive calls of flash_write_page() (I have taken those functions from here, please refer to that link for details), I get something like below:

Flash memory after the first two steps of StoreLUTToFlash():

prog 0x0680  00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 00 0a 00 0b 00 0c 00 0d 00 0e  .............................
prog 0x069D  00 0f 00 10 00 11 00 12 00 13 00 14 00 15 00 16 00 17 00 18 00 19 00 1a 00 1b 00 1c 00  .............................
prog 0x06BA  1d 00 1e 00 1f 00 20 00 21 00 22 00 23 00 24 00 25 00 26 00 27 00 28 00 29 00 2a 00 2b  ...... .!.".#.$.%.&.'.(.).*.+
prog 0x06D7  00 2c 00 2d 00 2e 00 2f 00 30 00 31 00 32 00 33 00 34 00 35 00 36 00 37 00 38 00 39 00  .,.-.../.0.1.2.3.4.5.6.7.8.9.
prog 0x06F4  3a 00 3b 00 3c 00 3d 00 3e 00 3f 00 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08  :.;.<.=.>.?..................
prog 0x0711  00 09 00 0a 00 0b 00 0c 00 0d 00 0e 00 0f 00 10 00 11 00 12 00 13 00 14 00 15 00 16 00  .............................
prog 0x072E  17 00 18 00 19 00 1a 00 1b 00 1c 00 1d 00 1e 00 1f 00 20 00 21 00 22 00 23 00 24 00 25  .................. .!.".#.$.%
prog 0x074B  00 26 00 27 00 28 00 29 00 2a 00 2b 00 2c 00 2d 00 2e 00 2f 00 30 00 31 00 32 00 33 00  .&.'.(.).*.+.,.-.../.0.1.2.3.
prog 0x0768  34 00 35 00 36 00 37 00 38 00 39 00 3a 00 3b 00 3c 00 3d 00 3e 00 3f 00 ff ff ff ff ff  4.5.6.7.8.9.:.;.<.=.>.?.ÿÿÿÿÿ
...

Flash memory after the third step of StoreLUTToFlash():

prog 0x0680  00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 00 0a 00 0b 00 0c 00 0d 00 0e  .............................
prog 0x069D  00 0f 00 10 00 11 00 12 00 13 00 14 00 15 00 16 00 17 00 18 00 19 00 1a 00 1b 00 1c 00  .............................
prog 0x06BA  1d 00 1e 00 1f 00 20 00 21 00 22 00 23 00 24 00 25 00 26 00 27 00 28 00 29 00 2a 00 2b  ...... .!.".#.$.%.&.'.(.).*.+
prog 0x06D7  00 2c 00 2d 00 2e 00 2f 00 30 00 31 00 32 00 33 00 34 00 35 00 36 00 37 00 38 00 39 00  .,.-.../.0.1.2.3.4.5.6.7.8.9.
prog 0x06F4  3a 00 3b 00 3c 00 3d 00 3e 00 3f 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  :.;.<.=.>.?.ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
prog 0x0711  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
prog 0x072E  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
prog 0x074B  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
prog 0x0768  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 00 01 00 02  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ.....
prog 0x0785  00 03 00 04 00 05 00 06 00 07 00 08 00 09 00 0a 00 0b 00 0c 00 0d 00 0e 00 0f 00 10 00  .............................
prog 0x07A2  11 00 12 00 13 00 14 00 15 00 16 00 17 00 18 00 19 00 1a 00 1b 00 1c 00 1d 00 1e 00 1f  .............................
prog 0x07BF  00 20 00 21 00 22 00 23 00 24 00 25 00 26 00 27 00 28 00 29 00 2a 00 2b 00 2c 00 2d 00  . .!.".#.$.%.&.'.(.).*.+.,.-.
prog 0x07DC  2e 00 2f 00 30 00 31 00 32 00 33 00 34 00 35 00 36 00 37 00 38 00 39 00 3a 00 3b 00 3c  ../.0.1.2.3.4.5.6.7.8.9.:.;.<
prog 0x07F9  00 3d 00 3e 00 3f 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  .=.>.?.ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
...

In other words, it seems that every two successive steps, the page that precedes the one being currently written is erased. I have checked and double-checked addressing and have not found anything apparently wrong. Any ideas?

 

EDIT: Here is the function that erases a page in flash, copied verbatim from boot.h:

#define __boot_page_erase_normal(address)        \
(__extension__({                                 \
    __asm__ __volatile__                         \
    (                                            \
        "sts %0, %1\n\t"                         \
        "spm\n\t"                                \
        :                                        \
        : "i" (_SFR_MEM_ADDR(__SPM_REG)),        \
          "r" ((uint8_t)(__BOOT_PAGE_ERASE)),    \
          "z" ((uint16_t)(address))              \
    );                                           \
}))

I suspect that the culprit must be somewhere there, since data are written in the correct places; the only strange thing is that the preceding page gets erased. Has anything to do with the addresses that I pass, i.e. is there a casting that I am missing or something similar?

 

 

Last Edited: Tue. May 23, 2017 - 06:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why make that 2D? Just pass &test[0] (or just "test") as the address (but you still need to round that up to the next SPM boundary)

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

Cliff, I will try out your suggestion at a later step; but for the moment, debugging revealed the following:

I made a lightweight application for ATmega328P having only flash memory functionality - no ISRs, no communications, nothing but an array in SRAM, another array that serves as the page buffer for writing to flash memory, and the routines to read and write to flash memory. I have attached the project to this post if anyone wants to check things out along with me.

I noticed that boot_page_erase(page) erases 2 * 128 = 256 bytes starting from flash memory address page*SPM_PAGESIZE. I thought that boot_page_erase(page) erases 128 bytes (=SPM_PAGESIZE for ATmega328P).

I am still trying to work around this but with no success. What can I do in order to have my data stored in flash without losing any of them and without having any "gaps", i.e. having them stored in continuous addresses?

 

EDIT: As I never give up easily, I made the following alterations to the code of my full application:

I filled up array LUTRAM with each one of LUTRAM[0], LUTRAM[1], LUTRAM[2] starting with 0x00 and ending with 0xFA.

Then I stored that array in flash, page 0x0D - this gives a start address of 0x0680 in flash memory for my data.

 

Then programmed the chip and after that, I read the contents of flash memory into a file. Here is an excerpt of that:

:10068000000001000200030004000500060007004E   // this is where test[0] starts - first element is 0x00
:10069000080009000A000B000C000D000E000F00FE
:1006A00010001100120013001400150016001700AE
........
:10086000F000F100F200F300F400F500F600F700EC
:10087000F800F900FA000000010002000300040083   // this is where test[0] ends - last element is 0xFA
:10088000050006000700080009000A000B000C0024
:100890000D000E000F0010001100120013001400D4
:1008A000150016001700180019001A001B001C0084
........
:100A5000ED00EE00EF00F000F100F200F300F40012
:100A6000F500F600F700F800F900FA0000000100B8   // this is where test[1] ends - last element is 0xFA
:100A7000020003000400050006000700080009004A   // this is where test[2] starts - first element is 0x00
:100A80000A000B000C000D000E000F0010001100FA
:100A900012001300140015001600170018001900AA
........
:100C5000F200F300F400F500F600F700F800F900E8
:100C6000FA0000000000000000000000000000008A   // this is where test[2] ends - last element is 0xFA  
:100C70000000000000000000000000000000000074

If I can understand what I am reading, my data have been successfully stored in flash! Can anyone confirm if I am right?

If I am right, this means that the AVR Simulator has another bug that should be taken into consideration.

Attachment(s): 

Last Edited: Tue. May 23, 2017 - 12:10 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Why not simply reserve a __flash array in the C then use that as the address to write to?
I disagree regarding the 'simply'. :-)

clawson wrote:
The only issue you will be to assure SPM page alignment. For that just over allocate the round up the base address to the first whole SPM page.
So the actual data has an offset within that array. How is it "simply" accessed then?

 

The "classical" approach of having it at a fixed address somewhere behind the code is simpler, especially because the data is written only at runtime so you don't have to handle that address anywhere else but in the source code. And with an appropriate declaration of the reading pointer you still have the convenience of the __flash access.

Stefan Ernst

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

sternst wrote:
. How is it "simply" accessed then?
the same expression that rounds up to the first flash page boundary gives you the address of the data doesn't it. 

 

But yeah maybe it's best to just manually pre-empt the linker and simply base at "end of app space" - "size of data" 

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

gmetaxas wrote:
I am still trying to work around this but with no success.
I haven't looked at your attachment, but I guess it has something  to do with bytes vs words.

 

Why do you insist in working with page numbers anyway? Use the example code as is with addresses (without your "page number wrapper" around it).

Stefan Ernst