📄 i2c.c
字号:
/* * Copyright (c) 2006, Swedish Institute of Computer Science * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)$Id: i2c.c,v 1.2 2007/01/12 13:41:57 bg- Exp $ *//* * Small and portable implementation of a bit-banging I2C bus master. * * The code should port really easily to platforms other than the * msp430 but has some hardcoded constants in it. * * More info at: * http://i2c-bus.org/ * http://www.esacademy.com/faq/i2c/ */#include <stdio.h>#include <io.h>#include <contiki.h>#include <dev/spi.h>#include <dev/leds.h>#include "dev/i2c.h"/* * On the Tmote sky access to I2C/SPI/UART0 must always be exclusive. */void i2c_enable(void);void i2c_disable(void);int i2c_start(void);unsigned i2c_read(int send_ack);int i2c_write(unsigned);void i2c_stop(void);#define I2C_PxDIR P3DIR#define I2C_PxIN P3IN#define I2C_PxOUT P3OUT#define I2C_PxSEL P3SEL/* * SDA == P3.1 * SCL == P3.3 */#define SDA 1#define SCL 3#define SDA_0() (I2C_PxDIR |= BV(SDA)) /* SDA Output */#define SDA_1() (I2C_PxDIR &= ~BV(SDA)) /* SDA Input */#define SDA_IS_1 (I2C_PxIN & BV(SDA))#define SCL_0() (I2C_PxDIR |= BV(SCL)) /* SCL Output */#define SCL_1() (I2C_PxDIR &= ~BV(SCL)) /* SCL Input */#define SCL_IS_1 (I2C_PxIN & BV(SCL))/* * Should avoid infinite looping while waiting for SCL_IS_1. xxx/bg */#define SCL_WAIT_FOR_1() do{}while (!SCL_IS_1)#define delay_4_7us() do{ _NOP(); _NOP(); _NOP(); _NOP(); \ _NOP(); _NOP(); _NOP(); _NOP(); \ _NOP(); _NOP(); _NOP(); _NOP(); }while(0)#define delay_4us() do{ _NOP(); _NOP(); _NOP(); _NOP(); \ _NOP(); _NOP(); _NOP(); _NOP(); \ _NOP(); _NOP(); }while(0)static unsigned char old_pxsel, old_pxout, old_pxdir;/* * Grab SDA and SCL pins for exclusive use but remember old * configuration so that it may be restored when we are done. */voidi2c_enable(void){ unsigned char sda_scl = BV(SDA)|BV(SCL); old_pxsel = I2C_PxSEL & sda_scl; old_pxout = I2C_PxOUT & sda_scl; old_pxdir = I2C_PxDIR & sda_scl; spi_busy = 1; I2C_PxSEL &= ~sda_scl; I2C_PxOUT &= ~sda_scl; I2C_PxDIR |= BV(SCL); /* SCL Output */ I2C_PxDIR &= ~BV(SDA); /* SDA Input */}/* * Restore bus to what it was before i2c_enable. * */voidi2c_disable(void){ unsigned char not_sda_scl = ~(BV(SDA)|BV(SCL)); I2C_PxDIR = (I2C_PxDIR & not_sda_scl) | old_pxdir; I2C_PxOUT = (I2C_PxOUT & not_sda_scl) | old_pxout; I2C_PxSEL = (I2C_PxSEL & not_sda_scl) | old_pxsel; spi_busy = 0;}inti2c_start(void){ SDA_1(); SCL_1();#if 1 SCL_WAIT_FOR_1();#else { unsigned long n; for (n = 0; n < 100000 && !SCL_IS_1; n++) ; if (!SCL_IS_1) return -1; }#endif delay_4_7us(); SDA_0(); delay_4us(); SCL_0(); return 0;}voidi2c_stop(void){ SDA_0(); delay_4us(); SCL_1(); SCL_WAIT_FOR_1(); SDA_1();}/* * Return true if we received an ACK. */inti2c_write(unsigned _c){ unsigned char c = _c; unsigned long n; int i; int ret; for (i = 0; i < 8; i++, c <<= 1) { if (c & 0x80) SDA_1(); else SDA_0(); SCL_1(); SCL_WAIT_FOR_1(); SCL_0(); } SDA_1(); SCL_1(); ret = 0; /* Loop waiting for an ACK to arrive. */ for (n = 0; n < 250000; n++) { if (!SDA_IS_1) { ret = 1; break; } } SCL_WAIT_FOR_1(); /* clock stretching? */ SCL_0(); return ret;}unsignedi2c_read(int send_ack){ int i; unsigned char c = 0x00; SDA_1(); for (i = 0; i < 8; i++) { c <<= 1; SCL_1(); SCL_WAIT_FOR_1(); if (SDA_IS_1) c |= 0x1; SCL_0(); } if (send_ack) SDA_0(); SCL_1(); SCL_WAIT_FOR_1(); SCL_0(); return c;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -