PCF8574/PCF8574A I2C lockup on Picaxe 20X2 @ 64MHz

PhilHornby

Senior Member
I just bought myself a third Sainsmart LCD2004 and was surprised to find it behaving somewhat differently to the previous two, when connected to a Picaxe 20X2.

[The Sainsmart LCD2004 is a HD44780 compatible LCD, connected to an I²C I/O expander]

My first two devices have a PCF8574 on-board, wired to respond to I²C address $3F. The new one has a PCF8574A instead. The difference being that this one responds to I²C address $27 instead (being similarly wired). From my research, this is the main difference between the two devices - though I'm suspecting there may be something else...

I have an LCD diagnostic program, which when run on a Picaxe 20X2 @ 64MHz, does not work with the new (PCF8457A) device. It results (fairly quickly, if not instantly) in an I²C bus 'lock-up', that requires the technique described by edmunds, in this thread, to fix. I modified my test program so that I could have old and new LCD displays on the bus at the same time - it was always when addressing the new one, that the problem occurs. (The problem being the SDA line stuck low and neither device responding).

Lowering the Picaxe clock speed to 32MHz meant the problem was no longer reproducible - both devices work correctly....

I looked in more detail at the I2Cslow_x parameters that I was passing into my HI2CSetup call. They have the following decimal values (ignoring the top bit, which AIUI is only used on input) :-
Code:
i2cslow_4 = 9
i2cslow_8 = 19
i2cslow_16 = 39
i2cslow_32 = 79
i2cslow_64 = 127

It struck me that they double in value, as the clock speed doubles - apart from the last one. Doesn't this mean that @ 64MHz, the i2cslow_64 parameter results in an I²C bus running @ 125KHz instead of 100KHz? ... (I may have misunderstood how this works!)

If this theory is correct, it's amazing that any I²C devices work with the 20X2 @ 64MHz ?!?

I tried running the Picaxe @ 32MHz, but using the i2cslow_16 parameter instead. I expected this to result in instant failure on both devices ... yet, they both seem perfectly happy. Isn't the I²C bus speed running at 200KHz under these circumstances? :confused:

Any thoughts as to what I'm seeing? - Although I can work around my problem, I'd like to understand what's going on.
 

kranenborg

Senior Member
Hi Phil,

The PCF8574A and the likes (non-A) are relatively old devices that are guaranteed to work only at a slow I2C speed of up to 100kHz, as per the datasheet. So I suspect that you had sheer luck with a few of them working just above 100kHz. That would be my explanation of the different behavior you just reported on. More modern I2C devices with a similar functionality are rated at a 400kHz or even 1.2MHz bus speeds (e.g. MCP23008 obeys the latter) and thus should function properly at all circumstances.

regards,
Jurjen
http://www.kranenborg.org/electronics
 
Last edited:

BESQUEUT

Senior Member
I tried running the Picaxe @ 32MHz, but using the i2cslow_16 parameter instead. I expected this to result in instant failure on both devices ... yet, they both seem perfectly happy. Isn't the I²C bus speed running at 200KHz under these circumstances? :confused:
I2C can run as low as 1hz or less (YES you can make it "by hand" with 2 switchs)
100 kHz or 400khz are max values for normal or high speed I2C, as said by kranenborg.
Any lower values will work.
 

Buzby

Senior Member
I2C can run as low as 1hz or less ...
If you want to run I2C as slow as this, first check the datasheet for the slave.

Some slaves, ( I can't remember which ), will timeout and reset if they don't see a fast enough clock.

Cheers,

Buzby
 

Goeytex

Senior Member
As noted by Kraneborg, the PCF8574/A is rated at 100kHz. This applies to genuine parts from TI or ON which i doubt will be found on $2 Asian sourced I/0 expanders. That being said I have setup probably 30 of these and have yet to come across one that did not work reliably at 400kHz. I recently pushed one to > 600kHz before it failed.

My guess is that the PCF8574A that you are having to slow down is from a different fab source than your previous ones.

Even though these cheap LCD adapters usually have 10k pullup resistors on board, this is generally not enough. I add additional pullup resistor from 2.2K to 4.7K depending upon the length of the SCL/SDA lines. You may want to try 2.2K pullups and see what happens.
 

inglewoodpete

Senior Member
I looked in more detail at the I2Cslow_x parameters that I was passing into my HI2CSetup call. They have the following decimal values (ignoring the top bit, which AIUI is only used on input) :-
Code:
i2cslow_4 = 9
i2cslow_8 = 19
i2cslow_16 = 39
i2cslow_32 = 79
i2cslow_64 = 127

It struck me that they double in value, as the clock speed doubles - apart from the last one. Doesn't this mean that @ 64MHz, the i2cslow_64 parameter results in an I²C bus running @ 125KHz instead of 100KHz? ... (I may have misunderstood how this works!)

Any thoughts as to what I'm seeing? - Although I can work around my problem, I'd like to understand what's going on.
You may need to do a bit of heavy reading of the PIC18F14K22 data sheet regarding the Baud Rate Generator (BRG) for i2c. [Edit: I've just had a look at the data sheet and it's a bit light-on in that section. No discussion of clock frequencies above 48MHz!] A short cut may be to substitute a value of 159. Is this possible - you refer to the MSBit affecting AIUI (I can't find AIUI in the data sheet)? Does that mean that the BRG divider value is limited to 7bits?
 
Last edited:

PhilHornby

Senior Member
Working now...

Thanks for the input, everyone.

I've now got it working. What I hadn't taken into account at all, were the physical connections I was using; with shorter leads and a couple of extra pull-up resistors, close to the Picaxe, it burst into life.

I attached my Salae logic clone and grabbed a bit of data from the bus: at Picaxe speeds up to 32MHz, the bus is running @ approx. 98KHz. With the Picaxe @ 64MHz, I measure the I²C bus speed as 117KHz...which I would say, is out-of-spec!

@inglewoodpete: AIUI = As I understand It :) ... but it turns out I don't quite understand it. If I manually set the speed parameter without the top bit set, it doesn't work the same as with it set.
 

inglewoodpete

Senior Member
@inglewoodpete: AIUI = As I understand It :) ... but it turns out I don't quite understand it.
AIUI - ASM. I must be at the point in life where Another Senior Moment is becoming more prevalent :). Too many acronyms.

So, does a BRG divider of 159 bring the data rate down to ~100kHz?
 

hippy

Technical Support
Staff member
It is somewhat confusing.

At 16MHz the divisor should be 39 which is what is held in the seven lsb's of I2CSLOW_16, at 32MHz it should be 79, and at 64MHz the divisor should be 159. However, as the divisor can only have seven bits the highest it can be is 127. This means that at 64MHz the I2CSLOW_64 bus will run faster than it should; 125kHz.

The recommended workround would probably be to use I2CSLOW_32 in the HI2CSETUP command and drop the PICAXE operating speed to 32MHz when using the I2C bus.

However it may be possible to poke 159 directly to the SPADD SFR register.

I thought the 64MHz limitation was documented but I have not found where. We will need to investigate that further.
 

PhilHornby

Senior Member
However it may be possible to poke 159 directly to the SPADD SFR register.
I tried this, as an experiment. I used one of my original PCF8574A-equipped displays (which is seemingly perfectly happy with the Picaxe @ 64MHz and the bus @ 120KHz).

I added the following line of code:-

Code:
pokesfr $C8,159
and it stopped working!

I can see from my 'scope that the average frequency drops from 120KHz (ish) to 98KHz (ish) ... and the signals all still look plausible (though I've not analysed any in detail). I used the decoder in the Salae software to look at a few of the data exchanges - and nothing leaps out at me there either.

I went back and used some other Picaxe frequencies and pokesfr'd the equivalent values in. Only pokesfr'ing 159 @ 64MHz upsets it - for whatever reason.
 

PhilHornby

Senior Member
Only pokesfr'ing 159 @ 64MHz upsets it - for whatever reason.
Actually, there's more to it...

I modified the program to start with Hi2csetup - i2cslow_64, followed by 'pokesfr $C8,159'. It then loops, decrementing the value in SSPADD ($FC8) and thereby increasing the bus frequency.

Using the PCF8457A display, nothing happens until SSPADD reaches 137, when a few splurges of data start to appear on the LCD. At SSPADD = 135, it starts working properly - but stops @ SSPADD=130 with a bus lock-up that needs a Power-cycle to clear.

Continuing, it works all the way down to about 8 ish !!! (My scope was saying 600+KHz SCL average frequency at this point!). Actually, I say it works - but my "LCD diagnostic" was running so fast at this stage, it was hard to read it!

As SSPADD goes below 8 or so, the SDA output breaks up into a MHz region, unstable mess. At some point later, after SSPADD underflows back to 255, SCL settles down as a nice 68KHz square wave ... :cool:

Just to confirm what I'd seen, I tried a simple Hi2csetup - i2cFAST_64 ... and, yes - that particular LCD display is perfectly happy at 400KHz!

Weird!
 
Last edited:

westaust55

Moderator
I did a bit more digging myself based upon hippy's earlier comment.
There was a statement on the i2c BRG value range by Technical as follow back in 2009:

Actually these i2cslow numbers are correct, as bit7 in the BASIC command is used as the SSPSTAT.SMP slew control bit (see hi2csetup command in manual 2 - advanced details). That is why the numbers are 128 greater than you expected - as the slew control bit is enabled by bit 7.

The theroretical value for 64MHz is indeed $9F (159) , but the max value that is actually possible in that baud register is 127 (bit 7 is not used when reloading the baud rate generator). So you can only ever use assembler baud values of 3 to 127 (0-2 also don't work if you read the errata sheets for that PIC type!).

So at i2cslow_64 127 is used (as the nearest possible) + 128 = 255.
EDIT:
Actually the same information does exist in PICAXE Manual 2 V7.9.2 (2015) at Page82 also as:

Advanced Technical Information:
Users familiar with assembler code programming may choose to create their own
‘mode’ settings to adjust the i2c communication speed. The mode value is a value
between 0-127 that is the preload BRG value loaded into SSPADD. Bit 7 of the
mode byte is used to set/clear the SSPSTAT,SMP slew control bit.
 
Last edited:

hippy

Technical Support
Staff member
I did a bit more digging myself based upon hippy's earlier comment.
There was a statement on the i2c BRG value range by Technical as follow back in 2009:
Many thanks for finding that. That confirms the maximum divisor setting of 127 but doesn't explain why things don't work when 159 ($9F) is poked direct to SSPADD.

It could be the slew-rate bit affecting the bus, but that seems unlikely when it's able to run faster with higher and lower values poked in. I haven't even checked the datasheet but it should be possible to try both with and without ...

HI2cSetup ... , $FF : PokeSfr SSPADD, 159 ; with
HI2cSetup ... , $7F : PokeSfr SSPADD, 159 ; without
 

PhilHornby

Senior Member
More experiments...

...it should be possible to try both with and without ...

HI2cSetup ... , $FF : PokeSfr SSPADD, 159 ; with
HI2cSetup ... , $7F : PokeSfr SSPADD, 159 ; without
I tried both of these - but to no avail.

I simplified my program somewhat, to see if I could spot what's going on. I tried a few variations on the following theme :-

Rich (BB code):
      hi2csetup i2cmaster,LCDAddress ,i2cslow_64, i2cbyte ; Need to set up I2c before we can use it.
      pokesfr sspadd,159
           
      hi2cout 0,("*")
     
      end
In other words, it outputs a single byte "*" ($00101010, or 42dec). LCDAddress is $3F or 63dec (PCF8574A).

At 32Mhz, using i2cslow_32 (and no pokesfr) I get what you'd expect ...

32MHz.png

Increasing Picaxe close to 64MHz and using i2cslow_64 (again no pokesfr) ... gives roughly the same, but at a higher frequency:-

64MHz.png

Can't add another attachment, so continuing in next post ...
 
Last edited:

PhilHornby

Senior Member
Data, what data?

When I add the pokesfr 159 into the mix, there's no longer any data being output!

64MHz_pokesfr159.png

Just to add - pokesfr 136 gives the same result as above. Pokesfr 135 makes the data come back.

Scope traces, as above:-

CombinedScopeTraces.png
 
Last edited:

westaust55

Moderator
From reading the PIC datasheet either only 7 bits are used for the i2cMaster Baud Rate Generator and/or there are typo conflicts in the PIC datasheet:

14.3.3.1 Addressing
Once the MSSP module has been enabled, it waits for a Start condition to occur. Following the Start condition, the eight bits are shifted into the SSPSR register. All incoming bits are sampled with the rising edge of the clock (SCL) line. The value of register SSPSR<7:1> is compared to the value of the SSPADD register. The address is compared on the falling edge of the eighth clock (SCL) pulse.

From the above reference as: SSPSR<7:1> is only using 7 bits through the following sentence mentions 8th clock pulses.

PIC datasheet in FIGURE 14-16: MSSP BLOCK DIAGRAM (I2C MASTER MODE)
Depicts only SSPADD<6:0> which is only 7 bits (not 8 bits)

However, FIGURE 14-17: BAUD RATE GENERATOR BLOCK DIAGRAM
Depicts SSPADD<7:0> inferring all 8 bits are used for the i2c BRG

However, next in the PICA datasheet we have:
14.3.7.1 Clock Arbitration
When the SCL pin is sampled high, the Baud Rate Generator is reloaded with the contents of SSPADD<6:0> and begins counting.

Again this infers that only 7 bits (not 8) are loaded

From the Mikro-Electronic assembler manuals we see that only the low 7 bits are suggested as being utilised.
Mikroe_Extract.jpg


On the Microchip forums I found several references such as:
Only the low 7-bits of SSPADD are used for the I2C Baud Rate Generator.
This give you division factors from 1 to 128.
Actually the low 7 bits would allow values 0 to 127.


If we look at some other Microchip datasheets, eg:
http://ww1.microchip.com/downloads/en/devicedoc/39632c.pdf
then we see that both figures 19:18 and 19:19 show SSPADD<6:0>

So it would seem that only the lower 7 bits are used and that the PIC16F1XK22 related datasheethas an error at figure 14:17
 
Last edited:

PhilHornby

Senior Member
Although you have demonstrated there is still considerable confusion regarding the size of the BRG, didn't Microchip's answer to Technical, in the earlier thread you highlighted, give the definitive answer?

If the BRG was being mis-interpreted as only 7 bits, wouldn't this just result in a bus that was running much faster than normal - rather than one that mis-behaves?

I modified my test program slightly, to send two bytes before terminating, but it still shows the same pattern:-

Rich (BB code):
#picaxe 20x2
#no_data
#no_table
#terminal 76800
symbol LCDAddress = %01111110             ;I2C address of Display (PCF8574A) = $3F, (shifted left one bit).
;symbol LCDAddress = %01001110            ;$27 - new display has PCF8574                                    
symbol sspadd = $C8
      pause 5000                          ;chance to start logging.
      setfreq M64                         ;maximum bananas
      hi2csetup i2cmaster,LCDAddress ,i2cslow_64, i2cbyte ; Set up I2c
     
      pokesfr sspadd,159                  ;update SSPADD with 'correct' value
      peeksfr sspadd,b0                   ;prove it worked...
      sertxd (cr,lf,"SSPADD=",#b0)        ;...by printing it
     
      hi2cout 0,("*U")                    ;transmit "*U" 42+85 (00101010+01010101)
     
      end
The strange absence of data is still apparent:-

TwoBytes.png
 
Last edited:

PhilHornby

Senior Member
In search of the missing data...

Playing around with my test program, I noticed that if you try often enough, data does get sent with SSPADD = 159. However, the success rate is very low.

I'd previously thought the "work/not work" cutoff point was at 136 ... but it's not that simple. In a nutshell, it starts to fail at around the 135/136 mark and rapidly deteriorates after that. But the fact that it can work @ 159, might suggest a timing problem somewhere?

Examining some of the I²C registers, revealed that SSPBUF still holds the last byte transmitted - so I wrote a program to loop around checking its value after an 'hi2cout (1)' command. On success, it contains the '1', but in the failure scenarios, it contains the I²C address of the slave device (recall that the bus traces show that only the 'setup' is done, followed by no data).

UPDATE: On success, SSPSTAT, has the "P" bit set; on failure, the "S" bit is set instead. [P = Stop bit detected, S = Start bit detected. I don't really understand the significance of that...]

Rich (BB code):
#picaxe 20x2
#no_data
#no_table
#terminal 76800

symbol LCDAddress = %01111110             ;I2C address of Display (PCF8574A) = $3F, (shifted left one bit).
;symbol LCDAddress = %01001110            ;$27 - new display has PCF8574                                   


;
; I2C registers
;
symbol sspmsk = $6F
symbol sspcon2 = $C5
symbol sspcon1 = $C6
symbol sspstat = $C7
symbol sspadd = $C8
symbol sspbuf = $C9


#macro PrintSFR(sfr,label)
      peeksfr sfr,b0
      sertxd (cr,lf,label," = ",#bit7,",",#bit6,",",#bit5,",",#bit4,",",#bit3,",",#bit2,",",#bit1,",",#bit0)
#endm


      pause 5000                          ;chance to start logging.


      setfreq M64                         ;maximum bananas


      hi2csetup i2cmaster,LCDAddress ,i2cslow_64, i2cbyte ; Set up I2c
     
      gosub DumpSFR
     
      sertxd (cr,lf,"Changing SSPADD to 159")
     
      pokesfr sspadd,159                  ;update SSPADD with 'correct' value
     
      W27 = 0
do   
      sertxd (cr,lf,"hi2cout")
      hi2cout (1)                         ;Just send a 1


      gosub DumpSFR
      if b0 = 1 then                      ;last value examined is SSPBUF, should contain last byte sent (1)
            sertxd (" ** SUCCESS ** (Pass",#W27,")")  ;sspbuf = 1, which is what we were trying to transmit
            end
      endif


      pause 4000
      inc W27
loop 


      
DumpSFR:
      PrintSFR(sspmsk,"SSPMSK")
      PrintSFR(sspcon1,"SSPCON1")
      PrintSFR(sspcon2,"SSPCON2")
      PrintSFR(sspstat,"SSPSTAT")
      PrintSFR(sspadd,"SSPADD")
      PrintSFR(sspbuf,"SSPBUF")
      return
So, I thought - let's try and replace hi2csetup and hi2cout with 'peeksfr/pokesfr' ...

The PIC18(L)F1XK22 data sheet gives the following clues...
Master mode is enabled by setting and clearing the appropriate SSPM bits in SSPCON1 and by setting the SSPEN bit.
and

A typical transmit sequence would go as follows:
1. The user generates a Start condition by setting
the SEN bit of the SSPCON2 register.
2. SSPIF is set. The MSSP module will wait the
required start time before any other operation
takes place.
3. The user loads the SSPBUF with the slave
address to transmit.
4. Address is shifted out the SDA pin until all 8 bits
are transmitted.
5. The MSSP module shifts in the ACK bit from the
slave device and writes its value into the
ACKSTAT bit of the SSPCON2 register.
6. The MSSP module generates an interrupt at the
end of the ninth clock cycle by setting the SSPIF
bit.
7. The user loads the SSPBUF with eight bits of
data.
8. Data is shifted out the SDA pin until all 8 bits are
transmitted.
9. The MSSP module shifts in the ACK bit from the
slave device and writes its value into the
ACKSTAT bit of the SSPCON2 register.
10. The MSSP module generates an interrupt at the
end of the ninth clock cycle by setting the SSPIF
bit.
11. The user generates a Stop condition by setting
the PEN bit of the SSPCON2 register.
12. Interrupt is generated once the Stop condition is
complete.
Sadly, I've reached some forum limit or other, so the next thrilling instalment is in the next post :rolleyes:
 
Last edited:

PhilHornby

Senior Member
In search of the missing data, continued ...

This code :-

Rich (BB code):
#picaxe 20x2
#no_data
#no_table

symbol LCDAddress = %01111110             ;I2C address of Display (PCF8574A) = $3F, (shifted left one bit).
;symbol LCDAddress = %01001110            ;$27 - new display has PCF8574                                   


;
; I2C registers
;
symbol sspmsk = $6F
symbol sspcon2 = $C5
symbol sspcon1 = $C6
symbol sspstat = $C7
symbol sspadd = $C8
symbol sspbuf = $C9


;
; SSPCON2 bits
;
symbol SEN = 0
symbol PEN = 2
symbol ACKSTAT = 6


      pause 5000                          ;chance to start logging.


      setfreq M64                         ;maximum bananas
;
; DIY i2c
;


      pokesfr sspadd,159                  ;set divisor for 100KHz @ 64MHz clock
     
      b0 = %00101000                      ;SSPEN + SSPM3. Enable SDA/SCL and set Master mode
      pokesfr sspcon1,b0                  ;enable
     
      peeksfr sspcon2,b0
      setbit b0,SEN                       ;Generate start condition
      pokesfr sspcon2,b0
     
      pokesfr sspbuf,LCDAddress           ;set slave address
      'pause 1                            ;pretty sure this isn't needed!
      peeksfr sspcon2,b0                  ;bit 6 is ackstat and should be zero
      if b0 bit ACKSTAT set then
            sertxd (cr,lf,"NAK on address")
            end
      endif
     
      pokesfr sspbuf,1                    ;let's send a 1.
      'pause 1                            ;pretty sure this isn't needed either!
      peeksfr sspcon2,b0                  ;bit 6 is ackstat and should be zero
      if b0 bit ACKSTAT set then
            sertxd (cr,lf,"NAK on data")
            end
      endif


      peeksfr sspcon2,b0
      setbit b0,PEN                       ;generate Stop condition.
      pokesfr sspcon2,b0
      end
successfully transmits a single byte of data @ 100KHz, with the 20X2 @ 64MHz.

As shown here:-

DIYI2C.png

(Remember, this isn't bit-banged - this is using the 20X2's I²C hardware support.)
 
Last edited:

westaust55

Moderator
Well done on solving / producing a usable workaround. :)

It is strange that albeit Microchip informed Technical back in 2009 that the BRG was in fact 8 bits for the 20X2 PIC part that even the datasheet now dated as 2016 still has the same inconsistency.
 

inglewoodpete

Senior Member
Sadly, I've reached some forum limit or other, so the next thrilling instalment is in the next post :rolleyes:
Yes, the forum limits member's excitement to 10,000 characters at a time :).

Well done for persisting and getting work-around. I've made a note of it for future reference.
 

AllyCat

Senior Member
Hi,

Sadly, I've reached some forum limit or other, so the next thrilling instalment is in the next post :rolleyes:
It was very probably the multi-coloured PE6 code that did it ! ;)

Yes, there are still a few "bugs" in both the Microchip silicon and the PICaxe compiler/interpreter/editor. I've also learnt the hard way that sometimes it can be worthwhile to bypass the "normal" instructions and test with PEEK/POKESFRs instead. Well done!

Cheers, Alan.
 
Top