1   //*****************************************************************************
2   //
3   //  File  Name    :  'i2c.c'
4   //  Title                :  Itronove  hodiny 
5   #define  __PIC18F8720A__
6   //  Author              :  http://www.prochazka.zde.cz  -&rsaquo   hacesoft  2017
7   //  Created            :  30-06-2017,  11:58
8   //  Revised            :  04-07-2017,  08:52
9   //  Version            :  1.3
10   //  Target  MCU   :  PIC  18F8720
11   //
12   //  This  code  is  distributed  under  the  GNU  Public  License
13   //  Vsechny  informace  jsou  zahrnuty  pod  GPL  licenci,  pokud  není  explicitne  uveden  jiný  typ  licence.
14   //  Pouzivání  techto  stránek  ke  komercním  úcelum  lze  jen  se  souhlasem  autora.
15   //  Vsechna  práva  vyhrazena  (c)  1997  -  2017  hacesoft.
16   //
17   //*****************************************************************************
18  
19   #include &lsaquo xc.h&rsaquo
20   #include &lsaquo stdint.h&rsaquo   //uint8_t,  uint16_t,  uint32_t
21   #include  "i2c.h"
22  
23   //*****************************************************************************
24   void  I2C_Start(uint8_t  type){
25        if  (type  ==  _SW){I2C_StartMasterSW();}
26        else  i2c_Start();
27   }
28   //*****************************************************************************
29   void  I2C_StartMasterSW(void){
30        i2c_WaitGeneral();
31           SDA_MasterSW  =  1;              //  Pull  SDA  High
32        __delay_us(_wt_speed_i2c_Master);
33        SCL_MasterSW  =  1;      //  Pull  SCL  High
34           __delay_us(_wt_speed_i2c_Master);
35           SDA_MasterSW  =  0;              //  Pull  SDA  Low
36           __delay_us(_wt_speed_i2c_Master);
37        SCL_MasterSW  =  0;
38        i2c_WaitGeneral();
39   }
40   //*****************************************************************************
41   //  i2c_Start  -  Start  I2C  communication
42   void  i2c_Start(void){
43        GIE  =  0;         //  Global  interrupt  stop
44        i2c_WaitGeneral();
45        I2C_HW_Wait();
46        SEN=1;
47        i2c_WaitGeneral();
48   }
49   //*****************************************************************************
50   //  i2c_Start  -  Start  I2C  communication
51   void  I2C_Start_PCA955PW(void){
52        GIE  =  0;         //  Global  interrupt  stop
53        i2c_WaitGeneral_PCA955PW();
54        I2C_HW_Wait_PCA955PW();
55        SEN=1;
56        i2c_WaitGeneral_PCA955PW();
57   }
58   //*****************************************************************************
59   void  I2C_Stop(uint8_t  type){
60        if  (type  ==  _SW){I2C_StopMasterSW();}
61        else  i2c_Stop();
62   }
63   //*****************************************************************************
64   void  I2C_StopMasterSW(void){
65        i2c_WaitGeneral();
66        SCL_MasterSW  =  1;
67           __delay_us(_wt_speed_i2c_Master);
68           SDA_MasterSW  =  1;         
69           i2c_WaitGeneral();
70   }
71   //*****************************************************************************
72   //  i2c_Stop  -  Stop  I2C  communication
73   void  i2c_Stop(void){
74        i2c_WaitGeneral();
75        I2C_HW_Wait();
76        PEN=1;
77        i2c_WaitGeneral();
78        GIE  =  1;         //  Global  interrupt  enable
79   }
80   //*****************************************************************************
81   //  i2c_Stop  -  Stop  I2C  communication
82   void  I2C_Stop_PCA955PW(void){
83        i2c_WaitGeneral_PCA955PW();
84        I2C_HW_Wait_PCA955PW();
85        PEN=1;
86        i2c_WaitGeneral_PCA955PW();
87        GIE  =  1;         //  Global  interrupt  enable
88   }
89   //*****************************************************************************
90   void  I2C_Write(uint8_t  type,  unsigned  char  data){
91        if  (type  ==  _SW){I2C_WriteMasterSW(data);}
92        else  i2c_Write(data);
93   }
94   //*****************************************************************************
95   void  I2C_WriteMasterSW(unsigned  char  data){
96           uint8_t  i;
97           uint8_t  SdaBuffer;
98          
99           for(i=0;i&lsaquo 8;i++){                                          //  loop  8  times  to  send  1-byte  of  data
100            i2c_WaitGeneral();
101                   SdaBuffer  =  data  &  (unsigned)  0x80;                    //  Send  Bit  by  Bit  on  SDA  line
102                if  (SdaBuffer  ==  0x80){SDA_MasterSW  =  1;}
103                else  {SDA_MasterSW  =  0;} 
104                   I2C_ClockMasterSW();                    //  Generate  Clock  at  SCL
105                   data  =  (unsigned)  data &lsaquo &lsaquo   1;
106           }
107        i2c_WaitGeneral();
108        SDA_MasterSW  =  1;                          //  Set  SDA  at  last
109        i2c_WaitGeneral();
110        I2C_AckNowLedgeMasterSW();
111   }
112   //*****************************************************************************
113   //  i2c_Write  -  Sends  one  byte  of  data
114   void  i2c_Write(unsigned  char  data){
115        I2C_HW_Wait();
116        SSPBUF  =  data;
117        i2c_WaitGeneral();
118   }
119   //*****************************************************************************
120   //  i2c_Write  -  Sends  one  byte  of  data
121   void  I2C_Write_PCA955PW(unsigned  char  data){
122        I2C_HW_Wait_PCA955PW();
123        SSPBUF  =  data;
124        i2c_WaitGeneral_PCA955PW();
125   }
126   //*****************************************************************************
127   //  i2c_Address  -  Sends  Slave  Address  and  Read/Write  mode
128   //  mode  is  either  I2C_WRITE  or  I2C_READ
129   void  i2c_Address(unsigned  char  address,  unsigned  char  mode){
130        unsigned  char  l_address;
131  
132        l_address  =  (unsigned)  address &lsaquo &lsaquo   1;
133        l_address+=mode;
134        I2C_HW_Wait();
135        SSPBUF  =  l_address;
136        i2c_WaitGeneral();
137   }
138   //*****************************************************************************
139   unsigned  char  I2C_Read(uint8_t  type,  unsigned  char  ack){
140        unsigned  char  nBuffer;
141       
142        if  (type  ==  _SW){  nBuffer  =  I2C_ReadMasterSW();}
143        else  nBuffer  =  i2c_Read(ack);
144       return  nBuffer;
145   }
146   //*****************************************************************************
147   //I2C_Read()
148   //I/P  Arguments:  none
149   //Return  value  :  Unsigned  char(received  byte)
150   //Description  :This  fun  is  used  to  receive  a  byte  on  SDA  line  using  I2C  protocol.
151   //8bit  data  is  received  bit-by-bit  each  clock  and  finally  packed  into  Byte.
152   //MSB(bit)  is  received  first  and  LSB(bit)  is  received  at  last.
153   //I2C  read.png
154   unsigned  char  I2C_ReadMasterSW(void){
155           unsigned  char  i  =  0; 
156        unsigned  char  nBuffer  =  0x00;
157          
158           SDA_MasterSW  =  1;                    //Make  SDA  as  I/P
159           for(i=0;i&lsaquo 8;i++){                     //  loop  8times  to  read  1-byte  of  data
160                   i2c_WaitGeneral();
161             SCL_MasterSW  =  1;                //Pull  SCL  High
162            i2c_WaitGeneral();
163                   nBuffer  =  (unsigned)nBuffer &lsaquo &lsaquo   1;         //dat  is  Shifted  each  time  and
164                   nBuffer  =  (unsigned)nBuffer  |  SDA_MasterSW;          //ORed  with  the  received  bit  to  pack  into  byte
165                   //dat  =  dat  |  (PIND,  SDAbit);   //ORed  with  the  received  bit  to  pack  into  byte
166                   SCL_MasterSW  =  0;                 //  Clear  SCL  to  complete  the  Clock
167            i2c_WaitGeneral();
168           }
169           return  (nBuffer);                          //  Finally  return  the  received  Byte*
170   }
171   //*****************************************************************************
172   //  i2c_Read  -  Reads  a  byte  from  Slave  device
173   unsigned  char  i2c_Read(unsigned  char  ack){
174        //  Read  data  from  slave
175        //  ack  should  be  1  if  there  is  going  to  be  more  data  read
176        //  ack  should  be  0  if  this  is  the  last  byte  of  data  read
177        //  ack  nastavit  na  1  v  p?ípad?,  ?e  se  ma  cist  vice  dat  ...
178        //  ack  nastavit  na  0,  pokud  se  jedna  o  posledni  bajt  ...
179        unsigned  char  i2cReadData;
180  
181        I2C_HW_Wait();
182        RCEN=1;
183        I2C_HW_Wait();
184        i2cReadData  =  SSPBUF;
185        I2C_HW_Wait();
186        if  (  ack  )  ACKDT=0;          //  Ack
187        else        ACKDT=1;          //  NAck
188        ACKEN=1;                     //  send  acknowledge  sequence
189        return(  i2cReadData  );
190   }
191   //*****************************************************************************
192   //  i2c_Read  -  Reads  a  byte  from  Slave  device
193   unsigned  char  I2C_Read_PCA955PW(unsigned  char  ack){
194        //  Read  data  from  slave
195        //  ack  should  be  1  if  there  is  going  to  be  more  data  read
196        //  ack  should  be  0  if  this  is  the  last  byte  of  data  read
197        //  ack  nastavit  na  1  v  p?ípad?,  ?e  se  ma  cist  vice  dat  ...
198        //  ack  nastavit  na  0,  pokud  se  jedna  o  posledni  bajt  ...
199        unsigned  char  i2cReadData;
200  
201        I2C_HW_Wait_PCA955PW();
202        RCEN=1;
203        I2C_HW_Wait_PCA955PW();
204        i2cReadData  =  SSPBUF;
205        I2C_HW_Wait_PCA955PW();
206        if  (  ack  )  ACKDT=0;          //  Ack
207        else        ACKDT=1;          //  NAck
208        ACKEN=1;                     //  send  acknowledge  sequence
209        return(  i2cReadData  );
210   }
211   //*****************************************************************************
212   void  i2c_Ack_HW(unsigned  char  ack){
213        i2c_WaitGeneral();
214        if  (  ack  )  ACKDT=0;          //  Ack
215        else        ACKDT=1;          //  NAck
216        I2C_HW_Wait();
217        ACKEN=1;                     //  send  acknowledge  sequence
218        i2c_WaitGeneral();
219   }
220   //*****************************************************************************
221   void  I2C_AckNowLedgeMasterSW(void){
222        //i2c_WaitGeneral();
223           ////__delay_us(_wt_speed_i2c_Master);      //  Wait  for  Some  time
224           SCL_MasterSW  =  1; 
225           __delay_us(_wt_speed_i2c_Master);              //  Wait  for  Some  time
226           SCL_MasterSW  =  0;
227        //i2c_WaitGeneral();
228        __delay_us(_wt_speed_i2c_Master);
229   }
230   //*****************************************************************************
231   void  I2C_ReStart(uint8_t  type){
232        if  (type  ==  _SW){  I2C_ReStartMasterSW();}
233        else  i2c_Restart(); 
234   }
235   //*****************************************************************************
236   void  I2C_ReStartMasterSW  (void){
237        //i2c_WaitGeneral();
238        __delay_us(_wt_speed_i2c_Master);
239        SDA_MasterSW  =  1;
240        SCL_MasterSW  =  0;
241        __delay_us(_wt_speed_i2c_Master);
242        SCL_MasterSW  =  1;
243        __delay_us(_wt_speed_i2c_Master);
244        SDA_MasterSW  =  0;
245        __delay_us(_wt_speed_i2c_Master);
246        SCL_MasterSW  =  0;
247        __delay_us(_wt_speed_i2c_Master);
248   }
249   //*****************************************************************************
250   //  i2c_Restart  -  Re-Start  I2C  communication
251   void  i2c_Restart(void){
252        i2c_WaitGeneral();
253        I2C_HW_Wait();
254        RSEN=1;
255        i2c_WaitGeneral();
256   }
257   //*****************************************************************************
258   //  i2c_Restart  -  Re-Start  I2C  communication
259   void  I2C_ReStart_PCA955PW(void){
260        i2c_WaitGeneral_PCA955PW();
261        I2C_HW_Wait_PCA955PW();
262        RSEN=1;
263        i2c_WaitGeneral_PCA955PW();
264   }
265   //*****************************************************************************
266   //  i2c_Wait  -  wait  for  I2C  transfer  to  finish
267   void  I2C_HW_Wait_PCA955PW(void){
268        __delay_ms(2);
269        while  ((SSPSTAT  &  0x04)  ||  (SSPCON2  &  0x1F));  //Transmit  is  in  progress
270   }
271   //*****************************************************************************
272   void  i2c_WaitGeneral_PCA955PW(void){
273        __delay_us(_wt_speed_i2c_Master  *  2);
274   }
275   //*****************************************************************************
276   //  i2c_Wait  -  wait  for  I2C  transfer  to  finish
277   void  I2C_HW_Wait(void){
278        __delay_ms(2);
279        while  ((SSPSTAT  &  0x04)  ||  (SSPCON2  &  0x1F));  //Transmit  is  in  progress
280  
281   }
282   //*****************************************************************************
283   void  i2c_WaitGeneral(void){
284        __delay_us(_wt_speed_i2c_Master  *  2);
285   }
286   //*****************************************************************************
287   void  I2C_ClockMasterSW(void){
288        SCL_MasterSW  =  0; 
289           __delay_us(_wt_speed_i2c_Master);              //  Wait  for  Some  time
290           SCL_MasterSW  =  1;  
291           __delay_us(_wt_speed_i2c_Master);              //  Wait  for  Some  time
292           SCL_MasterSW  =  0; 
293        __delay_us(_wt_speed_i2c_Master);      //  Wait  for  Some  time
294   }
295   //*****************************************************************************
296   void  InitMasterPort(uint8_t  type){
297        if  (type  ==  _SW){  InitMasterSwPort();}
298        else  InitMasterHwPort(); 
299   }
300   //*****************************************************************************
301  
302   void  InitMasterSwPort(void){
303        BitClear  (PORTB,SCL_MasterSW_PIN);
304        BitClear  (PORTB,SDA_MasterSW_PIN);
305        BitClear  (LATB,SCL_MasterSW_PIN);
306        BitClear  (LATB,SDA_MasterSW_PIN);
307        SDAt_MasterSW  =  Output;                    //  SDA  Output               
308        SCLt_MasterSW  =  Output;                    //  SCL  Output               
309        SDA_MasterSW   =  1;
310        SCL_MasterSW   =  1;
311   }
312   //*****************************************************************************
313   void  InitMasterHwPort(void){
314       BitClear  (PORTC,SCL_MasterHW_PIN);
315       BitClear  (PORTC,SDA_MasterHW_PIN);
316       BitClear  (LATC,SCL_MasterHW_PIN);
317       BitClear  (LATC,SDA_MasterHW_PIN);
318      
319       SCLt_MasterHW  =  Input;                            //  SCL  Input     
320       SDAt_MasterHW  =  Input;                            //  SDA  Input     
321  
322       SSPCON1  =  0b00101000;         //  I2C  enabled,  Master  mode
323       SSPCON2  =  0x00;
324       SSPADD  =  254;            //  100kHz  bus  with  20Mhz  xtal
325  
326   }