diff --git a/src/main/fc/settings.yaml b/src/main/fc/settings.yaml index 01ca6149bfb..8675fa0efa8 100644 --- a/src/main/fc/settings.yaml +++ b/src/main/fc/settings.yaml @@ -3329,6 +3329,13 @@ groups: max: 600 type: int16_t field: msp_displayport_fullframe_interval + - name: osd_framerate_hz + description: "OSD element refresh rate in Hz. Controls how often OSD elements are updated (except artificial horizon and telemetry which are always updated). Higher values provide smoother updates but increase CPU load. Set to -1 for legacy mode (one element per frame). Default: -1" + default_value: -1 + min: -1 + max: 60 + type: int8_t + field: osd_framerate_hz - name: osd_units description: "IMPERIAL, METRIC, UK" default_value: "METRIC" diff --git a/src/main/io/osd.c b/src/main/io/osd.c index c7a40e982cc..536da49b3f2 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -4242,6 +4242,18 @@ uint8_t osdIncElementIndex(uint8_t elementIndex) return elementIndex; } +static void osdDrawAllElements(void) +{ + for (uint8_t element = 0; element < OSD_ITEM_COUNT; element++) { + osdDrawSingleElement(element); + } + + osdDrawSingleElement(OSD_ARTIFICIAL_HORIZON); + if (osdConfig()->telemetry>0){ + osdDisplayTelemetry(); + } +} + void osdDrawNextElement(void) { static uint8_t elementIndex = 0; @@ -4304,6 +4316,7 @@ PG_RESET_TEMPLATE(osdConfig_t, osdConfig, .video_system = SETTING_OSD_VIDEO_SYSTEM_DEFAULT, .row_shiftdown = SETTING_OSD_ROW_SHIFTDOWN_DEFAULT, .msp_displayport_fullframe_interval = SETTING_OSD_MSP_DISPLAYPORT_FULLFRAME_INTERVAL_DEFAULT, + .framerate_hz = SETTING_OSD_FRAMERATE_HZ_DEFAULT, .ahi_reverse_roll = SETTING_OSD_AHI_REVERSE_ROLL_DEFAULT, .ahi_max_pitch = SETTING_OSD_AHI_MAX_PITCH_DEFAULT, @@ -5976,7 +5989,28 @@ static void osdRefresh(timeUs_t currentTimeUs) displayClearScreen(osdDisplayPort); fullRedraw = false; } - osdDrawNextElement(); + + if (osdConfig()->osd_framerate_hz == -1) { + osdDrawNextElement(); + } else { + static uint32_t lastDrawAllTimeUs = 0; + const int8_t hz = osdConfig()->osd_framerate_hz; + const uint32_t drawAllIntervalUs = (hz > 0) ? (1000000 / hz) : 0; + + const bool forceDraw = (drawAllIntervalUs == 0); + const bool intervalExceeded = (currentTimeUs - lastDrawAllTimeUs) >= drawAllIntervalUs; + + if (forceDraw || intervalExceeded) { + osdDrawAllElements(); + lastDrawAllTimeUs = currentTimeUs; + } + + osdDrawSingleElement(OSD_ARTIFICIAL_HORIZON); + if (osdConfig()->telemetry>0){ + osdDisplayTelemetry(); + } + } + displayHeartbeat(osdDisplayPort); displayCommitTransaction(osdDisplayPort); #ifdef OSD_CALLS_CMS diff --git a/src/main/io/osd.h b/src/main/io/osd.h index bbaa68f862d..d644d841a01 100644 --- a/src/main/io/osd.h +++ b/src/main/io/osd.h @@ -451,6 +451,7 @@ typedef struct osdConfig_s { videoSystem_e video_system; uint8_t row_shiftdown; int16_t msp_displayport_fullframe_interval; + int8_t osd_framerate_hz; // Preferences uint8_t main_voltage_decimals;