I've only used AVR and Arduino before which really don't count as embed! so I have a little trouble compiling my blinky.
I'm mainly a PC programmer. I have an LPC1768 dev board!
Here's what I did:
I first installed arm-none-eabi-gcc on my Ubuntu virtual machine (I have a ubuntu dual boot but I wanted to try it here first to learn)
Secondly I wrote a small code which uses the lpc17xx.h header and does nothing but turn a GPIO on and high, I then compiled it with
arm-none-eabi-gcc -Wall -mcpu=cortex-m3 -mlittle-endian -mthumb -DLPX17xx -Os -c main.c -o main.o
It worked! I repeated this for all of the files("core_cm3.h", "LPC17xx.h", "system_LPC17xx.c") and it worked too, but when I tried to compile "startup_lpc17xx.s" it gave me a bunch of errors saying "startup_LPC17xx.s:272: Error: bad instruction".
So I found an already compiled .o version of this file in keil folders and used it instead.
I googled and found an lpc1768 linker script and ran this:
arm-none-eabi-gcc -mcpu=cortex-m3 -mlittle-endian -mthumb -DLPC17xx -TLPC17xx.ld -Wl,--gc-sections system_LPC17xx.o main.o startup_LPC17xx.o -o main.elf
and I get this error: "startup_LPC17xx.o: file not recognized: File format not recognized
collect2: error: ld returned 1 exit status"
Can anyone help me I also edited the linker script, I changed "FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K" to "FLASH (rx) : ORIGIN = 0x2000 , LENGTH = 512K" because the board says the code should start from here as it has a bootloader and my pc recogonizes it as a USB storage
also the board manual says I should add "NO_CRP" to asm tab of keil project options. I don't know what this is so I've no idea what to do.
I did manage to create a file in windows with CrossStudios but my board didn't blink the leds the same code worked in keil but I rather fix my GCC toolchain
I'm a begginer and I don't know how to use makefile or write a linker script or a startup code! I don't know much on how the code runs either
I don't own such board, so I can't provide instructions on how to build the whole project.
However, googling the problematic file, startup_LPC17xx.s, shows 2 different versions of the same file. One written using the ARM assembly syntax understood by the Keil toolset, one written using the GNU assembly syntax understood by the GNU ASsembler. Chances are that you're trying to assemble the Keil's version with GCC, which uses GNU AS to parse and assemble .S files.
Did you try to clone and compile the linked project ?
Thanks a lot for answer
And I didn't know GCC and arm have different assembly syntax strange....
and there's nothing special about my board. just have to turn the app into a .bin with 0x2000 as starting address and ad NO_CRP to asm :S
I don't have access to anything to try it now sadly but if it doesn't work it most be with my code. the thing is i compiled it successfully!
If I'm not mistaken, CRP refers to the Code Read Protection feature activated by reading an address at 0x2fc.
It seems that writing 0xffffffff at 0x2fc disable this feature.
According the documentation linked above (page 5), you can define NO_CRP in you C code like this :
#define NO_CRP 0xFFFFFFFF #define NO_ISP_MAGIC 0x4E697370 #define CRP1_MAGIC 0x12345678 #define CRP2_MAGIC 0x87654321 /**** DANGER CRP3 WILL LOCK PART TO ALL READS and WRITES ****/ /*********** #define CRP3_MAGIC xxxx 0x43218765 *************/ #define CURRENT_CRP_SETTING NO_CRP __attribute__ ((section(".crp"))) const uint32_t CRP_WORD = CURRENT_CRP_SETTING;
And the add this to your linker code :
ENTRY(ResetISR) SECTIONS { .text : { KEEP(*(.isr_vector)) . = 0x000002FC; KEEP(*(.crp)) *(.text*) *(.rodata*) } > MFlash32 ...}
ENTRY(ResetISR)
SECTIONS
{
.text :
KEEP(*(.isr_vector))
. = 0x000002FC;
KEEP(*(.crp))
*(.text*)
*(.rodata*)
} > MFlash32
...
}
If you search for NO_CRP on Github, and select "Code" after submitting the search, you might find some working examples, like this.
Sorry to ask this here. but as it sounds like ARM is a lot different and I can't ask questions here for every app I'm going to write, can you recommend me any book to learn these myself? a book or a website or anything! O'Reilly's embedded book never mentioned this kind of stuff, at least not until chapter 3!
While I don't have any recommendations for books on "how to create linker scripts", you might be interested by The Definitive Guide to ARM® CORTEX®-M3 and CORTEX®-M4 Processors (Third Edition).
When it comes to ARM programming, what helped me the most was building my first "Hello world" assembler script, that ran on an Android device through adb shell.
The Hello world script was :
.data msg: .ascii "Hello, ARM!\n" len = . - msg .text .globl _start _start: /* syscall write(int fd, const void *buf, size_t count) */ mov %r0, $1 /* fd -> stdout */ ldr %r1, =msg /* buf -> msg */ ldr %r2, =len /* count -> len(msg) */ mov %r7, $4 /* write is syscall #4 */ svc $0 /* invoke syscall */ /* syscall exit(int status) */ mov %r0, $0 /* status -> 0 */ mov %r7, $1 /* exit is syscall #1 */ svc $0 /* invoke syscall */
And compiled like this :
armv7a-hardfloat-linux-gnueabi-as -o hello.o hello.s armv7a-hardfloat-linux-gnueabi-ld -o hello hello.o adb push hello /data/local/tmp adb shell /data/local/tmp/hello
Hello, ARM!
Then, I searched for a list of Linux system calls numbers for ARM and began playing with the code.
I also learned how to execute ARM code directly on a virtual machine, using this tutorial : 3. Hello ARM . You're maybe searching for that kind of tutorials. QEMU allows you to use GDB to step on each instruction executed by the virtual machine, and check/change the registers between instructions.
I learned the ELF structure and ARM machine code format by creating a small ELF linker myself in ruby, using :
- ARM Architecture Reference Manual, from ARM. You can get it from the ARM website. The instruction encoding section is a gold mine to understand how the instructions can be encoded.
- Executable and Linking Format (ELF) Specification, in order to understand the architecture of ELF files.
- A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux
I didn't go very far (Never implemented a Global Offset Table/Procedure Linkage Table), but I learned enough to understand the architecture of ELF objects (headers and sections) and how calling procedures from external libraries and dlopen() worked, which demystified a LOT of things.
Embedded programming is complicated thanks a lot for your help I have an android phone so i can start with he first one
It's more about knowing the conventions, especially when loading code on a machine directly or through a boot loader, than the programming itself. Though, I haven't tested direct hardware programming.
IMHO, the best way to get working with programming tasks riddled with a lot of conventions is to start from a working project, reduce it to its bare minimum, and go from there.
Also, you might want to create your own tools with any programming language you master, in order to have more control on your development process. For example, generating raw binaries with machine code in Python, Ruby or Javascript is rather easy. In order to generate an executable with an entry point at 0x10000 and ten 32-bit instructions, you only need to generate a file with 0x10000 zeros and write the machine code of these ten instructions, in little endian format (e.g. 0x12345678 -> 0x78563412). Python and Ruby have ready made data-packers that already deal with Big endian, Little Endian encodings of short/int/long/float/double data types, so it should not take too much time.
Android systems are great to test ARM assembly code and libraries quickly. However, due to Android's security constraints, if you want to do more advanced operations you might need to go through a NativeActivity setup and use the common libraries available (OpenGL/AL/CV, ...), or try to find a way to create a custom ROM.
Thanks a lot for your help I forgot i also have 2 raspberry pies I can learn a bit there too !