BeRTOS
|
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 /* At least 1 byte *must* be transmitted, thanks to crappy hw implementation */ 00073 ASSERT(size >= 1); 00074 00075 /* Check internal byte address presence */ 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 /* Wait tx buffer empty */ 00093 while (!(TWI_SR & BV(TWI_TXRDY))) 00094 { 00095 if (timer_clock() - start > TWI_TIMEOUT) 00096 return false; 00097 } 00098 00099 /* Set slave address and (optional) internal slave addresses */ 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 /* Send data */ 00107 TWI_THR = *buf++; 00108 00109 start = timer_clock(); 00110 /* Wait tx buffer empty */ 00111 while (!(TWI_SR & BV(TWI_TXRDY))) 00112 { 00113 if (timer_clock() - start > TWI_TIMEOUT) 00114 return false; 00115 } 00116 } 00117 00118 /* Wait transmit complete bit */ 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 /* At least 1 byte *must* be transmitted, thanks to crappy twi implementation */ 00148 ASSERT(size >= 1); 00149 00150 /* Check internal byte address presence */ 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 /* Wait tx buffer empty */ 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 /* Set slave address and (optional) internal slave addresses */ 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 * Start reception. 00182 * Kludge: if we want to receive only 1 byte, the stop but *must* be set here 00183 * (thanks to crappy twi implementation again). 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 /* If we are at the last byte, inform the crappy hw that we 00196 want to stop the reception. */ 00197 if (!size && !stopped) 00198 TWI_CR = BV(TWI_STOP); 00199 00200 /* Wait until a byte is received */ 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 /* Wait transmit complete bit */ 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 /* Disable PIO on TWI pins */ 00234 PIOA_PDR = BV(TWD) | BV(TWCK); 00235 00236 /* Enable oper drain on TWI pins */ 00237 PIOA_MDER = BV(TWD); 00238 00239 /* Disable all irqs */ 00240 TWI_IDR = 0xFFFFFFFF; 00241 00242 TWI_CR = BV(TWI_SWRST); 00243 00244 /* Enable master mode */ 00245 TWI_CR = BV(TWI_MSEN); 00246 00247 PMC_PCER = BV(TWI_ID); 00248 00249 /* 00250 * Compute twi clock. 00251 * CLDIV = ((Tlow * 2^CKDIV) -3) * Tmck 00252 * CHDIV = ((THigh * 2^CKDIV) -3) * Tmck 00253 * Only CLDIV is computed since CLDIV = CHDIV (50% duty cycle) 00254 */ 00255 uint16_t cldiv, ckdiv = 0; 00256 while ((cldiv = ((CPU_FREQ / (2 * CONFIG_I2C_FREQ)) - 3) / (1 << ckdiv)) > 255) 00257 ckdiv++; 00258 00259 /* Atmel errata states that ckdiv *must* be less than 5 for unknown reason */ 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