怎么在S12X上使用XGATE协处理器

翻译的资料是公开的,在这里下载https://www.nxp.com/products/microcontrollers-and-processors/additional-processors-and-mcus/8-16-bit-mcus/16-bit-s12-and-s12x-mcus/ultra-reliable-s12xe-high-performance-automotive-and-industrial-microcontrollers:S12XE?tab=Documentation_Tab,我想应该不会有什么版权问题,如涉及版权问题,请联系我删除文章。另感谢NXP提供的学习资料。


How to Configure and Use the XGATE on S12X Devices

译者注:译者博客(http://blog.csdn.net/lin_strong),转载请保留这条。此为官方文档AN2685,仅供学习交流使用,请勿用于商业用途。

介绍

HCS12X微控制器家族相比HCS12家族有许多的增强;其中最重要的增强是XGATE协处理器。XGATE是一个独立于主CPU运行的可编程内核,它可以访问S12X的所有外设,使用的是RISC命令集。这篇应用笔记描述了怎么配置和使用XGATE。

这篇文档先讨论了双核系统中的数据一致性问题以及怎么通过软件来解决这个问题。

接着,在下一个部分,描述了XGATE的多种节能模式并比较了它们的性能和差异。

最后,提供了关于怎么设置和初始化XGATE模块的常用信息和建议。

数据一致性

数据一致性是指一种状态,在这组状态下的数据集合,对于任何想要访问它的进程看来,是一致和完整的。在实践中指的是,如果数据当前正在被修改的话,对数据的访问会被拒绝,所以其实内部并不是一致的。
比如:一个进程往一块内存区域中存入数据并递增一个计数变量,同时另一个进程从这个内存区域中取走数据比递减那个计数变量。典型的代码序列如下。

  1. 将变量读入一个内部处理器寄存器
  2. 递增或递减变量
  3. 把变量写回内存

在一个多任务系统中,中断可能会导致在读取变量之后立刻发生任务切换。这时,变量可能被另一个任务读取,减一,然后写回,这就会导致这个变量处于不一致状态。在单处理器系统中,典型地我们会通过在进入关键的代码序列之前禁用中断,运行完后使能中断以避免不一致。
当使用双处理器架构时,这种方法就没用了。严格来说,几乎所有外设都有这种问题。比如,SCI接收器会在接收到新的字节时填入接收缓冲;同时,CPU可能会读接收缓冲并得到不正确的数据。对于外设,大部分情况下,会使用特殊的标志位来表明是否接收到了数据或者是否可以传输数据了。
简而言之,只要有资源可能被两个以上的进程同时访问,就需要考虑这个问题。

XGATE和HCS12X CPU使用时分复用的方式来访问RAM。在一个S12X CPU周期中(25ns),如果S12X CPU没有访问RAM,XGATE可以以12.5ns周期访问两次RAM;如果S12X CPU访问了RAM的话,那就是XGATE访问一次,S12X CPU访问一次。这个良好的特性同时提高了XGATE和CPU的吞吐量,但是数据一致性的问题也更突出了。

这篇应用笔记描述了许多可以用来解决数据一致性问题的应用相关技术。

简单缓冲区方案

在两个处理器间交换数据同时还能避免数据一致性问题的一种简单的方法是使用一个缓存。两个处理器必须遵守一个底层协议:只有当另一个处理器标识缓冲区为空时,当前处理器才能向缓冲区内写入;只有另一个处理器标识缓冲区满时,当前处理器才能读缓冲区。

传输缓冲区

可以使用这个简单方案的典型应用是LIN传输和SPI主机。使用一个传输缓冲区的流程会是这样的:

  1. CPU填充缓冲区。
  2. CPU通知XGATE模块:可以传输数据啦!(这可以通过,比如,在外设内使能传输请求来实现)
  3. XGATE模块收到一条传输服务请求。
  4. XGATE模块发送数据到外设。
  5. 一完成,XGATE就禁用外设的传输请求。
  6. XGATE通知CPU(比如,通过中断)传输已经完成。
  7. 现在CPU又可以从步骤1开始了。

传输或接收缓冲区数据结构
图 1.传输或接收缓冲区数据结构

接收缓冲区

从外设中接收数据并存储其到一个缓冲区中的流程也十分相似。然而,要注意的是,在读取缓冲区之前不会再收到新的数据。这对于比如一个LIN节点或者SPI协议并不是问题,因为发送数据实际上是由一个传输进程控制的,即CPU本身控制的。如果接收进程与CPU活动是异步的,就必须使用不同的方法了,如下所示。对于接收进程,可以使用与传输同样的结构。

  1. XGATE为来自外设的一个 接收服务请求 服务。
  2. XGATE模块不断填充缓冲区直到填满预定数量的字节或者接收到了结束标志。
  3. XGATE通知CPU(比如,通过中断)传输已经完成。
  4. CPU从缓冲区中获取数据以进一步处理。

Guard技术

另一种不使用信号量的技术能够实现数据的复写。读取方必须在读取数据前置位一个“guard”,并在完成读序列后验证guard仍然被置位。对比于基于信号量的技术(见后面),这个技术的优点是:读取数据的进程不会被停止,也不需要阻塞中断;而缺点则是数据读取可能会需要重复进行。在一个进程开始填充一个缓冲区之前,变量guard会被递增。 在数据被完整地写入缓冲区后,再次递增变量guard。在 读进程 开始读缓冲区之前,它会创建当前guard的拷贝(OldG)。假设变量guard被初始化为0x0000,则奇数意味着正在进行写操作,所以 读进程 会轮询变量guard直到其变为偶数,这时它也开始读数据。在读取结束后,就对比下新旧guard变量。如果不相等,那么说明在读的过程中发生了写,因此读取的数据有问题。这样,就必须重新读。图2展示了过程。

这个技术不管是XGATE到S12X CPU还是反过来的方向都可以使用。

Guarding技术 流程图
图 2.Guarding技术 流程图

互斥量(互斥的RAM变量)或信号量

许多情况下,会通过使用互斥量(互斥的RAM变量)或者信号量来避免对同个资源的同时访问。然而,对于S12X CPU和XGATE模块,不可能使用RAM中的 读-修改-写 互斥量或信号量来宣称对任何资源的独占式访问,因为需要花费数个周期以读取一个RAM变量、测试其内容、将修改后的变量写回RAM。在读和写之间,变量是在CPU或者XGATE模块的内部寄存器内转变的。如果这期间另一个模块访问了变量,回写就会导致不一致。XGATE为解决这个问题专门提供了一个8个硬件信号量的集合。这信号量可以处于以下三种状态之一。

  1. 未使用,释放状态
  2. 赋值给S12X CPU进程
  3. 赋值给XGATE进程

在一般的多任务操作系统内使用信号量或类似的东西是可以保证任务能互斥地访问共享资源的。这是由于大部分CPU使用的是不可中断的“读-修改-写”指令,因此变量永远不会处于”转变中”这个状态。HCS12必须通过在 读-修改-写 序列间禁用和使能中断来模拟这个行为,但是HCS12X是有这个专用指令的(BTAS)。

在三种状态间的转换是这样进行的。

  1. 设置信号量。
    XGATE提供了一个专用的名为SSEM的指令,其以一个3bit立即数或者一个寄存器作为操作数。如果XGATE成功的锁上信号量,就会置位进位标志;如果信号量已经上锁了,就会清零进位标志。
    S12CPU经由XGSEM外设寄存器访问信号量,使用下面要说的C语言宏,按两步设置和检查信号量。
  2. 释放信号量。
    XGATE提供了一个专用的名为CSEM的指令,其以一个3bit立即数或者一个寄存器作为操作数以释放信号量。
    而S12CPU同样经由XGSEM外设寄存器访问信号量。

这个硬件解决了当同时提交了两个“get”命令时的优先级问题。“release”命令只应该由与信号量相关的进程提交。

#define SET_SEM(x) (XGATE.XGSEM = 0x0101 << (x))
#define TST_SEM(x) (XGATE.XGSEM & 0x0001 << (x))
#define REL_SEM(x) (XGATE.XGSEM = 0x0100 << (x))

        do {SET_SEM(2);            /* 试着设置信号量2 */
           } while (!TST_SEM(2));  /* 不在0..7之间 */
        /* 受保护的软件区域开始                         */
        /* 现在尽快做完要做的事情                       */
        /* 受保护的软件区域结束                         */
        REL_SEM(2);

XGATE汇编器中等价的代码
LOOP1:  SSEM    #2              ; 试着设置信号量2
        BCC     LOOP1           ; 如果上锁了就重试
        ....                    ; 受保护的软件区域开始
        CSEM    #2              ; 释放信号量

信号量的状态转换
图 3.信号量的状态转换

FIFO

一个用于解耦两个异步数据流的知名技术是先入先出(FIFO)数据结构。FIFO在有数据流需要接收的时候最为有用,因为字节(或整个消息)可能会被爆发式地传送,比CPU的处理速度都快,尽管全局来看,CPU的性能绝对可以来的及处理平均数据率了。通过使用FIFO,可以大大缓解CPU的压力。典型的例子是在几乎所有个人电脑上都可以找到的16550 UART,它使用16字节FIFO来缓存进入和出去的数据。

任何FIFO的主要问题是,起码需要使用一个bit来给填充FIFO的进程以及提取FIFO的进程使用。这个部分展示了实现一个FIFO的一种方式。基础的数据结构如图4所示。系数putidx展示的是新的对象要放入数据缓冲区的位置。系数getidx展示的是下一个要被读取的对象的位置。在这个例子中,使用了变量num,其代表了FIFO中的实体个数。当然,putidxgetidx的差别也可以用于计算FIFO中实体的个数,专门使用一个变量来存储FIFO中实体的个数是为了简化软件实现。变量num会由填充FIFO的进程递增,由提取FIFO的进程递减,因此它是由两个进程共享的资源。这个示例使用了互斥量来保护关键代码区域,如“互斥量(互斥的RAM变量)或信号量”中所述。

FIFO数据结构
图 4.FIFO数据结构

接收FIFO

下例代码展示了实体大小为一个字节、最多256个实体的FIFO。简单地修改下就能存放更多或者更复杂的实体了。XGATE存储一个字节到FIFO中,同时CPU从里头读取它。

使用XGATE把实体放入FIFO中

; Entry Conditions for this code sequence
; R1 points to data structure
; R2 to hardware (not shown here)
; R3 points to FIFOs data space
; R4 contains the byte to be stored in to the FIFO (also not shown how its loaded)
        LDL     R5,(R1,#num)    ; get number of entries in the FIFO
        LDL     R7,(R1,#size)
        CMP     R7,R5           ; check if there is space left
        BHI     SPACEOK         ; at least one item space left
; overflow error can be raised here
; further checks can be made here for high watermarks typically for XON/XOFF protocols
SPACEOK LDL     R6,(R1,#putidx) ; get the index where to put this in the buffer
        STB     R4,(R3,R6+)     ; Store byte to buffer an increment put index
        CMP     R6,R7           ; check on overflow
        BLO     LBL1
        CLR     R5              ; cyclical increment
LBL1    EQU     *
        STB     R6,(R1,#putidx) ; bump the next store index
; since the variable items is also updated by the reading side precautions must be
; taken to avoid a clash
; try to set a semaphore
SEMLOP  SSEM    #FIFOSEM        ; try to lock it
        BCC     SEMLOP
        LDB     R5,(R1,#num)    ; get value again in protected region
        INC     R5              ; since it might got changed in the mean time
        STB     R5,(R1,#num)    ; update length byte
        SIF                     ; signal to the HCS12 at least one byte is available
        CSEM    #FIFOSEM        ; unlock semaphore, leave protection
                                ; further activities like clearing request flag,...

使用S12 CPU从FIFO中提取字节

; Entry:
; Typically the FIFO might be drained in an interrupt handler
; X register points to the FIFO control structure
; Y points to FIFO Data space
        LDAA    num,X           ; get number of entries
        BNE     ONEPLUS         ; at least one item in FIFO
; underrun error, should never occur
; further comparisons can be made here for a low watermark if e.g. the transmission has
; been blocked using e.g. XON/XOFF protocol
ONEPLUS LDAB    getidx,X        ; where to pick data from
        LDAA    B,Y             ; get the byte item
; Content of Accumulator A must now be stored into the next level data structure
        INCB
        CMPB    size,X          ; check length
        BLO     LBL1
        CLRB                    ; cyclical increment
LBL1    STAB    getidx,X
; now we need to updated the number of items left in the FIFO
; since this can clash with the filling side it must be locked using the
; same semaphore as above
SEMLOP  MOVW    #$0101<<FIFOSEM,XGSEM              ; try to lock semaphore
        BRCLR   XGSEM+1,#1<<FIFOSEM,SEMLOP         ; repeat if not successful
        DEC     num,X                              ; decrement number of entries left
        BNE     LEFTOVERS                          ; leave the interrupt asserted
        MOVB    #CLAERIF,XGIF                      ; clear interrupt in case last entry removed
        MOVW    #$0100<<FIFOSEM,XGSEM
unlock  semaphore
        RTS

节能模式

S12X的特点是有许多结合XGATE I/O处理器的节能方式。

为了减少能耗,当XGATE等待新线程启动的时候,XGATE的所有时钟都被关闭。因此,并不需要,如S12 CPU上的,STOP指令。

从整个系统的角度来看,表1中所示的四种节能模式可以被分为两大类:STOP 和 PSEUDO-STOP一类;WAIT 和 RUN一类。

STOP模式和PSEUDO-STOP模式会尽可能的降低能耗,它们会关闭除了少数支持模块外的所有内部时钟。

而在WAIT模式和RUN模式下,大部分的内部时钟分配网(时钟树)依然活跃。

表 1.节能模式

模块STOPPSEUDO-STOPWAITRUN
电压调节器降能耗降能耗全性能全性能
晶体振荡器停止降振幅全驱动全驱动
VCO停止如果时钟监控器探测到故障并且使能了内部时钟模式的话就会运行如果PLLON和PLLWAI=0或者时钟监控器探测到了故障并且使能了内部时钟模式的话就会运行如果PLLON或者时钟监控器探测到了故障并且使能了内部时钟模式的话就会运行
PLL停止停止如果PLLON并且PLLWAI=0的话就会运行如果PLLON的话就会运行
API (内部RC振荡器)如果APIFE=1就会运行如果APIFE=1就会运行如果APIFE=1就会运行如果APIFE=1就会运行
S12CPU无时钟无时钟无时钟时钟控制
XGATE无时钟无时钟时钟控制的激活如果激活的话由时钟控制
RTI停止如果PRE=1的话就会运行如果RTIWAI=0的话就会运行
COP停止如果PCE=1的话就会运行如果COPWAI=0的话就会运行
其他外设模块停止停止大部分模块有个lock Module_Stops_In_Wait 标志位时钟控制(如果确定使能的话)

STOP

如果CPU执行了STOP指令,并且XGATE并不在执行一个线程的话,系统会进入STOP模式。

唤醒性能

为了从STOP模式唤醒系统,可以使用特定引脚上的外部输入信号。在S12XDP512上,引脚是XIRQ和IRQ;端口H、J和P上的引脚;以及与SCI或CAN模块相关的引脚,如果使能了对应模块的话。唤醒的是S12 CPU还是XGATE取决于中断模块中RQST位的设置。

9S12XDP512 还有一个纯粹的内部API(异步周期性终端),精度取决于温度和电压,在±5%。

在唤醒事件中,用户有许多节能选项。

  1. 通过使用最小VCO时钟(总线率典型为1.5MHz)来驱动内部时钟系统以立即启动。在许多情况下,只会执行那些时序性要求不高的任务(比如,读取开关输入)。其中大部分,都不需要进一步的行动,系统直接回到STOP模式。在激活事件中,晶体振荡器可以使用软件控制启动。一旦振荡器启动了,SCMIF(内部时钟模式中断标志位)就被置位,然后内部时钟系统就切换到了晶体振荡器的输出。然后软件就可以打开PLL以得到更高的时钟频率。
  2. 立即启动晶体振荡器并在继续之前等待振荡器稳定(SCMIF置位)。典型的晶体振荡器稳定时间时5-10ms,取决于晶体的频率和质量。
注意:
如果XGATE是由一个外部事件唤醒的,它可以通过触发CPU中断来唤醒处于STOP模式下的CPU。

PSEUDO-STOP

PSEUDO-STOP模式与STOP模式很相似,但是它会保持外部晶体振荡器和时钟监控器电路处于活跃状态,当然前提是你使能了它们。还可以选择让RTI和COP看门狗定时器继续计数。

唤醒性能

PSEUDO-STOP模式下的唤醒性能和STOP模式很相似,除了多了通过RTI(实时中断)唤醒。不像API,这个RTI可以达到准确的时间基准,因为它衍生自晶体振荡器。

如果出现了问题,可以使用COP重置系统。

WAIT

在WAIT模式下,电压调节器处于全性能模式,大部分内部时钟分配网保持活跃状态。这相比于STOP和PSEUDO-STOP模式会大大增加能耗。大部分外设默认都有一个Module_Stops_In_Wait位,这个位使得模块的时钟能在WAIT模式下关闭。

唤醒性能

这个模式下的唤醒性能和PSEUDO-STOP模式一样,但是大部分外设模块都可以触发XGATE或者S12的中断以唤醒系统。

CWAI位使得CPU和BDM的时钟能被关闭,因此也阻止了WAIT模式下的调试链接。

RUN

在RUN模式下,所有使能的模块,包括内核,都是时钟控制的。

通用设置向导

这个部分简短地解释了怎么合适地配置和初始化HCS12X系统。它给出了一些小贴士,只要你遵循这些小贴士,是可以按照需求定制的。

初始化栈指针

首先,应该禁止中断:应该加载CLI(只是为了保险)和初始栈指针。在S12X上,大部分情况下,0x4000 (RAM的顶+1) 就够了。如果有中断向量基寄存器的话,也可以在这里初始化它。如果使用了XIRQ来处理紧急的不可屏蔽的中断,也可以在这里使能它。如果XIRQ没那么重要,它应该与其他中断一起被使能,见“最后步骤”。

初始化I/O端口

然后,应该初始化通用I/O端口(GPIO),以降低输出引脚上出错的可能。

初始化RAM变量

如果需要进行存储器测试,比如基础RAM测试,或者FLASH或EEPROM校验和测试,应该在RAM变量被初始化前进行。

初始化RAM变量。这常常是在进入main例程之前,在“C”的startup例程中完成的。(注意,ANSI-C要求所有静态变量都被初始化)这里要注意一些事情:

  1. 这里不包括外设的寄存器,因为一些是只能写一次的,否则设置的顺序就十分重要。
  2. 如果在main例程内进行了RAM测试,可能会使变量的初始化出问题。
  3. 如果可能的话,代码不应该依赖于自动的初始化。
  4. 如果无法避免自动的初始化,应该在栈初始化之后进行它。

大部分编译器供应商会开源startup例程源代码,以使得用户能够按照需求进行修改。

下载XGATE代码

如果应用程序使用了XGATE,XGATE代码应该被下载进RAM。可以在下载完成后启用RAM保护,这样就可以避免复写XGATE代码或者S12 RAM变量了。之后还应该设置XGATE向量基寄存器。

中断模块

通过为每个向量写入中断优先级来设置中断模块(如果和重置后默认的不同的话)。如果服务请求被路由到XGATE模块,这些中断的RQST位也必须被置位。另外,建议初始化中断向量基寄存器,即使使用的就是重置值(0xFF)。

外设模块

初始化所有的外设模块并设置它们的本地中断使能位,如果需要的话。

最后步骤

初始化和使用看门狗。

注意:
一些设备允许在重置序列之外使能看门狗。这种情况下,必须小心地确保在执行上述序列时不会触发看门狗。
  1. 如果需要的话,使能STOP指令。
  2. 如果需要的话,使能XIRQ。
  3. 使能中断(CLI如果XGATE使用了的话;XGE=1)。
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值