Netduino home hardware projects downloads community

Jump to content


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.
Photo

SPI.WriteRead() returns junk


  • Please log in to reply
25 replies to this topic

#1 FelixEmman

FelixEmman

    Member

  • Members
  • PipPip
  • 25 posts

Posted 16 February 2011 - 01:48 PM

Hello netduino world,

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);
        	}
    	}
	}
}

The output is:

27
27
27
27
27
27
27
27
27
27

#2 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 16 February 2011 - 09:56 PM

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

#3 FelixEmman

FelixEmman

    Member

  • Members
  • PipPip
  • 25 posts

Posted 17 February 2011 - 03:40 AM

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


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...

#4 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 17 February 2011 - 07:36 AM

So this simple command works with these SPI settings, but I'm not getting back the expected MISO data...

Could you please share the LCD datasheet?

#5 FelixEmman

FelixEmman

    Member

  • Members
  • PipPip
  • 25 posts

Posted 17 February 2011 - 01:08 PM

Could you please share the LCD datasheet?


Sure, see attached.

Attached Files



#6 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 17 February 2011 - 02:39 PM

Sure, see attached.

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).

#7 FelixEmman

FelixEmman

    Member

  • Members
  • PipPip
  • 25 posts

Posted 17 February 2011 - 04:13 PM

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?

#8 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 17 February 2011 - 07:20 PM

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.

#9 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 17 February 2011 - 07:37 PM

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);
    ...
}


#10 FelixEmman

FelixEmman

    Member

  • Members
  • PipPip
  • 25 posts

Posted 17 February 2011 - 11:38 PM

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.

#11 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 18 February 2011 - 12:55 AM

Felix, 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

#12 FelixEmman

FelixEmman

    Member

  • Members
  • PipPip
  • 25 posts

Posted 18 February 2011 - 02:07 AM

Felix,

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.

#13 ajcg1973

ajcg1973

    Advanced Member

  • Members
  • PipPipPip
  • 71 posts

Posted 18 February 2011 - 10:24 PM

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.

#14 FelixEmman

FelixEmman

    Member

  • Members
  • PipPip
  • 25 posts

Posted 19 February 2011 - 02:07 PM

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.


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.

#15 ajcg1973

ajcg1973

    Advanced Member

  • Members
  • PipPipPip
  • 71 posts

Posted 21 February 2011 - 05:37 AM

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.

#16 FelixEmman

FelixEmman

    Member

  • Members
  • PipPip
  • 25 posts

Posted 24 February 2011 - 01:28 PM

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!

#17 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 24 February 2011 - 02:08 PM

FWIW, the NETMF SPI init also turns on the internal pullup resistors on CLK/MISO/MOSI ports.

Please note the 'true' SPI init happens in Xaction_Start() function (every time it is called, though).

#18 FelixEmman

FelixEmman

    Member

  • Members
  • PipPip
  • 25 posts

Posted 24 February 2011 - 02:38 PM

Please note the 'true' SPI init happens in Xaction_Start() function (every time it is called, though).


You're right, and it appears that it disables the internal pullups...

#19 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 25 February 2011 - 02:03 AM

...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.

Chris

#20 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 25 February 2011 - 02:06 AM

Hey FelixEmman,

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.

Chris




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.