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.
90 ticks_t start = timer_clock(); \
91 while( !(I2C_CONSET & BV(I2CON_SI)) ) \
93 if (timer_clock() - start > ms_to_ticks(CONFIG_I2C_START_TIMEOUT)) \
95 LOG_ERR("Timeout SI assert\n"); \
101 static uint8_t i2c_builtin_start(void)
103 // Clear all pending flags.
104 I2C_CONCLR = BV(I2CON_STAC) | BV(I2CON_SIC) | BV(I2CON_AAC);
106 // Set start and ack bit.
107 I2C_CONSET = BV(I2CON_STA) | BV(I2CON_AA);
116 * Send START condition and select slave for write.
117 * \c id is the device id comprehensive of address left shifted by 1.
118 * The LSB of \c id is ignored and reset to 0 for write operation.
120 * \return true on success, false otherwise.
122 bool i2c_builtin_start_w(uint8_t id)
124 ticks_t start = timer_clock();
125 while (i2c_builtin_start())
127 uint8_t status = GET_STATUS();
129 /* Start status ok, set addres and the R/W bit */
130 if ((status == I2C_STAT_SEND) || (status == I2C_STAT_RESEND))
131 I2C_DAT = id & ~I2C_READBIT;
133 /* Clear the start bit and clear the SI bit */
134 I2C_CONCLR = BV(I2CON_SIC) | BV(I2CON_STAC);
136 if (status == I2C_STAT_SLAW_ACK)
138 else if (status == I2C_STAT_ARB_LOST)
140 LOG_ERR("Arbitration lost\n");
144 if (timer_clock() - start > ms_to_ticks(CONFIG_I2C_START_TIMEOUT))
146 LOG_ERR("Timeout on I2C START\n");
155 * Send START condition and select slave for read.
156 * \c id is the device id comprehensive of address left shifted by 1.
157 * The LSB of \c id is ignored and set to 1 for read operation.
159 * \return true on success, false otherwise.
161 bool i2c_builtin_start_r(uint8_t id)
163 if (i2c_builtin_start())
165 uint8_t status = GET_STATUS();
167 /* Start status ok, set addres and the R/W bit */
168 if ((status == I2C_STAT_SEND) || (status == I2C_STAT_RESEND))
169 I2C_DAT = id | I2C_READBIT;
171 /* Clear the start bit and clear the SI bit */
172 I2C_CONCLR = BV(I2CON_SIC) | BV(I2CON_STAC);
176 status = GET_STATUS();
178 if (status == I2C_STAT_SLAR_ACK)
181 else if (status == I2C_STAT_SLAR_ACK)
183 LOG_ERR("SLAR NACK:%02x\n", status);
185 else if (status == I2C_STAT_ARB_LOST)
187 LOG_ERR("ARB Lost:%02x\n", status);
195 void i2c_builtin_stop(void)
197 /* Set the stop bit */
198 I2C_CONSET = BV(I2CON_STO);
199 /* Clear pending flags */
200 I2C_CONCLR = BV(I2CON_STAC) | BV(I2CON_SIC) | BV(I2CON_AAC);
204 bool i2c_builtin_put(const uint8_t data)
207 I2C_CONCLR = BV(I2CON_SIC);
211 uint32_t status = GET_STATUS();
213 if (status == I2C_STAT_DATA_ACK)
215 else if (status == I2C_STAT_DATA_NACK)
217 LOG_ERR("Data NACK\n");
220 else if (status == I2C_STAT_ERROR)
222 LOG_ERR("I2C error.\n");
225 else if (status == I2C_STAT_UNKNOW)
227 LOG_ERR("I2C unable to read status.\n");
235 int i2c_builtin_get(bool ack)
239 * Set ack bit if we want read more byte, otherwise
243 I2C_CONSET = BV(I2CON_AA);
245 I2C_CONCLR = BV(I2CON_AAC);
247 I2C_CONCLR = BV(I2CON_SIC);
251 uint32_t status = GET_STATUS();
253 if (status == I2C_STAT_RDATA_ACK)
254 return (uint8_t)I2C_DAT;
255 else if (status == I2C_STAT_RDATA_NACK)
257 else if (status == I2C_STAT_ERROR)
259 LOG_ERR("I2C error.\n");
262 else if (status == I2C_STAT_UNKNOW)
264 LOG_ERR("I2C unable to read status.\n");
274 * Initialize I2C module.
276 void i2c_builtin_init(void)
278 /* Enable I2C clock */
279 PCONP |= BV(I2C_PCONP);
281 #if (CONFIG_I2C_FREQ > 400000)
282 #error i2c frequency is to hight.
285 I2C_CONCLR = BV(I2CON_I2ENC) | BV(I2CON_STAC) | BV(I2CON_SIC) | BV(I2CON_AAC);
288 * Bit Frequency = Fplk / (I2C_I2SCLH + I2C_I2SCLL)
289 * value of I2SCLH and I2SCLL must be different
291 I2C_PCLKSEL &= ~I2C_PCLK_MASK;
292 I2C_PCLKSEL |= I2C_PCLK_DIV8;
294 I2C_SCLH = (((CPU_FREQ / 8) / CONFIG_I2C_FREQ) / 2) + 1;
295 I2C_SCLL = (((CPU_FREQ / 8) / CONFIG_I2C_FREQ) / 2);
297 ASSERT(I2C_SCLH > 4 || I2C_SCLL > 4);
299 /* Assign pins to SCL and SDA (P0_27, P0_28) */
300 I2C_PINSEL_PORT &= ~I2C_PINSEL_MASK;
301 I2C_PINSEL_PORT |= I2C_PINSEL;
304 I2C_CONSET = BV(I2CON_I2EN);