UoS³ Flight Computer Firmware
 All Data Structures Files Functions Groups Pages
i2c.c
1 
2 // i2c base functions, built over TI library functions - produce drivers for higher level functionality
3 //
4 // Suzanna Lucarotti (c) 31/8/2017
5 //
6 // for use with the UoS3 Cubesat
7 //
8 // hacked together from the various datasheets
9 
10 //#include "../firmware.h"
11 
12 #include <stdint.h>
13 #include <stdbool.h>
14 #include <stdlib.h>
15 #include <stdarg.h>
16 
17 
18 #include "inc/hw_i2c.h"
19 #include "inc/hw_memmap.h"
20 #include "inc/hw_types.h"
21 
22 #include "driverlib/gpio.h"
23 #include "driverlib/i2c.h"
24 #include "driverlib/pin_map.h"
25 #include "driverlib/sysctl.h"
26 
27 
28 #include "../i2c.h" // base definitions for functions
29 
30 /* I2C physical port description struct */
31 typedef struct I2C_port_t {
32  uint32_t peripheral_gpio; // TI Driver GPIO Peripheral Reference
33  uint32_t peripheral_i2c; // TI Driver I2C Peripheral Reference
34  uint32_t base_gpio; // TI Driver GPIO Base Reference
35  uint32_t base_i2c; // TI Driver I2C Base Reference
36  uint32_t pin_scl_function; // TI Driver I2C SCL Pin Reference
37  uint32_t pin_sda_function; // TI Driver I2C SDA Pin Reference
38  uint8_t pin_scl; // TI Driver SCL Pin Reference
39  uint8_t pin_sda; // TI Driver SDA Pin Reference
40  bool full_speed; // Standard Speed = 100KHz, Full Speed = 400KHz
41  bool initialised;
42 } I2C_port_t;
43 
44 static I2C_port_t I2C_ports[2] =
45  {
46  {
47  SYSCTL_PERIPH_GPIOB,
48  SYSCTL_PERIPH_I2C0,
49  GPIO_PORTB_BASE,
50  I2C0_BASE,
51  GPIO_PB2_I2C0SCL,
52  GPIO_PB3_I2C0SDA,
53  GPIO_PIN_2,
54  GPIO_PIN_3,
55  false,
56  false
57  },
58  {
59  SYSCTL_PERIPH_GPIOE,
60  SYSCTL_PERIPH_I2C2,
61  GPIO_PORTE_BASE,
62  I2C2_BASE,
63  GPIO_PE4_I2C2SCL,
64  GPIO_PE5_I2C2SDA,
65  GPIO_PIN_4,
66  GPIO_PIN_5,
67  false,
68  false
69  }
70  };
71 
72 #define NUMBER_OF_I2C_PORTS ( sizeof(I2C_ports) / sizeof(I2C_port_t) )
73 
74 #define check_i2c_num(x, y) if(x >= NUMBER_OF_I2C_PORTS) { return y; }
75 
78 void I2C_init(uint8_t i2c_num)
79 {
80  check_i2c_num(i2c_num,);
81  I2C_port_t *i2c = &I2C_ports[i2c_num];
82 
83  /* Check Virtual SPI is initialised */
84  if(!i2c->initialised)
85  {
86  /* Initialise SPI Peripheral if not already initialised */
87  if(!SysCtlPeripheralReady(i2c->peripheral_i2c))
88  {
89  SysCtlPeripheralReset(i2c->peripheral_gpio);
90  SysCtlPeripheralEnable(i2c->peripheral_i2c);
91  while(!SysCtlPeripheralReady(i2c->peripheral_i2c)) { };
92  }
93 
94  /* Initialise GPIO Peripheral if not already initialised */
95  if(!SysCtlPeripheralReady(i2c->peripheral_gpio))
96  {
97  SysCtlPeripheralReset(i2c->peripheral_gpio);
98  SysCtlPeripheralEnable(i2c->peripheral_gpio);
99  while(!SysCtlPeripheralReady(i2c->peripheral_gpio)) { };
100  }
101 
102  /* Configure Pins for I2C function */
103  GPIOPinConfigure(i2c->pin_sda_function);
104  GPIOPinConfigure(i2c->pin_scl_function);
105 
106  /* Assign pins to I2C peripheral */
107  GPIOPinTypeI2C(i2c->base_gpio, i2c->pin_sda);
108  GPIOPinTypeI2CSCL(i2c->base_gpio, i2c->pin_scl);
109 
110  /* Set peripheral clockrate */
111  I2CMasterInitExpClk(i2c->base_i2c, SysCtlClockGet(), i2c->full_speed);
112 
113  I2CMasterEnable(i2c->base_i2c);
114 
115  /* Clear current pending data */
116  I2CRxFIFOFlush(i2c->base_i2c);
117  I2CTxFIFOFlush(i2c->base_i2c);
118 
119  i2c->initialised = true;
120  }
121 }
122 
123 
125 
126 
127 #define I2CRECVMAXBUFFERLEN 4
128 
129 static uint8_t I2CReceiveBuffer[I2CRECVMAXBUFFERLEN+1]; // this is the receive array for receipt of data
130 
132 
133 
134 //sends an array of data via I2C to the specified slave, zero terminated as a string.
135 void I2CSendString(uint8_t i2c_num, uint8_t slave_addr, uint8_t array[])
136 {
137  check_i2c_num(i2c_num,);
138  I2C_port_t *i2c = &I2C_ports[i2c_num];
139 
140  I2C_init(i2c_num);
141 
142  I2CMasterSlaveAddrSet(i2c->base_i2c, slave_addr, false); // tell it which slave to talk to
143  I2CMasterDataPut(i2c->base_i2c, array[0]);
144 
145  if(array[1] == 0) // single byte mode
146  {
147  I2CMasterControl(i2c->base_i2c, I2C_MASTER_CMD_SINGLE_SEND);
148  while(I2CMasterBusy(i2c->base_i2c)); // wait
149  }
150 
151  else // multi byte mode
152  {
153  I2CMasterControl(i2c->base_i2c, I2C_MASTER_CMD_BURST_SEND_START);
154  while(I2CMasterBusy(i2c->base_i2c)); //wait
155  uint8_t i = 1;
156  while(array[i + 1] != 0) // keep going until find the end
157  {
158  I2CMasterDataPut(i2c->base_i2c, array[i++]);
159  I2CMasterControl(i2c->base_i2c, I2C_MASTER_CMD_BURST_SEND_CONT);
160  while(I2CMasterBusy(i2c->base_i2c));
161  }
162  I2CMasterDataPut(i2c->base_i2c, array[i]);
163  I2CMasterControl(i2c->base_i2c, I2C_MASTER_CMD_BURST_SEND_FINISH);
164  while(I2CMasterBusy(i2c->base_i2c));
165 
166  if (I2CMasterErr(i2c->base_i2c)) // error handling to stop I2C freezing if glitches during transmission
167  I2CMasterControl(i2c->base_i2c,I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
168  }
169 }
170 
171  // this is the guts of the function, called by intermediate functions to get around C's lack of function overloading
172 
173 uint8_t *I2CReceiveGP(uint8_t i2c_num, uint8_t slave_addr, uint8_t reg,uint8_t strlen, bool reverse) // returns zero pointer if an error...
174  {
175  check_i2c_num(i2c_num,NULL);
176  I2C_port_t *i2c = &I2C_ports[i2c_num];
177 
178  I2C_init(i2c_num);
179 
180  // else pointer to zero terminated string of bytes read, reversed if requested
181  // this should fill buffer exactly with no overrun, max buffer length defined as shown
182  if (strlen>I2CRECVMAXBUFFERLEN || strlen<=0) { return NULL;}
183  // before can receive data, have to tell slave what register to start at
184  I2CMasterSlaveAddrSet(i2c->base_i2c, slave_addr, false); // set address to send to
185  I2CMasterDataPut(i2c->base_i2c, reg); // tell it register to be read
186  I2CMasterControl(i2c->base_i2c, I2C_MASTER_CMD_SINGLE_SEND); // send message to prepare for read
187 
188  while(I2CMasterBusy(i2c->base_i2c)); // wait for I2c ready
189 
190  I2CMasterSlaveAddrSet(i2c->base_i2c, slave_addr, true); // set address to read from
191 
192  if (strlen==1) {
193  I2CMasterControl(i2c->base_i2c, I2C_MASTER_CMD_SINGLE_RECEIVE);
194  while(I2CMasterBusy(i2c->base_i2c));
195  I2CReceiveBuffer[0]=(uint8_t) I2CMasterDataGet(i2c->base_i2c); // exit with ptr to zero terminated two byte string
196  I2CReceiveBuffer[1]=0;
197  return I2CReceiveBuffer;
198  }
199  else // we want a burst from the slave, not just one byte, slave interprets burst reads as starting from given reg and ascending
200  {
201  I2CMasterControl(i2c->base_i2c, I2C_MASTER_CMD_BURST_RECEIVE_START);
202  while(I2CMasterBusy(i2c->base_i2c));
203  I2CReceiveBuffer[0]=(uint8_t) I2CMasterDataGet(i2c->base_i2c);
204  uint8_t i=1;
205  while (i<strlen-1) // do the middle bytes
206  {
207  while(I2CMasterBusy(i2c->base_i2c)); // wait for ready
208  I2CMasterControl(i2c->base_i2c, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
209  if (I2CMasterErr(i2c->base_i2c)) // error handling
210  {I2CMasterControl(i2c->base_i2c,I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP);return NULL;}
211  I2CReceiveBuffer[i]=(uint8_t) I2CMasterDataGet(i2c->base_i2c);
212  i++;
213  }
214 
215  I2CMasterControl(i2c->base_i2c, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
216  while(I2CMasterBusy(i2c->base_i2c));
217  I2CReceiveBuffer[strlen-1]=(uint8_t) I2CMasterDataGet(i2c->base_i2c);
218  I2CReceiveBuffer[strlen]=0;
219 
220  if (I2CMasterErr(i2c->base_i2c)) // error handling to stop I2C interface freezing if glitches during transmission
221  {I2CMasterControl(i2c->base_i2c,I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP);return NULL;}
222  }
223 
224  if (reverse==false) // handle big endian or little endian data
225  for (uint8_t i=0;i<(strlen/2);i++) // quick bytewise reverse
226  {uint8_t b=I2CReceiveBuffer[i];I2CReceiveBuffer[i]=I2CReceiveBuffer[strlen-i-1];I2CReceiveBuffer[strlen-i-1]=b;}
227  return I2CReceiveBuffer;
228  }
229 
230 uint8_t I2CReceive(uint8_t i2c_num, uint8_t slave_addr, uint8_t reg)
231 {
232  check_i2c_num(i2c_num,0);
233  I2C_init(i2c_num);
234 
235  uint8_t *ans=I2CReceiveGP(i2c_num, slave_addr,reg,1,false);
236 
237  if (ans==NULL) return 0; // error handling
238  return ans[0];
239  }
240 
241 uint16_t I2CReceive16(uint8_t i2c_num, uint8_t slave_addr,uint8_t reg) // lets get 2 byte value
242  {
243  check_i2c_num(i2c_num,0);
244  I2C_init(i2c_num);
245 
246  uint8_t *ans=I2CReceiveGP(i2c_num, slave_addr,reg,2,false);
247  if (ans==NULL) return 0; // error handling
248  //return ans[0]|(ans[1]<<8); // same as below, but below better
249  return *(uint16_t *)ans;
250  }
251 
252 uint16_t I2CReceive16r(uint8_t i2c_num, uint8_t slave_addr,uint8_t reg) // lets get 2 byte value reversed (for other endian words)
253  {
254  check_i2c_num(i2c_num,0);
255  I2C_init(i2c_num);
256 
257  uint8_t *ans=I2CReceiveGP(i2c_num, slave_addr,reg,2,true);
258  if (ans==NULL) return 0; // error handling
259  return *(uint16_t *)ans;
260  }
261 
262 
263 
Definition: i2c.c:31