feat: add capture sketch, Vidor image tool and jitter analysis script

This commit is contained in:
randogoth 2026-10-25 12:30:12 +02:00
parent 0332d8eb33
commit d51a6c0ca8
20 changed files with 2085 additions and 0 deletions

View file

@ -0,0 +1,200 @@
/*
This file is part of the VidorBoot/VidorPeripherals/VidorGraphics library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
extern "C" {
#include "jtag_host.h"
}
#include <Arduino.h>
#include <SPI.h>
#define TMS 28 // PA14 | SERCOM2/ PAD[2]
#define TCK 27 // PA13 -> SPI CLK | SERCOM2/ PAD[1]
#define TDO 29 // PA15 -> MISO | SERCOM2/ PAD[3]
#define TDI 26 // PA12 -> MOSI | SERCOM2/ PAD[0]
#define TMS_HIGH() (digitalPinToPort(TMS)->OUTSET.reg = digitalPinToBitMask(TMS))
#define TMS_LOW() (digitalPinToPort(TMS)->OUTCLR.reg = digitalPinToBitMask(TMS))
#define TCK_HIGH() (digitalPinToPort(TCK)->OUTSET.reg = digitalPinToBitMask(TCK))
#define TCK_LOW() (digitalPinToPort(TCK)->OUTCLR.reg = digitalPinToBitMask(TCK))
#define TCK_PMUX() (digitalPinToPort(TCK)->PINCFG[g_APinDescription[TCK].ulPin].bit.PMUXEN = 1)
#define TCK_UNPMUX() (digitalPinToPort(TCK)->PINCFG[g_APinDescription[TCK].ulPin].bit.PMUXEN = 0)
#define TDI_HIGH() (digitalPinToPort(TDI)->OUTSET.reg = digitalPinToBitMask(TDI))
#define TDI_LOW() (digitalPinToPort(TDI)->OUTCLR.reg = digitalPinToBitMask(TDI))
#define TDI_PMUX() (digitalPinToPort(TDI)->PINCFG[g_APinDescription[TDI].ulPin].bit.PMUXEN = 1)
#define TDI_UNPMUX() (digitalPinToPort(TDI)->PINCFG[g_APinDescription[TDI].ulPin].bit.PMUXEN = 0)
#define TDO_PMUX() (digitalPinToPort(TDO)->PINCFG[g_APinDescription[TDO].ulPin].bit.PMUXEN = 1)
#define TDO_UNPMUX() (digitalPinToPort(TDO)->PINCFG[g_APinDescription[TDO].ulPin].bit.PMUXEN = 0)
#define TMS_WRITE(val) {if (val) { TMS_HIGH(); } else { TMS_LOW(); }}
#define TDI_WRITE(val) {if (val) { TDI_HIGH(); } else { TDI_LOW(); }}
#define TDO_READ() ((digitalPinToPort(TDO)->IN.reg & digitalPinToBitMask(TDO)) != 0)
#define SPI_JTAG SPI1
SPISettings JTAG_SPISettings(12000000, LSBFIRST, SPI_MODE0);
extern "C" {
int jtag_host_setup()
{
pinMode(TMS, OUTPUT);
pinMode(TCK, OUTPUT);
pinMode(TDO, INPUT);
pinMode(TDI, OUTPUT);
TMS_LOW();
TCK_LOW();
TDI_LOW();
SPI_JTAG.begin();
SPI_JTAG.beginTransaction(JTAG_SPISettings);
TCK_UNPMUX();
TDI_UNPMUX();
return 0;
}
int jtag_host_shutdown()
{
TMS_LOW();
TCK_LOW();
TDI_LOW();
pinMode(TMS, INPUT);
pinMode(TCK, INPUT);
pinMode(TDO, INPUT);
pinMode(TDI, INPUT);
return 0;
}
void jtag_host_pulse_tck(int tms)
{
TMS_WRITE(tms);
TCK_LOW();
TCK_HIGH();
}
int jtag_host_pulse_tdo_bit()
{
TDI_LOW();
TCK_LOW();
TCK_HIGH();
return TDO_READ();
}
unsigned int jtag_host_pulse_tdio_instruction(int bits, unsigned int out)
{
unsigned int in = 0;
for (int i = 0; i < bits; i++) {
TDI_WRITE(out & 1);
if (i != (bits - 1)) {
TCK_LOW();
TCK_HIGH();
in |= (TDO_READ() << i);
out >>= 1;
}
}
return in;
}
void jtag_host_pulse_tdi_instruction(int bits, unsigned int out)
{
for (int i = 0; i < bits; i++) {
TDI_WRITE(out & 1);
if (i != (bits - 1)) {
TCK_LOW();
TCK_HIGH();
out >>= 1;
}
}
}
unsigned int jtag_host_pulse_tdio(int bits, unsigned int out)
{
unsigned int in = 0;
for (int i = 0; i < bits; i++) {
TDI_WRITE(out & 1);
TCK_LOW();
TCK_HIGH();
in |= (TDO_READ() << i);
out >>= 1;
}
return in;
}
void jtag_host_pulse_tdi_0(int bits)
{
digitalWrite(TDI, LOW);
for (int i = 0; i < bits; i++) {
TCK_LOW();
TCK_HIGH();
}
}
void jtag_host_pulse_tdi(const uint8_t* data, size_t size)
{
TCK_LOW();
TCK_PMUX();
TDI_PMUX();
for (size_t i = 0; i < size; i++) {
SPI_JTAG.transfer(*data++);
}
TCK_UNPMUX();
TDI_UNPMUX();
}
void jtag_host_pulse_tdo(uint8_t* data, size_t size)
{
TCK_LOW();
TCK_PMUX();
TDO_PMUX();
for (size_t i = 0; i < size; i++) {
*data = SPI_JTAG.transfer(0x00);
data++;
}
TCK_UNPMUX();
TDO_UNPMUX();
}
}

View file

@ -0,0 +1,56 @@
/*
This file is part of the VidorBoot/VidorPeripherals/VidorGraphics library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __JTAG_HOST_H__
#define __JTAG_HOST_H__
#include <stddef.h>
#include <stdint.h>
// setups the JTAG host
extern int jtag_host_setup();
// shutdowns the JTAG host
extern int jtag_host_shutdown();
// set TMS to the value and pulses TCK
extern void jtag_host_pulse_tck(int tms);
// pulses TCK and returns value of TDO pin
extern int jtag_host_pulse_tdo_bit();
// pulses out an instrution of bits length, returns data pulsed in from TDO
extern unsigned int jtag_host_pulse_tdio_instruction(int bits, unsigned int out);
// pulses out an instrution of bits length
extern void jtag_host_pulse_tdi_instruction(int bits, unsigned int out);
// pulses out data to TDI of bits length, returns data pulsed in from TDO
extern unsigned int jtag_host_pulse_tdio(int bits, unsigned int out);
// pulses out bits 0's to TDI
extern void jtag_host_pulse_tdi_0(int bits);
// pulses out bytes to TDI
extern void jtag_host_pulse_tdi(const uint8_t* data, size_t size);
// pulses in bytes from TDO
extern void jtag_host_pulse_tdo(uint8_t* data, size_t size);
#endif

View file

@ -0,0 +1,168 @@
/*
* Lib(X)SVF - A library for implementing SVF and XSVF JTAG players
*
* Copyright (C) 2009 RIEGL Research ForschungsGmbH
* Copyright (C) 2009 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef LIBXSVF_H
#define LIBXSVF_H
#ifndef ARDUINO
enum libxsvf_mode {
LIBXSVF_MODE_SVF = 1,
LIBXSVF_MODE_XSVF = 2,
LIBXSVF_MODE_SCAN = 3
};
#endif
enum libxsvf_tap_state {
/* Special States */
LIBXSVF_TAP_INIT = 0,
LIBXSVF_TAP_RESET = 1,
LIBXSVF_TAP_IDLE = 2,
/* DR States */
LIBXSVF_TAP_DRSELECT = 3,
LIBXSVF_TAP_DRCAPTURE = 4,
LIBXSVF_TAP_DRSHIFT = 5,
LIBXSVF_TAP_DREXIT1 = 6,
LIBXSVF_TAP_DRPAUSE = 7,
LIBXSVF_TAP_DREXIT2 = 8,
LIBXSVF_TAP_DRUPDATE = 9,
/* IR States */
LIBXSVF_TAP_IRSELECT = 10,
LIBXSVF_TAP_IRCAPTURE = 11,
LIBXSVF_TAP_IRSHIFT = 12,
LIBXSVF_TAP_IREXIT1 = 13,
LIBXSVF_TAP_IRPAUSE = 14,
LIBXSVF_TAP_IREXIT2 = 15,
LIBXSVF_TAP_IRUPDATE = 16
};
#ifndef ARDUINO
enum libxsvf_mem {
LIBXSVF_MEM_XSVF_TDI_DATA = 0,
LIBXSVF_MEM_XSVF_TDO_DATA = 1,
LIBXSVF_MEM_XSVF_TDO_MASK = 2,
LIBXSVF_MEM_XSVF_ADDR_MASK = 3,
LIBXSVF_MEM_XSVF_DATA_MASK = 4,
LIBXSVF_MEM_SVF_COMMANDBUF = 5,
LIBXSVF_MEM_SVF_SDR_TDI_DATA = 6,
LIBXSVF_MEM_SVF_SDR_TDI_MASK = 7,
LIBXSVF_MEM_SVF_SDR_TDO_DATA = 8,
LIBXSVF_MEM_SVF_SDR_TDO_MASK = 9,
LIBXSVF_MEM_SVF_SDR_RET_MASK = 10,
LIBXSVF_MEM_SVF_SIR_TDI_DATA = 11,
LIBXSVF_MEM_SVF_SIR_TDI_MASK = 12,
LIBXSVF_MEM_SVF_SIR_TDO_DATA = 13,
LIBXSVF_MEM_SVF_SIR_TDO_MASK = 14,
LIBXSVF_MEM_SVF_SIR_RET_MASK = 15,
LIBXSVF_MEM_SVF_HDR_TDI_DATA = 16,
LIBXSVF_MEM_SVF_HDR_TDI_MASK = 17,
LIBXSVF_MEM_SVF_HDR_TDO_DATA = 18,
LIBXSVF_MEM_SVF_HDR_TDO_MASK = 19,
LIBXSVF_MEM_SVF_HDR_RET_MASK = 20,
LIBXSVF_MEM_SVF_HIR_TDI_DATA = 21,
LIBXSVF_MEM_SVF_HIR_TDI_MASK = 22,
LIBXSVF_MEM_SVF_HIR_TDO_DATA = 23,
LIBXSVF_MEM_SVF_HIR_TDO_MASK = 24,
LIBXSVF_MEM_SVF_HIR_RET_MASK = 25,
LIBXSVF_MEM_SVF_TDR_TDI_DATA = 26,
LIBXSVF_MEM_SVF_TDR_TDI_MASK = 27,
LIBXSVF_MEM_SVF_TDR_TDO_DATA = 28,
LIBXSVF_MEM_SVF_TDR_TDO_MASK = 29,
LIBXSVF_MEM_SVF_TDR_RET_MASK = 30,
LIBXSVF_MEM_SVF_TIR_TDI_DATA = 31,
LIBXSVF_MEM_SVF_TIR_TDI_MASK = 32,
LIBXSVF_MEM_SVF_TIR_TDO_DATA = 33,
LIBXSVF_MEM_SVF_TIR_TDO_MASK = 34,
LIBXSVF_MEM_SVF_TIR_RET_MASK = 35,
LIBXSVF_MEM_NUM = 36
};
#endif
struct libxsvf_host {
#ifndef ARDUINO
int (*setup)(struct libxsvf_host *h);
int (*shutdown)(struct libxsvf_host *h);
void (*udelay)(struct libxsvf_host *h, long usecs, int tms, long num_tck);
int (*getbyte)(struct libxsvf_host *h);
int (*sync)(struct libxsvf_host *h);
int (*pulse_tck)(struct libxsvf_host *h, int tms, int tdi, int tdo, int rmask, int sync);
void (*pulse_sck)(struct libxsvf_host *h);
void (*set_trst)(struct libxsvf_host *h, int v);
int (*set_frequency)(struct libxsvf_host *h, int v);
void (*report_tapstate)(struct libxsvf_host *h);
void (*report_device)(struct libxsvf_host *h, unsigned long idcode);
void (*report_status)(struct libxsvf_host *h, const char *message);
void (*report_error)(struct libxsvf_host *h, const char *file, int line, const char *message);
void *(*realloc)(struct libxsvf_host *h, void *ptr, int size, enum libxsvf_mem which);
#endif
enum libxsvf_tap_state tap_state;
#ifndef ARDUINO
void *user_data;
#endif
};
#ifndef ARDUINO
int libxsvf_play(struct libxsvf_host *, enum libxsvf_mode mode);
const char *libxsvf_state2str(enum libxsvf_tap_state tap_state);
const char *libxsvf_mem2str(enum libxsvf_mem which);
/* Internal API */
int libxsvf_svf(struct libxsvf_host *h);
int libxsvf_xsvf(struct libxsvf_host *h);
int libxsvf_scan(struct libxsvf_host *h);
#endif
int libxsvf_tap_walk(struct libxsvf_host *, enum libxsvf_tap_state);
/* Host accessor macros (see README) */
#ifdef ARDUINO
#ifdef __cplusplus
extern "C"{
#endif // __cplusplus
extern int jtag_host_setup();
extern int jtag_host_shutdown();
extern void jtag_host_pulse_tck(int tms);
#ifdef __cplusplus
};
#endif // __cplusplus
#define LIBXSVF_HOST_SETUP() jtag_host_setup()
#define LIBXSVF_HOST_SHUTDOWN() jtag_host_shutdown()
#define LIBXSVF_HOST_PULSE_TCK(_tms, _tdi, _tdo, _rmask, _sync) { (void)h; jtag_host_pulse_tck(_tms); }
#define LIBXSVF_HOST_REPORT_TAPSTATE()
#define LIBXSVF_HOST_REPORT_ERROR(_msg)
#else
#define LIBXSVF_HOST_SETUP() h->setup(h)
#define LIBXSVF_HOST_SHUTDOWN() h->shutdown(h)
#define LIBXSVF_HOST_UDELAY(_usecs, _tms, _num_tck) h->udelay(h, _usecs, _tms, _num_tck)
#define LIBXSVF_HOST_GETBYTE() h->getbyte(h)
#define LIBXSVF_HOST_SYNC() (h->sync ? h->sync(h) : 0)
#define LIBXSVF_HOST_PULSE_TCK(_tms, _tdi, _tdo, _rmask, _sync) h->pulse_tck(h, _tms, _tdi, _tdo, _rmask, _sync)
#define LIBXSVF_HOST_PULSE_SCK() do { if (h->pulse_sck) h->pulse_sck(h); } while (0)
#define LIBXSVF_HOST_SET_TRST(_v) do { if (h->set_trst) h->set_trst(h, _v); } while (0)
#define LIBXSVF_HOST_SET_FREQUENCY(_v) (h->set_frequency ? h->set_frequency(h, _v) : -1)
#define LIBXSVF_HOST_REPORT_TAPSTATE() do { if (h->report_tapstate) h->report_tapstate(h); } while (0)
#define LIBXSVF_HOST_REPORT_DEVICE(_v) do { if (h->report_device) h->report_device(h, _v); } while (0)
#define LIBXSVF_HOST_REPORT_STATUS(_msg) do { if (h->report_status) h->report_status(h, _msg); } while (0)
#define LIBXSVF_HOST_REPORT_ERROR(_msg) h->report_error(h, __FILE__, __LINE__, _msg)
#define LIBXSVF_HOST_REALLOC(_ptr, _size, _which) h->realloc(h, _ptr, _size, _which)
#endif
#endif

View file

@ -0,0 +1,175 @@
/*
* Lib(X)SVF - A library for implementing SVF and XSVF JTAG players
*
* Copyright (C) 2009 RIEGL Research ForschungsGmbH
* Copyright (C) 2009 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "libxsvf.h"
static void tap_transition(struct libxsvf_host *h, int v)
{
LIBXSVF_HOST_PULSE_TCK(v, -1, -1, 0, 0);
}
int libxsvf_tap_walk(struct libxsvf_host *h, enum libxsvf_tap_state s)
{
int i, j;
for (i=0; s != h->tap_state; i++)
{
switch (h->tap_state)
{
/* Special States */
case LIBXSVF_TAP_INIT:
for (j = 0; j < 6; j++)
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_RESET;
break;
case LIBXSVF_TAP_RESET:
tap_transition(h, 0);
h->tap_state = LIBXSVF_TAP_IDLE;
break;
case LIBXSVF_TAP_IDLE:
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_DRSELECT;
break;
/* DR States */
case LIBXSVF_TAP_DRSELECT:
if (s >= LIBXSVF_TAP_IRSELECT || s == LIBXSVF_TAP_RESET) {
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_IRSELECT;
} else {
tap_transition(h, 0);
h->tap_state = LIBXSVF_TAP_DRCAPTURE;
}
break;
case LIBXSVF_TAP_DRCAPTURE:
if (s == LIBXSVF_TAP_DRSHIFT) {
tap_transition(h, 0);
h->tap_state = LIBXSVF_TAP_DRSHIFT;
} else {
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_DREXIT1;
}
break;
case LIBXSVF_TAP_DRSHIFT:
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_DREXIT1;
break;
case LIBXSVF_TAP_DREXIT1:
if (s == LIBXSVF_TAP_DRPAUSE) {
tap_transition(h, 0);
h->tap_state = LIBXSVF_TAP_DRPAUSE;
} else {
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_DRUPDATE;
}
break;
case LIBXSVF_TAP_DRPAUSE:
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_DREXIT2;
break;
case LIBXSVF_TAP_DREXIT2:
if (s == LIBXSVF_TAP_DRSHIFT) {
tap_transition(h, 0);
h->tap_state = LIBXSVF_TAP_DRSHIFT;
} else {
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_DRUPDATE;
}
break;
case LIBXSVF_TAP_DRUPDATE:
if (s == LIBXSVF_TAP_IDLE) {
tap_transition(h, 0);
h->tap_state = LIBXSVF_TAP_IDLE;
} else {
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_DRSELECT;
}
break;
/* IR States */
case LIBXSVF_TAP_IRSELECT:
if (s == LIBXSVF_TAP_RESET) {
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_RESET;
} else {
tap_transition(h, 0);
h->tap_state = LIBXSVF_TAP_IRCAPTURE;
}
break;
case LIBXSVF_TAP_IRCAPTURE:
if (s == LIBXSVF_TAP_IRSHIFT) {
tap_transition(h, 0);
h->tap_state = LIBXSVF_TAP_IRSHIFT;
} else {
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_IREXIT1;
}
break;
case LIBXSVF_TAP_IRSHIFT:
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_IREXIT1;
break;
case LIBXSVF_TAP_IREXIT1:
if (s == LIBXSVF_TAP_IRPAUSE) {
tap_transition(h, 0);
h->tap_state = LIBXSVF_TAP_IRPAUSE;
} else {
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_IRUPDATE;
}
break;
case LIBXSVF_TAP_IRPAUSE:
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_IREXIT2;
break;
case LIBXSVF_TAP_IREXIT2:
if (s == LIBXSVF_TAP_IRSHIFT) {
tap_transition(h, 0);
h->tap_state = LIBXSVF_TAP_IRSHIFT;
} else {
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_IRUPDATE;
}
break;
case LIBXSVF_TAP_IRUPDATE:
if (s == LIBXSVF_TAP_IDLE) {
tap_transition(h, 0);
h->tap_state = LIBXSVF_TAP_IDLE;
} else {
tap_transition(h, 1);
h->tap_state = LIBXSVF_TAP_DRSELECT;
}
break;
default:
LIBXSVF_HOST_REPORT_ERROR("Illegal tap state.");
return -1;
}
#ifndef ARDUINO
if (h->report_tapstate)
LIBXSVF_HOST_REPORT_TAPSTATE();
#endif
if (i>10) {
LIBXSVF_HOST_REPORT_ERROR("Loop in tap walker.");
return -1;
}
}
return 0;
}