Arduino I2C to SPI with SC18IS602B

I’m going to be doing some neat things with an STM32F030 and since it’s a limited pin number, I want to maximize my pins and I want to make it somewhat expandable\hackable, so because of this, almost everything is going to need to go across i2c; however, I have LCD screens that work across SPI and likewise SD cards can use a SPI interface, so I need a way to access those over SPI.

Enter the SC18IS602B! A relatively cheap I2C to SPI adapter and super easy to work with.

Setup

For our SPI device, I’m using Sparkfun’s Serial 7-Segment Display because of how basic it is. Just send it data and it’ll spit it on the screen.

Once you have it soldered to a breakout board, here is the layout I’ve gone with:

You’ll notice three lines going from 14-16 to ground. These are the address lines (A0 – A2 respectively). If you look in the datasheet (linked above) on Figure 4 we can configure the address for our device. Now if you’re new to I2C, then this is a very common feature of I2C devices.

For us Arduino users, we ignore the RW bit as that’s automatically taken care of by the Wire library, so all we need to do is look at the actual numbers, in our case, we are dealing with 0x28. So we would use

Wire.beginTransmission(0x28);

when we want to talk to that device. Of course, you can change the address lines yourself and change your corresponding variables. If you can’t figure it out, then the Arduino I2C Scanner Sketch is super useful.

First attempt

To talk to a specific SPI slave, then we simply do

Wire.beginTransmission(0x28);
Wire.write(0x0X);
Wire.write(DATA);
Wire.endTransmission();

Where X = the SPI slave number + 1 (yes, SPI slave 0 you would do Wire.write(0x01), see Table 4 for more information).

So, let’s write ‘hiEe’ to the display:

#include <Wire.h>

#define TWI_ADDR 0x28
#define RESET_SEG 7
#define RESET_TWI 8
void setup() {
// put your setup code here, to run once:

pinMode(RESET_SEG, OUTPUT);
pinMode(RESET_TWI, OUTPUT);
digitalWrite(RESET_SEG, HIGH);
digitalWrite(RESET_SEG, LOW);
delay(50);
digitalWrite(RESET_SEG, HIGH);

digitalWrite(RESET_TWI, HIGH);
delay(100);
digitalWrite(RESET_TWI, LOW);
delay(100);
digitalWrite(RESET_TWI, HIGH);
delay(1000);
Wire.begin();

}

void loop() {
// put your main code here, to run repeatedly:
Wire.beginTransmission(TWI_ADDR);
Wire.write(0x01);
Wire.write('v');
Wire.write('h');
Wire.write('i');
Wire.write('E');
Wire.write('e');
Wire.endTransmission();
delay(500);
}

Diagnosing the problem

We upload this and…..we get garbage!? Did we do something wrong? Is the chip broken? What’s going on?

We’ll let’s debug this using an oscilloscope. I’m using anOpenScope MZ and by probing the SPI Clock (Blue) and MOSI (Orange), I get this wave form:

Here, we can see our v and h being sent correctly, but we the screen is garbage…so what’s going on?

Well, sadly, the SparkFun datasheet doesn’t say this, but our problem is that we’re going too fast for the display to keep up with. So we must slow down our chip!

How though?

Fixing the problem

Well, time to turn to the Datasheet!

Section 7.5.1 gives detail on how to configure the SPI interface.

By default register 0xF0 is set to all zeros. If we look at bits 0 and 1, we can set the clock!

To do this, we’ll add the following:


Wire.beginTransmission(0x28);
Wire.write(0xF0);
Wire.write(0x03); //set our SPI clock to the slowest
Wire.endTransmission();

With this change and after we reupload, things should look correct, although, you may still see a flicker, but that can be adjusted to your own needs.

Now, I don’t know how a beginner is supposed to figure this out on their own (especially if they don’t have an oscilloscope), but I hope that this helps someone out.

Final Code

#include <Wire.h>

#define TWI_ADDR 0x28
#define RESET_SEG 7
#define RESET_TWI 8
void setup() {
// put your setup code here, to run once:

pinMode(RESET_SEG, OUTPUT);
pinMode(RESET_TWI, OUTPUT);
digitalWrite(RESET_SEG, HIGH);
digitalWrite(RESET_SEG, LOW);
delay(50);
digitalWrite(RESET_SEG, HIGH);

digitalWrite(RESET_TWI, HIGH);
delay(100);
digitalWrite(RESET_TWI, LOW);
delay(100);
digitalWrite(RESET_TWI, HIGH);
delay(1000);
Wire.begin();

//Slow down our SPI bus
Wire.beginTransmission(TWI_ADDR);
Wire.write(0xF0);
Wire.write(0x03);
Wire.endTransmission();

}

void loop() {
// put your main code here, to run repeatedly:
Wire.beginTransmission(TWI_ADDR);
Wire.write(0x01);
Wire.write('v');
Wire.write('h');
Wire.write('i');
Wire.write('E');
Wire.write('e');
Wire.endTransmission();
delay(500);
}

This entry was posted in Engineering and tagged , , , . Bookmark the permalink.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.