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\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 }