From 0f4566d0e7f80fae9619c26f9a8e1eba9f884315 Mon Sep 17 00:00:00 2001 From: sys64738 Date: Sun, 4 Jul 2021 16:09:45 +0200 Subject: [PATCH] spi stuff --- bsp/rp2040/m_default/bsp-feature.h | 4 +- bsp/rp2040/m_default/spi_serprog.c | 70 +++++++-- src/m_default/_default.c | 30 ++-- src/m_default/cdc_serprog.c | 239 ++++++++++++++++++++--------- src/m_default/serprog.h | 44 ++++-- src/m_default/tempsensor.c | 5 +- src/m_default/vnd_i2ctinyusb.c | 2 +- src/mode.h | 2 +- src/modeset.c | 8 +- src/vnd_cfg.c | 31 ++-- src/vnd_cfg.h | 2 +- 11 files changed, 310 insertions(+), 127 deletions(-) diff --git a/bsp/rp2040/m_default/bsp-feature.h b/bsp/rp2040/m_default/bsp-feature.h index e059f85..439f020 100644 --- a/bsp/rp2040/m_default/bsp-feature.h +++ b/bsp/rp2040/m_default/bsp-feature.h @@ -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 diff --git a/bsp/rp2040/m_default/spi_serprog.c b/bsp/rp2040/m_default/spi_serprog.c index 44147a1..dcc7c55 100644 --- a/bsp/rp2040/m_default/spi_serprog.c +++ b/bsp/rp2040/m_default/spi_serprog.c @@ -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); + } } diff --git a/src/m_default/_default.c b/src/m_default/_default.c index b01ac38..aad22b9 100644 --- a/src/m_default/_default.c +++ b/src/m_default/_default.c @@ -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[] = { diff --git a/src/m_default/cdc_serprog.c b/src/m_default/cdc_serprog.c index ff90598..5850dcf 100644 --- a/src/m_default/cdc_serprog.c +++ b/src/m_default/cdc_serprog.c @@ -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 */ diff --git a/src/m_default/serprog.h b/src/m_default/serprog.h index 7c06bd0..39f8981 100644 --- a/src/m_default/serprog.h +++ b/src/m_default/serprog.h @@ -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); diff --git a/src/m_default/tempsensor.c b/src/m_default/tempsensor.c index f7230c1..b68dcb2 100644 --- a/src/m_default/tempsensor.c +++ b/src/m_default/tempsensor.c @@ -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; diff --git a/src/m_default/vnd_i2ctinyusb.c b/src/m_default/vnd_i2ctinyusb.c index 4661b28..533022d 100644 --- a/src/m_default/vnd_i2ctinyusb.c +++ b/src/m_default/vnd_i2ctinyusb.c @@ -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; diff --git a/src/mode.h b/src/mode.h index 8af69a4..6256eba 100644 --- a/src/mode.h +++ b/src/mode.h @@ -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])) diff --git a/src/modeset.c b/src/modeset.c index f31f00c..8af2b6e 100644 --- a/src/modeset.c +++ b/src/modeset.c @@ -1,13 +1,15 @@ // vim: set et: +#include + #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 diff --git a/src/vnd_cfg.c b/src/vnd_cfg.c index 5cbb328..623cebf 100644 --- a/src/vnd_cfg.c +++ b/src/vnd_cfg.c @@ -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(); diff --git a/src/vnd_cfg.h b/src/vnd_cfg.h index b39a751..c6c5346 100644 --- a/src/vnd_cfg.h +++ b/src/vnd_cfg.h @@ -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: