From f82c3dea8c5745861e8d46dd37460646185775c3 Mon Sep 17 00:00:00 2001 From: richardclli Date: Wed, 16 Apr 2025 09:18:21 +0800 Subject: [PATCH] feat: Support for Flysky ST16 (#6071) Co-authored-by: raphaelcoeffic <1050031+raphaelcoeffic@users.noreply.github.com> Co-authored-by: Peter Feerick Co-authored-by: philmoz Co-authored-by: Malte Langermann --- .github/ISSUE_TEMPLATE/bug-report.yml | 1 + .github/workflows/actions.yml | 3 + .github/workflows/nightly.yml | 1 + companion/src/CMakeLists.txt | 2 + companion/src/firmwares/boards.cpp | 16 +- companion/src/firmwares/boards.h | 10 +- companion/src/firmwares/generalsettings.cpp | 2 + .../src/firmwares/opentx/opentxinterface.cpp | 7 + fw.json | 1 + radio/src/CMakeLists.txt | 4 +- radio/src/datastructs.h | 2 + radio/src/datastructs_private.h | 2 +- .../gui/colorlcd/model/function_switches.cpp | 4 +- radio/src/gui/colorlcd/model/menu_model.cpp | 2 +- radio/src/io/uf2.cpp | 2 + radio/src/io/uf2.h | 3 +- radio/src/lua/api_general.cpp | 21 +- radio/src/stamp.cpp | 4 +- radio/src/storage/yaml/CMakeLists.txt | 2 + radio/src/storage/yaml/yaml_datastructs.cpp | 2 + .../storage/yaml/yaml_datastructs_st16.cpp | 939 ++++++ .../common/arm/stm32/h7/CMakeLists.txt | 4 +- radio/src/targets/st16/CMakeLists.txt | 187 ++ radio/src/targets/st16/backlight_driver.cpp | 94 + radio/src/targets/st16/battery_driver.h | 30 + radio/src/targets/st16/board.cpp | 356 ++ radio/src/targets/st16/board.h | 249 ++ .../src/targets/st16/bootloader/boot_menu.cpp | 127 + radio/src/targets/st16/bsp_io.cpp | 140 + radio/src/targets/st16/bsp_io.h | 68 + radio/src/targets/st16/extflash_driver.cpp | 154 + radio/src/targets/st16/extflash_driver.h | 33 + radio/src/targets/st16/extmodule_helper.cpp | 49 + radio/src/targets/st16/hal.h | 526 +++ radio/src/targets/st16/haptic_driver.cpp | 60 + radio/src/targets/st16/key_driver.cpp | 81 + radio/src/targets/st16/lcd_driver.cpp | 2884 +++++++++++++++++ radio/src/targets/st16/lcd_driver.h | 85 + radio/src/targets/st16/led_driver.cpp | 131 + radio/src/targets/st16/libopenui_config.h | 27 + radio/src/targets/st16/sdram_driver.cpp | 252 ++ radio/src/targets/st16/system_clock.cpp | 117 + radio/src/targets/st16/system_clock.h | 23 + radio/src/targets/st16/system_init.cpp | 222 ++ radio/src/targets/st16/touch_driver.cpp | 477 +++ radio/src/targets/st16/touch_driver.h | 31 + radio/src/targets/st16/tp_cst340.cpp | 560 ++++ radio/src/targets/st16/tp_cst340.h | 289 ++ radio/src/targets/st16/usb_descriptor.h | 26 + radio/util/hw_defs/hal_keys.py | 6 + radio/util/hw_defs/legacy_names.py | 37 + radio/util/hw_defs/pot_config.py | 6 + radio/util/hw_defs/switch_config.py | 12 + tools/build-common.sh | 3 + tools/build-flysky.py | 3 +- tools/build-gh.sh | 11 +- tools/generate-hw-defs.sh | 2 +- tools/generate-yaml.sh | 2 +- 58 files changed, 8369 insertions(+), 25 deletions(-) create mode 100644 radio/src/storage/yaml/yaml_datastructs_st16.cpp create mode 100644 radio/src/targets/st16/CMakeLists.txt create mode 100644 radio/src/targets/st16/backlight_driver.cpp create mode 100644 radio/src/targets/st16/battery_driver.h create mode 100644 radio/src/targets/st16/board.cpp create mode 100644 radio/src/targets/st16/board.h create mode 100644 radio/src/targets/st16/bootloader/boot_menu.cpp create mode 100644 radio/src/targets/st16/bsp_io.cpp create mode 100644 radio/src/targets/st16/bsp_io.h create mode 100644 radio/src/targets/st16/extflash_driver.cpp create mode 100644 radio/src/targets/st16/extflash_driver.h create mode 100644 radio/src/targets/st16/extmodule_helper.cpp create mode 100644 radio/src/targets/st16/hal.h create mode 100644 radio/src/targets/st16/haptic_driver.cpp create mode 100644 radio/src/targets/st16/key_driver.cpp create mode 100644 radio/src/targets/st16/lcd_driver.cpp create mode 100644 radio/src/targets/st16/lcd_driver.h create mode 100644 radio/src/targets/st16/led_driver.cpp create mode 100644 radio/src/targets/st16/libopenui_config.h create mode 100644 radio/src/targets/st16/sdram_driver.cpp create mode 100644 radio/src/targets/st16/system_clock.cpp create mode 100644 radio/src/targets/st16/system_clock.h create mode 100644 radio/src/targets/st16/system_init.cpp create mode 100644 radio/src/targets/st16/touch_driver.cpp create mode 100644 radio/src/targets/st16/touch_driver.h create mode 100644 radio/src/targets/st16/tp_cst340.cpp create mode 100644 radio/src/targets/st16/tp_cst340.h create mode 100644 radio/src/targets/st16/usb_descriptor.h mode change 100644 => 100755 tools/build-flysky.py diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index b64a6a505..042811d71 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -88,6 +88,7 @@ body: - Flysky NB4+ - Flysky NV14 - Flysky PL18/PL18EV + - Flysky ST16 - FrSky Q X7 / Q X7S (ACCST) - FrSky Q X7 / Q X7S (ACCESS) - FrSky X9D diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 3c0474a9d..eb6c411f7 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -72,6 +72,7 @@ jobs: - mt12 - gx12 - nb4p + - st16 container: image: ghcr.io/edgetx/edgetx-dev:latest volumes: @@ -118,6 +119,7 @@ jobs: - xlite;xlites - mt12;gx12 - nb4p + - st16 container: image: ghcr.io/edgetx/edgetx-dev:latest volumes: @@ -143,6 +145,7 @@ jobs: fw.json LICENSE *.bin + *.uf2 retention-days: 15 if-no-files-found: error diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 9e6f193cf..a1322487f 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -36,6 +36,7 @@ jobs: - xlite;xlites - mt12 - nb4p + - st16 container: image: ghcr.io/edgetx/edgetx-dev:latest volumes: diff --git a/companion/src/CMakeLists.txt b/companion/src/CMakeLists.txt index c799b4f3d..7070a1718 100644 --- a/companion/src/CMakeLists.txt +++ b/companion/src/CMakeLists.txt @@ -358,6 +358,8 @@ elseif(PCB STREQUAL PL18 AND PCBREV STREQUAL PL18EV) set(FLAVOUR pl18ev) elseif(PCB STREQUAL PL18) set(FLAVOUR pl18) +elseif(PCB STREQUAL ST16) + set(FLAVOR st16) else() string(TOLOWER ${PCB} FLAVOUR) endif() diff --git a/companion/src/firmwares/boards.cpp b/companion/src/firmwares/boards.cpp index 778a2f50c..60ec9fad7 100644 --- a/companion/src/firmwares/boards.cpp +++ b/companion/src/firmwares/boards.cpp @@ -158,6 +158,8 @@ uint32_t Boards::getFourCC(Type board) case BOARD_FLYSKY_PL18: case BOARD_FLYSKY_PL18EV: return 0x4878746F; + case BOARD_FLYSKY_ST16: + return 0x4C78746F; default: return 0; } @@ -216,6 +218,7 @@ int Boards::getEEpromSize(Board::Type board) case BOARD_FLYSKY_EL18: case BOARD_FLYSKY_PL18: case BOARD_FLYSKY_PL18EV: + case BOARD_FLYSKY_ST16: case BOARD_FATFISH_F16: case BOARD_HELLORADIOSKY_V16: return 0; @@ -275,6 +278,7 @@ int Boards::getFlashSize(Type board) case BOARD_FLYSKY_EL18: case BOARD_FLYSKY_PL18: case BOARD_FLYSKY_PL18EV: + case BOARD_FLYSKY_ST16: case BOARD_FATFISH_F16: case BOARD_HELLORADIOSKY_V16: return FSIZE_HORUS; @@ -373,7 +377,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) case LcdHeight: if (IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board)) return 480; - else if (IS_FAMILY_PL18(board) || IS_JUMPER_T15(board)) + else if (IS_FAMILY_PL18(board) || IS_JUMPER_T15(board) || IS_FLYSKY_ST16(board)) return 320; else if (IS_FAMILY_HORUS_OR_T16(board)) return 272; @@ -383,7 +387,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) case LcdWidth: if (IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board)) return 320; - else if (IS_FAMILY_PL18(board)) + else if (IS_FAMILY_PL18(board) || IS_FLYSKY_ST16(board)) return 480; else if (IS_FAMILY_HORUS_OR_T16(board)) return 480; @@ -656,7 +660,9 @@ QString Boards::getBoardName(Board::Type board) case BOARD_FLYSKY_PL18: return "FlySky PL18"; case BOARD_FLYSKY_PL18EV: - return "FlySky PL18EV"; + return "FlySky PL18EV"; + case BOARD_FLYSKY_ST16: + return "FlySky ST16"; case BOARD_BETAFPV_LR3PRO: return "BETAFPV LR3PRO"; case BOARD_IFLIGHT_COMMANDO8: @@ -769,6 +775,7 @@ int Boards::getDefaultInternalModules(Board::Type board) case BOARD_JUMPER_TPROV2: case BOARD_FLYSKY_PL18: case BOARD_FLYSKY_PL18EV: + case BOARD_FLYSKY_ST16: return (int)MODULE_TYPE_MULTIMODULE; case BOARD_BETAFPV_LR3PRO: @@ -856,6 +863,9 @@ void Boards::getBattRange(Board::Type board, int& vmin, int& vmax, unsigned int& case BOARD_FLYSKY_PL18EV: BR(35, 43, 37) break; + case BOARD_FLYSKY_ST16: + BR(70, 86,80) + break; case BOARD_IFLIGHT_COMMANDO8: BR(30, 42, 32) break; diff --git a/companion/src/firmwares/boards.h b/companion/src/firmwares/boards.h index 5c8131774..a787c294f 100644 --- a/companion/src/firmwares/boards.h +++ b/companion/src/firmwares/boards.h @@ -79,6 +79,7 @@ namespace Board { BOARD_FLYSKY_NV14, BOARD_FLYSKY_PL18, BOARD_FLYSKY_PL18EV, + BOARD_FLYSKY_ST16, BOARD_RADIOMASTER_ZORRO, BOARD_JUMPER_TPRO, BOARD_BETAFPV_LR3PRO, @@ -666,6 +667,11 @@ inline bool IS_FLYSKY_PL18EV(Board::Type board) return (board == Board::BOARD_FLYSKY_PL18EV); } +inline bool IS_FLYSKY_ST16(Board::Type board) +{ + return (board == Board::BOARD_FLYSKY_ST16); +} + inline bool IS_FAMILY_PL18(Board::Type board) { return IS_FLYSKY_PL18(board) || IS_FLYSKY_PL18EV(board); @@ -750,7 +756,7 @@ inline bool IS_FAMILY_HORUS_OR_T16(Board::Type board) { return IS_FAMILY_HORUS(board) || IS_FAMILY_T16(board) || IS_FLYSKY_NV14(board)/*generally*/ || IS_FLYSKY_EL18(board)/*generally*/ - || IS_FAMILY_PL18(board); + || IS_FAMILY_PL18(board) || IS_FLYSKY_ST16(board)/*generally*/; } inline bool IS_HORUS_OR_TARANIS(Board::Type board) @@ -761,7 +767,7 @@ inline bool IS_HORUS_OR_TARANIS(Board::Type board) inline bool IS_STM32(Board::Type board) { return IS_TARANIS(board) || IS_FAMILY_HORUS_OR_T16(board) || - IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_FAMILY_PL18(board); + IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_FAMILY_PL18(board) || IS_FLYSKY_ST16(board); } inline bool IS_ARM(Board::Type board) diff --git a/companion/src/firmwares/generalsettings.cpp b/companion/src/firmwares/generalsettings.cpp index c4f9be1a0..af9443f89 100644 --- a/companion/src/firmwares/generalsettings.cpp +++ b/companion/src/firmwares/generalsettings.cpp @@ -224,6 +224,8 @@ void GeneralSettings::init() strcpy(bluetoothName, "pl18"); else if (IS_FLYSKY_PL18EV(board)) strcpy(bluetoothName, "pl18ev"); + else if (IS_FLYSKY_ST16(board)) + strcpy(bluetoothName, "st16"); else if (IS_FAMILY_HORUS_OR_T16(board)) strcpy(bluetoothName, "horus"); else if (IS_TARANIS_X9E(board) || IS_TARANIS_SMALL(board)) diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp index cf953ee06..dc1d24ecd 100644 --- a/companion/src/firmwares/opentx/opentxinterface.cpp +++ b/companion/src/firmwares/opentx/opentxinterface.cpp @@ -512,6 +512,13 @@ void registerOpenTxFirmwares() addOpenTxRfOptions(firmware, FLEX + AFHDS3); registerOpenTxFirmware(firmware); + /* FlySky ST16 board */ + firmware = new OpenTxFirmware(FIRMWAREID("st16"), Firmware::tr("FlySky ST16"), BOARD_FLYSKY_ST16); + addOpenTxFrskyOptions(firmware); + firmware->addOption(opt_bt); + addOpenTxRfOptions(firmware, FLEX + AFHDS3); + registerOpenTxFirmware(firmware); + /* FrSky Horus X10 board */ firmware = new OpenTxFirmware(FIRMWAREID("x10"), Firmware::tr("FrSky Horus X10 / X10S"), BOARD_X10); addOpenTxFrskyOptions(firmware); diff --git a/fw.json b/fw.json index 9eac988f3..f4b3cb9b7 100644 --- a/fw.json +++ b/fw.json @@ -7,6 +7,7 @@ ["Flysky PL18", "pl18-"], ["Flysky PL18EV", "pl18ev-"], ["Flysky NB4+", "nb4p-"], + ["Flysky ST16", "st16-"], ["FrSky Horus X10", "x10-"], ["FrSky Horus X10 Express", "x10express-"], ["FrSky Horus X12s", "x12s-"], diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index cb0967f60..739ec5708 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -1,7 +1,7 @@ include(CMakeForceCompiler) include(Bitmaps) -set(PCB_TYPES X9LITE X9LITES X7 XLITE XLITES X9D X9D+ X9E X10 X12S NV14 PL18) +set(PCB_TYPES X9LITE X9LITES X7 XLITE XLITES X9D X9D+ X9E X10 X12S NV14 PL18 ST16) set(RADIO_LANGUAGES CN CZ DA DE EN ES FI FR HE HU IT JP NL PL PT RU SE SK TW UA) set(TTS_LANGUAGES CN CZ DA DE EN ES FR HE HU IT JP NL PL PT RU SE SK UA) @@ -89,6 +89,8 @@ elseif(PCB STREQUAL NV14) include(targets/nv14/CMakeLists.txt) elseif(PCB STREQUAL PL18) include(targets/pl18/CMakeLists.txt) +elseif(PCB STREQUAL ST16) + include(targets/st16/CMakeLists.txt) elseif(PCB STREQUAL STM32H7S78_DK) include(targets/stm32h7s78-dk/CMakeLists.txt) elseif(PCB STREQUAL X9E OR PCB STREQUAL X9D+ OR PCB STREQUAL X9D OR PCB STREQUAL X7 OR PCB STREQUAL X9LITE OR PCB STREQUAL X9LITES OR PCB STREQUAL XLITE OR PCB STREQUAL XLITES) diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index 0f6718449..87c18b981 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -112,6 +112,8 @@ static inline void check_struct() #endif #elif defined(PCBNV14) CHKSIZE(ModelData, 26463); +#elif defined(PCBST16) + CHKSIZE(ModelData, 26906); #elif defined(RADIO_T15) CHKSIZE(ModelData, 26834); #elif defined(PCBHORUS) diff --git a/radio/src/datastructs_private.h b/radio/src/datastructs_private.h index a47094de3..27260ab9e 100644 --- a/radio/src/datastructs_private.h +++ b/radio/src/datastructs_private.h @@ -620,7 +620,7 @@ PACK(struct CustomScreenData { #define TOPBAR_DATA #endif -#if defined(PCBHORUS) || defined(PCBTARANIS) || defined(PCBNV14) || defined(PCBPL18) +#if defined(PCBHORUS) || defined(PCBTARANIS) || defined(PCBNV14) || defined(PCBPL18) || defined(PCBST16) #define SCRIPT_DATA \ NOBACKUP(ScriptData scriptsData[MAX_SCRIPTS]); #else diff --git a/radio/src/gui/colorlcd/model/function_switches.cpp b/radio/src/gui/colorlcd/model/function_switches.cpp index f230b4ad0..3d92911dd 100644 --- a/radio/src/gui/colorlcd/model/function_switches.cpp +++ b/radio/src/gui/colorlcd/model/function_switches.cpp @@ -131,7 +131,7 @@ class FunctionSwitch : public Window offColor = new ColorPicker( this, {C1_X, 0, C1_W, 0}, [=]() -> int { // getValue - return g_model.functionSwitchLedOFFColor[switchIndex].getColor(); + return g_model.functionSwitchLedOFFColor[switchIndex].getColor() | RGB888_FLAG; }, [=](int newValue) { // setValue g_model.functionSwitchLedOFFColor[switchIndex] = offValue; @@ -149,7 +149,7 @@ class FunctionSwitch : public Window onColor = new ColorPicker( this, {C2_X, 0, C2_W, 0}, [=]() -> int { // getValue - return g_model.functionSwitchLedONColor[switchIndex].getColor(); + return g_model.functionSwitchLedONColor[switchIndex].getColor() | RGB888_FLAG; }, [=](int newValue) { // setValue g_model.functionSwitchLedOFFColor[switchIndex] = offValue; diff --git a/radio/src/gui/colorlcd/model/menu_model.cpp b/radio/src/gui/colorlcd/model/menu_model.cpp index e4076d0ae..0169993b2 100644 --- a/radio/src/gui/colorlcd/model/menu_model.cpp +++ b/radio/src/gui/colorlcd/model/menu_model.cpp @@ -65,7 +65,7 @@ void ModelMenu::build() #endif addTab(new ModelTelemetryPage()); -#if defined(PCBNV14) || defined(PCBPL18) +#if defined(PCBNV14) || defined(PCBPL18) || defined(PCBST16) new TextButton( this, {LCD_W / 2 + 6, MENU_TITLE_TOP, LCD_W / 2 - 8, MENU_TITLE_HEIGHT}, diff --git a/radio/src/io/uf2.cpp b/radio/src/io/uf2.cpp index 487015a36..cb8654188 100644 --- a/radio/src/io/uf2.cpp +++ b/radio/src/io/uf2.cpp @@ -147,6 +147,7 @@ static uint8_t* skipUF2Extensions(uint8_t* data) { return (uint8_t*)ptr; } +#if defined(STM32) && !defined(SIMU) void writeUF2FirmwareVersion(void* block) { UF2_Block* uf2 = (UF2_Block*)block; @@ -209,3 +210,4 @@ void writeUF2RebootBlock(void* block) uint32_t reboot_addr = BOOTLOADER_ADDRESS; memcpy(end_data, &reboot_addr, sizeof(reboot_addr)); } +#endif diff --git a/radio/src/io/uf2.h b/radio/src/io/uf2.h index 7870881a5..375e05c30 100644 --- a/radio/src/io/uf2.h +++ b/radio/src/io/uf2.h @@ -39,6 +39,7 @@ bool isUF2FirmwareFile(const char * filename); bool extractUF2FirmwareVersion(const void* block, VersionTag* tag); +#if defined(STM32) && !defined(SIMU) void writeUF2FirmwareVersion(void* block); void writeUF2RebootBlock(void* block); - +#endif diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index cdebe19af..48c43ba28 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -1810,9 +1810,9 @@ Raises a pop-up on screen that allows uses input @param event (number) the event variable that is passed in from the Run function (key pressed) -@param input (number) value that can be adjusted by the +/­- keys +@param input (number) value that can be adjusted by the +/- keys -@param min (number) min value that input can reach (by pressing the -­ key) +@param min (number) min value that input can reach (by pressing the - key) @param max (number) max value that input can reach @@ -2268,7 +2268,7 @@ static int luaResetGlobalTimer(lua_State * L) /*luadoc @function multiBuffer(address[,value]) -This function reads/writes the Multi protocol buffer to interact with a protocol². +This function reads/writes the Multi protocol buffer to interact with a protocol. @param address to read/write in the buffer @param (optional): value to write in the buffer @@ -2875,6 +2875,13 @@ static int luaSetRgbLedColor(lua_State * L) uint8_t g = luaL_checkunsigned(L, 3); uint8_t b = luaL_checkunsigned(L, 4); + #if defined(LED_STRIP_RESERVED_AT_END) + if (id >= LED_STRIP_LENGTH - LED_STRIP_RESERVED_AT_END) { + lua_pushboolean(L, false); + return 1; + } + #endif + rgbSetLedColor(id, r, g, b); return 1; @@ -3196,9 +3203,13 @@ LROT_BEGIN(etxcst, NULL, 0) LROT_NUMENTRY( TIMEHOUR, TIMEHOUR ) #if defined(LED_STRIP_GPIO) #if defined(RADIO_V16) - LROT_NUMENTRY( LED_STRIP_LENGTH, LED_STRIP_LENGTH - 6) + LROT_NUMENTRY( LED_STRIP_LENGTH, LED_STRIP_LENGTH - 6 ) #elif defined(RGB_LED_OFFSET) - LROT_NUMENTRY( LED_STRIP_LENGTH, LED_STRIP_LENGTH - RGB_LED_OFFSET) + // Exclude function switch LEDs + LROT_NUMENTRY( LED_STRIP_LENGTH, LED_STRIP_LENGTH - RGB_LED_OFFSET ) + #elif defined(LED_STRIP_RESERVED_AT_END) + // Exclude leds at the end of the strip + LROT_NUMENTRY( LED_STRIP_LENGTH, LED_STRIP_LENGTH - LED_STRIP_RESERVED_AT_END ) #else LROT_NUMENTRY( LED_STRIP_LENGTH, LED_STRIP_LENGTH ) #endif diff --git a/radio/src/stamp.cpp b/radio/src/stamp.cpp index cfaaf6a51..a68a88347 100644 --- a/radio/src/stamp.cpp +++ b/radio/src/stamp.cpp @@ -106,12 +106,12 @@ const char * getFirmwareVersion(const uint8_t* buffer) #endif } - for (int i = 0; i < 2024; i++) { + for (int i = 0; i < 1024; i++) { if ((memcmp(buffer + i, "edgetx-", 7) == 0) || memcmp(buffer + i, "opentx-", 7) == 0) { return (const char*)buffer + i; } } - return "no version found"; + return nullptr; } #endif diff --git a/radio/src/storage/yaml/CMakeLists.txt b/radio/src/storage/yaml/CMakeLists.txt index 12dde124a..81d79ecc6 100644 --- a/radio/src/storage/yaml/CMakeLists.txt +++ b/radio/src/storage/yaml/CMakeLists.txt @@ -32,6 +32,8 @@ elseif(PCB STREQUAL PL18) else() set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_pl18.cpp) endif() +elseif(PCB STREQUAL ST16) + set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_st16.cpp) elseif(PCB STREQUAL X7) if(PCBREV STREQUAL TPRO) set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_tpro.cpp) diff --git a/radio/src/storage/yaml/yaml_datastructs.cpp b/radio/src/storage/yaml/yaml_datastructs.cpp index 4263f50e9..e2e3ca8ab 100644 --- a/radio/src/storage/yaml/yaml_datastructs.cpp +++ b/radio/src/storage/yaml/yaml_datastructs.cpp @@ -46,6 +46,8 @@ #endif #elif defined(PCBNV14) #include "yaml_datastructs_nv14.cpp" +#elif defined(PCBST16) + #include "yaml_datastructs_st16.cpp" #elif defined(PCBX7) #if defined(RADIO_TPRO) || defined(RADIO_TPROV2) || defined(RADIO_BUMBLEBEE) #include "yaml_datastructs_tpro.cpp" diff --git a/radio/src/storage/yaml/yaml_datastructs_st16.cpp b/radio/src/storage/yaml/yaml_datastructs_st16.cpp new file mode 100644 index 000000000..ed55c8818 --- /dev/null +++ b/radio/src/storage/yaml/yaml_datastructs_st16.cpp @@ -0,0 +1,939 @@ +// generated by generate_yaml.py + +// +// Enums first +// + +const struct YamlIdStr enum_BacklightMode[] = { + { e_backlight_mode_off, "backlight_mode_off" }, + { e_backlight_mode_keys, "backlight_mode_keys" }, + { e_backlight_mode_sticks, "backlight_mode_sticks" }, + { e_backlight_mode_all, "backlight_mode_all" }, + { e_backlight_mode_on, "backlight_mode_on" }, + { 0, NULL } +}; +const struct YamlIdStr enum_AntennaModes[] = { + { ANTENNA_MODE_INTERNAL, "MODE_INTERNAL" }, + { ANTENNA_MODE_ASK, "MODE_ASK" }, + { ANTENNA_MODE_PER_MODEL, "MODE_PER_MODEL" }, + { ANTENNA_MODE_EXTERNAL, "MODE_EXTERNAL" }, + { 0, NULL } +}; +const struct YamlIdStr enum_ModuleType[] = { + { MODULE_TYPE_NONE, "TYPE_NONE" }, + { MODULE_TYPE_PPM, "TYPE_PPM" }, + { MODULE_TYPE_XJT_PXX1, "TYPE_XJT_PXX1" }, + { MODULE_TYPE_ISRM_PXX2, "TYPE_ISRM_PXX2" }, + { MODULE_TYPE_DSM2, "TYPE_DSM2" }, + { MODULE_TYPE_CROSSFIRE, "TYPE_CROSSFIRE" }, + { MODULE_TYPE_MULTIMODULE, "TYPE_MULTIMODULE" }, + { MODULE_TYPE_R9M_PXX1, "TYPE_R9M_PXX1" }, + { MODULE_TYPE_R9M_PXX2, "TYPE_R9M_PXX2" }, + { MODULE_TYPE_R9M_LITE_PXX1, "TYPE_R9M_LITE_PXX1" }, + { MODULE_TYPE_R9M_LITE_PXX2, "TYPE_R9M_LITE_PXX2" }, + { MODULE_TYPE_GHOST, "TYPE_GHOST" }, + { MODULE_TYPE_R9M_LITE_PRO_PXX2, "TYPE_R9M_LITE_PRO_PXX2" }, + { MODULE_TYPE_SBUS, "TYPE_SBUS" }, + { MODULE_TYPE_XJT_LITE_PXX2, "TYPE_XJT_LITE_PXX2" }, + { MODULE_TYPE_FLYSKY_AFHDS2A, "TYPE_FLYSKY_AFHDS2A" }, + { MODULE_TYPE_FLYSKY_AFHDS3, "TYPE_FLYSKY_AFHDS3" }, + { MODULE_TYPE_LEMON_DSMP, "TYPE_LEMON_DSMP" }, + { 0, NULL } +}; +const struct YamlIdStr enum_TrainerMultiplex[] = { + { TRAINER_OFF, "OFF" }, + { TRAINER_ADD, "ADD" }, + { TRAINER_REPL, "REPL" }, + { 0, NULL } +}; +const struct YamlIdStr enum_BeeperMode[] = { + { e_mode_quiet, "mode_quiet" }, + { e_mode_alarms, "mode_alarms" }, + { e_mode_nokeys, "mode_nokeys" }, + { e_mode_all, "mode_all" }, + { 0, NULL } +}; +const struct YamlIdStr enum_BluetoothModes[] = { + { BLUETOOTH_OFF, "OFF" }, + { BLUETOOTH_TELEMETRY, "TELEMETRY" }, + { BLUETOOTH_TRAINER, "TRAINER" }, + { 0, NULL } +}; +const struct YamlIdStr enum_Functions[] = { + { FUNC_OVERRIDE_CHANNEL, "OVERRIDE_CHANNEL" }, + { FUNC_TRAINER, "TRAINER" }, + { FUNC_INSTANT_TRIM, "INSTANT_TRIM" }, + { FUNC_RESET, "RESET" }, + { FUNC_SET_TIMER, "SET_TIMER" }, + { FUNC_ADJUST_GVAR, "ADJUST_GVAR" }, + { FUNC_VOLUME, "VOLUME" }, + { FUNC_SET_FAILSAFE, "SET_FAILSAFE" }, + { FUNC_RANGECHECK, "RANGECHECK" }, + { FUNC_BIND, "BIND" }, + { FUNC_PLAY_SOUND, "PLAY_SOUND" }, + { FUNC_PLAY_TRACK, "PLAY_TRACK" }, + { FUNC_PLAY_VALUE, "PLAY_VALUE" }, + { FUNC_PLAY_SCRIPT, "PLAY_SCRIPT" }, + { FUNC_BACKGND_MUSIC, "BACKGND_MUSIC" }, + { FUNC_BACKGND_MUSIC_PAUSE, "BACKGND_MUSIC_PAUSE" }, + { FUNC_VARIO, "VARIO" }, + { FUNC_HAPTIC, "HAPTIC" }, + { FUNC_LOGS, "LOGS" }, + { FUNC_BACKLIGHT, "BACKLIGHT" }, + { FUNC_SCREENSHOT, "SCREENSHOT" }, + { FUNC_RACING_MODE, "RACING_MODE" }, + { FUNC_DISABLE_TOUCH, "DISABLE_TOUCH" }, + { FUNC_SET_SCREEN, "SET_SCREEN" }, + { FUNC_DISABLE_AUDIO_AMP, "DISABLE_AUDIO_AMP" }, + { FUNC_RGB_LED, "RGB_LED" }, + { FUNC_PUSH_CUST_SWITCH, "PUSH_CUST_SWITCH" }, + { FUNC_TEST, "TEST" }, + { 0, NULL } +}; +const struct YamlIdStr enum_TimerModes[] = { + { TMRMODE_OFF, "OFF" }, + { TMRMODE_ON, "ON" }, + { TMRMODE_START, "START" }, + { TMRMODE_THR, "THR" }, + { TMRMODE_THR_REL, "THR_REL" }, + { TMRMODE_THR_START, "THR_START" }, + { 0, NULL } +}; +const struct YamlIdStr enum_MixerMultiplex[] = { + { MLTPX_ADD, "ADD" }, + { MLTPX_MUL, "MUL" }, + { MLTPX_REPL, "REPL" }, + { 0, NULL } +}; +const struct YamlIdStr enum_MixSources[] = { + { MIXSRC_NONE, "NONE" }, + { MIXSRC_TILT_X, "TILT_X" }, + { MIXSRC_TILT_Y, "TILT_Y" }, + { MIXSRC_SPACEMOUSE_A, "SPACEMOUSE_A" }, + { MIXSRC_SPACEMOUSE_B, "SPACEMOUSE_B" }, + { MIXSRC_SPACEMOUSE_C, "SPACEMOUSE_C" }, + { MIXSRC_SPACEMOUSE_D, "SPACEMOUSE_D" }, + { MIXSRC_SPACEMOUSE_E, "SPACEMOUSE_E" }, + { MIXSRC_SPACEMOUSE_F, "SPACEMOUSE_F" }, + { MIXSRC_MIN, "MIN" }, + { MIXSRC_MAX, "MAX" }, + { MIXSRC_TX_VOLTAGE, "TX_VOLTAGE" }, + { MIXSRC_TX_TIME, "TX_TIME" }, + { MIXSRC_TX_GPS, "TX_GPS" }, + { 0, NULL } +}; +const struct YamlIdStr enum_LogicalSwitchesFunctions[] = { + { LS_FUNC_NONE, "FUNC_NONE" }, + { LS_FUNC_VEQUAL, "FUNC_VEQUAL" }, + { LS_FUNC_VALMOSTEQUAL, "FUNC_VALMOSTEQUAL" }, + { LS_FUNC_VPOS, "FUNC_VPOS" }, + { LS_FUNC_VNEG, "FUNC_VNEG" }, + { LS_FUNC_APOS, "FUNC_APOS" }, + { LS_FUNC_ANEG, "FUNC_ANEG" }, + { LS_FUNC_AND, "FUNC_AND" }, + { LS_FUNC_OR, "FUNC_OR" }, + { LS_FUNC_XOR, "FUNC_XOR" }, + { LS_FUNC_EDGE, "FUNC_EDGE" }, + { LS_FUNC_EQUAL, "FUNC_EQUAL" }, + { LS_FUNC_GREATER, "FUNC_GREATER" }, + { LS_FUNC_LESS, "FUNC_LESS" }, + { LS_FUNC_DIFFEGREATER, "FUNC_DIFFEGREATER" }, + { LS_FUNC_ADIFFEGREATER, "FUNC_ADIFFEGREATER" }, + { LS_FUNC_TIMER, "FUNC_TIMER" }, + { LS_FUNC_STICKY, "FUNC_STICKY" }, + { 0, NULL } +}; +const struct YamlIdStr enum_SwashType[] = { + { SWASH_TYPE_NONE, "TYPE_NONE" }, + { SWASH_TYPE_120, "TYPE_120" }, + { SWASH_TYPE_120X, "TYPE_120X" }, + { SWASH_TYPE_140, "TYPE_140" }, + { SWASH_TYPE_90, "TYPE_90" }, + { 0, NULL } +}; +const struct YamlIdStr enum_SwitchSources[] = { + { SWSRC_NONE, "NONE" }, + { SWSRC_ON, "ON" }, + { SWSRC_ONE, "ONE" }, + { SWSRC_TELEMETRY_STREAMING, "TELEMETRY_STREAMING" }, + { SWSRC_RADIO_ACTIVITY, "RADIO_ACTIVITY" }, + { SWSRC_TRAINER_CONNECTED, "TRAINER_CONNECTED" }, + { SWSRC_OFF, "OFF" }, + { 0, NULL } +}; +const struct YamlIdStr enum_PotsWarnMode[] = { + { POTS_WARN_OFF, "WARN_OFF" }, + { POTS_WARN_MANUAL, "WARN_MANUAL" }, + { POTS_WARN_AUTO, "WARN_AUTO" }, + { 0, NULL } +}; +const struct YamlIdStr enum_ModelOverridableEnable[] = { + { OVERRIDE_GLOBAL, "GLOBAL" }, + { OVERRIDE_OFF, "OFF" }, + { OVERRIDE_ON, "ON" }, + { 0, NULL } +}; +const struct YamlIdStr enum_FailsafeModes[] = { + { FAILSAFE_NOT_SET, "NOT_SET" }, + { FAILSAFE_HOLD, "HOLD" }, + { FAILSAFE_CUSTOM, "CUSTOM" }, + { FAILSAFE_NOPULSES, "NOPULSES" }, + { FAILSAFE_RECEIVER, "RECEIVER" }, + { 0, NULL } +}; +const struct YamlIdStr enum_TelemetrySensorFormula[] = { + { TELEM_FORMULA_ADD, "FORMULA_ADD" }, + { TELEM_FORMULA_AVERAGE, "FORMULA_AVERAGE" }, + { TELEM_FORMULA_MIN, "FORMULA_MIN" }, + { TELEM_FORMULA_MAX, "FORMULA_MAX" }, + { TELEM_FORMULA_MULTIPLY, "FORMULA_MULTIPLY" }, + { TELEM_FORMULA_TOTALIZE, "FORMULA_TOTALIZE" }, + { TELEM_FORMULA_CELL, "FORMULA_CELL" }, + { TELEM_FORMULA_CONSUMPTION, "FORMULA_CONSUMPTION" }, + { TELEM_FORMULA_DIST, "FORMULA_DIST" }, + { 0, NULL } +}; +const struct YamlIdStr enum_TelemetrySensorType[] = { + { TELEM_TYPE_CUSTOM, "TYPE_CUSTOM" }, + { TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" }, + { 0, NULL } +}; +const struct YamlIdStr enum_ZoneOptionValueEnum[] = { + { ZOV_Unsigned, "Unsigned" }, + { ZOV_Signed, "Signed" }, + { ZOV_Bool, "Bool" }, + { ZOV_String, "String" }, + { ZOV_Source, "Source" }, + { ZOV_Color, "Color" }, + { 0, NULL } +}; +const struct YamlIdStr enum_USBJoystickIfMode[] = { + { USBJOYS_JOYSTICK, "JOYSTICK" }, + { USBJOYS_GAMEPAD, "GAMEPAD" }, + { USBJOYS_MULTIAXIS, "MULTIAXIS" }, + { 0, NULL } +}; +const struct YamlIdStr enum_USBJoystickCh[] = { + { USBJOYS_CH_NONE, "CH_NONE" }, + { USBJOYS_CH_BUTTON, "CH_BUTTON" }, + { USBJOYS_CH_AXIS, "CH_AXIS" }, + { USBJOYS_CH_SIM, "CH_SIM" }, + { 0, NULL } +}; + +// +// Structs last +// + +static const struct YamlNode struct_CalibData[] = { + YAML_IDX_CUST("calib",r_calib,w_calib), + YAML_SIGNED( "mid", 16 ), + YAML_SIGNED( "spanNeg", 16 ), + YAML_SIGNED( "spanPos", 16 ), + YAML_END +}; +static const struct YamlNode struct_signed_16[] = { + YAML_IDX, + YAML_SIGNED( "val", 16 ), + YAML_END +}; +static const struct YamlNode struct_TrainerMix[] = { + YAML_IDX, + YAML_UNSIGNED( "srcChn", 6 ), + YAML_ENUM("mode", 2, enum_TrainerMultiplex), + YAML_SIGNED( "studWeight", 8 ), + YAML_END +}; +static const struct YamlNode struct_TrainerData[] = { + YAML_ARRAY("calib", 16, 4, struct_signed_16, NULL), + YAML_ARRAY("mix", 16, 4, struct_TrainerMix, NULL), + YAML_END +}; +static const struct YamlNode struct_anonymous_1[] = { + YAML_STRING("name", 8), + YAML_END +}; +static const struct YamlNode struct_anonymous_2[] = { + YAML_SIGNED( "val", 16 ), + YAML_UNSIGNED( "mode", 8 ), + YAML_UNSIGNED( "param", 8 ), + YAML_SIGNED( "val2", 32 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_3[] = { + YAML_SIGNED( "val1", 32 ), + YAML_SIGNED( "val2", 32 ), + YAML_END +}; +static const struct YamlNode union_anonymous_0_elmts[] = { + YAML_STRUCT("play", 64, struct_anonymous_1, NULL), + YAML_STRUCT("all", 64, struct_anonymous_2, NULL), + YAML_STRUCT("clear", 64, struct_anonymous_3, NULL), + YAML_END +}; +static const struct YamlNode struct_CustomFunctionData[] = { + YAML_IDX, + YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ), + YAML_ENUM("func", 6, enum_Functions), + YAML_CUSTOM("def",r_customFn,w_customFn), + YAML_PADDING( 64 ), + YAML_PADDING( 1 ), + YAML_PADDING( 7 ), + YAML_END +}; +static const struct YamlNode struct_RadioData[] = { + YAML_UNSIGNED( "manuallyEdited", 1 ), + YAML_SIGNED( "timezoneMinutes", 3 ), + YAML_UNSIGNED( "ppmunit", 2 ), + YAML_PADDING( 2 ), + YAML_CUSTOM("semver",nullptr,w_semver), + YAML_CUSTOM("board",nullptr,w_board), + YAML_ARRAY("calib", 48, 20, struct_CalibData, NULL), + YAML_PADDING( 16 ), + YAML_UNSIGNED( "vBatWarn", 8 ), + YAML_SIGNED( "txVoltageCalibration", 8 ), + YAML_ENUM("backlightMode", 3, enum_BacklightMode), + YAML_ENUM("antennaMode", 2, enum_AntennaModes), + YAML_UNSIGNED( "disableRtcWarning", 1 ), + YAML_UNSIGNED( "keysBacklight", 1 ), + YAML_UNSIGNED( "dontPlayHello", 1 ), + YAML_ENUM("internalModule", 8, enum_ModuleType), + YAML_STRUCT("trainer", 128, struct_TrainerData, NULL), + YAML_UNSIGNED( "view", 8 ), + YAML_PADDING( 2 ), + YAML_UNSIGNED( "fai", 1 ), + YAML_SIGNED_CUST( "beepMode", 2, r_beeperMode, w_beeperMode ), + YAML_UNSIGNED( "alarmsFlash", 1 ), + YAML_UNSIGNED( "disableMemoryWarning", 1 ), + YAML_UNSIGNED( "disableAlarmWarning", 1 ), + YAML_UNSIGNED( "stickMode", 2 ), + YAML_SIGNED( "timezone", 5 ), + YAML_UNSIGNED( "adjustRTC", 1 ), + YAML_UNSIGNED( "inactivityTimer", 8 ), + YAML_CUSTOM("telemetryBaudrate",r_telemetryBaudrate,nullptr), + YAML_UNSIGNED( "internalModuleBaudrate", 3 ), + YAML_SIGNED( "splashMode", 3 ), + YAML_SIGNED_CUST( "hapticMode", 2, r_beeperMode, w_beeperMode ), + YAML_SIGNED( "switchesDelay", 8 ), + YAML_UNSIGNED( "lightAutoOff", 8 ), + YAML_UNSIGNED( "templateSetup", 8 ), + YAML_SIGNED( "PPM_Multiplier", 8 ), + YAML_SIGNED_CUST( "hapticLength", 8, r_5pos, w_5pos ), + YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), + YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), + YAML_UNSIGNED( "gpsFormat", 1 ), + YAML_UNSIGNED( "audioMuteEnable", 1 ), + YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), + YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), + YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), + YAML_SIGNED_CUST( "vBatMax", 8, r_vbat_max, w_vbat_max ), + YAML_UNSIGNED( "backlightBright", 8 ), + YAML_UNSIGNED( "globalTimer", 32 ), + YAML_UNSIGNED( "bluetoothBaudrate", 4 ), + YAML_ENUM("bluetoothMode", 4, enum_BluetoothModes), + YAML_UNSIGNED( "countryCode", 2 ), + YAML_SIGNED( "pwrOnSpeed", 3 ), + YAML_SIGNED( "pwrOffSpeed", 3 ), + YAML_CUSTOM("jitterFilter",r_jitterFilter,nullptr), + YAML_UNSIGNED( "noJitterFilter", 1 ), + YAML_UNSIGNED( "imperial", 1 ), + YAML_UNSIGNED( "disableRssiPoweroffAlarm", 1 ), + YAML_UNSIGNED( "USBMode", 2 ), + YAML_UNSIGNED( "jackMode", 2 ), + YAML_PADDING( 1 ), + YAML_STRING("ttsLanguage", 2), + YAML_SIGNED_CUST( "beepVolume", 4, r_5pos, w_5pos ), + YAML_SIGNED_CUST( "wavVolume", 4, r_5pos, w_5pos ), + YAML_SIGNED_CUST( "varioVolume", 4, r_5pos, w_5pos ), + YAML_SIGNED_CUST( "backgroundVolume", 4, r_5pos, w_5pos ), + YAML_SIGNED_CUST( "varioPitch", 8, r_vPitch, w_vPitch ), + YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ), + YAML_SIGNED( "varioRepeat", 8 ), + YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active), + YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr), + YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr), + YAML_ARRAY("serialPort", 8, 4, struct_serialConfig, nullptr), + YAML_ARRAY("sticksConfig", 0, MAX_STICKS, struct_stickConfig, stick_name_valid), + YAML_ARRAY("slidersConfig", 0, MAX_POTS, struct_sliderConfig, nullptr), + YAML_ARRAY("potsConfig", 4, 16, struct_potConfig, nullptr), + YAML_ARRAY("switchConfig", 2, 32, struct_switchConfig, nullptr), + YAML_ARRAY("flexSwitches", 0, MAX_FLEX_SWITCHES, struct_flexSwitch, flex_sw_valid), + YAML_STRING("currModelFilename", 17), + YAML_UNSIGNED( "modelQuickSelect", 1 ), + YAML_UNSIGNED( "blOffBright", 7 ), + YAML_STRING("bluetoothName", 10), + YAML_STRING("ownerRegistrationID", 8), + YAML_CUSTOM("rotEncDirection",r_rotEncDirection,nullptr), + YAML_UNSIGNED( "rotEncMode", 3 ), + YAML_SIGNED( "uartSampleMode", 2 ), + YAML_UNSIGNED( "stickDeadZone", 3 ), + YAML_SIGNED( "imuMax", 8 ), + YAML_SIGNED( "imuOffset", 8 ), + YAML_STRING("selectedTheme", 26), + YAML_UNSIGNED( "labelSingleSelect", 1 ), + YAML_UNSIGNED( "labelMultiMode", 1 ), + YAML_UNSIGNED( "favMultiMode", 1 ), + YAML_UNSIGNED( "modelSelectLayout", 2 ), + YAML_UNSIGNED( "radioThemesDisabled", 1 ), + YAML_UNSIGNED( "radioGFDisabled", 1 ), + YAML_UNSIGNED( "radioTrainerDisabled", 1 ), + YAML_UNSIGNED( "modelHeliDisabled", 1 ), + YAML_UNSIGNED( "modelFMDisabled", 1 ), + YAML_UNSIGNED( "modelCurvesDisabled", 1 ), + YAML_UNSIGNED( "modelGVDisabled", 1 ), + YAML_UNSIGNED( "modelLSDisabled", 1 ), + YAML_UNSIGNED( "modelSFDisabled", 1 ), + YAML_UNSIGNED( "modelCustomScriptsDisabled", 1 ), + YAML_UNSIGNED( "modelTelemetryDisabled", 1 ), + YAML_UNSIGNED( "disableTrainerPoweroffAlarm", 1 ), + YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), + YAML_PADDING( 6 ), + YAML_UNSIGNED( "pwrOffIfInactive", 8 ), + YAML_END +}; +static const struct YamlNode struct_unsigned_8[] = { + YAML_IDX, + YAML_UNSIGNED( "val", 8 ), + YAML_END +}; +static const struct YamlNode struct_ModelHeader[] = { + YAML_STRING("name", 15), + YAML_ARRAY("modelId", 8, 2, struct_unsigned_8, NULL), + YAML_STRING("bitmap", 14), + YAML_STRING("labels", 100), + YAML_END +}; +static const struct YamlNode struct_TimerData[] = { + YAML_IDX, + YAML_UNSIGNED( "start", 22 ), + YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ), + YAML_SIGNED( "value", 22 ), + YAML_ENUM("mode", 3, enum_TimerModes), + YAML_UNSIGNED( "countdownBeep", 2 ), + YAML_UNSIGNED( "minuteBeep", 1 ), + YAML_UNSIGNED( "persistent", 2 ), + YAML_SIGNED( "countdownStart", 2 ), + YAML_UNSIGNED( "showElapsed", 1 ), + YAML_UNSIGNED( "extraHaptic", 1 ), + YAML_PADDING( 6 ), + YAML_STRING("name", 8), + YAML_END +}; +static const struct YamlNode struct_CurveRef[] = { + YAML_UNSIGNED( "type", 5 ), + YAML_SIGNED_CUST( "value", 11, r_sourceNumVal, w_sourceNumVal ), + YAML_END +}; +static const struct YamlNode struct_MixData[] = { + YAML_UNSIGNED( "destCh", 5 ), + YAML_SIGNED_CUST( "srcRaw", 10, r_mixSrcRawEx, w_mixSrcRawEx ), + YAML_UNSIGNED( "carryTrim", 1 ), + YAML_UNSIGNED( "mixWarn", 2 ), + YAML_ENUM("mltpx", 2, enum_MixerMultiplex), + YAML_UNSIGNED( "delayPrec", 1 ), + YAML_UNSIGNED( "speedPrec", 1 ), + YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), + YAML_PADDING( 1 ), + YAML_UNSIGNED_CUST( "weight", 11, r_sourceNumVal, w_sourceNumVal ), + YAML_UNSIGNED_CUST( "offset", 11, r_sourceNumVal, w_sourceNumVal ), + YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ), + YAML_STRUCT("curve", 16, struct_CurveRef, NULL), + YAML_UNSIGNED( "delayUp", 8 ), + YAML_UNSIGNED( "delayDown", 8 ), + YAML_UNSIGNED( "speedUp", 8 ), + YAML_UNSIGNED( "speedDown", 8 ), + YAML_STRING("name", 6), + YAML_END +}; +static const struct YamlNode struct_LimitData[] = { + YAML_IDX, + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), + YAML_SIGNED( "ppmCenter", 10 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), + YAML_UNSIGNED( "symetrical", 1 ), + YAML_UNSIGNED( "revert", 1 ), + YAML_PADDING( 3 ), + YAML_SIGNED( "curve", 8 ), + YAML_STRING("name", 6), + YAML_END +}; +static const struct YamlNode struct_ExpoData[] = { + YAML_UNSIGNED( "mode", 2 ), + YAML_UNSIGNED( "scale", 14 ), + YAML_CUSTOM("carryTrim",r_carryTrim,nullptr), + YAML_SIGNED( "trimSource", 6 ), + YAML_SIGNED_CUST( "srcRaw", 10, r_mixSrcRawEx, w_mixSrcRawEx ), + YAML_UNSIGNED_CUST( "weight", 11, r_sourceNumVal, w_sourceNumVal ), + YAML_UNSIGNED_CUST( "offset", 11, r_sourceNumVal, w_sourceNumVal ), + YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ), + YAML_STRUCT("curve", 16, struct_CurveRef, NULL), + YAML_UNSIGNED( "chn", 5 ), + YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), + YAML_PADDING( 2 ), + YAML_STRING("name", 6), + YAML_END +}; +static const struct YamlNode struct_CurveHeader[] = { + YAML_IDX, + YAML_UNSIGNED( "type", 1 ), + YAML_UNSIGNED( "smooth", 1 ), + YAML_SIGNED( "points", 6 ), + YAML_STRING("name", 3), + YAML_END +}; +static const struct YamlNode struct_signed_8[] = { + YAML_IDX, + YAML_SIGNED( "val", 8 ), + YAML_END +}; +static const struct YamlNode struct_LogicalSwitchData[] = { + YAML_IDX, + YAML_ENUM("func", 8, enum_LogicalSwitchesFunctions), + YAML_CUSTOM("def",r_logicSw,w_logicSw), + YAML_PADDING( 10 ), + YAML_PADDING( 10 ), + YAML_SIGNED_CUST( "andsw", 10, r_swtchSrc, w_swtchSrc ), + YAML_UNSIGNED( "lsPersist", 1 ), + YAML_UNSIGNED( "lsState", 1 ), + YAML_PADDING( 16 ), + YAML_UNSIGNED( "delay", 8 ), + YAML_UNSIGNED( "duration", 8 ), + YAML_END +}; +static const struct YamlNode struct_SwashRingData[] = { + YAML_ENUM("type", 8, enum_SwashType), + YAML_UNSIGNED( "value", 8 ), + YAML_UNSIGNED_CUST( "collectiveSource", 8, r_mixSrcRaw, w_mixSrcRaw ), + YAML_UNSIGNED_CUST( "aileronSource", 8, r_mixSrcRaw, w_mixSrcRaw ), + YAML_UNSIGNED_CUST( "elevatorSource", 8, r_mixSrcRaw, w_mixSrcRaw ), + YAML_SIGNED( "collectiveWeight", 8 ), + YAML_SIGNED( "aileronWeight", 8 ), + YAML_SIGNED( "elevatorWeight", 8 ), + YAML_END +}; +static const struct YamlNode struct_trim_t[] = { + YAML_IDX, + YAML_SIGNED( "value", 11 ), + YAML_UNSIGNED( "mode", 5 ), + YAML_END +}; +static const struct YamlNode struct_FlightModeData[] = { + YAML_IDX, + YAML_ARRAY("trim", 16, 8, struct_trim_t, NULL), + YAML_STRING("name", 10), + YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ), + YAML_PADDING( 6 ), + YAML_UNSIGNED( "fadeIn", 8 ), + YAML_UNSIGNED( "fadeOut", 8 ), + YAML_ARRAY("gvars", 16, 9, struct_signed_16, gvar_is_active), + YAML_END +}; +static const struct YamlNode struct_GVarData[] = { + YAML_IDX, + YAML_STRING("name", 3), + YAML_UNSIGNED( "min", 12 ), + YAML_UNSIGNED( "max", 12 ), + YAML_UNSIGNED( "popup", 1 ), + YAML_UNSIGNED( "prec", 1 ), + YAML_UNSIGNED( "unit", 2 ), + YAML_PADDING( 4 ), + YAML_END +}; +static const struct YamlNode struct_VarioData[] = { + YAML_UNSIGNED_CUST( "source", 7, r_tele_sensor, w_tele_sensor ), + YAML_UNSIGNED( "centerSilent", 1 ), + YAML_SIGNED( "centerMax", 8 ), + YAML_SIGNED( "centerMin", 8 ), + YAML_SIGNED( "min", 8 ), + YAML_SIGNED( "max", 8 ), + YAML_END +}; +static const struct YamlNode struct_RssiAlarmData[] = { + YAML_CUSTOM("disabled",r_rssiDisabled,nullptr), + YAML_CUSTOM("warning",r_rssiWarning,nullptr), + YAML_CUSTOM("critical",r_rssiCritical,nullptr), + YAML_END +}; +static const struct YamlNode struct_RFAlarmData[] = { + YAML_SIGNED( "warning", 8 ), + YAML_SIGNED( "critical", 8 ), + YAML_END +}; +static const struct YamlNode struct_PpmModule[] = { + YAML_SIGNED( "delay", 6 ), + YAML_UNSIGNED( "pulsePol", 1 ), + YAML_UNSIGNED( "outputType", 1 ), + YAML_SIGNED( "frameLength", 8 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_5[] = { + YAML_PADDING( 8 ), + YAML_UNSIGNED( "disableTelemetry", 1 ), + YAML_UNSIGNED( "disableMapping", 1 ), + YAML_UNSIGNED( "autoBindMode", 1 ), + YAML_UNSIGNED( "lowPowerMode", 1 ), + YAML_UNSIGNED( "receiverTelemetryOff", 1 ), + YAML_UNSIGNED( "receiverHigherChannels", 1 ), + YAML_PADDING( 2 ), + YAML_SIGNED( "optionValue", 8 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_6[] = { + YAML_UNSIGNED( "power", 2 ), + YAML_PADDING( 2 ), + YAML_UNSIGNED( "receiverTelemetryOff", 1 ), + YAML_UNSIGNED( "receiverHigherChannels", 1 ), + YAML_SIGNED( "antennaMode", 2 ), + YAML_PADDING( 8 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_7[] = { + YAML_PADDING( 6 ), + YAML_UNSIGNED( "noninverted", 1 ), + YAML_PADDING( 1 ), + YAML_SIGNED( "refreshRate", 8 ), + YAML_END +}; +static const struct YamlNode struct_string_64[] = { + YAML_IDX, + YAML_STRING("val", 8), + YAML_END +}; +static const struct YamlNode struct_anonymous_8[] = { + YAML_UNSIGNED( "receivers", 7 ), + YAML_UNSIGNED( "racingMode", 1 ), + YAML_ARRAY("receiverName", 64, 3, struct_string_64, NULL), + YAML_END +}; +static const struct YamlNode struct_anonymous_9[] = { + YAML_ARRAY("rx_id", 8, 4, struct_unsigned_8, NULL), + YAML_UNSIGNED( "mode", 3 ), + YAML_UNSIGNED( "rfPower", 1 ), + YAML_UNSIGNED( "reserved", 4 ), + YAML_ARRAY("rx_freq", 8, 2, struct_unsigned_8, NULL), + YAML_END +}; +static const struct YamlNode struct_anonymous_10[] = { + YAML_UNSIGNED( "emi", 2 ), + YAML_UNSIGNED( "telemetry", 1 ), + YAML_UNSIGNED( "phyMode", 3 ), + YAML_UNSIGNED( "reserved", 2 ), + YAML_UNSIGNED( "rfPower", 8 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_11[] = { + YAML_UNSIGNED( "raw12bits", 1 ), + YAML_UNSIGNED( "telemetryBaudrate", 3 ), + YAML_PADDING( 4 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_12[] = { + YAML_UNSIGNED( "telemetryBaudrate", 3 ), + YAML_UNSIGNED( "crsfArmingMode", 1 ), + YAML_PADDING( 4 ), + YAML_SIGNED_CUST( "crsfArmingTrigger", 10, r_swtchSrc, w_swtchSrc ), + YAML_SIGNED( "spare3", 6 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_13[] = { + YAML_UNSIGNED( "flags", 8 ), + YAML_END +}; +static const struct YamlNode union_anonymous_4_elmts[] = { + YAML_ARRAY("raw", 8, 25, struct_unsigned_8, NULL), + YAML_STRUCT("ppm", 16, struct_PpmModule, NULL), + YAML_STRUCT("multi", 24, struct_anonymous_5, NULL), + YAML_STRUCT("pxx", 16, struct_anonymous_6, NULL), + YAML_STRUCT("sbus", 16, struct_anonymous_7, NULL), + YAML_STRUCT("pxx2", 200, struct_anonymous_8, NULL), + YAML_STRUCT("flysky", 56, struct_anonymous_9, NULL), + YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL), + YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL), + YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL), + YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL), + YAML_END +}; +static const struct YamlNode struct_ModuleData[] = { + YAML_IDX, + YAML_UNSIGNED_CUST( "type", 8, r_moduleType, w_moduleType ), + YAML_CUSTOM("subType",r_modSubtype,w_modSubtype), + YAML_UNSIGNED( "channelsStart", 8 ), + YAML_SIGNED_CUST( "channelsCount", 8, r_channelsCount, w_channelsCount ), + YAML_ENUM("failsafeMode", 4, enum_FailsafeModes), + YAML_PADDING( 4 ), + YAML_UNION("mod", 200, union_anonymous_4_elmts, select_mod_type), + YAML_END +}; +static const struct YamlNode struct_TrainerModuleData[] = { + YAML_UNSIGNED_CUST( "mode", 8, r_trainerMode, w_trainerMode ), + YAML_UNSIGNED( "channelsStart", 8 ), + YAML_SIGNED( "channelsCount", 8 ), + YAML_SIGNED( "frameLength", 8 ), + YAML_SIGNED( "delay", 6 ), + YAML_UNSIGNED( "pulsePol", 1 ), + YAML_PADDING( 1 ), + YAML_END +}; +static const struct YamlNode union_ScriptDataInput_elmts[] = { + YAML_SIGNED( "value", 16 ), + YAML_UNSIGNED_CUST( "source", 16, r_mixSrcRaw, w_mixSrcRaw ), + YAML_END +}; +static const struct YamlNode union_ScriptDataInput[] = { + YAML_IDX, + YAML_UNION("u", 16, union_ScriptDataInput_elmts, select_script_input), + YAML_END +}; +static const struct YamlNode struct_ScriptData[] = { + YAML_IDX, + YAML_STRING("file", 6), + YAML_STRING("name", 6), + YAML_ARRAY("inputs", 16, 6, union_ScriptDataInput, NULL), + YAML_END +}; +static const struct YamlNode struct_string_32[] = { + YAML_IDX, + YAML_STRING("val", 4), + YAML_END +}; +static const struct YamlNode union_anonymous_14_elmts[] = { + YAML_UNSIGNED( "id", 16 ), + YAML_UNSIGNED( "persistentValue", 16 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_16[] = { + YAML_UNSIGNED( "physID", 5 ), + YAML_UNSIGNED( "rxIndex", 3 ), + YAML_END +}; +static const struct YamlNode union_anonymous_15_elmts[] = { + YAML_STRUCT("frskyInstance", 8, struct_anonymous_16, NULL), + YAML_UNSIGNED( "instance", 8 ), + YAML_ENUM("formula", 8, enum_TelemetrySensorFormula), + YAML_END +}; +static const struct YamlNode struct_anonymous_18[] = { + YAML_UNSIGNED( "ratio", 16 ), + YAML_SIGNED( "offset", 16 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_19[] = { + YAML_UNSIGNED( "source", 8 ), + YAML_UNSIGNED( "index", 8 ), + YAML_PADDING( 16 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_20[] = { + YAML_ARRAY("sources", 8, 4, struct_signed_8, NULL), + YAML_END +}; +static const struct YamlNode struct_anonymous_21[] = { + YAML_UNSIGNED( "source", 8 ), + YAML_PADDING( 24 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_22[] = { + YAML_UNSIGNED( "gps", 8 ), + YAML_UNSIGNED( "alt", 8 ), + YAML_PADDING( 16 ), + YAML_END +}; +static const struct YamlNode union_anonymous_17_elmts[] = { + YAML_STRUCT("custom", 32, struct_anonymous_18, NULL), + YAML_STRUCT("cell", 32, struct_anonymous_19, NULL), + YAML_STRUCT("calc", 32, struct_anonymous_20, NULL), + YAML_STRUCT("consumption", 32, struct_anonymous_21, NULL), + YAML_STRUCT("dist", 32, struct_anonymous_22, NULL), + YAML_UNSIGNED( "param", 32 ), + YAML_END +}; +static const struct YamlNode struct_TelemetrySensor[] = { + YAML_IDX, + YAML_UNION("id1", 16, union_anonymous_14_elmts, select_id1), + YAML_UNION("id2", 8, union_anonymous_15_elmts, select_id2), + YAML_STRING("label", 4), + YAML_UNSIGNED( "subId", 8 ), + YAML_ENUM("type", 1, enum_TelemetrySensorType), + YAML_PADDING( 1 ), + YAML_UNSIGNED( "unit", 6 ), + YAML_UNSIGNED( "prec", 2 ), + YAML_UNSIGNED( "autoOffset", 1 ), + YAML_UNSIGNED( "filter", 1 ), + YAML_UNSIGNED( "logs", 1 ), + YAML_UNSIGNED( "persistent", 1 ), + YAML_UNSIGNED( "onlyPositive", 1 ), + YAML_PADDING( 1 ), + YAML_UNION("cfg", 32, union_anonymous_17_elmts, select_sensor_cfg), + YAML_END +}; +static const struct YamlNode union_ZoneOptionValue_elmts[] = { + YAML_UNSIGNED( "unsignedValue", 32 ), + YAML_SIGNED( "signedValue", 32 ), + YAML_UNSIGNED( "boolValue", 32 ), + YAML_STRING("stringValue", 12), + YAML_CUSTOM("source",r_zov_source,w_zov_source), + YAML_CUSTOM("color",r_zov_color,w_zov_color), + YAML_END +}; +static const struct YamlNode struct_ZoneOptionValueTyped[] = { + YAML_IDX, + YAML_ENUM("type", 32, enum_ZoneOptionValueEnum), + YAML_UNION("value", 96, union_ZoneOptionValue_elmts, select_zov), + YAML_END +}; +static const struct YamlNode struct_WidgetPersistentData[] = { + YAML_ARRAY("options", 128, 10, struct_ZoneOptionValueTyped, NULL), + YAML_END +}; +static const struct YamlNode struct_ZonePersistentData[] = { + YAML_IDX, + YAML_STRING("widgetName", 12), + YAML_STRUCT("widgetData", 1280, struct_WidgetPersistentData, NULL), + YAML_END +}; +static const struct YamlNode struct_LayoutPersistentData[] = { + YAML_ARRAY("zones", 1376, 10, struct_ZonePersistentData, NULL), + YAML_ARRAY("options", 128, 10, struct_ZoneOptionValueTyped, NULL), + YAML_END +}; +static const struct YamlNode struct_CustomScreenData[] = { + YAML_IDX, + YAML_STRING("LayoutId", 12), + YAML_STRUCT("layoutData", 15040, struct_LayoutPersistentData, NULL), + YAML_END +}; +static const struct YamlNode struct_TopBarPersistentData[] = { + YAML_ARRAY("zones", 1376, 6, struct_ZonePersistentData, NULL), + YAML_ARRAY("options", 128, 1, struct_ZoneOptionValueTyped, NULL), + YAML_END +}; +static const struct YamlNode struct_string_24[] = { + YAML_IDX, + YAML_STRING("val", 3), + YAML_END +}; +static const struct YamlNode struct_RGBLedColor[] = { + YAML_IDX, + YAML_UNSIGNED( "r", 8 ), + YAML_UNSIGNED( "g", 8 ), + YAML_UNSIGNED( "b", 8 ), + YAML_END +}; +static const struct YamlNode struct_USBJoystickChData[] = { + YAML_IDX, + YAML_ENUM("mode", 3, enum_USBJoystickCh), + YAML_UNSIGNED( "inversion", 1 ), + YAML_UNSIGNED( "param", 4 ), + YAML_UNSIGNED( "btn_num", 5 ), + YAML_UNSIGNED( "switch_npos", 3 ), + YAML_END +}; +static const struct YamlNode struct_ModelData[] = { + YAML_CUSTOM("semver",nullptr,w_semver), + YAML_STRUCT("header", 1048, struct_ModelHeader, NULL), + YAML_ARRAY("timers", 136, 3, struct_TimerData, NULL), + YAML_UNSIGNED( "telemetryProtocol", 3 ), + YAML_UNSIGNED( "thrTrim", 1 ), + YAML_UNSIGNED( "noGlobalFunctions", 1 ), + YAML_UNSIGNED( "displayTrims", 2 ), + YAML_UNSIGNED( "ignoreSensorIds", 1 ), + YAML_SIGNED( "trimInc", 3 ), + YAML_UNSIGNED( "disableThrottleWarning", 1 ), + YAML_UNSIGNED( "displayChecklist", 1 ), + YAML_UNSIGNED( "extendedLimits", 1 ), + YAML_UNSIGNED( "extendedTrims", 1 ), + YAML_UNSIGNED( "throttleReversed", 1 ), + YAML_UNSIGNED( "enableCustomThrottleWarning", 1 ), + YAML_UNSIGNED( "disableTelemetryWarning", 1 ), + YAML_UNSIGNED( "showInstanceIds", 1 ), + YAML_UNSIGNED( "checklistInteractive", 1 ), + YAML_PADDING( 4 ), + YAML_SIGNED( "customThrottleWarningPosition", 8 ), + YAML_UNSIGNED( "beepANACenter", 16 ), + YAML_ARRAY("mixData", 160, 64, struct_MixData, NULL), + YAML_ARRAY("limitData", 104, 32, struct_LimitData, NULL), + YAML_ARRAY("expoData", 144, 64, struct_ExpoData, NULL), + YAML_ARRAY("curves", 32, 32, struct_CurveHeader, NULL), + YAML_ARRAY("points", 8, 512, struct_signed_8, NULL), + YAML_ARRAY("logicalSw", 72, 64, struct_LogicalSwitchData, NULL), + YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active), + YAML_STRUCT("swashR", 64, struct_SwashRingData, swash_is_active), + YAML_ARRAY("flightModeData", 384, 9, struct_FlightModeData, fmd_is_active), + YAML_UNSIGNED_CUST( "thrTraceSrc", 8, r_thrSrc, w_thrSrc ), + YAML_CUSTOM("switchWarningState",r_swtchWarn,nullptr), + YAML_ARRAY("switchWarning", 3, 21, struct_swtchWarn, nullptr), + YAML_PADDING(1), + YAML_ARRAY("gvars", 56, 9, struct_GVarData, NULL), + YAML_STRUCT("varioData", 40, struct_VarioData, NULL), + YAML_UNSIGNED_CUST( "rssiSource", 8, r_tele_sensor, w_tele_sensor ), + YAML_STRUCT("rssiAlarms", 0, struct_RssiAlarmData, NULL), + YAML_STRUCT("rfAlarms", 16, struct_RFAlarmData, NULL), + YAML_UNSIGNED( "thrTrimSw", 3 ), + YAML_ENUM("potsWarnMode", 2, enum_PotsWarnMode), + YAML_ENUM("jitterFilter", 2, enum_ModelOverridableEnable), + YAML_PADDING( 1 ), + YAML_ARRAY("moduleData", 232, 2, struct_ModuleData, NULL), + YAML_ARRAY("failsafeChannels", 16, 32, struct_signed_16, NULL), + YAML_STRUCT("trainerData", 40, struct_TrainerModuleData, NULL), + YAML_ARRAY("scriptsData", 192, 9, struct_ScriptData, NULL), + YAML_ARRAY("inputNames", 32, 32, struct_string_32, NULL), + YAML_UNSIGNED( "potsWarnEnabled", 16 ), + YAML_ARRAY("potsWarnPosition", 8, 16, struct_signed_8, NULL), + YAML_ARRAY("telemetrySensors", 112, 60, struct_TelemetrySensor, NULL), + YAML_ARRAY("screenData", 15136, 10, struct_CustomScreenData, NULL), + YAML_STRUCT("topbarData", 8384, struct_TopBarPersistentData, NULL), + YAML_ARRAY("topbarWidgetWidth", 8, 6, struct_unsigned_8, NULL), + YAML_UNSIGNED( "view", 8 ), + YAML_STRING("modelRegistrationID", 8), + YAML_UNSIGNED( "functionSwitchConfig", 16 ), + YAML_UNSIGNED( "functionSwitchGroup", 16 ), + YAML_UNSIGNED( "functionSwitchStartConfig", 16 ), + YAML_UNSIGNED( "functionSwitchLogicalState", 8 ), + YAML_ARRAY("switchNames", 24, 6, struct_string_24, NULL), + YAML_ARRAY("functionSwitchLedONColor", 24, 6, struct_RGBLedColor, NULL), + YAML_ARRAY("functionSwitchLedOFFColor", 24, 6, struct_RGBLedColor, NULL), + YAML_UNSIGNED( "usbJoystickExtMode", 1 ), + YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode), + YAML_UNSIGNED( "usbJoystickCircularCut", 4 ), + YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL), + YAML_ENUM("radioThemesDisabled", 2, enum_ModelOverridableEnable), + YAML_ENUM("radioGFDisabled", 2, enum_ModelOverridableEnable), + YAML_ENUM("radioTrainerDisabled", 2, enum_ModelOverridableEnable), + YAML_ENUM("modelHeliDisabled", 2, enum_ModelOverridableEnable), + YAML_ENUM("modelFMDisabled", 2, enum_ModelOverridableEnable), + YAML_ENUM("modelCurvesDisabled", 2, enum_ModelOverridableEnable), + YAML_ENUM("modelGVDisabled", 2, enum_ModelOverridableEnable), + YAML_ENUM("modelLSDisabled", 2, enum_ModelOverridableEnable), + YAML_ENUM("modelSFDisabled", 2, enum_ModelOverridableEnable), + YAML_ENUM("modelCustomScriptsDisabled", 2, enum_ModelOverridableEnable), + YAML_ENUM("modelTelemetryDisabled", 2, enum_ModelOverridableEnable), + YAML_END +}; +static const struct YamlNode struct_PartialModel[] = { + YAML_STRUCT("header", 1048, struct_ModelHeader, NULL), + YAML_ARRAY("timers", 136, 3, struct_TimerData, NULL), + YAML_END +}; + +#define MAX_RADIODATA_MODELDATA_PARTIALMODEL_STR_LEN 29 + +static const struct YamlNode __RadioData_root_node = YAML_ROOT( struct_RadioData ); + +const YamlNode* get_radiodata_nodes() +{ + return &__RadioData_root_node; +} +static const struct YamlNode __ModelData_root_node = YAML_ROOT( struct_ModelData ); + +const YamlNode* get_modeldata_nodes() +{ + return &__ModelData_root_node; +} +static const struct YamlNode __PartialModel_root_node = YAML_ROOT( struct_PartialModel ); + +const YamlNode* get_partialmodel_nodes() +{ + return &__PartialModel_root_node; +} + diff --git a/radio/src/targets/common/arm/stm32/h7/CMakeLists.txt b/radio/src/targets/common/arm/stm32/h7/CMakeLists.txt index 1306a2562..71368fd26 100644 --- a/radio/src/targets/common/arm/stm32/h7/CMakeLists.txt +++ b/radio/src/targets/common/arm/stm32/h7/CMakeLists.txt @@ -121,7 +121,7 @@ else() add_definitions(-DSTM32H7) endif() -if(CPU_TYPE_FULL STREQUAL STM32H750Ix) +if(CPU_TYPE_FULL STREQUAL STM32H750xB) set(CMSIS_SRC ${CMSIS_SRC} boards/generic_stm32/startup/startup_stm32h750xx.s ) @@ -134,7 +134,7 @@ elseif(CPU_TYPE_FULL STREQUAL STM32H7S7xx) boards/generic_stm32/startup/startup_stm32h7s7xx.s ) else() - message("### ERROR ####: ${CPU_TYPE_FULL}") + message(FATAL_ERROR "### ERROR ####: ${CPU_TYPE_FULL}") endif() add_library(cmsis OBJECT EXCLUDE_FROM_ALL diff --git a/radio/src/targets/st16/CMakeLists.txt b/radio/src/targets/st16/CMakeLists.txt new file mode 100644 index 000000000..2bb703028 --- /dev/null +++ b/radio/src/targets/st16/CMakeLists.txt @@ -0,0 +1,187 @@ +option(UNEXPECTED_SHUTDOWN "Enable the Unexpected Shutdown screen" ON) +option(PXX1 "PXX1 protocol support" ON) +option(PXX2 "PXX2 protocol support" OFF) +option(AFHDS3 "AFHDS3 TX Module" ON) +option(MULTIMODULE "DIY Multiprotocol TX Module (https://github.com/pascallanger/DIY-Multiprotocol-TX-Module)" ON) +option(GHOST "Ghost TX Module" ON) +option(MODULE_SIZE_STD "Standard size TX Module" ON) +option(LUA_MIXER "Enable LUA mixer/model scripts support" ON) +option(DISK_CACHE "Enable SD card disk cache" ON) + +set(FIRMWARE_QSPI YES) +set(FIRMWARE_FORMAT_UF2 YES) +set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)") +set(CPU_TYPE STM32H7) +set(HSE_VALUE 8000000) +set(SDCARD YES) +set(STORAGE_MODELSLIST YES) +set(HAPTIC YES) +set(GUI_DIR colorlcd) +set(BITMAPS_DIR 480x272) +set(TARGET_DIR st16) +# set(RTC_BACKUP_RAM YES) +set(PPM_LIMITS_SYMETRICAL YES) +set(USB_SERIAL ON CACHE BOOL "Enable USB serial (CDC)") +set(HARDWARE_EXTERNAL_MODULE YES) +set(INTERNAL_MODULE_AFHDS3 YES) +set(ROTARY_ENCODER YES) +set(FUNCTION_SWITCHES_WITH_RGB YES) + +#option(STICKS_DEAD_ZONE "Enable sticks dead zone" YES) + +# IMU support +set(IMU ON) + +# for size report script +set(CPU_TYPE_FULL STM32H750xB) +set(TARGET_LINKER_DIR stm32h750_sdram) +set(TARGET_SDRAM_START 0xC0000000) +set(SIZE_TARGET_MEM_DEFINE "MEM_SIZE_SDRAM1=8192") +set(FIRMWARE_STRIP_BOOTLOADER YES) + +add_definitions(-DPCBST16 -DPCBHORUS -DPCBFLYSKY) +add_definitions(-DBATTERY_CHARGE) +add_definitions(-DSTM32_SUPPORT_32BIT_TIMERS) +add_definitions(-DFIRMWARE_QSPI) +add_definitions(-DFIRMWARE_FORMAT_UF2) +add_definitions(-DUSE_CUSTOM_EXTI_IRQ) + +set(FLAVOUR st16) +add_definitions(-DRADIO_ST16) + +# Defines internal modules for PL18 via UART7 +# set(INTERNAL_MODULES MULTI CACHE STRING "Internal modules") +# set(DEFAULT_INTERNAL_MODULE MULTIMODULE CACHE STRING "Default internal module") + +set(BITMAPS_TARGET bm480_bitmaps) +set(FONTS_TARGET x12_fonts) +set(LCD_DRIVER lcd_driver.cpp) +set(HARDWARE_TOUCH YES) +set(RADIO_DEPENDENCIES ${RADIO_DEPENDENCIES} ${BITMAPS_TARGET}) +set(FIRMWARE_DEPENDENCIES datacopy) +set(SOFTWARE_KEYBOARD ON) +set(FLYSKY_GIMBAL ON) +set(FUNCTION_SWITCHES ON) + + +add_definitions( + -DSTM32H750IBTx -DSTM32H750xx + -DSDRAM -DCCMRAM + -DCOLORLCD -DLIBOPENUI + -DHARDWARE_TOUCH -DHARDWARE_KEYS -DSOFTWARE_KEYBOARD + -DWS2812_MAX_LEDS=24 +) + +set(SDRAM ON) + +add_definitions(-DAUDIO -DVOICE -DRTCLOCK) +add_definitions(-DGPS_USART_BAUDRATE=${INTERNAL_GPS_BAUDRATE}) +add_definitions(-DPWR_BUTTON_${PWR_BUTTON}) + +if(STICKS_DEAD_ZONE) + add_definitions(-DSTICK_DEAD_ZONE) +endif() + +if(NOT UNEXPECTED_SHUTDOWN) + add_definitions(-DNO_UNEXPECTED_SHUTDOWN) +endif() + +if(DISK_CACHE) + set(SRC ${SRC} disk_cache.cpp) + add_definitions(-DDISK_CACHE) +endif() + +if(FUNCTION_SWITCHES_WITH_RGB) + set(FUNCTION_SWITCHES YES) + add_definitions(-DFUNCTION_SWITCHES) + add_definitions(-DFUNCTION_SWITCHES_RGB_LEDS) +endif() + +if(FUNCTION_SWITCHES) +add_definitions(-DFUNCTION_SWITCHES) +endif() + +set(AFHDS3 ON) + +# VCP CLI +set(ENABLE_SERIAL_PASSTHROUGH ON CACHE BOOL "Enable serial passthrough") +set(CLI ON CACHE BOOL "Enable CLI") + +set(TARGET_SRC_DIR targets/${TARGET_DIR}) + +set(BOARD_COMMON_SRC + ${TARGET_SRC_DIR}/board.cpp + ${TARGET_SRC_DIR}/bsp_io.cpp + ${TARGET_SRC_DIR}/key_driver.cpp + ${TARGET_SRC_DIR}/system_init.cpp + ${TARGET_SRC_DIR}/lcd_driver.cpp + ${TARGET_SRC_DIR}/backlight_driver.cpp + ${TARGET_SRC_DIR}/haptic_driver.cpp + ${TARGET_SRC_DIR}/extflash_driver.cpp + targets/common/arm/stm32/abnormal_reboot.cpp + targets/common/arm/stm32/delays_driver.cpp + targets/common/arm/stm32/dma2d.cpp + targets/common/arm/stm32/flash_driver.cpp + targets/common/arm/stm32/pwr_driver.cpp + targets/common/arm/stm32/rotary_encoder_driver.cpp + targets/common/arm/stm32/rtc_driver.cpp + targets/common/arm/stm32/watchdog_driver.cpp + drivers/pca95xx.cpp +) + +# Bootloader board library +add_library(board_bl OBJECT EXCLUDE_FROM_ALL + ${BOARD_COMMON_SRC} + ${TARGET_SRC_DIR}/system_clock.cpp + ${TARGET_SRC_DIR}/sdram_driver.cpp + ${TARGET_SRC_DIR}/bootloader/boot_menu.cpp + targets/common/arm/stm32/stm32_qspi.cpp + targets/common/arm/stm32/stm32_pulse_driver.cpp +) +add_dependencies(board_bl minimal_board_lib) +set(BOOTLOADER_SRC ${BOOTLOADER_SRC} $) + +# Firmware board library +add_library(board OBJECT EXCLUDE_FROM_ALL + ${BOARD_COMMON_SRC} + ${TARGET_SRC_DIR}/led_driver.cpp + ${TARGET_SRC_DIR}/touch_driver.cpp + targets/common/arm/stm32/heartbeat_driver.cpp + targets/common/arm/stm32/lsm6ds_driver.cpp + targets/common/arm/stm32/mixer_scheduler_driver.cpp + targets/common/arm/stm32/module_timer_driver.cpp + targets/common/arm/stm32/stm32_pulse_driver.cpp + targets/common/arm/stm32/stm32_softserial_driver.cpp + targets/common/arm/stm32/stm32_qspi.cpp + targets/common/arm/stm32/stm32_switch_driver.cpp + targets/common/arm/stm32/vs1053b.cpp + targets/common/arm/stm32/stm32_ws2812.cpp + targets/common/arm/stm32/trainer_driver.cpp +) +add_dependencies(board board_lib) +set(FIRMWARE_SRC ${FIRMWARE_SRC} $) + +include_directories(${RADIO_SRC_DIR}/fonts/colorlcd gui/${GUI_DIR} gui/${GUI_DIR}/layouts) + +if(BOOTLOADER) + set(FIRMWARE_TARGET_SRC + ${FIRMWARE_TARGET_SRC} + ../common/arm/loadboot.cpp + ) +endif() + +set(SRC + ${SRC} + io/frsky_firmware_update.cpp + io/multi_firmware_update.cpp + ) + +if (MULTIMODULE) + add_definitions(-DMULTI_PROTOLIST) + set(SRC ${SRC} + io/multi_protolist.cpp + ) +endif() + +# Make malloc() thread-safe +add_definitions(-DTHREADSAFE_MALLOC) diff --git a/radio/src/targets/st16/backlight_driver.cpp b/radio/src/targets/st16/backlight_driver.cpp new file mode 100644 index 000000000..70be8a500 --- /dev/null +++ b/radio/src/targets/st16/backlight_driver.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "hal/gpio.h" +#include "stm32_gpio.h" +#include "stm32_timer.h" +#include "stm32_pulse_driver.h" + +#include "edgetx_types.h" +#include "board.h" + +#include "globals.h" +#include "lcd_driver.h" + +static const stm32_pulse_timer_t _bl_timer = { + .GPIO = (gpio_t)BACKLIGHT_GPIO, + .GPIO_Alternate = BACKLIGHT_GPIO_AF, + .TIMx = BACKLIGHT_TIMER, + .TIM_Freq = BACKLIGHT_TIMER_FREQ, + .TIM_Channel = LL_TIM_CHANNEL_CH1, + .TIM_IRQn = (IRQn_Type)-1, + .DMAx = nullptr, + .DMA_Stream = 0, + .DMA_Channel = 0, + .DMA_IRQn = (IRQn_Type)-1, + .DMA_TC_CallbackPtr = nullptr, +}; + +void backlightLowInit() +{ + gpio_init(BACKLIGHT_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW); + gpio_clear(BACKLIGHT_GPIO); +} + +void backlightInit() +{ + stm32_pulse_init(&_bl_timer, 10000); + stm32_pulse_config_output(&_bl_timer, true, LL_TIM_OCMODE_PWM1, 100); + LL_TIM_SetAutoReload(_bl_timer.TIMx, 100); + LL_TIM_EnableCounter(_bl_timer.TIMx); +} + +uint8_t lastDutyCycle = 0; + +void backlightEnable(uint8_t dutyCycle) +{ + stm32_pulse_set_cmp_val(&_bl_timer, dutyCycle); + + if(!dutyCycle) { + //experimental to turn off LCD when no backlight + if(lcdOffFunction) lcdOffFunction(); + } + else if(!lastDutyCycle) { + if(lcdOnFunction) lcdOnFunction(); + else lcdInit(); + } + + lastDutyCycle = dutyCycle; +} + +void lcdOff() { + backlightEnable(0); +} + +void lcdOn(){ + if(lcdOnFunction) lcdOnFunction(); + else lcdInit(); + backlightEnable(BACKLIGHT_LEVEL_MAX); +} + +bool boardBacklightOn; + +bool isBacklightEnabled() +{ + return boardBacklightOn; +} diff --git a/radio/src/targets/st16/battery_driver.h b/radio/src/targets/st16/battery_driver.h new file mode 100644 index 000000000..2b905a3ee --- /dev/null +++ b/radio/src/targets/st16/battery_driver.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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. + */ + +/*************************************************************************************************** + +***************************************************************************************************/ +#pragma once +/*************************************************************************************************** + +***************************************************************************************************/ + +#define IS_UCHARGER_ACTIVE() gpio_read(UCHARGER_GPIO) diff --git a/radio/src/targets/st16/board.cpp b/radio/src/targets/st16/board.cpp new file mode 100644 index 000000000..2d19d315e --- /dev/null +++ b/radio/src/targets/st16/board.cpp @@ -0,0 +1,356 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "stm32_adc.h" +#include "stm32_gpio.h" +#include "stm32_i2c_driver.h" +#include "stm32_hal.h" +#include "stm32_ws2812.h" +#include "stm32_spi.h" +#include "vs1053b.h" + +#include "flash_driver.h" +#include "extflash_driver.h" + +#include "board.h" +#include "boards/generic_stm32/module_ports.h" +#include "boards/generic_stm32/rgb_leds.h" +#include "bsp_io.h" + +#include "hal/adc_driver.h" +#include "hal/trainer_driver.h" +#include "hal/rotary_encoder.h" +#include "hal/switch_driver.h" +#include "hal/abnormal_reboot.h" +#include "hal/watchdog_driver.h" +#include "hal/usb_driver.h" +#include "hal/gpio.h" + +#include "globals.h" +#include "sdcard.h" +#include "debug.h" + +#include "flysky_gimbal_driver.h" +#include "timers_driver.h" + +#include "battery_driver.h" + +#include "bitmapbuffer.h" +#include "colors.h" + + +#include "touch_driver.h" + +#include + +// common ADC driver +extern const etx_hal_adc_driver_t _adc_driver; + +// RGB LED timer +extern const stm32_pulse_timer_t _led_timer; + +#if defined(SEMIHOSTING) +extern "C" void initialise_monitor_handles(); +#endif + +#if defined(SPI_FLASH) +extern "C" void flushFTL(); +#endif + +static void led_strip_charge_animation(uint8_t ledOn) +{ + for (uint8_t i = 0; i < LED_STRIP_LENGTH; i++) { + if (i == ledOn) + ws2812_set_color(i, 10, 10, 10); + else + ws2812_set_color(i, 0, 0, 0); + } + ws2812_update(&_led_timer); +} + +static void led_strip_off() +{ + for (uint8_t i = 0; i < LED_STRIP_LENGTH; i++) { + ws2812_set_color(i, 0, 0, 0); + } + ws2812_update(&_led_timer); +} + +void INTERNAL_MODULE_ON() +{ + bsp_output_clear(BSP_INT_PWR); +} + +void INTERNAL_MODULE_OFF() +{ + bsp_output_set(BSP_INT_PWR); +} + +void EXTERNAL_MODULE_ON() +{ + bsp_output_clear(BSP_EXT_PWR); +} + +void EXTERNAL_MODULE_OFF() +{ + bsp_output_set(BSP_EXT_PWR); +} + +static stm32_spi_t audioSpi = +{ + .SPIx = AUDIO_SPI, + .SCK = AUDIO_SPI_SCK_GPIO, + .MISO = AUDIO_SPI_MISO_GPIO, + .MOSI = AUDIO_SPI_MOSI_GPIO, + .CS = AUDIO_CS_GPIO, +}; + +static void audio_set_rst_pin(bool set) +{ + if (set) { + bsp_output_set(BSP_AUDIO_RST); + } else { + bsp_output_clear(BSP_AUDIO_RST); + } +} + +static void audio_set_mute_pin(bool set) +{ +#if defined(INVERTED_MUTE_PIN) + set = !set; +#endif + if (set) { + bsp_output_set(BSP_PA_NMUTE); + } else { + bsp_output_clear(BSP_PA_NMUTE); + } +} + +static vs1053b_t audioConfig = +{ + .spi = &audioSpi, + .XDCS = AUDIO_XDCS_GPIO, + .DREQ = AUDIO_DREQ_GPIO, + .set_rst_pin = audio_set_rst_pin, + .set_mute_pin = audio_set_mute_pin, + .mute_delay_ms = AUDIO_MUTE_DELAY, + .unmute_delay_ms = AUDIO_UNMUTE_DELAY, +}; + +void audioInit(){ + // assume BSP IO is already init + vs1053b_init(&audioConfig); +} + +void boardBLEarlyInit() +{ + timersInit(); + bsp_io_init(); +} + +void boardBLPreJump() +{ + ExtFLASH_Init(); + SDRAM_Init(); + + // Stop 1ms timer + MS_TIMER->CR1 &= ~TIM_CR1_CEN; +} + +void boardBLInit() +{ + ExtFLASH_Init(); + SDRAM_Init(); + + // register external FLASH for DFU + usbRegisterDFUMedia((void*)extflash_dfu_media); + + // register internal & external FLASH for UF2 + flashRegisterDriver(FLASH_BANK1_BASE, BOOTLOADER_SIZE, &stm32_flash_driver); + flashRegisterDriver(QSPI_BASE, 8 * 1024 * 1024, &extflash_driver); +} + +void boardInit() +{ + // enable interrupts + __enable_irq(); + +#if defined(DEBUG) + serialSetMode(SP_AUX1, UART_MODE_DEBUG); // indicate AUX1 is used + serialInit(SP_AUX1, UART_MODE_DEBUG); // early AUX1 init +#endif + + boardInitModulePorts(); + + pwrInit(); + delaysInit(); + timersInit(); + + bsp_io_init(); + bsp_output_set(BSP_PWR_LED); + + ExtFLASH_InitRuntime(); + + // register internal & external FLASH for UF2 + flashRegisterDriver(FLASH_BANK1_BASE, BOOTLOADER_SIZE, &stm32_flash_driver); + flashRegisterDriver(QSPI_BASE, QSPI_FLASH_SIZE, &extflash_driver); + + // init_trainer(); + flysky_gimbal_init(); + + usbInit(); + +#if defined(LED_STRIP_GPIO) + rgbLedInit(); +#endif + +#if !defined(DEBUG_SEGGER_RTT) + // prime debounce state... + usbPlugged(); + + if (usbPlugged()) { + delaysInit(); + uint8_t ledOn = 0; + while (usbPlugged()) { + if(IS_UCHARGER_ACTIVE()) { + led_strip_charge_animation(ledOn++); + if (ledOn == LED_STRIP_LENGTH) + ledOn = 0; + } + else { + led_strip_off(); + } + delay_ms(1000); + } + while(1) // Wait power to drain + boardOff(); + } +#endif + + led_strip_off(); + + // uint32_t press_start = 0; + // uint32_t press_end = 0; + + // if (UNEXPECTED_SHUTDOWN()) { + pwrOn(); + // } else if (isChargerActive()) { + // while (true) { + // pwrOn(); + // uint32_t now = get_tmr10ms(); + // if (pwrPressed()) { + // press_end = now; + // if (press_start == 0) press_start = now; + // if ((now - press_start) > POWER_ON_DELAY) { + // break; + // } + // } else if (!isChargerActive()) { + // boardOff(); + // } else { + // uint32_t press_end_touch = press_end; + // press_start = 0; + // handle_battery_charge(press_end_touch); + // delay_ms(10); + // press_end = 0; + // } + // } + // } + + keysInit(); + switchInit(); + rotaryEncoderInit(); + touchPanelInit(); + audioInit(); + adcInit(&_adc_driver); + hapticInit(); + +#if defined(RTCLOCK) + rtcInit(); // RTC must be initialized before rambackupRestore() is called +#endif + + lcdSetInitalFrameBuffer(lcdFront->getData()); +} + +extern void rtcDisableBackupReg(); + +void boardOff() +{ + lcdOff(); + + while (pwrPressed()) { + WDG_RESET(); + } + + SysTick->CTRL = 0; // turn off systick + + // Shutdown the Haptic + hapticDone(); + + rtcDisableBackupReg(); + +// RTC->BKP0R = SHUTDOWN_REQUEST; + pwrOff(); + + // We reach here only in forced power situations, such as hw-debugging with external power + // Enter STM32 stop mode / deep-sleep + // Code snippet from ST Nucleo PWR_EnterStopMode example +#define PDMode 0x00000000U +#if defined(PWR_CR1_MRUDS) && defined(PWR_CR1_LPUDS) && defined(PWR_CR1_FPDS) + MODIFY_REG(PWR->CR1, (PWR_CR1_PDDS | PWR_CR1_LPDS | PWR_CR1_FPDS | PWR_CR1_LPUDS | PWR_CR1_MRUDS), PDMode); +#elif defined(PWR_CR_MRLVDS) && defined(PWR_CR_LPLVDS) && defined(PWR_CR_FPDS) + MODIFY_REG(PWR->CR1, (PWR_CR1_PDDS | PWR_CR1_LPDS | PWR_CR1_FPDS | PWR_CR1_LPLVDS | PWR_CR1_MRLVDS), PDMode); +#else +// MODIFY_REG(PWR->CR1, (PWR_CR1_P_PDDS| PWR_CR1_LPDS), PDMode); +#endif /* PWR_CR_MRUDS && PWR_CR_LPUDS && PWR_CR_FPDS */ + +/* Set SLEEPDEEP bit of Cortex System Control Register */ + SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk)); + + // To avoid HardFault at return address, end in an endless loop + while (1) { + + } +} +/* +int usbPlugged() +{ + static uint8_t debouncedState = 0; + static uint8_t lastState = 0; + + uint8_t state = gpio_read(UCHARGER_GPIO); + + if (state == lastState) + debouncedState = state; + else + lastState = state; + + return debouncedState||1; +} +*/ + +// extern "C" void * memcpy(void* dst, const void*src, size_t count) +// { +// uint8_t* d = (uint8_t*)dst; +// const uint8_t* s = (const uint8_t*)src; +// while(count--) +// *d++ = *s++; +// return dst; +// } diff --git a/radio/src/targets/st16/board.h b/radio/src/targets/st16/board.h new file mode 100644 index 000000000..0fb93d33f --- /dev/null +++ b/radio/src/targets/st16/board.h @@ -0,0 +1,249 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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. + */ + +#pragma once + +#include "definitions.h" +#include "edgetx_constants.h" + +#include "board_common.h" +#include "hal.h" +#include "hal/serial_port.h" +#include "hal/watchdog_driver.h" + +#define FLASHSIZE 0x800000 +#define FLASH_PAGESIZE 256 +#define BOOTLOADER_SIZE 0x10000 +#define BOOTLOADER_ADDRESS 0x08000000 +#define FIRMWARE_ADDRESS 0x90000000 +#define FIRMWARE_LEN(fsize) (fsize) +#define FIRMWARE_MAX_LEN FLASHSIZE +#define APP_START_ADDRESS (uint32_t)(FIRMWARE_ADDRESS) + +#define BOOTLOADER_KEYS 0x42 + +#define MB *1024*1024 +#define LUA_MEM_EXTRA_MAX (2 MB) // max allowed memory usage for Lua bitmaps (in bytes) +#define LUA_MEM_MAX (6 MB) // max allowed memory usage for complete Lua (in bytes), 0 means unlimited + +extern uint16_t sessionTimer; + +#define SLAVE_MODE() (g_model.trainerData.mode == TRAINER_MODE_SLAVE) + +// Board driver +void boardInit(); +void boardOff(); + +// CPU Unique ID +#define LEN_CPU_UID (3*8+2) +void getCPUUniqueID(char * s); + +// Flash Write driver +#define FLASH_PAGESIZE 256 +void unlockFlash(); +void lockFlash(); +void flashWrite(uint32_t * address, const uint32_t * buffer); +uint32_t isFirmwareStart(const uint8_t * buffer); +uint32_t isBootloaderStart(const uint8_t * buffer); + +// SDRAM driver +extern "C" void SDRAM_Init(); + +// Pulses driver +#if !defined(SIMU) + +void INTERNAL_MODULE_ON(); /*gpio_set(INTMODULE_PWR_GPIO)*/ +void INTERNAL_MODULE_OFF(); /*gpio_clear(INTMODULE_PWR_GPIO);*/ +void EXTERNAL_MODULE_ON(); /*gpio_set(EXTMODULE_PWR_GPIO)*/ +void EXTERNAL_MODULE_OFF(); /*gpio_clear(EXTMODULE_PWR_GPIO)*/ +#define EXTERNAL_MODULE_PWR_OFF EXTERNAL_MODULE_OFF +#define BLUETOOTH_MODULE_ON() gpio_clear(BLUETOOTH_ON_GPIO) +#define BLUETOOTH_MODULE_OFF() gpio_set(BLUETOOTH_ON_GPIO) +#define IS_INTERNAL_MODULE_ON() (false) +#define IS_EXTERNAL_MODULE_ON() (GPIO_ReadInputDataBit(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN) == Bit_SET) + +#else + +#define INTERNAL_MODULE_OFF() +#define INTERNAL_MODULE_ON() +#define EXTERNAL_MODULE_ON() +#define EXTERNAL_MODULE_OFF() +#define BLUETOOTH_MODULE_ON() +#define BLUETOOTH_MODULE_OFF() +#define IS_INTERNAL_MODULE_ON() (false) +#define IS_EXTERNAL_MODULE_ON() (false) + +#endif // defined(SIMU) + +#if defined(FUNCTION_SWITCHES) +#define NUM_FUNCTIONS_SWITCHES 6 +#define NUM_FUNCTIONS_GROUPS 3 +#define DEFAULT_FS_CONFIG \ + (SWITCH_2POS << 10) + (SWITCH_2POS << 8) + (SWITCH_2POS << 6) + \ + (SWITCH_2POS << 4) + (SWITCH_2POS << 2) + (SWITCH_2POS << 0) + +#define DEFAULT_FS_GROUPS \ + (1 << 10) + (1 << 8) + (1 << 6) + (1 << 4) + (1 << 2) + \ + (1 << 0) // Set all FS to group 1 to act like a 6pos + +#define DEFAULT_FS_STARTUP_CONFIG \ + ((FS_START_PREVIOUS << 10) + (FS_START_PREVIOUS << 8) + \ + (FS_START_PREVIOUS << 6) + (FS_START_PREVIOUS << 4) + \ + (FS_START_PREVIOUS << 2) + \ + (FS_START_PREVIOUS << 0)) // keep last state by default + +#else +#define NUM_FUNCTIONS_SWITCHES 0 +#endif + +#define NUM_TRIMS 8 +#define DEFAULT_STICK_DEADZONE 2 + +#define BATTERY_WARN 74 // 7.4V +#define BATTERY_MIN 70 // 6.8V +#define BATTERY_MAX 86 // 8.6V +#define BATTERY_DIVIDER 2323 + +#if defined(__cplusplus) && !defined(SIMU) +extern "C" { +#endif + +// Power driver +#define SOFT_PWR_CTRL +#define POWER_ON_DELAY 10 // 1s +void pwrInit(); +void extModuleInit(); +uint32_t pwrCheck(); +uint32_t lowPowerCheck(); + +void pwrOn(); +void pwrSoftReboot(); +void pwrOff(); +void pwrResetHandler(); +bool pwrPressed(); +bool pwrOffPressed(); +#if defined(PWR_EXTRA_SWITCH_GPIO) + bool pwrForcePressed(); +#else + #define pwrForcePressed() false +#endif +uint32_t pwrPressedDuration();; + +const etx_serial_port_t* auxSerialGetPort(int port_nr); +#define AUX_SERIAL_POWER_ON() +#define AUX_SERIAL_POWER_OFF() + +// LED driver +void ledInit(); +void ledOff(); +void ledRed(); +void ledBlue(); +void ledGreen(); + +// LCD driver +void lcdSetInitalFrameBuffer(void* fbAddress); +void lcdInit(); +void lcdCopy(void * dest, void * src); + +void lcdOff(); +void lcdOn(); + +#define lcdRefreshWait(...) + +// Backlight driver +#define BACKLIGHT_LEVEL_MAX 100 +#define BACKLIGHT_FORCED_ON BACKLIGHT_LEVEL_MAX + 1 +#define BACKLIGHT_LEVEL_MIN 1 + +extern bool boardBacklightOn; +void backlightLowInit( void ); +void backlightInit(); +void backlightEnable(uint8_t dutyCycle); +void backlightFullOn(); +bool isBacklightEnabled(); + +#define BACKLIGHT_ENABLE() \ + { \ + boardBacklightOn = true; \ + backlightEnable(BACKLIGHT_LEVEL_MAX - currentBacklightBright); \ + } + +#define BACKLIGHT_DISABLE() \ + { \ + boardBacklightOn = false; \ + backlightEnable(((g_eeGeneral.blOffBright == BACKLIGHT_LEVEL_MIN) && \ + (g_eeGeneral.backlightMode != e_backlight_mode_off)) \ + ? 0 \ + : g_eeGeneral.blOffBright); \ + } + +#define USB_NAME "ST16" +#define USB_MANUFACTURER 'F', 'l', 'y', 'S', 'k', 'y', ' ', ' ' /* 8 bytes */ +#define USB_PRODUCT 'S', 'T', '1', '6', ' ', ' ', ' ', ' ' /* 8 Bytes */ + +#if defined(__cplusplus) && !defined(SIMU) +} +#endif + +// Audio driver +class stm32_spi_t; +struct AudioConfig_t +{ + stm32_spi_t* spi; + void (*setMuteHigh)(); + void (*setMuteLow)(); + void (*setResetHigh)(); + void (*setResetLow)(); +}; +void audioInit(const AudioConfig_t* cfg); +void audioConsumeCurrentBuffer(); + +#define audioDisableIrq() // interrupts must stay enabled on Horus +#define audioEnableIrq() // interrupts must stay enabled on Horus +#define setSampleRate(freq) +void setScaledVolume(uint8_t volume); +void setVolume(uint8_t volume); +int32_t getVolume(); +#define VOLUME_LEVEL_MAX 23 +#define VOLUME_LEVEL_DEF 12 + +// Telemetry driver +#define INTMODULE_FIFO_SIZE 512 +#define TELEMETRY_FIFO_SIZE 512 + +// Haptic driver +void hapticInit(); +void hapticDone(); +void hapticOff(); +void hapticOn(uint32_t pwmPercent); + +// Second serial port driver +//#define AUX_SERIAL +#define DEBUG_BAUDRATE 115200 +#define LUA_DEFAULT_BAUDRATE 115200 + +extern uint8_t currentTrainerMode; +void checkTrainerSettings(); + +// Touch panel driver +bool touchPanelEventOccured(); +struct TouchState touchPanelRead(); +struct TouchState getInternalTouchState(); diff --git a/radio/src/targets/st16/bootloader/boot_menu.cpp b/radio/src/targets/st16/bootloader/boot_menu.cpp new file mode 100644 index 000000000..4a8a9ad35 --- /dev/null +++ b/radio/src/targets/st16/bootloader/boot_menu.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "board.h" +#include "bsp_io.h" +#include "fw_version.h" +#include "lcd.h" +#include "bitmapbuffer.h" + +#include "translations.h" + +#include "targets/common/arm/stm32/bootloader/boot.h" + +#include + +// #define USB_SW_TO_INTERNAL_MODULE() bsp_output_set(BSP_USB_SW); +// #define USB_SW_TO_MCU() bsp_output_clear(BSP_USB_SW); + +#define SELECTED_COLOR (INVERS | COLOR_THEME_SECONDARY1) +#define DEFAULT_PADDING 28 +#define DOUBLE_PADDING 56 +#define MESSAGE_TOP (LCD_H - (2*DOUBLE_PADDING)) + +#define BL_GREEN COLOR2FLAGS(RGB(73, 219, 62)) +#define BL_RED COLOR2FLAGS(RGB(229, 32, 30)) +#define BL_BACKGROUND COLOR_BLACK +#define BL_FOREGROUND COLOR_WHITE +#define BL_SELECTED COLOR2FLAGS(RGB(11, 65, 244)) // deep blue + +extern BitmapBuffer* lcd; + +// static bool rfUsbAccess = false; + +void bootloaderInitScreen() +{ + lcdInitDisplayDriver(); + backlightInit(); + backlightEnable(100); +} + +static void bootloaderDrawTitle(const char* text) +{ + lcd->drawText(LCD_W / 2, DEFAULT_PADDING, text, CENTERED | BL_FOREGROUND); + lcd->drawSolidFilledRect(DEFAULT_PADDING, DOUBLE_PADDING, + LCD_W - DOUBLE_PADDING, 2, BL_FOREGROUND); +} + +static void bootloaderDrawFooter() +{ + lcd->drawSolidFilledRect(DEFAULT_PADDING, LCD_H - (DEFAULT_PADDING + 10), + LCD_W - DOUBLE_PADDING, 2, BL_FOREGROUND); +} + +static void bootloaderDrawBackground() { lcd->clear(BL_BACKGROUND); } + +void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) +{ + lcdInitDirectDrawing(); + bootloaderDrawBackground(); + bootloaderDrawTitle(BOOTLOADER_TITLE); + + if (st == ST_START || st == ST_USB) { + + const char* msg = nullptr; + if (st == ST_START) { + msg = "Plug USB cable"; + } else if (st == ST_USB) { + msg = "Copy firmware.uf2 to flash"; + } + + coord_t x = LCD_W/2; + coord_t y = LCD_H/2; + lcd->drawText(x, y, msg, CENTERED | BL_FOREGROUND); + + bootloaderDrawFooter(); + + const char* fw_ver = getFirmwareVersion(); + if (!fw_ver) fw_ver = "no version"; + lcd->drawText(x, LCD_H - DEFAULT_PADDING, fw_ver, + CENTERED | BL_FOREGROUND); + + } else if (st == ST_FLASHING || st == ST_FLASH_DONE) { + + const coord_t pb_h = 31; + const coord_t pb_x = 70; + const coord_t pb_y = (LCD_H - pb_h) / 2; + + const char* msg = (st == ST_FLASH_DONE) ? TR_BL_WRITING_COMPL : TR_BL_WRITING_FW; + lcd->drawText(pb_x, pb_y - 28, msg, BL_FOREGROUND); + lcd->drawRect(pb_x, pb_y, 340, pb_h, 2, SOLID, BL_SELECTED); + + LcdFlags color = (st == ST_FLASH_DONE) ? BL_GREEN : BL_RED; + lcd->drawSolidFilledRect(pb_x + 4, pb_y + 4, (332 * opt) / 100, 23, color); + } +} + +void bootloaderDrawDFUScreen() +{ + lcdInitDirectDrawing(); + bootloaderDrawBackground(); + lcd->drawText(LCD_W / 2, LCD_H / 2, "DFU mode", CENTERED | BL_FOREGROUND); +} + +void blExit(void) +{ + lcdClear(); + lcdRefresh(); + lcdRefreshWait(); +} diff --git a/radio/src/targets/st16/bsp_io.cpp b/radio/src/targets/st16/bsp_io.cpp new file mode 100644 index 000000000..db2d565f1 --- /dev/null +++ b/radio/src/targets/st16/bsp_io.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) EdgeTx + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "bsp_io.h" + +#include "drivers/pca95xx.h" +#include "stm32_i2c_driver.h" +#include "stm32_switch_driver.h" + +#define BSP_IN_I2C_BUS I2C_Bus_2 +#define BSP_IN_I2C_ADDR 0x20 + +#define BSP_IN_MASK 0xFFFF + +#define BSP_OUT_I2C_BUS I2C_Bus_2 +#define BSP_OUT_I2C_ADDR 0x21 + +#define BSP_OUT_MASK \ + (PCA95XX_PIN_0 | PCA95XX_PIN_1 | PCA95XX_PIN_2 | PCA95XX_PIN_3 | \ + PCA95XX_PIN_4 | PCA95XX_PIN_5 | PCA95XX_PIN_6 | PCA95XX_PIN_7 | \ + PCA95XX_PIN_8 | PCA95XX_PIN_9 | PCA95XX_PIN_10) + +#define BSP_CHECK(x) \ + if ((x) < 0) return -1 + +static pca95xx_t output_exp; +static pca95xx_t input_exp; + +static uint16_t inputState = 0; +static bool updateInputState = false; + +void bsp_port_extender_irq_handler() { updateInputState = true; } + +static void bsp_input_read() +{ + // this is a fall back, the interrupts from the port extender + // are unreliable under some circumstances + static int readCount = 0; + readCount++; + + if (!updateInputState && readCount < 50) return; + + uint16_t value=0; + + readCount=0; + updateInputState = false; + + if (pca95xx_read(&input_exp, BSP_IN_MASK, &value) < 0) return; + inputState = value; +} + +int bsp_io_init() +{ + // init outputs + BSP_CHECK(pca95xx_init(&output_exp, BSP_OUT_I2C_BUS, BSP_OUT_I2C_ADDR)); + BSP_CHECK(pca95xx_write(&output_exp, BSP_OUT_MASK, + BSP_CHARGE_EN | BSP_EXT_PWR | BSP_INT_PWR)); + BSP_CHECK(pca95xx_set_direction(&output_exp, BSP_OUT_MASK, 0)); + + // init inputs + BSP_CHECK(pca95xx_init(&input_exp, BSP_IN_I2C_BUS, BSP_IN_I2C_ADDR)); + + gpio_init_int(GPIO_PIN(GPIOH, 6), GPIO_IN, GPIO_FALLING, + bsp_port_extender_irq_handler); + updateInputState = true; + bsp_input_read(); + + return 0; +} + +void bsp_output_set(uint16_t pin) { pca95xx_write(&output_exp, pin, pin); } + +void bsp_output_clear(uint16_t pin) { pca95xx_write(&output_exp, pin, 0); } + +uint16_t bsp_input_get() +{ + bsp_input_read(); + return inputState; +} + +SwitchHwPos bsp_get_switch_position(const stm32_switch_t *sw, + SwitchCategory cat, uint8_t idx) +{ + bool val = false; + uint16_t pins = bsp_input_get(); + + if (cat == SWITCH_PHYSICAL) { + switch (idx) { + case 6: + val = (pins & BSP_BACK_KEY1) != 0; + break; + case 7: + val = (pins & BSP_BACK_KEY2) != 0; + break; + } + } else if (cat == SWITCH_FUNCTION) { + switch (idx) { + case 0: + val = (pins & BSP_EXT_KEY1) != 0; + break; + case 1: + val = (pins & BSP_EXT_KEY2) != 0; + break; + case 2: + val = (pins & BSP_EXT_KEY3) != 0; + break; + case 3: + val = (pins & BSP_EXT_KEY4) != 0; + break; + case 4: + val = (pins & BSP_EXT_KEY5) != 0; + break; + case 5: + val = (pins & BSP_EXT_KEY6) != 0; + break; + } + } + + if (sw->flags & SWITCH_HW_INVERTED) val = !val; + + return val ? SWITCH_HW_UP : SWITCH_HW_DOWN; +} diff --git a/radio/src/targets/st16/bsp_io.h b/radio/src/targets/st16/bsp_io.h new file mode 100644 index 000000000..c01f33524 --- /dev/null +++ b/radio/src/targets/st16/bsp_io.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) EdgeTx + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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. + */ + +#pragma once + +#include "drivers/pca95xx.h" +#include "hal/switch_driver.h" + +// Input port expander +#define BSP_EXT_KEY1 PCA95XX_PIN_0 +#define BSP_EXT_KEY2 PCA95XX_PIN_1 +#define BSP_EXT_KEY3 PCA95XX_PIN_2 +#define BSP_EXT_KEY4 PCA95XX_PIN_3 +#define BSP_EXT_KEY5 PCA95XX_PIN_4 +#define BSP_EXT_KEY6 PCA95XX_PIN_5 + +#define BSP_BACK_KEY1 PCA95XX_PIN_6 +#define BSP_BACK_KEY2 PCA95XX_PIN_7 + +#define BSP_TR1U PCA95XX_PIN_8 +#define BSP_TR1D PCA95XX_PIN_9 +#define BSP_TR3L PCA95XX_PIN_10 +#define BSP_TR3R PCA95XX_PIN_11 +#define BSP_TR2U PCA95XX_PIN_12 +#define BSP_TR2D PCA95XX_PIN_13 +#define BSP_TR4L PCA95XX_PIN_14 +#define BSP_TR4R PCA95XX_PIN_15 + +// Output port expander +#define BSP_AUDIO_RST PCA95XX_PIN_0 +#define BSP_PA_NMUTE PCA95XX_PIN_1 +#define BSP_INT_PWR PCA95XX_PIN_2 +#define BSP_EXT_PWR PCA95XX_PIN_3 +#define BSP_CHARGE_EN PCA95XX_PIN_4 +#define BSP_LCD_NRST PCA95XX_PIN_5 +#define BSP_USB_SW PCA95XX_PIN_6 +#define BSP_PWR_LED PCA95XX_PIN_7 +#define BSP_LCD_CS PCA95XX_PIN_8 +#define BSP_RF_BOOT0 PCA95XX_PIN_9 +#define BSP_USB_SWB PCA95XX_PIN_10 + +int bsp_io_init(); + +void bsp_output_set(uint16_t pin); +void bsp_output_clear(uint16_t pin); + +uint16_t bsp_input_get(); +struct stm32_switch_t; +SwitchHwPos bsp_get_switch_position(const stm32_switch_t *sw, SwitchCategory cat, uint8_t idx); + diff --git a/radio/src/targets/st16/extflash_driver.cpp b/radio/src/targets/st16/extflash_driver.cpp new file mode 100644 index 000000000..2354db468 --- /dev/null +++ b/radio/src/targets/st16/extflash_driver.cpp @@ -0,0 +1,154 @@ +#include "extflash_driver.h" + +#include "stm32_hal.h" +#include "stm32_qspi.h" + +#include "board.h" + +#define QSPI_NOR_PAGE_SIZE 256 + +int32_t ExtFLASH_Init() +{ + if (stm32_qspi_nor_init() != 0) { + return -1; + } + + return stm32_qspi_nor_memory_mapped(); +} + +void ExtFLASH_InitRuntime() { stm32_qspi_no_init_runtime(); } + +// +// ETX HAL flash interface +// + +static uint32_t extflash_get_size_kb() +{ + return QSPI_FLASH_SIZE / 1024; +} + +static uint32_t extflash_get_sector(uint32_t address) +{ + address -= QSPI_BASE; + return address / (64 * 1024); +} + +static uint32_t extflash_get_sector_size(uint32_t sector) +{ + (void)sector; + return (64 * 1024); +} + +static int extflash_erase_sector(uint32_t address) +{ + address -= QSPI_BASE; + return stm32_qspi_nor_erase_sector(address); +} + +static int extflash_program(uint32_t address, void* data, uint32_t len) +{ + address -= QSPI_BASE; + + int ret = 0; + while (len > 0) { + uint32_t size = (len > QSPI_NOR_PAGE_SIZE) ? QSPI_NOR_PAGE_SIZE : len; + ret = stm32_qspi_nor_program(address, data, size); + if (ret != 0) break; + len -= size; + address += size; + data = (uint8_t*)data + size; + } + + return ret; +} + +static int extflash_read(uint32_t address, void* data, uint32_t len) +{ + address -= QSPI_BASE; + return stm32_qspi_nor_read(address, data, len); +} + +const etx_flash_driver_t extflash_driver = { + .get_size_kb = extflash_get_size_kb, + .get_sector = extflash_get_sector, + .get_sector_size = extflash_get_sector_size, + .erase_sector = extflash_erase_sector, + .program = extflash_program, + .read = extflash_read, +}; + +#if defined(BOOT) +// +// USB DFU interface +// +#include "usbd_dfu.h" + +#define MEDIA_DESC_STR "@External Flash /0x90000000/128*064Kg" + +static uint16_t extflash_dfu_init() +{ + return USBD_OK; +} + +static uint16_t extflash_dfu_deinit() +{ + return USBD_OK; +} + +static uint16_t extflash_dfu_erase(uint32_t address) +{ + if (extflash_erase_sector(address) < 0) { + return USBD_FAIL; + } + return USBD_OK; +} + +static uint16_t extflash_dfu_write(uint8_t* src, uint8_t* dest, uint32_t len) +{ + if (extflash_program((intptr_t)dest, (void*)src, len) < 0) { + return USBD_FAIL; + } + return USBD_OK; +} + +static uint8_t* extflash_dfu_read(uint8_t* src, uint8_t* dest, uint32_t len) +{ + if (extflash_read((intptr_t)src, (void*)dest, len) < 0) { + return nullptr; + } + return dest; +} + +static uint16_t extflash_dfu_get_status(uint32_t address, uint8_t cmd, uint8_t *buffer) +{ + switch (cmd) { + case DFU_MEDIA_PROGRAM: + buffer[1] = 1; + buffer[2] = 0; + buffer[3] = 0; + break; + + case DFU_MEDIA_ERASE: + default: + buffer[1] = 20; + buffer[2] = 0; + buffer[3] = 0; + break; + } + + return USBD_OK; +} + +const USBD_DFU_MediaTypeDef _extflash_dfu_media = { + .pStrDesc = (uint8_t*)MEDIA_DESC_STR, + .Init = extflash_dfu_init, + .DeInit = extflash_dfu_deinit, + .Erase = extflash_dfu_erase, + .Write = extflash_dfu_write, + .Read = extflash_dfu_read, + .GetStatus = extflash_dfu_get_status, +}; + +const void* extflash_dfu_media = &_extflash_dfu_media; + +#endif // BOOT diff --git a/radio/src/targets/st16/extflash_driver.h b/radio/src/targets/st16/extflash_driver.h new file mode 100644 index 000000000..c51d6a3aa --- /dev/null +++ b/radio/src/targets/st16/extflash_driver.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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. + */ + +#pragma once + +#include "hal/flash_driver.h" + +extern const etx_flash_driver_t extflash_driver; +extern const void* extflash_dfu_media; + +// init external FLASH hardware +int32_t ExtFLASH_Init(); + +// init only runtime structures +void ExtFLASH_InitRuntime(); diff --git a/radio/src/targets/st16/extmodule_helper.cpp b/radio/src/targets/st16/extmodule_helper.cpp new file mode 100644 index 000000000..dbb02e90b --- /dev/null +++ b/radio/src/targets/st16/extmodule_helper.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "board.h" + +void EXTERNAL_MODULE_ON() +{ + GPIO_SetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN); +} + +void EXTERNAL_MODULE_OFF() +{ + GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN); +} + +void extModuleInit() +{ + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = EXTMODULE_TX_INVERT_GPIO_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(EXTMODULE_TX_INVERT_GPIO, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Pin = EXTMODULE_RX_INVERT_GPIO_PIN; + GPIO_Init(EXTMODULE_RX_INVERT_GPIO, &GPIO_InitStructure); + + EXTMODULE_TX_INVERTED(); + EXTMODULE_RX_INVERTED(); +} diff --git a/radio/src/targets/st16/hal.h b/radio/src/targets/st16/hal.h new file mode 100644 index 000000000..39e4185a6 --- /dev/null +++ b/radio/src/targets/st16/hal.h @@ -0,0 +1,526 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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. + */ + +#pragma once + +#define CPU_FREQ 400000000 + +#define PERI1_FREQUENCY 100000000 +#define PERI2_FREQUENCY 100000000 +#define TIMER_MULT_APB1 2 +#define TIMER_MULT_APB2 2 + +// Keys +#define KEYS_GPIO_REG_ENTER GPIOG +#define KEYS_GPIO_PIN_ENTER LL_GPIO_PIN_14 // PG.14 +#define KEYS_GPIO_REG_PAGEDN GPIOA +#define KEYS_GPIO_PIN_PAGEDN LL_GPIO_PIN_8 // PA.08 +#define KEYS_GPIO_REG_EXIT GPIOC +#define KEYS_GPIO_PIN_EXIT LL_GPIO_PIN_5 // PC.05 + +// Trims +#define TRIMS_GPIO_REG_LHL +#define TRIMS_GPIO_PIN_LHL + +#define TRIMS_GPIO_REG_LHR +#define TRIMS_GPIO_PIN_LHR + +#define TRIMS_GPIO_REG_LVD +#define TRIMS_GPIO_PIN_LVD + +#define TRIMS_GPIO_REG_LVU +#define TRIMS_GPIO_PIN_LVU + +#define TRIMS_GPIO_REG_RHL +#define TRIMS_GPIO_PIN_RHL + +#define TRIMS_GPIO_REG_RHR +#define TRIMS_GPIO_PIN_RHR + +#define TRIMS_GPIO_REG_RVD +#define TRIMS_GPIO_PIN_RVD + +#define TRIMS_GPIO_REG_RVU +#define TRIMS_GPIO_PIN_RVU + + +// function switches +#define FUNCTION_SWITCH_1 I2C +#define FUNCTION_SWITCH_2 I2C +#define FUNCTION_SWITCH_3 I2C +#define FUNCTION_SWITCH_4 I2C +#define FUNCTION_SWITCH_5 I2C +#define FUNCTION_SWITCH_6 I2C + +// Direct switches + +// Key 1 +#define STORAGE_SWITCH_G +#define HARDWARE_SWITCH_G +#define SWITCHES_G_2POS +//#define SWITCHES_GPIO_REG_G GPIOI +//#define SWITCHES_GPIO_PIN_G LL_GPIO_PIN_3 // PI.03 + +// Key 2 +#define STORAGE_SWITCH_H +#define HARDWARE_SWITCH_H +#define SWITCHES_H_2POS +//#define SWITCHES_GPIO_REG_H GPIOI +//#define SWITCHES_GPIO_PIN_H LL_GPIO_PIN_11 // PI.11 + + +// Key 3 +#define STORAGE_SWITCH_I +#define HARDWARE_SWITCH_I +#define SWITCHES_GPIO_REG_I GPIOI +#define SWITCHES_GPIO_PIN_I LL_GPIO_PIN_3 // PI.03 + +// Key 4 +#define STORAGE_SWITCH_J +#define HARDWARE_SWITCH_J +#define SWITCHES_GPIO_REG_J GPIOI +#define SWITCHES_GPIO_PIN_J LL_GPIO_PIN_11 // PI.11 + + +// ADC +#define ADC_GPIO_PIN_STICK_LH LL_GPIO_PIN_0 // PA.00 +#define ADC_GPIO_PIN_STICK_LV LL_GPIO_PIN_1 // PA.01 +#define ADC_GPIO_PIN_STICK_RV LL_GPIO_PIN_2 // PA.02 +#define ADC_GPIO_PIN_STICK_RH LL_GPIO_PIN_3 // PA.03 + +#define ADC_GPIO_PIN_POT1 LL_GPIO_PIN_6 // PA.06 VRA +#define ADC_GPIO_PIN_POT2 LL_GPIO_PIN_1 // PB.01 VRB +#define ADC_GPIO_PIN_SLIDER1 LL_GPIO_PIN_0 // PB.00 VRC/LS +#define ADC_GPIO_PIN_SLIDER2 LL_GPIO_PIN_7 // PA.07 VRD/RS + +// If serial gimbals are used, we can reuse the channels +#define ADC_GPIO_PIN_EXT1 LL_GPIO_PIN_0 // PA.00 EXT1 +#define ADC_GPIO_PIN_EXT2 LL_GPIO_PIN_1 // PA.01 EXT2 +#define ADC_GPIO_PIN_EXT3 LL_GPIO_PIN_2 // PA.02 EXT3 +#define ADC_GPIO_PIN_EXT4 LL_GPIO_PIN_3 // PA.03 EXT4 + +#define ADC_GPIO_PIN_SWA LL_GPIO_PIN_2 // PC.02_C +#define ADC_GPIO_PIN_SWB LL_GPIO_PIN_3 // PC.03_C +#define ADC_GPIO_PIN_SWC LL_GPIO_PIN_9 // PF.09 +#define ADC_GPIO_PIN_SWD LL_GPIO_PIN_7 // PF.07 +#define ADC_GPIO_PIN_SWE LL_GPIO_PIN_8 // PF.08 +#define ADC_GPIO_PIN_SWF LL_GPIO_PIN_6 // PF.06 + +#define ADC_GPIO_PIN_BATT LL_GPIO_PIN_1 // PC.01 + +#define ADC_GPIOA_PINS \ + (ADC_GPIO_PIN_POT1 | ADC_GPIO_PIN_SLIDER2 | ADC_GPIO_PIN_STICK_LH | \ + ADC_GPIO_PIN_STICK_LV | ADC_GPIO_PIN_STICK_RH | ADC_GPIO_PIN_STICK_RV) + +#define ADC_GPIOB_PINS (ADC_GPIO_PIN_POT2 | ADC_GPIO_PIN_SLIDER1) + +#define ADC_GPIOC_PINS (ADC_GPIO_PIN_SWA | ADC_GPIO_PIN_SWB | ADC_GPIO_PIN_BATT) + +#define ADC_GPIOF_PINS \ + (ADC_GPIO_PIN_SWC | ADC_GPIO_PIN_SWD | ADC_GPIO_PIN_SWE | ADC_GPIO_PIN_SWF) + +#define ADC_CHANNEL_STICK_LH LL_ADC_CHANNEL_14 // ADC12_INP14 +#define ADC_CHANNEL_STICK_LV LL_ADC_CHANNEL_15 // ADC12_INP15 +#define ADC_CHANNEL_STICK_RV LL_ADC_CHANNEL_16 // ADC12_INP16 +#define ADC_CHANNEL_STICK_RH LL_ADC_CHANNEL_17 // ADC12_INP17 + +// Each ADC cannot map more than 8 channels, otherwise it will cause problems +#define ADC_CHANNEL_POT1 LL_ADC_CHANNEL_3 // ADC12_INP3 +#define ADC_CHANNEL_POT2 LL_ADC_CHANNEL_5 // ADC12_INP5 +#define ADC_CHANNEL_SLIDER1 LL_ADC_CHANNEL_9 // ADC12_INP9 +#define ADC_CHANNEL_SLIDER2 LL_ADC_CHANNEL_7 // ADC12_INP7 + +// Ext inputs: analog gimbal channel re-use +#define ADC_CHANNEL_EXT1 LL_ADC_CHANNEL_14 // ADC12_INP14 +#define ADC_CHANNEL_EXT2 LL_ADC_CHANNEL_15 // ADC12_INP15 +#define ADC_CHANNEL_EXT3 LL_ADC_CHANNEL_16 // ADC12_INP16 +#define ADC_CHANNEL_EXT4 LL_ADC_CHANNEL_17 // ADC12_INP17 + +// Analog switches +#define ADC_CHANNEL_SWA LL_ADC_CHANNEL_0 // ADC3_INP0 +#define ADC_CHANNEL_SWB LL_ADC_CHANNEL_1 // ADC3_INP1 +#define ADC_CHANNEL_SWC LL_ADC_CHANNEL_2 // ADC3_INP2 +#define ADC_CHANNEL_SWD LL_ADC_CHANNEL_3 // ADC3_INP3 +#define ADC_CHANNEL_SWE LL_ADC_CHANNEL_8 // ADC3_INP8 +#define ADC_CHANNEL_SWF LL_ADC_CHANNEL_7 // ADC3_INP7 + +#define ADC_CHANNEL_BATT LL_ADC_CHANNEL_11 // ADC123_INP11 +#define ADC_CHANNEL_RTC_BAT LL_ADC_CHANNEL_VBAT // ADC12_IN16 + +#define ADC_MAIN ADC1 +#define ADC_DMA DMA2 +#define ADC_DMA_CHANNEL LL_DMAMUX1_REQ_ADC1 +#define ADC_DMA_STREAM LL_DMA_STREAM_4 +#define ADC_DMA_STREAM_IRQ DMA2_Stream4_IRQn +#define ADC_DMA_STREAM_IRQHandler DMA2_Stream4_IRQHandler +#define ADC_SAMPTIME LL_ADC_SAMPLINGTIME_64CYCLES_5 + +#define ADC_EXT ADC3 +#define ADC_EXT_CHANNELS \ + { \ + ADC_CHANNEL_SWA, ADC_CHANNEL_SWB, ADC_CHANNEL_SWC, ADC_CHANNEL_SWD, \ + ADC_CHANNEL_SWE, ADC_CHANNEL_SWF, ADC_CHANNEL_BATT \ + } + +#define ADC_EXT_DMA DMA2 +#define ADC_EXT_DMA_CHANNEL LL_DMAMUX1_REQ_ADC3 +#define ADC_EXT_DMA_STREAM LL_DMA_STREAM_0 +#define ADC_EXT_DMA_STREAM_IRQ DMA2_Stream0_IRQn +#define ADC_EXT_DMA_STREAM_IRQHandler DMA2_Stream0_IRQHandler +#define ADC_EXT_SAMPTIME LL_ADC_SAMPLINGTIME_64CYCLES_5 + +#define ADC_VREF_PREC2 329 + +#define ADC_DIRECTION { \ + 0,0,0,0, /* gimbals */ \ + 0,0, /* pots */ \ + 0,0, /* sliders */ \ + 0, /* vbat */ \ + 0, /* rtc_bat */ \ + 0, /* SWA */ \ + 0, /* SWB */ \ + 0, /* SWC */ \ + 0, /* SWD */ \ + 0, /* SWE */ \ + 0 /* SWF */ \ + } + +#define USE_EXTI9_5_IRQ // used for I2C port extender interrupt +#define EXTI9_5_IRQ_Priority 5 + +// Power +#define PWR_SWITCH_GPIO GPIO_PIN(GPIOB, 3) // PE.03 +#define PWR_ON_GPIO GPIO_PIN(GPIOI, 8) // PE.04 + +// Chargers (USB and wireless) +#define UCHARGER_GPIO GPIO_PIN(GPIOD, 4) // PD.02 input + +// TODO! Check IOLL1 to PI.01 connectivity! + +// S.Port update connector +#define HAS_SPORT_UPDATE_CONNECTOR() (false) + +// Serial Port (DEBUG) +// We will temporarily used the PPM and the HEARTBEAT PINS +// #define AUX_SERIAL_RCC_AHB1Periph (RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOE) +// #define AUX_SERIAL_RCC_APB1Periph 0 +// #define AUX_SERIAL_RCC_APB2Periph RCC_APB2Periph_USART6 +// #define AUX_SERIAL_GPIO GPIOC +// #define AUX_SERIAL_GPIO_PIN_TX GPIO_Pin_6 // PC.06 +// #define AUX_SERIAL_GPIO_PIN_RX GPIO_Pin_7 // PC.07 +// #define AUX_SERIAL_GPIO_PinSource_TX GPIO_PinSource6 +// #define AUX_SERIAL_GPIO_PinSource_RX GPIO_PinSource7 +// #define AUX_SERIAL_GPIO_AF GPIO_AF_USART6 +// #define AUX_SERIAL_USART USART6 +// #define AUX_SERIAL_USART_IRQHandler USART6_IRQHandler +// #define AUX_SERIAL_USART_IRQn USART6_IRQn +// #define AUX_SERIAL_TX_INVERT_GPIO GPIOE +// #define AUX_SERIAL_TX_INVERT_GPIO_PIN GPIO_Pin_3 // PE.03 +// #define AUX_SERIAL_RX_INVERT_GPIO GPIOI +// #define AUX_SERIAL_RX_INVERT_GPIO_PIN GPIO_Pin_15 // PI.15 + +//used in BOOTLOADER +// #define SERIAL_RCC_AHB1Periph 0 +// #define SERIAL_RCC_APB1Periph 0 +// #define AUX2_SERIAL_RCC_AHB1Periph 0 +// #define AUX2_SERIAL_RCC_APB1Periph 0 +// #define AUX2_SERIAL_RCC_APB2Periph 0 +// #define KEYS_BACKLIGHT_RCC_AHB1Periph 0 + +// Telemetry + #define TELEMETRY_TX_GPIO GPIO_PIN(GPIOB, 13) + #define TELEMETRY_RX_GPIO GPIO_UNDEF //GPIO_PIN(GPIOB, 12) + #define TELEMETRY_USART UART5 + #define TELEMETRY_USART_IRQn UART5_IRQn + #define TELEMETRY_DMA DMA1 + #define TELEMETRY_DMA_Stream_TX LL_DMA_STREAM_7 + #define TELEMETRY_DMA_Channel_TX LL_DMAMUX1_REQ_UART5_TX + #define TELEMETRY_DMA_TX_Stream_IRQ DMA1_Stream7_IRQn + #define TELEMETRY_DMA_TX_IRQHandler DMA1_Stream7_IRQHandler + #define TELEMETRY_DMA_Stream_RX LL_DMA_STREAM_3 + #define TELEMETRY_DMA_Channel_RX LL_DMAMUX1_REQ_UART5_RX + #define TELEMETRY_USART_IRQHandler UART5_IRQHandler + +// Software IRQ (Prio 5 -> FreeRTOS compatible) +//#define USE_CUSTOM_EXTI_IRQ +#define TELEMETRY_USE_CUSTOM_EXTI +#define CUSTOM_EXTI_IRQ_NAME ETH_WKUP_IRQ +#define ETH_WKUP_IRQ_Priority 5 +#define CUSTOM_EXTI_IRQ_LINE 86 +//#define USE_EXTI15_10_IRQ +//#define CUSTOM_EXTI_IRQ_Priority 5 +#define TELEMETRY_RX_FRAME_EXTI_LINE CUSTOM_EXTI_IRQ_LINE + +// USB +#define USB_GPIO GPIOA +#define USB_GPIO_VBUS GPIO_PIN(GPIOC, 0) // PC.00 +#define USB_GPIO_DM GPIO_PIN(GPIOA, 11) // PA.11 +#define USB_GPIO_DP GPIO_PIN(GPIOA, 12) // PA.12 +#define USB_GPIO_AF GPIO_AF10 + +// LCD +#define LCD_SPI_CS_GPIO GPIOH +#define LCD_SPI_CS_GPIO_PIN LL_GPIO_PIN_6 // PH.06 +#define LCD_SPI_GPIO GPIOE +#define LCD_SPI_SCK_GPIO_PIN LL_GPIO_PIN_4 // PE.04 +#define LCD_SPI_MOSI_GPIO_PIN LL_GPIO_PIN_3 // PE.03 +#define LTDC_IRQ_PRIO 4 +#define DMA_SCREEN_IRQ_PRIO 6 + +// Backlight +#define BACKLIGHT_GPIO GPIO_PIN(GPIOC, 06) // TIM3_CH1 +#define BACKLIGHT_TIMER TIM3 +#define BACKLIGHT_GPIO_AF GPIO_AF2 +#define BACKLIGHT_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) + +// QSPI Flash +#define QSPI_MAX_FREQ 80000000U // 80 MHz +#define QSPI_CLK_GPIO GPIO_PIN(GPIOB, 2) +#define QSPI_CLK_GPIO_AF GPIO_AF9 +#define QSPI_CS_GPIO GPIO_PIN(GPIOB, 6) +#define QSPI_CS_GPIO_AF GPIO_AF10 +#define QSPI_MISO_GPIO GPIO_PIN(GPIOD, 12) +#define QSPI_MISO_GPIO_AF GPIO_AF9 +#define QSPI_MOSI_GPIO GPIO_PIN(GPIOD, 11) +#define QSPI_MOSI_GPIO_AF GPIO_AF9 +#define QSPI_WP_GPIO GPIO_PIN(GPIOE, 2) +#define QSPI_WP_GPIO_AF GPIO_AF9 +#define QSPI_HOLD_GPIO GPIO_PIN(GPIOD, 13) +#define QSPI_HOLD_GPIO_AF GPIO_AF9 +#define QSPI_FLASH_SIZE 0x800000 + +// SPI NOR Flash +#define FLASH_SPI SPI6 +#define FLASH_SPI_CS_GPIO GPIOG +#define FLASH_SPI_CS_GPIO_PIN LL_GPIO_PIN_6 // PG.06 +#define FLASH_SPI_GPIO GPIOG +#define FLASH_SPI_SCK_GPIO_PIN LL_GPIO_PIN_13 // PG.13 +#define FLASH_SPI_MISO_GPIO_PIN LL_GPIO_PIN_12 // PG.12 +#define FLASH_SPI_MOSI_GPIO_PIN LL_GPIO_PIN_14 // PG.14 +// #define FLASH_SPI_DMA DMA2 +// #define FLASH_SPI_DMA_CHANNEL LL_DMA_CHANNEL_1 +// #define FLASH_SPI_DMA_TX_STREAM LL_DMA_STREAM_5 +// #define FLASH_SPI_DMA_TX_IRQn DMA2_Stream5_IRQn +// #define FLASH_SPI_DMA_TX_IRQHandler DMA2_Stream5_IRQHandler +// #define FLASH_SPI_DMA_RX_STREAM LL_DMA_STREAM_6 +// #define FLASH_SPI_DMA_RX_IRQn DMA2_Stream6_IRQn +// #define FLASH_SPI_DMA_RX_IRQHandler DMA2_Stream6_IRQHandler + +#define SD_PRESENT_GPIO GPIO_PIN(GPIOD, 3) // PD.03 +#define SD_SDIO SDMMC1 +#define SD_SDIO_CLK_DIV(fq) (HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SDMMC) / (2 * fq)) +#define SD_SDIO_INIT_CLK_DIV SD_SDIO_CLK_DIV(400000) +#define SD_SDIO_TRANSFER_CLK_DIV SD_SDIO_CLK_DIV(20000000) +#define STORAGE_USE_SDIO + + +// Audio +#define AUDIO_XDCS_GPIO GPIO_PIN(GPIOG, 12) // PG.12 +#define AUDIO_CS_GPIO GPIO_PIN(GPIOG, 10) // PG.10 +#define AUDIO_DREQ_GPIO GPIO_PIN(GPIOG, 13) // PG.13 +#define AUDIO_SPI SPI1 +#define AUDIO_SPI_GPIO_AF LL_GPIO_AF_5 +#define AUDIO_SPI_SCK_GPIO GPIO_PIN(GPIOA, 5) // PA.05 +#define AUDIO_SPI_MISO_GPIO GPIO_PIN(GPIOG, 9) // PG.09 +#define AUDIO_SPI_MOSI_GPIO GPIO_PIN(GPIOD, 7) // PD.07 +#define AUDIO_MUTE_GPIO 0 +#define AUDIO_UNMUTE_DELAY 180 // ms +#define AUDIO_MUTE_DELAY 200 // ms +#define INVERTED_MUTE_PIN + +// I2C Bus +#define I2C_B1 I2C1 +#define I2C_B1_SDA_GPIO GPIO_PIN(GPIOB, 7) // PB.07 +#define I2C_B1_SCL_GPIO GPIO_PIN(GPIOB, 8) // PB.08 +#define I2C_B1_GPIO_AF LL_GPIO_AF_4 +#define I2C_B1_CLK_RATE 400000 + +#define I2C_B2 I2C3 +#define I2C_B2_SDA_GPIO GPIO_PIN(GPIOH, 8) // PH.08 +#define I2C_B2_SCL_GPIO GPIO_PIN(GPIOH, 7) // PH.07 +#define I2C_B2_GPIO_AF LL_GPIO_AF_4 +#define I2C_B2_CLK_RATE 400000 + +// Haptic: TIM3_CH2 +#define HAPTIC_PWM +#define HAPTIC_GPIO GPIO_PIN(GPIOB, 5) // PB.05 +#define HAPTIC_GPIO_TIMER TIM3 +#define HAPTIC_GPIO_AF GPIO_AF2 +#define HAPTIC_TIMER_OUTPUT_ENABLE TIM_CCER_CC2E | TIM_CCER_CC2NE; +#define HAPTIC_TIMER_MODE TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2PE +#define HAPTIC_TIMER_COMPARE_VALUE HAPTIC_GPIO_TIMER->CCR2 + +// Flysky Hall Stick +#define FLYSKY_HALL_SERIAL_USART USART2 + +#define FLYSKY_HALL_SERIAL_TX_GPIO GPIO_PIN(GPIOD, 5) // PD.05 +#define FLYSKY_HALL_SERIAL_RX_GPIO GPIO_PIN(GPIOD, 6) // PD.06 +#define FLYSKY_HALL_SERIAL_USART_IRQn USART2_IRQn + +#define FLYSKY_HALL_SERIAL_DMA DMA1 +#define FLYSKY_HALL_DMA_Stream_RX LL_DMA_STREAM_2 +#define FLYSKY_HALL_DMA_Channel LL_DMAMUX1_REQ_USART2_RX + +// LED Strip +#define LED_STRIP_LENGTH 24 +#define LED_STRIP_RESERVED_AT_END 12 +#define LED_STRIP_GPIO GPIO_PIN(GPIOA, 15) // PA.15 / TIM2_CH1 +#define LED_STRIP_GPIO_AF LL_GPIO_AF_1 // TIM1/2/16/17 +#define LED_STRIP_TIMER TIM2 +#define LED_STRIP_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) +#define LED_STRIP_TIMER_CHANNEL LL_TIM_CHANNEL_CH1 +#define LED_STRIP_TIMER_DMA DMA1 +#define LED_STRIP_TIMER_DMA_CHANNEL LL_DMAMUX1_REQ_TIM2_UP +#define LED_STRIP_TIMER_DMA_STREAM LL_DMA_STREAM_0 +#define LED_STRIP_TIMER_DMA_IRQn DMA1_Stream0_IRQn +#define LED_STRIP_TIMER_DMA_IRQHandler DMA1_Stream0_IRQHandler +#define LED_STRIP_REFRESH_PERIOD 50 //ms +#define STATUS_LEDS + + +// Internal Module +#define INTMODULE_TX_GPIO GPIO_PIN(GPIOB, 11) // PB.11 +#define INTMODULE_RX_GPIO GPIO_PIN(GPIOB, 10) // PB.10 +#define INTMODULE_USART USART3 +#define INTMODULE_GPIO_AF LL_GPIO_AF_7 +#define INTMODULE_USART_IRQn USART3_IRQn +#define INTMODULE_USART_IRQHandler USART3_IRQHandler +//#define INTMODULE_DMA DMA1 +#define INTMODULE_DMA_STREAM LL_DMA_STREAM_1 +#define INTMODULE_DMA_STREAM_IRQ DMA1_Stream1_IRQn +#define INTMODULE_DMA_FLAG_TC DMA_FLAG_TCIF1 +#define INTMODULE_DMA_CHANNEL LL_DMA_CHANNEL_5 +//#define INTMODULE_RX_DMA DMA1 +#define INTMODULE_RX_DMA_STREAM LL_DMA_STREAM_3 +#define INTMODULE_RX_DMA_CHANNEL LL_DMA_CHANNEL_5 +// #define INTMODULE_RX_DMA_Stream_IRQn DMA1_Stream3_IRQn +// #define INTMODULE_RX_DMA_Stream_IRQHandler DMA1_Stream_IRQHandler + +// #define INTMODULE_TIMER TIM3 +// #define INTMODULE_TIMER_IRQn TIM3_IRQn +// #define INTMODULE_TIMER_IRQHandler TIM3_IRQHandler +// #define INTMODULE_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) + +// External Module +#define EXTMODULE +#define EXTMODULE_PULSES +#define EXTMODULE_TX_GPIO GPIO_PIN(GPIOB, 9) // PB.09 +#define EXTMODULE_RX_GPIO GPIO_PIN(GPIOI, 9) // PI.09 +#define EXTMODULE_TX_GPIO_AF LL_GPIO_AF_3 // TIM8_CH1 +#define EXTMODULE_TIMER TIM8 +#define EXTMODULE_TIMER_Channel LL_TIM_CHANNEL_CH1 +#define EXTMODULE_TIMER_IRQn TIM8_UP_TIM13_IRQn +#define EXTMODULE_TIMER_IRQHandler TIM8_UP_TIM13_IRQHandler +#define EXTMODULE_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2) +#define EXTMODULE_TIMER_TX_GPIO_AF LL_GPIO_AF_3 + + +//USART +#define EXTMODULE_USART UART4 +#define EXTMODULE_USART_RX_GPIO GPIO_PIN(GPIOI, 9) +#define EXTMODULE_USART_TX_GPIO GPIO_PIN(GPIOB, 9) +#define EXTMODULE_USART_TX_DMA DMA2 +#define EXTMODULE_USART_TX_DMA_CHANNEL LL_DMAMUX1_REQ_UART4_TX +#define EXTMODULE_USART_TX_DMA_STREAM LL_DMA_STREAM_6 + +#define EXTMODULE_USART_RX_DMA_CHANNEL LL_DMAMUX1_REQ_UART4_RX +#define EXTMODULE_USART_RX_DMA_STREAM LL_DMA_STREAM_4 + +#define EXTMODULE_USART_IRQHandler UART4_IRQHandler +#define EXTMODULE_USART_IRQn UART4_IRQn + +//TIMER +// TODO +#define EXTMODULE_TIMER_DMA_CHANNEL LL_DMAMUX1_REQ_TIM8_CH1 +#define EXTMODULE_TIMER_DMA DMA2 +#define EXTMODULE_TIMER_DMA_STREAM LL_DMA_STREAM_1 +#define EXTMODULE_TIMER_DMA_STREAM_IRQn DMA2_Stream1_IRQn +#define EXTMODULE_TIMER_DMA_IRQHandler DMA2_Stream1_IRQHandler + +// Trainer Port +#define TRAINER_RCC_AHB1Periph (RCC_AHB1Periph_GPIOD) + +#define TRAINER_IN_GPIO GPIO_PIN(GPIOE, 5) // PE.05 +#define TRAINER_IN_TIMER_Channel LL_TIM_CHANNEL_CH1 + +#define TRAINER_OUT_GPIO GPIO_PIN(GPIOE, 6) // PE.06 +#define TRAINER_OUT_TIMER_Channel LL_TIM_CHANNEL_CH2 + +#define TRAINER_TIMER TIM15 +#define TRAINER_TIMER_IRQn TIM15_IRQn +#define TRAINER_TIMER_IRQHandler TIM15_IRQHandler +#define TRAINER_GPIO_AF LL_GPIO_AF_4 +#define TRAINER_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) + +#define TOUCH_I2C_BUS I2C_Bus_1 +#define TOUCH_I2C_CLK_RATE 100000 + +#define IMU_I2C_BUS I2C_Bus_1 +#define IMU_I2C_ADDRESS 0x6A + +//ROTARY emulation for trims as buttons +#define ROTARY_ENCODER_NAVIGATION +// Rotary Encoder +#define ROTARY_ENCODER_INVERTED +#define ROTARY_ENCODER_GPIO GPIOG +#define ROTARY_ENCODER_GPIO_PIN_A LL_GPIO_PIN_2 // PG.02 +#define ROTARY_ENCODER_GPIO_PIN_B LL_GPIO_PIN_3 // PG.03 +#define ROTARY_ENCODER_POSITION() ((ROTARY_ENCODER_GPIO->IDR >> 2) & 0x03) +#define ROTARY_ENCODER_EXTI_LINE1 LL_EXTI_LINE_2 +#define ROTARY_ENCODER_EXTI_LINE2 LL_EXTI_LINE_3 +#if !defined(USE_EXTI2_IRQ) + #define USE_EXTI2_IRQ + #define EXTI2_IRQ_Priority 5 +#endif +#if !defined(USE_EXTI3_IRQ) + #define USE_EXTI3_IRQ + #define EXTI3_IRQ_Priority 5 +#endif +#define ROTARY_ENCODER_EXTI_PORT LL_SYSCFG_EXTI_PORTG +#define ROTARY_ENCODER_EXTI_SYS_LINE1 LL_SYSCFG_EXTI_LINE2 +#define ROTARY_ENCODER_EXTI_SYS_LINE2 LL_SYSCFG_EXTI_LINE3 +#define ROTARY_ENCODER_TIMER TIM17 +#define ROTARY_ENCODER_TIMER_IRQn TIM17_IRQn +#define ROTARY_ENCODER_TIMER_IRQHandler TIM17_IRQHandler + +// Millisecond timer +#define MS_TIMER TIM14 +#define MS_TIMER_IRQn TIM8_TRG_COM_TIM14_IRQn +#define MS_TIMER_IRQHandler TIM8_TRG_COM_TIM14_IRQHandler + +// Mixer scheduler timer +#define MIXER_SCHEDULER_TIMER TIM12 +#define MIXER_SCHEDULER_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) +#define MIXER_SCHEDULER_TIMER_IRQn TIM8_BRK_TIM12_IRQn +#define MIXER_SCHEDULER_TIMER_IRQHandler TIM8_BRK_TIM12_IRQHandler + +#define LANDSCAPE_LCD_SML false +#define LANDSCAPE_LCD_STD true +#define LANDSCAPE_LCD_LRG false +#define PORTRAIT_LCD false + +#define LCD_W 480 +#define LCD_H 320 + +#define LCD_PHYS_W LCD_H +#define LCD_PHYS_H LCD_W + +#define LCD_DEPTH 16 diff --git a/radio/src/targets/st16/haptic_driver.cpp b/radio/src/targets/st16/haptic_driver.cpp new file mode 100644 index 000000000..148312717 --- /dev/null +++ b/radio/src/targets/st16/haptic_driver.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "hal/gpio.h" +#include "stm32_gpio.h" +#include "stm32_timer.h" +#include "stm32_pulse_driver.h" + +#include "board.h" + +#define HAPTIC_TIMER_FREQ 200000000 + +static const stm32_pulse_timer_t _haptic_timer = { + .GPIO = (gpio_t)HAPTIC_GPIO, + .GPIO_Alternate = HAPTIC_GPIO_AF, + .TIMx = HAPTIC_GPIO_TIMER, + .TIM_Freq = HAPTIC_TIMER_FREQ, + .TIM_Channel = LL_TIM_CHANNEL_CH2, + .TIM_IRQn = (IRQn_Type)-1, + .DMAx = nullptr, + .DMA_Stream = 0, + .DMA_Channel = 0, + .DMA_IRQn = (IRQn_Type)-1, + .DMA_TC_CallbackPtr = nullptr, +}; + +void hapticInit(void) +{ + stm32_pulse_init(&_haptic_timer, 10000); + stm32_pulse_config_output(&_haptic_timer, true, LL_TIM_OCMODE_PWM1, 0); + LL_TIM_SetAutoReload(_haptic_timer.TIMx, 100); + LL_TIM_EnableCounter(_haptic_timer.TIMx); +} + +void hapticOn(uint32_t pwmPercent) +{ + if (pwmPercent > 100) pwmPercent = 100; + stm32_pulse_set_cmp_val(&_haptic_timer, pwmPercent); +} + +void hapticOff(void) { hapticOn(0); } +void hapticDone(void) { hapticOff(); } diff --git a/radio/src/targets/st16/key_driver.cpp b/radio/src/targets/st16/key_driver.cpp new file mode 100644 index 000000000..5905a140b --- /dev/null +++ b/radio/src/targets/st16/key_driver.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "hal/key_driver.h" + +#include "bsp_io.h" +#include "stm32_hal_ll.h" +#include "stm32_gpio_driver.h" +#include "stm32_i2c_driver.h" + +#include "hal.h" +#include "delays_driver.h" +#include "keys.h" + +#include "stm32_keys.inc" + +void keysInit() { _init_keys(); } + +uint32_t readKeys() { return _read_keys(); } + +/* The output bit-order has to be: + 0 LHL TR3L (Left equals down) + 1 LHR TR3R + 2 LVD TR1D + 3 LVU TR1U + 4 RVD TR2D + 5 RVU TR2U + 6 RHL TR4L + 7 RHR TR4R +*/ + +enum PhysicalTrims { + TR3L = 0, + TR3R, + TR1D = 2, + TR1U, + TR2D = 4, + TR2U, + TR4L = 6, + TR4R +}; + +uint32_t readTrims() +{ + uint32_t result = 0; + uint16_t keys = bsp_input_get(); + +#define _TRIM(t) \ + if ((keys & BSP_##t) == 0) result |= 1 << t; + + _TRIM(TR1U); + _TRIM(TR1D); + _TRIM(TR3L); + _TRIM(TR3R); + _TRIM(TR2U); + _TRIM(TR2D); + _TRIM(TR4L); + _TRIM(TR4R); + +#undef _TRIM + + return result; +} diff --git a/radio/src/targets/st16/lcd_driver.cpp b/radio/src/targets/st16/lcd_driver.cpp new file mode 100644 index 000000000..dac00790b --- /dev/null +++ b/radio/src/targets/st16/lcd_driver.cpp @@ -0,0 +1,2884 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "stm32_hal_ll.h" +#include "stm32_hal.h" +#include "edgetx_types.h" +#include "dma2d.h" +#include "hal.h" +#include "delays_driver.h" +#include "debug.h" +#include "lcd.h" +#include "lcd_driver.h" +#include "board.h" + +#include "stm32_gpio.h" +#include "hal/gpio.h" + +uint8_t TouchControllerType = 0; // 0: other; 1: CST836U +static volatile uint16_t lcd_phys_w = LCD_PHYS_W; +static volatile uint16_t lcd_phys_h = LCD_PHYS_H; + +static LTDC_HandleTypeDef hltdc; +static void* initialFrameBuffer = nullptr; + +static volatile uint8_t _frame_addr_reloaded = 0; + +static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, + const rect_t ©_area) +{ + (void)disp_drv; + (void)copy_area; + +// LTDC_Layer1->CFBAR &= ~(LTDC_LxCFBAR_CFBADD); + LTDC_Layer1->CFBAR = (uint32_t)buffer; + // reload shadow registers on vertical blank + _frame_addr_reloaded = 0; + LTDC->SRCR = LTDC_SRCR_VBR; + __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); + + // wait for reload + // TODO: replace through some smarter mechanism without busy wait + while(_frame_addr_reloaded == 0); +} + +lcdSpiInitFucPtr lcdInitFunction; +lcdSpiInitFucPtr lcdOffFunction; +lcdSpiInitFucPtr lcdOnFunction; +uint32_t lcdPixelClock; + +volatile uint8_t LCD_ReadBuffer[24] = { 0, 0 }; + +static void LCD_Delay(void) { + volatile unsigned int i; + + for (i = 0; i < 20; i++) { + ; + } +} + +enum ENUM_IO_SPEED +{ + IO_SPEED_LOW, + IO_SPEED_MID, + IO_SPEED_QUICK, + IO_SPEED_HIGH +}; + +enum ENUM_IO_MODE +{ + IO_MODE_INPUT, + IO_MODE_OUTPUT, + IO_MODE_ALTERNATE, + IO_MODE_ANALOG +}; + +static void LCD_AF_GPIOConfig(void) { + //HAL_RCCEx_PeriphCLKConfig(); + /**LTDC GPIO Configuration + PI10 ------> LTDC_HSYNC + PF10 ------> LTDC_DE + PA4 ------> LTDC_VSYNC + PH9 ------> LTDC_R3 + PH10 ------> LTDC_R4 + PH11 ------> LTDC_R5 + PH12 ------> LTDC_R6 + PG6 ------> LTDC_R7 + PG7 ------> LTDC_CLK + PH13 ------> LTDC_G2 + PH14 ------> LTDC_G3 + PH15 ------> LTDC_G4 + PI0 ------> LTDC_G5 + PI1 ------> LTDC_G6 + PI2 ------> LTDC_G7 + PG11 ------> LTDC_B3 + PI4 ------> LTDC_B4 + PI5 ------> LTDC_B5 + PI6 ------> LTDC_B6 + PI7 ------> LTDC_B7 + */ + + gpio_init_af(GPIO_PIN(GPIOI, 0), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + gpio_init_af(GPIO_PIN(GPIOI, 1), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + gpio_init_af(GPIO_PIN(GPIOI, 2), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + gpio_init_af(GPIO_PIN(GPIOI, 4), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + gpio_init_af(GPIO_PIN(GPIOI, 5), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + gpio_init_af(GPIO_PIN(GPIOI, 6), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + gpio_init_af(GPIO_PIN(GPIOI, 7), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + gpio_init_af(GPIO_PIN(GPIOI, 10), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + + + gpio_init_af(GPIO_PIN(GPIOF, 10), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + + gpio_init_af(GPIO_PIN(GPIOA, 4), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + + + gpio_init_af(GPIO_PIN(GPIOH, 9), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + gpio_init_af(GPIO_PIN(GPIOH, 10), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + gpio_init_af(GPIO_PIN(GPIOH, 11), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + gpio_init_af(GPIO_PIN(GPIOH, 12), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + gpio_init_af(GPIO_PIN(GPIOH, 13), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + gpio_init_af(GPIO_PIN(GPIOH, 14), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + gpio_init_af(GPIO_PIN(GPIOH, 15), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + + gpio_init_af(GPIO_PIN(GPIOG, 6), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + gpio_init_af(GPIO_PIN(GPIOG, 7), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + gpio_init_af(GPIO_PIN(GPIOG, 11), GPIO_AF14, GPIO_SPEED_FREQ_LOW); + +} + +static void lcdSpiConfig(void) { + LL_GPIO_InitTypeDef GPIO_InitStructure; + LL_GPIO_StructInit(&GPIO_InitStructure); + + GPIO_InitStructure.Pin = LCD_SPI_SCK_GPIO_PIN | LCD_SPI_MOSI_GPIO_PIN; + GPIO_InitStructure.Speed = LL_GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Mode = LL_GPIO_MODE_OUTPUT; + GPIO_InitStructure.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + GPIO_InitStructure.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(LCD_SPI_GPIO, &GPIO_InitStructure); + + /* Set the chip select pin always low */ + LCD_CS_LOW(); +} + +void lcdDelay() { + delay_01us(1); +} + +static void lcdReset() { + LCD_NRST_HIGH(); + delay_ms(1); + + LCD_NRST_LOW(); // RESET(); + delay_ms(100); + + LCD_NRST_HIGH(); + delay_ms(100); +} + +unsigned char LCD_ReadByteOnFallingEdge(void) { + unsigned int i; + unsigned char ReceiveData = 0; + + LCD_MOSI_HIGH(); + LCD_MOSI_AS_INPUT(); + + for (i = 0; i < 8; i++) { + LCD_DELAY(); + LCD_SCK_HIGH(); + LCD_DELAY(); + LCD_DELAY(); + ReceiveData <<= 1; + + LCD_SCK_LOW(); + LCD_DELAY(); + LCD_DELAY(); + if (LCD_READ_DATA_PIN()) { + ReceiveData |= 0x01; + } + } + + LCD_MOSI_AS_OUTPUT(); + + return (ReceiveData); +} + +static void lcdWriteByte(uint8_t data_enable, uint8_t byte) { + + LCD_SCK_LOW(); + lcdDelay(); + + if (data_enable) { + LCD_MOSI_HIGH(); + } else { + LCD_MOSI_LOW(); + } + + LCD_SCK_HIGH(); + lcdDelay(); + + for (int i = 0; i < 8; i++) { + LCD_SCK_LOW(); + lcdDelay(); + + if (byte & 0x80) { + LCD_MOSI_HIGH(); + } else { + LCD_MOSI_LOW(); + } + + LCD_SCK_HIGH(); + byte <<= 1; + + lcdDelay(); + } + + LCD_SCK_LOW(); +} + +unsigned char LCD_ReadByte(void) { + unsigned int i; + unsigned char ReceiveData = 0; + + LCD_MOSI_HIGH(); + LCD_MOSI_AS_INPUT(); + for (i = 0; i < 8; i++) { + LCD_SCK_LOW(); + lcdDelay(); + ReceiveData <<= 1; + LCD_SCK_HIGH(); + lcdDelay(); + if (LCD_READ_DATA_PIN()) { + ReceiveData |= 0x01; + } + } + LCD_SCK_LOW(); + LCD_MOSI_AS_OUTPUT(); + return (ReceiveData); +} + +unsigned char LCD_ReadRegister(unsigned char Register) { + unsigned char ReadData = 0; + + lcdWriteByte(0, Register); + lcdDelay(); + lcdDelay(); + ReadData = LCD_ReadByte(); + return (ReadData); +} + +void lcdWriteCommand(uint8_t command) { + lcdWriteByte(0, command); +} + +void lcdWriteData(uint8_t data) { + lcdWriteByte(1, data); +} + +void LCD_HX8357D_Init(void) { +#if 0 + lcdWriteCommand(0x11); + delay_ms(200); + + lcdWriteCommand(0xB9); + lcdWriteData(0xFF); + lcdWriteData(0x83); + lcdWriteData(0x57); + + lcdWriteCommand(0xB1); + lcdWriteData(0x00); + lcdWriteData(0x14); + lcdWriteData(0x1C); + lcdWriteData(0x1C); + lcdWriteData(0xC7); + lcdWriteData(0x21); + + lcdWriteCommand(0xB3); + lcdWriteData(0x83); + lcdWriteData(0x00); + lcdWriteData(0x06); + lcdWriteData(0x06); + + lcdWriteCommand(0xB4); + lcdWriteData(0x11); + lcdWriteData(0x40); + lcdWriteData(0x00); + lcdWriteData(0x2A); + lcdWriteData(0x2A); + lcdWriteData(0x20); + lcdWriteData(0x4E); + + lcdWriteCommand(0xB5); + lcdWriteData(0x03); + lcdWriteData(0x03); + + lcdWriteCommand(0xB6); + lcdWriteData(0x38); + + lcdWriteCommand(0xC0); + lcdWriteData(0x24); + lcdWriteData(0x24); + lcdWriteData(0x00); + lcdWriteData(0x10); + lcdWriteData(0xc8); + lcdWriteData(0x08); + + lcdWriteCommand(0xC2); + lcdWriteData(0x00); + lcdWriteData(0x08); + lcdWriteData(0x04); + + lcdWriteCommand(0xCC); + lcdWriteData(0x00); + +//GAMMA 2.5" + lcdWriteCommand(0xE0); + lcdWriteData(0x00); + lcdWriteData(0x06); + lcdWriteData(0x0D); + lcdWriteData(0x18); + lcdWriteData(0x23); + lcdWriteData(0x3B); + lcdWriteData(0x45); + lcdWriteData(0x4D); + lcdWriteData(0x4D); + lcdWriteData(0x46); + lcdWriteData(0x40); + lcdWriteData(0x37); + lcdWriteData(0x34); + lcdWriteData(0x2F); + lcdWriteData(0x2B); + lcdWriteData(0x21); + lcdWriteData(0x00); + lcdWriteData(0x06); + lcdWriteData(0x0D); + lcdWriteData(0x18); + lcdWriteData(0x23); + lcdWriteData(0x3B); + lcdWriteData(0x45); + lcdWriteData(0x4D); + lcdWriteData(0x4D); + lcdWriteData(0x46); + lcdWriteData(0x40); + lcdWriteData(0x37); + lcdWriteData(0x34); + lcdWriteData(0x2F); + lcdWriteData(0x2B); + lcdWriteData(0x21); + lcdWriteData(0x00); + lcdWriteData(0x01); + + lcdWriteCommand(0x3A); + lcdWriteData(0x66); + + lcdWriteCommand(0x36); + lcdWriteData(0x28); + lcdWriteCommand( 0x2A ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x01 ); + lcdWriteData( 0xDF ); + lcdWriteCommand( 0x2B ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x01 ); + lcdWriteData( 0x3F ); + + lcdWriteCommand(0x29); + delay_ms(10); +#elif 0 + delay_ms(50); + lcdWriteCommand(0xB9); //EXTC + lcdWriteData(0xFF); //EXTC + lcdWriteData(0x83); //EXTC + lcdWriteData(0x57); //EXTC + delay_ms(5); + + lcdWriteCommand(0x3A); + lcdWriteData(0x65); //262k + + lcdWriteCommand(0xB3); //COLOR FORMAT + lcdWriteData(0x83); //SDO_EN,BYPASS,EPF[1:0],0,0,RM,DM //43 + + lcdWriteCommand(0xB6); // + lcdWriteData(0x5a); //VCOMDC + + lcdWriteCommand(0x35); // TE ON + lcdWriteData(0x01); + + lcdWriteCommand(0xB0); + lcdWriteData(0x68); //70Hz + + lcdWriteCommand(0xCC); // Set Panel + lcdWriteData(0x00); // + + lcdWriteCommand(0xB1); // + lcdWriteData(0x00); // + lcdWriteData(0x11); //BT + lcdWriteData(0x1C); //VSPR + lcdWriteData(0x1C); //VSNR + lcdWriteData(0x83); //AP + lcdWriteData(0x48); //FS 0xAA + + lcdWriteCommand(0xB4); // + lcdWriteData(0x02); //NW + lcdWriteData(0x40); //RTN + lcdWriteData(0x00); //DIV + lcdWriteData(0x2A); //DUM + lcdWriteData(0x2A); //DUM + lcdWriteData(0x0D); //GDON + lcdWriteData(0x78); //GDOFF 0x4F + lcdWriteCommand(0xC0); //STBA + lcdWriteData(0x50); //OPON + lcdWriteData(0x50); //OPON + lcdWriteData(0x01); // + lcdWriteData(0x3C); // + lcdWriteData(0x1E); // + lcdWriteData(0x08); //GEN + + /* + lcdWriteCommand(0xE0); // + lcdWriteData(0x02); //1 + lcdWriteData(0x06); //2 + lcdWriteData(0x09); //3 + lcdWriteData(0x1C); //4 + lcdWriteData(0x27); //5 + lcdWriteData(0x3C); //6 + lcdWriteData(0x48); //7 + lcdWriteData(0x50); //8 + lcdWriteData(0x49); //9 + lcdWriteData(0x42); //10 + lcdWriteData(0x3E); //11 + lcdWriteData(0x35); //12 + lcdWriteData(0x31); //13 + lcdWriteData(0x2A); //14 + lcdWriteData(0x28); //15 + lcdWriteData(0x03); //16 + lcdWriteData(0x02); //17 v1 + lcdWriteData(0x06); //18 + lcdWriteData(0x09); //19 + lcdWriteData(0x1C); //20 + lcdWriteData(0x27); //21 + lcdWriteData(0x3C); //22 + lcdWriteData(0x48); //23 + lcdWriteData(0x50); //24 + lcdWriteData(0x49); //25 + lcdWriteData(0x42); //26 + lcdWriteData(0x3E); //27 + lcdWriteData(0x35); //28 + lcdWriteData(0x31); //29 + lcdWriteData(0x2A); //30 + lcdWriteData(0x28); //31 + lcdWriteData(0x03); //32 + lcdWriteData(0x44); //33 + lcdWriteData(0x01); //34 + */ + lcdWriteCommand(0xE0); + lcdWriteData(0x00); + lcdWriteData(0x06); + lcdWriteData(0x0D); + lcdWriteData(0x18); + lcdWriteData(0x23); + lcdWriteData(0x3B); + lcdWriteData(0x45); + lcdWriteData(0x4D); + lcdWriteData(0x4D); + lcdWriteData(0x46); + lcdWriteData(0x40); + lcdWriteData(0x37); + lcdWriteData(0x34); + lcdWriteData(0x2F); + lcdWriteData(0x2B); + lcdWriteData(0x21); + lcdWriteData(0x00); + lcdWriteData(0x06); + lcdWriteData(0x0D); + lcdWriteData(0x18); + lcdWriteData(0x23); + lcdWriteData(0x3B); + lcdWriteData(0x45); + lcdWriteData(0x4D); + lcdWriteData(0x4D); + lcdWriteData(0x46); + lcdWriteData(0x40); + lcdWriteData(0x37); + lcdWriteData(0x34); + lcdWriteData(0x2F); + lcdWriteData(0x2B); + lcdWriteData(0x21); + lcdWriteData(0x00); + lcdWriteData(0x01); + lcdWriteCommand(0x36); + lcdWriteData(0x38); + + lcdWriteCommand(0x11); // SLPOUT + delay_ms(200); + + lcdWriteCommand(0x29); // Display On + delay_ms(25); + lcdWriteCommand(0x2C); +#else + lcdWriteCommand(0x11); + delay_ms(200); + + lcdWriteCommand(0xB9); + lcdWriteData(0xFF); + lcdWriteData(0x83); + lcdWriteData(0x57); + delay_ms(5); + +// lcdWriteCommand(0x36); +// lcdWriteData(0x10); + + lcdWriteCommand(0xB1); + lcdWriteData(0x00); + lcdWriteData(0x14); + lcdWriteData(0x1C); + lcdWriteData(0x1C); + lcdWriteData(0xC7); + lcdWriteData(0x21); + lcdWriteCommand(0xB3); + lcdWriteData(0x83); + lcdWriteData(0x00); + lcdWriteData(0x06); + lcdWriteData(0x06); + lcdWriteCommand(0xB4); + lcdWriteData(0x11); + lcdWriteData(0x40); + lcdWriteData(0x00); + lcdWriteData(0x2A); + lcdWriteData(0x2A); + lcdWriteData(0x20); + lcdWriteData(0x4E); + lcdWriteCommand(0xB5); + lcdWriteData(0x03); + lcdWriteData(0x03); + + lcdWriteCommand(0xB6); + lcdWriteData(0x38); + + lcdWriteCommand(0xC0); + lcdWriteData(0x24); + lcdWriteData(0x24); + lcdWriteData(0x00); + lcdWriteData(0x10); + lcdWriteData(0xc8); + lcdWriteData(0x08); + lcdWriteCommand(0xC2); + lcdWriteData(0x00); + lcdWriteData(0x08); + lcdWriteData(0x04); + //GAMMA 2.5" + lcdWriteCommand(0xE0); + lcdWriteData(0x00); + lcdWriteData(0x06); + lcdWriteData(0x0D); + lcdWriteData(0x18); + lcdWriteData(0x23); + lcdWriteData(0x3B); + lcdWriteData(0x45); + lcdWriteData(0x4D); + lcdWriteData(0x4D); + lcdWriteData(0x46); + lcdWriteData(0x40); + lcdWriteData(0x37); + lcdWriteData(0x34); + lcdWriteData(0x2F); + lcdWriteData(0x2B); + lcdWriteData(0x21); + lcdWriteData(0x00); + lcdWriteData(0x06); + lcdWriteData(0x0D); + lcdWriteData(0x18); + lcdWriteData(0x23); + lcdWriteData(0x3B); + lcdWriteData(0x45); + lcdWriteData(0x4D); + lcdWriteData(0x4D); + lcdWriteData(0x46); + lcdWriteData(0x40); + lcdWriteData(0x37); + lcdWriteData(0x34); + lcdWriteData(0x2F); + lcdWriteData(0x2B); + lcdWriteData(0x21); + lcdWriteData(0x00); + lcdWriteData(0x01); + // lcdWriteCommand(0x2A); + // lcdWriteData(0); + // lcdWriteData(0); + // lcdWriteData(480 >> 8); + // lcdWriteData(480); + // lcdWriteCommand(0x2B); + // lcdWriteData(0); + // lcdWriteData(0); + // lcdWriteData(320 >> 8); + // lcdWriteData(320); + lcdWriteCommand(0x3A); + lcdWriteData(0x66); + + lcdWriteCommand(0xCC); + lcdWriteData(0x01); + + lcdWriteCommand( 0x2A ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x01 ); + lcdWriteData( 0xDF ); + lcdWriteCommand( 0x2B ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x01 ); + lcdWriteData( 0x3F ); + + lcdWriteCommand(0x36); + lcdWriteData(0x20); + + lcdWriteCommand(0xB9); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + delay_ms(5); + lcdWriteCommand(0x29); +#endif +} + +void LCD_HX8357D_On(void) { + lcdWriteCommand(0x28); + lcdWriteCommand(0x29); +} + +void LCD_HX8357D_Off(void) { + lcdWriteCommand(0x28); +} + +unsigned int LCD_HX8357D_ReadID(void) { + lcdReset(); + int ID = 0; + + lcdWriteCommand( 0xB9 ); + lcdWriteData( 0xff ); + lcdWriteData( 0x83 ); + lcdWriteData( 0x57 ); + + lcdWriteCommand( 0xFE ); + lcdWriteData( 0xd0 ); + ID = LCD_ReadRegister( 0xff ); + + lcdWriteCommand( 0xB9 ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x00 ); + + return (ID); +} + +void LCD_ILI9481_Init(void) { + lcdWriteCommand(0x11); + delay_ms(120); + + lcdWriteCommand(0xE4); + lcdWriteData(0x0A); + + lcdWriteCommand(0xF0); + lcdWriteData(0x01); + + lcdWriteCommand(0xF3); + lcdWriteData(0x02); + lcdWriteData(0x1A); + + lcdWriteCommand(0xD0); + lcdWriteData(0x07); + lcdWriteData(0x42); + lcdWriteData(0x1B); + + lcdWriteCommand(0xD1); + lcdWriteData(0x00); + lcdWriteData(0x00); //04 + lcdWriteData(0x1A); + + lcdWriteCommand(0xD2); + lcdWriteData(0x01); + lcdWriteData(0x00); //11 + + lcdWriteCommand(0xC0); + lcdWriteData(0x10); + lcdWriteData(0x3B); // + lcdWriteData(0x00); // + lcdWriteData(0x02); + lcdWriteData(0x11); + + lcdWriteCommand(0xC5); + lcdWriteData(0x03); + + lcdWriteCommand(0xC8); + lcdWriteData(0x00); + lcdWriteData(0x01); + lcdWriteData(0x47); + lcdWriteData(0x60); + lcdWriteData(0x04); + lcdWriteData(0x16); + lcdWriteData(0x03); + lcdWriteData(0x67); + lcdWriteData(0x67); + lcdWriteData(0x06); + lcdWriteData(0x0F); + lcdWriteData(0x00); + + lcdWriteCommand(0x36); + lcdWriteData(0x08); + + lcdWriteCommand(0x3A); + lcdWriteData(0x66); //0x55=65k color, 0x66=262k color. + + lcdWriteCommand(0x2A); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x01); + lcdWriteData(0x3F); + + lcdWriteCommand(0x2B); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x01); + lcdWriteData(0xE0); + + lcdWriteCommand(0xB4); + lcdWriteData(0x11); + + lcdWriteCommand(0xc6); + lcdWriteData(0x82); + + delay_ms(120); + + lcdWriteCommand(0x21); + lcdWriteCommand(0x29); + lcdWriteCommand(0x2C); + +} + +void LCD_ILI9481_On(void) { + lcdWriteCommand(0x29); +} + +void LCD_ILI9481_Off(void) { + lcdWriteCommand(0x28); +} + +unsigned int LCD_ILI9481_ReadID(void) { +#if 1 + /* Have a issue here */ + return 0; +#else + int ID = 0; + int Data; + + + lcdWriteByte(0, 0xBF); + + Data = LCD_ReadByteOnFallingEdge(); + Data = LCD_ReadByteOnFallingEdge(); + ID = LCD_ReadByteOnFallingEdge(); + ID <<= 8; + ID |= LCD_ReadByteOnFallingEdge(); + Data = LCD_ReadByteOnFallingEdge(); + Data = LCD_ReadByteOnFallingEdge(); + + LCD_DELAY(); + LCD_DELAY(); + LCD_DELAY(); + + lcdWriteCommand(0xC6); + lcdWriteData(0x82); + //lcdWriteData( 0x9b ); + return (ID); +#endif +} + +void LCD_ILI9486_On(void) { + lcdWriteCommand(0x29); +} + +void LCD_ILI9486_Init(void) { + lcdWriteCommand(0XFB); + lcdWriteData(0x00); + + lcdWriteCommand(0xf2); + lcdWriteData(0x18); + lcdWriteData(0xa3); + lcdWriteData(0x12); + lcdWriteData(0x02); + lcdWriteData(0xb2); + lcdWriteData(0x12); + lcdWriteData(0xff); + lcdWriteData(0x13); + lcdWriteData(0x00); + lcdWriteCommand(0xf1); + lcdWriteData(0x36); + lcdWriteData(0x04); + lcdWriteData(0x00); + lcdWriteData(0x3c); + lcdWriteData(0x0f); + lcdWriteData(0x8f); + lcdWriteCommand(0xf8); + lcdWriteData(0x21); + lcdWriteData(0x04); + lcdWriteCommand(0xf9); + lcdWriteData(0x00); + lcdWriteData(0x08); + lcdWriteCommand(0x36); + lcdWriteData(0x18); + lcdWriteCommand(0x3a); + lcdWriteData(0x65); + lcdWriteCommand(0xc0); + lcdWriteData(0x0f); + lcdWriteData(0x0f); + lcdWriteCommand(0xc1); + lcdWriteData(0x41); + + lcdWriteCommand(0xc5); + lcdWriteData(0x00); + lcdWriteData(0x27); + lcdWriteData(0x80); + lcdWriteCommand(0xb6); + lcdWriteData(0xb2); + lcdWriteData(0x42); + lcdWriteData(0x3b); + lcdWriteCommand(0xb1); + lcdWriteData(0xb0); + lcdWriteData(0x11); + lcdWriteCommand(0xb4); + lcdWriteData(0x02); + lcdWriteCommand(0xb7); + lcdWriteData(0xC6); + + lcdWriteCommand(0xe0); + lcdWriteData(0x0f); + lcdWriteData(0x1C); + lcdWriteData(0x18); + lcdWriteData(0x0B); + lcdWriteData(0x0D); + lcdWriteData(0x06); + lcdWriteData(0x48); + lcdWriteData(0x87); + lcdWriteData(0x3A); + lcdWriteData(0x09); + lcdWriteData(0x15); + lcdWriteData(0x08); + lcdWriteData(0x0D); + lcdWriteData(0x04); + lcdWriteData(0x00); + + lcdWriteCommand(0xe1); + lcdWriteData(0x0f); + lcdWriteData(0x37); + lcdWriteData(0x34); + lcdWriteData(0x0A); + lcdWriteData(0x0B); + lcdWriteData(0x03); + lcdWriteData(0x4B); + lcdWriteData(0x31); + lcdWriteData(0x39); + lcdWriteData(0x03); + lcdWriteData(0x0F); + lcdWriteData(0x03); + lcdWriteData(0x22); + lcdWriteData(0x1D); + lcdWriteData(0x00); + + lcdWriteCommand(0x21); + lcdWriteCommand(0x11); + delay_ms(120); + lcdWriteCommand(0x28); + + LCD_ILI9486_On(); +} + +void LCD_ILI9486_Off(void) { + lcdWriteCommand(0x28); +} + +unsigned int LCD_ILI9486_ReadID(void) { + int ID = 0; + + lcdWriteCommand(0XF7); + lcdWriteData(0xA9); + lcdWriteData(0x51); + lcdWriteData(0x2C); + lcdWriteData(0x82); + lcdWriteCommand(0XB0); + lcdWriteData(0X80); + + lcdWriteCommand(0XFB); + lcdWriteData(0x10 | 0x00); + ID = LCD_ReadRegister(0xd3); + + lcdWriteCommand(0XFB); + lcdWriteData(0x10 | 0x01); + ID = LCD_ReadRegister(0xd3); + + lcdWriteCommand(0XFB); + lcdWriteData(0x10 | 0x02); + ID = LCD_ReadRegister(0xd3); + ID <<= 8; + lcdWriteCommand(0XFB); + lcdWriteData(0x10 | 0x03); + ID |= LCD_ReadRegister(0xd3); + + lcdWriteCommand(0XFB); + lcdWriteData(0x00); + + return (ID); +} + +void LCD_ILI9488_On(void) { + // Display ON + lcdWriteCommand(0x29); +} + +void LCD_ILI9488_Init(void) { + + // lcdWriteCommand(0xFB); + // lcdWriteData(0x00); + + // Adjust Control 3: + // -> DSI write DCS command, use stream packet RGB 666 + lcdWriteCommand(0xF7); + lcdWriteData(0xA9); + lcdWriteData(0x51); + lcdWriteData(0x2C); + lcdWriteData(0x82); + + // Power Control 1: + // -> VREG1OUT = 4.6250 + // -> VREG2OUT = -4.1250 + lcdWriteCommand(0xC0); + lcdWriteData(0x11); + lcdWriteData(0x09); + + // Power Control 2: + // -> VGH = VCI x 6, VGL = VCI x 4 + lcdWriteCommand(0xC1); + lcdWriteData(0x41); + + // VCOM Control + lcdWriteCommand(0xC5); + lcdWriteData(0x00); // NV memory not programmed + lcdWriteData(0x0A); // VCM_REG + lcdWriteData(0x80); // VCM_REG_EN + + // Frame Rate Control + lcdWriteCommand(0xB1); + lcdWriteData(0xB0); + lcdWriteData(0x11); + + // Display Inversion Control + lcdWriteCommand(0xB4); + lcdWriteData(0x01); + + lcdWriteCommand(0xB5); + lcdWriteData(VFP); + lcdWriteData(VBP); + lcdWriteData(HFP); + lcdWriteData(HBP); + + // Display Function Control + lcdWriteCommand(0xB6); + // !DM | RM | RCM + lcdWriteData(0x20 | 0x40); + lcdWriteData(0x02); + lcdWriteData(0x3B); // (59 + 1) x 8 = 480 lines + + // Entry Set Mode + lcdWriteCommand(0xB7); + lcdWriteData(0xc6); + + lcdWriteCommand(0xBE); + lcdWriteData(0x00); + // lcdWriteData(0x04); // ???? + + lcdWriteCommand(0xE9); + lcdWriteData(0x00); + + // Column Address Set + // -> SC=0, EC=479 + lcdWriteCommand( 0x2A ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x01 ); + lcdWriteData( 0xDF ); + + // Page Address Set + // -> SP=0, EP=319 + lcdWriteCommand( 0x2B ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x01 ); + lcdWriteData( 0x3F ); + + // Memory Access Control + lcdWriteCommand(0x36); + lcdWriteData(0x28); // 0x20 -> swap col/rows + + lcdWriteCommand(0x3A); + lcdWriteData(0x66); + + lcdWriteCommand(0xE0); + lcdWriteData(0x00); + lcdWriteData(0x07); + lcdWriteData(0x10); + lcdWriteData(0x09); + lcdWriteData(0x17); + lcdWriteData(0x0B); + lcdWriteData(0x41); + lcdWriteData(0x89); + lcdWriteData(0x4B); + lcdWriteData(0x0A); + lcdWriteData(0x0C); + lcdWriteData(0x0E); + lcdWriteData(0x18); + lcdWriteData(0x1B); + lcdWriteData(0x0F); + + lcdWriteCommand(0xE1); + lcdWriteData(0x00); + lcdWriteData(0x17); + lcdWriteData(0x1A); + lcdWriteData(0x04); + lcdWriteData(0x0E); + lcdWriteData(0x06); + lcdWriteData(0x2F); + lcdWriteData(0x45); + lcdWriteData(0x43); + lcdWriteData(0x02); + lcdWriteData(0x0A); + lcdWriteData(0x09); + lcdWriteData(0x32); + lcdWriteData(0x36); + lcdWriteData(0x0F); + + // Sleep OUT + lcdWriteCommand(0x11); + delay_ms(120); + + // Display OFF + lcdWriteCommand(0x28); + + LCD_ILI9488_On(); +} + +void LCD_ILI9488_Off(void) { + lcdWriteCommand(0x28); +} + +void LCD_ILI9488_ReadDevice(void) { + int Index = 0; + int Parameter = 0x80; + + lcdWriteCommand(0xF7); + lcdWriteData(0xA9); + lcdWriteData(0x51); + lcdWriteData(0x2C); + lcdWriteData(0x82); + + lcdWriteCommand(0xB0); + lcdWriteData(0x80); + + lcdWriteCommand(0xFB); + lcdWriteData(Parameter | 0x00); + LCD_ReadBuffer[Index++] = LCD_ReadRegister(0xd3); + + //lcdWriteCommand(0X2E); + lcdWriteCommand(0xFB); + lcdWriteData(Parameter | 0x01); //Parameter2=0x88 + LCD_ReadBuffer[Index++] = LCD_ReadRegister(0xd3); + + lcdWriteCommand(0XFB); + lcdWriteData(Parameter | 0x02); //Parameter2=0x88 + LCD_ReadBuffer[Index++] = LCD_ReadRegister(0xd3); + + lcdWriteCommand(0XFB); + lcdWriteData(Parameter | 0x03); //Parameter2=0x88 + LCD_ReadBuffer[Index++] = LCD_ReadRegister(0xd3); +} + +unsigned int LCD_ILI9488_ReadID(void) { + int ID = 0; + + // Adjust Control 3: + // -> DSI write DCS command, use stream packet RGB 666 + lcdWriteCommand(0xF7); + lcdWriteData(0xA9); + lcdWriteData(0x51); + lcdWriteData(0x2C); + lcdWriteData(0x82); + + // Interface Mode Control: + // SDA_EN = 1, DIN/SDA pin is used for 3/4 wire serial + // interface and SDO pin is not used. + lcdWriteCommand(0xB0); + lcdWriteData(0x80); + + // first byte is dummy one + lcdWriteCommand(0xFB); + lcdWriteData(0x80 | 0x00); + ID = LCD_ReadRegister(0xd3); + + lcdWriteCommand(0xFB); + lcdWriteData(0x80 | 0x01); + ID = LCD_ReadRegister(0xd3); + + lcdWriteCommand(0xFB); + lcdWriteData(0x80 | 0x02); + ID = LCD_ReadRegister(0xd3); + ID <<= 8; + + lcdWriteCommand(0xFB); + lcdWriteData(0x80 | 0x03); + ID |= LCD_ReadRegister(0xd3); + + lcdWriteCommand(0xFB); + lcdWriteData(0x00); + + return (ID); +} + +void LCD_ST7796S_On(void) { + lcdWriteCommand(0x29); +} + +void LCD_ST7796S_Init(void) { + delay_ms(120); + + lcdWriteCommand( 0x11 ); + delay_ms(120); + + lcdWriteCommand( 0xF0 ); + lcdWriteData( 0xC3 ); + + lcdWriteCommand( 0xF0 ); + lcdWriteData( 0x96 ); + + lcdWriteCommand( 0x36 ); + lcdWriteData( 0x28 ); + + lcdWriteCommand( 0x2A ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x01 ); + lcdWriteData( 0xDF ); + lcdWriteCommand( 0x2B ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x01 ); + lcdWriteData( 0x3F ); + + lcdWriteCommand( 0x3A ); + lcdWriteData( 0x66 ); + + //SET RGB STRAT + lcdWriteCommand (0xB0 ); //SET HS VS DE CLK 上升还是下降有效 + lcdWriteData( 0x80 ); + + lcdWriteCommand( 0xB4 ); + lcdWriteData( 0x01 ); + + lcdWriteCommand( 0xB6 ); + // lcdWriteData( 0x20 ); + // lcdWriteData( 0x02 ); + // lcdWriteData( 0x3B ); + lcdWriteData( 0x20 ); + lcdWriteData( 0x02 ); + lcdWriteData( 0x3B ); + //SET RGB END + + lcdWriteCommand( 0xB7); + lcdWriteData( 0xC6); + + lcdWriteCommand( 0xB9 ); + lcdWriteData( 0x02 ); + lcdWriteData( 0xE0 ); + + lcdWriteCommand( 0xC0 ); + lcdWriteData( 0x80 ); + lcdWriteData( 0x65 ); + + lcdWriteCommand( 0xC1 ); + lcdWriteData( 0x0D ); + + lcdWriteCommand( 0xC2 ); + lcdWriteData( 0xA7 ); + + lcdWriteCommand( 0xC5 ); + lcdWriteData( 0x14 ); + + lcdWriteCommand( 0xE8 ); + lcdWriteData( 0x40 ); + lcdWriteData( 0x8A ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x29 ); + lcdWriteData( 0x19 ); + lcdWriteData( 0xA5 ); + lcdWriteData( 0x33 ); + + lcdWriteCommand( 0xE0 ); + lcdWriteData( 0xD0 ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x04 ); + lcdWriteData( 0x05 ); + lcdWriteData( 0x04 ); + lcdWriteData( 0x21 ); + lcdWriteData( 0x25 ); + lcdWriteData( 0x43 ); + lcdWriteData( 0x3F ); + lcdWriteData( 0x37 ); + lcdWriteData( 0x13 ); + lcdWriteData( 0x13 ); + lcdWriteData( 0x29 ); + lcdWriteData( 0x32 ); + + lcdWriteCommand( 0xE1 ); + lcdWriteData( 0xD0 ); + lcdWriteData( 0x04 ); + lcdWriteData( 0x06 ); + lcdWriteData( 0x09 ); + lcdWriteData( 0x06 ); + lcdWriteData( 0x03 ); + lcdWriteData( 0x25 ); + lcdWriteData( 0x32 ); + lcdWriteData( 0x3E ); + lcdWriteData( 0x18 ); + lcdWriteData( 0x15 ); + lcdWriteData( 0x15 ); + lcdWriteData( 0x2B ); + lcdWriteData( 0x30 ); + + lcdWriteCommand( 0xF0 ); + lcdWriteData( 0x3C ); + + lcdWriteCommand( 0xF0 ); + lcdWriteData( 0x69 ); + + delay_ms(120); + + lcdWriteCommand( 0x21 ); + + LCD_ST7796S_On(); +} + +void LCD_ST7796S_Off(void) { + lcdWriteCommand(0x28); +} + +unsigned int LCD_ST7796S_ReadID(void) { + lcdReset(); + unsigned int ID = 0; + + lcdWriteCommand( 0XF0 ); + lcdWriteData( 0XC3 ); + lcdWriteCommand( 0XF0 ); + lcdWriteData( 0X96 ); + + lcdWriteCommand( 0XB0 ); + lcdWriteData( 0X80 ); + + lcdWriteCommand( 0XD3 ); + + LCD_MOSI_AS_INPUT(); + LCD_SCK_LOW(); + lcdDelay(); + lcdDelay(); + LCD_SCK_HIGH(); + lcdDelay(); + lcdDelay(); + + LCD_ReadByte(); + ID += (uint16_t)(LCD_ReadByte())<<8; + ID += LCD_ReadByte(); + + return (ID); + } + + +unsigned int LCD_NT35310_ReadID( void ) +{ + unsigned int ID = 0x3531; + + return( ID ); + +} + +void LCD_NT35310_Init( void ) +{ +#if 1 + lcdWriteCommand(0xED); + lcdWriteData(0x01); + lcdWriteData(0xFE); + + lcdWriteCommand(0xEE); + lcdWriteData(0xDE); + lcdWriteData(0x21); + + lcdWriteCommand(0x11); + delay_ms(120); + lcdWriteCommand(0xB3); + lcdWriteData(0x21); + + + + lcdWriteCommand(0xC0); + lcdWriteData(0x33); + lcdWriteData(0x33); + lcdWriteData(0x10); + lcdWriteData(0x10); + + + lcdWriteCommand(0xC4); + lcdWriteData(0x56); //3a + + lcdWriteCommand(0xBF); + lcdWriteData(0xAA); + + lcdWriteCommand(0xB0); + lcdWriteData(0x0D); + lcdWriteData(0x00); + lcdWriteData(0x0D); + lcdWriteData(0x00); + lcdWriteData(0x11); + lcdWriteData(0x00); + lcdWriteData(0x19); + lcdWriteData(0x00); + lcdWriteData(0x21); + lcdWriteData(0x00); + lcdWriteData(0x2D); + lcdWriteData(0x00); + lcdWriteData(0x3D); + lcdWriteData(0x00); + lcdWriteData(0x5D); + lcdWriteData(0x00); + lcdWriteData(0x5D); + lcdWriteData(0x00); + + lcdWriteCommand(0xB1); + lcdWriteData(0x80); + lcdWriteData(0x00); + lcdWriteData(0x8B); + lcdWriteData(0x00); + lcdWriteData(0x96); + lcdWriteData(0x00); + + lcdWriteCommand(0xB2); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x02); + lcdWriteData(0x00); + lcdWriteData(0x03); + lcdWriteData(0x00); + + lcdWriteCommand(0xB3); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xB4); + lcdWriteData(0x8B); + lcdWriteData(0x00); + lcdWriteData(0x96); + lcdWriteData(0x00); + lcdWriteData(0xA1); + lcdWriteData(0x00); + + lcdWriteCommand(0xB5); + lcdWriteData(0x02); + lcdWriteData(0x00); + lcdWriteData(0x03); + lcdWriteData(0x00); + lcdWriteData(0x04); + lcdWriteData(0x00); + lcdWriteCommand(0xB6); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xB7); + lcdWriteData(0x3E); + lcdWriteData(0x00); + lcdWriteData(0x5E); + lcdWriteData(0x00); + lcdWriteData(0x9E); + lcdWriteData(0x00); + lcdWriteData(0x74); + lcdWriteData(0x00); + lcdWriteData(0x8C); + lcdWriteData(0x00); + lcdWriteData(0xAC); + lcdWriteData(0x00); + lcdWriteData(0xDC); + lcdWriteData(0x00); + lcdWriteData(0x70); + lcdWriteData(0x00); + lcdWriteData(0xB9); + lcdWriteData(0x00); + lcdWriteData(0xEC); + lcdWriteData(0x00); + lcdWriteData(0xDC); + lcdWriteData(0x00); + + lcdWriteCommand(0xB8); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xBA); + lcdWriteData(0x24); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xC1); + lcdWriteData(0x20); + lcdWriteData(0x00); + lcdWriteData(0x54); + lcdWriteData(0x00); + lcdWriteData(0xFF); + lcdWriteData(0x00); + + lcdWriteCommand(0xC2); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x04); + lcdWriteData(0x00); + + lcdWriteCommand(0xC3); + lcdWriteData(0x3C); + lcdWriteData(0x00); + lcdWriteData(0x3A); + lcdWriteData(0x00); + lcdWriteData(0x39); + lcdWriteData(0x00); + lcdWriteData(0x37); + lcdWriteData(0x00); + lcdWriteData(0x3C); + lcdWriteData(0x00); + lcdWriteData(0x36); + lcdWriteData(0x00); + lcdWriteData(0x32); + lcdWriteData(0x00); + lcdWriteData(0x2F); + lcdWriteData(0x00); + lcdWriteData(0x2C); + lcdWriteData(0x00); + lcdWriteData(0x29); + lcdWriteData(0x00); + lcdWriteData(0x26); + lcdWriteData(0x00); + lcdWriteData(0x24); + lcdWriteData(0x00); + lcdWriteData(0x24); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + lcdWriteData(0x3C); + lcdWriteData(0x00); + lcdWriteData(0x36); + lcdWriteData(0x00); + lcdWriteData(0x32); + lcdWriteData(0x00); + lcdWriteData(0x2F); + lcdWriteData(0x00); + lcdWriteData(0x2C); + lcdWriteData(0x00); + lcdWriteData(0x29); + lcdWriteData(0x00); + lcdWriteData(0x26); + lcdWriteData(0x00); + lcdWriteData(0x24); + lcdWriteData(0x00); + lcdWriteData(0x24); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + + lcdWriteCommand(0xC4); + lcdWriteData(0x62); + lcdWriteData(0x00); + lcdWriteData(0x05); + lcdWriteData(0x00); + lcdWriteData(0x84); + lcdWriteData(0x00); + lcdWriteData(0xF0); + lcdWriteData(0x00); + lcdWriteData(0x18); + lcdWriteData(0x00); + lcdWriteData(0xA4); + lcdWriteData(0x00); + lcdWriteData(0x18); + lcdWriteData(0x00); + lcdWriteData(0x50); + lcdWriteData(0x00); + lcdWriteData(0x0C); + lcdWriteData(0x00); + lcdWriteData(0x17); + lcdWriteData(0x00); + lcdWriteData(0x95); + lcdWriteData(0x00); + lcdWriteData(0xF3); + lcdWriteData(0x00); + lcdWriteData(0xE6); + lcdWriteData(0x00); + + lcdWriteCommand(0xC5); + lcdWriteData(0x32); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x65); + lcdWriteData(0x00); + lcdWriteData(0x76); + lcdWriteData(0x00); + lcdWriteData(0x88); + lcdWriteData(0x00); + + lcdWriteCommand(0xC6); + lcdWriteData(0x20); + lcdWriteData(0x00); + lcdWriteData(0x17); + lcdWriteData(0x00); + lcdWriteData(0x01); + lcdWriteData(0x00); + + lcdWriteCommand(0xC7); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xC8); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xC9); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xE0); + lcdWriteData(0x02); + lcdWriteData(0x00); + lcdWriteData(0x06); + lcdWriteData(0x00); + lcdWriteData(0x10); + lcdWriteData(0x00); + lcdWriteData(0x25); + lcdWriteData(0x00); + lcdWriteData(0x36); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x57); + lcdWriteData(0x00); + lcdWriteData(0x6F); + lcdWriteData(0x00); + lcdWriteData(0x7F); + lcdWriteData(0x00); + lcdWriteData(0x8C); + lcdWriteData(0x00); + lcdWriteData(0x98); + lcdWriteData(0x00); + lcdWriteData(0xA6); + lcdWriteData(0x00); + lcdWriteData(0xAE); + lcdWriteData(0x00); + lcdWriteData(0xB4); + lcdWriteData(0x00); + lcdWriteData(0xBB); + lcdWriteData(0x00); + lcdWriteData(0xC0); + lcdWriteData(0x00); + lcdWriteData(0xC9); + lcdWriteData(0x00); + lcdWriteData(0xF3); + lcdWriteData(0x00); + + lcdWriteCommand(0xE1); + lcdWriteData(0x01); + lcdWriteData(0x00); + lcdWriteData(0x05); + lcdWriteData(0x00); + lcdWriteData(0x10); + lcdWriteData(0x00); + lcdWriteData(0x25); + lcdWriteData(0x00); + lcdWriteData(0x36); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x57); + lcdWriteData(0x00); + lcdWriteData(0x6F); + lcdWriteData(0x00); + lcdWriteData(0x7F); + lcdWriteData(0x00); + lcdWriteData(0x8C); + lcdWriteData(0x00); + lcdWriteData(0x98); + lcdWriteData(0x00); + lcdWriteData(0xA6); + lcdWriteData(0x00); + lcdWriteData(0xAE); + lcdWriteData(0x00); + lcdWriteData(0xB4); + lcdWriteData(0x00); + lcdWriteData(0xBB); + lcdWriteData(0x00); + lcdWriteData(0xC0); + lcdWriteData(0x00); + lcdWriteData(0xC9); + lcdWriteData(0x00); + lcdWriteData(0xF3); + lcdWriteData(0x00); + + lcdWriteCommand(0xE2); + lcdWriteData(0x02); + lcdWriteData(0x00); + lcdWriteData(0x06); + lcdWriteData(0x00); + lcdWriteData(0x10); + lcdWriteData(0x00); + lcdWriteData(0x25); + lcdWriteData(0x00); + lcdWriteData(0x36); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x57); + lcdWriteData(0x00); + lcdWriteData(0x6F); + lcdWriteData(0x00); + lcdWriteData(0x7F); + lcdWriteData(0x00); + lcdWriteData(0x8C); + lcdWriteData(0x00); + lcdWriteData(0x98); + lcdWriteData(0x00); + lcdWriteData(0xA6); + lcdWriteData(0x00); + lcdWriteData(0xAE); + lcdWriteData(0x00); + lcdWriteData(0xB4); + lcdWriteData(0x00); + lcdWriteData(0xBB); + lcdWriteData(0x00); + lcdWriteData(0xC0); + lcdWriteData(0x00); + lcdWriteData(0xC9); + lcdWriteData(0x00); + lcdWriteData(0xF3); + lcdWriteData(0x00); + + lcdWriteCommand(0xE3); + lcdWriteData(0x01); + lcdWriteData(0x00); + lcdWriteData(0x05); + lcdWriteData(0x00); + lcdWriteData(0x10); + lcdWriteData(0x00); + lcdWriteData(0x25); + lcdWriteData(0x00); + lcdWriteData(0x36); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x57); + lcdWriteData(0x00); + lcdWriteData(0x6F); + lcdWriteData(0x00); + lcdWriteData(0x7F); + lcdWriteData(0x00); + lcdWriteData(0x8C); + lcdWriteData(0x00); + lcdWriteData(0x98); + lcdWriteData(0x00); + lcdWriteData(0xA6); + lcdWriteData(0x00); + lcdWriteData(0xAE); + lcdWriteData(0x00); + lcdWriteData(0xB4); + lcdWriteData(0x00); + lcdWriteData(0xBB); + lcdWriteData(0x00); + lcdWriteData(0xC0); + lcdWriteData(0x00); + lcdWriteData(0xC9); + lcdWriteData(0x00); + lcdWriteData(0xF3); + lcdWriteData(0x00); + + lcdWriteCommand(0xE4); + lcdWriteData(0x02); + lcdWriteData(0x00); + lcdWriteData(0x06); + lcdWriteData(0x00); + lcdWriteData(0x10); + lcdWriteData(0x00); + lcdWriteData(0x25); + lcdWriteData(0x00); + lcdWriteData(0x36); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x57); + lcdWriteData(0x00); + lcdWriteData(0x6F); + lcdWriteData(0x00); + lcdWriteData(0x7F); + lcdWriteData(0x00); + lcdWriteData(0x8C); + lcdWriteData(0x00); + lcdWriteData(0x98); + lcdWriteData(0x00); + lcdWriteData(0xA6); + lcdWriteData(0x00); + lcdWriteData(0xAE); + lcdWriteData(0x00); + lcdWriteData(0xB4); + lcdWriteData(0x00); + lcdWriteData(0xBB); + lcdWriteData(0x00); + lcdWriteData(0xC0); + lcdWriteData(0x00); + lcdWriteData(0xC9); + lcdWriteData(0x00); + lcdWriteData(0xF3); + lcdWriteData(0x00); + + lcdWriteCommand(0xE5); + lcdWriteData(0x01); + lcdWriteData(0x00); + lcdWriteData(0x05); + lcdWriteData(0x00); + lcdWriteData(0x10); + lcdWriteData(0x00); + lcdWriteData(0x25); + lcdWriteData(0x00); + lcdWriteData(0x36); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x57); + lcdWriteData(0x00); + lcdWriteData(0x6F); + lcdWriteData(0x00); + lcdWriteData(0x7F); + lcdWriteData(0x00); + lcdWriteData(0x8C); + lcdWriteData(0x00); + lcdWriteData(0x98); + lcdWriteData(0x00); + lcdWriteData(0xA6); + lcdWriteData(0x00); + lcdWriteData(0xAE); + lcdWriteData(0x00); + lcdWriteData(0xB4); + lcdWriteData(0x00); + lcdWriteData(0xBB); + lcdWriteData(0x00); + lcdWriteData(0xC0); + lcdWriteData(0x00); + lcdWriteData(0xC9); + lcdWriteData(0x00); + lcdWriteData(0xF3); + lcdWriteData(0x00); + + lcdWriteCommand(0xE6); + lcdWriteData(0x55); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x56); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x57); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x77); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + lcdWriteData(0x65); + lcdWriteData(0x00); + + lcdWriteCommand(0xE7); + lcdWriteData(0x55); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x56); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x57); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x77); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + lcdWriteData(0x65); + lcdWriteData(0x00); + + lcdWriteCommand(0xE8); + lcdWriteData(0x55); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x56); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x57); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x77); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + lcdWriteData(0x65); + lcdWriteData(0x00); + + lcdWriteCommand(0xE9); + lcdWriteData(0xAA); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0x00); + lcdWriteData(0xAA); + + lcdWriteCommand(0xCF); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xF0); + lcdWriteData(0x00); + lcdWriteData(0x50); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xF1); + lcdWriteData(0x01); + + lcdWriteCommand(0xF9); + lcdWriteData(0x06); + lcdWriteData(0x10); + lcdWriteData(0x29); + lcdWriteData(0x00); + + lcdWriteCommand(0xDF); + lcdWriteData(0x10); + delay_ms(20); + lcdWriteCommand(0x36); +// if( IsHorizontal ) +// lcdWriteData(0x00);//需修改 +// else + lcdWriteData(0x14); + + lcdWriteCommand(0x3A); + lcdWriteData(0x66); + + lcdWriteCommand(0x21); + + lcdWriteCommand(0x35); + lcdWriteData(0x00); + + lcdWriteCommand(0x29); +#else + lcdWriteCommand(0xED); + lcdWriteData(0x01); + lcdWriteData(0xFE); + + lcdWriteCommand(0xEE); + lcdWriteData(0xDE); + lcdWriteData(0x21); + + lcdWriteCommand(0x11); + SYSTEM_DelayMS(120); + lcdWriteCommand(0xB3); + lcdWriteData(0x21); + + + lcdWriteCommand(0xc0); + lcdWriteData(0x56); + lcdWriteData(0x56); + lcdWriteData(0x24); + lcdWriteData(0x24); + + lcdWriteCommand(0xC4); + lcdWriteData(0x30); //3a + + lcdWriteCommand(0xBF); + lcdWriteData(0xAA); + + lcdWriteCommand(0xB0); + lcdWriteData(0x0D); + lcdWriteData(0x00); + lcdWriteData(0x0D); + lcdWriteData(0x00); + lcdWriteData(0x11); + lcdWriteData(0x00); + lcdWriteData(0x19); + lcdWriteData(0x00); + lcdWriteData(0x21); + lcdWriteData(0x00); + lcdWriteData(0x2D); + lcdWriteData(0x00); + lcdWriteData(0x3D); + lcdWriteData(0x00); + lcdWriteData(0x5D); + lcdWriteData(0x00); + lcdWriteData(0x5D); + lcdWriteData(0x00); + + lcdWriteCommand(0xB1); + lcdWriteData(0x80); + lcdWriteData(0x00); + lcdWriteData(0x8B); + lcdWriteData(0x00); + lcdWriteData(0x96); + lcdWriteData(0x00); + + lcdWriteCommand(0xB2); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x02); + lcdWriteData(0x00); + lcdWriteData(0x03); + lcdWriteData(0x00); + + lcdWriteCommand(0xB3); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xB4); + lcdWriteData(0x8B); + lcdWriteData(0x00); + lcdWriteData(0x96); + lcdWriteData(0x00); + lcdWriteData(0xA1); + lcdWriteData(0x00); + + lcdWriteCommand(0xB5); + lcdWriteData(0x02); + lcdWriteData(0x00); + lcdWriteData(0x03); + lcdWriteData(0x00); + lcdWriteData(0x04); + lcdWriteData(0x00); + lcdWriteCommand(0xB6); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xB7); + lcdWriteData(0x3E); + lcdWriteData(0x00); + lcdWriteData(0x5E); + lcdWriteData(0x00); + lcdWriteData(0x9E); + lcdWriteData(0x00); + lcdWriteData(0x74); + lcdWriteData(0x00); + lcdWriteData(0x8C); + lcdWriteData(0x00); + lcdWriteData(0xAC); + lcdWriteData(0x00); + lcdWriteData(0xDC); + lcdWriteData(0x00); + lcdWriteData(0x70); + lcdWriteData(0x00); + lcdWriteData(0xB9); + lcdWriteData(0x00); + lcdWriteData(0xEC); + lcdWriteData(0x00); + lcdWriteData(0xDC); + lcdWriteData(0x00); + + lcdWriteCommand(0xB8); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xBA); + lcdWriteData(0x24); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xC1); + lcdWriteData(0x20); + lcdWriteData(0x00); + lcdWriteData(0x54); + lcdWriteData(0x00); + lcdWriteData(0xFF); + lcdWriteData(0x00); + + lcdWriteCommand(0xC2); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x04); + lcdWriteData(0x00); + + lcdWriteCommand(0xC3); + lcdWriteData(0x3C); + lcdWriteData(0x00); + lcdWriteData(0x3A); + lcdWriteData(0x00); + lcdWriteData(0x39); + lcdWriteData(0x00); + lcdWriteData(0x37); + lcdWriteData(0x00); + lcdWriteData(0x3C); + lcdWriteData(0x00); + lcdWriteData(0x36); + lcdWriteData(0x00); + lcdWriteData(0x32); + lcdWriteData(0x00); + lcdWriteData(0x2F); + lcdWriteData(0x00); + lcdWriteData(0x2C); + lcdWriteData(0x00); + lcdWriteData(0x29); + lcdWriteData(0x00); + lcdWriteData(0x26); + lcdWriteData(0x00); + lcdWriteData(0x24); + lcdWriteData(0x00); + lcdWriteData(0x24); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + lcdWriteData(0x3C); + lcdWriteData(0x00); + lcdWriteData(0x36); + lcdWriteData(0x00); + lcdWriteData(0x32); + lcdWriteData(0x00); + lcdWriteData(0x2F); + lcdWriteData(0x00); + lcdWriteData(0x2C); + lcdWriteData(0x00); + lcdWriteData(0x29); + lcdWriteData(0x00); + lcdWriteData(0x26); + lcdWriteData(0x00); + lcdWriteData(0x24); + lcdWriteData(0x00); + lcdWriteData(0x24); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + + lcdWriteCommand(0xC4); + lcdWriteData(0x62); + lcdWriteData(0x00); + lcdWriteData(0x05); + lcdWriteData(0x00); + lcdWriteData(0x84); + lcdWriteData(0x00); + lcdWriteData(0xF0); + lcdWriteData(0x00); + lcdWriteData(0x18); + lcdWriteData(0x00); + lcdWriteData(0xA4); + lcdWriteData(0x00); + lcdWriteData(0x18); + lcdWriteData(0x00); + lcdWriteData(0x50); + lcdWriteData(0x00); + lcdWriteData(0x0C); + lcdWriteData(0x00); + lcdWriteData(0x17); + lcdWriteData(0x00); + lcdWriteData(0x95); + lcdWriteData(0x00); + lcdWriteData(0xF3); + lcdWriteData(0x00); + lcdWriteData(0xE6); + lcdWriteData(0x00); + + lcdWriteCommand(0xC5); + lcdWriteData(0x32); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x65); + lcdWriteData(0x00); + lcdWriteData(0x76); + lcdWriteData(0x00); + lcdWriteData(0x88); + lcdWriteData(0x00); + + lcdWriteCommand(0xC6); + lcdWriteData(0x20); + lcdWriteData(0x00); + lcdWriteData(0x17); + lcdWriteData(0x00); + lcdWriteData(0x01); + lcdWriteData(0x00); + + lcdWriteCommand(0xC7); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xC8); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xC9); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xE0); + lcdWriteData(0x01); + lcdWriteData(0x00); + lcdWriteData(0x1F); + lcdWriteData(0x00); + lcdWriteData(0x3C); + lcdWriteData(0x00); + lcdWriteData(0x59); + lcdWriteData(0x00); + lcdWriteData(0x67); + lcdWriteData(0x00); + lcdWriteData(0x72); + lcdWriteData(0x00); + lcdWriteData(0x82); + lcdWriteData(0x00); + lcdWriteData(0x93); + lcdWriteData(0x00); + lcdWriteData(0xA0); + lcdWriteData(0x00); + lcdWriteData(0xAB); + lcdWriteData(0x00); + lcdWriteData(0xB4); + lcdWriteData(0x00); + lcdWriteData(0xBF); + lcdWriteData(0x00); + lcdWriteData(0xC6); + lcdWriteData(0x00); + lcdWriteData(0xCA); + lcdWriteData(0x00); + lcdWriteData(0xCF); + lcdWriteData(0x00); + lcdWriteData(0xD3); + lcdWriteData(0x00); + lcdWriteData(0xDA); + lcdWriteData(0x00); + lcdWriteData(0xF3); + lcdWriteData(0x00); + + lcdWriteCommand(0xE1); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x1F); + lcdWriteData(0x00); + lcdWriteData(0x3C); + lcdWriteData(0x00); + lcdWriteData(0x59); + lcdWriteData(0x00); + lcdWriteData(0x67); + lcdWriteData(0x00); + lcdWriteData(0x72); + lcdWriteData(0x00); + lcdWriteData(0x82); + lcdWriteData(0x00); + lcdWriteData(0x93); + lcdWriteData(0x00); + lcdWriteData(0xA0); + lcdWriteData(0x00); + lcdWriteData(0xAB); + lcdWriteData(0x00); + lcdWriteData(0xB4); + lcdWriteData(0x00); + lcdWriteData(0xBF); + lcdWriteData(0x00); + lcdWriteData(0xC6); + lcdWriteData(0x00); + lcdWriteData(0xCA); + lcdWriteData(0x00); + lcdWriteData(0xD0); + lcdWriteData(0x00); + lcdWriteData(0xD4); + lcdWriteData(0x00); + lcdWriteData(0xD9); + lcdWriteData(0x00); + lcdWriteData(0xF3); + lcdWriteData(0x00); + + lcdWriteCommand(0xE2); + lcdWriteData(0x10); + lcdWriteData(0x00); + lcdWriteData(0x1F); + lcdWriteData(0x00); + lcdWriteData(0x3C); + lcdWriteData(0x00); + lcdWriteData(0x59); + lcdWriteData(0x00); + lcdWriteData(0x67); + lcdWriteData(0x00); + lcdWriteData(0x72); + lcdWriteData(0x00); + lcdWriteData(0x82); + lcdWriteData(0x00); + lcdWriteData(0x93); + lcdWriteData(0x00); + lcdWriteData(0xA0); + lcdWriteData(0x00); + lcdWriteData(0xAB); + lcdWriteData(0x00); + lcdWriteData(0xB4); + lcdWriteData(0x00); + lcdWriteData(0xBF); + lcdWriteData(0x00); + lcdWriteData(0xC6); + lcdWriteData(0x00); + lcdWriteData(0xCA); + lcdWriteData(0x00); + lcdWriteData(0xCF); + lcdWriteData(0x00); + lcdWriteData(0xD3); + lcdWriteData(0x00); + lcdWriteData(0xDA); + lcdWriteData(0x00); + lcdWriteData(0xF3); + lcdWriteData(0x00); + + lcdWriteCommand(0xE3); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x1F); + lcdWriteData(0x00); + lcdWriteData(0x3C); + lcdWriteData(0x00); + lcdWriteData(0x59); + lcdWriteData(0x00); + lcdWriteData(0x67); + lcdWriteData(0x00); + lcdWriteData(0x72); + lcdWriteData(0x00); + lcdWriteData(0x82); + lcdWriteData(0x00); + lcdWriteData(0x93); + lcdWriteData(0x00); + lcdWriteData(0xA0); + lcdWriteData(0x00); + lcdWriteData(0xAB); + lcdWriteData(0x00); + lcdWriteData(0xB4); + lcdWriteData(0x00); + lcdWriteData(0xBF); + lcdWriteData(0x00); + lcdWriteData(0xC6); + lcdWriteData(0x00); + lcdWriteData(0xCA); + lcdWriteData(0x00); + lcdWriteData(0xD0); + lcdWriteData(0x00); + lcdWriteData(0xD4); + lcdWriteData(0x00); + lcdWriteData(0xD9); + lcdWriteData(0x00); + lcdWriteData(0xF3); + lcdWriteData(0x00); + + lcdWriteCommand(0xE4); + lcdWriteData(0x01); + lcdWriteData(0x00); + lcdWriteData(0x1F); + lcdWriteData(0x00); + lcdWriteData(0x3C); + lcdWriteData(0x00); + lcdWriteData(0x59); + lcdWriteData(0x00); + lcdWriteData(0x67); + lcdWriteData(0x00); + lcdWriteData(0x72); + lcdWriteData(0x00); + lcdWriteData(0x82); + lcdWriteData(0x00); + lcdWriteData(0x93); + lcdWriteData(0x00); + lcdWriteData(0xA0); + lcdWriteData(0x00); + lcdWriteData(0xAB); + lcdWriteData(0x00); + lcdWriteData(0xB4); + lcdWriteData(0x00); + lcdWriteData(0xBF); + lcdWriteData(0x00); + lcdWriteData(0xC6); + lcdWriteData(0x00); + lcdWriteData(0xCA); + lcdWriteData(0x00); + lcdWriteData(0xCF); + lcdWriteData(0x00); + lcdWriteData(0xD3); + lcdWriteData(0x00); + lcdWriteData(0xDA); + lcdWriteData(0x00); + lcdWriteData(0xF3); + lcdWriteData(0x00); + + lcdWriteCommand(0xE5); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x1F); + lcdWriteData(0x00); + lcdWriteData(0x3C); + lcdWriteData(0x00); + lcdWriteData(0x59); + lcdWriteData(0x00); + lcdWriteData(0x67); + lcdWriteData(0x00); + lcdWriteData(0x72); + lcdWriteData(0x00); + lcdWriteData(0x82); + lcdWriteData(0x00); + lcdWriteData(0x93); + lcdWriteData(0x00); + lcdWriteData(0xA0); + lcdWriteData(0x00); + lcdWriteData(0xAB); + lcdWriteData(0x00); + lcdWriteData(0xB4); + lcdWriteData(0x00); + lcdWriteData(0xBF); + lcdWriteData(0x00); + lcdWriteData(0xC6); + lcdWriteData(0x00); + lcdWriteData(0xCA); + lcdWriteData(0x00); + lcdWriteData(0xD0); + lcdWriteData(0x00); + lcdWriteData(0xD4); + lcdWriteData(0x00); + lcdWriteData(0xD9); + lcdWriteData(0x00); + lcdWriteData(0xF3); + lcdWriteData(0x00); + + lcdWriteCommand(0xE6); + lcdWriteData(0x55); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x56); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x57); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x77); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + lcdWriteData(0x65); + lcdWriteData(0x00); + + lcdWriteCommand(0xE7); + lcdWriteData(0x55); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x56); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x57); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x77); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + lcdWriteData(0x65); + lcdWriteData(0x00); + + lcdWriteCommand(0xE8); + lcdWriteData(0x55); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x56); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x57); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x77); + lcdWriteData(0x00); + lcdWriteData(0x66); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x44); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x33); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + lcdWriteData(0x23); + lcdWriteData(0x00); + lcdWriteData(0x65); + lcdWriteData(0x00); + + lcdWriteCommand(0xE9); + lcdWriteData(0xAA); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0x00); + lcdWriteData(0xAA); + + lcdWriteCommand(0xCF); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xF0); + lcdWriteData(0x00); + lcdWriteData(0x50); + lcdWriteData(0x00); + lcdWriteData(0x00); + lcdWriteData(0x00); + + lcdWriteCommand(0xF1); + lcdWriteData(0x01); + + lcdWriteCommand(0xee); + lcdWriteData(0xde); + lcdWriteData(0x21); + + lcdWriteCommand(0xF3); + lcdWriteData(0x00); + + lcdWriteCommand(0xF9); + lcdWriteData(0x06); + lcdWriteData(0x10); + lcdWriteData(0x29); + lcdWriteData(0x00); + + lcdWriteCommand(0xDF); + lcdWriteData(0x10); + SYSTEM_DelayMS(20); + lcdWriteCommand(0x36); + if( IsHorizontal ) + lcdWriteData(0x14);//需修改 + else + lcdWriteData(0x14); + + lcdWriteCommand(0x3A); + lcdWriteData(0x66); + + lcdWriteCommand(0x21); + + lcdWriteCommand(0x35); + lcdWriteData(0x00); + + lcdWriteCommand(0x28); +#endif +} + +void LCD_NT35310_On( void ) +{ + lcdWriteCommand( 0x29 ); +} + +void LCD_NT35310_Off( void ) +{ + lcdWriteCommand( 0x28 ); +} + +void LCD_Init_LTDC() { + hltdc.Instance = LTDC; + + /* Configure PLLSAI prescalers for LCD */ + /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */ + /* PLLSAI_VCO Output = PLLSAI_VCO Input * lcdPixelclock * 16 = XX Mhz */ + /* PLLLCDCLK = PLLSAI_VCO Output/PLL_LTDC = PLLSAI_VCO/4 = YY Mhz */ + /* LTDC clock frequency = PLLLCDCLK / RCC_PLLSAIDivR = YY/4 = lcdPixelClock Mhz */ +// uint32_t clock = (lcdPixelClock*16) / 1000000; // clock*16 in MHz +// RCC_PeriphCLKInitTypeDef clkConfig; +// clkConfig.PeriphClockSelection = RCC_PERIPHCLK_LTDC; +// clkConfig.PLLI2S +// clkConfig.PLLSAI.PLLSAIN = clock; +// clkConfig.PLLSAI.PLLSAIR = 4; +// clkConfig.PLLSAIDivQ = 6; +// clkConfig.PLLSAIDivR = RCC_PLLSAIDIVR_4; +// HAL_RCCEx_PeriphCLKConfig(&clkConfig); + + /* LTDC Configuration *********************************************************/ + /* Polarity configuration */ + /* Initialize the horizontal synchronization polarity as active low */ + hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL; + /* Initialize the vertical synchronization polarity as active low */ + hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL; + /* Initialize the data enable polarity as active low */ + hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL; + /* Initialize the pixel clock polarity as input pixel clock */ + hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IIPC; + + /* Configure R,G,B component values for LCD background color */ + hltdc.Init.Backcolor.Red = 0; + hltdc.Init.Backcolor.Green = 0; + hltdc.Init.Backcolor.Blue = 0; + + /* Configure horizontal synchronization width */ + hltdc.Init.HorizontalSync = HSW; + /* Configure vertical synchronization height */ + hltdc.Init.VerticalSync = VSH; + /* Configure accumulated horizontal back porch */ + hltdc.Init.AccumulatedHBP = HBP; + /* Configure accumulated vertical back porch */ + hltdc.Init.AccumulatedVBP = VBP; + /* Configure accumulated active width */ + hltdc.Init.AccumulatedActiveW = lcd_phys_w + HBP; + /* Configure accumulated active height */ + hltdc.Init.AccumulatedActiveH = lcd_phys_h + VBP; + /* Configure total width */ + hltdc.Init.TotalWidth = lcd_phys_w + HBP + HFP; + /* Configure total height */ + hltdc.Init.TotalHeigh = lcd_phys_h + VBP + VFP; + + HAL_LTDC_Init(&hltdc); + + // Configure IRQ (line) + NVIC_SetPriority(LTDC_IRQn, LTDC_IRQ_PRIO); + NVIC_EnableIRQ(LTDC_IRQn); + + // Trigger on last line + HAL_LTDC_ProgramLineEvent(&hltdc, lcd_phys_h); + __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); +} + +void LCD_LayerInit() { + auto& layer = hltdc.LayerCfg[0]; + + /* Windowing configuration */ + layer.WindowX0 = 0; + layer.WindowX1 = lcd_phys_w; + layer.WindowY0 = 0; + layer.WindowY1 = lcd_phys_h; + + /* Pixel Format configuration*/ + layer.PixelFormat = LTDC_PIXEL_FORMAT_RGB565; + + /* Alpha constant (255 totally opaque) */ + layer.Alpha = 255; + + /* Default Color configuration (configure A,R,G,B component values) */ + layer.Backcolor.Blue = 0; + layer.Backcolor.Green = 0; + layer.Backcolor.Red = 0; + layer.Alpha0 = 0; + + /* Configure blending factors */ + layer.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA; + layer.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA; + + layer.ImageWidth = lcd_phys_w; + layer.ImageHeight = lcd_phys_h; + + /* Start Address configuration : the LCD Frame buffer is defined on SDRAM w/ Offset */ + layer.FBStartAdress = (intptr_t)initialFrameBuffer; + + /* Initialize LTDC layer 1 */ + HAL_LTDC_ConfigLayer(&hltdc, &hltdc.LayerCfg[0], 0); + + /* dithering activation */ + HAL_LTDC_EnableDither(&hltdc); +} + +extern "C" +void lcdSetInitalFrameBuffer(void* fbAddress) +{ + initialFrameBuffer = fbAddress; +} + +const char* boardLcdType = ""; + +extern "C" +void lcdInit(void) +{ + /* Configure the LCD SPI+RESET pins */ + lcdSpiConfig(); + + /* Reset the LCD --------------------------------------------------------*/ + lcdReset(); + + /* Configure the LCD Control pins */ + LCD_AF_GPIOConfig(); + + /* Send LCD initialization commands */ +// if (LCD_ILI9481_ReadID() == LCD_ILI9481_ID) { +// TRACE("LCD INIT: ILI9481"); +// boardLcdType = "ILI9481"; +// lcdInitFunction = LCD_ILI9481_Init; +// lcdOffFunction = LCD_ILI9481_Off; +// lcdOnFunction = LCD_ILI9481_On; +// lcdPixelClock = 12000000; +// } else if (LCD_ILI9486_ReadID() == LCD_ILI9486_ID) { +// TRACE("LCD INIT: ILI9486"); +// boardLcdType = "ILI9486"; +// lcdInitFunction = LCD_ILI9486_Init; +// lcdOffFunction = LCD_ILI9486_Off; +// lcdOnFunction = LCD_ILI9486_On; +// lcdPixelClock = 12000000; +// } else if (LCD_ILI9488_ReadID() == LCD_ILI9488_ID) { +// TRACE("LCD INIT: ILI9488"); +// boardLcdType = "ILI9488"; +// lcdInitFunction = LCD_ILI9488_Init; +// lcdOffFunction = LCD_ILI9488_Off; +// lcdOnFunction = LCD_ILI9488_On; +// lcdPixelClock = 12000000; +// lcd_phys_w = LCD_PHYS_H; +// lcd_phys_h = LCD_PHYS_W; +// } else if (LCD_HX8357D_ReadID() == LCD_HX8357D_ID) { +// TRACE("LCD INIT: HX8357D"); +// boardLcdType = "HX8357D"; +// lcdInitFunction = LCD_HX8357D_Init; +// lcdOffFunction = LCD_HX8357D_Off; +// lcdOnFunction = LCD_HX8357D_On; +// lcdPixelClock = 12000000; +// } else if (LCD_ST7796S_ReadID() == LCD_ST7796S_ID ) { +// TRACE("LCD INIT: ST7796S"); +// boardLcdType = "ST7796S"; +// lcdInitFunction = LCD_ST7796S_Init; +// lcdOffFunction = LCD_ST7796S_Off; +// lcdOnFunction = LCD_ST7796S_On; +// lcdPixelClock = 14500000; +// } +// else{ + TRACE("LCD INIT (default): ST7796S"); + boardLcdType = "ST7796S (Default)"; + lcdInitFunction = LCD_ST7796S_Init; + lcdOffFunction = LCD_ST7796S_Off; + lcdOnFunction = LCD_ST7796S_On; + lcdPixelClock = 12000000; +// } + + __HAL_RCC_LTDC_CLK_ENABLE(); + lcdInitFunction(); + + LCD_Init_LTDC(); + LCD_LayerInit(); + + // Enable LCD display + __HAL_LTDC_ENABLE(&hltdc); + + lcdSetFlushCb(startLcdRefresh); +} + +extern "C" void LTDC_IRQHandler(void) +{ + __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); + __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); + _frame_addr_reloaded = 1; +} diff --git a/radio/src/targets/st16/lcd_driver.h b/radio/src/targets/st16/lcd_driver.h new file mode 100644 index 000000000..ccc1aa003 --- /dev/null +++ b/radio/src/targets/st16/lcd_driver.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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. + */ + +#pragma once + +#include "bsp_io.h" + +#define HBP ( 24 ) // TODO use names from FlySky +#define VBP ( 10 ) + +#define HSW ( 4 ) +#define VSH ( 2 ) + +#define HFP ( 140 - HBP ) +#define VFP ( 22 - VBP ) + +#define LCD_ST7796S_ID ( 0x7796 ) +#define LCD_ILI9481_ID ( 0x9481 ) +#define LCD_ILI9486_ID ( 0x9486 ) +#define LCD_ILI9488_ID ( 0x9488 ) +#define LCD_HX8357D_ID ( 0x99 ) + +#define LCD_DELAY() LCD_Delay() + +typedef void (*lcdSpiInitFucPtr)(void); +typedef unsigned int LcdReadIDFucPtr( void ); + +extern lcdSpiInitFucPtr lcdInitFunction; +extern lcdSpiInitFucPtr lcdOffFunction; +extern lcdSpiInitFucPtr lcdOnFunction; + +#define SET_IO_INPUT( PORT, PIN ) LL_GPIO_SetPinMode( PORT, PIN, LL_GPIO_MODE_INPUT ) +#define SET_IO_OUTPUT( PORT, PIN ) LL_GPIO_SetPinMode( PORT, PIN, LL_GPIO_MODE_OUTPUT ) + +#define LCD_NRST_HIGH() bsp_output_set(BSP_LCD_NRST) +#define LCD_NRST_LOW() bsp_output_clear(BSP_LCD_NRST) + +#define LCD_CS_HIGH() bsp_output_set(BSP_LCD_CS) +#define LCD_CS_LOW() bsp_output_clear(BSP_LCD_CS) + +#define LCD_SCK_HIGH() LL_GPIO_SetOutputPin(LCD_SPI_GPIO, LCD_SPI_SCK_GPIO_PIN) +#define LCD_SCK_LOW() LL_GPIO_ResetOutputPin(LCD_SPI_GPIO, LCD_SPI_SCK_GPIO_PIN) + +#define LCD_MOSI_HIGH() LL_GPIO_SetOutputPin(LCD_SPI_GPIO, LCD_SPI_MOSI_GPIO_PIN) +#define LCD_MOSI_LOW() LL_GPIO_ResetOutputPin(LCD_SPI_GPIO, LCD_SPI_MOSI_GPIO_PIN) + +#define LCD_MOSI_AS_INPUT() SET_IO_INPUT( LCD_SPI_GPIO, LCD_SPI_MOSI_GPIO_PIN ) +#define LCD_MOSI_AS_OUTPUT() SET_IO_OUTPUT( LCD_SPI_GPIO, LCD_SPI_MOSI_GPIO_PIN ) + +#define LCD_READ_DATA_PIN() LL_GPIO_IsInputPinSet(LCD_SPI_GPIO, LCD_SPI_MOSI_GPIO_PIN) + + +#if 1 +#define HORIZONTAL_SYNC_WIDTH ( 4 ) +#define HORIZONTAL_BACK_PORCH ( 24 ) +#define HORIZONTAL_FRONT_PORCH ( 140 - HORIZONTAL_BACK_PORCH ) +#define VERTICAL_SYNC_HEIGHT ( 2 ) +#define VERTICAL_BACK_PORCH ( 10 ) +#define VERTICAL_FRONT_PORCH ( 22 - VERTICAL_BACK_PORCH ) +#else +#define HORIZONTAL_SYNC_WIDTH ( 4 ) +#define HORIZONTAL_BACK_PORCH ( 20 ) +#define HORIZONTAL_FRONT_PORCH ( 60 - HORIZONTAL_BACK_PORCH ) +#define VERTICAL_SYNC_HEIGHT ( 2 ) +#define VERTICAL_BACK_PORCH ( 6 ) +#define VERTICAL_FRONT_PORCH ( 14 - VERTICAL_BACK_PORCH ) +#endif diff --git a/radio/src/targets/st16/led_driver.cpp b/radio/src/targets/st16/led_driver.cpp new file mode 100644 index 000000000..c6bc8d598 --- /dev/null +++ b/radio/src/targets/st16/led_driver.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "hal/gpio.h" +#include "hal/rgbleds.h" +#include "stm32_gpio.h" +#include "boards/generic_stm32/rgb_leds.h" +#include "board.h" +#if defined(LED_STRIP_GPIO) +#include "boards/generic_stm32/rgb_leds.h" +#endif + +#define GET_RED(color) (((color) & 0xFF0000) >>16) +#define GET_GREEN(color) (((color) & 0x00FF00) >> 8) +#define GET_BLUE(color) ((color) & 0x0000FF) + +#if defined(FUNCTION_SWITCHES) && !defined(FUNCTION_SWITCHES_RGB_LEDS) +static const uint32_t fsLeds[] = {FSLED_GPIO_PIN_1, FSLED_GPIO_PIN_2, + FSLED_GPIO_PIN_3, FSLED_GPIO_PIN_4, + FSLED_GPIO_PIN_5, FSLED_GPIO_PIN_6}; +#endif + +void ledInit() +{ +#if defined(LED_GREEN_GPIO) + gpio_init(LED_GREEN_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW); +#endif + +#if defined(LED_RED_GPIO) + gpio_init(LED_RED_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW); +#endif + +#if defined(LED_BLUE_GPIO) + gpio_init(LED_BLUE_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW); +#endif + +#if defined(FUNCTION_SWITCHES) && !defined(FUNCTION_SWITCHES_RGB_LEDS) + for (size_t i = 0; i < DIM(fsLeds); i++) { + gpio_init(fsLeds[i], GPIO_OUT, GPIO_PIN_SPEED_LOW); + } +#endif +} + +#if defined(FUNCTION_SWITCHES_RGB_LEDS) +// used to map switch number to led number in the rgbled chain +uint8_t ledMapping[] = {12, 14, 16, 18, 20, 22}; + +void fsLedRGB(uint8_t index, uint32_t color) +{ + rgbSetLedColor(ledMapping[index], GET_RED(color), \ + GET_GREEN(color),GET_BLUE(color)); + rgbSetLedColor(ledMapping[index]+1, GET_RED(color), \ + GET_GREEN(color),GET_BLUE(color)); +} + +uint8_t getRGBColorIndex(uint32_t color) +{ + for (uint8_t i = 0; i < (sizeof(colorTable) / sizeof(colorTable[0])); i++) { + if (color == colorTable[i]) + return(i); + } + return 5; // Custom value set with Companion +} +#elif defined(FUNCTION_SWITCHES) +void fsLedOff(uint8_t index) +{ + gpio_clear(fsLeds[index]); +} + +void fsLedOn(uint8_t index) +{ + gpio_set(fsLeds[index]); +} + +bool fsLedState(uint8_t index) +{ + return gpio_read(fsLeds[index]) ? true : false; +} +#endif + +void ledOff() +{ +#if defined(LED_RED_GPIO) + GPIO_LED_GPIO_OFF(LED_RED_GPIO); +#endif +#if defined(LED_BLUE_GPIO) + GPIO_LED_GPIO_OFF(LED_BLUE_GPIO); +#endif +#if defined(LED_GREEN_GPIO) + GPIO_LED_GPIO_OFF(LED_GREEN_GPIO); +#endif +} + +void ledRed() +{ +#if defined(LED_RED_GPIO) + GPIO_LED_GPIO_ON(LED_RED_GPIO); +#endif +} + +void ledGreen() +{ +#if defined(LED_GREEN_GPIO) + GPIO_LED_GPIO_ON(LED_GREEN_GPIO); +#endif +} + +void ledBlue() +{ +#if defined(LED_BLUE_GPIO) + GPIO_LED_GPIO_ON(LED_BLUE_GPIO); +#endif +} diff --git a/radio/src/targets/st16/libopenui_config.h b/radio/src/targets/st16/libopenui_config.h new file mode 100644 index 000000000..7fa1b09a6 --- /dev/null +++ b/radio/src/targets/st16/libopenui_config.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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. + */ + +#pragma once + +constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 132; +constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = INPUT_EDIT_CURVE_WIDTH; +constexpr coord_t MENUS_MAX_HEIGHT = (MENUS_LINE_HEIGHT * 8) + 8; + diff --git a/radio/src/targets/st16/sdram_driver.cpp b/radio/src/targets/st16/sdram_driver.cpp new file mode 100644 index 000000000..0e95725af --- /dev/null +++ b/radio/src/targets/st16/sdram_driver.cpp @@ -0,0 +1,252 @@ +/* + * 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 "hal/gpio.h" +#include "stm32_gpio.h" +#include "stm32_hal_ll.h" + +#include "board.h" + +#define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_16 + +#define SDRAM_CAS_LATENCY FMC_SDRAM_CAS_LATENCY_3 + +#define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_2 + +#define SDRAM_TIMEOUT ((uint32_t)0xFFFF) + +#define SDRAM_READBURST FMC_SDRAM_RBURST_DISABLE + +#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) +#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) +#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) +#define SDRAM_MODEREG_BURST_FULL_PAGE ((uint16_t)0x0007) +#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) +#define SDRAM_MODEREG_CAS_LATENCY_1 ((uint16_t)0x0010) +#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) +#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) +#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) + +#define GPIO_AF_FMC GPIO_AF12 + +extern "C" void SDRAM_GPIOConfig(void) +{ + /*-- GPIOs Configuration -----------------------------------------------------*/ + /* + */ + + /* GPIOD configuration */ + gpio_init_af(GPIO_PIN(GPIOD, 0), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOD, 1), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOD, 8), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOD, 9), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOD, 10), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOD, 14), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOD, 15), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + + /* GPIOE configuration */ + gpio_init_af(GPIO_PIN(GPIOE, 0), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 1), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 7), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 8), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 9), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 10), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 11), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 12), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 13), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 14), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 15), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + + /* GPIOF configuration */ + gpio_init_af(GPIO_PIN(GPIOF, 0), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 1), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 2), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 3), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 4), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 5), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 11), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 12), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 13), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 14), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 15), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + + /* GPIOG configuration */ + gpio_init_af(GPIO_PIN(GPIOG, 0), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOG, 1), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOG, 4), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOG, 5), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOG, 8), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOG, 15), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + + + gpio_init_af(GPIO_PIN(GPIOH, 2), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOH, 3), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOH, 5), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + +} + +extern "C" void SDRAM_InitSequence(void) +{ + FMC_SDRAM_CommandTypeDef FMC_SDRAMCommandStructure; + uint32_t tmpr = 0; + uint32_t timeout = SDRAM_TIMEOUT; + + /* Step 3 --------------------------------------------------------------------*/ + /* Configure a clock configuration enable command */ + FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; + FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + FMC_SDRAMCommandStructure.AutoRefreshNumber = 1; + FMC_SDRAMCommandStructure.ModeRegisterDefinition = 0; + /* Wait until the SDRAM controller is ready */ + // while((__FMC_SDRAM_GET_FLAG(FMC_Bank5_6_R, FMC_SDRAM_FLAG_BUSY) != 0) && + // (timeout > 0)) + // { + // timeout--; + // } + /* Send the command */ + FMC_SDRAM_SendCommand(FMC_Bank5_6_R, &FMC_SDRAMCommandStructure, 10); + + /* Step 4 --------------------------------------------------------------------*/ + /* Insert 1 ms delay */ + delay_ms(100); + + /* Step 5 --------------------------------------------------------------------*/ + /* Configure a PALL (precharge all) command */ + FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_PALL; + FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + FMC_SDRAMCommandStructure.AutoRefreshNumber = 1; + FMC_SDRAMCommandStructure.ModeRegisterDefinition = 0; + /* Wait until the SDRAM controller is ready */ + // timeout = SDRAM_TIMEOUT; + // while((__FMC_SDRAM_GET_FLAG(FMC_Bank5_6_R, FMC_SDRAM_FLAG_BUSY) != 0) && (timeout > 0)) + // { + // timeout--; + // } + /* Send the command */ + FMC_SDRAM_SendCommand(FMC_Bank5_6_R, &FMC_SDRAMCommandStructure, 10); + // delay_ms(1); + + /* Step 6 --------------------------------------------------------------------*/ + /* Configure a Auto-Refresh command */ + FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; + FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + FMC_SDRAMCommandStructure.AutoRefreshNumber = 8; + FMC_SDRAMCommandStructure.ModeRegisterDefinition = 0; + + /* Wait until the SDRAM controller is ready */ + // timeout = SDRAM_TIMEOUT; + // while((__FMC_SDRAM_GET_FLAG(FMC_Bank5_6_R, FMC_SDRAM_FLAG_BUSY) != 0) && + // (timeout > 0)) + // { + // timeout--; + // } + /* Send the command */ + FMC_SDRAM_SendCommand(FMC_Bank5_6_R, &FMC_SDRAMCommandStructure, 10); + // delay_ms(1); + + /* Step 7 --------------------------------------------------------------------*/ + /* Program the external memory mode register */ + tmpr = (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; + + /* Configure a load Mode register command*/ + FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; + FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + FMC_SDRAMCommandStructure.AutoRefreshNumber = 1; + FMC_SDRAMCommandStructure.ModeRegisterDefinition = tmpr; + + /* Wait until the SDRAM controller is ready */ + // timeout = SDRAM_TIMEOUT; + // while((__FMC_SDRAM_GET_FLAG(FMC_Bank5_6_R, FMC_SDRAM_FLAG_BUSY) != 0) && (timeout > 0)) + // { + // timeout--; + // } + /* Send the command */ + FMC_SDRAM_SendCommand(FMC_Bank5_6_R, &FMC_SDRAMCommandStructure, 10); + // delay_ms(1); + + /* Step 8 --------------------------------------------------------------------*/ + /* Set the refresh rate counter */ + /* (15.62 us x Freq) - 20 */ + /* Set the device refresh counter */ + FMC_SDRAM_SetAutoRefreshNumber(FMC_Bank5_6_R, 15); + FMC_SDRAM_ProgramRefreshRate(FMC_Bank5_6_R, 1855); + /* Wait until the SDRAM controller is ready */ + // timeout = SDRAM_TIMEOUT; + // while((__FMC_SDRAM_GET_FLAG(FMC_Bank5_6_R, FMC_SDRAM_FLAG_BUSY) != 0) && (timeout > 0)) + // { + // timeout--; + // } + // delay_ms(1); +} + +extern "C" void SDRAM_Init(void) +{ + //delay funcion needed + delaysInit(); + + /* GPIO configuration for FMC SDRAM bank */ + SDRAM_GPIOConfig(); + + /* Enable FMC clock */ + LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_FMC); + + /* FMC Configuration ---------------------------------------------------------*/ + FMC_SDRAM_InitTypeDef FMC_SDRAMInitStructure; + FMC_SDRAM_TimingTypeDef FMC_SDRAMTimingInitStructure; + + /* FMC SDRAM Bank configuration */ + /* Timing configuration for 80 Mhz of SD clock */ + FMC_SDRAMTimingInitStructure.LoadToActiveDelay = 2; + FMC_SDRAMTimingInitStructure.ExitSelfRefreshDelay = 7; + FMC_SDRAMTimingInitStructure.SelfRefreshTime = 4; + FMC_SDRAMTimingInitStructure.RowCycleDelay = 7; + FMC_SDRAMTimingInitStructure.WriteRecoveryTime = 3; + FMC_SDRAMTimingInitStructure.RPDelay = 2; + FMC_SDRAMTimingInitStructure.RCDDelay = 2; + + /* FMC SDRAM control configuration */ + FMC_SDRAMInitStructure.SDBank = FMC_SDRAM_BANK1; + FMC_SDRAMInitStructure.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8; + FMC_SDRAMInitStructure.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; + FMC_SDRAMInitStructure.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16; + FMC_SDRAMInitStructure.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; + FMC_SDRAMInitStructure.CASLatency = FMC_SDRAM_CAS_LATENCY_3; + FMC_SDRAMInitStructure.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; + FMC_SDRAMInitStructure.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2; + FMC_SDRAMInitStructure.ReadBurst = FMC_SDRAM_RBURST_ENABLE; + FMC_SDRAMInitStructure.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0; + + /* FMC SDRAM bank initialization */ + FMC_SDRAM_Init(FMC_Bank5_6_R, &FMC_SDRAMInitStructure); + FMC_SDRAM_Timing_Init(FMC_Bank5_6_R, &FMC_SDRAMTimingInitStructure, FMC_SDRAM_BANK1); + + __FMC_ENABLE(); + + /* FMC SDRAM device initialization sequence */ + SDRAM_InitSequence(); +} diff --git a/radio/src/targets/st16/system_clock.cpp b/radio/src/targets/st16/system_clock.cpp new file mode 100644 index 000000000..05e3dd5bc --- /dev/null +++ b/radio/src/targets/st16/system_clock.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "stm32h7xx_ll_pwr.h" +#include "stm32h7xx_ll_rcc.h" +#include "stm32h7xx_ll_system.h" +#include "stm32h7xx_ll_bus.h" + +#define BOOTSTRAP __attribute__((section(".bootstrap"))) + +extern "C" BOOTSTRAP +void SystemClock_Config(void) +{ + /* Power Configuration */ + LL_PWR_ConfigSupply(LL_PWR_LDO_SUPPLY); + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); + while (LL_PWR_IsActiveFlag_VOS() == 0){ + } + + /* Enable HSE oscillator */ + LL_RCC_HSE_Enable(); + while (LL_RCC_HSE_IsReady() != 1) { + } + + /* Set FLASH latency */ + LL_FLASH_SetLatency(LL_FLASH_LATENCY_5); + + /* Main PLL configuration and activation */ + LL_RCC_PLL_SetSource(LL_RCC_PLLSOURCE_HSE); + LL_RCC_PLL1P_Enable(); + LL_RCC_PLL1Q_Enable(); + LL_RCC_PLL1R_Enable(); + LL_RCC_PLL1FRACN_Disable(); + LL_RCC_PLL1_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_2_4); + LL_RCC_PLL1_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE); + LL_RCC_PLL1_SetM(1); + LL_RCC_PLL1_SetN(100); + LL_RCC_PLL1_SetP(2); + LL_RCC_PLL1_SetQ(4); + LL_RCC_PLL1_SetR(2); + LL_RCC_PLL1_Enable(); + while (LL_RCC_PLL1_IsReady() != 1) { + } + + /* Set Sys & AHB & APB1 & APB2 & APB4 prescaler */ + LL_RCC_SetSysPrescaler(LL_RCC_SYSCLK_DIV_1); + LL_RCC_SetAHBPrescaler(LL_RCC_AHB_DIV_2); + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2); + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_2); + LL_RCC_SetAPB4Prescaler(LL_RCC_APB4_DIV_2); + + /* Set PLL1 as System Clock Source */ + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL1); + while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL1) { + } + + /* Config & activate PLL2 */ + LL_RCC_PLL2P_Enable(); + LL_RCC_PLL2Q_Enable(); + LL_RCC_PLL2R_Enable(); + LL_RCC_PLL2FRACN_Disable(); + LL_RCC_PLL2_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_2_4); + LL_RCC_PLL2_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE); + LL_RCC_PLL2_SetM(1); + LL_RCC_PLL2_SetN(120); + LL_RCC_PLL2_SetP(12); + LL_RCC_PLL2_SetQ(2); + LL_RCC_PLL2_SetR(4); + LL_RCC_PLL2_Enable(); + while (LL_RCC_PLL2_IsReady() != 1) { + } + + /* Config & activate PLL3 */ + LL_RCC_PLL3P_Enable(); + LL_RCC_PLL3Q_Enable(); + LL_RCC_PLL3R_Enable(); + LL_RCC_PLL3FRACN_Disable(); + LL_RCC_PLL3_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_2_4); + LL_RCC_PLL3_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE); + LL_RCC_PLL3_SetM(1); + LL_RCC_PLL3_SetN(120); + LL_RCC_PLL3_SetP(5); + LL_RCC_PLL3_SetQ(20); + LL_RCC_PLL3_SetR(80); + LL_RCC_PLL3_Enable(); + while (LL_RCC_PLL3_IsReady() != 1) { + } + + /* Enable SRAM1, SRAM2 & SRAM3 */ + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_D2SRAM1 | + LL_AHB2_GRP1_PERIPH_D2SRAM2 | + LL_AHB2_GRP1_PERIPH_D2SRAM3); + + /* Set periph clock sources */ + LL_RCC_SetFMCClockSource(LL_RCC_FMC_CLKSOURCE_HCLK); + LL_RCC_SetSPIClockSource(LL_RCC_SPI123_CLKSOURCE_PLL3P); + LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLL3Q); + LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_CLKP); +} diff --git a/radio/src/targets/st16/system_clock.h b/radio/src/targets/st16/system_clock.h new file mode 100644 index 000000000..758d63c32 --- /dev/null +++ b/radio/src/targets/st16/system_clock.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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. + */ + +extern "C" void SystemClock_Config(); + diff --git a/radio/src/targets/st16/system_init.cpp b/radio/src/targets/st16/system_init.cpp new file mode 100644 index 000000000..dc85d078f --- /dev/null +++ b/radio/src/targets/st16/system_init.cpp @@ -0,0 +1,222 @@ +#include +#include "stm32_cmsis.h" +#include "system_clock.h" + +#include "stm32_hal.h" + +#define NAKED __attribute__((naked)) +#define BOOTSTRAP __attribute__((section(".bootstrap"))) + +// Linker script symbols +extern uint32_t _sisr_vector; +extern uint32_t SDRAM_START; + +extern "C" NAKED BOOTSTRAP +void Reset_Handler() +{ + asm inline ( + "ldr sp, =_estack \n" + ); + +#if defined(BOOT) + asm inline ( + "bl SystemInit \n" + "bl SystemClock_Config \n" + "bl CPU_CACHE_Enable \n" + ); +#endif + + // Copy code into normal RAM + asm inline ( + "ldr r0, =_stext \n" + "ldr r1, =_etext \n" + "ldr r2, =_text_load \n" + "bl naked_copy \n" + ); + +#if defined(BOOT) + asm inline ( + "bl MPU_Init \n" + ); +#endif + + // Copy / setup ISR vector + asm inline ( + "ldr r0, =_sisr_vector \n" + "ldr r1, =_eisr_vector \n" + "ldr r2, =_isr_load \n" + "bl naked_copy \n" + "bl set_vtor \n" + ); + + // Copy code into fast RAM + asm inline ( + "ldr r0, =_siram \n" + "ldr r1, =_eiram \n" + "ldr r2, =_stext_iram \n" + "bl naked_copy \n" + ); + + // Copy initialized data segment + asm inline ( + "ldr r0, =_sdata \n" + "ldr r1, =_edata \n" + "ldr r2, =_sidata \n" + "bl naked_copy \n" + ); + +#if defined(BOOT) + asm inline ( + "bl pwrResetHandler \n" + ); +#endif + + // Zero fill bss segment + asm inline ( + "ldr r2, =_sbss \n" + "ldr r4, =_ebss \n" + "movs r3, 0 \n" + "b LoopFillZerobss \n" + + "FillZerobss: \n" + "str r3, [r2] \n" + "adds r2, r2, 4 \n" + + "LoopFillZerobss: \n" + "cmp r2, r4 \n" + "bcc FillZerobss \n" + ); + + asm inline ( + "bl clean_dcache \n" + // Call static constructors + "bl __libc_init_array \n" + "bl SystemCoreClockUpdate \n" + // Call the application's entry point + "bl main \n" + "bx lr \n" + ); +} + +extern "C" BOOTSTRAP void set_vtor() { + SCB->VTOR = (intptr_t)&_sisr_vector; +} + +extern "C" NAKED BOOTSTRAP void naked_copy() { + // r0: destination start + // r1: destination end + // r2: source start + asm inline ( + "cmp r0, r2 \n" + "beq SkipCopy \n" + "movs r3, 0 \n" + "b LoopCopyInit \n" + + "CopyInit: \n" + "ldr r4, [r2, r3] \n" + "str r4, [r0, r3] \n" + "adds r3, r3, #4 \n" + + "LoopCopyInit: \n" + "adds r4, r0, r3 \n" + "cmp r4, r1 \n" + "bcc CopyInit \n" + "SkipCopy: \n" + "bx lr \n" + ); +} + +extern "C" BOOTSTRAP +void CPU_CACHE_Enable() +{ + /* Enable I-Cache */ + SCB_EnableICache(); + + /* Enable D-Cache */ + SCB_EnableDCache(); +} + +extern "C" __attribute__((used)) +void MPU_Init() +{ + MPU_Region_InitTypeDef MPU_InitStruct = {0}; + + /* Disables the MPU */ + HAL_MPU_Disable(); + + /* + * Region 0: overwrite default setting to prevent speculative + * read to unavailable memories. + * Range: 0x60000000 to 0xE0000000 + * + * Set as strongly ordered, code execution disabled + */ + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = MPU_REGION_NUMBER0; + MPU_InitStruct.BaseAddress = 0; + MPU_InitStruct.Size = MPU_REGION_SIZE_4GB; + MPU_InitStruct.SubRegionDisable = 0x87; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; + MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; + HAL_MPU_ConfigRegion(&MPU_InitStruct); + +#if defined(FIRMWARE_QSPI) + /* Region 2: QSPI memory range, bank1 */ + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = MPU_REGION_NUMBER2; + MPU_InitStruct.BaseAddress = 0x90000000; + MPU_InitStruct.Size = MPU_REGION_SIZE_8MB; + MPU_InitStruct.SubRegionDisable = 0x0; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; + MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; + HAL_MPU_ConfigRegion(&MPU_InitStruct); +#endif + +#if defined(SDRAM) + /* Region 3: SDRAM memory range */ + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = MPU_REGION_NUMBER3; + MPU_InitStruct.BaseAddress = (uint32_t)&SDRAM_START; + MPU_InitStruct.Size = MPU_REGION_SIZE_8MB; + MPU_InitStruct.SubRegionDisable = 0x0; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; + MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; + HAL_MPU_ConfigRegion(&MPU_InitStruct); +#endif + + /* Region 3: SRAM1 memory range */ + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = MPU_REGION_NUMBER4; + MPU_InitStruct.BaseAddress = 0x30000000; + MPU_InitStruct.Size = MPU_REGION_SIZE_32KB; + MPU_InitStruct.SubRegionDisable = 0x0; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; + MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; + HAL_MPU_ConfigRegion(&MPU_InitStruct); + + + HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); + + /* Enable bus fault exception */ + SCB->SHCSR |= SCB_SHCSR_BUSFAULTENA_Msk; +} + +extern "C" void clean_dcache() { + SCB_CleanDCache(); +} diff --git a/radio/src/targets/st16/touch_driver.cpp b/radio/src/targets/st16/touch_driver.cpp new file mode 100644 index 000000000..e246cd65c --- /dev/null +++ b/radio/src/targets/st16/touch_driver.cpp @@ -0,0 +1,477 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "stm32_hal_ll.h" +#include "stm32_hal.h" +#include "stm32_i2c_driver.h" +#include "stm32_gpio_driver.h" +#include "stm32_exti_driver.h" + +#include "hal.h" +#include "timers_driver.h" +#include "delays_driver.h" +#include "touch_driver.h" + +#include "debug.h" + +#define TAP_TIME 25 +#define I2C_TIMEOUT_MAX 5 // 5 ms + +// FT6236 definitions +#define TOUCH_FT6236_I2C_ADDRESS (0x70>>1) +#define TOUCH_FT6236_REG_TH_GROUP 0x80 +#define TOUCH_FT6236_REG_PERIODACTIVE 0x88 +#define TOUCH_FT6236_REG_LIB_VER_H 0xa1 +#define TOUCH_FT6236_REG_LIB_VER_L 0xa2 +#define TOUCH_FT6236_REG_CIPHER 0xa3 +#define TOUCH_FT6236_REG_FIRMID 0xa6 +#define TOUCH_FT6236_REG_FOCALTECH_ID 0xa8 +#define TOUCH_FT6236_REG_RELEASE_CODE_ID 0xaf +#define TOUCH_FT6206_REG_TD_STAT 0x02 +#define TOUCH_FT6206_REG_P1_XH 0x03 +#define TOUCH_FT6206_EVT_SHIFT 6 +#define TOUCH_FT6206_EVT_MASK (3 << TOUCH_FT6206_EVT_SHIFT) +#define TOUCH_FT6206_EVT_CONTACT 0x02 +#define TOUCH_FT6206_MASK_TD_STAT 0x0f + +// CST340 definitions +#define TOUCH_CST340_I2C_ADDRESS 0x1a +#define TOUCH_CST340_REG_FINGER1 0x00 +#define TOUCH_CST340_EVT_CONTACT 0x06 + +// CHSC5448 definitions +#define TOUCH_CHSC5448_I2C_ADDRESS 0x2e +#define TOUCH_CHSC5448_REG_ADDR 0x2c000020 +#define TOUCH_CHSC5448_EVT_CONTACT 0x08 +#define TOUCH_CHSC5448_MAX_POINTS 5 + +// CST836U definitions +#define TOUCH_CST836U_I2C_ADDRESS (0x15) +#define TOUCH_CST836U_TOUCH_NUM_REG 0x02 +#define TOUCH_CST836U_TOUCH1_XH_REG 0x03 +#define TOUCH_CST836U_MSB_MASK 0x0F + +typedef enum {TC_NONE, TC_FT6236, TC_CST340, TC_CHSC5448, TC_CST836U} TouchController; + +#if defined(DEBUG) +const char TOUCH_CONTROLLER_STR[][10] = {"", "FT6236", "CST340", "CHSC5448", "CST836U"}; +#endif + +TouchController touchController = TC_NONE; + +struct TouchControllerDescriptor +{ + bool (*hasTouchEvent)(); + bool (*touchRead)(uint16_t * X, uint16_t * Y); + void (*printDebugInfo)(); + bool needTranspose; +}; + +union rpt_point_t +{ + struct + { + unsigned char x_l8; + unsigned char y_l8; + unsigned char z; + unsigned char x_h4:4; + unsigned char y_h4:4; + unsigned char id:4; + unsigned char event:4; + }rp; + unsigned char data[5]; +}; + +extern uint8_t TouchControllerType; + +static const TouchControllerDescriptor *tcd = nullptr; +static TouchState internalTouchState = {}; +volatile static bool touchEventOccured; +static tmr10ms_t downTime = 0; +static tmr10ms_t tapTime = 0; +static short tapCount = 0; + +static void _touch_exti_isr(void) +{ + touchEventOccured = true; +} + +static void _touch_exti_stop(void) {} +static void _touch_exti_config(void) {} +static void _touch_gpio_config(void) {} +static void _touch_reset() {} + +static int _i2c_read(uint8_t addr, uint32_t reg, uint8_t regSize, uint8_t* data, uint16_t len, uint32_t timeout, bool forceLong = false) +{ + if (regSize > 2 || forceLong) { + if(stm32_i2c_master_tx(TOUCH_I2C_BUS, addr, (uint8_t*) ®, regSize, 3) < 0) + return false; + delay_us(5); + if(stm32_i2c_master_rx(TOUCH_I2C_BUS, addr, data, len, I2C_TIMEOUT_MAX) < 0) + return false; + return true; + } else { + return stm32_i2c_read(TOUCH_I2C_BUS, addr, reg, regSize, data, len, timeout); + } +} + +static uint8_t _i2c_readRetry(uint8_t addr, uint32_t reg, uint8_t regSize) +{ + uint8_t result; + uint8_t tryCount = 3; + while (_i2c_read(addr, reg, regSize, &result, 1, I2C_TIMEOUT_MAX) < 0) { + if (--tryCount == 0) break; + } + return result; +} + +static uint16_t _i2c_readMultipleRetry(uint8_t addr, uint32_t reg, uint8_t regSize, uint8_t * buffer, uint16_t length, bool forceLong = false) +{ + uint8_t tryCount = 3; + while (_i2c_read(addr, reg, regSize, buffer, length, I2C_TIMEOUT_MAX, forceLong) < 0) { + if (--tryCount == 0) break; + } + return length; +} + +static bool ft6236TouchRead(uint16_t * X, uint16_t * Y) +{ + // Read register FT6206_TD_STAT_REG to check number of touches detection + uint8_t nbTouch = _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6206_REG_TD_STAT, 1); + nbTouch &= TOUCH_FT6206_MASK_TD_STAT; + bool hasTouch = nbTouch > 0; + + if (hasTouch) { + uint8_t dataxy[4]; + // Read X and Y positions and event + _i2c_readMultipleRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6206_REG_P1_XH, 1, dataxy, sizeof(dataxy)); + + // Send back ready X position to caller + *X = ((dataxy[0] & 0x0f) << 8) | dataxy[1]; + // Send back ready Y position to caller + *Y = ((dataxy[2] & 0x0f) << 8) | dataxy[3]; + + uint8_t event = (dataxy[0] & TOUCH_FT6206_EVT_MASK) >> TOUCH_FT6206_EVT_SHIFT; + return event == TOUCH_FT6206_EVT_CONTACT; + } + return false; +} + +static bool ft6236HasTouchEvent() +{ + touchEventOccured = true; + return true; + return touchEventOccured; +} + +static void ft6236PrintDebugInfo() +{ +#if defined(DEBUG)||1 + TRACE("ft6x36: thrhld = %d", _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_TH_GROUP, 1) * 4); + TRACE("ft6x36: rep rate=", _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_PERIODACTIVE, 1) * 10); + TRACE("ft6x36: fw lib 0x%02X %02X", _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_LIB_VER_H, 1), + _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_LIB_VER_L, 1)); + TRACE("ft6x36: fw v 0x%02X", _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_FIRMID, 1)); + TRACE("ft6x36: CHIP ID 0x%02X", _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_CIPHER, 1)); + TRACE("ft6x36: CTPM ID 0x%02X", _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_FOCALTECH_ID, 1)); + TRACE("ft6x36: rel code 0x%02X", _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_RELEASE_CODE_ID, 1)); +#endif + +} + +static bool cst340TouchRead(uint16_t * X, uint16_t * Y) +{ + uint8_t data[4]; + + // Read X and Y positions + _i2c_readMultipleRetry(TOUCH_CST340_I2C_ADDRESS, TOUCH_CST340_REG_FINGER1, 1, data, sizeof(data)); + + // Send back X position to caller + if (X) *X = ((data[1]<<4) + ((data[3]>>4)&0x0f)); + // Send back Y position to caller + if (Y) *Y = ((data[2]<<4) + ((data[3])&0x0f)); + + return data[0] == TOUCH_CST340_EVT_CONTACT; +} + +static bool cst340HasTouchEvent() +{ + static bool lastHasTouch = false; + bool ret = touchEventOccured; + if (ret) { + uint8_t hasTouch = cst340TouchRead(nullptr, nullptr); + if (!hasTouch && !lastHasTouch) { + TRACE("Interrupt occurs without touch event!!"); + touchEventOccured = false; + ret = false; + } + lastHasTouch = hasTouch; + } + + return ret; +} + +static void cst340PrintDebugInfo() +{ + // TODO, when necessary +} + +static bool chsc5448TouchRead(uint16_t * X, uint16_t * Y) +{ + static uint8_t readbuffer[84]; + const uint8_t reportSize = ((TOUCH_CHSC5448_MAX_POINTS * 5 + 2) + 3) & 0xfc; + + int ptCnt = 0; + union rpt_point_t* ppt; + + _i2c_readMultipleRetry(TOUCH_CHSC5448_I2C_ADDRESS, TOUCH_CHSC5448_REG_ADDR, 4, readbuffer, reportSize); + ptCnt = readbuffer[1] & 0x0f; + ppt = (union rpt_point_t*)&readbuffer[2]; + *X = ((ppt->rp.x_h4 & 0x0f) << 8) | ppt->rp.x_l8; + *Y = ((ppt->rp.y_h4 & 0x0f) << 8) | ppt->rp.y_l8; + uint8_t event = ppt->rp.event; + + return ptCnt > 0 && event == TOUCH_CHSC5448_EVT_CONTACT; +} + +static bool chsc5448HasTouchEvent() +{ + return touchEventOccured; +} + +static void chsc5448PrintDebugInfo() +{ + // TODO, when necessary +} + +static bool cst836uTouchRead(uint16_t * X, uint16_t * Y) +{ + uint8_t data[5]; + + // Read X and Y positions + _i2c_readMultipleRetry(TOUCH_CST836U_I2C_ADDRESS, TOUCH_CST836U_TOUCH_NUM_REG, 1, data, sizeof(data), true); + + // Send back X position to caller + if(X) *X = ((data[1] & TOUCH_CST836U_MSB_MASK) << 8) | data[2]; + // Send back Y position to caller + if(Y) *Y = ((data[3] & TOUCH_CST836U_MSB_MASK) << 8) | data[4]; + + return data[0] > 0 && data[0] <= 2; +} + +static bool cst836uHasTouchEvent() +{ + static bool lastHasTouch = false; + touchEventOccured = true; + bool ret = touchEventOccured; + if (ret||1) { + uint8_t data; + _i2c_readMultipleRetry(TOUCH_CST836U_I2C_ADDRESS, TOUCH_CST836U_TOUCH_NUM_REG, 1, &data, sizeof(data), true); + uint8_t hasTouch = data; + if(data > 2) + hasTouch = 0; + if (!hasTouch && !lastHasTouch) { + TRACE("Interrupt occurs without touch event!!"); + touchEventOccured = false; + ret = false; + } + lastHasTouch = hasTouch; + } + + return ret; +} + +static void cst836uPrintDebugInfo() +{ + // TODO, when necessary +} + +static const TouchControllerDescriptor FT6236 = +{ + .hasTouchEvent = ft6236HasTouchEvent, + .touchRead = ft6236TouchRead, + .printDebugInfo = ft6236PrintDebugInfo, + .needTranspose = true, +}; + +static const TouchControllerDescriptor CST340 = +{ + .hasTouchEvent = cst340HasTouchEvent, + .touchRead = cst340TouchRead, + .printDebugInfo = cst340PrintDebugInfo, + .needTranspose = true, +}; + +static const TouchControllerDescriptor CHSC5448 = +{ + .hasTouchEvent = chsc5448HasTouchEvent, + .touchRead = chsc5448TouchRead, + .printDebugInfo = chsc5448PrintDebugInfo, + .needTranspose = false, +}; + +static const TouchControllerDescriptor CST836U = +{ + .hasTouchEvent = cst836uHasTouchEvent, + .touchRead = cst836uTouchRead, + .printDebugInfo = cst836uPrintDebugInfo, + .needTranspose = true, +}; + +void _detect_touch_controller() +{ + if (stm32_i2c_is_dev_ready(TOUCH_I2C_BUS, TOUCH_CST340_I2C_ADDRESS, 3, I2C_TIMEOUT_MAX) == 0) { + touchController = TC_CST340; + tcd = &CST340; + TouchControllerType = 0; + } else if (stm32_i2c_is_dev_ready(TOUCH_I2C_BUS, TOUCH_CHSC5448_I2C_ADDRESS, 3, I2C_TIMEOUT_MAX) == 0) { + touchController = TC_CHSC5448; + tcd = &CHSC5448; + TouchControllerType = 0; + } else if (stm32_i2c_is_dev_ready(TOUCH_I2C_BUS, TOUCH_FT6236_I2C_ADDRESS, 3, I2C_TIMEOUT_MAX) == 0) { + touchController = TC_FT6236; + tcd = &FT6236; + TouchControllerType = 0; + } else if (stm32_i2c_is_dev_ready(TOUCH_I2C_BUS, TOUCH_CST836U_I2C_ADDRESS, 3, I2C_TIMEOUT_MAX) == 0) { + touchController = TC_CST836U; + tcd = &CST836U; + TouchControllerType = 1; + } else { + touchController = TC_NONE; + } +} + +void touchPanelDeInit() +{ + _touch_exti_stop(); +} + +bool touchPanelInit() +{ + _touch_gpio_config(); + _touch_reset(); + _detect_touch_controller(); + _touch_exti_config(); + + if(touchController != TC_NONE) + tcd->printDebugInfo(); + + return touchController != TC_NONE; +} + +bool touchPanelEventOccured() +{ + if(touchController == TC_NONE) + return false; + return tcd->hasTouchEvent(); +} + +struct TouchState touchPanelRead() +{ + if (!touchEventOccured || touchController == TC_NONE) return internalTouchState; + + touchEventOccured = false; + + tmr10ms_t now = get_tmr10ms(); + internalTouchState.tapCount = 0; + unsigned short touchX; + unsigned short touchY; + bool hasTouchContact = tcd->touchRead(&touchX, &touchY); + + if (tcd->needTranspose) { + // Touch sensor is rotated by 90 deg + unsigned short tmp = touchY; + touchY = 319 - touchX; + touchX = tmp; + } + + if (hasTouchContact) { + int dx = touchX - internalTouchState.x; + int dy = touchY - internalTouchState.y; + internalTouchState.x = touchX; + internalTouchState.y = touchY; + + if (internalTouchState.event == TE_NONE || internalTouchState.event == TE_UP || internalTouchState.event == TE_SLIDE_END) { + internalTouchState.startX = internalTouchState.x; + internalTouchState.startY = internalTouchState.y; + internalTouchState.event = TE_DOWN; + } + else if (internalTouchState.event == TE_DOWN) { + if (dx >= SLIDE_RANGE || dx <= -SLIDE_RANGE || dy >= SLIDE_RANGE || dy <= -SLIDE_RANGE) { + internalTouchState.event = TE_SLIDE; + internalTouchState.deltaX = (short) dx; + internalTouchState.deltaY = (short) dy; + } + else { + internalTouchState.event = TE_DOWN; + internalTouchState.deltaX = 0; + internalTouchState.deltaY = 0; + } + } + else if (internalTouchState.event == TE_SLIDE) { + internalTouchState.event = TE_SLIDE; //no change + internalTouchState.deltaX = (short) dx; + internalTouchState.deltaY = (short) dy; + } + + if (internalTouchState.event == TE_DOWN && downTime == 0) { + downTime = now; + } + } + else { + if (internalTouchState.event == TE_DOWN) { + internalTouchState.event = TE_UP; + if (now - downTime <= TAP_TIME) { + if (now - tapTime > TAP_TIME) { + tapCount = 1; + } else { + tapCount++; + } + internalTouchState.tapCount = tapCount; + tapTime = now; + } else { + internalTouchState.tapCount = 0; // not a tap + } + downTime = 0; + } else { + tapCount = 0; + internalTouchState.tapCount = 0; + internalTouchState.event = TE_SLIDE_END; + } + } + + TouchState ret = internalTouchState; + internalTouchState.deltaX = 0; + internalTouchState.deltaY = 0; + if (internalTouchState.event == TE_UP || internalTouchState.event == TE_SLIDE_END) + internalTouchState.event = TE_NONE; + +#if defined(DEBUG) + TRACE("%s: event=%d,X=%d,Y=%d", TOUCH_CONTROLLER_STR[touchController], ret.event, ret.x, ret.y); +#endif + + return ret; +} + +struct TouchState getInternalTouchState() +{ + return internalTouchState; +} diff --git a/radio/src/targets/st16/touch_driver.h b/radio/src/targets/st16/touch_driver.h new file mode 100644 index 000000000..6b0fb01a8 --- /dev/null +++ b/radio/src/targets/st16/touch_driver.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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. + */ + +#pragma once + +#include "touch.h" + +extern void touchPanelDeInit(); +extern bool touchPanelInit(); + +struct TouchState touchPanelRead(); +bool touchPanelEventOccured(); +struct TouchState getInternalTouchState(); diff --git a/radio/src/targets/st16/tp_cst340.cpp b/radio/src/targets/st16/tp_cst340.cpp new file mode 100644 index 000000000..c8e633ff3 --- /dev/null +++ b/radio/src/targets/st16/tp_cst340.cpp @@ -0,0 +1,560 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 "stm32_hal_ll.h" +#include "stm32_hal.h" +#include "stm32_i2c_driver.h" +#include "stm32_gpio_driver.h" +#include "stm32_exti_driver.h" + +#include "hal.h" +#include "timers_driver.h" +#include "delays_driver.h" +#include "tp_cst340.h" + +#include "debug.h" + +#define TOUCH_FT6236_I2C_ADDRESS (0x70>>1) +#define TOUCH_CST340_I2C_ADDRESS 0x1A + + +extern uint8_t TouchControllerType; + +volatile static bool touchEventOccured; +enum TouchControllers {TC_NONE, TC_FT6236, TC_CST340}; +TouchControllers touchController = TC_NONE; + +static tc_handle_TypeDef tc_handle = {0, 0}; + +tmr10ms_t downTime = 0; +tmr10ms_t tapTime = 0; +short tapCount = 0; +#define TAP_TIME 25 + +struct TouchControllerDescriptor +{ + void (*read)(uint16_t * X, uint16_t * Y, uint32_t * event); + uint8_t (*detectTouch)(); + void (*printDebugInfo)(); + uint32_t contactEvent; +}; + +static const TouchControllerDescriptor *tc = nullptr; + +static TouchState internalTouchState = {}; + +static void _cst340_exti_isr(void) +{ + touchEventOccured = true; +} + +static void TOUCH_AF_ExtiStop(void) +{ + stm32_exti_disable(TOUCH_INT_EXTI_Line); +} + +static void TOUCH_AF_ExtiConfig(void) +{ + __HAL_RCC_SYSCFG_CLK_ENABLE(); + LL_SYSCFG_SetEXTISource(TOUCH_INT_EXTI_Port, TOUCH_INT_EXTI_SysCfgLine); + + stm32_exti_enable(TOUCH_INT_EXTI_Line, + LL_EXTI_TRIGGER_FALLING, + _cst340_exti_isr); +} + +static void TOUCH_AF_GPIOConfig(void) +{ + LL_GPIO_InitTypeDef gpioInit; + LL_GPIO_StructInit(&gpioInit); + + stm32_gpio_enable_clock(TOUCH_RST_GPIO); + stm32_gpio_enable_clock(TOUCH_INT_GPIO); + + gpioInit.Mode = LL_GPIO_MODE_OUTPUT; + gpioInit.Speed = LL_GPIO_SPEED_FREQ_LOW; + gpioInit.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + gpioInit.Pull = LL_GPIO_PULL_NO; + + gpioInit.Pin = TOUCH_RST_GPIO_PIN; + LL_GPIO_Init(TOUCH_RST_GPIO, &gpioInit); + LL_GPIO_SetOutputPin(TOUCH_RST_GPIO, TOUCH_RST_GPIO_PIN); + + gpioInit.Pin = TOUCH_INT_GPIO_PIN; + gpioInit.Mode = LL_GPIO_MODE_INPUT; + gpioInit.Pull = LL_GPIO_PULL_UP; + gpioInit.OutputType = LL_GPIO_OUTPUT_OPENDRAIN; + LL_GPIO_Init(TOUCH_INT_GPIO, &gpioInit); + LL_GPIO_SetOutputPin(TOUCH_INT_GPIO, TOUCH_INT_GPIO_PIN); +} + +void I2C_Init_Radio(void) +{ + TRACE("CST340 I2C Init"); + + if (stm32_i2c_init(TOUCH_I2C_BUS, TOUCH_I2C_CLK_RATE) < 0) { + TRACE("CST340 ERROR: stm32_i2c_init failed"); + return; + } +} + +// void Touch_DeInit() +// { +// I2C_DeInit(I2C_B1); +// __HAL_RCC_I2C1_FORCE_RESET(); +// delay_ms(150); +// __HAL_RCC_I2C1_RELEASE_RESET(); +// } + +#define I2C_TIMEOUT_MAX 5 // 5 ms + +bool touch_i2c_read(uint8_t addr, uint8_t reg, uint8_t * data, uint8_t len) +{ +// if(touchController == TC_CST836U) +// { +// if(stm32_i2c_master_tx(TOUCH_I2C_BUS, addr, ®, 1, 3) < 0) +// return false; +// delay_us(5); +// if(stm32_i2c_master_rx(TOUCH_I2C_BUS, addr, data, len, I2C_TIMEOUT_MAX) < 0) +// return false; +// } else { + if (stm32_i2c_read(TOUCH_I2C_BUS, addr, reg, 1, data, len, I2C_TIMEOUT_MAX) < 0) + return false; +// } + + return true; +} + +#if 0 +static bool touch_i2c_write(uint8_t addr, uint8_t reg, uint8_t * data, uint8_t len) +{ + if (stm32_i2c_write(TOUCH_I2C_BUS, addr, reg, 1, data, len, I2C_TIMEOUT_MAX) < 0) + return false; + + return true; +} + +static void TS_IO_Write(uint8_t addr, uint8_t reg, uint8_t data) +{ + uint8_t tryCount = 3; + while (!touch_i2c_write(addr, reg, &data, 1)) { + if (--tryCount == 0) break; + I2C_Init(); + } +} +#endif + +static uint8_t TS_IO_Read(uint8_t addr, uint8_t reg) +{ + uint8_t result; + uint8_t tryCount = 3; + while (!touch_i2c_read(addr, reg, &result, 1)) { + if (--tryCount == 0) break; + I2C_Init_Radio(); +// I2C_Init(); + } + return result; +} + +static uint16_t TS_IO_ReadMultiple(uint8_t addr, uint8_t reg, uint8_t * buffer, uint16_t length) +{ + uint8_t tryCount = 3; + while (!touch_i2c_read(addr, reg, buffer, length)) { + if (--tryCount == 0) break; + I2C_Init_Radio(); +// I2C_Init(); + } + return 1; +} + +static void touch_ft6236_debug_info(void) +{ +#if defined(DEBUG) + TRACE("ft6x36: thrhld = %d", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_TH_GROUP) * 4); + TRACE("ft6x36: rep rate=", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_PERIODACTIVE) * 10); + TRACE("ft6x36: fw lib 0x%02X %02X", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_LIB_VER_H), TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_LIB_VER_L)); + TRACE("ft6x36: fw v 0x%02X", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_FIRMID)); + TRACE("ft6x36: CHIP ID 0x%02X", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_CIPHER)); + TRACE("ft6x36: CTPM ID 0x%02X", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_FOCALTECH_ID)); + TRACE("ft6x36: rel code 0x%02X", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_RELEASE_CODE_ID)); +#endif +} + +/** + * @brief Return if there is touches detected or not. + * Try to detect new touches and forget the old ones (reset internal global + * variables). + * @param DeviceAddr: Device address on communication Bus. + * @retval : Number of active touches detected (can be 0, 1 or 2). + */ +static uint8_t ft6x06_TS_DetectTouch() +{ + volatile uint8_t nbTouch = 0; + + /* Read register FT6206_TD_STAT_REG to check number of touches detection */ + nbTouch = TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, FT6206_TD_STAT_REG); + nbTouch &= FT6206_TD_STAT_MASK; + if (nbTouch > FT6206_MAX_DETECTABLE_TOUCH) { + /* If invalid number of touch detected, set it to zero */ + nbTouch = 0; + } + /* Update ft6x06 driver internal global : current number of active touches */ + tc_handle.currActiveTouchNb = nbTouch; + + /* Reset current active touch index on which to work on */ + tc_handle.currActiveTouchIdx = 0; + return (nbTouch); +} + +#if 0 +/** + * @brief Get the touch detailed informations on touch number 'touchIdx' (0..1) + * This touch detailed information contains : + * - weight that was applied to this touch + * - sub-area of the touch in the touch panel + * - event of linked to the touch (press down, lift up, ...) + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT6x06). + * @param touchIdx : Passed index of the touch (0..1) on which we want to get the + * detailed information. + * @param pWeight : Pointer to to get the weight information of 'touchIdx'. + * @param pArea : Pointer to to get the sub-area information of 'touchIdx'. + * @param pEvent : Pointer to to get the event information of 'touchIdx'. + + * @retval None. + */ +static void ft6x06_TS_GetTouchInfo(uint16_t DeviceAddr, + uint32_t touchIdx, + uint32_t * pWeight, + uint32_t * pArea, + uint32_t * pEvent) +{ + uint8_t regAddress = 0; + uint8_t dataxy[3]; + + if (touchIdx < ft6x06_handle.currActiveTouchNb) { + switch (touchIdx) { + case 0 : + regAddress = FT6206_P1_WEIGHT_REG; + break; + + case 1 : + regAddress = FT6206_P2_WEIGHT_REG; + break; + + default : + break; + + } /* end switch(touchIdx) */ + + /* Read weight, area and Event Id of touch index */ + TS_IO_ReadMultiple(DeviceAddr, regAddress, dataxy, sizeof(dataxy)); + + /* Return weight of touch index */ + *pWeight = (dataxy[0] & FT6206_TOUCH_WEIGHT_MASK) >> FT6206_TOUCH_WEIGHT_SHIFT; + /* Return area of touch index */ + *pArea = (dataxy[1] & FT6206_TOUCH_AREA_MASK) >> FT6206_TOUCH_AREA_SHIFT; + /* Return Event Id of touch index */ + *pEvent = (dataxy[2] & FT6206_TOUCH_EVT_FLAG_MASK) >> FT6206_TOUCH_EVT_FLAG_SHIFT; + + } /* of if(touchIdx < ft6x06_handle.currActiveTouchNb) */ +} +#endif + +/** + * @brief Get the touch screen X and Y positions values + * Manage multi touch thanks to touch Index global + * variable 'tc_handle.currActiveTouchIdx'. + * @param DeviceAddr: Device address on communication Bus. + * @param X: Pointer to X position value + * @param Y: Pointer to Y position value + * @retval None. + */ +static void ft6x06_TS_GetXY(uint16_t * X, uint16_t * Y, uint32_t * event) +{ + uint8_t regAddress = 0; + uint8_t dataxy[4]; + + if (tc_handle.currActiveTouchIdx < tc_handle.currActiveTouchNb) { + switch (tc_handle.currActiveTouchIdx) { + case 0 : + regAddress = FT6206_P1_XH_REG; + break; + case 1 : + regAddress = FT6206_P2_XH_REG; + break; + + default : + break; + } + + /* Read X and Y positions */ + TS_IO_ReadMultiple(TOUCH_FT6236_I2C_ADDRESS, regAddress, dataxy, sizeof(dataxy)); + /* Send back ready X position to caller */ + *X = ((dataxy[0] & FT6206_MSB_MASK) << 8) | (dataxy[1] & FT6206_LSB_MASK); + /* Send back ready Y position to caller */ + *Y = ((dataxy[2] & FT6206_MSB_MASK) << 8) | (dataxy[3] & FT6206_LSB_MASK); + + *event = (dataxy[0] & FT6206_TOUCH_EVT_FLAG_MASK) >> FT6206_TOUCH_EVT_FLAG_SHIFT; + /* + uint32_t weight; + uint32_t area; + ft6x06_TS_GetTouchInfo(DeviceAddr, ft6x06_handle.currActiveTouchIdx, &weight, &area, event); + */ + tc_handle.currActiveTouchIdx++; + } +} + +static void touch_cst340_debug_info(void) +{ +#if 0 // Disabled because cannot compile, will fix when necessary +#if defined(DEBUG) + uint8_t tmp[4]; + if (!TS_IO_Write(CST340_MODE_DEBUG_INFO, tmp, 0)) + TRACE("CST340 chip NOT FOUND"); + + // Check the value, expected ChipID + uint32_t chipId = tmp[0] << 8) + tmp[1]; + + if (!I2C_CST340_ReadRegister(CST340_FWVER_REG, tmp, 4)) + TRACE("Error reading CST340 firmware version!"); + uint32_t fwVersion = tmp[0] << 24 | tmp[1]<<16 | tmp[2]<<8 | tmp[0]; + + // Enter normal mode + if (!I2C_CST340_WriteRegister(CST340_MODE_NORMAL, tmp, 0)) + TRACE("ERROR chaning CST340 mode back to normal!"); + + TRACE("cst340: fw ver 0x%08X", fwVersion); + TRACE("cst836u: chip id 0x%04X", chipId); +#endif +#endif +} + +/** + * @brief Get the touch screen X and Y positions values + * @param DeviceAddr: Device address on communication Bus. + * @param X: Pointer to X position value + * @param Y: Pointer to Y position value + * @retval None. + */ +static void cst340_TS_GetXY(uint16_t * X, uint16_t * Y, uint32_t * event) +{ + uint8_t dataxy[4]; + + /* Read X and Y positions */ + TS_IO_ReadMultiple(TOUCH_CST340_I2C_ADDRESS, CST340_FINGER1_REG, dataxy, sizeof(dataxy)); + /* Send back ready X position to caller */ + *X = ((dataxy[1]<<4) + ((dataxy[3]>>4)&0x0f)); + *Y = ((dataxy[2]<<4) + ((dataxy[3])&0x0f)); + /* Send back ready Y position to caller */ + + *event = dataxy[0]; +} + +/** + * @brief Return if there is touches detected or not. + * Try to detect new touches and forget the old ones (reset internal global + * variables). + * @param DeviceAddr: Device address on communication Bus. + * @retval : Number of active touches detected + */ +static uint8_t cst340_TS_DetectTouch() +{ + uint8_t nbTouch; + uint8_t reg = TS_IO_Read(TOUCH_CST340_I2C_ADDRESS, CST340_FINGER1_REG); + if( reg == 0x06 ) + nbTouch = 1; + else + nbTouch = 0; + + tc_handle.currActiveTouchNb = nbTouch; + + tc_handle.currActiveTouchIdx = 0; + return (nbTouch); +} + +void TouchReset() +{ + LL_GPIO_ResetOutputPin(TOUCH_RST_GPIO, TOUCH_RST_GPIO_PIN); + delay_ms(10); + LL_GPIO_SetOutputPin(TOUCH_RST_GPIO, TOUCH_RST_GPIO_PIN); + delay_ms(300); +} + +static const TouchControllerDescriptor FT6236 = +{ + .read = ft6x06_TS_GetXY, + .detectTouch = ft6x06_TS_DetectTouch, + .printDebugInfo = touch_ft6236_debug_info, + .contactEvent = FT6206_TOUCH_EVT_FLAG_CONTACT +}; +static const TouchControllerDescriptor CST340 = +{ + .read = cst340_TS_GetXY, + .detectTouch = cst340_TS_DetectTouch, + .printDebugInfo = touch_cst340_debug_info, + .contactEvent = CST340_TOUCH_EVT_FLAG_CONTACT +}; + +void detectTouchController() +{ + if( stm32_i2c_is_dev_ready(TOUCH_I2C_BUS, TOUCH_CST340_I2C_ADDRESS, 3, 5) == 0) + { + TouchControllerType = 0; + touchController = TC_CST340; + tc = &CST340; + } else { + TouchControllerType = 1; + touchController = TC_FT6236; + tc = &FT6236; + } +} + +void TouchInit() +{ + TOUCH_AF_GPIOConfig(); // SET RST=OUT INT=IN INT=HIGH + I2C_Init_Radio(); + TouchReset(); + detectTouchController(); + TOUCH_AF_ExtiConfig(); + + tc->printDebugInfo(); +} + +void handleTouch() +{ + unsigned short touchX; + unsigned short touchY; + uint32_t tEvent = 0; + tc->read(&touchX, &touchY, &tEvent); + +#if defined(DEBUG) + TRACE("handleTouch: touchX=%d, touchY=%d, tEvent=%d", touchX, touchY, tEvent); +#endif + // touch sensor is rotated by 90 deg + unsigned short tmp = touchY; + touchY = 319 - touchX; + touchX = tmp; + + if (tEvent == tc->contactEvent) { + int dx = touchX - internalTouchState.x; + int dy = touchY - internalTouchState.y; + + internalTouchState.x = touchX; + internalTouchState.y = touchY; + + if (internalTouchState.event == TE_NONE || internalTouchState.event == TE_UP || internalTouchState.event == TE_SLIDE_END) { + internalTouchState.startX = internalTouchState.x; + internalTouchState.startY = internalTouchState.y; + internalTouchState.event = TE_DOWN; + } + else if (internalTouchState.event == TE_DOWN) { + if (dx >= SLIDE_RANGE || dx <= -SLIDE_RANGE || dy >= SLIDE_RANGE || dy <= -SLIDE_RANGE) { + internalTouchState.event = TE_SLIDE; + internalTouchState.deltaX = (short) dx; + internalTouchState.deltaY = (short) dy; + } + else { + internalTouchState.event = TE_DOWN; + internalTouchState.deltaX = 0; + internalTouchState.deltaY = 0; + } + } + else if (internalTouchState.event == TE_SLIDE) { + internalTouchState.event = TE_SLIDE; //no change + internalTouchState.deltaX = (short) dx; + internalTouchState.deltaY = (short) dy; + } + + } +} + +static bool lastHasTouch = false; +bool touchPanelEventOccured() +{ + bool result = touchEventOccured; + uint8_t hasTouch = false; + if (touchEventOccured) { + hasTouch = tc->detectTouch(); + if (!hasTouch && !lastHasTouch) { + touchEventOccured = false; + result = false; + } + lastHasTouch = hasTouch; + } + +#if defined(DEBUG) + TRACE("TouchEvent: %d, %d, %d, %d", touchEventOccured, lastHasTouch, hasTouch, result); +#endif + return result; +} + +TouchState touchPanelRead() +{ + if (!touchEventOccured) return internalTouchState; + + touchEventOccured = false; + + tmr10ms_t now = get_tmr10ms(); + internalTouchState.tapCount = 0; + + if (tc->detectTouch()) { + handleTouch(); + if (internalTouchState.event == TE_DOWN && downTime == 0) { + downTime = now; + } + } else { + if (internalTouchState.event == TE_DOWN) { + internalTouchState.event = TE_UP; + if (now - downTime <= TAP_TIME) { + if (now - tapTime > TAP_TIME) { + tapCount = 1; + } else { + tapCount++; + } + internalTouchState.tapCount = tapCount; + tapTime = now; + } else { + internalTouchState.tapCount = 0; // not a tap + } + downTime = 0; + } else { + tapCount = 0; + internalTouchState.tapCount = 0; + internalTouchState.event = TE_SLIDE_END; + } + } + TouchState ret = internalTouchState; + internalTouchState.deltaX = 0; + internalTouchState.deltaY = 0; + if(internalTouchState.event == TE_UP || internalTouchState.event == TE_SLIDE_END) + internalTouchState.event = TE_NONE; + +#if defined(DEBUG) + TRACE("%s: Event = %d", touchController == TC_CST340 ? "CST340" : "FT6236", ret.event); +#endif + + return ret; +} + +TouchState getInternalTouchState() +{ + return internalTouchState; +} diff --git a/radio/src/targets/st16/tp_cst340.h b/radio/src/targets/st16/tp_cst340.h new file mode 100644 index 000000000..ec5f16107 --- /dev/null +++ b/radio/src/targets/st16/tp_cst340.h @@ -0,0 +1,289 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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. + */ + +#pragma once + +#include "touch.h" + +typedef struct +{ + /* field holding the current number of simultaneous active touches */ + uint8_t currActiveTouchNb; + + /* field holding the touch index currently managed */ + uint8_t currActiveTouchIdx; + +} tc_handle_TypeDef; + + +#define TOUCH_FT6236_MAX_TOUCH_POINTS 2 + +#define TOUCH_FT6236_REG_TH_GROUP 0x80 +#define TOUCH_FT6236_REG_PERIODACTIVE 0x88 +#define TOUCH_FT6236_REG_LIB_VER_H 0xa1 +#define TOUCH_FT6236_REG_LIB_VER_L 0xa2 +#define TOUCH_FT6236_REG_CIPHER 0xa3 +#define TOUCH_FT6236_REG_FIRMID 0xa6 +#define TOUCH_FT6236_REG_FOCALTECH_ID 0xa8 +#define TOUCH_FT6236_REG_RELEASE_CODE_ID 0xaf + +#define TOUCH_FT6236_EVENT_PRESS_DOWN 0 +#define TOUCH_FT6236_EVENT_LIFT_UP 1 +#define TOUCH_FT6236_EVENT_CONTACT 2 +#define TOUCH_FT6236_EVENT_NO_EVENT 3 + +#define TOUCH_FT6236_GESTURE_MOVE_FLAG 0x10 +#define TOUCH_FT6236_GESTURE_MOVE_UP 0x10 +#define TOUCH_FT6236_GESTURE_MOVE_RIGHT 0x14 +#define TOUCH_FT6236_GESTURE_MOVE_DOWN 0x18 +#define TOUCH_FT6236_GESTURE_MOVE_LEFT 0x1C +#define TOUCH_FT6236_GESTURE_ZOOM_IN 0x48 +#define TOUCH_FT6236_GESTURE_ZOOM_OUT 0x49 +#define TOUCH_FT6236_GESTURE_NONE 0x00 + +#define TOUCH_GESTURE_UP ((TOUCH_FT6236_GESTURE_MOVE_UP & 0x0F)+1) +#define TOUCH_GESTURE_DOWN ((TOUCH_FT6236_GESTURE_MOVE_DOWN & 0x0F)+1) +#define TOUCH_GESTURE_LEFT ((TOUCH_FT6236_GESTURE_MOVE_LEFT & 0x0F)+1) +#define TOUCH_GESTURE_RIGHT ((TOUCH_FT6236_GESTURE_MOVE_RIGHT & 0x0F)+1) +#define TOUCH_GESTURE_MOUSE_DOWN (0x80+TOUCH_FT6236_EVENT_PRESS_DOWN) +#define TOUCH_GESTURE_MOUSE_UP (0x80+TOUCH_FT6236_EVENT_LIFT_UP) +#define TOUCH_GESTURE_MOUSE_MOVE (0x80+TOUCH_FT6236_EVENT_CONTACT) +#define TOUCH_GESTURE_MOUSE_NONE (0x80+TOUCH_FT6236_EVENT_NO_EVENT) + + + + /* Maximum border values of the touchscreen pad */ +#define FT_6206_MAX_WIDTH ((uint16_t)800) /* Touchscreen pad max width */ +#define FT_6206_MAX_HEIGHT ((uint16_t)480) /* Touchscreen pad max height */ + + /* Possible values of driver functions return status */ +#define FT6206_STATUS_OK 0 +#define FT6206_STATUS_NOT_OK 1 + + /* Max detectable simultaneous touches */ +#define FT6206_MAX_DETECTABLE_TOUCH 2 + + /** + * @brief : Definitions for FT6206 I2C register addresses on 8 bit + **/ + + /* Current mode register of the FT6206 (R/W) */ +#define FT6206_DEV_MODE_REG 0x00 + + /* Possible values of FT6206_DEV_MODE_REG */ +#define FT6206_DEV_MODE_WORKING 0x00 +#define FT6206_DEV_MODE_FACTORY 0x04 + +#define FT6206_DEV_MODE_MASK 0x7 +#define FT6206_DEV_MODE_SHIFT 4 + + /* Gesture ID register */ +#define FT6206_GEST_ID_REG 0x01 + + /* Possible values of FT6206_GEST_ID_REG */ +#define FT6206_GEST_ID_NO_GESTURE 0x00 +#define FT6206_GEST_ID_MOVE_UP 0x10 +#define FT6206_GEST_ID_MOVE_RIGHT 0x14 +#define FT6206_GEST_ID_MOVE_DOWN 0x18 +#define FT6206_GEST_ID_MOVE_LEFT 0x1C +#define FT6206_GEST_ID_ZOOM_IN 0x48 +#define FT6206_GEST_ID_ZOOM_OUT 0x49 + + /* Touch Data Status register : gives number of active touch points (0..2) */ +#define FT6206_TD_STAT_REG 0x02 + + /* Values related to FT6206_TD_STAT_REG */ +#define FT6206_TD_STAT_MASK 0x0F +#define FT6206_TD_STAT_SHIFT 0x00 + + /* Values Pn_XH and Pn_YH related */ +#define FT6206_TOUCH_EVT_FLAG_PRESS_DOWN 0x00 +#define FT6206_TOUCH_EVT_FLAG_LIFT_UP 0x01 +#define FT6206_TOUCH_EVT_FLAG_CONTACT 0x02 +#define FT6206_TOUCH_EVT_FLAG_NO_EVENT 0x03 + +#define FT6206_TOUCH_EVT_FLAG_SHIFT 6 +#define FT6206_TOUCH_EVT_FLAG_MASK (3 << FT6206_TOUCH_EVT_FLAG_SHIFT) + +#define FT6206_MSB_MASK 0x0F +#define FT6206_MSB_SHIFT 0 + + /* Values Pn_XL and Pn_YL related */ +#define FT6206_LSB_MASK 0xFF +#define FT6206_LSB_SHIFT 0 + +#define FT6206_P1_XH_REG 0x03 +#define FT6206_P1_XL_REG 0x04 +#define FT6206_P1_YH_REG 0x05 +#define FT6206_P1_YL_REG 0x06 + + /* Touch Pressure register value (R) */ +#define FT6206_P1_WEIGHT_REG 0x07 + + /* Values Pn_WEIGHT related */ +#define FT6206_TOUCH_WEIGHT_MASK 0xFF +#define FT6206_TOUCH_WEIGHT_SHIFT 0 + + /* Touch area register */ +#define FT6206_P1_MISC_REG 0x08 + + /* Values related to FT6206_Pn_MISC_REG */ +#define FT6206_TOUCH_AREA_MASK (0x04 << 4) +#define FT6206_TOUCH_AREA_SHIFT 0x04 + +#define FT6206_P2_XH_REG 0x09 +#define FT6206_P2_XL_REG 0x0A +#define FT6206_P2_YH_REG 0x0B +#define FT6206_P2_YL_REG 0x0C +#define FT6206_P2_WEIGHT_REG 0x0D +#define FT6206_P2_MISC_REG 0x0E + + /* Threshold for touch detection */ +#define FT6206_TH_GROUP_REG 0x80 + + /* Values FT6206_TH_GROUP_REG : threshold related */ +#define FT6206_THRESHOLD_MASK 0xFF +#define FT6206_THRESHOLD_SHIFT 0 + + /* Filter function coefficients */ +#define FT6206_TH_DIFF_REG 0x85 + + /* Control register */ +#define FT6206_CTRL_REG 0x86 + + /* Values related to FT6206_CTRL_REG */ + + /* Will keep the Active mode when there is no touching */ +#define FT6206_CTRL_KEEP_ACTIVE_MODE 0x00 + + /* Switching from Active mode to Monitor mode automatically when there is no touching */ +#define FT6206_CTRL_KEEP_AUTO_SWITCH_MONITOR_MODE 0x01 + + /* The time period of switching from Active mode to Monitor mode when there is no touching */ +#define FT6206_TIMEENTERMONITOR_REG 0x87 + + /* Report rate in Active mode */ +#define FT6206_PERIODACTIVE_REG 0x88 + + /* Report rate in Monitor mode */ +#define FT6206_PERIODMONITOR_REG 0x89 + + /* The value of the minimum allowed angle while Rotating gesture mode */ +#define FT6206_RADIAN_VALUE_REG 0x91 + + /* Maximum offset while Moving Left and Moving Right gesture */ +#define FT6206_OFFSET_LEFT_RIGHT_REG 0x92 + + /* Maximum offset while Moving Up and Moving Down gesture */ +#define FT6206_OFFSET_UP_DOWN_REG 0x93 + + /* Minimum distance while Moving Left and Moving Right gesture */ +#define FT6206_DISTANCE_LEFT_RIGHT_REG 0x94 + + /* Minimum distance while Moving Up and Moving Down gesture */ +#define FT6206_DISTANCE_UP_DOWN_REG 0x95 + + /* Maximum distance while Zoom In and Zoom Out gesture */ +#define FT6206_DISTANCE_ZOOM_REG 0x96 + + /* High 8-bit of LIB Version info */ +#define FT6206_LIB_VER_H_REG 0xA1 + + /* Low 8-bit of LIB Version info */ +#define FT6206_LIB_VER_L_REG 0xA2 + + /* Chip Selecting */ +#define FT6206_CIPHER_REG 0xA3 + + /* Interrupt mode register (used when in interrupt mode) */ +#define FT6206_GMODE_REG 0xA4 + +#define FT6206_G_MODE_INTERRUPT_MASK 0x03 +#define FT6206_G_MODE_INTERRUPT_SHIFT 0x00 + + /* Possible values of FT6206_GMODE_REG */ +#define FT6206_G_MODE_INTERRUPT_POLLING 0x00 +#define FT6206_G_MODE_INTERRUPT_TRIGGER 0x01 + + /* Current power mode the FT6206 system is in (R) */ +#define FT6206_PWR_MODE_REG 0xA5 + + /* FT6206 firmware version */ +#define FT6206_FIRMID_REG 0xA6 + + /* FT6206 Chip identification register */ +#define FT6206_CHIP_ID_REG 0xA8 + + /* Possible values of FT6206_CHIP_ID_REG */ +#define FT6206_ID_VALUE 0x11 + + /* Release code version */ +#define FT6206_RELEASE_CODE_ID_REG 0xAF + + /* Current operating mode the FT6206 system is in (R) */ +#define FT6206_STATE_REG 0xBC + + + +#define HAS_TOUCH_PANEL() touchCST340Flag == true + +#define CST340_MODE_DEBUG_INFO 0xD101 // To read out chip ID and firmware version +#define CST340_MODE_NORMAL 0xD109 // Normal mode +#define CST340_FINGER1_REG 0xD000 // Touch info register +#define CST340_CHIPTYPE_REG 0xD204 // uint16_t chip IC type & uint16_t project ID register +#define CST340_FWVER_REG 0xD208 // Firmware version register(uint8_t major, uint8_t minor, uint16_t build) +#define CST340_TOUCH_EVT_FLAG_CONTACT 6 + +#define CST340_CHIP_ID 0x011C // Expected answer to CST340_CHIPTYPE_REG query for the ChipID field + +#define TOUCH_POINTS_MAX 5 // Max touch points + +#define TOUCH_ACK 0 +#define TOUCH_NACK 1 + +#define CST340_I2C_ADDR 0x1A + +extern bool touchCST340Flag; +extern uint32_t touchI2Chiccups; +extern uint16_t touchICfwver; +void TouchInit(); + +struct TouchState touchPanelRead(); +bool touchPanelEventOccured(); + +PACK(typedef struct { + uint8_t track; + uint16_t x; + uint16_t y; + uint16_t size; + uint8_t reserved; +}) TouchPoint; + +PACK(struct TouchData { + union + { + TouchPoint points[TOUCH_POINTS_MAX]; + uint8_t data[TOUCH_POINTS_MAX * sizeof(TouchPoint)]; + }; +}); + +#define TPRST_LOW() do { TOUCH_RST_GPIO->BSRRH = TOUCH_RST_GPIO_PIN; } while(0) +#define TPRST_HIGH() do { TOUCH_RST_GPIO->BSRRL = TOUCH_RST_GPIO_PIN; } while(0) diff --git a/radio/src/targets/st16/usb_descriptor.h b/radio/src/targets/st16/usb_descriptor.h new file mode 100644 index 000000000..75ad49493 --- /dev/null +++ b/radio/src/targets/st16/usb_descriptor.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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. + */ + +#pragma once + +#define USB_NAME "ST16" +#define USB_MANUFACTURER 'F', 'l', 'y', 'S', 'k', 'y', ' ', ' ' /* 8 bytes */ +#define USB_PRODUCT 'S', 'T', '1', '6', ' ', ' ', ' ', ' ' /* 8 Bytes */ diff --git a/radio/util/hw_defs/hal_keys.py b/radio/util/hw_defs/hal_keys.py index 750963d3c..8a00b0a31 100644 --- a/radio/util/hw_defs/hal_keys.py +++ b/radio/util/hw_defs/hal_keys.py @@ -131,6 +131,12 @@ KEY_LABELS = [ "MENU": { "label": "Menu" } } }, + { + "targets": {"st16"}, + "keys": { + "PAGEDN": { "label": "MENU" } + } + }, ] class Key: diff --git a/radio/util/hw_defs/legacy_names.py b/radio/util/hw_defs/legacy_names.py index 3e98eab70..d462a8864 100644 --- a/radio/util/hw_defs/legacy_names.py +++ b/radio/util/hw_defs/legacy_names.py @@ -947,6 +947,43 @@ LEGACY_NAMES = [ }, }, }, + { + "targets": {"st16"}, + "inputs": { + "LH": {"yaml": "Rud", "lua": "rud", "description": "Rudder"}, + "LV": {"yaml": "Ele", "lua": "ele", "description": "Elevator"}, + "RV": {"yaml": "Thr", "lua": "thr", "description": "Throttle"}, + "RH": {"yaml": "Ail", "lua": "ail", "description": "Aileron"}, + "P1": { + "yaml": "S1", + "lua": "s1", + "label": "S1", + "short_label": "1", + "description": "Potentiometer 1", + }, + "P2": { + "yaml": "S2", + "lua": "s2", + "label": "S2", + "short_label": "2", + "description": "Potentiometer 2", + }, + "SL1": { + "yaml": "LS", + "lua": "ls", + "label": "LS", + "short_label": "L", + "description": "Left slider", + }, + "SL2": { + "yaml": "RS", + "lua": "rs", + "label": "RS", + "short_label": "R", + "description": "Right slider", + }, + }, + }, { "targets": {"h747", "h7rs"}, "inputs": { diff --git a/radio/util/hw_defs/pot_config.py b/radio/util/hw_defs/pot_config.py index 53bc2d551..0cd3bd22a 100644 --- a/radio/util/hw_defs/pot_config.py +++ b/radio/util/hw_defs/pot_config.py @@ -231,6 +231,12 @@ POT_CONFIG = { "pocket": { "P1": {"default": "POT"} }, + "st16": { + "P1": {"default": "POT"}, + "P2": {"default": "POT"}, + "SL1": {"default": "SLIDER"}, + "SL2": {"default": "SLIDER"}, + }, } diff --git a/radio/util/hw_defs/switch_config.py b/radio/util/hw_defs/switch_config.py index d7522d323..b2b1b82f3 100644 --- a/radio/util/hw_defs/switch_config.py +++ b/radio/util/hw_defs/switch_config.py @@ -69,6 +69,18 @@ SWITCH_CONFIG = { "SA" : { "default": "TOGGLE" }, "SB" : { "default": "TOGGLE" } }, + "st16": { + "SA": { "default": "2POS" }, + "SB": { "default": "3POS" }, + "SC": { "default": "3POS" }, + "SD": { "default": "2POS" }, + "SE": { "default": "2POS" }, + "SF": { "default": "2POS" }, + "SG": { "default": "TOGGLE" }, + "SH": { "default": "TOGGLE" }, + "SI": { "default": "TOGGLE" }, + "SJ": { "default": "TOGGLE" }, + }, "lr3pro": { # left side "SA": {"default": "3POS", "display": [0, 0]}, diff --git a/tools/build-common.sh b/tools/build-common.sh index aac802cf7..49fc2d716 100644 --- a/tools/build-common.sh +++ b/tools/build-common.sh @@ -152,6 +152,9 @@ get_target_build_options() { nb4p) BUILD_OPTIONS+="-DPCB=PL18 -DPCBREV=NB4P" ;; + st16) + BUILD_OPTIONS+="-DPCB=ST16 -DNANO=NO" + ;; *) echo "Unknown target: $target_name" return 1 diff --git a/tools/build-flysky.py b/tools/build-flysky.py old mode 100644 new mode 100755 index a327f5c49..832fd070e --- a/tools/build-flysky.py +++ b/tools/build-flysky.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import argparse import datetime @@ -13,6 +13,7 @@ boards = { "EL18": { "PCB": "PL18", "PCBREV": "EL18" }, "PL18": { "PCB": "PL18" }, "PL18EV": { "PCB": "PL18", "PCBREV": "PL18EV" }, + "ST16": { "PCB": "ST16" , "NANO": "NO" }, } translations = [ diff --git a/tools/build-gh.sh b/tools/build-gh.sh index 2d1371671..fc006054f 100755 --- a/tools/build-gh.sh +++ b/tools/build-gh.sh @@ -89,7 +89,7 @@ target_names=$(echo "$FLAVOR" | tr '[:upper:]' '[:lower:]' | tr ';' '\n') for target_name in $target_names do - fw_name="${target_name}-${GIT_SHA_SHORT}.bin" + fw_name="${target_name}-${GIT_SHA_SHORT}" BUILD_OPTIONS=${COMMON_OPTIONS} echo "Building ${fw_name}" @@ -104,5 +104,12 @@ do cmake --build arm-none-eabi -j"${CORES}" --target ${FIRMARE_TARGET} rm -f CMakeCache.txt arm-none-eabi/CMakeCache.txt - mv arm-none-eabi/firmware.bin "../${fw_name}" + + #if [ -f arm-none-eabi/firmware.uf2 ]; then + if [ "$target_name" = "st16" ]; then + mv arm-none-eabi/firmware.uf2 "../${fw_name}.uf2" + else + mv arm-none-eabi/firmware.bin "../${fw_name}.bin" + fi + done diff --git a/tools/generate-hw-defs.sh b/tools/generate-hw-defs.sh index d2bee0ce7..4075506e8 100755 --- a/tools/generate-hw-defs.sh +++ b/tools/generate-hw-defs.sh @@ -9,7 +9,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" : "${SRCDIR:=$(dirname "$(pwd)/$0")/..}" -: ${FLAVOR:="nv14;el18;t12;t12max;t15;t16;t18;t8;zorro;pocket;commando8;tlite;tpro;tprov2;tpros;bumblebee;t20;t20v2;t14;lr3pro;mt12;gx12;tx12;tx12mk2;boxer;tx16s;x10;x10express;x12s;x7;x7access;x9d;x9dp;x9dp2019;x9e;x9lite;x9lites;xlite;xlites;f16;v14;v12"} +: ${FLAVOR:="nv14;el18;pl18;pl18ev;nb4p;st16;t12;t12max;t15;t16;t18;t8;zorro;pocket;commando8;tlite;tpro;tprov2;tpros;bumblebee;t20;t20v2;t14;lr3pro;mt12;gx12;tx12;tx12mk2;boxer;tx16s;x10;x10express;x12s;x7;x7access;x9d;x9dp;x9dp2019;x9e;x9lite;x9lites;xlite;xlites;f16;v14;v12"} : ${COMMON_OPTIONS:="-DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_RULE_MESSAGES=OFF -Wno-dev -DCMAKE_MESSAGE_LOG_LEVEL=WARNING"} # wipe build directory clean diff --git a/tools/generate-yaml.sh b/tools/generate-yaml.sh index dcdef10b9..419d95aef 100755 --- a/tools/generate-yaml.sh +++ b/tools/generate-yaml.sh @@ -11,7 +11,7 @@ if [[ -n ${GCC_ARM} ]] ; then export PATH=${GCC_ARM}:$PATH fi -: ${FLAVOR:="t15;tx16s;nv14;pl18;nb4p;x9d;x9dp2019;x9e;xlite;xlites;x7;tpro;t20;f16;gx12"} +: ${FLAVOR:="t15;tx16s;nv14;pl18;nb4p;x9d;x9dp2019;x9e;xlite;xlites;x7;tpro;t20;f16;gx12;st16"} : ${SRCDIR:=$(dirname "$(pwd)/$0")/..} : ${COMMON_OPTIONS:="-DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_RULE_MESSAGES=OFF -Wno-dev -DDISABLE_COMPANION=YES -DCMAKE_MESSAGE_LOG_LEVEL=WARNING"}