139 lines
3.5 KiB
C
139 lines
3.5 KiB
C
/**
|
|
* @file swd-spi-tap.c
|
|
* @author Sergey Gavrilov (who.just.the.doctor@gmail.com)
|
|
* @version 1.0
|
|
* @date 2021-11-25
|
|
*
|
|
* Does not work due to bug with switching 3-wire mode to RX.
|
|
*
|
|
* https://github.com/espressif/esp-idf/issues/7800
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <adiv5.h>
|
|
|
|
#include <esp_log.h>
|
|
#include <driver/spi_master.h>
|
|
#include "../platform.h"
|
|
#include <string.h>
|
|
|
|
#define SWDTAP_DEBUG 0
|
|
|
|
typedef enum {
|
|
SpiSwdDirFloat,
|
|
SpiSwdDirDrive,
|
|
} SpiSwdDirection;
|
|
|
|
static bool spi_bus_initialized = false;
|
|
static spi_device_handle_t swd_spi_device;
|
|
|
|
inline static void swd_spi_transmit(spi_transaction_t* swd_spi_transaction) {
|
|
ESP_ERROR_CHECK(spi_device_polling_transmit(swd_spi_device, swd_spi_transaction));
|
|
}
|
|
|
|
inline static uint32_t swd_spi_rx(int ticks) {
|
|
uint32_t data = 0;
|
|
spi_transaction_t swd_spi_transaction = {
|
|
.rxlength = ticks,
|
|
.tx_buffer = NULL,
|
|
.rx_buffer = &data,
|
|
};
|
|
|
|
swd_spi_transmit(&swd_spi_transaction);
|
|
|
|
#if SWDTAP_DEBUG == 1
|
|
ESP_LOGW("spi_rx", "< [%02u] 0x%08x", ticks, data);
|
|
#endif
|
|
|
|
return data;
|
|
}
|
|
|
|
inline static void swd_spi_tx(uint32_t data, int ticks) {
|
|
spi_transaction_t swd_spi_transaction = {
|
|
.length = ticks,
|
|
.tx_buffer = &data,
|
|
.rx_buffer = NULL,
|
|
};
|
|
|
|
swd_spi_transmit(&swd_spi_transaction);
|
|
|
|
#if SWDTAP_DEBUG == 1
|
|
ESP_LOGI("spi_tx", "> [%02u] 0x%08x", ticks, data);
|
|
#endif
|
|
}
|
|
|
|
static void swdspitap_turnaround(SpiSwdDirection direction) {
|
|
static SpiSwdDirection old_direction = SpiSwdDirFloat;
|
|
|
|
if(direction == old_direction) return;
|
|
old_direction = direction;
|
|
|
|
swd_spi_tx(1, 1);
|
|
}
|
|
|
|
static uint32_t swdspitap_seq_in(int ticks) {
|
|
swdspitap_turnaround(SpiSwdDirFloat);
|
|
return swd_spi_rx(ticks);
|
|
}
|
|
|
|
static bool swdspitap_seq_in_parity(uint32_t* ret, int ticks) {
|
|
swdspitap_turnaround(SpiSwdDirFloat);
|
|
*ret = swd_spi_rx(ticks);
|
|
int parity = __builtin_popcount(*ret);
|
|
uint32_t data = swd_spi_rx(1);
|
|
parity += (data & 1);
|
|
swdspitap_turnaround(SpiSwdDirDrive);
|
|
return (parity & 1);
|
|
}
|
|
|
|
static void swdspitap_seq_out(uint32_t MS, int ticks) {
|
|
swdspitap_turnaround(SpiSwdDirDrive);
|
|
swd_spi_tx(MS, ticks);
|
|
}
|
|
|
|
static void swdspitap_seq_out_parity(uint32_t MS, int ticks) {
|
|
int parity = __builtin_popcount(MS);
|
|
swdspitap_turnaround(SpiSwdDirDrive);
|
|
swd_spi_tx(MS, ticks);
|
|
swd_spi_tx(parity & 1, 1);
|
|
}
|
|
|
|
int swdptap_init(ADIv5_DP_t* dp) {
|
|
if(!spi_bus_initialized) {
|
|
// config bus
|
|
spi_bus_config_t swd_spi_pins = {
|
|
.mosi_io_num = SWDIO_PIN, // SWD I/O
|
|
.miso_io_num = -1,
|
|
.sclk_io_num = SWCLK_PIN, // SWD CLK
|
|
.quadwp_io_num = -1,
|
|
.quadhd_io_num = -1,
|
|
};
|
|
ESP_ERROR_CHECK(spi_bus_initialize(HSPI_HOST, &swd_spi_pins, SPI_DMA_DISABLED));
|
|
|
|
// add device to bus with config
|
|
spi_device_interface_config_t swd_spi_config = {
|
|
.mode = 0,
|
|
.clock_speed_hz = 10 * 1000,
|
|
.spics_io_num = -1,
|
|
.flags = SPI_DEVICE_3WIRE | SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_BIT_LSBFIRST,
|
|
.queue_size = 24,
|
|
.pre_cb = NULL,
|
|
.post_cb = NULL,
|
|
};
|
|
ESP_ERROR_CHECK(spi_bus_add_device(HSPI_HOST, &swd_spi_config, &swd_spi_device));
|
|
|
|
spi_bus_initialized = true;
|
|
}
|
|
|
|
// set functions
|
|
dp->seq_in = swdspitap_seq_in;
|
|
dp->seq_in_parity = swdspitap_seq_in_parity;
|
|
dp->seq_out = swdspitap_seq_out;
|
|
dp->seq_out_parity = swdspitap_seq_out_parity;
|
|
|
|
return 0;
|
|
}
|