PIC24E I2C communication with MCP4725

Using I2C Library

From a theoretical viewpoint, the I2C protocol is defined as a synchronized serial communication with specific timing requirements for the two digital signals: clock and data. A good explanation is available from many sources, including Microchip datasheets and FRM. For programming sake, one only needs to know how to configure and read/write to particular registers to make the hardware work. With such knowledge, you can write your own library, but a better option is to use one that is readily available. Accompanied with [1] is a software package called pic24 library collection. Download the zip file and extract to a directory. Along with many useful stuff, you’ll find the I2C library in /lib/src. Examples are provided in /chap10. Consult the book [1] for more detail.

Because of copyright concern, I will not provide the source code of that library here. I just cut and paste the following functions from i2c.c

#ifndef I2C_ACK
# define I2C_ACK 0
#ifndef I2C_NAK
# define I2C_NAK 1

#define I2C_WADDR(x) (x & 0xFE) //clear R/W bit of I2C addr
#define I2C_RADDR(x) (x | 0x01) //set R/W bit of I2C addr

//I2C Operations

void configI2C1(uint16_t u16_FkHZ);
void startI2C1(void);
void rstartI2C1(void);
void stopI2C1(void);
void putI2C1(uint8_t u8_val);
uint8_t putNoAckCheckI2C1(uint8_t u8_val);
uint8_t getI2C1(uint8_t u8_ack2Send);

//I2C Transactions
void write1I2C1(uint8_t u8_addr,uint8_t u8_d1);
void write2I2C1(uint8_t u8_addr,uint8_t u8_d1, uint8_t u8_d2);
void writeNI2C1(uint8_t u8_addr,uint8_t* pu8_data, uint16_t u16_cnt);
void read1I2C1(uint8_t u8_addr,uint8_t* pu8_d1);
void read2I2C1(uint8_t u8_addr,uint8_t* pu8_d1, uint8_t* pu8_d2);
void readNI2C1(uint8_t u8_addr,uint8_t* pu8_data, uint16_t u16_cnt);

To use the above code without editing the variable types, define them at the top of your source file.

#define uint8_t unsigned char
#define uint16_t unsigned int
#define uint32_t unsigned long

In the library function implementation, comment out some lines that you don’t intend to use, or change it to suit your hardware. For example, an error message may be sent to hyperterminal when a device does not acknowledge the call.

Writing to the DAC

Here comes the part that I want to elaborate more. The MCP4725 has a couple of write modes depending on the speed and the destination. The chip has an internal EEPROM that can store a DAC value. This is useful for an application that requires some particular voltage at power on. Keep in mind that writing to EEPROM takes more time than writing directly to the DAC register. For our simple experiment, we do not need to memorize any value so we write only to the DAC register.

Before doing anything else, initialize the I2C by selecting the speed. The value is in kilohertz. For example, for 400 KHz speed


The function also enables the I2C1 module by setting I2C1CONbits.I2CEN = 1.

According to the datasheet, suppose we want to write a 12-bit value, say, 0xBD6, to MCP4725 using fast mode to DAC register, first it has to be addressed by sending the first byte 0xC0 (assuming A0 pin tied low), then the 2-byte data 0x0BD6. Note that the library has function write2I2C1(), which can be conveniently used. The only required task is to rearrange a 12-bit value to 2 bytes. A straightforward way people love is to assign the upper 4 bits to a 8-bit variable and perform some shifting. Here we prefer using union variable. Define a global union to keep DAC value

typedef union
    uint8_t half[2];
    uint16_t full;
} dacvalue;
dacvalue DacVal;

Then we can conveniently access the full value from DacVal.full, or either lower and upper half bytes from DacVal.half[0] and DacVal.half[1], respectively, without having to shift the data.

So, the writing process is implemented as a function writeMCP4725()

void writeMCP4725(void)  {
    write2I2C1(MCP4725ADDR, DacVal.half[1], DacVal.half[0]);

where MCP4725ADDR is defined as 0xC0 somewhere at the top of the source file.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s