BeRTOS
i2c_lm3s.c
Go to the documentation of this file.
00001 
00039 #include "cfg/cfg_i2c.h"
00040 
00041 #define LOG_LEVEL  I2C_LOG_LEVEL
00042 #define LOG_FORMAT I2C_LOG_FORMAT
00043 
00044 #include <cfg/log.h>
00045 
00046 #include <cfg/debug.h>
00047 #include <cfg/macros.h> // BV()
00048 
00049 #include <cpu/detect.h>
00050 #include <cpu/irq.h>
00051 #include <cpu/types.h>
00052 #include <cpu/power.h>
00053 
00054 #include <io/lm3s.h>
00055 
00056 #include <drv/timer.h>
00057 #include <drv/i2c.h>
00058 #include <drv/gpio_lm3s.h>
00059 #include <drv/clock_lm3s.h>
00060 
00061 
00062 struct I2cHardware
00063 {
00064     uint32_t base;
00065     uint32_t sys_cntl;
00066     uint32_t sys_gpio;
00067     uint32_t pin_mask;
00068     uint32_t gpio_base;
00069     bool first_xtranf;
00070 };
00071 
00072 #define WAIT_BUSY(base) \
00073     do { \
00074         while (HWREG(base + I2C_O_MCS) & I2C_MCS_BUSY ) \
00075             cpu_relax(); \
00076     } while (0);
00077 
00078 
00079 /*
00080  * The start is not performed when we call the start function
00081  * because the hardware should know the first data byte to send.
00082  * Generally to perform a byte send we should write the slave address
00083  * in slave address register and the first byte to send in data registry.
00084  * After then we can perform the start write procedure, and send really
00085  * the our data. To use common bertos i2c api the really start will be
00086  * performed when the user "put" or "send" its data. These tricks are hide
00087  * from the driver implementation.
00088  */
00089 static void i2c_lm3s_start(struct I2c *i2c, uint16_t slave_addr)
00090 {
00091     i2c->hw->first_xtranf = true;
00092 
00093     if (I2C_TEST_START(i2c->flags) == I2C_START_W)
00094         HWREG(i2c->hw->base + I2C_O_MSA) = slave_addr & ~BV(0);
00095     else /* (I2C_TEST_START(i2c->flags) == I2C_START_R) */
00096         HWREG(i2c->hw->base + I2C_O_MSA) = slave_addr | BV(0);
00097 }
00098 
00099 INLINE bool wait_addrAck(I2c *i2c, uint32_t mode_mask)
00100 {
00101     ticks_t start = timer_clock();
00102     while (1)
00103     {
00104         uint32_t status = HWREG(i2c->hw->base + I2C_O_MCS);
00105 
00106         if (timer_clock() - start > ms_to_ticks(CONFIG_I2C_START_TIMEOUT))
00107             return false;
00108 
00109         if(status & I2C_MCS_ADRACK)
00110         {
00111             HWREG(i2c->hw->base + I2C_O_MCS) = mode_mask;
00112             WAIT_BUSY(i2c->hw->base);
00113         }
00114         else
00115             break;
00116 
00117         cpu_relax();
00118     }
00119     return true;
00120 }
00121 
00122 static void i2c_lm3s_putc(I2c *i2c, const uint8_t data)
00123 {
00124     HWREG(i2c->hw->base + I2C_O_MDR) = data;
00125 
00126     if (i2c->hw->first_xtranf)
00127     {
00128         HWREG(i2c->hw->base + I2C_O_MCS) = I2C_MCS_RUN | I2C_MCS_START;
00129         while( HWREG(i2c->hw->base + I2C_O_MCS) & I2C_MCS_BUSY );
00130 
00131         if (!wait_addrAck(i2c, I2C_MCS_RUN | I2C_MCS_START))
00132         {
00133             LOG_ERR("Start timeout\n");
00134             i2c->errors |= I2C_START_TIMEOUT;
00135             HWREG(i2c->hw->base + I2C_O_MCS) = I2C_MCS_STOP;
00136             WAIT_BUSY(i2c->hw->base);
00137             return;
00138         }
00139 
00140         i2c->hw->first_xtranf = false;
00141     }
00142     else
00143     {
00144         HWREG(i2c->hw->base + I2C_O_MCS) = I2C_MCS_RUN;
00145         WAIT_BUSY(i2c->hw->base);
00146     }
00147 
00148     if ((i2c->xfer_size == 1) && (I2C_TEST_STOP(i2c->flags) == I2C_STOP))
00149     {
00150         HWREG(i2c->hw->base + I2C_O_MCS) = I2C_MCS_STOP;
00151         WAIT_BUSY(i2c->hw->base);
00152     }
00153 }
00154 
00155 static uint8_t i2c_lm3s_getc(I2c *i2c)
00156 {
00157     uint8_t data;
00158     if (i2c->hw->first_xtranf)
00159     {
00160         uint32_t start_mode;
00161         if (i2c->xfer_size == 1)
00162             start_mode = I2C_MCS_RUN | I2C_MCS_START;
00163         else
00164             start_mode = I2C_MCS_ACK | I2C_MCS_RUN | I2C_MCS_START;
00165 
00166         HWREG(i2c->hw->base + I2C_O_MCS) = start_mode;
00167         WAIT_BUSY(i2c->hw->base);
00168         if (!wait_addrAck(i2c, start_mode))
00169         {
00170             LOG_ERR("Start timeout\n");
00171             i2c->errors |= I2C_START_TIMEOUT;
00172             HWREG(i2c->hw->base + I2C_O_MCS) = I2C_MCS_STOP;
00173             WAIT_BUSY(i2c->hw->base);
00174             return 0xFF;
00175         }
00176 
00177         data = HWREG(i2c->hw->base + I2C_O_MDR);
00178         i2c->hw->first_xtranf = false;
00179     }
00180     else
00181     {
00182         if (i2c->xfer_size > 1)
00183             HWREG(i2c->hw->base + I2C_O_MCS) = I2C_MCS_ACK | I2C_MCS_RUN;
00184         else
00185             HWREG(i2c->hw->base + I2C_O_MCS) = I2C_MCS_RUN;
00186 
00187         WAIT_BUSY(i2c->hw->base);
00188         data = HWREG(i2c->hw->base + I2C_O_MDR);
00189     }
00190 
00191     if ((i2c->xfer_size == 1) && (I2C_TEST_STOP(i2c->flags) == I2C_STOP))
00192     {
00193         HWREG(i2c->hw->base + I2C_O_MCS) = I2C_MCS_STOP;
00194         WAIT_BUSY(i2c->hw->base);
00195     }
00196     return data;
00197 }
00198 
00199 static const I2cVT i2c_lm3s_vt =
00200 {
00201     .start = i2c_lm3s_start,
00202     .getc = i2c_lm3s_getc,
00203     .putc = i2c_lm3s_putc,
00204     .write = i2c_genericWrite,
00205     .read = i2c_genericRead,
00206 };
00207 
00208 static struct I2cHardware i2c_lm3s_hw[] =
00209 {
00210     { /* I2C0 */
00211         .base = I2C0_MASTER_BASE,
00212         .sys_cntl = SYSCTL_RCGC1_I2C0,
00213         .sys_gpio = SYSCTL_RCGC2_GPIOB,
00214         .pin_mask = (GPIO_I2C0_SCL_PIN | GPIO_I2C0_SDA_PIN),
00215         .gpio_base = GPIO_PORTB_BASE,
00216     },
00217     { /* I2C1 */
00218         .base = I2C1_MASTER_BASE,
00219         .sys_cntl = SYSCTL_RCGC1_I2C1,
00220         .sys_gpio = SYSCTL_RCGC2_GPIOA,
00221         .pin_mask = (GPIO_I2C1_SCL_PIN | GPIO_I2C1_SDA_PIN),
00222         .gpio_base = GPIO_PORTA_BASE,
00223     },
00224 };
00225 
00229 void i2c_hw_init(I2c *i2c, int dev, uint32_t clock)
00230 {
00231     i2c->hw = &i2c_lm3s_hw[dev];
00232     i2c->vt = &i2c_lm3s_vt;
00233 
00234     /* Enable the peripheral clock */
00235     SYSCTL_RCGC1_R |= i2c->hw->sys_cntl;
00236     SYSCTL_RCGC2_R |= i2c->hw->sys_gpio;
00237 
00238     /* Configure GPIO pins to work as I2C pins */
00239     lm3s_gpioPinConfig(i2c->hw->gpio_base, i2c->hw->pin_mask,
00240         GPIO_DIR_MODE_HW, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD_WPU);
00241     /*
00242      * Note: to set correctly the i2c speed we shold before enable the i2c
00243      * device and then set in master time period the correct value
00244      */
00245 
00246     /* Enable i2c device */
00247     HWREG(i2c->hw->base + I2C_O_MCR) |= I2C_MCR_MFE;
00248 
00249     /*
00250      * Compute the clock divider that achieves the fastest speed less than or
00251      * equal to the desired speed.  The numerator is biased to favor a larger
00252      * clock divider so that the resulting clock is always less than or equal
00253      * to the desired clock, never greater.
00254      */
00255     HWREG(i2c->hw->base + I2C_O_MTPR) = ((CPU_FREQ + (2 * 10 * clock) - 1) / (2 * 10 * clock)) - 1;
00256 }