OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5178|回复: 0

【正点原子Linux连载】第十二章官方SDK移植试验--摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

[复制链接]

1140

主题

1152

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4895
金钱
4895
注册时间
2019-5-8
在线时间
1248 小时
发表于 2019-11-30 15:56:19 | 显示全部楼层 |阅读模式
本帖最后由 正点原子01 于 2019-12-7 12:18 编辑

1)实验平台:正点原子阿尔法Linux开发板
2)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html
3)本实例源码下载: 官方SDK移植试验.zip (11.5 MB, 下载次数: 13)
4)对正点原子Linux感兴趣的同学可以加群讨论:935446741
5)关注正点原子公众号,获取最新资料更新
QQ图片20191129104007.png
第十二章官方SDK移植试验


       在上一章中,我们参考ST官方给STM32编写的stm32f10x.h来自行编写I.MX6U的寄存器定义文件。自己编写这些寄存器定义不仅费时费力,没有任何意义,而且很容易写错,幸好NXP官方为I.MX6ULL编写了SDK包,在SDK包里面NXP已经编写好了寄存器定义文件,所以我们可以直接移植SDK包里面的文件来用。虽然NXP是为I.MX6ULL编写的SDK包,但是I.MX6UL也是可以使用的!本章我们就来讲解如何移植SDK包里面重要的文件,方便我们的开发。

12.1 I.MX6ULL官方SDK包简介
       NXP针对I.MX6ULL编写了一个SDK包,这个SDK包就类似于STM32STD库或者HAL库,这个SDK包提供了WindowsLinux两种版本,分别针对主机系统是WindowsLinux。因为我们是在Windows下使用Source Insight来编写代码的,因此我们使用的是Windows版本的。Windows版本SDK里面的例程提供了IAR版本,肯定有人会问既然NXP提供了IAR版本的SDK,那我们为什么不用IAR来完成裸机试验,偏偏要用复杂的GCC?因为我们要从简单的裸机开始掌握Linux下的GCC开发方法,包括Ubuntu操作系统的使用、Makefile的编写、shell等等。如果为了偷懒而使用IAR开发裸机的话,那么后续学习Uboot移植、Linux移植和Linux驱动开发就会很难上手,因为开发环境都不熟悉!再者,不是所有的半导体厂商都会为Cortex-A架构的芯片编写裸机SDK包,我使用过那么多的Cotex-A系列芯片,也就发现了NXPI.MX6ULL编写了裸机SDK包。而且去NXP官网看一下,会发现只有I.MX6ULL这一款Cotex-A内核的芯片有裸机SDK包,NXP的其它Cotex-A芯片都没有。说明在NXP的定位里面,I.MX6ULL就是一个Cotex-A内核的高端单片机,定位类似STSTM32H7。说这么多的目的就是想告诉大家,使用Cortex-A内核芯片的时候不要想着有类似STM32库一样的东西,I.MX6ULL是一个特例,基本所有的Cortex-A内核的芯片都不会提供裸机SDK包。因此在使用STM32的时候那些用起来很顺手的库文件,在Cotex-A芯片下基本都需要我们自行编写,比如.s启动文件、寄存器定义等等。
       因为本教程是教大家Linux驱动开发入门的,本教程需要尽可能的降低入门难度,这也是为什么本教程会选择I.MX6U芯片的一个重要的原因,因为其提供了I.MX6ULL的裸机SDK包,大家上手会很容易。I.MX6ULLSDK包在NXP官网下载,下载界面如图12.1.1所示:
image892.png
12.1.1 I.MX6ULL SDK包下载界面
       我们下载图12.1.1中的WIN版本SDK,也就是“SDK2.2_iMX6ULL_WIN”,我们已经下载好放到光盘中,路径为:开发板光盘-> 7I.MX6U参考资料->3I.MX6ULLSDK->SDK_2.2_MCIM6ULL_RFP_Win.exe。双击SDK_2.2_MCIM6ULL_RFP_Win.exe安装SDK包,安装的时候需要设置好安装位置,安装完成以后的SDK包如图12.1.2所示:
image894.png
12.1.2 SDK
       我们本教程不是讲解SDK包如何开发的,我们只是需要SDK包里面的几个文件,所以就不去详细的讲解这个SDK包了,感兴趣的可以看一下,所有的例程都在boards这个文件夹里面。我们重点是需要SDK包里面与寄存器定义相关的文件,一共需要如下三个文件:
       fsl_common.h:位置为SDK_2.2_MCIM6ULL\devices\MCIMX6Y2\drivers\fsl_common.h
       fsl_iomuxc.h:  位置为SDK_2.2_MCIM6ULL\devices\MCIMX6Y2\drivers\fsl_iomuxc.h
       MCIMX6Y2.h:位置为SDK_2.2_MCIM6ULL\devices\MCIMX6Y2\MCIMX6YH2.h
       整个SDK包我们就需要上面这三个文件,把这三个文件准备好,我们后面移植要用。
12.2硬件原理图分析
本章使用到的硬件资源和第八章一样,就是一个LED0。
12.3试验程序编写
本实验对应的例程路径为:开发板光盘-> 1、裸机例程->4_ledc_sdk。
12.3.1 SDK文件移植
       使用VSCode新建工程,将fsl_common.hfsl_iomuxc.hMCIMX6Y2.h这三个文件拷贝到工程中,这三个文件直接编译的话肯定会出错的!需要对其做删减,因为这三个文件里面的代码都比较大,所以就不详细列出这三个文件删减以后的内容了。大家可以参考我们提供的裸机例程来修改这三个文件,很简单的。修改完成以后的工程目录如图12.3.1.1所示:
image896.png
12.3.1.1工程目录
12.3.2 创建cc.h文件
       新建一个名为cc.h的头文件,cc.h里面存放一些SDK库文件需要使用到的数据类型,在cc.h里面输入如下代码:
示例代码12.3.2.1 cc.h文件代码
  1.   #ifndef __CC_H
  2.   #define __CC_H
  3. /***************************************************************
  4.   Copyright ? zuozhongkai Co., Ltd. 1998-2019.All rights reserved.
  5. 文件名    :    cc.h
  6. 作者      : 左忠凯
  7. 版本      : V1.0
  8. 描述      : 有关变量类型的定义,NXP官方SDK的一些移植文件会用到。
  9. 其他      : 无
  10. 日志      : 初版V1.0 2019/1/3左忠凯创建
  11. ***************************************************************/

  12. /*
  13.   * 自定义一些数据类型供库文件使用
  14.   */
  15. #define     __I    volatile
  16. #define     __O    volatile
  17. #define     __IO   volatile

  18. #define      ON     1
  19. #define      OFF    0

  20. typedefsigned   char          int8_t;
  21. typedefsigned   short  int int16_t;
  22. typedefsigned   int int32_t;
  23. typedefunsigned char   uint8_t;
  24. typedefunsigned short  int uint16_t;
  25. typedefunsigned int uint32_t;
  26. typedefunsigned long   long   uint64_t;
  27. typedefsigned   char   s8;
  28. typedefsigned   short  int s16;
  29. typedefsigned   int s32;
  30. typedefsigned   long   long   int s64;
  31. typedefunsigned char   u8;
  32. typedefunsigned short  int u16;
  33. typedefunsigned int u32;
  34. typedefunsigned long   long   int u64;

  35. #endif
复制代码
       cc.h文件中我们定义了很多的数据类型,因为有些第三方库会用到这些变量类型。
12.3.3编写实验代码
       新建start.Smain.c这两个文件,start.S文件的内容和上一章一样,直接复制过来就可以,创建完成以后工程目录如图12.3.3.1所示:
image898.png
12.3.3.1 工程目录文件
       main.c中输入如下所示代码:
示例代码12.3.3.1 main.c文件代码
  1. /**************************************************************
  2. Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rightsreserved.
  3. 文件名   : mian.c
  4. 作者     : 左忠凯
  5. 版本     : V1.0
  6. 描述     : I.MX6U开发板裸机实验4 使用NXP提供的I.MX6ULL官方IAR SDK包开发
  7. 其他     : 前面其他所有实验中,寄存器定义都是我们自己手写的,但是I.MX6U
  8. 的寄存器有很多,全部自己写太费时间,而且没意义。NXP官方提供了
  9. 针对I.MX6ULL的SDK开发包,是基于IAR环境的,这个SDK包里面已经提
  10. 供了I.MX6ULL所有相关寄存器定义,虽然是针对I.MX6ULL编写的,但是同样
  11. 适用于I.MX6UL。本节我们就将相关的寄存器定义文件移植到Linux环境下,
  12. 要移植的文件有:
  13.           fsl_common.h
  14.           fsl_iomuxc.h
  15.           MCIMX6Y2.h
  16. 自定义文件 cc.h
  17. 日志     : 初版V1.0 2019/1/3 左忠凯创建
  18. **************************************************************/
  19.    #include "fsl_common.h"
  20.    #include "fsl_iomuxc.h"
  21.    #include "MCIMX6Y2.h"

  22. /*
  23.     * @description : 使能I.MX6U所有外设时钟
  24.     * @param       : 无
  25.     * @return      : 无
  26.     */
  27. void clk_enable(void)
  28. {
  29.       CCM->CCGR0 =0XFFFFFFFF;
  30.       CCM->CCGR1 =0XFFFFFFFF;

  31.       CCM->CCGR2 =0XFFFFFFFF;
  32.       CCM->CCGR3 =0XFFFFFFFF;
  33.       CCM->CCGR4 =0XFFFFFFFF;
  34.       CCM->CCGR5 =0XFFFFFFFF;
  35.       CCM->CCGR6 =0XFFFFFFFF;

  36. }

  37. /*
  38.    * @description : 初始化LED对应的GPIO
  39.    * @param       : 无
  40.    * @return      : 无
  41.    */
  42. void led_init(void)
  43. {
  44. /* 1、初始化IO复用 */
  45.       IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,0);

  46. /* 2、、配置GPIO1_IO03的IO属性
  47.        *bit 16:0 HYS关闭
  48.        *bit [15:14]: 00 默认下拉
  49.        *bit [13]: 0 kepper功能
  50.        *bit [12]: 1 pull/keeper使能
  51.        *bit [11]: 0 关闭开路输出
  52.        *bit [7:6]: 10 速度100Mhz
  53.        *bit [5:3]: 110 R0/6驱动能力
  54.        *bit [0]: 0 低转换率
  55.        */
  56.       IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,0X10B0);

  57. /* 3、初始化GPIO,设置GPIO1_IO03设置为输出  */
  58.       GPIO1->GDIR |=(1<<3);

  59. /* 4、设置GPIO1_IO03输出低电平,打开LED0 */
  60.       GPIO1->DR &=~(1<<3);
  61. }

  62. /*
  63.    * @description : 打开LED灯
  64.    * @param       : 无
  65.    * @return      : 无
  66.    */
  67. void led_on(void)
  68. {
  69. /* 将GPIO1_DR的bit3清零     */
  70.       GPIO1->DR &=~(1<<3);
  71. }

  72. /*
  73.    * @description : 关闭LED灯
  74.    * @param       : 无
  75.    * @return      : 无
  76.    */
  77. void led_off(void)
  78. {
  79. /* 将GPIO1_DR的bit3置1 */
  80.       GPIO1->DR |=(1<<3);
  81. }

  82. /*
  83.    * @description : 短时间延时函数
  84.    * @param - n  : 要延时循环次数(空操作循环次数,模式延时)
  85.    * @return      : 无
  86.    */
  87. void delay_short(volatileunsignedint n)
  88. {
  89. while(n--){}
  90. }

  91. /*
  92.    * @description : 延时函数,在396Mhz的主频下
  93.    *                  延时时间大约为1ms
  94.    * @param - n   : 要延时的ms数
  95.    * @return       : 无
  96.    */
  97. void delay(volatileunsignedint n)
  98. {
  99. while(n--)
  100. {
  101.           delay_short(0x7ff);
  102. }
  103. }

  104. /*
  105.    * @description : mian函数
  106.   * @param      : 无
  107.   * @return     : 无
  108.   */
  109. int main(void)
  110. {
  111.      clk_enable(); /* 使能所有的时钟   */
  112.      led_init();   /* 初始化led        */

  113. while(1)   /* 死循环   */
  114. {
  115.          led_off(); /* 关闭LED          */
  116.          delay(500); /* 延时500ms        */

  117.          led_on();  /* 打开LED          */
  118.          delay(500); /* 延时500ms        */
  119. }

  120. return0;
  121. }
复制代码
    和上一章一样,main.c7个函数,这7个函数的含义都一样,只是本例程我们使用的是移植好的NXP官方SDK里面的寄存器定义。main.c文件的这7个函数的内容都很简单,前面都讲过很多次了,我们重点来看一下led_init函数中的第31行和第43行,这两行的内容如下:
  1. IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,         0);   
  2. IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,      0X10B0);
复制代码
    这里使用了两个函数IOMUXC_SetPinMuxIOMUXC_SetPinConfig,其中函数IOMUXC_SetPinMux是用来设置IO复用功能的,最终肯定设置的是寄存器“IOMUXC_SW_MUX_CTL_PAD_XX”。函数IOMUXC_SetPinConfig设置的是IO的上下拉、速度等的,也就是寄存器“IOMUXC_SW_PAD_CTL_PAD_XX”,所以上面两个函数其实就是上一章中的:
  1. IOMUX_SW_MUX->GPIO1_IO03 = 0X5;
  2. IOMUX_SW_PAD->GPIO1_IO03 = 0X10B0;
复制代码
       函数IOMUXC_SetPinMux在文件fsl_iomuxc.h中定义,函数源码如下:
  1. static inline void IOMUXC_SetPinMux(uint32_t muxRegister,
  2.                                     uint32_t muxMode,
  3.                                     uint32_t inputRegister,
  4.                                     uint32_t inputDaisy,
  5.                                     uint32_t configRegister,
  6.                                     uint32_t inputOnfield)
  7. {
  8.     *((volatile uint32_t *)muxRegister) =
  9.         IOMUXC_SW_MUX_CTL_PAD_MUX_MODE(muxMode) |
  10. IOMUXC_SW_MUX_CTL_PAD_SION(inputOnfield);

  11.     if (inputRegister)
  12.     {
  13.         *((volatile uint32_t *)inputRegister) =
  14. IOMUXC_SELECT_INPUT_DAISY(inputDaisy);
  15.     }
  16. }
复制代码
       函数IOMUXC_SetPinMux6个参数,这6个参数的函数如下:
       muxRegisterIO的复用寄存器地址,比如GPIO1_IO03IO复用寄存器SW_MUX_CTL_PAD_GPIO1_IO03的地址为0X020E0068
       muxMode   IO复用值,也就是ALT0~ALT8,对应数字0~8,比如要将GPIO1_IO03设置为GPIO功能的话此参数就要设置为5
       inputRegister外设输入IO选择寄存器地址,有些IO在设置为其他的复用功能以后还需要设置IO输入寄存器,比如GPIO1_IO03要复用为UART1_RX的话还需要设置寄存器UART1_RX_DATA_SELECT_INPUT,此寄存器地址为0X020E0624
       inputDaisy寄存器inputRegister的值,比如GPIO1_IO03要作为UART1_RX引脚的话此参数就是1
       configRegister:未使用,函数IOMUXC_SetPinConfig会使用这个寄存器。
       inputOnfieldIO软件输入使能,以GPIO1_IO03为例就是寄存器SW_MUX_CTL_PAD_GPIO1_IO03SION(bit4)。如果需要使能GPIO1_IO03的软件输入功能的话此参数应该为1,否则的话就为0
       IOMUXC_SetPinMux的函数体很简单,就是根据参数对寄存器muxRegisterinputRegister进行赋值。在“示例代码12.3.3.1”中的31行使用此函数将GPIO1_IO03的复用功能设置为GPIO,如下:
  1. IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,  0);
复制代码
       第一次看到上面代码的时候肯定会奇怪,为何只有两个参数?不是应该6个参数的吗?不要着急,先看一个IOMUXC_GPIO1_IO03_GPIO1_IO03是个什么玩意。这是个宏,在文件fsl_iomuxc.h中有定义,NXPSDK库将一个IO的所有复用功能都定义了一个宏,比如GPIO1_IO03就有如下9个宏定义:
  1. IOMUXC_GPIO1_IO03_I2C1_SDA
  2. IOMUXC_GPIO1_IO03_GPT1_COMPARE3                  
  3. IOMUXC_GPIO1_IO03_USB_OTG2_OC                        
  4. IOMUXC_GPIO1_IO03_USDHC1_CD_B                     
  5. IOMUXC_GPIO1_IO03_GPIO1_IO03                       
  6. IOMUXC_GPIO1_IO03_CCM_DI0_EXT_CLK               
  7. IOMUXC_GPIO1_IO03_SRC_TESTER_ACK                    
  8. IOMUXC_GPIO1_IO03_UART1_RX                     
  9. IOMUXC_GPIO1_IO03_UART1_TX <span style="background-color: rgb(255, 255, 255);">                     </span>
复制代码
       上面9个宏定义分别对应着GPIO1_IO03的九种复用功能,比如复用为GPIO的宏定义就是:
       将这个宏带入到“示例代码12.3.3.1”的31行以后就是:
  1. IOMUXC_SetPinMux (0x020E0068U, 0x5U, 0x00000000U,0x0U, 0x020E02F4U,       0);
复制代码
       这样就与函数IOMUXC_SetPinMux6个参数对应起来了,如果我们要将GPIO1_IO03复用为I2C1_SDA的话就可以使用如下代码:
  1. IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_I2C1_SDA,  0);
复制代码
       函数IOMUXC_SetPinMux就讲解到这里,接下来看一下函数IOMUXC_SetPinConfig,此函数同样在文件fsl_iomuxc.h中有定义,函数源码如下:
  1. static inline void IOMUXC_SetPinConfig(uint32_tmuxRegister,
  2.                                        uint32_tmuxMode,
  3.                                        uint32_t inputRegister,
  4.                                        uint32_tinputDaisy,
  5.                                        uint32_tconfigRegister,
  6.                                        uint32_tconfigValue)
  7. {
  8.     if(configRegister)
  9.     {
  10.         *((volatile uint32_t *)configRegister) =configValue;
  11.     }
  12. }
复制代码
       函数IOMUXC_SetPinConfig6个参数,其中前五个参数和函数IOMUXC_SetPinMux一样,但是此函数只使用了参数configRegisterconfigValuecofigRegister参数是IO配置寄存器地址,比如GPIO1_IO03IO配置寄存器为IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03,其地址为0X020E02F4,参数configValue就是要写入到寄存器configRegister的值。同理,“示例代码12.3.3.1”的43行展开以后就是:
  1. IOMUXC_SetPinConfig(0x020E0068U, 0x5U, 0x00000000U,0x0U, 0x020E02F4U, 0X10B0);
复制代码
       根据函数IOMUXC_SetPinConfig的源码可以知道,上面函数就是将寄存器0x020E02F4的值设置为0X10B0。函数IOMUXC_SetPinMuxIOMUXC_SetPinConfig就讲解到这里,我们以后就可以使用这两个函数来方便的配置IO的复用功能和IO配置。
       main.c就讲到这里,基本和上一章一样,只是我们使用了NXP官方写好的寄存器定义,另外中断讲解了函数IOMUXC_SetPinMuxIOMUXC_SetPinConfig
12.4编译下载验证12.4.1编写Makefile和链接脚本
       新建Makefile文件,Makefile文件内容如下:
示例代码12.4.1.1 Makefile文件代码
  1. 1  CROSS_COMPILE  ?= arm-linux-gnueabihf-
  2. 2  NAME            ?= ledc
  3. 3
  4. 4  CC      :=$(CROSS_COMPILE)gcc
  5. 5  LD      :=$(CROSS_COMPILE)ld
  6. 6  OBJCOPY     :=$(CROSS_COMPILE)objcopy
  7. 7  OBJDUMP     :=$(CROSS_COMPILE)objdump
  8. 8  
  9. 9  OBJS:= start.o main.o
  10. 10
  11. 11$(NAME).bin:$(OBJS)
  12. 12     $(LD) -Timx6ul.lds -o $(NAME).elf $^
  13. 13  $(OBJCOPY) -O binary -S $(NAME).elf $@
  14. 14  $(OBJDUMP) -D -m arm $(NAME).elf >$(NAME).dis
  15. 15
  16. 16 %.o:%.s
  17. 17  $(CC) -Wall -nostdlib -c -O2 -o $@ [        DISCUZ_CODE_266        ]lt;
  18. 18
  19. 19 %.o:%.S
  20. 20  $(CC) -Wall -nostdlib -c -O2 -o $@ [        DISCUZ_CODE_266        ]lt;
  21. 21
  22. 22 %.o:%.c
  23. 23  $(CC) -Wall -nostdlib -c -O2 -o $@ [        DISCUZ_CODE_266        ]lt;
  24. 24
  25. 25 clean:
  26. 26  rm -rf *.o $(NAME).bin $(NAME).elf $(NAME).dis
复制代码
本章实验的Makefile文件是在第十一章中的Makefile上修改的,只是使用到了变量。链接脚本imx6ul.lds的内容和上一章一样,可以直接使用上一章的链接脚本文件。
12.4.2编译下载
       使用Make命令编译代码,编译成功以后使用软件imxdownload将编译完成的ledc.bin文件下载到SD卡中,命令如下:
  1. chmod 777 imxdownload                    //给予imxdownload可执行权限,一次即可
  2. ./imxdownload ledc.bin /dev/sdd          //烧写到SD卡中
复制代码
       烧写成功以后将SD卡插到开发板的SD卡槽中,然后复位开发板,如果代码运行正常的话LED0就会以500ms的时间间隔亮灭,实验现象和上一章一样。







正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-23 04:39

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表