SPI DMA functions.
Adds 6 new functions: DMA Transfer, DMA 8bit send, DMA 16bit send, write 16 bit int. and mode change to change between 8bit and 16 bit transfer.
This commit is contained in:
parent
331a02e296
commit
e13b9a0709
|
@ -183,6 +183,19 @@ void SPIClass::setBitOrder(BitOrder bitOrder)
|
|||
this->begin();
|
||||
}
|
||||
|
||||
/* Victor Perez. Added to test changing datasize from 8 to 16 bit modes on the fly.
|
||||
* Input parameter should be SPI_CR1_DFF set to 0 or 1 on a 32bit word.
|
||||
*
|
||||
*/
|
||||
void SPIClass::setDataSize(uint32 datasize)
|
||||
{
|
||||
uint32 cr1 = this->spi_d->regs->CR1;
|
||||
datasize &= SPI_CR1_DFF;
|
||||
cr1 &= ~(SPI_CR1_DFF);
|
||||
cr1 |= datasize;
|
||||
this->spi_d->regs->CR1 = cr1;
|
||||
}
|
||||
|
||||
void SPIClass::setDataMode(uint8_t dataMode)
|
||||
{
|
||||
/* Notes. As far as I can tell, the AVR numbers for dataMode appear to match the numbers required by the STM32
|
||||
|
@ -297,6 +310,20 @@ void SPIClass::read(uint8 *buf, uint32 len) {
|
|||
}
|
||||
}
|
||||
|
||||
void SPIClass::write(uint16 data) {
|
||||
// this->write(&data, 1);
|
||||
|
||||
/* Added for 16bit data Victor Perez. Roger Clark
|
||||
* Improved speed by just directly writing the single byte to the SPI data reg and wait for completion, * by taking the Tx code from transfer(byte)
|
||||
* The original method, of calling write(*data, length) .
|
||||
* This almost doubles the speed of this function.
|
||||
*/
|
||||
|
||||
spi_tx_reg(this->spi_d, data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
|
||||
while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
}
|
||||
|
||||
void SPIClass::write(uint8 byte) {
|
||||
// this->write(&byte, 1);
|
||||
|
||||
|
@ -329,35 +356,116 @@ uint8 SPIClass::transfer(uint8 byte) {
|
|||
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
return b;
|
||||
}
|
||||
|
||||
uint8 SPIClass::DMATransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint32 length) {
|
||||
/* Roger Clark and Victor Perez, 2015
|
||||
* Performs a DMA SPI transfer with at least a receive buffer.
|
||||
* If a TX buffer is not provided, FF is sent over and over for the lenght of the transfer.
|
||||
* On exit TX buffer is not modified, and RX buffer cotains the received data.
|
||||
* Still in progress.
|
||||
*/
|
||||
uint8 SPIClass::dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length) {
|
||||
if (length == 0) return 0;
|
||||
uint8 b;
|
||||
|
||||
if (spi_is_rx_nonempty(this->spi_d) == 1) b = spi_rx_reg(this->spi_d); //Clear the RX buffer in case a byte is waiting on it.
|
||||
dma1_ch3_Active=true;
|
||||
|
||||
dma_init(DMA1);
|
||||
|
||||
dma_attach_interrupt(DMA1, DMA_CH2, &SPIClass::DMA1_CH3_Event);
|
||||
|
||||
dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
|
||||
|
||||
// RX
|
||||
spi_rx_dma_enable(SPI1);
|
||||
dma_setup_transfer(DMA1, DMA_CH2, &SPI1->regs->DR, DMA_SIZE_8BITS,
|
||||
receiveBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT | DMA_TRNS_ERR));// receive buffer DMA
|
||||
receiveBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA
|
||||
dma_set_num_transfers(DMA1, DMA_CH2, length);
|
||||
|
||||
|
||||
// TX
|
||||
spi_tx_dma_enable(SPI1);
|
||||
spi_tx_dma_enable(SPI1);
|
||||
if (!transmitBuf) {
|
||||
static uint8_t ff = 0XFF;
|
||||
transmitBuf = &ff;
|
||||
dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS,
|
||||
transmitBuf, DMA_SIZE_8BITS, (DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit FF repeatedly
|
||||
}
|
||||
else {
|
||||
dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS,
|
||||
transmitBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit buffer DMA
|
||||
dma_set_num_transfers(DMA1, DMA_CH3, length);
|
||||
|
||||
transmitBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit buffer DMA
|
||||
}
|
||||
dma_set_num_transfers(DMA1, DMA_CH3, length);
|
||||
|
||||
dma_enable(DMA1, DMA_CH2);// enable receive
|
||||
dma_enable(DMA1, DMA_CH3);// enable transmit
|
||||
|
||||
while (dma1_ch3_Active);
|
||||
// while (dma1_ch3_Active);
|
||||
// if (receiveBuf) {
|
||||
uint32_t m = millis();
|
||||
while (dma1_ch3_Active) {
|
||||
if ((millis() - m) > 100) {
|
||||
dma1_ch3_Active = 0;
|
||||
b = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// }
|
||||
while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
dma_disable(DMA1, DMA_CH3);
|
||||
dma_disable(DMA1, DMA_CH2);
|
||||
spi_rx_dma_disable(SPI1);
|
||||
spi_tx_dma_disable(SPI1);
|
||||
return b;
|
||||
}
|
||||
|
||||
/* Roger Clark and Victor Perez, 2015
|
||||
* Performs a DMA SPI send using a TX buffer.
|
||||
* On exit TX buffer is not modified.
|
||||
* Still in progress.
|
||||
*/
|
||||
uint8 SPIClass::dmaSend(uint8 *transmitBuf, uint16 length, bool minc) {
|
||||
if (length == 0) return 0;
|
||||
uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
|
||||
uint8 b;
|
||||
dma1_ch3_Active=true;
|
||||
dma_init(DMA1);
|
||||
dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
|
||||
|
||||
// TX
|
||||
spi_tx_dma_enable(SPI1);
|
||||
dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS,
|
||||
transmitBuf, DMA_SIZE_8BITS, flags);// Transmit buffer DMA
|
||||
dma_set_num_transfers(DMA1, DMA_CH3, length);
|
||||
dma_enable(DMA1, DMA_CH3);// enable transmit
|
||||
|
||||
while (dma1_ch3_Active);
|
||||
while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..."
|
||||
b = spi_rx_reg(this->spi_d); // "... and read the last received data."
|
||||
while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
dma_disable(DMA1, DMA_CH3);
|
||||
spi_tx_dma_disable(SPI1);
|
||||
return b;
|
||||
}
|
||||
|
||||
uint8 SPIClass::dmaSend(uint16 *transmitBuf, uint16 length, bool minc) {
|
||||
if (length == 0) return 0;
|
||||
uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
|
||||
uint8 b;
|
||||
dma1_ch3_Active=true;
|
||||
dma_init(DMA1);
|
||||
dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
|
||||
|
||||
// TX
|
||||
spi_tx_dma_enable(SPI1);
|
||||
dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_16BITS,
|
||||
transmitBuf, DMA_SIZE_16BITS, flags);// Transmit buffer DMA
|
||||
dma_set_num_transfers(DMA1, DMA_CH3, length);
|
||||
dma_enable(DMA1, DMA_CH3);// enable transmit
|
||||
|
||||
while (dma1_ch3_Active);
|
||||
while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..."
|
||||
b = spi_rx_reg(this->spi_d); // "... and read the last received data."
|
||||
while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
dma_disable(DMA1, DMA_CH3);
|
||||
spi_tx_dma_disable(SPI1);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
|
|
@ -183,6 +183,12 @@ public:
|
|||
void attachInterrupt(void);
|
||||
void detachInterrupt(void);
|
||||
|
||||
/* Victor Perez. Added to change datasize from 8 to 16 bit modes on the fly.
|
||||
* Input parameter should be SPI_CR1_DFF set to 0 or 1 on a 32bit word.
|
||||
* Requires an added function spi_data_size on STM32F1 / cores / maple / libmaple / spi.c
|
||||
*/
|
||||
void setDataSize(uint32 ds);
|
||||
|
||||
|
||||
/*
|
||||
* I/O
|
||||
|
@ -211,6 +217,12 @@ public:
|
|||
*/
|
||||
void write(uint8 data);
|
||||
|
||||
/**
|
||||
* @brief Transmit a half word.
|
||||
* @param data to transmit.
|
||||
*/
|
||||
void write(uint16 data);
|
||||
|
||||
/**
|
||||
* @brief Transmit multiple bytes.
|
||||
* @param buffer Bytes to transmit.
|
||||
|
@ -227,8 +239,40 @@ public:
|
|||
* @return Next unread byte.
|
||||
*/
|
||||
uint8 transfer(uint8 data);
|
||||
|
||||
/**
|
||||
* @brief Sets up a DMA Transfer for "length" bytes.
|
||||
*
|
||||
* This function transmits and receives to buffers.
|
||||
*
|
||||
* @param transmitBuf buffer Bytes to transmit. If passed as 0, it sends FF repeatedly for "length" bytes
|
||||
* @param receiveBuf buffer Bytes to save received data.
|
||||
* @param length Number of bytes in buffer to transmit.
|
||||
*/
|
||||
uint8 dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length);
|
||||
|
||||
uint8 DMATransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint32 length);
|
||||
/**
|
||||
* @brief Sets up a DMA Transmit for bytes.
|
||||
*
|
||||
* This function transmits and does not care about the RX fifo.
|
||||
*
|
||||
* @param transmitBuf buffer Bytes to transmit,
|
||||
* @param length Number of bytes in buffer to transmit.
|
||||
* @param minc Set to use Memory Increment mode, clear to use Circular mode.
|
||||
*/
|
||||
uint8 dmaSend(uint8 *transmitBuf, uint16 length, bool minc = 1);
|
||||
|
||||
/**
|
||||
* @brief Sets up a DMA Transmit for half words.
|
||||
* SPI PERFIPHERAL MUST BE SET TO 16 BIT MODE BEFORE
|
||||
*
|
||||
* This function transmits and does not care about the RX fifo.
|
||||
*
|
||||
* @param data buffer half words to transmit,
|
||||
* @param length Number of bytes in buffer to transmit.
|
||||
* @param minc Set to use Memory Increment mode (default if blank), clear to use Circular mode.
|
||||
*/
|
||||
uint8 dmaSend(uint16 *transmitBuf, uint16 length, bool minc = 1);
|
||||
|
||||
/*
|
||||
* Pin accessors
|
||||
|
@ -302,8 +346,8 @@ private:
|
|||
|
||||
static inline void DMA1_CH3_Event() {
|
||||
dma1_ch3_Active = 0;
|
||||
dma_disable(DMA1, DMA_CH3);
|
||||
dma_disable(DMA1, DMA_CH2);
|
||||
// dma_disable(DMA1, DMA_CH3);
|
||||
// dma_disable(DMA1, DMA_CH2);
|
||||
|
||||
// To Do. Need to wait for
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue