1 /* 2 * Ben NanoNote I2C communication. 3 * 4 * Copyright (C) 2013 Paul Boddie 5 * 6 * This program 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. 10 */ 11 12 #include <time.h> 13 #include "i2c.h" 14 15 extern uint32_t I2C_SCL, I2C_SDA; 16 17 void wait() 18 { 19 /* NOTE: Would want 600ns or 1300ns, but nanosleep appears too slow. 20 struct timespec ts = {0, 600}; 21 nanosleep(&ts, NULL); */ 22 23 uint8_t i; 24 for (i = 0; i < 200; i++); 25 } 26 27 /** 28 * Declare the pins for initial I2C communications. 29 */ 30 void i2c_init() 31 { 32 OUT(I2C_SCL); 33 OUT(I2C_SDA); 34 } 35 36 /** 37 * Initiate an I2C transaction. 38 */ 39 void i2c_start() 40 { 41 OUT(I2C_SDA); 42 CLR(I2C_SCL); 43 wait(); 44 SET(I2C_SDA); 45 SET(I2C_SCL); 46 wait(); 47 CLR(I2C_SDA); 48 } 49 50 /** 51 * Terminate an I2C transaction. 52 */ 53 void i2c_stop() 54 { 55 OUT(I2C_SDA); 56 CLR(I2C_SCL); 57 wait(); 58 CLR(I2C_SDA); 59 SET(I2C_SCL); 60 wait(); 61 SET(I2C_SDA); 62 } 63 64 /** 65 * Send an I2C acknowledgement to a transmitting device. 66 */ 67 void i2c_ack(bool ack) 68 { 69 OUT(I2C_SDA); 70 71 if (ack) 72 CLR(I2C_SDA); 73 else 74 SET(I2C_SDA); 75 76 SET(I2C_SCL); 77 wait(); 78 CLR(I2C_SCL); 79 80 IN(I2C_SDA); 81 } 82 83 /** 84 * Receive a single byte from an I2C device as part of a transaction. 85 */ 86 uint8_t i2c_recv() 87 { 88 uint8_t mask, result = 0; 89 90 IN(I2C_SDA); 91 CLR(I2C_SCL); 92 93 for (mask = 0x80; mask; mask >>= 1) 94 { 95 SET(I2C_SCL); 96 wait(); 97 98 if (PIN(I2C_SDA)) 99 result |= mask; 100 101 CLR(I2C_SCL); 102 wait(); 103 } 104 105 return result; 106 } 107 108 /** 109 * Receive into a buffer a transmission of the given length in bytes. 110 */ 111 void i2c_recvmany(uint8_t *data, uint8_t len) 112 { 113 uint8_t *end = data + len; 114 115 for (; data != end; data++, len--) 116 { 117 *data = i2c_recv(); 118 i2c_ack(len > 1); 119 } 120 } 121 122 void i2c_wait() 123 { 124 IN(I2C_SCL); 125 while (!PIN(I2C_SCL)); 126 OUT(I2C_SCL); 127 } 128 129 /** 130 * Send a single byte of data to an I2C device as part of a transaction, 131 * returning whether the transmission succeeded. 132 */ 133 bool i2c_send(uint8_t data) 134 { 135 uint8_t mask; 136 bool status; 137 138 OUT(I2C_SDA); 139 CLR(I2C_SCL); 140 141 for (mask = 0x80; mask; mask >>= 1) 142 { 143 wait(); 144 145 if (data & mask) 146 SET(I2C_SDA); 147 else 148 CLR(I2C_SDA); 149 150 SET(I2C_SCL); 151 wait(); 152 CLR(I2C_SCL); 153 } 154 155 /* Wait for acknowledgement, failing if none is given. */ 156 157 IN(I2C_SDA); 158 SET(I2C_SCL); 159 wait(); 160 161 status = PIN(I2C_SDA); 162 CLR(I2C_SCL); 163 return !status; 164 } 165 166 /** 167 * Send from the buffer provided a transmission with the given length to an I2C 168 * device. 169 */ 170 bool i2c_sendmany(uint8_t *data, uint8_t len) 171 { 172 uint8_t *end = data + len; 173 174 for (; data != end; data++) 175 { 176 if (!i2c_send(*data)) 177 return false; 178 179 /* NOTE: Should test for the slave holding the clock signal low. */ 180 } 181 182 return true; 183 }