Teensy 4.1 and 23LCV1024

KeithB

Member
Hello,
I am working on a project where I need to connect a Teensy 4.1 to 4 off 23LCV1024 SRAM chips using SPI.
I have the teensy eventually talking to a single chip. I had to put some delayNanosecond calls into the code to get the timing correct. I have yet to fine tune the delay number but for the moment this is functioning.

My problem is when I add a second chip in parallel to the first. The communications stops working correctly. The way I have the two chips connected is as follows…
SO from chip 1 is connected to SO on chip 2.
SI from chip 1 is connected to SI on chip 2.
SCK from chip 1 is connected to SCK on chip 2
CS for chip 1 is connected to pin 10 on Teensy 4.1
CS on chip 2 is connected to pin 21 on Teensy 4.1

With this configuration, nothing works. If however, I disconnect the SCK link between the two chips, then I can talk to Chip 1 again.

Has none encountered anything like this or any ideas to try Please.
I am wondering if the issue is a drive issue, I.e. driving 1 chip on SCK is OK, but driving more than 1 is an issue?
Would a pull up resistor help or hinder the SCK line?

Any thoughts or suggestions welcome Thanks.
 
Your description doesn't mention any connections to Teensy pins 11, 12, 13. Is that just an unintentional omission from the text, or do you really have just 2 CS signals (but no data & clock) connected from Teensy to those memory chips?
 
Apologies, yes, I do have the connections from the teensy to chip 1 for MISO, MOSI and CLK.

with just a single chip connected, I can communicate with the SRAM fine. It is only when I link the SCK pin from the first chip to the second chip that everything appears to stop working.
 
Maybe try shorter wires or slower clock speed?

Really just a blind guess, since I can't see your wires and without the code I have no idea of what clock rare you're using...
 
You might also try adding pullup resistors to the CS pins, so they're high when not actively driven.

Then maybe try running the LED blink example and edit the pin number to 11, 12, 13 and check each wire at each chip with a voltmeter (measure 6 places total for each run) to make sure each Teensy pin really is connected to both chips and neither of the other signals are accidentally shorted to it.
 
Still struggling with this and getting even more confusing as I get further into it.

My code is as follows..(Apologies, can't see how to ad the code tags)

The Setup section
Code:
void setup()
{
  //5 second startup delay
  Serial.print(".");
  delay(1000);
  Serial.print(".");
  delay(1000);
  Serial.print(".");
  delay(1000);
  Serial.print(".");
  delay(1000);
  Serial.print(".");
  delay(1000);

  Test2_Init();
}

//This function just initialises the CS Output pins and sets them to HIGH state.
void Test2_Init()
{
 
  //CS Pins
  pinMode(10, OUTPUT);
  pinMode(21, OUTPUT);

  digitalWrite(10, HIGH);
  digitalWrite(21, HIGH);
  delayNanoseconds(100);

  SPI.begin();

  Serial.println(F("SRAM Initialised - 1 SRAM Chip"));
}

//This function is called every 5 seconds from the Loop routine.
//This will setup a 4 byte buffer and write it to the SRAM (Values are cycled around 4 at a time).
//Next it will clear the Buffer
//Then it will read the 4 bytes from the SRAM and display.
//
void Test2_Write()
{
  static byte DataByte = 0x00;
  char Buffer[8];

  //Write some data
  Buffer[0]=DataByte;
  Buffer[1]=DataByte+1;
  Buffer[2]=DataByte+2;
  Buffer[3]=DataByte+3;

  if (DataByte>0xF0)
  {
    DataByte=0;
  }
  else
  {
    DataByte=DataByte+4;
  }

  //Start the transfer
  SPI.beginTransaction(SPISettings(100000,MSBFIRST,SPI_MODE0));
 
  //Activate the Chip
  digitalWrite(10, LOW);
  delayNanoseconds(50);
     
  //Send WRITE Command
  SPI.transfer(0x02);
  //Send the Address
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0);
  //Send the Data
  for (byte i=0; i<4; i++)
  {
    SPI.transfer(Buffer[i]);
  }

  //Deactivate the Chip
  digitalWrite(10, HIGH);
  delayNanoseconds(50);
  
  //End the Transfer
  SPI.endTransaction();
  delayNanoseconds(100);

  Serial.println(F("SRAM Written data"));


  //Read the Data
  Buffer[0]=0x00;
  Buffer[1]=0x00;
  Buffer[2]=0x00;
  Buffer[3]=0x00;

  //Start the transfer
  SPI.beginTransaction(SPISettings(100000,MSBFIRST,SPI_MODE0));

  //Activate the Chip
  digitalWrite(10, LOW);
  delayNanoseconds(50);
      
  //Send READ Command
  SPI.transfer(0x03);
  //Send the Address
  SPI.transfer(0); 
  SPI.transfer(0);
  SPI.transfer(0);
  //Read the Data
  for (word i=0; i<4; i++)
  {
    Buffer[i]=SPI.transfer(0x00);
  }

  //Deactivate the Chip
  digitalWrite(10, HIGH);
  delayNanoseconds(50);

  //End the Transfer
  SPI.endTransaction();
  delayNanoseconds(100);

  Serial.println(F("SRAM Read Data"));

  Serial.println(Buffer[0], HEX);
  Serial.println(Buffer[1], HEX);
  Serial.println(Buffer[2], HEX);
  Serial.println(Buffer[3], HEX);
}
What is really odd is when I have only 1 SRAM chip connected, everything works fine.
When I connect the second SRAM chip (without the SCK signal), then everything works fine.
When I connect the SCK signal to the second SRAM chip I can no longer write to the first SRAM. but I can still read from the first SRAM, the returned values from the Read are the same as the last time anything was written.

If anyone has any ideas what is happening here it would be appreciated.
I have tried reducing the Clock all the way down to 1000 and it makes no difference.
My wires are literally 50-100mm in length

I have tried hooking up my oscilloscope (which is not very good), but when I connect the probe to the SCK line (even on x10), everything stops.

Any thoughts or further ideas welcome.
thanks
Keith
 
Last edited:
This looks wrong, as does the corresponding read code:
C++:
//Send the Data
for (byte i=0; i<4; i++)
{
   SPI.transfer(Buffer);
}
You need to index the buffer, i.e. Buffer[i]

Use the </> button to get a code block on the forum…
 
Thanks, I have edited the post to add the code tokens.

regarding the comment on the buffer index, something must have gone wrong in the copy / paste as these indexes are in the code. I have corrected the code above.
 
Probably not critical but when setting up the CS pins I'd use DigitalWriteFast to set the lines high and then set them to outputs.
This lets you set the output level before enabling the output driver and avoids a short low glitch for the time between the pin mode being set and the output level being set.
You can also change the other DigitalWrite commands to use the Fast version, this is faster (obviously) and is safe to use as long as the pin being set is a constant.

I'd also set the CS lines to idle right at the start, not after 5 seconds and use a #define or const int to set the pin numbers, it makes the code more readable and helps avoid typos.

None of which should stop it from working...

If connecting the second device impacts how things work then either it's signal integrity or a timing that is right on the edge. You're running the clock slow enough that signal integrity is unlikely to be much of an issue unless the wires are out of control which makes me suspect a timing issue.

Have you tried moving where you set the CS line? Set it low and then have a short delay before the SPI.begin and then SPI.endTransaction, short delay, CS high?

Is the SPI mode correct?
 
Thanks for the comments.

Normally, I would use a define for the PIN numbers, This was a very crude test program to try and debug the system.

An interesting development. The issue is clearly something in the Writing of the data since the reading part appears to be functioning.
As a quick test, I reduced the SPI clock down to 1000 and I also set the Teensy 4.1 clock to 24MHZ in the IDE, compiled and uploaded. The software did not run correctly, but it was changing the values. The last byte written to SRAM was always incorrect for some reason even at this slow data rate and slow CPU clock. I increased the CPU clock to 150MHZ and it all stopped again.

I am thinking this is some form of timing issue on the write side of the code. I need to look at the data sheet again and study the write timing diagrams in case there is an issue or anomaly somewhere.

I need to run teensy at 4.1 at 600MHZ for the application and the SRAM at higher than 100000 but need to get it working first, then speed things up later.
 
I am thinking this is some form of timing issue on the write side of the code. I need to look at the data sheet again and study the write timing diagrams in case there is an issue or anomaly somewhere.
Any chance that setting CS high before doing the SPI end is causing the last byte to not get written correctly?

Adding the second device will delay the SPI clock slightly but not impact the CS line so if the CS is going high slightly too early you may be able to get away with it with one device but not two.

This does feel like the sort of issue where breaking out the scope and checking the relative signal timings against the datasheet requirements is a sensible next step.
 
What is the correct order between cs and begintransaction?

I originally had the CS state change before the begin transaction and the CS state change after the end transaction. However I saw something whilst trying to solve this that the CS should be within the begin transaction and endtransaction statements So I changed it. it’s easy to move. I will give it a go to see if it makes any difference.
 
The transaction defines the clock state so should be the outermost thing I think - then if the clock needs to be idle-HIGH that is setup before the #CS line is active?
 
Further investigation results in the following.
I have written an SPI interface using bit banging of the MOSI, MISO and SCK lines on the teensy to try and find why multiple SRAM chips stop working. Oddly this bit banging approach works.
However to achieve this I am doing the following…

For the data transfer ( the CS pin is still brought low as required).
For each bit in the byte to send.
1. Set MOSI output to HIGH or LOW depending upon the bit state.
2. set SCK to HIGH
3. Read MISO state and update result Byte.
4. set SCK to LOW

However this ordering is different to SPI mode 0 I believe. Mode 0 as I understand it should read MISO only once SCK goes LOW. However if I implement this ordering, then I get the same issues with bit banging as I get with the hardware SPI implementation.
Could it be that these SRAM chips do not implement SPI correctly, or have I miss understood how SPI works?
or have I got the wrong SPI mode selected?

thoughts welcome, thanks
Keith
 
SPI states you should read synchronous to one clock edge and write synchronous to the other (which edges depends on the mode) Since you can't do these simultaneously by simple bit banging your waveforms will be out on the timing, and if slow enough can just happen to work (or just happen to be one bit early or one bit late).

Its a real pain that SPI has 4 modes, it could easily have been defined with a single mode and thus have avoided all sorts of compatibility headaches....

For example mode 0 expects clock to idle low (between transactions SCLK is low). And MISO/MOSI are supposed to change on clock falling edges, and be sampled on clock rising edges.

This is of course inconsistent since the first bit has to be written without a clock edge being involved - the first clock edge is rising (in fact it is often simply clocked by #CS falling edge - consult individual device datasheets for detailed timing requirements)

Its not uncommon to see errors in timing diagrams for SPI, for instance Analog Devices' guide to SPI gets it wrong!

And in real devices the slave is always going to be late compared to the master as it doesn't generate the clock, so MISO will in practice be a little delayed compared with the ideal, whereas the master should easily be able to gate out SCLK and MOSI in lockstep. Once you start buffering SPI busses the delays start to add up and can break the timing if the SPI frequency is high or you expect SPI signals to travel long distance.

3-wire SPI (no MISO) can be buffered happily though as all three signals are in the same direction.
 
Thanks,
My issue I think is related to timing of the signals, which is why I tried the bit banging approach to try and identify what was occurring. Even when I reduced the SPI bit rate down, everything was still messed up.

I will try changing the SPI mode later today to see if this works. I am currently using Mode 0. I am sure this is the correct mode, but will try anyway.

The data sheet for the chip states that on MOSI, the data must be present at least 10ns before and after the rising edge of the SCK.
It also states that the data will only be valid on MISO for a maximum of 25ns after the falling edge of the SCk. however the timing diagram shows that the MISO data is also valid around the same time as the rising edges of the SCK, which is likely why it is working in the bit banging approach.

Out of interest, I measured the time it took to perform a single transaction in my bit banging method. This sends 8 bytes of data to the SRAM ( 1 x command byte, 3 x address bytes and 4 x data bytes).

It would be helpful if someone could verify my calculations please.

I used the cycle counter for the timer which at 600MHz on the Teensy 4.1, I believe is 1.67ns.
It took approx 2500 cycle ticks to complete the 8 byte Transfer.
2500 cycle ticks at 1.67ns per tick equates to 4175ns total time.
4175ns equals 8 bytes so that is 522ns per byte
522ns per byte equals 65.3ns per bit

This equates to a bit rate of 15MHz on average.
This is not definitive as there is the overhead of other software activities, but even so, this is quite impressive if it is anywhere near correct. The max the chip can handle is 20MHz.

thanks again
Keith
 
I found a 23LC1024 chip here (without "V" in the part number).

If I were to give it a try, should I use the code in msg #6?
 
That should be ok to use I believe.
The V part number is the version with battery backup, other than that I believe they are the same.
 
I have edited the test code to use all 4 of the SRAM chips that I have, using the SPI hardware interface with SPI Mode 0.

The chips are connected using CS on pins 10, 21, 22 and 23 respectively.
I have 3 of the chips running, those connected to CS pins 21, 22 and 23. But CS 10 does not work.
Is there anything handled differently when using CS on pin 10?
 
As an update, I changed the first CS pin to 20 to see if all four chips would start working. It looks like this does work, but the Way my circuit board is setup currently, I have to break the connection on pin 21 so can not confirm definitely.
It is looking more and more like I have either a faulty teensy 4.1 or pin 10 behaves differently to other pins when used as a CS Pin.

When I performed some early tests, I swapped the teensy 4.1 for a teensy 4.0 and got the same results so unlikely to be a faulty teensy.

Is there something different with pin 10 when used for SPI coms?
 
To confirm, I have just modified my PCB to connect my SRAM chips to pins 20,21,22 and 23.
Everything is functioning with a SPI clock at 10MHz And talking to all 4 SRAMs.
I have pin 10 set as output and at HIGH state but nothing connected to it.

These chips must be sensitive to something which they do not like on pin 10.

Thanks to everyone who has helped with thoughts and comments.
 
Back
Top