Skip to content

Commit b2e349c

Browse files
committed
Revert "Revert "improve SPI low level functions""
This reverts commit 3469ef2.
1 parent 3469ef2 commit b2e349c

3 files changed

Lines changed: 74 additions & 135 deletions

File tree

STM32F1/cores/maple/libmaple/spi.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags) {
8484
}
8585

8686
/**
87-
* @brief Nonblocking SPI transmit.
87+
* @brief Blocking SPI transmit.
8888
* @param dev SPI port to use for transmission
8989
* @param buf Buffer to transmit. The sizeof buf's elements are
9090
* inferred from dev's data frame format (i.e., are
@@ -95,7 +95,8 @@ void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags) {
9595
uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len) {
9696
uint32 txed = 0;
9797
uint8 byte_frame = spi_dff(dev) == SPI_DFF_8_BIT;
98-
while (spi_is_tx_empty(dev) && (txed < len)) {
98+
while ( txed < len ) {
99+
while ( spi_is_tx_empty(dev)==0 ); // wait Tx to be empty
99100
if (byte_frame) {
100101
dev->regs->DR = ((const uint8*)buf)[txed++];
101102
} else {
@@ -162,5 +163,6 @@ static void spi_reconfigure(spi_dev *dev, uint32 cr1_config) {
162163
spi_irq_disable(dev, SPI_INTERRUPTS_ALL);
163164
if ( (dev->regs->CR1&MASK)!=(cr1_config&MASK) ) spi_peripheral_disable(dev);
164165
dev->regs->CR1 = cr1_config;
166+
//spi_rx_dma_enable(dev);
165167
spi_peripheral_enable(dev);
166168
}

STM32F1/libraries/SPI/src/SPI.cpp

Lines changed: 63 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
#include "boards.h"
4242

4343
//#include "HardwareSerial.h"
44+
/** Time in ms for DMA receive timeout */
45+
#define DMA_TIMEOUT 100
4446

4547
#if CYCLES_PER_MICROSECOND != 72
4648
/* TODO [0.2.0?] something smarter than this */
@@ -304,205 +306,151 @@ void SPIClass::endTransaction(void)
304306
* I/O
305307
*/
306308

307-
uint8 SPIClass::read(void) {
308-
uint8 buf[1];
309-
this->read(buf, 1);
310-
return buf[0];
309+
uint8 SPIClass::read(void)
310+
{
311+
while ( spi_is_rx_nonempty(_currentSetting->spi_d)==0 ) ;
312+
return (uint8)spi_rx_reg(_currentSetting->spi_d);
311313
}
312314

313-
void SPIClass::read(uint8 *buf, uint32 len) {
315+
void SPIClass::read(uint8 *buf, uint32 len)
316+
{
317+
spi_reg_map * regs = _currentSetting->spi_d->regs;
318+
uint8 b = (regs->DR); // clear the RX buffer in case a byte is waiting on it.
314319
uint32 rxed = 0;
315-
while (rxed < len) {
316-
while (!spi_is_rx_nonempty(_currentSetting->spi_d))
317-
;
318-
buf[rxed++] = (uint8)spi_rx_reg(_currentSetting->spi_d);
320+
// start sequence
321+
while ( rxed < len) {
322+
regs->DR = 0x00FF; // " write the data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
323+
while ( (regs->SR & SPI_SR_RXNE)==0 ) ; // wait till data is available in the Rx register
324+
buf[rxed++] = (uint8)(regs->DR); // read and store the received byte
319325
}
320326
}
321327

322-
void SPIClass::write(uint16 data) {
323-
// this->write(&data, 1);
324-
328+
void SPIClass::write(uint16 data)
329+
{
325330
/* Added for 16bit data Victor Perez. Roger Clark
326-
* 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)
327-
* The original method, of calling write(*data, length) .
331+
* Improved speed by just directly writing the single byte to the SPI data reg and wait for completion,
332+
* by taking the Tx code from transfer(byte)
328333
* This almost doubles the speed of this function.
329334
*/
330-
331335
spi_tx_reg(_currentSetting->spi_d, data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
332336
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
333337
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
334338
}
335339

336-
//void SPIClass::write(uint8 byte) {
337-
// this->write(&byte, 1);
338-
339-
/* Roger Clark
340-
* 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)
341-
* The original method, of calling write(*data, length) .
342-
* This almost doubles the speed of this function.
343-
*/
344-
345-
// 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)."
346-
// while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
347-
// while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
348-
//}
349-
350-
void SPIClass::write(const uint8 *data, uint32 length) {
351-
uint32 txed = 0;
352-
while (txed < length) {
353-
txed += spi_tx(_currentSetting->spi_d, data + txed, length - txed);
354-
}
355-
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "4. After writing the last data item into the SPI_DR register, wait until TXE=1 ..."
356-
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... then wait until BSY=0, this indicates that the transmission of the last data is complete."
340+
void SPIClass::write(const void *data, uint32 length)
341+
{
342+
spi_tx(_currentSetting->spi_d, data, length); // data can be array of bytes or words
343+
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
344+
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
357345
// taken from SdSpiSTM32F1.cpp - Victor's lib, and adapted to support device selection
358-
if (spi_is_rx_nonempty(_currentSetting->spi_d)) {
359-
uint8_t b = spi_rx_reg(_currentSetting->spi_d);
360-
}
346+
uint16 b = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove!
361347
}
362348

363349
uint16_t SPIClass::transfer16(uint16_t wr_data) const {
364350
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)."
365-
while (spi_is_rx_nonempty(_currentSetting->spi_d) == 0); // "4. Wait until RXNE=1 ..."
366-
uint16_t rd_data = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
367-
// while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
368-
// while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
369-
return rd_data;
351+
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
352+
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
353+
return (uint16)spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
370354
}
371355

372356
uint8 SPIClass::transfer(uint8 byte) const {
373357
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)."
374-
while (spi_is_rx_nonempty(_currentSetting->spi_d) == 0); // "4. Wait until RXNE=1 ..."
375-
uint8 b = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
376-
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
377-
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
378-
return b;
358+
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
359+
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
360+
return (uint8)spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
379361
}
362+
380363
/* Roger Clark and Victor Perez, 2015
381364
* Performs a DMA SPI transfer with at least a receive buffer.
382-
* If a TX buffer is not provided, FF is sent over and over for the lenght of the transfer.
383-
* On exit TX buffer is not modified, and RX buffer cotains the received data.
365+
* If a TX buffer is not provided, FF is sent over and over for the length of the transfer.
366+
* On exit TX buffer is not modified, and RX buffer contains the received data.
384367
* Still in progress.
385368
*/
386-
uint8 SPIClass::dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length) {
369+
uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length)
370+
{
387371
if (length == 0) return 0;
388372
uint8 b = 0;
389-
if (spi_is_rx_nonempty(_currentSetting->spi_d) == 1) b = spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it.
373+
spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it.
390374
// dma1_ch3_Active=true;
391375
dma_init(_currentSetting->spiDmaDev);
392376
// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
393-
377+
394378
// RX
395379
spi_rx_dma_enable(_currentSetting->spi_d);
396-
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS,
397-
receiveBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA
380+
dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_8BIT) ? DMA_SIZE_8BITS : DMA_SIZE_16BITS;
381+
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
382+
receiveBuf, dma_bit_size, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA
398383
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length);
399-
384+
400385
// TX
386+
uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT);
401387
spi_tx_dma_enable(_currentSetting->spi_d);
402-
if (!transmitBuf) {
403-
static uint8_t ff = 0XFF;
404-
transmitBuf = &ff;
405-
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS,
406-
transmitBuf, DMA_SIZE_8BITS, (DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit FF repeatedly
407-
}
408-
else {
409-
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS,
410-
transmitBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit buffer DMA
388+
if ( transmitBuf==0 ) {
389+
static uint8_t ff = 0XFF;
390+
transmitBuf = &ff;
391+
flags ^= DMA_MINC_MODE; // remove increment mode
411392
}
393+
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
394+
transmitBuf, dma_bit_size, flags);// Transmit buffer DMA
412395
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
413396

414397
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);// enable receive
415398
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
416399

417-
// while (dma1_ch3_Active);
418-
// if (receiveBuf) {
419400
uint32_t m = millis();
420401
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0) {//Avoid interrupts and just loop waiting for the flag to be set.
421-
if ((millis() - m) > 100) {
422-
// dma1_ch3_Active = 0;
423-
b = 2;
424-
break;
425-
}
402+
if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
426403
}
427404
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
428405

429-
// }
430406
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
431407
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
432408
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
433409
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);
434410
spi_rx_dma_disable(_currentSetting->spi_d); // And disable generation of DMA request from the SPI port so other peripherals can use the channels
435411
spi_tx_dma_disable(_currentSetting->spi_d);
436-
if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..."
437-
uint8 x = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
438-
}
412+
uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove!
439413
return b;
440414
}
441415

442416
/* Roger Clark and Victor Perez, 2015
443417
* Performs a DMA SPI send using a TX buffer.
444418
* On exit TX buffer is not modified.
445419
* Still in progress.
420+
* 2016 - stevstrong - reworked to automatically detect bit size from SPI setting
446421
*/
447-
uint8 SPIClass::dmaSend(uint8 *transmitBuf, uint16 length, bool minc) {
422+
uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length)
423+
{
448424
if (length == 0) return 0;
449-
uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
425+
uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT);
450426
uint8 b = 0;
451427
// dma1_ch3_Active=true;
452428
dma_init(_currentSetting->spiDmaDev);
453429
// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
454430

455431
// TX
456432
spi_tx_dma_enable(_currentSetting->spi_d);
457-
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS,
458-
transmitBuf, DMA_SIZE_8BITS, flags);// Transmit buffer DMA
433+
dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_8BIT) ? DMA_SIZE_8BITS : DMA_SIZE_16BITS;
434+
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
435+
transmitBuf, dma_bit_size, flags);// Transmit buffer DMA
459436
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
460437
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
461-
462-
// while (dma1_ch3_Active);
463-
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0); //Avoid interrupts and just loop waiting for the flag to be set.
464-
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
465438

466-
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
467-
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
468-
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
469-
spi_tx_dma_disable(_currentSetting->spi_d);
470-
if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..."
471-
uint8 x = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
472-
}
473-
return b;
474-
}
475-
476-
uint8 SPIClass::dmaSend(uint16 *transmitBuf, uint16 length, bool minc) {
477-
if (length == 0) return 0;
478-
uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
479-
uint8 b;
480-
dma1_ch3_Active=true;
481-
dma_init(_currentSetting->spiDmaDev);
482-
// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
483-
484-
// TX
485-
spi_tx_dma_enable(_currentSetting->spi_d);
486-
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_16BITS,
487-
transmitBuf, DMA_SIZE_16BITS, flags);// Transmit buffer DMA
488-
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
489-
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
490-
491439
// while (dma1_ch3_Active);
492-
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0); //Avoid interrupts and just loop waiting for the flag to be set.
440+
uint32_t m = millis();
441+
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0) {//Avoid interrupts and just loop waiting for the flag to be set.
442+
if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
443+
}
493444
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
494445

495446
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
496447
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
497448
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
498449
spi_tx_dma_disable(_currentSetting->spi_d);
499-
if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..."
500-
b = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
501-
}
450+
uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove!
502451
return b;
503452
}
504453

505-
506454
void SPIClass::attachInterrupt(void) {
507455
// Should be enableInterrupt()
508456
}

STM32F1/libraries/SPI/src/SPI.h

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ class SPIClass {
249249
* @param buffer Bytes to transmit.
250250
* @param length Number of bytes in buffer to transmit.
251251
*/
252-
void write(const uint8 *buffer, uint32 length);
252+
void write(const void * buffer, uint32 length);
253253

254254
/**
255255
* @brief Transmit a byte, then return the next unread byte.
@@ -264,37 +264,26 @@ class SPIClass {
264264

265265
/**
266266
* @brief Sets up a DMA Transfer for "length" bytes.
267+
* The transfer mode (8 or 16 bit mode) is evaluated from the SPI peripheral setting.
267268
*
268269
* This function transmits and receives to buffers.
269270
*
270271
* @param transmitBuf buffer Bytes to transmit. If passed as 0, it sends FF repeatedly for "length" bytes
271272
* @param receiveBuf buffer Bytes to save received data.
272273
* @param length Number of bytes in buffer to transmit.
273274
*/
274-
uint8 dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length);
275+
uint8 dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length);
275276

276277
/**
277-
* @brief Sets up a DMA Transmit for bytes.
278+
* @brief Sets up a DMA Transmit for SPI 8 or 16 bit transfer mode.
279+
* The transfer mode (8 or 16 bit mode) is evaluated from the SPI peripheral setting.
278280
*
279-
* This function transmits and does not care about the RX fifo.
280-
*
281-
* @param transmitBuf buffer Bytes to transmit,
282-
* @param length Number of bytes in buffer to transmit.
283-
* @param minc Set to use Memory Increment mode, clear to use Circular mode.
284-
*/
285-
uint8 dmaSend(uint8 *transmitBuf, uint16 length, bool minc = 1);
286-
287-
/**
288-
* @brief Sets up a DMA Transmit for half words.
289-
* SPI PERFIPHERAL MUST BE SET TO 16 BIT MODE BEFORE
290-
*
291-
* This function transmits and does not care about the RX fifo.
281+
* This function only transmits and does not care about the RX fifo.
292282
*
293283
* @param data buffer half words to transmit,
294284
* @param length Number of bytes in buffer to transmit.
295-
* @param minc Set to use Memory Increment mode (default if blank), clear to use Circular mode.
296285
*/
297-
uint8 dmaSend(uint16 *transmitBuf, uint16 length, bool minc = 1);
286+
uint8 dmaSend(void * transmitBuf, uint16 length);
298287

299288
/*
300289
* Pin accessors

0 commit comments

Comments
 (0)