JTAG ID scanning works!
This commit is contained in:
parent
f96243eb80
commit
9ca6ae61c0
|
@ -32,6 +32,7 @@ if(FAMILY STREQUAL "rp2040")
|
|||
target_sources(${PROJECT} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pio_sbw.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/tap.c
|
||||
)
|
||||
|
||||
# Example include
|
||||
|
|
13
src/main.c
13
src/main.c
|
@ -9,7 +9,9 @@
|
|||
#include <hardware/gpio.h>
|
||||
#include <pico/stdlib.h>
|
||||
#include <pico/binary_info.h>
|
||||
|
||||
#include "pio_sbw.h"
|
||||
#include "tap.h"
|
||||
|
||||
void printbuf(const uint8_t* buf, size_t size) {
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
|
@ -30,7 +32,7 @@ int main() {
|
|||
bool s = sbw_init();
|
||||
printf("%s\n", s ? "inited" : "failure");
|
||||
|
||||
uint8_t tdi = 0x0f, tdo = 0;
|
||||
/*uint8_t tdi = 0x0f, tdo = 0;
|
||||
sbw_sequence(8, true, &tdi, &tdo);
|
||||
printf("seq done, tdo=%02x\n", tdo);
|
||||
|
||||
|
@ -49,7 +51,14 @@ int main() {
|
|||
|
||||
printf("doing a tclk burst now!\n");
|
||||
sbw_tclk_burst(16);
|
||||
printf("done.\n");
|
||||
printf("done.\n");*/
|
||||
|
||||
sbw_tap_reset();
|
||||
sbw_check_fuse();
|
||||
|
||||
uint8_t id = sbw_tap_shift_ir(0xff/*IR_BYPASS*/);
|
||||
|
||||
printf("JTAG ID=%02x\n", id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -24,24 +24,50 @@ void sbw_preinit(void) {
|
|||
// TEST low for >0.025us <7us: latch on "we want SBW" signal
|
||||
// TEST high again for >1 us: ready to SBW
|
||||
|
||||
gpio_put(PINOUT_SBW_TCK , false);
|
||||
//gpio_put(PINOUT_SBW_TCK , false);
|
||||
gpio_put(PINOUT_SBW_TDIO, true );
|
||||
gpio_put(PINOUT_SBW_TDIO, false);
|
||||
gpio_set_dir(PINOUT_SBW_TCK , true);
|
||||
gpio_set_dir(PINOUT_SBW_TDIO, true);
|
||||
gpio_set_function(PINOUT_SBW_TCK , GPIO_FUNC_SIO);
|
||||
gpio_set_function(PINOUT_SBW_TDIO, GPIO_FUNC_SIO);
|
||||
|
||||
// TCK, TDIO now low
|
||||
busy_wait_us_32(150); // reset debug state while keeping CPU in reset
|
||||
/*// TCK, TDIO now low
|
||||
busy_wait_ms(4);//busy_wait_us_32(150); // reset debug state while keeping CPU in reset
|
||||
|
||||
gpio_put(PINOUT_SBW_TCK , true ); // we want a debugger
|
||||
busy_wait_us_32(1);
|
||||
gpio_put(PINOUT_SBW_TDIO, true ); // we want SBW
|
||||
busy_wait_us_32(1);
|
||||
busy_wait_ms(20);//busy_wait_us_32(1);
|
||||
gpio_put(PINOUT_SBW_TCK , false); // latch "we want SBW"
|
||||
busy_wait_us_32(3);
|
||||
gpio_put(PINOUT_SBW_TCK , true ); // start SBW stuff
|
||||
busy_wait_us_32(100); // wait a bit more
|
||||
busy_wait_ms(5);//busy_wait_us_32(100); // wait a bit more*/
|
||||
|
||||
gpio_put(PINOUT_SBW_TCK , false);
|
||||
gpio_put(PINOUT_SBW_TDIO, true);
|
||||
busy_wait_ms(4); // reset TEST logic
|
||||
gpio_put(PINOUT_SBW_TDIO, true);
|
||||
busy_wait_us_32(1);
|
||||
gpio_put(PINOUT_SBW_TCK , true);
|
||||
busy_wait_ms(20); // activate TEST logic
|
||||
|
||||
// "phase 1"
|
||||
gpio_put(PINOUT_SBW_TDIO, true);
|
||||
busy_wait_us_32(60);
|
||||
|
||||
// "phase 2"
|
||||
gpio_put(PINOUT_SBW_TCK , false);
|
||||
|
||||
// "phase 3"
|
||||
busy_wait_us_32(1);
|
||||
|
||||
// "phase 4"
|
||||
gpio_put(PINOUT_SBW_TCK , true);
|
||||
busy_wait_us_32(60);
|
||||
|
||||
// "phase 5"
|
||||
busy_wait_ms(5);
|
||||
}
|
||||
|
||||
int sbw_piosm = -1, sbw_offset = -1;
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
|
||||
#include "pio_sbw.h"
|
||||
|
||||
#include "tap.h"
|
||||
|
||||
// FIXME: TDI in run-test/idle ALWAYS TCLK value??
|
||||
|
||||
void sbw_tap_reset(void) {
|
||||
// TDI always 1
|
||||
// TMS=1,1,1,1,1,1 -- reset TAP state to initial
|
||||
// TMS=0 -- test-logic-reset to run-test/idle
|
||||
// TMS=1,0,1,0,1 -- perform fuse check
|
||||
// TMS=1,0 -- back to run-test/idle
|
||||
|
||||
//const uint16_t tms_seq = 0x1abf;//0x3f | (0<<6) | (0x15 << 7) | (0x1 << 12);
|
||||
const uint8_t tms_seq[2] = {0xbf,0x1a};
|
||||
sbw_tms_sequence(14, true, tms_seq);
|
||||
}
|
||||
|
||||
void sbw_check_fuse(void) {
|
||||
// TDI always 1
|
||||
// TMS=01010110
|
||||
const uint8_t tms_seq = 0x6a;
|
||||
sbw_tms_sequence(8, true, &tms_seq);
|
||||
}
|
||||
|
||||
static uint8_t bitswap(uint8_t in) {
|
||||
static const uint8_t lut[16] = {
|
||||
0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
|
||||
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
|
||||
};
|
||||
|
||||
return (lut[in&0xf] << 4) | lut[in>>4];
|
||||
}
|
||||
static inline uint16_t bitswap16(uint16_t in) {
|
||||
return ((uint16_t)bitswap(in & 0xff) << 8) | bitswap(in >> 8);
|
||||
}
|
||||
|
||||
uint16_t sbw_tap_shift_dr(uint16_t newdr) {
|
||||
// DR content is MSB-first instead of LSB-first (IR is the latter)
|
||||
// except the PIO already does bitswaps, so we need to do it for the IR instead
|
||||
newdr = /*bitswap16(*/newdr/*)*/;
|
||||
|
||||
// 100: run-test/idle -> select-dr-scan -> capture-dr -> shift-dr
|
||||
const uint8_t tms_seq = 0x01;
|
||||
sbw_tms_sequence(3, true, &tms_seq);
|
||||
|
||||
// 15 data bits with TMS=0
|
||||
// 1 data bit with TMS=1 (to exit1-dr)
|
||||
uint16_t res = 0;
|
||||
uint8_t newdr2 = newdr >> 15, resb = 0;
|
||||
sbw_sequence(15, false, (const uint8_t*)&newdr, (uint8_t*)&res); // FIXME: little-endian-only
|
||||
sbw_sequence( 1, true , &newdr2, &resb);
|
||||
res |= (uint16_t)resb << 15;
|
||||
|
||||
// TMS=1 (to update-dr)
|
||||
// TMS=0 (to run-test/idle)
|
||||
const uint8_t tms_seq_2 = 0x01;
|
||||
sbw_tms_sequence(2, true, &tms_seq_2);
|
||||
|
||||
return /*bitswap16(*/res/*)*/;
|
||||
}
|
||||
|
||||
uint8_t sbw_tap_shift_ir(uint8_t newir) {
|
||||
newir = bitswap(newir);
|
||||
|
||||
// 1100: run-test/idle -> select-dr-scan -> select-ir-scan -> capture-ir -> shift-ir
|
||||
const uint8_t tms_seq = 0x03;
|
||||
sbw_tms_sequence(4, true, &tms_seq);
|
||||
|
||||
// 7 data bits with TMS=0
|
||||
// 1 data bit with TMS=1 (to exit1-ir)
|
||||
uint8_t res = 0, resb = 0, newir2 = newir >> 7;
|
||||
sbw_sequence(7, false, &newir , &res );
|
||||
sbw_sequence(1, true , &newir2, &resb);
|
||||
res |= resb << 7;
|
||||
|
||||
// TMS=1 (to update-ir)
|
||||
// TMS=0 (to run-test/idle)
|
||||
const uint8_t tms_seq_2 = 0x01;
|
||||
sbw_tms_sequence(2, true, &tms_seq_2);
|
||||
|
||||
return bitswap(res);
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
#ifndef SBW_TAP_H_
|
||||
#define SBW_TAP_H_
|
||||
|
||||
// move to run-test/idle. typically this is done by sending a single TMS=0
|
||||
// cycle, but the MSP430 has an extra JTAG fuse check that needs to be done
|
||||
void sbw_tap_reset(void);
|
||||
// more fuse checking stuff
|
||||
void sbw_check_fuse(void);
|
||||
|
||||
// write IR contents. starts and ends in run-test/idle
|
||||
uint8_t sbw_tap_shift_ir(uint8_t newir);
|
||||
// read current IR contents. starts and ends in run-test/idle
|
||||
//uint8_t sbw_tap_read_ir(void);
|
||||
|
||||
// write DR contents. starts and ends in run-test/idle
|
||||
uint16_t sbw_tap_shift_dr(uint16_t newdr);
|
||||
// read current DR contents. starts and ends in run-test/idle
|
||||
static inline uint16_t sbw_tap_read_dr(void) { return sbw_tap_shift_dr(0x0000); }
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue