diff --git a/k5viewer/README.md b/tools/k5viewer/README.md similarity index 100% rename from k5viewer/README.md rename to tools/k5viewer/README.md diff --git a/k5viewer/k5viewer.py b/tools/k5viewer/k5viewer.py similarity index 100% rename from k5viewer/k5viewer.py rename to tools/k5viewer/k5viewer.py diff --git a/utils/clean.bat b/tools/misc/clean.bat similarity index 100% rename from utils/clean.bat rename to tools/misc/clean.bat diff --git a/utils/main.cpp b/tools/misc/main.cpp similarity index 100% rename from utils/main.cpp rename to tools/misc/main.cpp diff --git a/utils/misc.bpf b/tools/misc/misc.bpf similarity index 100% rename from utils/misc.bpf rename to tools/misc/misc.bpf diff --git a/utils/misc.bpr b/tools/misc/misc.bpr similarity index 100% rename from utils/misc.bpr rename to tools/misc/misc.bpr diff --git a/utils/misc.exe b/tools/misc/misc.exe similarity index 100% rename from utils/misc.exe rename to tools/misc/misc.exe diff --git a/utils/misc.res b/tools/misc/misc.res similarity index 100% rename from utils/misc.res rename to tools/misc/misc.res diff --git a/utils/uv-k5_small.bin b/tools/misc/uv-k5_small.bin similarity index 100% rename from utils/uv-k5_small.bin rename to tools/misc/uv-k5_small.bin diff --git a/utils/uv-k5_small.fon b/tools/misc/uv-k5_small.fon similarity index 100% rename from utils/uv-k5_small.fon rename to tools/misc/uv-k5_small.fon diff --git a/utils/uv-k5_small_bold.bin b/tools/misc/uv-k5_small_bold.bin similarity index 100% rename from utils/uv-k5_small_bold.bin rename to tools/misc/uv-k5_small_bold.bin diff --git a/utils/uv-k5_small_bold.fon b/tools/misc/uv-k5_small_bold.fon similarity index 100% rename from utils/uv-k5_small_bold.fon rename to tools/misc/uv-k5_small_bold.fon diff --git a/serialtool/__init__.py b/tools/serialtool/__init__.py similarity index 100% rename from serialtool/__init__.py rename to tools/serialtool/__init__.py diff --git a/serialtool/_dump.py b/tools/serialtool/_dump.py similarity index 100% rename from serialtool/_dump.py rename to tools/serialtool/_dump.py diff --git a/serialtool/_prog.py b/tools/serialtool/_prog.py similarity index 100% rename from serialtool/_prog.py rename to tools/serialtool/_prog.py diff --git a/serialtool/_restore.py b/tools/serialtool/_restore.py similarity index 100% rename from serialtool/_restore.py rename to tools/serialtool/_restore.py diff --git a/serialtool/cli.py b/tools/serialtool/cli.py similarity index 100% rename from serialtool/cli.py rename to tools/serialtool/cli.py diff --git a/serialtool/msg.py b/tools/serialtool/msg.py similarity index 100% rename from serialtool/msg.py rename to tools/serialtool/msg.py diff --git a/tools/unbrick_k5_v1/README.md b/tools/unbrick_k5_v1/README.md new file mode 100644 index 00000000..738aae4f --- /dev/null +++ b/tools/unbrick_k5_v1/README.md @@ -0,0 +1,119 @@ +# Unbricking the UV-K5 V1 + +pcbite + +Restoring a UV-K5 V1 accidentally flashed with the F4HWN 4.3 Fusion 🔥 Edition firmware, using OpenOCD and a ST-LINK programmer. + +## Introduction + +Some users have accidentally flashed a UV-K5 V1 with the F4HWN 4.3 Fusion 🔥 Edition firmware. This edition **is only** compatible with: + +- UV-K5 V3 +- UV-K1 + +When flashed onto a UV-K5 V1, it causes a complete brick, such as: + +- The radio does not power on anymore +- DFU mode is unavailable +- No LED activity +- Flashing tools cannot detect the device + +Fortunately, the UV-K5 V1 can be fully restored by using OpenOCD and a ST-LINK programmer. + +## Requirements + +You will need: + +- A ST-LINK V2 programmer (original or clone) +- Four Dupont jumper wires +- A small screwdriver to open the radio +- A computer with OpenOCD installed (Windows / macOS / Linux). + +## SWD connection points on the UV-K5 V1 + +The radio must be opened to access the front side of the PCB. +The UV-K5 V1 exposes a 4-pin SWD (Serial Wire Debug) interface: + +|Signal| UV-K5 V1 Pad| ST-LINK Pin| +|:-------- |:--------:| --------:| +|GND |GND pad | GND | +|SWCLK |SWCLK pad | SWCLK +|SWDIO |SWDIO pad | SWDIO +|3.3V | VCC pad | 3.3V | + +bottom + +> [!WARNING] +> Do not connect the battery while using the ST-LINK. +The ST-LINK provides 3.3V to the board. + +## Installing OpenOCD + +### macOS (Homebrew) + +`brew install openocd` + +### Windows + +Download the official build from: + +- [Website](https://openocd.org/pages/getting-openocd.html) +- [GitHub](https://github.com/openocd-org/openocd/releases) + +### Linux (Ubuntu / Debian) + +`sudo apt install openocd` + +### Verify installation + +`openocd --version` + +## Download unbrick toolkit + +Download the [unbrick toolkit archive](https://github.com/user-attachments/files/24002834/unbrick_k5_v1.zip) and extract it on your PC. + +## Unbrick procedure + +### Connect the ST-LINK + +1. Connect the ST-LINK pins to the SWD pads: + + * 3.3V → 3.3V + * SWDIO → SWDIO + * SWCLK → SWCLK + * GND → GND + +2. Plug the ST-LINK into your computer. +3. Power on your UV-K5 V1 (normal mode). + +### Flash the bootloader + +From the `unbrick_k5_v1` directory: + +#### Option A — Use the helper script + +` +./unbrick_k5_v1.sh +` + +#### Option B — Run the OpenOCD command manually + +` +openocd -f ./interface/stlink.cfg -f ./target/dp32g030.cfg -c "init; reset halt; uv_flash_bl bootloader.bin; shutdown" +` + + +https://github.com/user-attachments/assets/a511fdb3-a3a3-4fe1-91cc-31e765221b22 + + +If no errors appear, the bootloader has been successfully restored. + +- Disconnect and remove the ST-LINK from your UV-K5 V1 SWD port +- Reinstall the battery +- Power on the radio on DFU mode + +The device should now start correctly on DFU mode again. You can then flash stock firmware, or the [F4HWN firmware for UV-K5 V1](https://github.com/armel/uv-k5-firmware-custom) (not the Fusion 🔥 Edition). + +# Disclaimer + +This procedure requires opening the device and directly manipulating its microcontroller over SWD. Incorrect use may permanently damage the radio. Proceed at your own risk. diff --git a/tools/unbrick_k5_v1/bootloader.bin b/tools/unbrick_k5_v1/bootloader.bin new file mode 100644 index 00000000..11fdf1d8 Binary files /dev/null and b/tools/unbrick_k5_v1/bootloader.bin differ diff --git a/tools/unbrick_k5_v1/interface/stlink-dap.cfg b/tools/unbrick_k5_v1/interface/stlink-dap.cfg new file mode 100644 index 00000000..2103a298 --- /dev/null +++ b/tools/unbrick_k5_v1/interface/stlink-dap.cfg @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# STMicroelectronics ST-LINK/V1, ST-LINK/V2, ST-LINK/V2-1, STLINK-V3 in-circuit +# debugger/programmer +# +# This new interface driver creates a ST-Link wrapper for ARM-DAP named "dapdirect" +# Old ST-LINK/V1 and ST-LINK/V2 pre version V2J24 don't support "dapdirect" +# +# SWIM transport is natively supported +# + +adapter driver st-link +st-link vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 0x0483 0x3755 0x0483 0x3757 + +# transport select dapdirect_jtag +# transport select dapdirect_swd +# transport select swim + +# Optionally specify the serial number of usb device +# e.g. +# adapter serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" diff --git a/tools/unbrick_k5_v1/interface/stlink-v1.cfg b/tools/unbrick_k5_v1/interface/stlink-v1.cfg new file mode 100644 index 00000000..9319fc35 --- /dev/null +++ b/tools/unbrick_k5_v1/interface/stlink-v1.cfg @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +echo "WARNING: interface/stlink-v1.cfg is deprecated, please switch to interface/stlink.cfg" +source [find interface/stlink.cfg] diff --git a/tools/unbrick_k5_v1/interface/stlink-v2-1.cfg b/tools/unbrick_k5_v1/interface/stlink-v2-1.cfg new file mode 100644 index 00000000..dd03e1b4 --- /dev/null +++ b/tools/unbrick_k5_v1/interface/stlink-v2-1.cfg @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +echo "WARNING: interface/stlink-v2-1.cfg is deprecated, please switch to interface/stlink.cfg" +source [find interface/stlink.cfg] diff --git a/tools/unbrick_k5_v1/interface/stlink-v2.cfg b/tools/unbrick_k5_v1/interface/stlink-v2.cfg new file mode 100644 index 00000000..c52eec9b --- /dev/null +++ b/tools/unbrick_k5_v1/interface/stlink-v2.cfg @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +echo "WARNING: interface/stlink-v2.cfg is deprecated, please switch to interface/stlink.cfg" +source [find interface/stlink.cfg] diff --git a/tools/unbrick_k5_v1/interface/stlink.cfg b/tools/unbrick_k5_v1/interface/stlink.cfg new file mode 100644 index 00000000..0a00581f --- /dev/null +++ b/tools/unbrick_k5_v1/interface/stlink.cfg @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# STMicroelectronics ST-LINK/V1, ST-LINK/V2, ST-LINK/V2-1, STLINK-V3 in-circuit +# debugger/programmer +# + +adapter driver hla +hla layout stlink +hla device_desc "ST-LINK" +hla vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 0x0483 0x3755 0x0483 0x3757 + +# Optionally specify the serial number of ST-LINK/V2 usb device. ST-LINK/V2 +# devices seem to have serial numbers with unreadable characters. ST-LINK/V2 +# firmware version >= V2.J21.S4 recommended to avoid issues with adapter serial +# number reset issues. +# eg. +#adapter serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" diff --git a/tools/unbrick_k5_v1/media/bottom.png b/tools/unbrick_k5_v1/media/bottom.png new file mode 100644 index 00000000..07a8b7d3 Binary files /dev/null and b/tools/unbrick_k5_v1/media/bottom.png differ diff --git a/tools/unbrick_k5_v1/media/openocd.png b/tools/unbrick_k5_v1/media/openocd.png new file mode 100644 index 00000000..f15a1ca0 Binary files /dev/null and b/tools/unbrick_k5_v1/media/openocd.png differ diff --git a/tools/unbrick_k5_v1/media/pcbite.png b/tools/unbrick_k5_v1/media/pcbite.png new file mode 100644 index 00000000..e2c02b2c Binary files /dev/null and b/tools/unbrick_k5_v1/media/pcbite.png differ diff --git a/tools/unbrick_k5_v1/media/pinout.png b/tools/unbrick_k5_v1/media/pinout.png new file mode 100644 index 00000000..2551cc36 Binary files /dev/null and b/tools/unbrick_k5_v1/media/pinout.png differ diff --git a/tools/unbrick_k5_v1/media/unbrick.mov b/tools/unbrick_k5_v1/media/unbrick.mov new file mode 100644 index 00000000..45838867 Binary files /dev/null and b/tools/unbrick_k5_v1/media/unbrick.mov differ diff --git a/tools/unbrick_k5_v1/target/dp32g030.cfg b/tools/unbrick_k5_v1/target/dp32g030.cfg new file mode 100644 index 00000000..fe9e6963 --- /dev/null +++ b/tools/unbrick_k5_v1/target/dp32g030.cfg @@ -0,0 +1,359 @@ +#OpenOCD script for Action Dynamic DP32G030 ARM Cortex M0 CPU (UV-5R, UV-k5 Ham HTs) +#For use with cheap ST-Link USB debug probe +source target/swj-dp.tcl + +set _CHIP_NAME DP32G0xx +set _ENDIAN little +set _WORKAREASIZE 0x1000 +set _FLASH_SIZE 0x10000 +set _CPUTAPID 0x0BB11477 +set _TARGETNAME $_CHIP_NAME.cpu +set _FLASHNAME $_CHIP_NAME.flash +set _SECTOR_SIZE 512 +set _MASKING_CFG 2 ;#1:2kB, 2:4kB, 3:8kB + +adapter speed 960 +adapter srst delay 100 +reset_config srst_nogate + +# Create a new dap, with name chip and role CPU, -enable let's OpenOCD to know to add it to the scan +swj_newdap $_CHIP_NAME cpu -expected-id $_CPUTAPID -enable + +# Create the DAP instance, this must be explicitly created according to the OpenOCD docs +dap create $_CHIP_NAME.dap -chain-position $_CHIP_NAME.cpu + +# Set up the GDB target for the CPU +target create $_CHIP_NAME.cpu cortex_m -endian $_ENDIAN -dap $_CHIP_NAME.dap +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +# Declare internal bank +flash bank $_FLASHNAME stm32f1x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME + +proc check_readiness {} { + while {[read_memory 0x4006F014 32 1] & 0x2} {} +} + +proc rom_mask_off {} { + echo "\nChecking ROM masking" + check_readiness + set status [read_memory 0x4006F020 32 1] + if {($status & 0x3) != 0} { + echo [format "\nROM masking is set to 0b%03b. Unsetting..." $status] + write_memory 0x4006F020 32 [expr {[read_memory 0x4006F020 32 1] & 0x3}] + check_readiness + write_memory 0x4006F020 32 0 + check_readiness + write_memory 0x4006F020 32 4 + } + return [read_memory 0x4006F020 32 1] +} + +proc rom_mask_on {} { + global _MASKING_CFG + echo "\nChecking ROM masking" + check_readiness + set status [read_memory 0x4006F020 32 1] + if {($status & 0x3) != $_MASKING_CFG} { + echo [format "\nROM masking is set to 0b%03b. Setting ON..." $status] + write_memory 0x4006F020 32 [expr {[read_memory 0x4006F020 32 1] & 0x3}] + check_readiness + write_memory 0x4006F020 32 $_MASKING_CFG + check_readiness + write_memory 0x4006F020 32 [expr {4 | $_MASKING_CFG}] + } + return [read_memory 0x4006F020 32 1] +} + +proc unlock_rom {} { + write_memory 0x4006F01c 32 0xAA + check_readiness +} + +proc lock_rom {} { + write_memory 0x4006F018 32 0x55 + check_readiness +} + +proc select_region {target_r} { + #Region 0 is main user ROM area, 1 is NVRAM area + write_memory 0x4006F000 32 [expr {(0x31 & [read_memory 0x4006F000 32 1]) | (($target_r & 0x1) << 1)}] + check_readiness +} + +proc wipe_sector_range {st_sec sec_count} { + set last [expr {$st_sec + $sec_count}] + set reg [expr {[read_memory 0x4006F000 32 1] & 0x7FFFFFFF}] + write_memory 0x4006F000 32 [expr {$reg | 0x8}] ;#set writing mode ERASE + + for {set i $st_sec} {$i < $last} {incr i} { + check_readiness + echo -n [format "\rErasing sector 0x%02x = offset 0x%04x" [expr {$i}] [expr {$i*512}] ] + write_memory 0x4006F004 32 [expr {$i << 7}] ;#set address in flash + write_memory 0x4006F010 32 0x01 ;#do it + } + check_readiness + write_memory 0x4006F000 32 $reg +} + +proc wipe_rom {} { + #This will wipe everything including bootloader + global _SECTOR_SIZE + global _FLASH_SIZE + unlock_rom + select_region 0 + if {[rom_mask_off] != 4} { + echo "\nROM Masking failed to disable!" + close $fd + return + } + wipe_sector_range 0 [expr {$_FLASH_SIZE / $_SECTOR_SIZE}] +} + +proc binary_to_int {data} { + # Complète la chaîne à 4 octets si nécessaire + set data $data[string repeat \xFF [expr {4 - [string length $data]}]] + + # Initialise le résultat à 0 + set result 0 + + # Parcourt les octets et assemble l'entier + for {set i 0} {$i < 4} {incr i} { + # Récupère l'octet à la position $i + set byte [scan [string index $data $i] %c] + # Décale l'octet en fonction de l'ordre Little Endian + set result [expr {$result | ($byte & 0xFF) << (8 * $i)}] + } + + return $result +} + +proc write_image {filename offset} { + global _SECTOR_SIZE + global _FLASH_SIZE + set fs [file size $filename] + set fd [open $filename "rb"] + set reg [expr {[read_memory 0x4006F000 32 1] & 0x7FFFFFFF}] + write_memory 0x4006F000 32 [expr {$reg | 0x4}] ;#set writing mode PROGRAM + while {![eof $fd]} { + if {($offset+4) > $_FLASH_SIZE} { + echo "\nData exceeds main storage capacity!" + write_memory 0x4006F000 32 $reg + lock_rom + close $fd + return + } + check_readiness + set data [read $fd 4] + set data $data[string repeat \xFF [expr {4-[string length $data]}]] ;#padding + #binary scan $data i i_data + set i_data [binary_to_int $data] + write_memory 0x4006F004 32 [expr {($offset>>2)+0xC000}] ;#set destination offset + write_memory 0x4006F008 32 $i_data ;#set word + write_memory 0x4006F010 32 0x01 ;#set OPSTART=1 + while {([read_memory 0x4006F014 32 1] & 4) == 0} {} + echo -n [format "\rProgrammed up to 0x%04x (FLASH_ADDR=0x%04x)" $offset [expr {($offset>>2)+0xC000}]] + incr offset 4 + } + check_readiness + write_memory 0x4006F000 32 $reg ;#reset writing mode to OFF +} + +proc flash_blocks {filename address nblocks offset} { + #Intended for speed. Due to tight timings, sometimes it works, sometimes it does not. Needs clocks adjusting there. + global _SECTOR_SIZE + global _FLASH_SIZE + + if {($nblocks != 0) & [expr {$nblocks & 1}]} { + set nblocks [expr {$nblocks + 1}] + } + set addr [expr {$_SECTOR_SIZE * ($address >> 9)}] + set fs [expr {((($_SECTOR_SIZE*$nblocks)/2 + $_SECTOR_SIZE-1)&(0x10000000-$_SECTOR_SIZE))}] + set fd [open $filename "rb"] + + read $fd $addr + set addr [expr {$addr + $offset}] ;#apply ROM offset + set reg [expr {[read_memory 0x4006F000 32 1] & 0x7FFFFFFF}] + + echo -n [format "\tWiping %02d sectors, starting at %02d " [expr {$nblocks / 2}] [expr {$addr >> 9}]] + + wipe_sector_range [expr {$addr >> 9}] [expr {$nblocks / 2}] ;#wipe related sectors + echo "\nRegion cleared OK" + + echo [format "%02d bytes to push" $fs]; ##DEBUG + write_memory 0x4006F000 32 [expr {$reg | 0x4}] ;#set writing mode PROGRAM + + while {$fs > 0} { + write_memory 0x4006F004 32 [expr {0xC000+(($addr)>>2)}] ;#set block starting offset + set i_buffer {} + for {set blk 0} {$blk < $_SECTOR_SIZE/2} {incr blk 4} { + set data [read $fd 4] + set data $data[string repeat \xFF [expr {4-[string length $data]}]] ;#padding to desired ending block + if {($addr+$_SECTOR_SIZE/2) >= $_FLASH_SIZE} { + echo [format "\nMain firmware image upper boundary reached (%d)!" $addr] + write_memory 0x4006F000 32 $reg ;#reset writing mode to OFF + close $fd + return + } + binary scan $data i i_data + lappend i_buffer [expr {$i_data & 0xFFFFFFFF}] + incr fs -4 + } + echo [format "\nWriting at offset 0x%04x" [expr {$addr}]] + ##for {set bi 0} {$bi < 64} {incr bi} {echo -n [format "%08x" [lindex $i_buffer $bi]]}; #DEBUG + write_memory 0x4006F008 32 [lindex $i_buffer 0] ;#prepare 1st word: we need to be quick beyond this point + check_readiness + write_memory 0x4006F010 32 0x01 + for {set bi 1} {$bi < 64} {incr bi} {while {([read_memory 0x4006F014 32 1] & 0x4) == 4} {write_memory 0x4006F008 32 [lindex $i_buffer $bi]}} + check_readiness + incr addr $_SECTOR_SIZE/2 ;# Next block + } + write_memory 0x4006F000 32 $reg ;#reset writing mode to OFF + echo [format "\nLast write was 0x%08x " [lindex $i_buffer 63]] + close $fd + return +} + +proc toggle_pin_gpioa {pin} { + write_memory 0x40060000 16 [expr {[read_memory 0x40060000 16 1] ^(1<<$pin) }] +} + +proc toggle_pin_gpiob {pin} { + write_memory 0x40060800 16 [expr {[read_memory 0x40060800 16 1] ^(1<<$pin) }] +} + +proc toggle_pin_gpioc {pin} { + write_memory 0x40061000 16 [expr {[read_memory 0x40061000 16 1] ^(1<<$pin) }] +} + +proc set_pin_gpioa {pin value} { + if {$value == 0} { + write_memory 0x40060000 16 [expr {[read_memory 0x40060000 16 1] &~(1<<$pin) }] + } else { + write_memory 0x40060000 16 [expr {[read_memory 0x40060000 16 1] |(1<<$pin) }] + } +} + +proc set_pin_gpiob {pin value} { + if {$value == 0} { + write_memory 0x40060800 16 [expr {[read_memory 0x40060800 16 1] &~(1<<$pin) }] + } else { + write_memory 0x40060800 16 [expr {[read_memory 0x40060800 16 1] |(1<<$pin) }] + } +} + +proc set_pin_gpioc {pin value} { + if {$value == 0} { + write_memory 0x40061000 16 [expr {[read_memory 0x40061000 16 1] &~(1<<$pin) }] + } else { + write_memory 0x40061000 16 [expr {[read_memory 0x40061000 16 1] |(1<<$pin) }] + } +} + +##Quansheng UVK5-specific snippets + +proc uv_fastflash_bl {filename} { + write_memory 0x4006F024 32 0x4E02A300 ;#force stock timings, just in case + write_memory 0x4006F028 32 0x210360 + write_memory 0x4006F000 32 0x1 + check_readiness + select_region 0 + if {[rom_mask_off] != 4} { + echo "\nROM Masking failed to disable!" + close $fd + return + } + reset halt + unlock_rom + + flash_blocks $filename 0 16 0 + + #just relock flashROM + lock_rom +} + +proc uv_fastflash_fw {filename} { + #Make sure bootloader is hidden + if {[rom_mask_on] != 6} { + echo "\nROM Masking failed to enable!" + close $fd + return + } + reset halt + unlock_rom + + flash_blocks $filename 0 [expr {[file size $filename] >> 8}] 0 + reset + echo "\nCPU reset: Transceiver should boot now." +} + +proc uv_flash_bl {filename} { + #Securely rewrites bootloader (slowly) + + if {[file size $filename] > 0x1000} { + echo [format "Bootloader image is too large to fit!] + return + } + select_region 0 + if {[rom_mask_off] != 4} { + echo "\nROM Masking failed to disable!" + return + } + reset halt + unlock_rom + + wipe_sector_range 0 8 + echo "\nRegion cleared OK" + + write_image $filename 0 + + if {[rom_mask_on] != 6} { + echo "\nROM Masking failed to enable!" + lock_rom + return + } + #relock flashROM, in case conventional method for fw is preferred + lock_rom + echo "\nBootloader code programmed.\nYou can use uv_flash_fw to program main firmware, or just use stock tool to do it." +} + +proc uv_flash_fw {filename} { + #Securely rewrites main firmware (slowly) + + select_region 0 + #Make sure bootloader is hidden + if {[rom_mask_on] != 6} { + echo "\nROM Masking failed to enable!" + return + } + reset halt + unlock_rom + + wipe_sector_range 0 120 + echo "\nRegion cleared OK" + + write_image $filename 0 + + #relock flashROM, then reset CPU + lock_rom + reset + echo "\nCPU reset: Transceiver should boot now." +} + +proc uv_flashlight_toggle {} { + toggle_pin_gpioc 3 ;# toggles PORTC.3 +} + +proc uv_flashlight_on {} { + set_pin_gpioc 3 1 ;# set PORTC.3 high +} + +proc uv_flashlight_off {} { + set_pin_gpioc 3 0 ;# set PORTC.3 to low +} + +proc uv_backlight_toggle {} { + toggle_pin_gpiob 6 ;# toggles PORTB.6 +} + +init +#reset halt diff --git a/tools/unbrick_k5_v1/target/swj-dp-legacy.tcl b/tools/unbrick_k5_v1/target/swj-dp-legacy.tcl new file mode 100644 index 00000000..8d2464a6 --- /dev/null +++ b/tools/unbrick_k5_v1/target/swj-dp-legacy.tcl @@ -0,0 +1,34 @@ +# ARM Debug Interface V5 (ADI_V5) utility +# ... Mostly for SWJ-DP (not SW-DP or JTAG-DP, since +# SW-DP and JTAG-DP targets don't need to switch based +# on which transport is active. +# +# declare a JTAG or SWD Debug Access Point (DAP) +# based on the transport in use with this session. +# You can't access JTAG ops when SWD is active, etc. + +# params are currently what "jtag newtap" uses +# because OpenOCD internals are still strongly biased +# to JTAG .... but for SWD, "irlen" etc are ignored, +# and the internals work differently + +# for now, ignore non-JTAG and non-SWD transports +# (e.g. initial flash programming via SPI or UART) + +# split out "chip" and "tag" so we can someday handle +# them more uniformly irlen too...) + +if [catch {transport select}] { + echo "Error: unable to select a session transport. Can't continue." + shutdown +} + +proc swj_newdap {chip tag args} { + if [using_hla] { + eval hla newtap $chip $tag $args + } elseif [using_jtag] { + eval jtag newtap $chip $tag $args + } elseif [using_swd] { + eval swd newdap $chip $tag $args + } +} diff --git a/tools/unbrick_k5_v1/target/swj-dp.tcl b/tools/unbrick_k5_v1/target/swj-dp.tcl new file mode 100644 index 00000000..ee28b6fe --- /dev/null +++ b/tools/unbrick_k5_v1/target/swj-dp.tcl @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# ARM Debug Interface V5 (ADI_V5) utility +# ... Mostly for SWJ-DP (not SW-DP or JTAG-DP, since +# SW-DP and JTAG-DP targets don't need to switch based +# on which transport is active. +# +# declare a JTAG or SWD Debug Access Point (DAP) +# based on the transport in use with this session. +# You can't access JTAG ops when SWD is active, etc. + +# params are currently what "jtag newtap" uses +# because OpenOCD internals are still strongly biased +# to JTAG .... but for SWD, "irlen" etc are ignored, +# and the internals work differently + +# for now, ignore non-JTAG and non-SWD transports +# (e.g. initial flash programming via SPI or UART) + +# split out "chip" and "tag" so we can someday handle +# them more uniformly irlen too...) + +if [catch {transport select}] { + echo "Error: unable to select a session transport. Can't continue." + shutdown +} + +proc swj_newdap {chip tag args} { + if [using_jtag] { + eval jtag newtap $chip $tag $args + } elseif [using_swd] { + eval swd newdap $chip $tag $args + } else { + echo "Error: transport '[ transport select ]' not supported by swj_newdap" + shutdown + } +} diff --git a/tools/unbrick_k5_v1/unbrick_k5_v1.sh b/tools/unbrick_k5_v1/unbrick_k5_v1.sh new file mode 100755 index 00000000..d6638418 --- /dev/null +++ b/tools/unbrick_k5_v1/unbrick_k5_v1.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +openocd -f ./interface/stlink.cfg -f ./target/dp32g030.cfg -c "init; reset halt; uv_flash_bl bootloader.bin; shutdown" \ No newline at end of file