Writting to FLash Memory

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

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 

#define BOOTLOADER_SECTION __attribute__ ((section(".bootloader"))) ;
:
:
:
:
...
static void do_spm_N (uint32_t address,  uint8_t *data) BOOTLOADER_SECTION;
:
:
:
:
......
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_page_erase (address);
    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_fill (address + i, w);
    }
    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
    // to the application after bootloading.
    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();
	}

}

2- Adding linker option in makefile

// 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
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What does the hex or nm say?

  • 1
  • 2
  • 3
  • 4
  • 5
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?

"For every Christmas tree lit before Thanksgiving,
an elf drowns a baby reindeer"

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

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
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

"Read a lot.  Write a lot."

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

 

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

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?

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

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
:1070E000AD0AF00100000102030111241FBECFEF21
:1070F000DAE0DEBFCDBF11E0A0E0B1E0E2E2FFE701
:1071000002C005900D92AE39B107D9F721E0AEE982
:10711000B1E001C01D92A73FB207E1F762D3FFC6FD
:107120006FCF84E08093E9008091E80085FD0DC079
:107130008091E8008B778093E8008091E80082FDE1

But what is "nm"?

Last Edited: Fri. Oct 5, 2018 - 12:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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
:1070E000AD0AF00100000102030111241FBECFEF21
:1070F000DAE0DEBFCDBF11E0A0E0B1E0E2E2FFE701
:1071000002C005900D92AE39B107D9F721E0AEE982
:10711000B1E001C01D92A73FB207E1F762D3FFC6FD
:107120006FCF84E08093E9008091E80085FD0DC079
:107130008091E8008B778093E8008091E80082FDE1

But what is "nm"?

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

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 

 

 

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

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 

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

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
  • 1
  • 2
  • 3
  • 4
  • 5
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).

  • 1
  • 2
  • 3
  • 4
  • 5
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 

 

  • 1
  • 2
  • 3
  • 4
  • 5
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.

  • 1
  • 2
  • 3
  • 4
  • 5
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?

static void (*do_spm_N)(uint32_t address,  uint8_t *data)__attribute__ ((section(".bootloader"))) ;

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

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

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
    \def BOOTLOADER_SECTION

    Used to declare a function or variable to be placed into a
    new section called .bootloader. This section and its contents
    can then be relocated to any address (such as the bootloader
    NRWW area) at link-time. */

#define BOOTLOADER_SECTION    __attribute__ ((section (".bootloader")))

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

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

 

:10     7000  00    74C000008DC000008BC0000089C00000 6B
length  addr  type  data                             checksum 

 

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 ? 

 

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

sternst wrote:

I am confused about your general setup.

static void (*do_spm_N)(uint32_t address,  uint8_t *data)__attribute__ ((section(".bootloader"))) ;

 

 

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:-

static void (*do_spm_N)(uint32_t address,  uint8_t *data)__attribute__ ((section(".bootloader"))) ; --> in application 

[

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 :)

 

 

 

 

 

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

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

#define BOOTLOADER_SECTION    __attribute__ ((section (".bootloader")))

 

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?

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

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

 

Then all this is nonsense:

#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)
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

  • 1
  • 2
  • 3
  • 4
  • 5
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.

  • 1
  • 2
  • 3
  • 4
  • 5
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.

  • 1
  • 2
  • 3
  • 4
  • 5
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

 

"For every Christmas tree lit before Thanksgiving,
an elf drowns a baby reindeer"

Last Edited: Fri. Oct 5, 2018 - 06:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

"Read a lot.  Write a lot."

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

 

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

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 devildifferent 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
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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		section .bootloader loaded at [00007000,00007001] overlaps section .text loaded at [00007000,00007f67]	SNSBootloader		1
Error		recipe for target 'Caterina.elf' failed	SNSBootloader	C:\Users\bghobreal\Documents\Atmel Studio\7.0\SNSBootloader\SNSBootloader\Makefile	652
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


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

and this 

 void do_spm_N (void)BOOTLOADER_SECTION;


int main(void)
{
	
	    TCNT1 = &do_spm_N;
	    :
	    :
	    :
	    :
	    ................
	    
}

 

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

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 devildifferent 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 

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

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 :-)

"For every Christmas tree lit before Thanksgiving,
an elf drowns a baby reindeer"

Last Edited: Fri. Oct 5, 2018 - 07:09 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

 

 

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

sternst wrote:

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

 

Then all this is nonsense:

#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)
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.

 

I tried that but it still doesn't work 

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

*Declare*do_spm_N in the application source.

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

"For every Christmas tree lit before Thanksgiving,
an elf drowns a baby reindeer"

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

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 ?

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

DO I need to do anything with the bit locks ?

the manual says the following 

 

 

 

 

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

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 .

"For every Christmas tree lit before Thanksgiving,
an elf drowns a baby reindeer"

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

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 ?

 

 

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

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!

share.robinhood.com/jamesc3274

 

 

 

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

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 ???

 

 

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

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
Address of section .bootloader set to 0x7000

 

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

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.

"For every Christmas tree lit before Thanksgiving,
an elf drowns a baby reindeer"

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

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 ??

 

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

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.

If your bootloader lacks an SPM, it won't work.

"For every Christmas tree lit before Thanksgiving,
an elf drowns a baby reindeer"

Last Edited: Wed. Oct 10, 2018 - 06:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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 ?

 

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

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 ?

 

You have your syntax wrong.

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.

"For every Christmas tree lit before Thanksgiving,
an elf drowns a baby reindeer"

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

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.

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

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.

"For every Christmas tree lit before Thanksgiving,
an elf drowns a baby reindeer"

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

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.

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

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 ?

 

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

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).

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

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.

 

 

 

 

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

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

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

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

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

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.

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

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).

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

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!

share.robinhood.com/jamesc3274

 

 

 

Last Edited: Thu. Oct 11, 2018 - 04:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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 ?

 

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

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!

share.robinhood.com/jamesc3274

 

 

 

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

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
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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 ??

 

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

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?

"For every Christmas tree lit before Thanksgiving,
an elf drowns a baby reindeer"

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

You're still getting confused between byte-addresses and word-addresses.

 

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

"Read a lot.  Write a lot."

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

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
static void (*do_spm_N)(uint32_t address,  uint8_t *data)__attribute__ ((section(".bootloader"))) ;

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

 

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

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.

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

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
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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 

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

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>

00000080 <__bad_interrupt>:
  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
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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? 

 

 

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

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).

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

 

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

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

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!

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

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. 

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

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 ?

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

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 

static void ReadWriteMemoryBlock(const uint8_t Command)
{
	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)
				WriteNextResponseByte(pgm_read_byte_far(CurrAddress | HighByte));
				#else
				WriteNextResponseByte(pgm_read_byte(CurrAddress | HighByte));
				#endif

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

				HighByte = !HighByte;
			}
			else
			{
				/* Read the next EEPROM byte into the endpoint */
				WriteNextResponseByte(eeprom_read_byte((uint8_t*)(intptr_t)(CurrAddress >> 1)));

				/* Increment the address counter after use */
				CurrAddress += 2;
			}
		}
	}
	else
	{
		uint32_t PageStartAddress = CurrAddress;

		if (MemoryType == 'F')
		{
			boot_page_erase(PageStartAddress);
			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 */
					CurrAddress += 2;
				}
				else
				{
					LowByte = FetchNextCommandByte();
				}
				
				HighByte = !HighByte;
			}
			else
			{
				/* Write the next EEPROM byte from the endpoint */
				eeprom_write_byte((uint8_t*)((intptr_t)(CurrAddress >> 1)), FetchNextCommandByte());

				/* Increment the address counter after use */
				CurrAddress += 2;
			}
		}

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

			/* 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);
}

 

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

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).

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

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

void do_spm_N (uint32_t BMem_address){
	uint16_t i;
    uint8_t sreg;
	char  w ;
	w  =  "testing01234";
    // Disable interrupts.
    sreg = SREG;
    cli();
    eeprom_busy_wait ();
    boot_page_erase (BMem_address);
    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_fill (BMem_address + i, w);
    }
    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
    // to the application after bootloading.
    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
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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??)

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

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;

    uint32_t Read_Ptr = 0x6000;

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

            case 'n' :{
               do_spm_N(Read_Ptr);

          }
   }
  }
}

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

// 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
// this comes from the .booloader  at the linker
//

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
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
void (*do_spm_N)(uint32_t address)=0x7000; // this is the location , or what i think is the location
// this comes from the .booloader  at the linker

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

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

sternst wrote:

void (*do_spm_N)(uint32_t address)=0x7000; // this is the location , or what i think is the location
// this comes from the .booloader  at the linker

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 

#define address= 0x7000;

void (*do_spm_N)(uint32_t address)=address;

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

 

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

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

 void do_spm_N (uint32_t BMem_address){

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

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

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...

 

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

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

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

clawson wrote:
PS I still don't understand why Bill would have you do this anyway?

I'm missing something.  Is "Bill" one of the players in this comic tragedy?

 

Mr. Bill:

 

Red Green's "Adventures with Bill":