  | 
	  | 
		 
	 
	
		| View previous topic :: View next topic   | 
	 
	
	
		| Author | 
		Message | 
	 
	
		
			silelis
 
 
  Joined: 12 Jun 2007 Posts: 68 Location: Poland, podlaskie district 
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				| I2C PIC (master) to PIC (slave) routine | 
			 
			
				 Posted: Mon Sep 25, 2017 5:16 am     | 
				     | 
			 
			
				
  | 
			 
			
				Hello,
 
 
I've spent a lot of time on my project and one of the results is i2c_engine which I want to share with you.
 
 
It is PIC to PIC engine.
 
 
I2C_Engine.h
 
 	  | Code: | 	 		  
 
/**************************************************************************/
 
/*! 
 
    @file     i2c_engine.h
 
    @author   D. Bankowski (d.bankowski@gmail.com)
 
    
 
    @brief    Driver for i2c master.
 
    @section LICENSE
 
    Software License Agreement (BSD License)
 
    Copyright (c) 2017, D. Bankowski
 
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
 
    modification, are permitted provided that the following conditions are met:
 
    1. Redistributions of source code must retain the above copyright
 
    notice, this list of conditions and the following disclaimer.
 
    2. Redistributions in binary form must reproduce the above copyright
 
    notice, this list of conditions and the following disclaimer in the
 
    documentation and/or other materials provided with the distribution.
 
    3. Neither the name of the copyright holders nor the
 
    names of its contributors may be used to endorse or promote products
 
    derived from this software without specific prior written permission.
 
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
 
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
 
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
*/
 
/**************************************************************************/
 
 
#ifndef _I2C_ENGINE_
 
   #define _I2C_ENGINE_
 
 
   #define  I2C_DELAY_US            20 
 
   #define  I2C_INTERBYTE_DELAY_US  60
 
   #define  READ__EEPROM            TRUE
 
   #define  normal__I2C             FALSE
 
   
 
   void i2cInit      (void);   
 
   void i2cEngine    (int1);
 
 
#endif
 
 | 	  
 
 
I2C_Engine.c
 
 	  | Code: | 	 		  
 
/**************************************************************************/
 
/*! 
 
    @file     i2c_engine.c
 
    @author   D. Bankowski (d.bankowski@gmail.com)
 
    
 
    @brief    Driver for i2c master.
 
    @section LICENSE
 
    Software License Agreement (BSD License)
 
    Copyright (c) 2017, D. Bankowski
 
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
 
    modification, are permitted provided that the following conditions are met:
 
    1. Redistributions of source code must retain the above copyright
 
    notice, this list of conditions and the following disclaimer.
 
    2. Redistributions in binary form must reproduce the above copyright
 
    notice, this list of conditions and the following disclaimer in the
 
    documentation and/or other materials provided with the distribution.
 
    3. Neither the name of the copyright holders nor the
 
    names of its contributors may be used to endorse or promote products
 
    derived from this software without specific prior written permission.
 
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
 
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
 
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
*/
 
/**************************************************************************/
 
 
#include </I2C_Engine.h>
 
 
#ifndef _TRANSMISSION_BUFFERS_
 
   #include </MCU_include/core/transmission_buffers/transmission_buffers.c>
 
#endif
 
 
unsigned int32 I2CReadLength; //I2C zmieniФ na 
 
unsigned int32 I2CWriteLength;
 
 
void i2cInit(void) {
 
   output_float(_I2C_SCL);
 
   output_float(_I2C_SDA);
 
}
 
 
int8 __i2cDeviceStatus() {
 
   int8 ack;
 
   i2c_start();            // If the write command is acknowledged,
 
   delay_us(I2C_DELAY_US);
 
   ack = i2c_write(MasterBuffer[0]&0xFE);  // then the device is ready. PING should be always of write address so 0xFE 0b11111110 is required on ping
 
   delay_us(I2C_DELAY_US);
 
   i2c_stop();
 
   delay_us(I2C_DELAY_US);
 
   return ack;             // 0 means ACK, 1 means NO ACK, 2 means there was a collision if in Multi_Master Mode. This does not return an ACK if using i2c in slave mode
 
}
 
 
int8 __try_i2c_bus(void)
 
{
 
   int8  i2c_try=1;
 
   unsigned int16 i2c_tryout_error = 0;
 
   while(i2c_try!=0&&i2c_tryout_error <100) //i2c_tryout_error<100
 
   {
 
      i2c_try = __i2cDeviceStatus();
 
      
 
      if (i2c_try!= 0)
 
      {
 
         dbg_printf("I2C w.addr:%x error try(s):%Lu status:%d", MasterBuffer[0], i2c_tryout_error, i2c_try);
 
         dbg_return_carriage();
 
      }
 
      i2c_tryout_error = i2c_tryout_error +1;
 
      delay_us(254);
 
   }
 
   return i2c_try;
 
}
 
 
void i2cEngine(int1 eeprom_read = FALSE) //, unsigned int8 = 0)
 
{
 
   disable_interrupts(GLOBAL);
 
   
 
   int8  i2c_ACK=__try_i2c_bus();
 
   
 
   if (i2c_ACK==0)
 
   {
 
   i2c_start();
 
   delay_us(I2C_DELAY_US);
 
   unsigned int8 i;
 
   if (I2CWriteLength>0)
 
   {     
 
      for(i=0;i<I2CWriteLength; i++)
 
      {
 
         i2c_write(MasterBuffer[i]); //write to device from buffer
 
         delay_us(I2C_DELAY_US);
 
      }
 
   }
 
      if (eeprom_read == TRUE)
 
   {
 
      i2c_start();
 
      delay_us(I2C_DELAY_US);
 
      i2c_write(MasterBuffer[2]);
 
      delay_us(I2C_DELAY_US);
 
   }   
 
   
 
   if (I2CReadLength > 0)
 
   {  
 
      int1 state;
 
      for(i=0;i<I2CReadLength; i++)
 
      {  
 
      
 
         if (i<(I2CReadLength-1))
 
            state = TRUE;
 
         else
 
            state = FALSE;
 
         SlaveBuffer[i]=i2c_read(state);
 
         delay_us(I2C_INTERBYTE_DELAY_US);
 
      }
 
   }
 
   i2c_stop();
 
   delay_us(I2C_DELAY_US);
 
   if (I2CReadLength == 0)
 
      {
 
         dbg_printf("I2C w.addr:%x ACK", MasterBuffer[0]);
 
         dbg_return_carriage();
 
      }
 
   else
 
      {
 
         dbg_printf("I2C r.addr:%x ACK", MasterBuffer[0]);
 
         dbg_return_carriage();
 
      }
 
   break;
 
   }
 
   else if (i2c_ACK==1)
 
   {
 
   dbg_printf("I2C addr:%x !ACK", MasterBuffer[0]);
 
   dbg_return_carriage();
 
   break;
 
   }
 
   else if (i2c_ACK==2)
 
   {
 
   dbg_printf("I2C adr:%x COLISION", MasterBuffer[0]);
 
   dbg_return_carriage();
 
   break;
 
   }
 
   I2CWriteLength = 0;
 
   I2CReadLength = 0;
 
   enable_interrupts(GLOBAL); 
 
}
 
 | 	  
 
 
transmission_buffers.h
 
 	  | Code: | 	 		  
 
#ifndef _TRANSMISSION_BUFFERS_
 
   #define _TRANSMISSION_BUFFERS_
 
   
 
   #define mcu_Transmission_BUFSIZE         65
 
   #define mcu_Reception_BUFSIZE            257
 
 
   unsigned int   MasterBuffer[mcu_Transmission_BUFSIZE ];
 
   unsigned int   SlaveBuffer[mcu_Reception_BUFSIZE];
 
 
   void ClearBuffers (unsigned int, short int);
 
   void ClearMasterBuffer  (void);
 
   void ClearSlaveBuffers  (void);
 
   
 
#endif
 
 | 	  
 
 
 
transmission_buffers.c
 
 	  | Code: | 	 		  
 
#include </transmission_buffers.h>
 
 
void ClearBuffers (unsigned int *buffer, short int buffer_size)
 
   {
 
      unsigned int8 i;
 
      for ( i = 0; i < buffer_size; i++ )
 
      {
 
         *(buffer+i)= 0x00;
 
      }
 
   }
 
 
void ClearMasterBuffer  (void)
 
{
 
   ClearBuffers(&MasterBuffer,mcu_Transmission_BUFSIZE);
 
}
 
 
void ClearSlaveBuffers  (void)
 
{
 
   ClearBuffers(&SlaveBuffer,mcu_Reception_BUFSIZE);
 
}
 
 | 	  
 
 
The whole idea is to use only one function to perform i2c which is i2c_engine.
 
 
based on information in:
 
I2CReadLength;
 
I2CWriteLength;
 
It reads and send MasterBuffer data and receive data to SlaveBuffer.
 
 
In excample to write data you should:
 
 	  | Code: | 	 		  
 
MasterBuffer[0]= i2c_slave_wirte_addres;
 
MasterBuffer[1]= data1;
 
MasterBuffer[2]= data2;
 
I2CWriteLength=3;
 
I2CReadLength=0;
 
i2c_engine(false); //Generaly false is required. Only eeprom requires extra i2c_stat os TRUE only in case of eeprom
 
 | 	  
 
 
To read data you need:
 
 	  | Code: | 	 		  
 
MasterBuffer[0]= i2c_slave_read_addres;
 
//MasterBuffer[1]= read_parameter; //if required - mostly not required
 
I2CWriteLength=1; //Because You have to write at least address
 
I2CReadLength=x; //x = number of bytes You want to read.
 
i2c_engine(false);
 
 | 	  
 
 
There is also some kind of ping function so if the device is broken it will not freeze routine. | 
			 
		  | 
	 
	
		  | 
	 
	
		
			silelis
 
 
  Joined: 12 Jun 2007 Posts: 68 Location: Poland, podlaskie district 
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 Posted: Mon Sep 25, 2017 5:25 am     | 
				     | 
			 
			
				
  | 
			 
			
				Ok. Now something about slave PIC.
 
 
i2c_slave.h
 
 	  | Code: | 	 		  
 
/**************************************************************************/
 
/*! 
 
    @file     i2c_slave.h
 
    @author   D. Bankowski (d.bankowski@gmail.com)
 
    
 
    @brief    Driver for i2c slave.
 
    @section LICENSE
 
    Software License Agreement (BSD License)
 
    Copyright (c) 2017, D. Bankowski
 
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
 
    modification, are permitted provided that the following conditions are met:
 
    1. Redistributions of source code must retain the above copyright
 
    notice, this list of conditions and the following disclaimer.
 
    2. Redistributions in binary form must reproduce the above copyright
 
    notice, this list of conditions and the following disclaimer in the
 
    documentation and/or other materials provided with the distribution.
 
    3. Neither the name of the copyright holders nor the
 
    names of its contributors may be used to endorse or promote products
 
    derived from this software without specific prior written permission.
 
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
 
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
 
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
*/
 
/**************************************************************************/
 
 
#ifndef _I2C_ENGINE_SLAVE_
 
   #define _I2C_ENGINE_SLAVE_
 
   
 
   #if getenv("SFR_VALID:SSPSTAT")
 
      #byte SSP1STAT = getenv("SFR:SSPSTAT")
 
      #bit SSP1STAT_STOP_SEEN=SSP1STAT.4 
 
      #WARNING "PIC_SSPSTAT REGISTER CONFIGURED"
 
   #else
 
      #ERROR "PIC_SSPSTAT REGISTER SHOULD BE DEFINED in i2c_slave.h"
 
   #endif
 
  
 
   #define  I2C_SLAVE_BUFSIZE       15
 
   
 
   unsigned int8   Master_2_Slave_Buffer[I2C_SLAVE_BUFSIZE];
 
   unsigned int8   Slave_2_Master_Buffer[I2C_SLAVE_BUFSIZE];
 
   unsigned int    i2c_buffer_counter;
 
   
 
   void clr_SSPSTAT(void);
 
   void ClearBuffers (unsigned int, short int);
 
   void set_i2c_interrupt_ready(void);
 
   void i2c_slave_interrupt (void);
 
#endif
 
 | 	  
 
 
i2c_slave.c
 
 	  | Code: | 	 		  
 
/**************************************************************************/
 
/*! 
 
    @file     i2c_slave.c
 
    @author   D. Bankowski (d.bankowski@gmail.com)
 
    
 
    @brief    Driver for i2c slave.
 
    @section LICENSE
 
    Software License Agreement (BSD License)
 
    Copyright (c) 2017, D. Bankowski
 
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
 
    modification, are permitted provided that the following conditions are met:
 
    1. Redistributions of source code must retain the above copyright
 
    notice, this list of conditions and the following disclaimer.
 
    2. Redistributions in binary form must reproduce the above copyright
 
    notice, this list of conditions and the following disclaimer in the
 
    documentation and/or other materials provided with the distribution.
 
    3. Neither the name of the copyright holders nor the
 
    names of its contributors may be used to endorse or promote products
 
    derived from this software without specific prior written permission.
 
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
 
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
 
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
*/
 
/**************************************************************************/
 
 
#include <i2c_slave.h>
 
 
 
void clr_SSPSTAT(void)     //when data is counted by program and can read new data
 
{
 
   SSP1STAT = 0;
 
   i2c_buffer_counter = 0;
 
}
 
 
void ClearBuffers (unsigned int *buffer, short int buffer_size)
 
{
 
   unsigned int8 i;
 
   for ( i = 0; i < buffer_size; i++ )
 
   {
 
      *(buffer+i)= 0x00;
 
   }
 
}
 
 
//unsigned int set_i2c_interrupt_ready(void)
 
void set_i2c_interrupt_ready(void)
 
{
 
   clr_SSPSTAT();
 
   i2c_slave_ready();
 
}
 
   
 
   
 
void i2c_slave_interrupt (void) //Interrupt hendler
 
{
 
   unsigned int8 state; //, incoming;
 
   state = i2c_isr_state();
 
   if (state < 0x80)
 
       {
 
       Master_2_Slave_Buffer[i2c_buffer_counter]= i2c_read();
 
       i2c_buffer_counter=i2c_buffer_counter+1;
 
       }
 
       
 
   if(state >= 0x80)                      //Master is requesting data do Your operations here
 
   {
 
 
      i2c_write(DATA_HERE);
 
 
   }
 
   if (SSP1STAT_STOP_SEEN==1)
 
   {
 
      i2c_slave_not_ready() ;
 
   }
 
}
 
 | 	  
 
 
One of the problems that I appear was that my slave was calculating the received data, and the next one was coming. This is dangerous because You can not take next data before old was calculated.
 
 
To prevent this action after I receive data I have put to pic fake i2c adress and after calculation I put correct one like bellow:
 
 
 	  | Code: | 	 		  
 
 
#define i2c_slave_address        0x10
 
#define i2c_slave_fake_address   0x12
 
 
#define i2c_slave_ready()            I2C_SlaveAddr(i2c_slave_address)            
 
#define i2c_slave_not_ready()        I2C_SlaveAddr(i2c_slave_fake_address)       
 
 | 	  
 
 
If slave is in fake address mode the master can not ping it and will not send data. | 
			 
		  | 
	 
	
		  | 
	 
	
		
			silelis
 
 
  Joined: 12 Jun 2007 Posts: 68 Location: Poland, podlaskie district 
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 Posted: Mon Sep 25, 2017 5:29 am     | 
				     | 
			 
			
				
  | 
			 
			
				And last thing, debug functions are:
 
 	  | Code: | 	 		  
 
#define dbg_printf(fmt,...)   fprintf(LOG_PORT,fmt, __VA_ARGS__)//; 
 
#define dbg_return_carriage() fprintf(LOG_PORT,"\r\n");
 
 | 	 
  | 
			 
		  | 
	 
	
		  | 
	 
	
		
			Gabriel
 
 
  Joined: 03 Aug 2009 Posts: 1074 Location: Panama 
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 Posted: Thu Sep 28, 2017 8:16 pm     | 
				     | 
			 
			
				
  | 
			 
			
				I dont know if this works, but your code looks pretty. _________________ CCS PCM 5.078 & CCS PCH 5.093 | 
			 
		  | 
	 
	
		  | 
	 
	
		
			silelis
 
 
  Joined: 12 Jun 2007 Posts: 68 Location: Poland, podlaskie district 
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 Posted: Thu Sep 28, 2017 11:19 pm     | 
				     | 
			 
			
				
  | 
			 
			
				It is working. I have spend a lot of time on it for my radio. The code is written in way that also allows to me to share sending/receiving buffer between multiple communication protocols (i2c, uart, etc). And to be honest that was the main reason to do that.
 
 
And here is an example of using it with TDA7418 equaliser.
  Last edited by silelis on Thu Sep 28, 2017 11:32 pm; edited 1 time in total | 
			 
		  | 
	 
	
		  | 
	 
	
		
			silelis
 
 
  Joined: 12 Jun 2007 Posts: 68 Location: Poland, podlaskie district 
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 Posted: Thu Sep 28, 2017 11:22 pm     | 
				     | 
			 
			
				
  | 
			 
			
				Oh and one more think. The code of slave to handle received data.
 
 
 	  | Code: | 	 		  
 
main()
 
{
 
   if (SSP1STAT_STOP_SEEN==1 && i2c_buffer_counter==1)
 
      {
 
      set_i2c_interrupt_ready();    //i2c_engine() test condition (ping) only - NO DATA WAS SENT
 
      }
 
   else if (SSP1STAT_STOP_SEEN==1&& i2c_buffer_counter>1)
 
      {
 
      // proceed recived data
 
      }
 
}
 
 | 	 
  | 
			 
		  | 
	 
	
		  | 
	 
	
		 | 
	 
 
  
	 
	    
	   | 
	
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
  | 
   
 
  
Powered by phpBB © 2001, 2005 phpBB Group
  
		 |