Introduction: RC Plane Altimeter (compatible With Spektrum Telemetry)
I made this altimeter so the pilot could know that they are under the 400 foot limit on RC aircraft in the US. My friend was concerned since he couldn't say for certain that he was always under 400 ft, and wanted the added assurance that a sensor with telemetry data would provide. Yes, you can buy a sensor from Spektrum, but you can build this project for less than $20 with breakout boards (which are already inflated in price). If you already have the J-link programmer, you can build this on a custom board for a few dollars. Not to mention once you understand the Xbus protocol, you can make any of the other supported sensors! But I will just be covering an altimeter in this project...
- I used a Seeeduino XIAO microcontroller board for this project since it's tiny, uses a M0 processor that has plenty of power for this project, has both I2C and SPI ready to go out of the box, and uses 3.3v logic so no level shifting is required.
- For air pressure sensing, I purchased a BMP388 breakout board from Adafruit. The board has both I2C and SPI broken out, and can work at 3.3v or 5v logic.
- Protoboard for wiring up the circuit
- Solder/soldering iron
- Male/female pin headers so I can easily detach the sensor/microcontroller.
- Small button. I use this for resetting the starting altitude.
- 10k resistor for a pull-down on the button.
- JST-XH 4 pin female connector to plug into the telemetry port of the Spektrum receiver
- SEGGER J-Link EDU programmer to flash the M0 without a bootloader.
- Adafruit SWD 10-pin breakout board
- I also 3D printed a small enclosure for my altimeter, but this is not needed.
- Oscilloscope- If you don't have one, I highly recommend this one:
Step 1: Learn the Spektrum Telemetry Protocol
This was mostly done for me by Raymond Domingo. They had already made an altimeter compatible with Spektrum, so following that source code really helped. The Spektrum telemetry datasheet filled in the rest of the gaps. Measuring the data levels out of the receiver showed that I would need 3.3v logic.
The receiver sends the device address, and then expects a 16-byte reply. The datasheet shows the structures for all the various sensors. Even if the structure isn't 16 bytes long, the receiver expects 16 bytes back each time.
Raymond Domingo's Project:
Step 2: Select Hardware
I used a BMP388 breakout board from Adafruit for pressure sensing. The breakout provides I2C and SPI breakouts, and works at 3.3v or 5v logic. Adafruit always does an amazing job with their breakout boards, so I purchased it. I used a DFRobot Gravity BMP388 board instead in my build since my Adafruit board was already in use.
Given that the host I2C device uses 3.3v logic, I needed a 3.3v microcontroller, and I wanted it to be small. I was going to use a Adafruit Trinket M0, but they're relatively expensive, and don't have very many pins broken out. Then I found the Seeeduino XIAO board. It is a M0 board with both I2C and SPI ready to go, with a USB-C connector. Also, it's really tiny! Overall I really like this board (even though the slow startup crystal took me forever to figure out).
Spektrum uses a JST-XH size 4-pin male connector on the receiver for the "Xbus" port that we will be tapping into. I used a 4-pin JST-XH female plug on the altimeter and it worked perfectly.
Step 3: Write Software
I used the Arduino IDE to write all of the code. I copied the Spektrum telemetry protocol out of their datasheet and added it to my Arduino library. Since Adafruit always has nice libraries for their breakouts, I used their BMP3XX library for the BMP388 sensor.
The main takeaways from my design are:
- Setup the I2C to behave as a client device and respond to the Spektrum altimeter address (0x12).
- Read the BMP388 barometer through SPI.
- Save the altitude data in two different buffers so that an I2C request from the receiver won't corrupt the data, and alternate between the two buffers when fetching the data. This makes sure that the data sent to the receiver is always complete.
- Uses a button to zero the altimeter.
For more details and code analysis, watch the video.
Step 4: Wire the Circuit
I used protoboard, but if you want to take the time to design a custom milled board, you could make the circuit a lot cleaner.
I connected the JST-XH connector to the XIAO's I2C pins. Since the receiver outputs 5 volts to the telemetry bus, the positive from the bus went to the XIAO's VCC pin. That way the onboard 3.3v regulator is used to power the BMP388 sensor.
Step 5: Compile Without a Bootloader
- Find your boards.txt file (for whatever board you are using).
- In my case, it was located here: C:\Users\\AppData\Local\Arduino15\packages\Seeeduino\hardware\samd\1.7.7\boards.txt
- Copy your board, and rename the first key to specify a no bootloader version. I just added _nbl to the original name.
- Old: seeed_XIAO_m0
- New: seeed_XIAO_m0_nbl
- Change the .name value:
- Old: seeed_XIAO_m0_nbl.name=Seeeduino XIAO
- New: seeed_XIAO_m0_nbl.name=Seeeduino XIAO No Bootloader
- Modify the linker to flash without the bootloader by changing the builder ld script:
- Old: seeed_XIAO_m0_nbl.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld
- New: seeed_XIAO_m0_nbl.build.ldscript=linker_scripts/gcc/flash_without_bootloader.ld
- Restart the Arduino IDE.
- Select the new "Seeeduino XIAO No Bootloader" board from the boards menu.
- Select "Export Compiled Binary"
- Once compiled, the .bin file will be in your Arduino project folder.
Step 6: Flash MCU With J-Link
Adafruit has a fantastic guide on reprogramming a bootloader on a M0/M4 device. In our case, we want to get rid of the bootloader, but it works the same way.
Once you do this, you won't be able to upload code through USB. You can follow the above guide to flash the bootloader back onto the device to upload code through USB again like you were able to from the factory.
The Adafruit guide is very thorough, but these are the basic steps:
- Solder jumper wires to the back of the XIAO board.
- The Adafruit guide didn't say the RST pin on the 2x5 breakout board needed to be connected to the reset pin on the Adafruit boards. But for the XIAO, I needed to connect to all four pads on the back of the board.
- The VREF pin needs to be connected to the XIAO 3.3v pin. This tells the debugger that the device logic is 3.3v. Without it, if you select the wrong option, you could damage the microcontroller.
- Connect the jumper wires to the J-Link.
- Power on the XIAO board with a USB cable.
- Open Atmel Studio.
- Select Tools --> Device Programming
- Select your M0 board. In this case, the ATSAMD21G18A
- Select SWD.
- Read the configuration from the target.
- Verify that the read in voltage is correct in the upper right hand corner. If it isn't 3.3v, you could break your board!
- Clear the boot protect fuse (set the bootloader size to 0 bytes), and then select program.
- In the memories section, select your compiled .bin or .hex file, and select program.
- When you read the device configuration, if you get a voltage out of range error, then make sure the MCU is plugged into power and that the J-Link VREF pin is connected to 3.3 volts.
Step 7: Recompile Without the External Crystal
The XIAO board has an external crystal that takes a long time to start. The Spektrum receiver does a device discovery on the telemetry bus 350 milliseconds after power up, so we need to tell the compiler to use the internal oscillator instead which will make startup nearly instantaneous.
- Find the boards.txt file that you modified earlier (yes, I could have saved you this step earlier, but this was a learning process for me)
- Add "-DCRYSTALLESS" to the seeed_XIAO_m0_nbl.build.extra_flags string. This will tell the compiler to use the internal oscillator.
- Recompile the code.
- Re-flash the MCU.
- Verify the startup time is fast enough using an oscilloscope.
As you can see from the picture, the yellow channel 1 is the power supply. The cyan channel 2 is the ready pin on the microcontroller. About 10 milliseconds after power-up, channel two is pulled high by the microcontroller which indicates it is in the setup loop. Once setup is done, the MCU is coded to pull the pin low, indicating the main loop is starting. The scope shows that the setup takes about 3 milliseconds. Overall the microcontroller takes 13 milliseconds after power-up to be ready to go.