int spi_tx(int port, const uint8_t* buffer, int len, int block, int unknown) { if(port > (NUM_SPIPORTS - 1)) { return -1; } SET_REG(SPIRegs[port].control, GET_REG(SPIRegs[port].control) | (1 << 2)); SET_REG(SPIRegs[port].control, GET_REG(SPIRegs[port].control) | (1 << 3)); spi_info[port].txBuffer = buffer; if(len > MAX_TX_BUFFER) spi_info[port].txCurrentLen = MAX_TX_BUFFER; else spi_info[port].txCurrentLen = len; spi_info[port].txTotalLen = len; spi_info[port].txDone = FALSE; if(unknown == 0) { SET_REG(SPIRegs[port].cnt, 0); } spi_txdata(port, buffer, 0, spi_info[port].txCurrentLen); SET_REG(SPIRegs[port].control, 1); if(block) { while(!spi_info[port].txDone || GET_BITS(GET_REG(SPIRegs[port].status), 4, 4) != 0) { // yield } return len; } else { return 0; } }
int spi_tx(int port, const uint8_t* buffer, int len, int block, int unknown) { if(port >= SPICount || port < 0) return -1; SPIStruct *spi = &SPIData[port]; SET_REG(spi->registers->control, GET_REG(spi->registers->control) | (1 << 2)); SET_REG(spi->registers->control, GET_REG(spi->registers->control) | (1 << 3)); // Set len to number of words. len = (len + ((1<<spi->wordSize)-1)) >> spi->wordSize; spi->txBuffer = (void*)buffer; spi->rxBuffer = NULL; spi->txLength = len; if(len > MAX_TX_BUFFER) spi->txDone = MAX_TX_BUFFER; else spi->txDone = len; if(unknown == 0) { SET_REG(spi->registers->rxCount, 0); } else { spi->config |= 0x80; } //bufferPrintf("spi_tx(%d, %p, %d, %d, %d)\n", port, buffer, len, block, unknown); spi_txdata(spi, buffer, 0, spi->txDone); spi->config |= 0x200100; SET_REG(spi->registers->txCount, len); SET_REG(spi->registers->config, spi->config); SET_REG(spi->registers->control, 1); if(block) { while(spi->txBuffer != NULL || TX_BUFFER_LEFT(GET_REG(spi->registers->status)) > 0) task_yield(); return len; } else return 0; }
int spi_txrx(int port, const uint8_t* outBuffer, int outLen, uint8_t* inBuffer, int inLen, int block) { if(port > (NUM_SPIPORTS - 1)) { return -1; } SET_REG(SPIRegs[port].control, GET_REG(SPIRegs[port].control) | (1 << 2)); SET_REG(SPIRegs[port].control, GET_REG(SPIRegs[port].control) | (1 << 3)); spi_info[port].txBuffer = outBuffer; if(outLen > MAX_TX_BUFFER) spi_info[port].txCurrentLen = MAX_TX_BUFFER; else spi_info[port].txCurrentLen = outLen; spi_info[port].txTotalLen = outLen; spi_info[port].txDone = FALSE; spi_info[port].rxBuffer = inBuffer; spi_info[port].rxDone = FALSE; spi_info[port].rxCurrentLen = 0; spi_info[port].rxTotalLen = inLen; spi_info[port].counter = 0; spi_txdata(port, outBuffer, 0, spi_info[port].txCurrentLen); SET_REG(SPIRegs[port].cnt, (inLen + ((1<<spi_info[port].wordSize)-1)) >> spi_info[port].wordSize); SET_REG(SPIRegs[port].control, 1); if(block) { while(!spi_info[port].txDone || !spi_info[port].rxDone || GET_BITS(GET_REG(SPIRegs[port].status), 4, 4) != 0) { // yield } return inLen; } else { return 0; } }
static void spiIRQHandler(uint32_t port) { if(port > (NUM_SPIPORTS - 1)) { return; } uint32_t status = GET_REG(SPIRegs[port].status); if(status & (1 << 3)) { spi_info[port].counter++; } if(status & (1 << 1)) { while(TRUE) { // take care of tx if(spi_info[port].txBuffer != NULL) { if(spi_info[port].txCurrentLen < spi_info[port].txTotalLen) { int toTX = spi_info[port].txTotalLen - spi_info[port].txCurrentLen; int canTX = (MAX_TX_BUFFER - TX_BUFFER_LEFT(status)) << spi_info[port].wordSize; if(toTX > canTX) toTX = canTX; spi_txdata(port, spi_info[port].txBuffer, spi_info[port].txCurrentLen, spi_info[port].txCurrentLen+toTX); spi_info[port].txCurrentLen += toTX; } else { spi_info[port].txDone = TRUE; spi_info[port].txBuffer = NULL; } } dorx: // take care of rx if(spi_info[port].rxBuffer == NULL) break; int toRX = spi_info[port].rxTotalLen - spi_info[port].rxCurrentLen; int canRX = GET_BITS(status, 8, 4) << spi_info[port].wordSize; if(toRX > canRX) toRX = canRX; spi_rxdata(port, spi_info[port].rxBuffer, spi_info[port].rxCurrentLen, spi_info[port].rxCurrentLen+toRX); spi_info[port].rxCurrentLen += toRX; if(spi_info[port].rxCurrentLen < spi_info[port].rxTotalLen) break; spi_info[port].rxDone = TRUE; spi_info[port].rxBuffer = NULL; } } else if(status & (1 << 0)) { // jump into middle of the loop to handle rx only, stupidly goto dorx; } // acknowledge interrupt handling complete SET_REG(SPIRegs[port].status, status); }
static void spi_irq_handler(uint32_t i) { SPIStruct *spi = &SPIData[i]; uint32_t status = GET_REG(spi->registers->status); if((status & 1) && !(status & 0x400002)) goto do_rx; else if(!(status & 0x400002)) goto complete; while(TRUE) { if(spi->txBuffer != NULL) { uint32_t avail = MAX_TX_BUFFER - TX_BUFFER_LEFT(status); uint32_t left = spi->txLength - spi->txDone; if(avail > left) avail = left; spi_txdata(spi, spi->txBuffer, spi->txDone, spi->txDone + avail); spi->txDone += avail; if(spi->txDone >= spi->txLength) { spi->txBuffer = NULL; spi->txLength = 0; spi->txDone = 0; spi->config &=~ 0x200000; SET_REG(spi->registers->config, spi->config); } } do_rx: if(spi->rxBuffer != NULL) { uint32_t avail = RX_BUFFER_LEFT(status); uint32_t left = spi->rxLength - spi->rxDone; if(avail > left) avail = left; if(avail > 0) { spi_rxdata(spi, spi->rxBuffer, spi->rxDone, spi->rxDone + avail); spi->rxDone += avail; } spi->rxDone += avail; if(spi->rxDone >= spi->rxLength) { spi->rxBuffer = NULL; spi->rxLength = 0; spi->rxDone = 0; spi->config &=~ 0x81; SET_REG(spi->registers->config, spi->config); } } complete: if(spi->txBuffer == NULL && spi->rxBuffer == NULL) { spi->config &=~ 0x200181; SET_REG(spi->registers->config, spi->config); break; } else break; } SET_REG(spi->registers->status, status); }