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>
58 #define I2C_READBIT BV(0)
66 #define I2C_PCONP PCONP_PCI2C0
67 #define I2C_CONSET I20CONSET
68 #define I2C_CONCLR I20CONCLR
69 #define I2C_SCLH I20SCLH
70 #define I2C_SCLL I20SCLL
71 #define I2C_STAT I20STAT
72 #define I2C_DAT I20DAT
73 #define I2C_SDA_PINSEL_MASK I2C_SDA0_PINSEL_MASK
74 #define I2C_SCL_PINSEL_MASK I2C_SCL0_PINSEL_MASK
75 #define I2C_SDA_PINSEL I2C_SDA0_PINSEL
76 #define I2C_SCL_PINSEL I2C_SCL0_PINSEL
81 #define GET_STATUS() (I2C_STAT)
83 static uint8_t i2c_builtin_start(void)
85 I2C_CONSET = BV(I2CON_STA) | BV(I2CON_AA);
87 while( !(I2C_CONSET & BV(I2CON_SI)) );
94 * Send START condition and select slave for write.
95 * \c id is the device id comprehensive of address left shifted by 1.
96 * The LSB of \c id is ignored and reset to 0 for write operation.
98 * \return true on success, false otherwise.
100 bool i2c_builtin_start_w(uint8_t id)
102 ticks_t start = timer_clock();
103 while (i2c_builtin_start())
105 uint32_t status = GET_STATUS();
107 if ((status == I2C_STAT_SEND) || (status == I2C_STAT_RESEND))
108 I2C_DAT = id & ~I2C_READBIT;
110 /* Clear the start bit and clear the SI bit */
111 I2C_CONCLR = BV(I2CON_SIC) | BV(I2CON_STAC);
113 if (status == I2C_STAT_SLAW_ACK)
115 else if (status == I2C_STAT_ARB_LOST)
117 else if (timer_clock() - start > ms_to_ticks(CONFIG_I2C_START_TIMEOUT))
119 LOG_ERR("Timeout on I2C START\n");
128 * Send START condition and select slave for read.
129 * \c id is the device id comprehensive of address left shifted by 1.
130 * The LSB of \c id is ignored and set to 1 for read operation.
132 * \return true on success, false otherwise.
134 bool i2c_builtin_start_r(uint8_t id)
136 if (i2c_builtin_start())
138 uint32_t status = GET_STATUS();
140 if ((status == I2C_STAT_SEND) || (status == I2C_STAT_RESEND))
141 I2C_DAT = id | I2C_READBIT;
143 /* Clear the start bit and clear the SI bit */
144 I2C_CONCLR = BV(I2CON_SIC) | BV(I2CON_STAC);
146 while( !(I2C_CONSET & BV(I2CON_SI)) );
148 status = GET_STATUS();
150 if (status == I2C_STAT_SLAR_ACK)
152 else if (status == I2C_STAT_ARB_LOST)
160 void i2c_builtin_stop(void)
162 I2C_CONSET = BV(I2CON_STO);
163 I2C_CONCLR = BV(I2CON_STAC) | BV(I2CON_SIC) | BV(I2CON_AAC);
167 bool i2c_builtin_put(const uint8_t data)
174 int i2c_builtin_get(bool ack)
181 * With this function is allowed only the atomic write.
183 bool i2c_send(const void *_buf, size_t count)
185 const uint8_t *buf = (const uint8_t *)_buf;
191 I2C_CONSET = BV(I2CON_AA);
192 I2C_CONCLR = BV(I2CON_SIC);
195 while( !(I2C_CONSET & BV(I2CON_SI)) );
197 status = GET_STATUS();
198 if (status == I2C_STAT_DATA_ACK)
200 else if (status == I2C_STAT_DATA_NACK)
202 LOG_ERR("send:%02x\n", (uint8_t)status);
205 else if (status == 0xf8)
207 LOG_ERR("send:%02x\n", (uint8_t)status);
210 else if (status == 0x10)
212 LOG_ERR("send:%02x\n", (uint8_t)status);
222 * In order to read bytes from the i2c we should make some tricks.
224 bool i2c_recv(void *_buf, size_t count)
226 uint8_t *buf = (uint8_t *)_buf;
227 uint8_t status = GET_STATUS();
229 // LOG_ERR("recv:%02x\n", (uint8_t)status);
235 I2C_CONSET = BV(I2CON_AA);
237 I2C_CONCLR = BV(I2CON_AAC);
239 I2C_CONCLR = BV(I2CON_SIC);
242 while( !(I2C_CONSET & BV(I2CON_SI)) );
244 status = GET_STATUS();
246 if (status == I2C_STAT_RDATA_ACK)
248 else if (status == I2C_STAT_RDATA_NACK)
250 // LOG_ERR("recv:%02x\n", (uint8_t)status);
253 else if (status == 0xf8)
255 LOG_ERR("recv:%02x\n", (uint8_t)status);
258 else if (status == 0x10)
260 LOG_ERR("recv:%02x\n", (uint8_t)status);
271 * Initialize I2C module.
273 void i2c_builtin_init(void)
275 /* Enable I2C clock */
276 PCONP |= BV(I2C_PCONP);
278 #if (CONFIG_I2C_FREQ > 400000)
279 #error i2c frequency is to hight.
282 I2C_CONCLR = BV(I2CON_I2ENC) | BV(I2CON_STAC) | BV(I2CON_SIC) | BV(I2CON_AAC);
285 * Bit Frequency = Fplk / (I2C_I2SCLH + I2C_I2SCLL)
286 * value of I2SCLH and I2SCLL must be different
288 PCLKSEL0 &= ~I2C0_PCLK_MASK;
289 PCLKSEL0 |= I2C0_PCLK_DIV8;
291 I2C_SCLH = (((CPU_FREQ / 8) / CONFIG_I2C_FREQ) / 2) + 1;
292 I2C_SCLL = (((CPU_FREQ / 8) / CONFIG_I2C_FREQ) / 2);
294 ASSERT(I2C_SCLH > 4 || I2C_SCLL > 4);
296 /* Assign pins to SCL and SDA (P0_27, P0_28) */
297 PINSEL1 &= ~I2C_PINSEL_MASK;
298 PINSEL1 |= I2C_PINSEL;
301 I2C_CONSET = BV(I2CON_I2EN);