Go Down

Topic: Syntax question for: SPI.transfer(buffer, size) (Read 17768 times) previous topic - next topic

wolfv

I got a shift register working.  WOO HOO.  No I am trying to daisy chain.

Three 74HC165 Parallel-In-Serial-Out (PISO) shift registers are Daisy chained.
I want to transfer 24 bytes at a time.

The Arduino reference shows syntax:
      SPI.transfer(buffer, size)
But no example is given.

My attempt at the syntax is:
      SPI.transfer(optionSwitch, 16);
Which gets this syntax error:
Code: [Select]

/home/wolfv/Documents/Arduino/demo/PISO/PISO.ino: In function 'void loop()':
/home/wolfv/Documents/Arduino/demo/PISO/PISO.ino:27:32: error: invalid conversion from 'uint16_t {aka short unsigned int}' to 'void*' [-fpermissive]
SPI.transfer(optionSwitch, 16); //
^
In file included from /home/wolfv/Documents/Arduino/demo/PISO/PISO.ino:7:0:
/opt/arduino-1.6.7/hardware/teensy/avr/libraries/SPI/SPI.h:787:21: error:   initializing argument 1 of 'static void SPIClass::transfer(void*, size_t)' [-fpermissive]
inline static void transfer(void *buf, size_t count) {
^


The following sketch is modified from Nick Gammon's excellent tutorial on http://www.gammon.com.au/forum/?id=11979
The sketch is for two shift registers, which will be expanded to three when I get another shift register:
Code: [Select]
#include <SPI.h>

const uint8_t LATCH = 9;

void setup ()
{
  SPI.begin ();
  Serial.begin (115200);
  Serial.println ("Begin switch test.");
  pinMode (LATCH, OUTPUT);
  digitalWrite (LATCH, HIGH);
}

uint16_t  optionSwitch;
uint16_t  oldOptionSwitch;

void loop ()
{
  digitalWrite (LATCH, LOW);
  digitalWrite (LATCH, HIGH);
  SPI.transfer(optionSwitch, 16); //error: invalid conversion from 'uint16_t {aka short unsigned int}' to 'void*' [-fpermissive]

  uint16_t mask = 1;
  for (uint8_t i = 0; i < 16; i++)
    {
    if ((optionSwitch & mask) != (oldOptionSwitch & mask))
      {
      Serial.print ("Switch ");
      Serial.print (i);
      Serial.print (" ");
      Serial.print ((optionSwitch & mask) ? "closed" : "opened");
      Serial.print (", optionSwitch=");
      Serial.println (optionSwitch, BIN);
      }
    mask <<= 1; 
    }
 
  oldOptionSwitch = optionSwitch;
  delay (10);   // debounce
}

What is the correct syntax for SPI.transfer(buffer, size)?

Thank you.

johnwasser

The function takes a pointer to the first byte and a number of bytes.  You can send your unsigned int with:
Code: [Select]
 SPI.transfer(&optionSwitch, 2);

The '&' operator is generally read as 'address of'.  It returns the address of a variable rather than the value it contains.
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

wolfv


Philblaze

May I chime in here, because I have the exact same question? I'm not understanding from the exchange above.

The documentation in the SPI reference page says that in SPI.transfer(buffer, size), buffer is an array. In the above it appears that the required data type for the buffer is an integer. Can you guys explain this? I get the part about the argument being a pointer.

Also, what are the limitations on size? I have 32 bits of data to read. Can I set size to 32 once the data type question is answered?

 

wolfv

#4
Jun 16, 2016, 08:22 pm Last Edit: Jun 16, 2016, 08:24 pm by wolfv
Hi Philblaze,

This should work:
Code: [Select]

#include <SPI.h>

uint32_t buffer;  //32 bits of data
uint8 size = 4;   //number of bytes

SPI.transfer(&buffer, size);


In this case, "array" means a sequence of bits (not a C array like buffer[] = {0,1, .. ,31} ).

johnwasser

The documentation in the SPI reference page says that in SPI.transfer(buffer, size), buffer is an array. In the above it appears that the required data type for the buffer is an integer. Can you guys explain this?
The actual argument is "void *" which basically mean "the address of some byte in memory".  If you are using a simple variable you prepend the '&' operator to get the address of the variable.  If you are passing an array or a pointer you just use the name.  The "rvalue" of an array name (the value when it is on the right side of an assignment operator) is the address of the first byte of the array.  The "rvalue" of a pointer is the contents of the pointer which is the address of the byte to which the pointer points.
Also, what are the limitations on size? I have 32 bits of data to read. Can I set size to 32 once the data type question is answered?
32 bits would be 4 bytes so set the size to 4.  You can't use the array-form for reading, only for writing.  The size is an unsigned int so you are limited to 65535 bytes.  Of course you are also limited by available SRAM.  Doesn't look like they support data in FLASH so to do that you'd need to write your own loop.
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

Philblaze

Thanks so much. It's still not working correctly, but I'm trying not to ask a whole bunch of noob questions. I've been working in Labview for the last 15 years and haven't touched text based programming much since the 6502 in assembly.

The important thing I've gleaned from this is that the array form cant be used for reads which is all I want to do. I don't need to send data. 

It's more important to me that I understand how this all works rather than just finding some code that works.

wolfv

#7
Jun 16, 2016, 10:31 pm Last Edit: Jun 16, 2016, 10:53 pm by wolfv
It can work for arrays too.
A tutorial on C arrays and pointers would explain how.

Code: [Select]

#include <SPI.h>

uint32_t buffer[ELEMENT_COUNT];  //32 bits of data per element
int i;        //buffer index
uint8 size = 4;   //number of bytes

SPI.transfer(&buffer[i], size);


Or did you want one bit per array element?  You can convert a 32 bit buffer to an array of bools using:
* for loop
* bitwise operator
* shift operator <<


westfw

SPI.transfer(buffer, N) transfers N 8bit bytes from the buffer to the SPI interface.  It does NOT set the size of each SPI data elements to N bytes (or bits); the AVR SPI peripheral only supports 8bit transfers.  Because of the way that SPI works, transferring 2 8-bit bytes MIGHT be equivalent to sending a 16bit transaction (I'm not sure whether that works with cascaded 74hc595-like chips.)

johnwasser

The important thing I've gleaned from this is that the array form cant be used for reads which is all I want to do.

It's more important to me that I understand how this all works rather than just finding some code that works.
Think of the SPI interface as a shift register. When you pull the SlaveSelect line low the slave's shift register is connected to the master's shift register. On each clock the master presents a bit to the slave via MOSI (Master Out/Slave In) line and the slave presents a bit to the master via MISO (Master In/Slave Out). After eight clocks the transfer is complete and the master and slave have exchanged one byte of information. If you are only sending you just ignore the data you received. If you are only receiving you load the register with data that the slave will ignore, typically zero.
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

DevilWAH

I have the following code, just for testing and i know variables are declared in the wrong place etc.

for the first transfer I want it to send 32 zeros to the SPI bus, and I thought I would output to serial to see what is being done.

However all i see in the serial monitor screen is a "y" with a few dots above it.

sizeof(Start) comes back as 4, which seems correct.

can any one point out where my issues might be as I am not seeing what is expected.

I want to be able to pass a 32bit value to the SPI bus in hex format.





Code: [Select]
#include <SPI.h>


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

  Serial.begin(9600);

  SPI.begin();
 
  uint32_t Start = 0x00000000;
  SPI.transfer(&Start, sizeof(Start));
  int num = sizeof(Start);
  Serial.print(num);
 

}

void loop() {
  // put your main code here, to run repeatedly:


 
  //SPI.transfer(&LED, sizeof(LED));
  uint32_t LED = 0xffffffff;
  uint32_t LEDoff = 0xe0000000;
  SPI.transfer(&LED, 4);
  SPI.transfer(&LEDoff, 4);
 
  Serial.write(LED);
  Serial.write(LEDoff);
 
  delay(1000);

}

westfw

Quote
all i see in the serial monitor screen is a "y" with a few dots above it.
I'm pretty sure that's what a 0 looks like when you try to display/write it (which is what serial.write() will do) instead of converting it to a number.   If you want to see the value, use Serial.print()


DevilWAH

Ahh good to know i will try that :) thank you

DevilWAH

OK so I have this code now

Code: [Select]
LED = (0x00000000);
  Serial.print(LED);
  Serial.print("\n");
  SPI.transfer(&LED, sizeof(LED));
  LED = (0xEF000000);
  Serial.print(LED);
  Serial.print("\n");
  SPI.transfer(&LED, sizeof(LED));
  Serial.print(LED);
  Serial.print("\n");
  SPI.transfer(&LED, sizeof(LED));
  Serial.print(LED);
  Serial.print("\n");
  SPI.transfer(&LED, sizeof(LED));
 


and the serial out put is

0
4009754624
4294967295
4294967295


So taking this a step at a time

1. the "0" is correct it = 0x00000000
2. the "4009754624" is also correct it = 0xef000000
3. 4294967295 is not correct it = 0xffffffff

So why is the value of LED changing between the SPI.tranfers? What am i missing in the code? any thoughts welcome.

DevilWAH

Oh I get it now, when using buffer it overwrites the buffer with the return data.

Just been reading up on it :)

Go Up