Compare commits
1 commit
master
...
latest-hal
Author | SHA1 | Date | |
---|---|---|---|
ca9c9bae75 |
14 changed files with 53 additions and 43290 deletions
|
@ -1,5 +1,4 @@
|
||||||
[target.thumbv7em-none-eabihf]
|
[target.thumbv7em-none-eabihf]
|
||||||
runner = "arm-none-eabi-gdb -x openocd.gdb -q"
|
|
||||||
rustflags = [
|
rustflags = [
|
||||||
"-C", "link-arg=-Tfixed-link.x",
|
"-C", "link-arg=-Tfixed-link.x",
|
||||||
]
|
]
|
||||||
|
|
1
.vscode/.cortex-debug.peripherals.state.json
vendored
1
.vscode/.cortex-debug.peripherals.state.json
vendored
|
@ -1 +0,0 @@
|
||||||
[]
|
|
1
.vscode/.cortex-debug.registers.state.json
vendored
1
.vscode/.cortex-debug.registers.state.json
vendored
|
@ -1 +0,0 @@
|
||||||
[]
|
|
114
.vscode/launch.json
vendored
114
.vscode/launch.json
vendored
|
@ -1,114 +0,0 @@
|
||||||
{
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "PineTime Debug",
|
|
||||||
"device": "nRF52832",
|
|
||||||
"svdFile": ".vscode/nrf52.svd",
|
|
||||||
"cwd": "${workspaceRoot}",
|
|
||||||
"configFiles": [
|
|
||||||
// Tell OpenOCD to open the ST Link connection.
|
|
||||||
"scripts/swd-stlink.ocd",
|
|
||||||
// Tell OpenOCD to run our custom debug commands.
|
|
||||||
"scripts/debug.ocd"
|
|
||||||
],
|
|
||||||
"executable": "./target/thumbv7em-none-eabihf/debug/pinetime-rs",
|
|
||||||
"request": "launch",
|
|
||||||
"type": "cortex-debug",
|
|
||||||
"servertype": "openocd",
|
|
||||||
"preLaunchCommands": [
|
|
||||||
// Before loading the Application, run these gdb commands.
|
|
||||||
// Set timeout for executing openocd commands.
|
|
||||||
"set remotetimeout 60",
|
|
||||||
|
|
||||||
// This indicates that an unrecognized breakpoint location should automatically result in a pending breakpoint being created.
|
|
||||||
"set breakpoint pending on",
|
|
||||||
|
|
||||||
// Display the Arm instruction when hitting breakpoint.
|
|
||||||
// "display/i $pc",
|
|
||||||
|
|
||||||
// Load Bootloader symbols in case we jump to the Bootloader.
|
|
||||||
// "symbol-file bin/targets/bluepill_boot/app/apps/boot/boot.elf",
|
|
||||||
|
|
||||||
// Restore Application symbols.
|
|
||||||
// "symbol-file bin/targets/bluepill_my_sensor/app/apps/my_sensor_app/my_sensor_app.elf",
|
|
||||||
"monitor arm semihosting enable"
|
|
||||||
],
|
|
||||||
"postLaunchCommands": [
|
|
||||||
// After loading the Application, run these gdb commands. The Application ELF image does not contain a valid Image Header.
|
|
||||||
// If not using the Stub Bootloader boot_stub, we need to bypass the Bootloader and jump to the Application directly:
|
|
||||||
// "stepi", // Must step before setting PC
|
|
||||||
// "set $pc = Reset_Handler", // Prepare to jump to the Application's Reset Handler
|
|
||||||
// "stepi", // Execute the Reset Handler
|
|
||||||
//"break main", // Break at main()
|
|
||||||
"break __assert_func", // Break for any assert failures
|
|
||||||
"break os_default_irq", // Break for any unhandled interrupts
|
|
||||||
"break HardFault",
|
|
||||||
"break rust_begin_unwind"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "PineTime Debug Release",
|
|
||||||
"device": "nRF52832",
|
|
||||||
"svdFile": ".vscode/nrf52.svd",
|
|
||||||
"cwd": "${workspaceRoot}",
|
|
||||||
"configFiles": [
|
|
||||||
// Tell OpenOCD to open the ST Link connection.
|
|
||||||
"scripts/swd-stlink.ocd",
|
|
||||||
// Tell OpenOCD to run our custom debug commands.
|
|
||||||
"scripts/debug.ocd"
|
|
||||||
],
|
|
||||||
"executable": "./target/thumbv7em-none-eabihf/release/pinetime-rs",
|
|
||||||
"request": "launch",
|
|
||||||
"type": "cortex-debug",
|
|
||||||
"servertype": "openocd",
|
|
||||||
// "swoConfig": {
|
|
||||||
// "enabled": true,
|
|
||||||
// "cpuFrequency": 16000000,
|
|
||||||
// "swoFrequency": 2000000,
|
|
||||||
// "source": "probe",
|
|
||||||
// "decoders": [
|
|
||||||
// {
|
|
||||||
// "type": "console",
|
|
||||||
// "label": "ITM",
|
|
||||||
// "port": 0
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
"preLaunchCommands": [
|
|
||||||
// Before loading the Application, run these gdb commands.
|
|
||||||
// Set timeout for executing openocd commands.
|
|
||||||
"set remotetimeout 60",
|
|
||||||
|
|
||||||
// This indicates that an unrecognized breakpoint location should automatically result in a pending breakpoint being created.
|
|
||||||
"set breakpoint pending on",
|
|
||||||
|
|
||||||
// Display the Arm instruction when hitting breakpoint.
|
|
||||||
// "display/i $pc",
|
|
||||||
|
|
||||||
// Load Bootloader symbols in case we jump to the Bootloader.
|
|
||||||
// "symbol-file bin/targets/bluepill_boot/app/apps/boot/boot.elf",
|
|
||||||
|
|
||||||
// Restore Application symbols.
|
|
||||||
// "symbol-file bin/targets/bluepill_my_sensor/app/apps/my_sensor_app/my_sensor_app.elf",
|
|
||||||
"set print asm-demangle on",
|
|
||||||
//"monitor semihosting ioclient 3",
|
|
||||||
"monitor arm semihosting enable"
|
|
||||||
],
|
|
||||||
"postLaunchCommands": [
|
|
||||||
// After loading the Application, run these gdb commands. The Application ELF image does not contain a valid Image Header.
|
|
||||||
// If not using the Stub Bootloader boot_stub, we need to bypass the Bootloader and jump to the Application directly:
|
|
||||||
// "stepi", // Must step before setting PC
|
|
||||||
// "set $pc = Reset_Handler", // Prepare to jump to the Application's Reset Handler
|
|
||||||
// "stepi", // Execute the Reset Handler
|
|
||||||
//"break main", // Break at main()
|
|
||||||
"break __assert_func", // Break for any assert failures
|
|
||||||
"break os_default_irq", // Break for any unhandled interrupts
|
|
||||||
"break HardFault"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
42660
.vscode/nrf52.svd
vendored
42660
.vscode/nrf52.svd
vendored
File diff suppressed because it is too large
Load diff
41
.vscode/tasks.json
vendored
41
.vscode/tasks.json
vendored
|
@ -1,41 +0,0 @@
|
||||||
{
|
|
||||||
"version": "2.0.0",
|
|
||||||
"tasks": [
|
|
||||||
{
|
|
||||||
"label": "cargo release",
|
|
||||||
"type": "shell",
|
|
||||||
"problemMatcher": [
|
|
||||||
"$rustc"
|
|
||||||
],
|
|
||||||
"command": "cargo",
|
|
||||||
"args": [
|
|
||||||
"build",
|
|
||||||
"--release",
|
|
||||||
"-Zfeatures=build_dep"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "flash release",
|
|
||||||
"type": "shell",
|
|
||||||
"problemMatcher": [
|
|
||||||
"$rustc"
|
|
||||||
],
|
|
||||||
"command": "cargo",
|
|
||||||
"args": [
|
|
||||||
"embed",
|
|
||||||
"--release"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "flash debug",
|
|
||||||
"type": "shell",
|
|
||||||
"problemMatcher": [
|
|
||||||
"$rustc"
|
|
||||||
],
|
|
||||||
"command": "cargo",
|
|
||||||
"args": [
|
|
||||||
"embed"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
77
Cargo.lock
generated
77
Cargo.lock
generated
|
@ -59,6 +59,12 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bare-metal"
|
name = "bare-metal"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
|
@ -98,12 +104,6 @@ version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "byte-slice-cast"
|
|
||||||
version = "0.3.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.3.4"
|
version = "1.3.4"
|
||||||
|
@ -198,18 +198,11 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cortex-m-semihosting"
|
|
||||||
version = "0.3.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "113ef0ecffee2b62b58f9380f4469099b30e9f9cbee2804771b4203ba1762cfa"
|
|
||||||
dependencies = [
|
|
||||||
"cortex-m",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cst816s"
|
name = "cst816s"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "988624bfaeaa34565792f7badc33cd02e84ba51fff4bbc3cd76f59d4af5658e7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cortex-m",
|
"cortex-m",
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
|
@ -231,23 +224,6 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7313c0d620d0cb4dbd9d019e461a4beb501071ff46ec0ab933efb4daa76d73e3"
|
checksum = "7313c0d620d0cb4dbd9d019e461a4beb501071ff46ec0ab933efb4daa76d73e3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "display-interface"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da12a892db5cce95ae247e8803dc653b1a73da3b0450f7983eb518dd54f583cf"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "display-interface-spi"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "94d08c3a1682b166cbcbb4fe009a31a1834ba46c16599bf7a9b3cc7bc31b38b0"
|
|
||||||
dependencies = [
|
|
||||||
"byte-slice-cast",
|
|
||||||
"display-interface",
|
|
||||||
"embedded-hal",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embedded-graphics"
|
name = "embedded-graphics"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
|
@ -490,18 +466,32 @@ dependencies = [
|
||||||
"vcell",
|
"vcell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-derive"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c8b15b261814f992e33760b1fca9fe8b693d8a65299f20c9901688636cfb746"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "numtoa"
|
name = "numtoa"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e521b6adefa0b2c1fa5d2abdf9a5216288686fe6146249215d884c0e5ab320b0"
|
checksum = "e521b6adefa0b2c1fa5d2abdf9a5216288686fe6146249215d884c0e5ab320b0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "panic-halt"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "peeking_take_while"
|
name = "peeking_take_while"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
@ -514,17 +504,13 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cortex-m",
|
"cortex-m",
|
||||||
"cortex-m-rt",
|
"cortex-m-rt",
|
||||||
"cortex-m-semihosting",
|
|
||||||
"cst816s",
|
"cst816s",
|
||||||
"cstr_core",
|
"cstr_core",
|
||||||
"display-interface",
|
|
||||||
"display-interface-spi",
|
|
||||||
"embedded-graphics",
|
"embedded-graphics",
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
"lvgl",
|
"lvgl",
|
||||||
"nrf52832-hal",
|
"nrf52832-hal",
|
||||||
"numtoa",
|
"numtoa",
|
||||||
"panic-halt",
|
|
||||||
"st7789",
|
"st7789",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -620,15 +606,16 @@ checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "st7789"
|
name = "st7789"
|
||||||
version = "0.5.0"
|
version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a9f2a309b876ab3ac011a437624b439ec22387db20c86e024b5aae8090428623"
|
checksum = "5ccc7b7e79f9e578e981bfab45b502b72ca02717a4356df0478228a6ff7c47c4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"display-interface",
|
|
||||||
"embedded-graphics",
|
"embedded-graphics",
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
"heapless",
|
"heapless",
|
||||||
"nb",
|
"nb",
|
||||||
|
"num-derive",
|
||||||
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -8,17 +8,13 @@ license = "BSD-3-Clause"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cortex-m = "0.6"
|
cortex-m = "0.6"
|
||||||
cortex-m-rt = "0.6"
|
cortex-m-rt = "0.6"
|
||||||
cortex-m-semihosting = "0.3.5"
|
|
||||||
embedded-graphics = "0.6"
|
embedded-graphics = "0.6"
|
||||||
embedded-hal = {version ="0.2.3", features = ["unproven"] }
|
embedded-hal = {version ="0.2.3", features = ["unproven"] }
|
||||||
nrf52832-hal = { version = "0.10", default-features = false, features = ["xxAA-package", "rt"] }
|
nrf52832-hal = { version = "0.10", default-features = false, features = ["xxAA-package", "rt"] }
|
||||||
st7789 = { version = "0.5.0", features = ["graphics", "batch", "buffer"], default-features = false }
|
st7789 = { version = "0.2", features = ["graphics", "batch", "buffer"], default-features = false }
|
||||||
display-interface = "0.4"
|
|
||||||
display-interface-spi = "0.4"
|
|
||||||
panic-halt = "0.2.0"
|
|
||||||
cstr_core = "0.2.0"
|
cstr_core = "0.2.0"
|
||||||
numtoa = "0.2.3"
|
numtoa = "0.2.3"
|
||||||
cst816s = { path = "../cst816s" }
|
cst816s = "0.1.4"
|
||||||
lvgl = { path = "../lvgl-rs/lvgl" }
|
lvgl = { path = "../lvgl-rs/lvgl" }
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
|
|
49
openocd.gdb
49
openocd.gdb
|
@ -1,49 +0,0 @@
|
||||||
target extended-remote :3333
|
|
||||||
|
|
||||||
# print demangled symbols
|
|
||||||
set print asm-demangle on
|
|
||||||
|
|
||||||
# set backtrace limit to not have infinite backtrace loops
|
|
||||||
set backtrace limit 32
|
|
||||||
|
|
||||||
# detect unhandled exceptions, hard faults and panics
|
|
||||||
#break DefaultHandler
|
|
||||||
break HardFault
|
|
||||||
break rust_begin_unwind
|
|
||||||
#break panic
|
|
||||||
# # run the next few lines so the panic message is printed immediately
|
|
||||||
# # the number needs to be adjusted for your panic handler
|
|
||||||
# commands $bpnum
|
|
||||||
# next 4
|
|
||||||
# end
|
|
||||||
|
|
||||||
# *try* to stop at the user entry point (it might be gone due to inlining)
|
|
||||||
# break main
|
|
||||||
|
|
||||||
monitor arm semihosting enable
|
|
||||||
|
|
||||||
# # send captured ITM to the file itm.fifo
|
|
||||||
# # (the microcontroller SWO pin must be connected to the programmer SWO pin)
|
|
||||||
# # 8000000 must match the core clock frequency
|
|
||||||
# monitor tpiu config internal itm.txt uart off 8000000
|
|
||||||
|
|
||||||
# # OR: make the microcontroller SWO pin output compatible with UART (8N1)
|
|
||||||
# # 8000000 must match the core clock frequency
|
|
||||||
# # 2000000 is the frequency of the SWO pin
|
|
||||||
# monitor tpiu config external uart off 8000000 2000000
|
|
||||||
|
|
||||||
# # enable ITM port 0
|
|
||||||
# monitor itm port 0 on
|
|
||||||
|
|
||||||
# don't confirm when quitting debugger
|
|
||||||
define hook-quit
|
|
||||||
set confirm off
|
|
||||||
end
|
|
||||||
|
|
||||||
load
|
|
||||||
#monitor reset halt
|
|
||||||
|
|
||||||
# start the process but immediately halt the processor
|
|
||||||
# stepi
|
|
||||||
|
|
||||||
continue
|
|
|
@ -1,10 +0,0 @@
|
||||||
# This is an OpenOCD script that connects to the nRF52 for Cortex Debug.
|
|
||||||
|
|
||||||
# Debug Level must be 2 or greater or gdb will fail.
|
|
||||||
debug_level 2
|
|
||||||
|
|
||||||
$_TARGETNAME configure -event reset-init {
|
|
||||||
# Arm Semihosting is used to show debug console output and may only be enabled after init event. We wait for the event and enable Arm Semihosting.
|
|
||||||
echo "Enable ARM Semihosting to show debug output"
|
|
||||||
arm semihosting enable
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
# This is an OpenOCD script that prepares the microcontroller before any flashing.
|
|
||||||
|
|
||||||
# Disable all openocd messages.
|
|
||||||
debug_level 0
|
|
|
@ -1,14 +0,0 @@
|
||||||
# OpenOCD script for using ST-Link v2 as SWD Programmer for nRF52
|
|
||||||
|
|
||||||
# VSCode debugger searches this folder for OpenOCD scripts
|
|
||||||
add_script_search_dir openocd/scripts
|
|
||||||
|
|
||||||
# Set OpenOCD logging
|
|
||||||
source [find scripts/flash-init.ocd]
|
|
||||||
|
|
||||||
# Select the ST-Link v2 interface (SWD transport)
|
|
||||||
source [find interface/stlink-v2.cfg]
|
|
||||||
transport select hla_swd
|
|
||||||
|
|
||||||
# Select nRF52 as target
|
|
||||||
source [find target/nrf52.cfg]
|
|
80
src/main.rs
80
src/main.rs
|
@ -1,18 +1,14 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
extern crate panic_halt;
|
|
||||||
|
|
||||||
mod backlight;
|
mod backlight;
|
||||||
mod delay;
|
mod delay;
|
||||||
mod monotonic_nrf52;
|
|
||||||
|
|
||||||
use nrf52832_hal::gpio::Level;
|
use nrf52832_hal::gpio::Level;
|
||||||
use nrf52832_hal::{self as p_hal, pac};
|
use nrf52832_hal::{self as p_hal, pac};
|
||||||
use p_hal::{delay::Delay, spim, twim};
|
use p_hal::{delay::Delay, spim, twim};
|
||||||
|
|
||||||
use cortex_m_rt as rt;
|
use cortex_m_rt as rt;
|
||||||
use cortex_m_semihosting::hprintln;
|
|
||||||
use cst816s::CST816S;
|
use cst816s::CST816S;
|
||||||
use cstr_core::CStr;
|
use cstr_core::CStr;
|
||||||
use embedded_graphics::prelude::*;
|
use embedded_graphics::prelude::*;
|
||||||
|
@ -20,25 +16,21 @@ use embedded_hal::blocking::delay::{DelayMs, DelayUs};
|
||||||
use embedded_hal::digital::v2::OutputPin;
|
use embedded_hal::digital::v2::OutputPin;
|
||||||
use numtoa::NumToA;
|
use numtoa::NumToA;
|
||||||
use rt::entry;
|
use rt::entry;
|
||||||
use st7789::{Orientation, ST7789};
|
use st7789::Orientation;
|
||||||
|
|
||||||
use lvgl::input_device::{InputData, Pointer};
|
use lvgl::input_device::{InputData, Pointer};
|
||||||
use lvgl::style::Style;
|
use lvgl::style::Style;
|
||||||
use lvgl::widgets::{Btn, Label};
|
use lvgl::widgets::{Btn, Label};
|
||||||
use lvgl::{self, Align, Color, Part, State, Widget, UI};
|
use lvgl::{self, Align, Color, Part, State, Widget, UI};
|
||||||
|
|
||||||
use crate::monotonic_nrf52::Instant;
|
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
use display_interface_spi::SPIInterfaceNoCS;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// This example was written and tested for the PineTime smart watch
|
/// This example was written and tested for the PineTime smart watch
|
||||||
///
|
///
|
||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
hprintln!("\nStarting...").unwrap();
|
|
||||||
|
|
||||||
let cp = pac::CorePeripherals::take().unwrap();
|
let cp = pac::CorePeripherals::take().unwrap();
|
||||||
let mut delay_source = Delay::new(cp.SYST);
|
let mut delay_source = Delay::new(cp.SYST);
|
||||||
|
|
||||||
|
@ -46,14 +38,12 @@ fn main() -> ! {
|
||||||
// Optimize clock config
|
// Optimize clock config
|
||||||
let dp = pac::Peripherals::take().unwrap();
|
let dp = pac::Peripherals::take().unwrap();
|
||||||
|
|
||||||
//let lcd_delay = delay::TimerDelay::new(dp.TIMER0);
|
let lcd_delay = delay::TimerDelay::new(dp.TIMER0);
|
||||||
|
|
||||||
// Initialize monotonic timer on TIMER1 (for RTFM)
|
|
||||||
monotonic_nrf52::Tim1::initialize(dp.TIMER1);
|
|
||||||
|
|
||||||
// Set up clocks. On reset, the high frequency clock is already used,
|
// Set up clocks. On reset, the high frequency clock is already used,
|
||||||
// but we also need to switch to the external HF oscillator. This is
|
// but we also need to switch to the external HF oscillator. This is
|
||||||
// needed for Bluetooth to work.
|
// needed for Bluetooth to work.
|
||||||
|
|
||||||
let _clocks = p_hal::clocks::Clocks::new(dp.CLOCK).enable_ext_hfosc();
|
let _clocks = p_hal::clocks::Clocks::new(dp.CLOCK).enable_ext_hfosc();
|
||||||
|
|
||||||
let gpio = p_hal::gpio::p0::Parts::new(dp.P0);
|
let gpio = p_hal::gpio::p0::Parts::new(dp.P0);
|
||||||
|
@ -61,9 +51,10 @@ fn main() -> ! {
|
||||||
// Set up SPI pins
|
// Set up SPI pins
|
||||||
let spi_clk = gpio.p0_02.into_push_pull_output(Level::Low).degrade();
|
let spi_clk = gpio.p0_02.into_push_pull_output(Level::Low).degrade();
|
||||||
let spi_mosi = gpio.p0_03.into_push_pull_output(Level::Low).degrade();
|
let spi_mosi = gpio.p0_03.into_push_pull_output(Level::Low).degrade();
|
||||||
|
let spi_miso = gpio.p0_04.into_floating_input().degrade();
|
||||||
let spi_pins = spim::Pins {
|
let spi_pins = spim::Pins {
|
||||||
sck: spi_clk,
|
sck: spi_clk,
|
||||||
miso: None,
|
miso: Some(spi_miso),
|
||||||
mosi: Some(spi_mosi),
|
mosi: Some(spi_mosi),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -111,12 +102,9 @@ fn main() -> ! {
|
||||||
spim::Frequency::M8,
|
spim::Frequency::M8,
|
||||||
// SPI must be used in mode 3. Mode 0 (the default) won't work.
|
// SPI must be used in mode 3. Mode 0 (the default) won't work.
|
||||||
spim::MODE_3,
|
spim::MODE_3,
|
||||||
122,
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
// display interface abstraction from SPI and DC
|
|
||||||
let di = SPIInterfaceNoCS::new(spi, lcd_dc);
|
|
||||||
|
|
||||||
// Chip select must be held low while driving the display. It must be high
|
// Chip select must be held low while driving the display. It must be high
|
||||||
// when using other SPI devices on the same bus (such as external flash
|
// when using other SPI devices on the same bus (such as external flash
|
||||||
// storage) so that the display controller won't respond to the wrong
|
// storage) so that the display controller won't respond to the wrong
|
||||||
|
@ -124,17 +112,17 @@ fn main() -> ! {
|
||||||
lcd_cs.set_low().unwrap();
|
lcd_cs.set_low().unwrap();
|
||||||
|
|
||||||
// Initialize LCD
|
// Initialize LCD
|
||||||
let mut lcd = ST7789::new(
|
let mut lcd = st7789::ST7789::new(
|
||||||
di,
|
spi,
|
||||||
|
lcd_dc,
|
||||||
lcd_rst,
|
lcd_rst,
|
||||||
lvgl::HOR_RES_MAX as u16,
|
lvgl::HOR_RES_MAX as u16,
|
||||||
lvgl::VER_RES_MAX as u16,
|
lvgl::VER_RES_MAX as u16,
|
||||||
|
lcd_delay,
|
||||||
);
|
);
|
||||||
|
|
||||||
lcd.init(&mut delay_source).unwrap();
|
lcd.init().unwrap();
|
||||||
lcd.set_orientation(Orientation::Portrait).unwrap();
|
lcd.set_orientation(&Orientation::Portrait).unwrap();
|
||||||
|
|
||||||
hprintln!("\nAll devices set!").unwrap();
|
|
||||||
|
|
||||||
// Initialize LVGL
|
// Initialize LVGL
|
||||||
let mut ui = UI::init().unwrap();
|
let mut ui = UI::init().unwrap();
|
||||||
|
@ -187,17 +175,7 @@ fn main() -> ! {
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut loop_time = Instant::now();
|
|
||||||
let mut total_time = Duration::from_secs(0);
|
|
||||||
let mut time_text_buf = [0u8; 20];
|
|
||||||
|
|
||||||
let mut last_update_time_secs = 0;
|
|
||||||
let mut last_inc_time_ms = 0;
|
|
||||||
|
|
||||||
hprintln!("\nLVGL widgets built!").unwrap();
|
|
||||||
loop {
|
loop {
|
||||||
ui.task_handler();
|
|
||||||
|
|
||||||
if let Some(evt) = touchpad.read_one_touch_event(true) {
|
if let Some(evt) = touchpad.read_one_touch_event(true) {
|
||||||
latest_touch_point = Point::new(evt.x, evt.y);
|
latest_touch_point = Point::new(evt.x, evt.y);
|
||||||
// Pressed
|
// Pressed
|
||||||
|
@ -211,32 +189,12 @@ fn main() -> ! {
|
||||||
.once();
|
.once();
|
||||||
delay_source.delay_us(1u32);
|
delay_source.delay_us(1u32);
|
||||||
}
|
}
|
||||||
|
ui.task_handler();
|
||||||
total_time += Duration::from_micros(loop_time.elapsed().as_cycles() as u64);
|
ui.tick_inc(Duration::from_secs(1));
|
||||||
|
|
||||||
if total_time.as_secs() > last_update_time_secs {
|
|
||||||
last_update_time_secs = total_time.as_secs();
|
|
||||||
|
|
||||||
let text = (total_time.as_secs() as u32).numtoa(10, &mut time_text_buf);
|
|
||||||
|
|
||||||
let time_text = unsafe { CStr::from_bytes_with_nul_unchecked(&text) };
|
|
||||||
time_lbl.set_text(time_text).unwrap();
|
|
||||||
time_lbl
|
|
||||||
.set_align(&mut button, Align::OutTopMid, 0, -50)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Reset buffer
|
|
||||||
for p in time_text_buf.iter_mut() {
|
|
||||||
*p = '\0' as u8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if total_time.as_millis() > last_inc_time_ms {
|
|
||||||
//let diff_ms = total_time.as_millis() - last_inc_time_ms;
|
|
||||||
last_inc_time_ms = total_time.as_millis();
|
|
||||||
}
|
|
||||||
ui.tick_inc(Duration::from_millis(50));
|
|
||||||
|
|
||||||
loop_time = Instant::now();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(_info: &PanicInfo) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
|
@ -1,283 +0,0 @@
|
||||||
//! Using NRF52 as monotonic timer
|
|
||||||
//!
|
|
||||||
//! Source:
|
|
||||||
//! https://github.com/rtfm-rs/rtfm-examples/blob/master/rtfm_v5/monotonic_nrf52/src/monotonic_nrf52.rs
|
|
||||||
|
|
||||||
use core::u32;
|
|
||||||
use core::{
|
|
||||||
cmp::Ordering,
|
|
||||||
convert::{Infallible, TryInto},
|
|
||||||
fmt, ops,
|
|
||||||
};
|
|
||||||
use nrf52832_hal::target;
|
|
||||||
|
|
||||||
/// A measurement of the counter. Opaque and useful only with `Duration`
|
|
||||||
///
|
|
||||||
/// # Correctness
|
|
||||||
///
|
|
||||||
/// Adding or subtracting a `Duration` of more than `(1 << 31)` cycles to an `Instant` effectively
|
|
||||||
/// makes it "wrap around" and creates an incorrect value. This is also true if the operation is
|
|
||||||
/// done in steps, e.g. `(instant + dur) + dur` where `dur` is `(1 << 30)` ticks.
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
|
||||||
pub struct Instant {
|
|
||||||
inner: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Instant {
|
|
||||||
/// Returns an instant corresponding to "now"
|
|
||||||
pub fn now() -> Self {
|
|
||||||
let now = {
|
|
||||||
let timer = unsafe { &*target::TIMER1::ptr() };
|
|
||||||
timer.tasks_capture[0].write(|w| unsafe { w.bits(1) });
|
|
||||||
timer.cc[0].read().bits()
|
|
||||||
};
|
|
||||||
|
|
||||||
Instant { inner: now as i32 }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the amount of time elapsed since this instant was created.
|
|
||||||
pub fn elapsed(&self) -> Duration {
|
|
||||||
Instant::now() - *self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the underlying count
|
|
||||||
pub fn counts(&self) -> u32 {
|
|
||||||
self.inner as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the amount of time elapsed from another instant to this one.
|
|
||||||
pub fn duration_since(&self, earlier: Instant) -> Duration {
|
|
||||||
let diff = self.inner - earlier.inner;
|
|
||||||
assert!(diff >= 0, "second instant is later than self");
|
|
||||||
Duration { inner: diff as u32 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Instant {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_tuple("Instant")
|
|
||||||
.field(&(self.inner as u32))
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ops::AddAssign<Duration> for Instant {
|
|
||||||
fn add_assign(&mut self, dur: Duration) {
|
|
||||||
// NOTE this is a debug assertion because there's no foolproof way to detect a wrap around;
|
|
||||||
// the user may write `(instant + dur) + dur` where `dur` is `(1<<31)-1` ticks.
|
|
||||||
debug_assert!(dur.inner < (1 << 31));
|
|
||||||
self.inner = self.inner.wrapping_add(dur.inner as i32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ops::Add<Duration> for Instant {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn add(mut self, dur: Duration) -> Self {
|
|
||||||
self += dur;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ops::SubAssign<Duration> for Instant {
|
|
||||||
fn sub_assign(&mut self, dur: Duration) {
|
|
||||||
// NOTE see the NOTE in `<Instant as AddAssign<Duration>>::add_assign`
|
|
||||||
debug_assert!(dur.inner < (1 << 31));
|
|
||||||
self.inner = self.inner.wrapping_sub(dur.inner as i32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ops::Sub<Duration> for Instant {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn sub(mut self, dur: Duration) -> Self {
|
|
||||||
self -= dur;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ops::Sub<Instant> for Instant {
|
|
||||||
type Output = Duration;
|
|
||||||
|
|
||||||
fn sub(self, other: Instant) -> Duration {
|
|
||||||
self.duration_since(other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for Instant {
|
|
||||||
fn cmp(&self, rhs: &Self) -> Ordering {
|
|
||||||
self.inner.wrapping_sub(rhs.inner).cmp(&0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for Instant {
|
|
||||||
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(rhs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A `Duration` type to represent a span of time.
|
|
||||||
///
|
|
||||||
/// This data type is only available on ARMv7-M
|
|
||||||
///
|
|
||||||
/// # Correctness
|
|
||||||
///
|
|
||||||
/// This type is *not* appropriate for representing time spans in the order of, or larger than,
|
|
||||||
/// seconds because it can hold a maximum of `(1 << 31)` "ticks" where each tick is the inverse of
|
|
||||||
/// the CPU frequency, which usually is dozens of MHz.
|
|
||||||
#[derive(Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd)]
|
|
||||||
pub struct Duration {
|
|
||||||
inner: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Duration {
|
|
||||||
/// Creates a new `Duration` from the specified number of clock cycles
|
|
||||||
pub fn from_cycles(cycles: u32) -> Self {
|
|
||||||
Duration { inner: cycles }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total number of clock cycles contained by this `Duration`
|
|
||||||
pub fn as_cycles(&self) -> u32 {
|
|
||||||
self.inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used internally by RTFM to convert the duration into a known type
|
|
||||||
impl TryInto<u32> for Duration {
|
|
||||||
type Error = Infallible;
|
|
||||||
|
|
||||||
fn try_into(self) -> Result<u32, Infallible> {
|
|
||||||
Ok(self.as_cycles())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ops::AddAssign for Duration {
|
|
||||||
fn add_assign(&mut self, dur: Duration) {
|
|
||||||
self.inner += dur.inner;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ops::Add<Duration> for Duration {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn add(self, other: Self) -> Self {
|
|
||||||
Duration {
|
|
||||||
inner: self.inner + other.inner,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ops::Mul<u32> for Duration {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn mul(self, other: u32) -> Self {
|
|
||||||
Duration {
|
|
||||||
inner: self.inner * other,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ops::MulAssign<u32> for Duration {
|
|
||||||
fn mul_assign(&mut self, other: u32) {
|
|
||||||
*self = *self * other;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ops::SubAssign for Duration {
|
|
||||||
fn sub_assign(&mut self, rhs: Duration) {
|
|
||||||
self.inner -= rhs.inner;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ops::Sub<Duration> for Duration {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn sub(self, rhs: Self) -> Self {
|
|
||||||
Duration {
|
|
||||||
inner: self.inner - rhs.inner,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds the `millis` and `micros` methods to the `u32` type
|
|
||||||
///
|
|
||||||
/// This trait is only available on ARMv7-M
|
|
||||||
pub trait U32Ext {
|
|
||||||
/// Converts the `u32` value as seconds into ticks
|
|
||||||
fn secs(self) -> Duration;
|
|
||||||
|
|
||||||
/// Converts the `u32` value as milliseconds into ticks
|
|
||||||
fn millis(self) -> Duration;
|
|
||||||
|
|
||||||
/// Converts the `u32` value as microseconds into ticks
|
|
||||||
fn micros(self) -> Duration;
|
|
||||||
|
|
||||||
/// Converts the `u32` value as hertz into ticks
|
|
||||||
fn hz(self) -> Duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl U32Ext for u32 {
|
|
||||||
fn secs(self) -> Duration {
|
|
||||||
self.millis() * 1_000
|
|
||||||
}
|
|
||||||
|
|
||||||
fn millis(self) -> Duration {
|
|
||||||
self.micros() * 1_000
|
|
||||||
}
|
|
||||||
|
|
||||||
fn micros(self) -> Duration {
|
|
||||||
Duration { inner: self }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hz(self) -> Duration {
|
|
||||||
(1_000_000 / self).micros()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implementor of the `rtfm::Monotonic` traits and used to consume the timer
|
|
||||||
/// to not allow for erroneous configuration.
|
|
||||||
///
|
|
||||||
/// The timer must be initialized through `initialize()`.
|
|
||||||
pub struct Tim1;
|
|
||||||
|
|
||||||
impl Tim1 {
|
|
||||||
pub fn initialize(timer: target::TIMER1) {
|
|
||||||
// Auto restart, make sure the entire timer won't stop for any event
|
|
||||||
timer.shorts.write(|w| {
|
|
||||||
w.compare0_clear()
|
|
||||||
.enabled()
|
|
||||||
.compare0_stop()
|
|
||||||
.disabled()
|
|
||||||
.compare1_clear()
|
|
||||||
.enabled()
|
|
||||||
.compare1_stop()
|
|
||||||
.disabled()
|
|
||||||
.compare2_clear()
|
|
||||||
.enabled()
|
|
||||||
.compare2_stop()
|
|
||||||
.disabled()
|
|
||||||
.compare3_clear()
|
|
||||||
.enabled()
|
|
||||||
.compare3_stop()
|
|
||||||
.disabled()
|
|
||||||
});
|
|
||||||
|
|
||||||
// 1 MHz mode
|
|
||||||
timer.prescaler.write(|w| unsafe { w.prescaler().bits(4) });
|
|
||||||
|
|
||||||
// 32 bit mode
|
|
||||||
timer.bitmode.write(|w| w.bitmode()._32bit());
|
|
||||||
|
|
||||||
// Set compare value to max, not sure if this is needed
|
|
||||||
timer.cc[0].write(|w| unsafe { w.cc().bits(u32::MAX) });
|
|
||||||
|
|
||||||
// Clear the counter value
|
|
||||||
timer.tasks_clear.write(|w| unsafe { w.bits(1) });
|
|
||||||
|
|
||||||
// Start the timer
|
|
||||||
timer.tasks_start.write(|w| unsafe { w.bits(1) });
|
|
||||||
|
|
||||||
// Throw away the timer, it is now setup and consumed
|
|
||||||
drop(timer);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue