Jump to content

Recommended Posts

Hello,

 

I have wrote a function to have a 18F4520 working as an I2C slaves. The write procedure work fine (at least till now). But the read one let me craze !

 

In the application note AN734 for state 3 it is explained for new 18F and asm code is :

 

; State 3: I2C read operation, last byte was an address byte
; SSPSTAT bits: S = 1, D_A = 0, R_W = 1 (see Appendix C for more information)

SSP_Handler
movf  SSPSTAT,W; Get the value of SSPSTAT	
andlw b'00101101'; Mask out unimportant bits in SSPSTAT.
movwf Temp; for comparision checking.

State3:
movf  Temp,W; 
andlw b'00101100'; Mask BF bit in SSPSTAT
xorlw b'00001100'
btfss STATUS,Z; Are we in State3?
goto  State4; No, check for next state.....
movf  SSPBUF,W 
clrf  Index; Clear the buffer index.
load  RXBuffer,Index		; Point to the buffer
movf  INDF0,W; Get the byte from buffer.
call  WriteI2C; Write the byte to SSPBUF
incf  Index,F; Increment the buffer index.
return

 

I have difficulties to understand the following lines :

movf SSPBUF,W ---
SSPBUF is loaded into the working buffer

 

load RXBuffer,Index ;
Point to the buffer

movf INDF0,W ; Get the byte from buffer. --------
First data we wants to send to the master is loaded into the working buffer

call WriteI2C ; Write the byte to SSPBUF

 

Then we went to WriteI2C :

WriteI2C
btfsc   SSPSTAT,BF	 ; Is the buffer full?
goto	WriteI2C	   ; Yes, keep waiting.
DoI2CWrite
bcf	 SSPCON1,WCOL   ; Clear the WCOL flag.
movwf   SSPBUF		 ; Write the byte in WREG
btfsc   SSPCON1,WCOL   ; Was there a write collision?
goto	DoI2CWrite
return

 

I wrote my code as follow, but the b_S is never cleared. What is wrong in my interpretation ?

 

		if((b_S == 1) & (b_DA == 0) & (b_RW == 1)) // & (b_BF == 1))
	{
		unsigned char i = 0;
		i = sspbuf;
		while(b_S == 1);

		do 
		{													// Yes - Write data again
			clear_bit( sspcon1, WCOL);					// Done waiting, clear the WCOL flag
			sspbuf = 145;							// Write the data to the SSP Buffer register
		}					
		while	
		( test_bit(sspcon1, WCOL) == 1);	

		b_CKP = 1;
		b_SSPIF = 0;
		return 0;
	}

 

Thanks you for your help,

Jean-Marie

Share this post


Link to post
Share on other sites

Hi Jean-Marie,

 

The 'S' bit will be set for the complete message and will reset when a stop condition has been detected, when the 'P' bit will be set.

 

Don't forget to check if the master is ACKing or NAKing the data you are sending.

 

Cheers

 

Reynard

Share this post


Link to post
Share on other sites

Thanks for your replies.

 

RSABear I saw your code, but I found it difficult to read.

 

Thanks Reynard, I made confusion with BF.

 

Now the code is :

		if((b_S == 1) & (b_DA == 0) & (b_RW == 1)) // & (b_BF == 1))
	{
		unsigned char i = sspbuf;
		while(b_BF== 1);

		sspbuf = I2C_Donnee[Compteur];	
		do 
		{													// Yes - Write data again
			clear_bit( sspcon1, WCOL);					// Done waiting, clear the WCOL flag
			sspbuf = I2C_Donnee[Compteur];							// Write the data to the SSP Buffer register
		}					
		while	
		( test_bit(sspcon1, WCOL) == 1);	

		b_CKP = 1;
		b_SSPIF = 0;
		Compteur++;
		return 0;
	}

	// Read operation, last byte is a data byte
	if((b_S == 1) & (b_DA == 1) & (b_RW == 1)) // & (b_BF == 0))
	{
		while(b_BF == 1);

		sspbuf = I2C_Donnee[Compteur];	
		do 
		{													// Yes - Write data again
			clear_bit( sspcon1, WCOL);					// Done waiting, clear the WCOL flag
			sspbuf = I2C_Donnee[Compteur];							// Write the data to the SSP Buffer register
		}					
		while	
		( test_bit(sspcon1, WCOL) == 1);	

		b_CKP = 1;
		b_SSPIF = 0;
		Compteur++;
		return 0;
	}

 

But every thinks is not working correctly : after living the if statement the SDA remain at level 0. And I see that BF bit is set. But I don't why.

 

Jean-Marie

Share this post


Link to post
Share on other sites

Hi Jean-Marie,

 

You have a double write to sspbif in your routines.

 

			sspbuf = I2C_Donnee[Compteur];	
		do 
		{													// Yes - Write data again
			clear_bit( sspcon1, WCOL);					// Done waiting, clear the WCOL flag
			sspbuf = I2C_Donnee[Compteur];							// Write the data to

 

This may not be helping you.

 

Cheers

 

Reynard

Share this post


Link to post
Share on other sites

Thanks Reynard. But that did not solve my problem.

 

Some news :

 

I use the the asm file for 18F of the AN734, compile it and programme the 18F4520.

 

Then from the master I send a write order for 4 bytes and a read order of 4 bytes also.

I obtain exactly the same behaviour than with my own C code : after the read operation the SDA remain low. The first part of the picture correspond to the write operation. The second is the read one :

 

I2C%20slave%20ASM%20AN736.JPG

 

After this if I perform a new write operation from the master, the master ramin in the initialisation function, which same normal as the SDA is low.

If I reset the slave before performing this second write operation, the master work fine.

 

So my slave procedure or the AN736 procedure give the same result : said the SDA line remain low after the read operation. And as a reset of the slave allow the SDA to be hight again I think the problem is coming from the slave.

 

If that supposition correct ? If yes what is the problem ?

Share this post


Link to post
Share on other sites

Hi Jean-Marie,

 

Your slave has not recieved a NAK from the master to say send no more data, therefore the slave still has control of the SDA line as it thinks the master wants more data.

 

Cheers

 

Reynard

 

ps. What are you using to capture your waveforms ? Look like a nice tool to have.

Share this post


Link to post
Share on other sites

Reynard,

 

After the read section I send a stop : code is as follow :

 

void ConnexionJulabo_Read(unsigned char Temperature[])
{
unsigned char Adresse[1];
Adresse[0] = 0b10011001; // adresse en mode écriture

I2Cjms_Initialise();
I2CjmsWrite(Adresse, 1);

Temperature[0] = I2CjmsReadSimple();
Temperature[1] = I2CjmsReadSimple();
Temperature[2] = I2CjmsReadSimple();
Temperature[3] = I2CjmsReadSimple();
I2Cjms_Stop();
}

void I2Cjms_Stop()
{
b_SSPIF = 0;
b_PEN = 1;  // send a stop 
while ((b_ACKSTAT != 0) & (b_SSPIF == 0)) 
{
	Start_Flag = 0;
}

b_SSPIF = 0; 
b_SSPEN = 0; // disable the SSP module
}

 

I use the same stop function after write action and in that case the STOP bit is send.

 

The logic analyser I am using is very nice and not expensive (not to expensive). You can found information here : Intronix logicport

 

Jean-Marie

Edited by schneiderj

Share this post


Link to post
Share on other sites

Hi Jean-Marie,

 

At some point during the read the master has to send a NAK.

 

	 ACKDT = true;	// output a NAK.

 

When writing to the slave (data) the slave has to send a NAK to say MASTER give me no more data.

 

Cheers

 

Reynard

Share this post


Link to post
Share on other sites

OK,

 

I begin (or expecting) to understand : the last read operation should be completed by setting ACKDT bit. Is that correct ? But in that situation how can I know that the master as correctly received the last byte ?

 

Jean-Marie

 

Edit : I modify my code and set AKDT after the last write operation. SDA return to the "normal state".

Many tanks !

Edited by schneiderj

Share this post


Link to post
Share on other sites

Hi Jean-Marie,

 

Good to read you are making progress.

 

I2C is a simple interface. If the master does not like the data it received then it will have to ask for it again.

 

You could append a checksum to your data packet (assuming you are writing for master and slave) or add a parity bit to each byte.

 

The master could also send another message to the slave to acknowledge the received data if the slave want to move on and change its data. There are probably numerous solutions if you think they are worth it.

 

Cheers

 

Reynard

Share this post


Link to post
Share on other sites

Hi Reynard,

 

I found some problem in my code and it seams that better results are obtained.

 

But after I2C working properly for few minutes, I obtaine a NACK (after the slave has been asked and had answered more than 50 times (for each, receiving one byte and latter sending 4 bytes). You can see the sequence in the picture :

 

I2C_Slave.JPG

 

- the first pulse is master sending a byte to the slave to tell it that he must prepare data's to send

- the second the the slave sending the data's

- the third is two in fact : communication with an A2D (ADS1100) and then writing the 6 bytes to an eeprom.

 

Then the cycle roll-over. But on the third cycle of the picture the address is not received by slave and a NACK is put. The SCL is set low and never return to an hight state.

 

I presume that come from the slave which was not ready to read this new request, but why ? Is that coming from the SSP module which was not free and how can I know origin of this trouble ? Or other thing ?

 

Thanks you for your comments,

Jean-Marie

Share this post


Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...