Guest User

uv-k5 unbrick target fix

a guest
Jan 20th, 2026
23
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.55 KB | Fixit | 0 0
  1. #OpenOCD script for Action Dynamic DP32G030 ARM Cortex M0 CPU (UV-5R, UV-k5 Ham HTs)
  2. #For use with cheap ST-Link USB debug probe
  3. source target/swj-dp.tcl
  4.  
  5. set _CHIP_NAME DP32G0xx
  6. set _ENDIAN little
  7. set _WORKAREASIZE 0x1000
  8. set _FLASH_SIZE 0x10000
  9. set _CPUTAPID 0x0BB11477
  10. set _TARGETNAME $_CHIP_NAME.cpu
  11. set _FLASHNAME $_CHIP_NAME.flash
  12. set _SECTOR_SIZE 512
  13. set _MASKING_CFG 2 ;#1:2kB, 2:4kB, 3:8kB
  14.  
  15. adapter speed 960
  16. adapter srst delay 100
  17. reset_config srst_nogate
  18.  
  19. # Create a new dap, with name chip and role CPU, -enable let's OpenOCD to know to add it to the scan
  20. swj_newdap $_CHIP_NAME cpu -expected-id $_CPUTAPID -enable
  21.  
  22. # Create the DAP instance, this must be explicitly created according to the OpenOCD docs
  23. dap create $_CHIP_NAME.dap -chain-position $_CHIP_NAME.cpu
  24.  
  25. # Set up the GDB target for the CPU
  26. target create $_CHIP_NAME.cpu cortex_m -endian $_ENDIAN -dap $_CHIP_NAME.dap
  27. $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
  28.  
  29. # Declare internal bank
  30. flash bank $_FLASHNAME stm32f1x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME
  31.  
  32. proc check_readiness {} {
  33. while {[read_memory 0x4006F014 32 1] & 0x2} {}
  34. }
  35.  
  36. proc rom_mask_off {} {
  37. echo "\nChecking ROM masking"
  38. check_readiness
  39. set status [read_memory 0x4006F020 32 1]
  40. if {($status & 0x3) != 0} {
  41. echo [format "\nROM masking is set to 0b%03b. Unsetting..." $status]
  42. write_memory 0x4006F020 32 [expr {[read_memory 0x4006F020 32 1] & 0x3}]
  43. check_readiness
  44. write_memory 0x4006F020 32 0
  45. check_readiness
  46. write_memory 0x4006F020 32 4
  47. }
  48. return [read_memory 0x4006F020 32 1]
  49. }
  50.  
  51. proc rom_mask_on {} {
  52. global _MASKING_CFG
  53. echo "\nChecking ROM masking"
  54. check_readiness
  55. set status [read_memory 0x4006F020 32 1]
  56. if {($status & 0x3) != $_MASKING_CFG} {
  57. echo [format "\nROM masking is set to 0b%03b. Setting ON..." $status]
  58. write_memory 0x4006F020 32 [expr {[read_memory 0x4006F020 32 1] & 0x3}]
  59. check_readiness
  60. write_memory 0x4006F020 32 $_MASKING_CFG
  61. check_readiness
  62. write_memory 0x4006F020 32 [expr {4 | $_MASKING_CFG}]
  63. }
  64. return [read_memory 0x4006F020 32 1]
  65. }
  66.  
  67. proc unlock_rom {} {
  68. write_memory 0x4006F01c 32 0xAA
  69. check_readiness
  70. }
  71.  
  72. proc lock_rom {} {
  73. write_memory 0x4006F018 32 0x55
  74. check_readiness
  75. }
  76.  
  77. proc select_region {target_r} {
  78. #Region 0 is main user ROM area, 1 is NVRAM area
  79. write_memory 0x4006F000 32 [expr {(0x31 & [read_memory 0x4006F000 32 1]) | (($target_r & 0x1) << 1)}]
  80. check_readiness
  81. }
  82.  
  83. proc wipe_sector_range {st_sec sec_count} {
  84. set last [expr {$st_sec + $sec_count}]
  85. set reg [expr {[read_memory 0x4006F000 32 1] & 0x7FFFFFFF}]
  86. write_memory 0x4006F000 32 [expr {$reg | 0x8}] ;#set writing mode ERASE
  87.  
  88. for {set i $st_sec} {$i < $last} {incr i} {
  89. check_readiness
  90. echo -n [format "\rErasing sector 0x%02x = offset 0x%04x" [expr {$i}] [expr {$i*512}] ]
  91. write_memory 0x4006F004 32 [expr {$i << 7}] ;#set address in flash
  92. write_memory 0x4006F010 32 0x01 ;#do it
  93. }
  94. check_readiness
  95. write_memory 0x4006F000 32 $reg
  96. }
  97.  
  98. proc wipe_rom {} {
  99. #This will wipe everything including bootloader
  100. global _SECTOR_SIZE
  101. global _FLASH_SIZE
  102. unlock_rom
  103. select_region 0
  104. if {[rom_mask_off] != 4} {
  105. echo "\nROM Masking failed to disable!"
  106. close $fd
  107. return
  108. }
  109. wipe_sector_range 0 [expr {$_FLASH_SIZE / $_SECTOR_SIZE}]
  110. }
  111.  
  112. proc write_image {filename offset} {
  113. global _SECTOR_SIZE
  114. global _FLASH_SIZE
  115. set fs [file size $filename]
  116. set fd [open $filename "rb"]
  117. set reg [expr {[read_memory 0x4006F000 32 1] & 0x7FFFFFFF}]
  118. write_memory 0x4006F000 32 [expr {$reg | 0x4}] ;#set writing mode PROGRAM
  119. while {![eof $fd]} {
  120. if {($offset+4) > $_FLASH_SIZE} {
  121. echo "\nData exceeds main storage capacity!"
  122. write_memory 0x4006F000 32 $reg
  123. lock_rom
  124. close $fd
  125. return
  126. }
  127. check_readiness
  128. set data [read $fd 4]
  129. set data $data[string repeat \xFF [expr {4-[string length $data]}]] ;#padding
  130. scan [string index $data 0] %c b0
  131. scan [string index $data 1] %c b1
  132. scan [string index $data 2] %c b2
  133. scan [string index $data 3] %c b3
  134. set i_data [expr {($b0 & 0xFF) | (($b1 & 0xFF) << 8) | (($b2 & 0xFF) << 16) | (($b3 & 0xFF) << 24)}]
  135. write_memory 0x4006F004 32 [expr {($offset>>2)+0xC000}] ;#set destination offset
  136. write_memory 0x4006F008 32 $i_data ;#set word
  137. write_memory 0x4006F010 32 0x01 ;#set OPSTART=1
  138. while {([read_memory 0x4006F014 32 1] & 4) == 0} {}
  139. echo -n [format "\rProgrammed up to 0x%04x (FLASH_ADDR=0x%04x)" $offset [expr {($offset>>2)+0xC000}]]
  140. incr offset 4
  141. }
  142. check_readiness
  143. write_memory 0x4006F000 32 $reg ;#reset writing mode to OFF
  144. }
  145.  
  146. proc flash_blocks {filename address nblocks offset} {
  147. #Intended for speed. Due to tight timings, sometimes it works, sometimes it does not. Needs clocks adjusting there.
  148. global _SECTOR_SIZE
  149. global _FLASH_SIZE
  150.  
  151. if {($nblocks != 0) & [expr {$nblocks & 1}]} {
  152. set nblocks [expr {$nblocks + 1}]
  153. }
  154. set addr [expr {$_SECTOR_SIZE * ($address >> 9)}]
  155. set fs [expr {((($_SECTOR_SIZE*$nblocks)/2 + $_SECTOR_SIZE-1)&(0x10000000-$_SECTOR_SIZE))}]
  156. set fd [open $filename "rb"]
  157.  
  158. read $fd $addr
  159. set addr [expr {$addr + $offset}] ;#apply ROM offset
  160. set reg [expr {[read_memory 0x4006F000 32 1] & 0x7FFFFFFF}]
  161.  
  162. echo -n [format "\tWiping %02d sectors, starting at %02d " [expr {$nblocks / 2}] [expr {$addr >> 9}]]
  163.  
  164. wipe_sector_range [expr {$addr >> 9}] [expr {$nblocks / 2}] ;#wipe related sectors
  165. echo "\nRegion cleared OK"
  166.  
  167. echo [format "%02d bytes to push" $fs]; ##DEBUG
  168. write_memory 0x4006F000 32 [expr {$reg | 0x4}] ;#set writing mode PROGRAM
  169.  
  170. while {$fs > 0} {
  171. write_memory 0x4006F004 32 [expr {0xC000+(($addr)>>2)}] ;#set block starting offset
  172. set i_buffer {}
  173. for {set blk 0} {$blk < $_SECTOR_SIZE/2} {incr blk 4} {
  174. set data [read $fd 4]
  175. set data $data[string repeat \xFF [expr {4-[string length $data]}]] ;#padding to desired ending block
  176. if {($addr+$_SECTOR_SIZE/2) >= $_FLASH_SIZE} {
  177. echo [format "\nMain firmware image upper boundary reached (%d)!" $addr]
  178. write_memory 0x4006F000 32 $reg ;#reset writing mode to OFF
  179. close $fd
  180. return
  181. }
  182. binary scan $data i i_data
  183. lappend i_buffer [expr {$i_data & 0xFFFFFFFF}]
  184. incr fs -4
  185. }
  186. echo [format "\nWriting at offset 0x%04x" [expr {$addr}]]
  187. ##for {set bi 0} {$bi < 64} {incr bi} {echo -n [format "%08x" [lindex $i_buffer $bi]]}; #DEBUG
  188. write_memory 0x4006F008 32 [lindex $i_buffer 0] ;#prepare 1st word: we need to be quick beyond this point
  189. check_readiness
  190. write_memory 0x4006F010 32 0x01
  191. for {set bi 1} {$bi < 64} {incr bi} {while {([read_memory 0x4006F014 32 1] & 0x4) == 4} {write_memory 0x4006F008 32 [lindex $i_buffer $bi]}}
  192. check_readiness
  193. incr addr $_SECTOR_SIZE/2 ;# Next block
  194. }
  195. write_memory 0x4006F000 32 $reg ;#reset writing mode to OFF
  196. echo [format "\nLast write was 0x%08x " [lindex $i_buffer 63]]
  197. close $fd
  198. return
  199. }
  200.  
  201. proc toggle_pin_gpioa {pin} {
  202. write_memory 0x40060000 16 [expr {[read_memory 0x40060000 16 1] ^(1<<$pin) }]
  203. }
  204.  
  205. proc toggle_pin_gpiob {pin} {
  206. write_memory 0x40060800 16 [expr {[read_memory 0x40060800 16 1] ^(1<<$pin) }]
  207. }
  208.  
  209. proc toggle_pin_gpioc {pin} {
  210. write_memory 0x40061000 16 [expr {[read_memory 0x40061000 16 1] ^(1<<$pin) }]
  211. }
  212.  
  213. proc set_pin_gpioa {pin value} {
  214. if {$value == 0} {
  215. write_memory 0x40060000 16 [expr {[read_memory 0x40060000 16 1] &~(1<<$pin) }]
  216. } else {
  217. write_memory 0x40060000 16 [expr {[read_memory 0x40060000 16 1] |(1<<$pin) }]
  218. }
  219. }
  220.  
  221. proc set_pin_gpiob {pin value} {
  222. if {$value == 0} {
  223. write_memory 0x40060800 16 [expr {[read_memory 0x40060800 16 1] &~(1<<$pin) }]
  224. } else {
  225. write_memory 0x40060800 16 [expr {[read_memory 0x40060800 16 1] |(1<<$pin) }]
  226. }
  227. }
  228.  
  229. proc set_pin_gpioc {pin value} {
  230. if {$value == 0} {
  231. write_memory 0x40061000 16 [expr {[read_memory 0x40061000 16 1] &~(1<<$pin) }]
  232. } else {
  233. write_memory 0x40061000 16 [expr {[read_memory 0x40061000 16 1] |(1<<$pin) }]
  234. }
  235. }
  236.  
  237. ##Quansheng UVK5-specific snippets
  238.  
  239. proc uv_fastflash_bl {filename} {
  240. write_memory 0x4006F024 32 0x4E02A300 ;#force stock timings, just in case
  241. write_memory 0x4006F028 32 0x210360
  242. write_memory 0x4006F000 32 0x1
  243. check_readiness
  244. select_region 0
  245. if {[rom_mask_off] != 4} {
  246. echo "\nROM Masking failed to disable!"
  247. close $fd
  248. return
  249. }
  250. reset halt
  251. unlock_rom
  252.  
  253. flash_blocks $filename 0 16 0
  254.  
  255. #just relock flashROM
  256. lock_rom
  257. }
  258.  
  259. proc uv_fastflash_fw {filename} {
  260. #Make sure bootloader is hidden
  261. if {[rom_mask_on] != 6} {
  262. echo "\nROM Masking failed to enable!"
  263. close $fd
  264. return
  265. }
  266. reset halt
  267. unlock_rom
  268.  
  269. flash_blocks $filename 0 [expr {[file size $filename] >> 8}] 0
  270. reset
  271. echo "\nCPU reset: Transceiver should boot now."
  272. }
  273.  
  274. proc uv_flash_bl {filename} {
  275. #Securely rewrites bootloader (slowly)
  276.  
  277. if {[file size $filename] > 0x1000} {
  278. echo [format "Bootloader image is too large to fit!]
  279. return
  280. }
  281. select_region 0
  282. if {[rom_mask_off] != 4} {
  283. echo "\nROM Masking failed to disable!"
  284. return
  285. }
  286. reset halt
  287. unlock_rom
  288.  
  289. wipe_sector_range 0 8
  290. echo "\nRegion cleared OK"
  291.  
  292. write_image $filename 0
  293.  
  294. if {[rom_mask_on] != 6} {
  295. echo "\nROM Masking failed to enable!"
  296. lock_rom
  297. return
  298. }
  299. #relock flashROM, in case conventional method for fw is preferred
  300. lock_rom
  301. echo "\nBootloader code programmed.\nYou can use uv_flash_fw to program main firmware, or just use stock tool to do it."
  302. }
  303.  
  304. proc uv_flash_fw {filename} {
  305. #Securely rewrites main firmware (slowly)
  306.  
  307. select_region 0
  308. #Make sure bootloader is hidden
  309. if {[rom_mask_on] != 6} {
  310. echo "\nROM Masking failed to enable!"
  311. return
  312. }
  313. reset halt
  314. unlock_rom
  315.  
  316. wipe_sector_range 0 120
  317. echo "\nRegion cleared OK"
  318.  
  319. write_image $filename 0
  320.  
  321. #relock flashROM, then reset CPU
  322. lock_rom
  323. reset
  324. echo "\nCPU reset: Transceiver should boot now."
  325. }
  326.  
  327. proc uv_flashlight_toggle {} {
  328. toggle_pin_gpioc 3 ;# toggles PORTC.3
  329. }
  330.  
  331. proc uv_flashlight_on {} {
  332. set_pin_gpioc 3 1 ;# set PORTC.3 high
  333. }
  334.  
  335. proc uv_flashlight_off {} {
  336. set_pin_gpioc 3 0 ;# set PORTC.3 to low
  337. }
  338.  
  339. proc uv_backlight_toggle {} {
  340. toggle_pin_gpiob 6 ;# toggles PORTB.6
  341. }
  342.  
  343. init
  344. #reset halt
Advertisement
Add Comment
Please, Sign In to add comment