{"id":13995908,"url":"https://github.com/lupyuen/visual-embedded-rust","last_synced_at":"2025-04-11T17:40:45.399Z","repository":{"id":87767400,"uuid":"200803058","full_name":"lupyuen/visual-embedded-rust","owner":"lupyuen","description":"Visual Embedded Rust extension for Visual Studio Code","archived":false,"fork":false,"pushed_at":"2023-03-03T05:04:30.000Z","size":27640,"stargazers_count":84,"open_issues_count":3,"forks_count":11,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-25T13:39:45.477Z","etag":null,"topics":["mynewt","rust","vscode"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lupyuen.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null},"funding":{"github":["lupyuen"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":["paypal.me/lupyuen"]}},"created_at":"2019-08-06T07:49:09.000Z","updated_at":"2025-02-06T10:16:50.000Z","dependencies_parsed_at":"2024-01-23T08:57:43.532Z","dependency_job_id":null,"html_url":"https://github.com/lupyuen/visual-embedded-rust","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lupyuen%2Fvisual-embedded-rust","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lupyuen%2Fvisual-embedded-rust/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lupyuen%2Fvisual-embedded-rust/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lupyuen%2Fvisual-embedded-rust/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lupyuen","download_url":"https://codeload.github.com/lupyuen/visual-embedded-rust/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248451349,"owners_count":21105854,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mynewt","rust","vscode"],"created_at":"2024-08-09T14:03:39.274Z","updated_at":"2025-04-11T17:40:45.376Z","avatar_url":"https://github.com/lupyuen.png","language":"TypeScript","funding_links":["https://github.com/sponsors/lupyuen","paypal.me/lupyuen"],"categories":["TypeScript"],"sub_categories":[],"readme":"UPDATE: This code in this article has been archived in the [pre-lvgl branch of pinetime-rust-mynewt](https://github.com/lupyuen/pinetime-rust-mynewt/tree/pre-lvgl). The [pinetime-rust-mynewt firmware](https://github.com/lupyuen/pinetime-rust-mynewt) has been revamped to support [Rust Watch Faces on LVGL](https://lupyuen.github.io/pinetime-rust-mynewt/articles/watchface). [Check out the updates](https://lupyuen.github.io/pinetime-rust-mynewt/articles/watchface)\n\n# visual-embedded-rust\n\n- Create and edit Embedded Rust programs visually by dragging and dropping blocks\n\n- Generates Embedded Rust firmware code for [__PineTime Smart Watch__](https://wiki.pine64.org/index.php/PineTime) hosted on [__Apache Mynewt__](https://mynewt.apache.org/) realtime operating system, with [__druid UI Framework__](https://github.com/lupyuen/druid-embedded)\n\n- Hardware Required: PineTime Smart Watch and Raspberry Pi (preferably Pi 4 with Raspbian)\n\n![Demo](images/demo.gif)\n\n![Visual Embedded Rust](images/animation.gif)\n\n# Connect PineTime to Raspberry Pi\n\n1️⃣ Carefully pry open the PineTime casing. Use tweezers to pivot the shiny battery gently to the side. Be careful not to break the red and black wires that connect the battery to the watch!\n\n2️⃣ Just above the battery we see 4 shiny rings. This is the __[Serial Wire Debug](https://en.wikipedia.org/wiki/JTAG#Serial_Wire_Debug) (SWD)__ Port for PineTime. We’ll use this port to flash our firmware to PineTime. The 4 pins (from left to right) are SWDIO (Data I/O), SWDCLK (Clock), 3.3V, GND.\n\n🛈 [_What is “flash memory” / “flashing” / “firmware”? Read this_](https://gist.github.com/lupyuen/41fffaddade277d27c48697bca21d837)\n\n![SWD Port on PineTime](images/pinetime-swd3.jpg)\n\nIn the above photo, the SWD pins from left to right are…\n\n1. __SWDIO__ (Yellow)\n\n1. __SWDCLK__ (Blue)\n\n1. __3.3V__ (Red)\n\n1. __GND__ (Black)\n\nThe exposed copper wire at the top centre of the photo is the Bluetooth antenna. Bend it upwards so that it doesn’t come into contact with anything.\n\n![Bend PineTime antenna](images/pinetime-antenna.png)\n\n3️⃣ At lower right we see a pad marked 5V. We’ll connect this pad to Raspberry Pi to charge the battery. If charging of the battery is not needed during development, we may leave5V disconnected.\n\n4️⃣ Connect the SWD Port and the 5V Pad (optional) to the Raspberry Pi with [__Solid-Core Wire (22 AWG)__](https://www.adafruit.com/product/288) and [__Female-To-Female Jumper Cables__](https://www.adafruit.com/product/1951)…\n\n| PineTime   | Raspberry Pi        | Wire Colour |\n| :---               | :---              | :---        |\n| `SWDIO`            | `Header Pin 19 (MOSI)`  | Yellow |\n| `SWDCLK`           | `Header Pin 23 (SCLK)`  | Blue |\n| `3.3V`             | `3.3V`  | Red    |\n| `GND`              | `GND`  | Black  |\n| `5V`               | `5V`  | Green (Optional)  |\n\n![Raspberry Pi Pinout](images/pinetime-pi-pinout-spi.png)\n\n_Based on https://pinout.xyz/_\n\n5️⃣ We may use Raspberry Pi Zero, 1, 2, 3 or 4.\n\n![Raspberry Pi Pinout](images/pi-spi-pin.jpg)\n\n6️⃣ The PineTime touchscreen needs to be accessible during development, so I mounted PineTime on a [$2 clear box cover from Daiso](https://www.daisojapan.com/p-30955-clear-box-28-x-47-x-19-x-in-12pks.aspx) with Blu Tack and sticky tape.\n\n![Connecting PineTime to Raspberry Pi](images/pi-spi-pinetime-small.jpg)\n\n# Remove PineTime Flash Protection\n\nPineTime is shipped with preloaded demo firmware. We need to erase the demo firmware and unprotect PineTime’s flash memory so that we may flash our own firmware.\n\n🛈 [_What is “flash protection”? Read this_](https://gist.github.com/lupyuen/3ee440542853e1e637582c4efa1b240a)\n\n1️⃣ Power on the Raspberry Pi. Open a command prompt and enter the following…\n\n```bash\nsudo raspi-config\n```\n\nSelect `Interfacing Options → SPI → Yes`\n\nSelect `Finish`\n\nAt the command prompt, enter the following…\n\n```bash\n#  Remove folders ~/pinetime-rust-mynewt and ~/openocd-spi (if they exist)\nrm -rf ~/pinetime-rust-mynewt\nrm -rf ~/openocd-spi\n\n# Download and extract \"pinetime-rust-mynewt\" folder containing our prebuilt firmware, source files and flashing scripts\nsudo apt install -y wget p7zip-full\ncd ~\nwget https://github.com/lupyuen/pinetime-rust-mynewt/releases/download/v3.0.3/pinetime-rust-mynewt.7z\n7z x pinetime-rust-mynewt.7z\nrm pinetime-rust-mynewt.7z\n\n# Install build tools for PineTime: VSCode, Rust, gcc, gdb, openocd-spi, newt\ncd ~/pinetime-rust-mynewt\nscripts/install-pi.sh\n\n# Latest nightly-2020-04-20 fails with asm error, so we use nightly-2020-02-16\nsource $HOME/.cargo/env\nrustup default nightly-2020-02-16\nrustup update\nrustup target add thumbv7em-none-eabihf\n```\n\n2️⃣ At the `Welcome to Rust!` prompt, press Enter to select the default option:\n\n`1) Proceed with installation (default)`\n\nIf you see this error…\n\n```\nCloning into 'openocd-spi/jimtcl'...\nfatal: unable to access 'http://repo.or.cz/r/jimtcl.git/': Recv failure: Connection reset by peer\nfatal: clone of 'http://repo.or.cz/r/jimtcl.git' into submodule path '/private/tmp/aa/openocd-spi/jimtcl' failed\n```\n\nIt means that the sub-repository for one of the dependencies jimtcl is temporarily down. You may download the pre-built `openocd-spi` binaries [from this link](https://github.com/lupyuen/pinetime-rust-mynewt/releases/download/openocd-spi2/openocd-spi.7z). Then copy the executable openocd-spi/src/openocd to pinetime-rust-mynewt/openocd/bin/openocd\n\n3️⃣ When the installation has completed, enter the following at the command prompt…\n\n```bash\n# Remove flash protection from PineTime and erase demo firmware\ncd ~/pinetime-rust-mynewt\nscripts/nrf52-pi/flash-unprotect.sh\n```\n\n4️⃣ We should see `Shut Down And Power Off Your Raspberry Pi`…\n\n![Unprotect Flash ROM](https://lupyuen.github.io/images/flash-unprotect.png)\n\nIf we see `Clock Speed` and nothing else after that…\n\n```\nInfo : BCM2835 SPI SWD driver\nInfo : SWD only mode enabled\nInfo : clock speed 31200 kHz\nInfo : SWD DPIDR 0x2ba01477\n```\n\nThen the connection to the SWD Port is probably loose, please check the pins. \n\nIf we don't see this `DPIDR` number, or if we see a different `DPIDR` number...\n\n```\nSWD DPIDR 0x2ba01477\n```\n\nThen the connection to the SWD Port is most likely loose, please check the pins. \n\nAlso enter `sudo raspi-config` and confirm that the SPI port has been enabled.\n\nIf we see this instead…\n\n```\nopenocd/bin/openocd: cannot execute binary file: Exec format error\n```\n\nThen `install-pi.sh` probably didn’t run correctly. To fix this, copy the `openocd` executable like this…\n\n```bash\ncp $HOME/openocd-spi/src/openocd $HOME/pinetime-rust-mynewt/openocd/bin/openocd\n```\n\n5️⃣ Shut down and power off your Raspberry Pi. Wait 30 seconds for the red and green LEDs on your Pi to turn off. Power on your Pi. Enter the same commands at a command prompt…\n\n```bash\n# Remove flash protection from PineTime and erase demo firmware\ncd ~/pinetime-rust-mynewt\nscripts/nrf52-pi/flash-unprotect.sh\n```\n\n6️⃣ We should see `Flash Is Already Unprotected`…\n\nPineTime’s demo firmware has been erased and the flash protection has been removed.\n\n🛈 [_What is OpenOCD? Why Raspberry Pi and not ROCK64 or Nvidia Jetson Nano? Read this_](https://gist.github.com/lupyuen/18e66c3e81e11050a10d1192c5b84bb0)\n\n# Edit The Visual Rust Application\n\nWe shall be using VSCode with the Visual Embedded Rust Extension to edit our Visual Rust application graphically.\n\n🛈 [_What is VSCode? Is it related to Visual Studio? How is Microsoft involved? Read this_](https://gist.github.com/lupyuen/08e383845d68d3337747e8eb59d0f624)\n\n1️⃣ Launch VSCode by clicking the Raspberry Pi Menu (top left corner) → Programming → Code OSS Headmelted\n\nIn VSCode, click `File → Open Folder`\n\nUnder `Home`, select the folder `pinetime-rust-mynewt` and click OK\n\nWhen prompted to open the workspace, click Open Workspace\n\nWhen prompted to install Extension Recommendations, click `Install All`\n\nIgnore the message `Unable To Watch For File Changes`. Close the message when it appears.\n\n2️⃣ Install the `Visual Embedded Rust` Extension...\n\nClick `View → Extensions`\n\nSearch for `Visual Embedded Rust`\n\nInstall the extension\n\n3️⃣ Enable the Visual Rust application...\n\nBrowse to `rust/app/Cargo.toml`\n\nModify the file such that `visual_app` is uncommented and the other options are commented out...\n\n```yaml\ndefault =  [          # Select the conditional compiled features\n    # \"display_app\",  # Disable graphics display app\n    # \"ui_app\",       # Disable druid UI app\n    \"visual_app\",     # Enable Visual Rust app\n    # \"use_float\",    # Disable floating-point for GPS geolocation\n]\n```\n\n4️⃣ Edit the Visual Rust application...\n\nBrowse to [`rust/app/src/visual.rs`](https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/rust/app/src/visual.rs)\n\nClick `Visual Editor` at top right\n\n![Click Visual Editor](images/install3.png)\n\nUse the Visual Editor to edit the Visual Rust application\n\n![Editing the Visual Rust application](images/animation.gif)\n\n5️⃣ After editing, save the [`visual.rs`](https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/rust/app/src/visual.rs) source file to save the visual program. Don't edit the Rust source file manually, always use the Visual Editor.\n\n[_Rust Source Code generated from Visual Rust application_](https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/rust/app/src/visual.rs)\n\nThe Visual Rust application shows a button that increments a counter...\n\n![Demo](images/demo.gif)\n\nLet's look at the blocks in the Visual Rust application...\n\n# On Start\n\n![On Start Block](images/animation1.gif)\n\nUpon starting the Watch App, we initialise the `count` variable to 0. \n\nThis block generates the following Rust code...\n\n```rust\n/// Application State\n#[infer_type]  //  Infer the missing types\n#[derive(Clone, Data, Default)]\nstruct State {\n    count: _,\n}\n\n/// Will be run upon startup to launch the app\n#[infer_type]  //  Infer the missing types\npub fn on_start() -\u003e MynewtResult\u003c()\u003e {\n    console::print(\"on_start\\n\");\n    //  Build a new window\n    let main_window = WindowDesc::new(ui_builder);\n    //  Create application state\n    let mut state = State::default();\n    state.count = 0;\n\n    //  Launch the window with the application state\n    AppLauncher::with_window(main_window)\n        .use_simple_logger()\n        .launch(state)\n        .expect(\"launch failed\");\n    //  Return success to `main()` function\n    Ok(())\n}\n```\n\n# Create App\n\n![Create App Block](images/animation2.gif)\n\nWe create a Watch App with two Widgets...\n\n1. A Label named `my_label` surrounded by padding of 5 pixels\n\n1. A Button named `my_button` with the title `Press Me`, surrounded by padding of 5 pixels\n\nThis block generates the following Rust code...\n\n```rust\n/// Build the UI for the window\n#[infer_type]  //  Infer the missing types\nfn ui_builder() -\u003e impl Widget\u003cState\u003e {  //  `State` is the Application State\n    console::print(\"Rust UI builder\\n\"); console::flush();\n    //  Create a line of text\n    //  Call `on_my_label_show` to get label text\n    let my_label_text = LocalizedString::new(\"hello-counter\")\n        .with_arg(\"count\", on_my_label_show);  \n    //  Create a label widget `my_label`\n    let my_label = Label::new(my_label_text);\n    //  Create a button widget `my_button`\n    //  Call `on_my_button_press` when pressed\n    let my_button = Button::new(\"Press Me\", on_my_button_press);\n\n    //  Create a column\n    let mut col = Column::new();\n    //  Add the label widget to the column, centered with padding\n    col.add_child(\n        Align::centered(\n            Padding::new(5.0,\n                my_label\n            )\n        ),\n        1.0\n    );\n    //  Add the button widget to the column, with padding\n    col.add_child(\n        Padding::new(5.0,\n            my_button\n        ),\n        1.0\n    );\n    //  Return the column containing the widgets\n    col\n}  //  ;\n```\n\n# On Label Show\n\n![On Label Show Block](images/animation3.gif)\n\nThis block is called to generate the text that will be shown on the label `my_label`.\n\nWe return the variable `count` for display on the label.\n\nThis block generates the following Rust code...\n\n```rust\n/// Callback function that will be called to create the formatted text for the label `my_label`\n#[infer_type]  //  Infer the missing types\nfn on_my_label_show(state: _, env: _) -\u003e ArgValue {\n    console::print(\"on_my_label_show\\n\");\n    state.count.into()\n}\n```\n\n# On Button Press\n\n![On Button Press Block](images/animation4.gif)\n\nThis block is called to when the button `my_button` is pressed.\n\nWe increment the variable `count` by 1.\n\nThis block generates the following Rust code...\n\n```rust\n/// Callback function that will be called when the button `my_button` is pressed\n#[infer_type]  //  Infer the missing types\nfn on_my_button_press(ctx: _, state: _, env: _) {\n    console::print(\"on_my_button_press\\n\");\n    state.count = state.count + 1;\n}\n```\n\n# Build And Flash The Firmware\n\nWe’ll be flashing the PineTime firmware that’s based on open-source [__Apache Mynewt embedded operating system__](https://mynewt.apache.org/). Mynewt OS contains two components that we shall flash to PineTime…\n\n__Mynewt Bootloader__: This is the C code that’s run whenever we power on PineTime. The Bootloader executes the Mynewt Application upon startup.\n\n__Mynewt Application__: Contains a Rust application that controls the PineTime functions, and low-level system functions written in C.\n\nThe Bootloader and Application firmware image files may be found at these locations…\n\n| Mynewt Component          | Flash Memory Address      | Location of Firmware Image  |\n| :---               | :---              | :---        |\n| Bootloader           | `0x0`  | `~/pinetime-rust-mynewt/bin/targets/nrf52_boot/app/apps/boot_stub/boot_stub.elf.bin` |\n| Application          | `0x8000`  | `~/pinetime-rust-mynewt/bin/targets/nrf52_my_sensor/app/apps/my_sensor_app/my_sensor_app.img` |\n\n_From https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/hw/bsp/nrf52/bsp.yml_\n\n🛈 [_What is a Bootloader? Read this_](https://gist.github.com/lupyuen/93ba71e0ae5e746e7a68e4513e0a54d8)\n\n1️⃣ At the lower left corner, there is a panel `Task Runner`. Click the panel to display the build and flash tasks.\n\n2️⃣ In the Task Runner, click `[1] Build Bootloader`\n\nWhen the Terminal Panel appears, right-click the `Terminal` tab, select `Move Panel Right`\n\nAfter the building the Bootloader, we should see `Done`\n\nIgnore the message `There Are Task Errors`\n\nThe Bootloader only needs to be built once.\n\n3️⃣ In the Task Runner, click `[2] Build Application`\n\nAfter the building the Application, we should see `Done`\n\nIf you see the message `Undefined Reference To Main`, click `[2] Build Application` again and it should succeed.\n\nThe Application needs to be rebuilt whenever a source file has been changed.\n\n4️⃣ In the Task Runner, click `[3] Image Application`\n\nAfter the creating the Firmware Image, we should see `Done`\n\n5️⃣ In the Task Runner, click `[4] Flash Bootloader`\n\nAfter flashing the Bootloader Firmware to PineTime, we should see `Done`\n\n\n```\nFlashing Bootloader...\ntarget halted due to debug-request, current mode: Thread \nxPSR: 0x01000000 pc: 0x000000d8 msp: 0x20010000\nEnabled ARM Semihosting to show debug output\n** Programming Started **\nInfo : nRF52832-QFAA(build code: E1) 512kB Flash, 64kB RAM\nWarn : Adding extra erase range, 0x00000b78 .. 0x00000fff\n** Programming Finished **\n** Verify Started **\n** Verified OK **\n\nRestarting...\ntarget halted due to debug-request, current mode: Thread \nxPSR: 0x01000000 pc: 0x000000d8 msp: 0x20010000, semihosting\n\n**** Done!\n```\n\n_From https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/logs/load-bootloader-pi.log_\n\nThe Bootloader only needs to be flashed once.\n\n6️⃣ In the Task Runner, click `[5] Flash Application`\n\nAfter the flashing the Application Firmware to PineTime, we should see `Done! Press Ctrl-C To Exit`…\n\n```\nFlashing Application...\ntarget halted due to debug-request, current mode: Thread \nxPSR: 0x01000000 pc: 0x000000d8 msp: 0x20010000\nEnabled ARM Semihosting to show debug output\n** Programming Started **\nInfo : nRF52832-QFAA(build code: E1) 512kB Flash, 64kB RAM\nWarn : Adding extra erase range, 0x0003e820 .. 0x0003efff\n** Programming Finished **\n** Verify Started **\n** Verified OK **\n\nRestarting...\ntarget halted due to debug-request, current mode: Thread \nxPSR: 0x01000000 pc: 0x000000d8 msp: 0x20010000, semihosting\nEnabled ARM Semihosting to show debug output\n\n**** Done! Press Ctrl-C to exit...\n```\n\n_From https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/logs/load-application-pi.log_\n\n7️⃣ Our Visual Rust application starts running on PineTime\n\n![Demo](images/demo.gif)\n\n8️⃣ Click the Trash icon 🗑 near the top right to terminate the application. If we click the Close icon ❌ instead of the Trash icon, the next flash or debug command will fail.\n\n![Click the Trash icon, not the Close icon](images/trash-close.png)\n\n# PineTime Updater\n\nAlternatively, flash the following two files to PineTime with [__PineTime Updater__](https://github.com/lupyuen/pinetime-updater)...\n\n1.  __MCUBoot Bootloader__\n\n    File: `bin/targets/nrf52_boot/app/boot/mynewt/mynewt.elf`\n\n    Address: `0x0`\n\n1.  __Rust+Mynewt Firmware__\n\n    File: `bin/targets/nrf52_my_sensor/app/apps/my_sensor_app/my_sensor_app.elf`\n\n    Address: `0x8000`\n\n# Debug The Firmware\n\n1️⃣ Build the application: In the Task Runner, click `[2] Build Application`\n\n2️⃣ Click `Debug → Start Debugging` or press `F5`\n\nThis starts the VSCode Debugger and automatically flashes our updated firmware to PineTime.\n\n3️⃣ Click `View → Output`\n\nIn the Output Panel, select `Adapter Output`\n\nThe debugging messages will be displayed here.\n\n4️⃣ The program has paused at first line of code in our firmware, the Reset Handler.\n\nIn the Debug Toolbar, click `Continue` or press `F5`\n\n![Continue](images/debug-bar-continue.png)\n\n🛈 [_What’s a Reset Handler? Read this_](https://gist.github.com/lupyuen/b0b7782f21330e292ea65b9c875bd9a7)\n\n5️⃣ The debugger now pauses at the first line of the main function that’s defined in rust/app/src/lib.rs\n\nThis is the first line of Rust code in our Rust Application, which will call test_display in a while.\n\nIn the Debug Toolbar, click Continue or press F5\n\n🛈 [_What’s a main function? Read this_](https://gist.github.com/lupyuen/5360769a2d92ec50d988cce92622abff)\n\n# Edit, Build and Debug the Visual Rust Application on Windows\n\n![Debugging PineTime Firmware with VSCode on Windows](images/vscode-debug-windows.png)\n\nTo edit, build and debug the Visual Rust Application on Windows, follow these steps...\n\n## _[Windows]_ Connect PineTime to ST-Link\n\nIf we’re doing serious development with PineTime, I recommend getting an [ST-Link v2 USB dongle](https://www.aliexpress.com/wholesale?catId=0\u0026initiative_id=SB_20180924134644\u0026SearchText=st-link+v2\u0026switch_new_app=y) ($2) that connects PineTime directly to our Windows, macOS or Linux computer.\n\nST-Link allows us to flash PineTime directly from our computer, and it even supports firmware debugging (setting breakpoints, checking values of variables at runtime, …)\n\nHere’s how we connect PineTime to ST-Link…\n\n![PineTime connected to ST-Link](images/stlink.jpg)\n\n| PineTime          | ST-Link        | Wire Colour |\n| :---               | :---              | :---        |\n| `SWDIO`            | `SWDIO`  | Yellow |\n| `SWDCLK`           | `SWDCLK`  | Blue |\n| `3.3V`             | `3.3V`  | Red    |\n| `GND`              | `GND`  | Black  |\n| `5V`               | `5V`   | Green (Optional) |\n\nBefore connecting ST-Link to our Windows computer, the ST-Link USB driver should be installed...\n\nDownload the ST-Link USB driver from ST-Link Driver Website (email registration required)…\n\nhttps://www.st.com/en/development-tools/stsw-link009.html\n\nClick `Get Software`\n\nUnzip the downloaded file. Double-click the driver installer:\n`dpinst_amd64.exe`\n\n## _[Windows]_ Remove PineTime Flash Protection\n\nThis must be done with a Raspberry Pi, not on Windows, because ST-Link is a High-Level Adapter that doesn't implement all flash commands. Follow the instructions above for Raspberry Pi.\n\n## _[Windows]_ Install PineTime Build Tools\n\n1️⃣ Download the pinetime-rust-mynewt.7z file attached below…\n\nhttps://github.com/lupyuen/pinetime-rust-mynewt/releases/download/v3.0.1/pinetime-rust-mynewt.7z\n\nExpand the `.7z` file with 7zip…\n\nhttps://www.7-zip.org/download.html\n\n2️⃣ Click here to install Build Tools For Visual Studio 2019:\n\nhttps://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019\n\n![Build Tools For Visual Studio 2019](images/vsstudio-build-tools.png)\n\nClick the `Individual Components` tab\n\nSelect the following components:\n\n1. `Windows 10 SDK (10.0.18362.0)`\n\n1. `C++ CMake Tools for Windows`\n\n1. (This should be automatically selected) `MSVC v142 — VS 2019 C++ x64/x86 Build Tools`\n\n3️⃣ Install `rustup` according to the instructions here:\n`rustup.rs`\n\nClick the link provided to download `rustup‑init.exe`\n\nLaunch the downloaded file `rustup‑init.exe`\n\nIf you see the message `Windows Defender SmartScreen prevented an unrecognised app from starting`…\n\nClick `More Info`\n\nClick `Run Anyway`\n\nAt the `Welcome to Rust!` prompt, press Enter to select the default option:\n\n`1) Proceed with installation (default)`\n\n4️⃣ Open the Command Prompt and enter…\n\n```cmd\n:: Install Rust build tools for Arm Cortex\nrustup default nightly\nrustup update\nrustup target add thumbv7em-none-eabihf\n```\n\n5️⃣ Install [GNU Arm Embedded Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads) for Windows from Arm Developer Website…\n\nhttps://developer.arm.com/-/media/Files/downloads/gnu-rm/8-2019q3/RC1.1/gcc-arm-none-eabi-8-2019-q3-update-win32-sha1.exe?revision=fcadabed-d946-49dc-8f78-0732d2f43773?product=GNU%20Arm%20Embedded%20Toolchain,32-bit,,Windows,8-2019-q3-update\n\nSelect this option at the last install step:\n`\"Add path to environment variable\"`\n\n6️⃣ Install VSCode…\n\nhttps://code.visualstudio.com/\n\n## _[Windows]_ Edit The Visual Rust Application\n\n1️⃣ Launch VSCode\n\nClick `File → Open Folder`\n\nSelect the downloaded folder `pinetime-rust-mynewt` and click OK\n\nWhen prompted to open the workspace, click Open Workspace\n\nWhen prompted to install Extension Recommendations, click `Install All`\n\n2️⃣ Install the `Visual Embedded Rust` Extension...\n\nClick `View → Extensions`\n\nSearch for `Visual Embedded Rust`\n\nInstall the extension\n\n3️⃣ Enable the Visual Rust application...\n\nBrowse to `rust/app/Cargo.toml`\n\nModify the file such that `visual_app` is uncommented and the other options are commented out...\n\n```yaml\ndefault =  [          # Select the conditional compiled features\n    # \"display_app\",  # Disable graphics display app\n    # \"ui_app\",       # Disable druid UI app\n    \"visual_app\",     # Enable Visual Rust app\n    # \"use_float\",    # Disable floating-point for GPS geolocation\n]\n```\n\n4️⃣ Edit the Visual Rust application...\n\nBrowse to [`rust/app/src/visual.rs`](https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/rust/app/src/visual.rs)\n\nClick `Visual Editor` at top right\n\n![Click Visual Editor](images/install3.png)\n\nUse the Visual Editor to edit the Visual Rust application\n\n![Editing the Visual Rust application](images/animation.gif)\n\n5️⃣ After editing, save the [`visual.rs`](https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/rust/app/src/visual.rs) source file to save the visual program. Don't edit the Rust source file manually, always use the Visual Editor.\n\n## _[Windows]_ Build And Flash The Firmware\n\n1️⃣ At the lower left corner, there is a panel `Task Runner`. Click the panel to display the build and flash tasks.\n\n2️⃣ In the Task Runner, click `[1] Build Bootloader`\n\nWhen the Terminal Panel appears, right-click the `Terminal` tab, select `Move Panel Right`\n\nAfter the building the Bootloader, we should see `Done`\n\nIgnore the message `There Are Task Errors`\n\nThe Bootloader only needs to be built once.\n\n3️⃣ In the Task Runner, click `[2] Build Application`\n\nAfter the building the Application, we should see `Done`\n\nIf you see the message `Undefined Reference To Main`, click `[2] Build Application` again and it should succeed.\n\nThe Application needs to be rebuilt whenever a source file has been changed.\n\n__Note:__ When we run `Build Application`, the build script will overwrite the default `.vscode/launch.json` (meant for Raspberry Pi) with the correct version `.vscode/launch-nrf52.json` (meant for ST-Link on Windows and macOS)\n\n4️⃣ In the Task Runner, click `[3] Image Application`\n\nAfter the creating the Firmware Image, we should see `Done`\n\n5️⃣ In the Task Runner, click `[4] Flash Bootloader`\n\nAfter flashing the Bootloader Firmware to PineTime, we should see `Done`\n\n\n```\nFlashing Bootloader...\ntarget halted due to debug-request, current mode: Thread \nxPSR: 0x01000000 pc: 0x000000d8 msp: 0x20010000\nEnabled ARM Semihosting to show debug output\n** Programming Started **\nInfo : nRF52832-QFAA(build code: E1) 512kB Flash, 64kB RAM\nWarn : Adding extra erase range, 0x00000b78 .. 0x00000fff\n** Programming Finished **\n** Verify Started **\n** Verified OK **\n\nRestarting...\ntarget halted due to debug-request, current mode: Thread \nxPSR: 0x01000000 pc: 0x000000d8 msp: 0x20010000, semihosting\n\n**** Done!\n```\n\n_From https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/logs/load-bootloader-pi.log_\n\nThe Bootloader only needs to be flashed once.\n\n6️⃣ In the Task Runner, click `[5] Flash Application`\n\nAfter the flashing the Application Firmware to PineTime, we should see `Done! Press Ctrl-C To Exit`…\n\n```\nFlashing Application...\ntarget halted due to debug-request, current mode: Thread \nxPSR: 0x01000000 pc: 0x000000d8 msp: 0x20010000\nEnabled ARM Semihosting to show debug output\n** Programming Started **\nInfo : nRF52832-QFAA(build code: E1) 512kB Flash, 64kB RAM\nWarn : Adding extra erase range, 0x0003e820 .. 0x0003efff\n** Programming Finished **\n** Verify Started **\n** Verified OK **\n\nRestarting...\ntarget halted due to debug-request, current mode: Thread \nxPSR: 0x01000000 pc: 0x000000d8 msp: 0x20010000, semihosting\nEnabled ARM Semihosting to show debug output\n\n**** Done! Press Ctrl-C to exit...\n```\n\n_From https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/logs/load-application-pi.log_\n\n7️⃣ Our Visual Rust application starts running on PineTime\n\n![Demo](images/demo.gif)\n\n8️⃣ Click the Trash icon 🗑 near the top right to terminate the application. If we click the Close icon ❌ instead of the Trash icon, the next flash or debug command will fail.\n\n![Click the Trash icon, not the Close icon](images/trash-close.png)\n\n## _[Windows]_ Debug The Firmware\n\n1️⃣ Build the application: In the Task Runner, click `[2] Build Application`\n\nThe build script will also overwrite the default `.vscode/launch.json` (meant for Raspberry Pi) with the correct version `.vscode/launch-nrf52.json` (meant for ST-Link on Windows and macOS)\n\n2️⃣ Click `Debug → Start Debugging` or press `F5`\n\nThis starts the VSCode Debugger and automatically flashes our updated firmware to PineTime.\n\n3️⃣ Click `View → Output`\n\nIn the Output Panel, select `Adapter Output`\n\nThe debugging messages will be displayed here.\n\n4️⃣ The program has paused at first line of code in our firmware, the Reset Handler.\n\nIn the Debug Toolbar, click `Continue` or press `F5`\n\n![Continue](images/debug-bar-continue.png)\n\n🛈 [_What’s a Reset Handler? Read this_](https://gist.github.com/lupyuen/b0b7782f21330e292ea65b9c875bd9a7)\n\n5️⃣ The debugger now pauses at the first line of the main function that’s defined in rust/app/src/lib.rs\n\nThis is the first line of Rust code in our Rust Application, which will call test_display in a while.\n\nIn the Debug Toolbar, click Continue or press F5\n\n🛈 [_What’s a main function? Read this_](https://gist.github.com/lupyuen/5360769a2d92ec50d988cce92622abff)\n\n# TODO: Edit, Build and Debug the Visual Rust Application on macOS\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flupyuen%2Fvisual-embedded-rust","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flupyuen%2Fvisual-embedded-rust","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flupyuen%2Fvisual-embedded-rust/lists"}