Linux开发板C语言实现LED闪烁

一、处理器模式的设置

Cortex-A 处理器有6种运行模式,当前实验需要将模式设置为SVC超级管理员模式,从寄存器设置中可以看到CPSR的M【4:0】控制着处理器的运行模式。因此可以将CPSR【4:0】设置为10011即为SVC模式。

二、SP指针的设置

Sp可以指向内部RAM,也可以指向DDR,在此实验中我们将指向DDR。I.MX6U-ALPHA 开发板上的 DDR3 地 址 范 围 是0X80000000~0XA0000000(512MB),也有可能是256MB的,但是其 DDR3 起始地址是 0X80000000。由于 Cortex-A7 的堆栈是向下增长的,所以将 SP 指针设置为 0X80200000。因此 SVC 模式的栈大小 0X80200000-0X80000000=0X200000=2MB,2MB 的栈空间已经很大了。最后就是跳转到main函数。

三、start.S文件代码如下

.global _start

_start:
    /*设置处理器进入SVC模式 */
    mrs r0, cpsr   /*读取cpsr到r0 */
    bic r0, r0, #0x1f  /*清除cpsr的bit4:0*/
    orr r0, r0, #0x13  /*使用SVC模式 */
    msr cpsr, r0       /*将r0写入到cpsr */

    /*设置SP指针 */
    ldr sp, =0x80200000
    b main             /*跳转到C语言main函数 */

四、C语言代码的编写

C代码主要由main.c和main.h两部分组成,main.h主要定义寄存器地址,代码如下:

#ifndef __MAIN_H
#define __MAIN_H

/*定义要使用的寄存器*/
#define CCCM_CCGR0 *((volatile unsigned int*)0x020c4068)
#define CCCM_CCGR1 *((volatile unsigned int*)0x020c406c)
#define CCCM_CCGR2 *((volatile unsigned int*)0x020c4070)
#define CCCM_CCGR3 *((volatile unsigned int*)0x020c4074)
#define CCCM_CCGR4 *((volatile unsigned int*)0x020c4078)
#define CCCM_CCGR5 *((volatile unsigned int*)0x020c407c)
#define CCCM_CCGR6 *((volatile unsigned int*)0x020c4080)

#define SW_MUX_GPIO1_IO03 *((volatile unsigned int*)0x020e0068)
#define SW_PAD_GPIO1_IO03 *((volatile unsigned int*)0x020e02f4)

#define GPIO1_GDIR *((volatile unsigned int*)0x0209c004)
#define GPIO1_DR *((volatile unsigned int*)0x0209c000)
#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)

#endif // !__MAIN_H

接下来就是main.c文件的编写,该文件是正式实现LED灯的闪烁,其代码如下:

#include "main.h"

/*使能外设时钟*/
void clk_enable(void)
{
    CCCM_CCGR0 = 0xffffffff;
    CCCM_CCGR1 = 0xffffffff;
    CCCM_CCGR2 = 0xffffffff;
    CCCM_CCGR3 = 0xffffffff;
    CCCM_CCGR4 = 0xffffffff;
    CCCM_CCGR5 = 0xffffffff;
    CCCM_CCGR6 = 0xffffffff;
}

/*初始化LED*/
void led_init(void)
{
    SW_MUX_GPIO1_IO03 = 0x5;
    SW_PAD_GPIO1_IO03 = 0x10b0;

    /*GPIO初始化*/
    GPIO1_GDIR = 0x8; /*设置为输出*/
    GPIO1_DR = 0x0;   /*打开led灯*/
}

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

/*延时,一次循环大概是1ms 在主频396Mhz
 *n:延时ms数
 */
void delay(volatile unsigned int n)
{
    while(n--){
        delayshort(0x7ff);
    }
}

/*打开led灯*/
void led_on(void)
{
    GPIO1_DR &= ~(1<<3); /*bit3清0*/
}

/*关闭led灯*/
void led_off(void)
{
    GPIO1_DR |= (1<<3); /*bit3置1*/
}

int main(void)
{
    clk_enable();
    led_init();
    /*初始化LED*/

    /*设置LED闪烁*/
    while(1){
        led_on();
        delay(1000);
        led_off();
        delay(1000);
    }
    return 0;
}

五、编写Makefile

objs = main.o start.o

ledc.bin : $(objs)
	arm-linux-gnueabihf-ld -Timx6u.lds $^ -o ledc.elf
	arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@
	arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis

%.o : %.c
	arm-linux-gnueabihf-gcc -Wall -nostdlib -O2 -c -o $@ $<

%.o : %.S
	arm-linux-gnueabihf-gcc -Wall -nostdlib -O2 -c -o $@ $<

clean:
	rm -rf *.o ledc.bin ledc,elf ledc.dis

链接脚本的编写,主要是将我们编译出来的代码块链接到指定的地址,一般编译的代码块包含 text、data、bss 和 rodata 这四个段。其代码如下:

SECTIONS{
    . = 0x87800000;
    .text :
    {
        start.o
        *(.text)
    }
    .rodate ALIGN(4) : {*(.rodate*)}
    .date ALIGN(4) : {*(.date)}
    __bss_start=.;
    .bss ALIGN(4) : {*(.bss) *(COMMON)}
    __bss_end=.;
}

完成以上工作后即可按照之前的步骤进行烧写验证。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值