DmaSpi for teensyduino 1.20 RC2

Status
Not open for further replies.

christoph

Well-known member
DmaSpi for teensyduino

Old original post below, I'll now put the zipped library here.

Zipped Library:

Repo:
The repo is still at https://github.com/crteensy/DmaSpi and the master branch should be up to date.

Installation:
  • If you have the zip from here (name ends with a date):
    • Put the zip file wherever you want
    • In the arduino IDE, go to Sketch -> Import Library -> Add Library and pick the zip
  • If you have checked out the repo:
    • Close your arduino IDE
    • The library folder name after checking out is "DmaSpi-master" (or similar, depending on the branch), which is not a legal arduino library name (because it contains a dash)
    • copy or move it into a folder recognized as a library folder by your arduino installation
    • rename the library folder to "DmaSpi_master" or similar (the point here is to remove the dash)
    • reopen your arduino IDE and see if it shows up.
  • also see http://arduino.cc/en/pmwiki.php?n=Guide/Libraries

Example Sketch:
There is an example included in the library (examples/DMASpi_example1/DMASpi_example1.ino) that demonstrates most of the DmaSpi's capabilities. If the library is installed correctly, the arduino IDE should list it in File->Examples.



Old original post: (kept for reference only)

Yay!

Here's the new and disimproved DmaSpi library: https://github.com/crteensy/DmaSpi/tree/teensyduino_1.20_RC2 (make sure you get the correct branch)

It's only for use with teensyduino 1.20 RC2 (current master from https://github.com/paulstoffregen/cores). It's important to get the current fixes to DmaChannel.h which Paul pulled today (thanks!).

The following teensyduino RC2 features are used:
  • SPI transactions
  • Dynamic DMA channel allocation
  • Interrupt vector table in RAM

The interface has changed a bit, I'll include a sketch for testing purposes further down in this post. It demonstrates the use of transfers, starting, stopping and resuming the DmaSpi operation.

Especially starting and stopping of DMA transfers to and from the SPI has changed. Transfers can be registered after a call to DmaSpi0::begin(), but nothing will happen (yet), because the driver doesn't yet know if it may use the SPI. That's why the DmaSpi0::start() method has been added, which calls SPI.beginTransaction() with default settings.

DMA operation can be stopped by calling DmaSpi0::stop() and then waiting until DmaSpi0::stopped() returns true (the driver will finish a running transfer first and not start a new one when DmaSpi0::stop() was called). After that, other drivers can call SPI.beginTransaction(), use the SPI, and call SPI.endTransaction() again. After that, a call to DmaSpi0::start() allows the driver to handle any transfers that are still pending.

The ChipSelect classes are responsible for setting the SPI's speed, mode and bit order. The test sketch below includes a usage example (last block) that applies standard settings (you can change them, though) and uses pin 0 as chip select.

Test sketch (wiring info in line 10):
Code:
#include <WProgram.h>

#include <SPI.h>

#include <DmaSpi.h>



/** Hardware setup:
 plain Teensy 3.1 with DOUT connected to DIN, and an active low LED on pin 0
 nothing else
**/

/** buffers to send from and to receive to **/
#define DMASIZE 100
uint8_t src[DMASIZE];
volatile uint8_t dest[DMASIZE];
volatile uint8_t dest1[DMASIZE];

/** Wait for and consume a keypress over USB **/
void waitForKeyPress()
{
  Serial.println("\nPress a key to continue\n");
  while(!Serial.available());
  while(Serial.available())
  {
    Serial.read();
  }
}

void dumpBuffer(const volatile uint8_t* buf, const char* prefix)
{
  Serial.print(prefix);
  for (size_t i = 0; i < DMASIZE; i++)
  {
    Serial.printf("0x%02x ", buf[i]);
  }
  Serial.print('\n');
}
/** Compare the buffers and print the destination contents if there's a mismatch **/
void compareBuffers(const uint8_t* src_, const uint8_t* dest_)
{
  int n = memcmp((const void*)src_, (const void*)dest_, DMASIZE);
  if (n == 0)
  {
    Serial.println("src and dest match");
  }
  else
  {
    Serial.println("src and dest don't match");
    dumpBuffer(src_, " src: " );
    dumpBuffer(dest_, "dest: ");
  }
}

void setSrc()
{
  for (size_t i = 0; i < DMASIZE; i++)
  {
    src[i] = i;
  }
}

void clrDest(uint8_t* dest_)
{
  memset((void*)dest_, 0x00, DMASIZE);
}

void setup()
{
  waitForKeyPress();
  Serial.println("Hi!");

  /** Prepare source and destination **/
  setSrc();
  clrDest((uint8_t*)dest);
  Serial.println("Buffers are prepared");Serial.flush();

  /** set up SPI **/
  SPISettings spiSettings;
  SPI.begin();

  // transmit 10 bytes and measure time to get a feel of how long that takes
  SPI.beginTransaction(spiSettings);
  elapsedMicros us;
  for (size_t i = 0; i < DMASIZE; i++)
  {
    dest[i] = SPI.transfer(src[i]);
  }
  uint32_t t = us;
  Serial.print("Time for non-DMA transfer: ");Serial.print(t);Serial.println("us");
  SPI.endTransaction();
  compareBuffers(src, (const uint8_t*)dest);

  waitForKeyPress();

  DMASPI0.begin();

  DMASPI0.start();


  Serial.println("Testing src -> dest, single transfer");
  Serial.println("--------------------------------------------------");
  DmaSpi0::Transfer trx(src, DMASIZE, dest);
  clrDest((uint8_t*)dest);
  DMASPI0.registerTransfer(trx);
  while(trx.busy())
  {
  }
  Serial.println("Finished DMA transfer");
  compareBuffers(src, (const uint8_t*)dest);
  Serial.println("==================================================\n\n");


  Serial.println("Testing src -> discard, single transfer");
  Serial.println("--------------------------------------------------");
  trx = DmaSpi0::Transfer(src, DMASIZE, nullptr);
  DMASPI0.registerTransfer(trx);
  while(trx.busy())
  {
  }
  Serial.println("Finished DMA transfer");
  Serial.printf("last discarded value is 0x%02x\n", DMASPI0.devNull());
  if (DMASPI0.devNull() == src[DMASIZE-1])
  {
    Serial.println("That appears to be correct");
  }
  else
  {
    Serial.printf("That appears to be wrong, it should be src[DMASIZE-1] which is 0x%02x\n", src[DMASIZE-1]);
  }
  Serial.println("==================================================\n\n");


  Serial.println("Testing 0xFF dummy data -> dest, single transfer");
  Serial.println("--------------------------------------------------");
  trx = DmaSpi0::Transfer(nullptr, DMASIZE, dest, 0xFF);
  memset((void*)src, 0xFF, DMASIZE); // we need this for checking the dest buffer
  clrDest((uint8_t*)dest);
  DMASPI0.registerTransfer(trx);
  while(trx.busy())
  {
  }
  Serial.println("Finished DMA transfer");
  compareBuffers(src, (const uint8_t*)dest);
  Serial.println("==================================================\n\n");


  Serial.println("Testing multiple queued transfers");
  Serial.println("--------------------------------------------------");
  trx = DmaSpi0::Transfer(src, DMASIZE, dest, 0xFF);
  setSrc();
  clrDest((uint8_t*)dest);
  clrDest((uint8_t*)dest1);
  DmaSpi0::Transfer trx1(src, DMASIZE, dest1);
  DMASPI0.registerTransfer(trx);
  DMASPI0.registerTransfer(trx1);
  while(trx.busy());
  Serial.println("Finished DMA transfer");
  while(trx1.busy());
  Serial.println("Finished DMA transfer1");
  compareBuffers(src, (const uint8_t*)dest);
  compareBuffers(src, (const uint8_t*)dest1);
  Serial.println("==================================================\n\n");


  Serial.println("Testing pause and restart");
  Serial.println("--------------------------------------------------");
  clrDest((uint8_t*)dest);
  clrDest((uint8_t*)dest1);
  DMASPI0.registerTransfer(trx);
  DMASPI0.registerTransfer(trx1);
  DMASPI0.stop();
  us = elapsedMicros();
  while(!DMASPI0.stopped());
  t = us;
  while(trx.busy());
  Serial.printf("Time until stopped: %lu us\n", t);
  Serial.println("Finished DMA transfer");

  if (DMASPI0.stopped())
  {
    Serial.println("DMA SPI appears to have stopped (this is good)\nrestarting");
  }
  else
  {
    Serial.println("DMA SPI does not report stopped state, but it should. (this is bad)");
  }

  DMASPI0.start();
  while(trx1.busy());
  Serial.println("Finished DMA transfer1");
  compareBuffers(src, (const uint8_t*)dest);
  compareBuffers(src, (const uint8_t*)dest1);
  Serial.println("==================================================\n\n");


  Serial.println("Testing src -> dest, with chip select object");
  Serial.println("--------------------------------------------------");
  ActiveLowChipSelect cs(0, SPISettings());
  trx = DmaSpi0::Transfer(src, DMASIZE, dest, 0, &cs);
  clrDest((uint8_t*)dest);
  DMASPI0.registerTransfer(trx);
  while(trx.busy())
  {
  }
  Serial.println("Finished DMA transfer");
  compareBuffers(src, (const uint8_t*)dest);
  Serial.println("==================================================\n\n");


  DmaSpi0::Transfer(src, DMASIZE, dest, 0, &cs);

  if (DMASPI0.stopped())
  {
    Serial.println("DMA SPI stopped.");
  }
  else
  {
    Serial.println("DMA SPI is still running");
  }
  DMASPI0.stop();
  if (DMASPI0.stopped())
  {
    Serial.println("DMA SPI stopped.");
  }
  else
  {
    Serial.println("DMA SPI is still running");
  }

  DMASPI0.end();
  SPI.end();
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
  digitalWriteFast(LED_BUILTIN, true);
  delay(500);
  digitalWriteFast(LED_BUILTIN, false);
  delay(500);
}
 
Last edited:
A question to those more experienced with git:

The DmaSpi library for teensyduino 1.20 RC2 is currently in a separate branch (not master). The older version (for 1.18) also has its own branch. Would it be better to merge the 1.20 branch into master? When people clone the repo or arrive at the repos website, the branch that is shown is the master, which might not be what they want.
 
I'm gonna test with 3 libraries, TFT_ILI9163, gpio_expander and LiquidOLED tomorrow, I've already modified the code and compile without errors, just curious to see the DMA on LiquidOLED wait routine that use spi reading, it should be much faster and no more waits!
 
Have you used the previous DmaSpi library before? I have not yet updated the chip select classes, I'll do that tomorrow. The chip select objects have to configure the SPI for your device (speed, mode) and also handle the CS pin. There is a simple ActiveLowChipSelect class in ChipSelect.h which you can modify to apply the correct SPI settings.
 
Here's what ChipSelect.h might look like later (won't work yet):
Code:
#ifndef CHIPSELECT_H
#define CHIPSELECT_H

#include <core_pins.h> // <-- necessary!?

/** A abstract class that provides a chip select interface
**/

class AbstractChipSelect
{
	public:
    virtual void select() = 0;
    virtual void deselect() = 0;
		virtual ~AbstractChipSelect() {}
};

class DummyChipSelect : public AbstractChipSelect
{
  void select() override {}
  void deselect() override {}
};

/** An active low chip select class. This also configures the pin once.
**/
class ActiveLowChipSelect : public AbstractChipSelect
{
  public:
    ActiveLowChipSelect(const unsigned int& pin, const SPISettings& settings)
      : pin_(pin),
      settings_(settings)
    {
      pinMode(pin, OUTPUT);
      digitalWriteFast(pin, 1);
    }
    void select() override
    {
      applySpiSettings(settings_);
      digitalWriteFast(pin_, 0);
    }
    void deselect() override
    {
      applySpiSettings(SPISettings());
      digitalWriteFast(pin_, 1);
    }
  private:
    void applySpiSettings(const SPISettings& settings)
    {
      if (SPI0_CTAR0 != settings.ctar)
      {
        SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
        SPI0_CTAR0 = settings.ctar;
        SPI0_CTAR1 = settings.ctar| SPI_CTAR_FMSZ(8);
        SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
      }
    }
    const unsigned int pin_;
    const SPISettings& settings_;

//    static Init m_init;
};

#endif // CHIPSELECT_H
This won't work because SPISettings::ctar is private and can only be accessed by SPIClass (I've proposed a change: https://github.com/PaulStoffregen/SPI/pull/1). Instead, you can apply SPI settings on register level or do something that pops up now that I'm writing. In ActiveLowChipSelect:
Code:
  private:
    void applySpiSettings(const SPISettings& settings)
    {
      SPI.endTransaction();
      SPI.beginTransaction(settings);
    }
 
OK I've commited a slight change to ChipSelect.h for you to try. A dry test seemed to work well. I'll update the example sketch in the first post to demonstrate the new ActiveLowChipSelect class (edit: done).
 
Last edited:
oh, thanks! My bad I was try to understand why CS not work as suppose, I didn't read entirely your first post! I will try later the new change!
 
Sorry for delay christoph, I'm actually in a tiny island in greece and yesterday 12 hours of blackout, also internet hyperslow and almost unavailable most of the time, I'm actually power internet, notebook and Teensy with solar power. I had no luck with some TFT libraries so I decided to start again with some more basic, a GPIO chip (MCP23S17) but still no luck, I try to upload here the code I used, maybe I'm missing something!
 
That sounds great, actually!

Post your code and I'll have a look if you're using DmaSpi correctly. If that's the case, stay tuned for more commits, as I've already thought about modifying it a bit.
 
Here is my current DmaSpi code that should be working well. I worked through the internals and made two tests, one with a simple loopback (example sketch included) and one with external shift registers. If it doesn't work for you, please post the code you used for me to have a look.

Regards

Christoph

WARNING: The attached file is outdated. A newer version can be found in post #21 (http://forum.pjrc.com/threads/26479-DmaSpi-for-teensyduino-1-20-RC2?p=55837&viewfull=1#post55837)
 

Attachments

  • DmaSpi.zip
    5.4 KB · Views: 168
Last edited:
I have been looking into DMA SPI transfers and came across your library. Unfortunately, when compiling the example code, I get the following error:

Code:
Arduino: 1.0.6 + Td: 1.20-rc5 (Mac OS X), Board: "Teensy 3.1"
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/arm-none-eabi/bin/arm-none-eabi-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mcpu=cortex-m4 -DF_CPU=96000000 -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=106 -mthumb -nostdlib -D__MK20DX256__ -DTEENSYDUINO=120 -fno-rtti -felide-constructors -std=gnu++0x -DUSB_SERIAL -DLAYOUT_US_ENGLISH -I/Applications/Arduino.app/Contents/Resources/Java/hardware/teensy/cores/teensy3 -I/Users/troy/Documents/Arduino/libraries/DmaSpi -I/Applications/Arduino.app/Contents/Resources/Java/libraries/SPI /var/folders/dn/dntXHJyRHXmmRBJIgQrw1++++Tk/-Tmp-/build660635512682593202.tmp/DMASpi_example1.cpp -o /var/folders/dn/dntXHJyRHXmmRBJIgQrw1++++Tk/-Tmp-/build660635512682593202.tmp/DMASpi_example1.cpp.o 
In file included from DMASpi_example1.ino:1:0:
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h: In member function 'virtual void DebugChipSelect::select()':
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:25:27: error: 'Serial' was not declared in this scope
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h: In member function 'virtual void DebugChipSelect::deselect()':
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:26:29: error: 'Serial' was not declared in this scope
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h: At global scope:
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:34:56: error: 'SPISettings' does not name a type
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:34:69: error: ISO C++ forbids declaration of 'settings' with no type [-fpermissive]
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:53:11: error: 'SPISettings' does not name a type
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h: In constructor 'ActiveLowChipSelect::ActiveLowChipSelect(const unsigned int&, const int&)':
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:36:7: error: class 'ActiveLowChipSelect' does not have any field named 'settings_'
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h: In member function 'virtual void ActiveLowChipSelect::select()':
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:43:7: error: 'SPI' was not declared in this scope
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:43:28: error: 'settings_' was not declared in this scope
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h: In member function 'virtual void ActiveLowChipSelect::deselect()':
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:49:7: error: 'SPI' was not declared in this scope
DMASpi_example1.ino: At global scope:
DMASpi_example1:6: error: 'ActiveLowChipSelect' is not a template
DMASpi_example1:6: error: no matching function for call to 'ActiveLowChipSelect::ActiveLowChipSelect()'
DMASpi_example1.ino:6:25: note: candidates are:
In file included from DMASpi_example1.ino:1:0:
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:34:5: note: ActiveLowChipSelect::ActiveLowChipSelect(const unsigned int&, const int&)
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:34:5: note:   candidate expects 2 arguments, 0 provided
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:31:7: note: constexpr ActiveLowChipSelect::ActiveLowChipSelect(const ActiveLowChipSelect&)
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:31:7: note:   candidate expects 1 argument, 0 provided

I have Arduino 1.06 and Teensy 1.20 RC5. I think I have the latest version of your DmaSPI Library. Any suggestions?

I am using the example code:

Code:
#include <ChipSelect.h>
#include <DmaSpi.h>
#include <SPI.h>

// create a chip select object. This one uses pin 14.
ActiveLowChipSelect<14> cs;

void setup() {
  DMASPI0.begin();
  // create a transfer object
  DmaSpi0::Transfer trx(nullptr, 100, nullptr, 0xFF, &cs);

  // and register it. If the DMA SPI is idle, it will immediately start transmitting. Otherwise the transfer is added to a queue.
  DMASPI0.registerTransfer(trx);

  /** FREE CPU TIME YOU DIDN'T HAVE BEFORE! DO SOMETHING USEFUL! **/

  // wait for the transfer to finish
  while(trx.busy());
}

void loop() {

}



Here is my current DmaSpi code that should be working well. I worked through the internals and made two tests, one with a simple loopback (example sketch included) and one with external shift registers. If it doesn't work for you, please post the code you used for me to have a look.

Regards

Christoph
 
Hi spectasaurus,

thanks for trying! The first error indicates that Serial is not known to the compiler at that point, but it is declared in the main teensyduino header WProgram.h. ChipSelect.h just doesn't include that. DmaSpi.h, however, does. It also includes ChipSelect.h, so try removing the first include directive:
Code:
#include <DmaSpi.h>
#include <SPI.h>

// create a chip select object. This one uses pin 14.
ActiveLowChipSelect<14> cs;

void setup() {
  DMASPI0.begin();
  // create a transfer object
  DmaSpi0::Transfer trx(nullptr, 100, nullptr, 0xFF, &cs);

  // and register it. If the DMA SPI is idle, it will immediately start transmitting. Otherwise the transfer is added to a queue.
  DMASPI0.registerTransfer(trx);

  /** FREE CPU TIME YOU DIDN'T HAVE BEFORE! DO SOMETHING USEFUL! **/

  // wait for the transfer to finish
  while(trx.busy());
}

void loop() {

}

Are you using the arduino IDE?

Regards

Christoph
 
Thanks. Yes, I am using the Arduino IDE.

I have tried this revision, but I get the following error:

sketch_oct07a:5: error: 'ActiveLowChipSelect' is not a template
sketch_oct07a:5: error: no matching function for call to 'ActiveLowChipSelect::ActiveLowChipSelect()'
sketch_oct07a.ino:5:25: note: candidates are:
In file included from /Users/troy/Documents/Arduino/libraries/DmaSpi/DmaSpi.h:13:0,
from sketch_oct07a.ino:1:
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:34:5: note: ActiveLowChipSelect::ActiveLowChipSelect(const unsigned int&, const SPISettings&)
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:34:5: note: candidate expects 2 arguments, 0 provided
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:31:7: note: constexpr ActiveLowChipSelect::ActiveLowChipSelect(const ActiveLowChipSelect&)
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:31:7: note: candidate expects 1 argument, 0 provided

I have added the following template declaration for ActiveChipSelectLow in ChipSelect.h:

Code:
#ifndef CHIPSELECT_H
#define CHIPSELECT_H

#include <core_pins.h>

/** A abstract class that provides a chip select interface
**/

class AbstractChipSelect
{
        public:
    virtual void select() = 0;
    virtual void deselect() = 0;
                virtual ~AbstractChipSelect() {}
};

class DummyChipSelect : public AbstractChipSelect
{
  void select() override {}
  void deselect() override {}
};

class DebugChipSelect : public AbstractChipSelect
{
  void select() override {Serial.println("Dummy CS: select()");}
  void deselect() override {Serial.println("Dummy CS: deselect()");}
};

/** An active low chip select class. This also configures the pin once.
**/
[B]template<unsigned int pin>[/B]
class ActiveLowChipSelect : public AbstractChipSelect
{
  public:
    ActiveLowChipSelect(const unsigned int& pin, const SPISettings& settings)
      : pin_(pin),
      settings_(settings)
    {
      pinMode(pin, OUTPUT);
      digitalWriteFast(pin, 1);
    }
    void select() override
    {
      SPI.beginTransaction(settings_);
      digitalWriteFast(pin_, 0);
    }
    void deselect() override
    {
      digitalWriteFast(pin_, 1);
      SPI.endTransaction();
    }
  private:
    const unsigned int pin_;
    const SPISettings& settings_;

};

#endif // CHIPSELECT_H

But now I get the error relating to no matching function for call to 'ActiveLowChipSelect<14u>::ActiveLowChipSelect()' in the IDE:

Arduino: 1.0.6 + Td: 1.20-rc5 (Mac OS X), Board: "Teensy 3.1"
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/arm-none-eabi/bin/arm-none-eabi-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mcpu=cortex-m4 -DF_CPU=72000000 -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=106 -mthumb -nostdlib -D__MK20DX256__ -DTEENSYDUINO=120 -fno-rtti -felide-constructors -std=gnu++0x -DUSB_SERIAL -DLAYOUT_US_ENGLISH -I/Applications/Arduino.app/Contents/Resources/Java/hardware/teensy/cores/teensy3 -I/Users/troy/Documents/Arduino/libraries/DmaSpi -I/Applications/Arduino.app/Contents/Resources/Java/libraries/SPI /var/folders/dn/dntXHJyRHXmmRBJIgQrw1++++Tk/-Tmp-/build2844571224604834876.tmp/sketch_oct07a.cpp -o /var/folders/dn/dntXHJyRHXmmRBJIgQrw1++++Tk/-Tmp-/build2844571224604834876.tmp/sketch_oct07a.cpp.o
In file included from /Users/troy/Documents/Arduino/libraries/DmaSpi/DmaSpi.h:13:0,
from sketch_oct07a.ino:1:
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:35:45: error: declaration of 'const unsigned int& pin'
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:31:10: error: shadows template parm 'unsigned int pin'
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h: In constructor 'ActiveLowChipSelect<pin>::ActiveLowChipSelect(const unsigned int&, const SPISettings&)':
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:35:5: error: declaration of 'const unsigned int& pin'
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:31:10: error: shadows template parm 'unsigned int pin'
sketch_oct07a.ino: At global scope:
sketch_oct07a:5: error: no matching function for call to 'ActiveLowChipSelect<14u>::ActiveLowChipSelect()'
sketch_oct07a.ino:5:25: note: candidates are:
In file included from /Users/troy/Documents/Arduino/libraries/DmaSpi/DmaSpi.h:13:0,
from sketch_oct07a.ino:1:
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:35:5: note: ActiveLowChipSelect<pin>::ActiveLowChipSelect(const unsigned int&, const SPISettings&) [with unsigned int pin = 14u]
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:35:5: note: candidate expects 2 arguments, 0 provided
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:32:7: note: constexpr ActiveLowChipSelect<14u>::ActiveLowChipSelect(const ActiveLowChipSelect<14u>&)
/Users/troy/Documents/Arduino/libraries/DmaSpi/ChipSelect.h:32:7: note: candidate expects 1 argument, 0 provided

Any thoughts?
 
Yes indeed! The ActiveLowChipSelect class changed a bit since I wrote it for teensyduino 1.18 and somehow the old constructor call is still in the example. In the class definition you posted there's a constructor that takes an unsigned int (the pin number) and an SpiSettings object as arguments. That's the only available constructor, so you have to use it, like this:
Code:
SPISettings mySettings; // <- adjust SPI settings to your needs
ActiveLowChipSelect cs(14, mySettings);
You can remove the template declaration you added, it's just the constructor arguments that were missing.

Regards

Christoph
 
Eeeew...I need to do some tests and update code/examples later today to clean up this mess. Apparently, nothing is quite fitting. Sorry for that!
 
OK, so I guess it's not just me then. I am still having some issues. It's getting caught up in the while(trx.busy()); loop.

I am trying to make 24 bit word transfers using SPI at 24 MHz, and was hoping DMA + SPI would help eliminate the gap in sending 8 bit + 16 bit words within one chip select assertion. I have done this previously with the Arduino Due and it worked well using DMA, so I had hopes for the Teensy as well. My existing code yields the following. Notice the ~100ns delay between 8 bit and 16 bit frames.

SPI_gaps.jpg





Eeeew...I need to do some tests and update code/examples later today to clean up this mess. Apparently, nothing is quite fitting. Sorry for that!
 
OK, here's a zip with an updated example, that demonstrates most of the library's features. The only thing you need is a connection between the SPI's DOUT (pin 11) and DIN (12), as it makes a loopback test:

View attachment DmaSpi.zip

See if that works, please.

I will change the internal usage of SPI transactions a bit, but that shouldn't affect you as long as you don't write your own custom chip select classes - which brings me to your use case:

SPI with DMA only pays off if you have transfers longer than about 10 bytes. This is mostly due to the overhead involved in maintaining the queue of transfers and setting them up. In your case, do you need to change any chip select lines between the 8-bit and the 16-bit word sent to the device? Are all three bytes stored in a contiguous block of memory?

If all you need is to send those 3 bytes to your device, it might be better to use the SPI directly and hack together a command that first pushes and 8-it word to the FIFO and then a 16-bit word. If you can stuff multiple of those 3-byte packets into a longer buffer, DMA can be beneficial again.

Regards

Christoph
 
This seems to be working, although I will run it through some more tests. I found I had to add an #include <SPI.h> header. But no big deal.

I am communicating with a device that uses 24 bit words, but since the ARM doesn't support words longer than 16 bits, I have to separate this into separate 8 and 16 bit words, and send them back to back within one CS assert. This is working pretty well, but leaves the 100 ns gap between the words. I can guarantee that the entire 24 bits are contiguous since they are held as a 32 bit uint on the ARM (I only care about the lower 24 bits). I was really hoping that DMA would reduce this gap as it did on the Due.
 
OK, then it's at least possible to make a 3-byte transfer using DmaSpi. But if you need single 3-byte transfers between a pair of CS assert/deassert, you won't get an overall increase in speed because the amount of data is simply too small. So what is the goal you are trying to achieve by getting rid of the 100 ns gap?
 
I appreciate the help on this, Christoph. I am communicating with a sensor that send 24 bit words at 24MHz. I am not sure how the sensor will behave with a short gap between the 8 bit and 16 bit frames. So, aside from the elegance factor keeping the 24 bit frame together in one uniformly spaced piece, I am also interested in reducing latency as much as possible as this may reduce the overall readout rate of the sensor. Granted, I seem to be getting over 500k 24 bit words per second (12Mbs) each with individual CS asserts/deasserts, so this might be acceptable. Thanks again for the great work.

OK, then it's at least possible to make a 3-byte transfer using DmaSpi. But if you need single 3-byte transfers between a pair of CS assert/deassert, you won't get an overall increase in speed because the amount of data is simply too small. So what is the goal you are trying to achieve by getting rid of the 100 ns gap?
 
With a little hacking you can create a self-repeating chain of transfers, say 8, and a custom chip select class. Together they could feed a FIFO with timestamped values.
 
Status
Not open for further replies.
Back
Top