SPI improvements: non-DMA block read + added DMA transfer functions
This commit is contained in:
parent
fc0ee24184
commit
bd3fb68a5e
|
@ -117,33 +117,16 @@ void dma_detach_interrupt(dma_dev *dev, dma_stream stream) {
|
|||
dev->handlers[stream].handler = NULL;
|
||||
}
|
||||
|
||||
const uint8 dma_isr_bits_shift[] = { 0, 6, 16, 22};
|
||||
|
||||
uint8 dma_get_isr_bits(dma_dev *dev, dma_stream stream) {
|
||||
if ( stream&0xFC ) return ((dev->regs->HISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d;
|
||||
else return ((dev->regs->LISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d;
|
||||
}
|
||||
|
||||
void dma_clear_isr_bits(dma_dev *dev, dma_stream stream) {
|
||||
switch (stream) {
|
||||
case 0:
|
||||
dev->regs->LIFCR|=0x0000003d;
|
||||
break;
|
||||
case 1:
|
||||
dev->regs->LIFCR|=0x00000f40;
|
||||
break;
|
||||
case 2:
|
||||
dev->regs->LIFCR|=0x003d0000;
|
||||
break;
|
||||
case 3:
|
||||
dev->regs->LIFCR|=0x0f400000;
|
||||
break;
|
||||
case 4:
|
||||
dev->regs->HIFCR|=0x0000003d;
|
||||
break;
|
||||
case 5:
|
||||
dev->regs->HIFCR|=0x00000f40;
|
||||
break;
|
||||
case 6:
|
||||
dev->regs->HIFCR|=0x003d0000;
|
||||
break;
|
||||
case 7:
|
||||
dev->regs->HIFCR|=0x0f400000;
|
||||
break;
|
||||
}
|
||||
if ( stream&0xFC ) dev->regs->HIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03];
|
||||
else dev->regs->LIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03];
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @file dma.h
|
||||
* @file dmaF4.h
|
||||
*
|
||||
* @author Marti Bolivar <mbolivar@leaflabs.com>;
|
||||
* Original implementation by Michael Hope
|
||||
|
@ -84,7 +84,7 @@ typedef struct dma_reg_map {
|
|||
* Register bit definitions
|
||||
*/
|
||||
|
||||
/* Channel configuration register */
|
||||
/* Stream configuration register */
|
||||
|
||||
#define DMA_CR_CH0 (0x0 << 25)
|
||||
#define DMA_CR_CH1 (0x1 << 25)
|
||||
|
@ -136,6 +136,25 @@ typedef struct dma_reg_map {
|
|||
#define DMA_CR_DMEIE (0x1 << 1)
|
||||
#define DMA_CR_EN (0x1)
|
||||
|
||||
typedef enum dma_channel {
|
||||
DMA_CH0 = DMA_CR_CH0, /**< Channel 0 */
|
||||
DMA_CH1 = DMA_CR_CH1, /**< Channel 1 */
|
||||
DMA_CH2 = DMA_CR_CH2, /**< Channel 2 */
|
||||
DMA_CH3 = DMA_CR_CH3, /**< Channel 3 */
|
||||
DMA_CH4 = DMA_CR_CH4, /**< Channel 4 */
|
||||
DMA_CH5 = DMA_CR_CH5, /**< Channel 5 */
|
||||
DMA_CH6 = DMA_CR_CH6, /**< Channel 6 */
|
||||
DMA_CH7 = DMA_CR_CH7, /**< Channel 7 */
|
||||
} dma_channel;
|
||||
|
||||
/* Device interrupt status register flags */
|
||||
|
||||
#define DMA_ISR_TCIF (1 << 5)
|
||||
#define DMA_ISR_HTIF (1 << 4)
|
||||
#define DMA_ISR_TEIF (1 << 3)
|
||||
#define DMA_ISR_DMEIF (1 << 2)
|
||||
#define DMA_ISR_FEIF (1 << 0)
|
||||
|
||||
/*
|
||||
* Devices
|
||||
*/
|
||||
|
@ -166,25 +185,35 @@ extern dma_dev *DMA2;
|
|||
* Convenience functions
|
||||
*/
|
||||
|
||||
void dma_init(dma_dev *dev);
|
||||
extern void dma_init(dma_dev *dev);
|
||||
|
||||
/** Flags for DMA transfer configuration. */
|
||||
typedef enum dma_mode_flags {
|
||||
DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */
|
||||
DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */
|
||||
DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */
|
||||
DMA_CIRC_MODE = 1 << 5, /**< Circular mode */
|
||||
DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */
|
||||
DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */
|
||||
DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */
|
||||
DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */
|
||||
DMA_MEM_BUF_0 = DMA_CR_CT0, /**< Current memory target buffer 0 */
|
||||
DMA_MEM_BUF_1 = DMA_CR_CT1, /**< Current memory target buffer 1 */
|
||||
DMA_DBL_BUF_MODE = DMA_CR_DBM, /**< Current memory double buffer mode */
|
||||
DMA_PINC_OFFSET = DMA_CR_PINCOS, /**< Peripheral increment offset size */
|
||||
DMA_MINC_MODE = DMA_CR_MINC, /**< Memory increment mode */
|
||||
DMA_PINC_MODE = DMA_CR_PINC, /**< Peripheral increment mode */
|
||||
DMA_CIRC_MODE = DMA_CR_CIRC, /**< Memory Circular mode */
|
||||
DMA_FROM_PER = DMA_CR_DIR_P2M, /**< Read from memory to peripheral */
|
||||
DMA_FROM_MEM = DMA_CR_DIR_M2P, /**< Read from memory to peripheral */
|
||||
DMA_MEM_TO_MEM = DMA_CR_DIR_M2M, /**< Read from memory to memory */
|
||||
DMA_PERIF_CTRL = DMA_CR_PFCTRL, /**< Peripheral flow controller */
|
||||
DMA_PRIO_MEDIUM = DMA_CR_PL_MEDIUM, /**< Medium priority */
|
||||
DMA_PRIO_HIGH = DMA_CR_PL_HIGH, /**< High priority */
|
||||
DMA_PRIO_VERY_HIGH = DMA_CR_PL_VERY_HIGH, /**< Very high priority */
|
||||
DMA_TRNS_CMPLT = DMA_CR_TCIE, /**< Interrupt on transfer completion */
|
||||
DMA_TRNS_HALF = DMA_CR_HTIE, /**< Interrupt on half-transfer */
|
||||
DMA_TRNS_ERR = DMA_CR_TEIE, /**< Interrupt on transfer error */
|
||||
DMA_DIR_MODE_ERR = DMA_CR_DMEIE /**< Interrupt on direct mode error */
|
||||
} dma_mode_flags;
|
||||
|
||||
/** Source and destination transfer sizes. */
|
||||
typedef enum dma_xfer_size {
|
||||
DMA_SIZE_8BITS = 0, /**< 8-bit transfers */
|
||||
DMA_SIZE_16BITS = 1, /**< 16-bit transfers */
|
||||
DMA_SIZE_32BITS = 2 /**< 32-bit transfers */
|
||||
DMA_SIZE_8BITS = ( DMA_CR_MSIZE_8BITS|DMA_CR_PSIZE_8BITS ), /**< 8-bit transfers */
|
||||
DMA_SIZE_16BITS = (DMA_CR_MSIZE_16BITS|DMA_CR_PSIZE_16BITS), /**< 16-bit transfers */
|
||||
DMA_SIZE_32BITS = (DMA_CR_MSIZE_32BITS|DMA_CR_PSIZE_32BITS) /**< 32-bit transfers */
|
||||
} dma_xfer_size;
|
||||
|
||||
/** DMA channel */
|
||||
|
@ -201,17 +230,17 @@ typedef enum dma_stream {
|
|||
|
||||
static inline void dma_setup_transfer(dma_dev *dev,
|
||||
dma_stream stream,
|
||||
dma_channel channel,
|
||||
dma_xfer_size trx_size,
|
||||
__io void *peripheral_address,
|
||||
__io void *memory_address0,
|
||||
__io void *memory_address1,
|
||||
uint32 flags,
|
||||
uint32 fifo_flags) {
|
||||
uint32 flags) {
|
||||
dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; // disable
|
||||
dev->regs->STREAM[stream].PAR = (uint32)peripheral_address;
|
||||
dev->regs->STREAM[stream].M0AR = (uint32)memory_address0;
|
||||
dev->regs->STREAM[stream].M1AR = (uint32)memory_address1;
|
||||
dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits
|
||||
dev->regs->STREAM[stream].CR = flags & 0x0feffffe; // mask out reserved and enable
|
||||
dev->regs->STREAM[stream].CR = ((flags|channel|trx_size) & 0x0feffffe); // mask out reserved and enable
|
||||
}
|
||||
|
||||
static inline void dma_set_num_transfers(dma_dev *dev,
|
||||
|
@ -220,6 +249,12 @@ static inline void dma_set_num_transfers(dma_dev *dev,
|
|||
dev->regs->STREAM[stream].NDTR = num_transfers;
|
||||
}
|
||||
|
||||
static inline void dma_set_fifo_flags(dma_dev *dev,
|
||||
dma_stream stream,
|
||||
uint8 fifo_flags) {
|
||||
dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits
|
||||
}
|
||||
|
||||
void dma_attach_interrupt(dma_dev *dev,
|
||||
dma_stream stream,
|
||||
void (*handler)(void));
|
||||
|
@ -232,6 +267,7 @@ static inline void dma_enable(dma_dev *dev, dma_stream stream) {
|
|||
|
||||
static inline void dma_disable(dma_dev *dev, dma_stream stream) {
|
||||
dev->regs->STREAM[stream].CR &= ~DMA_CR_EN;
|
||||
while (dev->regs->STREAM[stream].CR & DMA_CR_EN); // wait till EN bit is reset, see AN4031, chapter 4.1
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
#include "wirish.h"
|
||||
#include "boards.h"
|
||||
|
||||
#define DMA_TIMEOUT 100
|
||||
|
||||
#if CYCLES_PER_MICROSECOND != 168
|
||||
/* TODO [0.2.0?] something smarter than this */
|
||||
#warning "Unexpected clock speed; SPI frequency calculation will be incorrect"
|
||||
|
@ -115,27 +117,37 @@ SPIClass::SPIClass(uint32 spi_num) {
|
|||
|
||||
// Init things specific to each SPI device
|
||||
// clock divider setup is a bit of hack, and needs to be improved at a later date.
|
||||
/*****************************************************************************/
|
||||
// DMA / Channel / Stream
|
||||
// Rx Tx
|
||||
// SPI1: 2 / 3 / 0 (2) - 2 / 3 / 3 (5)
|
||||
// SPI2: 1 / 0 / 3 - 1 / 0 / 4
|
||||
// SPI3: 1 / 0 / 0 (2) - 1 / 0 / 5 (7)
|
||||
/*****************************************************************************/
|
||||
_settings[0].spi_d = SPI1;
|
||||
_settings[0].clockDivider = determine_baud_rate(_settings[0].spi_d, _settings[0].clock);
|
||||
#ifdef SPI_DMA
|
||||
_settings[0].spiDmaDev = DMA1;
|
||||
_settings[0].spiTxDmaChannel = DMA_CH3;
|
||||
_settings[0].spiRxDmaChannel = DMA_CH2;
|
||||
_settings[0].spiDmaDev = DMA2;
|
||||
_settings[0].spiDmaChannel = DMA_CH3;
|
||||
_settings[0].spiRxDmaStream = DMA_STREAM0; // alternative: DMA_STREAM2
|
||||
_settings[0].spiTxDmaStream = DMA_STREAM3; // alternative: DMA_STREAM5
|
||||
#endif
|
||||
_settings[1].spi_d = SPI2;
|
||||
_settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock);
|
||||
#ifdef SPI_DMA
|
||||
_settings[1].spiDmaDev = DMA1;
|
||||
_settings[1].spiTxDmaChannel = DMA_CH5;
|
||||
_settings[1].spiRxDmaChannel = DMA_CH4;
|
||||
_settings[1].spiDmaChannel = DMA_CH0;
|
||||
_settings[1].spiRxDmaStream = DMA_STREAM3; // alternative: -
|
||||
_settings[1].spiTxDmaStream = DMA_STREAM4; // alternative: -
|
||||
#endif
|
||||
#if BOARD_NR_SPI >= 3
|
||||
_settings[2].spi_d = SPI3;
|
||||
_settings[2].clockDivider = determine_baud_rate(_settings[2].spi_d, _settings[2].clock);
|
||||
#ifdef SPI_DMA
|
||||
_settings[2].spiDmaDev = DMA2;
|
||||
_settings[2].spiTxDmaChannel = DMA_CH2;
|
||||
_settings[2].spiRxDmaChannel = DMA_CH1;
|
||||
_settings[2].spiDmaDev = DMA1;
|
||||
_settings[2].spiDmaChannel = DMA_CH0;
|
||||
_settings[2].spiRxDmaStream = DMA_STREAM0; // alternative: DMA_STREAM2
|
||||
_settings[2].spiTxDmaStream = DMA_STREAM5; // alternative: DMA_STREAM7
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -265,9 +277,6 @@ void SPIClass::beginTransaction(uint8_t pin, SPISettings settings)
|
|||
#ifdef SPI_DEBUG
|
||||
Serial.println("SPIClass::beginTransaction");
|
||||
#endif
|
||||
//_SSPin=pin;
|
||||
//pinMode(_SSPin,OUTPUT);
|
||||
//digitalWrite(_SSPin,LOW);
|
||||
setBitOrder(settings.bitOrder);
|
||||
setDataMode(settings.dataMode);
|
||||
setDataSize(settings.dataSize);
|
||||
|
@ -321,14 +330,23 @@ uint16 SPIClass::read(void)
|
|||
|
||||
void SPIClass::read(uint8 *buf, uint32 len)
|
||||
{
|
||||
spi_rx_reg(_currentSetting->spi_d); // clear the RX buffer in case a byte is waiting on it.
|
||||
if ( len == 0 ) return;
|
||||
spi_rx_reg(_currentSetting->spi_d); // clear the RX buffer in case a byte is waiting on it.
|
||||
spi_reg_map * regs = _currentSetting->spi_d->regs;
|
||||
// start sequence
|
||||
while ( (len--)>0) {
|
||||
regs->DR = 0x00FF; // " write the data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
|
||||
while ( (regs->SR & SPI_SR_RXNE)==0 ) ; // wait till data is available in the Rx register
|
||||
*buf++ = (uint8)(regs->DR); // read and store the received byte
|
||||
}
|
||||
// start sequence: write byte 0
|
||||
regs->DR = 0x00FF; // write the first byte
|
||||
// main loop
|
||||
while ( (--len) ) {
|
||||
while( !(regs->SR & SPI_SR_TXE) ); // wait for TXE flag
|
||||
noInterrupts(); // go atomic level - avoid interrupts to surely get the previously received data
|
||||
regs->DR = 0x00FF; // write the next data item to be transmitted into the SPI_DR register. This clears the TXE flag.
|
||||
while ( !(regs->SR & SPI_SR_RXNE) ); // wait till data is available in the DR register
|
||||
*buf++ = (uint8)(regs->DR); // read and store the received byte. This clears the RXNE flag.
|
||||
interrupts(); // let systick do its job
|
||||
}
|
||||
// read remaining last byte
|
||||
while ( !(regs->SR & SPI_SR_RXNE) ); // wait till data is available in the Rx register
|
||||
*buf++ = (uint8)(regs->DR); // read and store the received byte
|
||||
}
|
||||
|
||||
void SPIClass::write(uint16 data)
|
||||
|
@ -393,47 +411,66 @@ uint16_t SPIClass::transfer16(uint16_t wr_data) const
|
|||
uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length)
|
||||
{
|
||||
if (length == 0) return 0;
|
||||
|
||||
uint8 b = 0;
|
||||
spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it.
|
||||
// dma1_ch3_Active=true;
|
||||
|
||||
dma_init(_currentSetting->spiDmaDev);
|
||||
// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
|
||||
|
||||
// RX
|
||||
spi_rx_dma_enable(_currentSetting->spi_d);
|
||||
dma_xfer_size dma_bit_size = (_currentSetting->dataSize==SPI_DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS;
|
||||
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
|
||||
receiveBuf, dma_bit_size, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA
|
||||
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length);
|
||||
dma_setup_transfer( _currentSetting->spiDmaDev,
|
||||
_currentSetting->spiRxDmaStream,
|
||||
_currentSetting->spiDmaChannel,
|
||||
dma_bit_size,
|
||||
&_currentSetting->spi_d->regs->DR, // peripheral address
|
||||
receiveBuf, // memory bank 0 address
|
||||
NULL, // memory bank 1 address
|
||||
(DMA_MINC_MODE | DMA_FROM_PER | DMA_PRIO_VERY_HIGH) // flags
|
||||
);
|
||||
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream, length);
|
||||
dma_set_fifo_flags(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream, 0);
|
||||
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream);
|
||||
|
||||
// TX
|
||||
uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT);
|
||||
spi_tx_dma_enable(_currentSetting->spi_d);
|
||||
uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM); // | DMA_TRNS_CMPLT);
|
||||
if ( transmitBuf==0 ) {
|
||||
static uint8_t ff = 0XFF;
|
||||
transmitBuf = &ff;
|
||||
flags ^= DMA_MINC_MODE; // remove increment mode
|
||||
flags &= ~((uint32)DMA_MINC_MODE); // remove increment mode
|
||||
}
|
||||
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
|
||||
transmitBuf, dma_bit_size, flags);// Transmit buffer DMA
|
||||
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
|
||||
|
||||
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);// enable receive
|
||||
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
|
||||
dma_setup_transfer( _currentSetting->spiDmaDev,
|
||||
_currentSetting->spiTxDmaStream,
|
||||
_currentSetting->spiDmaChannel,
|
||||
dma_bit_size,
|
||||
&_currentSetting->spi_d->regs->DR, // peripheral address
|
||||
transmitBuf, // memory bank 0 address
|
||||
NULL, // memory bank 1 address
|
||||
flags
|
||||
);
|
||||
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, length);
|
||||
dma_set_fifo_flags(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, 0);
|
||||
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream);
|
||||
// software enable sequence, see AN4031, chapter 4.3
|
||||
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream);// enable receive
|
||||
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream);// enable transmit
|
||||
spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it.
|
||||
spi_rx_dma_enable(_currentSetting->spi_d);
|
||||
spi_tx_dma_enable(_currentSetting->spi_d); // must be the last enable to avoid DMA error flag
|
||||
|
||||
uint32_t m = millis();
|
||||
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1)==0) {//Avoid interrupts and just loop waiting for the flag to be set.
|
||||
while ((b = dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set
|
||||
if ( b&(DMA_ISR_TEIF|DMA_ISR_DMEIF|DMA_ISR_FEIF) ) { b = 1; break; } // break on any error flag
|
||||
if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
|
||||
}
|
||||
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
|
||||
if (b & DMA_ISR_TCIF) b = 0;
|
||||
|
||||
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
|
||||
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);
|
||||
spi_rx_dma_disable(_currentSetting->spi_d); // And disable generation of DMA request from the SPI port so other peripherals can use the channels
|
||||
// software disable sequence, see AN4031, chapter 4.1
|
||||
spi_tx_dma_disable(_currentSetting->spi_d);
|
||||
//uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove!
|
||||
spi_rx_dma_disable(_currentSetting->spi_d);
|
||||
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream);
|
||||
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
@ -446,28 +483,36 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length
|
|||
uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc)
|
||||
{
|
||||
if (length == 0) return 0;
|
||||
uint32 flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
|
||||
uint8 b = 0;
|
||||
dma_init(_currentSetting->spiDmaDev);
|
||||
// TX
|
||||
spi_tx_dma_enable(_currentSetting->spi_d);
|
||||
dma_xfer_size dma_bit_size = (_currentSetting->dataSize==SPI_DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS;
|
||||
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
|
||||
transmitBuf, dma_bit_size, flags);// Transmit buffer DMA
|
||||
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
|
||||
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
|
||||
dma_setup_transfer( _currentSetting->spiDmaDev,
|
||||
_currentSetting->spiTxDmaStream,
|
||||
_currentSetting->spiDmaChannel,
|
||||
dma_bit_size,
|
||||
&_currentSetting->spi_d->regs->DR, // peripheral address
|
||||
transmitBuf, // memory bank 0 address
|
||||
NULL, // memory bank 1 address
|
||||
( (DMA_MINC_MODE*minc) | DMA_FROM_MEM ) //| DMA_TRNS_CMPLT ) // flags
|
||||
);// Transmit buffer DMA
|
||||
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, length);
|
||||
dma_set_fifo_flags(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, 0);
|
||||
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream);
|
||||
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream);// enable transmit
|
||||
spi_tx_dma_enable(_currentSetting->spi_d);
|
||||
|
||||
uint32_t m = millis();
|
||||
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1)==0) {//Avoid interrupts and just loop waiting for the flag to be set.
|
||||
while ((b = dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set
|
||||
if ( b&(DMA_ISR_TEIF|DMA_ISR_DMEIF|DMA_ISR_FEIF) ) { b = 1; break; } // break on any error flag
|
||||
if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
|
||||
}
|
||||
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
|
||||
}
|
||||
if (b & DMA_ISR_TCIF) b = 0;
|
||||
|
||||
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
|
||||
spi_tx_dma_disable(_currentSetting->spi_d);
|
||||
//uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove!
|
||||
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream);
|
||||
return b;
|
||||
}
|
||||
#endif
|
||||
|
@ -507,18 +552,13 @@ uint8 SPIClass::nssPin(void) {
|
|||
*/
|
||||
|
||||
uint8 SPIClass::send(uint8 data) {
|
||||
uint8 buf[] = {data};
|
||||
return this->send(buf, 1);
|
||||
this->write(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8 SPIClass::send(uint8 *buf, uint32 len) {
|
||||
uint32 txed = 0;
|
||||
uint8 ret = 0;
|
||||
while (txed < len) {
|
||||
this->write(buf[txed++]);
|
||||
ret = this->read();
|
||||
}
|
||||
return ret;
|
||||
this->write(buf, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
uint8 SPIClass::recv(void) {
|
||||
|
@ -640,4 +680,3 @@ static spi_baud_rate determine_baud_rate(spi_dev *dev, uint32_t freq) {
|
|||
|
||||
|
||||
//SPIClass SPI(3);
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
#include <libmaple/dma.h>
|
||||
#include <wirish.h>
|
||||
|
||||
#define SPI_DMA
|
||||
|
||||
// SPI_HAS_TRANSACTION means SPI has
|
||||
// - beginTransaction()
|
||||
// - endTransaction()
|
||||
|
@ -135,19 +137,18 @@ private:
|
|||
uint32_t dataSize;
|
||||
|
||||
spi_dev *spi_d;
|
||||
//uint8_t _SSPin;
|
||||
uint32_t clockDivider;
|
||||
|
||||
#ifdef SPI_DMA
|
||||
dma_channel spiRxDmaChannel, spiTxDmaChannel;
|
||||
dma_dev* spiDmaDev;
|
||||
dma_channel spiDmaChannel;
|
||||
dma_stream spiRxDmaStream, spiTxDmaStream;
|
||||
#endif
|
||||
|
||||
friend class SPIClass;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Wirish SPI interface.
|
||||
*
|
||||
|
@ -157,18 +158,11 @@ private:
|
|||
class SPIClass {
|
||||
public:
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param spiPortNumber Number of the SPI port to manage.
|
||||
*/
|
||||
SPIClass(uint32 spiPortNumber);
|
||||
|
||||
/*
|
||||
* Set up/tear down
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Equivalent to begin(SPI_1_125MHZ, MSBFIRST, 0).
|
||||
|
@ -396,5 +390,6 @@ private:
|
|||
*/
|
||||
};
|
||||
|
||||
extern SPIClass SPI;
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue