SPI MISO signal without SPI.transfer() function

I have an Arduino Mega 2560 set up as a slave, and a LabView program sending a byte of information on the MOSI line. This operation is successful.

I want my Arduino to send data along the MISO line back to the LabView (or, as it might be described, have the LabView program get data from the Arduino.)

I intend on periodically sending data to LabView (or requesting data), acting as a "visual update" for this UI software I'm developing.

Any thoughts?

Any website references I could brief?

SPI is for synchronous data. The master knows down to the nanosecond when a bit of data is going to be present or absent on the MISO line because the master sent out a clock signal to the slave.

Serial is for asynchronous data. The sender can send at any time with no prior coordination with the receiver.

You have 3 extra hardware serial ports on your Mega. Use one of them.

Err... maybe you have Labview acting as the SPI master? Then you need to understand how SPI works. Try Nick Gammon's tutorial: Gammon Forum : Electronics : Microprocessors : SPI - Serial Peripheral Interface - for Arduino

I'm going to try to apply what you're saying about the hardware pins, thank you.

Follow-up question: does the master need to initiate the request of slave data? If this is the case, would I need to use the ISR (SPI_STC_vect) to set the SPDR?

This might emphasize my lack of understanding of SPI, but my issue revolves around the fact that I want to use SPI for different, separate circumstances. When I send data from Master to Slave, I use the ISR interrupt to capture the byte. I've read that you can set the SPDR (send data from the slave back up to master) during this operation, as part of the whole transaction, however I do not intend on sending anything back to master while this happens...which might conflict with the purpose of SPI.

lennon-pledge:
I have an Arduino Mega 2560 set up as a slave

I want my Arduino to send data along the MISO line back to the LabView (or, as it might be described, have the LabView program get data from the Arduino.)

I intend on periodically sending data to LabView (or requesting data), acting as a "visual update" for this UI software I'm developing.

Transmission is under control of the Master. LabView (the Master) will have to periodically ask the Arduino (the Slave) for data. If LabView can handle an interrupt you could have the Arduino use a line to tell LabView that it has data.

I would hope LabView has an interrupt service set up in the FPGA ha.

Here's a scenario that might occur given what I want to do (does it make sense or not?)

Situation 1: I send a byte from LV, here's what it's info represents (LSB is first): e.g. 01001100

8th and 7th bit can be 10 or 01, to signify that the byte I'm sending represents either setpoint temperature or vial selection. Bits 5-1 represent the temp or vial value (temp: 3-8 deg. C; vial: 1-16). My 6th bit isn't used.

Situation 2 (unresolved): Master gets byte from slave, this byte represents the current temperature being read from a sensor.

Regarding the 6th bit, if I separate these situations by a 0 or 1 for the 6th bit, would I be able to accomplish my goal?

So, the byte from Situation 1 now contains a 1 for the 6th bit ---- when the ISR gets fired, I'll first analyze the bit via bitRead(x,5). If it's a 1, sit. 1 is run. If sit. 2, the bit will be 0 and I'll then set the SPDR with the temperature byte and give it to the master.

Does this sound like an appropriate thing to do for the SPI?

Vial? Temperature? We can't see your setup. We've got no idea what you have over there.

SPI is great for stuff that needs to happen quickly. It can send a lot of data to a screen or an Ethernet shield. For anything else that needs slightly less data, Serial is usually best.

SPI is also great for small sensors like thermometers or accelerometers where there isn't a fully-featured microprocessor inside the sensor. You use it like a memory chip - send the address you want to read, then read as many bytes as you want. The sensor can act on these requests with some very simple logic. This makes the sensor smaller and cheaper.

Since it seems like you're so far down the track of SPI, then it's probably best to keep going that way. Look at how a sensor like the ADXL345 works on the SPI side. If you want to change a setting on the chip, you send a "command" which says what register you're going to change. Then you send a value to be put into that register. If you want to read data from the chip, you send a read command which includes the register number you want to read. The chip places the value into the outgoing SPI buffer and the next 8 clock cycles from the master will send out the 8 bits.

Don't try to cram everything into one 8-bit byte. You have a relatively large amount of memory and you don't need this to happen super-fast. I would make a separate register for each piece of information, even if it's only one bit of an on/off command. A temperature reading is likely a 2-byte value.

I attached a photo of the SPI output from Labview. Here's the breakdown:

  1. Button selection for rotating a carousel to a specified vial, or for selecting a setpoint for temperature (applied in a PID loop format in Arduino.)
  2. SS goes low, MOSI goes high, and the byte is sent.
  3. SS goes high, MOSI goes low, and the button functionalities are shut off (so as to make the case condition (the question mark) false.)

That is for Situation 1. Situation 2 (the way I want it to work) will rely on 5 second interval signals to be sent to the LabView console, to be read and processed with the current temperature sensor readings. Now that I'm thinking about how these situations won't conflict, I don't think there will be a way (in an FPGA environment) to use SPI for both situations.

So, Morgan, you mentioned using hardware serial ports. I have never used them but 0 and 1 (RX and TX) are available. I will do my reading and researching, but would I be able to conduct Situation 2 via the transmit and receive lines (given that my LabView software is set to send 5 second requests via the RX line?) Can the RX line receive 1 or 2 bytes, and can the TX line transmit 1-2 bytes?

Thanks for all the help so far.

lennon-pledge:
If sit. 2, the bit will be 0 and I'll then set the SPDR with the temperature byte and give it to the master.
Does this sound like an appropriate thing to do for the SPI?

The problem with that is that by the time you receive the command byte from the Master it is too late to provide data in the response.

Think of SPI as two shift registers at each end. The output register is Parallel In/Serial Out. The input register is Serial In/Parallel Out. The master pulls the SlaveSelect pin LOW to enable the registers and pulses the SCK line 8 times. On each clock pulse, one bit shifts out of the Master's output register onto the MOSI line and into the Slave input register. On the same clock one bit shifts out of the Slave output register onto the MISO line and into the Master input register. The Master can then save the received byte, put a new value into the output register, and clock 8 more times. Repeat until all data is sent and received. Then the Master raises the SlaveSelect line to let the the slave know that the transaction is done. The Master receives one byte for every byte it sends.

Typically the Master will send commands that don't require a response by just clocking out the bytes and ignoring the data that arrives in the input register. If a command expects a response it will send one or more bytes of command and then send DUMMY BYTES while clocking in the one or more bytes of response. The Slave recognizes the command and uses the clocks for the DUMMY BYTES to provide a response.

You should probably not use the SPDR register directly but use the Slave features of the Wire library.

lennon-pledge:
(in an FPGA environment)

You have failed to introduce this aparrently-critical component. Where does the FPGA fit between the Arduino and Labview? Can you draw a schematic?

Here's the diagram from post #6 (note there were zero downloads before I added this)

I don't understand Labview, but it look like there's no FPGA in that diagram.

I don't know what you mean by "where does FPGA fit between Labview and Arduino." The Labview .vi contains logical operations that the FPGA's mezzanine I/O pins conduct. I don't want to preach about FPGA's 'cause I don't have enough experience to do so hah, but from I've gathered so far, the .vi is not operations by software, but via the hardware on the mezzanine card.

So to answer your question as best I can, the graphical code in the Labview .vi gets burned to physical gates and wires in the FPGA. When I run the .vi that my diagram is contained in, the while loop (outer-most gray rectangle) basically runs continuously 'til I stop the program with the stop button provided in LabView. If those 2 buttons you see are false, currently, the while loop will run but nothing will execute.

I have some questions now regarding the SPDR register and how MOSI and MISO are supposed to transfer data simultaneously. Below is my Arduino ISR function to get you a better picture of what it is I'm doing during the transfer. Ignore the purpose behind "Vial Change" and "Setpoint Change"....they could be anything.

ISR (SPI_STC_vect) {
  byte b = SPDR;
  // check if 5th bit is 0 or 1.  0 implies a request for temp data. 1 implies to initiate an action.
  if (bitRead(b, 5)) {  
    if (bitRead(b,6)) {
      Serial.println("7th bit for Vial Change is set.");
      vial = b - 64;
      Serial.println(vial);
      process_vial = true;
    } else if (bitRead(b,7)) {
      Serial.println("8th bit for Setpoint Change is set.");
      setp = b - 128;
      Serial.println(setp);
      process_temp = true;
    } else {
      Serial.println(b);
    }
  } else {
    Serial.println("Sending temperature data to LabView.");
  }
}
  1. When my LabView MOSI signal transfers the 8 bits, does the Arduino SPDR "collect" all 8 bits before I can read them in my ISR function? I figure it will because my first line in the ISR reads in a full byte from SPDR, so they should all be there.
  2. When do I send data through the MISO line? In my current ISR, I collect the byte transferred from the LabView .vi. The 5th bit, if set to 0, is the indicator that the temperature information (integer 3 - 8.) should be transferred to my LabView .vi via the MISO line (which currently just prints out "Sending....").
    a) Do I perform this in the ISR?
    b) If so, how do I prevent it from conflicting with the current SPDR register?
    c) If, after the byte b = SPDR, the SPDR is empty, can I set the SPDR with my temperature data?

I wouldn't ask so many questions if my searches online came to fruition (or even partial fruition hah.)

Thanks.

withoout reposting your code, the way I would do it firstly would put all your Serialprintln commands in the while loop

create a global variable to retain the SPDR command from master

so something like that maybe:

volatile byte spi;

// SPI interrupt routine
ISR (SPI_STC_vect)
{
spi = SPDR;

// if spi -bit 5 is zero

SPDR = temperature update

//else if spi bit bla bla = 0

do something and so on....

//else SPDR = 0; //Reset SPDR value (so set it to a default value of your choosing)

}

void setup (void)
{

// have to send on master in, slave out
pinMode(MISO, OUTPUT);

// turn on SPI in slave mode
SPCR |= _BV(SPE);

// turn on interrupts
SPCR |= _BV(SPIE);

SPDR = 0; //initialise SPI register

} // end of setup

void loop{
// if spi -bit 5 is zero

//print message x

//and so on...

}

I've read about setting the SPDR register, but is that something that needs to be written in conjunction with the incoming byte on the MOSI line (so that the slave can be active to send byte data back on the MISO line?)

Furthermore, I read about a clever line that waits 'til the SPIF bit is no longer set (on account of the interrupt service no longer being needed) and the SPSR register no longer needs to be read.

while (!(SPSR) & (1<<SPIF));

I'll use that after setting the SPDR.

lennon-pledge:

  1. When my LabView MOSI signal transfers the 8 bits, does the Arduino SPDR "collect" all 8 bits before I can read them in my ISR function? I figure it will because my first line in the ISR reads in a full byte from SPDR, so they should all be there.
  2. When do I send data through the MISO line? In my current ISR, I collect the byte transferred from the LabView .vi. The 5th bit, if set to 0, is the indicator that the temperature information (integer 3 - 8.) should be transferred to my LabView .vi via the MISO line (which currently just prints out "Sending....").
    a) Do I perform this in the ISR?
    b) If so, how do I prevent it from conflicting with the current SPDR register?
    c) If, after the byte b = SPDR, the SPDR is empty, can I set the SPDR with my temperature data?

I wouldn't ask so many questions if my searches online came to fruition (or even partial fruition hah.)

Thanks.

OK, I think I understand a little better now. The "Labview program" mentioned in the first post is actually running on an FPGA. I thought Labview was some kind of PC program. That makes things a little simpler.

  1. Yes. You only need to know that there's new SPI data available to the Arduino when there's a complete byte. The Arduino is an 8-bit machine so it makes no sense to get an alert that some of the bits have arrived and others haven't.

  2. You don't. The SPI hardware in the Arduino chip does that. It just lets you know when it's sent a byte and you should load a new one ready for the next clock pulse from the master.

2a. Yes.

2b. This is one of those special registers where writing to the register does something different to reading from the register. The hardware presents to the Arduino program as if there's only one register but there's actually several, to take care of problems loading the register during data transmission. Read the datasheet for your Arduino's chip.

2c. Yes.

Have you read: Gammon Forum : Electronics : Microprocessors : SPI - Serial Peripheral Interface - for Arduino yet?

Morgan, thank you very much for that information...I'm about 95% to the finish line.

I've got a final follow-up question for you (or for anyone else, really.)

I read on the Gammon SPI forum that the function SPI.transfer() allows for "simultaneous" give-and-take between master and slave....however, I can surmise that that is applicable only for a setup of two Arduinos (not using LabView.)

Based off of my Arduino code, LabView cannot determine when the MISO line begins to receive the data (especially if the first bit is 0.) From the picture I attached (I have reformatted it a bit but it's generally the same thing), I'm making "educational" timing guesses in order to sync the returned byte to LabView. I noticed that if I add statements in the Arduino IDE that takes 1 ms, my bit-stream is shifted 1 to the right.

I drew out a scheme that initiates the first 8 bits along the MOSI line.
Next, an undetermined amount of time (a variable time, given that I add or remove statements in the Arduino ISR function) passes 'til the SPDR register gets set with the return byte.
Then, LabView reads the data as best it can (which, right now, consists of technically-correct bits of value 1, just shifted left or right (which sometimes leads to loss of data.))

I figured I could make a calculation based on this undetermined amount of time, but it will not work since it is impossible to tell at what point the returned byte should be read.

So my next idea is to send 2 bytes in succession...the first byte contains only a 1 for the 8th bit...then I can make the assumption that, 7 bits later, the important byte can be assumed to be the following 8 bits.

If that makes sense, how do I go about setting the SPDR register twice? Or, how do I go about sending a 16-bit int/char through the MISO line?

Thanks

lennon-pledge:
LabView cannot determine when the MISO line begins to receive the data (especially if the first bit is 0.)

It's supposed to look at the SS and SCL lines to figure out when a data bit is available on the signal line.

Ok, time to stop hand-waving and show your code. A 1ms delay is probably not 1 bit right-shift. What is the actual clock speed that the master generates on SCL?

The slave should load the outgoing SPI register with the next byte when it gets the interrupt which tells it the last byte has gone out OK. It doesn't shift right by one bit. If it is too late to load the register then the hardware will send a byte which is probably all zeroes. (I have not checked the datasheet.)

Bear with me here, I'm going to write a paragraph from the SPI Operation section 4.6.1.1 from the book "Arduino Microcontroller Processing for Everyone! Part 1". After that, I'm going to write down an order of operations, so to speak, that I plan on using....I just want to know if I understand SPI operation to it's fullest extent.

"SPI transmission is initiated by loading a data byte into the master configured SPDR. At that time, the SPI clock generator provides clock pulses to the master and also to the slave via the SCK pin. A single bit is shifted out of the master designated shift register on the MOSI microcontroller pin on every SCK pulse. The data is received at the MOSI pin of the slave designated device. At the same time, a single bit is shifted out of the MISO pin of the slave device and into the MISO pin on the master device. After eight master SCK clock pulses, a byte of data has been exchanged between the master and slave designated SPI devices. Completion of data transmission in the master and data reception in the slave is signaled by the SPIF in both devices. The SPIF flag is located in the SPSR of each device. At that time, another data byte may be transmitted."

So, with that being said, here's how I want to approach conducting an SPI transmit/receive between this LabView project and the Arduino Mega 2560.

A little background first, my main goal is taking a temperature value (achieved via an LM35 sensor wired to the Arduino - acting as the slave) and putting it into my LabView software - the master. For now, I'm treating it as an integer data type. I have a volatile global variable that stores this temperature value every 5 seconds (using the Timer.h library.) This is done via my timer-based function obtainTemp().

  1. In obtainTemp(), I set the SPDR to the byte 10000000.
  2. LabView triggers transmit/receive, so the byte 00100000 gets transmitted to Ard., and 10000000 gets received in LabView. 00100000 gets stored in a global volatile variable called incoming.
  3. SPIF is now 1, so interrupt ISR routine is triggered.

This is the part that gets me: if the transaction happens simultaneously, I feel like that implies the SPDR register should have data in it before the Arduino receives any byte at all.

  1. Inside ISR, I set the SPDR with the temperature data. When I transmit the second byte from LabView, it'll store it in a local variable called byte b and, I assume at the same time, receive the temperature data from the previously set SPDR.
ISR (SPI_STC_vect)
{
    if (bitRead(incoming, 5)) {    // I evaluate that 6th bit to see if LV wants to read data
        SPDR = temp;    // get the buffer ready for transaction
        byte b = SPDR;  // receive data from LabView...hopefully the temp data gets exchanged
        // other stuff
    } else {
        // other situation irrelevant to post
    }
}

If any of you are wondering why I don't just send the temp data immediately upon request, instead of sending two bytes (10000000 and the temp byte) I'll explain that now.

In LabView, I am not using any definitive pre-built SPI functionalities, I'm doing everything hard-pulsed. I have noticed that if I add even one line extra in my Arduino code, signals will be thrown off by 1 ms. My clock pulses are 2 ms periods (1 ms up, 1 ms down)....and there is no way to get these two separate machines in sync with each other. However, I created this process in LV that allows me to receive the byte 10000000 as sort of an initial timer pulse to time when the next byte gets received (the temp byte.) This might not be without it's errors, but it can compensate for the unknowable lines of code that I may or may not add in the future.

So in terms of my ISR routine and how I'm treating this exchange process, is this the correct way to do it?

You didn't mention the Slave Select line at all.

You didn't mention what data mode you are using. The clocking of MOSI is on one edge of the clock pulse and the clocking of MISO is on the other edge. Does your clock line idle in the HIGH state or the LOW state?

lennon-pledge:
Bear with me here,

Why not just use the Arduino SPI library?

...R

Clock line idles in the High State. When I initiate a transmission from LabView, the SS is pulled low (then set High at the end of the process....then a wait of 5 ms is employed to separate transmissions.)

I'm not actually using any of the SPI library functions except in the setup(), when I initialized the lines and interrupt:

void setup() {
    pinMode(MISO, OUTPUT); 
    pinMode(MOSI, INPUT);
    pinMode(SS,OUTPUT);  
    pinMode(SCK, INPUT);
    SPCR = (1<<SPIE)|(1<<SPE)|(0<<MSTR);
    SPDR = 0;
}

I'm not using the SPI library because that works with 2 synchronous Arduino's (from what I've read at least.) With LabView, it's got it's own mindset...the Arduino has to abide by it in the most literal Master-Slave scenario possible. So, SPI.transaction() would've been very helpful, but since the Arduino is a bare-bones slave and the master operates in a completely different tongue (even though the procedure is similar), I can't perform the functions from the library. HOWEVER, if you know of any way to manipulate the library to abide for slaves communicating to non-Arduino masters, let me know...that'll provide me with other options if my current scenario fails. Thanks.