• AVR Freaks

Helpful ReplyHot!dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line?

Author
arigead
Super Member
  • Total Posts : 445
  • Reward points : 0
  • Joined: 2011/02/07 06:58:31
  • Location: 0
  • Status: offline
2020/09/21 04:54:18 (permalink)
0

dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line?

I'm trying to program the dsPIC33EP128GS702 as the I2C Slave side of the I2C protocol, to act as a 24LCxx EEPROM Memory device. At present my code is ignoring the received 24LCxx IC address and the two memory address bytes in the initial phase of the protocol, so regardless of chip address or memory address I'm just tying to write back to the I2C Master the bytes 0x55. What I'm seeing in the Logic analyser is that it appears that the dsPIC33 is not releasing the Clock line, even though I disabled the clock stretching in the initialisation of the channel:
 
 ANSELBbits.ANSB6 = 0;
 TRISBbits.TRISB6 = 1;
 ODCBbits.ODCB6 = 1;
 ANSELBbits.ANSB7 = 0;
 TRISBbits.TRISB7 = 1;
 ODCBbits.ODCB7 = 1;

 I2C1CONLbits.I2CSIDL = 0; // Module continues in Idle.
 I2C1CONLbits.SCLREL = 1; // Release clock (Slave mode))
 I2C1CONLbits.A10M = 0; // 7 bit mode
 I2C1CONLbits.DISSLW = 1; // Disable Slew rate.
 I2C1CONLbits.SMEN = 0; // Disable SMBus thresholds
 I2C1CONLbits.GCEN = 1; // Enable General call address
 I2C1CONLbits.STREN = 0; // Disable clock stretching

 I2C1CONHbits.SCIE = 1; // Enable Start ISR
 I2C1CONHbits.PCIE = 1; // Enable Stop ISR

 I2C1MSK = 0xff; // Don't care about address for moment
 I2C1ADD = 0xa0;

 IFS1bits.MI2C1IF = 0; // Clear Master ISR Flag
 IEC1bits.MI2C1IE = 1; // Enable Master Interrupts

 IFS1bits.SI2C1IF = 0; // Clear Slave ISR Flag
 IEC1bits.SI2C1IE = 1; // Enable Slave Interrupts

 IFS10bits.I2C1BCIF = 0;
 IEC10bits.I2C1BCIE = 1;

 I2C1CONLbits.I2CEN = 1;

 
Maybe I'm not processing the transmission in the ISR correctly. The way I read the Datasheets I had to write to the transmit register and set the TBF flag?
 
void __attribute__((__interrupt__, __no_auto_psv__)) _SI2C1Interrupt(void)
{
 uint8_t rx_byte;

 while (IFS1bits.SI2C1IF) {
  IFS1bits.SI2C1IF = 0;
  if (I2C1STATbits.P) {
   serial_printf("!");
  } else if (I2C1STATbits.S) {
   if(I2C1STATbits.RBF) {
    rx_byte = I2C1RCV;
   }
   if (I2C1STATbits.R_W) {
    while(I2C1STATbits.TBF);
    I2C1TRN = 0x55;
    I2C1STATbits.TBF = 1;
   }
  }

  if (I2C1STATbits.IWCOL) {
   serial_printf("W");
  }
  if (I2C1STATbits.I2COV) {
   serial_printf("V");
  }
 }
}

 
There are a couple of 'printf()' calls in the ISR there for debugging, but only for the errors and the Stop condition. At present I'm not getting either to occur as the clock line is never released. Well it appears to me as if it's not released by the dsPIC33?

Attached Image(s)

#1
ric
Super Member
  • Total Posts : 28674
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line? 2020/09/21 05:09:31 (permalink)
0
What in the datasheet makes you think that you should set TBF?
(FYI, it is a "read-only" flag).
Why not leave the MSK register as the default zero, so you can see the peripheral generate an ACK automatically if it receives the address correctly?
 
Have you read the I2C chapter of the Family Reference Manual?
http://ww1.microchip.com/downloads/en/DeviceDoc/70000195g.pdf
 
post edited by ric - 2020/09/21 05:13:50

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#2
arigead
Super Member
  • Total Posts : 445
  • Reward points : 0
  • Joined: 2011/02/07 06:58:31
  • Location: 0
  • Status: offline
Re: dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line? 2020/09/21 08:29:28 (permalink)
0
It was from the family reference that I misinterpreted the TBF flag:
 
The slave sets the TBF status bit (I2CxSTAT). The eight data bits are shifted out on the falling
edge of the SCLx input. This ensures that the SDAx signal is valid during the SCLx high time.
When all 8 bits have been shifted out, the TBF status bit is cleared.

 
I read that the slave sets the flag and as I was implementing the slave I set it. But you're right it means that the I2C Peripheral sets it and it's read only. Still can't have done much harm.
 
As for the ACK generation for the Address, as far as I can see thus far in the comms all ACKs are in place so I don't have an issue with those. I get as far as the read from the Slave and that's where it falls down.
 
Again from the I2C Family reference document:
 
When the interrupt from the address detection occurs, the user software can write a byte to the
I2CxTRN register to start the data transmission.

 
The thing about that is that all interrupts share the same vector and ISR. So the address detection is just an interrupt without a corresponding Status But, as far as I could see. Even if I set the MASK to 100% don't care about address, I'd still expect the ISR to be executed, and I just triggered of the R_W bit. If there's a Read from the Master then write to the I2CxTRN. Perhaps I'm writing to it late, so perhaps if I wrote to the transmit reg as soon as the start condition is detected it'd be loaded and ready to go. I'll try that, perhaps I'll get the first byte out the interface and then stall.
 
Thanks for the help.
#3
arigead
Super Member
  • Total Posts : 445
  • Reward points : 0
  • Joined: 2011/02/07 06:58:31
  • Location: 0
  • Status: offline
Re: dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line? 2020/09/22 04:21:33 (permalink)
0
So I changed the Address Mask so that I do care and try to match the address being passed by the Master. That is working in so far as I do get the match and I do get the Ack from the Slave dsPIC33EP128GS702, but still no transmitting the data.
 
So instead of writing to the transmit register when the R_W flag is set I just ignore that bit and simply write to the transmit register when the Start bit is set. That is giving me data on the line, but it's not right, well it doesn't feel right. From the family reference again:
 
When the R/W status bit of the incoming device address byte is ‘1’ and an address match occurs,
the R/W status bit (I2CxSTAT) is set. At this point, the master device is expecting the slave
to respond by sending a byte of data. The contents of the byte are defined by the system protocol
and are only transmitted by the slave.

 
By this stage, you've got an address match and the R_W is set it appears to be already too late to load the transmit register. So it appears that the flag is useless. From my trace the Master has the clock operating at a frequency of 255KHz, I can't do anything with that it's fixed. The dsPIC33EP128GS702 is operating at a frequency of 59.8MHz, of the Internal RC with a PLL. According to the Family reference the uC supports the 400KHz protocol so 255KHz should not be a problem to it, but it does appear to be, a problem. 
 
 
#4
arigead
Super Member
  • Total Posts : 445
  • Reward points : 0
  • Joined: 2011/02/07 06:58:31
  • Location: 0
  • Status: offline
Re: dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line? 2020/09/22 07:32:32 (permalink)
0
I'm finding that the results I'm getting don't agree with the documentation on I2C Slave mode. According to the family reference there should be an interrupt on every byte transmitted from the Slave to the Master. That appears not to be the case. So to transmit all the bytes requested by the Master I've had to go into a loop in the ISR, the problem is terminating out of that loop.
 
I'll raise a ticket as this seems to be a feature not often used. And seems not to work as documented.
#5
ric
Super Member
  • Total Posts : 28674
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line? 2020/09/22 14:09:50 (permalink)
0
That can't be right. You should NEVER loop inside an ISR.
Something else is not configured right if you're not getting an interrupt each transfer.

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#6
Gort2015
Klaatu Barada Nikto
  • Total Posts : 4003
  • Reward points : 0
  • Joined: 2015/04/30 10:49:57
  • Location: 0
  • Status: offline
Re: dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line? 2020/09/22 17:13:49 (permalink)
0
The slave I2C code is the reverse of the master I2C code.
 
Slave interrupts must be done in the correct order.
 
Not every interrupt is because a byte was received.
Code should check for ACKTIM (Acknowledge Time) and ACKSTAT.
 
Exit the interrupt like this:
    ; - - - - - - - - - - - - - - - -
exit_isr:
    ; release clock and clear irq
    bset    [CONL], #SCLREL
    bclr    IFS1, #SI2C1IF
    ; - - - - - - - - - - - - - - - -
 
You can spend as much time as you like in the slave intterupt.
 
 
 
 

MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
https://www.youtube.com/watch?v=Iu1qa8N2ID0
+ ST:Continues, "What Ships are Made for", Q's back.
#7
Gort2015
Klaatu Barada Nikto
  • Total Posts : 4003
  • Reward points : 0
  • Joined: 2015/04/30 10:49:57
  • Location: 0
  • Status: offline
Re: dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line? 2020/09/22 17:22:26 (permalink)
0
I wouldn't raise a ticket with Microchip because you do not understand it.
 
Loops?
 
Read the original Philips docs, some things are missing in the MC documentation such as general call.
 
"From my trace the Master has the clock operating at a frequency of 255KHz, I can't do anything with that it's fixed."
 
It is not fixed, set BRG (Baudrate Generator)
 
 
post edited by Gort2015 - 2020/09/22 17:31:07

MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
https://www.youtube.com/watch?v=Iu1qa8N2ID0
+ ST:Continues, "What Ships are Made for", Q's back.
#8
Antipodean
Super Member
  • Total Posts : 1927
  • Reward points : 0
  • Joined: 2008/12/09 10:19:08
  • Location: Didcot, United Kingdom
  • Status: offline
Re: dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line? 2020/09/23 04:31:56 (permalink)
0
Gort2015
"From my trace the Master has the clock operating at a frequency of 255KHz, I can't do anything with that it's fixed."
 
It is not fixed, set BRG (Baudrate Generator)

 
Well, it is fixed in that as a slave device he has no control over it. But that should not be a problem as it is pretty well smack in the middle of the normal I2C clock speed, so should not be a problem.
 

Do not use my alias in your message body when replying, your message will disappear ...

Alan
#9
Gort2015
Klaatu Barada Nikto
  • Total Posts : 4003
  • Reward points : 0
  • Joined: 2015/04/30 10:49:57
  • Location: 0
  • Status: offline
Re: dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line? 2020/09/23 07:56:59 (permalink)
4 (1)
Creating a ram memory device is fairly easy.
 
If simulating an eeprom, a buffer is used to store incoming data.
When a stop is asserted on the bus, slave can write to flash from the buffer.
 
Slave should spend little time in the interrupt, it transmits data back
to the master I2C when it has control of the clock.
 
Set the slave BRG @ 400KHz or 1,000KHz if using a cpu depending on clock frq.
 
Also the slave interrupt occurs on the falling edge of the 8th clock and
the rising edge of bit 9 where the slave tests ACKTIM for slave acknowledge.
 
Interrupts and status flags - The order of things:
- Stop -
General Call
Master NAK - ACKSTAT
- Start - (One time)
R_W ?
     Read OP
     D_A   ?
         Read Chip ID 7bit or 10bit in 2 interrupts
         and (start master receive, data immediate) /  or
         Read Data
    Write OP
    D_A ?
       Write Chip ID 7bit or 10bit in 2 interrupts
       or
       Write Data
           ACKTIM ? bit 9 - acknowledge (data tested on bit 8 last interrupt)
           or Write Data
 

MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
https://www.youtube.com/watch?v=Iu1qa8N2ID0
+ ST:Continues, "What Ships are Made for", Q's back.
#10
arigead
Super Member
  • Total Posts : 445
  • Reward points : 0
  • Joined: 2011/02/07 06:58:31
  • Location: 0
  • Status: offline
Re: dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line? 2020/09/23 08:19:31 (permalink)
0
Thanks for your responses on this issue. There was mention of checking the Acknowledgement status bit in the status register. I'm probably going to ask a stupid question on that topic, Acknowledgements that is. According to the family reference:
 
ACKTIM: Acknowledge Time Status bit (valid in I 2 C Slave mode only) (1)
1 = Indicates that the I 2 C bus is in an Acknowledge sequence; set on the falling edge of eighth SCLx clock
0 = Not an Acknowledge sequence, cleared on ninth rising edge of the SCLx clock
Hardware sets at the beginning of master transmission; hardware clears at the end of slave Acknowledge.

 
So the status Bit gets set when the clock pulse goes low. That's when the data on the data line is NOT valid. So now the Master can change the Data line to transmit ACK/NACK. It's only when that Status Flag goes low again that the data on the bus is valid. But that status flag is low for all 8 data bits so 1/16 it's set and the only thing you know when it is set is that data is NOT valid.
The only way to use that flag would be to hope that you catch it and loop on it.

if (I2C1STATbits.ACKTIM) {
    while (ISC1STATbits.ACKTIM);  // wait for ack bit to be valid
    if (!I2C1STATbits.ACKTIM) {
        I2C1TRN = 0x55;
    }
}

 
My problem with that, in my head, is that at the instant when the clock goes high for the 9th bit the data on the bus should now be valid. But that's on the bus! At that instant has the uC sampled the bus and updated the ACKSTAT bit, or has it started to sample the data line. Am I just now in a race condition with the I2C Peripheral to see who gets to ACKSTAT first.
 
To be honest I think the easiest solution here is to bit bang this protocol. I'm doing this as a proof of concept prototype so bit banging might work for that, as I now have the dsPIC33 on the bread board, but ultimately this does no feel like a reliable solution. And yes perhaps I have this mis-configured, but having been back and forward through the documentation I can't see where. 
 
#11
Gort2015
Klaatu Barada Nikto
  • Total Posts : 4003
  • Reward points : 0
  • Joined: 2015/04/30 10:49:57
  • Location: 0
  • Status: offline
Re: dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line? 2020/09/23 09:53:46 (permalink) ☄ Helpfulby arigead 2020/09/24 11:45:23
0
MC I2C doc - DS70000195F
The MC slave diagrams need to be studied, take figure 7.3, look where the interrupt occurs.
 
It can look confusing, it does become clear though with time.
The NXP docs are good.
 
I am not sure what you mean by race conditions, only 1 event can occur at a time.
The clock is stretched on entry, on exit the clock is manually released so that the master can rd/wr further data.
 
"Stop" is the one to look out for as the clock must be stretched manually if data is to be processed or stored in say flash memory.  Spurious stops and starts need to be accounted for as well if interrupts are enabled for them.
 
When in the slave interrupt, output the status register to uart.
 
I will publish output from Master I2C and Slave I2C soon that shows I2C at every stage.
 

MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
https://www.youtube.com/watch?v=Iu1qa8N2ID0
+ ST:Continues, "What Ships are Made for", Q's back.
#12
arigead
Super Member
  • Total Posts : 445
  • Reward points : 0
  • Joined: 2011/02/07 06:58:31
  • Location: 0
  • Status: offline
Re: dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line? 2020/09/24 11:45:06 (permalink)
0
Thanks for that. I got the bit bang version of the Comms protocol, so I'm more sure that my Hardware design can work. That kinda takes the pressure off so I can come back to this and work on the ISR version of an I2C Implementation.
 
As you say things become clearer with time. You have to be in the frame of mind for reading datasheets.
#13
Gort2015
Klaatu Barada Nikto
  • Total Posts : 4003
  • Reward points : 0
  • Joined: 2015/04/30 10:49:57
  • Location: 0
  • Status: offline
Re: dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line? 2020/09/24 14:29:59 (permalink)
0
Like Joe 90 on Youtube.
 
Some of the things I described were for manual control because you can
have multiple devices.
 
I have my own system in my I2C library.
// ----------------------------------------------------
// slave structure
typedef struct{
    unsigned int    ID;
    unsigned char   ASize;
    unsigned char   Mode;
    unsigned long   EndAddress;
    unsigned char   (*Read_Data)    (void *this, unsigned long Address);
    void            (*Write_Data)   (void *this, unsigned long Address, unsigned char X);
    void            (*Stop)         (void *this);
    void            *NextSlave;
}i2cslave_t;
// ----------------------------------------------------

 
Filling in the structure:
 
I2C_RAM_t i2c_ram = {
        {
            I2C_RAM,            // ID
            2,                  // 16bit address size
            //I2CMODE_ADDR,
            0,
            1024UL,             // ram size
            ram_Read_Data,
            ram_Write_Data,
            ram_stop,
            //(I2C_LED_t*) &i2c_led
            NULL
        },
        {}
    };

Functions:
// ----------------------------------------------------
// ----------------------------------------------------
unsigned char ram_Read_Data(void *this, unsigned long Address) {
    unsigned char   x;
    I2C_RAM_t      *ram = (I2C_RAM_t *) this;
 

    return ram -> Cell[Address];
}
// ----------------------------------------------------
// ----------------------------------------------------
void ram_Write_Data(void *this, unsigned long Address, unsigned char X){
    I2C_RAM_t *ram = (I2C_RAM_t *) this;
    
    ram -> Cell[Address] = X;
}
// ----------------------------------------------------
// ----------------------------------------------------

Stop not needed, table entry filled with NULL.
 
The RAM structure:
// ----------------------------------------------------
// ----------------------------------------------------
#define MEMSIZE      1024
// ----------------------------------------------------
// ----------------------------------------------------
#define I2C_RAM     0x321  // 10bit Chip ID
#define GCDATASIZE     20  // General Call
// ----------------------------------------------------
typedef struct {
    i2cslave_t      Slaves;
    unsigned char   Cell[MEMSIZE];              // at end of cell set pos 0
    unsigned char   GeneralData[GCDATASIZE];    // general data area
}I2C_RAM_t;
// ----------------------------------------------------
// ----------------------------------------------------

 
Then:
    err = i2c_generalcall_setup(Device_GeneralDataArea, GCDATASIZE);
 
    err =  i2c_addslavelist((void*) &i2c_ram);

post edited by Gort2015 - 2020/09/24 14:31:20

MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
https://www.youtube.com/watch?v=Iu1qa8N2ID0
+ ST:Continues, "What Ships are Made for", Q's back.
#14
Mysil
Super Member
  • Total Posts : 3809
  • Reward points : 0
  • Joined: 2012/07/01 04:19:50
  • Location: Norway
  • Status: offline
Re: dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line? 2020/09/24 16:23:37 (permalink)
4 (1)
Hi,
In my opinion, it is a bad idea to disable clock stretching when running I2C slave code on a microcontroller,
especially when running at a I2C clock frequency as high as 255 kHz.
I2C peripheral in microcontroller, may be able to shift bits in or out at 400 kHz, or even faster,
but this do not promise that MCU firmware will be fast enough to service bytes transferred without delay.
 
The first byte transferred after Start or Repeat Start condition, is Address byte from Master to Slave:
Slave code should Read this byte from I2CBUF register, when Address match interrupt occur,
and then immediately Write the first data byte into I2CBUF register, for transfer from slave to master.
Then if Clock Stretching is used, Release the clock by setting SCLREL bit before returning from interrupt processing.
 
    Mysil
#15
arigead
Super Member
  • Total Posts : 445
  • Reward points : 0
  • Joined: 2011/02/07 06:58:31
  • Location: 0
  • Status: offline
Re: dsPIC33EP128GS702 I2C Slave Mode not releasing the Clock line? 2020/09/28 04:06:27 (permalink)
0
Possibly disabling the clock stretching in I2C Slave mode is a bad idea but the master in this case is an IC which uses the interface to an I2C EEPROM chip to read configuration/program information. The IC probably started life as an FPGA which then got fabricated in an IC. So the IC blindly, or dumbly, executes the output pattern which would read an EEPROM. If I connect nothing to the clock and data lines, apart from pull up resistors the IC will blindly read back the number of bytes it wants to read. It will ignore the lack of Acknowledgement or anything else and read back all 0xFF as the configuration/Program. So in this case stretching the clock will probably not have the desired effect. Apart from the IC possibly reading back 0x00 instead of 0xFF.
 
I've already got a solution where by I bit bang the I2C Slave response in a synchronous fashion so loop on the clock pulse from the master and set the bit when it goes low and way till it goes low and set the next bit on the Data line. It works at 255KHz, possibly the I2C Peripheral won't work at that speed so that's the answer to this question. Just bit bang it.
#16
Jump to:
© 2020 APG vNext Commercial Version 4.5