前言
本文主要介紹了本人在學(xué)習(xí)使用 S32K144EVB中遇到的問題和解決辦法,由于本芯片是 NXP(原 freescale) 生產(chǎn)的基于 ARM M4F 內(nèi)核的32位芯片,主要適用對象是汽車 肩祥。目前在網(wǎng)絡(luò)上該芯片還沒有相關(guān)的中文學(xué)習(xí)資料,到筆者寫本文目前,網(wǎng)絡(luò)上能夠找到的資料只有開發(fā)板的電路圖和 Reference Manual 和該芯片配套的 IDE 內(nèi)置頭文件以及給出的 cookbook 例程,筆者也是在一步步摸索學(xué)習(xí)类茂,故本文為一個(gè)記錄性質(zhì)的文章耍属。
- 本文閱讀需要 C 語言基礎(chǔ)和一些簡單的單片機(jī)知識,筆者在之前曾經(jīng)開發(fā)過51單片機(jī)和 freescale 公司的 HC08GP32 單片機(jī)巩检,故可能會跳過一些基礎(chǔ)說明厚骗。
- 由于該芯片的 Manual 文件長達(dá) 1929 頁,全讀完肯定要浪費(fèi)很多時(shí)間兢哭,為了節(jié)約時(shí)間领舰,我就針對例程中給出的部分內(nèi)容查詢手冊相關(guān)內(nèi)容,進(jìn)行分析厦瓢。
- 本文針對 S32K144EVB-Q100X 開發(fā)板提揍,但基本原理都是相同的啤月。
Hello World
1. 本例程主要包含以下部分的操作:
- 配置 GPIO
- 根據(jù)按鍵狀態(tài)輸出 LED 燈信號
2. 使用到的電路圖:
3. 第一個(gè)例程的代碼如下:
#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. 代碼詳解
主要關(guān)注 main()
內(nèi)部
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
是一個(gè)指向固定地址的 PCC_Type
結(jié)構(gòu)體指針煮仇,他的固定地址是 (0x40065000u)
它對應(yīng)的 PCC_Type
結(jié)構(gòu)擁有一個(gè)116個(gè)無符號整型變量的數(shù)組 PCCn
根據(jù)注釋內(nèi)容判斷,這個(gè)指針的主要作用是用來改變 PCC (Peripheral Clock Controller)控制器內(nèi)部寄存器的值(下稱 PCC )谎仲,PCC 控制有關(guān)外部時(shí)鐘頻率相關(guān)的設(shè)置浙垫。
查詢了 Reference Manual 后得知,PCC 有三個(gè)功能:
- 時(shí)鐘界面開閉控制 CGC (Clock Gating Controller)
- *功能性時(shí)鐘源選擇控制(如果對應(yīng)模塊有時(shí)鐘源)
- *功能性時(shí)鐘分頻值控制(如果對應(yīng)模塊有分頻器)
在這個(gè)地方郑诺,我們僅僅用到第一個(gè)功能夹姥,也就是時(shí)鐘界面開關(guān)功能。在本文文末辙诞,我將給出 PCC 的內(nèi)存地圖辙售。
PCC 模塊給芯片上面每一個(gè)外圍模塊都設(shè)置了獨(dú)自的 PCC 內(nèi)部寄存器地址,用于控制以上的三個(gè)功能飞涂,PCC 內(nèi)的每一個(gè)寄存器都有一個(gè)時(shí)鐘界面開閉位 (CGC)旦部。
在每一個(gè)模塊使用前,必須打開該模塊的CGC (CGC = 1)较店,才能使用該模塊
如何打開士八?首先是尋址,在頭文件 "S32K144.h"
中已經(jīng)將 PCC 控制器的各個(gè)寄存器地址全部用宏定義了:
/* 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 對應(yīng)的地址梁呈。將其賦值為 PCC_PCCn_CGC_MASK
即可打開 CGC婚度。PCC_PCCn_CGC_MASK
在頭文件中定義為:
#define PCC_PCCn_CGC_MASK 0x40000000u
后面的 GPIO 端口方向控制類似 PCC 的控制,在這里使用了一個(gè) PTC 和 PTD 指針官卡,指向兩個(gè)固定地址的結(jié)構(gòu)體 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 輸出管腳的值,對應(yīng)邏輯值 |
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 將指定管腳的值反轉(zhuǎn) 讀取恒為零 |
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
我做個(gè)比喻寻咒,在 ARM 中哮翘,各個(gè)管腳就像是一個(gè)個(gè)等待工作的銀行柜臺窗口,可以存錢仔涩,也可以取錢忍坷,也可以借貸款,也可以辦理理財(cái)業(yè)務(wù),銀行不能一個(gè)業(yè)務(wù)開一個(gè)窗口佩研,所以每個(gè)窗口必須可以做很多事情柑肴,ARM 也是這樣,在有限的管腳上旬薯,需要進(jìn)行中斷晰骑,PWM,GPIO绊序,UART串口硕舆,SPI,I2C骤公,CAN 信息交流功能抚官,所以有些管腳有很多功能可以選擇,我們要使用某個(gè)功能就要自己進(jìn)行設(shè)置阶捆,設(shè)置的地方呢就在 PCR(Pin Controller Register) 這個(gè)寄存器里面凌节。
/** 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)
同樣每個(gè) PCR 都有 32 位,與之前不同的是洒试,這 32 位僅僅設(shè)置了一個(gè)管腳倍奢,而不是 32 個(gè)個(gè),這 32 位的功能如下:
Field | Name | Description |
---|---|---|
24 | ISF |
Interrupt Status Flag 0 管腳未檢測中斷 1 管腳檢測到中斷 |
19-16 | IRQC |
Interrupt Configuration 對應(yīng)管腳的設(shè)置如下 0000 ISF 關(guān)閉 0001 ISF標(biāo)志 和 DMA 請求垒棋,產(chǎn)生在上升沿 0010 ISF標(biāo)志 和 DMA 請求卒煞,產(chǎn)生在下降沿 0011 ISF標(biāo)志 和 DMA 請求,既在上升沿也在下降沿產(chǎn)生 0100 保留 0101 保留 0110 保留 0111 保留 1000 SF 標(biāo)志和中斷叼架,產(chǎn)生于邏輯 0 1001 ISF 標(biāo)志和中斷畔裕,產(chǎn)生于上升沿 1010 ISF 標(biāo)志和中斷,產(chǎn)生于下降沿 1100 ISF 標(biāo)志和中斷碉碉,產(chǎn)生于兩個(gè)沿 1100 ISF 標(biāo)志和中斷柴钻,產(chǎn)生于邏輯 1 1101 保留 1110 保留 1111 保留 |
15 | LK |
Lock Register 0 PCR 寄存器 0 到 15 位值不鎖定 1 PCR 寄存器 0 - 15 位值鎖定,直到下次重新啟動(dòng)才能夠更改 |
10-8 | MUX |
Pin Mux Control 管腳復(fù)用控制 不是所有的管腳都支持管腳復(fù)用垢粮,若支持贴届,則可以有以下的設(shè)置: 000 關(guān)閉管腳復(fù)用 001 功能 1 ,GPIO 010 功能 2 蜡吧,芯片特定功能 011 功能 3 毫蚓,芯片特定功能 100 功能 4 ,芯片特定功能 101 功能 5 昔善,芯片特定功能 110 功能 6 元潘,芯片特定功能 111 功能 7 ,芯片特定功能 |
6 | DSE |
Drive Strength Enable DSE 驅(qū)動(dòng)力加強(qiáng)設(shè)置君仆,此位在各種復(fù)用模式下都有效 0 低驅(qū)動(dòng)力模式翩概,如果管腳處于輸出模式 1 高驅(qū)動(dòng)力模式牲距,如果管腳處于輸出模式 |
4 | PFE |
Passive Filter Enable 被動(dòng)濾波功能,此位在各復(fù)用狀態(tài)下都有效 0 關(guān)閉被動(dòng)濾波 1 開啟被動(dòng)濾波钥庇,工作在輸入狀態(tài)下牍鞠,詳情參考濾波說明 |
1 | PE |
Pull Enable PE 使能上下拉電阻 0 無內(nèi)部上下拉電阻 1 有上下拉電阻 |
0 | PS |
Pull Select PE 選擇上下拉電阻 0 有上拉電阻 1 有下拉電阻 |
總結(jié)
如果要使用某個(gè) GPIO 端口,需要的準(zhǔn)備工作是:
- 使用 PCC 指針打開對應(yīng)的 PCCn[] 對應(yīng)的CGC 评姨,PCCn是 PCC 所指向的結(jié)構(gòu)體內(nèi)部的數(shù)組难述,固定地址,包含一共有116個(gè) uint32 類型寄存器吐句,將對應(yīng)的寄存器賦值為
PCC_PCCn_CGC_MASK
即可打開 CGC = 1 胁后。 - 設(shè)置 GPIO 的控制器中的 PDDR 寄存器,用于調(diào)整輸入/輸出方向嗦枢。此寄存器在一個(gè)類型為
GPIO_Type
的結(jié)構(gòu)中攀芯,一共有 5 個(gè)固定地址的結(jié)構(gòu),使用 PTA/PTB/PTC/PTD/PTE 訪問净宵。 - 設(shè)置 PORT.PCR 控制器敲才,關(guān)閉中斷裹纳,MUX 設(shè)置成為 001择葡,是否開啟被動(dòng)濾波。使用 PORTA/PORTB/PORTC/PORTD/PORTE 訪問剃氧。
- 讀取對應(yīng)的 PDIR (輸入)敏储,或者給 PDOR 賦值 (輸出)。使用 PTA/PTB/PTC/PTD/PTE 訪問朋鞍。
附錄:PCC 各個(gè)寄存器地圖
偏移地址 | 寄存器名稱 | 長度/位 (bit) | 權(quán)限 | 重啟默認(rèn)值 |
---|---|---|---|---|
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 |