单片机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 …...

互联网赚钱项目有哪些?目前最火的互联网项目
互联网是一个神奇的行业,大门不出二门不迈,一根网线一台电脑,甚至一台手机就可以赚钱。它给我们创造了前所未有的商业机会,让成千上万有梦想,敢想敢干的人通过互联网获得了巨大的成功!正因为如此࿰…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

若依登录用户名和密码加密
/*** 获取公钥:前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...
接口 RESTful 中的超媒体:REST 架构的灵魂驱动
在 RESTful 架构中,** 超媒体(Hypermedia)** 是一个核心概念,它体现了 REST 的 “表述性状态转移(Representational State Transfer)” 的本质,也是区分 “真 RESTful API” 与 “伪 RESTful AP…...
使用python进行图像处理—图像滤波(5)
图像滤波是图像处理中最基本和最重要的操作之一。它的目的是在空间域上修改图像的像素值,以达到平滑(去噪)、锐化、边缘检测等效果。滤波通常通过卷积操作实现。 5.1卷积(Convolution)原理 卷积是滤波的核心。它是一种数学运算,…...