add jtag to ESP32
This commit is contained in:
parent
853d12f17c
commit
a15c797e93
Binary file not shown.
|
@ -0,0 +1,63 @@
|
|||
# USE jtag for openocd in ESP32
|
||||
|
||||
## board
|
||||
|
||||
ESP-C3-32S-Kit https://docs.ai-thinker.com/_media/esp32/docs/esp-c3-32s-kit-v1.0_规格书.pdf
|
||||
|
||||
## install JLink deb software and driver
|
||||
|
||||
## build esp32-c3 binary
|
||||
|
||||
```bash
|
||||
# At esp-idf
|
||||
source export.sh
|
||||
cd examples/get-started/blink
|
||||
idf.py set-target esp32-c3
|
||||
idf.py menuconfig # config the io and LED mode
|
||||
idf.py build
|
||||
idf.py -p (PORT) flash # to flash to module to verify the effect of binary by USART port
|
||||
```
|
||||
|
||||
## 配置ESP32
|
||||
|
||||
由于 ESP32-C3 默认选用 内置的 USB_SERIAL_JTAG 外设。此时需要烧录 efuse 来选择外接 JTAG 适配器,有以下两种方式:
|
||||
|
||||
* 烧毁 DIS_USB_JTAG eFuse: 将永久禁用 USB_SERIAL_JTAG 和 CPU 的 JTAG 端口之间的连接。 然后可以将 JTAG 接口连接到 GPIO4 - GPIO7。 请注意,USB_SERIAL_JTAG 的 USB CDC 功能仍然可用,即仍然可以通过 USB CDC 进行烧录和 log 查看。
|
||||
* 烧毁 JTAG_SEL_ENABLE eFuse: 将启用由 Strapping 引脚 GPIO10 选择的 JTAG 接口。 如果 ESP32-C3 复位时 Strapping 引脚为低电平,则 JTAG 接口将使用 GPIO4 - GPIO7。 如果 Strapping 引脚为高电平,则 USB_SERIAL_JTAG 将用作 JTAG 接口。
|
||||
|
||||
`espefuse.py burn_efuse JTAG_SEL_ENABLE -p /dev/ttyUSB0`
|
||||
然后你会得到一个需要输入BURN 的确认信息,如下:
|
||||
|
||||
```bash
|
||||
Connecting....
|
||||
Detecting chip type... ESP32-C3
|
||||
espefuse.py v3.3-dev
|
||||
The efuses to burn:
|
||||
from BLOCK0
|
||||
- JTAG_SEL_ENABLE
|
||||
|
||||
Burning efuses:
|
||||
|
||||
- 'JTAG_SEL_ENABLE' (Disables USB JTAG. JTAG access via pads is controlled separately) 0b0 -> 0b1
|
||||
|
||||
Check all blocks for burn...
|
||||
idx, BLOCK_NAME, Conclusion
|
||||
[00] BLOCK0 is not empty
|
||||
(written ): 0x000000000000008000000000000000000000800000000000
|
||||
(to write): 0x000000000000000000000000000000000000020000000000
|
||||
(coding scheme = NONE)
|
||||
.
|
||||
This is an irreversible operation!
|
||||
Type 'BURN' (all capitals) to continue.
|
||||
```
|
||||
|
||||
## usage
|
||||
|
||||
* 链接JLink的 jtag 四个IO,`TMS` `TDI` `TDO` `TCK`
|
||||
* 默认固件开发板的JTAG IO不能用于其他功能,必须是闲置状态
|
||||
* Must use esp's `openocd` by source export.sh in esp-idy, after esp-idf installed.
|
||||
|
||||
## cmd
|
||||
|
||||
* `./openocd.sh` start openocd
|
||||
* `./gdb.sh` start gdb
|
|
@ -0,0 +1,59 @@
|
|||
#----------------------------------------
|
||||
# Purpose - Create some $BIT variables
|
||||
# Create $K and $M variables
|
||||
# and some bit field extraction variables.
|
||||
# Creat helper variables ...
|
||||
# BIT0.. BIT31
|
||||
|
||||
for { set x 0 } { $x < 32 } { set x [expr $x + 1]} {
|
||||
set vn [format "BIT%d" $x]
|
||||
global $vn
|
||||
set $vn [expr (1 << $x)]
|
||||
}
|
||||
|
||||
# Create K bytes values
|
||||
# __1K ... to __2048K
|
||||
for { set x 1 } { $x < 2048 } { set x [expr $x * 2]} {
|
||||
set vn [format "__%dK" $x]
|
||||
global $vn
|
||||
set $vn [expr (1024 * $x)]
|
||||
}
|
||||
|
||||
# Create M bytes values
|
||||
# __1M ... to __2048K
|
||||
for { set x 1 } { $x < 2048 } { set x [expr $x * 2]} {
|
||||
set vn [format "__%dM" $x]
|
||||
global $vn
|
||||
set $vn [expr (1024 * 1024 * $x)]
|
||||
}
|
||||
|
||||
proc create_mask { MSB LSB } {
|
||||
return [expr (((1 << ($MSB - $LSB + 1))-1) << $LSB)]
|
||||
}
|
||||
|
||||
# Cut Bits $MSB to $LSB out of this value.
|
||||
# Example: % format "0x%08x" [extract_bitfield 0x12345678 27 16]
|
||||
# Result: 0x02340000
|
||||
|
||||
proc extract_bitfield { VALUE MSB LSB } {
|
||||
return [expr [create_mask $MSB $LSB] & $VALUE]
|
||||
}
|
||||
|
||||
|
||||
# Cut bits $MSB to $LSB out of this value
|
||||
# and shift (normalize) them down to bit 0.
|
||||
#
|
||||
# Example: % format "0x%08x" [normalize_bitfield 0x12345678 27 16]
|
||||
# Result: 0x00000234
|
||||
#
|
||||
proc normalize_bitfield { VALUE MSB LSB } {
|
||||
return [expr [extract_bitfield $VALUE $MSB $LSB ] >> $LSB]
|
||||
}
|
||||
|
||||
proc show_normalize_bitfield { VALUE MSB LSB } {
|
||||
set m [create_mask $MSB $LSB]
|
||||
set mr [expr $VALUE & $m]
|
||||
set sr [expr $mr >> $LSB]
|
||||
echo [format "((0x%08x & 0x%08x) -> 0x%08x) >> %2d => (0x%x) %5d " $VALUE $m $mr $LSB $sr $sr]
|
||||
return $sr
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,134 @@
|
|||
# The ESP32-C3 only supports JTAG.
|
||||
transport select jtag
|
||||
|
||||
set CPU_MAX_ADDRESS 0xFFFFFFFF
|
||||
source [find bitsbytes.tcl]
|
||||
source [find memory.tcl]
|
||||
source [find mmr_helpers.tcl]
|
||||
# Source the ESP common configuration file
|
||||
source [find target/esp_common.cfg]
|
||||
|
||||
# Target specific registers
|
||||
set EFUSE_MAC_ADDR_REG 0x60008844
|
||||
|
||||
if { [info exists CHIPNAME] } {
|
||||
set _CHIPNAME $CHIPNAME
|
||||
} else {
|
||||
set _CHIPNAME esp32c3
|
||||
}
|
||||
|
||||
if { [info exists CPUTAPID] } {
|
||||
set _CPUTAPID $CPUTAPID
|
||||
} else {
|
||||
set _CPUTAPID 0x00005c25
|
||||
}
|
||||
|
||||
set _TARGETNAME $_CHIPNAME
|
||||
set _CPUNAME cpu
|
||||
set _TAPNAME $_CHIPNAME.$_CPUNAME
|
||||
|
||||
jtag newtap $_CHIPNAME $_CPUNAME -irlen 5 -expected-id $_CPUTAPID
|
||||
|
||||
proc esp32c3_wdt_disable { } {
|
||||
# Halt event can occur during config phase (before "init" is done).
|
||||
# Ignore it since mww commands don't work at that time.
|
||||
if { [string compare [command mode] config] == 0 } {
|
||||
return
|
||||
}
|
||||
|
||||
# Timer Group 0 & 1 WDTs
|
||||
mww 0x6001f064 0x50D83AA1
|
||||
mww 0x6001F048 0
|
||||
mww 0x60020064 0x50D83AA1
|
||||
mww 0x60020048 0
|
||||
# RTC WDT
|
||||
mww 0x600080a8 0x50D83AA1
|
||||
mww 0x60008090 0
|
||||
# SWD
|
||||
mww 0x600080b0 0x8F1D312A
|
||||
mww 0x600080ac 0x84B00000
|
||||
}
|
||||
|
||||
proc esp32c3_soc_reset { } {
|
||||
# This procedure does "digital system reset", i.e. resets
|
||||
# all the peripherals except for the RTC block.
|
||||
# It is called from reset-assert-post target event callback,
|
||||
# after assert_reset procedure was called.
|
||||
# Since we need the hart to to execute a write to RTC_CNTL_SW_SYS_RST,
|
||||
# temporarily take it out of reset. Save the dmcontrol state before
|
||||
# doing so.
|
||||
riscv dmi_write 0x10 0x80000001
|
||||
# If SBA is used to trigger the reset, the debug module gets stuck
|
||||
# in a busy state waiting for the bus write to complete (HW quirk?),
|
||||
# so trigger the reset by CPU instead.
|
||||
riscv set_prefer_sba off
|
||||
mww 0x60008000 0x9c00a000
|
||||
# Workaround for stuck in cpu start during calibration.
|
||||
# By writing zero to TIMG_RTCCALICFG_REG, we are disabling calibration
|
||||
mww 0x6001F068 0
|
||||
# Wait for the reset to happen
|
||||
sleep 10
|
||||
poll
|
||||
# Restore SBA setting
|
||||
riscv set_prefer_sba on
|
||||
# Disable the watchdogs again
|
||||
esp32c3_wdt_disable
|
||||
# Put the hart back into reset state. Note that we need to keep haltreq set.
|
||||
riscv dmi_write 0x10 0x80000003
|
||||
}
|
||||
|
||||
proc esp32c3_memprot_is_enabled { } {
|
||||
# IRAM0 PMS lock, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_0_REG
|
||||
if { [mmr_get_bit 0x600C10A8 0] != 0 } {
|
||||
return 1
|
||||
}
|
||||
# DRAM0 PMS lock, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_0_REG
|
||||
if { [mmr_get_bit 0x600C10C0 0] != 0 } {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
if { $_RTOS == "none" } {
|
||||
target create $_TARGETNAME esp32c3 -chain-position $_TAPNAME
|
||||
} else {
|
||||
target create $_TARGETNAME esp32c3 -chain-position $_TAPNAME -rtos $_RTOS
|
||||
}
|
||||
|
||||
$_TARGETNAME configure -event reset-assert-post { esp32c3_soc_reset }
|
||||
$_TARGETNAME configure -event halted {
|
||||
esp32c3_wdt_disable
|
||||
}
|
||||
$_TARGETNAME configure -event examine-end {
|
||||
# Need this to handle 'apptrace init' syscall correctly because semihosting is not enabled by default
|
||||
arm semihosting enable
|
||||
arm semihosting_resexit enable
|
||||
}
|
||||
$_TARGETNAME configure -event gdb-attach {
|
||||
# 'halt' is necessary to auto-probe flash bank when GDB is connected and generate proper memory map
|
||||
halt
|
||||
if { [esp32c3_memprot_is_enabled] } {
|
||||
# 'reset halt' to disable memory protection and allow flasher to work correctly
|
||||
echo "Memory protection is enabled. Reset target to disable it..."
|
||||
reset halt
|
||||
}
|
||||
# by default mask interrupts while stepping
|
||||
riscv maskisr steponly
|
||||
}
|
||||
|
||||
# stub flasher may need a lot of memory in case of compressed writes to flash (~107KB):
|
||||
# - for apptrace: 2x16KB up buffers + 32KB down buffer
|
||||
# - for uncompression: 32KB for unzip buffer size + 11KB for inflator data structs
|
||||
# TODO: In general when up buffers are swapped apptrace copies `host->target` data from new up buffer to down buffer to free space for `target->host` data.
|
||||
# In case of flash writes we use apptrace transfers in one direction only. So we can avoid copying and re-use up buffer instead of down one.
|
||||
configure_esp_workarea $_TARGETNAME 0x40380000 0x4000 0x3FC84000 0x20000
|
||||
configure_esp_flash_bank $_TARGETNAME $_TARGETNAME $_FLASH_SIZE
|
||||
|
||||
if { $_FLASH_SIZE == 0 } {
|
||||
gdb_breakpoint_override hard
|
||||
}
|
||||
|
||||
riscv set_reset_timeout_sec 2
|
||||
riscv set_command_timeout_sec 5
|
||||
riscv set_prefer_sba on
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
source ~/develop/esp-idf/export.sh
|
||||
riscv32-esp-elf-gdb -x gdbinit blink.elf
|
|
@ -0,0 +1,7 @@
|
|||
target remote :3333
|
||||
set remote hardware-watchpoint-limit 2
|
||||
mon reset halt
|
||||
flushregs
|
||||
thb app_main
|
||||
directory /home/colin/develop/esp-idf
|
||||
c
|
|
@ -0,0 +1,16 @@
|
|||
#
|
||||
# SEGGER J-Link
|
||||
#
|
||||
# http://www.segger.com/jlink.html
|
||||
#
|
||||
|
||||
adapter driver jlink
|
||||
adapter speed 1000
|
||||
|
||||
|
||||
# The serial number can be used to select a specific device in case more than
|
||||
# one is connected to the host.
|
||||
#
|
||||
# Example: Select J-Link with serial number 123456789
|
||||
#
|
||||
# adapter serial 123456789
|
|
@ -0,0 +1,187 @@
|
|||
# MEMORY
|
||||
#
|
||||
# All Memory regions have two components.
|
||||
# (1) A count of regions, in the form N_NAME
|
||||
# (2) An array within info about each region.
|
||||
#
|
||||
# The ARRAY
|
||||
#
|
||||
# <NAME>( RegionNumber , ATTRIBUTE )
|
||||
#
|
||||
# Where <NAME> is one of:
|
||||
#
|
||||
# N_FLASH & FLASH (internal memory)
|
||||
# N_RAM & RAM (internal memory)
|
||||
# N_MMREGS & MMREGS (for memory mapped registers)
|
||||
# N_XMEM & XMEM (off chip memory, ie: flash on cs0, sdram on cs2)
|
||||
# or N_UNKNOWN & UNKNOWN for things that do not exist.
|
||||
#
|
||||
# We have 1 unknown region.
|
||||
set N_UNKNOWN 1
|
||||
# All MEMORY regions must have these attributes
|
||||
# CS - chip select (if internal, use -1)
|
||||
set UNKNOWN(0,CHIPSELECT) -1
|
||||
# BASE - base address in memory
|
||||
set UNKNOWN(0,BASE) 0
|
||||
# LEN - length in bytes
|
||||
set UNKNOWN(0,LEN) $CPU_MAX_ADDRESS
|
||||
# HUMAN - human name of the region
|
||||
set UNKNOWN(0,HUMAN) "unknown"
|
||||
# TYPE - one of:
|
||||
# flash, ram, mmr, unknown
|
||||
# For harvard arch:
|
||||
# iflash, dflash, iram, dram
|
||||
set UNKNOWN(0,TYPE) "unknown"
|
||||
# RWX - access ablity
|
||||
# unix style chmod bits
|
||||
# 0 - no access
|
||||
# 1 - execute
|
||||
# 2 - write
|
||||
# 4 - read
|
||||
# hence: 7 - readwrite execute
|
||||
set RWX_NO_ACCESS 0
|
||||
set RWX_X_ONLY $BIT0
|
||||
set RWX_W_ONLY $BIT1
|
||||
set RWX_R_ONLY $BIT2
|
||||
set RWX_RW [expr $RWX_R_ONLY + $RWX_W_ONLY]
|
||||
set RWX_R_X [expr $RWX_R_ONLY + $RWX_X_ONLY]
|
||||
set RWX_RWX [expr $RWX_R_ONLY + $RWX_W_ONLY + $RWX_X_ONLY]
|
||||
set UNKNOWN(0,RWX) $RWX_NO_ACCESS
|
||||
|
||||
# WIDTH - access width
|
||||
# 8,16,32 [0 means ANY]
|
||||
set ACCESS_WIDTH_NONE 0
|
||||
set ACCESS_WIDTH_8 $BIT0
|
||||
set ACCESS_WIDTH_16 $BIT1
|
||||
set ACCESS_WIDTH_32 $BIT2
|
||||
set ACCESS_WIDTH_ANY [expr $ACCESS_WIDTH_8 + $ACCESS_WIDTH_16 + $ACCESS_WIDTH_32]
|
||||
set UNKNOWN(0,ACCESS_WIDTH) $ACCESS_WIDTH_NONE
|
||||
|
||||
proc iswithin { ADDRESS BASE LEN } {
|
||||
return [expr ((($ADDRESS - $BASE) >= 0) && (($BASE + $LEN - $ADDRESS) > 0))]
|
||||
}
|
||||
|
||||
proc address_info { ADDRESS } {
|
||||
|
||||
foreach WHERE { FLASH RAM MMREGS XMEM UNKNOWN } {
|
||||
if { info exists $WHERE } {
|
||||
set lmt [set N_[set WHERE]]
|
||||
for { set region 0 } { $region < $lmt } { incr region } {
|
||||
if { iswithin $ADDRESS $WHERE($region,BASE) $WHERE($region,LEN) } {
|
||||
return "$WHERE $region";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Return the 'unknown'
|
||||
return "UNKNOWN 0"
|
||||
}
|
||||
|
||||
proc memread32 {ADDR} {
|
||||
set foo(0) 0
|
||||
if ![ catch { mem2array foo 32 $ADDR 1 } msg ] {
|
||||
return $foo(0)
|
||||
} else {
|
||||
error "memread32: $msg"
|
||||
}
|
||||
}
|
||||
|
||||
proc memread16 {ADDR} {
|
||||
set foo(0) 0
|
||||
if ![ catch { mem2array foo 16 $ADDR 1 } msg ] {
|
||||
return $foo(0)
|
||||
} else {
|
||||
error "memread16: $msg"
|
||||
}
|
||||
}
|
||||
|
||||
proc memread8 {ADDR} {
|
||||
set foo(0) 0
|
||||
if ![ catch { mem2array foo 8 $ADDR 1 } msg ] {
|
||||
return $foo(0)
|
||||
} else {
|
||||
error "memread8: $msg"
|
||||
}
|
||||
}
|
||||
|
||||
proc memwrite32 {ADDR DATA} {
|
||||
set foo(0) $DATA
|
||||
if ![ catch { array2mem foo 32 $ADDR 1 } msg ] {
|
||||
return $foo(0)
|
||||
} else {
|
||||
error "memwrite32: $msg"
|
||||
}
|
||||
}
|
||||
|
||||
proc memwrite16 {ADDR DATA} {
|
||||
set foo(0) $DATA
|
||||
if ![ catch { array2mem foo 16 $ADDR 1 } msg ] {
|
||||
return $foo(0)
|
||||
} else {
|
||||
error "memwrite16: $msg"
|
||||
}
|
||||
}
|
||||
|
||||
proc memwrite8 {ADDR DATA} {
|
||||
set foo(0) $DATA
|
||||
if ![ catch { array2mem foo 8 $ADDR 1 } msg ] {
|
||||
return $foo(0)
|
||||
} else {
|
||||
error "memwrite8: $msg"
|
||||
}
|
||||
}
|
||||
|
||||
proc memread32_phys {ADDR} {
|
||||
set foo(0) 0
|
||||
if ![ catch { mem2array foo 32 $ADDR 1 phys } msg ] {
|
||||
return $foo(0)
|
||||
} else {
|
||||
error "memread32: $msg"
|
||||
}
|
||||
}
|
||||
|
||||
proc memread16_phys {ADDR} {
|
||||
set foo(0) 0
|
||||
if ![ catch { mem2array foo 16 $ADDR 1 phys } msg ] {
|
||||
return $foo(0)
|
||||
} else {
|
||||
error "memread16: $msg"
|
||||
}
|
||||
}
|
||||
|
||||
proc memread8_phys {ADDR} {
|
||||
set foo(0) 0
|
||||
if ![ catch { mem2array foo 8 $ADDR 1 phys } msg ] {
|
||||
return $foo(0)
|
||||
} else {
|
||||
error "memread8: $msg"
|
||||
}
|
||||
}
|
||||
|
||||
proc memwrite32_phys {ADDR DATA} {
|
||||
set foo(0) $DATA
|
||||
if ![ catch { array2mem foo 32 $ADDR 1 phys } msg ] {
|
||||
return $foo(0)
|
||||
} else {
|
||||
error "memwrite32: $msg"
|
||||
}
|
||||
}
|
||||
|
||||
proc memwrite16_phys {ADDR DATA} {
|
||||
set foo(0) $DATA
|
||||
if ![ catch { array2mem foo 16 $ADDR 1 phys } msg ] {
|
||||
return $foo(0)
|
||||
} else {
|
||||
error "memwrite16: $msg"
|
||||
}
|
||||
}
|
||||
|
||||
proc memwrite8_phys {ADDR DATA} {
|
||||
set foo(0) $DATA
|
||||
if ![ catch { array2mem foo 8 $ADDR 1 phys } msg ] {
|
||||
return $foo(0)
|
||||
} else {
|
||||
error "memwrite8: $msg"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
|
||||
proc proc_exists { NAME } {
|
||||
set n [info commands $NAME]
|
||||
set l [string length $n]
|
||||
return [expr $l != 0]
|
||||
}
|
||||
|
||||
# Give: REGISTER name - must be a global variable.
|
||||
proc show_mmr32_reg { NAME } {
|
||||
|
||||
global $NAME
|
||||
# we want $($NAME)
|
||||
set a [set [set NAME]]
|
||||
|
||||
if ![catch { set v [memread32 $a] } msg ] {
|
||||
echo [format "%15s: (0x%08x): 0x%08x" $NAME $a $v]
|
||||
|
||||
# Was a helper defined?
|
||||
set fn show_${NAME}_helper
|
||||
if [ proc_exists $fn ] {
|
||||
# Then call it
|
||||
$fn $NAME $a $v
|
||||
}
|
||||
return $v;
|
||||
} else {
|
||||
error [format "%s (%s)" $msg $NAME ]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Give: NAMES - an array of names accessible
|
||||
# in the callers symbol-scope.
|
||||
# VAL - the bits to display.
|
||||
|
||||
proc show_mmr32_bits { NAMES VAL } {
|
||||
|
||||
upvar $NAMES MYNAMES
|
||||
|
||||
set w 5
|
||||
foreach {IDX N} $MYNAMES {
|
||||
set l [string length $N]
|
||||
if { $l > $w } { set w $l }
|
||||
}
|
||||
|
||||
for { set x 24 } { $x >= 0 } { incr x -8 } {
|
||||
echo -n " "
|
||||
for { set y 7 } { $y >= 0 } { incr y -1 } {
|
||||
set s $MYNAMES([expr $x + $y])
|
||||
echo -n [format "%2d: %-*s | " [expr $x + $y] $w $s ]
|
||||
}
|
||||
echo ""
|
||||
|
||||
echo -n " "
|
||||
for { set y 7 } { $y >= 0 } { incr y -1 } {
|
||||
echo -n [format " %d%*s | " [expr !!($VAL & (1 << ($x + $y)))] [expr $w -1] ""]
|
||||
}
|
||||
echo ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
proc show_mmr_bitfield { MSB LSB VAL FIELDNAME FIELDVALUES } {
|
||||
set width [expr (($MSB - $LSB + 1) + 7) / 4]
|
||||
set nval [show_normalize_bitfield $VAL $MSB $LSB ]
|
||||
set name0 [lindex $FIELDVALUES 0 ]
|
||||
if [ string compare $name0 _NUMBER_ ] {
|
||||
set sval [lindex $FIELDVALUES $nval]
|
||||
} else {
|
||||
set sval ""
|
||||
}
|
||||
echo [format "%-15s: %d (0x%0*x) %s" $FIELDNAME $nval $width $nval $sval ]
|
||||
}
|
||||
|
||||
# Give: ADDR - address of the register.
|
||||
# BIT - bit's number.
|
||||
|
||||
proc mmr_get_bit { ADDR BIT } {
|
||||
set val [memread32 $ADDR]
|
||||
set bit_val [expr $val & [expr 1 << $BIT]]
|
||||
return $bit_val
|
||||
}
|
||||
|
||||
|
||||
# Give: ADDR - address of the register.
|
||||
# MSB - MSB bit's number.
|
||||
# LSB - LSB bit's number.
|
||||
|
||||
proc mmr_get_bitfield { ADDR MSB LSB } {
|
||||
set rval [memread32 $ADDR]
|
||||
return normalize_bitfield $rval $MSB $LSB
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
source ~/develop/esp-idf/export.sh
|
||||
openocd -f jlink.cfg -f esp32c3.cfg
|
|
@ -0,0 +1,269 @@
|
|||
# Common ESP chips definitions
|
||||
|
||||
if { [info exists ESP_RTOS] } {
|
||||
set _RTOS "$ESP_RTOS"
|
||||
} else {
|
||||
set _RTOS "FreeRTOS"
|
||||
}
|
||||
|
||||
if { [info exists ESP_SEMIHOST_BASEDIR] } {
|
||||
set _SEMIHOST_BASEDIR "$ESP_SEMIHOST_BASEDIR"
|
||||
} else {
|
||||
# by default current dir (when OOCD has been started)
|
||||
set _SEMIHOST_BASEDIR "."
|
||||
}
|
||||
|
||||
if { [info exists ESP_FLASH_SIZE] } {
|
||||
set _FLASH_SIZE $ESP_FLASH_SIZE
|
||||
} else {
|
||||
set _FLASH_SIZE "auto"
|
||||
}
|
||||
|
||||
proc configure_esp_workarea { TGT CODE_ADDR CODE_SZ DATA_ADDR DATA_SZ } {
|
||||
#WARNING: be careful when selecting working ares for code and data, they should not overlap due to ESP32 physical memory mappings
|
||||
$TGT configure -work-area-phys $CODE_ADDR -work-area-virt $CODE_ADDR -work-area-size $CODE_SZ -work-area-backup 1
|
||||
# since ESP32 cannot use single address space for code and data we need additional working area to keep data
|
||||
$TGT configure -alt-work-area-phys $DATA_ADDR -alt-work-area-virt $DATA_ADDR -alt-work-area-size $DATA_SZ -alt-work-area-backup 1
|
||||
}
|
||||
|
||||
proc configure_esp_workarea_backups { wab_list awab_list } {
|
||||
set index 0
|
||||
foreach tgt [target names] {
|
||||
$tgt configure -work-area-backup [lindex $wab_list $index]
|
||||
$tgt configure -alt-work-area-backup [lindex $awab_list $index]
|
||||
incr $index
|
||||
}
|
||||
}
|
||||
|
||||
proc configure_esp_flash_bank { TGT DRV SIZE } {
|
||||
set _SIZE SIZE
|
||||
if { $SIZE == 0 } {
|
||||
echo "WARNING: ESP flash support is disabled!"
|
||||
return
|
||||
} else {
|
||||
if { $SIZE == "auto" } {
|
||||
# special value for flash driver
|
||||
set _SIZE 0
|
||||
}
|
||||
}
|
||||
# whole flash for programming purposes
|
||||
# TODO: remove it when support for GDB's 'load' comand is implemented
|
||||
flash bank $TGT.flash $DRV 0x0 $_SIZE 0 0 $TGT
|
||||
# So define mapped flash regions as separate flashes
|
||||
# OOCD creates memory map using registered flash banks
|
||||
flash bank $TGT.irom $DRV 0x0 0 0 0 $TGT
|
||||
flash bank $TGT.drom $DRV 0x0 0 0 0 $TGT
|
||||
}
|
||||
|
||||
# special function to program ESP chip, it differs from the original 'program' that
|
||||
# it verifies written image by reading flash directly, instead of reading memory mapped flash regions
|
||||
proc program_esp {filename args} {
|
||||
set exit 0
|
||||
set compress 0
|
||||
set restore_clock 0
|
||||
|
||||
set flash_list_size [llength [flash list]]
|
||||
if { $flash_list_size == 0} {
|
||||
program_error "** ESP flash programming is not supported yet! **" $exit
|
||||
}
|
||||
|
||||
foreach arg $args {
|
||||
if {[string equal $arg "verify"]} {
|
||||
set verify 1
|
||||
} elseif {[string equal $arg "reset"]} {
|
||||
set reset 1
|
||||
} elseif {[string equal $arg "exit"]} {
|
||||
set exit 1
|
||||
} elseif {[string equal $arg "compress"]} {
|
||||
set compress 1
|
||||
} elseif {[string equal $arg "restore_clock"]} {
|
||||
set restore_clock 1
|
||||
} else {
|
||||
set address $arg
|
||||
}
|
||||
}
|
||||
|
||||
# make sure init is called
|
||||
if {[catch {init}] != 0} {
|
||||
program_error "** OpenOCD init failed **" 1
|
||||
}
|
||||
|
||||
# reset target and call any init scripts
|
||||
if {[catch {reset init}] != 0} {
|
||||
program_error "** Unable to reset target **" $exit
|
||||
}
|
||||
|
||||
set wab_list {}
|
||||
set awab_list {}
|
||||
foreach tgt [target names] {
|
||||
lappend wab_list [$tgt cget -work-area-backup]
|
||||
$tgt configure -work-area-backup 0
|
||||
lappend awab_list [$tgt cget -alt-work-area-backup]
|
||||
$tgt configure -alt-work-area-backup 0
|
||||
}
|
||||
|
||||
if {$compress == 1} {
|
||||
eval esp compression "on"
|
||||
} else {
|
||||
eval esp compression "off"
|
||||
}
|
||||
|
||||
# start programming phase
|
||||
echo "** Programming Started **"
|
||||
if {[info exists address]} {
|
||||
set flash_args "$filename $address"
|
||||
} else {
|
||||
set flash_args "$filename"
|
||||
}
|
||||
|
||||
if {[catch {eval esp flash_stub_clock_boost "on"}] != 0} {
|
||||
program_error "** Clock configuration set failed **" $exit
|
||||
}
|
||||
|
||||
if {[catch {eval flash write_image erase $flash_args}] == 0} {
|
||||
echo "** Programming Finished **"
|
||||
if {[info exists verify]} {
|
||||
# verify phase
|
||||
echo "** Verify Started **"
|
||||
if {[catch {eval esp verify_bank_hash 0 $flash_args}] == 0} {
|
||||
echo "** Verified OK **"
|
||||
} else {
|
||||
configure_esp_workarea_backups $wab_list $awab_list
|
||||
if {$restore_clock == 1} {
|
||||
eval esp flash_stub_clock_boost "off"
|
||||
}
|
||||
program_error "** Verify Failed **" $exit
|
||||
}
|
||||
}
|
||||
|
||||
configure_esp_workarea_backups $wab_list $awab_list
|
||||
|
||||
if {$restore_clock == 1} {
|
||||
if {[catch {eval esp flash_stub_clock_boost "off"}] != 0} {
|
||||
program_error "** Clock configuration restore failed **" $exit
|
||||
}
|
||||
}
|
||||
|
||||
if {[info exists reset]} {
|
||||
# reset target if requested
|
||||
echo "** Resetting Target **"
|
||||
reset run
|
||||
}
|
||||
} else {
|
||||
configure_esp_workarea_backups $wab_list $awab_list
|
||||
if {$restore_clock == 1} {
|
||||
eval esp flash_stub_clock_boost "off"
|
||||
}
|
||||
program_error "** Programming Failed **" $exit
|
||||
}
|
||||
|
||||
if {$exit == 1} {
|
||||
shutdown
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
add_help_text program_esp "write an image to flash, address is only required for binary images. verify, reset, exit, compress, restore_clock are optional"
|
||||
add_usage_text program_esp "<filename> \[address\] \[verify\] \[reset\] \[exit\] \[compress\] \[restore_clock\]"
|
||||
|
||||
proc program_esp_bins {build_dir filename args} {
|
||||
set exit 0
|
||||
set compress 0
|
||||
set restore_clock 0
|
||||
|
||||
foreach arg $args {
|
||||
if {[string equal $arg "reset"]} {
|
||||
set reset 1
|
||||
} elseif {[string equal $arg "verify"]} {
|
||||
set verify 1
|
||||
} elseif {[string equal $arg "exit"]} {
|
||||
set exit 1
|
||||
} elseif {[string equal $arg "compress"]} {
|
||||
set compress 1
|
||||
} elseif {[string equal $arg "restore_clock"]} {
|
||||
set restore_clock 1
|
||||
} else {
|
||||
echo "** Unsupported arg $arg, skipping **"
|
||||
}
|
||||
}
|
||||
|
||||
# Open and Read file
|
||||
set fp [open [file join $build_dir $filename] r]
|
||||
set file_data [read $fp]
|
||||
close $fp
|
||||
|
||||
# Decode JSON to dict
|
||||
set flasher_args [json::decode $file_data]
|
||||
|
||||
set flash_files [dict get $flasher_args flash_files]
|
||||
|
||||
foreach addr [dict keys $flash_files] {
|
||||
set bin_file [dict get $flash_files $addr]
|
||||
set bin_file_path [file join $build_dir $bin_file]
|
||||
|
||||
echo "Flashing $bin_file_path at $addr"
|
||||
|
||||
if {[info exists verify]} {
|
||||
set flash_args "$bin_file_path $addr verify"
|
||||
} else {
|
||||
set flash_args "$bin_file_path $addr"
|
||||
}
|
||||
|
||||
if {$compress == 1} {
|
||||
append flash_args " compress"
|
||||
}
|
||||
|
||||
if {$restore_clock == 1} {
|
||||
append flash_args " restore_clock"
|
||||
}
|
||||
|
||||
if {[ catch { eval program_esp $flash_args} ] == 0} {
|
||||
echo "** Flashing done for $bin_file **"
|
||||
} else {
|
||||
echo "** Flashing Failed **"
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
# Reset
|
||||
if {[info exists reset]} {
|
||||
echo "** Resetting Target **"
|
||||
reset run
|
||||
}
|
||||
|
||||
# Exit
|
||||
if {$exit == 1} {
|
||||
shutdown
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
add_help_text program_esp_bins "write all the images at address specified in flasher_args.json generated while building idf project"
|
||||
add_usage_text program_esp_bins "<build_dir> flasher_args.json \[verify\] \[reset\] \[exit\] \[compress\] \[restore_clock\]"
|
||||
|
||||
proc esp_get_mac {args} {
|
||||
global EFUSE_MAC_ADDR_REG
|
||||
foreach arg $args {
|
||||
if {[string equal $arg "format"]} {
|
||||
set format 1
|
||||
}
|
||||
}
|
||||
|
||||
if { [string equal [target current] esp32c3] } {
|
||||
mem2array mac 8 $EFUSE_MAC_ADDR_REG 6
|
||||
} else {
|
||||
xtensa set_permissive 1
|
||||
mem2array mac 8 $EFUSE_MAC_ADDR_REG 6
|
||||
xtensa set_permissive 0
|
||||
}
|
||||
|
||||
if {[info exists format]} {
|
||||
format %02x:%02x:%02x:%02x:%02x:%02x $mac(5) $mac(4) $mac(3) $mac(2) $mac(1) $mac(0)
|
||||
} else {
|
||||
format 0x0000%02x%02x%02x%02x%02x%02x $mac(5) $mac(4) $mac(3) $mac(2) $mac(1) $mac(0)
|
||||
}
|
||||
}
|
||||
|
||||
add_help_text esp_get_mac "Print MAC address of the chip. Use a `format` argument to return formatted MAC value"
|
||||
add_usage_text esp_get_mac "\[format\]"
|
|
@ -0,0 +1,16 @@
|
|||
# USE USB for openocd in ESP32
|
||||
|
||||
## board
|
||||
|
||||
ESP-C3-32S-Kit https://docs.ai-thinker.com/_media/esp32/docs/esp-c3-32s-kit-v1.0_规格书.pdf
|
||||
|
||||
|
||||
## usage
|
||||
|
||||
* 连接usb的io18和io19,并确保这两个IO没有被连接到其他地方
|
||||
* 配置esp32-c3打开usb及jtag
|
||||
|
||||
## cmd
|
||||
|
||||
* `source openocd.sh` 启动openocd
|
||||
* `source gdb.sh` 启动gdb
|
Binary file not shown.
|
@ -0,0 +1,2 @@
|
|||
source ~/develop/esp-idf/export.sh
|
||||
riscv32-esp-elf-gdb -x gdbinit blink.elf
|
|
@ -0,0 +1,6 @@
|
|||
target remote :3333
|
||||
set remote hardware-watchpoint-limit 2
|
||||
mon reset halt
|
||||
flushregs
|
||||
thb app_main
|
||||
c
|
|
@ -0,0 +1,2 @@
|
|||
source ~/develop/esp-idf/export.sh
|
||||
openocd -f board/esp32c3-builtin.cfg
|
Loading…
Reference in New Issue