mirror of
https://github.com/garrettsworkshop/ROMBUSDriver.git
synced 2025-02-09 00:31:01 +00:00
130 lines
3.5 KiB
C
130 lines
3.5 KiB
C
#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; }
|