## Writting to FLash Memory

97 posts / 0 new
Author
Message

HI all,

This is my first question in the form. I will try my best to follow the rules and be as clear as possible

I am working with Atmega32u4 (in Arduino board-this is BASED OF THE CATERINA BOOTLOADER) and I'm trying to write data to flash memory from the application. After a lot of research and long working hours I came close but not there yet.

I Defined a function called Do_spm_N () that write data to flash memory, in the bootloader section. Mad sure that the section lives in the bootloader part.

in my application I'm calling the function to write data to flash. however nothing written to flash. memory any idea what could be wrong. here is the code

1- defining function in the bootloader

// this part in my bootloader.c

:
:
:
:
...
:
:
:
:
......
static void do_spm_N (uint32_t address,  uint8_t *data){

uint16_t i;
uint8_t sreg;
// Disable interrupts.
sreg = SREG;
cli();
eeprom_busy_wait ();
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 = *data++;
w += (*data++) << 8;

}
boot_page_write (address);     // Store buffer in flash page.
boot_spm_busy_wait();       // Wait until the memory is written.
// Reenable RWW-section again. We need this if we want to jump back
boot_rww_enable ();
// Re-enable interrupts (if they were ever enabled).
SREG = sreg;
// this is for indication
for(int i=0; i >= 5;i++){
L_LED_ON();
delay(10);

RX_LED_OFF();
TX_LED_OFF();
L_LED_OFF();
delay(10);
RX_LED_ON();
TX_LED_ON();
L_LED_ON();
delay(10);
RX_LED_OFF();
TX_LED_OFF();
L_LED_OFF();
}

}

// MAKE FILE
LDFLAGS += -Wl,--section-start=.bootloader=(BOOT_START) 3- defining the function and calling it in my application // APPLication.h static void (*do_spm_N)(uint32_t address, uint8_t *data)__attribute__ ((section(".bootloader"))) ; // Application.ino (the atmerga32u4 lives in an arduino board) const char flash_buffer[SPM_PAGESIZE] __attribute__ (( aligned(SPM_PAGESIZE) )) PROGMEM= {}; char Str [] = " 0123456789ABCDEFGHIJKLMNOPQRSTUVW"; uint8_t ram_buffer[SPM_PAGESIZE]; void setup() { // Init serial Serial.begin(9600); for (int i = 0; i<= sizeof(Str);i++){ ram_buffer[i] =Str[i]; } } void loop() { // no code here int i; uint8_t c; uint16_t w; byte data ino // Print current flash buffer content if (Serial.available() > 0 ) { data = Serial.read() ; switch (data) { case 'w':{ do_spm_N ((uint32_t) &flash_buffer[0], *ram_buffer); } } } } Any idea/suggestion ? thanks in advance Supporting Information:- Last Edited: Thu. Oct 11, 2018 - 03:34 PM Total votes: 0 What does the hex or nm say? Total votes: 0 An AVR's idea of the bootloader section depends on its fuses. The linker's idea of the .bootloader section depends on(BOOT_START).

Do they match?

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

WHY are you writing to flash memory from a running application?   This is never done.

If you need to store lots of data, even through power cycles, use serial EEPROM or FRAM.  Here is an example of a simple 512 x 8 8-pin cheap EEPROM IC.  Other serial EEPROMs hold up to 128K bytes in the same pin-out:

https://www.ebay.com/itm/25LC040...

Last Edited: Fri. Oct 5, 2018 - 02:23 AM

This is never done.

Rubbish.

It is infrequently done, but 'never' is a long time.

 "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]

Simonetta wrote:
This is never done.
As someone who has done exactly this - written to flash in an app - this just proves what utter nonsense you talk almost all the time. You clearly have no idea how micros are used at all so I don't know who you think you can advise people about the subject with such utter drivel and misinformation?

I think the .hex file is correct ( I might be wrong). I looked at the hex and it starts at the correct address (per my calculation )

here is the first 20 lines

:1070000074C000008DC000008BC0000089C000006B
:1070100087C0000085C0000083C0000081C0000060
:107020007FC000007DC0000007C5000079C00000DF
:1070300077C0000075C0000073C0000071C0000080
:107040006FC00000FEC000006BC0000069C00000FF
:1070500067C0000065C0000063C0000061C00000A0
:107060005FC000005DC000005BC0000059C00000B0
:1070700057C0000055C0000053C0000051C00000C0
:107080004FC000004DC000004BC0000049C00000D0
:1070900047C0000045C0000043C0000041C00000E0
:1070A0003FC000003DC000003BC00000873EA03E46
:1070B0004C3FA03E4C3FD83EFA3E4C3F1A3F2C3F3F
:1070C0002203300030003000320034003900340038
:1070D00033003500380000001201100102000008E2
:1070F000DAE0DEBFCDBF11E0A0E0B1E0E2E2FFE701
:1071000002C005900D92AE39B107D9F721E0AEE982
:10711000B1E001C01D92A73FB207E1F762D3FFC6FD
:107120006FCF84E08093E9008091E80085FD0DC079
:107130008091E8008B778093E8008091E80082FDE1

But what is "nm"?

Last Edited: Fri. Oct 5, 2018 - 12:36 PM

clawson wrote:

What does the hex or nm say?

I think the .hex file is correct ( I might be wrong). I looked at the hex and it starts at the correct address (per my calculation )

here is the first 20 lines

:1070000074C000008DC000008BC0000089C000006B
:1070100087C0000085C0000083C0000081C0000060
:107020007FC000007DC0000007C5000079C00000DF
:1070300077C0000075C0000073C0000071C0000080
:107040006FC00000FEC000006BC0000069C00000FF
:1070500067C0000065C0000063C0000061C00000A0
:107060005FC000005DC000005BC0000059C00000B0
:1070700057C0000055C0000053C0000051C00000C0
:107080004FC000004DC000004BC0000049C00000D0
:1070900047C0000045C0000043C0000041C00000E0
:1070A0003FC000003DC000003BC00000873EA03E46
:1070B0004C3FA03E4C3FD83EFA3E4C3F1A3F2C3F3F
:1070C0002203300030003000320034003900340038
:1070D00033003500380000001201100102000008E2
:1070F000DAE0DEBFCDBF11E0A0E0B1E0E2E2FFE701
:1071000002C005900D92AE39B107D9F721E0AEE982
:10711000B1E001C01D92A73FB207E1F762D3FFC6FD
:107120006FCF84E08093E9008091E80085FD0DC079
:107130008091E8008B778093E8008091E80082FDE1

But what is "nm"?

Simonetta wrote:

WHY are you writing to flash memory from a running application?   This is never done.

NO< Let me correct you. I searched the web and It was done before for sure.

the EEPROm is small i need to use the rest of my flash memory to save data

clawson wrote:

Simonetta wrote:
This is never done.
As someone who has done exactly this - written to flash in an app - t

agree with you it was done before

skeeve wrote:

An AVR's idea of the bootloader section depends on its fuses.

The linker's idea of the .bootloader section depends on $(BOOT_START). Do they match? I 'm not sure how to check the fuses, any hint ? I am using a make file to compile . DO you mean BOOTSZ? Last Edited: Fri. Oct 5, 2018 - 12:50 PM Total votes: 0 avr-nm is one of the tools that comes with avr-gcc. If you happen to use AS7 then on the tools menu there is an entry for "Command Prompt". When you select that then PATH is set so all the avr-gcc tools like avr-gcc, avr-objcopy, avr-objdump, avr-ar, avr-nm can be found. It's basically these: C:\>where avr-gcc C:\program files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin\avr-gcc.exe C:\>cd C:\program files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin>dir avr-*.exe Volume in drive C is OSDISK Volume Serial Number is 7AF3-B2D0 Directory of C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin 13/09/2017 00:24 494,080 avr-addr2line.exe 13/09/2017 00:24 514,560 avr-ar.exe 13/09/2017 00:24 666,112 avr-as.exe 13/09/2017 00:24 736,768 avr-c++.exe 13/09/2017 00:24 492,544 avr-c++filt.exe 13/09/2017 00:24 735,744 avr-cpp.exe 13/09/2017 00:24 31,744 avr-elfedit.exe 13/09/2017 00:24 736,768 avr-g++.exe 13/09/2017 00:24 734,208 avr-gcc-5.4.0.exe 13/09/2017 00:24 49,664 avr-gcc-ar.exe 13/09/2017 00:24 49,152 avr-gcc-nm.exe 13/09/2017 00:24 49,152 avr-gcc-ranlib.exe 13/09/2017 00:24 734,208 avr-gcc.exe 13/09/2017 00:24 380,928 avr-gcov-tool.exe 13/09/2017 00:24 390,656 avr-gcov.exe 13/09/2017 00:24 3,988,480 avr-gdb-py.exe 13/09/2017 00:24 3,831,296 avr-gdb.exe 13/09/2017 00:24 544,256 avr-gprof.exe 13/09/2017 00:24 942,080 avr-ld.bfd.exe 13/09/2017 00:24 942,080 avr-ld.exe 13/09/2017 00:24 502,272 avr-nm.exe 13/09/2017 00:24 629,760 avr-objcopy.exe 13/09/2017 00:24 730,112 avr-objdump.exe 13/09/2017 00:24 514,560 avr-ranlib.exe 13/09/2017 00:24 393,728 avr-readelf.exe 13/09/2017 00:24 502,272 avr-size.exe 13/09/2017 00:24 495,104 avr-strings.exe 13/09/2017 00:24 629,760 avr-strip.exe 28 File(s) 21,442,048 bytes So if I now switch to a directory where a program has been built and give the command: C:\Users\uid23021\Documents\Atmel Studio\7.0\test1\test1\Debug>avr-nm test1.elf 00000076 T __bad_interrupt 00000062 T __ctors_end 00000062 T __ctors_start 00000096 A __data_load_end 00000096 A __data_load_start 0000ffa0 A __DATA_REGION_LENGTH__ 00000062 T __dtors_end 00000062 T __dtors_start 00810000 D __eeprom_end 00010000 A __EEPROM_REGION_LENGTH__ 00000002 A __FUSE_REGION_LENGTH__ 00000000 W __heap_end 00000062 W __init 00000400 A __LOCK_REGION_LENGTH__ 00000400 A __SIGNATURE_REGION_LENGTH__ 0000003e a __SP_H__ 0000003d a __SP_L__ 0000003f a __SREG__ 0000045f W __stack 00000094 t __stop_program 00020000 A __TEXT_REGION_LENGTH__ 00000000 a __tmp_reg__ 00000054 T __trampolines_end 00000054 T __trampolines_start 00000400 A __USER_SIGNATURE_REGION_LENGTH__ 00000076 W __vector_1 00000076 W __vector_10 00000076 W __vector_11 00000076 W __vector_12 00000076 W __vector_13 00000076 W __vector_14 00000076 W __vector_15 00000076 W __vector_16 00000076 W __vector_17 00000076 W __vector_18 00000076 W __vector_19 00000076 W __vector_2 00000076 W __vector_20 00000076 W __vector_3 00000076 W __vector_4 00000076 W __vector_5 00000076 W __vector_6 00000076 W __vector_7 00000076 W __vector_8 00000076 W __vector_9 00000000 W __vector_default 00000000 T __vectors 00000001 a __zero_reg__ 00800060 D _edata 00800060 D _end 00000096 T _etext 00000092 T _exit 00000092 W exit 00000054 T foo 0000007a T main All of the code addresses in this are down near location 0. For a bootloader I'd expect these to be up near the BLS address. In fact "__vectors" should have the entry address. In this case that is 00000000. But anyway your .hex file already confirms the location: :1070000074C000008DC000008BC0000089C000006B It's the 7000 in that, just after the start of the line that gives the address as 0x7000 which is about right for the bootloader location in a 32K micro. (it'a actually 28K so it's 4K from the end of the chip). Total votes: 0 clawson wrote: your .hex file already confirms the location: :1070000074C000008DC000008BC0000089C000006B It's the 7000 in that, just after the start of the line that gives the address as 0x7000 which is about right for the bootloader location in a 32K micro. (it'a actually 28K so it's 4K from the end of the chip). OH I see. That will come handy one day. thanks for explanation. Yes the .hex confirm the bot location , but what could i be missing. DO you think I need to set lock bits i'm thinking to use something like that boot_lock_bits_set (_BV (BLB11)); what you think Total votes: 0 AVATAR_Freaks wrote: OH I see. That will come handy one day. thanks for explanation. The full explanation (as for so many things in like) is on Wikipedia: https://en.wikipedia.org/wiki/In... So: :1070000074C000008DC000008BC0000089C000006B should be read as: :10 7000 00 74C000008DC000008BC0000089C00000 6B length addr type data checksum As to your problems. Just never go anywhere near lockbits until you are finally ready to deploy the product and they won't trouble you - so as long as there's been a chip erase and reprogram (which resets everything to default) forget the lockbits as an issue - they won't affect this. Total votes: 0 I am confused about your general setup. #define BOOTLOADER_SECTION __attribute__ ((section(".bootloader"))) ; ... static void do_spm_N (uint32_t address, uint8_t *data) BOOTLOADER_SECTION; LDFLAGS += -Wl,--section-start=.bootloader=$(BOOT_START)

So the function is part of a normal application (located at 0x0000) where only the function is relocated to the boot sector?

But then why are you using a function pointer to call the function?

How is it possible that the pointer can have the same name as the function itself?

Where is this pointer even initialized?

What sense does it make to put the pointer into the .bootloader section?

And even more confusing, you have now presented a HEX file which contains a whole application (with interrupt vectors and all) being located in the boot sector.

Stefan Ernst

When I've done this in the past I have used the fact that <avr/boot.h> already has a definition of a BOOTLOADER_SECTION macro to assign a section attribute.

/** \ingroup avr_boot

Used to declare a function or variable to be placed into a
new section called .bootloader. This section and its contents

Then I just wrote the rest of the code like "normal C" just applying that macro to the handful of functions that needed to remain visible while SPM was operating (the rest of the code just switches to all 0xFFFF opcodes). No special consideration was needed for making the calls from the app functions to the SPM functions. Just code it like normal C but keep in mind that fact about "things disappearing" so relocate all the functions that might be required while SPM executes. And that, basically, is all there is to it. (not forgetting to do the -section-start thing on ".bootloader" to place it at/above the BLS address

:10     7000  00    74C000008DC000008BC0000089C00000 6B

is there a way to understand what "74C000008DC000008BC0000089C00000" actually means ?

ALso, If I erase and upload the bootloader , and the lockbits not set then i wont be able  to use SPM right ?

sternst wrote:

The function called do_spm_N() lives in the bootloader sector which is located at address 0x7000 which is the start of the bootloader.

this is how i define it in my application which could be wrong:-

[

sternst wrote:

But then why are you using a function pointer to call the function?

I though this is the way i should call it from my application, how else can I called from the application? i tried to use "extern" but it didn't compile any suggestions ?

[

sternst wrote:

How is it possible that the pointer can have the same name as the function itself?

Where is this pointer even initialized?

SO how can I point to an external function that is not defined in my sketch ?

[

sternst wrote:

What sense does it make to put the pointer into the .bootloader section?

NO the pointer is in the sketch

[

sternst wrote:

And even more confusing, you have now presented a HEX file which contains a whole application (with interrupt vectors and all) being located in the boot sector.

Yes it is a full application, but I only put the relevant parts :)

clawson wrote:

When I've done this in the past I have used the fact that <avr/boot.h> already has a definition of a BOOTLOADER_SECTION macro to assign a section attribute.

/** \ingroup avr_boot

this is basically what I'm doing.

clawson wrote:

Then I just wrote the rest of the code like "normal C" just applying that macro to the handful of functions that needed to remain visible while SPM was operating (the rest of the code just switches to all 0xFFFF opcodes). No special consideration was needed for making the calls from the app functions to the SPM functions. Just code it like normal C but keep in mind that fact about "things disappearing" so relocate all the functions that might be required while SPM executes. And that, basically, is all there is to it. (not forgetting to do the -section-start thing on ".bootloader" to place it at/above the BLS address

I feel like i taken care of all of that as you see previously, but i think maybe the way I call the function from my application

SO when I upload my bootloader to the baord and run an application both RX& TX LEDs are on as a sold color (not flashing), like it gets stuck.

Only if there is a ways  to debug, when the application call Do_SPM_N , does the bootloader  goes to that function or no?

So actually you have a bootloader and the function do_spm_N is part of it?

Then all this is nonsense:

...
LDFLAGS += -Wl,--section-start=.bootloader=$(BOOT_START) static void (*do_spm_N)(uint32_t address, uint8_t *data)__attribute__ ((section(".bootloader"))) ; All you need in the application is a correctly initialized function pointer: void (*do_spm_N)(uint32_t address, uint8_t *data) = 0xXXXX; Replace 0xXXXX with the word address of do_spm_N within the bootloader. Stefan Ernst Total votes: 0 I wrote some words the other day (which turned out at the time to be misguided) about sharing bootloader functions to an application: https://www.avrfreaks.net/commen... You may find something of use there. The basic principle here is that the only piece of "shared knowledge" between the app code and the boot code is a 16 bit pointer passed from one to the other and also that each knows the order of entries in an array of function pointers (who's base address is passed as that 16 bit value). The actual routines in the boot code that are shared to the app can actually live anywhere in the bootloader space. Total votes: 0 clawson wrote: Simonetta wrote: This is never done. As someone who has done exactly this - written to flash in an app ... joeymorin wrote: It is infrequently done, but 'never' is a long time. Agree with "perhaps unusual but not unheard of". I suppose one needs to put aside for the moment the merit of it? I well might determine in an app that it might be easier/more cost efficient/smaller footprint to e.g. get a bigger model of the AVR family versus adding e.g. external flash or EEPROM or similar storage chip. Atmel chose to put out an app note many years ago, with a sample application: Butterfly Logger: https://www.brokentoaster.com/bu... Doesn't ButtLoad store the ISP image into flash? Arduino discussions: (many) https://forum.arduino.cc/index.p... https://arduino.stackexchange.co... Prior discussions here: (many) https://www.avrfreaks.net/forum/... https://community.atmel.com/foru... https://www.avrfreaks.net/forum/... 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. Total votes: 0 AVATAR_Freaks wrote: skeeve wrote: An AVR's idea of the bootloader section depends on its fuses. The linker's idea of the .bootloader section depends on$(BOOT_START). Do they match? I 'm not sure how to check the fuses, any hint ? I am using a make file to compile . DO you mean BOOTSZ?
Yes.  Your IDE probably has a section for it somewhere.

If no IDE, avrdude can read them if you are not stuck with the wrong USB drivers.

The default bootloader section size is 0x1000 bytes.  Starts at 0x7000.

The smallest is 0x200 bytes.  Starts at 0x7E00.

If you place SPM at 0x7E00, the BOOTSZ bits won't matter.

Edit: correction

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

Last Edited: Fri. Oct 5, 2018 - 06:26 PM

skeeve wrote:
The smallest is 0x200 bytes. Starts at 0x7E00. If you place SPM at 0xFE00, the BOOTSZ bits won't matter.
Typo?

 "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]

joeymorin wrote:
Typo?

No, probably not.  App SPM writes must be from legal bootloader area, right?  So if (say) no bootloader, that would be  "safe" address irregardless of BOOTSZ fuse setting.

Note the reference to "fuse settings".  Lock bits and boot lock bits are a different matter.

[hmmm--on second thought one probably needs to pay attention to BLB...]

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: Fri. Oct 5, 2018 - 05:03 PM

But a 32K micro doesn't have flash at 0xFE00? That's up near the end of a 64K micro.
.
#1 mentions 32U4

Last Edited: Fri. Oct 5, 2018 - 05:37 PM

clawson wrote:

I wrote some words the other day (which turned out at the time to be misguided) about sharing bootloader functions to an application:

https://www.avrfreaks.net/commen...

You may find something of use there. The basic principle here is that the only piece of "shared knowledge" between the app code and the boot code is a 16 bit pointer passed from one to the other and also that each knows the order of entries in an array of function pointers (who's base address is passed as that 16 bit value). The actual routines in the boot code that are shared to the app can actually live anywhere in the bootloader space.

when i tried your method in the other form i came acorss this error

Severity	Code	Description	Project	File	Line
Error		ld returned 1 exit status	SNSBootloader	collect2.exe	0

I wonder why the compiler complained when I tried to have a pointer to the function (do_spm_N) ;

this is what I tried

typedef void(*P_do_spm_N)(void);
P_do_spm_N functions[]={
do_spm_N
};

and this

int main(void)
{

TCNT1 = &do_spm_N;
:
:
:
:
................

}

theusch wrote:

joeymorin wrote:
Typo?

No, probably not.  App SPM writes must be from legal bootloader area, right?  So if (say) no bootloader, that would be  "safe" address irregardless of BOOTSZ fuse setting.

Note the reference to "fuse settings".  Lock bits and boot lock bits are a different matter.

[hmmm--on second thought one probably needs to pay attention to BLB...]

yes but  0xFE00  way out of the boot section ,that wont work

joeymorin wrote:

skeeve wrote:
The smallest is 0x200 bytes. Starts at 0x7E00. If you place SPM at 0xFE00, the BOOTSZ bits won't matter.
Typo?

Yes, will edit, though the statement is true as is :-)

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

Last Edited: Fri. Oct 5, 2018 - 07:09 PM

clawson wrote:

I wrote some words the other day (which turned out at the time to be misguided) about sharing bootloader functions to an application:

https://www.avrfreaks.net/commen...

TCNT1 = &functions;

what did you use TCNT1 , it compiles but it doesn't allow me to load to the MC

sternst wrote:

So actually you have a bootloader and the function do_spm_N is part of it?

Then all this is nonsense:

...

All you need in the application is a correctly initialized function pointer:

void (*do_spm_N)(uint32_t address, uint8_t *data) = 0xXXXX;

I tried that but it still doesn't work

*Declare*do_spm_N in the application source.

"Define* it with the linker.  --define-symbol or something like that.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

skeeve wrote:

*Declare*do_spm_N in the application source.

"Define* it with the linker.  --define-symbol or something like that.

I am not sure how can I define a function in the linker ?

Never done that before ?

DO I need to do anything with the bit locks ?

the manual says the following

AVATAR_Freaks wrote:

skeeve wrote:

*Declare*do_spm_N in the application source.

"Define* it with the linker.  --define-symbol or something like that.

I am not sure how can I define a function in the linker ?

Never done that before ?

Define the symbol do_spm_N .

To find the correct value, look at the output of avr-nm bootloater.elf .

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

skeeve wrote:

AVATAR_Freaks wrote:

skeeve wrote:

*Declare*do_spm_N in the application source.

"Define* it with the linker.  --define-symbol or something like that.

I am not sure how can I define a function in the linker ?

Never done that before ?

Define the symbol do_spm_N .

To find the correct value, look at the output of avr-nm bootloater.elf .

What should I look for tho in the .elf file ?

AVATAR_Freaks wrote:
l i need to use the rest of my flash memory to save data

Static data?  i.e. known at compile time?  if so, then use flash keyword on your data array to store in flash

If dynamic, at run time, you do know the max writes to flash is about 10k times. i.e. if writing to only once per second, will only be usable for ~3 hours.

Jim

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

AVATAR_Freaks wrote:

skeeve wrote:

AVATAR_Freaks wrote:

skeeve wrote:

*Declare*do_spm_N in the application source.

"Define* it with the linker.  --define-symbol or something like that.

I am not sure how can I define a function in the linker ?

Never done that before ?

Define the symbol do_spm_N .

To find the correct value, look at the output of avr-nm bootloater.elf .

What should I look for tho in the .elf file ?

when I look at my .elf file I can't find do_SPM_N ???

I was looking at the linker ,

IS it okay that the .text and the .bootloader sets at the same address  location  ??

Address of section .text set to 0x7000

AVATAR_Freaks wrote:
I was looking at the linker ,
IS it okay that the .text and the .bootloader sets at the same address  location  ??
Only if one is empty.

Note that in the normal course of events, the bootloader's .text section is in the AVR's bootloader section.

The bootloader is a complete program.

If you wish to have your application use a function in the bootloader.

The application will have to know its address, hence avr-nm .

If you do not know the function's name, that would be a problem.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

skeeve wrote:

If you wish to have your application use a function in the bootloader.

The application will have to know its address, hence avr-nm .

If you do not know the function's name, that would be a problem.

Yes I know my function name, but when I run avr-nm I cant see my function, Hence I don't know the address ??

AVATAR_Freaks wrote:
Yes I know my function name, but when I run avr-nm I cant see my function, Hence I don't know the address ??
You sure that it is a function and not a macro?

If all else fails look at the bootloader's .lss file and look for the SPM instruction.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

Last Edited: Wed. Oct 10, 2018 - 06:37 PM

let me ask a simple question, I want to do a simple test

I would like to have a CONSTANT value in my boot loader at specific adress and read it from my application how can DO that ?

can I do somthin like

static uni32_t = 0x5a5a

how Can i read it from the application ?

AVATAR_Freaks wrote:

let me ask a simple question, I want to do a simple test

I would like to have a CONSTANT value in my boot loader at specific adress and read it from my application how can DO that ?

can I do somthin like

static uni32_t = 0x5a5a

how Can i read it from the application ?

In any case, the application needs the address.

If it's in flash, you have roughly the situation you have with do_spm_N.

You'll need LPM.

In-ram also works.

You will need to go through some contortions to ensure

neither code writes over it before the app reads it.

End of RAM is probably best.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

If you want to "share" a value from boot to app the best place to pass it is one of the SFRs. Modern AVRs have GPIOR0, GPIOR1, GPIOR2 for this purpose. Both "sides of the fence" already know the (unchanging) address of these storage locations.

Having said that you can actually use any (otherwise unused) SFR for this. In the past I have used TWAR and also TCNT1 as 8 or 16 bit registers that can just be used to pass some data.

clawson wrote:
f you want to "share" a value from boot to app the best place to pass it is one of the SFRs. Modern AVRs have GPIOR0, GPIOR1, GPIOR2 for this purpose. Both "sides of the fence" already know the (unchanging) address of these storage locations.
I'd thought they were wiped out by a watchdog reset.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

Nothing to stop the bootloader setting the register AFTER the WDT reset (assuming there even is one).

As I've shown elsewhere, if the boot wants to share a table of function pointers to make certain routines (UART, SPM etc) available to the app, so it can save some of its flash, then the boot can pass the 16 bit base address of the dispatch table in some "known place" such as a 16 bit SFR. This negates the need for app/boot to share "internal addresses" such as might happen if, otherwise, the bootloader decided to fix such a table at 0x7FF0 or something like that. The only "common thing" is that single 16 bit pointer and a shared knowledge of the order of entries in the function pointer array.

clawson wrote:

Nothing to stop the bootloader setting the register AFTER the WDT reset (assuming there even is one).

As I've shown elsewhere, if the boot wants to share a table of function pointers to make certain routines (UART, SPM etc) available to the app, so it can save some of its flash, then the boot can pass the 16 bit base address of the dispatch table in some "known place" such as a 16 bit SFR. This negates the need for app/boot to share "internal addresses" such as might happen if, otherwise, the bootloader decided to fix such a table at 0x7FF0 or something like that. The only "common thing" is that single 16 bit pointer and a shared knowledge of the order of entries in the function pointer array.

skeeve wrote:

clawson wrote:
f you want to "share" a value from boot to app the best place to pass it is one of the SFRs. Modern AVRs have GPIOR0, GPIOR1, GPIOR2 for this purpose. Both "sides of the fence" already know the (unchanging) address of these storage locations.
I'd thought they were wiped out by a watchdog reset.

Okay so my understanding is if I use one of the sfrs or GPIOR I can pass a value between the application and the bootloader right? I will try that.

BTW, MY bootloader based on the Catrerina Bootloader , with some editing to it.

SHould I put the bootloader here if you guys wanna take a look at it ?

If you want to "publish" code you are far better off doing it on github, Microchip "Spaces", or similar.

(actually I see that Sparkfun and Adafruit each already have versions of "Caterina" on github too).

clawson wrote:

If you want to "publish" code you are far better off doing it on github, Microchip "Spaces", or similar.

(actually I see that Sparkfun and Adafruit each already have versions of "Caterina" on github too).

Yes, I know I want to have as a reference. Have you ever used the caterina or went through it ?

I am just afraid that there is something in that code disabling SPM , because every time i try to use my own function from the application the board freezes.

Actually looking at the caterina, it uses

/* Undo TIMER1 setup and clear the count before running the sketch */
TIMSK1 = 0;
TCCR1B = 0;
TCNT1H = 0;        // 16-bit write to TCNT1 requires high byte be written first
TCNT1L = 0;
/

so I can't use TCNT1

AVATAR_Freaks wrote:
the application the board freezes.
This is why God invented ICE debuggers. I would never contemplate working on a bootloader without an ICE to see what's going on !

AVRs never really "freeze" (well not unless they execute the SLEEP opcode) so the likelihood is actually that it is held in some kind of conditional while() loop waiting for some even that never occurs. An ICE would let you break execution and find out where it is "stuck".

clawson wrote:
AVRs never really "freeze"...

My first job out of college, for a mainframe manufacturer, one of the first things I was taught "When the lights stop blinking, the computer stops thinking".

clawson wrote:
An ICE would let you break execution and find out where it is "stuck".

Set up the watchdog for interrupt mode.  When it fires, dig out the come-from address off of the stack and log to EEPROM or whatever.

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.

theusch wrote:
When it fires, dig out the come-from address off of the stack and log to EEPROM or whatever.
Me? I think I'd just buy an ICE (or I would if Atmel hadn't already sent me 3 or 4 - not to mention the ones on myriad Xplained bords they've also sent).

AVATAR_Freaks wrote:
so I can't use TCNT1

Sure you can, you will need to init T1 as you see fit to do.

All that code does is reset the T1 back to default values before running your sketch.

Jim

Edit:  Ok, I have no idea what happened to the message I was replying to ???

Never mind!

Edit2: found it msg# 51

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

Last Edited: Thu. Oct 11, 2018 - 04:04 PM

one more question , in the atmega32U4 manual

it says that the bootloader section from @ 0x3800 :0x3FFF,

but based on  my calculation it should be as follwoing

the flash size is 32k

flash ends = 32*1024 =0x8000

flash start = 32-4 = 28k = 28)1024= 0x7000

then It should be from 0x7000 to 0x8000

which is the right start location now ?

AVATAR_Freaks wrote:
the flash size is 32k

32k bytes, but flash is word addressed, =16k words!

Divide all byte address by 2.

Jim

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

ki0bk wrote:

AVATAR_Freaks wrote:
the flash size is 32k

32k bytes, but flash is word addressed, =16k words!

Divide all byte address by 2.

Jim

I did that , but now I can't load my arduino sketch to my board ?? it says

NO ACTUALLY I CAN't see the device in my device manager anymore , when i but the bootloader at 0x3800

what is the reason fro that?

Connecting to programmer: .avrdude: butterfly_recv(): programmer is not responding

ummmm

Last Edited: Thu. Oct 11, 2018 - 06:49 PM

OKay, so I looked into the im32u4.h that comes with the atmel software and the Flash end is defined as

#define FLASHEND     (0x7FFF)

this is confusing ??

AVATAR_Freaks wrote:
OKay, so I looked into the im32u4.h that comes with the atmel software and the Flash end is defined as

#define FLASHEND     (0x7FFF)

this is confusing ??

Don't know why.

32K = 0x8000 = FLASHEND+1

What is the problem?

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

NO ACTUALLY I CAN't see the device in my device manager anymore , when i but the bootloader at 0x3800

what is the reason fro that?

Which device?  Your ISP programmer?  Or the 32u4 as a USB-reachable bootloader?  If you've messed up the bootloader, you won't see it in the device manager.

 "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]

AFAICT, you never actually initialize the do_spm_N pointer to point at your actual function.

I'm not sure that you need to, if you're actually linking together your bootloader and application code (but then you shouldn't need a function pointer.)

The usual "problem" with calling functions in the bootloader from the application is that they are NOT "linked" together, and the application has no way of knowing exactly where in the bootloader section the "do_spm" function lives.

This is generally solved by putting a jump table at some "known absolute location" - usually at the very beginning of the bootloader section, or at the very end of memory.   For example, a do_spm() was added to Optiboot recently", and they put vectors at the beginning of the section:

void pre_main(void) __attribute__ ((naked)) __attribute__ ((section (".init8")));
void pre_main(void) {
// Allow convenient way of calling do_spm function - jump table,
//   so entry to this function will always be here, indepedent of compilation,
//   features etc
asm volatile (
"	rjmp	1f\n"
"	rjmp	do_spm\n"
"1:\n"
);
}

There's an example of using it at https://github.com/Optiboot/optiboot/tree/master/optiboot/examples/test_dospm

AVATAR_Freaks wrote:
this is confusing ??
The point is this. The granularity of opcodes in AVR is a minimum 16 bit pattern or multiple there of. Therefore Atmel, in their own documentation, always speak in terms of words for addresses and sizes. So a 32K (byte) chip has 16K words and in their scheme these are addressed as 0x0000..0x3FFFF but in byte terms that is 0x0000..0x7FFF

The GCC compiler and accompanying tools on the other hand is a generic compiler for a load of different micros and other CPUs. To have a common base it does EVERYTHING in terms of bytes. That is also true of all the addresses in all the ioXXX.h headers in AVR-LibC. That too uses BYTE addressing everywhere.

The confusion arises because Atmel have chosen to bundle GCC with their IDE so some parts are word-centric and some parts are byte-centric.

You possibly see this most clearly when you use the "Meomories" section in a project to set a flash address. Atmel invite you to entry the address as words so you may enter 0x1234 but when this is actually passed to the linker as -Wl,-section-start=.something=0x2468 where the 1234 values is seen to be doubled as Atmel have applied a word to byte conversion on it.

skeeve wrote:

You possibly see this most clearly when you use the "Meomories" section in a project to set a flash address. Atmel invite you to entry the address as words so you may enter 0x1234 but when this is actually passed to the linker as -Wl,-section-start=.something=0x2468 where the 1234 values is seen to be doubled as Atmel have applied a word to byte conversion on it.

Ohhh, they speak in terms of Words, but when it comes to programming then we program in terms of Bytes. Man thank you so much , now it all m make sense

Last Edited: Fri. Oct 12, 2018 - 12:35 PM

westfw wrote:

void pre_main(void) __attribute__ ((naked)) __attribute__ ((section (".init8")));
void pre_main(void) {
// Allow convenient way of calling do_spm function - jump table,
//   so entry to this function will always be here, indepedent of compilation,
//   features etc
asm volatile (
"	rjmp	1f\n"
"	rjmp	do_spm\n"
"1:\n"
);
}

There's an example of using it at https://github.com/Optiboot/optiboot/tree/master/optiboot/examples/test_dospm

Oka great you brough a very important point, that i have been wondering about for a while.

I don't understand what  asm  Volatile do or mean ? it seems so necerssary to have it

can you explain that in few details

You are wasting you time learning inline asm. While the manual covers it in some detail:

https://www.nongnu.org/avr-libc/...

There's almost always a better (or at least easier, equal) way to achieve the same thing so I wouldn't waste too much time on it.  The above, for example could just as easily have been written (much clearer in my opinion) as:

.section .init8

.extern do_spm
rjmp skip
rjmp do_spm
skip:

.section .text
do_spm:
SPM
ret

Put that into a .S file and build it along with the rest of the code. You get:

// main.c
#include <avr/io.h>

int main(void)
{
while(1);
}
// asm.S
.section .init8

.extern do_spm
rjmp skip
rjmp do_spm
skip:

.section .text
do_spm:
SPM
ret

When built this yields:

00000068 <__ctors_end>:
68:	11 24       	eor	r1, r1
6a:	1f be       	out	0x3f, r1	; 63
6c:	cf ef       	ldi	r28, 0xFF	; 255
6e:	d8 e0       	ldi	r29, 0x08	; 8
70:	de bf       	out	0x3e, r29	; 62
72:	cd bf       	out	0x3d, r28	; 61
.section .init8

.extern do_spm
rjmp skip
74:	01 c0       	rjmp	.+2      	; 0x78 <skip>
rjmp do_spm
76:	06 c0       	rjmp	.+12     	; 0x84 <do_spm>

00000078 <skip>:
78:	0e 94 44 00 	call	0x88	; 0x88 <main>
7c:	0c 94 49 00 	jmp	0x92	; 0x92 <_exit>

80:	0c 94 00 00 	jmp	0	; 0x0 <__vectors>

00000084 <do_spm>:
skip:

.section .text
do_spm:
SPM
84:	e8 95       	spm
ret
86:	08 95       	ret

00000088 <main>:
etc. etc.

The only time you need asm() is when something is SO timing critical you cannot afford the CALL/RET overhead to access it. Otherwise .S files are a MUCH easier answer.

PS I still don't understand why Bill would have you do this anyway? Sure that has put an "rjmp spm" at 0x0076 but with what intention? In fact, for my money I would have thought:

// asm.S
#include <avr/interrupt.h>
.global INT0_vect

INT0_vect:
SPM
ret

would be a better solution. This compiles to be:

00000000 <__vectors>:
0:	0c 94 34 00 	jmp	0x68	; 0x68 <__ctors_end>
4:	0c 94 40 00 	jmp	0x80	; 0x80 <__vector_1>
8:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt>
...
00000080 <__vector_1>:
#include <avr/interrupt.h>

.global INT0_vect

INT0_vect:
SPM
80:	e8 95       	spm
ret
82:	08 95       	ret

so I now have a "do_spm" always available at a a fixed start+0x0004 which can never be subject to change (because INT0 is not going anywhere!)

This does, of course, rely on the bootloader never wanting to use interrupts and specifically never wanting to use INT0.

OTOH maybe the whole thing is built with -nostartfiles anyway??

Last Edited: Fri. Oct 12, 2018 - 01:25 PM

clawson wrote:

// main.c
#include <avr/io.h>

int main(void)
{
while(1);
}
// asm.S
.section .init8

.extern do_spm
rjmp skip
rjmp do_spm
skip:

.section .text
do_spm:
SPM
ret

Okay i wanna try that, but I am new to assembly langague so take it easy on me ,then that for me should be ':-

// main.c
#include <avr/io.h>

int main(void)
{
while(1);
}

// asm.S
.section .init8

.extern do_spm_N
rjmp skip
rjmp do_spm_N
skip:

.section .text
do_spm_N:
SPM
ret

SO how can i added to my code when I build, do i uses something like include file, I build useing a makefile not the atmel studio.

what is "SPM" , and "ret" refer too?

The way I am suggesting you add Asm code to a mainly C project is to add a new source file. When you do AS7 offers you the option of creating an "Asm source" with a .s extension. Atmel have actually got this wrong it should have a .S extension so change the entire name offered to something like "myasm.S" and save. That adds a blank file (well a comment at the top) to your project. Make the first two lines:

#define __SFR_OFFSET 0
#include <avr/io.h>

then you write the Asm code after that. You'll need to learn AVR Asm first.

if you want to interact between Asm and C code then the Asm has to be written to follow the Application Binary Interface (ABI) of the GCC compiler. (things like first function parameter in R25 and R24 etc).

I don't think optippot works with atmega32u4 ... I tested it and it is not working

Surely if it's a 32U4 you want to use a DFU bootloader not a UART one like Optiboot?

(DFU = USB class for Device Firmware Update)

The whole point of buying a 32U4 is the USB so you might as well use it!

clawson wrote:

Surely if it's a 32U4 you want to use a DFU bootloader not a UART one like Optiboot?

(DFU = USB class for Device Firmware Update)

The whole point of buying a 32U4 is the USB so you might as well use it!

Yes true, that is exactly why choose it. I am using Caterina and the LUFA project together to take a advantage of the USB , and it came out very nice-except that the eeprom is too small for the data we need. so we trying to explore the idea of using the flash memory to save the data.

So Caterina is a USB based bootloader is it? If so then surely you can just make its own SPM functions visible to the app code and call those ?

clawson wrote:

So Caterina is a USB based bootloader is it? If so then surely you can just make its own SPM functions visible to the app code and call those ?

Yes it is

the problem with its SPM function is need special commands take a a look

{
uint16_t BlockSize;
char     MemoryType;

bool     HighByte = false;
uint8_t  LowByte  = 0;

BlockSize  = (FetchNextCommandByte() << 8);
BlockSize |=  FetchNextCommandByte();

MemoryType =  FetchNextCommandByte();

if ((MemoryType != 'E') && (MemoryType != 'F'))
{
/* Send error byte back to the host */
WriteNextResponseByte('?');

return;
}

/* Disable timer 1 interrupt - can't afford to process nonessential interrupts
* while doing SPM tasks */
TIMSK1 = 0;

/* Check if command is to read memory */
if (Command == 'g')
{
/* Re-enable RWW section */
boot_rww_enable();

while (BlockSize--)
{
if (MemoryType == 'F')
{
/* Read the next FLASH byte from the current FLASH page */
#if (FLASHEND > 0xFFFF)
#else
#endif

/* If both bytes in current word have been read, increment the address counter */
if (HighByte)

HighByte = !HighByte;
}
else
{
/* Read the next EEPROM byte into the endpoint */

/* Increment the address counter after use */
}
}
}
else
{

if (MemoryType == 'F')
{
boot_spm_busy_wait();
}

while (BlockSize--)
{
if (MemoryType == 'F')
{
/* If both bytes in current word have been written, increment the address counter */
if (HighByte)
{
/* Write the next FLASH word to the current FLASH page */
boot_page_fill(CurrAddress, ((FetchNextCommandByte() << 8) | LowByte));

/* Increment the address counter after use */
}
else
{
LowByte = FetchNextCommandByte();
}

HighByte = !HighByte;
}
else
{
/* Write the next EEPROM byte from the endpoint */

/* Increment the address counter after use */
}
}

/* If in FLASH programming mode, commit the page after writing */
if (MemoryType == 'F')
{
/* Commit the flash page to memory */

/* Wait until write operation has completed */
boot_spm_busy_wait();
}

/* Send response byte back to the host */
WriteNextResponseByte('\r');
}

/* Re-enable timer 1 interrupt disabled earlier in this routine */
TIMSK1 = (1 << OCIE1A);
}

Just isolate the call to boot_page_write() into a separate function and then you can also call that from your app code (if you can pass the address of where it is).

clawson wrote:

Just isolate the call to boot_page_write() into a separate function and then you can also call that from your app code (if you can pass the address of where it is).

that is exactly what I did for my do_spm_n function

uint16_t i;
uint8_t sreg;
char  w ;
w  =  "testing01234";
// Disable interrupts.
sreg = SREG;
cli();
eeprom_busy_wait ();
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 = *data++;
//w += (*data++) << 8;

}
boot_page_write (BMem_address);     // Store buffer in flash page.
boot_spm_busy_wait();       // Wait until the memory is written.
// Reenable RWW-section again. We need this if we want to jump back
boot_rww_enable ();
// Re-enable interrupts (if they were ever enabled).
SREG = sreg;

}
/**********

but every time i call the do_spm_N from my arduino sketch the rx and tx go solid yellow

Last Edited: Fri. Oct 12, 2018 - 05:49 PM

AVATAR_Freaks wrote:
the rx and tx go solid yellow
No idea what those are and how they are connected to the above code (which as far as I can see has nothing to control an LED??)

clawson wrote:

AVATAR_Freaks wrote:
the rx and tx go solid yellow
No idea what those are and how they are connected to the above code (which as far as I can see has nothing to control an LED??)

yes you are right, but  in the arduino sketch I use the erial port to communicate and send data here is the sketch

// this is the Arduino code, SPM.ino

#include"SPM.h"

void setup() {
// put your setup code here, to run once:
Serial.begin(9600);

}

void loop() {
byte data;

// Print current flash buffer content
if (Serial.available() > 0 ) {
switch (data) {

case 'n' :{

}
}
}
}

/****************************************************************/

// SPM.h

#include <avr/boot.h>

void (*do_spm_N)(uint32_t address)=0x7000; // this is the location , or what i think is the location
//

if you notice I don't print anything to the serial port, yet . this code is just for testing the do_spm_N . so when i send "n" on the serial port the app should call do_spm_N and write the data to the flash at location 0x6000. but the RX,TX led turn on solid  yellow , and doesn't turn off at all and I have to restart the board (arduino Micro Board)

Last Edited: Fri. Oct 12, 2018 - 06:14 PM
void (*do_spm_N)(uint32_t address)=0x7000; // this is the location , or what i think is the location

1) I highly doubt that this is the correct address. You can't "give" it an address from within the application (I already told you in #20 that all the .bootloader stuff in the OP is nonsense). For this function pointer approach you need to find out the actual address where the function got located in the bootloader.

2) For this function pointer approach you need to use the word address (again, I already told you that in #20).

Stefan Ernst

sternst wrote:

void (*do_spm_N)(uint32_t address)=0x7000; // this is the location , or what i think is the location

1) I highly doubt that this is the correct address. You can't "give" it an address from within the application (I already told you in #20 that all the .bootloader stuff in the OP is nonsense). For this function pointer approach you need to find out the actual address where the function got located in the bootloader.

remmeber we discussed that before, and we couldn't locate the exact address, but I know where the section .bootloader lives which at(0x7000) and the only thing in this section is do_spm_N,  so it has to be at 0x7000

sternst wrote:

2) For this function pointer approach you need to use the word address (again, I already told you that in #20).

What you mean us the word adress, fo yo mean something like that

OR "address" is already a defined  macro can be used in Ardino environment

AVATAR_Freaks wrote:
but I know where the section .bootloader lives which at(0x7000) and the only thing in this section is do_spm_N
But you wrote this:
AVATAR_Freaks wrote:
that is exactly what I did for my do_spm_n function

I can't see any relocation of the function there.

And you can't put it at 0x7000 (where the bootloader starts) anyway.

AVATAR_Freaks wrote:
What you mean us the word adress, fo yo mean something like that
No, I mean something like this:

void (*do_spm_N)(uint32_t address) = 0x7000 / 2;

(but again: 0x7000 is for sure not the correct address)

Stefan Ernst

I still don't understand why Bill would have you do this anyway? Sure that has put an "rjmp spm" at 0x0076 but with what intention? In fact, for my money I would have thought:

// asm.S
#include <avr/interrupt.h>
.global INT0_vect

INT0_vect:
SPM
ret

Well, first of all, I didn't write this code.  It was written by Marek Wodziński ("Majekw")  I just played "gatekeeper" on the official Optiboot page.

2nd, simple code like the above won't work because SPM requires those "timed write sequences" where you write some code to SPMCSR and then do the SPM within four clock cycles.  CALL is a 4-cycle instruction; I don't think it would work to have just the SPM be callable.

3rd, the way the code was originally written, it also replaced all of the uses of SPM within Optiboot itself, with some overall savings in code space requirements, but having it do "all the stuff that is ever needed, whether its needed or not."   (This wasn't retained - it conflicts with the desire to use avr-libc functions as often as possible, and we don't need the space at the moment.)

I should mention that the scheme with vectors in .init8 only results in "known locations" if you're also omitting the standard startup files ("-nostartfiles" in the link command.)  Otherwise the vectors end up being located after an "unknown" amount of startup code (as Clawson's sample asm listing showed.)  (this somewhat argues that the vectors should have gone at the end of flash, instead.  (too late now!  Sigh.))  (perhaps one of the other .initN sections would be better.)

[inline asm vs separate .S files]

We can probably blame the avr-libc authors for that.  There is lots of inline ASM in the boot.h file.

I'm not really convinced.  Use of ASM seems to three general cases:

1. very simple stuff, like insertion of a particular instruction.  (like these vectors, actually.)  Not much to learn, so I don't see why to avoid inline asm.
2. relatively complex stand-alone functions (say, like the soft-uart functions in optiboot.)  These would be a lot cleaner in their own .S file.
3. asm that interacts in complex ways with the C code (accessing local variables, maintaining register optimization, etc.)  Really annoying, and this is where you call up the tutorial on one page, while you write your code in another.

[no Optiboot for 32u4]

It's been requested, and even implemented: https://github.com/Optiboot/opti...

It has not been added, because Optiboot is a serial-only bootloader, and claiming 32u4 support would probably confuse more people (expecting it to work over USB) than it would help...

clawson wrote:

The way I am suggesting you add Asm code to a mainly C project is to add a new source file. When you do AS7 offers you the option of creating an "Asm source" with a .s extension. Atmel have actually got this wrong it should have a .S extension so change the entire name offered to something like "myasm.S" and save. That adds a blank file (well a comment at the top) to your project. Make the first two lines:

#define __SFR_OFFSET 0
#include <avr/io.h>

then you write the Asm code after that. You'll need to learn AVR Asm first.

if you want to interact between Asm and C code then the Asm has to be written to follow the Application Binary Interface (ABI) of the GCC compiler. (things like first function parameter in R25 and R24 etc).

I use a make file to build the projecy, how can i do that using make file