• AVR Freaks

Hot!Has anyone gotten an I2C Slave to work with K42-family PIC18s yet?

Author
WebMaka
New Member
  • Total Posts : 7
  • Reward points : 0
  • Joined: 2019/02/21 19:38:57
  • Location: 0
  • Status: offline
2019/02/22 14:57:48 (permalink)
0

Has anyone gotten an I2C Slave to work with K42-family PIC18s yet?

Not sure if this belongs in the MPLAB X IDE forum or the PIC18 forum or the peripherals forum or all of the above, so if this would belong elsewhere please let me know...
 
I'm trying to port working code from an atmega328P to something with a larger program space that's cheaper per chip (should my project see production), but I'm having a hell of a time getting I2C slave code to work. I've gone through every datasheet and appnote I could find, hundreds of example code snippets, hundreds more forum threads, and on and on and I'm likely missing something really stupid and obvious that I just can't seem to home in on.
 
Guess I'll start with pertinent details...
 
Dev environment: MPLAB X IDE 5.10 on Win10 Pro, with MCC 3.75 installed
Target MCU: PIC18F46K42 on Xpress dev board, programmed via hex-file drag-and-drop. I2C Master on MSSP1, pins RC3 (SCL) and RC4 (SDA), I2C Slave on MSSP2, pins RB1 (SCL) and RB2 (SDA), with the slave using MCC generated code. Master currently unimplemented aside from pin reservations.
 
Pin manager init:

void PIN_MANAGER_Initialize(void)
{
    /**
    LATx registers
    */
    LATE = 0x00;
    LATD = 0x00;
    LATA = 0x00;
    LATB = 0x00;
    LATC = 0x00;

    /**
    TRISx registers
    */
    TRISE = 0x07;
    TRISA = 0xFF;
    TRISB = 0xF8;
    TRISC = 0xE7;
    TRISD = 0xFF;

    /**
    ANSELx registers
    */
    ANSELD = 0x00;
    ANSELC = 0x00;
    ANSELB = 0x00;
    ANSELE = 0x00;
    ANSELA = 0x00;

    /**
    WPUx registers
    */
    WPUD = 0x00;
    WPUE = 0x00;
    WPUB = 0x06;
    WPUA = 0x00;
    WPUC = 0x00;

    /**
    RxyI2C registers
    */
    RB1I2C = 0x13;
    RB2I2C = 0x24;
    RC3I2C = 0x21;
    RC4I2C = 0x22;
    RD0I2C = 0x00;
    RD1I2C = 0x00;

    /**
    ODx registers
    */
    ODCONE = 0x00;
    ODCONA = 0x00;
    ODCONB = 0x06;
    ODCONC = 0x18;
    ODCOND = 0x00;

    /**
    SLRCONx registers
    */
    SLRCONA = 0xFF;
    SLRCONB = 0xFF;
    SLRCONC = 0xFF;
    SLRCOND = 0xFF;
    SLRCONE = 0x07;




    RC3PPS = 0x21;   //RC3->I2C1:SCL1;    
    I2C1SCLPPS = 0x13;   //RC3->I2C1:SCL1;    
    RC4PPS = 0x22;   //RC4->I2C1:SDA1;    
    I2C1SDAPPS = 0x14;   //RC4->I2C1:SDA1;    
   
    RB1PPS = 0x23;   //RB1->I2C2:SCL2;    
    I2C2SCLPPS = 0x09;   //RB1->I2C2:SCL2;    
    RB2PPS = 0x24;   //RB2->I2C2:SDA2;    
    I2C2SDAPPS = 0x0A;   //RB2->I2C2:SDA2;    
    
    
}

 
I2C2 init:

void I2C2_Initialize(void)
{
    
        // ADR 64;
        I2C2ADR0 = 0x40;
        // ADR 64;
        I2C2ADR1 = 0x80;
        // ADR 0;
        I2C2ADR2 = 0x00;
        // ADR 0;
        I2C2ADR3 = 0x00;
        // TXU 0; CSD Clock Stretching enabled; ACKT 0; RXO 0; ACKDT Acknowledge; ACKSTAT ACK received; ACKCNT Acknowledge;
        I2C2CON1 = 0x00;
        // ABD enabled; GCEN disabled; ACNT disabled; SDAHT 30 ns hold time; BFRET 8 I2C Clock pulses; FME enabled;
        I2C2CON2 = 0x28;
        // CLK MFINTOSC;
        I2C2CLK = 0x03;
        // CNT 255;
        I2C2CNT = 0xFF;
        // CSTR clock stretching; S Cleared by hardware after Start; MODE four 7-bit address; EN disabled; RSEN disabled;
        I2C2CON0 = 0x10;
    
    
    PIR5bits.I2C2RXIF=0;
    PIR5bits.I2C2TXIF=0;
    PIR6bits.I2C2EIF=0;
    I2C2ERRbits.NACKIF=0;
    PIR6bits.I2C2IF=0;
    I2C2PIRbits.PCIF=0;
    I2C2PIRbits.ADRIF=0;
    
    PIE5bits.I2C2RXIE=1;//enable I2C RX interrupt
    PIE5bits.I2C2TXIE=1;//enable I2C TX interrupt
    PIE6bits.I2C2EIE=1;//enable I2C error interrupt
    I2C2ERRbits.NACKIE=1;//enable I2C error interrupt for NACK
    PIE6bits.I2C2IE=1;//enable I2C  interrupt
    I2C2PIEbits.PCIE=1;//enable I2C interrupt for stop condition
    I2C2PIEbits.ADRIE=1;//enable I2C interrupt for I2C address match condition
    
    I2C2PIR = 0;//    ;Clear all the error flags
    I2C2ERR = 0;
    
}

 
(The ISR is MCC-generated stock boilerplate, which I'll edit once I have the basic comms side working. I left it out for brevity but can paste it if it'd help.)
 
When I connect the PIC to an I2C Master running known-working code (an Odroid C2 running an ARM variant of Debian), and try an "i2cdetect -y" on the master, it scans slowly, taking about a second per address to step through all addresses on the bus. It shouldn't be a slow scan - i2cdetect should return a list of addresses on the bus almost immediately - so I'm thinking that the PIC is trying but either I2C is misconfigured or it's manipulating the bus in some way the master doesn't like. (Not sure, for example, if the C2 supports clock stretching.)
 
Unfortunately I don't have access to a logic analyzer or O-scope so no watching waveforms on the bus for me.
 
Does anyone have working code on a K42-family PIC18 they don't mind sharing so I can compare notes? Or, does anyone see anything amiss that I'm just plain a-missing?
 
#1

11 Replies Related Threads

    mbrowning
    USNA79
    • Total Posts : 1795
    • Reward points : 0
    • Joined: 2005/03/16 14:32:56
    • Location: Melbourne, FL
    • Status: offline
    Re: Has anyone gotten an I2C Slave to work with K42-family PIC18s yet? 2019/02/25 11:48:23 (permalink)
    0
    take a look at TB3159. It's all I needed.
    http://ww1.microchip.com/downloads/en/AppNotes/TB3159-I2C-with-Hardware-Protocol-Acceleration-on-8-Bit-PIC-90003159B.pdf
     
    For some reason, this document is not in the documents section in k42 product pages anymore. Instead are some generic I2C TB's that aren't K42 specific.
    #2
    WebMaka
    New Member
    • Total Posts : 7
    • Reward points : 0
    • Joined: 2019/02/21 19:38:57
    • Location: 0
    • Status: offline
    Re: Has anyone gotten an I2C Slave to work with K42-family PIC18s yet? 2019/02/25 13:57:24 (permalink)
    0
    I'd already found that appnote and tried its sample I2C slave code, and I got as far as having the K42 be detectable by the master SBC (read: its address shows on i2cdetect), but any attempt to access the K42 slave makes it "go away" until manually reset. (All calls from the master error out, and it doesn't respond to i2cdetect any more after the master makes any attempt to address it.)
     
    I'm thinking that something isn't being reset/cleared properly in the ISR so the K42's I2C module is left hanging, but I can't seem to get a handle on what.
     
    #3
    WebMaka
    New Member
    • Total Posts : 7
    • Reward points : 0
    • Joined: 2019/02/21 19:38:57
    • Location: 0
    • Status: offline
    Re: Has anyone gotten an I2C Slave to work with K42-family PIC18s yet? 2019/02/25 21:22:18 (permalink)
    0
    I retried the sample code from TB3159, compiled (MPLAB X 5.1, XC8 2.05), pushed to the K42 I'm using (18F46K42 on an Xpress dev board), and connected the K42 to my I2C master, an Odroid C2 SBC running DietPi, an ARM Debian variant of Linux. (This SBC, like many of its kin, does not support clock stretching.) The main loop toggles a LED connected to RB0 on 250ms intervals, just to show the rest of the K42 is running code. The K42 is using I2C address 0x30, and running TB3159's I2C slave code on I2C module 2 (SCL2>RB1/SDA2>RB2).
     

     
     
     
    root@Informant:~# i2cdetect -y 1
         0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
    00:          -- -- -- -- -- -- -- -- -- -- -- -- --
    10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    30: 30 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    70: -- -- -- -- -- -- -- --
    root@Informant:~# i2cget -y 1 0x30
    Error: Read failed
    root@Informant:~# i2cdetect -y 1
         0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
    00:          -- -- -- -- -- -- -- -- -- -- -- -- --
    10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    70: -- -- -- -- -- -- -- --
     
     
     

     
    Trying a master-read/slave-write with no register or command byte errors out, and the I2C slave on the K42 stops responding until I press the magic reset button. Trying a master-read/slave-write with any value as a register/command returns 0xFF - the interrupt code running on the K42 should return 0x00 for this call - and again the K42's I2C slave dies until reset.
     
    I can send single bytes to the K42, one at a time, but if I try to send more than one at a time, and after any read, the slave goes away until reset.
     
    I'm heavily leaning toward the interrupt not completing or resetting like it's supposed to, and thus leaving the I2C module suspended. Or, the SBC is sending or not sending something important; however, I'm leaning away from this because the Arduino code I want to port still works/communicates fine when I reconnect it to the SBC.
     
     
    At any rate, here's what I have, and again most of it is ripped out of TB3159, with a few additions and notes to self thrown in:
     

     
     
     
    void I2C2_Initialize(void)
    {
        // Configure the pins as digital
        ANSELBbits.ANSELB1 = 0;
        ANSELBbits.ANSELB2 = 0;

        // PPS Unlock Sequence
        PPSLOCK = 0x55;
        PPSLOCK = 0xAA;
        PPSLOCKbits.PPSLOCKED = 0x00;

        // Set RB1 for SCL
        RB1PPS = 0x23;
        I2C2SCLPPS = 0x09;

        // Set RB2 for SDA
        RB2PPS = 0x24;
        I2C2SDAPPS = 0x0A;

        // PPS Lock Sequence
        PPSLOCK = 0x55;
        PPSLOCK = 0xAA;
        PPSLOCKbits.PPSLOCKED = 0x01;

        // Configure the pins as Open-drain
        ODCONBbits.ODCB1 = 1;
        ODCONBbits.ODCB1 = 1;

        // Set the I2C levels
        RB1I2Cbits.TH = 1;
        RB2I2Cbits.TH = 1;

        // Configure the pins as Outputs
        TRISBbits.TRISB1 = 0;
        TRISBbits.TRISB2 = 0;    
    }
     
     
     
     
     
     
     
     
     
     
     
    void I2C2_InitSlave(unsigned char SLAVE_ADDRESS)
    {
        // 7bit Slave Mode (MODE = 0)
        I2C2CON0 = 0x00;
        
        // Slave Address Match
        if (SLAVE_ADDRESS == 0x00)
            SLAVE_ADDRESS = 0x20;
        SLAVE_ADDRESS = SLAVE_ADDRESS << 1;
        I2C2ADR0 = SLAVE_ADDRESS;
        I2C2ADR1 = SLAVE_ADDRESS;
        I2C2ADR2 = SLAVE_ADDRESS;
        I2C2ADR3 = SLAVE_ADDRESS;
        
        // ACK for every valid byte (ACKDT = 0)
        // ACK at the end of a Read (ACKCNT = 0)
        // Clock stretching DISabled (CSTRDIS = 1)
        I2C2CON1 = 0x01;
        
        // Auto-count disabled (ACNT = 0)
        // General Call disabled (GCEN = 0)
        // Fast mode enabled (FME = 1)
        // ADB0 address buffer used (ADB = 0)
        // SDA Hold time of 30 ns (SDAHT = 2)
        // Bus free time of 8 I2C Clock pulses
        // (BFRET = 1)
        I2C2CON2 = 0x28;
        
        // Clear all I2C flags
        PIR6bits.I2C2IF = 0;
        I2C2PIR = 0x00;
        
        // Enable I2C interrupts
        PIE6bits.I2C2IE = 1;
        IPR6bits.I2C2IP = 1;
        // NOTE: Enable global and peripheral interrupts somewhere!
        //INTCON0bits.IPEN = 1;
        //INTCON0bits.GIEH = 1;
        
        // Enable local interrupt on ACK Sequence
        I2C2PIE = 0x40;
        
        // Enable I2C module
        I2C2CON0bits.EN = 1;
        
        // Set the read and write position pointers to zero
        i2c2_read_pos = 0;
        i2c2_write_pos = 0;
        
        
        i2c2_data = 0;
    }


     
     
     
     
     
     
     
    void __interrupt() I2CSLAVE_ISR (void)
    {
     
     
     
        // I2C2
        if (PIR6bits.I2C2IF)
        {
            // Clear the I2C interrupt flag
            PIR6bits.I2C2IF = 0;
            
            
            
            // Address Match Interrupt Detected
            if (I2C2PIRbits.ADRIF)
            {
                // Clear the interrupt flag
                I2C2PIRbits.ADRIF = 0;
                
                /*
                 *
                 * Handle initial communications setup here - this interrupt
                 * triggers as soon as the Master sends this slave's address
                 * down the line.
                 *
                 */
            }
            
            
                
            // ACK Sequence Interrupt Detected
            if (I2C2PIRbits.ACKTIF)
            {
                // Clear the interrupt flag
                I2C2PIRbits.ACKTIF = 0;
                
                // For Slave Read/Master Write
                if (!I2C2STAT0bits.R)
                {
                    // Data Byte Received
                    if (I2C2STAT0bits.D)
                    {        
                        // Read from RXB
                        i2c2_data = I2C2RXB;
                        //i2c2_read_buffer[i2c2_read_pos] = I2C2RXB;
                        //i2c2_read_pos++;
                    }
                }
                // For Slave Write/Master Read
                else
                {
                    // Write to TXB
                    I2C2TXB = i2c2_data;
                    //I2C2TXB = i2c2_write_buffer[i2c2_write_pos];
                    //i2c2_write_pos++;
                }
                
                // Release SCL
                I2C2CON0bits.CSTR = 0;
            }
            
            
            
            // STOP or RESTART Interrupt Detected
            if ((I2C2PIRbits.PCIF) || (I2C2PIRbits.RSCIF))
            {
                // Clear whichever interrupt flag was set
                if (I2C2PIRbits.PCIF)
                    I2C2PIRbits.PCIF = 0;
                if (I2C2PIRbits.RSCIF)
                    I2C2PIRbits.RSCIF = 0;
                
                /*
                 *
                 * Add STOP/RESTART handler here
                 *
                 */
                
                // Reset the read and write position pointers
                i2c2_read_pos = 0;
                i2c2_write_pos = 0;            
            }
            
            
            
            // Reset both interrupt and error flags
            I2C2PIR = 0;
            I2C2ERR = 0;
        }



        // Handling Any Other Interrupts?
        
    }
     
     
     

     
    Hopefully someone will spot something I keep missing...
     
    post edited by WebMaka - 2019/02/25 21:28:25
    #4
    paulfjujo
    paulfjujo
    • Total Posts : 94
    • Reward points : 0
    • Joined: 2011/03/08 05:33:46
    • Location: France 01700
    • Status: offline
    Re: Has anyone gotten an I2C Slave to work with K42-family PIC18s yet? 2019/02/28 05:17:39 (permalink)
    0
    hello,
     
    i tested  a 18F27K42 as master with I2C1 Hardware
    linked to an RTC (Read/write)   and a LCD  (write only)
    using MikroC 7.30 Beta 
    .. but not as slave.
    #5
    cbest
    Senior Member
    • Total Posts : 72
    • Reward points : 0
    • Joined: 2016/01/07 09:47:13
    • Location: 0
    • Status: offline
    Re: Has anyone gotten an I2C Slave to work with K42-family PIC18s yet? 2019/02/28 05:35:41 (permalink)
    0
    I have and my code is here:
    www.mplabxpress.microchip.com/mplabcloud/example/details/519
    I use the 26K42, have I2C1 as the master, and I2C2 as the slave.
    Please look at that project's slave code and hopefully that will help you.
     
    Chris
     
    #6
    WebMaka
    New Member
    • Total Posts : 7
    • Reward points : 0
    • Joined: 2019/02/21 19:38:57
    • Location: 0
    • Status: offline
    Re: Has anyone gotten an I2C Slave to work with K42-family PIC18s yet? 2019/02/28 08:56:48 (permalink)
    0
    cbest
    I have and my code is here:
    www.mplabxpress.microchip.com/mplabcloud/example/details/519
    I use the 26K42, have I2C1 as the master, and I2C2 as the slave.
    Please look at that project's slave code and hopefully that will help you.



    I did come across your project before but hadn't grabbed its source - I'll have to do some investigating to see what I've missed.
     
    One thing I've noticed, and I don't know if this isn't a large part of my problem, is that my I2C master (Amlogic S905 SoC, Odroid C2 SBC running DietPi, an ARM Debian Stretch variant) doesn't appear to support clock stretching at all according to the SBC's manufacturer. This seems to be a common problem with SoCs used in SBCs - the Broadcom SoC in Raspberry Pi 2s apparently doesn't support clock stretching either, and RPi 3s do in hardware but don't have driver support for it so people occasionally have problems with I2C on them as well. I'm starting to wonder if the K42 has problems with I2C masters that don't like slaves manipulating SCL, and once I have a working slave generally I'll investigate this further.
     
    #7
    WebMaka
    New Member
    • Total Posts : 7
    • Reward points : 0
    • Joined: 2019/02/21 19:38:57
    • Location: 0
    • Status: offline
    Re: Has anyone gotten an I2C Slave to work with K42-family PIC18s yet? 2019/02/28 09:00:35 (permalink)
    0
    paulfjujo
    hello,
     
    i tested  a 18F27K42 as master with I2C1 Hardware
    linked to an RTC (Read/write)   and a LCD  (write only)
    using MikroC 7.30 Beta 
    .. but not as slave.




    I2C masters are always substantially easier than slaves because of not having to set up an entire state machine to step through the protocol's processes when you're the one issuing the orders. My issue on this front (using a master vs. using a slave) is that I have master hardware already in place for this project, and either the hardware doesn't support slave operation or there are no drivers for it. (Haven't gotten a clear answer on which is the case from the hardware mfr.)
    #8
    WebMaka
    New Member
    • Total Posts : 7
    • Reward points : 0
    • Joined: 2019/02/21 19:38:57
    • Location: 0
    • Status: offline
    Re: Has anyone gotten an I2C Slave to work with K42-family PIC18s yet? 2019/03/05 16:58:02 (permalink)
    0
    Okay, update time...
     
    Having grown very tired of not actually KNOWING what the lines are doing, I grabbed a cheap knockoff logic analyzer, and probed the SDA/SCL lines.
     
    I send the command "i2cget -y 1 0x30 0x01", which, for folks unfamiliar with using I2C on Linux distros, means to request data from register 0x01 on I2C device 0x30.
     
    Logic analyzer shows start, address (0x30), write flag, ACK, data write (0x01), ACK, a small gap, repeat-start, address (0x30), read flag, ACK, data read (0xFF), NACK, STOP. The data read is interesting since the I2C slave's ISR code is supposed to send back anything sent to it (I2CxRXB is copied to I2CxTXB), so writing 0x01 should have resulted in reading 0x01.
     
    Any further communications with the K42 slave are NACKed until I reset the chip. It only responds to the master once. This positively screams "something isn't being cleared properly in the ISR and it's not retriggering on subsequent squawks from the master" to me...
     
    #9
    WebMaka
    New Member
    • Total Posts : 7
    • Reward points : 0
    • Joined: 2019/02/21 19:38:57
    • Location: 0
    • Status: offline
    Re: Has anyone gotten an I2C Slave to work with K42-family PIC18s yet? 2019/03/05 18:51:53 (permalink)
    +1 (1)
    Tried to edit my post, above but I'm getting "you don't have permission" errors for some reason, so let's see if this works...
     

    First try to converse with the K42 slave.
     

    All subsequent conversations until the K42 is reset.
     
    #10
    ThomasWpoint
    New Member
    • Total Posts : 1
    • Reward points : 0
    • Joined: 2019/11/01 07:37:52
    • Location: 0
    • Status: offline
    Re: Has anyone gotten an I2C Slave to work with K42-family PIC18s yet? 2019/12/19 12:22:10 (permalink)
    0
    Hi WebMaka,
    did you went lucky and solved the behaviour reported in your last post. I see perfectly the same issue with PIC18F46K42. I'm running crazy on it since I tried to get behind it and couldn't get any close.
     
    #11
    meanilkp
    New Member
    • Total Posts : 23
    • Reward points : 0
    • Joined: 2018/08/19 22:12:10
    • Location: India
    • Status: offline
    Re: Has anyone gotten an I2C Slave to work with K42-family PIC18s yet? 2020/08/06 02:30:48 (permalink)
    0
    Hi,
    Seem like you are using an old MCC PIC8  library. Please update to the latest 1.81.4 and create a new project. Please finds the example code in the attachment and work for me.
     
    Even if it does not work for you, please share your code.
    post edited by meanilkp - 2020/08/06 02:41:01
    #12
    Jump to:
    © 2020 APG vNext Commercial Version 4.5