I was looking for a skydiving Digital Altimeter and found that they cost about 300 to 500 USD here. It is not only that, most of them have three buttons, but they don't perform the same function on each device. As a result, we have to read the manual and memorize button pressing sequence for each functionality.
In this tutorial, we will be referring to Audible Abby a lot, therefore, it helps to be familiar with that project. One feedback I received on Audible Abby is "so, how do you change alarm altitudes?". To be honest with you, if you don't know Arduino, you're outta luck!
The solution to the issues mentioned above is a free Android Bluetooth Low Energy (BLE) app that allows you to adjust altitude in the plane using your smartphone. Once launched, that app connects to a home-built altimeter (ALTER) powered by ON Semiconductor's RSL10-SENSE-DB-GEVK.
The goal of this tutorial is to teach you how to fish as opposed to just watch me eat Sashimi. You will learn how to do factory reset, create BLE Android app, add OLED to your project, get more GPIOs out of RSL10-SENSE-DB-GEVK, and deal with life's adversities in general.
I will try my best to entertain you along the way because this is gonna be a long tutorial; so, you may wanna take a seat. If you're already sitting down then no further action is needed.
Software:This step may look intimidating, but it is really simple once you know couple things. Martyn Currey's tutorial shows how to easily create a free Android app to connect your phone to BLE device. The problem here is UUID looks like this:
0000FFE0-0000-1000-8000-00805F9B34FB
If you open BLE_ICS.h (in Pack folder) you have something like this:
#define ICS_SERVICE_UUID { 0x24, 0xdc, 0x0e, 0x6e, 0x01, 0x40, \0xca, 0x9e, 0xe5, 0xa9, 0xa3, 0x00, \0xb5, 0xf3, 0x93, 0xe0 }
Here is how to convert your format to a format usable by ai2.appinventor.mit.edu:
1 - Keep spaces and remove curly braces, commas, and 0x 24 dc 0e 6e 01 40 ca 9e e5 a9 a3 00 b5 f3 93 e0
2 - Reverse all pairs order (first pair becomes last and last pair becomes first) e0 93 f3 b5 00 a3 a9 e5 9e ca 40 01 6e 0e dc 24
3 - Remove spaces e093f3b500a3a9e59eca40016e0edc24
4 - Add the four strategic dashes e093f3b5-00a3-a9e5-9eca-40016e0edc24
You only have to do that once because other UUIDs are just couple of digits off.
Read = e093f3b6-00a3-a9e5-9eca-40026e0edc24
Write = e093f3b7-00a3-a9e5-9eca-40036e0edc24
If your Bluetooth blocks look different you have to take a look at this:
Basically, at 4:24 you have to import BLE extension. To save you some googleing, you can download the latest version from this page.
Here is how we envision the app to work:
We start by scanning for BLE devices then we use a timer to connect to MAC address after a little delay (you can find your MAC using RSL10 Sense and Control App). Once we connect, we stop scanning, disable the timer and enable Up and Down buttons. Next, we register for string to listen for RSL10-SENSE-DB-GEVK data. We need a procedure to write values back to the device. The first time this procedure is used we send +1 then -1. That is needed to initiate receiving altitude string forcing refresh of the number on the phone.
Also in the blocks we have a Quit button, and couple of buttons to increment and decrement altitude by 50 feet. As soon as a string is received, we will remove the parentheses from it and display the current altitude value.
I exported aia file then uploaded it to Github in the project repository at the end of this tutorial. I tried to publish appinventor project but the site won't let me.
I love RSL10-SENSE-DB-GEVK hardware so much I considered starting with this section instead of Software. There are five holes on the board and four of them can be used for I2C connection. I had an OLED laying around waiting for a project so I soldered it directly to RSL10-SENSE-DB-GEVK.
While trying to move ALTER to a case that I can wear on my hand like a watch, I managed to break the first OLED display. Furthermore, I damaged a second display, and to add insult to injury, I destroyed SCL and SDA pin holes in the process. Now it's personal.
Few options here to move forward with the project:
- Fake it like some "Makers" do on YouTube - if you fake it you'll never make it
- Buy a new board - it's only 50 bones, yo
- Use Arduino Pro Mini to take UART data from the last pin (GIO) available on RSL10-SENSE-DB-GEVK then send it to OLED via Arduino's I2C
I started going down the path of the last option in parallel with another option that we have not talked about yet.
One of the problems with using Arduino Pro Mini option is the two I have are 5V which are not compatible with RSL10-SENSE-DB-GEVK or OLED voltage. It is not only I have to up-size the CR2032 voltage supply to accommodate OLED, I also have to take into consideration another board's power requirements.
We are going to leave this section with a cliffhanger, but before we move on to the next section we will briefly talk about the enclosure.
I have to be able to fit an Arduino Pro Mini inside the bottle cap along with RSL10-SENSE-DB-GEVK, OLED, and a battery. Most important, it has to be Blue.
I didn't have any experience using Eclipse when I started, but I was able to do a factory reset using this document. I soon realized I have to find an example to modify and use in this project.
I chose "Custom Service Firmware" because it has BLE, and BME680 code. It also does not have the complications that comes with deep sleep code. If it is too much code, you can always delete or comment out like we're about to do here very soon. If this seems like too much work, don't worry, I uploaded the final working consolidated code to Github project repository at the end of this tutorial.
Continue reading if you wanna learn more or just skip a head to the next section instead.
Just like Audible Abby, ALTER needs to calculate altitude. We will use pressure and temperature data from the on-board integrated sensors to figure out changes in Above Ground Level value. ALTER also needs to display real-time altitude on OLED screen, but there are no examples in ON Semiconductor IDE to show how to do that. I tried few things, but what came to the rescue is an unlikely project from the only contest I didn't win in 2019.
I took 5 files from here, and modified them to make them work with RSL10-SENSE-DB-GEVK just like they did with Azure Sphere Starter-Kit. I placed these files in 2 folders in my workspace:
- src\oled.c
- src\sd1306.c
- include\font.h
- include\oled.h
- include\sd1306.h
Running the code resulted in some errors which is great because I can just comment out the code that is causing problems. Here is what I did to clean up this mess:
- sd1306.hComment out lines 8 and 9 like so//#include "i2c.h"//#include <applibs/i2c.h>and add #include <BDK.h>
- oled.hComment out lines 9, 10, 11, and 58 like so//#include "applibs_versions.h"//#include <applibs/wificonfig.h>//#include "deviceTwin.h"//uint8_t SSID[WIFICONFIG_SSID_MAX_LENGTH];
- oled.cComment out lines 24, 25, 26, 27, 64, 65, 66, 67, and 287 like so//extern uint8_t oled_ms1[CLOUD_MSG_SIZE];//extern uint8_t oled_ms2[CLOUD_MSG_SIZE];//extern uint8_t oled_ms3[CLOUD_MSG_SIZE];//extern uint8_t oled_ms4[CLOUD_MSG_SIZE];//sd1306_draw_string(OLED_LINE_1_X, OLED_LINE_1_Y, oled_ms1, FONT_SIZE_LINE, white_pixel);//sd1306_draw_string(OLED_LINE_2_X, OLED_LINE_2_Y, oled_ms2, FONT_SIZE_LINE, white_pixel);//sd1306_draw_string(OLED_LINE_3_X, OLED_LINE_3_Y, oled_ms3, FONT_SIZE_LINE, white_pixel);//sd1306_draw_string(OLED_LINE_4_X, OLED_LINE_4_Y, oled_ms4, FONT_SIZE_LINE, white_pixel);//sd1306_draw_string(sizeof(str_SSID)*6, OLED_LINE_1_Y, network_data.SSID, FONT_SIZE_LINE, white_pixel);
- sd1306.cWe have couple of lines here that we can't just comment out; we have to find a replacement. Line 48 becomes:retval = HAL_I2C_Write(addr, data_to_send, 2, false); //I2CMaster_Write(i2cFd, addr, data_to_send, 2);and line 73 becomes:retval = HAL_I2C_Write(addr, data_to_send, 1025, false); //I2CMaster_Write(i2cFd, addr, data_to_send, 1025);
- font.hI did modify that file to make 0 and 1 look better. You'd think a micro controller would get those two right!{0x3E, 0x51, 0x49, 0x45, 0x3E} became {0x3E, 0x41, 0x41, 0x41, 0x3E}{0x04, 0x02, 0x7F, 0x00, 0x00} became {0x00, 0x02, 0x7F, 0x00, 0x00}
One more thing you'll find in oled.c is a logo starting at line 698. There are plenty of tutorial on the interwebs on how to create your own OLED logo. I used LCDAssistant, but you can also use http://javl.github.io/image2cpp/ which is an online solution to convert images to numbers that C could understand.
Let's go back to Hardware section before we continue with Firmware. Remember that I said I no loner have SCL or SDA? That means lines 48 and 73 in src\sd1306.c will not be able to send anything to OLED. I just added them because you probably still have your I2C pins.
If you want to use UART, you'll have to find and modify PinNames.h in
C:\Users\<...>\PACK\ONSemiconductor\BDK\1.12.1\include\target\RSL10_SENSE ReplacePIN_UART_TX = NC and PIN_GIO_SPARE = PIN_DIO3withPIN_UART_TX = PIN_DIO3 and PIN_GIO_SPARE = NC
Since I am not using UART either, as you're about to find out shortly, the only changes I made to PinNames.h are PIN_BUTTON0 = NC and PIN_GIO_SPARE = NC.
UART to me was Plan B because I was trying hard to make something similar in functionality to I2C. That's when I discovered Bit Banging (Yes, it is as cool as it sounds). There are a lot of Bit Bangers out there, but I found Kevin Darrah's tutorial to be very useful in understanding the basics of I2C protocol. I also had to learn the concept of Port Manipulation using GreatScott's tutorial. RSL10-SENSE-DB-GEVK is no Arduino, consequently, I had to adjust the code accordingly. Wanna know why we need Port Manipulation?
You might say "You need only one wire for UART, but you'll need two for I2C. You only have one remaining place to solder a wire on the board. How are you going to pull off Bit Banging I2C?" to which I reply:
ICYMI, I soldered a wire to the ungrounded side of one of the push buttons.
In sd1306.c line 49 is now:retval = SWI2C(data_to_send, 2);and line 74 is now:retval = SWI2C(data_to_send, 1025);
We will need two more files: BitBanging.c and BitBanging.h. Make sure to add #include <BitBanging.h> to main.c. You should also add BitBanging_Init(); before the infinite loop and SendAltitudeToDisplay(); inside it.
Find CS.c in C:\Users\<...>\PACK\ONSemiconductor\BDK\1.12.1\source\firmware\BoardSupport\hb\src\ics and add the following lines at the top:
#include <BitBanging.h>
#include <math.h>
int InitialAlt = -9999;
int OffsetAlt;
int AGL;
int PreviousAGL = -9999;
You will need to add couple of procedures as well:
int CalculateAltitude(float P, float T) {
// Get Altitude from Pressure and Temperature
return (int) ((pow(P / 101.325, 0.190223) - 1) * (T * 280.4137 + 128897.8));
}
void SendAltitudeToDisplay(void) {
// Save the response values
float ResponseP, ResponseT;
// Send a request in a specific format
cs.node[1]->request_handler((struct CS_Request_Struct[] ) {{ "5", "EV", "P" }}, cs_node_response);
// Save Pressure value
ResponseP = atof(&cs_node_response[2]);
if (ResponseP != 0.00) {
// Send a request in a specific format
cs.node[1]->request_handler((struct CS_Request_Struct[] ) {{ "6", "EV","T" }}, cs_node_response);
// Save Temperature value
ResponseT = atof(&cs_node_response[2]);
// Right align text on OLED
char TextBuffer[5];
// Check if baseline altitude has been set
if (InitialAlt == -9999) {
// Set baseline
InitialAlt = CalculateAltitude(ResponseP, ResponseT);
} else {
// Measure from baseline and take into account external Altitude adjustment
AGL = InitialAlt - CalculateAltitude(ResponseP, ResponseT) + OffsetAlt;
// Less than 1000 feet
if (AGL < 1000) {
// Print into 4 places to right align text on OLED
snprintf(TextBuffer, sizeof(TextBuffer), "%4d", AGL);
} else {
// Less than 10000
if (AGL < 10000) {
// Print whole number into two places and one after the decimal
snprintf(TextBuffer, sizeof(TextBuffer), "%2d.%d",AGL / 1000, AGL % 1000 / 100);
} else {
// Just use all of OLED
snprintf(TextBuffer, sizeof(TextBuffer), "%d.%d",AGL / 1000, AGL % 1000 / 100);
}
}
// Send to OLED if it has been more than 0.2 seconds since last update
////if (HAL_Time() - TimeStamp > 200) {
//sd1306_draw_string(0, 15, TextBuffer, 5, white_pixel);
// Loop through digits
for (uint16_t k = 0; k < 4; k++) {
// Remove ASCII offset
char digit = TextBuffer[k] - 48;
// Adjust if decimal point or negative
if (digit < 0) digit = digit + 13;
// Loop through pages
for (uint16_t j = 0; j < 8; j++)
// Columns of each page
for (uint16_t i = j * 128; i < j * 128 + 32; i++)
// Copy to OLED buffer in specific order
if (digit >= 0)
oled_buffer[i + k * 32] = Image_num_bmp[i - (j * 128) + (j * 32) + (digit * 256)];
else
// If blank
oled_buffer[i + k * 32] = 0x00;
}
// Send OLED buffer to sd1306
WriteBufferToDisplay();
// Send via BLE only if AGL value has changed
if (PreviousAGL != AGL) CS_PlatformWrite(TextBuffer, sizeof(TextBuffer));
TimeStamp = HAL_Time();
PreviousAGL = AGL;
////}
}
}
}
Also, in CS.c you will need to add the following to CS_Loop (after "int errcode, bytes, i;" of course)
// Read available BLE packet
memset(cs_rx_buffer, 0, 21);
CS_PlatformRead(cs_rx_buffer, 21, &bytes);
// New packet available
if (bytes > 0) {
// New AGL offset
OffsetAlt = OffsetAlt + atoi(cs_rx_buffer);
// Fore update BLE
PreviousAGL = -9999;
}
// We're done here
return 0;
I inserted x = x+ size ; at line 770 in sd1306.c just to add some space between digits. Finally, comment out the following lines in main.c for much needed speed:ASSERT_ALWAYS(CSN_ALS_CheckAvailability() == true);ASSERT_ALWAYS(CS_RegisterNode(CSN_ALS_Create()) == CS_OK);ASSERT_ALWAYS(CSN_AO_CheckAvailability() == true);ASSERT_ALWAYS(CS_RegisterNode(CSN_AO_Create()) == CS_OK);ASSERT_ALWAYS(CS_RegisterNode(CSN_PB_Create()) == CS_OK);
TL;DR:If you skipped the last section or part of it, you can still build this project. Start by copying Custom Service Firmware example from CMSIS Pack Manager and make sure it works on your board. Next, save the 5 files you downloaded from Github in the following locations:
C:\Users\<...>\ON_Semiconductor\PACK\ONSemiconductor\BDK\1.12.1\include\target\RSL10_SENSE\PinNames.h
C:\Users\<...>\ON_Semiconductor\PACK\ONSemiconductor\BDK\1.12.1\source\firmware\BoardSupport\hb\src\ics\CS.c
C:\Users\<...>\on-semiconductor-workspace\sense_ics_firmware\include\BitBanging.h
C:\Users\<...>\on-semiconductor-workspace\sense_ics_firmware\src\BitBanging.c
C:\Users\<...>\on-semiconductor-workspace\sense_ics_firmware\src\main.c
DemoUnlike Audible Abby, ALTER performed a live demo. After all, if a tree falls in a forest and no one is around to hear it, well, you get the idea.
I created my own numbers because the numbers that came in font.h were so ugly I almost hesitated to pull my parachute. On a more serious note, you've seen altitude fluctuating at the beginning of the video right at takeoff because of changes in pressure at the back of the plane. Here is a video from a different flight:
Sure enough, altitude was accurate according to the analog altimeter. You probably also noticed that display is affected by ambient light. ALTER is much more readable in real life than in video even out in the sun.
Last but not least, please don't use the following video as evidence in a flat earth debate.
Conclusion:I Spent hundreds of hours having fun and learning while building this project. I am impressed by how quickly I was able to launch a Minimum Viable Product without any special portal, additional MCU, or even an external sensor. To me, that is really powerful. Looking back at previous competitions, many submissions are using Hardware and Software with little to no modification, but that's not my M.O. At the same time, I wanted my customization to be reproducible and maintainable, The flexibility of RSL10-SENSE-DB-GEVK enabled me to Transform My Thinking.
ALTER is just the beginning and can be expanded to log jumps, total free-fall time, vertical speed, etc. It can also be modified to be used by pilots where they update the barometric pressure via BLE app to get in-flight accurate altitude on OLED display. The sky is the limit!
I hope you found this project useful and enjoyed it as much as I did. I don't expect to see many submissions levering BLE, OLED, or even GPIOs. Therefore, I hope that ON Semiconductor can use this project or parts of it as examples for others to benefit from and build on.
Comments