Andrei put up a posts about how a UART works, different connection mechanisms, and making a UART work on the STM32F4 using Cube. I know he’s planning on talking about receiving characters and doing this all efficiently (DMA!).
But what good is a UART? Why is it the second thing I get set up? (The first being the ubiquitous blinking light.)
A UART gives me a way to type at my embedded software from my computer, testing the hardware as I bring it up as well as the software drivers and algorithm. Even better, it lets other people type at my software, someone like the electrical engineer who says that the GPIO is connected when I can clearly see it isn’t doing anything, or someone like a manufacturing engineer who needs to verify the peripherals work before allowing the board to be shipped.
For all of that I need a command console. I’m sick of writing command consoles for different clients. I finally wrote one for myself that I can then reuse for clients who need it. I wrote it for you too, public domain licensed. The code is in github.
The test code runs on Visual Studio… that is pretty embarrassing but I wanted an easy test method. I also used clang to verify it compiles cleanly. The goal is to have this be platform agnostic anyway (and all of my embedded compilers were being mean to me when I started developing this).
I had a lot of goals: no printf and scanf, sometimes no atoi or itoa, only edit one file to add commands, and keep the UART code separate (especially since I prototyped in Visual Studio using standard IO). I also wanted the console to return regularly so I can add some other main loop calls; I didn’t want the console to take over the whole system.
I ended up with four files:
The very small main.c calls ConsoleInit at setup time and then repeatedly calls ConsoleProcess.
To hide the UART details, I have consoleIO.c that should be easily mapped to the driver produced by Cube.
To add a new command, you’ll need to edit consoleCommands.c by putting a function prototype, adding it to the command table, then implementing the function.
Finally, console.c is in the middle of everything, juggling the connections between each of these. It looks for input from the console, tries to match it against the command table, and calls the associated function.
I implemented a version command (ver), a command to list the table’s help strings (help), and a comment indicator (;).
Simply matching the command and being able to print out static data was not enough so I added a two commands to receive and send parameters. The u16h command reads in an unsigned 16-bit hex value (no 0x prefix) and prints out a hex value. The int command reads a signed 16-bit decimal number and prints it out again as both the integer and the associated hex value.
This isn’t a huge pile of code and there are plenty of complex consoles out there but it is nice to have a leg up the next time I need a simple one.
One final note: leaving your command console enabled after manufacturing is a gaping security hole. You should disable or lock it before shipping (or require some authentication before enabling it).