Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

i2c issues

Status
Not open for further replies.

TucsonDon

Member
I am having issues with the i2c protocol that I hope someone can help with. I am using a PIC18F46K22 as a master. I am also using MCC for the code and have attached copies of the files that it generated and a shot of my logic analyzer that shows the output. That output is for a lcd display (address 0x50) which if I read it right it is acknowledging the address but that is it, no data transfer and nothing on the display. I also have tried MCU-MCU (master to slave) with the same result.


I have tried to step through the code in MPLab over and over but I am unable to identify the problem

C:
uint8_t data;
uint8_t addr;
/******************************************************************************/
static void display_write (uint8_t addr, uint8_t data);
static uint16_t temp_read (uint8_t addr);
/******************************************************************************/
static void display_write (uint8_t addr, uint8_t data)
{
    i2c_write1ByteRegister(LCD, addr, data);
    __delay_ms(5);
}

static uint16_t temp_read (uint8_t addr)
{
    return i2c_read2ByteRegister (TEMP, addr);
}
/*****DISPLAY COMMANDS*********************************************************/
void display_Initialize (void)
{
    display_write (Display_on, NULL);
    display_write (Clear_screen, NULL);
    display_write (Cursor_home, NULL);
}
void display_add (ddadr)
{
    display_write (Set_cursor, ddadr);
}
void clear_display (void)
{
    display_write (Clear_screen, NULL);
}
void putsLCD (char *buffer)
{
    while(*buffer)                  // Write data to LCD up to null
    {
        display_write (NULL, *buffer); // Write character to LCD
        buffer++;               // Increment buffer
    }
    return;
}

/*****TEMPERATURE**************************************************************/
i2c_temp Get_Temp (void)
{
    RawTemp.RawPool = temp_read (Pool);
    RawTemp.RawSolar = temp_read (Solar);
    RawTemp.RawWater = temp_read (Water);
}

header file
C:
#ifndef I2C_LCD_H
#define I2C_LCD_H
#include "temp.h"
#define LCD         0x50                    //LCD I2C Address
/************LCD Display Commands*************************************************/
#define Display_on          0x41            //turns the display on
#define Display_off         0x42            //turn the display off
#define Set_cursor          0x45            //move to address
#define Cursor_home         0x46            //moves to address 0,0
#define Underline_on        0x47            //turns underline cursor on
#define Underline_off       0x48            //turns underline cursor off
#define Cursor_left         0x49            //shifts cursor left one space
#define Cursor_right        0x4A            //shifts cursor righr one space
#define Blink_on            0x4B            //turns on blinking cursor
#define Blink_off           0x4C            //turns off blinking cursor
#define Backspace           0x4E            //moves cursor back one space
#define Clear_screen        0x51            //clears the screen
#define Set_contrast        0x52            //sets screen contrast (1-50)
#define Set_brightness      0x53            //sets screen brightness (1-8)
#define Load_character      0x54            //loads custom character
#define Display_left        0x55            //shifts display left one space
#define Display_right       0x56            //shifts display right onr space
#define Change_addr         0x62            //changes display i2c address
#define Display_firmware    0x70            //displays firmware ver
#define Display_addr        0x72            //displays i2c address

/*****FUNCTION PROTOTYPE*******************************************************/
void display_Initialize (void);
void clear_display (void);
void putsLCD (char *buffer);
i2c_temp Get_Temp (void);
void display_add ();
#ifdef __cplusplus
extern "C" {
#endif


#ifdef __cplusplus
}
#endif
#endif /* I2C_LCD_H */
 

Attachments

  • i2c display.pdf
    182.7 KB · Views: 200
  • i2c_master.c
    12.8 KB · Views: 189
  • i2c_simple_master.c
    5.4 KB · Views: 256
  • i2c_types.c
    1.5 KB · Views: 177
  • i2c1_driver.c
    5.9 KB · Views: 194
Last edited:
First thing to check... Most of these I2C backpacks are just a serial to parallel register... You still need to fully initialise the display.

First read the IC on the back pack Tell me what it is..And I'll show you what to do...
 
Ian Rogers ,I assume you are asking about the chip on the display. The display is Newhaven Display NHD-0420D3Z-NSW-BBW-V3 that uses a Microchip PIC16F690.

As I stated in an other thread (ADC Channel) I am also trying to transfer the adc result from one MCU(slave) to another(master) and appear to have the same issue and the question that I had with that was is the read/write flag set by hardware or software? Again as I step through the code it doesn't appear that the slave is going to Tx with the read slave address.
 

Attachments

  • test.pdf
    114.2 KB · Views: 213
No I didn't, I misunderstood the use, so having said that what is the correct syntax to send a command to the display?
I just had one of those "light bulb" moments. 0xFE is the register address and the command is the data that is written to that address.
 
Last edited:
I must admit... I can't find a decent piece of code... The only code I have found is written in an Object pascal type syntax.

But they write.... Address, command, data... The same as you are doing BUT!! The command is weird

I think you send addr then the 0xFE then the command, then any other bytes....
Looky here.. https://www.newhavendisplay.com/NHD_forum/index.php/topic,8844.0.html
 
I'm not sure that will help and I cannot say that I read everything in your posts and the attachments. So, with that qualification, I would offer the following:

Try this in main (and assuming status is declared and you are the pins with IC1 and pullups and anything else that is careless on my part):

uint8_t cmdS[]={0xfe, 0x45, 0x00, 0x30}

I2C1_MasterWrite(cmdS, 4, 0x50, &status);
while(status == I2C1_MESSAGE_PENDING);

If "A" appears on the screen, I would say that you need to abandon byte writing and write a sequence of bytes characters and then a STOP.

Again, sorry if I am wrong, just trying to help.
 
Is there an update on this?

I am curious because I was looking at this display and it has some real nice capabilities. That is, having a switch selectable I2C, SPI or TTL RS-232 on one display interests me. I see a couple of caveats though.

First, I should explain my previous comment. I have recently ported some LCD functions to a PIC and used mcc for the first time. The port was to an LCD that uses a ST7032 controller. As I remember, I gave up on byte transfers because (as far as I could tell) a stop was issued after the byte send and it messed up the command/memory sequences. I ended up using byte arrays using the function as in my post. I don’t know if that is required in this case.
Your display https://www.newhavendisplay.com/nhd0420d3znswbbwv3-p-5745.html uses a ST7066U but, as you already know, also a PIC16F690.

Points that you might find interesting if you don’t already know…

1) A 100 ms (milliseconds) delay on power up is required from data here https://www.newhavendisplay.com/specs/NHD-0420D3Z-NSW-BBW-V3.pdf.

2) The display apparently drops characters at 100 kHz I2C and it is recommended that you use 50 kHz. No provision for 400 kHz. Newhaven seems to admit this outright https://www.newhavendisplay.com/NHD_forum/index.php/topic,8660.0.html. This is a big negative for me.

There is some Arduino UNO code that the user said works here https://www.newhavendisplay.com/NHD_forum/index.php/topic,8844.0.html Note that in the example, data are queues and then sent sequentially before a stop (I think).

The code here https://www.newhavendisplay.com/app_notes/Serial_LCD.txt appears to be a PIC tester program although I can’t find tester_init.h

Hope this helps.
 
DrG no update still working on some bugs in my code but thanks for asking. I did figure out that that I was having an i2c address issue as the code was shifting left by 1 so the display address of 0x50 was sent out as 0xA0 but haven't tried it out yet. As for the clock speed I am using i2c over a distance (~60') so I can't run any faster then 100kHz.
 
2) The display apparently drops characters at 100 kHz I2C and it is recommended that you use 50 kHz. No provision for 400 kHz. Newhaven seems to admit this outright https://www.newhavendisplay.com/NHD_forum/index.php/topic,8660.0.html. This is a big negative for me.

As the displays are so slow anyway, it's not really much of a concern - you can still write to it far faster than the display can update.

I had similar concerns about the I2C 'back packs' using the simple 'bit banging' technique, I then tested them with multiple displays, one via normal 4 bit mode, and three via I2C back packs - there was no visible speed difference in any of the cases. As always, the limit is how fast the display can update, and either type easily updates fast enough to make the slow changing display a meaningless blur.
 
As the displays are so slow anyway, it's not really much of a concern - you can still write to it far faster than the display can update.

I had similar concerns about the I2C 'back packs' using the simple 'bit banging' technique, I then tested them with multiple displays, one via normal 4 bit mode, and three via I2C back packs - there was no visible speed difference in any of the cases. As always, the limit is how fast the display can update, and either type easily updates fast enough to make the slow changing display a meaningless blur.

If I understand you, I think you are right. That is, you are noting the rise and fall times for an element on the display. I was looking at some data sheets today and, yes, for those kinds of units, 100-140 ms (milliseconds) one way is not unusual. So, if you are changing an element while it is in the processes of being changed, it is going to be a blur. That is with reference to the display, not the controller or the interface to the controller. Is that what you mean, or am I missing your point?

I also noted that TFT displays are faster – maybe 50 ms. But, OLED displays are along the order of 10 microseconds each way.

In any event, and by way of rationalizing, my noting it as a big negative I think was more a reference to difficulties I have had trying to mix I2C speed for different devices. For example I had a Newhaven display that wanted a 10K pull up and was limited to 100 kHz. I could not get an EEPROM to work at even 400 kHz (which wanted a 2K pullup). So, my thinking was…50 kHz?? What about anything else on the bus? Now, I may have just been doing something wrong…but I remember that.

I have also had some difficulty with some boards changing I2C speeds. Arduino was easy and I remember an AM/FM/SW chip that during a power up/reset could only communicate at 10 kHz and once complete could only use 50 kHz. On a D2000 board, I could never seem to reinitialize the I2C to a different speed. I don’t know if using mcc lets you have different profiles like with SPI. I’m sure it could be done more directly.
 
I also noted that TFT displays are faster – maybe 50 ms. But, OLED displays are along the order of 10 microseconds each way.

The problem isn't really the speed, but the amount of data required - OLED aren't too bad, as they are mostly monochrome, but colour TFT's need huge amounts of data transferring - which is why you don't tend to get I2C versions, only SPI (and that's fairly slow).
 
I have made progress, the biggest issue I was having was timing. DrG you pointed out the power up delay that I had missed, once I corrected that and the other execution timing a lot of the problems I was having stopped and still @ 100kHz. Right now the issue that I am having is when I send a string to the display I am getting odd charters in between them.

DrG, Ian Rogers, and Nigel Goodwin thanks for your input
 
I have made progress, the biggest issue I was having was timing. DrG you pointed out the power up delay that I had missed, once I corrected that and the other execution timing a lot of the problems I was having stopped and still @ 100kHz. Right now the issue that I am having is when I send a string to the display I am getting odd charters in between them.

DrG, Ian Rogers, and Nigel Goodwin thanks for your input

Good deal and it does sound like you are close. The "garbage" you mentioned immediately makes me think about noise interference. Do you have 10K pullups as Newhaven wants (I would have used something smaller, but they should know -right)?

Also, and maybe more important, if I remember correctly, you were going a relatively long distance. If you cut the distance to 6 inches, for example, do you still get the garbage?
 
DrG the display comes with 10kΩ resistors installed. The display is 6" from the MCU, the distance is MCU-MCU.
 
The display that I was using was an 8 bit display and was using the sprintf function to convert the text, so is it possible that is what is creating the "garbage" in the display? In reading the data sheet (see attached) is says to "enter the ASCII number" and isn't that what the compiler does?
 

Attachments

  • data sheet.pdf
    58.5 KB · Views: 198
The display that I was using was an 8 bit display and was using the sprintf function to convert the text, so is it possible that is what is creating the "garbage" in the display? In reading the data sheet (see attached) is says to "enter the ASCII number" and isn't that what the compiler does?

I'm not sure I am understanding you. Page 14 of the datasheet for the display https://www.newhavendisplay.com/specs/NHD-0420D3Z-NSW-BBW-V3.pdf
tells you what the display will show when you send it different bytes.

It seems like what you are saying is that you are getting repeatable garbage characters mixed with the characters you are intending to display.
If that is correct, it may have nothing to with noise but may mean that the display is working just fine.

Can you give an example code fragment that gives you the same garbage out?
 
Can you set a breakpoint so you can see what is in the sprintf buffer prior to sending?

Mike.
 
I was able to figure out that when I sent a command that the function was inverting the command and data i.e. for contrast it was sending the setting then the register.

The issue now is sending characters, the function (putsLCD (char *buffer)) that I have uses a char pointer and the function that MCC generated (i2c_writeNBytes(address, void *data, size_t len)) uses a void pointer. So the question is how do I go from a char pointer to a void pointer, beyond just typecasting?
 

Attachments

  • i2c.c
    2.7 KB · Views: 180
  • i2c_simple_master.c
    5.4 KB · Views: 276
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top