Mercurial > public > ostc4
view Discovery/Src/base.c @ 368:50ea68c7a153 MotionDetection
Added menu item for motion detection. There are several possibility to use motion detection for user action input. To select of the a new menu entry has been added to the Sys2 =>Custom View Menu (Variables in german)
author | ideenmodellierer |
---|---|
date | Tue, 13 Aug 2019 21:10:46 +0200 |
parents | e309f78f89a5 |
children | fca370f847f8 |
line wrap: on
line source
/////////////////////////////////////////////////////////////////////////////// /// -*- coding: UTF-8 -*- /// /// \file Discovery/Src/base.c /// \brief main(): init hardware, IRQs and start sub-systems /// \author heinrichs weikamp gmbh /// \date 26-February-2014 /// /// $Id$ /////////////////////////////////////////////////////////////////////////////// /// \par Copyright (c) 2014-2018 Heinrichs Weikamp gmbh /// /// This program is free software: you can redistribute it and/or modify /// it under the terms of the GNU General Public License as published by /// the Free Software Foundation, either version 3 of the License, or /// (at your option) any later version. /// /// 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. /// /// You should have received a copy of the GNU General Public License /// along with this program. If not, see <http://www.gnu.org/licenses/>. ////////////////////////////////////////////////////////////////////////////// /** @verbatim ============================================================================== ##### Firmware Info ##### ============================================================================== [..] In settings.c including text and magic stuff ============================================================================== ##### IRQs ##### ============================================================================== [..] The IRQs are very important and most functions should only run there. PreemptPriority are as follows (#) 2 (low) sprintf _only_ here. Don't use in maintask or anywhere else. Called by Buttons und Timer3 Timer3 is 1/10 second (#) 1 (mid) anything that should work while in IRQ2 like HalDelay(), VSYNC and DMA2D Transfer Complete for housekeepingFrame(); (#) 0 (high) _very very short_ interrupts like The HAL hardware part for spi, uart, i2c. SubPriority within PreemptPriority give the order to execute. Introduced 30.Oct.14 as it used by several HAL examples. Three levelAmbients are available (2 low,1 mid,0 high) The STM32F4 has 4bits for IRQ levelAmbients, divided 2/2 in this code with the NVIC_PRIORITYGROUP_2 setting. ============================================================================== ##### MainTask ##### ============================================================================== [..] For everthing slow without importance to be 'in time'. Like VPM and Buehlmann. No sprintf and probably no GFX_SetFramesTopBottom() stuff neither. If sprintf is called while sprintf is executed it blows up everything. ============================================================================== ##### Frames / the external SDRAM ##### ============================================================================== [..] The SDRAM is handled by getFrame() and releaseFrame(). Each frame with 800*480*2 Bytes. Be carefull to release every frame otherwise there will be a memory leakage over time. housekeepingFrame() in the MainTask takes care of cleaning the frames. All frames are filled with 0x00. This will be transparent with color of CLUT_Font020 (is CLUT 0) if the alpha is set for a 16bit pair. housekeepingFrame() delays the cleaning of frames still used as screen buffer to prevent flickering. [..] use global variable frameCounter[] in gfxengine.c to control memory all but the last three are identical to caller_id for example 0x05 are the menu frames the last but one is a sum for higher numbers (shouldn't be any) the last but one are those in status RELEASED the last are those CLEAR (as of 151202 down to 4 in logbook mode) [..] 4 pages are used for two double memories for screenshots (since Nov. 15) ============================================================================== ##### Display ##### ============================================================================== [..] There is a Top layer, Bottom layer and background color. All are perfectly alpha-blended by hardware. (#) top layer has 800x480 option function calls only as it is not used for cursors here (#) bottom layer has free size and start option to be used for cursors (or sprites in the future ;-) (#) background only black in the moment. ToDo: Could be anything else for warnings etc. if needed [..] Frame updates, switching and cursors is done with (#) GFX_SetFramesTopBottom() and the subset GFX_SetFrameTop() + GFX_SetFrameBottom() Those do not change anything on the display but give commands to.. (#) GFX_change_LTDC() The only place that changes the pointer. This prevents erratic behaviour if several changes are made within one refresh rate of the screen. Is called in IRQ by PD4 and HAL_GPIO_EXTI_IRQHandler from VSYNC signal. [..] Content (#) Colors by LookupTable only. This could be modified by system settings in the future. (gfx_color.h/.c) (#) Text by text_multilinguage.h/.c with one char necessary only starting from '\x80' with automatic language switch by selected_language in SSettings see openEdit_Language() in tMenuEditSystem.c Therefore there are differnent functions for example: write_label_fix() for single char multilanguage write_label_var() for strings that could include multilanguage as well see GFX_write_string() to get an overview of the controls as well as the command list in gfx_engine.h There is no clear before writing, text overlay is always on. Many options to have LargeFont.SmallFont for numbers etc. ============================================================================== ##### Update, DualBoot and build-in FLASH memory usage ##### ============================================================================== [..] Boot0 pin, Boot1/PB2 pin and BFB2 software bit control the behaviour. PB2 should be tied to GND. Boot0 == VDD -> bootloader on start, otherwise boot from Bank1 or Bank2 depending on BFB2. Bank2 contains the Fonts and should contain a proper test code in future Bank1 is the main code (Bank1 is 1 MB too, usage as of Oct. 14 is 200 KB) [..] Bootloader should be either UART or USB (on FS pins _only_) USB HS to FS like on the Eval board does not work. [..] Bootloader for the smaller CPU2 is implemented via the SPI used for DMA copy. ============================================================================== ##### Connection to CPU2 (STM32F411 as of Oct.14 ##### ============================================================================== [..] Connected via SPI and DMA for every purpose. two entire arrays are transfered for data security reasons with respect to master (STM32F429) might interrupt internal data copy in CPU2 (like hi byte, low byte, etc.). [..] The entire life data is calculated in CPU2. Like tissues, CNS,... Therefore the main unit is _not_ necessarily a Real Time system. Simulation on the main unit can be executed without disrupting life data. [..] SPI is triggered and timed by calling DataEX_call() in data_exchange_main.c DataEX_copy_to_LifeData() does the transfer from buffer to variables used. ============================================================================== ##### Menu, MenuEdit, Info ##### ============================================================================== [..] tMenu.c, tMenuEdit.c and tInfo.c is the system used. logbook is part of Info not Menu. The Info Menu is accessed by button 'Back' The regular Menu is accessed by button 'Enter' [..] Menu content is kept in frame memory for fast access. There is no need to build pages if the 'Enter' button is pressed. This is in contrast to MenuEdit pages. [..] Button control for new pages (and pages in general) have to implemented in tMenu.c, tMenuEdit.c or tInfo.c [..] ToDo (Oct. 14) Timeout for menus via Timer3 / IRQ 2 ============================================================================== ##### settings ##### ============================================================================== [..] files: settings.c, settings.h 1. adjust struct SSettings in settings.h 2. adjust const SSettings SettingsStandard in settings.c 3. adjust set_new_settings_missing_in_ext_flash() 4. adjust check_and_correct_settings() IMPORTANT as it changes values! ============================================================================== ##### specials ##### ============================================================================== [..] There was code for vector graphics from great demos (peridiummmm and jupiter) that can be fitted again ============================================================================== ##### ppO2 sensors ##### ============================================================================== [..] in tCCR.c is function get_ppO2SensorWeightedResult_cbar(); @endverbatim ****************************************************************************** * @attention * * <h2><center>© COPYRIGHT(c) 2014 heinrichs weikamp</center></h2> * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stdio.h" #include <string.h> // for memcopy #include "stm32f4xx_hal.h" #include "ostc.h" #include "base.h" #include "display.h" #include "gfx_engine.h" #include "show_logbook.h" #include "text_multilanguage.h" #include "tHome.h" #include "tInfo.h" #include "tInfoLog.h" #include "tMenu.h" #include "tMenuEdit.h" #include "tMenuEditGasOC.h" #include "tStructure.h" #include "externLogbookFlash.h" #include "tComm.h" #include "tCCR.h" #include "data_exchange.h" #include "data_exchange_main.h" #include "vpm.h" #include "buehlmann.h" #include "logbook.h" #include "check_warning.h" #include "simulation.h" #include "decom.h" #include "timer.h" #include "logbook_miniLive.h" #include "test_vpm.h" #include "tDebug.h" #include "motion.h" #ifdef DEMOMODE #include "demo.h" static void TIM_DEMO_init(void); #endif //#include "lodepng.h" //#include <stdlib.h> // for malloc and free /** @addtogroup OSTC 4 * @{ */ /* Private typedef -----------------------------------------------------------*/ //#define NO_TIMEOUT //#define QUICK_SLEEP /* Private define ------------------------------------------------------------*/ #define REFRESH_COUNT ((uint32_t)0x0569) /**< for SDRAM refresh counter (90Mhz SD clock) */ #define INVALID_BUTTON ((uint8_t) 0xFF) /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ static RTC_HandleTypeDef RtcHandle; /* used to change time and date, no RTC is running on this MCU */ TIM_HandleTypeDef TimHandle; /* used in stm32f4xx_it.c too */ static TIM_HandleTypeDef TimBacklightHandle; #ifdef DEMOMODE TIM_HandleTypeDef TimDemoHandle; /* used in stm32f4xx_it.c too */ #endif static uint8_t LastButtonPressed; static uint32_t LastButtonPressedTick; static uint32_t BaseTick100ms; /* Tick at last 100ms cycle */ /* SDRAM handler declaration */ static SDRAM_HandleTypeDef hsdram; static FMC_SDRAM_TimingTypeDef SDRAM_Timing; static FMC_SDRAM_CommandTypeDef command; /* This was used for Dual Boot */ //FLASH_OBProgramInitTypeDef OBInit; //FLASH_AdvOBProgramInitTypeDef AdvOBInit; /* Private variables with external access ------------------------------------*/ static uint32_t globalStateID = 0; static uint32_t time_without_button_pressed_deciseconds = 0; /**< langbeschreibung (eigenes Feld) warum diese variable verwendet wird um den sleepmode zu aktivieren */ uint8_t bootToBootloader = 0; ///< set in tComm.c to install firmware updates, calls resetToFirmwareUpdate() static uint8_t returnFromCommCleanUpRequest = 0; ///< use this to exit bluetooth mode and call tComm_exit() uint32_t base_tempLightLevel = 0; static uint8_t wasFirmwareUpdateCheckBattery = 0; static uint8_t DoDisplayRefresh = 0; /* trigger to refresh display data */ /* Private function prototypes -----------------------------------------------*/ static void SystemClock_Config(void); static void Error_Handler(void); static void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *Command); static void SDRAM_Config(void); static void EXTILine_Buttons_Config(void); static void TIM_init(void); static void TIM_BACKLIGHT_init(void); static uint32_t TIM_BACKLIGHT_adjust(void); static void gotoSleep(void); static void deco_loop(void); static void resetToFirmwareUpdate(void); static void TriggerButtonAction(void); static void EvaluateButton(void); static void RefreshDisplay(void); /* ITM Trace-------- ---------------------------------------------------------*/ /* #define ITM_Port8(n) (*((volatile unsigned char *)(0xE0000000+4*n))) #define ITM_Port16(n) (*((volatile unsigned short*)(0xE0000000+4*n))) #define ITM_Port32(n) (*((volatile unsigned long *)(0xE0000000+4*n))) #define DEMCR (*((volatile unsigned long *)(0xE000EDFC))) #define TRCENA 0x01000000 struct __FILE { int handle; }; FILE __stdout; FILE __stdin; int fputc(int ch, FILE *f) { if (DEMCR & TRCENA) { while (ITM_Port32(0) == 0); ITM_Port8(0) = ch; } return(ch); } */ /* #define DEBUG_RUNTIME TRUE */ #ifdef DEBUG_RUNTIME #define MEASURECNT 60 /* number of measuremets to be stored */ static uint32_t loopcnt[MEASURECNT]; #endif static uint8_t ButtonAction = ACTION_END; static void StoreButtonAction(uint8_t action) { ButtonAction = action; } // =============================================================================== // main /// @brief This function makes initializations and has the nonIRQ endless loop /// for bluetooth and deco calculations /// // =============================================================================== int main(void) { uint32_t pLayerInvisible; uint16_t totalDiveCounterFound; #ifdef DEBUG_RUNTIME RTC_TimeTypeDef Stime; uint8_t measurementindex = 0; uint8_t lastsecond = 0xFF; #endif detectionState_t pitchstate; set_globalState( StBoot0 ); LastButtonPressed = 0; HAL_Init(); HAL_NVIC_SetPriorityGrouping( NVIC_PRIORITYGROUP_2 ); SystemClock_Config(); MX_GPIO_Init(); // MX_SmallCPU_NO_Reset_Helper(); //161116 hw MX_SPI_Init(); MX_UART_Init(); SDRAM_Config(); HAL_Delay( 100 ); stateRealGetPointerWrite()->lastKnownBatteryPercentage = 0; // damit das nicht in settings kopiert wird. set_settings_to_Standard(); mod_settings_for_first_start_with_empty_ext_flash(); ext_flash_read_settings(); if( newFirmwareVersionCheckViaSettings() ) // test for old firmware version in loaded settings { wasFirmwareUpdateCheckBattery = 1; set_settings_button_to_standard_with_individual_buttonBalance(); // will adapt individual values } //settingsGetPointer()->bluetoothActive = 0; /* MX_Bluetooth_PowerOff(); unnecessary as part of MX_GPIO_Init() */ //settingsGetPointer()->compassBearing = 0; set_new_settings_missing_in_ext_flash(); // includes update of firmware version 161121 GFX_init( &pLayerInvisible ); TIM_BACKLIGHT_init(); // new 170508: bluetooth on at start settingsGetPointer()->bluetoothActive = 1; MX_Bluetooth_PowerOn(); // Haase Geburtstag: // settingsGetPointer()->serialHigh = (3012 / 256); // settingsGetPointer()->serialLow = (3012 & 0xFF); // settingsGetPointer()->showDebugInfo = 1; /* if( (hardwareDataGetPointer()->primarySerial == 20+18) || (hardwareDataGetPointer()->primarySerial == 20+25) || (hardwareDataGetPointer()->primarySerial == 20+27)) { MX_Bluetooth_PowerOn(); tComm_Set_Bluetooth_Name(1); } */ errorsInSettings = check_and_correct_settings(); createDiveSettings(); #ifdef QUICK_SLEEP settingsGetPointer()->timeoutSurfacemode = 20; #else settingsGetPointer()->timeoutSurfacemode = 120; #endif #ifdef DEMOMODE demoConfigureSettings(); TIM_DEMO_init(); #endif // ----------------------------- display_power_on__1_of_2__pre_RGB(); GFX_LTDC_Init(); GFX_LTDC_LayerDefaultInit( TOP_LAYER, pLayerInvisible ); GFX_LTDC_LayerDefaultInit( BACKGRD_LAYER, pLayerInvisible ); GFX_SetFramesTopBottom( pLayerInvisible, pLayerInvisible, 480 ); HAL_Delay( 20 ); display_power_on__2_of_2__post_RGB(); GFX_use_colorscheme( settingsGetPointer()->tX_colorscheme ); tHome_init(); tI_init(); tM_init(); tMenuEdit_init(); tInfoLog_init(); tComm_init(); DataEX_init(); setButtonResponsiveness( settingsGetPointer()->ButtonResponsiveness ); set_globalState_tHome(); GFX_start_VSYNC_IRQ(); tCCR_init(); GFX_logoAutoOff(); EXTILine_Buttons_Config(); ext_flash_repair_dive_log(); //ext_flash_repair_SPECIAL_dive_numbers_starting_count_with(1); totalDiveCounterFound = logbook_lastDive_diveNumber(); if( settingsGetPointer()->totalDiveCounter < totalDiveCounterFound ) settingsGetPointer()->totalDiveCounter = totalDiveCounterFound; if( settingsGetPointer()->debugModeOnStart ) { settingsGetPointer()->debugModeOnStart = 0; ext_flash_write_settings(); setDebugMode(); openInfo( StIDEBUG ); } InitMotionDetection(); TIM_init(); /* start cylic 100ms task */ /* @brief main LOOP * * this is executed while no IRQ interrupts it * - deco calculation * - bluetooth * and resetToFirmwareUpdate() * because tComm_control() does not exit before disconnection */ while( 1 ) { if( bootToBootloader ) resetToFirmwareUpdate(); tCCR_control(); if( tComm_control() )// will stop while loop if tComm Mode started until exit from UART { createDiveSettings(); updateMenu(); ext_flash_write_settings(); } deco_loop(); TriggerButtonAction(); if(DoDisplayRefresh) { DoDisplayRefresh = 0; RefreshDisplay(); switch(settingsGetPointer()->MotionDetection) { case MOTION_DETECT_MOVE: pitchstate = detectPitch(stateRealGetPointer()->lifeData.compass_pitch); break; case MOTION_DETECT_SECTOR: pitchstate = detectSectorButtonEvent(stateRealGetPointer()->lifeData.compass_pitch); break; default: pitchstate = DETECT_NOTHING; break; } if(DETECT_NEG_PITCH == pitchstate) { StoreButtonAction((uint8_t)ACTION_PITCH_NEG); } if(DETECT_POS_PITCH == pitchstate) { StoreButtonAction((uint8_t)ACTION_PITCH_POS); } // Enable this to make the simulator write a logbook entry // #define SIM_WRITES_LOGBOOK 1 #ifdef SIM_WRITES_LOGBOOK if(stateUsed == stateSimGetPointer()) logbook_InitAndWrite(stateUsed); #endif if(stateUsed == stateRealGetPointer()) /* Handle log entries while in dive mode*/ logbook_InitAndWrite(stateUsed); } #ifdef DEBUG_RUNTIME translateTime(stateUsed->lifeData.timeBinaryFormat, &Stime); if(lastsecond == 0xFF) { measurementindex = 0; loopcnt[measurementindex] = 0; lastsecond = Stime.Seconds; } loopcnt[measurementindex]++; if(lastsecond != Stime.Seconds) { measurementindex++; if (measurementindex == MEASURECNT) measurementindex = 0; loopcnt[measurementindex] = 0; lastsecond = Stime.Seconds; if(measurementindex +1 < MEASURECNT) loopcnt[measurementindex +1] = 0xffff; /* helps to identify the latest value */ } #endif } } // =============================================================================== // timer IRQ /// @brief this is called periodically /// /// - refresh screen (the actual change is done in the VSYNC IRQ) /// - start data transfer with RTE / small CPU (DateEX....) /// - update logbook /// - timeouts /// .... /// /// all this in three steps / switch() routines in a given order /// as the previous switch() might influence the next functions /// to be called /// // =============================================================================== void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { #ifdef DEMOMODE if(htim->Instance==TIM7) { HAL_GPIO_EXTI_Callback(demoGetCommand()); return; } #endif static uint8_t last_base; SStateList status; uint32_t timeout_in_seconds; uint32_t timeout_limit_Surface_in_seconds; BaseTick100ms = HAL_GetTick(); /* store start of 100ms cycle */ _Bool InDiveMode = 0; _Bool modeChange = 0; // to exit from menu and logbook if(stateUsed->mode == MODE_DIVE) InDiveMode = 1; else InDiveMode = 0; EvaluateButton(); if(returnFromCommCleanUpRequest) { tComm_exit(); returnFromCommCleanUpRequest = 0; } get_globalStateList(&status); switch(status.base) { case BaseHome: case BaseMenu: case BaseInfo: updateSetpointStateUsed(); DateEx_copy_to_dataOut(); DataEX_copy_to_LifeData(&modeChange); //foto session :-) stateRealGetPointerWrite()->lifeData.battery_charge = 99; //foto session :-) stateSimGetPointerWrite()->lifeData.battery_charge = 99; DataEX_copy_to_deco(); DataEX_call(); if(stateUsed == stateSimGetPointer()) { simulation_UpdateLifeData(1); } check_warning(); updateMiniLiveLogbook(1); timer_UpdateSecond(1); base_tempLightLevel = TIM_BACKLIGHT_adjust(); tCCR_tick(); tHome_tick(); if(status.base == BaseHome) tMenuEdit_writeSettingsToFlash(); // takes 900 ms!! break; case BaseStop: DateEx_copy_to_dataOut(); DataEX_call(); DataEX_control_connection_while_asking_for_sleep(); break; default: case BaseComm: if(get_globalState() == StUART_RTECONNECT) { DateEx_copy_to_dataOut(); DataEX_call(); DataEX_copy_to_LifeData(0); } break; } /* timeout control */ if(modeChange) ///< from RTE, set in data_exchange_main.c time_without_button_pressed_deciseconds = (settingsGetPointer()->timeoutSurfacemode / 4) * 3; if(status.base != last_base) time_without_button_pressed_deciseconds = 0; last_base = status.base; timeout_in_seconds = time_without_button_pressed_deciseconds / 10; time_without_button_pressed_deciseconds += 1; if(modeChange || (timeout_in_seconds != time_without_button_pressed_deciseconds / 10)) { #ifdef NO_TIMEOUT timeout_in_seconds = 0; #else timeout_in_seconds += 1; #endif if(InDiveMode) { switch(status.base) { case BaseHome: if((status.line != 0) && (timeout_in_seconds >= settingsGetPointer()->timeoutEnterButtonSelectDive)) { set_globalState(StD); timeout_in_seconds = 0; } break; case BaseMenu: if((status.line == 0) && ((timeout_in_seconds >= settingsGetPointer()->timeoutMenuDive) || modeChange)) { exitMenu(); timeout_in_seconds = 0; } if((status.line != 0) && ((timeout_in_seconds >= settingsGetPointer()->timeoutMenuEdit) || modeChange)) { exitMenuEdit_to_Home(); timeout_in_seconds = 0; } break; default: break; } } else /* surface mode */ { switch(status.base) { case BaseHome: // added hw 161027 if(!(stateRealGetPointer()->warnings.lowBattery) && (stateRealGetPointer()->lifeData.battery_charge > 9)) { stateRealGetPointerWrite()->lastKnownBatteryPercentage = stateRealGetPointer()->lifeData.battery_charge; } else if((wasFirmwareUpdateCheckBattery) && (timeout_in_seconds > 3)) { wasFirmwareUpdateCheckBattery = 0; setButtonResponsiveness(settingsGetPointer()->ButtonResponsiveness); // added 170306 if( (settingsGetPointer()->lastKnownBatteryPercentage > 0) && (settingsGetPointer()->lastKnownBatteryPercentage <= 100) && (stateRealGetPointer()->warnings.lowBattery)) { setBatteryPercentage(settingsGetPointer()->lastKnownBatteryPercentage); } } // stuff before and new @161121 CCR-sensor limit 10 minutes if((settingsGetPointer()->dive_mode == DIVEMODE_CCR) && (settingsGetPointer()->CCR_Mode == CCRMODE_Sensors)) { timeout_limit_Surface_in_seconds = settingsGetPointer()->timeoutSurfacemodeWithSensors; } else { timeout_limit_Surface_in_seconds = settingsGetPointer()->timeoutSurfacemode; } if(timeout_in_seconds >= timeout_limit_Surface_in_seconds) { gotoSleep(); } break; case BaseMenu: if((status.line == 0) && ((timeout_in_seconds >= settingsGetPointer()->timeoutMenuSurface) || modeChange)) { exitMenu(); timeout_in_seconds = 0; } if((status.line != 0) && ((timeout_in_seconds >= settingsGetPointer()->timeoutMenuEdit) || modeChange)) { if((status.page != (uint8_t)((StMPLAN >> 24) & 0x0F)) || (timeout_in_seconds >= 10*(settingsGetPointer()->timeoutMenuEdit))) { exitMenuEdit_to_Home(); timeout_in_seconds = 0; } } break; case BaseInfo: if((timeout_in_seconds >= settingsGetPointer()->timeoutInfo) || modeChange) { if(status.page == InfoPageLogList) { exitLog(); timeout_in_seconds = 0; } else if(status.page == InfoPageLogShow) { show_logbook_exit(); exitLog(); timeout_in_seconds = 0; } else if(status.page != InfoPageCompass) { exitInfo(); timeout_in_seconds = 0; } } break; default: break; } } } get_globalStateList(&status); if(status.base == BaseComm) /* main loop not serviced in com mode */ { tComm_refresh(); } else { DoDisplayRefresh = 1; } } /* button and VSYNC IRQ * * VSYNC will switch foreground and background picture * if demanded. see GFX_change_LTDC() * */ // =============================================================================== // HAL_GPIO_EXTI_Callback /// @brief button and VSYNC IRQ /// /// VSYNC will switch foreground and background picture if demanded - /// see GFX_change_LTDC() /// // =============================================================================== void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (!GPIO_Pin) return; if (GPIO_Pin == VSYNC_IRQ_PIN) // rechts, unten { GFX_change_LTDC(); housekeepingFrame(); /* #ifdef DEMOMODE static uint8_t countCall = 0; if(countCall++ < 10) return; countCall = 0; uint8_t buttonAction = demoGetCommand(); if(buttonAction) GPIO_Pin = buttonAction; else #endif */ return; } LastButtonPressed = GPIO_Pin; LastButtonPressedTick = HAL_GetTick(); #ifdef DEMOMODE uint8_t demoMachineCall = 0; if(GPIO_Pin & 0x80) { demoMachineCall = 1; GPIO_Pin &= 0x7F; } #endif } static void RefreshDisplay() { SStateList status; get_globalStateList(&status); switch(status.base) { case BaseHome: tHome_refresh(); tM_check_content(); break; case BaseMenu: tM_refresh_live_content(); tMenuEdit_refresh_live_content(); break; case BaseInfo: tInfo_refresh(); ///< only compass at the moment 23.Feb.2015 hw break; case BaseComm: /* refresh already done in tim callback */ break; default: if(get_globalState() == StStop) tHome_sleepmode_fun(); break; } } static void TriggerButtonAction() { uint8_t action = ButtonAction; SStateList status; if(ButtonAction != ACTION_END) { get_globalStateList(&status); if (action == ACTION_BUTTON_CUSTOM) { GFX_screenshot(); } switch (status.base) { case BaseStop: if (action == ACTION_BUTTON_BACK) resetToFirmwareUpdate(); break; case BaseComm: /* already handled in tim callback */ break; case BaseHome: if (action == ACTION_BUTTON_NEXT) { if (status.page == PageSurface) openMenu(1); else tHomeDiveMenuControl(action); } else if (action == ACTION_BUTTON_BACK) { if (get_globalState() == StS) openInfo(StILOGLIST); else if ((status.page == PageDive) && (settingsGetPointer()->design < 7)) { settingsGetPointer()->design = 7; // auto switch to 9 if necessary } else if ((status.page == PageDive) && (status.line != 0)) { if (settingsGetPointer()->extraDisplay == EXTRADISPLAY_BIGFONT) settingsGetPointer()->design = 3; else if (settingsGetPointer()->extraDisplay == EXTRADISPLAY_DECOGAME) settingsGetPointer()->design = 4; set_globalState(StD); } else tHome_change_field_button_pressed(); } else if ((action == ACTION_BUTTON_ENTER) || (action == ACTION_PITCH_NEG) || (action == ACTION_PITCH_POS)) { if ((status.page == PageDive) && (status.line == 0)) { tHome_change_customview_button_pressed(action); if((settingsGetPointer()->MotionDetection == MOTION_DETECT_SECTOR) && (action == ACTION_BUTTON_ENTER)) /* Button pressed while sector detection is active => calibrate to current pitch value */ { DefinePitchSectors(stateRealGetPointer()->lifeData.compass_pitch); } } else if (status.page == PageSurface) tHome_change_customview_button_pressed(action); else tHomeDiveMenuControl(action); } break; case BaseMenu: if (status.line == 0) sendActionToMenu(action); else sendActionToMenuEdit(action); break; case BaseInfo: if (status.page == InfoPageLogList) sendActionToInfoLogList(action); else if (status.page == InfoPageLogShow) sendActionToInfoLogShow(action); else sendActionToInfo(action); break; default: break; } ButtonAction = ACTION_END; } } static void EvaluateButton() { uint8_t action = 0; SStateList status; SSettings* pSettings; pSettings = settingsGetPointer(); if (GFX_logoStatus() != 0) return; if ((LastButtonPressed != INVALID_BUTTON) && (time_elapsed_ms(LastButtonPressedTick, HAL_GetTick())) > 50) { if (LastButtonPressed == BUTTON_BACK_PIN) { // links if (HAL_GPIO_ReadPin(BUTTON_BACK_GPIO_PORT, BUTTON_BACK_PIN) == 1) { action = ACTION_BUTTON_BACK; } } else if (LastButtonPressed == BUTTON_ENTER_PIN) { // mitte if (HAL_GPIO_ReadPin(BUTTON_ENTER_GPIO_PORT, BUTTON_ENTER_PIN) == 1) { action = ACTION_BUTTON_ENTER; } } else if (LastButtonPressed == BUTTON_NEXT_PIN) { // rechts if (HAL_GPIO_ReadPin(BUTTON_NEXT_GPIO_PORT, BUTTON_NEXT_PIN) == 1) { action = ACTION_BUTTON_NEXT; } } if(action != 0) { time_without_button_pressed_deciseconds = 0; if(pSettings->FlipDisplay) /* switch action resulting from pressed button */ { if (action == ACTION_BUTTON_BACK) { action = ACTION_BUTTON_NEXT; } else { if (action == ACTION_BUTTON_NEXT) { action = ACTION_BUTTON_BACK; } } } } #ifdef BUTTON_CUSTOM_PIN else if(LastButtonPressed == BUTTON_CUSTOM_PIN) // extra action = ACTION_BUTTON_CUSTOM; #endif #ifdef DEMOMODE // user pressed button ? if((!demoMachineCall) && demoModeActive()) { demoSendCommand(action); return; } #endif get_globalStateList(&status); if(status.base == BaseComm) /* main loop is not serviced in comm mode => react immediately */ { if (action == ACTION_BUTTON_BACK) { settingsGetPointer()->bluetoothActive = 0; MX_Bluetooth_PowerOff(); tComm_exit(); } } else { StoreButtonAction(action); /* Handle action in main loop */ } LastButtonPressed = INVALID_BUTTON; } } static void gotoSleep(void) { /* not at the moment of testing */ // ext_flash_erase_firmware_if_not_empty(); GFX_logoAutoOff(); set_globalState(StStop); } // ----------------------------- uint32_t get_globalState(void) { return globalStateID; } void get_globalStateList(SStateList *output) { output->base = (uint8_t)((globalStateID >> 28) & 0x0F); output->page = (uint8_t)((globalStateID >> 24) & 0x0F); output->line = (uint8_t)((globalStateID >> 16) & 0xFF); output->field = (uint8_t)((globalStateID >> 8) & 0xFF); output->mode = (uint8_t)((globalStateID ) & 0xFF); } void get_idSpecificStateList(uint32_t id, SStateList *output) { output->base = (uint8_t)((id >> 28) & 0x0F); output->page = (uint8_t)((id >> 24) & 0x0F); output->line = (uint8_t)((id >> 16) & 0xFF); output->field = (uint8_t)((id >> 8) & 0xFF); output->mode = (uint8_t)((id ) & 0xFF); } void set_globalState_Menu_Page(uint8_t page) { globalStateID = ((BaseMenu << 28) + (page << 24)); } void set_globalState_Log_Page(uint8_t pageIsLine) { globalStateID = StILOGLIST + (pageIsLine << 16); } void set_globalState_Menu_Line(uint8_t line) { globalStateID = ((globalStateID & MaskLineFieldDigit) + (line << 16)); } void set_globalState(uint32_t newID) { globalStateID = newID; } void set_returnFromComm(void) { returnFromCommCleanUpRequest = 1; } uint8_t font_update_required(void) { uint8_t *fontVersionHigh; uint8_t *fontVersionLow; fontVersionHigh = (uint8_t *)0x08132000; fontVersionLow = (uint8_t *)0x08132001; if(FONTminimum_required_high() < *fontVersionHigh) return 0; if((FONTminimum_required_high() == *fontVersionHigh) && (FONTminimum_required_low() <= *fontVersionLow)) return 0; return 1; } __attribute__((optimize("O0"))) void delayMicros(uint32_t micros) { micros = micros * (168/4) - 10; while(micros--); } void get_RTC_DateTime(RTC_DateTypeDef * sdatestructureget, RTC_TimeTypeDef * stimestructureget) { /* Get the RTC current Time */ if(sdatestructureget) HAL_RTC_GetTime(&RtcHandle, stimestructureget, FORMAT_BIN); /* Get the RTC current Date */ if(stimestructureget) HAL_RTC_GetDate(&RtcHandle, sdatestructureget, FORMAT_BIN); } void set_RTC_DateTime(RTC_DateTypeDef * sdatestructure, RTC_TimeTypeDef * stimestructure) { if(sdatestructure) if(HAL_RTC_SetDate(&RtcHandle,sdatestructure,FORMAT_BCD) != HAL_OK) { /* Initialization Error */ Error_Handler(); } if(stimestructure) if(HAL_RTC_SetTime(&RtcHandle,stimestructure,FORMAT_BCD) != HAL_OK) { /* Initialization Error */ Error_Handler(); } } static void TIM_init(void) { uint16_t uwPrescalerValue = 0; uwPrescalerValue = (uint32_t) ((SystemCoreClock /2) / 10000) - 1; /* Set TIMx instance */ TimHandle.Instance = TIMx; /* Initialize TIM3 peripheral as follows: + Period = 10000 - 1 + Prescaler = ((SystemCoreClock/2)/10000) - 1 + ClockDivision = 0 + Counter direction = Up */ TimHandle.Init.Period = 1000 - 1; TimHandle.Init.Prescaler = uwPrescalerValue; TimHandle.Init.ClockDivision = 0; TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP; if(HAL_TIM_Base_Init(&TimHandle) != HAL_OK) { /* Initialization Error */ Error_Handler(); } /*##-2- Start the TIM Base generation in interrupt mode ####################*/ /* Start Channel1 */ if(HAL_TIM_Base_Start_IT(&TimHandle) != HAL_OK) { /* Starting Error */ Error_Handler(); } } #ifdef DEMOMODE static void TIM_DEMO_init(void) { uint16_t uwPrescalerValue = 0; uwPrescalerValue = (uint32_t) ((SystemCoreClock /2) / 10000) - 1; /* Set TIMx instance */ TimDemoHandle.Instance = TIM7; /* Initialize TIM3 peripheral as follows: + Period = 10000 - 1 + Prescaler = ((SystemCoreClock/2)/10000) - 1 + ClockDivision = 0 + Counter direction = Up */ TimDemoHandle.Init.Period = 1000 - 1; TimDemoHandle.Init.Prescaler = uwPrescalerValue; TimDemoHandle.Init.ClockDivision = 0; TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP; if(HAL_TIM_Base_Init(&TimDemoHandle) != HAL_OK) { /* Initialization Error */ Error_Handler(); } /*##-2- Start the TIM Base generation in interrupt mode ####################*/ /* Start Channel1 */ if(HAL_TIM_Base_Start_IT(&TimDemoHandle) != HAL_OK) { /* Starting Error */ Error_Handler(); } } #endif #ifndef TIM_BACKLIGHT static uint32_t TIM_BACKLIGHT_adjust(void) { return 0; } static void TIM_BACKLIGHT_init(void) { } #else static uint32_t TIM_BACKLIGHT_adjust(void) { static uint32_t levelActual = 12000; static uint8_t brightnessModeLast = 0; // static _Bool wasLostConnection = 0; uint32_t levelAmbient; uint32_t levelMax; uint32_t levelMin; uint32_t levelUpStep_100ms = 200; uint32_t levelDnStep_100ms = 20; TIM_OC_InitTypeDef sConfig; sConfig.OCMode = TIM_OCMODE_PWM1; sConfig.OCPolarity = TIM_OCPOLARITY_HIGH; sConfig.OCFastMode = TIM_OCFAST_DISABLE; const SDiveState * pStateReal = stateRealGetPointer(); // if(pStateReal->data_old__lost_connection_to_slave) // { // changed 160613 from 6000 to 12000 // removed hw 161209 // levelAmbient = 12000; // levelActual = 12000; // wasLostConnection = 1; // } // else // { SSettings *pSettings = settingsGetPointer(); /* 300 - 4000 */ /* important levelAmbient 300 - 1200 */ levelAmbient = 10 * pStateReal->lifeData.ambient_light_level; switch( pSettings->brightness) { case 0: /* Cave */ levelMax = 3000;/* max 25 % (x2) */ levelMin = 1500; break; case 1: /* Eco */ levelMax = 6000;/* max 50 % (x2) */ levelMin = 3000; break; case 2: /* Std */ levelAmbient += 1000; levelMax = 9000; levelMin = 4500; levelUpStep_100ms += levelUpStep_100ms/2; // 4500 instead of 3000 levelDnStep_100ms += levelDnStep_100ms/2; break; case 3: /* High */ default: levelAmbient += 3000; levelMax = 12000; /* max 100% (x2) */ levelMin = 6000; levelUpStep_100ms += levelUpStep_100ms; // 6000 instead of 3000 levelDnStep_100ms += levelDnStep_100ms; break; case 4: /* New Max */ levelAmbient = 12000; levelMax = 12000; /* max 100% (x2) */ levelMin = 12000; levelUpStep_100ms += 12000; levelDnStep_100ms += 0; break; } if((pSettings->brightness != brightnessModeLast))// || wasLostConnection) { levelActual = levelAmbient; brightnessModeLast = pSettings->brightness; // wasLostConnection = 0; } // } if(levelAmbient > levelActual) levelActual += levelUpStep_100ms; else if((levelAmbient < levelActual) && (levelActual > levelMin) && (levelActual > levelDnStep_100ms)) levelActual -= levelDnStep_100ms; if(levelActual > levelMax) levelActual = levelMax; else if(levelActual < levelMin) levelActual = levelMin; // sConfig.Pulse = levelActual / 20; sConfig.Pulse = (levelMin + ((levelMax - levelMin)/2)) / 20; // added 170306 /* xx - 600 */ if(sConfig.Pulse > 600) sConfig.Pulse = 600; else if(sConfig.Pulse < 100) sConfig.Pulse = 100; HAL_TIM_PWM_ConfigChannel(&TimBacklightHandle, &sConfig, TIM_BACKLIGHT_CHANNEL); HAL_TIM_PWM_Start(&TimBacklightHandle, TIM_BACKLIGHT_CHANNEL); return levelActual; } static void TIM_BACKLIGHT_init(void) { uint32_t uwPrescalerValue = 0; TIM_OC_InitTypeDef sConfig; uwPrescalerValue = (uint32_t) ((SystemCoreClock /2) / 18000000) - 1; TimBacklightHandle.Instance = TIM_BACKLIGHT; /* Initialize TIM3 peripheral as follows: 30 kHz */ TimBacklightHandle.Init.Period = 600 - 1; TimBacklightHandle.Init.Prescaler = uwPrescalerValue; TimBacklightHandle.Init.ClockDivision = 0; TimBacklightHandle.Init.CounterMode = TIM_COUNTERMODE_UP; HAL_TIM_PWM_Init(&TimBacklightHandle); sConfig.OCMode = TIM_OCMODE_PWM1; sConfig.OCPolarity = TIM_OCPOLARITY_HIGH; sConfig.OCFastMode = TIM_OCFAST_DISABLE; sConfig.Pulse = 100; /* Initial brigthness of display */ HAL_TIM_PWM_ConfigChannel(&TimBacklightHandle, &sConfig, TIM_BACKLIGHT_CHANNEL); HAL_TIM_PWM_Start(&TimBacklightHandle, TIM_BACKLIGHT_CHANNEL); } #endif static void EXTILine_Buttons_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; BUTTON_ENTER_GPIO_ENABLE(); BUTTON_NEXT_GPIO_ENABLE(); BUTTON_BACK_GPIO_ENABLE(); /* Configure pin as weak PULLUP input */ /* buttons */ GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING; GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Speed = GPIO_SPEED_LOW; GPIO_InitStructure.Pin = BUTTON_ENTER_PIN; HAL_GPIO_Init(BUTTON_ENTER_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.Pin = BUTTON_NEXT_PIN; HAL_GPIO_Init(BUTTON_NEXT_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.Pin = BUTTON_BACK_PIN; HAL_GPIO_Init(BUTTON_BACK_GPIO_PORT, &GPIO_InitStructure); /* Enable and set EXTI Line0 Interrupt to the lowest priority */ HAL_NVIC_SetPriority(BUTTON_ENTER_EXTI_IRQn, 2, 0); HAL_NVIC_SetPriority(BUTTON_NEXT_EXTI_IRQn, 2, 0); HAL_NVIC_SetPriority(BUTTON_BACK_EXTI_IRQn, 2, 0); HAL_NVIC_EnableIRQ(BUTTON_ENTER_EXTI_IRQn); HAL_NVIC_EnableIRQ(BUTTON_NEXT_EXTI_IRQn); HAL_NVIC_EnableIRQ(BUTTON_BACK_EXTI_IRQn); #ifdef BUTTON_CUSTOM_PIN BUTTON_CUSTOM_GPIO_ENABLE(); GPIO_InitStructure.Pin = BUTTON_CUSTOM_PIN; HAL_GPIO_Init(BUTTON_CUSTOM_GPIO_PORT, &GPIO_InitStructure); HAL_NVIC_SetPriority(BUTTON_CUSTOM_EXTI_IRQn, 2, 0); HAL_NVIC_EnableIRQ(BUTTON_CUSTOM_EXTI_IRQn); #endif } /** * @brief System Clock Configuration * The system Clock is configured as follow : * System Clock source = PLL (HSE) * SYSCLK(Hz) = 180000000 * HCLK(Hz) = 180000000 * AHB Prescaler = 1 * APB1 Prescaler = 4 * APB2 Prescaler = 2 * HSE Frequency(Hz) = 8000000 * PLL_M = 8 * PLL_N = 360 * PLL_P = 2 * PLL_Q = 7 * VDD(V) = 3.3 * Main regulator output voltage = Scale1 mode * Flash Latency(WS) = 5 * The LTDC Clock is configured as follow : * PLLSAIN = 192 * PLLSAIR = 4 * PLLSAIDivR = 8 * @param None * @retval None */ static void SystemClock_Config(void) { /* Enable Power Control clock */ __PWR_CLK_ENABLE(); /* The voltage scaling allows optimizing the power consumption when the device is clocked below the maximum system frequency, to update the voltage scaling value regarding system frequency refer to product datasheet. */ __HAL_PWR_VOLTAGESCALING_CONFIG( PWR_REGULATOR_VOLTAGE_SCALE1 ); /*##-1- System Clock Configuration #########################################*/ /* Enable HighSpeed Oscillator and activate PLL with HSE/HSI as source */ RCC_OscInitTypeDef RCC_OscInitStruct = { 0 }; #ifdef DISC1_BOARD // Use High Speed Internal (HSI) oscillator, running at 16MHz. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = 0x10; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 16; // HSI/16 is 1Mhz. #else // Use High Speed External oscillator, running at 8MHz RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 8; // HSE/8 is 1Mhz. #endif // System clock = PLL (1MHz) * N/p = 180 MHz. RCC_OscInitStruct.PLL.PLLN = 360; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 7; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; HAL_RCC_OscConfig( &RCC_OscInitStruct ); // HAL_PWREx_ActivateOverDrive(); HAL_PWREx_DeactivateOverDrive(); /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */ RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 }; RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; HAL_RCC_ClockConfig( &RCC_ClkInitStruct, FLASH_LATENCY_8 ); //FLASH_LATENCY_5); /*##-2- LTDC Clock Configuration ###########################################*/ /* LCD clock configuration */ /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */ /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 192 Mhz */ /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 192/4 = 48 Mhz */ /* LTDC clock frequency = PLLLCDCLK / RCC_PLLSAIDIVR_8 = 48/8 = 6 Mhz */ /* neu: 8MHz/8*300/5/8 = 7,5 MHz = 19,5 Hz bei 800 x 480 */ RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC; PeriphClkInitStruct.PLLSAI.PLLSAIN = 300; //192; PeriphClkInitStruct.PLLSAI.PLLSAIR = 5; //4; PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_8;//RCC_PLLSAIDIVR_4;// RCC_PLLSAIDIVR_2; // RCC_PLLSAIDIVR_8 HAL_RCCEx_PeriphCLKConfig( &PeriphClkInitStruct ); } /** * @brief This function is executed in case of error occurrence. * @param None * @retval None */ static void Error_Handler(void) { /* Turn LED3 on */ // BSP_LED_On(LED3); while(1) { } } /** * @brief Perform the SDRAM exernal memory inialization sequence * @param hsdram: SDRAM handle * @param Command: Pointer to SDRAM command structure * @retval None */ static void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *Command) { __IO uint32_t tmpmrd =0; /* Step 3: Configure a clock configuration enable command */ Command->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2; Command->AutoRefreshNumber = 1; Command->ModeRegisterDefinition = 0; /* Send the command */ HAL_SDRAM_SendCommand(hsdram, Command, 0x1000); /* Step 4: Insert 100 ms delay */ HAL_Delay(100); /* Step 5: Configure a PALL (precharge all) command */ Command->CommandMode = FMC_SDRAM_CMD_PALL; Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2; Command->AutoRefreshNumber = 1; Command->ModeRegisterDefinition = 0; /* Send the command */ HAL_SDRAM_SendCommand(hsdram, Command, 0x1000); /* Step 6 : Configure a Auto-Refresh command */ Command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2; Command->AutoRefreshNumber = 4; Command->ModeRegisterDefinition = 0; /* Send the command */ HAL_SDRAM_SendCommand(hsdram, Command, 0x1000); /* Step 7: Program the external memory mode register */ tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_2 | SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | SDRAM_MODEREG_CAS_LATENCY_3 | SDRAM_MODEREG_OPERATING_MODE_STANDARD | SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; Command->CommandMode = FMC_SDRAM_CMD_LOAD_MODE; Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2; Command->AutoRefreshNumber = 1; Command->ModeRegisterDefinition = tmpmrd; /* Send the command */ HAL_SDRAM_SendCommand(hsdram, Command, 0x1000); /* Step 8: Set the refresh rate counter */ /* (15.62 us x Freq) - 20 */ /* neu: (8 us x Freq) - 20 */ /* Set the device refresh counter */ HAL_SDRAM_ProgramRefreshRate(hsdram, REFRESH_COUNT); } /** ****************************************************************************** ****************************************************************************** ****************************************************************************** */ /** * @brief DMA2D configuration. * @note This function Configure tha DMA2D peripheral : * 1) Configure the transfer mode : memory to memory W/ pixel format conversion * 2) Configure the output color mode as ARGB4444 * 3) Configure the output memory address at SRAM memory * 4) Configure the data size : 320x120 (pixels) * 5) Configure the input color mode as ARGB8888 * 6) Configure the input memory address at FLASH memory * @retval * None */ static void SDRAM_Config(void) { /*##-1- Configure the SDRAM device #########################################*/ /* SDRAM device configuration */ hsdram.Instance = FMC_SDRAM_DEVICE; /* Timing configuration for 90 Mhz of SD clock frequency (180Mhz/2) */ /* TMRD: 2 Clock cycles */ SDRAM_Timing.LoadToActiveDelay = 2; /* TXSR: min=70ns (6x11.90ns) */ SDRAM_Timing.ExitSelfRefreshDelay = 7; /* TRAS: min=42ns (4x11.90ns) max=120k (ns) */ SDRAM_Timing.SelfRefreshTime = 4; /* TRC: min=63 (6x11.90ns) */ SDRAM_Timing.RowCycleDelay = 7; /* TWR: 2 Clock cycles */ SDRAM_Timing.WriteRecoveryTime = 2; /* TRP: 15ns => 2x11.90ns */ SDRAM_Timing.RPDelay = 2; /* TRCD: 15ns => 2x11.90ns */ SDRAM_Timing.RCDDelay = 2; hsdram.Init.SDBank = FMC_SDRAM_BANK2; hsdram.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9; hsdram.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13; hsdram.Init.MemoryDataWidth = SDRAM_MEMORY_WIDTH; hsdram.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; hsdram.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3; hsdram.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; hsdram.Init.SDClockPeriod = SDCLOCK_PERIOD; hsdram.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE; hsdram.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1; /* Initialize the SDRAM controller */ if(HAL_SDRAM_Init(&hsdram, &SDRAM_Timing) != HAL_OK) { /* Initialization Error */ Error_Handler(); } /* Program the SDRAM external device */ SDRAM_Initialization_Sequence(&hsdram, &command); } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* Infinite loop */ while (1) { } } #endif static void deco_loop(void) { typedef enum { CALC_VPM, CALC_VPM_FUTURE, CALC_BUEHLMANN, CALC_BUEHLMANN_FUTURE, CALC_INVALID } CALC_WHAT; static CALC_WHAT what = CALC_INVALID; static int counter = 0; if((stateUsed->mode != MODE_DIVE) || (stateUsed->diveSettings.diveMode == DIVEMODE_Apnea) || (decoLock != DECO_CALC_ready )) return; decoLock = DECO_CALC_running; if(stateDeco.diveSettings.deco_type.ub.standard == GF_MODE) { // hw 151110 mh wants future TTS even in deco zone if((what == CALC_BUEHLMANN) && (stateDeco.lifeData.pressure_ambient_bar > stateDeco.diveSettings.internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero)) if(what == CALC_BUEHLMANN) { //Calc future what = CALC_BUEHLMANN_FUTURE; } else what = CALC_BUEHLMANN; } else { // hw 151110 mh wants future TTS even in deco zone if((what == CALC_VPM) && (!stateDeco.vpm.deco_zone_reached)) if(what == CALC_VPM) { //Calc future what = CALC_VPM_FUTURE; } else what = CALC_VPM; } //In one of ten calc the other option if(counter == 10) { if(what == CALC_VPM) what = CALC_BUEHLMANN; if(what == CALC_BUEHLMANN) what = CALC_VPM; counter = 0; } decom_CreateGasChangeList(&stateDeco.diveSettings, &stateDeco.lifeData); switch(what) { case CALC_VPM: vpm_calc(&stateDeco.lifeData,&stateDeco.diveSettings,&stateDeco.vpm,&stateDeco.decolistVPM, DECOSTOPS); decoLock = DECO_CALC_FINSHED_vpm; return; case CALC_VPM_FUTURE: decom_tissues_exposure(stateDeco.diveSettings.future_TTS_minutes * 60,&stateDeco.lifeData); vpm_calc(&stateDeco.lifeData,&stateDeco.diveSettings,&stateDeco.vpm,&stateDeco.decolistFutureVPM, FUTURESTOPS); decoLock = DECO_CALC_FINSHED_Futurevpm; return; case CALC_BUEHLMANN: buehlmann_calc_deco(&stateDeco.lifeData,&stateDeco.diveSettings,&stateDeco.decolistBuehlmann); buehlmann_ceiling_calculator(&stateDeco.lifeData, &stateDeco.decolistBuehlmann); buehlmann_super_saturation_calculator(&stateDeco.lifeData,&stateDeco.decolistBuehlmann); decoLock = DECO_CALC_FINSHED_Buehlmann; return; case CALC_BUEHLMANN_FUTURE: decom_tissues_exposure(stateDeco.diveSettings.future_TTS_minutes * 60,&stateDeco.lifeData); buehlmann_calc_deco(&stateDeco.lifeData,&stateDeco.diveSettings,&stateDeco.decolistFutureBuehlmann); decoLock = DECO_CALC_FINSHED_FutureBuehlmann; return; default: break; } counter++; } static void resetToFirmwareUpdate(void) { __HAL_RCC_CLEAR_RESET_FLAGS(); HAL_NVIC_SystemReset(); } // debugging by https://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/ /* void printErrorMsg(const char * errMsg) { // printf(errMsg); // return; while(*errMsg != 0){ ITM_SendChar(*errMsg); ++errMsg; } } enum { r0, r1, r2, r3, r12, lr, pc, psr}; void stackDump(uint32_t stack[]) { static char msg[80]; sprintf(msg, "r0 = 0x%08x\n", stack[r0]); printErrorMsg(msg); sprintf(msg, "r1 = 0x%08x\n", stack[r1]); printErrorMsg(msg); sprintf(msg, "r2 = 0x%08x\n", stack[r2]); printErrorMsg(msg); sprintf(msg, "r3 = 0x%08x\n", stack[r3]); printErrorMsg(msg); sprintf(msg, "r12 = 0x%08x\n", stack[r12]); printErrorMsg(msg); sprintf(msg, "lr = 0x%08x\n", stack[lr]); printErrorMsg(msg); sprintf(msg, "pc = 0x%08x\n", stack[pc]); printErrorMsg(msg); sprintf(msg, "psr = 0x%08x\n", stack[psr]); printErrorMsg(msg); } void printUsageErrorMsg(uint32_t CFSRValue) { printErrorMsg("Usage fault: "); CFSRValue >>= 16; // right shift to lsb if((CFSRValue & (1 << 9)) != 0) { printErrorMsg("Divide by zero\n"); } } void Hard_Fault_Handler()//uint32_t stack[]) { static char msg[80]; printErrorMsg("In Hard Fault Handler\n"); sprintf(msg, "SCB->HFSR = 0x%08x\n", SCB->HFSR); printErrorMsg(msg); if ((SCB->HFSR & (1 << 30)) != 0) { printErrorMsg("Forced Hard Fault\n"); sprintf(msg, "SCB->CFSR = 0x%08x\n", SCB->CFSR ); printErrorMsg(msg); if((SCB->CFSR & 0xFFFF0000) != 0) { printUsageErrorMsg(SCB->CFSR); } } __ASM volatile("BKPT #01"); while(1); } int my_store_of_MSP; void HardFault_Handler(void) { __asm ("MRS my_store_of_MSP, MSP"); Hard_Fault_Handler(); } */ /* __asm void HardFault_Handler(void) { TST lr, #4 // Test for MSP or PSP ITE EQ MRSEQ r0, MSP MRSNE r0, PSP B __cpp(Hard_Fault_Handler) } */ /* HardFault_Handler\ PROC EXPORT HardFault_Handler B . ENDP */ /* __asm int f(int i) { ADD i, i, #1 // error } EXPORT HardFault_Handler HardFault_Handler FUNCTION MRS r0, MSP B __cpp(Hard_Fault_Handler) ENDFUNC */