missing pin-highs

Status
Not open for further replies.

duschl

Member
Hi,
I am using a Teensy 3.2 to communicate with an ADXL355 using SPI. Fundamentally, it all works and I can write to registers and read registers, etc. The ADXL has a DATA_RDY flag which goes high when information is available and it clears on a read of the status register (DATA_RDY is the last bit in the status register).

For example I can set the sampling frequency to 3.906 Hz (ie some 4 times per second - slow) and I am using this code to check whether the DATA_RDY pin has been set to high:


Code:
void loop() {

  elapsed = micros();

  //this approach does not work. it appears to be skipping data_rdy highs at irregular intervals
  //alternatively, the adxl355 does not set data_rdy high. 

  if (getRegisterByte(0x04) & 0b1) {
    
    Serial.println(1000000./(elapsed-elapsed2));
    
    elapsed2 = elapsed;

    //reading to clear data_rdy as per data sheet but this line can be commented, makes no difference;
    dummyread = getRegisterByte(0x04);   
        
  }

The code mostly works and produces outputs such as this in the serial monitor:

3.89
1.94
3.89
3.89
1.94
1.94
3.89
3.89
3.89
1.94
1.94
1.30
3.89
3.89

3.89 is the frequency and it matches closely the ADXL355's of 3.906 Hz. I believe discrepancies arise from the fact that the millis and micros functions are not exactly 1e3 and 1e6 microseconds - but that's not my issue.
Sometimes, however, the result is 1.94 Hz which means that a DATA_RDY flag is missed and therefore the duration doubles, halving the frequency.

I have observed the same issues at other sampling frequencies.

One answer to this could be that this is inherent to the ADXL355's behaviour and maybe it's "normal" to occasionally not set the data ready flag. I am in the process of following up on this.
Notwithstanding, I am wondering if the issue could be the Teensy and my poor coding - does it need a certain duration for the DATA_RDY flag to be in high to register it as high?

I have tested various SPI transfer rates from 0.1 to 10 million cycles (ie min to max of the ADXL355) and I have also tried various BAUD rates in case throwing data to the serial monitor causes the Teensy to "not see" that the flag is high. None of this changed the outcome. I have also wiggled the leads in case it was a lead issue and wiggling or non-wiggling made a difference. Finally, I have also checked whether the pattern of missing DATA_RDY highs is regular or not - it is not, there's no pattern. It's completely random.

Does anyone have suggestions on a better way to listen to a flag constantly using SPI?

All suggestions would be greatly appreciated,
duschl
 
I don't find a link to an SPI 355 - the 345 on sparkfun seems to have an interrupt pin? If that is changed on data ready - with attachInterrupt - it would be faster to know when the data is read, and prevent overpolling the device.

May be a quick check would be: wait a few millis in the if() after seeing the data ready bit - and put a short microsecond(s) delay in each loop() read? Can the getRegisterByte() return failure to read?

The Teensy is fast and will run that loop perhaps two fast for the device.

Teensy USB always runs at full speed - that number in .begin is ignored. That shouldn't be part of the trouble with Teensy.
 
Thanks. I did initially run tests with the delay() function which weren't successful but I picked up on them following your suggestion.... and it appears to have solved the issue! For example for a OutputDataRate (ODR) of 3.906 Hz if I use
Code:
delayMicroseconds(100);  // 100 works for 3.906 Hz
then there are no errors. Shorter delays (say 1-50 us) will still produce the same error. I found that for faster ODRs (max 4 kHz) i need to find the optimum delay via testing.
So yes, using delays shorter than a microsecond did fix the issue. I suspect (or rather hope) that I will get away without delays in future when other functions are added (which take up time). I still don't fully understand why the SPI protocol would miss this high bits on occasion, though. I will follow up with relevant updates in this post as I keep learning.
Regs,
duschl
 
If you run the loop without delays and show loop() counts per second you'll see a number over 5-50,000 perhaps over - depending on how much time it takes to do the test read. That will be well in excess of normal usage and it may be affecting the device when it is only expecting to return data 100-2000 times per second.

Knowing the expected Hz rate of data from the device the time between data points would be knowable in microseconds and you could tune from there:: EXPECTED_MICROSECONDS = 1,000,000 / Hz

Code:
static elapsedMicros GoNow=0; 
if ( GoNow>= EXPECTED_MICROSECONDS ) {
  // ReadDevice() as needed until done
  while ( !(getRegisterByte(0x04) & 0b1) ) {
    delayMicroseconds(2);
    // do a count here and make sure it doesn't loop too much to adjust the EXPECTED_MICROSECONDS as needed
  }
  GoNow = 0;
}
 
Status
Not open for further replies.
Back
Top