From 01d07e6d54315d5fc3a789af081c4265769306d5 Mon Sep 17 00:00:00 2001 From: HalfSweet <60973476+HalfSweet@users.noreply.github.com> Date: Thu, 5 Sep 2024 20:25:58 +0800 Subject: [PATCH] Add HSLink Pro board (#11) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * The details are as follows: - Distinguish between onboard 20P and custom pin - Support IO over JTAG - Support changing LED RST and other pins in cmakelists file - support Adjust frequency for swj clock * projects: hpm5301evklite: add jtag over single jtag * add: Bootloader工程 * add: 添加App工程 * add: 添加Github Action * fix: -Wattributes * feat: 在bootloader里面加入对于外设的初始化 * update: 更新路径 * refactor: 不需要EXPANSION配置宏了 * chore: 可通过外部宏指定FW_VER * feat: 添加用于配置的HID接口 * fix: SWD切换电平问题 * fix: 关闭HID接口的时候有些代码会编译出错 * chore: CI添加上传APP区域的bin文件 * fix: action语法错误 * release: 2.2.1 * chore: 更新CherryUSB库到1.4.0 * chore: 统一脚本路径 * chore: 添加合并的bin文件 * fix: 文件一起上传 * fix: 脚本路径错误 * chore: 使用dd来合并bin * fix: some warning * fix: HID部分接口更新到CherryUSB 1.4.0 * update: 更新WS2812库 * fix: 让退出bl的时候灯珠始终保持关闭 * chore: 将XPI0的长度修改为128k,方便检查 * feat: 添加唯一的serial number * add: app中添加WS2812驱动 * format: 格式化代码 * feat: 增加运行时LED * fix: SWDIO空闲的时候默认为输入状态,由target拉高 * release: 2.2.2 * add: 添加单SPI模拟JTAG * fix: 增加对TMS的电平转换方向控制 * fix: JTAG下DIR有误 * update: 将初始化SWDIO部分放在APP区 * fix: 先使用GPIO模拟JTAG * add: 添加README * fix: 修改P_EN的IO端口 * fix: Vref计算有误 * fix: 加入了IO模拟SWD的DIR切换 * fix: UART引脚切换 * release: 2.2.3.IO * fix: IO模拟SWD时序 * release: 2.2.4.IO * fix: 减少兼容性问题 * Merge remote-tracking branch 'RCSN/feature/refine_the_options_for_swd_jtag' into HSLink-Pro --------- Co-authored-by: Runcheng Lu --- .github/workflows/HPM-build.yml | 88 ++ .github/workflows/create_riscv32_symlink.sh | 22 + .gitmodules | 3 + CherryUSB | 2 +- DAP/Include/DAP.h | 2 + DAP/Source/DAP.c | 15 +- dap_main.c | 392 +++++--- dap_main.h | 2 +- projects/HSLink-Pro/README.md | 16 + projects/HSLink-Pro/WS2812 | 1 + projects/HSLink-Pro/bootloader/.clang-format | 8 + projects/HSLink-Pro/bootloader/.gitignore | 119 +++ projects/HSLink-Pro/bootloader/CMakeLists.txt | 38 + projects/HSLink-Pro/bootloader/README.md | 5 + projects/HSLink-Pro/bootloader/app.yaml | 2 + .../HSLink-Pro/bootloader/bootuf2/bootuf2.c | 463 ++++++++++ .../HSLink-Pro/bootloader/bootuf2/bootuf2.h | 218 +++++ .../bootloader/bootuf2/bootuf2_config.h | 27 + projects/HSLink-Pro/bootloader/flash_xip.ld | 306 +++++++ projects/HSLink-Pro/bootloader/src/main.c | 165 ++++ .../HSLink-Pro/bootloader/src/msc_bootuf2.c | 248 +++++ .../HSLink-Pro/bootloader/src/usb_config.h | 240 +++++ .../HSLink-Pro/common/BL_Setting_Common.h | 23 + .../HSLink-Pro/common/HSLink_Pro_expansion.c | 296 ++++++ .../HSLink-Pro/common/HSLink_Pro_expansion.h | 28 + projects/HSLink-Pro/common/WS2812_Conf.h | 25 + projects/HSLink-Pro/scripts/uf2conv.py | 319 +++++++ projects/HSLink-Pro/src/.gitignore | 28 + projects/HSLink-Pro/src/.version | 1 + projects/HSLink-Pro/src/CMakeLists.txt | 110 +++ projects/HSLink-Pro/src/DAP_config.h | 857 ++++++++++++++++++ projects/HSLink-Pro/src/JTAG_DP_SPI.c | 728 +++++++++++++++ projects/HSLink-Pro/src/SW_DP_SPI.c | 393 ++++++++ projects/HSLink-Pro/src/app.yaml | 2 + projects/HSLink-Pro/src/dp_common.c | 76 ++ projects/HSLink-Pro/src/main.c | 69 ++ projects/HSLink-Pro/src/swd_common.h | 322 +++++++ projects/HSLink-Pro/src/usb2uart.c | 206 +++++ projects/HSLink-Pro/src/usb_config.h | 177 ++++ projects/hpm5301evklite/CMakeLists.txt | 38 +- projects/hpm5301evklite/DAP_config.h | 238 +++-- projects/hpm5301evklite/JTAG_DP_SPI.c | 725 +++++++++++++++ projects/hpm5301evklite/SW_DP_SPI.c | 66 +- projects/hpm5301evklite/dp_common.c | 76 ++ 44 files changed, 6916 insertions(+), 269 deletions(-) create mode 100644 .github/workflows/HPM-build.yml create mode 100644 .github/workflows/create_riscv32_symlink.sh create mode 100644 projects/HSLink-Pro/README.md create mode 160000 projects/HSLink-Pro/WS2812 create mode 100644 projects/HSLink-Pro/bootloader/.clang-format create mode 100644 projects/HSLink-Pro/bootloader/.gitignore create mode 100644 projects/HSLink-Pro/bootloader/CMakeLists.txt create mode 100644 projects/HSLink-Pro/bootloader/README.md create mode 100644 projects/HSLink-Pro/bootloader/app.yaml create mode 100644 projects/HSLink-Pro/bootloader/bootuf2/bootuf2.c create mode 100644 projects/HSLink-Pro/bootloader/bootuf2/bootuf2.h create mode 100644 projects/HSLink-Pro/bootloader/bootuf2/bootuf2_config.h create mode 100644 projects/HSLink-Pro/bootloader/flash_xip.ld create mode 100644 projects/HSLink-Pro/bootloader/src/main.c create mode 100644 projects/HSLink-Pro/bootloader/src/msc_bootuf2.c create mode 100644 projects/HSLink-Pro/bootloader/src/usb_config.h create mode 100644 projects/HSLink-Pro/common/BL_Setting_Common.h create mode 100644 projects/HSLink-Pro/common/HSLink_Pro_expansion.c create mode 100644 projects/HSLink-Pro/common/HSLink_Pro_expansion.h create mode 100644 projects/HSLink-Pro/common/WS2812_Conf.h create mode 100644 projects/HSLink-Pro/scripts/uf2conv.py create mode 100644 projects/HSLink-Pro/src/.gitignore create mode 100644 projects/HSLink-Pro/src/.version create mode 100644 projects/HSLink-Pro/src/CMakeLists.txt create mode 100644 projects/HSLink-Pro/src/DAP_config.h create mode 100644 projects/HSLink-Pro/src/JTAG_DP_SPI.c create mode 100644 projects/HSLink-Pro/src/SW_DP_SPI.c create mode 100644 projects/HSLink-Pro/src/app.yaml create mode 100644 projects/HSLink-Pro/src/dp_common.c create mode 100644 projects/HSLink-Pro/src/main.c create mode 100644 projects/HSLink-Pro/src/swd_common.h create mode 100644 projects/HSLink-Pro/src/usb2uart.c create mode 100644 projects/HSLink-Pro/src/usb_config.h create mode 100644 projects/hpm5301evklite/JTAG_DP_SPI.c create mode 100644 projects/hpm5301evklite/dp_common.c diff --git a/.github/workflows/HPM-build.yml b/.github/workflows/HPM-build.yml new file mode 100644 index 0000000..893ad6d --- /dev/null +++ b/.github/workflows/HPM-build.yml @@ -0,0 +1,88 @@ +name: HPM Build + +on: + push: + paths: + - '.github/workflows/HPM-build.yml' + - 'projects/HSLink-Pro/**' + pull_request: + paths: + - '.github/workflows/HPM-build.yml' + - 'projects/HSLink-Pro/**' + + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - uses: gregdavill/setup-riscv-gnu-toolchain@v2.0 + + # 创建riscv-none-elf-到riscv32-unknown-elf-的软链接 + - name: Create riscv-none-elf- to riscv32-unknown-elf- symlink + run: | + sudo bash ./.github/workflows/create_riscv32_symlink.sh + + - name: Install HPM SDK + run: | + cd ~ + git clone https://github.com/hpmicro/sdk_env.git --recursive + + - name: Create Python Venv + run: | + python3 -m venv ~/HPM_PYTHON + source ~/HPM_PYTHON/bin/activate + pip install pyyaml jinja2 + + - uses: seanmiddleditch/gha-setup-ninja@master + + - name: Build bootloader + run: | + cd projects/HSLink-Pro/bootloader + export HPM_SDK_BASE=~/sdk_env/hpm_sdk + export GNURISCV_TOOLCHAIN_PATH=~/risv32-unknown-elf + export HPM_SDK_TOOLCHAIN_VARIANT=gcc + export PYTHON_EXECUTABLE=~/HPM_PYTHON/bin/python3 + + cmake -GNinja -DBOARD=hpm5301evklite -DHPM_BUILD_TYPE=flash_xip -DCMAKE_BUILD_TYPE=release -Dpython_exec="~/HPM_PYTHON/bin/python3" -DRV_ARCH="rv32imac_zicsr_zifencei" . -B=./build + cmake --build ./build + + - name: Build APP + run: | + cd projects/HSLink-Pro/src + export HPM_SDK_BASE=~/sdk_env/hpm_sdk + export GNURISCV_TOOLCHAIN_PATH=~/risv32-unknown-elf + export HPM_SDK_TOOLCHAIN_VARIANT=gcc + export PYTHON_EXECUTABLE=~/HPM_PYTHON/bin/python3 + + cmake -GNinja -DBOARD=hpm5301evklite -DHPM_BUILD_TYPE=flash_uf2 -DCMAKE_BUILD_TYPE=release -Dpython_exec="~/HPM_PYTHON/bin/python3" -DRV_ARCH="rv32imac_zicsr_zifencei" -DCONFIG_HSLINK_PRO_EXPANSION=ON -DCONFIG_SWDIO_DIR=IOC_PAD_PA30 . -B=./build + cmake --build ./build + + - name: Merge Bin + run: | + cd projects/HSLink-Pro + cp bootloader/build/output/HSLink-Pro-Bootloader.bin Merger.bin + dd if=src/build/output/HSLink-Pro.bin of=Merger.bin bs=1024 seek=127 conv=notrunc + + - run: | + mkdir -p releases + cd releases + cp ../projects/HSLink-Pro/bootloader/build/output/HSLink-Pro-Bootloader.bin HSLink-Pro-Bootloader.bin + cp ../projects/HSLink-Pro/src/build/output/HSLink-Pro.uf2 HSLink-Pro.uf2 + cp ../projects/HSLink-Pro/src/build/output/HSLink-Pro.bin HSLink-Pro.bin + cp ../projects/HSLink-Pro/Merger.bin Merger.bin + + - name: Upload file + uses: actions/upload-artifact@v4 + with: + name: release + path: | + releases/HSLink-Pro-Bootloader.bin + releases/HSLink-Pro.uf2 + releases/HSLink-Pro.bin + releases/Merger.bin \ No newline at end of file diff --git a/.github/workflows/create_riscv32_symlink.sh b/.github/workflows/create_riscv32_symlink.sh new file mode 100644 index 0000000..6eb653b --- /dev/null +++ b/.github/workflows/create_riscv32_symlink.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +old_path="/home/runner/work/_temp/.setup-riscv-gnu-toolchain/bin" + +new_path="/home/runner/risv32-unknown-elf/bin" +mkdir -p $new_path + +cd $old_path + +# 查找所有以 "riscv-none-elf-" 开头的文件 +for file in riscv-none-elf-*; do + # 如果文件存在 + if [[ -e "$file" ]]; then + # 构造新的链接名称 + new_link="$new_path/riscv32-unknown-elf-${file#riscv-none-elf-}" + + # 创建软链接 + ln -s "$old_path/$file" "$new_link" + + printf "Create symlink: %s -> %s\n" "$new_link" "$file" + fi +done \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 0dc7e35..7248381 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "CherryRB"] path = CherryRB url = https://github.com/cherry-embedded/CherryRB.git +[submodule "projects/HSLink-Pro/WS2812"] + path = projects/HSLink-Pro/WS2812 + url = https://github.com/HalfSweet/HPM_WS2812.git diff --git a/CherryUSB b/CherryUSB index 3c1168d..02ac1db 160000 --- a/CherryUSB +++ b/CherryUSB @@ -1 +1 @@ -Subproject commit 3c1168d58c8c288fd6013fa3a11e3afb672048e4 +Subproject commit 02ac1db3ff88c585c131a88a019f25a60d0ab2bb diff --git a/DAP/Include/DAP.h b/DAP/Include/DAP.h index d87bf7d..3b839ef 100644 --- a/DAP/Include/DAP.h +++ b/DAP/Include/DAP.h @@ -30,11 +30,13 @@ // DAP Firmware Version +#ifndef DAP_FW_VER #ifdef DAP_FW_V1 #define DAP_FW_VER "1.3.0" #else #define DAP_FW_VER "2.1.1" #endif +#endif // DAP Command IDs #define ID_DAP_Info 0x00U diff --git a/DAP/Source/DAP.c b/DAP/Source/DAP.c index f4b3eb9..6dea026 100644 --- a/DAP/Source/DAP.c +++ b/DAP/Source/DAP.c @@ -406,6 +406,7 @@ static uint32_t DAP_SWJ_Clock(const uint8_t *request, uint8_t *response) { #if ((DAP_SWD != 0) || (DAP_JTAG != 0)) uint32_t clock; uint32_t delay; + (void)delay; clock = (uint32_t)(*(request+0) << 0) | (uint32_t)(*(request+1) << 8) | @@ -417,7 +418,7 @@ static uint32_t DAP_SWJ_Clock(const uint8_t *request, uint8_t *response) { return ((4U << 16) | 1U); } -#ifndef USE_SPI_SWD +#if !defined(USE_SPI_SWD) && !defined(USE_SPI_JTAG) Set_Clock_Delay(clock); #else set_swj_clock_frequency(clock); @@ -557,12 +558,12 @@ static uint32_t DAP_JTAG_Sequence(const uint8_t *request, uint8_t *response) { sequence_count = *request++; while (sequence_count--) { - sequence_info = *request++; - count = sequence_info & JTAG_SEQUENCE_TCK; - if (count == 0U) { - count = 64U; - } - count = (count + 7U) / 8U; + sequence_info = *request++; + count = sequence_info & JTAG_SEQUENCE_TCK; + if (count == 0U) { + count = 64U; + } + count = (count + 7U) / 8U; #if (DAP_JTAG != 0) JTAG_Sequence(sequence_info, request, response); #endif diff --git a/dap_main.c b/dap_main.c index 8c9970c..e0aad1c 100644 --- a/dap_main.c +++ b/dap_main.c @@ -2,6 +2,10 @@ #include "DAP_config.h" #include "DAP.h" +#ifdef CONFIG_USE_HID_CONFIG +#include "usbd_hid.h" +#endif + #define DAP_IN_EP 0x81 #define DAP_OUT_EP 0x02 @@ -12,20 +16,53 @@ #define MSC_IN_EP 0x86 #define MSC_OUT_EP 0x07 +#ifdef CONFIG_USE_HID_CONFIG +#define HID_IN_EP 0x88 +#define HID_OUT_EP 0x09 + +#ifdef CONFIG_USB_HS +#define HID_PACKET_SIZE 1024 +#else +#define HID_PACKET_SIZE 64 +#endif + +#endif + #define USBD_VID 0x0D28 #define USBD_PID 0x0204 #define USBD_MAX_POWER 500 #define USBD_LANGID_STRING 1033 #define CMSIS_DAP_INTERFACE_SIZE (9 + 7 + 7) -#ifndef CONFIG_CHERRYDAP_USE_MSC -#define USB_CONFIG_SIZE (9 + CMSIS_DAP_INTERFACE_SIZE + CDC_ACM_DESCRIPTOR_LEN) -#define INTF_NUM 3 + +#ifdef CONFIG_CHERRYDAP_USE_MSC +#define CONFIG_MSC_DESCRIPTOR_LEN CDC_ACM_DESCRIPTOR_LEN +#define CONFIG_MSC_INTF_NUM 1 +#define MSC_INTF_NUM (0x02 + 1) +#else +#define CONFIG_MSC_DESCRIPTOR_LEN 0 +#define CONFIG_MSC_INTF_NUM 0 +#define MSC_INTF_NUM (0x02) +#endif + +#ifdef CONFIG_USE_HID_CONFIG +#define CONFIG_HID_DESCRIPTOR_LEN (9 + 9 + 7 + 7) +#define CONFIG_HID_INTF_NUM 1 +#define HID_CUSTOM_REPORT_DESC_SIZE 38 +#define HIDRAW_INTERVAL 4 +#define HID_INTF_NUM (MSC_INTF_NUM + 1) + +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[HID_PACKET_SIZE]; +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[HID_PACKET_SIZE]; #else -#define USB_CONFIG_SIZE (9 + CMSIS_DAP_INTERFACE_SIZE + CDC_ACM_DESCRIPTOR_LEN + MSC_DESCRIPTOR_LEN) -#define INTF_NUM 4 +#define CONFIG_HID_DESCRIPTOR_LEN 0 +#define CONFIG_HID_INTF_NUM 0 +#define HID_INTF_NUM (MSC_INTF_NUM) #endif +#define USB_CONFIG_SIZE (9 + CMSIS_DAP_INTERFACE_SIZE + CDC_ACM_DESCRIPTOR_LEN + CONFIG_MSC_DESCRIPTOR_LEN + CONFIG_HID_DESCRIPTOR_LEN) +#define INTF_NUM (2 + 1 + CONFIG_MSC_INTF_NUM + CONFIG_HID_INTF_NUM) + #ifdef CONFIG_USB_HS #if DAP_PACKET_SIZE != 512 #error "DAP_PACKET_SIZE must be 512 in hs" @@ -154,9 +191,11 @@ __ALIGN_BEGIN const uint8_t USBD_BinaryObjectStoreDescriptor[] = { #endif }; -const uint8_t cmsisdap_descriptor[] = { +static const uint8_t device_descriptor[] = { USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01), - /* Configuration 0 */ +}; + +static const uint8_t config_descriptor[] = { USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), /* Interface 0 */ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02), @@ -166,76 +205,168 @@ const uint8_t cmsisdap_descriptor[] = { USB_ENDPOINT_DESCRIPTOR_INIT(DAP_IN_EP, USB_ENDPOINT_TYPE_BULK, DAP_PACKET_SIZE, 0x00), CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, DAP_PACKET_SIZE, 0x00), #ifdef CONFIG_CHERRYDAP_USE_MSC - MSC_DESCRIPTOR_INIT(0x03, MSC_OUT_EP, MSC_IN_EP, DAP_PACKET_SIZE, 0x00), + MSC_DESCRIPTOR_INIT(MSC_INTF_NUM, MSC_OUT_EP, MSC_IN_EP, DAP_PACKET_SIZE, 0x00), #endif - /* String 0 (LANGID) */ - USB_LANGID_INIT(USBD_LANGID_STRING), - /* String 1 (Manufacturer) */ - 0x14, /* bLength */ - USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ - 'C', 0x00, /* wcChar0 */ - 'h', 0x00, /* wcChar1 */ - 'e', 0x00, /* wcChar2 */ - 'r', 0x00, /* wcChar3 */ - 'r', 0x00, /* wcChar4 */ - 'y', 0x00, /* wcChar5 */ - 'U', 0x00, /* wcChar6 */ - 'S', 0x00, /* wcChar7 */ - 'B', 0x00, /* wcChar8 */ - /* String 2 (Product) */ - 0x28, // bLength - USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType - 'C', 0x00, // wcChar0 - 'h', 0x00, // wcChar1 - 'e', 0x00, // wcChar2 - 'r', 0x00, // wcChar3 - 'r', 0x00, // wcChar4 - 'y', 0x00, // wcChar5 - 'U', 0x00, // wcChar6 - 'S', 0x00, // wcChar7 - 'B', 0x00, // wcChar8 - ' ', 0x00, // wcChar9 - 'C', 0x00, // wcChar10 - 'M', 0x00, // wcChar11 - 'S', 0x00, // wcChar12 - 'I', 0x00, // wcChar13 - 'S', 0x00, // wcChar14 - '-', 0x00, // wcChar15 - 'D', 0x00, // wcChar16 - 'A', 0x00, // wcChar17 - 'P', 0x00, // wcChar18 - /* String 3 (Serial Number) */ - 0x1A, // bLength - USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType - '0', 0, // wcChar0 - '1', 0, // wcChar1 - '2', 0, // wcChar2 - '3', 0, // wcChar3 - '4', 0, // wcChar4 - '5', 0, // wcChar5 - 'A', 0, // wcChar6 - 'B', 0, // wcChar7 - 'C', 0, // wcChar8 - 'D', 0, // wcChar9 - 'E', 0, // wcChar10 - 'F', 0, // wcChar11 -#ifdef CONFIG_USB_HS - /* Device Qualifier */ - 0x0a, - USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, - 0x10, - 0x02, - 0x00, - 0x00, +#ifdef CONFIG_USE_HID_CONFIG + /************** Descriptor of Custom interface *****************/ + 0x09, /* bLength: Interface Descriptor size */ + USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */ + HID_INTF_NUM, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x02, /* bNumEndpoints */ + 0x03, /* bInterfaceClass: HID */ + 0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */ + 0x00, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */ + 0, /* iInterface: Index of string descriptor */ + /******************** Descriptor of Custom HID ********************/ + 0x09, /* bLength: HID Descriptor size */ + HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */ + 0x11, /* bcdHID: HID Class Spec release number */ + 0x01, + 0x00, /* bCountryCode: Hardware target country */ + 0x01, /* bNumDescriptors: Number of HID class descriptors to follow */ + 0x22, /* bDescriptorType */ + HID_CUSTOM_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */ 0x00, - 0x40, + /******************** Descriptor of Custom in endpoint ********************/ + 0x07, /* bLength: Endpoint Descriptor size */ + USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */ + HID_IN_EP, /* bEndpointAddress: Endpoint Address (IN) */ + 0x03, /* bmAttributes: Interrupt endpoint */ + WBVAL(HID_PACKET_SIZE), /* wMaxPacketSize: 4 Byte max */ + HIDRAW_INTERVAL, /* bInterval: Polling Interval */ + /******************** Descriptor of Custom out endpoint ********************/ + 0x07, /* bLength: Endpoint Descriptor size */ + USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */ + HID_OUT_EP, /* bEndpointAddress: Endpoint Address (IN) */ + 0x03, /* bmAttributes: Interrupt endpoint */ + WBVAL(HID_PACKET_SIZE), /* wMaxPacketSize: 4 Byte max */ + HIDRAW_INTERVAL, /* bInterval: Polling Interval */ +#endif +}; + +static const uint8_t other_speed_config_descriptor[] = { + USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), + /* Interface 0 */ + USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02), + /* Endpoint OUT 2 */ + USB_ENDPOINT_DESCRIPTOR_INIT(DAP_OUT_EP, USB_ENDPOINT_TYPE_BULK, DAP_PACKET_SIZE, 0x00), + /* Endpoint IN 1 */ + USB_ENDPOINT_DESCRIPTOR_INIT(DAP_IN_EP, USB_ENDPOINT_TYPE_BULK, DAP_PACKET_SIZE, 0x00), + CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, DAP_PACKET_SIZE, 0x00), +#ifdef CONFIG_CHERRYDAP_USE_MSC + MSC_DESCRIPTOR_INIT(MSC_INTF_NUM, MSC_OUT_EP, MSC_IN_EP, DAP_PACKET_SIZE, 0x00), +#endif +#ifdef CONFIG_USE_HID_CONFIG + /************** Descriptor of Custom interface *****************/ + 0x09, /* bLength: Interface Descriptor size */ + USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */ + HID_INTF_NUM, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x02, /* bNumEndpoints */ + 0x03, /* bInterfaceClass: HID */ + 0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */ + 0x00, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */ + 0, /* iInterface: Index of string descriptor */ + /******************** Descriptor of Custom HID ********************/ + 0x09, /* bLength: HID Descriptor size */ + HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */ + 0x11, /* bcdHID: HID Class Spec release number */ 0x01, + 0x00, /* bCountryCode: Hardware target country */ + 0x01, /* bNumDescriptors: Number of HID class descriptors to follow */ + 0x22, /* bDescriptorType */ + HID_CUSTOM_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */ 0x00, + /******************** Descriptor of Custom in endpoint ********************/ + 0x07, /* bLength: Endpoint Descriptor size */ + USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */ + HID_IN_EP, /* bEndpointAddress: Endpoint Address (IN) */ + 0x03, /* bmAttributes: Interrupt endpoint */ + WBVAL(HID_PACKET_SIZE), /* wMaxPacketSize: 4 Byte max */ + HIDRAW_INTERVAL, /* bInterval: Polling Interval */ + /******************** Descriptor of Custom out endpoint ********************/ + 0x07, /* bLength: Endpoint Descriptor size */ + USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */ + HID_OUT_EP, /* bEndpointAddress: Endpoint Address (IN) */ + 0x03, /* bmAttributes: Interrupt endpoint */ + WBVAL(HID_PACKET_SIZE), /* wMaxPacketSize: 4 Byte max */ + HIDRAW_INTERVAL, /* bInterval: Polling Interval */ #endif - /* End */ - 0x00 }; +char *string_descriptors[] = { + (char[]){ 0x09, 0x04 }, /* Langid */ + "CherryUSB", /* Manufacturer */ + "CherryUSB CMSIS-DAP", /* Product */ + "00000000000000000123456789ABCDEF", /* Serial Number */ +}; + +static const uint8_t device_quality_descriptor[] = { + USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_1, 0x00, 0x00, 0x00, 0x01), +}; + +static const uint8_t *device_descriptor_callback(uint8_t speed) +{ + (void)speed; + return device_descriptor; +} + +static const uint8_t *config_descriptor_callback(uint8_t speed) +{ + (void)speed; + return config_descriptor; +} + +static const uint8_t *device_quality_descriptor_callback(uint8_t speed) +{ + (void)speed; + return device_quality_descriptor; +} + +static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed) +{ + (void)speed; + return other_speed_config_descriptor; +} + +static const char *string_descriptor_callback(uint8_t speed, uint8_t index) +{ + (void)speed; + + if (index >= (sizeof(string_descriptors) / sizeof(char *))) { + return NULL; + } + return string_descriptors[index]; +} + +#ifdef CONFIG_USE_HID_CONFIG +/*!< custom hid report descriptor */ +static const uint8_t hid_custom_report_desc[HID_CUSTOM_REPORT_DESC_SIZE] = { + /* USER CODE BEGIN 0 */ + 0x06, 0x00, 0xff, /* USAGE_PAGE (Vendor Defined Page 1) */ + 0x09, 0x01, /* USAGE (Vendor Usage 1) */ + 0xa1, 0x01, /* COLLECTION (Application) */ + 0x85, 0x02, /* REPORT ID (0x02) */ + 0x09, 0x02, /* USAGE (Vendor Usage 1) */ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ + 0x25, 0xff, /*LOGICAL_MAXIMUM (255) */ + 0x75, 0x08, /* REPORT_SIZE (8) */ + 0x96, 0xff, 0x03, /* REPORT_COUNT (63) */ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ + /* <___________________________________________________> */ + 0x85, 0x01, /* REPORT ID (0x01) */ + 0x09, 0x03, /* USAGE (Vendor Usage 1) */ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ + 0x25, 0xff, /* LOGICAL_MAXIMUM (255) */ + 0x75, 0x08, /* REPORT_SIZE (8) */ + 0x96, 0xff, 0x03, /* REPORT_COUNT (63) */ + 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ + /* USER CODE END 0 */ + 0xC0 /* END_COLLECTION */ +}; +#endif + static volatile uint16_t USB_RequestIndexI; // Request Index In static volatile uint16_t USB_RequestIndexO; // Request Index Out static volatile uint16_t USB_RequestCountI; // Request Count In @@ -270,8 +401,9 @@ static volatile uint8_t uarttx_idle_flag = 0; USB_NOCACHE_RAM_SECTION chry_ringbuffer_t g_uartrx; USB_NOCACHE_RAM_SECTION chry_ringbuffer_t g_usbrx; -void usbd_event_handler(uint8_t event) +void usbd_event_handler(uint8_t busid, uint8_t event) { + (void)busid; switch (event) { case USBD_EVENT_RESET: usbrx_idle_flag = 0; @@ -291,8 +423,13 @@ void usbd_event_handler(uint8_t event) /* setup first out ep read transfer */ USB_RequestIdle = 0U; - usbd_ep_start_read(DAP_OUT_EP, USB_Request[0], DAP_PACKET_SIZE); - usbd_ep_start_read(CDC_OUT_EP, usb_tmpbuffer, DAP_PACKET_SIZE); + usbd_ep_start_read(0, DAP_OUT_EP, USB_Request[0], DAP_PACKET_SIZE); + usbd_ep_start_read(0, CDC_OUT_EP, usb_tmpbuffer, DAP_PACKET_SIZE); + +#ifdef CONFIG_USE_HID_CONFIG + usbd_ep_start_read(0, HID_OUT_EP, read_buffer, HID_PACKET_SIZE); +#endif + break; case USBD_EVENT_SET_REMOTE_WAKEUP: break; @@ -304,8 +441,9 @@ void usbd_event_handler(uint8_t event) } } -void dap_out_callback(uint8_t ep, uint32_t nbytes) +void dap_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes) { + (void)busid; if (USB_Request[USB_RequestIndexI][0] == ID_DAP_TransferAbort) { DAP_TransferAbort = 1U; } else { @@ -318,17 +456,18 @@ void dap_out_callback(uint8_t ep, uint32_t nbytes) // Start reception of next request packet if ((uint16_t)(USB_RequestCountI - USB_RequestCountO) != DAP_PACKET_COUNT) { - usbd_ep_start_read(DAP_OUT_EP, USB_Request[USB_RequestIndexI], DAP_PACKET_SIZE); + usbd_ep_start_read(0, DAP_OUT_EP, USB_Request[USB_RequestIndexI], DAP_PACKET_SIZE); } else { USB_RequestIdle = 1U; } } -void dap_in_callback(uint8_t ep, uint32_t nbytes) +void dap_in_callback(uint8_t busid, uint8_t ep, uint32_t nbytes) { + (void)busid; if (USB_ResponseCountI != USB_ResponseCountO) { // Load data from response buffer to be sent back - usbd_ep_start_write(DAP_IN_EP, USB_Response[USB_ResponseIndexO], USB_RespSize[USB_ResponseIndexO]); + usbd_ep_start_write(0, DAP_IN_EP, USB_Response[USB_ResponseIndexO], USB_RespSize[USB_ResponseIndexO]); USB_ResponseIndexO++; if (USB_ResponseIndexO == DAP_PACKET_COUNT) { USB_ResponseIndexO = 0U; @@ -339,29 +478,31 @@ void dap_in_callback(uint8_t ep, uint32_t nbytes) } } -void usbd_cdc_acm_bulk_out(uint8_t ep, uint32_t nbytes) +void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes) { + (void)busid; chry_ringbuffer_write(&g_usbrx, usb_tmpbuffer, nbytes); if (chry_ringbuffer_get_free(&g_usbrx) >= DAP_PACKET_SIZE) { - usbd_ep_start_read(CDC_OUT_EP, usb_tmpbuffer, DAP_PACKET_SIZE); + usbd_ep_start_read(0, CDC_OUT_EP, usb_tmpbuffer, DAP_PACKET_SIZE); } else { usbrx_idle_flag = 1; } } -void usbd_cdc_acm_bulk_in(uint8_t ep, uint32_t nbytes) +void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes) { + (void)busid; uint32_t size; uint8_t *buffer; chry_ringbuffer_linear_read_done(&g_uartrx, nbytes); if ((nbytes % DAP_PACKET_SIZE) == 0 && nbytes) { /* send zlp */ - usbd_ep_start_write(CDC_IN_EP, NULL, 0); + usbd_ep_start_write(0, CDC_IN_EP, NULL, 0); } else { if (chry_ringbuffer_get_used(&g_uartrx)) { buffer = chry_ringbuffer_linear_read_setup(&g_uartrx, &size); - usbd_ep_start_write(CDC_IN_EP, buffer, size); + usbd_ep_start_write(0, CDC_IN_EP, buffer, size); } else { usbtx_idle_flag = 1; } @@ -388,10 +529,40 @@ static struct usbd_endpoint cdc_in_ep = { .ep_cb = usbd_cdc_acm_bulk_in }; +#ifdef CONFIG_USE_HID_CONFIG + +__WEAK void usbd_hid_custom_in_callback(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + (void)busid; + USB_LOG_RAW("actual in len:%d\r\n", nbytes); + // custom_state = HID_STATE_IDLE; +} + +__WEAK void usbd_hid_custom_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + (void)busid; + USB_LOG_RAW("actual out len:%d\r\n", nbytes); + usbd_ep_start_read(0, ep, read_buffer, HID_PACKET_SIZE); + read_buffer[0] = 0x02; /* IN: report id */ + usbd_ep_start_write(0, HID_IN_EP, read_buffer, nbytes); +} + +static struct usbd_endpoint hid_custom_in_ep = { + .ep_cb = usbd_hid_custom_in_callback, + .ep_addr = HID_IN_EP +}; + +static struct usbd_endpoint hid_custom_out_ep = { + .ep_cb = usbd_hid_custom_out_callback, + .ep_addr = HID_OUT_EP +}; +#endif + struct usbd_interface dap_intf; struct usbd_interface intf1; struct usbd_interface intf2; struct usbd_interface intf3; +struct usbd_interface hid_intf; static void chry_dap_state_init(void) { @@ -419,7 +590,17 @@ struct usb_bos_descriptor bos_desc = { .string_len = USBD_BOS_WTOTALLENGTH }; -void chry_dap_init(void) +const struct usb_descriptor cmsisdap_descriptor = { + .device_descriptor_callback = device_descriptor_callback, + .config_descriptor_callback = config_descriptor_callback, + .device_quality_descriptor_callback = device_quality_descriptor_callback, + .other_speed_descriptor_callback = other_speed_config_descriptor_callback, + .string_descriptor_callback = string_descriptor_callback, + .bos_descriptor = &bos_desc, + .msosv2_descriptor = &msosv2_desc, +}; + +void chry_dap_init(uint8_t busid, uint32_t reg_base) { chry_ringbuffer_init(&g_uartrx, uartrx_ringbuffer, CONFIG_UARTRX_RINGBUF_SIZE); chry_ringbuffer_init(&g_usbrx, usbrx_ringbuffer, CONFIG_USBRX_RINGBUF_SIZE); @@ -428,25 +609,32 @@ void chry_dap_init(void) chry_dap_state_init(); - usbd_desc_register(cmsisdap_descriptor); - usbd_bos_desc_register(&bos_desc); - usbd_msosv2_desc_register(&msosv2_desc); + usbd_desc_register(0, &cmsisdap_descriptor); + // usbd_bos_desc_register(0, &bos_desc); + // usbd_msosv2_desc_register(0, &msosv2_desc); /*!< winusb */ - usbd_add_interface(&dap_intf); - usbd_add_endpoint(&dap_out_ep); - usbd_add_endpoint(&dap_in_ep); + usbd_add_interface(0, &dap_intf); + usbd_add_endpoint(0, &dap_out_ep); + usbd_add_endpoint(0, &dap_in_ep); /*!< cdc acm */ - usbd_add_interface(usbd_cdc_acm_init_intf(&intf1)); - usbd_add_interface(usbd_cdc_acm_init_intf(&intf2)); - usbd_add_endpoint(&cdc_out_ep); - usbd_add_endpoint(&cdc_in_ep); + usbd_add_interface(0, usbd_cdc_acm_init_intf(0, &intf1)); + usbd_add_interface(0, usbd_cdc_acm_init_intf(0, &intf2)); + usbd_add_endpoint(0, &cdc_out_ep); + usbd_add_endpoint(0, &cdc_in_ep); + +#ifdef CONFIG_USE_HID_CONFIG + /*!< hid */ + usbd_add_interface(0, usbd_hid_init_intf(0, &hid_intf, hid_custom_report_desc, HID_CUSTOM_REPORT_DESC_SIZE)); + usbd_add_endpoint(0, &hid_custom_in_ep); + usbd_add_endpoint(0, &hid_custom_out_ep); +#endif #ifdef CONFIG_CHERRYDAP_USE_MSC - usbd_add_interface(usbd_msc_init_intf(&intf3, MSC_OUT_EP, MSC_IN_EP)); + usbd_add_interface(0, usbd_msc_init_intf(0, &intf3, MSC_OUT_EP, MSC_IN_EP)); #endif - usbd_initialize(); + usbd_initialize(busid, reg_base, usbd_event_handler); } void chry_dap_handle(void) @@ -485,7 +673,7 @@ void chry_dap_handle(void) if (USB_RequestIdle) { if ((uint16_t)(USB_RequestCountI - USB_RequestCountO) != DAP_PACKET_COUNT) { USB_RequestIdle = 0U; - usbd_ep_start_read(DAP_OUT_EP, USB_Request[USB_RequestIndexI], DAP_PACKET_SIZE); + usbd_ep_start_read(0, DAP_OUT_EP, USB_Request[USB_RequestIndexI], DAP_PACKET_SIZE); } } @@ -505,14 +693,15 @@ void chry_dap_handle(void) } USB_ResponseCountO++; USB_ResponseIdle = 0U; - usbd_ep_start_write(DAP_IN_EP, USB_Response[n], USB_RespSize[n]); + usbd_ep_start_write(0, DAP_IN_EP, USB_Response[n], USB_RespSize[n]); } } } } -void usbd_cdc_acm_set_line_coding(uint8_t intf, struct cdc_line_coding *line_coding) +void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding) { + (void)busid; if (memcmp(line_coding, (uint8_t *)&g_cdc_lincoding, sizeof(struct cdc_line_coding)) != 0) { memcpy((uint8_t *)&g_cdc_lincoding, line_coding, sizeof(struct cdc_line_coding)); config_uart = 1; @@ -520,8 +709,9 @@ void usbd_cdc_acm_set_line_coding(uint8_t intf, struct cdc_line_coding *line_cod } } -void usbd_cdc_acm_get_line_coding(uint8_t intf, struct cdc_line_coding *line_coding) +void usbd_cdc_acm_get_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding) { + (void)busid; memcpy(line_coding, (uint8_t *)&g_cdc_lincoding, sizeof(struct cdc_line_coding)); } @@ -557,7 +747,7 @@ void chry_dap_usb2uart_handle(void) usbtx_idle_flag = 0; /* start first transfer */ buffer = chry_ringbuffer_linear_read_setup(&g_uartrx, &size); - usbd_ep_start_write(CDC_IN_EP, buffer, size); + usbd_ep_start_write(0, CDC_IN_EP, buffer, size); } } @@ -575,7 +765,7 @@ void chry_dap_usb2uart_handle(void) if (usbrx_idle_flag) { if (chry_ringbuffer_get_free(&g_usbrx) >= DAP_PACKET_SIZE) { usbrx_idle_flag = 0; - usbd_ep_start_read(CDC_OUT_EP, usb_tmpbuffer, DAP_PACKET_SIZE); + usbd_ep_start_read(0, CDC_OUT_EP, usb_tmpbuffer, DAP_PACKET_SIZE); } } } diff --git a/dap_main.h b/dap_main.h index f1278b5..cb14914 100644 --- a/dap_main.h +++ b/dap_main.h @@ -9,7 +9,7 @@ extern chry_ringbuffer_t g_uartrx; extern chry_ringbuffer_t g_usbrx; -void chry_dap_init(void); +void chry_dap_init(uint8_t busid, uint32_t base); void chry_dap_handle(void); void chry_dap_usb2uart_handle(void); diff --git a/projects/HSLink-Pro/README.md b/projects/HSLink-Pro/README.md new file mode 100644 index 0000000..7582ff3 --- /dev/null +++ b/projects/HSLink-Pro/README.md @@ -0,0 +1,16 @@ +# HSLink Pro + +## 升级流程 + +1. 长按`BL`按钮5秒以上即可进入升级模式,此时电脑上会出现一个`CHERRYUF2`的移动存储设备,将升级的`.uf2`文件拖入其中即可。最新的固件可以在或者QQ群内自行获取。 + +## FAQ + +Q:为什么我插上去以后,`keil(MDK5)`没有反应? +A:请检查版本号,只有5.27以上的版本才能支持CMSIS-DAP V2版本,如在此版本号以下的请自行升级。 + +## 已知问题 + +- [ ] VREF输出电平有误,实际为VREF/2 +- [ ] TVcc和5V输出引脚定义有误 +- [ ] PyOCD和Probe-rs无法正常连接 diff --git a/projects/HSLink-Pro/WS2812 b/projects/HSLink-Pro/WS2812 new file mode 160000 index 0000000..20d67b6 --- /dev/null +++ b/projects/HSLink-Pro/WS2812 @@ -0,0 +1 @@ +Subproject commit 20d67b6dd634068dd9ccb1134f3da97892b754c0 diff --git a/projects/HSLink-Pro/bootloader/.clang-format b/projects/HSLink-Pro/bootloader/.clang-format new file mode 100644 index 0000000..2b4ffc1 --- /dev/null +++ b/projects/HSLink-Pro/bootloader/.clang-format @@ -0,0 +1,8 @@ +BasedOnStyle: Microsoft +AccessModifierOffset: -4 +AlignConsecutiveMacros: true +AlignTrailingComments: true +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: false +BreakBeforeBraces: Allman +ColumnLimit: 0 \ No newline at end of file diff --git a/projects/HSLink-Pro/bootloader/.gitignore b/projects/HSLink-Pro/bootloader/.gitignore new file mode 100644 index 0000000..4ddec47 --- /dev/null +++ b/projects/HSLink-Pro/bootloader/.gitignore @@ -0,0 +1,119 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +# *.lib +# *.a +# *.la +# *.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +.vscode/ +*.rar +*.o +*.d +*.crf +*.htm +*.dep +*.map +*.bak +*.lnp +*.lst +*.ini +*.iex +*.sct +*.scvd +*.uvguix +*.dbg* +*.uvguix.* +.mxproject +*.uvguit +*.uvgui.* + +RTE/ +Templates/ +Examples/ + +!*.uvoptx +!*.h +!*.c +!*.ioc +!*.axf +!*.bin +!*.hex + +JlinkLog.txt +*.axf + +*.hex + +*.pkg + +Listings/* + +Objects/* +*.uvoptx + +MDK-ARM/out/* + +MDK-ARM/tmp/* +*.log + +build/ + +*.idx + +.idea/ + +cmake-build* + +projects/standard/Output/bin/app.bin +projects/standard/Output/bin/res.bin +projects/standard/Output/bin/xcfg.bin +projects/standard/Output/bin/*.h +projects/standard/Output/bin/app.dcf +projects/standard/Output/bin/app.rv32 +projects/standard/Output/bin/map.txt \ No newline at end of file diff --git a/projects/HSLink-Pro/bootloader/CMakeLists.txt b/projects/HSLink-Pro/bootloader/CMakeLists.txt new file mode 100644 index 0000000..44b5848 --- /dev/null +++ b/projects/HSLink-Pro/bootloader/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.13) + +set(APP_NAME HSLink-Pro-Bootloader) + +set(CONFIG_DMA_MGR 1) + +set(CONFIG_CHERRYUSB 1) +set(CONFIG_USB_DEVICE 1) +set(CONFIG_USB_DEVICE_MSC 1) +set(CUSTOM_GCC_LINKER_FILE + ${CMAKE_CURRENT_SOURCE_DIR}/flash_xip.ld +) + +find_package(hpm-sdk REQUIRED HINTS $ENV{HPM_SDK_BASE}) + +project(HSLink-Pro-Bootloader) + +add_subdirectory(../WS2812 ${CMAKE_CURRENT_BINARY_DIR}/ws2812) + +sdk_compile_definitions( +# -DBOARD_SHOW_CLOCK=0 + -DBOARD_SHOW_BANNER=0 +) + +sdk_app_src(src/main.c) +sdk_app_src(src/msc_bootuf2.c) +sdk_app_src(bootuf2/bootuf2.c) +sdk_app_inc(bootuf2) + +sdk_inc(src) + +sdk_inc(../common) + +sdk_compile_definitions(-DPRODUCT_STRING="HSLink Pro") +sdk_compile_definitions(-DCONFIG_USE_HID_CONFIG=1) +sdk_app_src(../common/HSLink_Pro_expansion.c) + +#generate_ide_projects() \ No newline at end of file diff --git a/projects/HSLink-Pro/bootloader/README.md b/projects/HSLink-Pro/bootloader/README.md new file mode 100644 index 0000000..f757ed8 --- /dev/null +++ b/projects/HSLink-Pro/bootloader/README.md @@ -0,0 +1,5 @@ +# CherryDAP HPM5301系列的Bootloader + +## 注意事项 +1. Boot区预留为128k,APP从`0x80020000`开始。 +2. APP工程的`HPM_BUILD_TYPE`必须为`flash_uf2`,编译出来的bin才可以转换为`.uf2`升级 diff --git a/projects/HSLink-Pro/bootloader/app.yaml b/projects/HSLink-Pro/bootloader/app.yaml new file mode 100644 index 0000000..effbeab --- /dev/null +++ b/projects/HSLink-Pro/bootloader/app.yaml @@ -0,0 +1,2 @@ +minimum_sdk_version: + - 1.6.0 \ No newline at end of file diff --git a/projects/HSLink-Pro/bootloader/bootuf2/bootuf2.c b/projects/HSLink-Pro/bootloader/bootuf2/bootuf2.c new file mode 100644 index 0000000..0743100 --- /dev/null +++ b/projects/HSLink-Pro/bootloader/bootuf2/bootuf2.c @@ -0,0 +1,463 @@ +/* +* Copyright (c) 2024, sakumisu +* Copyright (c) 2024, Egahp +* +* SPDX-License-Identifier: Apache-2.0 +*/ +#include "bootuf2.h" +#include "usbd_core.h" + +char file_INFO[] = { + "CherryUSB UF2 BOOT\r\n" + "Model: " CONFIG_PRODUCT "\r\n" + "Board-ID: " CONFIG_BOARD "\r\n" +}; + +const char file_IDEX[] = { + "\n" + "" + "" + "" + "" + "\n" +}; + +const char file_JOIN[] = { + "\n" + "" + "" + "" + "" + "\n" +}; + +const char file_ID__[12] = BOOTUF2_FAMILYID_ARRAY; + +static struct bootuf2_FILE files[] = { + [0] = { .Name = file_ID__, .Content = NULL, .FileSize = 0 }, + [1] = { .Name = "INFO_UF2TXT", .Content = file_INFO, .FileSize = sizeof(file_INFO) - 1 }, + [2] = { .Name = "INDEX HTM", .Content = file_IDEX, .FileSize = sizeof(file_IDEX) - 1 }, + [3] = { .Name = "JOIN HTM", .Content = file_JOIN, .FileSize = sizeof(file_JOIN) - 1 }, +}; + +struct bootuf2_data { + const struct bootuf2_DBR *const DBR; + struct bootuf2_STATE *const STATE; + uint8_t *const fbuff; + uint8_t *const erase; + size_t page_count; + uint8_t *const cache; + const size_t cache_size; + uint32_t cached_address; + size_t cached_bytes; +}; + +/*!< define DBRs */ +static const struct bootuf2_DBR bootuf2_DBR = { + .JMPInstruction = { 0xEB, 0x3C, 0x90 }, + .OEM = "UF2 UF2 ", + .BPB = { + .BytesPerSector = CONFIG_BOOTUF2_SECTOR_SIZE, + .SectorsPerCluster = CONFIG_BOOTUF2_SECTOR_PER_CLUSTER, + .ReservedSectors = CONFIG_BOOTUF2_SECTOR_RESERVED, + .NumberOfFAT = CONFIG_BOOTUF2_NUM_OF_FAT, + .RootEntries = CONFIG_BOOTUF2_ROOT_ENTRIES, + .Sectors = (BOOTUF2_SECTORS(0) > 0xFFFF) ? 0 : BOOTUF2_SECTORS(0), + .MediaDescriptor = 0xF8, + .SectorsPerFAT = BOOTUF2_SECTORS_PER_FAT(0), + .SectorsPerTrack = 1, + .Heads = 1, + .HiddenSectors = 0, + .SectorsOver32MB = (BOOTUF2_SECTORS(0) > 0xFFFF) ? BOOTUF2_SECTORS(0) : 0, + .BIOSDrive = 0x80, + .Reserved = 0, + .ExtendBootSignature = 0x29, + .VolumeSerialNumber = 0x00420042, + .VolumeLabel = "CHERRYUF2", + .FileSystem = "FAT16 ", + }, +}; + +/*!< define mask */ +static uint8_t __attribute__((aligned(4))) bootuf2_mask[BOOTUF2_BLOCKSMAX / 8 + 1] = { 0 }; + +/*!< define state */ +static struct bootuf2_STATE bootuf2_STATE = { + .NumberOfBlock = 0, + .NumberOfWritten = 0, + .Mask = bootuf2_mask, + .Enable = 1, +}; + +/*!< define flash cache */ +static uint8_t __attribute__((aligned(4))) bootuf2_disk_cache[CONFIG_BOOTUF2_CACHE_SIZE]; + +/*!< define flash buff */ +static uint8_t __attribute__((aligned(4))) bootuf2_disk_fbuff[256]; + +/*!< define erase flag buff */ +static uint8_t __attribute__((aligned(4))) bootuf2_disk_erase[BOOTUF2_DIVCEIL(CONFIG_BOOTUF2_PAGE_COUNTMAX, 8)]; + +/*!< define disk */ +static struct bootuf2_data bootuf2_disk = { + .DBR = &bootuf2_DBR, + .STATE = &bootuf2_STATE, + .fbuff = bootuf2_disk_fbuff, + .erase = bootuf2_disk_erase, + .cache = bootuf2_disk_cache, + .cache_size = sizeof(bootuf2_disk_cache), +}; + +static void fname_copy(char *dst, char const *src, uint16_t len) +{ + for (size_t i = 0; i < len; ++i) { + if (*src) + *dst++ = *src++; + else + *dst++ = ' '; + } +} + +static void fcalculate_cluster(struct bootuf2_data *ctx) +{ + /*!< init files cluster */ + uint16_t cluster_beg = 2; + for (int i = 0; i < ARRAY_SIZE(files); i++) { + files[i].ClusterBeg = cluster_beg; + files[i].ClusterEnd = -1 + cluster_beg + + BOOTUF2_DIVCEIL(files[i].FileSize, + ctx->DBR->BPB.BytesPerSector * + ctx->DBR->BPB.SectorsPerCluster); + cluster_beg = files[i].ClusterEnd + 1; + } +} + +static int ffind_by_cluster(uint32_t cluster) +{ + if (cluster >= 0xFFF0) { + return -1; + } + + for (uint32_t i = 0; i < ARRAY_SIZE(files); i++) { + if ((files[i].ClusterBeg <= cluster) && + (cluster <= files[i].ClusterEnd)) { + return i; + } + } + + return -1; +} + +static bool bootuf2block_check_writable(struct bootuf2_STATE *STATE, + struct bootuf2_BLOCK *uf2, uint32_t block_max) +{ + if (uf2->NumberOfBlock) { + if (uf2->BlockIndex < block_max) { + uint8_t mask = 1 << (uf2->BlockIndex % 8); + uint32_t pos = uf2->BlockIndex / 8; + + if ((STATE->Mask[pos] & mask) == 0) { + return true; + } + } + } + + return false; +} + +static void bootuf2block_state_update(struct bootuf2_STATE *STATE, + struct bootuf2_BLOCK *uf2, uint32_t block_max) +{ + if (uf2->NumberOfBlock) { + if (STATE->NumberOfBlock != uf2->NumberOfBlock) { + if ((uf2->NumberOfBlock >= BOOTUF2_BLOCKSMAX) || + STATE->NumberOfBlock) { + /*!< uf2 block only can be update once */ + /*!< this will cause never auto reboot */ + STATE->NumberOfBlock = 0xffffffff; + } else { + STATE->NumberOfBlock = uf2->NumberOfBlock; + } + } + + if (uf2->BlockIndex < block_max) { + uint8_t mask = 1 << (uf2->BlockIndex % 8); + uint32_t pos = uf2->BlockIndex / 8; + + if ((STATE->Mask[pos] & mask) == 0) { + STATE->Mask[pos] |= mask; + STATE->NumberOfWritten++; + } + } + } + + USB_LOG_DBG("UF2 block total %d written %d index %d\r\n", + uf2->NumberOfBlock, STATE->NumberOfWritten, uf2->BlockIndex); +} + +static bool bootuf2block_state_check(struct bootuf2_STATE *STATE) +{ + return (STATE->NumberOfWritten >= STATE->NumberOfBlock) && + STATE->NumberOfBlock; +} + +static int bootuf2_flash_flush(struct bootuf2_data *ctx) +{ + int err; + + if (ctx->cached_bytes == 0) { + return 0; + } + + err = bootuf2_flash_write(ctx->cached_address, ctx->cache, ctx->cached_bytes); + + if (err) { + USB_LOG_ERR("UF2 slot flash write error %d at offset %08lx len %d\r\n", + err, ctx->cached_address, ctx->cached_bytes); + return -1; + } + + ctx->cached_bytes = 0; + + return 0; +} + +int bootuf2_flash_write_internal(struct bootuf2_data *ctx, struct bootuf2_BLOCK *uf2) +{ + /*!< 1.cache not empty and address not continue */ + /*!< 2.cache full */ + if ((ctx->cached_bytes && ((ctx->cached_address + ctx->cached_bytes) != uf2->TargetAddress)) || + (ctx->cached_bytes == ctx->cache_size)) { + int err = bootuf2_flash_flush(ctx); + if (err) + return err; + } + + /*!< write len always is 256, cache_size always is a multiple of 256 */ + memcpy(ctx->cache + ctx->cached_bytes, uf2->Data, uf2->PayloadSize); + + ctx->cached_address = uf2->TargetAddress - ctx->cached_bytes; + ctx->cached_bytes += uf2->PayloadSize; + + return 0; +} + +void bootuf2_init(void) +{ + struct bootuf2_data *ctx; + + ctx = &bootuf2_disk; + + fcalculate_cluster(ctx); + + ctx->cached_bytes = 0; + ctx->cached_address = 0; +} + +int boot2uf2_read_sector(uint32_t start_sector, uint8_t *buff, uint32_t sector_count) +{ + struct bootuf2_data *ctx; + + ctx = &bootuf2_disk; + + while (sector_count) { + memset(buff, 0, ctx->DBR->BPB.BytesPerSector); + + uint32_t sector_relative = start_sector; + + /*!< DBR sector */ + if (start_sector == BOOTUF2_SECTOR_DBR_END) { + memcpy(buff, ctx->DBR, sizeof(struct bootuf2_DBR)); + buff[510] = 0x55; + buff[511] = 0xaa; + } + /*!< FAT sector */ + else if (start_sector < BOOTUF2_SECTOR_FAT_END(ctx->DBR)) { + uint16_t *buff16 = (uint16_t *)buff; + + sector_relative -= BOOTUF2_SECTOR_RSVD_END(ctx->DBR); + + /*!< Perform the same operation on all FAT tables */ + while (sector_relative >= ctx->DBR->BPB.SectorsPerFAT) { + sector_relative -= ctx->DBR->BPB.SectorsPerFAT; + } + + uint16_t cluster_unused = files[ARRAY_SIZE(files) - 1].ClusterEnd + 1; + uint16_t cluster_absolute_first = sector_relative * + BOOTUF2_FAT16_PER_SECTOR(ctx->DBR); + + /*!< cluster used link to chain, or unsed */ + for (uint16_t i = 0, cluster_absolute = cluster_absolute_first; + i < BOOTUF2_FAT16_PER_SECTOR(ctx->DBR); + i++, cluster_absolute++) { + if (cluster_absolute >= cluster_unused) + buff16[i] = 0; + else + buff16[i] = cluster_absolute + 1; + } + + /*!< cluster 0 and 1 */ + if (sector_relative == 0) { + buff[0] = ctx->DBR->BPB.MediaDescriptor; + buff[1] = 0xff; + buff16[1] = 0xffff; + } + + /*!< cluster end of file */ + for (uint32_t i = 0; i < ARRAY_SIZE(files); i++) { + uint16_t cluster_file_last = files[i].ClusterEnd; + + if (cluster_file_last >= cluster_absolute_first) { + uint16_t idx = cluster_file_last - cluster_absolute_first; + if (idx < BOOTUF2_FAT16_PER_SECTOR(ctx->DBR)) { + buff16[idx] = 0xffff; + } + } + } + } + /*!< root entries */ + else if (start_sector < BOOTUF2_SECTOR_ROOT_END(ctx->DBR)) { + sector_relative -= BOOTUF2_SECTOR_FAT_END(ctx->DBR); + + struct bootuf2_ENTRY *ent = (void *)buff; + int remain_entries = BOOTUF2_ENTRY_PER_SECTOR(ctx->DBR); + + uint32_t file_index_first; + + /*!< volume label entry */ + if (sector_relative == 0) { + fname_copy(ent->Name, (char const *)ctx->DBR->BPB.VolumeLabel, 11); + ent->Attribute = 0x28; + ent++; + remain_entries--; + file_index_first = 0; + } else { + /*!< -1 to account for volume label in first sector */ + file_index_first = sector_relative * BOOTUF2_ENTRY_PER_SECTOR(ctx->DBR) - 1; + } + + for (uint32_t idx = file_index_first; + (remain_entries > 0) && (idx < ARRAY_SIZE(files)); + idx++, ent++) { + const uint32_t cluster_beg = files[idx].ClusterBeg; + + const struct bootuf2_FILE *f = &files[idx]; + + if ((0 == f->FileSize) && + (0 != idx)) { + continue; + } + + fname_copy(ent->Name, f->Name, 11); + ent->Attribute = 0x05; + ent->CreateTimeTeenth = BOOTUF2_SECONDS_INT % 2 * 100; + ent->CreateTime = BOOTUF2_DOS_TIME; + ent->CreateDate = BOOTUF2_DOS_DATE; + ent->LastAccessDate = BOOTUF2_DOS_DATE; + ent->FirstClustH16 = cluster_beg >> 16; + ent->UpdateTime = BOOTUF2_DOS_TIME; + ent->UpdateDate = BOOTUF2_DOS_DATE; + ent->FirstClustL16 = cluster_beg & 0xffff; + ent->FileSize = f->FileSize; + } + } + /*!< data */ + else if (start_sector < BOOTUF2_SECTOR_DATA_END(ctx->DBR)) { + sector_relative -= BOOTUF2_SECTOR_ROOT_END(ctx->DBR); + + int fid = ffind_by_cluster(2 + sector_relative / ctx->DBR->BPB.SectorsPerCluster); + + if (fid >= 0) { + const struct bootuf2_FILE *f = &files[fid]; + + uint32_t sector_relative_file = + sector_relative - + (files[fid].ClusterBeg - 2) * ctx->DBR->BPB.SectorsPerCluster; + + size_t fcontent_offset = sector_relative_file * ctx->DBR->BPB.BytesPerSector; + size_t fcontent_length = f->FileSize; + + if (fcontent_length > fcontent_offset) { + const void *src = (void *)((uint8_t *)(f->Content) + fcontent_offset); + size_t copy_size = fcontent_length - fcontent_offset; + + if (copy_size > ctx->DBR->BPB.BytesPerSector) { + copy_size = ctx->DBR->BPB.BytesPerSector; + } + + memcpy(buff, src, copy_size); + } + } + } + /*!< unknown sector, ignore */ + + start_sector++; + sector_count--; + buff += ctx->DBR->BPB.BytesPerSector; + } + + return 0; +} + +int bootuf2_write_sector(uint32_t start_sector, const uint8_t *buff, uint32_t sector_count) +{ + struct bootuf2_data *ctx; + + ctx = &bootuf2_disk; + + while (sector_count) { + struct bootuf2_BLOCK *uf2 = (void *)buff; + + if (!((uf2->MagicStart0 == BOOTUF2_MAGIC_START0) && + (uf2->MagicStart1 == BOOTUF2_MAGIC_START1) && + (uf2->MagicEnd == BOOTUF2_MAGIC_END) && + (uf2->Flags & BOOTUF2_FLAG_FAMILID_PRESENT) && + !(uf2->Flags & BOOTUF2_FLAG_NOT_MAIN_FLASH))) { + goto next; + } + + if (uf2->FamilyID == CONFIG_BOOTUF2_FAMILYID) { + if (bootuf2block_check_writable(ctx->STATE, uf2, CONFIG_BOOTUF2_FLASHMAX)) { + bootuf2_flash_write_internal(ctx, uf2); + bootuf2block_state_update(ctx->STATE, uf2, CONFIG_BOOTUF2_FLASHMAX); + } else { + USB_LOG_DBG("UF2 block %d already written\r\n", + uf2->BlockIndex); + } + } else { + USB_LOG_DBG("UF2 block illegal id %08x\r\n", uf2->FamilyID); + } + + next: + start_sector++; + sector_count--; + buff += ctx->DBR->BPB.BytesPerSector; + } + + return 0; +} + +uint16_t bootuf2_get_sector_size(void) +{ + return bootuf2_disk.DBR->BPB.BytesPerSector; +} + +uint32_t bootuf2_get_sector_count(void) +{ + return bootuf2_disk.DBR->BPB.SectorsOver32MB + bootuf2_disk.DBR->BPB.Sectors; +} + +bool bootuf2_is_write_done(void) +{ + if (bootuf2block_state_check(bootuf2_disk.STATE)) { + bootuf2_flash_flush(&bootuf2_disk); + USB_LOG_DBG("UF2 update ok\r\n"); + return true; + } else { + return false; + } +} \ No newline at end of file diff --git a/projects/HSLink-Pro/bootloader/bootuf2/bootuf2.h b/projects/HSLink-Pro/bootloader/bootuf2/bootuf2.h new file mode 100644 index 0000000..aa83eac --- /dev/null +++ b/projects/HSLink-Pro/bootloader/bootuf2/bootuf2.h @@ -0,0 +1,218 @@ +/* +* Copyright (c) 2024, sakumisu +* Copyright (c) 2024, Egahp +* +* SPDX-License-Identifier: Apache-2.0 +*/ +#ifndef BOOTUF2_H +#define BOOTUF2_H + +#include +#include +#include +#include +#include +#include + +#ifndef __PACKED +#define __PACKED __attribute__((packed)) +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(array) \ + ((int)((sizeof(array) / sizeof((array)[0])))) +#endif + +struct bootuf2_BLOCK +{ + // 32 byte header + uint32_t MagicStart0; + uint32_t MagicStart1; + uint32_t Flags; + uint32_t TargetAddress; + uint32_t PayloadSize; + uint32_t BlockIndex; + uint32_t NumberOfBlock; + uint32_t FamilyID; // or file_size + uint8_t Data[476]; + uint32_t MagicEnd; +} __PACKED; +//BUILD_ASSERT(sizeof(struct bootuf2_BLOCK) == 512, "bootuf2_BLOCK not sector sized"); + +struct bootuf2_STATE +{ + uint32_t NumberOfBlock; + uint32_t NumberOfWritten; + uint8_t *const Mask; + uint8_t Enable; +}; + +struct bootuf2_DBR +{ + /*!< offset 0 */ + uint8_t JMPInstruction[3]; + /*!< offset 3 */ + uint8_t OEM[8]; + /*!< offset 11 */ + struct + { + uint16_t BytesPerSector; + uint8_t SectorsPerCluster; + uint16_t ReservedSectors; + uint8_t NumberOfFAT; + uint16_t RootEntries; + uint16_t Sectors; + uint8_t MediaDescriptor; + uint16_t SectorsPerFAT; + uint16_t SectorsPerTrack; + uint16_t Heads; + uint32_t HiddenSectors; + uint32_t SectorsOver32MB; + uint8_t BIOSDrive; + uint8_t Reserved; + uint8_t ExtendBootSignature; + uint32_t VolumeSerialNumber; + uint8_t VolumeLabel[11]; + uint8_t FileSystem[8]; + } __PACKED BPB; + /*!< offset 62 */ + /*!< BootLoader */ + /*!< offset 511 */ + /*!< 0x55 0xAA */ +} __PACKED; +//BUILD_ASSERT(sizeof(struct bootuf2_DBR) == 62, "bootuf2_DBR size must be 62 byte"); + +struct bootuf2_ENTRY +{ + char Name[11]; + uint8_t Attribute; + uint8_t NTReserved; + uint8_t CreateTimeTeenth; + uint16_t CreateTime; + uint16_t CreateDate; + uint16_t LastAccessDate; + uint16_t FirstClustH16; + uint16_t UpdateTime; + uint16_t UpdateDate; + uint16_t FirstClustL16; + uint32_t FileSize; +} __PACKED; +//BUILD_ASSERT(sizeof(struct bootuf2_ENTRY) == 32, "bootuf2_ENTRY size must be 32 byte"); + +struct bootuf2_FILE +{ + const char *const Name; + const void *const Content; + uint32_t FileSize; + uint16_t ClusterBeg; + uint16_t ClusterEnd; +}; + +#define BOOTUF2_DIVCEIL(_v, _d) (((_v) / (_d)) + ((_v) % (_d) ? 1 : 0)) + +#define BOOTUF2_MAGIC_START0 0x0A324655u +#define BOOTUF2_MAGIC_START1 0x9E5D5157u +#define BOOTUF2_MAGIC_SERIAL 0x251B18BDu +#define BOOTUF2_MAGIC_END 0x0AB16F30u + +#define BOOTUF2_FLAG_NOT_MAIN_FLASH 0x00000001u +#define BOOTUF2_FLAG_FILE_CONTAINER 0x00001000u +#define BOOTUF2_FLAG_FAMILID_PRESENT 0x00002000u +#define BOOTUF2_FLAG_MD5_PRESENT 0x00004000u + +#define BOOTUF2_CMD_READ 0 +#define BOOTUF2_CMD_SYNC 1 + +#define BOOTUF2_BLOCKSMAX (((CONFIG_BOOTUF2_FLASHMAX) / 256) + (((CONFIG_BOOTUF2_FLASHMAX) % 256) ? 1 : 0)) + +#define BOOTUF2_FAMILYID_POSNUM(n) (((CONFIG_BOOTUF2_FAMILYID) / (0x10000000 >> ((n) * 4))) % 0x10) +#define BOOTUF2_FAMILYID_ARRAY \ + { \ + ((BOOTUF2_FAMILYID_POSNUM(0) >= 10) ? BOOTUF2_FAMILYID_POSNUM(0) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(0) + '0'), \ + ((BOOTUF2_FAMILYID_POSNUM(1) >= 10) ? BOOTUF2_FAMILYID_POSNUM(1) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(1) + '0'), \ + ((BOOTUF2_FAMILYID_POSNUM(2) >= 10) ? BOOTUF2_FAMILYID_POSNUM(2) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(2) + '0'), \ + ((BOOTUF2_FAMILYID_POSNUM(3) >= 10) ? BOOTUF2_FAMILYID_POSNUM(3) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(3) + '0'), \ + ((BOOTUF2_FAMILYID_POSNUM(4) >= 10) ? BOOTUF2_FAMILYID_POSNUM(4) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(4) + '0'), \ + ((BOOTUF2_FAMILYID_POSNUM(5) >= 10) ? BOOTUF2_FAMILYID_POSNUM(5) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(5) + '0'), \ + ((BOOTUF2_FAMILYID_POSNUM(6) >= 10) ? BOOTUF2_FAMILYID_POSNUM(6) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(6) + '0'), \ + ((BOOTUF2_FAMILYID_POSNUM(7) >= 10) ? BOOTUF2_FAMILYID_POSNUM(7) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(7) + '0'), \ + ('I'), \ + ('D'), \ + (' '), \ + ('\0'), \ + }; + +#define BOOTUF2_FAT16_PER_SECTOR(pDBR) (pDBR->BPB.BytesPerSector / 2) +#define BOOTUF2_ENTRY_PER_SECTOR(pDBR) (pDBR->BPB.BytesPerSector / sizeof(struct bootuf2_ENTRY)) +#define BOOTUF2_CLUSTERSMAX (0xFFF0 - 2) +#define BOOTUF2_SECTOR_DBR_END (0) +#define BOOTUF2_SECTOR_RSVD_END(pDBR) BOOTUF2_SECTOR_DBR_END + (pDBR->BPB.ReservedSectors) +#define BOOTUF2_SECTOR_FAT_END(pDBR) BOOTUF2_SECTOR_RSVD_END(pDBR) + (pDBR->BPB.SectorsPerFAT * pDBR->BPB.NumberOfFAT) +#define BOOTUF2_SECTOR_ROOT_END(pDBR) BOOTUF2_SECTOR_FAT_END(pDBR) + (pDBR->BPB.RootEntries / (pDBR->BPB.BytesPerSector / sizeof(struct bootuf2_ENTRY))) +#define BOOTUF2_SECTOR_DATA_END(pDBR) (pDBR->BPB.Sectors + pDBR->BPB.SectorsOver32MB) + +#define BOOTUF2_SECTORS_PER_FAT(n) \ + BOOTUF2_DIVCEIL(BOOTUF2_CLUSTERSMAX, (CONFIG_BOOTUF2_SECTOR_SIZE / 2)) +#define BOOTUF2_SECTORS_FOR_ENTRIES(n) \ + (CONFIG_BOOTUF2_ROOT_ENTRIES / (CONFIG_BOOTUF2_SECTOR_SIZE / sizeof(struct bootuf2_ENTRY))) +#define BOOTUF2_SECTORS(n) \ + (CONFIG_BOOTUF2_SECTOR_RESERVED + \ + CONFIG_BOOTUF2_NUM_OF_FAT * BOOTUF2_SECTORS_PER_FAT(n) + \ + BOOTUF2_SECTORS_FOR_ENTRIES(n) + \ + BOOTUF2_CLUSTERSMAX * CONFIG_BOOTUF2_SECTOR_PER_CLUSTER) + +#define BOOTUF2_YEAR_INT ( \ + (__DATE__[7u] - '0') * 1000u + \ + (__DATE__[8u] - '0') * 100u + \ + (__DATE__[9u] - '0') * 10u + \ + (__DATE__[10u] - '0') * 1u) + +#define BOOTUF2_MONTH_INT ( \ + (__DATE__[2u] == 'n' && __DATE__[1u] == 'a') ? 1u /*Jan*/ \ + : (__DATE__[2u] == 'b') ? 2u /*Feb*/ \ + : (__DATE__[2u] == 'r' && __DATE__[1u] == 'a') ? 3u /*Mar*/ \ + : (__DATE__[2u] == 'r') ? 4u /*Apr*/ \ + : (__DATE__[2u] == 'y') ? 5u /*May*/ \ + : (__DATE__[2u] == 'n') ? 6u /*Jun*/ \ + : (__DATE__[2u] == 'l') ? 7u /*Jul*/ \ + : (__DATE__[2u] == 'g') ? 8u /*Aug*/ \ + : (__DATE__[2u] == 'p') ? 9u /*Sep*/ \ + : (__DATE__[2u] == 't') ? 10u /*Oct*/ \ + : (__DATE__[2u] == 'v') ? 11u /*Nov*/ \ + : 12u /*Dec*/) + +#define BOOTUF2_DAY_INT ( \ + (__DATE__[4u] == ' ' ? 0 : __DATE__[4u] - '0') * 10u + \ + (__DATE__[5u] - '0')) + +#define BOOTUF2_HOUR_INT ( \ + (__TIME__[0u] == '?' ? 0 : __TIME__[0u] - '0') * 10u + (__TIME__[1u] == '?' ? 0 : __TIME__[1u] - '0')) + +#define BOOTUF2_MINUTE_INT ( \ + (__TIME__[3u] == '?' ? 0 : __TIME__[3u] - '0') * 10u + (__TIME__[4u] == '?' ? 0 : __TIME__[4u] - '0')) + +#define BOOTUF2_SECONDS_INT ( \ + (__TIME__[6u] == '?' ? 0 : __TIME__[6u] - '0') * 10u + (__TIME__[7u] == '?' ? 0 : __TIME__[7u] - '0')) + +#define BOOTUF2_DOS_DATE ( \ + ((BOOTUF2_YEAR_INT - 1980u) << 9u) | \ + (BOOTUF2_MONTH_INT << 5u) | \ + (BOOTUF2_DAY_INT << 0u)) + +#define BOOTUF2_DOS_TIME ( \ + (BOOTUF2_HOUR_INT << 11u) | \ + (BOOTUF2_MINUTE_INT << 5u) | \ + (BOOTUF2_SECONDS_INT << 0u)) + +void bootuf2_init(void); +int boot2uf2_read_sector(uint32_t start_sector, uint8_t *buff, uint32_t sector_count); +int bootuf2_write_sector(uint32_t start_sector, const uint8_t *buff, uint32_t sector_count); +uint16_t bootuf2_get_sector_size(void); +uint32_t bootuf2_get_sector_count(void); + +bool bootuf2_is_write_done(void); + +void boot2uf2_flash_init(void); +int bootuf2_flash_write(uint32_t address, const uint8_t *data, size_t size); + +#endif /* BOOTUF2_H */ \ No newline at end of file diff --git a/projects/HSLink-Pro/bootloader/bootuf2/bootuf2_config.h b/projects/HSLink-Pro/bootloader/bootuf2/bootuf2_config.h new file mode 100644 index 0000000..c7e1161 --- /dev/null +++ b/projects/HSLink-Pro/bootloader/bootuf2/bootuf2_config.h @@ -0,0 +1,27 @@ +/* +* Copyright (c) 2024, sakumisu +* +* SPDX-License-Identifier: Apache-2.0 +*/ +#ifndef BOOTUF2_CONFIG_H +#define BOOTUF2_CONFIG_H + +#define CONFIG_PRODUCT "CherryDAP" +#define CONFIG_BOARD "HSLink Pro" +#define CONFIG_BOOTUF2_INDEX_URL "https://github.com/cherry-embedded/CherryDAP" +#define CONFIG_BOOTUF2_JOIN_URL "http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=NXGLdOOrFypXfBoAmh_eLwmcAZ2doqxJ&authKey=CDerxhytwBfYn1jHcfmBwOOl2B73vRxGmPJ0utVTFrnjfwfTikpzJbYUUPhyicmK&noverify=0&group_code=975779851" + +#define CONFIG_BOOTUF2_CACHE_SIZE 4096 +#define CONFIG_BOOTUF2_SECTOR_SIZE 512 +#define CONFIG_BOOTUF2_SECTOR_PER_CLUSTER 2 +#define CONFIG_BOOTUF2_SECTOR_RESERVED 1 +#define CONFIG_BOOTUF2_NUM_OF_FAT 2 +#define CONFIG_BOOTUF2_ROOT_ENTRIES 64 + +#define CONFIG_BOOTUF2_FAMILYID 0x0A4D5048 +#define CONFIG_BOOTUF2_FLASHMAX (1*1024*1024 - 0x20000) +#define CONFIG_BOOTUF2_PAGE_COUNTMAX 1024 + +#define CONFIG_BOOTUF2_APP_START (0x80020000UL) + +#endif \ No newline at end of file diff --git a/projects/HSLink-Pro/bootloader/flash_xip.ld b/projects/HSLink-Pro/bootloader/flash_xip.ld new file mode 100644 index 0000000..fea1a46 --- /dev/null +++ b/projects/HSLink-Pro/bootloader/flash_xip.ld @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2023 HPMicro + * SPDX-License-Identifier: BSD-3-Clause + */ + +ENTRY(_start) + +STACK_SIZE = _stack_size; +HEAP_SIZE = _heap_size; + +/* 预留512字节的空间到AHB_SRAM给bootloader做配置 */ +__bootloader_reserved_length__ = 512; + +MEMORY +{ + XPI0 (rx) : ORIGIN = 0x80000000, LENGTH = 128k + ILM (wx) : ORIGIN = 0x00000000, LENGTH = 128K + DLM (w) : ORIGIN = 0x00080000, LENGTH = 128K + AHB_SRAM (w) : ORIGIN = 0xf0400000, LENGTH = 32K +} + +__nor_cfg_option_load_addr__ = ORIGIN(XPI0) + 0x400; +__boot_header_load_addr__ = ORIGIN(XPI0) + 0x1000; +__app_load_addr__ = ORIGIN(XPI0) + 0x3000; +__boot_header_length__ = __boot_header_end__ - __boot_header_start__; +__app_offset__ = __app_load_addr__ - __boot_header_load_addr__; + + +SECTIONS +{ + .nor_cfg_option __nor_cfg_option_load_addr__ : { + KEEP(*(.nor_cfg_option)) + } > XPI0 + + .boot_header __boot_header_load_addr__ : { + __boot_header_start__ = .; + KEEP(*(.boot_header)) + KEEP(*(.fw_info_table)) + KEEP(*(.dc_info)) + __boot_header_end__ = .; + } > XPI0 + + .start __app_load_addr__ : { + . = ALIGN(8); + KEEP(*(.start)) + } > XPI0 + + __vector_load_addr__ = ADDR(.start) + SIZEOF(.start); + .vectors ORIGIN(ILM) : AT(__vector_load_addr__) { + . = ALIGN(8); + __vector_ram_start__ = .; + KEEP(*(.vector_table)) + KEEP(*(.isr_vector)) + KEEP(*(.vector_s_table)) + KEEP(*(.isr_s_vector)) + . = ALIGN(8); + __vector_ram_end__ = .; + } > ILM + + .text (__vector_load_addr__ + SIZEOF(.vectors)) : { + . = ALIGN(8); + *(.text) + *(.text*) + *(.rodata) + *(.rodata*) + *(.srodata) + *(.srodata*) + + *(.hash) + *(.dyn*) + *(.gnu*) + *(.pl*) + + KEEP (*(.init)) + KEEP (*(.fini)) + + /* section information for usbh class */ + . = ALIGN(8); + __usbh_class_info_start__ = .; + KEEP(*(.usbh_class_info)) + __usbh_class_info_end__ = .; + + /* RT-Thread related sections - Start */ + /* section information for finsh shell */ + . = ALIGN(4); + __fsymtab_start = .; + KEEP(*(FSymTab)) + __fsymtab_end = .; + . = ALIGN(4); + __vsymtab_start = .; + KEEP(*(VSymTab)) + __vsymtab_end = .; + . = ALIGN(4); + + . = ALIGN(4); + __rt_init_start = .; + KEEP(*(SORT(.rti_fn*))) + __rt_init_end = .; + . = ALIGN(4); + + /* section information for modules */ + . = ALIGN(4); + __rtmsymtab_start = .; + KEEP(*(RTMSymTab)) + __rtmsymtab_end = .; + + /* RT-Thread related sections - end */ + . = ALIGN(8); + } > XPI0 + + .eh_frame : + { + __eh_frame_start = .; + KEEP(*(.eh_frame)) + __eh_frame_end = .; + } > XPI0 + + .eh_frame_hdr : + { + KEEP(*(.eh_frame_hdr)) + } > XPI0 + __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0; + __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0; + + + .rel : { + KEEP(*(.rel*)) + } > XPI0 + + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + __data_load_addr__ = etext; + .data : AT(__data_load_addr__) { + . = ALIGN(8); + __data_start__ = .; + __global_pointer$ = . + 0x800; + *(.data) + *(.data*) + *(.sdata) + *(.sdata*) + + KEEP(*(.jcr)) + KEEP(*(.dynamic)) + KEEP(*(.got*)) + KEEP(*(.got)) + KEEP(*(.gcc_except_table)) + KEEP(*(.gcc_except_table.*)) + + . = ALIGN(8); + PROVIDE(__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE(__preinit_array_end = .); + + . = ALIGN(8); + PROVIDE(__init_array_start = .); + KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE(__init_array_end = .); + + . = ALIGN(8); + PROVIDE(__finit_array_start = .); + KEEP(*(SORT_BY_INIT_PRIORITY(.finit_array.*))) + KEEP(*(.finit_array)) + PROVIDE(__finit_array_end = .); + + . = ALIGN(8); + KEEP(*crtbegin*.o(.ctors)) + KEEP(*(EXCLUDE_FILE (*crtend*.o) .ctors)) + KEEP(*(SORT(.ctors.*))) + KEEP(*(.ctors)) + + . = ALIGN(8); + KEEP(*crtbegin*.o(.dtors)) + KEEP(*(EXCLUDE_FILE (*crtend*.o) .dtors)) + KEEP(*(SORT(.dtors.*))) + KEEP(*(.dtors)) + . = ALIGN(8); + __data_end__ = .; + PROVIDE (__edata = .); + PROVIDE (_edata = .); + PROVIDE (edata = .); + } > DLM + + __fast_load_addr__ = etext + SIZEOF(.data); + .fast : AT(__fast_load_addr__) { + . = ALIGN(8); + PROVIDE(__ramfunc_start__ = .); + *(.fast) + *(.fast.*) + . = ALIGN(8); + PROVIDE(__ramfunc_end__ = .); + } > ILM + + __tdata_load_addr__ = etext + SIZEOF(.data) + SIZEOF(.fast); + .tdata : AT(__tdata_load_addr__) { + . = ALIGN(8); + PROVIDE(__tdata_start__ = .); + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + . = ALIGN(8); + PROVIDE(__tdata_end__ = .); + } > DLM + + .tbss (NOLOAD) : { + . = ALIGN(8); + PROVIDE(__tbss_start__ = .); + __thread_pointer$ = .; + *(.tbss) + *(.tbss.*) + *(.gnu.linkonce.tb.*) + *(.tcommon) + . = ALIGN(8); + PROVIDE(__tbss_end__ = .); + } > DLM + + __noncacheable_init_load_addr__ = etext + SIZEOF(.data) + SIZEOF(.fast) + SIZEOF(.tdata); + .noncacheable.init : AT(__noncacheable_init_load_addr__) { + . = ALIGN(8); + __noncacheable_init_start__ = .; + KEEP(*(.noncacheable.init)) + __noncacheable_init_end__ = .; + . = ALIGN(8); + } > DLM + + __fast_ram_init_load_addr__ = etext + SIZEOF(.data) + SIZEOF(.fast) + SIZEOF(.tdata) + SIZEOF(.noncacheable.init); + .fast_ram.init : AT(__fast_ram_init_load_addr__) { + . = ALIGN(8); + __fast_ram_init_start__ = .; + KEEP(*(.fast_ram.init)) + __fast_ram_init_end__ = .; + . = ALIGN(8); + } > DLM + + .bss (NOLOAD) : { + . = ALIGN(8); + __bss_start__ = .; + *(.bss) + *(.bss*) + *(.sbss*) + *(.scommon) + *(.scommon*) + *(.dynsbss*) + *(COMMON) + . = ALIGN(8); + _end = .; + __bss_end__ = .; + } > DLM + + .framebuffer (NOLOAD) : { + . = ALIGN(8); + KEEP(*(.framebuffer)) + . = ALIGN(8); + } > DLM + + .noncacheable.bss (NOLOAD) : { + . = ALIGN(8); + KEEP(*(.noncacheable)) + __noncacheable_bss_start__ = .; + KEEP(*(.noncacheable.bss)) + __noncacheable_bss_end__ = .; + . = ALIGN(8); + } > DLM + + .fast_ram.bss (NOLOAD) : { + . = ALIGN(8); + KEEP(*(.fast_ram)) + __fast_ram_bss_start__ = .; + KEEP(*(.fast_ram.bss)) + __fast_ram_bss_end__ = .; + . = ALIGN(8); + } > DLM + + .heap (NOLOAD) : { + . = ALIGN(8); + __heap_start__ = .; + . += HEAP_SIZE; + __heap_end__ = .; + } > DLM + + .stack (NOLOAD) : { + . = ALIGN(16); + __stack_base__ = .; + . += STACK_SIZE; + . = ALIGN(16); + PROVIDE (_stack = .); + PROVIDE (_stack_safe = .); + } > DLM + + .ahb_sram (NOLOAD) : { + KEEP(*(.ahb_sram)) + } > AHB_SRAM + + __boot_header_load_addr__ = ORIGIN(AHB_SRAM) + LENGTH(AHB_SRAM) - __bootloader_reserved_length__; + .bl_setting (NOLOAD) : AT(__boot_header_load_addr__) { + KEEP(*(.bl_setting)) + } > AHB_SRAM + + ASSERT(SIZEOF(.bl_setting) <= __bootloader_reserved_length__, "****** FAILED! .bl_setting too many!! ******") + + __fw_size__ = SIZEOF(.start) + SIZEOF(.vectors) + SIZEOF(.rel) + SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.fast) + SIZEOF(.tdata) + SIZEOF(.noncacheable.init) + SIZEOF(.fast_ram.init); + __last_addr__ = __fast_ram_init_load_addr__ + SIZEOF(.fast_ram.init); + ASSERT(((__fw_size__ <= LENGTH(XPI0)) && (__last_addr__ <= (ORIGIN(XPI0) + LENGTH(XPI0)))), "****** FAILED! XPI0 has not enough space! ******") +} diff --git a/projects/HSLink-Pro/bootloader/src/main.c b/projects/HSLink-Pro/bootloader/src/main.c new file mode 100644 index 0000000..e3960f2 --- /dev/null +++ b/projects/HSLink-Pro/bootloader/src/main.c @@ -0,0 +1,165 @@ +#include "BL_Setting_Common.h" +#include "WS2812.h" +#include "bootuf2.h" +#include "usb_config.h" +#include +#include +#include +#include +#include +#include "HSLink_Pro_expansion.h" +#include + +ATTR_PLACE_AT(".bl_setting") +static BL_Setting_t bl_setting; + +static void jump_app(void) +{ + fencei(); + l1c_dc_disable(); + __asm("la a0, %0" ::"i"(CONFIG_BOOTUF2_APP_START + 4)); + __asm("jr a0"); +} + +static void bootloader_button_init(void) +{ + // BOOT1(PA03) + HPM_IOC->PAD[IOC_PAD_PA03].FUNC_CTL = IOC_PA03_FUNC_CTL_GPIO_A_03; + + gpiom_set_pin_controller(HPM_GPIOM, GPIOM_ASSIGN_GPIOA, 3, gpiom_soc_gpio0); + gpio_set_pin_input(HPM_GPIO0, GPIO_OE_GPIOA, 3); + gpio_disable_pin_interrupt(HPM_GPIO0, GPIO_IE_GPIOA, 3); +} + +static bool bootloader_button_pressed(void) +{ + if (gpio_read_pin(HPM_GPIO0, GPIO_DI_GPIOA, 3) == 1) + { + board_delay_ms(5); + if (gpio_read_pin(HPM_GPIO0, GPIO_DI_GPIOA, 3) == 1) + { + return true; + } + } + return false; +} + +/** + * @brief 验证APP区是否合法 + * @return true: APP区合法 false: APP区不合法 + */ +static bool app_valid(void) +{ + if (((volatile uint32_t const *)CONFIG_BOOTUF2_APP_START)[0] != BOARD_UF2_SIGNATURE) + { + return false; + } + return true; +} + +static void show_logo(void) +{ + const char str[] = { + " _ _ _____ _ _ _ _____ \n" + " | | | |/ ____| | (_) | | | __ \\ \n" + " | |__| | (___ | | _ _ __ | | __ | |__) | __ ___ \n" + " | __ |\\___ \\| | | | '_ \\| |/ / | ___/ '__/ _ \\ \n" + " | | | |____) | |____| | | | | < | | | | | (_) |\n" + " |_| |_|_____/|______|_|_| |_|_|\\_\\ |_| |_| \\___/ \n" + " \n" + " \n" + ""}; + printf("%s", str); +} + +static void show_rainbow(void) +{ + for (int j = 0; j < 256; j++) + { + uint8_t r, g, b; + uint8_t pos = j & 255; + if (pos < 85) + { + r = pos * 3; + g = 255 - pos * 3; + b = 0; + } + else if (pos < 170) + { + pos -= 85; + r = 255 - pos * 3; + g = 0; + b = pos * 3; + } + else + { + pos -= 170; + r = 0; + g = pos * 3; + b = 255 - pos * 3; + } + for (size_t i = 0; i < WS2812_LED_NUM; i++) + { + WS2812_SetPixel(i, r, g, b); + } + WS2812_Update(); + board_delay_ms(10); // 纯阻塞,好孩子别学 + } +} + +static void TurnOffLED(void) +{ + WS2812_SetPixel(0, 0, 0, 0); + WS2812_Update(); + while (WS2812_IsBusy()) + ; +} + +int main(void) +{ + board_init(); + dma_mgr_init(); + show_logo(); + HSP_Init(); // 关闭电源输出,将电平修改为3.3V + board_init_usb_pins(); + bootloader_button_init(); + WS2812_Init(); + + if (bl_setting.magic != BL_SETTING_MAGIC) + { + memset(&bl_setting, 0x00, sizeof(bl_setting)); + bl_setting.magic = BL_SETTING_MAGIC; + } + + if (!bootloader_button_pressed() // 按键未按下 + && app_valid() // APP区合法 + && bl_setting.is_update == 0 // 不需要进入bootloader + ) + { + USB_LOG_INFO("Jump to application @0x%x(0x%x)\r\n", CONFIG_BOOTUF2_APP_START, *(volatile uint32_t *)CONFIG_BOOTUF2_APP_START); + TurnOffLED(); + jump_app(); + while (1) + ; + } + + intc_set_irq_priority(CONFIG_HPM_USBD_IRQn, 2); + printf("HSLink Pro UF2 Bootloader\n"); + + extern void msc_bootuf2_init(uint8_t busid, uint32_t reg_base); + msc_bootuf2_init(0, CONFIG_HPM_USBD_BASE); + + while (1) + { + if (bootuf2_is_write_done()) + { + USB_LOG_INFO("Update success! Jump to application.\n"); + TurnOffLED(); + jump_app(); + while (1) + ; + } + show_rainbow(); + } + return 0; +} diff --git a/projects/HSLink-Pro/bootloader/src/msc_bootuf2.c b/projects/HSLink-Pro/bootloader/src/msc_bootuf2.c new file mode 100644 index 0000000..d6c3b22 --- /dev/null +++ b/projects/HSLink-Pro/bootloader/src/msc_bootuf2.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2024, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "bootuf2.h" +#include "usbd_core.h" +#include "usbd_msc.h" +#include +#include + +#include "hpm_romapi.h" + +#define OTP_CHIP_UUID_IDX_START (88U) +#define OTP_CHIP_UUID_IDX_END (91U) + +#define MSC_IN_EP 0x81 +#define MSC_OUT_EP 0x02 + +#define USBD_LANGID_STRING 1033 + +#define USB_CONFIG_SIZE (9 + MSC_DESCRIPTOR_LEN) + +#ifdef CONFIG_USB_HS +#define MSC_MAX_MPS 512 +#else +#define MSC_MAX_MPS 64 +#endif + +static uint8_t msc_bootuf2_descriptor[] = { + USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01), + USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), + MSC_DESCRIPTOR_INIT(0x00, MSC_OUT_EP, MSC_IN_EP, MSC_MAX_MPS, 0x02), + /////////////////////////////////////// + /// string0 descriptor + /////////////////////////////////////// + USB_LANGID_INIT(USBD_LANGID_STRING), + /////////////////////////////////////// + /// string1 descriptor + /////////////////////////////////////// + 0x14, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + 'C', 0x00, /* wcChar0 */ + 'h', 0x00, /* wcChar1 */ + 'e', 0x00, /* wcChar2 */ + 'r', 0x00, /* wcChar3 */ + 'r', 0x00, /* wcChar4 */ + 'y', 0x00, /* wcChar5 */ + 'U', 0x00, /* wcChar6 */ + 'S', 0x00, /* wcChar7 */ + 'B', 0x00, /* wcChar8 */ + /////////////////////////////////////// + /// string2 descriptor + /////////////////////////////////////// + 0x1C, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + 'C', 0x00, /* wcChar0 */ + 'h', 0x00, /* wcChar1 */ + 'e', 0x00, /* wcChar2 */ + 'r', 0x00, /* wcChar3 */ + 'r', 0x00, /* wcChar4 */ + 'y', 0x00, /* wcChar5 */ + 'D', 0x00, /* wcChar6 */ + 'A', 0x00, /* wcChar7 */ + 'P', 0x00, /* wcChar8 */ + ' ', 0x00, /* wcChar9 */ + 'U', 0x00, /* wcChar10 */ + 'F', 0x00, /* wcChar11 */ + '2', 0x00, /* wcChar12 */ + /////////////////////////////////////// + /// string3 descriptor + /////////////////////////////////////// + 0x42, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + '0', 0x00, /* wcChar0 */ + '0', 0x00, /* wcChar1 */ + '0', 0x00, /* wcChar2 */ + '0', 0x00, /* wcChar3 */ + '0', 0x00, /* wcChar4 */ + '0', 0x00, /* wcChar5 */ + '0', 0x00, /* wcChar6 */ + '0', 0x00, /* wcChar7 */ + '0', 0x00, /* wcChar8 */ + '0', 0x00, /* wcChar9 */ + '0', 0x00, /* wcChar10 */ + '0', 0x00, /* wcChar11 */ + '0', 0x00, /* wcChar12 */ + '0', 0x00, /* wcChar13 */ + '0', 0x00, /* wcChar14 */ + '0', 0x00, /* wcChar15 */ + '0', 0x00, /* wcChar16 */ + '0', 0x00, /* wcChar17 */ + '0', 0x00, /* wcChar18 */ + '0', 0x00, /* wcChar19 */ + '0', 0x00, /* wcChar20 */ + '0', 0x00, /* wcChar21 */ + '0', 0x00, /* wcChar22 */ + '0', 0x00, /* wcChar23 */ + '0', 0x00, /* wcChar24 */ + '0', 0x00, /* wcChar25 */ + '0', 0x00, /* wcChar26 */ + '0', 0x00, /* wcChar27 */ + '0', 0x00, /* wcChar28 */ + '0', 0x00, /* wcChar29 */ + '0', 0x00, /* wcChar30 */ + '0', 0x00, /* wcChar31 */ +#ifdef CONFIG_USB_HS + /////////////////////////////////////// + /// device qualifier descriptor + /////////////////////////////////////// + 0x0a, + USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, + 0x00, + 0x02, + 0x00, + 0x00, + 0x00, + 0x40, + 0x01, + 0x00, +#endif + 0x00}; + +/** + * @brief 在初始化之前修改描述符中的chip_id,本质上是修改string3 descriptor + * @param chip_id 16个字符 + */ +static void modify_descriptor_chip_id(void) +{ + uint32_t uuid_words[4]; + + uint32_t word_idx = 0; + for (uint32_t i = OTP_CHIP_UUID_IDX_START; i <= OTP_CHIP_UUID_IDX_END; i++) + { + uuid_words[word_idx++] = ROM_API_TABLE_ROOT->otp_driver_if->read_from_shadow(i); + } + + char chip_id[32]; + sprintf(chip_id, "%08X%08X%08X%08X", uuid_words[0], uuid_words[1], uuid_words[2], uuid_words[3]); + const size_t index = 114; + for (size_t i = 0; i < 32; i++) + { + msc_bootuf2_descriptor[index + i * 2] = chip_id[i]; + } +} + +static void usbd_event_handler(uint8_t busid, uint8_t event) +{ + switch (event) + { + case USBD_EVENT_RESET: + break; + case USBD_EVENT_CONNECTED: + break; + case USBD_EVENT_DISCONNECTED: + break; + case USBD_EVENT_RESUME: + break; + case USBD_EVENT_SUSPEND: + break; + case USBD_EVENT_CONFIGURED: + bootuf2_init(); + break; + case USBD_EVENT_SET_REMOTE_WAKEUP: + break; + case USBD_EVENT_CLR_REMOTE_WAKEUP: + break; + + default: + break; + } +} + +void usbd_msc_get_cap(uint8_t busid, uint8_t lun, uint32_t *block_num, uint32_t *block_size) +{ + *block_num = bootuf2_get_sector_count(); + *block_size = bootuf2_get_sector_size(); + + USB_LOG_INFO("sector count:%d, sector size:%d\n", *block_num, *block_size); +} +int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length) +{ + boot2uf2_read_sector(sector, buffer, length / bootuf2_get_sector_size()); + return 0; +} + +int usbd_msc_sector_write(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length) +{ + bootuf2_write_sector(sector, buffer, length / bootuf2_get_sector_size()); + return 0; +} + +static struct usbd_interface intf0; + +void msc_bootuf2_init(uint8_t busid, uint32_t reg_base) +{ + modify_descriptor_chip_id(); + boot2uf2_flash_init(); + usbd_desc_register(busid, msc_bootuf2_descriptor); + usbd_add_interface(busid, usbd_msc_init_intf(busid, &intf0, MSC_OUT_EP, MSC_IN_EP)); + + usbd_initialize(busid, reg_base, usbd_event_handler); +} + +static xpi_nor_config_t s_xpi_nor_config; + +void boot2uf2_flash_init(void) +{ + xpi_nor_config_option_t option; + option.header.U = BOARD_APP_XPI_NOR_CFG_OPT_HDR; + option.option0.U = BOARD_APP_XPI_NOR_CFG_OPT_OPT0; + option.option1.U = BOARD_APP_XPI_NOR_CFG_OPT_OPT1; + rom_xpi_nor_auto_config(BOARD_APP_XPI_NOR_XPI_BASE, &s_xpi_nor_config, &option); +} + +int bootuf2_flash_write(uint32_t address, const uint8_t *data, size_t size) +{ + hpm_stat_t status; + USB_LOG_INFO("address:%08x, size:%d\n", address, size); + + uint32_t const page_addr = address & ~(CONFIG_BOOTUF2_SECTOR_SIZE - 1); + uint32_t const sector_addr = (page_addr - BOARD_FLASH_BASE_ADDRESS); + disable_global_irq(CSR_MSTATUS_MIE_MASK); + status = rom_xpi_nor_erase(BOARD_APP_XPI_NOR_XPI_BASE, xpi_xfer_channel_auto, &s_xpi_nor_config, + sector_addr, size); + enable_global_irq(CSR_MSTATUS_MIE_MASK); + + if (status != status_success) + { + USB_LOG_ERR("Erase failed: status = %ld!\r\n", status); + return 1; + } + + USB_LOG_INFO("Erase %08x success\n", sector_addr); + + disable_global_irq(CSR_MSTATUS_MIE_MASK); + status = rom_xpi_nor_program(BOARD_APP_XPI_NOR_XPI_BASE, xpi_xfer_channel_auto, &s_xpi_nor_config, + (uint32_t *)data, sector_addr, size); + enable_global_irq(CSR_MSTATUS_MIE_MASK); + if (status != status_success) + { + USB_LOG_ERR("Page program failed: status = %ld!\r\n", status); + return 1; + } + + USB_LOG_INFO("Write %08x success\n", sector_addr); + return 0; +} \ No newline at end of file diff --git a/projects/HSLink-Pro/bootloader/src/usb_config.h b/projects/HSLink-Pro/bootloader/src/usb_config.h new file mode 100644 index 0000000..2379fc1 --- /dev/null +++ b/projects/HSLink-Pro/bootloader/src/usb_config.h @@ -0,0 +1,240 @@ +/* +* Copyright (c) 2022, sakumisu +* Copyright (c) 2022-2024, HPMicro +* +* SPDX-License-Identifier: Apache-2.0 +*/ +#ifndef CHERRYUSB_CONFIG_H +#define CHERRYUSB_CONFIG_H + +#include "hpm_soc_feature.h" + +#define CHERRYUSB_VERSION 0x010300 +#define CHERRYUSB_VERSION_STR "v1.3.0" + +/* ================ USB common Configuration ================ */ + +#define CONFIG_USB_PRINTF(...) printf(__VA_ARGS__) + +#define usb_malloc(size) malloc(size) +#define usb_free(ptr) free(ptr) + +#ifndef CONFIG_USB_DBG_LEVEL +#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO +#endif + +#ifdef CONFIG_USB_DEVICE_FS +#undef CONFIG_USB_HS +#else +#define CONFIG_USB_HS +#endif + +/* Enable print with color */ +#define CONFIG_USB_PRINTF_COLOR_ENABLE + +/* data align size when use dma */ +#ifndef CONFIG_USB_ALIGN_SIZE +#define CONFIG_USB_ALIGN_SIZE 4 +#endif + +/* descriptor common define */ +//#define CONFIG_USBDEV_ADVANCE_DESC +#define USBD_VID 0x34B7 /* HPMicro VID */ +#define USBD_PID 0xFFFF +#define USBD_MAX_POWER 500 + +/* attribute data into no cache ram */ +#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable"))) + +/* ================= USB Device Stack Configuration ================ */ + +/* Ep0 in and out transfer buffer */ +#ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN +#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512 +#endif + +/* Setup packet log for debug */ +/* #define CONFIG_USBDEV_SETUP_LOG_PRINT */ + +/* Send ep0 in data from user buffer instead of copying into ep0 reqdata +* Please note that user buffer must be aligned with CONFIG_USB_ALIGN_SIZE +*/ +/* #define CONFIG_USBDEV_EP0_INDATA_NO_COPY */ + +/* Check if the input descriptor is correct */ +/* #define CONFIG_USBDEV_DESC_CHECK */ + +/* Enable test mode */ +#define CONFIG_USBDEV_TEST_MODE + +#ifndef CONFIG_USBDEV_MSC_MAX_LUN +#define CONFIG_USBDEV_MSC_MAX_LUN 1 +#endif + +#ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE +#define CONFIG_USBDEV_MSC_MAX_BUFSIZE 512 +#endif + +#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING +#define CONFIG_USBDEV_MSC_MANUFACTURER_STRING "" +#endif + +#ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING +#define CONFIG_USBDEV_MSC_PRODUCT_STRING "" +#endif + +#ifndef CONFIG_USBDEV_MSC_VERSION_STRING +#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01" +#endif + +/* #define CONFIG_USBDEV_MSC_THREAD */ + +#ifndef CONFIG_USBDEV_MSC_PRIO +#define CONFIG_USBDEV_MSC_PRIO 4 +#endif + +#ifndef CONFIG_USBDEV_MSC_STACKSIZE +#define CONFIG_USBDEV_MSC_STACKSIZE 2048 +#endif + +#ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE +#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156 +#endif + +/* rndis transfer buffer size, must be a multiple of (1536 + 44)*/ +#ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE +#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1580 +#endif + +#ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID +#define CONFIG_USBDEV_RNDIS_VENDOR_ID 0x0000ffff +#endif + +#ifndef CONFIG_USBDEV_RNDIS_VENDOR_DESC +#define CONFIG_USBDEV_RNDIS_VENDOR_DESC "HPMicro" +#endif + +#define CONFIG_USBDEV_RNDIS_USING_LWIP + +/* ================ USB HOST Stack Configuration ================== */ + +#define CONFIG_USBHOST_MAX_RHPORTS 1 +#define CONFIG_USBHOST_MAX_EXTHUBS 1 +#define CONFIG_USBHOST_MAX_EHPORTS 4 +#define CONFIG_USBHOST_MAX_INTERFACES 8 +#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 2 +#define CONFIG_USBHOST_MAX_ENDPOINTS 8 + +#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4 +#define CONFIG_USBHOST_MAX_HID_CLASS 4 +#define CONFIG_USBHOST_MAX_MSC_CLASS 2 +#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1 +#define CONFIG_USBHOST_MAX_VIDEO_CLASS 1 + +#define CONFIG_USBHOST_DEV_NAMELEN 16 + +#ifndef CONFIG_USBHOST_PSC_PRIO +#define CONFIG_USBHOST_PSC_PRIO 0 +#endif +#ifndef CONFIG_USBHOST_PSC_STACKSIZE +#define CONFIG_USBHOST_PSC_STACKSIZE 2048 +#endif + +/* #define CONFIG_USBHOST_GET_STRING_DESC */ + +/* #define CONFIG_USBHOST_MSOS_ENABLE */ +#ifndef CONFIG_USBHOST_MSOS_VENDOR_CODE +#define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00 +#endif + +/* Ep0 max transfer buffer */ +#ifndef CONFIG_USBHOST_REQUEST_BUFFER_LEN +#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512 +#endif + +#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT +#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500 +#endif + +#ifndef CONFIG_USBHOST_MSC_TIMEOUT +#define CONFIG_USBHOST_MSC_TIMEOUT 5000 +#endif + +/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size, +* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow. +*/ +#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE +#define CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE (2048) +#endif + +/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */ +#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE +#define CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE (2048) +#endif + +/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size, +* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow. +*/ +#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE +#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE (2048) +#endif +/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */ +#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE +#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE (2048) +#endif + +/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size, +* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow. +*/ +#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE +#define CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE (2048) +#endif +/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */ +#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE +#define CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE (2048) +#endif + +#define CONFIG_USBHOST_BLUETOOTH_HCI_H4 +/* #define CONFIG_USBHOST_BLUETOOTH_HCI_LOG */ + +#ifndef CONFIG_USBHOST_BLUETOOTH_TX_SIZE +#define CONFIG_USBHOST_BLUETOOTH_TX_SIZE 2048 +#endif +#ifndef CONFIG_USBHOST_BLUETOOTH_RX_SIZE +#define CONFIG_USBHOST_BLUETOOTH_RX_SIZE 2048 +#endif + +/* ================ USB Device Port Configuration ================*/ + +#define CONFIG_USBDEV_MAX_BUS USB_SOC_MAX_COUNT + +#ifndef CONFIG_USBDEV_EP_NUM +#define CONFIG_USBDEV_EP_NUM USB_SOC_DCD_MAX_ENDPOINT_COUNT +#endif + +#ifndef CONFIG_HPM_USBD_BASE +#define CONFIG_HPM_USBD_BASE HPM_USB0_BASE +#endif +#ifndef CONFIG_HPM_USBD_IRQn +#define CONFIG_HPM_USBD_IRQn IRQn_USB0 +#endif + +/* ================ USB Host Port Configuration ==================*/ +#define CONFIG_USBHOST_MAX_BUS USB_SOC_MAX_COUNT +#define CONFIG_USBHOST_PIPE_NUM 5 + +#ifndef CONFIG_HPM_USBH_BASE +#define CONFIG_HPM_USBH_BASE HPM_USB0_BASE +#endif +#ifndef CONFIG_HPM_USBH_IRQn +#define CONFIG_HPM_USBH_IRQn IRQn_USB0 +#endif + +/* ================ EHCI Configuration ================ */ + +#define CONFIG_USB_EHCI_HPMICRO (1) +#define CONFIG_USB_EHCI_HCCR_OFFSET (0x100u) +#define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024 +#define CONFIG_USB_EHCI_QTD_NUM 8 + +#endif diff --git a/projects/HSLink-Pro/common/BL_Setting_Common.h b/projects/HSLink-Pro/common/BL_Setting_Common.h new file mode 100644 index 0000000..c6d7aa0 --- /dev/null +++ b/projects/HSLink-Pro/common/BL_Setting_Common.h @@ -0,0 +1,23 @@ +#ifndef BL_SETTING_COMMON_H +#define BL_SETTING_COMMON_H + +#include + +typedef enum { + BL_SETTING_MAGIC = 0xB7B7B7B7, + + BL_SETTING_MAGIC_INVALID = 0xFFFFFFFF, +} BL_SETTING_MAGIC_t; + +typedef struct { + uint32_t magic; // 这个段未初始化,使用magic来判断是否已经初始化 + union { + uint8_t data0; + struct { + uint8_t is_update : 1; // 判断是否需要进入bootloader + }; + }; + +} BL_Setting_t; + +#endif \ No newline at end of file diff --git a/projects/HSLink-Pro/common/HSLink_Pro_expansion.c b/projects/HSLink-Pro/common/HSLink_Pro_expansion.c new file mode 100644 index 0000000..d0ad076 --- /dev/null +++ b/projects/HSLink-Pro/common/HSLink_Pro_expansion.c @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2024 HalfSweet + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "hpm_common.h" +#include +#include +#include +#include +#include "HSLink_Pro_expansion.h" +#include "board.h" +#include "hpm_gptmr_drv.h" +#include "hpm_gpio_drv.h" +#include "hpm_adc16_drv.h" +#include "hpm_mchtmr_drv.h" + +const double ADC_REF = 3.3; + +GPTMR_Type *const USER_PWM = HPM_GPTMR0; +const clock_name_t USER_PWM_CLK = clock_gptmr0; +const uint8_t PWM_CHANNEL = 2; + +ADC16_Type *const USER_ADC = HPM_ADC0; + +const uint32_t DEFAULT_PWM_FREQ = 100000; +const uint8_t DEFAULT_PWM_DUTY = 50; + +const uint8_t DEFAULT_ADC_RUN_MODE = adc16_conv_mode_oneshot; +const uint8_t DEFAULT_ADC_CYCLE = 20; + +static uint32_t pwm_current_reload; + +static uint64_t MCHTMR_CLK_FREQ = 0; + +volatile bool WS2812_Update_Flag = false; + +static const uint32_t CONFIG_P_EN = IOC_PAD_PA31; + +static void set_pwm_waveform_edge_aligned_frequency(uint32_t freq) +{ + gptmr_channel_config_t config; + uint32_t gptmr_freq; + + gptmr_channel_get_default_config(USER_PWM, &config); + gptmr_freq = clock_get_frequency(USER_PWM_CLK); + pwm_current_reload = gptmr_freq / freq; + config.reload = pwm_current_reload; + config.cmp_initial_polarity_high = false; + gptmr_stop_counter(USER_PWM, PWM_CHANNEL); + gptmr_channel_config(USER_PWM, PWM_CHANNEL, &config, false); + gptmr_channel_reset_count(USER_PWM, PWM_CHANNEL); + gptmr_start_counter(USER_PWM, PWM_CHANNEL); +} + +static void set_pwm_waveform_edge_aligned_duty(uint8_t duty) +{ + uint32_t cmp; + if (duty > 100) { + duty = 100; + } + cmp = ((pwm_current_reload * duty) / 100) + 1; + gptmr_update_cmp(USER_PWM, PWM_CHANNEL, 0, cmp); +} + +static void Power_Enable_Init(void) +{ + // PY0 高电平有效 + HPM_PIOC->PAD[IOC_PAD_PY00].FUNC_CTL = PIOC_PY00_FUNC_CTL_SOC_GPIO_Y_00; + HPM_IOC->PAD[IOC_PAD_PY00].FUNC_CTL = IOC_PY00_FUNC_CTL_GPIO_Y_00; + + gpiom_set_pin_controller(HPM_GPIOM, GPIOM_ASSIGN_GPIOY, 0, gpiom_soc_gpio0); + gpio_set_pin_output(HPM_GPIO0, GPIO_OE_GPIOY, 0); + gpio_write_pin(HPM_GPIO0, GPIO_DO_GPIOY, 0, 0); +} + +ATTR_ALWAYS_INLINE +static inline void Power_Turn_On(void) +{ + gpio_write_pin(HPM_GPIO0, GPIO_GET_PORT_INDEX(CONFIG_P_EN), GPIO_GET_PIN_INDEX(CONFIG_P_EN), 1); +} + +ATTR_ALWAYS_INLINE +static inline void Power_Turn_Off(void) +{ + gpio_write_pin(HPM_GPIO0, GPIO_GET_PORT_INDEX(CONFIG_P_EN), GPIO_GET_PIN_INDEX(CONFIG_P_EN), 0); +} + +static void Power_PWM_Init(void) +{ + // PA10 100k PWM,占空比50% + HPM_IOC->PAD[IOC_PAD_PA10].FUNC_CTL = IOC_PA10_FUNC_CTL_GPTMR0_COMP_2; + set_pwm_waveform_edge_aligned_frequency(DEFAULT_PWM_FREQ); + set_pwm_waveform_edge_aligned_duty(DEFAULT_PWM_DUTY); +} + +static void Power_Set_TVCC_Voltage(double voltage) +{ + // voltage = -DAC + (1974/395) + // DAC = -voltage + (1974/395) + + // PWM DAC需要输出的电压 + double dac = -voltage + (1974.0 / 395.0); + if (dac < 0) { + dac = 0; + } else if (dac > 3.3) { + dac = 3.3; + } + + // 计算PWM占空比 + uint8_t duty = (uint8_t)(dac / 3.3 * 100); + set_pwm_waveform_edge_aligned_duty(duty); +} + +static void ADC_Init() +{ + /* Configure the ADC clock from AHB (@200MHz by default)*/ + clock_set_adc_source(clock_adc0, clk_adc_src_ahb0); + + adc16_config_t cfg; + + /* initialize an ADC instance */ + adc16_get_default_config(&cfg); + + cfg.res = adc16_res_16_bits; + cfg.conv_mode = DEFAULT_ADC_RUN_MODE; + cfg.adc_clk_div = adc16_clock_divider_4; + cfg.sel_sync_ahb = (clk_adc_src_ahb0 == clock_get_source(BOARD_APP_ADC16_CLK_NAME)) ? true : false; + + if (cfg.conv_mode == adc16_conv_mode_sequence || + cfg.conv_mode == adc16_conv_mode_preemption) { + cfg.adc_ahb_en = true; + } + + /* adc16 initialization */ + if (adc16_init(USER_ADC, &cfg) == status_success) { + /* enable irq */ + // intc_m_enable_irq_with_priority(BOARD_APP_ADC16_IRQn, 1); + } +} + +static void ADC_Channel_Init(USER_ADC_CHANNEL_t channel) +{ + adc16_channel_config_t ch_cfg; + + /* get a default channel config */ + adc16_get_channel_default_config(&ch_cfg); + + /* initialize an ADC channel */ + ch_cfg.ch = channel; + ch_cfg.sample_cycle = DEFAULT_ADC_CYCLE; + + adc16_init_channel(USER_ADC, &ch_cfg); + + adc16_set_nonblocking_read(USER_ADC); + +#if defined(ADC_SOC_BUSMODE_ENABLE_CTRL_SUPPORT) && ADC_SOC_BUSMODE_ENABLE_CTRL_SUPPORT + /* enable oneshot mode */ + adc16_enable_oneshot_mode(USER_ADC); +#endif +} + +static uint16_t Get_ADC_Value(USER_ADC_CHANNEL_t channel) +{ + ADC_Channel_Init(channel); + + uint16_t result = 0; + + if (adc16_get_oneshot_result(USER_ADC, channel, &result) == status_success) { + if (adc16_is_nonblocking_mode(USER_ADC)) { + adc16_get_oneshot_result(USER_ADC, channel, &result); + } + } + + return result; +} + +ATTR_ALWAYS_INLINE +static inline void VREF_Init(void) +{ + // VREF 的输入是 PB08 + HPM_IOC->PAD[IOC_PAD_PB08].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK; +} + +ATTR_ALWAYS_INLINE +static inline void TVCC_Init(void) +{ + // TVCC 的输入是 PB09 + HPM_IOC->PAD[IOC_PAD_PB09].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK; +} + +ATTR_ALWAYS_INLINE +static inline double Get_VREF_Voltage(void) +{ + return (double)Get_ADC_Value(USER_ADC_VREF_CHANNEL) * ADC_REF / 65535 * 2; +} + +ATTR_ALWAYS_INLINE +static double inline Get_TVCC_Voltage(void) +{ + return (double)Get_ADC_Value(USER_ADC_TVCC_CHANNEL) * ADC_REF / 65535 * 2; +} + +ATTR_ALWAYS_INLINE +static inline void BOOT_Init(void) +{ + // PA03 + HPM_IOC->PAD[IOC_PAD_PA03].FUNC_CTL = IOC_PA03_FUNC_CTL_GPIO_A_03; + + gpiom_set_pin_controller(HPM_GPIOM, GPIOM_ASSIGN_GPIOA, 3, gpiom_soc_gpio0); + gpio_set_pin_input(HPM_GPIO0, GPIO_OE_GPIOA, 3); + gpio_disable_pin_interrupt(HPM_GPIO0, GPIO_IE_GPIOA, 3); +} + +static uint32_t millis(void) +{ + uint64_t mchtmr_count = mchtmr_get_count(HPM_MCHTMR); + return (uint32_t)(mchtmr_count * 1000 / MCHTMR_CLK_FREQ); +} + +static bool BOOT_Button_Pressed(void) +{ + static bool last_state = false; + bool current_state = gpio_read_pin(HPM_GPIO0, GPIO_DI_GPIOA, 3) == 1; + static uint64_t now = 0; + + if (current_state == true) { + if (last_state == false) { + now = millis(); + last_state = true; + } else { + if (millis() - now > 1000) // 长按1000ms + { + last_state = false; + return true; + } + } + } else { + last_state = false; + } + return false; +} + +void HSP_Init(void) +{ + MCHTMR_CLK_FREQ = clock_get_frequency(clock_mchtmr0); + // 初始化电源部分 + Power_Enable_Init(); + Power_PWM_Init(); + + // 初始化ADC部分 + ADC_Init(); + VREF_Init(); + TVCC_Init(); + + BOOT_Init(); + + WS2812_Init(); +} + +void HSP_Loop(void) +{ + // 检测VREF电压 + double vref = Get_VREF_Voltage(); + + if (vref > 0.6) { + Power_Set_TVCC_Voltage(vref); + Power_Turn_On(); + } else { + Power_Turn_Off(); + Power_Set_TVCC_Voltage(3.3); + } + + if (BOOT_Button_Pressed()) { + printf("Enter Bootloader\n"); + Power_Turn_Off(); + + l1c_dc_disable(); + + api_boot_arg_t boot_arg = { + .index = 0, + .peripheral = API_BOOT_PERIPH_AUTO, + .src = API_BOOT_SRC_PRIMARY, + .tag = API_BOOT_TAG, + }; + + ROM_API_TABLE_ROOT->run_bootloader(&boot_arg); + } + + if (WS2812_Update_Flag) { + WS2812_Update(); + WS2812_Update_Flag = false; + } +} diff --git a/projects/HSLink-Pro/common/HSLink_Pro_expansion.h b/projects/HSLink-Pro/common/HSLink_Pro_expansion.h new file mode 100644 index 0000000..12c7c02 --- /dev/null +++ b/projects/HSLink-Pro/common/HSLink_Pro_expansion.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 HalfSweet + * + * 参考硬件设计:https://github.com/HalfSweet/HSLinkPro-Hardware + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef HPM5300EVKLITE_DAP_HSLINK_PRO_EXPANSION_H +#define HPM5300EVKLITE_DAP_HSLINK_PRO_EXPANSION_H + +typedef enum { + USER_ADC_VREF_CHANNEL = 11, + USER_ADC_TVCC_CHANNEL = 1, +} USER_ADC_CHANNEL_t; + +/** + * @brief 外部扩展初始化 + */ +void HSP_Init(void); + +/** + * @brief 外部扩展循环,放入主循环中 + */ +void HSP_Loop(void); + +#endif //HPM5300EVKLITE_DAP_HSLINK_PRO_EXPANSION_H diff --git a/projects/HSLink-Pro/common/WS2812_Conf.h b/projects/HSLink-Pro/common/WS2812_Conf.h new file mode 100644 index 0000000..b2b315e --- /dev/null +++ b/projects/HSLink-Pro/common/WS2812_Conf.h @@ -0,0 +1,25 @@ +#ifndef WS2812_WS2812_CONF_TEMPLATE_H +#define WS2812_WS2812_CONF_TEMPLATE_H + +#include "WS2812_Type.h" +#include + +#define WS2812_DIN PA02 +#define WS2812_GPTMR 1 +#define WS2812_GPTMR_CHANNLE 1 + +#define WS2812_LED_CONNECT WS2812_CONNECT_LINE + +#if WS2812_LED_CONNECT == WS2812_CONNECT_LINE +#define WS2812_LED_NUM 1 +#elif WS2812_LED_CONNECT == WS2812_CONNECT_MATRIX +#define WS2812_LED_COL 5 // 行 +#define WS2812_LED_ROW 5 // 列 +#define WS2812_LED_NUM (WS2812_LED_COL * WS2812_LED_ROW) +#elif WS2812_LED_CONNECT == WS2812_CONNECT_3D +#define WS2812_LED_COL 5 // 行 +#define WS2812_LED_ROW 5 // 列 +#define WS2812_LED_LAYER 5 // 层 +#define WS2812_LED_NUM (WS2812_LED_COL * WS2812_LED_ROW * WS2812_LED_LAYER) +#endif +#endif // WS2812_WS2812_CONF_TEMPLATE_H diff --git a/projects/HSLink-Pro/scripts/uf2conv.py b/projects/HSLink-Pro/scripts/uf2conv.py new file mode 100644 index 0000000..e0d5d1a --- /dev/null +++ b/projects/HSLink-Pro/scripts/uf2conv.py @@ -0,0 +1,319 @@ +#!/usr/bin/env python3 +import sys +import struct +import subprocess +import re +import os +import os.path +import argparse + + +UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" +UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected +UF2_MAGIC_END = 0x0AB16F30 # Ditto + +families = { + 'SAMD21': 0x68ed2b88, + 'SAML21': 0x1851780a, + 'SAMD51': 0x55114460, + 'NRF52': 0x1b57745f, + 'STM32F0': 0x647824b6, + 'STM32F1': 0x5ee21072, + 'STM32F2': 0x5d1a0a2e, + 'STM32F3': 0x6b846188, + 'STM32F4': 0x57755a57, + 'STM32F7': 0x53b80f00, + 'STM32G0': 0x300f5633, + 'STM32G4': 0x4c71240a, + 'STM32H7': 0x6db66082, + 'STM32L0': 0x202e3a91, + 'STM32L1': 0x1e1f432d, + 'STM32L4': 0x00ff6919, + 'STM32L5': 0x04240bdf, + 'STM32WB': 0x70d16653, + 'STM32WL': 0x21460ff0, + 'ATMEGA32': 0x16573617, + 'MIMXRT10XX': 0x4FB2D5BD, + 'LPC55': 0x2abc77ec, + 'GD32F350': 0x31D228C6, + 'ESP32S2': 0xbfdd4eee, + 'HPM6700': 0x0A4D5048 +} + +INFO_FILE = "/INFO_UF2.TXT" + +appstartaddr = 0x2000 +familyid = 0x0 + + +def is_uf2(buf): + w = struct.unpack(" 476: + assert False, "Invalid UF2 data size at " + ptr + newaddr = hd[3] + if curraddr == None: + appstartaddr = newaddr + curraddr = newaddr + padding = newaddr - curraddr + if padding < 0: + assert False, "Block out of order at " + ptr + if padding > 10*1024*1024: + assert False, "More than 10M of padding needed at " + ptr + if padding % 4 != 0: + assert False, "Non-word padding size at " + ptr + while padding > 0: + padding -= 4 + outp += b"\x00\x00\x00\x00" + outp.append(block[32 : 32 + datalen]) + curraddr = newaddr + datalen + return b"".join(outp) + +def convert_to_carray(file_content): + outp = "const unsigned long bindata_len = %d;\n" % len(file_content) + outp += "const unsigned char bindata[] __attribute__((aligned(16))) = {" + for i in range(len(file_content)): + if i % 16 == 0: + outp += "\n" + outp += "0x%02x, " % file_content[i] + outp += "\n};\n" + return bytes(outp, "utf-8") + +def convert_to_uf2(file_content): + global familyid + datapadding = b"" + while len(datapadding) < 512 - 256 - 32 - 4: + datapadding += b"\x00\x00\x00\x00" + numblocks = (len(file_content) + 255) // 256 + outp = [] + for blockno in range(numblocks): + ptr = 256 * blockno + chunk = file_content[ptr:ptr + 256] + flags = 0x0 + if familyid: + flags |= 0x2000 + hd = struct.pack(b"= 3 and words[1] == "2" and words[2] == "FAT": + drives.append(words[0]) + else: + rootpath = "/media" + if sys.platform == "darwin": + rootpath = "/Volumes" + elif sys.platform == "linux": + tmp = rootpath + "/" + os.environ["USER"] + if os.path.isdir(tmp): + rootpath = tmp + for d in os.listdir(rootpath): + drives.append(os.path.join(rootpath, d)) + + + def has_info(d): + try: + return os.path.isfile(d + INFO_FILE) + except: + return False + + return list(filter(has_info, drives)) + + +def board_id(path): + with open(path + INFO_FILE, mode='r') as file: + file_content = file.read() + return re.search("Board-ID: ([^\r\n]*)", file_content).group(1) + + +def list_drives(): + for d in get_drives(): + print(d, board_id(d)) + + +def write_file(name, buf): + with open(name, "wb") as f: + f.write(buf) + print("Wrote %d bytes to %s" % (len(buf), name)) + + +def main(): + global appstartaddr, familyid + def error(msg): + print(msg) + sys.exit(1) + parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.') + parser.add_argument('input', metavar='INPUT', type=str, nargs='?', + help='input file (HEX, BIN or UF2)') + parser.add_argument('-b' , '--base', dest='base', type=str, + default="0x2000", + help='set base address of application for BIN format (default: 0x2000)') + parser.add_argument('-o' , '--output', metavar="FILE", dest='output', type=str, + help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible') + parser.add_argument('-d' , '--device', dest="device_path", + help='select a device path to flash') + parser.add_argument('-l' , '--list', action='store_true', + help='list connected devices') + parser.add_argument('-c' , '--convert', action='store_true', + help='do not flash, just convert') + parser.add_argument('-D' , '--deploy', action='store_true', + help='just flash, do not convert') + parser.add_argument('-f' , '--family', dest='family', type=str, + default="0x0", + help='specify familyID - number or name (default: 0x0)') + parser.add_argument('-C' , '--carray', action='store_true', + help='convert binary file to a C array, not UF2') + args = parser.parse_args() + appstartaddr = int(args.base, 0) + + if args.family.upper() in families: + familyid = families[args.family.upper()] + else: + try: + familyid = int(args.family, 0) + except ValueError: + error("Family ID needs to be a number or one of: " + ", ".join(families.keys())) + + if args.list: + list_drives() + else: + if not args.input: + error("Need input file") + with open(args.input, mode='rb') as f: + inpbuf = f.read() + from_uf2 = is_uf2(inpbuf) + ext = "uf2" + if args.deploy: + outbuf = inpbuf + elif from_uf2: + outbuf = convert_from_uf2(inpbuf) + ext = "bin" + elif is_hex(inpbuf): + outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8")) + elif args.carray: + outbuf = convert_to_carray(inpbuf) + ext = "h" + else: + outbuf = convert_to_uf2(inpbuf) + print("Converting to %s, output size: %d, start address: 0x%x" % + (ext, len(outbuf), appstartaddr)) + if args.convert or ext != "uf2": + drives = [] + if args.output == None: + args.output = "flash." + ext + else: + drives = get_drives() + + if args.output: + write_file(args.output, outbuf) + else: + if len(drives) == 0: + error("No drive to deploy.") + for d in drives: + print("Flashing %s (%s)" % (d, board_id(d))) + write_file(d + "/NEW.UF2", outbuf) + + +if __name__ == "__main__": + main() diff --git a/projects/HSLink-Pro/src/.gitignore b/projects/HSLink-Pro/src/.gitignore new file mode 100644 index 0000000..daa9dd7 --- /dev/null +++ b/projects/HSLink-Pro/src/.gitignore @@ -0,0 +1,28 @@ +.DS_Store +.swp +.bak +cscope.* +*.orig +*.patch + +build +*_build +cmake-build* +.idea +.vscode +.cache + +*.log +*.jou +.settings +.cproject +.project + +doctrees +doc/output/* + +segger_embedded_studio +*.pyc +sec_core_img.c +*.o + diff --git a/projects/HSLink-Pro/src/.version b/projects/HSLink-Pro/src/.version new file mode 100644 index 0000000..5c2ca7c --- /dev/null +++ b/projects/HSLink-Pro/src/.version @@ -0,0 +1 @@ +2.2.4.IO \ No newline at end of file diff --git a/projects/HSLink-Pro/src/CMakeLists.txt b/projects/HSLink-Pro/src/CMakeLists.txt new file mode 100644 index 0000000..87df9b9 --- /dev/null +++ b/projects/HSLink-Pro/src/CMakeLists.txt @@ -0,0 +1,110 @@ +# Copyright (c) 2023 HPMicro +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.13) + +option(CONFIG_HSLINK_PRO_EXPANSION "Enable HSLink Pro expansion" OFF) + +option(CONFIG_SWDIO_DIR "SWDIO direction" OFF) + +set(APP_NAME "HSLink-Pro") + +set(CONFIG_USB_DEVICE 1) +set(CONFIG_DMA_MGR 1) + +# CONFIG_USE_HPM_BOARD_JTAG_GPIO is for 20p output SWD+JTAG signal of hpm5301evklite +set(CONFIG_USE_HPM_BOARD_JTAG_GPIO 0) + +if (NOT DEFINED CONFIG_USE_HPM_BOARD_JTAG_GPIO OR (CONFIG_USE_HPM_BOARD_JTAG_GPIO EQUAL "0")) + set(CONFIG_USE_SPI_SWD 0) + set(CONFIG_USE_SPI_JTAG 0) +endif () + +find_package(hpm-sdk REQUIRED HINTS $ENV{HPM_SDK_BASE}) + +project(HSLink-Pro) + +add_subdirectory(../WS2812 ${CMAKE_CURRENT_BINARY_DIR}/ws2812) + +# 设置版本号 +if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.version) + file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/.version BUILD_VERSION) + string(STRIP ${BUILD_VERSION} BUILD_VERSION) + set(CONFIG_BUILD_VERSION ${BUILD_VERSION}) +endif () + +# for sync, use cherryusb from cherryDAP instead of hpm sdk middleware +sdk_compile_definitions(-DCONFIG_USB_HS) +sdk_inc(../../../CherryUSB/common) +sdk_inc(../../../CherryUSB/core) +sdk_inc(../../../CherryUSB/class/cdc) +sdk_inc(../../../CherryUSB/class/msc) +sdk_inc(../../../CherryUSB/class/hid) +sdk_src(../../../CherryUSB/core/usbd_core.c) +sdk_src(../../../CherryUSB/port/hpm/usb_dc_hpm.c) +sdk_src(../../../CherryUSB/class/cdc/usbd_cdc_acm.c) +sdk_src(../../../CherryUSB/class/hid/usbd_hid.c) + +# swj_clock default use keil swd frequency boost +sdk_compile_definitions(-DBOOST_KEIL_SWD_FREQ=0) + +sdk_compile_definitions(-DPIN_JTAG_TRST=IOC_PAD_PB14) +sdk_compile_definitions(-DPIN_SRST=IOC_PAD_PB15) + +sdk_compile_definitions(-DCONFIG_WS2812=1) + +if (CONFIG_SWDIO_DIR) + sdk_compile_definitions(-DSWDIO_DIR=${CONFIG_SWDIO_DIR}) +endif () + +if (DEFINED CONFIG_USE_SPI_SWD AND (CONFIG_USE_SPI_SWD EQUAL "1")) + sdk_compile_definitions(-DUSE_SPI_SWD=1) + sdk_app_src(SW_DP_SPI.c) +else () + sdk_app_src(../../../DAP/Source/SW_DP.c) +endif () + +if (DEFINED CONFIG_USE_SPI_JTAG AND (CONFIG_USE_SPI_JTAG EQUAL "1")) + sdk_compile_definitions(-DUSE_SPI_JTAG=1) + sdk_app_src(JTAG_DP_SPI.c) +else () + sdk_app_src(../../../DAP/Source/JTAG_DP.c) +endif () + + +sdk_inc(.) +sdk_inc(../../..) +sdk_inc(../../../CherryRB) +sdk_inc(../../../DAP/Include) + +sdk_inc(../common) + +sdk_app_src(../../../dap_main.c) +sdk_app_src(../../../DAP/Source/DAP_vendor.c) +sdk_app_src(../../../DAP/Source/DAP.c) + +sdk_app_src(../../../CherryRB/chry_ringbuffer.c) + +sdk_app_src(main.c) +sdk_app_src(usb2uart.c) +sdk_app_src(dp_common.c) + +if (CONFIG_BUILD_VERSION) + sdk_compile_definitions(-DDAP_FW_VER="2.1.1") +else () + sdk_compile_definitions(-DDAP_FW_VER="Debug") +endif () + +sdk_compile_definitions(-DPRODUCT_STRING="HSLink Pro") +#sdk_compile_definitions(-DCONFIG_USE_HID_CONFIG=1) +sdk_app_src(../common/HSLink_Pro_expansion.c) +sdk_compile_options("-g") + +# 执行完之后转换为uf2 +add_custom_command( + TARGET ${APP_ELF_NAME} POST_BUILD + COMMAND ${python_exec} ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/uf2conv.py -f 0x0A4D5048 -b 0x80020000 -c ${CMAKE_BINARY_DIR}/output/${APP_BIN_NAME} -o ${CMAKE_BINARY_DIR}/output/${APP_NAME}.uf2 + COMMENT "Convert to UF2" +) + +#generate_ses_project() \ No newline at end of file diff --git a/projects/HSLink-Pro/src/DAP_config.h b/projects/HSLink-Pro/src/DAP_config.h new file mode 100644 index 0000000..798f9bc --- /dev/null +++ b/projects/HSLink-Pro/src/DAP_config.h @@ -0,0 +1,857 @@ +/* + * Copyright (c) 2013-2021 ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ---------------------------------------------------------------------- + * + * $Date: 16. June 2021 + * $Revision: V2.1.0 + * + * Project: CMSIS-DAP Configuration + * Title: DAP_config.h CMSIS-DAP Configuration File (Template) + * + *---------------------------------------------------------------------------*/ + +#ifndef __DAP_CONFIG_H__ +#define __DAP_CONFIG_H__ + + +//************************************************************************************************** +/** +\defgroup DAP_Config_Debug_gr CMSIS-DAP Debug Unit Information +\ingroup DAP_ConfigIO_gr +@{ +Provides definitions about the hardware and configuration of the Debug Unit. + +This information includes: + - Definition of Cortex-M processor parameters used in CMSIS-DAP Debug Unit. + - Debug Unit Identification strings (Vendor, Product, Serial Number). + - Debug Unit communication packet size. + - Debug Access Port supported modes and settings (JTAG/SWD and SWO). + - Optional information about a connected Target Device (for Evaluation Boards). +*/ + +#include +#include +#include +#include "stdint.h" + +#ifndef __STATIC_INLINE +#define __STATIC_INLINE static inline +#endif +#ifndef __STATIC_FORCEINLINE +#define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline +#endif +#ifndef __WEAK +#define __WEAK __attribute__((weak)) +#endif + +/// Processor Clock of the Cortex-M MCU used in the Debug Unit. +/// This value is used to calculate the SWD/JTAG clock speed. +#define CPU_CLOCK 36000000U ///< Specifies the CPU Clock in Hz. + +/// Number of processor cycles for I/O Port write operations. +/// This value is used to calculate the SWD/JTAG clock speed that is generated with I/O +/// Port write operations in the Debug Unit by a Cortex-M MCU. Most Cortex-M processors +/// require 2 processor cycles for a I/O Port Write operation. If the Debug Unit uses +/// a Cortex-M0+ processor with high-speed peripheral I/O only 1 processor cycle might be +/// required. +#define IO_PORT_WRITE_CYCLES 1U ///< I/O Cycles: 2=default, 1=Cortex-M0+ fast I/0. + +/// Indicate that Serial Wire Debug (SWD) communication mode is available at the Debug Access Port. +/// This information is returned by the command \ref DAP_Info as part of Capabilities. +#define DAP_SWD 1 ///< SWD Mode: 1 = available, 0 = not available. + +/// Indicate that JTAG communication mode is available at the Debug Port. +/// This information is returned by the command \ref DAP_Info as part of Capabilities. +#define DAP_JTAG 1 ///< JTAG Mode: 1 = available, 0 = not available. + +/// Configure maximum number of JTAG devices on the scan chain connected to the Debug Access Port. +/// This setting impacts the RAM requirements of the Debug Unit. Valid range is 1 .. 255. +#define DAP_JTAG_DEV_CNT 8U ///< Maximum number of JTAG devices on scan chain. + +/// Default communication mode on the Debug Access Port. +/// Used for the command \ref DAP_Connect when Port Default mode is selected. +#define DAP_DEFAULT_PORT 1U ///< Default JTAG/SWJ Port Mode: 1 = SWD, 2 = JTAG. + +/// Default communication speed on the Debug Access Port for SWD and JTAG mode. +/// Used to initialize the default SWD/JTAG clock frequency. +/// The command \ref DAP_SWJ_Clock can be used to overwrite this default setting. +#define DAP_DEFAULT_SWJ_CLOCK 10000000U ///< Default SWD/JTAG clock frequency in Hz. + +/// Maximum Package Size for Command and Response data. +/// This configuration settings is used to optimize the communication performance with the +/// debugger and depends on the USB peripheral. Typical vales are 64 for Full-speed USB HID or WinUSB, +/// 1024 for High-speed USB HID and 512 for High-speed USB WinUSB. +#define DAP_PACKET_SIZE 512U ///< Specifies Packet Size in bytes. + +/// Maximum Package Buffers for Command and Response data. +/// This configuration settings is used to optimize the communication performance with the +/// debugger and depends on the USB peripheral. For devices with limited RAM or USB buffer the +/// setting can be reduced (valid range is 1 .. 255). +#define DAP_PACKET_COUNT 8U ///< Specifies number of packets buffered. + +/// Indicate that UART Serial Wire Output (SWO) trace is available. +/// This information is returned by the command \ref DAP_Info as part of Capabilities. +#define SWO_UART 0 ///< SWO UART: 1 = available, 0 = not available. + +/// USART Driver instance number for the UART SWO. +#define SWO_UART_DRIVER 0 ///< USART Driver instance number (Driver_USART#). + +/// Maximum SWO UART Baudrate. +#define SWO_UART_MAX_BAUDRATE 10000000U ///< SWO UART Maximum Baudrate in Hz. + +/// Indicate that Manchester Serial Wire Output (SWO) trace is available. +/// This information is returned by the command \ref DAP_Info as part of Capabilities. +#define SWO_MANCHESTER 0 ///< SWO Manchester: 1 = available, 0 = not available. + +/// SWO Trace Buffer Size. +#define SWO_BUFFER_SIZE 4096U ///< SWO Trace Buffer Size in bytes (must be 2^n). + +/// SWO Streaming Trace. +#define SWO_STREAM 0 ///< SWO Streaming Trace: 1 = available, 0 = not available. + +/// Clock frequency of the Test Domain Timer. Timer value is returned with \ref TIMESTAMP_GET. +#define TIMESTAMP_CLOCK 100000000U ///< Timestamp clock in Hz (0 = timestamps not supported). + +/// Indicate that UART Communication Port is available. +/// This information is returned by the command \ref DAP_Info as part of Capabilities. +#define DAP_UART 0 ///< DAP UART: 1 = available, 0 = not available. + +/// USART Driver instance number for the UART Communication Port. +#define DAP_UART_DRIVER 1 ///< USART Driver instance number (Driver_USART#). + +/// UART Receive Buffer Size. +#define DAP_UART_RX_BUFFER_SIZE 1024U ///< Uart Receive Buffer Size in bytes (must be 2^n). + +/// UART Transmit Buffer Size. +#define DAP_UART_TX_BUFFER_SIZE 1024U ///< Uart Transmit Buffer Size in bytes (must be 2^n). + +/// Indicate that UART Communication via USB COM Port is available. +/// This information is returned by the command \ref DAP_Info as part of Capabilities. +#define DAP_UART_USB_COM_PORT 1 ///< USB COM Port: 1 = available, 0 = not available. + + +/// Debug Unit is connected to fixed Target Device. +/// The Debug Unit may be part of an evaluation board and always connected to a fixed +/// known device. In this case a Device Vendor, Device Name, Board Vendor and Board Name strings +/// are stored and may be used by the debugger or IDE to configure device parameters. +#define TARGET_FIXED 0 ///< Target: 1 = known, 0 = unknown; + +#define TARGET_DEVICE_VENDOR "Arm" ///< String indicating the Silicon Vendor +#define TARGET_DEVICE_NAME "Cortex-M" ///< String indicating the Target Device +#define TARGET_BOARD_VENDOR "Arm" ///< String indicating the Board Vendor +#define TARGET_BOARD_NAME "Arm board" ///< String indicating the Board Name + +#if TARGET_FIXED != 0 +#include +static const char TargetDeviceVendor [] = TARGET_DEVICE_VENDOR; +static const char TargetDeviceName [] = TARGET_DEVICE_NAME; +static const char TargetBoardVendor [] = TARGET_BOARD_VENDOR; +static const char TargetBoardName [] = TARGET_BOARD_NAME; +#endif + +/** Get Vendor Name string. +\param str Pointer to buffer to store the string (max 60 characters). +\return String length (including terminating NULL character) or 0 (no string). +*/ +__STATIC_INLINE uint8_t DAP_GetVendorString (char *str) { +// static const char * Vendor = "CherryDAP"; +// uint8_t len = strlen(Vendor); +// for(uint32_t i = 0; i < len; i++) { +// str[i] = Vendor[i]; +// } +// return len; + (void)str; + return (0U); +} + +/** Get Product Name string. +\param str Pointer to buffer to store the string (max 60 characters). +\return String length (including terminating NULL character) or 0 (no string). +*/ +__STATIC_INLINE uint8_t DAP_GetProductString (char *str) { +//#ifdef PRODUCT_STRING +#if 0 + static const char * Product = PRODUCT_STRING; + uint8_t len = strlen(Product); + for(uint32_t i = 0; i < len; i++) { + str[i] = Product[i]; + } + return len; +#else + (void)str; + return (0U); +#endif +} + +/** Get Serial Number string. +\param str Pointer to buffer to store the string (max 60 characters). +\return String length (including terminating NULL character) or 0 (no string). +*/ +__STATIC_INLINE uint8_t DAP_GetSerNumString (char *str) { +// extern char serial_number[32]; +// uint8_t len = strlen(serial_number); +// for(uint32_t i = 0; i < len; i++) { +// str[i] = serial_number[i]; +// } +// return len; + (void)str; + return (0U); +} + +/** Get Target Device Vendor string. +\param str Pointer to buffer to store the string (max 60 characters). +\return String length (including terminating NULL character) or 0 (no string). +*/ +__STATIC_INLINE uint8_t DAP_GetTargetDeviceVendorString (char *str) { +#if TARGET_FIXED != 0 + uint8_t len; + + strcpy(str, TargetDeviceVendor); + len = (uint8_t)(strlen(TargetDeviceVendor) + 1U); + return (len); +#else + (void)str; + return (0U); +#endif +} + +/** Get Target Device Name string. +\param str Pointer to buffer to store the string (max 60 characters). +\return String length (including terminating NULL character) or 0 (no string). +*/ +__STATIC_INLINE uint8_t DAP_GetTargetDeviceNameString (char *str) { +#if TARGET_FIXED != 0 + uint8_t len; + + strcpy(str, TargetDeviceName); + len = (uint8_t)(strlen(TargetDeviceName) + 1U); + return (len); +#else + (void)str; + return (0U); +#endif +} + +/** Get Target Board Vendor string. +\param str Pointer to buffer to store the string (max 60 characters). +\return String length (including terminating NULL character) or 0 (no string). +*/ +__STATIC_INLINE uint8_t DAP_GetTargetBoardVendorString (char *str) { +#if TARGET_FIXED != 0 + uint8_t len; + + strcpy(str, TargetBoardVendor); + len = (uint8_t)(strlen(TargetBoardVendor) + 1U); + return (len); +#else + (void)str; + return (0U); +#endif +} + +/** Get Target Board Name string. +\param str Pointer to buffer to store the string (max 60 characters). +\return String length (including terminating NULL character) or 0 (no string). +*/ +__STATIC_INLINE uint8_t DAP_GetTargetBoardNameString (char *str) { +#if TARGET_FIXED != 0 + uint8_t len; + + strcpy(str, TargetBoardName); + len = (uint8_t)(strlen(TargetBoardName) + 1U); + return (len); +#else + (void)str; + return (0U); +#endif +} + +/** Get Product Firmware Version string. +\param str Pointer to buffer to store the string (max 60 characters). +\return String length (including terminating NULL character) or 0 (no string). +*/ +__STATIC_INLINE uint8_t DAP_GetProductFirmwareVersionString (char *str) { +#ifdef CONFIG_BUILD_VERSION + const char * version = CONFIG_BUILD_VERSION; +#else + const char * version = DAP_FW_VER; +#endif +// uint8_t len = strlen(version); +// for(uint32_t i = 0; i < len; i++) { +// str[i] = version[i]; +// } +// return len; + (void)str; + return (0U); +} + +///@} + +#include "hpm_gpio_drv.h" +#include "hpm_gpiom_regs.h" +#include "hpm_gpiom_drv.h" +#include "hpm_soc.h" +#include "hpm_csr_drv.h" +#include "hpm_clock_drv.h" + +#define JTAG_SPI_BASE HPM_SPI2 +#define JTAG_SPI_BASE_CLOCK_NAME clock_spi2 + +#define SWD_SPI_BASE HPM_SPI1 +#define SWD_SPI_BASE_CLOCK_NAME clock_spi1 + +#define PIN_GPIOM_BASE HPM_GPIOM +#define PIN_GPIO HPM_FGPIO + +#if defined(USE_HPM_BOARD_JTAG_GPIO) && (USE_HPM_BOARD_JTAG_GPIO == 1) + #define PIN_TCK IOC_PAD_PA06 + #define PIN_TMS IOC_PAD_PA07 + #define PIN_TDI IOC_PAD_PA05 + #define PIN_TDO IOC_PAD_PA04 +#else + #define PIN_TCK IOC_PAD_PB11 + #define PIN_TMS IOC_PAD_PA29 + #define PIN_TDI IOC_PAD_PB13 + #define PIN_TDO IOC_PAD_PB12 +#endif + +//************************************************************************************************** +/** +\defgroup DAP_Config_PortIO_gr CMSIS-DAP Hardware I/O Pin Access +\ingroup DAP_ConfigIO_gr +@{ + +Standard I/O Pins of the CMSIS-DAP Hardware Debug Port support standard JTAG mode +and Serial Wire Debug (SWD) mode. In SWD mode only 2 pins are required to implement the debug +interface of a device. The following I/O Pins are provided: + +JTAG I/O Pin | SWD I/O Pin | CMSIS-DAP Hardware pin mode +---------------------------- | -------------------- | --------------------------------------------- +TCK: Test Clock | SWCLK: Clock | Output Push/Pull +TMS: Test Mode Select | SWDIO: Data I/O | Output Push/Pull; Input (for receiving data) +TDI: Test Data Input | | Output Push/Pull +TDO: Test Data Output | | Input +nTRST: Test Reset (optional) | | Output Open Drain with pull-up resistor +nRESET: Device Reset | nRESET: Device Reset | Output Open Drain with pull-up resistor + + +DAP Hardware I/O Pin Access Functions +------------------------------------- +The various I/O Pins are accessed by functions that implement the Read, Write, Set, or Clear to +these I/O Pins. + +For the SWDIO I/O Pin there are additional functions that are called in SWD I/O mode only. +This functions are provided to achieve faster I/O that is possible with some advanced GPIO +peripherals that can independently write/read a single I/O pin without affecting any other pins +of the same I/O port. The following SWDIO I/O Pin functions are provided: + - \ref PIN_SWDIO_OUT_ENABLE to enable the output mode from the DAP hardware. + - \ref PIN_SWDIO_OUT_DISABLE to enable the input mode to the DAP hardware. + - \ref PIN_SWDIO_IN to read from the SWDIO I/O pin with utmost possible speed. + - \ref PIN_SWDIO_OUT to write to the SWDIO I/O pin with utmost possible speed. +*/ + + +// Configure DAP I/O pins ------------------------------ + +/** Setup JTAG I/O pins: TCK, TMS, TDI, TDO, nTRST, and nRESET. +Configures the DAP Hardware I/O pins for JTAG mode: + - TCK, TMS, TDI, nTRST, nRESET to output mode and set to high level. + - TDO to input mode. +*/ +__STATIC_INLINE void gpiom_configure_pin_control_setting(uint16_t gpio_index) +{ + gpiom_set_pin_controller(PIN_GPIOM_BASE, GPIO_GET_PORT_INDEX(gpio_index), GPIO_GET_PIN_INDEX(gpio_index), gpiom_core0_fast); + gpiom_enable_pin_visibility(PIN_GPIOM_BASE, GPIO_GET_PORT_INDEX(gpio_index), GPIO_GET_PIN_INDEX(gpio_index), gpiom_core0_fast); + gpiom_lock_pin(PIN_GPIOM_BASE, GPIO_GET_PORT_INDEX(gpio_index), GPIO_GET_PIN_INDEX(gpio_index)); +} + +#if !defined(USE_SPI_JTAG) || (USE_SPI_JTAG == 0) +__STATIC_INLINE void PORT_JTAG_SETUP (void) { + HPM_IOC->PAD[PIN_TCK].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0) | IOC_PAD_FUNC_CTL_LOOP_BACK_MASK; /* as gpio*/ + HPM_IOC->PAD[PIN_TMS].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); /* as gpio*/ + HPM_IOC->PAD[PIN_TDI].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); /* as gpio*/ + HPM_IOC->PAD[PIN_TDO].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + HPM_IOC->PAD[PIN_JTAG_TRST].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + HPM_IOC->PAD[PIN_SRST].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + +#ifdef PIN_LED_RUNNING + HPM_IOC->PAD[PIN_LED_RUNNING].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + gpiom_configure_pin_control_setting(PIN_LED_RUNNING); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_RUNNING), GPIO_GET_PIN_INDEX(PIN_LED_RUNNING)); + HPM_IOC->PAD[PIN_LED_RUNNING].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); +#endif + +#ifdef PIN_LED_CONNECTED + HPM_IOC->PAD[PIN_LED_CONNECTED].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + gpiom_configure_pin_control_setting(PIN_LED_CONNECTED); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_CONNECTED), GPIO_GET_PIN_INDEX(PIN_LED_CONNECTED)); +#endif + + + gpiom_configure_pin_control_setting(PIN_TDO); + gpiom_configure_pin_control_setting(PIN_TCK); + gpiom_configure_pin_control_setting(PIN_TMS); + gpiom_configure_pin_control_setting(PIN_TDI); + gpiom_configure_pin_control_setting(PIN_JTAG_TRST); + gpiom_configure_pin_control_setting(PIN_SRST); + + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDO), GPIO_GET_PIN_INDEX(PIN_TDO)); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK)); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDI), GPIO_GET_PIN_INDEX(PIN_TDI)); + + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); // JTAG模式下SWDIO_DIR为高 + + HPM_IOC->PAD[PIN_TDO].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_TCK].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_TMS].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_TDI].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_JTAG_TRST].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_SRST].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); +} +#else +void PORT_JTAG_SETUP(void); +#endif + +/** Setup SWD I/O pins: SWCLK, SWDIO, and nRESET. +Configures the DAP Hardware I/O pins for Serial Wire Debug (SWD) mode: + - SWCLK, SWDIO, nRESET to output mode and set to default high level. + - TDI, nTRST to HighZ mode (pins are unused in SWD mode). +*/ +#if !defined(USE_SPI_SWD) || (USE_SPI_SWD == 0) +__STATIC_INLINE void PORT_SWD_SETUP (void) { + + HPM_IOC->PAD[PIN_TCK].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0) | IOC_PAD_FUNC_CTL_LOOP_BACK_MASK; /* as gpio*/ + HPM_IOC->PAD[PIN_TMS].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); /* as gpio*/ + HPM_IOC->PAD[PIN_SRST].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); +#ifdef PIN_LED_RUNNING + HPM_IOC->PAD[PIN_LED_RUNNING].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); +#endif + +#ifdef PIN_LED_CONNECTED + HPM_IOC->PAD[PIN_LED_CONNECTED].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); +#endif + +#ifdef PIN_LED_RUNNING + HPM_IOC->PAD[PIN_LED_RUNNING].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + gpiom_configure_pin_control_setting(PIN_LED_RUNNING); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_RUNNING), GPIO_GET_PIN_INDEX(PIN_LED_RUNNING)); + HPM_IOC->PAD[PIN_LED_RUNNING].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); +#endif + +#ifdef PIN_LED_CONNECTED + HPM_IOC->PAD[PIN_LED_CONNECTED].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + gpiom_configure_pin_control_setting(PIN_LED_CONNECTED); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_CONNECTED), GPIO_GET_PIN_INDEX(PIN_LED_CONNECTED)); +#endif + + gpiom_configure_pin_control_setting(PIN_TCK); + gpiom_configure_pin_control_setting(PIN_TMS); + gpiom_configure_pin_control_setting(PIN_SRST); + + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK)); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); + + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 0); // 默认SWDIO为输入 + + HPM_IOC->PAD[PIN_TCK].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_TMS].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_SRST].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); +} +#else +void PORT_SWD_SETUP(void); +#endif +/** Disable JTAG/SWD I/O Pins. +Disables the DAP Hardware I/O pins which configures: + - TCK/SWCLK, TMS/SWDIO, TDI, TDO, nTRST, nRESET to High-Z mode. +*/ +__STATIC_INLINE void PORT_OFF (void) { + HPM_IOC->PAD[PIN_TCK].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2); + HPM_IOC->PAD[PIN_TCK].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + + HPM_IOC->PAD[PIN_TMS].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2); + HPM_IOC->PAD[PIN_TMS].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + + HPM_IOC->PAD[PIN_TDI].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2); + HPM_IOC->PAD[PIN_TDI].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + + HPM_IOC->PAD[PIN_TDO].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2); + HPM_IOC->PAD[PIN_TDO].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + + HPM_IOC->PAD[PIN_SRST].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2); + HPM_IOC->PAD[PIN_SRST].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + + HPM_IOC->PAD[PIN_JTAG_TRST].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2); + HPM_IOC->PAD[PIN_JTAG_TRST].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK)); + gpio_disable_pin_interrupt(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK)); + gpiom_set_pin_controller(HPM_GPIOM, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK), gpiom_soc_gpio0); + + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); + gpio_disable_pin_interrupt(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); + gpiom_set_pin_controller(HPM_GPIOM, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS), gpiom_soc_gpio0); + + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDI), GPIO_GET_PIN_INDEX(PIN_TDI)); + gpio_disable_pin_interrupt(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDI), GPIO_GET_PIN_INDEX(PIN_TDI)); + gpiom_set_pin_controller(HPM_GPIOM, GPIO_GET_PORT_INDEX(PIN_TDI), GPIO_GET_PIN_INDEX(PIN_TDI), gpiom_soc_gpio0); + + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDO), GPIO_GET_PIN_INDEX(PIN_TDO)); + gpio_disable_pin_interrupt(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDO), GPIO_GET_PIN_INDEX(PIN_TDO)); + gpiom_set_pin_controller(HPM_GPIOM, GPIO_GET_PORT_INDEX(PIN_TDO), GPIO_GET_PIN_INDEX(PIN_TDO), gpiom_soc_gpio0); + + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_SRST), GPIO_GET_PIN_INDEX(PIN_SRST)); + gpio_disable_pin_interrupt(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_SRST), GPIO_GET_PIN_INDEX(PIN_SRST)); + gpiom_set_pin_controller(HPM_GPIOM, GPIO_GET_PORT_INDEX(PIN_SRST), GPIO_GET_PIN_INDEX(PIN_SRST), gpiom_soc_gpio0); + + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TRST), GPIO_GET_PIN_INDEX(PIN_JTAG_TRST)); + gpio_disable_pin_interrupt(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TRST), GPIO_GET_PIN_INDEX(PIN_JTAG_TRST)); + gpiom_set_pin_controller(HPM_GPIOM, GPIO_GET_PORT_INDEX(PIN_JTAG_TRST), GPIO_GET_PIN_INDEX(PIN_JTAG_TRST), gpiom_soc_gpio0); +} + + +// SWCLK/TCK I/O pin ------------------------------------- + +/** SWCLK/TCK I/O pin: Get Input. +\return Current status of the SWCLK/TCK DAP hardware I/O pin. +*/ +__STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN (void) { + uint32_t sta = gpio_read_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK)); + __asm volatile("fence io, io"); + return sta; +} + +/** SWCLK/TCK I/O pin: Set Output to High +Set the SWCLK/TCK DAP hardware I/O pin to high level.; +*/ +__STATIC_FORCEINLINE void PIN_SWCLK_TCK_SET (void) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK), true); + __asm volatile("fence io, io"); +} + +/** SWCLK/TCK I/O pin: Set Output to Low. +Set the SWCLK/TCK DAP hardware I/O pin to low level. +*/ +__STATIC_FORCEINLINE void PIN_SWCLK_TCK_CLR (void) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK), false); + __asm volatile("fence io, io"); +} + + +// SWDIO/TMS Pin I/O -------------------------------------- + +/** SWDIO/TMS I/O pin: Get Input. +\return Current status of the SWDIO/TMS DAP hardware I/O pin. +*/ +__STATIC_FORCEINLINE uint32_t PIN_SWDIO_TMS_IN (void) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 0); + uint32_t sta = gpio_read_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); + __asm volatile("fence io, io"); + return sta; +} + +/** SWDIO/TMS I/O pin: Set Output to High. +Set the SWDIO/TMS DAP hardware I/O pin to high level. +*/ +__STATIC_FORCEINLINE void PIN_SWDIO_TMS_SET (void) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS), true); + __asm volatile("fence io, io"); +} + +/** SWDIO/TMS I/O pin: Set Output to Low. +Set the SWDIO/TMS DAP hardware I/O pin to low level. +*/ +__STATIC_FORCEINLINE void PIN_SWDIO_TMS_CLR (void) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS), false); + __asm volatile("fence io, io"); +} + +/** SWDIO I/O pin: Get Input (used in SWD mode only). +\return Current status of the SWDIO DAP hardware I/O pin. +*/ +__STATIC_FORCEINLINE uint32_t PIN_SWDIO_IN (void) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 0); + uint32_t sta = gpio_read_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); + __asm volatile("fence io, io"); + return sta; +} + +/** SWDIO I/O pin: Set Output (used in SWD mode only). +\param bit Output value for the SWDIO DAP hardware I/O pin. +*/ +__STATIC_FORCEINLINE void PIN_SWDIO_OUT (uint32_t bit) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); + if(bit & 0x01) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS), true); + } + else { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS), false); + } + __asm volatile("fence io, io"); +} + +/** SWDIO I/O pin: Switch to Output mode (used in SWD mode only). +Configure the SWDIO DAP hardware I/O pin to output mode. This function is +called prior \ref PIN_SWDIO_OUT function calls. +*/ +__STATIC_FORCEINLINE void PIN_SWDIO_OUT_ENABLE (void) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); + HPM_IOC->PAD[PIN_TMS].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); /* as gpio*/ + HPM_IOC->PAD[PIN_TMS].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1); + gpiom_configure_pin_control_setting(PIN_TMS); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); +} + +/** SWDIO I/O pin: Switch to Input mode (used in SWD mode only). +Configure the SWDIO DAP hardware I/O pin to input mode. This function is +called prior \ref PIN_SWDIO_IN function calls. +*/ +__STATIC_FORCEINLINE void PIN_SWDIO_OUT_DISABLE (void) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 0); + HPM_IOC->PAD[PIN_TMS].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2); + HPM_IOC->PAD[PIN_TMS].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); + gpio_disable_pin_interrupt(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); + gpiom_set_pin_controller(HPM_GPIOM, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS), gpiom_soc_gpio0); +} + + +// TDI Pin I/O --------------------------------------------- + +/** TDI I/O pin: Get Input. +\return Current status of the TDI DAP hardware I/O pin. +*/ +__STATIC_FORCEINLINE uint32_t PIN_TDI_IN (void) { + uint32_t sta = gpio_read_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDI), GPIO_GET_PIN_INDEX(PIN_TDI)); + __asm volatile("fence io, io"); + return sta; +} + +/** TDI I/O pin: Set Output. +\param bit Output value for the TDI DAP hardware I/O pin. +*/ +__STATIC_FORCEINLINE void PIN_TDI_OUT (uint32_t bit) { + + if(bit & 0x01) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDI), GPIO_GET_PIN_INDEX(PIN_TDI), true); + } + else { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDI), GPIO_GET_PIN_INDEX(PIN_TDI), false); + } + __asm volatile("fence io, io"); +} + + +// TDO Pin I/O --------------------------------------------- + +/** TDO I/O pin: Get Input. +\return Current status of the TDO DAP hardware I/O pin. +*/ +__STATIC_FORCEINLINE uint32_t PIN_TDO_IN (void) { + uint32_t sta = gpio_read_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDO), GPIO_GET_PIN_INDEX(PIN_TDO)); + __asm volatile("fence io, io"); + return sta; +} + + +// nTRST Pin I/O ------------------------------------------- + +/** nTRST I/O pin: Get Input. +\return Current status of the nTRST DAP hardware I/O pin. +*/ +__STATIC_FORCEINLINE uint32_t PIN_nTRST_IN (void) { + uint32_t sta = gpio_read_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TRST), GPIO_GET_PIN_INDEX(PIN_JTAG_TRST)); + __asm volatile("fence io, io"); + return sta; +} + +/** nTRST I/O pin: Set Output. +\param bit JTAG TRST Test Reset pin status: + - 0: issue a JTAG TRST Test Reset. + - 1: release JTAG TRST Test Reset. +*/ +__STATIC_FORCEINLINE void PIN_nTRST_OUT (uint32_t bit) { + if(bit & 0x01) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TRST), GPIO_GET_PIN_INDEX(PIN_JTAG_TRST), true); + } + else { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TRST), GPIO_GET_PIN_INDEX(PIN_JTAG_TRST), false); + } + __asm volatile("fence io, io"); +} + +// nRESET Pin I/O------------------------------------------ + +/** nRESET I/O pin: Get Input. +\return Current status of the nRESET DAP hardware I/O pin. +*/ +__STATIC_FORCEINLINE uint32_t PIN_nRESET_IN (void) { + uint32_t sta = gpio_read_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_SRST), GPIO_GET_PIN_INDEX(PIN_SRST)); + __asm volatile("fence io, io"); + return sta; +} + +/** nRESET I/O pin: Set Output. +\param bit target device hardware reset pin status: + - 0: issue a device hardware reset. + - 1: release device hardware reset. +*/ +__STATIC_FORCEINLINE void PIN_nRESET_OUT (uint32_t bit) { + if(bit & 0x01) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_SRST), GPIO_GET_PIN_INDEX(PIN_SRST), true); + } + else { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_SRST), GPIO_GET_PIN_INDEX(PIN_SRST), false); + } + __asm volatile("fence io, io"); +} + +///@} + + +//************************************************************************************************** +/** +\defgroup DAP_Config_LEDs_gr CMSIS-DAP Hardware Status LEDs +\ingroup DAP_ConfigIO_gr +@{ + +CMSIS-DAP Hardware may provide LEDs that indicate the status of the CMSIS-DAP Debug Unit. + +It is recommended to provide the following LEDs for status indication: + - Connect LED: is active when the DAP hardware is connected to a debugger. + - Running LED: is active when the debugger has put the target device into running state. +*/ + +/** Debug Unit: Set status of Connected LED. +\param bit status of the Connect LED. + - 1: Connect LED ON: debugger is connected to CMSIS-DAP Debug Unit. + - 0: Connect LED OFF: debugger is not connected to CMSIS-DAP Debug Unit. +*/ +__STATIC_INLINE void LED_CONNECTED_OUT (uint32_t bit) { +#ifdef PIN_LED_CONNECTED + if(bit & 0x01) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_CONNECTED), GPIO_GET_PIN_INDEX(PIN_LED_RUNNING), true); + } + else { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_CONNECTED), GPIO_GET_PIN_INDEX(PIN_LED_RUNNING), false); + } +#endif + +#if CONFIG_WS2812 + extern volatile bool WS2812_Update_Flag; + if (bit & 0x01) { + WS2812_MixPixel(0, 128, 0, 0); + } else { + WS2812_ReverseMixPixel(0, 128, 0, 0); + } + WS2812_Update_Flag = true; +#endif + __asm volatile("fence io, io"); +} + +/** Debug Unit: Set status Target Running LED. +\param bit status of the Target Running LED. + - 1: Target Running LED ON: program execution in target started. + - 0: Target Running LED OFF: program execution in target stopped. +*/ +__STATIC_INLINE void LED_RUNNING_OUT (uint32_t bit) { +#ifdef PIN_LED_RUNNING + if(bit & 0x01) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_RUNNING), GPIO_GET_PIN_INDEX(PIN_LED_RUNNING), true); + } + else { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_RUNNING), GPIO_GET_PIN_INDEX(PIN_LED_RUNNING), false); + } +#endif + +#ifdef CONFIG_WS2812 + extern volatile bool WS2812_Update_Flag; + if (bit & 0x01) { + WS2812_MixPixel(0, 0, 0, 128); + } else { + WS2812_ReverseMixPixel(0, 0, 0, 128); + } + WS2812_Update_Flag = true; +#endif + __asm volatile("fence io, io"); +} + +///@} + + +//************************************************************************************************** +/** +\defgroup DAP_Config_Timestamp_gr CMSIS-DAP Timestamp +\ingroup DAP_ConfigIO_gr +@{ +Access function for Test Domain Timer. + +The value of the Test Domain Timer in the Debug Unit is returned by the function \ref TIMESTAMP_GET. By +default, the DWT timer is used. The frequency of this timer is configured with \ref TIMESTAMP_CLOCK. + +*/ + +/** Get timestamp of Test Domain Timer. +\return Current timestamp value. +*/ +__STATIC_INLINE uint32_t TIMESTAMP_GET (void) { + uint32_t current_us = (hpm_csr_get_core_cycle() * 1000000)/ clock_get_frequency(clock_cpu0); + return current_us; +} + +///@} + + +//************************************************************************************************** +/** +\defgroup DAP_Config_Initialization_gr CMSIS-DAP Initialization +\ingroup DAP_ConfigIO_gr +@{ + +CMSIS-DAP Hardware I/O and LED Pins are initialized with the function \ref DAP_SETUP. +*/ + +/** Setup of the Debug Unit I/O pins and LEDs (called when Debug Unit is initialized). +This function performs the initialization of the CMSIS-DAP Hardware I/O Pins and the +Status LEDs. In detail the operation of Hardware I/O and LED pins are enabled and set: + - I/O clock system enabled. + - all I/O pins: input buffer enabled, output pins are set to HighZ mode. + - for nTRST, nRESET a weak pull-up (if available) is enabled. + - LED output pins are enabled and LEDs are turned off. +*/ +__STATIC_INLINE void DAP_SETUP (void) { + ; +} + +/** Reset Target Device with custom specific I/O pin or command sequence. +This function allows the optional implementation of a device specific reset sequence. +It is called when the command \ref DAP_ResetTarget and is for example required +when a device needs a time-critical unlock sequence that enables the debug port. +\return 0 = no device specific reset sequence is implemented.\n + 1 = a device specific reset sequence is implemented. +*/ +__STATIC_INLINE uint8_t RESET_TARGET (void) { + return (0U); // change to '1' when a device reset sequence is implemented +} + +///@} + + +#endif /* __DAP_CONFIG_H__ */ diff --git a/projects/HSLink-Pro/src/JTAG_DP_SPI.c b/projects/HSLink-Pro/src/JTAG_DP_SPI.c new file mode 100644 index 0000000..2fcd584 --- /dev/null +++ b/projects/HSLink-Pro/src/JTAG_DP_SPI.c @@ -0,0 +1,728 @@ +/* + * Copyright (c) 2013-2017 ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ---------------------------------------------------------------------- + * + * $Date: 1. December 2017 + * $Revision: V2.0.0 + * + * Project: CMSIS-DAP Source + * Title: JTAG_DP.c CMSIS-DAP JTAG DP I/O + * + *---------------------------------------------------------------------------*/ + +#include "DAP_config.h" +#include "DAP.h" +#include "board.h" +#include "hpm_spi_drv.h" +#include "hpm_clock_drv.h" +#ifdef HPMSOC_HAS_HPMSDK_DMAV2 +#include "hpm_dmav2_drv.h" +#else +#include "hpm_dma_drv.h" +#endif +#include "hpm_dmamux_drv.h" + +// JTAG Macros + +#define USE_GPIO_1_BIT 0 + +#define PIN_JTAG_GPIO HPM_FGPIO + +#define JTAG_SPI_DMA HPM_HDMA +#define JTAG_SPI_DMAMUX HPM_DMAMUX +#define JTAG_SPI_RX_DMA_REQ HPM_DMA_SRC_SPI2_RX +#define JTAG_SPI_TX_DMA_REQ HPM_DMA_SRC_SPI2_TX +#define JTAG_SPI_RX_DMA_CH 0 +#define JTAG_SPI_TX_DMA_CH 1 +#define JTAG_SPI_RX_DMAMUX_CH DMA_SOC_CHN_TO_DMAMUX_CHN(JTAG_SPI_DMA, JTAG_SPI_RX_DMA_CH) +#define JTAG_SPI_TX_DMAMUX_CH DMA_SOC_CHN_TO_DMAMUX_CHN(JTAG_SPI_DMA, JTAG_SPI_TX_DMA_CH) +#define JTAG_SPI_SCLK_FREQ (20000000UL) + +#define PIN_SINGLE_SPI_JTAG_TMS IOC_PAD_PA29 +#define PIN_JTAG_TCK IOC_PAD_PB11 +#define PIN_JTAG_TDO IOC_PAD_PB12 +#define PIN_JTAG_TDI IOC_PAD_PB13 + +#define PIN_JTAG_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) + +static void jtag_spi_sequece (uint32_t info, const uint8_t *tdi, uint8_t *tdo); +static void jtag_spi_ir_fast(uint32_t ir, uint16_t ir_before, uint8_t ir_length, uint16_t ir_after); +static uint8_t jtag_spi_transfer_fast(uint32_t request, uint32_t *data, uint8_t index_count, uint8_t index, uint8_t idle_cycles); +static uint32_t jtag_spi_read_idcode(uint8_t index); +static void jtag_spi_write_abort(uint32_t data, uint8_t index_count, uint8_t index); +static void jtag_emulation_init(void); + +#if (DAP_JTAG != 0) + + +void PORT_JTAG_SETUP(void) +{ + clock_add_to_group(JTAG_SPI_BASE_CLOCK_NAME, 0); + clock_set_source_divider(JTAG_SPI_BASE_CLOCK_NAME, clk_src_pll1_clk0, 10U); /* 80MHz */ + HPM_IOC->PAD[IOC_PAD_PB10].FUNC_CTL = IOC_PB10_FUNC_CTL_GPIO_B_10; + HPM_IOC->PAD[PIN_JTAG_TCK].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(5) | IOC_PAD_FUNC_CTL_LOOP_BACK_SET(1); /* as spi sck*/ + HPM_IOC->PAD[PIN_JTAG_TDO].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(5); /* as spi mosi */ + HPM_IOC->PAD[PIN_JTAG_TDI].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(5); /** as spi miso */ + HPM_IOC->PAD[PIN_SINGLE_SPI_JTAG_TMS].FUNC_CTL = IOC_PA29_FUNC_CTL_GPIO_A_29; + HPM_IOC->PAD[IOC_PAD_PB10].PAD_CTL = IOC_PAD_PAD_CTL_SR_MASK | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_JTAG_TCK].PAD_CTL = IOC_PAD_PAD_CTL_SR_MASK | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_JTAG_TDO].PAD_CTL = IOC_PAD_PAD_CTL_SR_MASK | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_JTAG_TDI].PAD_CTL = IOC_PAD_PAD_CTL_SR_MASK | IOC_PAD_PAD_CTL_SPD_SET(3) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(0); + HPM_IOC->PAD[PIN_SINGLE_SPI_JTAG_TMS].PAD_CTL = IOC_PAD_PAD_CTL_SR_MASK | IOC_PAD_PAD_CTL_SPD_SET(3); + gpiom_configure_pin_control_setting(PIN_SINGLE_SPI_JTAG_TMS); + gpio_set_pin_output(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS)); + + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); // TMS引脚在JTAG下始终为输出 + +#if defined(USE_GPIO_1_BIT) && (USE_GPIO_1_BIT == 1) + gpiom_configure_pin_control_setting(PIN_JTAG_TCK); + gpiom_configure_pin_control_setting(PIN_JTAG_TDO); + gpiom_configure_pin_control_setting(PIN_JTAG_TDI); + gpiom_configure_pin_control_setting(IOC_PAD_PB10); + gpio_set_pin_output(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(IOC_PAD_PB10), GPIO_GET_PIN_INDEX(IOC_PAD_PB10)); + gpio_set_pin_output(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TCK), GPIO_GET_PIN_INDEX(PIN_JTAG_TCK)); + gpio_set_pin_output(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TDI), GPIO_GET_PIN_INDEX(PIN_JTAG_TDI)); + gpio_set_pin_input(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TDO), GPIO_GET_PIN_INDEX(PIN_JTAG_TDO)); +#endif + jtag_emulation_init(); +} + +// Generate JTAG Sequence +// info: sequence information +// tdi: pointer to TDI generated data +// tdo: pointer to TDO captured data +// return: none +void JTAG_Sequence (uint32_t info, const uint8_t *tdi, uint8_t *tdo) { + jtag_spi_sequece(info, tdi, tdo); +} + +static void JTAG_IR_Fast(uint32_t ir) +{ + uint16_t ir_before, ir_after; + uint8_t ir_length; + ir_before = DAP_Data.jtag_dev.ir_before[DAP_Data.jtag_dev.index]; + ir_length = DAP_Data.jtag_dev.ir_length[DAP_Data.jtag_dev.index]; + ir_after = DAP_Data.jtag_dev.ir_after[DAP_Data.jtag_dev.index]; + jtag_spi_ir_fast(ir, ir_before, ir_length, ir_after); +} + +static void JTAG_IR_Slow(uint32_t ir) +{ + JTAG_IR_Fast(ir); +} + +static uint8_t JTAG_TransferFast(uint32_t request, uint32_t *data) +{ + uint8_t index_count, index, idle_cycles; + index_count = DAP_Data.jtag_dev.count; + index = DAP_Data.jtag_dev.index; + idle_cycles = DAP_Data.transfer.idle_cycles; + return jtag_spi_transfer_fast(request, data, index_count, index, idle_cycles); +} + +static uint8_t JTAG_TransferSlow(uint32_t request, uint32_t *data) +{ + return JTAG_TransferFast(request, data); +} + +// JTAG Read IDCODE register +// return: value read +uint32_t JTAG_ReadIDCode (void) { + uint8_t index = DAP_Data.jtag_dev.index; + return jtag_spi_read_idcode(index); +} + + +// JTAG Write ABORT register +// data: value to write +// return: none +void JTAG_WriteAbort (uint32_t data) { + uint8_t index_count, index; + index_count = DAP_Data.jtag_dev.count; + index = DAP_Data.jtag_dev.index; + jtag_spi_write_abort(data, index_count, index); +} + + +// JTAG Set IR +// ir: IR value +// return: none +void JTAG_IR (uint32_t ir) { + if (DAP_Data.fast_clock) { + JTAG_IR_Fast(ir); + } else { + JTAG_IR_Slow(ir); + } +} + + +// JTAG Transfer I/O +// request: A[3:2] RnW APnDP +// data: DATA[31:0] +// return: ACK[2:0] +uint8_t JTAG_Transfer(uint32_t request, uint32_t *data) { + if (DAP_Data.fast_clock) { + return JTAG_TransferFast(request, data); + } else { + return JTAG_TransferSlow(request, data); + } +} + + +static void jtag_reset(void) +{ + JTAG_SPI_BASE->CTRL |= SPI_CTRL_RXFIFORST_MASK | SPI_CTRL_TXFIFORST_MASK; + while (JTAG_SPI_BASE->STATUS & (SPI_CTRL_RXFIFORST_MASK | SPI_CTRL_TXFIFORST_MASK)) { + }; +} + +static void jtag_less_than_32bit_size_for_tck(uint16_t bit_size, uint32_t dummy) +{ + if (bit_size == 0) + return; + jtag_reset(); + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_only); + spi_set_data_bits(JTAG_SPI_BASE, bit_size); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = dummy; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; +} + +static void jtag_more_than_32bit_size_for_tck(uint16_t bit_size, uint32_t dummy) +{ + uint32_t n_len_in_byte = 0; + uint32_t n_len_remain_bit = 0; + uint32_t i; + + if (bit_size == 0) { + return; + } + n_len_in_byte = bit_size / 32; + n_len_remain_bit = bit_size % 32; + if (n_len_in_byte) { + jtag_reset(); + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_only); + spi_set_data_bits(JTAG_SPI_BASE, 32); + spi_set_read_data_count(JTAG_SPI_BASE, n_len_in_byte); + spi_set_write_data_count(JTAG_SPI_BASE, n_len_in_byte); + for (i = 0; i < n_len_in_byte; i++) { + JTAG_SPI_BASE->DATA = dummy; + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_TXFULL_MASK) == SPI_STATUS_TXFULL_MASK) { + }; + } + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + if (n_len_remain_bit) { + jtag_less_than_32bit_size_for_tck(n_len_remain_bit, dummy); + } +} + +// Generate JTAG Sequence +// info: sequence information +// tdi: pointer to TDI generated data +// tdo: pointer to TDO captured data +// return: none +static void jtag_spi_sequece (uint32_t info, const uint8_t *tdi, uint8_t *tdo) +{ + uint32_t n; + uint32_t n_len_in_byte = 0; + uint32_t n_len_remain_bit = 0; + uint32_t rx_index = 0, tx_index = 0; + bool is_tdo = false; + uint8_t txfifo_size = spi_get_tx_fifo_size(JTAG_SPI_BASE); + uint8_t txfifo_valid_size = 0, rxfifo_valid_size = 0, j = 0; + n = info & JTAG_SEQUENCE_TCK; + if (info & JTAG_SEQUENCE_TMS) { + //printf("1s: %d %d\n", n_len_in_byte, n_len_remain_bit); + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + } else { + //printf("0s: %d %d\n", n_len_in_byte, n_len_remain_bit); + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), false); + } + if (n == 1) { +#if defined(USE_GPIO_1_BIT) && (USE_GPIO_1_BIT == 1) + + HPM_IOC->PAD[PIN_JTAG_TCK].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + HPM_IOC->PAD[PIN_JTAG_TDI].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + PIN_JTAG_DELAY(); + if((*tdi) & 0x01) { + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TDI), GPIO_GET_PIN_INDEX(PIN_JTAG_TDI), true); + } + else { + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TDI), GPIO_GET_PIN_INDEX(PIN_JTAG_TDI), false); + } + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TCK), GPIO_GET_PIN_INDEX(PIN_JTAG_TCK), true); + // PIN_JTAG_DELAY(); + if (info & JTAG_SEQUENCE_TDO) { + (*tdo) = gpio_read_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TDO), GPIO_GET_PIN_INDEX(PIN_JTAG_TDO)); + } + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TCK), GPIO_GET_PIN_INDEX(PIN_JTAG_TCK), false); + // PIN_JTAG_DELAY(); + HPM_IOC->PAD[PIN_JTAG_TCK].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(5) | IOC_PAD_FUNC_CTL_LOOP_BACK_SET(1); + HPM_IOC->PAD[PIN_JTAG_TDO].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(5); + HPM_IOC->PAD[PIN_JTAG_TDI].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(5); + return; +#else + switch ((*tdi) & 0x01) + { + case 1: + JTAG_SPI_BASE->DIRECTIO = 0x1040400; + JTAG_SPI_BASE->DIRECTIO = 0x1060600; /* diretion = 1, slck_oe = 1, mosi_oe = 1, sclk_o = 1, mosi_o = 1 */ + if (is_tdo == true) { + *(uint8_t *)(tdo) = (uint8_t)(JTAG_SPI_BASE->DIRECTIO >> 3); + } + JTAG_SPI_BASE->DIRECTIO = 0x1060400; /* diretion = 1, slck_oe = 1, mosi_oe = 1, sclk_o = 0, mosi_o = 1*/ + break; + case 0: + JTAG_SPI_BASE->DIRECTIO = 0x1040000; + JTAG_SPI_BASE->DIRECTIO = 0x1060200; /* diretion = 1, slck_oe = 1, mosi_oe = 1, sclk_o = 1, mosi_o = 0 */ + if (is_tdo == true) { + *(uint8_t *)(tdo) = (uint8_t)(JTAG_SPI_BASE->DIRECTIO >> 3); + } + JTAG_SPI_BASE->DIRECTIO = 0x1060000; /* diretion = 1, slck_oe = 1, mosi_oe = 1, sclk_o = 0, mosi_o = 0 */ + default: + break; + } + JTAG_SPI_BASE->DIRECTIO = 0; /* diretion = 0 */ + return; +#endif + } + + jtag_reset(); + if (info & JTAG_SEQUENCE_TDO) { + is_tdo = true; + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_read_together); + } else { + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_only); + } + if (n == 0U) { + n = 64U; + } + n_len_in_byte = n / 8; + n_len_remain_bit = n % 8; + + if (n_len_in_byte) { + spi_set_data_bits(JTAG_SPI_BASE, 8); + spi_set_read_data_count(JTAG_SPI_BASE, n_len_in_byte); + spi_set_write_data_count(JTAG_SPI_BASE, n_len_in_byte); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + if (is_tdo == false) { + rx_index = n_len_in_byte; + } + while ((rx_index < n_len_in_byte) || (tx_index < n_len_in_byte)) { + if (tx_index < n_len_in_byte) { + txfifo_valid_size = spi_get_tx_fifo_valid_data_size(JTAG_SPI_BASE); + if ((txfifo_size - txfifo_valid_size) > 0) { + for (j = 0; j < (txfifo_size - txfifo_valid_size); j++) { + if (tx_index >= n_len_in_byte) { + break; + } + JTAG_SPI_BASE->DATA = *tdi; + tdi++; + tx_index++; + } + } + } + if (rx_index < n_len_in_byte) { + rxfifo_valid_size = spi_get_rx_fifo_valid_data_size(JTAG_SPI_BASE); + if (rxfifo_valid_size > 0) { + for (j = 0; j < rxfifo_valid_size; j++) { + if (rx_index >= n_len_in_byte) { + break; + } + *tdo = JTAG_SPI_BASE->DATA; + tdo++; + rx_index++; + } + } + } + } + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + if (n_len_remain_bit) { + spi_set_data_bits(JTAG_SPI_BASE, n_len_remain_bit); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = *(uint8_t *)(tdi); + if (is_tdo == true) { + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + *(uint8_t *)(tdo) = JTAG_SPI_BASE->DATA; + } + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } +} + +static void jtag_ir(uint32_t ir, uint8_t ir_bit_size) +{ + uint8_t tmp_bits = 0; + tmp_bits = (ir_bit_size > 32) ? 32 : ir_bit_size; + jtag_less_than_32bit_size_for_tck(tmp_bits, ir); + ir_bit_size -= tmp_bits; + if (ir_bit_size) { + jtag_more_than_32bit_size_for_tck(ir_bit_size, 0x0); + } +} + +static void jtag_spi_ir_fast(uint32_t ir, uint16_t ir_before, uint8_t ir_length, uint16_t ir_after) +{ + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_only); + /* Select-DR-Scan and Select-IR-Scan */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(2, 0); + /* Capture-IR and Shift-IR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), false); + jtag_less_than_32bit_size_for_tck(2, 0); + if (ir_before) { + if (ir_before > 32) { + jtag_more_than_32bit_size_for_tck(ir_before, 0xFFFFFFFF); /* Bypass before data */ + } else { + jtag_less_than_32bit_size_for_tck(ir_before, 0xFFFFFFFF); + } + } + if (ir_length) { + jtag_ir(ir, ir_length - 1); /* Set IR bits (except last) */ + ir >>= (ir_length - 2); + } + if (ir_after) { + /* Set last IR bit */ + jtag_less_than_32bit_size_for_tck(1, ir); + ir_after -= 1; + if (ir_after > 32) { + jtag_more_than_32bit_size_for_tck(ir_after, 0xFFFFFFFF); /* Bypass after data */ + } else { + jtag_less_than_32bit_size_for_tck(ir_after, 0xFFFFFFFF); + } + /* Bypass & Exit1-IR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0xFFFFFFFF); + } else { + /* Set last IR bit & Exit1-IR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, ir); + } + /* Update-IR */ + jtag_less_than_32bit_size_for_tck(1, 0); + /* Idle */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), false); + jtag_less_than_32bit_size_for_tck(1, 0xFFFFFFFF); +} + +static uint8_t jtag_spi_transfer_fast(uint32_t request, uint32_t *data, uint8_t index_count, uint8_t index, uint8_t idle_cycles) +{ + uint32_t ack = 0; + uint32_t bit = 0; + uint32_t n = 0; + uint32_t val; + /* Select-DR-Scan */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0); + /* Capture-DR & Shift-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), false); + jtag_less_than_32bit_size_for_tck(2, 0); + /* Bypass before data */ + if (index) { + if (index > 32) { + jtag_more_than_32bit_size_for_tck(index, 0xFFFFFFFF); /* Bypass before data */ + } else { + jtag_less_than_32bit_size_for_tck(index, 0xFFFFFFFF); + } + } + jtag_reset(); + /* Set RnW A2 A3, Get ACK.0 ACK.1 ACK.2*/ + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_read_together); + spi_set_data_bits(JTAG_SPI_BASE, 3); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = request; + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + bit = JTAG_SPI_BASE->DATA; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + ack = ((bit & 0x01) << 1) | ((bit & 0x02) >> 0) | (bit & 0x04); + if (ack != DAP_TRANSFER_OK) { + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0xFFFFFFFF); + goto exit; + } + jtag_reset(); + if (request & DAP_TRANSFER_RnW) { + /* Read Transfer */ + val = 0; + /* Get D0..D30 */ + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_read_only); + spi_set_data_bits(JTAG_SPI_BASE, 32); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + bit = JTAG_SPI_BASE->DATA; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + val = bit; + n = index_count - index - 1U; + bit = 0; + jtag_reset(); + spi_set_data_bits(JTAG_SPI_BASE, 1); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + if (n) { + /* Get D31 */ + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + bit = JTAG_SPI_BASE->DATA; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + /* Bypass after data */ + jtag_less_than_32bit_size_for_tck(n - 1, 0xFFFFFFFF); + /* Bypass & Exit1-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0xFFFFFFFF); + } else { + /* Get D31 & Exit1-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + bit = JTAG_SPI_BASE->DATA; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + val |= bit << 31; + if (data) { + *data = val; + } + } else { + /* Write Transfer */ + val = (*data); + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_only); + /* Set D0..D30 */ + jtag_less_than_32bit_size_for_tck(31, val); + n = index_count - index - 1U; + val >>= 31; + spi_set_data_bits(JTAG_SPI_BASE, 1); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + if (n) { + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = val; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + /* Bypass after data */ + jtag_less_than_32bit_size_for_tck(n - 1, 0); + /* Bypass & Exit1-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0); + } else { + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = val; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + } +exit: + /* Update-DR */ + jtag_less_than_32bit_size_for_tck(1, 0); + board_write_spi_cs(BOARD_SPI_CS_PIN, false); + /* Idle */ + jtag_less_than_32bit_size_for_tck(1, 0xFFFFFFFF); + + /* Capture Timestamp */ + if (request & DAP_TRANSFER_TIMESTAMP) { + // DAP_Data.timestamp = TIMESTAMP_GET(); + } + + /* Idle cycles */ + jtag_less_than_32bit_size_for_tck(idle_cycles, 0xFFFFFFFF); + return ((uint8_t)ack); +} + +// JTAG Read IDCODE register +// return: value read +static uint32_t jtag_spi_read_idcode (uint8_t index) +{ + uint32_t bit; + uint32_t val; + /* Select-DR-Scan */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0); + + /* Capture-DR & Shift-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), false); + jtag_less_than_32bit_size_for_tck(2, 0); + + /* Bypass before data */ + jtag_more_than_32bit_size_for_tck(index, 0xFFFFFFFF); + + val = 0U; + /* Get D0..D30 */ + jtag_reset(); + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_read_only); + spi_set_data_bits(JTAG_SPI_BASE, 32); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + bit = JTAG_SPI_BASE->DATA; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + val = bit; + bit = 0; + jtag_reset(); + spi_set_data_bits(JTAG_SPI_BASE, 1); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + /* Get D31 & Exit1-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + bit = JTAG_SPI_BASE->DATA; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + val |= bit << 31; + /* Update-DR */ + jtag_less_than_32bit_size_for_tck(1, 0); + board_write_spi_cs(BOARD_SPI_CS_PIN, false); + /* Idle */ + jtag_less_than_32bit_size_for_tck(1, 0xFFFFFFFF); + return (val); +} + +// JTAG Write ABORT register +// data: value to write +// return: none +static void jtag_spi_write_abort (uint32_t data, uint8_t index_count, uint8_t index) +{ + uint32_t n = 0; + /* Select-DR-Scan */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0); + + /* Capture-DR & Shift-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), false); + jtag_less_than_32bit_size_for_tck(2, 0); + + /* Bypass before data */ + jtag_more_than_32bit_size_for_tck(index, 0xFFFFFFFF); + + /* Set RnW=0 (Write) & Set A2 = 0 & Set A3 = 0 */ + jtag_reset(); + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_only); + spi_set_data_bits(JTAG_SPI_BASE, 3); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = n; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + + /* Set D0..D30 */ + jtag_less_than_32bit_size_for_tck(31, data); + n = index_count - index - 1U; + /* Set D31 */ + data >>= 31; + jtag_reset(); + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_only); + spi_set_data_bits(JTAG_SPI_BASE, 1); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + if (n) { + /* Bypass after data */ + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = data; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + /* Bypass after data */ + jtag_less_than_32bit_size_for_tck(n - 1, 0); + /* Bypass & Exit1-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0); + } else { + /* Set D31 & Exit1-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = data; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + /* Update-DR */ + jtag_less_than_32bit_size_for_tck(1, 0); + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), false); + /* Idle */ + jtag_less_than_32bit_size_for_tck(1, 0xFFFFFFFF); +} + +static void jtag_emulation_init(void) +{ + spi_timing_config_t timing_config = {0}; + spi_format_config_t format_config = {0}; + spi_control_config_t control_config = {0}; + uint32_t spi_clcok; + uint32_t pll_clk = 0, div = 0; + /* set SPI sclk frequency for master */ + spi_clcok = board_init_spi_clock(JTAG_SPI_BASE); + spi_master_get_default_timing_config(&timing_config); + timing_config.master_config.cs2sclk = spi_cs2sclk_half_sclk_1; + timing_config.master_config.csht = spi_csht_half_sclk_1; + timing_config.master_config.clk_src_freq_in_hz = spi_clcok; + timing_config.master_config.sclk_freq_in_hz = JTAG_SPI_SCLK_FREQ; + if (status_success != spi_master_timing_init(JTAG_SPI_BASE, &timing_config)) { + spi_master_set_sclk_div(JTAG_SPI_BASE, 0xFF); + pll_clk = get_frequency_for_source(clock_source_pll1_clk0); + div = pll_clk / JTAG_SPI_SCLK_FREQ; + clock_set_source_divider(JTAG_SPI_BASE_CLOCK_NAME, clk_src_pll1_clk0, div); + } + + /* set SPI format config for master */ + spi_master_get_default_format_config(&format_config); + format_config.master_config.addr_len_in_bytes = 1U; + format_config.common_config.data_len_in_bits = 1; + format_config.common_config.data_merge = false; + format_config.common_config.mosi_bidir = false; + format_config.common_config.lsb = true; + format_config.common_config.mode = spi_master_mode; + format_config.common_config.cpol = spi_sclk_low_idle; + format_config.common_config.cpha = spi_sclk_sampling_odd_clk_edges; + spi_format_init(JTAG_SPI_BASE, &format_config); + + /* set SPI control config for master */ + spi_master_get_default_control_config(&control_config); + control_config.master_config.cmd_enable = false; + control_config.master_config.addr_enable = false; + control_config.master_config.addr_phase_fmt = spi_address_phase_format_single_io_mode; + control_config.common_config.trans_mode = spi_trans_write_read_together; + control_config.common_config.rx_dma_enable = false; + control_config.common_config.tx_dma_enable = false; + spi_control_init(JTAG_SPI_BASE, &control_config, 1, 1); +} + +#endif /* (DAP_JTAG != 0) */ diff --git a/projects/HSLink-Pro/src/SW_DP_SPI.c b/projects/HSLink-Pro/src/SW_DP_SPI.c new file mode 100644 index 0000000..4bd7aed --- /dev/null +++ b/projects/HSLink-Pro/src/SW_DP_SPI.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2024 RCSN + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + + +#include "board.h" +#include "hpm_spi_drv.h" +#include "swd_common.h" +#ifdef HPMSOC_HAS_HPMSDK_DMAV2 +#include "hpm_dmav2_drv.h" +#else +#include "hpm_dma_drv.h" +#endif +#include "hpm_dmamux_drv.h" +#include "DAP_config.h" +#include "DAP.h" + +#define SWD_SPI_SCLK_FREQ (20000000UL) + +#define SWD_SPI_DMA BOARD_APP_HDMA +#define SWD_SPI_DMAMUX BOARD_APP_DMAMUX +#define SWD_SPI_RX_DMA_REQ BOARD_APP_SPI_RX_DMA +#define SWD_SPI_TX_DMA_REQ BOARD_APP_SPI_TX_DMA +#define SWD_SPI_RX_DMA_CH 0 +#define SWD_SPI_TX_DMA_CH 1 +#define SWD_SPI_RX_DMAMUX_CH DMA_SOC_CHN_TO_DMAMUX_CHN(SWD_SPI_DMA, SWD_SPI_RX_DMA_CH) +#define SWD_SPI_TX_DMAMUX_CH DMA_SOC_CHN_TO_DMAMUX_CHN(SWD_SPI_DMA, SWD_SPI_TX_DMA_CH) + +extern host_ops_t host_ops_table[]; +ATTR_PLACE_AT(".ahb_sram") uint8_t target_ack[4]; + +static void swd_emulation_init(void); + +void PORT_SWD_SETUP(void) +{ + board_init_spi_pins(SWD_SPI_BASE); + HPM_IOC->PAD[PIN_TCK].PAD_CTL = IOC_PAD_PAD_CTL_SR_MASK | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_TMS].PAD_CTL = IOC_PAD_PAD_CTL_SR_MASK | IOC_PAD_PAD_CTL_SPD_SET(3) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(0); + + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 0); // 默认SWDIO为输入 + + swd_emulation_init(); +} + +// Generate SWJ Sequence +// count: sequence bit count +// data: pointer to sequence bit data +// return: none +#if ((DAP_SWD != 0) || (DAP_JTAG != 0)) +void SWJ_Sequence (uint32_t count, const uint8_t *data) +{ + uint32_t n; + uint32_t integer_val = (count / 8); + uint32_t remaind_val = (count % 8); +// printf("SWJ_Sequence %d\n", count); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); + spi_set_transfer_mode(SWD_SPI_BASE, spi_trans_write_only); + spi_set_data_bits(SWD_SPI_BASE, 8); + SWD_SPI_BASE->CTRL |= SPI_CTRL_RXFIFORST_MASK | SPI_CTRL_TXFIFORST_MASK; + while (SWD_SPI_BASE->STATUS & (SPI_CTRL_RXFIFORST_MASK | SPI_CTRL_TXFIFORST_MASK)) { + }; + spi_set_write_data_count(SWD_SPI_BASE, integer_val); + SWD_SPI_BASE->CMD = 0xFF; + for (n = 0; n < integer_val; n++) { + SWD_SPI_BASE->DATA = *(data + n); + } + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + if (remaind_val > 0) { + spi_set_write_data_count(SWD_SPI_BASE, 1); + spi_set_data_bits(SWD_SPI_BASE, remaind_val); + SWD_SPI_BASE->DATA = *(data + integer_val); + SWD_SPI_BASE->CMD = 0xFF; + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); +} +#endif + +// Generate SWD Sequence +// info: sequence information +// swdo: pointer to SWDIO generated data +// swdi: pointer to SWDIO captured data +// return: none +#if (DAP_SWD != 0) +void SWD_Sequence (uint32_t info, const uint8_t *swdo, uint8_t *swdi) +{ + uint32_t count, integer_val, remaind_val, n = 0; + + count = info & SWD_SEQUENCE_CLK; + if (count == 0U) { + count = 64U; + } +// printf("SWD_Sequence\n"); + SWD_SPI_BASE->CTRL |= SPI_CTRL_RXFIFORST_MASK | SPI_CTRL_TXFIFORST_MASK; + while (SWD_SPI_BASE->STATUS & (SPI_CTRL_RXFIFORST_MASK | SPI_CTRL_TXFIFORST_MASK)) { + }; + integer_val = (count / 8); + remaind_val = (count % 8); + spi_set_data_bits(SWD_SPI_BASE, 8); + if (info & SWD_SEQUENCE_DIN) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 0); + spi_set_read_data_count(SWD_SPI_BASE, integer_val); + spi_set_transfer_mode(SWD_SPI_BASE, spi_trans_read_only); + SWD_SPI_BASE->CMD = 0xFF; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) != SPI_STATUS_RXEMPTY_MASK) { + *(swdi + n) = SWD_SPI_BASE->DATA; + n++; + } + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + if (remaind_val > 0) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 0); + spi_set_read_data_count(SWD_SPI_BASE, 1); + spi_set_data_bits(SWD_SPI_BASE, remaind_val); + SWD_SPI_BASE->CMD = 0xFF; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) != SPI_STATUS_RXEMPTY_MASK) { + *(swdi + integer_val) = SWD_SPI_BASE->DATA ; + } + } + } else { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); + spi_set_write_data_count(SWD_SPI_BASE, integer_val); + spi_set_transfer_mode(SWD_SPI_BASE, spi_trans_write_only); + SWD_SPI_BASE->CMD = 0xFF; + for (n = 0; n < integer_val; n++) { + SWD_SPI_BASE->DATA = *(swdo + n); + } + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + if (remaind_val > 0) { + spi_set_data_bits(SWD_SPI_BASE, remaind_val); + SWD_SPI_BASE->DATA = *(swdo + integer_val); + SWD_SPI_BASE->CMD = 0xFF; + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + } + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 0); +} + +// SWD Transfer I/O +// request: A[3:2] RnW APnDP +// data: DATA[31:0] +// return: ACK[2:0] +uint8_t SWD_Transfer(uint32_t request, uint32_t *data) +{ + uint8_t ack = 0; + uint32_t parity = 0; + uint8_t calc_parity = 0; + uint8_t i = 0; + uint32_t host_data = 0x81; /* start = 1, stop = 0, park = 1 0b10000001*/ + uint32_t dummy = 0; + uint8_t ack_width = 0; + SWD_SPI_BASE->CTRL |= SPI_CTRL_RXFIFORST_MASK | SPI_CTRL_TXFIFORST_MASK; + while (SWD_SPI_BASE->STATUS & (SPI_CTRL_RXFIFORST_MASK | SPI_CTRL_TXFIFORST_MASK)) { + }; + spi_set_write_data_count(SWD_SPI_BASE, 1); + spi_set_read_data_count(SWD_SPI_BASE, 1); + switch (request & 0x0F) + { + case 0: + case 3: + case 5: + case 6: + case 9: + case 10: + case 12: + case 15: + parity = 0; + break; + default: + parity = 1; + break; + } + host_data |= ((request & 0x0F) << 1) | (parity << 5); + parity = 0; + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); + spi_set_transfer_mode(SWD_SPI_BASE, spi_trans_write_only); + if (request & DAP_TRANSFER_RnW) { + spi_set_data_bits(SWD_SPI_BASE, 8); + ack_width = 4; + } else { + for (i = 0; i < 32; i++) { + parity += (((*data) >> i) & 0x01); + } + spi_set_data_bits(SWD_SPI_BASE, 8); + ack_width = 5; + } + SWD_SPI_BASE->CMD = 0xFF; + SWD_SPI_BASE->DATA = host_data; + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 0); + spi_set_transfer_mode(SWD_SPI_BASE, spi_trans_read_only); + spi_set_data_bits(SWD_SPI_BASE, ack_width); + SWD_SPI_BASE->CMD = 0xFF; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + ack = SWD_SPI_BASE->DATA; + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + ack >>= 1; + if (ack == DAP_TRANSFER_OK) { /* OK response */ + /* Data transfer */ + if (request & DAP_TRANSFER_RnW) { + /* Read data */ + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 0); + SWD_SPI_BASE->TRANSCTRL = 0x2000000; /* only read mode*/ + SWD_SPI_BASE->TRANSFMT = 0x1F18; /* datalen = 32bit, mosibidir = 1, lsb=1 */ + SWD_SPI_BASE->CMD = 0xFF; + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + dummy = SWD_SPI_BASE->DATA; + spi_set_data_bits(SWD_SPI_BASE, 1); + SWD_SPI_BASE->CMD = 0xFF; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + parity = (SWD_SPI_BASE->DATA) & 0x01; + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + /* Turnaround */ + if (DAP_Data.swd_conf.turnaround > 0) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); + SWD_SPI_BASE->TRANSCTRL = 0x01000000; /* only write mode*/ + SWD_SPI_BASE->TRANSFMT = 0x0018; /* datalen = 1bit, mosibidir = 1, lsb=1 */ + spi_set_write_data_count(SWD_SPI_BASE, DAP_Data.swd_conf.turnaround); + SWD_SPI_BASE->CMD = 0xFF; + SWD_SPI_BASE->DATA = 0; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_TXFULL_MASK) == SPI_STATUS_TXFULL_MASK) { + }; + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + for (i = 0; i < 32U; i++) { + calc_parity += ((dummy >> i) & 0x01); + } + if (parity != (calc_parity & 0x01)) { + ack = DAP_TRANSFER_ERROR; + } + if (data != NULL) { + (*data) = dummy; + } + } else { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); + SWD_SPI_BASE->TRANSCTRL = 0x1000000; /* only write mode*/ + SWD_SPI_BASE->TRANSFMT = 0x1F18; /* datalen = 32bit, mosibidir = 1, lsb=1 */ + SWD_SPI_BASE->CMD = 0xFF; + SWD_SPI_BASE->DATA = (*data); + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + spi_set_data_bits(SWD_SPI_BASE, 1); + SWD_SPI_BASE->CMD = 0xFF; + SWD_SPI_BASE->DATA = parity; + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + /* Capture Timestamp */ + if (request & DAP_TRANSFER_TIMESTAMP) { + DAP_Data.timestamp = TIMESTAMP_GET(); + } + if (DAP_Data.transfer.idle_cycles > 0) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); + SWD_SPI_BASE->TRANSCTRL = 0x01000000; /* only write mode*/ + SWD_SPI_BASE->TRANSFMT = 0x0018; /* datalen = 1bit, mosibidir = 1, lsb=1 */ + spi_set_write_data_count(SWD_SPI_BASE, DAP_Data.transfer.idle_cycles); + SWD_SPI_BASE->CMD = 0xFF; + SWD_SPI_BASE->DATA = 0; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_TXFULL_MASK) == SPI_STATUS_TXFULL_MASK) { + }; + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + } + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 0); + return ack; + } + + /* WAIT or FAULT response */ + if ((ack == DAP_TRANSFER_WAIT) || (ack == DAP_TRANSFER_FAULT)) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 0); + SWD_SPI_BASE->TRANSCTRL = 0x02000000; /* only read mode*/ + SWD_SPI_BASE->TRANSFMT = 0x0018; /* datalen = 1bit, mosibidir = 1, lsb=1 */ + /* Dummy Read RDATA[0:31] + Parity */ + if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) != 0U)) { + spi_set_write_data_count(SWD_SPI_BASE, 33); + SWD_SPI_BASE->CMD = 0xFF; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + parity = (SWD_SPI_BASE->DATA) & 0x01; + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + /* Turnaround */ + if (DAP_Data.swd_conf.turnaround > 0) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); + SWD_SPI_BASE->TRANSCTRL = 0x01000000; /* only write mode*/ + SWD_SPI_BASE->TRANSFMT = 0x0018; /* datalen = 1bit, mosibidir = 1, lsb=1 */ + spi_set_write_data_count(SWD_SPI_BASE, DAP_Data.swd_conf.turnaround); + SWD_SPI_BASE->CMD = 0xFF; + SWD_SPI_BASE->DATA = 0; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_TXFULL_MASK) == SPI_STATUS_TXFULL_MASK) { + }; + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + /* Dummy Write WDATA[0:31] + Parity */ + if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) == 0U)) { + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); + SWD_SPI_BASE->TRANSCTRL = 0x01000000; /* only write mode*/ + SWD_SPI_BASE->TRANSFMT = 0x0018; /* datalen = 1bit, mosibidir = 1, lsb=1 */ + spi_set_write_data_count(SWD_SPI_BASE, 33); + SWD_SPI_BASE->CMD = 0xFF; + for (i = 0; i < 33; i++) { + SWD_SPI_BASE->DATA = 0; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_TXFULL_MASK) == SPI_STATUS_TXFULL_MASK) { + }; + } + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 0); + return ack; + } + /* Protocol error */ + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); + spi_set_transfer_mode(SWD_SPI_BASE, spi_trans_write_only); + spi_set_data_bits(SWD_SPI_BASE, 1); + spi_set_write_data_count(SWD_SPI_BASE, DAP_Data.swd_conf.turnaround + 32U + 1U); + SWD_SPI_BASE->CMD = 0xFF; + for (i = 0; i < DAP_Data.swd_conf.turnaround + 32U + 1U; i++) { + SWD_SPI_BASE->DATA = 0; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_TXFULL_MASK) == SPI_STATUS_TXFULL_MASK) { + }; + } + spi_set_data_bits(SWD_SPI_BASE, 1); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 0); + return ack; +} +#endif + +static void swd_emulation_init(void) +{ + spi_timing_config_t timing_config = {0}; + spi_format_config_t format_config = {0}; + spi_control_config_t control_config = {0}; + uint32_t spi_clcok; + uint32_t pll_clk = 0, div = 0; + /* set SPI sclk frequency for master */ + spi_clcok = board_init_spi_clock(SWD_SPI_BASE); + spi_master_get_default_timing_config(&timing_config); + timing_config.master_config.cs2sclk = spi_cs2sclk_half_sclk_1; + timing_config.master_config.csht = spi_csht_half_sclk_1; + timing_config.master_config.clk_src_freq_in_hz = spi_clcok; + timing_config.master_config.sclk_freq_in_hz = SWD_SPI_SCLK_FREQ; + if (status_success != spi_master_timing_init(SWD_SPI_BASE, &timing_config)) { + spi_master_set_sclk_div(SWD_SPI_BASE, 0xFF); + pll_clk = get_frequency_for_source(clock_source_pll1_clk0); + div = pll_clk / SWD_SPI_SCLK_FREQ; + clock_set_source_divider(SWD_SPI_BASE_CLOCK_NAME, clk_src_pll1_clk0, div); + } + + /* set SPI format config for master */ + spi_master_get_default_format_config(&format_config); + format_config.master_config.addr_len_in_bytes = 1U; + format_config.common_config.data_len_in_bits = 1; + format_config.common_config.data_merge = false; + format_config.common_config.mosi_bidir = true; + format_config.common_config.lsb = true; + format_config.common_config.mode = spi_master_mode; + format_config.common_config.cpol = spi_sclk_low_idle; + format_config.common_config.cpha = spi_sclk_sampling_odd_clk_edges; + spi_format_init(SWD_SPI_BASE, &format_config); + + /* set SPI control config for master */ + spi_master_get_default_control_config(&control_config); + control_config.master_config.cmd_enable = false; + control_config.master_config.addr_enable = false; + control_config.master_config.addr_phase_fmt = spi_address_phase_format_single_io_mode; + control_config.common_config.trans_mode = spi_trans_write_dummy_read; + control_config.common_config.data_phase_fmt = spi_single_io_mode; + control_config.common_config.dummy_cnt = spi_dummy_count_1; + spi_control_init(SWD_SPI_BASE, &control_config, 1, 1); +} diff --git a/projects/HSLink-Pro/src/app.yaml b/projects/HSLink-Pro/src/app.yaml new file mode 100644 index 0000000..10d330f --- /dev/null +++ b/projects/HSLink-Pro/src/app.yaml @@ -0,0 +1,2 @@ +minimum_sdk_version: + - 1.6.0 diff --git a/projects/HSLink-Pro/src/dp_common.c b/projects/HSLink-Pro/src/dp_common.c new file mode 100644 index 0000000..cafc060 --- /dev/null +++ b/projects/HSLink-Pro/src/dp_common.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024 RCSN + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include "DAP_config.h" +#include "DAP.h" +#include "hpm_spi_drv.h" + +void set_swj_clock_frequency(uint32_t clock) +{ + uint8_t div, sclk_div; + uint32_t div_remainder; + uint32_t div_integer; + uint32_t clk_src_freq_in_hz, sclk_freq_in_hz; + sclk_freq_in_hz = clock; + SPI_Type *spi_base = NULL; + clock_name_t clock_name; + clk_src_freq_in_hz = clock_get_frequency(JTAG_SPI_BASE_CLOCK_NAME); + clk_src_t src_clock = clk_src_pll1_clk0; /* 800M */ + if (DAP_Data.debug_port == DAP_PORT_SWD) { + if (clock >= 10000000) { /* clock >= 10M */ + sclk_div = 0xFF; /* actual 80M*/ + div = 10; + } else if ((clock >= 5000000) && (clock < 10000000)) { /* 5M <= clock < 10M */ + sclk_div = 0xFF; /* actual 50M*/ + div = 16; + } else if ((clock >= 2000000) && (clock < 5000000)) { /* 2M <= clock < 5M */ + sclk_div = 1; /* actual 20M */ + div = 10; + } else if ((clock >= 1000000) && (clock < 2000000)) { /* 1M <= clock < 2M */ + sclk_div = 3; /* actual 10M */ + div = 10; + } else if ((clock >= 500000) && (clock < 1000000)) { /* 500K <= clock < 1M */ + sclk_div = 7; /* actual 5M */ + div = 10; + } else if ((clock >= 200000) && (clock < 500000)) { /* 200K <= clock < 500K */ + sclk_div = 19; /* actual 2M */ + div = 10; + } else { + sclk_div = 39; /* actual 1M */ + div = 10; + } + spi_base = SWD_SPI_BASE; + clock_name = SWD_SPI_BASE_CLOCK_NAME; + } else { + if (clock >= 40000000) { /* >= 40M*/ + sclk_div = 0xFF; + div = clock_get_frequency(clk_pll1clk0) / clock; + } else if ((clock >= 10000000) && (clock < 40000000)) { /* 10M <= clock < 40M */ + clock_set_source_divider(JTAG_SPI_BASE_CLOCK_NAME, src_clock, 10); + clk_src_freq_in_hz = clock_get_frequency(JTAG_SPI_BASE_CLOCK_NAME); + div_remainder = (clk_src_freq_in_hz % sclk_freq_in_hz); + div_integer = (clk_src_freq_in_hz / sclk_freq_in_hz); + if ((div_remainder != 0) || ((div_integer % 2) != 0)) { + sclk_div = 0; + clk_src_freq_in_hz = sclk_freq_in_hz * 2; + div = clock_get_frequency(clk_pll1clk0) / clk_src_freq_in_hz; + } else { + sclk_div = (div_integer / 2) - 1; + div = 10; + } + } else { /* < 10M */ + sclk_div = 3; + clk_src_freq_in_hz = sclk_freq_in_hz * 8; + div = clock_get_frequency(clk_pll1clk0) / clk_src_freq_in_hz; + } + spi_base = JTAG_SPI_BASE; + clock_name = JTAG_SPI_BASE_CLOCK_NAME; + } + + spi_master_set_sclk_div(spi_base, sclk_div); + clock_set_source_divider(clock_name, src_clock, div); +} + diff --git a/projects/HSLink-Pro/src/main.c b/projects/HSLink-Pro/src/main.c new file mode 100644 index 0000000..c1dcbb0 --- /dev/null +++ b/projects/HSLink-Pro/src/main.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include "board.h" +#include "dap_main.h" +#include "WS2812.h" +#include "projects/HSLink-Pro/common/HSLink_Pro_expansion.h" + +extern void uartx_preinit(void); + +char serial_number[32]; + +static void serial_number_init(void) +{ +#define OTP_CHIP_UUID_IDX_START (88U) +#define OTP_CHIP_UUID_IDX_END (91U) + uint32_t uuid_words[4]; + + uint32_t word_idx = 0; + for (uint32_t i = OTP_CHIP_UUID_IDX_START; i <= OTP_CHIP_UUID_IDX_END; i++) { + uuid_words[word_idx++] = ROM_API_TABLE_ROOT->otp_driver_if->read_from_shadow(i); + } + + char chip_id[32]; + sprintf(chip_id, "%08X%08X%08X%08X", uuid_words[0], uuid_words[1], uuid_words[2], uuid_words[3]); + memcpy(serial_number, chip_id, 32); + + printf("Serial number: %s\n", serial_number); +} + +ATTR_ALWAYS_INLINE +static inline void SWDIO_DIR_Init(void) +{ + HPM_IOC->PAD[SWDIO_DIR].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0);; + + gpiom_set_pin_controller(HPM_GPIOM, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), gpiom_core0_fast); + gpio_set_pin_output(HPM_FGPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR)); + gpio_write_pin(HPM_FGPIO, GPIO_GET_PORT_INDEX(SWDIO_DIR), GPIO_GET_PIN_INDEX(SWDIO_DIR), 1); +} + + +int main(void) +{ + board_init(); + serial_number_init(); + board_init_led_pins(); + board_init_usb_pins(); + dma_mgr_init(); + + SWDIO_DIR_Init(); + + printf("version: %s\n", DAP_FW_VER); + extern char *string_descriptors[]; +// string_descriptors[3] = serial_number; + memcpy(string_descriptors[3], serial_number, 32); + + HSP_Init(); + + intc_set_irq_priority(CONFIG_HPM_USBD_IRQn, 5); + uartx_preinit(); + + chry_dap_init(0, CONFIG_HPM_USBD_BASE); + while (1) { + chry_dap_handle(); + chry_dap_usb2uart_handle(); + HSP_Loop(); + } +} diff --git a/projects/HSLink-Pro/src/swd_common.h b/projects/HSLink-Pro/src/swd_common.h new file mode 100644 index 0000000..6b86aa3 --- /dev/null +++ b/projects/HSLink-Pro/src/swd_common.h @@ -0,0 +1,322 @@ + +/* + * Copyright (c) 2024 HPMicro + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include "hpm_common.h" + +typedef struct { + uint8_t start; + uint8_t ap_n_dp; + uint8_t r_n_w; + uint8_t addr[2]; + uint8_t parity; + uint8_t stop; + uint8_t park; +} host_format_t; + +typedef struct { + uint8_t ap_dp; + uint8_t rw; + uint8_t addr; + host_format_t *format; +} host_ops_t; + +ATTR_PLACE_AT(".ahb_sram") host_format_t host_format_table[] = { + /* APnDP = 0, RnW = 0 */ + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x00, + .r_n_w = 0x00, + .addr = {0x00, 0x00}, + .parity = 0x00, + }, + + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x00, + .r_n_w = 0x00, + .addr = {0x00, 0x01}, + .parity = 0x01, + }, + + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x00, + .r_n_w = 0x00, + .addr = {0x01, 0x00}, + .parity = 0x01, + }, + + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x00, + .r_n_w = 0x00, + .addr = {0x01, 0x01}, + .parity = 0x00, + }, + + /* APnDP = 1, RnW = 0 */ + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x01, + .r_n_w = 0x00, + .addr = {0x00, 0x00}, + .parity = 0x01, + }, + + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x01, + .r_n_w = 0x00, + .addr = {0x00, 0x01}, + .parity = 0x00, + }, + + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x01, + .r_n_w = 0x00, + .addr = {0x01, 0x00}, + .parity = 0x00, + }, + + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x01, + .r_n_w = 0x00, + .addr = {0x01, 0x01}, + .parity = 0x01, + }, + + /* APnDP = 0, RnW = 1 */ + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x00, + .r_n_w = 0x01, + .addr = {0x00, 0x00}, + .parity = 0x01, + }, + + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x00, + .r_n_w = 0x01, + .addr = {0x00, 0x01}, + .parity = 0x00, + }, + + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x00, + .r_n_w = 0x01, + .addr = {0x01, 0x00}, + .parity = 0x00, + }, + + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x00, + .r_n_w = 0x01, + .addr = {0x01, 0x01}, + .parity = 0x01, + }, + + /* APnDP = 1, RnW = 1 */ + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x01, + .r_n_w = 0x01, + .addr = {0x00, 0x00}, + .parity = 0x00, + }, + + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x01, + .r_n_w = 0x01, + .addr = {0x00, 0x01}, + .parity = 0x01, + }, + + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x01, + .r_n_w = 0x01, + .addr = {0x01, 0x00}, + .parity = 0x01, + }, + + { + .start = 0x01, + .stop = 0x00, + .park = 0x01, + .ap_n_dp = 0x01, + .r_n_w = 0x01, + .addr = {0x01, 0x01}, + .parity = 0x00, + }, +}; + +ATTR_PLACE_AT(".ahb_sram") host_ops_t host_ops_table[] = { + /* APnDP = 0, RnW = 0, ADDR = 0x00 */ + { + .ap_dp = 0x00, + .rw = 0x00, + .addr = 0x00, + .format = &host_format_table[0], + }, + + /* APnDP = 0, RnW = 0, ADDR = 0x01 */ + { + .ap_dp = 0x00, + .rw = 0x00, + .addr = 0x01, + .format = &host_format_table[1], + }, + + /* APnDP = 0, RnW = 0, ADDR = 0x10 */ + { + .ap_dp = 0x00, + .rw = 0x00, + .addr = 0x02, + .format = &host_format_table[2], + }, + + /* APnDP = 0, RnW = 0, ADDR = 0x11 */ + { + .ap_dp = 0x00, + .rw = 0x00, + .addr = 0x03, + .format = &host_format_table[3], + }, + + /* APnDP = 1, RnW = 0, ADDR = 0x00 */ + { + .ap_dp = 0x01, + .rw = 0x00, + .addr = 0x00, + .format = &host_format_table[4], + }, + + /* APnDP = 1, RnW = 0, ADDR = 0x01 */ + { + .ap_dp = 0x01, + .rw = 0x00, + .addr = 0x01, + .format = &host_format_table[5], + }, + + /* APnDP = 1, RnW = 0, ADDR = 0x10 */ + { + .ap_dp = 0x01, + .rw = 0x00, + .addr = 0x02, + .format = &host_format_table[6], + }, + + /* APnDP = 1, RnW = 0, ADDR = 0x11 */ + { + .ap_dp = 0x01, + .rw = 0x00, + .addr = 0x03, + .format = &host_format_table[7], + }, + + /* APnDP = 0, RnW = 1, ADDR = 0x00 */ + { + .ap_dp = 0x00, + .rw = 0x01, + .addr = 0x00, + .format = &host_format_table[8], + }, + + /* APnDP = 0, RnW = 1, ADDR = 0x01 */ + { + .ap_dp = 0x00, + .rw = 0x01, + .addr = 0x01, + .format = &host_format_table[9], + }, + + /* APnDP = 0, RnW = 1, ADDR = 0x10 */ + { + .ap_dp = 0x00, + .rw = 0x01, + .addr = 0x02, + .format = &host_format_table[10], + }, + + /* APnDP = 0, RnW = 1, ADDR = 0x11 */ + { + .ap_dp = 0x00, + .rw = 0x01, + .addr = 0x03, + .format = &host_format_table[11], + }, + + /* APnDP = 1, RnW = 1, ADDR = 0x00 */ + { + .ap_dp = 0x01, + .rw = 0x01, + .addr = 0x00, + .format = &host_format_table[12], + }, + + /* APnDP = 1, RnW = 1, ADDR = 0x01 */ + { + .ap_dp = 0x01, + .rw = 0x01, + .addr = 0x01, + .format = &host_format_table[13], + }, + + /* APnDP = 1, RnW = 1, ADDR = 0x10 */ + { + .ap_dp = 0x01, + .rw = 0x01, + .addr = 0x02, + .format = &host_format_table[14], + }, + + /* APnDP = 1, RnW = 1, ADDR = 0x11 */ + { + .ap_dp = 0x01, + .rw = 0x01, + .addr = 0x03, + .format = &host_format_table[15], + }, + +}; diff --git a/projects/HSLink-Pro/src/usb2uart.c b/projects/HSLink-Pro/src/usb2uart.c new file mode 100644 index 0000000..ca7f688 --- /dev/null +++ b/projects/HSLink-Pro/src/usb2uart.c @@ -0,0 +1,206 @@ +#include +#include "board.h" +#include "hpm_uart_drv.h" +#include "hpm_debug_console.h" +#include "hpm_dma_mgr.h" +#include "hpm_sysctl_drv.h" +#include "dap_main.h" + +#define UART_BASE HPM_UART2 +#define UART_IRQ IRQn_UART2 +#define UART_CLK_NAME clock_uart2 +#define UART_RX_DMA HPM_DMA_SRC_UART2_RX +#define UART_RX_DMA_RESOURCE_INDEX (0U) +#define UART_RX_DMA_BUFFER_SIZE (8192U) +#define UART_RX_DMA_BUFFER_COUNT (5) + +#define UART_TX_DMA HPM_DMA_SRC_UART2_TX +#define UART_TX_DMA_RESOURCE_INDEX (1U) +#define UART_TX_DMA_BUFFER_SIZE (8192U) + +ATTR_PLACE_AT_NONCACHEABLE_BSS_WITH_ALIGNMENT(4) +uint8_t uart_tx_buf[UART_TX_DMA_BUFFER_SIZE]; +ATTR_PLACE_AT_NONCACHEABLE_BSS_WITH_ALIGNMENT(4) +uint8_t uart_rx_buf[UART_RX_DMA_BUFFER_COUNT][UART_RX_DMA_BUFFER_SIZE]; +ATTR_PLACE_AT_NONCACHEABLE_BSS_WITH_ALIGNMENT(8) +dma_linked_descriptor_t rx_descriptors[UART_RX_DMA_BUFFER_COUNT - 1]; + +static dma_resource_t dma_resource_pools[2]; +volatile uint32_t g_uart_tx_transfer_length = 0; +static hpm_stat_t board_uart_dma_config(void); +static hpm_stat_t board_uart_rx_dma_restart(void); + +void dma_channel_tc_callback(DMA_Type *ptr, uint32_t channel, void *user_data) +{ + (void)ptr; + (void)channel; + (void)user_data; + uint32_t i; + dma_resource_t *rx_resource = &dma_resource_pools[UART_RX_DMA_RESOURCE_INDEX]; + dma_resource_t *tx_resource = &dma_resource_pools[UART_TX_DMA_RESOURCE_INDEX]; + uint32_t link_addr = ptr->CHCTRL[channel].LLPOINTER; + uint32_t rx_desc_size = (sizeof(rx_descriptors) / sizeof(dma_linked_descriptor_t)); + if (rx_resource->channel == channel) { + if (link_addr == (uint32_t)NULL) { + board_uart_rx_dma_restart(); + return; + } + for (i = 0; i < rx_desc_size; i++) { + if (link_addr == core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)&rx_descriptors[i])) { + chry_ringbuffer_write(&g_uartrx, uart_rx_buf[i - 1], UART_RX_DMA_BUFFER_SIZE); + } + } + } + if (tx_resource->channel == channel) { + chry_dap_usb2uart_uart_send_complete(g_uart_tx_transfer_length); + } +} + +void uart_isr(void) +{ + uint32_t uart_received_data_count; + uint32_t i; + dma_resource_t *rx_resource = &dma_resource_pools[UART_RX_DMA_RESOURCE_INDEX]; + uint32_t link_addr = rx_resource->base->CHCTRL[rx_resource->channel].LLPOINTER; + uint32_t rx_desc_size = (sizeof(rx_descriptors) / sizeof(dma_linked_descriptor_t)); + if (uart_is_rxline_idle(UART_BASE)) { + uart_clear_rxline_idle_flag(UART_BASE); + uart_received_data_count = UART_RX_DMA_BUFFER_SIZE - dma_get_remaining_transfer_size(rx_resource->base, rx_resource->channel); + if (uart_received_data_count > 0) { + for (i = 0; i < rx_desc_size; i++) { + if (link_addr == core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)&rx_descriptors[i])) { + chry_ringbuffer_write(&g_uartrx, uart_rx_buf[i], uart_received_data_count); + board_uart_rx_dma_restart(); + break; + } + } + } + } +} +SDK_DECLARE_EXT_ISR_M(UART_IRQ, uart_isr) + +void uartx_preinit(void) +{ + // board_init_uart(UART_BASE); + HPM_IOC->PAD[IOC_PAD_PA09].FUNC_CTL = IOC_PA09_FUNC_CTL_UART2_RXD; + HPM_IOC->PAD[IOC_PAD_PA08].FUNC_CTL = IOC_PA08_FUNC_CTL_UART2_TXD; + + clock_set_source_divider(UART_CLK_NAME, clk_src_pll1_clk0, 8); + clock_add_to_group(UART_CLK_NAME, 0); + intc_m_enable_irq_with_priority(UART_IRQ, 2); + uart_clear_rxline_idle_flag(UART_BASE); + if (board_uart_dma_config() != status_success) { + return; + } +} + +void chry_dap_usb2uart_uart_config_callback(struct cdc_line_coding *line_coding) +{ + uart_config_t config = { 0 }; + uart_default_config(UART_BASE, &config); + config.baudrate = line_coding->dwDTERate; + config.parity = line_coding->bParityType; + config.word_length = line_coding->bDataBits - 5; + config.num_of_stop_bits = line_coding->bCharFormat; + config.fifo_enable = true; + config.dma_enable = true; + config.src_freq_in_hz = clock_get_frequency(UART_CLK_NAME); + config.rx_fifo_level = uart_rx_fifo_trg_not_empty; /* this config should not change */ + config.tx_fifo_level = uart_tx_fifo_trg_not_full; + config.rxidle_config.detect_enable = true; + config.rxidle_config.detect_irq_enable = true; + config.rxidle_config.idle_cond = uart_rxline_idle_cond_state_machine_idle; + config.rxidle_config.threshold = 30U; /* 20bit */ + uart_init(UART_BASE, &config); + uart_clear_rxline_idle_flag(UART_BASE); + uart_reset_rx_fifo(UART_BASE); + uart_reset_tx_fifo(UART_BASE); +} + +void chry_dap_usb2uart_uart_send_bydma(uint8_t *data, uint16_t len) +{ + uint32_t buf_addr; + dma_resource_t *tx_resource = &dma_resource_pools[UART_TX_DMA_RESOURCE_INDEX]; + if (len <= 0) { + return; + } + g_uart_tx_transfer_length = len; + buf_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)data); + dma_mgr_set_chn_src_addr(tx_resource, buf_addr); + dma_mgr_set_chn_transize(tx_resource, len); + dma_mgr_enable_channel(tx_resource); +} + +static hpm_stat_t board_uart_rx_dma_restart(void) +{ + dma_resource_t *resource = &dma_resource_pools[UART_RX_DMA_RESOURCE_INDEX]; + dma_mgr_disable_channel(resource); + uint32_t addr = core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)uart_rx_buf[0]); + dma_mgr_set_chn_dst_addr(resource, addr); + addr = core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)&rx_descriptors[0]); + resource->base->CHCTRL[resource->channel].LLPOINTER = addr; + dma_mgr_set_chn_transize(resource, UART_RX_DMA_BUFFER_SIZE); + dma_mgr_enable_channel(resource); + return status_success; +} +static hpm_stat_t board_uart_dma_config(void) +{ + dma_mgr_chn_conf_t chg_config; + dma_resource_t *resource = NULL; + uint32_t i = 0; + uint32_t rx_desc_size = (sizeof(rx_descriptors) / sizeof(dma_linked_descriptor_t)); + dma_mgr_get_default_chn_config(&chg_config); + chg_config.src_width = DMA_MGR_TRANSFER_WIDTH_BYTE; + chg_config.dst_width = DMA_MGR_TRANSFER_WIDTH_BYTE; + /* uart rx dma config */ + resource = &dma_resource_pools[UART_RX_DMA_RESOURCE_INDEX]; + if (dma_mgr_request_resource(resource) == status_success) { + chg_config.src_mode = DMA_MGR_HANDSHAKE_MODE_HANDSHAKE; + chg_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED; + chg_config.src_addr = (uint32_t)&UART_BASE->RBR; + chg_config.dst_mode = DMA_MGR_HANDSHAKE_MODE_NORMAL; + chg_config.dst_addr_ctrl = DMA_MGR_ADDRESS_CONTROL_INCREMENT; + chg_config.size_in_byte = UART_RX_DMA_BUFFER_SIZE; + chg_config.en_dmamux = true; + chg_config.dmamux_src = UART_RX_DMA; + for (i = 0; i < rx_desc_size; i++) { + if (i < (rx_desc_size - 1)) { + chg_config.dst_addr = core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)uart_rx_buf[i + 1]); + chg_config.linked_ptr = core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)&rx_descriptors[i + 1]); + } else { + chg_config.dst_addr = core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)uart_rx_buf[1]); + chg_config.linked_ptr = core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)&rx_descriptors[0]); + } + if (dma_mgr_config_linked_descriptor(resource, &chg_config, (dma_mgr_linked_descriptor_t *)&rx_descriptors[i]) != status_success) { + printf("generate dma desc fail\n"); + return status_fail; + } + rx_descriptors[i].ctrl &= ~DMA_MGR_INTERRUPT_MASK_TC; + printf("linker_addr:0x%08x %d\n", (uint32_t)&rx_descriptors[i], i); + } + chg_config.dst_addr = core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)uart_rx_buf[0]); + chg_config.linked_ptr = core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)&rx_descriptors[0]); + dma_mgr_setup_channel(resource, &chg_config); + dma_mgr_enable_channel(resource); + dma_mgr_install_chn_tc_callback(resource, dma_channel_tc_callback, NULL); + dma_mgr_enable_chn_irq(resource, DMA_MGR_INTERRUPT_MASK_TC); + dma_mgr_enable_dma_irq_with_priority(resource, 1); + } + /* uart tx dma config */ + resource = &dma_resource_pools[UART_TX_DMA_RESOURCE_INDEX]; + if (dma_mgr_request_resource(resource) == status_success) { + chg_config.src_mode = DMA_MGR_HANDSHAKE_MODE_NORMAL; + chg_config.src_addr_ctrl = DMA_MGR_ADDRESS_CONTROL_INCREMENT; + chg_config.dst_mode = DMA_MGR_HANDSHAKE_MODE_HANDSHAKE; + chg_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED; + chg_config.dst_addr = (uint32_t)&UART_BASE->THR; + chg_config.en_dmamux = true; + chg_config.dmamux_src = UART_TX_DMA; + chg_config.linked_ptr = (uint32_t)NULL; + dma_mgr_setup_channel(resource, &chg_config); + dma_mgr_install_chn_tc_callback(resource, dma_channel_tc_callback, NULL); + dma_mgr_enable_chn_irq(resource, DMA_MGR_INTERRUPT_MASK_TC); + dma_mgr_enable_dma_irq_with_priority(resource, 1); + } + return status_success; +} diff --git a/projects/HSLink-Pro/src/usb_config.h b/projects/HSLink-Pro/src/usb_config.h new file mode 100644 index 0000000..919f709 --- /dev/null +++ b/projects/HSLink-Pro/src/usb_config.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2022, sakumisu + * Copyright (c) 2022-2023, HPMicro + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef CHERRYUSB_CONFIG_H +#define CHERRYUSB_CONFIG_H + +#include "hpm_soc.h" + +//#define CHERRYUSB_VERSION 0x001002 + +/* ================ USB common Configuration ================ */ + +#define CONFIG_USB_PRINTF(...) printf(__VA_ARGS__) + +#define usb_malloc(size) malloc(size) +#define usb_free(ptr) free(ptr) + +#ifndef CONFIG_USB_DBG_LEVEL +#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO +#endif + + +/* Enable print with color */ +#define CONFIG_USB_PRINTF_COLOR_ENABLE + +/* data align size when use dma */ +#ifndef CONFIG_USB_ALIGN_SIZE +#define CONFIG_USB_ALIGN_SIZE 4 +#endif + +#define CONFIG_USBDEV_ADVANCE_DESC + +/* attribute data into no cache ram */ +#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable"))) + +/* ================= USB Device Stack Configuration ================ */ + +/* Ep0 max transfer buffer, specially for receiving data from ep0 out */ +#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512 + +/* Setup packet log for debug */ +/* #define CONFIG_USBDEV_SETUP_LOG_PRINT */ + +/* Check if the input descriptor is correct */ +/* #define CONFIG_USBDEV_DESC_CHECK */ + +/* Enable test mode */ +/* #define CONFIG_USBDEV_TEST_MODE */ + +#ifndef CONFIG_USBDEV_MSC_BLOCK_SIZE +#define CONFIG_USBDEV_MSC_BLOCK_SIZE 512 +#endif + +#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING +#define CONFIG_USBDEV_MSC_MANUFACTURER_STRING "" +#endif + +#ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING +#define CONFIG_USBDEV_MSC_PRODUCT_STRING "" +#endif + +#ifndef CONFIG_USBDEV_MSC_VERSION_STRING +#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01" +#endif + +/* #define CONFIG_USBDEV_MSC_THREAD */ + +#ifndef CONFIG_USBDEV_MSC_PRIO +#define CONFIG_USBDEV_MSC_PRIO 4 +#endif + +#ifndef CONFIG_USBDEV_MSC_STACKSIZE +#define CONFIG_USBDEV_MSC_STACKSIZE 2048 +#endif + +#ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE +#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156 +#endif + +#ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE +#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1536 +#endif + +#ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID +#define CONFIG_USBDEV_RNDIS_VENDOR_ID 0x0000ffff +#endif + +#ifndef CONFIG_USBDEV_RNDIS_VENDOR_DESC +#define CONFIG_USBDEV_RNDIS_VENDOR_DESC "CherryUSB" +#endif + +#define CONFIG_USBDEV_RNDIS_USING_LWIP + +/* ================ USB HOST Stack Configuration ================== */ + +#define CONFIG_USBHOST_MAX_RHPORTS 1 +#define CONFIG_USBHOST_MAX_EXTHUBS 1 +#define CONFIG_USBHOST_MAX_EHPORTS 4 +#define CONFIG_USBHOST_MAX_INTERFACES 8 +#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 2 +#define CONFIG_USBHOST_MAX_ENDPOINTS 8 + +#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4 +#define CONFIG_USBHOST_MAX_HID_CLASS 4 +#define CONFIG_USBHOST_MAX_MSC_CLASS 2 +#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1 +#define CONFIG_USBHOST_MAX_VIDEO_CLASS 1 + +#define CONFIG_USBHOST_DEV_NAMELEN 16 + +#ifndef CONFIG_USBHOST_PSC_PRIO +#define CONFIG_USBHOST_PSC_PRIO 0 +#endif +#ifndef CONFIG_USBHOST_PSC_STACKSIZE +#define CONFIG_USBHOST_PSC_STACKSIZE 2048 +#endif + +/* #define CONFIG_USBHOST_GET_STRING_DESC */ + +/* #define CONFIG_USBHOST_MSOS_ENABLE */ +#define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00 + +/* Ep0 max transfer buffer */ +#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512 + +#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT +#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500 +#endif + +#ifndef CONFIG_USBHOST_MSC_TIMEOUT +#define CONFIG_USBHOST_MSC_TIMEOUT 5000 +#endif + +/* ================ USB Device Port Configuration ================*/ + +#ifndef CONFIG_USBDEV_MAX_BUS +#define CONFIG_USBDEV_MAX_BUS 1 // for now, bus num must be 1 except hpm ip +#endif + +#ifndef CONFIG_USBDEV_EP_NUM +#define CONFIG_USBDEV_EP_NUM 16 +#endif + +/* ================ USB Device Port Configuration ================*/ + +#ifndef CONFIG_HPM_USBD_BASE +#define CONFIG_HPM_USBD_BASE HPM_USB0_BASE +#endif +#ifndef CONFIG_HPM_USBD_IRQn +#define CONFIG_HPM_USBD_IRQn IRQn_USB0 +#endif + +/* ================ USB Host Port Configuration ==================*/ + +#define CONFIG_USBHOST_PIPE_NUM 10 +#ifndef CONFIG_HPM_USBH_BASE +#define CONFIG_HPM_USBH_BASE HPM_USB0_BASE +#endif +#ifndef CONFIG_HPM_USBH_IRQn +#define CONFIG_HPM_USBH_IRQn IRQn_USB0 +#endif + +/* ================ EHCI Configuration ================ */ + +#define CONFIG_USB_EHCI_HPMICRO (1) +#define CONFIG_USB_EHCI_HCCR_BASE (0) +#define CONFIG_USB_EHCI_HCOR_BASE (CONFIG_HPM_USBH_BASE + 0x140) +#define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024 +/* #define CONFIG_USB_EHCI_INFO_ENABLE */ +/* #define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE */ +/* #define CONFIG_USB_EHCI_CONFIGFLAG */ +#define CONFIG_USB_EHCI_PORT_POWER + +#endif diff --git a/projects/hpm5301evklite/CMakeLists.txt b/projects/hpm5301evklite/CMakeLists.txt index 4805afb..088ee4d 100644 --- a/projects/hpm5301evklite/CMakeLists.txt +++ b/projects/hpm5301evklite/CMakeLists.txt @@ -5,7 +5,15 @@ cmake_minimum_required(VERSION 3.13) set(CONFIG_USB_DEVICE 1) set(CONFIG_DMA_MGR 1) -# set(CONFIG_USE_SPI_SWD 1) + +# CONFIG_USE_HPM_BOARD_JTAG_GPIO is for 20p output SWD+JTAG signal of hpm5301evklite +set(CONFIG_USE_HPM_BOARD_JTAG_GPIO 0) + +if(NOT DEFINED CONFIG_USE_HPM_BOARD_JTAG_GPIO OR (CONFIG_USE_HPM_BOARD_JTAG_GPIO EQUAL "0")) + set(CONFIG_USE_SPI_SWD 1) + set(CONFIG_USE_SPI_JTAG 1) +endif() + find_package(hpm-sdk REQUIRED HINTS $ENV{HPM_SDK_BASE}) project(hpm5300evklite_dap) @@ -20,14 +28,38 @@ sdk_src(../../CherryUSB/core/usbd_core.c) sdk_src(../../CherryUSB/port/hpm/usb_dc_hpm.c) sdk_src(../../CherryUSB/class/cdc/usbd_cdc.c) +# swj_clock default use keil swd frequency boost +sdk_compile_definitions(-DBOOST_KEIL_SWD_FREQ=1) + +if(NOT DEFINED CONFIG_USE_HPM_BOARD_JTAG_GPIO AND (CONFIG_USE_HPM_BOARD_JTAG_GPIO EQUAL "1")) +sdk_compile_definitions(-DUSE_HPM_BOARD_JTAG_GPIO=1) +sdk_compile_definitions(-DPIN_LED_CONNECTED=IOC_PAD_PA10) +sdk_compile_definitions(-DPIN_LED_RUNNING=IOC_PAD_PA10) +sdk_compile_definitions(-DPIN_JTAG_TRST=IOC_PAD_PA08) +sdk_compile_definitions(-DPIN_SRST=IOC_PAD_PA08) +sdk_compile_definitions(-DLED_ACTIVE_LEVEL=1) +else() +sdk_compile_definitions(-DPIN_LED_CONNECTED=IOC_PAD_PA10) +sdk_compile_definitions(-DPIN_LED_RUNNING=IOC_PAD_PA10) +sdk_compile_definitions(-DPIN_JTAG_TRST=IOC_PAD_PB08) +sdk_compile_definitions(-DPIN_SRST=IOC_PAD_PB09) +sdk_compile_definitions(-DLED_ACTIVE_LEVEL=1) +endif() -if(CONFIG_USE_SPI_SWD) +if(DEFINED CONFIG_USE_SPI_SWD AND (CONFIG_USE_SPI_SWD EQUAL "1")) sdk_compile_definitions(-DUSE_SPI_SWD=1) sdk_app_src(SW_DP_SPI.c) else() sdk_app_src(../../DAP/Source/SW_DP.c) endif() +if(DEFINED CONFIG_USE_SPI_JTAG AND (CONFIG_USE_SPI_JTAG EQUAL "1")) +sdk_compile_definitions(-DUSE_SPI_JTAG=1) +sdk_app_src(JTAG_DP_SPI.c) +else() +sdk_app_src(../../DAP/Source/JTAG_DP.c) +endif() + sdk_inc(./) sdk_inc(../..) sdk_inc(../../CherryRB) @@ -37,11 +69,11 @@ sdk_app_src(../../dap_main.c) sdk_app_src(../../DAP/Source/DAP_vendor.c) sdk_app_src(../../DAP/Source/DAP.c) -sdk_app_src(../../DAP/Source/JTAG_DP.c) sdk_app_src(../../CherryRB/chry_ringbuffer.c) sdk_app_src(main.c) sdk_app_src(usb2uart.c) +sdk_app_src(dp_common.c) sdk_compile_options("-O3") generate_ses_project() diff --git a/projects/hpm5301evklite/DAP_config.h b/projects/hpm5301evklite/DAP_config.h index 12a5982..4c13a2b 100644 --- a/projects/hpm5301evklite/DAP_config.h +++ b/projects/hpm5301evklite/DAP_config.h @@ -141,7 +141,7 @@ This information includes: /// This information is returned by the command \ref DAP_Info as part of Capabilities. #define DAP_UART_USB_COM_PORT 1 ///< USB COM Port: 1 = available, 0 = not available. -#define USE_SPI_GPIO 0 + /// Debug Unit is connected to fixed Target Device. /// The Debug Unit may be part of an evaluation board and always connected to a fixed /// known device. In this case a Device Vendor, Device Name, Board Vendor and Board Name strings @@ -274,56 +274,25 @@ __STATIC_INLINE uint8_t DAP_GetProductFirmwareVersionString (char *str) { #include "hpm_csr_drv.h" #include "hpm_clock_drv.h" -/*SPI -MISO----TDO PA28 -MOSI----TDI PA29 -SCLK----TCK PA27 -CE0-----TMS PA26 -NRESET--IO PA31 -*/ - -/*GPIO -TDO PA04 -TDI PA05 -TCK PA06 -TMS PA07 -NRESET--IO PA31 -*/ +#define JTAG_SPI_BASE HPM_SPI2 +#define JTAG_SPI_BASE_CLOCK_NAME clock_spi2 -#define PIN_LED IOC_PAD_PA10 -#define PIN_LED_NUM 10 - -#if defined(USE_SPI_GPIO) && (USE_SPI_GPIO == 1) +#define SWD_SPI_BASE HPM_SPI1 +#define SWD_SPI_BASE_CLOCK_NAME clock_spi1 #define PIN_GPIOM_BASE HPM_GPIOM #define PIN_GPIO HPM_FGPIO -#define PIN_PORT GPIO_OE_GPIOA -#define PIN_TCK IOC_PAD_PA27 -#define PIN_TMS IOC_PAD_PA26 -#define PIN_TDI IOC_PAD_PA29 -#define PIN_TDO IOC_PAD_PA28 -#define PIN_nRESET IOC_PAD_PA31 - -#define PIN_TCK_NUM 27 -#define PIN_TMS_NUM 26 -#define PIN_TDI_NUM 29 -#define PIN_TDO_NUM 28 -#define PIN_nRESET_NUM 31 + +#if defined(USE_HPM_BOARD_JTAG_GPIO) && (USE_HPM_BOARD_JTAG_GPIO == 1) + #define PIN_TCK IOC_PAD_PA06 + #define PIN_TMS IOC_PAD_PA07 + #define PIN_TDI IOC_PAD_PA05 + #define PIN_TDO IOC_PAD_PA04 #else -#define PIN_GPIOM_BASE HPM_GPIOM -#define PIN_GPIO HPM_FGPIO -#define PIN_PORT GPIO_OE_GPIOA -#define PIN_TCK IOC_PAD_PA06 -#define PIN_TMS IOC_PAD_PA07 -#define PIN_TDI IOC_PAD_PA05 -#define PIN_TDO IOC_PAD_PA04 -#define PIN_nRESET IOC_PAD_PA08 - -#define PIN_TCK_NUM 6 -#define PIN_TMS_NUM 7 -#define PIN_TDI_NUM 5 -#define PIN_TDO_NUM 4 -#define PIN_nRESET_NUM 8 + #define PIN_TCK IOC_PAD_PB11 + #define PIN_TMS IOC_PAD_PA29 + #define PIN_TDI IOC_PAD_PB13 + #define PIN_TDO IOC_PAD_PB12 #endif //************************************************************************************************** @@ -369,67 +338,79 @@ Configures the DAP Hardware I/O pins for JTAG mode: - TCK, TMS, TDI, nTRST, nRESET to output mode and set to high level. - TDO to input mode. */ -__STATIC_INLINE void gpiom_configure_pin_control_setting(uint8_t pin_index) +__STATIC_INLINE void gpiom_configure_pin_control_setting(uint16_t gpio_index) { - gpiom_set_pin_controller(PIN_GPIOM_BASE, PIN_PORT, pin_index, gpiom_core0_fast); - gpiom_enable_pin_visibility(PIN_GPIOM_BASE, PIN_PORT, pin_index, gpiom_core0_fast); - gpiom_lock_pin(PIN_GPIOM_BASE, PIN_PORT, pin_index); + gpiom_set_pin_controller(PIN_GPIOM_BASE, GPIO_GET_PORT_INDEX(gpio_index), GPIO_GET_PIN_INDEX(gpio_index), gpiom_core0_fast); + gpiom_enable_pin_visibility(PIN_GPIOM_BASE, GPIO_GET_PORT_INDEX(gpio_index), GPIO_GET_PIN_INDEX(gpio_index), gpiom_core0_fast); + gpiom_lock_pin(PIN_GPIOM_BASE, GPIO_GET_PORT_INDEX(gpio_index), GPIO_GET_PIN_INDEX(gpio_index)); } - +#if !defined(USE_SPI_JTAG) || (USE_SPI_JTAG == 0) __STATIC_INLINE void PORT_JTAG_SETUP (void) { HPM_IOC->PAD[PIN_TCK].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0) | IOC_PAD_FUNC_CTL_LOOP_BACK_MASK; /* as gpio*/ HPM_IOC->PAD[PIN_TMS].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); /* as gpio*/ HPM_IOC->PAD[PIN_TDI].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); /* as gpio*/ HPM_IOC->PAD[PIN_TDO].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); - HPM_IOC->PAD[PIN_nRESET].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); - HPM_IOC->PAD[PIN_LED].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); - - gpiom_configure_pin_control_setting(PIN_TDO_NUM); - gpiom_configure_pin_control_setting(PIN_TCK_NUM); - gpiom_configure_pin_control_setting(PIN_TMS_NUM); - gpiom_configure_pin_control_setting(PIN_TDI_NUM); - gpiom_configure_pin_control_setting(PIN_nRESET_NUM); - gpiom_configure_pin_control_setting(PIN_LED_NUM); - - gpio_set_pin_input(PIN_GPIO, PIN_PORT, PIN_TDO_NUM); - gpio_set_pin_output(PIN_GPIO, PIN_PORT, PIN_TCK_NUM); - gpio_set_pin_output(PIN_GPIO, PIN_PORT, PIN_TMS_NUM); - gpio_set_pin_output(PIN_GPIO, PIN_PORT, PIN_TDI_NUM); - gpio_set_pin_output(PIN_GPIO, PIN_PORT, PIN_LED_NUM); + HPM_IOC->PAD[PIN_JTAG_TRST].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + HPM_IOC->PAD[PIN_SRST].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + HPM_IOC->PAD[PIN_LED_RUNNING].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + HPM_IOC->PAD[PIN_LED_CONNECTED].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + + gpiom_configure_pin_control_setting(PIN_TDO); + gpiom_configure_pin_control_setting(PIN_TCK); + gpiom_configure_pin_control_setting(PIN_TMS); + gpiom_configure_pin_control_setting(PIN_TDI); + gpiom_configure_pin_control_setting(PIN_JTAG_TRST); + gpiom_configure_pin_control_setting(PIN_SRST); + gpiom_configure_pin_control_setting(PIN_LED_RUNNING); + gpiom_configure_pin_control_setting(PIN_LED_CONNECTED); + + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDO), GPIO_GET_PIN_INDEX(PIN_TDO)); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK)); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDI), GPIO_GET_PIN_INDEX(PIN_TDI)); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_RUNNING), GPIO_GET_PIN_INDEX(PIN_LED_RUNNING)); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_CONNECTED), GPIO_GET_PIN_INDEX(PIN_LED_CONNECTED)); HPM_IOC->PAD[PIN_TDO].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); HPM_IOC->PAD[PIN_TCK].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); HPM_IOC->PAD[PIN_TMS].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); HPM_IOC->PAD[PIN_TDI].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); - HPM_IOC->PAD[PIN_nRESET].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_JTAG_TRST].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_SRST].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); } +#else +void PORT_JTAG_SETUP(void); +#endif /** Setup SWD I/O pins: SWCLK, SWDIO, and nRESET. Configures the DAP Hardware I/O pins for Serial Wire Debug (SWD) mode: - SWCLK, SWDIO, nRESET to output mode and set to default high level. - TDI, nTRST to HighZ mode (pins are unused in SWD mode). */ -#ifndef USE_SPI_SWD +#if !defined(USE_SPI_SWD) || (USE_SPI_SWD == 0) __STATIC_INLINE void PORT_SWD_SETUP (void) { HPM_IOC->PAD[PIN_TCK].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0) | IOC_PAD_FUNC_CTL_LOOP_BACK_MASK; /* as gpio*/ HPM_IOC->PAD[PIN_TMS].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); /* as gpio*/ - HPM_IOC->PAD[PIN_nRESET].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); - HPM_IOC->PAD[PIN_LED].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); - - gpiom_configure_pin_control_setting(PIN_TCK_NUM); - gpiom_configure_pin_control_setting(PIN_TMS_NUM); - gpiom_configure_pin_control_setting(PIN_nRESET_NUM); - gpiom_configure_pin_control_setting(PIN_LED_NUM); - - gpio_set_pin_output(PIN_GPIO, PIN_PORT, PIN_TCK_NUM); - gpio_set_pin_output(PIN_GPIO, PIN_PORT, PIN_TMS_NUM); - gpio_set_pin_output(PIN_GPIO, PIN_PORT, PIN_LED_NUM); + HPM_IOC->PAD[PIN_SRST].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + HPM_IOC->PAD[PIN_LED_RUNNING].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + HPM_IOC->PAD[PIN_LED_CONNECTED].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + + gpiom_configure_pin_control_setting(PIN_TCK); + gpiom_configure_pin_control_setting(PIN_TMS); + gpiom_configure_pin_control_setting(PIN_SRST); + gpiom_configure_pin_control_setting(PIN_LED_RUNNING); + gpiom_configure_pin_control_setting(PIN_LED_CONNECTED); + + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK)); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_RUNNING), GPIO_GET_PIN_INDEX(PIN_LED_RUNNING)); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_CONNECTED), GPIO_GET_PIN_INDEX(PIN_LED_CONNECTED)); HPM_IOC->PAD[PIN_TCK].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); HPM_IOC->PAD[PIN_TMS].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); - HPM_IOC->PAD[PIN_nRESET].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_SRST].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_SPD_SET(3); } #else void PORT_SWD_SETUP(void); @@ -451,28 +432,35 @@ __STATIC_INLINE void PORT_OFF (void) { HPM_IOC->PAD[PIN_TDO].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2); HPM_IOC->PAD[PIN_TDO].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); - HPM_IOC->PAD[PIN_nRESET].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2); - HPM_IOC->PAD[PIN_nRESET].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + HPM_IOC->PAD[PIN_SRST].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2); + HPM_IOC->PAD[PIN_SRST].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + + HPM_IOC->PAD[PIN_JTAG_TRST].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2); + HPM_IOC->PAD[PIN_JTAG_TRST].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK)); + gpio_disable_pin_interrupt(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK)); + gpiom_set_pin_controller(HPM_GPIOM, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK), gpiom_soc_gpio0); - gpio_set_pin_input(PIN_GPIO, PIN_PORT, PIN_TCK_NUM); - gpio_disable_pin_interrupt(PIN_GPIO, GPIO_IE_GPIOA, PIN_TCK_NUM); - gpiom_set_pin_controller(HPM_GPIOM, GPIOM_ASSIGN_GPIOA, PIN_TCK_NUM, gpiom_soc_gpio0); + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); + gpio_disable_pin_interrupt(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); + gpiom_set_pin_controller(HPM_GPIOM, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS), gpiom_soc_gpio0); - gpio_set_pin_input(PIN_GPIO, PIN_PORT, PIN_TMS_NUM); - gpio_disable_pin_interrupt(PIN_GPIO, GPIO_IE_GPIOA, PIN_TMS_NUM); - gpiom_set_pin_controller(HPM_GPIOM, GPIOM_ASSIGN_GPIOA, PIN_TMS_NUM, gpiom_soc_gpio0); + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDI), GPIO_GET_PIN_INDEX(PIN_TDI)); + gpio_disable_pin_interrupt(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDI), GPIO_GET_PIN_INDEX(PIN_TDI)); + gpiom_set_pin_controller(HPM_GPIOM, GPIO_GET_PORT_INDEX(PIN_TDI), GPIO_GET_PIN_INDEX(PIN_TDI), gpiom_soc_gpio0); - gpio_set_pin_input(PIN_GPIO, PIN_PORT, PIN_TDI_NUM); - gpio_disable_pin_interrupt(PIN_GPIO, GPIO_IE_GPIOA, PIN_TDI_NUM); - gpiom_set_pin_controller(HPM_GPIOM, GPIOM_ASSIGN_GPIOA, PIN_TDI_NUM, gpiom_soc_gpio0); + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDO), GPIO_GET_PIN_INDEX(PIN_TDO)); + gpio_disable_pin_interrupt(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDO), GPIO_GET_PIN_INDEX(PIN_TDO)); + gpiom_set_pin_controller(HPM_GPIOM, GPIO_GET_PORT_INDEX(PIN_TDO), GPIO_GET_PIN_INDEX(PIN_TDO), gpiom_soc_gpio0); - gpio_set_pin_input(PIN_GPIO, PIN_PORT, PIN_TDO_NUM); - gpio_disable_pin_interrupt(PIN_GPIO, GPIO_IE_GPIOA, PIN_TDO_NUM); - gpiom_set_pin_controller(HPM_GPIOM, GPIOM_ASSIGN_GPIOA, PIN_TDO_NUM, gpiom_soc_gpio0); + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_SRST), GPIO_GET_PIN_INDEX(PIN_SRST)); + gpio_disable_pin_interrupt(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_SRST), GPIO_GET_PIN_INDEX(PIN_SRST)); + gpiom_set_pin_controller(HPM_GPIOM, GPIO_GET_PORT_INDEX(PIN_SRST), GPIO_GET_PIN_INDEX(PIN_SRST), gpiom_soc_gpio0); - gpio_set_pin_input(PIN_GPIO, PIN_PORT, PIN_nRESET_NUM); - gpio_disable_pin_interrupt(PIN_GPIO, GPIO_IE_GPIOA, PIN_nRESET_NUM); - gpiom_set_pin_controller(HPM_GPIOM, GPIOM_ASSIGN_GPIOA, PIN_nRESET_NUM, gpiom_soc_gpio0); + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TRST), GPIO_GET_PIN_INDEX(PIN_JTAG_TRST)); + gpio_disable_pin_interrupt(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TRST), GPIO_GET_PIN_INDEX(PIN_JTAG_TRST)); + gpiom_set_pin_controller(HPM_GPIOM, GPIO_GET_PORT_INDEX(PIN_JTAG_TRST), GPIO_GET_PIN_INDEX(PIN_JTAG_TRST), gpiom_soc_gpio0); } @@ -482,7 +470,7 @@ __STATIC_INLINE void PORT_OFF (void) { \return Current status of the SWCLK/TCK DAP hardware I/O pin. */ __STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN (void) { - uint32_t sta = gpio_read_pin(PIN_GPIO, PIN_PORT, PIN_TCK_NUM); + uint32_t sta = gpio_read_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK)); __asm volatile("fence io, io"); return sta; } @@ -491,7 +479,7 @@ __STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN (void) { Set the SWCLK/TCK DAP hardware I/O pin to high level.; */ __STATIC_FORCEINLINE void PIN_SWCLK_TCK_SET (void) { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_TCK_NUM, true); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK), true); __asm volatile("fence io, io"); } @@ -499,7 +487,7 @@ __STATIC_FORCEINLINE void PIN_SWCLK_TCK_SET (void) { Set the SWCLK/TCK DAP hardware I/O pin to low level. */ __STATIC_FORCEINLINE void PIN_SWCLK_TCK_CLR (void) { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_TCK_NUM, false); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TCK), GPIO_GET_PIN_INDEX(PIN_TCK), false); __asm volatile("fence io, io"); } @@ -510,7 +498,7 @@ __STATIC_FORCEINLINE void PIN_SWCLK_TCK_CLR (void) { \return Current status of the SWDIO/TMS DAP hardware I/O pin. */ __STATIC_FORCEINLINE uint32_t PIN_SWDIO_TMS_IN (void) { - uint32_t sta = gpio_read_pin(PIN_GPIO, PIN_PORT, PIN_TMS_NUM); + uint32_t sta = gpio_read_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); __asm volatile("fence io, io"); return sta; } @@ -519,7 +507,7 @@ __STATIC_FORCEINLINE uint32_t PIN_SWDIO_TMS_IN (void) { Set the SWDIO/TMS DAP hardware I/O pin to high level. */ __STATIC_FORCEINLINE void PIN_SWDIO_TMS_SET (void) { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_TMS_NUM, true); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS), true); __asm volatile("fence io, io"); } @@ -527,7 +515,7 @@ __STATIC_FORCEINLINE void PIN_SWDIO_TMS_SET (void) { Set the SWDIO/TMS DAP hardware I/O pin to low level. */ __STATIC_FORCEINLINE void PIN_SWDIO_TMS_CLR (void) { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_TMS_NUM, false); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS), false); __asm volatile("fence io, io"); } @@ -535,7 +523,7 @@ __STATIC_FORCEINLINE void PIN_SWDIO_TMS_CLR (void) { \return Current status of the SWDIO DAP hardware I/O pin. */ __STATIC_FORCEINLINE uint32_t PIN_SWDIO_IN (void) { - uint32_t sta = gpio_read_pin(PIN_GPIO, PIN_PORT, PIN_TMS_NUM); + uint32_t sta = gpio_read_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); __asm volatile("fence io, io"); return sta; } @@ -545,10 +533,10 @@ __STATIC_FORCEINLINE uint32_t PIN_SWDIO_IN (void) { */ __STATIC_FORCEINLINE void PIN_SWDIO_OUT (uint32_t bit) { if(bit & 0x01) { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_TMS_NUM, true); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS), true); } else { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_TMS_NUM, false); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS), false); } __asm volatile("fence io, io"); } @@ -560,8 +548,8 @@ called prior \ref PIN_SWDIO_OUT function calls. __STATIC_FORCEINLINE void PIN_SWDIO_OUT_ENABLE (void) { HPM_IOC->PAD[PIN_TMS].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); /* as gpio*/ HPM_IOC->PAD[PIN_TMS].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1); - gpiom_configure_pin_control_setting(PIN_TMS_NUM); - gpio_set_pin_output(PIN_GPIO, PIN_PORT, PIN_TMS_NUM); + gpiom_configure_pin_control_setting(PIN_TMS); + gpio_set_pin_output(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); } /** SWDIO I/O pin: Switch to Input mode (used in SWD mode only). @@ -571,9 +559,9 @@ called prior \ref PIN_SWDIO_IN function calls. __STATIC_FORCEINLINE void PIN_SWDIO_OUT_DISABLE (void) { HPM_IOC->PAD[PIN_TMS].PAD_CTL = IOC_PAD_PAD_CTL_PRS_SET(2); HPM_IOC->PAD[PIN_TMS].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); - gpio_set_pin_input(PIN_GPIO, PIN_PORT, PIN_TMS_NUM); - gpio_disable_pin_interrupt(PIN_GPIO, GPIO_IE_GPIOA, PIN_TMS_NUM); - gpiom_set_pin_controller(HPM_GPIOM, GPIOM_ASSIGN_GPIOA, PIN_TMS_NUM, gpiom_soc_gpio0); + gpio_set_pin_input(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); + gpio_disable_pin_interrupt(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS)); + gpiom_set_pin_controller(HPM_GPIOM, GPIO_GET_PORT_INDEX(PIN_TMS), GPIO_GET_PIN_INDEX(PIN_TMS), gpiom_soc_gpio0); } @@ -583,7 +571,7 @@ __STATIC_FORCEINLINE void PIN_SWDIO_OUT_DISABLE (void) { \return Current status of the TDI DAP hardware I/O pin. */ __STATIC_FORCEINLINE uint32_t PIN_TDI_IN (void) { - uint32_t sta = gpio_read_pin(PIN_GPIO, PIN_PORT, PIN_TDI_NUM); + uint32_t sta = gpio_read_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDI), GPIO_GET_PIN_INDEX(PIN_TDI)); __asm volatile("fence io, io"); return sta; } @@ -594,10 +582,10 @@ __STATIC_FORCEINLINE uint32_t PIN_TDI_IN (void) { __STATIC_FORCEINLINE void PIN_TDI_OUT (uint32_t bit) { if(bit & 0x01) { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_TDI_NUM, true); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDI), GPIO_GET_PIN_INDEX(PIN_TDI), true); } else { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_TDI_NUM, false); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDI), GPIO_GET_PIN_INDEX(PIN_TDI), false); } __asm volatile("fence io, io"); } @@ -609,7 +597,7 @@ __STATIC_FORCEINLINE void PIN_TDI_OUT (uint32_t bit) { \return Current status of the TDO DAP hardware I/O pin. */ __STATIC_FORCEINLINE uint32_t PIN_TDO_IN (void) { - uint32_t sta = gpio_read_pin(PIN_GPIO, PIN_PORT, PIN_TDO_NUM); + uint32_t sta = gpio_read_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_TDO), GPIO_GET_PIN_INDEX(PIN_TDO)); __asm volatile("fence io, io"); return sta; } @@ -621,7 +609,7 @@ __STATIC_FORCEINLINE uint32_t PIN_TDO_IN (void) { \return Current status of the nTRST DAP hardware I/O pin. */ __STATIC_FORCEINLINE uint32_t PIN_nTRST_IN (void) { - uint32_t sta = gpio_read_pin(PIN_GPIO, PIN_PORT, PIN_nRESET_NUM); + uint32_t sta = gpio_read_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TRST), GPIO_GET_PIN_INDEX(PIN_JTAG_TRST)); __asm volatile("fence io, io"); return sta; } @@ -633,10 +621,10 @@ __STATIC_FORCEINLINE uint32_t PIN_nTRST_IN (void) { */ __STATIC_FORCEINLINE void PIN_nTRST_OUT (uint32_t bit) { if(bit & 0x01) { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_nRESET_NUM, true); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TRST), GPIO_GET_PIN_INDEX(PIN_JTAG_TRST), true); } else { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_nRESET_NUM, false); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TRST), GPIO_GET_PIN_INDEX(PIN_JTAG_TRST), false); } __asm volatile("fence io, io"); } @@ -647,7 +635,7 @@ __STATIC_FORCEINLINE void PIN_nTRST_OUT (uint32_t bit) { \return Current status of the nRESET DAP hardware I/O pin. */ __STATIC_FORCEINLINE uint32_t PIN_nRESET_IN (void) { - uint32_t sta = gpio_read_pin(PIN_GPIO, PIN_PORT, PIN_nRESET_NUM); + uint32_t sta = gpio_read_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_SRST), GPIO_GET_PIN_INDEX(PIN_SRST)); __asm volatile("fence io, io"); return sta; } @@ -659,10 +647,10 @@ __STATIC_FORCEINLINE uint32_t PIN_nRESET_IN (void) { */ __STATIC_FORCEINLINE void PIN_nRESET_OUT (uint32_t bit) { if(bit & 0x01) { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_nRESET_NUM, true); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_SRST), GPIO_GET_PIN_INDEX(PIN_SRST), true); } else { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_nRESET_NUM, false); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_SRST), GPIO_GET_PIN_INDEX(PIN_SRST), false); } __asm volatile("fence io, io"); } @@ -690,10 +678,10 @@ It is recommended to provide the following LEDs for status indication: */ __STATIC_INLINE void LED_CONNECTED_OUT (uint32_t bit) { if(bit & 0x01) { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_LED_NUM, true); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_CONNECTED), GPIO_GET_PIN_INDEX(PIN_LED_RUNNING), true); } else { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_LED_NUM, false); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_CONNECTED), GPIO_GET_PIN_INDEX(PIN_LED_RUNNING), false); } __asm volatile("fence io, io"); } @@ -705,10 +693,10 @@ __STATIC_INLINE void LED_CONNECTED_OUT (uint32_t bit) { */ __STATIC_INLINE void LED_RUNNING_OUT (uint32_t bit) { if(bit & 0x01) { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_LED_NUM, true); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_RUNNING), GPIO_GET_PIN_INDEX(PIN_LED_RUNNING), true); } else { - gpio_write_pin(PIN_GPIO, PIN_PORT, PIN_LED_NUM, false); + gpio_write_pin(PIN_GPIO, GPIO_GET_PORT_INDEX(PIN_LED_RUNNING), GPIO_GET_PIN_INDEX(PIN_LED_RUNNING), false); } __asm volatile("fence io, io"); } diff --git a/projects/hpm5301evklite/JTAG_DP_SPI.c b/projects/hpm5301evklite/JTAG_DP_SPI.c new file mode 100644 index 0000000..1db7bb5 --- /dev/null +++ b/projects/hpm5301evklite/JTAG_DP_SPI.c @@ -0,0 +1,725 @@ +/* + * Copyright (c) 2013-2017 ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ---------------------------------------------------------------------- + * + * $Date: 1. December 2017 + * $Revision: V2.0.0 + * + * Project: CMSIS-DAP Source + * Title: JTAG_DP.c CMSIS-DAP JTAG DP I/O + * + *---------------------------------------------------------------------------*/ + +#include "DAP_config.h" +#include "DAP.h" +#include "board.h" +#include "hpm_spi_drv.h" +#include "hpm_clock_drv.h" +#ifdef HPMSOC_HAS_HPMSDK_DMAV2 +#include "hpm_dmav2_drv.h" +#else +#include "hpm_dma_drv.h" +#endif +#include "hpm_dmamux_drv.h" + +// JTAG Macros + +#define USE_GPIO_1_BIT 0 + +#define PIN_JTAG_GPIO HPM_FGPIO + +#define JTAG_SPI_DMA HPM_HDMA +#define JTAG_SPI_DMAMUX HPM_DMAMUX +#define JTAG_SPI_RX_DMA_REQ HPM_DMA_SRC_SPI2_RX +#define JTAG_SPI_TX_DMA_REQ HPM_DMA_SRC_SPI2_TX +#define JTAG_SPI_RX_DMA_CH 0 +#define JTAG_SPI_TX_DMA_CH 1 +#define JTAG_SPI_RX_DMAMUX_CH DMA_SOC_CHN_TO_DMAMUX_CHN(JTAG_SPI_DMA, JTAG_SPI_RX_DMA_CH) +#define JTAG_SPI_TX_DMAMUX_CH DMA_SOC_CHN_TO_DMAMUX_CHN(JTAG_SPI_DMA, JTAG_SPI_TX_DMA_CH) +#define JTAG_SPI_SCLK_FREQ (20000000UL) + +#define PIN_SINGLE_SPI_JTAG_TMS IOC_PAD_PA29 +#define PIN_JTAG_TCK IOC_PAD_PB11 +#define PIN_JTAG_TDO IOC_PAD_PB12 +#define PIN_JTAG_TDI IOC_PAD_PB13 + +#define PIN_JTAG_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) + +static void jtag_spi_sequece (uint32_t info, const uint8_t *tdi, uint8_t *tdo); +static void jtag_spi_ir_fast(uint32_t ir, uint16_t ir_before, uint8_t ir_length, uint16_t ir_after); +static uint8_t jtag_spi_transfer_fast(uint32_t request, uint32_t *data, uint8_t index_count, uint8_t index, uint8_t idle_cycles); +static uint32_t jtag_spi_read_idcode(uint8_t index); +static void jtag_spi_write_abort(uint32_t data, uint8_t index_count, uint8_t index); +static void jtag_emulation_init(void); + +#if (DAP_JTAG != 0) + + +void PORT_JTAG_SETUP(void) +{ + clock_add_to_group(JTAG_SPI_BASE_CLOCK_NAME, 0); + clock_set_source_divider(JTAG_SPI_BASE_CLOCK_NAME, clk_src_pll1_clk0, 10U); /* 80MHz */ + HPM_IOC->PAD[IOC_PAD_PB10].FUNC_CTL = IOC_PB10_FUNC_CTL_GPIO_B_10; + HPM_IOC->PAD[PIN_JTAG_TCK].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(5) | IOC_PAD_FUNC_CTL_LOOP_BACK_SET(1); /* as spi sck*/ + HPM_IOC->PAD[PIN_JTAG_TDO].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(5); /* as spi mosi */ + HPM_IOC->PAD[PIN_JTAG_TDI].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(5); /** as spi miso */ + HPM_IOC->PAD[PIN_SINGLE_SPI_JTAG_TMS].FUNC_CTL = IOC_PA29_FUNC_CTL_GPIO_A_29; + HPM_IOC->PAD[IOC_PAD_PB10].PAD_CTL = IOC_PAD_PAD_CTL_SR_MASK | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_JTAG_TCK].PAD_CTL = IOC_PAD_PAD_CTL_SR_MASK | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_JTAG_TDO].PAD_CTL = IOC_PAD_PAD_CTL_SR_MASK | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_JTAG_TDI].PAD_CTL = IOC_PAD_PAD_CTL_SR_MASK | IOC_PAD_PAD_CTL_SPD_SET(3) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(0); + HPM_IOC->PAD[PIN_SINGLE_SPI_JTAG_TMS].PAD_CTL = IOC_PAD_PAD_CTL_SR_MASK | IOC_PAD_PAD_CTL_SPD_SET(3); + gpiom_configure_pin_control_setting(PIN_SINGLE_SPI_JTAG_TMS); + gpio_set_pin_output(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS)); +#if defined(USE_GPIO_1_BIT) && (USE_GPIO_1_BIT == 1) + gpiom_configure_pin_control_setting(PIN_JTAG_TCK); + gpiom_configure_pin_control_setting(PIN_JTAG_TDO); + gpiom_configure_pin_control_setting(PIN_JTAG_TDI); + gpiom_configure_pin_control_setting(IOC_PAD_PB10); + gpio_set_pin_output(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(IOC_PAD_PB10), GPIO_GET_PIN_INDEX(IOC_PAD_PB10)); + gpio_set_pin_output(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TCK), GPIO_GET_PIN_INDEX(PIN_JTAG_TCK)); + gpio_set_pin_output(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TDI), GPIO_GET_PIN_INDEX(PIN_JTAG_TDI)); + gpio_set_pin_input(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TDO), GPIO_GET_PIN_INDEX(PIN_JTAG_TDO)); +#endif + jtag_emulation_init(); +} + +// Generate JTAG Sequence +// info: sequence information +// tdi: pointer to TDI generated data +// tdo: pointer to TDO captured data +// return: none +void JTAG_Sequence (uint32_t info, const uint8_t *tdi, uint8_t *tdo) { + jtag_spi_sequece(info, tdi, tdo); +} + +static void JTAG_IR_Fast(uint32_t ir) +{ + uint16_t ir_before, ir_after; + uint8_t ir_length; + ir_before = DAP_Data.jtag_dev.ir_before[DAP_Data.jtag_dev.index]; + ir_length = DAP_Data.jtag_dev.ir_length[DAP_Data.jtag_dev.index]; + ir_after = DAP_Data.jtag_dev.ir_after[DAP_Data.jtag_dev.index]; + jtag_spi_ir_fast(ir, ir_before, ir_length, ir_after); +} + +static void JTAG_IR_Slow(uint32_t ir) +{ + JTAG_IR_Fast(ir); +} + +static uint8_t JTAG_TransferFast(uint32_t request, uint32_t *data) +{ + uint8_t index_count, index, idle_cycles; + index_count = DAP_Data.jtag_dev.count; + index = DAP_Data.jtag_dev.index; + idle_cycles = DAP_Data.transfer.idle_cycles; + return jtag_spi_transfer_fast(request, data, index_count, index, idle_cycles); +} + +static uint8_t JTAG_TransferSlow(uint32_t request, uint32_t *data) +{ + return JTAG_TransferFast(request, data); +} + +// JTAG Read IDCODE register +// return: value read +uint32_t JTAG_ReadIDCode (void) { + uint8_t index = DAP_Data.jtag_dev.index; + return jtag_spi_read_idcode(index); +} + + +// JTAG Write ABORT register +// data: value to write +// return: none +void JTAG_WriteAbort (uint32_t data) { + uint8_t index_count, index; + index_count = DAP_Data.jtag_dev.count; + index = DAP_Data.jtag_dev.index; + jtag_spi_write_abort(data, index_count, index); +} + + +// JTAG Set IR +// ir: IR value +// return: none +void JTAG_IR (uint32_t ir) { + if (DAP_Data.fast_clock) { + JTAG_IR_Fast(ir); + } else { + JTAG_IR_Slow(ir); + } +} + + +// JTAG Transfer I/O +// request: A[3:2] RnW APnDP +// data: DATA[31:0] +// return: ACK[2:0] +uint8_t JTAG_Transfer(uint32_t request, uint32_t *data) { + if (DAP_Data.fast_clock) { + return JTAG_TransferFast(request, data); + } else { + return JTAG_TransferSlow(request, data); + } +} + + +static void jtag_reset(void) +{ + JTAG_SPI_BASE->CTRL |= SPI_CTRL_RXFIFORST_MASK | SPI_CTRL_TXFIFORST_MASK; + while (JTAG_SPI_BASE->STATUS & (SPI_CTRL_RXFIFORST_MASK | SPI_CTRL_TXFIFORST_MASK)) { + }; +} + +static void jtag_less_than_32bit_size_for_tck(uint16_t bit_size, uint32_t dummy) +{ + if (bit_size == 0) + return; + jtag_reset(); + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_only); + spi_set_data_bits(JTAG_SPI_BASE, bit_size); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = dummy; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; +} + +static void jtag_more_than_32bit_size_for_tck(uint16_t bit_size, uint32_t dummy) +{ + uint32_t n_len_in_byte = 0; + uint32_t n_len_remain_bit = 0; + uint32_t i; + + if (bit_size == 0) { + return; + } + n_len_in_byte = bit_size / 32; + n_len_remain_bit = bit_size % 32; + if (n_len_in_byte) { + jtag_reset(); + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_only); + spi_set_data_bits(JTAG_SPI_BASE, 32); + spi_set_read_data_count(JTAG_SPI_BASE, n_len_in_byte); + spi_set_write_data_count(JTAG_SPI_BASE, n_len_in_byte); + for (i = 0; i < n_len_in_byte; i++) { + JTAG_SPI_BASE->DATA = dummy; + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_TXFULL_MASK) == SPI_STATUS_TXFULL_MASK) { + }; + } + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + if (n_len_remain_bit) { + jtag_less_than_32bit_size_for_tck(n_len_remain_bit, dummy); + } +} + +// Generate JTAG Sequence +// info: sequence information +// tdi: pointer to TDI generated data +// tdo: pointer to TDO captured data +// return: none +static void jtag_spi_sequece (uint32_t info, const uint8_t *tdi, uint8_t *tdo) +{ + uint32_t n; + uint32_t n_len_in_byte = 0; + uint32_t n_len_remain_bit = 0; + uint32_t rx_index = 0, tx_index = 0; + bool is_tdo = false; + uint8_t txfifo_size = spi_get_tx_fifo_size(JTAG_SPI_BASE); + uint8_t txfifo_valid_size = 0, rxfifo_valid_size = 0, j = 0; + n = info & JTAG_SEQUENCE_TCK; + if (info & JTAG_SEQUENCE_TMS) { + //printf("1s: %d %d\n", n_len_in_byte, n_len_remain_bit); + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + } else { + //printf("0s: %d %d\n", n_len_in_byte, n_len_remain_bit); + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), false); + } + if (n == 1) { +#if defined(USE_GPIO_1_BIT) && (USE_GPIO_1_BIT == 1) + + HPM_IOC->PAD[PIN_JTAG_TCK].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + HPM_IOC->PAD[PIN_JTAG_TDI].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0); + PIN_JTAG_DELAY(); + if((*tdi) & 0x01) { + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TDI), GPIO_GET_PIN_INDEX(PIN_JTAG_TDI), true); + } + else { + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TDI), GPIO_GET_PIN_INDEX(PIN_JTAG_TDI), false); + } + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TCK), GPIO_GET_PIN_INDEX(PIN_JTAG_TCK), true); + // PIN_JTAG_DELAY(); + if (info & JTAG_SEQUENCE_TDO) { + (*tdo) = gpio_read_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TDO), GPIO_GET_PIN_INDEX(PIN_JTAG_TDO)); + } + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_JTAG_TCK), GPIO_GET_PIN_INDEX(PIN_JTAG_TCK), false); + // PIN_JTAG_DELAY(); + HPM_IOC->PAD[PIN_JTAG_TCK].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(5) | IOC_PAD_FUNC_CTL_LOOP_BACK_SET(1); + HPM_IOC->PAD[PIN_JTAG_TDO].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(5); + HPM_IOC->PAD[PIN_JTAG_TDI].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(5); + return; +#else + switch ((*tdi) & 0x01) + { + case 1: + JTAG_SPI_BASE->DIRECTIO = 0x1040400; + JTAG_SPI_BASE->DIRECTIO = 0x1060600; /* diretion = 1, slck_oe = 1, mosi_oe = 1, sclk_o = 1, mosi_o = 1 */ + if (is_tdo == true) { + *(uint8_t *)(tdo) = (uint8_t)(JTAG_SPI_BASE->DIRECTIO >> 3); + } + JTAG_SPI_BASE->DIRECTIO = 0x1060400; /* diretion = 1, slck_oe = 1, mosi_oe = 1, sclk_o = 0, mosi_o = 1*/ + break; + case 0: + JTAG_SPI_BASE->DIRECTIO = 0x1040000; + JTAG_SPI_BASE->DIRECTIO = 0x1060200; /* diretion = 1, slck_oe = 1, mosi_oe = 1, sclk_o = 1, mosi_o = 0 */ + if (is_tdo == true) { + *(uint8_t *)(tdo) = (uint8_t)(JTAG_SPI_BASE->DIRECTIO >> 3); + } + JTAG_SPI_BASE->DIRECTIO = 0x1060000; /* diretion = 1, slck_oe = 1, mosi_oe = 1, sclk_o = 0, mosi_o = 0 */ + default: + break; + } + JTAG_SPI_BASE->DIRECTIO = 0; /* diretion = 0 */ + return; +#endif + } + + jtag_reset(); + if (info & JTAG_SEQUENCE_TDO) { + is_tdo = true; + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_read_together); + } else { + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_only); + } + if (n == 0U) { + n = 64U; + } + n_len_in_byte = n / 8; + n_len_remain_bit = n % 8; + + if (n_len_in_byte) { + spi_set_data_bits(JTAG_SPI_BASE, 8); + spi_set_read_data_count(JTAG_SPI_BASE, n_len_in_byte); + spi_set_write_data_count(JTAG_SPI_BASE, n_len_in_byte); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + if (is_tdo == false) { + rx_index = n_len_in_byte; + } + while ((rx_index < n_len_in_byte) || (tx_index < n_len_in_byte)) { + if (tx_index < n_len_in_byte) { + txfifo_valid_size = spi_get_tx_fifo_valid_data_size(JTAG_SPI_BASE); + if ((txfifo_size - txfifo_valid_size) > 0) { + for (j = 0; j < (txfifo_size - txfifo_valid_size); j++) { + if (tx_index >= n_len_in_byte) { + break; + } + JTAG_SPI_BASE->DATA = *tdi; + tdi++; + tx_index++; + } + } + } + if (rx_index < n_len_in_byte) { + rxfifo_valid_size = spi_get_rx_fifo_valid_data_size(JTAG_SPI_BASE); + if (rxfifo_valid_size > 0) { + for (j = 0; j < rxfifo_valid_size; j++) { + if (rx_index >= n_len_in_byte) { + break; + } + *tdo = JTAG_SPI_BASE->DATA; + tdo++; + rx_index++; + } + } + } + } + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + if (n_len_remain_bit) { + spi_set_data_bits(JTAG_SPI_BASE, n_len_remain_bit); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = *(uint8_t *)(tdi); + if (is_tdo == true) { + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + *(uint8_t *)(tdo) = JTAG_SPI_BASE->DATA; + } + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } +} + +static void jtag_ir(uint32_t ir, uint8_t ir_bit_size) +{ + uint8_t tmp_bits = 0; + tmp_bits = (ir_bit_size > 32) ? 32 : ir_bit_size; + jtag_less_than_32bit_size_for_tck(tmp_bits, ir); + ir_bit_size -= tmp_bits; + if (ir_bit_size) { + jtag_more_than_32bit_size_for_tck(ir_bit_size, 0x0); + } +} + +static void jtag_spi_ir_fast(uint32_t ir, uint16_t ir_before, uint8_t ir_length, uint16_t ir_after) +{ + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_only); + /* Select-DR-Scan and Select-IR-Scan */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(2, 0); + /* Capture-IR and Shift-IR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), false); + jtag_less_than_32bit_size_for_tck(2, 0); + if (ir_before) { + if (ir_before > 32) { + jtag_more_than_32bit_size_for_tck(ir_before, 0xFFFFFFFF); /* Bypass before data */ + } else { + jtag_less_than_32bit_size_for_tck(ir_before, 0xFFFFFFFF); + } + } + if (ir_length) { + jtag_ir(ir, ir_length - 1); /* Set IR bits (except last) */ + ir >>= (ir_length - 2); + } + if (ir_after) { + /* Set last IR bit */ + jtag_less_than_32bit_size_for_tck(1, ir); + ir_after -= 1; + if (ir_after > 32) { + jtag_more_than_32bit_size_for_tck(ir_after, 0xFFFFFFFF); /* Bypass after data */ + } else { + jtag_less_than_32bit_size_for_tck(ir_after, 0xFFFFFFFF); + } + /* Bypass & Exit1-IR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0xFFFFFFFF); + } else { + /* Set last IR bit & Exit1-IR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, ir); + } + /* Update-IR */ + jtag_less_than_32bit_size_for_tck(1, 0); + /* Idle */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), false); + jtag_less_than_32bit_size_for_tck(1, 0xFFFFFFFF); +} + +static uint8_t jtag_spi_transfer_fast(uint32_t request, uint32_t *data, uint8_t index_count, uint8_t index, uint8_t idle_cycles) +{ + uint32_t ack = 0; + uint32_t bit = 0; + uint32_t n = 0; + uint32_t val; + /* Select-DR-Scan */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0); + /* Capture-DR & Shift-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), false); + jtag_less_than_32bit_size_for_tck(2, 0); + /* Bypass before data */ + if (index) { + if (index > 32) { + jtag_more_than_32bit_size_for_tck(index, 0xFFFFFFFF); /* Bypass before data */ + } else { + jtag_less_than_32bit_size_for_tck(index, 0xFFFFFFFF); + } + } + jtag_reset(); + /* Set RnW A2 A3, Get ACK.0 ACK.1 ACK.2*/ + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_read_together); + spi_set_data_bits(JTAG_SPI_BASE, 3); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = request; + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + bit = JTAG_SPI_BASE->DATA; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + ack = ((bit & 0x01) << 1) | ((bit & 0x02) >> 0) | (bit & 0x04); + if (ack != DAP_TRANSFER_OK) { + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0xFFFFFFFF); + goto exit; + } + jtag_reset(); + if (request & DAP_TRANSFER_RnW) { + /* Read Transfer */ + val = 0; + /* Get D0..D30 */ + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_read_only); + spi_set_data_bits(JTAG_SPI_BASE, 32); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + bit = JTAG_SPI_BASE->DATA; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + val = bit; + n = index_count - index - 1U; + bit = 0; + jtag_reset(); + spi_set_data_bits(JTAG_SPI_BASE, 1); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + if (n) { + /* Get D31 */ + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + bit = JTAG_SPI_BASE->DATA; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + /* Bypass after data */ + jtag_less_than_32bit_size_for_tck(n - 1, 0xFFFFFFFF); + /* Bypass & Exit1-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0xFFFFFFFF); + } else { + /* Get D31 & Exit1-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + bit = JTAG_SPI_BASE->DATA; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + val |= bit << 31; + if (data) { + *data = val; + } + } else { + /* Write Transfer */ + val = (*data); + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_only); + /* Set D0..D30 */ + jtag_less_than_32bit_size_for_tck(31, val); + n = index_count - index - 1U; + val >>= 31; + spi_set_data_bits(JTAG_SPI_BASE, 1); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + if (n) { + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = val; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + /* Bypass after data */ + jtag_less_than_32bit_size_for_tck(n - 1, 0); + /* Bypass & Exit1-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0); + } else { + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = val; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + } +exit: + /* Update-DR */ + jtag_less_than_32bit_size_for_tck(1, 0); + board_write_spi_cs(BOARD_SPI_CS_PIN, false); + /* Idle */ + jtag_less_than_32bit_size_for_tck(1, 0xFFFFFFFF); + + /* Capture Timestamp */ + if (request & DAP_TRANSFER_TIMESTAMP) { + // DAP_Data.timestamp = TIMESTAMP_GET(); + } + + /* Idle cycles */ + jtag_less_than_32bit_size_for_tck(idle_cycles, 0xFFFFFFFF); + return ((uint8_t)ack); +} + +// JTAG Read IDCODE register +// return: value read +static uint32_t jtag_spi_read_idcode (uint8_t index) +{ + uint32_t bit; + uint32_t val; + /* Select-DR-Scan */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0); + + /* Capture-DR & Shift-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), false); + jtag_less_than_32bit_size_for_tck(2, 0); + + /* Bypass before data */ + jtag_more_than_32bit_size_for_tck(index, 0xFFFFFFFF); + + val = 0U; + /* Get D0..D30 */ + jtag_reset(); + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_read_only); + spi_set_data_bits(JTAG_SPI_BASE, 32); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + bit = JTAG_SPI_BASE->DATA; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + val = bit; + bit = 0; + jtag_reset(); + spi_set_data_bits(JTAG_SPI_BASE, 1); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + /* Get D31 & Exit1-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + while ((JTAG_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + }; + bit = JTAG_SPI_BASE->DATA; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + val |= bit << 31; + /* Update-DR */ + jtag_less_than_32bit_size_for_tck(1, 0); + board_write_spi_cs(BOARD_SPI_CS_PIN, false); + /* Idle */ + jtag_less_than_32bit_size_for_tck(1, 0xFFFFFFFF); + return (val); +} + +// JTAG Write ABORT register +// data: value to write +// return: none +static void jtag_spi_write_abort (uint32_t data, uint8_t index_count, uint8_t index) +{ + uint32_t n = 0; + /* Select-DR-Scan */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0); + + /* Capture-DR & Shift-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), false); + jtag_less_than_32bit_size_for_tck(2, 0); + + /* Bypass before data */ + jtag_more_than_32bit_size_for_tck(index, 0xFFFFFFFF); + + /* Set RnW=0 (Write) & Set A2 = 0 & Set A3 = 0 */ + jtag_reset(); + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_only); + spi_set_data_bits(JTAG_SPI_BASE, 3); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = n; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + + /* Set D0..D30 */ + jtag_less_than_32bit_size_for_tck(31, data); + n = index_count - index - 1U; + /* Set D31 */ + data >>= 31; + jtag_reset(); + spi_set_transfer_mode(JTAG_SPI_BASE, spi_trans_write_only); + spi_set_data_bits(JTAG_SPI_BASE, 1); + spi_set_read_data_count(JTAG_SPI_BASE, 1); + spi_set_write_data_count(JTAG_SPI_BASE, 1); + if (n) { + /* Bypass after data */ + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = data; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + /* Bypass after data */ + jtag_less_than_32bit_size_for_tck(n - 1, 0); + /* Bypass & Exit1-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + jtag_less_than_32bit_size_for_tck(1, 0); + } else { + /* Set D31 & Exit1-DR */ + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), true); + JTAG_SPI_BASE->CMD = 0xFF; /* Write a dummy byte */ + JTAG_SPI_BASE->DATA = data; + while (JTAG_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } + /* Update-DR */ + jtag_less_than_32bit_size_for_tck(1, 0); + gpio_write_pin(PIN_JTAG_GPIO, GPIO_GET_PORT_INDEX(PIN_SINGLE_SPI_JTAG_TMS), GPIO_GET_PIN_INDEX(PIN_SINGLE_SPI_JTAG_TMS), false); + /* Idle */ + jtag_less_than_32bit_size_for_tck(1, 0xFFFFFFFF); +} + +static void jtag_emulation_init(void) +{ + spi_timing_config_t timing_config = {0}; + spi_format_config_t format_config = {0}; + spi_control_config_t control_config = {0}; + uint32_t spi_clcok; + uint32_t pll_clk = 0, div = 0; + /* set SPI sclk frequency for master */ + spi_clcok = board_init_spi_clock(JTAG_SPI_BASE); + spi_master_get_default_timing_config(&timing_config); + timing_config.master_config.cs2sclk = spi_cs2sclk_half_sclk_1; + timing_config.master_config.csht = spi_csht_half_sclk_1; + timing_config.master_config.clk_src_freq_in_hz = spi_clcok; + timing_config.master_config.sclk_freq_in_hz = JTAG_SPI_SCLK_FREQ; + if (status_success != spi_master_timing_init(JTAG_SPI_BASE, &timing_config)) { + spi_master_set_sclk_div(JTAG_SPI_BASE, 0xFF); + pll_clk = get_frequency_for_source(clock_source_pll1_clk0); + div = pll_clk / JTAG_SPI_SCLK_FREQ; + clock_set_source_divider(JTAG_SPI_BASE_CLOCK_NAME, clk_src_pll1_clk0, div); + } + + /* set SPI format config for master */ + spi_master_get_default_format_config(&format_config); + format_config.master_config.addr_len_in_bytes = 1U; + format_config.common_config.data_len_in_bits = 1; + format_config.common_config.data_merge = false; + format_config.common_config.mosi_bidir = false; + format_config.common_config.lsb = true; + format_config.common_config.mode = spi_master_mode; + format_config.common_config.cpol = spi_sclk_low_idle; + format_config.common_config.cpha = spi_sclk_sampling_odd_clk_edges; + spi_format_init(JTAG_SPI_BASE, &format_config); + + /* set SPI control config for master */ + spi_master_get_default_control_config(&control_config); + control_config.master_config.cmd_enable = false; + control_config.master_config.addr_enable = false; + control_config.master_config.addr_phase_fmt = spi_address_phase_format_single_io_mode; + control_config.common_config.trans_mode = spi_trans_write_read_together; + control_config.common_config.rx_dma_enable = false; + control_config.common_config.tx_dma_enable = false; + spi_control_init(JTAG_SPI_BASE, &control_config, 1, 1); +} + +#endif /* (DAP_JTAG != 0) */ diff --git a/projects/hpm5301evklite/SW_DP_SPI.c b/projects/hpm5301evklite/SW_DP_SPI.c index 89e0971..3eb741d 100644 --- a/projects/hpm5301evklite/SW_DP_SPI.c +++ b/projects/hpm5301evklite/SW_DP_SPI.c @@ -18,9 +18,7 @@ #include "DAP_config.h" #include "DAP.h" -#define SWD_SPI_BASE BOARD_APP_SPI_BASE -#define SWD_SPI_BASE_CLOCK_NAME BOARD_APP_SPI_CLK_NAME -#define SWD_SPI_SCLK_FREQ (15000000UL) +#define SWD_SPI_SCLK_FREQ (20000000UL) #define SWD_SPI_DMA BOARD_APP_HDMA #define SWD_SPI_DMAMUX BOARD_APP_DMAMUX @@ -39,6 +37,8 @@ static void swd_emulation_init(void); void PORT_SWD_SETUP(void) { board_init_spi_pins(SWD_SPI_BASE); + HPM_IOC->PAD[PIN_TCK].PAD_CTL = IOC_PAD_PAD_CTL_SR_MASK | IOC_PAD_PAD_CTL_SPD_SET(3); + HPM_IOC->PAD[PIN_TMS].PAD_CTL = IOC_PAD_PAD_CTL_SR_MASK | IOC_PAD_PAD_CTL_SPD_SET(3) | IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(0); swd_emulation_init(); } @@ -183,16 +183,11 @@ uint8_t SWD_Transfer(uint32_t request, uint32_t *data) for (i = 0; i < 32; i++) { parity += (((*data) >> i) & 0x01); } - spi_set_data_bits(SWD_SPI_BASE, 8 + DAP_Data.swd_conf.turnaround); - if (DAP_Data.swd_conf.turnaround > 0) { - host_data <<= 1; - } + spi_set_data_bits(SWD_SPI_BASE, 8); ack_width = 5; } SWD_SPI_BASE->CMD = 0xFF; - for (uint8_t i = 0; i < DAP_Data.swd_conf.turnaround; i++) { - SWD_SPI_BASE->DATA = host_data; - } + SWD_SPI_BASE->DATA = host_data; while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { }; spi_set_transfer_mode(SWD_SPI_BASE, spi_trans_read_only); @@ -216,13 +211,25 @@ uint8_t SWD_Transfer(uint32_t request, uint32_t *data) while ((SWD_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { }; dummy = SWD_SPI_BASE->DATA; - spi_set_data_bits(SWD_SPI_BASE, 1 + DAP_Data.swd_conf.turnaround); + spi_set_data_bits(SWD_SPI_BASE, 1); SWD_SPI_BASE->CMD = 0xFF; while ((SWD_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { }; parity = (SWD_SPI_BASE->DATA) & 0x01; while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { }; + /* Turnaround */ + if (DAP_Data.swd_conf.turnaround > 0) { + SWD_SPI_BASE->TRANSCTRL = 0x01000000; /* only write mode*/ + SWD_SPI_BASE->TRANSFMT = 0x0018; /* datalen = 1bit, mosibidir = 1, lsb=1 */ + spi_set_write_data_count(SWD_SPI_BASE, DAP_Data.swd_conf.turnaround); + SWD_SPI_BASE->CMD = 0xFF; + SWD_SPI_BASE->DATA = 0; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_TXFULL_MASK) == SPI_STATUS_TXFULL_MASK) { + }; + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } for (i = 0; i < 32U; i++) { calc_parity += ((dummy >> i) & 0x01); } @@ -239,7 +246,7 @@ uint8_t SWD_Transfer(uint32_t request, uint32_t *data) SWD_SPI_BASE->DATA = (*data); while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { }; - spi_set_data_bits(SWD_SPI_BASE, 1 + DAP_Data.transfer.idle_cycles); + spi_set_data_bits(SWD_SPI_BASE, 1); SWD_SPI_BASE->CMD = 0xFF; SWD_SPI_BASE->DATA = parity; while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { @@ -248,6 +255,17 @@ uint8_t SWD_Transfer(uint32_t request, uint32_t *data) if (request & DAP_TRANSFER_TIMESTAMP) { DAP_Data.timestamp = TIMESTAMP_GET(); } + if (DAP_Data.transfer.idle_cycles > 0) { + SWD_SPI_BASE->TRANSCTRL = 0x01000000; /* only write mode*/ + SWD_SPI_BASE->TRANSFMT = 0x0018; /* datalen = 1bit, mosibidir = 1, lsb=1 */ + spi_set_write_data_count(SWD_SPI_BASE, DAP_Data.transfer.idle_cycles); + SWD_SPI_BASE->CMD = 0xFF; + SWD_SPI_BASE->DATA = 0; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_TXFULL_MASK) == SPI_STATUS_TXFULL_MASK) { + }; + while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { + }; + } } return ack; } @@ -268,11 +286,13 @@ uint8_t SWD_Transfer(uint32_t request, uint32_t *data) } /* Turnaround */ if (DAP_Data.swd_conf.turnaround > 0) { + SWD_SPI_BASE->TRANSCTRL = 0x01000000; /* only write mode*/ + SWD_SPI_BASE->TRANSFMT = 0x0018; /* datalen = 1bit, mosibidir = 1, lsb=1 */ spi_set_write_data_count(SWD_SPI_BASE, DAP_Data.swd_conf.turnaround); SWD_SPI_BASE->CMD = 0xFF; - while ((SWD_SPI_BASE->STATUS & SPI_STATUS_RXEMPTY_MASK) == SPI_STATUS_RXEMPTY_MASK) { + SWD_SPI_BASE->DATA = 0; + while ((SWD_SPI_BASE->STATUS & SPI_STATUS_TXFULL_MASK) == SPI_STATUS_TXFULL_MASK) { }; - parity = (SWD_SPI_BASE->DATA) & 0x01; while (SWD_SPI_BASE->STATUS & SPI_STATUS_SPIACTIVE_MASK) { }; } @@ -294,6 +314,7 @@ uint8_t SWD_Transfer(uint32_t request, uint32_t *data) } /* Protocol error */ spi_set_transfer_mode(SWD_SPI_BASE, spi_trans_write_only); + spi_set_data_bits(SWD_SPI_BASE, 1); spi_set_write_data_count(SWD_SPI_BASE, DAP_Data.swd_conf.turnaround + 32U + 1U); SWD_SPI_BASE->CMD = 0xFF; for (i = 0; i < DAP_Data.swd_conf.turnaround + 32U + 1U; i++) { @@ -350,22 +371,5 @@ static void swd_emulation_init(void) spi_control_init(SWD_SPI_BASE, &control_config, 1, 1); } -void set_swj_clock_frequency(uint32_t clock) -{ - uint8_t div, sclk_div; - if (clock >= 10000000) { - sclk_div = 0xFF; /* 80M*/ - div = 10; - } else if ((clock >= 1000000) && (clock < 10000000)) { - sclk_div = 0xFF; /* 50M*/ - div = 16; - } else { - sclk_div = 1; /* 15M*/ - div = 12; - } - spi_master_set_sclk_div(SWD_SPI_BASE, sclk_div); - clock_set_source_divider(SWD_SPI_BASE_CLOCK_NAME, clk_src_pll1_clk0, div); -} - diff --git a/projects/hpm5301evklite/dp_common.c b/projects/hpm5301evklite/dp_common.c new file mode 100644 index 0000000..cafc060 --- /dev/null +++ b/projects/hpm5301evklite/dp_common.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024 RCSN + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include "DAP_config.h" +#include "DAP.h" +#include "hpm_spi_drv.h" + +void set_swj_clock_frequency(uint32_t clock) +{ + uint8_t div, sclk_div; + uint32_t div_remainder; + uint32_t div_integer; + uint32_t clk_src_freq_in_hz, sclk_freq_in_hz; + sclk_freq_in_hz = clock; + SPI_Type *spi_base = NULL; + clock_name_t clock_name; + clk_src_freq_in_hz = clock_get_frequency(JTAG_SPI_BASE_CLOCK_NAME); + clk_src_t src_clock = clk_src_pll1_clk0; /* 800M */ + if (DAP_Data.debug_port == DAP_PORT_SWD) { + if (clock >= 10000000) { /* clock >= 10M */ + sclk_div = 0xFF; /* actual 80M*/ + div = 10; + } else if ((clock >= 5000000) && (clock < 10000000)) { /* 5M <= clock < 10M */ + sclk_div = 0xFF; /* actual 50M*/ + div = 16; + } else if ((clock >= 2000000) && (clock < 5000000)) { /* 2M <= clock < 5M */ + sclk_div = 1; /* actual 20M */ + div = 10; + } else if ((clock >= 1000000) && (clock < 2000000)) { /* 1M <= clock < 2M */ + sclk_div = 3; /* actual 10M */ + div = 10; + } else if ((clock >= 500000) && (clock < 1000000)) { /* 500K <= clock < 1M */ + sclk_div = 7; /* actual 5M */ + div = 10; + } else if ((clock >= 200000) && (clock < 500000)) { /* 200K <= clock < 500K */ + sclk_div = 19; /* actual 2M */ + div = 10; + } else { + sclk_div = 39; /* actual 1M */ + div = 10; + } + spi_base = SWD_SPI_BASE; + clock_name = SWD_SPI_BASE_CLOCK_NAME; + } else { + if (clock >= 40000000) { /* >= 40M*/ + sclk_div = 0xFF; + div = clock_get_frequency(clk_pll1clk0) / clock; + } else if ((clock >= 10000000) && (clock < 40000000)) { /* 10M <= clock < 40M */ + clock_set_source_divider(JTAG_SPI_BASE_CLOCK_NAME, src_clock, 10); + clk_src_freq_in_hz = clock_get_frequency(JTAG_SPI_BASE_CLOCK_NAME); + div_remainder = (clk_src_freq_in_hz % sclk_freq_in_hz); + div_integer = (clk_src_freq_in_hz / sclk_freq_in_hz); + if ((div_remainder != 0) || ((div_integer % 2) != 0)) { + sclk_div = 0; + clk_src_freq_in_hz = sclk_freq_in_hz * 2; + div = clock_get_frequency(clk_pll1clk0) / clk_src_freq_in_hz; + } else { + sclk_div = (div_integer / 2) - 1; + div = 10; + } + } else { /* < 10M */ + sclk_div = 3; + clk_src_freq_in_hz = sclk_freq_in_hz * 8; + div = clock_get_frequency(clk_pll1clk0) / clk_src_freq_in_hz; + } + spi_base = JTAG_SPI_BASE; + clock_name = JTAG_SPI_BASE_CLOCK_NAME; + } + + spi_master_set_sclk_div(spi_base, sclk_div); + clock_set_source_divider(clock_name, src_clock, div); +} +