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

这篇具有很好参考价值的文章主要介绍了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);

文章来源地址https://www.toymoban.com/news/detail-499183.html

到了这里,关于Clion开发STM32之I2C驱动(参考RT-Thread)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32 SHT40驱动源码(使用硬件I2C)

    目录 简介: SHT40.c: SHT40.h 测试结果:         SHT40是瑞士Sensirion公司推出的第四代温湿度传感器,内部集成加热器用于去除表面微小液滴。集成I2C接口,典型的相对湿度精度1.8%RH,典型温度精度0.2℃,运行在0-100%RH和-40-125℃的环境中。 主控:STM32H7B0VBT6 平台:STM32CubeIDE SHT4

    2024年03月19日
    浏览(61)
  • STM32配合cubeMX硬件I2C驱动0.96寸OLED

    目录 一、简单介绍 1.1   OLED 1.2   I2C协议 二、实战 2.1 工程配置 2.2 测试工程 2.3 波形分析 三、驱动OLED 3.1 初始化代码 3.2 清屏函数 3.3 设置坐标函数 3.4 显示字符函数 3.5 显示字符串函数 3.6 显示图片函数 附录 驱动代码文件 oled.c oled.h f6x8.h 有机发光二极管 (英语:Organic

    2024年02月08日
    浏览(52)
  • HAL STM32 HW I2C DMA + SSD1306/SH1106驱动示例

    📍硬件I2C DMA驱动参考: https://blog.csdn.net/weixin_45065888/article/details/118225993 🔖本工程基于 STM32F103VCT6 ,驱动程序独立,可以移植到任意STM32型号上使用。 📑字体大小说明 🌿该驱动程序ASCII字符集类型大小包含:6X8、8X16,12X6 三种。其中6X8和8X16共用一个API函数调用,形参不同

    2024年02月22日
    浏览(39)
  • 【STM32 CubeMX】I2C层次结构、I2C协议

    在STM32 CubeMX环境中,I2C(Inter-Integrated Circuit)是一种常用的串行通信协议,广泛应用于连接各种外设和传感器。理解I2C的层次结构、协议和硬件结构对于STM32微控制器的开发至关重要。通过STM32 CubeMX提供的图形化配置工具,我们能够更轻松地理解和配置I2C通信,同时深入了解

    2024年02月22日
    浏览(66)
  • STM32F103C8T6—库函数应用I2C/SPI驱动OLED显示中文、字符串

    I2C(Inter-Integrated Circuit) SPI(Serial Peripheral Interface) 传输方式 半双工 全双工 传输速度 低速,100Kbps----4Mbps 高速,30Mbps以上 几线制 4线制:VCC,GND,SCL,SDA 6/7线制:VCC,GND,SCLK(D0),MOSI(D1/SDA),DC,CS/SS 主从模式 多主机总线,通过SDA上的地址信息锁定从机 只有一个主机,主

    2024年02月02日
    浏览(50)
  • STM32 I2C

    目录 I2C通信  软件I2C读写MPU6050 I2C通信外设 硬件I2C读写MPU6050 I2C通信 R/W:0写1读 十轴:3轴加速度,3轴角速度,3轴磁场强度和一个气压强度  软件I2C读写MPU6050 MyI2C.c MPU6050.c MPU6050_Reg.h(寄存器) main.c I2C通信外设 GPIO口需要配置为复用开漏输出模式。复用:就是GPIO的状态是交由

    2024年02月19日
    浏览(40)
  • STM32---I2C

    目录                                       一.I2C协议 1.什么是I2C协议?  2.物理层特性                                     二.协议层 1.I2C读写过程 2.I2C外设 3.I2C外设通讯过程              三.I2C库函数                       四.EEPROM 写操作: 读操作:      

    2024年02月16日
    浏览(34)
  • STM32学习笔记(十)丨I2C通信(使用I2C实现MPU6050和STM32之间通信)

    ​  本次课程采用单片机型号为STM32F103C8T6。(鉴于笔者实验时身边只有STM32F103ZET6,故本次实验使基于ZET6进行的) ​  课程链接:江协科技 STM32入门教程   往期笔记链接:   STM32学习笔记(一)丨建立工程丨GPIO 通用输入输出   STM32学习笔记(二)丨STM32程序调试

    2024年01月19日
    浏览(50)
  • STM32——I2C通信

            I2C(Inter IC Bus)是由Philips公司开发的一种通用数据总线,它是两线式串行总线,它具有两根通信线: SCL(Serial Clock)、SDA(Serial Data) ,多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。I2C是同步半双

    2024年01月25日
    浏览(42)
  • STM32-I2C通讯

    I2C( Inter-Integrated Circuit )是一种通用的总线协议。它是由Philips(飞利浦)公司,现NXP(恩智浦)半导体开发的一种 简单的双向两线制 总线协议标准。 I2C有两根双向的信号线,一根数据线SDA用于收发数据,一根时钟线SCL用于通信双方时钟的同步。 支持同步,半双工,带数据应答,

    2024年03月14日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包