S5PV210 | 裸机LED灯呼吸实验

S5PV210 | 裸机LED灯呼吸实验


  • 电路原理

HW-LED

本实验中,我们通过控制D25(LED4)来实现一个呼吸灯。GPD0_1输出高电平,熄灭LED;反之,输出低电平,点亮LED。

这里通过延时函数,来控制LED灯亮灭的时间长短。

渐亮过程:在调光级数递增过程中,LED灯亮起来的时间越来越长;

渐灭过程:在调光级数递增过程中,LED灯熄灭起来的时间越来越长。

两个过程即为一个呼吸周期,一个过程控制在一秒左右,即可实现灯的呼吸效果。

  • DATASHEET(相关寄存器设置详解)

2.2.7 GPD0控制寄存器组

GPD0控制寄存器组包含六组控制寄存器,分别叫做:GPD0CON, GPD0DAT, GPD0PUD, GPD0DRV, GPD0CONPDN
GPD0PUDPDN

2.2.7.1 Port Group GPD0 Control Register (GPD0CON, R/W, Address = 0xE020_00A0)

GPD0CON

2.2.7.2 Port Group GPD0 Control Register (GPD0DAT, R/W, Address = 0xE020_00A4)

GPD0DAT

2.2.7.3 Port Group GPD0 Control Register (GPD0PUD, R/W, Address = 0xE020_00A8)

GPD0PUD

2.2.7.4 Port Group GPD0 Control Register (GPD0DRV, R/W, Address = 0xE020_00AC)

GPD0DRV

2.2.7.5 Port Group GPD0 Control Register (GPD0CONPDN, R/W, Address = 0xE020_00B0)

GPD0PUDPDN

2.2.7.6 Port Group GPD0 Control Register (GPD0PUDPDN, R/W, Address = 0xE020_00B4)

GPD0PUDPDN

  • 代码编写

  • 启动代码

/**********************************************************
 *   > File Name: start.S
 *   > Author: fly
 *   > Create Time: 2020年07月17日 星期五 07时56分19秒
 *********************************************************/
#define PS_HOLD_CONTORL 0xE010E81C
#define WTCON           0xE2700000
#define SVC_STACK       0xD0037D80

//#define CONFIG_SYS_ICACHE_OFF   1

.global _start
_start:
    // 给5v电源置锁
    // LDR指令:从内存中将1个32位的字读取到目标寄存器中
    // STR指令:将1个32位的字数据写入到指令中指定的内存单元中
    // ORR指令:逻辑或
	// BIC指令:位清零
    ldr r0,=PS_HOLD_CONTORL     // r0 = 0xE010E81C
    ldr r1,[r0]                 // 将r0地址处的数据读出,保存到r1中(零偏移)
    orr r1,r1,#0x300            // 设置r1的第8、9位,其他位保持不变
    orr r1,r1,#0x1              // 设置r1的第1位,其他位保持不变
    str r1,[r0]                 // 将r1中的内容传输到r0中数指定的地址内存中去

    //关看门狗
    ldr r0, =WTCON			// r0 = 0xE2700000
    mov r1, #0				// r1 = 0
    str r1, [r0]			// 将r1中的内容传输到r0中数指定的地址内存中去

    // 开/关iCache
    // MRC指令:从协处理器寄存器传数据到ARM寄存器
    // MCR指令:从ARM寄存器传数据到协处理器寄存器
    mrc p15, 0, r0, c1, c0, 0
    #ifdef CONFIG_SYS_ICACHE_OFF
    bic r0, r0, #0x00001000     @ clear bit 12 (I) I-Cache
    #else
    orr r0, r0, #0x00001000     @ set bit 12 (I) I-Cache
    #endif
    mcr p15, 0, r0, c1, c0, 0

    // 设置栈,以便调用c函数
    ldr sp, =SVC_STACK

    bl main /* 跳转到main函数 */

    b . /* 死循环 */

  • LED灯控制代码

/*********************************************************
 *   > File Name: led.c
 *   > Author: fly
 *   > Create Time: 2021-06-26  6/25  21:46:02 +0800
 *======================================================*/
typedef struct{
    unsigned int GPD0CON;
    unsigned int GPD0DAT;
    unsigned int GPD0PUD;
    unsigned int GPD0DRV;
    unsigned int GPD0CONPDN;
    unsigned int GPD0PUDPDN;
}gpd0;
#define GPD0 (*(volatile gpd0*)0xE02000A0) 

typedef struct{
    unsigned int GPJ0CON;
    unsigned int GPJ0DAT;
    unsigned int GPJ0PUD;
    unsigned int GPJ0DRV;
    unsigned int GPJ0CONPDN;
    unsigned int GPJ0PUDPDN;
}gpj0;
#define GPJ0 (*(volatile gpj0*)0xE0200240) 

void delay(volatile unsigned int i)
{
    while(i--);
}

unsigned int readl(unsigned int addr)
{
    return ( *((volatile unsigned int *)addr) );
}

void writel(unsigned int addr, unsigned int value)
{
    *((volatile unsigned int *)addr) = value;
}

void led_init(void)
{
    /* LED1 */
    GPJ0.GPJ0CON = (GPJ0.GPJ0CON & ~(0xf<<12)) | (0x1<<12);
    GPJ0.GPJ0DAT = (GPJ0.GPJ0DAT & ~(0x1<<3)) | (0x1<<3);

    /* LED2 */
    GPJ0.GPJ0CON = (GPJ0.GPJ0CON & ~(0xf<<16)) | (0x1<<16);
    GPJ0.GPJ0DAT = (GPJ0.GPJ0DAT & ~(0x1<<4)) | (0x1<<4);

    /* LED3 */
    GPJ0.GPJ0CON = (GPJ0.GPJ0CON & ~(0xf<<20)) | (0x1<<20);
    GPJ0.GPJ0DAT = (GPJ0.GPJ0DAT & ~(0x1<<5)) | (0x1<<5);

    /* LED4 */
    GPD0.GPD0CON = (GPD0.GPD0CON & ~(0xf<<4)) | (0x1<<4);
    GPD0.GPD0DAT = (GPD0.GPD0DAT & ~(0x1<<1)) | (0x1<<1);
}

void led_set_led1(unsigned int value)
{
    if (value){
        GPJ0.GPJ0DAT = (GPJ0.GPJ0DAT & ~(0x1<<3)) | (0x0<<3);//ON
    }else{
        GPJ0.GPJ0DAT = (GPJ0.GPJ0DAT & ~(0x1<<3)) | (0x1<<3);//OFF
    }
}

void led_set_led2(unsigned int value)
{
    if (value){
        GPJ0.GPJ0DAT = (GPJ0.GPJ0DAT & ~(0x1<<4)) | (0x0<<4);//ON
    }else{
        GPJ0.GPJ0DAT = (GPJ0.GPJ0DAT & ~(0x1<<4)) | (0x1<<4);//OFF
    }
}

void led_set_led3(unsigned int value)
{
    if (value){
        GPJ0.GPJ0DAT = (GPJ0.GPJ0DAT & ~(0x1<<5)) | (0x0<<5);//ON
    }else{
        GPJ0.GPJ0DAT = (GPJ0.GPJ0DAT & ~(0x1<<5)) | (0x1<<5);//OFF
    }
}

void led_set_led4(unsigned int value)
{
    if (value){
        GPD0.GPD0DAT = (GPD0.GPD0DAT & ~(0x1<<1)) | (0x0<<1);//ON
    }else{
        GPD0.GPD0DAT = (GPD0.GPD0DAT & ~(0x1<<1)) | (0x1<<1);//OFF
    }
}

void led_set_all_led(unsigned int value)
{
    if(value){
        led_set_led1(1);
        led_set_led2(1);
        led_set_led3(1);
        led_set_led4(1);
    }else{
        led_set_led1(0);
        led_set_led2(0);
        led_set_led3(0);
        led_set_led4(0);
    }
}

void tester_led(void)
{
    led_init();

    /* 流水灯 */
    while(1){
        led_set_led1(1);
        delay(900000);
        led_set_led1(0);
        led_set_led2(1);
        delay(900000);
        led_set_led2(0); 
        led_set_led3(1);
        delay(900000);
        led_set_led3(0); 
        led_set_led4(1);
        delay(900000);
        led_set_all_led(1);
        delay(900000);
        led_set_all_led(0);
        delay(900000);
    }
}

void tester_breath_led(void)
{
    #define CYCLE       (3500)
    unsigned int pwm;
    led_init();

    /* 呼吸灯 */
    while(1){
        /* LED灯渐渐变亮 */
        for(pwm = 1; pwm < CYCLE; pwm++)
        {
            led_set_led4(0), delay(CYCLE - pwm);
            led_set_led4(1), delay(pwm);  
        }
        led_set_led4(1), delay(pwm/5);
        /* LED灯渐渐熄灭 */
        for(pwm = 1; pwm < CYCLE; pwm++)
        {
            led_set_led4(1), delay(CYCLE - pwm);
            led_set_led4(0), delay(pwm);   
        }
        led_set_led4(0), delay(pwm);
    }
}

int main(int argc, char* argv[])
{
    tester_breath_led();

    return 0;
}

  • Makefile文件

# 将所有的.o文件链接成.elf文件,“-Ttext 0x0”
# 表示程序的运行地址是0x0,由于目前编写的是位置
# 无关码,可以在任一地址运行
# 将elf文件抽取为可在开发板上运行的bin文件
# 将elf文件反汇编保存在dis文件中,调试程序会用
# 添加文件头
.PHONY: all clean tools

CROSS		?= arm-linux-
NAME		:= LED

LD			:= $(CROSS)ld
OC			:= $(CROSS)objcopy
OD			:= $(CROSS)objdump
CC			:= $(CROSS)gcc
MK			:= ../../tools/mk_image/mkv210_image
CFLAGS		:= -nostdlib

all:$(NAME).bin

$(NAME).bin : start.o led.o
	$(LD) -Ttext 0x0 -o $(NAME).elf $^
	$(OC) -O binary $(NAME).elf $(NAME).bin
	$(OD) -D $(NAME).elf > $(NAME)_elf.dis
	$(MK) $(NAME).bin

# 将当前目录下存在的汇编文件及C文件编译成.o文件
%.o : %.S
	$(CC) -o $@ $< -c $(CFLAGS)
%.o : %.c
	$(CC) -o $@ $< -c $(CFLAGS)

clean:
	$(RM) *.o *.elf *.bin *.dis *.sd

tools:
	make -C ../../tools/mk_image/
posted @ 2023-05-11 20:09  hello,123456  阅读(110)  评论(0编辑  收藏  举报