SPI Transfers

Hello,

I have some hardware that I have made which includes two 32 bit shift registers. I had two 32 bit variables in which i would use bitSet to set the required bits, I then send each set of 32 bits out using four 8 bit SPI.transfer statements as follows:

SPI.transfer((j >> 24) & 0xff);
SPI.transfer((j >> 16) & 0xff);
SPI.transfer((j >> 8) & 0xff);
SPI.transfer(j & 0xff);
SPI.transfer((k >> 24) & 0xff);
SPI.transfer((k>> 16) & 0xff);
SPI.transfer((k>> 8) & 0xff);
SPI.transfer(k & 0xff);

This all works really well.

For other reasons I would now like to use a single 64 bit number which I create as I did before using bitSet to set the required bits on (0-63).

I then set about sending the bits out using the following:

SPI.transfer((l >> 56) & 0xff);
SPI.transfer((l >> 48) & 0xff);
SPI.transfer((l >> 40) & 0xff);
SPI.transfer((l >> 32) & 0xff);
SPI.transfer((l >> 24) & 0xff);
SPI.transfer((l >> 16) & 0xff);
SPI.transfer((l >> 8) & 0xff);
SPI.transfer(l & 0xff);

I found that this only dealt with the first 32 bits - subsequent research suggested that the >> and << operators only work up to 32 bits.

I recall that it is possible to use SPI.transfer in an alternative manner by specifying a pointer to the variable and the buffer length so, knowing that my variable was ‘l’, I tried this:

SPI.transfer(&l, 64);

However, this appeared to send nothing.

Essentially I would like to know if I am on the right track or whether this is in fact not possible.
I could perhaps split the variable ‘l’ in to two 32 bit variables and revert back to my previous method though I think I am quite close to the answer - though I cannot make it work!
The hardware is an ESP8266 (Wemos) and the shift registers are HV5622’s which i have used many times with the 32 bit variable method.

All pointers would be gleefully received.

Kind regards

Richard

How is the 64 bit l variable declared ?

Please post a complete sketch showing the problem rather than snippets of it

Please follow the advice on posting code given in Read this before posting a programming question

In particular note the advice to Auto format code in the IDE and to use code tags when posting code here as it prevents some combinations of characters in code being interpreted as HTML commands such as italics, bold or a smiley character, all of which render the code useless

If the code exceeds the 9000 character inline limit then attach it to a post

Hello again and thank you for the pointer about how to include the code.
I have extracted the relevant points from the main program to illustrate my method.
I have declared the 64 bit variable using uint64_t.

Everything about the my previous attempts has worked perfectly - as long as I stuck within the constraints of using only 32 bits and shifting them to the right in order to perform groups of 8 bit transfers.

Am I pursuing something which is achievable or would I be better reverting to using on 32 bits?

  • Richard
#include <SPI.h>

const byte LEpin = 12;
uint64_t l ;  //the new store for 64 bits for the shift registers




void setup() {
  // put your setup code here, to run once:

  // set up SPI
  SPI.begin();
  SPI.setFrequency(100000);
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE1);


  //set outputs for SPI
  pinMode(LEpin, OUTPUT);

  
}

void loop() {
  // This for loop just sets l to 0, then sets bits and  calls the spi transfer
  // change the 32 to 24, 16, 8 or 0 to work on different sets of bits
  
for (int jloop=0; jloop<8; jloop++){
  l=0;
  bitSet(l,jloop+32);
  spiTX();
  nonBlock(3000);
  }
}

void spiTX(){
 
  //send L out 
  //SPI transfer code 

// perhaps split l into two parts, the lower part 

  digitalWrite(LEpin, LOW);
 // SPI.transfer((l >> 56) & 0xff);
 // SPI.transfer((l >> 48) & 0xff);
 // SPI.transfer((l >> 40) & 0xff);
 // SPI.transfer((l >> 32) & 0xff);
 // SPI.transfer((l >> 24) & 0xff);
 // SPI.transfer((l >> 16) & 0xff);
 // SPI.transfer((l >>  8) & 0xff);
 // SPI.transfer(l & 0xff);
 SPI.transfer(&l,32);
  digitalWrite(LEpin, HIGH);
  
}


//This is a non-blocking 'delay' - use instead of 'delay' to avoid ESP8266 WDT resets
void nonBlock(unsigned long delay_time)
{
  unsigned long time_now = millis();
  while (millis() < time_now + delay_time) {
    yield();
    ESP.wdtFeed();
    //waiting!
  }
}

I just noticed that in the code I have
SPI.transfer(&l,32);
I am experimenting at present - what i would like to make work is:
SPI.transfer(&l,64);

  • Richard
SPI.transfer((void *) l, sizeof(l));

BTW, using single-character variable names is very poor coding practice (except perhaps as the index of a very short 'for' loop). Using 'l' as a variable name is even worse since it looks like the numeral 'one' in some fonts.

Thank you for that suggestion it certainly output data though the bit pattern appeared not to change however I set it - more testing must be done.
I completely get it about the variable names - I think it stems from the late 70's and 80's when I was programming my Ohio Superboard in a BASIC that supported only 1 (or perhaps 2) character variable names!
Furthermore - I had already used j and k, l being the next in line though I knew from the outset that of all the single letters to choose from (which should have been 'none of them') that was probably the worst!
I shall report back asap.

  • Richard

Update - I got it working.

It turns out that:

SPI.transfer((void *) l, sizeof(l));

… was just part of my problem. I was struggling to set all 64 bits correctly until I modified the bitSet and bitClear macros as follows:

#define bitSet64(value, bit) ((value) |= (1ULL << (bit)))
#define bitClear64(value, bit) ((value) &= ~(1ULL << (bit)))

The change being from ‘1UL’ to ‘1ULL’ in both - which is beyond my skill level but I received some helpful advice which got me there.
Thank you gfvalvo for your help and advice.

  • Richard

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.