I2C Master with PIC*K42

Status
Not open for further replies.

Roze

New Member
Hi,
I've once again bashed my head to what is called HW I2C on the PIC K42 architecture. This time, yet again ran into a wall. And since granddad seems to have gotten it to work in the old thread, which is locked, https://www.electro-tech-online.com/threads/pic18f25k42-a-work-in-progress.152004/page-3 , I wish to query how he did it.

Also, just for good measure, I'm happy my slave routine came to the rescue and I hope you rooted out the issues. I know I did .

In any case, this is my current code for I2C transfer, but I get stuck in the TXBE check all the time. Hardware sets PCIF for some odd reason. Most commonly after writing the second data byte to the transmit buffer.

Any suggestions?

C:
void I2C_Transmit(char slave_write_address, int length, uint8_t *data) {
    I2C1ADB1 = slave_write_address;
    I2C1CNT = length;
    I2C1CON0bits.S = 1; //Start
    while (length-- > 0) {
        unsigned char d = *data++;
        I2C1TXB = d;
        while (!I2C1STAT1bits.TXBE) {
        }
    }
    // Detect Stop condition
    while (!I2C1PIRbits.PCIF) {}
    I2C1PIRbits.PCIF = 0;
    I2C1PIRbits.SCIF = 0;
    I2C1STAT1bits.CLRBF = 1;
}

All I2C1 registers at time of "hang":
I2C1ADB1 SFR 0x3D6E 0x78
I2C1BTO SFR 0x3D7C 0x00
I2C1CLK SFR 0x3D7B 0x03
I2C1CNT SFR 0x3D6C 0x18
I2C1CON0 SFR 0x3D73 0x84
I2C1CON1 SFR 0x3D74 0xA0
I2C1CON2 SFR 0x3D75 0x20
I2C1ERR SFR 0x3D76 0x10
I2C1PIE SFR 0x3D7A 0x00
I2C1PIR SFR 0x3D79 0x05
I2C1RXB SFR 0x3D6A 0x00
I2C1SCLPPS SFR 0x3AE1 0x13
I2C1SDAPPS SFR 0x3AE2 0x14
I2C1STAT0 SFR 0x3D77 0x88
I2C1STAT1 SFR 0x3D78 0x00
 
I got it working!
And for future reference to anyone trying. You can send an arbitrary number of bytes with the K42 HW I2C. You just have to take care to update the I2CxCNT so it keeps above 1 at all times while transferring blobs. However, care must be taken so that it actually decrements properly being 1 on the next to last byte so that it properly terminates the transfer. So rule of thumb, just reload 0xff untill there is less or equal to 0xff bytes remaining.

And for reference; my non-fail-safe I2C master code w/ initiation, tho the following code does not offer +0xff transmission.
Also my error was not adhering to the protocol rules. Apparently, I could only send 1 or 2 bytes at a time unless it was in "data-mode", so hence the stop from the slave.

C:
#include <xc.h>

void I2C1_Initialize(void)
{
   if(!I2C1CON0bits.EN)
    {
      I2C1CON1 = 0x80;
      I2C1CON2 = 0x20;
      // CLK MFINTOSC
      I2C1CLK = 0x03;

      I2C1CON0 = 0x84;
      I2C1PIR = 0;//    ;Clear all the error flags
      I2C1ERR = 0;
   }
}

void i2c_start(unsigned char addr, unsigned char length) {
   I2C1_Initialize();
   I2C1STAT1bits.CLRBF = 1;
   while (I2C1STAT1bits.CLRBF) {}
   while (!I2C1STAT0bits.BFRE) {}
   I2C1ADB0 = 0;
   I2C1ADB1 = addr;
   I2C1CNT = length;
   I2C1CON0bits.S = 1; //Start
   while (I2C1CON0bits.S) {
        __delay_us(1);
    }
}

void i2c_stop(void) {
   I2C1CNT = 0;
   while (!I2C1PIRbits.PCIF) {
        __delay_us(1);
    }
}

unsigned char i2c_write(unsigned char byte) {
   I2C1TXB = byte;
   while (!I2C1STAT1bits.TXBE) {
        __delay_us(1);
    }
   return I2C1CON1bits.ACKSTAT;
}

void i2c_writeNBytes(uint8_t address, unsigned char* data, uint8_t len)
{
    i2c_start(address, len);
    while(len--)
    {
        i2c_write(*data++);
    }
    i2c_stop();
}

//Kind regards.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…