diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index d715286bd..b2af3afac 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -487,6 +487,7 @@ if(ARCH STREQUAL ARM) option(SUPPORT_D16_EU_ONLY "XJT module only supports D16-EU and LR12-EU" OFF) # TODO rename to XJT_EU_ONLY option(DEBUG_INTERRUPTS "Count interrupts" OFF) option(DEBUG_TASKS "Task switching statistics" OFF) + option(DEBUG_TIMERS "Time critical parts of the code" OFF) if(TIMERS EQUAL 3) add_definitions(-DTIMERS=3) @@ -522,6 +523,10 @@ if(ARCH STREQUAL ARM) add_definitions(-DDEBUG_TASKS) set(DEBUG ON) endif() + if(DEBUG_TIMERS) + add_definitions(-DDEBUG_TIMERS) + set(DEBUG ON) + endif() if(CLI) add_definitions(-DCLI) set(FIRMWARE_SRC ${FIRMWARE_SRC} cli.cpp) diff --git a/radio/src/cli.cpp b/radio/src/cli.cpp index 3bcd12439..c4a30028c 100644 --- a/radio/src/cli.cpp +++ b/radio/src/cli.cpp @@ -423,10 +423,37 @@ void printTaskSwitchLog() delete[] tsl; serialCrlf(); } - - #endif // #if defined(DEBUG_TASKS) +#if defined(DEBUG_TIMERS) + +void printDebugTime(uint32_t time) +{ + if (time >= 30000) { + serialPrintf("%dms", time/1000); + } + else { + serialPrintf("%d.%03dms", time/1000, time%1000); + } +} + +void printDebugTimer(const char * name, DebugTimer & timer) +{ + serialPrintf("%s: ", name); + printDebugTime( timer.getMin()); + serialPrintf(" - "); + printDebugTime(timer.getMax()); + serialCrlf(); + timer.reset(); +} +void printDebugTimers() +{ + for(int n = 0; n < DEBUG_TIMERS_COUNT; n++) { + printDebugTimer(debugTimerNames[n], debugTimers[n]); + } +} +#endif + int cliDisplay(const char ** argv) { long long int address = 0; @@ -531,6 +558,9 @@ int cliDisplay(const char ** argv) case 2: tim = TIM2; break; + case 13: + tim = TIM13; + break; default: return 0; } @@ -558,12 +588,17 @@ int cliDisplay(const char ** argv) else if (!strcmp(argv[1], "int")) { printInterrupts(); } -#endif //#if defined(DEBUG_INTERRUPTS) +#endif #if defined(DEBUG_TASKS) else if (!strcmp(argv[1], "tsl")) { printTaskSwitchLog(); } -#endif //#if defined(DEBUG_TASKS) +#endif +#if defined(DEBUG_TIMERS) + else if (!strcmp(argv[1], "dt")) { + printDebugTimers(); + } +#endif else if (toLongLongInt(argv, 1, &address) > 0) { int size = 256; if (toInt(argv, 2, &size) >= 0) { diff --git a/radio/src/debug.cpp b/radio/src/debug.cpp index f7d89d472..30ced2354 100644 --- a/radio/src/debug.cpp +++ b/radio/src/debug.cpp @@ -165,3 +165,64 @@ void CoTaskSwitchHook(uint8_t taskID) } #endif // #if defined(DEBUG_TASKS) + +#if defined(DEBUG_TIMERS) + +void DebugTimer::start() +{ + _start_hiprec = getTmr2MHz(); + _start_loprec = get_tmr10ms(); +} + +void DebugTimer::stop() +{ + // getTmr2MHz is 16 bit timer, resolution 0.5us, max measurable value 32.7675 milli seconds + // tmr10ms_t tmr10ms = get_tmr10ms(); 32 bit timer, resolution 10ms, max measurable value: 42949672.95 s = 1.3 years + // if time difference is bigger than 30ms, then use low resolution timer + // otherwise use high resolution + if ((_start_hiprec == 0) && (_start_loprec == 0)) return; + + last = get_tmr10ms() - _start_loprec; //use low precision timer + if (last < 3) { + //use high precision + last = (uint16_t)(getTmr2MHz() - _start_hiprec) / 2; + } + else { + last *= 10000ul; //adjust unit to 1us + } + evalStats(); +} + +DebugTimer debugTimers[DEBUG_TIMERS_COUNT]; + +const char * debugTimerNames[DEBUG_TIMERS_COUNT] = { + "Pulses int." // debugTimerIntPulses, + ,"Pulses dur." // debugTimerIntPulsesDuration, + ,"10ms dur. " // debugTimerPer10ms, + ,"Rotary enc." // debugTimerRotEnc, + ,"Haptic " // debugTimerHaptic, + ,"Mixer calc " // debugTimerMixer, + ,"Tel. wakeup" // debugTimerTelemetryWakeup, + ,"perMain dur" // debugTimerPerMain, + ," perMain s1" // debugTimerPerMain1, + ," guiMain " // debugTimerGuiMain, + ," LUA bg " // debugTimerLuaBg, + ," LCD wait " // debugTimerLcdRefreshWait, + ," LUA fg " // debugTimerLuaFg, + ," LCD refr." // debugTimerLcdRefresh, + ," Menus " // debugTimerMenus, + ," Menu hnd" // debugTimerMenuHandlers, + ,"Menu Vers. " // debugTimerVersion, + ,"Menu simple" // debugTimerSimpleMenu, + ,"Menu drawte" // debugTimerDrawText, + ,"Menu drawt1" // debugTimerDrawText1, + ,"Mix ADC " // debugTimerGetAdc, + ,"Mix getsw " // debugTimerGetSwitches, + ,"Mix eval " // debugTimerEvalMixes, + ,"Mix 10ms " // debugTimerMixes10ms, + ,"ADC read " // debugTimerAdcRead, + ,"ADC loop " // debugTimerAdcLoop, + ,"ADC wait " // debugTimerAdcWait, +}; + +#endif diff --git a/radio/src/debug.h b/radio/src/debug.h index 006143d08..74dd90543 100644 --- a/radio/src/debug.h +++ b/radio/src/debug.h @@ -256,5 +256,94 @@ extern void CoTaskSwitchHook(uint8_t taskID); #endif // #if defined(DEBUG_TASKS) + +#if defined(DEBUG_TIMERS) + +#if defined(__cplusplus) +typedef uint32_t debug_timer_t; + +class DebugTimer +{ +private: + debug_timer_t min; + debug_timer_t max; + // debug_timer_t avg; + debug_timer_t last; //unit 1us + + uint16_t _start_hiprec; + uint32_t _start_loprec; + + void evalStats() { + if (min > last) min = last; + if (max < last) max = last; + //todo avg + } + +public: + DebugTimer(): min(-1), max(0), /*avg(0),*/ last(0), _start_hiprec(0), _start_loprec(0) {}; + + void start(); + void stop(); + void sample() { stop(); start(); } + + void reset() { min = -1; max = last = 0; } + + debug_timer_t getMin() const { return min; } + debug_timer_t getMax() const { return max; } + debug_timer_t getLast() const { return last; } +}; + +enum DebugTimers { + debugTimerIntPulses, + debugTimerIntPulsesDuration, + debugTimerPer10ms, + debugTimerRotEnc, + debugTimerHaptic, + debugTimerMixer, + debugTimerTelemetryWakeup, + debugTimerPerMain, + debugTimerPerMain1, + debugTimerGuiMain, + debugTimerLuaBg, + debugTimerLcdRefreshWait, + debugTimerLuaFg, + debugTimerLcdRefresh, + debugTimerMenus, + debugTimerMenuHandlers, + debugTimerVersion, + debugTimerSimpleMenu, + debugTimerDrawText, + debugTimerDrawText1, + + debugTimerGetAdc, + debugTimerGetSwitches, + debugTimerEvalMixes, + debugTimerMixes10ms, + + debugTimerAdcRead, + debugTimerAdcLoop, + debugTimerAdcWait, + + DEBUG_TIMERS_COUNT +}; + +extern DebugTimer debugTimers[DEBUG_TIMERS_COUNT]; +extern const char * debugTimerNames[DEBUG_TIMERS_COUNT]; + +#endif // #if defined(__cplusplus) + +#define DEBUG_TIMER_START(timer) debugTimers[timer].start() +#define DEBUG_TIMER_STOP(timer) debugTimers[timer].stop() +#define DEBUG_TIMER_SAMPLE(timer) debugTimers[timer].sample() + + +#else //#if defined(DEBUG_TIMERS) + +#define DEBUG_TIMER_START(timer) +#define DEBUG_TIMER_STOP(timer) +#define DEBUG_TIMER_SAMPLE(timer) + +#endif //#if defined(DEBUG_TIMERS) + #endif // _DEBUG_H_ diff --git a/radio/src/gui/horus/menu_general_version.cpp b/radio/src/gui/horus/menu_general_version.cpp index 546bdd8b8..05a61c290 100644 --- a/radio/src/gui/horus/menu_general_version.cpp +++ b/radio/src/gui/horus/menu_general_version.cpp @@ -22,18 +22,25 @@ bool menuGeneralVersion(evt_t event) { + DEBUG_TIMER_START(debugTimerVersion); + DEBUG_TIMER_START(debugTimerSimpleMenu); SIMPLE_MENU(STR_MENUVERSION, LBM_RADIO_ICONS, menuTabGeneral, e_Vers, 0); + DEBUG_TIMER_STOP(debugTimerSimpleMenu); + DEBUG_TIMER_START(debugTimerDrawText); + DEBUG_TIMER_START(debugTimerDrawText1); lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP + FH, vers_stamp); + DEBUG_TIMER_STOP(debugTimerDrawText1); lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP + 2*FH, date_stamp); lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP + 3*FH, time_stamp); lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP + 4*FH, eeprom_stamp); + DEBUG_TIMER_STOP(debugTimerDrawText); // TODO EEPROM erase + backup // lcd_putsCenter(MENU_HEADER_HEIGHT+6*FH, STR_EEBACKUP); // if (event == EVT_KEY_LONG(KEY_ENTER)) { // backupEeprom(); // } - + DEBUG_TIMER_STOP(debugTimerVersion); return true; } diff --git a/radio/src/main_arm.cpp b/radio/src/main_arm.cpp index 6b5103aee..d4cc9d450 100644 --- a/radio/src/main_arm.cpp +++ b/radio/src/main_arm.cpp @@ -178,22 +178,27 @@ void guiMain(evt_t evt) } // run Lua scripts that don't use LCD (to use CPU time while LCD DMA is running) + DEBUG_TIMER_START(debugTimerLuaBg); luaTask(0, RUN_MIX_SCRIPT | RUN_FUNC_SCRIPT | RUN_TELEM_BG_SCRIPT, false); - + DEBUG_TIMER_STOP(debugTimerLuaBg); // wait for LCD DMA to finish before continuing, because code from this point // is allowed to change the contents of LCD buffer // // WARNING: make sure no code above this line does any change to the LCD display buffer! // + DEBUG_TIMER_START(debugTimerLcdRefreshWait); lcdRefreshWait(); + DEBUG_TIMER_STOP(debugTimerLcdRefreshWait); // draw LCD from menus or from Lua script // run Lua scripts that use LCD + DEBUG_TIMER_START(debugTimerLuaFg); refreshNeeded = luaTask(evt, RUN_STNDAL_SCRIPT, true); if (!refreshNeeded) { refreshNeeded = luaTask(evt, RUN_TELEM_FG_SCRIPT, true); } + DEBUG_TIMER_STOP(debugTimerLuaFg); t0 = get_tmr10ms() - t0; if (t0 > maxLuaDuration) { @@ -204,6 +209,7 @@ void guiMain(evt_t evt) #endif if (!refreshNeeded) { + DEBUG_TIMER_START(debugTimerMenus); while (1) { // normal GUI from menus const char * warn = warningText; @@ -241,7 +247,9 @@ void guiMain(evt_t evt) } popupDisplayed = false; } + DEBUG_TIMER_START(debugTimerMenuHandlers); refreshNeeded = menuHandlers[menuLevel](evt); + DEBUG_TIMER_STOP(debugTimerMenuHandlers); } if (menuEvent == EVT_ENTRY) { @@ -260,10 +268,13 @@ void guiMain(evt_t evt) break; } } + DEBUG_TIMER_STOP(debugTimerMenus); } if (refreshNeeded) { + DEBUG_TIMER_START(debugTimerLcdRefresh); lcdRefresh(); + DEBUG_TIMER_STOP(debugTimerLcdRefresh); } } #elif defined(GUI) @@ -384,6 +395,7 @@ void guiMain(evt_t evt) void perMain() { + DEBUG_TIMER_START(debugTimerPerMain1); #if defined(PCBSKY9X) && !defined(REVA) calcConsumption(); #endif @@ -394,6 +406,7 @@ void perMain() handleUsbConnection(); checkTrainerSettings(); periodicTick(); + DEBUG_TIMER_STOP(debugTimerPerMain1); evt_t evt = getEvent(false); if (evt && (g_eeGeneral.backlightMode & e_backlight_mode_keys)) backlightOn(); // on keypress turn the light on @@ -423,7 +436,9 @@ void perMain() #endif #if defined(GUI) + DEBUG_TIMER_START(debugTimerGuiMain); guiMain(evt); + DEBUG_TIMER_STOP(debugTimerGuiMain); #endif #if defined(PCBTARANIS) diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 10830210d..ed38b9e8f 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -1588,6 +1588,7 @@ void getADC() } #endif + DEBUG_TIMER_START(debugTimerAdcRead); for (uint8_t i=0; i<4; i++) { adcRead(); for (uint8_t x=0; x> (3 - ANALOG_SCALE); @@ -1773,13 +1775,17 @@ void doMixerCalculations() // therefore forget the exact calculation and use only 1 instead; good compromise lastTMR = tmr10ms; + DEBUG_TIMER_START(debugTimerGetAdc); getADC(); + DEBUG_TIMER_STOP(debugTimerGetAdc); #if defined(PCBTARANIS) processSbusInput(); #endif + DEBUG_TIMER_START(debugTimerGetSwitches); getSwitchesPosition(!s_mixer_first_run_done); + DEBUG_TIMER_STOP(debugTimerGetSwitches); #if defined(PCBSKY9X) && !defined(REVA) && !defined(SIMU) Current_analogue = (Current_analogue*31 + s_anaFilt[8] ) >> 5 ; @@ -1791,13 +1797,16 @@ void doMixerCalculations() adcPrepareBandgap(); #endif + DEBUG_TIMER_START(debugTimerEvalMixes); evalMixes(tick10ms); + DEBUG_TIMER_STOP(debugTimerEvalMixes); #if !defined(CPUARM) // Bandgap has had plenty of time to settle... getADC_bandgap(); #endif + DEBUG_TIMER_START(debugTimerMixes10ms); if (tick10ms) { #if !defined(CPUM64) && !defined(ACCURAT_THROTTLE_TIMER) @@ -1942,6 +1951,7 @@ void doMixerCalculations() checkTrims(); #endif } + DEBUG_TIMER_STOP(debugTimerMixes10ms); s_mixer_first_run_done = true; } diff --git a/radio/src/targets/horus/adc_driver.cpp b/radio/src/targets/horus/adc_driver.cpp index b8f0f9bcb..49c45d92b 100644 --- a/radio/src/targets/horus/adc_driver.cpp +++ b/radio/src/targets/horus/adc_driver.cpp @@ -178,6 +178,7 @@ void adcRead() ADC_CS_HIGH(); delay_01us(1); + DEBUG_TIMER_START(debugTimerAdcLoop); for (uint32_t adcIndex=0; adcIndexLISR & DMA_LISR_TCIF1) { break; } } + DEBUG_TIMER_STOP(debugTimerAdcWait); // On chip ADC read should have finished } diff --git a/radio/src/targets/horus/board_horus.cpp b/radio/src/targets/horus/board_horus.cpp index 66ca387a3..c9ca34b9c 100644 --- a/radio/src/targets/horus/board_horus.cpp +++ b/radio/src/targets/horus/board_horus.cpp @@ -1,268 +1,274 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "../../opentx.h" - -#if defined(__cplusplus) && !defined(SIMU) -extern "C" { -#endif -#include "STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_dcd_int.h" -#include "STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_bsp.h" -#if defined(__cplusplus) && !defined(SIMU) -} -#endif - -void watchdogInit(unsigned int duration) -{ - IWDG->KR = 0x5555 ; // Unlock registers - IWDG->PR = 3 ; // Divide by 32 => 1kHz clock - IWDG->KR = 0x5555 ; // Unlock registers - IWDG->RLR = duration ; // 1.5 seconds nominal - IWDG->KR = 0xAAAA ; // reload - IWDG->KR = 0xCCCC ; // start -} - -void getCPUUniqueID(char * s) -{ - uint32_t * cpu_uid = (uint32_t *)0x1FFF7A10; - char * tmp = strAppendUnsigned(s, cpu_uid[0], 8, 16); - *tmp = ' '; - tmp = strAppendUnsigned(tmp+1, cpu_uid[1], 8, 16); - *tmp = ' '; - strAppendUnsigned(tmp+1, cpu_uid[2], 8, 16); -} - -// Start TIMER7 at 2000000Hz -void init2MhzTimer() -{ - TIMER_2MHz_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 2000000 - 1 ; // 0.5 uS, 2 MHz - TIMER_2MHz_TIMER->ARR = 65535; - TIMER_2MHz_TIMER->CR2 = 0; - TIMER_2MHz_TIMER->CR1 = TIM_CR1_CEN; -} - -// Starts TIMER at 1000Hz -void init1msTimer() -{ - INTERRUPT_5MS_TIMER->ARR = 999 ; // 1mS - INTERRUPT_5MS_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1 ; // 1uS from 30MHz - INTERRUPT_5MS_TIMER->CCER = 0 ; - INTERRUPT_5MS_TIMER->CCMR1 = 0 ; - INTERRUPT_5MS_TIMER->EGR = 0 ; - INTERRUPT_5MS_TIMER->CR1 = 5 ; - INTERRUPT_5MS_TIMER->DIER |= 1 ; - NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn) ; - NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 7); -} - -// TODO use the same than board_sky9x.cpp -void interrupt1ms() -{ - static uint32_t pre_scale ; // Used to get 10 Hz counter - - ++pre_scale; - - if (pre_scale == 5 || pre_scale == 10) { - -#if defined(HAPTIC) - HAPTIC_HEARTBEAT(); -#endif - - } - - if ( pre_scale == 10 ) { - pre_scale = 0 ; - per10ms(); - } - - checkRotaryEncoder(); -} - -#if !defined(SIMU) -extern "C" void TIM8_TRG_COM_TIM14_IRQHandler() -{ - TIM14->SR &= ~TIM_SR_UIF ; - interrupt1ms() ; - DEBUG_INTERRUPT(INT_1MS); -} - -void boardInit() -{ - RCC_AHB1PeriphClockCmd(PWR_RCC_AHB1Periph | - LED_RCC_AHB1Periph | - LCD_RCC_AHB1Periph | - AUDIO_RCC_AHB1Periph | - KEYS_RCC_AHB1Periph_GPIO | - ADC_RCC_AHB1Periph | - SERIAL_RCC_AHB1Periph | - TELEMETRY_RCC_AHB1Periph | - AUDIO_RCC_AHB1Periph | - HAPTIC_RCC_AHB1Periph | - INTMODULE_RCC_AHB1Periph | - EXTMODULE_RCC_AHB1Periph, - ENABLE); - RCC_APB1PeriphClockCmd(INTERRUPT_5MS_APB1Periph | - TIMER_2MHz_APB1Periph | - AUDIO_RCC_APB1Periph | - SERIAL_RCC_APB1Periph | - TELEMETRY_RCC_APB1Periph | - AUDIO_RCC_APB1Periph | - EXTMODULE_RCC_APB1Periph, - ENABLE); - RCC_APB2PeriphClockCmd(LCD_RCC_APB2Periph | - ADC_RCC_APB2Periph | - HAPTIC_RCC_APB2Periph | - INTMODULE_RCC_APB2Periph | - EXTMODULE_RCC_APB2Periph, ENABLE); - - pwrInit(); - delaysInit(); - - // FrSky removed the volume chip in latest board, that's why it doesn't answer! - // i2cInit(); - - serial2Init(0, 0); // default serial mode (None if DEBUG not defined) - - __enable_irq(); - - TRACE("Horus started :)"); - - keysInit(); - adcInit(); - lcdInit(); - audioInit(); - init2MhzTimer(); - init1msTimer(); - usbInit(); - hapticInit(); - - // bt_open(); - -#if defined(DEBUG) - DBGMCU_APB1PeriphConfig(DBGMCU_IWDG_STOP|DBGMCU_TIM1_STOP|DBGMCU_TIM2_STOP|DBGMCU_TIM3_STOP|DBGMCU_TIM4_STOP|DBGMCU_TIM5_STOP|DBGMCU_TIM6_STOP|DBGMCU_TIM7_STOP|DBGMCU_TIM8_STOP|DBGMCU_TIM9_STOP|DBGMCU_TIM10_STOP|DBGMCU_TIM11_STOP|DBGMCU_TIM12_STOP|DBGMCU_TIM13_STOP|DBGMCU_TIM14_STOP, ENABLE); -#endif - - ledBlue(); -} - -void boardOff() -{ - BACKLIGHT_OFF(); - - while (pwrPressed()) { - wdt_reset(); - } - - SysTick->CTRL = 0; // turn off systick - pwrOff(); -} - -#endif // #if !defined(SIMU) - -#if defined(USB_JOYSTICK) && !defined(SIMU) -extern USB_OTG_CORE_HANDLE USB_OTG_dev; - -/* - Prepare and send new USB data packet - - The format of HID_Buffer is defined by - USB endpoint description can be found in - file usb_hid_joystick.c, variable HID_JOYSTICK_ReportDesc -*/ -void usbJoystickUpdate(void) -{ - static uint8_t HID_Buffer[HID_IN_PACKET]; - - //buttons - HID_Buffer[0] = 0; //buttons - for (int i = 0; i < 8; ++i) { - if ( channelOutputs[i+8] > 0 ) { - HID_Buffer[0] |= (1 << i); - } - } - - //analog values - //uint8_t * p = HID_Buffer + 1; - for (int i = 0; i < 8; ++i) { - int16_t value = channelOutputs[i] / 8; - if ( value > 127 ) value = 127; - else if ( value < -127 ) value = -127; - HID_Buffer[i+1] = static_cast(value); - } - - USBD_HID_SendReport (&USB_OTG_dev, HID_Buffer, HID_IN_PACKET ); -} - -#endif //#if defined(USB_JOYSTICK) && defined(PCBTARANIS) && !defined(SIMU) - - -uint8_t currentTrainerMode = 0xff; - -void checkTrainerSettings() -{ - uint8_t requiredTrainerMode = g_model.trainerMode; - if (requiredTrainerMode != currentTrainerMode) { - switch (currentTrainerMode) { - case TRAINER_MODE_MASTER_TRAINER_JACK: - stop_trainer_capture(); - break; - case TRAINER_MODE_SLAVE: - stop_trainer_ppm(); - break; - case TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE: - stop_cppm_on_heartbeat_capture() ; - break; - case TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE: - stop_sbus_on_heartbeat_capture() ; - break; - case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT: - serial2Stop(); - } - - currentTrainerMode = requiredTrainerMode; - switch (requiredTrainerMode) { - case TRAINER_MODE_SLAVE: - init_trainer_ppm(); - break; - case TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE: - init_cppm_on_heartbeat_capture() ; - break; - case TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE: - init_sbus_on_heartbeat_capture() ; - break; - case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT: - if (g_eeGeneral.serial2Mode == UART_MODE_SBUS_TRAINER) { - serial2SbusInit(); - break; - } - // no break - default: - // master is default - init_trainer_capture(); - break; - } - } -} - -uint16_t getBatteryVoltage() -{ - int32_t instant_vbat = anaIn(TX_VOLTAGE); // using filtered ADC value on purpose - return (uint16_t)((instant_vbat * (1000 + g_eeGeneral.txVoltageCalibration) ) / 1629); -} +/* + * Copyright (C) OpenTX + * + * Based on code named + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "../../opentx.h" + +#if defined(__cplusplus) && !defined(SIMU) +extern "C" { +#endif +#include "STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_dcd_int.h" +#include "STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_bsp.h" +#if defined(__cplusplus) && !defined(SIMU) +} +#endif + +void watchdogInit(unsigned int duration) +{ + IWDG->KR = 0x5555 ; // Unlock registers + IWDG->PR = 3 ; // Divide by 32 => 1kHz clock + IWDG->KR = 0x5555 ; // Unlock registers + IWDG->RLR = duration ; // 1.5 seconds nominal + IWDG->KR = 0xAAAA ; // reload + IWDG->KR = 0xCCCC ; // start +} + +void getCPUUniqueID(char * s) +{ + uint32_t * cpu_uid = (uint32_t *)0x1FFF7A10; + char * tmp = strAppendUnsigned(s, cpu_uid[0], 8, 16); + *tmp = ' '; + tmp = strAppendUnsigned(tmp+1, cpu_uid[1], 8, 16); + *tmp = ' '; + strAppendUnsigned(tmp+1, cpu_uid[2], 8, 16); +} + +// Start TIMER7 at 2000000Hz +void init2MhzTimer() +{ + TIMER_2MHz_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 2000000 - 1 ; // 0.5 uS, 2 MHz + TIMER_2MHz_TIMER->ARR = 65535; + TIMER_2MHz_TIMER->CR2 = 0; + TIMER_2MHz_TIMER->CR1 = TIM_CR1_CEN; +} + +// Starts TIMER at 1000Hz +void init1msTimer() +{ + INTERRUPT_5MS_TIMER->ARR = 999 ; // 1mS + INTERRUPT_5MS_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1 ; // 1uS from 30MHz + INTERRUPT_5MS_TIMER->CCER = 0 ; + INTERRUPT_5MS_TIMER->CCMR1 = 0 ; + INTERRUPT_5MS_TIMER->EGR = 0 ; + INTERRUPT_5MS_TIMER->CR1 = 5 ; + INTERRUPT_5MS_TIMER->DIER |= 1 ; + NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn) ; + NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 7); +} + +// TODO use the same than board_sky9x.cpp +void interrupt1ms() +{ + static uint32_t pre_scale ; // Used to get 10 Hz counter + + ++pre_scale; + + if (pre_scale == 5 || pre_scale == 10) { + +#if defined(HAPTIC) + DEBUG_TIMER_START(debugTimerHaptic); + HAPTIC_HEARTBEAT(); + DEBUG_TIMER_STOP(debugTimerHaptic); +#endif + + } + + if ( pre_scale == 10 ) { + pre_scale = 0 ; + DEBUG_TIMER_START(debugTimerPer10ms); + per10ms(); + DEBUG_TIMER_STOP(debugTimerPer10ms); + } + + DEBUG_TIMER_START(debugTimerRotEnc); + checkRotaryEncoder(); + DEBUG_TIMER_STOP(debugTimerRotEnc); +} + +#if !defined(SIMU) +extern "C" void TIM8_TRG_COM_TIM14_IRQHandler() +{ + TIM14->SR &= ~TIM_SR_UIF ; + interrupt1ms() ; + DEBUG_INTERRUPT(INT_1MS); +} + +void boardInit() +{ + RCC_AHB1PeriphClockCmd(PWR_RCC_AHB1Periph | + LED_RCC_AHB1Periph | + LCD_RCC_AHB1Periph | + AUDIO_RCC_AHB1Periph | + KEYS_RCC_AHB1Periph_GPIO | + ADC_RCC_AHB1Periph | + SERIAL_RCC_AHB1Periph | + TELEMETRY_RCC_AHB1Periph | + AUDIO_RCC_AHB1Periph | + HAPTIC_RCC_AHB1Periph | + INTMODULE_RCC_AHB1Periph | + EXTMODULE_RCC_AHB1Periph, + ENABLE); + RCC_APB1PeriphClockCmd(INTERRUPT_5MS_APB1Periph | + TIMER_2MHz_APB1Periph | + AUDIO_RCC_APB1Periph | + SERIAL_RCC_APB1Periph | + TELEMETRY_RCC_APB1Periph | + AUDIO_RCC_APB1Periph | + EXTMODULE_RCC_APB1Periph, + ENABLE); + RCC_APB2PeriphClockCmd(LCD_RCC_APB2Periph | + ADC_RCC_APB2Periph | + HAPTIC_RCC_APB2Periph | + INTMODULE_RCC_APB2Periph | + EXTMODULE_RCC_APB2Periph, ENABLE); + + pwrInit(); + delaysInit(); + + // FrSky removed the volume chip in latest board, that's why it doesn't answer! + // i2cInit(); + + serial2Init(0, 0); // default serial mode (None if DEBUG not defined) + + __enable_irq(); + + TRACE("Horus started :)"); + + keysInit(); + adcInit(); + lcdInit(); + audioInit(); + init2MhzTimer(); + init1msTimer(); + usbInit(); + hapticInit(); + + // bt_open(); + +#if defined(DEBUG) + DBGMCU_APB1PeriphConfig(DBGMCU_IWDG_STOP|DBGMCU_TIM1_STOP|DBGMCU_TIM2_STOP|DBGMCU_TIM3_STOP|DBGMCU_TIM4_STOP|DBGMCU_TIM5_STOP|DBGMCU_TIM6_STOP|DBGMCU_TIM7_STOP|DBGMCU_TIM8_STOP|DBGMCU_TIM9_STOP|DBGMCU_TIM10_STOP|DBGMCU_TIM11_STOP|DBGMCU_TIM12_STOP|DBGMCU_TIM13_STOP|DBGMCU_TIM14_STOP, ENABLE); +#endif + + ledBlue(); +} + +void boardOff() +{ + BACKLIGHT_OFF(); + + while (pwrPressed()) { + wdt_reset(); + } + + SysTick->CTRL = 0; // turn off systick + pwrOff(); +} + +#endif // #if !defined(SIMU) + +#if defined(USB_JOYSTICK) && !defined(SIMU) +extern USB_OTG_CORE_HANDLE USB_OTG_dev; + +/* + Prepare and send new USB data packet + + The format of HID_Buffer is defined by + USB endpoint description can be found in + file usb_hid_joystick.c, variable HID_JOYSTICK_ReportDesc +*/ +void usbJoystickUpdate(void) +{ + static uint8_t HID_Buffer[HID_IN_PACKET]; + + //buttons + HID_Buffer[0] = 0; //buttons + for (int i = 0; i < 8; ++i) { + if ( channelOutputs[i+8] > 0 ) { + HID_Buffer[0] |= (1 << i); + } + } + + //analog values + //uint8_t * p = HID_Buffer + 1; + for (int i = 0; i < 8; ++i) { + int16_t value = channelOutputs[i] / 8; + if ( value > 127 ) value = 127; + else if ( value < -127 ) value = -127; + HID_Buffer[i+1] = static_cast(value); + } + + USBD_HID_SendReport (&USB_OTG_dev, HID_Buffer, HID_IN_PACKET ); +} + +#endif //#if defined(USB_JOYSTICK) && defined(PCBTARANIS) && !defined(SIMU) + + +uint8_t currentTrainerMode = 0xff; + +void checkTrainerSettings() +{ + uint8_t requiredTrainerMode = g_model.trainerMode; + if (requiredTrainerMode != currentTrainerMode) { + switch (currentTrainerMode) { + case TRAINER_MODE_MASTER_TRAINER_JACK: + stop_trainer_capture(); + break; + case TRAINER_MODE_SLAVE: + stop_trainer_ppm(); + break; + case TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE: + stop_cppm_on_heartbeat_capture() ; + break; + case TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE: + stop_sbus_on_heartbeat_capture() ; + break; + case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT: + serial2Stop(); + } + + currentTrainerMode = requiredTrainerMode; + switch (requiredTrainerMode) { + case TRAINER_MODE_SLAVE: + init_trainer_ppm(); + break; + case TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE: + init_cppm_on_heartbeat_capture() ; + break; + case TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE: + init_sbus_on_heartbeat_capture() ; + break; + case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT: + if (g_eeGeneral.serial2Mode == UART_MODE_SBUS_TRAINER) { + serial2SbusInit(); + break; + } + // no break + default: + // master is default + init_trainer_capture(); + break; + } + } +} + +uint16_t getBatteryVoltage() +{ + int32_t instant_vbat = anaIn(TX_VOLTAGE); // using filtered ADC value on purpose + return (uint16_t)((instant_vbat * (1000 + g_eeGeneral.txVoltageCalibration) ) / 1629); +} diff --git a/radio/src/targets/horus/pulses_driver.cpp b/radio/src/targets/horus/pulses_driver.cpp index 129610ed4..031d1cf1b 100644 --- a/radio/src/targets/horus/pulses_driver.cpp +++ b/radio/src/targets/horus/pulses_driver.cpp @@ -175,6 +175,8 @@ extern "C" void DMA2_Stream7_IRQHandler(void) extern "C" void TIM1_CC_IRQHandler() { DEBUG_INTERRUPT(INT_TIM1CC); + DEBUG_TIMER_SAMPLE(debugTimerIntPulses); + DEBUG_TIMER_START(debugTimerIntPulsesDuration); INTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE; // stop this interrupt INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // clear flag @@ -206,6 +208,7 @@ extern "C" void TIM1_CC_IRQHandler() } INTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; + DEBUG_TIMER_STOP(debugTimerIntPulsesDuration); } #endif diff --git a/radio/src/tasks_arm.cpp b/radio/src/tasks_arm.cpp index b1a32584a..1bea7d9d6 100644 --- a/radio/src/tasks_arm.cpp +++ b/radio/src/tasks_arm.cpp @@ -105,12 +105,16 @@ void mixerTask(void * pdata) if (!s_pulses_paused) { uint16_t t0 = getTmr2MHz(); + DEBUG_TIMER_START(debugTimerMixer); CoEnterMutexSection(mixerMutex); doMixerCalculations(); CoLeaveMutexSection(mixerMutex); + DEBUG_TIMER_STOP(debugTimerMixer); #if defined(FRSKY) || defined(MAVLINK) + DEBUG_TIMER_START(debugTimerTelemetryWakeup); telemetryWakeup(); + DEBUG_TIMER_STOP(debugTimerTelemetryWakeup); #endif if (heartbeat == HEART_WDT_CHECK) { @@ -145,10 +149,12 @@ void menusTask(void * pdata) #else while (pwrCheck() != e_power_off) { #endif - U64 start = CoGetOSTime(); + uint32_t start = (uint32_t)CoGetOSTime(); + DEBUG_TIMER_START(debugTimerPerMain); perMain(); + DEBUG_TIMER_STOP(debugTimerPerMain); // TODO remove completely massstorage from sky9x firmware - U32 runtime = (U32)(CoGetOSTime() - start); + uint32_t runtime = ((uint32_t)CoGetOSTime() - start); // deduct the thread run-time from the wait, if run-time was more than // desired period, then skip the wait all together if (runtime < MENU_TASK_PERIOD_TICKS) {