DmaSpi for teensyduino 1.20 RC2

Status
Not open for further replies.
OK, let's start with the last part of you post:

The difference between
Code:
trx = DmaSpi0::Transfer(src, DMASIZE, dest);
and
Code:
DmaSpi0::Transfer trx(src, DMASIZE, dest);
is that the first one can be made use of, and the second is absolutely useless. When a transfer is created by the constructor, it merely describes what should be done by the DMA SPI driver. Constructing a transfer does not register it for handling -registerTransfer(trx) must be used to actually queue up a transfer.

This should also clarify why the second line is useless - you cannot register the transfer that was just created, and the compiler might even optimize it away entirely (I'm not sure about that, though).

If you want to handle multiple transfers, one after each other, with the least possible amount of delay between them, here's how (with 3 transfers, pseudo-code):
Code:
create transfer0 (src, size, dest)
create transfer1 (src, size, dest)
create transfer2 (src, size, dest)

register transfer0
register transfer1
register transfer2

in a loop:
  if transfer0.done() == true
    register transfer0

  do something useful

  if transfer1.done() == true
    register transfer1

  do something useful

  if transfer2.done() == true
    register transfer2

  do something useful
This can be slightly dangerous, though, because with very short transfers you might mess up their order. I'll now have a closer look at you actual code to see if I can spot potential problems. From what I've already seen, you don't seem to make any serious mistakes here!
 
OK, I had a look at your code. As far as I can tell, most of your basic usage of the DMA SPI driver and the transfer object is ok, so let's dissect the main loop for a single transfer:

Code:
void loop()
{
  ActiveLowChipSelect cs(10, SPISettings());
This looks dangerous! Your cs object is constructed locally, on the stack. This means that it will be destroyed once it goes out of scope at the end of loop(), and in the next iteration it will be constructed again. However, your transfer objects keep a pointer to it, and depending on the adress that cs has in the next iteration, this can work or not. If cs is reconstructed at the exact same address in the next iteration of loop(), this is just a "sleeping" bug that won't have any real effect. You can work around this destroying and reconstructing cs again and again by making it a static local variable: static ActiveLowChipSelect cs(10, SPISettings()); You can also turn it into a global variable (but prefer a static local if you can!).

After re-reading the whole I thing I notices that you also have a global variable with the same name. This won't confuse your compiler, but everyone else (including yourself) and you should get a warning about an unused variable.

When an ActiveLowChipSelect is constructed, the pin is configured as an output and set to high (usually this deselects the connected slave chip). This means that in every iteration of loop(), while the transfers are still running, your chip will be deselected. This will break your SPI communication. Again, this will be fixed by making cs static or global. See https://github.com/crteensy/DmaSpi/blob/master/ChipSelect.h for the constructor implementation.
Code:
  if (trans0.busy()==0 && req[0]==1){
    // Serial.println("Q 0 ");
    us0=micros();
    trans0 = DmaSpi0::Transfer(read_cmd0, DMASIZE-4, dest0, 0, &cs);
    DMASPI0.registerTransfer(trans0);
    sent[0]=1;
    req[0]=0;

    //Serial.print(micros()-us1);Serial.println(" 0 us");

  }
If transfer0 is not busy and the req flag is set, create a transfer (you can reuse transfer objects btw, there's no need to reconstruct them every time you need the same transfer again) and register it. The sent flag is set, and req is cleared. Looks fine.
Code:
  if (trans0.busy()==0 && sent[0]==1){

    uint32_t t2 = micros()-us0;

    if ((millis()-prev2)>1000){
      prev2=millis();

      Serial.println("dest0: ");

      for (int i = 4; i < 127+4; ++i)
      {
        Serial.print(dest0[i]);
        Serial.print(" ");
      }
      Serial.println();
    }
    sent[0]=0;
    req[0]=1;
    clrDest((uint8_t*)dest0);
  }

  // waste time
If transfer0 is not busy and the sent flag is set, clear the sent flag and set the req flag. The previous code snippet should catch this condition, because transfer0 is still not busy and will re-create and re-register transfer0. You then do some timing trickery (seriously I don't understand that code, but it looks like it could benefit from the elapsedMillis and elapsedMicros classes: https://www.pjrc.com/teensy/td_timing_elaspedMillis.html) and print out the transfer's destination buffer.

The two transfer objects you are using do not depend on each other's state at all. Is that correct?

You have some magic numbers in there. Please replace them with constants (prefer static const uint8_t and similar constructs over defines, because they are typesafe). Your two transfers have different lengths, but you print out the same number of destination bytes when the transfer is done.

So first of all, make cs static or move it to global scope. Prefer static, though:

Code:
// ActiveLowChipSelect cs(10, SPISettings()); <-- REMOVE GLOBAL

// DmaSpi0::Transfer trans0(read_cmd0, DMASIZE, dest0, 0, &cs); <-- REMOVE GLOBAL
// DmaSpi0::Transfer trans1(read_cmd1, DMASIZE, dest1, 0, &cs); <-- REMOVE GLOBAL

void loop()
{

  ///Serial.println("start");

  //Serial.print(trans0.busy());  Serial.println(" 0busy");
  // Serial.print(trans1.busy());  Serial.println(" 1busy");

  static ActiveLowChipSelect cs(10, SPISettings()); <-- MAKE CS STATIC
  static DmaSpi0::Transfer trans0(read_cmd0, DMASIZE, dest0, 0, &cs); <-- ADD THESE TWO
  static DmaSpi0::Transfer trans1(read_cmd1, DMASIZE, dest1, 0, &cs); <---|

  // rest of your loop code goes here, as it is, but try to remove the time wasting code.

Regards

Christoph
 
Thank you very much for the detailed response!

Unfortunately removing them from global and adding the static lines doesn't work either. Both transfers just stay "busy"


You then do some timing trickery...
Yes it's just do I can keep the loop going as fast as possible and not Serial.print a jillion times a second.
I've also tried it by only sending the requests every second with the same results.

The two transfer objects you are using do not depend on each other's state at all. Is that correct?
Correct

You have some magic numbers in there. Please replace them with constants (prefer static const uint8_t and similar constructs over defines, because they are typesafe).
Which ones do you see taht would cause an issue? I'm pretty in the dark about this whole concept.

Your two transfers have different lengths, but you print out the same number of destination bytes when the transfer is done.
Yes I'm only writing 0-255 in the first 256 bytes of the serial flash. The two reads are from bytes 0-255 and 64-319 where the last 64 values will just be empty (255).


I have this entire system working well using spi4teensy3, I'd just like it to run faster at the expense of some latency.

Thanks again!
 
Can you please check the transfer objects for an error state? Something like
Code:
if (trans0.m_state == DmaSpi0::Transfer::State::error)
{
  Serial.println("transfer 0 error");
  while(1);
}
to see if there's anything going wrong. Do this check at two points (with individual error messages)
  • after registering the transfer
  • before checking if it's busy

What else might go wrong? Make sure you have the latest code from github, and use teensyduino 1.20 (release)
 
Does the example that ships the DmaSpi work on your teensy? It should print out all sorts of confirmations that everything is fine.
 
I added this before the time waster analogWrites

Code:
if (trans0.m_state == DmaSpi0::Transfer::State::error)
{
  Serial.println("transfer 0 error");
  while(1);
}

if (trans1.m_state == DmaSpi0::Transfer::State::error)
{
  Serial.println("transfer 1 error");
  while(1);
}

if ((millis()-prev3)>500){
    prev3=millis();
  Serial.print(trans0.busy());  Serial.println(" 0 busy");
   Serial.print(trans1.busy());  Serial.println(" 1 busy");

}

I don't get any errors but the 0 stays busy and 1 goes back and forth without printing the received array.

Like before if delay(200) is added to the end everything works. This is why I was wondering if I was using, done, transferring, etc incorrectly.
 
Yes the example works. I just installed the most recent version of everything.

I have the same issues when the teensy is not connected to the serial flash.

Code:
#include <WProgram.h>

#include <SPI.h>
#include <DmaSpi.h>

#define DMASIZE 255

#define cs_pin  10   //Chip select pin


uint8_t src[DMASIZE];
volatile uint8_t dest[DMASIZE];
volatile uint8_t dest0[DMASIZE];
volatile uint8_t dest1[DMASIZE];


SPISettings spiSettings;

byte read_cmd0[DMASIZE]={
  0x03,0,0,0};
byte read_cmd1[DMASIZE]={
  0x03,0,0,0x40};


byte sent[8]={
};
byte req[8]={
  1,1,1,1,1,1,1,1};

uint32_t us1,us2,us3,us4,us0;

long prev1,prev2,prev3;
byte busy0;
byte printq[8]={
};
byte received_sample[8]={
};


///////////////////////////////////////////////////////////////////////////

void setSrc()
{
  for (size_t i = 0; i < DMASIZE; i++)
  {
    // int r = random(0,255);
    src[i] = i;
    Serial.print(src[i],HEX);
    Serial.print(" ");

  }
  Serial.println();
  Serial.println("src'd");


}

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


//////////////////////////////s25fl commands

byte stat(){  
  SPI.beginTransaction(spiSettings);  
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0x05);
  byte stat = SPI.transfer(0);
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();
  return stat;
}

void waitforit (){
  while ((stat() & B0000001)==B00000001)
  {

  }
  Serial.println("flash ready");
}

void write_enable(){

  SPI.beginTransaction(spiSettings);   
  digitalWriteFast(cs_pin,LOW);
  SPI.transfer(0x06);
  digitalWriteFast(cs_pin,HIGH);
  SPI.endTransaction();

  waitforit();
}


///////////////////////////////////////////////////////////////////////////////

void setup()
{
  randomSeed(A0);
  while (!Serial) {
  }

  delay(100);
  //     Serial.println("jhey");


  pinMode(cs_pin, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);

  delay(1000);
  randomSeed(A1);

  /** Prepare source and destination **/
  setSrc();
  clrDest((uint8_t*)dest);
  Serial.flush();

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

  write_enable();
  SPI.beginTransaction(spiSettings);   //errase first 64k
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0xD8);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();
  waitforit ();
  // Serial.println("errased");
  write_enable();

  SPI.beginTransaction(spiSettings);   //write
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0x02);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(src, DMASIZE);
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();
  waitforit ();
  //  Serial.println("written");


  SPI.beginTransaction(spiSettings);   //read
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0x03);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  for (int i = 0; i < DMASIZE; ++i)
  {
    dest[i]=SPI.transfer(0);

  }
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();    
  waitforit ();

  //   Serial.println("read");


  Serial.flush();

  DMASPI0.begin();
  DMASPI0.start();


  ActiveLowChipSelect cs(10, SPISettings()); //cs seems to work
  DmaSpi0::Transfer trans0(src, 1, dest);
  trans0 = DmaSpi0::Transfer(read_cmd0, DMASIZE, dest, 0, &cs);

  DMASPI0.registerTransfer(trans0);

  while (trans0.done()==0){
  };

  for (int i = 4; i < 127+4; ++i)
  {
    Serial.print(dest[i]);
    Serial.print(" ");

  }

}

//////////////////////////////////////////////////////////////////////////





void loop()
{

  ///Serial.println("start");

  //Serial.print(trans0.busy());  Serial.println(" 0busy");
  // Serial.print(trans1.busy());  Serial.println(" 1busy");

static ActiveLowChipSelect cs(10, SPISettings()); 

static DmaSpi0::Transfer trans0(read_cmd0, DMASIZE, dest0, 0, &cs);
static DmaSpi0::Transfer trans1(read_cmd1, DMASIZE, dest1, 0, &cs);



  if (trans0.busy()==0 && req[0]==1){
    // Serial.println("Q 0 ");
    us0=micros();
    trans0 = DmaSpi0::Transfer(read_cmd0, DMASIZE-4, dest0, 0, &cs);
    DMASPI0.registerTransfer(trans0);
    sent[0]=1;
    req[0]=0;

    //Serial.print(micros()-us1);Serial.println(" 0 us");

  }

  if (trans1.busy()==0 && req[1]==1){
   // Serial.println("Q 1 ");
    us1=micros();
    //ActiveLowChipSelect cs(10, SPISettings()); 
    trans1 = DmaSpi0::Transfer(read_cmd1, DMASIZE, dest1, 0, &cs);
    DMASPI0.registerTransfer(trans1);
    sent[1]=1;
    req[1]=0;

    // Serial.print(micros()-us1);Serial.println(" 1 us");

  }




  if (trans0.busy()==0 && sent[0]==1){

    uint32_t t2 = micros()-us0;

    if ((millis()-prev2)>1000){
      prev2=millis();

      Serial.println("dest0: ");

      for (int i = 4; i < 127+4; ++i)
      {
        Serial.print(dest0[i]);
        Serial.print(" ");

      }

      Serial.println();

    }

    //Serial.print(t2);Serial.println(" us0");
    sent[0]=0;
    req[0]=1;
    clrDest((uint8_t*)dest0);

    //delay(1000);


  }

  if (trans1.busy()==0 && sent[1]==1){

    uint32_t t3 = micros()-us1;


    if ((millis()-prev1)>1000){
      prev1=millis();

      Serial.println("dest1: ");

      for (int i = 4; i < 127+4; ++i)
      {
        Serial.print(dest1[i]);
        Serial.print(" ");

      }

      Serial.println();

    }

    //Serial.print(t3);Serial.println(" us1");
    sent[1]=0;
    req[1]=1;
    clrDest((uint8_t*)dest1);

    //delay(1000);


  }

if (trans0.m_state == DmaSpi0::Transfer::State::error)
{
  Serial.println("transfer 0 error");
  while(1);
}

if (trans1.m_state == DmaSpi0::Transfer::State::error)
{
  Serial.println("transfer 1 error");
  while(1);
}

if ((millis()-prev3)>500){
    prev3=millis();
  Serial.print(trans0.busy());  Serial.println(" 0 busy");
   Serial.print(trans1.busy());  Serial.println(" 1 busy");

}


  // waste time 
  for (int i = 0; i < 100; ++i)
  {
    byte r,b,g;
    r=(micros()>>24) & 127;
    g=(micros()>>16) & 127;
    b=(micros()>>8) & 127;
    analogWrite(3,g);
    analogWrite(4,b);
    analogWrite(5,r);
  }

delay(100);

}
 
Last edited:
Try to use a non-temporary object for the SPI settings:
Code:
void loop()
{
  SPISettings spiSettings;
  static ActiveLowChipSelect cs(10, spiSettings); 

  static DmaSpi0::Transfer trans0(read_cmd0, DMASIZE, dest0, 0, &cs);
  static DmaSpi0::Transfer trans1(read_cmd1, DMASIZE, dest1, 0, &cs);
and leave the rest as it is. Does that change anything?
 
That's odd, really. I'll do some testing as soon as I can (later today or tomorrow) to see what's happening. Just to clarify:

Do you still get the desired behavior when you add the time wasting code at the end of the loop?

Having the teensy disconnected from the flash shouldn't make any difference for the SPI and the DMA SPI driver. An absent SPI slave will only have an effect when the code tries to act on values read from the slave, as in your stat() and waitforit() functions. You main loop doesn't use those.
 
With SPISettings spiSettings; added at the beginning it now needs to be a delay(500) for it to get data back.

Having the teensy disconnected from the flash shouldn't make any difference for the SPI and the DMA SPI driver. An absent SPI slave will only have an effect when the code tries to act on values read from the slave, as in your stat() and waitforit() functions. You main loop doesn't use those.

Right I meant that you don't need the flash chip to get the same response out of it.


Here is some simplified code that is a little cleaner and better illustrates what parts are triggered when.

Code:
#include <WProgram.h>

#include <SPI.h>
#include <DmaSpi.h>

#define DMASIZE 255

#define cs_pin  10   //Chip select pin


uint8_t src[DMASIZE];
volatile uint8_t dest[DMASIZE];
volatile uint8_t dest0[DMASIZE];
volatile uint8_t dest1[DMASIZE];


SPISettings spiSettings;

byte read_cmd0[DMASIZE]={
  0x03,0,0,0};
byte read_cmd1[DMASIZE]={
  0x03,0,0,0x40};


byte sent[8]={
};
byte req[8]={
  1,1,1,1,1,1,1,1};

uint32_t us1,us2,us3,us4,us0;

long prev1,prev2,prev3,prev0;
byte busy0;
byte printq[8]={
};
byte received_sample[8]={
};


///////////////////////////////////////////////////////////////////////////

void setSrc()
{
  for (size_t i = 0; i < DMASIZE; i++)
  {
    // int r = random(0,255);
    src[i] = i;
    Serial.print(src[i],HEX);
    Serial.print(" ");

  }
  Serial.println();
  Serial.println("src'd");


}

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


//////////////////////////////s25fl commands

byte stat(){  
  SPI.beginTransaction(spiSettings);  
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0x05);
  byte stat = SPI.transfer(0);
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();
  return stat;
}

void waitforit (){
  while ((stat() & B0000001)==B00000001)
  {

  }
  //Serial.println("flash ready");
}

void write_enable(){

  SPI.beginTransaction(spiSettings);   
  digitalWriteFast(cs_pin,LOW);
  SPI.transfer(0x06);
  digitalWriteFast(cs_pin,HIGH);
  SPI.endTransaction();

  waitforit();
}


///////////////////////////////////////////////////////////////////////////////

void setup()
{
  randomSeed(A0);
  while (!Serial) {
  }

  delay(100);
  //     Serial.println("jhey");


  pinMode(cs_pin, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);

  delay(1000);
  randomSeed(A1);

  /** Prepare source and destination **/
  setSrc();
  clrDest((uint8_t*)dest);
  Serial.flush();

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

  write_enable();
  SPI.beginTransaction(spiSettings);   //errase first 64k
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0xD8);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();
  waitforit ();
  // Serial.println("errased");
  write_enable();

  SPI.beginTransaction(spiSettings);   //write
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0x02);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(src, DMASIZE);
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();
  waitforit ();
  //  Serial.println("written");


  SPI.beginTransaction(spiSettings);   //read
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0x03);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  for (int i = 0; i < DMASIZE; ++i)
  {
    dest[i]=SPI.transfer(0);

  }
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();    
  waitforit ();

  //   Serial.println("read");


  Serial.flush();

  DMASPI0.begin();
  DMASPI0.start();


  ActiveLowChipSelect cs(10, SPISettings()); //cs seems to work
  DmaSpi0::Transfer trans0(src, 1, dest);
  trans0 = DmaSpi0::Transfer(read_cmd0, DMASIZE, dest, 0, &cs);

  DMASPI0.registerTransfer(trans0);

  while (trans0.done()==0){
  };

  for (int i = 4; i < 127+4; ++i)
  {
    Serial.print(dest[i]);
    Serial.print(" ");

  }

}

//////////////////////////////////////////////////////////////////////////





void loop()
{

  SPISettings spiSettings;

  static ActiveLowChipSelect cs(10, SPISettings()); 

  static DmaSpi0::Transfer trans0(read_cmd0, DMASIZE, dest0, 0, &cs);
  static DmaSpi0::Transfer trans1(read_cmd1, DMASIZE, dest1, 0, &cs);

  //delay(500); //add this and it works


  if ((millis()-prev0)>1000){  //// send requnests every second
    prev0=millis();


    Serial.println();
    Serial.println();



    if (trans0.busy()==1)
    {
      Serial.println("   0 is busy"); 
    }

    if (trans1.busy()==1)
    {
      Serial.println("   1 is busy"); 
    }

    Serial.println("send req 0 ");
    Serial.println("send req 1 ");
    req[0]=1;
    req[1]=1;


  }



  if (trans0.busy()==0 && req[0]==1){
    Serial.println("      Transfering 0 ");
    us0=micros();
    trans0 = DmaSpi0::Transfer(read_cmd0, DMASIZE-4, dest0, 0, &cs);
    DMASPI0.registerTransfer(trans0);
    sent[0]=1;
    req[0]=0;

    //Serial.print(micros()-us1);Serial.println(" 0 us");

  }

  if (trans1.busy()==0 && req[1]==1){
    Serial.println("      Transfering 1 ");
    us1=micros();
    //ActiveLowChipSelect cs(10, SPISettings()); 
    trans1 = DmaSpi0::Transfer(read_cmd1, DMASIZE, dest1, 0, &cs);
    DMASPI0.registerTransfer(trans1);
    sent[1]=1;
    req[1]=0;

    // Serial.print(micros()-us1);Serial.println(" 1 us");

  }




  if (trans0.busy()==0 && sent[0]==1){

    uint32_t t2 = micros()-us0;

    Serial.println("   Recieved 0");

    sent[0]=0;
    //req[0]=0;
    clrDest((uint8_t*)dest0);

  }


  if (trans1.busy()==0 && sent[1]==1){

    uint32_t t3 = micros()-us1;

    Serial.println("   Recieved 1");

    sent[1]=0;
    //req[1]=0;
    clrDest((uint8_t*)dest1);

  }


  if (trans0.m_state == DmaSpi0::Transfer::State::error)
  {
    Serial.println("transfer 0 error");
    while(1);
  }

  if (trans1.m_state == DmaSpi0::Transfer::State::error)
  {
    Serial.println("transfer 1 error");
    while(1);
  }

  if ((millis()-prev3)>500){
    prev3=millis();


  }

  /*
  // waste time 
   for (int i = 0; i < 100; ++i)
   {
   byte r,b,g;
   r=(micros()>>24) & 127;
   g=(micros()>>16) & 127;
   b=(micros()>>8) & 127;
   analogWrite(3,g);
   analogWrite(4,b);
   analogWrite(5,r);
   }
   */


}
 
OK, I ran your code and the first three blocks of output in loop() are:

Code:
send req 0 
send req 1 
      Transfering 0 
      Transfering 1 
   Recieved 0
   Recieved 1

send req 0 
send req 1 
      Transfering 0 
      Transfering 1 

   0 is busy
   1 is busy
send req 0 
send req 1

Round 1:
The transfers seem to be handled by the driver. There are also no errors, and together that means that the interrupt service routine for the receiving DMA channel was called - there is no other way that the transfer can get flagged as "not busy", unless there is memory corruption happening somewhere. The "receiving" part of the code catches the completed transfer and flags it for the next "send" iteration.

Round 2:
The transfers are queued up again - we get the correct message " Transfering 0" on the terminal, indicating that the transfers were registered with the DMA SPI driver. This time, however, there is no matching pair of success messages.

Round 3:
Nothing happened. Oh crap.

I uncommented all the debugging messages in DmaSpi.h and they revealed that the Rx ISR for rounds 2 and all following is not called - there's no interrupt. If you like, you can see that as well when you uncomment all those messages in your copy of the library. However, there's a little detail missing in the sketch you posted above (the last one you posted, the cleaned up version): You're still using a temporary SPISettings object to construct your transfers. For comparison, consider this sketch (which seems to work as intended):

Code:
#include <WProgram.h>

#include <SPI.h>
#include <DmaSpi.h>

#define DMASIZE 255

#define cs_pin  10   //Chip select pin


uint8_t src[DMASIZE];
volatile uint8_t dest[DMASIZE];
volatile uint8_t dest0[DMASIZE];
volatile uint8_t dest1[DMASIZE];


byte read_cmd0[DMASIZE]={
  0x03,0,0,0};
byte read_cmd1[DMASIZE]={
  0x03,0,0,0x40};

void setup()
{
  randomSeed(A0);
  while (!Serial) {
  }

  SPI.begin();
  DMASPI0.begin();
  DMASPI0.start();
}

void loop()
{
  static uint16_t counter = 0;

  static SPISettings spiSettings;
  static ActiveLowChipSelect cs(10, spiSettings); // <-- WORKS
//  static ActiveLowChipSelect cs(10, SPISettings()); // <-- DOESN'T WORK, BUT YOU STILL HAVE THIS! 
  static DmaSpi0::Transfer trans0(read_cmd0, DMASIZE, dest0, 0, &cs);

  static bool request = true;
  
  if (request)
  {
    Serial.print("registering transfer: ");
    Serial.println(DMASPI0.registerTransfer(trans0));
    request = false;
  }
  else if(trans0.busy() == false)
  {
    Serial.println("transfer done");
    request = true;
    counter++;
    Serial.print("count: ");Serial.println(counter);
  }

}
Replacing the static with a temporary SPISettings object resulted in the behavior seen previously - it works once, but not again after that. So, try again with a static settings object, please. I've tried it on my machine (your code, but using the static settings object) and it seemed to work.

Regards

Christoph
 
Ok it seems to work!
Sorry, I missed the difference between SPISettings and spiSettings.

Code:
#include <WProgram.h>

#include <SPI.h>
#include <DmaSpi.h>

#define DMASIZE 255

#define cs_pin  10   //Chip select pin


uint8_t src[DMASIZE];
volatile uint8_t dest[DMASIZE];
volatile uint8_t dest0[DMASIZE];
volatile uint8_t dest1[DMASIZE];


SPISettings spiSettings;

byte read_cmd0[DMASIZE]={
  0x03,0,0,0};
byte read_cmd1[DMASIZE]={
  0x03,0,0,0x40};


byte sent[8]={
};
byte req[8]={
  1,1,1,1,1,1,1,1};

uint32_t us1,us2,us3,us4,us0;

long prev1,prev2,prev3,prev0;
byte busy0;
byte printq[8]={
};
byte received_sample[8]={
};


///////////////////////////////////////////////////////////////////////////

void setSrc()
{
  for (size_t i = 0; i < DMASIZE; i++)
  {
    // int r = random(0,255);
    src[i] = i;
    Serial.print(src[i],HEX);
    Serial.print(" ");

  }
  Serial.println();
  Serial.println("src'd");


}

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


//////////////////////////////s25fl commands

byte stat(){  
  SPI.beginTransaction(spiSettings);  
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0x05);
  byte stat = SPI.transfer(0);
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();
  return stat;
}

void waitforit (){
  while ((stat() & B0000001)==B00000001)
  {

  }
  //Serial.println("flash ready");
}

void write_enable(){

  SPI.beginTransaction(spiSettings);   
  digitalWriteFast(cs_pin,LOW);
  SPI.transfer(0x06);
  digitalWriteFast(cs_pin,HIGH);
  SPI.endTransaction();

  waitforit();
}


///////////////////////////////////////////////////////////////////////////////

void setup()
{
  randomSeed(A0);
  while (!Serial) {
  }

  delay(100);
  //     Serial.println("jhey");


  pinMode(cs_pin, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);

  delay(1000);
  randomSeed(A1);

  /** Prepare source and destination **/
  setSrc();
  clrDest((uint8_t*)dest);
  Serial.flush();

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

  write_enable();
  SPI.beginTransaction(spiSettings);   //errase first 64k
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0xD8);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();
  waitforit ();
  // Serial.println("errased");
  write_enable();

  SPI.beginTransaction(spiSettings);   //write
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0x02);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(src, DMASIZE);
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();
  waitforit ();
  //  Serial.println("written");


  SPI.beginTransaction(spiSettings);   //read
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0x03);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  for (int i = 0; i < DMASIZE; ++i)
  {
    dest[i]=SPI.transfer(0);

  }
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();    
  waitforit ();

  //   Serial.println("read");


  Serial.flush();

  DMASPI0.begin();
  DMASPI0.start();


  ActiveLowChipSelect cs(10, SPISettings()); //cs seems to work
  DmaSpi0::Transfer trans0(src, 1, dest);
  trans0 = DmaSpi0::Transfer(read_cmd0, DMASIZE, dest, 0, &cs);

  DMASPI0.registerTransfer(trans0);

  while (trans0.done()==0){
  };

  for (int i = 4; i < 127+4; ++i)
  {
    Serial.print(dest[i]);
    Serial.print(" ");

  }

}

//////////////////////////////////////////////////////////////////////////





void loop()
{

  static SPISettings spiSettings;

  static ActiveLowChipSelect cs(10, spiSettings); 

  static DmaSpi0::Transfer trans0(read_cmd0, DMASIZE, dest0, 0, &cs);
  static DmaSpi0::Transfer trans1(read_cmd1, DMASIZE, dest1, 0, &cs);

  //delay(500); //add this and it works


  if ((millis()-prev0)>1000){  //// send requnests every second
    prev0=millis();

    Serial.println();
    Serial.println("start");
    Serial.println();



    if (trans0.busy()==1)
    {
      Serial.println("   0 is busy"); 
    }

    if (trans1.busy()==1)
    {
      Serial.println("   1 is busy"); 
    }

    //Serial.println("send req 0 ");
    //Serial.println("send req 1 ");
    req[0]=1;
    req[1]=1;


  }



  if (trans0.busy()==0 && req[0]==1){
    //Serial.println("      Transfering 0 ");
    us0=micros();
    trans0 = DmaSpi0::Transfer(read_cmd0, DMASIZE-4, dest0, 0, &cs);
    DMASPI0.registerTransfer(trans0);
    sent[0]=1;
    req[0]=0;



    //Serial.print(micros()-us1);Serial.println(" 0 us");

  }

  if (trans1.busy()==0 && req[1]==1){
    //Serial.println("      Transfering 1 ");
    us1=micros();
    //ActiveLowChipSelect cs(10, SPISettings()); 
    trans1 = DmaSpi0::Transfer(read_cmd1, DMASIZE, dest1, 0, &cs);
    DMASPI0.registerTransfer(trans1);
    sent[1]=1;
    req[1]=0;

    // Serial.print(micros()-us1);Serial.println(" 1 us");

  }




  if (trans0.done()==1 && sent[0]==1){

    uint32_t t2 = micros()-us0;

    Serial.println("   R 0");
/*
      for (int i = 4; i < 127+4; ++i)
      {
          Serial.print(dest0[i]);Serial.print(" ");

      }

    Serial.println();
*/

    sent[0]=0;
    //req[0]=0;
    clrDest((uint8_t*)dest0);

  }


  if (trans1.done()==1 && sent[1]==1){

    uint32_t t3 = micros()-us1;

    Serial.println("   R 1");
/*
      for (int i = 4; i < 127+4; ++i)
      {
          Serial.print(dest1[i]);Serial.print(" ");

      }
    Serial.println();
*/

    sent[1]=0;
    //req[1]=0;
    clrDest((uint8_t*)dest1);

  }


  if (trans0.m_state == DmaSpi0::Transfer::State::error)
  {
    Serial.println("transfer 0 error");
    while(1);
  }

  if (trans1.m_state == DmaSpi0::Transfer::State::error)
  {
    Serial.println("transfer 1 error");
    while(1);
  }

  if ((millis()-prev3)>500){
    prev3=millis();


  }

  /*
  // waste time 
   for (int i = 0; i < 100; ++i)
   {
   byte r,b,g;
   r=(micros()>>24) & 127;
   g=(micros()>>16) & 127;
   b=(micros()>>8) & 127;
   analogWrite(3,g);
   analogWrite(4,b);
   analogWrite(5,r);
   }
   */


}


Now to see how fast I can get 8 working. I'll let you know how it goes

Thanks again for this great library!
 
Well it looks like queuing isn't working for me, though.

The 2nd 3rd and 4th transfer return identical information to what was requested on the 4th.

Here's the serial out. I tried to uncomment the prints in DmaSpi.h but it crashes...
Code:
start

trans_t 0 11 | rec_t 0 141
trans_t 1 3 | rec_t 1 479
trans_t 2 3 | rec_t 2 824
trans_t 3 2 | rec_t 3 1163
   R 0
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 0 0 0 0 0 1 2 3 
   R 1
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 140 45 0 0 
   R 2
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 255 255 255 255 
   R 3
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 1 16 1 56

Code:
#include <WProgram.h>

#include <SPI.h>
#include <DmaSpi.h>

#define DMASIZE 64

#define cs_pin  10   //Chip select pin


uint8_t src[DMASIZE];
volatile uint8_t dest[DMASIZE];
volatile uint8_t dest0[DMASIZE];
volatile uint8_t dest1[DMASIZE];
volatile uint8_t dest2[DMASIZE];
volatile uint8_t dest3[DMASIZE];

byte read_cmd[DMASIZE]={
  0x03,0,0,0};

byte read_cmd0[DMASIZE]={
  0x03,0,0,0};
byte read_cmd1[DMASIZE]={
  0x03,0,0,0x40};


byte sent[8]={
};
byte req[8]={
};

uint32_t us[8]={
};
uint32_t trans_t[8]={
};
uint32_t rec_t[8]={
};

long prev1,prev2,prev3,prev0;
byte busy0;
byte printq[8]={
};
byte received_sample[8]={
};

static SPISettings spiSettings;
static ActiveLowChipSelect cs(10, spiSettings); 
static DmaSpi0::Transfer trans0(read_cmd, DMASIZE, dest0, 0, &cs);
static DmaSpi0::Transfer trans1(read_cmd, DMASIZE, dest1, 0, &cs);
static DmaSpi0::Transfer trans2(read_cmd, DMASIZE, dest2, 0, &cs);
static DmaSpi0::Transfer trans3(read_cmd, DMASIZE, dest3, 0, &cs);

///////////////////////////////////////////////////////////////////////////

void setSrc()
{
  for (size_t i = 0; i < DMASIZE; i++)
  {
    // int r = random(0,255);
    src[i] = i;
    Serial.print(src[i],HEX);
    Serial.print(" ");

  }
  Serial.println();
  Serial.println("src'd");


}

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


//////////////////////////////s25fl commands

byte stat(){  
  SPI.beginTransaction(spiSettings);  
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0x05);
  byte stat = SPI.transfer(0);
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();
  return stat;
}

void waitforit (){
  while ((stat() & B0000001)==B00000001)
  {

  }
  //Serial.println("flash ready");
}

void write_enable(){

  SPI.beginTransaction(spiSettings);   
  digitalWriteFast(cs_pin,LOW);
  SPI.transfer(0x06);
  digitalWriteFast(cs_pin,HIGH);
  SPI.endTransaction();

  waitforit();
}


///////////////////////////////////////////////////////////////////////////////

void setup()
{
  randomSeed(A0);
  while (!Serial) {
  }

  delay(100);
  //     Serial.println("jhey");


  pinMode(cs_pin, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);

  delay(1000);
  randomSeed(A1);

  /** Prepare source and destination **/
  setSrc();
  clrDest((uint8_t*)dest);
  Serial.flush();

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

  write_enable();
  SPI.beginTransaction(spiSettings);   //errase first 64k
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0xD8);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();
  waitforit ();
  // Serial.println("errased");
  write_enable();

  SPI.beginTransaction(spiSettings);   //write
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0x02);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(src, DMASIZE);
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();
  waitforit ();
  //  Serial.println("written");


  SPI.beginTransaction(spiSettings);   //read
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0x03);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  for (int i = 0; i < DMASIZE; ++i)
  {
    dest[i]=SPI.transfer(0);

  }
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();    
  waitforit ();

  //   Serial.println("read");


  Serial.flush();

  DMASPI0.begin();
  DMASPI0.start();






}

//////////////////////////////////////////////////////////////////////////

uint32_t loc[8]={
  0,10,20,30,40};

byte bank_print=1;

void loop()
{


  //delay(500); //add this and it works


  if ((millis()-prev0)>1000){  //// send requests every second
    prev0=millis();

    loc[0]++;
    loc[0]%=8;

    loc[1]++;
    loc[1]%=18;

    Serial.println();
    Serial.println("start");
    Serial.println();

    for (int i = 0; i < 4; ++i)
    {
      Serial.print("trans_t "); 
      Serial.print(i);   
      Serial.print(" "); 
      Serial.print(trans_t[i]);
      Serial.print(" | rec_t "); 
      Serial.print(i);   
      Serial.print(" ");  
      Serial.print(rec_t[i]);
      Serial.println();

    }

    if (trans0.busy()==1)
    {
      Serial.println("   0 is busy"); 
    }

    if (trans1.busy()==1)
    {
      Serial.println("   1 is busy"); 
    }

    if (trans2.busy()==1)
    {
      Serial.println("   2 is busy"); 
    }

    if (trans3.busy()==1)
    {
      Serial.println("   3 is busy"); 
    }

    req[0]=1;
    req[1]=1;
    req[2]=1;
    req[3]=1;

  }

  if (trans0.busy()==0 && req[0]==1)
  {
    //Serial.println("      Transfering 0 ");
    us[0]=micros();

    read_cmd[1]=(loc[0] >> 16);
    read_cmd[2]=(loc[0] >> 8);  
    read_cmd[3]=(loc[0] & 0xFF);

    trans0 = DmaSpi0::Transfer(read_cmd, DMASIZE-4, dest0, 0, &cs);
    DMASPI0.registerTransfer(trans0);
    sent[0]=1;
    req[0]=0;
    trans_t[0]=micros()-us[0];

  }


  if (trans0.done()==1 && sent[0]==1)
  {

    rec_t[0] = micros()-us[0];
    if (bank_print==1)
    {
      Serial.println("   R 0");

      for (int i = 4; i < DMASIZE+4; ++i)
      {
        Serial.print(dest0[i]);
        Serial.print(" ");

      }

      Serial.println();
    }
    sent[0]=0;
    //req[0]=0;
    //clrDest((uint8_t*)dest0);

  }       





  if (trans1.busy()==0 && req[1]==1)
  {
    //Serial.println("      Transfering 1 ");
    us[1]=micros();

    read_cmd[1]=(loc[1] >> 16);
    read_cmd[2]=(loc[1] >> 8);  
    read_cmd[3]=(loc[1] & 0xFF);

    trans1 = DmaSpi0::Transfer(read_cmd, DMASIZE-4, dest1, 0, &cs);
    DMASPI0.registerTransfer(trans1);
    sent[1]=1;
    req[1]=0;
    trans_t[1]=micros()-us[1];

  }


  if (trans1.done()==1 && sent[1]==1)
  {

    rec_t[1] = micros()-us[1];
    if (bank_print==1)
    {

      Serial.println("   R 1");

      for (int i = 4; i < DMASIZE+4; ++i)
      {
        Serial.print(dest1[i]);
        Serial.print(" ");

      }

      Serial.println();
    }
    sent[1]=0;
    //req[0]=0;
    //clrDest((uint8_t*)dest0);

  }       





  if (trans2.busy()==0 && req[2]==1)
  {
    //Serial.println("      Transfering 2 ");
    us[2]=micros();

    read_cmd[1]=(loc[2] >> 16);
    read_cmd[2]=(loc[2] >> 8);  
    read_cmd[3]=(loc[2] & 0xFF);

    trans2 = DmaSpi0::Transfer(read_cmd, DMASIZE-4, dest2, 0, &cs);
    DMASPI0.registerTransfer(trans2);
    sent[2]=1;
    req[2]=0;
    trans_t[2]=micros()-us[2];

  }


  if (trans2.done()==1 && sent[2]==1)
  {

    rec_t[2] = micros()-us[2];
    if (bank_print==1)
    {

      Serial.println("   R 2");

      for (int i = 4; i < DMASIZE+4; ++i)
      {
        Serial.print(dest2[i]);
        Serial.print(" ");

      }

      Serial.println();
    }
    sent[2]=0;
    //req[0]=0;
    //clrDest((uint8_t*)dest0);

  }       



  if (trans3.busy()==0 && req[3]==1)
  {
    //Serial.println("      Transfering 3 ");
    us[3]=micros();

    read_cmd[1]=(loc[3] >> 16);
    read_cmd[2]=(loc[3] >> 8);  
    read_cmd[3]=(loc[3] & 0xFF);

    trans3 = DmaSpi0::Transfer(read_cmd, DMASIZE-4, dest3, 0, &cs);
    DMASPI0.registerTransfer(trans3);
    sent[3]=1;
    req[3]=0;
    trans_t[3]=micros()-us[3];

  }


  if (trans3.done()==1 && sent[3]==1)
  {

    rec_t[3] = micros()-us[3];
    if (bank_print==1)
    {

      Serial.println("   R 3");

      for (int i = 4; i < DMASIZE+4; ++i)
      {
        Serial.print(dest3[i]);
        Serial.print(" ");

      }

      Serial.println();
    }
    sent[3]=0;
    //req[0]=0;
    //clrDest((uint8_t*)dest0);

  }       


}
 
Last edited:
Are you sure you are using the code you posted? It's not crashing for me, I get repeated blocks of output similar to this one:
Code:
start

trans_t 0 11 | rec_t 0 143
trans_t 1 3 | rec_t 1 460
trans_t 2 3 | rec_t 2 774
trans_t 3 3 | rec_t 3 1084
   R 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
   R 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 222 2 0 
   R 2
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 30 
   R 3
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 16 1 56
the times (trans_t and rec_t) and the last 4 bytes of the printed buffer are always different, and it's been running for a while now.

When I uncomment the extra 500 ms loop delay:
Code:
start

trans_t 0 11 | rec_t 0 500028
trans_t 1 3 | rec_t 1 500323
trans_t 2 3 | rec_t 2 500636
trans_t 3 2 | rec_t 3 500944
   R 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
   R 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 82 56 0 0 
   R 2
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 30 
   R 3
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 16 1 56
Again, it's not hanging.

I either misinterpreted your error description, or the error is not occuring for me.
 
Ah I see, the problem is not that the transfers are not executed, but that the data received from the slave seems to be wrong. I cannot reproduce that without the specific chip, but I'll try to understand what you're doing. In loop(), you alter the read command before trans0 is started:
Code:
  if (trans0.busy()==0 && req[0]==1)
  {
    //Serial.println("      Transfering 0 ");
    us[0]=micros();

    read_cmd[1]=(loc[0] >> 16);
    read_cmd[2]=(loc[0] >> 8);  
    read_cmd[3]=(loc[0] & 0xFF);

    trans0 = DmaSpi0::Transfer(read_cmd, DMASIZE-4, dest0, 0, &cs);
    DMASPI0.registerTransfer(trans0);
    sent[0]=1;
    req[0]=0;
    trans_t[0]=micros()-us[0];

  }
The problem here is that you need to have one read command buffer for each transfer. Let's walk through the chain of events, beginning with the first transfer:
  1. read_cmd is set up for trans0
  2. trans0 is registered and started by the DMA SPI, the first bytes are on their way to the slave
  3. read_cmd is set up for trans1
  4. trans1 is registered, but trans0 has not finished yet, so trans1 is waiting
  5. read_cmd is set up for trans2
  6. trans2 is registered and waiting
  7. read_cmd is set up for trans3
  8. trans3 is registered and waiting
  9. time passes until trans0 is finished
  10. trans1 is started, but the setup for trans3 has altered trans1's address bytes in read_cmd
  11. trans1 is doing what should actually be done by trans3
  12. time passes until trans1 is finished
  13. trans2 is started, but the setup for trans3 has altered trans2's address bytes in read_cmd
  14. trans2 is doing what should actually be done by trans3
  15. time passes until trans2 is finished
  16. trans3 is started
  17. trans3 is executed as intended
So you need separate command buffers for trans0, trans1, and so on.

Edit: It's hard to switch from procedural to asynchronous code, they are fundamentally different when it comes to managing object lifetime, or entry and exit points. What you are experiencing here is a symptom of exactly that transition. The DMASPI library tries to create as few copies of data as possible, which in turn means that you have to make sure that all referenced objects (SPISettings for example) remain alive until they are not needed any more. Overwriting buffers that you think you don't need any more is again such a thing - the transfer you queued up for later will use the data it finds, and if that data was altered since the transfer was registered, the alteration will have an effect on that transfer.

Also, having 8 consecutive, but basically equivalent transfers is crying out for a set of classes that wrap those transfers and the re-queuing logic.
 
Last edited:
Yes the data coming back is wrong.

Oh I see. It's not reading read_cmd when you registerTransfer but when it gets around to it and by then it's changed.

Also, having 8 consecutive, but basically equivalent transfers is crying out for a set of classes that wrap those transfers and the re-queuing logic.
In the actual device the transfers will not be similar at all and will be constantly changing. This is just a test.

This code seems to work pretty well.

Code:
#include <WProgram.h>

#include <SPI.h>
#include <DmaSpi.h>

#define DMASIZE 128

#define cs_pin  10   //Chip select pin


uint8_t src[DMASIZE];
volatile uint8_t dest[DMASIZE];
volatile uint8_t dest0[DMASIZE];
volatile uint8_t dest1[DMASIZE];
volatile uint8_t dest2[DMASIZE];
volatile uint8_t dest3[DMASIZE];

byte read_cmd[8][DMASIZE]={
};
/*
byte read_cmd0[DMASIZE]={
 0x03,0,0,0};
 byte read_cmd1[DMASIZE]={
 0x03,0,0,0x40};
 */

byte sent[8]={
};
byte req[8]={
};

uint32_t us[8]={
};
uint32_t trans_t[8]={
};
uint32_t rec_t[8]={
};

long prev1,prev2,prev3,prev0;
byte busy0;
byte printq[8]={
};
byte received_sample[8]={
};

static SPISettings spiSettings;
static ActiveLowChipSelect cs(10, spiSettings); 
static DmaSpi0::Transfer trans0(read_cmd[0], DMASIZE, dest0, 0, &cs);
static DmaSpi0::Transfer trans1(read_cmd[1], DMASIZE, dest1, 0, &cs);
static DmaSpi0::Transfer trans2(read_cmd[2], DMASIZE, dest2, 0, &cs);
static DmaSpi0::Transfer trans3(read_cmd[3], DMASIZE, dest3, 0, &cs);

///////////////////////////////////////////////////////////////////////////

void setSrc()
{
  for (size_t i = 0; i < DMASIZE; i++)
  {
    // int r = random(0,255);
    src[i] = i;
    Serial.print(src[i],HEX);
    Serial.print(" ");

  }
  Serial.println();
  Serial.println("src'd");


}

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


//////////////////////////////s25fl commands

byte stat(){  
  SPI.beginTransaction(spiSettings);  
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0x05);
  byte stat = SPI.transfer(0);
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();
  return stat;
}

void waitforit (){
  while ((stat() & B0000001)==B00000001)
  {

  }
  //Serial.println("flash ready");
}

void write_enable(){

  SPI.beginTransaction(spiSettings);   
  digitalWriteFast(cs_pin,LOW);
  SPI.transfer(0x06);
  digitalWriteFast(cs_pin,HIGH);
  SPI.endTransaction();

  waitforit();
}


///////////////////////////////////////////////////////////////////////////////

void setup()
{
  randomSeed(A0);
  while (!Serial) {
  }

  delay(100);
  //     Serial.println("jhey");


  pinMode(cs_pin, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);

  delay(1000);
  randomSeed(A1);

  /** Prepare source and destination **/
  setSrc();
  clrDest((uint8_t*)dest);
  Serial.flush();

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

  write_enable();
  SPI.beginTransaction(spiSettings);   //errase first 64k
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0xD8);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();
  waitforit ();
  // Serial.println("errased");
  write_enable();

  SPI.beginTransaction(spiSettings);   //write
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0x02);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(src, DMASIZE);
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();
  waitforit ();
  //  Serial.println("written");


  SPI.beginTransaction(spiSettings);   //read
  digitalWrite (cs_pin, LOW);
  SPI.transfer(0x03);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  for (int i = 0; i < DMASIZE; ++i)
  {
    dest[i]=SPI.transfer(0);

  }
  digitalWrite (cs_pin, HIGH);
  SPI.endTransaction();    
  waitforit ();

  //   Serial.println("read");


  Serial.flush();

  DMASPI0.begin();
  DMASPI0.start();






}

//////////////////////////////////////////////////////////////////////////

uint32_t loc1=0;
uint32_t loc2=50;

byte bank_print=1;

void loop()
{
  loc1++;
  loc1%=16;

  loc2++;
  loc2%=64;

  //delay(500); //add this and it works


  if ((millis()-prev0)>1000){  //// send requnests every second
    prev0=millis();

    Serial.println();
    Serial.println("start");
    Serial.println();

    for (int i = 0; i < 4; ++i)
    {
      Serial.print("trans_t "); 
      Serial.print(i);   
      Serial.print(" "); 
      Serial.print(trans_t[i]);
      Serial.print(" | rec_t "); 
      Serial.print(i);   
      Serial.print(" ");  
      Serial.print(rec_t[i]);
      Serial.println();

    }

    if (trans0.busy()==1)
    {
      Serial.println("   0 is busy"); 
    }

    if (trans1.busy()==1)
    {
      Serial.println("   1 is busy"); 
    }

    if (trans2.busy()==1)
    {
      Serial.println("   2 is busy"); 
    }

    if (trans3.busy()==1)
    {
      Serial.println("   3 is busy"); 
    }
    //Serial.println("send req 0 ");
    //Serial.println("send req 1 ");
    req[0]=1;
    req[1]=1;
    req[2]=1;
    req[3]=1;

  }

  get_sample(0, loc1);
  get_sample(1, loc2);
  get_sample(2, 1+loc1);
  get_sample(3, 1+loc2);
}




void get_sample(uint8_t sample_n, uint32_t loc){

  if (sample_n==0)
  {
    if (trans0.busy()==0 && req[sample_n]==1)
    {
      //Serial.println("      Transfering 0 ");
      us[sample_n]=micros();
      read_cmd[sample_n][0]=(0x03);
      read_cmd[sample_n][1]=(loc >> 16);
      read_cmd[sample_n][2]=(loc >> 8);  
      read_cmd[sample_n][3]=(loc & 0xFF);

      trans0 = DmaSpi0::Transfer(read_cmd[sample_n], DMASIZE-4, dest0, 0, &cs);
      DMASPI0.registerTransfer(trans0);
      sent[sample_n]=1;
      req[sample_n]=0;
      trans_t[sample_n]=micros()-us[sample_n];

    }


    if (trans0.done()==1 && sent[sample_n]==1)
    {

      rec_t[sample_n] = micros()-us[sample_n];
      if (bank_print==1)
      {
        Serial.println("   R 0");

        for (int i = 4; i < DMASIZE+4; ++i)
        {
          Serial.print(dest0[i]);
          Serial.print(" ");

        }

        Serial.println();
      }
      sent[sample_n]=0;
      //req[0]=0;
      //clrDest((uint8_t*)dest0);

    }       


  }  

  if (sample_n==1)
  {
    if (trans1.busy()==0 && req[sample_n]==1)
    {
      //Serial.println("      Transfering 0 ");
      us[sample_n]=micros();
      read_cmd[sample_n][0]=(0x03);
      read_cmd[sample_n][1]=(loc >> 16);
      read_cmd[sample_n][2]=(loc >> 8);  
      read_cmd[sample_n][3]=(loc & 0xFF);

      trans1 = DmaSpi0::Transfer(read_cmd[sample_n], DMASIZE-4, dest1, 0, &cs);
      DMASPI0.registerTransfer(trans1);
      sent[sample_n]=1;
      req[sample_n]=0;
      trans_t[sample_n]=micros()-us[sample_n];

    }


    if (trans1.done()==1 && sent[sample_n]==1)
    {

      rec_t[sample_n] = micros()-us[sample_n];
      if (bank_print==1)
      {

        Serial.println("   R 1");

        for (int i = 4; i < DMASIZE+4; ++i)
        {
          Serial.print(dest1[i]);
          Serial.print(" ");

        }

        Serial.println();
      }
      sent[sample_n]=0;
      //req[0]=0;
      //clrDest((uint8_t*)dest0);

    }       


  }

  if (sample_n==2)
  {
    if (trans2.busy()==0 && req[sample_n]==1)
    {
      //Serial.println("      Transfering 0 ");
      us[sample_n]=micros();
      read_cmd[sample_n][0]=(0x03);
      read_cmd[sample_n][1]=(loc >> 16);
      read_cmd[sample_n][2]=(loc >> 8);  
      read_cmd[sample_n][3]=(loc & 0xFF);

      trans2 = DmaSpi0::Transfer(read_cmd[sample_n], DMASIZE-4, dest2, 0, &cs);
      DMASPI0.registerTransfer(trans2);
      sent[sample_n]=1;
      req[sample_n]=0;
      trans_t[sample_n]=micros()-us[sample_n];

    }


    if (trans2.done()==1 && sent[sample_n]==1)
    {

      rec_t[sample_n] = micros()-us[sample_n];
      if (bank_print==1)
      {

        Serial.println("   R 2");

        for (int i = 4; i < DMASIZE+4; ++i)
        {
          Serial.print(dest2[i]);
          Serial.print(" ");

        }

        Serial.println();
      }
      sent[sample_n]=0;
      //req[0]=0;
      //clrDest((uint8_t*)dest0);

    }       


  }

  if (sample_n==3)
  {
    if (trans3.busy()==0 && req[sample_n]==1)
    {
      //Serial.println("      Transfering 0 ");
      us[sample_n]=micros();
      read_cmd[sample_n][0]=(0x03);
      read_cmd[sample_n][1]=(loc >> 16);
      read_cmd[sample_n][2]=(loc >> 8);  
      read_cmd[sample_n][3]=(loc & 0xFF);

      trans3 = DmaSpi0::Transfer(read_cmd[sample_n], DMASIZE-4, dest3, 0, &cs);
      DMASPI0.registerTransfer(trans3);
      sent[sample_n]=1;
      req[sample_n]=0;
      trans_t[sample_n]=micros()-us[sample_n];

    }


    if (trans3.done()==1 && sent[sample_n]==1)
    {

      rec_t[sample_n] = micros()-us[sample_n];
      if (bank_print==1)
      {

        Serial.println("   R 3");

        for (int i = 4; i < DMASIZE+4; ++i)
        {
          Serial.print(dest3[i]);
          Serial.print(" ");

        }

        Serial.println();
      }
      sent[sample_n]=0;
      //req[0]=0;
      //clrDest((uint8_t*)dest0);

    }       


  }

}

Thanks again for all of your thorough and prompt help!!
 
You're welcome!

Once more, regarding your periodic reports: Use elapsedMillis - it's a very convenient class. Here's how I do it:
Code:
{ // open an anonymous scope for simple names
  static const uint16_t period = 1000; // time between reports
  static elapsedMillis elapsed = period; // initialize like this if you want a first report immediately
  // static elapsedMillis elapsed; // initialize like this if you want a first report after period milliseconds

  if (elapsed >= period)
  {
    // send a report, update a sensor, whatever you need
    elapsed -= period;
  }
}
The advantage of the anonymous scope around this is that you can open a seond anonymous scope after this one with the same names for period and elapsed.

This way you can concentrate on the "how often" instead of having to track absolute system time (with millis(), as you're doing it now).

Regards

Christoph
 
Once more, regarding your periodic reports: Use elapsedMillis - it's a very convenient class. Here's how I do it:

Right! But in this case I needed to know the difference of two separate actions from the same starting point so I went with the traditional micros().
 
Great Library, works good!


Please excuse the silly question.. how can I set the parameters for DMA-spi ?

For example,
SPISettings (20000000 , MSBFIRST , SPI_MODE0 );

I think, i'm missing something...

It seems to default to "very slow", for me... :)

Thanks,
Frank.
 
Hi Frank,

sorry for the delay, but I was in Wacken. You can set the SPI parameters with a chip select object which is used to select a chip (and configure the SPI) when a transfer is actually started and ended. See the example (starting at line 201). Does that answer your question?

Regards

Christoph
 
Hi Frank,

sorry for the delay, but I was in Wacken. You can set the SPI parameters with a chip select object which is used to select a chip (and configure the SPI) when a transfer is actually started and ended. See the example (starting at line 201). Does that answer your question?

Regards

Christoph

Wacken..geil.. Da will ich auch mal hin.

Thank you!
That means i have to do my own fork.. I need 3 cs pins, notthe standard 1-pin solution.. But no problem.
 
You can create your own chip select class (just derive from AbstractChipSelect, like ActiveLowChipSelect does) and do whatever you want to select your chip(s). Then you can even select a chip with an I2C port expander if you like. If you have a few minutes of spare time, create another example using your custom chip select class and push it back to my repo. I'm sure someone will benefit from that.
 
So I'm trying to figure out how to configure the SPI0 on a Teensy LC to be in 16bit mode and operate it via DMA. My understanding is the 16bit mode is enabled in registers CTAR0 and/or CTAR1, but for the life of me can't figure out the abstracted way of doing this. I'm assuming that after you setup the SPI0 properly that I should just be able to use the ActiveLowChipSelect in the DmaSpi library.

I forgot to mention that I need the CS pin to be asserted/deasserted for every 16bits transferred/received.

I know this is a little silly, but would appreciate pointers on this.
 
Status
Not open for further replies.
Back
Top