AVR SPM instruction usage - peculiar behavior - soliciting input

Go To Last Post
81 posts / 0 new

Pages

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

I would agree that STM8 controllers are attractive.   I have an evaluation board somewhere.    From memory the peripherals were slightly better than AVR.    I have no idea what the registers are like.    I just used C.

 

I posted a full project.   You only need a uart_putc(), uart_getc() and initstdio().    Do you need this?

 

#include <avr/io.h>
#include <stdio.h>
#define BAUD 9600
#include <util/setbaud.h>

#if defined(RXC0)
#define UCSRA UCSR0A
#define UCSRB UCSR0B
#define UCSRC UCSR0C
#define UBRRL UBRR0L
#define UBRRH UBRR0H
#define UDR   UDR0
#define RXC   RXC0
#define UDRE  UDRE0
#define RXEN  RXEN0
#define TXEN  TXEN0
#define U2X   U2X0
#define UCSZ2 UCSZ02
#endif

int USART_ReceiveByte(FILE *fp)
{
    while ((UCSRA & (1<<RXC)) == 0) ;
    return UDR;
}

int USART_SendByte(char data, FILE *fp)
{
    if (data == '\n') USART_SendByte('\r', fp);
    while ((UCSRA & (1<<UDRE)) == 0) ;
    UDR = data;
    return data;
}

void initstdio(void)
{
    static FILE mystdout = FDEV_SETUP_STREAM(USART_SendByte, USART_ReceiveByte, _FDEV_SETUP_RW);
    stdout = stdin = &mystdout;                // Required for printf init

    /* Set baud rate */
    UBRRH = UBRR_VALUE >> 8;
    UBRRL = UBRR_VALUE;

    /* Enable receiver and transmitter */
    UCSRA = (0<<U2X);
    UCSRB = (1<<RXEN)|(1<<TXEN)|(0<<UCSZ2);
}

Your AS7 project needs F_CPU value in its "Symbols"

Your AS7 Linker flags need .bootloader=0x1f00

 

Obviously you may need to change these for your AVR.

 

Shout if you need help.   I would appreciate some more "tests".  e.g. a size limit on the emulated "EEPROM".   And more boundary cases.

Note that you want to change as many fields as you can in each call.    Flash will be erased every time there is an update.   even for one byte.

 

David.

 

Edit.  Corrected data type.

Last Edited: Thu. Jun 30, 2016 - 10:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

David:

I apologize, I did not see the full code posted in #46.  I see it now.  Not sure why it didn't show up.  GOOGLE Chrome cache perhaps?

 

Anyways, thank you.  I will work with that code to see the differences.

 

What is the code for in #52?

 

Peace and blessings,

Scott

Last Edited: Thu. Jun 30, 2016 - 09:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So... Is anyone going to suggest that perhaps LPM interferes with the SPM buffer?   thinking like a hardware engineer, I can see how that might happen, and how it might not get documented.

 

We have two cases:

 

;; Normal "bootloader" case.  Known to work. ("Alternative 2")

SPM erase page

SPM fill page from RAM buffer

SPM Write page

 

;; late erase ("Alternative 1") (Documented but suspect?)

SPM fill page from RAM buffer

SPM erase page

SPM Write page

 

I'm suggesting that the following might be a THIRD case, subject to complications:

SPM fill page from same page using LPM

SPM erase page

SPM write page

 

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

ksvitale wrote:
As a general observation, I see a lot of advantages to "C" over ASM but I see a lot of waste in code due to all the need for pointers pointing to pointers pointing to data, etc., which slows down code execution because there are so many LOAD/STORE operations.  The use of RAM seems to be a bit more bloated as well.  I comprehend that in avr-gcc, there are a lot of tricks and techniques to get around SOME of those issues but to design something more that a blinking LED or thermostat can a bit more complex.  Sure, ARDUINO has made it a bit easier to use due to CPP but much more bloated code.
It seems to me that you are describing a rather poorly written C program.

C has been described as as an <insert adjective here> assembler.

In any case, a C pointer is close enough to an address register that I rather

doubt using C actually requires using more levels of indirection than assembler.

Iluvatar is the better part of Valar.

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

skeeve wrote:
<insert adjective here>

Macro?

Powerful?

Replacement?

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

Macro?

Powerful?

Replacement?

Portable?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Hi Bill:

Thank you for responding.  I was hoping someone that had worked heavily on bootloaders (like Optiboot) would be able to add some input on this subject.

 

westfw wrote:

So... Is anyone going to suggest that perhaps LPM interferes with the SPM buffer?   thinking like a hardware engineer, I can see how that might happen, and how it might not get documented.

 

Yes, the LPM instruction uses th ZH:ZL as a pointer and yes, all SPM commands (fill buffer, erase page, write page) also use ZH:ZL but unless there is some, like you said "undocumented" behavior, I am not sure that I can see how that happen.  Do you have a more specific hypothesis?

 

In testing, I have not had any problems copying from FLASH to RAM buffer then erase, fill temp-buffer, write page.  In my application though, I have no place else to put the existing page data and as the ATMEL datasheet states, the temp-buffer can be used for such a purpose as quoted in post #34.

 

The frustrating issue I have with this whole confusion is that ATMEL corporate has not responded to my support ticket in about four weeks.  I am sure they could clear this up ... but for whatever reasons, they are remaining silent.

 

westfw wrote:

We have two cases:

 

;; Normal "bootloader" case.  Known to work. ("Alternative 2")

SPM erase page

SPM fill page from RAM buffer

SPM Write page

 

;; late erase ("Alternative 1") (Documented but suspect?)

SPM fill page from RAM buffer

SPM erase page

SPM Write page

 

Except that David was able to test that both work with his code.  I am still working to get his code to work.  There was no "Makefile" attached so I have to set one up with the proper parameters to be passed to his test program.

 

westfw wrote:

I'm suggesting that the following might be a THIRD case, subject to complications:

SPM fill page from same page using LPM

SPM erase page

SPM write page

 

I have done that, copy directly from FLASH to the temp-buffer but as you show in the scenario above, it requires that the page to be erase AFTER writing to the temp-buffer, which I am having difficulty with in my ASM code.  That's why I am trying (as I have stated, I am not a fluent "C" programmer) to get his test code running so I can compare to my ASM code to see what I am missing.

 

I will be away till from July 3 to July 6 and not be able to respond to any posts.

 

Thank you again  for your input.

 

Peace and blessings,

Scott

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

Scott,

If you say which AVR, which IDE, which operating system, ...

I could provide you with the associated project or Makefile.
I must confess that any "I don't do X" announcement is treated with little sympathy.
You must be capable of building an App Note with standard tools. After you have got it running as Nature intended, you can translate to whatever language or platform you like.
.
Anyway, tell us what "conventional" setup is your preference. I will post you an example that works straight out of the box.
.
Incidentally, since I was using a Mega16, I built the same project in AS4 with a Chinese JTAGICE-1 clone. It is a pity that the AS4 local variables are not so easy to follow. Rowley Crossworks is a far more pleasant environment than any of the AS#.
.
David.

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

I was hoping someone that had worked heavily on bootloaders (like Optiboot) would be able to add some input on this subject.

Well, I can confirm that optiboot does the "erase page" before it starts  doing the "fill page" operation.   But aside from that, Optiboot had working flash-write code when I started hacking it, and I've been pretty careful to leave it alone.  So I'm not really familiar with the details and peculiarities.   I suspect that that is a good part of your problem you're having getting responses; most people copy some working example and it's "good enough."

 

 

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

I can assure you that all sorts of things happen when you don't wait for SPM completion.  e.g. temporary buffer ANDs the contents instead of replacing when you use boot_page_fill

 

If Scott wants to investigate how everything works,   he just wants to specify his Tools, Platform etc.

 

The Bootloader is simple.   You erase a Page.  And fill it with fresh contents.   I presume that Scott wants to update a field rather than write the whole record in one go.

 

David.

Last Edited: Fri. Jul 1, 2016 - 10:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am behind on replies.

 

david.prentice wrote:

I can assure you that all sorts of things happen when you don't wait for SPM completion.  e.g. temporary buffer ANDs the contents instead of replacing when you use boot_page_fill

 

I agree BUT the code DOES wait for the SPMEN bit to clear before doing anything else. 

 

david.prentice wrote:

If Scott wants to investigate how everything works,   he just wants to specify his Tools, Platform etc.

 

I do not comprehend that statement.  Please clarify.  To the best of my knowledge, I have specified everything that I thought was required for assistance; target platforms, tools, code, observations, etc.

 

david.prentice wrote:

The Bootloader is simple.   You erase a Page.  And fill it with fresh contents.   I presume that Scott wants to update a field rather than write the whole record in one go.

 

As I have consistently stated on a few occasions throughout this thread, I want to copy existing page FLASH data directly to the temp-buffer, modifying as much as 32 bytes in the process of the existing data with new data, erase the target page then write it it back, the entire modified page, not a partial page.  All the datasheets say I can do that, yet I cannot with the sample code published in the datasheets.  It does not seem to be related to the SPMEN bit nor the RWWSRE bit.  It APPEARS to be a hardware issue but I have not yet been able to compile and test David's "working" test code.  I was getting compilation errors but have those resolved.  Now I have to figure out how to get the bootloader section addressed in the MAKE file.  Once I get his code to compile, I will compare the order of operations at the assembly level to see what is different.  If the "C" <avr/boot.h> library macros work then the avr-gcc programmers guys must have figured out something that isn't quite so obvious to me.   I am out of town for a few days and will be unavailable to test this any further.

 

[slightly off-topic comments]

skeeve wrote:

ksvitale wrote:
As a general observation, I see a lot of advantages to "C" over ASM but I see a lot of waste in code due to all the need for pointers pointing to pointers pointing to data, etc., which slows down code execution because there are so many LOAD/STORE operations.  The use of RAM seems to be a bit more bloated as well.  I comprehend that in avr-gcc, there are a lot of tricks and techniques to get around SOME of those issues but to design something more that a blinking LED or thermostat can a bit more complex.  Sure, ARDUINO has made it a bit easier to use due to CPP but much more bloated code.

  1. It seems to me that you are describing a rather poorly written C program.
  2. C has been described as as an <insert adjective here> assembler.
  3. In any case, a C pointer is close enough to an address register that I rather doubt using C actually requires using more levels of indirection than assembler.

  1. Perhaps but many programs that I have seen posted or available LOOK cryptic.  Yes, I comprehend the syntax, pointers to variable vs. variable, ext.  If I look at an ASM program, I can follow the flow but in many cases, looking at a "C" program, it sometimes gets to the point where all the keywords and syntax starts to blend into just a screen full of characters (pixels?) that no longer have structure or meaning.  LOL Couple that with the sometimes cryptic error messages and warnings from the compiler plus author specific MAKE file idiosyncrasies, its gets overwhelming for me.  I have recently been told by someone that "no one wants to spend the time assisting some one that does not want to keep up with the times".  Huh?  Learning any programming language and it's the associated idiosyncrasies of the language, MCU and development tools requires the simplest form of brainwashing; repetition.  I do not program full time; i.e. I am not programming in "C" 8 to 12 hours a day for 5 or 6 days a week, hence no repetition.  
  2. Yes, the word I have always read was "Generic" but honestly, like any program, if written in a modular fashion and properly documented, assembly language is a whole lot more straightforward.
  3. In theory and concept I agree but at the register and memory level, no.  "C" makes heavy use of pointers, thus in order to access a variable, the pointer must first be "loaded" from memory into a 16-bit register, say XH:XL then another "load" from memory to register in performed; that's two loads from memory just to get to the data and 3 bytes of memory for an 8-bit value.  In ASM, I already know the memory location of the variable in RAM, thus only one "load" is required and it requires only one byte of memory.  I comprehend that registers can be specified to hold a value instead of holding the value in memory.  AVR-gcc zeroes register "r1" so that any clearing or "zeroing" of a register is as simple as a "mov rd,r1" or "out I/O,r1" or "sts I/O,r1".

[/slightly off-topic comments]

 

So to those of you who are avid "C" programmers, have been programming for a while and have great memory retention for the "knowledge base" required to keep track of all the variations of coding, tool and MCU idiosyncrasies, I have great respect for you.  I want to again extend an appreciation to those who have added valuable input , research time or just read over the thread.  

 

Peace and blessings,

Scott

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

Hi David:

david.prentice wrote:

If you say which AVR, which IDE, which operating system, ...

I could provide you with the associated project or Makefile.

Incidentally, since I was using a Mega16, I built the same project in AS4 with a Chinese JTAGICE-1 clone. It is a pity that the AS4 local variables are not so easy to follow. Rowley Crossworks is a far more pleasant environment than any of the AS#.
.
David.

 

I recant the last statement.  I THOUGHT I had mentioned IDE, target MCU, etc. in the initial post.

 

Linux is my development platform but I am running WINDOWS XP in an virtual machine so that I can use AVR STUDIO 4.19 (sp3?) with an AVR-DRAGON as an emulator.  Depending on MCU, either using JTAG or DEBUGWIRE interface.  I prefer the JTAG interface so have tested the code on the mega32u4 and 90usb1286 (JTAG) but also on the mega32, mega328p and tiny85 (DEBUGWIRE).

 

I am fully aware of and competent to modify MAKE files and "C" processor conditionals and definitions to compensate in the difference between MCU-to-MCU I/O register name differences.  BUT your MAKEFILE may be helpful so I can see how you are defining the bootloader section for the linker.

 

Thank you.

 

Peace and blessings,

Scott

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

I have attached an AS4 project.   It is configured for a ATmega32 @ 8MHz.   It is untested with my Dragon because it is a pain to downgrade and I can't be bothered to swap the mega16 chip.

 

I built on AS7 or various targets: mega16, mega168, mega128, mega32, mega328P, mega32u4, 90usb1287.

I have tested on a mega16, mega128 with Dragon (AS7) and JTAGICE-1 (AS4)

I have tested on a mega168 with STK500.

 

It will not build on a tiny85 because 1: there is no USART, 2: the Tiny does not have RWWSE bit.

 

Note that you MUST change the Memory Settings manually in both AS4 and AS7.   i.e. for .bootloader=xxxx

 

If you have a problem,  please ask.   Especially about the macros.   It complicates matters when you want 128k AVRs.

 

David.

Attachment(s): 

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

ksvitale wrote:
[slightly off-topic comments]
Quote:
In theory and concept I agree but at the register and memory level, no.  "C" makes heavy use of pointers, thus in order to access a variable, the pointer must first be "loaded" from memory into a 16-bit register, say XH:XL then another "load" from memory to register in performed; that's two loads from memory just to get to the data and 3 bytes of memory for an 8-bit value.  In ASM, I already know the memory location of the variable in RAM, thus only one "load" is required and it requires only one byte of memory.  I comprehend that registers can be specified to hold a value instead of holding the value in memory.  AVR-gcc zeroes register "r1" so that any clearing or "zeroing" of a register is as simple as a "mov rd,r1" or "out I/O,r1" or "sts I/O,r1".

[/slightly off-topic comments]

Not even at -O0 .

 

If you know the address before run time, to C, that is a global or a static.

At pretty much any optimization level, avr-gcc will give you a single LDS instruction.

At -O0 , I think that you would get a a couple LDIs, a MOVW and a LD.

Don't use -O0 .

 

In the case of a one-byte local variable stored in SRAM,

the stack pointer will have been copied to Y and the fetch would likely be a single LDD instruction.

Exceptions occur, e.g. when you have so many locals that some are outside the range of the LDD.

Iluvatar is the better part of Valar.

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

Hi Scott,

 

Made a small assembly thing that seems to do what you want. At least it works on the atmega324pb that I tested it on. I wrote it for GNU asm, so you will have to change a bit of the code, but nothing special. Also you must add the code to change some of the bytes inside the loop that reads out the content of flash.

.nolist
;.include "usb1286def.inc"	;128K FLASH, 8K DATA, 4K EEP, USB
;.include "m32u4def.inc"		;32K FLASH, 2.5K DATA, 1K EEP, USB
#include <avr/io.h>   


.list

;define register names
#define temp1		r16
#define temp2		r17
#define spmcrval	r20
#define looplo		r18
#define loophi		r19
#define PAGESIZE	128

.section .vectors
start:
	jmp boot

;===============================================================================
.org PAGESIZE; set program counter for page alignment
SPM_DATA:		; reserve FLASH memory for data storage (MCU specific)
	.int	0x03020100,0x07060504,0x0B0A0908,0x0F0E0D0C
	.int	0x13121110,0x17161514,0x1B1A1918,0x1F1E1D1C
	.int	0x23222120,0x27262524,0x2B2A2928,0x2F2E2D2C
	.int	0x33323130,0x37363534,0x3B3A3938,0x3F3E3D3C
	.int	0x03020100,0x07060504,0x0B0A0908,0x0F0E0D0C
	.int	0x13121110,0x17161514,0x1B1A1918,0x1F1E1D1C
	.int	0x23222120,0x27262524,0x2B2A2928,0x2F2E2D2C
	.int	0x33323130,0x37363534,0x3B3A3938,0x3F3E3D3C
.fill FLASHEND-0xff-256, 1, 0xff
;===============================================================================
.org (FLASHEND-0xff)
boot:
	ldi loophi, hi8(PAGESIZE*2)
	ldi looplo, lo8(PAGESIZE*2)
	ldi ZH, hi8(PAGESIZE)
	ldi ZL, lo8(PAGESIZE)
	/* Read out flash to page buffer */
	ldi	spmcrval, 0x1
loop:
	lpm r0, Z+
	lpm r1, Z
	dec ZL
	/* change r0 and r1 here */
	sts SPMCSR, spmcrval
	spm Z
	adiw ZL, 2
	cp ZL, looplo
	cpc ZH, loophi
	brlo loop

	/* Erase page */
	ldi ZH, hi8(PAGESIZE)
	ldi ZL, lo8(PAGESIZE)
	ldi spmcrval, 0x3
	sts SPMCSR, spmcrval
	spm
	
	/* Wait loop */
wait:
	lds temp1, SPMCSR
	sbrc temp1, SPMEN
	rjmp wait

	/* Write data in page buffer */
	ldi spmcrval, 0x5
	sts SPMCSR, spmcrval
	spm
	
End:
	rjmp End

Also, I might have missed something. :P

 

Hope this helps,

-Bent

 

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

Hi Scott,

hope I am not repeating what was already made clear in previous posts as it is a bit TL;DR as clawson already said.

 

As the subject piqued my interest (and recognising a fellow control freak :D ) I decided to do a bit of basic testing myself, using the ATmega48 as a reasonable (low memory size) target.

 

IIUC you want to modify various length blocks of the AVR Flash memory without resorting to any RAM PAGE buffers (the easy way).

 

As I see it with the constraints imposed by the AVR Flash memory programming architecture you will have to :

 

(a) Transfer in your bootloader client application firstly the start address (and length/end address possibly) of your block to be changed, then wait for the AVR to respond ready.

 

(b) Based on this address the AVR bootloader code copies from this selected flash page (which is still intact as no erase has as yet been performed) all the bytes (LPMs) into the temporary PAGE buffer preceding the block to be altered by the new data.

 

(c) Then the AVR acknowledges to the client application it is ready for the data from the block to be changed.

 

(d) As each byte arrives over the comms link it is also written contiguously directly into the temporary PAGE buffer.

 

(e) Once the last byte of the block to be changed has been received (using the end-address/block length data originally transferred) the AVR signals the client bootloader application to wait once more.

 

(f) The AVR now finally copies the remaining bytes of the (as yet unaltered) Flash Page to the temporary PAGE buffer such that the PAGE buffer now contains all the unaltered flash bytes plus those altered via the bootloader page data transfer (d).

 

(g) Now you can execute the flash PAGE ERASE (flash now gone but PAGE buffer intact) and flash PAGE WRITE (now PAGE buffer also cleared) operations and wait for completion.

 

(h) Finally the AVR signals the client that the PAGE is done and it can continue or finish the bootloader operation.

 

Niceties like maybe transferring the integral page/s of the FLASH data first back over the comms link to the client application which may have more memory buffering resources for validation of the result (or recovery if something happens to go awry on the AVR side) can be considered.

 

This should allow you to avoid any AVR RAM page buffers as long as the speed/complexity of Flash updating process isn't an absolute constraint.

 

Multiple Odd bytes of Flash to be changed could be done by successive programming operations if Flash Endurance criteria (Tens of thousands of erase cycles per page) isn't a problem or by a slightly more complex AVR bootloader code understanding page multi-block criteria.

 

Regards,

Robin.

 

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

I don't know if you are back from your trip.

 

I tried spideog's idea.   It does not work.   When you have loaded the whole temporary buffer with the current Flash page,  any subsequent writes to the buffer AND with the contents.   So it works fine with a virginal page.   It does not work if you are trying to update a small block.    (unless bits are going from 1 to 0)

 

This is slightly different to the datasheet.   The datasheet says that if you write more than a pageful to the temporary buffer,  the buffer is automatically erased.

 

So I think the best approach is to fill each byte of the buffer from Flash or SRAM in one pass.   (as in the AS4 and AS7 projects that I posted)

 

David.

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

Hi David,

in (b) I said ..."all the bytes (LPMs) into the temporary PAGE buffer preceding the block to be altered by the new data.

 

I did not say to copy all the bytes in the block, which would then necessarily incur double writing of the temporary PAGE buffer which is forbidden (probably correctly).

 

I didn't get around to looking at the code you posted so I am not saying anything about that, I am just trying to reconcile the datasheet Alternative 1 indications with a technical feasibility e.g. a procedure.

 

Regards,

 

Robin.

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

Life would certainly be easier if you could overwrite the temporary page buffer like a 24Cxxx EEPROM.
You would write your changed bytes with random access. Then write the page like you would with a 24Cxxxx.
.
Anyway, it is fairly easy to flip between LPM and SRAM in a single pass. As you can see by my later code. My first attempt with word alignment was clunky.
.
David.

Last Edited: Thu. Jul 7, 2016 - 09:40 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If life were easy you wouldn't need engineers ;)

 

Sometimes you need to be grateful for problems :D

 

 

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

Folks:

I've been off this project for a few months as it got shelved temporarily.

 

However, ATMEL tech support FINALLY got back to me, nearly four months later.  The "SPM issue", at least from my perspective, has been resolved but I am awaiting a confirmation back from tech support to verify that the issue I found can be duplicated on their end, thus the case will not be marked as "closed" until I receive such confirmation.  I will update this thread upon confirmation.

 

I found the culprit because ATMEL's tech support submitted to me a piece of slightly modified ASM test code (acquired from the datasheet) for "Alternative Method 1" that worked correctly.  Upon further review, I saw that they had commented out the RWW re-enabling code (two instructions) performed after the page erase.   Essentially, the code example in the datasheets, which has been duplicated in the datasheets (for the last 15 years?) in at least the 7 or so AVR8's that I have been working with, have the same erroneous code example.   That is, if one tries to use it (slightly modified) with "Alternative Method 1", it will not work but it will work correctly with "Alternative Method 2"

 

In the datasheet example code, after a page erase, the RWW (application) section of FLASH is re-enabled.  If after a page erase, the RWW section IS NOT re-enabled, "Alternate Method 1" works correctly.  What I suspect happens is that after a page erase, re-enabling the RWW section clears the temporary buffer.  I tested this by un-commenting the RWW re-enable code in ATMEL's submitted test program and it then fails.  I then commented out the RWW re-enable code in my test code and my test code now works properly, both in filling the temporary buffer from RAM and filling the temporary buffer directly from the target page in FLASH "on-the-fly".  Re-enabling of the RWW section using "Alternative Method 2" is not affected because filling the temporary buffer is done AFTER the page erase.  This is the difference and why the example code in the datasheets works for "Alternative Method 2" and not "Alternative Method 1".

 

Why then does the "C" code that Dave Prentice of the U.K. work when my pure assembly version does not?  Dave's code does not enable the RWW section after a page erase, only after the page write.  I also checked the the resulting ASM listing from Dave's code example (and GCC's boot.h) to verify that GCC's "boot_page_erase" functions does not embed an RWW re-enable and found that I was correct .

 

Excerpt from Dave's code:

            boot_page_erase(loc_page);  //
            boot_spm_busy_wait();       // Wait until the memory is erased.
            boot_page_write(loc_page);  // Store buffer in flash page.
            boot_spm_busy_wait();       // Wait for completion.
            boot_rww_enable();          // should erase the temp buffer
            boot_spm_busy_wait();       // Wait for completion.

BTW: on the RWWSRE bit the datasheet(s) simply states the following.  It does not say anything about it clearing the temporary buffer nor does it warn the programmer to not re-enable the RWW section after a page erase, thus it is easy to assume that re-enabling the RWW section after a page erase is okay and will cause no problems.  As a mattrer of fact, to further support this assumption, the example code in the datasheet implies that it MUST ALWAYS be done after a page erase. :(

• Bit 4 – RWWSRE: Read-While-Write Section Read Enable
When programming (Page Erase or Page Write) to the RWW section, the RWW section is
blocked for reading (the RWWSB will be set by hardware). To re-enable the RWW section, the
user software must wait until the programming is completed (SPMEN will be cleared). Then, if
the RWWSRE bit is written to one at the same time as SPMEN, the next SPM instruction within
four clock cycles re-enables the RWW section. The RWW section cannot be re-enabled while
the Flash is busy with a Page Erase or a Page Write (SPMEN is set). If the RWWSRE bit is writ-
ten while the Flash is being loaded, the Flash load operation will abort and the data loaded will
be lost.

 

I hope this helps others that may also be using the "Alternative Method 1" using assembly language programming of the AVR8's.

 

For all those that took the time to investigate this issue, I thank you for your time, effort and support.

 

Peace and blessings.

Scott

 

Edit: See post #78 further down on Oct 17, 2016 for ATMEL's response.

Last Edited: Mon. Oct 17, 2016 - 03:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ksvitale wrote:
Why then does the "C" code that Dave Prentice of the U.K. work when my pure assembly version does not?
First guess would be a timing thing then.

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

Hello Clawson:

Actually, as I had stated:

Dave's code does not enable the RWW section after a page erase, only after the page write.  

Thanks for your reply.

 

Peace and blessings,

Scott

 

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

Hi Scott,

 

Have you tried having a wait loop after the erase, before you re-enable the RWW? As you pointed to yourself in the datasheet:

If the RWWSRE bit is written while the Flash is being loaded, the Flash load operation will abort and the data loaded will
be lost.

Edit: Yes, I guess you do.

Edit2: In the 324PB datasheet, as pointed out earlier:

30.8.2. Filling the Temporary Buffer (Page Loading)
To write an instruction word, set up the address in the Z-pointer and data in [R1:R0], write “0x00000001”
to SPMCSR and execute SPM within four clock cycles after writing SPMCSR. The content of PCWORD
([Z5:Z1]) in the Z-register is used to address the data in the temporary buffer. The temporary buffer will
auto-erase after a Page Write operation or by writing the RWWSRE bit in SPMCSR
(SPMCSR.RWWSRE). It is also erased after a system reset. It is not possible to write more than one time
to each address without erasing the temporary buffer.
If the EEPROM is written in the middle of an SPM Page Load operation, all data loaded will be lost.

 

Last Edited: Fri. Oct 14, 2016 - 12:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello benteven:

Thanks for your response.

 

I have read that statement probably 100 times and always questioned why the example program in the datasheet showed to use it after a page erase.  That was precisely why I contacted ATMEL tech support, for clarification on the correct way to implement "Alternative Method 1" when the example in the datasheet, with the page erase and page write functions reversed, always failed.

 

I have found nothing in the datasheet that says that the RWW section must be enabled after a page erase nor have I found anything in the datasheets that says it should not be performed after a page erase (contrary to the example code in the datasheet).  The implication, at least in my view WAS that the RWW section had to be re-enabled after any FLASH writes, which includes page erase.  I do not expect the datasheets to be changed but a clarification in future releases would be nice.

 

In any case, the clarification was eventually found on when to use the RWWSRE bit to re-enable the RWW section: Don't enable the RWW section of FLASH by setting the RWWSRE bit after a page erase, only after a page write. 

 

Seems like it would have been a quick answer from ATMEL, though.

 

Peace and blessings,

Scott

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

ksvitale wrote:
I have found nothing in the datasheet that says that the RWW section must be enabled after a page erase nor have I found anything in the datasheets that says it should not be performed after a page erase (contrary to the example code in the datasheet).  The implication, at least in my view WAS that the RWW section had to be re-enabled after any FLASH writes, which includes page erase.  I do not expect the datasheets to be changed but a clarification in future releases would be nice.

 

Hi Scott,

 

Well, you can re-enable the RWW section after an erase, it will only be a problem when you have something in the page buffer like "Alternativ 1". If that was not in the datasheet, I'm sure we would have someone else posting a thread about how they are not able to run code from the RWW section to fetch more data from their USART between erase and write. :P But it could be mentioned in the programming example that the RWW section must not be enabled if there is something in the page buffer.

 

-Bent

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

Hi Bent:

Thank you for responding.

 

Yes,  erasing the temporary buffer after a page erase was the issue after all.  Today, I received an email from ATMEL factory tech support.  They admitted that the use of the RWWSRE bit was a little ambiguous based on the datasheet example and agreed to modify the datasheets.  Here is an excerpt from their email to me.

The “re-enabling the RWW section” actually set the RWWSRE bit after page erase sequence. When we try to set the RWWSRE bit when the temporary page buffer is already filled. The contents of the temporary page buffer will be erased. Hence, while using alternative 1 the re-enabling of RWW section should not be done after the page erase. 

And we will also acknowledge that this information is not documented properly in the datasheet. Hence we have suggested the following improvement in the datasheet. 

Instead of the following line below erase sequence, 

******************************* 
; re-enable the RWW section 
ldi spmcrval, (1<<RWWSRE) | (1<<SPMEN) 
call Do_spm 
******************************* 

We have suggested the following lines to be replaced 

******************************* 
; re-enable the RWW section 
; must be avoided if page buffer is pre-filled. Will flush page buffer. 
ldi spmcrval, (1<<RWWSRE) | (1<<SPMEN) 
call Do_spm 
******************************* 

Thank you to all who have added to this thread.

 

Peace and blessings,

Scott

 

 

 

 

 

 

 

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

You say you do not have enough ram left for one SPM page of data? I suggest you rethink some of your design to free up some of that ram.

 

Alternatively do you have at least one page of eeprom available?

 

1: copy data from flash page to eeprom with the modifications being applied prior to writing

2: erase flash page

3: copy modified data out of eeprom back to flash.

If something can be read without effort then great effort has gone into its writing

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

mark4th wrote:
I suggest you rethink
Well here's the thing - he sat there contemplating this for the last THREE YEARS but in the end he thought his current design was OK so he went off happy anyway ;-)

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

When I respond to an old thread, it is usually because I found

it with a search and was not conscious of how old it was.

Iluvatar is the better part of Valar.

Pages