{"id":365095,"date":"2024-05-21T02:30:50","date_gmt":"2024-05-21T02:30:50","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=365095"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=365095","title":{"rendered":"<span>STM32 without any trouble<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>Easy Marlin installation on STM32 debug board<\/p>\n<p><strong>Confusion over bootloaders<\/strong><\/p>\n<p>Here\u2019s a brief historical and technical overview to help us understand what a bootloader is, why you need it, and what it has to do with Marlin and STM32.<\/p>\n<p><strong>Arduino<\/strong><\/p>\n<p>Arduino boards use a special bootloader that allows you to update the microcontroller firmware without a programmer. This bootloader is not part of the microcontroller, but is pre-flashed into it by the board manufacturer and is never changed.<\/p>\n<p>In 2009, leaflabs tried to produce its own line of Arduino-like boards based on STM32. A set of libmaple libraries and a special loader were developed for Arduino compatibility. This initiative did not have any notable success, and in 2015 the libmaple project was closed.<\/p>\n<p>Marlin has never used or supported the bootloader from leaflabs.<\/p>\n<p><strong>STM32<\/strong><\/p>\n<p>STM32 microcontrollers have a built-in bootloader, which allows you to upload firmware without using a programmer or debugger. The bootloader is stored in the microcontroller\u2019s non-volatile ROM and cannot be corrupted or deleted without physically damaging the chip.<\/p>\n<p>A special BOOT0 pin is used to activate this bootloader. Depending on the signal applied to it at power-up or reboot, control is transferred either to custom firmware (low signal level) or to the built-in bootloader (high signal level).<\/p>\n<p>The built-in bootloader allows one to upload the firmware using UART or USB connection. The latter option is available only on STM32F4 and newer microcontrollers.<\/p>\n<p><strong>Marlin<\/strong><\/p>\n<p>In December 2018, Marlin introduced support for the MKS Robin board with its proprietary bootloader, which allowed firmware updates from an encrypted file on the SD card. The MKS bootloader is stored at the beginning of the flash memory and from the microcontroller\u2019s point of view is custom firmware. The firmware for MKS Robin had to be built using a non-standard location on the flash memory.<\/p>\n<p>The ability to update the firmware from an SD card proved to be a decisive factor, and in spring 2019, BTT SKR Mini v1.1\u2014the first commercial STM32-based 3D printer control board made specifically for Marlin 2.0\u2014appeared on the market. Naturally, it had its own loader, but the general working principle did not change.<\/p>\n<p>All STM32-based 3D printer control boards on the market use the manufacturer\u2019s bootloader that allows you to update the firmware from an SD card. The size of such a loader depends on its functionality as well as the developer and varies from 8 to 64 kb. When you see mentions of a damaged bootloader, it\u2019s all about this one.<\/p>\n<p>In case of debug boards manufacturers don\u2019t bother with a bootloader because it\u2019s completely unnecessary. Flashing through the ST-Link debugger is infinitely easier, and if the developer needs a non-standard bootloader, he can flash it himself, and with exactly the right functionality.<\/p>\n<p>If, for some reason, ST-Link is not available, there is always the possibility of flashing the debug board via the built-in bootloader.<\/p>\n<p>Thus, when the word &#171;bootloader&#187; is used in relation to STM32, its meaning depends on the context. On a 3D printer control board, it\u2019s a manufacturer\u2019s bootloader, stored at the beginning of the flash memory, which allows updating the firmware from the SD card. On the debug board, it\u2019s a built-in bootloader that uses its own ROM without taking up any space in flash memory.<\/p>\n<p><strong>Choosing a debug board<\/strong><\/p>\n<p>Any debug board can be used, but it\u2019s worth considering that the availability of documentation saves you from having to manually create a pinout diagram, which is a huge time-saver.<\/p>\n<p>Debug boards from STMicroelectronics Nucleo and Discovery series are well documented and come with a built-in ST-Link debugger. However, they cost more than their Chinese alternatives.<\/p>\n<p>As a starting point for board selection, you can use the STM32-base project, which describes many popular debug boards on various STM32 microcontrollers.<\/p>\n<p>I have two boards from this list lying around, so I will use them:<\/p>\n<ul>\n<li>\n<p>SM32F103ZET6 from EUse<\/p>\n<\/li>\n<li>\n<p>SM32F407ZET6 from MCUDev<\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f2b\/678\/707\/f2b678707fdf3691c5048a806f130853.png\" width=\"870\" height=\"599\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f2b\/678\/707\/f2b678707fdf3691c5048a806f130853.png\"\/><\/figure>\n<p><strong>Connecting and uploading firmware<\/strong><\/p>\n<p>So, we\u2019ve decided on types of bootloaders, and now let\u2019s move on to the ways of uploading the firmware to the debug board.<\/p>\n<p>The most convenient and versatile way is to use the ST-Link debugger. I won\u2019t dwell on alternatives like J-Link, Black Magic Probe and CMSIS-DAP, because they are not as common as ST-Link. And if you have one of those, you already know how to work with it.<\/p>\n<p>The second best in terms of convenience and simply the best in terms of economy is flashing via USB using DFU (device firmware update). It\u2019s not as convenient as using ST-Link, because it requires rebooting the microcontroller and running the built-in bootloader, but it allows you to do without additional expenses for ST-Link or USB-UART adapter. Unfortunately, this method is not available to all and owners of F103-based debug boards have nothing to do but throw up their hands.<\/p>\n<p>Another versatile way is to flash via UART using a USB-UART adapter (FT232R, CH340, etc.). It also requires rebooting the microcontroller and running the built-in bootloader, but it works for all STM32 controllers.<\/p>\n<p>Some guides on how to flash STM32 mention such programs as ST-LINK Utility, Flash Loader Demonstrator and DfuSe used to upload the firmware via ST-Link, UART and USB. They are still available for download on the manufacturer\u2019s site, but there you can notice that all three are no longer recommended for use and have been replaced by the universal STM32CubeProgrammer.<\/p>\n<p>Download and install STM32CubeProgrammer, connect the debug board in the chosen way and check that the drivers for the USB device are installed. When connecting via UART and USB, do not forget to connect the BOOT0 pin to 3V3.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ce8\/fba\/7c9\/ce8fba7c9339b9f1f7d980190c263a39.png\" width=\"870\" height=\"328\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ce8\/fba\/7c9\/ce8fba7c9339b9f1f7d980190c263a39.png\"\/><\/figure>\n<p>After that, start STM32CubeProgrammer, select the desired type of connection and press the Connect button. If you have not messed up the wires, then in a few seconds the program will inform you about a successful connection and show information about the controller used.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/eec\/9b9\/3e2\/eec9b93e2fbab800c1661e09ab6452f2.png\" width=\"870\" height=\"219\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/eec\/9b9\/3e2\/eec9b93e2fbab800c1661e09ab6452f2.png\"\/><\/figure>\n<p>We don\u2019t have ready firmware to upload yet, but now we know for sure that the necessary drivers are installed and the board is connected correctly.<\/p>\n<p>Those who wish can make a copy of the demo firmware. To do this, in the Size field specify the size of the microcontroller flash memory (for STM32F103ZE it\u2019s 524288 or 0x80000), click on the Read button and wait for the process to finish. Save the firmware by selecting Save As in the drop-down menu.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8ed\/592\/160\/8ed5921608e386d715ac23ca760999eb.png\" width=\"870\" height=\"656\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/8ed\/592\/160\/8ed5921608e386d715ac23ca760999eb.png\"\/><\/figure>\n<p>Reading the firmware from the microcontroller is not a quick process, especially via UART, so we won\u2019t wait for those who want to make a backup copy. Let\u2019s go straight to the Marlin assembly. As for STM32CubeProgrammer, we won\u2019t need it anymore.<\/p>\n<p><strong>Marlin assembly<\/strong><\/p>\n<p>Now that the preparatory stage is over, we can move on to the fun part.<\/p>\n<p>In the Marlin configuration there is a special type of board for working with non-standard hardware, which we\u2019ll use. To do this, in Configuration.h enter:<\/p>\n<p><em>#define MOTHERBOARD BOARD_CUSTOM<\/em><\/p>\n<p>The pinout for this type of board is taken from the nonexistent Marlin\\src\\pins\\pins_custom.h file. And this file does not exist to prevent it from being overwritten when updating the code.<\/p>\n<p>Since we don\u2019t have a real 3D printer, but a debug board, we need to define 4 pins of the microcontroller to create a minimal configuration:<\/p>\n<ul>\n<li>\n<p>The pin to which the LED is connected, which will blink to indicate that the firmware is successfully running.<\/p>\n<\/li>\n<li>\n<p>The pin that will be used to read the state of all the end stops. I will use the one to which the custom buttons on the debug board are connected. That\u2019s not necessary, but this way it will be possible to check the state of the end stops and demonstrate some working functionality.<\/p>\n<\/li>\n<li>\n<p>The pin to which the control signals for the stepper motors, heaters and fan will be output is also one for all. In my case it will be the pin with the second diode.<\/p>\n<\/li>\n<li>\n<p>The pin that will be used to read the temperature sensors, also one for all. Here the choice is quite limited, since it should be one of those pins that can work as an ADC input. Which pins can be used for this can be found in the microcontroller documentation as well as in the framework-arduinoststm32 code. For me it\u2019s PA0.<\/p>\n<\/li>\n<\/ul>\n<p><strong>STM32F103ZE and UART<\/strong><\/p>\n<p>Create a file Marlin\\src\\pins\\pins_custom.h and fill it with the minimum necessary settings:<\/p>\n<p><em>#define LED_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PC0<\/em><\/p>\n<p><em>#define DUMMY_IN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PF11<\/em><\/p>\n<p><em>#define DUMMY_OUT \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PD3<\/em><\/p>\n<p><em>#define DUMMY_ADC \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PA0<\/em><\/p>\n<p><em>\/\/ Limit Switches<\/em><\/p>\n<p><em>#define X_MIN_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_IN<\/em><\/p>\n<p><em>#define Y_MIN_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_IN<\/em><\/p>\n<p><em>#define Z_MIN_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_IN<\/em><\/p>\n<p><em>\/\/ Steppers<\/em><\/p>\n<p><em>#define X_STEP_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define X_DIR_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define X_ENABLE_PIN\u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define Y_STEP_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define Y_DIR_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define Y_ENABLE_PIN\u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define Z_STEP_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define Z_DIR_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define Z_ENABLE_PIN\u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define E0_STEP_PIN \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define E0_DIR_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define E0_ENABLE_PIN \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>\/\/ Temperature Sensors<\/em><\/p>\n<p><em>#define TEMP_0_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_ADC<\/em><\/p>\n<p><em>#define TEMP_BED_PIN\u00a0 \u00a0 \u00a0 \u00a0 DUMMY_ADC<\/em><\/p>\n<p><em>\/\/ Heaters \/ Fans<\/em><\/p>\n<p><em>#define HEATER_0_PIN\u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define HEATER_BED_PIN\u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define FAN0_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p>To build firmware for BOARD_CUSTOM board we need to use a new environment [env:custom]. To do this, create an ini\\custom.ini file and in the platformio.ini file in the [platformio] section add a new file to the extra_configs parameter. In the same section specify the environment you want to build for.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fc1\/e0f\/f0b\/fc1e0ff0bcbbd8ec3aa30ab60f83fb9f.png\" width=\"438\" height=\"538\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fc1\/e0f\/f0b\/fc1e0ff0bcbbd8ec3aa30ab60f83fb9f.png\"\/><\/figure>\n<p>In the file ini\\custom.ini create a custom environment for STM32F103ZE. There is no special description for the Euse M3 DEMO board, so we will use the basic version for this microcontroller. The whole range of available boards can be found in the .platformio\\platforms\\ststm32\\boards catalog.<\/p>\n<p><em>[env:custom]<\/em><\/p>\n<p><em>extends \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 = common_stm32<\/em><\/p>\n<p><em>board \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 = genericSTM32F103ZE<\/em><\/p>\n<p><em>build_flags \u00a0 \u00a0 \u00a0 = ${common_stm32.build_flags}<\/em><\/p>\n<p><em>upload_protocol \u00a0 = serial<\/em><\/p>\n<p>This is the configuration for flashing via UART. If the flashing is done via ST-Link, it must be specified in the boot parameters:<\/p>\n<p><em>upload_protocol \u00a0 = stlink<\/em><\/p>\n<p>There is no bootloader in the debug boards except for the built-in one. The firmware is written standardly, to the beginning of the flash memory, so no additional parameters are required. Flashing is always done via UART1 (PA9 and PA10), so we\u2019ll specify the same port in Configuration.h:<\/p>\n<p><em>#define SERIAL_PORT 1<\/em><\/p>\n<p>There are no temperature sensors on the debug board, nor any wiring, and an attempt to read the temperature values from the ADC can produce excessively high values, which will lead to the firmware crash. To avoid this, let\u2019s change the types of hotend and bed sensors to 998, which always reports a temperature of 25 \u2103:<\/p>\n<p><em>#define TEMP_SENSOR_0 998<\/em><\/p>\n<p><em>#define TEMP_SENSOR_BED 998<\/em><\/p>\n<p>We will also change the pull-up of the end stops, since the board description for the buttons says Active High:<\/p>\n<p><em>#define ENDSTOPPULLDOWNS<\/em><\/p>\n<p>If this is not done, pressing the button will not change the state of the end stops.<\/p>\n<p>Now we can move on to building and uploading the firmware. Connect the BOOT0 pin to 3V3 using a jumper or the corresponding button and reboot the board. In PlatformIO press the Upload button on the status bar at the bottom of the screen and patiently wait for the process to finish.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/61d\/936\/215\/61d9362159059e7851f7629665b52458.png\" width=\"700\" height=\"60\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/61d\/936\/215\/61d9362159059e7851f7629665b52458.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/044\/8c1\/537\/0448c1537d27483b55811f433bd9d319.png\" width=\"870\" height=\"807\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/044\/8c1\/537\/0448c1537d27483b55811f433bd9d319.png\"\/><\/figure>\n<p>The firmware is assembled and, judging by blinking, it works fine.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/694\/b99\/38e\/694b9938eecc515a9fd7ce24c04a2a3f.png\" width=\"597\" height=\"546\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/694\/b99\/38e\/694b9938eecc515a9fd7ce24c04a2a3f.png\"\/><\/figure>\n<p>Next, let\u2019s ground BOOT0, connect to the COM port with your favorite terminal and reboot the board. Marlin boots up and starts blinking again. Using the M119 command and the button on the board, check the functionality of the end stops.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/628\/3d1\/678\/6283d16783fc4cb05d2095a262534b3b.png\" width=\"870\" height=\"614\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/628\/3d1\/678\/6283d16783fc4cb05d2095a262534b3b.png\"\/><\/figure>\n<p>Although nothing spectacular, everything works fine. Let\u2019s add USB connectivity, SD card support and TFT screen, since the board has a separate slot for it.\u00a0<\/p>\n<p>Let\u2019s write this in Configuration.h:<\/p>\n<p><em>#define SERIAL_PORT_2 -1<\/em><\/p>\n<p><em>#define LCD_LANGUAGE ru<\/em><\/p>\n<p><em>#define SDSUPPORT<\/em><\/p>\n<p><em>#define TFT_GENERIC<\/em><\/p>\n<p><em>#define TFT_INTERFACE_FSMC<\/em><\/p>\n<p><em>#define TFT_RES_480x320<\/em><\/p>\n<p><em>#define TFT_COLOR_UI<\/em><\/p>\n<p><em>#define TFT_ROTATION TFT_ROTATE_270<\/em><\/p>\n<p><em>#define TOUCH_SCREEN<\/em><\/p>\n<p>It\u2019s worth mentioning that using a virtual COM port (created when the board is connected via USB) is poorly suited for debugging firmware. Every time the microcontroller is rebooted, the connection drops, and most (or even all) terminal programs cannot reconnect automatically when the device is lost. The optimal option for debugging is an external USB-UART adapter, which will maintain a stable connection and avoid loss of firmware data.<\/p>\n<p>Pins for connecting a display are determined by a thoughtful comparison of the inscriptions on the pinout of the board. SD card is connected to the SDIO interface of the microcontroller, which should also be specified in pins_custom.h:<\/p>\n<p><em>#define TFT_CS_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PG12<\/em><\/p>\n<p><em>#define TFT_RS_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PG0<\/em><\/p>\n<p><em>#define TFT_BACKLIGHT_PIN \u00a0 PB0<\/em><\/p>\n<p><em>#define TFT_RESET_PIN \u00a0 \u00a0 \u00a0 PC5<\/em><\/p>\n<p><em>#define TOUCH_INT_PIN \u00a0 \u00a0 \u00a0 PF10<\/em><\/p>\n<p><em>#define TOUCH_CS_PIN\u00a0 \u00a0 \u00a0 \u00a0 PB2<\/em><\/p>\n<p><em>#define TOUCH_MISO_PIN\u00a0 \u00a0 \u00a0 PF8<\/em><\/p>\n<p><em>#define TOUCH_MOSI_PIN\u00a0 \u00a0 \u00a0 PF9<\/em><\/p>\n<p><em>#define TOUCH_SCK_PIN \u00a0 \u00a0 \u00a0 PB1<\/em><\/p>\n<p><em>#ifndef SDCARD_CONNECTION<\/em><\/p>\n<p><em>\u00a0\u00a0#define SDCARD_CONNECTION\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ONBOARD<\/em><\/p>\n<p><em>\u00a0\u00a0#define ONBOARD_SDIO\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ Use SDIO for onboard SD<\/em><\/p>\n<p><em>#endif<\/em><\/p>\n<p>The framework-arduinoststm32 has a modular structure, and by default modules for SDIO and FSMC are not connected. You can connect them by adding two parameters to the assembly:<\/p>\n<p><em>build_flags \u00a0 \u00a0 \u00a0 = ${common_stm32.build_flags}<\/em><\/p>\n<p><em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0-DHAL_SD_MODULE_ENABLED<\/em><\/p>\n<p><em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0-DHAL_SRAM_MODULE_ENABLED<\/em><\/p>\n<p>To avoid calibrating the touch screen after every reboot, let\u2019s add the ability to save the settings:<\/p>\n<p><em>#define EEPROM_SETTINGS<\/em><\/p>\n<p>On the back of the Euse M3 DEMO board there is a place to install the EEPROM chip, but the chip itself is not soldered, so we\u2019ll use flash memory of the controller to store settings. The resource of this flash memory is less than that of EEPROM (ten thousand write cycles against four million), but it\u2019s quite enough for storing settings. For this purpose we\u2019ll add the corresponding parameter in pins_custom.h:<\/p>\n<p><em>#define FLASH_EEPROM_EMULATION<\/em><\/p>\n<p>The final configuration for building under STM32F103ZE:<\/p>\n<p><em>ini\/custom.ini<\/em><\/p>\n<p><em>[env:custom]<\/em><\/p>\n<p><em>extends \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 = common_stm32<\/em><\/p>\n<p><em>board \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 = genericSTM32F103ZE<\/em><\/p>\n<p><em>build_flags \u00a0 \u00a0 \u00a0 = ${common_stm32.build_flags}<\/em><\/p>\n<p><em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0-DHAL_SD_MODULE_ENABLED<\/em><\/p>\n<p><em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0-DHAL_SRAM_MODULE_ENABLED<\/em><\/p>\n<p><em>upload_protocol \u00a0 = serial<\/em><\/p>\n<p>And here is pins_custom.h without the DUMMY part, which remains unchanged:<\/p>\n<p><em>#pragma once<\/em><\/p>\n<p><em>#define DEFAULT_MACHINE_NAME &#171;STM32F103ZET6&#187;<\/em><\/p>\n<p><em>#define FLASH_EEPROM_EMULATION<\/em><\/p>\n<p><em>#define LED_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PD3<\/em><\/p>\n<p><em>#define DUMMY_IN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PF11<\/em><\/p>\n<p><em>#define DUMMY_OUT \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PC0<\/em><\/p>\n<p><em>#define DUMMY_ADC \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PA0<\/em><\/p>\n<p><em>#define TFT_CS_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PG12<\/em><\/p>\n<p><em>#define TFT_RS_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PG0<\/em><\/p>\n<p><em>#define TFT_BACKLIGHT_PIN \u00a0 PB0<\/em><\/p>\n<p><em>#define TFT_RESET_PIN \u00a0 \u00a0 \u00a0 PC5<\/em><\/p>\n<p><em>#define TOUCH_INT_PIN \u00a0 \u00a0 \u00a0 PF10<\/em><\/p>\n<p><em>#define TOUCH_CS_PIN\u00a0 \u00a0 \u00a0 \u00a0 PB2<\/em><\/p>\n<p><em>#define TOUCH_MISO_PIN\u00a0 \u00a0 \u00a0 PF8<\/em><\/p>\n<p><em>#define TOUCH_MOSI_PIN\u00a0 \u00a0 \u00a0 PF9<\/em><\/p>\n<p><em>#define TOUCH_SCK_PIN \u00a0 \u00a0 \u00a0 PB1<\/em><\/p>\n<p><em>\/\/ Onboard SD support<\/em><\/p>\n<p><em>#ifndef SDCARD_CONNECTION<\/em><\/p>\n<p><em>\u00a0\u00a0#define SDCARD_CONNECTION\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ONBOARD<\/em><\/p>\n<p><em>\u00a0\u00a0#define ONBOARD_SDIO\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ Use SDIO for onboard SD<\/em><\/p>\n<p><em>#endif<\/em><\/p>\n<p><strong>STM32F407ZE and DFU<\/strong><\/p>\n<p>Now, let\u2019s move on to building the firmware under STM32F407ZE. This board has its own description, which includes SDIO support, so you\u2019ll need fewer parameters to build it.<\/p>\n<p><em>[env:custom]<\/em><\/p>\n<p><em>extends \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 = common_stm32<\/em><\/p>\n<p><em>board \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 = black_f407ze<\/em><\/p>\n<p><em>build_flags \u00a0 \u00a0 \u00a0 = ${common_stm32.build_flags}<\/em><\/p>\n<p><em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0-DHAL_SRAM_MODULE_ENABLED<\/em><\/p>\n<p><em>upload_protocol \u00a0 = dfu<\/em><\/p>\n<p>The buttons on the board work in the Active Low mode, and the screen for this board is smaller and differently arranged. In Configuration.h you need to change the corresponding parameters:<\/p>\n<p><em>#define ENDSTOPPULLUPS<\/em><\/p>\n<p><em>#define TFT_RES_320x240<\/em><\/p>\n<p><em>#define TFT_ROTATION TFT_ROTATE_90<\/em><\/p>\n<p>Also STM32F4 has 4 kb of RAM powered by the board battery. Marlin can use this memory to store settings, which is great for us:<\/p>\n<p><em>#define SRAM_EEPROM_EMULATION<\/em><\/p>\n<p>Here\u2019s the final pins_custom.h without the DUMMY part, which remains unchanged:<\/p>\n<p><em>#pragma once<\/em><\/p>\n<p><em>#define DEFAULT_MACHINE_NAME &#171;STM32F407ZET6&#187;<\/em><\/p>\n<p><em>#define SRAM_EEPROM_EMULATION<\/em><\/p>\n<p><em>#define LED_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PF10<\/em><\/p>\n<p><em>#define DUMMY_IN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PE4<\/em><\/p>\n<p><em>#define DUMMY_OUT \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PF9<\/em><\/p>\n<p><em>#define DUMMY_ADC \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PA0<\/em><\/p>\n<p><em>#define TFT_CS_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PG12<\/em><\/p>\n<p><em>#define TFT_RS_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PF12<\/em><\/p>\n<p><em>#define TFT_BACKLIGHT_PIN \u00a0 PB15<\/em><\/p>\n<p><em>#define TOUCH_INT_PIN \u00a0 \u00a0 \u00a0 PB1<\/em><\/p>\n<p><em>#define TOUCH_CS_PIN\u00a0 \u00a0 \u00a0 \u00a0 PC13<\/em><\/p>\n<p><em>#define TOUCH_MISO_PIN\u00a0 \u00a0 \u00a0 PB2<\/em><\/p>\n<p><em>#define TOUCH_MOSI_PIN\u00a0 \u00a0 \u00a0 PF11<\/em><\/p>\n<p><em>#define TOUCH_SCK_PIN \u00a0 \u00a0 \u00a0 PB0<\/em><\/p>\n<p><em>\/\/ Onboard SD support<\/em><\/p>\n<p><em>#ifndef SDCARD_CONNECTION<\/em><\/p>\n<p><em>\u00a0\u00a0#define SDCARD_CONNECTION\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ONBOARD<\/em><\/p>\n<p><em>\u00a0\u00a0#define ONBOARD_SDIO\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ Use SDIO for onboard SD<\/em><\/p>\n<p><em>#endif<\/em><\/p>\n<p>The next step is similar to the previous board: connect BOOT0 to 3V3, reboot and upload the firmware. As in that example, don\u2019t forget to ground BOOT0 when there\u2019s no need to update the firmware.<\/p>\n<p>Flashing via ST-Link is a bit simpler, since it does not require manipulations with BOOT0 and manual reboot.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/4b6\/5c5\/c91\/4b65c5c912adf279f04dfdc2d99c8c9a.png\" width=\"774\" height=\"810\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/4b6\/5c5\/c91\/4b65c5c912adf279f04dfdc2d99c8c9a.png\"\/><\/figure>\n<p><strong>TL;DR<\/strong><\/p>\n<ul>\n<li>\n<p>Marlin is easy and fast to install on STM32 debug boards.<\/p>\n<\/li>\n<li>\n<p>PlatformIO can flash STM32 debug boards using ST-Link, UART or USB.<\/p>\n<\/li>\n<li>\n<p>ST-Link is convenient, but not required. For STM32F4, a USB cable is enough.<\/p>\n<\/li>\n<\/ul>\n<p><em>This article was originally written by jmz, published at 3dtoday.ru, translated by the Top 3D Shop team.<\/em><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/785866\/\"> https:\/\/habr.com\/ru\/articles\/785866\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>Easy Marlin installation on STM32 debug board<\/p>\n<p><strong>Confusion over bootloaders<\/strong><\/p>\n<p>Here\u2019s a brief historical and technical overview to help us understand what a bootloader is, why you need it, and what it has to do with Marlin and STM32.<\/p>\n<p><strong>Arduino<\/strong><\/p>\n<p>Arduino boards use a special bootloader that allows you to update the microcontroller firmware without a programmer. This bootloader is not part of the microcontroller, but is pre-flashed into it by the board manufacturer and is never changed.<\/p>\n<p>In 2009, leaflabs tried to produce its own line of Arduino-like boards based on STM32. A set of libmaple libraries and a special loader were developed for Arduino compatibility. This initiative did not have any notable success, and in 2015 the libmaple project was closed.<\/p>\n<p>Marlin has never used or supported the bootloader from leaflabs.<\/p>\n<p><strong>STM32<\/strong><\/p>\n<p>STM32 microcontrollers have a built-in bootloader, which allows you to upload firmware without using a programmer or debugger. The bootloader is stored in the microcontroller\u2019s non-volatile ROM and cannot be corrupted or deleted without physically damaging the chip.<\/p>\n<p>A special BOOT0 pin is used to activate this bootloader. Depending on the signal applied to it at power-up or reboot, control is transferred either to custom firmware (low signal level) or to the built-in bootloader (high signal level).<\/p>\n<p>The built-in bootloader allows one to upload the firmware using UART or USB connection. The latter option is available only on STM32F4 and newer microcontrollers.<\/p>\n<p><strong>Marlin<\/strong><\/p>\n<p>In December 2018, Marlin introduced support for the MKS Robin board with its proprietary bootloader, which allowed firmware updates from an encrypted file on the SD card. The MKS bootloader is stored at the beginning of the flash memory and from the microcontroller\u2019s point of view is custom firmware. The firmware for MKS Robin had to be built using a non-standard location on the flash memory.<\/p>\n<p>The ability to update the firmware from an SD card proved to be a decisive factor, and in spring 2019, BTT SKR Mini v1.1\u2014the first commercial STM32-based 3D printer control board made specifically for Marlin 2.0\u2014appeared on the market. Naturally, it had its own loader, but the general working principle did not change.<\/p>\n<p>All STM32-based 3D printer control boards on the market use the manufacturer\u2019s bootloader that allows you to update the firmware from an SD card. The size of such a loader depends on its functionality as well as the developer and varies from 8 to 64 kb. When you see mentions of a damaged bootloader, it\u2019s all about this one.<\/p>\n<p>In case of debug boards manufacturers don\u2019t bother with a bootloader because it\u2019s completely unnecessary. Flashing through the ST-Link debugger is infinitely easier, and if the developer needs a non-standard bootloader, he can flash it himself, and with exactly the right functionality.<\/p>\n<p>If, for some reason, ST-Link is not available, there is always the possibility of flashing the debug board via the built-in bootloader.<\/p>\n<p>Thus, when the word &#171;bootloader&#187; is used in relation to STM32, its meaning depends on the context. On a 3D printer control board, it\u2019s a manufacturer\u2019s bootloader, stored at the beginning of the flash memory, which allows updating the firmware from the SD card. On the debug board, it\u2019s a built-in bootloader that uses its own ROM without taking up any space in flash memory.<\/p>\n<p><strong>Choosing a debug board<\/strong><\/p>\n<p>Any debug board can be used, but it\u2019s worth considering that the availability of documentation saves you from having to manually create a pinout diagram, which is a huge time-saver.<\/p>\n<p>Debug boards from STMicroelectronics Nucleo and Discovery series are well documented and come with a built-in ST-Link debugger. However, they cost more than their Chinese alternatives.<\/p>\n<p>As a starting point for board selection, you can use the STM32-base project, which describes many popular debug boards on various STM32 microcontrollers.<\/p>\n<p>I have two boards from this list lying around, so I will use them:<\/p>\n<ul>\n<li>\n<p>SM32F103ZET6 from EUse<\/p>\n<\/li>\n<li>\n<p>SM32F407ZET6 from MCUDev<\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><\/figure>\n<p><strong>Connecting and uploading firmware<\/strong><\/p>\n<p>So, we\u2019ve decided on types of bootloaders, and now let\u2019s move on to the ways of uploading the firmware to the debug board.<\/p>\n<p>The most convenient and versatile way is to use the ST-Link debugger. I won\u2019t dwell on alternatives like J-Link, Black Magic Probe and CMSIS-DAP, because they are not as common as ST-Link. And if you have one of those, you already know how to work with it.<\/p>\n<p>The second best in terms of convenience and simply the best in terms of economy is flashing via USB using DFU (device firmware update). It\u2019s not as convenient as using ST-Link, because it requires rebooting the microcontroller and running the built-in bootloader, but it allows you to do without additional expenses for ST-Link or USB-UART adapter. Unfortunately, this method is not available to all and owners of F103-based debug boards have nothing to do but throw up their hands.<\/p>\n<p>Another versatile way is to flash via UART using a USB-UART adapter (FT232R, CH340, etc.). It also requires rebooting the microcontroller and running the built-in bootloader, but it works for all STM32 controllers.<\/p>\n<p>Some guides on how to flash STM32 mention such programs as ST-LINK Utility, Flash Loader Demonstrator and DfuSe used to upload the firmware via ST-Link, UART and USB. They are still available for download on the manufacturer\u2019s site, but there you can notice that all three are no longer recommended for use and have been replaced by the universal STM32CubeProgrammer.<\/p>\n<p>Download and install STM32CubeProgrammer, connect the debug board in the chosen way and check that the drivers for the USB device are installed. When connecting via UART and USB, do not forget to connect the BOOT0 pin to 3V3.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>After that, start STM32CubeProgrammer, select the desired type of connection and press the Connect button. If you have not messed up the wires, then in a few seconds the program will inform you about a successful connection and show information about the controller used.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>We don\u2019t have ready firmware to upload yet, but now we know for sure that the necessary drivers are installed and the board is connected correctly.<\/p>\n<p>Those who wish can make a copy of the demo firmware. To do this, in the Size field specify the size of the microcontroller flash memory (for STM32F103ZE it\u2019s 524288 or 0x80000), click on the Read button and wait for the process to finish. Save the firmware by selecting Save As in the drop-down menu.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>Reading the firmware from the microcontroller is not a quick process, especially via UART, so we won\u2019t wait for those who want to make a backup copy. Let\u2019s go straight to the Marlin assembly. As for STM32CubeProgrammer, we won\u2019t need it anymore.<\/p>\n<p><strong>Marlin assembly<\/strong><\/p>\n<p>Now that the preparatory stage is over, we can move on to the fun part.<\/p>\n<p>In the Marlin configuration there is a special type of board for working with non-standard hardware, which we\u2019ll use. To do this, in Configuration.h enter:<\/p>\n<p><em>#define MOTHERBOARD BOARD_CUSTOM<\/em><\/p>\n<p>The pinout for this type of board is taken from the nonexistent Marlin\\src\\pins\\pins_custom.h file. And this file does not exist to prevent it from being overwritten when updating the code.<\/p>\n<p>Since we don\u2019t have a real 3D printer, but a debug board, we need to define 4 pins of the microcontroller to create a minimal configuration:<\/p>\n<ul>\n<li>\n<p>The pin to which the LED is connected, which will blink to indicate that the firmware is successfully running.<\/p>\n<\/li>\n<li>\n<p>The pin that will be used to read the state of all the end stops. I will use the one to which the custom buttons on the debug board are connected. That\u2019s not necessary, but this way it will be possible to check the state of the end stops and demonstrate some working functionality.<\/p>\n<\/li>\n<li>\n<p>The pin to which the control signals for the stepper motors, heaters and fan will be output is also one for all. In my case it will be the pin with the second diode.<\/p>\n<\/li>\n<li>\n<p>The pin that will be used to read the temperature sensors, also one for all. Here the choice is quite limited, since it should be one of those pins that can work as an ADC input. Which pins can be used for this can be found in the microcontroller documentation as well as in the framework-arduinoststm32 code. For me it\u2019s PA0.<\/p>\n<\/li>\n<\/ul>\n<p><strong>STM32F103ZE and UART<\/strong><\/p>\n<p>Create a file Marlin\\src\\pins\\pins_custom.h and fill it with the minimum necessary settings:<\/p>\n<p><em>#define LED_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PC0<\/em><\/p>\n<p><em>#define DUMMY_IN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PF11<\/em><\/p>\n<p><em>#define DUMMY_OUT \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PD3<\/em><\/p>\n<p><em>#define DUMMY_ADC \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PA0<\/em><\/p>\n<p><em>\/\/ Limit Switches<\/em><\/p>\n<p><em>#define X_MIN_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_IN<\/em><\/p>\n<p><em>#define Y_MIN_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_IN<\/em><\/p>\n<p><em>#define Z_MIN_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_IN<\/em><\/p>\n<p><em>\/\/ Steppers<\/em><\/p>\n<p><em>#define X_STEP_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define X_DIR_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define X_ENABLE_PIN\u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define Y_STEP_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define Y_DIR_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define Y_ENABLE_PIN\u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define Z_STEP_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define Z_DIR_PIN \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define Z_ENABLE_PIN\u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define E0_STEP_PIN \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define E0_DIR_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define E0_ENABLE_PIN \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>\/\/ Temperature Sensors<\/em><\/p>\n<p><em>#define TEMP_0_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_ADC<\/em><\/p>\n<p><em>#define TEMP_BED_PIN\u00a0 \u00a0 \u00a0 \u00a0 DUMMY_ADC<\/em><\/p>\n<p><em>\/\/ Heaters \/ Fans<\/em><\/p>\n<p><em>#define HEATER_0_PIN\u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define HEATER_BED_PIN\u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p><em>#define FAN0_PIN\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 DUMMY_OUT<\/em><\/p>\n<p>To build firmware for BOARD_CUSTOM board we need to use a new environment [env:custom]. To do this, create an ini\\custom.ini file and in the platformio.ini file in the [platformio] section add a new file to the extra_configs parameter. In the same section specify the environment you want to build for.<\/p>\n<figure class=\"\"><\/figure>\n<p>In the file ini\\custom.ini create a custom environment for STM32F103ZE. There is no special description for the Euse M3 DEMO board, so we will use the basic version for this microcontroller. The whole range of available boards can be found in the .platformio\\platforms\\ststm32\\boards catalog.<\/p>\n<p><em>[env:custom]<\/em><\/p>\n<p><em>extends \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 = common_stm32<\/em><\/p>\n<p><em>board \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 = genericSTM32F103ZE<\/em><\/p>\n<p><em>build_flags \u00a0 \u00a0 \u00a0 = ${common_stm32.build_flags}<\/em><\/p>\n<p><em>upload_protocol \u00a0 = serial<\/em><\/p>\n<p>This is the configuration for flashing via UART. If the flashing is done<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-365095","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/365095","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=365095"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/365095\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=365095"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=365095"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=365095"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}