Merge branch 'devel' into sam_can

This commit is contained in:
Oskar Weigl
2018-06-06 23:39:03 -07:00
118 changed files with 20777 additions and 1960 deletions
-28
View File
@@ -6,34 +6,6 @@ __pycache__/
# C extensions
*.so
# Distribution / packaging
.Python
#env/
#build/
#develop-eggs/
#dist/
#downloads/
#eggs/
#.eggs/
#lib/
#lib64/
#parts/
#sdist/
#var/
#*.egg-info/
#.installed.cfg
#*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
+13 -4
View File
@@ -19,11 +19,18 @@ cache:
- "$HOME/dl"
install:
- export GCC_DIR=$HOME/dl/gcc-arm-none-eabi-5_2-2015q4
- export GCC_ARCHIVE=$HOME/dl/gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2
- export GCC_URL=https://launchpad.net/gcc-arm-embedded/5.0/5-2015-q4-major/+download/gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2
# - export GCC_DIR=$HOME/dl/gcc-arm-none-eabi-5_2-2015q4
# - export GCC_ARCHIVE=$HOME/dl/gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2
# - export GCC_URL=https://launchpad.net/gcc-arm-embedded/5.0/5-2015-q4-major/+download/gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2
# - if [ ! -e $GCC_DIR/bin/arm-none-eabi-gcc ]; then wget $GCC_URL -O $GCC_ARCHIVE; tar xfj $GCC_ARCHIVE -C $HOME/dl; fi
# - export PATH=$PATH:$GCC_DIR/bin
- export GCC_DIR=$HOME/dl/gcc-arm-none-eabi-7-2017-q4-major
- export GCC_ARCHIVE=$HOME/dl/gcc-arm-none-eabi-7-2017-q4-major-linux.tar.bz2
- export GCC_URL=https://developer.arm.com/-/media/Files/downloads/gnu-rm/7-2017q4/gcc-arm-none-eabi-7-2017-q4-major-linux.tar.bz2
- if [ ! -e $GCC_DIR/bin/arm-none-eabi-gcc ]; then wget $GCC_URL -O $GCC_ARCHIVE; tar xfj $GCC_ARCHIVE -C $HOME/dl; fi
- export PATH=$PATH:$GCC_DIR/bin
- export TUP_DIR=$HOME/dl/tup_0.7.5-0~16.04.york0_amd64
- export TUP_ARCHIVE=$HOME/dl/tup_0.7.5-0~16.04.york0_amd64.deb
- export TUP_URL=http://ppa.launchpad.net/jonathonf/tup/ubuntu/pool/main/t/tup/tup_0.7.5-0~16.04.york0_amd64.deb
@@ -36,10 +43,12 @@ env:
- CONFIG_BOARD_VERSION=v3.3 DEPLOY=v3.3
- CONFIG_BOARD_VERSION=v3.4-24V DEPLOY=v3.4-24V
- CONFIG_BOARD_VERSION=v3.4-48V DEPLOY=v3.4-48V
- CONFIG_BOARD_VERSION=v3.5-24V DEPLOY=v3.5-24V
- CONFIG_BOARD_VERSION=v3.5-48V DEPLOY=v3.5-48V
# Various protocol combinations
- CONFIG_BOARD_VERSION=v3.4-24V CONFIG_USB_PROTOCOL=native-stream CONFIG_UART_PROTOCOL=native
- CONFIG_BOARD_VERSION=v3.4-24V CONFIG_USB_PROTOCOL=stdout CONFIG_UART_PROTOCOL=ascii
- CONFIG_BOARD_VERSION=v3.4-24V CONFIG_USB_PROTOCOL=stdout CONFIG_UART_PROTOCOL=stdout
- CONFIG_BOARD_VERSION=v3.4-24V CONFIG_USB_PROTOCOL=none CONFIG_UART_PROTOCOL=none
script:
+197
View File
@@ -0,0 +1,197 @@
#include <Wire.h>
#include "odrive.h"
// See odrive.h for a description
bool I2C_transaction(uint8_t slave_addr, const uint8_t * tx_buffer, size_t tx_length, uint8_t * rx_buffer, size_t rx_length) {
// transmit
if (tx_buffer) {
Wire.beginTransmission(slave_addr);
if (Wire.write(tx_buffer, tx_length) != tx_length)
return false;
bool should_stop = !rx_buffer;
if (Wire.endTransmission(should_stop) != 0)
return false;
}
// receive
if (rx_buffer) {
while(Wire.available()) Wire.read(); // flush input buffer
if (Wire.requestFrom(slave_addr, (uint8_t)rx_length, (uint8_t)true /* stop after receiving */) != rx_length)
return false;
for (size_t i = 0; i < rx_length; ++i)
rx_buffer[i] = Wire.read();
}
return true;
}
int set_and_save_configuration(uint8_t odrive_num, uint8_t axis_num) {
bool success;
success = odrive::clear_errors(odrive_num, axis_num);
if (!success)
return __LINE__;
// select hall effect mode
bool user_config_loaded = false;
success = odrive::read_property<odrive::USER_CONFIG_LOADED>(odrive_num, &user_config_loaded);
if (!success)
return __LINE__;
if (user_config_loaded) {
Serial.println("ODrive already configured");
return 0;
}
// select hall effect mode
success = odrive::write_axis_property<odrive::AXIS__ENCODER__CONFIG__MODE>(odrive_num, axis_num, 1);
if (!success)
return __LINE__;
// configure encoder counts per revolution (6 hall effect states * 12 pole pairs)
success = odrive::write_axis_property<odrive::AXIS__ENCODER__CONFIG__CPR>(odrive_num, axis_num, 72);
if (!success)
return __LINE__;
// disable velocity integrator
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__CONFIG__VEL_INTEGRATOR_GAIN>(odrive_num, axis_num, 0);
if (!success)
return __LINE__;
// select velocity control
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__CONFIG__CONTROL_MODE>(odrive_num, axis_num, 2);
if (!success)
return __LINE__;
// set velocity controller P-gain
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__CONFIG__VEL_GAIN>(odrive_num, axis_num, 0.005f);
if (!success)
return __LINE__;
// request state: motor calibration
success = odrive::write_axis_property<odrive::AXIS__REQUESTED_STATE>(odrive_num, axis_num, 4);
if (!success)
return __LINE__;
delay(6000);
// check if the axis is in idle and no errors occurred
if (!odrive::check_axis_state(odrive_num, axis_num, 1))
return __LINE__;
// ensure that the motor calibration is considered valid after power cycle
success = odrive::write_axis_property<odrive::AXIS__MOTOR__CONFIG__PRE_CALIBRATED>(odrive_num, axis_num, true);
if (!success)
return __LINE__;
// request state: encoder calibration
success = odrive::write_axis_property<odrive::AXIS__REQUESTED_STATE>(odrive_num, axis_num, 7);
if (!success)
return __LINE__;
delay(12000);
// check if the axis is in idle and no errors occurred
if (!odrive::check_axis_state(odrive_num, axis_num, 1))
return __LINE__;
// ensure that the encoder calibration is considered valid after power cycle
success = odrive::write_axis_property<odrive::AXIS__ENCODER__CONFIG__PRE_CALIBRATED>(odrive_num, axis_num, true);
if (!success)
return __LINE__;
// store the configuration to NVM
// Caution: this operation is usually instantaneous but after every couple of hundred calls it will
// take around 1 second (because a flash page needs to be erased).
success = odrive::trigger<odrive::SAVE_CONFIGURATION>(odrive_num);
if (!success)
return __LINE__;
return 0;
}
byte odrive_num = 7;
byte axis_num = 0;
bool do_setup = true;
void setup() {
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600);
Serial.println("Hello World!");
if (do_setup) {
Serial.println("Starting ODrive setup...");
int error_line = set_and_save_configuration(odrive_num, axis_num);
if (error_line != 0) {
Serial.print("ODrive setup failed at line ");
Serial.print(error_line);
Serial.println();
return;
}
Serial.println("ODrive setup succeeded!");
do_setup = false;
}
}
void loop() {
bool success;
delay(500);
success = odrive::check_axis_state(odrive_num, axis_num, 8);
if (!success) {
Serial.println("not in closed loop control - entering closed loop control");
// clear previous error state
success = odrive::clear_errors(odrive_num, axis_num);
if (!success) {
Serial.println("could not enter closed loop control");
return;
}
// request velocity 0
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__VEL_SETPOINT>(odrive_num, axis_num, 0);
if (!success) {
Serial.println("could not enter closed loop control");
return;
}
// request state: closed loop control
success = odrive::write_axis_property<odrive::AXIS__REQUESTED_STATE>(odrive_num, axis_num, 8);
if (!success) {
Serial.println("could not enter closed loop control");
return;
}
success = odrive::check_axis_state(odrive_num, axis_num, 8);
if (!success) {
Serial.println("could not enter closed loop control");
return;
}
}
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__VEL_SETPOINT>(odrive_num, axis_num, 72 * 5);
if (!success) {
Serial.println("error");
return;
}
delay(500);
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__VEL_SETPOINT>(odrive_num, axis_num, -72 * 5);
if (!success) {
Serial.println("error");
return;
}
// print Vbus to show liveness
float vbus;
success = odrive::read_property<odrive::VBUS_VOLTAGE>(odrive_num, &vbus);
if (!success) {
Serial.println("error");
return;
}
Serial.println(vbus);
}
+199
View File
@@ -0,0 +1,199 @@
/*
* ODrive I2C communication library
* This file implements I2C communication with the ODrive.
*
* - Implement the C function I2C_transaction to provide low level I2C access.
* - Use read_property<PropertyId>() to read properties from the ODrive.
* - Use write_property<PropertyId>() to modify properties on the ODrive.
* - Use trigger<PropertyId>() to trigger a function (such as reboot or save_configuration)
* - Use endpoint_type_t<PropertyId> to retrieve the underlying type
* of a given property.
* - Refer to PropertyId for a list of available properties.
*
* To regenerate the interface definitions, flash an ODrive with
* the new firmware, connect it to your PC via USB and then run
* ../tools/odrivetool generate-code --output [path to odrive_endpoints.h]
* This step can be done with any ODrive, it doesn't have to be the
* one that you'll be controlling over I2C.
*/
#include <limits.h>
#include <stdint.h>
#include "odrive_endpoints.h"
#ifdef __AVR__
// AVR-GCC doesn't ship with the STL, so we use our own little excerpt
#include "type_traits.h"
#else
#include <type_traits>
#endif
extern "C" {
/* @brief Send and receive data to/from an I2C slave
*
* This function carries out the following sequence:
* 1. generate a START condition
* 2. if the tx_buffer is not null:
* a. send 7-bit slave address (with the LSB 0)
* b. send all bytes in the tx_buffer
* 3. if both tx_buffer and rx_buffer are not null, generate a REPEATED START condition
* 4. if the rx_buffer is not null:
* a. send 7-bit slave address (with the LSB 1)
* b. read rx_length bytes into rx_buffer
* 5. send STOP condition
*
* @param slave_addr: 7-bit slave address (the MSB is ignored)
* @return true if all data was transmitted and received as requested by the caller, false otherwise
*/
bool I2C_transaction(uint8_t slave_addr, const uint8_t * tx_buffer, size_t tx_length, uint8_t * rx_buffer, size_t rx_length);
}
namespace odrive {
static constexpr const uint8_t i2c_addr = (0xD << 3); // write: 1101xxx0, read: 1101xxx1
template<typename T>
using bit_width = std::integral_constant<unsigned int, CHAR_BIT * sizeof(T)>;
template<typename T>
using byte_width = std::integral_constant<unsigned int, (bit_width<T>::value + 7) / 8>;
template<unsigned int IBitSize>
struct unsigned_int_of_size;
template<> struct unsigned_int_of_size<32> { typedef uint32_t type; };
template<typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
read_le(const uint8_t buffer[byte_width<T>::value]) {
T value = 0;
for (size_t i = 0; i < byte_width<T>::value; ++i)
value |= (static_cast<T>(buffer[i]) << (i << 3));
return value;
}
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
read_le(const uint8_t buffer[]) {
using T_Int = typename unsigned_int_of_size<bit_width<T>::value>::type;
T_Int value = read_le<T_Int>(buffer);
return *reinterpret_cast<T*>(&value);
}
template<typename T>
typename std::enable_if<std::is_integral<T>::value, void>::type
write_le(uint8_t buffer[byte_width<T>::value], T value) {
for (size_t i = 0; i < byte_width<T>::value; ++i)
buffer[i] = (value >> (i << 3)) & 0xff;
}
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
write_le(uint8_t buffer[byte_width<T>::value], T value) {
using T_Int = typename unsigned_int_of_size<bit_width<T>::value>::type;
write_le<T_Int>(buffer, *reinterpret_cast<T_Int*>(&value));
}
/* @brief Read from an endpoint on the ODrive.
* To read from an axis specific endpoint use read_axis_property() instead.
*
* Usage example:
* float val;
* success = odrive::read_property<odrive::VBUS_VOLTAGE>(0, &val);
*
* @param num Selects the ODrive. For instance the value 4 selects
* the ODrive that has [A2, A1, A0] connected to [VCC, GND, GND].
* @return true if the I2C transaction succeeded, false otherwise
*/
template<int IPropertyId>
bool read_property(uint8_t num, endpoint_type_t<IPropertyId>* value, uint16_t address = IPropertyId) {
uint8_t i2c_tx_buffer[4];
write_le<uint16_t>(i2c_tx_buffer, address);
write_le<uint16_t>(i2c_tx_buffer + sizeof(i2c_tx_buffer) - 2, json_crc);
uint8_t i2c_rx_buffer[byte_width<endpoint_type_t<IPropertyId>>::value];
if (!I2C_transaction(i2c_addr + num,
i2c_tx_buffer, sizeof(i2c_tx_buffer),
i2c_rx_buffer, sizeof(i2c_rx_buffer)))
return false;
if (value)
*value = read_le<endpoint_type_t<IPropertyId>>(i2c_rx_buffer);
return true;
}
/* @brief Write to an endpoint on the ODrive.
* To write to an axis specific endpoint use write_axis_property() instead.
*
* Usage example:
* success = odrive::write_property<odrive::TEST_PROPERTY>(0, 42);
*
* @param num Selects the ODrive. For instance the value 4 selects
* the ODrive that has [A2, A1, A0] connected to [VCC, GND, GND].
* @return true if the I2C transaction succeeded, false otherwise
*/
template<int IPropertyId>
bool write_property(uint8_t num, endpoint_type_t<IPropertyId> value, uint16_t address = IPropertyId) {
uint8_t i2c_tx_buffer[4 + byte_width<endpoint_type_t<IPropertyId>>::value];
write_le<uint16_t>(i2c_tx_buffer, address);
write_le<endpoint_type_t<IPropertyId>>(i2c_tx_buffer + 2, value);
write_le<uint16_t>(i2c_tx_buffer + sizeof(i2c_tx_buffer) - 2, json_crc);
return I2C_transaction(i2c_addr + num, i2c_tx_buffer, sizeof(i2c_tx_buffer), nullptr, 0);
}
/* @brief Trigger an parameter-less function on the ODrive
*
* Usage example:
* success = odrive::trigger<odrive::SAVE_CONFIGURATION>(0);
*
* @param num Selects the ODrive. For instance the value 4 selects
* the ODrive that has [A2, A1, A0] connected to [VCC, GND, GND].
* @return true if the I2C transaction succeeded, false otherwise
*/
template<int IPropertyId,
typename = typename std::enable_if<std::is_void<endpoint_type_t<IPropertyId>>::value>::type>
bool trigger(uint8_t num, uint16_t address = IPropertyId) {
uint8_t i2c_tx_buffer[4];
write_le<uint16_t>(i2c_tx_buffer, address);
write_le<uint16_t>(i2c_tx_buffer + sizeof(i2c_tx_buffer) - 2, json_crc);
return I2C_transaction(i2c_addr + num, i2c_tx_buffer, sizeof(i2c_tx_buffer), nullptr, 0);
}
template<int IPropertyId>
bool read_axis_property(uint8_t num, uint8_t axis, endpoint_type_t<IPropertyId>* value) {
return read_property<IPropertyId>(num, value, IPropertyId + axis * per_axis_offset);
}
template<int IPropertyId>
bool write_axis_property(uint8_t num, uint8_t axis, endpoint_type_t<IPropertyId> value) {
return write_property<IPropertyId>(num, value, IPropertyId + axis * per_axis_offset);
}
/* @brief Checks if the axis is in the requested state and the error register is clear */
bool check_axis_state(uint8_t num, uint8_t axis, uint8_t state) {
endpoint_type_t<odrive::AXIS__CURRENT_STATE> observed_state = 0;
endpoint_type_t<odrive::AXIS__ERROR> observed_error = 0;
if (!read_axis_property<odrive::AXIS__CURRENT_STATE>(num, axis, &observed_state))
return false;
if (!read_axis_property<odrive::AXIS__ERROR>(num, axis, &observed_error))
return false;
return (observed_error == 0) && (observed_state == state);
}
/* @brief Clears any error state of the specified axis */
bool clear_errors(uint8_t num, uint8_t axis) {
if (!write_axis_property<odrive::AXIS__ERROR>(num, axis, 0))
return false;
if (!write_axis_property<odrive::AXIS__MOTOR__ERROR>(num, axis, 0))
return false;
if (!write_axis_property<odrive::AXIS__ENCODER__ERROR>(num, axis, 0))
return false;
return true;
}
}
+299
View File
@@ -0,0 +1,299 @@
/*
* This file was autogenerated using the "odrivetool generate-code" feature.
*
* The file matches a specific firmware version. If you add/remove/rename any
* properties exposed by the ODrive, this file needs to be regenerated, otherwise
* the ODrive will ignore all commands.
*/
#ifndef __ODRIVE_ENDPOINTS_HPP
#define __ODRIVE_ENDPOINTS_HPP
namespace odrive {
static constexpr const uint16_t json_crc = 0xbe97;
static constexpr const uint16_t per_axis_offset = 101;
enum {
VBUS_VOLTAGE = 1,
SERIAL_NUMBER = 2,
HW_VERSION_MAJOR = 3,
HW_VERSION_MINOR = 4,
HW_VERSION_VARIANT = 5,
FW_VERSION_MAJOR = 6,
FW_VERSION_MINOR = 7,
FW_VERSION_REVISION = 8,
FW_VERSION_UNRELEASED = 9,
USER_CONFIG_LOADED = 10,
BRAKE_RESISTOR_ARMED = 11,
SYSTEM_STATS__UPTIME = 12,
SYSTEM_STATS__MIN_HEAP_SPACE = 13,
SYSTEM_STATS__MIN_STACK_SPACE_AXIS0 = 14,
SYSTEM_STATS__MIN_STACK_SPACE_AXIS1 = 15,
SYSTEM_STATS__MIN_STACK_SPACE_COMMS = 16,
SYSTEM_STATS__MIN_STACK_SPACE_USB = 17,
SYSTEM_STATS__MIN_STACK_SPACE_UART = 18,
SYSTEM_STATS__MIN_STACK_SPACE_USB_IRQ = 19,
SYSTEM_STATS__MIN_STACK_SPACE_STARTUP = 20,
SYSTEM_STATS__USB__RX_CNT = 21,
SYSTEM_STATS__USB__TX_CNT = 22,
SYSTEM_STATS__USB__TX_OVERRUN_CNT = 23,
SYSTEM_STATS__I2C__ADDR = 24,
SYSTEM_STATS__I2C__ADDR_MATCH_CNT = 25,
SYSTEM_STATS__I2C__RX_CNT = 26,
SYSTEM_STATS__I2C__ERROR_CNT = 27,
CONFIG__BRAKE_RESISTANCE = 28,
CONFIG__ENABLE_UART = 29,
CONFIG__ENABLE_I2C_INSTEAD_OF_CAN = 30,
CONFIG__DC_BUS_UNDERVOLTAGE_TRIP_LEVEL = 31,
CONFIG__DC_BUS_OVERVOLTAGE_TRIP_LEVEL = 32,
TEST_PROPERTY = 235,
ADC_GPIO1 = 242,
ADC_GPIO2 = 243,
SAVE_CONFIGURATION = 244,
ERASE_CONFIGURATION = 245,
REBOOT = 246,
ENTER_DFU_MODE = 247,
// Per-Axis endpoints (to be used with read_axis_property and write_axis_property)
AXIS__ERROR = 33,
AXIS__ENABLE_STEP_DIR = 34,
AXIS__CURRENT_STATE = 35,
AXIS__REQUESTED_STATE = 36,
AXIS__LOOP_COUNTER = 37,
AXIS__CONFIG__STARTUP_MOTOR_CALIBRATION = 38,
AXIS__CONFIG__STARTUP_ENCODER_INDEX_SEARCH = 39,
AXIS__CONFIG__STARTUP_ENCODER_OFFSET_CALIBRATION = 40,
AXIS__CONFIG__STARTUP_CLOSED_LOOP_CONTROL = 41,
AXIS__CONFIG__STARTUP_SENSORLESS_CONTROL = 42,
AXIS__CONFIG__ENABLE_STEP_DIR = 43,
AXIS__CONFIG__COUNTS_PER_STEP = 44,
AXIS__CONFIG__RAMP_UP_TIME = 45,
AXIS__CONFIG__RAMP_UP_DISTANCE = 46,
AXIS__CONFIG__SPIN_UP_CURRENT = 47,
AXIS__CONFIG__SPIN_UP_ACCELERATION = 48,
AXIS__CONFIG__SPIN_UP_TARGET_VEL = 49,
AXIS__MOTOR__ERROR = 50,
AXIS__MOTOR__ARMED_STATE = 51,
AXIS__MOTOR__IS_CALIBRATED = 52,
AXIS__MOTOR__CURRENT_MEAS_PHB = 53,
AXIS__MOTOR__CURRENT_MEAS_PHC = 54,
AXIS__MOTOR__DC_CALIB_PHB = 55,
AXIS__MOTOR__DC_CALIB_PHC = 56,
AXIS__MOTOR__PHASE_CURRENT_REV_GAIN = 57,
AXIS__MOTOR__CURRENT_CONTROL__P_GAIN = 58,
AXIS__MOTOR__CURRENT_CONTROL__I_GAIN = 59,
AXIS__MOTOR__CURRENT_CONTROL__V_CURRENT_CONTROL_INTEGRAL_D = 60,
AXIS__MOTOR__CURRENT_CONTROL__V_CURRENT_CONTROL_INTEGRAL_Q = 61,
AXIS__MOTOR__CURRENT_CONTROL__IBUS = 62,
AXIS__MOTOR__CURRENT_CONTROL__FINAL_V_ALPHA = 63,
AXIS__MOTOR__CURRENT_CONTROL__FINAL_V_BETA = 64,
AXIS__MOTOR__CURRENT_CONTROL__IQ_SETPOINT = 65,
AXIS__MOTOR__CURRENT_CONTROL__IQ_MEASURED = 66,
AXIS__MOTOR__CURRENT_CONTROL__MAX_ALLOWED_CURRENT = 67,
AXIS__MOTOR__GATE_DRIVER__DRV_FAULT = 68,
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_GENERAL = 69,
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ADC_CB_I = 70,
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ADC_CB_DC = 71,
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_MEAS_R = 72,
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_MEAS_L = 73,
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ENC_CALIB = 74,
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_IDX_SEARCH = 75,
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_FOC_VOLTAGE = 76,
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_FOC_CURRENT = 77,
AXIS__MOTOR__CONFIG__PRE_CALIBRATED = 78,
AXIS__MOTOR__CONFIG__POLE_PAIRS = 79,
AXIS__MOTOR__CONFIG__CALIBRATION_CURRENT = 80,
AXIS__MOTOR__CONFIG__RESISTANCE_CALIB_MAX_VOLTAGE = 81,
AXIS__MOTOR__CONFIG__PHASE_INDUCTANCE = 82,
AXIS__MOTOR__CONFIG__PHASE_RESISTANCE = 83,
AXIS__MOTOR__CONFIG__DIRECTION = 84,
AXIS__MOTOR__CONFIG__MOTOR_TYPE = 85,
AXIS__MOTOR__CONFIG__CURRENT_LIM = 86,
AXIS__CONTROLLER__POS_SETPOINT = 87,
AXIS__CONTROLLER__VEL_SETPOINT = 88,
AXIS__CONTROLLER__VEL_INTEGRATOR_CURRENT = 89,
AXIS__CONTROLLER__CURRENT_SETPOINT = 90,
AXIS__CONTROLLER__CONFIG__CONTROL_MODE = 91,
AXIS__CONTROLLER__CONFIG__POS_GAIN = 92,
AXIS__CONTROLLER__CONFIG__VEL_GAIN = 93,
AXIS__CONTROLLER__CONFIG__VEL_INTEGRATOR_GAIN = 94,
AXIS__CONTROLLER__CONFIG__VEL_LIMIT = 95,
AXIS__CONTROLLER__START_ANTICOGGING_CALIBRATION = 105,
AXIS__ENCODER__ERROR = 106,
AXIS__ENCODER__IS_READY = 107,
AXIS__ENCODER__INDEX_FOUND = 108,
AXIS__ENCODER__SHADOW_COUNT = 109,
AXIS__ENCODER__COUNT_IN_CPR = 110,
AXIS__ENCODER__OFFSET = 111,
AXIS__ENCODER__INTERPOLATION = 112,
AXIS__ENCODER__PHASE = 113,
AXIS__ENCODER__POS_ESTIMATE = 114,
AXIS__ENCODER__POS_CPR = 115,
AXIS__ENCODER__HALL_STATE = 116,
AXIS__ENCODER__PLL_VEL = 117,
AXIS__ENCODER__PLL_KP = 118,
AXIS__ENCODER__PLL_KI = 119,
AXIS__ENCODER__CONFIG__MODE = 120,
AXIS__ENCODER__CONFIG__USE_INDEX = 121,
AXIS__ENCODER__CONFIG__PRE_CALIBRATED = 122,
AXIS__ENCODER__CONFIG__IDX_SEARCH_SPEED = 123,
AXIS__ENCODER__CONFIG__CPR = 124,
AXIS__ENCODER__CONFIG__OFFSET = 125,
AXIS__ENCODER__CONFIG__OFFSET_FLOAT = 126,
AXIS__ENCODER__CONFIG__CALIB_RANGE = 127,
AXIS__SENSORLESS_ESTIMATOR__ERROR = 128,
AXIS__SENSORLESS_ESTIMATOR__PHASE = 129,
AXIS__SENSORLESS_ESTIMATOR__PLL_POS = 130,
AXIS__SENSORLESS_ESTIMATOR__PLL_VEL = 131,
AXIS__SENSORLESS_ESTIMATOR__PLL_KP = 132,
AXIS__SENSORLESS_ESTIMATOR__PLL_KI = 133,
};
template<int I>
struct endpoint_type;
template<> struct endpoint_type<VBUS_VOLTAGE> { typedef float type; };
template<> struct endpoint_type<SERIAL_NUMBER> { typedef uint64_t type; };
template<> struct endpoint_type<HW_VERSION_MAJOR> { typedef uint8_t type; };
template<> struct endpoint_type<HW_VERSION_MINOR> { typedef uint8_t type; };
template<> struct endpoint_type<HW_VERSION_VARIANT> { typedef uint8_t type; };
template<> struct endpoint_type<FW_VERSION_MAJOR> { typedef uint8_t type; };
template<> struct endpoint_type<FW_VERSION_MINOR> { typedef uint8_t type; };
template<> struct endpoint_type<FW_VERSION_REVISION> { typedef uint8_t type; };
template<> struct endpoint_type<FW_VERSION_UNRELEASED> { typedef uint8_t type; };
template<> struct endpoint_type<USER_CONFIG_LOADED> { typedef bool type; };
template<> struct endpoint_type<BRAKE_RESISTOR_ARMED> { typedef bool type; };
template<> struct endpoint_type<SYSTEM_STATS__UPTIME> { typedef uint32_t type; };
template<> struct endpoint_type<SYSTEM_STATS__MIN_HEAP_SPACE> { typedef uint32_t type; };
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_AXIS0> { typedef uint32_t type; };
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_AXIS1> { typedef uint32_t type; };
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_COMMS> { typedef uint32_t type; };
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_USB> { typedef uint32_t type; };
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_UART> { typedef uint32_t type; };
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_USB_IRQ> { typedef uint32_t type; };
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_STARTUP> { typedef uint32_t type; };
template<> struct endpoint_type<SYSTEM_STATS__USB__RX_CNT> { typedef uint32_t type; };
template<> struct endpoint_type<SYSTEM_STATS__USB__TX_CNT> { typedef uint32_t type; };
template<> struct endpoint_type<SYSTEM_STATS__USB__TX_OVERRUN_CNT> { typedef uint32_t type; };
template<> struct endpoint_type<SYSTEM_STATS__I2C__ADDR> { typedef uint8_t type; };
template<> struct endpoint_type<SYSTEM_STATS__I2C__ADDR_MATCH_CNT> { typedef uint32_t type; };
template<> struct endpoint_type<SYSTEM_STATS__I2C__RX_CNT> { typedef uint32_t type; };
template<> struct endpoint_type<SYSTEM_STATS__I2C__ERROR_CNT> { typedef uint32_t type; };
template<> struct endpoint_type<CONFIG__BRAKE_RESISTANCE> { typedef float type; };
template<> struct endpoint_type<CONFIG__ENABLE_UART> { typedef bool type; };
template<> struct endpoint_type<CONFIG__ENABLE_I2C_INSTEAD_OF_CAN> { typedef bool type; };
template<> struct endpoint_type<CONFIG__DC_BUS_UNDERVOLTAGE_TRIP_LEVEL> { typedef float type; };
template<> struct endpoint_type<CONFIG__DC_BUS_OVERVOLTAGE_TRIP_LEVEL> { typedef float type; };
template<> struct endpoint_type<TEST_PROPERTY> { typedef uint32_t type; };
template<> struct endpoint_type<ADC_GPIO1> { typedef uint16_t type; };
template<> struct endpoint_type<ADC_GPIO2> { typedef uint16_t type; };
template<> struct endpoint_type<SAVE_CONFIGURATION> { typedef void type; };
template<> struct endpoint_type<ERASE_CONFIGURATION> { typedef void type; };
template<> struct endpoint_type<REBOOT> { typedef void type; };
template<> struct endpoint_type<ENTER_DFU_MODE> { typedef void type; };
// Per-axis endpoints
template<> struct endpoint_type<AXIS__ERROR> { typedef uint16_t type; };
template<> struct endpoint_type<AXIS__ENABLE_STEP_DIR> { typedef bool type; };
template<> struct endpoint_type<AXIS__CURRENT_STATE> { typedef uint8_t type; };
template<> struct endpoint_type<AXIS__REQUESTED_STATE> { typedef uint8_t type; };
template<> struct endpoint_type<AXIS__LOOP_COUNTER> { typedef uint32_t type; };
template<> struct endpoint_type<AXIS__CONFIG__STARTUP_MOTOR_CALIBRATION> { typedef bool type; };
template<> struct endpoint_type<AXIS__CONFIG__STARTUP_ENCODER_INDEX_SEARCH> { typedef bool type; };
template<> struct endpoint_type<AXIS__CONFIG__STARTUP_ENCODER_OFFSET_CALIBRATION> { typedef bool type; };
template<> struct endpoint_type<AXIS__CONFIG__STARTUP_CLOSED_LOOP_CONTROL> { typedef bool type; };
template<> struct endpoint_type<AXIS__CONFIG__STARTUP_SENSORLESS_CONTROL> { typedef bool type; };
template<> struct endpoint_type<AXIS__CONFIG__ENABLE_STEP_DIR> { typedef bool type; };
template<> struct endpoint_type<AXIS__CONFIG__COUNTS_PER_STEP> { typedef float type; };
template<> struct endpoint_type<AXIS__CONFIG__RAMP_UP_TIME> { typedef float type; };
template<> struct endpoint_type<AXIS__CONFIG__RAMP_UP_DISTANCE> { typedef float type; };
template<> struct endpoint_type<AXIS__CONFIG__SPIN_UP_CURRENT> { typedef float type; };
template<> struct endpoint_type<AXIS__CONFIG__SPIN_UP_ACCELERATION> { typedef float type; };
template<> struct endpoint_type<AXIS__CONFIG__SPIN_UP_TARGET_VEL> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__ERROR> { typedef uint16_t type; };
template<> struct endpoint_type<AXIS__MOTOR__ARMED_STATE> { typedef uint8_t type; };
template<> struct endpoint_type<AXIS__MOTOR__IS_CALIBRATED> { typedef bool type; };
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_MEAS_PHB> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_MEAS_PHC> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__DC_CALIB_PHB> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__DC_CALIB_PHC> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__PHASE_CURRENT_REV_GAIN> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__P_GAIN> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__I_GAIN> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__V_CURRENT_CONTROL_INTEGRAL_D> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__V_CURRENT_CONTROL_INTEGRAL_Q> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__IBUS> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__FINAL_V_ALPHA> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__FINAL_V_BETA> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__IQ_SETPOINT> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__IQ_MEASURED> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__MAX_ALLOWED_CURRENT> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__GATE_DRIVER__DRV_FAULT> { typedef uint16_t type; };
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_GENERAL> { typedef uint16_t type; };
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ADC_CB_I> { typedef uint16_t type; };
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ADC_CB_DC> { typedef uint16_t type; };
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_MEAS_R> { typedef uint16_t type; };
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_MEAS_L> { typedef uint16_t type; };
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ENC_CALIB> { typedef uint16_t type; };
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_IDX_SEARCH> { typedef uint16_t type; };
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_FOC_VOLTAGE> { typedef uint16_t type; };
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_FOC_CURRENT> { typedef uint16_t type; };
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__PRE_CALIBRATED> { typedef bool type; };
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__POLE_PAIRS> { typedef int32_t type; };
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__CALIBRATION_CURRENT> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__RESISTANCE_CALIB_MAX_VOLTAGE> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__PHASE_INDUCTANCE> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__PHASE_RESISTANCE> { typedef float type; };
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__DIRECTION> { typedef int32_t type; };
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__MOTOR_TYPE> { typedef uint8_t type; };
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__CURRENT_LIM> { typedef float type; };
template<> struct endpoint_type<AXIS__CONTROLLER__POS_SETPOINT> { typedef float type; };
template<> struct endpoint_type<AXIS__CONTROLLER__VEL_SETPOINT> { typedef float type; };
template<> struct endpoint_type<AXIS__CONTROLLER__VEL_INTEGRATOR_CURRENT> { typedef float type; };
template<> struct endpoint_type<AXIS__CONTROLLER__CURRENT_SETPOINT> { typedef float type; };
template<> struct endpoint_type<AXIS__CONTROLLER__CONFIG__CONTROL_MODE> { typedef uint8_t type; };
template<> struct endpoint_type<AXIS__CONTROLLER__CONFIG__POS_GAIN> { typedef float type; };
template<> struct endpoint_type<AXIS__CONTROLLER__CONFIG__VEL_GAIN> { typedef float type; };
template<> struct endpoint_type<AXIS__CONTROLLER__CONFIG__VEL_INTEGRATOR_GAIN> { typedef float type; };
template<> struct endpoint_type<AXIS__CONTROLLER__CONFIG__VEL_LIMIT> { typedef float type; };
template<> struct endpoint_type<AXIS__CONTROLLER__START_ANTICOGGING_CALIBRATION> { typedef void type; };
template<> struct endpoint_type<AXIS__ENCODER__ERROR> { typedef uint8_t type; };
template<> struct endpoint_type<AXIS__ENCODER__IS_READY> { typedef bool type; };
template<> struct endpoint_type<AXIS__ENCODER__INDEX_FOUND> { typedef bool type; };
template<> struct endpoint_type<AXIS__ENCODER__SHADOW_COUNT> { typedef int32_t type; };
template<> struct endpoint_type<AXIS__ENCODER__COUNT_IN_CPR> { typedef int32_t type; };
template<> struct endpoint_type<AXIS__ENCODER__OFFSET> { typedef int32_t type; };
template<> struct endpoint_type<AXIS__ENCODER__INTERPOLATION> { typedef float type; };
template<> struct endpoint_type<AXIS__ENCODER__PHASE> { typedef float type; };
template<> struct endpoint_type<AXIS__ENCODER__POS_ESTIMATE> { typedef float type; };
template<> struct endpoint_type<AXIS__ENCODER__POS_CPR> { typedef float type; };
template<> struct endpoint_type<AXIS__ENCODER__HALL_STATE> { typedef uint8_t type; };
template<> struct endpoint_type<AXIS__ENCODER__PLL_VEL> { typedef float type; };
template<> struct endpoint_type<AXIS__ENCODER__PLL_KP> { typedef float type; };
template<> struct endpoint_type<AXIS__ENCODER__PLL_KI> { typedef float type; };
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__MODE> { typedef uint8_t type; };
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__USE_INDEX> { typedef bool type; };
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__PRE_CALIBRATED> { typedef bool type; };
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__IDX_SEARCH_SPEED> { typedef float type; };
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__CPR> { typedef int32_t type; };
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__OFFSET> { typedef int32_t type; };
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__OFFSET_FLOAT> { typedef float type; };
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__CALIB_RANGE> { typedef float type; };
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__ERROR> { typedef uint8_t type; };
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__PHASE> { typedef float type; };
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__PLL_POS> { typedef float type; };
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__PLL_VEL> { typedef float type; };
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__PLL_KP> { typedef float type; };
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__PLL_KI> { typedef float type; };
template<int I>
using endpoint_type_t = typename endpoint_type<I>::type;
}
#endif // __ODRIVE_ENDPOINTS_HPP
+267
View File
@@ -0,0 +1,267 @@
/*
* This file is a very small part of the GCC STL because AVR-GCC ships
* without the STL.
*/
namespace std
{
/**
* @defgroup metaprogramming Metaprogramming
* @ingroup utilities
*
* Template utilities for compile-time introspection and modification,
* including type classification traits, type property inspection traits
* and type transformation traits.
*
* @{
*/
/// integral_constant
template<typename _Tp, _Tp __v>
struct integral_constant
{
static constexpr _Tp value = __v;
typedef _Tp value_type;
typedef integral_constant<_Tp, __v> type;
constexpr operator value_type() const noexcept { return value; }
#if __cplusplus > 201103L
#define __cpp_lib_integral_constant_callable 201304
constexpr value_type operator()() const noexcept { return value; }
#endif
};
template<typename _Tp, _Tp __v>
constexpr _Tp integral_constant<_Tp, __v>::value;
/// The type used as a compile-time boolean with true value.
typedef integral_constant<bool, true> true_type;
/// The type used as a compile-time boolean with false value.
typedef integral_constant<bool, false> false_type;
template<bool __v>
using __bool_constant = integral_constant<bool, __v>;
#if __cplusplus > 201402L
# define __cpp_lib_bool_constant 201505
template<bool __v>
using bool_constant = integral_constant<bool, __v>;
#endif
// Primary type categories.
template<typename>
struct remove_cv;
template<typename>
struct __is_void_helper
: public false_type { };
template<>
struct __is_void_helper<void>
: public true_type { };
/// is_void
template<typename _Tp>
struct is_void
: public __is_void_helper<typename remove_cv<_Tp>::type>::type
{ };
template<typename>
struct __is_integral_helper
: public false_type { };
template<>
struct __is_integral_helper<bool>
: public true_type { };
template<>
struct __is_integral_helper<char>
: public true_type { };
template<>
struct __is_integral_helper<signed char>
: public true_type { };
template<>
struct __is_integral_helper<unsigned char>
: public true_type { };
#ifdef _GLIBCXX_USE_WCHAR_T
template<>
struct __is_integral_helper<wchar_t>
: public true_type { };
#endif
template<>
struct __is_integral_helper<char16_t>
: public true_type { };
template<>
struct __is_integral_helper<char32_t>
: public true_type { };
template<>
struct __is_integral_helper<short>
: public true_type { };
template<>
struct __is_integral_helper<unsigned short>
: public true_type { };
template<>
struct __is_integral_helper<int>
: public true_type { };
template<>
struct __is_integral_helper<unsigned int>
: public true_type { };
template<>
struct __is_integral_helper<long>
: public true_type { };
template<>
struct __is_integral_helper<unsigned long>
: public true_type { };
template<>
struct __is_integral_helper<long long>
: public true_type { };
template<>
struct __is_integral_helper<unsigned long long>
: public true_type { };
// Conditionalizing on __STRICT_ANSI__ here will break any port that
// uses one of these types for size_t.
#if defined(__GLIBCXX_TYPE_INT_N_0)
template<>
struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_0>
: public true_type { };
template<>
struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_0>
: public true_type { };
#endif
#if defined(__GLIBCXX_TYPE_INT_N_1)
template<>
struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_1>
: public true_type { };
template<>
struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_1>
: public true_type { };
#endif
#if defined(__GLIBCXX_TYPE_INT_N_2)
template<>
struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_2>
: public true_type { };
template<>
struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_2>
: public true_type { };
#endif
#if defined(__GLIBCXX_TYPE_INT_N_3)
template<>
struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_3>
: public true_type { };
template<>
struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_3>
: public true_type { };
#endif
/// is_integral
template<typename _Tp>
struct is_integral
: public __is_integral_helper<typename remove_cv<_Tp>::type>::type
{ };
template<typename>
struct __is_floating_point_helper
: public false_type { };
template<>
struct __is_floating_point_helper<float>
: public true_type { };
template<>
struct __is_floating_point_helper<double>
: public true_type { };
template<>
struct __is_floating_point_helper<long double>
: public true_type { };
#if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_FLOAT128)
template<>
struct __is_floating_point_helper<__float128>
: public true_type { };
#endif
/// is_floating_point
template<typename _Tp>
struct is_floating_point
: public __is_floating_point_helper<typename remove_cv<_Tp>::type>::type
{ };
// Const-volatile modifications.
/// remove_const
template<typename _Tp>
struct remove_const
{ typedef _Tp type; };
template<typename _Tp>
struct remove_const<_Tp const>
{ typedef _Tp type; };
/// remove_volatile
template<typename _Tp>
struct remove_volatile
{ typedef _Tp type; };
template<typename _Tp>
struct remove_volatile<_Tp volatile>
{ typedef _Tp type; };
/// remove_cv
template<typename _Tp>
struct remove_cv
{
typedef typename
remove_const<typename remove_volatile<_Tp>::type>::type type;
};
// Primary template.
/// Define a member typedef @c type only if a boolean constant is true.
template<bool, typename _Tp = void>
struct enable_if
{ };
// Partial specialization for true.
template<typename _Tp>
struct enable_if<true, _Tp>
{ typedef _Tp type; };
// Type relations.
/// is_same
template<typename, typename>
struct is_same
: public false_type { };
template<typename _Tp>
struct is_same<_Tp, _Tp>
: public true_type { };
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,33 @@
From ab5ca860b3729d76a9c43c485776147ab69d2342 Mon Sep 17 00:00:00 2001
From: Samuel Sadok <samuel.sadok@bluewin.ch>
Date: Mon, 26 Mar 2018 19:02:45 -0700
Subject: [PATCH] disable IRQ for DMA2_Stream0
This DMA stream is used to read values from ADC1
while ADC1 cycles through it's sequence of input
channels. No interrupts are required to make
this work.
---
Firmware/Board/v3/Src/dma.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/Firmware/Board/v3/Src/dma.c b/Firmware/Board/v3/Src/dma.c
index 55d5e03..3de873a 100644
--- a/Firmware/Board/v3/Src/dma.c
+++ b/Firmware/Board/v3/Src/dma.c
@@ -78,8 +78,10 @@ void MX_DMA_Init(void)
HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
/* DMA2_Stream0_IRQn interrupt configuration */
- HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 0);
- HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
+ // Dear STM, no we _don't_ want to fire an interrupt for this DMA
+ // (it's not possible to deselect this in CubeMX)
+ //HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 0);
+ //HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
}
--
2.16.2
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,137 @@
/**
******************************************************************************
* @file stm32f4xx_hal_i2c_ex.h
* @author MCD Application Team
* @brief Header file of I2C HAL Extension module.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F4xx_HAL_I2C_EX_H
#define __STM32F4xx_HAL_I2C_EX_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) ||\
defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F446xx) ||\
defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) || defined(STM32F423xx)
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal_def.h"
/** @addtogroup STM32F4xx_HAL_Driver
* @{
*/
/** @addtogroup I2CEx
* @{
*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup I2CEx_Exported_Constants I2C Exported Constants
* @{
*/
/** @defgroup I2CEx_Analog_Filter I2C Analog Filter
* @{
*/
#define I2C_ANALOGFILTER_ENABLE 0x00000000U
#define I2C_ANALOGFILTER_DISABLE I2C_FLTR_ANOFF
/**
* @}
*/
/**
* @}
*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup I2CEx_Exported_Functions
* @{
*/
/** @addtogroup I2CEx_Exported_Functions_Group1
* @{
*/
/* Peripheral Control functions ************************************************/
HAL_StatusTypeDef HAL_I2CEx_ConfigAnalogFilter(I2C_HandleTypeDef *hi2c, uint32_t AnalogFilter);
HAL_StatusTypeDef HAL_I2CEx_ConfigDigitalFilter(I2C_HandleTypeDef *hi2c, uint32_t DigitalFilter);
/**
* @}
*/
/**
* @}
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @defgroup I2CEx_Private_Constants I2C Private Constants
* @{
*/
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup I2CEx_Private_Macros I2C Private Macros
* @{
*/
#define IS_I2C_ANALOG_FILTER(FILTER) (((FILTER) == I2C_ANALOGFILTER_ENABLE) || \
((FILTER) == I2C_ANALOGFILTER_DISABLE))
#define IS_I2C_DIGITAL_FILTER(FILTER) ((FILTER) <= 0x0000000FU)
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* STM32F427xx || STM32F429xx || STM32F437xx || STM32F439xx || STM32F401xC ||\
STM32F401xE || STM32F411xE || STM32F446xx || STM32F469xx || STM32F479xx ||\
STM32F413xx || STM32F423xx */
#ifdef __cplusplus
}
#endif
#endif /* __STM32F4xx_HAL_I2C_EX_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,204 @@
/**
******************************************************************************
* @file stm32f4xx_hal_i2c_ex.c
* @author MCD Application Team
* @brief I2C Extension HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of I2C extension peripheral:
* + Extension features functions
*
@verbatim
==============================================================================
##### I2C peripheral extension features #####
==============================================================================
[..] Comparing to other previous devices, the I2C interface for STM32F427xx/437xx/
429xx/439xx devices contains the following additional features :
(+) Possibility to disable or enable Analog Noise Filter
(+) Use of a configured Digital Noise Filter
##### How to use this driver #####
==============================================================================
[..] This driver provides functions to configure Noise Filter
(#) Configure I2C Analog noise filter using the function HAL_I2C_AnalogFilter_Config()
(#) Configure I2C Digital noise filter using the function HAL_I2C_DigitalFilter_Config()
@endverbatim
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
/** @addtogroup STM32F4xx_HAL_Driver
* @{
*/
/** @defgroup I2CEx I2CEx
* @brief I2C HAL module driver
* @{
*/
#ifdef HAL_I2C_MODULE_ENABLED
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) ||\
defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F446xx) ||\
defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) || defined(STM32F423xx)
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup I2CEx_Exported_Functions I2C Exported Functions
* @{
*/
/** @defgroup I2CEx_Exported_Functions_Group1 Extension features functions
* @brief Extension features functions
*
@verbatim
===============================================================================
##### Extension features functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Configure Noise Filters
@endverbatim
* @{
*/
/**
* @brief Configures I2C Analog noise filter.
* @param hi2c pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2Cx peripheral.
* @param AnalogFilter new state of the Analog filter.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2CEx_ConfigAnalogFilter(I2C_HandleTypeDef *hi2c, uint32_t AnalogFilter)
{
/* Check the parameters */
assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance));
assert_param(IS_I2C_ANALOG_FILTER(AnalogFilter));
if(hi2c->State == HAL_I2C_STATE_READY)
{
hi2c->State = HAL_I2C_STATE_BUSY;
/* Disable the selected I2C peripheral */
__HAL_I2C_DISABLE(hi2c);
/* Reset I2Cx ANOFF bit */
hi2c->Instance->FLTR &= ~(I2C_FLTR_ANOFF);
/* Disable the analog filter */
hi2c->Instance->FLTR |= AnalogFilter;
__HAL_I2C_ENABLE(hi2c);
hi2c->State = HAL_I2C_STATE_READY;
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Configures I2C Digital noise filter.
* @param hi2c pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2Cx peripheral.
* @param DigitalFilter Coefficient of digital noise filter between 0x00 and 0x0F.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2CEx_ConfigDigitalFilter(I2C_HandleTypeDef *hi2c, uint32_t DigitalFilter)
{
uint16_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance));
assert_param(IS_I2C_DIGITAL_FILTER(DigitalFilter));
if(hi2c->State == HAL_I2C_STATE_READY)
{
hi2c->State = HAL_I2C_STATE_BUSY;
/* Disable the selected I2C peripheral */
__HAL_I2C_DISABLE(hi2c);
/* Get the old register value */
tmpreg = hi2c->Instance->FLTR;
/* Reset I2Cx DNF bit [3:0] */
tmpreg &= ~(I2C_FLTR_DNF);
/* Set I2Cx DNF coefficient */
tmpreg |= DigitalFilter;
/* Store the new register value */
hi2c->Instance->FLTR = tmpreg;
__HAL_I2C_ENABLE(hi2c);
hi2c->State = HAL_I2C_STATE_READY;
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @}
*/
/**
* @}
*/
#endif /* STM32F427xx || STM32F429xx || STM32F437xx || STM32F439xx || STM32F401xC ||\
STM32F401xE || STM32F446xx || STM32F469xx || STM32F479xx || STM32F413xx ||\
STM32F423xx */
#endif /* HAL_I2C_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+1 -1
View File
@@ -96,7 +96,7 @@
#define configUSE_PREEMPTION 1
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_IDLE_HOOK 1
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( SystemCoreClock )
#define configTICK_RATE_HZ ((TickType_t)1000)
+3
View File
@@ -8,4 +8,7 @@ extern osSemaphoreId sem_uart_dma;
extern osSemaphoreId sem_usb_rx;
extern osSemaphoreId sem_usb_tx;
extern osThreadId defaultTaskHandle;
extern osThreadId usb_irq_thread;
#endif /* __FREERTOS_H */
+3 -1
View File
@@ -71,12 +71,14 @@ void MX_GPIO_Init(void);
/* USER CODE BEGIN Prototypes */
void SetGPIO12toUART();
void SetupENCIndexGPIO();
bool GPIO_subscribe(GPIO_TypeDef* GPIO_port, uint16_t GPIO_pin,
uint32_t pull_up_down,
void (*callback)(void*), void* ctx);
void GPIO_unsubscribe(GPIO_TypeDef* GPIO_port, uint16_t GPIO_pin);
void GPIO_set_to_analog(GPIO_TypeDef* GPIO_port, uint16_t GPIO_pin);
uint16_t get_gpio_pin_by_pin(uint16_t GPIO_pin);
GPIO_TypeDef* get_gpio_port_by_pin(uint16_t GPIO_pin);
/* USER CODE END Prototypes */
+91
View File
@@ -0,0 +1,91 @@
/**
******************************************************************************
* File Name : I2C.h
* Description : This file provides code for the configuration
* of the I2C instances.
******************************************************************************
* This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* Copyright (c) 2018 STMicroelectronics International N.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted, provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific written permission.
* 4. This software, including modifications and/or derivative works of this
* software, must execute solely and exclusively on microcontroller or
* microprocessor devices manufactured by or for STMicroelectronics.
* 5. Redistribution and use of this software other than as permitted under
* this license is void and will automatically terminate your rights under
* this license.
*
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __i2c_H
#define __i2c_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
extern I2C_HandleTypeDef hi2c1;
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
extern void _Error_Handler(char *, int);
void MX_I2C1_Init(uint8_t addr);
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /*__ i2c_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+18 -15
View File
@@ -54,10 +54,14 @@
/* Includes ------------------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stm32f4xx_hal.h"
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 1 \
|| HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 2
#include "prev_board_ver/main_V3_2.h"
#elif HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 3 \
|| HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 4
#include "prev_board_ver/main_V3_4.h"
#else
/* USER CODE END Includes */
@@ -74,8 +78,8 @@
#define M0_nCS_GPIO_Port GPIOC
#define M1_nCS_Pin GPIO_PIN_14
#define M1_nCS_GPIO_Port GPIOC
#define M1_DC_CAL_Pin GPIO_PIN_15
#define M1_DC_CAL_GPIO_Port GPIOC
#define M1_ENC_Z_Pin GPIO_PIN_15
#define M1_ENC_Z_GPIO_Port GPIOC
#define M0_IB_Pin GPIO_PIN_0
#define M0_IB_GPIO_Port GPIOC
#define M0_IC_Pin GPIO_PIN_1
@@ -90,27 +94,26 @@
#define GPIO_2_GPIO_Port GPIOA
#define GPIO_3_Pin GPIO_PIN_2
#define GPIO_3_GPIO_Port GPIOA
#define GPIO_3_EXTI_IRQn EXTI2_IRQn
#define GPIO_4_Pin GPIO_PIN_3
#define GPIO_4_GPIO_Port GPIOA
#define M1_TEMP_Pin GPIO_PIN_4
#define M1_TEMP_GPIO_Port GPIOA
#define AUX_I_Pin GPIO_PIN_5
#define AUX_I_GPIO_Port GPIOA
#define AUX_TEMP_Pin GPIO_PIN_5
#define AUX_TEMP_GPIO_Port GPIOA
#define VBUS_S_Pin GPIO_PIN_6
#define VBUS_S_GPIO_Port GPIOA
#define M1_AL_Pin GPIO_PIN_7
#define M1_AL_GPIO_Port GPIOA
#define AUX_TEMP_Pin GPIO_PIN_4
#define AUX_TEMP_GPIO_Port GPIOC
#define GPIO_5_Pin GPIO_PIN_4
#define GPIO_5_GPIO_Port GPIOC
#define M0_TEMP_Pin GPIO_PIN_5
#define M0_TEMP_GPIO_Port GPIOC
#define M1_BL_Pin GPIO_PIN_0
#define M1_BL_GPIO_Port GPIOB
#define M1_CL_Pin GPIO_PIN_1
#define M1_CL_GPIO_Port GPIOB
#define GPIO_5_Pin GPIO_PIN_2
#define GPIO_5_GPIO_Port GPIOB
#define GPIO_6_Pin GPIO_PIN_2
#define GPIO_6_GPIO_Port GPIOB
#define AUX_L_Pin GPIO_PIN_10
#define AUX_L_GPIO_Port GPIOB
#define AUX_H_Pin GPIO_PIN_11
@@ -129,20 +132,20 @@
#define M1_BH_GPIO_Port GPIOC
#define M1_CH_Pin GPIO_PIN_8
#define M1_CH_GPIO_Port GPIOC
#define M0_DC_CAL_Pin GPIO_PIN_9
#define M0_DC_CAL_GPIO_Port GPIOC
#define M0_ENC_Z_Pin GPIO_PIN_9
#define M0_ENC_Z_GPIO_Port GPIOC
#define M0_AH_Pin GPIO_PIN_8
#define M0_AH_GPIO_Port GPIOA
#define M0_BH_Pin GPIO_PIN_9
#define M0_BH_GPIO_Port GPIOA
#define M0_CH_Pin GPIO_PIN_10
#define M0_CH_GPIO_Port GPIOA
#define M0_ENC_Z_Pin GPIO_PIN_15
#define M0_ENC_Z_GPIO_Port GPIOA
#define GPIO_7_Pin GPIO_PIN_15
#define GPIO_7_GPIO_Port GPIOA
#define nFAULT_Pin GPIO_PIN_2
#define nFAULT_GPIO_Port GPIOD
#define M1_ENC_Z_Pin GPIO_PIN_3
#define M1_ENC_Z_GPIO_Port GPIOB
#define GPIO_8_Pin GPIO_PIN_3
#define GPIO_8_GPIO_Port GPIOB
#define M0_ENC_A_Pin GPIO_PIN_4
#define M0_ENC_A_GPIO_Port GPIOB
#define M0_ENC_B_Pin GPIO_PIN_5
@@ -6,6 +6,7 @@
#define TIM_APB1_CLOCK_HZ 84000000
#define TIM_APB1_PERIOD_CLOCKS 4096
#define TIM_APB1_DEADTIME_CLOCKS 40
#define configAPPLICATION_ALLOCATED_HEAP 1
#define M0_nCS_Pin GPIO_PIN_13
#define M0_nCS_GPIO_Port GPIOC
@@ -0,0 +1,91 @@
/* Private define ------------------------------------------------------------*/
#define TIM_1_8_CLOCK_HZ 168000000
#define TIM_1_8_PERIOD_CLOCKS 10192
#define TIM_1_8_DEADTIME_CLOCKS 20
#define TIM_APB1_CLOCK_HZ 84000000
#define TIM_APB1_PERIOD_CLOCKS 4096
#define TIM_APB1_DEADTIME_CLOCKS 40
#define configAPPLICATION_ALLOCATED_HEAP 1
#define M0_nCS_Pin GPIO_PIN_13
#define M0_nCS_GPIO_Port GPIOC
#define M1_nCS_Pin GPIO_PIN_14
#define M1_nCS_GPIO_Port GPIOC
#define M1_DC_CAL_Pin GPIO_PIN_15
#define M1_DC_CAL_GPIO_Port GPIOC
#define M0_IB_Pin GPIO_PIN_0
#define M0_IB_GPIO_Port GPIOC
#define M0_IC_Pin GPIO_PIN_1
#define M0_IC_GPIO_Port GPIOC
#define M1_IC_Pin GPIO_PIN_2
#define M1_IC_GPIO_Port GPIOC
#define M1_IB_Pin GPIO_PIN_3
#define M1_IB_GPIO_Port GPIOC
#define GPIO_1_Pin GPIO_PIN_0
#define GPIO_1_GPIO_Port GPIOA
#define GPIO_2_Pin GPIO_PIN_1
#define GPIO_2_GPIO_Port GPIOA
#define GPIO_3_Pin GPIO_PIN_2
#define GPIO_3_GPIO_Port GPIOA
#define GPIO_3_EXTI_IRQn EXTI2_IRQn
#define GPIO_4_Pin GPIO_PIN_3
#define GPIO_4_GPIO_Port GPIOA
#define M1_TEMP_Pin GPIO_PIN_4
#define M1_TEMP_GPIO_Port GPIOA
#define AUX_I_Pin GPIO_PIN_5
#define AUX_I_GPIO_Port GPIOA
#define VBUS_S_Pin GPIO_PIN_6
#define VBUS_S_GPIO_Port GPIOA
#define M1_AL_Pin GPIO_PIN_7
#define M1_AL_GPIO_Port GPIOA
#define AUX_TEMP_Pin GPIO_PIN_4
#define AUX_TEMP_GPIO_Port GPIOC
#define M0_TEMP_Pin GPIO_PIN_5
#define M0_TEMP_GPIO_Port GPIOC
#define M1_BL_Pin GPIO_PIN_0
#define M1_BL_GPIO_Port GPIOB
#define M1_CL_Pin GPIO_PIN_1
#define M1_CL_GPIO_Port GPIOB
#define GPIO_5_Pin GPIO_PIN_2
#define GPIO_5_GPIO_Port GPIOB
#define AUX_L_Pin GPIO_PIN_10
#define AUX_L_GPIO_Port GPIOB
#define AUX_H_Pin GPIO_PIN_11
#define AUX_H_GPIO_Port GPIOB
#define EN_GATE_Pin GPIO_PIN_12
#define EN_GATE_GPIO_Port GPIOB
#define M0_AL_Pin GPIO_PIN_13
#define M0_AL_GPIO_Port GPIOB
#define M0_BL_Pin GPIO_PIN_14
#define M0_BL_GPIO_Port GPIOB
#define M0_CL_Pin GPIO_PIN_15
#define M0_CL_GPIO_Port GPIOB
#define M1_AH_Pin GPIO_PIN_6
#define M1_AH_GPIO_Port GPIOC
#define M1_BH_Pin GPIO_PIN_7
#define M1_BH_GPIO_Port GPIOC
#define M1_CH_Pin GPIO_PIN_8
#define M1_CH_GPIO_Port GPIOC
#define M0_DC_CAL_Pin GPIO_PIN_9
#define M0_DC_CAL_GPIO_Port GPIOC
#define M0_AH_Pin GPIO_PIN_8
#define M0_AH_GPIO_Port GPIOA
#define M0_BH_Pin GPIO_PIN_9
#define M0_BH_GPIO_Port GPIOA
#define M0_CH_Pin GPIO_PIN_10
#define M0_CH_GPIO_Port GPIOA
#define M0_ENC_Z_Pin GPIO_PIN_15
#define M0_ENC_Z_GPIO_Port GPIOA
#define nFAULT_Pin GPIO_PIN_2
#define nFAULT_GPIO_Port GPIOD
#define M1_ENC_Z_Pin GPIO_PIN_3
#define M1_ENC_Z_GPIO_Port GPIOB
#define M0_ENC_A_Pin GPIO_PIN_4
#define M0_ENC_A_GPIO_Port GPIOB
#define M0_ENC_B_Pin GPIO_PIN_5
#define M0_ENC_B_GPIO_Port GPIOB
#define M1_ENC_A_Pin GPIO_PIN_6
#define M1_ENC_A_GPIO_Port GPIOB
#define M1_ENC_B_Pin GPIO_PIN_7
#define M1_ENC_B_GPIO_Port GPIOB
+1 -1
View File
@@ -65,7 +65,7 @@
/* #define HAL_SRAM_MODULE_ENABLED */
/* #define HAL_SDRAM_MODULE_ENABLED */
/* #define HAL_HASH_MODULE_ENABLED */
/* #define HAL_I2C_MODULE_ENABLED */
#define HAL_I2C_MODULE_ENABLED
/* #define HAL_I2S_MODULE_ENABLED */
/* #define HAL_IWDG_MODULE_ENABLED */
/* #define HAL_LTDC_MODULE_ENABLED */
+1 -1
View File
@@ -132,7 +132,7 @@ extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS;
* @{
*/
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len);
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len, uint8_t endpoint_pair);
/* USER CODE BEGIN EXPORTED_FUNCTIONS */
/* USER CODE END EXPORTED_FUNCTIONS */
+2 -1
View File
@@ -89,6 +89,7 @@
* @brief Defines for configuration of the Usb device.
* @{
*/
#define MS_VendorCode 'P'
/*---------- -----------*/
#define USBD_MAX_NUM_INTERFACES 1
@@ -97,7 +98,7 @@
/*---------- -----------*/
#define USBD_MAX_STR_DESC_SIZ 512
/*---------- -----------*/
#define USBD_SUPPORT_USER_STRING 0
#define USBD_SUPPORT_USER_STRING 1
/*---------- -----------*/
#define USBD_DEBUG_LEVEL 0
/*---------- -----------*/
+2
View File
@@ -133,6 +133,8 @@ extern USBD_DescriptorsTypeDef FS_Desc;
/* USER CODE BEGIN EXPORTED_FUNCTIONS */
uint8_t * USBD_UsrStrDescriptor(struct _USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length);
/* USER CODE END EXPORTED_FUNCTIONS */
/**
+4 -1
View File
@@ -58,7 +58,10 @@ Middlewares/Third_Party/FreeRTOS/Source/timers.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c \
Middlewares/Third_Party/FreeRTOS/Source/event_groups.c
Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c \
Src/i2c.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c
ASM_SOURCES = \
startup_stm32f405xx.s
@@ -52,13 +52,15 @@
#define CDC_IN_EP 0x81 /* EP1 for data IN */
#define CDC_OUT_EP 0x01 /* EP1 for data OUT */
#define CDC_CMD_EP 0x82 /* EP2 for CDC commands */
#define ODRIVE_IN_EP 0x83 /* EP3 IN: ODrive device TX endpoint */
#define ODRIVE_OUT_EP 0x03 /* EP3 OUT: ODrive device RX endpoint */
/* CDC Endpoints parameters: you can fine tune these values depending on the needed baudrates and performance. */
#define CDC_DATA_HS_MAX_PACKET_SIZE 512 /* Endpoint IN & OUT Packet size */
#define CDC_DATA_HS_MAX_PACKET_SIZE 64 /* Endpoint IN & OUT Packet size */
#define CDC_DATA_FS_MAX_PACKET_SIZE 64 /* Endpoint IN & OUT Packet size */
#define CDC_CMD_PACKET_SIZE 8 /* Control Endpoint Packet size */
#define USB_CDC_CONFIG_DESC_SIZ 67
#define USB_CDC_CONFIG_DESC_SIZ (67 + 39)
#define CDC_DATA_HS_IN_PACKET_SIZE CDC_DATA_HS_MAX_PACKET_SIZE
#define CDC_DATA_HS_OUT_PACKET_SIZE CDC_DATA_HS_MAX_PACKET_SIZE
@@ -103,7 +105,7 @@ typedef struct _USBD_CDC_Itf
int8_t (* Init) (void);
int8_t (* DeInit) (void);
int8_t (* Control) (uint8_t, uint8_t * , uint16_t);
int8_t (* Receive) (uint8_t *, uint32_t *);
int8_t (* Receive) (uint8_t *, uint32_t *, uint8_t);
}USBD_CDC_ItfTypeDef;
@@ -156,9 +158,9 @@ uint8_t USBD_CDC_SetTxBuffer (USBD_HandleTypeDef *pdev,
uint8_t USBD_CDC_SetRxBuffer (USBD_HandleTypeDef *pdev,
uint8_t *pbuff);
uint8_t USBD_CDC_ReceivePacket (USBD_HandleTypeDef *pdev);
uint8_t USBD_CDC_ReceivePacket (USBD_HandleTypeDef *pdev, uint8_t endpoint_pair);
uint8_t USBD_CDC_TransmitPacket (USBD_HandleTypeDef *pdev);
uint8_t USBD_CDC_TransmitPacket (USBD_HandleTypeDef *pdev, uint8_t endpoint_pair);
/**
* @}
*/
File diff suppressed because it is too large Load Diff
@@ -68,7 +68,9 @@
#define USBD_IDX_PRODUCT_STR 0x02
#define USBD_IDX_SERIAL_STR 0x03
#define USBD_IDX_CONFIG_STR 0x04
#define USBD_IDX_INTERFACE_STR 0x05
#define USBD_IDX_INTERFACE_STR 0x05
#define USBD_IDX_ODRIVE_INTF_STR 0x06
#define USBD_IDX_MICROSOFT_DESC_STR 0xEE
#define USB_REQ_TYPE_STANDARD 0x00
#define USB_REQ_TYPE_CLASS 0x20
+43 -26
View File
@@ -82,9 +82,20 @@ CAN1.IPParameters=CalculateTimeQuantum,CalculateTimeBit,Prescaler,TimeSeg1,TimeS
CAN1.Prescaler=7
CAN1.TimeSeg1=CAN_BS1_6TQ
CAN1.TimeSeg2=CAN_BS2_5TQ
Dma.ADC1.2.Direction=DMA_PERIPH_TO_MEMORY
Dma.ADC1.2.FIFOMode=DMA_FIFOMODE_DISABLE
Dma.ADC1.2.Instance=DMA2_Stream0
Dma.ADC1.2.MemDataAlignment=DMA_MDATAALIGN_HALFWORD
Dma.ADC1.2.MemInc=DMA_MINC_ENABLE
Dma.ADC1.2.Mode=DMA_CIRCULAR
Dma.ADC1.2.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD
Dma.ADC1.2.PeriphInc=DMA_PINC_DISABLE
Dma.ADC1.2.Priority=DMA_PRIORITY_LOW
Dma.ADC1.2.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
Dma.Request0=UART4_RX
Dma.Request1=UART4_TX
Dma.RequestsNb=2
Dma.Request2=ADC1
Dma.RequestsNb=3
Dma.UART4_RX.0.Direction=DMA_PERIPH_TO_MEMORY
Dma.UART4_RX.0.FIFOMode=DMA_FIFOMODE_DISABLE
Dma.UART4_RX.0.Instance=DMA1_Stream2
@@ -108,10 +119,11 @@ Dma.UART4_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataA
FREERTOS.FootprintOK=true
FREERTOS.INCLUDE_uxTaskGetStackHighWaterMark=1
FREERTOS.INCLUDE_vTaskDelayUntil=1
FREERTOS.IPParameters=Tasks01,INCLUDE_vTaskDelayUntil,configTOTAL_HEAP_SIZE,FootprintOK,configCHECK_FOR_STACK_OVERFLOW,INCLUDE_uxTaskGetStackHighWaterMark
FREERTOS.IPParameters=Tasks01,INCLUDE_vTaskDelayUntil,configTOTAL_HEAP_SIZE,FootprintOK,configCHECK_FOR_STACK_OVERFLOW,INCLUDE_uxTaskGetStackHighWaterMark,configUSE_IDLE_HOOK
FREERTOS.Tasks01=defaultTask,0,256,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL
FREERTOS.configCHECK_FOR_STACK_OVERFLOW=1
FREERTOS.configTOTAL_HEAP_SIZE=65536
FREERTOS.configUSE_IDLE_HOOK=1
File.Version=6
KeepUserPlacement=true
Mcu.Family=STM32F4
@@ -206,8 +218,8 @@ NVIC.CAN1_SCE_IRQn=true\:6\:0\:true\:false\:true\:true\:true
NVIC.CAN1_TX_IRQn=true\:6\:0\:true\:false\:true\:true\:true
NVIC.DMA1_Stream2_IRQn=true\:5\:0\:false\:false\:true\:true\:true
NVIC.DMA1_Stream4_IRQn=true\:5\:0\:false\:false\:true\:true\:false
NVIC.DMA2_Stream0_IRQn=true\:5\:0\:false\:false\:false\:true\:false
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:true
NVIC.EXTI2_IRQn=true\:0\:0\:false\:false\:false\:false\:true
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:true
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:true
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:true
@@ -216,7 +228,9 @@ NVIC.PendSV_IRQn=true\:15\:0\:false\:false\:false\:true\:true
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false\:true
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:true\:true
NVIC.TIM1_UP_TIM10_IRQn=true\:0\:0\:false\:false\:false\:false\:true
NVIC.TIM8_TRG_COM_TIM14_IRQn=true\:0\:0\:false\:false\:true\:false\:false
NVIC.TIM8_UP_TIM13_IRQn=true\:0\:0\:false\:false\:false\:false\:true
NVIC.TimeBase=TIM8_TRG_COM_TIM14_IRQn
NVIC.TimeBaseIP=TIM14
NVIC.UART4_IRQn=true\:5\:0\:false\:false\:true\:true\:true
@@ -246,14 +260,13 @@ PA13.Signal=SYS_JTMS-SWDIO
PA14.Mode=Serial_Wire
PA14.Signal=SYS_JTCK-SWCLK
PA15.GPIOParameters=GPIO_Label
PA15.GPIO_Label=M0_ENC_Z
PA15.GPIO_Label=GPIO_7
PA15.Locked=true
PA15.Signal=GPIO_Input
PA2.GPIOParameters=GPIO_PuPd,GPIO_Label
PA2.GPIOParameters=GPIO_Label
PA2.GPIO_Label=GPIO_3
PA2.GPIO_PuPd=GPIO_PULLDOWN
PA2.Locked=true
PA2.Signal=GPXTI2
PA2.Signal=GPIO_Input
PA3.GPIOParameters=GPIO_PuPd,GPIO_Label
PA3.GPIO_Label=GPIO_4
PA3.GPIO_PuPd=GPIO_NOPULL
@@ -264,7 +277,7 @@ PA4.GPIO_Label=M1_TEMP
PA4.Locked=true
PA4.Signal=ADCx_IN4
PA5.GPIOParameters=GPIO_Label
PA5.GPIO_Label=AUX_I
PA5.GPIO_Label=AUX_TEMP
PA5.Locked=true
PA5.Signal=ADCx_IN5
PA6.GPIOParameters=GPIO_Label
@@ -322,11 +335,11 @@ PB15.Locked=true
PB15.Mode=PWM Generation3 CH3 CH3N
PB15.Signal=TIM1_CH3N
PB2.GPIOParameters=GPIO_Label
PB2.GPIO_Label=GPIO_5
PB2.GPIO_Label=GPIO_6
PB2.Locked=true
PB2.Signal=GPIO_Input
PB3.GPIOParameters=GPIO_Label
PB3.GPIO_Label=M1_ENC_Z
PB3.GPIO_Label=GPIO_8
PB3.Locked=true
PB3.Signal=GPIO_Input
PB4.GPIOParameters=GPIO_Label
@@ -341,10 +354,12 @@ PB6.Signal=S_TIM4_CH1
PB7.GPIOParameters=GPIO_Label
PB7.GPIO_Label=M1_ENC_B
PB7.Signal=S_TIM4_CH2
PB8.Mode=Master
PB8.Signal=CAN1_RX
PB9.Mode=Master
PB9.Signal=CAN1_TX
PB8.Locked=true
PB8.Signal=SharedStack_PB8
PB8.Stacked=true
PB9.Locked=true
PB9.Signal=SharedStack_PB9
PB9.Stacked=true
PC0.GPIOParameters=GPIO_Label
PC0.GPIO_Label=M0_IB
PC0.Signal=ADCx_IN10
@@ -368,9 +383,9 @@ PC14-OSC32_IN.Locked=true
PC14-OSC32_IN.PinState=GPIO_PIN_SET
PC14-OSC32_IN.Signal=GPIO_Output
PC15-OSC32_OUT.GPIOParameters=GPIO_Label
PC15-OSC32_OUT.GPIO_Label=M1_DC_CAL
PC15-OSC32_OUT.GPIO_Label=M1_ENC_Z
PC15-OSC32_OUT.Locked=true
PC15-OSC32_OUT.Signal=GPIO_Output
PC15-OSC32_OUT.Signal=GPIO_Input
PC2.GPIOParameters=GPIO_Label
PC2.GPIO_Label=M1_IC
PC2.Signal=ADCx_IN12
@@ -378,8 +393,9 @@ PC3.GPIOParameters=GPIO_Label
PC3.GPIO_Label=M1_IB
PC3.Signal=ADCx_IN13
PC4.GPIOParameters=GPIO_Label
PC4.GPIO_Label=AUX_TEMP
PC4.Signal=ADCx_IN14
PC4.GPIO_Label=GPIO_5
PC4.Locked=true
PC4.Signal=GPIO_Input
PC5.GPIOParameters=GPIO_Label
PC5.GPIO_Label=M0_TEMP
PC5.Signal=ADCx_IN15
@@ -396,9 +412,9 @@ PC8.GPIO_Label=M1_CH
PC8.Locked=true
PC8.Signal=S_TIM8_CH3
PC9.GPIOParameters=GPIO_Label
PC9.GPIO_Label=M0_DC_CAL
PC9.GPIO_Label=M0_ENC_Z
PC9.Locked=true
PC9.Signal=GPIO_Output
PC9.Signal=GPIO_Input
PCC.Checker=false
PCC.Line=STM32F405/415
PCC.MCU=STM32F405RGTx
@@ -441,7 +457,7 @@ ProjectManager.StackSize=0x800
ProjectManager.TargetToolchain=Makefile
ProjectManager.ToolChainLocation=
ProjectManager.UnderRoot=false
ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-MX_DMA_Init-DMA-false-HAL-true,3-MX_ADC1_Init-ADC1-false-HAL-true,4-MX_ADC2_Init-ADC2-false-HAL-true,5-MX_CAN1_Init-CAN1-false-HAL-true,6-MX_TIM1_Init-TIM1-false-HAL-true,7-MX_TIM8_Init-TIM8-false-HAL-true,8-MX_TIM3_Init-TIM3-false-HAL-true,9-MX_TIM4_Init-TIM4-false-HAL-true,10-MX_SPI3_Init-SPI3-false-HAL-true,11-MX_ADC3_Init-ADC3-false-HAL-true,12-SystemClock_Config-RCC-false-HAL-true,13-MX_TIM2_Init-TIM2-false-HAL-true,14-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL-true,15-MX_UART4_Init-UART4-false-HAL-true
ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-MX_DMA_Init-DMA-false-HAL-true,3-MX_ADC1_Init-ADC1-false-HAL-true,4-MX_ADC2_Init-ADC2-false-HAL-true,5-MX_TIM1_Init-TIM1-false-HAL-true,6-MX_TIM8_Init-TIM8-false-HAL-true,7-MX_TIM3_Init-TIM3-false-HAL-true,8-MX_TIM4_Init-TIM4-false-HAL-true,9-MX_SPI3_Init-SPI3-false-HAL-true,10-MX_ADC3_Init-ADC3-false-HAL-true,11-SystemClock_Config-RCC-false-HAL-true,12-MX_TIM2_Init-TIM2-false-HAL-true,13-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL-true,14-MX_UART4_Init-UART4-false-HAL-true,15-MX_CAN1_Init-CAN1-false-HAL-true
RCC.48MHZClocksFreq_Value=48000000
RCC.AHBFreq_Value=168000000
RCC.APB1CLKDivider=RCC_HCLK_DIV4
@@ -492,9 +508,6 @@ SH.ADCx_IN13.0=ADC1_IN13,IN13
SH.ADCx_IN13.1=ADC2_IN13,IN13
SH.ADCx_IN13.2=ADC3_IN13,IN13
SH.ADCx_IN13.ConfNb=3
SH.ADCx_IN14.0=ADC1_IN14,IN14
SH.ADCx_IN14.1=ADC2_IN14,IN14
SH.ADCx_IN14.ConfNb=2
SH.ADCx_IN15.0=ADC1_IN15,IN15
SH.ADCx_IN15.1=ADC2_IN15,IN15
SH.ADCx_IN15.ConfNb=2
@@ -507,8 +520,6 @@ SH.ADCx_IN5.ConfNb=2
SH.ADCx_IN6.0=ADC1_IN6,IN6
SH.ADCx_IN6.1=ADC2_IN6,IN6
SH.ADCx_IN6.ConfNb=2
SH.GPXTI2.0=GPIO_EXTI2
SH.GPXTI2.ConfNb=1
SH.S_TIM1_CH1.0=TIM1_CH1,PWM Generation1 CH1 CH1N
SH.S_TIM1_CH1.ConfNb=1
SH.S_TIM1_CH2.0=TIM1_CH2,PWM Generation2 CH2 CH2N
@@ -539,6 +550,12 @@ SH.SharedStack_PA0.ConfNb=2
SH.SharedStack_PA1.0=GPIO_Input+0
SH.SharedStack_PA1.1=UART4_RX,Asynchronous
SH.SharedStack_PA1.ConfNb=2
SH.SharedStack_PB8.0=CAN1_RX,Master
SH.SharedStack_PB8.1=I2C1_SCL
SH.SharedStack_PB8.ConfNb=2
SH.SharedStack_PB9.0=CAN1_TX,Master
SH.SharedStack_PB9.1=I2C1_SDA
SH.SharedStack_PB9.ConfNb=2
SPI3.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16
SPI3.CLKPhase=SPI_PHASE_2EDGE
SPI3.CalculateBaudRate=2.625 MBits/s
+35 -12
View File
@@ -51,18 +51,23 @@
#include "adc.h"
#include "gpio.h"
#include "dma.h"
/* USER CODE BEGIN 0 */
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 1 \
|| HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 2
#include "prev_board_ver/adc_V3_2.c"
#elif HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 3 \
|| HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 4
#include "prev_board_ver/adc_V3_4.c"
#else
/* USER CODE END 0 */
ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;
ADC_HandleTypeDef hadc3;
DMA_HandleTypeDef hdma_adc1;
/* ADC1 init function */
void MX_ADC1_Init(void)
@@ -241,20 +246,38 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
PA4 ------> ADC1_IN4
PA5 ------> ADC1_IN5
PA6 ------> ADC1_IN6
PC4 ------> ADC1_IN14
PC5 ------> ADC1_IN15
*/
GPIO_InitStruct.Pin = M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|AUX_TEMP_Pin|M0_TEMP_Pin;
|M0_TEMP_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin;
GPIO_InitStruct.Pin = M1_TEMP_Pin|AUX_TEMP_Pin|VBUS_S_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* ADC1 DMA Init */
/* ADC1 Init */
hdma_adc1.Instance = DMA2_Stream0;
hdma_adc1.Init.Channel = DMA_CHANNEL_0;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
/* ADC1 interrupt Init */
HAL_NVIC_SetPriority(ADC_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(ADC_IRQn);
@@ -278,16 +301,15 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
PA4 ------> ADC2_IN4
PA5 ------> ADC2_IN5
PA6 ------> ADC2_IN6
PC4 ------> ADC2_IN14
PC5 ------> ADC2_IN15
*/
GPIO_InitStruct.Pin = M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|AUX_TEMP_Pin|M0_TEMP_Pin;
|M0_TEMP_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin;
GPIO_InitStruct.Pin = M1_TEMP_Pin|AUX_TEMP_Pin|VBUS_S_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
@@ -346,13 +368,15 @@ void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
PA4 ------> ADC1_IN4
PA5 ------> ADC1_IN5
PA6 ------> ADC1_IN6
PC4 ------> ADC1_IN14
PC5 ------> ADC1_IN15
*/
HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|AUX_TEMP_Pin|M0_TEMP_Pin);
|M0_TEMP_Pin);
HAL_GPIO_DeInit(GPIOA, M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin);
HAL_GPIO_DeInit(GPIOA, M1_TEMP_Pin|AUX_TEMP_Pin|VBUS_S_Pin);
/* ADC1 DMA DeInit */
HAL_DMA_DeInit(adcHandle->DMA_Handle);
/* ADC1 interrupt Deinit */
/* USER CODE BEGIN ADC1:ADC_IRQn disable */
@@ -383,13 +407,12 @@ void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
PA4 ------> ADC2_IN4
PA5 ------> ADC2_IN5
PA6 ------> ADC2_IN6
PC4 ------> ADC2_IN14
PC5 ------> ADC2_IN15
*/
HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|AUX_TEMP_Pin|M0_TEMP_Pin);
|M0_TEMP_Pin);
HAL_GPIO_DeInit(GPIOA, M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin);
HAL_GPIO_DeInit(GPIOA, M1_TEMP_Pin|AUX_TEMP_Pin|VBUS_S_Pin);
/* ADC2 interrupt Deinit */
/* USER CODE BEGIN ADC2:ADC_IRQn disable */
+6
View File
@@ -68,6 +68,7 @@ void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Stream2_IRQn interrupt configuration */
@@ -76,6 +77,11 @@ void MX_DMA_Init(void)
/* DMA1_Stream4_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
/* DMA2_Stream0_IRQn interrupt configuration */
// Dear STM, no we _don't_ want to fire an interrupt for this DMA
// (it's not possible to deselect this in CubeMX)
//HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 0);
//HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
}
+19 -1
View File
@@ -68,6 +68,8 @@ osSemaphoreId sem_uart_dma;
osSemaphoreId sem_usb_rx;
osSemaphoreId sem_usb_tx;
osThreadId usb_irq_thread;
// Place FreeRTOS heap in core coupled memory for better performance
__attribute__((section(".ccmram")))
uint8_t ucHeap[configTOTAL_HEAP_SIZE];
@@ -84,8 +86,24 @@ void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
/* USER CODE END FunctionPrototypes */
/* Hook prototypes */
void vApplicationIdleHook(void);
void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName);
/* USER CODE BEGIN 2 */
__weak void vApplicationIdleHook( void )
{
/* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle
task. It is essential that code added to this hook function never attempts
to block in any way (for example, call xQueueReceive() with a block time
specified, or call vTaskDelay()). If the application makes use of the
vTaskDelete() API function (as this demo application does) then it is also
important that vApplicationIdleHook() is permitted to return to its calling
function, because it is the responsibility of the idle task to clean up
memory allocated by the kernel to any task that has since been deleted. */
}
/* USER CODE END 2 */
/* USER CODE BEGIN 4 */
__weak void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName)
{
@@ -112,7 +130,7 @@ void usb_deferred_interrupt_thread(void * ctx) {
void init_deferred_interrupts(void) {
// Start USB interrupt handler thread
osThreadDef(task_usb_pump, usb_deferred_interrupt_thread, osPriorityAboveNormal, 0, 512);
osThreadCreate(osThread(task_usb_pump), NULL);
usb_irq_thread = osThreadCreate(osThread(task_usb_pump), NULL);
}
/* USER CODE END 4 */
+51 -17
View File
@@ -55,6 +55,9 @@
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 1 \
|| HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 2
#include "prev_board_ver/gpio_V3_2.c"
#elif HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 3 \
|| HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 4
#include "prev_board_ver/gpio_V3_4.c"
#else
/* USER CODE END 0 */
@@ -87,33 +90,30 @@ void MX_GPIO_Init(void)
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, M0_nCS_Pin|M1_nCS_Pin, GPIO_PIN_SET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, M1_DC_CAL_Pin|M0_DC_CAL_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(EN_GATE_GPIO_Port, EN_GATE_Pin, GPIO_PIN_RESET);
/*Configure GPIO pins : PCPin PCPin PCPin PCPin */
GPIO_InitStruct.Pin = M0_nCS_Pin|M1_nCS_Pin|M1_DC_CAL_Pin|M0_DC_CAL_Pin;
/*Configure GPIO pins : PCPin PCPin */
GPIO_InitStruct.Pin = M0_nCS_Pin|M1_nCS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = GPIO_3_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIO_3_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : PCPin PCPin PCPin */
GPIO_InitStruct.Pin = M1_ENC_Z_Pin|GPIO_5_Pin|M0_ENC_Z_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pins : PAPin PAPin */
GPIO_InitStruct.Pin = GPIO_4_Pin|M0_ENC_Z_Pin;
/*Configure GPIO pins : PAPin PAPin PAPin */
GPIO_InitStruct.Pin = GPIO_3_Pin|GPIO_4_Pin|GPIO_7_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : PBPin PBPin */
GPIO_InitStruct.Pin = GPIO_5_Pin|M1_ENC_Z_Pin;
GPIO_InitStruct.Pin = GPIO_6_Pin|GPIO_8_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
@@ -131,10 +131,6 @@ void MX_GPIO_Init(void)
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(nFAULT_GPIO_Port, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
}
/* USER CODE BEGIN 2 */
@@ -145,6 +141,7 @@ void MX_GPIO_Init(void)
// no matter which port they belong to.
IRQn_Type get_irq_number(uint16_t pin) {
uint16_t pin_number = 0;
pin >>= 1;
while (pin) {
pin >>= 1;
pin_number++;
@@ -260,6 +257,17 @@ void GPIO_unsubscribe(GPIO_TypeDef* GPIO_port, uint16_t GPIO_pin) {
HAL_NVIC_DisableIRQ(get_irq_number(GPIO_pin));
}
// @brief Configures the specified GPIO as an analog input.
// This disables any subscriptions that were active for this pin.
void GPIO_set_to_analog(GPIO_TypeDef* GPIO_port, uint16_t GPIO_pin) {
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_unsubscribe(GPIO_port, GPIO_pin);
GPIO_InitStruct.Pin = GPIO_pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIO_port, &GPIO_InitStruct);
}
//Dispatch processing of external interrupts based on source
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_pin) {
for (size_t i = 0; i < n_subscriptions; ++i) {
@@ -269,6 +277,32 @@ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_pin) {
}
}
GPIO_TypeDef* get_gpio_port_by_pin(uint16_t GPIO_pin){
switch(GPIO_pin){
case 1: return GPIO_1_GPIO_Port; break;
case 2: return GPIO_2_GPIO_Port; break;
case 3: return GPIO_3_GPIO_Port; break;
case 4: return GPIO_4_GPIO_Port; break;
#ifdef GPIO_5_GPIO_Port
case 5: return GPIO_5_GPIO_Port; break;
#endif
default: return GPIO_1_GPIO_Port;
}
}
uint16_t get_gpio_pin_by_pin(uint16_t GPIO_pin){
switch(GPIO_pin){
case 1: return GPIO_1_Pin; break;
case 2: return GPIO_2_Pin; break;
case 3: return GPIO_3_Pin; break;
case 4: return GPIO_4_Pin; break;
#ifdef GPIO_5_Pin
case 5: return GPIO_5_Pin; break;
#endif
default: return GPIO_1_Pin;
}
}
/* USER CODE END 2 */
/**
+198
View File
@@ -0,0 +1,198 @@
/**
******************************************************************************
* File Name : I2C.c
* Description : This file provides code for the configuration
* of the I2C instances.
******************************************************************************
* This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* Copyright (c) 2018 STMicroelectronics International N.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted, provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific written permission.
* 4. This software, including modifications and/or derivative works of this
* software, must execute solely and exclusively on microcontroller or
* microprocessor devices manufactured by or for STMicroelectronics.
* 5. Redistribution and use of this software other than as permitted under
* this license is void and will automatically terminate your rights under
* this license.
*
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "i2c.h"
#include "gpio.h"
#include "dma.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
I2C_HandleTypeDef hi2c1;
DMA_HandleTypeDef hdma_i2c1_rx;
DMA_HandleTypeDef hdma_i2c1_tx;
/* I2C1 init function */
void MX_I2C1_Init(uint8_t addr)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = addr << 1;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(i2cHandle->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspInit 0 */
/* USER CODE END I2C1_MspInit 0 */
/**I2C1 GPIO Configuration
PB8 ------> I2C1_SCL
PB9 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* I2C1 clock enable */
__HAL_RCC_I2C1_CLK_ENABLE();
/* I2C1 DMA Init */
/* I2C1_RX Init */
hdma_i2c1_rx.Instance = DMA1_Stream0;
hdma_i2c1_rx.Init.Channel = DMA_CHANNEL_1;
hdma_i2c1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_i2c1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2c1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2c1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_i2c1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_i2c1_rx.Init.Mode = DMA_CIRCULAR;
hdma_i2c1_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_i2c1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_i2c1_rx) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
__HAL_LINKDMA(i2cHandle,hdmarx,hdma_i2c1_rx);
/* I2C1_TX Init */
hdma_i2c1_tx.Instance = DMA1_Stream6;
hdma_i2c1_tx.Init.Channel = DMA_CHANNEL_1;
hdma_i2c1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_i2c1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2c1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2c1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_i2c1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_i2c1_tx.Init.Mode = DMA_NORMAL;
hdma_i2c1_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_i2c1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_i2c1_tx) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
__HAL_LINKDMA(i2cHandle,hdmatx,hdma_i2c1_tx);
/* I2C1 interrupt Init */
HAL_NVIC_SetPriority(I2C1_EV_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
HAL_NVIC_SetPriority(I2C1_ER_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
/* USER CODE BEGIN I2C1_MspInit 1 */
/* USER CODE END I2C1_MspInit 1 */
}
}
void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{
if(i2cHandle->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspDeInit 0 */
/* USER CODE END I2C1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_I2C1_CLK_DISABLE();
/**I2C1 GPIO Configuration
PB8 ------> I2C1_SCL
PB9 ------> I2C1_SDA
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8|GPIO_PIN_9);
/* I2C1 DMA DeInit */
HAL_DMA_DeInit(i2cHandle->hdmarx);
HAL_DMA_DeInit(i2cHandle->hdmatx);
/* I2C1 interrupt Deinit */
HAL_NVIC_DisableIRQ(I2C1_EV_IRQn);
HAL_NVIC_DisableIRQ(I2C1_ER_IRQn);
/* USER CODE BEGIN I2C1_MspDeInit 1 */
/* USER CODE END I2C1_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+23 -18
View File
@@ -61,6 +61,7 @@
/* USER CODE BEGIN Includes */
#include <MotorControl/odrive_main.h>
#include "freertos_vars.h"
#include "i2c.h"
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
@@ -86,29 +87,33 @@ extern char _estack; // provided by the linker script
// Gets called from the startup assembly code
void early_start_checks(void) {
if(_reboot_cookie == 0xDEADFE75) {
/* The STM DFU bootloader enables internal pull-up resistors on PB10 (AUX_H)
* and PB11 (AUX_L), thereby causing shoot-through on the brake resistor
* FETs and obliterating them unless external 3.3k pull-down resistors are
* present. Pull-downs are only present on ODrive 3.5 or newer.
* On older boards we disable DFU by default but if the user insists
* there's only one thing left that might save it: time.
* The brake resistor gate driver needs a certain 10V supply (GVDD) to
* make it work. This voltage is supplied by the motor gate drivers which get
* disabled at system reset. So over time GVDD voltage _should_ below
* dangerous levels. This is completely handwavy and should not be relied on
* so you are on your own on if you ignore this warning.
*
* This loop takes 5 cycles per iteration and at this point the system runs
* on the internal 16MHz RC oscillator so the delay is about 2 seconds.
*/
for (size_t i = 0; i < (16000000UL / 5UL * 2UL); ++i) {
__NOP();
}
_reboot_cookie = 0xDEADBEEF;
}
/* We could jump to the bootloader directly on demand without rebooting
but that requires us to reset several peripherals and interrupts for it
to function correctly. Therefore it's easier to just reset the entire chip. */
if(_reboot_cookie == 0xDEADBEEF) {
_reboot_cookie = 0xCAFEFEED; //Reset bootloader trigger
/*
* This wait loop solves an obscure timing issue, but we don't exactly understand why.
* When the transition NVIC_SystemReset() => STM bootloader happens very quickly,
* there is a yet unexplained phenomenon where the ODrive would emit an audible click,
* followed by one the following symptoms:
* - Device reboots in normal mode (possibly due to the bootloader exiting immidiately)
* - Device goes into DFU mode and then the power supply turns off
* This manifests in the DFU script detecting the device in DFU mode but then
* losing the device immidiately after.
* There were no motors/encoders/brake resistor connected when testing this. As far as
* we can tell, the only way for the software to cause a short circuit is through the
* brake FETs.
*/
for (size_t i = 0; i < 1000000; ++i) {
__NOP();
}
__set_MSP((uintptr_t)&_estack);
// http://www.st.com/content/ccc/resource/technical/document/application_note/6a/17/92/02/58/98/45/0c/CD00264379.pdf/files/CD00264379.pdf
void (*builtin_bootloader)(void) = (void (*)(void))(*((uint32_t *)0x1FFF0004));
@@ -2,6 +2,7 @@
ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;
ADC_HandleTypeDef hadc3;
DMA_HandleTypeDef hdma_adc1;
/* ADC1 init function */
void MX_ADC1_Init(void)
@@ -195,6 +196,25 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* ADC1 DMA Init */
/* ADC1 Init */
hdma_adc1.Instance = DMA2_Stream0;
hdma_adc1.Init.Channel = DMA_CHANNEL_0;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
/* ADC1 interrupt Init */
HAL_NVIC_SetPriority(ADC_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(ADC_IRQn);
@@ -0,0 +1,395 @@
ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;
ADC_HandleTypeDef hadc3;
DMA_HandleTypeDef hdma_adc1;
/* ADC1 init function */
void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
ADC_InjectionConfTypeDef sConfigInjected;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_6;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
*/
sConfigInjected.InjectedChannel = ADC_CHANNEL_6;
sConfigInjected.InjectedRank = 1;
sConfigInjected.InjectedNbrOfConversion = 1;
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING;
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_TRGO;
sConfigInjected.AutoInjectedConv = DISABLE;
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
sConfigInjected.InjectedOffset = 0;
if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
/* ADC2 init function */
void MX_ADC2_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
ADC_InjectionConfTypeDef sConfigInjected;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc2.Instance = ADC2;
hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc2.Init.Resolution = ADC_RESOLUTION_12B;
hadc2.Init.ScanConvMode = DISABLE;
hadc2.Init.ContinuousConvMode = DISABLE;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc2.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T8_TRGO;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.NbrOfConversion = 1;
hadc2.Init.DMAContinuousRequests = DISABLE;
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_13;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
*/
sConfigInjected.InjectedChannel = ADC_CHANNEL_10;
sConfigInjected.InjectedRank = 1;
sConfigInjected.InjectedNbrOfConversion = 1;
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING;
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_TRGO;
sConfigInjected.AutoInjectedConv = DISABLE;
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
sConfigInjected.InjectedOffset = 0;
if (HAL_ADCEx_InjectedConfigChannel(&hadc2, &sConfigInjected) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
/* ADC3 init function */
void MX_ADC3_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
ADC_InjectionConfTypeDef sConfigInjected;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc3.Instance = ADC3;
hadc3.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc3.Init.Resolution = ADC_RESOLUTION_12B;
hadc3.Init.ScanConvMode = DISABLE;
hadc3.Init.ContinuousConvMode = DISABLE;
hadc3.Init.DiscontinuousConvMode = DISABLE;
hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc3.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T8_TRGO;
hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc3.Init.NbrOfConversion = 1;
hadc3.Init.DMAContinuousRequests = DISABLE;
hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_12;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
*/
sConfigInjected.InjectedChannel = ADC_CHANNEL_11;
sConfigInjected.InjectedRank = 1;
sConfigInjected.InjectedNbrOfConversion = 1;
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING;
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_TRGO;
sConfigInjected.AutoInjectedConv = DISABLE;
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
sConfigInjected.InjectedOffset = 0;
if (HAL_ADCEx_InjectedConfigChannel(&hadc3, &sConfigInjected) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(adcHandle->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspInit 0 */
/* USER CODE END ADC1_MspInit 0 */
/* ADC1 clock enable */
__HAL_RCC_ADC1_CLK_ENABLE();
/**ADC1 GPIO Configuration
PC0 ------> ADC1_IN10
PC1 ------> ADC1_IN11
PC2 ------> ADC1_IN12
PC3 ------> ADC1_IN13
PA4 ------> ADC1_IN4
PA5 ------> ADC1_IN5
PA6 ------> ADC1_IN6
PC4 ------> ADC1_IN14
PC5 ------> ADC1_IN15
*/
GPIO_InitStruct.Pin = M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|AUX_TEMP_Pin|M0_TEMP_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* ADC1 DMA Init */
/* ADC1 Init */
hdma_adc1.Instance = DMA2_Stream0;
hdma_adc1.Init.Channel = DMA_CHANNEL_0;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
/* ADC1 interrupt Init */
HAL_NVIC_SetPriority(ADC_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(ADC_IRQn);
/* USER CODE BEGIN ADC1_MspInit 1 */
/* USER CODE END ADC1_MspInit 1 */
}
else if(adcHandle->Instance==ADC2)
{
/* USER CODE BEGIN ADC2_MspInit 0 */
/* USER CODE END ADC2_MspInit 0 */
/* ADC2 clock enable */
__HAL_RCC_ADC2_CLK_ENABLE();
/**ADC2 GPIO Configuration
PC0 ------> ADC2_IN10
PC1 ------> ADC2_IN11
PC2 ------> ADC2_IN12
PC3 ------> ADC2_IN13
PA4 ------> ADC2_IN4
PA5 ------> ADC2_IN5
PA6 ------> ADC2_IN6
PC4 ------> ADC2_IN14
PC5 ------> ADC2_IN15
*/
GPIO_InitStruct.Pin = M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|AUX_TEMP_Pin|M0_TEMP_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* ADC2 interrupt Init */
HAL_NVIC_SetPriority(ADC_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(ADC_IRQn);
/* USER CODE BEGIN ADC2_MspInit 1 */
/* USER CODE END ADC2_MspInit 1 */
}
else if(adcHandle->Instance==ADC3)
{
/* USER CODE BEGIN ADC3_MspInit 0 */
/* USER CODE END ADC3_MspInit 0 */
/* ADC3 clock enable */
__HAL_RCC_ADC3_CLK_ENABLE();
/**ADC3 GPIO Configuration
PC0 ------> ADC3_IN10
PC1 ------> ADC3_IN11
PC2 ------> ADC3_IN12
PC3 ------> ADC3_IN13
*/
GPIO_InitStruct.Pin = M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* ADC3 interrupt Init */
HAL_NVIC_SetPriority(ADC_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(ADC_IRQn);
/* USER CODE BEGIN ADC3_MspInit 1 */
/* USER CODE END ADC3_MspInit 1 */
}
}
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{
if(adcHandle->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspDeInit 0 */
/* USER CODE END ADC1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_ADC1_CLK_DISABLE();
/**ADC1 GPIO Configuration
PC0 ------> ADC1_IN10
PC1 ------> ADC1_IN11
PC2 ------> ADC1_IN12
PC3 ------> ADC1_IN13
PA4 ------> ADC1_IN4
PA5 ------> ADC1_IN5
PA6 ------> ADC1_IN6
PC4 ------> ADC1_IN14
PC5 ------> ADC1_IN15
*/
HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|AUX_TEMP_Pin|M0_TEMP_Pin);
HAL_GPIO_DeInit(GPIOA, M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin);
/* ADC1 interrupt Deinit */
/* USER CODE BEGIN ADC1:ADC_IRQn disable */
/**
* Uncomment the line below to disable the "ADC_IRQn" interrupt
* Be aware, disabling shared interrupt may affect other IPs
*/
/* HAL_NVIC_DisableIRQ(ADC_IRQn); */
/* USER CODE END ADC1:ADC_IRQn disable */
/* USER CODE BEGIN ADC1_MspDeInit 1 */
/* USER CODE END ADC1_MspDeInit 1 */
}
else if(adcHandle->Instance==ADC2)
{
/* USER CODE BEGIN ADC2_MspDeInit 0 */
/* USER CODE END ADC2_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_ADC2_CLK_DISABLE();
/**ADC2 GPIO Configuration
PC0 ------> ADC2_IN10
PC1 ------> ADC2_IN11
PC2 ------> ADC2_IN12
PC3 ------> ADC2_IN13
PA4 ------> ADC2_IN4
PA5 ------> ADC2_IN5
PA6 ------> ADC2_IN6
PC4 ------> ADC2_IN14
PC5 ------> ADC2_IN15
*/
HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|AUX_TEMP_Pin|M0_TEMP_Pin);
HAL_GPIO_DeInit(GPIOA, M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin);
/* ADC2 interrupt Deinit */
/* USER CODE BEGIN ADC2:ADC_IRQn disable */
/**
* Uncomment the line below to disable the "ADC_IRQn" interrupt
* Be aware, disabling shared interrupt may affect other IPs
*/
/* HAL_NVIC_DisableIRQ(ADC_IRQn); */
/* USER CODE END ADC2:ADC_IRQn disable */
/* USER CODE BEGIN ADC2_MspDeInit 1 */
/* USER CODE END ADC2_MspDeInit 1 */
}
else if(adcHandle->Instance==ADC3)
{
/* USER CODE BEGIN ADC3_MspDeInit 0 */
/* USER CODE END ADC3_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_ADC3_CLK_DISABLE();
/**ADC3 GPIO Configuration
PC0 ------> ADC3_IN10
PC1 ------> ADC3_IN11
PC2 ------> ADC3_IN12
PC3 ------> ADC3_IN13
*/
HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin);
/* ADC3 interrupt Deinit */
/* USER CODE BEGIN ADC3:ADC_IRQn disable */
/**
* Uncomment the line below to disable the "ADC_IRQn" interrupt
* Be aware, disabling shared interrupt may affect other IPs
*/
/* HAL_NVIC_DisableIRQ(ADC_IRQn); */
/* USER CODE END ADC3:ADC_IRQn disable */
/* USER CODE BEGIN ADC3_MspDeInit 1 */
/* USER CODE END ADC3_MspDeInit 1 */
}
}
@@ -0,0 +1,71 @@
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, M0_nCS_Pin|M1_nCS_Pin, GPIO_PIN_SET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, M1_DC_CAL_Pin|M0_DC_CAL_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(EN_GATE_GPIO_Port, EN_GATE_Pin, GPIO_PIN_RESET);
/*Configure GPIO pins : PCPin PCPin PCPin PCPin */
GPIO_InitStruct.Pin = M0_nCS_Pin|M1_nCS_Pin|M1_DC_CAL_Pin|M0_DC_CAL_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = GPIO_3_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIO_3_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : PAPin PAPin */
GPIO_InitStruct.Pin = GPIO_4_Pin|M0_ENC_Z_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : PBPin PBPin */
GPIO_InitStruct.Pin = GPIO_5_Pin|M1_ENC_Z_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = EN_GATE_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(EN_GATE_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = nFAULT_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(nFAULT_GPIO_Port, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
}
+57 -2
View File
@@ -46,6 +46,10 @@ void ADC_IRQ_Dispatch(ADC_HandleTypeDef* hadc, ADC_handler_t callback);
// TODO: move somewhere else
void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected);
void vbus_sense_adc_cb(ADC_HandleTypeDef* hadc, bool injected);
void tim_update_cb(TIM_HandleTypeDef* htim);
extern TIM_HandleTypeDef htim1;
extern I2C_HandleTypeDef hi2c1;
/* USER CODE END 0 */
@@ -365,6 +369,40 @@ void ADC_IRQ_Dispatch(ADC_HandleTypeDef* hadc, ADC_handler_t callback) {
}
}
/**
* @brief This function handles TIM1 update interrupt and TIM10 global interrupt.
*/
void TIM1_UP_TIM10_IRQHandler(void)
{
__HAL_TIM_CLEAR_IT(&htim1, TIM_IT_UPDATE);
tim_update_cb(&htim1);
}
/**
* @brief This function handles TIM8 update interrupt and TIM13 global interrupt.
*/
void TIM8_UP_TIM13_IRQHandler(void)
{
__HAL_TIM_CLEAR_IT(&htim8, TIM_IT_UPDATE);
tim_update_cb(&htim8);
}
/**
* @brief This function handles I2C1 event interrupt.
*/
void I2C1_EV_IRQHandler(void)
{
HAL_I2C_EV_IRQHandler(&hi2c1);
}
/**
* @brief This function handles I2C1 error interrupt.
*/
void I2C1_ER_IRQHandler(void)
{
HAL_I2C_ER_IRQHandler(&hi2c1);
}
/**
* @brief This function handles EXTI line0 interrupt.
@@ -398,15 +436,32 @@ void EXTI4_IRQHandler(void)
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
}
/**
* @brief This function handles EXTI lines 5-9 interrupt.
*/
void EXTI9_5_IRQHandler(void)
{
// The true source of the interrupt is checked inside HAL_GPIO_EXTI_IRQHandler()
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_5);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_8);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);
}
/**
* @brief This function handles EXTI lines 10-15 interrupt.
*/
void EXTI15_10_IRQHandler(void)
{
// The true source of the interrupt is checked inside HAL_GPIO_EXTI_IRQHandler()
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_15);
}
/* USER CODE END 1 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+10
View File
@@ -346,6 +346,10 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
/* USER CODE END TIM1_MspInit 0 */
/* TIM1 clock enable */
__HAL_RCC_TIM1_CLK_ENABLE();
/* TIM1 interrupt Init */
HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
/* USER CODE BEGIN TIM1_MspInit 1 */
/* USER CODE END TIM1_MspInit 1 */
@@ -375,6 +379,8 @@ void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* tim_pwmHandle)
__HAL_RCC_TIM8_CLK_ENABLE();
/* TIM8 interrupt Init */
HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn);
/* USER CODE BEGIN TIM8_MspInit 1 */
@@ -542,6 +548,9 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
/* USER CODE END TIM1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM1_CLK_DISABLE();
/* TIM1 interrupt Deinit */
HAL_NVIC_DisableIRQ(TIM1_UP_TIM10_IRQn);
/* USER CODE BEGIN TIM1_MspDeInit 1 */
/* USER CODE END TIM1_MspDeInit 1 */
@@ -571,6 +580,7 @@ void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef* tim_pwmHandle)
__HAL_RCC_TIM8_CLK_DISABLE();
/* TIM8 interrupt Deinit */
HAL_NVIC_DisableIRQ(TIM8_UP_TIM13_IRQn);
HAL_NVIC_DisableIRQ(TIM8_TRG_COM_TIM14_IRQn);
/* USER CODE BEGIN TIM8_MspDeInit 1 */
+5 -5
View File
@@ -151,7 +151,7 @@ extern USBD_HandleTypeDef hUsbDeviceFS;
static int8_t CDC_Init_FS(void);
static int8_t CDC_DeInit_FS(void);
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length);
static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len);
static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len, uint8_t endpoint_pair);
/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */
/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */
@@ -287,10 +287,10 @@ static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
* @param Len: Number of data received (in bytes)
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len, uint8_t endpoint_pair)
{
/* USER CODE BEGIN 6 */
usb_process_packet(Buf, *Len);
usb_process_packet(Buf, *Len, endpoint_pair);
return (USBD_OK);
/* USER CODE END 6 */
@@ -307,7 +307,7 @@ static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
* @param Len: Number of data to be sent (in bytes)
* @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
*/
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len, uint8_t endpoint_pair)
{
uint8_t result = USBD_OK;
/* USER CODE BEGIN 7 */
@@ -323,7 +323,7 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
memcpy(UserTxBufferFS, Buf, Len);
// Update Len
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, Len);
result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
result = USBD_CDC_TransmitPacket(&hUsbDeviceFS, endpoint_pair);
/* USER CODE END 7 */
return result;
}
+20 -2
View File
@@ -154,6 +154,23 @@ void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle)
*/
void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
{
USBD_StatusTypeDef ret = USBD_OK;
USBD_HandleTypeDef *pdev = hpcd->pData;
USBD_SetupReqTypedef *req = &pdev->request;
USBD_ParseSetupRequest(req, (uint8_t *)hpcd->Setup);
if ( ( USB_REQ_TYPE_VENDOR == (req->bmRequest & USB_REQ_TYPE_MASK) ) && ( MS_VendorCode == req->bRequest ) )
{
pdev->ep0_state = USBD_EP0_SETUP;
pdev->ep0_data_len = pdev->request.wLength;
ret = pdev->pClass->Setup(pdev, req);
if( (req->wLength == 0) && (ret == USBD_OK) )
{
USBD_CtlSendStatus(pdev);
}
return;
}
USBD_LL_SetupStage((USBD_HandleTypeDef*)hpcd->pData, (uint8_t *)hpcd->Setup);
}
@@ -312,7 +329,7 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
pdev->pData = &hpcd_USB_OTG_FS;
hpcd_USB_OTG_FS.Instance = USB_OTG_FS;
hpcd_USB_OTG_FS.Init.dev_endpoints = 4;
hpcd_USB_OTG_FS.Init.dev_endpoints = 6;
hpcd_USB_OTG_FS.Init.speed = PCD_SPEED_FULL;
hpcd_USB_OTG_FS.Init.dma_enable = DISABLE;
hpcd_USB_OTG_FS.Init.ep0_mps = DEP0CTL_MPS_64;
@@ -329,7 +346,8 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_FS, 0x80);
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 0, 0x40);
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 0x80);
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 0x40); // CDC IN endpoint
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 3, 0x40); // ODrive IN endpoint
}
return USBD_OK;
}
+50 -4
View File
@@ -97,7 +97,8 @@
#define USBD_PID_FS 0x0D32
#define USBD_PRODUCT_XSTR(s) USBD_PRODUCT_STR(s)
#define USBD_PRODUCT_STR(s) #s
#define USBD_PRODUCT_STRING_FS ODrive version HW_VERSION_MAJOR.HW_VERSION_MINOR
#define USBD_PRODUCT_STRING_FS ODrive HW_VERSION_MAJOR.HW_VERSION_MINOR CDC Interface
#define NATIVE_STRING ODrive HW_VERSION_MAJOR.HW_VERSION_MINOR Native Interface
#define USBD_SERIALNUMBER_STRING_FS "000000000001"
#define USBD_CONFIGURATION_STRING_FS "CDC Config"
#define USBD_INTERFACE_STRING_FS "CDC Interface"
@@ -114,6 +115,50 @@
/* USER CODE BEGIN 0 */
// MS OS String descriptor to tell Windows that it may query for other descriptors
// It's a standard string descriptor.
// Windows will only query for OS descriptors once!
// Delete the information about already queried devices in registry by deleting:
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags\VVVVPPPPRRRR
__ALIGN_BEGIN uint8_t USBD_MS_OS_StringDescriptor[] __ALIGN_END =
{
0x12, // bLength 1 0x12 Length of the descriptor
0x03, // bDescriptorType 1 0x03 Descriptor type
// qwSignature 14 MSFT100 Signature field
0x4D, 0x00, // 'M'
0x53, 0x00, // 'S'
0x46, 0x00, // 'F'
0x54, 0x00, // 'T'
0x31, 0x00, // '1'
0x30, 0x00, // '0'
0x30, 0x00, // '0'
MS_VendorCode, // bMS_VendorCode 1 Vendor-specific Vendor code
0x00 // bPad 1 0x00 Pad field
};
// redefined further down
__ALIGN_BEGIN uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
/**
* @brief UsrStrDescriptor
* return non standard string descriptor
* @param pdev: device instance
* @param index : descriptor index (0xEE for MS OS String Descriptor)
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_UsrStrDescriptor(struct _USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length)
{
*length = 0;
if (USBD_IDX_MICROSOFT_DESC_STR == index) {
*length = sizeof (USBD_MS_OS_StringDescriptor);
return USBD_MS_OS_StringDescriptor;
} else if (USBD_IDX_ODRIVE_INTF_STR == index) {
USBD_GetString((uint8_t *)USBD_PRODUCT_XSTR(NATIVE_STRING), USBD_StrDesc, length);
return USBD_StrDesc;
}
return NULL;
}
/* USER CODE END 0 */
/** @defgroup USBD_DESC_Private_Macros USBD_DESC_Private_Macros
@@ -189,16 +234,17 @@ __ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
0x00, /*bcdUSB */
#endif /* (USBD_LPM_ENABLED == 1) */
0x02,
0x02, /*bDeviceClass*/
// Notify OS that this is a composite device
0xEF, /*bDeviceClass*/
0x02, /*bDeviceSubClass*/
0x00, /*bDeviceProtocol*/
0x01, /*bDeviceProtocol*/
USB_MAX_EP0_SIZE, /*bMaxPacketSize*/
LOBYTE(USBD_VID), /*idVendor*/
HIBYTE(USBD_VID), /*idVendor*/
LOBYTE(USBD_PID_FS), /*idProduct*/
HIBYTE(USBD_PID_FS), /*idProduct*/
0x00, /*bcdDevice rel. 2.00*/
0x02,
0x03, /* bNumInterfaces */
USBD_IDX_MFC_STR, /*Index of manufacturer string*/
USBD_IDX_PRODUCT_STR, /*Index of product string*/
USBD_IDX_SERIAL_STR, /*Index of serial number string*/
+31 -4
View File
@@ -2,14 +2,39 @@
Please add a note of your changes below this heading if you make a Pull Request.
### Added
* `make write_otp` command to burn the board version onto the ODrive's one-time programmable memory. If you have an ODrive v3.4 or older, you can run this once for a better firmware update user experience in the future. Run the command without any options for more details. Once set, the board version is exposed through the `board_version_[...]` properties.
* bake Git-derived firmware version into firmware binary. The firmware version is exposed through the `fw_version_[...]` properties.
* Encoder can now go forever in velocity/torque mode due to using circular encoder space.
* `make write_otp` command to burn the board version onto the ODrive's one-time programmable memory. If you have an ODrive v3.4 or older, you should run this once for a better firmware update user experience in the future. Run the command without any options for more details. Once set, the board version is exposed through the `hw_version_[...]` properties.
* bake Git-derived firmware version into firmware binary. The firmware version is exposed through the `fw_version_[...]` properties.
* infrastructure to publish the python tools to PyPi. See `tools/setup.py` for details.
* Automated test script `run_tests.py`
* Protocol supports function return values
* System stats (e.g. stack usage) are exposed under `<odrv>.system_stats`
### Changed
* The DFU script now verifies the flash after writing
* DFU script updates
* Verify the flash after writing
* Automatically download firmware from GitHub releases if no file is provided
* Retain configuration during firmware updates
* Refactor python tools
* The scripts `explore_odrive.py`, `liveplotter.py`, `drv_status.py` and `rate_test.py` have been merged into one single `odrivetool` script. Running this script without any arguments provides the shell that `explore_odrive.py` used to provide.
* The command line options of `odrivetool` have changed compared to the original `explore_odrive.py`. See `odrivetool --help` for more details.
* `odrivetool` (previously `explore_odrive.py`) now supports controlling multiple ODrives concurrently (`odrv0`, `odrv1`, ...)
* No need to restart the `odrivetool` shell when devices get disconnected and reconnected
* ODrive accesses from within python tools are now thread-safe. That means you can read from the same remote property from multiple threads concurrently.
* The liveplotter (`odrivetool liveplotter`, formerly `liveplotter.py`) does no longer steal focus and closes as expected
* Add commands `odrivetool backup-config` and `odrivetool restore-config`
* (experimental: start liveplotter from `odrivetool` shell by typing `start_liveplotter(lambda: odrv0.motor0.encoder.encoder_state)`)
* `make write_otp` command to burn the board version onto the ODrive's one-time programmable memory. If you have an ODrive v3.4 or older, you can run this once for a better firmware update user experience in the future. Run the command without any options for more details. Once set, the board version is exposed through the `hw_version_[...]` properties.
* bake Git-derived firmware version into firmware binary. The firmware version is exposed through the `fw_version_[...]` properties.
* Set thread priority of USB pump thread above protocol thread
* GPIO3 not sensitive to edges by default
* The device now appears as a composite device on USB. One subdevice is still a CDC device (virtual COM port), the other subdevice is a vendor specific class. This should resolve several issues that were caused by conflicting kernel drivers or OS services.
* Add WinUSB descriptors. This will tell Windows >= 8 to automatically load winusb.sys for the ODrive (only for the vendor specific subdevice). This makes it possible to use the ODrive from userspace via WinUSB with zero configuration. The Python tool currently still uses libusb so Zadig is still required.
* Add a configuration to enable the ASCII protocol on USB at runtime. This will only enable the ASCII protocol on the USB CDC subdevice, not the vendor specific subdevice so the python tools will still be able to talk to the ODrive.
### Fixed
* Enums now transported with correct underlying type on native protocol
* USB issue where the device would stop responding when the host script would quit abruptly or reset the device during operation
# Releases
@@ -18,13 +43,15 @@ Please add a note of your changes below this heading if you make a Pull Request.
### Added
* **Storing of configuration parameters to Non Volatile Memory**
* **USB Bootloader**
* `make erase_config` to erase the configuration with an STLink (the configuration can also be erased from within explore_odrive.py, using `my_odrive.erase_configuration()`)
* `make erase_config` to erase the configuration with an STLink (the configuration can also be erased from within explore_odrive.py, using `odrv0.erase_configuration()`)
* Travis-CI builds firmware for all board versions and deploys the binaries when a tag is pushed to master
* General purpose ADC API. See function get_adc_voltage() in low_level.cpp for more detais.
### Changed
* Most of the code from `lowlevel.c` moved to `axis.cpp`, `encoder.cpp`, `controller.cpp`, `sensorless_estimator.cpp`, `motor.cpp` and the corresponding header files
* Refactoring of the developer-facing communication protocol interface. See e.g. `axis.hpp` or `controller.hpp` for examples on how to add your own fields and functions
* Change of the user-facing field paths. E.g. `my_odrive.motor0.pos_setpoint` is now at `my_odrive.axis0.controller.pos_setpoint`. Names are mostly unchanged.
* Rewrite of the top-level per-axis state-machine
* The build is now configured using the `tup.config` file instead of editing source files. Make sure you set your board version correctly. See [here](README.md#configuring-the-build) for details.
* The toplevel directory for tup is now `Firmware`. If you used tup before, go to `Firmware` and run `rm -rd ../.tup; rm -rd build/*; make`.
* Update CubeMX generated STM platform code to version 1.19.0
+18 -6
View File
@@ -5,18 +5,26 @@
BUILD_DIR = build
FIRMWARE = $(BUILD_DIR)/ODriveFirmware.elf
FIRMWARE_HEX = $(BUILD_DIR)/ODriveFirmware.hex
OPENOCD := openocd -f interface/stlink-v2.cfg \
$(if $(value PROGRAMMER),-c 'hla_serial $(PROGRAMMER)',) \
-f target/stm32f4x.cfg
all:
@tup --quiet --no-environ-check
flash: all
openocd -f interface/stlink-v2.cfg -f target/stm32f4x.cfg -c init -c reset\ halt -c flash\ write_image\ erase\ $(FIRMWARE) -c reset\ run -c exit
$(OPENOCD) -c init \
-c 'reset halt' \
-c 'flash write_image erase $(FIRMWARE)' \
-c 'reset run' \
-c exit
gdb: all
arm-none-eabi-gdb $(FIRMWARE) -x openocd.gdbinit
dfu: all
../tools/dfu.py $(if $(value SERIAL_NUMBER),--serial-number $(SERIAL_NUMBER),) $(FIRMWARE_HEX)
python ../tools/odrivetool $(if $(value SERIAL_NUMBER),--serial-number $(SERIAL_NUMBER),) dfu $(FIRMWARE_HEX)
bmp: all
arm-none-eabi-gdb --ex 'target extended-remote /dev/stlink' \
@@ -24,9 +32,13 @@ bmp: all
--ex 'attach 1' \
--ex 'load' $(FIRMWARE)
# Erase entire STM32
erase:
$(OPENOCD) -c init -c reset\ halt -c flash\ erase_address\ 0x8000000\ 0x100000 -c reset\ run -c exit
# Erase all configuration from the ODrive
erase_config:
openocd -f interface/stlink-v2.cfg -f target/stm32f4x.cfg -c init -c reset\ halt -c flash\ erase_address\ 0x80C0000\ 0x40000 -c reset\ run -c exit
$(OPENOCD) -c init -c reset\ halt -c flash\ erase_address\ 0x80C0000\ 0x40000 -c reset\ init -c reset\ run -c exit
# The one-time programmable memory stores the board version
# has the following format:
@@ -46,9 +58,9 @@ erase_config:
# FLASH_CR = (1 << FLASH_CR_PG); // unlock flash memory
# [write OTP]
write_otp:
ifeq ($(ODRV_FACTORY),TRUE)
ifeq ($(OTP_CONFIRM),TRUE)
# Data:
openocd -f interface/stlink-v2.cfg -f target/stm32f4x.cfg \
$(OPENOCD) \
-c init \
-c 'reset halt' \
-c 'mww 0x40023C04 0x45670123' \
@@ -72,7 +84,7 @@ else
@echo " 1. open the Makefile and look at the write_otp target"
@echo " 2. understand the structure of the OTP"
@echo " 3. edit the bytes that are written to match your board version"
@echo "Run this command again, this time with ODRV_FACTORY=TRUE appended"
@echo "Run this command again, this time with OTP_CONFIRM=TRUE appended"
@echo "to the command in the terminal"
endif
+71 -70
View File
@@ -25,6 +25,10 @@ Axis::Axis(const AxisHardwareConfig_t& hw_config,
motor_.axis_ = this;
}
static void step_cb_wrapper(void* ctx) {
reinterpret_cast<Axis*>(ctx)->step_cb();
}
// @brief Sets up all components of the axis,
// such as gate driver and encoder hardware.
void Axis::setup() {
@@ -34,6 +38,7 @@ void Axis::setup() {
static void run_state_machine_loop_wrapper(void* ctx) {
reinterpret_cast<Axis*>(ctx)->run_state_machine_loop();
reinterpret_cast<Axis*>(ctx)->thread_id_valid_ = false;
}
// @brief Starts run_state_machine_loop in a new thread
@@ -56,10 +61,6 @@ bool Axis::wait_for_current_meas() {
return osSignalWait(M_SIGNAL_PH_CURRENT_MEAS, PH_CURRENT_MEAS_TIMEOUT).status == osEventSignal;
}
static void step_cb_wrapper(void* ctx) {
reinterpret_cast<Axis*>(ctx)->step_cb();
}
// step/direction interface
void Axis::step_cb() {
if (enable_step_dir_) {
@@ -92,16 +93,34 @@ void Axis::set_step_dir_enabled(bool enable) {
}
}
// @brief Returns true if everything is ok.
// Sets error and returns false otherwise.
// @brief Do axis level checks and call subcomponent do_checks
// Returns true if everything is ok.
bool Axis::do_checks() {
if (!motor_.do_checks())
return error_ |= ERROR_MOTOR_FAILED, false;
if (!brake_resistor_armed)
error_ |= ERROR_BRAKE_RESISTOR_DISARMED;
if ((current_state_ != AXIS_STATE_IDLE) && (motor_.armed_state_ == Motor::ARMED_STATE_DISARMED))
// motor got disarmed in something other than the idle loop
error_ |= ERROR_MOTOR_DISARMED;
if (!(vbus_voltage >= board_config.dc_bus_undervoltage_trip_level))
return error_ |= ERROR_DC_BUS_UNDER_VOLTAGE, false;
error_ |= ERROR_DC_BUS_UNDER_VOLTAGE;
if (!(vbus_voltage <= board_config.dc_bus_overvoltage_trip_level))
return error_ |= ERROR_DC_BUS_OVER_VOLTAGE, false;
return true;
error_ |= ERROR_DC_BUS_OVER_VOLTAGE;
// Sub-components should use set_error which will propegate to this error_
motor_.do_checks();
encoder_.do_checks();
// sensorless_estimator_.do_checks();
// controller_.do_checks();
return error_ == ERROR_NONE;
}
// @brief Update all esitmators
bool Axis::do_updates() {
// Sub-components should use set_error which will propegate to this error_
encoder_.update();
sensorless_estimator_.update();
return error_ == ERROR_NONE;
}
bool Axis::run_sensorless_spin_up() {
@@ -115,7 +134,7 @@ bool Axis::run_sensorless_spin_up() {
return error_ |= ERROR_MOTOR_FAILED, false;
return x < 1.0f;
});
if (error_ != ERROR_NO_ERROR)
if (error_ != ERROR_NONE)
return false;
// Late Spin-up: accelerate
@@ -129,49 +148,41 @@ bool Axis::run_sensorless_spin_up() {
return error_ |= ERROR_MOTOR_FAILED, false;
return vel < config_.spin_up_target_vel;
});
return error_ == ERROR_NO_ERROR;
return error_ == ERROR_NONE;
}
// Note run_sensorless_control_loop and run_closed_loop_control_loop are very similar and differ only in where we get the estimate from.
bool Axis::run_sensorless_control_loop() {
set_step_dir_enabled(config_.enable_step_dir);
run_control_loop([this](){
float pos_estimate, vel_estimate, phase, current_setpoint;
if (controller_.config_.control_mode >= CTRL_MODE_POSITION_CONTROL)
return error_ |= ERROR_POS_CTRL_DURING_SENSORLESS, false;
// We update the encoder just in case someone needs the output for testing
encoder_.update(nullptr, nullptr, nullptr);
if (!sensorless_estimator_.update(&pos_estimate, &vel_estimate, &phase))
return error_ |= ERROR_SENSORLESS_ESTIMATOR_FAILED, false;
if (!controller_.update(pos_estimate, vel_estimate, &current_setpoint))
// Note that all estimators are updated in the loop prefix in run_control_loop
float current_setpoint;
if (!controller_.update(sensorless_estimator_.pll_pos_, sensorless_estimator_.pll_vel_, &current_setpoint))
return error_ |= ERROR_CONTROLLER_FAILED, false;
if (!motor_.update(current_setpoint, phase))
return error_ |= ERROR_MOTOR_FAILED, false;
if (!motor_.update(current_setpoint, sensorless_estimator_.phase_))
return false; // set_error should update axis.error_
return true;
});
set_step_dir_enabled(false);
return error_ == ERROR_NO_ERROR;
return error_ == ERROR_NONE;
}
bool Axis::run_closed_loop_control_loop() {
set_step_dir_enabled(config_.enable_step_dir);
run_control_loop([this](){
float pos_estimate, vel_estimate, phase, current_setpoint;
// We update the sensorless estimator just in case someone needs the output for testing
sensorless_estimator_.update(nullptr, nullptr, nullptr);
if (!encoder_.update(&pos_estimate, &vel_estimate, &phase))
return error_ |= ERROR_ENCODER_FAILED, false;
if (!controller_.update(pos_estimate, vel_estimate, &current_setpoint))
return error_ |= ERROR_CONTROLLER_FAILED, false;
if (!motor_.update(current_setpoint, phase))
return error_ |= ERROR_MOTOR_FAILED, false;
// Note that all estimators are updated in the loop prefix in run_control_loop
float current_setpoint;
if (!controller_.update(encoder_.pos_estimate_, encoder_.pll_vel_, &current_setpoint))
return error_ |= ERROR_CONTROLLER_FAILED, false; //TODO: Make controller.set_error
if (!motor_.update(current_setpoint, encoder_.phase_))
return false; // set_error should update axis.error_
return true;
});
set_step_dir_enabled(false);
return error_ == ERROR_NO_ERROR;
return error_ == ERROR_NONE;
}
bool Axis::run_idle_loop() {
@@ -179,11 +190,9 @@ bool Axis::run_idle_loop() {
// if and only if we're in AXIS_STATE_IDLE
safety_critical_disarm_motor_pwm(motor_);
run_control_loop([this](){
sensorless_estimator_.update(nullptr, nullptr, nullptr);
encoder_.update(nullptr, nullptr, nullptr);
return true;
});
return error_ == ERROR_NO_ERROR;
return error_ == ERROR_NONE;
}
// Infinite loop that does calibration and enters main control loop as appropriate
@@ -246,43 +255,37 @@ void Axis::run_state_machine_loop() {
// Handlers should exit if requested_state != AXIS_STATE_UNDEFINED
bool status;
switch (current_state_) {
case AXIS_STATE_MOTOR_CALIBRATION:
status = motor_.run_calibration();
if (!status)
error_ |= ERROR_MOTOR_FAILED;
break;
case AXIS_STATE_MOTOR_CALIBRATION:
status = motor_.run_calibration();
break;
case AXIS_STATE_ENCODER_INDEX_SEARCH:
status = encoder_.run_index_search();
if (!status)
error_ |= ERROR_ENCODER_FAILED;
break;
case AXIS_STATE_ENCODER_INDEX_SEARCH:
status = encoder_.run_index_search();
break;
case AXIS_STATE_ENCODER_OFFSET_CALIBRATION:
status = encoder_.run_offset_calibration();
if (!status)
error_ |= ERROR_ENCODER_FAILED;
break;
case AXIS_STATE_ENCODER_OFFSET_CALIBRATION:
status = encoder_.run_offset_calibration();
break;
case AXIS_STATE_SENSORLESS_CONTROL:
status = run_sensorless_spin_up(); // TODO: restart if desired
if (status)
status = run_sensorless_control_loop();
break;
case AXIS_STATE_SENSORLESS_CONTROL:
status = run_sensorless_spin_up(); // TODO: restart if desired
if (status)
status = run_sensorless_control_loop();
break;
case AXIS_STATE_CLOSED_LOOP_CONTROL:
status = run_closed_loop_control_loop();
break;
case AXIS_STATE_CLOSED_LOOP_CONTROL:
status = run_closed_loop_control_loop();
break;
case AXIS_STATE_IDLE:
run_idle_loop();
status = motor_.arm(); // done with idling - try to arm the motor
break;
case AXIS_STATE_IDLE:
run_idle_loop();
status = motor_.arm(); // done with idling - try to arm the motor
break;
default:
error_ |= ERROR_INVALID_STATE;
status = false; // this will set the state to idle
break;
default:
error_ |= ERROR_INVALID_STATE;
status = false; // this will set the state to idle
break;
}
// If the state failed, go to idle, else advance task chain
@@ -291,6 +294,4 @@ void Axis::run_state_machine_loop() {
else
memcpy(task_chain_, task_chain_ + 1, sizeof(task_chain_) - sizeof(task_chain_[0]));
}
thread_id_valid_ = false;
}
+12 -19
View File
@@ -26,7 +26,7 @@ struct AxisConfig_t {
bool startup_encoder_offset_calibration = false; //<! run encoder offset calibration after startup, skip otherwise
bool startup_closed_loop_control = false; //<! enable closed loop control after calibration/startup
bool startup_sensorless_control = false; //<! enable sensorless control after calibration/startup
bool enable_step_dir = true; //<! enable step/dir input after calibration
bool enable_step_dir = false; //<! enable step/dir input after calibration
// For M0 this has no effect if enable_uart is true
float counts_per_step = 2.0f;
@@ -42,7 +42,7 @@ struct AxisConfig_t {
class Axis {
public:
enum Error_t {
ERROR_NO_ERROR = 0x00,
ERROR_NONE = 0x00,
ERROR_INVALID_STATE = 0x01, //<! an invalid state was requested
ERROR_DC_BUS_UNDER_VOLTAGE = 0x02,
ERROR_DC_BUS_OVER_VOLTAGE = 0x04,
@@ -78,6 +78,7 @@ public:
bool check_DRV_fault();
bool check_PSU_brownout();
bool do_checks();
bool do_updates();
// @brief Runs the specified update handler at the frequency of the current measurements.
//
@@ -102,25 +103,14 @@ public:
template<typename T>
void run_control_loop(const T& update_handler) {
while (requested_state_ == AXIS_STATE_UNDEFINED) {
if (!brake_resistor_armed_) {
error_ |= ERROR_BRAKE_RESISTOR_DISARMED;
if (!do_checks()) // look for errors at axis level and also all subcomponents
break;
}
if ((current_state_ != AXIS_STATE_IDLE) && (motor_.armed_state_ == Motor::ARMED_STATE_DISARMED)) {
// motor got disarmed in something other than the idle loop
error_ |= ERROR_MOTOR_DISARMED;
break;
}
if (motor_.error_ != Motor::ERROR_NO_ERROR) {
error_ |= ERROR_MOTOR_FAILED;
break;
}
if (!do_checks()) // error set during function call
if (!do_updates()) // Update all estimators
break;
if (!update_handler()) // error set during function call
break;
// Run main loop function, defer quitting for after wait
// TODO: change arming logic to arm after waiting
bool main_continue = update_handler();
// Check we meet deadlines after queueing
++loop_counter_;
@@ -134,6 +124,9 @@ public:
error_ |= ERROR_CURRENT_MEASUREMENT_TIMEOUT;
break;
}
if (!main_continue)
break;
}
}
@@ -156,7 +149,7 @@ public:
volatile bool thread_id_valid_ = false;
// variables exposed on protocol
Error_t error_ = ERROR_NO_ERROR;
Error_t error_ = ERROR_NONE;
bool enable_step_dir_ = false; // auto enabled after calibration, based on config.enable_step_dir
AxisState_t requested_state_ = AXIS_STATE_STARTUP_SEQUENCE;
AxisState_t task_chain_[10] = { AXIS_STATE_UNDEFINED };
+27
View File
@@ -32,6 +32,12 @@ typedef struct {
TIM_HandleTypeDef* timer;
GPIO_TypeDef* index_port;
uint16_t index_pin;
GPIO_TypeDef* hallA_port;
uint16_t hallA_pin;
GPIO_TypeDef* hallB_port;
uint16_t hallB_pin;
GPIO_TypeDef* hallC_port;
uint16_t hallC_pin;
} EncoderHardwareConfig_t;
typedef struct {
TIM_HandleTypeDef* timer;
@@ -56,6 +62,7 @@ typedef struct {
extern const BoardHardwareConfig_t hw_configs[2];
//TODO stick this in a C file
#ifdef __MAIN_CPP__
const BoardHardwareConfig_t hw_configs[2] = { {
.axis_config = {
@@ -69,6 +76,12 @@ const BoardHardwareConfig_t hw_configs[2] = { {
.timer = &htim3,
.index_port = M0_ENC_Z_GPIO_Port,
.index_pin = M0_ENC_Z_Pin,
.hallA_port = M0_ENC_A_GPIO_Port,
.hallA_pin = M0_ENC_A_Pin,
.hallB_port = M0_ENC_B_GPIO_Port,
.hallB_pin = M0_ENC_B_Pin,
.hallC_port = M0_ENC_Z_GPIO_Port,
.hallC_pin = M0_ENC_Z_Pin,
},
.motor_config = {
.timer = &htim1,
@@ -97,6 +110,12 @@ const BoardHardwareConfig_t hw_configs[2] = { {
.timer = &htim4,
.index_port = M1_ENC_Z_GPIO_Port,
.index_pin = M1_ENC_Z_Pin,
.hallA_port = M1_ENC_A_GPIO_Port,
.hallA_pin = M1_ENC_A_Pin,
.hallB_port = M1_ENC_B_GPIO_Port,
.hallB_pin = M1_ENC_B_Pin,
.hallC_port = M1_ENC_Z_GPIO_Port,
.hallC_pin = M1_ENC_Z_Pin,
},
.motor_config = {
.timer = &htim8,
@@ -117,4 +136,12 @@ const BoardHardwareConfig_t hw_configs[2] = { {
#endif
#define I2C_A0_PORT GPIO_3_GPIO_Port
#define I2C_A0_PIN GPIO_3_Pin
#define I2C_A1_PORT GPIO_4_GPIO_Port
#define I2C_A1_PIN GPIO_4_Pin
#define I2C_A2_PORT GPIO_5_GPIO_Port
#define I2C_A2_PIN GPIO_5_Pin
#endif // __BOARD_CONFIG_H
+8 -1
View File
@@ -6,6 +6,13 @@ Controller::Controller(ControllerConfig_t& config) :
config_(config)
{}
void Controller::reset() {
pos_setpoint_ = 0.0f;
vel_setpoint_ = 0.0f;
vel_integrator_current_ = 0.0f;
current_setpoint_ = 0.0f;
}
//--------------------------------
// Command Handling
//--------------------------------
@@ -39,7 +46,7 @@ void Controller::set_current_setpoint(float current_setpoint) {
void Controller::start_anticogging_calibration() {
// Ensure the cogging map was correctly allocated earlier and that the motor is capable of calibrating
if (anticogging_.cogging_map != NULL && axis_->error_ == Axis::ERROR_NO_ERROR) {
if (anticogging_.cogging_map != NULL && axis_->error_ == Axis::ERROR_NONE) {
anticogging_.calib_anticogging = true;
}
}
+2 -1
View File
@@ -18,7 +18,7 @@ struct ControllerConfig_t {
Motor_control_mode_t control_mode = CTRL_MODE_POSITION_CONTROL; //see: Motor_control_mode_t
float pos_gain = 20.0f; // [(counts/s) / counts]
float vel_gain = 5.0f / 10000.0f; // [A/(counts/s)]
// float vel_gain = 15.0f / 200.0f, // [A/(rad/s)] <sensorless example>
// float vel_gain = 5.0f / 200.0f, // [A/(rad/s)] <sensorless example>
float vel_integrator_gain = 10.0f / 10000.0f; // [A/(counts/s * s)]
float vel_limit = 20000.0f; // [counts/s]
};
@@ -26,6 +26,7 @@ struct ControllerConfig_t {
class Controller {
public:
Controller(ControllerConfig_t& config);
void reset();
void set_pos_setpoint(float pos_setpoint, float vel_feed_forward, float current_feed_forward);
void set_vel_setpoint(float vel_setpoint, float current_feed_forward);
+142 -44
View File
@@ -3,7 +3,7 @@
Encoder::Encoder(const EncoderHardwareConfig_t& hw_config,
EncoderConfig_t& config) :
Config_t& config) :
hw_config_(hw_config),
config_(config)
{
@@ -14,6 +14,11 @@ Encoder::Encoder(const EncoderHardwareConfig_t& hw_config,
// Critically damped
pll_ki_ = 0.25f * (pll_kp_ * pll_kp_);
if (config.pre_calibrated && (config.mode == Encoder::MODE_HALL)) {
offset_ = config.offset;
is_ready_ = true;
}
}
static void enc_index_cb_wrapper(void* ctx) {
@@ -26,6 +31,15 @@ void Encoder::setup() {
enc_index_cb_wrapper, this);
}
void Encoder::set_error(Encoder::Error_t error) {
error_ |= error;
axis_->error_ |= Axis::ERROR_MOTOR_FAILED;
}
bool Encoder::do_checks(){
return error_ == ERROR_NONE;
}
//--------------------
// Hardware Dependent
//--------------------
@@ -35,7 +49,7 @@ void Encoder::setup() {
// TODO: disable interrupt once we found the index
void Encoder::enc_index_cb() {
if (config_.use_index && !index_found_) {
set_count(0);
set_circular_count(0);
if (config_.pre_calibrated) {
offset_ = config_.offset;
is_ready_ = true;
@@ -45,15 +59,34 @@ void Encoder::enc_index_cb() {
}
// Function that sets the current encoder count to a desired 32-bit value.
void Encoder::set_count(int32_t count) {
void Encoder::set_linear_count(int32_t count) {
// Disable interrupts to make a critical section to avoid race condition
uint32_t prim = __get_PRIMASK();
__disable_irq();
// Offset and state must be shifted by the same amount
offset_ += count - state_;
state_ = count;
// Update states
shadow_count_ = count;
pos_estimate_ = (float)count;
//Write hardware last
hw_config_.timer->Instance->CNT = count;
pll_pos_ = (float)count;
__set_PRIMASK(prim);
}
// Function that sets the CPR circular tracking encoder count to a desired 32-bit value.
// Note that this will get mod'ed down to [0, cpr)
void Encoder::set_circular_count(int32_t count) {
// Disable interrupts to make a critical section to avoid race condition
uint32_t prim = __get_PRIMASK();
__disable_irq();
// Offset and state must be shifted by the same amount
offset_ += count - count_in_cpr_;
offset_ = mod(offset_, config_.cpr);
// Update states
count_in_cpr_ = mod(count, config_.cpr);
pos_cpr_ = (float)count_in_cpr_;
__set_PRIMASK(prim);
}
@@ -86,7 +119,7 @@ bool Encoder::run_index_search() {
// continue until the index is found
return !index_found_;
});
return axis_->error_ != Axis::ERROR_NO_ERROR;
return true;
}
// @brief Turns the motor in one direction for a bit and then in the other
@@ -97,7 +130,7 @@ bool Encoder::run_offset_calibration() {
static const float start_lock_duration = 1.0f;
static const float scan_omega = 4.0f * M_PI;
static const float scan_distance = 16.0f * M_PI;
static const int num_steps = scan_distance / scan_omega * current_meas_hz;
static const int num_steps = (int)(scan_distance / scan_omega * (float)current_meas_hz);
// Temporarily disable index search so it doesn't mess
// with the offset calibration
@@ -120,10 +153,10 @@ bool Encoder::run_offset_calibration() {
axis_->motor_.log_timing(Motor::TIMING_LOG_ENC_CALIB);
return ++i < start_lock_duration * current_meas_hz;
});
if (axis_->error_ != Axis::ERROR_NO_ERROR)
if (axis_->error_ != Axis::ERROR_NONE)
return false;
int32_t init_enc_val = (int16_t)hw_config_.timer->Instance->CNT;
int32_t init_enc_val = shadow_count_;
int64_t encvaluesum = 0;
// scan forward
@@ -136,32 +169,32 @@ bool Encoder::run_offset_calibration() {
return false; // error set inside enqueue_voltage_timings
axis_->motor_.log_timing(Motor::TIMING_LOG_ENC_CALIB);
encvaluesum += (int16_t)hw_config_.timer->Instance->CNT;
encvaluesum += shadow_count_;
return ++i < num_steps;
});
if (axis_->error_ != Axis::ERROR_NO_ERROR)
if (axis_->error_ != Axis::ERROR_NONE)
return false;
//TODO avoid recomputing elec_rad_per_enc every time
float elec_rad_per_enc = axis_->motor_.config_.pole_pairs * 2 * M_PI * (1.0f / (float)(config_.cpr));
float expected_encoder_delta = scan_distance / elec_rad_per_enc;
float actual_encoder_delta_abs = fabsf((int16_t)hw_config_.timer->Instance->CNT-init_enc_val);
float actual_encoder_delta_abs = fabsf(shadow_count_-init_enc_val);
if(fabsf(actual_encoder_delta_abs - expected_encoder_delta)/expected_encoder_delta > config_.calib_range)
{
error_ |= ERROR_CPR_OUT_OF_RANGE;
set_error(ERROR_CPR_OUT_OF_RANGE);
return false;
}
// check direction
if ((int16_t)hw_config_.timer->Instance->CNT > init_enc_val + 8) {
if (shadow_count_ > init_enc_val + 8) {
// motor same dir as encoder
axis_->motor_.config_.direction = 1;
} else if ((int16_t)hw_config_.timer->Instance->CNT < init_enc_val - 8) {
} else if (shadow_count_ < init_enc_val - 8) {
// motor opposite dir as encoder
axis_->motor_.config_.direction = -1;
} else {
// Encoder response error
error_ |= ERROR_RESPONSE;
set_error(ERROR_RESPONSE);
return false;
}
@@ -175,53 +208,118 @@ bool Encoder::run_offset_calibration() {
return false; // error set inside enqueue_voltage_timings
axis_->motor_.log_timing(Motor::TIMING_LOG_ENC_CALIB);
encvaluesum += (int16_t)hw_config_.timer->Instance->CNT;
encvaluesum += shadow_count_;
return ++i < num_steps;
});
if (axis_->error_ != Axis::ERROR_NO_ERROR)
if (axis_->error_ != Axis::ERROR_NONE)
return false;
offset_ = encvaluesum / (num_steps * 2);
config_.offset = offset_;
int32_t residual = encvaluesum - ((int64_t)offset_ * (int64_t)(num_steps * 2));
config_.offset_float = (float)residual / (float)(num_steps * 2) + 0.5f; // add 0.5 to center-align state to phase
is_ready_ = true;
config_.use_index = old_use_index;
return true;
}
bool Encoder::update(float* pos_estimate, float* vel_estimate, float* phase_output) {
static bool decode_hall(uint8_t hall_state, int32_t* hall_cnt) {
switch (hall_state) {
case 0b001: *hall_cnt = 0; return true;
case 0b011: *hall_cnt = 1; return true;
case 0b010: *hall_cnt = 2; return true;
case 0b110: *hall_cnt = 3; return true;
case 0b100: *hall_cnt = 4; return true;
case 0b101: *hall_cnt = 5; return true;
default: return false;
}
}
bool Encoder::update() {
// Check that we don't get problems with discrete time approximation
if (!(current_meas_period * pll_kp_ < 1.0f)) {
error_ |= ERROR_NUMERICAL;
set_error(ERROR_UNSTABLE_GAIN);
return false;
}
// update internal encoder state
int16_t delta_enc = (int16_t)hw_config_.timer->Instance->CNT - (int16_t)state_;
state_ += (int32_t)delta_enc;
// update internal encoder state.
int32_t delta_enc = 0;
switch (config_.mode) {
case MODE_INCREMENTAL: {
//TODO: use count_in_cpr_ instead as shadow_count_ can overflow
//or use 64 bit
int16_t delta_enc_16 = (int16_t)hw_config_.timer->Instance->CNT - (int16_t)shadow_count_;
delta_enc = (int32_t)delta_enc_16; //sign extend
} break;
// compute electrical phase
int corrected_enc = state_ % config_.cpr;
corrected_enc -= offset_;
//corrected_enc *= axis_->motor_.config_.direction; TODO: verify if this still works
case MODE_HALL: {
int32_t hall_cnt;
if (decode_hall(hall_state_, &hall_cnt)) {
delta_enc = hall_cnt - count_in_cpr_;
delta_enc = mod(delta_enc, 6);
if (delta_enc > 3)
delta_enc -= 6;
} else {
set_error(ERROR_ILLEGAL_HALL_STATE);
return false;
}
} break;
default: {
set_error(ERROR_UNSUPPORTED_ENCODER_MODE);
return false;
} break;
}
shadow_count_ += delta_enc;
count_in_cpr_ += delta_enc;
count_in_cpr_ = mod(count_in_cpr_, config_.cpr);
//// run pll (for now pll is in units of encoder counts)
// Predict current pos
pos_estimate_ += current_meas_period * pll_vel_;
pos_cpr_ += current_meas_period * pll_vel_;
// discrete phase detector
float delta_pos = (float)(shadow_count_ - (int32_t)floorf(pos_estimate_));
float delta_pos_cpr = (float)(count_in_cpr_ - (int32_t)floorf(pos_cpr_));
delta_pos_cpr = wrap_pm(delta_pos_cpr, 0.5f * (float)(config_.cpr));
// pll feedback
pos_estimate_ += current_meas_period * pll_kp_ * delta_pos;
pos_cpr_ += current_meas_period * pll_kp_ * delta_pos_cpr;
pos_cpr_ = fmodf_pos(pos_cpr_, (float)(config_.cpr));
pll_vel_ += current_meas_period * pll_ki_ * delta_pos_cpr;
bool snap_to_zero_vel = false;
if (fabsf(pll_vel_) < 0.5f * current_meas_period * pll_ki_) {
pll_vel_ = 0.0f; //align delta-sigma on zero to prevent jitter
snap_to_zero_vel = true;
}
//// run encoder count interpolation
int32_t corrected_enc = count_in_cpr_ - offset_;
// if we are stopped, make sure we don't randomly drift
if (snap_to_zero_vel) {
interpolation_ = 0.5f;
// reset interpolation if encoder edge comes
} else if (delta_enc > 0) {
interpolation_ = 0.0f;
} else if (delta_enc < 0) {
interpolation_ = 1.0f;
} else {
// Interpolate (predict) between encoder counts using pll_vel,
interpolation_ += current_meas_period * pll_vel_;
// don't allow interpolation indicated position outside of [enc, enc+1)
if (interpolation_ > 1.0f) interpolation_ = 1.0f;
if (interpolation_ < 0.0f) interpolation_ = 0.0f;
}
float interpolated_enc = corrected_enc + interpolation_;
//// compute electrical phase
//TODO avoid recomputing elec_rad_per_enc every time
float elec_rad_per_enc = axis_->motor_.config_.pole_pairs * 2 * M_PI * (1.0f / (float)(config_.cpr));
float ph = elec_rad_per_enc * (float)corrected_enc;
float ph = elec_rad_per_enc * (interpolated_enc - config_.offset_float);
// ph = fmodf(ph, 2*M_PI);
phase_ = wrap_pm_pi(ph);
// run pll (for now pll is in units of encoder counts)
// TODO pll_pos runs out of precision very quickly here! Perhaps decompose into integer and fractional part?
// Predict current pos
pll_pos_ += current_meas_period * pll_vel_;
// discrete phase detector
float delta_pos = (float)(state_ - (int32_t)floorf(pll_pos_));
// pll feedback
pll_pos_ += current_meas_period * pll_kp_ * delta_pos;
pll_vel_ += current_meas_period * pll_ki_ * delta_pos;
// Assign output arguments
if (pos_estimate) *pos_estimate = pll_pos_;
if (vel_estimate) *vel_estimate = pll_vel_;
if (phase_output) *phase_output = phase_;
return true;
}

Some files were not shown because too many files have changed in this diff Show More