diff --git a/Firmware/MotorControl/board_config_v3.h b/Firmware/Board/v3/Inc/board.h similarity index 56% rename from Firmware/MotorControl/board_config_v3.h rename to Firmware/Board/v3/Inc/board.h index 64cbdc78..2dfb9289 100644 --- a/Firmware/MotorControl/board_config_v3.h +++ b/Firmware/Board/v3/Inc/board.h @@ -10,6 +10,9 @@ #include #include #include +#include "cmsis_os.h" + +#include #if HW_VERSION_MAJOR == 3 #if HW_VERSION_MINOR <= 3 @@ -20,6 +23,29 @@ #endif +#ifdef __cplusplus +#include +#include +#include + +using TGateDriver = Drv8301; +using TOpAmp = Drv8301; + +#include + +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 { uint16_t step_gpio_pin; uint16_t dir_gpio_pin; @@ -38,16 +64,6 @@ typedef struct { uint16_t hallC_pin; SPI_HandleTypeDef* spi; } 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 { SPI_HandleTypeDef* spi; GPIO_TypeDef* enable_port; @@ -60,18 +76,12 @@ typedef struct { typedef struct { AxisHardwareConfig_t axis_config; EncoderHardwareConfig_t encoder_config; - MotorHardwareConfig_t motor_config; - ThermistorHardwareConfig_t thermistor_config; - GateDriverHardwareConfig_t gate_driver_config; } BoardHardwareConfig_t; extern const BoardHardwareConfig_t hw_configs[2]; //TODO stick this in a C file #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] = { { //M0 @@ -92,26 +102,6 @@ const BoardHardwareConfig_t hw_configs[2] = { { .hallC_pin = M0_ENC_Z_Pin, .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 .axis_config = { @@ -136,35 +126,9 @@ const BoardHardwareConfig_t hw_configs[2] = { { .hallC_pin = M1_ENC_Z_Pin, .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 - - #define I2C_A0_PORT GPIO_3_GPIO_Port #define I2C_A0_PIN GPIO_3_Pin #define I2C_A1_PORT GPIO_4_GPIO_Port diff --git a/Firmware/Board/v3/board.cpp b/Firmware/Board/v3/board.cpp new file mode 100644 index 00000000..eca62cc1 --- /dev/null +++ b/Firmware/Board/v3/board.cpp @@ -0,0 +1,72 @@ +/* +* @brief Contains board specific variables and initialization functions +*/ + +#include + +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(); + } +} diff --git a/Firmware/Drivers/DRV8301/drv8301.c b/Firmware/Drivers/DRV8301/drv8301.c deleted file mode 100644 index c65cc4d3..00000000 --- a/Firmware/Drivers/DRV8301/drv8301.c +++ /dev/null @@ -1,778 +0,0 @@ -/* --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 "assert.h" -#include -#include "cmsis_os.h" - -// drivers -#include "drv8301.h" - -#include "utils.hpp" - - -// ************************************************************************** -// the defines - - -// ************************************************************************** -// the globals - - -// ************************************************************************** -// the function prototypes - -void DRV8301_enable(DRV8301_Handle handle) -{ - - //Enable driver - HAL_GPIO_WritePin(handle->EngpioHandle, handle->EngpioNumber, GPIO_PIN_SET); - - //Wait for driver to come online - osDelay(10); - - // Make sure the Fault bit is not set during startup - while((DRV8301_readSpi(handle,DRV8301_RegName_Status_1) & DRV8301_STATUS1_FAULT_BITS) != 0); - - // Wait for the DRV8301 registers to update - osDelay(1); - - return; -} - -DRV8301_DcCalMode_e DRV8301_getDcCalMode(DRV8301_Handle handle,const DRV8301_ShuntAmpNumber_e ampNumber) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_2); - - // clear the bits - if(ampNumber == DRV8301_ShuntAmpNumber_1) - { - data &= (~DRV8301_CTRL2_DC_CAL_1_BITS); - - } - else if(ampNumber == DRV8301_ShuntAmpNumber_2) - { - data &= (~DRV8301_CTRL2_DC_CAL_2_BITS); - } - - return((DRV8301_DcCalMode_e)data); -} // end of DRV8301_getDcCalMode() function - - -DRV8301_FaultType_e DRV8301_getFaultType(DRV8301_Handle handle) -{ - DRV8301_Word_t readWord; - DRV8301_FaultType_e faultType = DRV8301_FaultType_NoFault; - - - // read the data - readWord = DRV8301_readSpi(handle,DRV8301_RegName_Status_1); - - if(readWord & DRV8301_STATUS1_FAULT_BITS) - { - faultType = (DRV8301_FaultType_e)(readWord & DRV8301_FAULT_TYPE_MASK); - - if(faultType == DRV8301_FaultType_NoFault) - { - // read the data - readWord = DRV8301_readSpi(handle,DRV8301_RegName_Status_2); - - if(readWord & DRV8301_STATUS2_GVDD_OV_BITS) - { - faultType = DRV8301_FaultType_GVDD_OV; - } - } - } - - return(faultType); -} // end of DRV8301_getFaultType() function - - -uint16_t DRV8301_getId(DRV8301_Handle handle) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Status_2); - - // mask bits - data &= DRV8301_STATUS2_ID_BITS; - - return(data); -} // end of DRV8301_getId() function - - -DRV8301_VdsLevel_e DRV8301_getOcLevel(DRV8301_Handle handle) -{ - uint16_t data; - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_1); - - // clear the bits - data &= (~DRV8301_CTRL1_OC_ADJ_SET_BITS); - - return((DRV8301_VdsLevel_e)data); -} // end of DRV8301_getOcLevel() function - - -DRV8301_OcMode_e DRV8301_getOcMode(DRV8301_Handle handle) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_1); - - // clear the bits - data &= (~DRV8301_CTRL1_OC_MODE_BITS); - - return((DRV8301_OcMode_e)data); -} // end of DRV8301_getOcMode() function - - -DRV8301_OcOffTimeMode_e DRV8301_getOcOffTimeMode(DRV8301_Handle handle) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_2); - - // clear the bits - data &= (~DRV8301_CTRL2_OC_TOFF_BITS); - - return((DRV8301_OcOffTimeMode_e)data); -} // end of DRV8301_getOcOffTimeMode() function - - -DRV8301_OcTwMode_e DRV8301_getOcTwMode(DRV8301_Handle handle) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_2); - - // clear the bits - data &= (~DRV8301_CTRL2_OCTW_SET_BITS); - - return((DRV8301_OcTwMode_e)data); -} // end of DRV8301_getOcTwMode() function - - -DRV8301_PeakCurrent_e DRV8301_getPeakCurrent(DRV8301_Handle handle) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_1); - - // clear the bits - data &= (~DRV8301_CTRL1_GATE_CURRENT_BITS); - - return((DRV8301_PeakCurrent_e)data); -} // end of DRV8301_getPeakCurrent() function - - -DRV8301_PwmMode_e DRV8301_getPwmMode(DRV8301_Handle handle) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_1); - - // clear the bits - data &= (~DRV8301_CTRL1_PWM_MODE_BITS); - - return((DRV8301_PwmMode_e)data); -} // end of DRV8301_getPwmMode() function - - -DRV8301_ShuntAmpGain_e DRV8301_getShuntAmpGain(DRV8301_Handle handle) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_2); - - // clear the bits - data &= (~DRV8301_CTRL2_GAIN_BITS); - - return((DRV8301_ShuntAmpGain_e)data); -} // end of DRV8301_getShuntAmpGain() function - - -DRV8301_Handle DRV8301_init(void *pMemory,const size_t numBytes) -{ - DRV8301_Handle handle; - - - if(numBytes < sizeof(DRV8301_Obj)) - return((DRV8301_Handle)NULL); - - - // assign the handle - handle = (DRV8301_Handle)pMemory; - - DRV8301_resetRxTimeout(handle); - DRV8301_resetEnableTimeout(handle); - - - return(handle); -} // end of DRV8301_init() function - - -void DRV8301_setEnGpioHandle(DRV8301_Handle handle,GPIO_Handle gpioHandle) -{ - DRV8301_Obj *obj = (DRV8301_Obj *)handle; - - // initialize the gpio interface object - obj->EngpioHandle = gpioHandle; - - return; -} // end of DRV8301_setGpioHandle() function - - -void DRV8301_setEnGpioNumber(DRV8301_Handle handle,GPIO_Number_e gpioNumber) -{ - DRV8301_Obj *obj = (DRV8301_Obj *)handle; - - // initialize the gpio interface object - obj->EngpioNumber = gpioNumber; - - return; -} // end of DRV8301_setGpioNumber() function - - -void DRV8301_setnCSGpioHandle(DRV8301_Handle handle,GPIO_Handle gpioHandle) -{ - DRV8301_Obj *obj = (DRV8301_Obj *)handle; - - // initialize the gpio interface object - obj->nCSgpioHandle = gpioHandle; - - return; -} // end of DRV8301_setGpioHandle() function - - -void DRV8301_setnCSGpioNumber(DRV8301_Handle handle,GPIO_Number_e gpioNumber) -{ - DRV8301_Obj *obj = (DRV8301_Obj *)handle; - - // initialize the gpio interface object - obj->nCSgpioNumber = gpioNumber; - - return; -} // end of DRV8301_setGpioNumber() function - - -void DRV8301_setSpiHandle(DRV8301_Handle handle,SPI_Handle spiHandle) -{ - DRV8301_Obj *obj = (DRV8301_Obj *)handle; - - // initialize the serial peripheral interface object - obj->spiHandle = spiHandle; - - return; -} // end of DRV8301_setSpiHandle() function - - -bool DRV8301_isFault(DRV8301_Handle handle) -{ - DRV8301_Word_t readWord; - bool status=false; - - - // read the data - readWord = DRV8301_readSpi(handle,DRV8301_RegName_Status_1); - - if(readWord & DRV8301_STATUS1_FAULT_BITS) - { - status = true; - } - - return(status); -} // end of DRV8301_isFault() function - - -bool DRV8301_isReset(DRV8301_Handle handle) -{ - DRV8301_Word_t readWord; - bool status=false; - - - // read the data - readWord = DRV8301_readSpi(handle,DRV8301_RegName_Control_1); - - if(readWord & DRV8301_CTRL1_GATE_RESET_BITS) - { - status = true; - } - - return(status); -} // end of DRV8301_isReset() function - - -uint16_t DRV8301_readSpi(DRV8301_Handle handle, const DRV8301_RegName_e regName) -{ - - // Actuate chipselect - HAL_GPIO_WritePin(handle->nCSgpioHandle, handle->nCSgpioNumber, GPIO_PIN_RESET); - delay_us(1); - - // Do blocking read - uint16_t zerobuff = 0; - uint16_t controlword = (uint16_t)DRV8301_buildCtrlWord(DRV8301_CtrlMode_Read, regName, 0); - uint16_t recbuff = 0xbeef; - HAL_SPI_Transmit(handle->spiHandle, (uint8_t*)(&controlword), 1, 1000); - - // 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. - // Actuate chipselect - HAL_GPIO_WritePin(handle->nCSgpioHandle, handle->nCSgpioNumber, GPIO_PIN_SET); - delay_us(1); - // Actuate chipselect - HAL_GPIO_WritePin(handle->nCSgpioHandle, handle->nCSgpioNumber, GPIO_PIN_RESET); - delay_us(1); - - HAL_SPI_TransmitReceive(handle->spiHandle, (uint8_t*)(&zerobuff), (uint8_t*)(&recbuff), 1, 1000); - delay_us(1); - - // Actuate chipselect - HAL_GPIO_WritePin(handle->nCSgpioHandle, handle->nCSgpioNumber, GPIO_PIN_SET); - delay_us(1); - - assert(recbuff != 0xbeef); - - return(recbuff & DRV8301_DATA_MASK); -} // end of DRV8301_readSpi() function - - -void DRV8301_reset(DRV8301_Handle handle) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_1); - - // set the bits - data |= DRV8301_CTRL1_GATE_RESET_BITS; - - // write the data - DRV8301_writeSpi(handle,DRV8301_RegName_Control_1,data); - - return; -} // end of DRV8301_reset() function - - -void DRV8301_setDcCalMode(DRV8301_Handle handle,const DRV8301_ShuntAmpNumber_e ampNumber,const DRV8301_DcCalMode_e mode) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_2); - - // clear the bits - if(ampNumber == DRV8301_ShuntAmpNumber_1) - { - data &= (~DRV8301_CTRL2_DC_CAL_1_BITS); - - } - else if(ampNumber == DRV8301_ShuntAmpNumber_2) - { - data &= (~DRV8301_CTRL2_DC_CAL_2_BITS); - } - - // set the bits - data |= mode; - - // write the data - DRV8301_writeSpi(handle,DRV8301_RegName_Control_2,data); - - return; -} // end of DRV8301_setDcCalMode() function - - -void DRV8301_setOcLevel(DRV8301_Handle handle,const DRV8301_VdsLevel_e VdsLevel) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_1); - - // clear the bits - data &= (~DRV8301_CTRL1_OC_ADJ_SET_BITS); - - // set the bits - data |= VdsLevel; - - // write the data - DRV8301_writeSpi(handle,DRV8301_RegName_Control_1,data); - - return; -} // end of DRV8301_setOcLevel() function - - -void DRV8301_setOcMode(DRV8301_Handle handle,const DRV8301_OcMode_e mode) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_1); - - // clear the bits - data &= (~DRV8301_CTRL1_OC_MODE_BITS); - - // set the bits - data |= mode; - - // write the data - DRV8301_writeSpi(handle,DRV8301_RegName_Control_1,data); - - return; -} // end of DRV8301_setOcMode() function - - -void DRV8301_setOcOffTimeMode(DRV8301_Handle handle,const DRV8301_OcOffTimeMode_e mode) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_2); - - // clear the bits - data &= (~DRV8301_CTRL2_OC_TOFF_BITS); - - // set the bits - data |= mode; - - // write the data - DRV8301_writeSpi(handle,DRV8301_RegName_Control_2,data); - - return; -} // end of DRV8301_setOcOffTimeMode() function - - -void DRV8301_setOcTwMode(DRV8301_Handle handle,const DRV8301_OcTwMode_e mode) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_2); - - // clear the bits - data &= (~DRV8301_CTRL2_OCTW_SET_BITS); - - // set the bits - data |= mode; - - // write the data - DRV8301_writeSpi(handle,DRV8301_RegName_Control_2,data); - - return; -} // end of DRV8301_setOcTwMode() function - - -void DRV8301_setPeakCurrent(DRV8301_Handle handle,const DRV8301_PeakCurrent_e peakCurrent) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_1); - - // clear the bits - data &= (~DRV8301_CTRL1_GATE_CURRENT_BITS); - - // set the bits - data |= peakCurrent; - - // write the data - DRV8301_writeSpi(handle,DRV8301_RegName_Control_1,data); - - return; -} // end of DRV8301_setPeakCurrent() function - - -void DRV8301_setPwmMode(DRV8301_Handle handle,const DRV8301_PwmMode_e mode) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_1); - - // clear the bits - data &= (~DRV8301_CTRL1_PWM_MODE_BITS); - - // set the bits - data |= mode; - - // write the data - DRV8301_writeSpi(handle,DRV8301_RegName_Control_1,data); - - return; -} // end of DRV8301_setPwmMode() function - - -void DRV8301_setShuntAmpGain(DRV8301_Handle handle,const DRV8301_ShuntAmpGain_e gain) -{ - uint16_t data; - - - // read data - data = DRV8301_readSpi(handle,DRV8301_RegName_Control_2); - - // clear the bits - data &= (~DRV8301_CTRL2_GAIN_BITS); - - // set the bits - data |= gain; - - // write the data - DRV8301_writeSpi(handle,DRV8301_RegName_Control_2,data); - - return; -} // end of DRV8301_setShuntAmpGain() function - - -void DRV8301_writeSpi(DRV8301_Handle handle, const DRV8301_RegName_e regName,const uint16_t data) -{ - // Actuate chipselect - HAL_GPIO_WritePin(handle->nCSgpioHandle, handle->nCSgpioNumber, GPIO_PIN_RESET); - delay_us(1); - - // Do blocking write - uint16_t controlword = (uint16_t)DRV8301_buildCtrlWord(DRV8301_CtrlMode_Write, regName, data); - HAL_SPI_Transmit(handle->spiHandle, (uint8_t*)(&controlword), 1, 1000); - delay_us(1); - - // Actuate chipselect - HAL_GPIO_WritePin(handle->nCSgpioHandle, handle->nCSgpioNumber, GPIO_PIN_SET); - delay_us(1); - - return; -} // end of DRV8301_writeSpi() function - - -void DRV8301_writeData(DRV8301_Handle handle, DRV_SPI_8301_Vars_t *Spi_8301_Vars) -{ - DRV8301_RegName_e drvRegName; - uint16_t drvDataNew; - - - if(Spi_8301_Vars->SndCmd) - { - // Update Control Register 1 - drvRegName = DRV8301_RegName_Control_1; - drvDataNew = Spi_8301_Vars->Ctrl_Reg_1.DRV8301_CURRENT | \ - Spi_8301_Vars->Ctrl_Reg_1.DRV8301_RESET | \ - Spi_8301_Vars->Ctrl_Reg_1.PWM_MODE | \ - Spi_8301_Vars->Ctrl_Reg_1.OC_MODE | \ - Spi_8301_Vars->Ctrl_Reg_1.OC_ADJ_SET; - DRV8301_writeSpi(handle,drvRegName,drvDataNew); - - // Update Control Register 2 - drvRegName = DRV8301_RegName_Control_2; - drvDataNew = Spi_8301_Vars->Ctrl_Reg_2.OCTW_SET | \ - Spi_8301_Vars->Ctrl_Reg_2.GAIN | \ - Spi_8301_Vars->Ctrl_Reg_2.DC_CAL_CH1p2 | \ - Spi_8301_Vars->Ctrl_Reg_2.OC_TOFF; - DRV8301_writeSpi(handle,drvRegName,drvDataNew); - - Spi_8301_Vars->SndCmd = false; - } - - return; -} // end of DRV8301_writeData() function - - -void DRV8301_readData(DRV8301_Handle handle, DRV_SPI_8301_Vars_t *Spi_8301_Vars) -{ - DRV8301_RegName_e drvRegName; - uint16_t drvDataNew; - - - if(Spi_8301_Vars->RcvCmd) - { - // Update Status Register 1 - drvRegName = DRV8301_RegName_Status_1; - drvDataNew = DRV8301_readSpi(handle,drvRegName); - Spi_8301_Vars->Stat_Reg_1.FAULT = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FAULT_BITS); - Spi_8301_Vars->Stat_Reg_1.GVDD_UV = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_GVDD_UV_BITS); - Spi_8301_Vars->Stat_Reg_1.PVDD_UV = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_PVDD_UV_BITS); - Spi_8301_Vars->Stat_Reg_1.OTSD = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_OTSD_BITS); - Spi_8301_Vars->Stat_Reg_1.OTW = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_OTW_BITS); - Spi_8301_Vars->Stat_Reg_1.FETHA_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETHA_OC_BITS); - Spi_8301_Vars->Stat_Reg_1.FETLA_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETLA_OC_BITS); - Spi_8301_Vars->Stat_Reg_1.FETHB_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETHB_OC_BITS); - Spi_8301_Vars->Stat_Reg_1.FETLB_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETLB_OC_BITS); - Spi_8301_Vars->Stat_Reg_1.FETHC_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETHC_OC_BITS); - Spi_8301_Vars->Stat_Reg_1.FETLC_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETLC_OC_BITS); - Spi_8301_Vars->Stat_Reg_1_Value = drvDataNew; - - // Update Status Register 2 - drvRegName = DRV8301_RegName_Status_2; - drvDataNew = DRV8301_readSpi(handle,drvRegName); - Spi_8301_Vars->Stat_Reg_2.GVDD_OV = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS2_GVDD_OV_BITS); - Spi_8301_Vars->Stat_Reg_2.DeviceID = (uint16_t)(drvDataNew & (uint16_t)DRV8301_STATUS2_ID_BITS); - Spi_8301_Vars->Stat_Reg_2_Value = drvDataNew; - - // Update Control Register 1 - drvRegName = DRV8301_RegName_Control_1; - drvDataNew = DRV8301_readSpi(handle,drvRegName); - Spi_8301_Vars->Ctrl_Reg_1.DRV8301_CURRENT = (DRV8301_PeakCurrent_e)(drvDataNew & (uint16_t)DRV8301_CTRL1_GATE_CURRENT_BITS); - Spi_8301_Vars->Ctrl_Reg_1.DRV8301_RESET = (DRV8301_Reset_e)(drvDataNew & (uint16_t)DRV8301_CTRL1_GATE_RESET_BITS); - Spi_8301_Vars->Ctrl_Reg_1.PWM_MODE = (DRV8301_PwmMode_e)(drvDataNew & (uint16_t)DRV8301_CTRL1_PWM_MODE_BITS); - Spi_8301_Vars->Ctrl_Reg_1.OC_MODE = (DRV8301_OcMode_e)(drvDataNew & (uint16_t)DRV8301_CTRL1_OC_MODE_BITS); - Spi_8301_Vars->Ctrl_Reg_1.OC_ADJ_SET = (DRV8301_VdsLevel_e)(drvDataNew & (uint16_t)DRV8301_CTRL1_OC_ADJ_SET_BITS); - Spi_8301_Vars->Ctrl_Reg_1_Value = drvDataNew; - - // Update Control Register 2 - drvRegName = DRV8301_RegName_Control_2; - drvDataNew = DRV8301_readSpi(handle,drvRegName); - Spi_8301_Vars->Ctrl_Reg_2.OCTW_SET = (DRV8301_OcTwMode_e)(drvDataNew & (uint16_t)DRV8301_CTRL2_OCTW_SET_BITS); - Spi_8301_Vars->Ctrl_Reg_2.GAIN = (DRV8301_ShuntAmpGain_e)(drvDataNew & (uint16_t)DRV8301_CTRL2_GAIN_BITS); - Spi_8301_Vars->Ctrl_Reg_2.DC_CAL_CH1p2 = (DRV8301_DcCalMode_e)(drvDataNew & (uint16_t)(DRV8301_CTRL2_DC_CAL_1_BITS | DRV8301_CTRL2_DC_CAL_2_BITS)); - Spi_8301_Vars->Ctrl_Reg_2.OC_TOFF = (DRV8301_OcOffTimeMode_e)(drvDataNew & (uint16_t)DRV8301_CTRL2_OC_TOFF_BITS); - Spi_8301_Vars->Ctrl_Reg_2_Value = drvDataNew; - Spi_8301_Vars->RcvCmd = false; - } - - return; -} // end of DRV8301_readData() function - - -void DRV8301_setupSpi(DRV8301_Handle handle, DRV_SPI_8301_Vars_t *Spi_8301_Vars) -{ - DRV8301_RegName_e drvRegName; - uint16_t drvDataNew; - -// Why impose hardcoded values? -// Defaults should be device defaults or application level specified. -// Setting other hardcoded here is just confusing! - -#if 0 - // Update Control Register 1 - drvRegName = DRV8301_RegName_Control_1; - drvDataNew = (DRV8301_PeakCurrent_0p25_A | \ - DRV8301_Reset_Normal | \ - DRV8301_PwmMode_Six_Inputs | \ - DRV8301_OcMode_CurrentLimit | \ - DRV8301_VdsLevel_0p730_V); - DRV8301_writeSpi(handle,drvRegName,drvDataNew); - - // Update Control Register 2 - drvRegName = DRV8301_RegName_Control_2; - drvDataNew = (DRV8301_OcTwMode_Both | \ - DRV8301_ShuntAmpGain_10VpV | \ - DRV8301_DcCalMode_Ch1_Load | \ - DRV8301_DcCalMode_Ch2_Load | \ - DRV8301_OcOffTimeMode_Normal); - DRV8301_writeSpi(handle,drvRegName,drvDataNew); -#endif - - - Spi_8301_Vars->SndCmd = false; - Spi_8301_Vars->RcvCmd = false; - - - // Wait for the DRV8301 registers to update - osDelay(1); - - - // Update Status Register 1 - drvRegName = DRV8301_RegName_Status_1; - drvDataNew = DRV8301_readSpi(handle,drvRegName); - Spi_8301_Vars->Stat_Reg_1.FAULT = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FAULT_BITS); - Spi_8301_Vars->Stat_Reg_1.GVDD_UV = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_GVDD_UV_BITS); - Spi_8301_Vars->Stat_Reg_1.PVDD_UV = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_PVDD_UV_BITS); - Spi_8301_Vars->Stat_Reg_1.OTSD = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_OTSD_BITS); - Spi_8301_Vars->Stat_Reg_1.OTW = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_OTW_BITS); - Spi_8301_Vars->Stat_Reg_1.FETHA_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETHA_OC_BITS); - Spi_8301_Vars->Stat_Reg_1.FETLA_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETLA_OC_BITS); - Spi_8301_Vars->Stat_Reg_1.FETHB_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETHB_OC_BITS); - Spi_8301_Vars->Stat_Reg_1.FETLB_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETLB_OC_BITS); - Spi_8301_Vars->Stat_Reg_1.FETHC_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETHC_OC_BITS); - Spi_8301_Vars->Stat_Reg_1.FETLC_OC = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS1_FETLC_OC_BITS); - - // Update Status Register 2 - drvRegName = DRV8301_RegName_Status_2; - drvDataNew = DRV8301_readSpi(handle,drvRegName); - Spi_8301_Vars->Stat_Reg_2.GVDD_OV = (bool)(drvDataNew & (uint16_t)DRV8301_STATUS2_GVDD_OV_BITS); - Spi_8301_Vars->Stat_Reg_2.DeviceID = (uint16_t)(drvDataNew & (uint16_t)DRV8301_STATUS2_ID_BITS); - - // Update Control Register 1 - drvRegName = DRV8301_RegName_Control_1; - drvDataNew = DRV8301_readSpi(handle,drvRegName); - Spi_8301_Vars->Ctrl_Reg_1.DRV8301_CURRENT = (DRV8301_PeakCurrent_e)(drvDataNew & (uint16_t)DRV8301_CTRL1_GATE_CURRENT_BITS); - Spi_8301_Vars->Ctrl_Reg_1.DRV8301_RESET = (DRV8301_Reset_e)(drvDataNew & (uint16_t)DRV8301_CTRL1_GATE_RESET_BITS); - Spi_8301_Vars->Ctrl_Reg_1.PWM_MODE = (DRV8301_PwmMode_e)(drvDataNew & (uint16_t)DRV8301_CTRL1_PWM_MODE_BITS); - Spi_8301_Vars->Ctrl_Reg_1.OC_MODE = (DRV8301_OcMode_e)(drvDataNew & (uint16_t)DRV8301_CTRL1_OC_MODE_BITS); - Spi_8301_Vars->Ctrl_Reg_1.OC_ADJ_SET = (DRV8301_VdsLevel_e)(drvDataNew & (uint16_t)DRV8301_CTRL1_OC_ADJ_SET_BITS); - - // Update Control Register 2 - drvRegName = DRV8301_RegName_Control_2; - drvDataNew = DRV8301_readSpi(handle,drvRegName); - Spi_8301_Vars->Ctrl_Reg_2.OCTW_SET = (DRV8301_OcTwMode_e)(drvDataNew & (uint16_t)DRV8301_CTRL2_OCTW_SET_BITS); - Spi_8301_Vars->Ctrl_Reg_2.GAIN = (DRV8301_ShuntAmpGain_e)(drvDataNew & (uint16_t)DRV8301_CTRL2_GAIN_BITS); - Spi_8301_Vars->Ctrl_Reg_2.DC_CAL_CH1p2 = (DRV8301_DcCalMode_e)(drvDataNew & (uint16_t)(DRV8301_CTRL2_DC_CAL_1_BITS | DRV8301_CTRL2_DC_CAL_2_BITS)); - Spi_8301_Vars->Ctrl_Reg_2.OC_TOFF = (DRV8301_OcOffTimeMode_e)(drvDataNew & (uint16_t)DRV8301_CTRL2_OC_TOFF_BITS); - - return; -} - - -// end of file diff --git a/Firmware/Drivers/DRV8301/drv8301.cpp b/Firmware/Drivers/DRV8301/drv8301.cpp new file mode 100644 index 00000000..a8635c4e --- /dev/null +++ b/Firmware/Drivers/DRV8301/drv8301.cpp @@ -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 +#include +#include + +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, 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 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(®s)) { + 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(®s)) { + 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 & 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; +} diff --git a/Firmware/Drivers/DRV8301/drv8301.h b/Firmware/Drivers/DRV8301/drv8301.h deleted file mode 100644 index e3c3e3f3..00000000 --- a/Firmware/Drivers/DRV8301/drv8301.h +++ /dev/null @@ -1,727 +0,0 @@ -/* --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_H_ -#define _DRV8301_H_ - -//! \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" - -// Port -typedef SPI_HandleTypeDef* SPI_Handle; -typedef GPIO_TypeDef* GPIO_Handle; -typedef uint16_t GPIO_Number_e; - - -//! -//! \defgroup DRV8301 - -//! -//! \ingroup DRV8301 -//@{ - - -#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) - - -// ************************************************************************** -// the typedefs - -//! \brief Enumeration for the R/W modes -//! -typedef enum -{ - DRV8301_CtrlMode_Read = 1 << 15, //!< Read Mode - DRV8301_CtrlMode_Write = 0 << 15 //!< Write Mode -} DRV8301_CtrlMode_e; - - -//! \brief Enumeration for the DC calibration modes -//! -typedef enum -{ - DRV8301_DcCalMode_Ch1_Load = (0 << 4), //!< Shunt amplifier 1 connected to load via input pins - DRV8301_DcCalMode_Ch1_NoLoad = (1 << 4), //!< Shunt amplifier 1 disconnected from load and input pins are shorted - DRV8301_DcCalMode_Ch2_Load = (0 << 5), //!< Shunt amplifier 2 connected to load via input pins - DRV8301_DcCalMode_Ch2_NoLoad = (1 << 5) //!< Shunt amplifier 2 disconnected from load and input pins are shorted -} DRV8301_DcCalMode_e; - - -//! \brief Enumeration for the fault types -//! -typedef enum -{ - DRV8301_FaultType_NoFault = (0 << 0), //!< No fault - DRV8301_FaultType_FETLC_OC = (1 << 0), //!< FET Low side, Phase C Over Current fault - DRV8301_FaultType_FETHC_OC = (1 << 1), //!< FET High side, Phase C Over Current fault - DRV8301_FaultType_FETLB_OC = (1 << 2), //!< FET Low side, Phase B Over Current fault - DRV8301_FaultType_FETHB_OC = (1 << 3), //!< FET High side, Phase B Over Current fault - DRV8301_FaultType_FETLA_OC = (1 << 4), //!< FET Low side, Phase A Over Current fault - DRV8301_FaultType_FETHA_OC = (1 << 5), //!< FET High side, Phase A Over Current fault - DRV8301_FaultType_OTW = (1 << 6), //!< Over Temperature Warning fault - DRV8301_FaultType_OTSD = (1 << 7), //!< Over Temperature Shut Down fault - DRV8301_FaultType_PVDD_UV = (1 << 8), //!< Power supply Vdd Under Voltage fault - DRV8301_FaultType_GVDD_UV = (1 << 9), //!< DRV8301 Vdd Under Voltage fault - DRV8301_FaultType_GVDD_OV = (1 << 10) //!< DRV8301 Vdd Over Voltage fault -} DRV8301_FaultType_e; - - -//! \brief Enumeration for the Over Current modes -//! -typedef enum -{ - DRV8301_OcMode_CurrentLimit = 0 << 4, //!< current limit when OC detected - DRV8301_OcMode_LatchShutDown = 1 << 4, //!< latch shut down when OC detected - DRV8301_OcMode_ReportOnly = 2 << 4, //!< report only when OC detected - DRV8301_OcMode_Disabled = 3 << 4 //!< OC protection disabled -} DRV8301_OcMode_e; - - -//! \brief Enumeration for the Over Current Off Time modes -//! -typedef enum -{ - DRV8301_OcOffTimeMode_Normal = 0 << 6, //!< normal CBC operation - DRV8301_OcOffTimeMode_Ctrl = 1 << 6 //!< off time control during OC -} DRV8301_OcOffTimeMode_e; - - -//! \brief Enumeration for the Over Current, Temperature Warning modes -//! -typedef enum -{ - DRV8301_OcTwMode_Both = 0 << 0, //!< report both OT and OC at /OCTW pin - DRV8301_OcTwMode_OT_Only = 1 << 0, //!< report only OT at /OCTW pin - DRV8301_OcTwMode_OC_Only = 2 << 0 //!< report only OC at /OCTW pin -} DRV8301_OcTwMode_e; - - -//! \brief Enumeration for the drv8301 peak current levels -//! -typedef enum -{ - DRV8301_PeakCurrent_1p70_A = 0 << 0, //!< drv8301 driver peak current 1.70A - DRV8301_PeakCurrent_0p70_A = 1 << 0, //!< drv8301 driver peak current 0.70A - DRV8301_PeakCurrent_0p25_A = 2 << 0 //!< drv8301 driver peak current 0.25A -} DRV8301_PeakCurrent_e; - - -//! \brief Enumeration for the PWM modes -//! -typedef enum -{ - DRV8301_PwmMode_Six_Inputs = 0 << 3, //!< six independent inputs - DRV8301_PwmMode_Three_Inputs = 1 << 3 //!< three independent nputs -} DRV8301_PwmMode_e; - - -//! \brief Enumeration for the register names -//! -typedef enum -{ - DRV8301_RegName_Status_1 = 0 << 11, //!< Status Register 1 - DRV8301_RegName_Status_2 = 1 << 11, //!< Status Register 2 - DRV8301_RegName_Control_1 = 2 << 11, //!< Control Register 1 - DRV8301_RegName_Control_2 = 3 << 11 //!< Control Register 2 -} DRV8301_RegName_e; - - - -//! \brief Enumeration for the shunt amplifier gains -//! -typedef enum -{ - DRV8301_Reset_Normal = 0 << 2, //!< normal - DRV8301_Reset_All = 1 << 2 //!< reset all -} DRV8301_Reset_e; - - -//! \brief Enumeration for the shunt amplifier gains -//! -typedef enum -{ - DRV8301_ShuntAmpGain_10VpV = 0 << 2, //!< 10 V per V - DRV8301_ShuntAmpGain_20VpV = 1 << 2, //!< 20 V per V - DRV8301_ShuntAmpGain_40VpV = 2 << 2, //!< 40 V per V - DRV8301_ShuntAmpGain_80VpV = 3 << 2 //!< 80 V per V -} DRV8301_ShuntAmpGain_e; - - -//! \brief Enumeration for the shunt amplifier number -//! -typedef enum -{ - DRV8301_ShuntAmpNumber_1 = 1, //!< Shunt amplifier number 1 - DRV8301_ShuntAmpNumber_2 = 2 //!< Shunt amplifier number 2 -} DRV8301_ShuntAmpNumber_e; - - -//! \brief Enumeration for the Vds level for th over current adjustment -//! -typedef enum -{ - DRV8301_VdsLevel_0p060_V = 0 << 6, //!< Vds = 0.060 V - DRV8301_VdsLevel_0p068_V = 1 << 6, //!< Vds = 0.068 V - DRV8301_VdsLevel_0p076_V = 2 << 6, //!< Vds = 0.076 V - DRV8301_VdsLevel_0p086_V = 3 << 6, //!< Vds = 0.086 V - DRV8301_VdsLevel_0p097_V = 4 << 6, //!< Vds = 0.097 V - DRV8301_VdsLevel_0p109_V = 5 << 6, //!< Vds = 0.109 V - DRV8301_VdsLevel_0p123_V = 6 << 6, //!< Vds = 0.123 V - DRV8301_VdsLevel_0p138_V = 7 << 6, //!< Vds = 0.138 V - DRV8301_VdsLevel_0p155_V = 8 << 6, //!< Vds = 0.155 V - DRV8301_VdsLevel_0p175_V = 9 << 6, //!< Vds = 0.175 V - DRV8301_VdsLevel_0p197_V = 10 << 6, //!< Vds = 0.197 V - DRV8301_VdsLevel_0p222_V = 11 << 6, //!< Vds = 0.222 V - DRV8301_VdsLevel_0p250_V = 12 << 6, //!< Vds = 0.250 V - DRV8301_VdsLevel_0p282_V = 13 << 6, //!< Vds = 0.282 V - DRV8301_VdsLevel_0p317_V = 14 << 6, //!< Vds = 0.317 V - DRV8301_VdsLevel_0p358_V = 15 << 6, //!< Vds = 0.358 V - DRV8301_VdsLevel_0p403_V = 16 << 6, //!< Vds = 0.403 V - DRV8301_VdsLevel_0p454_V = 17 << 6, //!< Vds = 0.454 V - DRV8301_VdsLevel_0p511_V = 18 << 6, //!< Vds = 0.511 V - DRV8301_VdsLevel_0p576_V = 19 << 6, //!< Vds = 0.576 V - DRV8301_VdsLevel_0p648_V = 20 << 6, //!< Vds = 0.648 V - DRV8301_VdsLevel_0p730_V = 21 << 6, //!< Vds = 0.730 V - DRV8301_VdsLevel_0p822_V = 22 << 6, //!< Vds = 0.822 V - DRV8301_VdsLevel_0p926_V = 23 << 6, //!< Vds = 0.926 V - DRV8301_VdsLevel_1p043_V = 24 << 6, //!< Vds = 1.403 V - DRV8301_VdsLevel_1p175_V = 25 << 6, //!< Vds = 1.175 V - DRV8301_VdsLevel_1p324_V = 26 << 6, //!< Vds = 1.324 V - DRV8301_VdsLevel_1p491_V = 27 << 6, //!< Vds = 1.491 V - DRV8301_VdsLevel_1p679_V = 28 << 6, //!< Vds = 1.679 V - DRV8301_VdsLevel_1p892_V = 29 << 6, //!< Vds = 1.892 V - DRV8301_VdsLevel_2p131_V = 30 << 6, //!< Vds = 2.131 V - DRV8301_VdsLevel_2p400_V = 31 << 6 //!< Vds = 2.400 V -} DRV8301_VdsLevel_e; - - -typedef enum -{ - DRV8301_GETID=0 -} Drv8301SpiOutputDataSelect_e; - - -typedef struct _DRV_SPI_8301_Stat1_t_ -{ - 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; -}DRV_SPI_8301_Stat1_t_; - - -typedef struct _DRV_SPI_8301_Stat2_t_ -{ - bool GVDD_OV; - uint16_t DeviceID; -}DRV_SPI_8301_Stat2_t_; - - -typedef struct _DRV_SPI_8301_CTRL1_t_ -{ - DRV8301_PeakCurrent_e DRV8301_CURRENT; - DRV8301_Reset_e DRV8301_RESET; - DRV8301_PwmMode_e PWM_MODE; - DRV8301_OcMode_e OC_MODE; - DRV8301_VdsLevel_e OC_ADJ_SET; -}DRV_SPI_8301_CTRL1_t_; - - -typedef struct _DRV_SPI_8301_CTRL2_t_ -{ - DRV8301_OcTwMode_e OCTW_SET; - DRV8301_ShuntAmpGain_e GAIN; - DRV8301_DcCalMode_e DC_CAL_CH1p2; - DRV8301_OcOffTimeMode_e OC_TOFF; -}DRV_SPI_8301_CTRL2_t_; - - -typedef struct _DRV_SPI_8301_Vars_t_ -{ - DRV_SPI_8301_Stat1_t_ Stat_Reg_1; - DRV_SPI_8301_Stat2_t_ Stat_Reg_2; - DRV_SPI_8301_CTRL1_t_ Ctrl_Reg_1; - DRV_SPI_8301_CTRL2_t_ 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; - bool SndCmd; - bool RcvCmd; - -}DRV_SPI_8301_Vars_t; - - -//! \brief Defines the DRV8301 object -//! -typedef struct _DRV8301_Obj_ -{ - SPI_Handle spiHandle; //!< the handle for the serial peripheral interface - GPIO_Handle EngpioHandle; //!< the gpio handle that is connected to the drv8301 enable pin - GPIO_Number_e EngpioNumber; //!< the gpio number that is connected to the drv8301 enable pin - GPIO_Handle nCSgpioHandle; //!< the gpio handle that is connected to the drv8301 nCS pin - GPIO_Number_e nCSgpioNumber; //!< the gpio number that is connected to the drv8301 nCS pin - bool RxTimeOut; //!< the timeout flag for the RX fifo - bool enableTimeOut; //!< the timeout flag for drv8301 enable -} DRV8301_Obj; - - -//! \brief Defines the DRV8301 handle -//! -typedef struct _DRV8301_Obj_ *DRV8301_Handle; - - -//! \brief Defines the DRV8301 Word type -//! -typedef uint16_t DRV8301_Word_t; - - -// ************************************************************************** -// the globals - - - -// ************************************************************************** -// the function prototypes - - -//! \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 DRV8301_Word_t DRV8301_buildCtrlWord(const DRV8301_CtrlMode_e ctrlMode, - const DRV8301_RegName_e regName, - const uint16_t data) -{ - DRV8301_Word_t ctrlWord = ctrlMode | regName | (data & DRV8301_DATA_MASK); - - return(ctrlWord); -} // end of DRV8301_buildCtrlWord() function - - -//! \brief Gets the DC calibration mode -//! \param[in] handle The DRV8301 handle -//! \param[in] ampNumber The shunt amplifier number -//! \return The DC calibration mode -extern DRV8301_DcCalMode_e DRV8301_getDcCalMode(DRV8301_Handle handle, - const DRV8301_ShuntAmpNumber_e ampNumber); - -//! \brief Enables the DRV8301 -//! \param[in] handle The DRV8301 handle -extern void DRV8301_enable(DRV8301_Handle handle); - - -//! \brief Gets the fault type -//! \param[in] handle The DRV8301 handle -//! \return The fault type -extern DRV8301_FaultType_e DRV8301_getFaultType(DRV8301_Handle handle); - - -//! \brief Gets the device ID -//! \param[in] handle The DRV8301 handle -//! \return The device ID -extern uint16_t DRV8301_getId(DRV8301_Handle handle); - - -//! \brief Gets the over current level -//! \param[in] handle The DRV8301 handle -//! \return The over current level, V -extern DRV8301_VdsLevel_e DRV8301_getOcLevel(DRV8301_Handle handle); - - -//! \brief Gets the over current mode -//! \param[in] handle The DRV8301 handle -//! \return The over current mode -extern DRV8301_OcMode_e DRV8301_getOcMode(DRV8301_Handle handle); - - -//! \brief Gets the over current off time mode -//! \param[in] handle The DRV8301 handle -//! \return The over current off time mode -extern DRV8301_OcOffTimeMode_e DRV8301_getOcOffTimeMode(DRV8301_Handle handle); - - -//! \brief Gets the over current, temperature warning mode -//! \param[in] handle The DRV8301 handle -//! \return The over current, temperature warning mode -extern DRV8301_OcTwMode_e DRV8301_getOcTwMode(DRV8301_Handle handle); - - -//! \brief Gets the peak current value -//! \param[in] handle The DRV8301 handle -//! \return The peak current value -extern DRV8301_PeakCurrent_e DRV8301_getPeakCurrent(DRV8301_Handle handle); - - -//! \brief Gets the PWM mode -//! \param[in] handle The DRV8301 handle -//! \return The PWM mode -extern DRV8301_PwmMode_e DRV8301_getPwmMode(DRV8301_Handle handle); - - -//! \brief Gets the shunt amplifier gain value -//! \param[in] handle The DRV8301 handle -//! \return The shunt amplifier gain value -extern DRV8301_ShuntAmpGain_e DRV8301_getShuntAmpGain(DRV8301_Handle handle); - - -//! \brief Gets the status register 1 value -//! \param[in] handle The DRV8301 handle -//! \return The status register1 value -extern uint16_t DRV8301_getStatusRegister1(DRV8301_Handle handle); - - -//! \brief Gets the status register 2 value -//! \param[in] handle The DRV8301 handle -//! \return The status register2 value -extern uint16_t DRV8301_getStatusRegister2(DRV8301_Handle handle); - - -//! \brief Initializes the DRV8301 object -//! \param[in] pMemory A pointer to the memory for the DRV8301 object -//! \param[in] numBytes The number of bytes allocated for the DRV8301 object, bytes -//! \return The DRV8301 object handle -extern DRV8301_Handle DRV8301_init(void *pMemory,const size_t numBytes); - - -//! \brief Determines if DRV8301 fault has occurred -//! \param[in] handle The DRV8301 handle -//! \return A boolean value denoting if a fault has occurred (true) or not (false) -extern bool DRV8301_isFault(DRV8301_Handle handle); - - -//! \brief Determines if DRV8301 is in reset -//! \param[in] handle The DRV8301 handle -//! \return A boolean value denoting if the DRV8301 is in reset (true) or not (false) -extern bool DRV8301_isReset(DRV8301_Handle handle); - - -//! \brief Reads data from the DRV8301 register -//! \param[in] handle The DRV8301 handle -//! \param[in] regName The register name -//! \return The data value -extern uint16_t DRV8301_readSpi(DRV8301_Handle handle,const DRV8301_RegName_e regName); - - -//! \brief Resets the DRV8301 -//! \param[in] handle The DRV8301 handle -extern void DRV8301_reset(DRV8301_Handle handle); - - -//! \brief Resets the enable timeout flag -//! \param[in] handle The DRV8301 handle -static inline void DRV8301_resetEnableTimeout(DRV8301_Handle handle) -{ - DRV8301_Obj *obj = (DRV8301_Obj *)handle; - - obj->enableTimeOut = false; - - return; -} - - -//! \brief Resets the RX fifo timeout flag -//! \param[in] handle The DRV8301 handle -static inline void DRV8301_resetRxTimeout(DRV8301_Handle handle) -{ - DRV8301_Obj *obj = (DRV8301_Obj *)handle; - - obj->RxTimeOut = false; - - return; -} - - -//! \brief Sets the DC calibration mode -//! \param[in] handle The DRV8301 handle -//! \param[in] ampNumber The shunt amplifier number -//! \param[in] mode The DC calibration mode -extern void DRV8301_setDcCalMode(DRV8301_Handle handle, - const DRV8301_ShuntAmpNumber_e ampNumber, - const DRV8301_DcCalMode_e mode); - - -//! \brief Sets the GPIO handle in the DRV8301 -//! \param[in] handle The DRV8301 handle -//! \param[in] gpioHandle The GPIO handle to use -void DRV8301_setGpioHandle(DRV8301_Handle handle,GPIO_Handle gpioHandle); - - -//! \brief Sets the GPIO number in the DRV8301 -//! \param[in] handle The DRV8301 handle -//! \param[in] gpioHandle The GPIO number to use -void DRV8301_setGpioNumber(DRV8301_Handle handle,GPIO_Number_e gpioNumber); - - -//! \brief Sets the over current level in terms of Vds -//! \param[in] handle The DRV8301 handle -//! \param[in] VdsLevel The over current level, V -extern void DRV8301_setOcLevel(DRV8301_Handle handle,const DRV8301_VdsLevel_e VdsLevel); - - -//! \brief Sets the over current mode -//! \param[in] handle The DRV8301 handle -//! \param[in] mode The over current mode -extern void DRV8301_setOcMode(DRV8301_Handle handle,const DRV8301_OcMode_e mode); - - -//! \brief Sets the over current off time mode -//! \param[in] handle The DRV8301 handle -//! \param[in] mode The over current off time mode -extern void DRV8301_setOcOffTimeMode(DRV8301_Handle handle,const DRV8301_OcOffTimeMode_e mode); - - -//! \brief Sets the over current, temperature warning mode -//! \param[in] handle The DRV8301 handle -//! \param[in] mode The over current, temperature warning mode -extern void DRV8301_setOcTwMode(DRV8301_Handle handle,const DRV8301_OcTwMode_e mode); - - -//! \brief Sets the peak current value -//! \param[in] handle The DRV8301 handle -//! \param[in] peakCurrent The peak current value -extern void DRV8301_setPeakCurrent(DRV8301_Handle handle,const DRV8301_PeakCurrent_e peakCurrent); - - -//! \brief Sets the PWM mode -//! \param[in] handle The DRV8301 handle -//! \param[in] mode The PWM mode -extern void DRV8301_setPwmMode(DRV8301_Handle handle,const DRV8301_PwmMode_e mode); - - -//! \brief Sets the shunt amplifier gain value -//! \param[in] handle The DRV8301 handle -//! \param[in] gain The shunt amplifier gain value -extern void DRV8301_setShuntAmpGain(DRV8301_Handle handle,const DRV8301_ShuntAmpGain_e gain); - - -//! \brief Sets the SPI handle in the DRV8301 -//! \param[in] handle The DRV8301 handle -//! \param[in] spiHandle The SPI handle to use -void DRV8301_setSpiHandle(DRV8301_Handle handle,SPI_Handle spiHandle); - - -//! \brief Writes data to the DRV8301 register -//! \param[in] handle The DRV8301 handle -//! \param[in] regName The register name -//! \param[in] data The data value -extern void DRV8301_writeSpi(DRV8301_Handle handle,const DRV8301_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 DRV_SPI_8301_Vars_t. -//! How to use in Setup -//! Code -//! Add the structure declaration DRV_SPI_8301_Vars_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 -//! How to use in Runtime -//! Watch window -//! Add the structure, declared by DRV_SPI_8301_Vars_t above, to the watch window -//! Runtime -//! Pull down the menus from the DRV_SPI_8301_Vars_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] handle The DRV8301 handle -//! \param[in] Spi_8301_Vars The (DRV_SPI_8301_Vars_t) structure that contains all DRV8301 Status/Control register options -extern void DRV8301_writeData(DRV8301_Handle handle, DRV_SPI_8301_Vars_t *Spi_8301_Vars); - - -//! \param[in] handle The DRV8301 handle -//! \param[in] Spi_8301_Vars The (DRV_SPI_8301_Vars_t) structure that contains all DRV8301 Status/Control register options -extern void DRV8301_readData(DRV8301_Handle handle, DRV_SPI_8301_Vars_t *Spi_8301_Vars); - - -//! \brief Initialize the interface to all 8301 SPI variables -//! \param[in] handle The DRV8301 handle -extern void DRV8301_setupSpi(DRV8301_Handle handle, DRV_SPI_8301_Vars_t *Spi_8301_Vars); - - -#ifdef __cplusplus -} -#endif // extern "C" - -//@} // ingroup - -#endif // end of _DRV8301_H_ definition - - - - - diff --git a/Firmware/Drivers/DRV8301/drv8301.hpp b/Firmware/Drivers/DRV8301/drv8301.hpp new file mode 100644 index 00000000..155a6d41 --- /dev/null +++ b/Firmware/Drivers/DRV8301/drv8301.hpp @@ -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 +#include +#include + + +#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. + //! How to use in Setup + //! Code + //! 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 + //! How to use in Runtime + //! Watch window + //! Add the structure, declared by Registers_t above, to the watch window + //! Runtime + //! 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_ diff --git a/Firmware/Drivers/STM32/stm32_gpio.hpp b/Firmware/Drivers/STM32/stm32_gpio.hpp new file mode 100644 index 00000000..e5636fc6 --- /dev/null +++ b/Firmware/Drivers/STM32/stm32_gpio.hpp @@ -0,0 +1,25 @@ +#ifndef STM32_GPIO_HPP__ +#define STM32_GPIO_HPP__ + +#include + +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__ diff --git a/Firmware/Drivers/STM32/stm32_spi_arbiter.cpp b/Firmware/Drivers/STM32/stm32_spi_arbiter.cpp new file mode 100644 index 00000000..093e1453 --- /dev/null +++ b/Firmware/Drivers/STM32/stm32_spi_arbiter.cpp @@ -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(); + } +} diff --git a/Firmware/Drivers/STM32/stm32_spi_arbiter.hpp b/Firmware/Drivers/STM32/stm32_spi_arbiter.hpp new file mode 100644 index 00000000..59c1772a --- /dev/null +++ b/Firmware/Drivers/STM32/stm32_spi_arbiter.hpp @@ -0,0 +1,56 @@ +#ifndef SPI_ARBITER_HPP__ +#define SPI_ARBITER_HPP__ + +#include "stm32_gpio.hpp" + +#include + +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 \ No newline at end of file diff --git a/Firmware/Drivers/STM32/stm32_system.h b/Firmware/Drivers/STM32/stm32_system.h new file mode 100644 index 00000000..d7cc14e5 --- /dev/null +++ b/Firmware/Drivers/STM32/stm32_system.h @@ -0,0 +1,16 @@ +#ifndef __STM32_SYSTEM_H +#define __STM32_SYSTEM_H + +#include + +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 \ No newline at end of file diff --git a/Firmware/Drivers/gate_driver.hpp b/Firmware/Drivers/gate_driver.hpp new file mode 100644 index 00000000..a95ffaf6 --- /dev/null +++ b/Firmware/Drivers/gate_driver.hpp @@ -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 \ No newline at end of file diff --git a/Firmware/MotorControl/arm_cos_f32.c b/Firmware/MotorControl/arm_cos_f32.c index a63d14cb..80f7e1ad 100644 --- a/Firmware/MotorControl/arm_cos_f32.c +++ b/Firmware/MotorControl/arm_cos_f32.c @@ -25,10 +25,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include // Sets up the correct chip specifc defines required by arm_math -#define ARM_MATH_CM4 // TODO: might change in future board versions + +#include #include "arm_math.h" #include "arm_common_tables.h" + /** * @ingroup groupFastMath */ diff --git a/Firmware/MotorControl/arm_sin_f32.c b/Firmware/MotorControl/arm_sin_f32.c index f037248f..baec2318 100644 --- a/Firmware/MotorControl/arm_sin_f32.c +++ b/Firmware/MotorControl/arm_sin_f32.c @@ -26,8 +26,7 @@ * limitations under the License. */ -#include // Sets up the correct chip specifc defines required by arm_math -#define ARM_MATH_CM4 // TODO: might change in future board versions +#include #include "arm_math.h" #include "arm_common_tables.h" diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index f66f8f32..c6a7602f 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -87,8 +87,8 @@ static void step_cb_wrapper(void* ctx) { // @brief Sets up all components of the axis, // such as gate driver and encoder hardware. -void Axis::setup() { - motor_.setup(); +bool Axis::setup() { + return motor_.setup(); } static void run_state_machine_loop_wrapper(void* ctx) { diff --git a/Firmware/MotorControl/axis.hpp b/Firmware/MotorControl/axis.hpp index 2c749fa6..f35c11e2 100644 --- a/Firmware/MotorControl/axis.hpp +++ b/Firmware/MotorControl/axis.hpp @@ -1,9 +1,15 @@ #ifndef __AXIS_HPP #define __AXIS_HPP -#ifndef __ODRIVE_MAIN_H -#error "This file should not be included directly. Include odrive_main.h instead." -#endif +class Axis; + +#include "encoder.hpp" +#include "sensorless_estimator.hpp" +#include "controller.hpp" +#include "trapTraj.hpp" +#include "endstop.hpp" +#include "low_level.h" +#include "utils.hpp" #include @@ -84,7 +90,7 @@ public: Endstop& min_endstop, Endstop& max_endstop); - void setup(); + bool setup(); void start_thread(); void signal_current_meas(); bool wait_for_current_meas(); diff --git a/Firmware/MotorControl/controller.hpp b/Firmware/MotorControl/controller.hpp index 0b692450..b1b80afd 100644 --- a/Firmware/MotorControl/controller.hpp +++ b/Firmware/MotorControl/controller.hpp @@ -1,10 +1,6 @@ #ifndef __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 { public: typedef struct { diff --git a/Firmware/MotorControl/current_limiter.hpp b/Firmware/MotorControl/current_limiter.hpp index 4334f5c0..acb96f0b 100644 --- a/Firmware/MotorControl/current_limiter.hpp +++ b/Firmware/MotorControl/current_limiter.hpp @@ -1,10 +1,6 @@ #ifndef __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 { public: virtual ~CurrentLimiter() = default; diff --git a/Firmware/MotorControl/encoder.cpp b/Firmware/MotorControl/encoder.cpp index 97801945..62bb0b13 100644 --- a/Firmware/MotorControl/encoder.cpp +++ b/Firmware/MotorControl/encoder.cpp @@ -1,5 +1,6 @@ #include "odrive_main.h" +#include Encoder::Encoder(const EncoderHardwareConfig_t& hw_config, diff --git a/Firmware/MotorControl/encoder.hpp b/Firmware/MotorControl/encoder.hpp index cb97a45b..e3c99c81 100644 --- a/Firmware/MotorControl/encoder.hpp +++ b/Firmware/MotorControl/encoder.hpp @@ -1,9 +1,7 @@ #ifndef __ENCODER_HPP #define __ENCODER_HPP -#ifndef __ODRIVE_MAIN_H -#error "This file should not be included directly. Include odrive_main.h instead." -#endif +#include "utils.hpp" class Encoder : public ODriveIntf::EncoderIntf { public: diff --git a/Firmware/MotorControl/low_level.cpp b/Firmware/MotorControl/low_level.cpp index b6cd64be..25b3e9e5 100644 --- a/Firmware/MotorControl/low_level.cpp +++ b/Firmware/MotorControl/low_level.cpp @@ -4,7 +4,7 @@ // otherwise chip specific defines are ommited #include #include // Sets up the correct chip specifc defines required by arm_math -#define ARM_MATH_CM4 +#include #include #include @@ -114,7 +114,7 @@ bool safety_critical_disarm_motor_pwm(Motor& motor) { uint32_t mask = cpu_enter_critical(); bool was_armed = 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); 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.hw_config_.timer->Instance->CCR1 = timings[0]; - motor.hw_config_.timer->Instance->CCR2 = timings[1]; - motor.hw_config_.timer->Instance->CCR3 = timings[2]; + motor.timer_->Instance->CCR1 = timings[0]; + motor.timer_->Instance->CCR2 = timings[1]; + motor.timer_->Instance->CCR3 = timings[2]; if (motor.armed_state_ == Motor::ARMED_STATE_WAITING_FOR_TIMINGS) { // 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 // enable the actual PWM outputs. 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) { // nothing to do, PWM is running, all good } else { @@ -508,7 +508,7 @@ void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { Axis& axis = injected ? *axes[0] : *axes[1]; int axis_num = injected ? 0 : 1; 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; // Check the timing of the sequencing @@ -812,7 +812,7 @@ void start_analog_thread() { osThreadCreate(osThread(thread_def), NULL); } - +/* void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) { 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_) axes[1]->encoder_.abs_spi_cb(); } +*/ \ No newline at end of file diff --git a/Firmware/MotorControl/low_level.h b/Firmware/MotorControl/low_level.h index 11494cbf..6e972856 100644 --- a/Firmware/MotorControl/low_level.h +++ b/Firmware/MotorControl/low_level.h @@ -2,10 +2,6 @@ #ifndef __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 extern "C" { #endif @@ -59,16 +55,6 @@ void start_analog_thread(); 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 } #endif diff --git a/Firmware/MotorControl/main.cpp b/Firmware/MotorControl/main.cpp index 2809f5da..dac1be28 100644 --- a/Firmware/MotorControl/main.cpp +++ b/Firmware/MotorControl/main.cpp @@ -14,8 +14,6 @@ ODriveCAN::Config_t can_config; Encoder::Config_t encoder_configs[AXIS_COUNT]; SensorlessEstimator::Config_t sensorless_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]; Axis::Config_t axis_configs[AXIS_COUNT]; TrapezoidalTrajectory::Config_t trap_configs[AXIS_COUNT]; @@ -32,8 +30,8 @@ typedef Config< Encoder::Config_t[AXIS_COUNT], SensorlessEstimator::Config_t[AXIS_COUNT], Controller::Config_t[AXIS_COUNT], - Motor::Config_t[AXIS_COUNT], - OnboardThermistorCurrentLimiter::Config_t[AXIS_COUNT], + Motor::Config_t, Motor::Config_t, + OnboardThermistorCurrentLimiter::Config_t, OnboardThermistorCurrentLimiter::Config_t, OffboardThermistorCurrentLimiter::Config_t[AXIS_COUNT], TrapezoidalTrajectory::Config_t[AXIS_COUNT], Endstop::Config_t[AXIS_COUNT], @@ -47,8 +45,10 @@ void ODrive::save_configuration(void) { &encoder_configs, &sensorless_configs, &controller_configs, - &motor_configs, - &fet_thermistor_configs, + &m0.config_, + &m1.config_, + &m0_fet_thermistor.config_, + &m1_fet_thermistor.config_, &motor_thermistor_configs, &trap_configs, &min_endstop_configs, @@ -69,8 +69,10 @@ extern "C" int load_configuration(void) { &encoder_configs, &sensorless_configs, &controller_configs, - &motor_configs, - &fet_thermistor_configs, + &m0.config_, + &m1.config_, + &m0_fet_thermistor.config_, + &m1_fet_thermistor.config_, &motor_thermistor_configs, &trap_configs, &min_endstop_configs, @@ -79,12 +81,14 @@ extern "C" int load_configuration(void) { //If loading failed, restore defaults odrv.config_ = BoardConfig_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) { encoder_configs[i] = Encoder::Config_t(); sensorless_configs[i] = SensorlessEstimator::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(); trap_configs[i] = TrapezoidalTrajectory::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); #endif + m0.reload_config(); + m1.reload_config(); + // Construct all objects. odCAN = new ODriveCAN(can_config, &hcan1); for (size_t i = 0; i < AXIS_COUNT; ++i) { 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]); 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]); - - 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]); Endstop *min_endstop = new Endstop(min_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], - *encoder, *sensorless_estimator, *controller, *fet_thermistor, - *motor_thermistor, *motor, *trap, *min_endstop, *max_endstop); + *encoder, *sensorless_estimator, *controller, i ? m1_fet_thermistor : m0_fet_thermistor, *motor_thermistor, i ? m1 : m0, *trap, *min_endstop, *max_endstop); controller_configs[i].parent = controller; encoder_configs[i].parent = encoder; motor_thermistor_configs[i].parent = motor_thermistor; - motor_configs[i].parent = motor; min_endstop_configs[i].parent = min_endstop; max_endstop_configs[i].parent = max_endstop; axis_configs[i].parent = axes[i]; @@ -264,7 +262,9 @@ int odrive_main(void) { // Setup hardware for all components 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){ diff --git a/Firmware/MotorControl/motor.cpp b/Firmware/MotorControl/motor.cpp index a27ed5b1..89d01b1d 100644 --- a/Firmware/MotorControl/motor.cpp +++ b/Firmware/MotorControl/motor.cpp @@ -1,24 +1,22 @@ +#include "motor.hpp" +#include "axis.hpp" +#include "low_level.h" +#include "odrive_main.h" + #include -#include "drv8301.h" -#include "odrive_main.h" - - -Motor::Motor(const MotorHardwareConfig_t& hw_config, - const GateDriverHardwareConfig_t& gate_driver_config, - Config_t& config) : - hw_config_(hw_config), - gate_driver_config_(gate_driver_config), - config_(config), - gate_driver_({ - .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(); +Motor::Motor(TIM_HandleTypeDef* timer, + uint16_t control_deadline, + float shunt_conductance, + TGateDriver& gate_driver, + TOpAmp& opamp) : + timer_(timer), + control_deadline_(control_deadline), + shunt_conductance_(shunt_conductance), + gate_driver_(gate_driver), + opamp_(opamp) { + reload_config(); } // @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; } -// @brief Set up the gate drivers -void Motor::DRV8301_setup() { - // 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 +void Motor::reload_config() { + config_.parent = this; + is_calibrated_ = config_.pre_calibrated; + update_current_controller_gains(); +} +// @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 // or largest possible range otherwise 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 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] - - // Decoding array for snapping gain - std::array, 4> gain_choices = { - std::make_pair(10.0f, DRV8301_ShuntAmpGain_10VpV), - std::make_pair(20.0f, DRV8301_ShuntAmpGain_20VpV), - 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 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; + + float actual_gain = NAN; + bool success = opamp_.set_gain(requested_gain, &actual_gain); + if (!success) + return false; // 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 current_control_.max_allowed_current = max_unity_gain_current * phase_current_rev_gain_; // Set trip level 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; } @@ -145,7 +102,7 @@ void Motor::set_error(Motor::Error error){ } bool Motor::do_checks() { - if (!check_DRV_fault()) { + if (!gate_driver_.check_fault()) { set_error(ERROR_DRV_FAULT); return false; } @@ -201,7 +158,7 @@ float Motor::phase_current_from_adcval(uint32_t ADCValue) { int adcval_bal = (int)ADCValue - (1 << 11); float amp_out_volt = (3.3f / (float)(1 << 12)) * (float)adcval_bal; 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; } diff --git a/Firmware/MotorControl/motor.hpp b/Firmware/MotorControl/motor.hpp index 85c2c1e9..991a4cab 100644 --- a/Firmware/MotorControl/motor.hpp +++ b/Firmware/MotorControl/motor.hpp @@ -1,11 +1,31 @@ #ifndef __MOTOR_HPP #define __MOTOR_HPP -#ifndef __ODRIVE_MAIN_H -#error "This file should not be included directly. Include odrive_main.h instead." +class Axis; // declared in axis.hpp +class Motor; + +#include + +#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 -#include "drv8301.h" +#include class Motor : public ODriveIntf::MotorIntf { public: @@ -76,20 +96,19 @@ public: void set_current_control_bandwidth(float value) { current_control_bandwidth = value; parent->update_current_controller_gains(); } }; - Motor(const MotorHardwareConfig_t& hw_config, - const GateDriverHardwareConfig_t& gate_driver_config, - Config_t& config); + Motor(TIM_HandleTypeDef* timer, + uint16_t control_deadline, + float shunt_conductance, + TGateDriver& gate_driver, + TOpAmp& opamp); bool arm(); void disarm(); - void setup() { - DRV8301_setup(); - } + void reload_config(); + bool setup(); void reset_current_control(); void update_current_controller_gains(); - void DRV8301_setup(); - bool check_DRV_fault(); void set_error(Error error); bool do_checks(); 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 update(float current_setpoint, float phase, float phase_vel); - const MotorHardwareConfig_t& hw_config_; - const GateDriverHardwareConfig_t gate_driver_config_; - Config_t& config_; + // hardware 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 //private: - DRV8301_Obj gate_driver_; // initialized in constructor uint16_t next_timings_[3] = { TIM_1_8_PERIOD_CLOCKS / 2, TIM_1_8_PERIOD_CLOCKS / 2, @@ -155,11 +179,7 @@ public: .async_phase_vel = 0.0f, .async_phase_offset = 0.0f, }; - struct : GateDriverIntf { - 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; + float effective_current_lim_ = 10.0f; // [A] }; #endif // __MOTOR_HPP diff --git a/Firmware/MotorControl/odrive_main.h b/Firmware/MotorControl/odrive_main.h index 392b9c7e..8d768bc8 100644 --- a/Firmware/MotorControl/odrive_main.h +++ b/Firmware/MotorControl/odrive_main.h @@ -1,12 +1,8 @@ #ifndef __ODRIVE_MAIN_H #define __ODRIVE_MAIN_H -// Note on central include scheme by Samuel: -// there are circular dependencies between some of the header files, -// 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 +// Hardware configuration +#include #ifdef __cplusplus #include @@ -19,28 +15,13 @@ extern "C" { #include // Sets up the correct chip specifc defines required by arm_math #include #include -#define ARM_MATH_CM4 // TODO: might change in future board versions -#include // OS includes #include -// 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 #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 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(~static_cast>(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" @@ -201,7 +166,6 @@ enum TimingLog_t { #include #include #include -#include #include #include #include diff --git a/Firmware/MotorControl/thermistor.cpp b/Firmware/MotorControl/thermistor.cpp index 68656315..5b1e425a 100644 --- a/Firmware/MotorControl/thermistor.cpp +++ b/Firmware/MotorControl/thermistor.cpp @@ -49,14 +49,13 @@ float ThermistorCurrentLimiter::get_current_limit(float base_current_lim) const return std::min(thermal_current_lim, base_current_lim); } -OnboardThermistorCurrentLimiter::OnboardThermistorCurrentLimiter(const ThermistorHardwareConfig_t& hw_config, Config_t& config) : - ThermistorCurrentLimiter(hw_config.adc_ch, - hw_config.coeffs, - hw_config.num_coeffs, - config.temp_limit_lower, - config.temp_limit_upper, - config.enabled), - config_(config) +OnboardThermistorCurrentLimiter::OnboardThermistorCurrentLimiter(uint16_t adc_channel, const float* const coefficients, size_t num_coeffs) : + ThermistorCurrentLimiter(adc_channel, + coefficients, + num_coeffs, + config_.temp_limit_lower, + config_.temp_limit_upper, + config_.enabled) { } diff --git a/Firmware/MotorControl/thermistor.hpp b/Firmware/MotorControl/thermistor.hpp index c403f189..5a703654 100644 --- a/Firmware/MotorControl/thermistor.hpp +++ b/Firmware/MotorControl/thermistor.hpp @@ -1,10 +1,31 @@ #ifndef __THERMISTOR_HPP #define __THERMISTOR_HPP -#ifndef __ODRIVE_MAIN_H -#error "This file should not be included directly. Include odrive_main.h instead." +class Axis; // declared in axis.hpp + +#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 +#include + class ThermistorCurrentLimiter : public CurrentLimiter, public ODriveIntf::ThermistorCurrentLimiterIntf { public: virtual ~ThermistorCurrentLimiter() = default; @@ -23,7 +44,7 @@ public: uint16_t adc_channel_; const float* const coefficients_; 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_upper_; const bool& enabled_; @@ -40,9 +61,9 @@ public: }; 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 { diff --git a/Firmware/Tupfile.lua b/Firmware/Tupfile.lua index bf077598..9dc03669 100644 --- a/Firmware/Tupfile.lua +++ b/Firmware/Tupfile.lua @@ -34,45 +34,51 @@ tup.frule{ 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 boardversion = tup.getconfig("BOARD_VERSION") if boardversion == "v3.1" then - boarddir = 'Board/v3' -- currently all platform code is in the same v3.3 directory - FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=1" - FLAGS += "-DHW_VERSION_VOLTAGE=24" + board = board_v3 + board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=1" + board.flags += "-DHW_VERSION_VOLTAGE=24" elseif boardversion == "v3.2" then - boarddir = 'Board/v3' - FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=2" - FLAGS += "-DHW_VERSION_VOLTAGE=24" + board = board_v3 + board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=2" + board.flags += "-DHW_VERSION_VOLTAGE=24" elseif boardversion == "v3.3" then - boarddir = 'Board/v3' - FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=3" - FLAGS += "-DHW_VERSION_VOLTAGE=24" + board = board_v3 + board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=3" + board.flags += "-DHW_VERSION_VOLTAGE=24" elseif boardversion == "v3.4-24V" then - boarddir = 'Board/v3' - FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=4" - FLAGS += "-DHW_VERSION_VOLTAGE=24" + board = board_v3 + board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=4" + board.flags += "-DHW_VERSION_VOLTAGE=24" elseif boardversion == "v3.4-48V" then - boarddir = 'Board/v3' - FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=4" - FLAGS += "-DHW_VERSION_VOLTAGE=48" + board = board_v3 + board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=4" + board.flags += "-DHW_VERSION_VOLTAGE=48" elseif boardversion == "v3.5-24V" then - boarddir = 'Board/v3' - FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=5" - FLAGS += "-DHW_VERSION_VOLTAGE=24" + board = board_v3 + board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=5" + board.flags += "-DHW_VERSION_VOLTAGE=24" elseif boardversion == "v3.5-48V" then - boarddir = 'Board/v3' - FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=5" - FLAGS += "-DHW_VERSION_VOLTAGE=48" + board = board_v3 + board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=5" + board.flags += "-DHW_VERSION_VOLTAGE=48" elseif boardversion == "v3.6-24V" then - boarddir = 'Board/v3' - FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=6" - FLAGS += "-DHW_VERSION_VOLTAGE=24" + board = board_v3 + board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=6" + board.flags += "-DHW_VERSION_VOLTAGE=24" elseif boardversion == "v3.6-56V" then - boarddir = 'Board/v3' - FLAGS += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=6" - FLAGS += "-DHW_VERSION_VOLTAGE=56" + board = board_v3 + board.flags += "-DHW_VERSION_MAJOR=3 -DHW_VERSION_MINOR=6" + board.flags += "-DHW_VERSION_VOLTAGE=56" elseif boardversion == "" then error("board version not specified - take a look at tup.config.default") else @@ -121,22 +127,19 @@ if tup.getconfig("STRICT") == "true" then end -- C-specific flags +FLAGS += board.flags FLAGS += '-D__weak="__attribute__((weak))"' FLAGS += '-D__packed="__attribute__((__packed__))"' FLAGS += '-DUSE_HAL_DRIVER' -FLAGS += '-DSTM32F405xx' FLAGS += '-mthumb' -FLAGS += '-mcpu=cortex-m4' -FLAGS += '-mfpu=fpv4-sp-d16' FLAGS += '-mfloat-abi=hard' FLAGS += { '-Wall', '-Wdouble-promotion', '-Wfloat-conversion', '-fdata-sections', '-ffunction-sections'} -- linker flags -LDFLAGS += '-T'..boarddir..'/STM32F405RGTx_FLASH.ld' -LDFLAGS += '-L'..boarddir..'/Drivers/CMSIS/Lib' -- lib dir -LDFLAGS += '-lc -lm -lnosys -larm_cortexM4lf_math' -- libs -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 += board.ldflags +LDFLAGS += '-lc -lm -lnosys' -- libs +LDFLAGS += '-mthumb -mfloat-abi=hard -specs=nosys.specs -specs=nano.specs -u _printf_float -u _scanf_float -Wl,--cref -Wl,--gc-sections' LDFLAGS += '-Wl,--undefined=uxTopUsedPriority' -- 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 -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 '') for src in string.gmatch(all_stm_sources, "%S+") do - stm_sources += boarddir..'/'..src + stm_sources += board.dir..'/'..src end 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 -- TODO: cleaner separation of the platform code and the rest stm_includes += '.' -stm_includes += 'Drivers/DRV8301' -stm_sources += boarddir..'/Src/syscalls.c' +--stm_includes += 'Drivers/DRV8301' build{ name='stm_platform', type='objects', @@ -178,39 +180,42 @@ build{ 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{ name='ODriveFirmware', toolchains={toolchain}, --toolchains={LLVMToolchain('x86_64', {'-Ofast'}, {'-flto'})}, packages={'stm_platform'}, - 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' - }, + sources=sources, includes={ 'Drivers/DRV8301', 'MotorControl', diff --git a/Firmware/communication/interface_can.hpp b/Firmware/communication/interface_can.hpp index 19855047..0ba7a1d0 100644 --- a/Firmware/communication/interface_can.hpp +++ b/Firmware/communication/interface_can.hpp @@ -2,7 +2,6 @@ #define __INTERFACE_CAN_HPP #include -#include #include "fibre/protocol.hpp" #include "odrive_main.h" #include "can_helpers.hpp" diff --git a/Firmware/fibre/cpp/endpoints_template.j2 b/Firmware/fibre/cpp/endpoints_template.j2 index db9b8dbd..50669b77 100644 --- a/Firmware/fibre/cpp/endpoints_template.j2 +++ b/Firmware/fibre/cpp/endpoints_template.j2 @@ -10,8 +10,8 @@ * a function-oriented approach and a more powerful object model. * */ -#ifndef __FIBRE_INTERFACES_HPP -#define __FIBRE_INTERFACES_HPP +#ifndef __FIBRE_ENDPOINTS_HPP +#define __FIBRE_ENDPOINTS_HPP #include @@ -87,4 +87,4 @@ bool set_endpoint_from_float(endpoint_ref_t endpoint_ref, float value) { #pragma GCC pop_options -#endif // __FIBRE_INTERFACES_HPP \ No newline at end of file +#endif // __FIBRE_ENDPOINTS_HPP \ No newline at end of file diff --git a/Firmware/fibre/cpp/interfaces_template.j2 b/Firmware/fibre/cpp/interfaces_template.j2 index f4eb3163..cbf7e72f 100644 --- a/Firmware/fibre/cpp/interfaces_template.j2 +++ b/Firmware/fibre/cpp/interfaces_template.j2 @@ -9,6 +9,10 @@ * interfaces. * */ +#ifndef __FIBRE_INTERFACES_HPP +#define __FIBRE_INTERFACES_HPP + +#include #pragma GCC push_options #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 + +#endif // __FIBRE_INTERFACES_HPP \ No newline at end of file diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index 438226c2..7c3602b5 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -355,6 +355,29 @@ interfaces: doc: Both axes will have the same id to start can_node_id_extended: bool 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 motor_thermistor: OffboardThermistorCurrentLimiter motor: Motor @@ -548,29 +571,6 @@ interfaces: acim_rotor_flux: float32 async_phase_vel: readonly 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: c_is_class: False attributes: diff --git a/Firmware/Board/v3/Src/syscalls.c b/Firmware/syscalls.c similarity index 100% rename from Firmware/Board/v3/Src/syscalls.c rename to Firmware/syscalls.c diff --git a/tools/odrive/enums.py b/tools/odrive/enums.py index c836f39d..8ba173b7 100644 --- a/tools/odrive/enums.py +++ b/tools/odrive/enums.py @@ -107,20 +107,6 @@ ARMED_STATE_WAITING_FOR_TIMINGS = 1 ARMED_STATE_WAITING_FOR_UPDATE = 2 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 CONTROLLER_ERROR_NONE = 0x00000000 CONTROLLER_ERROR_OVERSPEED = 0x00000001