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