Skip to content

Commit

Permalink
Fix pullup/pulldown configuration, update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelsadok committed Aug 24, 2020
1 parent f59c805 commit f3fa0af
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 82 deletions.
14 changes: 9 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
# Unreleased Features
Please add a note of your changes below this heading if you make a Pull Request.

### Changed

* Use DMA for DRV8301 setup
* Make NVM configuration code more dynamic so that the layout doesn't have to be known at compile time.
* GPIO initialization logic was changed. GPIOs now need to be explicitly set to the mode corresponding to the feature that they are used by. See `<odrv>.config.gpioX_mode`.
* Previously, if two components used the same interrupt pin (e.g. step input for axis0 and axis1) then the one that was configured later would override the other one. Now this is no longer the case (the old component remains the owner of the pin).

### API Miration Notes

* `enable_uart` and `uart_baudrate` were renamed to `enable_uart0` and `uart0_baudrate`.
* `enable_i2c_instead_of_can` was replaced by the separate settings `enable_i2c0` and `enable_can0`.

* `<axis>.motor.gate_driver` was moved to `<axis>.gate_driver`.
* `<axis>.min_endstop.pullup` and `<axis>.max_endstop.pullup` were removed. Use `<odrv>.config.gpioX_mode = GPIO_MODE_DIGITAL / GPIO_MODE_DIGITAL_PULL_UP / GPIO_MODE_DIGITAL_PULL_DOWN` instead.

# Release Candidate
## [0.5.1] - Date TBD
Expand Down Expand Up @@ -50,7 +58,6 @@ Please add a note of your changes below this heading if you make a Pull Request.
* Using an STM32F405 .svd file allows CortexDebug to view registers during debugging
* Added scripts for building via docker.
* Added ability to change uart baudrate via fibre
* Introduced GPIO modes. GPIOs now need to be explicitly set to the mode corresponding to the feature that they are used by. See `<odrv>.config.gpioX_mode`.

### Changed
* Changed ratiometric `motor.config.current_lim_tolerance` to absolute `motor.config.current_lim_margin`
Expand All @@ -65,9 +72,6 @@ Please add a note of your changes below this heading if you make a Pull Request.
* Reboot on `erase_configuration()`. This avoids unexpected behavior of a subsequent `save_configuration()` call, since the configuration is only erased from NVM, not from RAM.
* Change `motor.get_inverter_temp()` to use a property which was already being sampled at `motor.inverter_temp`
* Fixed a numerical issue in the trajectory planner that could cause sudden jumps of the position setpoint
* Use DMA for DRV8301 setup
* Make NVM configuration code more dynamic so that the layout doesn't have to be known at compile time
* Refactor GPIO code. Note that if two components use the same interrupt pin (e.g. step input for axis0 and axis1) then previously the one that was configured later would override the other one. Now this is no longer the case (the old component remains the owner of the pin).

## [0.4.12] - 2020-05-06
### Fixed
Expand Down
4 changes: 2 additions & 2 deletions Firmware/Board/v3/Inc/board.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@
ODriveIntf::GPIO_MODE_DIGITAL, \
ODriveIntf::GPIO_MODE_ENC0, \
ODriveIntf::GPIO_MODE_ENC0, \
ODriveIntf::GPIO_MODE_DIGITAL, \
ODriveIntf::GPIO_MODE_DIGITAL_PULL_DOWN, \
ODriveIntf::GPIO_MODE_ENC1, \
ODriveIntf::GPIO_MODE_ENC1, \
ODriveIntf::GPIO_MODE_DIGITAL, \
ODriveIntf::GPIO_MODE_DIGITAL_PULL_DOWN, \
ODriveIntf::GPIO_MODE_CAN0, \
ODriveIntf::GPIO_MODE_CAN0,

Expand Down
4 changes: 0 additions & 4 deletions Firmware/MotorControl/axis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,6 @@ void Axis::decode_step_dir_pins() {
// @brief (de)activates step/dir input
void Axis::set_step_dir_active(bool active) {
if (active) {
// Set up the step/direction GPIOs as input
dir_gpio_.config(GPIO_MODE_INPUT, GPIO_NOPULL);
step_gpio_.config(GPIO_MODE_INPUT, GPIO_PULLDOWN);

// Subscribe to rising edges of the step GPIO
if (!step_gpio_.subscribe(true, false, step_cb_wrapper, this)) {
odrv.misconfigured_ = true;
Expand Down
1 change: 0 additions & 1 deletion Firmware/MotorControl/encoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ void Encoder::enc_index_cb() {

void Encoder::set_idx_subscribe(bool override_enable) {
if (config_.use_index && (override_enable || !config_.find_idx_on_lockin_only)) {
index_gpio_.config(GPIO_MODE_INPUT, GPIO_PULLDOWN);
if (!index_gpio_.subscribe(true, false, enc_index_cb_wrapper, this)) {
odrv.misconfigured_ = true;
}
Expand Down
19 changes: 6 additions & 13 deletions Firmware/MotorControl/endstop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,12 @@ bool Endstop::get_state() {
}

bool Endstop::apply_config() {
set_enabled(config_.enabled);
debounceTimer_.reset();
if (config_.enabled) {
debounceTimer_.start();
} else {
debounceTimer_.stop();
}
debounceTimer_.setIncrement(config_.debounce_ms * 0.001f);
return true;
}

void Endstop::set_enabled(bool enable) {
debounceTimer_.reset();
if (config_.gpio_num != 0) {
if (enable) {
Stm32Gpio gpio = get_gpio(config_.gpio_num);
gpio.config(GPIO_MODE_INPUT, config_.pullup ? GPIO_PULLUP : GPIO_PULLDOWN);
debounceTimer_.start();
} else
debounceTimer_.stop();
}
}
1 change: 0 additions & 1 deletion Firmware/MotorControl/endstop.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class Endstop {
Axis* axis_ = nullptr;

bool apply_config();
void set_enabled(bool enabled);

void update();
bool get_state();
Expand Down
15 changes: 14 additions & 1 deletion Firmware/MotorControl/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,10 @@ extern "C" int main(void) {
GPIO_InitStruct.Pin = get_gpio(i).pin_mask_;

// Set Alternate Function setting for this GPIO mode
if (mode == ODriveIntf::GPIO_MODE_DIGITAL || mode == ODriveIntf::GPIO_MODE_ANALOG_IN) {
if (mode == ODriveIntf::GPIO_MODE_DIGITAL ||
mode == ODriveIntf::GPIO_MODE_DIGITAL_PULL_UP ||
mode == ODriveIntf::GPIO_MODE_DIGITAL_PULL_DOWN ||
mode == ODriveIntf::GPIO_MODE_ANALOG_IN) {
GPIO_InitStruct.Alternate = 0;
} else {
auto it = std::find_if(
Expand All @@ -427,6 +430,16 @@ extern "C" int main(void) {
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
} break;
case ODriveIntf::GPIO_MODE_DIGITAL_PULL_UP: {
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
} break;
case ODriveIntf::GPIO_MODE_DIGITAL_PULL_DOWN: {
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
} break;
case ODriveIntf::GPIO_MODE_ANALOG_IN: {
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
Expand Down
5 changes: 4 additions & 1 deletion Firmware/odrive-interface.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,6 @@ interfaces:
enabled: {type: bool, c_setter: set_enabled}
offset: float32
is_active_high: bool
pullup: bool
debounce_ms: {type: uint32, c_setter: set_debounce_ms}


Expand All @@ -926,6 +925,10 @@ valuetypes:
doc: |
The pin can be used for one or more of these functions:
Step, dir, enable, encoder index, hall effect encoder, SPI encoder nCS (this one is exclusive).
DigitalPullUp:
doc: Same as `Digital` but with the internal pull-up resistor enabled.
DigitalPullDown:
doc: Same as `Digital` but with the internal pull-down resistor enabled.
AnalogIn:
doc: |
The pin can be used for one or more of these functions:
Expand Down
24 changes: 24 additions & 0 deletions docs/encoders.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,30 @@ If you are using an encoder with an index signal, another problem that has been
* when performing an index_search, the motor does not return to the same position each time.
One easy step that _might_ fix the noise on the Z input has been to solder a 22nF-47nF capacitor to the Z pin and the GND pin on the underside of the ODrive board.

## Hall feedback pinout
If position accuracy is not a concern, you can use A/B/C hall effect encoders for position feedback.

To use this mode, configure the corresponding encoder mode: `<encoder>.config.mode = ENCODER_MODE_HALL`. Configure the corresponding GPIOs as digital inputs:

For encoder 0:

<odrv>.config.gpio9_mode = GPIO_MODE_DIGITAL
<odrv>.config.gpio10_mode = GPIO_MODE_DIGITAL
<odrv>.config.gpio11_mode = GPIO_MODE_DIGITAL

For encoder 1:

<odrv>.config.gpio12_mode = GPIO_MODE_DIGITAL
<odrv>.config.gpio13_mode = GPIO_MODE_DIGITAL
<odrv>.config.gpio14_mode = GPIO_MODE_DIGITAL

In this mode, the pinout on the encoder port is as follows:

| Label on ODrive | Hall feedback |
|-----------------|---------------|
| A | Hall A |
| B | Hall B |
| Z | Hall C |

## SPI Encoders

Expand Down
3 changes: 3 additions & 0 deletions docs/hoverboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ The hall feedback has 6 states for every pole pair in the motor. Since we have 1
```txt
odrv0.axis0.encoder.config.mode = ENCODER_MODE_HALL
odrv0.axis0.encoder.config.cpr = 90
odrv0.config.gpio9_mode = GPIO_MODE_DIGITAL
odrv0.config.gpio10_mode = GPIO_MODE_DIGITAL
odrv0.config.gpio11_mode = GPIO_MODE_DIGITAL
```

Since the hall feedback only has 90 counts per revolution, we want to reduce the velocity tracking bandwidth to get smoother velocity estimates.
Expand Down
69 changes: 26 additions & 43 deletions docs/interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,36 +50,12 @@ Notes:
* Digital mode is a general purpose mode that can be used for these functions: step, dir, enable, encoder index, hall effect encoder, SPI encoder nCS.
* You must also connect GND between ODrive and your other board.
* ODrive v3.3 and onward have 5V tolerant GPIO pins.
* You can change the step/dir pins using `axis.config.<step/dir>_gpio_pin`.

### Pin function priorities
1. PWM in, if enabled. Disabled by default.
1. UART, **Enabled by default**.
1. Step/Dir, if enabled. Disabled by default.
1. Analog, default behavior if not overridden (only on supported pins).
1. Digital in, default behavior on pins not capable of analog input.

For predictable results, try to have only one feature enabled for any one pin. When changing pin assignments you must:
* `odrv0.save_configuration()`
* `odrv0.reboot()`

### Analog input
Analog inputs can be used to measure voltages between 0 and 3.3V. Odrive uses a 12 bit ADC (4096 steps) and so has a maximum resolution of 0.8 mV. Some GPIO pins require the appropriate pin priority (see above) to be set before they can be used as an analog input. To read the voltage on GPIO1 in odrive tool the following would be entered: `odrv0.get_adc_voltage(1)`

### Hall feedback pinout
When the encoder mode is set to hall feedback, the pinout on the encoder port is as follows:

| Label on ODrive | Hall feedback |
|-----------------|---------------|
| A | Hall A |
| B | Hall B |
| Z | Hall C |

## Native Protocol

This protocol is what the ODrive Tool uses to talk to the ODrive. If you have a choice, this is the recommended protocol for all applications. The native protocol runs on USB and can also be configured to run on UART.

#### Python
### Python

The ODrive Tool you installed as part of the [Getting Started guide](getting-started.md#downloading-and-installing-tools) comes with a library that you can use to easily control the ODrive from Python.

Expand All @@ -93,7 +69,7 @@ print(str(odrv0.vbus_voltage))

For a more comprehensive example, see [tools/odrive_demo.py](../tools/odrive_demo.py).

#### Other languages
### 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). You are of course welcome to contribute it back.

Expand All @@ -113,40 +89,50 @@ Pinout:
* Step/dir signals: see [Pinout](#pinout) above. Note in that section how to reassign the pins.
* GND: you must connect the grounds of the devices together. Use any GND pin on J3 of the ODrive.

To enable step/dir mode for the GPIO, set `<axis>.config.enable_step_dir` to true for each axis that you wish to use this on.
Axis 0 step/dir pins conflicts with UART, and the UART takes priority. So to be able to use step/dir on Axis 0, you must also set `odrv0.config.enable_uart = False`. See the [pin function priorities](#pin-function-priorities) for more detail. Don't forget to save configuration and reboot.
1. Choose any two of the unused GPIOs for step/dir input. Let's say you chose GPIO7 for the step signal and GPIO8 for the dir signal.
2. Configure the GPIO modes:

<odrv>.config.gpio7_mode = GPIO_MODE_DIGITAL_PULL_DOWN
<odrv>.config.gpio8_mode = GPIO_MODE_DIGITAL

3. Configure the axis:

<axis>.config.step_gpio_pin = 7
<axis>.config.dir_gpio_pin = 8
<axis>.config.enable_step_dir = True

There is also a config variable called `<axis>.config.turns_per_step`, which specifies how many turns a "step" corresponds to. The default value is 1.0f/1024.0f. It can be any floating point value.
The maximum step rate is pending tests, but it should handle at least 50kHz. 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. To get the ODrive to go into position control mode at bootup, see how to configure the [startup procedure](commands.md#startup-procedure).

## RC PWM input
You can control the ODrive directly from an hobby RC receiver.

Some GPIO pins can be used for PWM input, if they are not allocated to other functions. For example, you must disable the UART to use GPIO 1,2. See the [pin function priorities](#pin-function-priorities) for more detail.
You can control the ODrive directly from a hobby RC receiver.

Any of the numerical parameters that are writable from the ODrive Tool can be hooked up to a PWM input.
As an example, we'll configure GPIO4 to control the angle of axis 0. We want the axis to move within a range of -2 to 2 turns.
Any of the numerical parameters that are writable from the ODrive Tool can be hooked up to a PWM input. The [Pinout](#pinout) tells you which pins are PWM input capable. As an example, we'll configure GPIO4 to control the angle of axis 0. We want the axis to move within a range of -2 to 2 turns.

1. Make sure you're able control the axis 0 angle by writing to `odrv0.axis0.controller.input_pos`. If you need help with this follow the [getting started guide](getting-started.md).
2. If you want to control your ODrive with the PWM input without using anything else to activate the ODrive, you can configure the ODrive such that axis 0 automatically goes operational at startup. See [here](commands.md#startup-procedure) for more information.
3. In ODrive Tool, configure the PWM input mapping
```
In [1]: odrv0.config.gpio4_pwm_mapping.min = -2
In [2]: odrv0.config.gpio4_pwm_mapping.max = 2
In [3]: odrv0.config.gpio4_pwm_mapping.endpoint = odrv0.axis0.controller._remote_attributes['input_pos']
odrv0.config.gpio4_mode = GPIO_MODE_PWM0
odrv0.config.gpio4_pwm_mapping.min = -2
odrv0.config.gpio4_pwm_mapping.max = 2
odrv0.config.gpio4_pwm_mapping.endpoint = odrv0.axis0.controller._remote_attributes['input_pos']
```
Note: you can disable the input by setting `odrv0.config.gpio4_pwm_mapping.endpoint = None`
4. Save the configuration and reboot
```
In [4]: odrv0.save_configuration()
In [5]: odrv0.reboot()
odrv0.save_configuration()
odrv0.reboot()
```
5. With the ODrive powered off, connect the RC receiver ground to the ODrive's GND and one of the RC receiver signals to GPIO4. You may try to power the receiver from the ODrive's 5V supply if it doesn't draw too much power. Power up the the RC transmitter. You should now be able to control axis 0 from one of the RC sticks.

Be sure to setup the Failsafe feature on your RC Receiver so that if connection is lost between the remote and the receiver, the receiver outputs 0 for the velocity setpoint of both axes (or whatever is safest for your configuration). Also note that if the receiver turns off (loss of power, etc) or if the signal from the receiver to the ODrive is lost (wire comes unplugged, etc), the ODrive will continue the last commanded velocity setpoint. There is currently no timeout function in the ODrive for PWM inputs.

## Analog input
Analog inputs can be used to measure voltages between 0 and 3.3V. ODrive uses a 12 bit ADC (4096 steps) and so has a maximum resolution of 0.8 mV. A GPIO must be configured with `<odrv>.config.gpioX_mode = GPIO_MODE_ANALOG_IN` before it can be used as an analog input. To read the voltage on GPIO1 in odrivetool the following would be entered: `odrv0.get_adc_voltage(1)`.

## Ports
Note: when you use an existing library you don't have to deal with the specifics described in this section.

Expand Down Expand Up @@ -178,11 +164,8 @@ The endpoint pairs `0x01, 0x81` and `0x03, 0x83` behave exactly identical, only
If you plan to access the USB endpoints directly it is recommended that you use interface 2. The other interfaces (the ones associated with the CDC device) are usually claimed by the CDC driver of the host OS, so their endpoints cannot be used without first detaching the CDC driver.

### UART
Baud rate: 115200 by default. See `odrv0.config.uart_baudrate` to change value. Requires a restart.
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.

UART0 is enabled by default with a baudrate of 115200 on the pins as shown in [Pinout](#pinout). Don't forget to also connect GND of the two UART devices. You can use `odrv0.config.uart0_baudrate` to change the baudrate and `odrv0.config.enable_uart0` to disable/reenable UART0.

## CAN Simple Protocol

Expand Down
24 changes: 13 additions & 11 deletions tools/odrive/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@

# ODrive.GpioMode
GPIO_MODE_DIGITAL = 0
GPIO_MODE_ANALOG_IN = 1
GPIO_MODE_UART0 = 2
GPIO_MODE_UART1 = 3
GPIO_MODE_UART2 = 4
GPIO_MODE_CAN0 = 5
GPIO_MODE_I2C0 = 6
GPIO_MODE_SPI0 = 7
GPIO_MODE_PWM0 = 8
GPIO_MODE_ENC0 = 9
GPIO_MODE_ENC1 = 10
GPIO_MODE_ENC2 = 11
GPIO_MODE_DIGITAL_PULL_UP = 1
GPIO_MODE_DIGITAL_PULL_DOWN = 2
GPIO_MODE_ANALOG_IN = 3
GPIO_MODE_UART0 = 4
GPIO_MODE_UART1 = 5
GPIO_MODE_UART2 = 6
GPIO_MODE_CAN0 = 7
GPIO_MODE_I2C0 = 8
GPIO_MODE_SPI0 = 9
GPIO_MODE_PWM0 = 10
GPIO_MODE_ENC0 = 11
GPIO_MODE_ENC1 = 12
GPIO_MODE_ENC2 = 13

# ODrive.Can.Protocol
PROTOCOL_SIMPLE = 0
Expand Down

0 comments on commit f3fa0af

Please sign in to comment.