单片机GD32F303RCT6 (Macos环境)开发 (十五)—— i2c1采用DMA方式的读写函数
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
相关文章:
单片机GD32F303RCT6 (Macos环境)开发 (十五)—— i2c1采用DMA方式的读写函数
i2c1采用DMA方式的读写函数 1、关于i2c1的DMA的映射如图 2、关于代码的宏定义配置 Application目录的Makefile中 ENABLE_I2C_TEST yes才会编译I2C1的相关代码。 同时修改i2c.h文件,定义I2C1_MODE为I2C1_MODE_DMA,这样i2c1的配置为dma模式。 #define …...
通知短信 API 技术细节以及发送流程机制原理解析
引言 短信是一种简单、直接、高效的通信方式,被广泛应用于各个领域。在移动互联网时代,短信成为了客户服务、政府通知、公共服务等方面的重要工具。为了更好地利用短信这种通信方式,通知短信 API应运而生。短信API可以帮助企业、政府和应用程…...
Protobuf: 高效数据传输的秘密武器
当涉及到网络通信和数据存储时,数据序列化一直都是一个重要的话题;特别是现在很多公司都在推行微服务,数据序列化更是重中之重,通常会选择使用 JSON 作为数据交换格式,且 JSON 已经成为业界的主流。但是 Google 这么大…...
第五十四章 Unity 移动平台输入(下)
本章节我们介绍一个模拟器插件。这种插件比较多,比如EasyTouch,Lean Touch,Joystick Pack等等。EasyTouch是一个使用非常广泛的插件,支持点击,拖拽,遥感等很多常用功能。不过遗憾的是,该插件已经…...
KD305Y带吸收比极化指数兆欧表
一、概述 KD305Y绝缘电阻测试仪对众多的电力设备如:电缆、电机、发电机、变压器、互感器、高压开关、避雷器等要求做一系列的绝缘性能试验,首先是要做绝缘电阻测试。近年来随着电力事业的飞速发展,大容量设备的使用不断增加,用普通的兆欧表无…...
磁盘空间不足怎么办?释放磁盘空间的4种方法
虽然现在硬盘的空间越来越大,但是在这个数据爆炸的时代中,总是会觉得存储空间不够用,一不注意磁盘就满了,那么除了清空回收站、卸载某些程序外,还能怎么释放磁盘空间呢? 方案一:禁用休眠 休眠是…...
ChatGPT调教指北,技巧就是效率!
技巧就是效率 很多人都知道ChatGPT很火很强,几乎无所不能,但跨越了重重门槛之才有机会使用的时候却有些迷茫,一时间不知道如何使用它。如果你就是把他当作一个普通的智能助手来看待,那与小爱同学有什么区别?甚至还差劲…...
Android启动流程(五)——init进程对子进程的监控
init进程会读取rc文件,然后孵化很多其他系统服务进程,为防止子进程死亡后称为僵尸进程,init需要监测子进程是否死亡,如果死亡,则清除子进程资源,并重新拉起进程。 system/core/init/init.cpp InstallSigna…...
Python每日一练:蚂蚁家族(详解集合法)
文章目录 前言一、题目二、代码分析总结 前言 这题挺有意思,感觉评简单难度有点低了,如果正经用无向图来做,代码还是有点长的。首先得建立节点,估计除第一个和最后一个每个节点都是一条线连进,一条线连出的。就可以这…...
图神经网络:在KarateClub数据集上动手实现图神经网络
文章说明: 1)参考资料:PYG官方文档。超链。 2)博主水平不高,如有错误还望批评指正。 3)我在百度网盘上传了这篇文章的jupyter notebook。超链。提取码8888。 文章目录 文献阅读:代码实操: 文献阅读: 参考文…...
ArduPilot之开源代码调试技巧
ArduPilot之开源代码调试技巧 1. 源由2. ArduPilot Code Debugging Part13. ArduPilot Code Debugging Part24. 持续更新中。。。5. 参考资料 1. 源由 对于如何调试和验证ArduPilot,对于新手来说,有的时候反而是入门的一个门槛。 其实这个并不难&#…...
Linux网络基础-2
在之前的网络基础博客中,我们对网络的基本概念进行了一个简单的介绍,那么接下来的网络内容中,我们将对网络通信中的典型协议进行详细解释。 我们根据网络协议中的分层来对典型协议进行注意介绍,不过对于物理层的传输我们不做考究…...
软件测试报告模板
目录 2 1 概述... 3 1.1 测试目的... 3 1.2 测试策略... 3 1.3 测试方法... 3 1.4 计划验收标准... 3 1.5 测试用例... 4...
记一次azkaban调度异常处理
一、背景 预发布环境使用的数据库性能比较低,根据业务测试的需求,需要将数据库更换成 稳定高性能的数据库。更换业务数据库后azkaban定时任务失败 二、数据库服务信息 说明:该部分使用代号来代替,非真实信息 该数据库存储了azka…...
开发一个vue自定义指令的npm库-系列三:使用rollup打包npm库并发布
配置 rollup 使用rollup将 TypeScript 代码转换为 JavaScript,然后进行压缩和输出到目标文件。 项目根目录新建rollup.config.js import typescript from "rollup/plugin-typescript"; import terser from "rollup/plugin-terser"; import de…...
C嘎嘎的运算符重载基础教程以及遵守规则【文末赠书三本】
博主名字:阿玥的小东东 大家一起共进步! 目录 基础概念 优先级和结合性 不会改变用法 在全局范围内重载运算符 小结 本期送书:盼了一年的Core Java最新版卷Ⅱ,终于上市了 基础概念 运算符重载是通过函数重载实现的…...
【MCAL_UART】-1.2-图文详解RS232,RS485和MODBUS的关系
目录 1 UART,RS232和RS485通信拓扑 2 什么是RS232 2.1 RS232标准的演变 2.2 RS232标准讲了哪些 2.2.1 RS232通信的电平 2.2.2 RS232通信的带宽 2.2.3 RS232通信距离 2.2.4 RS232通信的机械接口 3 什么是RS485 3.1 RS485标准的演变 3.2 RS485标准讲了哪些…...
设计模式详解(二)——单例模式
单例模式简介 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,创建型模式是一类最常用的设计模式,在软件开发中应用非常广泛,它提供了一种创建对象的最佳方式。 单例模…...
为什么hooks不能在循环、条件或嵌套函数中调用
hooks不能在循环、条件或嵌套函数中调用 为什么? 带着疑问一起去看源码吧~ function App() {const [num, setNum] useState(0);const [count, setCount] useState(0);const handleClick () > {setNum(num > num 1)setCount(2)}return <p …...
互联网赚钱项目有哪些?目前最火的互联网项目
互联网是一个神奇的行业,大门不出二门不迈,一根网线一台电脑,甚至一台手机就可以赚钱。它给我们创造了前所未有的商业机会,让成千上万有梦想,敢想敢干的人通过互联网获得了巨大的成功!正因为如此࿰…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
mac:大模型系列测试
0 MAC 前几天经过学生优惠以及国补17K入手了mac studio,然后这两天亲自测试其模型行运用能力如何,是否支持微调、推理速度等能力。下面进入正文。 1 mac 与 unsloth 按照下面的进行安装以及测试,是可以跑通文章里面的代码。训练速度也是很快的。 注意…...
消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...
车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...
js 比较两个对象的值,不相等就push对象的key
在JavaScript中,比较两个对象(object)的值并找出不相等的key,可以通过多种方法实现。下面是一些常用的方法: 方法1:使用JSON.stringify 这种方法适用于简单的对象,其中对象的值是基本类型或可…...
