The Netduino forums have been replaced by new forums at community.wildernesslabs.co.
This site has been preserved for archival purposes only
and the ability to make new accounts or posts has been turned off.
I'm having some trouble with the SPI.WriteRead method. I've seen some older posts that reported issues with this method. I have the latest firmware (4.1.1 alpha7) on my netduino+, but it looks like the data coming back from my device is junk.
I have an LCD which talks SPI and always sends back a MISO status register byte as a response to any MOSI byte sent to it. This byte can change during the transmission of a multi byte command, but certain bits in this byte should always be the same (ie ONLINE bit). So I'd expect precise return bytes after each byte sent. Changing the clock does seem to have an effect, the return bytes change the pattern, but with the configuration in the code below I always get a 27 back. If I send the bytes as an array to a single WriteRead() call (commented code), the return bytes are junk, however they seem to have some kind of pattern (I see some bytes repeat in certain positions).
I don't have a logic analyzer yet to see what's on the wire but since the simple command in the code below is successful, I don't think my code is bad and I know that the device must be sending the expected MISO values back, but SPI.WriteRead() must be reading them wrong. From what I can tell, the Netduino firmware calls the SPI routines directly from NETMF without any alterations. Thoughts? Could SPI.WriteRead() still broken?
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.NetduinoPlus;
namespace NetduinoPlusApplication1
{
public class Program
{
public static void Main()
{
var SPIConfig = new SPI.Configuration(Pins.GPIO_PIN_D10, // CS port
false, // SS active when LOW
0, // CS Setup time
0, // CS Hold time
true, // Clock idle is high
true, // Data is sampled on rising edge of clock
6000, // Clock rate in KHz
SPI_Devices.SPI1);
var SPI = new SPI(SPIConfig);
//send some empty bytes first - response should be 0x08 (ONLINE), but always 27 (0x1B)
byte[] readBuff = new byte[] { 0x0 };
SPI.WriteRead(new byte[] { 0x00 }, readBuff);
Debug.Print("" + readBuff[0]);
SPI.WriteRead(new byte[] { 0x00 }, readBuff);
Debug.Print("" + readBuff[0]);
//simple command - clear screen to red, the return bytes are always 27
SPI.WriteRead(new byte[] { 0x13 }, readBuff);
Debug.Print("" + readBuff[0]);
SPI.WriteRead(new byte[] { 0xEC }, readBuff);
Debug.Print("" + readBuff[0]);
SPI.WriteRead(new byte[] { 0x00 }, readBuff);
Debug.Print("" + readBuff[0]);
SPI.WriteRead(new byte[] { 0x01 }, readBuff);
Debug.Print("" + readBuff[0]);
SPI.WriteRead(new byte[] { 0x09 }, readBuff);
Debug.Print("" + readBuff[0]);
SPI.WriteRead(new byte[] { 0x55 }, readBuff);
Debug.Print("" + readBuff[0]);
SPI.WriteRead(new byte[] { 0xAA }, readBuff);
Debug.Print("" + readBuff[0]);
SPI.WriteRead(new byte[] { 0x00 }, readBuff);
Debug.Print("" + readBuff[0]);
//sending the same command this way will instead return junk in the readBuff
//byte[] writeBuff = new byte[] { 0x13, 0xEC, 0x00, 0x01, 0x09, 0x55, 0xAA, 0x00 };
//byte[] readBuff = new byte[9];
//SPI.WriteRead(writeBuff, readBuff);
//now just blink an led
var led = new OutputPort(Pins.ONBOARD_LED, false);
while (true)
{
led.Write(true);
Thread.Sleep(1000);
led.Write(false);
Thread.Sleep(1000);
}
}
}
}
Hi Felix,
Have you double-checked the SPI configuration settings (active high/low, rising/falling edge, KHz speed, etc.)? When I have trouble with SPI it's almost always one of those that's causing me trouble.
Chris
Have you double-checked the SPI configuration settings (active high/low, rising/falling edge, KHz speed, etc.)? When I have trouble with SPI it's almost always one of those that's causing me trouble.
Chris
Chris, I'm sure about the config, per the datasheet the CS is active low, clock idle is high, data sampling is on rising clock edge, clock khz doesn't really matter (I get the same results with 750 - 6000 values). Any other combinations of CS, clock idle and data sampling edge will not work. I know because the LCD will not carry out the [clear screen to specific color] command which I'm sending in my example, unless I have the settings as specified above. So this simple command works with these SPI settings, but I'm not getting back the expected MISO data...
Thanks. For what I have read in the datasheet, you should use single WriteRead() method call to send multi-byte command to the LCD (the current SPI implementation is a bit unfortunate, because it initializes SPI pins at the beginning of each WriteRead() method call and then uninitializes them at the end, which causes toggling Chip Select line and unwanted Clock signal transitions).
If I send the bytes as an array to a single WriteRead() call (commented code), the return bytes are junk, however they seem to have some kind of pattern (I see some bytes repeat in certain positions).
My guess here is that the received junk is caused by missing inter-byte delays, as specified in the datasheet (p. 22). Unfortunately, this feature is not currently supported in the firmware neither (and you cannot achieve it with multiple WriteRead() calls, because they toggle Chip Select, as noted above).
Thanks. For what I have read in the datasheet, you should use single WriteRead() method call to send multi-byte command to the LCD (the current SPI implementation is a bit unfortunate, because it initializes SPI pins at the beginning of each WriteRead() method call and then uninitializes them at the end, which causes toggling Chip Select line and unwanted Clock signal transitions).
My guess here is that the received junk is caused by missing inter-byte delays, as specified in the datasheet (p. 22). Unfortunately, this feature is not currently supported in the firmware neither (and you cannot achieve it with multiple WriteRead() calls, because they toggle Chip Select, as noted above).
CW2, thanks for taking time to read through all this.
The interbyte delay should be accounted for by the fact that I'm sending bytes separately. If this did not work at all then I'd be more worried about my code. But like I said, the command is carried out and the screen turns red, which indicates that it received the byte sequence and interpreted it correctly. I just don't know why I'm not getting the expected reply bytes.
I do realize that I have to build my own native driver to control a bunch of these from a single master. Instead of using separate CS lines I will need to use a 3-to-8 decoder with 3 wires to control 8 SPI devices. I'm really not sure how to achieve that in native code. I'm new to NETMF and would need some advice on how to actually implement the native code. I'm wondering if Corey's fluent interop can handle something like that. Or should I wait for the rumored interop feature that will be added soon? The SPI code in the NETMF codebase seems to be doing a lot of stuff which I'm not sure I need, but does anyone know if that's a good place to look for code examples of how to write to registers and flip ports?
The interbyte delay should be accounted for by the fact that I'm sending bytes separately. If this did not work at all then I'd be more worried about my code. But like I said, the command is carried out and the screen turns red, which indicates that it received the byte sequence and interpreted it correctly. I just don't know why I'm not getting the expected reply bytes.
I see - you would probably need to analyze the communication to see what exactly is happening there.
I do realize that I have to build my own native driver to control a bunch of these from a single master. Instead of using separate CS lines I will need to use a 3-to-8 decoder with 3 wires to control 8 SPI devices. I'm really not sure how to achieve that in native code.
I think you could do that in managed code: pass Pins.GPIO_NONE as ChipSelect_Port in SPI.Configuration constructor and the instantiate (3 to 8) OutputPort-s to handle chip select signals. The Netduino microcontroller has built-in 4-to-16 decoder for chip select lines, but unfortunately this is not supported in the current firmware, and the necessary pins are not broken out.
Actually, could you please try the following? I.e. using a separate OutputPort for chip select?
public static void Main()
{
var cs = new OutputPort(Pins.GPIO_PIN_D10, true);
var spiConfig = new SPI.Configuration(Pins.GPIO_NONE, ...);
var spi = new SPI(spiConfig);
var readBuff = new byte[1];
cs.Write(false);
spi.WriteRead(new byte[] { 0x00 }, readBuff);
// ...
cs.Write(true);
...
}
Actually, could you please try the following? I.e. using a separate OutputPort for chip select?
public static void Main()
{
var cs = new OutputPort(Pins.GPIO_PIN_D10, true);
var spiConfig = new SPI.Configuration(Pins.GPIO_NONE, ...);
var spi = new SPI(spiConfig);
var readBuff = new byte[1];
cs.Write(false);
spi.WriteRead(new byte[] { 0x00 }, readBuff);
// ...
cs.Write(true);
...
}
I tried your suggestion to drive CS explicitly but the command doesn't get picked up by the LCD. The more I look at my requirements, the more I'm convinced that what I need cannot be done with the currently available SPI functionality. I'll have to come up with a native driver of some sort.
If you bit-bang the SPI in managed code, does it work? [That is a slow way to do it--but a good step from a diagnostics standpoint.]
Chris
Hey Chris,
I haven't tried that, and it would probably be very slow for any practical purposes. I might try it if I get some time, but in all reality I'm trying to get away from having to implement SPI manually by bitbanging. Meanwhile I ordered a saleae logic analyzer to look at what's going on the wires. At this point I'm looking more at ways to implement my SPI requirements in native code, one way or another.
Felix,
I had an issue with SPI when I was reading and writing to a wireless module. The issue that I saw seems to be very similar to your issue. The returned byte was never what was to be expected but it was always the same value being returned. I by accident, put resistance on my CS pin inline to my wireless module and now it works correctly with SPI just fine. I wasn't ever able to figure out what the resistor did that made it work.
Can you install a ~220 ohm resistor inline between your LCD and the Netduino CS line and see if you get a different result back? The issue just sounds so similar to my issue that I'm really wondering if it makes a difference for you as well.
I had an issue with SPI when I was reading and writing to a wireless module. The issue that I saw seems to be very similar to your issue. The returned byte was never what was to be expected but it was always the same value being returned. I by accident, put resistance on my CS pin inline to my wireless module and now it works correctly with SPI just fine. I wasn't ever able to figure out what the resistor did that made it work.
Can you install a ~220 ohm resistor inline between your LCD and the Netduino CS line and see if you get a different result back? The issue just sounds so similar to my issue that I'm really wondering if it makes a difference for you as well.
Hi ajcg1973,
Can you detail a bit more on how exactly you connected the resistor to the CS line? My LCD has the following lines, all coming from the netduino+: 3.3v, a few connections to GND, MOSI, MISO, SCLK, CS. Did you connect the 220ohm to 3.3v (pullup)? or to GND (pulldown)? Or to another netduino port (not sure if that would make sense...)?
I'm away for the weekend but I'll try the pullup/pulldown on the CS line when I get back.
Hi ajcg1973,
Can you detail a bit more on how exactly you connected the resistor to the CS line? My LCD has the following lines, all coming from the netduino+: 3.3v, a few connections to GND, MOSI, MISO, SCLK, CS. Did you connect the 220ohm to 3.3v (pullup)? or to GND (pulldown)? Or to another netduino port (not sure if that would make sense...)?
I'm away for the weekend but I'll try the pullup/pulldown on the CS line when I get back.
I just installed the resistor between the Netduino's CS pin and the CS pin of the other chip (or the CS line on the LCD in your case). No pull downs or pull ups needed. Once again, I'm just curious of your results because I'm trying to gather more information on why a resistor on the CS line worked for my circuit. I'm also seeing other people post in the forums about SPI problems more and more and I'm wondering if there is a connection somewhere.
I tried the 220 resistor between the netduino CS and device CS with no success. The data is the same. FWIW, the NETMF SPI init also turns on the internal pullup resistors on CLK/MISO/MOSI ports.
I think the SPI functions are very limited to what they can do, and for more precise SPI timings, the SPI namespace is useless...
I would like to start building some drivers but since there is no Wiki ... digging through the many different ways from different people in the forum will be a bad dream.
Secret Labs : No disrespect but for doing something more meaningful than blinking LEDs, we need a Wiki, and we need the latest source code!
...the current SPI implementation is a bit unfortunate, because it initializes SPI pins at the beginning of each WriteRead() method call and then uninitializes them at the end, which causes toggling Chip Select line and unwanted Clock signal transitions).
CW2, does it still do this in the newest firmware releases (v4.1.0.6 RC2, v4.1.1 a7, and v4.1.2 a0)?
We found a few bugs in the .NET MF AT91 SPI code which were fixed about a month ago...
If there are specific issues, we should start a thread about them and see if we can get them resolved in the v4.1.1 beta.
Secret Labs : No disrespect but for doing something more meaningful than blinking LEDs, we need a Wiki, and we need the latest source code!
What do you need? The latest production source should be posted. We are working on getting alpha/beta source up soon too so you can always build the latest "daily" code. The only things I know of which aren't posted right now are beta code.
Really quick...we have the source for 4.1.0.6 all ready to go. If you want to PM me with your e-mail address, I can send it to you. We're planning on calling 4.1.0.6 "gold" and changing RC2 to RTM in the next few days...we're just waiting the traditional 2 weeks to make sure no critical last-minute issues crop up.