SWD PIO works now, too!
This commit is contained in:
parent
9aeaea5d9f
commit
b461946751
|
@ -92,7 +92,7 @@ __WEAK void SWJ_Sequence (uint32_t count, const uint8_t *data) {
|
|||
// swdi: pointer to SWDIO captured data
|
||||
// return: none
|
||||
#if (DAP_SWD != 0)
|
||||
void SWD_Sequence (uint32_t info, const uint8_t *swdo, uint8_t *swdi) {
|
||||
__WEAK void SWD_Sequence (uint32_t info, const uint8_t *swdo, uint8_t *swdi) {
|
||||
uint32_t val;
|
||||
uint32_t bit;
|
||||
uint32_t n, k;
|
||||
|
|
|
@ -137,6 +137,7 @@ if(FAMILY STREQUAL "rp2040")
|
|||
endif()
|
||||
|
||||
pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/dap_jtag.pio)
|
||||
pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/dap_swd.pio)
|
||||
pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/swo_uart_rx.pio)
|
||||
pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/swo_manchester_encoding.pio)
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
The BSD-3-Clause license applies to portions of the following files, which have
|
||||
been modified from their original versions in <https://github.com/raspberrypi/pico-examples/>
|
||||
(the "Pico examples repository")
|
||||
|
||||
- bsp/rp2040/m_default/swo_manchester_encoding.pio
|
||||
- bsp/rp2040/m_default/swo_uart_rx.pio
|
||||
|
||||
The below notice does not apply to any modifications made to the above files
|
||||
since the versions present in the Pico examples repository, nor to any files
|
||||
not present in the Pico exmaples repository.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
11
README.md
11
README.md
|
@ -71,15 +71,17 @@ libco is licensed under the [ISC license](https://opensource.org/licenses/ISC).
|
|||
|
||||
Some code has been incorporated from the [DapperMime](https://github.com/majbthrd/DapperMime),
|
||||
[picoprobe-sump](https://github.com/perexg/picoprobe-sump),
|
||||
[JTAGenum](https://github.com/cyphunk/JTAGenum) and
|
||||
[SWDscan](https://github.com/szymonh/SWDscan)
|
||||
[JTAGenum](https://github.com/cyphunk/JTAGenum),
|
||||
[SWDscan](https://github.com/szymonh/SWDscan) and the [Raspberry Pico
|
||||
examples](https://github.com/raspberrypi/pico-examples/)
|
||||
projects. These respective licenses can be found in
|
||||
[this](./LICENSE.dappermime), [this](./LICENSE.picoprobe-sump),
|
||||
[this](./LICENSE.jtagenum) and [this](./LICENSE.swdscan) file.
|
||||
[this](./LICENSE.jtagenum), [this](./LICENSE.swdscan) and
|
||||
[this](./LICENSE.pico-examples) file.
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] **A (VID and) PID, and maybe better subclass & protocol IDs for the vnd cfg itf**
|
||||
- [ ] **A (VID and) PID**
|
||||
- [ ] GPL license headers on every file
|
||||
- [x] Debug interface to send printf stuff directly to USB, instead of having
|
||||
to use the UART interface as a loopback thing.
|
||||
|
@ -98,7 +100,6 @@ projects. These respective licenses can be found in
|
|||
- interface 1 ("B"): index 2, epin 0x04, epout 0x83
|
||||
- interface 2 ("C"): index 3, epin 0x06, epout 0x85
|
||||
- interface 3 ("D"): index 4, epin 0x08, epout 0x87
|
||||
- ~~or, FX2 emulation mode??? (useful links: https://sigrok.org/wiki/Fx2lafw ; https://sigrok.org/wiki/CWAV_USBee_SX/Info )~~ has a ROM/fw and everything, so, maybe not
|
||||
- [ ] "Complex Trigger" mode for aiding with glitching triggers, by turning
|
||||
UART/SPI/I2C/eMMC/... sequences into a GPIO toggle
|
||||
- [ ] Mode where you can define custom PIO stuff for custom pinouts/protocols??????
|
||||
|
|
|
@ -440,13 +440,15 @@ __STATIC_FORCEINLINE void PIN_SWDIO_OUT(uint32_t bit) {
|
|||
Configure the SWDIO DAP hardware I/O pin to output mode. This function is
|
||||
called prior \ref PIN_SWDIO_OUT function calls.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PIN_SWDIO_OUT_ENABLE(void) { sio_hw->gpio_oe_set = PINOUT_SWDIO_MASK; }
|
||||
//__STATIC_FORCEINLINE void PIN_SWDIO_OUT_ENABLE(void) { sio_hw->gpio_oe_set = PINOUT_SWDIO_MASK; }
|
||||
void PIN_SWDIO_OUT_ENABLE(void);
|
||||
|
||||
/** SWDIO I/O pin: Switch to Input mode (used in SWD mode only).
|
||||
Configure the SWDIO DAP hardware I/O pin to input mode. This function is
|
||||
called prior \ref PIN_SWDIO_IN function calls.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PIN_SWDIO_OUT_DISABLE(void) { sio_hw->gpio_oe_clr = PINOUT_SWDIO_MASK; }
|
||||
//__STATIC_FORCEINLINE void PIN_SWDIO_OUT_DISABLE(void) { sio_hw->gpio_oe_clr = PINOUT_SWDIO_MASK; }
|
||||
void PIN_SWDIO_OUT_DISABLE(void);
|
||||
|
||||
// TDI Pin I/O ---------------------------------------------
|
||||
|
||||
|
@ -636,5 +638,7 @@ __STATIC_INLINE uint8_t RESET_TARGET(void) {
|
|||
|
||||
///@}
|
||||
|
||||
extern int swdsm, swdoffset, jtagsm, jtagoffset;
|
||||
|
||||
#endif /* __DAP_CONFIG_H__ */
|
||||
|
||||
|
|
|
@ -7,10 +7,8 @@
|
|||
#include "DAP_config.h"
|
||||
#include <DAP.h>
|
||||
|
||||
#include "tusb_config.h"
|
||||
#include <tusb.h>
|
||||
|
||||
#include "dap_jtag.pio.h"
|
||||
#include "dap_swd.pio.h"
|
||||
|
||||
#define JTAG_PIO
|
||||
|
||||
|
@ -103,7 +101,7 @@ void JTAG_Sequence(uint32_t info, const uint8_t* tdi, uint8_t* tdo) {
|
|||
} else printf("%s", "\nno tdo\n");
|
||||
}
|
||||
#else
|
||||
static int jtagsm = -1, offset = -1;
|
||||
int jtagsm = -1, jtagoffset = -1;
|
||||
|
||||
void PORT_JTAG_SETUP(void) {
|
||||
resets_hw->reset &= ~(RESETS_RESET_IO_BANK0_BITS | RESETS_RESET_PADS_BANK0_BITS);
|
||||
|
@ -145,17 +143,28 @@ void PORT_JTAG_SETUP(void) {
|
|||
iobank0_hw->io[PINOUT_JTAG_nTRST].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
|
||||
iobank0_hw->io[PINOUT_JTAG_nRESET].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
|
||||
|
||||
jtagsm = pio_claim_unused_sm(PINOUT_JTAG_PIO_DEV, true);
|
||||
offset = pio_add_program(PINOUT_JTAG_PIO_DEV, &dap_jtag_program);
|
||||
dap_jtag_program_init(PINOUT_JTAG_PIO_DEV, jtagsm, offset,
|
||||
if (jtagsm == -1) jtagsm = pio_claim_unused_sm(PINOUT_JTAG_PIO_DEV, true);
|
||||
if (jtagoffset == -1)
|
||||
jtagoffset = pio_add_program(PINOUT_JTAG_PIO_DEV, &dap_jtag_program);
|
||||
dap_jtag_program_init(PINOUT_JTAG_PIO_DEV, jtagsm, jtagoffset,
|
||||
50*1000, PINOUT_JTAG_TCK, PINOUT_JTAG_TDI, PINOUT_JTAG_TDO);
|
||||
}
|
||||
|
||||
void PORT_OFF(void) {
|
||||
if (jtagsm) {
|
||||
pio_sm_set_enabled(PINOUT_JTAG_PIO_DEV, jtagsm, false);
|
||||
pio_sm_unclaim(PINOUT_JTAG_PIO_DEV, jtagsm);
|
||||
pio_remove_program(PINOUT_JTAG_PIO_DEV, &dap_jtag_program, offset);
|
||||
offset = jtagsm = -1;
|
||||
}
|
||||
if (jtagoffset)
|
||||
pio_remove_program(PINOUT_JTAG_PIO_DEV, &dap_jtag_program, jtagoffset);
|
||||
jtagoffset = jtagsm = -1;
|
||||
|
||||
if (swdsm) {
|
||||
pio_sm_set_enabled(PINOUT_JTAG_PIO_DEV, swdsm, false);
|
||||
pio_sm_unclaim(PINOUT_JTAG_PIO_DEV, swdsm);
|
||||
}
|
||||
if (swdoffset)
|
||||
pio_remove_program(PINOUT_JTAG_PIO_DEV, &dap_swd_program, swdoffset);
|
||||
|
||||
sio_hw->gpio_oe_clr = PINOUT_SWCLK_MASK | PINOUT_SWDIO_MASK |
|
||||
PINOUT_TDI_MASK //| PINOUT_TDO_MASK
|
||||
|
@ -201,10 +210,9 @@ void JTAG_Sequence(uint32_t info, const uint8_t* tdi, uint8_t* tdo) {
|
|||
}
|
||||
printf("%c", '\n');*/
|
||||
|
||||
PINOUT_JTAG_PIO_DEV->txf[jtagsm] = (uint8_t)(n - 1);
|
||||
pio_sm_put_blocking(PINOUT_JTAG_PIO_DEV, jtagsm, (uint8_t)(n - 1));
|
||||
|
||||
size_t oi = 0, ii = 0;
|
||||
while (txremain || rxremain) {
|
||||
for (size_t oi = 0, ii = 0; txremain || rxremain; tight_loop_contents()) {
|
||||
if (txremain && !pio_sm_is_tx_fifo_full(PINOUT_JTAG_PIO_DEV, jtagsm)) {
|
||||
*tx = bitswap(tdi[ii]);
|
||||
--txremain;
|
||||
|
@ -243,23 +251,29 @@ static void jtag_seq(uint32_t num, int tms, const void* tdi, void* tdo) {
|
|||
static uint64_t last_bit = ~(uint64_t)0;
|
||||
uint64_t devnull = 0;
|
||||
|
||||
bool notdi, notdo;
|
||||
bool notdi = tdi == NULL, notdo = tdo == NULL;
|
||||
|
||||
if ((notdi = (tdi == NULL))) tdi = &last_bit;
|
||||
if ((notdo = (tdo == NULL))) tdo = &devnull;
|
||||
else tms |= JTAG_SEQUENCE_TDO;
|
||||
if (!notdo) tms |= JTAG_SEQUENCE_TDO;
|
||||
|
||||
const void* jdi;
|
||||
void* jdo;
|
||||
|
||||
uint32_t nreal;
|
||||
for (uint32_t i = 0; i < num; i += nreal) {
|
||||
uint32_t nmod = (num - i) & 63;
|
||||
nreal = nmod ? nmod : 64;
|
||||
|
||||
JTAG_Sequence(nmod | tms, (const uint8_t*)tdi + (i >> 3), (uint8_t*)tdo + (i >> 3));
|
||||
jdi = notdi ? (const void*)&last_bit : ((const uint8_t*)tdi + (i >> 3));
|
||||
jdo = notdo ? ( void*)&devnull : (( uint8_t*)tdo + (i >> 3));
|
||||
|
||||
JTAG_Sequence(nmod | tms, jdi, jdo);
|
||||
}
|
||||
|
||||
uint8_t lastbyte = *((const uint8_t*)tdi + (num >> 3));
|
||||
if (tdi) {
|
||||
uint8_t lastbyte = *((const uint8_t*)tdi + (((num + 7) >> 3)) - 1);
|
||||
last_bit = (lastbyte & (1 << (num & 7))) ? ~(uint64_t)0 : (uint64_t)0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t JTAG_ReadIDCode(void) {
|
||||
// tdi=NULL: ~~0xff!~~ repeat last-seen bit, ignore otherwise
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
; vim: set et:
|
||||
|
||||
; code mostly from https://github.com/phdussud/pico-dirtyJtag/blob/master/jtag.pio
|
||||
; which doesn't have a license...
|
||||
|
||||
.program dap_jtag
|
||||
.side_set 1 opt
|
||||
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
// vim: set et:
|
||||
|
||||
#include <hardware/clocks.h>
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/pio.h>
|
||||
#include <hardware/timer.h>
|
||||
|
||||
#include "DAP_config.h"
|
||||
#include <DAP.h>
|
||||
|
||||
/*#define SWD_PIO*/
|
||||
#include "dap_swd.pio.h"
|
||||
|
||||
#define SWD_PIO
|
||||
|
||||
#ifndef SWD_PIO
|
||||
void PORT_SWD_SETUP(void) {
|
||||
|
@ -20,16 +27,177 @@ void PORT_SWD_SETUP(void) {
|
|||
iobank0_hw->io[PINOUT_SWCLK].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
|
||||
iobank0_hw->io[PINOUT_SWDIO].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
|
||||
}
|
||||
#else
|
||||
void PORT_SWD_SETUP(void) {
|
||||
// TODO...
|
||||
|
||||
void PIN_SWDIO_OUT_ENABLE(void) {
|
||||
sio_hw->gpio_oe_set = PINOUT_SWDIO_MASK;
|
||||
}
|
||||
void PIN_SWDIO_OUT_DISABLE(void) {
|
||||
sio_hw->gpio_oe_clr = PINOUT_SWDIO_MASK;
|
||||
}
|
||||
|
||||
inline static void PIN_SWDIO_SET_PIO(void) { PIN_SWDIO_TMS_SET(); }
|
||||
#else
|
||||
//#error "no"
|
||||
int swdsm = -1, swdoffset = -1;
|
||||
|
||||
void PORT_SWD_SETUP(void) {
|
||||
resets_hw->reset &= ~(RESETS_RESET_IO_BANK0_BITS | RESETS_RESET_PADS_BANK0_BITS);
|
||||
|
||||
/* set to default high level */
|
||||
sio_hw->gpio_oe_set = PINOUT_SWCLK_MASK | PINOUT_SWDIO_MASK;
|
||||
sio_hw->gpio_set = PINOUT_SWCLK_MASK | PINOUT_SWDIO_MASK;
|
||||
|
||||
hw_write_masked(&padsbank0_hw->io[PINOUT_SWCLK], PADS_BANK0_GPIO0_IE_BITS,
|
||||
PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS);
|
||||
hw_write_masked(&padsbank0_hw->io[PINOUT_SWDIO], PADS_BANK0_GPIO0_IE_BITS,
|
||||
PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS);
|
||||
iobank0_hw->io[PINOUT_SWCLK].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
|
||||
iobank0_hw->io[PINOUT_SWDIO].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
|
||||
|
||||
if (swdsm == -1) swdsm = pio_claim_unused_sm(PINOUT_JTAG_PIO_DEV, true);
|
||||
if (swdoffset == -1)
|
||||
swdoffset = pio_add_program(PINOUT_JTAG_PIO_DEV, &dap_swd_program);
|
||||
dap_swd_program_init(PINOUT_JTAG_PIO_DEV, swdsm, swdoffset,
|
||||
50*1000, PINOUT_SWCLK, PINOUT_SWDIO);
|
||||
}
|
||||
|
||||
// TODO: also hijack PIN_SWDIO_OUT_{DIS,EN}ABLE ! (used in DAP_SWD_Sequence)
|
||||
// TODO: also hijack DAP_SWJ_PINS(?: should data pins be controlled like that? only rst stuff tbh)
|
||||
|
||||
void PIN_SWDIO_OUT_ENABLE(void) {
|
||||
pio_sm_set_pindirs_with_mask(PINOUT_JTAG_PIO_DEV, swdsm,
|
||||
(1u << PINOUT_SWDIO), (1u << PINOUT_SWDIO));
|
||||
}
|
||||
void PIN_SWDIO_OUT_DISABLE(void) {
|
||||
pio_sm_set_pindirs_with_mask(PINOUT_JTAG_PIO_DEV, swdsm,
|
||||
(0u << PINOUT_SWDIO), (1u << PINOUT_SWDIO));
|
||||
}
|
||||
|
||||
inline static void PIN_SWDIO_SET_PIO(void) {
|
||||
pio_sm_set_pins_with_mask(PINOUT_JTAG_PIO_DEV, swdsm,
|
||||
(1u << PINOUT_SWDIO), (1u << PINOUT_SWDIO));
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
void SWD_Sequence(uint32_t info, const uint8_t* swdo, uint8_t* swdi) {
|
||||
pio_sm_set_enabled(PINOUT_JTAG_PIO_DEV, swdsm, true);
|
||||
//busy_wait_us_32(0);
|
||||
|
||||
float div = (float)clock_get_hz(clk_sys) / (2 * DAP_Data.clock_freq);
|
||||
if (div < 2) div = 2;
|
||||
else if (div > 65536) div = 65536;
|
||||
pio_sm_set_clkdiv(PINOUT_JTAG_PIO_DEV, swdsm, div);
|
||||
|
||||
uint32_t n = info & SWD_SEQUENCE_CLK;
|
||||
if (n == 0) n = 64;
|
||||
|
||||
io_wo_8* tx = (io_wo_8*)&PINOUT_JTAG_PIO_DEV->txf[swdsm];
|
||||
io_ro_8* rx = (io_ro_8*)&PINOUT_JTAG_PIO_DEV->rxf[swdsm];
|
||||
|
||||
uint32_t bytelen = (n + 7) >> 3;
|
||||
uint32_t last_shift = (8 - n) & 7;
|
||||
uint32_t txremain = bytelen,
|
||||
rxremain = last_shift ? bytelen : (bytelen + 1);
|
||||
|
||||
/*printf("seq start n=%lu bytelen=%lu lsh=%lu txr=%lu rxr=%lu\n",
|
||||
n, bytelen, last_shift, txremain, rxremain);*/
|
||||
|
||||
pio_sm_put_blocking(PINOUT_JTAG_PIO_DEV, swdsm,
|
||||
(uint8_t)(n - 1) | ((info & SWD_SEQUENCE_DIN) ? 0x80000000u : 0));
|
||||
|
||||
if (info & SWD_SEQUENCE_DIN) {
|
||||
for (size_t i = 0; rxremain; tight_loop_contents()) {
|
||||
if (!pio_sm_is_rx_fifo_empty(PINOUT_JTAG_PIO_DEV, swdsm)) {
|
||||
uint8_t v = *rx;
|
||||
--rxremain;
|
||||
//printf("seq din rx %02x rxr=%lu\n", bitswap(v), rxremain);
|
||||
if (i < bytelen) {
|
||||
if (last_shift && i == bytelen - 1) {
|
||||
swdi[i] = bitswap(v) >> last_shift;
|
||||
} else {
|
||||
swdi[i] = bitswap(v);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; txremain; tight_loop_contents()) {
|
||||
if (!pio_sm_is_tx_fifo_full(PINOUT_JTAG_PIO_DEV, swdsm)) {
|
||||
*tx = bitswap(swdo[i]);
|
||||
--txremain;
|
||||
//printf("seq dout tx %02x txr=%lu\n", swdo[i], txremain);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// wait until FIFO empty, so that all bytes have been xmitted
|
||||
//while (!pio_sm_is_tx_fifo_empty(PINOUT_JTAG_PIO_DEV, swdsm)) tight_loop_contents();
|
||||
// ^ isn't enough, because of the side-set, so we need the loop below
|
||||
|
||||
// wait until last bit xmitted, and back at the starting insn
|
||||
while (pio_sm_get_pc(PINOUT_JTAG_PIO_DEV, swdsm) != swdoffset) tight_loop_contents();
|
||||
}
|
||||
|
||||
// we need to disable (and reenable at the start of this routine) the SM
|
||||
// because we also use it to set the SWDIO pin and direction elsewhere,
|
||||
// which shouldn't happen when the SM is enabled
|
||||
//busy_wait_us_32(0);
|
||||
pio_sm_set_enabled(PINOUT_JTAG_PIO_DEV, swdsm, false);
|
||||
|
||||
//printf("seq done, disabled\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
void swd_seq(uint32_t count, uint32_t flags, const uint8_t* swdo, uint8_t* swdi) {
|
||||
static uint64_t last_bit = ~(uint64_t)0;
|
||||
uint64_t devnull = 0;
|
||||
|
||||
if ( (flags & SWD_SEQUENCE_DIN) && !swdi) swdi = (uint8_t*)&devnull;
|
||||
if (!(flags & SWD_SEQUENCE_DIN) && !swdo) swdo = (const uint8_t*)&last_bit;
|
||||
|
||||
if (flags & SWD_SEQUENCE_DIN) {
|
||||
PIN_SWDIO_OUT_DISABLE();
|
||||
} else {
|
||||
PIN_SWDIO_OUT_ENABLE();
|
||||
}
|
||||
|
||||
const uint8_t* sdo = NULL;
|
||||
uint8_t* sdi = NULL;
|
||||
|
||||
uint32_t nreal;
|
||||
for (uint32_t i = 0; i < count; i += nreal) {
|
||||
uint32_t nmod = (count - i) & 63;
|
||||
nreal = nmod ? nmod : 64;
|
||||
|
||||
if (flags & SWD_SEQUENCE_DIN) {
|
||||
sdi = swdi ? &swdi[i >> 3] : ( uint8_t*)&devnull ;
|
||||
sdo = NULL;
|
||||
} else {
|
||||
sdo = swdo ? &swdo[i >> 3] : (const uint8_t*)&last_bit;
|
||||
sdi = NULL;
|
||||
}
|
||||
|
||||
SWD_Sequence(nmod | flags, sdo, sdi);
|
||||
}
|
||||
|
||||
if (!(flags & SWD_SEQUENCE_DIN) && swdo) {
|
||||
uint8_t lastbyte = swdo[((count + 7) >> 3) - 1];
|
||||
last_bit = (lastbyte & (1 << (count & 7))) ? ~(uint64_t)0 : (uint64_t)0;
|
||||
}
|
||||
}
|
||||
|
||||
void SWJ_Sequence(uint32_t count, const uint8_t* data) {
|
||||
for (uint32_t i = 0, k = 0; i < count; ++i) {
|
||||
swd_seq(count, 0, data, NULL);
|
||||
|
||||
/*for (uint32_t i = 0, k = 0; i < count; ++i) {
|
||||
if ((i & 7) == 0) {
|
||||
val = data[k];
|
||||
++k;
|
||||
|
@ -38,187 +206,90 @@ void SWJ_Sequence(uint32_t count, const uint8_t* data) {
|
|||
swdio = (val >> (i & 7)) & 1;
|
||||
// SET SWDIO
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void SWD_Sequence(uint32_t info, const uint8_t* swdo, uint8_t* swdi) {
|
||||
uint32_t n = info & SWD_SEQUENCE_CLK;
|
||||
if (n == 0) n = 64;
|
||||
uint8_t SWD_Transfer(uint32_t request, uint32_t* data) {
|
||||
uint32_t parity;
|
||||
uint8_t swdo;
|
||||
|
||||
if (info & SWD_SEQUENCE_DIN) {
|
||||
for (uint32_t i = 0; i < n; ) {
|
||||
uint32_t v = 0;
|
||||
for (uint32_t k = 0; k < 8; ++k, ++i) {
|
||||
// SWCLK LO; DELAY
|
||||
// GET SWDIO; SWCLK HI; DELAY
|
||||
val |= swdio << k;
|
||||
}
|
||||
swdi[i >> 3] = v;
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0; i < n; ) {
|
||||
uint32_t val = swdo[i >> 3];
|
||||
for (uint32_t k = 0; k < 8; ++i, ++k) {
|
||||
swdio = (val >> k) & 1;
|
||||
// SET SWDIO
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parity = ((request >> 0) & 1) + ((request >> 1) & 1)
|
||||
+ ((request >> 2) & 1) + ((request >> 3) & 1);
|
||||
swdo = 1 | ((request & 0xf) << 1) | ((parity & 1) << 5) | (0<<6) | (1<<7);
|
||||
swd_seq(8, 0, &swdo, NULL);
|
||||
|
||||
void SWD_Transfer(uint32_t request, uint32_t* data) {
|
||||
// TODO: to SWD_Sequence stuff(?)
|
||||
swd_seq(DAP_Data.swd_conf.turnaround, SWD_SEQUENCE_DIN, NULL, NULL);
|
||||
|
||||
uint32_t parity = 0;
|
||||
|
||||
swdio = 1;
|
||||
parity += swdio;
|
||||
// SET SWDIO
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
swdio = (request >> 0) & 1;
|
||||
parity += swdio;
|
||||
// SET SWDIO
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
swdio = (request >> 1) & 1;
|
||||
parity += swdio;
|
||||
// SET SWDIO
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
swdio = (request >> 2) & 1;
|
||||
parity += swdio;
|
||||
// SET SWDIO
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
swdio = (request >> 3) & 1;
|
||||
parity += swdio;
|
||||
// SET SWDIO
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
|
||||
swdio = parity & 1;
|
||||
// SET SWDIO
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
|
||||
swdio = 0;
|
||||
// SET SWDIO
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
|
||||
swdio = 1;
|
||||
// SET SWDIO
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
|
||||
// TODO: SWDIO is now input
|
||||
|
||||
for (size_t i = 0; i < DAP_Data.swd_conf.turnaround; ++i) {
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
}
|
||||
|
||||
uint32_t ack = 0;
|
||||
|
||||
// SWCLK LO; DELAY
|
||||
// GET SWDIO; SWCLK HI; DELAY
|
||||
ack |= swdio << 0;
|
||||
// SWCLK LO; DELAY
|
||||
// GET SWDIO; SWCLK HI; DELAY
|
||||
ack |= swdio << 1;
|
||||
// SWCLK LO; DELAY
|
||||
// GET SWDIO; SWCLK HI; DELAY
|
||||
ack |= swdio << 2;
|
||||
uint8_t ack = 0;
|
||||
swd_seq(3, SWD_SEQUENCE_DIN, NULL, &ack);
|
||||
|
||||
uint32_t num;
|
||||
switch (ack) {
|
||||
case DAP_TRANSFER_OK:
|
||||
if (request & DAP_TRANSFER_RnW) { // read
|
||||
uint32_t val = 0;
|
||||
if (request & DAP_TRANSFER_RnW) {
|
||||
uint64_t val = 0;
|
||||
parity = 0;
|
||||
// FIXME: this is little-endian-only!
|
||||
swd_seq(32, SWD_SEQUENCE_DIN, NULL, (uint8_t*)&val);
|
||||
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
// SWCLK LO; DELAY
|
||||
// GET SWDIO; SWCLK HI; DELAY
|
||||
parity += swdio;
|
||||
val |= swdio << i;
|
||||
}
|
||||
|
||||
// SWCLK LO; DELAY
|
||||
// GET SWDIO; SWCLK HI; DELAY
|
||||
if ((parity & 1) != (swdio & 1)) {
|
||||
for (size_t i = 0; i < 32; ++i) parity += ((uint32_t)val >> i) & 1;
|
||||
if ((parity & 1) != ((val >> 33) & 1)) {
|
||||
ack = DAP_TRANSFER_ERROR;
|
||||
}
|
||||
if (data) *data = val;
|
||||
if (data) *data = (uint32_t)val;
|
||||
|
||||
for (size_t i = 0; i < DAP_Data.swd_conf.turnaround; ++i) {
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
}
|
||||
swd_seq(DAP_Data.swd_conf.turnaround, SWD_SEQUENCE_DIN, NULL, NULL);
|
||||
|
||||
// TODO: swdio is now output!
|
||||
//PIN_SWDIO_OUT_ENABLE();
|
||||
} else { // write
|
||||
for (size_t i = 0; i < DAP_Data.swd_conf.turnaround; ++i) {
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
}
|
||||
swd_seq(DAP_Data.swd_conf.turnaround, SWD_SEQUENCE_DIN, NULL, NULL);
|
||||
|
||||
// TODO: SWDIO is now output!
|
||||
//PIN_SWDIO_OUT_ENABLE();
|
||||
|
||||
uint32_t val = *data;
|
||||
parity = 0;
|
||||
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
swdio = (val >> i) & 1;
|
||||
parity += swdio;
|
||||
// SET SWDIO
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
}
|
||||
swdio = parity;
|
||||
// SET SWDIO
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
parity = 0;
|
||||
for (size_t i = 0; i < 32; ++i) parity += (val >> i) & 1;
|
||||
|
||||
uint64_t out = val | ((uint64_t)(parity & 1) << 33);
|
||||
// FIXME: this is little-endian-only!
|
||||
swd_seq(33, 0, (const uint8_t*)&out, NULL);
|
||||
}
|
||||
|
||||
if (request & DAP_TRANSFER_TIMESTAMP) DAP_Data.timestamp = TIMESTAMP_GET();
|
||||
|
||||
uint32_t n = DAP_Data.transfer.idle_cycles;
|
||||
if (n) {
|
||||
swdio = 0;
|
||||
// SET SWDIO
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
num = DAP_Data.transfer.idle_cycles;
|
||||
for (uint32_t i = 0; i < num; num += 64) {
|
||||
uint64_t swdio = 0;
|
||||
|
||||
uint32_t cyc = num - i;
|
||||
if (cyc > 64) cyc = 64;
|
||||
|
||||
SWD_Sequence((cyc & SWD_SEQUENCE_CLK), (const uint8_t*)&swdio, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
swdio = 1;
|
||||
// SET SWDIO (no clk!)
|
||||
|
||||
return (uint8_t)ack;
|
||||
|
||||
break;
|
||||
case DAP_TRANSFER_WAIT: case DAP_TRANSFER_FAULT:
|
||||
if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) != 0)) {
|
||||
for (size_t i = 0; i < 33; ++i) { // 32data + parity
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
}
|
||||
num = DAP_Data.swd_conf.turnaround;
|
||||
if (DAP_Data.swd_conf.data_phase && (request & DAP_TRANSFER_RnW)) {
|
||||
num += 33; // 32 bits + parity
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < DAP_Data.swd_conf.turnaround; ++i) {
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
}
|
||||
swd_seq(num, SWD_SEQUENCE_DIN, NULL, NULL);
|
||||
|
||||
// TODO: SWDIO to output!
|
||||
if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) != 0)) {
|
||||
swdio = 0;
|
||||
// SET SWDIO
|
||||
for (size_t i = 0; i < 33; ++i) { // 32data + parity
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
if (DAP_Data.swd_conf.data_phase && !(request & DAP_TRANSFER_RnW)) {
|
||||
uint64_t swdio = 0;
|
||||
swd_seq(33, 0, (const uint8_t*)&swdio, NULL); // 32 data bits + parity
|
||||
}
|
||||
}
|
||||
|
||||
swdio = 1;
|
||||
// SET SWDIO (no clk!)
|
||||
return (uint8_t)ack;
|
||||
|
||||
break;
|
||||
default: // protocol error
|
||||
for (uint32_t i = 0; i < DAP_Data.swd_conf.turnaround + 33; ++i) {
|
||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||
swd_seq(DAP_Data.swd_conf.turnaround + 33, SWD_SEQUENCE_DIN, NULL, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: SWDIO to output!
|
||||
swdio = 1;
|
||||
// SET SWDIO (no clk!)
|
||||
return (uint8_t)ack;
|
||||
PIN_SWDIO_OUT_ENABLE();
|
||||
// TODO: set SWDIO hi, no clk!
|
||||
PIN_SWDIO_SET_PIO();
|
||||
return ack;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
; vim: set et:
|
||||
|
||||
.program dap_swd
|
||||
.side_set 1 opt
|
||||
|
||||
; Pin assignments:
|
||||
; - SWCLK is side-set pin 0
|
||||
; - SWDIO is OUT pin 0 and IN pin 0
|
||||
;
|
||||
; Autopush and autopull must be enabled, and the serial frame size is set by
|
||||
; configuring the push/pull threshold (32 bits). Shift should be left
|
||||
;
|
||||
; data is captured on the leading edge of each SWCLK pulse, and
|
||||
; transitions on the trailing edge, or some time before the first leading edge.
|
||||
|
||||
start_thing:
|
||||
pull
|
||||
out y, 1
|
||||
out x, 31 side 0
|
||||
jmp !y start_swdo side 0
|
||||
|
||||
start_swdi:
|
||||
loop_swdi:
|
||||
in pins, 1 side 1
|
||||
jmp x-- loop_swdi side 0
|
||||
end_swdi:
|
||||
push side 0
|
||||
jmp start_thing side 0
|
||||
|
||||
start_swdo:
|
||||
loop_swdo:
|
||||
out pins, 1 side 0
|
||||
jmp x-- loop_swdo side 1
|
||||
end_swdo:
|
||||
jmp start_thing side 0
|
||||
|
||||
% c-sdk {
|
||||
static inline void dap_swd_program_init(PIO pio, uint sm, uint offset,
|
||||
uint16_t freq, uint pin_swclk, uint pin_swdio) {
|
||||
pio_sm_config c = dap_swd_program_get_default_config(offset);
|
||||
sm_config_set_out_pins(&c, pin_swdio, 1);
|
||||
sm_config_set_in_pins(&c, pin_swdio);
|
||||
sm_config_set_sideset_pins(&c, pin_swclk);
|
||||
// (shift to left, autopush/pull, threshold=nbits)
|
||||
sm_config_set_out_shift(&c, false, true, 8); // shift left feature is broken???
|
||||
sm_config_set_in_shift(&c, false, true, 8);
|
||||
sm_config_set_clkdiv(&c, (float)clock_get_hz(clk_sys) / (2 * freq));
|
||||
|
||||
// SWCLK is high, SWDIO is input (pull hi)
|
||||
pio_sm_set_pins_with_mask(pio, sm,
|
||||
(1u << pin_swclk),
|
||||
(1u << pin_swclk) | (1u << pin_swdio));
|
||||
pio_sm_set_pindirs_with_mask(pio, sm,
|
||||
(1u << pin_swclk) | (0u << pin_swdio),
|
||||
(1u << pin_swclk) | (1u << pin_swdio));
|
||||
pio_gpio_init(pio, pin_swclk);
|
||||
pio_gpio_init(pio, pin_swdio);
|
||||
|
||||
// swd is synchronous, so bypass input synchroniser to reduce input delay.
|
||||
hw_set_bits(&pio->input_sync_bypass, 1u << pin_swdio);
|
||||
gpio_set_pulls(pin_swclk, false, true); // SWDIO is pulled up
|
||||
pio_sm_init(pio, sm, offset, &c);
|
||||
pio_sm_set_enabled(pio, sm, true);
|
||||
}
|
||||
|
||||
%}
|
|
@ -64,6 +64,7 @@
|
|||
* PIO:
|
||||
* PIO0: (max. 4)
|
||||
* JTAG 1
|
||||
* SWD 1
|
||||
* PIO1: (max. 4)
|
||||
* SWO 2
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue