diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..9b03fb32a06d419b7025e7900fcc3027420ef18a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,268 @@
+# Hardware
+
+## Board DC Motor Driver Hat DFRobot DFR0592
+
+-   [Main page](https://www.dfrobot.com/product-1911.html)
+-   [Wiki](https://wiki.dfrobot.com/DC_Motor_Driver_HAT_SKU_DFR0592)
+-   [Schematics](https://dfimg.dfrobot.com/nobody/wiki/7e756410f3e4c915a21cacd63f98e337.pdf)
+
+## Microcontroller STM32F103C8T6 (medium density)
+
+-   [Documentation](https://www.st.com/en/microcontrollers-microprocessors/stm32f103c8.html#documentation)
+-   [Reference
+    manual](https://www.st.com/resource/en/reference_manual/rm0008-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf)
+-   [Programming
+    manual](https://www.st.com/resource/en/programming_manual/pm0056-stm32f10xxx20xxx21xxxl1xxxx-cortexm3-programming-manual-stmicroelectronics.pdf)
+
+### Useful onboard peripherals
+
+  Peripheral                  N
+  --------------------------- -------
+  Flash                       64kiB
+  RAM                         20kiB
+  Timers (general purpose)    3
+  Timers (advanced control)   1
+  CPU frequency               72MHz
+  I2C                         2
+
+The `I2C2` is used (`PB10`/`SCL`, `PB11`/`SDA`) to communicate with
+the TB6612FNG motor driver.
+
+### Flash-memory organization
+
+-   Main memory: 64 pages of 1KiB
+-   Page erasable
+-   Programmable by half-words
+-   `VTOR` must be aligned with the number of exception entries or 128
+    bits, whichever is largest. To use all DMA channels (`DMA2_Channel4_5`
+    is at position 59), an alignment of 256 is required. In any case,
+    aligning it on a page boundary will work.
+
+## Driver IC TB6612FNG for dual DC motor
+
+-   [Datasheet](https://www.sparkfun.com/datasheets/Robotics/TB6612FNG.pdf)
+
+## Encoders FIT0450
+
+-   [Wiki](https://wiki.dfrobot.com/Micro_DC_Motor_with_Encoder-SJ01_SKU__FIT0450)
+
+# Led pattern
+
+The led pattern is in Morse code.
+
+  Code   Meaning                                                Pattern
+  ------ ------------------------------------------------------ -----------
+  I      Regular mode                                           ..
+  LP     Low power (Vdd is below 2.9V)                          .-.. .--.
+  WW     Last reset was due to the window watchdog trigerring   .-- .--
+
+# Motor controller command set
+
+I²C address: 0x57
+
+I²C uses clock stretching, so care must be taken when using a Raspberry
+Pi whose SOC is bogus. Using 400kHz instead of the default 100kHz seems
+to mask the problem if not outputting too much debug information. Using
+a software I²C solves the issue.
+
+Multibyte values are exchanged in little endian format.
+
+## \[IMPLEMENTED\] 0x08 Firmware version (R)
+
+-   Return three bytes containing the major, minor and patch version
+    numbers derived from `Cargo.toml`.
+
+## \[IMPLEMENTED\] 0x0F Who am I? (R)
+
+-   The I²C address
+
+## 0x10 \[IMPLEMENTED\] PWM frequency (R/W)
+
+-   Frequency in Hz on 3 bytes, from 1 to 100~000~ (default: 10~000~)
+
+## 0x14 Encoder to motor reduction (R/W)
+
+-   Between 1 and 255. 0 disable encoder control (default 0)
+
+## \[IMPLEMENTED\] 0x20-0x22 PID coefficients (R/W)
+
+The PID will be working at 100Hz.
+
+P, I and D are expressed as 32 bit signed numbers with a 28 bit integer
+part and 4 bit fractional part.
+
+-   0x20: P (4 bytes). Default value is 0x0000~0004~ (0.25)
+-   0x21: I (4 bytes). Default value is 0x0000~0000~ (0.0)
+-   0x22: D (4 bytes). Default value is 0x0000~0000~ (0.0)
+
+Changing the coefficients will take effect only when the controlled mode
+is off, for example by setting the motors to standby mode.
+
+## 0x26 Ramp time (R/W)
+
+-   In automatic motor distance, time in 100th of seconds to reach the
+    maximum speed or to decrease the speed from the maximum to 0.
+
+## \[IMPLEMENTED\] 0x28 Motor shutdown timeout (R/W)
+
+-   Number of tenths of seconds in before the motor shut down. The
+    minimum is 1 (0.1 seconds) and the maximum is 100 (10 seconds).
+
+## \[IMPLEMENTED\] 0x30 Raw motor speed (R/W)
+
+-   Left and right motor speed, between -100 and 100 each, max speed is
+    ±100. None means standby. ±100 corresponds to the value limited by
+    the max motor percentage.
+-   This is the raw speed sent to the motor, no PID is computed.
+-   If written while in controlled mode, the robot switches to manual
+    mode
+
+## \[IMPLEMENTED\] 0x31 Controlled motor speed (R/W)
+
+-   Left and right motor speed, beween -32767 and 32767 each. The unit
+    is the number of ticks per 100th of seconds.
+-   Each motor will be controlled by a separate PID with shared
+    coefficients.
+-   Using a speed of (0, 0) will exit the controlled mode and switch to
+    raw mode. This allows the PID coefficients to be updated if needed.
+-   Speed will be returned as (-32768, -32768) if controlled mode is not
+    active.
+
+## \[IMPLEMENTED\] 0x32 Encoder ticks (R)
+
+-   Left and right encoder counters since last time, 2 complement, 2
+    bytes each
+
+## \[IMPLEMENTED\] 0x36 Status (R)
+
+-   Bit 0: moving (1) or idle (0)
+-   Bit 1: controlled mode (1) or raw mode (0)
+
+## 0x37-0x3A Automatic motor distance (R/W) \[optional\]
+
+-   Left and right distance in number of encoder ticks, between -32768
+    and 32767 each.
+-   Reading this value gives the distance to the target in ticks.
+-   If left and right distances are not equal, they will be kept
+    proportional as much as possible in order to progress the same way.
+
+## 0x40-0x43 Music (W) \[optional\]
+
+-   For each motor, left then right, frequency in Hz on 1 byte and
+    duration in 10th of seconds on 1 byte. This cannot be used if the
+    motor is moving.
+
+## \[IMPLEMENTED\] 0xE0 Reset (W)
+
+-   Reset the device. Used mainly for testing.
+
+## \[IMPLEMENTED\] 0xE1 Reset to bootloader (W)
+
+-   Reset the device in bootloader mode. Used when reprogramming.
+
+## \[IMPLEMENTED\] 0xF0 Unique device ID (R)
+
+-   Unique device ID as found in addresses 0x1FFFF7E8-0x1FFFF7EF
+
+## \[IMPLEMENTED\] 0xFE Firmware capabilities (R)
+
+-   Bit 0: bootloader feature is activated
+
+# Bootloader command set
+
+If a firmware is present, the bootloader will start it unless the
+firmware has explicitly chosen to reboot in bootloader mode.
+
+I²C address: 0x58
+
+The note about clock stretching also applies for the bootloader.
+
+## \[IMPLEMENTED\] 0x08 Firmware version (R)
+
+-   Return three bytes containing the major, minor and patch version
+    numbers derived from `Cargo.toml`.
+
+## \[IMPLEMENTED\] 0x0F Who am I? (R)
+
+-   The I²C address
+
+## \[IMPLEMENTED\] 0x10 Status (R)
+
+Returns two bytes:
+
+-   One set of flags ORed together:
+    -   0x01: system is in programming mode
+    -   0x02: at least one error was detected since the last time the
+        system has been put in programming mode
+    -   0x04: a program is currently present in flash
+-   A XORed version of all data received so far since the programming
+    address was last set, either by entering programming mode, or by
+    using the SET PROGRAMMING ADDRESS command.
+
+## \[IMPLEMENTED\] 0x20 Change programming mode (W)
+
+-   0: leave programming mode without marking the application as
+    succesfully written
+-   1: leave programming mode and mark the application as succesfully
+    written
+-   \[0x17, 0x27, 0x65, 0x40\]: enter programming mode
+
+## \[IMPLEMENTED\] 0x24 Erase pages (W) \[PROGRAMMING MODE\]
+
+-   First byte: index of the first 1kB page in the application area
+-   Second byte: number of pages to erase (up to the end of the
+    application area)
+-   Third byte: XOR of the first two bytes, as a safety
+
+The memory will be erased. The active programming address is then set to
+the beginning of the erased area.
+
+Even if the last page of the application does not belong to the erased
+page set, it will be erased with the first erase request of the current
+session (or after having being set again) to ensure that the application
+is no longer considered valid.
+
+Designating address outside the application area, or having a wrong
+checksum, will be an error.
+
+## \[IMPLEMENTED\] 0x28 Set programming address (W) \[PROGRAMMING MODE\]
+
+-   4 bytes containing the next address to program, relative to the
+    application start
+-   One byte XORing the previous ones
+
+## \[IMPLEMENTED\] 0x2c Program data (W) \[PROGRAMMING MODE\]
+
+-   2, 4, 6, or 8 data bytes
+-   One byte XORing the previous ones
+
+In case of error, the bootloader leaves programming mode immediately.
+
+The programming address will advance with the right number of bytes.
+
+## \[IMPLEMENTED\] 0x30 Read memory (R) \[PROGRAMMING MODE\]
+
+-   Read 8 consecutive bytes in memory from the programming address
+    (relative to the applicatin start), and advance it by 8.
+
+0 will be returned outside the application memory area.
+
+## \[IMPLEMENTED\] 0x34 Set checksum (W) \[PROGRAMMING~MODE~\]
+
+-   Set the checksum value to the given byte.
+
+## \[IMPLEMENTED\] 0xE0 Reset (W)
+
+-   Reset the bootloader in automatic mode
+
+## \[IMPLEMENTED\] 0xE1 Reset to the bootloader (W)
+
+-   Reset the bootloader in bootloader mode
+
+## \[IMPLEMENTED\] 0xE2 Reset to the application (W)
+
+-   Reset the bootloader in application mode
+
+## \[IMPLEMENTED\] 0xF0-0xF7 Unique device ID (R)
+
+-   Unique device ID as found in addresses 0x1FFFF7E8-0x1FFFF7EF
diff --git a/README.org b/README.org
deleted file mode 100644
index bfcfc4ea4a5f3e5e623ad404ae14cf1c6c19a15c..0000000000000000000000000000000000000000
--- a/README.org
+++ /dev/null
@@ -1,262 +0,0 @@
-* Hardware
-
-** Board DC Motor Driver Hat DFRobot DFR0592
-
-- [[https://www.dfrobot.com/product-1911.html][Main page]]
-- [[https://wiki.dfrobot.com/DC_Motor_Driver_HAT_SKU_DFR0592][Wiki]]
-- [[https://dfimg.dfrobot.com/nobody/wiki/7e756410f3e4c915a21cacd63f98e337.pdf][Schematics]]
-
-** Microcontroller STM32F103C8T6 (medium density)
-
-- [[https://www.st.com/en/microcontrollers-microprocessors/stm32f103c8.html#documentation][Documentation]]
-- [[https://www.st.com/resource/en/reference_manual/rm0008-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf][Reference manual]]
-- [[https://www.st.com/resource/en/programming_manual/pm0056-stm32f10xxx20xxx21xxxl1xxxx-cortexm3-programming-manual-stmicroelectronics.pdf][Programming manual]]
-
-*** Useful onboard peripherals
-
-| Peripheral                | N     |
-|---------------------------+-------|
-| Flash                     | 64kiB |
-| RAM                       | 20kiB |
-| Timers (general purpose)  | 3     |
-| Timers (advanced control) | 1     |
-| CPU frequency             | 72MHz |
-| I2C                       | 2     |
-
-The =I2C2= is used (=PB10=/=SCL=, =PB11=/=SDA=) to communicate with
-the TB6612FNG motor driver.
-
-*** Flash-memory organization
-
-- Main memory: 64 pages of 1KiB
-- Page erasable
-- Programmable by half-words
-- ~VTOR~ must be aligned with the number of exception entries or 128
-  bits, whichever is largest. To use all DMA channels (DMA2_Channel4_5
-  is at position 59), an alignment of 256 is required. In any case,
-  aligning it on a page boundary will work.
-
-** Driver IC TB6612FNG for dual DC motor
-
-- [[https://www.sparkfun.com/datasheets/Robotics/TB6612FNG.pdf][Datasheet]]
-
-** Encoders FIT0450
-
-- [[https://wiki.dfrobot.com/Micro_DC_Motor_with_Encoder-SJ01_SKU__FIT0450][Wiki]]
-
-* Led pattern
-
-The led pattern is in Morse code.
-
-| Code | Meaning                                              | Pattern   |
-|------+------------------------------------------------------+-----------|
-| I    | Regular mode                                         | ..        |
-| LP   | Low power (Vdd is below 2.9V)                        | .-.. .--. |
-| WW   | Last reset was due to the window watchdog trigerring | .-- .--   |
-
-* Motor controller command set
-
-I²C address: 0x57
-
-I²C uses clock stretching, so care must be taken when using a
-Raspberry Pi whose SOC is bogus. Using 400kHz instead of the default
-100kHz seems to mask the problem if not outputting too much debug
-information. Using a software I²C solves the issue.
-
-Multibyte values are exchanged in little endian format.
-
-** [IMPLEMENTED] 0x08 Firmware version (R)
-
-- Return three bytes containing the major, minor and patch version numbers
-  derived from =Cargo.toml=.
-
-** [IMPLEMENTED] 0x0F Who am I? (R)
-
-- The I²C address
-
-** 0x10 [IMPLEMENTED] PWM frequency (R/W)
-
-- Frequency in Hz on 3 bytes, from 1 to 100_000 (default: 10_000)
-
-** 0x14 Encoder to motor reduction (R/W)
-
-- Between 1 and 255. 0 disable encoder control (default 0)
-
-** [IMPLEMENTED] 0x20-0x22 PID coefficients (R/W)
-
-The PID will be working at 100Hz.
-
-P, I and D are expressed as 32 bit signed numbers with a 28 bit integer part
-and 4 bit fractional part.
-
-- 0x20: P (4 bytes). Default value is 0x0000_0004 (0.25)
-- 0x21: I (4 bytes). Default value is 0x0000_0000 (0.0)
-- 0x22: D (4 bytes). Default value is 0x0000_0000 (0.0)
-
-Changing the coefficients will take effect only when the controlled mode is off,
-for example by setting the motors to standby mode.
-
-** 0x26 Ramp time (R/W)
-
-- In automatic motor distance, time in 100th of seconds to reach the maximum speed
-  or to decrease the speed from the maximum to 0.
-
-** [IMPLEMENTED] 0x28 Motor shutdown timeout (R/W)
-
-- Number of tenths of seconds in before the motor shut down. The minimum is 1
-  (0.1 seconds) and the maximum is 100 (10 seconds).
-
-** [IMPLEMENTED] 0x30 Raw motor speed (R/W)
-
-- Left and right motor speed, between -100 and 100 each, max speed is
-  ±100. None means standby. ±100 corresponds to the value limited by the
-  max motor percentage.
-- This is the raw speed sent to the motor, no PID is computed.
-- If written while in controlled mode, the robot switches to manual mode
-
-** [IMPLEMENTED] 0x31 Controlled motor speed (R/W)
-
-- Left and right motor speed, beween -32767 and 32767 each. The unit is the
-  number of ticks per 100th of seconds.
-- Each motor will be controlled by a separate PID with shared coefficients.
-- Using a speed of (0, 0) will exit the controlled mode and switch to raw mode.
-  This allows the PID coefficients to be updated if needed.
-- Speed will be returned as (-32768, -32768) if controlled mode is not active.
-
-** [IMPLEMENTED] 0x32 Encoder ticks (R)
-
-- Left and right encoder counters since last time, 2 complement, 2 bytes each
-
-** [IMPLEMENTED] 0x36 Status (R)
-
-- Bit 0: moving (1) or idle (0)
-- Bit 1: controlled mode (1) or raw mode (0)
-
-** 0x37-0x3A Automatic motor distance (R/W) [optional]
-
-- Left and right distance in number of encoder ticks, between -32768 and 32767 each.
-- Reading this value gives the distance to the target in ticks.
-- If left and right distances are not equal, they will be kept
-  proportional as much as possible in order to progress the same way.
-
-** 0x40-0x43 Music (W) [optional]
-
-- For each motor, left then right, frequency in Hz on 1 byte and
-  duration in 10th of seconds on 1 byte. This cannot be used if the
-  motor is moving.
-
-** [IMPLEMENTED] 0xE0 Reset (W)
-
-- Reset the device. Used mainly for testing.
-
-** [IMPLEMENTED] 0xE1 Reset to bootloader (W)
-
-- Reset the device in bootloader mode. Used when reprogramming.
-
-** [IMPLEMENTED] 0xF0 Unique device ID (R)
-
-- Unique device ID as found in addresses 0x1FFFF7E8-0x1FFFF7EF
-
-** [IMPLEMENTED] 0xFE Firmware capabilities (R)
-
-- Bit 0: bootloader feature is activated
-
-
-* Bootloader command set
-
-If a firmware is present, the bootloader will start it unless the
-firmware has explicitly chosen to reboot in bootloader mode.
-
-I²C address: 0x58
-
-The note about clock stretching also applies for the bootloader.
-
-** [IMPLEMENTED] 0x08 Firmware version (R)
-
-- Return three bytes containing the major, minor and patch version numbers
-  derived from =Cargo.toml=.
-
-** [IMPLEMENTED] 0x0F Who am I? (R)
-
-- The I²C address
-
-** [IMPLEMENTED] 0x10 Status (R)
-
-Returns two bytes:
-
-- One set of flags ORed together:
-    - 0x01: system is in programming mode
-    - 0x02: at least one error was detected since the last time the
-      system has been put in programming mode
-    - 0x04: a program is currently present in flash
-- A XORed version of all data received so far since the programming
-  address was last set, either by entering programming mode, or by
-  using the SET PROGRAMMING ADDRESS command.
-
-** [IMPLEMENTED] 0x20 Change programming mode (W)
-
-- 0: leave programming mode without marking the application as
-  succesfully written
-- 1: leave programming mode and mark the application as succesfully
-  written
-- [0x17, 0x27, 0x65, 0x40]: enter programming mode
-
-** [IMPLEMENTED] 0x24 Erase pages (W) [PROGRAMMING MODE]
-
-- First byte: index of the first 1kB page in the application area
-- Second byte: number of pages to erase (up to the end of the application area)
-- Third byte: XOR of the first two bytes, as a safety
-
-The memory will be erased. The active programming address is then set to
-the beginning of the erased area.
-
-Even if the last page of the application does not belong to the erased
-page set, it will be erased with the first erase request of the
-current session (or after having being set again) to ensure that the
-application is no longer considered valid.
-
-Designating address outside the application area, or having a wrong checksum,
-will be an error.
-
-** [IMPLEMENTED] 0x28 Set programming address (W) [PROGRAMMING MODE]
-
-- 4 bytes containing the next address to program, relative to the
-  application start
-- One byte XORing the previous ones
-
-** [IMPLEMENTED] 0x2c Program data (W) [PROGRAMMING MODE]
-
-- 2, 4, 6, or 8 data bytes
-- One byte XORing the previous ones
-
-In case of error, the bootloader leaves programming mode immediately.
-
-The programming address will advance with the right number of bytes.
-
-** [IMPLEMENTED] 0x30 Read memory (R) [PROGRAMMING MODE]
-
-- Read 8 consecutive bytes in memory from the programming address
-  (relative to the applicatin start), and advance it by 8.
-
-0 will be returned outside the application memory area.
-
-** [IMPLEMENTED] 0x34 Set checksum (W) [PROGRAMMING_MODE]
-
-- Set the checksum value to the given byte.
-
-** [IMPLEMENTED] 0xE0 Reset (W)
-
-- Reset the bootloader in automatic mode
-
-** [IMPLEMENTED] 0xE1 Reset to the bootloader (W)
-
-- Reset the bootloader in bootloader mode
-
-** [IMPLEMENTED] 0xE2 Reset to the application (W)
-
-- Reset the bootloader in application mode
-
-** [IMPLEMENTED] 0xF0-0xF7 Unique device ID (R)
-
-- Unique device ID as found in addresses 0x1FFFF7E8-0x1FFFF7EF
-