Infineon-AURIX_TC3xx学习篇 -Clock System

1. 概述

时钟系统是一条由不同的模块组成的链,这些模块允许这个时钟链有不同的功能部件
这些组件包括:

  • Basic clock generation (Clock Source) 基础时钟生成
  • Clock speed up-scaling (PLLs) 锁相环
  • Clock distribution (CCU) 负责时钟分配
  • Individual clock configuration (Peripherals) 外围设备的单独时钟
    在这里插入图片描述

时钟模块的主要任务: 时钟生成 时钟倍频 时钟分配
除了纯粹的时钟生成选项外,还集成了几个支持功能,以支持简单方便的控制。
以下各小节将从左到右解释时钟树。在初始也建议使用此流程进行初始配置。当然,专家用户可以按个别顺序执行配置。

2. Clocking System Registers Overview

下表列出了时钟系统专用的所有 SCU 寄存器。这些寄存器在寄存器文件中以 SCU_ 前缀。
Table 276 Register Overview - CCU (ascending Offset Address)

Short NameLong NameOffset Address
OSCCONOSC Control Register0010H
SYSPLLSTATSystem PLL Status Register0014H
SYSPLLCON0System PLL Configuration 0 Register0018H
SYSPLLCON1System PLL Configuration 1 Register001CH
SYSPLLCON2System PLL Configuration 2 Register0020H
PERPLLSTATPeripheral PLL Status Register0024H
PERPLLCON0Peripheral PLL Configuration 0 Register0028H
PERPLLCON1Peripheral PLL Configuration 1 Register002CH
CCUCON0CCU Clock Control Register 00030H
CCUCON1CCU Clock Control Register 10034H
FDRFractional Divider Register0038H
EXTCONExternal Clock Control Register003CH
CCUCON2CCU Clock Control Register 20040H
CCUCON3CCU Clock Control Register 30044H
CCUCON4CCU Clock Control Register 40048H
CCUCON5CCU Clock Control Register 5004CH
CCUCON6CCU Clock Control Register 60080H
CCUCON7CCU Clock Control Register 70084H
CCUCON8CCU Clock Control Register 80088H
CCUCON9CCU Clock Control Register 9008CH
CCUCON10CCU Clock Control Register 100090H
CCUCON11CCU Clock Control Register 110094H

2.1 Safety Flip-Flops

安全触发器是一种特殊的触发器,它实现了一种硬件机制,能够检测可能导致单次事件中断(位翻转)的单次事件效应。可能导致单次事件中断(位翻转)的影响。
使用安全触发器实现的配置和控制寄存器包括 安全触发器的配置和控制寄存器包括

  • OSCCON
  • SYSPLLCON0
  • SYSPLLCON1
  • SYSPLLCON2
  • PERPLLCON0
  • PERPLLCON1
  • CCUCON0
  • CCUCON1
  • CCUCON2
  • CCUCON3
  • CCUCON4
  • CCUCON5
  • CCUCON6
  • CCUCON7
  • CCUCON8
  • CCUCON9
  • CCUCON10
  • CCUCON11

3. 时钟源(Clock Source):

有几个可用的时钟源,取决于时钟源的配置;这些时钟源要么是整个设备的时钟源,要么是主要或次要的时钟源,要么是专用模块的时钟源。
请注意,系统内部可以并行使用多个时钟源,但每个外围设备的主要功能在任何时候都只与一个时钟源相关。

3.1 Oscillator Circuit (OSC)振荡器电路

该振荡电路是皮尔斯振荡器,可与外部晶体/陶瓷谐振器或外部稳定时钟源配合使用。
电路由一个反相放大器组成,XTAL1 作为输入,XTAL2 作为输出,并带有一个集成反馈电阻器。

3.1.1 External Input Clock Mode

使用外部时钟信号时,必须将其连接到 XTAL1。XTAL2 保持开路(未连接)。
在这里插入图片描述
如果不使用外部晶体/陶瓷谐振器和旁路振荡器而直接提供时钟信号,在正常模式下使用时,输入频率必须等于或大于 PLL 的 DCO 输入频率(该值列于Data Sheet中)。

3.1.2 External Crystal / Ceramic Resonator Mode 外部晶体/陶瓷谐振器模式

下图显示了两种工作模式的推荐外部电路: 带外部晶体/陶瓷 和 不带外部元件的谐振器模式。
在这里插入图片描述

3.1.3 Configuration of the Oscillator

在使用外部晶体/陶瓷谐振器作为时钟源之前,始终需要对振荡器进行配置。
上电复位后,振荡器将被禁用,需要按照本节所述进行配置。在任何其他复位期间和复位后,振荡器不受影响,并按先前配置运行,因此无需重新配置。
对于这种start up配置,支持两种选项:

  • 通过 SSW 配置
  • 执行 SSW 后进行配置
3.1.3.1 Configuration via SSW

当 FLASH0_PROCOND.OSCCFG 位被设置时,该选项将被启用。
在这种模式下,寄存器 OSCCON 的控制信息由 SSW 从 FLASH0_PROCOND 加载。
因此,需要将所需信息存储在偏移量为 00H 的 UCB_DFlash 中。
在这种模式下,OSCCON.MODE、OSCCON.GAIN、OSCCON.HYSEN、OSCCON.HYSCTL、OSCCON.AMPCTL 和 OSCCON.CAPxEN 以及位 OSCCON.APREN 均可控制。

如果已禁用振荡器,则必须通过设置 OSCCON.MODE = 00B 位来启用振荡器。
增益设置应根据所连接的外部晶体/谐振器的需要和所使用的电容器配置进行调整。

如果使用集成电容,则可通过 OSCCON.CAPxEN 位启用。如果OSCCON[27:24]≠0000B,则也需要设置 OSCCON.APREN 位。
请注意,使用集成电容时必须始终启用振幅调节。
启用振幅调节功能无需更改 OSCCON.GAINSEL,该位应保持在 11B

3.1.3.2 Configuration after SSW

在 SSW 中进行可选配置后,还可以在应用软件中配置振荡器。
可以通过寄存器 OSCCON 进行配置。寄存器本身受安全ENDINIT保护。
一般来说,配置规则与上一节所述相同。

3.1.3.3 Oscillator Watchdog

通过配置 SYSPLLCON0.INSEL = 01B 可以选择振荡器时钟作为看门狗的时钟源。
结合系统 PLL,可实现监控功能。该功能用于检测外部晶体/陶瓷谐振器的严重故障。
系统可检测到时钟输入丢失或输入频率过高(在高次谐波上运行)。
振荡器看门狗监控来自 OSC 的输入时钟频率 fOSC。稳定和确定的输入频率是运行的强制性要求。
因此,每次系统复位后都会自动选择该模式。
预期输入频率 fOSC 通过位域 OSCCON.OSCVAL 进行选择。
OSC_WDT 会检查频率是否过低或过高。
fOSC = OSCCON.OSCVAL - 1 + 16 MHz
在配置 OSC_WDT 功能之前,应禁用所有 SMU 振荡器看门狗警报响应选项,以避免发生意外的 SMU 警报。之后可以更改 OSCCON.OSCVAL 的值。然后,应通过设置 OSCCON.OSCRES 复位 OSC_WDT。这就要求使用新配置开始监控 OSC_WDT。
当设置 OSCCON.PLLLV 和/或 OSCCON.PLLHV 之后得到预期的监测结果时,输入频率将在预期范围内。由于设置 OSCCON.OSCRES 会清除 OSCCON.PLLLV和 OSCCON.PLLHV 这两个状态标志位都将被置位。因此,在再次启用 SMU 警报响应之前,应清除这两个标志。
如果只设置了 OSCCON.OSCRES 位,而未修改 OSCCON.OSCVAL 位, SMU 警报也应使用禁用-清除-启用序列。
如果 SMU 检测到振荡器看门狗警报,则必须执行与 PLL 失锁事件相同的恢复程序。
Note:
通过寄存器 SYSPLLCON0.INSEL = 01B 将 PLL 输入时钟 fOSC_i 设置为 fOSC0 时,就会主要使用振荡器看门狗。
如果通过寄存器 SYSPLLCON0.INSEL = 10B 将 fOSC_i 设置为SYSCLK ,则用户应将 SYSCLK 频率限制在与使用晶体时相同的范围内,或者禁用 SMU 中的看门狗警报。
当通过 SYSPLLCON0.INSEL = 00B 将fOSC_i 的输入设置为备用时钟时,也需要禁用看门狗警报。
数据手册中列出了通过指定 GPIO 输入引脚驱动 SYSCLK 时的可用晶体频率范围和允许频率范围。

3.2 Back-up Clock

备用时钟源,提供稳定可靠的时钟源,可用作系统时钟。
与外部晶体或陶瓷谐振器相比,它的精度较低。
备用时钟不能启用或禁用,也不能进行其他控制,以免影响其正常工作。
因此,在选择备用时钟源时,没有控制位可用(可以用的设置就是:CCUCON0.CLKSEL = 00B 作为时钟分配的时钟源,SYSPLLCON0.INSEL = 00B 作为两个 PLL 的时钟源)。

4. Clock Speed Up-Scaling (PLLs)

  • TC3XX支持16-40HZ的外部晶振或陶瓷振荡器,作为MCU的时钟来源
  • CPU最大允许频率为300MHz,是外部晶振频率的十倍以上
  • 芯片内部有两个PLL锁相环,一个系统PLL,一个外设PLL
  • PLL的功能是将较低的外部时钟信号转化为较高的内部时钟信号来最大化的利用芯片性能
  • Back UP Clock是内部产生的100MHZ的备用时钟
  • 除了纯时钟生成选项,有几个支持功能旨在使控制更容易,更方便
  • 一般来说,CPU的运行速度大约比晶体的速度高10倍; 因此,2 相锁相环 (PLL) 是提供用于提高时钟频率。
  • PLL的作用是转换低频率外部时钟信号转换成高加快内部时钟的速度,以最大化性能
  • AURIXTM 的 PLL 还具有故障安全功能,可以检测退化外部时钟的逻辑、异常频率等行为、外部时钟的偏差或全部损耗

4.1 System PLL

在这里插入图片描述
The input frequency fOSC is divided down by a factor P, multiplied by a factor N, and then divided down by a factor K2.
The output frequency is given by
fPLL0 = (N * fOSC) / (P * K2)

4.2 Peripheral PLL

在这里插入图片描述
The input frequency fOSC is divided down by a factor P, multiplied by a factor N, and then divided down by a factor K2 / K3.
The output frequency is given by:

  • fPLL1 = (N * fOSC) / (P * K2)
  • fPLL2 = (N * fOSC) / (P * K3 * 1,6) if DIVBY = 0
  • or fPLL2 = (N * fOSC) / (P * K3 * 2) if DIVBY = 1
  • fHSCT = fDCO / 2

外设PLL操作需要 fOSC 的输入时钟频率。因此,建议通过检查 OSCCON.PLLLV 来检查和监控输入频率 fOSC 是否可用。为了更好地监控,还可以通过 OSCCON.PLLHV 监控上限频率。
系统工作频率由四个分频器的值控制: P、N 和 K2 / K3。修改两个分频器 P 和 N 会直接影响 DCO 频率,并可能导致锁定状态丢失。修改 K2 / K3 分频器不会影响锁定状态,但仍会改变外设 PLL 输出频率 fPLL1/2。
note: 通过改变 K2 / K3 分频器的值来改变系统运行频率会直接影响设备的功耗。因此必须谨慎操作。
当必须修改外设 PLL 输出频率时,应遵循以下顺序:
应禁用 SMU 的锁定丢失报警功能。
外设 PLL 的配置可以独立于System PLL 进行。在配置外设 PLL 时,所连接的模块要么在不同的时钟源上运行,要么不运行。
P 分频器和 N 分频器应按以下方式选择:

  • 选择 P 和 N 时,应使 fDCO 处于允许值的较低区域。这将略微降低功耗,但会略微增加抖动。
  • 选择 P 和 N 时,应使 fDCO 处于允许值的上限区域。这将导致功耗略有增加,但抖动略有减少。

在第一次配置更新 P、N 和 K2 / K3 分频器后,应检查锁定状态指示(PERPLLSTAT.LOCK = 1)。
外设 PLL 锁定后,即可切换到外围 PLL。应清除外设 PLL 失锁事件的 SMU 状态标志,然后重新启用。
现在只需更改 K2 / K3-Dividers 即可配置外设 PLL 输出目标频率。
分多级改变 K2 / K3 分频器,以避免频率变化过大,从而导致功耗变化过大。
根据 K2 / K3-Dividers 的值,可以选择时钟的周期时间。
这可能会对外部通信接口的操作产生影响。
Notes

  1. 建议在配置分频器的新值后重置锁定检测(PERPLLCON0.RESLD = 1),以获得确定的锁定检查时间。

  2. 由于从 PLL 到备份时钟的紧急切换会同时对两个 PLL 激活,因此强烈建议只有在系统 PLL 也已设置并锁定到目标频率的情况下,才将外围时钟切换到外围 PLL。
    如果执行顺序设置,系统 PLL 在设置过程中可能会发生锁定丢失事件,从而导致外设时钟也切换到备用时钟。

  3. 建议在 DCO 频率设置完成且外设 PLL 已锁定后,再应用外设 PLL K2/K3-Divider 步进。
    外围 PLL 锁定后再应用外围 PLL K2/K3-Divider 步进。此外,在再次更改相关的 PERPLLCON1.KxDIV 值之前,用户必须检查 PERPLLSTAT.KxRDY = 1。
    当 PERPLLSTAT.KxRDY = 0 时(x = 2、3),PERPLLCON1.KxDIV 寄存器锁定,而之前的写入仍在进行中。

5. Clock Distribution (CCU)

通过时钟系统的前两个部分,定义了系统运行所依赖的所有根时钟。接下来,需要单独调整这些根时钟的频率(分频),并将其分配给所有 MCU 模块、CPU 和blocks。这样做的重点是优化性能和功耗。
在时钟分配方面,系统被划分为多个子时钟域,在这些子时钟域中可以单独配置时钟速度。每个子时钟域还有内部接口的限制。从时钟角度来看,每个子时钟域定义了一个逻辑单元。
时钟分配通过时钟控制单元(CCU)完成。
CCU 接收由两个 PLL(fPLL0 和 fPLL1/2)、备用时钟 fBack 和 fOSC0 生成的时钟。这些时钟或直接转发,或被分频,以提供子时钟域。
在这里插入图片描述
对于大多数时钟,都提供了一个线性分频器,以根据应用要求调整时钟频率。分频器由寄存器 CCUCONy 中的 XXXDIV 位控制。
时钟系统的配置非常灵活。这使得频率变化可适应应用所定义的特定电流限制。

对于 GTM,CCU 中有一个固定分频器和一个可编程分频器,提供的时钟仅取决于系统 PLL 或备用时钟。

  • fGTM = fSOURCEGTM / GTMDIV
  • fSOURCEGTM = fSPB *2 if GTMDIV = 0001B else fSOURCEGTM = fSOURCE0

对于以太网 RAM, ERAY, EBU,ADC, HSPDM, HSCT等模块,CCU 中有一个固定分频器,从系统 PLL 或备用时钟中提供恒定时钟。

  • fRAM = fSPB *2
  • fERAY = fsource1 / 2
  • fEBU = fsource1
  • fADC = fsource1
  • fHSPDM_ 160 = fsource1
  • fHSPDM_ 320 = fsrc1
  • fHSCT = fDCO / 2

Debug block 还有一个固定参考时钟 REFCLK1/2,它将主时钟 fSOURCE0/1 除以 24。
这使得 OCDS 能够生成独立于所选 SRI 和 SPB 时钟速度的时间戳。

6. Clock Generation Unit

在这里插入图片描述

7. Use Cases

7.1 Clock Ramp-up Example

下面的sequence给出了一个时钟ramp-up的示例。正常target setting的目标是system clock基于带有外部晶体的 PLL。

  • power-on and system reset 之后:
    • system 运行在 back-up clock之上
    • 振荡器 (OSC) 需要通过软件启用,或通过 BMI 设置由固件启用
  • Fast clocks (比如 SRI bus 和CPU) 运行在back-up clock的频率(微调至大约100MHz)
  • 外设 clock, SPB-Bus总线的速度运行在 back-up clock的 1/3上(微调大约至 33MHZ)
  • 在以下步骤中,将用符号描述 AAA 和 BBB 两种设置: AAA[BBB]
    AAA 设置 用于 20MHz 晶振/时钟输入,为 300MHz 系统配置。
    BBB 设置用于 25MHz 晶振/时钟输入,并为 300MHz 系统配置。
  • Step 1:如果要使用 fOSC0,但它尚未运行,则要enable振荡器并等待它提供稳定的时钟。
  • Step 2: 初始化 PLLs 到想要的 fDCO, fPLLx频率
    • SYSPLLCON0.INSEL = 01B, 设置PLL input clock source
    • 设置 P, K2,N 参数,来设置最终的DCO和PLL 频率
      SYSPLLCON0 = 40013A00H[40012E00H]
      SYSPLLCON1 = 00000005H[00000005H]
      SYSPLL fDCO = 600MHz[600MHz];  	fPLL0 = 100MHz[100MHz]
      
      PERPLLCON0 = 00013E00H[00013E01H]
      PERPLLCON1 = 00000101H[00000104H]
      PERPLL fDCO = 640MHz[800MHz]; fPLL1 = 320MHz[160MHz]; fPLL2 = 200MHz[200MHz]
      
  • Step 3: 等待 PLL lock被设置
  • Step 4: 配置 CCUCON0, CCUCON1
CCUCON0 = 07230113H[07230113H]
CCUCON1 = 21210312H[21210392H]
CCUCON2 = 07001201H[07001201H]
CCUCON5 = 40000132H[40000030H]
fSTM = 33.3MHz[33.3MHz]; fGTM = 66.6MHz[66.6MHz]; fSRI = 100MHz[150MHz]; fSPB = 33.3MHz[33.3MHz];
fBBB = 50MHz[50MHz]; fFSI = 33.3MHz[33.3MHz]; fFSI2 = 100MHz[100MHz];
fGETH = 50MHz[50MHz]; fMCANH = 33.3MHz[33.3MHz]; fADAS = 100MHz[100MHz];
fMCAN = 50MHz[50MHz]; fI2C = 33.3MHz[33.3MHz]; fMSC = 100MHz[100MHz]; fQSPI = 100MHz[100MHz];
fASCLINF = 100MHz[100MHz]; fASCLINS = 50MHz[50MHz]; fEBU = 100MHz[100MHz]; fERAY = 50MHz[50MHz];
fHSPDM_320 = 100MHz[100MHz]; fHSPDM_160 = 100MHz[100MHz];
fADC = 100MHz[100MHz]; fHSCT = 320MHz[400MHz]; fRAM = 66.6MHz[66.6MHz]; 
fREFCLK1 = 4.16MHz[4.16MHz]; fREFCLK2 = 4.16MHz[4.16MHz];

notes:
如果 PERPLLCON1.K2DIV 配置为 0H 或 1H,CCUCON1.PLL1DIVDIS 应设置为 0B。
如果 PERPLLCON1.K2DIV 配置为 2H 或更大值,则应将 CCUCON1.PLL1DIVDIS 设置为 1B。

  • Step 5: 配置 CCUCON0.CLKSEL来切换CCU的input clock source fSOURCE0
  • 在每个频率编程步骤之后,建议等待一段时间,直到电源电流瞬态引起的电源纹波稳定下来。

CCUCON0 = 57230113H[57230113H]

fSTM = 33.3MHz[33.3MHz]; fGTM = 66.6MHz[66.6MHz]; fSRI = 100MHz[100MHz]; fSPB = 33.3MHz[33.3MHz];
fBBB = 50MHz[50MHz]; fFSI = 33.3MHz[33.3MHz]; fFSI2 = 100MHz[100MHz];
fGETH = 50MHz[50MHz]; fMCANH = 33.3MHz[33.3MHz]; fADAS = 100MHz[100MHz];
fMCAN = 80MHz[80MHz]; fI2C = 66.6MHz[66.6MHz]; fMSC = 200MHz[200MHz]; fQSPI = 200MHz[200MHz];
fASCLINF = 200MHz[200MHz]; fASCLINS = 80MHz[80MHz]; fEBU = 160MHz[160MHz]; fERAY = 80MHz[80MHz];
fHSPDM_320 = 320MHz[160MHz]; fHSPDM_160 = 160MHz[160MHz];
fADC = 160MHz[160MHz]; fHSCT = 320MHz[400MHz]; fRAM = 66.6MHz[66.6MHz]; 
fREFCLK1 = 4.16MHz[4.16MHz]; fREFCLK2 = 6.67MHz[6.67MHz];
  • Step 6: 设置完CCU fSOURCE = fPLL之后,逐步设置以下步骤来达到想要的频率

a) SYSPLLCON1 = 00000003H[00000003H]

fSTM = 50MHz[50MHz]; fGTM = 100MHz[100MHz]; fSRI = 150MHz[150MHz]; fSPB = 50MHz[50MHz];
fBBB = 75MHz[75MHz]; fFSI = 50MHz[50MHz]; fFSI2 = 150MHz[150MHz];
fGETH = 75MHz[75MHz];fMCANH = 50MHz[50MHz]; fADAS = 150MHz[150MHz];
fMCAN = 80MHz[80MHz]; fI2C = 66.6MHz[66.6MHz]; fMSC = 200MHz[200MHz]; fQSPI = 200MHz[200MHz];
fASCLINF = 200MHz[200MHz]; fASCLINS = 80MHz[80MHz]; fEBU = 160MHz[160MHz]; fERAY = 80MHz[80MHz];
fHSPDM_320 = 320MHz[160MHz]; fHSPDM_160 = 160MHz[160MHz];
fADC = 160MHz[160MHz]; fHSCT = 320MHz[400MHz]; fRAM = 100MHz[100MHz]; 
fREFCLK1 = 6.25MHz[6.25MHz]; fREFCLK2 = 6.67MHz[6.67MHz];

b) SYSPLLCON1 = 00000002H[00000002H]

SYSPLL fDCO = 600MHz[600MHz]; fPLL0 = 200MHz[200MHz]
fSTM = 66.6MHz[66.6MHz]; fGTM = 133.3MHz[133.3MHz]; fSRI = 200MHz[200MHz]; fSPB = 66.6MHz[66.MHz];
fBBB = 100MHz[100MHz]; fFSI = 66.6MHz[66.6MHz]; fFSI2 = 200MHz[200MHz];
fGETH = 100MHz[100MHz]; fMCANH = 66.6MHz[66.6MHz]; fADAS = 200MHz[200MHz];
fMCAN = 80MHz[80MHz]; fI2C = 66.6MHz[66.6MHz]; fMSC = 200MHz[200MHz]; fQSPI = 200MHz[200MHz];
fASCLINF = 200MHz[200MHz]; fASCLINS = 80MHz[80MHz]; fEBU = 160MHz[160MHz]; fERAY = 80MHz[80MHz];
fHSPDM_320 = 320MHz[160MHz]; fHSPDM_160 = 160MHz[160MHz];
fADC = 160MHz[160MHz]; fHSCT = 320MHz[400MHz]; fRAM = 133MHz[133MHz]; 
fREFCLK1 = 8.3MHz[8.3MHz]; fREFCLK2 = 6.67MHz[6.67MHz];

c) SYSPLLCON1 = 00000001H[00000001H]

SYSPLL fDCO = 600MHz[600MHz]; fPLL0 = 300MHz[300MHz]
fSTM = 100MHz[100MHz]; fGTM = 200MHz[200MHz]; fSRI = 300MHz[300MHz]; fSPB = 100MHz[100MHz];
fBBB = 150MHz[150MHz]; fFSI = 100MHz[100MHz]; fFSI2 = 300MHz[300MHz];
fGETH = 150MHz[150MHz]; fMCANH = 100MHz[100MHz]; fADAS = 300MHz[300MHz];
fMCAN = 80MHz[80MHz]; fI2C = 66.6MHz[66.6MHz]; fMSC = 200MHz[200MHz]; fQSPI = 200MHz[200MHz];
fASCLINF = 200MHz[200MHz]; fASCLINS = 80MHz[80MHz]; fEBU = 160MHz[160MHz]; fERAY = 80MHz[80MHz];
fHSPDM_320 = 320MHz[160MHz]; fHSPDM_160 = 160MHz[160MHz];
fADC = 160MHz[160MHz]; fHSCT = 320MHz[400MHz]; fRAM = 200MHz[200MHz]; 
fREFCLK1 = 12.5MHz[12.5MHz]; fREFCLK2 = 6.67MHz[6.67MHz];

在这里插入图片描述

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是S32K144-EVB开发板CAN的示例代码,可以作为参考: ```c #include "board.h" #include "fsl_debug_console.h" #include "fsl_flexcan.h" /******************************************************************************* * Definitions ******************************************************************************/ /* Define constants for FlexCAN baudrate calculation */ #define PCLK_FREQ (CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) / (CLOCK_GetRootPreDivider(kCLOCK_RootCan1)) / \ (CLOCK_GetRootPostDivider(kCLOCK_RootCan1)) / 2U) #define FLEXCAN_EXAMPLE_FRAME_COUNT (1U) #define EXAMPLE_FLEXCAN (CAN0) #define EXAMPLE_CAN_CLK_FREQ (PCLK_FREQ) #define EXAMPLE_CAN_IRQn CAN0_IRQn #define EXAMPLE_CAN_IRQHandler CAN0_IRQHandler #define EXAMPLE_FLEXCAN_DMA_IRQn DMA0_DMA16_IRQn #define EXAMPLE_RX_MESSAGE_BUFFER_NUM (5U) #define EXAMPLE_TX_MESSAGE_BUFFER_NUM (4U) #define RX_MAILBOX_NUM (7U) #define TX_MAILBOX_NUM (8U) #define DLC (8U) /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /* ESR register */ volatile uint32_t g_err_cnt = 0; volatile uint32_t g_esr = 0; /* CAN message buffer */ flexcan_mb_transfer_t rxXfer, txXfer; /* Received data */ flexcan_frame_t rxFrames[EXAMPLE_FLEXCAN_FRAME_COUNT]; /* Remote request data */ flexcan_frame_t txRemoteFrame; /******************************************************************************* * Code ******************************************************************************/ /*! * @brief FlexCAN user callback function. * * This function is called when FlexCAN receive a frame or finished a transfer. * * @param base FlexCAN peripheral base address. * @param handle Pointer to FlexCAN handle structure. * @param status FlexCAN transfer status. * @param userData User data. */ void FLEXCAN_UserCallback(CAN_Type *base, flexcan_handle_t *handle, status_t status, void *userData) { switch (status) { /* Process FlexCAN Rx event. */ case kStatus_FLEXCAN_RxIdle: PRINTF("Frame received successfully!\r\n"); break; /* Process FlexCAN Tx event. */ case kStatus_FLEXCAN_TxIdle: PRINTF("Frame transmitted successfully!\r\n"); break; /* Process FlexCAN error event. */ case kStatus_FLEXCAN_ErrorStatus: PRINTF("FlexCAN error happened: %#x!\r\n", handle->errorCode); break; default: break; } } /*! * @brief Main function. */ int main(void) { flexcan_config_t flexcanConfig; flexcan_frame_t txFrame; flexcan_handle_t flexcanHandle; uint32_t i; /* Initialize board hardware. */ BOARD_InitPins(); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); PRINTF("\r\nFlexCAN example -- Start.\r\n"); /* Initialize FlexCAN module. */ flexcanConfig.clkSrc = kFLEXCAN_ClkSrcPeri; flexcanConfig.baudRate = 125000U; flexcanConfig.enableLoopBack = false; flexcanConfig.enableSelfWakeup = false; flexcanConfig.enableIndividMask = false; flexcanConfig.maxMbNum = 16U; FLEXCAN_Init(EXAMPLE_FLEXCAN, &flexcanConfig, EXAMPLE_CAN_CLK_FREQ); /* Create FlexCAN handle structure and set call back function. */ FLEXCAN_TransferCreateHandle(EXAMPLE_FLEXCAN, &flexcanHandle, FLEXCAN_UserCallback, NULL); /* Setup Rx Message Buffer. */ rxXfer.frame = &rxFrames[0]; rxXfer.mbIdx = RX_MAILBOX_NUM; FLEXCAN_SetRxMbConfig(EXAMPLE_FLEXCAN, rxXfer.mbIdx, true); /* Setup Tx Message Buffer. */ txXfer.frame = &txFrame; txXfer.mbIdx = TX_MAILBOX_NUM; FLEXCAN_SetTxMbConfig(EXAMPLE_FLEXCAN, txXfer.mbIdx, true); /* Start receive data through polling mode. */ rxXfer.frame = &rxFrames[0]; rxXfer.mbIdx = RX_MAILBOX_NUM; /* Set up remote request data. */ txRemoteFrame.format = kFLEXCAN_FrameFormatStandard; txRemoteFrame.type = kFLEXCAN_FrameTypeRemote; txRemoteFrame.id = FLEXCAN_ID_STD(0x123); txRemoteFrame.length = DLC; while (1) { /* Wait for receive data. */ while (kStatus_FLEXCAN_RxIdle != FLEXCAN_TransferReceiveNonBlocking(EXAMPLE_FLEXCAN, &flexcanHandle, &rxXfer)) { } /* Copy remote request data to Tx Message Buffer. */ for (i = 0; i < DLC; i++) { txFrame.dataByte[i] = txRemoteFrame.dataByte[i]; } txFrame.format = kFLEXCAN_FrameFormatStandard; txFrame.type = kFLEXCAN_FrameTypeData; txFrame.id = FLEXCAN_ID_STD(0x321); txFrame.length = DLC; /* Wait until previous FlexCAN transfer finished. */ while (kStatus_FLEXCAN_TxIdle != FLEXCAN_GetTransferStatusFlags(EXAMPLE_FLEXCAN, txXfer.mbIdx)) { } /* Transmit remote request frame. */ FLEXCAN_TransferSendNonBlocking(EXAMPLE_FLEXCAN, &flexcanHandle, &txXfer); /* Wait until transfer finished. */ while (kStatus_FLEXCAN_TxIdle != FLEXCAN_GetTransferStatusFlags(EXAMPLE_FLEXCAN, txXfer.mbIdx)) { } } } ``` 这个示例程序演示了如何使用S32K144-EVB开发板上CAN模块。在这个例子中,我们使用了两个邮箱,其中一个用于接收数据,另一个用于发送数据。在主函数中,我们使用了一个 while 循环,不断地等待接收数据,并且发送一条远程请求帧作为响应。可以根据自己的需求进行修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值