单片机GD32F303RCT6 (Macos环境)开发 (十五)—— i2c1采用DMA方式的读写函数

news2024/11/29 6:31:30

i2c1采用DMA方式的读写函数

1、关于i2c1的DMA的映射如图
在这里插入图片描述
2、关于代码的宏定义配置
Application目录的Makefile中 ENABLE_I2C_TEST = yes才会编译I2C1的相关代码。
同时修改i2c.h文件,定义I2C1_MODE为I2C1_MODE_DMA,这样i2c1的配置为dma模式。

#define I2C1_MODE                   I2C1_MODE_DMA

3、I2C相关配置,外部调用函数,供main.c初始化i2c1时使用。
代码如下:

void i2c1_dma_init(void)
{
    /* enable GPIOB clock */
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_DMA0);

    /* enable I2C1 clock */
    rcu_periph_clock_enable(RCU_I2C1);
    /* connect PB10 to I2C1_SCL */
    /* connect PB11 to I2C2_SDA */
    gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10 | GPIO_PIN_11);//配置PB10,PB11为复用功能

    /* configure I2C clock */
    i2c_clock_config(I2C1, I2C1_SPEED, I2C_DTCY_2);
    /* configure I2C address */
    i2c_mode_addr_config(I2C1, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0xff);
    /* enable I2C1 */
    i2c_enable(I2C1);
    /* enable acknowledge */
    i2c_ack_config(I2C1, I2C_ACK_ENABLE);
}

4、DMA发送函数,可发送多字节寄存器+数据格式。

static void i2c1_dma_tx_config(uint8_t *p_data,uint8_t len)
{
    dma_parameter_struct dma_init_struct;
    /* initialize DMA channel3 */
    dma_deinit(DMA0, DMA_CH3);
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = (uint32_t)p_data;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = len;
    dma_init_struct.periph_addr = (uint32_t)&I2C_DATA(I2C1);
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA0, DMA_CH3, &dma_init_struct);
}

static void i2c1_dma_tx_data(uint8_t slave_addr,uint8_t *p_data,uint8_t len)
{
    /* wait until I2C bus is idle */
    while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
    
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C1);
    
    /* wait until SBSEND bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_SBSEND));
    
    /* send slave address to I2C bus */
    i2c_master_addressing(I2C1, slave_addr, I2C_TRANSMITTER);
    
    /* wait until ADDSEND bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
    
    /* clear the ADDSEND bit */
    i2c_flag_clear(I2C1,I2C_FLAG_ADDSEND);
    
    /* wait until the transmit data buffer is empty */
    while( SET != i2c_flag_get(I2C1, I2C_FLAG_TBE));

    i2c1_dma_tx_config(p_data,len);
    
      /* enable I2C1 DMA */
    i2c_dma_config(I2C1, I2C_DMA_ON);

    /* enable DMA0 channel3 */
    dma_channel_enable(DMA0, DMA_CH3);

    /* DMA0 channel3 full transfer finish flag */
    while(!dma_flag_get(DMA0, DMA_CH3, DMA_FLAG_FTF));
    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(I2C1);
    
    /* wait until the stop condition is finished */
    while(I2C_CTL0(I2C1)&0x0200);  
}
/**
 * 封装一个函数按寄存器写的函数,寄存器地址可以有多位。
 * 数据可以有多个
 * dma方式
*/
void i2c1_dma_send_data(uint8_t slave_addr,uint8_t *reg_addr,
                        uint16_t addr_len,uint8_t *p_data,uint8_t data_len)
{
    uint8_t data[I2C_TX_RX_DATA_LEN_MAX] = {0};
    uint8_t *p;
    if ((addr_len + data_len) > I2C_TX_RX_DATA_LEN_MAX)
    {
        perror("data to long and return\r\n");
        return ;
    }
    p = data;
    memcpy(p,reg_addr,addr_len);
    p += addr_len;
    memcpy(p,p_data,data_len);

    i2c1_dma_tx_data(slave_addr,data,(addr_len+data_len));

}	

5、DMA接收函数封装,注意读取一个自己数据的时候,不能采用dma的方式,在函数中做了判断,一个字节的读取继续用poll方式。

uint8_t i2c1_buff_rx[128];

static void i2c1_dma_rx_config(uint8_t *p_data,uint8_t len)
{
    dma_parameter_struct dma_init_struct;
    /* initialize DMA channel4 */
    dma_deinit(DMA0, DMA_CH4);
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = (uint32_t)p_data;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = len;
    dma_init_struct.periph_addr = (uint32_t)&I2C_DATA(I2C1);
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA0, DMA_CH4, &dma_init_struct);
}

void i2c1_dma_receive_data(uint8_t slave_addr, uint8_t *reg_addr,uint16_t addr_len,  
            uint8_t* p_buffer, uint16_t number_of_byte)
{  
    /* wait until I2C bus is idle */
    while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));

    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C1);
    
    /* wait until SBSEND bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_SBSEND));
    
    /* send slave address to I2C bus */
    i2c_master_addressing(I2C1, slave_addr, I2C_TRANSMITTER);
    
    /* wait until ADDSEND bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
    
    /* clear the ADDSEND bit */
    i2c_flag_clear(I2C1,I2C_FLAG_ADDSEND);
    
    /* wait until the transmit data buffer is empty */
    while(SET != i2c_flag_get( I2C1 , I2C_FLAG_TBE));

    /* enable I2C1*/
    i2c_enable(I2C1);
    
    /* send the EEPROM's internal address to write to */
    while (addr_len)
    {
        i2c_data_transmit(I2C1, *reg_addr++); 
        addr_len--; 
        /* wait until BTC bit is set */
        while(!i2c_flag_get(I2C1, I2C_FLAG_BTC));
    }
    
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C1);
    
    /* wait until SBSEND bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_SBSEND));
    
    /* send slave address to I2C bus */
    i2c_master_addressing(I2C1, slave_addr, I2C_RECEIVER);

    /* wait until ADDSEND bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
    
    /* clear the ADDSEND bit */
    i2c_flag_clear(I2C1,I2C_FLAG_ADDSEND);

    if(number_of_byte < 2) 
    {
        /* disable acknowledge */
        i2c_ack_config(I2C1, I2C_ACK_DISABLE);
        /* clear ADDSEND register by reading I2C_STAT0 then I2C_STAT1 register (I2C_STAT0 has already been read) */
        i2c_flag_get(I2C1, I2C_FLAG_ADDSEND);
        /* send a stop condition to I2C bus*/
        i2c_stop_on_bus(I2C1);
        /* wait for the byte to be received */
        while(!i2c_flag_get(I2C1, I2C_FLAG_RBNE));
        /* read the byte received from the EEPROM */
        *p_buffer = i2c_data_receive(I2C1);
        /* decrement the read bytes counter */
        number_of_byte--;     
    } 
    else
    {
        i2c1_dma_rx_config(p_buffer,number_of_byte);
        i2c_dma_last_transfer_config(I2C1, I2C_DMALST_ON);
        /* enable I2C1 DMA */
        i2c_dma_config(I2C1, I2C_DMA_ON);
        /* enable DMA0 channel5 */
        dma_channel_enable(DMA0, DMA_CH4);
        /* wait until BTC bit is set */
        while(!dma_flag_get(DMA0, DMA_CH4, DMA_FLAG_FTF));
    }
    /* wait until the stop condition is finished */
    while(I2C_CTL0(I2C1)&0x0200);
    i2c_stop_on_bus(I2C1);

    /* enable acknowledge */
    i2c_ack_config(I2C1,I2C_ACK_ENABLE);
    i2c_ackpos_config(I2C1,I2C_ACKPOS_CURRENT);

}

5、main.c中调用,往eeprom中写入{0x02,0x07,0x05,0x45,0x56,0x89,0xF3,然后读出来,看看是否一致。

uint8_t addr = 0x00;
unsigned char data[7] = {0x02,0x07,0x05,0x45,0x56,0x89,0xF3};
i2c1_dma_init();
i2c1_dma_send_data(0xA0,&addr,1,data,7);

delay_1ms(200);
unsigned char r_data[7];
i2c1_dma_receive_data(0xA0,&addr,1,r_data,7);
print_register_value(r_data,7);

在这里插入图片描述
读出来是一样的
6、代码路径:https://gitee.com/xiaoguo-tec_0/gd32-iap-code.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/512553.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Microelectronic学习章节总结(3)-- gate level to physical level design

文章目录 数字逻辑设计的主要流程logic familyCMOSTransistor实现的时序逻辑 PSUDO-NMOSDCVSL(Differential Cascode Voltage Swing Logic)DOMINOC2MOS&#xff08;Clocked CMOS&#xff09;TSPC&#xff08;True Single Phase Clocking&#xff09; Transistor behaviorCMOS i…

【C生万物】 指针篇 (进级) 00

欢迎来到 Claffic 的博客 &#x1f49e;&#x1f49e;&#x1f49e; &#x1f449; 专栏&#xff1a;《C生万物 | 先来学C》&#x1f448; 前言&#xff1a; 前面已经带大家学习了初级的指针&#xff0c;先回顾一下重点&#xff1a;指针是用来存…

数据库sql语句(视图的创建)

例题&#xff1a; 建表&#xff1a;要注意各表之间的索引联系&#xff0c;建表先后顺序很重要&#xff0c;不然建不了&#xff0c;例如先建dept&#xff0c;在建其他表&#xff0c;先在dept插入数据&#xff0c;再在其他表插入数据 &#xff08;1&#xff09; create table …

SW simulation解算器选取

接下来重点介绍以下4种解算器&#xff0c;并对解算器进行实际的计算测试。1)Direct sparse解算器&#xff1a;稀疏矩阵解算器&#xff0c;目前使用最为广泛也是发展最为成熟的解算器&#xff0c;几乎所有的有限元分析软件都有该解算器。它可以用于大多数计算模型&#xff0c;堪…

<IBM> 《HA网卡确认方法》

《HA网卡确认方法》 1 HA IP地址类型2HA IP地址设置原则3 HA网卡日常查看方法3.1 查看hosts文件3.2 查看网卡和IP 4 通过命令方式直接查看5 直接查看HA配置4 HA网卡SMIT查看方法&#xff08;暂不完整&#xff09;4.1 根据hosts文件确认IP对应的别名4.2 根据serviceIP确认Persis…

Django SQL注入漏洞分析(CVE-2022-28346)

漏洞简介 Django 在2022年发布的安全更新&#xff0c;修复了在 QuerySet 的 annotate()&#xff0c; aggregate()&#xff0c; extra() 等函数中存在的 SQL 注入漏洞。 影响版本 2.2< Django Django <2.2.28 3.2< Django Django ❤️.2.13 4.0< Django Django &…

白盒测试的静态和动态

白盒测试的静态和动态 静态白盒测试 检查设计和代码 静态测试是指测试非运行部分——检查和审查。白盒测试是指访问代码&#xff0c;能够查看和审查。静态白盒测试实在不执行的条件下有条理地仔细审查软件设计、体系结构和代码&#xff0c;从而找出软件缺陷的过程。有时也称为结…

SpringBoot中@ControllerAdvice/@RestControlAdvice+@ExceptionHandler实现全局异常捕获与处理

场景 在编写Controller接口时&#xff0c;为避免接口因为未知的异常导致返回不友好的结果和提示。 如果不进行全局异常捕获则需要对每个接口进行try-catch或其他操作。 可以对Controller进行全局的异常捕获和处理&#xff0c;一旦发生异常&#xff0c;则返回通用的500响应码与…

洁净环境GMP 要求悬浮粒子 浮游菌 高效过滤器检漏验证所需仪器

lighthouse尘埃粒子计数器 北京中邦兴业是美国lighthouse中国区核心代理服务商&#xff0c;各类型号尘埃粒子计数器均有现货可发。常见尘埃粒子计数器类型&#xff1a;便携式&#xff08;台式&#xff09;、手持式、在线式、液体式。 客户现场 lighthouse浮游菌采样器 北京中…

nginx(七十五)nginx与Vary响应头细节探讨

一 Vary ① nginx与Vary有关联的地方 nginx源码分析处理Vary响应头的逻辑 CORS和缓存 gzip_vary 1) gzip_vary on 如果设置为开启2) 服务器返回数据时会在头部带上"Vary:Accept-Encoding"的标识3) 客户端便可以知道获取到的数据是否已经被压缩,默认为关闭 prox…

ros获取typec-usb摄像头

确保usb或者typec摄像头插在主机上,我这里是typec摄像头&#xff0c;使用了一个usb-typec转接头。 windows在设备管理器中查看是否存在端口&#xff0c;如果没有&#xff0c;可以使用下面的软件进行尝试。 链接&#xff1a;https://pan.baidu.com/s/1hxp3m68W6NjY-3D7q8rGnA 提…

Linux线程同步(1)——一个例子看懂为什么需要线程同步?

对于一个单线程进程来说&#xff0c;它不需要处理线程同步的问题&#xff0c;所以线程同步是在多线程环境下需要注意的问题。线程的主要优势在于&#xff0c;资源的共享性&#xff0c;譬如通过全局变量来实现信息共享&#xff0c;不过这种便捷的共享是有代价的&#xff0c;那就…

postman处理各种请求数据

1、后台request接收postman参数 2、后台单个参数接收postman 3、后台RequestParam参数接收postman 注意事项&#xff1a;情况一&#xff1a;全部都是单个字符串的 情况二&#xff1a;有可能是一个json对象序列化成字符串过来的&#xff0c;那么需要在form-data中设置 …

区间预测 | MATLAB实现QRCNN-LSTM卷积长短期记忆神经网络分位数回归时间序列区间预测

区间预测 | MATLAB实现QRCNN-LSTM卷积长短期记忆神经网络分位数回归时间序列区间预测 目录 区间预测 | MATLAB实现QRCNN-LSTM卷积长短期记忆神经网络分位数回归时间序列区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 1.Matlab实现基于QRCNN-LSTM分位数回…

Elasticsearch:如何在 Elasticsearch 中存储复杂的关系数据

在传统的数据库中&#xff0c;对数据关系的描述无外乎三种&#xff1a;一对一、一对多和多对多关系。 如果有关系相关的数据&#xff0c;我们一般在建表的时候加上主外键。 建立数据链接&#xff0c;然后在查询或者统计中通过 join 恢复或者补全数据&#xff0c;最后得到我们需…

Springboot +Flowable,设置流程变量的方式(二)

一.简介 为什么需要流程变量。 举个例子&#xff0c;假设有如下一个流程&#xff0c;截图如下&#xff1a; 这是一个请假流程&#xff0c;那么谁请假、请几天、起始时间、请假理由等等&#xff0c;这些都需要说明&#xff0c;不然领导审批的依据是啥&#xff1f;那么如何传递…

软件测试面试宝典,最常见的7个高频面试题(附答案,建议收藏)

收集了2022年所有黑马学员的面试题后&#xff0c;负责就业的黑马讲师们整理出了7个高频出现的面试题&#xff0c;一起来看看。 高频问题1&#xff1a;请自我介绍下&#xff1f; 高频问题2&#xff1a;请介绍下最近做过的项目&#xff1f; 高频问题3&#xff1a;请介绍下你印象…

2023 年第三届长三角高校数学建模 A 题 快递包裹装箱优化问题

2022 年&#xff0c;中国一年的包裹已经超过 1000 亿件&#xff0c;占据了全球快递事务量的一 半以上。近几年&#xff0c;中国每年新增包裹数量相当于美国整个国家一年的包裹数量&#xff0c; 十年前中国还是物流成本最昂贵的国家&#xff0c;当前中国已经建立起全世界最强大、…

利用jQuery做一个简单的猜数字游戏

目录 利用jQuery做一个简单的猜数字游戏 代码 效果 利用jQuery做一个简单的猜数字游戏 代码 <!DOCTYPE html> <html><head><title>键盘事件-猜数字</title><style>#body_style {background-color: #c7f5db;}#myDiv {position: absolu…

单片机GD32F303RCT6 (Macos环境)开发 (十七)—— i2c1从机中断接收发送数据

i2c1从机中断接收发送数据 1、将i2c1设置为从机模式&#xff0c;与树莓派连接。树莓派发送或者读取数据&#xff0c;gd32中断触发&#xff0c;从而接收数据或者向主机发送数据。 2、关于代码的宏定义配置 Application目录的Makefile中 ENABLE_I2C_TEST yes才会编译I2C1的相关…