4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
33 * \brief Driver for the LPC23xx I2C (implementation)
37 #include "cfg/cfg_i2c.h"
39 #define LOG_LEVEL I2C_LOG_LEVEL
40 #define LOG_FORMAT I2C_LOG_FORMAT
44 #include <cfg/debug.h>
45 #include <cfg/macros.h> // BV()
46 #include <cfg/module.h>
48 #include <cpu/detect.h>
51 #include <drv/timer.h>
53 #include <drv/vic_lpc2.h> /* vic_handler_t */
55 #include <io/lpc23xx.h>
62 #define I2C_PCONP PCONP_PCI2C0
63 #define I2C_CONSET I20CONSET
64 #define I2C_CONCLR I20CONCLR
65 #define I2C_SCLH I20SCLH
66 #define I2C_SCLL I20SCLL
67 #define I2C_STAT I20STAT
68 #define I2C_DAT I20DAT
69 #define I2C_PINSEL_PORT PINSEL1
70 #define I2C_PINSEL I2C0_PINSEL
71 #define I2C_PINSEL_MASK I2C0_PINSEL_MASK
72 #define I2C_PCLKSEL PCLKSEL0
73 #define I2C_PCLK_MASK I2C0_PCLK_MASK
74 #define I2C_PCLK_DIV8 I2C0_PCLK_DIV8
80 #define GET_STATUS() ((uint8_t)I2C_STAT)
82 * Wait that SI bit is set.
84 * Note: this bit is set when the I2C state changes. However, entering
85 * state F8 does not set SI since there is nothing for an interrupt service
86 * routine to do in that case.
88 #define WAIT_SI() while( !(I2C_CONSET & BV(I2CON_SI)) )
90 static uint8_t i2c_builtin_start(void)
92 // Clear all pending flags.
93 I2C_CONCLR = BV(I2CON_STAC) | BV(I2CON_SIC) | BV(I2CON_AAC);
95 // Set start and ack bit.
96 I2C_CONSET = BV(I2CON_STA) | BV(I2CON_AA);
105 * Send START condition and select slave for write.
106 * \c id is the device id comprehensive of address left shifted by 1.
107 * The LSB of \c id is ignored and reset to 0 for write operation.
109 * \return true on success, false otherwise.
111 bool i2c_builtin_start_w(uint8_t id)
113 ticks_t start = timer_clock();
114 while (i2c_builtin_start())
116 uint8_t status = GET_STATUS();
118 /* Start status ok, set addres and the R/W bit */
119 if ((status == I2C_STAT_SEND) || (status == I2C_STAT_RESEND))
120 I2C_DAT = id & ~I2C_READBIT;
122 /* Clear the start bit and clear the SI bit */
123 I2C_CONCLR = BV(I2CON_SIC) | BV(I2CON_STAC);
125 if (status == I2C_STAT_SLAW_ACK)
127 else if (status == I2C_STAT_ARB_LOST)
129 LOG_ERR("Arbitration lost\n");
132 else if (timer_clock() - start > ms_to_ticks(CONFIG_I2C_START_TIMEOUT))
134 LOG_ERR("Timeout on I2C START\n");
143 * Send START condition and select slave for read.
144 * \c id is the device id comprehensive of address left shifted by 1.
145 * The LSB of \c id is ignored and set to 1 for read operation.
147 * \return true on success, false otherwise.
149 bool i2c_builtin_start_r(uint8_t id)
151 if (i2c_builtin_start())
153 uint8_t status = GET_STATUS();
155 /* Start status ok, set addres and the R/W bit */
156 if ((status == I2C_STAT_SEND) || (status == I2C_STAT_RESEND))
157 I2C_DAT = id | I2C_READBIT;
159 /* Clear the start bit and clear the SI bit */
160 I2C_CONCLR = BV(I2CON_SIC) | BV(I2CON_STAC);
164 status = GET_STATUS();
166 if (status == I2C_STAT_SLAR_ACK)
169 else if (status == I2C_STAT_SLAR_ACK)
171 LOG_ERR("SLAR NACK:%02x\n", status);
173 else if (status == I2C_STAT_ARB_LOST)
175 LOG_ERR("ARB Lost:%02x\n", status);
183 void i2c_builtin_stop(void)
185 /* Set the stop bit */
186 I2C_CONSET = BV(I2CON_STO);
187 /* Clear pending flags */
188 I2C_CONCLR = BV(I2CON_STAC) | BV(I2CON_SIC) | BV(I2CON_AAC);
192 bool i2c_builtin_put(const uint8_t data)
199 int i2c_builtin_get(bool ack)
206 * With this function is allowed only the atomic write.
208 bool i2c_send(const void *_buf, size_t count)
210 const uint8_t *buf = (const uint8_t *)_buf;
216 I2C_CONCLR = BV(I2CON_SIC);
221 status = GET_STATUS();
223 if (status == I2C_STAT_DATA_ACK)
225 else if (status == I2C_STAT_DATA_NACK)
227 LOG_ERR("Data NACK\n");
230 else if (status == I2C_STAT_ERROR)
232 LOG_ERR("I2C error.\n");
235 else if (status == I2C_STAT_UNKNOW)
237 LOG_ERR("I2C unable to read status.\n");
247 * In order to read bytes from the i2c we should make some tricks.
249 bool i2c_recv(void *_buf, size_t count)
251 uint8_t *buf = (uint8_t *)_buf;
252 uint8_t status = GET_STATUS();
255 I2C_CONSET = BV(I2CON_AA);
256 I2C_CONCLR = BV(I2CON_SIC);
264 * Set ack bit if we want read more byte, otherwise
268 I2C_CONSET = BV(I2CON_AA);
270 I2C_CONCLR = BV(I2CON_AAC);
272 I2C_CONCLR = BV(I2CON_SIC);
277 status = GET_STATUS();
279 if (status == I2C_STAT_RDATA_ACK)
281 else if (status == I2C_STAT_RDATA_NACK)
283 else if (status == I2C_STAT_ERROR)
285 LOG_ERR("I2C error.\n");
288 else if (status == I2C_STAT_UNKNOW)
290 LOG_ERR("I2C unable to read status.\n");
301 * Initialize I2C module.
303 void i2c_builtin_init(void)
305 /* Enable I2C clock */
306 PCONP |= BV(I2C_PCONP);
308 #if (CONFIG_I2C_FREQ > 400000)
309 #error i2c frequency is to hight.
312 I2C_CONCLR = BV(I2CON_I2ENC) | BV(I2CON_STAC) | BV(I2CON_SIC) | BV(I2CON_AAC);
315 * Bit Frequency = Fplk / (I2C_I2SCLH + I2C_I2SCLL)
316 * value of I2SCLH and I2SCLL must be different
318 I2C_PCLKSEL &= ~I2C_PCLK_MASK;
319 I2C_PCLKSEL |= I2C_PCLK_DIV8;
321 I2C_SCLH = (((CPU_FREQ / 8) / CONFIG_I2C_FREQ) / 2) + 1;
322 I2C_SCLL = (((CPU_FREQ / 8) / CONFIG_I2C_FREQ) / 2);
324 ASSERT(I2C_SCLH > 4 || I2C_SCLL > 4);
326 /* Assign pins to SCL and SDA (P0_27, P0_28) */
327 I2C_PINSEL_PORT &= ~I2C_PINSEL_MASK;
328 I2C_PINSEL_PORT |= I2C_PINSEL;
331 I2C_CONSET = BV(I2CON_I2EN);