refactor drv8301 driver

This commit is contained in:
Samuel Sadok
2020-07-21 12:31:03 +02:00
parent 8b3a290522
commit 856455077d
34 changed files with 1330 additions and 1887 deletions
@@ -10,6 +10,9 @@
#include <spi.h> #include <spi.h>
#include <tim.h> #include <tim.h>
#include <main.h> #include <main.h>
#include "cmsis_os.h"
#include <arm_math.h>
#if HW_VERSION_MAJOR == 3 #if HW_VERSION_MAJOR == 3
#if HW_VERSION_MINOR <= 3 #if HW_VERSION_MINOR <= 3
@@ -20,6 +23,29 @@
#endif #endif
#ifdef __cplusplus
#include <Drivers/STM32/stm32_gpio.hpp>
#include <Drivers/DRV8301/drv8301.hpp>
#include <MotorControl/thermistor.hpp>
using TGateDriver = Drv8301;
using TOpAmp = Drv8301;
#include <MotorControl/motor.hpp>
extern Motor m0;
extern Motor m1;
extern OnboardThermistorCurrentLimiter m0_fet_thermistor;
extern OnboardThermistorCurrentLimiter m1_fet_thermistor;
#endif
// Period in [s]
static const float current_meas_period = CURRENT_MEAS_PERIOD;
// Frequency in [Hz]
static const int current_meas_hz = CURRENT_MEAS_HZ;
typedef struct { typedef struct {
uint16_t step_gpio_pin; uint16_t step_gpio_pin;
uint16_t dir_gpio_pin; uint16_t dir_gpio_pin;
@@ -38,16 +64,6 @@ typedef struct {
uint16_t hallC_pin; uint16_t hallC_pin;
SPI_HandleTypeDef* spi; SPI_HandleTypeDef* spi;
} EncoderHardwareConfig_t; } EncoderHardwareConfig_t;
typedef struct {
TIM_HandleTypeDef* timer;
uint16_t control_deadline;
float shunt_conductance;
} MotorHardwareConfig_t;
typedef struct {
const float* const coeffs;
size_t num_coeffs;
size_t adc_ch;
} ThermistorHardwareConfig_t;
typedef struct { typedef struct {
SPI_HandleTypeDef* spi; SPI_HandleTypeDef* spi;
GPIO_TypeDef* enable_port; GPIO_TypeDef* enable_port;
@@ -60,18 +76,12 @@ typedef struct {
typedef struct { typedef struct {
AxisHardwareConfig_t axis_config; AxisHardwareConfig_t axis_config;
EncoderHardwareConfig_t encoder_config; EncoderHardwareConfig_t encoder_config;
MotorHardwareConfig_t motor_config;
ThermistorHardwareConfig_t thermistor_config;
GateDriverHardwareConfig_t gate_driver_config;
} BoardHardwareConfig_t; } BoardHardwareConfig_t;
extern const BoardHardwareConfig_t hw_configs[2]; extern const BoardHardwareConfig_t hw_configs[2];
//TODO stick this in a C file //TODO stick this in a C file
#ifdef __MAIN_CPP__ #ifdef __MAIN_CPP__
const float fet_thermistor_poly_coeffs[] =
{363.93910201f, -462.15369634f, 307.55129571f, -27.72569531f};
const size_t fet_thermistor_num_coeffs = sizeof(fet_thermistor_poly_coeffs)/sizeof(fet_thermistor_poly_coeffs[1]);
const BoardHardwareConfig_t hw_configs[2] = { { const BoardHardwareConfig_t hw_configs[2] = { {
//M0 //M0
@@ -92,26 +102,6 @@ const BoardHardwareConfig_t hw_configs[2] = { {
.hallC_pin = M0_ENC_Z_Pin, .hallC_pin = M0_ENC_Z_Pin,
.spi = &hspi3, .spi = &hspi3,
}, },
.motor_config = {
.timer = &htim1,
.control_deadline = TIM_1_8_PERIOD_CLOCKS,
.shunt_conductance = 1.0f / SHUNT_RESISTANCE, //[S]
},
.thermistor_config = {
.coeffs = &fet_thermistor_poly_coeffs[0],
.num_coeffs = fet_thermistor_num_coeffs,
.adc_ch = 15,
},
.gate_driver_config = {
.spi = &hspi3,
// Note: this board has the EN_Gate pin shared!
.enable_port = EN_GATE_GPIO_Port,
.enable_pin = EN_GATE_Pin,
.nCS_port = M0_nCS_GPIO_Port,
.nCS_pin = M0_nCS_Pin,
.nFAULT_port = nFAULT_GPIO_Port, // the nFAULT pin is shared between both motors
.nFAULT_pin = nFAULT_Pin,
}
},{ },{
//M1 //M1
.axis_config = { .axis_config = {
@@ -136,35 +126,9 @@ const BoardHardwareConfig_t hw_configs[2] = { {
.hallC_pin = M1_ENC_Z_Pin, .hallC_pin = M1_ENC_Z_Pin,
.spi = &hspi3, .spi = &hspi3,
}, },
.motor_config = {
.timer = &htim8,
.control_deadline = (3 * TIM_1_8_PERIOD_CLOCKS) / 2,
.shunt_conductance = 1.0f / SHUNT_RESISTANCE, //[S]
},
.thermistor_config = {
.coeffs = &fet_thermistor_poly_coeffs[0],
.num_coeffs = fet_thermistor_num_coeffs,
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR >= 3
.adc_ch = 4,
#else
.adc_ch = 1,
#endif
},
.gate_driver_config = {
.spi = &hspi3,
// Note: this board has the EN_Gate pin shared!
.enable_port = EN_GATE_GPIO_Port,
.enable_pin = EN_GATE_Pin,
.nCS_port = M1_nCS_GPIO_Port,
.nCS_pin = M1_nCS_Pin,
.nFAULT_port = nFAULT_GPIO_Port, // the nFAULT pin is shared between both motors
.nFAULT_pin = nFAULT_Pin,
}
} }; } };
#endif #endif
#define I2C_A0_PORT GPIO_3_GPIO_Port #define I2C_A0_PORT GPIO_3_GPIO_Port
#define I2C_A0_PIN GPIO_3_Pin #define I2C_A0_PIN GPIO_3_Pin
#define I2C_A1_PORT GPIO_4_GPIO_Port #define I2C_A1_PORT GPIO_4_GPIO_Port
+72
View File
@@ -0,0 +1,72 @@
/*
* @brief Contains board specific variables and initialization functions
*/
#include <board.h>
Stm32SpiArbiter spi3_arbiter{&hspi3};
Drv8301 m0_gate_driver{
&spi3_arbiter,
{M0_nCS_GPIO_Port, M0_nCS_Pin}, // nCS
{EN_GATE_GPIO_Port, EN_GATE_Pin}, // EN pin (shared between both motors)
{nFAULT_GPIO_Port, nFAULT_Pin} // nFAULT pin (shared between both motors)
};
Drv8301 m1_gate_driver{
&spi3_arbiter,
{M1_nCS_GPIO_Port, M1_nCS_Pin}, // nCS
{EN_GATE_GPIO_Port, EN_GATE_Pin}, // EN pin (shared between both motors)
{nFAULT_GPIO_Port, nFAULT_Pin} // nFAULT pin (shared between both motors)
};
const float fet_thermistor_poly_coeffs[] =
{363.93910201f, -462.15369634f, 307.55129571f, -27.72569531f};
const size_t fet_thermistor_num_coeffs = sizeof(fet_thermistor_poly_coeffs)/sizeof(fet_thermistor_poly_coeffs[1]);
OnboardThermistorCurrentLimiter m0_fet_thermistor{
15, // adc_channel
&fet_thermistor_poly_coeffs[0], // coefficients
fet_thermistor_num_coeffs // num_coeffs
};
OnboardThermistorCurrentLimiter m1_fet_thermistor{
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR >= 3
4, // adc_channel
#else
1, // adc_channel
#endif
&fet_thermistor_poly_coeffs[0], // coefficients
fet_thermistor_num_coeffs // num_coeffs
};
Motor m0{
&htim1, // timer
TIM_1_8_PERIOD_CLOCKS, // control_deadline
1.0f / SHUNT_RESISTANCE, // shunt_conductance [S]
m0_gate_driver, // gate_driver
m0_gate_driver // opamp
};
Motor m1{
&htim8, // timer
(3 * TIM_1_8_PERIOD_CLOCKS) / 2, // control_deadline
1.0f / SHUNT_RESISTANCE, // shunt_conductance [S]
m1_gate_driver, // gate_driver
m1_gate_driver // opamp
};
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) {
HAL_SPI_TxRxCpltCallback(hspi);
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) {
HAL_SPI_TxRxCpltCallback(hspi);
}
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
if (hspi == &hspi3) {
spi3_arbiter.on_complete();
}
}
File diff suppressed because it is too large Load Diff
+276
View File
@@ -0,0 +1,276 @@
/* --COPYRIGHT--,BSD
* Copyright (c) 2015, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * 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.
*
* * Neither the name of Texas Instruments Incorporated 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 OWNER 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.
* --/COPYRIGHT--*/
//! \file drivers/drvic/drv8301/src/32b/f28x/f2806x/drv8301.c
//! \brief Contains the various functions related to the DRV8301 object
//!
//! (C) Copyright 2015, Texas Instruments, Inc.
// **************************************************************************
// the includes
#include "drv8301.hpp"
#include "utils.hpp"
#include "cmsis_os.h"
#include <math.h>
#include <array>
#include <algorithm>
const SPI_InitTypeDef Drv8301::spi_config_ = {
.Mode = SPI_MODE_MASTER,
.Direction = SPI_DIRECTION_2LINES,
.DataSize = SPI_DATASIZE_16BIT,
.CLKPolarity = SPI_POLARITY_LOW,
.CLKPhase = SPI_PHASE_2EDGE,
.NSS = SPI_NSS_SOFT,
.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16,
.FirstBit = SPI_FIRSTBIT_MSB,
.TIMode = SPI_TIMODE_DISABLE,
.CRCCalculation = SPI_CRCCALCULATION_DISABLE,
.CRCPolynomial = 10,
};
Drv8301::FaultType_e Drv8301::get_error() {
uint16_t readWord;
FaultType_e faultType = FaultType_NoFault;
// read the data
if (!read_spi(RegName_Status_1, &readWord)) {
return (FaultType_e)0xffff;
}
if (readWord & DRV8301_STATUS1_FAULT_BITS) {
faultType = (FaultType_e)(readWord & DRV8301_FAULT_TYPE_MASK);
if (faultType == FaultType_NoFault) {
// read the data
if (!read_spi(RegName_Status_2, &readWord)) {
return (FaultType_e)0xffff;
}
if (readWord & DRV8301_STATUS2_GVDD_OV_BITS) {
faultType = FaultType_GVDD_OV;
}
}
}
return faultType;
}
bool Drv8301::set_gain(float requested_gain, float* actual_gain) {
// for reference:
// 20V/V on 500uOhm gives a range of +/- 150A
// 40V/V on 500uOhm gives a range of +/- 75A
// 20V/V on 666uOhm gives a range of +/- 110A
// 40V/V on 666uOhm gives a range of +/- 55A
// Snap down to have equal or larger range as requested or largest possible range otherwise
// Decoding array for snapping gain
std::array<std::pair<float, ShuntAmpGain_e>, 4> gain_choices = {
std::make_pair(10.0f, ShuntAmpGain_10VpV),
std::make_pair(20.0f, ShuntAmpGain_20VpV),
std::make_pair(40.0f, ShuntAmpGain_40VpV),
std::make_pair(80.0f, ShuntAmpGain_80VpV)
};
// We use lower_bound in reverse because it snaps up by default, we want to snap down.
auto gain_snap_down = std::lower_bound(gain_choices.crbegin(), gain_choices.crend(), requested_gain,
[](std::pair<float, ShuntAmpGain_e> pair, float val){
return (bool)(pair.first > val);
});
// If we snap to outside the array, clip to smallest val
if (gain_snap_down == gain_choices.crend())
--gain_snap_down;
Registers_t regs;
if (!read_regs(&regs)) {
return false;
}
regs.Ctrl_Reg_1.OC_MODE = OcMode_LatchShutDown;
// Overcurrent set to approximately 150A at 100degC. This may need tweaking.
regs.Ctrl_Reg_1.OC_ADJ_SET = VdsLevel_0p730_V;
regs.Ctrl_Reg_2.GAIN = gain_snap_down->second;
if (!write_regs(&regs)) {
return false;
}
if (actual_gain) {
*actual_gain = gain_snap_down->first;
}
return true;
}
bool Drv8301::check_fault() {
if (nfault_gpio_) {
return nfault_gpio_.read();
} else {
return true;
}
}
bool Drv8301::set_enabled(bool enabled) {
enable_gpio_.write(enabled);
if (enabled) {
// Wait for driver to come online
osDelay(10);
// Make sure the Fault bit is not set during startup
uint16_t reg;
while (!read_spi(RegName_Status_1, &reg) || (reg & DRV8301_STATUS1_FAULT_BITS))
; // TODO: don't spin
// Wait for the DRV8301 registers to update
osDelay(1);
}
return true;
}
bool Drv8301::read_spi(const RegName_e regName, uint16_t* data) {
tx_buf_ = build_ctrl_word(DRV8301_CtrlMode_Read, regName, 0);
if (!spi_arbiter_->transfer(spi_config_, ncs_gpio_, (uint8_t *)(&tx_buf_), nullptr, 1, 1000)) {
return false;
}
// Datasheet says you don't have to pulse the nCS between transfers, (16
// clocks should commit the transfer) but for some reason you actually need
// to pulse it.
delay_us(1);
tx_buf_ = 0;
rx_buf_ = 0xbeef;
if (!spi_arbiter_->transfer(spi_config_, ncs_gpio_, (uint8_t *)(&tx_buf_), (uint8_t *)(&rx_buf_), 1, 1000)) {
return false;
}
delay_us(1);
if (rx_buf_ == 0xbeef) {
return false;
}
if (data) {
*data = rx_buf_ & DRV8301_DATA_MASK;
}
return true;
}
bool Drv8301::write_spi(const RegName_e regName, const uint16_t data) {
// Do blocking write
tx_buf_ = build_ctrl_word(DRV8301_CtrlMode_Write, regName, data);
if (!spi_arbiter_->transfer(spi_config_, ncs_gpio_, (uint8_t *)(&tx_buf_), nullptr, 1, 1000)) {
return false;
}
delay_us(1);
return true;
}
bool Drv8301::write_regs(Registers_t *regs) {
uint16_t ctrl1 = regs->Ctrl_Reg_1.DRV8301_CURRENT |
regs->Ctrl_Reg_1.DRV8301_RESET |
regs->Ctrl_Reg_1.PWM_MODE |
regs->Ctrl_Reg_1.OC_MODE |
regs->Ctrl_Reg_1.OC_ADJ_SET;
uint16_t ctrl2 = regs->Ctrl_Reg_2.OCTW_SET |
regs->Ctrl_Reg_2.GAIN |
regs->Ctrl_Reg_2.DC_CAL_CH1p2 |
regs->Ctrl_Reg_2.OC_TOFF;
return write_spi(RegName_Control_1, ctrl1)
&& write_spi(RegName_Control_2, ctrl2);
}
bool Drv8301::read_regs(Registers_t *regs) {
bool success = true;
uint16_t drvDataNew;
// Update Status Register 1
if (read_spi(RegName_Status_1, &drvDataNew)) {
regs->Stat_Reg_1.FAULT = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FAULT_BITS);
regs->Stat_Reg_1.GVDD_UV = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_GVDD_UV_BITS);
regs->Stat_Reg_1.PVDD_UV = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_PVDD_UV_BITS);
regs->Stat_Reg_1.OTSD = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_OTSD_BITS);
regs->Stat_Reg_1.OTW = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_OTW_BITS);
regs->Stat_Reg_1.FETHA_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETHA_OC_BITS);
regs->Stat_Reg_1.FETLA_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETLA_OC_BITS);
regs->Stat_Reg_1.FETHB_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETHB_OC_BITS);
regs->Stat_Reg_1.FETLB_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETLB_OC_BITS);
regs->Stat_Reg_1.FETHC_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETHC_OC_BITS);
regs->Stat_Reg_1.FETLC_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETLC_OC_BITS);
regs->Stat_Reg_1_Value = drvDataNew;
} else {
success = false;
}
// Update Status Register 2
if (read_spi(RegName_Status_2, &drvDataNew)) {
regs->Stat_Reg_2.GVDD_OV = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS2_GVDD_OV_BITS);
regs->Stat_Reg_2.DeviceID = (uint16_t)(drvDataNew & (uint16_t)DRV8301_STATUS2_ID_BITS);
regs->Stat_Reg_2_Value = drvDataNew;
} else {
success = false;
}
// Update Control Register 1
if (read_spi(RegName_Control_1, &drvDataNew)) {
regs->Ctrl_Reg_1.DRV8301_CURRENT = (PeakCurrent_e)(drvDataNew & (uint16_t)DRV8301_CTRL1_GATE_CURRENT_BITS);
regs->Ctrl_Reg_1.DRV8301_RESET = (Reset_e)(drvDataNew & (uint16_t)DRV8301_CTRL1_GATE_RESET_BITS);
regs->Ctrl_Reg_1.PWM_MODE = (PwmMode_e)(drvDataNew & (uint16_t)DRV8301_CTRL1_PWM_MODE_BITS);
regs->Ctrl_Reg_1.OC_MODE = (OcMode_e)(drvDataNew & (uint16_t)DRV8301_CTRL1_OC_MODE_BITS);
regs->Ctrl_Reg_1.OC_ADJ_SET = (VdsLevel_e)(drvDataNew & (uint16_t)DRV8301_CTRL1_OC_ADJ_SET_BITS);
regs->Ctrl_Reg_1_Value = drvDataNew;
} else {
success = false;
}
// Update Control Register 2
if (read_spi(RegName_Control_2, &drvDataNew)) {
regs->Ctrl_Reg_2.OCTW_SET = (OcTwMode_e)(drvDataNew & (uint16_t)DRV8301_CTRL2_OCTW_SET_BITS);
regs->Ctrl_Reg_2.GAIN = (ShuntAmpGain_e)(drvDataNew & (uint16_t)DRV8301_CTRL2_GAIN_BITS);
regs->Ctrl_Reg_2.DC_CAL_CH1p2 = (DcCalMode_e)(drvDataNew & (uint16_t)(DRV8301_CTRL2_DC_CAL_1_BITS | DRV8301_CTRL2_DC_CAL_2_BITS));
regs->Ctrl_Reg_2.OC_TOFF = (OcOffTimeMode_e)(drvDataNew & (uint16_t)DRV8301_CTRL2_OC_TOFF_BITS);
regs->Ctrl_Reg_2_Value = drvDataNew;
} else {
success = false;
}
return success;
}
File diff suppressed because it is too large Load Diff
+436
View File
@@ -0,0 +1,436 @@
/* --COPYRIGHT--,BSD
* Copyright (c) 2015, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * 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.
*
* * Neither the name of Texas Instruments Incorporated 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 OWNER 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.
* --/COPYRIGHT--*/
#ifndef _DRV8301_HPP_
#define _DRV8301_HPP_
//! \file drivers/drvic/drv8301/src/32b/f28x/f2806x/drv8301.h
//! \brief Contains public interface to various functions related
//! to the DRV8301 object
//!
//! (C) Copyright 2015, Texas Instruments, Inc.
// **************************************************************************
// the includes
#include "stdbool.h"
#include "stdint.h"
// drivers
#include "stm32f4xx_hal.h"
#include <Drivers/gate_driver.hpp>
#include <Drivers/STM32/stm32_spi_arbiter.hpp>
#include <Drivers/STM32/stm32_gpio.hpp>
#ifdef __cplusplus
extern "C" {
#endif
// **************************************************************************
// the defines
//! \brief Defines the address mask
//!
#define DRV8301_ADDR_MASK (0x7800)
//! \brief Defines the data mask
//!
#define DRV8301_DATA_MASK (0x07FF)
//! \brief Defines the R/W mask
//!
#define DRV8301_RW_MASK (0x8000)
//! \brief Defines the R/W mask
//!
#define DRV8301_FAULT_TYPE_MASK (0x07FF)
//! \brief Defines the location of the FETLC_OC (FET Low side, Phase C Over Current) bits in the Status 1 register
//!
#define DRV8301_STATUS1_FETLC_OC_BITS (1 << 0)
//! \brief Defines the location of the FETLC_OC (FET High side, Phase C Over Current) bits in the Status 1 register
//!
#define DRV8301_STATUS1_FETHC_OC_BITS (1 << 1)
//! \brief Defines the location of the FETLC_OC (FET Low side, Phase B Over Current) bits in the Status 1 register
//!
#define DRV8301_STATUS1_FETLB_OC_BITS (1 << 2)
//! \brief Defines the location of the FETLC_OC (FET High side, Phase B Over Current) bits in the Status 1 register
//!
#define DRV8301_STATUS1_FETHB_OC_BITS (1 << 3)
//! \brief Defines the location of the FETLC_OC (FET Low side, Phase A Over Current) bits in the Status 1 register
//!
#define DRV8301_STATUS1_FETLA_OC_BITS (1 << 4)
//! \brief Defines the location of the FETLC_OC (FET High side, Phase A Over Current) bits in the Status 1 register
//!
#define DRV8301_STATUS1_FETHA_OC_BITS (1 << 5)
//! \brief Defines the location of the OTW (Over Temperature Warning) bits in the Status 1 register
//!
#define DRV8301_STATUS1_OTW_BITS (1 << 6)
//! \brief Defines the location of the OTSD (Over Temperature Shut Down) bits in the Status 1 register
//!
#define DRV8301_STATUS1_OTSD_BITS (1 << 7)
//! \brief Defines the location of the PVDD_UV (Power supply Vdd, Under Voltage) bits in the Status 1 register
//!
#define DRV8301_STATUS1_PVDD_UV_BITS (1 << 8)
//! \brief Defines the location of the GVDD_UV (DRV8301 Vdd, Under Voltage) bits in the Status 1 register
//!
#define DRV8301_STATUS1_GVDD_UV_BITS (1 << 9)
//! \brief Defines the location of the FAULT bits in the Status 1 register
//!
#define DRV8301_STATUS1_FAULT_BITS (1 << 10)
//! \brief Defines the location of the Device ID bits in the Status 2 register
//!
#define DRV8301_STATUS2_ID_BITS (15 << 0)
//! \brief Defines the location of the GVDD_OV (DRV8301 Vdd, Over Voltage) bits in the Status 2 register
//!
#define DRV8301_STATUS2_GVDD_OV_BITS (1 << 7)
//! \brief Defines the location of the GATE_CURRENT bits in the Control 1 register
//!
#define DRV8301_CTRL1_GATE_CURRENT_BITS (3 << 0)
//! \brief Defines the location of the GATE_RESET bits in the Control 1 register
//!
#define DRV8301_CTRL1_GATE_RESET_BITS (1 << 2)
//! \brief Defines the location of the PWM_MODE bits in the Control 1 register
//!
#define DRV8301_CTRL1_PWM_MODE_BITS (1 << 3)
//! \brief Defines the location of the OC_MODE bits in the Control 1 register
//!
#define DRV8301_CTRL1_OC_MODE_BITS (3 << 4)
//! \brief Defines the location of the OC_ADJ bits in the Control 1 register
//!
#define DRV8301_CTRL1_OC_ADJ_SET_BITS (31 << 6)
//! \brief Defines the location of the OCTW_SET bits in the Control 2 register
//!
#define DRV8301_CTRL2_OCTW_SET_BITS (3 << 0)
//! \brief Defines the location of the GAIN bits in the Control 2 register
//!
#define DRV8301_CTRL2_GAIN_BITS (3 << 2)
//! \brief Defines the location of the DC_CAL_1 bits in the Control 2 register
//!
#define DRV8301_CTRL2_DC_CAL_1_BITS (1 << 4)
//! \brief Defines the location of the DC_CAL_2 bits in the Control 2 register
//!
#define DRV8301_CTRL2_DC_CAL_2_BITS (1 << 5)
//! \brief Defines the location of the OC_TOFF bits in the Control 2 register
//!
#define DRV8301_CTRL2_OC_TOFF_BITS (1 << 6)
#ifdef __cplusplus
}
#endif // extern "C"
class Drv8301 : public GateDriverBase, public OpAmpBase {
public:
typedef enum {
FaultType_NoFault = (0 << 0), //!< No fault
FaultType_FETLC_OC = (1 << 0), //!< FET Low side, Phase C Over Current fault
FaultType_FETHC_OC = (1 << 1), //!< FET High side, Phase C Over Current fault
FaultType_FETLB_OC = (1 << 2), //!< FET Low side, Phase B Over Current fault
FaultType_FETHB_OC = (1 << 3), //!< FET High side, Phase B Over Current fault
FaultType_FETLA_OC = (1 << 4), //!< FET Low side, Phase A Over Current fault
FaultType_FETHA_OC = (1 << 5), //!< FET High side, Phase A Over Current fault
FaultType_OTW = (1 << 6), //!< Over Temperature Warning fault
FaultType_OTSD = (1 << 7), //!< Over Temperature Shut Down fault
FaultType_PVDD_UV = (1 << 8), //!< Power supply Vdd Under Voltage fault
FaultType_GVDD_UV = (1 << 9), //!< DRV8301 Vdd Under Voltage fault
FaultType_GVDD_OV = (1 << 10) //!< DRV8301 Vdd Over Voltage fault
} FaultType_e;
Drv8301(Stm32SpiArbiter* spi_arbiter, Stm32Gpio ncs_gpio,
Stm32Gpio enable_gpio, Stm32Gpio nfault_gpio)
: spi_arbiter_(spi_arbiter), ncs_gpio_(ncs_gpio),
enable_gpio_(enable_gpio), nfault_gpio_(nfault_gpio) {}
bool set_gain(float requested_gain, float* actual_gain) final;
bool check_fault() final;
bool set_enabled(bool enabled) final;
FaultType_e get_error();
float get_midpoint() final {
return 0.5f; // [V]
}
float get_max_output_swing() final {
return 1.35f / 1.65f; // +-1.35V, normalized from a scale of +-1.65V to +-0.5
}
private:
enum CtrlMode_e {
DRV8301_CtrlMode_Read = 1 << 15, //!< Read Mode
DRV8301_CtrlMode_Write = 0 << 15 //!< Write Mode
};
enum RegName_e {
RegName_Status_1 = 0 << 11, //!< Status Register 1
RegName_Status_2 = 1 << 11, //!< Status Register 2
RegName_Control_1 = 2 << 11, //!< Control Register 1
RegName_Control_2 = 3 << 11 //!< Control Register 2
};
//! \brief Enumeration for the DC calibration modes
enum DcCalMode_e {
DcCalMode_Ch1_Load = (0 << 4), //!< Shunt amplifier 1 connected to load via input pins
DcCalMode_Ch1_NoLoad = (1 << 4), //!< Shunt amplifier 1 disconnected from load and input pins are shorted
DcCalMode_Ch2_Load = (0 << 5), //!< Shunt amplifier 2 connected to load via input pins
DcCalMode_Ch2_NoLoad = (1 << 5) //!< Shunt amplifier 2 disconnected from load and input pins are shorted
};
//! \brief Enumeration for the Over Current modes
enum OcMode_e {
OcMode_CurrentLimit = 0 << 4, //!< current limit when OC detected
OcMode_LatchShutDown = 1 << 4, //!< latch shut down when OC detected
OcMode_ReportOnly = 2 << 4, //!< report only when OC detected
OcMode_Disabled = 3 << 4 //!< OC protection disabled
};
//! \brief Enumeration for the Over Current Off Time modes
enum OcOffTimeMode_e {
OcOffTimeMode_Normal = 0 << 6, //!< normal CBC operation
OcOffTimeMode_Ctrl = 1 << 6 //!< off time control during OC
};
//! \brief Enumeration for the Over Current, Temperature Warning modes
enum OcTwMode_e {
OcTwMode_Both = 0 << 0, //!< report both OT and OC at /OCTW pin
OcTwMode_OT_Only = 1 << 0, //!< report only OT at /OCTW pin
OcTwMode_OC_Only = 2 << 0 //!< report only OC at /OCTW pin
};
//! \brief Enumeration for the drv8301 peak current levels
enum PeakCurrent_e {
PeakCurrent_1p70_A = 0 << 0, //!< drv8301 driver peak current 1.70A
PeakCurrent_0p70_A = 1 << 0, //!< drv8301 driver peak current 0.70A
PeakCurrent_0p25_A = 2 << 0 //!< drv8301 driver peak current 0.25A
};
//! \brief Enumeration for the PWM modes
enum PwmMode_e {
PwmMode_Six_Inputs = 0 << 3, //!< six independent inputs
PwmMode_Three_Inputs = 1 << 3 //!< three independent nputs
};
//! \brief Enumeration for the shunt amplifier gains
enum Reset_e {
Reset_Normal = 0 << 2, //!< normal
Reset_All = 1 << 2 //!< reset all
};
//! \brief Enumeration for the shunt amplifier gains
enum ShuntAmpGain_e {
ShuntAmpGain_10VpV = 0 << 2, //!< 10 V per V
ShuntAmpGain_20VpV = 1 << 2, //!< 20 V per V
ShuntAmpGain_40VpV = 2 << 2, //!< 40 V per V
ShuntAmpGain_80VpV = 3 << 2 //!< 80 V per V
};
//! \brief Enumeration for the shunt amplifier number
enum ShuntAmpNumber_e {
ShuntAmpNumber_1 = 1, //!< Shunt amplifier number 1
ShuntAmpNumber_2 = 2 //!< Shunt amplifier number 2
};
//! \brief Enumeration for the Vds level for th over current adjustment
enum VdsLevel_e {
VdsLevel_0p060_V = 0 << 6, //!< Vds = 0.060 V
VdsLevel_0p068_V = 1 << 6, //!< Vds = 0.068 V
VdsLevel_0p076_V = 2 << 6, //!< Vds = 0.076 V
VdsLevel_0p086_V = 3 << 6, //!< Vds = 0.086 V
VdsLevel_0p097_V = 4 << 6, //!< Vds = 0.097 V
VdsLevel_0p109_V = 5 << 6, //!< Vds = 0.109 V
VdsLevel_0p123_V = 6 << 6, //!< Vds = 0.123 V
VdsLevel_0p138_V = 7 << 6, //!< Vds = 0.138 V
VdsLevel_0p155_V = 8 << 6, //!< Vds = 0.155 V
VdsLevel_0p175_V = 9 << 6, //!< Vds = 0.175 V
VdsLevel_0p197_V = 10 << 6, //!< Vds = 0.197 V
VdsLevel_0p222_V = 11 << 6, //!< Vds = 0.222 V
VdsLevel_0p250_V = 12 << 6, //!< Vds = 0.250 V
VdsLevel_0p282_V = 13 << 6, //!< Vds = 0.282 V
VdsLevel_0p317_V = 14 << 6, //!< Vds = 0.317 V
VdsLevel_0p358_V = 15 << 6, //!< Vds = 0.358 V
VdsLevel_0p403_V = 16 << 6, //!< Vds = 0.403 V
VdsLevel_0p454_V = 17 << 6, //!< Vds = 0.454 V
VdsLevel_0p511_V = 18 << 6, //!< Vds = 0.511 V
VdsLevel_0p576_V = 19 << 6, //!< Vds = 0.576 V
VdsLevel_0p648_V = 20 << 6, //!< Vds = 0.648 V
VdsLevel_0p730_V = 21 << 6, //!< Vds = 0.730 V
VdsLevel_0p822_V = 22 << 6, //!< Vds = 0.822 V
VdsLevel_0p926_V = 23 << 6, //!< Vds = 0.926 V
VdsLevel_1p043_V = 24 << 6, //!< Vds = 1.403 V
VdsLevel_1p175_V = 25 << 6, //!< Vds = 1.175 V
VdsLevel_1p324_V = 26 << 6, //!< Vds = 1.324 V
VdsLevel_1p491_V = 27 << 6, //!< Vds = 1.491 V
VdsLevel_1p679_V = 28 << 6, //!< Vds = 1.679 V
VdsLevel_1p892_V = 29 << 6, //!< Vds = 1.892 V
VdsLevel_2p131_V = 30 << 6, //!< Vds = 2.131 V
VdsLevel_2p400_V = 31 << 6 //!< Vds = 2.400 V
};
struct Registers_t {
struct {
bool FAULT;
bool GVDD_UV;
bool PVDD_UV;
bool OTSD;
bool OTW;
bool FETHA_OC;
bool FETLA_OC;
bool FETHB_OC;
bool FETLB_OC;
bool FETHC_OC;
bool FETLC_OC;
} Stat_Reg_1;
struct {
bool GVDD_OV;
uint16_t DeviceID;
} Stat_Reg_2;
struct {
PeakCurrent_e DRV8301_CURRENT;
Reset_e DRV8301_RESET;
PwmMode_e PWM_MODE;
OcMode_e OC_MODE;
VdsLevel_e OC_ADJ_SET;
} Ctrl_Reg_1;
struct {
OcTwMode_e OCTW_SET;
ShuntAmpGain_e GAIN;
DcCalMode_e DC_CAL_CH1p2;
OcOffTimeMode_e OC_TOFF;
} Ctrl_Reg_2;
uint16_t Stat_Reg_1_Value;
uint16_t Stat_Reg_2_Value;
uint16_t Ctrl_Reg_1_Value;
uint16_t Ctrl_Reg_2_Value;
};
//! \brief Builds the control word
//! \param[in] ctrlMode The control mode
//! \param[in] regName The register name
//! \param[in] data The data
//! \return The control word
static inline uint16_t build_ctrl_word(const CtrlMode_e ctrlMode,
const RegName_e regName,
const uint16_t data) {
return ctrlMode | regName | (data & DRV8301_DATA_MASK);
} // end of DRV8301_buildCtrlWord() function
//! \brief Enables the DRV8301
void enable();
//! \brief Reads data from the DRV8301 register
//! \param[in] regName The register name
//! \return The data value
bool read_spi(const RegName_e regName, uint16_t* data);
//! \brief Writes data to the DRV8301 register
//! \param[in] regName The register name
//! \param[in] data The data value
bool write_spi(const RegName_e regName, const uint16_t data);
//! \brief Interface to all 8301 SPI variables
//!
//! \details Call this function periodically to be able to read the DRV8301 Status1, Status2,
//! Control1, and Control2 registers and write the Control1 and Control2 registers.
//! This function updates the members of the structure Registers_t.
//! <b>How to use in Setup</b>
//! <b>Code</b>
//! Add the structure declaration Registers_t to your code
//! Make sure the SPI and 8301 EN_Gate GPIO are setup for the 8301 by using HAL_init and HAL_setParams
//! During code setup, call HAL_enableDrv and HAL_setupDrvSpi
//! In background loop, call DRV8301_writeData and DRV8301_readData
//! <b>How to use in Runtime</b>
//! <b>Watch window</b>
//! Add the structure, declared by Registers_t above, to the watch window
//! <b>Runtime</b>
//! Pull down the menus from the Registers_t strcuture to the desired setting
//! Set SndCmd to send the settings to the DRV8301
//! If a read of the DRV8301 registers is required, se RcvCmd
//!
//! \param[in] regs The (Registers_t) structure that contains all DRV8301 Status/Control register options
bool write_regs(Registers_t *regs);
//! \param[in] regs The (Registers_t) structure that contains all DRV8301 Status/Control register options
bool read_regs(Registers_t *regs);
Stm32SpiArbiter* spi_arbiter_;
Stm32Gpio ncs_gpio_;
Stm32Gpio enable_gpio_;
Stm32Gpio nfault_gpio_;
// We don't put these buffers on the stack because we place the stack in
// a RAM section which cannot be used by DMA.
uint16_t tx_buf_;
uint16_t rx_buf_;
static const SPI_InitTypeDef spi_config_;
};
#endif // _DRV8301_HPP_
+25
View File
@@ -0,0 +1,25 @@
#ifndef STM32_GPIO_HPP__
#define STM32_GPIO_HPP__
#include <gpio.h>
class Stm32Gpio {
public:
Stm32Gpio(GPIO_TypeDef* port, uint16_t pin) : port_(port), pin_(pin) {}
operator bool() const { return port_; }
void write(bool state) {
HAL_GPIO_WritePin(port_, pin_, state ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
bool read() {
return HAL_GPIO_ReadPin(port_, pin_) != GPIO_PIN_RESET;
}
private:
GPIO_TypeDef* port_;
uint16_t pin_;
};
#endif // STM32_GPIO_HPP__
@@ -0,0 +1,123 @@
#include "stm32_spi_arbiter.hpp"
#include "stm32_system.h"
#include "utils.hpp"
bool equals(const SPI_InitTypeDef& lhs, const SPI_InitTypeDef& rhs) {
return (lhs.Mode == rhs.Mode)
&& (lhs.Direction == rhs.Direction)
&& (lhs.DataSize == rhs.DataSize)
&& (lhs.CLKPolarity == rhs.CLKPolarity)
&& (lhs.CLKPhase == rhs.CLKPhase)
&& (lhs.NSS == rhs.NSS)
&& (lhs.BaudRatePrescaler == rhs.BaudRatePrescaler)
&& (lhs.FirstBit == rhs.FirstBit)
&& (lhs.TIMode == rhs.TIMode)
&& (lhs.CRCCalculation == rhs.CRCCalculation)
&& (lhs.CRCPolynomial == rhs.CRCPolynomial);
}
bool Stm32SpiArbiter::start() {
if (!task_list_) {
return false;
}
SpiTask& task = *task_list_;
if (!equals(task.config, hspi_->Init)) {
HAL_SPI_DeInit(hspi_);
hspi_->Init = task.config;
HAL_SPI_Init(hspi_);
}
task.ncs_gpio.write(false);
HAL_StatusTypeDef status = HAL_ERROR;
if (task.tx_buf && task.rx_buf) {
status = HAL_SPI_TransmitReceive_DMA(hspi_, (uint8_t*)task.tx_buf, task.rx_buf, task.length);
} else if (task.tx_buf) {
status = HAL_SPI_Transmit_DMA(hspi_, (uint8_t*)task.tx_buf, task.length);
} else if (task.rx_buf) {
status = HAL_SPI_Receive_DMA(hspi_, task.rx_buf, task.length);
}
if (status != HAL_OK) {
task.ncs_gpio.write(true);
}
return status == HAL_OK;
}
bool Stm32SpiArbiter::transfer(SPI_InitTypeDef config, Stm32Gpio ncs_gpio, const uint8_t* tx_buf, uint8_t* rx_buf, size_t length, uint32_t timeout_ms) {
bool done = false;
SpiTask task = {
.config = config,
.ncs_gpio = ncs_gpio,
.tx_buf = tx_buf,
.rx_buf = rx_buf,
.length = length,
.on_complete = [](void* ctx) { *(bool*)ctx = true; },
.cb_ctx = &done,
.next = nullptr
};
// Append new task to task list.
// We could try to do this lock free but we could also use our time for useful things.
SpiTask** ptr = &task_list_;
{
uint32_t prim = cpu_enter_critical();
while (*ptr)
ptr = &(*ptr)->next;
*ptr = &task;
cpu_exit_critical(prim);
}
// If the list was empty before, kick off the SPI arbiter now
if (ptr == &task_list_) {
if (!start()) {
return false;
}
}
while (!done) {
osDelay(1); // TODO: honor timeout
}
return true;
/* HAL_StatusTypeDef status = HAL_ERROR;
// delay_us(1);
task.ncs_gpio.write(false);
// delay_us(1);
if (task.tx_buf && task.rx_buf) {
status = HAL_SPI_TransmitReceive(hspi_, (uint8_t*)task.tx_buf, task.rx_buf, task.length, 1000);
} else if (task.tx_buf) {
status = HAL_SPI_Transmit(hspi_, (uint8_t*)task.tx_buf, task.length, 1000);
} else if (task.rx_buf) {
status = HAL_SPI_Receive(hspi_, task.rx_buf, task.length, 1000);
}
// delay_us(1);
task.ncs_gpio.write(true);
// delay_us(1);
return status == HAL_OK;*/
}
void Stm32SpiArbiter::on_complete() {
if (!task_list_) {
return; // this should not happen
}
// Wrap up transfer
task_list_->ncs_gpio.write(true);
if (task_list_->on_complete) {
(*task_list_->on_complete)(task_list_->cb_ctx);
}
// Start next task if any
SpiTask* next = task_list_->next;
task_list_ = next;
if (next) {
start();
}
}
@@ -0,0 +1,56 @@
#ifndef SPI_ARBITER_HPP__
#define SPI_ARBITER_HPP__
#include "stm32_gpio.hpp"
#include <spi.h>
class Stm32SpiArbiter {
public:
struct SpiTask {
SPI_InitTypeDef config;
Stm32Gpio ncs_gpio;
const uint8_t* tx_buf;
uint8_t* rx_buf;
size_t length;
void (*on_complete)(void*);
void* cb_ctx;
struct SpiTask* next;
};
Stm32SpiArbiter(SPI_HandleTypeDef* hspi): hspi_(hspi) {}
/**
* @brief Executes a blocking transfer.
*
* If the SPI is busy this function waits until it becomes available or
* the specified timeout passes, whichever comes first.
*
* Returns true on successful transfer or false otherwise.
*
* This function is thread-safe with respect to itself.
*
* @param config: The SPI configuration to apply for this transfer.
* @param ncs_gpio: The active low GPIO to actuate during this transfer.
* @param tx_buf: Buffer for the outgoing data to be sent. Can be null unless
* rx_buf is null too.
* @param rx_buf: Buffer for the incoming data to be sent. Can be null unless
* tx_buf is null too.
*/
bool transfer(SPI_InitTypeDef config, Stm32Gpio ncs_gpio, const uint8_t* tx_buf, uint8_t* rx_buf, size_t length, uint32_t timeout_ms);
/**
* @brief Completion method to be called from HAL_SPI_TxCpltCallback,
* HAL_SPI_RxCpltCallback and HAL_SPI_TxRxCpltCallback.
*/
void on_complete();
private:
bool start();
SPI_HandleTypeDef* hspi_;
SpiTask* task_list_ = nullptr;
SpiTask* current_task_ = nullptr;
};
#endif
+16
View File
@@ -0,0 +1,16 @@
#ifndef __STM32_SYSTEM_H
#define __STM32_SYSTEM_H
#include <cmsis_os.h>
inline uint32_t cpu_enter_critical() {
uint32_t primask = __get_PRIMASK();
__disable_irq();
return primask;
}
inline void cpu_exit_critical(uint32_t priority_mask) {
__set_PRIMASK(priority_mask);
}
#endif // __STM32_SYSTEM_H
+39
View File
@@ -0,0 +1,39 @@
#ifndef __GATE_DRIVER_HPP
#define __GATE_DRIVER_HPP
struct GateDriverBase {
/**
* @brief Unlocks or locks the gate signals of the gate driver.
*
* While locked the PWM inputs are ignored and the switches are always in
* OFF state.
* Not all gate drivers implement this function and may return true even if
* the gate driver was not locked.
*/
virtual bool set_enabled(bool enabled) = 0;
/**
* @brief Checks for a fault condition. Returns false if the driver is in a
* fault state and true if it is in a nominal state.
*/
virtual bool check_fault() = 0;
};
struct OpAmpBase {
/**
* @brief Tries to set the OpAmp gain to the specified value or lower.
*/
virtual bool set_gain(float requested_gain, float* actual_gain) = 0;
/**
* @brief Returns the neutral voltage of the OpAmp in Volts
*/
virtual float get_midpoint() = 0;
/**
* @brief Returns the maximum voltage swing away from the midpoint voltage (in Volts)
*/
virtual float get_max_output_swing() = 0;
};
#endif // __GATE_DRIVER_HPP
+3 -2
View File
@@ -25,10 +25,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include <stm32f4xx_hal.h> // Sets up the correct chip specifc defines required by arm_math
#define ARM_MATH_CM4 // TODO: might change in future board versions #include <board.h>
#include "arm_math.h" #include "arm_math.h"
#include "arm_common_tables.h" #include "arm_common_tables.h"
/** /**
* @ingroup groupFastMath * @ingroup groupFastMath
*/ */
+1 -2
View File
@@ -26,8 +26,7 @@
* limitations under the License. * limitations under the License.
*/ */
#include <stm32f4xx_hal.h> // Sets up the correct chip specifc defines required by arm_math #include <board.h>
#define ARM_MATH_CM4 // TODO: might change in future board versions
#include "arm_math.h" #include "arm_math.h"
#include "arm_common_tables.h" #include "arm_common_tables.h"
+2 -2
View File
@@ -87,8 +87,8 @@ static void step_cb_wrapper(void* ctx) {
// @brief Sets up all components of the axis, // @brief Sets up all components of the axis,
// such as gate driver and encoder hardware. // such as gate driver and encoder hardware.
void Axis::setup() { bool Axis::setup() {
motor_.setup(); return motor_.setup();
} }
static void run_state_machine_loop_wrapper(void* ctx) { static void run_state_machine_loop_wrapper(void* ctx) {
+10 -4
View File
@@ -1,9 +1,15 @@
#ifndef __AXIS_HPP #ifndef __AXIS_HPP
#define __AXIS_HPP #define __AXIS_HPP
#ifndef __ODRIVE_MAIN_H class Axis;
#error "This file should not be included directly. Include odrive_main.h instead."
#endif #include "encoder.hpp"
#include "sensorless_estimator.hpp"
#include "controller.hpp"
#include "trapTraj.hpp"
#include "endstop.hpp"
#include "low_level.h"
#include "utils.hpp"
#include <array> #include <array>
@@ -84,7 +90,7 @@ public:
Endstop& min_endstop, Endstop& min_endstop,
Endstop& max_endstop); Endstop& max_endstop);
void setup(); bool setup();
void start_thread(); void start_thread();
void signal_current_meas(); void signal_current_meas();
bool wait_for_current_meas(); bool wait_for_current_meas();
-4
View File
@@ -1,10 +1,6 @@
#ifndef __CONTROLLER_HPP #ifndef __CONTROLLER_HPP
#define __CONTROLLER_HPP #define __CONTROLLER_HPP
#ifndef __ODRIVE_MAIN_H
#error "This file should not be included directly. Include odrive_main.h instead."
#endif
class Controller : public ODriveIntf::ControllerIntf { class Controller : public ODriveIntf::ControllerIntf {
public: public:
typedef struct { typedef struct {
@@ -1,10 +1,6 @@
#ifndef __CURRENT_LIMITER_HPP #ifndef __CURRENT_LIMITER_HPP
#define __CURRENT_LIMITER_HPP #define __CURRENT_LIMITER_HPP
#ifndef __ODRIVE_MAIN_H
#error "This file should not be included directly. Include odrive_main.h instead."
#endif
class CurrentLimiter { class CurrentLimiter {
public: public:
virtual ~CurrentLimiter() = default; virtual ~CurrentLimiter() = default;
+1
View File
@@ -1,5 +1,6 @@
#include "odrive_main.h" #include "odrive_main.h"
#include <Drivers/STM32/stm32_system.h>
Encoder::Encoder(const EncoderHardwareConfig_t& hw_config, Encoder::Encoder(const EncoderHardwareConfig_t& hw_config,
+1 -3
View File
@@ -1,9 +1,7 @@
#ifndef __ENCODER_HPP #ifndef __ENCODER_HPP
#define __ENCODER_HPP #define __ENCODER_HPP
#ifndef __ODRIVE_MAIN_H #include "utils.hpp"
#error "This file should not be included directly. Include odrive_main.h instead."
#endif
class Encoder : public ODriveIntf::EncoderIntf { class Encoder : public ODriveIntf::EncoderIntf {
public: public:
+9 -8
View File
@@ -4,7 +4,7 @@
// otherwise chip specific defines are ommited // otherwise chip specific defines are ommited
#include <stm32f405xx.h> #include <stm32f405xx.h>
#include <stm32f4xx_hal.h> // Sets up the correct chip specifc defines required by arm_math #include <stm32f4xx_hal.h> // Sets up the correct chip specifc defines required by arm_math
#define ARM_MATH_CM4 #include <Drivers/STM32/stm32_system.h>
#include <arm_math.h> #include <arm_math.h>
#include <cmsis_os.h> #include <cmsis_os.h>
@@ -114,7 +114,7 @@ bool safety_critical_disarm_motor_pwm(Motor& motor) {
uint32_t mask = cpu_enter_critical(); uint32_t mask = cpu_enter_critical();
bool was_armed = motor.armed_state_ != Motor::ARMED_STATE_DISARMED; bool was_armed = motor.armed_state_ != Motor::ARMED_STATE_DISARMED;
motor.armed_state_ = Motor::ARMED_STATE_DISARMED; motor.armed_state_ = Motor::ARMED_STATE_DISARMED;
__HAL_TIM_MOE_DISABLE_UNCONDITIONALLY(motor.hw_config_.timer); __HAL_TIM_MOE_DISABLE_UNCONDITIONALLY(motor.timer_);
cpu_exit_critical(mask); cpu_exit_critical(mask);
return was_armed; return was_armed;
} }
@@ -130,9 +130,9 @@ void safety_critical_apply_motor_pwm_timings(Motor& motor, uint16_t timings[3])
motor.armed_state_ = Motor::ARMED_STATE_DISARMED; motor.armed_state_ = Motor::ARMED_STATE_DISARMED;
} }
motor.hw_config_.timer->Instance->CCR1 = timings[0]; motor.timer_->Instance->CCR1 = timings[0];
motor.hw_config_.timer->Instance->CCR2 = timings[1]; motor.timer_->Instance->CCR2 = timings[1];
motor.hw_config_.timer->Instance->CCR3 = timings[2]; motor.timer_->Instance->CCR3 = timings[2];
if (motor.armed_state_ == Motor::ARMED_STATE_WAITING_FOR_TIMINGS) { if (motor.armed_state_ == Motor::ARMED_STATE_WAITING_FOR_TIMINGS) {
// timings were just loaded into the timer registers // timings were just loaded into the timer registers
@@ -144,7 +144,7 @@ void safety_critical_apply_motor_pwm_timings(Motor& motor, uint16_t timings[3])
// now we waited long enough. Enter armed state and // now we waited long enough. Enter armed state and
// enable the actual PWM outputs. // enable the actual PWM outputs.
motor.armed_state_ = Motor::ARMED_STATE_ARMED; motor.armed_state_ = Motor::ARMED_STATE_ARMED;
__HAL_TIM_MOE_ENABLE(motor.hw_config_.timer); // enable pwm outputs __HAL_TIM_MOE_ENABLE(motor.timer_); // enable pwm outputs
} else if (motor.armed_state_ == Motor::ARMED_STATE_ARMED) { } else if (motor.armed_state_ == Motor::ARMED_STATE_ARMED) {
// nothing to do, PWM is running, all good // nothing to do, PWM is running, all good
} else { } else {
@@ -508,7 +508,7 @@ void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) {
Axis& axis = injected ? *axes[0] : *axes[1]; Axis& axis = injected ? *axes[0] : *axes[1];
int axis_num = injected ? 0 : 1; int axis_num = injected ? 0 : 1;
Axis& other_axis = injected ? *axes[1] : *axes[0]; Axis& other_axis = injected ? *axes[1] : *axes[0];
bool counting_down = axis.motor_.hw_config_.timer->Instance->CR1 & TIM_CR1_DIR; bool counting_down = axis.motor_.timer_->Instance->CR1 & TIM_CR1_DIR;
bool current_meas_not_DC_CAL = !counting_down; bool current_meas_not_DC_CAL = !counting_down;
// Check the timing of the sequencing // Check the timing of the sequencing
@@ -812,7 +812,7 @@ void start_analog_thread() {
osThreadCreate(osThread(thread_def), NULL); osThreadCreate(osThread(thread_def), NULL);
} }
/*
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{ {
if(hspi->pRxBuffPtr == (uint8_t*)axes[0]->encoder_.abs_spi_dma_rx_) if(hspi->pRxBuffPtr == (uint8_t*)axes[0]->encoder_.abs_spi_dma_rx_)
@@ -820,3 +820,4 @@ void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
else if (hspi->pRxBuffPtr == (uint8_t*)axes[1]->encoder_.abs_spi_dma_rx_) else if (hspi->pRxBuffPtr == (uint8_t*)axes[1]->encoder_.abs_spi_dma_rx_)
axes[1]->encoder_.abs_spi_cb(); axes[1]->encoder_.abs_spi_cb();
} }
*/
-14
View File
@@ -2,10 +2,6 @@
#ifndef __LOW_LEVEL_H #ifndef __LOW_LEVEL_H
#define __LOW_LEVEL_H #define __LOW_LEVEL_H
#ifndef __ODRIVE_MAIN_H
#error "This file should not be included directly. Include odrive_main.h instead."
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -59,16 +55,6 @@ void start_analog_thread();
void update_brake_current(); void update_brake_current();
inline uint32_t cpu_enter_critical() {
uint32_t primask = __get_PRIMASK();
__disable_irq();
return primask;
}
inline void cpu_exit_critical(uint32_t priority_mask) {
__set_PRIMASK(priority_mask);
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
+22 -22
View File
@@ -14,8 +14,6 @@ ODriveCAN::Config_t can_config;
Encoder::Config_t encoder_configs[AXIS_COUNT]; Encoder::Config_t encoder_configs[AXIS_COUNT];
SensorlessEstimator::Config_t sensorless_configs[AXIS_COUNT]; SensorlessEstimator::Config_t sensorless_configs[AXIS_COUNT];
Controller::Config_t controller_configs[AXIS_COUNT]; Controller::Config_t controller_configs[AXIS_COUNT];
Motor::Config_t motor_configs[AXIS_COUNT];
OnboardThermistorCurrentLimiter::Config_t fet_thermistor_configs[AXIS_COUNT];
OffboardThermistorCurrentLimiter::Config_t motor_thermistor_configs[AXIS_COUNT]; OffboardThermistorCurrentLimiter::Config_t motor_thermistor_configs[AXIS_COUNT];
Axis::Config_t axis_configs[AXIS_COUNT]; Axis::Config_t axis_configs[AXIS_COUNT];
TrapezoidalTrajectory::Config_t trap_configs[AXIS_COUNT]; TrapezoidalTrajectory::Config_t trap_configs[AXIS_COUNT];
@@ -32,8 +30,8 @@ typedef Config<
Encoder::Config_t[AXIS_COUNT], Encoder::Config_t[AXIS_COUNT],
SensorlessEstimator::Config_t[AXIS_COUNT], SensorlessEstimator::Config_t[AXIS_COUNT],
Controller::Config_t[AXIS_COUNT], Controller::Config_t[AXIS_COUNT],
Motor::Config_t[AXIS_COUNT], Motor::Config_t, Motor::Config_t,
OnboardThermistorCurrentLimiter::Config_t[AXIS_COUNT], OnboardThermistorCurrentLimiter::Config_t, OnboardThermistorCurrentLimiter::Config_t,
OffboardThermistorCurrentLimiter::Config_t[AXIS_COUNT], OffboardThermistorCurrentLimiter::Config_t[AXIS_COUNT],
TrapezoidalTrajectory::Config_t[AXIS_COUNT], TrapezoidalTrajectory::Config_t[AXIS_COUNT],
Endstop::Config_t[AXIS_COUNT], Endstop::Config_t[AXIS_COUNT],
@@ -47,8 +45,10 @@ void ODrive::save_configuration(void) {
&encoder_configs, &encoder_configs,
&sensorless_configs, &sensorless_configs,
&controller_configs, &controller_configs,
&motor_configs, &m0.config_,
&fet_thermistor_configs, &m1.config_,
&m0_fet_thermistor.config_,
&m1_fet_thermistor.config_,
&motor_thermistor_configs, &motor_thermistor_configs,
&trap_configs, &trap_configs,
&min_endstop_configs, &min_endstop_configs,
@@ -69,8 +69,10 @@ extern "C" int load_configuration(void) {
&encoder_configs, &encoder_configs,
&sensorless_configs, &sensorless_configs,
&controller_configs, &controller_configs,
&motor_configs, &m0.config_,
&fet_thermistor_configs, &m1.config_,
&m0_fet_thermistor.config_,
&m1_fet_thermistor.config_,
&motor_thermistor_configs, &motor_thermistor_configs,
&trap_configs, &trap_configs,
&min_endstop_configs, &min_endstop_configs,
@@ -79,12 +81,14 @@ extern "C" int load_configuration(void) {
//If loading failed, restore defaults //If loading failed, restore defaults
odrv.config_ = BoardConfig_t(); odrv.config_ = BoardConfig_t();
can_config = ODriveCAN::Config_t(); can_config = ODriveCAN::Config_t();
m0.config_ = Motor::Config_t();
m1.config_ = Motor::Config_t();
m0_fet_thermistor.config_ = OnboardThermistorCurrentLimiter::Config_t();
m1_fet_thermistor.config_ = OnboardThermistorCurrentLimiter::Config_t();
for (size_t i = 0; i < AXIS_COUNT; ++i) { for (size_t i = 0; i < AXIS_COUNT; ++i) {
encoder_configs[i] = Encoder::Config_t(); encoder_configs[i] = Encoder::Config_t();
sensorless_configs[i] = SensorlessEstimator::Config_t(); sensorless_configs[i] = SensorlessEstimator::Config_t();
controller_configs[i] = Controller::Config_t(); controller_configs[i] = Controller::Config_t();
motor_configs[i] = Motor::Config_t();
fet_thermistor_configs[i] = OnboardThermistorCurrentLimiter::Config_t();
motor_thermistor_configs[i] = OffboardThermistorCurrentLimiter::Config_t(); motor_thermistor_configs[i] = OffboardThermistorCurrentLimiter::Config_t();
trap_configs[i] = TrapezoidalTrajectory::Config_t(); trap_configs[i] = TrapezoidalTrajectory::Config_t();
axis_configs[i] = Axis::Config_t(); axis_configs[i] = Axis::Config_t();
@@ -176,32 +180,26 @@ extern "C" int construct_objects(){
HAL_GPIO_Init(GPIO_5_GPIO_Port, &GPIO_InitStruct); HAL_GPIO_Init(GPIO_5_GPIO_Port, &GPIO_InitStruct);
#endif #endif
m0.reload_config();
m1.reload_config();
// Construct all objects. // Construct all objects.
odCAN = new ODriveCAN(can_config, &hcan1); odCAN = new ODriveCAN(can_config, &hcan1);
for (size_t i = 0; i < AXIS_COUNT; ++i) { for (size_t i = 0; i < AXIS_COUNT; ++i) {
Encoder *encoder = new Encoder(hw_configs[i].encoder_config, Encoder *encoder = new Encoder(hw_configs[i].encoder_config,
encoder_configs[i], motor_configs[i]); encoder_configs[i], (i ? m1 : m0).config_);
SensorlessEstimator *sensorless_estimator = new SensorlessEstimator(sensorless_configs[i]); SensorlessEstimator *sensorless_estimator = new SensorlessEstimator(sensorless_configs[i]);
Controller *controller = new Controller(controller_configs[i]); Controller *controller = new Controller(controller_configs[i]);
OnboardThermistorCurrentLimiter *fet_thermistor = new OnboardThermistorCurrentLimiter(hw_configs[i].thermistor_config,
fet_thermistor_configs[i]);
OffboardThermistorCurrentLimiter *motor_thermistor = new OffboardThermistorCurrentLimiter(motor_thermistor_configs[i]); OffboardThermistorCurrentLimiter *motor_thermistor = new OffboardThermistorCurrentLimiter(motor_thermistor_configs[i]);
Motor *motor = new Motor(hw_configs[i].motor_config,
hw_configs[i].gate_driver_config,
motor_configs[i]);
TrapezoidalTrajectory *trap = new TrapezoidalTrajectory(trap_configs[i]); TrapezoidalTrajectory *trap = new TrapezoidalTrajectory(trap_configs[i]);
Endstop *min_endstop = new Endstop(min_endstop_configs[i]); Endstop *min_endstop = new Endstop(min_endstop_configs[i]);
Endstop *max_endstop = new Endstop(max_endstop_configs[i]); Endstop *max_endstop = new Endstop(max_endstop_configs[i]);
axes[i] = new Axis(i, hw_configs[i].axis_config, axis_configs[i], axes[i] = new Axis(i, hw_configs[i].axis_config, axis_configs[i],
*encoder, *sensorless_estimator, *controller, *fet_thermistor, *encoder, *sensorless_estimator, *controller, i ? m1_fet_thermistor : m0_fet_thermistor, *motor_thermistor, i ? m1 : m0, *trap, *min_endstop, *max_endstop);
*motor_thermistor, *motor, *trap, *min_endstop, *max_endstop);
controller_configs[i].parent = controller; controller_configs[i].parent = controller;
encoder_configs[i].parent = encoder; encoder_configs[i].parent = encoder;
motor_thermistor_configs[i].parent = motor_thermistor; motor_thermistor_configs[i].parent = motor_thermistor;
motor_configs[i].parent = motor;
min_endstop_configs[i].parent = min_endstop; min_endstop_configs[i].parent = min_endstop;
max_endstop_configs[i].parent = max_endstop; max_endstop_configs[i].parent = max_endstop;
axis_configs[i].parent = axes[i]; axis_configs[i].parent = axes[i];
@@ -264,7 +262,9 @@ int odrive_main(void) {
// Setup hardware for all components // Setup hardware for all components
for (size_t i = 0; i < AXIS_COUNT; ++i) { for (size_t i = 0; i < AXIS_COUNT; ++i) {
axes[i]->setup(); if (!axes[i]->setup()) {
for (;;); // TODO: proper error handling
}
} }
for(auto& axis : axes){ for(auto& axis : axes){
+34 -77
View File
@@ -1,24 +1,22 @@
#include "motor.hpp"
#include "axis.hpp"
#include "low_level.h"
#include "odrive_main.h"
#include <algorithm> #include <algorithm>
#include "drv8301.h" Motor::Motor(TIM_HandleTypeDef* timer,
#include "odrive_main.h" uint16_t control_deadline,
float shunt_conductance,
TGateDriver& gate_driver,
Motor::Motor(const MotorHardwareConfig_t& hw_config, TOpAmp& opamp) :
const GateDriverHardwareConfig_t& gate_driver_config, timer_(timer),
Config_t& config) : control_deadline_(control_deadline),
hw_config_(hw_config), shunt_conductance_(shunt_conductance),
gate_driver_config_(gate_driver_config), gate_driver_(gate_driver),
config_(config), opamp_(opamp) {
gate_driver_({ reload_config();
.spiHandle = gate_driver_config_.spi,
.EngpioHandle = gate_driver_config_.enable_port,
.EngpioNumber = gate_driver_config_.enable_pin,
.nCSgpioHandle = gate_driver_config_.nCS_port,
.nCSgpioNumber = gate_driver_config_.nCS_pin,
}) {
update_current_controller_gains();
} }
// @brief Arms the PWM outputs that belong to this motor. // @brief Arms the PWM outputs that belong to this motor.
@@ -63,77 +61,36 @@ void Motor::update_current_controller_gains() {
current_control_.i_gain = plant_pole * current_control_.p_gain; current_control_.i_gain = plant_pole * current_control_.p_gain;
} }
// @brief Set up the gate drivers void Motor::reload_config() {
void Motor::DRV8301_setup() { config_.parent = this;
// for reference: is_calibrated_ = config_.pre_calibrated;
// 20V/V on 500uOhm gives a range of +/- 150A update_current_controller_gains();
// 40V/V on 500uOhm gives a range of +/- 75A }
// 20V/V on 666uOhm gives a range of +/- 110A
// 40V/V on 666uOhm gives a range of +/- 55A
// @brief Set up the gate drivers
bool Motor::setup() {
gate_driver_.set_enabled(true);
// Solve for exact gain, then snap down to have equal or larger range as requested // Solve for exact gain, then snap down to have equal or larger range as requested
// or largest possible range otherwise // or largest possible range otherwise
static const float kMargin = 0.90f; static const float kMargin = 0.90f;
static const float kTripMargin = 1.0f; // Trip level is at edge of linear range of amplifer static const float kTripMargin = 1.0f; // Trip level is at edge of linear range of amplifer
static const float max_output_swing = 1.35f; // [V] out of amplifier static const float max_output_swing = 1.35f; // [V] out of amplifier
float max_unity_gain_current = kMargin * max_output_swing * hw_config_.shunt_conductance; // [A] float max_unity_gain_current = kMargin * max_output_swing * shunt_conductance_; // [A]
float requested_gain = max_unity_gain_current / config_.requested_current_range; // [V/V] float requested_gain = max_unity_gain_current / config_.requested_current_range; // [V/V]
// Decoding array for snapping gain float actual_gain = NAN;
std::array<std::pair<float, DRV8301_ShuntAmpGain_e>, 4> gain_choices = { bool success = opamp_.set_gain(requested_gain, &actual_gain);
std::make_pair(10.0f, DRV8301_ShuntAmpGain_10VpV), if (!success)
std::make_pair(20.0f, DRV8301_ShuntAmpGain_20VpV), return false;
std::make_pair(40.0f, DRV8301_ShuntAmpGain_40VpV),
std::make_pair(80.0f, DRV8301_ShuntAmpGain_80VpV)
};
// We use lower_bound in reverse because it snaps up by default, we want to snap down.
auto gain_snap_down = std::lower_bound(gain_choices.crbegin(), gain_choices.crend(), requested_gain,
[](std::pair<float, DRV8301_ShuntAmpGain_e> pair, float val){
return pair.first > val;
});
// If we snap to outside the array, clip to smallest val
if(gain_snap_down == gain_choices.crend())
--gain_snap_down;
// Values for current controller // Values for current controller
phase_current_rev_gain_ = 1.0f / gain_snap_down->first; phase_current_rev_gain_ = 1.0f / actual_gain;
// Clip all current control to actual usable range // Clip all current control to actual usable range
current_control_.max_allowed_current = max_unity_gain_current * phase_current_rev_gain_; current_control_.max_allowed_current = max_unity_gain_current * phase_current_rev_gain_;
// Set trip level // Set trip level
current_control_.overcurrent_trip_level = (kTripMargin / kMargin) * current_control_.max_allowed_current; current_control_.overcurrent_trip_level = (kTripMargin / kMargin) * current_control_.max_allowed_current;
// We now have the gain settings we want to use, lets set up DRV chip
DRV_SPI_8301_Vars_t* local_regs = &gate_driver_regs_;
DRV8301_enable(&gate_driver_);
DRV8301_setupSpi(&gate_driver_, local_regs);
local_regs->Ctrl_Reg_1.OC_MODE = DRV8301_OcMode_LatchShutDown;
// Overcurrent set to approximately 150A at 100degC. This may need tweaking.
local_regs->Ctrl_Reg_1.OC_ADJ_SET = DRV8301_VdsLevel_0p730_V;
local_regs->Ctrl_Reg_2.GAIN = gain_snap_down->second;
local_regs->SndCmd = true;
DRV8301_writeData(&gate_driver_, local_regs);
local_regs->RcvCmd = true;
DRV8301_readData(&gate_driver_, local_regs);
}
// @brief Checks if the gate driver is in operational state.
// @returns: true if the gate driver is OK (no fault), false otherwise
bool Motor::check_DRV_fault() {
//TODO: make this pin configurable per motor ch
GPIO_PinState nFAULT_state = HAL_GPIO_ReadPin(gate_driver_config_.nFAULT_port, gate_driver_config_.nFAULT_pin);
if (nFAULT_state == GPIO_PIN_RESET) {
// Update DRV Fault Code
gate_driver_exported_.drv_fault = (GateDriverIntf::DrvFault)DRV8301_getFaultType(&gate_driver_);
// Update/Cache all SPI device registers
// DRV_SPI_8301_Vars_t* local_regs = &gate_driver_regs_;
// local_regs->RcvCmd = true;
// DRV8301_readData(&gate_driver_, local_regs);
return false;
};
return true; return true;
} }
@@ -145,7 +102,7 @@ void Motor::set_error(Motor::Error error){
} }
bool Motor::do_checks() { bool Motor::do_checks() {
if (!check_DRV_fault()) { if (!gate_driver_.check_fault()) {
set_error(ERROR_DRV_FAULT); set_error(ERROR_DRV_FAULT);
return false; return false;
} }
@@ -201,7 +158,7 @@ float Motor::phase_current_from_adcval(uint32_t ADCValue) {
int adcval_bal = (int)ADCValue - (1 << 11); int adcval_bal = (int)ADCValue - (1 << 11);
float amp_out_volt = (3.3f / (float)(1 << 12)) * (float)adcval_bal; float amp_out_volt = (3.3f / (float)(1 << 12)) * (float)adcval_bal;
float shunt_volt = amp_out_volt * phase_current_rev_gain_; float shunt_volt = amp_out_volt * phase_current_rev_gain_;
float current = shunt_volt * hw_config_.shunt_conductance; float current = shunt_volt * shunt_conductance_;
return current; return current;
} }
+40 -20
View File
@@ -1,11 +1,31 @@
#ifndef __MOTOR_HPP #ifndef __MOTOR_HPP
#define __MOTOR_HPP #define __MOTOR_HPP
#ifndef __ODRIVE_MAIN_H class Axis; // declared in axis.hpp
#error "This file should not be included directly. Include odrive_main.h instead." class Motor;
#include <board.h>
#ifndef __TimingLog_t
#define __TimingLog_t
enum TimingLog_t { // TODO: remove
TIMING_LOG_GENERAL,
TIMING_LOG_ADC_CB_I,
TIMING_LOG_ADC_CB_DC,
TIMING_LOG_MEAS_R,
TIMING_LOG_MEAS_L,
TIMING_LOG_ENC_CALIB,
TIMING_LOG_IDX_SEARCH,
TIMING_LOG_FOC_VOLTAGE,
TIMING_LOG_FOC_CURRENT,
TIMING_LOG_SPI_START,
TIMING_LOG_SAMPLE_NOW,
TIMING_LOG_SPI_END,
TIMING_LOG_NUM_SLOTS
};
#endif #endif
#include "drv8301.h" #include <autogen/interfaces.hpp>
class Motor : public ODriveIntf::MotorIntf { class Motor : public ODriveIntf::MotorIntf {
public: public:
@@ -76,20 +96,19 @@ public:
void set_current_control_bandwidth(float value) { current_control_bandwidth = value; parent->update_current_controller_gains(); } void set_current_control_bandwidth(float value) { current_control_bandwidth = value; parent->update_current_controller_gains(); }
}; };
Motor(const MotorHardwareConfig_t& hw_config, Motor(TIM_HandleTypeDef* timer,
const GateDriverHardwareConfig_t& gate_driver_config, uint16_t control_deadline,
Config_t& config); float shunt_conductance,
TGateDriver& gate_driver,
TOpAmp& opamp);
bool arm(); bool arm();
void disarm(); void disarm();
void setup() { void reload_config();
DRV8301_setup(); bool setup();
}
void reset_current_control(); void reset_current_control();
void update_current_controller_gains(); void update_current_controller_gains();
void DRV8301_setup();
bool check_DRV_fault();
void set_error(Error error); void set_error(Error error);
bool do_checks(); bool do_checks();
float effective_current_lim(); float effective_current_lim();
@@ -105,14 +124,19 @@ public:
bool FOC_current(float Id_des, float Iq_des, float I_phase, float pwm_phase); bool FOC_current(float Id_des, float Iq_des, float I_phase, float pwm_phase);
bool update(float current_setpoint, float phase, float phase_vel); bool update(float current_setpoint, float phase, float phase_vel);
const MotorHardwareConfig_t& hw_config_; // hardware config
const GateDriverHardwareConfig_t gate_driver_config_;
Config_t& config_; TIM_HandleTypeDef* const timer_;
const uint16_t control_deadline_;
const float shunt_conductance_;
TGateDriver& gate_driver_;
TOpAmp& opamp_;
Config_t config_;
Axis* axis_ = nullptr; // set by Axis constructor Axis* axis_ = nullptr; // set by Axis constructor
//private: //private:
DRV8301_Obj gate_driver_; // initialized in constructor
uint16_t next_timings_[3] = { uint16_t next_timings_[3] = {
TIM_1_8_PERIOD_CLOCKS / 2, TIM_1_8_PERIOD_CLOCKS / 2,
TIM_1_8_PERIOD_CLOCKS / 2, TIM_1_8_PERIOD_CLOCKS / 2,
@@ -155,11 +179,7 @@ public:
.async_phase_vel = 0.0f, .async_phase_vel = 0.0f,
.async_phase_offset = 0.0f, .async_phase_offset = 0.0f,
}; };
struct : GateDriverIntf { float effective_current_lim_ = 10.0f; // [A]
DrvFault drv_fault = DRV_FAULT_NO_FAULT;
} gate_driver_exported_;
DRV_SPI_8301_Vars_t gate_driver_regs_; //Local view of DRV registers (initialized by DRV8301_setup)
float effective_current_lim_ = 10.0f;
}; };
#endif // __MOTOR_HPP #endif // __MOTOR_HPP
+2 -38
View File
@@ -1,12 +1,8 @@
#ifndef __ODRIVE_MAIN_H #ifndef __ODRIVE_MAIN_H
#define __ODRIVE_MAIN_H #define __ODRIVE_MAIN_H
// Note on central include scheme by Samuel: // Hardware configuration
// there are circular dependencies between some of the header files, #include <board.h>
// e.g. the Motor header needs a forward declaration of Axis and vice versa
// so I figured I'd make one main header that takes care of
// the forward declarations and right ordering
// btw this pattern is not so uncommon, for instance IIRC the stdlib uses it too
#ifdef __cplusplus #ifdef __cplusplus
#include <fibre/protocol.hpp> #include <fibre/protocol.hpp>
@@ -19,28 +15,13 @@ extern "C" {
#include <stm32f4xx_hal.h> // Sets up the correct chip specifc defines required by arm_math #include <stm32f4xx_hal.h> // Sets up the correct chip specifc defines required by arm_math
#include <can.h> #include <can.h>
#include <i2c.h> #include <i2c.h>
#define ARM_MATH_CM4 // TODO: might change in future board versions
#include <arm_math.h>
// OS includes // OS includes
#include <cmsis_os.h> #include <cmsis_os.h>
// Hardware configuration
#if HW_VERSION_MAJOR == 3
#include "board_config_v3.h"
#else
#error "unknown board version"
#endif
//default timeout waiting for phase measurement signals //default timeout waiting for phase measurement signals
#define PH_CURRENT_MEAS_TIMEOUT 2 // [ms] #define PH_CURRENT_MEAS_TIMEOUT 2 // [ms]
// Period in [s]
static const float current_meas_period = CURRENT_MEAS_PERIOD;
// Frequency in [Hz]
static const int current_meas_hz = CURRENT_MEAS_HZ;
// extern const float elec_rad_per_enc; // extern const float elec_rad_per_enc;
extern uint32_t _reboot_cookie; extern uint32_t _reboot_cookie;
@@ -178,22 +159,6 @@ inline ENUMTYPE &operator ^= (ENUMTYPE &a, ENUMTYPE b) { return reinterpret_cast
inline ENUMTYPE operator ~ (ENUMTYPE a) { return static_cast<ENUMTYPE>(~static_cast<std::underlying_type_t<ENUMTYPE>>(a)); } inline ENUMTYPE operator ~ (ENUMTYPE a) { return static_cast<ENUMTYPE>(~static_cast<std::underlying_type_t<ENUMTYPE>>(a)); }
enum TimingLog_t {
TIMING_LOG_GENERAL,
TIMING_LOG_ADC_CB_I,
TIMING_LOG_ADC_CB_DC,
TIMING_LOG_MEAS_R,
TIMING_LOG_MEAS_L,
TIMING_LOG_ENC_CALIB,
TIMING_LOG_IDX_SEARCH,
TIMING_LOG_FOC_VOLTAGE,
TIMING_LOG_FOC_CURRENT,
TIMING_LOG_SPI_START,
TIMING_LOG_SAMPLE_NOW,
TIMING_LOG_SPI_END,
TIMING_LOG_NUM_SLOTS
};
#include "autogen/interfaces.hpp" #include "autogen/interfaces.hpp"
@@ -201,7 +166,6 @@ enum TimingLog_t {
#include <utils.hpp> #include <utils.hpp>
#include <gpio_utils.hpp> #include <gpio_utils.hpp>
#include <low_level.h> #include <low_level.h>
#include <motor.hpp>
#include <encoder.hpp> #include <encoder.hpp>
#include <sensorless_estimator.hpp> #include <sensorless_estimator.hpp>
#include <controller.hpp> #include <controller.hpp>
+7 -8
View File
@@ -49,14 +49,13 @@ float ThermistorCurrentLimiter::get_current_limit(float base_current_lim) const
return std::min(thermal_current_lim, base_current_lim); return std::min(thermal_current_lim, base_current_lim);
} }
OnboardThermistorCurrentLimiter::OnboardThermistorCurrentLimiter(const ThermistorHardwareConfig_t& hw_config, Config_t& config) : OnboardThermistorCurrentLimiter::OnboardThermistorCurrentLimiter(uint16_t adc_channel, const float* const coefficients, size_t num_coeffs) :
ThermistorCurrentLimiter(hw_config.adc_ch, ThermistorCurrentLimiter(adc_channel,
hw_config.coeffs, coefficients,
hw_config.num_coeffs, num_coeffs,
config.temp_limit_lower, config_.temp_limit_lower,
config.temp_limit_upper, config_.temp_limit_upper,
config.enabled), config_.enabled)
config_(config)
{ {
} }
+26 -5
View File
@@ -1,10 +1,31 @@
#ifndef __THERMISTOR_HPP #ifndef __THERMISTOR_HPP
#define __THERMISTOR_HPP #define __THERMISTOR_HPP
#ifndef __ODRIVE_MAIN_H class Axis; // declared in axis.hpp
#error "This file should not be included directly. Include odrive_main.h instead."
#include "current_limiter.hpp"
#ifndef __TimingLog_t
#define __TimingLog_t
enum TimingLog_t { // TODO: remove
TIMING_LOG_GENERAL,
TIMING_LOG_ADC_CB_I,
TIMING_LOG_ADC_CB_DC,
TIMING_LOG_MEAS_R,
TIMING_LOG_MEAS_L,
TIMING_LOG_ENC_CALIB,
TIMING_LOG_IDX_SEARCH,
TIMING_LOG_FOC_VOLTAGE,
TIMING_LOG_FOC_CURRENT,
TIMING_LOG_SPI_START,
TIMING_LOG_SAMPLE_NOW,
TIMING_LOG_SPI_END,
TIMING_LOG_NUM_SLOTS
};
#endif #endif
#include <autogen/interfaces.hpp>
class ThermistorCurrentLimiter : public CurrentLimiter, public ODriveIntf::ThermistorCurrentLimiterIntf { class ThermistorCurrentLimiter : public CurrentLimiter, public ODriveIntf::ThermistorCurrentLimiterIntf {
public: public:
virtual ~ThermistorCurrentLimiter() = default; virtual ~ThermistorCurrentLimiter() = default;
@@ -23,7 +44,7 @@ public:
uint16_t adc_channel_; uint16_t adc_channel_;
const float* const coefficients_; const float* const coefficients_;
const size_t num_coeffs_; const size_t num_coeffs_;
float temperature_; float temperature_ = NAN; // [°C] NaN while the ODrive is initializing.
const float& temp_limit_lower_; const float& temp_limit_lower_;
const float& temp_limit_upper_; const float& temp_limit_upper_;
const bool& enabled_; const bool& enabled_;
@@ -40,9 +61,9 @@ public:
}; };
virtual ~OnboardThermistorCurrentLimiter() = default; virtual ~OnboardThermistorCurrentLimiter() = default;
OnboardThermistorCurrentLimiter(const ThermistorHardwareConfig_t& hw_config, Config_t& config); OnboardThermistorCurrentLimiter(uint16_t adc_channel, const float* const coefficients, size_t num_coeffs);
Config_t& config_; Config_t config_;
}; };
class OffboardThermistorCurrentLimiter : public ThermistorCurrentLimiter, public ODriveIntf::OffboardThermistorCurrentLimiterIntf { class OffboardThermistorCurrentLimiter : public ThermistorCurrentLimiter, public ODriveIntf::OffboardThermistorCurrentLimiterIntf {
+71 -66
View File
@@ -34,45 +34,51 @@ tup.frule{
outputs={'autogen/version.c'} outputs={'autogen/version.c'}
} }
board_v3 = {
dir = 'Board/v3',
sources = {'Drivers/DRV8301/drv8301.cpp', 'Board/v3/board.cpp'},
flags = {'-DSTM32F405xx', '-DARM_MATH_CM4', '-mcpu=cortex-m4', '-mfpu=fpv4-sp-d16'},
ldflags = {'-TBoard/v3/STM32F405RGTx_FLASH.ld', '-LBoard/v3/Drivers/CMSIS/Lib', '-larm_cortexM4lf_math', '-mcpu=cortex-m4', '-mfpu=fpv4-sp-d16'}
}
-- Switch between board versions -- Switch between board versions
boardversion = tup.getconfig("BOARD_VERSION") boardversion = tup.getconfig("BOARD_VERSION")
if boardversion == "v3.1" then if boardversion == "v3.1" then
boarddir = 'Board/v3' -- currently all platform code is in the same v3.3 directory board = board_v3
FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=1" board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=1"
FLAGS += "-DHW_VERSION_VOLTAGE=24" board.flags += "-DHW_VERSION_VOLTAGE=24"
elseif boardversion == "v3.2" then elseif boardversion == "v3.2" then
boarddir = 'Board/v3' board = board_v3
FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=2" board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=2"
FLAGS += "-DHW_VERSION_VOLTAGE=24" board.flags += "-DHW_VERSION_VOLTAGE=24"
elseif boardversion == "v3.3" then elseif boardversion == "v3.3" then
boarddir = 'Board/v3' board = board_v3
FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=3" board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=3"
FLAGS += "-DHW_VERSION_VOLTAGE=24" board.flags += "-DHW_VERSION_VOLTAGE=24"
elseif boardversion == "v3.4-24V" then elseif boardversion == "v3.4-24V" then
boarddir = 'Board/v3' board = board_v3
FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=4" board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=4"
FLAGS += "-DHW_VERSION_VOLTAGE=24" board.flags += "-DHW_VERSION_VOLTAGE=24"
elseif boardversion == "v3.4-48V" then elseif boardversion == "v3.4-48V" then
boarddir = 'Board/v3' board = board_v3
FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=4" board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=4"
FLAGS += "-DHW_VERSION_VOLTAGE=48" board.flags += "-DHW_VERSION_VOLTAGE=48"
elseif boardversion == "v3.5-24V" then elseif boardversion == "v3.5-24V" then
boarddir = 'Board/v3' board = board_v3
FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=5" board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=5"
FLAGS += "-DHW_VERSION_VOLTAGE=24" board.flags += "-DHW_VERSION_VOLTAGE=24"
elseif boardversion == "v3.5-48V" then elseif boardversion == "v3.5-48V" then
boarddir = 'Board/v3' board = board_v3
FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=5" board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=5"
FLAGS += "-DHW_VERSION_VOLTAGE=48" board.flags += "-DHW_VERSION_VOLTAGE=48"
elseif boardversion == "v3.6-24V" then elseif boardversion == "v3.6-24V" then
boarddir = 'Board/v3' board = board_v3
FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=6" board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=6"
FLAGS += "-DHW_VERSION_VOLTAGE=24" board.flags += "-DHW_VERSION_VOLTAGE=24"
elseif boardversion == "v3.6-56V" then elseif boardversion == "v3.6-56V" then
boarddir = 'Board/v3' board = board_v3
FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=6" board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=6"
FLAGS += "-DHW_VERSION_VOLTAGE=56" board.flags += "-DHW_VERSION_VOLTAGE=56"
elseif boardversion == "" then elseif boardversion == "" then
error("board version not specified - take a look at tup.config.default") error("board version not specified - take a look at tup.config.default")
else else
@@ -121,22 +127,19 @@ if tup.getconfig("STRICT") == "true" then
end end
-- C-specific flags -- C-specific flags
FLAGS += board.flags
FLAGS += '-D__weak="__attribute__((weak))"' FLAGS += '-D__weak="__attribute__((weak))"'
FLAGS += '-D__packed="__attribute__((__packed__))"' FLAGS += '-D__packed="__attribute__((__packed__))"'
FLAGS += '-DUSE_HAL_DRIVER' FLAGS += '-DUSE_HAL_DRIVER'
FLAGS += '-DSTM32F405xx'
FLAGS += '-mthumb' FLAGS += '-mthumb'
FLAGS += '-mcpu=cortex-m4'
FLAGS += '-mfpu=fpv4-sp-d16'
FLAGS += '-mfloat-abi=hard' FLAGS += '-mfloat-abi=hard'
FLAGS += { '-Wall', '-Wdouble-promotion', '-Wfloat-conversion', '-fdata-sections', '-ffunction-sections'} FLAGS += { '-Wall', '-Wdouble-promotion', '-Wfloat-conversion', '-fdata-sections', '-ffunction-sections'}
-- linker flags -- linker flags
LDFLAGS += '-T'..boarddir..'/STM32F405RGTx_FLASH.ld' LDFLAGS += board.ldflags
LDFLAGS += '-L'..boarddir..'/Drivers/CMSIS/Lib' -- lib dir LDFLAGS += '-lc -lm -lnosys' -- libs
LDFLAGS += '-lc -lm -lnosys -larm_cortexM4lf_math' -- libs LDFLAGS += '-mthumb -mfloat-abi=hard -specs=nosys.specs -specs=nano.specs -u _printf_float -u _scanf_float -Wl,--cref -Wl,--gc-sections'
LDFLAGS += '-mthumb -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -specs=nosys.specs -specs=nano.specs -u _printf_float -u _scanf_float -Wl,--cref -Wl,--gc-sections'
LDFLAGS += '-Wl,--undefined=uxTopUsedPriority' LDFLAGS += '-Wl,--undefined=uxTopUsedPriority'
-- debug build -- debug build
@@ -156,19 +159,18 @@ toolchain = GCCToolchain('arm-none-eabi-', 'build', FLAGS, LDFLAGS)
-- Load list of source files Makefile that was autogenerated by CubeMX -- Load list of source files Makefile that was autogenerated by CubeMX
vars = parse_makefile_vars(boarddir..'/Makefile') vars = parse_makefile_vars(board.dir..'/Makefile')
all_stm_sources = (vars['C_SOURCES'] or '')..' '..(vars['CPP_SOURCES'] or '')..' '..(vars['ASM_SOURCES'] or '') all_stm_sources = (vars['C_SOURCES'] or '')..' '..(vars['CPP_SOURCES'] or '')..' '..(vars['ASM_SOURCES'] or '')
for src in string.gmatch(all_stm_sources, "%S+") do for src in string.gmatch(all_stm_sources, "%S+") do
stm_sources += boarddir..'/'..src stm_sources += board.dir..'/'..src
end end
for src in string.gmatch(vars['C_INCLUDES'] or '', "%S+") do for src in string.gmatch(vars['C_INCLUDES'] or '', "%S+") do
stm_includes += boarddir..'/'..string.sub(src, 3, -1) -- remove "-I" from each include path stm_includes += board.dir..'/'..string.sub(src, 3, -1) -- remove "-I" from each include path
end end
-- TODO: cleaner separation of the platform code and the rest -- TODO: cleaner separation of the platform code and the rest
stm_includes += '.' stm_includes += '.'
stm_includes += 'Drivers/DRV8301' --stm_includes += 'Drivers/DRV8301'
stm_sources += boarddir..'/Src/syscalls.c'
build{ build{
name='stm_platform', name='stm_platform',
type='objects', type='objects',
@@ -178,39 +180,42 @@ build{
includes=stm_includes includes=stm_includes
} }
sources = {
'syscalls.c',
'MotorControl/utils.cpp',
'MotorControl/arm_sin_f32.c',
'MotorControl/arm_cos_f32.c',
'MotorControl/low_level.cpp',
'MotorControl/nvm.c',
'MotorControl/axis.cpp',
'MotorControl/motor.cpp',
'MotorControl/thermistor.cpp',
'MotorControl/encoder.cpp',
'MotorControl/endstop.cpp',
'MotorControl/controller.cpp',
'MotorControl/sensorless_estimator.cpp',
'MotorControl/trapTraj.cpp',
'MotorControl/main.cpp',
'Drivers/STM32/stm32_spi_arbiter.cpp',
'communication/can_simple.cpp',
'communication/communication.cpp',
'communication/ascii_protocol.cpp',
'communication/interface_uart.cpp',
'communication/interface_usb.cpp',
'communication/interface_can.cpp',
'communication/interface_i2c.cpp',
'fibre/cpp/protocol.cpp',
'FreeRTOS-openocd.c',
'autogen/version.c'
}
tup.append_table(sources, board.sources)
build{ build{
name='ODriveFirmware', name='ODriveFirmware',
toolchains={toolchain}, toolchains={toolchain},
--toolchains={LLVMToolchain('x86_64', {'-Ofast'}, {'-flto'})}, --toolchains={LLVMToolchain('x86_64', {'-Ofast'}, {'-flto'})},
packages={'stm_platform'}, packages={'stm_platform'},
sources={ sources=sources,
'Drivers/DRV8301/drv8301.c',
'MotorControl/utils.cpp',
'MotorControl/arm_sin_f32.c',
'MotorControl/arm_cos_f32.c',
'MotorControl/low_level.cpp',
'MotorControl/nvm.c',
'MotorControl/axis.cpp',
'MotorControl/motor.cpp',
'MotorControl/thermistor.cpp',
'MotorControl/encoder.cpp',
'MotorControl/endstop.cpp',
'MotorControl/controller.cpp',
'MotorControl/sensorless_estimator.cpp',
'MotorControl/trapTraj.cpp',
'MotorControl/main.cpp',
'communication/can_simple.cpp',
'communication/communication.cpp',
'communication/ascii_protocol.cpp',
'communication/interface_uart.cpp',
'communication/interface_usb.cpp',
'communication/interface_can.cpp',
'communication/interface_i2c.cpp',
'fibre/cpp/protocol.cpp',
'FreeRTOS-openocd.c',
'autogen/version.c'
},
includes={ includes={
'Drivers/DRV8301', 'Drivers/DRV8301',
'MotorControl', 'MotorControl',
-1
View File
@@ -2,7 +2,6 @@
#define __INTERFACE_CAN_HPP #define __INTERFACE_CAN_HPP
#include <cmsis_os.h> #include <cmsis_os.h>
#include <stm32f4xx_hal.h>
#include "fibre/protocol.hpp" #include "fibre/protocol.hpp"
#include "odrive_main.h" #include "odrive_main.h"
#include "can_helpers.hpp" #include "can_helpers.hpp"
+3 -3
View File
@@ -10,8 +10,8 @@
* a function-oriented approach and a more powerful object model. * a function-oriented approach and a more powerful object model.
* *
*/ */
#ifndef __FIBRE_INTERFACES_HPP #ifndef __FIBRE_ENDPOINTS_HPP
#define __FIBRE_INTERFACES_HPP #define __FIBRE_ENDPOINTS_HPP
#include <fibre/introspection.hpp> #include <fibre/introspection.hpp>
@@ -87,4 +87,4 @@ bool set_endpoint_from_float(endpoint_ref_t endpoint_ref, float value) {
#pragma GCC pop_options #pragma GCC pop_options
#endif // __FIBRE_INTERFACES_HPP #endif // __FIBRE_ENDPOINTS_HPP
@@ -9,6 +9,10 @@
* interfaces. * interfaces.
* *
*/ */
#ifndef __FIBRE_INTERFACES_HPP
#define __FIBRE_INTERFACES_HPP
#include <fibre/protocol.hpp>
#pragma GCC push_options #pragma GCC push_options
#pragma GCC optimize ("s") #pragma GCC optimize ("s")
@@ -92,3 +96,5 @@ inline [[enum.c_name]] operator ~ ([[enum.c_name]] a) { return static_cast<[[enu
#pragma GCC pop_options #pragma GCC pop_options
#endif // __FIBRE_INTERFACES_HPP
+23 -23
View File
@@ -355,6 +355,29 @@ interfaces:
doc: Both axes will have the same id to start doc: Both axes will have the same id to start
can_node_id_extended: bool can_node_id_extended: bool
can_heartbeat_rate_ms: uint32 can_heartbeat_rate_ms: uint32
gate_driver:
c_name: gate_driver_exported_
c_is_class: False
attributes:
drv_fault:
typeargs: {fibre.Property.mode: readonly}
nullflag: NoFault
flags:
FetLowCOvercurrent: {bit: 0, doc: FET Low side, Phase C Over Current fault}
FetHighCOvercurrent: {bit: 1, doc: FET High side, Phase C Over Current fault}
FetLowBOvercurrent: {bit: 2, doc: FET Low side, Phase B Over Current fault}
FetHighBOvercurrent: {bit: 3, doc: FET High side, Phase B Over Current fault}
FetLowAOvercurrent: {bit: 4, doc: FET Low side, Phase A Over Current fault}
FetHighAOvercurrent: {bit: 5, doc: FET High side, Phase A Over Current fault}
OvertemperatureWarning: {bit: 6, doc: Over Temperature Warning fault}
OvertemperatureShutdown: {bit: 7, doc: Over Temperature Shut Down fault}
PVddUndervoltage: {bit: 8, doc: Power supply Vdd Under Voltage fault}
GVddUndervoltage: {bit: 9, doc: DRV8301 Vdd Under Voltage fault}
GVddOvervoltage: {bit: 10, doc: DRV8301 Vdd Over Voltage fault}
# status_reg_1: readonly uint32
# status_reg_2: readonly uint32
# ctrl_reg_1: readonly uint32
# ctrl_reg_2: readonly uint32
fet_thermistor: OnboardThermistorCurrentLimiter fet_thermistor: OnboardThermistorCurrentLimiter
motor_thermistor: OffboardThermistorCurrentLimiter motor_thermistor: OffboardThermistorCurrentLimiter
motor: Motor motor: Motor
@@ -548,29 +571,6 @@ interfaces:
acim_rotor_flux: float32 acim_rotor_flux: float32
async_phase_vel: readonly float32 async_phase_vel: readonly float32
async_phase_offset: float32 async_phase_offset: float32
gate_driver:
c_name: gate_driver_exported_
c_is_class: False
attributes:
drv_fault:
typeargs: {fibre.Property.mode: readonly}
nullflag: NoFault
flags:
FetLowCOvercurrent: {bit: 0, doc: FET Low side, Phase C Over Current fault}
FetHighCOvercurrent: {bit: 1, doc: FET High side, Phase C Over Current fault}
FetLowBOvercurrent: {bit: 2, doc: FET Low side, Phase B Over Current fault}
FetHighBOvercurrent: {bit: 3, doc: FET High side, Phase B Over Current fault}
FetLowAOvercurrent: {bit: 4, doc: FET Low side, Phase A Over Current fault}
FetHighAOvercurrent: {bit: 5, doc: FET High side, Phase A Over Current fault}
OvertemperatureWarning: {bit: 6, doc: Over Temperature Warning fault}
OvertemperatureShutdown: {bit: 7, doc: Over Temperature Shut Down fault}
PVddUndervoltage: {bit: 8, doc: Power supply Vdd Under Voltage fault}
GVddUndervoltage: {bit: 9, doc: DRV8301 Vdd Under Voltage fault}
GVddOvervoltage: {bit: 10, doc: DRV8301 Vdd Over Voltage fault}
# status_reg_1: readonly uint32
# status_reg_2: readonly uint32
# ctrl_reg_1: readonly uint32
# ctrl_reg_2: readonly uint32
timing_log: timing_log:
c_is_class: False c_is_class: False
attributes: attributes:
-14
View File
@@ -107,20 +107,6 @@ ARMED_STATE_WAITING_FOR_TIMINGS = 1
ARMED_STATE_WAITING_FOR_UPDATE = 2 ARMED_STATE_WAITING_FOR_UPDATE = 2
ARMED_STATE_ARMED = 3 ARMED_STATE_ARMED = 3
# ODrive.Motor.GateDriver.DrvFault
DRV_FAULT_NO_FAULT = 0x00000000
DRV_FAULT_FET_LOW_C_OVERCURRENT = 0x00000001
DRV_FAULT_FET_HIGH_C_OVERCURRENT = 0x00000002
DRV_FAULT_FET_LOW_B_OVERCURRENT = 0x00000004
DRV_FAULT_FET_HIGH_B_OVERCURRENT = 0x00000008
DRV_FAULT_FET_LOW_A_OVERCURRENT = 0x00000010
DRV_FAULT_FET_HIGH_A_OVERCURRENT = 0x00000020
DRV_FAULT_OVERTEMPERATURE_WARNING = 0x00000040
DRV_FAULT_OVERTEMPERATURE_SHUTDOWN = 0x00000080
DRV_FAULT_P_VDD_UNDERVOLTAGE = 0x00000100
DRV_FAULT_G_VDD_UNDERVOLTAGE = 0x00000200
DRV_FAULT_G_VDD_OVERVOLTAGE = 0x00000400
# ODrive.Controller.Error # ODrive.Controller.Error
CONTROLLER_ERROR_NONE = 0x00000000 CONTROLLER_ERROR_NONE = 0x00000000
CONTROLLER_ERROR_OVERSPEED = 0x00000001 CONTROLLER_ERROR_OVERSPEED = 0x00000001