ROMBUSDriver/spi.c

130 lines
3.5 KiB
C
Raw Normal View History

2022-12-18 13:46:39 +00:00
#include "spi.h"
#include "spi_hal.h"
static int _search_lt(char *buf, int stride, int threshold) {
for (int i = 1; i < 256; i++) {
if (buf[i * stride] < threshold) { return 1; }
}
return 0;
}
int _spi_hal_rx8_nops, _spi_hal_tx8_nops;
int _spi_hal_rx16_nops, _spi_hal_tx16_nops;
int _spi_hal_rxtx8_nops;
short *_spi_reg_rx16;
char *_spi_reg_tx16;
short *_spi_reg_rd16;
int spi_init(int swap) {
short buf16[256];
char *buf8 = (char*)&buf16;
for (int i = 0; i < 8; i++) {
spi_hal_rx8(SPI_REG_TIMER8, buf8, 256, i);
_spi_hal_rx8_nops = i;
_spi_hal_tx8_nops = i > 0 ? i - 1 : 0;
if (!_search_lt(buf8, 1, 8)) { break; }
}
for (int i = 0; i < 16; i++) {
spi_hal_rx16(SPI_REG_TIMER16, buf16, 256, i);
_spi_hal_rx16_nops = i;
_spi_hal_tx16_nops = i > 0 ? i - 1 : 0;
if (!_search_lt(buf8, 2, 8)) { break; }
}
for (int i = 0; i < 8; i++) {
spi_hal_rxtx8(SPI_REG_EMPTY, SPI_REG_TIMER16, buf8, buf8, 256, i);
_spi_hal_rxtx8_nops = i;
if (!_search_lt(buf8, 1, 8)) { break; }
}
_spi_reg_rx16 = swap ? SPI_REG_RX16S : SPI_REG_RX16;
_spi_reg_tx16 = swap ? SPI_REG_TX16S : SPI_REG_TX16;
_spi_reg_rd16 = swap ? SPI_REG_RD16S : SPI_REG_RD16;
return 0;
}
void spi_cs(int cs) {
if (cs) { SPI_REG_CSR_SET_CS(); }
else { SPI_REG_CSR_CLR_CS(); }
}
char spi_txrx8_slow(char txd) {
char rxd = 0;
for (int i = 7; i >= 0; i--) {
spi_delay(64);
SPI_REG_CSR_CLR_SCK();
spi_delay(64);
SPI_REG_SET_MOSI((txd >> i) & 1);
rxd = (rxd << 1) | SPI_REG_CSR_GET_MISO();
SPI_REG_CSR_SET_SCK();
}
spi_delay(64);
SPI_REG_CSR_CLR_SCK();
return rxd;
}
char spi_txrx8(char txd) {
spi_hal_tx8(SPI_REG_TX8, &txd, 1, _spi_hal_tx8_nops);
return *SPI_REG_RD8;
}
char spi_rxtx8(char txd) {
char rxd = *SPI_REG_RD8;
spi_hal_tx8(SPI_REG_TX8, &txd, 1, _spi_hal_tx8_nops);
return rxd;
}
#define UNROLL_LENGTH 5
void spi_rx(char txd, char *rxb, unsigned int length) {
if (length == 0) { return; } // Return if length 0
// Word-align rx pointer by transferring 0/1 bytes
if ((int)rxb & 1) {
*(rxb++) = spi_rxtx8(txd);
length--;
}
// Set tx pattern
reg_write16(SPI_REG_ST16, smear8to32(txd));
// Transfer all but 0-65 bytes
for (int i = length >> (UNROLL_LENGTH +1); i > 0; i--) {
// Transfer 2^UNROLL_LENGTH words (2 * 2^UNROLL_LENGTH bytes)
spi_hal_rx16(_spi_reg_rx16, rxb, UNROLL_LENGTH, _spi_hal_rx16_nops);
}
// Transfer remaining 1-32 words (2-64 bytes)
spi_hal_rx16(_spi_reg_rx16, rxb, length >> 1, _spi_hal_rx16_nops);
// Transfer remaining byte if any
if (length & 1) { *(rxb++) = spi_rxtx8(txd); }
}
void spi_tx(char *txb, unsigned int length) {
if (length == 0) { return; } // Return if length 0
// Word-align tx pointer by transferring 0/1 bytes
if ((int)txb & 1) {
spi_rxtx8(*(txb++));
length--;
}
// Transfer all but 0-65 bytes
for (; length > UNROLL_LENGTH; length -= UNROLL_LENGTH) {
spi_hal_tx16(_spi_reg_tx16, txb, UNROLL_LENGTH, _spi_hal_tx16_nops);
}
// Transfer remaining 1-32 words (2-64 bytes)
spi_hal_tx16(_spi_reg_tx16, txb, length >> 1, _spi_hal_tx16_nops);
// Transfer remaining byte if any
if (length & 1) { spi_rxtx8(*(txb++)); }
}
char spi_rd8() { return *SPI_REG_RD8; }
short spi_rd16() { return *_spi_reg_rd16; }