Skip to content

Software Onboarding

Vraj Parikh edited this page Jul 12, 2026 · 7 revisions

Welcome to the GNC software onboarding guide!. Firstly, make sure to follow the instructions to setup your workstation, if you haven't already.

Onboarding will be split into 3 parts, to remain consistent with other subteams:

  • Part 1: C language fundamentals
  • Part 2: Working with embedded systems + peripheral basics
  • Part 3: Using FreeRTOS + more advanced peripherals (interrupts)

Note that since different people have different backgrounds, there are no hard timelines on each part of this project. New members that are unfamiliar with C, for example, may find part 1 to be the most time consuming. For someone with no prior background with C or with embedded systems, a likely timeline would be to spend ~3 weeks on part 1, ~2 weeks on part 2, and ~1 week on part 3.

Remember that the subteam leads are here to help! Always feel free to reach out to either of us if you have any questions or feel as though you are stuck. This is our first year with these new onboarding exercises, so any feedback is greatly appreciated.

Reminder for Windows users: make sure to run all commands through WSL, not through Windows PowerShell.

Part 1

TODO

Part 2

For parts 2 and 3, we will be working with the flight-software repository. If you haven't already, pull the repository to your device and check out the project/onboarding branch. I would also recommend taking a quick glance at the README to familiarize yourself with the repository's layout. When you are done, it's time to start part 2!

Deliverables and Content Focus

This section is all about familiarizing yourself with using our codebase and writing embedded code that can interact with hardware peripherals. By the end, you should be comfortable with the following things:

  1. Compiling and modifying this repository
  2. Writing basic peripheral drivers
  3. Understanding the basic HAL interfaces for GPIO pins, UART, and SPI

The only deliverable for this project is to complete part C, which involves submit a PR for a functioning LSM6DSO driver (more details below) that passes all of the CI checks and then demonstrating to either software lead that your code correctly reads/writes the appropriate registers when tested on a development board. However, since embedded programming can have a steep learning curve, we have included two optional (but highly recommended) prerequisite sections (sections A and B) to help you along the way. Feel free to ask with help for any of these sections, and good luck!

Part A - Compiling and flashing code

This section is a brief introduction to CMake and the STM32CubeProgrammer utility tool. You will need an stm32h723 nucleo board and a compatible cable. Please ask either software lead for one, as we have many available to loan out. Then follow the instructions.

  1. This repository is compiled using CMake. You can read a bit about how CMake work here: TODO. To make things easy, this repo has a "dev" preset already set up. If you are curious as to what settings this preset actually does, feel free to take a look at CMakePresets.json.
    1. Start by configuring the build using this command: cmake --preset dev. You will need to rerun this command every time you modify a CMake File (like when you add new .c files to the codebase). That also includes when pulling changes or checking out new branches
    2. To compile the codebase, use the command cmake --build --preset dev. If everything works, you should see a new folder called build/dev, with a file called "flight-software.elf" inside. This is your compiled binary! (you can ignore the other files)

If you are having issues compiling the codebase for the first time, please ask for help. Dealing with dependency issues on different systems can be a hassle.

  1. Now you can flash your code. Take out the nucleo board, and plug in the Micro-USB port labeled "USB PWR" (opposite to the side with the ethernet port) into your computer. You should see some lights on the board turn on.
  2. Open STM32CubeProgrammer, and make sure that the blue dropdown on the top-right says "ST-LINK". Then, hit the green button next to it that says "connect".

If you get an error when trying to connect, it usually means that either your cable is not compatible or that your ST-Link driver is broken. Try switching the USB cable and/or the port on your device, and if it still does not work, ask one of the subteam leads for help.

  1. On the toolbar on the left-hand side, select the option for "Erasing and Programming" (the second icon from the top). Then in the filepath option, select the path to the "flight-software.elf" file you generated earlier.

  2. Make sure that the options to "verify programming" and "run after programming" are enabled, and that the options to "skip flash erase before programming" and "full flash memory checksum" are disabled. Then, push the big blue button that says "start programming"

  3. If the code was flashed, you should see some messages letting you know that everything worked correctly. If you got a message saying the core was locked up, simply disconnect and reconnect using the button in the top-right corner.

Part B - Flashing LED's and hello world

In this section, you will be writing a simple program to make an led blink and print hello world.

  1. To start off, open core/src/main.c. The method shared_main() in this file is the entry point for all of our code, and is called from the actual main method once all of the necessary chip drivers have been initialized.

  2. Now, we can make an LED blink. To interact with peripheral devices, we will be using the STM Hardware Abstraction Layer (HAL) library. All of the important methods in the HAL are automatically included through the statement #include "main.h". To start off, here are some HAL methods that you may find useful:

// Enables the GPIO (general-purpose input-output pin) connected to the green led.
HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_SET);

// Disables the GPIO (general-purpose input-output pin) connected to the green led.
HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_RESET);

// Waits for the specified number of milliseconds
HAL_Delay(<insert delay in milliseconds>);

Note that the macros LED_GREEN_GPIO_Port and LED_GREEN_Pin aren't part of the HAL library, but are rather peripheral handles that have been configured manually. For part 2, we have configured multiple different peripherals for you to use (check out the hint in core/src/main.c for the list), but in part 3, you'll get to try configuring them yourself!

  1. Using the above helper methods, write a program in shared_main() that makes the green LED blink on and off forever. When you are done, recompile your code, flash it to the development board, and verify that the green led does in fact blink as intended.

  2. Now it's time for something more complicated, printing "hello world!". For this, we will be using the UART peripheral, which in this case has been configured to communicate directly with your computer. You can read more about how the UART protocol works here: TODO. Once again, here are some helpful methods that you may find useful:

// Send some number of bytes over UART
HAL_UART_Transmit(&huart3, <POINTER TO DATA TO SEND>, <DATA_SIZE_IN_BYTES>, HAL_MAX_DELAY);

// Block until some number of bytes are received via UART
HAL_UART_Receive(&huart3, <POINTER TO BUFFER WHERE DATA WILL BE RECEIVED>, <DATA_SIZE_IN_BYTES>, HAL_MAX_DELAY);

To start off, try sending data over UART periodically inside the same loop as your LED. To actually receive the data, you will need a serial port terminal emulator like picocom, which you can install using any of these commands:

  • homebrew (macOS): brew install picocom
  • apt (Ubuntu/WSL): sudo apt update && sudo apt install picocom
  • dnf (Fedora): sudo dnf install picocom The stm32 is configured to use a baud rate of 115200, so you can connect to the device by using the command picocom /dev/tty -b 115200. To figure out what serial port you are connected to, use ls /dev/tty* (ls /dev/tty.* on macOS) to see a list of options. If you are not sure which option is the stm32, you can also try unplugging it and rerunning the command (and seeing which serial port disappears from the list). When you are connected to the correct port and baud rate, you should see the data you are sending over uart in your terminal. You can use "ctrl-a ctrl-x" to exit picocom. While in picocom, you can also type characters, which will be transmitted over UART to the nucleo board.
  1. Feel free to experiment with using UART, and move on to part C when you are ready.

Part C - A simple SPI driver

In this section, you will be writing a simple SPI driver to communicate with the LSM6DSO IMU. This part is the only deliverable for part 2.

  1. For this project, you will be using the SPI peripheral. Since SPI is more complex than UART or GPIO pins, you should first read about this peripheral here: TODO.

  2. You will be implementing the method stubs provided in core/inc/lsm6dso.h in the file core/src/lsm6dso.c. Note that a utility method, delay_us, has been provided for you. The helpful hints comment in core/src/main.c also provides some HAL methods that you may find useful.

  3. In order to communicate with the LSM6DSO imu, you will need to read (and potentially write) to certain device registers. In order to find out what those registers are, consult the datasheet. Note that datasheets can be long and complicated, and reading them is a skill (but feel free to ask for help if you are stuck)! To get you started, here are some hints:

    1. Ctrl-F is your friend
    2. You will be using the SPI interface, so feel free to ignore directions specific to the I2C interface.
    3. Section 5.1.2 provides some guidance you may find useful regarding how to read/write registers
    4. Section 4.4.1 describes timing requirements for the SPI interface. We have already setup the SPI peripheral to handle most of these, but you are responsible for handing the chip select (CS) pin yourself.
    5. Sections 8 and 9 provide a list of registers you can interact with.
  4. Implement all of the remaining stubs in core/src/lsm6dso.c. Feel free to add additional functionality and methods, but the items listed are the minimum you must implement.

  5. Write a simple demo in shared_main.c that shows off your driver working correctly. You are free to implement this however you want, as long as it is easy for a user to see that the all of the methods in lsm6dso.c are working correctly. Consider utilizing UART to print out values.

  6. When you are confident your code works correctly and compiles, submit a PR to this repository and make sure that it passes all of the CI checks.

  7. Get a nucleo board and a sparkfun 18020 eval board, wire up the sensor to SPI1 on the nucleo (feel free to ask for help with this part), and then demonstrate that the code you wrote in part 5 works as intended to either software lead.

With that, you've finished onboarding section 2! Congratulations!

Clone this wiki locally