spi stuff
This commit is contained in:
parent
5c17820a52
commit
0f4566d0e7
|
@ -5,7 +5,7 @@
|
|||
#define DBOARD_HAS_UART
|
||||
#define DBOARD_HAS_CMSISDAP
|
||||
// TODO: rename to _SPI
|
||||
#define DBOARD_HAS_SERPROG
|
||||
#define DBOARD_HAS_SPI
|
||||
#define DBOARD_HAS_I2C
|
||||
#define DBOARD_HAS_TEMPSENSOR
|
||||
|
||||
|
@ -27,7 +27,7 @@ enum {
|
|||
};
|
||||
enum {
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
VND_CFG = 0,
|
||||
VND_N_CFG = 0,
|
||||
#endif
|
||||
|
||||
VND_N__NITF
|
||||
|
|
|
@ -13,10 +13,15 @@
|
|||
|
||||
static bool cs_asserted;
|
||||
|
||||
static uint32_t freq;
|
||||
static enum serprog_flags sflags;
|
||||
|
||||
void sp_spi_init(void) {
|
||||
cs_asserted = false;
|
||||
|
||||
spi_init(PINOUT_SPI_DEV, 512 * 1000); // default to 512 kHz
|
||||
freq = 512*1000; // default to 512 kHz
|
||||
sflags = 0; // CPOL 0, CPHA 0, 8bit
|
||||
spi_init(PINOUT_SPI_DEV, freq);
|
||||
|
||||
gpio_set_function(PINOUT_SPI_MISO, GPIO_FUNC_SPI);
|
||||
gpio_set_function(PINOUT_SPI_MOSI, GPIO_FUNC_SPI);
|
||||
|
@ -32,6 +37,8 @@ void sp_spi_init(void) {
|
|||
}
|
||||
void sp_spi_deinit(void) {
|
||||
cs_asserted = false;
|
||||
sflags = 0;
|
||||
freq = 512*1000;
|
||||
|
||||
gpio_set_function(PINOUT_SPI_MISO, GPIO_FUNC_NULL);
|
||||
gpio_set_function(PINOUT_SPI_MOSI, GPIO_FUNC_NULL);
|
||||
|
@ -43,32 +50,52 @@ void sp_spi_deinit(void) {
|
|||
|
||||
spi_deinit(PINOUT_SPI_DEV);
|
||||
}
|
||||
|
||||
uint32_t __not_in_flash_func(sp_spi_set_freq)(uint32_t freq_wanted) {
|
||||
return spi_set_baudrate(PINOUT_SPI_DEV, freq_wanted);
|
||||
freq = spi_set_baudrate(PINOUT_SPI_DEV, freq_wanted);
|
||||
return freq;
|
||||
}
|
||||
void __not_in_flash_func(sp_spi_cs_deselect)(void) {
|
||||
void __not_in_flash_func(sp_spi_set_flags)(enum serprog_flags flags) {
|
||||
sflags = flags;
|
||||
spi_set_format(PINOUT_SPI_DEV, (flags & S_FLG_16BIT) ? 16 : 8,
|
||||
(flags & S_FLG_CPOL) ? SPI_CPOL_1 : SPI_CPOL_0,
|
||||
(flags & S_FLG_CPHA) ? SPI_CPHA_1 : SPI_CPHA_0,
|
||||
SPI_MSB_FIRST);
|
||||
}
|
||||
__attribute__((__const__))
|
||||
int __not_in_flash_func(sp_spi_get_num_cs)(void) { return 1; }
|
||||
|
||||
void __not_in_flash_func(sp_spi_cs_deselect)(uint8_t csflags) {
|
||||
(void)csflags;
|
||||
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
gpio_put(PINOUT_SPI_nCS, 1);
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
cs_asserted = false;
|
||||
}
|
||||
void __not_in_flash_func(sp_spi_cs_select)(void) {
|
||||
void __not_in_flash_func(sp_spi_cs_select)(uint8_t csflags) {
|
||||
(void)csflags;
|
||||
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
gpio_put(PINOUT_SPI_nCS, 0);
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
cs_asserted = true;
|
||||
}
|
||||
|
||||
void __not_in_flash_func(sp_spi_op_begin)(void) {
|
||||
// sp_spi_cs_select();
|
||||
void __not_in_flash_func(sp_spi_op_begin)(uint8_t csflags) {
|
||||
// sp_spi_cs_select(csflags);
|
||||
(void)csflags;
|
||||
|
||||
if (!cs_asserted) {
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
gpio_put(PINOUT_SPI_nCS, 0);
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
}
|
||||
}
|
||||
void __not_in_flash_func(sp_spi_op_end)(void) {
|
||||
// sp_spi_cs_deselect();
|
||||
void __not_in_flash_func(sp_spi_op_end)(uint8_t csflags) {
|
||||
// sp_spi_cs_deselect(csflags);
|
||||
(void)csflags;
|
||||
|
||||
if (!cs_asserted) { // YES, this condition is the intended one!
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
gpio_put(PINOUT_SPI_nCS, 1);
|
||||
|
@ -77,10 +104,29 @@ void __not_in_flash_func(sp_spi_op_end)(void) {
|
|||
}
|
||||
|
||||
// TODO: use dma?
|
||||
void __not_in_flash_func(sp_spi_op_write)(uint32_t write_len, const uint8_t* write_data) {
|
||||
spi_write_blocking(PINOUT_SPI_DEV, write_data, write_len);
|
||||
// TODO: routines for non-8/16-bit xfers??
|
||||
void __not_in_flash_func(sp_spi_op_write)(uint32_t write_len, const void* write_data) {
|
||||
if (sflags & S_FLG_16BIT) {
|
||||
spi_write16_blocking(PINOUT_SPI_DEV, (const uint16_t*)write_data, write_len >> 1);
|
||||
} else {
|
||||
spi_write_blocking(PINOUT_SPI_DEV, (const uint8_t*)write_data, write_len);
|
||||
}
|
||||
}
|
||||
void __not_in_flash_func(sp_spi_op_read)(uint32_t read_len, uint8_t* read_data) {
|
||||
spi_read_blocking(PINOUT_SPI_DEV, 0, read_data, read_len);
|
||||
void __not_in_flash_func(sp_spi_op_read)(uint32_t read_len, void* read_data) {
|
||||
if (sflags & S_FLG_16BIT) {
|
||||
spi_read16_blocking(PINOUT_SPI_DEV, 0, (uint16_t*)read_data, read_len >> 1);
|
||||
} else {
|
||||
spi_read_blocking(PINOUT_SPI_DEV, 0, (uint8_t*)read_data, read_len);
|
||||
}
|
||||
}
|
||||
void __not_in_flash_func(sp_spi_op_read_write)(uint32_t len, void* read_data,
|
||||
const void* write_data) {
|
||||
if (sflags & S_FLG_16BIT) {
|
||||
spi_write16_read16_blocking(PINOUT_SPI_DEV, (const uint16_t*)write_data,
|
||||
(uint16_t*)read_data, len >> 1);
|
||||
} else {
|
||||
spi_write_read_blocking(PINOUT_SPI_DEV, (const uint8_t*)write_data,
|
||||
(uint8_t*)read_data, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ static void uart_thread_fn(void) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
#ifdef DBOARD_HAS_SPI
|
||||
static cothread_t serprogthread;
|
||||
static uint8_t serprogstack[THREAD_STACK_SIZE];
|
||||
|
||||
|
@ -82,7 +82,7 @@ static void enter_cb(void) {
|
|||
uartthread = co_derive(uartstack, sizeof uartstack, uart_thread_fn);
|
||||
thread_enter(uartthread); // will call cdc_uart_init() on correct thread
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
#ifdef DBOARD_HAS_SPI
|
||||
serprogthread = co_derive(serprogstack, sizeof serprogstack, serprog_thread_fn);
|
||||
thread_enter(serprogthread); // will call cdc_serprog_init() on correct thread
|
||||
#endif
|
||||
|
@ -95,7 +95,7 @@ static void leave_cb(void) {
|
|||
#ifdef DBOARD_HAS_UART
|
||||
cdc_uart_deinit();
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
#ifdef DBOARD_HAS_SPI
|
||||
cdc_serprog_deinit();
|
||||
#endif
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ static void task_cb(void) {
|
|||
tud_task();
|
||||
thread_enter(uartthread);
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
#ifdef DBOARD_HAS_SPI
|
||||
tud_task();
|
||||
thread_enter(serprogthread);
|
||||
#endif
|
||||
|
@ -122,7 +122,7 @@ static void handle_cmd_cb(uint8_t cmd) {
|
|||
#ifdef DBOARD_HAS_CMSISDAP
|
||||
resp |= mdef_feat_cmsisdap;
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
#ifdef DBOARD_HAS_SPI
|
||||
resp |= mdef_feat_spi;
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_I2C
|
||||
|
@ -134,7 +134,7 @@ static void handle_cmd_cb(uint8_t cmd) {
|
|||
vnd_cfg_write_resp(cfg_resp_ok, 1, &resp);
|
||||
break;
|
||||
case mdef_cmd_spi:
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
#ifdef DBOARD_HAS_SPI
|
||||
sp_spi_bulk_cmd();
|
||||
#else
|
||||
vnd_cfg_write_resp(cfg_resp_illcmd, 0, NULL);
|
||||
|
@ -194,7 +194,7 @@ enum {
|
|||
ITF_NUM_CDC_UART_COM,
|
||||
ITF_NUM_CDC_UART_DATA,
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
#ifdef DBOARD_HAS_SPI
|
||||
ITF_NUM_CDC_SERPROG_COM,
|
||||
ITF_NUM_CDC_SERPROG_DATA,
|
||||
#endif
|
||||
|
@ -220,7 +220,7 @@ enum {
|
|||
#ifdef DBOARD_HAS_UART
|
||||
+ TUD_CDC_DESC_LEN
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
#ifdef DBOARD_HAS_SPI
|
||||
+ TUD_CDC_DESC_LEN
|
||||
#endif
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
|
@ -265,7 +265,7 @@ static const uint8_t desc_configuration[] = {
|
|||
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
TUD_VENDOR_DESCRIPTOR(ITF_NUM_VND_CFG, STRID_IF_VND_CFG, EPNUM_VND_CFG_OUT,
|
||||
EPNUM_VND_CFG_IN, 64),
|
||||
EPNUM_VND_CFG_IN, CFG_TUD_VENDOR_RX_BUFSIZE),
|
||||
#endif
|
||||
|
||||
#if defined(DBOARD_HAS_I2C) && defined(MODE_ENABLE_I2CTINYUSB)
|
||||
|
@ -279,18 +279,18 @@ static const uint8_t desc_configuration[] = {
|
|||
#endif
|
||||
|
||||
#ifdef DBOARD_HAS_UART
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_UART_COM, STRID_IF_CDC_UART, EPNUM_CDC_UART_NOTIF, 64,
|
||||
EPNUM_CDC_UART_OUT, EPNUM_CDC_UART_IN, 64),
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_UART_COM, STRID_IF_CDC_UART, EPNUM_CDC_UART_NOTIF,
|
||||
CFG_TUD_CDC_RX_BUFSIZE, EPNUM_CDC_UART_OUT, EPNUM_CDC_UART_IN, CFG_TUD_CDC_RX_BUFSIZE),
|
||||
#endif
|
||||
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
#ifdef DBOARD_HAS_SPI
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_SERPROG_COM, STRID_IF_CDC_SERPROG, EPNUM_CDC_SERPROG_NOTIF,
|
||||
64, EPNUM_CDC_SERPROG_OUT, EPNUM_CDC_SERPROG_IN, 64),
|
||||
CFG_TUD_CDC_RX_BUFSIZE, EPNUM_CDC_SERPROG_OUT, EPNUM_CDC_SERPROG_IN, CFG_TUD_CDC_RX_BUFSIZE),
|
||||
#endif
|
||||
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_STDIO_COM, STRID_IF_CDC_STDIO, EPNUM_CDC_STDIO_NOTIF, 64,
|
||||
EPNUM_CDC_STDIO_OUT, EPNUM_CDC_STDIO_IN, 64),
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_STDIO_COM, STRID_IF_CDC_STDIO, EPNUM_CDC_STDIO_NOTIF,
|
||||
CFG_TUD_CDC_RX_BUFSIZE, EPNUM_CDC_STDIO_OUT, EPNUM_CDC_STDIO_IN, CFG_TUD_CDC_RX_BUFSIZE),
|
||||
#endif
|
||||
};
|
||||
static const char* string_desc_arr[] = {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "m_default/bsp-feature.h"
|
||||
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
#ifdef DBOARD_HAS_SPI
|
||||
|
||||
#include "info.h"
|
||||
#include "util.h"
|
||||
|
@ -20,6 +20,11 @@ static const uint8_t serprog_cmdmap[32] = {
|
|||
0x3f, // cmd 00..05 not 0x06 (Q_CHIPSIZE) and 0x07 (Q_OPBUF), as this is a SPI-only device
|
||||
0x01, // only cmd 08
|
||||
0x1f, // cmd 10..15 supported
|
||||
0, // 18..1f
|
||||
0, // 20..27
|
||||
0, // 28..2f
|
||||
0, // 30..37
|
||||
0x3f, // cmd 40..45
|
||||
0, // rest is 0
|
||||
};
|
||||
// clang-format on
|
||||
|
@ -29,10 +34,12 @@ static uint8_t rx_buf[CFG_TUD_CDC_RX_BUFSIZE];
|
|||
static uint8_t tx_buf[CFG_TUD_CDC_TX_BUFSIZE];
|
||||
|
||||
static uint32_t rxavail, rxpos;
|
||||
static uint8_t selchip;
|
||||
|
||||
void cdc_serprog_init(void) {
|
||||
rxavail = 0;
|
||||
rxpos = 0;
|
||||
selchip = 1;
|
||||
|
||||
sp_spi_init();
|
||||
}
|
||||
|
@ -41,9 +48,15 @@ void cdc_serprog_deinit(void) {
|
|||
|
||||
rxavail = 0;
|
||||
rxpos = 0;
|
||||
selchip = 1;
|
||||
}
|
||||
|
||||
static uint8_t read_byte(void) {
|
||||
__attribute__((__const__))
|
||||
uint32_t sp_spi_get_buf_limit(void) {
|
||||
return sizeof(rx_buf) - 1;
|
||||
}
|
||||
|
||||
static uint8_t read_byte_cdc(void) {
|
||||
while (rxavail <= 0) {
|
||||
if (!tud_cdc_n_connected(CDC_N_SERPROG) || !tud_cdc_n_available(CDC_N_SERPROG)) {
|
||||
thread_yield();
|
||||
|
@ -62,10 +75,13 @@ static uint8_t read_byte(void) {
|
|||
return rv;
|
||||
}
|
||||
|
||||
static void handle_cmd(void) {
|
||||
uint32_t nresp = 0;
|
||||
static uint32_t nresp = 0;
|
||||
static void handle_cmd(uint8_t cmd, int ud, uint8_t (*read_byte)(void),
|
||||
void (*writepkt)(int ud, const uint8_t* buf, uint32_t len),
|
||||
void (*flushpkt)(int ud),
|
||||
void (*writehdr)(enum cfg_resp stat, uint32_t len, const void* data)) {
|
||||
nresp = 0;
|
||||
|
||||
uint8_t cmd = read_byte();
|
||||
switch (cmd) {
|
||||
case S_CMD_NOP:
|
||||
tx_buf[0] = S_ACK;
|
||||
|
@ -104,17 +120,19 @@ static void handle_cmd(void) {
|
|||
nresp = 2;
|
||||
break;
|
||||
case S_CMD_Q_WRNMAXLEN:
|
||||
nresp = sp_spi_get_buf_limit();
|
||||
tx_buf[0] = S_ACK;
|
||||
tx_buf[1] = (sizeof(tx_buf) - 1) & 0xff;
|
||||
tx_buf[2] = ((sizeof(tx_buf) - 1) >> 8) & 0xff;
|
||||
tx_buf[3] = ((sizeof(tx_buf) - 1) >> 16) & 0xff;
|
||||
tx_buf[1] = nresp & 0xff;
|
||||
tx_buf[2] = (nresp >> 8) & 0xff;
|
||||
tx_buf[3] = (nresp >> 16) & 0xff;
|
||||
nresp = 4;
|
||||
break;
|
||||
case S_CMD_Q_RDNMAXLEN:
|
||||
nresp = sp_spi_get_buf_limit();
|
||||
tx_buf[0] = S_ACK;
|
||||
tx_buf[1] = (sizeof(rx_buf) - 1) & 0xff;
|
||||
tx_buf[2] = ((sizeof(rx_buf) - 1) >> 8) & 0xff;
|
||||
tx_buf[3] = ((sizeof(rx_buf) - 1) >> 16) & 0xff;
|
||||
tx_buf[1] = nresp & 0xff;
|
||||
tx_buf[2] = (nresp >> 8) & 0xff;
|
||||
tx_buf[3] = (nresp >> 16) & 0xff;
|
||||
nresp = 4;
|
||||
break;
|
||||
case S_CMD_S_BUSTYPE:
|
||||
|
@ -126,58 +144,6 @@ static void handle_cmd(void) {
|
|||
nresp = 1;
|
||||
break;
|
||||
|
||||
case S_CMD_SPIOP: {
|
||||
uint32_t slen, rlen;
|
||||
|
||||
// clang-format off
|
||||
slen = (uint32_t)read_byte();
|
||||
slen |= (uint32_t)read_byte() << 8;
|
||||
slen |= (uint32_t)read_byte() << 16;
|
||||
rlen = (uint32_t)read_byte();
|
||||
rlen |= (uint32_t)read_byte() << 8;
|
||||
rlen |= (uint32_t)read_byte() << 16;
|
||||
// clang-format on
|
||||
|
||||
sp_spi_op_begin();
|
||||
size_t this_batch;
|
||||
|
||||
// 1. write slen data bytes
|
||||
// we're going to use the tx buf for all operations here
|
||||
while (slen > 0) {
|
||||
this_batch = sizeof(tx_buf);
|
||||
if (this_batch > slen) this_batch = slen;
|
||||
|
||||
for (size_t i = 0; i < this_batch; ++i) tx_buf[i] = read_byte();
|
||||
sp_spi_op_write(this_batch, tx_buf);
|
||||
|
||||
slen -= this_batch;
|
||||
}
|
||||
|
||||
// 2. write data
|
||||
// first, do a batch of 63, because we also need to send an ACK byte
|
||||
this_batch = sizeof(tx_buf) - 1;
|
||||
if (this_batch > rlen) this_batch = rlen;
|
||||
sp_spi_op_read(this_batch, &tx_buf[1]);
|
||||
tx_buf[0] = S_ACK;
|
||||
tud_cdc_n_write(CDC_N_SERPROG, tx_buf, this_batch + 1);
|
||||
rlen -= this_batch;
|
||||
|
||||
// now do in batches of 64
|
||||
while (rlen > 0) {
|
||||
this_batch = sizeof(tx_buf);
|
||||
if (this_batch > rlen) this_batch = rlen;
|
||||
|
||||
sp_spi_op_read(this_batch, tx_buf);
|
||||
tud_cdc_n_write(CDC_N_SERPROG, tx_buf, this_batch);
|
||||
|
||||
rlen -= this_batch;
|
||||
}
|
||||
tud_cdc_n_write_flush(CDC_N_SERPROG);
|
||||
|
||||
// that's it!
|
||||
sp_spi_op_end();
|
||||
nresp = 0; // we sent our own response manually
|
||||
} break;
|
||||
case S_CMD_S_SPI_FREQ: {
|
||||
uint32_t freq;
|
||||
// clang-format off
|
||||
|
@ -198,19 +164,134 @@ static void handle_cmd(void) {
|
|||
} break;
|
||||
case S_CMD_S_PINSTATE: {
|
||||
if (read_byte() == 0)
|
||||
sp_spi_cs_deselect();
|
||||
sp_spi_cs_deselect(selchip);
|
||||
else
|
||||
sp_spi_cs_select();
|
||||
sp_spi_cs_select(selchip);
|
||||
|
||||
tx_buf[0] = S_ACK;
|
||||
nresp = 1;
|
||||
} break;
|
||||
|
||||
case S_CMD_Q_NUM_CS:
|
||||
tx_buf[0] = S_ACK;
|
||||
tx_buf[1] = sp_spi_get_num_cs();
|
||||
nresp = 2;
|
||||
break;
|
||||
case S_CMD_S_SPI_FLAGS:
|
||||
sp_spi_set_flags(read_byte());
|
||||
tx_buf[0] = S_ACK;
|
||||
nresp = 1;
|
||||
break;
|
||||
case S_CMD_S_SPI_CHIPN:
|
||||
selchip = read_byte();
|
||||
tx_buf[0] = S_ACK;
|
||||
nresp = 1;
|
||||
break;
|
||||
|
||||
case S_CMD_SPIOP: case S_CMD_SPI_READ: case S_CMD_SPI_WRITE: {
|
||||
uint32_t slen, rlen;
|
||||
|
||||
// clang-format off
|
||||
slen = (uint32_t)read_byte();
|
||||
slen |= (uint32_t)read_byte() << 8;
|
||||
slen |= (uint32_t)read_byte() << 16;
|
||||
rlen = (uint32_t)read_byte();
|
||||
rlen |= (uint32_t)read_byte() << 8;
|
||||
rlen |= (uint32_t)read_byte() << 16;
|
||||
// clang-format on
|
||||
|
||||
if (writehdr)
|
||||
writehdr(cfg_resp_ok, rlen+1, NULL);
|
||||
|
||||
sp_spi_op_begin(selchip);
|
||||
size_t this_batch;
|
||||
|
||||
// 1. write slen data bytes
|
||||
// we're going to use the tx buf for all operations here
|
||||
if (cmd == S_CMD_SPIOP || cmd == S_CMD_SPI_WRITE) {
|
||||
while (slen > 0) {
|
||||
this_batch = sizeof(tx_buf);
|
||||
if (this_batch > slen) this_batch = slen;
|
||||
|
||||
for (size_t i = 0; i < this_batch; ++i) tx_buf[i] = read_byte();
|
||||
sp_spi_op_write(this_batch, tx_buf);
|
||||
|
||||
slen -= this_batch;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. read data
|
||||
// first, do a batch of 63, because we also need to send an ACK byte
|
||||
if (cmd == S_CMD_SPIOP || cmd == S_CMD_SPI_READ) {
|
||||
this_batch = sizeof(tx_buf) - 1;
|
||||
if (this_batch > rlen) this_batch = rlen;
|
||||
sp_spi_op_read(this_batch, &tx_buf[1]);
|
||||
tx_buf[0] = S_ACK;
|
||||
writepkt(ud, tx_buf, this_batch + 1);
|
||||
rlen -= this_batch;
|
||||
|
||||
// now do in batches of 64
|
||||
while (rlen > 0) {
|
||||
this_batch = sizeof(tx_buf);
|
||||
if (this_batch > rlen) this_batch = rlen;
|
||||
|
||||
sp_spi_op_read(this_batch, tx_buf);
|
||||
writepkt(ud, tx_buf, this_batch);
|
||||
|
||||
rlen -= this_batch;
|
||||
}
|
||||
flushpkt(ud);
|
||||
}
|
||||
|
||||
// that's it!
|
||||
sp_spi_op_end(selchip);
|
||||
nresp = 0; // we sent our own response manually
|
||||
} break;
|
||||
case S_CMD_SPI_RDWR: {
|
||||
uint32_t len;
|
||||
|
||||
// clang-format off
|
||||
len = (uint32_t)read_byte();
|
||||
len |= (uint32_t)read_byte() << 8;
|
||||
len |= (uint32_t)read_byte() << 16;
|
||||
// clang-format on
|
||||
|
||||
sp_spi_op_begin(selchip);
|
||||
size_t this_batch;
|
||||
|
||||
// first, do a batch of 63, because we also need to send an ACK byte
|
||||
this_batch = sizeof(tx_buf) - 1;
|
||||
if (this_batch > len) this_batch = len;
|
||||
for (size_t i = 0; i < this_batch; ++i) rx_buf[i] = read_byte();
|
||||
sp_spi_op_read_write(this_batch, &tx_buf[1], rx_buf);
|
||||
tx_buf[0] = S_ACK;
|
||||
writepkt(ud, tx_buf, this_batch + 1);
|
||||
len -= this_batch;
|
||||
|
||||
// now do in batches of 64
|
||||
while (len > 0) {
|
||||
this_batch = sizeof(tx_buf);
|
||||
if (this_batch > len) this_batch = len;
|
||||
|
||||
for (size_t i = 0; i < this_batch; ++i) rx_buf[i] = read_byte();
|
||||
sp_spi_op_read_write(this_batch, tx_buf, rx_buf);
|
||||
writepkt(ud, tx_buf, this_batch);
|
||||
|
||||
len -= this_batch;
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
tx_buf[0] = S_NAK;
|
||||
nresp = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cdc_serprog_task(void) {
|
||||
uint8_t cmd = read_byte_cdc();
|
||||
handle_cmd(cmd, CDC_N_SERPROG, read_byte_cdc,
|
||||
tud_cdc_n_write, tud_cdc_n_write_flush, NULL);
|
||||
|
||||
if (nresp > 0) {
|
||||
tud_cdc_n_write(CDC_N_SERPROG, tx_buf, nresp);
|
||||
|
@ -218,12 +299,32 @@ static void handle_cmd(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void cdc_serprog_task(void) { handle_cmd(); }
|
||||
|
||||
static void vnd_writepkt(int ud, const uint8_t* buf, uint32_t len) {
|
||||
(void)ud;
|
||||
|
||||
for (size_t i = 0; i < len; ++i) vnd_cfg_write_byte(buf[i]);
|
||||
}
|
||||
static void vnd_flushpkt(int ud) {
|
||||
(void)ud;
|
||||
|
||||
vnd_cfg_write_flush();
|
||||
}
|
||||
void sp_spi_bulk_cmd(void) {
|
||||
// TODO
|
||||
vnd_cfg_write_resp(cfg_resp_illcmd, 0, NULL);
|
||||
uint8_t cmd = read_byte_cdc();
|
||||
handle_cmd(cmd, VND_N_CFG, vnd_cfg_read_byte, vnd_writepkt, vnd_flushpkt,
|
||||
vnd_cfg_write_resp);
|
||||
|
||||
if (nresp > 0) {
|
||||
enum cfg_resp stat = cfg_resp_ok;
|
||||
if (nresp == 1 && tx_buf[0] == S_NAK) // invalid cmd
|
||||
stat = cfg_resp_illcmd;
|
||||
|
||||
vnd_cfg_write_resp(stat, nresp, tx_buf);
|
||||
} else {
|
||||
// hanlded using the writehdr callback
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DBOARD_HAS_SERPROG */
|
||||
#endif /* DBOARD_HAS_SPI */
|
||||
|
||||
|
|
|
@ -27,35 +27,57 @@ enum serprog_cmd {
|
|||
S_CMD_S_SPI_FREQ = 0x14,
|
||||
S_CMD_S_PINSTATE = 0x15,
|
||||
|
||||
S_CMD_MAGIC_SETTINGS = 0x53
|
||||
// TODO: upstream this to flashrom? could be useful to others maybe
|
||||
S_CMD_Q_NUM_CS = 0x40,
|
||||
S_CMD_S_SPI_FLAGS = 0x41,
|
||||
// number of chip (well, bitflags) to use when asserting/deasserting the chip select line
|
||||
S_CMD_S_SPI_CHIPN = 0x42,
|
||||
S_CMD_SPI_READ = 0x43,
|
||||
S_CMD_SPI_WRITE = 0x44,
|
||||
// as opposed to S_CMD_SPIOP, this one is full-duplex instead of half-duplex
|
||||
S_CMD_SPI_RDWR = 0x45,
|
||||
};
|
||||
|
||||
enum serprog_response { S_ACK = 0x06, S_NAK = 0x15 };
|
||||
|
||||
enum serprog_flags {
|
||||
S_FLG_CPOL = 1<<0, // 1: clock polarity 1, else clkpol 0
|
||||
S_FLG_CPHA = 1<<1, // 1: clock phase 1, else clkpha 1
|
||||
S_FLG_16BIT = 1<<2, // 1: 16-bit transfers, else 8-bit xfers
|
||||
};
|
||||
|
||||
#define SERPROG_IFACE_VERSION 0x0001
|
||||
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
#ifdef DBOARD_HAS_SPI
|
||||
/* functions to be implemented by the BSP */
|
||||
uint32_t /*freq_applied*/ sp_spi_set_freq(uint32_t freq_wanted);
|
||||
|
||||
void sp_spi_set_flags(enum serprog_flags flags);
|
||||
__attribute__((__const__)) int sp_spi_get_num_cs(void);
|
||||
|
||||
void sp_spi_init(void);
|
||||
void sp_spi_deinit(void);
|
||||
void sp_spi_cs_deselect(void);
|
||||
void sp_spi_cs_select(void);
|
||||
void sp_spi_op_begin(void);
|
||||
void sp_spi_op_write(uint32_t write_len, const uint8_t* write_data);
|
||||
void sp_spi_op_read(uint32_t read_len, uint8_t* read_data);
|
||||
void sp_spi_op_end(void);
|
||||
void sp_spi_cs_deselect(uint8_t csflags);
|
||||
void sp_spi_cs_select(uint8_t csflags);
|
||||
|
||||
static inline void sp_spi_op_do(
|
||||
uint32_t write_len, const uint8_t* write_data, uint32_t read_len, uint8_t* read_data) {
|
||||
void sp_spi_op_write(uint32_t write_len, const void* write_data);
|
||||
void sp_spi_op_read(uint32_t read_len, void* read_data);
|
||||
void sp_spi_op_read_write(uint32_t len, void* read_data, const void* write_data);
|
||||
|
||||
/* serprog-specific */
|
||||
void sp_spi_op_begin(uint8_t csflags);
|
||||
void sp_spi_op_end(uint8_t csflags);
|
||||
// half-duplex
|
||||
/*static inline void sp_spi_op_do(uint32_t write_len, const uint8_t* write_data,
|
||||
uint32_t read_len, uint8_t* read_data) {
|
||||
sp_spi_op_begin();
|
||||
sp_spi_op_write(write_len, write_data);
|
||||
sp_spi_op_write(read_len, read_data);
|
||||
sp_spi_op_end();
|
||||
}
|
||||
}*/
|
||||
|
||||
/* protocol handling functions */
|
||||
__attribute__((__const__)) uint32_t sp_spi_get_buf_limit(void); // rdnmaxlen, wrnmaxlen
|
||||
void cdc_serprog_init(void);
|
||||
void cdc_serprog_deinit(void);
|
||||
void cdc_serprog_task(void);
|
||||
|
|
|
@ -105,7 +105,6 @@ int tempsense_do_read(int length, uint8_t* buf) {
|
|||
int i;
|
||||
for (i = 0; i < length; ++i, ++index) {
|
||||
switch (reg) {
|
||||
// TODO: big or little endian? seems to be big
|
||||
case cap: buf[index] = 0; break;
|
||||
case config:
|
||||
if (index == 0)
|
||||
|
@ -273,21 +272,25 @@ void tempsense_bulk_cmd(void) {
|
|||
resp[0] = temp & 0xff;
|
||||
resp[1] = (temp >> 8) & 0xff;
|
||||
vnd_cfg_write_resp(cfg_resp_ok, 2, resp);
|
||||
break;
|
||||
case tcmd_get_lower:
|
||||
temp = tempsense_dev_get_lower();
|
||||
resp[0] = temp & 0xff;
|
||||
resp[1] = (temp >> 8) & 0xff;
|
||||
vnd_cfg_write_resp(cfg_resp_ok, 2, resp);
|
||||
break;
|
||||
case tcmd_get_upper:
|
||||
temp = tempsense_dev_get_upper();
|
||||
resp[0] = temp & 0xff;
|
||||
resp[1] = (temp >> 8) & 0xff;
|
||||
vnd_cfg_write_resp(cfg_resp_ok, 2, resp);
|
||||
break;
|
||||
case tcmd_get_crit:
|
||||
temp = tempsense_dev_get_crit();
|
||||
resp[0] = temp & 0xff;
|
||||
resp[1] = (temp >> 8) & 0xff;
|
||||
vnd_cfg_write_resp(cfg_resp_ok, 2, resp);
|
||||
break;
|
||||
default:
|
||||
vnd_cfg_write_resp(cfg_resp_illcmd, 0, NULL);
|
||||
break;
|
||||
|
|
|
@ -259,7 +259,7 @@ void i2ctu_bulk_cmd(void) {
|
|||
handle_read(&cmd);
|
||||
us = cmd.len;
|
||||
if (us > sizeof txbuf) us = sizeof txbuf;
|
||||
vnd_cfg_write_resp(cfg_resp_ok, us, txbuf);
|
||||
vnd_cfg_write_resp(cfg_resp_ok, (uint32_t)us, txbuf);
|
||||
} else if (cmd.len == 0) {
|
||||
handle_probe(&cmd);
|
||||
txbuf[0] = status;
|
||||
|
|
|
@ -52,7 +52,7 @@ void modes_switch(uint8_t newmode);
|
|||
|
||||
extern int mode_current_id;
|
||||
extern int mode_next_id;
|
||||
extern const struct mode* mode_list[16];
|
||||
extern const struct mode* const mode_list[16];
|
||||
#define mode_default (mode_list[1])
|
||||
#define mode_current (((mode_current_id)==-1)?NULL:(mode_list[mode_current_id]))
|
||||
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
// vim: set et:
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "mode.h"
|
||||
|
||||
extern struct mode m_01_default/*, m_02_default2*/;
|
||||
|
||||
// clang-format off
|
||||
const struct mode* mode_list[16] = {
|
||||
const struct mode* const mode_list[16] = {
|
||||
NULL, // dummy 0 entry
|
||||
&m_01_default,
|
||||
&m_01_default, // entry 1 CANNOT be NULL!
|
||||
//&m_02_default2,
|
||||
NULL, // terminating entry
|
||||
};
|
||||
|
@ -36,7 +38,7 @@ void modes_init(void) {
|
|||
mode_current_id = &mode_default - mode_list;
|
||||
mode_next_id = -1;
|
||||
|
||||
if (!mode_default) return; // TODO: panic here
|
||||
//if (!mode_default) return;
|
||||
|
||||
// clang-format off
|
||||
#if CFG_TUD_HID > 0
|
||||
|
|
|
@ -56,19 +56,28 @@ void vnd_cfg_write_byte(uint8_t v) {
|
|||
tx_buf[txpos] = v;
|
||||
++txpos;
|
||||
}
|
||||
void vnd_cfg_write_resp(enum cfg_resp stat, uint16_t len, const void* data) {
|
||||
if (len > 0x7fff) len = 0x7fff; // aaaaaaaaaaaaaaaaa // TODO: throw some kind of error
|
||||
|
||||
vnd_cfg_write_byte(stat);
|
||||
if (len < 0x80) {
|
||||
vnd_cfg_write_byte(len);
|
||||
} else {
|
||||
vnd_cfg_write_byte((len & 0x7f) | 0x80);
|
||||
vnd_cfg_write_byte(len >> 7);
|
||||
void vnd_cfg_write_resp(enum cfg_resp stat, uint32_t len, const void* data) {
|
||||
if (len > 0x3fffff) {
|
||||
printf("W: truncating response length from 0x%lx to 0x3fffff\n", len);
|
||||
len = 0x3fffff;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
vnd_cfg_write_byte(((const uint8_t*)data)[i]);
|
||||
vnd_cfg_write_byte(stat);
|
||||
if (len < (1<<7)) {
|
||||
vnd_cfg_write_byte(len);
|
||||
} else if (len < (1<<14)) {
|
||||
vnd_cfg_write_byte((len & 0x7f) | 0x80);
|
||||
vnd_cfg_write_byte((len >> 7) & 0x7f);
|
||||
} else {
|
||||
vnd_cfg_write_byte((len & 0x7f) | 0x80);
|
||||
vnd_cfg_write_byte(((len >> 7) & 0x7f) | 0x80);
|
||||
vnd_cfg_write_byte(((len >> 14) & 0x7f));
|
||||
}
|
||||
|
||||
if (data) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
vnd_cfg_write_byte(((const uint8_t*)data)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
vnd_cfg_write_flush();
|
||||
|
|
|
@ -43,7 +43,7 @@ enum cfg_resp {
|
|||
uint8_t vnd_cfg_read_byte (void);
|
||||
void vnd_cfg_write_flush(void);
|
||||
void vnd_cfg_write_byte(uint8_t v);
|
||||
void vnd_cfg_write_resp(enum cfg_resp stat, uint16_t len, const void* data);
|
||||
void vnd_cfg_write_resp(enum cfg_resp stat, uint32_t len, const void* data);
|
||||
|
||||
/*
|
||||
* wire protocol:
|
||||
|
|
Loading…
Reference in New Issue