Spi for both wiz820io and OLED ssd1332 not working correctly

Status
Not open for further replies.
Hi,

I've tested the wiz820io and an ssd1332 OLED with a teensy 3.2, each separately and they both work.

Now I'm trying to use both at once with different chip select pins.
To test it I have a counter that is displayed on the oled and the upd send receive string example with processing.
At first the counter works fine and the wiz receives some of the processing strings but then the serial monitor shows that the wiz received some random junk upd and the oled freezes.

Code:
Received packet of size 53394
From 149.79.84.47, port 40219
Contents:
�/08g7�g����zvGM:A�w��-�~
Received packet of size 59142
From 207.170.92.51, port 59013
Contents:
�����_9L���v;��$

It seems like a problem with the spi sharing. I've tried wrapping each segment with beginTransaction endTransaction, put pull up resistors on both CS (10k).
I'll also post a picture of my breadboard later.
I'm using the ethernet library straight from paul's github and the oled library and modified adafruit graphics library from sumotoy.

Any hints or ideas?

Here is my code
Code:
#include <Adafruit_GFX.h>
#include <OLED_SSD1332.h>


/*
Note for Teensy 3.x !!!!!!!!!!!!!!!!!!!
 You should choose from those pins for CS and RS:
 2,6,9,10,15,20,23
 */
#define cs   15
#define rst  6
#define dc   2


// Color definitions
#define  BLACK           0x0000
#define BLUE            0x001F
#define RED             0xF800
#define GREEN           0x07E0
#define CYAN            0x07FF
#define MAGENTA         0xF81F
#define YELLOW          0xFFE0  
#define WHITE           0xFFFF
#define TRANSPARENT     -1

int count = 0;
OLED_SSD1332 display = OLED_SSD1332(cs, dc, rst);


#include <SPI.h>         // needed for Arduino versions later than 0018
#include <Ethernet.h>
#include <EthernetUdp.h>         // UDP library from: bjoern@cs.stanford.edu 12/30/2008
//#include <SPI.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(10, 10, 10, 2);

unsigned int localPort = 8888;      // local port to listen on

// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];  // buffer to hold incoming packet,
char ReplyBuffer[] = "acknowledged";        // a string to send back

// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;


void setup() {
  //oled 
  pinMode(9, OUTPUT);
  digitalWrite(9, LOW);   // reset the WIZ820io
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);  // de-select WIZ820io
  pinMode(cs, OUTPUT);
  digitalWrite(cs, HIGH);   // de-select the SD Card
//  SPI.setCS(cs);

  SPI.setCS(cs);
//  SPI.beginTransaction(SPISettings(24000000, MSBFIRST, SPI_MODE0));
  display.begin();
  display.setBitrate(24000000);
  display.setRotation(270);
//  SPI.endTransaction();

  SPI.setCS(10);
  // start the Ethernet and UDP:
//  SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
  Ethernet.begin(mac, ip);
  Udp.begin(localPort);
//  SPI.endTransaction();
  Serial.begin(115200);
//  SPI.begin();
  
}

void loop() {
  SPI.setCS(10);
  
  digitalWrite(10, LOW);
  delay(2);
  SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
  // if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    Serial.print("Received packet of size ");
    Serial.println(packetSize);
    Serial.print("From ");
    IPAddress remote = Udp.remoteIP();
    for (int i=0; i < 4; i++) {
      Serial.print(remote[i], DEC);
//      gotPacket = true;
      if (i < 3) {
        Serial.print(".");
      }
    }
    Serial.print(", port ");
    Serial.println(Udp.remotePort());

    // read the packet into packetBufffer
    Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    Serial.println("Contents:");
    Serial.println(packetBuffer);

    // send a reply to the IP address and port that sent us the packet we received
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(ReplyBuffer);
    Udp.endPacket();
  }
  SPI.endTransaction();
  digitalWrite(10, HIGH);
  delay(40);

  //oled 
//  if(gotPacket)
//  {
  SPI.setCS(cs);
  digitalWrite(cs, LOW);
  delay(2);
  
  SPI.beginTransaction(SPISettings(24000000, MSBFIRST, SPI_MODE0));
  
  display.clearScreen();
  display.setTextColor(WHITE);  
  display.setTextSize(1);
  String st;
  for(int i = 0; i < 7; i++)
  {
    if(i == 0)
    display.setTextColor(RED);  
    else
    display.setTextColor(WHITE);  
    display.setCursor(0, i*9);
    display.println(count);
  }
  
  
  SPI.endTransaction();
  digitalWrite(cs, HIGH);
  
  delay(40);
//gotPacket = false;
//  }
  count ++;
}


/*
  Processing sketch to run with this example
 =====================================================

 // Processing UDP example to send and receive string data from Arduino
 // press any key to send the "Hello Arduino" message


 import hypermedia.net.*;

 UDP udp;  // define the UDP object


 void setup() {
 udp = new UDP( this, 6000 );  // create a new datagram connection on port 6000
 //udp.log( true );     // <-- printout the connection activity
 udp.listen( true );           // and wait for incoming message
 }

 void draw()
 {
 }

 void keyPressed() {
 String ip       = "192.168.1.177"; // the remote IP address
 int port        = 8888;    // the destination port

 udp.send("Hello World", ip, port );   // the message to send

 }

 void receive( byte[] data ) {      // <-- default handler
 //void receive( byte[] data, String ip, int port ) { // <-- extended handler

 for(int i=0; i < data.length; i++)
 print(char(data[i]));
 println();
 }
 */
 
If the ethernet interface uses a software driver with an interrupt upon receipt of message (IP packet), and a read is ever-present so as not to miss packets, then the ISR for that interface may use the SPI port without "asking". This is the basic issue with sharing an SPI port, even with independent chip select pins.

The driver for the wiznet... does its ISR use the SPI port?
Same applies to any device that uses a shared SPI port in an ISR.

SPI transactions, as best as I know, facilitates SPI port sharing among application layer functions, but cannot deal with the ISR issue - other than blocking the interrupt for a time. That latency can be brief enough to be viable in some communications methods.

Of course, one can have a driver whose ISR sets a flag or changes a task's state, or changes a finite state machine's state to do the work later in a non-ISR context were sharing might work. Since the Wiznet chips have on-chip packet buffers, this would work. SPI based devices like low cost data radios that don't have such a buffer have to get the ISR to use the SPI port.

This can happen eve with, say, an LCD driver where the LCD interrupts to say "last graphics command is finished", and if that ISR uses the SPI port, the same issue arises; deferred SPI I/O is needed, and in this case, it's not perishable data as is the case for received communications data.

So, if these situations arise, one must use Paul's SPI transactions to manage sharing of the SPI port at the ISR level.
 
Last edited:
Hi,

Actually nope, it's not using the interrupt, and I'm using beginTransaction/endTransaction in the code to guard against this kind of potential problem.
 
Is the Wiznet interface then done with high-rate Polling of its interrupt request bit - though it's not used to actually interrupt? Else polling where each poll is SPI traffic would be very inefficient and require the overhead of SPI Transactions for each poll?
 
Is the Wiznet interface then done with high-rate Polling of its interrupt request bit - though it's not used to actually interrupt?

Nope. The Wiznet IRQ signal isn't used in any way, not even polling.

Else polling where each poll is SPI traffic would be very inefficient and require the overhead of SPI Transactions for each poll?

Oh how this underestimates the terribly inefficient design of the Arduino Ethernet library!

Actually, with Teensyduino 1.28 I've published a new version that removes much of the redundant register access, which speeds it up dramatically... about to this inefficient level.
 
as you probably know, to avoid polling by sending SPI inquiries in a polling superloop, one can connect the interrupt request bit from the Wiznet to a GPIO input bit. But not use it as an interrupt. So avoid the architectural impact and SPI sharing impact of an ISR that uses SPI, the polling loop can look at the GPIO bit. If true, it means that at a future time when the SPI port can be "taken", the reason for the GPIO polled bit being true can be ascertained via an SPI read of status. But only when the chip has a status change that necessitates doing the SPI read. Most changes are packet transmit complete and packet received. The latter is the hard nut.

This might be easily implemented and not affect the overall structure. Just a different criteria in the polling loop.

I take it that no one has implemented a real interrupt driven handler for the Wiznet chips for the Arduino world?
 
stevech: This seems like what I did on the ILI9341 Touch driver. Put in an (optional) interrupt pin that sets a flag in the library that retards polling when no touch has been registered. It doesn't do any SPI I/O on the interrupt and it cuts down on polling SPI noise, but allows 'polling' when wanted to keep the touch responsive rather than cutting back to save I/O, making the touch sluggish. It was ~20 line PULL request - included struct adds.
 
So am I getting this issue from the arduino's ethernet library inefficiency?
As I understand it the polling and interrupt shouldn't be a problem in my case?

Any other suggestions?

Thanks
 
Any other suggestions?

Please give it a try with the just-released Teensyduino 1.28. The Ethernet lib has lots of improvements in 1.28. When compiling, pay attention to any messages about duplicate libs. You want to make sure it's using Ethernet from hardware/teensy/avr/libraries.

If that doesn't pan out, can you give me a link to the OLED_SSD1332 library, and the least expensive display it supports. Maybe I'll get one and try to reproduce the problem here.
 
Just tried teensyduino 1.28 with arduino 1.6.8 and still the same problem.

I was using the ethernet library straight from your github Paul, now I'm just using the one in the teensyduino package.

Here is the library I'm using https://github.com/sumotoy/OLED_SSD1332 it also needs a modified version of the adafruit gfx library: https://github.com/sumotoy/Adafruit_GFX


And here is the OLED I'm using: http://www.waveshare.com/0.95inch-rgb-oled-b.htm
I thought the (sparce) documentation for it was a bit misleading as it says it uses the ssd1331 controller but somotoy's sdd1332 library worked with it whereas his ssd1331 library didn't. But I just tested the adafruit library for ssd1331 and it works, expect it's really slow (adafruit doesn't use hardware spi) and so the teensy's loop refresh rate drops to about 1hz.

I'll try to get back into sumotoy's library and see if I can hack something.

Thanks Paul!!
 
Status
Not open for further replies.
Back
Top