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);
Related
I am getting a "undefined reference to 'i2c_master_init' " i think this is to do some linking but not to sure how to correct ?
UPDATE :
iv been trying to find the answer for this for a while now. and have noticed a few bit but just not sure what i am doing wrong ! sorry it must be getting hard to read now !
This is from i2c_master.h and give me no issues
static inline void i2c_master_enable(const struct i2c_master_module *const module){
/* Sanity check of arguments */
Assert(module);
Assert(module->hw);
SercomI2cm *const i2c_module = &(module->hw->I2CM);
/* Timeout counter used to force bus state */
uint32_t timeout_counter = 0;
/* Wait for module to sync */
_i2c_master_wait_for_sync(module);
/* Enable module */
i2c_module->CTRLA.reg |= SERCOM_I2CM_CTRLA_ENABLE;
#if I2C_MASTER_CALLBACK_MODE == true
/* Enable module interrupts */
system_interrupt_enable(_sercom_get_interrupt_vector(module->hw));
#endif
/* Start timeout if bus state is unknown */
while (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(1))) {
timeout_counter++;
if(timeout_counter >= (module->unknown_bus_state_timeout)) {
/* Timeout, force bus state to idle */
i2c_module->STATUS.reg = SERCOM_I2CM_STATUS_BUSSTATE(1);
/* Workaround #1 */
return;
}
This is in the same file and is giving me issues
enum status_code i2c_master_init(struct i2c_master_module *const module,
Sercom *const hw, const struct i2c_master_config *const config);
this is my code.....
#include <asf.h>
void initialize(void)
{
system_init();
delay_init();
ioport_init();
}
//I2c slave address
#define AM2315_ADDRESS 0xB8 //temp and humity sensor
#define DATA_LENGTH 10
#define TIMEOUT 1000 //number of time to try and send the packet before it
fails
static uint8_t write_buffer[DATA_LENGTH] = {0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09};
static uint8_t read_buffer[DATA_LENGTH];
struct i2c_master_module i2c_master_instance;
void configure_i2c_master(void)
{
/* Initialize config structure and software module. */
struct i2c_master_config config_i2c_master;
i2c_master_get_config_defaults(&config_i2c_master);
/* Change buffer timeout to something longer. */
config_i2c_master.buffer_timeout = 10000;
/* Initialize and enable device with config. */
i2c_master_init(&i2c_master_instance, SERCOM1, &config_i2c_master);
i2c_master_enable(&i2c_master_instance);
}
int main (void)
{
initialize();
configure_i2c_master();
uint8_t timeout = 0 ;
struct i2c_master_packet packet ={
.address = AM2315_ADDRESS,
.data_length = DATA_LENGTH,
.data = write_buffer,
.ten_bit_address = false,
.hs_master_code = 0x0,
};
ioport_set_pin_dir(PIN_PA27, IOPORT_DIR_OUTPUT);
while(1)
{
delay_ms(1000);
ioport_set_pin_level(PIN_PA27, true);
delay_ms(1000);
ioport_set_pin_level(PIN_PA27, false);
//write buffer to slave untill success
while(i2c_master_read_packet_wait(&i2c_master_instance, &packet) !=
STATUS_OK){
if (timeout++ ==TIMEOUT){
break;
}
}
//Read from slave until success.
packet.data = read_buffer;
while (i2c_master_read_packet_wait(&i2c_master_instance, &packet) !=
STATUS_OK){
if (timeout++ ==TIMEOUT){
break;
}
}
}
}
this is my output...
------ Build started: Project: GccBoardProject1, Configuration: Debug ARM --
Build started.
Project "GccBoardProject1.cproj" (default targets):
Target "PreBuildEvent" skipped, due to false condition;
('$(PreBuildEvent)'!='') was evaluated as (''!='').
Target "CoreBuild" in file "C:\Program Files
(x86)\Atmel\Studio\7.0\Vs\Compiler.targets" from project
"C:\Users\benvo\Documents\Atmel
Studio\7.0\GccBoardProject1\GccBoardProject1\GccBoardProject1.cproj"
(target "Build" depends on it):
Task "RunCompilerTask"
Shell Utils Path C:\Program Files (x86)\Atmel\Studio\7.0\shellUtils
C:\Program Files (x86)\Atmel\Studio\7.0\shellUtils\make.exe all --jobs 4 --
output-sync
C:\Users\benvo\Documents\Atmel
Studio\7.0\GccBoardProject1\GccBoardProject1\src\main.c(35,6): warning: no
previous prototype for 'initialize' [-Wmissing-prototypes]
void initialize(void)
^~~~~~~~~~
C:\Users\benvo\Documents\Atmel
Studio\7.0\GccBoardProject1\GccBoardProject1\src\main.c(58,6): warning: no
previous prototype for 'configure_i2c_master' [-Wmissing-prototypes]
void configure_i2c_master(void)
^~~~~~~~~~~~~~~~~~~~
Building file: ../src/main.c
Invoking: ARM/GNU C Compiler : 6.3.1
"C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\arm\arm-gnu-
toolchain\bin\arm-none-eabi-gcc.exe" -x c -mthumb -D__SAMD21G18A__ -DDEBUG
-DBOARD=USER_BOARD -DARM_MATH_CM0PLUS=true -DSYSTICK_MODE -
DI2C_MASTER_CALLBACK_MODE=true -I"../src/ASF/common/boards" -
I"../src/ASF/sam0/utils" -I"../src/ASF/sam0/utils/header_files" -
I"../src/ASF/sam0/utils/preprocessor" -
I"../src/ASF/thirdparty/CMSIS/Include" -
I"../src/ASF/thirdparty/CMSIS/Lib/GCC" -I"../src/ASF/common/utils" -
I"../src/ASF/sam0/utils/cmsis/samd21/include" -
I"../src/ASF/sam0/utils/cmsis/samd21/source" -
I"../src/ASF/sam0/drivers/system"
-I"../src/ASF/sam0/drivers/system/clock/clock_samd21_r21_da_ha1" -
I"../src/ASF/sam0/drivers/system/clock" -
I"../src/ASF/sam0/drivers/system/interrupt" -
I"../src/ASF/sam0/drivers/system/interrupt/system_interrupt_samd21" -
I"../src/ASF/sam0/drivers/system/pinmux" -
I"../src/ASF/sam0/drivers/system/power" -
I"../src/ASF/sam0/drivers/system/power/power_sam_d_r_h" -
I"../src/ASF/sam0/drivers/system/reset" -
I"../src/ASF/sam0/drivers/system/reset/reset_sam_d_r_h" -
I"../src/ASF/common2/boards/user_board" -I"../src" -I"../src/config" -
I"../src/ASF/common2/services/delay" -
I"../src/ASF/common2/services/delay/sam0" -
I"../src/ASF/common/services/ioport" -I"../src/ASF/sam0/drivers/sercom" -
I"../src/ASF/sam0/drivers/sercom/i2c" -O1 -fdata-sections -ffunction-
sections -mlong-calls -g3 -Wall -mcpu=cortex-m0plus -c -pipe -fno-strict-
aliasing -Wall -Wstrict-prototypes -Wmissing-prototypes -Werror-implicit-
function-declaration -Wpointer-arith -std=gnu99 -ffunction-sections -fdata-
sections -Wchar-subscripts -Wcomment -Wformat=2 -Wimplicit-int -Wmain -
Wparentheses -Wsequence-point -Wreturn-type -Wswitch -Wtrigraphs -Wunused -
Wuninitialized -Wunknown-pragmas -Wfloat-equal -Wundef -Wshadow -Wbad-
function-cast -Wwrite-strings -Wsign-compare -Waggregate-return -Wmissing-
declarations -Wformat -Wmissing-format-attribute -Wno-deprecated-
declarations -Wpacked -Wredundant-decls -Wnested-externs -Wlong-long -
Wunreachable-code -Wcast-align --param max-inline-insns-single=500 -MD -MP -
MF "src/main.d" -MT"src/main.d" -MT"src/main.o" -o "src/main.o"
"../src/main.c"
Finished building: ../src/main.c
src/main.o: In function `configure_i2c_master':
C:\Users\benvo\Documents\Atmel
Studio\7.0\GccBoardProject1\GccBoardProject1\src\main.c(69,1): error:
undefined reference to `i2c_master_init'
src/main.o: In function `main':
C:\Users\benvo\Documents\Atmel
Studio\7.0\GccBoardProject1\GccBoardProject1\src\main.c(103,1): error:
undefined reference to `i2c_master_read_packet_wait'
collect2.exe(0,0): error: ld returned 1 exit status
make: *** [GccBoardProject1.elf] Error 1
Building target: GccBoardProject1.elf
Invoking: ARM/GNU Linker : 6.3.1
"C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\arm\arm-gnu-
toolchain\bin\arm-none-eabi-gcc.exe" -o GccBoardProject1.elf
src/ASF/sam0/drivers/sercom/sercom.o
src/ASF/sam0/drivers/sercom/sercom_interrupt.o
src/ASF/common2/services/delay/sam0/systick_counter.o
src/ASF/common2/boards/user_board/init.o
src/ASF/common/utils/interrupt/interrupt_sam_nvic.o
src/ASF/sam0/drivers/system/clock/clock_samd21_r21_da_ha1/clock.o
src/ASF/sam0/drivers/system/clock/clock_samd21_r21_da_ha1/gclk.o
src/ASF/sam0/drivers/system/interrupt/system_interrupt.o
src/ASF/sam0/drivers/system/pinmux/pinmux.o
src/ASF/sam0/drivers/system/system.o
src/ASF/sam0/utils/cmsis/samd21/source/gcc/startup_samd21.o
src/ASF/sam0/utils/cmsis/samd21/source/system_samd21.o
src/ASF/sam0/utils/syscalls/gcc/syscalls.o src/main.o -mthumb -Wl,-
Map="GccBoardProject1.map" --specs=nano.specs -Wl,--start-group -
larm_cortexM0l_math -lm -Wl,--end-group -
L"../src/ASF/thirdparty/CMSIS/Lib/GCC" -Wl,--gc-sections -mcpu=cortex-
m0plus -Wl,--entry=Reset_Handler -Wl,--cref -mthumb -
T../src/ASF/sam0/utils/linker_scripts/samd21/gcc/samd21g18a_flash.ld
C:\Users\benvo\Documents\Atmel
Studio\7.0\GccBoardProject1\GccBoardProject1\Debug\Makefile(333,1): error:
recipe for target 'GccBoardProject1.elf' failed
The command exited with code 2.
Done executing task "RunCompilerTask" -- FAILED.
Done building target "CoreBuild" in project "GccBoardProject1.cproj" --
FAILED.
Done building project "GccBoardProject1.cproj" -- FAILED.
Build FAILED.
========== Build: 0 succeeded or up-to-date, 1 failed, 0 skipped ==========
TAGS:
Tools, Atmel Software Framework (ASF) and Atmel Start (ASFv4), all
architectures
Hello and thank you for your assistance.
I'm attempting to create a simple 'hello world' using only low-level OS X kernel calls to allocate memory and write out to stdout. Why? I'm finishing up chapter 8 of 2nd Edition K&R which is focused on writing standard file library from scratch. It is, of course, totally out of date but the concept of the chapter remains. Anyway, I cannot seem to figure out how to properly link to get everything to work out and are thus earning myself lots of nice undefined symbol errors.
I have parsed through many other questions causing the same error, but have not found any that address how to link in the kernel library I'm attempting to use. The crazy long path in the third #include was needed to just get the thing to compile even prior to the link errors.
The Code:
#include <fcntl.h>
#include <unistd.h> // equivalent to (K&R) #include "syscalls.h"
#include </Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/libkern/OSMalloc.h> // for low-level memory allocation
#define MINSTDIOTAG "com.apple.minstdio" // Used by OSMalloc from <libkern/OSMalloc.h>
#define PAGE_SIZE_64K (64 * 1024) // Page size to allocate
int main(void) {
char *base = NULL; // Memory buffer
char *ptr = base; // Location in buffer
// Create tag
OSMallocTag mytag = OSMalloc_Tagalloc(MINSTDIOTAG, OSMT_DEFAULT);
// Attempt to allocate PAGE_SIZE_64K of memory
if ((base = (char *)OSMalloc(PAGE_SIZE_64K, mytag)) == NULL)
return 1;
ptr = base;
// Stuff the buffer with stuff
*ptr++ = 'f';
*ptr++ = 'o';
*ptr++ = 'o';
*ptr++ = '\n';
*ptr = '\0';
// Write it out to stdout
(void)write(STDOUT_FILENO, base, (size_t)(ptr - base));
// Free allocated memory
OSFree(base, PAGE_SIZE_64K, mytag);
// Get out of Dodge City, Kansas
return 0;
}
Makefile:
BIN = ../../bin
ODIR = obj
CC = cc
CFLAGS = -std=c99 -Wall -g -I.
_OBJ = minstdio3.o
_BIN = minstdio3
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
.PHONY: all clean
all: $(_BIN)
clean:
rm -rv $(ODIR) $(_BIN)
minstdio3: $(ODIR)/minstdio3.o
$(CC) $(CFLAGS) $^ -o $#
cp -v $# $(BIN)/$#
$(ODIR)/%.o: %.c $(DEPS)
mkdir -pv $(ODIR)
$(CC) $(CFLAGS) -c -o $# $<
Errors Received:
Todds-MBP-2:cbasics todddecker$ make
mkdir -pv obj
cc -std=c99 -Wall -g -I. -c -o obj/minstdio3.o minstdio3.c
cc -std=c99 -Wall -g -I. obj/minstdio3.o -o minstdio3
Undefined symbols for architecture x86_64:
"_OSFree", referenced from:
_main in minstdio3.o
"_OSMalloc", referenced from:
_main in minstdio3.o
"_OSMalloc_Tagalloc", referenced from:
_main in minstdio3.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [minstdio3] Error 1
-- EDITS --
"Why are you not using the sbrk system call if you want low-level? This would match your use of write and shouldn't give any linking issues." (from CRD)
Using 'sbrk' (and it's cousin 'brk') was the original path I was headed down; however, the man page for 'sbrk' states, "The brk and sbrk functions are historical curiosities left over from earlier days before the advent of virtual memory management." This statement put me on a path toward trying to discover its replacement. 'malloc' is, of course, the correct and normal utility for memory allocation. However, K&R Chapter 8 is all about writing your own from base OS system calls. So, the base call I was able to find for OS X Darwin is 'OSMalloc' which I'm trying to use.
OSMalloc is only available for writing the kernel itself (kernel extensions, device drivers). User programs have to use sbrk.
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.
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.
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.