# ODrive Firmware Developer Guide
This guide is intended for developers who wish to modify the firmware of the ODrive.
As such it assumes that you know things like how to use Git, what a compiler is, etc. If that sounds scary, turn around now.
The official releases are maintained on the `master` branch. However since you are a developer, you are encouraged to use the `devel` branch, as it contains the latest features.
The project is under active development, so make sure to check the [Changelog](../CHANGELOG.md) to keep track of updates.
### Table of contents
- [Prerequisites](#prerequisites)
- [Configuring the build](#configuring-the-build)
- [Building and flashing the Firmware](#building-and-flashing-the-firmware)
- [Debugging](#debugging)
- [Testing](#testing)
- [Setting up an IDE](#setting-up-an-ide)
- [STM32CubeMX](#stm32cubemx)
- [Troubleshooting](#troubleshooting)
- [Documentation](#documentation)
- [Releases](#releases)
- [Notes for Contributors](#notes-for-contributors)
## Prerequisites
The recommended tools for ODrive development are:
* **make**: Used to invoke tup
* **Tup**: The build system used to invoke the compile commands
* **ARM GNU Compiler**: For cross-compiling code
* **ARM GDB**: For debugging the code and stepping through on the device
* **OpenOCD**: For flashing the ODrive with the STLink/v2 programmer
* **Python 3**, along with the packages `PyYAML`, `Jinja2` and `jsonschema`: For running the Python tools (`odrivetool`). Also required for compiling firmware.
See below for specific installation instructions for your OS.
Depending on what you're gonna do, you may not need all of the components.
Once you have everything, you can verify the correct installation by running:
```bash
$ arm-none-eabi-gcc --version
$ arm-none-eabi-gdb --version
$ openocd --version # should be 0.10.0 or later
$ tup --version # should be 0.7.5 or later
$ python --version # should be 3.7 or later
```
#### Linux (Ubuntu < 20.04)
```bash
sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa
sudo apt-get update
sudo apt-get install gcc-arm-embedded
sudo apt-get install openocd
sudo add-apt-repository ppa:jonathonf/tup && sudo apt-get update && sudo apt-get install tup
sudo apt-get install python3 python3-yaml python3-jinja2 python3-jsonschema
```
#### Linux (Ubuntu >= 20.04)
```bash
sudo apt install gcc-arm-embedded
sudo apt install openocd
sudo apt install tup
sudo apt install python3 python3-yaml python3-jinja2 python3-jsonschema
```
#### Arch Linux
```bash
sudo pacman -S arm-none-eabi-gcc arm-none-eabi-binutils
sudo pacman -S arm-none-eabi-gdb
sudo pacman -S tup
sudo pacman -S python python-yaml python-jinja python-jsonschema
```
* [OpenOCD AUR package](https://aur.archlinux.org/packages/openocd/)
#### Mac
First install [Homebrew](https://brew.sh/). Then you can run these commands in Terminal:
```bash
brew install armmbed/formulae/arm-none-eabi-gcc
brew cask install osxfuse && brew install tup
brew install openocd
pip3 install PyYAML Jinja2 jsonschema
```
#### Windows
__Note__: make sure these programs are not only installed but also added to your `PATH`.
Some instructions in this document may assume that you're using a bash command prompt, such as the Windows 10 built-in bash or [Git](https://git-scm.com/download/win) bash.
* [ARM compiler](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads)
* __Note 1__: After installing, create an environment variable named `ARM_GCC_ROOT` whose value is the path you installed to. e.g. `C:\Program Files (x86)\GNU Tools Arm Embedded\7 2018-q2-update`. This variable is used to locate include files for the c/c++ Visual Studio Code extension.
* __Note 2__: 8-2018-q4-major seems to have a bug on Windows. Please use 7-2018-q2-update.
* [Tup](http://gittup.org/tup/index.html)
* [GNU MCU Eclipse's Windows Build Tools](https://github.com/gnu-mcu-eclipse/windows-build-tools/releases)
* [Python 3](https://www.python.org/downloads/)
* Install Python packages: `pip install PyYAML Jinja2 jsonschema`
* [OpenOCD](https://github.com/xpack-dev-tools/openocd-xpack/releases/).
* [ST-Link/V2 Drivers](http://www.st.com/web/en/catalog/tools/FM147/SC1887/PF260219)
## Configuring the build
To customize the compile time parameters, copy or rename the file `Firmware/tup.config.default` to `Firmware/tup.config` and edit the parameters in that file:
__CONFIG_BOARD_VERSION__: The board version you're using. Can be `v3.1`, `v3.2`, `v3.3`, `v3.4-24V`, `v3.4-48V`, `v3.5-24V`, `v3.5-48V`, etc. Check for a label on the upper side of the ODrive to find out which version you have. Some ODrive versions don't specify the voltage: in that case you can read the value of the main capacitors: 120uF are 48V ODrives, 470uF are 24V ODrives.
__CONFIG_USB_PROTOCOL__: Defines which protocol the ODrive should use on the USB interface.
* `native`: The native ODrive protocol. Use this if you want to use the python tools in this repo. Can maybe work with macOS.
* `native-stream`: Like the native ODrive protocol, but the ODrive will treat the USB connection exactly as if it was a UART connection. __You may need to use this if you're on macOS__. This is necessary because macOS doesn't grant our python tools sufficient low-level access to treat the device as the USB device that it is.
* `none`: Disable USB. The device will still show up when plugged in but it will ignore any commands.
**Note**: There is a second USB interface that is always a serial port.
__CONFIG_UART_PROTOCOL__: Defines which protocol the ODrive should use on the UART interface (GPIO1 and GPIO2). Note that UART is only supported on ODrive v3.3 and higher.
* `native`: The native ODrive protocol. Use this if you're connecting the ODrive to a PC using UART and want to use the python tools to control and setup the ODrive.
* `ascii`: The ASCII protocol. Use this option if you control the ODrive with an Arduino. The ODrive Arduino library is not yet updated to the native protocol.
* `none`: Disable UART.
__CONFIG_DEBUG__: Defines wether debugging will be enabled when compiling the firmware; specifically the `-g -gdwarf-2` flags. Note that printf debugging will only function if your tup.config specifies the `USB_PROTOCOL` or `UART_PROTOCOL` as stdout and `DEBUG_PRINT` is defined. See the IDE specific documentation for more information.
You can also modify the compile-time defaults for all `.config` parameters. You will find them if you search for `AxisConfig`, `MotorConfig`, etc.
## Building and flashing the Firmware
1. Run `make` in the `Firmware` directory.
2. Connect the ODrive via USB and power it up.
3. Flash the firmware using [odrivetool dfu](odrivetool#device-firmware-update).
### Flashing using an STLink/v2 programmer
* Connect `GND`, `SWD`, and `SWC` on connector J2 to the programmer. Note: Always plug in `GND` first!
* You need to power the board by only **ONE** of the following: VCC(3.3v), 5V, or the main power connection (the DC bus). The USB port (J1) does not power the board.
* Run `make flash` in the `Firmware` directory.
__Note__: If you receive the error `can't find target interface/stlink-v2.cfg` or similar, create and set an environment variable named `OPENOCD_SCRIPTS` to the location of the openocd scripts directory.
If the flashing worked, you can connect to the board using the [odrivetool](getting-started#start-odrivetool).
## Testing
The script `tools/run_tests.py` runs a sequence of automated tests for several firmware features as well as high power burn-in tests. Some tests only need one ODrive and one motor/encoder pair while other tests need a back-to-back test rig such as [this one](https://cad.onshape.com/documents/026bda35ad5dff4d73c1d37f/w/ae302174f402737e1fdb3783/e/5ca143a6e5e24daf1fe8e434). In any case, to run the tests you need to provide a YAML file that lists the parameters of your test setup. An example can be found at [`tools/test-rig-parallel.yaml`](tools/test-rig-parallel.yaml`). The programmer serial number can be found by running `Firmware/find_programmer.sh` (make sure it has the latest firmware from STM).