Autosar CAN协议栈移植

背景

项目使用的芯片是AM62A7,MCU是它的协处理器(单核 Arm Cortex-R5F)。对于AM62这款芯片vector的回复是之前没有做过Canbedded,且同意开发新芯片的CBD的可能性是比较小的,因此需要将Autosar的CAN协议栈移植到项目上来。

AM62x是德州仪器(Texas Instruments)推出的一款高性能嵌入式处理器系列。

准备工作

MCAL下载:不涉及。如果需要,参考:CCS使用笔记 | 仙人

协议栈移植

往工程添加需要的文件

基于SIP包的Demo做修改,删掉多余的无关文件,剩下的就是需要参与编译的文件了。

  • 删除无关的canoe工程等调试文件

  • Appl 删掉 ti 和 RteAnalyzer 文件夹

  • Appl\GenData 删掉无关模块文件,以及启动链接等相关文件。

  • 在Configurator里面把与CAN协议栈无关的模块删掉,增加缺少的模块,如CanTrcv模块。然后,重新生成代码。
    如何删除模块,可以参考下图:

  • 添加需要的BSW模块的静态代码到项目工程里

关于OS模块

项目跑FreeRTOS,不用AUTOSAR OS模块(为了省钱)。

所以,生成代码后把OS相关文件去掉。其中需要注意的是,为了访问OS API,RTE包含了Os.h头文件。所以 Appl\GenData 下面生成的这几个文件要保留,否则编译会报错:

同样,OS静态代码要添加头文件如下。

除此之外,还会缺少一些OS相关的接口。可以建一个Usr_Common文件夹,放一些自定义内容,其中Os_User.c文件是为了适配OS相关的接口,需要自己实现,需要实现的内容如下:

  1. Hardware Loop Check,具体实现:

    • 只开关CAN中断

    • 使用systick实现Hardware Loop check

  2. 增加临界区保护机制

    • 任务侧:通过调用 SuspendAllInterrupts禁用CAN中断并挂起调度器,确保自身独占访问共享变量。没有采用互斥信号量,因为会存在上下文切换的开销,实测对报文周期影响比较大。

    • 中断侧:CAN中断处理程序仅在中断未被禁用时执行,而任务的临界区会禁用中断,故二者不会冲突访问。

代码要点:

  • 嵌套处理:使用 os_user_suspend_nesting_counter跟踪嵌套,确保只有最外层调用实际开关中断。

  • 调度器挂起:通过 vTaskSuspendAllxTaskResumeAll防止多任务竞争静态变量。

  • 中断状态保存与恢复: HwiP_disableIntHwiP_restoreInt确保仅CAN中断受控,不影响其他中断。

说明:

  • 中断处理中的访问:CAN中断执行时任务未处于临界区(因中断未被禁用),故无需额外保护。

  • 调度器挂起的作用:防止任务切换,但不影响中断。结合禁用CAN中断,确保单任务访问且不被中断打断。

协议栈初始化

根据TR文档的描述,EcuM的初始化分为两部分:一部分是在操作系统启动运行之前进行的初始化,第二部分在操作系统启动后执行。

  • 第一部分将由函数 EcuM_Init执行。这个函数执行DriverInitLists的“EcuMDriverInitListZero”和“EcuMDriverInitListOne”,进行基本驱动初始化。然后,EcuM_Init 通过调用 StartOS 函数来启动OS。

  • 初始化序列的第二部分将由 EcuM_StartupTwo 执行。在操作系统启动后立即调用此函数一次。

何时调用这两个函数?

ECU上电之后程序开始执行:启动文件->BootLoader->Application,进入“main”函数,也就是我们熟知的用户代码程序。这里主要分析EcuM管理的上电到程序运行过程。

如下图所示,C Init Code一般是应用程序的main函数,即 EcuM_Init在应用程序的 main 函数被调用,EcuM将控制ECU的启动流程,EcuM调用StartOS,让Os完成Task的激活。

实际实现如下:

前面提到了, EcuM_Init并不能完成MCU所有的初始化动作,在StartPreOS Sequence阶段主要完成DET模块(最先完成初始化,便于其它模块可以上报错误)以及一些硬件外设的初始化,如Port、Watchdog等。

在StartPostOS Sequence阶段 EcuM_StartupTwo将完成SchM(Os),BSW模块的初始化,其中各个模块的初始化(Can_InitCanIf_Init等)在BswM中完成。程序所需的所有外设、模块初始化之后,启动Scheduler定时,即周期性的执行BSW/SWCs任务,至此App程序得以运行。

实际实现如下,在操作系统启动后立即调用此函数一次:

协议栈运行

创建一个FreeRTOS的任务,运行协议栈相关主函数,参照 Rte.cDefault_BSW_Async_Task

1
2
3
4
5
6
7
8
9
10
void can_thread(void *args)
{
for(;;)
{
CanTp_MainFunction();
Dcm_MainFunction();
...
...
}
}

问题记录

  1. mcu跑飞

    最终定位到是执行到 Can_EccInit挂的。原因是Demo工程用的是MCAN2,实际用的是MCAN0,查看datasheet这款芯片R5F核,最多到MCAN1,按照电路图修改Autosar里面的配置为MCAN0就好了。

  2. DET:BswM_MainFunction函数,errorid是1

    这个DET代表BswM未初始化,实际上是有调用初始化的。出现这个DET是因为没有及时请求通信,Ecu State状态机走到了shutdown状态,执行了BswM反初始化,但是实际上ECU还在正常运行。因为,该项目只有CAN协议栈是用的Autosar,Power模块不使用Autosar机制,所以出现该问题。

中断

R5F的中断是通过 HwiP_irq_handler统一处理的, HwiP_irq_handler调用vApplicationIRQHandlerConst,然后根据 HwiP_construct注册的中断号和处理函数,执行对应的中断服务函数。

对于上层应用来说,调用 HwiP_construct注册需要的中断就行了。

问题记录

  1. 使用中断收发报文的话, GetElapsedValue函数的传入传出参数需要赋值,比如*ElapsedValue = 0;,否则是随机数的话接收会有问题,因为传入的参数在外面没有初始化。代码包的问题,vector的正式包解决了这个问题。

  2. 基于ti给的demo将报文收发改为中断方式,测试的时候发现,如果关掉canoe再重新打开,ECU发不出报文,mcu没有任何打印,已知不是进入DET。也就是说进入noack状态,再恢复后,报文不会恢复发送。

    原因在于,ti的demo使能了所有can相关的中断,但是autosar生成的中断服务函数,只处理了部分中断。如果触发了autosar接口没有处理的中断,那么中断标志会清不掉,导致其他中断也处理不了。所以应该基于CanInterrupt_30_Mcan的处理情况,在调用MCAN_enableIntr时,只使能部分中断。

NM

Passive Autosar Nm设计 | 仙人

Linker

  1. linker.cmd增加自定义段。示例如下
1
2
3
4
5
6
7
8
9
10
11
12
13
/* This is used to store memory segments related to the AUTOSAR. */
GROUP
{
.text.Autosar: {} palign(8)
.rodata.Autosar: {} palign(8)
} > MSRAM

/* This is used to store memory segments related to the TI SDK library files.
*/
GROUP
{
.text.ti_lib: {"freertos.am62ax.r5f.ti-arm-clang.release.lib"<*.obj>(.text)} align(8)
} > MSRAM
  1. 修改MemMap配置。示例如下
1
2
#pragma clang section text = ".text.Autosar"
#pragma clang section text = "" // Restore default

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2021-2026 wrd
  • 访问人数: | 浏览次数:

      请我喝杯咖啡吧~

      支付宝
      微信