Skip to content

Commit 8556b42

Browse files
Merge pull request #11561 from iNavFlight/maintenance-9.x
Maintenance 9.x to 10
2 parents 990b0dd + 824f582 commit 8556b42

30 files changed

Lines changed: 1009 additions & 597 deletions

docs/Controls.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ The stick positions are combined to activate different functions:
3131
| Battery profile 3 | HIGH | LOW | CENTER | HIGH |
3232
| Calibrate Gyro | LOW | LOW | LOW | CENTER |
3333
| Calibrate Acc | HIGH | LOW | LOW | CENTER |
34-
| Calibrate Mag/Compass | HIGH | HIGH | LOW | CENTER |
34+
| Calibrate Compass/Zero Yaw | HIGH | HIGH | LOW | CENTER |
3535
| Trim Acc Left | HIGH | CENTER | CENTER | LOW |
3636
| Trim Acc Right | HIGH | CENTER | CENTER | HIGH |
3737
| Trim Acc Forwards | HIGH | CENTER | HIGH | CENTER |
@@ -52,6 +52,14 @@ The stick positions are combined to activate different functions:
5252
For graphical stick position in all transmitter modes, check out [this page](https://www.mrd-rc.com/tutorials-tools-and-testing/inav-flight/inav-stick-commands-for-all-transmitter-modes/).
5353
![Stick Positions](assets/images/StickPositions.png)
5454

55+
## Compass Calibration and Yaw Zero Reset
56+
57+
The stick function `Calibrate Compass/Zero Yaw` provides 2 functions depending on whether or not a compass is available.
58+
59+
If a compass is available the stick function initiates the compass calibration routine.
60+
61+
If no compass is available the stick function will reset the current yaw/heading estimate to zero (North) and also set the heading as trusted. This is useful on multirotors, allowing the craft yaw/heading to be correctly aligned to actual North simply by physically pointing the craft North then using the stick function to zero the yaw estimate. Since this also sets the heading as trusted Nav modes reliant on heading will be available immediately after arming without the need to fly fast enough to obtain a valid heading from GPS ground course.
62+
5563
## Yaw control
5664

5765
While arming/disarming with sticks, your yaw stick will be moving to extreme values. In order to prevent your craft from trying to yaw during arming/disarming while on the ground, your yaw input will not cause the craft to yaw when the throttle is LOW (i.e. below the `min_check` setting).

src/main/common/filter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ float nullFilterApply4(void *filter, float input, float f_cut, float dt)
4444

4545
// PT1 Low Pass filter
4646

47-
static float pt1ComputeRC(const float f_cut)
47+
static float FAST_CODE pt1ComputeRC(const float f_cut)
4848
{
4949
return 1.0f / (2.0f * M_PIf * f_cut);
5050
}

src/main/common/maths.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ int32_t applyDeadbandRescaled(int32_t value, int32_t deadband, int32_t min, int3
165165
return value;
166166
}
167167

168-
int32_t constrain(int32_t amt, int32_t low, int32_t high)
168+
int32_t FAST_CODE constrain(int32_t amt, int32_t low, int32_t high)
169169
{
170170
if (amt < low)
171171
return low;
@@ -175,7 +175,7 @@ int32_t constrain(int32_t amt, int32_t low, int32_t high)
175175
return amt;
176176
}
177177

178-
float constrainf(float amt, float low, float high)
178+
float FAST_CODE constrainf(float amt, float low, float high)
179179
{
180180
if (amt < low)
181181
return low;
@@ -225,7 +225,7 @@ int scaleRange(int x, int srcMin, int srcMax, int destMin, int destMax) {
225225
return ((a / b) + destMin);
226226
}
227227

228-
float scaleRangef(float x, float srcMin, float srcMax, float destMin, float destMax) {
228+
float FAST_CODE scaleRangef(float x, float srcMin, float srcMax, float destMin, float destMax) {
229229
float a = (destMax - destMin) * (x - srcMin);
230230
float b = srcMax - srcMin;
231231
return ((a / b) + destMin);

src/main/config/config_eeprom.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
#include "drivers/system.h"
3535
#include "drivers/flash.h"
36+
#include "drivers/pwm_output.h"
3637

3738
#include "fc/config.h"
3839

@@ -321,6 +322,13 @@ static bool writeSettingsToEEPROM(void)
321322

322323
void writeConfigToEEPROM(void)
323324
{
325+
#if !defined(SITL_BUILD) && defined(USE_DSHOT)
326+
// Enable circular DMA so hardware keeps repeating zero-throttle DShot
327+
// packets during flash writes (which block the CPU for 20-200ms).
328+
// Without this, ESCs lose signal and may spin up or reboot.
329+
pwmSetMotorDMACircular(true);
330+
#endif
331+
324332
bool success = false;
325333
// write it
326334
for (int attempt = 0; attempt < 3 && !success; attempt++) {
@@ -333,6 +341,10 @@ void writeConfigToEEPROM(void)
333341
}
334342
}
335343

344+
#if !defined(SITL_BUILD) && defined(USE_DSHOT)
345+
pwmSetMotorDMACircular(false);
346+
#endif
347+
336348
if (success && isEEPROMContentValid()) {
337349
return;
338350
}

src/main/drivers/flash.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ typedef struct flashGeometry_s {
4040
uint32_t totalSize; // This is just sectorSize * sectors
4141
uint16_t pagesPerSector;
4242
flashType_e flashType;
43+
int32_t bbReplacementBlocks;
44+
uint8_t bblutTableEntryCount; // Used by W25N_BBLUT_TABLE_ENTRY_COUNT for bad-block scanning
4345
} flashGeometry_t;
4446

4547
typedef struct

src/main/drivers/flash_w25n.c

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
#include "platform.h"
2525

26-
#if defined(USE_FLASH_W25N01G) || defined(USE_FLASH_W25N02K)
26+
#if defined(USE_FLASH_W25N01G) || defined(USE_FLASH_W25N02K) || defined(USE_FLASH_MX35LF2G)
2727

2828
#include "drivers/bus.h"
2929
#include "drivers/io.h"
@@ -37,26 +37,24 @@
3737

3838
#define W25N01GV_BLOCKS_PER_DIE 1024
3939
#define W25N02KV_BLOCKS_PER_DIE 2048
40-
40+
#define MX35LF2G_BLOCKS_PER_DIE 2048
4141

4242

4343
// BB replacement area
4444
#define W25N_BB_MARKER_BLOCKS 1
45-
#define W25N_BB_REPLACEMENT_BLOCKS 20
45+
#define W25N_BB_REPLACEMENT_BLOCKS (geometry.bbReplacementBlocks)
4646
#define W25N_BB_MANAGEMENT_BLOCKS (W25N_BB_REPLACEMENT_BLOCKS + W25N_BB_MARKER_BLOCKS)
4747

4848
// blocks are zero-based index
49-
#define W25N_BB_REPLACEMENT_START_BLOCK (W25N_BLOCKS_PER_DIE - W25N_BB_REPLACEMENT_BLOCKS)
50-
#define W25N_BB_MANAGEMENT_START_BLOCK (W25N_BLOCKS_PER_DIE - W25N_BB_MANAGEMENT_BLOCKS)
49+
#define W25N_BB_REPLACEMENT_START_BLOCK (geometry.sectors - W25N_BB_REPLACEMENT_BLOCKS)
50+
#define W25N_BB_MANAGEMENT_START_BLOCK (geometry.sectors - W25N_BB_MANAGEMENT_BLOCKS)
5151
#define W25N_BB_MARKER_BLOCK (W25N_BB_REPLACEMENT_START_BLOCK - W25N_BB_MARKER_BLOCKS)
5252

5353
// Instructions
5454
#define W25N_INSTRUCTION_RDID 0x9F
5555
#define W25N_INSTRUCTION_DEVICE_RESET 0xFF
56-
#define W25N_INSTRUCTION_READ_STATUS_REG 0x05
57-
#define W25N_INSTRUCTION_READ_STATUS_ALTERNATE_REG 0x0F
58-
#define W25N_INSTRUCTION_WRITE_STATUS_REG 0x01
59-
#define W25N_INSTRUCTION_WRITE_STATUS_ALTERNATE_REG 0x1F
56+
#define W25N_INSTRUCTION_READ_STATUS_REG 0x0F
57+
#define W25N_INSTRUCTION_WRITE_STATUS_REG 0x1F
6058
#define W25N_INSTRUCTION_WRITE_ENABLE 0x06
6159
#define W25N_INSTRUCTION_DIE_SELECT 0xC2
6260
#define W25N_INSTRUCTION_BLOCK_ERASE 0xD8
@@ -99,7 +97,7 @@
9997
#define W25N_STATUS_ERASE_FAIL (1 << 2)
10098
#define W25N_STATUS_FLAG_WRITE_ENABLED (1 << 1)
10199
#define W25N_STATUS_FLAG_BUSY (1 << 0)
102-
#define W25N_BBLUT_TABLE_ENTRY_COUNT 20
100+
#define W25N_BBLUT_TABLE_ENTRY_COUNT geometry.bblutTableEntryCount
103101
#define W25N_BBLUT_TABLE_ENTRY_SIZE 4 // in bytes
104102

105103
// Bits in LBA for BB LUT
@@ -110,8 +108,8 @@
110108
// Some useful defs and macros
111109
#define W25N_LINEAR_TO_COLUMN(laddr) ((laddr) % W25N_PAGE_SIZE)
112110
#define W25N_LINEAR_TO_PAGE(laddr) ((laddr) / W25N_PAGE_SIZE)
113-
#define W25N_LINEAR_TO_BLOCK(laddr) (W25N_LINEAR_TO_PAGE(laddr) / W25N_PAGES_PER_BLOCK)
114-
#define W25N_BLOCK_TO_PAGE(block) ((block) * W25N_PAGES_PER_BLOCK)
111+
#define W25N_LINEAR_TO_BLOCK(laddr) (W25N_LINEAR_TO_PAGE(laddr) / geometry.pagesPerSector)
112+
#define W25N_BLOCK_TO_PAGE(block) ((block) * geometry.pagesPerSector)
115113
#define W25N_BLOCK_TO_LINEAR(block) (W25N_BLOCK_TO_PAGE(block) * W25N_PAGE_SIZE)
116114

117115
// IMPORTANT: Timeout values are currently required to be set to the highest value required by any of the supported flash chips by this driver
@@ -129,6 +127,7 @@
129127
// JEDEC ID
130128
#define JEDEC_ID_WINBOND_W25N01GV 0xEFAA21
131129
#define JEDEC_ID_WINBOND_W25N02KV 0xEFAA22
130+
#define JEDEC_ID_MACRONIX_MX35LF2G 0xC22603
132131

133132
static busDevice_t *busDev = NULL;
134133
static flashGeometry_t geometry;
@@ -242,19 +241,31 @@ bool w25n_detect(uint32_t chipID)
242241
geometry.sectors = W25N01GV_BLOCKS_PER_DIE; // Blocks
243242
geometry.pagesPerSector = W25N_PAGES_PER_BLOCK; // Pages/Blocks
244243
geometry.pageSize = W25N_PAGE_SIZE;
244+
geometry.bbReplacementBlocks = 20;
245+
geometry.bblutTableEntryCount = 20;
245246
break;
246247
case JEDEC_ID_WINBOND_W25N02KV:
247248
geometry.sectors = W25N02KV_BLOCKS_PER_DIE; // Blocks
248249
geometry.pagesPerSector = W25N_PAGES_PER_BLOCK; // Pages/Blocks
249250
geometry.pageSize = W25N_PAGE_SIZE;
251+
geometry.bbReplacementBlocks = 20;
252+
geometry.bblutTableEntryCount = 20;
253+
break;
254+
case JEDEC_ID_MACRONIX_MX35LF2G:
255+
geometry.sectors = MX35LF2G_BLOCKS_PER_DIE; // Blocks
256+
geometry.pagesPerSector = W25N_PAGES_PER_BLOCK; // Pages/Blocks
257+
geometry.pageSize = W25N_PAGE_SIZE;
258+
geometry.bbReplacementBlocks = 40;
259+
geometry.bblutTableEntryCount = 40;
250260
break;
251-
252261
default:
253262
// Unsupported chip
254263
geometry.sectors = 0;
255264
geometry.pagesPerSector = 0;
256265
geometry.sectorSize = 0;
257266
geometry.totalSize = 0;
267+
geometry.bbReplacementBlocks = 0;
268+
geometry.bblutTableEntryCount = 0;
258269
return false;
259270
}
260271

src/main/drivers/pwm_mapping.c

Lines changed: 77 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -270,23 +270,43 @@ uint8_t pwmClaimTimer(HAL_Timer_t *tim, uint32_t usageFlags) {
270270
return changed;
271271
}
272272

273-
static void pwmAssignOutput(timMotorServoHardware_t *timOutputs, timerHardware_t *timHw, int type)
273+
void pwmEnsureEnoughtMotors(uint8_t motorCount)
274274
{
275-
switch (type) {
276-
case MAP_TO_MOTOR_OUTPUT:
277-
timHw->usageFlags &= TIM_USE_MOTOR;
278-
timOutputs->timMotors[timOutputs->maxTimMotorCount++] = timHw;
279-
pwmClaimTimer(timHw->tim, timHw->usageFlags);
280-
break;
281-
case MAP_TO_SERVO_OUTPUT:
282-
timHw->usageFlags &= TIM_USE_SERVO;
283-
timOutputs->timServos[timOutputs->maxTimServoCount++] = timHw;
284-
pwmClaimTimer(timHw->tim, timHw->usageFlags);
285-
break;
286-
case MAP_TO_LED_OUTPUT:
287-
timHw->usageFlags &= TIM_USE_LED;
288-
pwmClaimTimer(timHw->tim, timHw->usageFlags);
289-
break;
275+
uint8_t motorOnlyOutputs = 0;
276+
277+
for (int idx = 0; idx < timerHardwareCount; idx++) {
278+
timerHardware_t *timHw = &timerHardware[idx];
279+
280+
timerHardwareOverride(timHw);
281+
282+
if (checkPwmTimerConflicts(timHw)) {
283+
continue;
284+
}
285+
286+
if (TIM_IS_MOTOR_ONLY(timHw->usageFlags)) {
287+
motorOnlyOutputs++;
288+
motorOnlyOutputs += pwmClaimTimer(timHw->tim, timHw->usageFlags);
289+
}
290+
}
291+
292+
for (int idx = 0; idx < timerHardwareCount; idx++) {
293+
timerHardware_t *timHw = &timerHardware[idx];
294+
295+
if (checkPwmTimerConflicts(timHw)) {
296+
continue;
297+
}
298+
299+
if (TIM_IS_MOTOR(timHw->usageFlags) && !TIM_IS_MOTOR_ONLY(timHw->usageFlags)) {
300+
if (motorOnlyOutputs < motorCount) {
301+
timHw->usageFlags &= ~TIM_USE_SERVO;
302+
timHw->usageFlags |= TIM_USE_MOTOR;
303+
motorOnlyOutputs++;
304+
motorOnlyOutputs += pwmClaimTimer(timHw->tim, timHw->usageFlags);
305+
} else {
306+
timHw->usageFlags &= ~TIM_USE_MOTOR;
307+
pwmClaimTimer(timHw->tim, timHw->usageFlags);
308+
}
309+
}
290310
}
291311
}
292312

@@ -296,54 +316,54 @@ void pwmBuildTimerOutputList(timMotorServoHardware_t * timOutputs, bool isMixerU
296316
timOutputs->maxTimMotorCount = 0;
297317
timOutputs->maxTimServoCount = 0;
298318

299-
const uint8_t motorCount = getMotorCount();
319+
uint8_t motorCount = getMotorCount();
320+
uint8_t motorIdx = 0;
300321

301-
// Apply configurator overrides to all timer outputs
302-
for (int idx = 0; idx < timerHardwareCount; idx++) {
303-
timerHardwareOverride(&timerHardware[idx]);
304-
}
322+
pwmEnsureEnoughtMotors(motorCount);
305323

306-
// Assign outputs in priority order: dedicated first, then auto.
307-
// Within each pass, array order (S1, S2, ...) is preserved.
308-
// Motors and servos cannot share a timer, enforced by pwmHasMotorOnTimer/pwmHasServoOnTimer.
309-
for (int priority = 0; priority < 2; priority++) {
310-
uint8_t motorIdx = timOutputs->maxTimMotorCount;
324+
for (int idx = 0; idx < timerHardwareCount; idx++) {
325+
timerHardware_t *timHw = &timerHardware[idx];
311326

312-
for (int idx = 0; idx < timerHardwareCount; idx++) {
313-
timerHardware_t *timHw = &timerHardware[idx];
314-
outputMode_e mode = timerOverrides(timer2id(timHw->tim))->outputMode;
315-
bool isDedicated = (priority == 0);
327+
int type = MAP_TO_NONE;
316328

317-
if (checkPwmTimerConflicts(timHw)) {
318-
if (priority == 0) {
319-
LOG_WARNING(PWM, "Timer output %d skipped", idx);
320-
}
321-
continue;
322-
}
329+
// Check for known conflicts (i.e. UART, LEDSTRIP, Rangefinder and ADC)
330+
if (checkPwmTimerConflicts(timHw)) {
331+
LOG_WARNING(PWM, "Timer output %d skipped", idx);
332+
continue;
333+
}
323334

324-
// Motors: dedicated (OUTPUT_MODE_MOTORS) first, then auto
325-
if (TIM_IS_MOTOR(timHw->usageFlags) && motorIdx < motorCount
326-
&& !pwmHasServoOnTimer(timOutputs, timHw->tim)
327-
&& (isDedicated ? mode == OUTPUT_MODE_MOTORS : mode != OUTPUT_MODE_MOTORS)) {
328-
pwmAssignOutput(timOutputs, timHw, MAP_TO_MOTOR_OUTPUT);
329-
motorIdx++;
330-
continue;
331-
}
335+
// Make sure first motorCount motor outputs get assigned to motor
336+
if (TIM_IS_MOTOR(timHw->usageFlags) && (motorIdx < motorCount)) {
337+
timHw->usageFlags &= ~TIM_USE_SERVO;
338+
pwmClaimTimer(timHw->tim, timHw->usageFlags);
339+
motorIdx += 1;
340+
}
332341

333-
// Servos: dedicated (OUTPUT_MODE_SERVOS) first, then auto
334-
if (TIM_IS_SERVO(timHw->usageFlags)
335-
&& !pwmHasMotorOnTimer(timOutputs, timHw->tim)
336-
&& (isDedicated ? mode == OUTPUT_MODE_SERVOS : mode != OUTPUT_MODE_SERVOS)) {
337-
pwmAssignOutput(timOutputs, timHw, MAP_TO_SERVO_OUTPUT);
338-
continue;
339-
}
342+
if (TIM_IS_SERVO(timHw->usageFlags) && !pwmHasMotorOnTimer(timOutputs, timHw->tim)) {
343+
type = MAP_TO_SERVO_OUTPUT;
344+
} else if (TIM_IS_MOTOR(timHw->usageFlags) && !pwmHasServoOnTimer(timOutputs, timHw->tim)) {
345+
type = MAP_TO_MOTOR_OUTPUT;
346+
} else if (TIM_IS_LED(timHw->usageFlags) && !pwmHasMotorOnTimer(timOutputs, timHw->tim) && !pwmHasServoOnTimer(timOutputs, timHw->tim)) {
347+
type = MAP_TO_LED_OUTPUT;
348+
}
340349

341-
// LEDs: only on the auto pass, and only if timer is uncontested
342-
if (!isDedicated && TIM_IS_LED(timHw->usageFlags)
343-
&& !pwmHasMotorOnTimer(timOutputs, timHw->tim)
344-
&& !pwmHasServoOnTimer(timOutputs, timHw->tim)) {
345-
pwmAssignOutput(timOutputs, timHw, MAP_TO_LED_OUTPUT);
346-
}
350+
switch(type) {
351+
case MAP_TO_MOTOR_OUTPUT:
352+
timHw->usageFlags &= TIM_USE_MOTOR;
353+
timOutputs->timMotors[timOutputs->maxTimMotorCount++] = timHw;
354+
pwmClaimTimer(timHw->tim, timHw->usageFlags);
355+
break;
356+
case MAP_TO_SERVO_OUTPUT:
357+
timHw->usageFlags &= TIM_USE_SERVO;
358+
timOutputs->timServos[timOutputs->maxTimServoCount++] = timHw;
359+
pwmClaimTimer(timHw->tim, timHw->usageFlags);
360+
break;
361+
case MAP_TO_LED_OUTPUT:
362+
timHw->usageFlags &= TIM_USE_LED;
363+
pwmClaimTimer(timHw->tim, timHw->usageFlags);
364+
break;
365+
default:
366+
break;
347367
}
348368
}
349369
}

0 commit comments

Comments
 (0)