AVR ATtiny814 program executes first function, ignoring main - c

I'm trying to write software for an ATtiny814 (tiny avr 1-series) microcontroller, but I encounter a strange problem: whatever the first function in main.c is, gets executed and the remaining code gets ignored - including the main() function.
I'm using the avr-toolchain from the Arduino IDE on macOS, but I'm not using the IDE, I just added the bin/ directory of the avr-toolchain to the PATH variable. The code just compiles fine without errors or warnings. Using pyupdi I can successfully flash the program to the chip, and again it works fine - except that only code from the first function in the main.c is executed.
Makefile:
TARGET = project
CLOCK = 2000000 # configured in main
SOURCES = main.c
OBJECTS = $(SOURCES:.c=.o)
COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -D__AVR_DEVICE_NAME__=attiny814 -D__AVR_DEV_LIB_NAME__=tn814
# compiling and linking, target is the finished hex file
all: $(TARGET).hex
# compile source files to object files
.c.o:
$(COMPILE) -c $< -o $#
# link the object files together
$(TARGET).elf: $(OBJECTS)
$(COMPILE) $(OBJECTS) -o $(TARGET).elf
# convert elf file to hex file
$(TARGET).hex: $(TARGET).elf
avr-objcopy -O ihex -j .data -j .text $(TARGET).elf $(TARGET).hex
clean:
rm -f $(TARGET).hex $(TARGET).elf $(OBJECTS)
Example 1
main.c:
#include <avr/io.h>
void test1() {
// turn on PB1
PORTB.DIR |= PIN1_bm;
PORTB.OUT |= PIN1_bm;
}
int main() {
// disable protection to configure clock frequency
CCP = CCP_IOREG_gc;
// configure CPU frequency
CLKCTRL.MCLKCTRLA = CLKCTRL_CLKSEL_OSC20M_gc; // use 20 MHz internal clock as source
CLKCTRL.MCLKCTRLB = CLKCTRL_PDIV_10X_gc | CLKCTRL_PEN_bm; // divide by 10 and enable divider
// turn on PB0
PORTB.DIR |= PIN0_bm;
PORTB.OUT |= PIN0_bm;
// main program loop
while(1) {};
return 0;
}
Here, only test1() is executed, as only PB1 turns on.
Example 2
main.c:
#include <avr/io.h>
// prototype
void test1();
int main() {
// disable protection to configure clock frequency
CCP = CCP_IOREG_gc;
// configure CPU frequency
CLKCTRL.MCLKCTRLA = CLKCTRL_CLKSEL_OSC20M_gc; // use 20 MHz internal clock as source
CLKCTRL.MCLKCTRLB = CLKCTRL_PDIV_10X_gc | CLKCTRL_PEN_bm; // divide by 10 and enable divider
// turn on PB0
PORTB.DIR |= PIN0_bm;
PORTB.OUT |= PIN0_bm;
// main program loop
while(1) {};
return 0;
}
void test1() {
// turn on PB1
PORTB.DIR |= PIN1_bm;
PORTB.OUT |= PIN1_bm;
}
Here, main() gets skipped and again test1() is executed, turning PB1 on.
Example 3
main.c:
#include <avr/io.h>
void test0() {
// turn on PB0
PORTB.DIR |= PIN0_bm;
PORTB.OUT |= PIN0_bm;
}
void test1() {
// turn on PB1
PORTB.DIR |= PIN1_bm;
PORTB.OUT |= PIN1_bm;
}
No main function at all. No compiler errors. Only test0() gets executed and PB0 turns on.
I have no clue whats going on here. Btw, using the same avr-toolchain setup, I can write software for an ATtiny841 (it's a different architecture/series) as expected.

Okay, found a solution: When I compile it as described here https://github.com/vladbelous/tinyAVR_gcc_setup#example-of-compiler-usage, it works.
So in my case:
avr-gcc -c -Os -DF_CPU=2000000 -mmcu=attiny814 main.c
avr-gcc -mmcu=attiny814 -o main.elf main.o
avr-objcopy -j .text -j .data -j .rodata -O ihex main.elf main.hex
Fixed Makefile:
TARGET = project
MCU = attiny814
DEVICE = tiny814
# clock settings applied in main.c
CLOCK = 2000000
PROGRAMMER = /dev/tty.usbserial-A50285BI
SOURCES = main.c
OBJECTS = $(SOURCES:.c=.o)
COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(MCU)
# compiling and linking, target is the finished hex file
all: $(TARGET).hex
# compile source files to object files
.c.o:
$(COMPILE) -c $< -o $#
# link the object files together
$(TARGET).elf: $(OBJECTS)
$(COMPILE) $(OBJECTS) -o $(TARGET).elf
# convert elf file to hex file
$(TARGET).hex: $(TARGET).elf
avr-objcopy -j .text -j .data -j .rodata -O ihex $(TARGET).elf $(TARGET).hex
# flash (call make flash), requires pyupdi installed
flash: $(TARGET).hex
python3 -m updi.pyupdi -d $(DEVICE) -c $(PROGRAMMER) -f "$(shell pwd)/$(TARGET).hex"
clean:
rm -f $(TARGET).hex $(TARGET).elf $(OBJECTS)

Related

makefile error in c project multiple definitions [duplicate]

This question is a repex created corresponding to this problem.
In my embedded C project I have two separate boards and I want to create two .c files (master.c and slave.c) for each board containing their own specific main() function.
I've used stm32cumbemx to generate the project with main.c, makefile and other sources and headers (I want to replace main.c with master.c and slave.c manually).
this is the folder structure of the project (I deleted slave.c for simplicity):
.
├── Inc
│   └── main.h
├── Makefile
├── Src
│   ├── main.c
│   └── master.c
└── STM32F103RBTx_FLASH.ld
main.h:
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
main.c:
#include "main.h"
int variable = 1;
void function(void);
int main() {
variable += 1;
while(1){}
}
void function(void) {
int something = 0;
something++;
}
master.c:
#include "main.h"
int variable = 1;
int variable2;
void function(void);
void function2(void);
int main() {
variable += 1;
while(1){
function2();
}
}
void function(void) {
int something = 0;
something++;
}
void function2(void) {
variable2++;
}
STM32F103RBTx_FlASH.ld:
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20005000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
and makefile (the parts I added to pre-generated file are between #edit begin and #edit end comments:
TARGET = myproject
#edit begin
MASTER = master
SLAVE = slave
#edit end
DEBUG = 1
# optimization
OPT = -Og
BUILD_DIR = build
# C sources
C_SOURCES = \
Src/main.c
#edint begin
SLAVE_SOURCES = \
Src/slave.c
MASTER_SOURCES = \
Src/master.c \
#edit end
PREFIX = arm-none-eabi-
# The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx)
# either it can be added to the PATH environment variable.
ifdef GCC_PATH
CC = $(GCC_PATH)/$(PREFIX)gcc
AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp
CP = $(GCC_PATH)/$(PREFIX)objcopy
SZ = $(GCC_PATH)/$(PREFIX)size
else
CC = $(PREFIX)gcc
AS = $(PREFIX)gcc -x assembler-with-cpp
CP = $(PREFIX)objcopy
SZ = $(PREFIX)size
endif
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S
CPU = -mcpu=cortex-m3
# fpu
# NONE for Cortex-M0/M0+/M3
# float-abi
# mcu
MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)
# macros for gcc
# AS defines
AS_DEFS =
# C defines
C_DEFS = \
-DUSE_HAL_DRIVER \
-DSTM32F103xB
# AS includes
AS_INCLUDES =
# C includes
C_INCLUDES = \
-IInc \
# compile gcc flags
ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
CFLAGS = $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
ifeq ($(DEBUG), 1)
CFLAGS += -g -gdwarf-2
endif
# Generate dependency information
CFLAGS += -MMD -MP -MF"$(#:%.o=%.d)"
# link script
LDSCRIPT = STM32F103RBTx_FLASH.ld
# libraries
LIBS = -lc -lm -lnosys
LIBDIR =
LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections
# default action: build all
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
#edit begin
master: $(BUILD_DIR)/$(MASTER).elf $(BUILD_DIR)/$(MASTER).hex $(BUILD_DIR)/$(MASTER).bin
slave: $(BUILD_DIR)/$(SLAVE).elf $(BUILD_DIR)/$(SLAVE).hex $(BUILD_DIR)/$(SLAVE).bin
#edit end
#######################################
# build the application
#######################################
# list of objects
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(C_SOURCES)))
# list of ASM program objects
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))
vpath %.s $(sort $(dir $(ASM_SOURCES)))
$(info OBJECTS is $(OBJECTS))
#edit begin
MASTER_OBJ = $(addprefix $(BUILD_DIR)/,$(notdir $(MASTER_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(MASTER_SOURCES)))
$(info MASTER_OBJ is $(MASTER_OBJ))
MASTER_OBJ += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))
vpath %.s $(sort $(dir $(ASM_SOURCES)))
#edit end
$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $#
$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
$(AS) -c $(CFLAGS) $< -o $#
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
$(CC) $(OBJECTS) $(LDFLAGS) -o $#
$(SZ) $#
#edit begin
$(BUILD_DIR)/$(MASTER).elf: $(MASTER_OBJ) Makefile
$(CC) $(MASTER_OBJ) $(LDFLAGS) -o $#
$(SZ) $#
$(BUILD_DIR)/$(SLAVE).elf: $(SLAVE_OBJ) Makefile
$(CC) $(SLAVE_OBJ) $(LDFLAGS) -o $#
$(SZ) $#
#edit end
$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
$(HEX) $< $#
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
$(BIN) $< $#
$(BUILD_DIR):
mkdir $#
clean:
-rm -fR $(BUILD_DIR)
-include $(wildcard $(BUILD_DIR)/*.d)
# *** EOF ***
resutlt of sudo make in terminal:
OBJECTS is build/main.o
MASTER_OBJ is build/master.o
mkdir build
arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb -DUSE_HAL_DRIVER -DSTM32F103xB -IInc -Og -Wall -fdata-sections -ffunction-sections -g -gdwarf-2 -MMD -MP -MF"build/main.d" -Wa,-a,-ad,-alms=build/main.lst Src/main.c -o build/main.o
arm-none-eabi-gcc build/main.o -mcpu=cortex-m3 -mthumb -specs=nano.specs -TSTM32F103RBTx_FLASH.ld -lc -lm -lnosys -Wl,-Map=build/myproject.map,--cref -Wl,--gc-sections -o build/myproject.elf
arm-none-eabi-size build/myproject.elf
text data bss dec hex filename
88 8 1568 1664 680 build/myproject.elf
arm-none-eabi-objcopy -O ihex build/myproject.elf build/myproject.hex
arm-none-eabi-objcopy -O binary -S build/myproject.elf build/myproject.bin
as you see the code compiles with no errors.
and result of sudo make master (after running sudo make clean):
MASTER_OBJ is build/master.o
mkdir build
arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb -DUSE_HAL_DRIVER -DSTM32F103xB -IInc -IDrivers/STM32F1xx_HAL_Driver/Inc -IDrivers/STM32F1xx_HAL_Driver/Inc/Legacy -IDrivers/CMSIS/Device/ST/STM32F1xx/Include -IDrivers/CMSIS/Include -Og -Wall -fdata-sections -ffunction-sections -g -gdwarf-2 -MMD -MP -MF"build/master.d" -Wa,-a,-ad,-alms=build/master.lst Src/master.c -o build/master.o
arm-none-eabi-gcc build/master.o -mcpu=cortex-m3 -mthumb -specs=nano.specs -TSTM32F103RBTx_FLASH.ld -lc -lm -lnosys -Wl,-Map=build/dual-interface.map,--cref -Wl,--gc-sections -o build/master.elf
c:/program files (x86)/gnu arm embedded toolchain/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: warning: cannot find entry symbol Reset_Handler; defaulting to 08000000
arm-none-eabi-size build/master.elf
text data bss dec hex filename
88 8 1568 1664 680 build/master.elf
arm-none-eabi-objcopy -O ihex build/master.elf build/master.hex
arm-none-eabi-objcopy -O binary -S build/master.elf build/master.bin
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -DUSE_HAL_DRIVER -DSTM32F103xB -IInc -IDrivers/STM32F1xx_HAL_Driver/Inc -IDrivers/STM32F1xx_HAL_Driver/Inc/Legacy -IDrivers/CMSIS/Device/ST/STM32F1xx/Include -IDrivers/CMSIS/Include -Og -Wall -fdata-sections -ffunction-sections -g -gdwarf-2 -MMD -MP -MF"master" -mcpu=cortex-m3 -mthumb -specs=nano.specs -TSTM32F103RBTx_FLASH.ld -lc -lm -lnosys -Wl,-Map=build/dual-interface.map,--cref -Wl,--gc-sections Src/master.c build/master.elf build/master.hex build/master.bin -o master
c:/program files (x86)/gnu arm embedded toolchain/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: build/master.elf: in function `_init':
(.text+0x40): multiple definition of `_init'; c:/program files (x86)/gnu arm embedded toolchain/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/thumb/v7-m/nofp/crti.o:(.init+0x0): first defined here
c:/program files (x86)/gnu arm embedded toolchain/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: build/master.elf: in function `_fini':
(.text+0x4c): multiple definition of `_fini'; c:/program files (x86)/gnu arm embedded toolchain/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/thumb/v7-m/nofp/crti.o:(.fini+0x0): first defined here
build/master.bin: file not recognized: file format not recognized
collect2.exe: error: ld returned 1 exit status
make: *** [master] Error 1
How can I solve this?
you can recreate the error in windows with "gnu make" and "arm-none-eabi-gcc" as compiler. in linux and in case of stdint.h error, you also need to install one of the packages mentioned here.
The last gcc run ...
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -DUSE_HAL_DRIVER -DSTM32F103xB -IInc -Og -Wall -fdata-sections -ffunction-sections -g -gdwarf-2 -MMD -MP -MF"master" -mcpu=cortex-m3 -mthumb -specs=nano.specs -TSTM32F103RBTx_FLASH.ld -lc -lm -lnosys -Wl,-Map=build/myproject.map,--cref -Wl,--gc-sections Src/master.c build/master.elf build/master.hex -o master
... that generates the errors, is itself erroneous. Where does it come from?
Note the -o master at the end: there is no rule presented in the makefile whose recipe would produce such a compilation, but it is building a file with the same name, master, as the goal target. This is the result of the exercise of a built-in implicit rule for building an executable from a correspondingly-named C source file.
Several circumstances contribute to this.
A request is made to build target master. It is the goal target in this case, but it would also suffice for it to be a prerequisite of another target that make wants to build.
The makefile does not provide any recipe for building master.
There is a source file named master.c. Although it is in subdirectory Src, there is a %vpath directive that tells make to treat files in that directory as if they appeared in the project root directory.
Additionally,
The built-in rule is apparently including the declared prerequisites of target master (build/master.elf and build/master.hex) in the compilation command. This is not documented or standard for versions of make I've checked, and it is the reason for the multiple-definition errors: gcc is building an executable, so it provides standard _init and _fini functions, but the already-built executable build/master.elf that is included in the link also has these.
Since you don't actually want a file named master built, a good solution would be to declare that target phony:
.PHONY: master
That has several useful effects, but key for your purposes is that it causes the implicit rule search for that target to be skipped.

Why does SystemTable->ConIn functions cause my fans to go insane and freeze the booting process?

So basically, I'm trying to do input with gnu-efi and I've struggled but I finally got something compiling. Here it is:
#include <efi.h>
#include <efilib.h>
EFI_STATUS EFIAPI efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
EFI_STATUS status;
EFI_INPUT_KEY Key;
InitializeLib(ImageHandle, SystemTable);
//status = SystemTable->ConIn->Reset(SystemTable->ConIn, FALSE);
if (EFI_ERROR(status))
return status;
SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello pussy\n");
while((status = SystemTable->ConIn->ReadKeyStroke(SystemTable->ConIn, &Key)) == EFI_NOT_READY && Key.ScanCode != 0x17);
times
return EFI_SUCCESS;
}
My problem is that this causes the process to be stuck on the starting and makes my fans go crazy. There are no errors or anything. It just doesn't work. It stops the process and it makes my fans go overdrive. Any ConIn function does that.
**
Extra info:
**
The make file I compile my code with:
OBJS = main3.o
TARGET = hello3.efi
EFIINC = /usr/include/efi
EFIINCS = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol
LIB = /usr/lib64
EFILIB = /usr/lib64/
EFI_CRT_OBJS = $(EFILIB)/crt0-efi-$(ARCH).o
EFI_LDS = $(EFILIB)/elf_$(ARCH)_efi.lds
CFLAGS = -ffreestanding $(EFIINCS) -fno-stack-protector -fpic \
-fshort-wchar -mno-red-zone -Wall -c
ifeq ($(ARCH),x86_64)
CFLAGS += -DEFI_FUNCTION_WRAPPER
endif
LDFLAGS = -nostdlib -znocombreloc -T $(EFI_LDS) -shared \
-Bsymbolic -L $(EFILIB) -L $(LIB) $(EFI_CRT_OBJS)
all: $(TARGET)
main3.o: hello.c
gcc $(CFLAGS) hello3.c -o main3.o
hello3.so: $(OBJS)
ld $(LDFLAGS) $(OBJS) -o $# -lefi -lgnuefi
%.efi: %.so
objcopy -j .text -j .sdata -j .data -j .dynamic \
-j .dynsym -j .rel -j .rela -j .reloc \
--target=efi-app-$(ARCH) $^ $#
the command I run qemu with:
qemu-system-x86_64 -bios OVMF.fd -drive media=disk,id=boot,format=raw,file=fat:rw:DirContainingEFI/BOOT/bootx64.efi,index=0

AVR USART file not recognized in C

I have the following test setup below. When I compile the code, I get the following error: The initUSART is not recognized, but I have included the file in the appropriate places. Did I miss out on anything?
AVR Development Stack
Get input main.c file...
Compile code and return elf file...
main.o: In function `main':
/Users/sebastianscharf/Documents/Hardware/AVR/main.c:14: undefined reference to `initUSART'
collect2: error: ld returned 1 exit status
avr-objcopy: 'main.elf': No such file
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.00s
avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: Expected signature for ATmega328 is 1E 95 14
Double check chip, or use -F to override this check.
avrdude done. Thank you.
main file
#include "config.h"
#include <avr/io.h>
#include <util/delay.h>
#include "USART.h"
int main(void) {
char serialCharacter;
// --- INITS --- //
DDRB = 0xff;
// Set up LED for output
initUSART();
return 0;
}
USART.h
/* These are defined for convenience */
#define USART_HAS_DATA bit_is_set(UCSR0A, RXC0)
#define USART_READY bit_is_set(UCSR0A, UDRE0)
uint8_t receiveByte(void);
/* Takes the defined BAUD and F_CPU, calculates the bit-clock multiplier, and configures the hardware USART*/
void initUSART(void);
USART.c
#include "config.h"
#include <avr/io.h>
#include <util/setbaud.h>
#include "USART.h"
void initUSART(void) {
// Requires BAUD
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
#if USE_2X
UCSR0A |= (1 << U2X0);
#else
UCSR0A &= ~(1 << U2X0);
#endif
// Enable USART
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); // 8 data bits, 1 stop bit
}
bash file
#!/bin/bash
source bashColors.sh
echo -e "${IGreen}AVR Development Stack${Reset}"
echo -e "${BIBlue}Get input main.c file...${Reset}"
avr-gcc -g -Os -mmcu=atmega328p -c main.c USART.c &&
echo -e "${BIBlue}Compile code and return elf file...${Reset}"
avr-gcc -g -mmcu=atmega328p -o main.elf main.o &&
echo -e "${BIBlue}Convert elf file to hex...${Reset}"
# avr-objcopy converts into hex file. -j indicates that we want the information from the .text and .data segment extracted.
avr-objcopy -j .text -j .data -O ihex main.elf out.hex &&
echo -e "${BIBlue}Uploading data to microcontroller...${Reset}"
avrdude -c usbtiny -p m328
You compiled both source files properly to .o with:
avr-gcc -g -Os -mmcu=atmega328p -c main.c USART.c
Now the main.o file contains an external reference to initUSART (partly thanks to the #include "USART.h" directive which provides the proper prototype)
but this link line:
avr-gcc -g -mmcu=atmega328p -o main.elf main.o &&
only references main.o. You need to add USART.o so the symbol is resolved by the linker (the linker doesn't care about .h include files), like this:
avr-gcc -g -mmcu=atmega328p -o main.elf main.o USART.o &&

gcc generates binary of size 0 with -Os

I have a simple FreeRTOS application that just toggles an LED in the main loop.
When I compile it with -Os, the resulting binary has size 0. Without -Os everything works as expected. What is happening here?
My CFLAGS are:
CPUFLAG = -mthumb -mcpu=cortex-m4
FPUFLAG = -mfpu=fpv4-sp-d16 -mfloat-abi=hard
WFLAG = -Wall -Wextra -Werror -Wstrict-prototypes
CFLAGS += -std=gnu99 $(WFLAG) $(CPUFLAG) $(FPUFLAG) -mlittle-endian -mthumb -nostartfiles
CFLAGS += -ffunction-sections -fdata-sections -fno-builtin
LDFLAGS += -nostdlib --gc-sections -static
main is basically TI's blinky demo:
int main(void)
{
volatile uint32_t ui32Loop;
//
// Enable the GPIO port that is used for the on-board LED.
//
SYSCTL_RCGC2_R = SYSCTL_RCGC2_GPIOF;
//
// Do a dummy read to insert a few cycles after enabling the peripheral.
//
ui32Loop = SYSCTL_RCGC2_R;
//
// Enable the GPIO pin for the LED (PF3). Set the direction as output, and
// enable the GPIO pin for digital function.
//
GPIO_PORTF_DIR_R = 0x08;
GPIO_PORTF_DEN_R = 0x08;
//
// Loop forever.
//
while(1)
{
//
// Turn on the LED.
//
GPIO_PORTF_DATA_R |= 0x08;
//
// Delay for a bit.
//
for(ui32Loop = 0; ui32Loop < 200000; ui32Loop++)
{
}
//
// Turn off the LED.
//
GPIO_PORTF_DATA_R &= ~(0x08);
//
// Delay for a bit.
//
for(ui32Loop = 0; ui32Loop < 200000; ui32Loop++)
{
}
}
return 0;
}
With -Os this generates
text data bss dec hex filename
0 0 0 0 0 image.elf
otherwise
text data bss dec hex filename
2012 4 728 2744 ab8 image.elf
edit: differences in .map files
Since you specified -nostartfiles, the standard startup and its entrypoint is not used, so there is no reference to your main function, and --gc-sections discards the whole section as unused.
To fix, try to either name your function start or add -e _main to the ld flags.

Hello world, bare metal Beagleboard

I'm trying to get a 'hello world' type program running on my Beagleboard-xm rev. C, by calling a C puts function from assembly.
So far I've been using this as a reference: http://wiki.osdev.org/ARM_Beagleboard
Here's what I have so far, but there's no output.
hello.c
volatile unsigned int * const UART3DR = (unsigned int *)0x49020000;
void puts(const char *s) {
while(*s != '\0') {
*UART3DR = (unsigned int)(*s);
s++;
}
}
void hello() {
puts("Hello, Beagleboard!\n");
}
boot.asm
.global start
start:
ldr sp, =stack_bottom
bl hello
b .
linker.ld
ENTRY(start)
MEMORY
{
ram : ORIGIN = 0x80200000, LENGTH = 0x10000
}
SECTIONS
{
.hello : { hello.o(.text) } > ram
.text : { *(.text) } > ram
.data : { *(.data) } > ram
.bss : { *(.bss) } > ram
. = . + 0x5000; /* 4kB of stack memory */
stack_bottom = .;
}
Makefile
ARMGNU = arm-linux-gnueabi
AOPS = --warn --fatal-warnings
COPS = -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding
boot.bin: boot.asm
$(ARMGNU)-as boot.asm -o boot.o
$(ARMGNU)-gcc-4.6 -c $(COPS) hello.c -o hello.o
$(ARMGNU)-ld -T linker.ld hello.o boot.o -o boot.elf
$(ARMGNU)-objdump -D boot.elf > boot.list
$(ARMGNU)-objcopy boot.elf -O srec boot.srec
$(ARMGNU)-objcopy boot.elf -O binary boot.bin
Using just the asm file like this works.
.equ UART3.BASE, 0x49020000
start:
ldr r0,=UART3.BASE
mov r1,#'c'
Here are some Beagleboard/minicom related info: http://paste.ubuntu.com/829072/
Any pointers? :)
I also tried
void hello() {
*UART3DR = 'c';
}
I'm using minicom and send the file via ymodem, then I try to run it with:
go 0x80200000
Hardware and software control flow in minicom are off.
that should have worked for you. Here is some code I dug up from way back when, did not try it on a beagleboard tonight just made sure it compiled, it had worked at one time...
startup.s:
.code 32
.globl _start
_start:
bl main
hang: b hang
.globl PUT32
PUT32:
str r1,[r0]
bx lr
.globl GET32
GET32:
ldr r0,[r0]
bx lr
hello.c :
extern void PUT32 ( unsigned int, unsigned int );
extern unsigned int GET32 ( unsigned int );
void uart_send ( unsigned char x )
{
while((GET32(0x49020014)&0x20)==0x00) continue;
PUT32(0x49020000,x);
}
void hexstring ( unsigned int d )
{
//unsigned int ra;
unsigned int rb;
unsigned int rc;
rb=32;
while(1)
{
rb-=4;
rc=(d>>rb)&0xF;
if(rc>9) rc+=0x37; else rc+=0x30;
uart_send(rc);
if(rb==0) break;
}
uart_send(0x0D);
uart_send(0x0A);
}
int main ( void )
{
hexstring(0x12345678);
return(0);
}
memmap (linker script):
MEMORY
{
ram : ORIGIN = 0x82000000, LENGTH = 256K
}
SECTIONS
{
ROM : { startup.o } > ram
}
Makefile :
CROSS_COMPILE = arm-none-eabi
AOPS = --warn --fatal-warnings
COPS = -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding
all : hello.bin
hello.bin : startup.o hello.o memmap
$(CROSS_COMPILE)-ld startup.o hello.o -T memmap -o hello.elf
$(CROSS_COMPILE)-objdump -D hello.elf > hello.list
$(CROSS_COMPILE)-objcopy hello.elf -O binary hello.bin
startup.o : startup.s
$(CROSS_COMPILE)-as $(AOPS) startup.s -o startup.o
hello.o : hello.c
$(CROSS_COMPILE)-gcc -c $(COPS) hello.c -o hello.o
clean :
rm -f *.o
rm -f *.elf
rm -f *.bin
rm -f *.list
Looks like I just left the stack pointer wherever the bootloader had it. Likewise, as you, assumed the bootloader had initialized the serial port.
I assume you have serial port access working, you see uboot and you are able to type commands in order to download this program (xmodem, or whatever) into the boards ram? If you cant do that then it may be you are not connected to the serial port right. the beagleboards serial port is screwy, might need to make your own cable.
You can't just blindly write a string of characters to a UART - you need to check status on each character - it works in the single character example because the UART is always going to be ready for the first character, but for the second and subsequent characters you need to poll (or better yet use an ISR, but let's walk before we run).
There's some good example code here: http://hardwarefreak.wordpress.com/2011/08/30/some-experience-with-the-beagleboard-xm-part-2/
I've not enough repetation to comment..
But my answere to
Works either way. Now the weird thing is that I can print individual
characters with with uart_send('c') for example, but cannot print
strings print_string(char *str){ while (*str != '\0') uart_send
(*str++); } print_string("Test"); . Any thoughts on this?
is:
You write faster in the output buffer, as UART is able to send..
So you've to check, if the output buffer is empty, before you send a new character.
I've done this in the code on my blog (http://hardwarefreak.wordpress.com/2011/08/30/some-experience-with-the-beagleboard-xm-part-2/)

Resources