However many times you may want to connect a real device to a virtual serial cable. This can be done using program hub4com. While the com0com works on the “driver side” of the com port the hub4com works on the “software side” and can be used to connect mutliple com ports (virtual or real ports) together. Professional Open Source Autopilot Stack. PX4 Drone Autopilot has 73 repositories available. Follow their code on GitHub. The mass flow meter does not measure the volume per unit time (e.g., cubic meters per second) passing through the device; it measures the mass per unit time (e.g., kilograms per second) flowing through the device. Volumetric flow rate is the mass flow rate divided by the fluid density. If the density is constant, then the relationship is simple.
If you’ve been reading the posts about STM32s that I’ve been writing, I owe you an apology. Usually when people write microcontroller tutorials,
UART is one of the first peripherals that they talk about, and I’ve gone far too long without mentioning it. It is such a fundamental peripheral that I vaguely thought I’d already written about it until I got a couple of comments asking about it, so thank you for those reminders!
UART stands for “Universal Asynchronous Receiver / Transmitter”, and it is a very simple serial communication interface. In its most basic form, it only uses two data signals: “Receive” (
RX) and “Transmit” (
TX). Since it is asynchronous (no clock signal), both devices need to use the same “baud rate”, which is basically the transmission frequency measured in Hertz. If you have a baud rate of 9600, then you expect a new bit every 1 / 9600 of a second. (But technically, your actual transmission frequency will be slightly lower than the baud rate, because the standard includes extra “control” bits which are sent in addition to the actual data.)
One of the most common uses of
UART is to transmit strings of text or binary data between devices. That, combined with the availability of cheap off-the-shelf
USB / UART bridges, makes it a popular way to add some interactivity and a working
printf(...) function to bare-metal applications.
And while a simple 2-wire
UART connection is reliable enough for most purposes, there is also an extended
USART standard which adds an optional “clock” line to synchronize the two devices’ timing; the extra “S” stands for “Synchronous”. The standards are otherwise very similar, so you might see
USART used interchangeably in some places. There are also a set of extra “flow control” signals, but I’m not going to talk about those or
USART functionality in this post.
I will cover a few basic ways to use the STM32
UART peripherals, though:
- Setting up the
UARTperipheral to send / receive data one byte at a time.
- Implementing the C standard library’s
printf(...)function to send text strings over
- Using interrupts to receive data as it arrives.
- Setting up a “ring buffer” to handle continuous data reception.
If any of that sounds interesting, keep reading! The target hardware will be either an
STM32L432KC “Nucleo-32” board or an
STM32F103C8 “pill” board; they cost around $11 or $2-5 respectively. The “Nucelo” boards are easier to use, because they include a debugger. If you use a “pill” board, you’ll also need an
ST-LINK debugger and a
USB / UART bridge such as a
CP2102 board. And these examples are all available in a GitHub repository, if you just want a quick reference.
Most STM32 chips contain several
USART peripherals, including simpler
UART peripherals which do not support the extra “synchronization” clock signal. You’ll probably have at least 3 of them, but some larger chips have 8 or more since it is such a common interface. Like with other STM32 peripherals, you can check your chip’s datasheet to see which pins can be used with which peripherals.
For these examples, I’ll use the
USART2 peripheral. If you’re using an
STM32L432KC “Nucleo-32” board, pins
A15 are connected to its built-in debugger which will forward the serial connection over the board’s USB connector. If you’re using an
STM32F103C8 “pill” board, pins
A3 are connected to the
The first step, as usual, is to initialize the chip by setting up the core system clock. I set up this project similarly to the ones in my previous tutorials, with a
Makefile capable of building the program for different targets. You can see how that works in the GitHub repository, but tl;dr, the
Makefile defines different compilation flags depending on the target chip. This is one way to adjust your code for different hardware, but you can also write separate “port” files for each target chip when your project outgrows it:
The floating-point unit is also enabled for
STM32L4 targets, because it will be required by the standard library’s
printf function later on. The FPU is part of the ARM Cortex-M CPU, so you won’t find much information about it in the STM32 reference manuals. Instead, check the ARM infocenter or the Cortex-M4 technical reference manual.
Next, we need to enable the peripheral clocks and configure the GPIO pins:
I don’t think I’ve talked about
STM32F1 GPIO pin configurations before, and they work a little differently from most other STM32 lines. Each pin has four configuration bits spread across two 32-bit registers.
CRL configures pins 0-7, and
CRH configures pins 8-15. The pin settings are spread across two “configuration” bits and two “mode” bits:
Notice that the
RX pin (
A3) is configured as a floating input rather than an alternate-function output. Sometimes it can be tricky to get the
STM32F1 pin configurations right for different peripherals, so keep in mind that the “alternate function” configurations are not always used with “input” peripheral signals.
Once you’ve enabled the peripheral and set up the GPIO pins, you’re almost done. The
UART peripherals’ reset configurations match the most common settings of 8 bits per byte, no parity checks, and 1 “stop bit”. If you need a non-standard configuration, you can find more information about these settings in the “USART registers” section of your chip’s reference manual. The
STM32L4 peripherals are slightly different, but in both cases, the parity settings and number of bits per byte are in
CR1 and the number of stop bits are in
You’ll also need to set the baud rate so that the peripheral knows how quickly it should send and receive data. There’s a special
BRR Baud Rate Register which contains a factor to divide the core clock speed by in order to get the desired baud rate. The
STM32L4 peripheral sets its baud rate equal to the core clock rate divided by the
BRR register’s value, but the
STM32F1 peripheral is a bit more complex. It divides by (
BRR * 16), with the register’s 4 lowest bits representing a fractional value. So given the
SystemCoreClock values set above, we can configure a baud rate of 9600 like this:
(In computing, the term “Mantissa” is often used to describe the numbers left of a decimal point in a fractional number.)
The way that the reference manuals describe baud rate configurations can be a little confusing, but they do include a few example calculations under a “baud rate generation” sub-heading of the “USART functional description” section.
Finally, you can turn the peripheral on by setting the
TE (Transmit Enable), and
RE (Receive Enable) bits in the
And that’s it! You are now ready to transmit and receive data. You can test the peripheral with a simple “echo” program which repeats bytes from its “receive” line onto its “transmit” line:
TXE (Transmitter Empty) bit will be set when the peripheral’s “transmit” register is ready to accept new data; you can also check the
TC (Transfer Complete) bit to see when the peripheral has finished sending all of its pending data. And similarly, the
RXNE (Receiver Not Empty) bit will be set when the peripheral’s “receive” register contains a new byte of data. The
TXE bit is automatically reset when you write a new byte of data to the
UART data register, and the
RXNE bit is automatically reset when you read a byte from it. There is a shared
DR Data Register in the
STM32F1 peripheral, and separate
RDR Transmit / Receive Data Registers in the
And if you don’t want to create a project and copy / paste all of this code, you can find a full example project on GitHub.
If you flash this example “echo” program to your board and connect to the
UART interface through a serial terminal on your computer, you should be able to type into the terminal and see your keystrokes repeated back. But how do you connect to the serial interface from you computer? (Feel free to skip down to the “Implementing ‘printf'” section if you already have a preferred way of doing this.)
If you are using one of ST’s “Nucleo” boards, you don’t need any more hardware; you can just plug in a micro-USB cable. The pins that we used in the example are connected to the built-in debugger’s “virtual COM port”, which forwards the serial connection over the debugger’s USB interface. For more information, check the “USART virtual communication” section of the user manual.
If you are using a cheap
STM32F103C8-based board, you’ll need to connect a debugger to upload the program and a
USB / UART bridge to interact with the board from your computer. Connect the ground pins of both boards, and wire each side’s
TX pin to the other side’s
RX pin. You’ll also need to provide power to the board, either from your bridge chip or a separate USB cable. Remember to avoid giving the board more than one power supply at a time; for example, don’t plug in a USB cable while you are providing a 3.3V supply from somewhere else.
Cheap STM32F103C8 boards require an external USB / UART converter (left), while “Nucleo” boards can simply be plugged in (right).
CP2102 board in that picture is from Waveshare, but you can also make your own or find other options on sites like AliExpress / eBay / Tindie / etc. Once everything is plugged in, you should be able to see a new serial resource in your computer’s OS.
Connecting From Linux
If you’re on Linux, you can list the relevant system resources with
ls /dev/tty*. You want the one that shows up only while your device is plugged in; it will probably be called either
ttyUSBx, where “x” is a number.
There are many ways to access a serial port in Linux, but the GNU
screen program is simple and easily available in most distributions. It is often used by web developers and sysadmins to keep terminal sessions running on remote hosts across logins, but you can also use it to open a serial pipe with something like:
The last option specifies the baud rate. If it prints “[screen is terminating]” and exits immediately, you might need to run it as root or with
sudo. You’ll see a blank screen when the connection is opened, but when you press a key, that character will be transmitted over the
UART connection. And when a character is received, it will be printed on the screen. If you’ve flashed the “echo” program above, you should be able to type on the keyboard and see your keystrokes printed back.
Unfortunately, it’s a little bit tricky to quit
screen once you’ve opened a connection. You need to hit
ctrl + a, followed by
, followed by
y. I think that’s one of those legacy things that made more sense in the ’70s; apparently the program tries to have similar key bindings to the venerable VT100.
Connecting From Windows
If you’re using Windows, you can find your device’s port name and number in the “Device Manager” system application. Look under the “Ports (COM & LPT)” section for a resource which appears only when your device is plugged in. It will probably be called
COMx, where “x” is a number.
Windows also has a handful of popular programs which can connect to serial interfaces. TeraTerm is one of them, with a simple and easy-to-use GUI. To open a new connection, open the program and hit “Cancel” on the initial dialog. Then click on the “Setup” toolbar menu and select “Serial Port…”, at which point a dialog should pop up:
TeraTerm serial port setup
Under the “Port:” menu, select ther resource ID that you found in the Device Manager; in my case, it was
COM14. You can also configure the baud rate (“Speed”) and other settings, but we’re using the default configuration of 8 bits per byte, 1 stop bit, and no parity check. Once you hit “OK”, the program should connect and act similarly to
screen: characters get sent over the
TX line as you type them in, and characters received over the
RX line will be displayed in the terminal. So again, you should see your keystrokes printed back if you’ve flashed the previous “echo” program onto your board and connected it properly.
You can add support for the C standard library’s
printf(...) function to your project by overriding the standard library’s
_write(...) function to transmit characters over
…And that’s all you need to do. The standard library code still works in a bare-metal environment, but only with the help of some important system calls which are usually provided by an operating system.
_write is one of those system calls, so once you implement it, you can use standard library functions which depend on it. Try this new “echo” program:
You can find a project with this new code on GitHub. If you flash the program and connect to the serial interface, you should see a new line saying
RX: <key> for every key that you press. But if you press keys very quickly or copy / paste a long message, the application will miss some characters. What gives?
At a baud rate of 9600, it can take awhile to finish sending a string of text. And since the “transmit” and “receive” logic are both blocking, your program might not be able to keep up with rapid inputs. We could try using a higher baud rate to send data more quickly, but a better solution is to use a hardware interrupt for the “receive” logic; we’ll do that in the next section.
First, though, a quick note about
printf. If you work on larger projects, it is good practice to add print statements for logging, debugging, and error reporting. But as we have just seen, printing messages over
UART can take a long time, so you might also want to add a “debug” build flag which can enable or disable optional logging statements. Preprocessor statements are an easy way to accomplish that:
If you use a variadic macro like that, the logging statement will only be included in the program if
-DDEBUG is passed into the compiler, or if
#define DEBUG 1 is included in one of the source files. If you’re using a
Makefile like the one in the reference repository, you can add this sort of flag to the
CFLAGS variable. And once you’re happy with how the program works, you can build it without the
DEBUG flag to save space and speed things up.
You might also notice that the compiled program is much larger with
printf included (1-2KB vs. 24-28KB at the time of writing). Standard library functions can pull in a lot of extra code, but it would be annoying, time-consuming, and error-prone to write your own comprehensive print function with formatting. Life is full of tradeoffs.
Getting back to the problem of overrun errors, it’s usually good to avoid listening for incoming data in a busy-loop. Your application will have other things to do, and we’ve seen how easy it is to miss data if you only check on the peripheral periodically. So let’s enable the
UART “receive” interrupt, and store incoming data as soon as it arrives.
I wrote about how to listen for button presses using interrupts a little while ago, and the process to set up
UART interrupts looks very similar. The
NVIC “interrupt controller” peripheral takes a couple of extra steps to configure, though. Depending on which board you chose to follow along with, you’ll be using either an ARM Cortex-M3 or Cortex-M4 CPU core. My earlier “interrupts” tutorial was written for boards which used simpler Cortex-M0 or Cortex-M0+ CPUs, and they have slightly simpler
NVIC peripherals with a single “priority” setting for each interrupt.
The more complex Cortex-M cores support two separate “priority” and “sub-priority” settings to provide more granular control over interrupt pre-emption. You can read more about these priority settings in this article on one of ARM’s blogs, but to avoid confusion, I usually ignore “sub-priority” settings by configuring the whole priority field as “preempt priority” bits:
NVIC_EncodePriority call translates your desired “priority / sub-priority” values into a single value that the interrupt controller will understand, depending on how many bits are assigned to each setting. With zero bits assigned to the “sub-priority” setting, that value can be left at zero. And remember, a lower “priority” value indicates a higher urgency. I set the
UART interrupt to have the second-highest priority level,
1, because it needs to be executed quickly to avoid missing incoming data. These settings don’t really matter when your program only uses a single interrupt, but that’s pretty uncommon outside of examples and demonstrations.
Defining the interrupt handler works the same as before; you just declare a
void function with no arguments and the same name as the corresponding entry in the vector table. The interrupt request function is responsible for handling every type of
UART peripheral interrupt, but they all start in a “disabled” state. So if you want to use one, you need to enable it in the
UART peripheral first. We’ll want to use the
RXNEIE interrupt flag, which triggers an interrupt whenever the
RXNE bit is set. So first, you’ll need to replace the
CR1 register logic from this:
Then you can write an interrupt handler to store incoming bytes of data as they arrive:
Finally, your main program loop can be a bit simpler:
__WFI(); function is located in one of the CMSIS header files, which are
#included by the STM32 device header file. It tells the chip to halt until an interrupt triggers, which is a simple way to use a bit less energy while the chip is idle. It is very general, though: it cannot wait for a particular type of interrupt. Fortunately, only one interrupt is active in this example, so we can safely assume that the chip will sleep until it receives a new character over
putchar standard library function prints a single character using the
_write system call that we implemented earlier.
fflush standard library function forces the program to print any buffered writes. Usually this is done whenever a newline is printed, but when you write one character at a time, the actual “printing” logic can get deferred. You’d also need to call
fflush after a statement like
printf( '%c', rxb ) if you wanted to ensure that the text is printed immediately.
You can find a full project implementing this code on GitHub.
This is much more reliable, but it still only receives one character at a time. The peripheral won’t encounter overrun errors anymore, but the application might still miss a character if it doesn’t process them quickly enough. We could try reading characters into a static buffer, but that can be dangerous; the buffer might overflow, which is a very common source of security and stability issues.
Fortunately, there is a simple way to buffer arbitrarily-sized inputs without risking corrupted memory: a “ring buffer”. Wikipedia calls it a “circular buffer”, and they do a much better job of explaining the concept than I could.
Basically, you set up a statically-allocated buffer and write to it continuously, jumping back to the beginning when the buffer fills up. The data structure keeps track of two separate “read” and “write” pointers: when you read a character out of the buffer, you increment the “read” pointer and loop back to the beginning when it reaches the end. And when you write a character to the buffer, you increment the “write” pointer and loop back if necessary. Sometimes people call these “head” and “tail” pointers; if you think of it like that, the data structure works like an ouroboros.
When the “write” pointer equals the “read” pointer, the buffer is either empty (if the “read” pointer just incremented) or full (if the “write” pointer just incremented). The number of characters in the buffer can be inferred by observing the difference between the “read” and “write” pointers, but you need to account for the fact that both pointers can “loop around” from the end of the buffer back to the beginning.
If you receive a message that is too long or fail to process an incoming data stream quickly enough, you can still miss data when the “write” pointer leap-frogs the “read” pointer. But you won’t have data spilling over into areas of memory where it shouldn’t be, and you won’t need to repeatedly clear out or re-allocate the same buffer. Here’s an example implementation of a ring buffer which you can fit into a single
ringbuf.h header file:
It’s a little rough around the edges, and it doesn’t do any fancy error handling, but it seems to work well enough for simple applications. You can use it by including the header file and defining a
ringbuf struct near the other global variables like
Usually it’s bad practice to stuff your whole project into a single
main.c file, but these are simple examples and I think that talking about project directory structures can distract from the information which is actually important.
Anyways, next you can re-write your interrupt handler function to use the ring buffer:
And you can write a main loop to wait for an entire line of data to be received before printing the buffer contents:
If you flash that program and connect to the serial interface, you should be able to type into the console and only see your keystrokes after pressing “enter” or “return”. If you type in a message longer than 128 characters, the “write” pointer will leap-frog the “read” pointer and you won’t see the first part of what you typed in. But this is a simple way to receive blocks of data without corrupting memory if an overflow occurs, and you can detect impending overflows by comparing the “read” and “write” pointers when data is written.
Again, you can find a project with this code on GitHub.
Well I think that’s enough for now, although there is a lot more to these peripherals.
If all you need is a
printf function, you can omit the “receive” logic to simplify your code. When you just need to transmit data, it’s perfectly fine to only configure the
TX GPIO pin and leave the
USART_CR1_RE bit un-set. Likewise, you can enable only the
RX line if your program just needs to listen. And if you want to write a more efficient
_write method, there is also a
TXEIE interrupt which triggers when the peripheral is ready to accept a new byte of data.
I should also mention that modern devices are moving away from using 9600 as a standard baud rate. As microcontrollers have gotten faster, higher-speed
UART has become more common, and these days a baud rate of 115200 is often used with devices that run faster than ~10-20MHz. But you might still need to use a slower baud rate if you expect to communicate over very long wires or in an electromagnetically noisy environment. Parity checks can also help if you expect to have problems with noise.
Anyways, I hope that this quick introduction covered enough of the basics to help you interact with generic
UART devices and add logging or “print debugging” to your projects.
This article describes how to setup the PX4FLOW (Optical Flow) Sensor which can be used in place of a GPS.
The PX4FLOW is not yet supported in Plane or Rover.
Px4 Flow (com14) Driver Download Windows 7
The PX4FLOW (Optical Flow) Sensor is aspecialized high resolution downward pointing camera module and a 3-axis gyro that usesthe ground texture and visible features to determine aircraft ground velocity.Although the sensor may be supplied with a built-in Maxbotix LZ-EZ4 sonar to measureheight, this has not been reliable enough over a range of surfaces in testing, so itsreadings are not used. It is recommended to purchase a PX4Flow device without the sonar.Instead a separate Range Findersuch as the LightWare SF10bshould also be attached to the vehicle.
To best use this flow sensor you will need to purchase a separate rangefinder like the LightWare SF10b
Install Drivers (Windows only)¶
On a Windows machine a “PX4Flow” device should appear in Connection drop-down of the Mission Planner (and the Windows Device Manager), or be automatically recognized by QGroundControl. If it does not you may need to download, unzip and manually install the px4flow windows driver which may in turn require allowing installing unsigned drivers.
Download and unzip the PX4Flow-KLT firmware(source code here)
Connect the PX4Flow sensor to your computer using a micro USB cable.
Open the Initial Setup, Install Firmware screen, select the COM port and click the “Load custom firmware” link. Select the px4flow-klt-06dec2014.px4 binary you downloaded in Step 1. You may need to unplug and plug back in the sensor to start the upload.
Disconnect and reconnect the sensor/USB cable
Select the appropriate COM port and press Connect
Open the Initial Setup > Optional Hardware > PX4Flow screen
Remove the lens cap and point the camera at a high contrast object at least 3m away. Remove the small screw that stops the lens from turning and adjust the focus until the image appears clearly
In order to use QgroundControl, PX4Flow and ArduPilot, you will need to complete setup and focussing with the firmware loaded by QGroundControl, and then update the firmware to be compatible with ArduPilot.
- Select the Vehicle Setup page, and click the Firmware tab.
- Connect the PX4Flow sensor to your computer using a micro USB cable.
- Check the “Standard Version (stable)” is selected in the right hand pane. Click “OK”. QGroundControl will flash a firmware that can be used to focus the lens.
- Unplug and replug the sensor. Two extra tabs should appear: “PX4Flow” and “Parameters”.
- Click “PX4Flow”, remove the lens cap and point the camera at a high contrast object at least 3m away. Remove the small screw that stops the lens from turning and adjust the focus until the image appears clearly. This will focus the device to infinity. Refit the screw.
- Download and unzip the PX4Flow-KLT firmware(source code here)
- Unplug the sensor, click on the “Firmware” tab and replug the sensor.
- On the right hand side, click on the firmware version dropdown, and select “Custom firmware file”. Click “OK”. Then select the firmware downloaded above. QGroundControl should now flash a firmware compatible with ArduPilot. QGroundControl will now think that the sensor is a Pixhawk. Dont worry. Unplug it, and connect it to your autopilot.
Connect to the Pixhawk¶
The sensor should be connected to the autopilot via the 4-pin I2C port. Inmost cases an I2C splitter should be used to allow other I2C devices (like the external RGB LED andGPS/Compass module’s compass) to share the same port.
Mounting to the Frame¶
Px4 Flow (com14) Driver Download Win 7
The default mounting of the flow sensor is for it to be pointing straight down with the micro USB port pointing towards the front of the vehicle.On the back of the sensor you should see the axis printed, the X axis should point forwards and the Y axis to the right.The FLOW_ORIENT_YAW parameter can be used to account for other yaw orientations.
It is important that the flow sensor be mounted where it does not experienceangular angular vibration that could blur the image.
The default mounting orientation is different to that shown onthe ETH PX4FLOW wiki. If youmount the board as shown in the ETH PX4FLOW wiki, you will need to setFLOW_ORIENT_YAW to -9000.
Enabling the sensor¶
The sensor can be enabled by connecting to the autopilot with the Mission Planner andthen on the Initial Setup Optional Hardware Optical Flow pagecheck the Enable checkbox. Alternatively the FLOW_TYPEparameter should be set to “1” through the full parameters list. Thesensor will be initialised once the Pixhawk board is rebooted.
Testing and Setup¶
See Optical Flow Sensor Testing and Setup