AVR-GCC. How to remove Interrupt table?

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

Hi,
I'm writing a bootloader (not interrupt driven) and need more program space.
I set the flag in the makefile not to generate Interrupts.. It does it, but don't removed the table.
Anyone an idea?

Andreas from Germany

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

Moin Andreas,

Try the -nostartfiles flag, as in:

CFLAGS = -g -O1 -mmcu=$(TARGET) -nostartfiles ...

Please note that you will have to manually clear and initialize your static variables after you add it, meaning more chances to save flash!

-John

- John

Last Edited: Tue. Aug 9, 2005 - 10:31 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmm... The Problem is, I've no stack now.... It's a bit difficult to programm without stack...
Andreas

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

Someone please correct me if I am wrong. The stack pointer is just another register or register pair: just set it or them to the last RAM address, RAMEND, before you use the stack.

- John

Last Edited: Tue. Aug 9, 2005 - 05:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I also believe that you won't have access to the 'zero' register.

R1 is preset to have a value of zero as part of the startup routine. Gcc then assumes that R1 will always be zero from then on. If you skip the startup sections, then you might end up with a couple of surprises if you try to make use of the numeric constant 'zero' in your code. So, you might also have to include special provisions to ensure that R1 is zero before you do anything else in your main() function.

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

I forgot about the zero register -- thank you for pointing that out! You can clear R1 in your start up code as you prepare to zero all the static variables (the bss segment). The cautiously paranoid might also have main() periodically clear R1 to address the nagging worry: What if zero accidently becomes non-zero?

- John

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

I have found a HACK to prevent the stack problem also just use:

COMMON_FLAGS  = -mmcu=$(CPU) -nostartfiles -minit-stack=0x4FF

Where 0x4FF is the end of the SRAM address to init the Stack pointer.
Also if you want to intialize some variables before main just do by:

void initvars(void) __attribute__ ((section(".init0")));
void initvars(void)
{
   //Your custome initialization before Main
}

But still the IVT remains. I am really not sure How to remove that.

AVR Rulez...;-)

Warm Regards,
Boseji
http://m8051.blogspot.com/

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

Hi,
One way to do this is to use your own linker script.

Copy the appropriate script from

../avr/lib/ldscripts/...

into your source directory.

Look for the .text section for example

.text :
{

and just before the .text line, place the following :

/DISCARD/ : { *(.vectors); } /* Interrupt vectors */

There may be a 'cleaner' way to do this than to take a copy of the
system linker script and editting it, if so I'd be interested to hear :)

-- Simon.

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

Oops I should have said that you need to tell the linker to actually use this
file when linking your application!!

Use the -T switch to gcc.

-- Simon.

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

The idea with adding .vectors to DISCARD is OK, but keep in mind that
the very first entry of .vectors is actually the jump to the program
entry. You might want to replace that by your own jump. As you're
going to use a custom linker script anyway, it should be easy enough
by inventing your own initialization section, and use that in place of
the original .vectors.

.section .myvectors,"ax",@progbits
RJMP __init

__init is the name of the entry point of the section .init0
initialization code. Of course, if you don't need/want the standard
initialization either, feel free to replace whatever parts seem
appropriate from the original crt code.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

If you don't wont to edit the linker script add

-nostartfiles -nodefaultlibs to LDFLAGS

and the following code to your bootloader module
(assuming you are not using static variables)

void __jumpMain     (void) __attribute__ ((naked)) __attribute__ ((section (".init9")));

void __jumpMain(void)
{    
    asm volatile ( ".set __stack, %0" :: "i" (RAMEND) );
    asm volatile ( "clr __zero_reg__" );        // r1 set to 0
    asm volatile ( "rjmp main");                   // jump to main()
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There was a little bit of glitch in this:

-nostartfiles -nodefaultlibs to LDFLAGS 

I made it to:

-nostartfiles -nodefaultlibs

Worked Fine and now from 300 bytes my codesize is 212 bytes only.
Thanks for the help.
Also I just wanted to ask where we can get the info for the avr-gcc flags and the info regarding the Linker Scripts.

AVR Rulez...;-)

Warm Regards,
Boseji
http://m8051.blogspot.com/

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

> Also I just wanted to ask where we can get the info for the avr-gcc
> flags

In the GCC manual and/or info pages. Some important options are also
explained in the avr-libc documentation.

> and the info regarding the Linker Scripts.

In the linker manual (info pages -- for WinAVR, see the TkInfo
browser).

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

I am also designing a bootloader... in this case an I2C bootloader.

So, I also want to discard the IVT generation... I am trying to follow these indications to create a new script file and discard the standard code with something custom... what I am doing is using the /DISCARD/ command to remove the (.vectors) section, but I am returning an error:

Quote:
C:\WinAVR\bin\..\lib\gcc\avr\3.4.5\..\..\..\..\avr\bin\ld.exe: `__vector_default' referenced in section `.text' of C:/WinAVR/bin/../lib/gcc/avr/3.4.5/../../../../avr/lib/avr5/crtm168.o: defined in discarded section `.vectors' of C:/WinAVR/bin/../lib/gcc/av
r/3.4.5/../../../../avr/lib/avr5/crtm168.o

The make files looks like this:

 ###############################################################################
# Makefile for the project i2cboot
###############################################################################

## General Flags
PROJECT = i2cboot
MCU = atmega168
TARGET = i2cboot.elf
CC = avr-gcc.exe

## Options common to compile, link and assembly rules
COMMON = -mmcu=$(MCU)

## Compile options common for all C compilation units.
CFLAGS = $(COMMON)
CFLAGS += -Wall -gdwarf-2       -DF_CPU=8000000UL  -O0 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d 

## Assembly specific flags
ASMFLAGS = $(COMMON)
ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2

## Linker flags
LDFLAGS = $(COMMON)
LDFLAGS += --verbose -Tavr5.x  -Wl,-Map=i2cboot.map


## Intel Hex file production flags
HEX_FLASH_FLAGS = -R .eeprom

HEX_EEPROM_FLAGS = -j .eeprom
HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"
HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0


## Objects that must be built in order to link
OBJECTS = main.o init.o 

## Objects explicitly added by the user
LINKONLYOBJECTS = 

## Build
all: $(TARGET) i2cboot.hex i2cboot.eep i2cboot.lss size

## Compile
main.o: ../main.c
	$(CC) $(INCLUDES) $(CFLAGS) -c  $<

init.o: ../init.c
	$(CC) $(INCLUDES) $(CFLAGS) -c  $<

##Link
$(TARGET): $(OBJECTS)
	 $(CC) $(LDFLAGS) $(OBJECTS) $(LINKONLYOBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET)

%.hex: $(TARGET)
	avr-objcopy -O ihex $(HEX_FLASH_FLAGS)  $< $@

%.eep: $(TARGET)
	avr-objcopy $(HEX_EEPROM_FLAGS) -O ihex $< $@

%.lss: $(TARGET)
	avr-objdump -h -S $< > $@

size: ${TARGET}
	@echo
	@avr-size -C --mcu=${MCU} ${TARGET}

## Clean target
.PHONY: clean
clean:
	-rm -rf $(OBJECTS) i2cboot.elf dep/* i2cboot.hex i2cboot.eep i2cboot.lss i2cboot.map


## Other dependencies
-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)

What am I doing wrong?

---
ARod

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

Hi,

I am enclosing my own boot loader make file. This file was auto generated
by the KamAVR and later I modified it to my needs.

################################################################################
################################################################################
##                                                                            ##
## NOTE:  This makefile uses GNU make syntax.                                 ##
## =====  It may not work when called by other make utilities                 ##
##                                                                            ##
################################################################################
################################################################################

################################################################################
###              ###############################################################
### PROJECT NAME ###############################################################
###              ###############################################################
################################################################################

PROJECT = dk1-boot

################################################################################
##     #########################################################################
## CPU #########################################################################
##     #########################################################################
################################################################################

CPU = atmega8

################################################################################
###         ####################################################################
### SOURCES ####################################################################
###         ####################################################################
################################################################################

OBJ  = bootprog.o

################################################################################
##       #######################################################################
## TOOLS #######################################################################
##       #######################################################################
################################################################################

COMPILER  = avr-gcc
ASSEMBLER = avr-gcc
LINKER    = avr-gcc
ROMIZER   = avr-objcopy
DUMPER    = avr-objdump

################################################################################
##       #######################################################################
## FLAGS #######################################################################
##       #######################################################################
################################################################################

COMMON_FLAGS  = -mmcu=$(CPU) -nostartfiles -nodefaultlibs
COMMON_FLAGS += -Os
COMMON_FLAGS += -mno-interrupts
COMMON_FLAGS += -funsigned-char
COMMON_FLAGS += -funsigned-bitfields
COMMON_FLAGS += -Wall
COMMON_FLAGS += -Wstrict-prototypes

LINK_FLAGS  = $(COMMON_FLAGS) -ggdb

COMPILE_FLAGS  = $(LINK_FLAGS) -c -DF_CPU=4000000UL
COMPILE_FLAGS += -Wa,-acdhlmns=$(<:.c=.lst)

ASSEMBLE_FLAGS  = $(COMMON_FLAGS) -c -I. -x assembler-with-cpp
ASSEMBLE_FLAGS += -Wa,-gstabs,-acdhlmns=$(<:.s=.lst)

EEPROM_FLAGS  = -j .eeprom
EEPROM_FLAGS += --change-section-lma .eeprom=0

FLASH_FLAGS  = -j .text
FLASH_FLAGS += -j .data
FLASH_FLAGS += -j .Topseg

ELF_FLAGS  = -Wl,-Map=$(PROJECT).map
ELF_FLAGS += -Wl,-section-start=.text=0x1800
ELF_FLAGS += -Wl,-section-start=.Topseg=0x0
ELF_FLAGS += --cref
ELF_FLAGS += -lm

################################################################################
##         #####################################################################
## ACTIONS #####################################################################
##         #####################################################################
################################################################################

COMPILE      = $(COMPILER) $(COMPILE_FLAGS)
ASSEMBLE     = $(ASSEMBLER) $(ASSEMBLE_FLAGS)
LINK         = $(LINKER) $(LINK_FLAGS)
REMOVE       = rm -f
SIZE1        = avr-size $(PROJECT).elf
SIZE2        = sh avr-mem.sh $(PROJECT).elf $(CPU)

################################################################################
##       #######################################################################
## BUILD #######################################################################
##       #######################################################################
################################################################################

all: elf flash eep list
	$(SIZE1)
	$(SIZE2)

rebuild: clean all

clean:
	$(REMOVE) $(PROJECT).hex
	$(REMOVE) $(PROJECT)_eeprom.hex
	$(REMOVE) $(PROJECT).elf
	$(REMOVE) $(PROJECT).map
	$(REMOVE) $(PROJECT).cof
	$(REMOVE) $(PROJECT).lst
	$(REMOVE) $(OBJ:.o=.lst)
	$(REMOVE) $(OBJ)

eep:     $(PROJECT)_eeprom.hex
flash:   $(PROJECT).hex
elf:     $(PROJECT).elf
list:    $(PROJECT).lst

################################################################################
##      ########################################################################
## LINK ########################################################################
##      ########################################################################
################################################################################

$(PROJECT)_eeprom.hex: $(PROJECT).elf
	$(ROMIZER) $(EEPROM_FLAGS) -O ihex $(PROJECT).elf $(PROJECT)_eeprom.hex

$(PROJECT).hex: $(PROJECT).elf
	$(ROMIZER) $(FLASH_FLAGS) -O ihex $(PROJECT).elf $(PROJECT).hex

$(PROJECT).lst: $(PROJECT).elf
	$(DUMPER) -d -S $(PROJECT).elf > $(PROJECT).lst

$(PROJECT).elf: $(OBJ)
	$(LINK) $(OBJ) -o $(PROJECT).elf $(ELF_FLAGS)

################################################################################
##         #####################################################################
## COMPILE #####################################################################
##         #####################################################################
################################################################################

%.o : %.c
	$(COMPILE) $< -o $@

%.o : %.s
	$(ASSEMBLE) $< -o $@

Hope that it is helpful to you.

Regards,

Boseji

AVR Rulez...;-)

Warm Regards,
Boseji
http://m8051.blogspot.com/

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

Hey thanks for sharing!!! :)

Also I just want to point out that I am using avrStudio4.12 SP2 and the gcc plug-in and all my development is done on it. Also I found that if I hit twice the Rebuild button, the second time the error disappear...

Boseji,
I will look at your Makefile to play with it... what it is interesting is that you don't need to use a modified ldscript version. ( avr5.x)... isn't it? meaning that I won't need to mess up with link scripts.. just the Makefile... awesome!

---
ARod

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

If I compile the code given by Peter Fleury the generated code locates statck initialisation to main() and not in __jumpMain(). So if I for example end __jumpMain with rjmp WinMain and rename main to WinMain there will be no stack initialisation.

Why isn't stack initialisation done in the C-startup code before main?

Olof

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

> Why isn't stack initialisation done in the
> C-startup code before main?

It is, look closely.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

This is the result::

main.elf:     file format elf32-avr

Disassembly of section .text:

00000000 <__jumpMain>:

void __jumpMain(void)
{
        asm volatile ( ".set __stack, %0" :: "i" (0x55aa) );
        asm volatile ( "clr __zero_reg__" );            // r1 set to 0
   0:   11 24           eor     r1, r1
        asm volatile ( "rjmp main");                            // jump to main(
)
   2:   00 c0           rjmp    .+0             ; 0x4

00000004 
: } int main( void ) { 4: ca ea ldi r28, 0xAA ; 170 6: d5 e5 ldi r29, 0x55 ; 85 8: de bf out 0x3e, r29 ; 62 a: cd bf out 0x3d, r28 ; 61 return 0; } c: 80 e0 ldi r24, 0x00 ; 0 e: 90 e0 ldi r25, 0x00 ; 0 10: 00 c0 rjmp .+0 ; 0x12 00000012 : void exit( int a ) { for(;;); // Lock forever in a loop. 12: ff cf rjmp .-2 ; 0x12

To me it is pretty clear that main starts at 4h. And that the stack pointer is initialised after 4h.

I appeded the example files used to produce the code.

Best regards

Olof

Attachment(s): 

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

Olof,

I just download your zip file, and I found the __stack declaration, also I compile it everything went ok... see the first code line after void __jumpMain(void) declaration.

---
ARod

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

To Olof or anybody,

dummy question!!!

what do I need to do to be able to link more that one file... in you case you have main.c but in my case I have to more files(main.c, twifsm.c and init.c), I have been playing with your makefile but I have failed to link more that 1 file.. =(

---
ARod

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

Been there, its a lable declaration not an assembly instruction. The real implementation is located at 4h and forward.

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

SRC = $(TARGET).c kallekaka.c and_so_on.c

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

Olof,

Thank you, I got it... I was changing the TARGET tag!!! :oops:

thanks again.

---
ARod

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

Old thread, but I have a question that may be appropriate here.

I am making a bootloader for a mega88, using WinAVR/AVR Studio.
https://www.avrfreaks.net/index.p...
All is going well, and am using the code above to rid myself of the interrupt vectors- https://www.avrfreaks.net/index.p...

It works, but I have program data (my string constants) that wants to go to the bootloader beginning (in my case 0x1800/0xC00). The map file shows '.progmem.data' at 1800 and '.init9' right after that. Any way to move the constant string data somewhere else? (By luck- it happens to work now because the string data just does some unneeded math on some registers before it reaches the rjmp to main).

Thanks!

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

I copied this post from another thread, so an answer not required here.

I think I found a solution to my .progmem.data problem.
problem-
https://www.avrfreaks.net/index.p...
(.progmem.data going before .init9 since using a method to get rid of vector table)

I found avr4.x in ldscripts directory, made a copy of it, 'moved' the .progmem lines (3 lines)that were just before .init0, and moved them to just after .init9, then in avr studio, to linker options I added -Wl,-TC:\WinAVR\avr\lib\ldscripts\avr4_bl.x , and the bootloader still works, with my string data now at 0x1804 with a clearing of r1, and an rjmp to main just before it.

I hope nothing catches on fire.

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

An old thread brought back to life:

I'm trying to write a custom interrupt vector table for Atmel Studio 6.1 using bits of information from this thread and #18 from this document:

blog.schicks.net/wp-content/uploads/2009/09/bootloader_faq.pdf

I have copied (in this case) the avr5.x linker script and added the DISCARD stuff. The new file mylinker.x is both in my /src/ folder and in the /ldscripts/ folder. I have added "-T mylinker.x" with and without absolute path to the Toolchain/AVR/GNU Linker/Miscellaneous field "Other Linker Flags", but AS build complains that "cannot open linker script file mylinker.x: No such file or directory". Changing to "-T avr5.h" returns the same error message.

I am also uncertain about where to place

.section .myvectors,"ax",@progbits
.global __vector_default
__vector_default:
jmp __init

I've tried putting it in an .h or an .s file in /src/ but I need to do something else/more.

It's probably a newbie problem, but could somebody please help me get this right?

Thanks in advance.

Niclas

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

Not sure why your linker script is not found but for the Asm code to do the reset jump, put it in a .S (not .s) file and that to the list of files to be built. avr-gcc should pass a .S file to avr-as to be assembled.

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

Thanks! Sorry for a dumb question, but where do I add "that to the list of files to be built"?

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

Well as you are using Studio 6 that would be in the list of source files for the project under solution explorer. Right click, add existing item and point to the .S file you have already created.

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

Thanks again. Now it seems to be working, even though I haven't completed the real code. I have combined the various input from this thread.

Here's what you need to do with AS6.1:

1. Copy the original linker file into your project. They are located here:
C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.2.939\avr8-gnu-toolchain\avr\lib\ldscripts
Somebody suggested that you temporarily rename this folder so that you get a build error telling you which linker file you should use. Otherwise, you can look at the files in the \lib\ directory. In my case it was avr5.x.

2. Add the path and file name (e.g. "-T ../src/mylinker.x") to Toolchain/AVR/GNU Linker/Miscellaneous/Other Linker Flags. The path should be relative to the project root.

3. Change your linker file like this:

  /* Internal text space or external memory.  */
  /DISCARD/ : { *(.vectors); } /* Discard standard vectors */
  .text   :
  {
    *(.myvectors)
    KEEP(*(.myvectors))

4. Add new assembler item e.g. to the project /src/ folder. According to clawson, it should be named your_vector_file.S (CAPITOL S).
My interrupt vector file that creates an almost empty IV contains:

.section .myvectors, "ax", @progbits
.global __vector_default
__vector_default:
jmp __init

Add your custom IV code here.

Thanks for helping me out. I hope this will be of value to other people.

/Niclas

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

Quote:

Somebody suggested that you temporarily rename this folder so that you get a build error telling you which linker file you should use.

Surely it's far easier to just make a "normal" build then look at the .map file that is generated? For example building for mega88A the top of the .map file has this:

c:/program files/atmel/atmel toolchain/avr8 gcc/native/3.4.2.939/avr8-gnu-toolchain/bin/../lib/gcc/avr/4.7.2/avr4\libgcc.a(_exit.o)
                              c:/program files/atmel/atmel toolchain/avr8 gcc/native/3.4.2.939/avr8-gnu-toolchain/bin/../lib/gcc/avr/4.7.2/../../../../avr/lib/avr4/crtm88a.o (exit)

The key thing in that is the locations of libgcc.a and crtm88a.o. Both are in ../avr4/ so the architecture of a mega88A is "avr4". Therefore in ldscripts:

C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.2.939\avr8-gnu-toolchain\avr\lib\ldscripts>dir *.x
 Volume in drive C has no label.
 Volume Serial Number is E0DD-96FE

 Directory of C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.2.939\avr8-gnu-toolchain\avr\lib\ldscripts

22/04/2013  15:25             6,600 avr1.x
22/04/2013  15:25             6,605 avr2.x
22/04/2013  15:25             6,606 avr25.x
22/04/2013  15:25             6,607 avr3.x
22/04/2013  15:25             6,608 avr31.x
22/04/2013  15:25             6,607 avr35.x
22/04/2013  15:25             6,605 avr4.x
22/04/2013  15:25             6,607 avr5.x
22/04/2013  15:25             6,608 avr51.x
22/04/2013  15:25             6,608 avr6.x
22/04/2013  15:25             6,085 avr7.x
22/04/2013  15:25             6,041 avrtiny.x
22/04/2013  15:25             6,610 avrxmega1.x
22/04/2013  15:25             6,610 avrxmega2.x
22/04/2013  15:25             6,610 avrxmega3.x
22/04/2013  15:25             6,610 avrxmega4.x
22/04/2013  15:25             6,610 avrxmega5.x
22/04/2013  15:25             6,610 avrxmega6.x
22/04/2013  15:25             6,610 avrxmega7.x
              19 File(s)        124,457 bytes

It is avr4.x that will be used.

Anyway to be honest what your post describes seems a bit pointless to me. What is the actual point of modifying the local copy of .x? All you have changed is:

  .text   :
  {
    *(.vectors)
    KEEP(*(.vectors))

to be:

  .text   :
  {
    *(.myvectors)
    KEEP(*(.myvectors)) 

so that you can use:

    .section .myvectors, "ax", @progbits
    .global __vector_default
__vector_default:
    jmp __init 

So what was actually wrong with simply using the Asm:

    .section .vectors, "ax", @progbits
    .global __vector_default
__vector_default:
    jmp __init 

and the default linker script so this code will locate to .vectors?

If you look at a bootloader I wrote:

http://spaces.atmel.com/gf/proje...

then look at the main.c file:

http://spaces.atmel.com/gf/proje...

have a read from line 82 onwards. In particular I do what you are doing here with the C code:

__attribute__((naked,section(".vectors"))) void start(void) {
    asm("rjmp main");
}	

That simply puts a jump at the reset address. No need for Asm code (well OK inline asm() is used) and no need for fiddling with linker scripts.

As the comments surrounding this tell you it does, of course, rely on -nostartfiles being used so the crt*.o code that would have provided a reset jump and vector table are not linked.

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

Hi,

You are missing the line that says:

/DISCARD/ : { *(.vectors); } /* Discard standard vectors */

The point of renaming .vector to .myvector was to eliminate the risk of a name conflict. Are you saying that if you include your own .vector it will replace the original one without having to DISCARD it? In other words: is it unnecessary to do this modification of the original avr5.x linker script and still supply your own .vector?

As I wrote at the beginning of my previous post, I haven't completed my code. I just posted a coherent and hopefully complete summary of what you could do to achieve this, while it's fresh in my memory.

What I am really trying to do is to place custom code in the IV space. My application will only use two USART receive interrupts, so with an ATxmega128A1 its almost 500 bytes of wasted space. In an attempt to only use one ISR prologue+epilogue I would rewrite the disassembly of my C code and fit it in manually using assembly.

Thanks for the references to the bootloader. I will take a look at it.

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

Quote:

The point of renaming .vector to .myvector was to eliminate the risk of a name conflict.

Name conflict from what? There is only one use of ".vectors" in standard avr-gcc code and that is in the crtXXX.o file which, for each device, provides a reset jump and vector table. If you use -nostartfiles (as you must for this to work anyway) you are saying "don't use crtXXXX.o" so there's no possibility of a name clash.
Quote:

Are you saying that if you include your own .vector it will replace the original one without having to DISCARD it?

Well apart from the fact that my own bootloader proves that this works, yes, I'm saying that the default linker script simply arranges for anything in the link that is in a section called ".vectors" to be placed at 0. If you have already told the linker "don't supply your stuff for .vectors" (that is -nostartfiles) then you are quite at liberty to tag any of your own code/data and say "I'd like this in ".vectors" please" and it will be positioned into that section and then the linker will place it at 0.

The only potential issue might be if you have two or more things flagged as being in .vectors. It's clearly important that the reset jump itself must locate to 0. But usually you'd just elect to have a single thing placed into .vectors (and hence to 0).

Quote:

In other words: is it unnecessary to do this modification of the original avr5.x linker script and still supply your own .vector?

This is what I'm saying. The linker script usefully already has the technology to guarantee that something will be placed at 0 (by listing .vectors first under .text) so just make use of that IFF you have also told the linker "don't supply your usual stuff that locates at 0". (ie -nostartfiles).
Quote:

so with an ATxmega128A1 its almost 500 bytes of wasted space

Intriguing that a few hundred bytes matter in a device that has 131,072 ;-)

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

It seems that we are talking about two different approaches.

Mine is largely based on this document:
blog.schicks.net/wp-content/uploads/2009/09/bootloader_faq.pdf
It is very similar to some of the previous posts in this thread. As they provide almost all information necessary, I added the missing details to my summary above. It achieves my goal without using "-nostartfiles", as I am quite happy with the compiler taking care of everything except the IV code. Just based on my quick implementation and disassembly it seems to do exactly what I want. In this case, I still think you should do as I summarized.

Your approach is based on "-nostartfiles" and manually providing all the things you opt-out of. I have seen bits and pieces of it while googling but it seemed like more work. Could I ask you to post a how-to on this approach, as I am sure it also has its merits? (Of course you can't have a name conflict in this situation.)

Yes, it might seem silly to try to save slightly less than half a percent of this mcu, but it's part of an investigation of how you can write more efficient programs. I'm also aware that the unused interrupts in the standard IV code points to an eternal loop for safety and debugging reasons.

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

Quote:

Mine is largely based on this document:

I know that document. See line 2 where it says: "with contributions and editing by Cliff Lawson"? I am Cliff Lawson.

I simply don't agree with Brad on the approach in question 18. He says:

Quote:
The cleanest way to replace the default vector table is with a custom linker script.

I just don't agree with that. Replacing the linker script is the act of last resort. I'm sure I told him that at the time when I was helping him create the document but he continued to suggest that approach. It's something I guess we'll have to agree to disagree with.

I just don't see what's wrong with -nostartfiles. When you look at gcrt1.S and the code it generates a small AVR a very small program:

#include 

int a_bss_var;
int a_data_var = 12345;

int main (void)
{
}

generates:

00000000 <__vectors>:
   0:	09 c0       	rjmp	.+18     	; 0x14 <__ctors_end>
   2:	21 c0       	rjmp	.+66     	; 0x46 <__bad_interrupt>
   4:	20 c0       	rjmp	.+64     	; 0x46 <__bad_interrupt>
   6:	1f c0       	rjmp	.+62     	; 0x46 <__bad_interrupt>
   8:	1e c0       	rjmp	.+60     	; 0x46 <__bad_interrupt>
   a:	1d c0       	rjmp	.+58     	; 0x46 <__bad_interrupt>
   c:	1c c0       	rjmp	.+56     	; 0x46 <__bad_interrupt>
   e:	1b c0       	rjmp	.+54     	; 0x46 <__bad_interrupt>
  10:	1a c0       	rjmp	.+52     	; 0x46 <__bad_interrupt>
  12:	19 c0       	rjmp	.+50     	; 0x46 <__bad_interrupt>

00000014 <__ctors_end>:
  14:	11 24       	eor	r1, r1
  16:	1f be       	out	0x3f, r1	; 63
  18:	cf e9       	ldi	r28, 0x9F	; 159
  1a:	cd bf       	out	0x3d, r28	; 61

0000001c <__do_copy_data>:
  1c:	10 e0       	ldi	r17, 0x00	; 0
  1e:	a0 e6       	ldi	r26, 0x60	; 96
  20:	b0 e0       	ldi	r27, 0x00	; 0
  22:	e2 e5       	ldi	r30, 0x52	; 82
  24:	f0 e0       	ldi	r31, 0x00	; 0
  26:	02 c0       	rjmp	.+4      	; 0x2c <__do_copy_data+0x10>
  28:	05 90       	lpm	r0, Z+
  2a:	0d 92       	st	X+, r0
  2c:	a0 36       	cpi	r26, 0x60	; 96
  2e:	b1 07       	cpc	r27, r17
  30:	d9 f7       	brne	.-10     	; 0x28 <__do_copy_data+0xc>

00000032 <__do_clear_bss>:
  32:	20 e0       	ldi	r18, 0x00	; 0
  34:	a0 e6       	ldi	r26, 0x60	; 96
  36:	b0 e0       	ldi	r27, 0x00	; 0
  38:	01 c0       	rjmp	.+2      	; 0x3c <.do_clear_bss_start>

0000003a <.do_clear_bss_loop>:
  3a:	1d 92       	st	X+, r1

0000003c <.do_clear_bss_start>:
  3c:	a0 36       	cpi	r26, 0x60	; 96
  3e:	b2 07       	cpc	r27, r18
  40:	e1 f7       	brne	.-8      	; 0x3a <.do_clear_bss_loop>
  42:	02 d0       	rcall	.+4      	; 0x48 
44: 04 c0 rjmp .+8 ; 0x4e <_exit> 00000046 <__bad_interrupt>: 46: dc cf rjmp .-72 ; 0x0 <__vectors> 00000048
: int a_bss_var; int a_data_var = 12345; int main (void) { } 48: 80 e0 ldi r24, 0x00 ; 0 4a: 90 e0 ldi r25, 0x00 ; 0 4c: 08 95 ret

Apart from the reset jump and the vector table the CRT supplies this:

  14:	11 24       	eor	r1, r1
  16:	1f be       	out	0x3f, r1	; 63
  18:	cf e9       	ldi	r28, 0x9F	; 159
  1a:	cd bf       	out	0x3d, r28	; 61

and then code to clear .bss (_do_clear_bss) and copy the .data initialisers from flash to RAM (_do_copy_data). Those first instructions are basically:

register uint8_t reg_r1 asm("r1");

int main(void) {
   r1 = 0;
   SREG = r1;
   SP = RAMEND;
}

In my own bootloader that I already linked to you can see I do:

    // because -nostartfiles is used there is no CRT so nothing to ensure R1=0, clear SREG
    // setup the stack pointer and so on. The following therefore replaces those things from
    // the standard CRT. Note there is no .data or .bss usage in this program so no need to 
    // duplicate those loops.
    myR1 = 0;
    SREG = myR1;
    SPH = RAMEND >> 8;
    SPL = RAMEND & 0xFF;

In fact I'm sure "SP = RAMEND" would have sufficed and I needn't split it into SPH/SPL in fact. I had previously setup "myR1" with:

register uint8_t myR1 asm("r1"); // just doing this so I can do the normal CRT stuff (R1=0, SREG=R1)

Then there's the _do_copy_data() and _do_clear_bss() loops.

You can either implement those or just avoid using .bss and .data - this is a bootloader after all so the code is likely to be small and simple.

If you do want to use .bss vars (and rely on them holding 0x00) a very simple way to clear BSS is actually to start by clearing ALL the RAM (in fact this what the CodeVision compiler's CRT does). Again in my code you can see something similar:

    // This is a debug thing - it's sometimes useful to flood RAM with a known value to make
    // it easier to see in the debugger exactly what has been written
#ifdef FLOOD_RAM
    for (uint16_t i=RAMSTART; i

I actually use that to flood RAM with a recognisable value such as 0xA5 but "FLOOD_VALUE" could just as easily be 0x00.

So all that remains is to implement the _do_copy_data loop. One way to do that if you are going to use initialised globals is to pay the price and initialise them at run time. For a few variables this will "cost" less than a setup loop and block of initial values. The next option would be to simply lift the code that does it from gcrt1.S or just do what it does in plain C code. It's doing pgm_read_bytes() of the flash between __data_load_start and __data_load_end and writing this to RAM between _edata and __data_end in RAM. So a for loop based on either of those pairs of bounds with the base of the other as the source or destination would do the job of _do_copy_data.

And that's all CRT does. So that's all you have to worry about implementing.

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

Later: OK so I put a bit more flesh on the bone:

#include 
#include 

int bss_var;
char bss_array[10];
int data_var = 12345;
char data_array[] = "Now is the time for all good men";

register uint8_t myR1 asm("r1");

extern int __bss_start;
extern int __bss_end;
extern int _etext;
extern int __data_start;
extern int __data_end;

int main (void)
{
    myR1 = 0;
    SREG = myR1;
    SP = RAMEND;
    
    for (uint8_t * p=(uint8_t *)&__bss_start; p < (uint8_t *)&__bss_end; p++) {
        *p = 0x00;
    }
    for (uint8_t * p=(uint8_t *)&_etext,  * q=(uint8_t *)&__data_start; q < (uint8_t *)&__data_end; p++, q++) {
        *q = pgm_read_byte(p);
    }
    PORTB = 0x55; // just test breakpoint
}

void __do_copy_data(void) {}
void __do_clear_bss(void) {}

That's an example with some .bss and .data variables (and I remembered to switch off linker garbage collection!). As far as I can see that does pretty much the equivalent of the CRT though I was not 100% sure whether the __??_end addresses were inclusive or not (however the right stuff got wiped/copied. It generates:

	.section	.text.startup.main,"ax",@progbits
.global	main
	.type	main, @function
main:
//==> {
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
//==>     myR1 = 0;
	clr r1
//==>     SREG = myR1;
	out __SREG__,__zero_reg__
//==>     SP = RAMEND;
	ldi r24,lo8(-97)
	out __SP_L__,r24
//==>     for (uint8_t * p=(uint8_t *)&__bss_start; p < (uint8_t *)&__bss_end; p++) {
	ldi r30,lo8(__bss_start)
	ldi r31,hi8(__bss_start)
	rjmp .L2
.L3:
//==>         *p = 0x00;
	st Z+,__zero_reg__
.L2:
//==>     for (uint8_t * p=(uint8_t *)&__bss_start; p < (uint8_t *)&__bss_end; p++) {
	ldi r24,hi8(__bss_end)
	cpi r30,lo8(__bss_end)
	cpc r31,r24
	brlo .L3
//==>     for (uint8_t * p=(uint8_t *)&__bss_start; p < (uint8_t *)&__bss_end; p++) {
	ldi r26,lo8(__data_start)
	ldi r27,hi8(__data_start)
	ldi r30,lo8(_etext)
	ldi r31,hi8(_etext)
	rjmp .L4
.L5:
//==>         *q = pgm_read_byte(p);
/* #APP */
 ;  27 ".././test.c" 1
	lpm r24, Z
	
 ;  0 "" 2
/* #NOAPP */
	st X+,r24
//==>     for (uint8_t * p=(uint8_t *)&_etext,  * q=(uint8_t *)&__data_start; q < (uint8_t *)&__data_end; p++, q++) {
	adiw r30,1
.L4:
//==>     for (uint8_t * p=(uint8_t *)&_etext,  * q=(uint8_t *)&__data_start; q < (uint8_t *)&__data_end; p++, q++) {
	ldi r24,hi8(__data_end)
	cpi r26,lo8(__data_end)
	cpc r27,r24
	brlo .L5
//==>     PORTB = 0x55;
	ldi r24,lo8(85)
	out 0x18,r24
//==> }
	ldi r24,0
	ldi r25,0
	ret
	.size	main, .-main

	.section	.text.__do_copy_data,"ax",@progbits
.global	__do_copy_data
	.type	__do_copy_data, @function
__do_copy_data:
//==> void __do_copy_data(void) {}
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
	ret
	.size	__do_copy_data, .-__do_copy_data

	.section	.text.__do_clear_bss,"ax",@progbits
.global	__do_clear_bss
	.type	__do_clear_bss, @function
__do_clear_bss:
//==> void __do_clear_bss(void) {}
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
	ret
	.size	__do_clear_bss, .-__do_clear_bss
.global	data_array

	.section	.data.data_array,"aw",@progbits
	.type	data_array, @object
	.size	data_array, 33
data_array:
	.string	"Now is the time for all good men"
.global	data_var

	.section	.data.data_var,"aw",@progbits
	.type	data_var, @object
	.size	data_var, 2
data_var:
	.word	12345
	.comm	bss_array,10,1
	.comm	bss_var,2,1
	.text
.Letext0:

or to put it another way:

Disassembly of section .text:

00000000 
: extern int __data_start; extern int __data_end; int main (void) { myR1 = 0; 0: 11 24 eor r1, r1 SREG = myR1; 2: 1f be out 0x3f, r1 ; 63 SP = RAMEND; 4: 8f e9 ldi r24, 0x9F ; 159 6: 8d bf out 0x3d, r24 ; 61 for (uint8_t * p=(uint8_t *)&__bss_start; p < (uint8_t *)&__bss_end; p++) { 8: e4 e8 ldi r30, 0x84 ; 132 a: f0 e0 ldi r31, 0x00 ; 0 c: 01 c0 rjmp .+2 ; 0x10 <__zero_reg__+0xf> *p = 0x00; e: 11 92 st Z+, r1 { myR1 = 0; SREG = myR1; SP = RAMEND; for (uint8_t * p=(uint8_t *)&__bss_start; p < (uint8_t *)&__bss_end; p++) { 10: 80 e0 ldi r24, 0x00 ; 0 12: e0 39 cpi r30, 0x90 ; 144 14: f8 07 cpc r31, r24 16: d8 f3 brcs .-10 ; 0xe <__zero_reg__+0xd> 18: a0 e6 ldi r26, 0x60 ; 96 1a: b0 e0 ldi r27, 0x00 ; 0 1c: ee e3 ldi r30, 0x3E ; 62 1e: f0 e0 ldi r31, 0x00 ; 0 20: 03 c0 rjmp .+6 ; 0x28 <__zero_reg__+0x27> *p = 0x00; } for (uint8_t * p=(uint8_t *)&_etext, * q=(uint8_t *)&__data_start; q < (uint8_t *)&__data_end; p++, q++) { *q = pgm_read_byte(p); 22: 84 91 lpm r24, Z 24: 8d 93 st X+, r24 SP = RAMEND; for (uint8_t * p=(uint8_t *)&__bss_start; p < (uint8_t *)&__bss_end; p++) { *p = 0x00; } for (uint8_t * p=(uint8_t *)&_etext, * q=(uint8_t *)&__data_start; q < (uint8_t *)&__data_end; p++, q++) { 26: 31 96 adiw r30, 0x01 ; 1 28: 80 e0 ldi r24, 0x00 ; 0 2a: a4 38 cpi r26, 0x84 ; 132 2c: b8 07 cpc r27, r24 2e: c8 f3 brcs .-14 ; 0x22 <__zero_reg__+0x21> *q = pgm_read_byte(p); } PORTB = 0x55; 30: 85 e5 ldi r24, 0x55 ; 85 32: 88 bb out 0x18, r24 ; 24 } 34: 80 e0 ldi r24, 0x00 ; 0 36: 90 e0 ldi r25, 0x00 ; 0 38: 08 95 ret
===============================================================================

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

Thanks Cliff for the extensive information.

I agree that this is safer, especially when version upgrading. It also gives you full freedom with regard to initialization. The downside is that for a newbie it's a bit to digest.

Would an "override" functionality be a safe mid-way? I.e. if you include a file with .vector it uses this instead of the default one? Then it couldn't be broken by version upgrades. (And similar for __do_copy_data, __do_copy_bss, and so on.)

I will take a good look at your instructions and experiment. Thanks again!

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

There is another alternative you're not considering which is even safer, especially when you start dealing with processors like the xmegas where depending on the size of program memory, you may be needing to deal with a program counter thats greater than 16 bits and things get a little bit different.

This is already ALL done for you in the crt1.S file and its about as optimal code as you could ever want to write. The IDE passes the needed symbolic information to all compiled programs so no matter what ATTiny...AtXMega processor you're compiling for, it comes out correctly.

As an aside, does anyone know what file the IDE keeps this symbolic information in thats passed to every compiled file through the C preprocessor? Can't believe this is hardcoded in the compiler but so far I haven't found it.

Where Atmel chooses not to provide you with the startup source code (which I wonder why for people who need to "roll their own" since its in the public domain anyway - gnu license), you can go to https://savannah.nongnu.org/proj... and click on the download button at the top and download the latest/greatest version of the libary there to get it.

What you need is "gcrt1.S" which is in the crt1 directory and the two include files "macros.inc" and "sectionname.h" which are in the common directory in the archive you download.

Now simply drop those into your AVR Studio project (or create a CRT1 sub-directory and drop them in there) and then add existing files (all 3 of them) to your project, select "nostartfiles" for the linker to prevent it from pasting in the C startup library as you now have your own custom version (or will shortly) and then edit your copy of crt1.s to suit your needs.

If you want the RAM clear and const data copy stuff, simply leave the first jump in the vector table section (since if you have any PROGMEM data the compiler will paste that into the Flash between the end of the vector table and the start of the initialization routines so you need the jump)and delete (or comment out) the remaining interrupt vectors in the list, save, compile, done!

If you want either or both of the initialization routines you can comment out (or delete) the code in the section(s) you don't want though I'd leave the sections headers themselves intact so the linker sees them in case there's a reason it needs to or perhaps should. It certainly hurts nothing to leave them there.

No need to reinvent the wheel. Its already been invented for you - just need to remove a few spokes is all (wink).

Once you have the files, this takes perhaps not even a couple minutes to do and for using the real initialization code the compiler uses, you know its correct.

Last Edited: Tue. Aug 5, 2014 - 10:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Where Atmel chooses not to provide you with the startup source code

They do - Morten posted a link recently to an open Git (or was it SVN) where Atmel's branch of AVR-LibC can be located.
Quote:

What you need is "crt1.S" which is in the crt1 directory

Err no the file is called gcrt1.S not just crt1.S
Quote:

As an aside, does anyone know what file the IDE keeps this symbolic information in thats passed to every compiled file through the C preprocessor? Can't believe this is hardcoded in the compiler but so far I haven't found it.

I'm not sure what "symbolic" information you are talking about but the compiler does have a fixed table built in (which is why it must be rebuilt for new models of AVR). See:

https://github.com/mirrors/gcc/b...

A typical line there is:

AVR_MCU ("atmega16", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATmega16__", 0x0060, 0x0, 1, "m16")

When the compiler builds for mega16 it passes "-mmcu=atmega16" on the command line and the entry in this table arranges for the symbol "__AVR_ATmega16__" to be defined as the code is compiled. A file such as then has:

#elif defined (__AVR_ATmega16__)
#  include 

and that's how the compiler "knows" which set of PORT/DDR/etc symbols to be used.

BTW you are responding to a thread from January - I fear the bird has flown ;-)