stm32官方例程在哪找_正点原子Linux第十一章模仿STM32驱动开发格式实验
1)資料下載:點(diǎn)擊資料即可下載
2)對(duì)正點(diǎn)原子Linux感興趣的同學(xué)可以加群討論:935446741
3)關(guān)注正點(diǎn)原子公眾號(hào),獲取最新資料更新
第十一章模仿STM32驅(qū)動(dòng)開(kāi)發(fā)格式實(shí)驗(yàn)
在上一章使用C語(yǔ)言編寫(xiě)LED燈驅(qū)動(dòng)的時(shí)候,每個(gè)寄存器的地址我們都需要寫(xiě)宏定義,使用起來(lái)非常的不方便。我們?cè)趯W(xué)習(xí)STM32的時(shí)候,可以使用“GPIOB->ODR”這種方式來(lái)給GPIOB的寄存器ODR賦值,因?yàn)樵赟TM32中同屬于一個(gè)外設(shè)的所有寄存器地址基本是相鄰的(有些會(huì)有保留寄存器)。因此我們可以借助C語(yǔ)言里面的結(jié)構(gòu)體成員地址遞增的特點(diǎn)來(lái)將某個(gè)外設(shè)的所有寄存器寫(xiě)入到一個(gè)結(jié)構(gòu)體里面,然后定義一個(gè)結(jié)構(gòu)體指針指向這個(gè)外設(shè)的寄存器基地址,這樣我們就可以通過(guò)這個(gè)結(jié)構(gòu)體指針來(lái)訪問(wèn)這個(gè)外設(shè)的所有寄存器。同理,I.MX6U也可以使用這種方法來(lái)定義外設(shè)寄存器,本章我們就模仿STM32里面的寄存器定義方式來(lái)編寫(xiě)I.MX6U的驅(qū)動(dòng),通過(guò)本章的學(xué)習(xí)也可以對(duì)STM32的寄存器定義方式有一個(gè)深入的認(rèn)識(shí)。
11.1模仿STM32寄存器定義
11.1.1 STM32寄存器定義簡(jiǎn)介
為了開(kāi)發(fā)方便,ST官方為STM32F103編寫(xiě)了一個(gè)叫做stm32f10x.h的文件,在這個(gè)文件里面定義了STM32F103所有外設(shè)寄存器,我們可以使用其定義的寄存器來(lái)進(jìn)行開(kāi)發(fā),比如我們可以用如下代碼來(lái)初始化一個(gè)GPIO:
GPIOE->CRL&=0XFF0FFFFF;
GPIOE->CRL|=0X00300000; //PE5推挽輸出
GPIOE->ODR|=1<<5; //PE5輸出高
上述代碼是初始化STM32的PE5這個(gè)GPIO為推挽輸出,需要配置的就是GPIOE的寄存器CRL和ODR,“GPIOE”的定義:
#define GPIOE ((GPIO_TypeDef *) GPIOE_BASE)
可以看出“GPIOE”是個(gè)宏定義,是一個(gè)指向地址GPIOE_BASE的結(jié)構(gòu)體指針,結(jié)構(gòu)體為GPIO_TypeDef,GPIO_TypeDef和GPIOE_BASE的定義如下:
typedef struct
{
__IO uint32_t CRL;
__IO uint32_t CRH;
__IO uint32_t IDR;
__IO uint32_t ODR;
__IO uint32_t BSRR;
__IO uint32_t BRR;
__IO uint32_t LCKR;
} GPIO_TypeDef;
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define PERIPH_BASE ((uint32_t)0x40000000)
上述定義中GPIO_TypeDef是個(gè)結(jié)構(gòu)體,結(jié)構(gòu)體里面的成員變量有CRL、CRH、IDR、ODR、BSRR、BRR和LCKR,這些都是GPIO的寄存器,每個(gè)成員變量都是32位(4字節(jié)),這些寄存器在結(jié)構(gòu)體中的位置都是按照其地址值從小到大排序的。GPIOE_BASE就是GPIOE的基地址,其為:
GPIOE_BASE=APB2PERIPH_BASE+0x1800
= PERIPH_BASE + 0x10000 + 0x1800
=0x40000000 + 0x10000 + 0x1800
=0x40011800
GPIOE_BASE的基地址為0x40011800,宏GPIOE指向這個(gè)地址,因此GPIOE的寄存器CRL的地址就是0X40011800,寄存器CRH的地址就是0X40011800+4=0X40011804,其他寄存器地址以此類推。我們要操作GPIOE的ODR寄存器的話就可以通過(guò)“GPIOE->ODR”來(lái)實(shí)現(xiàn),這個(gè)方法是借助了結(jié)構(gòu)體成員地址連續(xù)遞增的原理。
了解了STM32的寄存器定義以后,我們就可以參考其原理來(lái)編寫(xiě)I.MX6U的外設(shè)寄存器定義了。NXP官方并沒(méi)有為I.MX6UL編寫(xiě)類似stm32f10x.h這樣的文件,NXP只為I.MX6ULL提供了類似stm32f10x.h這樣的文件,名為MCIMX6Y2.h,但是I.MX6UL和I.MX6ULL幾乎一模一樣,所以文件MCIMX6Y2.h可以用在I.MX6UL上。關(guān)于文件MCIMX6Y2.h的移植我們?cè)谙乱徽轮v解,本章我們參考stm32f10x.h來(lái)編寫(xiě)一個(gè)簡(jiǎn)單的MCIMX6Y2.h文件。
11.1.2 I.MX6U寄存器定義
參考STM32的官方文件來(lái)編寫(xiě)I.MX6U的寄存器定義,比如IO復(fù)用寄存器組“IOMUX_SW_MUX_CTL_PAD_XX”,步驟如下:
1、編寫(xiě)外設(shè)結(jié)構(gòu)體
先將同屬于一個(gè)外設(shè)的所有寄存器編寫(xiě)到一個(gè)結(jié)構(gòu)體里面,如IO復(fù)用寄存器組的結(jié)構(gòu)體如下:
示例代碼11.1.2.1 寄存器IOMUX_SW_MUX_Type
/*
* IOMUX寄存器組
*/
1typedefstruct
2{
3 volatileunsignedint BOOT_MODE0;
4 volatileunsignedint BOOT_MODE1;
5 volatileunsignedint SNVS_TAMPER0;
6 volatileunsignedint SNVS_TAMPER1;
………
107 volatileunsignedint CSI_DATA00;
108 volatileunsignedint CSI_DATA01;
109 volatileunsignedint CSI_DATA02;
110 volatileunsignedint CSI_DATA03;
111 volatileunsignedint CSI_DATA04;
112 volatileunsignedint CSI_DATA05;
113 volatileunsignedint CSI_DATA06;
114 volatileunsignedint CSI_DATA07;
/*為了縮短代碼,其余IO復(fù)用寄存器省略 */
115}IOMUX_SW_MUX_Tpye;
上述結(jié)構(gòu)體IOMUX_SW_MUX_Type就是IO復(fù)用寄存器組,成員變量是每個(gè)IO對(duì)應(yīng)的復(fù)用寄存器,每個(gè)寄存器的地址是32位,每個(gè)成員都使用“volatile”進(jìn)行了修飾,目的是防止編譯器優(yōu)化。
2、定義IO復(fù)用寄存器組的基地址
根據(jù)結(jié)構(gòu)體IOMUX_SW_MUX_Type的定義,其第一個(gè)成員變量為BOOT_MODE0,也就是BOOT_MODE0這個(gè)IO的IO復(fù)用寄存器,查找I.MX6U的參考手冊(cè)可以得知其地址為0X020E0014,所以IO復(fù)用寄存器組的基地址就是0X020E0014,定義如下:
#define IOMUX_SW_MUX_BASE (0X020E0014)
3、定義訪問(wèn)指針
訪問(wèn)指針定義如下:
#define IOMUX_SW_MUX ((IOMUX_SW_MUX_Type *)IOMUX_SW_MUX_BASE)
通過(guò)上面三步我們就可以通過(guò)“IOMUX_SW_MUX->GPIO1_IO03”來(lái)訪問(wèn)GPIO1_IO03的IO復(fù)用寄存器了。同樣的,其他的外設(shè)寄存器都可以通過(guò)這三步來(lái)定義。
11.2 硬件原理分析
本章使用到的硬件資源和第八章一樣,就是一個(gè)LED0。
11.3實(shí)驗(yàn)程序編寫(xiě)
本實(shí)驗(yàn)對(duì)應(yīng)的例程路徑為:開(kāi)發(fā)板光盤-> 1、裸機(jī)例程->3_ledc_stm32。
創(chuàng)建VSCode工程,工作區(qū)名字為“l(fā)edc_stm32”,新建三個(gè)文件:start.S、main.c和imx6ul.h。其中start.S是匯編文件,start.S文件的內(nèi)容和第十章的start.S一樣,直接復(fù)制過(guò)來(lái)就可以。main.c 和imx6ul.h是C文件,完成以后如圖11.3.1所示:
圖11.3.1工程文件目錄
文件imx6ul.h用來(lái)存放外設(shè)寄存器定義,在imx6ul.h中輸入如下代碼:
示例代碼11.2.1 imx6ul.h文件代碼
/***************************************************************
Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名 : imx6ul.h
作者 : 左忠凱
版本 : V1.0
描述 : IMX6UL相關(guān)寄存器定義,參考STM32寄存器定義方法
其他 : 無(wú)
日志 : 初版V1.0 2019/1/3 左忠凱創(chuàng)建
**************************************************************/
/*
* 外設(shè)寄存器組的基地址
*/
1 #define CCM_BASE (0X020C4000)
2 #define CCM_ANALOG_BASE (0X020C8000)
3 #define IOMUX_SW_MUX_BASE (0X020E0014)
4 #define IOMUX_SW_PAD_BASE (0X020E0204)
5 #define GPIO1_BASE (0x0209C000)
6 #define GPIO2_BASE (0x020A0000)
7 #define GPIO3_BASE (0x020A4000)
8 #define GPIO4_BASE (0x020A8000)
9 #define GPIO5_BASE (0x020AC000)
10
11/*
12 * CCM寄存器結(jié)構(gòu)體定義,分為CCM和CCM_ANALOG
13 */
14typedefstruct
15{
16volatileunsignedint CCR;
17volatileunsignedint CCDR;
18volatileunsignedint CSR;
……
46volatileunsignedint CCGR6;
47volatileunsignedint RESERVED_3[1];
48volatileunsignedint CMEOR;
49} CCM_Type;
50
51typedefstruct
52{
53volatileunsignedint PLL_ARM;
54volatileunsignedint PLL_ARM_SET;
55volatileunsignedint PLL_ARM_CLR;
56volatileunsignedint PLL_ARM_TOG;
……
110volatileunsignedint MISC2;
111volatileunsignedint MISC2_SET;
112volatileunsignedint MISC2_CLR;
113volatileunsignedint MISC2_TOG;
114} CCM_ANALOG_Type;
115
116/*
117 * IOMUX寄存器組
118 */
119typedefstruct
120{
121volatileunsignedint BOOT_MODE0;
122volatileunsignedint BOOT_MODE1;
123volatileunsignedint SNVS_TAMPER0;
……
241volatileunsignedint CSI_DATA04;
242volatileunsignedint CSI_DATA05;
243volatileunsignedint CSI_DATA06;
244volatileunsignedint CSI_DATA07;
245}IOMUX_SW_MUX_Type;
246
247typedefstruct
248{
249volatileunsignedint DRAM_ADDR00;
250volatileunsignedint DRAM_ADDR01;
……
419volatileunsignedint GRP_DDRPKE;
420volatileunsignedint GRP_DDRMODE;
421volatileunsignedint GRP_DDR_TYPE;
422}IOMUX_SW_PAD_Type;
423
424/*
425 * GPIO寄存器結(jié)構(gòu)體
426 */
427typedefstruct
428{
429volatileunsignedint DR;
430volatileunsignedint GDIR;
431volatileunsignedint PSR;
432volatileunsignedint ICR1;
433volatileunsignedint ICR2;
434volatileunsignedint IMR;
435volatileunsignedint ISR;
436volatileunsignedint EDGE_SEL;
437}GPIO_Type;
438
439
440/*
441 * 外設(shè)指針
442 */
443 #define CCM ((CCM_Type *)CCM_BASE)
444 #define CCM_ANALOG ((CCM_ANALOG_Type *)CCM_ANALOG_BASE)
445 #define IOMUX_SW_MUX ((IOMUX_SW_MUX_Type *)IOMUX_SW_MUX_BASE)
446 #define IOMUX_SW_PAD ((IOMUX_SW_PAD_Type *)IOMUX_SW_PAD_BASE)
447 #define GPIO1 ((GPIO_Type *)GPIO1_BASE)
448 #define GPIO2 ((GPIO_Type *)GPIO2_BASE)
449 #define GPIO3 ((GPIO_Type *)GPIO3_BASE)
450 #define GPIO4 ((GPIO_Type *)GPIO4_BASE)
451 #define GPIO5 ((GPIO_Type *)GPIO5_BASE)
在編寫(xiě)寄存器組結(jié)構(gòu)體的時(shí)候注意寄存器的地址是否連續(xù),有些外設(shè)的寄存器地址可能不是連續(xù)的,會(huì)有一些保留地址,因此我們需要在結(jié)構(gòu)體中留出這些保留的寄存器。比如CCM的CCGR6寄存器地址為0X020C4080,而寄存器CMEOR的地址為0X020C4088。按照地址順序遞增的原理,寄存器CMEOR的地址應(yīng)該是0X020C4084,但是實(shí)際上CMEOR的地址是0X020C4088,相當(dāng)于中間跳過(guò)了0X020C4088-0X020C4080=8個(gè)字節(jié),如果寄存器地址連續(xù)的話應(yīng)該只差4個(gè)字節(jié)(32位),但是現(xiàn)在差了8個(gè)字節(jié),所以需要在寄存器CCGR6和CMEOR直接加入一個(gè)保留寄存器,這個(gè)就是“示例代碼11.3.1”中第47行RESERVED_3[1]的來(lái)源。如果不添加保留為來(lái)占位的話就會(huì)導(dǎo)致寄存器地址錯(cuò)位!
main.c文件中輸入如下所示內(nèi)容:
示例代碼11.3.2 main.c文件代碼
1 #include "imx6ul.h"
2
3/*
4 * @description : 使能I.MX6U所有外設(shè)時(shí)鐘
5 * @param : 無(wú)
6 * @return : 無(wú)
7 */
8void clk_enable(void)
9{
10 CCM->CCGR0 =0XFFFFFFFF;
11 CCM->CCGR1 =0XFFFFFFFF;
12 CCM->CCGR2 =0XFFFFFFFF;
13 CCM->CCGR3 =0XFFFFFFFF;
14 CCM->CCGR4 =0XFFFFFFFF;
15 CCM->CCGR5 =0XFFFFFFFF;
16 CCM->CCGR6 =0XFFFFFFFF;
17}
18
19/*
20 * @description : 初始化LED對(duì)應(yīng)的GPIO
21 * @param : 無(wú)
22 * @return : 無(wú)
23 */
24void led_init(void)
25{
26/* 1、初始化IO復(fù)用 */
27 IOMUX_SW_MUX->GPIO1_IO03 =0X5;/* 復(fù)用為GPIO1_IO03 */
28
29
30/* 2、配置GPIO1_IO03的IO屬性
31 *bit 16:0 HYS關(guān)閉
32 *bit [15:14]: 00 默認(rèn)下拉
33 *bit [13]: 0 kepper功能
34 *bit [12]: 1 pull/keeper使能
35 *bit [11]: 0 關(guān)閉開(kāi)路輸出
36 *bit [7:6]: 10 速度100Mhz
37 *bit [5:3]: 110 R0/6驅(qū)動(dòng)能力
38 *bit [0]: 0 低轉(zhuǎn)換率
39 */
40 IOMUX_SW_PAD->GPIO1_IO03 =0X10B0;
41
42
43/* 3、初始化GPIO */
44 GPIO1->GDIR =0X0000008;/* GPIO1_IO03設(shè)置為輸出 */
45
46/* 4、設(shè)置GPIO1_IO03輸出低電平,打開(kāi)LED0 */
47 GPIO1->DR &=~(1<<3);
48
49}
50
51/*
52 * @description : 打開(kāi)LED燈
53 * @param : 無(wú)
54 * @return : 無(wú)
55 */
56void led_on(void)
57{
58/* 將GPIO1_DR的bit3清零 */
59 GPIO1->DR &=~(1<<3);
60}
61
62/*
63 * @description : 關(guān)閉LED燈
64 * @param : 無(wú)
65 * @return : 無(wú)
66 */
67void led_off(void)
68{
69/* 將GPIO1_DR的bit3置1 */
70 GPIO1->DR |=(1<<3);
71}
72
73/*
74 * @description : 短時(shí)間延時(shí)函數(shù)
75 * @param - n : 要延時(shí)循環(huán)次數(shù)(空操作循環(huán)次數(shù),模式延時(shí))
76 * @return : 無(wú)
77 */
78void delay_short(volatileunsignedint n)
79{
80while(n--){}
81}
82
83/*
84 * @description : 延時(shí)函數(shù),在396Mhz的主頻下
85 * 延時(shí)時(shí)間大約為1ms
86 * @param - n : 要延時(shí)的ms數(shù)
87 * @return : 無(wú)
88 */
89void delay(volatileunsignedint n)
90{
91while(n--)
92{
93 delay_short(0x7ff);
94}
95}
96
97/*
98 * @description : mian函數(shù)
99 * @param : 無(wú)
100 * @return : 無(wú)
101 */
102int main(void)
103{
104 clk_enable(); /* 使能所有的時(shí)鐘 */
105 led_init(); /* 初始化led */
106
107while(1) /* 死循環(huán) */
108{
109 led_off(); /* 關(guān)閉LED */
110 delay(500); /* 延時(shí)500ms */
111
112 led_on(); /* 打開(kāi)LED */
113 delay(500); /* 延時(shí)500ms */
114}
115
116return0;
117}
main.c中7個(gè)函數(shù),這7個(gè)函數(shù)的含義和第十章中的main.c文件一樣,只是函數(shù)體寫(xiě)法變了,寄存器的訪問(wèn)采用imx6ul.h中定義的外設(shè)指針。比如第27行設(shè)置GPIO1_IO03的復(fù)用功能就可以通過(guò)“IOMUX_SW_MUX->GPIO1_IO03”來(lái)給寄存SW_MUX_CTL_PAD_GPIO1_IO03賦值。
11.4編譯下載驗(yàn)證
11.4.1 編寫(xiě)Makefile和鏈接腳本
Makefile文件的內(nèi)容基本和第十章的Makefile一樣,如下:
示例代碼11.4.1 Makefile文件代碼
1 objs:= start.o main.o
2
3 ledc.bin:$(objs)
4 arm-linux-gnueabihf-ld -Timx6ul.lds -o ledc.elf $^
5 arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@
6 arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis
7
8 %.o:%.s
9 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
10
11 %.o:%.S
12 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
13
14 %.o:%.c
15 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
16
17 clean:
18 rm -rf *.o ledc.bin ledc.elf ledc.dis
鏈接腳本imx6ul.lds的內(nèi)容和上一章一樣,可以直接使用上一章的鏈接腳本文件。
11.4.2編譯下載
使用Make命令編譯代碼,編譯成功以后使用軟件imxdownload將編譯完成的ledc.bin文件下載到SD卡中,命令如下:
chmod 777 imxdownload //給予imxdownload可執(zhí)行權(quán)限,一次即可
./imxdownload ledc.bin /dev/sdd //燒寫(xiě)到SD卡中
燒寫(xiě)成功以后將SD卡插到開(kāi)發(fā)板的SD卡槽中,然后復(fù)位開(kāi)發(fā)板,如果代碼運(yùn)行正常的話LED0就會(huì)以500ms的時(shí)間間隔亮滅,實(shí)驗(yàn)現(xiàn)象和上一章一樣。
總結(jié)
以上是生活随笔為你收集整理的stm32官方例程在哪找_正点原子Linux第十一章模仿STM32驱动开发格式实验的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: truncate数据后回收空间_Trun
- 下一篇: python的表达式3or5_Pytho