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
|
// swdi: pointer to SWDIO captured data
|
||||||
// return: none
|
// return: none
|
||||||
#if (DAP_SWD != 0)
|
#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 val;
|
||||||
uint32_t bit;
|
uint32_t bit;
|
||||||
uint32_t n, k;
|
uint32_t n, k;
|
||||||
|
|
|
@ -137,6 +137,7 @@ if(FAMILY STREQUAL "rp2040")
|
||||||
endif()
|
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_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_uart_rx.pio)
|
||||||
pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/swo_manchester_encoding.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.
|
13
README.md
13
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),
|
Some code has been incorporated from the [DapperMime](https://github.com/majbthrd/DapperMime),
|
||||||
[picoprobe-sump](https://github.com/perexg/picoprobe-sump),
|
[picoprobe-sump](https://github.com/perexg/picoprobe-sump),
|
||||||
[JTAGenum](https://github.com/cyphunk/JTAGenum) and
|
[JTAGenum](https://github.com/cyphunk/JTAGenum),
|
||||||
[SWDscan](https://github.com/szymonh/SWDscan)
|
[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
|
projects. These respective licenses can be found in
|
||||||
[this](./LICENSE.dappermime), [this](./LICENSE.picoprobe-sump),
|
[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
|
## 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
|
- [ ] GPL license headers on every file
|
||||||
- [x] Debug interface to send printf stuff directly to USB, instead of having
|
- [x] Debug interface to send printf stuff directly to USB, instead of having
|
||||||
to use the UART interface as a loopback thing.
|
to use the UART interface as a loopback thing.
|
||||||
|
@ -87,7 +89,7 @@ projects. These respective licenses can be found in
|
||||||
- [x] I2C support ~~by emulating the I2C Tiny USB~~
|
- [x] I2C support ~~by emulating the I2C Tiny USB~~
|
||||||
- [x] Expose RP2040-internal temperature ADC on I2C-over-USB bus?
|
- [x] Expose RP2040-internal temperature ADC on I2C-over-USB bus?
|
||||||
- [ ] ~~Does SMBus stuff need special treatment here?~~ ~~No.~~ Actually, some
|
- [ ] ~~Does SMBus stuff need special treatment here?~~ ~~No.~~ Actually, some
|
||||||
parts do, but, laziness.
|
parts do, but, laziness.
|
||||||
- [x] 10-bit I2C address support (Needs poking at the Pico SDK, as it only
|
- [x] 10-bit I2C address support (Needs poking at the Pico SDK, as it only
|
||||||
supports 7-bit ones).
|
supports 7-bit ones).
|
||||||
- [ ] **1-wire**
|
- [ ] **1-wire**
|
||||||
|
@ -98,7 +100,6 @@ projects. These respective licenses can be found in
|
||||||
- interface 1 ("B"): index 2, epin 0x04, epout 0x83
|
- interface 1 ("B"): index 2, epin 0x04, epout 0x83
|
||||||
- interface 2 ("C"): index 3, epin 0x06, epout 0x85
|
- interface 2 ("C"): index 3, epin 0x06, epout 0x85
|
||||||
- interface 3 ("D"): index 4, epin 0x08, epout 0x87
|
- 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
|
- [ ] "Complex Trigger" mode for aiding with glitching triggers, by turning
|
||||||
UART/SPI/I2C/eMMC/... sequences into a GPIO toggle
|
UART/SPI/I2C/eMMC/... sequences into a GPIO toggle
|
||||||
- [ ] Mode where you can define custom PIO stuff for custom pinouts/protocols??????
|
- [ ] 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
|
Configure the SWDIO DAP hardware I/O pin to output mode. This function is
|
||||||
called prior \ref PIN_SWDIO_OUT function calls.
|
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).
|
/** 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
|
Configure the SWDIO DAP hardware I/O pin to input mode. This function is
|
||||||
called prior \ref PIN_SWDIO_IN function calls.
|
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 ---------------------------------------------
|
// 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__ */
|
#endif /* __DAP_CONFIG_H__ */
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,8 @@
|
||||||
#include "DAP_config.h"
|
#include "DAP_config.h"
|
||||||
#include <DAP.h>
|
#include <DAP.h>
|
||||||
|
|
||||||
#include "tusb_config.h"
|
|
||||||
#include <tusb.h>
|
|
||||||
|
|
||||||
#include "dap_jtag.pio.h"
|
#include "dap_jtag.pio.h"
|
||||||
|
#include "dap_swd.pio.h"
|
||||||
|
|
||||||
#define JTAG_PIO
|
#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 printf("%s", "\nno tdo\n");
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static int jtagsm = -1, offset = -1;
|
int jtagsm = -1, jtagoffset = -1;
|
||||||
|
|
||||||
void PORT_JTAG_SETUP(void) {
|
void PORT_JTAG_SETUP(void) {
|
||||||
resets_hw->reset &= ~(RESETS_RESET_IO_BANK0_BITS | RESETS_RESET_PADS_BANK0_BITS);
|
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_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;
|
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);
|
if (jtagsm == -1) jtagsm = pio_claim_unused_sm(PINOUT_JTAG_PIO_DEV, true);
|
||||||
offset = pio_add_program(PINOUT_JTAG_PIO_DEV, &dap_jtag_program);
|
if (jtagoffset == -1)
|
||||||
dap_jtag_program_init(PINOUT_JTAG_PIO_DEV, jtagsm, offset,
|
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);
|
50*1000, PINOUT_JTAG_TCK, PINOUT_JTAG_TDI, PINOUT_JTAG_TDO);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PORT_OFF(void) {
|
void PORT_OFF(void) {
|
||||||
pio_sm_set_enabled(PINOUT_JTAG_PIO_DEV, jtagsm, false);
|
if (jtagsm) {
|
||||||
pio_sm_unclaim(PINOUT_JTAG_PIO_DEV, jtagsm);
|
pio_sm_set_enabled(PINOUT_JTAG_PIO_DEV, jtagsm, false);
|
||||||
pio_remove_program(PINOUT_JTAG_PIO_DEV, &dap_jtag_program, offset);
|
pio_sm_unclaim(PINOUT_JTAG_PIO_DEV, jtagsm);
|
||||||
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 |
|
sio_hw->gpio_oe_clr = PINOUT_SWCLK_MASK | PINOUT_SWDIO_MASK |
|
||||||
PINOUT_TDI_MASK //| PINOUT_TDO_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');*/
|
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;
|
for (size_t oi = 0, ii = 0; txremain || rxremain; tight_loop_contents()) {
|
||||||
while (txremain || rxremain) {
|
|
||||||
if (txremain && !pio_sm_is_tx_fifo_full(PINOUT_JTAG_PIO_DEV, jtagsm)) {
|
if (txremain && !pio_sm_is_tx_fifo_full(PINOUT_JTAG_PIO_DEV, jtagsm)) {
|
||||||
*tx = bitswap(tdi[ii]);
|
*tx = bitswap(tdi[ii]);
|
||||||
--txremain;
|
--txremain;
|
||||||
|
@ -243,22 +251,28 @@ static void jtag_seq(uint32_t num, int tms, const void* tdi, void* tdo) {
|
||||||
static uint64_t last_bit = ~(uint64_t)0;
|
static uint64_t last_bit = ~(uint64_t)0;
|
||||||
uint64_t devnull = 0;
|
uint64_t devnull = 0;
|
||||||
|
|
||||||
bool notdi, notdo;
|
bool notdi = tdi == NULL, notdo = tdo == NULL;
|
||||||
|
|
||||||
if ((notdi = (tdi == NULL))) tdi = &last_bit;
|
if (!notdo) tms |= JTAG_SEQUENCE_TDO;
|
||||||
if ((notdo = (tdo == NULL))) tdo = &devnull;
|
|
||||||
else tms |= JTAG_SEQUENCE_TDO;
|
const void* jdi;
|
||||||
|
void* jdo;
|
||||||
|
|
||||||
uint32_t nreal;
|
uint32_t nreal;
|
||||||
for (uint32_t i = 0; i < num; i += nreal) {
|
for (uint32_t i = 0; i < num; i += nreal) {
|
||||||
uint32_t nmod = (num - i) & 63;
|
uint32_t nmod = (num - i) & 63;
|
||||||
nreal = nmod ? nmod : 64;
|
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) {
|
||||||
last_bit = (lastbyte & (1 << (num & 7))) ? ~(uint64_t)0 : (uint64_t)0;
|
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) {
|
uint32_t JTAG_ReadIDCode(void) {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
; vim: set et:
|
; 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
|
.program dap_jtag
|
||||||
.side_set 1 opt
|
.side_set 1 opt
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
// vim: set et:
|
// 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_config.h"
|
||||||
#include <DAP.h>
|
#include <DAP.h>
|
||||||
|
|
||||||
/*#define SWD_PIO*/
|
#include "dap_swd.pio.h"
|
||||||
|
|
||||||
|
#define SWD_PIO
|
||||||
|
|
||||||
#ifndef SWD_PIO
|
#ifndef SWD_PIO
|
||||||
void PORT_SWD_SETUP(void) {
|
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_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;
|
iobank0_hw->io[PINOUT_SWDIO].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
void PORT_SWD_SETUP(void) {
|
void PIN_SWDIO_OUT_ENABLE(void) {
|
||||||
// TODO...
|
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)
|
// 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) {
|
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) {
|
if ((i & 7) == 0) {
|
||||||
val = data[k];
|
val = data[k];
|
||||||
++k;
|
++k;
|
||||||
|
@ -38,187 +206,90 @@ void SWJ_Sequence(uint32_t count, const uint8_t* data) {
|
||||||
swdio = (val >> (i & 7)) & 1;
|
swdio = (val >> (i & 7)) & 1;
|
||||||
// SET SWDIO
|
// SET SWDIO
|
||||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void SWD_Sequence(uint32_t info, const uint8_t* swdo, uint8_t* swdi) {
|
uint8_t SWD_Transfer(uint32_t request, uint32_t* data) {
|
||||||
uint32_t n = info & SWD_SEQUENCE_CLK;
|
uint32_t parity;
|
||||||
if (n == 0) n = 64;
|
uint8_t swdo;
|
||||||
|
|
||||||
if (info & SWD_SEQUENCE_DIN) {
|
parity = ((request >> 0) & 1) + ((request >> 1) & 1)
|
||||||
for (uint32_t i = 0; i < n; ) {
|
+ ((request >> 2) & 1) + ((request >> 3) & 1);
|
||||||
uint32_t v = 0;
|
swdo = 1 | ((request & 0xf) << 1) | ((parity & 1) << 5) | (0<<6) | (1<<7);
|
||||||
for (uint32_t k = 0; k < 8; ++k, ++i) {
|
swd_seq(8, 0, &swdo, NULL);
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SWD_Transfer(uint32_t request, uint32_t* data) {
|
swd_seq(DAP_Data.swd_conf.turnaround, SWD_SEQUENCE_DIN, NULL, NULL);
|
||||||
// TODO: to SWD_Sequence stuff(?)
|
|
||||||
|
|
||||||
uint32_t parity = 0;
|
uint8_t ack = 0;
|
||||||
|
swd_seq(3, SWD_SEQUENCE_DIN, NULL, &ack);
|
||||||
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;
|
|
||||||
|
|
||||||
|
uint32_t num;
|
||||||
switch (ack) {
|
switch (ack) {
|
||||||
case DAP_TRANSFER_OK:
|
case DAP_TRANSFER_OK:
|
||||||
if (request & DAP_TRANSFER_RnW) { // read
|
if (request & DAP_TRANSFER_RnW) {
|
||||||
uint32_t val = 0;
|
uint64_t val = 0;
|
||||||
parity = 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) {
|
for (size_t i = 0; i < 32; ++i) parity += ((uint32_t)val >> i) & 1;
|
||||||
// SWCLK LO; DELAY
|
if ((parity & 1) != ((val >> 33) & 1)) {
|
||||||
// GET SWDIO; SWCLK HI; DELAY
|
|
||||||
parity += swdio;
|
|
||||||
val |= swdio << i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SWCLK LO; DELAY
|
|
||||||
// GET SWDIO; SWCLK HI; DELAY
|
|
||||||
if ((parity & 1) != (swdio & 1)) {
|
|
||||||
ack = DAP_TRANSFER_ERROR;
|
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) {
|
swd_seq(DAP_Data.swd_conf.turnaround, SWD_SEQUENCE_DIN, NULL, NULL);
|
||||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: swdio is now output!
|
//PIN_SWDIO_OUT_ENABLE();
|
||||||
} else { // write
|
} else { // write
|
||||||
for (size_t i = 0; i < DAP_Data.swd_conf.turnaround; ++i) {
|
swd_seq(DAP_Data.swd_conf.turnaround, SWD_SEQUENCE_DIN, NULL, NULL);
|
||||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: SWDIO is now output!
|
//PIN_SWDIO_OUT_ENABLE();
|
||||||
|
|
||||||
uint32_t val = *data;
|
uint32_t val = *data;
|
||||||
parity = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < 32; ++i) {
|
parity = 0;
|
||||||
swdio = (val >> i) & 1;
|
for (size_t i = 0; i < 32; ++i) parity += (val >> i) & 1;
|
||||||
parity += swdio;
|
|
||||||
// SET SWDIO
|
uint64_t out = val | ((uint64_t)(parity & 1) << 33);
|
||||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
// FIXME: this is little-endian-only!
|
||||||
}
|
swd_seq(33, 0, (const uint8_t*)&out, NULL);
|
||||||
swdio = parity;
|
|
||||||
// SET SWDIO
|
|
||||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request & DAP_TRANSFER_TIMESTAMP) DAP_Data.timestamp = TIMESTAMP_GET();
|
if (request & DAP_TRANSFER_TIMESTAMP) DAP_Data.timestamp = TIMESTAMP_GET();
|
||||||
|
|
||||||
uint32_t n = DAP_Data.transfer.idle_cycles;
|
num = DAP_Data.transfer.idle_cycles;
|
||||||
if (n) {
|
for (uint32_t i = 0; i < num; num += 64) {
|
||||||
swdio = 0;
|
uint64_t swdio = 0;
|
||||||
// SET SWDIO
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
uint32_t cyc = num - i;
|
||||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
if (cyc > 64) cyc = 64;
|
||||||
}
|
|
||||||
|
SWD_Sequence((cyc & SWD_SEQUENCE_CLK), (const uint8_t*)&swdio, NULL);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
swdio = 1;
|
|
||||||
// SET SWDIO (no clk!)
|
|
||||||
|
|
||||||
return (uint8_t)ack;
|
|
||||||
|
|
||||||
case DAP_TRANSFER_WAIT: case DAP_TRANSFER_FAULT:
|
case DAP_TRANSFER_WAIT: case DAP_TRANSFER_FAULT:
|
||||||
if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) != 0)) {
|
num = DAP_Data.swd_conf.turnaround;
|
||||||
for (size_t i = 0; i < 33; ++i) { // 32data + parity
|
if (DAP_Data.swd_conf.data_phase && (request & DAP_TRANSFER_RnW)) {
|
||||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
num += 33; // 32 bits + parity
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < DAP_Data.swd_conf.turnaround; ++i) {
|
swd_seq(num, SWD_SEQUENCE_DIN, NULL, NULL);
|
||||||
// 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
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
swdio = 1;
|
|
||||||
// SET SWDIO (no clk!)
|
|
||||||
return (uint8_t)ack;
|
|
||||||
|
|
||||||
default: // protocol error
|
default: // protocol error
|
||||||
for (uint32_t i = 0; i < DAP_Data.swd_conf.turnaround + 33; ++i) {
|
swd_seq(DAP_Data.swd_conf.turnaround + 33, SWD_SEQUENCE_DIN, NULL, NULL);
|
||||||
// SWCLK LO; DELAY; SWCLK HI; DELAY
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: SWDIO to output!
|
|
||||||
swdio = 1;
|
|
||||||
// SET SWDIO (no clk!)
|
|
||||||
return (uint8_t)ack;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
PIN_SWDIO_OUT_ENABLE();
|
||||||
|
// TODO: set SWDIO hi, no clk!
|
||||||
|
PIN_SWDIO_SET_PIO();
|
||||||
|
return ack;
|
||||||
|
}
|
||||||
|
//#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:
|
* PIO:
|
||||||
* PIO0: (max. 4)
|
* PIO0: (max. 4)
|
||||||
* JTAG 1
|
* JTAG 1
|
||||||
|
* SWD 1
|
||||||
* PIO1: (max. 4)
|
* PIO1: (max. 4)
|
||||||
* SWO 2
|
* SWO 2
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue