Skip to content

Latest commit

 

History

History
207 lines (133 loc) · 14.1 KB

CONTRIBUTING.md

File metadata and controls

207 lines (133 loc) · 14.1 KB

Contributing to Castor & Pollux / Gemini

Oh hey, it's super cool that you're interested in contributing. We love contributors! Before you jump in, take a minute to:

  1. Read our Code of Conduct
  2. Read our license - it's important to know what rights you have and cede when contributing to this project.
  3. For anything that can't be explained in one sentence, please file an issue about what you want to contribute. This gives us a chance to talk before you get too deep into things. We promise that it'll help make your experience more fun. If there's an existing issue that's related, feel free to comment on it.
  4. Read through our commit and pull request conventions
  5. If you want to help out with the user guide, read through the contributing to the user guide section.
  6. If contributing changes to the firmware (Gemini), read through the contributing to the firmware section.
  7. If contributing changes to the hardware designs, read through contributing to the hardware section.

Commit & Pull Request conventions

We aren't super rigid here and we're happy to rename your PR/commit to the right format, but, if you wanna help us out you can write your commits in this form:

{category}: {short description}

{long description}

Fixes / Related to / Part of #{issue number}

For category, add whichever of these fits:

  • docs for anything related to the user guide
  • hardware for anything related to the hardware
  • firmware for anything related to the firmware that don't fit into any other category
  • build for anything related to building the firmware, such as changes to the Makefiles or generated code.
  • third_party for anything that touches code in firmware/third_party
  • settings editor for changes related to the WebMIDI settings editor at user_guide/docs/settings.md.
  • factory for changes related to the factory setup scripts.
  • meta for changes to project-wide things like the README, this file, scripts, etc

You can add multiple categories or leave it out and we'll figure it out together. :)

For pull requests, please keep in mind we'd rather you send one that's not quite ready and start a discussion that keep a big change secret and send it all at once! That's also why we recommend filing an issue before getting starting on changing the code.

Contributing to the user guide

Did you find a typo? Got a hot tip you want to add? Wonderful! The user guide is located in the user_guide directory. It's built using MkDocs so as long as you know Markdown you can contribute!

You don't have to test your changes to the user guide locally, but, if you want to you'll need to install some Python packages:

$ cd user_guide
$ python3 -m pip install -r requirements.txt

After that you can run MkDocs to test out your changes:

$ mkdocs serve

Contributing to the hardware

The hardware design was created using KiCAD. That should be all you need to edit the hardware design files.

When sending pull requests that make hardware changes, please be very descriptive about what your change does. This helps us out because it's actually kind of hard to review changes to KiCAD files.

Contributing to the firmware

The firmware is the most complicated bit to contribute to, but, we're happy to guide you along the way. Please take a moment to look over the guidelines here- we don't expect you to get them perfectly right the first time, but you'll have to make sure that your pull request follows these guidelines before we can merge.

General information

Castor & Pollux's firmware is called Gemini. It's written in C using the GNU Dialect of ISO C17.

Gemini runs on a Microchip SAM D21 microcontroller. It's a 48 MHz, 32-bit ARM Cortex-M0+. The specific part used in Castor & Pollux is the ATSAMD21G18A. It has 256 kB of built-in flash memory and 32 kB of SRAM.

The primary purpose of Gemini is to read the status of the input jacks and potentiometers on the front panel and control the two oscillators based on their state. Gemini uses the built-in 12-bit multichannel ADC to read the state of the module and uses two 24-bit timers and an external 12-bit DAC to control the oscillators. You can read more about how the oscillators are controlled in Stargirl's article on Juno oscillators.

The majority of the code in Gemini is used for the input/output loop but there's some additional code for animating the LEDs, storing the user-configurable settings, and enabling configuration over USB (via MIDI SysEx).

Note that Gemini is a bare-metal ARM project. It doesn't use anything like the Arduino framework, platform.io, or any vendor-supplied frameworks like ASF4 or Harmony. It might seem a little intimidating but we've done a lot to try to make it approachable for contributors.

Directory layout

The firmware is organized into several directories:

  • src/ contains the primary headers and implementation files for the firmware. You'll notice that files are prefixed with gem_ throughout this directory.
  • src/drivers/ contains code used to communicate with devices external to the MCU - such as the ADC and the LEDs.
  • src/hw/ contains a very thin hardware abstraction layer (HAL) over the SAM D21 peripherals used by Gemini.
  • src/lib/ contains non-hardware specific modules and helpers. This directory will eventually be moved to another repository (and which point it'll be in third_party).
  • tests/ contains some basic tests for some of Gemini's functionality. The tests are definitely not comprehensive at this point- but it's something we plan on improving over time.
  • third_party/ contains all dependencies needed to build the firmware. See third-party code for more details.

Coding conventions

Try to follow these guidelines when submitting code. It's okay if you don't get them all right - that's what code review is for and we don't bite! The golden rule is:

Look at the code nearby and try to look like it

Silly stuff like whitespace and formatting is done using a formatter, so don't sweat that too much.

Names:

  • Files should be named gem_{thing}.h & gem_{thing}.c.
  • Public functions should be named using lower_snake_case() and should contain the gem_ prefix. The general format for function is gem_{noun}_{verb}() Examples: gem_adc_read(), gem_dotstar_set().
  • Static functions should be named using lower_snake_case(). They don't need to have any prefix unless they have a name collision.
  • Public structs and enums should be named using PascalCase and should have the Gem prefix. Examples: GemADCInput, GemSettings.
  • Structs and enums should not have typedef aliases, we prefer to use the full struct StructName.
  • Macros and constants should be SHOUTY_SNAKE_CASE.
  • Static variables should have a trailing _. For example: sysex_callbacks_.
  • Give variables descriptive names and don't try to optimize for name length. Abbreviations for common stuff like idx, buf, len, and num are fine if they're used in a descriptive name. For example, prefer current_input_idx over just idx.

Types:

  • Use fixed-width integer types from stdint.h such as uint8_t, int16_t, etc.
  • Use stdbool.h for booleans.
  • Use size_t for anything that stores the size of something and anything that is an offset / array index.
  • Never use float or double. The Cortex-M0+ does not have floating-point hardware. Use fixed-point arithmetic form fix16.h instead.

Comments:

  • Prefer /* */, but we don't have anything against //.
  • Comment every public function and comment on anything that's non-obvious or surprisingly. Err on the side of commenting too much rather than too little- it's easy to remove in the future but it's hard to pull the context back out of your head later.
  • Some of this codebase is written in the Literate Programming style. This isn't a requirement for contributors.

Printing

  • Instead of using printf and friends from stdio.h use the equivalent functions from printf.h. Printing to stdout in debug builds will print to the RTT buffer. In release builds RTT is disabled.

Compiler warnings & errors:

Assertions:

  • Use static_assert from assert.h for any compile-time assertions.
  • Use WNTR_ASSERT from wntr_assert.h for run-time asserts. WNTR_ASSERT will restart the MCU if an assert fails in a release build which is preferable to continuing in an undefined state.

Other stuff:

Linting & formatting

Rather than waste people's time with manually checking for silly things like whitespace or bracket locations, we just use clang-format.

You can run it against all of the code in firmware using:

$ make format

We also use clang-tidy to check for pitfalls that the C language leaves around for us. It's not required for clang-tidy to pass. You can run it with:

$ make tidy

Building the firmware

Gemini is built using the GNU ARM Compiler Toolchain. We highly recommend installing it directly from ARM instead of relying on package managers since they tend to be pretty out of date.

Gemini uses Python 3.9+ & Ninja build the firmware. You'll need to run the configure script to generate the ninja build file and then run ninja to build the firmware.

$ cd firmware
$ python3 configure.py
$ ninja

The firmware is built in firmware/build and is available as gemini-firmware.elf (it also creates .bin and .uf2 versions as well.)

To create a release build use:

$ cd firmware
$ python3 configure.py --config release
$ ninja

Loading and debugging

If you want to try your code out quickly and don't really want/need a debugger, you can flash the gemini-firmware.uf2 file using the updating the firmware instructions in the user guide.

If you want to debug and do more advanced stuff, you'll need a hardware debugger. Adafruit has a great guide on debugging SAM D-based MCUs that is recommended reading.

You'll need a debugger such as a J-Link EDU. We highly recommend the J-Link since we use Segger's RTT for printing information in debug builds.

The pins used for debugging/programming are located on the bottom of the module:

Location of debug pins

Castor & Pollux uses the Tag-Connect TC2030 for programming. If you have a Tag-Connect TC2030-CTX-NL cable just connect it to your debugging and Castor & Pollux and you're good to go. If you don't have one, you can solder to the individual pads. The pads are numbered like this:

Tag-Connect footprint pin numbers

And correspond to the following SWD signals:

  1. VCC
  2. SWDIO
  3. RESET
  4. SWCLK
  5. GND
  6. SWO (not connected)

Once you've physically connected to Castor & Pollux you can use arm-none-eabi-gdb to load, run, and debug your code. You can use JLinkRTTViewer to view debug messages. Gemini also has the Micro Trace Buffer enabled for better stack tracing.

Third-party code

Oh god you made it all the way down here. Well, since you're here let's talk about third-party code. Everything that isn't a direct part of Gemini's firmware should be placed in firmware/third_party. This includes other things written by Winterbloom that are used here (like structy for example).

We don't use git submodules, instead, we import the parts of the third-party code that we need into this repository. When adding third-party code you absolutely must include the code's LICENSE/COPYING/NOTICE/etc. Copyright information must be preserved. You should also update firmware/LICENSE to incorporate the copyright info from the imported library.