MSP432E4 系列 MCU 学习笔记

本文旨在帮助将参加国赛的同学快速了解 MSP432E4 系列 MCU 的基本特性和用法。具体而言,本笔记概括性描述了芯片特性及其驱动库用法,主要参考资料包括数据手册、技术参考手册、MSP432E4 驱动库用户手册及例程。推荐具有单片机开发经验和对 Cortex-M 架构有所了解的读者阅读。笔记不会尝试囊括所有内容,而是着重基本特性和常用功能。

前言

MSP432E4 系列比起 MSP432P4 系列更像是一款主流的高性能 MCU,主频可达 120MHz ,拥有 USB2.0 和百兆以太网,外设从数量和功能上都更加丰富。相比之下,P4 系列可能更像一个 Cortex-M4F 的大号 MSP430。不过,强大的芯片也意味着学习内容的增加以及学习难度的提升,因此本笔记不会采用 P4 系列笔记中通过例程以点带面,发散思维的方式,而是回归基础,一个个外设逐步学习。

在 IDE 方面,我选择的是 Texas Instruments 近年主推的 Code Composer Studio,版本号 10.2.0。选择 CCS 的主要原因是不想使用外观体验极差的 Keil,IAR 则了解不太多。工具链主要选择 CCS 工具链,日后视情况选择是否使用 GCC 工具链。CCS 内建的浏览器 Resource Exploer 可以查阅文档以及向工作区导入 SDK 中包含的例程,是重要的学习资源。

TI 有功能类似 STM32CubeMX 的代码初始化软件 TI System Configuration Tool,包括独立软件和 CCS 集成版。不过我个人认为这个软件还有不完善的地方,因此暂时不采用。

MSP432E4 系列的驱动库包含了很多功能相对的 API,例如有 xxxSet() 就会有 xxxGet(),有 xxxEnable() 就会有 xxxDisable(),为了节省篇幅,本文一般不会介绍起读取和失能作用的函数。

Kernel

一个 MCU 通常由 CPU 核心、总线、SRAM 等存储单元和外设组成。单片机程序最多的操作是外设的控制,但对于其他部分的特性也要有所了解。本章节主要记录了一些不属于单独外设而对使用 MCU 较为重要的内容

Bit-Band

本系列 MCU 支持 SRAM 区与外设区的位带操作。其中,1MB 大小的 SRAM 区 0x2000 0000~0x2006 FFFF对应着 32MB 大小的 0x2200 0000~0x2234 FFFF,前者称为 SRAM 位带区域,是 SRAM 直接映射的地址;后者称为 SRAM 位带别名(SRAM bit-band alias),显然其中每一字对应位带区域的一个比特。因此,很容易得到下面的换算公式。以 $A_{alias}$ 代指位带别名地址,$O_{region}$ 代指目标 SRAM 相对 SRAM 基址的偏移量,$B_{region}$ 代指要进行位操作的比特位。 \(A_{alias}=0x22000000+32*O_{region}+4*B_{region}\) 向 SRAM 别名区的 Bit0 写入的内容会被写入到 SRAM 区域的对应 bit 中,别名区的其余 bit 没有作用。外设别名区原理相同。

需要注意的是,仅通过数据总线访问别名区时会被映射,使用指令总线访问 SRAM 别名区不会被映射,访问外设别名区则不被允许。

睡眠模式

Cortex-M4F 核心拥有 Sleep mode 和 Deep-sleep mode 两种低功耗模式。前者会关闭处理器时钟,后者还将关闭系统时钟、PLL 和 FLASH

Internal Memory

MSP432E4 系列 MCU 集成了 265KB SRAM,1024KB FLASH,6KB EEPROM 以及内部 ROM。为了提高性能,FLASH 外部上还集成了两个 256bit 的指令预取缓存。它们共同构成了 MCU 的内部存储。

## ROM

MCU 的 ROM 区包含了中断向量表、Bootloader、外设固件库、AES 加密表和 CRC 错误检测功能。

放置在 ROM 区的外设固件库可以直接被用户应用调用,缩小用户应用的体积。如果希望使用这一功能,可以在外设固件库函数前添加 MAP_ 前缀,此时在 IDE 中无法查看函数声明和定义,因此对于应用体积不敏感的场合无需使用。MSP432E4 的图形库和 USB 库没有包含在 ROM 区。

当硬件上电复位时,MCU 会从 FLASH 或者 ROM 中加载栈指针。如果 0x00000004 上的 FLASH 空间上出现了 0xFFFFFFFF 代表 FLASH 处于擦除状态或者 BOOTCFG 的 EN 位清零,栈指针和中断向量表都会从 ROM 区加载,也就是执行 Bootloader 程序。Bootloader 程序使用内部时钟,可以通过 UART0,SSI0,I2C0 以及 USB 进行通信。

FLASH

E401 的 FLASH 分为四个 Blank,每个均为 128 位宽,扇区大小为 8K。FLASH 的读写是两个 256bit 交替进行的,因此对应有两个预取指缓存能够提升程序执行速度。因此,TI 推荐在编译期将字面量转换为 in-line code 以提升执行速度。

System Control

系统控制模块包含了一系列寄存器,可对复位、不可屏蔽中断、电源、时钟和低功耗模式进行控制,还记录了器件属性。

设备信息

系统控制模块中有一些只读寄存器详细记录了器件封装、工作温度范围、唯一序列号、外设情况等信息。下面举例了一些相关的驱动库函数,关于此部分更多的信息,请参阅驱动库指南。

uint32_t SysCtlSRAMSizeGet(void);
uint32_t SysCtlFlashSizeGet(void);
uint32_t SysCtlFlashSectorSizeGet(void);
bool SysCtlPeripheralPresent(uint32_t Peripheral);

电源控制

与 MSP432P4 系列不同,E4 系列只支持 2.97~3.63V 较窄的 VDD 输入。核心电压由内部 LDO 稳压输出,没有 DC/DC 的选项。模拟部分(包括时钟)则由外部 VDDA 电源提供。LDO 提供的核心电压可调,默认的配置被认为是功耗和性能平衡的设置,提高核心电压可能获得更好的性能表现,降低核心电压则可能降低功耗,对 LDO 输出电压进行调整应慎重考虑和测试。

MSP432E4 系列有三种模式:运行模式,睡眠模式和深度睡眠模式。运行模式下处理器执行指令;睡眠模式下处理器停止工作而设备时钟保持不变;深度睡眠模式下处理器停止工作,设备时钟则会根据配置改变。中断会使设备回到运行模式。

时钟控制

MSP432E4 系列 MCU 拥有内部两个,外部两个最多四个时钟源。PLL 可以接受所有时钟源作为输入。

当上电复位以后,内部基准时钟开始以 16 MHz 工作,对于那些无需准确时钟的应用,使用内部基准时钟可以节约成本。如果要使用外部晶振提供的主时钟,则内部基准时钟会工作到晶振稳定后进行时钟源切换。无论是否使用主时钟,内部基准时钟都可以单独为一些外设提供时钟。主时钟可以接受外部时钟信号或者外部晶振输入。低频内部时钟被设计用作深睡眠模式下使用,此时主时钟和内部基准时钟会被关闭以降低功耗。休眠模式 RTC 时钟可以接受外部时钟信号或外部晶振输入,提供 RTC 功能。

下面的驱动库函数用于配置系统时钟。

uint32_t SysCtlClockFreqSet(uint32_t Config, uint32_t SysClock);

Config 参数是一个综合性的参数,它囊括了时钟源选择、PLL 开启/关闭以及 PLL VCO 输出频率。SysClock 则代表了希望配置的频率。驱动库会自动使用 Config 的配置去匹配 SysClock,如果匹配失败,则选择一个最接近的频率配置方案。

The oscillator source is chosen with one of the following values:

  • SYSCTL_OSC_MAIN to use an external crystal or oscillator.
  • SYSCTL_OSC_INT to use the 16-MHz precision internal oscillator.
  • SYSCTL_OSC_INT30 to use the internal low frequency oscillator.
  • SYSCTL_OSC_EXT32 to use the hibernate modules 32.786-kHz oscillator.

The system clock source is chosen with one of the following values:

  • SYSCTL_USE_PLL is used to select the PLL output as the system clock.
  • SYSCTL_USE_OSC is used to choose one of the oscillators as the system clock.

The PLL VCO frequency is chosen with one of the the following values:

  • SYSCTL_CFG_VCO_480 to set the PLL VCO output to 480-MHz
  • SYSCTL_CFG_VCO_320 to set the PLL VCO output to 320-MHz

外设控制

设备上的每一个外设都可以单独配置开启或者关闭,需要注意的是,在深度睡眠模式下 PLL 将被关闭,因此对于 UART 等需要精确时钟的外设,在进入和退出深度睡眠模式时,都要重新配置时钟。

下面列举了一些重要的外设控制驱动库函数。

void SysCtlPeripheralEnable(uint32_t Periphera);
void SysCtlPeripheralDisable(uint32_t Periphera);
bool SysCtlPeripheralReady(uint32_t Periphera);

其中,SysCtlPeripheralEnable 函数会启动外设时钟,通常在其调用后通过循环 SysCtlPeripheralReady 确认外设是否启动成功。对于那些需要额外配置时钟的外设,会在启动后另行配置。对于配置为其他外设引脚的 GPIO,应首先启动 GPIO,配置完成后再启动对应的外设。

延时函数

void SysCtlDelay(uint32_t ui32Count);

这里的 Count 参数大概是指时钟周期数,可以给个 getSystemClock()/2 之类的参数方便配置。

Interrupt

中断驱动库提供了一系列函数进行对 NVIC 的管理,包括使能/失能中断,注册中断处理函数和配置中断优先级。

MSP432E4 系列 MCU 支持154 个独立的中断源和八个优先级,每个独立中断都可以被屏蔽,处理器中断则可以被全体屏蔽。当处理器决定响应中断时,NVIC 向其提供中断处理函数的地址。中断的响应函数被放在一个称为中断向量表的数组当中,可在手册或者 startup 文件中找到。中断向量表包括了复位响应、硬件错误响应等系统异常响应,也有 ADC 全局中断响应等外设响应。配置中断响应有两种方式:直接使用中断向量表定义的响应函数,编译期静态配置;运行时使用 NVIC API 动态配置。在本例程中,就使用了静态配置的 GPIO 中断:与其他 Cortex-M 系列单片机类似,中断拥有优先级和子优先级。

下面列举了一些重要的中断驱动库函数

void IntRegister(uint32_t Interrupt, void(*Handler)(void));
void IntPriorityGroupingSet(uint32_t Bits);
void IntPrioritySet(uint32_t Interrupt, uint8_t Priority);
void IntEnable(uint32_t Interrupt);
void IntDisable(uint32_t Interrupt);
void IntPriorityMaskSet(uint32_t PriorityMask);

MSP432E4 系列硬件支持 3 位的中断优先级,因此 IntPriorityGroupingSet 的参数最大只能设置到 3,IntPrioritySet 设置 Priority 时,除了高位作为优先级,其余位可以用作子优先级的配置。IntPriorityMaskSet 可以屏蔽小于等于给定优先级的中断。

GPIO

概述

MSP432E44 的 GPIO 模块最高支持 18 组共 140 个 GPIO,它们都能忍受 3.3V 电平,具备内部弱上拉/下拉和不同的电流输出能力,也可配置为开漏输出模式或者带施密特触发的输入模式。

GPIO 可分为两类:高速 GPIO 和慢速 GPIO。高速 GPIO 的输出能力可编程控制,最高可达 12mA。慢速 GPIO 仅有 2mA 的电流输出能力,但被设计为对输入电压敏感。高速 GPIO 中也有部分 IO 的输出能力较弱,如 PL6/PL7 仅有 4mA 的输出能力,PM[7:4] 只支持 2mA、4mA、6mA 和 8mA 四档输出模式。

为了提高程序运行效率,GPIO 接口支持对数据寄存器(GPIO DATA register)的单比特操作。一般情况下,我们修改 GPIO 寄存器中单个比特的值都要经历 “read-modify-write” 操作,即先将 GPIO 寄存器值(映射到内存空间)读取到 Cortex-M4 通用寄存器,进行位操作后再写回 GPIO 寄存器,全过程至少需要三条指令,GPIO 的单比特操作则只需一条指令。其作用原理是,程序向 GPIO DATA 寄存器的一个偏移地址写入,偏移量的 [9:2] 八个位代表了对应 GPIO DATA 寄存器的哪一个位将被修改。例如偏移量是 0x98,0x98 = 0b0010011000,第三、四、七位为 1 ,那么 GPIO DATA 寄存器的第一、二、五位的值将被修改为写入量的第一、二、五位的值。

每一个 GPIO 都支持边缘触发和电平触发的中断。如果使用电平触发模式,则输入电平必须保持一定时间直至中断服务响应,否则中断不会发生。GPIO Port P & Q 的每一个引脚都有专属的中断向量。

驱动库函数

GPIO 模块的驱动库函数主要分为三类

  1. 配置 GPIO 引脚属性

    开启 GPIO 外设时钟以后,可以通过下面函数配置 GPIO 方向、输出强度、上拉/下拉,开漏输出等功能。最后一个函数可以将 GPIO 的引脚配置为其他外设的引脚,其参数是 GPIO_PA2_SSI0CLK 的形式。

    GPIODirModeSet(uint32_t Port, uint8_t Pins, uint32_t PinIO);
    GPIOPadConfigSet(uint32_t Port, uint8_t Pins, uint32_t Strength, uint32_t PinType);
    GPIODirModeGet(uint32_t Port, uint8_t Pins);
    GPIOPadConfigGet(uint32_t Port, uint8_t Pins);
       
    GPIOPinConfigure(uint32_t PinConfig);
    
  2. 获取/设置 GPIO 电平

    MSP432E44 系列的驱动库函数没有提供 Toggle Pin 函数。

    int32_t GPIOPinRead(uint32_t Port, uint8_t Pins);
    void GPIOPinWrite(uint32_t Port, uint8_t Pins);
    
  3. 设置 GPIO 中断

    使用 GPIO 中断应首先配置引脚属性,再使用下列函数进行中断配置和管理。

    void GPIOIntTypeSet(uint32_t Port, uint32_t Pins, uint32_t IntType);
    void GPIOIntEnable(uint32_t Port, uint32_t IntFlags);
    void GPIOIntStatus(uint32_t Port, bool Masked);
    void GPIOIntClear(uint32_t Portm uint32_t IntFlags);
    void GPIOIntRegister(uint32_t Port, void(*)(void)IntHandler);
    

GPIO 驱动库函数还提供了一系列函数,可以直接将 GPIO PIN 配置为外设引脚,并使用推荐的输入/输出配置。例如直接将 GPIO 配置为开漏输出模式。

GPIOPinTypeGPIOOutputOD(uint32_t ui32Port, uint8_t ui8Pins)
{
    // Check the arguments.
    ASSERT(_GPIOBaseValid(ui32Port));

    // Set the pad(s) for standard push-pull operation.
    GPIOPadConfigSet(ui32Port, ui8Pins, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD);
    
    // Make the pin(s) be outputs.
    GPIODirModeSet(ui32Port, ui8Pins, GPIO_DIR_MODE_OUT);
}

使用这些函数可以有效节省编码时间。

PWM

概述

PWM 模块可以使用系统时钟或者预分频的系统时钟。每个 PWM 模块包括四个 PWM 发生模块和一个控制模块,最多可以产生八路 PWM 输出。单个 PWM 输出模块可以输出两路独立的 PWM 输出或是带死区的互补 PWM 输出。输出模块带有 16 bit 向下或向上/向下计数器和两个比较器,分别对应左/右对齐输出和中央对齐输出。控制模块则负责 PWM 输出的使能/失能、输出极性控制、同步、错误处理和中断处理。

PWM 的计数器在运行时会产生四种单周期脉冲信号,控制模块正是使用了这些信号控制输出。这五种信号分别在计数器值归零、计数器值等于重装载值、计数器值等于比较寄存器 A 值、计数器值等于比较寄存器 B 值时输出。除此以外,还有计数器计数方向信号。显然,当计数器处于向下计数模式下,计数器归零和计数器等于重装载值这两个信号会紧随产生;当重装载值小于比较寄存器值时,对应的信号将永远不会产生。当这些信号发生时,PWM 输出将根据软件配置情况更改或者保持不变。

当死区发生器使能时,PWM 发生模块的第二路信号 PWMB 将不起作用,两路输出都由 PWMA 信号负责。此时,第一路输出 PWMA’ 将会带有可编程的上升沿延迟,第二路输出 PWMB’ 将会带有可编程的下降沿延迟,形成带死区的互补 PWM 输出。

驱动库函数

在驱动库函数当中,四个 PWM 发生模块分别称作 Gen0、Gen1、Gen2 和 Gen3,单个模块的两路输出分别称为 OutA 和 OutB,八路输出分别对应 PWM0~PWM7,需要注意的是,并非所有的 PWM 模块都具备完整的八路输出。

PWM 模块的库函数较为复杂,下面展示了一个典型的,简单的 PWM 输出应用。

// Enable the PWM0 peripheral
SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0);

// Wait for the PWM0 module to be ready.
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_PWM0))
{
}

// Configure the PWM generator for count down mode with immediate updates
// to the parameters.
PWMGenConfigure(PWM_BASE, PWM_GEN_0, PWM_GEN_MODE_DOWN | PWM_GEN_MODE_NO_SYNC);

// Set the period.  For a 50 KHz frequency, the period = 1/50,000, or 20
// microseconds.  For a 20 MHz clock, this translates to 400 clock ticks.
// Use this value to set the period.
PWMGenPeriodSet(PWM_BASE, PWM_GEN_0, 400);

// Set the pulse width of PWM0 for a 25% duty cycle.
PWMPulseWidthSet(PWM_BASE, PWM_OUT_0, 100);

// Set the pulse width of PWM1 for a 75% duty cycle.
PWMPulseWidthSet(PWM_BASE, PWM_OUT_1, 300);

// Start the timers in generator 0.
PWMGenEnable(PWM_BASE, PWM_GEN_0);

// Enable the outputs.
PWMOutputState(PWM_BASE, (PWM_OUT_0_BIT | PWM_OUT_1_BIT), true);

PWMGenConfigure() 函数的 Base 参数代表了 PWM 模块的外设地址,Config 参数是一个综合参数,包含了以下内容

  • PWM_GEN_MODE_DOWN or PWM_GEN_MODE_UP_DOWN to specify the counting mode
  • PWM_GEN_MODE_SYNC or PWM_GEN_MODE_NO_SYNC to specify the counter load and comparator update synchronization mode
  • PWM_GEN_MODE_DBG_RUN or PWM_GEN_MODE_DBG_STOP to specify the debug behavior
  • PWM_GEN_MODE_GEN_NO_SYNC, PWM_GEN_MODE_GEN_SYNC_LOCAL, or PWM_GEN_MODE_GEN_SYNC_GLOBAL to specify the update synchronization mode for generator counting mode changes
  • PWM_GEN_MODE_DB_NO_SYNC, PWM_GEN_MODE_DB_SYNC_LOCAL, or PWM_GEN_MODE_DB_SYNC_GLOBAL to specify the deadband parameter synchronization mode
  • PWM_GEN_MODE_FAULT_LATCHED or PWM_GEN_MODE_FAULT_UNLATCHED to specify whether fault conditions are latched or not
  • PWM_GEN_MODE_FAULT_MINPER or PWM_GEN_MODE_FAULT_NO_MINPER to specify whether minimum fault period support is required
  • PWM_GEN_MODE_FAULT_EXT or PWM_GEN_MODE_FAULT_LEGACY to specify whether extended fault source selection support is enabled or not

下面的函数可以产生带死区的互补 PWM 输出,后两个参数分别指定了上升沿和下降沿的延迟

void PWMDeadBandEnable(uint32_t Base, uint32_t Gen, uint16_t Rise, uint16_t Fall);

ADC

消歧义

MSP432E4 系列 MCU 上有一个 ADC 外设(ADC Peripheral),它包含了两个 ADC 模块(ADC Module),两者名称不可混用。

概述

驱动库提供了简单的 API 使用户可以轻松配置 ADC 的采样率、读取采样数据、注册采样通道中断函数等操作。

MSP432E4 系列 MCU 的 ADC 外设是 12bit ADC,拥有两个一样的转换模块,它们分享最高 24 个输入通道以及一个内部温度传感器通道。ADC 模块拥有四个采样序列,每个均可独立配置输入、触发事件、中断和序列优先级。ADC 模块还带有八个数字比较器,它们可以将 ADC 测量值与用户给定值比较以决定输出信号。

MSP432E4 系列的 ADC 使用了基于队列的管理方式,而不是相当多其他 ADC 的单/双采样方式。每个采样队列都可以使 ADC 连续收集数据而无需重新配置,采样结束以后,还可以产生中断或者 DMA 传输。由于四个通道的 FIFO 深度不同,它们支持的队列长度不同,SS0 队列支持 8 个采样,SS1 和 SS2 支持 4 个采样,SS3 支持 1 个采样。采样队列具有 0~3 的优先级,0 表示最高。当队列拥有同一个优先级时,它们的采样次序是不确定的,因此必须为每个队列配置唯一的优先级。

除了处理器能够触发 ADC 采样以外,定时器、模拟比较器、PWM 外设和 GPIO 都可以作为 ADC 采样的触发源。需要注意的是,如果一个通道被配置为连续采样模式,那么它的优先级必须设置为最低,否则将会影响其他通道的触发。

ADC 外设的保持采样时间可调,保持采样时间不仅影响采样频率,也会影响允许的外部最大阻值。

ADC 模块可以配置同步和延时,这一特性可以使两个模块同时采样一个信号时获得双倍的采样率。

ADC 模块还支持差分输入模式。

ADC 外设的温度传感器可以用于确认芯片电压,也可以作为 RTC 时钟的校准。温度传感器包含了带隙基准(Bandgap reference)因此总是处于使能状态为其他模拟部分提供基准电压。温度传感器的计算公式如下。 \(V_{TSENS}=2.7V-(Temperature+55)/75\)

\[Temperature =147.5-((75*(V_{REFP}-V_{REFPN})*ADC_{CODE})/4096)\]

ADC 还支持硬件上的和软件上的过采样,此处暂不展开论述。

驱动库函数

ADC 外设的库函数可以分为三类:处理采样队列相关的库函数;处理处理器触发的库函数和处理中断的库函数。

由于 ADC 外设是基于队列控制的,在启动 ADC 外设以后,首先应进行队列的配置。以下第一个函数配置了指定的 ADC 转换队列的触发源和优先级。第二个函数则比较复杂,根据 ADC 转换队列号的不同,每个转换队列都有一定的深度,那么队列中的每一步(step)都要配置转换模式、输入通道和输出的数字比较器,config 参数即为上述参数的逻辑与。

void ADCSequenceConfigure(uint32_t ui32Base, uint32_t ui32SequenceNum, uint32_t ui32Trigger, uint32_t ui32Priority);
void ADCSequenceStepConfigure(uint32_t ui32Base, uint32_t ui32SequenceNum, uint32_t ui32Step, uint32_t 	ui32Config);

完成配置后即可启动 ADC,如果选择了使用处理器触发 ADC 转换,则使用下列第二个函数。

void ADCSequenceEnable(uint32_t ui32Base,uint32_t ui32SequenceNum);
void ADCProcessorTrigger(uint32_t ui32Base, uint32_t ui32SequenceNum);

ADC 转换完成后,读取 ADC 值

int32_t ADCSequenceDataGet(uint32_t ui32Base, uint32_t 	ui32SequenceNum, uint32_t * 	pui32Buffer);

每一个 ADC 转换队列都能够配置其中断处理函数,相对应的有中断状态查询和设置函数。

void ADCIntRegister(uint32_t ui32Base,uint32_t ui32SequenceNum,void(*)(void) pfnHandler);	
void ADCIntDisable(uint32_t ui32Base,uint32_t ui32SequenceNum);
void ADCIntEnable(uint32_t 	ui32Base,uint32_t ui32SequenceNum);	
uint32_t ADCIntStatus(uint32_t 	ui32Base,uint32_t ui32SequenceNum,bool bMasked);
void ADCIntClear(uint32_t ui32Base, uint32_t ui32SequenceNum);

Gereral Purposal Timers

消歧义

通用定时器的实例称作通用定时器模块(General-Purpose Timers Module, GPTM),GPTM 包含了八个通用定时器块(General-Purpose Timers Module Block)分别称作 Timer 0 ~ Timer 7,每个通用定时器块包含了两个 16bit 计数器,分别称为 Timer A、Timer B。

概述

通用定时器可以用于计数和为外部事件计时。MSP432E4 系列的通用定时器块包含了两个 16bit 的向上或向下计数器,它们既可以单独工作,也可以串联形成 32bit 的计时器或者一个 32bit 的 RTC 定时器。通用定时器的时钟源可以是系统时钟或者其他时钟源,如 RTC 时钟。定时器还可以作为 ADC 和 μDMA 的触发源。

通用定时器模块带有十六个 16bit/32bit 捕获比较 PWM 引脚

通用定时器支持形成菊花链(没有搞懂)

定时器模式

通用定时器块可以使用以下工作模式。可以注意到,预分频器只有在定时器块的两个计数器独立工作时才能生效。当两个计数器独立工作时,它们可以配置为不同的模式。当两个计数器串联使用时,TimerA 的控制与状态寄存器负责处理所有工作。

  • 16bit/32bit 单次计时器
  • 16bit/32bit 周期计时器
  • 带有 8bit 预分频器的 16bit 通用定时器
  • 使用外部 32768Hz 时钟源的 32bit RTC 定时器,只允许向上计数
  • 带有 8bit 预分频器的 16bit 边缘输入计数或时间捕获功能
  • 带有 8bit 预分频器和软件翻转功能的 16bit PWM 模式,只允许向下计数

单次/周期计时器模式

在单次和周期计数模式下,计数器会从 0 向上计数或者从预装载值(软件预先填充到寄存器中)向下计数,或者被设置为等待一个触发事件才开始计数。计数值溢出(无论上溢还是下溢)以后计数器都会重装载,单次模式会停下,周期模式则会继续下一个周期的计时,此时还可以配置触发中断。还有一个功能则是计数器计数值匹配时产生中断。

在计数器运行期间修改相关寄存器的值一般会立刻生效,具体请查看参考手册相关章节

单次和周期计数模式下有一个补充功能,可以改变引脚电平。当计数器达到指定值时,根据软件配置可以置位/复位/翻转指定的 Compare Capture Pin(CCP) 但如果使用的是 32bit 模式则只能选择偶数的 CCP。该功能不能与 PWM 模式共存。

RTC 模式

RTC 模式下定时器的时钟输入必须是 32768Hz ,在内部被分频至 1Hz

边缘输入计数模式

边缘输入计数模式下定时器以 24bit 向上或向下模式运行,可以捕获上升沿、下降沿或者两者都捕获。每次输入事件都会令计数器加/减 1,当计数器达到指定值,可以产生中断、ADC 转换或者 μDMA 传输。在向上计数模式下,计数器会清零并继续进入捕获模式,但在向下计数模式下则要应用重新开启才会继续捕获边缘。在上升沿发生以后,输入信号至少要保持两个时钟周期才不会被误判,下降沿同理,因此最大的输入频率只有定时器输入时钟的 1/4

边缘输入计时模式

边缘输入计时模式的基本功能是记录下外部边缘信号发生时的计数器值,因此此模式下计数器不断地从重装载值计数到溢出,当输入引脚捕获到边缘信号时,可配置产生中断、ADC 转换或者 μDMA 传输,计数器值则可被处理器读取。

PWM 模式

在 PWM 模式下定时器用作 24bit 向下计数模式,其周期和占空比由重装载值和匹配值共同确定。

等待触发模式

等待触发模式用作将多个定时模块配置为菊花链。此时,计时器会在前一个计时器计数溢出时才开始计数

驱动库函数

通用定时器功能众多,因此配置复杂。

  1. 定时器的配置与控制

    驱动库提供了一个通用定时器的高层次配置函数,它能同时配置定时器的两个计数器是协同工作还是独立工作、计数器的计数模式和功能模式。

    void TimerConfig(uint32_t Base, uint32_t Config);
    

    The configuration is specified in ui32Config as one of the following values:

    • TIMER_CFG_ONE_SHOT - Full-width one-shot timer
    • TIMER_CFG_ONE_SHOT_UP - Full-width one-shot timer that counts up instead of down
    • TIMER_CFG_PERIODIC - Full-width periodic timer
    • TIMER_CFG_PERIODIC_UP - Full-width periodic timer that counts up instead of down
    • TIMER_CFG_RTC - Full-width real time clock timer
    • TIMER_CFG_SPLIT_PAIR - Two half-width timers

    When configured for a pair of half-width timers, each timer is separately configured. The first timer is configured by setting ui32Config to the result of a logical OR operation between one of the following values and ui32Config:

    显然下述参数的 “A” 改为 “B” 也同样适用

    • TIMER_CFG_A_ONE_SHOT - Half-width one-shot timer
    • TIMER_CFG_A_ONE_SHOT_UP - Half-width one-shot timer that counts up instead of down
    • TIMER_CFG_A_PERIODIC - Half-width periodic timer
    • TIMER_CFG_A_PERIODIC_UP - Half-width periodic timer that counts up instead of down
    • TIMER_CFG_A_CAP_COUNT - Half-width edge count capture
    • TIMER_CFG_A_CAP_COUNT_UP - Half-width edge count capture that counts up instead of down
    • TIMER_CFG_A_CAP_TIME - Half-width edge time capture
    • TIMER_CFG_A_CAP_TIME_UP - Half-width edge time capture that counts up instead of down
    • TIMER_CFG_A_PWM - Half-width PWM output

    Config 参数还有一些可选的宏定义能够设置计数器超时时的执行的动作,例如翻转对应的比较捕获引脚(CCP)或者令其输出一个脉冲,详情可见驱动库用户手册。

    下列 API 能够启动定时器或者 RTC 模式定时器,必须在初始化以后才能启动,否则不起作用。

    void TimerEnable(uint32_t Base, uint32_t Timer);
    void TimerRTCEnable(uint32_t Base);
    

    下列 API 提供了对定时器各模式和功能的基本控制,例如 PWM 极性、ADC 触发控制等。

    void TimerControlLevel(uint32_t Base, uint32_t Timer, bool Invert);
    void TimerControlTrigger(uint32_t Base, uint32_t Timer, bool Enbale);
    void TimerControlEvent(uint32_t Base, uint32_t Timer, uint32_t Event);
    void TimerControlWaitOnTrigger(uint32_t Base, uint32_t Timer, bool Wait);
    

    下列的 API 则提供了对定时器几个关键数值的设置与访问,包括重装载值、比较值、预分频值等

    void TimerLoadSet(uint32_t Base, uint32_t Timer, uint32_t Value);
    void TimerMatchSet(uint32_t Base, uint32_t Timer, uint32_t Value);
    void TimerPrescalerSet(uint32_t Base, uint32_t Timer, uint32_t Value);
    
  2. 定时器的各种计数事件都可以触发中断,使用时要先使能对应的中断标志。同样的驱动库提供了注册中断处理函数、查询中断状态和清除中断标志位的 API

    void TimerIntEnable(uint32_t Base, uint32_t IntFlags);
    void TimerIntStatus(uint32_t Base, uint32_t Masked);
    void TimerIntClear(uint32_t Base, uint32_t IntFlags);
    void TimerIntRegister(uint32_t Base, uint32_t Timer, void(*)(void) Handler);
    

    可选的 IntFlags 参数如下

    • TIMER_TIMB_DMA - Timer B uDMA complete
    • TIMER_TIMA_DMA - Timer A uDMA complete
    • TIMER_CAPB_EVENT - Capture B event interrupt
    • TIMER_CAPB_MATCH - Capture B match interrupt
    • TIMER_TIMB_TIMEOUT - Timer B timeout interrupt
    • TIMER_RTC_MATCH - RTC interrupt mask
    • TIMER_CAPA_EVENT - Capture A event interrupt
    • TIMER_CAPA_MATCH - Capture A match interrupt
    • TIMER_TIMA_TIMEOUT - Timer A timeout interrupt
  3. 定时器的计数事件还能触发 ADC 采样和 DMA 传输

    void TimerADCEventSet(uint32_t Base, uint32_t ADCEvent);
    void TimerDMAEventSet(uint32_t Base, uint32_t DMAEvent);
    

    它们的参数分别是

    • TIMER_ADC_MODEMATCH_B - Enables the mode match ADC trigger for timer B.
    • TIMER_ADC_CAPEVENT_B - Enables the capture event ADC trigger for timer B.
    • TIMER_ADC_CAPMATCH_B - Enables the capture match ADC trigger for timer B.
    • TIMER_ADC_TIMEOUT_B - Enables the timeout ADC trigger for timer B.
    • TIMER_ADC_MODEMATCH_A - Enables the mode match ADC trigger for timer A.
    • TIMER_ADC_RTC_A - Enables the RTC ADC trigger for timer A.
    • TIMER_ADC_CAPEVENT_A - Enables the capture event ADC trigger for timer A.
    • TIMER_ADC_CAPMATCH_A - Enables the capture match ADC trigger for timer A.
    • TIMER_ADC_TIMEOUT_A - Enables the timeout ADC trigger for timer A.

    • TIMER_DMA_MODEMATCH_B - The mode match uDMA trigger for timer B is enabled.
    • TIMER_DMA_CAPEVENT_B - The capture event uDMA trigger for timer B is enabled.
    • TIMER_DMA_CAPMATCH_B - The capture match uDMA trigger for timer B is enabled.
    • TIMER_DMA_TIMEOUT_B - The timeout uDMA trigger for timer B is enabled.
    • TIMER_DMA_MODEMATCH_A - The mode match uDMA trigger for timer A is enabled.
    • TIMER_DMA_RTC_A - The RTC uDMA trigger for timer A is enabled.
    • TIMER_DMA_CAPEVENT_A - The capture event uDMA trigger for timer A is enabled.
    • TIMER_DMA_CAPMATCH_A - The capture match uDMA trigger for timer A is enabled.
    • TIMER_DMA_TIMEOUT_A - The timeout uDMA trigger for timer A is enabled.

Micro Direct Memory Access

概述

μDMA(本文其他部分简称 DMA)外设能帮助处理器进行数据传输从而节省处理器时间,MSP432E4 系列的 DMA 支持从外设到内存、从内存到外设以及从内存到内存的传输路径,每个支持 DMA 传输的外设都有专用的 DMA 通道。DMA 使用的总线优先权总是低于处理器,因此 DMA 不会导致任何处理器上的访问延迟。同时,总线结构和芯片设计方面也进行了优化,通过内存分段(RAM striping)和外设总线对齐等方式,尽量使 DMA 控制器和处理器能同时进行数据传输。

每一个片上外设都拥有独立可配置的 DMA 通道,在 MSP432E4 系列 MCU 中,DMA 通道的配置使用通道控制结构体保存在系统内存上。

每个 DMA 通道的优先级判定由两部分构成,首先,若通道的优先级寄存器位被置位,则该通道比所有没有被置位的通道优先级都要高。在优先级寄存器位相同的情况下,通道编号越小优先级越高。

当 DMA 通道发送传输请求时,DMA 控制器会选择优先级最高的通道开始传输,直至该通道传输结束以后重新开始选择优先级高的通道。每个通道都拥有一个可配置的仲裁大小(arbitration size)以决定在突发模式(burst mode)下传输的 item 数,最大为 1024,显然如果一个低优先级的通道配置了大的仲裁大小,则高优先级的通道也可能被延迟传输。需要注意的是,一些厂商的 MCU 的 DMA 外设有仲裁器,如 STM32 系列,它的作用是根据通道配置优先级选择哪个通道可以占用总线传输。而这里的仲裁大小并非指的是 DMA 总线的仲裁,而是代表一个通道已经占用 DMA 总线后,可传输数量的权限。

DMA 有两种外设请求模式:单次和突发,根据外设自身的特点支持不同的模式。它们之间的差别在于单次传输的数据是一个 item 还是多个 item。当外设同时触发了单次和突发模式 DMA 请求时,突发模式请求会被优先响应。

DMA 控制器支持字节、半字和字宽度的传输,源地址和目的地址的数据大小必须相同,而它们的地址自增模式则不必相同

DMA 传输结束时,会发送一个传输结束信号给外设,外设可以配置产生 DMA 完成中断。软件 DMA 传输则有专门的软件 DMA 传输中断。如果 DMA 传输时遇到了总线冲突或者存储保护,DMA 控制器将停止传输并触发 DMA 错误中断。

DMA 传输模式

DMA 有六种传输模式,Ping-pong mode, Memory Scatter-Gather 和 Peripheral Scatter-Gather 三种模式较为复杂,先不予讨论。

停止模式顾名思义,处于这个模式的 DMA 外设不传输任何数据。

基本模式用于外设的 DMA 传输,此模式下 DMA 传输会在 DMA 请求存在的情况下持续进行。基本模式不适用于只短时存在的 DMA 请求,因为请求结束以后,DMA 会在传输仲裁大小的数据后自动停止,即便仍有数据待传输。

自动模式则与基本模式相反,即便请求结束,也会继续传输直到完成,自动模式适合于软件触发的 DMA 传输而不适宜外设的 DMA 传输。(仍有疑问,“传输完成”是如何界定的?软件触发和硬件触发有何区别?)

外设 DMA 传输接口

支持 DMA 传输的外设可分为带 FIFO 类型与提供触发输入类型两类。它们分别有不同的设计。

FIFO 外设带有输入输出的 FIFO,DMA 则负责 FIFO 与缓存进行数据交换。例如 UART 外设的 TX FIFO 非空会发送单次模式请求,如果一直没有被补充,当达到预设的 TX FIFO 事件时就会触发中断,发送更高优先级的突发模式请求,传输完成后,DMA 控制器又通过中断标志传输结束。DMA 可被配置为只使用突发模式,但 TI 不推荐在 UART SSI 这些常用突发模式的外设中使用这个配置,因为传输结尾可能被卡在 FIFO(为什么?)

通用定时器这类外设会在需要时触发一个 DMA 请求给 DMA 控制器,DMA 控制器则根据配置进行 DMA 传输。

驱动库函数

DMA 的使用和外设息息相关,这里讨论的 API 只涉及到了基本使用操作。

根据前面对 μDMA 外设的描述,我们大致可以想象使用 DMA 进行数据传输应当包含下列步骤:使能外设、初始化通道控制表、配置通道的属性、配置传输的数据大小、地址自增模式等以及最后启动 DMA 传输。

void uDMAEnable(void);
void uDMAControlBaseSet(void *psControlBase);

由于 Control Table 需要 1024 字节的空间,可以在程序开头静态分配 1024 字节大小的数组,再传递指针。

void uDMAChannelArttributeEnable(uint32_t ChannelNumber, uint32_t Attr);

Attr 参数囊括了对通道属性的配置,包括通道的高优先级、突发传输模式使能等。

void  uDMAChannelControlSet(uint32_t ChannelStructIndex, uint32_t Control);

Control 参数则负责配置通道传输的细节,例如地址自增模式,源地址和目标地址数据大小等。

void uDMAChannelTransferSet(uint32_t ChannelStructIndex, uint32 Mode, void* SrcAddr, void* 								DstAddr, uint32_t TransferSize);
void uDMAChannelEnable(uint32_t ChannelNum);
void uDMAChannelEnable(uint32_t ui32ChannelNum);

在设置了传输的模式、源地址、目的地址和传输数据量以后即可开始传输。如果是软件触发的 DMA 传输,则使用软件 DMA 请求 API 触发传输。

The general order of function calls to set up and perform a uDMA transfer is the following:

UART

概述

MSP432E4 系列 MCU 拥有 8 个 UART 外设,最高支持 15Mbps 的通信速率,收发都有单独的 8byte FIFO 和独立的 DMA 通道,支持 FIFO 深度中断和传输完成中断。数据格式方面,支持产生标准的启动、停止和校验位,支持 5~8 位数据,支持 IrDA SIR 编解码功能和智能卡,支持 EIA-485 9bit 模式。部分 UART 外设带有流控功能。

关于 UART 通信协议的细节,请参阅相关资料。

UART 外设的波特率通过系统时钟分频得来。

UART 外设的数据传输均通过 FIFO 进行,其中接收部分的 FIFO 除了 8bit 的数据位以外还增加了 4bit 的状态位。当 UART 外设使能的时候,数据会不断从 FIFO 中移出和发送,BUSY 状态位将被置位直至发送 FIFO 空。相似的,接收部分检测到开始位以后,外设将不断读取输入的信息并存放到 FIFO 中,直至接收到停止位。如果中途出现了错误,则错误状态将被写入到状态位部分。

对 FIFO 的访问都是通过 UART 数据寄存器(UARTDR) 进行的,读取寄存器会返回接收 FIFO 一个 12bit 的值,写入它则要写入一个 8bit 的值到发送 FIFO。复位以后,外设的 FIFO 处于关闭模式,此时它相当于一个单字节的寄存器缓存。

IrDA SIR、智能卡、9bit 模式和流控暂不作介绍。

UART 外设的溢出、校验错误、帧格式错误、接收超时和预设的 FIFO 深度均可触发中断。根据 FIFO 的数据深度,可以触发 DMA 的单次传输或者突发传输。

UART 外设支持在启动前配置为环回模式,在内部将发送和接收连接在一起用于调试。

驱动库函数

让我们首先考虑最简单的情况:8bit 数据位,没有校验,不使用中断和 DMA 传输,这是我们需要做的是选择时钟源、配置波特率,使能外设并开始发送/接收数据。那么就有了下列最基本的 API

void UARTClockSourceSet(uint32_t Base, uint32_t Source);
void UARTConfigSetExpClk(uint32_t Base, uint32_t UARTClk, uint32_t Baud, uint32_t Config)

UARTClk 参数指输入到 UART 外设的时钟速度,如果使用系统时钟可以填入 SysCtlClockGet() 代替。Baud 则是希望配置的波特率,API 会自动处理分频系数而无需人工计算。Config 参数包含了数据位长度、校验位、停止位长度的配置。

void UARTEnable(uint32_t Base);
int32_t UARTCharGet(uint32_t Base);
int32_t UARTCharGetNonBlocking(uint32_t Base);
void UARTCharPut(uint32_t Base, unsigned char Data);
bool UARTCharPut(uint32_t Base, unsinged char Data);

外设驱动库提供了阻塞和非阻塞的读取写入操作,阻塞模式下的 API 会在对应 FIFO 满/空的时候阻塞等待,非阻塞模式下则不会等待。

void UARTIntEnable(uint32_t Base, uint32_t IntFlags);
void UARTIntRegister(uint32_t Base, void(*)(void) Handler);

使用 UART 中断模式时,程序应首先使能使用的 UART 外设中断(见中断章节),再使能需要的中断。根据需求,可以使用中断向量表的 UART 中断处理函数,也可以注册自己的处理函数。UART 外设的中断源包括下列选项。

  • UART_INT_9BIT - 9-bit Address Match interrupt
  • UART_INT_OE - Overrun Error interrupt
  • UART_INT_BE - Break Error interrupt
  • UART_INT_PE - Parity Error interrupt
  • UART_INT_FE - Framing Error interrupt
  • UART_INT_RT - Receive Timeout interrupt
  • UART_INT_TX - Transmit interrupt
  • UART_INT_RX - Receive interrupt
  • UART_INT_DSR - DSR interrupt
  • UART_INT_DCD - DCD interrupt
  • UART_INT_CTS - CTS interrupt
  • UART_INT_RI - RI interrupt

UART 外设的 DMA 传输部分和 FIFO 部分待补充。

uartstdio.h/c

这两个文件是 TI 部分例程中附带的串口配置与输出文件,提供了 UARTprintf() 等方便的函数。

I2C

概述

MSP432E4 系列的 I2C 外设支持主/从机模式,接收和发送各有 8-byte FIFO 和单独的 DMA 通道,支持标准模式(100kbps)、快速模式(400kbps)、快速加强(1Mbps)和高速模式(3.3Mbps)四种传输速率。数据格式方面,支持 7bit 地址模式,支持软件 SMBus

关于 I2C 通信协议的细节,请参阅相关资料。

I2C 外设的 SDA 信号线必须配置为开漏模式,SCL 则因为要兼容高速模式,不需要开漏模式。两信号线都要接上拉电阻。

当外设工作在标准模式、快速和快速加强模式下时,无需额外的配置,只需要根据需要的波特率配置时钟分频。在高速模式下,主机要先发送一个主机码以通知从机准备高速模式,主机码不能发送 ACK 确认。如果 MCU 作为高速模式的从机,则不需要添加额外的软件支持。

I2C 外设支持在启动前配置为环回模式,在内部将发送和接收连接在一起用于调试。

驱动库函数

首先考虑最简单的作为主机的情况:No FIFO, No Interrupt and No DMA. 显然我们需要使能外设、配置外设、设置从机地址,最后开始发送或者接收。这个过程需要下列 API

void I2CMasterInitExpClk(uint32_t Base, uint32_t Clk, bool Fast);
void I2CMasterSlaveAddrSet(uint32_t Base, uint8_t SlaveAddr, bool Receive);
void I2CMasterDataPut(uint32_t Base, uint8_t Data);
void I2CMasterControl(uint32_t Base, uint32_t Cmd);
bool I2CMasterBusBusy(uint32_t Base);

当希望从 I2C 总线读取数据时,I2CMasterSlaveAddrSet 函数的 Receive 参数应设置为真,反之为假。因此,如果希望先发送再接收,就需要重新设置从机地址。I2CMasterControl 函数调用后数据开始传输,根据 Cmd 参数的不同,可以配置为单字节传输、多字节传输、FIFO 等多种配置。使用 I2CMasterBusBusy 确认传输完成后,下面的两个 API 可用于检查传输错误和获取接收的数据。

uint32_t I2CMasterErr(uint32_t Base);
uint32_t I2CMasterDataGet(uint32_t Base);

再考虑最简单的从机情况。从机的任务比较简单,初始化后,驱动库函数提供了获取从机状态的 API,用户只需根据状态(例如主机向从机发送数据和主机要求从机发送数据)执行相应的操作即可。

void I2CSlaveInit(uint32_t Base, uint8_t Address);
uint32_t I2CSlaveStatus(uint32_t Base);
void I2CSlaveDataPut(uint32_t Base, uint8_t Data);
uint32_t I2CSlaveDataGet(uint32_t Base);

I2C 外设的中断、FIFO 与 DMA 操作待补充。

Quad Synchronous Serial Interface(QSSI)

概述

同步串行接口是一个广泛使用的串行通信协议,它最初被用作编码器接口的通信协议,后来应用范围逐渐扩展。与串行外设接口(SPI)不同,SSI 是一个差分、单工的协议,但 MSP432E4 的 QSSI 外设支持 SPI 模式。手册没有针对 SSI 差分的特性作出描述,仅给出了 TI SSI 协议帧格式,本节内容着重介绍 QSSI 的 SPI 模式。

MSP432E4 系列的 QSSI 外设支持双数据线的 BiSSI 和四数据线的 QSSI 以提供更高的数据交换速度。QSSI 外设可以作为 SSI 的主机或者从机与包含 Freescale SPI 接口或者 TI SSI 接口的外设进行通信。数据格式方面,支持 4~16bit 的数据帧大小,SPI 模式下支持配置时钟电平和时钟相位。

QSSI 外设具有 16bit 宽度的 FIFO 作为发送和接收的缓冲。发送时处理器通过数据寄存器 SSIDR 访问 FIFO,再从对应的引脚发送出去。在从机模式下如果 FIFO 空但主机开始传输,从机会发送 FIFO 存放的最后八个数据。如果发送的 FIFO 非满而开始传输,则发送完现有数据后会发送 0 填补(有疑问,待补充)。接受时处理器同样通过数据寄存器 SSIDR 访问 FIFO。需要注意的是,时钟信号只在发送数据的时候产生,因此作为主机接收数据时必须向 SSIDR 写入虚拟的发送数据以开始时钟。

Bi-SSI 模式和 QSSI 模式下外设使用两线和四线进行半双工数据传输,此时数据帧只能使用 8bit 模式。关于这两种模式更详细的资料,请参阅技术参考手册。

SSInFSS 信号在 SPI 模式下充当了 Chip Select 的作用,在 TI SSI 下则作为帧开始和结束的标志。如普通的 SPI 外设一般,FSS 信号为高电平代表停止。根据时钟极性(CPOL,TI 称其为 SPO)和时钟相位(CPHA,TI 称其为 SPH)的不同,SPI 信号总共有四种帧格式,QSSI 外设支持所有的四种帧格式,但支持 MSB 作为传输的首位。关于 SPI 的更多内容可以参考技术参考手册绘制精美的波形图和网络资料。

驱动库函数

总体而言,QSSI 外设的基本使用较为简单。只需设置时钟、帧格式等配置,使能后即可收发数据。

void SSIConfigSetExpClk(uint32_t Base, uint32_t SSIClk, uint32_t Protocol, uint32_t Mode, 							uint32_t BitRate, uint32_t DataWidth);
void SSIEnable(uint32_t Base);
void SSIDataPut(uint32_t Base, uint32_t Data);
void SSIDataPutNonBlocking(uint32_t Base, uint32_t Data);
void SSIDataGet(uint32_t Base, uint32_t* Data);
int32_t SSIDataGetNonBlocking(uint32_t Base, uint32_t* Data);

需要注意的是 SSIConfigSetExpClkProtocol 参数,它有下列取值可选:SSI_FRF_MOTO_MODE_0, SSI_FRF_MOTO_MODE_1, SSI_FRF_MOTO_MODE_2, SSI_FRF_MOTO_MODE_3, or SSI_FRF_TI.

Polarity Phase       Mode
  0       0   SSI_FRF_MOTO_MODE_0
  0       1   SSI_FRF_MOTO_MODE_1
  1       0   SSI_FRF_MOTO_MODE_2
  1       1   SSI_FRF_MOTO_MODE_3

顺便吐槽一下 TI 的文档系统,技术参考手册当中还将 SPI 称作 Freescale SPI,转头在驱动库中就成了 Motorola® SPI

QSSI 外设的中断、DMA 和 FIFO 留待日后补充。

1-Wire Master Module

单总线主机模块能通过一条线同时提供电源和数据传输功能,MSP432E4 系列的单总线主机模块支持美信半导体 Dallas Semiconductor 的单总线协议。实际应用时,传输线被上拉到高电平,二进制位以低电平持续时间的差别进行传输,因此对应的 GPIO 将使用开漏模式。

单总线协议在进行数据传输前要先复位:主机首先下拉总线大于 480μs 后释放,随后检测总线是否被从机拉低,如果没有则说明总线上没有从机。当主机向从机发送数据时,根据主机拉低总线的时间确定二进制位;当从机向主机发送数据时,主机先拉低总线后释放,等待一段时间后检测总线电平确定二进制位。

Watchdog Timers

概述

MSP432E4 系列共有两个看门狗定时器,分别称为 Watchdog Timer 0 和 Watchdog Timer 1,它们之间除了使用的时钟源不同以外没有差别。Timer 0 使用的是系统时钟,Timer 1 则可以配置。因为 Timer 1 有独立的时钟源,可能与系统时钟不同步,Timer 1 的控制寄存器增加了一个 bit 确定对 Timer 1 寄存器的访问是否已经完成。在之前的访问没有完成时,不能进行下一次的访问。

看门狗定时器是一个 32bit 的重装载值可配置的向下计数定时器。当它第一次超时时,可以产生普通中断或者 NMI 中断;第二次超时时,如果第一次的中断没有被清除则触发复位。但是,软件可以配置不产生中断或不产生复位。与 MSP432P4 系列不同的是,看门狗定时器复位后处于禁用状态。

驱动库函数

看门狗的使用非常简单,主要包括使能外设,解锁外设寄存器,写入重装载值,使能复位功能,启动这几个步骤。

// Enable the Watchdog 0 peripheral
SysCtlPeripheralEnable(SYSCTL_PERIPH_WDOG0);

// Wait for the Watchdog 0 module to be ready.
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_WDOG0))
{
}

// Check to see if the registers are locked, and if so, unlock them.
if(WatchdogLockState(WATCHDOG0_BASE) == true)
{
    WatchdogUnlock(WATCHDOG0_BASE);
}

// Initialize the watchdog timer.
WatchdogReloadSet(WATCHDOG0_BASE, 0xFEEFEE);

// Enable the reset.
WatchdogResetEnable(WATCHDOG0_BASE);

// Enable the watchdog timer.
WatchdogEnable(WATCHDOG0_BASE);

// Wait for the reset to occur.
while(1)
{
}

Cyclical Redundancy Check(CRC)

概述

循环冗余校验是常用的数据通信校验算法。MSP432E4 系列的 CRC 计算模块使用 CRC 表加速 CRC 运算。

运算模块支持的 CRC 格式如下所示。其他支持的特性包括 MSB 和 LSB(发送顺序的不同显然会导致校验和的不同),可以从 DMA,FLASH 和代码中以字节输入和字输入数据。

  • CRC16-CCITT as used by ITU-T X.25
  • CRC16-IBM as used by USB and ANSI
  • CRC32-IEEE as used by IEEE 802.3 and MPEG 2
  • CEC32C as used by G.Hn

CRC 模块能在一个时钟周期内完成计算,因此向 CRC 输入寄存器写入数据后可以立刻读出。CRC 模块能接收 32bit 的字输入和 8bit 的字节输入,当使用字节输入时,有必要考虑字节顺序的问题,因此 CRC 模块允许控制字节序和比特序,详情可见技术参考手册。一般情况下假设有一个字节序列 {D0, D1, D2…D16…},那么,按字节模式应该写入下列序列 {0, 0, 0, D0}, {0, 0, 0, D1}, {0, 0, 0, D2}….按字模式应该写入下列序列{D3, D2, D1, D0}, {D7, D6, D5, D4}……

CRC 校验码的计算本质是使用固定的多项式对数据进行异或运算,它通常被直观的表示为原数据对指定除数的模二除法的余数。但是,考虑一个数据的开头是一串 0,使用模二除法计算得到的校验位显然与开头 0 的数量是无关的。为了解决这个问题,增加了余数初始值的概念,即下文提到的 seed

驱动库函数

CRC 模块的驱动库函数非常简单,包括了两个设置 API、写入和读取 API 以及一个大量数据处理 API

void CRCConfigSet(uint32_t Base, uint32_t CRCConfig);

包含了所有的设置项,如下所示

CRC Initialization Value

  • CRC_CFG_INIT_SEED - Initialize with seed value
  • CRC_CFG_INIT_0 - Initialize to all ‘0s’
  • CRC_CFG_INIT_1 - Initialize to all ‘1s’

Input Data Size

  • CRC_CFG_SIZE_8BIT - Input data size of 8 bits
  • CRC_CFG_SIZE_32BIT - Input data size of 32 bits

Post Process Reverse/Inverse

  • CRC_CFG_RESINV - Result inverse enable
  • CRC_CFG_OBR - Output reverse enable

Input Bit Reverse

  • CRC_CFG_IBR - Bit reverse enable

Endian Control

  • CRC_CFG_ENDIAN_SBHW - Swap byte in half-word
  • CRC_CFG_ENDIAN_SHW - Swap half-word

Operation Type

  • CRC_CFG_TYPE_P8005 - Polynomial 0x8005
  • CRC_CFG_TYPE_P1021 - Polynomial 0x1021
  • CRC_CFG_TYPE_P4C11DB7 - Polynomial 0x4C11DB7
  • CRC_CFG_TYPE_P1EDC6F41 - Polynomial 0x1EDC6F41
  • CRC_CFG_TYPE_TCPCHKSUM - TCP checksum
void CRCSeedSet(uint32_t Base, uint32_t Seed);

如果没有设置种子,将使用上次计算的结果作为种子。

void CRCDataWrite(uint32_t Base, uint32_t Data);
uint32_t CRCResultRead(uint32_t Base, bool Result);

写入和读出,

uint32_t CRCDataProcess(uint32_t Base, uint32_t* DataIn, uint32_t DataLength, bool Result);

使用指针传入指定长度的数据计算,布尔值 Result 决定是否对结果进行后处理,具体内容可能要参考 CRC-16 的具体算法。此处暂时不作进一步讨论。

Quadrature Encoder Interface(QEI) 正交编码器模块

External Peripheral Interface(EPI)

Hibernation Module

休眠模块集成了多种功能。首先,休眠模块集成了 32bit 的 RTC 定时器,计时精度达到 1/32768 秒,带有硬件日历功能。其次,休眠模块承担了电源管理的功能,包括外部供电、电池供电切换和低电压检测,休眠唤醒等功能。