首页 > 其他分享 >痞子衡嵌入式:关于恩智浦SDK2.0里事务型中断处理函数(DriverIRQHandler)的重定向注意事项

痞子衡嵌入式:关于恩智浦SDK2.0里事务型中断处理函数(DriverIRQHandler)的重定向注意事项

时间:2024-11-12 22:19:20浏览次数:1  
标签:__ SDK2.0 lpuart LPUART 恩智浦 LPUART1 处理函数 外设


  大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是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 宏存在的情况下生效),查看其源码,发现作用有两个:一、如果 SCB->VTOR 指向得不是 SRAM,那么将中断向量表从 Flash 拷贝到 SRAM 中,并且重置 VTOR;二、根据传入参数修改 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,lpuart,LPUART,恩智浦,LPUART1,处理函数,外设
From: https://www.cnblogs.com/henjay724/p/18542788

相关文章

  • M68LC302CAF20VCT,MMC2107CFCPU33,MC9S12UF32PUM,S9S12DJ12F1MPVEMCF52235CVM60MAC7121MA
    NXPSemiconductors公司的产品和技术还广泛应用于安全和身份验证领域,包括智能卡、支付系统、身份识别和生物识别技术。此外,该公司还在电源管理、射频技术和传感器领域拥有丰富的经验和专业知识。恩智浦的产品不仅提供高性能和创新的解决方案,还致力于保证产品的安全性。NXPSem......
  • MySQL零基础入门教程-5 单行处理函数、分组函数、mysql关键字执行顺序,基础+实战
    教程来源:B站视频BV1Vy4y1z7EX001-数据库概述_哔哩哔哩_bilibili我听课整理的课程的完整笔记,供大家学习交流下载:夸克网盘分享本文内容为完整笔记的第五篇17、单行数据处理函数P30-36&分组函数17.1、数据处理函数又被称为单行处理函数单行处理函数的特点:一个输入对应一个输出。和单行......
  • 信号的机制——信号处理函数的注册
    在Linux操作系统中,为了响应各种各样的事件,也是定义了非常多的信号。我们可以通过kill-l命令,查看所有的信号。#kill-l1)SIGHUP2)SIGINT3)SIGQUIT4)SIGILL5)SIGTRAP6)SIGABRT7)SIGBUS8)SIGFPE9)SIGKILL10)......
  • matlab处理函数5
    1.数字数字图像和数字数字图像数据缺省情况下,MATLAB将数字数字图像中的数据存储为双精度类型(double),64位浮点数,所需存储量很大;MATLAB还支持另一种类型无符号整型(uint8),即数字数字图像矩阵中每个数据占用1个字节。  在使用MATLAB工具箱时,一定要注意函数所要求的参数类......
  • Linux Makefile文件名处理函数知识详解
    GNUmake提供了一系列对文件名进行各种操作的函数:文件名替换、加前缀、去目录等。1.1dir函数:取路径名的目录dir函数用来从一个路径名中截取目录的部分。$(dirNAMES…)dir函数会从NAMES文件名序列中,取出各个文件路径名中的目录部分并返回.PHONY:allLIST=/home/wit/ban......
  • MySQL零基础入门教程-5 单行处理函数、分组函数、mysql关键字执行顺序,基础+实战
     教程来源:B站视频BV1Vy4y1z7EX001-数据库概述_哔哩哔哩_bilibili我听课整理的课程的完整笔记,供大家学习交流下载:夸克网盘分享本文内容为完整笔记的第五篇17、单行数据处理函数P30-36&分组函数17.1、数据处理函数又被称为单行处理函数单行处理函数的特点:一个输入对应一个......
  • 分享几个简单的Pandas数据处理函数
    文末赠免费精品编程资料~~大家好,今天给大家简单分享几个好用的Pandas数据处理函数。id,category,sub_category,sales,year,var1,var2,age,score,status,quantity1,A,B,100,2019,50,70,35,85,active,1002,B,C,120,2020,60,80,28,90,inactive,2003,A,C,110,2020,70,90,32,75......
  • 35. 字符串处理函数
    1.strcpy()#include<string.h>char*strcpy(char*dest,constchar*src);功能:把src所指向的字符串复制到dest所指向的空间中,'\0’也会拷贝过去参数:dest:目的字符串首地址src:源字符首地址返回值:成功:返回dest字符串的首地址失败:NULL注意:如果参数dest所指的内存空间不够大,可能......
  • 禁用时钟中断并不直接保证中断处理函数能够不受时钟干扰即时执行
    实际上,关闭系统定时器(或更准确地说是禁用时钟中断)并不直接保证中断处理函数能够“不受时钟干扰即时执行”。相反,这种做法可能会带来一系列问题,包括影响系统的任务调度、时间管理、以及可能破坏其他依赖于时钟中断的功能。在Linux系统中,时钟中断(也称为节拍器中断或tick中断)扮演着......
  • C/C++语言基础--字符串(包括字符串与字符数组、字符串与指针、字符串处理函数等),代码
    本专栏目的更新C/C++的基础语法,包括C++的一些新特性前言无论什么语言,字符串都是最重要、最基础的数据类型,他对二进制有很好的对应关系在C语言中没有提供专门的处理字符串的类型,但是我们可以通过字符数组、开辟内存地址来处理字符串本文将从字符串与字符数组的关系、字符......