Clion开发STM32之I2C驱动(参考RT-Thread)

说明

  1. 本章是根据RT-Thread源码中的I2C组件进行抽离,主要不习惯用RT-Thread
  2. 然后在结合at24cxx模块补充测试
  3. 也为了方便移植和独立于框架的限制。

正文

操作gpio部分

#ifndef STM32_F1XX_TEMPLATE_BSP_GPIO_H
#define STM32_F1XX_TEMPLATE_BSP_GPIO_H

#include "sys_core.h"

#define GPIO_A_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define GPIO_B_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define GPIO_C_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
#define GPIO_D_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define GPIO_E_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
#define GPIO_F_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE()
#define GPIO_G_CLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE()

#define gpio_init(port, pin, mode, pull, speed)\
            do{\
                __HAL_RCC_##port##_CLK_ENABLE();\
                GPIO_InitTypeDef cnf ={pin,mode,pull,speed};\
                HAL_GPIO_Init(port, &cnf);\
            }while(0)
#define pin_high(port, pin) HAL_GPIO_WritePin(port,pin,GPIO_PIN_SET)
#define pin_low(port, pin) HAL_GPIO_WritePin(port,pin,GPIO_PIN_RESET)
#define stm_pin_set(port, pin, value)  HAL_GPIO_WritePin(port,pin,value)
#define pin_read(port, pin) HAL_GPIO_ReadPin(port,pin)
#define pin_toggle(port, pin) HAL_GPIO_TogglePin(port,pin)
typedef enum {
    pin_mode_output,
    pin_mode_input,
    pin_mode_input_pull_up,
    pin_mode_input_pull_down,
    pin_mode_output_od
} pin_mode_type;

sys_force_static_inline void gpio_clk_enable(GPIO_TypeDef *port) {
    if (port == GPIOA)GPIO_A_CLK_ENABLE();
    else if (port == GPIOB)GPIO_B_CLK_ENABLE();
    else if (port == GPIOC)GPIO_C_CLK_ENABLE();
    else if (port == GPIOD)GPIO_D_CLK_ENABLE();
    else if (port == GPIOE)GPIO_E_CLK_ENABLE();
    else if (port == GPIOF)GPIO_F_CLK_ENABLE();
    else if (port == GPIOG)GPIO_G_CLK_ENABLE();
}

sys_force_static_inline void stm32_pin_mode(GPIO_TypeDef *port, uint32_t pin, pin_mode_type mode) {
    GPIO_InitTypeDef GPIO_InitStruct = {
            .Pin = pin, .Mode = GPIO_MODE_OUTPUT_PP, .Speed = GPIO_SPEED_FREQ_HIGH, .Pull = GPIO_NOPULL};
    gpio_clk_enable(port);
    switch (mode) {

        case pin_mode_output: {
            /* output setting */
            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            break;
        }
        case pin_mode_input: {
            /* input setting: not pull. */
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            break;
        }
        case pin_mode_input_pull_up: {
            /* input setting: pull up. */
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            GPIO_InitStruct.Pull = GPIO_PULLUP;
            break;
        }
        case pin_mode_input_pull_down: {
            /* input setting: pull down. */
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            GPIO_InitStruct.Pull = GPIO_PULLDOWN;
            break;
        }
        case pin_mode_output_od: {
            /* output setting: od. */
            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            break;
        }
    }
    HAL_GPIO_Init(port, &GPIO_InitStruct);
}

#endif //STM32_F1XX_TEMPLATE_BSP_GPIO_H

头文件

#ifndef STM32_F1XX_TEMPLATE_BSP_I2C_SOFT_H
#define STM32_F1XX_TEMPLATE_BSP_I2C_SOFT_H

#include "bsp_include.h"

typedef struct {
    uint32_t scl;
    uint32_t sda;
    GPIO_TypeDef *port_scl;
    GPIO_TypeDef *port_sda;
} soft_i2c_cnf_t;
typedef struct {
    soft_i2c_cnf_t *cnf;/*硬件配置信息*/
    void (*w_sda)(soft_i2c_cnf_t *cnf, rt_uint32_t state);

    void (*w_scl)(soft_i2c_cnf_t *cnf, rt_uint32_t state);

    rt_int32_t (*r_sda)(soft_i2c_cnf_t *cnf);

    rt_int32_t (*r_scl)(soft_i2c_cnf_t *cnf);

    void (*us_delay)(rt_uint32_t us);


    struct {
        rt_uint32_t delay_us;
        rt_uint32_t timeout;
    } option;
} i2c_bit_ops_t; /*软件位操作*/

#define RT_I2C_WR                0x0000
#define RT_I2C_RD               (1u << 0)
#define RT_I2C_ADDR_10BIT       (1u << 2)  /* this is a ten bit chip address */
#define RT_I2C_NO_START         (1u << 4)
#define RT_I2C_IGNORE_NACK      (1u << 5)
#define RT_I2C_NO_READ_ACK      (1u << 6)  /* when I2C reading, we do not ACK */
#define RT_I2C_NO_STOP          (1u << 7)
typedef struct {
    rt_uint16_t addr;
    rt_uint16_t flags;
    rt_uint16_t len;
    rt_uint8_t *buf;
} rt_i2c_msg;

struct i2c_bus_device {
    i2c_bit_ops_t *bit_ops;

    struct {
        void (*start)(i2c_bit_ops_t *bit_ops); /*开启*/
        void (*stop)(i2c_bit_ops_t *bit_ops); /*停止*/
        rt_int32_t (*w_byte)(i2c_bit_ops_t *bit_ops, uint8_t data); /*write 1 byte*/
        rt_int32_t (*r_byte)(i2c_bit_ops_t *bit_ops);/*read 1 byte*/
        rt_bool_t (*wait_ack)(i2c_bit_ops_t *bit_ops);/*等待应答*/
        rt_int32_t (*send_ack_or_nack)(i2c_bit_ops_t *bit_ops, rt_int32_t ack); /*发送ack或nack*/

        rt_uint32_t (*w_bytes)(i2c_bit_ops_t *bit_ops, rt_i2c_msg *msg);

        rt_uint32_t (*r_bytes)(i2c_bit_ops_t *bit_ops, rt_i2c_msg *msg);

        rt_int32_t (*send_address)(i2c_bit_ops_t *bit_ops, uint8_t addr, rt_int32_t retries);

        rt_int32_t (*bit_send_address)(i2c_bit_ops_t *bit_ops, rt_i2c_msg *msg);

    } api;

    rt_uint32_t (*master_xfer)(i2c_bit_ops_t *bit_ops, rt_i2c_msg msgs[], rt_uint32_t num);
};/*I2C总线设备*/
typedef struct i2c_bus_device *i2c_bus_device_t;

void i2c_bus_init(i2c_bus_device_t device, i2c_bit_ops_t *i2c_ops, soft_i2c_cnf_t *cfg);

rt_size_t i2c_master_send(i2c_bus_device_t device, rt_uint16_t addr, rt_uint16_t flags, const rt_uint8_t *buf,
                          rt_uint32_t count);

rt_size_t i2c_master_rec(i2c_bus_device_t device, rt_uint16_t addr, rt_uint16_t flags, rt_uint8_t *buf,
                         rt_uint32_t count);

#endif //STM32_F1XX_TEMPLATE_BSP_I2C_SOFT_H

源码


#include "bsp_i2c_soft.h"
#include "sys_dbg.h"

/*————————————————————————————————————————————————基础外设层——————————————————————————————————————————————————*/
sys_force_static_inline void stm32_us_delay(rt_uint32_t us) {
    uint32_t start, now, delta, reload, us_tick;
    start = SysTick->VAL;
    reload = SysTick->LOAD;
    us_tick = SystemCoreClock / 1000000UL;
    do {
        now = SysTick->VAL;
        delta = start > now ? start - now : reload + start - now;
    } while (delta < us_tick * us);
}

sys_force_static_inline void w_sda(soft_i2c_cnf_t *cnf, rt_uint32_t state) {
    if (state) {
        pin_high(cnf->port_sda, cnf->sda);
    } else {
        pin_low(cnf->port_sda, cnf->sda);

    }
}

sys_force_static_inline void w_scl(soft_i2c_cnf_t *cnf, rt_uint32_t state) {
    if (state) {
        pin_high(cnf->port_scl, cnf->scl);
    } else {
        pin_low(cnf->port_scl, cnf->scl);
    }
}

sys_force_static_inline rt_int32_t r_sda(soft_i2c_cnf_t *cnf) {
    return pin_read(cnf->port_sda, cnf->sda);
}

sys_force_static_inline rt_int32_t r_scl(soft_i2c_cnf_t *cnf) {
    return pin_read(cnf->port_scl, cnf->scl);
}

sys_force_static_inline void i2c_soft_init(i2c_bit_ops_t *i2c_ops, soft_i2c_cnf_t *cfg) {
    i2c_ops->option.delay_us = 1;
    i2c_ops->option.timeout = 100;
    i2c_ops->cnf = cfg;
    i2c_ops->w_scl = w_scl;
    i2c_ops->w_sda = w_sda;
    i2c_ops->r_sda = r_sda;
    i2c_ops->r_scl = r_scl;
    i2c_ops->us_delay = stm32_us_delay;
    stm32_pin_mode(cfg->port_scl, cfg->scl, pin_mode_output_od);
    stm32_pin_mode(cfg->port_sda, cfg->sda, pin_mode_output_od);

    pin_high(cfg->port_scl, cfg->scl);
    pin_high(cfg->port_sda, cfg->sda);
}
/*————————————————————————————————————————————————设备层——————————————————————————————————————————————————*/
#define SET_SDA(ops, val)   ops->w_sda(ops->cnf,val)
#define SET_SCL(ops, val)   ops->w_scl(ops->cnf,val)
#define GET_SDA(ops)        ops->r_sda(ops->cnf)
#define GET_SCL(ops)        ops->r_scl(ops->cnf)
#define SDA_L(ops)          SET_SDA(ops,0)
#define SDA_H(ops)          SET_SDA(ops,1)
#define SCL_L(ops)          SET_SCL(ops,0)

static void us_delay(i2c_bit_ops_t *bit_ops) {
    bit_ops->us_delay((bit_ops->option.delay_us + 1) >> 1);
}

static void us_delay2(i2c_bit_ops_t *bit_ops) {
    bit_ops->us_delay(bit_ops->option.delay_us);
}

static int SCL_H(i2c_bit_ops_t *bit_ops) {
    rt_uint32_t start;
    SET_SCL(bit_ops, 1);
    start = HAL_GetTick();
    while (!GET_SCL(bit_ops)) {
        if ((HAL_GetTick() - start) > bit_ops->option.timeout)
            return -1;
        us_delay(bit_ops);
    }


    us_delay(bit_ops);


    return 0;
}

sys_force_static_inline rt_int32_t send_ack_or_nack(i2c_bit_ops_t *bit_ops, rt_int32_t ack) {
    if (ack)
        SET_SDA(bit_ops, 0);
    us_delay(bit_ops);
    if (SCL_H(bit_ops) < 0) {
        return -1;
    }
    SCL_L(bit_ops);
    return 0;
}

sys_force_static_inline rt_bool_t wait_ack(i2c_bit_ops_t *bit_ops) {
    bool ack;

    SDA_H(bit_ops);
    us_delay(bit_ops);


    if (SCL_H(bit_ops) < 0) {

        return -1;
    }

    ack = !GET_SDA(bit_ops);    /* ACK : SDA pin is pulled low */


    SCL_L(bit_ops);

    return ack;
}/*等待应答*/
sys_force_static_inline void start(i2c_bit_ops_t *bit_ops) {
    SDA_L(bit_ops);
    us_delay(bit_ops);

    SCL_L(bit_ops);
} /*开启*/
static void restart(i2c_bit_ops_t *bit_ops) {
    SDA_H(bit_ops);
    SCL_H(bit_ops);
    us_delay(bit_ops);
    SDA_L(bit_ops);
    us_delay(bit_ops);
    SCL_L(bit_ops);
}

sys_force_static_inline void stop(i2c_bit_ops_t *bit_ops) {
    SDA_L(bit_ops);
    us_delay(bit_ops);
    SCL_H(bit_ops);
    us_delay(bit_ops);
    SDA_H(bit_ops);
    us_delay2(bit_ops);

} /*停止*/

sys_force_static_inline rt_int32_t w_byte(i2c_bit_ops_t *bit_ops, uint8_t data) {
    uint8_t bit;
    for (int i = 7; i >= 0; i--) {
        SCL_L(bit_ops);
        bit = (data >> i) & 1;
        SET_SDA(bit_ops, bit);

        us_delay(bit_ops);
        if (SCL_H(bit_ops) < 0) {


            return -1;
        }
    }
    SCL_L(bit_ops);
    us_delay(bit_ops);
    return wait_ack(bit_ops);
} /*write 1 byte*/
sys_force_static_inline rt_int32_t r_byte(i2c_bit_ops_t *bit_ops) {
    uint8_t i;
    uint8_t data = 0;

    SDA_H(bit_ops);
    us_delay(bit_ops);
    for (i = 0; i < 8; i++) {
        data <<= 1;

        if (SCL_H(bit_ops) < 0) {
            return -1;
        }

        if (GET_SDA(bit_ops))
            data |= 1;
        SCL_L(bit_ops);
        us_delay2(bit_ops);
    }

    return data;
}

sys_force_static_inline rt_uint32_t w_bytes(i2c_bit_ops_t *bit_ops, rt_i2c_msg *msg) {
    rt_int32_t ret;
    size_t bytes = 0;
    const uint8_t *ptr = msg->buf;
    rt_int32_t count = msg->len;
    uint16_t ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
    while (count > 0) {
        ret = w_byte(bit_ops, *ptr);
        if ((ret > 0) || (ignore_nack && (ret == 0))) {
            count--;
            ptr++;
            bytes++;
        } else if (ret == 0) {
            return 0;
        } else {
            return ret;
        }
    }

    return bytes;
}

static rt_uint32_t r_bytes(i2c_bit_ops_t *bit_ops, rt_i2c_msg *msg) {
    rt_int32_t val;
    rt_int32_t bytes = 0;   /* actual bytes */
    uint8_t *ptr = msg->buf;
    rt_int32_t count = msg->len;
    const rt_uint32_t flags = msg->flags;
    while (count > 0) {
        val = r_byte(bit_ops);
        if (val >= 0) {
            *ptr = val;
            bytes++;
        } else {
            break;
        }

        ptr++;
        count--;
        if (!(flags & RT_I2C_NO_READ_ACK)) {
            val = send_ack_or_nack(bit_ops, count);
            if (val < 0)
                return val;
        }
    }

    return bytes;
}

static rt_int32_t send_address(i2c_bit_ops_t *bit_ops, uint8_t addr, rt_int32_t retries) {
    rt_int32_t i;
    rt_int32_t ret = 0;

    for (i = 0; i <= retries; i++) {
        ret = w_byte(bit_ops, addr);
        if (ret == 1 || i == retries)
            break;
        stop(bit_ops);
        us_delay2(bit_ops);
        start(bit_ops);
    }
    return ret;
}

static rt_int32_t bit_send_address(i2c_bit_ops_t *bit_ops, rt_i2c_msg *msg) {
    uint16_t flags = msg->flags;
    uint16_t ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
    uint8_t addr1, addr2;
    rt_int32_t retries = 0;
    rt_int32_t ret;
//    retries = ignore_nack ? 0 : bus->retries;
    if (flags & RT_I2C_ADDR_10BIT) {
        addr1 = 0xf0 | ((msg->addr >> 7) & 0x06);
        addr2 = msg->addr & 0xff;

        LOG_D("addr1: %d, addr2: %d", addr1, addr2);

        ret = send_address(bit_ops, addr1, retries);
        if ((ret != 1) && !ignore_nack) {
            LOG_W("NACK: sending first addr");

            return -RT_EIO;
        }

        ret = w_byte(bit_ops, addr2);
        if ((ret != 1) && !ignore_nack) {
            LOG_W("NACK: sending second addr");

            return -RT_EIO;
        }
        if (flags & RT_I2C_RD) {
            LOG_D("send repeated start condition");
            restart(bit_ops);
            addr1 |= 0x01;
            ret = send_address(bit_ops, addr1, retries);
            if ((ret != 1) && !ignore_nack) {
                LOG_E("NACK: sending repeated addr");

                return -RT_EIO;
            }
        }
    } else {
        /* 7-bit addr */
        addr1 = msg->addr << 1;
        if (flags & RT_I2C_RD)
            addr1 |= 1;
        ret = send_address(bit_ops, addr1, retries);
        if ((ret != 1) && !ignore_nack)
            return -8;
    }
    return 0;
}

/*————————————————————————————————————————————————协议逻辑层——————————————————————————————————————————————————*/
static rt_uint32_t bit_xfer(i2c_bit_ops_t *bit_ops, rt_i2c_msg msgs[], rt_uint32_t num) {
    rt_i2c_msg *msg;
    rt_int32_t i, ret;
    uint16_t ignore_nack;
    for (i = 0; i < num; i++) {
        msg = &msgs[i];
        ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
        if (!(msg->flags & RT_I2C_NO_START)) {
            if (i) {
                restart(bit_ops);
            } else {
                LOG_D("send start condition\r\n");
                start(bit_ops);
            }
            ret = bit_send_address(bit_ops, msg);
            if ((ret != 0) && !ignore_nack) {
                LOG_D("receive NACK from device addr 0x%02x msg %d\r\n",
                      msgs[i].addr, i);
                goto out;
            }
        }
        if (msg->flags & RT_I2C_RD) {
            ret = r_bytes(bit_ops, msg);
            if (ret >= 1)
                    LOG_D("read %d byte%s\r\n", ret, ret == 1 ? "" : "s");
            if (ret < msg->len) {
                if (ret >= 0)
                    ret = -8;
                goto out;
            }
        } else {
            ret = w_bytes(bit_ops, msg);
            if (ret >= 1) {
                LOG_D("write %d byte%s\r\n", ret, ret == 1 ? "" : "s");
            }
            if (ret < msg->len) {
                if (ret >= 0)
                    ret = -1;
                goto out;
            }
        }
    }
    ret = i;
    out:
    if (!(msg->flags & RT_I2C_NO_STOP)) {
        stop(bit_ops);
    }

    return ret;
}

sys_force_static_inline void i2c_device_registry(i2c_bus_device_t device, i2c_bit_ops_t *op) {
    device->bit_ops = op;
    device->api.start = start;
    device->api.stop = stop;
    device->api.w_byte = w_byte;
    device->api.r_byte = r_byte;
    device->api.wait_ack = wait_ack;
    device->api.send_ack_or_nack = send_ack_or_nack;
    device->api.w_bytes = w_bytes;
    device->api.r_bytes = r_bytes;
    device->api.send_address = send_address;
    device->api.bit_send_address = bit_send_address;
    device->master_xfer = bit_xfer;
}

void i2c_bus_init(i2c_bus_device_t device, i2c_bit_ops_t *i2c_ops, soft_i2c_cnf_t *cfg) {
    i2c_soft_init(i2c_ops, cfg);
    i2c_device_registry(device, i2c_ops);
}

rt_size_t rt_i2c_transfer(i2c_bus_device_t device, rt_i2c_msg msgs[], rt_uint32_t num) {
    if (device->master_xfer) {
        return device->master_xfer(device->bit_ops, msgs, num);
    }
    return 0;
}

rt_size_t i2c_master_send(i2c_bus_device_t device,
                          rt_uint16_t addr,
                          rt_uint16_t flags,
                          const rt_uint8_t *buf,
                          rt_uint32_t count) {
    rt_i2c_msg msg;
    msg.addr = addr;
    msg.flags = flags;
    msg.len = count;
    msg.buf = (uint8_t *) buf;
    rt_size_t ret = rt_i2c_transfer(device, &msg, 1);
    return (ret > 0) ? count : ret;
}

rt_size_t i2c_master_rec(i2c_bus_device_t device,
                         rt_uint16_t addr,
                         rt_uint16_t flags,
                         rt_uint8_t *buf,
                         rt_uint32_t count) {

    rt_err_t ret;
    rt_i2c_msg msg;

    msg.addr = addr;
    msg.flags = flags | RT_I2C_RD;
    msg.len = count;
    msg.buf = buf;

    ret = rt_i2c_transfer(device, &msg, 1);

    return (ret > 0) ? count : ret;
}

测试模块驱动(at24c02)

at24cxx,根据rt-thread里面搜索的包里面的源码来适配此驱动

头文件

#ifndef STM32_F1XX_TEMPLATE_MODULE_AT24CXX_H
#define STM32_F1XX_TEMPLATE_MODULE_AT24CXX_H

#include "bsp.h"

#define AT24C01     0
#define AT24C02     1
#define AT24C04     2
#define AT24C08     3
#define AT24C16     4
#define AT24C32     5
#define AT24C64     6
#define AT24C128    7
#define AT24C256    8
#define AT24C512    9
#define AT24CTYPE   10   // Number of supported types
#define EE_TWR      5
#ifndef EE_TYPE
#define EE_TYPE     AT24C02
#endif

struct at24cxx_device {
    i2c_bus_device_t i2c;



    uint8_t AddrInput;
};

typedef struct at24cxx_device *at24cxx_device_t;

extern at24cxx_device_t at24cxx_init(i2c_bus_device_t i2c, uint8_t AddrInput);

extern rt_err_t at24cxx_read(at24cxx_device_t dev, uint32_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead);

extern rt_err_t at24cxx_write(at24cxx_device_t dev, uint32_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite);

extern rt_err_t at24cxx_page_read(at24cxx_device_t dev, uint32_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead);

extern rt_err_t at24cxx_page_write(at24cxx_device_t dev, uint32_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite);

extern rt_err_t at24cxx_check(at24cxx_device_t dev, uint16_t addr, uint8_t val);

#endif //STM32_F1XX_TEMPLATE_MODULE_AT24CXX_H

源文件

#define DBG_ENABLE
#define DBG_SECTION_NAME "at24xx"
#define DBG_LEVEL DBG_LOG

#include "sys_dbg.h"
#include "module-at24cxx.h"

#define AT24CXX_ADDR (0xA0 >> 1)                      //A0 A1 A2 connect GND

#if (EE_TYPE == AT24C01)
#define AT24CXX_PAGE_BYTE               8
#define AT24CXX_MAX_MEM_ADDRESS         128
#elif (EE_TYPE == AT24C02)
#define AT24CXX_PAGE_BYTE               8
#define AT24CXX_MAX_MEM_ADDRESS         256
#elif (EE_TYPE == AT24C04)
#define AT24CXX_PAGE_BYTE               16
#define AT24CXX_MAX_MEM_ADDRESS         512
#elif (EE_TYPE == AT24C08)
#define AT24CXX_PAGE_BYTE               16
#define AT24CXX_MAX_MEM_ADDRESS         1024
#elif (EE_TYPE == AT24C16)
#define AT24CXX_PAGE_BYTE               16
#define AT24CXX_MAX_MEM_ADDRESS         2048
#elif (EE_TYPE == AT24C32)
#define AT24CXX_PAGE_BYTE               32
#define AT24CXX_MAX_MEM_ADDRESS         4096
#elif (EE_TYPE == AT24C64)
#define AT24CXX_PAGE_BYTE               32
#define AT24CXX_MAX_MEM_ADDRESS         8192
#elif (EE_TYPE == AT24C128)
#define AT24CXX_PAGE_BYTE               64
#define AT24CXX_MAX_MEM_ADDRESS         16384
#elif (EE_TYPE == AT24C256)
#define AT24CXX_PAGE_BYTE               64
#define AT24CXX_MAX_MEM_ADDRESS         32768
#elif (EE_TYPE == AT24C512)
#define AT24CXX_PAGE_BYTE               128
#define AT24CXX_MAX_MEM_ADDRESS         65536
#endif

sys_force_static_inline rt_err_t read_regs(at24cxx_device_t dev, rt_uint8_t len, rt_uint8_t *buf) {
    rt_i2c_msg msgs;

    msgs.addr = AT24CXX_ADDR | dev->AddrInput;
    msgs.flags = RT_I2C_RD;
    msgs.buf = buf;
    msgs.len = len;
    if (dev->i2c->master_xfer(dev->i2c->bit_ops, &msgs, 1) == 1) {
        return RT_EOK;
    } else {
        return -RT_ERROR;
    }
}

sys_force_static_inline uint8_t at24cxx_read_one_byte(at24cxx_device_t dev, uint16_t readAddr) {
    rt_uint8_t buf[2];
    rt_uint8_t temp;
#if (EE_TYPE > AT24C16)
    buf[0] = (uint8_t)(readAddr>>8);
    buf[1] = (uint8_t)readAddr;
    if (rt_i2c_master_send(dev->i2c, AT24CXX_ADDR, 0, buf, 2) == 0)
#else
    buf[0] = readAddr;
    if (i2c_master_send(dev->i2c, AT24CXX_ADDR | dev->AddrInput, 0, buf, 1) == 0)
#endif
    {
        return RT_ERROR;
    }
    read_regs(dev, 1, &temp);
    return temp;
}

sys_force_static_inline rt_err_t
at24cxx_write_one_byte(at24cxx_device_t dev, uint16_t writeAddr, uint8_t dataToWrite) {
    rt_uint8_t buf[3];
#if (EE_TYPE > AT24C16)
    buf[0] = (uint8_t)(writeAddr>>8);
    buf[1] = (uint8_t)writeAddr;
    buf[2] = dataToWrite;
    if (rt_i2c_master_send(dev->i2c, AT24CXX_ADDR, 0, buf, 3) == 3)
#else
    buf[0] = writeAddr; //cmd
    buf[1] = dataToWrite;
    //buf[2] = data[1];

    if (i2c_master_send(dev->i2c, AT24CXX_ADDR | dev->AddrInput, 0, buf, 2) == 2)
#endif
        return RT_EOK;
    else
        return -RT_ERROR;

}

sys_force_static_inline rt_err_t
at24cxx_read_page(at24cxx_device_t dev, uint32_t readAddr, uint8_t *pBuffer, uint16_t numToRead) {
    rt_i2c_msg msgs[2];
    uint8_t AddrBuf[2];

    msgs[0].addr = AT24CXX_ADDR | dev->AddrInput;
    msgs[0].flags = RT_I2C_WR;

#if (EE_TYPE > AT24C16)
    AddrBuf[0] = readAddr >> 8;
    AddrBuf[1] = readAddr;
    msgs[0].buf = AddrBuf;
    msgs[0].len = 2;
#else
    AddrBuf[0] = readAddr;
    msgs[0].buf = AddrBuf;
    msgs[0].len = 1;
#endif

    msgs[1].addr = AT24CXX_ADDR | dev->AddrInput;
    msgs[1].flags = RT_I2C_RD;
    msgs[1].buf = pBuffer;
    msgs[1].len = numToRead;

    if (dev->i2c->master_xfer(dev->i2c->bit_ops, msgs, 2) == 0) {
        return RT_ERROR;
    }
    return RT_EOK;
}

sys_force_static_inline rt_err_t
at24cxx_write_page(at24cxx_device_t dev, uint32_t wirteAddr, uint8_t *pBuffer, uint16_t numToWrite) {
    rt_i2c_msg msgs[2];
    uint8_t AddrBuf[2];

    msgs[0].addr = AT24CXX_ADDR | dev->AddrInput;
    msgs[0].flags = RT_I2C_WR;

#if (EE_TYPE > AT24C16)
    AddrBuf[0] = wirteAddr >> 8;
    AddrBuf[1] = wirteAddr;
    msgs[0].buf = AddrBuf;
    msgs[0].len = 2;
#else
    AddrBuf[0] = wirteAddr;
    msgs[0].buf = AddrBuf;
    msgs[0].len = 1;
#endif

    msgs[1].addr = AT24CXX_ADDR | dev->AddrInput;
    msgs[1].flags = RT_I2C_WR | RT_I2C_NO_START;
    msgs[1].buf = pBuffer;
    msgs[1].len = numToWrite;

    if (dev->i2c->master_xfer(dev->i2c->bit_ops, msgs, 2) <= 0) {
        return RT_ERROR;
    }

    return RT_EOK;
}

at24cxx_device_t at24cxx_init(i2c_bus_device_t i2c, uint8_t AddrInput) {
    at24cxx_device_t dev;
    dev = rt_calloc(1, sizeof(at24cxx_device_t));

    if (dev == NULL)
        return dev;
    dev->i2c = i2c;
    dev->AddrInput = AddrInput;
    return dev;
}

rt_err_t at24cxx_read(at24cxx_device_t dev, uint32_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead) {
    if (ReadAddr + NumToRead > AT24CXX_MAX_MEM_ADDRESS) {
        return RT_ERROR;
    }
    while (NumToRead) {
        *pBuffer++ = at24cxx_read_one_byte(dev, ReadAddr++);
        NumToRead--;
    }
    return RT_EOK;
}

rt_err_t at24cxx_write(at24cxx_device_t dev, uint32_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite) {
    uint16_t i = 0;
    if (WriteAddr + NumToWrite > AT24CXX_MAX_MEM_ADDRESS) {
        return RT_ERROR;
    }
    while (1) //NumToWrite--
    {
        if (at24cxx_write_one_byte(dev, WriteAddr, pBuffer[i]) == RT_EOK) {
            bsp_ms_delay(2);
            WriteAddr++;
        }
        if (++i == NumToWrite) {
            break;
        }
        bsp_ms_delay(EE_TWR);
    }
    return RT_EOK;
}

rt_err_t at24cxx_check(at24cxx_device_t dev, uint16_t addr, uint8_t val) {
    uint8_t temp;
    temp = at24cxx_read_one_byte(dev, addr);
    if (temp == val) return RT_EOK;
    else {
        at24cxx_write_one_byte(dev, addr, val);
        bsp_ms_delay(EE_TWR);            // wait 5ms befor next operation
        temp = at24cxx_read_one_byte(dev, addr);
        if (temp == val) return RT_EOK;
    }
    return RT_ERROR;
}

rt_err_t at24cxx_page_read(at24cxx_device_t dev, uint32_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead) {
    rt_err_t result = RT_EOK;
    uint16_t pageReadSize = AT24CXX_PAGE_BYTE - ReadAddr % AT24CXX_PAGE_BYTE;
    if (ReadAddr + NumToRead > AT24CXX_MAX_MEM_ADDRESS) {
        return RT_ERROR;
    }
    while (NumToRead) {
        if (NumToRead > pageReadSize) {
            if (at24cxx_read_page(dev, ReadAddr, pBuffer, pageReadSize)) {
                result = RT_ERROR;
            }

            ReadAddr += pageReadSize;
            pBuffer += pageReadSize;
            NumToRead -= pageReadSize;
            pageReadSize = AT24CXX_PAGE_BYTE;
        } else {
            if (at24cxx_read_page(dev, ReadAddr, pBuffer, NumToRead)) {
                result = RT_ERROR;
            }
            NumToRead = 0;
        }
    }


    return result;
}

rt_err_t at24cxx_page_write(at24cxx_device_t dev, uint32_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite) {
    rt_err_t result = RT_EOK;
    uint16_t pageWriteSize = AT24CXX_PAGE_BYTE - WriteAddr % AT24CXX_PAGE_BYTE;
    if (WriteAddr + NumToWrite > AT24CXX_MAX_MEM_ADDRESS) {
        return RT_ERROR;
    }

    while (NumToWrite) {
        if (NumToWrite > pageWriteSize) {
            if (at24cxx_write_page(dev, WriteAddr, pBuffer, pageWriteSize)) {
                result = RT_ERROR;
            }
            bsp_ms_delay(EE_TWR);   // wait 5ms befor next operation

            WriteAddr += pageWriteSize;
            pBuffer += pageWriteSize;
            NumToWrite -= pageWriteSize;
            pageWriteSize = AT24CXX_PAGE_BYTE;
        } else {
            if (at24cxx_write_page(dev, WriteAddr, pBuffer, NumToWrite)) {
                result = RT_ERROR;
            }
            bsp_ms_delay(EE_TWR);   // wait 5ms befor next operation

            NumToWrite = 0;
        }
    }

    return result;
}

测试源码

#include "bsp_i2c_soft.h"
#include "module-at24cxx.h"

#define DBG_ENABLE
#define DBG_SECTION_NAME "at24xx_test"
#define DBG_LEVEL DBG_LOG

#include "sys_dbg.h"

soft_i2c_cnf_t I2C_Gpio_Cnf = {
        .port_sda = GPIOB,
        .port_scl =GPIOB,
        .scl=GPIO_PIN_6,
        .sda=GPIO_PIN_7,
};
i2c_bit_ops_t bit_ops = {
        .option={
                .delay_us =1,
                .timeout=100
        }
};
struct i2c_bus_device i2c_device;
at24cxx_device_t at24CxxDevice;

static void pre_init(void) {


}

static void init(void) {
    i2c_bus_init(&i2c_device, &bit_ops, &I2C_Gpio_Cnf);
}


rt_uint8_t data[] = {12, 3, 4, 5, 7, 2, 5, 7, 4, 2};
rt_uint8_t read_data[10];

static void after_init(void) {
    at24CxxDevice = at24cxx_init(&i2c_device, 0);
    if (at24cxx_page_write(at24CxxDevice, 0x1, data, sizeof(data)) == RT_EOK) {
        LOG_D("write data ok\r\n");
        HAL_Delay(5);
        if (at24cxx_page_read(at24CxxDevice, 0x1, read_data, sizeof(read_data)) == RT_EOK) {
            LOG_D("read data ok\r\n");
        }

    }


}
//app_init_export(i2c_soft_test, pre_init, init, after_init);

你可能感兴趣的:(STM32相关驱动,stm32,单片机,嵌入式硬件)