Read sometimes returns different value from written to RAM

Dear all,

I have an encoder that gives me a position that I need to write into an SRAM module (23LC1024) every +/- 10 ms. I have the problem that the value that I write to the RAM is sometimes different from what I can read from it. I think it is a problem with the way I built my address variable but I can't find what the problem is.

I convert the position to an int of 2 bytes (uint16_t)

I did two tests:

  1. do a Serial write everytime the 2 bytes are written to memory. I do this in the function itself using the exact same address used for the write and for the read. I return the higher byte written then I read that byte again. I then serial write a "|" and do the same for the lower byte.
  2. in the loop, I first write the 2 bytes to memory and then read them again. The write function returns the address of the first byte that I use to send to the read function.

The first test returns as expected. No problem whatsoever: the bytes written and read are exactly the same every time. The second test however sometimes returns different values: about 5% of the printed values are different.

This is my script:

#include <Encoder.h>
#include <SPI.h>
#include <SpiRAM.h>

Encoder myEnc(19, 18);

// SPI SRAM acces variables
const int SS_SRAM1 = 30;
SpiRAM SRAM1(SS_SRAM1);

// working variables
volatile uint32_t lastSRAMAddress1=0;
uint32_t p_lastSRAMAddress1=0;
volatile float GlobalCWposition=0.0;

float displacement=0;
uint32_t address;

void setup() {
  Serial.begin(115200);
  // SRAM 23LC1024 IC's
  pinMode(SS_SRAM1,OUTPUT);digitalWrite(SS_SRAM1,HIGH);
  
  // powersupply sensor
  pinMode(16,OUTPUT); digitalWrite(16,HIGH);
  pinMode(17,OUTPUT); digitalWrite(17,LOW);
}

void loop() {
  
  long newPosition = myEnc.read();
  displacement = (float)newPosition/10/4;
  address = writePositionToRam((uint16_t)displacement);
  Serial.print((uint16_t)displacement);
  Serial.print("=");
  Serial.println(readPositionFromRam(address));

  delay(50);
}

Functions:

uint32_t writePositionToRam(int CWposition){
  // modify address to fall into SRAM limits and allow for int overflow
  uint32_t address = lastSRAMAddress1-(lastSRAMAddress1/125000)*125000;
  
  // write higher byte
  SRAM1.writeByte(address,((byte)(CWposition >> 8) & 0xff));
  //Serial.print((byte)((CWposition >> 8) & 0xff));
  //Serial.print("=");
  //Serial.print((byte)SRAM1.readByte(address));
  
  //Serial.print("|");
  delay(1);
  // write lower byte
  SRAM1.writeByte(address+1,((byte)CWposition));
  delay(1);
  //Serial.print(((byte)CWposition));
  //Serial.print("=");
  //Serial.println((byte)SRAM1.readByte(address+1));
  
  lastSRAMAddress1++;  
  lastSRAMAddress1++;
  
  return address;
}

uint16_t readPositionFromRam(uint32_t address){
  // modify address to fall into SRAM limits and allow for int overflow
  address = address-(address/125000)*125000;
  
  byte higher_byte = (byte)SRAM1.readByte(address);
  delay(1);
  byte lower_byte = (byte)SRAM1.readByte(address+1);
  delay(1);
  return (uint16_t) ((higher_byte << 8)+lower_byte);
}

I've included some delays to be sure there is no timing problem. Any ideas? Thanks!

Mmmh it appears that the first test also fails. Can there be a problem with te SPI bus? The spiram libraey works ok. Am I trying to write to ram to fast?

It really is a READ problem: when I WRITE a byte 1 time and read the same address 4 times then it's only 1 or 2 out of thoose 4 that give a value different from the one that has been written.

I'm at a loss... anyone?

Ok I've 'worked arround' (not solved...) this problem by reading from the same RAM address multiple times until I get two equal subsequent values:

uint16_t readPositionFromRam(uint32_t address){
  byte higher_byte;
  byte new_higher_byte;
  byte lower_byte;
  byte new_lower_byte;
  
  // modify address to fall into SRAM limits and allow for int overflow
  address = address-(address/125000)*125000;
  
  higher_byte = SRAM1.readByte(address);
  new_higher_byte=SRAM1.readByte(address);
  while(higher_byte!=new_higher_byte){
    new_higher_byte=SRAM1.readByte(address);
    higher_byte=new_higher_byte;
  }
  
  lower_byte = SRAM1.readByte(address+1);
  new_lower_byte=SRAM1.readByte(address+1);
  while(lower_byte!=new_lower_byte){
    new_lower_byte=SRAM1.readByte(address+1);
    lower_byte=new_lower_byte;
  }
  return (uint16_t) ((higher_byte << 8)+lower_byte);
}

Try slowing down the SPI bus speed to SPI_CLOCK_DIV8 in startup. I found the arduino could sometimes tend to read corruptly when doing block transfer (readBuffer) though it always read a single byte without problem, but worth a try.

Hey Riva, thanks for also helping me out here. Unfortunately that doesn't seem to work for me. From the moment I read your comment about that in the 23LC1024 lib topic, I tried it here too. But without luck.

I was thinking about some sort of interference but then you would think that something like that doesn't only happen during READ but also during WRITE? Maybe an instability in the MISO port of the Arduino?

Or maybe the arduino doesn't exactly know when a byte is being transmitted and when it actually receives:
0000 0001
It thinks it gets
0000 0010

I'm to much of a noob to go jungling with terms, when I don't understand the problem I'm trying to find a work around.

Anyway, the above mentioned problem is not only when reading to a buffer but also reading when reading a single byte. (I need to store a uint16_t so i just read the higher and lower byte and put them together in an uint16_t.

If you plug a single SRAM chip in and read/write does it work okay? I never tested the library with more than one SRAM chip at a time or other SPI devices on the bus. Maybe something else like this is corrupting the results. Maybe post a schematic of how it's all connected up and some (trimmed down) code that reproduces the problem. I have a couple of these chips and I can maybe breadboard test to your setup.

Thanks again Riva for your help!

Attached you can find the pin connections from the mega to the two SRAM modules and the 2xMCP3551 for the temperature measurement. Do you need the exact wire connections? Like from where everything starts to split up and such?

At the moment everything is already soldered on a prototype box.

Next to these SPI IC's there are some other components in my project:

  • gsm shield
  • SD/xbee radio (I'm not using the SD)
  • RTC
  • encoder sending pulses that I capture with interrupts (interrupts are disabled when reading/writing to ram)
  • some leds

I'm going to need to make a complete diagram anyway but probably not today or tomorrow. The current drawings are for the technical documentation and user manual.
For information: this is a personal project (in my free time) on the expenses of my company and for my company. It will be installed this Sunday night in the overhead contact line of our railways in Belgium. It's supposed to be a complete autonomous unit that will measure the uplift of the contact wire at train passage and send the results by GPRS to a webserver. I'll probably make a blog post or something like that once it's finished.

Connections SRAM and MCP3551.pdf (88.5 KB)

MathiasVDA:
I'm going to need to make a complete diagram anyway but probably not today or tomorrow. The current drawings are for the technical documentation and user manual.

A complete wiring schedule would be better but hopefully this will do to replicate your problems.
I will attempt to setup both SRAM chips in the same configuration you have and see what I get but with xmas it may be a few days. One question on your wiring is do you really need the hold function of the SRAM chips? I had just pulled ~hold to 5V.
Could the MCP3551 be effecting the results as a quick read of the datasheet maybe shows it effecting the SDO

SDO/RDY is the output data pin for the device. Once a
conversion is complete, this pin will go active-low,
acting as a ready flag. Subsequent falling clock edges
will then place the 24-bit data word (two overflow bits
and 22 bits of data, see Section 5.0 “Serial
Interface”) on the SPI bus through the SDO pin. Data
is clocked out on the falling edge of SCK.

Riva:
One question on your wiring is do you really need the hold function of the SRAM chips? I had just pulled ~hold to 5V.

No I don't need it, but in my drawings it's also connected to 5V?

Could the MCP3551 be effecting the results as a quick read of the datasheet maybe shows it effecting the SDO

Well, it could be, but isn't the SPI bus supposed to be multi device?

Is it a timing issue? Does the write complete before you try to do the read? If you do multiple writes does it put the correct data t the chip?

kf2qd:
Is it a timing issue? Does the write complete before you try to do the read? If you do multiple writes does it put the correct data t the chip?

Hey kf2qd, this is the script that will give me the problem:

void loop() {
  
  long newPosition = myEnc.read();
  displacement = (float)newPosition/10/4;
  address = writePositionToRam((uint16_t)displacement);
  Serial.print((uint16_t)displacement);
  Serial.print("=");
  Serial.println(readPositionFromRam(address));

  delay(50);
}

Since I put 2 serial prints between the write and the read I don't think it is a timing issue.

From my experience, I have absolutely no problem writing to the script. It's reading that gives bad results.

It's possible that the MCP3551 has something to do with it. It is not connected to the MOSI line, but it is connected on the MISO line. However, the CS pin remains high at all the times...

Oh God....

You are not going to believe this... Well probably you are but anyway... 'I' can't believe this.

So the problem was that I didn't connect 5V and GND.
:cold_sweat:

STUPID!

Now... In my defense.. everything looked like it was powered. I could do pretty much everything except that sometimes a few bits were off. The reason for this is that all four CS pin of both SRAMs and the MCP are connected to 5V (which was not 5V) by means of a resistor. In the script, all CS pins are set to high so there was power. However, I think that sometimes another CS pin might think it was low when another one was set to low.

Everything works fine now. I don't need any delays anymore, no double checks, nothing! Thanks for all your help!

To give you an idea at what I was staring...

Glad you got to the bottom of the problem.

No I don't need it, but in my drawings it's also connected to 5V?

Sorry, did not realize it was also connected to 5V (Drawing terminology the confusion here).
Someone else may have different ideas but do you really need to tie the ~CS pins to 5V. The Arduino ~CS pin is set to output and high when not in use so should never be at risk of floating. The 10K was obviously allowing parasitic powering of the SRAM chips.

I completely agree that resistor at CS should be avoided. I'm not going to change that anymore but I wonder why they do it like that I the tutorials.