CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

I2C PIC (master) to PIC (slave) routine

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
silelis



Joined: 12 Jun 2007
Posts: 68
Location: Poland, podlaskie district

View user's profile Send private message

I2C PIC (master) to PIC (slave) routine
PostPosted: Mon Sep 25, 2017 5:16 am     Reply with quote

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 ([email protected])
   
    @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 ([email protected])
   
    @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

View user's profile Send private message

PostPosted: Mon Sep 25, 2017 5:25 am     Reply with quote

Ok. Now something about slave PIC.

i2c_slave.h
Code:

/**************************************************************************/
/*!
    @file     i2c_slave.h
    @author   D. Bankowski ([email protected])
   
    @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 ([email protected])
   
    @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

View user's profile Send private message

PostPosted: Mon Sep 25, 2017 5:29 am     Reply with quote

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: 1067
Location: Panama

View user's profile Send private message

PostPosted: Thu Sep 28, 2017 8:16 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Sep 28, 2017 11:19 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Sep 28, 2017 11:22 pm     Reply with quote

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
      }
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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