嵌入式裸机烧写LED

Posted 敲代码两年半的练习生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了嵌入式裸机烧写LED相关的知识,希望对你有一定的参考价值。

1. 操作内容

  1. 熟悉嵌入式系统启动代码、头文件、Makefile文件的编写。
  2. 掌握GPIO控制程序的编写、编译、运行。
  3. 编写系统的启动代码、GPIO控制程序、头文件以及Makefile文件,编译得到可执行文件,下载至开发板,实现在开发板上启动系统。

2. 原理解释

2.1 电路图及寄存器功能简表

在这里插入图片描述
图 1实验箱LED电路图
在这里插入图片描述
图 2 寄存器功能简表

2.2 GPIO工作原理

GPIO(General Purpose Input/Output)是通用输入输出接口,可以通过引脚输出高低电平,或者读入引脚的状态。GPIO引脚功能由通用I/O控制寄存器GPxnCON设置,输出、输入的数据存储于通用I/O数据寄存器GPxnDAT,此外,还有其它寄存器实现对GPIO复杂功能的设置。
GPxnCON控制寄存器有32位,每4位控制一个引脚,可以控制总计八个引脚。通过设置4位二进制数可以设置GPIO引脚功能,其中,0000设置引脚为输入IO口,0001设置引脚为输出IO口,其它引脚功能可以参考芯片手册中的寄存器功能表。
GPxnDAT数据寄存器有32位,其中的[0:7]低八位用以存储数据。当GPIO引脚为输出IO时,将GPxnDAT中的数据1或0以高电平或低电平形式对外输出;当GPIO引脚为输入IO时,从外部由IO读入的高电平或低电平以1或0存储于GPxnDAT寄存器中。

2.3 启动代码

/*start.S*/
.global _start
_start :
ldr sp, = 0xD0037D80 
bl led_blink
halt : 
b halt

在这里插入图片描述

2.4 头文件

/*
** 在 BL0阶段,iROM内固化的代码读取 nandflash或 SD卡前面最大 16K的内
容(即 BL1)到 iRAM,
** 并比对前 16字节中的校验和是否正确,正确则继续,错误则尝试启动下一个设备。
** BL1的头信息规定如下
** 0x0:BL1的大小(最大 16K,包括 BL1头信息的大小)
** 0x4: 0(规定)
** 0x8:校验和
** 0xC:0(规定)
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define IMG_SIZE
#define HEADER_SIZE
#define BLKSIZE
(16 * 1024)16 512 int main(int argc, char *argv[])
{
    FILE
        *fp;
    unsigned int char *Buf;
    BufLen;
    int
        nbytes,
        fileLen;
    unsigned int checksum, count;
    int i;
    if (argc != 3)
    {
        printf("Usage: %s <source file> <destination file>\\n",
               argv[0]);
        return -1;
    }
    /* 分配 16K的 buffer */
    BufLen = IMG_SIZE;
    Buf = malloc(BufLen);
    if (!Buf)
    {
        perror("Alloc buffer failed!");
        return -1;
    }
    memset(Buf, 0x00, BufLen);
    /* 读源 bin到 buffer */
    fp = fopen(argv[1], "rb");
    if (fp == NULL){
        }
    perror("source file open error");
    free(Buf);
    return -1;
    /* 获取源 bin长度 */
    fseek(fp, 0L, SEEK_END);
    fileLen = ftell(fp);
    fseek(fp, 0L, SEEK_SET);
    /* 源 bin长度不得超过 16K-16byte */
    fileLen = (fileLen < (IMG_SIZE - HEADER_SIZE)) ? fileLen : (IMG_SIZE - HEADER_SIZE);
    /* 读源 bin到 buffer[16] */
    nbytes = fread(Buf + HEADER_SIZE, 1, fileLen, fp);
    if (nbytes != fileLen)
    {
        perror("source file read error\\n");
        free(Buf);
        fclose(fp);
        return -1;
    }
    fclose(fp);
    /* 计算校验和 */
    for (i = 0, checksum = 0; i < fileLen; i++)
        checksum += Buf[HEADER_SIZE + i];
    /* 计算 BL1的大小:
** BL1的大小包括 BL1的头信息
** 另外 iROM从 SD卡拷贝是按块拷贝的,因此这里需要调整大小为 512字节
的整数倍
*/
    fileLen += HEADER_SIZE;
    count = fileLen / BLKSIZE * BLKSIZE;
    if (count < fileLen)
        count += BLKSIZE;
    memcpy(Buf, &count, 4);
    // 保存 BL1的大小到 Buf[0-3]
    // 将校验和保存在 buffer[8~15]
    memcpy(Buf + 8, &checksum, 4);
    fp = fopen(argv[2], "wb");
    if (fp == NULL)
    {
        perror("destination file open error");
        free(Buf);
        return -1;
    }
    // 将 count + HEADER_SIZE字节的 buffer拷贝到目的 bin中
    nbytes = fwrite(Buf, 1, count, fp);
    if (nbytes != count)
    {
        perror("destination file write error");
        free(Buf);
        fclose(fp);
        return -1;
    }
    free(Buf);
    fclose(fp);
    return 0;
}

在这里插入图片描述

2.5 Makefile文件

Makefile是Linux为提高开发效率而为软件编译提供的一个自动化管理工具GNU make。GNU make是一种常用的编辑工具,其主要工作是读取Makefile文件。Makefile文件主要是有关目的文件是从哪些依赖文件中产生,以及用什么命令来进行这个产生过程。通过Makefile文件,可将逐行输入命令、逐行执行的命令行执行模式转换为利用make编译器、运行Makefile的自动运行模式。
本实验中,为了得到所需的二进制文件led.bin,可以编写一下Makefile文件,由start.o和led.o两个依赖文件生成led.bin文件。

led.bin:start.o led.o
arm-linux-ld -Ttext 0xd0020010 -o led.elf $^
arm-linux-objcopy -O binary led.elf led.bin
%.o : %.S
arm-linux-gcc -nostdlib -o $@ $< -c
%.o : %.c
arm-linux-gcc -nostdlib -o $@ $< -c
clean:
rm -rf *.o *.elf

在这里插入图片描述

3. 操作步骤

3.1 编译文件

1)在Windows和Linux共享文件夹“forlinux”中新建led文件夹。
2)在led文件夹中新建启动文件start.S,注意后缀“S”必须大写,并在start.S文件中添加启动代码。

$ gedit start.S

在这里插入图片描述

3)在l ed文件夹中新建led.c源文件,在led.c文件中编写控制LED的C语言源代码。

$ gedit led.c

添加以下LED控制代码。

#define GPJ2CON (*(volatile unsigned long *)0xE0200280)
#define GPJ2DAT (*(volatile unsigned long *)0xE0200284)
void delay(int t)
{
	volatile int count = t;
	while (count--)
		;
}void led_blink()
{
	GPJ2CON = 0x00001111;
	while (1)
	{
		GPJ2DAT = 0;
		delay(0x100000);
		GPJ2DAT = 0xF;
		delay(0x100000);
	}
}

在这里插入图片描述

4)在l ed文件夹中新建addheader.c文件,在addheader.c文件中添加头文件源代码,编译addheader.c文件生成可执行文件addheader。

$ gedit addheader.c
$ gcc addheader.c -o addheader

在这里插入图片描述

5)在l ed文件夹中新建Makefile文件,在Makefile文件中添加交叉编译代码,运行Makefile文件

$ gedit Makefile
$ make

6)利用addheader文件和交叉编译得到的led.bin文件制作二进制文件210.bin。

$ ./addheader led.bin 210.bin

在这里插入图片描述

3.2 安装USB驱动

将实验箱中的拨码开关2拨到on,长按Power键直至电脑提示安装驱动。打开计算机设备管理器,选择下图所示硬件安装驱动。

在这里插入图片描述

右键选择更新驱动程序,手动添加 USB驱动程序路径“D:\\新 509\\04-常用工具\\DNW”。
在图 4所示驱动安装过程中,将拨码开关 2重新置为 OFF状态,然后关闭开发板的电源,等待驱动安装完毕。

在这里插入图片描述

驱动安装完成后出现如图 5所示提示。

在这里插入图片描述

3.3 下载文件、启动系统

1)用 USB device线连接电脑和开发板,设置开发板为 nandflash启动(拨码开关全部拨至OFF状态)。
2)在目录“D:\\新509\\04-常用工具\\DNW”中打开DNW.exe。设置串口:波特率为115200 USB Port为0xd0020010。Download,Address为0Xd0020010。
3)在菜单栏开启DNW串口连接(Serial Port - >Connect)。启动开发板后立即在 DNW窗口迅速敲击空格键进入 Uboot状态,可见图 11启动界面。

在这里插入图片描述

4)在 DNW 窗口中输入“dnw 0xd0020010”设置下载地址。如果 DNW驱动安装失败或首次使用DNW,会提示安装驱动,请正确安装驱动,等到提示硬件可使用从进行下一步。
5)在DNW菜单中,选择usbport- >Transmit- >Transmit发送生成的 210.bin文件,DNW自动下载 210.bin文件至开发板。
(用MV指令将linux下的210.bin,移动到/mnt/hgfs/forlinux,方便DNW传输,/mnt/hgfs/forlinux 文件夹就是window下的forlinux文件夹)
6)在 DNW 窗口中输入“go 0xd0020010”,即可开始运行 210.bin程序。

在这里插入图片描述

4. 操作结果

在这里插入图片描述

以上是关于嵌入式裸机烧写LED的主要内容,如果未能解决你的问题,请参考以下文章

嵌入式Linux之旅——环境搭建篇之烧写裸机程序

初试ARM开发板

嵌入式Linux裸机开发——点亮Led

编译裸机程序以及交叉工具链

ARM裸机之点亮LED

ARM裸机之点亮LED