SPI1 SCK speed deviation

Hello,

I am using a Boron with an OV2640 SPI camera on SPI1 bus configured at 8Mhz. I observed an upper deviation of 0.081 Mhz on the SCK line, is that within frequency tolerances of the SPI1 bus? It’s the first time I seriously work with SPI so I’m a bit stumped. OV2640 documentation specifically mentions the need to not overclock its SPI, and I have strange behaviour when I change the length of the cable that goes to the camera board.

Thanks!

@Simgag, how are you setting your SPI clock in code? SPI is greatly affected by the length of wires which increases both capacitance and resistance between the SPI port and the device. How are you connecting to the camera (type of wires) and how long are you wanting those wires to go?

There’s an SPI1.begin(SPI_MODE_MASTER); and then every bus call goes like this in lib:

uint8_t ArduCAM::bus_write(int address,int value)
{
#if defined (PARTICLE)
  SPI1.beginTransaction(SPISettings(8*MHZ, MSBFIRST, SPI_MODE0));
#endif
    cbi(P_CS, B_CS);
    #if defined (RASPBERRY_PI)
        arducam_spi_write(address | 0x80, value);
    #else
        SPI1.transfer(address);
        SPI1.transfer(value);
    #endif
    sbi(P_CS, B_CS);
#if defined (PARTICLE)
    SPI1.endTransaction();
#endif
    return 1;
}
uint8_t ArduCAM:: bus_read(int address)
{
#if defined (PARTICLE)
  SPI1.beginTransaction(SPISettings(8*MHZ, MSBFIRST, SPI_MODE0));
#endif

	uint8_t value;
	cbi(P_CS, B_CS);
	#if defined (RASPBERRY_PI)
		value = arducam_spi_read(address & 0x7F);
		sbi(P_CS, B_CS);
		#if defined (PARTICLE)
            SPI1.endTransaction();
        #endif

		return value;	
	#else
		#if (defined(ESP8266) || defined(__arm__))
		#if defined(OV5642_MINI_5MP)
		  SPI1.transfer(address);
		  value = SPI1.transfer(0x00);
		  // correction for bit rotation from readback
		  value = (byte)(value >> 1) | (value << 7);
		  // take the SS pin high to de-select the chip:
		  sbi(P_CS, B_CS);
		  #if defined (PARTICLE)
                SPI1.endTransaction();
            #endif
		  return value;
		#else
		  SPI1.transfer(address);
		  value = SPI1.transfer(0x00);
		  // take the SS pin high to de-select the chip:
		  sbi(P_CS, B_CS);
		  #if defined (PARTICLE)
                SPI1.endTransaction();
            #endif
		  return value;
		#endif
		#else
		  SPI1.transfer(address);
		  value = SPI1.transfer(0x00);
		  // take the SS pin high to de-select the chip:
		  sbi(P_CS, B_CS);
		  #if defined (PARTICLE)
                SPI1.endTransaction();
            #endif
		  return value;
		#endif
#endif

Length of wires goes from about 2 inches when I install the OV2640 directly on my PCB to about 8 inches when I use it with the ribbon cable supplied with the camera board. Everything goes fine at 2 inches, I get some missing data at 8 inches. When I look at the Hex from the corrupted picture, I get a pair of 0x00 at every few bytes and at consistent intervals.

Just a note about SPI and its “need” for a stable clock.
The 8MHz setting you are referring to is a max. rate but the actual communication is typically resilient to moderate deviations above that limit and even more so for slower speeds as the the client will trigger data output by the edges of the clock signal rather than a constant rate.

So when you see erroneous data it’s more likely due to bad signal quality rather than “instable” clock frequency.

@Simgag, since the max speed of SPI1 is 8MHz, the calculation for the SPI1 clock setting should be “clean” producing the expect 8MHz. However, 0.081MHz deviation on 8MHz is 1% which is most likely within tolerances.

It is my understanding that GPIO current drive on the nRF52840 is set in the DeviceOS to “standard” which is 2-4mA. I believe this may have been changed in the 2.0.0-rc1 release but I’m not sure. This drive setting would substantially affect the rise time impact caused by longer wires.

@rickkas7, can you please comment on the GPIO current drive and possible changes in the DeviceOS?

1 Like

For the record, I use 1.5.2.

Yes, SPI drive strength changed from standard to high in 2.0.0.

@rickkas7 , can I configure pinSetDriveStrength(A5, DriveStrength::HIGH); in some way in 1.5.2? Updating my whole code to 2.0.0-rc1 may be tedious.

No, it’s not possible to change SPI drive strength on 1.5.x or earlier, because Device OS will overwrite any change you make for SPI or SPI1 if you try to set it directly using the nRF52 SDK or registers.

After giving a bit of tought, I don’t think that this would be the issue, I use a buffer chip between the Boron and OV2640 in both cases (ribbon or not). I will try to downclock to 4Mhz to see if this resolve the issue.