Help with I2C Control of 4-Digit 7-Segment Display w/I2C Backpack

EL Wire/Tape/Panels, LEDs, pixels and strips, LCDs and TFTs, etc products from Adafruit

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
vortex
 
Posts: 8
Joined: Sun Sep 30, 2012 10:05 pm

Re: Help with I2C Control of 4-Digit 7-Segment Display w/I2C Backpack

Post by vortex »

Code here includes working commands for talking to an 8 relay board over i2c. Using the code below, junk is printed to the LCD. The code looks like:

Code: Select all

// Test file to connect to a 7 segment Adafruit LED
// display over i2c and test it.
//
//
//

#include <iostream>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdint.h>
#include "i2c-dev.h"

using namespace std;

#define SEVEN_SEG_LCD_0 0x70 
#define SEVEN_SEG_LCD_1 0x71 

static const uint8_t numbertable[] = {
	0x3F, /* 0 */
	0x06, /* 1 */
	0x5B, /* 2 */
	0x4F, /* 3 */
	0x66, /* 4 */
	0x6D, /* 5 */
	0x7D, /* 6 */
	0x07, /* 7 */
	0x7F, /* 8 */
	0x6F, /* 9 */
	0x77, /* a */
	0x7C, /* b */
	0x39, /* C */
	0x5E, /* d */
	0x79, /* E */
	0x71, /* F */
};

uint16_t displaybuffer[8];
int file;

int beginTransmission();
void endTransmission();
void startOscillator();
void displayOnBlinkOff();
void setBrightness();
void sendCharacters();


int main() {

	startOscillator();
	displayOnBlinkOff();
	setBrightness();
	sendCharacters();

}

int beginTransmission() {

	// BeagleBone specific I2C bus
	if ((file = open("/dev/i2c-3", O_RDWR)) < 0) {
		cout << "Failed to open connection to the I2C Bus" << endl;
		return (1);
	}

	if (ioctl(file, I2C_SLAVE, SEVEN_SEG_LCD_1) < 0) {
		cout << "I2C_SLAVE address " << SEVEN_SEG_LCD_1 << " failed..." << endl;
		return (2);
	}

	return 1;
}

void endTransmission() {
	close(file);
}

void startOscillator() {
	beginTransmission();
	i2c_smbus_write_byte(file, 0x21);
	endTransmission();
}

void displayOnBlinkOff() {
	beginTransmission();
	i2c_smbus_write_byte(file, 0x80 | 0x01 | (0 << 1));
	endTransmission();
}

void setBrightness() {
	beginTransmission();
	i2c_smbus_write_byte(file, 0xE0 | 15);
	endTransmission();
}

void sendCharacters() {

	beginTransmission();

	displaybuffer[0] = 0x3F; // 0
	displaybuffer[1] = 0x06; // 1
	displaybuffer[2] = 0x00; // colon off
	displaybuffer[3] = 0x5B; // 2
	displaybuffer[4] = 0x4F; // 3

	for (uint8_t i=0; i<8; i++) {
		//Wire.write(displaybuffer[i] & 0xFF);
		i2c_smbus_write_byte(file, displaybuffer[i] & 0xFF);
	}

	endTransmission();
}


User avatar
vortex
 
Posts: 8
Joined: Sun Sep 30, 2012 10:05 pm

Re: Help with I2C Control of 4-Digit 7-Segment Display w/I2C Backpack

Post by vortex »

Have been playing around and refactored slightly, now 3 out of 4 characters are working OK. Not sure why the last one is always displaying as 0

Code: Select all

// Test file to connect to a 7 segment Adafruit LED
// display over i2c and test it.
//
//
//

#include <iostream>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdint.h>
#include "i2c-dev.h"

using namespace std;

#define SEVEN_SEG_LCD_1 0x71 //30a Relay Board

uint16_t displaybuffer[8];
int file;

int beginTransmission();
void endTransmission();
void sendCharacters();

int main() {
	sendCharacters();
}

int beginTransmission() {

	// BeagleBone specific I2C bus
	if ((file = open("/dev/i2c-3", O_RDWR)) < 0) {
		cout << "Failed to open connection to the I2C Bus" << endl;
		return (1);
	}

	if (ioctl(file, I2C_SLAVE, SEVEN_SEG_LCD_1) < 0) {
		cout << "I2C_SLAVE address " << SEVEN_SEG_LCD_1 << " failed..." << endl;
		return (2);
	}

	return 1;
}

void endTransmission() {
	close(file);
}

void sendCharacters() {

	beginTransmission();

	i2c_smbus_write_byte(file, 0x21); // start oscillator
	i2c_smbus_write_byte(file, 0x81); // display on, blink off
	i2c_smbus_write_byte(file, 0xEF); // set brightness to max

	i2c_smbus_write_byte(file, 0x00); // starting RAM Address

	cout << "First numbers " << endl;

	displaybuffer[0] = 0x3F; // 0
	displaybuffer[1] = 0x06; // 1
	displaybuffer[2] = 0x00; // colon off
	displaybuffer[3] = 0x5B; // 2
	displaybuffer[4] = 0x4F; // 3

	i2c_smbus_write_i2c_block_data(file, 0x00, 8, (__u8 *)displaybuffer);

	sleep(4);

	cout << "Second numbers" << endl;

	displaybuffer[0] = 0x7C; // b
	displaybuffer[1] = 0x79; // E
	displaybuffer[2] = 0x00; // colon off
	displaybuffer[3] = 0x79; // E
	displaybuffer[4] = 0x71; // F

	i2c_smbus_write_i2c_block_data(file, 0x00, 8, (__u8 *)displaybuffer);

	endTransmission();
}
The 7seg should show 0123 and then 4 seconds later show bEEF but, it shows 01230 and then bEE0. Unsure why.

Does anyone have any suggestions?

User avatar
high-fidelity
 
Posts: 4
Joined: Mon Jun 18, 2012 9:04 am

Re: Help with I2C Control of 4-Digit 7-Segment Display w/I2C Backpack

Post by high-fidelity »

Does the i2c_smbus_write_i2c_block_data function send the high or low 8 bits of each value in the displaybuffer first? It may be that it's sending the wrong bits initially. The low bits must be sent first (they're the ones connected to the segment). If it's sending the high bits first, then that may be the issue.

When I did this, I was sending them as follows:

Code: Select all

i2c_write(0x70 << 1 + 0x00); // send the address
i2c_write(0x00); //starting register
for (int i = 0; i < 8; i++) {
   i2c_write(displayBuffer[i] & 0xFF);
   i2c_write(displayBuffer[i] >> 8);
}
I do it in a series of discrete 8 bit transfers.

The project I'm working on is a Peugeot 206 GTi, which has currently ground to an exacting and complete halt! It turns out that when I wrote this up last year that my wife was pregnant with our second child and I rather grossly underestimated the time required to look after 2 babies under 1.5 years!

Anyway, the idea was that I was developing a monitoring box that has a 20Hz GPS, accelerometer and gyrometer which would interface with a MegaSquirt V3 ECU controlling the car's fuel and spark. Since the plan was for it to be a dedicated track car, the work I was doing would substitute as a dash and datalogger. It would also provide a synchronised trigger to a couple of GoPro cameras scattered around the car.

At this stage, the 206 will be going back on the road, ready to drive another few 10's of thousands of kilometres until I find enough time to do the work to turn it into a track car. Mechanically it was getting pretty close, but electrically and safety wise, it still had someway to go, and they're the bigger jobs, so back to the road it goes for now.

Have attached my code here. It will need some additional files to compile as is, but it should be enough to show how it works.
i2c.tar.gz
i2c source
(2.21 KiB) Downloaded 238 times

User avatar
vortex
 
Posts: 8
Joined: Sun Sep 30, 2012 10:05 pm

Re: Help with I2C Control of 4-Digit 7-Segment Display w/I2C Backpack

Post by vortex »

Wow thanks for the code! One thing I have run into is that it looks like the i2c code isn't sending a stop bit. My display gets confused sometimes when I play around with different options, but unplugging it doesn't fix it.

Actually perhaps it's the i2c bus that's getting confused?

Anyway I'm not sure how to send a stop bit. Your code has it but clearly the stm32 is different to on Linux, but the character must be the same surely?

User avatar
high-fidelity
 
Posts: 4
Joined: Mon Jun 18, 2012 9:04 am

Re: Help with I2C Control of 4-Digit 7-Segment Display w/I2C Backpack

Post by high-fidelity »

According to http://www.mjmwired.net/kernel/Document ... s-protocol the i2c_smbus_write_i2c_block_data function will do the stop for you, so you shouldn't need to worry about.

Not really sure what else could be the problem. I recommend giving it a go byte by byte and see if you can make it work like that. Once you've got that working, it shouldn't be too difficult to turn it into a block write operation.

I'm now playing with these displays on an LPC1114 for a little home project.

User avatar
high-fidelity
 
Posts: 4
Joined: Mon Jun 18, 2012 9:04 am

Re: Help with I2C Control of 4-Digit 7-Segment Display w/I2C Backpack

Post by high-fidelity »

One thing I should have mentioned... I verified that I was getting what I wanted on the i2c bus by using an el cheapo usb logic analyser. It may be worth trying the same if you're having problems.

User avatar
vortex
 
Posts: 8
Joined: Sun Sep 30, 2012 10:05 pm

Re: Help with I2C Control of 4-Digit 7-Segment Display w/I2C Backpack

Post by vortex »

I finally managed to get back to having another look at this problem today (haven't been able to look at it since February for various reasons, mostly laziness and lack of motivation).

I fixed the issue :)
For reasons I don't fully understand, when I used the code like this:

Code: Select all

		displaybuffer[0] = 0x02 | 0x80; // add a decimal point to this one
		displaybuffer[1] = 0x02 | 0x80; // add a decimal point to this one
		displaybuffer[2] = 0xFF; // colon.
		displaybuffer[3] = 0x02;
		displaybuffer[4] = 0x02;
		i2c_smbus_write_i2c_block_data(file, 0x00, 8, (__u8 *)displaybuffer);
The final number/letter would never work. I thought well perhaps I'm overflowing the buffer - I changed the length value from 8, to 4, lo-and behold only the first two digits only worked. A result, it looks like 8 may even be too short. Changed it to 10:

Code: Select all

		displaybuffer[0] = 0x02 | 0x80; // add a decimal point to this one
		displaybuffer[1] = 0x02 | 0x80; // add a decimal point to this one
		displaybuffer[2] = 0xFF; // colon.
		displaybuffer[3] = 0x02;
		displaybuffer[4] = 0x02;
		i2c_smbus_write_i2c_block_data(file, 0x00, 10, (__u8 *)displaybuffer);
And the last digit began to work!

Trap for young players!

User avatar
vortex
 
Posts: 8
Joined: Sun Sep 30, 2012 10:05 pm

Re: Help with I2C Control of 4-Digit 7-Segment Display w/I2C Backpack

Post by vortex »

It should be said, that now I know what that variable is for, the better way would be to use sizeof() thus:

Code: Select all

		displaybuffer[0] = 0x01 | 0x80; // add a decimal point to this one
		displaybuffer[1] = 0x01 | 0x80; // add a decimal point to this one
		displaybuffer[2] = 0xFF; // colon.
		displaybuffer[3] = 0x01;
		displaybuffer[4] = 0x01;
		i2c_smbus_write_i2c_block_data(file, 0x00, sizeof(displaybuffer), (__u8 *)displaybuffer);

Numerius_Negidius
 
Posts: 4
Joined: Sun Jun 02, 2013 4:25 pm

Re: Help with I2C Control of 4-Digit 7-Segment Display w/I2C Backpack

Post by Numerius_Negidius »

Hi,

I'm trying to access the Display using only the Wire library. I'd like to display High-Fidelity's Fuel message, the following code, however, does not work. What am I missing?

Code: Select all

#include <Wire.h>


void setup(){
  Wire.begin();
  Serial.begin(9600);



 Wire.beginTransmission(0x70);
 Wire.write(0x21);
 Wire.write(0xEF);
 Wire.write(0x85);
 Wire.write(0x00);
Wire.write(0x71);
Wire.write(0x3E);
Wire.write(0x00);
Wire.write(0x79);
Wire.write(0x38);
Wire.endTransmission();
}

void loop(){
}
Thank you very much!


Edit: Anyone?

Numerius_Negidius
 
Posts: 4
Joined: Sun Jun 02, 2013 4:25 pm

Re: Help with I2C Control of 4-Digit 7-Segment Display w/I2C Backpack

Post by Numerius_Negidius »

Anyone? Pretty please?

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Help with I2C Control of 4-Digit 7-Segment Display w/I2C Backpack

Post by adafruit_support_mike »

Hi - When you have a question, it's best to post a new topic than adding to the end of one that already exists. The new ones get our attention first, then if we have time we'll do a sweep through the other threads to look for stragglers.

WRT the code, I don't see anything immediately wrong. The general transmission sequence looks good, the address is right, and while I haven't translated the data values they should at least do something.

Let's test your wiring and hardware by dropping back to a known configuration and seeing if that works. Load the Adafruit sevenseg.ino sketch into your Arduino and see if that makes the display do what it should.

If you need the sketch, it's here: https://github.com/adafruit/Adafruit-LE ... venseg.ino , and the library is just up the file tree from there.

Numerius_Negidius
 
Posts: 4
Joined: Sun Jun 02, 2013 4:25 pm

Re: Help with I2C Control of 4-Digit 7-Segment Display w/I2C Backpack

Post by Numerius_Negidius »

Hm, the Adafruit code works just fine. I've also tried the code with an Attiny2313 (using an AVR library), the code definitely responds via I²C, because the Attiny doesn't keep sending the address (I would see this on the oscilloscope). Must be something with the commands themselves :(

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Help with I2C Control of 4-Digit 7-Segment Display w/I2C Backpack

Post by adafruit_support_mike »

Looking at the code above in the page, you seem to have the blink rate and brightness settings reversed. Try this:

Code: Select all

Wire.write( 0x21 );    //  start the oscillator
Wire.write( 0x81 );    //  display on, blink off
Wire.write( 0xEF );    //  brightness to maximum
Wire.write( 0x00 );    //  start at RAM address 0
Wire.write( 0x7C );    //  b
Wire.write( 0x79 );    //  E
Wire.write( 0x00 );    //  decimal point off
Wire.write( 0x79 );    //  E
Wire.write( 0x71 );    //  F

Numerius_Negidius
 
Posts: 4
Joined: Sun Jun 02, 2013 4:25 pm

Re: Help with I2C Control of 4-Digit 7-Segment Display w/I2C Backpack

Post by Numerius_Negidius »

OK, I got it now: Each write to a register (like the oscillator or the display enable) need to be prefaced with an own START condition :oops:

User avatar
christopher_guffey007
 
Posts: 3
Joined: Sun Feb 04, 2018 10:25 am

Re: Help with I2C Control of 4-Digit 7-Segment Display w/I2C

Post by christopher_guffey007 »

If you are rolling your own i2c libraries, send the HOLTEK setup commands between separate start/stop conditions. Sending them after another will not work -- the values don't take.

for PIC16F:

uint8_t display_setup[] = {0x21, 0xA0, 0xEF, 0x81};
for (k = 0; k < sizeof(display_setup); k++) {

SSP1CON2bits.SEN = 1; //send start
while(SSP1CON2bits.SEN); //wait for SEN to clear
PIR3bits.SSP1IF = 0; //reset SSP1 IF

SSP1BUF = HOLTEK_SLAVEADDRESS; //send I2C address
while(SSP1STATbits.BF); //wait for 8 bits to clock out
PIR3bits.SSP1IF = 0; //reset SSP1 IF

SSP1BUF = display_setup[k]; //
while(SSP1STATbits.BF); //wait for 8 bits to clock out
PIR3bits.SSP1IF = 0; //reset SSP1 IF

SSP1CON2bits.PEN = 1; //send stop
while(SSP1CON2bits.PEN); //wait for PEN to clear
PIR3bits.SSP1IF = 0; //reset SSP1 IF
}

Locked
Please be positive and constructive with your questions and comments.

Return to “Glowy things (LCD, LED, TFT, EL) purchased at Adafruit”