1.概述
TPU(Time Processing Unit)是一个灵活的时间控制模块,可以用于实时处理输入识别、输出控制等应用。主要包含以下特征内容:
两套AFCB总线分别用于Host(CM7内核)和Engine(RISCV内核)来访问各自的外设
总共有32个通道channel,每个channel都有自己的一对输入输出信号,每个信号都能产生自己对应的触发输出信号和DMA请求信号
有两个24bit位宽的全局时基(TCR1 和 TCR2)用于channel的同步
支持特殊的EAC模式用于角度计数,可以自动记录角度数值(匀速模式 加速度模式 减速度模式)
支持Host(CM7内核)单独操作或者设置成Flexcore模式(Host & Engine)下工作
支持HSR & HSA功能,用于CM7和RISCV之间进行信息交流和中断通知
2.系统架构介绍(基于flexcore模式)
由上图可以看到,框架中有两套外设总线(AFCB)都可以访问TPU外设;RISCV核可以访问的前提是使能了Flexcore模式;在Flexcore模式下,CM7和RISCV都可以通过系统总线访问flash和sram,同时RISCV端有自己的16KB Ccode RAM和16KB Data RAM;除了FC7240芯片本身固有的Mailbox机制外,新增了HSR&HSA机制来进行核间通信,我们会在下面的章节来介绍这种通信机制;同时可以看到有两个调试接口,实际开发中旗芯微支持使用opnocd调试接口来调试RISCV端,接下来我们介绍flexcore模式的使能,也就是TPU外设使用前的准备工作需要做哪些。
工作流程框图
2.1 使能flexcore模式
第一步就是需要将芯片配成成flexcore模式,这里我们需要做两步工作,首先需要在NVR里面配置使能位,然后需要在NVR里面配置flexcore执行程序的地址,这里的程序地址目的是后面boot流程需要将该地址的code copy到flexcore侧的code ram上。
如上图所示,将bit0 - bit3配成非0x5和0xf的数据,即代表使能了flexcore模式,SEC寄存器的值都是通过NVR在上电之后加载过来的,所以我们一开始修改NVR的值也能达到效果,所以这里我们使用旗芯微软件团队开发的NvrConfig工具对该区域的数据进行修改,使用工具前我们需要将该工具存放在FCIDE目录下面,因为放在外面有时候不一定能找到JLINK的设备,如下图所示:
打开NVR配置工具,可以先读取芯片的默认NVR区域数据,如下图所示:
首先使能FlexcoreEnable写成0,CodeAddr写成0x404000,这里的0x404000是真实地址的高29位,所以实际代表的是0x404000 << 2 = 0x1010000;修改后的数据如下图所示:
2.2 切换芯片启动模式从ROM开始
如图所示,将BOOTROM参数改成0x01,芯片上电后从ROM代码执行
2.3 如何烧录NVR的配置信息到芯片内部
方式一 直接通过配置工具的Gnerate Hex生成hex文件,然后点击Load Hex将hex文件烧录到芯片
方式二 通过配置工具的Gnerate Hex生成hex文件,然后通过jlink.exe连接连接芯片,连接之后最好halt住CPU;通过loadfile指令将hex文件烧录到芯片里面。
2.4 Host侧和Engine侧的工程配置
2.4.1 Host侧配置
首先需要在host侧工程的链接文件里面预留Engine侧工程编出来的工程大小的flash,如下图所示,可以看到host侧的代码不会链接到FLEXCORE_FLASH定义的区域里面来,为Engine的工程预留了空间;同时可以看到这里FLEXCORE_FLASH这里定义的起始地址是0x1010000,和2.1章节里面我们配置的NVR区域里面flexcoreaddr的地址是一一对应的,这里需要读者注意,如果需要更改flexcoreaddr的地址,那么这里也请自行更改。
Host侧工程需要将自己和Engine侧的工程都下载到flash里面去,这里需要用到FCIDE的一个组合下载功能,可以看到这里flexcore端的hex工程名和真实的名称多了一个packed名词,这里是一个细节,我们会在Engine侧的配置来讲这个。通过以下配置就可以把两个工程下载到flash里面去。
2.4.2 Enigne侧配置
首先打开Engine侧工程的链接文件,我们可以看到这里的中断向量表被分配在了0x20000的位置上,这个位置是flexcore侧的指令RAM地址,芯片上电执行ROM代码之后会把flexcore的代码从flash位置搬到RAM,说的也就是这里的RAM位置;所以如果想修改向量表地址的话,需要注意地址的范围需要在RAM里面
还记得2.4.1章节预留的一个伏笔吗,按照目前链接文件编译出来的hex文件的起始地址是0x20000;但是存放到flash地址应该是host侧和NVR区域配置的0x1010000,这里就需要在Engine侧的编译配置里面增加一个指令,如下图所示;这里生成的是名为TpuPwmFlexCorePacked.hex的文件,在host侧下载的时候用的是该文件
当然,上述提到的是flash下载的方式,如果是调试的话可以直接在RAM里面调试,通过debug串口选择openocd模式,具体配置方式如下图所示
具体的调试接线如下图所示,左边的是JLINK负责调试CM7,上面的调试器是旗芯微自己开发的dap调试器:
3. 初始化配置
3.1 Host侧的初始化配置
Host侧需要做两个操作,第一个是使能子系统,也就是激活flexcore;第二个就是打开TPU的时钟;
代码如下所示:
系统时钟框图对应如下图所示:
3.2 Engine侧的初始化配置
首先需要确认flexcore模式是否使能,使能了才能去操作TPU外设
volatile uint32_t *p = (volatile uint32_t *)0x40014094;
while (((*p) & 0x10) != 0x10);
这里的0x40014094就是SEC寄存器里面flexcore是否使能的状态位
然后需要把向量表的地址给到SS_CTRL寄存器
SystemSetIsrTableAddrWithBoot(0x20000u);
也就是把0x20000这个链接文件里面配置的地址给到SS_CTRL寄存器,低8位会忽略
最后需要在Engine侧打开TPU的时钟,如下图所示
SystemClockEnableSpecific(1u);
4 TPU功能简介
4.1 通道介绍
TPU总共有32个channel,每个通道都是双动作单元,具有输入检测,匹配检测和捕获的功能,具体框图如下所示
4.1.1 输入检测

4.1.2 输出引脚控制

4.1.3 使能匹配和设定匹配值


4.1.4 全局时基选择

4.1.5 通道模式
在单跳变模式下,TDLA产生服务请求
在双跳变模式下,TDLB产生服务请求,TDLA不产生
阻塞模式下,先发生的匹配事件会阻塞后续的匹配事件
在非阻塞模式下,匹配之间不会相互阻塞
mrlB产生服务请求,mrlA不产生
Both Match
只有当两个匹配事件都发生了才会产生服务请求
Ordered (Match)
匹配必须按照顺序进行,先MRLA然后再MRLB。在MRLA发生之前,MRLB一直处于禁止状态
Either Match
匹配识别可以不按顺序执行
Single Match
只有动作单元A的匹配使能。动作单元B的匹配被禁止





4.2 HSR & HSA
4.2.1 Host侧的设置
TPU_H_HWA_SetChHSA(pTPUH, u8channel, true);
TPU_H_HWA_SetChHSRIdx(pTPUH, u8channel, u8HSRIdx);
TPU_H_HWA_SetChHSRISR(pTPUH, u8channel, (bool)true);
发送HSR服务请求:
首先通过SR的状态位读取当前CAHNNEL有没有得到HSA的应答,如果没有应答信号,则会发送HSR的请求到Engine侧
if (TPU_GetHSA(TPU_CAPTURE_CHANNEL) != TPU_CAPTURE_START)
{
TPU_SendHSR(TPU_CAPTURE_CHANNEL);
}
得到HSA应答后进入中断:
清除HSA的标志位并且响应响应的回调函数
static inline void TPU_Event_IRQHandler(uint8_t u8MinChannel, uint8_t u8MaxChannel)
{
TPU_H_Type *const pTpuH = TPU_H_BASE_PTRS;
uint8_t u8Channel;
for (u8Channel = (uint8_t)u8MinChannel; u8Channel < ((uint8_t)u8MaxChannel + 1u); u8Channel++)
{
if (TPU_H_HWA_GetChEventTrigISRStatus(pTpuH, u8Channel) == true)
{
if (s_TpuEventNotify[u8Channel] != NULL)
{
s_TpuEventNotify[u8Channel]();
}
}
if (TPU_H_HWA_GetChHSAReqStatus(pTpuH, u8Channel) == true)
{
TPU_H_HWA_ClearChHSA(pTpuH, u8Channel);
s_TpuHSANotify[u8Channel]();
}
}
}
4.2.2 Engine侧的设置
TPU_E_HWA_EnableChEventInt(pTPUE, u8channel, (bool)true);
TPU_E_HWA_EnableSrvReq(pTPUE, u8channel, (bool)true);
服务请求接收中断:
当有HSR服务请求过来的时候会进入HSR的中断服务函数,这时候需要发送HSA信号给到主机
void Bsp_Tpu_HSRCallback(void)
{
if (TPU_GetHSR(TPU_PWM_CHANNEL) == TPU_PWM_START)
{
TPU_SendHSA(TPU_PWM_CHANNEL, TPU_PWM_START);
}
}
事件触发中断:
当有EVENT事件产生的时候(参考channel mode章节)会进入事件中断
4.3 角度模式
4.3.1 角度的概念
常用EAC角度计数模式
EAC示意图,有三个通道做齿信号识别
TPR指一个齿信号分成多少个tick
TRR指多少个bus clock增加一个tick,真正的两个齿之间的是bus cycle*TPR*TRR
Trr和TPR设置好后tick就会不停的加,加到设定的tick数后看齿信号是否到来,没来halt住,提前来了就快速得加。
这样tick加到预设值的时候就会有中断到来,在中断中就可以调节下一个齿信号的tick周期,让计数跟得上发动机
4.3.2 曲轴介绍
曲轴信号如下图所示
EAC中设定一个齿信号TCR2增加TPR个angle tick。实际应用中发动机会加减速,TCR2的角度计数需要跟上发动机的速度,因此通过修改TRR的值来使TCR2跟上发动机的速度
TPR寄存器如下图所示
TRR寄存器如下图所示
一个齿分为多少个tick,通过TPR寄存器的tick段实现,最多1024个tick,这个tick设定后就不会再改变
匀速的时候每个齿增加的tick数一样,但加减速tick会比齿提前或延迟到来,可以通过改变TRR的值来让计数跟上发动机的速度。
比如减速的时候,齿是延迟到来的,那就增大TRR,加速的时候齿提前到来,那就减小TRR
4.3.3 匀速 减速 加速EAC的处理
1.匀速:预测的齿信号到来,tick数刚好达到预设值
2.减速:tick数达到预设值,但是齿信号没到,此时angle tick counter处于halt mode
3.加速:齿信号到来,但是tick数没达到预设值,此时angle tick counter处于high rate mode
4.3.4 缺齿和最后齿
1.缺齿:检测到缺齿,EAC会自动加两个齿周期
2.最后齿:可做重置TCR2的操作