A reproducible, containerised cross-compilation environment for the Texas Instruments TMS570LS1224 (Cortex-R4F, big-endian) on Linux.
The TMS570LS1224 runs in big-endian mode. Prebuilt arm-none-eabi-gcc distributions (from Arch, Ubuntu, ARM's own releases, etc.) ship runtime libraries compiled for little-endian only. Linking with -mbig-endian against those libraries fails with errors like:
crti.o: compiled for a little endian system and target is big endian
Our solution is to build a custom GCC toolchain whose runtime libraries (libgcc, newlib, crt0, etc.) are compiled big-endian from the start. This guide packages that toolchain inside a Docker image so the build environment is isolated, reproducible, and portable.
- Docker installed and running
- HalCoGen installed (Windows/Linux) to generate peripheral driver code
your-repo/
├── Dockerfile
├── source/
│ ├── *.c ← HalCoGen generated + your own C files
│ ├── *.s ← HalCoGen generated assembly (must be .s, not .asm)
│ └── sys_link.ld ← HalCoGen generated linker script
├── include/
│ └── *.h ← HalCoGen generated headers
└── Makefile
Before generating code, in HalCoGen go to Tools → GCC Tools and make sure that option is selected. This ensures the assembler files are generated as .s (GCC syntax) rather than .asm (TI syntax). The .asm files will produce thousands of errors with GCC.
After selecting GCC Tools, regenerate all files.
Builds a two-stage Docker image. Stage 1 compiles binutils, GCC, and newlib from source with big-endian flags baked in. Stage 2 is a slim final image containing only the finished toolchain.
This is a one-time step. From the repo root:
docker build -t tms570-toolchain .This takes 25–35 minutes the first time. Docker caches every layer, so subsequent builds (e.g. after changing only the Makefile) are nearly instant.
From your repo root every time you want to build:
docker run --rm -v $(pwd):/project tms570-toolchain make--rmdeletes the container after it exits, keeping things tidy-v $(pwd):/projectmounts your local source tree into the container- Your compiled
firmware.elfandfirmware.binwill appear in your repo root on the host
To clean build artifacts:
docker run --rm -v $(pwd):/project tms570-toolchain make cleanTo drop into an interactive shell for debugging:
docker run --rm -it -v $(pwd):/project tms570-toolchain bashBefore flashing, confirm the ELF is actually big-endian:
docker run --rm -v $(pwd):/project tms570-toolchain arm-none-eabi-readelf -h firmware.elf | grep DataExpected output:
Data: 2's complement, big endian
If it says little endian, something is wrong with your flags and you should not flash it — the MCU will jump to an undefined instruction immediately on boot.
| Flag | Reason |
|---|---|
-mcpu=cortex-r4 |
Exact CPU core on TMS570LS1224 |
-mfpu=vfpv3-d16 |
FPU present on Cortex-R4F |
-mfloat-abi=hard |
Use FPU registers for float args/return values |
-mbig-endian |
TMS570 operates in big-endian mode |
-marm |
Reset vector executes in ARM state, not Thumb |
-nostartfiles |
HalCoGen provides its own startup/intvecs assembly |
- Do not use
-mthumbat the top level. The TMS570 boots in ARM state and HalCoGen'ssys_intvecs.sis written in ARM state. Mixing ARM and Thumb without explicit interworking stubs causes the same "undefined instruction" crash as the endianness bug. -lnosysstubs out syscalls (_write,_read,_sbrk, etc.) so newlib links cleanly without a full OS. If you wantprintfoutput over SCI/UART, implement_writeyourself to redirect to the SCI driver.- The toolchain image is self-contained. You can push it to a registry (Docker Hub, GHCR, etc.) and pull it on any machine without rebuilding.
- Special thank you to this repo.