Does size matter? 10-bits is a bit too much for i2c - Page 1
Forum section: electronics / general

author: Salome2
author_rank: Regular Contributor
timestamp: September 11, 2022, 10:25:42 am
content: Below is the code for a I2C configured as a Master 7-bit Addr sending to a Slave MCU and both are configured without Start/End IRQ configuration.I can't get my Slave MCU (both master and slave are pic18F252) to respond and I don't get any SSPIF when I socket the Slave MCU when this write address starting frame is sent. You can see the 0x20 address sent to it! (Addr1=0x20;)The Nack is clearly seen where Ack should be, identifying this bit as the Ack/Nack bit, but it's 10th in line.But what astonishes me is that I see a 10-bit frame when SEN starts sends this address! I can't make any SEN of this?Although you can't see it on the scope trace attached, the Start and Stop events are clearly ok. I2C baudrate 400KHzSlave mcu is not inserted in socket, this is only the Master's game.Attached is the scope trace that shows what I am talking about.I have run out of hair to pull out. This I2C is driving me SEN seless!There's an extra bit at the start!Is this normal? What do am I doing wrong?//00000000000h ooooooooooooooooooh!void GetDat() //Receiving data doesn't require interrupt ISR, Sending does.{if(SSt==Begin){ if(SSPOV || WCOL){ AdrRec=0; //just a 8-bit var to check the address being senti2c_Setup();goto xitgetdat;}hh=0;uu=0;bn=0; //all unsigned int 16-biti2c_start();SSPBUF=Addr1<<1; //address 0x20 sent to Slv in write modewaitmssp();bn=0;OhOh=0;W4Ack:while(ACKSTAT) //Waiting for Ack of address from SlaveLATD5=1;LATD5=0;hh++;if(hh>1000){ OhOh=1;LATD6=1;LATD6=0;i2c_stop();break;}}if(ACKDT){ OhOh=2;AdrRec=SSPBUF;i2c_stop();goto badxit;}if(OhOh)goto badxit; //Error got a Nack instead of ackW4byterec:if(BF==0){ uu++;if(uu>65534){ OhOh=3;goto badxit;}goto W4byterec;}Rx=SSPBUF;i2c_ack();SSPIF=0;}void i2c_start(){SEN=1;waitmssp();}void i2c_stop(){PEN=1;waitmssp();}void i2c_ack(){ACKDT=0;ACKEN=1;waitmssp();}void i2c_nak(){ACKDT=1;ACKEN=1;waitmssp();}void waitmssp(){while(!SSPIF);SSPIF=0;}

author: PCB.Wiz
author_rank: Super Contributor
timestamp: September 11, 2022, 08:17:29 pm
content: Quote from: Salome2 on September 11, 2022, 10:25:42 amIt is normal to see 9 clocks, which is 7 bits of address 1 bit of R/W and then the ACK.Some i2c parts have extended address, but you have too few clocks for thathttps://www.totalphase.com/support/articles/200349176-7-bit-8-bit-and-10-bit-I2C-Slave-AddressingIf you have bogus output, one approach could be to slow things down with debug delays between each i2c access.If you have setups or access-before-done issues you can get strange pin results.Also try send of different address values to see where the bogus clk appears. (beginning or end?)The first CLK is narrower, unsure if that is a clue or an artifact.

author: DavidAlfa
author_rank: Super Contributor
timestamp: September 11, 2022, 09:03:49 pm
content: You're lacking all the calls, and the most important part, the setup/initialization.Also the gotos... uhh no good, are you coming from old school assembly?Do you really understand how i2c works? Some basics:https://openlabpro.com/guide/basics-of-i2c/https://rheingoldheavy.com/i2c-signals/Of course you're not getting ACK, ACK is set by the slave by pulling SDA low, which you aren't connecting, so you're getting a NACK!Show us the rest of your i2c-related code for the slave & master...How is your circuit? And the pullpup resistors?It's clearly 100KHz, not 400.Your waveforms look wrong, i2c lines should be floating (high) when idle, but SDA is LOW before/after your clocks.This is how a byte transfer should look:The NAK at the end means the receiver doesn't want more bytes, thus ending the transfer.But for the address, a matching receiver will always acknowledge.10-bit addressing actually sends 2 bytes addressing bytes, not 10 bits! (You must take care of each of these bytes)Check pages 144-145 of thePIC18F252 datasheet! Better you throughly read the i2c section again

author: Salome2
author_rank: Regular Contributor
timestamp: September 12, 2022, 12:56:25 am
content: Thanks PCB.wiz, I have shifted the address sent and the scope clearly shows the first narrow bit is a puzzling glitch on the data line.If I shift the address left 3-bits, the one-bit of ox20<<3 disappears, while SSBUF=Addr1<<2 can still see the one bit as if setting the Slave an address of 0x40The glitch bit on the left only occurs if I use SEN to start the address transmission.I don't know why right after the SEN start event the clock is held low before starting to transmit the address bits ( using the code I have posted!)I do expect the Ack bit to be a Nack, as the Slave mcu is not inserted in its socket.All P/S voltages AOK, proper caps bypassing on the VDD pins.I am using 1-K pullups for I2C Clk and Data The 1k's are positioned right at the Slave mcu Clk and Data pins of the second Slave(also not yet inserted while I try to resolve this glitch bit problem.) The total wire twisted pair length of Master to 2nd Slave <5-in.Below is my setup code for I2C-------------------------------------void i2c_Setup() // (for the Master mcu){WCOL1=0;SSPOV1=0;SSPCON1=0x28;//SSP Module as Master 7-bt address I2C mode and Enabled /b]TRISC3=1;TRISC4=1; //Sets I2C clock and data pins as inputsSSPADD=((40000000/4)/400000)-1; //Setting I2C Baud/Clock Speed at , My Fosc = 40MHz 10MHz ext. Xtal PLL*4SSPSTATbits.SMP=1; //SMP Must be off=1 for i2cSSPIF=0;Addr1=0x20; //I2C address of first SlaveSSt=Begin; //The MSSP operation state var ( Stores Begin as MSSP I2C state to start communication by sending Addr1 )}void waitmssp(){while(!SSPIF);SSPIF=0;}void i2c_ack(){ACKDT=0;ACKEN=1;waitmssp();}void i2c_nak(){ACKDT=1;ACKEN=1;waitmssp();}

author: Salome2
author_rank: Regular Contributor
timestamp: September 12, 2022, 01:36:09 am
content: Thanks DavidAlfa. I assure you I have read and studied carefully so many datasheet I2C pages.(18F25K22, 16F18446, 18F252 and Microhip AN734,735 apnotes and also watched several videos on Youtube. )It is quite fascinating that almost everything, (especially Youtube videos) I've seen is almost always the same old story, almost all info I googled assumes a mcu is talking to an EEPROM, very little info out there shows interfacing MCU<-->MCU in C code(..and I don't do assembly.)Many thanks for posting a scope pattern I've seen over and over again, except yet on my scope.

author: DavidAlfa
author_rank: Super Contributor
timestamp: September 12, 2022, 02:57:02 am
content: You want help but you're still missing all the slave i2ccode...can't help more with so little details.

author: Salome2
author_rank: Regular Contributor
timestamp: September 12, 2022, 09:23:30 am
content: Thanks DavidAlfa for your kind help! Below is my Slave mcu code.I didn't think it was time to post the mcu Slave code when the Master sends leading extra bit prob was not resolved.void i2c_Setup() //MSSP Module as Slave{Addr1=0x20; //first SlaveAddr2=0x40;TRISC3=1;TRISC4=1;//Clk and Data TRIS'd as inputs Slave or Master modeSSPADD=Addr1<<1;//FirstSlave Addr1=0x20 (I have also tried SSPADD=Addr1; with still no acknowledge.)SSPSTATbits.SMP=1; //1=slew rate disabled, won't work without SMP setSSPCON1=0x26;//7-bit I2C Slave mode Enabled with no IRQs Enab for Start/Pen eventsSSt=Begin;SSPIF=0;}void interrupt high_priority hp(void) //Note: this code has minimized/modified just to see if any I2C address match event{if(SSt==Begin){ if(SSPIF){ LATC5=1;LATC5=0;LATC5=1;LATC5=0; //blips to watch on scope to detect if a SSPIF occurs(Unfortunately not yet blipped!)i2c_ack();}if(BF){ LATC5=1;LATC5=1;LATC5=1;LATC5=1;LATC5=1;LATC5=1;LATC5=0;Rx=SSPBUF;if(Rx==0x20){ LATC5=0;LATC5=0;LATC5=0;LATC5=0;LATC5=1;LATC5=1;LATC5=0;LATC5=1;LATC5=1;LATC5=0;i2c_ack();}}}/* This code is not ready for prime time until slave address issue is resolvedif(SSt==Begin){ if(BF!=1){ SSPIF=0;CKP=1;goto Xiti2c;}if(BF)i2c_ack();qq=SSPBUF; //address match qq=Addressif(qq & 1) //OK to start sending data to MAS{ SSt=Ready2Send;bn=1;Try2Send=0;CKP=0;}}else if(SSt==Ready2Send){R2Send:if(BF==0){Sends++;if(bn<70){Try2Send=0;Sends++;SSPBUF=Tx;SSPIF=0;CKP=1;}else{ SSt=Begin;CKP=1;SSPIF=0;i2c_stop();}goto Xiti2c;}else{Try2Send++;if(Try2Send<3){goto R2Send;}else{ goto badxit;}}}else{badxit:Senderr++;SSPOV=0;WCOL=0;SSPIF=0;CKP=1;SSt=Begin;}*/void waitmssp(){while(!SSPIF);SSPIF=0;}void i2c_ack(){ACKDT=0;ACKEN=1;waitmssp();}void i2c_nak(){ACKDT=1;ACKEN=1;waitmssp();}

author: DavidAlfa
author_rank: Super Contributor
timestamp: September 12, 2022, 01:54:49 pm
content: Definitely the logic levels in your picture are wrong for i2c, so first you must find the reason of why SDA/SCL are low!(Seems like you are sending start/data but never a stop, so SDA is never released)Each I2C transfer is 8+1 clocks, not any other size. At the end of each byte there's a 9th clock pulse for the ACK/NAK bit, so you will always see 9 clocks.From the master point of view, there's no diifference between 7 or 10-bit addressing, it simply sends raw bytes.Better to configure the i2c peripheral with SSPEN off, setting it afterwards, otherwise you might confuse the hardware.Try this very simple code in your master, with nothing connected to it:Code:// Some debugging leds#define LED_TIMEOUT LATC1#define LED_COLLISION LATC2#define LED_ERR_START LATC3#define LED_ERR_DATA LATC4#define LED_ERR_STOP LATC5bool i2c_error;void i2c_init(void){LED_TIMEOUT = 0;LED_COLLISION = 0;LED_TIMEOUT = 0;LED_ERR_START = 0;LED_ERR_DATA = 0;LED_ERR_STOP = 0;i2c_error = 0;SSPCON1 = 0x08;SSPCON2 = 0;SSPCON3 = 0;SSPSTAT = 0;SSPADD = 0x63; // For 100KHz//SSPADD = 0x18; // For 400KHzSSPEN = 1; // Enable MSSP}bool i2c_poll(void){uint16_t timeout = 1000;while(!SSPIF){if(BCLIF){ // Write collision detected, debug/do somethingBCLIF=0;LED_COLLISION = 1;i2c_error = true;break;}if(!--timeout){ // Timeout occurred, debug/do somethingLED_TIMEOUT = 1;i2c_error = true;break;}}SSPIF=0;return i2c_error;}void i2c_test(void){SEN = 1; // Initiate Startif( i2c_poll() ){LED_ERR_START = 1;return;}SSPBUF = 0x55; // Send 0x55if( i2c_poll() ){LED_ERR_DATA = 1;return;}PEN=1; // Initiate Stopif ( i2c_poll() ){LED_ERR_STOP = 1;return;}}void main(void){// system init, etci2c_init();while(1){i2c_test();if(i2c_error){// Compiler complaining on large delay values, split in a loop// Wait 5 seconds to show the ledsfor(uint8_t wait=5; wait; wait--){__delay_ms(1000);}i2c_init();}else{__delay_ms(1);}}}I tested it with a 18F23K22, you should see exactly this, and no errors.

author: Salome2
author_rank: Regular Contributor
timestamp: September 19, 2022, 09:55:12 pm
content: Now, after discovering that I had overlooked some details in my Fosc initialization. My bad to not set INTOSC to 16MHz and enable PLLEN and then discovering my delay ISR using TMR0 was counting the wrong number of Instr Clks,In converting my code to the 64MHz 18F25K22, I had forgot to I didn't update TMR0 settings, still set for a 18F252 at 40MHz Fosc.The problem initially was that I couldn't get rid of an extra start bit glitch. After so much time I finally realized the PIC18F452 MSSP does not do I2C correctly. SEN doesn't work! I spent a quite a few days finding no cure for the incurable extra bit.Oh My! Quite a few other errors!I2C now that Ack acts fine.

author: PCB.Wiz
author_rank: Super Contributor
timestamp: September 20, 2022, 02:16:39 am
content: Quote from: Salome2 on September 19, 2022, 09:55:12 pmDid you try a simple i2c slave part like an EEPROM, to verify your master code is ok.i2c slaves can be tricky to get working, the ones I've worked with need a careful phasing of SW and hardware.I assigned pins to tag START seen, and then Address Match and then Send ACK states.I read about one MCU that did i2c slave like a dual port memory, so the slave needed zero SW help. What a great idea !

author: Salome2
author_rank: Regular Contributor
timestamp: September 20, 2022, 02:50:39 am
content: Thanks, PCB.Wiz! I was really thrown off by trying to get things to work with a buggy chip (18F452) that undoubtedly has a serious bug with i2c SEN!Worse, I didn't find this bug listed in the 18Fx52 Errata!I had to convert my code after changing my mcu's to 18F25K22.After some hours I finally succeeded in finding some other coding errors.I had initialization omissions for Fosc and my TMR0 was way off in creating delays. I didn't realize that until finally, using a blip bit trace to debug, it showed that I was actually running the 18F25k22 chips at 4MHz. The default setting settings set INTOSC=4MHz and PLL was not enabled. Because I had a client 1/2 sec warmup delay that was way too long, my i2c test code was delaying the client to start until way after the host 18F25K22 sent out the SEN Address Write and the client missed this event.Finally, I discovered that I had to set SSPADD to 0x20 using SSPAD=Addr1<<1 in the i2c client.