|
41 | 41 | #include "boards.h" |
42 | 42 |
|
43 | 43 | //#include "HardwareSerial.h" |
| 44 | +/** Time in ms for DMA receive timeout */ |
| 45 | +#define DMA_TIMEOUT 100 |
44 | 46 |
|
45 | 47 | #if CYCLES_PER_MICROSECOND != 72 |
46 | 48 | /* TODO [0.2.0?] something smarter than this */ |
@@ -304,205 +306,151 @@ void SPIClass::endTransaction(void) |
304 | 306 | * I/O |
305 | 307 | */ |
306 | 308 |
|
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); |
311 | 313 | } |
312 | 314 |
|
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. |
314 | 319 | 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 |
319 | 325 | } |
320 | 326 | } |
321 | 327 |
|
322 | | -void SPIClass::write(uint16 data) { |
323 | | - // this->write(&data, 1); |
324 | | - |
| 328 | +void SPIClass::write(uint16 data) |
| 329 | +{ |
325 | 330 | /* 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) |
328 | 333 | * This almost doubles the speed of this function. |
329 | 334 | */ |
330 | | - |
331 | 335 | 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)." |
332 | 336 | while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." |
333 | 337 | while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." |
334 | 338 | } |
335 | 339 |
|
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." |
357 | 345 | // 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! |
361 | 347 | } |
362 | 348 |
|
363 | 349 | uint16_t SPIClass::transfer16(uint16_t wr_data) const { |
364 | 350 | 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." |
370 | 354 | } |
371 | 355 |
|
372 | 356 | uint8 SPIClass::transfer(uint8 byte) const { |
373 | 357 | 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." |
379 | 361 | } |
| 362 | + |
380 | 363 | /* Roger Clark and Victor Perez, 2015 |
381 | 364 | * 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. |
384 | 367 | * Still in progress. |
385 | 368 | */ |
386 | | -uint8 SPIClass::dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length) { |
| 369 | +uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length) |
| 370 | +{ |
387 | 371 | if (length == 0) return 0; |
388 | 372 | 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. |
390 | 374 | // dma1_ch3_Active=true; |
391 | 375 | dma_init(_currentSetting->spiDmaDev); |
392 | 376 | // dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); |
393 | | - |
| 377 | + |
394 | 378 | // RX |
395 | 379 | 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 |
398 | 383 | dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length); |
399 | | - |
| 384 | + |
400 | 385 | // TX |
| 386 | + uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT); |
401 | 387 | 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 |
411 | 392 | } |
| 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 |
412 | 395 | dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); |
413 | 396 |
|
414 | 397 | dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);// enable receive |
415 | 398 | dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit |
416 | 399 |
|
417 | | -// while (dma1_ch3_Active); |
418 | | -// if (receiveBuf) { |
419 | 400 | uint32_t m = millis(); |
420 | 401 | 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; } |
426 | 403 | } |
427 | 404 | dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); |
428 | 405 |
|
429 | | -// } |
430 | 406 | while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." |
431 | 407 | while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." |
432 | 408 | dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); |
433 | 409 | dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); |
434 | 410 | spi_rx_dma_disable(_currentSetting->spi_d); // And disable generation of DMA request from the SPI port so other peripherals can use the channels |
435 | 411 | 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! |
439 | 413 | return b; |
440 | 414 | } |
441 | 415 |
|
442 | 416 | /* Roger Clark and Victor Perez, 2015 |
443 | 417 | * Performs a DMA SPI send using a TX buffer. |
444 | 418 | * On exit TX buffer is not modified. |
445 | 419 | * Still in progress. |
| 420 | +* 2016 - stevstrong - reworked to automatically detect bit size from SPI setting |
446 | 421 | */ |
447 | | -uint8 SPIClass::dmaSend(uint8 *transmitBuf, uint16 length, bool minc) { |
| 422 | +uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length) |
| 423 | +{ |
448 | 424 | 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); |
450 | 426 | uint8 b = 0; |
451 | 427 | // dma1_ch3_Active=true; |
452 | 428 | dma_init(_currentSetting->spiDmaDev); |
453 | 429 | // dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); |
454 | 430 |
|
455 | 431 | // TX |
456 | 432 | 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 |
459 | 436 | dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); |
460 | 437 | 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); |
465 | 438 |
|
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 | | - |
491 | 439 | // 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 | + } |
493 | 444 | dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); |
494 | 445 |
|
495 | 446 | while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." |
496 | 447 | while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." |
497 | 448 | dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); |
498 | 449 | 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! |
502 | 451 | return b; |
503 | 452 | } |
504 | 453 |
|
505 | | - |
506 | 454 | void SPIClass::attachInterrupt(void) { |
507 | 455 | // Should be enableInterrupt() |
508 | 456 | } |
|
0 commit comments