Skip to content

Commit e13b9a0

Browse files
committed
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.
1 parent 331a02e commit e13b9a0

2 files changed

Lines changed: 170 additions & 18 deletions

File tree

STM32F1/libraries/SPI/src/SPI.cpp

Lines changed: 123 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,19 @@ void SPIClass::setBitOrder(BitOrder bitOrder)
183183
this->begin();
184184
}
185185

186+
/* Victor Perez. Added to test changing datasize from 8 to 16 bit modes on the fly.
187+
* Input parameter should be SPI_CR1_DFF set to 0 or 1 on a 32bit word.
188+
*
189+
*/
190+
void SPIClass::setDataSize(uint32 datasize)
191+
{
192+
uint32 cr1 = this->spi_d->regs->CR1;
193+
datasize &= SPI_CR1_DFF;
194+
cr1 &= ~(SPI_CR1_DFF);
195+
cr1 |= datasize;
196+
this->spi_d->regs->CR1 = cr1;
197+
}
198+
186199
void SPIClass::setDataMode(uint8_t dataMode)
187200
{
188201
/* 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) {
297310
}
298311
}
299312

313+
void SPIClass::write(uint16 data) {
314+
// this->write(&data, 1);
315+
316+
/* Added for 16bit data Victor Perez. Roger Clark
317+
* 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)
318+
* The original method, of calling write(*data, length) .
319+
* This almost doubles the speed of this function.
320+
*/
321+
322+
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)."
323+
while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..."
324+
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
325+
}
326+
300327
void SPIClass::write(uint8 byte) {
301328
// this->write(&byte, 1);
302329

@@ -329,35 +356,116 @@ uint8 SPIClass::transfer(uint8 byte) {
329356
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
330357
return b;
331358
}
332-
333-
uint8 SPIClass::DMATransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint32 length) {
359+
/* Roger Clark and Victor Perez, 2015
360+
* Performs a DMA SPI transfer with at least a receive buffer.
361+
* If a TX buffer is not provided, FF is sent over and over for the lenght of the transfer.
362+
* On exit TX buffer is not modified, and RX buffer cotains the received data.
363+
* Still in progress.
364+
*/
365+
uint8 SPIClass::dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length) {
366+
if (length == 0) return 0;
334367
uint8 b;
335-
368+
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.
336369
dma1_ch3_Active=true;
337-
338370
dma_init(DMA1);
339-
340-
dma_attach_interrupt(DMA1, DMA_CH2, &SPIClass::DMA1_CH3_Event);
341-
371+
dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
372+
342373
// RX
343374
spi_rx_dma_enable(SPI1);
344375
dma_setup_transfer(DMA1, DMA_CH2, &SPI1->regs->DR, DMA_SIZE_8BITS,
345-
receiveBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT | DMA_TRNS_ERR));// receive buffer DMA
376+
receiveBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA
346377
dma_set_num_transfers(DMA1, DMA_CH2, length);
347-
378+
348379
// TX
349-
spi_tx_dma_enable(SPI1);
380+
spi_tx_dma_enable(SPI1);
381+
if (!transmitBuf) {
382+
static uint8_t ff = 0XFF;
383+
transmitBuf = &ff;
384+
dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS,
385+
transmitBuf, DMA_SIZE_8BITS, (DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit FF repeatedly
386+
}
387+
else {
350388
dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS,
351-
transmitBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit buffer DMA
352-
dma_set_num_transfers(DMA1, DMA_CH3, length);
353-
389+
transmitBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit buffer DMA
390+
}
391+
dma_set_num_transfers(DMA1, DMA_CH3, length);
392+
354393
dma_enable(DMA1, DMA_CH2);// enable receive
355394
dma_enable(DMA1, DMA_CH3);// enable transmit
356395

357-
while (dma1_ch3_Active);
396+
// while (dma1_ch3_Active);
397+
// if (receiveBuf) {
398+
uint32_t m = millis();
399+
while (dma1_ch3_Active) {
400+
if ((millis() - m) > 100) {
401+
dma1_ch3_Active = 0;
402+
b = 2;
403+
break;
404+
}
405+
}
406+
407+
// }
408+
while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..."
409+
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
410+
dma_disable(DMA1, DMA_CH3);
411+
dma_disable(DMA1, DMA_CH2);
412+
spi_rx_dma_disable(SPI1);
413+
spi_tx_dma_disable(SPI1);
414+
return b;
415+
}
416+
417+
/* Roger Clark and Victor Perez, 2015
418+
* Performs a DMA SPI send using a TX buffer.
419+
* On exit TX buffer is not modified.
420+
* Still in progress.
421+
*/
422+
uint8 SPIClass::dmaSend(uint8 *transmitBuf, uint16 length, bool minc) {
423+
if (length == 0) return 0;
424+
uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
425+
uint8 b;
426+
dma1_ch3_Active=true;
427+
dma_init(DMA1);
428+
dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
429+
430+
// TX
431+
spi_tx_dma_enable(SPI1);
432+
dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS,
433+
transmitBuf, DMA_SIZE_8BITS, flags);// Transmit buffer DMA
434+
dma_set_num_transfers(DMA1, DMA_CH3, length);
435+
dma_enable(DMA1, DMA_CH3);// enable transmit
436+
437+
while (dma1_ch3_Active);
438+
while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..."
439+
b = spi_rx_reg(this->spi_d); // "... and read the last received data."
358440
while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..."
359-
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
441+
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
442+
dma_disable(DMA1, DMA_CH3);
443+
spi_tx_dma_disable(SPI1);
444+
return b;
445+
}
446+
447+
uint8 SPIClass::dmaSend(uint16 *transmitBuf, uint16 length, bool minc) {
448+
if (length == 0) return 0;
449+
uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
450+
uint8 b;
451+
dma1_ch3_Active=true;
452+
dma_init(DMA1);
453+
dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
454+
455+
// TX
456+
spi_tx_dma_enable(SPI1);
457+
dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_16BITS,
458+
transmitBuf, DMA_SIZE_16BITS, flags);// Transmit buffer DMA
459+
dma_set_num_transfers(DMA1, DMA_CH3, length);
460+
dma_enable(DMA1, DMA_CH3);// enable transmit
360461

462+
while (dma1_ch3_Active);
463+
while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..."
464+
b = spi_rx_reg(this->spi_d); // "... and read the last received data."
465+
while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..."
466+
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
467+
dma_disable(DMA1, DMA_CH3);
468+
spi_tx_dma_disable(SPI1);
361469
return b;
362470
}
363471

STM32F1/libraries/SPI/src/SPI.h

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,12 @@ class SPIClass {
183183
void attachInterrupt(void);
184184
void detachInterrupt(void);
185185

186+
/* Victor Perez. Added to change datasize from 8 to 16 bit modes on the fly.
187+
* Input parameter should be SPI_CR1_DFF set to 0 or 1 on a 32bit word.
188+
* Requires an added function spi_data_size on STM32F1 / cores / maple / libmaple / spi.c
189+
*/
190+
void setDataSize(uint32 ds);
191+
186192

187193
/*
188194
* I/O
@@ -211,6 +217,12 @@ class SPIClass {
211217
*/
212218
void write(uint8 data);
213219

220+
/**
221+
* @brief Transmit a half word.
222+
* @param data to transmit.
223+
*/
224+
void write(uint16 data);
225+
214226
/**
215227
* @brief Transmit multiple bytes.
216228
* @param buffer Bytes to transmit.
@@ -227,8 +239,40 @@ class SPIClass {
227239
* @return Next unread byte.
228240
*/
229241
uint8 transfer(uint8 data);
242+
243+
/**
244+
* @brief Sets up a DMA Transfer for "length" bytes.
245+
*
246+
* This function transmits and receives to buffers.
247+
*
248+
* @param transmitBuf buffer Bytes to transmit. If passed as 0, it sends FF repeatedly for "length" bytes
249+
* @param receiveBuf buffer Bytes to save received data.
250+
* @param length Number of bytes in buffer to transmit.
251+
*/
252+
uint8 dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length);
230253

231-
uint8 DMATransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint32 length);
254+
/**
255+
* @brief Sets up a DMA Transmit for bytes.
256+
*
257+
* This function transmits and does not care about the RX fifo.
258+
*
259+
* @param transmitBuf buffer Bytes to transmit,
260+
* @param length Number of bytes in buffer to transmit.
261+
* @param minc Set to use Memory Increment mode, clear to use Circular mode.
262+
*/
263+
uint8 dmaSend(uint8 *transmitBuf, uint16 length, bool minc = 1);
264+
265+
/**
266+
* @brief Sets up a DMA Transmit for half words.
267+
* SPI PERFIPHERAL MUST BE SET TO 16 BIT MODE BEFORE
268+
*
269+
* This function transmits and does not care about the RX fifo.
270+
*
271+
* @param data buffer half words to transmit,
272+
* @param length Number of bytes in buffer to transmit.
273+
* @param minc Set to use Memory Increment mode (default if blank), clear to use Circular mode.
274+
*/
275+
uint8 dmaSend(uint16 *transmitBuf, uint16 length, bool minc = 1);
232276

233277
/*
234278
* Pin accessors
@@ -302,8 +346,8 @@ class SPIClass {
302346

303347
static inline void DMA1_CH3_Event() {
304348
dma1_ch3_Active = 0;
305-
dma_disable(DMA1, DMA_CH3);
306-
dma_disable(DMA1, DMA_CH2);
349+
// dma_disable(DMA1, DMA_CH3);
350+
// dma_disable(DMA1, DMA_CH2);
307351

308352
// To Do. Need to wait for
309353
}

0 commit comments

Comments
 (0)