Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
I2C_IIC
risc-v_RISCV
RISC-V_milk-v_CV1800B
MilkV Duo I2C 适配 RT-Thread 设备驱动框架
发布于 2024-02-19 11:29:02 浏览:402
订阅该版
[tocm] # MilkV Duo I2C 适配 RT-Thread 设备驱动框架 ## SDK 相关 基于官方 [duo-buildroot-sdk](https://github.com/milkv-duo/duo-buildroot-sdk) 适配 RT-Thread 硬件 i2c 设备驱动。 - 首先复制寄存器,指令等结构体及宏定义,主要位于文件 `hal_dw_i2c.h` 中 - i2c_regs 为 各 i2c 外设的寄存器地址,对应以下起始地址,以便于访问,可通过 get_i2c_base 获取: ```c #define I2C0_BASE 0x4000000 #define I2C1_BASE 0x4010000 #define I2C2_BASE 0x4020000 #define I2C3_BASE 0x4030000 #define I2C4_BASE 0x4040000 ``` - i2c_write_cmd_data,i2c_enable,i2c_disable,i2c_flush_rxfifo,i2c_wait_for_bb,i2c_setaddress,i2c_xfer_init,i2c_xfer_finish,hal_i2c_read,hal_i2c_write,i2c_set_bus_speed,均为操作 i2c 外设的基础方法,通过组合以上函数,基本可以对接至 RT-Thread 的 i2c 设备驱动框架,dw_i2c_dev 那些就不实现了,直接将 i2c 底层的操作 api 对接到 rtt 的 i2c 设备驱动即可。 - 要实现以上API,需要先实现 mimo 方便对寄存器进行读写,目前 rtt 中对该需求已实现。还需要实现 uldey 等延时函数,rtt 中已经实现该芯片架构运行时间的获取: ```c static rt_uint64_t get_ticks(void) { __asm__ __volatile__( "rdtime %0" : "=r"(time_elapsed)); return time_elapsed; } ``` 基于其获取的时间,再实现 us 延时即可: ```c void rt_hw_us_delay(rt_uint32_t us) { unsigned long start_time; unsigned long end_time; unsigned long run_time; start_time = get_ticks(); end_time = start_time + us * (TIMER_CLK_FREQ / 1000000); do{ run_time = get_ticks(); } while(run_time < end_time); } ``` 这里特殊说明一下,芯片运行时钟的获取是移植 RTOS 前期基本,RTOS 移植适配完成后,一般 ms 级的延时就是具备了,例如 `rt_thread_mdelay` 并且一般情况,考虑系统资源的消耗,RTOS 的时间片大小通常设置为 ms 级,所以调用 `rt_thread_mdelay` `rt_thread_delay` 等 api 时,会进入调度。但对于 us 级即以下的延时处理,通常需要针对开发平台特殊实现,并且通常是阻塞型的,延时不会触发调度器,因此也要小心使用,尽量避免使用这类 api 延时较长时间。 ## RTT 设备驱动框架 RT-Thread 设备框架属于组件和服务层,是基于 RT-Thread 内核之上的上层软件。设备框架是针对某一类外设,抽象出来的一套统一的操作方法及接入标准,可以屏蔽硬件差异,为应用层提供统一的操作方法。 RT-Thread 设备框架分为三层:设备驱动层、设备驱动框架层、I/O 设备管理层。其中设备驱动层直接对接底层硬件设备,也是我们需要对接实现的部分。对于 i2c 总线设备有以下方法: ```c struct rt_i2c_bus_device_ops { rt_ssize_t (*master_xfer)(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num); rt_ssize_t (*slave_xfer)(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num); rt_err_t (*i2c_bus_control)(struct rt_i2c_bus_device *bus, int cmd, void *args); }; ``` 实现其中的 master_xfer 即可,其中包含 i2c 消息的收发。 - 其中一部分原代码是对接 sdk 中的 i2c 设备,我们这里不使用其抽象的 i2c 设备,对接至 rtt 的设备驱动框架,部分函数需要改写,去除其 i2c 设备相关部分,例如重写 `i2c_disable` : ```c static void i2c_disable(struct dw_i2c_dev *dw_i2c) { int timeout = 100; if (dw_i2c->wait_irq || dw_i2c->use_interstop) return; /* return due to i2c is still active */ do { mmio_write_32((uintptr_t)&dw_i2c->i2c->ic_enable, 0x0); if ((mmio_read_32((uintptr_t)&dw_i2c->i2c->ic_enable_status) & IC_ENABLE) == 0x0) return; /* * Wait 10 times the signaling period of the highest I2C * transfer supported by the driver (for 400KHz this is * 25us) as described in the DesignWare I2C databook. */ arch_usleep(25); } while (timeout--); printf("timeout in disabling I2C adapter\n"); } ``` 重写后: ```c static void i2c_disable(struct i2c_regs *i2c) { int timeout = 100; do { mmio_write_32((uintptr_t)&i2c->ic_enable, 0x0); if ((mmio_read_32((uintptr_t)&i2c->ic_enable_status) & IC_ENABLE) == 0x0) return; /* * Wait 10 times the signaling period of the highest I2C * transfer supported by the driver (for 400KHz this is * 25us) as described in the DesignWare I2C databook. */ rt_hw_us_delay(25); } while (timeout--); LOG_I("timeout in disabling I2C adapter\n"); } ``` - `hal_i2c_init` 重写如下: ```c static void hal_i2c_init(uint8_t i2c_id) { struct i2c_regs *i2c; uint32_t i2c_intr; LOG_I("%s, i2c-%d\n", __func__, i2c_id); /* Disable i2c */ //Need to acquire lock here i2c = get_i2c_base(i2c_id); i2c_intr = get_i2c_intr(i2c_id); // request_irq(i2c_intr, i2c_dw_isr, 0, "IC2_INTR int", &dw_i2c[i2c_id]); i2c_enable(i2c, false); mmio_write_32((uintptr_t)&i2c->ic_con, (IC_CON_SD | IC_CON_SPD_FS | IC_CON_MM | IC_CON_RE)); mmio_write_32((uintptr_t)&i2c->ic_rx_tl, IC_RX_TL); mmio_write_32((uintptr_t)&i2c->ic_tx_tl, IC_TX_TL); mmio_write_32((uintptr_t)&i2c->ic_intr_mask, 0x0); i2c_set_bus_speed(i2c, I2C_SPEED); //mmio_write_32((uintptr_t)&i2c->ic_sar, slaveaddr); /* Enable i2c */ i2c_enable(i2c, false); //Need to release lock here } ``` - 接下来需要对接一下 i2c 外设的对应中断号,sdk 中使用 `request_irq` 注册中断及其对应的回调函数,在 rtt 中使用 `rt_hw_interrupt_install` : ```c rt_hw_interrupt_install(irqno, rt_hw_i2c_isr, _i2c, _i2c_obj[i].device_name); ``` 并且为了便于应对大小核中断号不一致的情况,在 Kconfig 中添加对应处理: ```python config I2C_IRQ_BASE int default 32 ``` 并通过如下方式表示 i2c 外设的对应中断号: ```c #define I2C0_IRQ (I2C_IRQ_BASE + 0) #define I2C1_IRQ (I2C_IRQ_BASE + 1) #define I2C2_IRQ (I2C_IRQ_BASE + 2) #define I2C3_IRQ (I2C_IRQ_BASE + 3) #define I2C4_IRQ (I2C_IRQ_BASE + 4) ``` - 不要忘记了使能对应的引脚作为 i2c 总线的 sda 和 scl ,例如 i2c0 和 i2c1 分别使用以下引脚: ```c PINMUX_CONFIG(IIC0_SCL, IIC0_SCL); PINMUX_CONFIG(IIC0_SDA, IIC0_SDA); PINMUX_CONFIG(PAD_MIPIRX1P, IIC1_SDA); PINMUX_CONFIG(PAD_MIPIRX0N, IIC1_SCL); ``` 这部分内容是在 sdk 的 u-boot 中进行实现,启动阶段对各外设和引脚进行初始化配置,如果我们在移植到 rtt 中时遗漏了这部分的处理,外设对应的引脚将不会出现我们期望的行为。 ## 测试结果 基本对接完成以后,我们就可以编写一个调用 rtt i2c 设备的简单示例,并使用逻辑分析仪观察一下行为是否正确,这里主要基于 rtt 提供的示例编写一个测试用例 [官方示例](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/i2c/i2c?id=i2c-%e6%80%bb%e7%ba%bf%e8%ae%be%e5%a4%87%e4%bd%bf%e7%94%a8%e7%a4%ba%e4%be%8b) 使用逻辑分析仪查看波形如下: ![逻分波形.png](https://oss-club.rt-thread.org/uploads/20240219/6cff3e204179dafba934b5d317bb96a8.png) 因为并没有挂载对应的 i2c 传感器从机,因此没有应到信号,行为正常。
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
螺丝松掉的人
这家伙很懒,什么也没写!
文章
42
回答
0
被采纳
0
关注TA
发私信
相关文章
1
NXP的I2C应该比ST的好用吧
2
Use of I2C device driver
3
关于I2C 驱动问题请教
4
我如何知道这个iic的io配置和我电路设计的是一致的?
5
I2C模拟读操作失败,不知道问什么进不去读函数
6
RTT的I2C有官方文档资料没有
7
求 STM32F103 IIC 自定义IO初始化 代码
8
报一个LPC4008代码中I2C的bug
9
RTOS IIC总线使用
10
关于在RTT中使用STM32 I2C的疑问
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
cubemx
PWM
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
812
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
2
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部