ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RH850/F1K CSIH Direct Access Mode例程解析

RH850/F1K CSIH Direct Access Mode例程解析 简介瑞萨 RH850/F1K 是面向汽车电子应用的 32 位微控制器片内集成多种串行通信接口。压缩包围绕其 CSIH 模块的直通访问模式编写了完整的串行外设接口数据收发例程适合车规级嵌入式开发工程师以及希望入门瑞萨微控制器的单片机学习者。包内共 78 个文件压缩后仅 1.27MB除 C 源码与头文件外还包含编译器工程文件、链接脚本、编译输出文件以及可执行映像源代码中覆盖时钟控制器、复位控制器、外部中断和 FIFO 等关键模块的初始化与中断处理逻辑。配合附带的文档开发者可以快速对照寄存器配置流程理解直通访问模式下的数据收发机制并在此基础上进行移植或二次开发。目前已有 1025 人学习或下载对正在评估或使用该系列芯片串行外设接口功能的开发者具有较好的参考价值。1. RH850/F1K 的 CSIH例程名叫 FIFO跑的却是 Direct Access Mode拆开这个压缩包的第一印象很容易产生误判5_CSIH_FIFO.c这个文件名让人默认例程工作在 CSIH 的 FIFO 模式下实际顺着代码和摘要走一遍才能确认这套工程跑的是 Direct Access Mode。R7F701587 属于瑞萨 RH850/F1K 汽车级 32 位 MCUSPI 相关外设分 CSIH 与 CSIG 两类CSIH 带 FIFO、支持硬件仲裁和多通道片选适合 ECU 内部传感器、存储芯片的同步通信CSIG 则是精简版同步串行接口。Direct Access Mode 下 CPU 直接读写 CSIH 的数据寄存器完成收发不依赖 FIFO 队列深度适合报文短、频率不高的场景。对正在用 GHS 编译器做 RH850/F1K 开发的工程师这套例程真正的价值是把时钟、复位、中断、引脚和 CSIH 初始化全部串在一个可编译工程里能少翻很多手册。2. GHS 工程骨架从 example.gpj 到 dr7f701587.ld2.1 文件清单里藏着整条开发链路打开压缩包看到的不是孤零零一个.c文件而是一整套 Green Hills 工程。example.gpj、debug.gpj、source.gpj、device.gpj是不同层级的 GHS 工程描述文件dr7f701587.ld是链接脚本dr7f701587_startup.850是复位后执行的第一段汇编芯片寄存器定义集中在dr7f701587.h、dr7f701587.dvf.h、icu_feret.h、r_typedefs.h。要改这个工程先分清这些文件各自管什么文件作用example.gpj / debug.gpjGHS 工程顶层构建入口debug 变体带调试信息用于下载和单步source.gpj / device.gpj源文件分组和设备库引用里面定义了每个.c的所属组dr7f701587_startup.850V800 架构汇编启动代码负责栈指针初始化和进入 C 运行时dr7f701587.ld链接脚本定义 Flash/RAM 的加载区域和运行区域dr7f701587.h / dr7f701587.dvf.hRVF 驱动文件生成的寄存器定义是操作 CSIH、ICU 的基础icu_feret.h中断控制器单元 ICU 的相关定义中断配置要看它connection.conGHS Multi 调试器的目标连接配置换板子后第一处要改的文件example.out / example.hex / example.dla构建产物out用于调试器加载hex用于烧写这套文件组织方式很典型.gpj是工程入口device.gpj负责设备头文件路径.ld和.850一起决定了程序能不能跑起来。国产替代项目或二次开发时通常只改source.gpj增加自己的模块.ld保持原样就能直接编译通过。2.2 入口逻辑dr7f701587_startup.850 先于 main 做了三件事RH850/F1K 复位后从固定地址取复位向量在 GHS 里对应VECT段中的_Reset全局符号。启动汇编的职责可以精简成三步设置栈指针、调用运行时初始化、跳转 main。类似下面的结构在 V800 系列编译产物中很常见.section .text, ax .global _Reset _Reset: ldr sp, __stacktop /* 栈顶地址来自链接脚本符号 */ bl __init /* 拷贝 .data清零 .bss */ jal main loop: bra loop其中__stacktop不是魔法数字它定义在dr7f701587.ld里。如果链接脚本把 RAM 区域改小了__stacktop会跟着变程序一上电就踩栈表现为 PC 到处飞。.850的文件名后缀来自 GHS 的 V800 工具链不要按 ARM 的.s习惯去改扩展名编译器根据扩展名选择汇编器。不要把_Reset理解成普通函数它没有返回地址。GHS Multi 调试器里如果单步不到 main先看 PC 是否停在__init再确认.data段有没有被正确搬运。启动代码里的.section名必须与dr7f701587.ld中的执行区域对应否则 link 时会出现 multiple definition 或者 section 未分配的错误。2.3 链接脚本 dr7f701587.ld 的结构化读法GHS 的链接脚本和 GCC 的ld语法不一样核心是load_region和execute_region两层概念。load_region描述烧写到哪、execute_region描述运行在哪两者可以不同典型场景是代码从 Flash 加载到 RAM 执行。下面是一段风格相近的示意load_region FLASH, 0x00000000 { execute_region ROM { *(.text) *(.rodata) *(.cdata) } } load_region RAM, 0xFE000000 { execute_region RAM_DATA { *(.data) *(.ldata) *(.bss) } }这里的地址是占位示意不要直接照抄到 R7F701587 工程里具体 Flash 和 RAM 基地址要以设备手册或者原工程dr7f701587.ld为准。GHS 里小数据段.sdata、.zbss有独立访问方式如果编译选项改了-short-data或数据模型配置链接脚本也要同步否则会出现relocation truncated之类的问题。排查手段是把生成的example.map打开对照execute_region的起止地址看段归属这个动作在第五章还会展开。3. 5_CSIH_FIFO.c 的 Direct Access Mode 收发实现3.1 动 CSIH 之前先确认时钟和复位状态CSIH 外设挂在系统外设时钟域上R7F701587 复位后默认跑低速内部时钟如果不经过1_ClockController.c的 PLL 配置CSIH 的采样时钟可能达不到目标 SPI 波特率。例程里1_ClockController.c负责 PLL 和系统分频2_ClockMonitor.c做时钟监控3_ResetController.c管理复位源。常见做法是先把系统时钟从复位默认的内部振荡器切到外部晶振再通过 PLL 倍频到目标频率最后使能外设模块时钟void clock_init(void) { CGC_PLLCTL.BIT.PLLON 1; /* 打开 PLL */ while (!CGC_PLLSTS.BIT.PLLOCK); /* 等待 PLL 锁定 */ CGC_SYSCK.BYTE 0x01; /* 系统时钟切换到 PLL */ CSC_CSIH0.BYTE | 0x01; /* 打开 CSIH0 模块时钟 */ }代码里的CGC_PLLCTL、CGC_PLLSTS、CGC_SYSCK是 RH850/F1K 时钟控制寄存器的常见命名具体位名和偏移以 GHS 头文件dr7f701587.h为准。PLLON是 PLL 使能位PLLOCK是 PLL 锁定状态位轮询锁定是为了避免系统时钟源尚未稳定就切过去CSC_CSIH0对应 CSIH0 的时钟门控不同型号这个寄存器名可能不同可能是MSTPC之类的模块停止控制寄存器。注意不要在主频没稳定时就操作 CSIHSPI 波特率是由外设时钟分频得到的时钟源抖动会导致首个字节位错误。太早配置还会遇到2_ClockMonitor.c触发复位——当 PLL 未锁定而系统时钟选择位已经指向 PLL监控电路会把整个芯片拉回复位状态。调试时如果程序反复从_Reset重新执行先怀疑这个时序。3.2 引脚复用PMC 和 PIPC 决定 SCK 能不能出来R7F701587 的 GPIO 引脚默认是通用 IO必须通过外设模式控制寄存器切换成 CSIH 功能。GHS 工程里附带io_macros_v2.h它提供统一的寄存器读写宏避免直接对 volatile 指针赋值时被编译器优化掉。典型配置如下IO_WR(PM4, (IO_RD(PM4) ~0x0F)); /* P4.0-P4.3 设为输出模式 */ IO_WR(PMC4, (IO_RD(PMC4) | 0x0F)); /* 切换到外设功能 */ IO_WR(PIPC4, (IO_RD(PIPC4) | 0x0F)); /* 使能引脚输入输出控制 */这里的P4、PMC4、PIPC4是示例CSIH0 实际占用哪个端口要看 R7F701587 的引脚分配表不同的封装F1K 系列常见 LQFP 和 BGA对应端口也不同。PM是端口模式寄存器控制输入还是输出PMC是外设模式控制把引脚从 GPIO 切换到 CSIH/CSIG 等片上外设PIPC是外设输入输出控制决定该引脚在指定外设功能下是输入还是输出方向。容易踩的坑是只配了PMC忘了PIPC结果 SCK 引脚始终没有时钟输出但寄存器状态位显示 CSIH 已经启动。用示波器量不到波形时先回来看这两个寄存器的复位值和当前值。3.3 Direct Access Mode 的寄存器配置和数据交换5_CSIH_FIFO.c文件名里有 FIFO但实际工作在 Direct Access Mode这一点要从配置代码确认。Direct Access Mode 的本质是 CPU 直接读写 CSIH 的数据寄存器每次收发由状态位驱动不配置 FIFO 深度和触发阈值。以 CSIH0 为例一套完整的初始化函数大致长这样void csih0_init_direct(void) { CSIH0.CSP0.BYTE 0x00; /* 协议控制清错误标志、选中从设备 */ CSIH0.CSM0.BYTE 0x21; /* 模式控制主模式SPI 协议 */ CSIH0.CSM0.BIT.CPOL 0; /* 时钟极性空闲低电平 */ CSIH0.CSM0.BIT.CPHA 1; /* 时钟相位第二边沿采样 */ CSIH0.CSD0.BYTE 0x30; /* 片选建立/保持时间 */ CSIH0.CSIC0.BIT.TIE 1; /* 发送完成中断使能 */ CSIH0.CSIC0.BIT.RIE 1; /* 接收完成中断使能 */ } uint8_t csih0_xfer(uint8_t tx) { while (!CSIH0.CSST0.BIT.TXE); /* 等待发送缓冲空 */ CSIH0.CSIT0.BYTE tx; /* 写入发送数据 */ while (!CSIH0.CSST0.BIT.RXE); /* 等待接收缓冲满 */ return CSIH0.CSIR0.BYTE; /* 读回接收数据 */ }上面的寄存器名和位名是 RH850 CSIH 模块的常见命名R7F701587 的具体位定义以dr7f701587.h展开为准。CSP0负责片选极性和通道选择CSM0是模式控制里面带有 SPI/SCI 协议选择、主从模式、CPOL/CPHA 位CSD0用于调整片选建立时间和保持时间某些从设备要求 CS 先拉低一段时间再给 SCK这个寄存器就要配合外部设备的时序手册计算。CSIC0是中断控制TIE和RIE分别打开发送完成和接收完成中断如果不想用中断就把它们清零改用CSST0状态位轮询。CSST0状态寄存器里的TXE表示发送缓冲空RXE表示接收缓冲满。Direct Access Mode 下发送和接收是同步的SPI 是全双工协议主机发出一个字节的同时会收到一个字节所以写CSIT0之前要等TXE置位读CSIR0前要等RXE置位。注意读CSIR0这个动作本身会清除接收完成标志不要在读完后又去手动清标志否则可能把刚产生的新数据标志误清掉。3.4 main 函数里的初始化顺序把这几个模块串起来后main的调用顺序直接影响排查难度int main(void) { clock_init(); /* 1_ClockController.cPLL 与时钟切换 */ reset_init(); /* 3_ResetController.c复位和看门狗处理 */ intpn_init(); /* 4_INTPn.c外部中断引脚配置 */ csih0_init_direct(); /* 5_CSIH_FIFO.cCSIH0 初始化 */ uint8_t resp csih0_xfer(0x55); return 0; }初始化顺序不能乱尤其是时钟必须最先完成。如果先初始化 CSIH 再切 PLL外设拿到的时钟源是内部低速振荡器波特率会差一个量级逻辑分析仪上看到的波形完全对不上配置值。reset_init的作用是确认复位源并处理看门狗防止调试时看门狗超时把系统打断。4. 中断链路INTPn、ICU 与 GHS 的 IRQ 写法4.1 中断源编号从哪里来CSIH 的发送完成、接收完成、错误事件要到达 CPU先要经过 ICU中断控制单元。例程里dr7f701587_irq.h就是 GHS 根据 R7F701587 型号生成的中断源头文件里面以宏或枚举形式定义了类似CSIH0_TI、CSIH0_RI的中断源编号icu_feret.h则提供了 ICU 寄存器的访问接口。通常的中断初始化分两步把外设中断源通过 ICU 选择到 CPU 中断请求线再设置优先级和使能位ICU.IRQCSEL.BIT.SEL 0; /* 选择中断源分组 */ ICU.IRQPR0.BIT.PR 5; /* 设置优先级数值范围见手册 */ ICU.IRQEN0.BIT.EN 1; /* 使能中断请求 */SEL选择的是外设中断源到 CPU 中断引脚的映射PR是优先级数值越大还是越小代表越高要看具体 ICU 设计EN是总使能。这些寄存器名字以icu_feret.h里的实际定义为准不同子系列差异明显。实际开发中有个容易忽略的细节ICU 配置好之后CSIH 内部还有个中断使能位CSIC0.TIE/RIE两处都要打开。只开 CSIH 的中断位ICU 侧没有放行中断请求到不了 CPU调试时表现为标志位一直置位但从不进中断函数。4.2 GHS 编译器的中断函数写法GHS 的 V800 编译器支持#pragma interrupt声明中断函数部分版本也提供__interrupt属性。直接在普通函数前加这个声明编译器会为它生成中断返回指令。CSIH 接收中断的处理函数可以写成#pragma interrupt csih0_rx_handler void csih0_rx_handler(void) { rx_byte CSIH0.CSIR0.BYTE; /* 读接收数据寄存器 */ rx_done 1; /* 置标志主循环里处理 */ }中断函数里尽量不要做复杂业务逻辑读走数据、置标志就够了。读取CSIR0的动作在多数硬件实现上会清除接收完成标志所以不要在函数末尾额外写清标志代码。如果要清错误中断标志必须确认是对哪个寄存器写什么值错误标志的清除方式在 CSIH 模块里通常和接收完成标志不同贸然写 0 可能误清其他状态。4.3 INTPn 外部中断从设备的握手信号很多外设从设备在准备就绪时会给主机一个中断或 GPIO 高电平。4_INTPn.c的作用就是把这样的引脚配置成边沿触发的中断源。R7F701587 的 INTPn 引脚支持上升沿、下降沿或双沿触发配置代码类似IO_WR(PMx, (IO_RD(PMx) | 0x01)); /* 对应引脚设为输入 */ ICU.INTPCTLx.BIT.ES 1; /* 上升沿触发 */ ICU.INTPCTLx.BIT.IEN 1; /* 使能该外部中断 */PMx是目标端口模式寄存器置 1 表示输入ES是沿选择位IEN使能外部中断。INTPn 和 CSIH 的典型配合是握手式通信主机检测到从设备拉高 READY 引脚后再发起 CSIH 传输。如果从设备的 READY 信号维持时间很短边缘触发比电平触发可靠不会因为主循环调度延迟而漏掉状态变化。4.4 轮询和中断的选择Direct Access Mode 既可以用状态位轮询也可以挂在中断上。两者取舍不是性能越高越好而是要看代码的确定性要求方式优点限制适用场景轮询 TXE/RXE逻辑简单延迟确定代码容易跟踪传输期间 CPU 被占用函数内一次性收发几个字节收发中断主循环不被阻塞需要环形缓冲处理中断嵌套传感器周期性上报主循环有实时任务DMA 搬运CPU 开销最低需要额外配置 DMA 描述符本工程未启用适合大批量 Flash 编程本例程命名为 Direct Access Mode显然设计意图是让收发路径一眼到底便于理解 CSIH 的工作机制。工程做产品化升级时如果要从轮询改成中断寄存器配置只需要打开CSIC0的TIE/RIE并在 ICU 侧使能对应中断源数据通路部分不需要改。这一层解耦是 CSIH 模块设计得比较清晰的地方。5. 链接脚本、调试连接与 Direct Access Mode 的三个坑5.1 从 example.map 确认链接结果编译产物example.map里可以直接验证启动代码和链接脚本是否匹配。重点看RESET段和__stacktop的位置grep -n _Reset\|__stacktop\|\.text example.map正常情况下_Reset所在段应该落在dr7f701587.ld定义的 Flash 区域起始位置__stacktop应该指向 RAM 区顶部。如果_Reset被分配到了错误地址复位后 PC 直接跑飞这是启动类问题里最常见的一种。5.2 用 connection.con 连接 Multi 调试器换板调试第一件事是检查connection.con它描述调试器类型、目标芯片和下载方式。加载example.out而不是hex调试这样可以在 Memory 窗口直接查看 CSIH 寄存器和全局变量。跑起来后单步clock_init观察CGC_PLLSTS的锁定标志确认 PLL 稳定后再执行到csih0_xfer处检查CSST0的TXE/RXE是否按预期变化。5.3 三个真实会遇到的坑第一个坑来自文件名。5_CSIH_FIFO.c里的 FIFO 是 CSIH 外设单元的名字不代表代码启用了 FIFO 模式。如果在 Direct Access Mode 下去配置 FIFO 深度和触发阈值状态位的行为会对不上误以为外设坏了。第二个坑是时钟监控。2_ClockMonitor.c在 PLL 锁定过程中如果检测到时钟不稳定会拉低复位脚现象是程序反复重启。调试时先关掉时钟监控或延长锁定等待时间。第三个坑是片选时序。只调CPOL/CPHA不一定够CSD0里的建立时间不满足从设备要求时第二个字节开始就会出现错位。判断方法是用逻辑分析仪抓 CS 和 SCK 的间隔对照从设备数据手册里的时序参数表逐个核对。最后补一个排查技巧在 GHS Multi 的 Memory 窗口直接观察CSST0的TXE/RXE位能最快区分是外设时钟没起振还是软件状态机没走到位。本文还有配套的精品资源点击获取
返回列表