Compare commits

..
35 Commits
Author SHA1 Message Date
Armel FAUVEAU e0ac4de1ef Merge pull request #27 from armel/feature_update_v4
Compile new version 4.3.2
2025-12-08 03:05:02 +01:00
Armel FAUVEAU 9ad95af90e Compile new version 4.3.2 2025-12-08 03:04:12 +01:00
Armel FAUVEAU 64fefa92c6 Update download link for unbrick toolkit 2025-12-08 02:54:22 +01:00
Armel FAUVEAU 54ba31c4cb Merge pull request #26 from armel/feature_update_v4
Many fix and prepare new release
2025-12-08 02:51:50 +01:00
Armel FAUVEAU c9ee29438b Many fix and prepare new release 2025-12-08 02:51:23 +01:00
Armel FAUVEAU 89a6ad1428 Merge pull request #25 from armel/bugfix-broadcast-vhf-lna
Bugfix: Broadcast FM now enables VHF LNA
2025-12-08 01:09:57 +01:00
Andrej 5a4a89ae31 Bugfix: Broadcast FM now enables VHF LNA 2025-12-07 16:36:54 -05:00
Andrej 3dbe098ad9 Bugfix: FM no longer stuck in narrow mode, AM uses correct BW settings 2025-12-07 16:23:26 -05:00
Armel FAUVEAU 78aeedc251 Merge pull request #23 from armel/feature_update_v4
Feature update v4
2025-12-06 23:07:28 +01:00
Armel FAUVEAU 62b625475b Update README.md 2025-12-06 23:04:11 +01:00
Armel FAUVEAU 9a28e489a1 Remove zip 2025-12-06 23:01:34 +01:00
Armel FAUVEAU 8b4a2a5954 Add zip 2025-12-06 23:00:20 +01:00
Armel FAUVEAU 8af5a13979 Add zip 2025-12-06 23:00:04 +01:00
Armel FAUVEAU 654f313e2e Update README to clarify firmware edition 2025-12-06 22:51:26 +01:00
Armel FAUVEAU ef9285f344 Fix formatting for directory reference in README 2025-12-06 22:48:46 +01:00
Armel FAUVEAU 82e0b5c537 Fix command 2025-12-06 22:47:30 +01:00
Armel FAUVEAU 5c259cfcad Fix GND signal entry in README table
Corrected the GND signal entry in the table.
2025-12-06 22:44:38 +01:00
Armel FAUVEAU 44cf3de90a Update README with bootloader restoration link
Added a link to additional resources for restoring the bootloader.
2025-12-06 22:43:49 +01:00
Armel FAUVEAU 7d9ece1e18 Update README.md 2025-12-06 22:42:51 +01:00
Armel FAUVEAU 872372a8aa Update README with image for UV-K5 V1
Added an image to the README for visual reference.
2025-12-06 22:42:17 +01:00
Armel FAUVEAU 50e95b1531 Resize image 2025-12-06 22:40:17 +01:00
Armel FAUVEAU 200882d322 Update README 2025-12-06 22:37:35 +01:00
Armel FAUVEAU 40093dd705 Change scritp name 2025-12-06 12:46:13 +01:00
Armel FAUVEAU 643b205490 Change folder name 2025-12-06 12:45:29 +01:00
Armel FAUVEAU 5110d59a9f New tools... 2025-12-06 07:09:08 +01:00
Armel FAUVEAU 09f893b126 New tools... 2025-12-06 07:08:49 +01:00
Armel FAUVEAU 4d471dc33d Merge pull request #20 from armel/feature_update_v4
Update README
2025-12-06 00:49:28 +01:00
Armel FAUVEAU 4516486867 Update README 2025-12-06 00:48:56 +01:00
Armel FAUVEAU 15d9731611 Merge pull request #16 from armel/feature_update_v4
Fix AM (thank you Andrej)
2025-12-05 13:48:25 +01:00
Armel FAUVEAU 6cb9535ca2 Fix AM (thank you Andrej) 2025-12-05 13:47:51 +01:00
Armel FAUVEAU b8eca8810f Remove useless AM fix 2025-12-05 13:14:43 +01:00
Armel FAUVEAU 227242567d Merge pull request #15 from armel/feature-bk4829-am
Add BK4829-specific AM configuration
2025-12-05 13:12:33 +01:00
Andrej e534610d86 Add BK4829-specific AM configuration 2025-12-05 00:07:04 -05:00
Armel FAUVEAU f3e1a37701 Merge pull request #4 from armel/typo-correction
Fix typo: VOCIE->VOICE
2025-12-02 04:48:07 +01:00
Andrej 75a6e20026 Fix typo: VOCIE->VOICE 2025-12-01 22:30:29 -05:00
48 changed files with 688 additions and 29 deletions

No files matched your search

+5
View File
@@ -542,6 +542,11 @@ void ACTION_Ptt(void)
void ACTION_Wn(void)
{
if (gRxVfo->Modulation == MODULATION_AM)
{
BK4819_SetFilterBandwidth(BK4819_FILTER_BW_AM, true);
return;
}
#ifdef ENABLE_FEAT_F4HWN_NARROWER
bool narrower = 0;
if (FUNCTION_IsRx())
+7
View File
@@ -23,6 +23,7 @@
#include "app/generic.h"
#include "audio.h"
#include "driver/bk1080.h"
#include "driver/bk4819.h"
#include "driver/py25q16.h"
#include "driver/gpio.h"
#include "functions.h"
@@ -109,6 +110,10 @@ void FM_TurnOff(void)
BK1080_Init0();
// Enable relevant LNA based on VFO frequency
BK4819_PickRXFilterPathBasedOnFrequency(gRxVfo->freq_config_RX.Frequency);
gUpdateStatus = true;
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
@@ -619,6 +624,8 @@ void FM_Start(void)
gFM_RestoreCountdown_10ms = 0;
BK1080_Init(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
// Disable UHF LNA, enable VHF LNA
BK4819_PickRXFilterPathBasedOnFrequency(10320000); // 103.2 MHz < 280 MHz
AUDIO_AudioPathOn();
+1 -1
View File
@@ -306,7 +306,7 @@ static void LoadVoiceSamples()
{
gVoiceBuf[gVoiceBufWriteIndex][i] = VOICE_SAMPLES[Buf[i]];
}
VOCIE_BUF_ForwardWriteIndex();
VOICE_BUF_ForwardWriteIndex();
gVoiceBufLen++;
}
+2 -1
View File
@@ -48,7 +48,8 @@ enum BK4819_FilterBandwidth_t
{
BK4819_FILTER_BW_WIDE = 0,
BK4819_FILTER_BW_NARROW,
BK4819_FILTER_BW_NARROWER
BK4819_FILTER_BW_NARROWER,
BK4819_FILTER_BW_AM
};
typedef enum BK4819_FilterBandwidth_t BK4819_FilterBandwidth_t;
-2
View File
@@ -713,7 +713,6 @@ void BK4819_SetFilterBandwidth(const BK4819_FilterBandwidth_t Bandwidth, const b
val = 0x205C;
break;
/*
case BK4819_FILTER_BW_AM: // 8.33kHz
// if (weak_no_different) {
// // make the RX bandwidth the same with weak signals
@@ -724,7 +723,6 @@ void BK4819_SetFilterBandwidth(const BK4819_FilterBandwidth_t Bandwidth, const b
// }
val = 0x345C;
break;
*/
default:
val = 0x5C;
break;
+4 -4
View File
@@ -97,7 +97,7 @@ void VOICE_Start()
if (gVoiceBufLen > 0)
{
memcpy(DAC_Buf, gVoiceBuf[gVoiceBufReadIndex], VOICE_BUF_SIZE);
VOCIE_BUF_ForwardReadIndex();
VOICE_BUF_ForwardReadIndex();
gVoiceBufLen--;
}
else
@@ -110,7 +110,7 @@ void VOICE_Start()
gVoiceBuf[gVoiceBufReadIndex], //
VOICE_BUF_SIZE //
);
VOCIE_BUF_ForwardReadIndex();
VOICE_BUF_ForwardReadIndex();
gVoiceBufLen--;
}
else
@@ -141,7 +141,7 @@ void DMA1_Channel2_3_IRQHandler()
if (gVoiceBufLen > 0)
{
memcpy(DAC_Buf, gVoiceBuf[gVoiceBufReadIndex], VOICE_BUF_SIZE);
VOCIE_BUF_ForwardReadIndex();
VOICE_BUF_ForwardReadIndex();
gVoiceBufLen--;
}
else
@@ -158,7 +158,7 @@ void DMA1_Channel2_3_IRQHandler()
gVoiceBuf[gVoiceBufReadIndex], //
VOICE_BUF_SIZE //
);
VOCIE_BUF_ForwardReadIndex();
VOICE_BUF_ForwardReadIndex();
gVoiceBufLen--;
}
else
+2 -2
View File
@@ -26,12 +26,12 @@ extern uint8_t gVoiceBufReadIndex;
extern uint8_t gVoiceBufWriteIndex;
extern uint8_t gVoiceBufLen;
static inline void VOCIE_BUF_ForwardReadIndex()
static inline void VOICE_BUF_ForwardReadIndex()
{
gVoiceBufReadIndex = (1 + gVoiceBufReadIndex) % VOICE_BUF_CAP;
}
static inline void VOCIE_BUF_ForwardWriteIndex()
static inline void VOICE_BUF_ForwardWriteIndex()
{
gVoiceBufWriteIndex = (1 + gVoiceBufWriteIndex) % VOICE_BUF_CAP;
}
+47 -15
View File
@@ -699,21 +699,26 @@ void RADIO_SetupRegisters(bool switchToForeground)
BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2_GREEN, false);
switch (Bandwidth)
if (gRxVfo->Modulation == MODULATION_AM)
BK4819_SetFilterBandwidth(BK4819_FILTER_BW_AM, true);
else
{
default:
Bandwidth = BK4819_FILTER_BW_WIDE;
[[fallthrough]];
case BK4819_FILTER_BW_WIDE:
case BK4819_FILTER_BW_NARROW:
case BK4819_FILTER_BW_NARROWER:
#ifdef ENABLE_AM_FIX
// BK4819_SetFilterBandwidth(Bandwidth, gRxVfo->Modulation == MODULATION_AM && gSetting_AM_fix);
BK4819_SetFilterBandwidth(Bandwidth, true);
#else
BK4819_SetFilterBandwidth(Bandwidth, false);
#endif
break;
switch (Bandwidth)
{
default:
Bandwidth = BK4819_FILTER_BW_WIDE;
[[fallthrough]];
case BK4819_FILTER_BW_WIDE:
case BK4819_FILTER_BW_NARROW:
case BK4819_FILTER_BW_NARROWER:
#ifdef ENABLE_AM_FIX
// BK4819_SetFilterBandwidth(Bandwidth, gRxVfo->Modulation == MODULATION_AM && gSetting_AM_fix);
BK4819_SetFilterBandwidth(Bandwidth, true);
#else
BK4819_SetFilterBandwidth(Bandwidth, false);
#endif
break;
}
}
BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1_RED, false);
@@ -999,7 +1004,7 @@ void RADIO_SetModulation(ModulationMode_t modulation)
mod = BK4819_AF_FM;
break;
case MODULATION_AM:
mod = BK4819_AF_AM;
mod = BK4819_AF_FM; // AM no longer needs special AF setting
break;
case MODULATION_USB:
mod = BK4819_AF_BASEBAND2;
@@ -1017,6 +1022,33 @@ void RADIO_SetModulation(ModulationMode_t modulation)
BK4819_SetAF(mod);
// HACK, FIXME:
// What follows is a direct copy of the AM enable/disable code from
// the original UV-K1 firmware. It is not clear why these specific register
// values are used for AM all of a sudden instead of the AF setting like on
// the BK4819, nor what exactly they do.
// So for now we just keep it as is to maintain compatibility.
//
if (modulation != MODULATION_AM)
{
uint16_t uVar1 = BK4819_ReadRegister(0x31);
BK4819_WriteRegister(0x31,uVar1 & 0xfffffffe);
BK4819_WriteRegister(0x42,0x6b5a);
BK4819_WriteRegister(0x2a,0x7400);
BK4819_WriteRegister(0x2b,0);
BK4819_WriteRegister(0x2f,0x9890);
}
else
{
uint16_t uVar1 = BK4819_ReadRegister(0x31);
BK4819_WriteRegister(0x31,uVar1 | 1);
BK4819_WriteRegister(0x42,0x6f5c);
BK4819_WriteRegister(0x2a,0x7434);
BK4819_WriteRegister(0x2b,0x300);
BK4819_WriteRegister(0x2f,0x9990);
BK4819_SetFilterBandwidth(BK4819_FILTER_BW_AM, true);
}
BK4819_SetRegValue(afDacGainRegSpec, 0xF);
BK4819_WriteRegister(BK4819_REG_3D, modulation == MODULATION_USB ? 0 : 0x2AAB);
BK4819_SetRegValue(afcDisableRegSpec, modulation != MODULATION_FM);
+2 -2
View File
@@ -34,7 +34,7 @@
"ENABLE_SHOW_CHARGE_LEVEL": false,
"ENABLE_REVERSE_BAT_SYMBOL": false,
"ENABLE_NO_CODE_SCAN_TIMEOUT": true,
"ENABLE_AM_FIX": true,
"ENABLE_AM_FIX": false,
"ENABLE_SQUELCH_MORE_SENSITIVE": true,
"ENABLE_FASTER_CHANNEL_SCAN": true,
"ENABLE_RSSI_BAR": true,
@@ -70,7 +70,7 @@
"ENABLE_NAVIG_LEFT_RIGHT": true,
"ENABLE_SWD": false,
"VERSION_STRING_1": "v0.22",
"VERSION_STRING_2": "v4.3"
"VERSION_STRING_2": "v4.3.2"
}
},
{
+6 -2
View File
@@ -1,3 +1,7 @@
# Stats
![Alt](https://repobeats.axiom.co/api/embed/ecdd86aa536b716f088339a0c5ee734558f78c28.svg "Repobeats analytics image")
# F4HWN firmware port for the UV-K1 and UV-K5 V3 using the PY32F071 MCU
This repository is a fork of the [F4HWN custom firmware](https://github.com/armel/uv-k5-firmware-custom), who was a fork of [Egzumer custom firmware](https://github.com/egzumer/uv-k5-firmware-custom). It extends the work done for the UV-K5 V1, based on the DP32G030 MCU, and adapts it to the newer UV-K1 and UV-K5 V3 built around the PY32F071 MCU. It is the result of the joint work of [@muzkr](https://github.com/muzkr) and [@armel](https://github.com/armel).
@@ -38,7 +42,7 @@ Anyway, have fun.
# Donations
Special thanks to Jean-Cyrille F6IWW (2 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW, Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (3 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF, Eric KI1C (2 times), Phil G0ELM, Jérôme Lambert, Meinhard Frank Günther, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB, Ian KE2CHJ, Daryl VK3AWA, Roberto Brunelli, Robert Boardman, Stephen Oliver, Nicolas F4INE and William Bruno for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻
Special thanks to Jean-Cyrille F6IWW (2 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW (2 times), Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (3 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF, Eric KI1C (2 times), Phil G0ELM, Jérôme Lambert, Meinhard Frank Günther, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB, Ian KE2CHJ, Daryl VK3AWA, Roberto Brunelli, Robert Boardman, Stephen Oliver, Nicolas F4INE, William Bruno and Daniel OK2VLK for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻
## Table of Contents
@@ -338,11 +342,11 @@ Click `Restore Calibration Data` and wait until the process fully completes.
Many thanks to various people:
* [Muzkr](https://github.com/muzkr)
* [Andrej](https://github.com/Tunas1337)
* [Egzumer](https://github.com/egzumer)
* [OneOfEleven](https://github.com/OneOfEleven)
* [DualTachyon](https://github.com/DualTachyon)
* [Mikhail](https://github.com/fagci)
* [Andrej](https://github.com/Tunas1337)
* [Manuel](https://github.com/manujedi)
* @wagner
* @Lohtse Shar
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+128
View File
@@ -0,0 +1,128 @@
# Unbricking the UV-K5 V1
<img width="2016" height="1512" alt="pcbite" src="https://github.com/user-attachments/assets/b3086bf2-c14c-47da-b68b-a6867268ae78" />
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 |
<img width="750" height="500" alt="bottom" src="https://github.com/user-attachments/assets/381a9bc5-daac-4547-820e-a5c96c0bd2e1" />
> [!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/24021884/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).
# Helpful Videos
Here are two videos that can assist you during the unbricking process. If you’re new to ST-LINK, OpenOCD, or SWD debugging, these will give you a clear visual overview:
- [Your UV-K5 V1 is bricked? 🫣 Here’s how to fix it 😌](https://www.youtube.com/watch?v=4cWtYH_bpro) by F4HWN
- [UNBRICK - Process Windows Quansheng UV-K5 , K6](https://www.youtube.com/watch?v=EmF08o5MIE0) by M0FXB
These resources are not mandatory, but they can make the procedure much easier to follow.
# 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.
Binary file not shown.
@@ -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"
@@ -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]
@@ -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]
@@ -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]
+18
View File
@@ -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"
Binary file not shown.

After

Width:  |  Height:  |  Size: 685 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 MiB

Binary file not shown.
+359
View File
@@ -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
@@ -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
}
}
+37
View File
@@ -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
}
}
+2
View File
@@ -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"