i2c_sam3.c
Go to the documentation of this file.
00001 00041 #include "cfg/cfg_i2c.h" 00042 00043 #define LOG_LEVEL I2C_LOG_LEVEL 00044 #define LOG_FORMAT I2C_LOG_FORMAT 00045 00046 #include <cfg/log.h> 00047 00048 #include <hw/hw_cpufreq.h> // CPU_FREQ 00049 #include <cfg/debug.h> 00050 #include <cfg/macros.h> // BV() 00051 #include <cfg/module.h> 00052 #include <cpu/detect.h> 00053 #include <cpu/irq.h> 00054 #include <cpu/power.h> 00055 #include <drv/timer.h> 00056 #include <drv/i2c.h> 00057 #include <io/sam3.h> 00058 00059 00060 struct I2cHardware 00061 { 00062 uint32_t base; 00063 bool first_xtranf; 00064 }; 00065 00066 00067 INLINE bool waitTxRdy(I2c *i2c, time_t ms_timeout) 00068 { 00069 ticks_t start = timer_clock(); 00070 00071 while (!(HWREG(i2c->hw->base + TWI_SR_OFF) & TWI_SR_TXRDY)) 00072 { 00073 if (timer_clock() - start > ms_to_ticks(ms_timeout)) 00074 return false; 00075 cpu_relax(); 00076 } 00077 00078 return true; 00079 } 00080 00081 INLINE bool waitRxRdy(I2c *i2c, time_t ms_timeout) 00082 { 00083 ticks_t start = timer_clock(); 00084 00085 while (!(HWREG(i2c->hw->base + TWI_SR_OFF) & TWI_SR_RXRDY)) 00086 { 00087 if (timer_clock() - start > ms_to_ticks(ms_timeout)) 00088 return false; 00089 cpu_relax(); 00090 } 00091 00092 return true; 00093 } 00094 00095 INLINE void waitXferComplete(I2c *i2c) 00096 { 00097 while (!(HWREG(i2c->hw->base + TWI_SR_OFF) & TWI_SR_TXCOMP)) 00098 cpu_relax(); 00099 } 00100 00101 00102 /* 00103 * The start is not performed when we call the start function 00104 * because the hardware should know the first data byte to send. 00105 * Generally to perform a byte send we should write the slave address 00106 * in slave address register and the first byte to send in data registry. 00107 * After then we can perform the start write procedure, and send really 00108 * the our data. To use common bertos i2c api the really start will be 00109 * performed when the user "put" or "send" its data. These tricks are hide 00110 * from the driver implementation. 00111 */ 00112 static void i2c_sam3_start(struct I2c *i2c, uint16_t slave_addr) 00113 { 00114 i2c->hw->first_xtranf = true; 00115 00116 if (I2C_TEST_START(i2c->flags) == I2C_START_R) 00117 HWREG(i2c->hw->base + TWI_MMR_OFF) = TWI_MMR_DADR(slave_addr >> 1) | TWI_MMR_MREAD; 00118 else 00119 HWREG(i2c->hw->base + TWI_MMR_OFF) = TWI_MMR_DADR(slave_addr >> 1); 00120 } 00121 00122 static void i2c_sam3_putc(I2c *i2c, const uint8_t data) 00123 { 00124 if (!waitTxRdy(i2c, CONFIG_I2C_START_TIMEOUT)) 00125 { 00126 LOG_ERR("i2c: txready timeout\n"); 00127 i2c->errors |= I2C_START_TIMEOUT; 00128 return; 00129 } 00130 00131 HWREG(i2c->hw->base + TWI_THR_OFF) = data; 00132 00133 if ((i2c->xfer_size == 1) && (I2C_TEST_STOP(i2c->flags) == I2C_STOP)) 00134 HWREG(i2c->hw->base + TWI_CR_OFF) = TWI_CR_STOP; 00135 00136 // On first byte sent wait for start timeout 00137 if (i2c->hw->first_xtranf && !waitTxRdy(i2c, CONFIG_I2C_START_TIMEOUT)) 00138 { 00139 LOG_ERR("i2c: write start timeout\n"); 00140 i2c->errors |= I2C_START_TIMEOUT; 00141 HWREG(i2c->hw->base + TWI_CR_OFF) = TWI_CR_STOP; 00142 waitXferComplete(i2c); 00143 return; 00144 } 00145 i2c->hw->first_xtranf = false; 00146 00147 if ((i2c->xfer_size == 1) && (I2C_TEST_STOP(i2c->flags) == I2C_STOP)) 00148 waitXferComplete(i2c); 00149 } 00150 00151 static uint8_t i2c_sam3_getc(I2c *i2c) 00152 { 00153 uint8_t data; 00154 uint32_t cr = 0; 00155 00156 if (i2c->hw->first_xtranf) 00157 { 00158 cr |= TWI_CR_START; 00159 i2c->hw->first_xtranf = false; 00160 } 00161 if ((i2c->xfer_size == 1) && (I2C_TEST_STOP(i2c->flags) == I2C_STOP)) 00162 cr |= TWI_CR_STOP; 00163 00164 HWREG(i2c->hw->base + TWI_CR_OFF) = cr; 00165 00166 if (!waitRxRdy(i2c, CONFIG_I2C_START_TIMEOUT)) 00167 { 00168 LOG_ERR("i2c: read start timeout\n"); 00169 i2c->errors |= I2C_START_TIMEOUT; 00170 return 0xFF; 00171 } 00172 00173 data = HWREG(i2c->hw->base + TWI_RHR_OFF); 00174 00175 if ((i2c->xfer_size == 1) && (I2C_TEST_STOP(i2c->flags) == I2C_STOP)) 00176 waitXferComplete(i2c); 00177 00178 return data; 00179 } 00180 00181 static void i2c_setClock(I2c *i2c, int clock) 00182 { 00183 uint32_t ck_div = 0; 00184 uint32_t cl_div; 00185 00186 for (;;) 00187 { 00188 cl_div = ((CPU_FREQ / (2 * clock)) - 4) / (1 << ck_div); 00189 00190 if (cl_div <= 255) 00191 break; 00192 00193 ck_div++; 00194 } 00195 00196 ASSERT(ck_div < 8); 00197 LOG_INFO("i2c: using CKDIV = %lu and CLDIV/CHDIV = %lu\n", ck_div, cl_div); 00198 00199 HWREG(i2c->hw->base + TWI_CWGR_OFF) = 0; 00200 HWREG(i2c->hw->base + TWI_CWGR_OFF) = (ck_div << 16) | (cl_div << 8) | cl_div; 00201 } 00202 00203 00204 static const I2cVT i2c_sam3_vt = 00205 { 00206 .start = i2c_sam3_start, 00207 .getc = i2c_sam3_getc, 00208 .putc = i2c_sam3_putc, 00209 .write = i2c_genericWrite, 00210 .read = i2c_genericRead, 00211 }; 00212 00213 struct I2cHardware i2c_sam3_hw[I2C_CNT]; 00214 00215 00219 void i2c_hw_init(I2c *i2c, int dev, uint32_t clock) 00220 { 00221 ASSERT(dev < I2C_CNT); 00222 00223 i2c->hw = &i2c_sam3_hw[dev]; 00224 i2c->vt = &i2c_sam3_vt; 00225 00226 pmc_periphEnable(PIOA_ID); 00227 00228 switch (dev) 00229 { 00230 case I2C0: 00231 i2c->hw->base = TWI0_BASE; 00232 PIO_PERIPH_SEL(TWI0_PORT, BV(TWI0_TWD) | BV(TWI0_TWCK), TWI0_PERIPH); 00233 HWREG(TWI0_PORT + PIO_PDR_OFF) = BV(TWI0_TWD) | BV(TWI0_TWCK); 00234 pmc_periphEnable(TWI0_ID); 00235 break; 00236 case I2C1: 00237 i2c->hw->base = TWI1_BASE; 00238 PIO_PERIPH_SEL(TWI1_PORT, BV(TWI1_TWD) | BV(TWI1_TWCK), TWI1_PERIPH); 00239 HWREG(TWI1_PORT + PIO_PDR_OFF) = BV(TWI1_TWD) | BV(TWI1_TWCK); 00240 pmc_periphEnable(TWI1_ID); 00241 break; 00242 default: 00243 ASSERT(!"i2c: invalid dev number"); 00244 return; 00245 } 00246 00247 00248 // Reset and set master mode 00249 HWREG(i2c->hw->base + TWI_CR_OFF) = TWI_CR_SWRST; 00250 HWREG(i2c->hw->base + TWI_CR_OFF) = TWI_CR_MSEN | TWI_CR_SVDIS; 00251 00252 i2c_setClock(i2c, clock); 00253 }
![(please configure the [header_logo] section in trac.ini)](/chrome/site/bertos_logo.png)