ARM interrupts from the beginning (Cortex-M4) - c

I am dealing with a new microcontroller LPC4088 from NXP. I needed 2 weeks to study and write a working examples for peripherals: IOCONFIG, GPIO, TIMERS, PWM and ADC. Please take a look at my repositories here. This is how you will get a feeling for how I work and what my skill level is.
Until now I could simply disable interrupts and work without them. Now I want to deal with UART peripheral device which needs interrupts. I have never programmed interupts but know something about ARM interrupts. Sadly just in theory. Currently I am studying these two documents:
LPC4088 user guide (NVIC p.80 & UART1 p.461),
Cortex-M4 devices generic user manual
It became clear to me that I need to study ARM Cortex-M4 microprocessor besides the LPC4088 microcontroller which I got the hang of somehow. I know that I should put ARM exception vectors at the beginning of the program - usually in the startup code. But I don't know how to do this because what I got with the microcontroller is already compiled startup code (object file) which presumably defines exception vectors, reset handler which sets stacks for C and then jumps to function main() in C source code written by user.
After compilation of my programs using GCC ARM compiler I allways get this prompt, which must allso be the clue which I don't understand because of my inexperience with ARM mcpu's directly:
*****
***** You must modify vector checksum value in *.bin and *.hex files.
*****
I was thinking of reverse ingeneering the startup code using the Segger Jlink and fixing the exception vectors there, but there must be any other way besides writing my own open source startup code... So do you have any suggestions or examples which would be even better for me.
ADD: I really looked hard and got no source code for the startup code. This is what I got:
The only way to somehow manipulate vectors therefore must be hidden inside the linker script, which is the only part that is still a source code and it looks like this:
/* Linker script for mbed LPC1768 */
/* Linker script to configure memory regions. */
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K
RAM (rwx) : ORIGIN = 0x100000E8, LENGTH = (64K - 0xE8)
USB_RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 16K
ETH_RAM(rwx) : ORIGIN = 0x20004000, LENGTH = 16K
}
/* Linker script to place sections and symbol values. Should be used together
* with other linker script that defines memory regions FLASH and RAM.
* It references following symbols, which must be defined in code:
* Reset_Handler : Entry of reset handler
*
* It defines following symbols, which code can use without definition:
* __exidx_start
* __exidx_end
* __etext
* __data_start__
* __preinit_array_start
* __preinit_array_end
* __init_array_start
* __init_array_end
* __fini_array_start
* __fini_array_end
* __data_end__
* __bss_start__
* __bss_end__
* __end__
* end
* __HeapLimit
* __StackLimit
* __StackTop
* __stack
*/
ENTRY(Reset_Handler)
SECTIONS
{
.text :
{
KEEP(*(.isr_vector))
*(.text*)
KEEP(*(.init))
KEEP(*(.fini))
/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)
*(.rodata*)
KEEP(*(.eh_frame*))
} > FLASH
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;
__etext = .;
.data : AT (__etext)
{
__data_start__ = .;
Image$$RW_IRAM1$$Base = .;
*(vtable)
*(.data*)
. = ALIGN(4);
/* preinit data */
PROVIDE (__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE (__preinit_array_end = .);
. = ALIGN(4);
/* init data */
PROVIDE (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE (__init_array_end = .);
. = ALIGN(4);
/* finit data */
PROVIDE (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE (__fini_array_end = .);
. = ALIGN(4);
/* All data end */
__data_end__ = .;
} > RAM
.bss :
{
__bss_start__ = .;
*(.bss*)
*(COMMON)
__bss_end__ = .;
Image$$RW_IRAM1$$ZI$$Limit = . ;
} > RAM
.heap :
{
__end__ = .;
end = __end__;
*(.heap*)
__HeapLimit = .;
} > RAM
/* .stack_dummy section doesn't contains any symbols. It is only
* used for linker to calculate size of stack sections, and assign
* values to stack symbols later */
.stack_dummy :
{
*(.stack)
} > RAM
/* Set stack top to end of RAM, and stack limit move down by
* size of stack_dummy section */
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
PROVIDE(__stack = __StackTop);
/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
/* Code can explicitly ask for data to be
placed in these higher RAM banks where
they will be left uninitialized.
*/
.AHBSRAM0 (NOLOAD):
{
Image$$RW_IRAM2$$Base = . ;
*(AHBSRAM0)
Image$$RW_IRAM2$$ZI$$Limit = .;
} > USB_RAM
.AHBSRAM1 (NOLOAD):
{
Image$$RW_IRAM3$$Base = . ;
*(AHBSRAM1)
Image$$RW_IRAM3$$ZI$$Limit = .;
} > ETH_RAM
}
There is allso a makefile which looks like this and is contributing the prompt that I get at the end of every compilation:
# This file was automagically generated by mbed.org. For more information,
# see http://mbed.org/handbook/Exporting-to-GCC-ARM-Embedded
GCC_BIN =
PROJECT = executaable
OBJECTS = ./main.o
SYS_OBJECTS = ./mbed/TARGET_LPC4088/TOOLCHAIN_GCC_ARM/startup_LPC408x.o ./mbed/TARGET_LPC4088/TOOLCHAIN_GCC_ARM/retarget.o ./mbed/TARGET_LPC4088/TOOLCHAIN_GCC_ARM/system_LPC407x_8x_177x_8x.o ./mbed/TARGET_LPC4088/TOOLCHAIN_GCC_ARM/board.o ./mbed/TARGET_LPC4088/TOOLCHAIN_GCC_ARM/cmsis_nvic.o
INCLUDE_PATHS = -I. -I./mbed -I./mbed/TARGET_LPC4088 -I./mbed/TARGET_LPC4088/TOOLCHAIN_GCC_ARM -I./mbed/TARGET_LPC4088/TARGET_NXP -I./mbed/TARGET_LPC4088/TARGET_NXP/TARGET_LPC408X -I./mbed/TARGET_LPC4088/TARGET_NXP/TARGET_LPC408X/TARGET_LPC4088
LIBRARY_PATHS = -L./mbed/TARGET_LPC4088/TOOLCHAIN_GCC_ARM
LIBRARIES = -lmbed
LINKER_SCRIPT = ./mbed/TARGET_LPC4088/TOOLCHAIN_GCC_ARM/LPC4088.ld
###############################################################################
AS = $(GCC_BIN)arm-none-eabi-as
CC = $(GCC_BIN)arm-none-eabi-gcc
CPP = $(GCC_BIN)arm-none-eabi-g++
LD = $(GCC_BIN)arm-none-eabi-gcc
OBJCOPY = $(GCC_BIN)arm-none-eabi-objcopy
OBJDUMP = $(GCC_BIN)arm-none-eabi-objdump
SIZE = $(GCC_BIN)arm-none-eabi-size
CPU = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=softfp
CC_FLAGS = $(CPU) -c -g -fno-common -fmessage-length=0 -Wall -fno-exceptions -ffunction-sections -fdata-sections -fomit-frame-pointer
CC_FLAGS += -MMD -MP
CC_SYMBOLS = -DTARGET_LPC4088 -DTARGET_M4 -DTARGET_CORTEX_M -DTARGET_NXP -DTARGET_LPC408X -DTOOLCHAIN_GCC_ARM -DTOOLCHAIN_GCC -D__CORTEX_M4 -DARM_MATH_CM4 -D__FPU_PRESENT=1 -DMBED_BUILD_TIMESTAMP=1429428454.91 -D__MBED__=1
LD_FLAGS = $(CPU) -Wl,--gc-sections --specs=nano.specs -u _printf_float -u _scanf_float -Wl,--wrap,main
LD_FLAGS += -Wl,-Map=$(PROJECT).map,--cref
LD_SYS_LIBS = -lstdc++ -lsupc++ -lm -lc -lgcc -lnosys
ifeq ($(DEBUG), 1)
CC_FLAGS += -DDEBUG -O0
else
CC_FLAGS += -DNDEBUG -Os
endif
all: $(PROJECT).bin $(PROJECT).hex
clean:
rm -f $(PROJECT).bin $(PROJECT).elf $(PROJECT).hex $(PROJECT).map $(PROJECT).lst $(OBJECTS) $(DEPS)
.s.o:
$(AS) $(CPU) -o $# $<
.c.o:
$(CC) $(CC_FLAGS) $(CC_SYMBOLS) -std=gnu99 $(INCLUDE_PATHS) -o $# $<
.cpp.o:
$(CPP) $(CC_FLAGS) $(CC_SYMBOLS) -std=gnu++98 -fno-rtti $(INCLUDE_PATHS) -o $# $<
$(PROJECT).elf: $(OBJECTS) $(SYS_OBJECTS)
$(LD) $(LD_FLAGS) -T$(LINKER_SCRIPT) $(LIBRARY_PATHS) -o $# $^ $(LIBRARIES) $(LD_SYS_LIBS) $(LIBRARIES) $(LD_SYS_LIBS)
#echo ""
#echo "*****"
#echo "***** You must modify vector checksum value in *.bin and *.hex files."
#echo "*****"
#echo ""
$(SIZE) $#
$(PROJECT).bin: $(PROJECT).elf
#$(OBJCOPY) -O binary $< $#
$(PROJECT).hex: $(PROJECT).elf
#$(OBJCOPY) -O ihex $< $#
$(PROJECT).lst: $(PROJECT).elf
#$(OBJDUMP) -Sdh $< > $#
lst: $(PROJECT).lst
size:
$(SIZE) $(PROJECT).elf
DEPS = $(OBJECTS:.o=.d) $(SYS_OBJECTS:.o=.d)
-include $(DEPS)

Ok, took me some minutes. Checkout one of the projects in this zip. There are various startup codes. Btw.: It is not so complicated to write your own. most times one has to modify it anyway for "real" projects.
The zip comes from this page. The second zip might include liker files, but possibly not for gcc (the "keil" might be a good start though). But you already have one to start with.
I just had alook at periph_blinky. Note that the startup always has to correspond with the linker script, as there are some special sections. For reading, I recommend to check out the binutils docs and, of course, the gcc docs.
There should also be some libs as I stated in a comment with CMSIS functions and the header with MCU definitions. The CMSIS stuff can also be fetched from ARM, but might require some fiddling to tailor to the actual implementation (number of MPU regions, etc.).
Oh, and I would recommend not to use the vendor libraries for peripheral access. They might be called "standard", but they are actually not, but most times include a mass of bloat like run-time initialization (using separate writes to each member!) of structs which never change. Not sure about NXP, but STM, for instance provides one of the crappiest "std"library I've ever seen.

Quickly glancing at the question and answer. first off why is it you think you need interrupts for the uart? I have so far never met such a beast that is required, perhaps you have a desired use case, but required?
I have many examples, all bare metal, no hal or standard libraries, etc. search for thumbulator at github and then wander sideways from there to see a few. I have little use for interrupts but likely did some somewhere for sake of an example.
As mentioned in comments, the arm docs, and just trying it out you will see that for the cortex-m the stack pointer can be set by hardware based on the first entry in the vector table, and from there you dont have to mess with it for interrupts or exceptions. this is not how a full sized arm works with its many stacks that all have to be setup.
The cortex-m is such that you can fill the vector table with addresses to C functions if your compiler complies with the (E)ABI. With gcc it will. there may be some assembly required but not as much as you would deal with elsewhere.
arm makes cores not chips, so the arm docs only get you to the edge of the core, the rest is from the chip vendor and can vary widely, how to enable and clear the interrupts for example.

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.

How to write/read to FLASH on STM32F302

I am making a code using CubeIDE for a STM32F302K8UX and I need a variable to be persistent across resets.
One way I have seen ppl doing it is by making a variable that is saved directly on flash memory (at least this is what I understood of it).
I got it from #Stephan answer on this post:
How to write/read to FLASH on STM32F4, Cortex M4
So I tried following it with a few modifications. On the MEMORY section of STM32F302K8UX_FLASH.ld:
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 16K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 63K // subtracted 1kb from original value (64K)
DATA (rx) : ORIGIN = 0x0800FC00, LENGTH = 1K // created new section at the end of previous (0x8000000 + (63 * 1024))
}
Then on the SECTIONS section, I added this at the start:
SECTIONS
{
.user_data (NOLOAD):
{
. = ALIGN(4);
_user_data_start = .; /* create a global symbol at user_data start */
KEEP(*(.user_data))
. = ALIGN(4);
_user_data_end = .; /* create a global symbol at user_data end */
} >DATA
...
Now on my main code I declared the variable as such:
uint8_t persistent_config __attribute__ ((section(".user_data")));
But I get a linker error that I cannot really understand:
14:03:41 **** Incremental Build of configuration Debug for project sonicPlayer ****
make -j12 all
arm-none-eabi-gcc "../Core/Src/main.c" -mcpu=cortex-m4 -std=gnu11 -g3 -DUSE_HAL_DRIVER -DSTM32F302x8 -DDEBUG -c -I../Core/Inc -I../Drivers/STM32F3xx_HAL_Driver/Inc -I../Drivers/STM32F3xx_HAL_Driver/Inc/Legacy -I../Drivers/CMSIS/Device/ST/STM32F3xx/Include -I../Drivers/CMSIS/Include -O0 -ffunction-sections -fdata-sections -Wall -fstack-usage -MMD -MP -MF"Core/Src/main.d" -MT"Core/Src/main.o" --specs=nano.specs -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -o "Core/Src/main.o"
arm-none-eabi-gcc -o "sonicPlayer.elf" #"objects.list" -mcpu=cortex-m4 -T"C:\Users\werne\OwnCloud\Documents\Arquivos\Drive\Projetos\SonicScrewDriver\sonicPlayer\STM32F302K8UX_FLASH.ld" --specs=nosys.specs -Wl,-Map="sonicPlayer.map" -Wl,--gc-sections -static --specs=nano.specs -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -Wl,--start-group -lc -lm -Wl,--end-group
c:\st\stm32cubeide_1.4.0\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.7-2018-q2-update.win32_1.4.0.202007081208\tools\arm-none-eabi\bin\ld.exe:C:\Users\werne\OwnCloud\Documents\Arquivos\Drive\Projetos\SonicScrewDriver\sonicPlayer\STM32F302K8UX_FLASH.ld:40: syntax error
collect2.exe: error: ld returned 1 exit status
make: *** [makefile:50: sonicPlayer.elf] Error 1
"make -j12 all" terminated with exit code 2. Build might be incomplete.
14:03:42 Build Failed. 2 errors, 0 warnings. (took 598ms)
Description Resource Path Location Type
make: *** [makefile:50: sonicPlayer.elf] Error 1 sonicPlayer C/C++ Problem
make: *** No rule to make target 'clean'. Stop. Firmware C/C++ Problem
syntax error sonicPlayer line 40, external location: c:\st\stm32cubeide_1.4.0\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.7-2018-q2-update.win32_1.4.0.202007081208\tools\arm-none-eabi\bin\ld.exe:C:\Users\werne\OwnCloud\Documents\Arquivos\Drive\Projetos\SonicScrewDriver\sonicPlayer\STM32F302K8UX_FLASH.ld C/C++ Problem
How do I fix this?
The error description is pretty cryptic to me and I could find anything on google.
If you could explain what is going on here it would be nice too, I'm. not very experienced in this sort of too specific thing.
edit
I can see a syntax error, but no clue where or what.
edit 2: solution:
To fix the error code, I replaced // comments by /* */ as suggested by #KamilCuk However the code was not complete
With a bit more research based on all the other answers, I got this link: https://os.mbed.com/users/olympux/code/eeprom_flash/
So I scrapped all the above, added both .h and .c to my project, replaced #include "mbed.h" for #include "stm32f3xx_hal.h"
then I changed eeprom_flash.c first function
#include "eeprom_flash.h"
FLASH_EraseInitTypeDef eraseInit = {
FLASH_TYPEERASE_PAGES,
EEPROM_START_ADDRESS, // Memory location (beggining of page)
1 // Number of pages to erase
};
uint32_t pageError;
/*
* Must call this first to enable writing
*/
void enableEEPROMWriting() {
HAL_StatusTypeDef status = HAL_FLASH_Unlock();
HAL_FLASHEx_Erase(&eraseInit, &pageError);
}
That was it! to write to flash memory:
enableEEPROMWriting();
writeEEPROMHalfWord(0x0, var);
disableEEPROMWriting();
and to read
uint16_t var = readEEPROMHalfWord(0x0);

undefined reference to `calloc' when linking with arm-none-eabi-ld

I'm encountering an error that is doubtless due to some limit of my knowledge on how linkers work. Some ANSI C code I've written that compiles and links perfectly well on my OS X box fails to link with arm-none-eabi-ld when cross-compiled for ARM.
Here's the result from a clean make (with --verbose on ld):
arm-none-eabi-gcc -o build/fft.o src/fft.c -g -mthumb -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -Os -ffunction-sections -fdata-sections -MD -std=c99 -Wall -pedantic -DPART_TM4C123GH6PM -c -I../tivaware -DTARGET_IS_BLIZZARD_RA1
arm-none-eabi-gcc -o build/main.o src/main.c -g -mthumb -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -Os -ffunction-sections -fdata-sections -MD -std=c99 -Wall -pedantic -DPART_TM4C123GH6PM -c -I../tivaware -DTARGET_IS_BLIZZARD_RA1
arm-none-eabi-ld -o build/a.out build/fft.o build/main.o --verbose -T TM4C123GH6PM.ld --entry main --gc-sections
GNU ld (32-bit ARM EABI Toolchain JBS-FLOAT_IO-SGXXLITE_ML-2014.05-28-v2013.05-36-g3f93944) 2.24.51.20140217
Supported emulations:
armelf
opened script file TM4C123GH6PM.ld
using external linker script:
==================================================
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0X00008000
}
SECTIONS
{
/* code */
.text :
{
_text = .;
/* ensure ISR vectors are not removed by linker */
KEEP(*(.isr_vector))
*(.text*)
*(.rodata*)
_etext = .;
} > FLASH
/* static data */
.data : AT(ADDR(.text) + SIZEOF(.text))
{
_data = .;
*(vtable)
*(.data*)
_edata = .;
} > SRAM
/* static uninitialized data */
.bss :
{
_bss = .;
*(.bss*)
*(COMMON)
_ebss = .;
} > SRAM
}
==================================================
attempt to open build/fft.o succeeded
build/fft.o
attempt to open build/main.o succeeded
build/main.o
build/fft.o: In function `dft':
/path/src/fft.c:97: undefined reference to `calloc'
There's a number of other undefined symbols (__aeabi_dadd, __muldc3), which I've truncated for brevity.
Microcontrollers usually (practical reasons) are not configured with dynamic memory allocation facility.
so, malloc, calloc, free will not be available.
Recommendation: use static array to allocate memory.
even after reading this you need dynamic memory allocation, you can use newlibc
but beware that in case your heap and stack overlap, you will be in problem.

LD giving strange error and not finding an existing file when using ARM gcc

This is the command line executed by my Makefile:
arm-none-eabi-gcc bubblesort.c -O0 -mcpu=cortex-m0 -mthumb -Wl, -T ../boot_and_link/linker.ld -l ../boot_and_link/startup.o
As I understand it, it should compile bubblesort.c for a CortexM0 and then the linker should you use linker.ld as a linker script and should also link startup.o with the output of compiling bubblesort.c.
I get two errors:
/usr/lib/gcc/arm-none-eabi/4.8/../../../arm-none-eabi/bin/ld: cannot find : No such file or directory
/usr/lib/gcc/arm-none-eabi/4.8/../../../arm-none-eabi/bin/ld: cannot find -l../boot_and_link/startup.o
The first one I don't understand. ld tells me it cannot find : which makes no sense and makes me think there an error in my linker script.
The second error is just weird because my linker file is in the exact same location and it finds it and yes I've checked the file's names and they are the same.
Just in case I'm including my linker script on account of it being short and that I wrote it myself (first time) and I'm learning how to write them.
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 8K
ram : ORIGIN = 0x20004000, LENGTH = 16K
stack : ORIGIN = 0x20003FFF, LENGTH = 16K
}
SECTIONS
{
.nvic_vector : { } >rom /*The vector table that is initialized in c code*/
.text :
{
*(.text)
/*_DATAI_BEGIN = .;*/
} >rom
.data :
{
_DATA_LOAD = LOADADDR(.data); /*The absolute address of the data section*/
_DATA_BEGIN = .; /*From where to begin the copy to RAM*/
*(.data)
. = ALIGN(4); /*Make sure the byte boundary is correctly aligned*/
_DATA_END = .; /*Where to end the copy to RAM*/
} >ram AT >rom
.bss :
{
_BSS_BEGIN = .; /* Zero-filled run time allocate data memory */
*(.bss)
_BSS_END = .;
} > ram
.heap :
{
_HEAP = .;
} > ram
.stack :
{
. += LENGTH(stack);
. = ALIGN(4);
_STACKTOP = .; /* The top of the stack is the last available section of memory*/
} >stack
}
Any help would be appreciated.
You could separate compilation and linking, then it's easier to see
flags common both for compiler and linker
flags only for one of these
If you have main.c and startup.c, compilation should look like this:
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -Os -std=gnu99 -o startup.o -c startup.c
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -Os -std=gnu99 -o main.o -c main.c
As for linking
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -nostartfiles -T rom.ld -o main.elf startup.o main.o -lc -lm
If you want it in a single line:
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -Os -std=gnu99 -nostartfiles -T rom.ld -o main.elf startup.c main.c
So the main problem was this line:
arm-none-eabi-gcc bubblesort.c -O0 -mcpu=cortex-m0 -mthumb -Wl, -T ../boot_and_link/linker.ld -l ../boot_and_link/startup.o
This was wrong as the -l switched is used to link with a library and not to just point another object file which was my intention. You need to specify all files for linking as normal ordinary arguments to the linker. The way I ended up doing this was simply (taking Beryllium's advice) separating the compilation and linking into two steps and using two separate calls. Here are the commands that are run by my makefile:
<-------------------- Compiling C Source Files -------------------->
arm-none-eabi-gcc -O0 -c -mcpu=cortex-m0 -mthumb -g bubblesort.c -o bubblesort.o
<-------------------- Linking files -------------------->
arm-none-eabi-ld bubblesort.o ../boot_and_link/startup.o -nostartfiles -T ../boot_and_link/linker.ld -o bubblesort.elf
This worked.
PD: The first error (wher it says it cannot find : No such file or directory) had to to with incorrect spacing in the gcc call. However as I changed it, I cannot exactly recall where it was.

linking error when using sprintf()

on my cortex-m3, i am trying to output a float variable to my UART port.. so i need to convert the float DATA into a char outputstr[].
For this purpose, i used sprintf from the libc.a
if i comment out the sprintf(), i can compile and link.
if i use sprintf(outputstr, "t"), i can compile and link.
if i use sprintf(outputstr, "The value is %f", DATA), i will get linking errors like: no memory region specified for loadable section `.rodata', '.bss', '.text', '.data'
But i had already added *(.rodata), *(.bss) etc... in my linker script as below:
...
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(reset_handler)
MEMORY {
ROM : ORIGIN = 0x08000000, LENGTH = 128K
RAM : ORIGIN = 0x20000000, LENGTH = 16K
}
SECTIONS {
.ROMdata 0x8000000: AT(0x8000000){
startup.o(.romvect)
. = ALIGN(0x4);
system_stm32l1xx.o(.rodata*)
*(.rodata*)
_ROMdataend_ = ALIGN(0x4);
}
.ROMstartup (_ROMdataend_): AT(_ROMdataend_){
startup.o(.startup)
lowlevelinit.o(.lowlevelinit .tempexchandler)
system_stm32l1xx.o(.text*)
. = ALIGN(0x4);
}
.RAMbss 0x20000000 (NOLOAD):{
lowlevelinit.o(.ramvectortable)
. = ALIGN(0x4);
_RAMbssstart_ = .;
startup.o(.stack .heap)
. = ALIGN(0x4);
sensor_MTH01.o(.bss*)
. = ALIGN(0x4);
comm_BT-HC-05.o(.bss)
tim6.o(.bss)
main.o(.bss)
system_stm32l1xx.o(.bss*)
*(.bss*)
_RAMbssend_ = ALIGN(0x4);
}
.RAMcode (_RAMbssend_): AT(LOADADDR(.ROMstartup)+SIZEOF(.ROMstartup)){
_RAMcodeVMAstart_ = .;
_RAMcodeLMAstart_ = LOADADDR(.RAMcode);
main.o(.ramcode .text)
tim6.o(.tim6isr)
tim6.o(.text)
sensor_MTH01.o(.text)
comm_BT-HC-05.o(.text)
exti0_isr.o(.exti0isr)
*(.text*)
KEEP (*(.eh_*))
_RAMcodeVMAend_ = ALIGN(0x4);
}
.RAMdata (_RAMcodeVMAend_): AT(LOADADDR(.RAMcode)+SIZEOF(.RAMcode)){
_RAMcodeLMAend_ = (LOADADDR(.RAMcode)+SIZEOF(.RAMcode));
_RAMdataVMAstart_ = .;
_RAMdataLMAstart_ = LOADADDR(.RAMdata);
sensor_MTH01.o(.data)
system_stm32l1xx.o(.data*)
*(.data*)
_RAMdataVMAend_ = ALIGN(0x4);
_RAMdataLMAend_ = LOADADDR(.RAMdata) + SIZEOF(.RAMdata);
}
}
...
Also, i did include the lib paths and include paths in my makefile as below:
On a side note, i am also using strlen() and other float division operations from the libc.a and libgcc.a and these functions complile, link and work ok.
...
CC = arm-none-eabi-gcc
AS = arm-none-eabi-as
LD = arm-none-eabi-ld
OBJCPY = arm-none-eabi-objcopy
CCFLAGS = -c -mcpu=cortex-m3 -mthumb -O0 -g -Wall
ASMFLAGS = -mcpu=cortex-m3 -mthumb --gdwarf-2
LDFLAGS = -T CortexM3.ld -M=memmap.map
OBJCPYFLAGS = -O ihex
FLOATFLAGS = -mfloat-abi=soft -mfpu=vfp
LIBDIR = -L C:\\yagarto-20121222\\lib\\gcc\\arm-none-eabi\\4.7.2\\thumb\\v7m -L C:\\yagarto-20121222\\arm-none-eabi\\lib\\thumb\\v7m
INCDIR = -I C:\\yagarto-20121222\\lib\\gcc\\arm-none-eabi\\4.7.2\\include -I C:\\yagarto-20121222\\arm-none-eabi\\include
all: m3.elf
m3.elf: startup.o lowlevelinit.o system_stm32l1xx.o main.o tim6.o exti0_isr.o sensor_MTH01.o comm_BT-HC-05.o
$(LD) $(LDFLAGS) $(LIBDIR) $^ -lc -lgcc -o $#
$(OBJCPY) $(OBJCPYFLAGS) m3.elf m3.hex
startup.o: startup.s
lowlevelinit.o: lowlevelinit.c system_stm32l1xx.h stm32l1xx.h core_cm3.h
system_stm32l1xx.o: system_stm32l1xx.c stm32l1xx.h core_cm3.h system_stm32l1xx.h
main.o: main.c stm32l1xx.h
tim6.o: tim6.c
exti0_isr.o: exti0_isr.c
sensor_MTH01.o: sensor_MTH01.c
comm_BT-HC-05.o: comm_BT-HC-05.c
clean:
-rm -f startup.o lowlevelinit.o system_stm32l1xx.o main.o tim6.o tim6_isr.o exti0_isr.o sensor_MTH01.o comm_BT-HC-05.o memmap.map m3.elf m3.hex
%.o: %.s
$(AS) $(ASMFLAGS) $< -o $#
%.o: %.c
$(CC) $(CCFLAGS) $(INCDIR) $(FLOATFLAGS) $< -o $#
.PHONY: all clean
...
can anyone advise?
also, if i come across linking error message like: no memory region specified for loadable section `.rodata'... how can i know which object's (.o) .rodata section is being left out of my linker script?
update:
i realized that if the sprintf() function is called in main(), the program can compile and link successfully.. but if i call the sprintf() function in other functions, i will get above linking errors (no memory region specified for loadable section .bss), even if i used *(.bss) as the input sections for my output sections.
To solve the linking errors ('no memory region specified for loadable section .bss etc', i had to add *(COMMON) in the BSS output section.

Resources