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>
00049 #include <cfg/debug.h>
00050 #include <cfg/macros.h>
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
00104
00105
00106
00107
00108
00109
00110
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
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\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
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 }