Shell Integration : Setup

Foreword : each STM32 is a bit different from the others, or a lot. I can’t cover every existing and future device, not to mention the specifics of whatever board you’re using, so this guide should serve only as that : a guide, not a recipe. For the purpose of example, I will be targeting the NUCLEO-F303K8. Mainly because it’s cheap enough you can buy one easily if you don’t have any STM32 board yet. Also, I will be using a UART as the shell interface, since the NUCLEO-F303K8 also acts as a USB-to-UART bridge. Native USB for STM Shell will be covered separately.

 

Integrating STM Shell into your project is a three-step process :

  • Setup your project for STM Shell compatibility
  • Clone the STM Shell repository into your project
  • Connect the plumbing between your project and STM Shell

This page covers the setup step.

STM Shell requires a UART, interrupts and DMA. For this guide I will be using the UART that is wired to the NUCLEO module’s on-board ST-LINK probe. If you’re not familiar, each NUCLEO board carries its own JTAG probe that can be used for flashing and debugging. That probe also acts as a USB to UART bridge and is typically connected to one of the UART on the target STM32. This is a simple, effective way to let developers do such things as… develop shell libraries.

If you’re using a different NUCLEO, you may want to check its manual and schematics to find out if the probe and UART are indeed connected, or if you need to close some solder bridges. The UART may also be routed to two header pins. If you’re using the UART to communicate through the probe, you’ll want to leave those two pins unconnected.

1.   Project Creation

Launch STM32CubeIDE. You’ve reached the point where you’re considering adding a shell to your projects, so I’ll assume you know your way around the project creation wizard. If you’re using a NUCLEO board, do make sure to target the board (and not the chip) by using the Board Selector tab. This will let the wizard initialize the microcontroller’s peripherals to match the hardware on the board. That is a useful time-saver because one of those peripherals is the UART connected to the ST-LINK probe that we want to use.

You’ll want to click Yes

This gives you a boilerplate configuration that looks like this:

The VCP_TX and VCP_RX pins are for the UART connected to the NUCLEO’s ST-LINK. VCP stands for Virtual COM Port, and if you look around my site you’ll find I’ve written extensively about that. If your board isn’t a NUCLEO, you will need to setup a UART yourself and add the necessary hardware to connect it to your PC.

The MCO pin is the Master Clock Output from the ST-LINK. That probe is itself an STM32 and this signal is generated by its own PLL and used to clock the F303. If your board has a different clocking arrangement, make sure to configure it properly (as usual, RTFM). It’s hard to execute code without a clock.

The SWDIO and SWCLK are the SWD interface the ST-LINK uses to flash and debug the microcontroller. It’s JTAG but with fewer pins. Again, if your board is built different, make sure to set that up correctly as well.

2.   Microcontroller Configuration

Upon project creation, STM32CubeIDE should be showing you your project’s .ioc file in its configuration tool, which is basically STM32CubeMX integrated into the IDE. If that didn’t happen or you closed it, find the .ioc file in your project’s root and open it.

Pick the UART you intend to use. If you’re using a custom board, you need to choose a UART or USART that supports full-duplex asynchronous mode, listed in the GUI as “Asynchronous”. STM Shell essentially runs two separate processes to handle incoming keystrokes and outgoing output.

The UART parameters (baud rate, parity, etc) can be whatever you need. However, this being a terminal interface, it has to be compatible with your terminal and thus the symbols need to be capable of carrying a C “char”, meaning 7 or 8 bits. Go with 8 bits words.

Under NVIC Settings, you must enable the UART’s global interrupt. It’s what STM Shell relies on to process incoming keystrokes efficiently.

Under DMA Settings, you must enable the UART’s DMA TX request. It’s what STM Shell relies on to stream command output to your terminal efficiently. If you’ve never done it before, go to your UART’s DMA Settings tab, which should be empty, and click the “Add” button. This will let you choose which DMA request to add :

Select the TX (transmit) request. You will then be able to configure it, although STM Shell works with the default configuration. Compare yours to this screenshot and change what might be different :

New to DMA ? Let me talk you through it: this is a UART transmission request, therefore the data goes from memory to peripheral. The source of the data, the memory, is going to be a string (an array of bytes) therefore the DMA controller must increment its address every time it sends out a byte. The destination, however, is the transmit register of the UART, which is at a fixed address that should not be incremented throughout the DMA transfer. We’re dealing with character strings and an 8-bit UART therefore the data width is one byte, on both sides. “Normal” mode means each DMA transfer is performed only once, by opposition to “Circular” mode, where the DMA controller would loop and keep sending the same character string over and over again.

Note that enabling a DMA request also enables the interrupt for the DMA channel that will perform the request. This is perfectly normal, it happens to all microcontrollers when they hit puberty.

And that’s it for hardware configuration ! Well, almost.

Don’t forget to check the microcontroller’s clock configuration, although CubeIDE should give you an error message if, for example, your UART isn’t clocked fast enough to produce the baud rate you’ve set.

Also, if you’re not using a NUCLEO, you still have to configure your JTAG or SWD interface, your clock source, … but this is beyond the scope of this document. Not to mention your board-specific peripherals.

Myself, I’ll add an output pin to control the user LED on the NUCLEO-F303K8. That LED’s anode is tied to pin PB3, so I’ll set it as a push-pull output and name it “LED” for originality’s sake. This is a Chekov’s gun, by the way : I’m foreshadowing the use of that LED when I show you how to create your own shell commands.

Once that’s done, it’s time to generate some code. You probably know the drill : in the Project menu, hit Generate Code. After a few seconds CubeIDE will switch to an editor showing you your brand-new “main.c”

That means the easy part is over.