i2c.c ( File view )

  • By gregkam 2014-10-06
  • View(s):4272
  • Download(s):1
  • Point(s): 1
			/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * i2c.c --- STM32F4 I2C driver.
 *
 * Copyright (C) 2012, Galois, Inc.
 * All Rights Reserved.
 *
 * This software is released under the "BSD3" license.  Read the file
 * "LICENSE" for more information.
 */

#include <stddef.h>
#include <string.h>

#include <stm32f4xx.h>

#include <FreeRTOS.h>
#include <queue.h>
#include <semphr.h>
#include <task.h>

#include "hwf4/i2c.h"
#include "hwf4/gpio.h"
#include "hwf4/rcc.h"
#include "hwf4/interrupt.h"

struct i2chw_t {

    I2C_TypeDef* reg;
    enum RCCDevice dev;
    enum IRQn irq_ev;
    enum IRQn irq_er;

};

const struct i2chw_t i2c1_hw =
    {
 .reg = I2C1,
      .dev = RCCDEV_I2C1,
      .irq_ev = I2C1_EV_IRQn,
      .irq_er = I2C1_ER_IRQn
    
};

const struct i2chw_t i2c2_hw =
    {
 .reg = I2C2,
      .dev = RCCDEV_I2C2,
      .irq_ev = I2C2_EV_IRQn,
      .irq_er = I2C2_ER_IRQn
    
};

const struct i2chw_t i2c3_hw =
    {
 .reg = I2C3,
      .dev = RCCDEV_I2C3,
      .irq_ev = I2C3_EV_IRQn,
      .irq_er = I2C3_ER_IRQn
    
};

struct i2cdrv_t {

    struct i2chw_t const * hw;
    volatile uint8_t addr;
    volatile size_t  writing;
    volatile size_t  reading;
    volatile uint8_t* write_p;
    volatile uint8_t* read_p;

    volatile bool error;

    xSemaphoreHandle lock;      /* bus mutex */
    xSemaphoreHandle complete;  /* completion from ISR */

};

struct i2cdrv_t _i2c1_drv = {
 &i2c1_hw, 0, 0, 0, NULL, NULL, false, NULL, NULL 
};
struct i2cdrv_t _i2c2_drv = {
 &i2c2_hw, 0, 0, 0, NULL, NULL, false, NULL, NULL 
};
struct i2cdrv_t _i2c3_drv = {
 &i2c3_hw, 0, 0, 0, NULL, NULL, false, NULL, NULL 
};


static inline void __i2c_reset_cr2(struct i2cdrv_t *i2c, uint32_t val) {

    i2c->hw->reg->CR2 &= ~val;

}

static inline void __i2c_update_cr2(struct i2cdrv_t *i2c, uint32_t val) {

    i2c->hw->reg->CR2 |= val;

}

/**
 * Generate an I2C START condition.  Per the reference manual, we wait
 * for the hardware to clear the start bit after setting it before
 * allowing any further writes to CR1.  This prevents random lockups.
 */
static inline void __i2c_set_start(struct i2cdrv_t *i2c) {

    i2c->hw->reg->CR1 |= I2C_CR1_START;
    while (i2c->hw->reg->CR1 & I2C_CR1_START);

}

/**
 * Generate an I2C STOP condition.  Per the reference manual, we wait
 * for the hardware to clear the stop bit after setting it before
 * allowing any further writes to CR1.  This prevents random lockups.
 */
static inline void __i2c_set_stop(struct i2cdrv_t *i2c) {

    i2c->hw->reg->CR1 |= I2C_CR1_STOP;
    while (i2c->hw->reg->CR1 & I2C_CR1_STOP);

}

/**
 * Set the peripheral frequency.
 */
static inline void __i2c_set_freq(struct i2cdrv_t *i2c,
        struct rcc_clocks_freq *freq) {


    __i2c_reset_cr2(i2c, I2C_CR2_FREQ);
    __i2c_update_cr2(i2c, freq->pclk1 / 1000000);

}

void i2c_init(struct i2cdrv_t *drv, struct pin* sda, struct pin* scl) {

    pin_enable(sda);
    pin_enable(scl);
    rcc_enable(drv->hw->dev);

    drv->lock = xSemaphoreCreateMutex();
    vSemaphoreCreateBinary(drv->complete);
    xSemaphoreTake(drv->complete, portMAX_DELAY);

    /* sda : set open drain, alternate function mode, alternate function i2c */
    pin_set_otype(sda, PIN_TYPE_OPENDRAIN);
    pin_set_pupd (sda, PIN_PUPD_NONE);
    pin_set_af   (sda, PIN_AF_I2C);
    pin_set_mode (sda, PIN_MODE_AF);
    /* scl : open drain, alternate function mode, alternate function i2c */
    pin_set_otype(scl, PIN_TYPE_OPENDRAIN);
    pin_set_pupd (scl, PIN_PUPD_NONE);
    pin_set_af   (scl, PIN_AF_I2C);
    pin_set_mode (scl, PIN_MODE_AF);

    I2C_TypeDef* reg = drv->hw->reg;
    /* Reset and clear peripheral. */
    reg->CR1 = I2C_CR1_SWRST;
    reg->CR1 = 0;

    struct rcc_clocks_freq freq;
    rcc_get_clocks_freq(&freq);

    // enable the peripheral clock
    __i2c_set_freq(drv, &freq);

    // enable interrupts
    __i2c_update_cr2(drv,
          I2C_CR2_ITERREN  /* Error interrupt enable */
        | I2C_CR2_ITEVTEN  /* Event interrupt enable */
        | I2C_CR2_ITBUFEN  /* Buffer interrupt enable */
        );

    // fast speed init
    uint16_t result = (uint16_t)(freq.pclk1 / (400000 * 25));
    if (result < 1)
      result = 1;

    reg->CCR |= I2C_CCR_DUTY | I2C_CCR_FS | result;
    reg->TRISE = (uint16_t)((((freq.pclk1 / 1000000) * 300) / 1000) + 1);

    // standard speed init
#if 0
    uint16_t result = (uint16_t)(freq.pclk1 / (100000 << 1));
    if(result < 0x4) {

        result = 0x04;
    
}
    reg->CCR |= result;
    reg->TRISE = ((freq.pclk1 / 1000000 + 1) & I2C_TRISE_TRISE);
#endif

    /* Enable interrupts globally */
    interrupt_set_priority(drv->hw->irq_ev, INTERRUPT_PRIORITY_FREERTOS_SAFE);
    interrupt_set_priority(drv->hw->irq_er, INTERRUPT_PRIORITY_FREERTOS_SAFE);
    interrupt_enable(drv->hw->irq_ev);
    interrupt_enable(drv->hw->irq_er);

    /* Enable the I2C peripheral */
    reg->CR1 = I2C_CR1_PE;

}

bool i2c_transfer(struct i2cdrv_t *drv, uint8_t addr,
                  const uint8_t *tx_buf, size_t tx_len,
                  uint8_t *rx_buf, size_t rx_len) {

    bool result = true;

    if (!xSemaphoreTake(drv->lock, portMAX_DELAY))
        return false;

    drv->addr    = addr;
    drv->writing = tx_len;
    drv->write_p = (uint8_t *)tx_buf;
    drv->reading = rx_len;
    drv->read_p  = rx_buf;

    __i2c_set_start(drv);
    if (!xSemaphoreTake(drv->complete, 1000)) {

        asm volatile("bkpt");
        result = false;
    
}

    if (drv->error) {

        drv->error = false;
        result = false;
    
}

    xSemaphoreGive(drv->lock);
    return result;

}

bool i2c_write(struct i2cdrv_t *drv, uint8_t addr, uint8_t *buf, size_t len) {

    return i2c_transfer(drv, addr, buf, len, NULL, 0);

}

bool i2c_write_reg(struct i2cdrv_t *drv, uint8_t addr,
        uint8_t reg, uint8_t data) {

    uint8_t buf[2] = {
 reg, data 
};
    return i2c_write(drv, addr, buf, sizeof(buf));

}

bool i2c_write_regs(struct i2cdrv_t *drv, uint8_t addr, uint8_t reg,
                    uint8_t *data, uint8_t len) {

    uint8_t buf[len + 1];    // requires C99, careful of stack overflow!
    buf[0] = reg;
    memcpy(&buf[1], data, len);
    return i2c_transfer(drv, addr, buf, len + 1, NULL, 0);

}

bool i2c_read_reg(struct i2cd
...
...
(Please download the complete source code to view)
			
...
Expand> <Close

Want complete source code? Download it here

Point(s): 1

Download
0 lines left, continue to read
Sponsored links

File list

Tips: You can preview the content of files by clicking file names^_^
Name Size Date
01.97 kB
.gitignore19.00 B2013-04-23|01:09
01.97 kB
.gitignore8.00 B2013-04-23|01:09
build.mk1.82 kB2013-04-23|01:09
01.97 kB
default_handlers.c6.01 kB2013-04-23|01:09
default_hooks.c159.00 B2013-04-23|01:09
syscalls.c3.28 kB2013-04-23|01:09
Makefile327.00 B2013-04-23|01:09
README.md217.00 B2013-04-23|01:09
config.mk.example151.00 B2013-04-23|01:09
01.97 kB
FreeRTOSConfig.h8.59 kB2013-04-23|01:09
arm_common_tables.h1.09 kB2013-04-23|01:09
arm_math.h234.69 kB2013-04-23|01:09
core_cm0.h31.20 kB2013-04-23|01:09
core_cm3.h68.09 kB2013-04-23|01:09
core_cm4.h77.42 kB2013-04-23|01:09
core_cm4_simd.h23.42 kB2013-04-23|01:09
core_cmFunc.h15.32 kB2013-04-23|01:09
core_cmInstr.h15.73 kB2013-04-23|01:09
stm32f4xx.h507.96 kB2013-04-23|01:09
system_stm32f4xx.h2.17 kB2013-04-23|01:09
01.97 kB
01.97 kB
cortex-m4.mk646.00 B2013-04-23|01:09
01.97 kB
stm32f4.mk131.00 B2013-04-23|01:09
command.mk768.00 B2013-04-23|01:09
toolchain.mk150.00 B2013-04-23|01:09
01.97 kB
build.mk227.00 B2013-04-23|01:09
startup_stm32f4xx.s22.85 kB2013-04-23|01:09
system_stm32f4xx.c22.24 kB2013-04-23|01:09
01.97 kB
.gitignore8.00 B2013-04-23|01:09
build.mk1.04 kB2013-04-23|01:09
01.97 kB
01.97 kB
eeprom.h1.97 kB2013-04-23|01:09
gpio.h14.62 kB2013-04-23|01:09
i2c.h1.63 kB2013-04-23|01:09
interrupt.h1.61 kB2013-04-23|01:09
led.h904.00 B2013-04-23|01:09
rcc.h1.65 kB2013-04-23|01:09
spi.h3.46 kB2013-04-23|01:09
01.97 kB
irq.h6.68 kB2013-04-23|01:09
timer.h2.26 kB2013-04-23|01:09
usart.h3.38 kB2013-04-23|01:09
usb_cdc.h1.32 kB2013-04-23|01:09
01.97 kB
eeprom.c2.97 kB2013-04-23|01:09
fault.c1.38 kB2013-04-23|01:09
gpio.c5.12 kB2013-04-23|01:09
i2c.c9.10 kB2013-04-23|01:09
interrupt.c744.00 B2013-04-23|01:09
led.c2.11 kB2013-04-23|01:09
rcc.c11.74 kB2013-04-23|01:09
spi.c12.33 kB2013-04-23|01:09
timer.c10.08 kB2013-04-23|01:09
usart.c10.83 kB2013-04-23|01:09
usb_cdc.c1.21 kB2013-04-23|01:09
01.97 kB
gdb-init61.00 B2013-04-23|01:09
gdb-tdesc-cortexm-fpa.xml5.74 kB2013-04-23|01:09
openocd-stm32f4.cfg124.00 B2013-04-23|01:09
stm32_flash.ld5.33 kB2013-04-23|01:09
01.97 kB
01.97 kB
main.c2.92 kB2013-04-23|01:09
01.97 kB
main.c1.51 kB2013-04-23|01:09
01.97 kB
.gitignore32.00 B2013-04-23|01:09
build.mk1.12 kB2013-04-23|01:09
main.c740.00 B2013-04-23|01:09
01.97 kB
main.c11.32 kB2013-04-23|01:09
01.97 kB
main.c2.51 kB2013-04-23|01:09
01.97 kB
main.c2.14 kB2013-04-23|01:09
01.97 kB
main.c1.03 kB2013-04-23|01:09
01.97 kB
main.c1.49 kB2013-04-23|01:09
01.97 kB
main.c1.90 kB2013-04-23|01:09
01.97 kB
.gitignore8.00 B2013-04-23|01:09
build.mk1.17 kB2013-04-23|01:09
01.97 kB
01.97 kB
usb_bsp.h2.29 kB2013-04-23|01:09
usb_conf.h10.48 kB2013-04-23|01:09
usb_core.h12.29 kB2013-04-23|01:09
usb_dcd.h4.48 kB2013-04-23|01:09
usb_dcd_int.h3.03 kB2013-04-23|01:09
usb_defines.h6.52 kB2013-04-23|01:09
usb_hcd.h2.76 kB2013-04-23|01:09
usb_hcd_int.h3.65 kB2013-04-23|01:09
usb_otg.h1.97 kB2013-04-23|01:09
usb_regs.h21.22 kB2013-04-23|01:09
usbd_cdc_core.h3.87 kB2013-04-23|01:09
usbd_cdc_if_template.h1.85 kB2013-04-23|01:09
usbd_cdc_vcp.h2.89 kB2013-04-23|01:09
usbd_conf.h3.29 kB2013-04-23|01:09
usbd_core.h2.50 kB2013-04-23|01:09
usbd_def.h4.82 kB2013-04-23|01:09
usbd_desc.h3.35 kB2013-04-23|01:09
usbd_ioreq.h2.89 kB2013-04-23|01:09
usbd_req.h2.50 kB2013-04-23|01:09
usbd_usr.h3.00 kB2013-04-23|01:09
01.97 kB
usb_bsp.c3.27 kB2013-04-23|01:09
usb_core.c55.46 kB2013-04-23|01:09
usb_dcd.c9.21 kB2013-04-23|01:09
usb_dcd_int.c21.32 kB2013-04-23|01:09
usb_hcd.c5.62 kB2013-04-23|01:09
usb_hcd_int.c21.58 kB2013-04-23|01:09
usb_otg.c9.48 kB2013-04-23|01:09
usbd_cdc_core.c24.57 kB2013-04-23|01:09
usbd_cdc_if_template.c6.07 kB2013-04-23|01:09
usbd_cdc_vcp.c6.71 kB2013-04-23|01:09
usbd_core.c11.39 kB2013-04-23|01:09
usbd_desc.c8.23 kB2013-04-23|01:09
usbd_ioreq.c5.38 kB2013-04-23|01:09
usbd_req.c19.55 kB2013-04-23|01:09
usbd_usr.c3.48 kB2013-04-23|01:09
...
Sponsored links

i2c.c (278.02 kB)

Need 1 point
Your Point(s)

Your Point isn't enough.

Get point immediately by PayPal

More(Debit card / Credit card / PayPal Credit / Online Banking)

Submit your source codes. Get more point

LOGIN

Don't have an account? Register now
Need any help?
Mail to: support@codeforge.com

切换到中文版?

CodeForge Chinese Version
CodeForge English Version

Where are you going?

^_^"Oops ...

Sorry!This guy is mysterious, its blog hasn't been opened, try another, please!
OK

Warm tip!

CodeForge to FavoriteFavorite by Ctrl+D