Tag Archives: Firmware

Bringing Back the Stellaris Evalbot

The Stellaris Evalbot devkit
The Stellaris Evalbot devkit

TLDR; https://github.com/albertskog/stellaris-evalbot-fw

In my pile of old development kits is this little robot from Texas Instruments. The microcontroller on it is the LM3S9B92, an old (and, I seem to recall, fairly buggy) ARM Cortex-M3 chip. It must have gathered dust for around ten years at this point, but I did not want to throw it away. Instead, let’s see if we can bring it back to life!

I found some 4-11 year old projects on Github but was not able to make them compile. I also had some old training material from the course where I got the bot, but it was missing the TI StellarisWare SDK. Everywhere I looked online, including TI’s own E2E forum, the links to StellarisWare were dead since this family of chips has been deprecated and out of production for a long time. I finally found what seems to be the last working download link on the Internet:

🎉🎉 https://www.ti.com/tool/SW-DRL#downloads 🎉🎉

I briefly tried to get Texas Instrument’s own IDE Code Composer Studio to recognize this historical artifact but soon gave up since I much prefer to work in VSCodium anyway.

With the repositories I found online and an example project in StellarisWare I was finally able to compile some code by simply running make in a terminal (on my computer running Ubuntu 20.04). To get this working, you also need the gcc-arm-none-eabi suite of GCC tools for ARM installed (see Github repository for more instructions).

Luckily the LM3S9B92 is supported by OpenOCD, so after some trial and error, figuring out the location of some configuration files that had moved, I was finally able to connect to the board with openocd -f evalbot.cfg.

Contents of evalbot.cfg:

source [find interface/ftdi/luminary.cfg]
source [find target/stellaris.cfg]

I also created an alternative file evalbot_flash.cfg to flash a binary directly:

source [find evalbot.cfg]

init
halt
flash write_image erase ./gcc/project.bin
reset
shutdown

With this in place, I could create a workspace in VSCodium (you might prefer Visual Studio Code) and add a few tasks to .vscode/tasks.json:

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "make",
            "type": "process",
            "command": "make",
            "args": [],
            "problemMatcher": ["$gcc"],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        },
        {
            "label": "upload",
            "type": "process",
            "command": "openocd",
            "args": ["-f", "evalbot_flash.cfg"],
            "problemMatcher": ["$gcc"],
            "dependsOn": ["make"]
        },
        {
            "label": "clean",
            "type": "process",
            "command": "make",
            "args": ["clean"],
            "problemMatcher": ["$gcc"]
        }
    ]
}

Investigating a bit more, I found it’s even possible to do interactive debugging! You will need the Cortex-Debug extension for this:

VSCodium: https://open-vsx.org/extension/marus25/cortex-debug
VSCode: https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug

And then add this to .vscode/launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "cortex-debug",
            "request": "launch",
            "name": "Debug",
            "servertype": "openocd",
            "cwd": "${workspaceRoot}",
            "preLaunchTask": "make",
            "runToMain": true,
            "executable": "${workspaceFolder}/gcc/project.axf",
            "device": "LM3S9B92",
            "configFiles": ["evalbot.cfg"],
            "preRestartCommands": [
                "monitor reset halt",
                "break main"
            ]
        }
    ]
}

With this, you should now be able to launch a debug session!

With this in place, I made a basic robot example that drives around and avoids obstacles. I had come across a bunch of “helper” functions that look like they were distributed with the kit back in the day. One thing to look out for if you use them yourself is the function MotorSpeed(tSide ucMotor, unsigned short usPercent). ⚠️ Be warned! ⚠️ The parameter usPercent is not in percent, it is percent “in fixed point 8.8 notation”, meaning you need to shift your percent value 8 bits: speed = 50 << 8! Using the value 50 directly will in fact give you a tiny tiny speed that is not enough to make the wheels turn.

I gathered the code and some more detailed instructions in a Github repository. At the time of writing it is just a basic example as mentioned, but I might add more features in the future! Here it is:

https://github.com/albertskog/stellaris-evalbot-fw

Strict Aliasing – yet another way for C-code to blow up

Recently, I got to learn about Strict Aliasing in C. It is yet another thing that can cause your C code work perfectly fine today and then blow up because of Undefined Behavior down the line. One example of what not to do is casting an array of uint8_t (like a payload from a communications protocol) into a struct (like the message you are receiving):

void receive_data(uint8_t * payload, uint16_t length) {
    ... // Sanity checking etc
    my_struct_t * my_struct = (my_struct_t *) payload; // Don't do this!
    do_stuff(my_struct->some_field);
}

A better way is to use memcpy:

void receive_data(uint8_t * payload, uint16_t length) {
    ... // Sanity checking etc
    my_struct_t my_struct;
    memcpy(my_struct, payload, sizeof(my_struct_t)); // Do this instead!
    do_stuff(my_struct.some_field);
}

One reason this kind or “reinterpret cast” is not allowed is that you can’t be sure that accessing a field within the struct after typecasting will be a properly word-aligned memory access.

For more details, here is a write-up with more examples which also explains the situation for C++: https://gist.github.com/shafik/848ae25ee209f698763cffee272a58f8