Jump to content
ryeg

Using I2c Functions With 16f877

Recommended Posts

I am attempting to use the I2C functions supplied with Boost C. I had thought that these functions were generalized across the PIC family, but now that I look into the i2c.driver.h file I find that they are specific to only two device types -- the 18F2xx and 18F4xx:

// Existing constants predefined for i2c hardware driver and i2s software

// emulation for the PIC 18F2xx and 18F4xx processors. For hardware support

// on other PICs the constants must be mapped to the corresponding register

// map of the target device

 

I am not very competent at PIC internals, but thought that maybe I could change the register addresses listed in the .lib code below -- until I got to the last ones (_pir) that don't appear to have analogs in the F877 register set. So I am at a loss as to where to go from here.

#define PORTC 0x0f82

#define TRISC 0x0f94

#define e_SSPCON1 0xfc6

#define e_SSPCON2 0xfc5

#define e_SSPSTAT 0xfc7

#define e_SSPADD 0xfc8

#define e_SSPBUF 0xfc9

#define e_SSPIF_PIR 0xf9e

#define e_BCLIF_PIR 0xfa1

#define e_SSPIF_BIT 3

#define e_BCLIF_BIT 3

Has anybody out there made the I2c functions work with the 16F877 and, if so, could you give me some pointers on how to get things working on my CPU.

 

I'm a little discouraged that these don't seem to work with common a PIC like the 16F877 and wonder how many of the the other functions in the manual are device specific?

 

Rye

Share this post


Link to post
Share on other sites
I am attempting to use the I2C functions supplied with Boost C. I had thought that these functions were generalized across the PIC family, but now that I look into the i2c.driver.h file I find that they are specific to only two device types -- the 18F2xx and 18F4xx:

// Existing constants predefined for i2c hardware driver and i2s software

// emulation for the PIC 18F2xx and 18F4xx processors. For hardware support

// on other PICs the constants must be mapped to the corresponding register

// map of the target device

 

I am not very competent at PIC internals, but thought that maybe I could change the register addresses listed in the .lib code below -- until I got to the last ones (_pir) that don't appear to have analogs in the F877 register set. So I am at a loss as to where to go from here.

#define PORTC 0x0f82

#define TRISC 0x0f94

#define e_SSPCON1 0xfc6

#define e_SSPCON2 0xfc5

#define e_SSPSTAT 0xfc7

#define e_SSPADD 0xfc8

#define e_SSPBUF 0xfc9

#define e_SSPIF_PIR 0xf9e

#define e_BCLIF_PIR 0xfa1

#define e_SSPIF_BIT 3

#define e_BCLIF_BIT 3

Has anybody out there made the I2c functions work with the 16F877 and, if so, could you give me some pointers on how to get things working on my CPU.

 

I'm a little discouraged that these don't seem to work with common a PIC like the 16F877 and wonder how many of the the other functions in the manual are device specific?

 

Rye

 

I think you misinterpreted what the driver is telling you. I have used this driver on 16F series PICs. The I2C driver was originally designed to emulate the hardware I2C found on a PIC18F series processor. From time to time Microchip improves the various peripherals found in the PICs. The reference to the 18F2xx and 18F4xx is intended to let the developer know that the emulation closely matches the I2C found in these devices. In this way a developer can reference the hardware peripheral information for the 18F series PICs listed to understand how to use the emulated I2C driver. There is nothing to stop you using this driver on 16F series PICs.

 

If you look at the e_xxx defines above, you will notice that e_SSPBUF corresponds to the SSPBUF register in the 18F series PIC. The e_ indicates the name of the register that is being emulated.

 

If your PIC has free memory at say 0x40 (typical for a 16F series) then you could start mapping these addresses. For example you could have...

 

#define e_SSPCON1 0x40

#define e_SSPCON2 0x41

#define e_SSPSTAT 0x42

#define e_SSPADD 0x43

#define e_SSPBUF 0x44

#define e_SSPIF_PIR 0x45

#define e_BCLIF_PIR 0x46

Share this post


Link to post
Share on other sites

I have the I2C driver working on a 16F887 chip (hardware I2C). In order to keep it neat and simple, I have made the following edits:

 

////////////////////////////////////////////////////////////////////////////
// i2c hardwareware implementation template arguments
////////////////////////////////////////////////////////////////////////////
#define i2c_ARGS	3, e_MSSP_PORT, e_MSSP_TRIS, 4, e_MSSP_PORT, e_MSSP_TRIS, e_SSPCON1, e_SSPCON2, \
				e_SSPSTAT, e_SSPBUF, e_SSPIF_BIT, e_SSPIF_PIR,			\
				e_BCLIF_BIT, e_BCLIF_PIR, 7, e_SSPADD, (i2c_reset_wdt | i2c_SMP |i2c_HW)

// variables cannot be passed as template arguments. The following constants map to
// the PIC registers and PIC's i2c register locations. These constants are
// then used by the templated functions. 
#define e_MSSP_PORT		PORTC
#define e_MSSP_TRIS		TRISC
#define e_SSPCON1		SSPCON
#define e_SSPCON2		SSPCON2
#define e_SSPSTAT		SSPSTAT
#define e_SSPADD		SSPADD
#define e_SSPBUF		SSPBUF
#define e_SSPIF_PIR	PIR1
#define e_BCLIF_PIR	PIR2
#define e_SSPIF_BIT	SSPIF
#define e_BCLIF_BIT	BCLIF

////////////////////////////////////////////////////////////////////////////
// I2C Device constants
////////////////////////////////////////////////////////////////////////////

// define External I2C slave (Hardware) addresses
#define	xds_slave	0xD0	// Base address of DS1307

Share this post


Link to post
Share on other sites

I have the I2C driver working on a 16F887 chip (hardware I2C). In order to keep it neat and simple, I have made the following edits:......

 

 

Howzit:

Thanks. I think that's what I need and will try it today. I guess that I was on the right track about changing the register defines, but didn't know that the i2c_ARGS needed to be changed -- and in fact, because of my limited skills, I don't really understand the magic in particular item. (it's back to the books on that one)

 

The defines seem to appear in both the i2c_test.c and the i2c_driver.h program so I changed them in both places -- is that a correct thing to do?

I really appreciate your help on this and hope I can return the favor someday.

 

Cheers

Rye

Share this post


Link to post
Share on other sites

You only need them once, in your code or .h file. To keep things generic and processor independant, I have commented them out in the i2c_driver.h file. It is a bit confusing - read the instructions in the i2c_driver.h, look for "#if defined use_i2c_SW" then the "#else" and the "#endif", copy what you require for HW or SW I2C to your code and comment the lot out as you will get compile time errors.

 

What device are you going to I2C?

Share this post


Link to post
Share on other sites
You only need them once, in your code or .h file. To keep things generic and processor independant, I have commented them out in the i2c_driver.h file. It is a bit confusing - read the instructions in the i2c_driver.h, look for "#if defined use_i2c_SW" then the "#else" and the "#endif", copy what you require for HW or SW I2C to your code and comment the lot out as you will get compile time errors.

 

What device are you going to I2C?

 

 

That was fast!!!! thanks. I think there is some sort psychic communications going on as I was just working thru that part of the .h file. The sample from SBoost is what I am using and it appears to have done that dirty work for me -- but didn't comment out the stuff in the .h file.

 

I am using a 24LC512.

 

Here's my code -- which is pretty much the modified sample.

 

 

#include <system.h>
#include "i2c_driver.h"  //I moved this to local so I can mess with it
#include <string.h>
#include "lcd.h"
#include <stdlib.h>


//configuration word
#pragma DATA _CONFIG, _PWRTE_OFF & _BODEN_OFF & _WDT_ON & _LVP_OFF & _CPD_OFF & _DEBUG_OFF & _HS_OSC & _CP_OFF
//Set clock frequency
#pragma CLOCK_FREQ	20000000


void interrupt( void )
{


	//Handle timer0 interrupt
	if( intcon & (1<<T0IF) )
	{
		clear_bit( intcon, T0IF ); //clear timer 0 interrupt bit
	}

	//Handle timer1 interrupt
	if( pir1 & (1<<TMR1IF) )
	{
		clear_bit( pir1, TMR1IF ); //clear timer 1 interrupt bit
	}

	//Handle timer2 interrupt
	if( pir1 & (1<<TMR2IF) )
	{
		clear_bit( pir1, TMR2IF ); //clear timer 2 interrupt bit
	}

}


////////////////////////////////////////////////////////////////////////////
// I2C Communications Test Program
//
// Exercises the i2c driver code in <i2c_driver.h> by demonstrating
// reading and writing to an External EEPROM
////////////////////////////////////////////////////////////////////////////
// Author(s): Andrew Smallridge
// Date 15 November 2004
//
// Copyright© 2004-2006 Andrew Smallridge
// Copyright© 2004-2007 Pavel Baranov
// Copyright© 2004-2007 David Hobday
////////////////////////////////////////////////////////////////////////////




////////////////////////////////////////////////////////////////////////////
// i2c master hardware / software mode definition
//
// For i2c hardware support comment out the #define use_ic2_SW line
////////////////////////////////////////////////////////////////////////////

/*
//#define use_i2c_SW
//
#if defined use_i2c_SW
////////////////////////////////////////////////////////////////////////////
// i2c software implementation template arguments
////////////////////////////////////////////////////////////////////////////
#define i2c_ARGS	3, PORTC, TRISC, 4, PORTC, TRISC, e_SSPCON1, e_SSPCON2, \
					e_SSPSTAT, e_SSPBUF, e_SSPIF_BIT, e_SSPIF_PIR,			\
					e_BCLIF_BIT, e_BCLIF_PIR, 7, e_SSPADD, (i2c_reset_wdt | i2c_SMP)




// RAM used by the software i2c driver to emulate the equivalent i2c hardware registers					
unsigned short swi2c_SSPCON1@0x40;	// define location for the emulated SSPCON1
unsigned short swi2c_SSPCON2@0x41;	// define location for the emulated SSPCON2
unsigned short swi2c_SSPSTAT@0x42;	// define location for the emulated SSPSTAT
unsigned short swi2c_SSPBUF@0x43;	// define location for the emulated SSPBUF
unsigned short swi2c_SSPIF_PIR@0x44;// define location for the emulated SSPIF_PIR
unsigned short swi2c_BCLIF_PIR@0x45;// define location for the emulated BCLIF_PIR
unsigned short swi2c_SSPADD@0x46;	// define location for the emulated SSPADD

// variables cannot be passed as template arguments. The following constants map to
// the PIC registers and software emalated i2c RAM locations. These constants are
// then used by the templated functions. When changing the address of an emulated
// register the corresponding constant mapping must also be changed.
#define e_SSPCON1	0x40
#define e_SSPCON2	0x41
#define e_SSPSTAT	0x42
#define e_SSPADD	0x43
#define e_SSPBUF	0x44
#define e_SSPIF_PIR	0x45
#define e_BCLIF_PIR	0x46
#define e_SSPIF_BIT	3
#define e_BCLIF_BIT	3					

#else
*/
/*
////////////////////////////////////////////////////////////////////////////
// i2c hardwareware implementation template arguments
////////////////////////////////////////////////////////////////////////////
#define i2c_ARGS	3, PORTC, TRISC, 4, PORTC, TRISC, e_SSPCON1, e_SSPCON2, \
					e_SSPSTAT, e_SSPBUF, e_SSPIF_BIT, e_SSPIF_PIR,			\
					e_BCLIF_BIT, e_BCLIF_PIR, 7, e_SSPADD, (i2c_reset_wdt | i2c_SMP |i2c_HW)

			// variables cannot be passed as template arguments. The following constants map to
			// the PIC registers and PIC's i2c register locations. These constants are
			// then used by the templated functions. 


			//#define PORTC		0x0f82 illegal redef -- they are also in i2c_driver.g
			//#define TRISC		0x0f94 illegal redef
			#define e_SSPCON1	0xfc6
			#define e_SSPCON2	0xfc5
			#define e_SSPSTAT	0xfc7
			#define e_SSPADD	0xfc8
			#define e_SSPBUF	0xfc9
			#define e_SSPIF_PIR	0xf9e
			#define e_BCLIF_PIR	0xfa1
			#define e_SSPIF_BIT	3
			#define e_BCLIF_BIT	3

*/	

//changes from RSABear 10/1/07		
////////////////////////////////////////////////////////////////////////////
// i2c hardwareware implementation template arguments
////////////////////////////////////////////////////////////////////////////
#define i2c_ARGS	3, e_MSSP_PORT, e_MSSP_TRIS, 4, e_MSSP_PORT, e_MSSP_TRIS, e_SSPCON1, e_SSPCON2, \
				 e_SSPSTAT, e_SSPBUF, e_SSPIF_BIT, e_SSPIF_PIR,			\
				 e_BCLIF_BIT, e_BCLIF_PIR, 7, e_SSPADD, (i2c_reset_wdt | i2c_SMP |i2c_HW)

// variables cannot be passed as template arguments. The following constants map to
// the PIC registers and PIC's i2c register locations. These constants are
// then used by the templated functions.
#define e_MSSP_PORT	  PORTC
#define e_MSSP_TRIS	  TRISC
#define e_SSPCON1		SSPCON
#define e_SSPCON2		SSPCON2
#define e_SSPSTAT		SSPSTAT
#define e_SSPADD		SSPADD
#define e_SSPBUF		SSPBUF
#define e_SSPIF_PIR	PIR1
#define e_BCLIF_PIR	PIR2
#define e_SSPIF_BIT	SSPIF
#define e_BCLIF_BIT	BCLIF

			//#endif


			////////////////////////////////////////////////////////////////////////////
			// TEST CODE - I2C Device constants
			////////////////////////////////////////////////////////////////////////////

				// define External EEPROM I2C slave (Hardware) addresses
			#define	xee_slave	0xA0	// Base address of 24C512 EEPROM



			////////////////////////////////////////////////////////////////////////////
			// Read from the External EEPROM
			////////////////////////////////////////////////////////////////////////////
			// s is a pointer to the destination buffer to data read from the EEPROM
			// HW_address is the hardware address of the i2c device
			// ic2_addr is the target internal address within the External EEPROM
			// count is the number of bytes to be read starting at i2c_addr
			void read_XEE(char *s, char HW_address, unsigned short i2c_addr, unsigned short count)
			{
				short i;

				i2c_start();
				i2c_write(HW_address); // send XEE i2c address	
				i2c_write(i2c_addr >> 8); // send XEE internal HIGH address
				i2c_write((char) i2c_addr & 0x00ff); // send XEE internal LOW address
				i2c_restart(); // send i2c_restart

				// sending XEE read command via i2c_write
				i2c_write(HW_address | 0x01); // send device address + RD to I2C device

				// XEE read loop
				for (i=0;i<count-1;i++)
					*s++ = i2c_read(0);
				*s++ = i2c_read(1);
				*s = 0;

				i2c_stop();																								
			}

			////////////////////////////////////////////////////////////////////////////
			// Write to the External EEPROM
			////////////////////////////////////////////////////////////////////////////
			// s is a pointer to the string to be written to the EEPROM
			// HW_address is the hardware address of the i2c device
			// ic2_addr is the target internal address within the External EEPROM
			// count is the number of bytes to be written starting at i2c_addr
			void write_XEE(char *s, char HW_address, unsigned short i2c_addr, unsigned short count)
			{
				short i;

				i2c_start();
				i2c_write(HW_address); // send XEE i2c address					
				i2c_write(i2c_addr >> 8); // send XEE internal HIGH address
				i2c_write((char) i2c_addr & 0x00ff); // send XEE internal LOW address

				// XEE write loop
				for (i=0;i<count;i++)
					i2c_write(*s++);
				i2c_stop();																							
			}

void main()
{
	char buffer[32];
	char *mesg = "i2c Test String";
	char *s1;
	char i;
	unsigned short i2c_addr; 	// used for internal addressing for the target I2C device

	lcd_init();
	delay_ms(200);


	lcd_send_cmd( LINE1 );
	lcd_printf("ready");

	#define	I2C_divisor	0x7E
//	#define	I2C_divisor	0xFF


	// set the divisor for the I2C clock
	// for software I2C emulation this can be any value (such as 1)
	i2c_init(I2C_divisor); 

	lcd_send_cmd( LINE1 );
	lcd_printf("init complete  ");
	delay_s(1);

	// demonstrating a write to address 0x0210 in External EEPROM
	i2c_addr = 0x0210;
	write_XEE(mesg, xee_slave, i2c_addr, strlen(mesg)+1);
	i2c_init(I2C_divisor); 

	lcd_send_cmd( LINE1 );
	lcd_printf("write complete  ");
	delay_s(1);

	// The External EEPROM requires a delay to finish
	// programming the flash before it can be accessed again
	delay_ms(10);

	// demonstrating a read 16 bytes from address 0x0214 in External EEPROM		
	i2c_addr = 0x0214;
	s1 = buffer; // point s1 to the work buffer
	read_XEE(s1, xee_slave, i2c_addr, 16);

	lcd_send_cmd( LINE1 );
	lcd_printf("buffer read complete");
	lcd_send_cmd( LINE1 );
	for(i=0; i<12;i++)
		lcd_printf(s1[i]);

	while (1);

}

Share this post


Link to post
Share on other sites
I found the Modtronix demo code a good start for I2C and other coding - I was using their SBC44B board which has 16F877 MPU

 

http://forum.modtronix.com/index.php?topic=321.0

 

That's nice code. Far easier to read than the boostc 'all things to all people' example. I think that examples, buy their very nature, should be easy to read and not a demonstration of clever multipurpose code using estoeric mechanisms. Simple is good.

 

Thanks for the lead.

 

Rye

Share this post


Link to post
Share on other sites
I found the Modtronix demo code a good start for I2C and other coding - I was using their SBC44B board which has 16F877 MPU

 

http://forum.modtronix.com/index.php?topic=321.0

 

That's nice code. Far easier to read than the boostc 'all things to all people' example. I think that examples, buy their very nature, should be easy to read and not a demonstration of clever multipurpose code using estoeric mechanisms. Simple is good.

 

Thanks for the lead.

 

Rye

 

Pleased to help - i have posted on the Modtronix forum library code to drive their I2C Display board too.

 

Ted

Share this post


Link to post
Share on other sites

Hi Rye. I keep getting my reply to your e-mail bounced. Here it is:

 

Hi Rye.

 

I haven't made any progress since June. This project has quite a few

areas that need attention and I'm afraid that the I2C problem has been

put to the back of the queue. I have finished the PIC processor board

and 90% of the software is now running. The RF board is now complete

and tested and so is the multi-port I/O board. I am just finishing the

audio section this weekend. The next job will be the metalwork. I2C is

a longer term goal to give me 2 additional hardware serial ports and a

few more I/O ports from a couple of slave 876s (the main processor is

the 18F4525). I don't need I2C to get the basic system working.

 

Like you I am not a professional programmer and rely on help from the

web or the forum to get me out of a hole when I am stuck. If I make any

progress or find any useful sites I'll let you know. There seem to be

quite a few people with the same slave problems. Its a pity that

Microchip don't post more examples of slave operation using I2C.

 

Best wishes,

 

Danny

Share this post


Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...