mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-08-20 22:14:34 +08:00
Merge branch 'devel' into sam_can
This commit is contained in:
-28
@@ -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
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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>© 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>© 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****/
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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****/
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
/*---------- -----------*/
|
||||
|
||||
@@ -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 */
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
+282
-195
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
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
/**
|
||||
|
||||
@@ -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****/
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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****/
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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, ¤t_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_, ¤t_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, ¤t_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_, ¤t_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;
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user