#include #include #include #include #include #include "encoding.h" #include "platform.h" #include "plic/plic_driver.h" #include "eos.h" #include "msgq.h" #include "event.h" #include "interrupt.h" #include "net.h" #include "spi.h" #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) #define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) #define SPI_BUFQ_IDX_MASK(IDX) ((IDX) & (SPI_SIZE_BUFQ - 1)) static volatile uint8_t spi_res = 0; static volatile uint8_t spi_res_next = 0; static volatile unsigned char *spi_res_buf = NULL; static EOSMsgQ spi_sndq; static EOSMsgItem spi_sndq_array[SPI_SIZE_BUFQ]; static SPIBufQ spi_bufq; static unsigned char spi_bufq_array[SPI_SIZE_BUFQ][SPI_SIZE_BUF]; static int spi_bufq_push(unsigned char *buffer) { spi_bufq.array[SPI_BUFQ_IDX_MASK(spi_bufq.idx_w++)] = buffer; } static unsigned char *spi_bufq_pop(void) { if (spi_bufq.idx_r == spi_bufq.idx_w) return NULL; return spi_bufq.array[SPI_BUFQ_IDX_MASK(spi_bufq.idx_r++)]; } static volatile uint8_t spi_rdy = 0; static volatile uint8_t spi_cts = 0; static volatile uint8_t spi_rts = 0; static SPIBuffer spi_buffer; static void spi_reset(void) { int i; volatile uint32_t r; spi_cts = 0; // before starting a transaction, set SPI peripheral to desired mode SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD; while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); SPI1_REG(SPI_REG_TXFIFO) = 0; while ((r = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; } static void spi_xchg(unsigned char cmd, unsigned char *buffer, uint16_t len) { volatile uint32_t r1, r2; spi_cts = 0; spi_buffer.buffer = buffer; spi_buffer.len_rx = 0; spi_buffer.idx_tx = 0; spi_buffer.idx_rx = 0; if (spi_res_buf == NULL) { if (cmd & EOS_NET_CMD_FLAG_ONEW) { spi_res_next = 1; } else if (spi_res) { cmd |= EOS_NET_CMD_FLAG_ONEW; } } else if (cmd & EOS_NET_CMD_FLAG_ONEW) { cmd &= ~EOS_NET_CMD_FLAG_ONEW; } // before starting a transaction, set SPI peripheral to desired mode SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD; while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); SPI1_REG(SPI_REG_TXFIFO) = ((cmd << 3) | (len >> 8)) & 0xFF; while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); SPI1_REG(SPI_REG_TXFIFO) = len & 0xFF; while ((r1 = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); while ((r2 = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); if (cmd & EOS_NET_CMD_FLAG_ONEW) { r1 = 0; r2 = 0; } spi_buffer.cmd = ((r1 & 0xFF) >> 3); spi_buffer.len_rx = ((r1 & 0x07) << 8); spi_buffer.len_rx |= (r2 & 0xFF); spi_buffer.len = MAX(len, spi_buffer.len_rx); // Work around esp32 bug if (spi_buffer.len < 6) { spi_buffer.len = 6; } else if ((spi_buffer.len + 2) % 4 != 0) { spi_buffer.len = ((spi_buffer.len + 2)/4 + 1) * 4 - 2; } SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(SPI_SIZE_CHUNK/2); SPI1_REG(SPI_REG_RXCTRL) = SPI_RXWM(SPI_SIZE_CHUNK - 1); SPI1_REG(SPI_REG_IE) = SPI_IP_TXWM | SPI_IP_RXWM; } static int spi_xchg_next(unsigned char *_buffer) { unsigned char cmd; unsigned char *buffer = NULL; uint16_t len; eos_msgq_pop(&spi_sndq, &cmd, &buffer, &len); if (cmd) { spi_xchg(cmd, buffer, len); } else if (spi_rts) { if (_buffer == NULL) _buffer = spi_bufq_pop(); if (_buffer) { spi_xchg(0, _buffer, 0); return 0; } } return 1; } static void spi_xchg_handler(void) { int i; if (SPI1_REG(SPI_REG_IP) & SPI_IP_TXWM) { uint16_t sz_chunk = MIN(spi_buffer.len - spi_buffer.idx_tx, SPI_SIZE_CHUNK); for (i=0; i