Fast GPIO output with wide bus, what should I care for?

was-ja

Well-known member
Hi,

I am new in this forum and first, I would like to thank Pjrc team for very comfortable and robust hardware.

I am playing with Teensy 4.1 and trying to run 7 pairs of signals at as fast as possible frequency.

Practically, it works, please, see my attachment. I put these pairs into GPIO6, store data in the array DataTick and feed this array from the TCM memory into GPIO6.

Right now I am achieving 2.46ns per one signal change in GPIO (I run at 800MHz, actually at 1000GHz it fails with any cooling).

My questions are:
1. I found in the documentation at the page 958 that it is possible to increase SPEED Setting o GPIO, however, I cannot finally understand what I should do for it. It seems that I should store 111 into some register, but at what register? Please, suggest me!
2. I am using psram, sdcard, spi and i2c in parallel to these GPIO. I figured out that it does not work well, if I just write pregenerated data into GPIO6_DR. SDCARD + PSRAM + GPIO works, but SDCARD + SPI + GPIO - does not. It seems that some signals from SPI, etc mux with GPIO, but I cannot figure it exactly.
I see two solutions:
2.1. I should find what exactly does not work and find which MUX is involved;
2.2. I can rewrite my sequence such a way that instead of saving to GPIO6_DR I can generate only a mask for toggle signals, and at the end clear. So, I need GPIO6_TOGGLE and GPIO6_CLEAR, but I did not find them in headers.

Please, advice me with said my stupid questions!

Thank you!

Sincerely,

Was-Ja


Code:
#include <SPI.h>
#include <math.h>
#include <Arduino.h>
#include <SD.h>


const int chipSelect = BUILTIN_SDCARD; 


unsigned char EXTMEM DataRes1[8*1024*1024];
unsigned char EXTMEM DataRes2[8*1024*1024];


unsigned long my_rand=0;

float myrand()
{ my_rand = my_rand * 1103515245 + 12345;
  return (float)(my_rand>>16);
}


const unsigned int N_DataTicks=16*1024;

unsigned int DataTicks[N_DataTicks]; // 64K


unsigned int GenSetOutputRegisters(signed char *A)
{ unsigned int res=0; // what should I place here to mask SPI ???
  if(A[0]>0) res+=(1<<25); else if(A[0]<0) res+=(1<<24);
  if(A[1]>0) res+=(1<<27); else if(A[1]<0) res+=(1<<26);
  if(A[2]>0) res+=(1<<16); else if(A[2]<0) res+=(1<<17);
  if(A[3]>0) res+=(1<<22); else if(A[3]<0) res+=(1<<23);
  if(A[4]>0) res+=(1<<19); else if(A[4]<0) res+=(1<<18);
  if(A[5]>0) res+=(1<<21); else if(A[5]<0) res+=(1<<20);
  if(A[6]>0) res+=(1<<29); else if(A[6]<0) res+=(1<<28);
  return res;
}
// Our:PINS:
//  0 : 23 : AD_B1_09 -> GPIO6-25
//  1 : 22 : AD_B1_08 -> GPIO6-24
//  2 : 21 : AD_B1_11 -> GPIO6-27
//  3 : 20 : AD_B1_10 -> GPIO6-26
//  4 : 19 : AD_B1_00 -> GPIO6-16
//  5 : 18 : AD_B1_01 -> GPIO6-17
//  6 : 17 : AD_B1_06 -> GPIO6-22
//  7 : 16 : AD_B1_07 -> GPIO6-23
//  8 : 15 : AD_B1_03 -> GPIO6-19
//  9 : 14 : AD_B1_02 -> GPIO6-18
// 10 : 41 : AD_B1_05 -> GPIO6-21
// 11 : 40 : AD_B1_04 -> GPIO6-20
// 12 : 39 : AD_B1_13 -> GPIO6-29
// 13 : 38 : AD_B1_12 -> GPIO6-28


void GenDataTicks()
{ signed char A[7];
  for(int i=0; i<N_DataTicks; i++)
  { for(byte j=0; j<7; j++)
    { float r=myrand();
      A[j]=(r>0.6)?1:((r<0.3)?-1:0);
    }
    DataTicks[i] = GenSetOutputRegisters(A);
  }
}


void RunExcitation()
{ for(int i=0; i<N_DataTicks; i++)
    GPIO6_DR = DataTicks[i];
}


void setup()
{ Serial.begin(9600);
  while(!Serial); // wait for serial port to connect.

  SPI.begin();
//
  pinMode(23, OUTPUT);
  pinMode(22, OUTPUT);
  pinMode(21, OUTPUT);
  pinMode(20, OUTPUT);
  pinMode(19, OUTPUT);
  pinMode(18, OUTPUT);
  pinMode(17, OUTPUT);
  pinMode(16, OUTPUT);
  pinMode(15, OUTPUT);
  pinMode(14, OUTPUT);
  pinMode(41, OUTPUT);
  pinMode(40, OUTPUT);
  pinMode(39, OUTPUT);
  pinMode(38, OUTPUT);

  GenDataTicks();
  
  for(long i=0; i<sizeof(DataRes1); i+=2)
  { DataRes1[i]='A';
    DataRes1[i+1]='\n';
    DataRes1[i]='B';
    DataRes1[i+1]='\n';
  }

  Serial.print("Initializing SD card...");
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
}


int LoopIndex=0;

void loop()
{ long myTime1=millis();
  Serial.print(LoopIndex);
  Serial.println("-th data is generating");
  for(long i=0; i<sizeof(DataRes1); i+=2048L)
  { RunExcitation();
    // MeasureData(DataRes1+i); // this subroutine is not here, it reads data into EXTMEM from ADC's SPI
  }

  for(long i=0; i<sizeof(DataRes1); i+=2048L)
  { RunExcitation();
    // MeasureData(DataRes2+i); // this subroutine is not here, it reads data into EXTMEM from ADC's SPI
  }
  Serial.println("Done");

  myTime1=millis() - myTime1;
  Serial.print("Average tick time is ");
  Serial.print(((float)myTime1)/134.);
  Serial.println(" ns");
  char fn[20];
  sprintf(fn, "data_%d.txt", LoopIndex++);
  File dataFile = SD.open(fn, FILE_WRITE);

  if(dataFile)
  { long myTime=millis();
    dataFile.write(DataRes1, sizeof(DataRes1));
    dataFile.write(DataRes2, sizeof(DataRes2));
    myTime=millis() - myTime;
    Serial.print("Average SD card data transfer rate is ");
    Serial.print(16000. / (float)myTime);
    Serial.println(" Megabytes/s");
    dataFile.close();
  } else // if the file isn't open, pop up an error:
  { Serial.print("error opening");
    Serial.println(fn);
  }
}
 
See 106x manual chapter 11, page ~387 for info on registers containing SPEED, DSE, and SRE fields. I have no idea how to use these or whether they can help with what you are doing.
 
Oh, thank you very much! Yes, I read already this page but I was not sure about the way to use them. I am still preparing to use this part, and hopefully converge very soon.
 
Back
Top