Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
### Changes this version from 1.16 to 1.15:
### Changes this version:
- Inverted Y axis direction vector magnitude
- Fixes 2 axis setups in XPforce and DCS and other flight sims
- Changed 2 axis conditional effects to ignore direction vectors (Fixes DCS)
- Modified HID 2 axis descriptor, added back second direction for compliance
- Fixed chip temp sometimes glitching
- TMC debug mode: Changed openloopspeed command to use torque mode instead of raw PWM. Added new openloopspeedpwm to control raw PWM.
- CAN bus corrected packet length when packet is sent as command
- Corrected CAN speed preset in can bridge GVRET mode (savvycan works again)


### Changes in 1.16:
- Added MyActuator RMD CAN support class.
- Temporary implementation until CAN protocol changes. Usable but might be improved in the future
- Fixed issues in CAN analog class for packet 2. Allow shorter frames
Expand Down
2 changes: 1 addition & 1 deletion Configurator
18 changes: 0 additions & 18 deletions Firmware/FFBoard/Inc/Axis.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,24 +203,6 @@ class Axis : public PersistentStorage, public CommandHandler, public ErrorHandle
.pid_vel_lim = 2147483647,
.pid_pos_low = -2147483647,
.pid_pos_high = 2147483647});

// Lowpass 500Hz Q 0.7 @ 25khz
const TMC4671Biquad_t tmcbq_500hz_07q_25k = TMC4671Biquad_t(
{ .a1 = 979476766,
.a2 = -450370144,
.b0 = 1941073,
.b1 = 3882145,
.b2 = 1941073});

// Lowpass 1000Hz Q 0.7 @ 25khz
const TMC4671Biquad_t tmcbq_1000hz_07q_25k = TMC4671Biquad_t(
{ .a1 = 886773302,
.a2 = -378358476,
.b0 = 7114021,
.b1 = 14228043,
.b2 = 7114021});


#endif
float encoderOffset = 0; // Offset for absolute encoders
uint16_t degreesOfRotation = 900; // How many degrees of range for the full gamepad range
Expand Down
2 changes: 1 addition & 1 deletion Firmware/FFBoard/Inc/CAN.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class CANPortHardwareConfig{
constexpr PresetEntry getPreset(uint8_t idx) const {return PresetEntry(presets[std::min<uint8_t>(idx,presets.size())]);}
constexpr uint32_t speedToPreset(uint32_t speed) const {
auto it = std::find_if( presets.begin(), presets.end(), [&speed](const PresetEntry &e){return e.speed == speed;});
return it == presets.end() ? 255 : std::distance(it, presets.begin());
return it == presets.end() ? 255 : std::distance(presets.begin(),it);
}
constexpr uint32_t presetToSpeed(uint8_t preset) const {return presets[preset].speed;}
const std::span<const PresetEntry> presets; // Name for listing and init types for setup
Expand Down
2 changes: 1 addition & 1 deletion Firmware/FFBoard/Inc/CANPort2B.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class CANPort_2B : public CANPort, public CommandHandler,public CanHandler{
static const uint32_t sendTimeout = 20;

CAN_TxHeaderTypeDef header = {0,0,0,CAN_RTR_DATA,8,(FunctionalState)0};

uint8_t nextLen = 8;

};
#endif
Expand Down
15 changes: 7 additions & 8 deletions Firmware/FFBoard/Inc/FastAvg.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,20 @@ class FastAvg {
};

/**
* Calculates a moving average of unknown length
* Calculates a moving average of variable length
* Can periodically get and reset a value to average for an unknown amount of data points
* If len != 0 calculates an exponential moving average with length len.
* If len = 0 length equals the current amount of samples.
* If len = 0 length equals the current amount of samples up to 0x7FFFFFFF.
*/
template <class T>
class FastMovingAverage{
public:
FastMovingAverage(uint32_t len = 0) : fixedLen(len), count(0){};
FastMovingAverage(int32_t len = 0) : fixedLen(len > 0 ? len : INT32_MAX), count(0){};
~FastMovingAverage(){};

void clear(){
curAvg = 0;
if(!fixedLen)
count=0;
count=0;
}
/**
* Gets current average and clears current average and counter
Expand All @@ -89,15 +88,15 @@ class FastMovingAverage{
* Adds a value and returns current average
*/
T addValue(T v){
if(!fixedLen || count < fixedLen)
if(count < fixedLen)
count++;
curAvg += (v - curAvg)/count;
return curAvg;
}
private:
T curAvg = 0;
const uint32_t fixedLen;
uint32_t count = 0;
const int32_t fixedLen;
int32_t count = 0;
};

#endif
2 changes: 1 addition & 1 deletion Firmware/FFBoard/Inc/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* For more settings see target_constants.h in a target specific folder
*/

static const uint8_t SW_VERSION_INT[3] = {1,16,0}; // Version as array. 8 bit each!
static const uint8_t SW_VERSION_INT[3] = {1,16,1}; // Version as array. 8 bit each!
#ifndef MAX_AXIS
#define MAX_AXIS 2 // ONLY USE 2 for now else screws HID Reports
#endif
Expand Down
4 changes: 2 additions & 2 deletions Firmware/FFBoard/Inc/ffb_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ typedef struct
uint8_t triggerButton = 0; // button ID. unused
uint8_t enableAxis = 0; // bits: 0=X, 1=Y, 2=DirectionEnable
uint16_t directionX = 0; // angle (0=0 .. 36000=360deg)
// uint16_t directionY = 0; // angle (0=0 .. 36000=360deg) TODO axes are last bytes in struct if fewer axes are used. use different report if this is not enough anymore!
uint16_t directionY = 0; // angle (0=0 .. 36000=360deg) TODO axes are last bytes in struct if fewer axes are used. use different report if this is not enough anymore!
//#if MAX_AXIS == 3
// uint8_t directionZ = 0; // angle (0=0 .. 255=360deg)
//#endif
Expand Down Expand Up @@ -255,7 +255,7 @@ typedef struct
uint16_t deadBand = 0;

bool isActive(){ // Condition is active if either coefficient is not zero
return positiveCoefficient != 0 || negativeCoefficient != 0;
return (positiveCoefficient != 0 && positiveSaturation != 0) || (negativeCoefficient != 0 && negativeSaturation != 0);
}
} FFB_Effect_Condition;

Expand Down
2 changes: 1 addition & 1 deletion Firmware/FFBoard/Src/Axis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -419,11 +419,11 @@ void Axis::setupTMC4671()
{
TMC4671 *drv = static_cast<TMC4671 *>(this->drv.get());
// drv->setAxis(axis);
drv->setExternalEncoderAllowed(true);
drv->restoreFlash();
tmclimits.pid_torque_flux = getPower();
drv->setLimits(tmclimits);
//drv->setBiquadTorque(TMC4671Biquad(tmcbq_500hz_07q_25k));
drv->setExternalEncoderAllowed(true);


// Enable driver
Expand Down
5 changes: 3 additions & 2 deletions Firmware/FFBoard/Src/CANPort2B.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,15 +356,16 @@ CommandStatus CANPort_2B::command(const ParsedCommand& cmd,std::vector<CommandRe
CAN_tx_msg msg;
memcpy(msg.data,&cmd.val,8);
msg.header.id = cmd.adr;
msg.header.length = nextLen;
sendMessage(msg);
}else{
return CommandStatus::NOT_FOUND;
}
break;
}
case CanPort_commands::len:
handleGetSet(cmd, replies, header.DLC);
header.DLC = std::min<uint32_t>(header.DLC,8);
handleGetSet(cmd, replies, nextLen);
nextLen = std::min<uint32_t>(nextLen,8);
break;
default:
return CommandStatus::NOT_FOUND;
Expand Down
74 changes: 33 additions & 41 deletions Firmware/FFBoard/Src/HidFFB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,48 +290,36 @@ void HidFFB::set_effect(FFB_SetEffect_t* effect){
effect_p->type = effect->effectType;
effect_p->samplePeriod = effect->samplePeriod;

if(axisCount == 1){
/* Compatibility fix. Some games may send a 0° or 90° angle for the first axis.
* If we only have 1 axis defined we ignore any directions and force enable the first axis
*/
effect->enableAxis = X_AXIS_ENABLE;
}

bool directionEnable = (effect->enableAxis & this->directionEnableMask);
bool overridesCondition = false;

if(effect_p->useSingleCondition){ // Only allow turning single condition off in case it was overridden by sending multiple conditions previously
effect_p->useSingleCondition = directionEnable; // If direction is used only a single parameter block is allowed. Somehow this is still set while 2 conditions are sent...
}else if(directionEnable){
directionEnable = false; // If multiple conditions were previously sent we ignore direction enable and instead activate axes
// if(effect_p->useSingleCondition){ // Only allow turning single condition off in case it was overridden by sending multiple conditions previously
// effect_p->useSingleCondition = directionEnable; // If direction is used only a single parameter block is allowed. Somehow this is still set while 2 conditions are sent...
// }
// Conditional effects usually do not use directions
if(!effect_p->useSingleCondition && (effect->effectType == FFB_EFFECT_SPRING || effect->effectType == FFB_EFFECT_DAMPER || effect->effectType == FFB_EFFECT_INERTIA || effect->effectType == FFB_EFFECT_FRICTION))
{
if(effect_p->conditions[0].isActive()){
effect->enableAxis |= X_AXIS_ENABLE;
effect_p->axisMagnitudes[0] = 1.0f;
overridesCondition = true;
}
if(effect_p->conditions[1].isActive()){
effect->enableAxis |= Y_AXIS_ENABLE;
if(effect_p->conditions[1].isActive() || effect_p->useSingleCondition){
effect_p->axisMagnitudes[1] = 1.0f;
overridesCondition = true;
}
}

float phaseX = M_PI*2.0 * (effect->directionX/36000.0);

if(axisCount == 1){
/*
* Angular vector if dirEnable used or axis enabled otherwise 0 if axis disabled
* Compatibility fix.
* Some single axis games send no directionEnable but enableAxis but still use phase vectors to scale a single axis effect
*/
effect_p->axisMagnitudes[0] = (directionEnable || (effect->enableAxis & X_AXIS_ENABLE) ? sin(phaseX) : 0);
}else{
/*
* Some 2 axis games send no vector and require the axis to be enable via enableAxis
*/
effect_p->axisMagnitudes[0] = directionEnable ? sin(phaseX) : (effect->enableAxis & X_AXIS_ENABLE ? 1 : 0); // Angular vector if dirEnable used otherwise full or 0 if axis enabled
effect_p->axisMagnitudes[1] = directionEnable ? cos(phaseX) : (effect->enableAxis & Y_AXIS_ENABLE ? 1 : 0); // Angular vector if
if(!overridesCondition){
float phaseX = M_PI*2.0 * (effect->directionX/36000.0f);

effect_p->axisMagnitudes[0] = directionEnable ? sin(phaseX) : (effect->enableAxis & X_AXIS_ENABLE ? (effect->directionX - 18000.0f) / 18000.0f : 0); // Angular vector if dirEnable used otherwise linear or 0 if axis enabled
effect_p->axisMagnitudes[1] = directionEnable ? -cos(phaseX) : (effect->enableAxis & Y_AXIS_ENABLE ? -(effect->directionY - 18000.0f) / 18000.0f : 0);
}

#if MAX_AXIS == 3
float phaseY = M_PI*2.0 * (effect->directionY/36000.0);
effect_p->axisMagnitudes[3] = (directionEnable || (effect->enableAxis & Z_AXIS_ENABLE) ? sin(phaseY) : 0); // Angular vector if dirEnable used otherwise full or 0 if axis enabled

effect_p->axisMagnitudes[3] = directionEnable ? sin(phaseY) : (effect->enableAxis & Z_AXIS_ENABLE ? (effect->directionZ - 18000.0f) / 18000.0f : 0);
#endif
if(effect->duration == 0){ // Fix for games assuming 0 is infinite
effect_p->duration = FFB_EFFECT_DURATION_INFINITE;
Expand Down Expand Up @@ -372,20 +360,24 @@ void HidFFB::set_condition(FFB_SetCondition_Data_t *cond){
effect->conditions[axis].negativeSaturation = cond->negativeSaturation;
effect->conditions[axis].positiveSaturation = cond->positiveSaturation;
effect->conditions[axis].deadBand = cond->deadBand;
//effect->conditionsCount++;
if(effect->conditions[axis].positiveSaturation == 0){
effect->conditions[axis].positiveSaturation = 0x7FFF;
}
if(effect->conditions[axis].negativeSaturation == 0){
effect->conditions[axis].negativeSaturation = 0x7FFF;
}

if(axis>0){ // Workaround when direction enable is set but multiple conditions are defined... Resets direction and uses conditions again
// if(effect->conditions[axis].positiveSaturation == 0){
// effect->conditions[axis].positiveSaturation = 0x7FFF;
// }
// if(effect->conditions[axis].negativeSaturation == 0){
// effect->conditions[axis].negativeSaturation = 0x7FFF;
// }

if(axis>0 && axis < MAX_AXIS && effect->conditions[axis].isActive()){ // Workaround when direction enable is set but multiple conditions are defined... Resets direction and uses conditions again
effect->useSingleCondition = false;
for(uint8_t i = 0;i<MAX_AXIS;i++){
effect->axisMagnitudes[i] = 1.0;
}
}
if((effect->conditions[axis].isActive() || (axis > 0 && effect->useSingleCondition)) && effect->axisMagnitudes[axis] == 0){
effect->axisMagnitudes[axis] = 1.0;
}

// for(uint8_t i = 0;i<MAX_AXIS;i++){
// effect->axisMagnitudes[i] = 1.0;
// }
}

void HidFFB::set_effect_operation(FFB_EffOp_Data_t* report){
Expand Down
2 changes: 1 addition & 1 deletion Firmware/FFBoard/Src/voltagesense.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ void brakeCheck(){

}

FastMovingAverage<int32_t>chipTempAvg{5};
FastMovingAverage<int32_t>chipTempAvg{3};
__weak int32_t getChipTemp(){
#if !defined(TEMPSENSOR_ADC_VAL) || !defined(__LL_ADC_CALC_TEMPERATURE)
return 0;
Expand Down
14 changes: 13 additions & 1 deletion Firmware/FFBoard/UserExtensions/Inc/SPIButtons.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ struct ButtonSourceConfig{
SPI_BtnMode mode=SPI_BtnMode::TM; // Mode preset
uint8_t cs_num = 0;
uint8_t spi_speed = 1; // Medium
bool debounce_enabled = false;
uint16_t debounce_time = 0; // in ms
};


class SPI_Buttons: public ButtonSource,public CommandHandler,public SPIDevice {

enum class SPIButtons_commands : uint32_t {
mode,btncut,btnpol,btnnum,cs,spispeed
mode,btncut,btnpol,btnnum,cs,spispeed,debounceen,debouncetime
};

public:
Expand All @@ -62,6 +64,11 @@ class SPI_Buttons: public ButtonSource,public CommandHandler,public SPIDevice {

void setSpiSpeed(uint8_t speedPreset);

void setDebounceEnabled(bool enabled);
void setDebounceTime(uint16_t time_ms);
bool isDebounceEnabled() { return conf.debounce_enabled; }
uint16_t getDebounceTime() { return conf.debounce_time; }

protected:
SPI_Buttons(uint16_t configuration_address, uint16_t configuration_address_2);

Expand All @@ -77,6 +84,11 @@ class SPI_Buttons: public ButtonSource,public CommandHandler,public SPIDevice {
uint8_t offset = 0;

ButtonSourceConfig conf;

// Button debouncing variables
uint64_t last_button_state = 0; // Last button state for debounce detection
uint64_t debounced_state = 0; // Current stable debounced button state
uint32_t last_debounce_time = 0; // Timestamp of last button state change

uint8_t spi_buf[4] = {0};

Expand Down
4 changes: 2 additions & 2 deletions Firmware/FFBoard/UserExtensions/Inc/TMC4671.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ struct TMC4671MainConfig{
uint8_t bbmL = 50;
uint8_t bbmH = 50;
uint16_t mdecA = 660; // 334 default. 331 recommended by datasheet,662 double. 660 lowest noise
uint16_t mdecB = 660; // Encoder ADC high resolution recommended
uint16_t mdecB = 331; // Encoder ADC fast rate recommended
uint32_t mclkA = 0x20000000; //0x20000000 default
uint32_t mclkB = 0x20000000; // For AENC
uint16_t adc_I0_offset = 33415;
Expand Down Expand Up @@ -368,7 +368,7 @@ friend class TMCDebugBridge;

uint32_t readReg(uint8_t reg);
void writeReg(uint8_t reg,uint32_t dat);
void writeRegDMA(uint8_t reg,uint32_t dat);
void writeRegAsync(uint8_t reg,uint32_t dat);
void updateReg(uint8_t reg,uint32_t dat,uint32_t mask,uint8_t shift);
//void SpiTxCplt(SPI_HandleTypeDef *hspi);

Expand Down
2 changes: 1 addition & 1 deletion Firmware/FFBoard/UserExtensions/Inc/TMCDebugBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ extern SPI_HandleTypeDef HSPIDRV;

class TMCDebugBridge: public FFBoardMain {
enum class TMCDebugBridge_commands : uint32_t{
torque,pos,openloopspeed,velocity,mode,reg
torque,pos,openloopspeed,velocity,mode,reg,openloopspeedpwm
};
public:

Expand Down
2 changes: 1 addition & 1 deletion Firmware/FFBoard/UserExtensions/Inc/usb_hid_ffb_desc.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
extern const uint8_t hid_1ffb_desc[USB_HID_1FFB_REPORT_DESC_SIZE];
#endif

#define USB_HID_2FFB_REPORT_DESC_SIZE 1208//1213
#define USB_HID_2FFB_REPORT_DESC_SIZE 1215//1213
#ifdef AXIS2_FFB_HID_DESC
extern const uint8_t hid_2ffb_desc[USB_HID_2FFB_REPORT_DESC_SIZE];
#endif
Expand Down
Loading