美文网首页
S32K144EVB的学习历程(一)

S32K144EVB的学习历程(一)

作者: 夏华菌 | 来源:发表于2018-12-08 22:41 被阅读0次

    前言

    本文主要介绍了本人在学习使用 S32K144EVB中遇到的问题和解决办法,由于本芯片是 NXP(原 freescale) 生产的基于 ARM M4F 内核的32位芯片,主要适用对象是汽车 。目前在网络上该芯片还没有相关的中文学习资料,到笔者写本文目前,网络上能够找到的资料只有开发板的电路图和 Reference Manual 和该芯片配套的 IDE 内置头文件以及给出的 cookbook 例程,笔者也是在一步步摸索学习,故本文为一个记录性质的文章。

    • 本文阅读需要 C 语言基础和一些简单的单片机知识,笔者在之前曾经开发过51单片机和 freescale 公司的 HC08GP32 单片机,故可能会跳过一些基础说明。
    • 由于该芯片的 Manual 文件长达 1929 页,全读完肯定要浪费很多时间,为了节约时间,我就针对例程中给出的部分内容查询手册相关内容,进行分析。
    • 本文针对 S32K144EVB-Q100X 开发板,但基本原理都是相同的。

    Hello World

    1. 本例程主要包含以下部分的操作:

    • 配置 GPIO
    • 根据按键状态输出 LED 灯信号

    2. 使用到的电路图:

    Hello World block diagram

    3. 第一个例程的代码如下:

    #include "S32K144.h" /* include peripheral declarations S32K144 */
    #define PTD0 0 /* Port PTD0, bit 0: FRDM EVB output to blue LED */
    #define PTC12 12 /* Port PTC12, bit 12: FRDM EVB input from BTN0 [SW2] */
    void WDOG_disable (void){
    WDOG->CNT=0xD928C520; /*Unlock watchdog*/
    WDOG->TOVAL=0x0000FFFF; /*Maximum timeout value*/
    WDOG->CS = 0x00002100; /*Disable watchdog*/
    }
    int main(void) {
    int counter = 0;
    WDOG_disable();
    /* Enable clocks to peripherals (PORT modules) */
    PCC-> PCCn[PCC_PORTC_INDEX] = PCC_PCCn_CGC_MASK; /* Enable clock to PORT C */
    PCC-> PCCn[PCC_PORTD_INDEX] = PCC_PCCn_CGC_MASK; /* Enable clock to PORT D */
    /* Configure port C12 as GPIO input (BTN 0 [SW2] on EVB) */
    PTC->PDDR &= ~(1<<PTC12); /* Port C12: Data Direction= input (default) */
    PORTC->PCR[12] = 0x00000110; /* Port C12: MUX = GPIO, input filter enabled */
    /* Configure port D0 as GPIO output (LED on EVB) */
    PTD->PDDR |= 1<<PTD0; /* Port D0: Data Direction= output */
    PORTD->PCR[0] = 0x00000100; /* Port D0: MUX = GPIO */
    for(;;) {
    if (PTC->PDIR & (1<<PTC12)) { /* If Pad Data Input = 1 (BTN0 [SW2] pushed) */
    PTD-> PCOR |= 1<<PTD0; /* Clear Output on port D0 (LED on) */
    }
    else { /* If BTN0 was not pushed */
    PTD-> PSOR |= 1<<PTD0; /* Set Output on port D0 (LED off) */
    }
    counter++;
    }
    

    4. 代码详解

    主要关注 main() 内部

    PCC-> PCCn[PCC_PORTC_INDEX] = PCC_PCCn_CGC_MASK; /* Enable clock to PORT C */
    PCC-> PCCn[PCC_PORTD_INDEX] = PCC_PCCn_CGC_MASK; /* Enable clock to PORT D */
    

    这两句话使用的 PCC 等变量名都是在头文件 "S32K144.h" 中定义的:

    /** PCC - Size of Registers Arrays */
    #define PCC_PCCn_COUNT 116u
    
    /** PCC - Register Layout Typedef */
    typedef struct {
      __IO uint32_t PCCn[PCC_PCCn_COUNT];   /**< PCC Reserved Register 0..PCC CMP0 Register, array offset: 0x0, array step: 0x4 */
    } PCC_Type, *PCC_MemMapPtr;
    
    /** Peripheral PCC base address */
    #define PCC_BASE (0x40065000u)
    /** Peripheral PCC base pointer */
    #define PCC ((PCC_Type *)PCC_BASE)
    

    PCC 是一个指向固定地址的 PCC_Type结构体指针,他的固定地址是 (0x40065000u) 它对应的 PCC_Type 结构拥有一个116个无符号整型变量的数组 PCCn

    根据注释内容判断,这个指针的主要作用是用来改变 PCC (Peripheral Clock Controller)控制器内部寄存器的值(下称 PCC ),PCC 控制有关外部时钟频率相关的设置。
    查询了 Reference Manual 后得知,PCC 有三个功能:

    1. 时钟界面开闭控制 CGC (Clock Gating Controller)
    2. *功能性时钟源选择控制(如果对应模块有时钟源)
    3. *功能性时钟分频值控制(如果对应模块有分频器)

    在这个地方,我们仅仅用到第一个功能,也就是时钟界面开关功能。在本文文末,我将给出 PCC 的内存地图。
    PCC 模块给芯片上面每一个外围模块都设置了独自的 PCC 内部寄存器地址,用于控制以上的三个功能,PCC 内的每一个寄存器都有一个时钟界面开闭位 (CGC)。

    在每一个模块使用前,必须打开该模块的CGC (CGC = 1),才能使用该模块

    如何打开?首先是寻址,在头文件 "S32K144.h" 中已经将 PCC 控制器的各个寄存器地址全部用宏定义了:

    /* PCC index offsets */
    ...
    #define PCC_PORTA_INDEX 73
    #define PCC_PORTB_INDEX 74
    #define PCC_PORTC_INDEX 75
    #define PCC_PORTD_INDEX 76
    #define PCC_PORTE_INDEX 77
    ...
    

    可以看到 GPIO A/B/C/D/E 对应的地址。将其赋值为 PCC_PCCn_CGC_MASK 即可打开 CGC。PCC_PCCn_CGC_MASK 在头文件中定义为:

    #define PCC_PCCn_CGC_MASK 0x40000000u
    

    后面的 GPIO 端口方向控制类似 PCC 的控制,在这里使用了一个 PTC 和 PTD 指针,指向两个固定地址的结构体 GPIO_Type

    /** GPIO - Register Layout Typedef */
    typedef struct {
      __IO uint32_t PDOR;   /**< Port Data Output Register, offset: 0x0 */
      __O  uint32_t PSOR;   /**< Port Set Output Register, offset: 0x4 */
      __O  uint32_t PCOR;   /**< Port Clear Output Register, offset: 0x8 */
      __O  uint32_t PTOR;   /**< Port Toggle Output Register, offset: 0xC */
      __I  uint32_t PDIR;   /**< Port Data Input Register, offset: 0x10 */
      __IO uint32_t PDDR;   /**< Port Data Direction Register, offset: 0x14 */
      __IO uint32_t PIDR;   /**< Port Input Disable Register, offset: 0x18 */
    } GPIO_Type, *GPIO_MemMapPtr;
    
    /** Peripheral PTC base address */
    #define PTC_BASE (0x400FF080u)
    /** Peripheral PTC base pointer */
    #define PTC ((GPIO_Type *)PTC_BASE)
    /** Peripheral PTD base address */
    #define PTD_BASE (0x400FF0C0u)
    /** Peripheral PTD base pointer */
    #define PTD ((GPIO_Type *)PTD_BASE)
    

    GPIO 的控制器:

    Name Width
    (in bits)
    Access
    Port Data Output Register (PDOR) 32 RW
    Port Set Output Register (PSOR) 32 W
    Port Clear Output Register (PCOR) 32 W
    Port Toggle Output Register (PTOR) 32 W
    Port Data Input Register (PDIR) 32 R
    Port Data Direction Register (PDDR) 32 RW
    Port Input Disable Register (PIDR) 32 RW

    Port Data Output Register (PDOR)

    Field Name Description
    - PDO Port Data Output
    输出管脚的值,对应逻辑值

    Port Set Output Register (PSOR)

    Field Name Description
    - PTSO Port Set Output
    将指定管脚的值置 1
    读取恒为零

    Port Clear Output Register (PCOR)

    Field Name Description
    - PTCO Port Clear Output
    将指定管脚的值置 0
    读取恒为零

    Port Toggle Output Register (PTOR)

    Field Name Description
    - PTTO Port Toggle Output
    将指定管脚的值反转
    读取恒为零

    Port Data Input Register (PDIR)

    Field Name Description
    - PDI Port Data Input
    读取指定管脚的值

    Port Data Direction Register (PDDR)

    Field Name Description
    - PDD Port Data Direction
    0 Input
    1 Output

    Port Input Disable Register (PIDR)

    Field Name Description
    - PID Port Input Disable
    0 管脚正常输入
    1 管脚不能输入

    端口功能控制 PORT Controller Register

    我做个比喻,在 ARM 中,各个管脚就像是一个个等待工作的银行柜台窗口,可以存钱,也可以取钱,也可以借贷款,也可以办理理财业务,银行不能一个业务开一个窗口,所以每个窗口必须可以做很多事情,ARM 也是这样,在有限的管脚上,需要进行中断,PWM,GPIO,UART串口,SPI,I2C,CAN 信息交流功能,所以有些管脚有很多功能可以选择,我们要使用某个功能就要自己进行设置,设置的地方呢就在 PCR(Pin Controller Register) 这个寄存器里面。

    /** PORT - Register Layout Typedef */
    typedef struct {
      __IO uint32_t PCR[PORT_PCR_COUNT];    /**< Pin Control Register n, array offset: 0x0, array step: 0x4 */
      __O  uint32_t GPCLR;  /**< Global Pin Control Low Register, offset: 0x80 */
      __O  uint32_t GPCHR;  /**< Global Pin Control High Register, offset: 0x84 */
           uint8_t RESERVED_0[24];
      __IO uint32_t ISFR;   /**< Interrupt Status Flag Register, offset: 0xA0 */
           uint8_t RESERVED_1[28];
      __IO uint32_t DFER;   /**< Digital Filter Enable Register, offset: 0xC0 */
      __IO uint32_t DFCR;   /**< Digital Filter Clock Register, offset: 0xC4 */
      __IO uint32_t DFWR;   /**< Digital Filter Width Register, offset: 0xC8 */
    } PORT_Type, *PORT_MemMapPtr;
    
    /** Peripheral PORTC base address */
    #define PORTC_BASE (0x4004B000u)
    /** Peripheral PORTC base pointer */
    #define PORTC ((PORT_Type *)PORTC_BASE)
    /** Peripheral PORTD base address */
    #define PORTD_BASE (0x4004C000u)
    /** Peripheral PORTD base pointer */
    #define PORTD ((PORT_Type *)PORTD_BASE)
    

    同样每个 PCR 都有 32 位,与之前不同的是,这 32 位仅仅设置了一个管脚,而不是 32 个个,这 32 位的功能如下:

    Field Name Description
    24 ISF Interrupt Status Flag

    0 管脚未检测中断
    1 管脚检测到中断
    19-16 IRQC Interrupt Configuration 对应管脚的设置如下

    0000 ISF 关闭
    0001 ISF标志 和 DMA 请求,产生在上升沿
    0010 ISF标志 和 DMA 请求,产生在下降沿
    0011 ISF标志 和 DMA 请求,既在上升沿也在下降沿产生
    0100 保留
    0101 保留
    0110 保留
    0111 保留
    1000 SF 标志和中断,产生于逻辑 0
    1001 ISF 标志和中断,产生于上升沿
    1010 ISF 标志和中断,产生于下降沿
    1100 ISF 标志和中断,产生于两个沿
    1100 ISF 标志和中断,产生于逻辑 1
    1101 保留
    1110 保留
    1111 保留
    15 LK Lock Register

    0 PCR 寄存器 0 到 15 位值不锁定
    1 PCR 寄存器 0 - 15 位值锁定,直到下次重新启动才能够更改
    10-8 MUX Pin Mux Control 管脚复用控制

    不是所有的管脚都支持管脚复用,若支持,则可以有以下的设置:
    000 关闭管脚复用
    001 功能 1 ,GPIO
    010 功能 2 ,芯片特定功能
    011 功能 3 ,芯片特定功能
    100 功能 4 ,芯片特定功能
    101 功能 5 ,芯片特定功能
    110 功能 6 ,芯片特定功能
    111 功能 7 ,芯片特定功能
    6 DSE Drive Strength Enable DSE 驱动力加强设置,此位在各种复用模式下都有效

    0 低驱动力模式,如果管脚处于输出模式
    1 高驱动力模式,如果管脚处于输出模式
    4 PFE Passive Filter Enable 被动滤波功能,此位在各复用状态下都有效

    0 关闭被动滤波
    1 开启被动滤波,工作在输入状态下,详情参考滤波说明
    1 PE Pull Enable PE 使能上下拉电阻

    0 无内部上下拉电阻
    1 有上下拉电阻
    0 PS Pull Select PE 选择上下拉电阻

    0 有上拉电阻
    1 有下拉电阻

    总结

    如果要使用某个 GPIO 端口,需要的准备工作是:

    1. 使用 PCC 指针打开对应的 PCCn[] 对应的CGC ,PCCn是 PCC 所指向的结构体内部的数组,固定地址,包含一共有116个 uint32 类型寄存器,将对应的寄存器赋值为 PCC_PCCn_CGC_MASK 即可打开 CGC = 1 。
    2. 设置 GPIO 的控制器中的 PDDR 寄存器,用于调整输入/输出方向。此寄存器在一个类型为 GPIO_Type 的结构中,一共有 5 个固定地址的结构,使用 PTA/PTB/PTC/PTD/PTE 访问。
    3. 设置 PORT.PCR 控制器,关闭中断,MUX 设置成为 001,是否开启被动滤波。使用 PORTA/PORTB/PORTC/PORTD/PORTE 访问。
    4. 读取对应的 PDIR (输入),或者给 PDOR 赋值 (输出)。使用 PTA/PTB/PTC/PTD/PTE 访问。

    附录:PCC 各个寄存器地图

    偏移地址 寄存器名称 长度/位 (bit) 权限 重启默认值
    80h PCC FTFC Register (PCC_FTFC) 32 RW C000_0000h
    84h PCC DMAMUX Register (PCC_DMAMUX) 32 RW 8000_0000h
    90h PCC FlexCAN0 Register (PCC_FlexCAN0) 32 RW 8000_0000h
    94h PCC FlexCAN1 Register (PCC_FlexCAN1) 32 RW 8000_0000h
    98h PCC FTM3 Register (PCC_FTM3) 32 RW 8000_0000h
    9Ch PCC ADC1 Register (PCC_ADC1) 32 RW 8000_0000h
    ACh PCC FlexCAN2 Register (PCC_FlexCAN2) 32 RW 8000_0000h
    B0h PCC LPSPI0 Register (PCC_LPSPI0) 32 RW 8000_0000h
    B4h PCC LPSPI1 Register (PCC_LPSPI1) 32 RW 8000_0000h
    B8h PCC LPSPI2 Register (PCC_LPSPI2) 32 RW 8000_0000h
    C4h PCC PDB1 Register (PCC_PDB1) 32 RW 8000_0000h
    C8h PCC CRC Register (PCC_CRC) 32 RW 8000_0000h
    D8h PCC PDB0 Register (PCC_PDB0) 32 RW 8000_0000h
    DCh PCC LPIT Register (PCC_LPIT) 32 RW 8000_0000h
    E0h PCC FTM0 Register (PCC_FTM0) 32 RW 8000_0000h
    E4h PCC FTM1 Register (PCC_FTM1) 32 RW 8000_0000h
    E8h PCC FTM2 Register (PCC_FTM2) 32 RW 8000_0000h
    ECh PCC ADC0 Register (PCC_ADC0) 32 RW 8000_0000h
    F4h PCC RTC Register (PCC_RTC) 32 RW 8000_0000h
    100h PCC LPTMR0 Register (PCC_LPTMR0) 32 RW 8000_0000h
    124h PCC PORTA Register (PCC_PORTA) 32 RW 8000_0000h
    128h PCC PORTB Register (PCC_PORTB) 32 RW 8000_0000h
    12Ch PCC PORTC Register (PCC_PORTC) 32 RW 8000_0000h
    130h PCC PORTD Register (PCC_PORTD) 32 RW 8000_0000h
    134h PCC PORTE Register (PCC_PORTE) 32 RW 8000_0000h
    150h PCC SAI0 Register (PCC_SAI0) 32 RW 8000_0000h
    154h PCC SAI1 Register (PCC_SAI1) 32 RW 8000_0000h
    168h PCC FlexIO Register (PCC_FlexIO) 32 RW 8000_0000h
    184h PCC EWM Register (PCC_EWM) 32 RW 8000_0000h
    198h PCC LPI2C0 Register (PCC_LPI2C0) 32 RW 8000_0000h
    19Ch PCC LPI2C1 Register (PCC_LPI2C1) 32 RW 8000_0000h
    1A8h PCC LPUART0 Register (PCC_LPUART0) 32 RW 8000_0000h
    1ACh PCC LPUART1 Register (PCC_LPUART1) 32 RW 8000_0000h
    1B0h PCC LPUART2 Register (PCC_LPUART2) 32 RW 8000_0000h
    1B8h PCC FTM4 Register (PCC_FTM4) 32 RW 8000_0000h
    1BCh PCC FTM5 Register (PCC_FTM5) 32 RW 8000_0000h
    1C0h PCC FTM6 Register (PCC_FTM6) 32 RW 8000_0000h
    1C4h PCC FTM7 Register (PCC_FTM7) 32 RW 8000_0000h
    1CCh PCC CMP0 Register (PCC_CMP0) 32 RW 8000_0000h
    1D8h PCC QSPI Register (PCC_QSPI) 32 RW 8000_0000h
    1E4h PCC ENET Register (PCC_ENET) 32 RW 8000_0000h

    相关文章

      网友评论

          本文标题:S32K144EVB的学习历程(一)

          本文链接:https://www.haomeiwen.com/subject/iovchqtx.html