From 3c9da497a15a580cafaa2653ba4ecd54c6884295 Mon Sep 17 00:00:00 2001 From: binggee Date: Tue, 2 Jun 2026 23:32:26 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BArv-debugger=E6=8F=90=E4=BE=9Bcmsis=20d?= =?UTF-8?q?ap-link=E7=9A=84=E7=A7=BB=E6=A4=8D=EF=BC=8C=E6=94=AF=E6=8C=81JT?= =?UTF-8?q?AG/SWD=EF=BC=8Copenocd=E5=92=8Ckeil5=E5=9C=A8win11=E5=9D=87?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=8F=AF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- firmware/app/daplink_bl702/CMSIS_DAP_v2.inf | 67 + firmware/app/daplink_bl702/CMakeLists.txt | 41 + .../app/daplink_bl702/daplink/cmsis-dap/DAP.c | 1853 +++++++++++++++++ .../app/daplink_bl702/daplink/cmsis-dap/DAP.h | 384 ++++ .../daplink/cmsis-dap/DAP_UART.c | 652 ++++++ .../daplink/cmsis-dap/DAP_queue.c | 96 + .../daplink/cmsis-dap/DAP_queue.h | 65 + .../daplink/cmsis-dap/DAP_vendor.c | 14 + .../daplink/cmsis-dap/Driver_USART.h | 57 + .../daplink_bl702/daplink/cmsis-dap/JTAG_DP.c | 370 ++++ .../app/daplink_bl702/daplink/cmsis-dap/SWO.c | 798 +++++++ .../daplink_bl702/daplink/cmsis-dap/SW_DP.c | 301 +++ .../daplink/cmsis-dap/dap_strings.h | 1 + .../cmsis-dap/daplink_vendor_commands.h | 39 + .../daplink/cmsis-dap/debug_ca.h | 147 ++ .../daplink/cmsis-dap/debug_cm.h | 169 ++ firmware/app/daplink_bl702/daplink/compiler.h | 71 + firmware/app/daplink_bl702/daplink/cortex_m.c | 27 + firmware/app/daplink_bl702/daplink/cortex_m.h | 59 + firmware/app/daplink_bl702/daplink/daplink.h | 11 + .../app/daplink_bl702/daplink/daplink_addr.h | 28 + .../daplink_bl702/daplink/daplink_defaults.h | 37 + firmware/app/daplink_bl702/daplink/error.c | 272 +++ firmware/app/daplink_bl702/daplink/error.h | 110 + firmware/app/daplink_bl702/daplink/info.c | 324 +++ firmware/app/daplink_bl702/daplink/info.h | 91 + firmware/app/daplink_bl702/daplink/util.c | 172 ++ firmware/app/daplink_bl702/daplink/util.h | 104 + .../app/daplink_bl702/daplink/validation.c | 96 + .../app/daplink_bl702/daplink/validation.h | 46 + .../app/daplink_bl702/hic_hal/DAP_config.h | 252 +++ .../app/daplink_bl702/hic_hal/IO_Config.h | 71 + .../daplink_bl702/hic_hal/cmsis_compiler.h | 78 + firmware/app/daplink_bl702/hic_hal/compiler.h | 14 + firmware/app/daplink_bl702/hic_hal/device.h | 20 + firmware/app/daplink_bl702/hic_hal/flash.c | 35 + .../app/daplink_bl702/hic_hal/flash_hal.h | 28 + firmware/app/daplink_bl702/hic_hal/gpio.c | 89 + firmware/app/daplink_bl702/hic_hal/gpio.h | 45 + firmware/app/daplink_bl702/hic_hal/read_uid.c | 51 + firmware/app/daplink_bl702/hic_hal/read_uid.h | 27 + firmware/app/daplink_bl702/hic_hal/rl_usb.h | 52 + firmware/app/daplink_bl702/hic_hal/sdk.c | 19 + firmware/app/daplink_bl702/hic_hal/sdk.h | 23 + .../daplink_bl702/hic_hal/swo_uart_bl702.c | 176 ++ firmware/app/daplink_bl702/hic_hal/uart.c | 74 + firmware/app/daplink_bl702/hic_hal/uart.h | 72 + .../app/daplink_bl702/hic_hal/usbd_BL702.c | 96 + firmware/app/daplink_bl702/main.c | 211 ++ .../app/daplink_bl702/rtos_adapt/cmsis_os2.h | 92 + .../daplink_bl702/rtos_adapt/cmsis_os2_port.c | 168 ++ .../app/daplink_bl702/usb/usb_descriptor.c | 189 ++ 52 files changed, 8384 insertions(+) create mode 100644 firmware/app/daplink_bl702/CMSIS_DAP_v2.inf create mode 100644 firmware/app/daplink_bl702/CMakeLists.txt create mode 100644 firmware/app/daplink_bl702/daplink/cmsis-dap/DAP.c create mode 100644 firmware/app/daplink_bl702/daplink/cmsis-dap/DAP.h create mode 100644 firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_UART.c create mode 100644 firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_queue.c create mode 100644 firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_queue.h create mode 100644 firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_vendor.c create mode 100644 firmware/app/daplink_bl702/daplink/cmsis-dap/Driver_USART.h create mode 100644 firmware/app/daplink_bl702/daplink/cmsis-dap/JTAG_DP.c create mode 100644 firmware/app/daplink_bl702/daplink/cmsis-dap/SWO.c create mode 100644 firmware/app/daplink_bl702/daplink/cmsis-dap/SW_DP.c create mode 100644 firmware/app/daplink_bl702/daplink/cmsis-dap/dap_strings.h create mode 100644 firmware/app/daplink_bl702/daplink/cmsis-dap/daplink_vendor_commands.h create mode 100644 firmware/app/daplink_bl702/daplink/cmsis-dap/debug_ca.h create mode 100644 firmware/app/daplink_bl702/daplink/cmsis-dap/debug_cm.h create mode 100644 firmware/app/daplink_bl702/daplink/compiler.h create mode 100644 firmware/app/daplink_bl702/daplink/cortex_m.c create mode 100644 firmware/app/daplink_bl702/daplink/cortex_m.h create mode 100644 firmware/app/daplink_bl702/daplink/daplink.h create mode 100644 firmware/app/daplink_bl702/daplink/daplink_addr.h create mode 100644 firmware/app/daplink_bl702/daplink/daplink_defaults.h create mode 100644 firmware/app/daplink_bl702/daplink/error.c create mode 100644 firmware/app/daplink_bl702/daplink/error.h create mode 100644 firmware/app/daplink_bl702/daplink/info.c create mode 100644 firmware/app/daplink_bl702/daplink/info.h create mode 100644 firmware/app/daplink_bl702/daplink/util.c create mode 100644 firmware/app/daplink_bl702/daplink/util.h create mode 100644 firmware/app/daplink_bl702/daplink/validation.c create mode 100644 firmware/app/daplink_bl702/daplink/validation.h create mode 100644 firmware/app/daplink_bl702/hic_hal/DAP_config.h create mode 100644 firmware/app/daplink_bl702/hic_hal/IO_Config.h create mode 100644 firmware/app/daplink_bl702/hic_hal/cmsis_compiler.h create mode 100644 firmware/app/daplink_bl702/hic_hal/compiler.h create mode 100644 firmware/app/daplink_bl702/hic_hal/device.h create mode 100644 firmware/app/daplink_bl702/hic_hal/flash.c create mode 100644 firmware/app/daplink_bl702/hic_hal/flash_hal.h create mode 100644 firmware/app/daplink_bl702/hic_hal/gpio.c create mode 100644 firmware/app/daplink_bl702/hic_hal/gpio.h create mode 100644 firmware/app/daplink_bl702/hic_hal/read_uid.c create mode 100644 firmware/app/daplink_bl702/hic_hal/read_uid.h create mode 100644 firmware/app/daplink_bl702/hic_hal/rl_usb.h create mode 100644 firmware/app/daplink_bl702/hic_hal/sdk.c create mode 100644 firmware/app/daplink_bl702/hic_hal/sdk.h create mode 100644 firmware/app/daplink_bl702/hic_hal/swo_uart_bl702.c create mode 100644 firmware/app/daplink_bl702/hic_hal/uart.c create mode 100644 firmware/app/daplink_bl702/hic_hal/uart.h create mode 100644 firmware/app/daplink_bl702/hic_hal/usbd_BL702.c create mode 100644 firmware/app/daplink_bl702/main.c create mode 100644 firmware/app/daplink_bl702/rtos_adapt/cmsis_os2.h create mode 100644 firmware/app/daplink_bl702/rtos_adapt/cmsis_os2_port.c create mode 100644 firmware/app/daplink_bl702/usb/usb_descriptor.c diff --git a/firmware/app/daplink_bl702/CMSIS_DAP_v2.inf b/firmware/app/daplink_bl702/CMSIS_DAP_v2.inf new file mode 100644 index 0000000..281baf0 --- /dev/null +++ b/firmware/app/daplink_bl702/CMSIS_DAP_v2.inf @@ -0,0 +1,67 @@ +; CMSIS-DAP v2 WinUSB Driver Installation File +; For DAPLink BL702 firmware: VID=0xC251 PID=0xF00A +; +; Usage: Right-click the "DAPLink CMSIS-DAP" device in Device Manager, +; select "Update Driver" → "Browse my computer" → point to this file. +; +; This sets the DeviceInterfaceGUID to {CDB3B5AD-293B-4663-AA36-1AAE46463776} +; which is required by Keil MDK to identify CMSIS-DAP v2 debug probes. + +[Version] +Signature = "$Windows NT$" +Class = USBDevice +ClassGUID = {88BAE032-5A81-49f0-BC3D-A4FF138216D6} +Provider = %ManufacturerName% +DriverVer = 04/13/2016, 1.0.0.0 +CatalogFile.NT = CMSIS_DAP_v2.cat +CatalogFile.NTarm = CMSIS_DAP_v2.cat +CatalogFile.NTarm64 = CMSIS_DAP_v2.cat + +; ========== Manufacturer/Models sections =========== + +[Manufacturer] +%ManufacturerName% = Devices, NTarm, NTarm64, NTamd64 + +[Devices.NTarm] +%DeviceName% = USB_Install, USB\VID_C251&PID_F00A + +[Devices.NTarm64] +%DeviceName% = USB_Install, USB\VID_C251&PID_F00A + +[Devices.NTamd64] +%DeviceName% = USB_Install, USB\VID_C251&PID_F00A + +; ========== Class definition =========== + +[ClassInstall32] +AddReg = ClassInstall_AddReg + +[ClassInstall_AddReg] +HKR,,,,%ClassName% +HKR,,NoInstallClass,,1 +HKR,,IconPath,0x10000,"%%SystemRoot%%\System32\setupapi.dll,-20" +HKR,,LowerLogoVersion,,5.2 + +; =================== Installation =================== + +[USB_Install] +Include = winusb.inf +Needs = WINUSB.NT + +[USB_Install.Services] +Include = winusb.inf +Needs = WINUSB.NT.Services + +[USB_Install.HW] +AddReg = Dev_AddReg + +[Dev_AddReg] +; Set CMSIS-DAP v2 Device Interface GUID for Keil MDK / debugger detection +HKR,,DeviceInterfaceGUIDs,0x10000,"{CDB3B5AD-293B-4663-AA36-1AAE46463776}" + +; =================== Strings =================== + +[Strings] +ClassName = "Universal Serial Bus devices" +ManufacturerName = "ARM Ltd" +DeviceName = "DAPLink CMSIS-DAP v2" diff --git a/firmware/app/daplink_bl702/CMakeLists.txt b/firmware/app/daplink_bl702/CMakeLists.txt new file mode 100644 index 0000000..4e65782 --- /dev/null +++ b/firmware/app/daplink_bl702/CMakeLists.txt @@ -0,0 +1,41 @@ +# DAPLink Interface Firmware for BL702 (Minimal CMSIS-DAP Build) +# Phase 1-2: HIC HAL + CMSIS-DAP protocol core only + +set(BSP_COMMON_DIR ${CMAKE_SOURCE_DIR}/bsp/bsp_common) + +set(TARGET_REQUIRED_LIBS usb_stack) + +set(TARGET_REQUIRED_PRIVATE_INCLUDE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/hic_hal + ${CMAKE_CURRENT_LIST_DIR}/daplink + ${CMAKE_CURRENT_LIST_DIR}/daplink/cmsis-dap + ${CMAKE_CURRENT_LIST_DIR}/rtos_adapt + ${CMAKE_CURRENT_LIST_DIR}/usb) + +set(TARGET_REQUIRED_SRCS + # BL702 USB Device Controller driver + ${BSP_COMMON_DIR}/usb/usb_dc.c + + # HIC HAL implementation + ${CMAKE_CURRENT_LIST_DIR}/hic_hal/gpio.c + ${CMAKE_CURRENT_LIST_DIR}/hic_hal/uart.c + ${CMAKE_CURRENT_LIST_DIR}/hic_hal/sdk.c + ${CMAKE_CURRENT_LIST_DIR}/hic_hal/flash.c + ${CMAKE_CURRENT_LIST_DIR}/hic_hal/read_uid.c + + # USB descriptor + ${CMAKE_CURRENT_LIST_DIR}/usb/usb_descriptor.c + + # DAPLink CMSIS-DAP protocol core (self-contained, minimal dependencies) + ${CMAKE_CURRENT_LIST_DIR}/daplink/cmsis-dap/DAP.c + ${CMAKE_CURRENT_LIST_DIR}/daplink/cmsis-dap/SW_DP.c + ${CMAKE_CURRENT_LIST_DIR}/daplink/cmsis-dap/JTAG_DP.c + ${CMAKE_CURRENT_LIST_DIR}/daplink/cmsis-dap/DAP_vendor.c) + +set(TARGET_REQUIRED_PRIVATE_OPTIONS + -DDAPLINK_IF=1) + +set(mains main.c) + +generate_bin() diff --git a/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP.c b/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP.c new file mode 100644 index 0000000..03dbec4 --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP.c @@ -0,0 +1,1853 @@ +/* + * Copyright (c) 2013-2021 ARM Limited. All rights reserved. + * Copyright 2019, Cypress Semiconductor Corporation + * or a subsidiary of Cypress Semiconductor Corporation. + * + * 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: 7. September 2021 + * $Revision: V2.1.1 + * + * Project: CMSIS-DAP Source + * Title: DAP.c CMSIS-DAP Commands + * + *---------------------------------------------------------------------------*/ + +#include +#ifdef RTE_CMSIS_RTOS +#include "cmsis_os.h" +#endif +#include "DAP_config.h" +#include "DAP.h" +#include "info.h" +#include "dap_strings.h" + + +#if (DAP_PACKET_SIZE < 64U) +#error "Minimum Packet Size is 64!" +#endif +#if (DAP_PACKET_SIZE > 32768U) +#error "Maximum Packet Size is 32768!" +#endif +#if (DAP_PACKET_COUNT < 1U) +#error "Minimum Packet Count is 1!" +#endif +#if (DAP_PACKET_COUNT > 255U) +#error "Maximum Packet Count is 255!" +#endif + + +// Clock Macros + +#define MAX_SWJ_CLOCK(delay_cycles) \ + ((CPU_CLOCK/2U) / (IO_PORT_WRITE_CYCLES + delay_cycles)) + + + DAP_Data_t DAP_Data; // DAP Data +volatile uint8_t DAP_TransferAbort; // Transfer Abort Flag + + +static const char DAP_FW_Ver [] = DAP_FW_VER; + + + +// Get DAP Information +// id: info identifier +// info: pointer to info data +// return: number of bytes in info data +static uint8_t DAP_Info(uint8_t id, uint8_t *info) { + uint8_t length = 0U; + + switch (id) { + case DAP_ID_VENDOR: + length = DAP_GetVendorString((char *)info); + break; + case DAP_ID_PRODUCT: + length = DAP_GetProductString((char *)info); + break; + case DAP_ID_SER_NUM: + length = DAP_GetSerNumString((char *)info); + break; + case DAP_ID_DAP_FW_VER: + length = (uint8_t)sizeof(DAP_FW_Ver); + memcpy(info, DAP_FW_Ver, length); + break; + case DAP_ID_DEVICE_VENDOR: + length = DAP_GetTargetDeviceVendorString((char *)info); + break; + case DAP_ID_DEVICE_NAME: + length = DAP_GetTargetDeviceNameString((char *)info); + break; + case DAP_ID_BOARD_VENDOR: + length = DAP_GetTargetBoardVendorString((char *)info); + break; + case DAP_ID_BOARD_NAME: + length = DAP_GetTargetBoardNameString((char *)info); + break; + case DAP_ID_PRODUCT_FW_VER: + length = DAP_GetProductFirmwareVersionString((char *)info); + break; + case DAP_ID_CAPABILITIES: + info[0] = ((DAP_SWD != 0) ? (1U << 0) : 0U) | + ((DAP_JTAG != 0) ? (1U << 1) : 0U) | + ((SWO_UART != 0) ? (1U << 2) : 0U) | + ((SWO_MANCHESTER != 0) ? (1U << 3) : 0U) | + /* Atomic Commands */ (1U << 4) | + ((TIMESTAMP_CLOCK != 0U) ? (1U << 5) : 0U) | + ((SWO_STREAM != 0U) ? (1U << 6) : 0U) | + ((DAP_UART != 0U) ? (1U << 7) : 0U); +#if ((DAP_UART != 0) && (DAP_UART_USB_COM_PORT != 0)) + info[1] = ((DAP_UART_USB_COM_PORT != 0) ? (1U << 0) : 0U); + length = 2U; +#else + length = 1U; +#endif + break; + case DAP_ID_TIMESTAMP_CLOCK: +#if (TIMESTAMP_CLOCK != 0U) + info[0] = (uint8_t)(TIMESTAMP_CLOCK >> 0); + info[1] = (uint8_t)(TIMESTAMP_CLOCK >> 8); + info[2] = (uint8_t)(TIMESTAMP_CLOCK >> 16); + info[3] = (uint8_t)(TIMESTAMP_CLOCK >> 24); + length = 4U; +#endif + break; + case DAP_ID_UART_RX_BUFFER_SIZE: +#if (DAP_UART != 0) + info[0] = (uint8_t)(DAP_UART_RX_BUFFER_SIZE >> 0); + info[1] = (uint8_t)(DAP_UART_RX_BUFFER_SIZE >> 8); + info[2] = (uint8_t)(DAP_UART_RX_BUFFER_SIZE >> 16); + info[3] = (uint8_t)(DAP_UART_RX_BUFFER_SIZE >> 24); + length = 4U; +#endif + break; + case DAP_ID_UART_TX_BUFFER_SIZE: +#if (DAP_UART != 0) + info[0] = (uint8_t)(DAP_UART_TX_BUFFER_SIZE >> 0); + info[1] = (uint8_t)(DAP_UART_TX_BUFFER_SIZE >> 8); + info[2] = (uint8_t)(DAP_UART_TX_BUFFER_SIZE >> 16); + info[3] = (uint8_t)(DAP_UART_TX_BUFFER_SIZE >> 24); + length = 4U; +#endif + break; + case DAP_ID_SWO_BUFFER_SIZE: +#if ((SWO_UART != 0) || (SWO_MANCHESTER != 0)) + info[0] = (uint8_t)(SWO_BUFFER_SIZE >> 0); + info[1] = (uint8_t)(SWO_BUFFER_SIZE >> 8); + info[2] = (uint8_t)(SWO_BUFFER_SIZE >> 16); + info[3] = (uint8_t)(SWO_BUFFER_SIZE >> 24); + length = 4U; +#endif + break; + case DAP_ID_PACKET_SIZE: + info[0] = (uint8_t)(DAP_PACKET_SIZE >> 0); + info[1] = (uint8_t)(DAP_PACKET_SIZE >> 8); + length = 2U; + break; + case DAP_ID_PACKET_COUNT: + info[0] = DAP_PACKET_COUNT; + length = 1U; + break; + default: + break; + } + + return (length); +} + + +// Delay for specified time +// delay: delay time in ms +void Delayms(uint32_t delay) { + delay *= ((CPU_CLOCK/1000U) + (DELAY_SLOW_CYCLES-1U)) / DELAY_SLOW_CYCLES; + PIN_DELAY_SLOW(delay); +} + + +// Process Delay command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_Delay(const uint8_t *request, uint8_t *response) { + uint32_t delay; + + delay = (uint32_t)(*(request+0)) | + (uint32_t)(*(request+1) << 8); + delay *= ((CPU_CLOCK/1000000U) + (DELAY_SLOW_CYCLES-1U)) / DELAY_SLOW_CYCLES; + + PIN_DELAY_SLOW(delay); + + *response = DAP_OK; + return ((2U << 16) | 1U); +} + + +// Process Host Status command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_HostStatus(const uint8_t *request, uint8_t *response) { + + switch (*request) { + case DAP_DEBUGGER_CONNECTED: + LED_CONNECTED_OUT((*(request+1) & 1U)); + break; + case DAP_TARGET_RUNNING: + LED_RUNNING_OUT((*(request+1) & 1U)); + break; + default: + *response = DAP_ERROR; + return ((2U << 16) | 1U); + } + + *response = DAP_OK; + return ((2U << 16) | 1U); +} + + +// Process Connect command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_Connect(const uint8_t *request, uint8_t *response) { + uint32_t port; + + if (*request == DAP_PORT_AUTODETECT) { + port = DAP_DEFAULT_PORT; + } else { + port = *request; + } + + switch (port) { +#if (DAP_SWD != 0) + case DAP_PORT_SWD: + DAP_Data.debug_port = DAP_PORT_SWD; + PORT_SWD_SETUP(); + break; +#endif +#if (DAP_JTAG != 0) + case DAP_PORT_JTAG: + DAP_Data.debug_port = DAP_PORT_JTAG; + PORT_JTAG_SETUP(); + break; +#endif + default: + port = DAP_PORT_DISABLED; + break; + } + + *response = (uint8_t)port; + return ((1U << 16) | 1U); +} + + +// Process Disconnect command and prepare response +// response: pointer to response data +// return: number of bytes in response +static uint32_t DAP_Disconnect(uint8_t *response) { + + DAP_Data.debug_port = DAP_PORT_DISABLED; + PORT_OFF(); + + *response = DAP_OK; + return (1U); +} + + +// Process Reset Target command and prepare response +// response: pointer to response data +// return: number of bytes in response +static uint32_t DAP_ResetTarget(uint8_t *response) { + + *(response+1) = RESET_TARGET(); + *(response+0) = DAP_OK; + return (2U); +} + + +// Process SWJ Pins command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_SWJ_Pins(const uint8_t *request, uint8_t *response) { +#if ((DAP_SWD != 0) || (DAP_JTAG != 0)) + uint32_t value; + uint32_t select; + uint32_t wait; + uint32_t timestamp; + + value = (uint32_t) *(request+0); + select = (uint32_t) *(request+1); + wait = (uint32_t)(*(request+2) << 0) | + (uint32_t)(*(request+3) << 8) | + (uint32_t)(*(request+4) << 16) | + (uint32_t)(*(request+5) << 24); + + if ((select & (1U << DAP_SWJ_SWCLK_TCK)) != 0U) { + if ((value & (1U << DAP_SWJ_SWCLK_TCK)) != 0U) { + PIN_SWCLK_TCK_SET(); + } else { + PIN_SWCLK_TCK_CLR(); + } + } + if ((select & (1U << DAP_SWJ_SWDIO_TMS)) != 0U) { + if ((value & (1U << DAP_SWJ_SWDIO_TMS)) != 0U) { + PIN_SWDIO_TMS_SET(); + } else { + PIN_SWDIO_TMS_CLR(); + } + } + if ((select & (1U << DAP_SWJ_TDI)) != 0U) { + PIN_TDI_OUT(value >> DAP_SWJ_TDI); + } + if ((select & (1U << DAP_SWJ_nTRST)) != 0U) { + PIN_nTRST_OUT(value >> DAP_SWJ_nTRST); + } + if ((select & (1U << DAP_SWJ_nRESET)) != 0U){ + PIN_nRESET_OUT(value >> DAP_SWJ_nRESET); + } + + if (wait != 0U) { +#if (TIMESTAMP_CLOCK != 0U) + if (wait > 3000000U) { + wait = 3000000U; + } +#if (TIMESTAMP_CLOCK >= 1000000U) + wait *= TIMESTAMP_CLOCK / 1000000U; +#else + wait /= 1000000U / TIMESTAMP_CLOCK; +#endif +#else + wait = 1U; +#endif + timestamp = TIMESTAMP_GET(); + do { + if ((select & (1U << DAP_SWJ_SWCLK_TCK)) != 0U) { + if ((value >> DAP_SWJ_SWCLK_TCK) ^ PIN_SWCLK_TCK_IN()) { + continue; + } + } + if ((select & (1U << DAP_SWJ_SWDIO_TMS)) != 0U) { + if ((value >> DAP_SWJ_SWDIO_TMS) ^ PIN_SWDIO_TMS_IN()) { + continue; + } + } + if ((select & (1U << DAP_SWJ_TDI)) != 0U) { + if ((value >> DAP_SWJ_TDI) ^ PIN_TDI_IN()) { + continue; + } + } + if ((select & (1U << DAP_SWJ_nTRST)) != 0U) { + if ((value >> DAP_SWJ_nTRST) ^ PIN_nTRST_IN()) { + continue; + } + } + if ((select & (1U << DAP_SWJ_nRESET)) != 0U) { + if ((value >> DAP_SWJ_nRESET) ^ PIN_nRESET_IN()) { + continue; + } + } + break; + } while ((TIMESTAMP_GET() - timestamp) < wait); + } + + value = (PIN_SWCLK_TCK_IN() << DAP_SWJ_SWCLK_TCK) | + (PIN_SWDIO_TMS_IN() << DAP_SWJ_SWDIO_TMS) | + (PIN_TDI_IN() << DAP_SWJ_TDI) | + (PIN_TDO_IN() << DAP_SWJ_TDO) | + (PIN_nTRST_IN() << DAP_SWJ_nTRST) | + (PIN_nRESET_IN() << DAP_SWJ_nRESET); + + *response = (uint8_t)value; +#else + *response = 0U; +#endif + + return ((6U << 16) | 1U); +} + + +// Common clock delay calculation routine +// clock: requested SWJ frequency in Hertz +// return: void +static void Set_DAP_Clock_Delay(uint32_t clock) { + uint32_t delay; + + if (clock >= MAX_SWJ_CLOCK(DELAY_FAST_CYCLES)) { + DAP_Data.fast_clock = 1U; + DAP_Data.clock_delay = 1U; + } else { + DAP_Data.fast_clock = 0U; + + delay = ((CPU_CLOCK/2U) + (clock - 1U)) / clock; + if (delay > IO_PORT_WRITE_CYCLES) { + delay -= IO_PORT_WRITE_CYCLES; + delay = (delay + (DELAY_SLOW_CYCLES - 1U)) / DELAY_SLOW_CYCLES; + } else { + delay = 1U; + } + + DAP_Data.clock_delay = delay; + } +} + + +// Process SWJ Clock command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +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; + + clock = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8) | + (uint32_t)(*(request+2) << 16) | + (uint32_t)(*(request+3) << 24); + + if (clock == 0U) { + *response = DAP_ERROR; + return ((4U << 16) | 1U); + } + + DAP_Data.nominal_clock = clock; + + Set_DAP_Clock_Delay(clock); + + *response = DAP_OK; +#else + *response = DAP_ERROR; +#endif + + return ((4U << 16) | 1U); +} + + +// Process SWJ Sequence command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_SWJ_Sequence(const uint8_t *request, uint8_t *response) { + uint32_t count; + + count = *request++; + if (count == 0U) { + count = 256U; + } + +#if ((DAP_SWD != 0) || (DAP_JTAG != 0)) + SWJ_Sequence(count, request); + *response = DAP_OK; +#else + *response = DAP_ERROR; +#endif + + count = (count + 7U) >> 3; + + return (((count + 1U) << 16) | 1U); +} + + +// Process SWD Configure command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_SWD_Configure(const uint8_t *request, uint8_t *response) { +#if (DAP_SWD != 0) + uint8_t value; + + value = *request; + DAP_Data.swd_conf.turnaround = (value & 0x03U) + 1U; + DAP_Data.swd_conf.data_phase = (value & 0x04U) ? 1U : 0U; + + *response = DAP_OK; +#else + *response = DAP_ERROR; +#endif + + return ((1U << 16) | 1U); +} + + +// Process SWD Sequence command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_SWD_Sequence(const uint8_t *request, uint8_t *response) { + uint32_t sequence_info; + uint32_t sequence_count; + uint32_t request_count; + uint32_t response_count; + uint32_t count; + +#if (DAP_SWD != 0) + *response++ = DAP_OK; +#else + *response++ = DAP_ERROR; +#endif + request_count = 1U; + response_count = 1U; + + sequence_count = *request++; + while (sequence_count--) { + sequence_info = *request++; + count = sequence_info & SWD_SEQUENCE_CLK; + if (count == 0U) { + count = 64U; + } + count = (count + 7U) / 8U; +#if (DAP_SWD != 0) + if ((sequence_info & SWD_SEQUENCE_DIN) != 0U) { + PIN_SWDIO_OUT_DISABLE(); + } else { + PIN_SWDIO_OUT_ENABLE(); + } + SWD_Sequence(sequence_info, request, response); + if (sequence_count == 0U) { + PIN_SWDIO_OUT_ENABLE(); + } +#endif + if ((sequence_info & SWD_SEQUENCE_DIN) != 0U) { + request_count++; +#if (DAP_SWD != 0) + response += count; + response_count += count; +#endif + } else { + request += count; + request_count += count + 1U; + } + } + + return ((request_count << 16) | response_count); +} + + +// Process JTAG Sequence command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_JTAG_Sequence(const uint8_t *request, uint8_t *response) { + uint32_t sequence_info; + uint32_t sequence_count; + uint32_t request_count; + uint32_t response_count; + uint32_t count; + +#if (DAP_JTAG != 0) + *response++ = DAP_OK; +#else + *response++ = DAP_ERROR; +#endif + request_count = 1U; + response_count = 1U; + + sequence_count = *request++; + while (sequence_count--) { + 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 + request += count; + request_count += count + 1U; +#if (DAP_JTAG != 0) + if ((sequence_info & JTAG_SEQUENCE_TDO) != 0U) { + response += count; + response_count += count; + } +#endif + } + + return ((request_count << 16) | response_count); +} + + +// Process JTAG Configure command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_JTAG_Configure(const uint8_t *request, uint8_t *response) { + uint32_t count; +#if (DAP_JTAG != 0) + uint32_t length; + uint32_t bits; + uint32_t n; + + count = *request++; + DAP_Data.jtag_dev.count = (uint8_t)count; + + bits = 0U; + for (n = 0U; n < count; n++) { + length = *request++; + DAP_Data.jtag_dev.ir_length[n] = (uint8_t)length; + DAP_Data.jtag_dev.ir_before[n] = (uint16_t)bits; + bits += length; + } + for (n = 0U; n < count; n++) { + bits -= DAP_Data.jtag_dev.ir_length[n]; + DAP_Data.jtag_dev.ir_after[n] = (uint16_t)bits; + } + + *response = DAP_OK; +#else + count = *request; + *response = DAP_ERROR; +#endif + + return (((count + 1U) << 16) | 1U); +} + + +// Process JTAG IDCODE command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_JTAG_IDCode(const uint8_t *request, uint8_t *response) { +#if (DAP_JTAG != 0) + uint32_t data; + + if (DAP_Data.debug_port != DAP_PORT_JTAG) { + goto id_error; + } + + // Device index (JTAP TAP) + DAP_Data.jtag_dev.index = *request; + if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) { + goto id_error; + } + + // Select JTAG chain + JTAG_IR(JTAG_IDCODE); + + // Read IDCODE register + data = JTAG_ReadIDCode(); + + // Store Data + *(response+0) = DAP_OK; + *(response+1) = (uint8_t)(data >> 0); + *(response+2) = (uint8_t)(data >> 8); + *(response+3) = (uint8_t)(data >> 16); + *(response+4) = (uint8_t)(data >> 24); + + return ((1U << 16) | 5U); + +id_error: +#endif + *response = DAP_ERROR; + return ((1U << 16) | 1U); +} + + +// Process Transfer Configure command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_TransferConfigure(const uint8_t *request, uint8_t *response) { + + DAP_Data.transfer.idle_cycles = *(request+0); + DAP_Data.transfer.retry_count = (uint16_t) *(request+1) | + (uint16_t)(*(request+2) << 8); + DAP_Data.transfer.match_retry = (uint16_t) *(request+3) | + (uint16_t)(*(request+4) << 8); + + *response = DAP_OK; + return ((5U << 16) | 1U); +} + + +// Process SWD Transfer command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +#if (DAP_SWD != 0) +static uint32_t DAP_SWD_Transfer(const uint8_t *request, uint8_t *response) { + const + uint8_t *request_head; + uint32_t request_count; + uint32_t request_value; + uint8_t *response_head; + uint32_t response_count; + uint32_t response_value; + uint32_t post_read; + uint32_t check_write; + uint32_t match_value; + uint32_t match_retry; + uint32_t retry; + uint32_t data; +#if (TIMESTAMP_CLOCK != 0U) + uint32_t timestamp; +#endif + + request_head = request; + + response_count = 0U; + response_value = 0U; + response_head = response; + response += 2; + + DAP_TransferAbort = 0U; + + post_read = 0U; + check_write = 0U; + + request++; // Ignore DAP index + + request_count = *request++; + + for (; request_count != 0U; request_count--) { + request_value = *request++; + if ((request_value & DAP_TRANSFER_RnW) != 0U) { + // Read register + if (post_read) { + // Read was posted before + retry = DAP_Data.transfer.retry_count; + if ((request_value & (DAP_TRANSFER_APnDP | DAP_TRANSFER_MATCH_VALUE)) == DAP_TRANSFER_APnDP) { + // Read previous AP data and post next AP read + do { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } else { + // Read previous AP data + do { + response_value = SWD_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + post_read = 0U; + } + if (response_value != DAP_TRANSFER_OK) { + break; + } + // Store previous AP data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); +#if (TIMESTAMP_CLOCK != 0U) + if (post_read) { + // Store Timestamp of next AP read + if ((request_value & DAP_TRANSFER_TIMESTAMP) != 0U) { + timestamp = DAP_Data.timestamp; + *response++ = (uint8_t) timestamp; + *response++ = (uint8_t)(timestamp >> 8); + *response++ = (uint8_t)(timestamp >> 16); + *response++ = (uint8_t)(timestamp >> 24); + } + } +#endif + } + if ((request_value & DAP_TRANSFER_MATCH_VALUE) != 0U) { + // Read with value match + match_value = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8) | + (uint32_t)(*(request+2) << 16) | + (uint32_t)(*(request+3) << 24); + request += 4; + match_retry = DAP_Data.transfer.match_retry; + if ((request_value & DAP_TRANSFER_APnDP) != 0U) { + // Post AP read + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } + } + do { + // Read register until its value matches or retry counter expires + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } + } while (((data & DAP_Data.transfer.match_mask) != match_value) && match_retry-- && !DAP_TransferAbort); + if ((data & DAP_Data.transfer.match_mask) != match_value) { + response_value |= DAP_TRANSFER_MISMATCH; + } + if (response_value != DAP_TRANSFER_OK) { + break; + } + } else { + // Normal read + retry = DAP_Data.transfer.retry_count; + if ((request_value & DAP_TRANSFER_APnDP) != 0U) { + // Read AP register + if (post_read == 0U) { + // Post AP read + do { + response_value = SWD_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } +#if (TIMESTAMP_CLOCK != 0U) + // Store Timestamp + if ((request_value & DAP_TRANSFER_TIMESTAMP) != 0U) { + timestamp = DAP_Data.timestamp; + *response++ = (uint8_t) timestamp; + *response++ = (uint8_t)(timestamp >> 8); + *response++ = (uint8_t)(timestamp >> 16); + *response++ = (uint8_t)(timestamp >> 24); + } +#endif + post_read = 1U; + } + } else { + // Read DP register + do { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } +#if (TIMESTAMP_CLOCK != 0U) + // Store Timestamp + if ((request_value & DAP_TRANSFER_TIMESTAMP) != 0U) { + timestamp = DAP_Data.timestamp; + *response++ = (uint8_t) timestamp; + *response++ = (uint8_t)(timestamp >> 8); + *response++ = (uint8_t)(timestamp >> 16); + *response++ = (uint8_t)(timestamp >> 24); + } +#endif + // Store data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + } + } + check_write = 0U; + } else { + // Write register + if (post_read) { + // Read previous data + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } + // Store previous data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + post_read = 0U; + } + // Load data + data = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8) | + (uint32_t)(*(request+2) << 16) | + (uint32_t)(*(request+3) << 24); + request += 4; + if ((request_value & DAP_TRANSFER_MATCH_MASK) != 0U) { + // Write match mask + DAP_Data.transfer.match_mask = data; + response_value = DAP_TRANSFER_OK; + } else { + // Write DP/AP register + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } +#if (TIMESTAMP_CLOCK != 0U) + // Store Timestamp + if ((request_value & DAP_TRANSFER_TIMESTAMP) != 0U) { + timestamp = DAP_Data.timestamp; + *response++ = (uint8_t) timestamp; + *response++ = (uint8_t)(timestamp >> 8); + *response++ = (uint8_t)(timestamp >> 16); + *response++ = (uint8_t)(timestamp >> 24); + } +#endif + check_write = 1U; + } + } + response_count++; + if (DAP_TransferAbort) { + break; + } + } + + for (; request_count != 0U; request_count--) { + // Process canceled requests + request_value = *request++; + if ((request_value & DAP_TRANSFER_RnW) != 0U) { + // Read register + if ((request_value & DAP_TRANSFER_MATCH_VALUE) != 0U) { + // Read with value match + request += 4; + } + } else { + // Write register + request += 4; + } + } + + if (response_value == DAP_TRANSFER_OK) { + if (post_read) { + // Read previous data + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + // Store previous data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + } else if (check_write) { + // Check last write + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } + } + +end: + *(response_head+0) = (uint8_t)response_count; + *(response_head+1) = (uint8_t)response_value; + + return (((uint32_t)(request - request_head) << 16) | (uint32_t)(response - response_head)); +} +#endif + + +// Process JTAG Transfer command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +#if (DAP_JTAG != 0) +static uint32_t DAP_JTAG_Transfer(const uint8_t *request, uint8_t *response) { + const + uint8_t *request_head; + uint32_t request_count; + uint32_t request_value; + uint32_t request_ir; + uint8_t *response_head; + uint32_t response_count; + uint32_t response_value; + uint32_t post_read; + uint32_t match_value; + uint32_t match_retry; + uint32_t retry; + uint32_t data; + uint32_t ir; +#if (TIMESTAMP_CLOCK != 0U) + uint32_t timestamp; +#endif + + request_head = request; + + response_count = 0U; + response_value = 0U; + response_head = response; + response += 2; + + DAP_TransferAbort = 0U; + + ir = 0U; + post_read = 0U; + + // Device index (JTAP TAP) + DAP_Data.jtag_dev.index = *request++; + if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) { + goto end; + } + + request_count = *request++; + + for (; request_count != 0U; request_count--) { + request_value = *request++; + request_ir = (request_value & DAP_TRANSFER_APnDP) ? JTAG_APACC : JTAG_DPACC; + if ((request_value & DAP_TRANSFER_RnW) != 0U) { + // Read register + if (post_read) { + // Read was posted before + retry = DAP_Data.transfer.retry_count; + if ((ir == request_ir) && ((request_value & DAP_TRANSFER_MATCH_VALUE) == 0U)) { + // Read previous data and post next read + do { + response_value = JTAG_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } else { + // Select JTAG chain + if (ir != JTAG_DPACC) { + ir = JTAG_DPACC; + JTAG_IR(ir); + } + // Read previous data + do { + response_value = JTAG_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + post_read = 0U; + } + if (response_value != DAP_TRANSFER_OK) { + break; + } + // Store previous data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); +#if (TIMESTAMP_CLOCK != 0U) + if (post_read) { + // Store Timestamp of next AP read + if ((request_value & DAP_TRANSFER_TIMESTAMP) != 0U) { + timestamp = DAP_Data.timestamp; + *response++ = (uint8_t) timestamp; + *response++ = (uint8_t)(timestamp >> 8); + *response++ = (uint8_t)(timestamp >> 16); + *response++ = (uint8_t)(timestamp >> 24); + } + } +#endif + } + if ((request_value & DAP_TRANSFER_MATCH_VALUE) != 0U) { + // Read with value match + match_value = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8) | + (uint32_t)(*(request+2) << 16) | + (uint32_t)(*(request+3) << 24); + request += 4; + match_retry = DAP_Data.transfer.match_retry; + // Select JTAG chain + if (ir != request_ir) { + ir = request_ir; + JTAG_IR(ir); + } + // Post DP/AP read + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } + do { + // Read register until its value matches or retry counter expires + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } + } while (((data & DAP_Data.transfer.match_mask) != match_value) && match_retry-- && !DAP_TransferAbort); + if ((data & DAP_Data.transfer.match_mask) != match_value) { + response_value |= DAP_TRANSFER_MISMATCH; + } + if (response_value != DAP_TRANSFER_OK) { + break; + } + } else { + // Normal read + if (post_read == 0U) { + // Select JTAG chain + if (ir != request_ir) { + ir = request_ir; + JTAG_IR(ir); + } + // Post DP/AP read + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } +#if (TIMESTAMP_CLOCK != 0U) + // Store Timestamp + if ((request_value & DAP_TRANSFER_TIMESTAMP) != 0U) { + timestamp = DAP_Data.timestamp; + *response++ = (uint8_t) timestamp; + *response++ = (uint8_t)(timestamp >> 8); + *response++ = (uint8_t)(timestamp >> 16); + *response++ = (uint8_t)(timestamp >> 24); + } +#endif + post_read = 1U; + } + } + } else { + // Write register + if (post_read) { + // Select JTAG chain + if (ir != JTAG_DPACC) { + ir = JTAG_DPACC; + JTAG_IR(ir); + } + // Read previous data + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } + // Store previous data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + post_read = 0U; + } + // Load data + data = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8) | + (uint32_t)(*(request+2) << 16) | + (uint32_t)(*(request+3) << 24); + request += 4; + if ((request_value & DAP_TRANSFER_MATCH_MASK) != 0U) { + // Write match mask + DAP_Data.transfer.match_mask = data; + response_value = DAP_TRANSFER_OK; + } else { + // Select JTAG chain + if (ir != request_ir) { + ir = request_ir; + JTAG_IR(ir); + } + // Write DP/AP register + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } +#if (TIMESTAMP_CLOCK != 0U) + // Store Timestamp + if ((request_value & DAP_TRANSFER_TIMESTAMP) != 0U) { + timestamp = DAP_Data.timestamp; + *response++ = (uint8_t) timestamp; + *response++ = (uint8_t)(timestamp >> 8); + *response++ = (uint8_t)(timestamp >> 16); + *response++ = (uint8_t)(timestamp >> 24); + } +#endif + } + } + response_count++; + if (DAP_TransferAbort) { + break; + } + } + + for (; request_count != 0U; request_count--) { + // Process canceled requests + request_value = *request++; + if ((request_value & DAP_TRANSFER_RnW) != 0U) { + // Read register + if ((request_value & DAP_TRANSFER_MATCH_VALUE) != 0U) { + // Read with value match + request += 4; + } + } else { + // Write register + request += 4; + } + } + + if (response_value == DAP_TRANSFER_OK) { + // Select JTAG chain + if (ir != JTAG_DPACC) { + ir = JTAG_DPACC; + JTAG_IR(ir); + } + if (post_read) { + // Read previous data + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + // Store previous data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + } else { + // Check last write + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } + } + +end: + *(response_head+0) = (uint8_t)response_count; + *(response_head+1) = (uint8_t)response_value; + + return (((uint32_t)(request - request_head) << 16) | (uint32_t)(response - response_head)); +} +#endif + + +// Process Dummy Transfer command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_Dummy_Transfer(const uint8_t *request, uint8_t *response) { + const + uint8_t *request_head; + uint32_t request_count; + uint32_t request_value; + + request_head = request; + + request++; // Ignore DAP index + + request_count = *request++; + + for (; request_count != 0U; request_count--) { + // Process dummy requests + request_value = *request++; + if ((request_value & DAP_TRANSFER_RnW) != 0U) { + // Read register + if ((request_value & DAP_TRANSFER_MATCH_VALUE) != 0U) { + // Read with value match + request += 4; + } + } else { + // Write register + request += 4; + } + } + + *(response+0) = 0U; // Response count + *(response+1) = 0U; // Response value + + return (((uint32_t)(request - request_head) << 16) | 2U); +} + + +// Process Transfer command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_Transfer(const uint8_t *request, uint8_t *response) { + uint32_t num; + + switch (DAP_Data.debug_port) { +#if (DAP_SWD != 0) + case DAP_PORT_SWD: + num = DAP_SWD_Transfer(request, response); + break; +#endif +#if (DAP_JTAG != 0) + case DAP_PORT_JTAG: + num = DAP_JTAG_Transfer(request, response); + break; +#endif + default: + num = DAP_Dummy_Transfer(request, response); + break; + } + + return (num); +} + + +// Process SWD Transfer Block command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_SWD != 0) +static uint32_t DAP_SWD_TransferBlock(const uint8_t *request, uint8_t *response) { + uint32_t request_count; + uint32_t request_value; + uint32_t response_count; + uint32_t response_value; + uint8_t *response_head; + uint32_t retry; + uint32_t data; + + response_count = 0U; + response_value = 0U; + response_head = response; + response += 3; + + DAP_TransferAbort = 0U; + + request++; // Ignore DAP index + + request_count = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8); + request += 2; + if (request_count == 0U) { + goto end; + } + + request_value = *request++; + if ((request_value & DAP_TRANSFER_RnW) != 0U) { + // Read register block + if ((request_value & DAP_TRANSFER_APnDP) != 0U) { + // Post AP read + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + } + while (request_count--) { + // Read DP/AP register + if ((request_count == 0U) && ((request_value & DAP_TRANSFER_APnDP) != 0U)) { + // Last AP read + request_value = DP_RDBUFF | DAP_TRANSFER_RnW; + } + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + // Store data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + response_count++; + } + } else { + // Write register block + while (request_count--) { + // Load data + data = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8) | + (uint32_t)(*(request+2) << 16) | + (uint32_t)(*(request+3) << 24); + request += 4; + // Write DP/AP register + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + response_count++; + } + // Check last write + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } + +end: + *(response_head+0) = (uint8_t)(response_count >> 0); + *(response_head+1) = (uint8_t)(response_count >> 8); + *(response_head+2) = (uint8_t) response_value; + + return ((uint32_t)(response - response_head)); +} +#endif + + +// Process JTAG Transfer Block command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_JTAG != 0) +static uint32_t DAP_JTAG_TransferBlock(const uint8_t *request, uint8_t *response) { + uint32_t request_count; + uint32_t request_value; + uint32_t response_count; + uint32_t response_value; + uint8_t *response_head; + uint32_t retry; + uint32_t data; + uint32_t ir; + + response_count = 0U; + response_value = 0U; + response_head = response; + response += 3; + + DAP_TransferAbort = 0U; + + // Device index (JTAP TAP) + DAP_Data.jtag_dev.index = *request++; + if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) { + goto end; + } + + request_count = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8); + request += 2; + if (request_count == 0U) { + goto end; + } + + request_value = *request++; + + // Select JTAG chain + ir = (request_value & DAP_TRANSFER_APnDP) ? JTAG_APACC : JTAG_DPACC; + JTAG_IR(ir); + + if ((request_value & DAP_TRANSFER_RnW) != 0U) { + // Post read + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + // Read register block + while (request_count--) { + // Read DP/AP register + if (request_count == 0U) { + // Last read + if (ir != JTAG_DPACC) { + JTAG_IR(JTAG_DPACC); + } + request_value = DP_RDBUFF | DAP_TRANSFER_RnW; + } + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + // Store data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + response_count++; + } + } else { + // Write register block + while (request_count--) { + // Load data + data = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8) | + (uint32_t)(*(request+2) << 16) | + (uint32_t)(*(request+3) << 24); + request += 4; + // Write DP/AP register + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + response_count++; + } + // Check last write + if (ir != JTAG_DPACC) { + JTAG_IR(JTAG_DPACC); + } + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } + +end: + *(response_head+0) = (uint8_t)(response_count >> 0); + *(response_head+1) = (uint8_t)(response_count >> 8); + *(response_head+2) = (uint8_t) response_value; + + return ((uint32_t)(response - response_head)); +} +#endif + + +// Process Transfer Block command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_TransferBlock(const uint8_t *request, uint8_t *response) { + uint32_t num; + + switch (DAP_Data.debug_port) { +#if (DAP_SWD != 0) + case DAP_PORT_SWD: + num = DAP_SWD_TransferBlock (request, response); + break; +#endif +#if (DAP_JTAG != 0) + case DAP_PORT_JTAG: + num = DAP_JTAG_TransferBlock(request, response); + break; +#endif + default: + *(response+0) = 0U; // Response count [7:0] + *(response+1) = 0U; // Response count[15:8] + *(response+2) = 0U; // Response value + num = 3U; + break; + } + + if ((*(request+3) & DAP_TRANSFER_RnW) != 0U) { + // Read register block + num |= 4U << 16; + } else { + // Write register block + num |= (4U + (((uint32_t)(*(request+1)) | (uint32_t)(*(request+2) << 8)) * 4)) << 16; + } + + return (num); +} + + +// Process SWD Write ABORT command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_SWD != 0) +static uint32_t DAP_SWD_WriteAbort(const uint8_t *request, uint8_t *response) { + uint32_t data; + + // Load data (Ignore DAP index) + data = (uint32_t)(*(request+1) << 0) | + (uint32_t)(*(request+2) << 8) | + (uint32_t)(*(request+3) << 16) | + (uint32_t)(*(request+4) << 24); + + // Write Abort register + SWD_Transfer(DP_ABORT, &data); + + *response = DAP_OK; + return (1U); +} +#endif + + +// Process JTAG Write ABORT command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_JTAG != 0) +static uint32_t DAP_JTAG_WriteAbort(const uint8_t *request, uint8_t *response) { + uint32_t data; + + // Device index (JTAP TAP) + DAP_Data.jtag_dev.index = *request; + if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) { + *response = DAP_ERROR; + return (1U); + } + + // Select JTAG chain + JTAG_IR(JTAG_ABORT); + + // Load data + data = (uint32_t)(*(request+1) << 0) | + (uint32_t)(*(request+2) << 8) | + (uint32_t)(*(request+3) << 16) | + (uint32_t)(*(request+4) << 24); + + // Write Abort register + JTAG_WriteAbort(data); + + *response = DAP_OK; + return (1U); +} +#endif + + +// Process Write ABORT command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_WriteAbort(const uint8_t *request, uint8_t *response) { + uint32_t num; + + switch (DAP_Data.debug_port) { +#if (DAP_SWD != 0) + case DAP_PORT_SWD: + num = DAP_SWD_WriteAbort (request, response); + break; +#endif +#if (DAP_JTAG != 0) + case DAP_PORT_JTAG: + num = DAP_JTAG_WriteAbort(request, response); + break; +#endif + default: + *response = DAP_ERROR; + num = 1U; + break; + } + return ((5U << 16) | num); +} + + +// Process DAP Vendor command request and prepare response +// Default function (can be overridden) +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +__WEAK uint32_t DAP_ProcessVendorCommand(const uint8_t *request, uint8_t *response) { + (void)request; + *response = ID_DAP_Invalid; + return ((1U << 16) | 1U); +} + +// Process DAP Vendor extended command request and prepare response +// Default function (can be overridden) +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +__WEAK uint32_t DAP_ProcessVendorCommandEx(const uint8_t *request, uint8_t *response) { + *response = ID_DAP_Invalid; + return ((1U << 16) | 1U); +} + +// Process DAP command request and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t DAP_ProcessCommand(const uint8_t *request, uint8_t *response) { + uint32_t num; + + if ((*request >= ID_DAP_Vendor0) && (*request <= ID_DAP_Vendor31)) { + return DAP_ProcessVendorCommand(request, response); + } + + if ((*request >= ID_DAP_VendorExFirst) && (*request <= ID_DAP_VendorExLast)) { + return DAP_ProcessVendorCommandEx(request, response); + } + + *response++ = *request; + + switch (*request++) { + case ID_DAP_Info: + num = DAP_Info(*request, response+1); + *response = (uint8_t)num; + return ((2U << 16) + 2U + num); + + case ID_DAP_HostStatus: + num = DAP_HostStatus(request, response); + break; + + case ID_DAP_Connect: + num = DAP_Connect(request, response); + break; + case ID_DAP_Disconnect: + num = DAP_Disconnect(response); + break; + + case ID_DAP_Delay: + num = DAP_Delay(request, response); + break; + + case ID_DAP_ResetTarget: + num = DAP_ResetTarget(response); + break; + + case ID_DAP_SWJ_Pins: + num = DAP_SWJ_Pins(request, response); + break; + case ID_DAP_SWJ_Clock: + num = DAP_SWJ_Clock(request, response); + break; + case ID_DAP_SWJ_Sequence: + num = DAP_SWJ_Sequence(request, response); + break; + + case ID_DAP_SWD_Configure: + num = DAP_SWD_Configure(request, response); + break; + case ID_DAP_SWD_Sequence: + num = DAP_SWD_Sequence(request, response); + break; + + case ID_DAP_JTAG_Sequence: + num = DAP_JTAG_Sequence(request, response); + break; + case ID_DAP_JTAG_Configure: + num = DAP_JTAG_Configure(request, response); + break; + case ID_DAP_JTAG_IDCODE: + num = DAP_JTAG_IDCode(request, response); + break; + + case ID_DAP_TransferConfigure: + num = DAP_TransferConfigure(request, response); + break; + case ID_DAP_Transfer: + num = DAP_Transfer(request, response); + break; + case ID_DAP_TransferBlock: + num = DAP_TransferBlock(request, response); + break; + case ID_DAP_TransferAbort: + DAP_TransferAbort = 1U; + *response = DAP_OK; + num = 1U; + break; + + case ID_DAP_WriteABORT: + num = DAP_WriteAbort(request, response); + break; + +#if ((SWO_UART != 0) || (SWO_MANCHESTER != 0)) + case ID_DAP_SWO_Transport: + num = SWO_Transport(request, response); + break; + case ID_DAP_SWO_Mode: + num = SWO_Mode(request, response); + break; + case ID_DAP_SWO_Baudrate: + num = SWO_Baudrate(request, response); + break; + case ID_DAP_SWO_Control: + num = SWO_Control(request, response); + break; + case ID_DAP_SWO_Status: + num = SWO_Status(response); + break; + case ID_DAP_SWO_ExtendedStatus: + num = SWO_ExtendedStatus(request, response); + break; + case ID_DAP_SWO_Data: + num = SWO_Data(request, response); + break; +#endif + +#if (DAP_UART != 0) + case ID_DAP_UART_Transport: + num = UART_Transport(request, response); + break; + case ID_DAP_UART_Configure: + num = UART_Configure(request, response); + break; + case ID_DAP_UART_Control: + num = UART_Control(request, response); + break; + case ID_DAP_UART_Status: + num = UART_Status(response); + break; + case ID_DAP_UART_Transfer: + num = UART_Transfer(request, response); + break; +#endif + + default: + *(response-1) = ID_DAP_Invalid; + return ((1U << 16) | 1U); + } + + return ((1U << 16) + 1U + num); +} + + +// Execute DAP command (process request and prepare response) +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t DAP_ExecuteCommand(const uint8_t *request, uint8_t *response) { + uint32_t cnt, num, n; + + /* ID_DAP_ExecuteCommands (0x7F) and ID_DAP_QueueCommands (0x7E) both + * pack multiple DAP commands into one USB packet. Keil MDK uses + * ID_DAP_QueueCommands for flash programming; OpenOCD uses + * ID_DAP_ExecuteCommands. In a synchronous (bare-metal) firmware both + * are handled identically — execute immediately and return the combined + * response. */ + if ((*request == ID_DAP_ExecuteCommands) || (*request == ID_DAP_QueueCommands)) { + *response++ = *request++; + cnt = *request++; + *response++ = (uint8_t)cnt; + num = (2U << 16) | 2U; + while (cnt--) { + n = DAP_ProcessCommand(request, response); + num += n; + request += (uint16_t)(n >> 16); + response += (uint16_t) n; + } + return (num); + } + + return DAP_ProcessCommand(request, response); +} + + +// Setup DAP +void DAP_Setup(void) { + + // Default settings + DAP_Data.debug_port = 0U; + DAP_Data.nominal_clock = DAP_DEFAULT_SWJ_CLOCK; + DAP_Data.transfer.idle_cycles = 0U; + DAP_Data.transfer.retry_count = 100U; + DAP_Data.transfer.match_retry = 0U; + DAP_Data.transfer.match_mask = 0x00000000U; +#if (DAP_SWD != 0) + DAP_Data.swd_conf.turnaround = 1U; + DAP_Data.swd_conf.data_phase = 0U; +#endif +#if (DAP_JTAG != 0) + DAP_Data.jtag_dev.count = 0U; +#endif + + // Sets DAP_Data.fast_clock and DAP_Data.clock_delay. + Set_DAP_Clock_Delay(DAP_DEFAULT_SWJ_CLOCK); + + DAP_SETUP(); // Device specific setup +} diff --git a/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP.h b/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP.h new file mode 100644 index 0000000..1975d66 --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP.h @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2013-2021 ARM Limited. All rights reserved. + * Copyright 2019, Cypress Semiconductor Corporation + * or a subsidiary of Cypress Semiconductor Corporation. + * + * 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: 26. May 2021 + * $Revision: V2.1.0 + * + * Project: CMSIS-DAP Include + * Title: DAP.h Definitions + * + *---------------------------------------------------------------------------*/ + +#ifndef __DAP_H__ +#define __DAP_H__ + + +// DAP Firmware Version +#ifdef DAP_FW_V1 +#define DAP_FW_VER "1.3.0" +#else +#define DAP_FW_VER "2.1.0" +#endif + +// DAP Command IDs +#define ID_DAP_Info 0x00U +#define ID_DAP_HostStatus 0x01U +#define ID_DAP_Connect 0x02U +#define ID_DAP_Disconnect 0x03U +#define ID_DAP_TransferConfigure 0x04U +#define ID_DAP_Transfer 0x05U +#define ID_DAP_TransferBlock 0x06U +#define ID_DAP_TransferAbort 0x07U +#define ID_DAP_WriteABORT 0x08U +#define ID_DAP_Delay 0x09U +#define ID_DAP_ResetTarget 0x0AU +#define ID_DAP_SWJ_Pins 0x10U +#define ID_DAP_SWJ_Clock 0x11U +#define ID_DAP_SWJ_Sequence 0x12U +#define ID_DAP_SWD_Configure 0x13U +#define ID_DAP_SWD_Sequence 0x1DU +#define ID_DAP_JTAG_Sequence 0x14U +#define ID_DAP_JTAG_Configure 0x15U +#define ID_DAP_JTAG_IDCODE 0x16U +#define ID_DAP_SWO_Transport 0x17U +#define ID_DAP_SWO_Mode 0x18U +#define ID_DAP_SWO_Baudrate 0x19U +#define ID_DAP_SWO_Control 0x1AU +#define ID_DAP_SWO_Status 0x1BU +#define ID_DAP_SWO_ExtendedStatus 0x1EU +#define ID_DAP_SWO_Data 0x1CU +#define ID_DAP_UART_Transport 0x1FU +#define ID_DAP_UART_Configure 0x20U +#define ID_DAP_UART_Control 0x22U +#define ID_DAP_UART_Status 0x23U +#define ID_DAP_UART_Transfer 0x21U + +#define ID_DAP_QueueCommands 0x7EU +#define ID_DAP_ExecuteCommands 0x7FU + +// DAP Vendor Command IDs +#define ID_DAP_Vendor0 0x80U +#define ID_DAP_Vendor1 0x81U +#define ID_DAP_Vendor2 0x82U +#define ID_DAP_Vendor3 0x83U +#define ID_DAP_Vendor4 0x84U +#define ID_DAP_Vendor5 0x85U +#define ID_DAP_Vendor6 0x86U +#define ID_DAP_Vendor7 0x87U +#define ID_DAP_Vendor8 0x88U +#define ID_DAP_Vendor9 0x89U +#define ID_DAP_Vendor10 0x8AU +#define ID_DAP_Vendor11 0x8BU +#define ID_DAP_Vendor12 0x8CU +#define ID_DAP_Vendor13 0x8DU +#define ID_DAP_Vendor14 0x8EU +#define ID_DAP_Vendor15 0x8FU +#define ID_DAP_Vendor16 0x90U +#define ID_DAP_Vendor17 0x91U +#define ID_DAP_Vendor18 0x92U +#define ID_DAP_Vendor19 0x93U +#define ID_DAP_Vendor20 0x94U +#define ID_DAP_Vendor21 0x95U +#define ID_DAP_Vendor22 0x96U +#define ID_DAP_Vendor23 0x97U +#define ID_DAP_Vendor24 0x98U +#define ID_DAP_Vendor25 0x99U +#define ID_DAP_Vendor26 0x9AU +#define ID_DAP_Vendor27 0x9BU +#define ID_DAP_Vendor28 0x9CU +#define ID_DAP_Vendor29 0x9DU +#define ID_DAP_Vendor30 0x9EU +#define ID_DAP_Vendor31 0x9FU + +// DAP Extended range of Vendor Command IDs + +#define ID_DAP_VendorExFirst 0xA0U +#define ID_DAP_VendorExLast 0xFEU + +#define ID_DAP_Invalid 0xFFU + +// DAP Status Code +#define DAP_OK 0U +#define DAP_ERROR 0xFFU + +// DAP ID +#define DAP_ID_VENDOR 1U +#define DAP_ID_PRODUCT 2U +#define DAP_ID_SER_NUM 3U +#define DAP_ID_DAP_FW_VER 4U +#define DAP_ID_DEVICE_VENDOR 5U +#define DAP_ID_DEVICE_NAME 6U +#define DAP_ID_BOARD_VENDOR 7U +#define DAP_ID_BOARD_NAME 8U +#define DAP_ID_PRODUCT_FW_VER 9U +#define DAP_ID_CAPABILITIES 0xF0U +#define DAP_ID_TIMESTAMP_CLOCK 0xF1U +#define DAP_ID_UART_RX_BUFFER_SIZE 0xFBU +#define DAP_ID_UART_TX_BUFFER_SIZE 0xFCU +#define DAP_ID_SWO_BUFFER_SIZE 0xFDU +#define DAP_ID_PACKET_COUNT 0xFEU +#define DAP_ID_PACKET_SIZE 0xFFU + +// DAP Host Status +#define DAP_DEBUGGER_CONNECTED 0U +#define DAP_TARGET_RUNNING 1U + +// DAP Port +#define DAP_PORT_AUTODETECT 0U // Autodetect Port +#define DAP_PORT_DISABLED 0U // Port Disabled (I/O pins in High-Z) +#define DAP_PORT_SWD 1U // SWD Port (SWCLK, SWDIO) + nRESET +#define DAP_PORT_JTAG 2U // JTAG Port (TCK, TMS, TDI, TDO, nTRST) + nRESET + +// DAP SWJ Pins +#define DAP_SWJ_SWCLK_TCK 0 // SWCLK/TCK +#define DAP_SWJ_SWDIO_TMS 1 // SWDIO/TMS +#define DAP_SWJ_TDI 2 // TDI +#define DAP_SWJ_TDO 3 // TDO +#define DAP_SWJ_nTRST 5 // nTRST +#define DAP_SWJ_nRESET 7 // nRESET + +// DAP Transfer Request +#define DAP_TRANSFER_APnDP (1U<<0) +#define DAP_TRANSFER_RnW (1U<<1) +#define DAP_TRANSFER_A2 (1U<<2) +#define DAP_TRANSFER_A3 (1U<<3) +#define DAP_TRANSFER_MATCH_VALUE (1U<<4) +#define DAP_TRANSFER_MATCH_MASK (1U<<5) +#define DAP_TRANSFER_TIMESTAMP (1U<<7) + +// DAP Transfer Response +#define DAP_TRANSFER_OK (1U<<0) +#define DAP_TRANSFER_WAIT (1U<<1) +#define DAP_TRANSFER_FAULT (1U<<2) +#define DAP_TRANSFER_ERROR (1U<<3) +#define DAP_TRANSFER_MISMATCH (1U<<4) + +// DAP SWO Trace Mode +#define DAP_SWO_OFF 0U +#define DAP_SWO_UART 1U +#define DAP_SWO_MANCHESTER 2U + +// DAP SWO Trace Status +#define DAP_SWO_CAPTURE_ACTIVE (1U<<0) +#define DAP_SWO_CAPTURE_PAUSED (1U<<1) +#define DAP_SWO_STREAM_ERROR (1U<<6) +#define DAP_SWO_BUFFER_OVERRUN (1U<<7) + +// DAP UART Transport +#define DAP_UART_TRANSPORT_NONE 0U +#define DAP_UART_TRANSPORT_USB_COM_PORT 1U +#define DAP_UART_TRANSPORT_DAP_COMMAND 2U + +// DAP UART Control +#define DAP_UART_CONTROL_RX_ENABLE (1U<<0) +#define DAP_UART_CONTROL_RX_DISABLE (1U<<1) +#define DAP_UART_CONTROL_RX_BUF_FLUSH (1U<<2) +#define DAP_UART_CONTROL_TX_ENABLE (1U<<4) +#define DAP_UART_CONTROL_TX_DISABLE (1U<<5) +#define DAP_UART_CONTROL_TX_BUF_FLUSH (1U<<6) + +// DAP UART Status +#define DAP_UART_STATUS_RX_ENABLED (1U<<0) +#define DAP_UART_STATUS_RX_DATA_LOST (1U<<1) +#define DAP_UART_STATUS_FRAMING_ERROR (1U<<2) +#define DAP_UART_STATUS_PARITY_ERROR (1U<<3) +#define DAP_UART_STATUS_TX_ENABLED (1U<<4) + +// DAP UART Configure Error +#define DAP_UART_CFG_ERROR_DATA_BITS (1U<<0) +#define DAP_UART_CFG_ERROR_PARITY (1U<<1) +#define DAP_UART_CFG_ERROR_STOP_BITS (1U<<2) + +// Debug Port Register Addresses +#define DP_IDCODE 0x00U // IDCODE Register (SW Read only) +#define DP_ABORT 0x00U // Abort Register (SW Write only) +#define DP_CTRL_STAT 0x04U // Control & Status +#define DP_WCR 0x04U // Wire Control Register (SW Only) +#define DP_SELECT 0x08U // Select Register (JTAG R/W & SW W) +#define DP_RESEND 0x08U // Resend (SW Read Only) +#define DP_RDBUFF 0x0CU // Read Buffer (Read Only) + +// JTAG IR Codes +#define JTAG_ABORT 0x08U +#define JTAG_DPACC 0x0AU +#define JTAG_APACC 0x0BU +#define JTAG_IDCODE 0x0EU +#define JTAG_BYPASS 0x0FU + +// JTAG Sequence Info +#define JTAG_SEQUENCE_TCK 0x3FU // TCK count +#define JTAG_SEQUENCE_TMS 0x40U // TMS value +#define JTAG_SEQUENCE_TDO 0x80U // TDO capture + +// SWD Sequence Info +#define SWD_SEQUENCE_CLK 0x3FU // SWCLK count +#define SWD_SEQUENCE_DIN 0x80U // SWDIO capture + + +#include +#include +#include "cmsis_compiler.h" + +// DAP Data structure +typedef struct { + uint8_t debug_port; // Debug Port + uint8_t fast_clock; // Fast Clock Flag + uint8_t padding[2]; + uint32_t clock_delay; // Clock Delay + uint32_t nominal_clock; // Nominal requested clock frequency in Hertz. + uint32_t timestamp; // Last captured Timestamp + struct { // Transfer Configuration + uint8_t idle_cycles; // Idle cycles after transfer + uint8_t padding[3]; + uint16_t retry_count; // Number of retries after WAIT response + uint16_t match_retry; // Number of retries if read value does not match + uint32_t match_mask; // Match Mask + } transfer; +#if (DAP_SWD != 0) + struct { // SWD Configuration + uint8_t turnaround; // Turnaround period + uint8_t data_phase; // Always generate Data Phase + } swd_conf; +#endif +#if (DAP_JTAG != 0) + struct { // JTAG Device Chain + uint8_t count; // Number of devices + uint8_t index; // Device index (device at TDO has index 0) +#if (DAP_JTAG_DEV_CNT != 0) + uint8_t ir_length[DAP_JTAG_DEV_CNT]; // IR Length in bits + uint16_t ir_before[DAP_JTAG_DEV_CNT]; // Bits before IR + uint16_t ir_after [DAP_JTAG_DEV_CNT]; // Bits after IR +#endif + } jtag_dev; +#endif +} DAP_Data_t; + +extern DAP_Data_t DAP_Data; // DAP Data +extern volatile uint8_t DAP_TransferAbort; // Transfer Abort Flag + + +#ifdef __cplusplus +extern "C" +{ +#endif + +// Functions +extern void SWJ_Sequence (uint32_t count, const uint8_t *data); +extern void SWD_Sequence (uint32_t info, const uint8_t *swdo, uint8_t *swdi); +extern void JTAG_Sequence (uint32_t info, const uint8_t *tdi, uint8_t *tdo); +extern void JTAG_IR (uint32_t ir); +extern uint32_t JTAG_ReadIDCode (void); +extern void JTAG_WriteAbort (uint32_t data); +extern uint8_t JTAG_Transfer (uint32_t request, uint32_t *data); +extern uint8_t SWD_Transfer (uint32_t request, uint32_t *data); + +extern void Delayms (uint32_t delay); + +extern uint32_t SWO_Transport (const uint8_t *request, uint8_t *response); +extern uint32_t SWO_Mode (const uint8_t *request, uint8_t *response); +extern uint32_t SWO_Baudrate (const uint8_t *request, uint8_t *response); +extern uint32_t SWO_Control (const uint8_t *request, uint8_t *response); +extern uint32_t SWO_Status (uint8_t *response); +extern uint32_t SWO_ExtendedStatus (const uint8_t *request, uint8_t *response); +extern uint32_t SWO_Data (const uint8_t *request, uint8_t *response); + +extern void SWO_QueueTransfer (uint8_t *buf, uint32_t num); +extern void SWO_AbortTransfer (void); +extern void SWO_TransferComplete (void); + +extern uint32_t SWO_Mode_UART (uint32_t enable); +extern uint32_t SWO_Baudrate_UART (uint32_t baudrate); +extern uint32_t SWO_Control_UART (uint32_t active); +extern void SWO_Capture_UART (uint8_t *buf, uint32_t num); +extern uint32_t SWO_GetCount_UART (void); + +extern uint32_t SWO_Mode_Manchester (uint32_t enable); +extern uint32_t SWO_Baudrate_Manchester (uint32_t baudrate); +extern uint32_t SWO_Control_Manchester (uint32_t active); +extern void SWO_Capture_Manchester (uint8_t *buf, uint32_t num); +extern uint32_t SWO_GetCount_Manchester (void); + +extern uint32_t UART_Transport (const uint8_t *request, uint8_t *response); +extern uint32_t UART_Configure (const uint8_t *request, uint8_t *response); +extern uint32_t UART_Control (const uint8_t *request, uint8_t *response); +extern uint32_t UART_Status (uint8_t *response); +extern uint32_t UART_Transfer (const uint8_t *request, uint8_t *response); + +extern uint8_t USB_COM_PORT_Activate (uint32_t cmd); + +extern uint32_t DAP_ProcessVendorCommand (const uint8_t *request, uint8_t *response); +extern uint32_t DAP_ProcessCommand (const uint8_t *request, uint8_t *response); +extern uint32_t DAP_ExecuteCommand (const uint8_t *request, uint8_t *response); + +extern void DAP_Setup (void); + +// Configurable delay for clock generation +#ifndef DELAY_SLOW_CYCLES +#define DELAY_SLOW_CYCLES 3U // Number of cycles for one iteration +#endif +#ifndef PIN_DELAY_SLOW +#if defined(__riscv) || defined(__CC_ARM) +/* Inline assembly delay loop — MUST NOT be a pure C empty loop because + * #pragma GCC optimize("O3") in SW_DP.c would remove it as dead code, + * collapsing the SWD clock to maximum speed and breaking communication. */ +__STATIC_FORCEINLINE void PIN_DELAY_SLOW (uint32_t delay) { + __ASM_VOLATILE ( + "1:\n\t" + "addi %0, %0, -1\n\t" + "bnez %0, 1b\n\t" + : "+r" (delay) + ); +} +#else +__STATIC_FORCEINLINE void PIN_DELAY_SLOW (uint32_t delay) { + __ASM volatile ( + ".syntax unified\n" + "0:\n\t" + "subs %0,%0,#1\n\t" + "bne 0b\n" + : "+l" (delay) : : "cc" + ); +} +#endif +#endif + +// Fixed delay for fast clock generation +#ifndef DELAY_FAST_CYCLES +#define DELAY_FAST_CYCLES 0U // Number of cycles: 0..3 +#endif +__STATIC_FORCEINLINE void PIN_DELAY_FAST (void) { +#if (DELAY_FAST_CYCLES >= 1U) + __NOP(); +#endif +#if (DELAY_FAST_CYCLES >= 2U) + __NOP(); +#endif +#if (DELAY_FAST_CYCLES >= 3U) + __NOP(); +#endif +} + +#ifdef __cplusplus +} +#endif + + +#endif /* __DAP_H__ */ diff --git a/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_UART.c b/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_UART.c new file mode 100644 index 0000000..a29c847 --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_UART.c @@ -0,0 +1,652 @@ +/* + * Copyright (c) 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: 1. March 2021 + * $Revision: V1.0.0 + * + * Project: CMSIS-DAP Source + * Title: UART.c CMSIS-DAP UART + * + *---------------------------------------------------------------------------*/ + +#include "DAP_config.h" +#include "DAP.h" + +#if (DAP_UART != 0) + +#ifdef DAP_FW_V1 +#error "UART Communication Port not supported in DAP V1!" +#endif + +#include "Driver_USART.h" + +#include "cmsis_os2.h" +#include + +#define UART_RX_BLOCK_SIZE 32U /* Uart Rx Block Size (must be 2^n) */ + +// USART Driver +#define _USART_Driver_(n) Driver_USART##n +#define USART_Driver_(n) _USART_Driver_(n) +extern ARM_DRIVER_USART USART_Driver_(DAP_UART_DRIVER); +#define pUSART (&USART_Driver_(DAP_UART_DRIVER)) + +// UART Configuration +#if (DAP_UART_USB_COM_PORT != 0) +static uint8_t UartTransport = DAP_UART_TRANSPORT_USB_COM_PORT; +#else +static uint8_t UartTransport = DAP_UART_TRANSPORT_NONE; +#endif + +// UART Flags +static uint8_t UartConfigured = 0U; +static uint8_t UartReceiveEnabled = 0U; +static uint8_t UartTransmitEnabled = 0U; +static uint8_t UartTransmitActive = 0U; + +// UART TX Buffer +static uint8_t UartTxBuf[DAP_UART_TX_BUFFER_SIZE]; +static volatile uint32_t UartTxIndexI = 0U; +static volatile uint32_t UartTxIndexO = 0U; + +// UART RX Buffer +static uint8_t UartRxBuf[DAP_UART_RX_BUFFER_SIZE]; +static volatile uint32_t UartRxIndexI = 0U; +static volatile uint32_t UartRxIndexO = 0U; + +// Uart Errors +static volatile uint8_t UartErrorRxDataLost = 0U; +static volatile uint8_t UartErrorFraming = 0U; +static volatile uint8_t UartErrorParity = 0U; + +// UART Transmit +static uint32_t UartTxNum = 0U; + +// Function prototypes +static uint8_t UART_Init (void); +static void UART_Uninit (void); +static uint8_t UART_Get_Status (void); +static uint8_t UART_Receive_Enable (void); +static uint8_t UART_Transmit_Enable (void); +static void UART_Receive_Disable (void); +static void UART_Transmit_Disable (void); +static void UART_Receive_Flush (void); +static void UART_Transmit_Flush (void); +static void UART_Receive (void); +static void UART_Transmit (void); + + +// USART Driver Callback function +// event: event mask +static void USART_Callback (uint32_t event) { + if (event & ARM_USART_EVENT_SEND_COMPLETE) { + UartTxIndexO += UartTxNum; + UartTransmitActive = 0U; + UART_Transmit(); + } + if (event & ARM_USART_EVENT_RECEIVE_COMPLETE) { + UartRxIndexI += UART_RX_BLOCK_SIZE; + UART_Receive(); + } + if (event & ARM_USART_EVENT_RX_OVERFLOW) { + UartErrorRxDataLost = 1U; + } + if (event & ARM_USART_EVENT_RX_FRAMING_ERROR) { + UartErrorFraming = 1U; + } + if (event & ARM_USART_EVENT_RX_PARITY_ERROR) { + UartErrorParity = 1U; + } +} + +// Init UART +// return: DAP_OK or DAP_ERROR +static uint8_t UART_Init (void) { + int32_t status; + uint8_t ret = DAP_ERROR; + + UartConfigured = 0U; + UartReceiveEnabled = 0U; + UartTransmitEnabled = 0U; + UartTransmitActive = 0U; + UartErrorRxDataLost = 0U; + UartErrorFraming = 0U; + UartErrorParity = 0U; + UartTxIndexI = 0U; + UartTxIndexO = 0U; + UartRxIndexI = 0U; + UartRxIndexO = 0U; + UartTxNum = 0U; + + status = pUSART->Initialize(USART_Callback); + if (status == ARM_DRIVER_OK) { + status = pUSART->PowerControl(ARM_POWER_FULL); + } + if (status == ARM_DRIVER_OK) { + ret = DAP_OK; + } + + return (ret); +} + +// Un-Init UART +static void UART_Uninit (void) { + UartConfigured = 0U; + + pUSART->PowerControl(ARM_POWER_OFF); + pUSART->Uninitialize(); +} + +// Get UART Status +// return: status +static uint8_t UART_Get_Status (void) { + uint8_t status = 0U; + + if (UartReceiveEnabled != 0U) { + status |= DAP_UART_STATUS_RX_ENABLED; + } + if (UartErrorRxDataLost != 0U) { + UartErrorRxDataLost = 0U; + status |= DAP_UART_STATUS_RX_DATA_LOST; + } + if (UartErrorFraming != 0U) { + UartErrorFraming = 0U; + status |= DAP_UART_STATUS_FRAMING_ERROR; + } + if (UartErrorParity != 0U) { + UartErrorParity = 0U; + status |= DAP_UART_STATUS_PARITY_ERROR; + } + if (UartTransmitEnabled != 0U) { + status |= DAP_UART_STATUS_TX_ENABLED; + } + + return (status); +} + +// Enable UART Receive +// return: DAP_OK or DAP_ERROR +static uint8_t UART_Receive_Enable (void) { + int32_t status; + uint8_t ret = DAP_ERROR; + + if (UartReceiveEnabled == 0U) { + // Flush Buffers + UartRxIndexI = 0U; + UartRxIndexO = 0U; + + UART_Receive(); + status = pUSART->Control(ARM_USART_CONTROL_RX, 1U); + if (status == ARM_DRIVER_OK) { + UartReceiveEnabled = 1U; + ret = DAP_OK; + } + } else { + ret = DAP_OK; + } + + return (ret); +} + +// Enable UART Transmit +// return: DAP_OK or DAP_ERROR +static uint8_t UART_Transmit_Enable (void) { + int32_t status; + uint8_t ret = DAP_ERROR; + + if (UartTransmitEnabled == 0U) { + // Flush Buffers + UartTransmitActive = 0U; + UartTxIndexI = 0U; + UartTxIndexO = 0U; + UartTxNum = 0U; + + status = pUSART->Control(ARM_USART_CONTROL_TX, 1U); + if (status == ARM_DRIVER_OK) { + UartTransmitEnabled = 1U; + ret = DAP_OK; + } + } else { + ret = DAP_OK; + } + + return (ret); +} + +// Disable UART Receive +static void UART_Receive_Disable (void) { + if (UartReceiveEnabled != 0U) { + pUSART->Control(ARM_USART_CONTROL_RX, 0U); + pUSART->Control(ARM_USART_ABORT_RECEIVE, 0U); + UartReceiveEnabled = 0U; + } +} + +// Disable UART Transmit +static void UART_Transmit_Disable (void) { + if (UartTransmitEnabled != 0U) { + pUSART->Control(ARM_USART_ABORT_SEND, 0U); + pUSART->Control(ARM_USART_CONTROL_TX, 0U); + UartTransmitActive = 0U; + UartTransmitEnabled = 0U; + } +} + +// Flush UART Receive buffer +static void UART_Receive_Flush (void) { + pUSART->Control(ARM_USART_ABORT_RECEIVE, 0U); + UartRxIndexI = 0U; + UartRxIndexO = 0U; + if (UartReceiveEnabled != 0U) { + UART_Receive(); + } +} + +// Flush UART Transmit buffer +static void UART_Transmit_Flush (void) { + pUSART->Control(ARM_USART_ABORT_SEND, 0U); + UartTransmitActive = 0U; + UartTxIndexI = 0U; + UartTxIndexO = 0U; + UartTxNum = 0U; +} + +// Receive data from target via UART +static void UART_Receive (void) { + uint32_t index; + + index = UartRxIndexI & (DAP_UART_RX_BUFFER_SIZE - 1U); + pUSART->Receive(&UartRxBuf[index], UART_RX_BLOCK_SIZE); +} + +// Transmit available data to target via UART +static void UART_Transmit (void) { + uint32_t count; + uint32_t index; + + count = UartTxIndexI - UartTxIndexO; + index = UartTxIndexO & (DAP_UART_TX_BUFFER_SIZE - 1U); + + if (count != 0U) { + if ((index + count) <= DAP_UART_TX_BUFFER_SIZE) { + UartTxNum = count; + } else { + UartTxNum = DAP_UART_TX_BUFFER_SIZE - index; + } + UartTransmitActive = 1U; + pUSART->Send(&UartTxBuf[index], UartTxNum); + } +} + +// Process UART Transport command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t UART_Transport (const uint8_t *request, uint8_t *response) { + uint8_t transport; + uint8_t ret = DAP_ERROR; + + transport = *request; + switch (transport) { + case DAP_UART_TRANSPORT_NONE: + switch (UartTransport) { + case DAP_UART_TRANSPORT_NONE: + ret = DAP_OK; + break; + case DAP_UART_TRANSPORT_USB_COM_PORT: +#if (DAP_UART_USB_COM_PORT != 0) + USB_COM_PORT_Activate(0U); + UartTransport = DAP_UART_TRANSPORT_NONE; + ret = DAP_OK; +#endif + break; + case DAP_UART_TRANSPORT_DAP_COMMAND: + UART_Receive_Disable(); + UART_Transmit_Disable(); + UART_Uninit(); + UartTransport = DAP_UART_TRANSPORT_NONE; + ret= DAP_OK; + break; + } + break; + case DAP_UART_TRANSPORT_USB_COM_PORT: + switch (UartTransport) { + case DAP_UART_TRANSPORT_NONE: +#if (DAP_UART_USB_COM_PORT != 0) + if (USB_COM_PORT_Activate(1U) == 0U) { + UartTransport = DAP_UART_TRANSPORT_USB_COM_PORT; + ret = DAP_OK; + } +#endif + break; + case DAP_UART_TRANSPORT_USB_COM_PORT: + ret = DAP_OK; + break; + case DAP_UART_TRANSPORT_DAP_COMMAND: + UART_Receive_Disable(); + UART_Transmit_Disable(); + UART_Uninit(); + UartTransport = DAP_UART_TRANSPORT_NONE; +#if (DAP_UART_USB_COM_PORT != 0) + if (USB_COM_PORT_Activate(1U) == 0U) { + UartTransport = DAP_UART_TRANSPORT_USB_COM_PORT; + ret = DAP_OK; + } +#endif + break; + } + break; + case DAP_UART_TRANSPORT_DAP_COMMAND: + switch (UartTransport) { + case DAP_UART_TRANSPORT_NONE: + ret = UART_Init(); + if (ret == DAP_OK) { + UartTransport = DAP_UART_TRANSPORT_DAP_COMMAND; + } + break; + case DAP_UART_TRANSPORT_USB_COM_PORT: +#if (DAP_UART_USB_COM_PORT != 0) + USB_COM_PORT_Activate(0U); + UartTransport = DAP_UART_TRANSPORT_NONE; +#endif + ret = UART_Init(); + if (ret == DAP_OK) { + UartTransport = DAP_UART_TRANSPORT_DAP_COMMAND; + } + break; + case DAP_UART_TRANSPORT_DAP_COMMAND: + ret = DAP_OK; + break; + } + break; + default: + break; + } + + *response = ret; + + return ((1U << 16) | 1U); +} + +// Process UART Configure command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t UART_Configure (const uint8_t *request, uint8_t *response) { + uint8_t control, status; + uint32_t baudrate; + int32_t result; + + if (UartTransport != DAP_UART_TRANSPORT_DAP_COMMAND) { + status = DAP_UART_CFG_ERROR_DATA_BITS | + DAP_UART_CFG_ERROR_PARITY | + DAP_UART_CFG_ERROR_STOP_BITS; + baudrate = 0U; // baudrate error + } else { + + status = 0U; + control = *request; + baudrate = (uint32_t)(*(request+1) << 0) | + (uint32_t)(*(request+2) << 8) | + (uint32_t)(*(request+3) << 16) | + (uint32_t)(*(request+4) << 24); + + result = pUSART->Control(control | + ARM_USART_MODE_ASYNCHRONOUS | + ARM_USART_FLOW_CONTROL_NONE, + baudrate); + if (result == ARM_DRIVER_OK) { + UartConfigured = 1U; + } else { + UartConfigured = 0U; + switch (result) { + case ARM_USART_ERROR_BAUDRATE: + status = 0U; + baudrate = 0U; + break; + case ARM_USART_ERROR_DATA_BITS: + status = DAP_UART_CFG_ERROR_DATA_BITS; + break; + case ARM_USART_ERROR_PARITY: + status = DAP_UART_CFG_ERROR_PARITY; + break; + case ARM_USART_ERROR_STOP_BITS: + status = DAP_UART_CFG_ERROR_STOP_BITS; + break; + default: + status = DAP_UART_CFG_ERROR_DATA_BITS | + DAP_UART_CFG_ERROR_PARITY | + DAP_UART_CFG_ERROR_STOP_BITS; + baudrate = 0U; + break; + } + } + } + + *response++ = status; + *response++ = (uint8_t)(baudrate >> 0); + *response++ = (uint8_t)(baudrate >> 8); + *response++ = (uint8_t)(baudrate >> 16); + *response = (uint8_t)(baudrate >> 24); + + return ((5U << 16) | 5U); +} + +// Process UART Control command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t UART_Control (const uint8_t *request, uint8_t *response) { + uint8_t control; + uint8_t result; + uint8_t ret = DAP_OK; + + if (UartTransport != DAP_UART_TRANSPORT_DAP_COMMAND) { + ret = DAP_ERROR; + } else { + + control = *request; + + if ((control & DAP_UART_CONTROL_RX_DISABLE) != 0U) { + // Receive disable + UART_Receive_Disable(); + } else if ((control & DAP_UART_CONTROL_RX_ENABLE) != 0U) { + // Receive enable + if (UartConfigured != 0U) { + result = UART_Receive_Enable(); + if (result != DAP_OK) { + ret = DAP_ERROR; + } + } else { + ret = DAP_ERROR; + } + } + if ((control & DAP_UART_CONTROL_RX_BUF_FLUSH) != 0U) { + UART_Receive_Flush(); + } + + if ((control & DAP_UART_CONTROL_TX_DISABLE) != 0U) { + // Transmit disable + UART_Transmit_Disable(); + } else if ((control & DAP_UART_CONTROL_TX_ENABLE) != 0U) { + // Transmit enable + if (UartConfigured != 0U) { + result = UART_Transmit_Enable(); + if (result != DAP_OK) { + ret = DAP_ERROR; + } + } else { + ret = DAP_ERROR; + } + } + if ((control & DAP_UART_CONTROL_TX_BUF_FLUSH) != 0U) { + UART_Transmit_Flush(); + } + } + + *response = ret; + + return ((1U << 16) | 1U); +} + +// Process UART Status command and prepare response +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t UART_Status (uint8_t *response) { + uint32_t rx_cnt, tx_cnt; + uint32_t cnt; + uint8_t status; + + if ((UartTransport != DAP_UART_TRANSPORT_DAP_COMMAND) || + (UartConfigured == 0U)) { + rx_cnt = 0U; + tx_cnt = 0U; + status = 0U; + } else { + + rx_cnt = UartRxIndexI - UartRxIndexO; + rx_cnt += pUSART->GetRxCount(); + if (rx_cnt > (DAP_UART_RX_BUFFER_SIZE - (UART_RX_BLOCK_SIZE*2))) { + // Overflow + UartErrorRxDataLost = 1U; + rx_cnt = (DAP_UART_RX_BUFFER_SIZE - (UART_RX_BLOCK_SIZE*2)); + UartRxIndexO = UartRxIndexI - rx_cnt; + } + + tx_cnt = UartTxIndexI - UartTxIndexO; + cnt = pUSART->GetTxCount(); + if (UartTransmitActive != 0U) { + tx_cnt -= cnt; + } + + status = UART_Get_Status(); + } + + *response++ = status; + *response++ = (uint8_t)(rx_cnt >> 0); + *response++ = (uint8_t)(rx_cnt >> 8); + *response++ = (uint8_t)(rx_cnt >> 16); + *response++ = (uint8_t)(rx_cnt >> 24); + *response++ = (uint8_t)(tx_cnt >> 0); + *response++ = (uint8_t)(tx_cnt >> 8); + *response++ = (uint8_t)(tx_cnt >> 16); + *response = (uint8_t)(tx_cnt >> 24); + + return ((0U << 16) | 9U); +} + +// Process UART Transfer command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t UART_Transfer (const uint8_t *request, uint8_t *response) { + uint32_t rx_cnt, tx_cnt; + uint32_t rx_num, tx_num; + uint8_t *rx_data; + const + uint8_t *tx_data; + uint32_t num; + uint32_t index; + uint8_t status; + + if (UartTransport != DAP_UART_TRANSPORT_DAP_COMMAND) { + status = 0U; + rx_cnt = 0U; + tx_cnt = 0U; + } else { + + // RX Data + rx_cnt = ((uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8)); + + if (rx_cnt > (DAP_PACKET_SIZE - 6U)) { + rx_cnt = (DAP_PACKET_SIZE - 6U); + } + rx_num = UartRxIndexI - UartRxIndexO; + rx_num += pUSART->GetRxCount(); + if (rx_num > (DAP_UART_RX_BUFFER_SIZE - (UART_RX_BLOCK_SIZE*2))) { + // Overflow + UartErrorRxDataLost = 1U; + rx_num = (DAP_UART_RX_BUFFER_SIZE - (UART_RX_BLOCK_SIZE*2)); + UartRxIndexO = UartRxIndexI - rx_num; + } + if (rx_cnt > rx_num) { + rx_cnt = rx_num; + } + + rx_data = (response+5); + index = UartRxIndexO & (DAP_UART_RX_BUFFER_SIZE - 1U); + if ((index + rx_cnt) <= DAP_UART_RX_BUFFER_SIZE) { + memcpy( rx_data, &UartRxBuf[index], rx_cnt); + } else { + num = DAP_UART_RX_BUFFER_SIZE - index; + memcpy( rx_data, &UartRxBuf[index], num); + memcpy(&rx_data[num], &UartRxBuf[0], rx_cnt - num); + } + UartRxIndexO += rx_cnt; + + // TX Data + tx_cnt = ((uint32_t)(*(request+2) << 0) | + (uint32_t)(*(request+3) << 8)); + tx_data = (request+4); + + if (tx_cnt > (DAP_PACKET_SIZE - 5U)) { + tx_cnt = (DAP_PACKET_SIZE - 5U); + } + tx_num = UartTxIndexI - UartTxIndexO; + num = pUSART->GetTxCount(); + if (UartTransmitActive != 0U) { + tx_num -= num; + } + if (tx_cnt > (DAP_UART_TX_BUFFER_SIZE - tx_num)) { + tx_cnt = (DAP_UART_TX_BUFFER_SIZE - tx_num); + } + + index = UartTxIndexI & (DAP_UART_TX_BUFFER_SIZE - 1U); + if ((index + tx_cnt) <= DAP_UART_TX_BUFFER_SIZE) { + memcpy(&UartTxBuf[index], tx_data, tx_cnt); + } else { + num = DAP_UART_TX_BUFFER_SIZE - index; + memcpy(&UartTxBuf[index], tx_data, num); + memcpy(&UartTxBuf[0], &tx_data[num], tx_cnt - num); + } + UartTxIndexI += tx_cnt; + + if (UartTransmitActive == 0U) { + UART_Transmit(); + } + + status = UART_Get_Status(); + } + + *response++ = status; + *response++ = (uint8_t)(tx_cnt >> 0); + *response++ = (uint8_t)(tx_cnt >> 8); + *response++ = (uint8_t)(rx_cnt >> 0); + *response = (uint8_t)(rx_cnt >> 8); + + return (((4U + tx_cnt) << 16) | (5U + rx_cnt)); +} + +#endif /* DAP_UART */ diff --git a/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_queue.c b/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_queue.c new file mode 100644 index 0000000..d743ba9 --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_queue.c @@ -0,0 +1,96 @@ +/** + * @file DAP_queue.c + * @brief DAP processing queue + * + * DAPLink Interface Firmware + * Copyright (c) 2019, 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 + * + * http://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. + */ + +#include +#include "DAP_queue.h" +#include "daplink_vendor_commands.h" +#include "main_interface.h" + +void DAP_queue_init(DAP_queue * queue) +{ + queue->recv_idx = 0; + queue->send_idx = 0; + queue->free_count = FREE_COUNT_INIT; + queue->send_count = SEND_COUNT_INIT; +} + +/* + * Get the a buffer from the DAP_queue where the response to the request is stored + * Parameters: queue - DAP queue, buf = return the buffer location, len = return the len of the response + * Return Value: TRUE - Success, FALSE - Error + */ + +BOOL DAP_queue_get_send_buf(DAP_queue * queue, uint8_t ** buf, int * len) +{ + if (queue->send_count) { + queue->send_count--; + *buf = queue->USB_Request[queue->send_idx]; + *len = queue->resp_size[queue->send_idx]; + queue->send_idx = (queue->send_idx + 1) % DAP_PACKET_COUNT; + queue->free_count++; + return (__TRUE); + } + return (__FALSE); +} + +/* + * Overridable function to determine if the DAP activity should trigger or + * not the HID LED to flash. + * Parameters: buf: buffer with DAP request + * Return Value: 1 if DAP activity should blink the HID LED, 0 otherwise + */ +__WEAK uint8_t DAP_activity_blink(const uint8_t *buf) +{ + // Skip UART and MSD DAPLink Vendor DAP commands as they already produce LED blinks + return (buf[0] == ID_DAP_UART_Read || + buf[0] == ID_DAP_UART_Write || + buf[0] == ID_DAP_MSD_Write) ? 0 : 1; +} + +/* + * Execute a request and store result to the DAP_queue + * Parameters: queue - DAP queue, reqbuf = buffer with DAP request, len = of the request buffer, retbuf = buffer to peek on the result of the DAP operation + * Return Value: TRUE - Success, FALSE - Error + */ + + +BOOL DAP_queue_execute_buf(DAP_queue * queue, const uint8_t *reqbuf, int len, uint8_t ** retbuf) +{ + uint32_t rsize; + if (queue->free_count > 0) { + if (DAP_activity_blink(reqbuf)) { + main_blink_hid_led(MAIN_LED_FLASH); + } + + if (len > DAP_PACKET_SIZE) { + len = DAP_PACKET_SIZE; + } + queue->free_count--; + memcpy(queue->USB_Request[queue->recv_idx], reqbuf, len); + rsize = DAP_ExecuteCommand(reqbuf, queue->USB_Request[queue->recv_idx]); + queue->resp_size[queue->recv_idx] = rsize & 0xFFFF; //get the response size + *retbuf = queue->USB_Request[queue->recv_idx]; + queue->recv_idx = (queue->recv_idx + 1) % DAP_PACKET_COUNT; + queue->send_count++; + return (__TRUE); + } + return (__FALSE); +} diff --git a/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_queue.h b/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_queue.h new file mode 100644 index 0000000..94d27c4 --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_queue.h @@ -0,0 +1,65 @@ +/** + * @file DAP_queue.h + * @brief DAP processing queue + * + * DAPLink Interface Firmware + * Copyright (c) 2019, 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 + * + * http://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. + */ + +#ifndef DAP_QUEUE_H +#define DAP_QUEUE_H + +#include "usb_def.h" +#include "DAP_config.h" +#include "DAP.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FREE_COUNT_INIT (DAP_PACKET_COUNT) +#define SEND_COUNT_INIT 0 + +typedef struct _DAP_queue { + uint8_t USB_Request [DAP_PACKET_COUNT][DAP_PACKET_SIZE]; // Request Buffer + uint16_t resp_size[DAP_PACKET_COUNT]; //track the return response size + uint32_t free_count; + uint32_t send_count; + uint32_t recv_idx; + uint32_t send_idx; +} DAP_queue; + +void DAP_queue_init(DAP_queue * queue); + +/* + * Get the a buffer from the DAP_queue where the response to the request is stored + * Parameters: queue - DAP queue, buf = return the buffer location, len = return the len of the response + * Return Value: TRUE - Success, FALSE - Error + */ +BOOL DAP_queue_get_send_buf(DAP_queue * queue, uint8_t ** buf, int * len); + +/* + * Execute a request and store result to the DAP_queue + * Parameters: queue - DAP queue, reqbuf = buffer with DAP request, len = of the request buffer, retbuf = buffer to peek on the result of the DAP operation + * Return Value: TRUE - Success, FALSE - Error + */ +BOOL DAP_queue_execute_buf(DAP_queue * queue, const uint8_t *reqbuf, int len, uint8_t ** retbuf); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_vendor.c b/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_vendor.c new file mode 100644 index 0000000..166deef --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cmsis-dap/DAP_vendor.c @@ -0,0 +1,14 @@ +/** + * @file DAP_vendor.c + * @brief CMSIS-DAP Vendor Commands Stub for BL702 + * + * Minimal stub: vendor commands are not needed for basic CMSIS-DAP operation. + */ + +#include "DAP.h" + +__WEAK uint32_t DAP_ProcessVendorCommand(const uint8_t *request, uint8_t *response) { + (void)request; + *response = ID_DAP_Invalid; + return ((1U << 16) | 1U); +} diff --git a/firmware/app/daplink_bl702/daplink/cmsis-dap/Driver_USART.h b/firmware/app/daplink_bl702/daplink/cmsis-dap/Driver_USART.h new file mode 100644 index 0000000..c35f469 --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cmsis-dap/Driver_USART.h @@ -0,0 +1,57 @@ +/** + * @file Driver_USART.h + * @brief Minimal CMSIS-Driver USART stub for BL702 SWO + * + * The CMSIS-DAP SWO.c expects an ARM CMSIS-Driver USART interface. + * Since BL702 uses its own UART HAL, this stub provides the type + * definitions expected by SWO.c for compilation only — the actual + * SWO UART functions are implemented in swo_uart_bl702.c and + * override the __WEAK implementations in SWO.c at link time. + */ + +#ifndef __DRIVER_USART_H__ +#define __DRIVER_USART_H__ + +#include + +/* ARM_USART status bits */ +#define ARM_USART_EVENT_RECEIVE_COMPLETE (1U << 0) +#define ARM_USART_EVENT_TX_COMPLETE (1U << 1) +#define ARM_USART_EVENT_RX_OVERFLOW (1U << 2) +#define ARM_USART_EVENT_RX_BREAK (1U << 3) +#define ARM_USART_EVENT_RX_FRAMING_ERROR (1U << 4) +#define ARM_USART_EVENT_RX_PARITY_ERROR (1U << 5) + +/* ARM_USART control codes */ +#define ARM_USART_MODE_ASYNCHRONOUS (0x01U) +#define ARM_USART_DATA_BITS_8 (0x03U << 4) +#define ARM_USART_PARITY_NONE (0x00U << 6) +#define ARM_USART_STOP_BITS_1 (0x00U << 8) +#define ARM_USART_CONTROL_RX (0x02U) +#define ARM_USART_ABORT_RECEIVE (0x1002U) + +/* ARM Driver status codes */ +#define ARM_DRIVER_OK 0 + +/* ARM Power states */ +#define ARM_POWER_OFF 0 +#define ARM_POWER_FULL (1U << 0) + +/* USART Status */ +typedef struct { + uint8_t rx_busy; + uint8_t tx_busy; +} ARM_USART_STATUS; + +/* USART Driver — function pointer table (never called, for compilation only) */ +typedef struct _ARM_DRIVER_USART { + int32_t (*Initialize) (void *cb); + int32_t (*Uninitialize) (void); + int32_t (*PowerControl) (uint32_t state); + int32_t (*Control) (uint32_t control, uint32_t arg); + int32_t (*Receive) (void *buf, uint32_t num); + ARM_USART_STATUS (*GetStatus) (void); + uint32_t (*GetRxCount) (void); +} ARM_DRIVER_USART; + +#endif /* __DRIVER_USART_H__ */ diff --git a/firmware/app/daplink_bl702/daplink/cmsis-dap/JTAG_DP.c b/firmware/app/daplink_bl702/daplink/cmsis-dap/JTAG_DP.c new file mode 100644 index 0000000..24b1f3f --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cmsis-dap/JTAG_DP.c @@ -0,0 +1,370 @@ +/* + * 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" + + +// JTAG Macros + +#define PIN_TCK_SET PIN_SWCLK_TCK_SET +#define PIN_TCK_CLR PIN_SWCLK_TCK_CLR +#define PIN_TMS_SET PIN_SWDIO_TMS_SET +#define PIN_TMS_CLR PIN_SWDIO_TMS_CLR + +#define JTAG_CYCLE_TCK() \ + PIN_TCK_CLR(); \ + PIN_DELAY(); \ + PIN_TCK_SET(); \ + PIN_DELAY() + +#define JTAG_CYCLE_TDI(tdi) \ + PIN_TDI_OUT(tdi); \ + PIN_TCK_CLR(); \ + PIN_DELAY(); \ + PIN_TCK_SET(); \ + PIN_DELAY() + +#define JTAG_CYCLE_TDO(tdo) \ + PIN_TCK_CLR(); \ + PIN_DELAY(); \ + tdo = PIN_TDO_IN(); \ + PIN_TCK_SET(); \ + PIN_DELAY() + +#define JTAG_CYCLE_TDIO(tdi,tdo) \ + PIN_TDI_OUT(tdi); \ + PIN_TCK_CLR(); \ + PIN_DELAY(); \ + tdo = PIN_TDO_IN(); \ + PIN_TCK_SET(); \ + PIN_DELAY() + +#define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) + + +#if (DAP_JTAG != 0) + + +// 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) { + uint32_t i_val; + uint32_t o_val; + uint32_t bit; + uint32_t n, k; + + n = info & JTAG_SEQUENCE_TCK; + if (n == 0U) { + n = 64U; + } + + if (info & JTAG_SEQUENCE_TMS) { + PIN_TMS_SET(); + } else { + PIN_TMS_CLR(); + } + + while (n) { + i_val = *tdi++; + o_val = 0U; + for (k = 8U; k && n; k--, n--) { + JTAG_CYCLE_TDIO(i_val, bit); + i_val >>= 1; + o_val >>= 1; + o_val |= bit << 7; + } + o_val >>= k; + if (info & JTAG_SEQUENCE_TDO) { + *tdo++ = (uint8_t)o_val; + } + } +} + + +// JTAG Set IR +// ir: IR value +// return: none +#define JTAG_IR_Function(speed) /**/ \ +static void JTAG_IR_##speed (uint32_t ir) { \ + uint32_t n; \ + \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Select-DR-Scan */ \ + JTAG_CYCLE_TCK(); /* Select-IR-Scan */ \ + PIN_TMS_CLR(); \ + JTAG_CYCLE_TCK(); /* Capture-IR */ \ + JTAG_CYCLE_TCK(); /* Shift-IR */ \ + \ + PIN_TDI_OUT(1U); \ + for (n = DAP_Data.jtag_dev.ir_before[DAP_Data.jtag_dev.index]; n; n--) { \ + JTAG_CYCLE_TCK(); /* Bypass before data */ \ + } \ + for (n = DAP_Data.jtag_dev.ir_length[DAP_Data.jtag_dev.index] - 1U; n; n--) { \ + JTAG_CYCLE_TDI(ir); /* Set IR bits (except last) */ \ + ir >>= 1; \ + } \ + n = DAP_Data.jtag_dev.ir_after[DAP_Data.jtag_dev.index]; \ + if (n) { \ + JTAG_CYCLE_TDI(ir); /* Set last IR bit */ \ + PIN_TDI_OUT(1U); \ + for (--n; n; n--) { \ + JTAG_CYCLE_TCK(); /* Bypass after data */ \ + } \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Bypass & Exit1-IR */ \ + } else { \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TDI(ir); /* Set last IR bit & Exit1-IR */ \ + } \ + \ + JTAG_CYCLE_TCK(); /* Update-IR */ \ + PIN_TMS_CLR(); \ + JTAG_CYCLE_TCK(); /* Idle */ \ + PIN_TDI_OUT(1U); \ +} + + +// JTAG Transfer I/O +// request: A[3:2] RnW APnDP +// data: DATA[31:0] +// return: ACK[2:0] +#define JTAG_TransferFunction(speed) /**/ \ +static uint8_t JTAG_Transfer##speed (uint32_t request, uint32_t *data) { \ + uint32_t ack; \ + uint32_t bit; \ + uint32_t val; \ + uint32_t n; \ + \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Select-DR-Scan */ \ + PIN_TMS_CLR(); \ + JTAG_CYCLE_TCK(); /* Capture-DR */ \ + JTAG_CYCLE_TCK(); /* Shift-DR */ \ + \ + for (n = DAP_Data.jtag_dev.index; n; n--) { \ + JTAG_CYCLE_TCK(); /* Bypass before data */ \ + } \ + \ + JTAG_CYCLE_TDIO(request >> 1, bit); /* Set RnW, Get ACK.0 */ \ + ack = bit << 1; \ + JTAG_CYCLE_TDIO(request >> 2, bit); /* Set A2, Get ACK.1 */ \ + ack |= bit << 0; \ + JTAG_CYCLE_TDIO(request >> 3, bit); /* Set A3, Get ACK.2 */ \ + ack |= bit << 2; \ + \ + if (ack != DAP_TRANSFER_OK) { \ + /* Exit on error */ \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Exit1-DR */ \ + goto exit; \ + } \ + \ + if (request & DAP_TRANSFER_RnW) { \ + /* Read Transfer */ \ + val = 0U; \ + for (n = 31U; n; n--) { \ + JTAG_CYCLE_TDO(bit); /* Get D0..D30 */ \ + val |= bit << 31; \ + val >>= 1; \ + } \ + n = DAP_Data.jtag_dev.count - DAP_Data.jtag_dev.index - 1U; \ + if (n) { \ + JTAG_CYCLE_TDO(bit); /* Get D31 */ \ + for (--n; n; n--) { \ + JTAG_CYCLE_TCK(); /* Bypass after data */ \ + } \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Bypass & Exit1-DR */ \ + } else { \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TDO(bit); /* Get D31 & Exit1-DR */ \ + } \ + val |= bit << 31; \ + if (data) { *data = val; } \ + } else { \ + /* Write Transfer */ \ + val = *data; \ + for (n = 31U; n; n--) { \ + JTAG_CYCLE_TDI(val); /* Set D0..D30 */ \ + val >>= 1; \ + } \ + n = DAP_Data.jtag_dev.count - DAP_Data.jtag_dev.index - 1U; \ + if (n) { \ + JTAG_CYCLE_TDI(val); /* Set D31 */ \ + for (--n; n; n--) { \ + JTAG_CYCLE_TCK(); /* Bypass after data */ \ + } \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Bypass & Exit1-DR */ \ + } else { \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TDI(val); /* Set D31 & Exit1-DR */ \ + } \ + } \ + \ +exit: \ + JTAG_CYCLE_TCK(); /* Update-DR */ \ + PIN_TMS_CLR(); \ + JTAG_CYCLE_TCK(); /* Idle */ \ + PIN_TDI_OUT(1U); \ + \ + /* Capture Timestamp */ \ + if (request & DAP_TRANSFER_TIMESTAMP) { \ + DAP_Data.timestamp = TIMESTAMP_GET(); \ + } \ + \ + /* Idle cycles */ \ + n = DAP_Data.transfer.idle_cycles; \ + while (n--) { \ + JTAG_CYCLE_TCK(); /* Idle */ \ + } \ + \ + return ((uint8_t)ack); \ +} + + +#undef PIN_DELAY +#define PIN_DELAY() PIN_DELAY_FAST() +JTAG_IR_Function(Fast) +JTAG_TransferFunction(Fast) + +#undef PIN_DELAY +#define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) +JTAG_IR_Function(Slow) +JTAG_TransferFunction(Slow) + + +// JTAG Read IDCODE register +// return: value read +uint32_t JTAG_ReadIDCode (void) { + uint32_t bit; + uint32_t val; + uint32_t n; + + PIN_TMS_SET(); + JTAG_CYCLE_TCK(); /* Select-DR-Scan */ + PIN_TMS_CLR(); + JTAG_CYCLE_TCK(); /* Capture-DR */ + JTAG_CYCLE_TCK(); /* Shift-DR */ + + for (n = DAP_Data.jtag_dev.index; n; n--) { + JTAG_CYCLE_TCK(); /* Bypass before data */ + } + + val = 0U; + for (n = 31U; n; n--) { + JTAG_CYCLE_TDO(bit); /* Get D0..D30 */ + val |= bit << 31; + val >>= 1; + } + PIN_TMS_SET(); + JTAG_CYCLE_TDO(bit); /* Get D31 & Exit1-DR */ + val |= bit << 31; + + JTAG_CYCLE_TCK(); /* Update-DR */ + PIN_TMS_CLR(); + JTAG_CYCLE_TCK(); /* Idle */ + + return (val); +} + + +// JTAG Write ABORT register +// data: value to write +// return: none +void JTAG_WriteAbort (uint32_t data) { + uint32_t n; + + PIN_TMS_SET(); + JTAG_CYCLE_TCK(); /* Select-DR-Scan */ + PIN_TMS_CLR(); + JTAG_CYCLE_TCK(); /* Capture-DR */ + JTAG_CYCLE_TCK(); /* Shift-DR */ + + for (n = DAP_Data.jtag_dev.index; n; n--) { + JTAG_CYCLE_TCK(); /* Bypass before data */ + } + + PIN_TDI_OUT(0U); + JTAG_CYCLE_TCK(); /* Set RnW=0 (Write) */ + JTAG_CYCLE_TCK(); /* Set A2=0 */ + JTAG_CYCLE_TCK(); /* Set A3=0 */ + + for (n = 31U; n; n--) { + JTAG_CYCLE_TDI(data); /* Set D0..D30 */ + data >>= 1; + } + n = DAP_Data.jtag_dev.count - DAP_Data.jtag_dev.index - 1U; + if (n) { + JTAG_CYCLE_TDI(data); /* Set D31 */ + for (--n; n; n--) { + JTAG_CYCLE_TCK(); /* Bypass after data */ + } + PIN_TMS_SET(); + JTAG_CYCLE_TCK(); /* Bypass & Exit1-DR */ + } else { + PIN_TMS_SET(); + JTAG_CYCLE_TDI(data); /* Set D31 & Exit1-DR */ + } + + JTAG_CYCLE_TCK(); /* Update-DR */ + PIN_TMS_CLR(); + JTAG_CYCLE_TCK(); /* Idle */ + PIN_TDI_OUT(1U); +} + + +// 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); + } +} + + +#endif /* (DAP_JTAG != 0) */ diff --git a/firmware/app/daplink_bl702/daplink/cmsis-dap/SWO.c b/firmware/app/daplink_bl702/daplink/cmsis-dap/SWO.c new file mode 100644 index 0000000..4a850cf --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cmsis-dap/SWO.c @@ -0,0 +1,798 @@ +/* + * 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: 29. March 2021 + * $Revision: V2.0.1 + * + * Project: CMSIS-DAP Source + * Title: SWO.c CMSIS-DAP SWO I/O + * + *---------------------------------------------------------------------------*/ + +#include "DAP_config.h" +#include "DAP.h" +#if (SWO_UART != 0) +#include "Driver_USART.h" +#endif +#if (SWO_STREAM != 0) +#include "cmsis_os2.h" +#define osObjectsExternal +#include "osObjects.h" +#endif + +#if (SWO_STREAM != 0) +#ifdef DAP_FW_V1 +#error "SWO Streaming Trace not supported in DAP V1!" +#endif +#endif + +#if (SWO_UART != 0) + +// USART Driver +#define _USART_Driver_(n) Driver_USART##n +#define USART_Driver_(n) _USART_Driver_(n) +extern ARM_DRIVER_USART USART_Driver_(SWO_UART_DRIVER); +#define pUSART (&USART_Driver_(SWO_UART_DRIVER)) + +static uint8_t USART_Ready = 0U; + +#endif /* (SWO_UART != 0) */ + + +#if ((SWO_UART != 0) || (SWO_MANCHESTER != 0)) + + +#define SWO_STREAM_TIMEOUT 50U /* Stream timeout in ms */ + +#define USB_BLOCK_SIZE 512U /* USB Block Size */ +#define TRACE_BLOCK_SIZE 64U /* Trace Block Size (2^n: 32...512) */ + +// Trace State +static uint8_t TraceTransport = 0U; /* Trace Transport */ +static uint8_t TraceMode = 0U; /* Trace Mode */ +static uint8_t TraceStatus = 0U; /* Trace Status without Errors */ +static uint8_t TraceError[2] = {0U, 0U}; /* Trace Error flags (banked) */ +static uint8_t TraceError_n = 0U; /* Active Trace Error bank */ + +// Trace Buffer +static uint8_t TraceBuf[SWO_BUFFER_SIZE]; /* Trace Buffer (must be 2^n) */ +static volatile uint32_t TraceIndexI = 0U; /* Incoming Trace Index */ +static volatile uint32_t TraceIndexO = 0U; /* Outgoing Trace Index */ +static volatile uint8_t TraceUpdate; /* Trace Update Flag */ +static uint32_t TraceBlockSize; /* Current Trace Block Size */ + +#if (TIMESTAMP_CLOCK != 0U) +// Trace Timestamp +static volatile struct { + uint32_t index; + uint32_t tick; +} TraceTimestamp; +#endif + +// Trace Helper functions +static void ClearTrace (void); +static void ResumeTrace (void); +static uint32_t GetTraceCount (void); +static uint8_t GetTraceStatus (void); +static void SetTraceError (uint8_t flag); + +#if (SWO_STREAM != 0) +extern osThreadId_t SWO_ThreadId; +static volatile uint8_t TransferBusy = 0U; /* Transfer Busy Flag */ +static uint32_t TransferSize; /* Current Transfer Size */ +#endif + + +#if (SWO_UART != 0) + +// USART Driver Callback function +// event: event mask +static void USART_Callback (uint32_t event) { + uint32_t index_i; + uint32_t index_o; + uint32_t count; + uint32_t num; + + if (event & ARM_USART_EVENT_RECEIVE_COMPLETE) { +#if (TIMESTAMP_CLOCK != 0U) + TraceTimestamp.tick = TIMESTAMP_GET(); +#endif + index_o = TraceIndexO; + index_i = TraceIndexI; + index_i += TraceBlockSize; + TraceIndexI = index_i; +#if (TIMESTAMP_CLOCK != 0U) + TraceTimestamp.index = index_i; +#endif + num = TRACE_BLOCK_SIZE - (index_i & (TRACE_BLOCK_SIZE - 1U)); + count = index_i - index_o; + if (count <= (SWO_BUFFER_SIZE - num)) { + index_i &= SWO_BUFFER_SIZE - 1U; + TraceBlockSize = num; + pUSART->Receive(&TraceBuf[index_i], num); + } else { + TraceStatus = DAP_SWO_CAPTURE_ACTIVE | DAP_SWO_CAPTURE_PAUSED; + } + TraceUpdate = 1U; +#if (SWO_STREAM != 0) + if (TraceTransport == 2U) { + if (count >= (USB_BLOCK_SIZE - (index_o & (USB_BLOCK_SIZE - 1U)))) { + osThreadFlagsSet(SWO_ThreadId, 1U); + } + } +#endif + } + if (event & ARM_USART_EVENT_RX_OVERFLOW) { + SetTraceError(DAP_SWO_BUFFER_OVERRUN); + } + if (event & (ARM_USART_EVENT_RX_BREAK | + ARM_USART_EVENT_RX_FRAMING_ERROR | + ARM_USART_EVENT_RX_PARITY_ERROR)) { + SetTraceError(DAP_SWO_STREAM_ERROR); + } +} + +// Enable or disable SWO Mode (UART) +// enable: enable flag +// return: 1 - Success, 0 - Error +__WEAK uint32_t SWO_Mode_UART (uint32_t enable) { + int32_t status; + + USART_Ready = 0U; + + if (enable != 0U) { + status = pUSART->Initialize(USART_Callback); + if (status != ARM_DRIVER_OK) { + return (0U); + } + status = pUSART->PowerControl(ARM_POWER_FULL); + if (status != ARM_DRIVER_OK) { + pUSART->Uninitialize(); + return (0U); + } + } else { + pUSART->Control(ARM_USART_CONTROL_RX, 0U); + pUSART->Control(ARM_USART_ABORT_RECEIVE, 0U); + pUSART->PowerControl(ARM_POWER_OFF); + pUSART->Uninitialize(); + } + return (1U); +} + +// Configure SWO Baudrate (UART) +// baudrate: requested baudrate +// return: actual baudrate or 0 when not configured +__WEAK uint32_t SWO_Baudrate_UART (uint32_t baudrate) { + int32_t status; + uint32_t index; + uint32_t num; + + if (baudrate > SWO_UART_MAX_BAUDRATE) { + baudrate = SWO_UART_MAX_BAUDRATE; + } + + if (TraceStatus & DAP_SWO_CAPTURE_ACTIVE) { + pUSART->Control(ARM_USART_CONTROL_RX, 0U); + if (pUSART->GetStatus().rx_busy) { + TraceIndexI += pUSART->GetRxCount(); + pUSART->Control(ARM_USART_ABORT_RECEIVE, 0U); + } + } + + status = pUSART->Control(ARM_USART_MODE_ASYNCHRONOUS | + ARM_USART_DATA_BITS_8 | + ARM_USART_PARITY_NONE | + ARM_USART_STOP_BITS_1, + baudrate); + + if (status == ARM_DRIVER_OK) { + USART_Ready = 1U; + } else { + USART_Ready = 0U; + return (0U); + } + + if (TraceStatus & DAP_SWO_CAPTURE_ACTIVE) { + if ((TraceStatus & DAP_SWO_CAPTURE_PAUSED) == 0U) { + index = TraceIndexI & (SWO_BUFFER_SIZE - 1U); + num = TRACE_BLOCK_SIZE - (index & (TRACE_BLOCK_SIZE - 1U)); + TraceBlockSize = num; + pUSART->Receive(&TraceBuf[index], num); + } + pUSART->Control(ARM_USART_CONTROL_RX, 1U); + } + + return (baudrate); +} + +// Control SWO Capture (UART) +// active: active flag +// return: 1 - Success, 0 - Error +__WEAK uint32_t SWO_Control_UART (uint32_t active) { + int32_t status; + + if (active) { + if (!USART_Ready) { + return (0U); + } + TraceBlockSize = 1U; + status = pUSART->Receive(&TraceBuf[0], 1U); + if (status != ARM_DRIVER_OK) { + return (0U); + } + status = pUSART->Control(ARM_USART_CONTROL_RX, 1U); + if (status != ARM_DRIVER_OK) { + return (0U); + } + } else { + pUSART->Control(ARM_USART_CONTROL_RX, 0U); + if (pUSART->GetStatus().rx_busy) { + TraceIndexI += pUSART->GetRxCount(); + pUSART->Control(ARM_USART_ABORT_RECEIVE, 0U); + } + } + return (1U); +} + +// Start SWO Capture (UART) +// buf: pointer to buffer for capturing +// num: number of bytes to capture +__WEAK void SWO_Capture_UART (uint8_t *buf, uint32_t num) { + TraceBlockSize = num; + pUSART->Receive(buf, num); +} + +// Get SWO Pending Trace Count (UART) +// return: number of pending trace data bytes +__WEAK uint32_t SWO_GetCount_UART (void) { + uint32_t count; + + if (pUSART->GetStatus().rx_busy) { + count = pUSART->GetRxCount(); + } else { + count = 0U; + } + return (count); +} + +#endif /* (SWO_UART != 0) */ + + +#if (SWO_MANCHESTER != 0) + +// Enable or disable SWO Mode (Manchester) +// enable: enable flag +// return: 1 - Success, 0 - Error +__WEAK uint32_t SWO_Mode_Manchester (uint32_t enable) { + return (0U); +} + +// Configure SWO Baudrate (Manchester) +// baudrate: requested baudrate +// return: actual baudrate or 0 when not configured +__WEAK uint32_t SWO_Baudrate_Manchester (uint32_t baudrate) { + return (0U); +} + +// Control SWO Capture (Manchester) +// active: active flag +// return: 1 - Success, 0 - Error +__WEAK uint32_t SWO_Control_Manchester (uint32_t active) { + return (0U); +} + +// Start SWO Capture (Manchester) +// buf: pointer to buffer for capturing +// num: number of bytes to capture +__WEAK void SWO_Capture_Manchester (uint8_t *buf, uint32_t num) { +} + +// Get SWO Pending Trace Count (Manchester) +// return: number of pending trace data bytes +__WEAK uint32_t SWO_GetCount_Manchester (void) { +} + +#endif /* (SWO_MANCHESTER != 0) */ + + +// Clear Trace Errors and Data +static void ClearTrace (void) { + +#if (SWO_STREAM != 0) + if (TraceTransport == 2U) { + if (TransferBusy != 0U) { + SWO_AbortTransfer(); + TransferBusy = 0U; + } + } +#endif + + TraceError[0] = 0U; + TraceError[1] = 0U; + TraceError_n = 0U; + TraceIndexI = 0U; + TraceIndexO = 0U; + +#if (TIMESTAMP_CLOCK != 0U) + TraceTimestamp.index = 0U; + TraceTimestamp.tick = 0U; +#endif +} + +// Resume Trace Capture +static void ResumeTrace (void) { + uint32_t index_i; + uint32_t index_o; + + if (TraceStatus == (DAP_SWO_CAPTURE_ACTIVE | DAP_SWO_CAPTURE_PAUSED)) { + index_i = TraceIndexI; + index_o = TraceIndexO; + if ((index_i - index_o) < SWO_BUFFER_SIZE) { + index_i &= SWO_BUFFER_SIZE - 1U; + switch (TraceMode) { +#if (SWO_UART != 0) + case DAP_SWO_UART: + TraceStatus = DAP_SWO_CAPTURE_ACTIVE; + SWO_Capture_UART(&TraceBuf[index_i], 1U); + break; +#endif +#if (SWO_MANCHESTER != 0) + case DAP_SWO_MANCHESTER: + TraceStatus = DAP_SWO_CAPTURE_ACTIVE; + SWO_Capture_Manchester(&TraceBuf[index_i], 1U); + break; +#endif + default: + break; + } + } + } +} + +// Get Trace Count +// return: number of available data bytes in trace buffer +static uint32_t GetTraceCount (void) { + uint32_t count; + + if (TraceStatus == DAP_SWO_CAPTURE_ACTIVE) { + do { + TraceUpdate = 0U; + count = TraceIndexI - TraceIndexO; + switch (TraceMode) { +#if (SWO_UART != 0) + case DAP_SWO_UART: + count += SWO_GetCount_UART(); + break; +#endif +#if (SWO_MANCHESTER != 0) + case DAP_SWO_MANCHESTER: + count += SWO_GetCount_Manchester(); + break; +#endif + default: + break; + } + } while (TraceUpdate != 0U); + } else { + count = TraceIndexI - TraceIndexO; + } + + return (count); +} + +// Get Trace Status (clear Error flags) +// return: Trace Status (Active flag and Error flags) +static uint8_t GetTraceStatus (void) { + uint8_t status; + uint32_t n; + + n = TraceError_n; + TraceError_n ^= 1U; + status = TraceStatus | TraceError[n]; + TraceError[n] = 0U; + + return (status); +} + +// Set Trace Error flag(s) +// flag: error flag(s) to set +static void SetTraceError (uint8_t flag) { + TraceError[TraceError_n] |= flag; +} + + +// Process SWO Transport command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t SWO_Transport (const uint8_t *request, uint8_t *response) { + uint8_t transport; + uint32_t result; + + if ((TraceStatus & DAP_SWO_CAPTURE_ACTIVE) == 0U) { + transport = *request; + switch (transport) { + case 0U: + case 1U: +#if (SWO_STREAM != 0) + case 2U: +#endif + TraceTransport = transport; + result = 1U; + break; + default: + result = 0U; + break; + } + } else { + result = 0U; + } + + if (result != 0U) { + *response = DAP_OK; + } else { + *response = DAP_ERROR; + } + + return ((1U << 16) | 1U); +} + + +// Process SWO Mode command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t SWO_Mode (const uint8_t *request, uint8_t *response) { + uint8_t mode; + uint32_t result; + + mode = *request; + + switch (TraceMode) { +#if (SWO_UART != 0) + case DAP_SWO_UART: + SWO_Mode_UART(0U); + break; +#endif +#if (SWO_MANCHESTER != 0) + case DAP_SWO_MANCHESTER: + SWO_Mode_Manchester(0U); + break; +#endif + default: + break; + } + + switch (mode) { + case DAP_SWO_OFF: + result = 1U; + break; +#if (SWO_UART != 0) + case DAP_SWO_UART: + result = SWO_Mode_UART(1U); + break; +#endif +#if (SWO_MANCHESTER != 0) + case DAP_SWO_MANCHESTER: + result = SWO_Mode_Manchester(1U); + break; +#endif + default: + result = 0U; + break; + } + if (result != 0U) { + TraceMode = mode; + } else { + TraceMode = DAP_SWO_OFF; + } + + TraceStatus = 0U; + + if (result != 0U) { + *response = DAP_OK; + } else { + *response = DAP_ERROR; + } + + return ((1U << 16) | 1U); +} + + +// Process SWO Baudrate command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t SWO_Baudrate (const uint8_t *request, uint8_t *response) { + uint32_t baudrate; + + baudrate = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8) | + (uint32_t)(*(request+2) << 16) | + (uint32_t)(*(request+3) << 24); + + switch (TraceMode) { +#if (SWO_UART != 0) + case DAP_SWO_UART: + baudrate = SWO_Baudrate_UART(baudrate); + break; +#endif +#if (SWO_MANCHESTER != 0) + case DAP_SWO_MANCHESTER: + baudrate = SWO_Baudrate_Manchester(baudrate); + break; +#endif + default: + baudrate = 0U; + break; + } + + if (baudrate == 0U) { + TraceStatus = 0U; + } + + *response++ = (uint8_t)(baudrate >> 0); + *response++ = (uint8_t)(baudrate >> 8); + *response++ = (uint8_t)(baudrate >> 16); + *response = (uint8_t)(baudrate >> 24); + + return ((4U << 16) | 4U); +} + + +// Process SWO Control command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t SWO_Control (const uint8_t *request, uint8_t *response) { + uint8_t active; + uint32_t result; + + active = *request & DAP_SWO_CAPTURE_ACTIVE; + + if (active != (TraceStatus & DAP_SWO_CAPTURE_ACTIVE)) { + if (active) { + ClearTrace(); + } + switch (TraceMode) { +#if (SWO_UART != 0) + case DAP_SWO_UART: + result = SWO_Control_UART(active); + break; +#endif +#if (SWO_MANCHESTER != 0) + case DAP_SWO_MANCHESTER: + result = SWO_Control_Manchester(active); + break; +#endif + default: + result = 0U; + break; + } + if (result != 0U) { + TraceStatus = active; +#if (SWO_STREAM != 0) + if (TraceTransport == 2U) { + osThreadFlagsSet(SWO_ThreadId, 1U); + } +#endif + } + } else { + result = 1U; + } + + if (result != 0U) { + *response = DAP_OK; + } else { + *response = DAP_ERROR; + } + + return ((1U << 16) | 1U); +} + + +// Process SWO Status command and prepare response +// response: pointer to response data +// return: number of bytes in response +uint32_t SWO_Status (uint8_t *response) { + uint8_t status; + uint32_t count; + + status = GetTraceStatus(); + count = GetTraceCount(); + + *response++ = status; + *response++ = (uint8_t)(count >> 0); + *response++ = (uint8_t)(count >> 8); + *response++ = (uint8_t)(count >> 16); + *response = (uint8_t)(count >> 24); + + return (5U); +} + + +// Process SWO Extended Status command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t SWO_ExtendedStatus (const uint8_t *request, uint8_t *response) { + uint8_t cmd; + uint8_t status; + uint32_t count; +#if (TIMESTAMP_CLOCK != 0U) + uint32_t index; + uint32_t tick; +#endif + uint32_t num; + + num = 0U; + cmd = *request; + + if (cmd & 0x01U) { + status = GetTraceStatus(); + *response++ = status; + num += 1U; + } + + if (cmd & 0x02U) { + count = GetTraceCount(); + *response++ = (uint8_t)(count >> 0); + *response++ = (uint8_t)(count >> 8); + *response++ = (uint8_t)(count >> 16); + *response++ = (uint8_t)(count >> 24); + num += 4U; + } + +#if (TIMESTAMP_CLOCK != 0U) + if (cmd & 0x04U) { + do { + TraceUpdate = 0U; + index = TraceTimestamp.index; + tick = TraceTimestamp.tick; + } while (TraceUpdate != 0U); + *response++ = (uint8_t)(index >> 0); + *response++ = (uint8_t)(index >> 8); + *response++ = (uint8_t)(index >> 16); + *response++ = (uint8_t)(index >> 24); + *response++ = (uint8_t)(tick >> 0); + *response++ = (uint8_t)(tick >> 8); + *response++ = (uint8_t)(tick >> 16); + *response++ = (uint8_t)(tick >> 24); + num += 4U; + } +#endif + + return ((1U << 16) | num); +} + + +// Process SWO Data command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t SWO_Data (const uint8_t *request, uint8_t *response) { + uint8_t status; + uint32_t count; + uint32_t index; + uint32_t n, i; + + status = GetTraceStatus(); + count = GetTraceCount(); + + if (TraceTransport == 1U) { + n = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8); + if (n > (DAP_PACKET_SIZE - 4U)) { + n = DAP_PACKET_SIZE - 4U; + } + if (count > n) { + count = n; + } + } else { + count = 0U; + } + + *response++ = status; + *response++ = (uint8_t)(count >> 0); + *response++ = (uint8_t)(count >> 8); + + if (TraceTransport == 1U) { + index = TraceIndexO; + for (i = index, n = count; n; n--) { + i &= SWO_BUFFER_SIZE - 1U; + *response++ = TraceBuf[i++]; + } + TraceIndexO = index + count; + ResumeTrace(); + } + + return ((2U << 16) | (3U + count)); +} + + +#if (SWO_STREAM != 0) + +// SWO Data Transfer complete callback +void SWO_TransferComplete (void) { + TraceIndexO += TransferSize; + TransferBusy = 0U; + ResumeTrace(); + osThreadFlagsSet(SWO_ThreadId, 1U); +} + +// SWO Thread +__NO_RETURN void SWO_Thread (void *argument) { + uint32_t timeout; + uint32_t flags; + uint32_t count; + uint32_t index; + uint32_t i, n; + (void) argument; + + timeout = osWaitForever; + + for (;;) { + flags = osThreadFlagsWait(1U, osFlagsWaitAny, timeout); + if (TraceStatus & DAP_SWO_CAPTURE_ACTIVE) { + timeout = SWO_STREAM_TIMEOUT; + } else { + timeout = osWaitForever; + flags = osFlagsErrorTimeout; + } + if (TransferBusy == 0U) { + count = GetTraceCount(); + if (count != 0U) { + index = TraceIndexO & (SWO_BUFFER_SIZE - 1U); + n = SWO_BUFFER_SIZE - index; + if (count > n) { + count = n; + } + if (flags != osFlagsErrorTimeout) { + i = index & (USB_BLOCK_SIZE - 1U); + if (i == 0U) { + count &= ~(USB_BLOCK_SIZE - 1U); + } else { + n = USB_BLOCK_SIZE - i; + if (count >= n) { + count = n; + } else { + count = 0U; + } + } + } + if (count != 0U) { + TransferSize = count; + TransferBusy = 1U; + SWO_QueueTransfer(&TraceBuf[index], count); + } + } + } + } +} + +#endif /* (SWO_STREAM != 0) */ + + +#endif /* ((SWO_UART != 0) || (SWO_MANCHESTER != 0)) */ diff --git a/firmware/app/daplink_bl702/daplink/cmsis-dap/SW_DP.c b/firmware/app/daplink_bl702/daplink/cmsis-dap/SW_DP.c new file mode 100644 index 0000000..7ac13da --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cmsis-dap/SW_DP.c @@ -0,0 +1,301 @@ +/* + * 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: SW_DP.c CMSIS-DAP SW DP I/O + * + *---------------------------------------------------------------------------*/ + +#include "DAP_config.h" +#include "DAP.h" + +#if defined(__CC_ARM) +#pragma push +#pragma O3 +#pragma Otime +#elif defined(__GNUC__) && !defined(__ARMCC_VERSION) +#pragma GCC push_options +#pragma GCC optimize("O3") +#endif + +// SW Macros + +#define PIN_SWCLK_SET PIN_SWCLK_TCK_SET +#define PIN_SWCLK_CLR PIN_SWCLK_TCK_CLR + +#define SW_CLOCK_CYCLE() \ + PIN_SWCLK_CLR(); \ + PIN_DELAY(); \ + PIN_SWCLK_SET(); \ + PIN_DELAY() + +#define SW_WRITE_BIT(bit) \ + PIN_SWDIO_OUT(bit); \ + PIN_SWCLK_CLR(); \ + PIN_DELAY(); \ + PIN_SWCLK_SET(); \ + PIN_DELAY() + +#define SW_READ_BIT(bit) \ + PIN_SWCLK_CLR(); \ + PIN_DELAY(); \ + bit = PIN_SWDIO_IN(); \ + PIN_SWCLK_SET(); \ + PIN_DELAY() + +#define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) + + +// Generate SWJ Sequence +// count: sequence bit count +// data: pointer to sequence bit data +// return: none +#if ((DAP_SWD != 0) || (DAP_JTAG != 0)) +__WEAK void SWJ_Sequence (uint32_t count, const uint8_t *data) { + uint32_t val; + uint32_t n; + + val = 0U; + n = 0U; + while (count--) { + if (n == 0U) { + val = *data++; + n = 8U; + } + if (val & 1U) { + PIN_SWDIO_TMS_SET(); + } else { + PIN_SWDIO_TMS_CLR(); + } + SW_CLOCK_CYCLE(); + val >>= 1; + n--; + } +} +#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) +__WEAK void SWD_Sequence (uint32_t info, const uint8_t *swdo, uint8_t *swdi) { + uint32_t val; + uint32_t bit; + uint32_t n, k; + + n = info & SWD_SEQUENCE_CLK; + if (n == 0U) { + n = 64U; + } + + if (info & SWD_SEQUENCE_DIN) { + while (n) { + val = 0U; + for (k = 8U; k && n; k--, n--) { + SW_READ_BIT(bit); + val >>= 1; + val |= bit << 7; + } + val >>= k; + *swdi++ = (uint8_t)val; + } + } else { + while (n) { + val = *swdo++; + for (k = 8U; k && n; k--, n--) { + SW_WRITE_BIT(val); + val >>= 1; + } + } + } +} +#endif + + +#if (DAP_SWD != 0) + + +// SWD Transfer I/O +// request: A[3:2] RnW APnDP +// data: DATA[31:0] +// return: ACK[2:0] +#define SWD_TransferFunction(speed) /**/ \ +static uint8_t SWD_Transfer##speed (uint32_t request, uint32_t *data) { \ + uint32_t ack; \ + uint32_t bit; \ + uint32_t val; \ + uint32_t parity; \ + \ + uint32_t n; \ + \ + /* Packet Request */ \ + parity = 0U; \ + SW_WRITE_BIT(1U); /* Start Bit */ \ + bit = request >> 0; \ + SW_WRITE_BIT(bit); /* APnDP Bit */ \ + parity += bit; \ + bit = request >> 1; \ + SW_WRITE_BIT(bit); /* RnW Bit */ \ + parity += bit; \ + bit = request >> 2; \ + SW_WRITE_BIT(bit); /* A2 Bit */ \ + parity += bit; \ + bit = request >> 3; \ + SW_WRITE_BIT(bit); /* A3 Bit */ \ + parity += bit; \ + SW_WRITE_BIT(parity); /* Parity Bit */ \ + SW_WRITE_BIT(0U); /* Stop Bit */ \ + SW_WRITE_BIT(1U); /* Park Bit */ \ + \ + /* Turnaround */ \ + PIN_SWDIO_OUT_DISABLE(); \ + for (n = DAP_Data.swd_conf.turnaround; n; n--) { \ + SW_CLOCK_CYCLE(); \ + } \ + \ + /* Acknowledge response */ \ + SW_READ_BIT(bit); \ + ack = bit << 0; \ + SW_READ_BIT(bit); \ + ack |= bit << 1; \ + SW_READ_BIT(bit); \ + ack |= bit << 2; \ + \ + if (ack == DAP_TRANSFER_OK) { /* OK response */ \ + /* Data transfer */ \ + if (request & DAP_TRANSFER_RnW) { \ + /* Read data */ \ + val = 0U; \ + parity = 0U; \ + for (n = 32U; n; n--) { \ + SW_READ_BIT(bit); /* Read RDATA[0:31] */ \ + parity += bit; \ + val >>= 1; \ + val |= bit << 31; \ + } \ + SW_READ_BIT(bit); /* Read Parity */ \ + if ((parity ^ bit) & 1U) { \ + ack = DAP_TRANSFER_ERROR; \ + } \ + if (data) { *data = val; } \ + /* Turnaround */ \ + for (n = DAP_Data.swd_conf.turnaround; n; n--) { \ + SW_CLOCK_CYCLE(); \ + } \ + PIN_SWDIO_OUT_ENABLE(); \ + } else { \ + /* Turnaround */ \ + for (n = DAP_Data.swd_conf.turnaround; n; n--) { \ + SW_CLOCK_CYCLE(); \ + } \ + PIN_SWDIO_OUT_ENABLE(); \ + /* Write data */ \ + val = *data; \ + parity = 0U; \ + for (n = 32U; n; n--) { \ + SW_WRITE_BIT(val); /* Write WDATA[0:31] */ \ + parity += val; \ + val >>= 1; \ + } \ + SW_WRITE_BIT(parity); /* Write Parity Bit */ \ + } \ + /* Capture Timestamp */ \ + if (request & DAP_TRANSFER_TIMESTAMP) { \ + DAP_Data.timestamp = TIMESTAMP_GET(); \ + } \ + /* Idle cycles */ \ + n = DAP_Data.transfer.idle_cycles; \ + if (n) { \ + PIN_SWDIO_OUT(0U); \ + for (; n; n--) { \ + SW_CLOCK_CYCLE(); \ + } \ + } \ + PIN_SWDIO_OUT(1U); \ + return ((uint8_t)ack); \ + } \ + \ + if ((ack == DAP_TRANSFER_WAIT) || (ack == DAP_TRANSFER_FAULT)) { \ + /* WAIT or FAULT response */ \ + if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) != 0U)) { \ + for (n = 32U+1U; n; n--) { \ + SW_CLOCK_CYCLE(); /* Dummy Read RDATA[0:31] + Parity */ \ + } \ + } \ + /* Turnaround */ \ + for (n = DAP_Data.swd_conf.turnaround; n; n--) { \ + SW_CLOCK_CYCLE(); \ + } \ + PIN_SWDIO_OUT_ENABLE(); \ + if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) == 0U)) { \ + PIN_SWDIO_OUT(0U); \ + for (n = 32U+1U; n; n--) { \ + SW_CLOCK_CYCLE(); /* Dummy Write WDATA[0:31] + Parity */ \ + } \ + } \ + PIN_SWDIO_OUT(1U); \ + return ((uint8_t)ack); \ + } \ + \ + /* Protocol error */ \ + for (n = DAP_Data.swd_conf.turnaround + 32U + 1U; n; n--) { \ + SW_CLOCK_CYCLE(); /* Back off data phase */ \ + } \ + PIN_SWDIO_OUT_ENABLE(); \ + PIN_SWDIO_OUT(1U); \ + return ((uint8_t)ack); \ +} + + +#undef PIN_DELAY +#define PIN_DELAY() PIN_DELAY_FAST() +SWD_TransferFunction(Fast) + +#undef PIN_DELAY +#define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) +SWD_TransferFunction(Slow) + + +// SWD Transfer I/O +// request: A[3:2] RnW APnDP +// data: DATA[31:0] +// return: ACK[2:0] +__WEAK uint8_t SWD_Transfer(uint32_t request, uint32_t *data) { + if (DAP_Data.fast_clock) { + return SWD_TransferFast(request, data); + } else { + return SWD_TransferSlow(request, data); + } +} + + +#endif /* (DAP_SWD != 0) */ + + +#if defined(__CC_ARM) +#pragma pop +#elif defined(__GNUC__) && !defined(__ARMCC_VERSION) +#pragma GCC pop_options +#endif diff --git a/firmware/app/daplink_bl702/daplink/cmsis-dap/dap_strings.h b/firmware/app/daplink_bl702/daplink/cmsis-dap/dap_strings.h new file mode 100644 index 0000000..c25ff2b --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cmsis-dap/dap_strings.h @@ -0,0 +1 @@ +/* dap_strings.h - Empty stub; string functions are in DAP_config.h */ diff --git a/firmware/app/daplink_bl702/daplink/cmsis-dap/daplink_vendor_commands.h b/firmware/app/daplink_bl702/daplink/cmsis-dap/daplink_vendor_commands.h new file mode 100644 index 0000000..18aee74 --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cmsis-dap/daplink_vendor_commands.h @@ -0,0 +1,39 @@ +/* + * DAPLink Interface Firmware + * Copyright (c) 2021 Chris Reed + * 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 + * + * http://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. + */ +/** + * @file + * @brief Vendor-specific CMSIS-DAP command constants. + */ + +#include "DAP.h" + +//! @name DAPLink vendor-specific CMSIS-DAP command IDs +//@{ +#define ID_DAP_GetUniqueID ID_DAP_Vendor0 +#define ID_DAP_UART_GetLineCoding ID_DAP_Vendor1 +#define ID_DAP_UART_SetConfiguration ID_DAP_Vendor2 +#define ID_DAP_UART_Read ID_DAP_Vendor3 +#define ID_DAP_UART_Write ID_DAP_Vendor4 +#define ID_DAP_SetUSBTestMode ID_DAP_Vendor8 +#define ID_DAP_ResetTargetIfNoAutoReset ID_DAP_Vendor9 +#define ID_DAP_MSD_Open ID_DAP_Vendor10 +#define ID_DAP_MSD_Close ID_DAP_Vendor11 +#define ID_DAP_MSD_Write ID_DAP_Vendor12 +#define ID_DAP_SelectEraseMode ID_DAP_Vendor13 +//@} + diff --git a/firmware/app/daplink_bl702/daplink/cmsis-dap/debug_ca.h b/firmware/app/daplink_bl702/daplink/cmsis-dap/debug_ca.h new file mode 100644 index 0000000..dbe085a --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cmsis-dap/debug_ca.h @@ -0,0 +1,147 @@ +/** + * @file debug_ca.h + * @brief Access to ARM DAP (Cortex-A) using CMSIS-DAP protocol + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, 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 + * + * http://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. + */ + +#ifndef DEBUG_CA_H +#define DEBUG_CA_H + +#include "debug_cm.h" + +// Debug registers +#define DEBUG_REGSITER_BASE (0x80030000) + +#define DBGDIDR (DEBUG_REGSITER_BASE + (0 * 4)) // Debug ID +#define DBGWFAR (DEBUG_REGSITER_BASE + (6 * 4)) // Watchpoint Fault Address +#define DBGVCR (DEBUG_REGSITER_BASE + (7 * 4)) // Vector Catch +#define DBGECR (DEBUG_REGSITER_BASE + (9 * 4)) // Event Catch +#define DBGDTRRX (DEBUG_REGSITER_BASE + (32 * 4)) // Host to Target Data Transfer +#define DBGITR (DEBUG_REGSITER_BASE + (33 * 4)) // WO Instruction Transfer +#define DBGDSCR (DEBUG_REGSITER_BASE + (34 * 4)) // Debug Status and Control +#define DBGDTRTX (DEBUG_REGSITER_BASE + (35 * 4)) // Target to Host Data Transfer +#define DBGDRCR (DEBUG_REGSITER_BASE + (36 * 4)) // Debug Run Control +#define DBGEACR (DEBUG_REGSITER_BASE + (37 * 4)) // External Auxiliary Control +#define DBGPCSR (DEBUG_REGSITER_BASE + (40 * 4)) // Program Counter Sampling +#define DBGCIDSR (DEBUG_REGSITER_BASE + (41 * 4)) // Context ID Sampling +#define DBGVIDSR (DEBUG_REGSITER_BASE + (42 * 4)) // Virtualization ID Sampling +#define DBGBVR0 (DEBUG_REGSITER_BASE + (64 * 4)) // Breakpoint Value +#define DBGBVR1 (DEBUG_REGSITER_BASE + (65 * 4)) // Breakpoint Value +#define DBGBVR2 (DEBUG_REGSITER_BASE + (66 * 4)) // Breakpoint Value +#define DBGBVR3 (DEBUG_REGSITER_BASE + (67 * 4)) // Breakpoint Value +#define DBGBVR4 (DEBUG_REGSITER_BASE + (68 * 4)) // Breakpoint Value +#define DBGBVR5 (DEBUG_REGSITER_BASE + (69 * 4)) // Breakpoint Value +#define DBGBVR6 (DEBUG_REGSITER_BASE + (70 * 4)) // Breakpoint Value +#define DBGBVR7 (DEBUG_REGSITER_BASE + (71 * 4)) // Breakpoint Value +#define DBGBVR8 (DEBUG_REGSITER_BASE + (72 * 4)) // Breakpoint Value +#define DBGBVR9 (DEBUG_REGSITER_BASE + (73 * 4)) // Breakpoint Value +#define DBGBVR10 (DEBUG_REGSITER_BASE + (74 * 4)) // Breakpoint Value +#define DBGBVR11 (DEBUG_REGSITER_BASE + (75 * 4)) // Breakpoint Value +#define DBGBVR12 (DEBUG_REGSITER_BASE + (76 * 4)) // Breakpoint Value +#define DBGBVR13 (DEBUG_REGSITER_BASE + (77 * 4)) // Breakpoint Value +#define DBGBVR14 (DEBUG_REGSITER_BASE + (78 * 4)) // Breakpoint Value +#define DBGBVR15 (DEBUG_REGSITER_BASE + (79 * 4)) // Breakpoint Value +#define DBGBCR0 (DEBUG_REGSITER_BASE + (80 * 4)) // Breakpoint Control +#define DBGBCR1 (DEBUG_REGSITER_BASE + (81 * 4)) // Breakpoint Control +#define DBGBCR2 (DEBUG_REGSITER_BASE + (82 * 4)) // Breakpoint Control +#define DBGBCR3 (DEBUG_REGSITER_BASE + (83 * 4)) // Breakpoint Control +#define DBGBCR4 (DEBUG_REGSITER_BASE + (84 * 4)) // Breakpoint Control +#define DBGBCR5 (DEBUG_REGSITER_BASE + (85 * 4)) // Breakpoint Control +#define DBGBCR6 (DEBUG_REGSITER_BASE + (86 * 4)) // Breakpoint Control +#define DBGBCR7 (DEBUG_REGSITER_BASE + (87 * 4)) // Breakpoint Control +#define DBGBCR8 (DEBUG_REGSITER_BASE + (88 * 4)) // Breakpoint Control +#define DBGBCR9 (DEBUG_REGSITER_BASE + (89 * 4)) // Breakpoint Control +#define DBGBCR10 (DEBUG_REGSITER_BASE + (90 * 4)) // Breakpoint Control +#define DBGBCR11 (DEBUG_REGSITER_BASE + (91 * 4)) // Breakpoint Control +#define DBGBCR12 (DEBUG_REGSITER_BASE + (92 * 4)) // Breakpoint Control +#define DBGBCR13 (DEBUG_REGSITER_BASE + (93 * 4)) // Breakpoint Control +#define DBGBCR14 (DEBUG_REGSITER_BASE + (94 * 4)) // Breakpoint Control +#define DBGBCR15 (DEBUG_REGSITER_BASE + (95 * 4)) // Breakpoint Control +#define DBGWVR0 (DEBUG_REGSITER_BASE + (96 * 4)) // Watchpoint Value +#define DBGWVR1 (DEBUG_REGSITER_BASE + (97 * 4)) // Watchpoint Value +#define DBGWVR2 (DEBUG_REGSITER_BASE + (98 * 4)) // Watchpoint Value +#define DBGWVR3 (DEBUG_REGSITER_BASE + (99 * 4)) // Watchpoint Value +#define DBGWVR4 (DEBUG_REGSITER_BASE + (100 * 4)) // Watchpoint Value +#define DBGWVR5 (DEBUG_REGSITER_BASE + (101 * 4)) // Watchpoint Value +#define DBGWVR6 (DEBUG_REGSITER_BASE + (102 * 4)) // Watchpoint Value +#define DBGWVR7 (DEBUG_REGSITER_BASE + (103 * 4)) // Watchpoint Value +#define DBGWVR8 (DEBUG_REGSITER_BASE + (104 * 4)) // Watchpoint Value +#define DBGWVR9 (DEBUG_REGSITER_BASE + (105 * 4)) // Watchpoint Value +#define DBGWVR10 (DEBUG_REGSITER_BASE + (106 * 4)) // Watchpoint Value +#define DBGWVR11 (DEBUG_REGSITER_BASE + (107 * 4)) // Watchpoint Value +#define DBGWVR12 (DEBUG_REGSITER_BASE + (108 * 4)) // Watchpoint Value +#define DBGWVR13 (DEBUG_REGSITER_BASE + (109 * 4)) // Watchpoint Value +#define DBGWVR14 (DEBUG_REGSITER_BASE + (110 * 4)) // Watchpoint Value +#define DBGWVR15 (DEBUG_REGSITER_BASE + (111 * 4)) // Watchpoint Value +#define DBGWCR0 (DEBUG_REGSITER_BASE + (112 * 4)) // Watchpoint Control +#define DBGWCR1 (DEBUG_REGSITER_BASE + (113 * 4)) // Watchpoint Control +#define DBGWCR2 (DEBUG_REGSITER_BASE + (114 * 4)) // Watchpoint Control +#define DBGWCR3 (DEBUG_REGSITER_BASE + (115 * 4)) // Watchpoint Control +#define DBGWCR4 (DEBUG_REGSITER_BASE + (116 * 4)) // Watchpoint Control +#define DBGWCR5 (DEBUG_REGSITER_BASE + (117 * 4)) // Watchpoint Control +#define DBGWCR6 (DEBUG_REGSITER_BASE + (118 * 4)) // Watchpoint Control +#define DBGWCR7 (DEBUG_REGSITER_BASE + (119 * 4)) // Watchpoint Control +#define DBGWCR8 (DEBUG_REGSITER_BASE + (120 * 4)) // Watchpoint Control +#define DBGWCR9 (DEBUG_REGSITER_BASE + (121 * 4)) // Watchpoint Control +#define DBGWCR10 (DEBUG_REGSITER_BASE + (122 * 4)) // Watchpoint Control +#define DBGWCR11 (DEBUG_REGSITER_BASE + (123 * 4)) // Watchpoint Control +#define DBGWCR12 (DEBUG_REGSITER_BASE + (124 * 4)) // Watchpoint Control +#define DBGWCR13 (DEBUG_REGSITER_BASE + (125 * 4)) // Watchpoint Control +#define DBGWCR14 (DEBUG_REGSITER_BASE + (126 * 4)) // Watchpoint Control +#define DBGWCR15 (DEBUG_REGSITER_BASE + (127 * 4)) // Watchpoint Control +#define DBGBXVR0 (DEBUG_REGSITER_BASE + (144 * 4)) // Breakpoint Extended Valueb +#define DBGBXVR1 (DEBUG_REGSITER_BASE + (145 * 4)) // Breakpoint Extended Valueb +#define DBGBXVR2 (DEBUG_REGSITER_BASE + (146 * 4)) // Breakpoint Extended Valueb +#define DBGBXVR3 (DEBUG_REGSITER_BASE + (147 * 4)) // Breakpoint Extended Valueb +#define DBGBXVR4 (DEBUG_REGSITER_BASE + (148 * 4)) // Breakpoint Extended Valueb +#define DBGBXVR5 (DEBUG_REGSITER_BASE + (149 * 4)) // Breakpoint Extended Valueb +#define DBGBXVR6 (DEBUG_REGSITER_BASE + (150 * 4)) // Breakpoint Extended Valueb +#define DBGBXVR7 (DEBUG_REGSITER_BASE + (151 * 4)) // Breakpoint Extended Valueb +#define DBGBXVR8 (DEBUG_REGSITER_BASE + (152 * 4)) // Breakpoint Extended Valueb +#define DBGBXVR9 (DEBUG_REGSITER_BASE + (153 * 4)) // Breakpoint Extended Valueb +#define DBGBXVR10 (DEBUG_REGSITER_BASE + (154 * 4)) // Breakpoint Extended Valueb +#define DBGBXVR11 (DEBUG_REGSITER_BASE + (155 * 4)) // Breakpoint Extended Valueb +#define DBGBXVR12 (DEBUG_REGSITER_BASE + (156 * 4)) // Breakpoint Extended Valueb +#define DBGBXVR13 (DEBUG_REGSITER_BASE + (157 * 4)) // Breakpoint Extended Valueb +#define DBGBXVR14 (DEBUG_REGSITER_BASE + (158 * 4)) // Breakpoint Extended Valueb +#define DBGBXVR15 (DEBUG_REGSITER_BASE + (159 * 4)) // Breakpoint Extended Valueb +#define DBGOSLAR (DEBUG_REGSITER_BASE + (192 * 4)) // OS Lock Access +#define DBGOSLSR (DEBUG_REGSITER_BASE + (193 * 4)) // OS Lock Status +#define DBGPRCR (DEBUG_REGSITER_BASE + (196 * 4)) // Powerdown and Reset Control +#define DBGPRSR (DEBUG_REGSITER_BASE + (197 * 4)) // Powerdown and Reset Status +#define DBGITCTRL (DEBUG_REGSITER_BASE + (960 * 4)) // Integration Mode Control +#define DBGCLAIMSET (DEBUG_REGSITER_BASE + (1000 * 4)) // Claim Tag Set +#define DBGCLAIMCLR (DEBUG_REGSITER_BASE + (1001 * 4)) // Claim Tag Clear +#define DBGLAR (DEBUG_REGSITER_BASE + (1004 * 4)) // Lock Access +#define DBGLSR (DEBUG_REGSITER_BASE + (1005 * 4)) // Lock Status +#define DBGAUTHSTATUS (DEBUG_REGSITER_BASE + (1006 * 4)) // Authentication Status +#define DBGDEVID2 (DEBUG_REGSITER_BASE + (1008 * 4)) // Debug Device ID 2 +#define DBGDEVID1 (DEBUG_REGSITER_BASE + (1009 * 4)) // Debug Device ID 1 +#define DBGDEVID (DEBUG_REGSITER_BASE + (1010 * 4)) // Debug Device ID +#define DBGDEVTYPE (DEBUG_REGSITER_BASE + (1011 * 4)) // Device Type +#define DBGPID0 (DEBUG_REGSITER_BASE + (1012 * 4)) // Debug Peripheral ID +#define DBGPID1 (DEBUG_REGSITER_BASE + (1013 * 4)) // Debug Peripheral ID +#define DBGPID2 (DEBUG_REGSITER_BASE + (1014 * 4)) // Debug Peripheral ID +#define DBGPID3 (DEBUG_REGSITER_BASE + (1015 * 4)) // Debug Peripheral ID +#define DBGPID4 (DEBUG_REGSITER_BASE + (1016 * 4)) // Debug Peripheral ID +#define DBGCID0 (DEBUG_REGSITER_BASE + (1020 * 4)) // Debug Component ID +#define DBGCID1 (DEBUG_REGSITER_BASE + (1021 * 4)) // Debug Component ID +#define DBGCID2 (DEBUG_REGSITER_BASE + (1022 * 4)) // Debug Component ID +#define DBGCID3 (DEBUG_REGSITER_BASE + (1023 * 4)) // Debug Component ID + +#endif diff --git a/firmware/app/daplink_bl702/daplink/cmsis-dap/debug_cm.h b/firmware/app/daplink_bl702/daplink/cmsis-dap/debug_cm.h new file mode 100644 index 0000000..9fbe72b --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cmsis-dap/debug_cm.h @@ -0,0 +1,169 @@ +/** + * @file debug_cm.h + * @brief Access to ARM DAP (Cortex-M) using CMSIS-DAP protocol + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, 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 + * + * http://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. + */ + +#ifndef DEBUG_CM_H +#define DEBUG_CM_H + +#include "DAP.h" + +// SWD register access +#define SWD_REG_AP (1) +#define SWD_REG_DP (0) +#define SWD_REG_R (1<<1) +#define SWD_REG_W (0<<1) +#define SWD_REG_ADR(a) (a & 0x0c) + +// Abort Register definitions +#define DAPABORT 0x00000001 // DAP Abort +#define STKCMPCLR 0x00000002 // Clear STICKYCMP Flag (SW Only) +#define STKERRCLR 0x00000004 // Clear STICKYERR Flag (SW Only) +#define WDERRCLR 0x00000008 // Clear WDATAERR Flag (SW Only) +#define ORUNERRCLR 0x00000010 // Clear STICKYORUN Flag (SW Only) + +// Debug Control and Status definitions +#define ORUNDETECT 0x00000001 // Overrun Detect +#define STICKYORUN 0x00000002 // Sticky Overrun +#define TRNMODE 0x0000000C // Transfer Mode Mask +#define TRNNORMAL 0x00000000 // Transfer Mode: Normal +#define TRNVERIFY 0x00000004 // Transfer Mode: Pushed Verify +#define TRNCOMPARE 0x00000008 // Transfer Mode: Pushed Compare +#define STICKYCMP 0x00000010 // Sticky Compare +#define STICKYERR 0x00000020 // Sticky Error +#define READOK 0x00000040 // Read OK (SW Only) +#define WDATAERR 0x00000080 // Write Data Error (SW Only) +#define MASKLANE 0x00000F00 // Mask Lane Mask +#define MASKLANE0 0x00000100 // Mask Lane 0 +#define MASKLANE1 0x00000200 // Mask Lane 1 +#define MASKLANE2 0x00000400 // Mask Lane 2 +#define MASKLANE3 0x00000800 // Mask Lane 3 +#define TRNCNT 0x001FF000 // Transaction Counter Mask +#define CDBGRSTREQ 0x04000000 // Debug Reset Request +#define CDBGRSTACK 0x08000000 // Debug Reset Acknowledge +#define CDBGPWRUPREQ 0x10000000 // Debug Power-up Request +#define CDBGPWRUPACK 0x20000000 // Debug Power-up Acknowledge +#define CSYSPWRUPREQ 0x40000000 // System Power-up Request +#define CSYSPWRUPACK 0x80000000 // System Power-up Acknowledge + +// Debug Select Register definitions +#define CTRLSEL 0x00000001 // CTRLSEL (SW Only) +#define APBANKSEL 0x000000F0 // APBANKSEL Mask +#define APSEL 0xFF000000 // APSEL Mask + +// Access Port Register Addresses +#define AP_CSW 0x00 // Control and Status Word +#define AP_TAR 0x04 // Transfer Address +#define AP_DRW 0x0C // Data Read/Write +#define AP_BD0 0x10 // Banked Data 0 +#define AP_BD1 0x14 // Banked Data 1 +#define AP_BD2 0x18 // Banked Data 2 +#define AP_BD3 0x1C // Banked Data 3 +#define AP_ROM 0xF8 // Debug ROM Address +#define AP_IDR 0xFC // Identification Register + +// AP Control and Status Word definitions +#define CSW_SIZE 0x00000007 // Access Size: Selection Mask +#define CSW_SIZE8 0x00000000 // Access Size: 8-bit +#define CSW_SIZE16 0x00000001 // Access Size: 16-bit +#define CSW_SIZE32 0x00000002 // Access Size: 32-bit +#define CSW_ADDRINC 0x00000030 // Auto Address Increment Mask +#define CSW_NADDRINC 0x00000000 // No Address Increment +#define CSW_SADDRINC 0x00000010 // Single Address Increment +#define CSW_PADDRINC 0x00000020 // Packed Address Increment +#define CSW_DBGSTAT 0x00000040 // Debug Status +#define CSW_TINPROG 0x00000080 // Transfer in progress +#define CSW_HPROT 0x02000000 // User/Privilege Control +#define CSW_MSTRTYPE 0x20000000 // Master Type Mask +#define CSW_MSTRCORE 0x00000000 // Master Type: Core +#define CSW_MSTRDBG 0x20000000 // Master Type: Debug +#define CSW_RESERVED 0x01000000 // Reserved Value +#define CSW_SPROT 0x40000000 // SProt + +// Core Debug Register Address Offsets +#define DBG_OFS 0x0DF0 // Debug Register Offset inside NVIC +#define DBG_HCSR_OFS 0x00 // Debug Halting Control & Status Register +#define DBG_CRSR_OFS 0x04 // Debug Core Register Selector Register +#define DBG_CRDR_OFS 0x08 // Debug Core Register Data Register +#define DBG_EMCR_OFS 0x0C // Debug Exception & Monitor Control Register + +// Core Debug Register Addresses +#define DBG_HCSR (DBG_Addr + DBG_HCSR_OFS) +#define DBG_CRSR (DBG_Addr + DBG_CRSR_OFS) +#define DBG_CRDR (DBG_Addr + DBG_CRDR_OFS) +#define DBG_EMCR (DBG_Addr + DBG_EMCR_OFS) + +// Debug Halting Control and Status Register definitions +#define C_DEBUGEN 0x00000001 // Debug Enable +#define C_HALT 0x00000002 // Halt +#define C_STEP 0x00000004 // Step +#define C_MASKINTS 0x00000008 // Mask Interrupts +#define C_SNAPSTALL 0x00000020 // Snap Stall +#define S_REGRDY 0x00010000 // Register R/W Ready Flag +#define S_HALT 0x00020000 // Halt Flag +#define S_SLEEP 0x00040000 // Sleep Flag +#define S_LOCKUP 0x00080000 // Lockup Flag +#define S_RETIRE_ST 0x01000000 // Sticky Retire Flag +#define S_RESET_ST 0x02000000 // Sticky Reset Flag +#define DBGKEY 0xA05F0000 // Debug Key + +// Debug Exception and Monitor Control Register definitions +#define VC_CORERESET 0x00000001 // Reset Vector Catch +#define VC_MMERR 0x00000010 // Debug Trap on MMU Fault +#define VC_NOCPERR 0x00000020 // Debug Trap on No Coprocessor Fault +#define VC_CHKERR 0x00000040 // Debug Trap on Checking Error Fault +#define VC_STATERR 0x00000080 // Debug Trap on State Error Fault +#define VC_BUSERR 0x00000100 // Debug Trap on Bus Error Fault +#define VC_INTERR 0x00000200 // Debug Trap on Interrupt Error Fault +#define VC_HARDERR 0x00000400 // Debug Trap on Hard Fault +#define MON_EN 0x00010000 // Monitor Enable +#define MON_PEND 0x00020000 // Monitor Pend +#define MON_STEP 0x00040000 // Monitor Step +#define MON_REQ 0x00080000 // Monitor Request +#define TRCENA 0x01000000 // Trace Enable (DWT, ITM, ETM, TPIU) + +// NVIC: Interrupt Controller Type Register +#define NVIC_ICT (NVIC_Addr + 0x0004) +#define INTLINESNUM 0x0000001F // Interrupt Line Numbers + +// NVIC: CPUID Base Register +#define NVIC_CPUID (NVIC_Addr + 0x0D00) +#define CPUID_PARTNO 0x0000FFF0 // Part Number Mask +#define CPUID_REVISION 0x0000000F // Revision Mask +#define CPUID_VARIANT 0x00F00000 // Variant Mask + +// NVIC: Application Interrupt/Reset Control Register +#define NVIC_AIRCR (NVIC_Addr + 0x0D0C) +#define VECTRESET 0x00000001 // Reset Cortex-M (except Debug) +#define VECTCLRACTIVE 0x00000002 // Clear Active Vector Bit +#define SYSRESETREQ 0x00000004 // Reset System (except Debug) +#define VECTKEY 0x05FA0000 // Write Key + +// NVIC: Debug Fault Status Register +#define NVIC_DFSR (NVIC_Addr + 0x0D30) +#define HALTED 0x00000001 // Halt Flag +#define BKPT 0x00000002 // BKPT Flag +#define DWTTRAP 0x00000004 // DWT Match +#define VCATCH 0x00000008 // Vector Catch Flag +#define EXTERNAL 0x00000010 // External Debug Request + +// Data Watchpoint and Trace unit +#define DWT_PCSR 0xe000101c // DWT PC Sampling Register + +#endif diff --git a/firmware/app/daplink_bl702/daplink/compiler.h b/firmware/app/daplink_bl702/daplink/compiler.h new file mode 100644 index 0000000..4774e15 --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/compiler.h @@ -0,0 +1,71 @@ +/** + * @file compiler.h + * @brief Special asserts and macros + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, 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 + * + * http://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. + */ + +#ifndef COMPILER_H +#define COMPILER_H + +#include "cmsis_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define COMPILER_CONCAT_(a, b) a##b +#define COMPILER_CONCAT(a, b) COMPILER_CONCAT_(a, b) + +// Divide by zero if the the expression is false. This +// causes an error at compile time. +// +// The special value '__COUNTER__' is used to create a unique value to +// append to 'compiler_assert_' to create a unique token. This prevents +// conflicts resulting from the same enum being declared multiple times. +#define COMPILER_ASSERT(e) enum { COMPILER_CONCAT(compiler_assert_, __COUNTER__) = 1/((e) ? 1 : 0) } + +// Macros to disable optimisation of a function. +#if (defined(__ICCARM__)) +#define NO_OPTIMIZE_PRE _Pragma("optimize = none") +#define NO_OPTIMIZE_INLINE +#define NO_OPTIMIZE_POST +#elif (defined(__CC_ARM)) /* ARMCC */ +#define NO_OPTIMIZE_PRE _Pragma("push") \ + _Pragma("O0") +#define NO_OPTIMIZE_INLINE +#define NO_OPTIMIZE_POST _Pragma("pop") +#define RAM_FUNCTION __attribute__((section("ram_func"))) +#elif (defined(__ARMCC_VERSION)) /* ARMCLANG */ +#define NO_OPTIMIZE_PRE +#define NO_OPTIMIZE_INLINE +#define NO_OPTIMIZE_POST +#define RAM_FUNCTION __attribute__((section("ram_func"))) +#elif (defined(__GNUC__)) +#define NO_OPTIMIZE_PRE +#define NO_OPTIMIZE_INLINE __attribute__((optimize("O0"))) +#define NO_OPTIMIZE_POST +#define RAM_FUNCTION __attribute__((long_call, section(".ram_func"))) +#else +#error "Unknown compiler" +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/firmware/app/daplink_bl702/daplink/cortex_m.c b/firmware/app/daplink_bl702/daplink/cortex_m.c new file mode 100644 index 0000000..a9f0735 --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cortex_m.c @@ -0,0 +1,27 @@ +/** + * @file cortex_m.c + * @brief ARM Cortex-Mx cpu functions + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2019, 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 + * + * http://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. + */ + +#include "cortex_m.h" + +__WEAK void SystemReset(void) +{ + NVIC_SystemReset(); +} diff --git a/firmware/app/daplink_bl702/daplink/cortex_m.h b/firmware/app/daplink_bl702/daplink/cortex_m.h new file mode 100644 index 0000000..b3425ce --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/cortex_m.h @@ -0,0 +1,59 @@ +/** + * @file cortex_m.h + * @brief ARM Cortex-Mx cpu state helper functions + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, 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 + * + * http://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. + */ + +#ifndef CORTEX_M_H +#define CORTEX_M_H + +#include +#include +#include "device.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32_t cortex_int_state_t; + +__STATIC_FORCEINLINE cortex_int_state_t cortex_int_get_and_disable(void) +{ + cortex_int_state_t state; + state = __get_PRIMASK(); + __disable_irq(); + return state; +} + +__STATIC_FORCEINLINE void cortex_int_restore(cortex_int_state_t state) +{ + __set_PRIMASK(state); +} + +__STATIC_FORCEINLINE bool cortex_in_isr(void) +{ + return (__get_xPSR() & 0x1F) != 0; +} + +extern void SystemReset(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/firmware/app/daplink_bl702/daplink/daplink.h b/firmware/app/daplink_bl702/daplink/daplink.h new file mode 100644 index 0000000..e26781a --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/daplink.h @@ -0,0 +1,11 @@ +/** + * @file daplink.h + * @brief DAPLink Core Header Stub for BL702 Minimal Build + */ + +#ifndef DAPLINK_H +#define DAPLINK_H + +#define DAPLINK_IF 1 + +#endif diff --git a/firmware/app/daplink_bl702/daplink/daplink_addr.h b/firmware/app/daplink_bl702/daplink/daplink_addr.h new file mode 100644 index 0000000..56277c8 --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/daplink_addr.h @@ -0,0 +1,28 @@ +/** + * @file daplink_addr.h + * @brief DAPLink Address Definitions Stub for BL702 + * + * Single-image build: no separate bootloader/interface regions. + */ + +#ifndef DAPLINK_ADDR_H +#define DAPLINK_ADDR_H + +#define DAPLINK_ROM_START 0x00000000 +#define DAPLINK_ROM_SIZE 0x00080000 +#define DAPLINK_ROM_IF_START 0x00000000 +#define DAPLINK_ROM_IF_SIZE 0x00080000 +#define DAPLINK_ROM_BL_START 0x00000000 +#define DAPLINK_ROM_BL_SIZE 0 + +#define DAPLINK_ROM_CONFIG_USER_START 0 +#define DAPLINK_ROM_CONFIG_USER_SIZE 0 +#define DAPLINK_RAM_START 0x42000000 +#define DAPLINK_RAM_SIZE 0x00020000 +#define DAPLINK_RAM_APP_START 0x42000000 +#define DAPLINK_RAM_APP_SIZE 0x00020000 +#define DAPLINK_RAM_SHARED_START 0 +#define DAPLINK_RAM_SHARED_SIZE 0 +#define DAPLINK_AUTOMATION_ALL 0 + +#endif diff --git a/firmware/app/daplink_bl702/daplink/daplink_defaults.h b/firmware/app/daplink_bl702/daplink/daplink_defaults.h new file mode 100644 index 0000000..4a65f8a --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/daplink_defaults.h @@ -0,0 +1,37 @@ +/** + * @file daplink_defaults.h + * @brief Default settings + * + * DAPLink Interface Firmware + * Copyright (c) 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 + * + * http://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. + */ + +#ifndef DAPLINK_DEFAULTS_H +#define DAPLINK_DEFAULTS_H + +#ifndef DAPLINK_HEAP_SIZE +#define DAPLINK_HEAP_SIZE 0x0 +#endif + +#ifndef DAPLINK_STACK_SIZE +#if defined(DAPLINK_BL) +#define DAPLINK_STACK_SIZE 0x800 +#elif defined(DAPLINK_IF) +#define DAPLINK_STACK_SIZE 0x200 +#endif +#endif + +#endif diff --git a/firmware/app/daplink_bl702/daplink/error.c b/firmware/app/daplink_bl702/daplink/error.c new file mode 100644 index 0000000..6ae2889 --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/error.c @@ -0,0 +1,272 @@ +/** + * @file error.c + * @brief Implementation of error.h + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2020, 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 + * + * http://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. + */ + +#include +#include "error.h" +#include "util.h" +#include "compiler.h" + +#if !DAPLINK_NO_ERROR_MESSAGES +static const char *const error_message[] = { + + /* Shared errors */ + + // ERROR_SUCCESS + "Operation was successful", + // ERROR_FAILURE + "An error has occurred", + // ERROR_INTERNAL + "An internal error has occurred", + + /* VFS user errors */ + + // ERROR_ERROR_DURING_TRANSFER + "An error occurred during the transfer", + // ERROR_TRANSFER_TIMEOUT + "The transfer timed out.", + // ERROR_FILE_BOUNDS + "Possible mismatch between file size and size programmed", + // ERROR_OOO_SECTOR + "File sent out of order by PC. Target might not be programmed correctly.", + + /* Target flash errors */ + + // ERROR_RESET + "Failed to reset/halt the target MCU", + // ERROR_ALGO_DL + "Failed to download flash algorithm to target MCU", + //ERROR_ALGO_MISSING + "Flash algorithm missing for a region", + // ERROR_ALGO_DATA_SEQ + "Failed to download the flash data contents to be programmed", + // ERROR_INIT + "Failed to initialize the target MCU", + // ERROR_UNINIT + "Failed to uninitialize the target MCU", + // ERROR_SECURITY_BITS + "Programming aborted: image would lock target MCU", + // ERROR_UNLOCK + "Failed to unlock target MCU for programming", + // ERROR_ERASE_SECTOR + "Flash algorithm erase sector command FAILURE", + // ERROR_ERASE_ALL + "Flash algorithm erase all command FAILURE", + // ERROR_WRITE + "Flash algorithm write command FAILURE", + // ERROR_WRITE_VERIFY + "Flash algorithm write verify command FAILURE", + + /* File stream errors */ + + // ERROR_SUCCESS_DONE + "End of stream has been reached", + // ERROR_SUCCESS_DONE_OR_CONTINUE + "End of stream is unknown", + // ERROR_HEX_CKSUM + "The hex file cannot be decoded. Checksum calculation failure occurred.", + // ERROR_HEX_PARSER + "The hex file cannot be decoded. Parser logic failure occurred.", + // ERROR_HEX_PROGRAM + "The hex file cannot be programmed. Logic failure occurred.", + // ERROR_HEX_INVALID_ADDRESS + "The hex file you dropped isn't compatible with this mode or device. Are you in MAINTENANCE mode? See HELP FAQ.HTM", + // ERROR_HEX_INVALID_APP_OFFSET + "The hex file offset load address is not correct.", + + /* Flash decoder errors */ + + // ERROR_FD_BL_UPDT_ADDR_WRONG + "The starting address for the bootloader update is wrong.", + // ERROR_FD_INTF_UPDT_ADDR_WRONG + "The starting address for the interface update is wrong.", + // ERROR_FD_UNSUPPORTED_UPDATE + "The application file format is unknown and cannot be parsed and/or processed.", + // ERROR_FD_INCOMPATIBLE_IMAGE + "The application image is not compatible with the target.", + + /* Flash IAP interface */ + + // ERROR_IAP_INIT + "In application programming initialization failed.", + // ERROR_IAP_UNINIT + "In application programming uninit failed.", + // ERROR_IAP_WRITE + "In application programming write failed.", + // ERROR_IAP_ERASE_SECTOR + "In application programming sector erase failed.", + // ERROR_IAP_ERASE_ALL + "In application programming mass erase failed.", + // ERROR_IAP_OUT_OF_BOUNDS + "In application programming aborted due to an out of bounds address.", + // ERROR_IAP_UPDT_NOT_SUPPORTED + "In application programming not supported on this device.", + // ERROR_IAP_UPDT_INCOMPLETE + "In application programming failed because the update sent was incomplete.", + // ERROR_IAP_NO_INTERCEPT + "", + // ERROR_BL_UPDT_BAD_CRC + "The bootloader CRC did not pass.", + +}; + +COMPILER_ASSERT(ERROR_COUNT == ARRAY_SIZE(error_message)); + +#endif // DAPLINK_NO_ERROR_MESSAGES + +static error_type_t error_type[] = { + + /* These should always stay the same for each error type. */ + + // ERROR_SUCCESS + 0, + // ERROR_FAILURE + ERROR_TYPE_INTERNAL, + // ERROR_INTERNAL + ERROR_TYPE_INTERNAL, + + /* VFS user errors */ + + // ERROR_ERROR_DURING_TRANSFER + ERROR_TYPE_TRANSIENT, + // ERROR_TRANSFER_TIMEOUT + ERROR_TYPE_USER | ERROR_TYPE_TRANSIENT, + // ERROR_FILE_BOUNDS + ERROR_TYPE_TRANSIENT, + // ERROR_OOO_SECTOR + ERROR_TYPE_TRANSIENT, + + /* Target flash errors */ + + // ERROR_RESET + ERROR_TYPE_TARGET, + // ERROR_ALGO_DL + ERROR_TYPE_TARGET, + //ERROR_ALGO_MISSING + ERROR_TYPE_TARGET, + // ERROR_ALGO_DATA_SEQ + ERROR_TYPE_TARGET, + // ERROR_INIT + ERROR_TYPE_TARGET, + // ERROR_UNINIT + ERROR_TYPE_TARGET, + // ERROR_SECURITY_BITS + ERROR_TYPE_USER, + // ERROR_UNLOCK + ERROR_TYPE_TARGET, + // ERROR_ERASE_SECTOR + ERROR_TYPE_TARGET, + // ERROR_ERASE_ALL + ERROR_TYPE_TARGET, + // ERROR_WRITE + ERROR_TYPE_TARGET, + // ERROR_WRITE_VERIFY + ERROR_TYPE_TARGET, + + /* File stream errors */ + + // ERROR_SUCCESS_DONE + ERROR_TYPE_INTERNAL, + // ERROR_SUCCESS_DONE_OR_CONTINUE + ERROR_TYPE_INTERNAL, + // ERROR_HEX_CKSUM + ERROR_TYPE_USER | ERROR_TYPE_TRANSIENT, + // ERROR_HEX_PARSER + ERROR_TYPE_USER | ERROR_TYPE_TRANSIENT, + // ERROR_HEX_PROGRAM + ERROR_TYPE_USER | ERROR_TYPE_TRANSIENT, + // ERROR_HEX_INVALID_ADDRESS + ERROR_TYPE_USER, + // ERROR_HEX_INVALID_APP_OFFSET + ERROR_TYPE_USER, + + /* Flash decoder errors */ + + // ERROR_FD_BL_UPDT_ADDR_WRONG + ERROR_TYPE_USER, + // ERROR_FD_INTF_UPDT_ADDR_WRONG + ERROR_TYPE_USER, + // ERROR_FD_UNSUPPORTED_UPDATE + ERROR_TYPE_USER, + // ERROR_FD_INCOMPATIBLE_IMAGE + ERROR_TYPE_USER, + + /* Flash IAP interface */ + + // ERROR_IAP_INIT + ERROR_TYPE_INTERFACE, + // ERROR_IAP_UNINIT + ERROR_TYPE_INTERFACE, + // ERROR_IAP_WRITE + ERROR_TYPE_INTERFACE, + // ERROR_IAP_ERASE_SECTOR + ERROR_TYPE_INTERFACE, + // ERROR_IAP_ERASE_ALL + ERROR_TYPE_INTERFACE, + // ERROR_IAP_OUT_OF_BOUNDS + ERROR_TYPE_INTERFACE, + // ERROR_IAP_UPDT_NOT_SUPPORTED + ERROR_TYPE_INTERFACE, + // ERROR_IAP_UPDT_INCOMPLETE + ERROR_TYPE_INTERFACE, + // ERROR_IAP_NO_INTERCEPT + ERROR_TYPE_INTERFACE, + // ERROR_BL_UPDT_BAD_CRC + ERROR_TYPE_INTERFACE, +}; + +COMPILER_ASSERT(ERROR_COUNT == ARRAY_SIZE(error_type)); + +const char *error_get_string(error_t error) +{ +#if !DAPLINK_NO_ERROR_MESSAGES + const char *msg = NULL; + + if (error < ERROR_COUNT) { + msg = error_message[error]; + } + + if (0 == msg) { + util_assert(0); + msg = ""; + } + + return msg; +#else // DAPLINK_NO_ERROR_MESSAGES + static char error_num_str[10] = "Error 00"; +#define ERROR_NUM_CHAR_INDEX (6) // offset of first '0' in error_num_str[] + + error_num_str[ERROR_NUM_CHAR_INDEX+0] = '0' + ((int)error / 1000) % 10; + error_num_str[ERROR_NUM_CHAR_INDEX+1] = '0' + ((int)error / 100) % 10; + COMPILER_ASSERT(ERROR_COUNT < 100); // if this assert is hit, add a digit here + error_num_str[ERROR_NUM_CHAR_INDEX+2] = 0; +#endif // DAPLINK_NO_ERROR_MESSAGES +} + +error_type_t error_get_type(error_t error) +{ + error_type_t type = ERROR_TYPE_INTERNAL; + + if (error < ERROR_COUNT) { + type = error_type[error]; + } + + return type; +} diff --git a/firmware/app/daplink_bl702/daplink/error.h b/firmware/app/daplink_bl702/daplink/error.h new file mode 100644 index 0000000..ed248cb --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/error.h @@ -0,0 +1,110 @@ +/** + * @file error.h + * @brief collection of known errors and accessor for the friendly string + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, 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 + * + * http://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. + */ + +#ifndef ERROR_H +#define ERROR_H + +#ifdef __cplusplus +extern "C" { +#endif + +// Keep in sync with the lists error_message and error_type +// New values shold be added to the end of the enum to preserve error codes +typedef enum { + /* Shared errors */ + ERROR_SUCCESS = 0, + ERROR_FAILURE, + ERROR_INTERNAL, + + /* VFS user errors */ + ERROR_ERROR_DURING_TRANSFER, + ERROR_TRANSFER_TIMEOUT, + ERROR_FILE_BOUNDS, + ERROR_OOO_SECTOR, + + /* Target flash errors */ + ERROR_RESET, + ERROR_ALGO_DL, + ERROR_ALGO_MISSING, + ERROR_ALGO_DATA_SEQ, + ERROR_INIT, + ERROR_UNINIT, + ERROR_SECURITY_BITS, + ERROR_UNLOCK, + ERROR_ERASE_SECTOR, + ERROR_ERASE_ALL, + ERROR_WRITE, + ERROR_WRITE_VERIFY, + + /* File stream errors */ + ERROR_SUCCESS_DONE, + ERROR_SUCCESS_DONE_OR_CONTINUE, + ERROR_HEX_CKSUM, + ERROR_HEX_PARSER, + ERROR_HEX_PROGRAM, + ERROR_HEX_INVALID_ADDRESS, + ERROR_HEX_INVALID_APP_OFFSET, + + /* Flash decoder error */ + ERROR_FD_BL_UPDT_ADDR_WRONG, + ERROR_FD_INTF_UPDT_ADDR_WRONG, + ERROR_FD_UNSUPPORTED_UPDATE, + ERROR_FD_INCOMPATIBLE_IMAGE, + + /* Flash IAP interface */ + ERROR_IAP_INIT, + ERROR_IAP_UNINIT, + ERROR_IAP_WRITE, + ERROR_IAP_ERASE_SECTOR, + ERROR_IAP_ERASE_ALL, + ERROR_IAP_OUT_OF_BOUNDS, + ERROR_IAP_UPDT_NOT_SUPPORTED, + ERROR_IAP_UPDT_INCOMPLETE, + ERROR_IAP_NO_INTERCEPT, + ERROR_BL_UPDT_BAD_CRC, + + // Add new values here + + ERROR_COUNT +} error_t; + +const char *error_get_string(error_t error); + +typedef unsigned char error_type_t; + +#define ERROR_TYPE_INTERNAL 0x1 +#define ERROR_TYPE_TRANSIENT 0x2 +#define ERROR_TYPE_USER 0x4 +#define ERROR_TYPE_TARGET 0x8 +#define ERROR_TYPE_INTERFACE 0x10 +// If you add another error type: +// 1. update error_type_names, used by read_file_fail_txt() +// 2. update ERROR_TYPE_MASK +// 3. make sure that error type bits still fit inside of error_type_t +#define ERROR_TYPE_MASK 0x1F + +error_type_t error_get_type(error_t error); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/firmware/app/daplink_bl702/daplink/info.c b/firmware/app/daplink_bl702/daplink/info.c new file mode 100644 index 0000000..05efa20 --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/info.c @@ -0,0 +1,324 @@ +/** + * @file info.c + * @brief Implementation of info.h + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2020 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 + * + * http://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. + */ + +#include +#include "info.h" +#include "target_config.h" +#include "read_uid.h" +#include "util.h" +#include "crc.h" +#include "daplink.h" +#include "settings.h" +#include "target_board.h" +#include "flash_hal.h" + +static char hex_to_ascii(uint8_t x) +{ + return ('0' + (x>9 ? x+0x27 : x)); +} + +// Constant variables +static const daplink_info_t *const info_bl = (daplink_info_t *)(DAPLINK_ROM_BL_START + DAPLINK_INFO_OFFSET); +static const daplink_info_t *const info_if = (daplink_info_t *)(DAPLINK_ROM_IF_START + DAPLINK_INFO_OFFSET); + +// Raw variables +static uint32_t host_id[4]; +static uint32_t target_id[4]; +static uint32_t hic_id = DAPLINK_HIC_ID; + +static uint32_t crc_bootloader; +static uint32_t crc_interface; +static uint32_t crc_config_user; + +// Strings +static char string_unique_id[48 + 1]; +static char string_mac[12 + 1]; +static char string_board_id[4 + 1]; +static char string_family_id[4 + 1]; +static char string_host_id[32 + 1]; +static char string_target_id[32 + 1]; +static char string_hic_id[8 + 1]; +static char string_version[4 + 1]; + +static char usb_desc_unique_id[2 + sizeof(string_unique_id) * 2]; + + +const char *info_get_unique_id(void) +{ + return string_unique_id; +} + +const char *info_get_board_id(void) +{ + return string_board_id; +} + +const char *info_get_host_id(void) +{ + return string_host_id; +} + +const char *info_get_target_id(void) +{ + return string_target_id; +} + +const char *info_get_hic_id(void) +{ + return string_hic_id; +} +const char *info_get_version(void) +{ + return string_version; +} +const char *info_get_mac(void) +{ + return string_mac; +} + +const char *info_get_unique_id_string_descriptor(void) +{ + return usb_desc_unique_id; +} + +//prevent the compiler to optimize board and family id +static void setup_basics(void) +{ + uint8_t i = 0, idx = 0; + uint16_t family_id = get_family_id(); + memset(string_board_id, 0, sizeof(string_board_id)); + memset(string_host_id, 0, sizeof(string_host_id)); + memset(string_target_id, 0, sizeof(string_target_id)); + memset(string_hic_id, 0, sizeof(string_hic_id)); + memset(string_board_id, 0, sizeof(string_board_id)); + // Host ID + idx = 0; + + for (i = 0; i < 4; i++) { + idx += util_write_hex32(string_host_id + idx, host_id[i]); + } + + string_host_id[idx++] = 0; + // Target ID + idx = 0; + + for (i = 0; i < 4; i++) { + idx += util_write_hex32(string_target_id + idx, target_id[i]); + } + + string_target_id[idx++] = 0; + // HIC ID + idx = 0; + idx += util_write_hex32(string_hic_id + idx, hic_id); + string_hic_id[idx++] = 0; + // Board ID + memcpy(string_board_id, get_board_id(), 4); + string_board_id[4] = 0; + idx = 0; + //Family ID + string_family_id[idx++] = hex_to_ascii(((family_id >> 12) & 0xF)); + string_family_id[idx++] = hex_to_ascii(((family_id >> 8) & 0xF)); +#if !(defined(DAPLINK_BL)) && defined(DRAG_N_DROP_SUPPORT) //need to change the unique id when the msd is disabled + #if defined(MSC_ENDPOINT) + if (config_ram_get_disable_msd() == 1 || flash_algo_valid()==0){ + string_family_id[idx++] = hex_to_ascii((((family_id >> 4) | 0x08) & 0xF)); + } else { + string_family_id[idx++] = hex_to_ascii(((family_id >> 4) & 0xF)); + } + #else //no msd support always have the most significant bit set for family id 2nd byte + string_family_id[idx++] = hex_to_ascii((((family_id >> 4) | 0x08) & 0xF)); + #endif +#else + string_family_id[idx++] = hex_to_ascii(((family_id >> 4) & 0xF)); +#endif + string_family_id[idx++] = hex_to_ascii(((family_id) & 0xF)); + string_family_id[idx++] = 0; + // Version + idx = 0; + string_version[idx++] = '0' + (DAPLINK_VERSION / 1000) % 10; + string_version[idx++] = '0' + (DAPLINK_VERSION / 100) % 10; + string_version[idx++] = '0' + (DAPLINK_VERSION / 10) % 10; + string_version[idx++] = '0' + (DAPLINK_VERSION / 1) % 10; + string_version[idx++] = 0; +} + +static void setup_unique_id() +{ + memset(string_unique_id, 0, sizeof(string_unique_id)); + strcat(string_unique_id, string_board_id); + strcat(string_unique_id, string_family_id); + strcat(string_unique_id, string_host_id); + strcat(string_unique_id, string_hic_id); +} + +static void setup_string_descriptor() +{ + uint8_t i = 0, idx = 0, len = 0; + len = strlen((const char *)string_unique_id); + // bLength + usb_desc_unique_id[idx++] = len * 2 + 2; + // bDescriptorType + usb_desc_unique_id[idx++] = 3; + + // bString + for (i = 0; i < len; i++) { + usb_desc_unique_id[idx++] = string_unique_id[i]; + usb_desc_unique_id[idx++] = 0; + } +} + +void info_init(void) +{ + info_crc_compute(); + read_unique_id(host_id); + setup_basics(); + setup_unique_id(); + setup_string_descriptor(); +} + +void info_set_uuid_target(uint32_t *uuid_data) +{ + uint32_t idx = 0; + // Save the target ID + memcpy(target_id, uuid_data, 16); + // patch for MAC use. Make sure MSB bits are set correctly + uuid_data[2] |= (0x2 << 8); + uuid_data[2] &= ~(0x1 << 8); + idx += util_write_hex16(string_mac + idx, uuid_data[2] & 0xFFFF); + idx += util_write_hex32(string_mac + idx, uuid_data[3]); + string_mac[idx++] = 0; +} + +bool info_get_bootloader_present(void) +{ + if (0 == DAPLINK_ROM_BL_SIZE) { + return false; + } + + // Check whether we can read the bootloader info. + if (!flash_is_readable((uint32_t)info_bl, sizeof(daplink_info_t))) { + return false; + } + + if (DAPLINK_BUILD_KEY_BL != info_bl->build_key) { + return false; + } + + if (DAPLINK_HIC_ID != info_bl->hic_id) { + return false; + } + + return true; +} + +bool info_get_interface_present(void) +{ + if (0 == DAPLINK_ROM_IF_SIZE) { + return false; + } + + // Check whether we can read the interface info. + if (!flash_is_readable((uint32_t)info_if, sizeof(daplink_info_t))) { + return false; + } + + if (DAPLINK_BUILD_KEY_IF != info_if->build_key) { + return false; + } + + if (DAPLINK_HIC_ID != info_if->hic_id) { + return false; + } + + return true; +} + +bool info_get_config_admin_present(void) +{ + //TODO, c1728p9 - check if admin config has been loaded + return false; +} + +bool info_get_config_user_present(void) +{ + //TODO, c1728p9 - check if user config has a valid key + return false; +} + +uint32_t info_get_crc_bootloader() +{ + return crc_bootloader; +} + +uint32_t info_get_crc_interface() +{ + return crc_interface; +} + +uint32_t info_get_crc_config_user() +{ + return crc_config_user; +} + +void info_crc_compute() +{ + crc_bootloader = 0; + crc_interface = 0; + crc_config_user = 0; + + // Compute the CRCs of regions that exist + if ((DAPLINK_ROM_BL_SIZE > 0) + && flash_is_readable(DAPLINK_ROM_BL_START, DAPLINK_ROM_BL_SIZE - 4)) { + crc_bootloader = crc32((void *)DAPLINK_ROM_BL_START, DAPLINK_ROM_BL_SIZE - 4); + } + + if ((DAPLINK_ROM_IF_SIZE > 0) + && flash_is_readable(DAPLINK_ROM_IF_START, DAPLINK_ROM_IF_SIZE - 4)) { + crc_interface = crc32((void *)DAPLINK_ROM_IF_START, DAPLINK_ROM_IF_SIZE - 4); + } + + if ((DAPLINK_ROM_CONFIG_USER_SIZE > 0) + && flash_is_readable(DAPLINK_ROM_CONFIG_USER_START, DAPLINK_ROM_CONFIG_USER_SIZE)) { + crc_config_user = crc32((void *)DAPLINK_ROM_CONFIG_USER_START, DAPLINK_ROM_CONFIG_USER_SIZE); + } +} + +// Get version info as an integer +uint32_t info_get_bootloader_version(void) +{ + // Don't read version if image is not present + if (!info_get_bootloader_present()) { + return 0; + } + + return info_bl->version; +} + +uint32_t info_get_interface_version(void) +{ + // Don't read version if image is not present + if (!info_get_interface_present()) { + return 0; + } + + return info_if->version; +} + diff --git a/firmware/app/daplink_bl702/daplink/info.h b/firmware/app/daplink_bl702/daplink/info.h new file mode 100644 index 0000000..2250f84 --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/info.h @@ -0,0 +1,91 @@ +/** + * @file info.h + * @brief methods to get information about the board + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, 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 + * + * http://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. + */ + +#ifndef INFO_H +#define INFO_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void info_init(void); +void info_set_uuid_target(uint32_t *uuid_data); +void info_crc_compute(void); + + +// Get the 48 digit unique ID as a null terminated string. +// This is the string used as the USB serial number. +// This string is made up of the following: +// +const char *info_get_unique_id(void); + +// Get the 4 digit board ID as a null terminated string +const char *info_get_board_id(void); + +// Get the 32 digit ID of the processor running daplink as a null terminated string +const char *info_get_host_id(void); + +// Get the 32 digit ID of the target processor as a null terminated string +const char *info_get_target_id(void); + +// Get the 8 digit hic ID as a null terminated string +const char *info_get_hic_id(void); + +// Get the 4 digit version ID as a null terminated string +const char *info_get_version(void); + +// Get the 12 digit mac as a null terminated string +const char *info_get_mac(void); + + +// Get the string descriptor for for the unique_id +// This is in the format of a USB string descriptor +// offset 0, size 1, bLength +// offset 1, size 1, bDescriptorType always 3 +// offset 2, size n, bString - unicode encoded unique id +const char *info_get_unique_id_string_descriptor(void); + + +// Check if various regions are present +bool info_get_bootloader_present(void); +bool info_get_interface_present(void); +bool info_get_config_admin_present(void); +bool info_get_config_user_present(void); + +// Get the CRCs of various regions. +// The CRC returned is only valid if +// the given region is present. +uint32_t info_get_crc_bootloader(void); +uint32_t info_get_crc_interface(void); +uint32_t info_get_crc_config_user(void); + +// Get version info as an integer +uint32_t info_get_bootloader_version(void); +uint32_t info_get_interface_version(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/firmware/app/daplink_bl702/daplink/util.c b/firmware/app/daplink_bl702/daplink/util.c new file mode 100644 index 0000000..9a7b1f4 --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/util.c @@ -0,0 +1,172 @@ +/** + * @file util.c + * @brief Implementation of util.h + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, 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 + * + * http://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. + */ + +#include + +#include "util.h" +#include "settings.h" +#include "cortex_m.h" + +//remove dependency from vfs_manager +__WEAK void vfs_mngr_fs_remount(void) {} + +uint32_t util_write_hex8(char *str, uint8_t value) +{ + static const char nybble_chars[] = "0123456789abcdef"; + *(str + 0) = nybble_chars[(value >> 4) & 0x0F ]; + *(str + 1) = nybble_chars[(value >> 0) & 0x0F ]; + return 2; +} + +uint32_t util_write_hex16(char *str, uint16_t value) +{ + uint32_t pos = 0; + pos += util_write_hex8(str + pos, (value >> 8) & 0xFF); + pos += util_write_hex8(str + pos, (value >> 0) & 0xFF); + return pos; +} + +uint32_t util_write_hex32(char *str, uint32_t value) +{ + uint32_t pos = 0; + pos += util_write_hex8(str + pos, (value >> 0x18) & 0xFF); + pos += util_write_hex8(str + pos, (value >> 0x10) & 0xFF); + pos += util_write_hex8(str + pos, (value >> 0x08) & 0xFF); + pos += util_write_hex8(str + pos, (value >> 0x00) & 0xFF); + return pos; +} + +uint32_t util_write_uint32(char *str, uint32_t value) +{ + uint32_t temp_val; + uint64_t digits; + uint32_t i; + // Count the number of digits + digits = 0; + temp_val = value; + + while (temp_val > 0) { + temp_val /= 10; + digits += 1; + } + + if (digits <= 0) { + digits = 1; + } + + // Write the number + for (i = 0; i < digits; i++) { + str[digits - i - 1] = '0' + (value % 10); + value /= 10; + } + + return digits; +} + +uint32_t util_write_uint32_zp(char *str, uint32_t value, uint16_t total_size) +{ + uint32_t size; + // Get the size of value + size = util_write_uint32(str, value); + + if (size >= total_size) { + return size; + } + + // Zero fill + memset(str, '0', total_size); + // Write value + util_write_uint32(str + (total_size - size), value); + return total_size; +} + +uint32_t util_write_string(char *str, const char *data) +{ + uint32_t pos = 0; + + while (0 != data[pos]) { + str[pos] = data[pos]; + pos++; + } + + return pos; +} + +uint32_t util_write_string_in_region(uint8_t *buf, uint32_t size, uint32_t start, uint32_t pos, const char *input) { + return util_write_in_region(buf, size, start, pos, input, strlen(input)); +} + +uint32_t util_write_in_region(uint8_t *buf, uint32_t size, uint32_t start, uint32_t pos, const char *input, uint32_t length) { + if (buf != NULL) { + // Check if there is something to copy + if (((pos + length) >= start) && (pos <= (start + size))) { + uint32_t i_off = 0; + uint32_t o_off = 0; + uint32_t l = length; + if (pos < start) { + i_off = start - pos; + l -= i_off; + } else { + o_off = pos - start; + } + if ((pos + length) > (start + size)) { + l -= (pos + length) - (start + size); + } + memcpy(buf + o_off, input + i_off, l); + } + } + + return length; +} + +void _util_assert(bool expression, const char *filename, uint16_t line) +{ + bool assert_set; + cortex_int_state_t int_state; + + if (expression) { + return; + } + + int_state = cortex_int_get_and_disable(); + // Only write the assert if there is not already one + assert_set = config_ram_get_assert(0, 0, 0, 0); + + if (!assert_set) { + config_ram_set_assert(filename, line); + } + + cortex_int_restore(int_state); + + // Start a remount if this is the first assert + // Do not call vfs_mngr_fs_remount from an ISR! + if (!assert_set && !cortex_in_isr()) { + vfs_mngr_fs_remount(); + } +} + +void util_assert_clear() +{ + cortex_int_state_t int_state; + int_state = cortex_int_get_and_disable(); + config_ram_clear_assert(); + cortex_int_restore(int_state); +} diff --git a/firmware/app/daplink_bl702/daplink/util.h b/firmware/app/daplink_bl702/daplink/util.h new file mode 100644 index 0000000..f0970bb --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/util.h @@ -0,0 +1,104 @@ +/** + * @file util.h + * @brief useful things + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2020, 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 + * + * http://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. + */ + +#ifndef UTIL_H +#define UTIL_H + +#include +#include +#include "compiler.h" + +// Protect commonly-defined macros with ifdefs, to prevent conflicts if redefined +// in imported sources (mostly vendor SDKs). + +//! @brief Round up division to nearest number of words. +#define WORDS(s) (((s) + sizeof(uint32_t) - 1) / sizeof(uint32_t)) + +#if !defined(ARRAY_SIZE) +//! @brief Get number of elements in the array. +#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) +#endif + +#if !defined(MIN) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#if !defined(MAX) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#define MB(size) ((size) * 1024 * 1024) + +#define KB(size) ((size) * 1024) + +#define ROUND_UP(value, boundary) ((value) + ((boundary) - (value)) % (boundary)) + +#define ROUND_DOWN(value, boundary) ((value) - ((value) % (boundary))) + +#ifdef __cplusplus +extern "C" { +#endif + +// Write the value to the address specified and return the size +uint32_t util_write_hex8(char *str, uint8_t value); +uint32_t util_write_hex16(char *str, uint16_t value); +uint32_t util_write_hex32(char *str, uint32_t value); +uint32_t util_write_uint32(char *str, uint32_t value); +uint32_t util_write_uint32(char *str, uint32_t value); +uint32_t util_write_uint32_zp(char *str, uint32_t value, uint16_t total_size); +uint32_t util_write_string(char *str, const char *data); + +uint32_t util_write_in_region(uint8_t *buf, uint32_t size, uint32_t start, + uint32_t pos, const char *input, uint32_t length); +uint32_t util_write_string_in_region(uint8_t *buf, uint32_t size, uint32_t start, + uint32_t pos, const char *input); + +__STATIC_INLINE uint32_t util_div_round_up(uint32_t dividen, uint32_t divisor) +{ + return (dividen + divisor - 1) / divisor; +} + +__STATIC_INLINE uint32_t util_div_round_down(uint32_t dividen, uint32_t divisor) +{ + return dividen / divisor; +} + +__STATIC_INLINE uint32_t util_div_round(uint32_t dividen, uint32_t divisor) +{ + return (dividen + divisor / 2) / divisor; +} + +#if !(defined(DAPLINK_NO_ASSERT_FILENAMES) && defined(DAPLINK_BL)) +// With the filename enabled. +#define util_assert(expression) _util_assert((expression), __FILE__, __LINE__) +#else +// Filename disabled to save code size. +#define util_assert(expression) _util_assert((expression), "(file)", __LINE__) +#endif +void _util_assert(bool expression, const char *filename, uint16_t line); + +void util_assert_clear(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/firmware/app/daplink_bl702/daplink/validation.c b/firmware/app/daplink_bl702/daplink/validation.c new file mode 100644 index 0000000..0a3134f --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/validation.c @@ -0,0 +1,96 @@ +/** + * @file validation.c + * @brief Implementation of validation.h + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2019, 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 + * + * http://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. + */ + +#include +#include "validation.h" +#include "target_config.h" +#include "target_family.h" +#include "target_board.h" + +static inline uint32_t test_range(const uint32_t test, const uint32_t min, const uint32_t max) +{ + return ((test < min) || (test > max)) ? 0 : 1; +} + +uint8_t validate_bin_nvic(const uint8_t *buf) +{ + if (g_target_family && g_target_family->validate_bin_nvic) { + return g_target_family && g_target_family->validate_bin_nvic(buf); + } else { + return validate_bin_nvic_base(buf); + } +} + +uint8_t validate_bin_nvic_base(const uint8_t *buf) +{ + if (g_board_info.target_cfg) { + uint32_t i = 4, nvic_val = 0; + uint8_t in_range = 0; + // test the initial SP value + memcpy(&nvic_val, buf + 0, sizeof(nvic_val)); + + region_info_t * region = g_board_info.target_cfg->ram_regions; + for (; region->start != 0 || region->end != 0; ++region) { + if (1 == test_range(nvic_val, region->start, region->end)) { + in_range = 1; + break; + } + } + + if (in_range == 0) { + return 0; + } + + // Reset_Handler + // NMI_Handler + // HardFault_Handler + for (; i <= 12; i += 4) { + in_range = 0; + memcpy(&nvic_val, buf + i, sizeof(nvic_val)); + region_info_t * region = g_board_info.target_cfg->flash_regions; + for (; region->start != 0 || region->end != 0; ++region) { + if (1 == test_range(nvic_val, region->start, region->end)) { + in_range = 1; + break; + } + } + if (in_range == 0) { + return 0; + } + } + + return 1; + + } else { + return 0; + } +} + +uint8_t validate_hexfile(const uint8_t *buf) +{ + if (g_target_family && g_target_family->validate_hexfile) { + return g_target_family->validate_hexfile(buf); + } else { + // look here for known hex records + // add hex identifier b[0] == ':' && b[8] == {'0', '2', '3', '4', '5'} + return ((buf[0] == ':') && ((buf[8] == '0') || (buf[8] == '2') || (buf[8] == '3') || (buf[8] == '4') || (buf[8] == '5'))) ? 1 : 0; + } +} diff --git a/firmware/app/daplink_bl702/daplink/validation.h b/firmware/app/daplink_bl702/daplink/validation.h new file mode 100644 index 0000000..929d827 --- /dev/null +++ b/firmware/app/daplink_bl702/daplink/validation.h @@ -0,0 +1,46 @@ +/** + * @file validation.h + * @brief Helper functions to determine if a hex or binary file is valid + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2020, 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 + * + * http://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. + */ + +#ifndef VALIDATION_H +#define VALIDATION_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +uint8_t validate_bin_nvic(const uint8_t *buf); +uint8_t validate_hexfile(const uint8_t *buf); + +/*! + * @brief Baseline implementation of NVIC validator. + * + * This version does not include the redirection to a target family validator if + * one is supplied in the target family struct. + */ +uint8_t validate_bin_nvic_base(const uint8_t *buf); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/firmware/app/daplink_bl702/hic_hal/DAP_config.h b/firmware/app/daplink_bl702/hic_hal/DAP_config.h new file mode 100644 index 0000000..776b349 --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/DAP_config.h @@ -0,0 +1,252 @@ +/** + * @file DAP_config.h + * @brief CMSIS-DAP Configuration for BL702 (DAPLink-style) + * + * DAPLink Interface Firmware - BL702 Port + * + * Uses DAPLink's IO_Config.h for pin definitions, separating pin mapping + * from CMSIS-DAP protocol configuration. + */ + +#ifndef __DAP_CONFIG_H__ +#define __DAP_CONFIG_H__ + +#include "IO_Config.h" +#include "hal_gpio.h" +#include "hal_mtimer.h" +#include "gpio.h" +#include + +/* For __STATIC_INLINE, __STATIC_FORCEINLINE, __WEAK, __NOP */ +#include "cmsis_compiler.h" + + +//************************************************************************************************** +/** +\defgroup DAP_Config_Debug_gr CMSIS-DAP Debug Unit Information +@{ +*/ + +/// Processor Clock: BL702 max 144MHz +#define CPU_CLOCK 144000000U + +/// I/O Port write cycles (RISC-V typical: 2) +#define IO_PORT_WRITE_CYCLES 2U + +/// SWD support: enabled +#define DAP_SWD 1 + +/// JTAG support: enabled +#define DAP_JTAG 1 + +/// Max JTAG devices on scan chain +#define DAP_JTAG_DEV_CNT 8U + +/// Default port mode: 1=SWD, 2=JTAG +#define DAP_DEFAULT_PORT 1U + +/// Default SWD/JTAG clock: 1MHz +#define DAP_DEFAULT_SWJ_CLOCK 1000000U + +/// Packet size: 64 bytes (Full-speed USB BULK) +#define DAP_PACKET_SIZE 64U + +/// Packet buffers: 4 (BL702 SRAM-constrained) +#define DAP_PACKET_COUNT 4U + +/// SWO UART trace: not implemented (GPIO1/UART0 conflicts with JTAG TDO) +#define SWO_UART 0 +#define SWO_UART_DRIVER 0 +#define SWO_UART_MAX_BAUDRATE 10000000U + +/// SWO Manchester: not implemented +#define SWO_MANCHESTER 0 +#define SWO_BUFFER_SIZE 4096U +#define SWO_STREAM 0 + +/// Timestamp clock: 1MHz (BL702 mtime) +#define TIMESTAMP_CLOCK 1000000U + +/// UART COM port: not implemented +#define DAP_UART 0 +#define DAP_UART_DRIVER 0 +#define DAP_UART_RX_BUFFER_SIZE 1024U +#define DAP_UART_TX_BUFFER_SIZE 1024U + +/// USB COM Port: not implemented +#define DAP_UART_USB_COM_PORT 0 + +/// Fixed target: no +#define TARGET_FIXED 0 + +/* String functions */ +__STATIC_INLINE uint8_t DAP_GetVendorString (char *str) { + (void)str; return 0U; +} +__STATIC_INLINE uint8_t DAP_GetProductString (char *str) { + const char *p = "DAPLink CMSIS-DAP"; + uint8_t len = (uint8_t)strlen(p) + 1U; + memcpy(str, p, len); return len; +} +__STATIC_INLINE uint8_t DAP_GetSerNumString (char *str) { + const char *p = "202400000001"; + uint8_t len = (uint8_t)strlen(p) + 1U; + memcpy(str, p, len); return len; +} +__STATIC_INLINE uint8_t DAP_GetTargetDeviceVendorString (char *str) { (void)str; return 0U; } +__STATIC_INLINE uint8_t DAP_GetTargetDeviceNameString (char *str) { (void)str; return 0U; } +__STATIC_INLINE uint8_t DAP_GetTargetBoardVendorString (char *str) { (void)str; return 0U; } +__STATIC_INLINE uint8_t DAP_GetTargetBoardNameString (char *str) { (void)str; return 0U; } +__STATIC_INLINE uint8_t DAP_GetProductFirmwareVersionString (char *str) { (void)str; return 0U; } + +///@} + + +//************************************************************************************************** +/** +\defgroup DAP_Config_PortIO_gr CMSIS-DAP Hardware I/O Pin Access +@{ + +All GPIO operations use BL702 HAL: gpio_write(), gpio_read(), gpio_set_mode() +Pin numbers defined in IO_Config.h +*/ + +// JTAG/SWD Port Setup +__STATIC_INLINE void PORT_JTAG_SETUP (void) { + gpio_set_mode(SWCLK_TCK_PIN, GPIO_OUTPUT_MODE); gpio_write(SWCLK_TCK_PIN, 1); + gpio_set_mode(SWDIO_TMS_PIN, GPIO_OUTPUT_MODE); gpio_write(SWDIO_TMS_PIN, 1); + gpio_set_mode(TDI_PIN, GPIO_OUTPUT_MODE); gpio_write(TDI_PIN, 1); + gpio_set_mode(TDO_PIN, GPIO_INPUT_MODE); + gpio_set_mode(NRESET_PIN, GPIO_OUTPUT_MODE); gpio_write(NRESET_PIN, 1); +} +__STATIC_INLINE void PORT_SWD_SETUP (void) { + gpio_set_mode(SWCLK_TCK_PIN, GPIO_OUTPUT_MODE); gpio_write(SWCLK_TCK_PIN, 1); + gpio_set_mode(SWDIO_TMS_PIN, GPIO_OUTPUT_MODE); gpio_write(SWDIO_TMS_PIN, 1); + gpio_set_mode(NRESET_PIN, GPIO_OUTPUT_MODE); gpio_write(NRESET_PIN, 1); + gpio_set_mode(TDI_PIN, GPIO_HZ_MODE); +} +__STATIC_INLINE void PORT_OFF (void) { + gpio_set_mode(SWCLK_TCK_PIN, GPIO_HZ_MODE); + gpio_set_mode(SWDIO_TMS_PIN, GPIO_HZ_MODE); + gpio_set_mode(TDI_PIN, GPIO_HZ_MODE); + gpio_set_mode(TDO_PIN, GPIO_HZ_MODE); + gpio_set_mode(NRESET_PIN, GPIO_HZ_MODE); +} + +// SWCLK/TCK +__STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN (void) { return (uint32_t)gpio_read(SWCLK_TCK_PIN); } +__STATIC_FORCEINLINE void PIN_SWCLK_TCK_SET (void) { gpio_write(SWCLK_TCK_PIN, 1); } +__STATIC_FORCEINLINE void PIN_SWCLK_TCK_CLR (void) { gpio_write(SWCLK_TCK_PIN, 0); } + +// SWDIO/TMS +__STATIC_FORCEINLINE uint32_t PIN_SWDIO_TMS_IN (void) { return (uint32_t)gpio_read(SWDIO_TMS_PIN); } +__STATIC_FORCEINLINE void PIN_SWDIO_TMS_SET (void) { gpio_write(SWDIO_TMS_PIN, 1); } +__STATIC_FORCEINLINE void PIN_SWDIO_TMS_CLR (void) { gpio_write(SWDIO_TMS_PIN, 0); } +__STATIC_FORCEINLINE uint32_t PIN_SWDIO_IN (void) { return (uint32_t)gpio_read(SWDIO_TMS_PIN); } +__STATIC_FORCEINLINE void PIN_SWDIO_OUT (uint32_t b) { gpio_write(SWDIO_TMS_PIN, (b & 1U) ? 1 : 0); } +__STATIC_FORCEINLINE void PIN_SWDIO_OUT_ENABLE (void) { gpio_set_mode(SWDIO_TMS_PIN, GPIO_OUTPUT_MODE); } +__STATIC_FORCEINLINE void PIN_SWDIO_OUT_DISABLE (void) { gpio_set_mode(SWDIO_TMS_PIN, GPIO_INPUT_MODE); } + +// TDI +__STATIC_FORCEINLINE uint32_t PIN_TDI_IN (void) { return (uint32_t)gpio_read(TDI_PIN); } +__STATIC_FORCEINLINE void PIN_TDI_OUT (uint32_t b) { gpio_write(TDI_PIN, (b & 1U) ? 1 : 0); } + +// TDO +__STATIC_FORCEINLINE uint32_t PIN_TDO_IN (void) { return (uint32_t)gpio_read(TDO_PIN); } + +// nTRST (not connected on BL702 board) +__STATIC_FORCEINLINE uint32_t PIN_nTRST_IN (void) { return 0U; } +__STATIC_FORCEINLINE void PIN_nTRST_OUT (uint32_t b) { (void)b; } + +// nRESET +__STATIC_FORCEINLINE uint32_t PIN_nRESET_IN (void) { return (uint32_t)gpio_read(NRESET_PIN); } +__STATIC_FORCEINLINE void PIN_nRESET_OUT (uint32_t b) { + if (b) { + /* Release reset: MUST drive high BEFORE changing mode. + * gpio_set_mode() preserves the previous output value, so if we + * change mode first the pin stays low for the duration of the call, + * generating a spurious reset pulse that disrupts SWD. */ + gpio_write(NRESET_PIN, 1); + gpio_set_mode(NRESET_PIN, GPIO_OUTPUT_PP_MODE); + } else { + /* Assert reset: drive low */ + gpio_set_mode(NRESET_PIN, GPIO_OUTPUT_MODE); + gpio_write(NRESET_PIN, 0); + } +} + +///@} + + +//************************************************************************************************** +/** +\defgroup DAP_Config_LEDs_gr CMSIS-DAP Hardware Status LEDs +@{ +*/ +__STATIC_INLINE void LED_CONNECTED_OUT (uint32_t bit) { gpio_write(CONNECTED_LED_PIN, (bit & 1U) ? 0 : 1); } +__STATIC_INLINE void LED_RUNNING_OUT (uint32_t bit) { gpio_write(RUNNING_LED_PIN, (bit & 1U) ? 0 : 1); } +///@} + + +//************************************************************************************************** +/** +\defgroup DAP_Config_Timestamp_gr CMSIS-DAP Timestamp +@{ +*/ +__STATIC_INLINE uint32_t TIMESTAMP_GET (void) { return (uint32_t)mtimer_get_time_us(); } +///@} + + +//************************************************************************************************** +/** +\defgroup DAP_Config_Initialization_gr CMSIS-DAP Initialization +@{ +*/ +__STATIC_INLINE void DAP_SETUP (void) { + gpio_init(); /* Initialize all pins via HIC HAL */ +} +__STATIC_INLINE uint8_t RESET_TARGET (void) { + /* Hardware reset via nRESET pin (GPIO_PIN_3). + * Sequence: assert low → wait 20ms → release high → wait 20ms. + * Uses push-pull with internal pull-up when releasing to avoid + * floating when the target board lacks an external pull-up. */ + uint32_t delay; + + /* Assert reset: drive low */ + gpio_set_mode(NRESET_PIN, GPIO_OUTPUT_MODE); + gpio_write(NRESET_PIN, 0); + + /* Wait ~20ms (144MHz CPU, ~3 cycles/loop_iter) */ + for (delay = 960000U; delay; delay--) { + __NOP(); + } + + /* Release reset: drive high with internal pull-up */ + gpio_write(NRESET_PIN, 1); + gpio_set_mode(NRESET_PIN, GPIO_OUTPUT_PP_MODE); + + /* Wait ~20ms for target to stabilize */ + for (delay = 960000U; delay; delay--) { + __NOP(); + } + + return 1U; /* Reset performed */ +} +///@} + + +//************************************************************************************************** +/** +\defgroup DAP_Config_Delay_gr CMSIS-DAP Delay calibration (RISC-V) +@{ +*/ +#ifndef DELAY_SLOW_CYCLES +#define DELAY_SLOW_CYCLES 3U +#endif +#ifndef DELAY_FAST_CYCLES +#define DELAY_FAST_CYCLES 0U +#endif +///@} + + +#endif /* __DAP_CONFIG_H__ */ diff --git a/firmware/app/daplink_bl702/hic_hal/IO_Config.h b/firmware/app/daplink_bl702/hic_hal/IO_Config.h new file mode 100644 index 0000000..460d152 --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/IO_Config.h @@ -0,0 +1,71 @@ +/** + * @file IO_Config.h + * @brief I/O Pin Configuration for BL702 CMSIS-DAP Debug Probe + * + * DAPLink Interface Firmware - BL702 Port + * Based on the BL702 USB2JTAG board pinout. + * + * BL702 uses flat GPIO numbering (GPIO_PIN_0..31), unlike STM32's PORT+PIN. + * All pins are mapped directly to GPIO pin numbers. + */ + +#ifndef __IO_CONFIG_H__ +#define __IO_CONFIG_H__ + +#include "hal_gpio.h" +#include "compiler.h" + +/* ======================================================================== + * Debug Interface Pins (SWD/JTAG) + * ======================================================================== */ + +/* SWCLK / TCK */ +#define SWCLK_TCK_PIN GPIO_PIN_15 + +/* SWDIO / TMS (bidirectional: output + input on same pin) */ +#define SWDIO_TMS_PIN GPIO_PIN_2 + +/* TDI (JTAG only) */ +#define TDI_PIN GPIO_PIN_0 + +/* TDO (JTAG only) */ +#define TDO_PIN GPIO_PIN_1 + +/* nRESET - Target reset (open-drain, active low) */ +#define NRESET_PIN GPIO_PIN_3 + +/* ======================================================================== + * Status LEDs (active-low: 0 = ON, 1 = OFF) + * ======================================================================== */ + +/* Connected / HID LED - indicates debugger is connected */ +#define CONNECTED_LED_PIN GPIO_PIN_9 + +/* Running / CDC LED - indicates target is running */ +#define RUNNING_LED_PIN GPIO_PIN_17 + +/* MSC LED - indicates MSC activity (shared with HID LED for now) */ +#define MSC_LED_PIN GPIO_PIN_9 + +/* ======================================================================== + * USB Control + * ======================================================================== */ + +/* USB Connect (D+ pull-up enable) - BL702 handles this in hardware */ +/* No GPIO control needed */ + +/* ======================================================================== + * Target Power Control (optional) + * ======================================================================== */ + +/* If board has a power switch for the target, define the pin here */ +/* #define POWER_EN_PIN GPIO_PIN_xx */ + +/* ======================================================================== + * Reset Button (optional) + * ======================================================================== */ + +/* If board has a reset button */ +/* #define RESET_BTN_PIN GPIO_PIN_xx */ + +#endif /* __IO_CONFIG_H__ */ diff --git a/firmware/app/daplink_bl702/hic_hal/cmsis_compiler.h b/firmware/app/daplink_bl702/hic_hal/cmsis_compiler.h new file mode 100644 index 0000000..f902eea --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/cmsis_compiler.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024 CMSIS-DAP BL702 Port + * + * SPDX-License-Identifier: Apache-2.0 + * + * RISC-V CMSIS Compiler Adapter + * + * Maps ARM CMSIS compiler-specific macros to RISC-V (GCC) equivalents. + */ + +#ifndef __CMSIS_COMPILER_H__ +#define __CMSIS_COMPILER_H__ + +#include +#include + +/* === Inline macros === */ +#ifndef __STATIC_INLINE +#define __STATIC_INLINE static inline +#endif + +#ifndef __STATIC_FORCEINLINE +#define __STATIC_FORCEINLINE static inline __attribute__((always_inline)) +#endif + +#ifndef __WEAK +#define __WEAK __attribute__((weak)) +#endif + +/* === No Operation (NOP) === */ +#ifndef __NOP +#define __NOP() __asm__ volatile ("nop") +#endif + +/* === Inline Assembly === */ +#ifndef __ASM +#define __ASM __asm__ +#endif +#ifndef __ASM_VOLATILE +#define __ASM_VOLATILE __asm__ volatile +#endif + +/* === Packed attribute === */ +#ifndef __PACKED +#define __PACKED __attribute__((packed)) +#endif + +#ifndef __PACKED_STRUCT +#define __PACKED_STRUCT struct __attribute__((packed)) +#endif + +/* === Unused parameter === */ +#ifndef __UNUSED +#define __UNUSED(x) (void)(x) +#endif + +/* === No return === */ +#ifndef __NO_RETURN +#define __NO_RETURN __attribute__((noreturn)) +#endif + +/* === Section attribute === */ +#ifndef __SECTION +#define __SECTION(x) __attribute__((section(x))) +#endif + +/* === Aligned attribute === */ +#ifndef __ALIGNED +#define __ALIGNED(x) __attribute__((aligned(x))) +#endif + +/* === CLZ (Count Leading Zeros) === */ +__STATIC_FORCEINLINE uint32_t __CLZ(uint32_t value) { + if (value == 0U) return 32U; + return (uint32_t)__builtin_clz(value); +} + +#endif /* __CMSIS_COMPILER_H__ */ diff --git a/firmware/app/daplink_bl702/hic_hal/compiler.h b/firmware/app/daplink_bl702/hic_hal/compiler.h new file mode 100644 index 0000000..fddcc4a --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/compiler.h @@ -0,0 +1,14 @@ +/** + * @file compiler.h + * @brief Compiler Abstraction Macros (BL702 / RISC-V) + * + * DAPLink Interface Firmware - BL702 Port + */ + +#ifndef COMPILER_H +#define COMPILER_H + +/* Static assertion */ +#define COMPILER_ASSERT(expr) _Static_assert(expr, #expr) + +#endif diff --git a/firmware/app/daplink_bl702/hic_hal/device.h b/firmware/app/daplink_bl702/hic_hal/device.h new file mode 100644 index 0000000..cc7d9e0 --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/device.h @@ -0,0 +1,20 @@ +/** + * @file device.h + * @brief Device Header for BL702 (DAPLink-style) + * + * DAPLink Interface Firmware - BL702 Port + * + * Maps the INTERFACE_BL702 define to the BL702 CMSIS/device headers. + */ + +#ifndef DEVICE_H +#define DEVICE_H + +#if defined (INTERFACE_BL702) +/* BL702 RISC-V MCU - No CMSIS device header needed */ +/* DAPLink CMSIS-DAP core only needs this file to exist */ +#else +#error "Unknown INTERFACE_xxx define" +#endif + +#endif /* DEVICE_H */ diff --git a/firmware/app/daplink_bl702/hic_hal/flash.c b/firmware/app/daplink_bl702/hic_hal/flash.c new file mode 100644 index 0000000..9026999 --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/flash.c @@ -0,0 +1,35 @@ +/** + * @file flash.c + * @brief Flash HAL stub for BL702 + * + * DAPLink Interface Firmware - BL702 Port + * + * Stub implementation: BL702 as a debug probe does not self-program its flash. + * CMSIS-DAP core does not use these functions directly; they are for MSC + * drag-n-drop and bootloader features (Phase 5+). + */ + +#include +#include +#include "flash_hal.h" + +uint32_t flash_program_page(uint32_t adr, uint32_t sz, uint8_t *buf) +{ + (void)adr; + (void)sz; + (void)buf; + return 1; /* Error: not implemented */ +} + +uint32_t flash_erase_sector(uint32_t addr) +{ + (void)addr; + return 1; /* Error: not implemented */ +} + +bool flash_is_readable(uint32_t addr, uint32_t length) +{ + (void)addr; + (void)length; + return false; /* Stub */ +} diff --git a/firmware/app/daplink_bl702/hic_hal/flash_hal.h b/firmware/app/daplink_bl702/hic_hal/flash_hal.h new file mode 100644 index 0000000..362a32d --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/flash_hal.h @@ -0,0 +1,28 @@ +/** + * @file flash_hal.h + * @brief Flash HAL Interface for DAPLink HIC HAL + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2020, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef FLASH_HAL_H +#define FLASH_HAL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +uint32_t flash_program_page(uint32_t adr, uint32_t sz, uint8_t *buf); +uint32_t flash_erase_sector(uint32_t addr); +bool flash_is_readable(uint32_t addr, uint32_t length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/firmware/app/daplink_bl702/hic_hal/gpio.c b/firmware/app/daplink_bl702/hic_hal/gpio.c new file mode 100644 index 0000000..43e2af7 --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/gpio.c @@ -0,0 +1,89 @@ +/** + * @file gpio.c + * @brief GPIO Driver for BL702 CMSIS-DAP Debug Probe + * + * DAPLink Interface Firmware - BL702 Port + * + * Implements the DAPLink HIC HAL gpio.h interface using BL702 HAL GPIO API. + * + * LED convention (following DAPLink): + * - HID LED = CONNECTED_LED (GPIO_9) - on when debugger connected + * - CDC LED = running status (GPIO_17) - on when target running + * - MSC LED = activity (GPIO_9) - flashes during MSC activity + */ + +#include +#include "hal_gpio.h" +#include "IO_Config.h" +#include "gpio.h" +#include "compiler.h" + +void gpio_init(void) +{ + /* Initialize LED pins as outputs, LEDs OFF (active-low: 1=OFF) */ + gpio_set_mode(CONNECTED_LED_PIN, GPIO_OUTPUT_MODE); + gpio_write(CONNECTED_LED_PIN, 1); + + gpio_set_mode(RUNNING_LED_PIN, GPIO_OUTPUT_MODE); + gpio_write(RUNNING_LED_PIN, 1); + + gpio_set_mode(MSC_LED_PIN, GPIO_OUTPUT_MODE); + gpio_write(MSC_LED_PIN, 1); + + /* Initialize debug interface pins to Hi-Z (will be configured by DAP_Setup) */ + gpio_set_mode(SWCLK_TCK_PIN, GPIO_HZ_MODE); + gpio_set_mode(SWDIO_TMS_PIN, GPIO_HZ_MODE); + gpio_set_mode(TDI_PIN, GPIO_HZ_MODE); + gpio_set_mode(TDO_PIN, GPIO_HZ_MODE); + gpio_set_mode(NRESET_PIN, GPIO_HZ_MODE); + +#ifdef RESET_BTN_PIN + gpio_set_mode(RESET_BTN_PIN, GPIO_INPUT_MODE); +#endif + +#ifdef POWER_EN_PIN + gpio_set_mode(POWER_EN_PIN, GPIO_OUTPUT_MODE); + gpio_write(POWER_EN_PIN, 0); /* Power off initially */ +#endif +} + +void gpio_set_board_power(bool powerEnabled) +{ +#ifdef POWER_EN_PIN + gpio_write(POWER_EN_PIN, powerEnabled ? 1 : 0); +#else + (void)powerEnabled; +#endif +} + +void gpio_set_hid_led(gpio_led_state_t state) +{ + /* Active-low: GPIO_LED_ON (1) → write 0; GPIO_LED_OFF (0) → write 1 */ + gpio_write(CONNECTED_LED_PIN, (state == GPIO_LED_ON) ? 0 : 1); +} + +void gpio_set_cdc_led(gpio_led_state_t state) +{ + gpio_write(RUNNING_LED_PIN, (state == GPIO_LED_ON) ? 0 : 1); +} + +void gpio_set_msc_led(gpio_led_state_t state) +{ + gpio_write(MSC_LED_PIN, (state == GPIO_LED_ON) ? 0 : 1); +} + +uint8_t gpio_get_reset_btn_no_fwrd(void) +{ +#ifdef RESET_BTN_PIN + /* Active-low button: pressed = 0 */ + return (gpio_read(RESET_BTN_PIN) == 0) ? 1 : 0; +#else + return 0; +#endif +} + +uint8_t gpio_get_reset_btn_fwrd(void) +{ + /* Same as no_fwrd for simple probe (no separate forward pin) */ + return gpio_get_reset_btn_no_fwrd(); +} diff --git a/firmware/app/daplink_bl702/hic_hal/gpio.h b/firmware/app/daplink_bl702/hic_hal/gpio.h new file mode 100644 index 0000000..0272960 --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/gpio.h @@ -0,0 +1,45 @@ +/** + * @file gpio.h + * @brief GPIO Interface for DAPLink HIC HAL + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2019, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef GPIO_H +#define GPIO_H + +#include +#include "IO_Config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum led_state { + GPIO_LED_OFF = 0, + GPIO_LED_ON +} gpio_led_state_t; + +void gpio_init(void); +void gpio_set_board_power(bool powerEnabled); +void gpio_set_hid_led(gpio_led_state_t state); +void gpio_set_cdc_led(gpio_led_state_t state); +void gpio_set_msc_led(gpio_led_state_t state); +uint8_t gpio_get_reset_btn_no_fwrd(void); +uint8_t gpio_get_reset_btn_fwrd(void); +#ifdef PBON_BUTTON +uint8_t gpio_get_pbon_btn(void); +#endif + +static inline uint8_t gpio_get_reset_btn(void) +{ + return gpio_get_reset_btn_no_fwrd() || gpio_get_reset_btn_fwrd(); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/firmware/app/daplink_bl702/hic_hal/read_uid.c b/firmware/app/daplink_bl702/hic_hal/read_uid.c new file mode 100644 index 0000000..1b57475 --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/read_uid.c @@ -0,0 +1,51 @@ +/** + * @file read_uid.c + * @brief Unique ID Reader for BL702 + * + * DAPLink Interface Firmware - BL702 Port + * Reads the BL702 chip unique ID via EF_Ctrl. + */ + +#include +#include +#include "read_uid.h" +#include "bl702_ef_ctrl.h" + +static uint32_t g_unique_id[2] = { 0, 0 }; +static char g_unique_id_str[17] = ""; /* 8 hex bytes + null */ + +void read_unique_id(uint32_t *id) +{ + uint8_t chip_id[8]; + EF_Ctrl_Read_Chip_ID(chip_id); + + /* Pack 8 bytes into 2 x 32-bit words */ + id[0] = ((uint32_t)chip_id[0] << 0) | + ((uint32_t)chip_id[1] << 8) | + ((uint32_t)chip_id[2] << 16) | + ((uint32_t)chip_id[3] << 24); + id[1] = ((uint32_t)chip_id[4] << 0) | + ((uint32_t)chip_id[5] << 8) | + ((uint32_t)chip_id[6] << 16) | + ((uint32_t)chip_id[7] << 24); +} + +void create_unique_id(void) +{ + static const char hex[] = "0123456789ABCDEF"; + uint8_t chip_id[8]; + int i; + + EF_Ctrl_Read_Chip_ID(chip_id); + + for (i = 0; i < 8; i++) { + g_unique_id_str[i * 2 + 0] = hex[(chip_id[i] >> 4) & 0x0F]; + g_unique_id_str[i * 2 + 1] = hex[ chip_id[i] & 0x0F]; + } + g_unique_id_str[16] = '\0'; +} + +const char *read_unique_id_str(void) +{ + return g_unique_id_str; +} diff --git a/firmware/app/daplink_bl702/hic_hal/read_uid.h b/firmware/app/daplink_bl702/hic_hal/read_uid.h new file mode 100644 index 0000000..374103c --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/read_uid.h @@ -0,0 +1,27 @@ +/** + * @file read_uid.h + * @brief Unique ID Reader Interface + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef READ_UID_H +#define READ_UID_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void read_unique_id(uint32_t *id); +void create_unique_id(void); +const char *read_unique_id_str(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/firmware/app/daplink_bl702/hic_hal/rl_usb.h b/firmware/app/daplink_bl702/hic_hal/rl_usb.h new file mode 100644 index 0000000..a37cbfc --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/rl_usb.h @@ -0,0 +1,52 @@ +/** + * @file rl_usb.h + * @brief RL-USB API Stub Header for DAPLink → BL702 Port + * + * Provides the function declarations needed by DAPLink core source files. + * Actual implementation maps to BL702 USB stack in usbd_BL702.c. + */ + +#ifndef RL_USB_H +#define RL_USB_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* USB initialization */ +void usbd_init(void); +void usbd_connect(bool con); +bool usbd_configured(void); + +/* RL-USB Core API (implemented as stubs/usbd_BL702.c) */ +int32_t USBD_Initialize(uint32_t index); +int32_t USBD_Connect(uint32_t index); +bool USBD_Configured(uint32_t index); + +/* Endpoint operations */ +int32_t USBD_EndpointRead(uint32_t index, uint8_t ep, uint8_t *buf, uint32_t size); +int32_t USBD_EndpointWrite(uint32_t index, uint8_t ep, const uint8_t *buf, uint32_t size); +uint32_t USBD_EndpointReadGetResult(uint32_t index, uint8_t ep); +int32_t USBD_EndpointAbort(uint32_t index, uint8_t ep); + +/* USB event types (from RL-USB) */ +#define ARM_USBD_EVENT_OUT (1U << 0) +#define ARM_USBD_EVENT_IN (1U << 1) +#define ARM_USBD_EVENT_SETUP (1U << 2) + +/* Endpoint address helpers (avoid redefinition with usb_def.h) */ +#ifndef USB_ENDPOINT_OUT +#define USB_ENDPOINT_OUT(n) (n) +#endif +#ifndef USB_ENDPOINT_IN +#define USB_ENDPOINT_IN(n) (0x80U | (n)) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* RL_USB_H */ diff --git a/firmware/app/daplink_bl702/hic_hal/sdk.c b/firmware/app/daplink_bl702/hic_hal/sdk.c new file mode 100644 index 0000000..fa720d4 --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/sdk.c @@ -0,0 +1,19 @@ +/** + * @file sdk.c + * @brief BL702 SDK Initialization + * + * DAPLink Interface Firmware - BL702 Port + */ + +#include "sdk.h" +#include "bl702_glb.h" +#include "bflb_platform.h" + +void sdk_init(void) +{ + /* Select internal flash (required for BL702 boot) */ + GLB_Select_Internal_Flash(); + + /* Initialize platform (clocks, UART for debug output) */ + bflb_platform_init(0); +} diff --git a/firmware/app/daplink_bl702/hic_hal/sdk.h b/firmware/app/daplink_bl702/hic_hal/sdk.h new file mode 100644 index 0000000..6bc27bc --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/sdk.h @@ -0,0 +1,23 @@ +/** + * @file sdk.h + * @brief SDK Init Interface for DAPLink HIC HAL + * + * DAPLink Interface Firmware + * Copyright (c) 2017-2017, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SDK_H +#define SDK_H + +#ifdef __cplusplus +extern "C" { +#endif + +void sdk_init(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/firmware/app/daplink_bl702/hic_hal/swo_uart_bl702.c b/firmware/app/daplink_bl702/hic_hal/swo_uart_bl702.c new file mode 100644 index 0000000..6a82232 --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/swo_uart_bl702.c @@ -0,0 +1,176 @@ +/** + * @file swo_uart_bl702.c + * @brief SWO UART capture for BL702 using interrupt-driven RX + * + * Configures UART0 RX on GPIO_PIN_1 (reuses TDO pin) with RX FIFO + * interrupt to capture SWO trace data into SWO.c's TraceBuf. + * + * Interrupt flow: + * UART RX byte arrives → RX FIFO threshold reached → ISR fires → + * read all FIFO bytes → write to TraceBuf → update TraceIndexI + */ + +#include +#include "DAP_config.h" +#include "DAP.h" +#include "Driver_USART.h" +#include "bl702_uart.h" +#include "bl702_glb.h" +#include "hal_gpio.h" +#include "bl702_common.h" /* CPU_Interrupt_Enable/Disable */ + +#if (SWO_UART != 0) + +/* Dummy USART driver instance (required by SWO.c extern declaration) */ +ARM_DRIVER_USART Driver_USART0; + +/* Extern from SWO.c — ISR writes directly to trace buffer */ +extern uint8_t TraceBuf[SWO_BUFFER_SIZE]; +extern volatile uint32_t TraceIndexI; +extern volatile uint8_t TraceUpdate; + +/* ---- UART state ---- */ +static uint8_t swo_uart_ready = 0U; + +/* ======================================================================== + * UART RX Interrupt Handler + * ======================================================================== + * + * Called by BL702 UART interrupt when RX FIFO threshold is reached. + * Reads all available bytes from the FIFO and appends them to TraceBuf. + */ +static void swo_uart_rx_isr(uint32_t uart_id) { + uint32_t idx_i, fifo_cnt, avail; + uint8_t byte; + (void)uart_id; + + fifo_cnt = (uint32_t)UART_GetRxFifoCount(UART0_ID); + if (fifo_cnt == 0U) return; + + idx_i = TraceIndexI; + + /* Don't overflow the trace buffer (wrap-safe) */ + avail = SWO_BUFFER_SIZE - (idx_i & (SWO_BUFFER_SIZE - 1U)); + if (fifo_cnt > avail) { + fifo_cnt = avail; + } + + while (fifo_cnt--) { + UART_ReceiveData(UART0_ID, &byte, 1U); + TraceBuf[idx_i & (SWO_BUFFER_SIZE - 1U)] = byte; + idx_i++; + } + + TraceIndexI = idx_i; + TraceUpdate = 1U; + + UART_IntClear(UART0_ID, UART_INT_RX_FIFO_REQ); +} + +/* ======================================================================== + * SWO UART functions called by SWO.c + * ======================================================================== */ + +uint32_t SWO_Mode_UART (uint32_t enable) { + if (enable) { + UART_CFG_Type uartCfg; + UART_FifoCfg_Type fifoCfg; + + /* Enable UART clock (96MHz) */ + GLB_Set_UART_CLK(ENABLE, HBN_UART_CLK_96M, 1); + + /* Route GPIO1 (TDO) to UART0_RXD */ + GLB_UART_Fun_Sel(GLB_UART_SIG_1, GLB_UART_SIG_FUN_UART0_RXD); + GLB_UART_Sig_Swap_Set(0); + + /* Configure GPIO1 as input with pull-up */ + gpio_set_mode(TDO_PIN, GPIO_INPUT_PP_MODE); + + /* Configure UART: 8N1, default 2MHz */ + uartCfg.uartClk = 96000000U; + uartCfg.baudRate = 2000000U; /* Default 2MHz */ + uartCfg.dataBits = UART_DATABITS_8; + uartCfg.stopBits = UART_STOPBITS_1; + uartCfg.parity = UART_PARITY_NONE; + uartCfg.ctsFlowControl = DISABLE; + uartCfg.rxDeglitch = ENABLE; + uartCfg.byteBitInverse = UART_LSB_FIRST; + UART_Init(UART0_ID, &uartCfg); + + /* RX FIFO: threshold=1 (interrupt per byte), no DMA */ + fifoCfg.txFifoDmaThreshold = 0; + fifoCfg.rxFifoDmaThreshold = 0; + fifoCfg.txFifoDmaEnable = DISABLE; + fifoCfg.rxFifoDmaEnable = DISABLE; + UART_FifoConfig(UART0_ID, &fifoCfg); + + /* Install RX FIFO interrupt handler */ + UART_Int_Callback_Install(UART0_ID, UART_INT_RX_FIFO_REQ, + (intCallback_Type *)swo_uart_rx_isr); + UART_IntMask(UART0_ID, UART_INT_RX_FIFO_REQ, UNMASK); + CPU_Interrupt_Enable(UART0_IRQn); + + /* Enable UART RX */ + UART_Enable(UART0_ID, UART_RX); + + swo_uart_ready = 1U; + } else { + if (swo_uart_ready) { + CPU_Interrupt_Disable(UART0_IRQn); + UART_Disable(UART0_ID, UART_RX); + UART_DeInit(UART0_ID); + swo_uart_ready = 0U; + } + } + return 1U; +} + +uint32_t SWO_Baudrate_UART (uint32_t baudrate) { + if (baudrate > SWO_UART_MAX_BAUDRATE) { + baudrate = SWO_UART_MAX_BAUDRATE; + } + if (baudrate == 0U) return 0U; + + if (swo_uart_ready) { + CPU_Interrupt_Disable(UART0_IRQn); + UART_Disable(UART0_ID, UART_RX); + + UART_CFG_Type uartCfg; + uartCfg.uartClk = 96000000U; + uartCfg.baudRate = baudrate; + uartCfg.dataBits = UART_DATABITS_8; + uartCfg.stopBits = UART_STOPBITS_1; + uartCfg.parity = UART_PARITY_NONE; + uartCfg.ctsFlowControl = DISABLE; + uartCfg.rxDeglitch = ENABLE; + uartCfg.byteBitInverse = UART_LSB_FIRST; + UART_Init(UART0_ID, &uartCfg); + + UART_Enable(UART0_ID, UART_RX); + CPU_Interrupt_Enable(UART0_IRQn); + } + return baudrate; +} + +uint32_t SWO_Control_UART (uint32_t active) { + if (!swo_uart_ready) return 0U; + if (active) { + UART_RxFifoClear(UART0_ID); + } + return 1U; +} + +void SWO_Capture_UART (uint8_t *buf, uint32_t num) { + (void)buf; + (void)num; + /* Data is captured automatically by ISR */ +} + +uint32_t SWO_GetCount_UART (void) { + if (!swo_uart_ready) return 0U; + /* ISR writes directly to TraceBuf; return 0 as count is tracked + * by SWO.c's internal TraceIndexI (updated by ISR) */ + return 0U; +} + +#endif /* (SWO_UART != 0) */ diff --git a/firmware/app/daplink_bl702/hic_hal/uart.c b/firmware/app/daplink_bl702/hic_hal/uart.c new file mode 100644 index 0000000..58d4af7 --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/uart.c @@ -0,0 +1,74 @@ +/** + * @file uart.c + * @brief UART Driver stub for BL702 + * + * DAPLink Interface Firmware - BL702 Port + * + * Stub implementation: UART (CDC serial) not yet implemented. + * CMSIS-DAP core does not require UART for basic debug functionality. + * Full implementation needed for Phase 5 (CDC virtual COM port). + */ + +#include +#include +#include "uart.h" + +int32_t uart_initialize(void) +{ + return 0; /* Stub: success */ +} + +int32_t uart_uninitialize(void) +{ + return 0; +} + +int32_t uart_reset(void) +{ + return 0; +} + +int32_t uart_set_configuration(UART_Configuration *config) +{ + (void)config; + return 0; +} + +int32_t uart_get_configuration(UART_Configuration *config) +{ + (void)config; + return 0; +} + +int32_t uart_write_free(void) +{ + return 0; +} + +int32_t uart_write_data(uint8_t *data, uint16_t size) +{ + (void)data; + (void)size; + return 0; +} + +int32_t uart_read_data(uint8_t *data, uint16_t size) +{ + (void)data; + (void)size; + return 0; +} + +void uart_set_control_line_state(uint16_t ctrl_bmp) +{ + (void)ctrl_bmp; +} + +void uart_software_flow_control(void) +{ +} + +void uart_enable_flow_control(bool enabled) +{ + (void)enabled; +} diff --git a/firmware/app/daplink_bl702/hic_hal/uart.h b/firmware/app/daplink_bl702/hic_hal/uart.h new file mode 100644 index 0000000..793febd --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/uart.h @@ -0,0 +1,72 @@ +/** + * @file uart.h + * @brief UART Interface for DAPLink HIC HAL + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef UART_H +#define UART_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + UART_PARITY_NONE = 0, + UART_PARITY_ODD = 1, + UART_PARITY_EVEN = 2, + UART_PARITY_MARK = 3, + UART_PARITY_SPACE = 4 +} UART_Parity; + +typedef enum { + UART_STOP_BITS_1 = 0, + UART_STOP_BITS_1_5 = 1, + UART_STOP_BITS_2 = 2 +} UART_StopBits; + +typedef enum { + UART_DATA_BITS_5 = 5, + UART_DATA_BITS_6 = 6, + UART_DATA_BITS_7 = 7, + UART_DATA_BITS_8 = 8, + UART_DATA_BITS_16 = 16 +} UART_DataBits; + +typedef enum { + UART_FLOW_CONTROL_NONE = 0, + UART_FLOW_CONTROL_RTS_CTS = 1, + UART_FLOW_CONTROL_XON_XOFF = 2 +} UART_FlowControl; + +typedef struct { + uint32_t Baudrate; + UART_DataBits DataBits; + UART_Parity Parity; + UART_StopBits StopBits; + UART_FlowControl FlowControl; +} UART_Configuration; + +extern int32_t uart_initialize(void); +extern int32_t uart_uninitialize(void); +extern int32_t uart_reset(void); +extern int32_t uart_set_configuration(UART_Configuration *config); +extern int32_t uart_get_configuration(UART_Configuration *config); +extern int32_t uart_write_free(void); +extern int32_t uart_write_data(uint8_t *data, uint16_t size); +extern int32_t uart_read_data(uint8_t *data, uint16_t size); +extern void uart_set_control_line_state(uint16_t ctrl_bmp); +extern void uart_software_flow_control(void); +extern void uart_enable_flow_control(bool enabled); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/firmware/app/daplink_bl702/hic_hal/usbd_BL702.c b/firmware/app/daplink_bl702/hic_hal/usbd_BL702.c new file mode 100644 index 0000000..2af2596 --- /dev/null +++ b/firmware/app/daplink_bl702/hic_hal/usbd_BL702.c @@ -0,0 +1,96 @@ +/** + * @file usbd_BL702.c + * @brief USB Device Adapter: RL-USB API → BL702 USB Stack + * + * DAPLink Interface Firmware - BL702 Port + * + * Maps DAPLink's RL-USB function calls to BL702's native USB API. + * This allows DAPLink core code to compile against BL702 hardware. + */ + +#include +#include +#include "usbd_core.h" +#include "usb_dc.h" +#include "hal_usb.h" +#include "bl702_usb.h" +#include "rl_usb.h" + +/* ======================================================================== + * Internal state + * ======================================================================== */ + +static struct device *g_usb_dev = NULL; +static bool g_usb_connected = false; + +/* ======================================================================== + * RL-USB API → BL702 Implementation + * ======================================================================== */ + +void usbd_init(void) +{ + /* BL702 USB initialization is done in main.c via: + * usbd_desc_register() + usbd_class_register() + usb_dc_init() + * This stub exists for DAPLink source compatibility. + */ +} + +void usbd_connect(bool con) +{ + /* BL702 hardware automatically connects via D+ pull-up. + * No explicit connect/disconnect control. + */ + (void)con; + g_usb_connected = con; +} + +bool usbd_configured(void) +{ + return usb_device_is_configured(); +} + +int32_t USBD_Initialize(uint32_t index) +{ + (void)index; + return 0; /* ARM_DRIVER_OK */ +} + +int32_t USBD_Connect(uint32_t index) +{ + (void)index; + return 0; +} + +bool USBD_Configured(uint32_t index) +{ + (void)index; + return usb_device_is_configured(); +} + +/* Endpoint read/write mapped to BL702 API */ +int32_t USBD_EndpointRead(uint32_t index, uint8_t ep, uint8_t *buf, uint32_t size) +{ + uint32_t chunk = 0; + (void)index; + return usbd_ep_read(ep, buf, size, &chunk); +} + +int32_t USBD_EndpointWrite(uint32_t index, uint8_t ep, const uint8_t *buf, uint32_t size) +{ + (void)index; + return usbd_ep_write(ep, buf, size, NULL); +} + +uint32_t USBD_EndpointReadGetResult(uint32_t index, uint8_t ep) +{ + (void)index; + (void)ep; + return 0; +} + +int32_t USBD_EndpointAbort(uint32_t index, uint8_t ep) +{ + (void)index; + (void)ep; + return 0; +} diff --git a/firmware/app/daplink_bl702/main.c b/firmware/app/daplink_bl702/main.c new file mode 100644 index 0000000..5ee21db --- /dev/null +++ b/firmware/app/daplink_bl702/main.c @@ -0,0 +1,211 @@ +/** + * @file main.c + * @brief DAPLink Interface Firmware for BL702 + * + * Phase 2-5 entry point. Uses DAPLink HIC HAL and CMSIS-DAP core, + * with BL702 native USB stack and bare-metal main loop. + * + * Based on the proven synchronous CMSIS-DAP architecture verified with OpenOCD. + */ + +#include +#include +#include "hal_usb.h" +#include "bl702_usb.h" +#include "usbd_core.h" +#include "usb_dc.h" +#include "sdk.h" +#include "gpio.h" +#include "DAP_config.h" +#include "DAP.h" +#include "rl_usb.h" + +/* ======================================================================== + * CMSIS-DAP USB Endpoint Constants + * ======================================================================== */ +#define CMSIS_DAP_OUT_EP 0x02U /* EP2 OUT */ +#define CMSIS_DAP_IN_EP 0x81U /* EP1 IN */ +#define DAP_PACKET_SIZE 64U /* From DAP_config.h */ +/* Ring buffer needs N+1 slots for SPSC full-detection (1 slot always empty). + * DAP_PACKET_COUNT=4 means Keil may send up to 4 packets without waiting, + * so we need 5 slots (4 usable). With only 4 slots (3 usable) the 4th + * consecutive TransferBlock during flash download is silently dropped, + * the response never arrives, and Keil times out → "RDDI-DAP Error". */ +#define REQ_BUF_COUNT (DAP_PACKET_COUNT + 1U) + +/* ======================================================================== + * USB Communication Buffers (lock-free single-producer single-consumer ring) + * + * DAP_PACKET_COUNT=4 means Keil may pipeline up to 4 packets. The ring + * buffer absorbs bursts so packets are never dropped while the main loop + * processes a previous command. + * + * Design: classic SPSC ring buffer using head/tail indices only (no shared + * counter). ISR (producer) advances head; main loop (consumer) advances tail. + * Empty: head == tail. Full: (head + 1) % N == tail (one slot always empty). + * ======================================================================== */ +static uint8_t g_req_bufs[REQ_BUF_COUNT][DAP_PACKET_SIZE]; /* Request ring */ +static uint8_t g_resp_buf[DAP_PACKET_SIZE]; /* Response (single, synchronous send) */ +static uint16_t g_resp_len; +static volatile uint8_t g_req_head = 0U; /* ISR writes, main loop reads */ +static uint8_t g_req_tail = 0U; /* Main loop writes, ISR reads */ +static volatile uint8_t g_in_done = 0U; + +/* ======================================================================== + * USB Class & Endpoints + * ======================================================================== */ +extern uint8_t usbd_descriptor[]; + +static usbd_class_t dap_class; +static usbd_interface_t dap_intf; + +/* Forward declarations */ +void usbd_dap_out_cb(uint8_t ep); +void usbd_dap_in_cb(uint8_t ep); + +static usbd_endpoint_t dap_out_ep = { .ep_addr = CMSIS_DAP_OUT_EP, .ep_cb = usbd_dap_out_cb }; +static usbd_endpoint_t dap_in_ep = { .ep_addr = CMSIS_DAP_IN_EP, .ep_cb = usbd_dap_in_cb }; + +/* ======================================================================== + * USB Endpoint Callbacks + * ======================================================================== */ + +void usbd_dap_out_cb(uint8_t ep) +{ + uint32_t chunk = 0U; + uint8_t next_head = (g_req_head + 1U) % REQ_BUF_COUNT; + + /* Enqueue into ring buffer if there is room (one slot always empty) */ + if (next_head != g_req_tail) { + usbd_ep_read(ep, g_req_bufs[g_req_head], DAP_PACKET_SIZE, &chunk); + if (chunk > 0U) { + g_req_head = next_head; + } + } + /* Always re-arm the endpoint so the USB host can send the next packet. + * If the ring was full, data in the current packet is lost — but with + * REQ_BUF_COUNT=4 and the main loop depleting faster than Keil sends, + * this should never happen in practice. */ + usbd_ep_read(ep, NULL, 0, NULL); +} + +void usbd_dap_in_cb(uint8_t ep) +{ + (void)ep; + g_in_done = 1U; +} + +/* ======================================================================== + * USB Notification Handler + * ======================================================================== */ +static void dap_notify_handler(uint8_t event, void *arg) +{ + (void)arg; + switch (event) { + case USB_EVENT_RESET: break; + case USB_EVENT_CONFIGURED: break; + default: break; + } +} + +/* ======================================================================== + * Synchronous IN FIFO Write (byte-by-byte, matches memcopy_to_fifo) + * ======================================================================== */ +static int dap_fifo_write_sync(uint8_t ep, const uint8_t *data, uint32_t len) +{ + uint8_t ep_idx = USB_EP_GET_IDX(ep); + uint32_t timeout; + uint32_t addr; + uint32_t i; + + if (USB_EP_GET_DIR(ep) != USB_EP_DIR_IN) return -1; + + timeout = 0x00FFFFFFU; + while (!USB_Is_EPx_RDY_Free(ep_idx)) { + if (!--timeout) return -2; + } + + addr = USB_BASE + 0x118U + (uint32_t)(ep_idx - 1U) * 0x10U; + for (i = 0U; i < len; i++) { + *(volatile uint8_t *)addr = data[i]; + } + + g_in_done = 0U; + USB_Set_EPx_Rdy(ep_idx); + + timeout = 0x00FFFFFFU; + while (!g_in_done) { + if (!--timeout) return -3; + } + + return 0; +} + +/* ======================================================================== + * USB Initialization + * ======================================================================== */ +static void usb_init(void) +{ + /* Standard USB device descriptor */ + usbd_desc_register(usbd_descriptor); + + /* Microsoft OS 1.0 descriptors for automatic WinUSB driver binding on Windows. + * MS OS 1.0 uses a string descriptor at index 0xEE (no BOS/bcdUSB 2.1 needed) + * and is fully supported by the CherryUSB stack on BL702. */ + extern struct usb_msosv1_descriptor dap_msosv1_desc; + usbd_msosv1_desc_register(&dap_msosv1_desc); + + memset(&dap_class, 0, sizeof(dap_class)); + memset(&dap_intf, 0, sizeof(dap_intf)); + dap_class.name = "daplink"; + usbd_class_register(&dap_class); + + dap_intf.class_handler = NULL; + dap_intf.custom_handler = NULL; + dap_intf.vendor_handler = NULL; + dap_intf.notify_handler = dap_notify_handler; + usbd_class_add_interface(&dap_class, &dap_intf); + usbd_interface_add_endpoint(&dap_intf, &dap_out_ep); + usbd_interface_add_endpoint(&dap_intf, &dap_in_ep); + + struct device *usb_dev = usb_dc_init(); + if (usb_dev) { + device_control(usb_dev, DEVICE_CTRL_SET_INT, + (void *)(uintptr_t)(USB_SOF_IT | USB_EP2_DATA_OUT_IT | USB_EP1_DATA_IN_IT)); + } +} + +/* ======================================================================== + * Main Entry Point + * ======================================================================== */ +int main(void) +{ + /* Platform init */ + sdk_init(); + gpio_init(); + DAP_Setup(); + + /* USB init */ + usb_init(); + while (!usb_device_is_configured()) {} + + /* Main loop: dequeue requests from ring buffer, process, respond */ + while (1) { + /* SPSC ring: non-empty when head != tail */ + if (g_req_head != g_req_tail) { + uint8_t *req = g_req_bufs[g_req_tail]; + + /* Process command: req = input, g_resp_buf = output (separate buffers) */ + g_resp_len = (uint16_t)DAP_ExecuteCommand(req, g_resp_buf); + dap_fifo_write_sync(CMSIS_DAP_IN_EP, g_resp_buf, g_resp_len); + + /* Advance tail — slot is now free for the ISR to reuse. + * No lock needed: ISR only reads g_req_tail (volatile g_req_head + * is written by ISR and read here — both single-byte aligned + * stores/loads are atomic on RISC-V). */ + g_req_tail = (g_req_tail + 1U) % REQ_BUF_COUNT; + } + } + + return 0; +} diff --git a/firmware/app/daplink_bl702/rtos_adapt/cmsis_os2.h b/firmware/app/daplink_bl702/rtos_adapt/cmsis_os2.h new file mode 100644 index 0000000..5544647 --- /dev/null +++ b/firmware/app/daplink_bl702/rtos_adapt/cmsis_os2.h @@ -0,0 +1,92 @@ +/** + * @file cmsis_os2.h + * @brief CMSIS-RTOS2 API Header (minimal subset for DAPLink) + * + * DAPLink Interface Firmware - BL702 Port + * + * Provides the type and function declarations needed by DAPLink core. + * Actual implementation is in cmsis_os2_port.c (bare-metal polling). + */ + +#ifndef CMSIS_OS2_H_ +#define CMSIS_OS2_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Status codes */ +typedef int32_t osStatus_t; +#define osOK 0 +#define osError -1 +#define osErrorParameter -2 +#define osErrorResource -3 +#define osErrorTimeout -4 + +/* Thread */ +typedef void *osThreadId_t; +typedef void (*osThreadFunc_t)(void *argument); + +typedef struct { + const char *name; + uint32_t attr_bits; + void *cb_mem; + uint32_t cb_size; + void *stack_mem; + uint32_t stack_size; + uint32_t priority; +} osThreadAttr_t; + +/* Timer */ +typedef void *osTimerId_t; +typedef void (*osTimerFunc_t)(void *argument); + +typedef enum { + osTimerOnce = 0, + osTimerPeriodic = 1 +} osTimerType_t; + +typedef struct { + const char *name; + uint32_t attr_bits; + void *cb_mem; + uint32_t cb_size; +} osTimerAttr_t; + +/* Flags */ +#define osFlagsWaitAny 0x00000000U +#define osWaitForever 0xFFFFFFFFU + +/* Kernel */ +osStatus_t osKernelInitialize(void); +osStatus_t osKernelStart(void); +uint32_t osKernelGetTickCount(void); + +/* Thread */ +osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr); +osThreadId_t osThreadGetId(void); + +/* Flags */ +uint32_t osThreadFlagsSet(osThreadId_t thread_id, uint32_t flags); +uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout); + +/* Timer */ +osTimerId_t osTimerNew(osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr); +osStatus_t osTimerStart(osTimerId_t timer_id, uint32_t ticks); + +/* Delay */ +osStatus_t osDelay(uint32_t ticks); + +/* Global flags variable (set by ISRs, polled by main loop) */ +extern volatile uint32_t g_main_flags; + +/* SysTick handler (called from mtime interrupt) */ +void SysTick_Handler(void); + +#ifdef __cplusplus +} +#endif + +#endif /* CMSIS_OS2_H_ */ diff --git a/firmware/app/daplink_bl702/rtos_adapt/cmsis_os2_port.c b/firmware/app/daplink_bl702/rtos_adapt/cmsis_os2_port.c new file mode 100644 index 0000000..93b290d --- /dev/null +++ b/firmware/app/daplink_bl702/rtos_adapt/cmsis_os2_port.c @@ -0,0 +1,168 @@ +/** + * @file cmsis_os2_port.c + * @brief CMSIS-RTOS2 Bare-metal Adapter for BL702 + * + * DAPLink Interface Firmware - BL702 Port + * + * Implements a minimal subset of CMSIS-RTOS2 API using polling and + * a hardware timer (BL702 mtime) for periodic callbacks. + * + * Key mappings: + * osKernelInitialize / Start → init timer, call main function + * osThreadNew → save function pointer + * osThreadFlagsWait → poll global flag variable + * osThreadFlagsSet → set global flag variable + * osTimerNew / Start → register mtime callback + * osDelay → mtimer busy-wait + */ + +#include +#include +#include +#include "cmsis_os2.h" +#include "hal_mtimer.h" + +/* ======================================================================== + * Global state + * ======================================================================== */ + +static osThreadFunc_t g_main_thread_func = NULL; +static void *g_main_thread_arg = NULL; + +volatile uint32_t g_main_flags = 0; + +/* Timer callback storage */ +#define MAX_TIMERS 4 +static osTimerFunc_t g_timer_funcs[MAX_TIMERS] = { NULL }; +static uint32_t g_timer_periods[MAX_TIMERS] = { 0 }; +static uint32_t g_timer_ticks[MAX_TIMERS] = { 0 }; +static uint8_t g_timer_count = 0; + +/* ======================================================================== + * Timer ISR (called from mtime interrupt) + * ======================================================================== */ + +void SysTick_Handler(void) +{ + uint8_t i; + for (i = 0; i < g_timer_count; i++) { + if (g_timer_funcs[i] != NULL) { + g_timer_ticks[i]++; + if (g_timer_ticks[i] >= g_timer_periods[i]) { + g_timer_ticks[i] = 0; + g_timer_funcs[i](NULL); + } + } + } +} + +/* ======================================================================== + * Kernel API + * ======================================================================== */ + +osStatus_t osKernelInitialize(void) +{ + return osOK; +} + +osStatus_t osKernelStart(void) +{ + if (g_main_thread_func) { + g_main_thread_func(g_main_thread_arg); + } + /* Should never return */ + while (1) {} + return osOK; +} + +uint32_t osKernelGetTickCount(void) +{ + return (uint32_t)mtimer_get_time_ms(); +} + +/* ======================================================================== + * Thread API + * ======================================================================== */ + +osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr) +{ + (void)attr; + g_main_thread_func = func; + g_main_thread_arg = argument; + return (osThreadId_t)1; +} + +osThreadId_t osThreadGetId(void) +{ + return (osThreadId_t)1; +} + +/* ======================================================================== + * Flags API + * ======================================================================== */ + +uint32_t osThreadFlagsSet(osThreadId_t thread_id, uint32_t flags) +{ + (void)thread_id; + g_main_flags |= flags; + return flags; +} + +uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout) +{ + (void)options; + (void)timeout; + + /* Simple polling - wait until any requested flag is set */ + while (!(g_main_flags & flags)) { + /* Yield / wait */ + } + + uint32_t ret = g_main_flags & flags; + g_main_flags &= ~flags; + return ret; +} + +/* ======================================================================== + * Timer API + * ======================================================================== */ + +osTimerId_t osTimerNew(osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr) +{ + (void)type; + (void)argument; + (void)attr; + + if (g_timer_count >= MAX_TIMERS) { + return NULL; + } + + uint8_t idx = g_timer_count++; + g_timer_funcs[idx] = func; + g_timer_periods[idx] = 0; + g_timer_ticks[idx] = 0; + + return (osTimerId_t)(uintptr_t)(idx + 1); +} + +osStatus_t osTimerStart(osTimerId_t timer_id, uint32_t ticks) +{ + uint8_t idx = (uint8_t)((uintptr_t)timer_id - 1); + if (idx >= g_timer_count) { + return osErrorParameter; + } + g_timer_periods[idx] = ticks; + g_timer_ticks[idx] = 0; + return osOK; +} + +/* ======================================================================== + * Delay API + * ======================================================================== */ + +osStatus_t osDelay(uint32_t ticks) +{ + /* ticks in ms for our implementation */ + mtimer_delay_ms(ticks); + return osOK; +} diff --git a/firmware/app/daplink_bl702/usb/usb_descriptor.c b/firmware/app/daplink_bl702/usb/usb_descriptor.c new file mode 100644 index 0000000..97e9bcf --- /dev/null +++ b/firmware/app/daplink_bl702/usb/usb_descriptor.c @@ -0,0 +1,189 @@ +/** + * @file usb_descriptor.c + * @brief CMSIS-DAP v2 USB Descriptor for BL702 (DAPLink-style) + * + * USB descriptor table for CMSIS-DAP v2 WinUSB BULK interface. + * Phase 2: CMSIS-DAP only. Phase 5 will add MSC + CDC composite. + */ + +#include "usbd_core.h" +#include "usb_def.h" + +/* Keil CMSIS-DAP official VID/PID (recognized by Keil MDK out of the box) */ +#define USBD_VID 0xC251U +#define USBD_PID 0xF00AU + +/* Endpoint addresses (BL702: separate physical EP per direction) */ +#define DAP_OUT_EP 0x02U /* EP2 OUT - command */ +#define DAP_IN_EP 0x81U /* EP1 IN - response */ + +uint8_t usbd_descriptor[] = +{ + /* Device Descriptor (18 bytes) */ + 0x12, USB_DESCRIPTOR_TYPE_DEVICE, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x51, 0xC2, /* VID = 0xC251 */ + 0x0A, 0xF0, /* PID = 0xF00A */ + 0x00, 0x01, 0x01, 0x02, 0x03, 0x01, + + /* Configuration Descriptor (32 bytes total) */ + 0x09, USB_DESCRIPTOR_TYPE_CONFIGURATION, + 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0xFA, + + /* Interface Descriptor (CMSIS-DAP v2, Vendor-specific BULK) */ + 0x09, USB_DESCRIPTOR_TYPE_INTERFACE, + 0x00, 0x00, 0x02, /* bInterface=0, bAlternate=0, bNumEndpoints=2 */ + 0xFF, 0x00, 0x00, 0x00, /* Vendor Specific */ + + /* Endpoint: BULK OUT (EP2, must come first for OpenOCD) */ + 0x07, USB_DESCRIPTOR_TYPE_ENDPOINT, + DAP_OUT_EP, 0x02, /* EP2 OUT, BULK */ + 0x40, 0x00, 0x01, /* MaxPacket=64, Interval=1 */ + + /* Endpoint: BULK IN (EP1) */ + 0x07, USB_DESCRIPTOR_TYPE_ENDPOINT, + DAP_IN_EP, 0x02, /* EP1 IN, BULK */ + 0x40, 0x00, 0x01, /* MaxPacket=64, Interval=1 */ + + /* String 0: Language ID */ + 0x04, USB_DESCRIPTOR_TYPE_STRING, + 0x09, 0x04, + + /* String 1: Manufacturer "ARM Ltd" (16 bytes) */ + 0x10, USB_DESCRIPTOR_TYPE_STRING, + 'A',0x00,'R',0x00,'M',0x00,' ',0x00,'L',0x00,'t',0x00,'d',0x00, + + /* String 2: Product "DAPLink CMSIS-DAP" (38 bytes) */ + 0x24, USB_DESCRIPTOR_TYPE_STRING, + 'D',0x00,'A',0x00,'P',0x00,'L',0x00,'i',0x00,'n',0x00,'k',0x00, + ' ',0x00, + 'C',0x00,'M',0x00,'S',0x00,'I',0x00,'S',0x00,'-',0x00,'D',0x00,'A',0x00,'P',0x00, + + /* String 3: Serial Number "202400000001" (26 bytes) */ + 0x1A, USB_DESCRIPTOR_TYPE_STRING, + '2',0x00,'0',0x00,'2',0x00,'4',0x00,'0',0x00,'0',0x00,'0',0x00,'0',0x00,'0',0x00,'0',0x00,'0',0x00,'1',0x00, + + /* Device Qualifier */ + 0x0A, USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, + 0x00,0x02, 0x00,0x00,0x00,0x40,0x01,0x00, + + 0x00 /* Terminator */ +}; + +/* ======================================================================== +* Microsoft OS 1.0 Descriptors for automatic WinUSB driver binding +* ======================================================================== +* +* MS OS 1.0 uses a special string descriptor at index 0xEE plus a +* vendor request to return the Compatible ID. This approach: +* - Works on all Windows versions (XP through 11) +* - Does NOT require bcdUSB 2.1 / BOS descriptor +* - CherryUSB fully supports this path (unlike the untested BOS path) +* +* Without these, Windows sees a Vendor Specific interface (0xFF) and +* has no driver to load — Keil MDK cannot find the debug probe. +*/ + +/* Vendor request code embedded in the 0xEE string descriptor */ +#define MSOSV1_VENDOR_CODE 0x07U + +/* MS OS 1.0 String Descriptor at fixed index 0xEE (18 bytes). +* Windows reads this on first attach to detect MS OS descriptor support. +* Format: Unicode string "MSFT100" + vendor_code as last character. */ +static uint8_t dap_msosv1_string[] = { + 0x12, /* bLength = 18 */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType = 0x03 */ + 'M',0x00, 'S',0x00, 'F',0x00, 'T',0x00, + '1',0x00, '0',0x00, '0',0x00, + MSOSV1_VENDOR_CODE, 0x00, /* vendor code = 0x07 as Unicode char */ +}; + +/* MS OS 1.0 Compatible ID Descriptor (32 bytes). +* Returned in response to vendor request (bRequest = vendor_code, wIndex = 0x04). +* Tells Windows to load WinUSB.sys for interface 0. */ +static uint8_t dap_msosv1_compat_id[] = { + /* Header */ + 0x20, 0x00, 0x00, 0x00, /* dwLength = 32 */ + 0x00, 0x01, /* bcdVersion = 0x0100 */ + 0x04, 0x00, /* wIndex = 0x0004 (Compatible ID) */ + 0x01, /* bCount = 1 function section */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* reserved[7] */ + /* Function section 1 */ + 'W','I','N','U','S','B',0x00,0x00, /* compatibleID[8] = "WINUSB" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* subCompatibleID[8] = "" */ +}; + +/* MS OS 1.0 Extended Properties Descriptor (140 bytes). +* Sets DeviceInterfaceGUID = {CDB3B5AD-293B-4663-AA36-1AAE46463776} +* per CMSIS-DAP v2 spec. Debuggers (Keil, OpenOCD) use this GUID +* to identify CMSIS-DAP v2 devices among all WinUSB devices. +* +* Returned in response to vendor request (wIndex = 0x05). +* Property data uses Unicode (UTF-16LE) per MDK middleware convention. +* Property name "DeviceInterfaceGUID" (19 chars, singular) matches MDK example. */ +static uint8_t dap_msosv1_property[] = { + /* Extended Properties Header */ + 0x8C, 0x00, 0x00, 0x00, /* dwLength = 140 */ + 0x00, 0x01, /* bcdVersion = 0x0100 */ + 0x05, 0x00, /* wIndex = 0x0005 */ + 0x01, 0x00, /* wCount = 1 */ + + /* Custom Property Section 0 */ + 0x82, 0x00, 0x00, 0x00, /* dwSize = 130 */ + 0x01, 0x00, 0x00, 0x00, /* dwPropertyDataType = REG_SZ (1) */ + 0x26, 0x00, /* wPropertyNameLength = 38 (19 Unicode chars, no null) */ + /* bPropertyName: "DeviceInterfaceGUID" (Unicode UTF-16LE, 19 chars) */ + 'D',0x00,'e',0x00,'v',0x00,'i',0x00,'c',0x00,'e',0x00, + 'I',0x00,'n',0x00,'t',0x00,'e',0x00,'r',0x00,'f',0x00, + 'a',0x00,'c',0x00,'e',0x00, + 'G',0x00,'U',0x00,'I',0x00,'D',0x00, + /* dwPropertyDataLength = 78 (39 Unicode chars incl. null, × 2 bytes) */ + 0x4E, 0x00, 0x00, 0x00, + /* bPropertyData: "{CDB3B5AD-293B-4663-AA36-1AAE46463776}" + null (Unicode UTF-16LE) */ + '{',0x00,'C',0x00,'D',0x00,'B',0x00,'3',0x00,'B',0x00,'5',0x00,'A',0x00,'D',0x00, + '-',0x00, + '2',0x00,'9',0x00,'3',0x00,'B',0x00, + '-',0x00, + '4',0x00,'6',0x00,'6',0x00,'3',0x00, + '-',0x00, + 'A',0x00,'A',0x00,'3',0x00,'6',0x00, + '-',0x00, + '1',0x00,'A',0x00,'A',0x00,'E',0x00,'4',0x00,'6',0x00,'4',0x00,'6',0x00,'3',0x00,'7',0x00,'7',0x00,'6',0x00, + '}',0x00, + 0x00,0x00, /* null terminator (U+0000) */ +}; + +/* Wrapper struct for CherryUSB registration */ +struct usb_msosv1_descriptor dap_msosv1_desc = { + .string = dap_msosv1_string, + .string_len = sizeof(dap_msosv1_string), + .vendor_code = MSOSV1_VENDOR_CODE, + .compat_id = dap_msosv1_compat_id, + .compat_id_len = sizeof(dap_msosv1_compat_id), + .comp_id_property = dap_msosv1_property, + .comp_id_property_len = sizeof(dap_msosv1_property), +}; + +/* ======================================================================== +* Minimal BOS Descriptor (5 bytes, USB 2.1 compliance) +* ======================================================================== +* +* bcdUSB 2.1 (0x0210) REQUIRES BOS support per USB spec. +* Without BOS, Windows 11 rejects the device as non-compliant. +* This minimal BOS (zero capabilities) satisfies the requirement +* without triggering any MS OS 2.0 / vendor request behavior. +* +* Phase 2: no MS OS 2.0 platform capability (to be added if basic BOS works). +*/ +/* NOTE: non-static to ensure DMA-accessible memory placement on BL702 */ +uint8_t dap_bos_descriptor[] = { + 0x05, /* bLength = 5 */ + USB_DESCRIPTOR_TYPE_BINARY_OBJECT_STORE, /* bDescriptorType = 0x0F */ + 0x05, 0x00, /* wTotalLength = 5 */ + 0x00, /* bNumDeviceCaps = 0 */ +}; + +struct usb_bos_descriptor dap_bos_desc = { + .string = dap_bos_descriptor, + .string_len = sizeof(dap_bos_descriptor), +};