From 0d7832b20858420dc107980c631e7bd1ae028e6d Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Tue, 19 Dec 2017 12:13:59 +0100 Subject: [PATCH] Horus bootloader (#5455) Horus bootloader --- CMakeLists.txt | 6 +- radio/src/CMakeLists.txt | 6 +- radio/src/bitmaps/480x272/CMakeLists.txt | 8 +- .../480x272/bootloader/bmp_plug_usb.png | Bin 0 -> 9330 bytes .../480x272/bootloader/bmp_usb_plugged.png | Bin 0 -> 3722 bytes .../bitmaps/480x272/bootloader/icon_error.png | Bin 0 -> 1100 bytes .../bitmaps/480x272/bootloader/icon_exit.png | Bin 0 -> 641 bytes .../bitmaps/480x272/bootloader/icon_file.png | Bin 0 -> 276 bytes .../bitmaps/480x272/bootloader/icon_flash.png | Bin 0 -> 696 bytes .../bitmaps/480x272/bootloader/icon_ok.png | Bin 0 -> 823 bytes .../bitmaps/480x272/bootloader/icon_sd.png | Bin 0 -> 514 bytes radio/src/definitions.h | 2 +- radio/src/fonts.h | 5 + radio/src/gui/480x272/bitmapbuffer.cpp | 16 +- radio/src/gui/480x272/fonts.cpp | 9 + radio/src/gui/480x272/lcd.cpp | 16 +- radio/src/gui/480x272/lcd.h | 18 +- radio/src/loadboot.cpp | 161 ----- radio/src/opentx.h | 7 +- radio/src/serial.cpp | 2 + radio/src/stamp.cpp | 15 +- radio/src/targets/common/arm/loadboot.cpp | 25 + .../targets/common/arm/stm32/CMakeLists.txt | 1 + .../arm/stm32/bootloader/CMakeLists.txt | 130 ++++ .../common/arm/stm32/bootloader/bin_files.cpp | 145 ++++ .../common/arm/stm32/bootloader/bin_files.h | 88 +++ .../common/arm/stm32/bootloader/boot.cpp | 523 ++++++++++++++ .../common/arm/stm32/bootloader/boot.h | 80 +++ .../arm/stm32}/bootloader/init.c | 0 .../arm/stm32}/flash_driver.cpp | 87 ++- .../common/arm/stm32/usbd_storage_msd.cpp | 4 +- radio/src/targets/horus/CMakeLists.txt | 15 +- radio/src/targets/horus/backlight_driver.cpp | 58 +- radio/src/targets/horus/board.cpp | 37 +- radio/src/targets/horus/board.h | 5 +- .../targets/horus/bootloader/boot_menu.cpp | 172 +++++ radio/src/targets/horus/diskio.cpp | 9 + radio/src/targets/horus/hal.h | 69 +- radio/src/targets/horus/keys_driver.cpp | 2 +- radio/src/targets/horus/stm32_ramboot.ld | 186 +++++ radio/src/targets/horus/stm32f4_flash.ld | 7 +- radio/src/targets/sky9x/CMakeLists.txt | 6 +- radio/src/targets/sky9x/board.cpp | 9 - radio/src/targets/sky9x/sam3s4c_flash.ld | 13 +- radio/src/targets/sky9x/sam3s8c_flash.ld | 9 +- radio/src/targets/taranis/CMakeLists.txt | 11 +- radio/src/targets/taranis/board.cpp | 50 +- .../src/targets/taranis/bootloader/.gitignore | 3 - radio/src/targets/taranis/bootloader/boot.cpp | 655 ------------------ .../targets/taranis/bootloader/boot_menu.cpp | 91 +++ radio/src/targets/taranis/hal.h | 19 +- radio/src/targets/taranis/stm32_ramboot.ld | 14 +- radio/src/targets/taranis/stm32f2_flash.ld | 5 +- radio/src/targets/taranis/stm32f4_flash.ld | 11 +- 54 files changed, 1772 insertions(+), 1038 deletions(-) create mode 100644 radio/src/bitmaps/480x272/bootloader/bmp_plug_usb.png create mode 100644 radio/src/bitmaps/480x272/bootloader/bmp_usb_plugged.png create mode 100644 radio/src/bitmaps/480x272/bootloader/icon_error.png create mode 100644 radio/src/bitmaps/480x272/bootloader/icon_exit.png create mode 100644 radio/src/bitmaps/480x272/bootloader/icon_file.png create mode 100644 radio/src/bitmaps/480x272/bootloader/icon_flash.png create mode 100644 radio/src/bitmaps/480x272/bootloader/icon_ok.png create mode 100644 radio/src/bitmaps/480x272/bootloader/icon_sd.png delete mode 100644 radio/src/loadboot.cpp create mode 100644 radio/src/targets/common/arm/loadboot.cpp create mode 100644 radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt create mode 100644 radio/src/targets/common/arm/stm32/bootloader/bin_files.cpp create mode 100644 radio/src/targets/common/arm/stm32/bootloader/bin_files.h create mode 100644 radio/src/targets/common/arm/stm32/bootloader/boot.cpp create mode 100644 radio/src/targets/common/arm/stm32/bootloader/boot.h rename radio/src/targets/{taranis => common/arm/stm32}/bootloader/init.c (100%) rename radio/src/targets/{taranis => common/arm/stm32}/flash_driver.cpp (65%) create mode 100644 radio/src/targets/horus/bootloader/boot_menu.cpp create mode 100644 radio/src/targets/horus/stm32_ramboot.ld delete mode 100644 radio/src/targets/taranis/bootloader/.gitignore delete mode 100644 radio/src/targets/taranis/bootloader/boot.cpp create mode 100644 radio/src/targets/taranis/bootloader/boot_menu.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cc403535d5e..a62444aaa8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,9 @@ else() set(LUA NO) endif() +option(DISABLE_COMPANION "Disable building companion and simulators" OFF) + +if(NOT DISABLE_COMPANION) find_package(Qt5Core) find_package(Qt5Widgets) find_package(Qt5Xml) @@ -150,6 +153,7 @@ if(Qt5Core_FOUND OR FOX_FOUND) message(STATUS "SDL not found! Simulator audio, and joystick inputs, will not work.") endif() endif() +endif() # Check for a file that is typically left from a OpenTX 2.1 build and abort if found if (EXISTS ${RADIO_SRC_DIRECTORY}/stamp.h OR EXISTS ${RADIO_SRC_DIRECTORY}/translations/en.h) @@ -180,6 +184,6 @@ endif() add_subdirectory(${RADIO_SRC_DIRECTORY}) -if(Qt5Core_FOUND) +if(Qt5Core_FOUND AND NOT DISABLE_COMPANION) add_subdirectory(${COMPANION_SRC_DIRECTORY}) endif() diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index 414facee5c9..987dd83aed0 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -486,9 +486,9 @@ if(NOT MSVC) endif() - if(PCB STREQUAL X9D OR PCB STREQUAL X9D+ OR PCB STREQUAL X9E OR PCB STREQUAL X7) - add_subdirectory(targets/${TARGET_DIR}/bootloader) - include_directories(${CMAKE_CURRENT_BINARY_DIR}/targets/${TARGET_DIR}/bootloader) + if(PCB STREQUAL X9D OR PCB STREQUAL X9D+ OR PCB STREQUAL X9E OR PCB STREQUAL X7 OR PCB STREQUAL X10 OR PCB STREQUAL X12S) + add_subdirectory(targets/common/arm/stm32/bootloader) + include_directories(${CMAKE_CURRENT_BINARY_DIR}/targets/common/arm/stm32/bootloader) set(FIRMWARE_DEPENDENCIES ${FIRMWARE_DEPENDENCIES} bootloader) elseif(OPENRC_BOOTLOADER) # We fetch Mike's bootloader as it is not included inside OpenTX diff --git a/radio/src/bitmaps/480x272/CMakeLists.txt b/radio/src/bitmaps/480x272/CMakeLists.txt index 0b5ac853abe..26cfd2d4453 100644 --- a/radio/src/bitmaps/480x272/CMakeLists.txt +++ b/radio/src/bitmaps/480x272/CMakeLists.txt @@ -10,7 +10,9 @@ if(PCB STREQUAL X12S) add_bitmaps_target(x12s_themes_bitmaps "${RADIO_SRC_DIRECTORY}/gui/480x272/themes/*.png" 480 5/6/5) add_bitmaps_target(x12s_fonts ${RADIO_SRC_DIRECTORY}/fonts/480x272/*.png 480 8bits) add_bitmaps_target(x12s_volume_masks ${RADIO_SRC_DIRECTORY}/bitmaps/480x272/volume/*.png 480 8bits) - add_dependencies(x12s_bitmaps x12s_calibration_bitmaps x12s_button_bitmaps x12s_alpha_bitmaps x12s_alpha_calibration_bitmaps x12s_masks x12s_slider_masks x12s_layouts_masks x12s_themes_bitmaps x12s_fonts x12s_volume_masks) + add_bitmaps_target(x12s_bootloader_bitmaps ${RADIO_SRC_DIRECTORY}/bitmaps/480x272/bootloader/bmp_*.png 480 5/6/5) + add_bitmaps_target(x12s_bootloader_icons ${RADIO_SRC_DIRECTORY}/bitmaps/480x272/bootloader/icon_*.png 480 8bits) + add_dependencies(x12s_bitmaps x12s_calibration_bitmaps x12s_button_bitmaps x12s_alpha_bitmaps x12s_alpha_calibration_bitmaps x12s_masks x12s_slider_masks x12s_layouts_masks x12s_themes_bitmaps x12s_fonts x12s_volume_masks x12s_bootloader_bitmaps x12s_bootloader_icons) else() add_bitmaps_target(x10_bitmaps "${RADIO_SRC_DIRECTORY}/bitmaps/480x272/bmp_*.png" 480 5/6/5-R) add_bitmaps_target(x10_calibration_bitmaps "${RADIO_SRC_DIRECTORY}/bitmaps/480x272/calibration/bmp_*.png" 480 5/6/5-R) @@ -23,5 +25,7 @@ else() add_bitmaps_target(x10_themes_bitmaps "${RADIO_SRC_DIRECTORY}/gui/480x272/themes/*.png" 480 5/6/5-R) add_bitmaps_target(x10_fonts ${RADIO_SRC_DIRECTORY}/fonts/480x272/*.png 480 8bits) add_bitmaps_target(x10_volume_masks ${RADIO_SRC_DIRECTORY}/bitmaps/480x272/volume/*.png 480 8bits) - add_dependencies(x10_bitmaps x10_calibration_bitmaps x10_button_bitmaps x10_alpha_bitmaps x10_alpha_calibration_bitmaps x10_masks x10_slider_masks x10_layouts_masks x10_themes_bitmaps x10_fonts x10_volume_masks) + add_bitmaps_target(x10_bootloader_bitmaps ${RADIO_SRC_DIRECTORY}/bitmaps/480x272/bootloader/bmp_*.png 480 5/6/5-R) + add_bitmaps_target(x10_bootloader_icons ${RADIO_SRC_DIRECTORY}/bitmaps/480x272/bootloader/icon_*.png 480 8bits) + add_dependencies(x10_bitmaps x10_calibration_bitmaps x10_button_bitmaps x10_alpha_bitmaps x10_alpha_calibration_bitmaps x10_masks x10_slider_masks x10_layouts_masks x10_themes_bitmaps x10_fonts x10_volume_masks x10_bootloader_bitmaps x10_bootloader_icons) endif() diff --git a/radio/src/bitmaps/480x272/bootloader/bmp_plug_usb.png b/radio/src/bitmaps/480x272/bootloader/bmp_plug_usb.png new file mode 100644 index 0000000000000000000000000000000000000000..0f6015747a24a0f6ea8a7feb1f5e6d7be5b3e376 GIT binary patch literal 9330 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 literal 0 HcmV?d00001 diff --git a/radio/src/bitmaps/480x272/bootloader/bmp_usb_plugged.png b/radio/src/bitmaps/480x272/bootloader/bmp_usb_plugged.png new file mode 100644 index 0000000000000000000000000000000000000000..f374f5b77e48920a351f088e4f38a3ea8aede2aa GIT binary patch literal 3722 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 literal 0 HcmV?d00001 diff --git a/radio/src/bitmaps/480x272/bootloader/icon_error.png b/radio/src/bitmaps/480x272/bootloader/icon_error.png new file mode 100644 index 0000000000000000000000000000000000000000..52148e6bee4b2f4d4e3a55d683a770519a15770a GIT binary patch literal 1100 zcmV-S1he~zP)uQ<)0Tn1X{WFBjn z+0-M~=nsFPmy=xJ68}EdCw^7zdF ztL)|z&Tx%f2A0H1fxFnqOSJ(obq(6%Z3YGwC%FR)w!79-X@DuF@=$lDOk6_ZcQk3wFCV z%GpsLsEZ72ce6%7J?lz$+yI{Uk(6nhuOv*5`%n!su)}Q$n~Sb9wCe_Nz>bW0x4p5k zo^)C2YzDTw%}Q)B>}Ep)L%+5nqrRIt%7I0@+?_z4a%F5Yj=LPMR@`Y@w7T9=IqRyL z+6XM#={s@Abs$2HqMcr*V;oaeo z98JB-BHu_jpLdlzQn>wgr+hV5$n$QDK7O~A8v^^I zt#$tJUI$~hQCG(z9N6ZTlp1a^G<5%jVqf;j46NWC9!enf zXt^eS3q7gokSh#pG_%#U5$=#>JM7C&4*N3O4h)@bpQA3XJ52<(x>`MG+14lonaN=* zAE(Mm@=RkoXQhXyx44<8^6AAndJytFByRai{9=M_tiSv zV8-6Vr<~)TXu3{UcR(9mJj3g8B5rDEhZB5AKYwwJ>(OkTC!owio?~6ZH2nu0Y0Nrg Soy^Jr0000P000>X1ONa4Zs1Mm00002VoOIv0RM-N z%)bBt010qNS#tmY79{`x79{~mQY7#I00JdRL_t(I%axQ%NR>ethM!|c@swSJQba24 zj+GJ-U5FN8s6jz3!WKnTL_~{-%vHDxq65&%d>Ea86NQ_*H*vEb{ z!i!WjsrGuv0ugg8vCKRX=UHjoph$H(+$Q1y+kEdwKiOx8XN-v}Y)D65x?L>xp>Z!e zHaR_PrxjwcO<`ov6XF`5`Pvfkrpdsr@2wWg?G7UM%yG8&eQT*$IU)R6!Ohu zM!n@L*NZ#-Zn|!WTkT3A?N)i)H*OMl_`wl}0%b(iPPd4SszxEkX_j!1II}3Donv^ufY0W|}lnbv4kQD2DFomvJ-|Y;$M4c^D4#0G~$2aN=O7)j7g6LES;kk2}**hrKaAwNXYKP4ygADO63 bhfJs6o_vAFXquo*00000NkvXXu0mjf+SD7d literal 0 HcmV?d00001 diff --git a/radio/src/bitmaps/480x272/bootloader/icon_file.png b/radio/src/bitmaps/480x272/bootloader/icon_file.png new file mode 100644 index 0000000000000000000000000000000000000000..515ed0e39d4c05958672b6b2cbe64a40ad9c7383 GIT binary patch literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^fAl$b4ndSdd}o+-9Pw!Yw;NsX^iAoWvPP#VP_i)22*m znbFZP!OT#56Vt+wTAl25r5@7_b!ldY1ifVu{0{bEu{QH+@SFGOy|&mh1QRp zv+Sz$7+1kL40go#VzS2apKJ4i~9deH)6T@y06VxbP9v(ou$Wx&pc3D Uqt%|v5A*|rr>mdKI;Vst07@}o9smFU literal 0 HcmV?d00001 diff --git a/radio/src/bitmaps/480x272/bootloader/icon_flash.png b/radio/src/bitmaps/480x272/bootloader/icon_flash.png new file mode 100644 index 0000000000000000000000000000000000000000..a91436250e8dd1be66ad2cc849f8495aee688937 GIT binary patch literal 696 zcmV;p0!RIcP)P000>X1ONa4Zs1Mm00002VoOIv0RM-N z%)bBt010qNS#tmY79{`x79{~mQY7#I00LY|L_t(I%axQ{XwGpM$3O2jvzOtW)4U98 zj>EPbk_&O8lnV(-mczv^X+?1%IfUHJy;2TWk`zLbV~wGG}PhQ$+bs<^0RpMF%~MB1S>rNswUjzmZ;^^MW_Dk|0W)QkJroY#Jbg zU`UPbcaDe!7CA}8P3m(G_$?C^%5s|%Jfo1ktYjK_r1{P}R`HXw#F;u2ILO|0uDIQY zc8Buzn)bBC-VgZ#YsU}~-QvzHz3 zcprp1f5;1gRqH$pygk&HPMb};ORTYH*tn!rZMRCS3U^=ii6w5c!@t$$L9sM5Mj7OY z%Y1FhI+LOBe(zZ+#=SanU*6L~HH$gH70Ou7Y{rtJnR*`4L>VX9IC5XEd&abS&V?ez zj0am;=s_EXJv5@wPCX?Q11Uc8nwNZ_izu^MK{@jnH|#z{6q2Ngg`C~|qK|B%Od#^t e{fYel9s2`B(l#+)^lVfB0000!Gp)w5YQNd|p$cDu$N z8Uy1-NoRPTk=#ssAlycVLP(8tTI_t66%q`dP;ABBqBG>wt>>+J*c8UXxC^N~H(OU4 z77Y67Fyn5Ac~ckg{U5G_Z(+d_XyhQH{t{3d7HmDuL<57w`>g8?qZ}2`Mzrof{ji~i z!9^Vv`n--R-v=g{RMeI;JWB}xSWS~rQ|@yfr_Z_(gmkSlc|i#agQ6nXOQ!+reak%Jd>qqNT=)#QzCT!vaUUuMFVFg%{+RfGN9wqB&8WH&}CW|ah+IFcua<*SHUA`ebir|Mp(xmX)B&C zBP2ebx)dK?rb^097a#rBC9z6T9_5gd|MIxUMJ3U9%JoiD{_utq0rRelGfYboCzs5) zY@1f$ffN!(L(Y=Rw@>X^WQ`t&4IYH0|5lFNi5+iih4 zrCM$<3OQ!+pc;~WmS;VZGPc_HC|5ZgG$c8eLhGQ6LRloFQ7M*)IO*pWHNq>rqCkn2Y*QWPybq*}@}jSbwjX~}Hc#VTqgm%I64$~27?oa4xRx=(243ImKw zwK@_v9*QOB&k^U3Z9A_S!@*)aWazIJq2lH{{sMQc_X=qRH97zQ002ovPDHLkV1hJ? BZTbKJ literal 0 HcmV?d00001 diff --git a/radio/src/bitmaps/480x272/bootloader/icon_sd.png b/radio/src/bitmaps/480x272/bootloader/icon_sd.png new file mode 100644 index 0000000000000000000000000000000000000000..360ce328f2600aa352b520350407f55013df4bc3 GIT binary patch literal 514 zcmV+d0{#7oP)N8_cduHm^;Ziu!$5Y@(_BSIwm7z>?T73!|8_FL6y zoO`qtd`KKZ&5HUfXxnR+I>B1ea%Y5As9MvB2BGzE?S;qojFc0dL$^WbCXm#!Xe3*7 zzn^OxjUN-y@*y|31(rwtEq)(P7}{&HuO2v{2xFUG`92UWsBC%S&0t#;wM{Et&)}z+ zY*>?LF=EizpUG5lmNWBD*#G}P^X%yGsb*OegOL*hGY6$o5uCPUT{(63WX=^MMRd+> zrQNAB&%5NNk&tut%|~CRF87!-78LD`*k7O1b=n@7U!%^J6Dv%H9RL6T07*qoM6N<$ Eg6d@D-T(jq literal 0 HcmV?d00001 diff --git a/radio/src/definitions.h b/radio/src/definitions.h index 740e6a0de81..02ff26e61e9 100644 --- a/radio/src/definitions.h +++ b/radio/src/definitions.h @@ -29,7 +29,7 @@ #if defined(SIMU) #define __DMA -#elif defined(STM32F4) && !defined(BOOT) +#elif (defined(STM32F4) && !defined(BOOT)) || defined(PCBHORUS) #define __DMA __attribute__((section(".ram"), aligned(32))) #else #define __DMA __ALIGNED diff --git a/radio/src/fonts.h b/radio/src/fonts.h index f9430b8cb68..4a134e58f02 100644 --- a/radio/src/fonts.h +++ b/radio/src/fonts.h @@ -23,8 +23,13 @@ #if defined(COLORLCD) +#if !defined(BOOT) extern const uint16_t * const fontspecsTable[16]; extern const uint8_t * const fontsTable[16]; +#else +extern const uint16_t * const fontspecsTable[1]; +extern const uint8_t * const fontsTable[1]; +#endif #if defined(PCBHORUS) extern BitmapBuffer * fontCache[2]; diff --git a/radio/src/gui/480x272/bitmapbuffer.cpp b/radio/src/gui/480x272/bitmapbuffer.cpp index 6060a728fd9..204249e9904 100644 --- a/radio/src/gui/480x272/bitmapbuffer.cpp +++ b/radio/src/gui/480x272/bitmapbuffer.cpp @@ -320,10 +320,12 @@ void BitmapBuffer::drawSizedText(coord_t x, coord_t y, const char * s, uint8_t l const uint16_t * fontspecs = fontspecsTable[fontindex]; BitmapBuffer * fontcache = NULL; - if (flags & RIGHT) + if (flags & RIGHT) { INCREMENT_POS(-width); - else if (flags & CENTERED) + } + else if (flags & CENTERED) { INCREMENT_POS(-width/2); + } coord_t & pos = (flags & VERTICAL) ? y : x; @@ -380,11 +382,11 @@ void BitmapBuffer::drawSizedText(coord_t x, coord_t y, const char * s, uint8_t l bool setpos = false; const coord_t orig_pos = pos; while (len--) { - unsigned char c; - if (flags & ZCHAR) - c = idx2char(*s); - else - c = pgm_read_byte(s); +#if defined(BOOT) + unsigned char c = *s; +#else + unsigned char c = (flags & ZCHAR) ? idx2char(*s) : *s; +#endif if (setpos) { pos = c; setpos = false; diff --git a/radio/src/gui/480x272/fonts.cpp b/radio/src/gui/480x272/fonts.cpp index ea953f059b9..75cc2b98352 100644 --- a/radio/src/gui/480x272/fonts.cpp +++ b/radio/src/gui/480x272/fonts.cpp @@ -20,6 +20,7 @@ #include "opentx.h" +#if !defined(BOOT) const uint16_t font_tinsize_specs[] = { #include "font_tinsize.specs" }; @@ -35,6 +36,7 @@ const uint16_t font_smlsize_specs[] = { const pm_uchar font_smlsize[] = { #include "font_smlsize.lbm" }; +#endif const uint16_t font_stdsize_specs[] = { #include "font_stdsize.specs" @@ -44,6 +46,7 @@ const pm_uchar font_stdsize[] = { #include "font_stdsize.lbm" }; +#if !defined(BOOT) const uint16_t font_midsize_specs[] = { #include "font_midsize.specs" }; @@ -75,7 +78,9 @@ const uint16_t font_stdsizebold_specs[] = { const pm_uchar font_stdsizebold[] = { #include "font_stdsizebold.lbm" }; +#endif +#if !defined(BOOT) const uint16_t * const fontspecsTable[16] = { font_stdsize_specs, font_tinsize_specs, font_smlsize_specs, font_midsize_specs, font_dblsize_specs, font_xxlsize_specs, font_stdsize_specs, font_stdsize_specs, font_stdsizebold_specs, font_tinsize_specs, font_smlsize_specs, font_midsize_specs, font_dblsize_specs, font_xxlsize_specs, font_stdsize_specs, font_stdsize_specs @@ -85,6 +90,10 @@ const uint8_t * const fontsTable[16] = { font_stdsize, font_tinsize, font_smlsize, font_midsize, font_dblsize, font_xxlsize, font_stdsize, font_stdsize, font_stdsizebold, font_tinsize, font_smlsize, font_midsize, font_dblsize, font_xxlsize, font_stdsize, font_stdsize }; +#else +const uint16_t * const fontspecsTable[1] = { font_stdsize_specs }; +const uint8_t * const fontsTable[1] = { font_stdsize }; +#endif BitmapBuffer * fontCache[2] = { NULL, NULL }; diff --git a/radio/src/gui/480x272/lcd.cpp b/radio/src/gui/480x272/lcd.cpp index a6d69df10cf..88384eb6a35 100644 --- a/radio/src/gui/480x272/lcd.cpp +++ b/radio/src/gui/480x272/lcd.cpp @@ -21,6 +21,7 @@ #include #include #include "opentx.h" +#include "strhelpers.h" #if defined(SIMU) display_t displayBuf[DISPLAY_BUFFER_SIZE]; @@ -103,11 +104,12 @@ int getTextWidth(const char * s, int len, LcdFlags flags) int result = 0; for (int i=0; len==0 || i> 8) +#else +#define FONTSIZE(flags) STDSIZE +#define FONTINDEX(flags) STDSIZE_INDEX +#endif #define TIMEBLINK 0x1000 #define TIMEHOUR 0x2000 @@ -134,6 +140,13 @@ inline void lcdDrawSizedText(coord_t x, coord_t y, const pm_char * s, uint8_t le void lcdDrawHexNumber(coord_t x, coord_t y, uint32_t val, LcdFlags mode=0); void lcdDrawNumber(coord_t x, coord_t y, int32_t val, LcdFlags flags=0, uint8_t len=0, const char * prefix=NULL, const char * suffix=NULL); +#if !defined(BOOT) + +#define putstime_t int32_t + +void drawRtcTime(coord_t x, coord_t y, LcdFlags att=0); +void drawTimer(coord_t x, coord_t y, putstime_t tme, LcdFlags att=0); + void putsModelName(coord_t x, coord_t y, char *name, uint8_t id, LcdFlags att); void putsStickName(coord_t x, coord_t y, uint8_t idx, LcdFlags att=0); void drawSwitch(coord_t x, coord_t y, swsrc_t swtch, LcdFlags flags=0); @@ -145,10 +158,7 @@ void drawTrimMode(coord_t x, coord_t y, uint8_t phase, uint8_t idx, LcdFlags att #define putsChn(x, y, idx, att) drawSource(x, y, MIXSRC_CH1+idx-1, att) void putsChnLetter(coord_t x, coord_t y, uint8_t idx, LcdFlags attr); -#define putstime_t int32_t - -void drawRtcTime(coord_t x, coord_t y, LcdFlags att=0); -void drawTimer(coord_t x, coord_t y, putstime_t tme, LcdFlags att=0); +#endif // !BOOT #define SOLID 0xff #define DOTTED 0x55 diff --git a/radio/src/loadboot.cpp b/radio/src/loadboot.cpp deleted file mode 100644 index ae687e98051..00000000000 --- a/radio/src/loadboot.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "opentx.h" - -#if defined(PCBSKY9X) - #include "AT91SAM3S4.h" -#else - #include "targets/taranis/board.h" -#endif - -#if defined(PCBTARANIS) -void bwdt_reset() -{ - IWDG->KR = 0xAAAA; // reload -} -#endif - -#if defined(PCBTARANIS) -// TODO needed? -__attribute__ ((section(".bootrodata"), used)) -void _bootStart(void); -#endif - -#if defined(PCBTARANIS) -__attribute__ ((section(".isr_boot_vector"), used)) -const uint32_t BootVectors[] = { - (uint32_t) &_estack, - (uint32_t) (void (*)(void)) ((unsigned long) &_bootStart) }; -#endif - -#if defined(PCBTARANIS) -__attribute__ ((section(".bootrodata.*"), used)) -#elif defined(PCBSKY9X) -__attribute__ ((section(".bootrodata"), used)) -#endif - -const uint8_t BootCode[] = { -#include "bootloader.lbm" -}; - -#if defined(PCBTARANIS) -__attribute__ ((section(".bootrodata"), used)) -void _bootStart() -{ -#if defined(PCBX9E) - RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_GPIOGEN | RCC_AHB1ENR_GPIODEN; -#else - RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_GPIOEEN | RCC_AHB1ENR_GPIODEN; -#endif - - // these two NOPs are needed (see STM32F errata sheet) before the peripheral - // register can be written after the peripheral clock was enabled - __ASM volatile ("nop"); - __ASM volatile ("nop"); - - // Turn soft power ON now, but only if we got started because of the watchdog - // or software reset. If the radio was started by user pressing the power button - // then that button is providing power and we don't need to enable it here. - // - // If we were to turn it on here indiscriminately, then the radio can go into the - // power on/off loop after being powered off by the user. (issue #2790) - if (WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) { - GPIOD->BSRRL = 1; // set PWR_ON_GPIO_PIN pin to 1 - GPIOD->MODER = (GPIOD->MODER & 0xFFFFFFFC) | 1; // General purpose output mode - } - - // TRIMS_GPIO_PIN_LHR is on PG0 on X9E and on PE3 on Taranis - // TRIMS_GPIO_PIN_RHL is on PC1 on all versions - // turn on pull-ups on trim keys - GPIOC->PUPDR = 0x00000004; -#if defined(PCBX9E) - GPIOG->PUPDR = 0x00000001; -#else - GPIOE->PUPDR = 0x00000040; -#endif - - // wait for inputs to stabilize - for (uint32_t i = 0; i < 50000; i += 1) { - bwdt_reset(); - } - - // now the second part of power on sequence - // If we got here and the radio was not started by the watchdog/software reset, - // then we must have a power button pressed. If not then we are in power on/off loop - // and to terminate it, just wait here without turning on PWR pin. The power supply will - // eventually exhaust and the radio will turn off. - if (!WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) { - // wait here until the power key is pressed - while (GPIOD->IDR & PWR_SWITCH_GPIO_PIN) { - bwdt_reset(); - } - } - - if (!(TRIMS_GPIO_REG_LHR & TRIMS_GPIO_PIN_LHR) && !(TRIMS_GPIO_REG_RHL & TRIMS_GPIO_PIN_RHL)) { - // Bootloader needed - const uint8_t *src; - uint8_t *dest; - uint32_t size; - - bwdt_reset(); - size = sizeof(BootCode); - src = BootCode; - dest = (uint8_t *) 0x20000000; - - for (; size; size -= 1) { - *dest++ = *src++; - } - // Could check for a valid copy to RAM here - // Go execute bootloader - bwdt_reset(); - - uint32_t address = *(uint32_t *) 0x20000004; - - ((void (*)(void)) (address))(); // Go execute the loaded application - } - -// run_application() ; - asm(" mov.w r1, #134217728"); - // 0x8000000 - asm(" add.w r1, #32768"); - // 0x8000 - - asm(" movw r0, #60680"); - // 0xED08 - asm(" movt r0, #57344"); - // 0xE000 - asm(" str r1, [r0, #0]"); - // Set the VTOR - - asm("ldr r0, [r1, #0]"); - // Stack pointer value - asm("msr msp, r0"); - // Set it - asm("ldr r0, [r1, #4]"); - // Reset address - asm("mov.w r1, #1"); - asm("orr r0, r1"); - // Set lsbit - asm("bx r0"); - // Execute application -} -#endif - diff --git a/radio/src/opentx.h b/radio/src/opentx.h index f093549d1c1..a803ec6e4a4 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -980,7 +980,12 @@ extern const char eeprom_stamp[]; #else extern const char vers_stamp[]; #endif -const char* getOtherVersion(); +/** + * Tries to find opentx version in the first 1024 byte of either firmware/bootloader (the one not running) or the buffer + * @param buffer If non-null find the firmware version in the buffer instead + * @return The opentx version string starting with "opentx-" or "no version found" if the version string is not found + */ +const char* getOtherVersion(char* buffer); extern uint8_t g_vbat100mV; #if LCD_W > 128 diff --git a/radio/src/serial.cpp b/radio/src/serial.cpp index e7548f2347f..1fa7897658f 100644 --- a/radio/src/serial.cpp +++ b/radio/src/serial.cpp @@ -26,8 +26,10 @@ #define PRINTF_BUFFER_SIZE 128 void serialPutc(char c) { +#if !defined(BOOT) if (getSelectedUsbMode() == USB_SERIAL_MODE) usbSerialPutc(c); +#endif #if defined(SERIAL2) if (serial2TracesEnabled()) serial2Putc(c); diff --git a/radio/src/stamp.cpp b/radio/src/stamp.cpp index a3f32434b78..e26e83e393b 100644 --- a/radio/src/stamp.cpp +++ b/radio/src/stamp.cpp @@ -49,23 +49,24 @@ * Retrieves the version of the bootloader or firmware * @return */ -#if defined(HORUS) -const char* getOtherVersion() -{ - return "no bootloader support"; -} -#elif defined(STM32) +#if defined(STM32) __attribute__ ((section(".fwversiondata"), used)) const char firmware_version[32] = "opentx-" FLAVOUR "-" VERSION " (" GIT_STR ")"; __attribute__ ((section(".bootversiondata"), used)) const char boot_version[32] = "opentx-" FLAVOUR "-" VERSION " (" GIT_STR ")"; -const char* getOtherVersion() +/** + * Tries to find opentx version in the first 1024 byte of either firmware/bootloader (the one not running) or the buffer + * @param buffer If non-null find the firmware version in the buffer instead + */ +const char* getOtherVersion(char* buffer) { #if defined(BOOT) const char* startother = (char*)(FIRMWARE_ADDRESS+BOOTLOADER_SIZE); #else const char* startother = (char*)(FIRMWARE_ADDRESS); #endif + if (buffer != nullptr) + startother=buffer; const char* other_str = nullptr; for (int i=0; i< 1024;i++) { diff --git a/radio/src/targets/common/arm/loadboot.cpp b/radio/src/targets/common/arm/loadboot.cpp new file mode 100644 index 00000000000..3eb0d390b8a --- /dev/null +++ b/radio/src/targets/common/arm/loadboot.cpp @@ -0,0 +1,25 @@ +/* + * 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. + */ + +__attribute__ ((section(".bootloader"), used)) + +const unsigned char BootCode[] = { +#include "bootloader.lbm" +}; diff --git a/radio/src/targets/common/arm/stm32/CMakeLists.txt b/radio/src/targets/common/arm/stm32/CMakeLists.txt index a2c232e5a59..c99efa07575 100644 --- a/radio/src/targets/common/arm/stm32/CMakeLists.txt +++ b/radio/src/targets/common/arm/stm32/CMakeLists.txt @@ -36,6 +36,7 @@ set(FIRMWARE_TARGET_SRC ../common/arm/stm32/usbd_desc.c ../common/arm/stm32/usbd_usr.cpp ../common/arm/stm32/usb_driver.cpp + ../common/arm/stm32/flash_driver.cpp ) set(FIRMWARE_TARGET_SRC ${FIRMWARE_TARGET_SRC} diff --git a/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt b/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt new file mode 100644 index 00000000000..d9cd29bcd09 --- /dev/null +++ b/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt @@ -0,0 +1,130 @@ +# TODO if the files order is different (these 2 SRC sections exchanged), the bootloader hangs for 20s in USB init. Why? + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + +if(PCB STREQUAL X12S OR PCB STREQUAL X10) + set(BOOTLOADER_SRC + ${BOOTLOADER_SRC} + ../f4/system_stm32f4xx.c + ../../../../../targets/${TARGET_DIR}/startup_stm32f42_43xxx.s + ../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rcc.c + ../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_gpio.c + ../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_spi.c + ../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_fmc.c + ../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_ltdc.c + ../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_dma.c + ../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_dma2d.c + ../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_sdio.c + ../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/misc.c + ) +elseif(PCB STREQUAL X9E) + set(BOOTLOADER_SRC + ${BOOTLOADER_SRC} + ../f4/system_stm32f4xx.c + ../../../../../${STM32LIB_DIR}/CMSIS/Device/ST/STM32F4xx/Source/Templates/gcc_ride7/startup_stm32f40_41xxx.s + ../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rcc.c + ../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_gpio.c + ../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_spi.c + ../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_i2c.c + ../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/misc.c + ) +else() + set(BOOTLOADER_SRC + ${BOOTLOADER_SRC} + ../f2/system_stm32f2xx.c + ../../../../../${STM32LIB_DIR}/CMSIS/Device/ST/STM32F2xx/Source/Templates/gcc_ride7/startup_stm32f2xx.s + ../../../../../${STM32LIB_DIR}/STM32F2xx_StdPeriph_Driver/src/stm32f2xx_rcc.c + ../../../../../${STM32LIB_DIR}/STM32F2xx_StdPeriph_Driver/src/stm32f2xx_gpio.c + ../../../../../${STM32LIB_DIR}/STM32F2xx_StdPeriph_Driver/src/stm32f2xx_spi.c + ../../../../../${STM32LIB_DIR}/STM32F2xx_StdPeriph_Driver/src/stm32f2xx_i2c.c + ../../../../../${STM32LIB_DIR}/STM32F2xx_StdPeriph_Driver/src/misc.c + ) +endif() + +set(BOOTLOADER_SRC + ${BOOTLOADER_SRC} + ../../../../../gui/${GUI_DIR}/lcd.cpp + ../../../../../gui/${GUI_DIR}/fonts.cpp + ../../../../../keys.cpp + ../../../../../strhelpers.cpp + ../../../../../stamp.cpp + ../../../../../${STM32USB_DIR}/STM32_USB_OTG_Driver/src/usb_core.c + ../../../../../${STM32USB_DIR}/STM32_USB_OTG_Driver/src/usb_dcd.c + ../../../../../${STM32USB_DIR}/STM32_USB_OTG_Driver/src/usb_dcd_int.c + ../../../../../${STM32USB_DIR}/STM32_USB_Device_Library/Core/src/usbd_core.c + ../../../../../${STM32USB_DIR}/STM32_USB_Device_Library/Core/src/usbd_ioreq.c + ../../../../../${STM32USB_DIR}/STM32_USB_Device_Library/Core/src/usbd_req.c + ../../../../../${STM32USB_DIR}/STM32_USB_Device_Library/Class/msc/src/usbd_msc_data.c + ../../../../../${STM32USB_DIR}/STM32_USB_Device_Library/Class/msc/src/usbd_msc_scsi.c + ../../../../../${STM32USB_DIR}/STM32_USB_Device_Library/Class/msc/src/usbd_msc_bot.c + ../../../../../${STM32USB_DIR}/STM32_USB_Device_Library/Class/msc/src/usbd_msc_core.c + ../../../../../${FATFS_DIR}/ff.c + ../../../../../${FATFS_DIR}/option/ccsbcs.c + ../../../../../targets/${TARGET_DIR}/${LCD_DRIVER} + ../../../../../targets/${TARGET_DIR}/backlight_driver.cpp + ../../../../../targets/${TARGET_DIR}/keys_driver.cpp + ../../../../../targets/${TARGET_DIR}/diskio.cpp + ../../../../../targets/${TARGET_DIR}/pwr_driver.cpp + ../../../../../targets/${TARGET_DIR}/bootloader/boot_menu.cpp + ../usbd_usr.cpp + ../usbd_storage_msd.cpp + ../delays.cpp + ../usbd_desc.c + ../usb_bsp.c + ../usb_driver.cpp + ../flash_driver.cpp + init.c + boot.cpp + bin_files.cpp + ) + +if(NOT (PCB STREQUAL X10 OR PCB STREQUAL X12S)) + set(BOOTLOADER_SRC + ${BOOTLOADER_SRC} + ../../../../../targets/${TARGET_DIR}/i2c_driver.cpp + ) + + remove_definitions(-DDEBUG) + +else() + set(BOOTLOADER_SRC + ${BOOTLOADER_SRC} + ../../../../../targets/${TARGET_DIR}/sdram_driver.c + ../../../../../targets/${TARGET_DIR}/sdio_sd.c + ../../../../../targets/${TARGET_DIR}/haptic_driver.cpp + ../../../../../gui/${GUI_DIR}/bitmapbuffer.cpp + ../../../../../syscalls.c + ) + + if(DEBUG) + set(BOOTLOADER_SRC + ${BOOTLOADER_SRC} + ../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_usart.c + ../../../../../serial.cpp + ../serial2_driver.cpp + ) + endif() +endif() + +remove_definitions(-DDISK_CACHE) +remove_definitions(-DLUA) +remove_definitions(-DCLI) +add_definitions(-DBOOT) + +set(CMAKE_EXE_LINKER_FLAGS "-mcpu=${MCU} -mthumb -nostartfiles -lm -T${RADIO_SRC_DIRECTORY}/targets/${TARGET_DIR}/stm32_ramboot.ld -Wl,-Map=bootloader.map,--cref,--no-warn-mismatch,--gc-sections") + +add_executable(bootloader ${BOOTLOADER_SRC}) +add_dependencies(bootloader ${BITMAPS_TARGET} firmware_translations) + +add_custom_command( + TARGET bootloader POST_BUILD + COMMAND arm-none-eabi-objcopy -O binary bootloader.elf bootloader.bin +) +if(PYTHONINTERP_FOUND) + add_custom_command( + TARGET bootloader POST_BUILD + COMMAND ${PYTHON_EXECUTABLE} ${RADIO_DIRECTORY}/util/bin2lbm.py bootloader.bin bootloader.lbm + ) +endif() + +PrintTargetReport("bootloader") diff --git a/radio/src/targets/common/arm/stm32/bootloader/bin_files.cpp b/radio/src/targets/common/arm/stm32/bootloader/bin_files.cpp new file mode 100644 index 00000000000..3684f45d7ca --- /dev/null +++ b/radio/src/targets/common/arm/stm32/bootloader/bin_files.cpp @@ -0,0 +1,145 @@ +#include "opentx.h" +#include "boot.h" +#include "bin_files.h" + +// 'private' +static DIR dir; +static FIL FlashFile; + +// 'public' variables +BinFileInfo binFiles[MAX_BIN_FILES]; +uint8_t Block_buffer[BLOCK_LEN]; +UINT BlockCount; + + +FRESULT openBinDir(MemoryType mt) +{ + FRESULT fr = f_chdir(getBinaryPath(mt)); + if (fr != FR_OK) return fr; + + return f_opendir(&dir, "."); +} + +static FRESULT findNextBinFile(FILINFO* fno) +{ + FRESULT fr; + + do { + fr = f_readdir(&dir, fno); + + if (fr != FR_OK || fno->fname[0] == 0) + break; + + int32_t len = strlen(fno->fname) - 4; + if (len < 0) + continue; + + if (fno->fname[len] != '.') + continue; + + if ((fno->fname[len + 1] != 'b') && (fno->fname[len + 1] != 'B')) + continue; + + if ((fno->fname[len + 2] != 'i') && (fno->fname[len + 2] != 'I')) + continue; + + if ((fno->fname[len + 3] != 'n') && (fno->fname[len + 3] != 'N')) + continue; + + // match! + break; + + } while (1); + + return fr; +} + +unsigned int fetchBinFiles(unsigned int index) +{ + FILINFO file_info; + + // rewind + if (f_readdir(&dir, NULL) != FR_OK) + return 0; + + // skip 'index' .bin files + for (unsigned int i = 0; i <= index; i++) { + + if (findNextBinFile(&file_info) != FR_OK /*|| file_info.fname[0] == 0*/) + return 0; + } + + strAppend(binFiles[0].name, file_info.fname); + binFiles[0].size = file_info.fsize; + + unsigned int i = 1; + for (; i < MAX_NAMES_ON_SCREEN+1; i++) { + + if (findNextBinFile(&file_info) != FR_OK || file_info.fname[0] == 0) + return i; + + strAppend(binFiles[i].name, file_info.fname); + binFiles[i].size = file_info.fsize; + } + + return i; +} + +FRESULT openBinFile(MemoryType mt, unsigned int index) +{ + TCHAR full_path[_MAX_LFN+1]; + FRESULT fr; + + // build full_path: [bin path]/[filename] + char* s = strAppend(full_path, getBinaryPath(mt)); + s = strAppend(s, "/"); + strAppend(s, binFiles[index].name); + + BlockCount = 0; + + // open the file + if ((fr = f_open(&FlashFile, full_path, FA_READ)) != FR_OK) + return fr; + + // skip bootloader in firmware + if (mt == MEM_FLASH && + ((fr = f_lseek(&FlashFile, BOOTLOADER_SIZE)) != FR_OK)) + return fr; + + // ... and fetch BLOCK_LEN bytes + fr = f_read(&FlashFile, Block_buffer, BLOCK_LEN, &BlockCount); + + if (BlockCount == BLOCK_LEN) + return fr; + + return FR_INVALID_OBJECT; +} + +void extractFirmwareVersion(VersionTag* tag) +{ + const char* vers = getOtherVersion((char*)Block_buffer); + if (!vers || (vers[0] == 'n' && vers[1] == 'o')) { // "no version found" + memcpy(tag->flavour, "unknown", sizeof("unknown")); + tag->version = "unknown"; + } + + // skip "opentx-" + vers += sizeof("opentx-") - 1; + + char* fl = tag->flavour; + while(*vers != '-') + *(fl++) = *(vers++); + + tag->version = ++vers; +} + +FRESULT readBinFile() +{ + BlockCount = 0; + return f_read(&FlashFile, Block_buffer, sizeof(Block_buffer), &BlockCount); +} + +FRESULT closeBinFile() +{ + return f_close(&FlashFile); +} diff --git a/radio/src/targets/common/arm/stm32/bootloader/bin_files.h b/radio/src/targets/common/arm/stm32/bootloader/bin_files.h new file mode 100644 index 00000000000..33be0af2731 --- /dev/null +++ b/radio/src/targets/common/arm/stm32/bootloader/bin_files.h @@ -0,0 +1,88 @@ +/* + * 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. + */ + +#ifndef _bin_files_h_ +#define _bin_files_h_ + +#include "opentx.h" + +enum MemoryType { + MEM_FLASH, + MEM_EEPROM +}; + +#if defined(EEPROM) +#define getBinaryPath(mt) ((mt == MEM_FLASH) ? FIRMWARES_PATH : EEPROMS_PATH) +#else +#define getBinaryPath(mt) (FIRMWARES_PATH) +#endif + +#define MAX_NAMES_ON_SCREEN 6 +#define MAX_BIN_FILES (MAX_NAMES_ON_SCREEN+1) + +// Size of the block read when checking / writing BIN files +#define BLOCK_LEN 4096 + +// File info struct while browsing files on SD card +struct BinFileInfo { + TCHAR name[_MAX_LFN + 1]; + unsigned int size; +}; + +// File info storage while browsing files on SD card +extern BinFileInfo binFiles[MAX_BIN_FILES]; + +// Block buffer used when checking / writing BIN files +extern uint8_t Block_buffer[BLOCK_LEN]; + +// Bytes read into the Block_buffer +extern UINT BlockCount; + +// Open directory for EEPROM / firmware files +FRESULT openBinDir(MemoryType mt); + +// Fetch file names and sizes into binFiles, +// starting at the provided index. +// Only files ending with ".bin" (case-insensitive) +// will be considered. +unsigned int fetchBinFiles(unsigned int index); + +// Open file indexed in binFiles and read the first BLOCK_LEN bytes +// Bootloader is skipped in firmware files +FRESULT openBinFile(MemoryType mt, unsigned int index); + +struct VersionTag +{ + char flavour[8]; + const char* version; +}; + +// Can be called right after openBinFile() to extract the version information +// from a firmware file +void extractFirmwareVersion(VersionTag* tag); + +// Read the next BLOCK_LEN bytes into 'Block_buffer' +// Check 'BlockCount' for # of bytes read +FRESULT readBinFile(); + +// Close the previously opened file +FRESULT closeBinFile(); + +#endif diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp new file mode 100644 index 00000000000..f0cf3de2dae --- /dev/null +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp @@ -0,0 +1,523 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "opentx.h" +#include "stamp.h" + +#include "boot.h" +#include "bin_files.h" + +#define APP_START_ADDRESS (uint32_t)(FIRMWARE_ADDRESS + BOOTLOADER_SIZE) + +#if defined(EEPROM) +#define MAIN_MENU_LEN 3 +#else +#define MAIN_MENU_LEN 2 +#endif + +typedef void (*voidFunction)(void); + +#define jumpTo(addr) { \ + SCB->VTOR = addr; \ + __set_MSP(*(__IO uint32_t*)addr); \ + uint32_t jumpAddress = *(uint32_t*)(addr + 4); \ + voidFunction jumpFn = (voidFunction)jumpAddress; \ + jumpFn(); \ + } + +// Bootloader marker: +// -> used to detect valid bootloader files +const uint8_t bootloaderVersion[] __attribute__ ((section(".version"), used)) = +{ 'B', 'O', 'O', 'T', '1', '0' }; + +#if defined(ROTARY_ENCODER_NAVIGATION) +volatile rotenc_t rotencValue[1] = {0}; +#endif + +/*---------------------------------------------------------------------------- + * Local variables + *----------------------------------------------------------------------------*/ + +uint32_t FirmwareSize; +uint32_t firmwareAddress = FIRMWARE_ADDRESS; +uint32_t firmwareWritten = 0; + +#if defined(EEPROM) +uint32_t eepromAddress = 0; +uint32_t eepromWritten = 0; +#endif + +//TCHAR backupFilename[_MAX_LFN+1]; + +//uint32_t Master_frequency; +volatile uint8_t Tenms = 1; + +FlashCheckRes Valid; + +MemoryType memoryType; +uint32_t unlocked = 0; + +void interrupt10ms(void) +{ + Tenms |= 1; // 10 mS has passed + + uint8_t index = 0; + uint8_t in = readKeys(); + for (uint8_t i = 1; i != uint8_t(1 << TRM_BASE); i <<= 1) { + uint8_t value = (in & i); + keys[index].input(value); + ++index; + } + +#if defined(ROTARY_ENCODER_NAVIGATION) + checkRotaryEncoder(); + static rotenc_t rePreviousValue; + rotenc_t reNewValue = (rotencValue[0] / 2); + int8_t scrollRE = reNewValue - rePreviousValue; + if (scrollRE) { + rePreviousValue = reNewValue; + if (scrollRE < 0) { + putEvent(EVT_KEY_FIRST(KEY_UP)); //EVT_ROTARY_LEFT + } + else { + putEvent(EVT_KEY_FIRST(KEY_DOWN)); //EVT_ROTARY_RIGHT + } + } +#endif +} + +void init10msTimer() +{ + INTERRUPT_xMS_TIMER->ARR = 9999; // 10mS in uS + INTERRUPT_xMS_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1; // 1uS + INTERRUPT_xMS_TIMER->CCER = 0; + INTERRUPT_xMS_TIMER->CCMR1 = 0; + INTERRUPT_xMS_TIMER->EGR = 0; + INTERRUPT_xMS_TIMER->CR1 = 5; + INTERRUPT_xMS_TIMER->DIER |= 1; + NVIC_EnableIRQ(INTERRUPT_xMS_IRQn); +} + +extern "C" void INTERRUPT_xMS_IRQHandler() +{ + INTERRUPT_xMS_TIMER->SR &= ~TIM_SR_UIF; + interrupt10ms(); +} + +uint32_t isValidBufferStart(const uint8_t * buffer) +{ +#if defined(EEPROM) + if (memoryType == MEM_FLASH) + return isFirmwareStart(buffer); + else + return isEepromStart(buffer); +#else + return isFirmwareStart(buffer); +#endif +} + +FlashCheckRes checkFlashFile(unsigned int index, FlashCheckRes res) +{ + if (res != FC_UNCHECKED) + return res; + + if (openBinFile(memoryType, index) != FR_OK) + return FC_ERROR; + + if (closeBinFile() != FR_OK) + return FC_ERROR; + + if (!isValidBufferStart(Block_buffer)) + return FC_ERROR; + + return FC_OK; +} + +int menuFlashFile(uint32_t index, event_t event) +{ + Valid = checkFlashFile(index, Valid); + + if (Valid == FC_ERROR) { + + if (event == EVT_KEY_BREAK(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_ENTER)) + return 0; + + return -1; + } + + if (event == EVT_KEY_LONG(KEY_ENTER)) { + + return (openBinFile(memoryType, index) == FR_OK) && isValidBufferStart(Block_buffer); + } + else if (event == EVT_KEY_BREAK(KEY_EXIT)) + return 0; + + return -1; +} + +extern Key keys[]; + +static uint32_t PowerUpDelay; + +void flashWriteBlock() +{ + uint32_t blockOffset = 0; + while (BlockCount) { + flashWrite((uint32_t *)firmwareAddress, (uint32_t *)&Block_buffer[blockOffset]); + blockOffset += FLASH_PAGESIZE; + firmwareAddress += FLASH_PAGESIZE; + if (BlockCount > FLASH_PAGESIZE) { + BlockCount -= FLASH_PAGESIZE; + } + else { + BlockCount = 0; + } + } +} + +#if defined(EEPROM) +void writeEepromBlock() +{ + eepromWriteBlock(Block_buffer, eepromAddress, BlockCount); + eepromAddress += BlockCount; +} +#endif + +int main() +{ + BootloaderState state = ST_START; + uint32_t vpos = 0; + uint8_t index = 0; + FRESULT fr; + uint32_t nameCount = 0; + + wdt_reset(); + RCC_AHB1PeriphClockCmd(PWR_RCC_AHB1Periph | KEYS_RCC_AHB1Periph | + LCD_RCC_AHB1Periph | BACKLIGHT_RCC_AHB1Periph | + SERIAL_RCC_AHB1Periph | I2C_RCC_AHB1Periph | + SD_RCC_AHB1Periph, ENABLE); + + RCC_APB1PeriphClockCmd(LCD_RCC_APB1Periph | BACKLIGHT_RCC_APB1Periph | + INTERRUPT_xMS_RCC_APB1Periph | I2C_RCC_APB1Periph | + SERIAL_RCC_APB1Periph | + SD_RCC_APB1Periph, ENABLE); + + RCC_APB2PeriphClockCmd(LCD_RCC_APB2Periph | BACKLIGHT_RCC_APB2Periph, ENABLE); + + keysInit(); + + // wait for inputs to stabilize + for (uint32_t i = 0; i < 50000; i += 1) { + wdt_reset(); + } + + // LHR & RHL trims not pressed simultanously + if (readTrims() != 0x42) { + // Start main application + jumpTo(APP_START_ADDRESS); + } + + pwrInit(); + delaysInit(); // needed for lcdInit() + +#if defined(DEBUG) + serial2Init(UART_MODE_DEBUG, 0); // default serial mode (None if DEBUG not defined) +#endif + + __enable_irq(); + TRACE("\nBootloader started :)"); + + lcdInit(); + backlightInit(); + +#if defined(PCBTARANIS) + i2cInit(); +#endif + init10msTimer(); + + // SD card detect pin + sdInit(); + usbInit(); + + // init screen + bootloaderInitScreen(); + +#if defined(PWR_PRESS_BUTTON) or defined(PCBHORUS) + // wait until power button is released + while(pwrPressed()) { + wdt_reset(); + } +#endif + + for (;;) { + wdt_reset(); + + if (Tenms) { + Tenms = 0; + + if (state != ST_USB) { + if (usbPlugged()) { + state = ST_USB; + if (!unlocked) { + unlocked = 1; + unlockFlash(); + } + usbStart(); + usbPluggedIn(); + } + } + + if (state == ST_USB) { + if (usbPlugged() == 0) { + vpos = 0; + usbStop(); + if (unlocked) { + lockFlash(); + unlocked = 0; + } + state = ST_START; + } + bootloaderDrawScreen(state, 0); + } + + lcdRefreshWait(); + event_t event = getEvent(); + + if (state == ST_START) { + + bootloaderDrawScreen(state, vpos); + + if (event == EVT_KEY_FIRST(KEY_DOWN)) { + vpos = (vpos + 1) % MAIN_MENU_LEN; + continue; + } + else if (event == EVT_KEY_FIRST(KEY_UP)) { + vpos = (vpos + MAIN_MENU_LEN - 1) % MAIN_MENU_LEN; + continue; + } + else if (event == EVT_KEY_BREAK(KEY_ENTER)) { + switch (vpos) { + case 0: + memoryType = MEM_FLASH; + state = ST_DIR_CHECK; + break; +#if defined(EEPROM) + case 1: + memoryType = MEM_EEPROM; + state = ST_DIR_CHECK; + break; +#endif + default: + state = ST_REBOOT; + break; + } + + // next loop + continue; + } + } + else if (state == ST_DIR_CHECK) { + + fr = openBinDir(memoryType); + + if (fr == FR_OK) { + index = vpos = 0; + state = ST_FILE_LIST; + nameCount = fetchBinFiles(index); + continue; + } + else { + bootloaderDrawScreen(state, fr); + + if (event == EVT_KEY_BREAK(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_ENTER)) { + vpos = 0; + state = ST_START; + continue; + } + } + } + + if (state == ST_FILE_LIST) { + + uint32_t limit = MAX_NAMES_ON_SCREEN; + if (nameCount < limit) { + limit = nameCount; + } + + if (event == EVT_KEY_REPT(KEY_DOWN) || event == EVT_KEY_FIRST(KEY_DOWN)) { + if (vpos < limit - 1) { + vpos += 1; + } + else { + if (nameCount > limit) { + index += 1; + nameCount = fetchBinFiles(index); + } + } + } + else if (event == EVT_KEY_REPT(KEY_UP) || event == EVT_KEY_FIRST(KEY_UP)) { + if (vpos > 0) { + vpos -= 1; + } + else { + if (index) { + index -= 1; + nameCount = fetchBinFiles(index); + } + } + } + + bootloaderDrawScreen(state, 0); + + for (uint32_t i=0; i= FLASHSIZE - BOOTLOADER_SIZE)) { + state = ST_FLASH_DONE; // Backstop + } +#if defined(EEPROM) + else if ((memoryType == MEM_EEPROM) && + (eepromWritten >= EEPROM_SIZE)) { + state = ST_FLASH_DONE; // Backstop + } +#endif + } + + if (state == ST_FLASH_DONE) { + if (unlocked) { + lockFlash(); + unlocked = 0; + } + + if (event == EVT_KEY_BREAK(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_ENTER)) { + state = ST_START; + vpos = 0; + } + + bootloaderDrawScreen(state, 100); + } + + if (event == EVT_KEY_LONG(KEY_EXIT)) { + // Start the main application + + state = ST_REBOOT; + } + + lcdRefresh(); + + if (PowerUpDelay < 20) { // 200 mS + PowerUpDelay += 1; + } + else { + sdPoll10ms(); + } + } + + if (state != ST_FLASHING && state != ST_USB) { + if (pwrOffPressed()) { + lcdClear(); + lcdOff(); // this drains LCD caps + pwrOff(); + for (;;) { + // Wait for power to go off + } + } + } + + if (state == ST_REBOOT) { + // Jump to proper application address + lcdClear(); + jumpTo(APP_START_ADDRESS); + } + } + + return 0; +} + +#if defined(PCBHORUS) +void *__dso_handle = 0; +#endif diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.h b/radio/src/targets/common/arm/stm32/bootloader/boot.h new file mode 100644 index 00000000000..140c772e647 --- /dev/null +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#ifndef _boot_h_ +#define _boot_h_ + +#include "stamp.h" + +#define BOOTLOADER_TITLE " OTX Bootloader - " VERSION +#define DISPLAY_CHAR_WIDTH (LCD_COLS+4) + +#if LCD_W >= 480 + #define STR_INVALID_FIRMWARE "Not a valid firmware file" +#elif LCD_W >= 212 + #define STR_OR_PLUGIN_USB_CABLE INDENT "Or plug in a USB cable for mass storage" + #define STR_HOLD_ENTER_TO_START "\012Hold [ENT] to start writing" + #define STR_INVALID_FIRMWARE "\011Not a valid firmware file! " + #define STR_INVALID_EEPROM "\011Not a valid EEPROM file! " +#else + #define STR_OR_PLUGIN_USB_CABLE INDENT "Or plug in a USB cable" + #define STR_HOLD_ENTER_TO_START "\006Hold [ENT] to start" + #define STR_INVALID_FIRMWARE "\004Not a valid firmware! " + #define STR_INVALID_EEPROM "\004Not a valid EEPROM! " +#endif + +#define STR_USB_CONNECTED CENTER "\011USB Connected" + + +// Bootloader states +enum BootloaderState { + ST_START, + ST_FLASH_MENU, + ST_DIR_CHECK, + ST_OPEN_DIR, + ST_FILE_LIST, + ST_FLASH_CHECK, + ST_FLASHING, + ST_FLASH_DONE, + ST_RESTORE_MENU, + ST_USB, + ST_REBOOT, +}; + +enum FlashCheckRes { + FC_UNCHECKED=0, + FC_OK, + FC_ERROR +}; + +// Declarations of functions that need to be implemented +// for each target with a bootloader + +// On bootloader start after lcdInit() +void bootloaderInitScreen(); + +// Depending on the state, up to two optional parameters are passed. +// See boot.cpp/main for more details +void bootloaderDrawScreen(BootloaderState st, int opt, const char* str = NULL); + +// Once for each file in a filename list on screen +void bootloaderDrawFilename(const char* str, uint8_t line, bool selected); + +#endif diff --git a/radio/src/targets/taranis/bootloader/init.c b/radio/src/targets/common/arm/stm32/bootloader/init.c similarity index 100% rename from radio/src/targets/taranis/bootloader/init.c rename to radio/src/targets/common/arm/stm32/bootloader/init.c diff --git a/radio/src/targets/taranis/flash_driver.cpp b/radio/src/targets/common/arm/stm32/flash_driver.cpp similarity index 65% rename from radio/src/targets/taranis/flash_driver.cpp rename to radio/src/targets/common/arm/stm32/flash_driver.cpp index dc06d6b9d91..ab653c2d6f0 100644 --- a/radio/src/targets/taranis/flash_driver.cpp +++ b/radio/src/targets/common/arm/stm32/flash_driver.cpp @@ -70,31 +70,62 @@ void eraseSector(uint32_t sector) void flashWrite(uint32_t * address, uint32_t * buffer) // page size is 256 bytes { - if ((uint32_t) address == 0x08000000) { - eraseSector(0); - } - else if ((uint32_t) address == 0x08004000) { - eraseSector(1); - } - else if ((uint32_t) address == 0x08008000) { - eraseSector(2); - } - else if ((uint32_t) address == 0x0800C000) { - eraseSector(3); - } - else if ((uint32_t) address == 0x08010000) { - eraseSector(4); - } - else if ((uint32_t) address == 0x08020000) { - eraseSector(5); - } - else if ((uint32_t) address == 0x08040000) { - eraseSector(6); - } - else if ((uint32_t) address == 0x08060000) { - eraseSector(7); - } +#define SECTOR_ADDRESS (((uint32_t)address) & 0xFFFFF) + +// Please note that there is an offset of 4 between +// sector 11 and 12 +#define FLASH_BANK ((((uint32_t)address) & 0x100000) ? 16 : 0) + + // test for possible flash sector boundary + if ((((uint32_t)address) & 0x1FFFF) == 0) { + // test first 16KB sectors + if (SECTOR_ADDRESS == 0x00000) { + eraseSector(0 + FLASH_BANK); + } + // test 128KB sectors + else if (SECTOR_ADDRESS == 0x20000) { + eraseSector(5 + FLASH_BANK); + } + else if (SECTOR_ADDRESS == 0x40000) { + eraseSector(6 + FLASH_BANK); + } + else if (SECTOR_ADDRESS == 0x60000) { + eraseSector(7 + FLASH_BANK); + } + else if (SECTOR_ADDRESS == 0x80000) { + eraseSector(8 + FLASH_BANK); + } + else if (SECTOR_ADDRESS == 0xA0000) { + eraseSector(9 + FLASH_BANK); + } + else if (SECTOR_ADDRESS == 0xC0000) { + eraseSector(10 + FLASH_BANK); + } + else if (SECTOR_ADDRESS == 0xE0000) { + eraseSector(11 + FLASH_BANK); + } + } + // test 64KB sector + else if (SECTOR_ADDRESS == 0x10000) { + eraseSector(4 + FLASH_BANK); + } + else if ((((uint32_t)address) & 0x3FFF) == 0) { + + // test other 16KB sectors + if (SECTOR_ADDRESS == 0x04000) { + eraseSector(1 + FLASH_BANK); + } + else if (SECTOR_ADDRESS == 0x08000) { + eraseSector(2 + FLASH_BANK); + } + else if (SECTOR_ADDRESS == 0x0C000) { + eraseSector(3 + FLASH_BANK); + } + } +#undef SECTOR_ADDRESS +#undef FLASH_BANK + for (uint32_t i=0; iARR = 100; - BL_TIMER->PSC = BL_TIMER_FREQ / 10000 - 1; // 1kHz - BL_TIMER->CCMR2 = TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2; // PWM - BL_TIMER->CCER = TIM_CCER_CC4E; - BL_TIMER->CCR4 = 0; - BL_TIMER->EGR = 0; - BL_TIMER->CR1 = TIM_CR1_CEN; // Counter enable + BACKLIGHT_TIMER->ARR = 100; + BACKLIGHT_TIMER->PSC = BACKLIGHT_TIMER_FREQ / 10000 - 1; // 1kHz + BACKLIGHT_TIMER->CCMR2 = TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2; // PWM + BACKLIGHT_TIMER->CCER = TIM_CCER_CC4E; + BACKLIGHT_TIMER->CCR4 = 0; + BACKLIGHT_TIMER->EGR = 0; + BACKLIGHT_TIMER->CR1 = TIM_CR1_CEN; // Counter enable } else { - BL_TIMER->ARR = 100; - BL_TIMER->PSC = BL_TIMER_FREQ / 10000 - 1; // 1kHz - BL_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; // PWM - BL_TIMER->CCER = TIM_CCER_CC1E | TIM_CCER_CC1NE; - BL_TIMER->CCR1 = 100; - BL_TIMER->EGR = 1; - BL_TIMER->CR1 |= TIM_CR1_CEN; // Counter enable - BL_TIMER->BDTR |= TIM_BDTR_MOE; + BACKLIGHT_TIMER->ARR = 100; + BACKLIGHT_TIMER->PSC = BACKLIGHT_TIMER_FREQ / 10000 - 1; // 1kHz + BACKLIGHT_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; // PWM + BACKLIGHT_TIMER->CCER = TIM_CCER_CC1E | TIM_CCER_CC1NE; + BACKLIGHT_TIMER->CCR1 = 100; + BACKLIGHT_TIMER->EGR = 1; + BACKLIGHT_TIMER->CR1 |= TIM_CR1_CEN; // Counter enable + BACKLIGHT_TIMER->BDTR |= TIM_BDTR_MOE; } #elif defined(PCBX10) - BL_TIMER->ARR = 100; - BL_TIMER->PSC = BL_TIMER_FREQ / 1000000 - 1; // 10kHz (same as FrOS) - BL_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3PE; // PWM mode 1 - BL_TIMER->CCER = TIM_CCER_CC3E | TIM_CCER_CC3NE; - BL_TIMER->CCR3 = 100; - BL_TIMER->EGR = TIM_EGR_UG; - BL_TIMER->CR1 |= TIM_CR1_CEN; // Counter enable - BL_TIMER->BDTR |= TIM_BDTR_MOE; + BACKLIGHT_TIMER->ARR = 100; + BACKLIGHT_TIMER->PSC = BACKLIGHT_TIMER_FREQ / 1000000 - 1; // 10kHz (same as FrOS) + BACKLIGHT_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3PE; // PWM mode 1 + BACKLIGHT_TIMER->CCER = TIM_CCER_CC3E | TIM_CCER_CC3NE; + BACKLIGHT_TIMER->CCR3 = 100; + BACKLIGHT_TIMER->EGR = TIM_EGR_UG; + BACKLIGHT_TIMER->CR1 |= TIM_CR1_CEN; // Counter enable + BACKLIGHT_TIMER->BDTR |= TIM_BDTR_MOE; #endif } @@ -69,12 +69,12 @@ void backlightEnable(uint8_t dutyCycle) { #if defined(PCBX12S) if (IS_HORUS_PROD()) { - BL_TIMER->CCR4 = dutyCycle; + BACKLIGHT_TIMER->CCR4 = dutyCycle; } else { - BL_TIMER->CCR1 = BACKLIGHT_LEVEL_MAX - dutyCycle; + BACKLIGHT_TIMER->CCR1 = BACKLIGHT_LEVEL_MAX - dutyCycle; } #elif defined(PCBX10) - BL_TIMER->CCR3 = BACKLIGHT_LEVEL_MAX - dutyCycle; + BACKLIGHT_TIMER->CCR3 = BACKLIGHT_LEVEL_MAX - dutyCycle; #endif } diff --git a/radio/src/targets/horus/board.cpp b/radio/src/targets/horus/board.cpp index 8d6d89bafe4..6fc5405548f 100644 --- a/radio/src/targets/horus/board.cpp +++ b/radio/src/targets/horus/board.cpp @@ -42,7 +42,7 @@ void watchdogInit(unsigned int duration) // Start TIMER7 at 2000000Hz void init2MhzTimer() { - TIMER_2MHz_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 2000000 - 1; // 0.5 uS, 2 MHz + TIMER_2MHz_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 2000000 - 1; // 0.5 uS, 2 MHz TIMER_2MHz_TIMER->ARR = 65535; TIMER_2MHz_TIMER->CR2 = 0; TIMER_2MHz_TIMER->CR1 = TIM_CR1_CEN; @@ -51,15 +51,15 @@ void init2MhzTimer() // Starts TIMER at 1000Hz void init1msTimer() { - INTERRUPT_1MS_TIMER->ARR = 999; // 1mS - INTERRUPT_1MS_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1; // 1uS from 30MHz - INTERRUPT_1MS_TIMER->CCER = 0; - INTERRUPT_1MS_TIMER->CCMR1 = 0; - INTERRUPT_1MS_TIMER->EGR = 0; - INTERRUPT_1MS_TIMER->CR1 = 5; - INTERRUPT_1MS_TIMER->DIER |= 1; - NVIC_EnableIRQ(INTERRUPT_1MS_IRQn); - NVIC_SetPriority(INTERRUPT_1MS_IRQn, 7); + INTERRUPT_xMS_TIMER->ARR = 999; // 1mS in uS + INTERRUPT_xMS_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1; // 1uS + INTERRUPT_xMS_TIMER->CCER = 0; + INTERRUPT_xMS_TIMER->CCMR1 = 0; + INTERRUPT_xMS_TIMER->EGR = 0; + INTERRUPT_xMS_TIMER->CR1 = 5; + INTERRUPT_xMS_TIMER->DIER |= 1; + NVIC_EnableIRQ(INTERRUPT_xMS_IRQn); + NVIC_SetPriority(INTERRUPT_xMS_IRQn, 7); } // TODO use the same than board_sky9x.cpp @@ -90,9 +90,9 @@ void interrupt1ms() DEBUG_TIMER_STOP(debugTimerRotEnc); } -extern "C" void INTERRUPT_1MS_IRQHandler() +extern "C" void INTERRUPT_xMS_IRQHandler() { - INTERRUPT_1MS_TIMER->SR &= ~TIM_SR_UIF; + INTERRUPT_xMS_TIMER->SR &= ~TIM_SR_UIF; interrupt1ms(); DEBUG_INTERRUPT(INT_1MS); } @@ -135,10 +135,10 @@ void boardInit() PCBREV_RCC_AHB1Periph | LED_RCC_AHB1Periph | LCD_RCC_AHB1Periph | - BL_RCC_AHB1Periph | + BACKLIGHT_RCC_AHB1Periph | SD_RCC_AHB1Periph | AUDIO_RCC_AHB1Periph | - KEYS_RCC_AHB1Periph_GPIO | + KEYS_RCC_AHB1Periph | ADC_RCC_AHB1Periph | SERIAL_RCC_AHB1Periph | TELEMETRY_RCC_AHB1Periph | @@ -149,11 +149,10 @@ void boardInit() INTMODULE_RCC_AHB1Periph | EXTMODULE_RCC_AHB1Periph | GPS_RCC_AHB1Periph | - SPORT_UPDATE_RCC_AHB1Periph | - BL_RCC_AHB1Periph, + SPORT_UPDATE_RCC_AHB1Periph, ENABLE); - RCC_APB1PeriphClockCmd(INTERRUPT_1MS_RCC_APB1Periph | + RCC_APB1PeriphClockCmd(INTERRUPT_xMS_RCC_APB1Periph | ADC_RCC_APB1Periph | TIMER_2MHz_RCC_APB1Periph | AUDIO_RCC_APB1Periph | @@ -164,7 +163,7 @@ void boardInit() INTMODULE_RCC_APB1Periph | EXTMODULE_RCC_APB1Periph | GPS_RCC_APB1Periph | - BL_RCC_APB1Periph, + BACKLIGHT_RCC_APB1Periph, ENABLE); RCC_APB2PeriphClockCmd(LCD_RCC_APB2Periph | @@ -173,7 +172,7 @@ void boardInit() INTMODULE_RCC_APB2Periph | EXTMODULE_RCC_APB2Periph | BT_RCC_APB2Periph | - BL_RCC_APB2Periph, + BACKLIGHT_RCC_APB2Periph, ENABLE); pwrInit(); diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index e86487ec295..a4c9cfdb0fa 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -82,7 +82,7 @@ extern "C" { #endif #define FLASHSIZE 0x200000 -#define BOOTLOADER_SIZE 0x8000 +#define BOOTLOADER_SIZE 0x20000 #define FIRMWARE_ADDRESS 0x08000000 #define MB *1024*1024 @@ -160,6 +160,7 @@ uint32_t sdMounted(void); #define sdDone() #define SD_CARD_PRESENT() true #endif + #if defined(DISK_CACHE) #include "diskio.h" DRESULT __disk_read(BYTE drv, BYTE * buff, DWORD sector, UINT count); @@ -446,7 +447,7 @@ void DMABitmapConvert(uint16_t * dest, const uint8_t * src, uint16_t w, uint16_t void lcdStoreBackupBuffer(void); int lcdRestoreBackupBuffer(void); void lcdSetContrast(); -#define lcdOff(...) +#define lcdOff() backlightEnable(0) /* just disable the backlight */ #define lcdSetRefVolt(...) #define lcdRefreshWait(...) diff --git a/radio/src/targets/horus/bootloader/boot_menu.cpp b/radio/src/targets/horus/bootloader/boot_menu.cpp new file mode 100644 index 00000000000..b50b9c7299a --- /dev/null +++ b/radio/src/targets/horus/bootloader/boot_menu.cpp @@ -0,0 +1,172 @@ +#include "opentx.h" +#include "../../common/arm/stm32/bootloader/boot.h" +#include "../../common/arm/stm32/bootloader/bin_files.h" + +#define SELECTED_COLOR (INVERS | TEXT_COLOR) + +#include "bmp_plug_usb.lbm" +#include "bmp_usb_plugged.lbm" + +const uint8_t LBM_FLASH[] = { +#include "icon_flash.lbm" +}; + +const uint8_t LBM_EXIT[] = { +#include "icon_exit.lbm" +}; + +const uint8_t LBM_SD[] = { +#include "icon_sd.lbm" +}; + +const uint8_t LBM_FILE[] = { +#include "icon_file.lbm" +}; + +const uint8_t LBM_ERROR[] = { +#include "icon_error.lbm" +}; + +const uint8_t LBM_OK[] = { +#include "icon_ok.lbm" +}; + +void bootloaderInitScreen() +{ + lcdColorTable[TEXT_COLOR_INDEX] = BLACK; + lcdColorTable[TEXT_BGCOLOR_INDEX] = WHITE; + lcdColorTable[LINE_COLOR_INDEX] = RED; + lcdColorTable[BARGRAPH1_COLOR_INDEX] = RED; + lcdColorTable[BARGRAPH2_COLOR_INDEX] = RGB(73, 219, 62); // green + + backlightEnable(BACKLIGHT_LEVEL_MAX); +} + +static void bootloaderDrawTitle(unsigned int x, const char* text) +{ + lcdDrawText(x, 28, text); + lcdDrawSolidFilledRect(28, 56, 422, 2, TEXT_COLOR); +} + +static void bootloaderDrawFooter() +{ + lcdDrawSolidFilledRect(28, 234, 422, 2, TEXT_COLOR); +} + +void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) +{ + // clear screen + lcdDrawSolidFilledRect(0, 0, LCD_W-1, LCD_H-1, TEXT_BGCOLOR); + + if (st == ST_START) { + + bootloaderDrawTitle(88, "HORUS BOOTLOADER"); + + lcdDrawBitmapPattern(90, 72, LBM_FLASH, TEXT_COLOR); + lcdDrawText(124, 75, "Write Firmware"); + + lcdDrawBitmapPattern(90, 107, LBM_EXIT, TEXT_COLOR); + lcdDrawText(124, 110, "Exit"); + + lcdDrawSolidRect(119, (opt == 0) ? 72 : 107, 270, 26, 2, LINE_COLOR); + + lcd->drawBitmap(60, 166, &BMP_PLUG_USB); + lcdDrawText(195, 175, "Or plug in a USB cable"); + lcdDrawText(195, 200, "for mass storage"); + + bootloaderDrawFooter(); + lcdDrawText( 36, 242, "Current Firmware:"); + lcdDrawText(200, 242, getOtherVersion(nullptr)); + } + else if (st == ST_USB) { + + lcd->drawBitmap(136, 98, &BMP_USB_PLUGGED); + lcdDrawText(195, 128, "USB Connected"); + } + else if (st == ST_FILE_LIST || st == ST_DIR_CHECK || st == ST_FLASH_CHECK || + st == ST_FLASHING || st == ST_FLASH_DONE) { + + bootloaderDrawTitle(126, "SD>FIRMWARE"); + lcdDrawBitmapPattern(87, 16, LBM_SD, TEXT_COLOR); + + if (st == ST_FLASHING || st == ST_FLASH_DONE) { + + LcdFlags color = BARGRAPH1_COLOR; // red + + if (st == ST_FLASH_DONE) { + color = BARGRAPH2_COLOR/* green */; + opt = 100; // Completed > 100% + } + + lcdDrawRect(70, 120, 340, 31, 2); + lcdDrawSolidFilledRect(74, 124, (332 * opt) / 100, 23, color); + } + else if (st == ST_DIR_CHECK) { + + if (opt == FR_NO_PATH) { + lcdDrawText(90, 168, "Directory is missing"); + } + else { + lcdDrawText(90, 168, "Directory is empty"); + } + + lcdDrawBitmapPattern(356, 158, LBM_ERROR, BARGRAPH1_COLOR); + } + else if (st == ST_FLASH_CHECK) { + + bootloaderDrawFilename(str, 0, true); + + if (opt == FC_ERROR) { + lcdDrawText(94, 168, STR_INVALID_FIRMWARE); + lcdDrawBitmapPattern(356, 158, LBM_ERROR, BARGRAPH1_COLOR); + } + else if (opt == FC_OK) { + VersionTag tag; + extractFirmwareVersion(&tag); + + lcdDrawText(168, 158, "Version:", RIGHT); + lcdDrawText(174, 158, tag.version); + + lcdDrawText(168, 178, "Radio:", RIGHT); + lcdDrawText(174, 178, tag.flavour); + + lcdDrawBitmapPattern(356, 158, LBM_OK, BARGRAPH2_COLOR); + } + } + + bootloaderDrawFooter(); + + if ( st != ST_DIR_CHECK && (st != ST_FLASH_CHECK || opt == FC_OK)) { + + lcdDrawBitmapPattern(28, 242, LBM_FLASH, TEXT_COLOR); + + if (st == ST_FILE_LIST) { + lcdDrawText(56, 244, "[ENT] to select file"); + } + else if (st == ST_FLASH_CHECK && opt == FC_OK) { + lcdDrawText(56, 244, "Hold [ENT] long to flash"); + } + else if (st == ST_FLASHING) { + lcdDrawText(56, 244, "Writing Firmware ..."); + } + else if (st == ST_FLASH_DONE) { + lcdDrawText(56, 244, "Writing Completed"); + } + } + + if (st != ST_FLASHING) { + lcdDrawBitmapPattern(305, 242, LBM_EXIT, TEXT_COLOR); + lcdDrawText(335, 244, "[RTN] to exit"); + } + } +} + +void bootloaderDrawFilename(const char* str, uint8_t line, bool selected) +{ + lcdDrawBitmapPattern(94, 76 + (line * 25), LBM_FILE, TEXT_COLOR); + lcdDrawText(124, 75 + (line * 25), str); + + if (selected) { + lcdDrawSolidRect(119, 72 + (line * 25), 278, 26, 2, LINE_COLOR); + } +} diff --git a/radio/src/targets/horus/diskio.cpp b/radio/src/targets/horus/diskio.cpp index 489865b5c60..b0d9e8174c3 100644 --- a/radio/src/targets/horus/diskio.cpp +++ b/radio/src/targets/horus/diskio.cpp @@ -313,6 +313,14 @@ FATFS g_FATFS_Obj __DMA; // initialized in boardInit() FIL g_telemetryFile = {}; #endif +#if defined(BOOT) +void sdInit(void) +{ + if (f_mount(&g_FATFS_Obj, "", 1) == FR_OK) { + f_chdir("/"); + } +} +#else void sdInit() { TRACE("sdInit"); @@ -359,6 +367,7 @@ void sdDone() f_mount(NULL, "", 0); // unmount SD } } +#endif uint32_t sdMounted() { diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index 2608448cd09..f08800762c8 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -22,7 +22,7 @@ #define _HAL_H_ // Keys -#define KEYS_RCC_AHB1Periph_GPIO (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOH | RCC_AHB1Periph_GPIOI | RCC_AHB1Periph_GPIOJ) +#define KEYS_RCC_AHB1Periph (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOH | RCC_AHB1Periph_GPIOI | RCC_AHB1Periph_GPIOJ) #if defined(PCBX12S) #define KEYS_GPIO_REG_PGUP GPIOC->IDR #define KEYS_GPIO_PIN_PGUP GPIO_Pin_13 // PC.13 @@ -246,8 +246,11 @@ // Power #define PWR_RCC_AHB1Periph RCC_AHB1Periph_GPIOJ #define PWR_GPIO GPIOJ -#define PWR_ON_GPIO_PIN GPIO_Pin_1 // PJ.01 +#define PWR_SWITCH_GPIO_REG PWR_GPIO->IDR #define PWR_SWITCH_GPIO_PIN GPIO_Pin_0 // PJ.00 +#define PWR_ON_GPIO_PIN GPIO_Pin_1 // PJ.01 +#define PWR_ON_GPIO_MODER GPIO_MODER_MODER1 +#define PWR_ON_GPIO_MODER_OUT GPIO_MODER_MODER1_0 #if defined(PCBX10) #define SPORT_UPDATE_RCC_AHB1Periph RCC_AHB1Periph_GPIOH @@ -327,6 +330,7 @@ // LCD #define LCD_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOI | RCC_AHB1Periph_GPIOJ | RCC_AHB1Periph_GPIOK | RCC_AHB1Periph_DMA2D) +#define LCD_RCC_APB1Periph 0 #define LCD_RCC_APB2Periph RCC_APB2Periph_LTDC #if defined(PCBX12S) #define LCD_GPIO_NRST GPIOF @@ -340,39 +344,40 @@ // Backlight #if defined(PCBX12S) - #define BL_RCC_AHB1Periph RCC_AHB1Periph_GPIOA - #define BL_GPIO GPIOA + #define BACKLIGHT_RCC_AHB1Periph RCC_AHB1Periph_GPIOA + #define BACKLIGHT_GPIO GPIOA #if PCBREV >= 13 - #define BL_TIMER TIM5 - #define BL_GPIO_PIN GPIO_Pin_3 // PA.03 - #define BL_GPIO_PinSource GPIO_PinSource3 - #define BL_RCC_APB1Periph RCC_APB1Periph_TIM5 - #define BL_RCC_APB2Periph 0 - #define BL_GPIO_AF GPIO_AF_TIM5 - #define BL_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) + #define BACKLIGHT_TIMER TIM5 + #define BACKLIGHT_GPIO_PIN GPIO_Pin_3 // PA.03 + #define BACKLIGHT_GPIO_PinSource GPIO_PinSource3 + #define BACKLIGHT_RCC_APB1Periph RCC_APB1Periph_TIM5 + #define BACKLIGHT_RCC_APB2Periph 0 + #define BACKLIGHT_GPIO_AF GPIO_AF_TIM5 + #define BACKLIGHT_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) #else - #define BL_TIMER TIM8 - #define BL_GPIO_PIN GPIO_Pin_5 // PA.05 - #define BL_GPIO_PinSource GPIO_PinSource5 - #define BL_RCC_APB1Periph 0 - #define BL_RCC_APB2Periph RCC_APB2Periph_TIM8 - #define BL_GPIO_AF GPIO_AF_TIM8 - #define BL_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2) + #define BACKLIGHT_TIMER TIM8 + #define BACKLIGHT_GPIO_PIN GPIO_Pin_5 // PA.05 + #define BACKLIGHT_GPIO_PinSource GPIO_PinSource5 + #define BACKLIGHT_RCC_APB1Periph 0 + #define BACKLIGHT_RCC_APB2Periph RCC_APB2Periph_TIM8 + #define BACKLIGHT_GPIO_AF GPIO_AF_TIM8 + #define BACKLIGHT_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2) #endif #elif defined(PCBX10) - #define BL_RCC_AHB1Periph RCC_AHB1Periph_GPIOB - #define BL_GPIO GPIOB - #define BL_TIMER TIM8 - #define BL_GPIO_PIN GPIO_Pin_1 // PB.01 - #define BL_GPIO_PinSource GPIO_PinSource1 - #define BL_RCC_APB1Periph 0 - #define BL_RCC_APB2Periph RCC_APB2Periph_TIM8 - #define BL_GPIO_AF GPIO_AF_TIM8 - #define BL_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2) + #define BACKLIGHT_RCC_AHB1Periph RCC_AHB1Periph_GPIOB + #define BACKLIGHT_GPIO GPIOB + #define BACKLIGHT_TIMER TIM8 + #define BACKLIGHT_GPIO_PIN GPIO_Pin_1 // PB.01 + #define BACKLIGHT_GPIO_PinSource GPIO_PinSource1 + #define BACKLIGHT_RCC_APB1Periph 0 + #define BACKLIGHT_RCC_APB2Periph RCC_APB2Periph_TIM8 + #define BACKLIGHT_GPIO_AF GPIO_AF_TIM8 + #define BACKLIGHT_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2) #endif // SD #define SD_RCC_AHB1Periph (RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_DMA2) +#define SD_RCC_APB1Periph 0 #define SD_PRESENT_GPIO GPIOC #define SD_PRESENT_GPIO_PIN GPIO_Pin_5 // PC.05 #define SD_SDIO_DMA_STREAM DMA2_Stream3 @@ -607,11 +612,11 @@ #define TRAINER_DMA_FLAG_TC DMA_IT_TCIF2 #define TRAINER_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) -// 1ms Interrupt -#define INTERRUPT_1MS_RCC_APB1Periph RCC_APB1Periph_TIM14 -#define INTERRUPT_1MS_TIMER TIM14 -#define INTERRUPT_1MS_IRQn TIM8_TRG_COM_TIM14_IRQn -#define INTERRUPT_1MS_IRQHandler TIM8_TRG_COM_TIM14_IRQHandler +// Xms Interrupt +#define INTERRUPT_xMS_RCC_APB1Periph RCC_APB1Periph_TIM14 +#define INTERRUPT_xMS_TIMER TIM14 +#define INTERRUPT_xMS_IRQn TIM8_TRG_COM_TIM14_IRQn +#define INTERRUPT_xMS_IRQHandler TIM8_TRG_COM_TIM14_IRQHandler // 2MHz Timer #define TIMER_2MHz_RCC_APB1Periph RCC_APB1Periph_TIM7 diff --git a/radio/src/targets/horus/keys_driver.cpp b/radio/src/targets/horus/keys_driver.cpp index 1a4b96830db..a20d373973e 100644 --- a/radio/src/targets/horus/keys_driver.cpp +++ b/radio/src/targets/horus/keys_driver.cpp @@ -211,12 +211,12 @@ void readKeysAndTrims() } \ break -#if !defined(BOOT) uint8_t keyState(uint8_t index) { return keys[index].state(); } +#if !defined(BOOT) uint32_t switchState(uint8_t index) { uint32_t xxx = 0; diff --git a/radio/src/targets/horus/stm32_ramboot.ld b/radio/src/targets/horus/stm32_ramboot.ld new file mode 100644 index 00000000000..d7fa9d338c2 --- /dev/null +++ b/radio/src/targets/horus/stm32_ramboot.ld @@ -0,0 +1,186 @@ +/* +***************************************************************************** +** +** File : stm32f4_flash.ld +** +** Abstract : Linker script for STM32F439 Device with +** 2MByte FLASH, 192KByte SRAM, 64KByte CCM +** +** Set heap size, stack size and stack location according +** to application requirements. +** +** Set memory bank area and size if external memory is used. +** +** Target : STMicroelectronics STM32 +** +***************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20030000; /* end of 192K RAM */ +_heap_end = 0xD0800000; /* end of 8192K SDRAM */ + +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0; /* required amount of heap */ +_Main_Stack_Size = 1024; /* required amount of stack for interrupt stack (Main stack) */ + +/* Main stack end */ +_main_stack_start = _estack - _Main_Stack_Size; + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K + CCM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K + MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K + SDRAM(xrw) : ORIGIN = 0xD0000000, LENGTH = 8192K +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + KEEP(*(.version)) + KEEP(*(.bootversiondata)) + . = ALIGN(4); /* Align the start of the text part */ + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + .ARM.extab : + { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array*)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = .; + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >CCM + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss secion */ + _sbss = .; /* define a global symbol at bss start */ + /* __bss_start__ = _sbss; */ + *(.bss) + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + } >CCM + + /* Non-zeroed data section */ + . = ALIGN(4); + .noinit (NOLOAD) : + { + *(.noinit) + } >CCM + + /* collect all uninitialized .ccm sections */ + .ram (NOLOAD) : + { + . = ALIGN(4); + _sram = .; + *(.ram) + } >RAM + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(4); + . = . + _Min_Heap_Size; + . = . + _Main_Stack_Size; + . = ALIGN(4); + } >RAM + + /* MEMORY_bank1 section, code must be located here explicitly */ + /* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */ + .memory_b1_text : + { + *(.mb1text) /* .mb1text sections (code) */ + *(.mb1text*) /* .mb1text* sections (code) */ + *(.mb1rodata) /* read-only data (constants) */ + *(.mb1rodata*) + } >MEMORY_B1 + + .sdram (NOLOAD) : + { + *(.sdram) + *(.sdram*) + *(.sdram_rodata) + *(.sdram_rodata*) + . = ALIGN(4); + _eram = .; + } >SDRAM + + PROVIDE ( end = _eram ); + PROVIDE ( _end = _eram ); + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/radio/src/targets/horus/stm32f4_flash.ld b/radio/src/targets/horus/stm32f4_flash.ld index 47bffc1f278..7ab6ee4f0ba 100644 --- a/radio/src/targets/horus/stm32f4_flash.ld +++ b/radio/src/targets/horus/stm32f4_flash.ld @@ -52,6 +52,11 @@ SECTIONS CREATE_OBJECT_SYMBOLS + KEEP(*(.bootloader)) /* Bootloader code */ + + . = 0x20000; /* Set the start of the main program */ + _stext = .; /* Provide the name for the start of this section */ + . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */ KEEP(*(.fwversiondata)) *(.text) /* .text sections (code) */ @@ -60,7 +65,7 @@ SECTIONS *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ *(.glue_7) /* glue arm to thumb code */ *(.glue_7t) /* glue thumb to arm code */ - *(.eh_frame) + *(.eh_frame) KEEP (*(.init)) KEEP (*(.fini)) diff --git a/radio/src/targets/sky9x/CMakeLists.txt b/radio/src/targets/sky9x/CMakeLists.txt index 75f46956ecb..068e19bb881 100644 --- a/radio/src/targets/sky9x/CMakeLists.txt +++ b/radio/src/targets/sky9x/CMakeLists.txt @@ -67,6 +67,7 @@ set(GUI_SRC set(FIRMWARE_TARGET_SRC ${FIRMWARE_TARGET_SRC} + ../common/arm/loadboot.cpp core_cm3.c board_lowlevel.c crt.c @@ -109,11 +110,6 @@ set(TARGET_SRC audio_driver.cpp ) -set(FIRMWARE_SRC - ${FIRMWARE_SRC} - loadboot.cpp - ) - set(SRC ${SRC} debug.cpp diff --git a/radio/src/targets/sky9x/board.cpp b/radio/src/targets/sky9x/board.cpp index 359559c6165..fca8b297cee 100644 --- a/radio/src/targets/sky9x/board.cpp +++ b/radio/src/targets/sky9x/board.cpp @@ -401,15 +401,6 @@ void i2cInit() void boardInit() { - // TODO this is not clean, completely unuseful, but prevents the bootloader from being optimized away... - uint8_t dummy[3]; - memcpy(&dummy, BootCode, sizeof(dummy)); - for (unsigned int i=0; iRSTC_SR; diff --git a/radio/src/targets/sky9x/sam3s4c_flash.ld b/radio/src/targets/sky9x/sam3s4c_flash.ld index 1a7c1104170..4e3f55b3e6a 100644 --- a/radio/src/targets/sky9x/sam3s4c_flash.ld +++ b/radio/src/targets/sky9x/sam3s4c_flash.ld @@ -71,15 +71,14 @@ SECTIONS */ .text : { - FILL(0xFFFF) - - CREATE_OBJECT_SYMBOLS + FILL(0xFFFF) + + CREATE_OBJECT_SYMBOLS - *(.bootrodata) - *(.bootrodata.*) + KEEP(*(.bootloader)) /* Bootloader code */ - . = ALIGN(32768); /* Align the start of the exidx part */ - _stext = .; /* Provide the name for the start of this section */ + . = ALIGN(32768); /* Align the start of the exidx part */ + _stext = .; /* Provide the name for the start of this section */ KEEP(*(.vectors)) diff --git a/radio/src/targets/sky9x/sam3s8c_flash.ld b/radio/src/targets/sky9x/sam3s8c_flash.ld index 833e56e6944..010f7040808 100644 --- a/radio/src/targets/sky9x/sam3s8c_flash.ld +++ b/radio/src/targets/sky9x/sam3s8c_flash.ld @@ -71,15 +71,14 @@ SECTIONS */ .text : { - FILL(0xFFFF) + FILL(0xFFFF) CREATE_OBJECT_SYMBOLS - *(.bootrodata) - *(.bootrodata.*) - + KEEP(*(.bootloader)) + . = ALIGN(32768); /* Align the start of the exidx part */ - _stext = .; /* Provide the name for the start of this section */ + _stext = .; /* Provide the name for the start of this section */ KEEP(*(.vectors)) *(.text) diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt index f678b1fb566..98dc5de2f55 100644 --- a/radio/src/targets/taranis/CMakeLists.txt +++ b/radio/src/targets/taranis/CMakeLists.txt @@ -25,6 +25,7 @@ if(PCB STREQUAL X9E) endif() set(GUI_DIR 212x64) set(BITMAPS_TARGET taranis_bitmaps) + set(FONTS_TARGET taranis_fonts) set(LCD_DRIVER lcd_driver_spi.cpp) set(GVAR_SCREEN model_gvars.cpp) elseif(PCB STREQUAL X9D+) @@ -38,6 +39,7 @@ elseif(PCB STREQUAL X9D+) add_definitions(-DEEPROM_VARIANT=0) set(GUI_DIR 212x64) set(BITMAPS_TARGET taranis_bitmaps) + set(FONTS_TARGET taranis_fonts) set(LCD_DRIVER lcd_driver_spi.cpp) set(SERIAL2_DRIVER ../common/arm/stm32/serial2_driver.cpp) set(GVAR_SCREEN model_gvars.cpp) @@ -52,6 +54,7 @@ elseif(PCB STREQUAL X9D) add_definitions(-DEEPROM_VARIANT=0) set(GUI_DIR 212x64) set(BITMAPS_TARGET taranis_bitmaps) + set(FONTS_TARGET taranis_fonts) set(LCD_DRIVER lcd_driver_aspi.cpp) set(SERIAL2_DRIVER ../common/arm/stm32/serial2_driver.cpp) set(GVAR_SCREEN model_gvars.cpp) @@ -68,6 +71,7 @@ elseif(PCB STREQUAL X7) add_definitions(-DPWR_BUTTON_${PWR_BUTTON}) set(GUI_DIR 128x64) set(BITMAPS_TARGET 9x_bitmaps) + set(FONTS_TARGET 9x_fonts_1bit) set(LCD_DRIVER lcd_driver_spi.cpp) endif() @@ -124,17 +128,12 @@ set(TARGET_SRC ../common/arm/stm32/adc_driver.cpp ) -set(FIRMWARE_SRC - ${FIRMWARE_SRC} - loadboot.cpp - ) - set(FIRMWARE_TARGET_SRC ${FIRMWARE_TARGET_SRC} ${LCD_DRIVER} i2c_driver.cpp pwr_driver.cpp - flash_driver.cpp + ../common/arm/loadboot.cpp ) if(LCD_DUAL_BUFFER) diff --git a/radio/src/targets/taranis/board.cpp b/radio/src/targets/taranis/board.cpp index 7de3b5042f7..1ef74ee8da7 100644 --- a/radio/src/targets/taranis/board.cpp +++ b/radio/src/targets/taranis/board.cpp @@ -51,21 +51,21 @@ void init2MhzTimer() // Starts TIMER at 200Hz (5ms) void init5msTimer() { - INTERRUPT_5MS_TIMER->ARR = 4999 ; // 5mS - INTERRUPT_5MS_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1 ; // 1uS from 30MHz - INTERRUPT_5MS_TIMER->CCER = 0 ; - INTERRUPT_5MS_TIMER->CCMR1 = 0 ; - INTERRUPT_5MS_TIMER->EGR = 0 ; - INTERRUPT_5MS_TIMER->CR1 = 5 ; - INTERRUPT_5MS_TIMER->DIER |= 1 ; - NVIC_EnableIRQ(INTERRUPT_5MS_IRQn) ; - NVIC_SetPriority(INTERRUPT_5MS_IRQn, 7); + INTERRUPT_xMS_TIMER->ARR = 4999 ; // 5mS in uS + INTERRUPT_xMS_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1 ; // 1uS + INTERRUPT_xMS_TIMER->CCER = 0 ; + INTERRUPT_xMS_TIMER->CCMR1 = 0 ; + INTERRUPT_xMS_TIMER->EGR = 0 ; + INTERRUPT_xMS_TIMER->CR1 = 5 ; + INTERRUPT_xMS_TIMER->DIER |= 1 ; + NVIC_EnableIRQ(INTERRUPT_xMS_IRQn) ; + NVIC_SetPriority(INTERRUPT_xMS_IRQn, 7); } void stop5msTimer( void ) { - INTERRUPT_5MS_TIMER->CR1 = 0 ; // stop timer - NVIC_DisableIRQ(INTERRUPT_5MS_IRQn) ; + INTERRUPT_xMS_TIMER->CR1 = 0 ; // stop timer + NVIC_DisableIRQ(INTERRUPT_xMS_IRQn) ; } // TODO use the same than board_sky9x.cpp @@ -93,9 +93,9 @@ void interrupt5ms() } #if !defined(SIMU) -extern "C" void INTERRUPT_5MS_IRQHandler() +extern "C" void INTERRUPT_xMS_IRQHandler() { - INTERRUPT_5MS_TIMER->SR &= ~TIM_SR_UIF ; + INTERRUPT_xMS_TIMER->SR &= ~TIM_SR_UIF ; interrupt5ms() ; DEBUG_INTERRUPT(INT_5MS); } @@ -147,9 +147,27 @@ void sportUpdatePowerOff() void boardInit() { #if !defined(SIMU) - RCC_AHB1PeriphClockCmd(PWR_RCC_AHB1Periph | PCBREV_RCC_AHB1Periph | KEYS_RCC_AHB1Periph | LCD_RCC_AHB1Periph | AUDIO_RCC_AHB1Periph | BACKLIGHT_RCC_AHB1Periph | ADC_RCC_AHB1Periph | I2C_RCC_AHB1Periph | SD_RCC_AHB1Periph | HAPTIC_RCC_AHB1Periph | INTMODULE_RCC_AHB1Periph | EXTMODULE_RCC_AHB1Periph | TELEMETRY_RCC_AHB1Periph | SPORT_UPDATE_RCC_AHB1Periph | SERIAL_RCC_AHB1Periph | TRAINER_RCC_AHB1Periph | HEARTBEAT_RCC_AHB1Periph | BT_RCC_AHB1Periph, ENABLE); - RCC_APB1PeriphClockCmd(LCD_RCC_APB1Periph | AUDIO_RCC_APB1Periph | BACKLIGHT_RCC_APB1Periph | INTERRUPT_5MS_APB1Periph | TIMER_2MHz_APB1Periph | I2C_RCC_APB1Periph | SD_RCC_APB1Periph | TRAINER_RCC_APB1Periph | TELEMETRY_RCC_APB1Periph | SERIAL_RCC_APB1Periph | BT_RCC_APB1Periph, ENABLE); - RCC_APB2PeriphClockCmd(BACKLIGHT_RCC_APB2Periph | ADC_RCC_APB2Periph | HAPTIC_RCC_APB2Periph | INTMODULE_RCC_APB2Periph | EXTMODULE_RCC_APB2Periph | HEARTBEAT_RCC_APB2Periph | BT_RCC_APB2Periph, ENABLE); + RCC_AHB1PeriphClockCmd(PWR_RCC_AHB1Periph | PCBREV_RCC_AHB1Periph | + KEYS_RCC_AHB1Periph | LCD_RCC_AHB1Periph | + AUDIO_RCC_AHB1Periph | BACKLIGHT_RCC_AHB1Periph | + ADC_RCC_AHB1Periph | I2C_RCC_AHB1Periph | + SD_RCC_AHB1Periph | HAPTIC_RCC_AHB1Periph | + INTMODULE_RCC_AHB1Periph | EXTMODULE_RCC_AHB1Periph | + TELEMETRY_RCC_AHB1Periph | SPORT_UPDATE_RCC_AHB1Periph | + SERIAL_RCC_AHB1Periph | TRAINER_RCC_AHB1Periph | + HEARTBEAT_RCC_AHB1Periph | BT_RCC_AHB1Periph, ENABLE); + + RCC_APB1PeriphClockCmd(LCD_RCC_APB1Periph | AUDIO_RCC_APB1Periph | + BACKLIGHT_RCC_APB1Periph | INTERRUPT_xMS_RCC_APB1Periph | + TIMER_2MHz_RCC_APB1Periph | I2C_RCC_APB1Periph | + SD_RCC_APB1Periph | TRAINER_RCC_APB1Periph | + TELEMETRY_RCC_APB1Periph | SERIAL_RCC_APB1Periph | + BT_RCC_APB1Periph, ENABLE); + + RCC_APB2PeriphClockCmd(BACKLIGHT_RCC_APB2Periph | ADC_RCC_APB2Periph | + HAPTIC_RCC_APB2Periph | INTMODULE_RCC_APB2Periph | + EXTMODULE_RCC_APB2Periph | HEARTBEAT_RCC_APB2Periph | + BT_RCC_APB2Periph, ENABLE); #if !defined(PCBX9E) // some X9E boards need that the pwrInit() is moved a little bit later diff --git a/radio/src/targets/taranis/bootloader/.gitignore b/radio/src/targets/taranis/bootloader/.gitignore deleted file mode 100644 index eaeb7d8c513..00000000000 --- a/radio/src/targets/taranis/bootloader/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/bootloader_ramBoot.* -/.dep - diff --git a/radio/src/targets/taranis/bootloader/boot.cpp b/radio/src/targets/taranis/bootloader/boot.cpp deleted file mode 100644 index 5b5dd0fe1f3..00000000000 --- a/radio/src/targets/taranis/bootloader/boot.cpp +++ /dev/null @@ -1,655 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "opentx.h" -#include "stamp.h" - -#if defined(PCBX7) - #define BOOTLOADER_TITLE " X7 Bootloader - " VERSION -#elif defined(PCBTARANIS) - #define BOOTLOADER_TITLE " Taranis Bootloader - " VERSION -#else - #error "Not implemented" -#endif - -#if defined(PCBX9E) || defined(PCBX7) - #define BOOT_KEY_UP KEY_MINUS - #define BOOT_KEY_DOWN KEY_PLUS -#else - #define BOOT_KEY_UP KEY_PLUS - #define BOOT_KEY_DOWN KEY_MINUS -#endif -#define BOOT_KEY_LEFT KEY_MENU -#define BOOT_KEY_RIGHT KEY_PAGE -#define BOOT_KEY_MENU KEY_ENTER -#define BOOT_KEY_EXIT KEY_EXIT -#define DISPLAY_CHAR_WIDTH 35 - -#if LCD_W >= 212 - #define STR_OR_PLUGIN_USB_CABLE INDENT "Or plug in a USB cable for mass storage" - #define STR_HOLD_ENTER_TO_START "\012Hold [ENT] to start writing" - #define STR_INVALID_FIRMWARE "\011Not a valid firmware file! " - #define STR_INVALID_EEPROM "\011Not a valid EEPROM file! " -#else - #define STR_OR_PLUGIN_USB_CABLE INDENT "Or plug in a USB cable" - #define STR_HOLD_ENTER_TO_START "\006Hold [ENT] to start" - #define STR_INVALID_FIRMWARE "\004Not a valid firmware! " - #define STR_INVALID_EEPROM "\004Not a valid EEPROM! " -#endif - -#define STR_USB_CONNECTED CENTER "\011USB Connected" - -const uint8_t bootloaderVersion[] __attribute__ ((section(".version"), used)) = -{ - 'B', 'O', 'O', 'T', '1', '0' -}; - -#if defined(ROTARY_ENCODER_NAVIGATION) -volatile rotenc_t rotencValue[1] = {0}; -#endif - -// states -enum BootLoaderStates { - ST_START, - ST_FLASH_MENU, - ST_DIR_CHECK, - ST_OPEN_DIR, - ST_FILE_LIST, - ST_FLASH_CHECK, - ST_FLASHING, - ST_FLASH_DONE, - ST_RESTORE_MENU, - ST_USB, - ST_REBOOT, -}; - -enum MemoryTypes { - MEM_FLASH, - MEM_EEPROM -}; - -/*---------------------------------------------------------------------------- - * Local variables - *----------------------------------------------------------------------------*/ - -uint32_t FirmwareSize; -uint32_t firmwareAddress = FIRMWARE_ADDRESS; -uint32_t firmwareWritten = 0; -uint32_t eepromAddress = 0; -uint32_t eepromWritten = 0; - -TCHAR backupFilename[_MAX_LFN+1]; - -uint32_t Master_frequency; -volatile uint8_t Tenms; - -FIL FlashFile; -DIR Dj; -FILINFO Finfo; - -TCHAR Filenames[20][_MAX_LFN + 1]; -uint32_t FileSize[20]; -uint32_t Valid; - -#define BLOCK_LEN 4096 -uint8_t Block_buffer[BLOCK_LEN]; -UINT BlockCount; - -uint32_t memoryType; - -uint32_t unlocked = 0; - -void interrupt10ms(void) -{ - Tenms |= 1; // 10 mS has passed - - uint8_t index = KEY_MENU; - uint8_t in = readKeys(); - for (uint8_t i = 1; i != uint8_t(1 << TRM_BASE); i <<= 1) { - uint8_t value = (in & i); - keys[index].input(value); - ++index; - } - -#if defined(PCBX9E) || defined(PCBX7) - checkRotaryEncoder(); - static rotenc_t rePreviousValue; - rotenc_t reNewValue = (rotencValue[0] / 2); - int8_t scrollRE = reNewValue - rePreviousValue; - if (scrollRE) { - rePreviousValue = reNewValue; - if (scrollRE < 0) { - putEvent(EVT_KEY_FIRST(KEY_MINUS)); - } - else { - putEvent(EVT_KEY_FIRST(KEY_PLUS)); - } - } -#endif -} - -void init10msTimer() -{ - INTERRUPT_5MS_TIMER->ARR = 9999; // 10mS - INTERRUPT_5MS_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1; // 1uS from 12MHz - INTERRUPT_5MS_TIMER->CCER = 0; - INTERRUPT_5MS_TIMER->CCMR1 = 0; - INTERRUPT_5MS_TIMER->EGR = 0; - INTERRUPT_5MS_TIMER->CR1 = 5; - INTERRUPT_5MS_TIMER->DIER |= 1; - NVIC_EnableIRQ(INTERRUPT_5MS_IRQn); -} - -extern "C" void INTERRUPT_5MS_IRQHandler() -{ - INTERRUPT_5MS_TIMER->SR &= ~TIM_SR_UIF; - interrupt10ms(); -} - -FRESULT readBinDir(DIR *dj, FILINFO *fno) -{ - FRESULT fr; - uint32_t loop; - do { - loop = 0; - fr = f_readdir(dj, fno); // First entry - - if (fr != FR_OK || fno->fname[0] == 0) { - break; - } - int32_t len = strlen(fno->fname) - 4; - if (len < 0) { - loop = 1; - } - if (fno->fname[len] != '.') { - loop = 1; - } - if ((fno->fname[len + 1] != 'b') && (fno->fname[len + 1] != 'B')) { - loop = 1; - } - if ((fno->fname[len + 2] != 'i') && (fno->fname[len + 2] != 'I')) { - loop = 1; - } - if ((fno->fname[len + 3] != 'n') && (fno->fname[len + 3] != 'N')) { - loop = 1; - } - - } while (loop); - return fr; -} - -uint32_t fillNames(uint32_t index) -{ - uint32_t i; - FRESULT fr; - fr = f_readdir(&Dj, 0); // rewind - for (i = 0; i <= index; ++i) { - fr = readBinDir(&Dj, &Finfo); // First entry - if (fr == FR_NO_FILE) { - return 0; - } - } - strAppend(Filenames[0], Finfo.fname); - FileSize[0] = Finfo.fsize; - for (i = 1; i < 7; i += 1) { - fr = readBinDir(&Dj, &Finfo); - if (fr != FR_OK || Finfo.fname[0] == 0) { - break; - } - strAppend(Filenames[i], Finfo.fname); - FileSize[i] = Finfo.fsize; - } - return i; -} - -const char *getBinaryPath() -{ - if (memoryType == MEM_FLASH) - return FIRMWARES_PATH; - else - return EEPROMS_PATH; -} - -FRESULT openBinaryFile(uint32_t index) -{ - TCHAR filename[_MAX_LFN+1]; - FRESULT fr; - memset(Block_buffer, 0, sizeof(Block_buffer)); - strAppend(strAppend(strAppend(filename, getBinaryPath()), "/"), Filenames[index]); - if ((fr = f_open(&FlashFile, filename, FA_READ)) != FR_OK) { - return fr; - } - if (memoryType == MEM_FLASH) { - if ((fr = f_lseek(&FlashFile, BOOTLOADER_SIZE)) != FR_OK) { - return fr; - } - } - fr = f_read(&FlashFile, Block_buffer, BLOCK_LEN, &BlockCount); - - if (BlockCount == BLOCK_LEN) - return fr; - else - return FR_INVALID_OBJECT; -} - -uint32_t isValidBufferStart(const uint8_t * buffer) -{ - if (memoryType == MEM_FLASH) - return isFirmwareStart(buffer); - else - return isEepromStart(buffer); -} - -int menuFlashFile(uint32_t index, event_t event) -{ - FRESULT fr; - - lcdDrawTextAlignedLeft(4*FH, STR_HOLD_ENTER_TO_START); - - if (Valid == 0) { - // Validate file here - if ((fr = openBinaryFile(index))) { - Valid = 2; - } - else { - if ((fr = f_close(&FlashFile))) { - Valid = 2; - } - else { - Valid = 1; - } - if (!isValidBufferStart(Block_buffer)) { - Valid = 2; - } - } - } - - if (Valid == 2) { - if (memoryType == MEM_FLASH) - lcdDrawTextAlignedLeft(4*FH, STR_INVALID_FIRMWARE); - else - lcdDrawTextAlignedLeft(4*FH, STR_INVALID_EEPROM); - if (event == EVT_KEY_BREAK(BOOT_KEY_EXIT) || event == EVT_KEY_BREAK(BOOT_KEY_MENU)) { - return 0; - } - return -1; - } - - if (event == EVT_KEY_LONG(BOOT_KEY_MENU)) { - fr = openBinaryFile(index); - return (fr == FR_OK && isValidBufferStart(Block_buffer)); - } - else if (event == EVT_KEY_FIRST(BOOT_KEY_EXIT)) { - return 0; - } - - return -1; -} - -extern Key keys[]; - -static uint32_t PowerUpDelay; - -void flashWriteBlock() -{ - uint32_t blockOffset = 0; - while (BlockCount) { - flashWrite((uint32_t *)firmwareAddress, (uint32_t *)&Block_buffer[blockOffset]); - blockOffset += FLASH_PAGESIZE; - firmwareAddress += FLASH_PAGESIZE; - if (BlockCount > FLASH_PAGESIZE) { - BlockCount -= FLASH_PAGESIZE; - } - else { - BlockCount = 0; - } - } -} - -void writeEepromBlock() -{ - eepromWriteBlock(Block_buffer, eepromAddress, BlockCount); - eepromAddress += BlockCount; -} - -int main() -{ - uint8_t index = 0; - uint8_t maxhsize = DISPLAY_CHAR_WIDTH; - FRESULT fr; - uint32_t state = ST_START; - uint32_t nameCount = 0; - uint32_t vpos = 0; - uint32_t hpos = 0; - -#if defined(PCBTARANIS) - wdt_reset(); - RCC_AHB1PeriphClockCmd(PWR_RCC_AHB1Periph | KEYS_RCC_AHB1Periph | LCD_RCC_AHB1Periph | BACKLIGHT_RCC_AHB1Periph | I2C_RCC_AHB1Periph | SD_RCC_AHB1Periph, ENABLE); - RCC_APB1PeriphClockCmd(LCD_RCC_APB1Periph | BACKLIGHT_RCC_APB1Periph | INTERRUPT_5MS_APB1Periph | I2C_RCC_APB1Periph | SD_RCC_APB1Periph, ENABLE); - RCC_APB2PeriphClockCmd(BACKLIGHT_RCC_APB2Periph, ENABLE); -#endif - - pwrInit(); - delaysInit(); // needed for lcdInit() - lcdInit(); - backlightInit(); - - lcdClear(); - lcdDrawSizedText(0, 0, (const char *)bootloaderVersion, 0); // trick to avoid bootloaderVersion to be optimized out ... - lcdDrawTextAlignedLeft(0, BOOTLOADER_TITLE); - lcdInvertLine(0); - lcdRefresh(); - - keysInit(); - i2cInit(); - - __enable_irq(); - init10msTimer(); - -#if defined(PCBTARANIS) - // SD card detect pin - sdInit(); - usbInit(); -#endif - - for (;;) { - wdt_reset(); - - if (Tenms) { - Tenms = 0; - - lcdRefreshWait(); - lcdClear(); - lcdDrawTextAlignedLeft(0, BOOTLOADER_TITLE); - lcdInvertLine(0); - - event_t event = getEvent(); - - if (state != ST_USB) { - if (usbPlugged()) { - state = ST_USB; - if (!unlocked) { - unlocked = 1; - unlockFlash(); - } - usbStart(); - usbPluggedIn(); - } - } - - if (state == ST_START) { - lcdDrawTextAlignedLeft(2*FH, "\010Write Firmware"); - lcdDrawTextAlignedLeft(3*FH, "\010Restore EEPROM"); - lcdDrawTextAlignedLeft(4*FH, "\010Exit"); -#if LCD_W >= 212 - lcdDrawTextAlignedLeft(6*FH, "\001Curr FW:"); - lcdDrawText(50, 6*FH, getOtherVersion()); -#else - lcdDrawTextAlignedLeft(6*FH, "\001FW:"); - - // Remove opentx- from string - const char* other_ver = getOtherVersion(); - if (strstr(other_ver, "opentx-")) - other_ver = other_ver+7; - lcdDrawText(20, 6*FH, other_ver); -#endif - lcdInvertLine(2+vpos); - lcdDrawTextAlignedLeft(7*FH, STR_OR_PLUGIN_USB_CABLE); - if (event == EVT_KEY_FIRST(BOOT_KEY_DOWN)) { - vpos == 2 ? vpos = 0 : vpos = vpos+1; - } - else if (event == EVT_KEY_FIRST(BOOT_KEY_UP)) { - vpos == 0 ? vpos = 2 : vpos = vpos-1; - } - else if (event == EVT_KEY_BREAK(BOOT_KEY_MENU)) { - switch (vpos) { - case 0: - state = ST_FLASH_MENU; - break; - case 1: - state = ST_RESTORE_MENU; - break; - default: - state = ST_REBOOT; - } - } - } - - if (state == ST_USB) { - lcdDrawTextAlignedLeft(4*FH, STR_USB_CONNECTED); - if (usbPlugged() == 0) { - vpos = 0; - usbStop(); - if (unlocked) { - lockFlash(); - unlocked = 0; - } - state = ST_START; - } - } - - if (state == ST_FLASH_MENU || state == ST_RESTORE_MENU) { - sdInit(); - memoryType = (state == ST_RESTORE_MENU ? MEM_EEPROM : MEM_FLASH); - state = ST_DIR_CHECK; - } - - else if (state == ST_DIR_CHECK) { - fr = f_chdir(getBinaryPath()); - if (fr == FR_OK) { - state = ST_OPEN_DIR; - } - else { - lcdDrawTextAlignedLeft(2*FH, INDENT "Directory is missing!"); - if (event == EVT_KEY_BREAK(BOOT_KEY_EXIT) || event == EVT_KEY_BREAK(BOOT_KEY_MENU)) { - vpos = 0; - state = ST_START; - } - } - } - - if (state == ST_OPEN_DIR) { - index = 0; - fr = f_opendir(&Dj, "."); - if (fr == FR_OK) { - state = ST_FILE_LIST; - nameCount = fillNames(0); - hpos = 0; - vpos = 0; - } - } - - if (state == ST_FILE_LIST) { - uint32_t limit = 6; - if (nameCount < limit) { - limit = nameCount; - } - maxhsize = 0; - for (uint32_t i=0; i maxhsize) { - maxhsize = x; - } - if (x > DISPLAY_CHAR_WIDTH) { - if (hpos + DISPLAY_CHAR_WIDTH > x) { - x = x - DISPLAY_CHAR_WIDTH; - } - else { - x = hpos; - } - } - else { - x = 0; - } - lcdDrawSizedText(INDENT_WIDTH, 16 + FH * i, &Filenames[i][x], DISPLAY_CHAR_WIDTH, 0); - } - - if (event == EVT_KEY_REPT(BOOT_KEY_DOWN) || event == EVT_KEY_FIRST(BOOT_KEY_DOWN)) { - if (vpos < limit - 1) { - vpos += 1; - } - else { - if (nameCount > limit) { - index += 1; - nameCount = fillNames(index); - } - } - } - else if (event == EVT_KEY_REPT(BOOT_KEY_UP) || event == EVT_KEY_FIRST(BOOT_KEY_UP)) { - if (vpos > 0) { - vpos -= 1; - } - else { - if (index) { - index -= 1; - nameCount = fillNames(index); - } - } - } -#if !defined(PCBTARANIS) - else if (event == EVT_KEY_REPT(BOOT_KEY_RIGHT) || event == EVT_KEY_FIRST(BOOT_KEY_RIGHT)) { - if (hpos + DISPLAY_CHAR_WIDTH < maxhsize) { - hpos += 1; - } - } - else if (event == EVT_KEY_REPT(BOOT_KEY_LEFT) || event == EVT_KEY_FIRST(BOOT_KEY_LEFT)) { - if (hpos) { - hpos -= 1; - } - } -#endif - else if (event == EVT_KEY_BREAK(BOOT_KEY_MENU)) { - // Select file to flash - state = ST_FLASH_CHECK; - Valid = 0; - } - else if (event == EVT_KEY_FIRST(BOOT_KEY_EXIT)) { - state = ST_START; - vpos = 0; - } - - lcdInvertLine(2 + vpos); - } - - else if (state == ST_FLASH_CHECK) { - int result = menuFlashFile(vpos, event); - FirmwareSize = FileSize[vpos] - BOOTLOADER_SIZE; - if (result == 0) { - // canceled - state = ST_FILE_LIST; - } - else if (result == 1) { - // confirmed - firmwareAddress = FIRMWARE_ADDRESS + BOOTLOADER_SIZE; - firmwareWritten = 0; - eepromAddress = 0; - eepromWritten = 0; - state = ST_FLASHING; - } - } - - else if (state == ST_FLASHING) { - // commit to flashing - lcdDrawTextAlignedLeft(4*FH, CENTER "\015Writing..."); - - if (!unlocked && (memoryType == MEM_FLASH)) { - unlocked = 1; - unlockFlash(); - } - - int progress; - if (memoryType == MEM_FLASH) { - flashWriteBlock(); - firmwareWritten += sizeof(Block_buffer); - progress = ((LCD_W-12)*firmwareWritten) / FirmwareSize; - } - else { - writeEepromBlock(); - eepromWritten += sizeof(Block_buffer); - progress = ((LCD_W-12)*eepromWritten) / EEPROM_SIZE; - } - - lcdDrawRect(3, 6*FH+4, (LCD_W-8), 7); - lcdDrawSolidHorizontalLine(5, 6*FH+6, progress, FORCE); - lcdDrawSolidHorizontalLine(5, 6*FH+7, progress, FORCE); - lcdDrawSolidHorizontalLine(5, 6*FH+8, progress, FORCE); - - fr = f_read(&FlashFile, Block_buffer, sizeof(Block_buffer), &BlockCount); - if (BlockCount == 0) { - state = ST_FLASH_DONE; // EOF - } - if (firmwareWritten >= FLASHSIZE - BOOTLOADER_SIZE) { - state = ST_FLASH_DONE; // Backstop - } - if (eepromWritten >= EEPROM_SIZE) { - state = ST_FLASH_DONE; // Backstop - } - } - - if (state == ST_FLASH_DONE) { - if (unlocked) { - lockFlash(); - unlocked = 0; - } - lcdDrawTextAlignedLeft(4*FH, CENTER "\007Writing complete"); - if (event == EVT_KEY_FIRST(BOOT_KEY_EXIT) || event == EVT_KEY_BREAK(BOOT_KEY_MENU)) { - state = ST_START; - vpos = 0; - } - } - - if (event == EVT_KEY_LONG(BOOT_KEY_EXIT)) { - state = ST_REBOOT; - } - - lcdRefresh(); - - if (PowerUpDelay < 20) { // 200 mS - PowerUpDelay += 1; - } - else { - sdPoll10ms(); - } - } - - if (state != ST_FLASHING && state != ST_USB) { - if (pwrOffPressed()) { - lcdOff(); // this drains LCD caps - pwrOff(); - for (;;) { - // Wait for power to go off - } - } - } - - if (state == ST_REBOOT) { - if (readKeys() == 0) { - lcdClear(); - lcdRefresh(); - lcdRefreshWait(); - RCC->CSR |= RCC_CSR_RMVF; // clear the reset flags in RCC clock control & status register - NVIC_SystemReset(); - } - } - } - - return 0; -} diff --git a/radio/src/targets/taranis/bootloader/boot_menu.cpp b/radio/src/targets/taranis/bootloader/boot_menu.cpp new file mode 100644 index 00000000000..1d7835569cf --- /dev/null +++ b/radio/src/targets/taranis/bootloader/boot_menu.cpp @@ -0,0 +1,91 @@ +#include "opentx.h" +#include "../../common/arm/stm32/bootloader/boot.h" +#include "../../common/arm/stm32/bootloader/bin_files.h" + +extern MemoryType memoryType; + +void bootloaderInitScreen() +{ +} + +static void bootloaderDrawMsg(unsigned int x, const char* str, uint8_t line, bool inverted) +{ + lcdDrawSizedText(x, (line + 2) * FH, str, DISPLAY_CHAR_WIDTH, inverted ? INVERS : 0); +} + +void bootloaderDrawFilename(const char* str, uint8_t line, bool selected) +{ + bootloaderDrawMsg(INDENT_WIDTH, str, line, selected); +} + +void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) +{ + lcdClear(); + lcdDrawText(0, 0, BOOTLOADER_TITLE, INVERS); + + if (st == ST_START) { + lcdDrawTextAlignedLeft(2*FH, "\010Write Firmware"); + lcdDrawTextAlignedLeft(3*FH, "\010Restore EEPROM"); + lcdDrawTextAlignedLeft(4*FH, "\010Exit"); + +#if LCD_W >= 212 + lcdDrawTextAlignedLeft(6*FH, "\001Curr FW:"); + lcdDrawText(50, 6*FH, getOtherVersion(nullptr)); +#else + lcdDrawTextAlignedLeft(6*FH, "\001FW:"); + + // Remove opentx- from string + const char* other_ver = getOtherVersion(nullptr); + if (strstr(other_ver, "opentx-")) + other_ver = other_ver+7; + lcdDrawText(20, 6*FH, other_ver); +#endif + + lcdInvertLine(2+opt); + lcdDrawTextAlignedLeft(7*FH, STR_OR_PLUGIN_USB_CABLE); + } + else if (st == ST_USB) { + lcdDrawTextAlignedLeft(4*FH, STR_USB_CONNECTED); + } + else if (st == ST_DIR_CHECK) { + if (opt == FR_NO_PATH) { + bootloaderDrawMsg(INDENT_WIDTH, "Directory is missing!", 1, false); + bootloaderDrawMsg(INDENT_WIDTH, getBinaryPath(memoryType), 2, false); + } + else { + bootloaderDrawMsg(INDENT_WIDTH, "Directory is empty!", 1, false); + } + } + else if (st == ST_FLASH_CHECK) { + if (opt == FC_ERROR) { + + if (memoryType == MEM_FLASH) + bootloaderDrawMsg(0, STR_INVALID_FIRMWARE, 2, false); + else + bootloaderDrawMsg(0, STR_INVALID_EEPROM, 2, false); + } + else if (opt == FC_OK) { + + const char* vers = getOtherVersion((char*)Block_buffer); +#if LCD_W < 212 + // Remove opentx- from string + if (strstr(vers, "opentx-")) + vers = vers+7; +#endif + bootloaderDrawMsg(INDENT_WIDTH, vers, 0, false); + bootloaderDrawMsg(0, STR_HOLD_ENTER_TO_START, 2, false); + } + } + else if (st == ST_FLASHING) { + lcdDrawTextAlignedLeft(4*FH, CENTER "\015Writing..."); + + lcdDrawRect(3, 6*FH+4, (LCD_W-8), 7); + lcdDrawSolidHorizontalLine(5, 6*FH+6, (LCD_W-12) * opt / 100, FORCE); + lcdDrawSolidHorizontalLine(5, 6*FH+7, (LCD_W-12) * opt / 100, FORCE); + lcdDrawSolidHorizontalLine(5, 6*FH+8, (LCD_W-12) * opt / 100, FORCE); + } + else if (st == ST_FLASH_DONE) { + + lcdDrawTextAlignedLeft(4*FH, CENTER "\007Writing complete"); + } +} diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index afb8bdb4ef6..7c3857ab8f0 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -433,9 +433,14 @@ #if defined(PCBX9E) || defined(PCBX7) #define PWR_PRESS_BUTTON #endif + #define PWR_GPIO GPIOD +#define PWR_SWITCH_GPIO_REG PWR_GPIO->IDR #define PWR_SWITCH_GPIO_PIN GPIO_Pin_1 // PD.01 #define PWR_ON_GPIO_PIN GPIO_Pin_0 // PD.00 +#define PWR_ON_GPIO_MODER GPIO_MODER_MODER0 +#define PWR_ON_GPIO_MODER_OUT GPIO_MODER_MODER0_0 + #if defined(PCBX7) #define LED_GREEN_GPIO GPIOC #define LED_GREEN_GPIO_PIN GPIO_Pin_4 // PC.04 @@ -697,6 +702,8 @@ #define LCD_RST_GPIO GPIOD #define LCD_RST_GPIO_PIN GPIO_Pin_12 // PD.12 #endif +#define LCD_RCC_APB2Periph 0 + // I2C Bus: EEPROM and CAT5137 digital pot for volume control #define I2C_RCC_AHB1Periph RCC_AHB1Periph_GPIOB @@ -828,14 +835,14 @@ #define BT_RCC_APB2Periph 0 #endif -// 5ms Interrupt -#define INTERRUPT_5MS_APB1Periph RCC_APB1Periph_TIM14 -#define INTERRUPT_5MS_TIMER TIM14 -#define INTERRUPT_5MS_IRQn TIM8_TRG_COM_TIM14_IRQn -#define INTERRUPT_5MS_IRQHandler TIM8_TRG_COM_TIM14_IRQHandler +// Xms Interrupt +#define INTERRUPT_xMS_RCC_APB1Periph RCC_APB1Periph_TIM14 +#define INTERRUPT_xMS_TIMER TIM14 +#define INTERRUPT_xMS_IRQn TIM8_TRG_COM_TIM14_IRQn +#define INTERRUPT_xMS_IRQHandler TIM8_TRG_COM_TIM14_IRQHandler // 2MHz Timer -#define TIMER_2MHz_APB1Periph RCC_APB1Periph_TIM7 +#define TIMER_2MHz_RCC_APB1Periph RCC_APB1Periph_TIM7 #define TIMER_2MHz_TIMER TIM7 #endif // _HAL_H_ diff --git a/radio/src/targets/taranis/stm32_ramboot.ld b/radio/src/targets/taranis/stm32_ramboot.ld index f2e6e555a2d..05df857a6b5 100644 --- a/radio/src/targets/taranis/stm32_ramboot.ld +++ b/radio/src/targets/taranis/stm32_ramboot.ld @@ -47,7 +47,7 @@ SECTIONS { . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */ - *(.version) + KEEP(*(.bootversiondata)) . = ALIGN(4); /* Align the start of the text part */ *(.text) /* .text sections (code) */ *(.text*) /* .text* sections (code) */ @@ -62,36 +62,36 @@ SECTIONS . = ALIGN(4); _etext = .; /* define a global symbols at end of code */ - } >RAM + } >FLASH - .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH .ARM : { __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; - } >RAM + } >FLASH .preinit_array : { PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array*)) PROVIDE_HIDDEN (__preinit_array_end = .); - } >RAM + } >FLASH .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array*)) PROVIDE_HIDDEN (__init_array_end = .); - } >RAM + } >FLASH .fini_array : { PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(.fini_array*)) KEEP (*(SORT(.fini_array.*))) PROVIDE_HIDDEN (__fini_array_end = .); - } >RAM + } >FLASH /* used by the startup to initialize data */ _sidata = .; diff --git a/radio/src/targets/taranis/stm32f2_flash.ld b/radio/src/targets/taranis/stm32f2_flash.ld index 3d72e6a95e4..e696af60499 100644 --- a/radio/src/targets/taranis/stm32f2_flash.ld +++ b/radio/src/targets/taranis/stm32f2_flash.ld @@ -50,10 +50,7 @@ SECTIONS CREATE_OBJECT_SYMBOLS - KEEP(*(.isr_boot_vector)) /* Startup code */ - KEEP(*(.bootversiondata)) - *(.bootrodata) - *(.bootrodata.*) + KEEP(*(.bootloader)) /* Bootloader code */ . = 32768; /* Set the start of the main program */ _stext = .; /* Provide the name for the start of this section */ diff --git a/radio/src/targets/taranis/stm32f4_flash.ld b/radio/src/targets/taranis/stm32f4_flash.ld index c3732e799ce..7d5706c5528 100644 --- a/radio/src/targets/taranis/stm32f4_flash.ld +++ b/radio/src/targets/taranis/stm32f4_flash.ld @@ -51,14 +51,11 @@ SECTIONS CREATE_OBJECT_SYMBOLS - KEEP(*(.isr_boot_vector)) /* Startup code */ - KEEP(*(.bootversiondata)) - *(.bootrodata) - *(.bootrodata.*) + KEEP(*(.bootloader)) /* Bootloader code */ - . = 32768; /* Set the start of the main program */ + . = 0x8000; /* Set the start of the main program */ _stext = .; /* Provide the name for the start of this section */ - . = ALIGN(4); + . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */ KEEP(*(.fwversiondata)) *(.text) /* .text sections (code) */ @@ -67,7 +64,7 @@ SECTIONS *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ *(.glue_7) /* glue arm to thumb code */ *(.glue_7t) /* glue thumb to arm code */ - *(.eh_frame) + *(.eh_frame) KEEP (*(.init)) KEEP (*(.fini))