- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是SDK2.0里事务型中断处理函数(DriverIRQHandler)的重定向注意事项.
最近有一个 i.MXRT 客户在使用官方 SDK 外设驱动里的中断处理函数时遇到了代码重定向失效问题,客户用得是一个 XIP Flash 工程,想把程序中断向量表以及相关外设的驱动函数全部重定向到 RAM 中以提高系统性能,但实测发现中断发生时,仍然存在 Flash 访问行为。这本来不是个大问题,因为 SDK 在设计时已经从中断处理函数命名上就做了明确提醒,但是很多客户并没有意识到,今天痞子衡就来聊聊这个话题:
恩智浦 SDK 软件包里的外设驱动(HAL级)正常来说提供的 API 都是面对外设配置(init、deinit、set_feature、get_status) 的通用功能函数。此外对于通信接口类外设,一般还会有阻塞式(blocking)的数据传输功能函数。以 LPUART 外设为例,其数据传输有以下四个 API:
// 写入(发送)一个 Byte 数据(需在 FIFO 没满的情况下)
static inline void LPUART_WriteByte(LPUART_Type *base, uint8_t data);
// 读取(接收)一个 Byte 数据(需在 FIFO 非空的情况下)
static inline uint8_t LPUART_ReadByte(LPUART_Type *base);
// 阻塞式写入(发送)多个 Byte 数据
status_t LPUART_WriteBlocking(LPUART_Type *base, const uint8_t *data, size_t length);
// 阻塞式读取(接收)多个 Byte 数据
status_t LPUART_ReadBlocking(LPUART_Type *base, uint8_t *data, size_t length);
阻塞式数据传输 API 本质上就是独占 CPU 时间进行查询式传输,API 一旦调用,必须等到数据收发结束才会返回,这样会导致 CPU 利用率不高,其一般不利用外设中断。为了结合外设中断进行高效数据传输(non-blocking),SDK2.0 中额外提供了如下事务型相关函数(仅列出了部分):
// 创建事务型数据传输句柄
void LPUART_TransferCreateHandle(LPUART_Type *base,
lpuart_handle_t *handle,
lpuart_transfer_callback_t callback,
void *userData);
// 非阻塞式写入(发送)多个 Byte 数据
status_t LPUART_TransferSendNonBlocking(LPUART_Type *base, lpuart_handle_t *handle, lpuart_transfer_t *xfer)
// 非阻塞式读取(接收)多个 Byte 数据
status_t LPUART_TransferReceiveNonBlocking(LPUART_Type *base,
lpuart_handle_t *handle,
lpuart_transfer_t *xfer,
size_t *receivedBytes);
// 事务型数据传输中断处理函数
void LPUART_TransferHandleIRQ(LPUART_Type *base, void *irqHandle);
非阻塞式数据传输 API 显然就是结合了外设中断来做数据传输,API 调用后填入一些配置后会立刻返回,没有过多消耗 CPU 时间,等外设中断发生时再进一步处理数据。这类型 API 常常和应用设计紧相关,所以也称为事务型函数(transactional API).
SDK 里并不是所有外设驱动里包含事务性函数,这类 API 常出现在传输接口类外设上。对于 i.MXRT 来说,支持此类 API 的外设有:DMA、LPUART、LPSPI、LPI2C、SAI、FLEXIO、FLEXSPI、USDHC、ENET、CAN、MIPI_DSI/CSI、SPDIF、ASRC、PDM 等.
这里继续以 LPUART 外设来具体介绍。如下 i.MXRT1011 SDK 里提供的 8 个 LPUART 例程中有 5 个是基于事务型驱动函数的,我们就以 interrupt_transfer 的 IAR 工程为例.
打开这个 lpuart_interrupt_transfer 工程,找到芯片启动文件 startup_MIMXRT1011.s,在里面我们能找到 PUBWEAK 型的 LPUART1_IRQHandler() 函数定义,这个是大家比较常见的中断处理函数名,其代码里面就是简单跳转到另一个 PUBWEAK 型 LPUART1_DriverIRQHandler 函数.
在 fsl_lpuart.c/.h 驱动里,找不到 LPUART1_IRQHandler() 定义,但是有 LPUART1_DriverIRQHandler() 定义。这意味着 SDK 驱动设计时,将默认的 LPUART1_IRQHandler() 函数重写的权利留给了用户,而重新设计了 LPUART1_DriverIRQHandler() 函数来存放事务性中断处理代码,从而避免因用户自己重写中断处理函数时发生函数名重定义而去修改 fsl_lpuart.c 驱动文件的麻烦.
现在我们尝试重定向 lpuart_interrupt_transfer 工程,可以按照 《IAR下代码重定向的三种方法》 一文里的方法,将 fsl_lpuart.o 和 lpuart_interrupt_transfer.o 两个目标文件都重定向到 RAM 中,并且在 main 里加上拷贝 0x60002000 处开始的 1KB 中断向量表数据到 SRAM 中并且将 SCB->VTOR 指向对应 SRAM 的代码(这个过程可以参考 《Cortex-M中断向量表重定向方法》 一文).
上述改动完成之后,编译工程查看 map 文件,我们发现所有的相关代码都已经被链接在了 SRAM 里,但是 LPUART1_IRQHandler() 仍然在 Flash 里,很显然这种情况下中断发生时,仍然会有 Flash 访问行为(暂不考虑 L1-Cache 生效的情况),这就是客户遇到的问题.
那么如何解决这个问题?其实 SDK 已经为你考虑到了,在 fsl_common_arm.c 文件中定义了 InstallIRQHandler() 函数(仅在 ENABLE_RAM_VECTOR_TABLE 宏存在的情况下生效),查看其源码,发现作用有两个:1、如果 SCB->VTOR 指向得不是 SRAM,那么将中断向量表从 Flash 拷贝到 SRAM 中,并且重置 VTOR;2、根据传入参数修改 SRAM 中的某个中断向量值.
因此 lpuart_interrupt_transfer 例程中,如果需要彻底重定向中断处理函数,记得在 main 函数里的 LPUART_TransferCreateHandle() 函数调用之后加上如下一句代码,其作用除了重定向中断向量表之外,还将表里的 LPUART1 中断向量从 LPUART1_IRQHandler() 更换为了 LPUART1_DriverIRQHandler(),这样代码重定向就彻底了.
InstallIRQHandler(LPUART1_IRQn, (uint32_t)LPUART1_DriverIRQHandler);
此时再编译工程下载运行,发现出现 hardfault,这是怎么回事?别急,因为 InstallIRQHandler() 函数里需要用到链接文件 MIMXRT1011xxxxx_flexspi_nor.icf 里定义的三个 Symbol,工程选项 Linker/Configuration file symbol 里必须添加 __ram_vector_table__=1 设置,那些 Symbol 才会真正产生重定向作用.
define symbol m_interrupts_start = 0x60002000;
define symbol m_interrupts_ram_start = 0x20000000;
define symbol __ram_vector_table_size__ = isdefinedsymbol(__ram_vector_table__) ? 0x00000400 : 0;
define exported symbol __VECTOR_TABLE = m_interrupts_start;
define exported symbol __VECTOR_RAM = isdefinedsymbol(__ram_vector_table__) ? m_interrupts_ram_start : m_interrupts_start;
define exported symbol __RAM_VECTOR_TABLE_SIZE = __ram_vector_table_size__;
至此,SDK2.0里事务型中断处理函数(DriverIRQHandler)的重定向注意事项痞子衡便介绍完毕了,掌声在哪里~~~ 。
文章会同时发布到我的 博客园主页、CSDN主页、知乎主页、微信公众号 平台上.
微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦.
最后此篇关于痞子衡嵌入式:关于恩智浦SDK2.0里事务型中断处理函数(DriverIRQHandler)的重定向注意事项的文章就讲到这里了,如果你想了解更多关于痞子衡嵌入式:关于恩智浦SDK2.0里事务型中断处理函数(DriverIRQHandler)的重定向注意事项的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!