News:

;) This forum is the property of Proton software developers

Main Menu

Busout / i2c on high speed pics

Started by TimB, Feb 06, 2023, 08:16 PM

Previous topic - Next topic

TimB

Hi all

I'm messing around with the i2c slave routines Gabi sent (all work done in Labcenter VSM)

Out of the box on a 2 x 18F452 at 4mhz they work

Swap the Slave for a 18f13k22 at 4mhz and its ok
Up the OSC on the slave to 64mhz and its ok

Changed the Master to a 18f13k22 at 4 mhz and ok

But making the master 64mhz and it fails, Adding Declare Slow_Bus = On and no luck so is there a limit to the Bstart Busout or i2c commands in the speed they can run? Or is there another way?

Thanks

Tim

tumbleweed

I wouldn't trust VSM for something like this, but looking at the i2c_slave.zip code in the other thread I see some issues.

The method of handling the CKP clock stretch bit in the slave isn't how it's normally done and doesn't match the app note code. The 'CKP = 0' statements are suspect.

From the datasheet...
QuoteThe SEN bit (SSPCON2<0>) allows clock stretching to
be enabled during receives. Setting SEN will cause
the SCL pin to be held low at the end of each data
receive sequence.

You then just set CKP=1 when you're ready to release the clock and continue.

Trying to manipulate CKP=0 the way it's done in that code would be very timing dependent.

TimB


Hi

The code does have clock stretching. But I feel the issue is the VSM in that it is playing to the rules. The clock speeds etc will be to fast and it is catching it.

Tim

tumbleweed

QuoteThe code does have clock stretching.
Yes, but the method used isn't the way it's typically done.

If you read the app note, in the mssp setup it sets the SEN bit in SSPCON2, which will make the clock stretching automatic. Then in the isr you just set CKP to release the clock.
The code in the zip file tries to clear and set CKP on the fly, which would make it very dependent on the timing of the slave/master transactions.

QuoteWhen the SEN bit of the SSPCON2 register is set,
SCL will be held low (clock stretch) following each
received byte. This helps to prevent another byte from
being received. The clock must be released by setting
the CKP bit of the SSPCON1 register.


I wouldn't trust VSM to simulate this correctly.

Pepe

#4
I have fixed simulation in proteus and works fine at 64mhz
In the simulation the frequencies of the pic must be in 16mhz to work at 64mhz because the pll is enabled in the configuration of the pic and also the 10k resistors must be digital non-analog

TimB

The issues as seen by the VSM is the speed is wrong. The slave is not even getting the option

The i2c debugger is seeing at 32mhz  S 60 A 00 A 01 A 02 A 03 A P

at 48mhz S P S Sr Sr P S Sr P S P S P........

The VSM has no issues with other aspects of speed changes

From the Positron manual

The standard speed for the I2C bus is 100KHz. Some devices use a higher bus speed of
400KHz. If you use an 8MHz or higher oscillator, the bus speed may exceed the devices specs,
which will result in intermittent writes or reads,

At 64mhz were are talking 8 x faster.







TimB

Quote from: Pepe on Feb 07, 2023, 12:23 PMI have fixed simulation in proteus and works fine at 64mhz
In the simulation the frequencies of the pic must be in 16mhz to work at 64mhz because the pll is enabled in the configuration of the pic and also the 10k resistors must be digital non-analog

Ahh you genius them pesky pullups

Thanks all working now :)

 

tumbleweed

I see these comments in the I2C_master.bas file for the K22:
Quote; Slave pic must have i2c hardware (SSP) And have High clock speed


;; Small delays are To allow time For slave To get To And from
;; Interrupt handler.
and the use of 'delayus()' calls to slow down the master.

If clock stretching is done properly none of this is required... that's the whole point of clock stretching to begin with- to throttle the master transfers to the speed at which the slave can accept then.

None of the master->slave code I've done requires delays, and there's no speed requirement on the slave clock.



tumbleweed

and I forgot to mention...

@TimB - you might want to check out the errata for the 13K22/14K22 if that's the part you're interested in. It has some nasty errors in the USART and MSSP peripherals that they've never seen fit to fix.

Gabi

Remove delays, see if its running as expected. It should, without any issue.

Delays were there in that code as 17 years ago I was performing some debug/test with that code.

Btw, imho:  'based on' != 'copy/paste'.

Good luck.
GL & 73
YO4WM

Pepe

No lag also works

tumbleweed

QuoteBtw, imho:  'based on' != 'copy/paste'.
That's true, but the code is not properly using clock stretching as called out in the datasheet or app note code.

By not setting SEN in SSPCON2 and manually clearing/setting CKP in the slave isr you've created a race condition where the slave must beat the master, otherwise clock stretching will fail.

I'm not going to argue... if you believe the code is correct then good for you.

TimB


From the i2c org

Clock Stretching in High Speed Mode
Clock stretching in High-Speed-Mode is only allowed after the ACK bit (and before the 1st bit of the next byte). Stretching between bits 2-9 is illegal because the edges of these bits are boosted with an additional current source. See I2C specification Rev. 03 chapter 5.3.1 for further details.

Since I am using highspeed mode managing the clock is impossible from the slave side to slow the clock until you are given the opportunity to eg when you need time to collect data to place in the buffer as per Gabi's example.



 

tumbleweed

Gabi's example is exactly what you're pointing out. It tries to assert the clock hold at random times.

I have done extensive work with I2C on dozens of commercial products,some with over 60 slaves and multiple masters at speeds in excess of 1Mhz.

I'm not guessing about how this works... I'm very familiar with the spec.


TimB


Hi tumbleweed

So you recommend removing the CKP manipulation?

Thanks Tim

tumbleweed

#15
Not entirely...

First, change the setup portion to enable SEN. This will let the mssp automatically hold the clock
   SSPCON1 = $36            ' SSP settings: i2c slave mode, 7-bit address, enable SSP
   SSPADD = SLAVE_ADDR      ' Initial slave address setting
' disable general call addr, enable slave clock stretch (SEN=1)
'   SSPCON2.7 = 0            ' disable  general call address 
   SSPCON2 = $01        ' **ADDED**
   SSPSTAT = 0              ' Clear SSP Status reg

Then, change the isr to remove the 'CKP=0' statements. Leave 'CKP=1' since that's what releases the clock hold and lets things continue.
MAIN_I2C_ISR:                                        ' i2c Interrupt Service Routine
Context Save
     SSPIF = 0                                      ' Clear SSPIF interrupt bit
      CASE_SWITCH = SSPSTAT & %00101101              ' Mask SSPSTAT reg and keep only D/A, S, R/W and BF bits
      Select CASE_SWITCH
             
         Case STATE1                                 ' Master write operation, address Byte goes in SSPBUF.
' REMOVED
' this should never occur... we're clock stretching
'              SSPOV = 0                              ' Clear the receive overflow flag
'              CKP = 0                                ' Hold SCL low
              M_TO_S_BUF_INDEX = 0                   ' Reset the data (Master-->Slave) buffer index
              M_TO_S_BUF[M_TO_S_BUF_INDEX] = SSPBUF  ' Dummy read to clear BF
              CKP = 1                                ' Allow master to continue by re-enabling SCL
 
         Case STATE2                                 ' Master write operation, Data Byte (Master-->Slave) in SSPBUF
' REMOVED
' this should never occur... we're clock stretching
'              SSPOV = 0                              ' Clear receive overflow flag
'              CKP = 0                                ' Tell Master to wait by holding SCL low
              M_TO_S_BUF[M_TO_S_BUF_INDEX] = SSPBUF  ' Move received byte to buffer (Master-->Slave)
              Inc M_TO_S_BUF_INDEX                   ' Increment buffer Index
              CKP = 1                                ' Tell Master to continue by re-enabling SCL

         Case STATE3                                 ' Master is beggining a new Read operation by initiating a START Or RESTART
' REMOVED
'              CKP = 0                                ' Tell Master to wait by holding SCL low
              S_TO_M_BUF_INDEX = 0                   ' Reset buffer index
                                                     ' USB Buffer should be loaded with new data at this point
              SSPBUF = S_TO_M_BUF[S_TO_M_BUF_INDEX]  ' Loads the first byte (from USB_BUF Slave-->Master) to be sent
              Inc S_TO_M_BUF_INDEX                   ' Increment buffer Index
              CKP = 1                                ' High SCL so Master can get the Byte by shifting it out
             

         Case STATE4                                 ' Master Read operation, last Byte was Read Data (ie STATE3), SSPBUF empty.
' REMOVED
'              CKP = 0                                ' Tell Master to wait by holding SCL low
              SSPBUF = S_TO_M_BUF[S_TO_M_BUF_INDEX]  ' Get next byte (from USB_BUF Slave-->Master) To be sent
              Inc S_TO_M_BUF_INDEX                   ' Increment buffer Index
              CKP = 1                                ' High SCL so Master can get the Byte by shifting it out

         Case STATE5                                 ' A nack (High) was received from Master in response To Data
                                                     ' Byte received from Slave (last Byte). Slave i2c logic is reset,
                                                     ' And waits For Next Master operation.   
      EndSelect                                      '
Context Restore

I also commented out clearing the receive overflow flag SSPOV. Since we're controlling the clock it shouldn't be possible for an overflow to happen.

I usually have a little bit more code for handling the receive data, but I left the rest of it alone.
You shouldn't need any delays in the master code.


TimB


Hi tumbleweed

Thanks, sorry for the confusion.

The code posted by Gabi was very old and just an example for me to build on. I have loads to add like controlled writing of registers eg set a couple of flags in the first byte or subsequent writes are ignored etc etc All in the interrupt.

I understand now how your modifications work, eg clock stretching is automatic every time until the code releases it.