1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-26 01:35:41 +03:00

Add OSD_STATE_GROUP_ELEMENTS state to osdUpdate() and optimise DMA vs polled MAX7456 SPI access

This commit is contained in:
Steve Evans 2022-01-26 20:24:12 +00:00
parent 28e596a500
commit 2e8d026b4e
5 changed files with 68 additions and 45 deletions

View file

@ -635,7 +635,7 @@ void spiSequenceStart(const extDevice_t *dev)
}
// Use DMA if possible
if (bus->useDMA && dmaSafe && ((segmentCount > 1) || (xferLen > 8))) {
if (bus->useDMA && dmaSafe && ((segmentCount > 1) || (xferLen >= 8))) {
// Intialise the init structures for the first transfer
spiInternalInitStream(dev, false);

View file

@ -367,7 +367,7 @@ void spiSequenceStart(const extDevice_t *dev)
xferLen += checkSegment->len;
}
// Use DMA if possible
if (bus->useDMA && dmaSafe && ((segmentCount > 1) || (xferLen > 8))) {
if (bus->useDMA && dmaSafe && ((segmentCount > 1) || (xferLen >= 8))) {
// Intialise the init structures for the first transfer
spiInternalInitStream(dev, false);

View file

@ -206,7 +206,9 @@ static uint8_t shadowBuffer[VIDEO_BUFFER_CHARS_PAL];
//Max bytes to update in one call to max7456DrawScreen()
#define MAX_BYTES2SEND 250
#define MAX_BYTES2SEND_POLLED 20
#define MAX_BYTES2SEND_POLLED 12
#define MAX_ENCODE_US 20
#define MAX_ENCODE_US_POLLED 10
static DMA_DATA uint8_t spiBuf[MAX_BYTES2SEND];
@ -622,11 +624,13 @@ bool max7456DrawScreen(void)
uint8_t *buffer = getActiveLayerBuffer();
int spiBufIndex = 0;
int maxSpiBufStartIndex;
timeDelta_t maxEncodeTime;
bool setAddress = true;
bool autoInc = false;
int posLimit = pos + (maxScreenSize / 2);
maxSpiBufStartIndex = spiUseMOSI_DMA(dev) ? MAX_BYTES2SEND : MAX_BYTES2SEND_POLLED;
maxEncodeTime = spiUseMOSI_DMA(dev) ? MAX_ENCODE_US : MAX_ENCODE_US_POLLED;
// Abort for now if the bus is still busy
if (spiIsBusy(dev)) {
@ -634,11 +638,13 @@ bool max7456DrawScreen(void)
return true;
}
// Allow for 8 bytes followed by an ESCAPE and reset of DMM at end of buffer
maxSpiBufStartIndex -= 12;
timeUs_t startTime = micros();
// Allow for an ESCAPE, a reset of DMM and a two byte MAX7456ADD_DMM command at end of buffer
maxSpiBufStartIndex -= 4;
// Initialise the transfer buffer
while ((spiBufIndex < maxSpiBufStartIndex) && (pos < posLimit)) {
while ((spiBufIndex < maxSpiBufStartIndex) && (pos < posLimit) && (cmpTimeUs(micros(), startTime) < maxEncodeTime)) {
if (buffer[pos] != shadowBuffer[pos]) {
if (buffer[pos] == 0xff) {
buffer[pos] = ' ';

View file

@ -198,6 +198,7 @@ const osd_stats_e osdStatsDisplayOrder[OSD_STAT_COUNT] = {
#else
#define OSD_ELEMENT_RENDER_GROUP_MARGIN 2
#endif
#define OSD_TASK_MARGIN 1
// Decay the estimated max task duration by 1/(1 << OSD_EXEC_TIME_SHIFT) on every invocation
#define OSD_EXEC_TIME_SHIFT 8
@ -1130,6 +1131,7 @@ typedef enum {
OSD_STATE_PROCESS_STATS3,
OSD_STATE_UPDATE_ALARMS,
OSD_STATE_UPDATE_CANVAS,
OSD_STATE_GROUP_ELEMENTS,
OSD_STATE_UPDATE_ELEMENTS,
OSD_STATE_UPDATE_HEARTBEAT,
OSD_STATE_COMMIT,
@ -1164,14 +1166,13 @@ bool osdUpdateCheck(timeUs_t currentTimeUs, timeDelta_t currentDeltaTimeUs)
return (osdState != OSD_STATE_IDLE);
}
// Called when there is OSD update work to be done
void osdUpdate(timeUs_t currentTimeUs)
{
// Times are known to be short so use uint16_t rather than timeUs_t
static uint16_t osdStateDurationFracUs[OSD_STATE_COUNT] = { 0 };
static uint16_t osdElementDurationUs[OSD_ITEM_COUNT] = { 0 };
static uint16_t osdElementGroupMembership[OSD_ITEM_COUNT];
static uint32_t osdElementDurationUs[OSD_ITEM_COUNT] = { 0 };
static uint8_t osdElementGroupMembership[OSD_ITEM_COUNT];
static uint16_t osdElementGroupTargetFracUs[OSD_GROUP_COUNT] = { 0 };
static uint16_t osdElementGroupDurationFracUs[OSD_GROUP_COUNT] = { 0 };
static uint8_t osdElementGroup;
@ -1304,6 +1305,12 @@ void osdUpdate(timeUs_t currentTimeUs)
osdSyncBlink();
osdState = OSD_STATE_GROUP_ELEMENTS;
break;
case OSD_STATE_GROUP_ELEMENTS:
{
uint8_t elementGroup;
uint8_t activeElements = osdGetActiveElementCount();
@ -1325,7 +1332,7 @@ void osdUpdate(timeUs_t currentTimeUs)
osdElementGroupTargetFracUs[elementGroup] += osdElementDurationUs[curElement];
// If group membership changes, reset the stats for the group
if (osdElementGroupMembership[curElement] != elementGroup) {
osdElementGroupDurationFracUs[elementGroup] = osdElementGroupTargetFracUs[elementGroup];
osdElementGroupDurationFracUs[elementGroup] = osdElementGroupTargetFracUs[elementGroup] + (OSD_ELEMENT_RENDER_GROUP_MARGIN << OSD_EXEC_TIME_SHIFT);
}
osdElementGroupMembership[curElement] = elementGroup;
} else {
@ -1343,6 +1350,7 @@ void osdUpdate(timeUs_t currentTimeUs)
} else {
osdState = OSD_STATE_COMMIT;
}
}
break;
case OSD_STATE_UPDATE_ELEMENTS:
@ -1406,6 +1414,7 @@ void osdUpdate(timeUs_t currentTimeUs)
firstPass = false;
osdState = OSD_STATE_IDLE;
break;
case OSD_STATE_IDLE:
@ -1424,11 +1433,17 @@ void osdUpdate(timeUs_t currentTimeUs)
if (osdCurState == OSD_STATE_UPDATE_ELEMENTS) {
if (executeTimeUs > (osdElementGroupDurationFracUs[osdCurElementGroup] >> OSD_EXEC_TIME_SHIFT)) {
osdElementGroupDurationFracUs[osdCurElementGroup] = executeTimeUs << OSD_EXEC_TIME_SHIFT;
} else if (osdElementGroupDurationFracUs[osdCurElementGroup] > 0) {
// Slowly decay the max time
osdElementGroupDurationFracUs[osdCurElementGroup]--;
}
}
if (executeTimeUs > (osdStateDurationFracUs[osdCurState] >> OSD_EXEC_TIME_SHIFT)) {
osdStateDurationFracUs[osdCurState] = executeTimeUs << OSD_EXEC_TIME_SHIFT;
} else if (osdStateDurationFracUs[osdCurState] > 0) {
// Slowly decay the max time
osdStateDurationFracUs[osdCurState]--;
}
}
}
@ -1437,9 +1452,9 @@ void osdUpdate(timeUs_t currentTimeUs)
schedulerSetNextStateTime((osdElementGroupDurationFracUs[osdElementGroup] >> OSD_EXEC_TIME_SHIFT) + OSD_ELEMENT_RENDER_GROUP_MARGIN);
} else {
if (osdState == OSD_STATE_IDLE) {
schedulerSetNextStateTime(osdStateDurationFracUs[OSD_STATE_CHECK] >> OSD_EXEC_TIME_SHIFT);
schedulerSetNextStateTime((osdStateDurationFracUs[OSD_STATE_CHECK] >> OSD_EXEC_TIME_SHIFT) + OSD_TASK_MARGIN);
} else {
schedulerSetNextStateTime(osdStateDurationFracUs[osdState] >> OSD_EXEC_TIME_SHIFT);
schedulerSetNextStateTime((osdStateDurationFracUs[osdState] >> OSD_EXEC_TIME_SHIFT) + OSD_TASK_MARGIN);
}
}
}

View file

@ -709,7 +709,7 @@ TEST_F(OsdTest, TestAlarms)
// elements showing values in alarm range should flash
simulationTime += 1000000;
simulationTime -= simulationTime % 1000000;
timeUs_t startTime = simulationTime + 0.25e6;
timeUs_t startTime = simulationTime;
for (int i = 0; i < 15; i++) {
// Blinking should happen at 2Hz
simulationTime = startTime + i*0.25e6;
@ -1083,6 +1083,7 @@ TEST_F(OsdTest, TestElementWarningsBattery)
// Delay as the warnings are flashing
simulationTime += 1000000;
simulationTime -= simulationTime % 1000000;
simulationTime += 0.25e6;
osdRefresh();
// then
@ -1098,6 +1099,7 @@ TEST_F(OsdTest, TestElementWarningsBattery)
// Delay as the warnings are flashing
simulationTime += 1000000;
simulationTime -= simulationTime % 1000000;
simulationTime += 0.25e6;
osdRefresh();
// then
@ -1204,7 +1206,7 @@ TEST_F(OsdTest, TestGpsElements)
// Sat indicator should blink and show "NC"
simulationTime += 1000000;
simulationTime -= simulationTime % 1000000;
timeUs_t startTime = simulationTime + 0.25e6;
timeUs_t startTime = simulationTime;
for (int i = 0; i < 15; i++) {
// Blinking should happen at 2Hz
simulationTime = startTime + i*0.25e6;
@ -1228,7 +1230,7 @@ TEST_F(OsdTest, TestGpsElements)
// Sat indicator should blink and show "0"
simulationTime += 1000000;
simulationTime -= simulationTime % 1000000;
startTime = simulationTime + 0.25e6;
startTime = simulationTime;
for (int i = 0; i < 15; i++) {
// Blinking should happen at 2Hz
simulationTime = startTime + i*0.25e6;