twi_at91.c
Go to the documentation of this file.00001
00039 #include "twi_at91.h"
00040
00041 #include "cfg/cfg_i2c.h"
00042 #include <cfg/compiler.h>
00043 #include <cfg/debug.h>
00044 #include <cfg/macros.h>
00045 #include <cfg/module.h>
00046
00047 #include <drv/timer.h>
00048
00049 #include <io/arm.h>
00050
00054 #define TWI_TIMEOUT ms_to_ticks(50)
00055
00066 bool twi_write(uint8_t id, twi_iaddr_t byte1, twi_iaddr_t byte2, twi_iaddr_t byte3, const void *_buf, size_t size)
00067 {
00068 uint8_t addr_size = 0;
00069 const uint8_t *buf = (const uint8_t *)_buf;
00070 ticks_t start;
00071
00072
00073 ASSERT(size >= 1);
00074
00075
00076 if (byte1 != TWI_NO_IADDR)
00077 addr_size++;
00078
00079 if (byte2 != TWI_NO_IADDR)
00080 {
00081 ASSERT(addr_size == 1);
00082 addr_size++;
00083 }
00084
00085 if (byte3 != TWI_NO_IADDR)
00086 {
00087 ASSERT(addr_size == 2);
00088 addr_size++;
00089 }
00090
00091 start = timer_clock();
00092
00093 while (!(TWI_SR & BV(TWI_TXRDY)))
00094 {
00095 if (timer_clock() - start > TWI_TIMEOUT)
00096 return false;
00097 }
00098
00099
00100 TWI_MMR = (uint32_t)id << TWI_DADR_SHIFT | (uint32_t)addr_size << TWI_IADRSZ_SHIFT;
00101
00102 TWI_IADR = ((uint32_t)(byte3 & 0xff) << 16) | ((uint32_t)(byte2 & 0xff) << 8) | ((uint32_t)(byte1 & 0xff));
00103
00104 while (size--)
00105 {
00106
00107 TWI_THR = *buf++;
00108
00109 start = timer_clock();
00110
00111 while (!(TWI_SR & BV(TWI_TXRDY)))
00112 {
00113 if (timer_clock() - start > TWI_TIMEOUT)
00114 return false;
00115 }
00116 }
00117
00118
00119 start = timer_clock();
00120 while (!(TWI_SR & BV(TWI_TXCOMP)))
00121 {
00122 if (timer_clock() - start > TWI_TIMEOUT)
00123 return false;
00124 }
00125
00126 return true;
00127 }
00128
00129
00140 bool twi_read(uint8_t id, twi_iaddr_t byte1, twi_iaddr_t byte2, twi_iaddr_t byte3, void *_buf, size_t size)
00141 {
00142 uint8_t addr_size = 0;
00143 uint8_t *buf = (uint8_t *)_buf;
00144 bool stopped = false;
00145 ticks_t start;
00146
00147
00148 ASSERT(size >= 1);
00149
00150
00151 if (byte1 != TWI_NO_IADDR)
00152 addr_size++;
00153
00154 if (byte2 != TWI_NO_IADDR)
00155 {
00156 ASSERT(addr_size == 1);
00157 addr_size++;
00158 }
00159
00160 if (byte3 != TWI_NO_IADDR)
00161 {
00162 ASSERT(addr_size == 2);
00163 addr_size++;
00164 }
00165
00166
00167 start = timer_clock();
00168 while (!(TWI_SR & BV(TWI_TXRDY)))
00169 {
00170 if (timer_clock() - start > TWI_TIMEOUT)
00171 return false;
00172 }
00173
00174
00175
00176 TWI_MMR = ((uint32_t)id << TWI_DADR_SHIFT) | BV(TWI_MREAD) | ((uint32_t)addr_size << TWI_IADRSZ_SHIFT);
00177
00178 TWI_IADR = ((uint32_t)(byte3 & 0xff) << 16) | ((uint32_t)(byte2 & 0xff) << 8) | ((uint32_t)(byte1 & 0xff));
00179
00180
00181
00182
00183
00184
00185 if (size == 1)
00186 {
00187 TWI_CR = BV(TWI_START) | BV(TWI_STOP);
00188 stopped = true;
00189 }
00190 else
00191 TWI_CR = BV(TWI_START);
00192
00193 while (size--)
00194 {
00195
00196
00197 if (!size && !stopped)
00198 TWI_CR = BV(TWI_STOP);
00199
00200
00201 start = timer_clock();
00202 while (!(TWI_SR & BV(TWI_RXRDY)))
00203 {
00204 if (timer_clock() - start > TWI_TIMEOUT)
00205 {
00206 TWI_CR = BV(TWI_STOP);
00207 return false;
00208 }
00209 }
00210
00211
00212 *buf++ = TWI_RHR;
00213 }
00214
00215
00216 start = timer_clock();
00217 while (!(TWI_SR & BV(TWI_TXCOMP)))
00218 {
00219 if (timer_clock() - start > TWI_TIMEOUT)
00220 return false;
00221 }
00222
00223 return true;
00224 }
00225
00226 MOD_DEFINE(twi);
00227
00231 void twi_init(void)
00232 {
00233
00234 PIOA_PDR = BV(TWD) | BV(TWCK);
00235
00236
00237 PIOA_MDER = BV(TWD);
00238
00239
00240 TWI_IDR = 0xFFFFFFFF;
00241
00242 TWI_CR = BV(TWI_SWRST);
00243
00244
00245 TWI_CR = BV(TWI_MSEN);
00246
00247 PMC_PCER = BV(TWI_ID);
00248
00249
00250
00251
00252
00253
00254
00255 uint16_t cldiv, ckdiv = 0;
00256 while ((cldiv = ((CPU_FREQ / (2 * CONFIG_I2C_FREQ)) - 3) / (1 << ckdiv)) > 255)
00257 ckdiv++;
00258
00259
00260 ASSERT(ckdiv < 5);
00261
00262 TWI_CWGR = ((uint32_t)ckdiv << TWI_CKDIV_SHIFT) | (cldiv << TWI_CLDIV_SHIFT) | (cldiv << TWI_CHDIV_SHIFT);
00263 TRACEMSG("TWI_CWGR [%08lx]", TWI_CWGR);
00264
00265 MOD_INIT(twi);
00266 }
00267