Hi all:
Thanks for the input.
I modified the original C-code and added in-line assembler directive "clr r1" to zero the r1 registers in the routines that used it in the resulting assembly listing.
I am explicitly executing push/pop before/after calling the routines ... that is after I looked over the resulting ASM listing to see which registers are being used.
As it turns out, to support single-character xmit/recv in Virtual Com (CDC) mode, only a few routines are needed so the "transmit a buffer" and "CDC control signals" routines are not needed. This cuts out nearly 1K of program space for a total memory footprint size of 1.5K bytes.
In the header file for the C-code, I am using the following macro def:
Code:
#undef PROGDATA
#define PROGDATA __attribute__ ((section (".progdata")))
Then for all the PROGMEM "data", I use something like:
Code:
const struct usb_string_descriptor_struct PROGDATA string1 = {
sizeof(STR_MANUFACTURER),
3,
STR_MANUFACTURER
};
I am not an "expert" at Makefiles, actually, not even "fluent" but I was able to modify the Makefile and do the following:
Code:
PROG_START = 0x6800 #PROGMEM code
PROGDATA_START = 0x6E00 #PROGMEM data
DATA_START = 0x800A80 #RAM variables
then passed the linker the following:
Code:
CDEFS += -DPROG_START_ADDR=$(PROG_START)UL
LDFLAGS += -Wl,--retain-symbols-file $(TARGET)-api.lst
LDFLAGS += -Wl,--no-gc-sections
LDFLAGS += -Wl,--section-start=.text=$(PROG_START) -nostartfiles -nodefaultlibs
LDFLAGS += -Wl,--section-start=.progdata=$(PROGDATA_START)
LDFLAGS += -Wl,--section-start=.data=$(DATA_START)
The contents of "$(TARGET)-api.lst" is just the names of each function I want access to, the interrupt vectors I want and the starting location of the code block, like so:
Code:
__ctors_start
usb_serial_init
usb_serial_configured
usb_serial_shutdown
usb_serial_getchar
usb_serial_available
usb_serial_flush_input
usb_serial_putchar
usb_serial_putchar_nowait
usb_serial_flush_output
__vector_10
__vector_11
I then parse the symbols and create a HEX file that I drop into my ASM "include directory" with this section in the Makefile. The "--gap-fill 0xFF" directive insures that the space between code and data in FLASH is filled with 0xFF so srec_cat doesn't complain and toss "ORG" statements into your ASM's include file.
Code:
# Create final output files (.hex, .eep) from ELF output file.
%.hex: %.elf
@echo
@echo $(MSG_FLASH) $@
$(OBJCOPY) -O $(FORMAT) --gap-fill 0xFF -R .eeprom -R .fuse -R .lock $< $@
# Create the include hex listing and subroutine pointers for use with the project.
%.inc:
@echo $(MSG_CREATING_INCLUDE) $< $@ at $(PROG_START)
@$(SREC) $(TARGET).hex -intel -offset -$(PROG_START) -o - -asm -HEXadecimal_STyle | \
$(SED) 's/ DB / .db/g' > $(INC_DIR)/Code_$(TARGET).inc
@$(CAT) $(TARGET).sym | $(SED) 's/ T / .equ /g' | \
$(SED) 's/0000/0x/g' | \
$(SED) 's/__vector_10/USB_GEN_int/g' | \
$(SED) 's/__vector_11/USB_COM_int/g' > temp.sym
@$(REMOVE) $(INC_DIR)/Defs_USBserial.inc
@$(CAT) temp.sym | while read ADDR SYMBOL ; do \
echo "$$SYMBOL = $$ADDR/2" >> $(INC_DIR)/Defs_USBserial.inc ; \
done
@$(REMOVE) temp.sym
GCC uses byte addresses whereas AVR ASM uses word addresses so I create an ".equ" value that is the "address / 2". I tried using the "bc" calculator to calculate the addresses on the fly before stuffing them in a definition file but I could not get that to work (at all). The resulting include file looks like this:
Code:
.equ __ctors_start = 0x6800/2
.equ usb_serial_init = 0x6806/2
.equ usb_serial_shutdown = 0x683a/2
.equ usb_serial_configured = 0x6856/2
.equ usb_serial_getchar = 0x685c/2
.equ usb_serial_available = 0x68a6/2
.equ usb_serial_flush_input = 0x68dc/2
.equ usb_serial_putchar = 0x6902/2
.equ usb_serial_putchar_nowait = 0x6988/2
.equ usb_serial_flush_output = 0x69ca/2
.equ USB_GEN_int = 0x69ec/2
.equ USB_COM_int = 0x6a62/2
I stick the follwoing at the bottom of the main ASM file so the library routines go in after my project's main code (the ".cseg" and ".org" insure that!):
Code:
;******************************************************************************
;USB Support
;******************************************************************************
#if ( defined(__ATmega32U4__) && (USB) )
.cseg
.org __ctors_start ;start of ROM code + data
.include "Include/Code_usb_serial.inc"
#endif
I have not yet figured out how to pull the addresses of the RAM-based variables from the symbol table, so I have added this in another include file:
Code:
#if ( defined(__ATmega32U4__) && (USB) )
.equ USB_SERIAL_RAM = 0x0A80 ;start of RAM variables
;
#if ( (FCLK != 8000000) && (FCLK != 16000000) )
#error "USB support is enabled, 8MHz or 16MHz clock only!"
#endif
#endif
and this in my "data defs" include file:
Code:
;=============================================================================
; USB Serial I/O support
;=============================================================================
#if ( defined(__ATmega32U4__) && (USB) )
USBtxBufr: .byte 64 ;TX buffer for USB
;
.org USB_SERIAL_RAM ;start of USB serial I/O RAM usage
cdc_line_coding: .byte 8
usb_configuration: .byte 1
cdc_line_rtsdtr: .byte 1
transmit_flush_timer: .byte 1
transmit_previous_timeout: .byte 1
usb_suspended: .byte 1
#endif
That pretty much covers it.
Hope that helps others.
Peace,
Scott |