.encoder.motor_dir` - This should print 1 or -1.
+* Copy these numbers to the corresponding entries in low_level.c: `.encoder.encoder_offset` and `.encoder.motor_dir`.
+ * _Warning_: Please be careful to enter the correct numbers, and not to confuse the motor channels. Incorrect values may cause the motor to spin out of control.
+* Set `.encoder.calibrated = true`.
+* Flash this configuration and check that the motor scans for the index pulse but skips the encoder calibration.
+* Congratulations, you are now done. You may now attach the motor to your mechanical load.
+
+
+* If you wish to scan for the index pulse in the other direction (if for example your axis usually starts close to a hard-stop), you can set a negative value in `.encoder.config.idx_search_speed`.
+* If your motor has problems reaching the index location due to the mechanical load, you can increase `.encoder.calibration_current`.
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 00000000..58622112
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,6 @@
+
+{% for section in site.data.index.sections %}
+## {{ section.title }}
+{% for item in section.docs %}
+ * [{{ item.title }}]({{ item.url }}) {% endfor %}
+{% endfor %}
diff --git a/docs/interfaces.md b/docs/interfaces.md
new file mode 100644
index 00000000..0f495f7d
--- /dev/null
+++ b/docs/interfaces.md
@@ -0,0 +1,68 @@
+# Interfaces
+
+**Warning:** While developing custom ODrive control code it is recommend that your motors are free to spin continuously and are not connected to a drivetrain with limited travel.
+
+The ODrive can be controlled over various interfaces and protocols.
+
+[TODO: include a picture that shows all interfaces with the supported protocols]
+
+### Setting up UART
+Baud rate: 115200
+Pinout:
+* GPIO 1: Tx (connect to Rx of other device)
+* GPIO 2: Rx (connect to Tx of other device)
+* GND: you must connect the grounds of the devices together. Use any GND pin on J3 of the ODrive.
+
+## Native protocol
+
+If you have a choice, this is the recommended protocol for all applications.
+
+### Python
+
+The ODrive tools you installed earlier come with a library that you can use to easily control the ODrive from Python.
+
+Assuming you already installed the odrive library (`pip install odrive`), the simplest program to control the ODrive is this:
+
+```
+import odrive.discovery
+odrv0 = odrive.discovery.find_any()
+print(str(odrv0.vbus_voltage))
+```
+
+For a more detailed example, see [odrive_demo.py](tools/odrive_demo.py).
+
+### Other languages
+
+We don't have an official library for you just yet. Check the community, there might be someone working on it. If you want to write a library yourself, refer to the [native protocol specification](protocol.md). You are of course welcome to contribute it back.
+
+## ASCII protocol
+
+This is a simpler alternative to the native protocol if you don't need all its bells and whistles. Before you use this, be sure that you're ok with its limitations.
+
+This protocol may be extended in the future to support a selected set of GCode commands.
+
+For more details, see the [ASCII protocol specification](ascii-protocol.md).
+
+### C++ (Arduino)
+
+[See ODrive Arduino Library](https://github.com/madcowswe/ODriveArduino)
+
+## Step/direction
+This is the simplest possible way of controlling the ODrive. It is also the most primitive and brittle one. So don't use it unless you must interoperate with other hardware that you don't control.
+
+Pinout:
+* GPIO 1: M0 step
+* GPIO 2: M0 dir
+* GPIO 3: M1 step
+* GPIO 4: M1 dir
+* GND: you must connect the grounds of the devices together. Use any GND pin on J3 of the ODrive.
+
+Please note that GPIO_3 and GPIO_4 are NOT 5v tolerant on ODrive v3.2 and earlier, so 3.3V signals only!
+ODrive v3.3 and onward have 5V tolerant GPIO pins.
+
+To enable step/dir mode for the GPIO, please see [Setting the GPIO mode](Firmware/README.md#communication-configuration).
+
+There is also a config variable called `counts_per_step`, which specifies how many encoder counts a "step" corresponds to. It can be any floating point value.
+The maximum step rate is pending tests, but it should handle at least 16kHz. If you want to test it, please be aware that the failure mode on too high step rates is expected to be that the motors shuts down and coasts.
+
+Please be aware that there is no enable line right now, and the step/direction interface is enabled by default, and remains active as long as the ODrive is in position control mode. By default the ODrive starts in position control mode, so you don't need to send any commands over USB to get going. You can still send USB commands if you want to.
diff --git a/docs/odrivetool.md b/docs/odrivetool.md
new file mode 100644
index 00000000..f1bb3056
--- /dev/null
+++ b/docs/odrivetool.md
@@ -0,0 +1,23 @@
+# ODrive Tool
+
+### Multiple ODrives
+By default, `odrivetool` will connect to any ODrive it finds. If this is not what you want, you can select a specific ODrive.
+
+If you have multiple ODrives connected, you should specify which one to connect to.
+* Run `(lsusb -d 1209:0d32 -v; lsusb -d 0483:df11 -v) 2>/dev/null | grep iSerial` to list the serial number of all flashable devices. Example output:
+```
+ iSerial 3 385F324D3037
+ iSerial 3 306A396A3235
+```
+* The last column is the serial number you're looking for. You can unplug selected devices to track down the one you want to update.
+* Run `odrivetool --serial-number=385F324D3037`, where `385F324D3037` is the targeted serial number.
+* To connect over serial, run `odrivetool --path serial`.
+
+## Device Firmware Update
+
+Note: ODrive v3.4 and earlier require you to flash with the external programmer first (see below), before you can reflash in standalone mode.
+
+* Run `make dfu` in the `Firmware` directory.
+* __Windows__: During the update, a new device called "STM32 BOOTLOADER" will appear. Open the [Zadig](http://zadig.akeo.ie/) utility and set the driver for "STM32 BOOTLOADER" to libusb-win32. After that the firmware update will continue.
+* On some machines you will need to unplug and plug back in the USB cable to make the PC understand that we switched from regular mode to bootloader mode.
+* Currently a firmware update will preserve the configuration if and only if the parameters of both firmware versions are identical. This will change in the future.
diff --git a/docs/quick-start.md b/docs/quick-start.md
new file mode 100644
index 00000000..15934295
--- /dev/null
+++ b/docs/quick-start.md
@@ -0,0 +1,169 @@
+# Quick Start Guide
+
+### Table of contents
+
+
+
+- [Wiring up the ODrive](#wiring-up-the-odrive)
+- [Downloading and Installing Tools](#downloading-and-installing-tools)
+- [Start `odrivetool`](#start-odrivetool)
+- [Configure M0](#configure-m0)
+- [Position control of M0](#position-control-of-m0)
+- [What's next?](#whats-next)
+
+
+
+## Wiring up the ODrive
+
+
+Make sure you have a good mechanical connection between the encoder and the motor, slip can cause disasterous oscillations.
+
+
+All non-power I/O is 3.3V output and 5V tolerant on input, except:
+ __ODrive v3.2__: GPIO 3 and GPIO 4 are __not__ 5V tolerant.
+
+You will need:
+
+* One or two [brushless motors](https://hackaday.io/project/11583-odrive-high-performance-motor-control/log/37666-hobby-motors-in-your-robots). It is fine, even recommended, to start testing with just a single motor and encoder.
+* One or two [quadrature incremental encoder(s)](https://discourse.odriverobotics.com/t/which-encoders-to-choose/63/2)
+* A power resistor. A good starting point would be a [0.47 ohm, 50W resistor](https://www.digikey.com/product-detail/en/te-connectivity-passive-product/HSA50R47J/A102181-ND/2056131)
+
+ Do I really need a power resistor? What values to choose?
+
+ If you don't have a brake resistor, the ODrive will pump excess power back into the power supply during deceleration to achieve the desired deceleration torque. If your power supply doesn't eat that power (which it won't if it's not a battery), the bus voltage will inevitebly rise. If you're unlucky this will break the power supply.
+ At some point, the ODrive's overvoltage protection will trip, after which both motors will be allowed to spin freely. Depending on your machine, this may or may not be a problem.
+
+ The power resistor values you need depends on your motor setup, and peak/average deceleration power.
+
+ To be on the safe side, think about what speed and current limits you want to set for the motor.
+
+ When braking at max speed and with maximum motor current, the power that is dissipated in the power resistor can be calulated as: `P_brake = V_emf * I_motor` where `V_emf = motor_kv * V_bus`.
+
+
+
+* A power supply (12V-24V for the 24V board variant, 12V-48V for the 48V board variant). A battery is also fine.
+
+1. Wire up the motor phases into the 3-phase screw terminals, and the power resistor to the AUX terminal. Wire up the power source to the DC terminal, make sure to pay attention to the polarity. Do not apply power just yet.
+
+2. Wire up the encoder(s) to J4. The A,B phases are required, and the Z (index pulse) is optional. The A,B and Z lines have 3.3k pull up resistors, for use with open-drain encoder outputs. For single ended push-pull signals with weak drive current (\<4mA), you may want to desolder the pull-ups.
+
+
+
+## Downloading and Installing Tools
+
+Most instructions in this guide refer to a utility called `odrivetool`, so you should install that first.
+
+### Windows
+
+1. Install Python 3. We recommend the Anaconda distribution because it packs a lot of useful scientific tools, however you can also install the standalone python.
+ * __Anaconda__: Download the installer from [here](https://www.anaconda.com/download/#windows). Execute the downloaded file and follow the instructions.
+ * __Standalone Python__: Download the installer from [here](https://www.python.org/downloads/). Execute the downloaded file and follow the instructions.
+ * If you have Python 2 installed alongside Python 3, replace `pip` by `C:\Users\YOUR_USERNAME\AppData\Local\Programs\Python\Python36-32\Scripts\pip`. If you have trouble with this step then refer to [this walkthrough](https://www.youtube.com/watch?v=jnpC_Ib_lbc).
+2. Launch the command prompt.
+ * __Anaconda__: In the start menu, type `Anaconda Prompt` Enter
+ * __Standalone Python__: In the start menu, type `cmd` Enter
+3. Install the ODrive tools by typing `pip install odrive` Enter
+4. Plug in a USB cable into the microUSB connector on ODrive, and connect it to your PC.
+5. Use the [Zadig](http://zadig.akeo.ie/) utility to set ODrive driver to libusb-win32.
+ * If 'Odrive version 3.x' is not in the list of devices upon opening Zadig, check 'List All Devices' from the options menu. With the Odrive selected in the device list choose 'libusb-win32' from the target driver list and select the large 'install driver' button.
+
+
+### Linux/macOS
+
+1. [Install Python 3](https://www.python.org/downloads/).
+2. Install the ODrive tools by opening a terminal and typing `pip install odrive` Enter
+3. __Linux__: set up USB permissions
+```
+ echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1209", ATTR{idProduct}=="0d[0-9][0-9]", MODE="0666"' | sudo tee /etc/udev/rules.d/50-odrive.rules
+ sudo udevadm control --reload-rules
+ sudo udevadm trigger # until you reboot you may need to do this everytime you reset the ODrive
+```
+
+## Start `odrivetool`
+To launch the main interactive ODrive tool, type `odrivetool` Enter. Connect your ODrive and wait for the tool to find it. Now you can for instance type `odrv0.vbus_voltage` Enter to inpect the boards main supply voltage.
+It should look something like this:
+
+```
+ODrive control utility v0.4.0
+Please connect your ODrive.
+Type help() for help.
+
+Connected to ODrive 306A396A3235 as odrv0
+In [1]: odrv0.vbus_voltage
+Out[1]: 11.97055721282959
+```
+
+The tool you're looking at is a fully capable Python command prompt, so you can type any valid python code.
+
+## Configure M0
+
+Read this section carefully, else you risk breaking something.
+
+1. Set the limits:
+
+ Wait, how do I set these?
+
+ In the previous step we started `odrivetool`. In there, you can assign variables directly by name.
+
+ For instance, to set the current limit of M0 to 10A you would type: `odrv0.axis0.motor.config.current_lim = 10` Enter
+
+
+
+ * The current limit: `odrv0.axis0.motor.config.current_lim` [A]. The default current limit, for safety reasons, is set to 10A. This is quite weak, and good for making sure the drive is stable. Once you have tuned the drive, you can increase this to 75A to get some performance. Note that above 75A, you must change the current amplifier gains.
+ * Note: The motor current and the current drawn from the power supply is not the same in general. You should not look at the power supply current to see what is going on with the motor current.
+ * The velocity limit: `odrv0.axis0.motor.config.vel_limit` [counts/s]. The motor will be limited to this speed; again the default value is quite slow.
+ * You can change `odrv0.axis0.motor.config.calibration_current` [A] to the largest value you feel comfortable leaving running through the motor continously when the motor is stationary.
+
+2. Set other hardware parameters:
+
+ * `odrv0.config.brake_resistance` [Ohm]: This is the resistance of the brake resistor. If you are not using it, you may set it to `0`.
+ * `odrv0.axis0.motor.config.pole_pairs`: This is the number of **magnet poles** in the rotor, **divided by two**. You can simply count the number of permanent magnets in the rotor, if you can see them. _Note: this is not the same as the number of coils in the stator._
+ * `odrv0.axis0.motor.config.motor_type`: This is the type of motor being used. Currently two types of motors are supported: High-current motors (`MOTOR_TYPE_HIGH_CURRENT`) and Gimbal motors (`MOTOR_TYPE_GIMBAL`).
+
+ Which `motor_type` to choose?
+
+ If you're using a regular hobby brushless motor like [this](https://hobbyking.com/en_us/turnigy-aerodrive-sk3-5065-236kv-brushless-outrunner-motor.html) one, you should set `motor_mode` to `MOTOR_TYPE_HIGH_CURRENT`. For low-current gimbal motors like [this](https://hobbyking.com/en_us/turnigy-hd-5208-brushless-gimbal-motor-bldc.html) one, you should choose `MOTOR_TYPE_GIMBAL`. Do not use `MOTOR_TYPE_GIMBAL` on a motor that is not a gimbal motor, as it may overheat the motor or the ODrive.
+
+ **Further detail:**
+ If 100's of mA of current noise is "small" for you, you can choose `MOTOR_TYPE_HIGH_CURRENT`.
+ If 100's of mA of current noise is "large" for you, and you do not intend to spin the motor very fast (omega * L << R), and the motor is fairly large resistance (1 ohm or larger), you can chose `MOTOR_TYPE_GIMBAL`.
+ If 100's of mA current noise is "large" for you, _and_ you intend to spin the motor fast, then you need to replace the shunt resistors on the ODrive.
+
+
+
+ * `odrv0.axis0.encoder.config.cpr`: Encoder Count Per Revolution (CPR). This is 4x the Pulse Per Revolution (PPR) value. Usually this is indicated in the datasheet of your encoder.
+
+## Position control of M0
+
+Let's get motor 0 up and running. The procedure for motor 1 is exactly the same, so feel free to replace read "axis1" wherever it says "axis0".
+
+1. Type `odrv0.axis0.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE` Enter. After about 2 seconds should hear a beep. Then the motor will turn slowly in one direction for a few seconds, then back in the other direction.
+
+ What's the point of this?
+ This procedure first measures your motor's electrical properties (namely phase resistance and phase inductance) and then the offset between the motor's electrical phase and the encoder position.
+
+
+
+ The startup procedure is demonstrated [here](https://www.youtube.com/watch?v=VCX1bA2xnuY).
+
+ Note: the rotor must be allowed to rotate without any biased load during startup. That means mass and weak friction loads are fine, but gravity or spring loads are not okay. Also note that in the video, the motors spin after initalisation, but in the current software the default behaviour is to do position control to position 0 (i.e. the position at startup)
+
+ My motor doesn't beep or doesn't turn
+
+ Make sure the motor wires are connected firmly. Check the value of `odrv0.axis0.error` and then refer to the [error code documentation](troubleshooting.md#error-codes) for details.
+
+ Once you have understood the error and fixed its cause, you may clear the error state (`odrv0.axis0.error = 0` Enter) and retry. You may also need to clear the error state of other subcomponents (e.g. `odrv0.axis0.motor.error`).
+
+
+
+3. Type `odrv0.axis0.motor.config.pre_calibrated = True` Enter and then `odrv0.save_configuration()` Enter. This will save all the configuration and calibration you just did so the next time you start the device it's already ready to go. Except for one thing: you need to run the encoder offset calibration after every power cycle.
+4. Type `odrv0.axis0.requested_state = AXIS_STATE_CLOSED_CONTROL_LOOP` Enter. From now on the ODrive will try to hold the motor's position. If you try to turn it by hand, it will fight you gently. That is unless you bump up `odrv0.axis0.motor.config.current_lim`, in which case it will fight you more fiercely.
+
+## What's next?
+
+You can now:
+
+ * Set the [tuning parameters](commands#tuning-parameters) for better performance
+ * Control the ODrive from your own program or hook it up to an existing system through one of it's [interfaces](interfaces)
+
+If you have any issues or any questions please get in touch. The [ODrive Community](https://discourse.odriverobotics.com/) warmly welcomes you.
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
new file mode 100644
index 00000000..956480fb
--- /dev/null
+++ b/docs/troubleshooting.md
@@ -0,0 +1,144 @@
+# Troubleshooting
+
+## Error codes
+If your ODrive is not working as expected, run `odrivetool` and type `hex(odrv0.axis0.error)` Enter. This will display a [hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) representation of the error code. Each bit represents one error flag.
+
+Example
+
+Say you typed `hex(odrv0.axis0.error)` and got `0x6` as a result. Written in binary this number corresponds to `110`, so bits 1 and 2 are set.
+
+Looking at the reference below, this means that both `ERROR_DC_BUS_UNDER_VOLTAGE` and `ERROR_DC_BUS_OVER_VOLTAGE` occurred.
+
+
+
+There is a slight chance that the values here are out of sync with the actual firmware. To be completely sure, check the linked definition in the source code.
+
+### Axis error flags
+
+Defined [here](../Firmware/MotorControl/axis.hpp)
+
+0. `ERROR_INVALID_STATE`
+1. `ERROR_DC_BUS_UNDER_VOLTAGE`
+2. `ERROR_DC_BUS_OVER_VOLTAGE`
+3. `ERROR_CURRENT_MEASUREMENT_TIMEOUT`
+4. `ERROR_BRAKE_RESISTOR_DISARMED`
+5. `ERROR_MOTOR_DISARMED`
+6. `ERROR_MOTOR_FAILED` (check `.motor.error` for more details)
+7. `ERROR_SENSORLESS_ESTIMATOR_FAILED` (check `.sensorless_estimator.error` for more details)
+8. `ERROR_ENCODER_FAILED` (check `.encoder.error` for more details)
+9. `ERROR_CONTROLLER_FAILED`
+10. `ERROR_POS_CTRL_DURING_SENSORLESS`
+
+### Motor error flags
+
+Defined [here](MotorControl/motor.hpp)
+
+0. ERROR_PHASE_RESISTANCE_OUT_OF_RANGE
+1. ERROR_PHASE_INDUCTANCE_OUT_OF_RANGE
+2. ERROR_ADC_FAILED
+3. ERROR_DRV_FAULT
+4. ERROR_CONTROL_DEADLINE_MISSED
+5. ERROR_NOT_IMPLEMENTED_MOTOR_TYPE
+6. ERROR_BRAKE_CURRENT_OUT_OF_RANGE
+7. ERROR_NUMERICAL
+
+### Encoder error flags
+
+Defined [here](MotorControl/encoder.hpp)
+
+0. ERROR_NUMERICAL
+1. ERROR_CPR_OUT_OF_RANGE
+2. ERROR_RESPONSE
+
+### Sensorless estimator error flags
+
+Defined [here](MotorControl/sensorless_estimator.hpp)
+
+0. ERROR_NUMERICAL
+
+
+### Cannot connect to the ODrive
+
+ensure no other ODrive program is running
+prepend `PYUSB_DEBUG=debug` to the script
+
+## USB issues ##
+
+* Firmware:
+ 1. ODrive Firmware
+ 2. STM HAL code
+* Electrical:
+ 1. ODrive hardware
+ 2. connection (cables, hub)
+* PC side
+ 1. PC-side USB host controller
+ 2. kernel
+ 3. libusb driver
+ 4. libusb library
+ 5. PyUSB
+ 6. python code
+
+
+
+## DRV fault ##
+
+Hardware: 5330 (190kv), v3.4-48V, V_bus=12V
+Settings: default gains, current_lim=50A, position control, stationary
+Action: Applying a high torque manually
+Result: Trips at I_q=45A (+- 2A) on the big motor, I_q=50A (+-1A) on the black motor, I_bus=8.3A (+-0.4),
+
+phase=-2.3
+-2.7 (did not trip from -0.5 to -2.7 @ 50A)
+-2.8
+-2.7
+-2.4689412117004395
+0.7
+0.5
+
+other odrive:
+-0.8651647567749023
+
+Repeatability: about 5/5
+
+
+```
+ODrive control utility v0.3.7.dev
+Please connect your ODrive.
+Type help() for help.
+
+Connected to ODrive 385F324D3037 as odrv1
+In [1]: odrv1.axis0.requested_state = AXIS_STATE_ENCODER_OFFSET_CALIBRATION
+In [2]: start_liveplotter(lambda: [odrv1.axis0.motor.current_control.Ibus, odrv1.axis0.motor.current_control.Iq_setpoint])
+In [4]: odrv1.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
+In [9]: odrv1.axis0.motor.config.current_lim=50
+In [11]: odrv1.axis0.controller.config.vel_limit
+Out[11]: 20000.0
+In [12]: odrv1.axis0.controller.config.vel_gain
+Out[12]: 0.0005000000237487257
+```
+
+
+
+```
+In [9]: odrive.utils.print_drv_regs("M0",odrv1.axis0.motor)
+M0: 0
+DRV Fault Code: 0
+Status Reg 1: 0 (0b00000000)
+Status Reg 2: 1 (0b00000001)
+Control Reg 1: 1360 (0b10101010000)
+Control Reg 2: 8 (0b0001000)
+
+In [10]: odrive.utils.print_drv_regs("M1",odrv1.axis0.motor)
+M1: 0
+DRV Fault Code: 0
+Status Reg 1: 0 (0b00000000)
+Status Reg 2: 1 (0b00000001)
+Control Reg 1: 1360 (0b10101010000)
+Control Reg 2: 8 (0b0001000)
+
+In [11]: (hex(odrv1.axis0.error), hex(odrv1.axis0.motor.error))
+Out[11]: ('0x41', '0x18')
+
+In [12]: (hex(odrv1.axis1.error), hex(odrv1.axis1.motor.error))
+Out[12]: ('0x61', '0x10')
+```