1 /*
2 *
3 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the
16 * distribution.
17 *
18 * Neither the name of Texas Instruments Incorporated nor the names of
19 * its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
38 /****************************************************************************************************
39 * FILE PURPOSE: Write an I2C eeprom
40 ****************************************************************************************************
41 * @file i2cWrite.c
42 *
43 * @brief
44 * Writes bytes to an i2c eeprom. The bytes are stored in word format, and written out
45 * in big endian format, regardless of the endianness of the device.
46 *
47 ****************************************************************************************************/
49 #include "types.h"
50 #include "i2c.h"
51 #include "target.h"
52 #include "pllapi.h"
53 #include <stdio.h>
54 #include <string.h>
56 #ifndef I2C_SIZE_BYTES
57 #define I2C_SIZE_BYTES 0x10000
58 #endif
60 /* Run time configuration */
61 unsigned int deviceFreqMhz = 1000;
62 unsigned int prediv = 1; /* Pre-divider */
63 unsigned int mult = 20; /* Multiplier */
64 unsigned int postdiv = 1; /* Post-divider */
66 unsigned int busAddress = IBL_CFG_I2C_MAP_TABLE_DATA_BUS_ADDR;
67 unsigned int i2cBlockSize = 64;
68 unsigned int nbytes = I2C_SIZE_BYTES;
69 unsigned int dataAddress = 0;
71 #define I2C_DATA_ADDRESS_MASK 0xffff /* 16 bits specifiy the address (4 msb roll into dev address) */
74 #pragma DATA_SECTION(i2cData, ".i2cData")
75 unsigned int i2cData[I2C_SIZE_BYTES >> 2];
77 #pragma DATA_SECTION(i2cRead, ".i2cRead")
78 unsigned int i2cRead[I2C_SIZE_BYTES >> 2];
80 #define I2C_MAX_BLOCK_SIZE_BYTES 256
81 unsigned char i2cBlock[I2C_MAX_BLOCK_SIZE_BYTES+4]; /* need 2 bytes for the address */
84 /**
85 * @brief
86 * Get a single byte of data from i2cData based on big endian ordering
87 */
89 UINT8 getByte(int idx)
90 {
91 int word;
92 int byte;
93 UINT8 u;
94 unsigned int v;
96 word = idx >> 2;
97 byte = idx & 0x3;
99 v = i2cData[word];
101 u = (v >> ((3 - byte) << 3)) & 0xff;
103 return (u);
105 }
108 /**
109 * @brief
110 * Form a block of data to write to the i2c. The block is
111 * created as a byte stream from the 4 byte stream in which
112 * the MSB is always sent first.
113 */
114 int formBlock (unsigned int addr, int byteIndex, int n)
115 {
116 int p;
117 int i;
119 /* Must start on a word aligned boundary */
120 if ((n & 0x3) != 0) {
121 printf ("Error: Invalid block base offset specified\n");
122 return (-1);
123 }
125 /* The 1st two bytes are the address */
126 i2cBlock[0] = (addr >> 8) & 0xff;
127 i2cBlock[1] = (addr >> 0) & 0xff;
129 p = byteIndex >> 2;
132 for (i = 0; i < i2cBlockSize; i += 4, p++) {
134 i2cBlock[i+2+0] = (i2cData[p] >> 24) & 0xff;
135 i2cBlock[i+2+1] = (i2cData[p] >> 16) & 0xff;
136 i2cBlock[i+2+2] = (i2cData[p] >> 8) & 0xff;
137 i2cBlock[i+2+3] = (i2cData[p] >> 0) & 0xff;
139 }
142 return (n+2);
144 }
147 /**
148 * @brief
149 * Display the error returned by the i2c driver
150 */
151 void showI2cError (I2C_RET iret)
152 {
153 char *ecode;
155 switch (iret) {
156 case I2C_RET_LOST_ARB: ecode = "I2C master lost an arbitration battle";
157 break;
159 case I2C_RET_NO_ACK: ecode = "I2C master detected no ack from slave";
160 break;
162 case I2C_RET_IDLE_TIMEOUT: ecode = "I2C timed out";
163 break;
165 case I2C_RET_BAD_REQUEST: ecode = "I2C driver detected a bad data request";
166 break;
168 case I2C_RET_CLOCK_STUCK_LOW: ecode = "I2C driver found the bus stuck low";
169 break;
171 case I2C_RET_GEN_ERROR: ecode = "I2C driver reported a general error";
172 break;
174 }
176 printf ("I2C reported error: %s\n", ecode);
178 }
181 void main (void)
182 {
183 I2C_RET i2cRet;
184 int n, m, p;
185 int remain;
186 int progBytes;
187 int eCount;
189 unsigned int bAddress;
191 UINT8 *iData;
192 UINT8 writeByte;
193 int j;
195 volatile int i;
198 /* Program the main system PLL */
199 hwPllSetPll (0, /* Main PLL */
200 prediv, /* Pre-divider */
201 mult, /* Multiplier */
202 postdiv); /* Post-divider */
204 hwI2Cinit (deviceFreqMhz,
205 DEVICE_I2C_MODULE_DIVISOR,
206 25, /* Run the bus at 25 kHz */
207 10);
211 for (n = 0; n < nbytes; n += i2cBlockSize) {
213 remain = nbytes - n;
214 if (remain > i2cBlockSize)
215 remain = i2cBlockSize;
217 /* formBlock sets up the address as well as the data */
218 progBytes = formBlock (dataAddress + n, n, remain);
220 /* Form the i2c bus address. Bits from the i2c address can roll into the bus address field */
221 bAddress = (((busAddress << 16) & ~I2C_DATA_ADDRESS_MASK) + dataAddress + n) >> 16;
223 if (progBytes < 0)
224 return;
226 /* Write the block */
227 i2cRet = hwI2cMasterWrite (bAddress,
228 i2cBlock,
229 progBytes,
230 I2C_RELEASE_BUS,
231 FALSE);
234 if (i2cRet != I2C_RET_OK) {
235 showI2cError (i2cRet);
236 return;
237 }
241 /* Some delay */
242 for (i = 0; i < 600000; i++);
244 }
246 printf ("I2C write complete, reading data\n");
248 memset (i2cRead, 0xffffffff, sizeof(i2cRead));
250 iData = (UINT8 *)i2cRead;
252 for (p = 0, n = nbytes; n > 0; n = n - m, p = p + m) {
254 /* bAddress is the complete address, device address in bits 31:16 */
255 bAddress = ((busAddress << 16) & ~I2C_DATA_ADDRESS_MASK) + dataAddress + p;
257 /* m is the number of bytes that can be read from the current device address */
258 m = (bAddress + 0x10000) - bAddress;
259 if (m > n) m = n;
261 /* Read the data back */
262 i2cRet = hwI2cMasterRead (bAddress & 0xffff,
263 m,
264 &iData[p],
265 bAddress >> 16,
266 0x100);
269 if (i2cRet != I2C_RET_OK) {
270 showI2cError (i2cRet);
271 return;
272 }
274 }
276 printf ("I2C read complete, comparing data\n");
278 /* The data received was simply packed bytes, but the data sent was in big endian mode,
279 * so the compare must get the ordering correct */
280 iData = (UINT8 *)i2cRead;
281 eCount = 0;
282 for (j = 0; j < nbytes; j++) {
284 writeByte = getByte(j);
285 if (writeByte != iData[j]) {
286 printf ("Error at data byte %d: expected 0x%02x, read 0x%02x\n", j, writeByte, iData[j]);
287 eCount += 1;
288 }
290 if (eCount >= 20) {
291 printf ("Too many errors, stopping compare\n");
292 break;
293 }
295 }
297 if (eCount == 0)
298 printf ("Data compare passed\n");
299 else
300 printf ("Data compare failed\n");
304 }