I2C waveform Strange

Go To Last Post
24 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi
I Have been working on a project to control a I2C LCD & for the most part it seems to working fine. I am having some trouble reading the busy flag but it may still be a code issue.
The thing i was surprised to see was I2C waveform with its spikes & not returning to ground fully in some cases. Has anyone had this issue?

Device: ATmega328P
Using: Peter Fleury's library with my code.
Pull up Resistors: 4.7k & tried other values.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What is the problem?
Your trace shows 5us per division.
The bit width looks about 15us i.e. 67kHz bus frequency.
You are probably using 3.3V logic.

If anything, I would expect a slower rise time.
Are you using the TWI hardware?

There is absolutely no point in reading the Busy flag.
You need at least 5 I2C writes for any LCD operation. e.g. 450us @ 100kHz bus.

So you might just as well force a 2ms delay for HOME and CLRHOME. All other operations complete in less than 50us. (typical 37us)

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Frequency is 100khz.
Its running at 3.3volts.

Yes its using TWI hardware.

Ah ok i was wondering why anybody else's code was looking at wasn't looking at the busy flag. Now that you have jogged my memory i remember in a old 8bit display waiting for the port bit to go low to check for busy. So from what you say the bus speed isnt fast enough & by the time you check the busy flag its already done. Still i have noticed i have to insert a delay or i miss the first character.

But the problem i was more talking about was the uglyness of the waveform. Personally i wouldn't trust a waveform to give accurate data if it looked like that. Seems to work though!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, I would connect a regular analog scope with a good x10 probe. I bet that the trace would look nicer.

The TWI has slew-rate hardware. I presume that the PCF8574 has too.

What is your 'missing' first character. You still need some delays in the lcd_init() function.

I posted a "lcd_i2cmaster.c" file a couple of days ago.

Please try it. The OP of that thread has not come back to me with his experience yet.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ill see if can get my old analog scope going but it was rubbish last time i used it.

I found the reason for the missing character & it was not enough delay after a screen clear.

Line two characters don't show even though the you can see the cursor move the amount of positions it should be to fit in the characters. My bets are a code issue somewhere but everything seems enabled.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Watching the I2C bus with a scope is not too arduous. It is only running at 100kHz or so. So a 10MHz Analog scope will show a pretty good enough trace.

The critical thing with any scope is the correct probe and the correct test point.

It is only HOME and CLRHOME that take a significant time. I allow 2ms to be on the safe side. If you poll the Busy flag, you might save yourself some time.

If your second line does not display, your initialisation was wrong.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just for someone else reading this post in future it looks like you cant read the busy flag with the I2C interface anyway because i found this stuffed away in the datasheet

Quote:

I2C interface:
It just only could write Data or Instruction to ST7032 by the IIC Interface.
It could not read Data or Instruction from ST7032 (except Acknowledge signal).

Still cant write to second line but im working on it.

LCD is:
Midas MCCOG21605B6W-SPTLYI
It uses the ST7032i

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ah-ha. I rather assumed you were using the I2C adapters that fit on the back of regular 16x2 modules. They just use a PCF8574 I2C chip to drive the "HD44780 module" pins.

The ST7032 will have a native I2C protocol. So you don't need 5 bytes to send one command.

You will still have every command or data execute faster (26.3us) than the I2C bus. Except for CLRHOME and HOME (1080us).

I can't see any great need for testing BUSY flag.

David.

p.s. the I2C can run at 400kHz. So the data could be sent at full speed (22.5us) per byte if the internal oscillator is 'typical 540kHz' (18.5us)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah it would be good if i had one of those lying around but i have this... Darn.

Sorry i forgot to include more information at the start.

Yep there is no point in looking at the busy flag as we agreed earlier. I was just making the point that it's impossible too haha.

Still working on line two! (dumb display) or me. :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In looking at the waveform, there are signs of contention. That happens when two pins are fighting each other to drive signal. I would look for a short on control pins, improper use of R/W, or a pin not propery set for data direction.

It all starts with a mental vision.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

KitCarlson
Yes i would agree. It tries to pull the 3.3v rail to ground but it cant because "the device" impedance isn't low enough. Therefore you get that small step you are talking about. You can even see the load being released by "the device" as it shoots up briefly at the end of the step.
I have tried this IC on another Atmel chip using the same code but same scenario, i think it might be a rubbish display.

I have also noted that this strange effect is at a consistent frequency 9.62K, 103.9us & will interrupt the data (See waveform). I'm beginning to think that this LCD is faulty. I have had a good look over the connections.

Attachment(s): 

Last Edited: Sat. Jun 7, 2014 - 01:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can see that the AVR Master is sinking SDA to 0.0V and the Slave's ACK is sinking to 0.3V. i.e. a perfectly respectable low state.

I can see <P><P><S><0x7D><0xFF>

In other words, you are attempting to use an illegal "SLAVE_R" (0x7D) address. As far as I can see, the data sheet says only the "SLAVE_W" (0x7C) address is valid.

OTOH, I would certainly investigate the I2C "read" behaviour.

The brief +ve pulse in between the two <P> Stop operations is perfectly normal.

I have not got a ST7032 display to try.
It looks very straightforward.

Perhaps you could post your lcd_init(), lcd_command() and lcd_data() functions.

First off, we could get your LCD displaying properly.
Then we could look at the scope trace again.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I can see

<0x7D><0xFF>


The above was when i was reading the busy flag so don't really trust that. I can do a simple print like (Start "H" Stop) & post the picture here if you want.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No, I would prefer to see the software:
lcd_init(), lcd_command() and lcd_data() functions.

Since you are using Fleury, there is no need to post anything other than those functions.

But you can post a scope trace if you like.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok Here is both. Sorry to be such a pain.

This writes DATA to the screen.

Device+RW RS Data
Start 01111100 A 01000000 A 01001000 A Stop

In the above i have just written a single H to the screen & the screen displays it

RS is the 6th bit

A Command is the same but RS is LOW.


#include <avr/io.h>
#define F_CPU 8000000UL
#include "twimaster.h"
#include <util/delay.h>
#define DevLCD 0b01111100 // Device address of LCD
/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_READ 1
/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_WRITE 0

/*************************************************************************
Writes a Command to the Midas MCCOG21605B6W-SPTLYI LCD display

Input: Command byte.

Return:

*************************************************************************/
void LCD_Command_Write(uint8_t Cmd)
{
unsigned char ret;

ret = i2c_start(DevLCD+I2C_WRITE); // Set device address and write mode

if ( ret )
{
/* failed to issue start condition, possibly no device found */
i2c_stop();
}
else
{
// issuing start condition ok, device accessible
i2c_write(0b00000000); // Write RS low & Co low for Command
i2c_write(Cmd); // Write one byte
i2c_stop();
}
}

/*************************************************************************
Shifts the cursor of the Midas MCCOG21605B6W-SPTLYI LCD display

Display layout: (hex)
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F

Input: Position to move the cursor to

Return:

*************************************************************************/
void LCD_Shift_Cursor(unsigned char Position)
{
LCD_Command_Write(Position);
}

void LCD_Init(int ContrastVoltage)
{
//Screen I2C address is 0111110

_delay_ms(40); //Delay 40mS for startup

unsigned char ret;

ret = i2c_start(DevLCD+I2C_WRITE); // set device address and write mode

if ( ret )
{
/* failed to issue start condition, possibly no device found */
i2c_stop();
}
else
{
i2c_write(0b00000000); //Co = 1 to say another control byte will follow
// issuing start condition ok, device accessible
i2c_write(0b00111000); //Function Set 0x38H 0b00111000. 8bit, Two lines, Single height font, instruction set normal.
_delay_us(30); //Delay 26.3uS in manual but i gave it 30us
i2c_write(0b00111001); //Function Set 0x39H 0b00111001. 8bit, Two lines, Single height font, Instruction set Extension.
_delay_us(30);
//With the Extension instruction set selected (as above) i can now adjust the Internal OSC frequency below
i2c_write(0b00010111); //Internal oscillator frequency 0x17H 0b00010111. Oscillator to 347Hz (fastest)
_delay_us(30);
//A contrast difference between 3v & 5v as in manual
if (ContrastVoltage) //1 = 5volts
{
i2c_write(0b01111001); //Contrast set 0x79H 0b01111001
_delay_us(30);
i2c_write(0b01010000); //0x50H 0b01010000 Icon on, Booster off, Contrast set
}
else
{
i2c_write(0b01110100); //Contrast set 0x74H 0b01110100
_delay_us(30);
i2c_write(0b01010100); //0x54H 0b01010100. Icon off, Booster on, Contrast set
}
_delay_us(30);
i2c_write(0b01101111); //Follower control 0x6FH 0b01101111
_delay_ms(200); //Delay 200mS For power stable
i2c_write(0b00001111); //Display On/Off- 0x0F 0b00001111. Entire display on, cursor on, cursor position on.
_delay_us(30);
//End of LCD Initialization Sequence.
i2c_write(0b00000001); //Clear Display 0x01H 0b00000001
i2c_stop();
//Delay for Clear Display
_delay_ms(1);
}
}

/*************************************************************************
Writes a string or char to the Midas MCCOG21605B6W-SPTLYI LCD display

Input: String. "Hello World!"

Return:

*************************************************************************/
void LCD_Write_String(const char* dstring)
{
while(*dstring) //Is the character pointed at by dstring a zero? If not, write character to LCD
{
unsigned char ret;

ret = i2c_start(DevLCD+I2C_WRITE); // Set device address and write mode

if ( ret )
{
//Escape 2:
/* failed to issue start condition, possibly no device found */
i2c_stop();
//Stop "while(*dstring)" from continuing looping if no device is there
break;
}
else
{

i2c_write(0b01000000); //Tell the LCD i want to write text/data (Set RS High, 6th bit)
i2c_write(*dstring++); //Write the character from dstring to the LCD, then post-inc the dstring is pointing at.
i2c_stop();
}
}
}

int main(void)
{
i2c_init(); //Initialize I2C
LCD_Init(0); //Initialize LCD

LCD_Write_String("H");

while(1)
{
//TODO:: Please write your application code
}
}

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I use the D6W variant in a commercial product. 5v rail, 4k7 pull-ups on a tiny4313.

I've just had a quick look at the unit on the bench and see the same 500mV 'hump'.

My code is written in CVAVR but if it helps I'll post my routines. And I don't use the busy flag.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your init() looks fine to me. i.e. it follows the data sheet.
However, I would definitely use a 2ms delay after CLRHOME command.

Personally, I would just copy the 8051 example serial initialisation. Each WRINS_NOCHK() has a 1500us delay. So the DELAY30uS() calls are pointless.
OTOH, the data sheet example code omits the <S><0x7C><0x00> and the <P>

Your LCD_Write_String() could simply send all the data consecutively. e.g.

<S><0x7C><0x40><"Hello World"><P>

But your major problem is the initialisation.

I still maintain that your Slave ACK is perfectly valid. So what if it is 0.3V or 0.5V or 0.0V.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian:
Wow yours does it too! So it seems as though its part of the displays average design. If you have a initialization & how you write to the second line then that would be good as a reference. If its too much don't worry as i will keep plugging away at it.

David:
Yes im probably going write all the data in a string as it will save a bit of time etc. Just wanted a basic test for now.
Ill work on what you have said.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

HTH...


const char Slave = 0x7C;
const char Comsend = 0x00;
const char Datasend = 0x40;
const char CLEAR = 0x01;
const char HOME = 0x02;
const char LINE1 = 0x80;
const char LINE2 = 0xC0;


void lcd_init (void)
{

i2c_start();
delay_ms(2);
i2c_stop();
delay_ms(2);

i2c_start();

i2c_write(0x7C);
i2c_write(0x00);

i2c_write(0x38);
delay_ms(10);

i2c_write(0x39);
delay_ms(10);

i2c_write(0x14);

//midas 5v
i2c_write(0x79);
i2c_write(0x50);
i2c_write(0x6c);
delay_ms(200);

i2c_write(0x0C);
i2c_write(0x01);
i2c_write(0x06);
delay_ms(10);

i2c_stop();

delay_ms(10);
}


void lcd_line1(void)
{

i2c_start();
i2c_write(Slave);
i2c_write(Comsend);
i2c_write(LINE1);
i2c_stop();

g_cpos = 0;

delay_us(20);

}

void lcd_line2(void)
{

i2c_start();
i2c_write(Slave);
i2c_write(Comsend);
i2c_write(LINE2);
i2c_stop();

g_cpos = 16;

delay_us(20);

}

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@Brian,

Your initialisation is much the same as Warren's.
You appear to have some extra 10ms delays.

Looking at EastRising 8051 example code, they don't use delays. However, they use <0x80><cmd><0x80><cmd><0x80><cmd>...

And since they bit-bang the I2C, it won't have a very fast bus speed. The <0x80> byte will be 90us @ 100kHz. The EastRising example with a 12MHz 89S52 might manage about 80kHz.

I note that you don't delay after your CLRHOME. This would really upset most controllers.

Please could you try your display without the 10ms and with a 2ms after CLRHOME.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok i have figured out what is wrong with line two not working!
It seems i have been writing to the wrong address (For line one & line two). There seems to be something extra im missing or the datasheet was wrong. (Probably me!)
The bottom screen layout works good.

Thanks Brian your code helped me!!

Display layout: (hex)

What the datasheet says
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F

What appears to be correct
80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CD CC CD CE

Does anyone have an idea why that is?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok i have got it sorry.

The instruction address for DDRAM is 10000000.
The position for the cursor is written in that instruction. e.g.

For the start of each line

(instruction) (position)
First line 0b10000000 + 0b00000000 = 0b10000000 (0x80)
Second line 0b10000000 + 0b01000000 = 0b11000000 (0xC0)

E.g.
This will write H at the start of the first line
Start 0x80 "H" Stop

This will write E to the start of the second line
Start 0xC0 "E" Stop

I was lucky for line one to work due to the initialization put the cursor in the right spot.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Those waveforms are normal for I2C.

I2C doesn't work on logic levels exactly like other digital circuits. It works by 'asserting' and 'releasing' the SCL and SDA lines. As long as the SDA line is at a stable logic level at the instant that the SCL line is released, it will transfer data.

If the values of the I2C pull-up resistors are too high, then you can see curves (that have been created by RC time constants) when either of the lines is released.

When signals are fast enough, all electronics is analog.

There is no such thing as DC operation of an electronic device, because eventually every device is switched off.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What the datasheet says:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F

What appears to be correct:
80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CD CC CD CE

The LCD command is in two parts. The first part is the command itself which is the highest value logic high bit in the byte. The second part is the data for the LCD's command. In this case, the command is bit 7 (the most-significant-bit of the byte) being at logic high and the data bits are the other lower seven bits. This allows a command and some limited range of data to be transferred when the RegisterSelect line is at command-mode logic level instead of data-mode logic level. The command is the first logic high bit and the data is the lower bits. There can only be seven or so basic commands with this system and some commands can only have a few data values.

For character selection, bit 7 is set and there are 128 address locations in the LCD display possible that can accept characters for display. For another command, bit 4 would be the first logic high bit (coming from the left) found in the byte. In this case, only 16 values are possible for data (bits 3-0).

The data sheet is showing the internal Display DRAM address value and assuming that you know that bit 7 is set. The bottom set is showing the same data with bit 7 actually set, which is what the LCD module actually gets on its data pins.