Monday, May 11, 2020

Transmitting 32 bit longs between Arduinos using I2C

No soldering this time--let's get on the bench and get going!

TINY BUBBLES

From a previous post, I've been messing with new old stock NSA1166 bubble displays for an upcoming audio project; Part I post about retro bubble displays is here.


The 70's era stuff is cool, but who wants to hook up a lot of wiring for the display?  I want to make these bubbles respond to I2C commands, as you might see in an OLED display like the one here.  

I2C has 2 wires to transmit, 3 if you include ground so not too much wiring. 

If you need to brush up on the I2C protocol read more here--or watch a really good video here--in short, it's a super easy way to move data between digital dookies.

This time I'll focus on one tid-bit:  I2C wants us to send bytes of data (8 bits) down the wire, one at a time, but for this project I need 24 bits on the slave side; since this 6 digit bubble can display 0-999999. How do we do that?

Wait--let's transmit 32 bits, since that will be a common need for other projects. So: my goal is to be able to enter a long value in decimal on the master Arduino and have it show up in decimal on the slave.

I set up a Proof of Concept on the bench to figure this out. 

An Arduino UNO was used as I2C master and ProMicro cheapo clone as I2C slave--the $2 USD ProMicro used D2 for SDA and D3 for SCL. You knew that right? I didn't. 

Read more about that here

The Arduino IDE gives us the extremely useful wire.h library right out of the box, greatly simplifying I2C programming so let's use that.

HARDWARE SETUP

Here's how I wired it up:

I couldn't find an Eagle device for a 20 pin Pro Micro anywhere so I created an eagle device (how-to for that is here)--it's the 20 pin ProMicro Eagle footprint you see in the schematic above.



BENCH PRESS 

I used 2 old laptops each with the Arduino IDE running and an iPad for web access. Probably overkill?

To get this going the I2Cscanner sketch (here) proved its worth again, I used that to make sure the I2C device (the ProMicro Slave) could be recognized before creating any new code.

The Uno R2 talked to a ProMicro using I2C. Wiring details can be found here.  Again: on the Pro Micro Clone D2 is used for SDA and D3 for SCL.



 



ROPE-A-SCOPE

Turned out my bang for the buck Siglent 1202X-E scope (8VA teardown videois here) can accurately analyze and show me I2C data, which i didn't know before doing this proof of concept. This feature proved invaluable as I debugged my crappy code--for Siglent users, check out the video on getting I2C analysis going: here. Wish I knew about this feature before....

A couple of reminders for myself: bytes, ints, and chars are not the same thing.  For the master code I could get sloppy with variable types, but not with the slave code. I'll have to think about that, but overall, for Arduino, bytes and chars are 8 bits; ints are 16 bits, and longs are 32 bits. Doh!   

Shut up and show us the code! 

The POC code sends a sample long value to slave 10000 times over I2C then quits, which should be enough to see if the damn thing is working!


///////////////////MASTER/////////////////////////
#include <Wire.h>


// next line, put any decimal # here 0 to 999999



unsigned long int longInt = 333456;  
//on arduino unsigned long goes to 4 billion something

unsigned char byteArray[4];
   
int c = 0;


void setup() {
// put your setup code here, to run once:
Wire.begin();
//Serial.begin(9600);
}


void loop() {


 

Wire.beginTransmission(0x4);

byteArray[0] = (int)((longInt >> 24) & 0xFF) ;
byteArray[1] = (int)((longInt >> 16) & 0xFF) ;
byteArray[2] = (int)((longInt >> 8) & 0XFF);
byteArray[3] = (int)((longInt & 0XFF));


for (c = 0; c < 10000; c++)
    {
    Wire.write(byteArray, 4);
    delay(10 );
//    Serial.println("Sending");
//    Serial.println(c);
Wire.endTransmission();
    }


}


///////////////////////////////////////
//////////////////SLAVE/////////////////////////


#include <Wire.h>

long value = 0;

byte byteArray[4];

byte x = 0;



void setup() {
  // put your setup code here, to run once:
Wire.begin(0x4);
Wire.onReceive(receiveEvent);
Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
delay(100);    

}

void receiveEvent(byte)
{
  Serial.println("received");
  while(1 < Wire.available()) // loop through all but the last
  {
   
    for(int i=0; i<4; i++)
        {
         byteArray[i] = Wire.read();
        
     //    Serial.println(byteArray[i], HEX);
   
        }

  }
/////// convert back to long
delay(100);
for (int q = 0; q < 4; q++)
{
  value = (value << 8 ) + (byteArray[q] & 0xff);
}
Serial.println(value); 
}

BOARD YET?

I am also working on a PCB for the I2C slave arduino, bubble display, shift registers, pull up resistor array, etc., so far it looks like this; I might send it off for fab this week.



Enough! If anyone has questions about the code, bubbles, PCB, and all else, comment away, but for now, on the bench the POC works; putting a long value in the master code will make it show up in serial out on the slave side. Joy!  For the PCB, who knows--more bubble stuff coming up, as well as an audio chaos generator, just in time for the global chaos we are going through right now. Back to soldering soon. See ya.

UPDATE 7-18-20: Aloha! got this all working, see the Part III of this post here.

No comments:

Post a Comment

Anything to Clock Subcircuit

Readers:  If you want to build the project featured in today's post, please go to  PCBWAY's  Community pages --a gerber ready to dow...