ARM-I2C 驱动优化与 LM75 温度传感器读取实践

1. 引言

本文围绕嵌入式开发中 I2C 驱动的两个典型优化点展开:一是兼容多字节寄存器地址的读写逻辑,二是基于 LM75 温度传感器的数据读取实现。同时补充了 ARM 平台下 FPU 使能的汇编配置,帮助读者在底层驱动开发中快速定位并解决问题。

2. 代码优化:兼容多字节寄存器地址

在 I2C 通信中,部分传感器或外设的寄存器地址不止一个字节。若驱动只按单字节地址处理,会导致高位地址丢失,从而无法正确访问目标寄存器。下面这段代码通过循环逐字节发送寄存器地址,实现多字节地址兼容。

c 复制代码
// 3. 发送要读取的内存地址
int i = reg_len - 1;
for (; i >= 0; i--)
{
    base->I2DR = (reg_addr >> (8 * i)) & 0XFF;
    status = i2c_wait_iif(base);
    if (status != 0) goto stop;
}

上述实现从最高字节开始,依次将寄存器地址的每个字节写入 I2C 数据寄存器,并在每次写入后等待传输完成。这样无论寄存器地址是 8 位、16 位还是 32 位,都能按序完整发送。

3. LM75 温度传感器读取

LM75 是一款常见的 I2C 接口数字温度传感器,温度数据存放在寄存器 0x00 中,共 2 个字节。下面给出基于 I2C 消息结构体的读取实现。

c 复制代码
float get_temp_value(void)
{
    unsigned short t = 0;
    struct I2C_Msg msg = {
        .dev_addr = 0x48,
        .reg_addr = 0x00,
        .reg_len = 1,
        .data = rcv_buffer,
        .len = 2,
        .dir = I2C_read
    };
    i2c_transfer(I2C1, &msg);
    //i2c_read(I2C1, 0x48, 0x00, 1, rcv_buffer, 2);
    t |= (rcv_buffer[0] << 8) | (rcv_buffer[1] << 0);
    t = t >> 7;
    return t * 0.5;
}

读取流程说明:

  • 设备地址为 0x48,寄存器地址为 0x00,读取长度为 2 字节。
  • 通过 i2c_transfer 完成一次完整的读事务。
  • 将两个字节拼成 16 位数据后右移 7 位,得到 9 位有效温度值。
  • 每个 LSB 对应 0.5 摄氏度,因此乘以 0.5 得到实际温度。

4. ARM 平台 FPU 使能配置

在 ARM Cortex-A 系列处理器上,若需要使用浮点运算单元(FPU),必须先完成寄存器配置。下面是一段典型的 FPU 使能汇编代码。

arm 复制代码
enable_fpu:
    // 1. 设置CPACR寄存器使能FPU访问
    mrc     p15, 0, r0, c1, c0, 2   // 读取CPACR
    orr     r0, r0, #(0xF << 20)    // 设置CP10和CP11为完全访问
    mcr     p15, 0, r0, c1, c0, 2   // 写回CPACR
    // 2. 使能FPU
    mov     r0, #0x40000000         // 设置FPEXC的EN位
    vmsr    fpexc, r0               // 写入FPEXC
    // 3. 配置FPSCR
    mov     r0, #0x00000000         // 清除所有标志位
    vmsr    fpscr, r0               // 写入FPSCR
    bx      lr                      // 返回

配置步骤说明:

  • 第一步通过 CPACR 寄存器开放 CP10 和 CP11 协处理器的完全访问权限。
  • 第二步设置 FPEXC 的 EN 位,正式启用 FPU。
  • 第三步清零 FPSCR 标志位,确保浮点运算从干净状态开始。

5. ADC 模拟量采集

ADC(Analog-to-Digital Converter,模拟到数字转换器)是一种电子设备或模块,用于将连续变化的模拟信号转换为离散的数字信号,以便数字系统(如微处理器、微控制器等)能够对其进行处理和分析。这里的模拟信号是狭义的模拟信号,一般指模拟电压信号转换为数字信号。

相关概念说明:

  • 模拟信号:物理世界中连续变换的物理量。
  • 数字信号:一种离散的、不连续的信号。
  • 传感器:能够探测、感知外部环境信息(如温度、光线、压力、运动等),并将这些信息转换成电信号(通常是电压或电流)的装置或器件。

6. 原理图与参考手册分析

IMX6ULL 的 ADC 模块集成于 SoC 内部,参考电压引脚为 ADC_VREFH。在 Mini 底板原理图中,GPIO_1 的 7 号引脚用于 ADC 输入。参考手册中 ADC1 的输入通道与 GPIO 引脚的对应关系如下:

Signal Description Pad Mode Direction
ADC_VREFH Voltage reference high ADC_VREFH - I
ADC1_IN0 Analog channel 1 input 0 GPIO1_IO00 - I
ADC1_IN1 Analog channel 1 input 1 GPIO1_IO01 - I
ADC1_IN2 Analog channel 1 input 2 GPIO1_IO02 - I
ADC1_IN3 Analog channel 1 input 3 GPIO1_IO03 - I
ADC1_IN4 Analog channel 1 input 4 GPIO1_IO04 - I
ADC1_IN5 Analog channel 1 input 5 GPIO1_IO05 - I
ADC1_IN6 Analog channel 1 input 6 GPIO1_IO06 - I
ADC1_IN7 Analog channel 1 input 7 GPIO1_IO07 - I
ADC1_IN8 Analog channel 1 input 8 GPIO1_IO08 - I
ADC1_IN9 Analog channel 1 input 9 GPIO1_IO09 - I

时钟源选择(ADICLK)说明:

  • 00:IPG clock
  • 01:IPG clock divided by 2
  • 10:Reserved
  • 11:Asynchronous clock(ADACK)

ADC 模块还支持自动校准功能,具体原理可阅读参考手册对应章节。

7. ADC 寄存器配置

IMX6ULL 的 ADC 相关寄存器配置要点如下:

寄存器 位域 说明 默认值
ADCx_HC0 AIEN b7 转换完成中断启用/禁用控制 0
ADCx_HC0 ADCH b0-b4 选择 ADC 通道,每次切换通道时会引发一次 ADC 转换 1
ADCx_HS COCO0 b0 判断 ADC 转换是否完成,读 1 表示转换完成,为 0 则未完成 -
ADCx_R0 CDATA b0-b11 ADC 转换完的最终结果,读低十二位 -
ADCx_CFG OVWREN b16 数据覆盖使能 0
ADCx_CFG AVGS b15-b14 硬件平均选择 00
ADCx_CFG ADTRG b13 转换触发选择 0
ADCx_CFG REFSEL b12-b11 电压参考源选择 00
ADCx_CFG ADHSC b10 高速配置 0
ADCx_CFG ADSTS b9-b8 采样时间选择 00
ADCx_CFG ADLPC b7 低功耗配置 0
ADCx_CFG ADIV b6-b5 时钟分频选择 00
ADCx_CFG ADLSMP b4 长采样时间配置 0
ADCx_CFG MODE b3-b2 转换模式选择(分辨率) 10
ADCx_CFG ADICLK b1-b0 输入时钟源选择 11
ADCx_GC CAL b7 校准启动,写 1 启动,读 0 校准完成 -
ADCx_GC ADCO b6 连续转换使能 0
ADCx_GC AVGE b5 硬件平均使能 0
ADCx_GC ACFE b4 比较功能使能 0
ADCx_GC ACFGT b3 比较功能"大于"使能 0
ADCx_GC ACREN b2 比较功能范围使能 0
ADCx_GC DMAEN b1 DMA 使能 0
ADCx_GC ADACKEN b0 异步时钟输出使能 1
ADCx_GS CALF b1 校准失败标志,0 校准成功,1 校准失败,需要写 1 清零 -

8. 光敏传感器与代码编写

光敏传感器的原理图可参考 SmartDraw 图。代码编写主要包含三个步骤:ADC 校准、采样和均值滤波。

在编写代码前,需要理解以下几个核心问题:

  • 什么是 ADC?
  • 什么是 ADC 的基准电压?
  • ADC 的工作原理是什么?
  • 什么是 ADC 的分辨率?常见的分辨率有哪些?
  • 假设采用 12 位分辨率,基准电压为 3.3V,量化结果为 n 时的实际电压应该如何计算?

对于最后一个问题,12 位分辨率下量化结果为 n 时,实际电压的计算公式为:实际电压 = n × 3.3V / 4096。

5. 总结

本文介绍了 I2C 驱动中多字节寄存器地址的兼容写法、LM75 温度传感器的读取流程,以及 ARM 平台 FPU 的使能方法。这些代码片段可直接用于实际驱动开发,也可作为底层调试的参考。建议读者结合具体芯片手册,进一步验证寄存器地址长度和时序配置。

相关推荐
元器件BOM超人1 小时前
R7FA6M3AH3CFC#AA0 瑞萨RA6M3系列MCU解析
单片机
kkkkkkkkkk_Z2 小时前
新手自学嵌入式 | 学习日记:ARM内核启动代码、时钟系统(PLL/Prescaler/PFD)与IMX6ULL时钟配置
arm开发·学习
..Dauntless..2 小时前
【stm32】I2C(二)——Master和Slave之间的协议
stm32·单片机·嵌入式硬件
硅基手札2 小时前
【串口技术系列文档 04】UART协议深度解析
驱动开发·stm32·单片机·嵌入式硬件·mcu·计算机外设
sramdram2 小时前
预付费电能表BLE蓝牙MCU方案
单片机·嵌入式硬件·ble蓝牙·蓝牙mcu·蓝牙mcu方案
weixin_690654743 小时前
龙迅#LT7911EXS 高性价比IC,功能适用于HDMI/DP/TPYE-C转单PORT MIPICSI/DSI ,分辨率高达4K60HZ。
嵌入式硬件·音视频·信号处理
Zhang.Yi3 小时前
STM32-BKP和RTC
stm32·嵌入式硬件·实时音视频
Tronlong创龙3 小时前
IoTGateway可以让网关开发速度快一倍?
arm开发·嵌入式开发·硬件开发·工业控制·工业开发板
Yiran_G3 小时前
LoRa模块休眠后如何快速恢复通信?低功耗终端唤醒与数据交互实践
嵌入式硬件·物联网