Skip to content

Commit 8ba463a

Browse files
committed
improved SPI non-DMA block read routine, taken over from F4
1 parent 97329ef commit 8ba463a

2 files changed

Lines changed: 58 additions & 53 deletions

File tree

STM32F1/libraries/SPI/src/SPI.cpp

Lines changed: 57 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,8 @@ SPIClass::SPIClass(uint32 spi_num) {
135135
_settings[2].spiDmaDev = DMA2;
136136
_settings[2].spiTxDmaChannel = DMA_CH2;
137137
_settings[2].spiRxDmaChannel = DMA_CH1;
138-
#endif
139-
140-
//pinMode(BOARD_SPI_DEFAULT_SS,OUTPUT);
138+
#endif
139+
141140
}
142141

143142
/*
@@ -260,9 +259,6 @@ void SPIClass::beginTransaction(uint8_t pin, SPISettings settings)
260259
#ifdef SPI_DEBUG
261260
Serial.println("SPIClass::beginTransaction");
262261
#endif
263-
//_SSPin=pin;
264-
//pinMode(_SSPin,OUTPUT);
265-
//digitalWrite(_SSPin,LOW);
266262
setBitOrder(settings.bitOrder);
267263
setDataMode(settings.dataMode);
268264
setDataSize(settings.dataSize);
@@ -316,14 +312,23 @@ uint16 SPIClass::read(void)
316312

317313
void SPIClass::read(uint8 *buf, uint32 len)
318314
{
315+
if ( len == 0 ) return;
316+
spi_rx_reg(_currentSetting->spi_d); // clear the RX buffer in case a byte is waiting on it.
319317
spi_reg_map * regs = _currentSetting->spi_d->regs;
320-
uint8 b = (regs->DR); // clear the RX buffer in case a byte is waiting on it.
321-
// start sequence
322-
while ( (len--)>0) {
323-
regs->DR = 0x00FF; // " write the data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
324-
while ( (regs->SR & SPI_SR_RXNE)==0 ) ; // wait till data is available in the Rx register
325-
*buf++ = (uint8)(regs->DR); // read and store the received byte
326-
}
318+
// start sequence: write byte 0
319+
regs->DR = 0x00FF; // write the first byte
320+
// main loop
321+
while ( (--len) ) {
322+
while( !(regs->SR & SPI_SR_TXE) ); // wait for TXE flag
323+
noInterrupts(); // go atomic level - avoid interrupts to surely get the previously received data
324+
regs->DR = 0x00FF; // write the next data item to be transmitted into the SPI_DR register. This clears the TXE flag.
325+
while ( !(regs->SR & SPI_SR_RXNE) ); // wait till data is available in the DR register
326+
*buf++ = (uint8)(regs->DR); // read and store the received byte. This clears the RXNE flag.
327+
interrupts(); // let systick do its job
328+
}
329+
// read remaining last byte
330+
while ( !(regs->SR & SPI_SR_RXNE) ); // wait till data is available in the Rx register
331+
*buf++ = (uint8)(regs->DR); // read and store the received byte
327332
}
328333

329334
void SPIClass::write(uint16 data)
@@ -344,32 +349,37 @@ void SPIClass::write(uint16 data, uint32 n)
344349
spi_reg_map * regs = _currentSetting->spi_d->regs;
345350
while ( (n--)>0 ) {
346351
regs->DR = data; // write the data to be transmitted into the SPI_DR register (this clears the TXE flag)
347-
while ( (regs->SR & SPI_SR_TXE)==0 ) ; // wait till Tx empty
352+
while ( (regs->SR & SPI_SR_TXE)==0 ) ; // wait till Tx empty
348353
}
349354
while ( (regs->SR & SPI_SR_BSY) != 0); // wait until BSY=0 before returning
350355
}
351356

352-
void SPIClass::write(const void *data, uint32 length)
357+
void SPIClass::write(void *data, uint32 length)
353358
{
354-
spi_tx(_currentSetting->spi_d, data, length); // data can be array of bytes or words
355-
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
356-
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
357-
// taken from SdSpiSTM32F1.cpp - Victor's lib, and adapted to support device selection
358-
uint16 b = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove!
359+
spi_dev * spi_d = _currentSetting->spi_d;
360+
spi_tx(spi_d, (void*)data, length); // data can be array of bytes or words
361+
while (spi_is_tx_empty(spi_d) == 0); // "5. Wait until TXE=1 ..."
362+
while (spi_is_busy(spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
359363
}
360364

361-
uint8 SPIClass::transfer(uint8 byte) const {
362-
spi_tx_reg(_currentSetting->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
363-
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
364-
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
365-
return (uint8)spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
365+
uint8 SPIClass::transfer(uint8 byte) const
366+
{
367+
spi_dev * spi_d = _currentSetting->spi_d;
368+
spi_rx_reg(spi_d); // read any previous data
369+
spi_tx_reg(spi_d, byte); // Write the data item to be transmitted into the SPI_DR register
370+
while (spi_is_tx_empty(spi_d) == 0); // "5. Wait until TXE=1 ..."
371+
while (spi_is_busy(spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
372+
return (uint8)spi_rx_reg(spi_d); // "... and read the last received data."
366373
}
367374

368-
uint16_t SPIClass::transfer16(uint16_t wr_data) const {
369-
spi_tx_reg(_currentSetting->spi_d, wr_data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
370-
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
371-
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
372-
return (uint16)spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
375+
uint16_t SPIClass::transfer16(uint16_t wr_data) const
376+
{
377+
spi_dev * spi_d = _currentSetting->spi_d;
378+
spi_rx_reg(spi_d); // read any previous data
379+
spi_tx_reg(spi_d, wr_data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
380+
while (spi_is_tx_empty(spi_d) == 0); // "5. Wait until TXE=1 ..."
381+
while (spi_is_busy(spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
382+
return (uint16)spi_rx_reg(spi_d); // "... and read the last received data."
373383
}
374384

375385
/* Roger Clark and Victor Perez, 2015
@@ -382,21 +392,19 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length
382392
{
383393
if (length == 0) return 0;
384394
uint8 b = 0;
385-
spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it.
386395
// dma1_ch3_Active=true;
387396
dma_init(_currentSetting->spiDmaDev);
388397
// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
389398

390399
// RX
391-
spi_rx_dma_enable(_currentSetting->spi_d);
392400
dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS;
393401
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
394402
receiveBuf, dma_bit_size, (DMA_MINC_MODE));// receive buffer DMA
395403
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length);
404+
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);// enable receive
396405

397406
// TX
398407
uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM);
399-
spi_tx_dma_enable(_currentSetting->spi_d);
400408
if ( transmitBuf==0 ) {
401409
static uint8_t ff = 0XFF;
402410
transmitBuf = &ff;
@@ -405,23 +413,25 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length
405413
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
406414
transmitBuf, dma_bit_size, flags);// Transmit buffer DMA
407415
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
408-
409-
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);// enable receive
410416
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
411417
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
418+
419+
spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it.
420+
spi_rx_dma_enable(_currentSetting->spi_d);
421+
spi_tx_dma_enable(_currentSetting->spi_d); // must be the last enable to avoid DMA error flag
412422

413423
uint32_t m = millis();
414424
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.
425+
//delayMicroseconds(10);
415426
if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
416427
}
417428

418429
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
419430
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
420-
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
421-
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);
422-
spi_rx_dma_disable(_currentSetting->spi_d); // And disable generation of DMA request from the SPI port so other peripherals can use the channels
423431
spi_tx_dma_disable(_currentSetting->spi_d);
424-
uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove!
432+
spi_rx_dma_disable(_currentSetting->spi_d); // And disable generation of DMA request from the SPI port so other peripherals can use the channels
433+
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
434+
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);
425435
return b;
426436
}
427437

@@ -438,25 +448,25 @@ uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc)
438448
uint8 b = 0;
439449
dma_init(_currentSetting->spiDmaDev);
440450
// TX
441-
spi_tx_dma_enable(_currentSetting->spi_d);
442451
dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS;
443452
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
444453
transmitBuf, dma_bit_size, flags);// Transmit buffer DMA
445454
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
446455
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
447456
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
457+
spi_tx_dma_enable(_currentSetting->spi_d);
448458

449459
uint32_t m = millis();
450460
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.
461+
//delayMicroseconds(10);
451462
if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
452463
}
453464

454465
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
455466
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
456-
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
457467
spi_tx_dma_disable(_currentSetting->spi_d);
458-
uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove!
459-
return b;
468+
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
469+
return b;
460470
}
461471

462472
void SPIClass::attachInterrupt(void) {
@@ -492,18 +502,13 @@ uint8 SPIClass::nssPin(void) {
492502
*/
493503

494504
uint8 SPIClass::send(uint8 data) {
495-
uint8 buf[] = {data};
496-
return this->send(buf, 1);
505+
this->write(data);
506+
return 1;
497507
}
498508

499509
uint8 SPIClass::send(uint8 *buf, uint32 len) {
500-
uint32 txed = 0;
501-
uint8 ret = 0;
502-
while (txed < len) {
503-
this->write(buf[txed++]);
504-
ret = this->read();
505-
}
506-
return ret;
510+
this->write(buf, len);
511+
return len;
507512
}
508513

509514
uint8 SPIClass::recv(void) {

STM32F1/libraries/SPI/src/SPI.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ class SPIClass {
256256
* @param buffer Bytes/words to transmit.
257257
* @param length Number of bytes/words in buffer to transmit.
258258
*/
259-
void write(const void * buffer, uint32 length);
259+
void write(void * buffer, uint32 length);
260260

261261
/**
262262
* @brief Transmit a byte, then return the next unread byte.

0 commit comments

Comments
 (0)