This is an automated email from the ASF dual-hosted git repository. kasjer pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
commit a79e882a471377b27960b09ea036345be5251b9d Author: Jerzy Kasenberg <[email protected]> AuthorDate: Sun Oct 18 20:59:12 2026 +0200 hw/scripts: Add common PIC32 download script This adds hw/scripts/pic32_download.sh that PIC32 BSPs can use as bsp.downloadscript instead of BSP specific scripts. Device name is taken from JLINK_TARGET set in BSP syscfg, image location and size from flash area provided by newt (FLASH_OFFSET, FLASH_AREA_SIZE). MYNEWT_DOWNLOADER selects programmer: - jlink: J-Link with ICSP (default); only flash pages covered by image are erased, after programming MCLR is pulsed to start code since reset and go from debugger does not run code reliably. J-Link errors fail the download. - mplab_ipe (new): Microchip PICkit, Snap or ICD with MPLAB IPE command line (ipecmd). Programmer is selected with MYNEWT_DOWNLOADER_MPLAB_TOOL (or MPLAB_TOOL environment variable), device name for ipecmd with MYNEWT_DOWNLOADER_MPLAB_DEVICE (defaults to JLINK_TARGET without PIC prefix). ipecmd can't erase part of flash: it either erases whole device or requires programmed memory to be blank. Bootloader and images built with MCU_NO_BOOTLOADER_BUILD are programmed after full erase. Application image is programmed to blank slot without erase; if slot is not blank, whole device is read, slot content is replaced with new image and everything is programmed back so bootloader, configuration words and other flash areas (file systems, logs) are preserved. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Jerzy Kasenberg <[email protected]> --- hw/scripts/mplab_ipe.sh | 235 +++++++++++++++++++++++++++++++++++++++++++ hw/scripts/pic32_download.sh | 114 +++++++++++++++++++++ hw/scripts/syscfg.yml | 13 +++ 3 files changed, 362 insertions(+) diff --git a/hw/scripts/mplab_ipe.sh b/hw/scripts/mplab_ipe.sh new file mode 100644 index 000000000..a39c6c8c2 --- /dev/null +++ b/hw/scripts/mplab_ipe.sh @@ -0,0 +1,235 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +. $CORE_PATH/hw/scripts/common.sh + +# +# Programming with Microchip MPLAB IPE command line tool (ipecmd) using +# PICkit 3/4/5, Snap or ICD programmers. +# +# Variables used: +# - MPLAB_DEVICE device name as accepted by ipecmd -P option +# (e.g. 32MZ2048EFM144), must be set by caller +# - BIN_BASENAME, BOOT_LOADER, MFG_IMAGE as set by newt +# - MYNEWT_VAL_MCU_NO_BOOTLOADER_BUILD set when application is built +# to run without bootloader +# - MYNEWT_VAL_MYNEWT_DOWNLOADER_MPLAB_TOOL programmer (PK3, PK4, SNAP, ...) +# can be overridden with MPLAB_TOOL environment variable +# - MYNEWT_VAL_MYNEWT_DEBUGGER_SN programmer serial number, needed when +# more than one programmer is connected; can be overridden with +# MPLAB_TOOL_SN environment variable +# - IMAGE_FLASH_ADDR physical flash address of application image +# (required for images with header) +# - IPECMD path to ipecmd, if not set it is searched in PATH and in +# default MPLAB X installation directories +# - EXTRA_JTAG_CMD additional ipecmd options (e.g. -W to power target +# from programmer) +# + +ipe_find_ipecmd() { + if [ -n "$IPECMD" ]; then + return + fi + + IPECMD=$(command -v ipecmd.exe || command -v ipecmd.sh || command -v ipecmd) + if [ -n "$IPECMD" ]; then + return + fi + + # Newest MPLAB X version from default installation places + for d in "${PROGRAMFILES:+$(cygpath -u "$PROGRAMFILES" 2>/dev/null)/Microchip/MPLABX}" \ + "/c/Program Files/Microchip/MPLABX" "/opt/microchip/mplabx" \ + "/Applications/microchip/mplabx"; do + for f in $(ls -d "$d"/v*/mplab_platform/mplab_ipe/ipecmd.{exe,sh} 2>/dev/null | sort -V -r); do + IPECMD=$f + return + done + done + + echo "ipecmd not found, set IPECMD or add MPLAB IPE directory to PATH" + exit 1 +} + +# +# Converts image to hex file with physical addresses as expected by ipecmd. +# Sets HEX_FILE, IPE_MEMORY (memory regions to program) and IPE_ERASE. +# +# Note: when programming, ipecmd (at least with PICkit 3) either erases +# whole device first or (with -OH) requires programmed memory to be blank, +# there is no erase of selected region only. +# Full images (bootloader, manufacturing image or application built with +# MCU_NO_BOOTLOADER_BUILD) are programmed after full device erase. +# Application image is programmed without erase so bootloader is not +# lost, this works only when application area is blank (right after +# bootloader was programmed) or already holds the same image. +# +ipe_prepare_hex() { + if [ "$BOOT_LOADER" -o "$MFG_IMAGE" -o "$MYNEWT_VAL_MCU_NO_BOOTLOADER_BUILD" == "1" ]; then + # ELF contains boot flash and configuration words, xc32-bin2hex + # converts virtual addresses to physical ones. + xc32-bin2hex ${BIN_BASENAME}.elf || exit 1 + HEX_FILE=${BIN_BASENAME}.hex + IPE_MEMORY= + IPE_ERASE= + else + if [ -z "$IMAGE_FLASH_ADDR" ]; then + echo "IMAGE_FLASH_ADDR not set" + exit 1 + fi + HEX_FILE=${BIN_BASENAME}.img.hex + xc32-objcopy -I binary -O ihex --change-addresses ${IMAGE_FLASH_ADDR} \ + ${BIN_BASENAME}.img ${HEX_FILE} || exit 1 + # Program memory only, without erase, leave boot flash (bootloader) + # intact. Range limits programming and verification to application + # area, other flash areas may hold data. + IPE_MEMORY=P + if [ -n "$IMAGE_FLASH_SIZE" ]; then + IPE_MEMORY=$(printf "P0x%X-0x%X" $((IMAGE_FLASH_ADDR)) \ + $((IMAGE_FLASH_ADDR + IMAGE_FLASH_SIZE - 1))) + fi + IPE_ERASE=-OH + fi +} + +# +# Runs ipecmd from BUILD_DIR (ipecmd writes log files to current directory). +# Output is stored in IPE_OUT. Returns 0 when operation succeeded. +# +ipe_run() { + local args="-P${MPLAB_DEVICE} -TP${TOOL} $*" + if [ -n "$TOOL_SN" ]; then + args="$args -TS${TOOL_SN}" + fi + IPE_OUT=$(cd "${BUILD_DIR}" && "$IPECMD" $args $EXTRA_JTAG_CMD 2>&1) + local rc=$? + echo "$IPE_OUT" + # ipecmd does not always report failures with exit code + [ $rc -eq 0 ] && echo "$IPE_OUT" | grep -q -i -E "(Program|Operation) Succeeded" +} + +# Native path for ipecmd (MSYS does not convert path glued to -F) +ipe_native_path() { + if command -v cygpath > /dev/null; then + cygpath -m "$1" + else + echo "$1" + fi +} + +# +# Replaces area <start> <size> (hex) in device hex file <dev_hex> with +# content of <app_hex> and writes result to <out_hex>. Data records inside +# the area are dropped (area is left erased except for application data). +# Records produced by ipecmd read are 16 bytes and aligned so filtering +# by record start address is exact. +# +ipe_merge_hex() { + awk -v start="$3" -v size="$4" -v app="$2" ' + function hex2dec(h, i, n, c) { + n = 0 + h = toupper(h) + sub(/^0X/, "", h) + for (i = 1; i <= length(h); i++) { + c = index("0123456789ABCDEF", substr(h, i, 1)) - 1 + n = n * 16 + c + } + return n + } + BEGIN { s = hex2dec(start); e = s + hex2dec(size); base = 0 } + { + sub(/\r$/, "") + type = substr($0, 8, 2) + if (type == "04") { + base = hex2dec(substr($0, 10, 4)) * 65536 + } else if (type == "00") { + addr = base + hex2dec(substr($0, 4, 4)) + if (addr >= s && addr < e) { + next + } + } else if (type == "01") { + next + } + print + } + END { + while ((getline line < app) > 0) { + sub(/\r$/, "", line) + print line + } + }' "$1" > "$5" +} + +ipe_load() { + if [ -z "$MPLAB_DEVICE" ]; then + echo "MPLAB_DEVICE not set" + exit 1 + fi + + ipe_find_ipecmd + ipe_prepare_hex + + TOOL=${MPLAB_TOOL:-${MYNEWT_VAL_MYNEWT_DOWNLOADER_MPLAB_TOOL:-PK4}} + TOOL_SN=${MPLAB_TOOL_SN:-$MYNEWT_VAL_MYNEWT_DEBUGGER_SN} + + BUILD_DIR=$(cd "$(dirname "${HEX_FILE}")" && pwd) + HEX_PATH=$(ipe_native_path "${BUILD_DIR}/$(basename "${HEX_FILE}")") + + echo "Downloading ${HEX_FILE} with ${TOOL}" + # -OL: release device from reset after programming + if ipe_run -F${HEX_PATH} -M${IPE_MEMORY} ${IPE_ERASE} -OL; then + return + fi + + # PICkit 3 refuses non-blank memory, Snap/PICkit 4 program it and fail + # verification (flash bits can only be cleared without erase). + # ipecmd can't erase only part of flash, so whole device is read, + # application area is replaced and everything is programmed back after + # full erase. Bootloader, configuration words and other flash areas + # (file systems, logs) are restored from what was read. + if [ -z "$IPE_ERASE" ] || ! echo "$IPE_OUT" | grep -q -i -E "memory is not blank|expected 0x"; then + echo "Programming failed" + exit 1 + fi + if [ -z "$IMAGE_FLASH_SIZE" -o "$MPLAB_NO_READ_BACK" == "1" ]; then + echo "Application area is not blank, ipecmd can't program it without" + echo "erasing whole device. Load bootloader first, use manufacturing" + echo "image or build with MCU_NO_BOOTLOADER_BUILD." + echo "Programming failed" + exit 1 + fi + + echo "Application area is not blank, reading device to preserve other areas" + DEV_HEX=device_read.hex + rm -f "${BUILD_DIR}/${DEV_HEX}" + # ipecmd accepts only file name relative to current directory for -GF + if ! ipe_run -GF${DEV_HEX} || [ ! -s "${BUILD_DIR}/${DEV_HEX}" ]; then + echo "Device read failed, nothing was erased" + exit 1 + fi + + MERGED_HEX=${BUILD_DIR}/$(basename "${BIN_BASENAME}").merged.hex + ipe_merge_hex "${BUILD_DIR}/${DEV_HEX}" "${BUILD_DIR}/$(basename "${HEX_FILE}")" \ + ${IMAGE_FLASH_ADDR} ${IMAGE_FLASH_SIZE} "${MERGED_HEX}" || exit 1 + + echo "Programming application merged with device content" + if ! ipe_run -F$(ipe_native_path "${MERGED_HEX}") -M -OL; then + echo "Programming failed, device content was saved in ${BUILD_DIR}/${DEV_HEX}" + exit 1 + fi +} diff --git a/hw/scripts/pic32_download.sh b/hw/scripts/pic32_download.sh new file mode 100755 index 000000000..7a2da1ca0 --- /dev/null +++ b/hw/scripts/pic32_download.sh @@ -0,0 +1,114 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +# +# Download script for PIC32 BSPs (bsp.downloadscript). +# +# Called with following variables set: +# - CORE_PATH is absolute path to @apache-mynewt-core +# - BSP_PATH is absolute path to hw/bsp/bsp_name +# - BIN_BASENAME is the path to prefix to target binary, +# .elf appended to name is the ELF file +# - FLASH_OFFSET, FLASH_AREA_SIZE flash area (application slot or +# bootloader) to download to, from BSP flash map +# - EXTRA_JTAG_CMD holds extra parameters to pass to programmer software +# - MFG_IMAGE is "1" if this is a manufacturing image +# - BOOT_LOADER is set if downloading a bootloader +# +# Syscfg values used: +# - JLINK_TARGET device name (e.g. PIC32MZ2048EFM144), set by BSP +# - MYNEWT_DOWNLOADER: jlink or mplab_ipe (PICkit, Snap, ICD) +# - MCU_NO_BOOTLOADER_BUILD set when application is built to run without +# bootloader +# + +. $CORE_PATH/hw/scripts/jlink.sh + +PIC32_DEVICE=${MYNEWT_VAL_JLINK_TARGET} +IMAGE_FLASH_ADDR=${FLASH_OFFSET} +IMAGE_FLASH_SIZE=${FLASH_AREA_SIZE} +PIC32_JLINK_SPEED=${PIC32_JLINK_SPEED:-12000} + +# Runs JLinkExe with command file; fails if J-Link reported an error +pic32_jlink_run() { + local out + out=$(JLink${COMSPEC:+.}Exe -Device ${PIC32_DEVICE} -If ICSP $EXTRA_JTAG_CMD "$@" 2>&1) + local rc=$? + echo "$out" + if [ $rc -ne 0 ] || echo "$out" | grep -q -E "Error occurred|Could not connect|Failed to"; then + echo "J-Link operation failed" + exit 1 + fi +} + +pic32_jlink_load() { + jlink_sn + + local script=${BIN_BASENAME}.jlink + + echo "r" > $script + echo "h" >> $script + if [ "$BOOT_LOADER" -o "$MYNEWT_VAL_MCU_NO_BOOTLOADER_BUILD" == "1" ]; then + xc32-objcopy -O ihex ${BIN_BASENAME}.elf ${BIN_BASENAME}.hex || exit 1 + echo "loadfile ${BIN_BASENAME}.hex" >> $script + else + # J-Link erases only flash pages covered by the image, everything + # else (bootloader, other slots, data areas) is left intact. + cp ${BIN_BASENAME}.img ${BIN_BASENAME}.bin || exit 1 + echo "loadfile ${BIN_BASENAME}.bin ${IMAGE_FLASH_ADDR}" >> $script + fi + echo "q" >> $script + + pic32_jlink_run -AutoConnect 1 -speed ${PIC32_JLINK_SPEED} -CommandFile $script + + # Code started by debugger reset and go does not run reliably (first + # context switch never happens). Pulse MCLR without connecting to the + # target instead. + echo "r0" > $script + echo "sleep 200" >> $script + echo "r1" >> $script + echo "q" >> $script + pic32_jlink_run -CommandFile $script +} + +if [ -z "$PIC32_DEVICE" ]; then + >&2 echo "Syscfg value JLINK_TARGET (PIC32 device name) not set" + exit 1 +fi +if [ "$MFG_IMAGE" ]; then + >&2 echo "Manufacturing images are not supported for PIC32" + exit 1 +fi + +case "${MYNEWT_VAL_MYNEWT_DOWNLOADER}" in +"mplab_ipe") + . $CORE_PATH/hw/scripts/mplab_ipe.sh + # ipecmd expects device name without PIC prefix + MPLAB_DEVICE=${MYNEWT_VAL_MYNEWT_DOWNLOADER_MPLAB_DEVICE:-${PIC32_DEVICE#PIC}} + ipe_load + ;; +"" | "jlink") + pic32_jlink_load + ;; +*) + >&2 echo "Downloader ${MYNEWT_VAL_MYNEWT_DOWNLOADER} not supported for PIC32" + exit 1 + ;; +esac diff --git a/hw/scripts/syscfg.yml b/hw/scripts/syscfg.yml index 77076dce5..3d48f7be3 100644 --- a/hw/scripts/syscfg.yml +++ b/hw/scripts/syscfg.yml @@ -38,8 +38,21 @@ syscfg.defs: - nrfutil # Renesas ezFlashCLI for DA146x devices - ezflashcli + # Microchip MPLAB IPE command line (ipecmd) with PICkit, Snap, ICD + - mplab_ipe - bsp_downloader value: + MYNEWT_DOWNLOADER_MPLAB_TOOL: + description: > + Programmer used by mplab_ipe downloader as passed to ipecmd + with -TP option (PK3, PK4, PK5, SNAP, ICD3, ICD4, ICD5). + value: PK4 + MYNEWT_DOWNLOADER_MPLAB_DEVICE: + description: > + Device name used by mplab_ipe downloader as passed to ipecmd + with -P option (e.g. 32MZ2048EFM144). If not set, PIC32 + download script uses JLINK_TARGET without PIC prefix. + value: MYNEWT_DOWNLOADER_SCRIPT: description: > Custom downloader script name
