跳转至

基础环境

硬件环境:正点原子IMX6ULL MINI板 V1.7 EMMC板

程序说明:为方便开发,程序使用 BootLoader + APP 的方式开发。使用BootLoader来进行升级,前期不将 BootLoader 作为开发重点,所以先使用 UBoot 作为我们的 BootLoader 后续可能会使用自写的 loader 。所以先使用正点原子的教程给板子的 EMMC或者SD卡 下载一个 Uboot。方便实现在线程序升级和运行。随便烧一个就行,不用自己去编译,下载它自带的就可以了。等下做说明。

裸机程序编写软件:SEGGER Embedded Studio V8.24 。 为了在Windows环境下编译裸机开发,所以使用 SES 的软件编写。

下载 Uboot 程序

主要是需要板子上有个能启动的程序。SD卡或者EMMC都行,只要能让板子启动起来就行。使用正点原子的下载工具。但是我们只下载Uboot,不下载其他的,如果你是使用的EMMC的话,它本身里面就有了出厂的Uboot这些程序,理论上就可以不用咋管了。

【全量烧写】SD 卡使用正点原子出厂工具烧写

1、如果图省事,我们可以直接把Uboot、Linux内核和文件系统全量烧写到SD卡中,找到正点原子改版的mfgtools。不要找到NXP原厂那个了,那个还要自己改。

2、将 USB 插到 USBOTG 上,并且将启动方式调整到 USB 启动。

3、根据你的板子配置选择合适的脚本烧写。

4、插上SD卡打开脚本并上电,会发现软件检测到板子,记得SD卡需要格式化,然后点击 Start 就等着。它下的内容比较多,可能要等一会,中间可能会弹出几秒的无设备连接,也比较正常,等一会就好了。下载完成后,显示done。

5、将电源关闭,引脚调整到SD卡启动,然后连接到串口,使用串口调试助手查看结果。

6、开机后我们一直回车,串口调试助手自己选择合适的,我这里使用的是 SecureCRT,因为他能发送各种协议的文本。开机后,就能发现Uboot打印了,回车就会进入 UBoot 命令行了,就可以操控 Uboot 的相关指令了。

7、可以尝试一下复位后不回车,就会发现我们会一直进入到内核程序中。

【仅Uboot烧写】SD 卡使用正点原子出厂工具烧写Uboot

1、我们还可以只烧写 Uboot 。打开烧写工具中的烧写ucl2.xml。使用文本文件打开。

2、会发现中间有 3 个 List ,每个的内容会详细描述每个启动方式怎么烧写,我们先看 SD 卡的。

3、可以看每个命令前面的注释,比如创建分区,烧写分区什么的。

4、我们只保留Uboot相关的,其他的直接注释。也就是从 burn logo 开始,SD 卡下面的 那些CMD 全部注释,你要是嫌麻烦,也可以直接删除,但是建议你**备份**一个,因为你后面肯定还有要学烧写全部的需求。

5、然后我们再去烧写 SD 卡,就和上面全量烧写的步骤一样了。只下载Uboot的话,就比较快。然后我们调整到SD卡启动,然后打开串口调试助手。你会发现你就算不回车,也进入不了Kernel,因为压根就没Kernel。

【全量烧写-Uboot烧写】EMMC 用正点原子出厂工具烧写

其实和SD卡的步骤一样的,只是在选择启动方式的时候,需要选择 EMMC 的启动方式,还有就是那个烧写脚本后缀需要选择带 EMMC的而不是带SD卡的。

然后只烧写UBoot的话,就得记着修改 ucl2.xml 中 EMMC 的部分,把其他全部去掉。

SEGGER ES 编写代码环境搭建

1、SEGGER Embedded Studio官网下载一个这个软件。根据你的操作系统选择软件,我们用 Windows。至于安装傻瓜式默认,只需要中间安装路径选择一个比较合适的位置。

2、打开软件,我们新建一个工程

3、选择建立一个新的解决方案

4、选择Cotex-A的解决方案,因为我们用的IMX是Cotex-A并且选择一个路径名和工程名。

5、在选择目标设备中,我们搜索我们的芯片型号

6、编译环境默认。

7、添加程序,默认

8、配置方案,也默认

9、全部配置好后,就会生成工程。SEGGER_Flash_ARM.icf 是链接文件,main是编译文件,.s的是启动文件。

icf文件中我们改一点东西,主要就是链接地址改成自己想要的位置。

/******************    改1前    *********************/
define region FLASH = FLASH1;
define region RAM   = RAM1;
/****************************************************/

/******************    改1后    *********************/
define region FLASH2 = [from 0x87800000 to 0x87FFFFFF];
define region RAM2   = [from 0x80000000 to 0x8003FFFF];

define region FLASH = FLASH2;
define region RAM   = RAM2;
/****************************************************/

11、为了生成bin文件,我们右键工程,点配置。

12、在linker中,将输出配置成bin

13、右键工程就可以Build

14、可以看到Output中就会有bin

14、我们写一个基本的LED翻转驱动,使用正点原子的例程,并且烧写。先在Source目录下建立两个文件。当然,你也可以其他地方建立。

15、工程中,右键文件夹,新建文件夹分类。建立BSP文件夹,并且把刚刚的两个文件加进去。

16、因为有了新的文件夹,所以工程还需要能够找到文件夹路径。右键项目option,配置Preprocessor的User Include Dir

17、点击后面几个点,然后把自己的路径加上去。每行用,号隔开,我这里使用的是相对路径,他是相对这个工程文件的路径,然后要添加的文件夹是你外面文件的路径,不是工程里面的路径。是实际的文件路径。

18、源码如下

// bsp_led.c
#include "bsp_led.h"
#include <stdint.h>

void clk_enable(void)
{
    CCM_CCGR0 = 0xffffffff;
    CCM_CCGR1 = 0xffffffff;
    CCM_CCGR2 = 0xffffffff;
    CCM_CCGR3 = 0xffffffff;
    CCM_CCGR4 = 0xffffffff;
    CCM_CCGR5 = 0xffffffff;
    CCM_CCGR6 = 0xffffffff;
}

void led_init(void)
{
    SW_MUX_GPIO1_IO03 = 0x5;    /* 复用为GPIO1_IO03 */
    SW_PAD_GPIO1_IO03 = 0X10B0;     
    GPIO1_GDIR = 0X0000008; /* GPIO1_IO03设置为输出 */
    GPIO1_DR = 0X0;
}

void led_on(void)
{
    GPIO1_DR &= ~(1<<3); 
}

void led_off(void)
{
    GPIO1_DR |= (1<<3);
}

void delay_short(volatile unsigned int n)
{
    while(n--){}
}

void delay(volatile unsigned int n)
{
    while(n--)
    {
        delay_short(0x7ff);
    }
}


// bsp_led.h
#ifndef BSP_LED_H
#define BSP_LED_H

/* 
 * CCM相关寄存器地址 
 */
#define CCM_CCGR0           *((volatile unsigned int *)0X020C4068)
#define CCM_CCGR1           *((volatile unsigned int *)0X020C406C)

#define CCM_CCGR2           *((volatile unsigned int *)0X020C4070)
#define CCM_CCGR3           *((volatile unsigned int *)0X020C4074)
#define CCM_CCGR4           *((volatile unsigned int *)0X020C4078)
#define CCM_CCGR5           *((volatile unsigned int *)0X020C407C)
#define CCM_CCGR6           *((volatile unsigned int *)0X020C4080)

/* 
 * IOMUX相关寄存器地址 
 */
#define SW_MUX_GPIO1_IO03   *((volatile unsigned int *)0X020E0068)
#define SW_PAD_GPIO1_IO03   *((volatile unsigned int *)0X020E02F4)

/* 
 * GPIO1相关寄存器地址 
 */
#define GPIO1_DR            *((volatile unsigned int *)0X0209C000)
#define GPIO1_GDIR          *((volatile unsigned int *)0X0209C004)
#define GPIO1_PSR           *((volatile unsigned int *)0X0209C008)
#define GPIO1_ICR1          *((volatile unsigned int *)0X0209C00C)
#define GPIO1_ICR2          *((volatile unsigned int *)0X0209C010)
#define GPIO1_IMR           *((volatile unsigned int *)0X0209C014)
#define GPIO1_ISR           *((volatile unsigned int *)0X0209C018)
#define GPIO1_EDGE_SEL      *((volatile unsigned int *)0X0209C01C)

void clk_enable(void);
void led_init(void);
void led_on(void);
void led_off(void);
void delay_short(volatile unsigned int n);
void delay(volatile unsigned int n);

#endif

// main.c
#include "bsp_led.h"

int main(void) {
    clk_enable();       /* 使能所有的时钟          */
    led_init();         /* 初始化led           */

    while(1)            /* 死循环              */
    {   
        led_off();      /* 关闭LED            */
        delay(50000);       /* 延时大约500ms        */

        led_on();       /* 打开LED            */
        delay(50000);       /* 延时大约500ms        */
    }

    return 0;
}

19,然后编译就可以得到bin文件了。

下载程序

我们现在有 Uboot 和 bin程序了,那我们就可以使用 Uboot 的相关指令下载程序了。先启动Uboot

先选择我们要控制的设备,要么SD卡要么EMMC,选择一个就可以了,我这里用SD卡

mmc dev 0  #控制SD卡
mmc dev 1  #控制EMMC

然后我们使用xmode协议把我们刚生成的bin文件传输到DDR内存中,我们把代码放到 0x87800000 中 。

loadx 0x87800000

然后uboot会启动xmode协议接收,我们在SecureCRT中选择 Xmode 协议发送。并选择文件。

发送完成后,会给你说发送的文件大小,这里是484Byte。

=> loadx 0x87800000
## Ready for binary (xmodem) download to 0x87800000 at 115200 bps...
CCCCCCCCCC
Starting xmodem transfer.  Press Ctrl+C to cancel.
Transferring Project.bin...
  100%     484 bytes  484 bytes/sec 00:00:01       0 Errors  

## Total Size      = 0x000001e4 = 484 Bytes

我们可以把他写入到SD卡中。

mmc write 0x87800000 0x800 1

然后我们可以直接启动程序

go 0x87800000

复位之后,可以把写入到 0x800 区域的 代码读出来放到0x87800000再跑

mmc dev 0  #控制SD卡
mmc read 0x87800000 0x800 1
go 0x87800000