TQ210天嵌开发板S5PV210 LED闪烁程序C语言代码记录
之前也学习过LDE闪烁程序,一般通过如下方式实现:
主要思想是通过操作寄存器地址的方式操作寄存器,这种实现方式的优点就
是简单容易理解,但是具有一定的局限性,一般在较大的工程中不会这样实
现,因为通过直接操作地址的方式实现,必定会频繁查询数据手册,查询相
应寄存器地址,还有就是程序中会出现大量地址,可读性差不利于程序移植
和优化。
通过学习,了解了一种通用的程序设计方式,特此记录
先说下大概思想:
1)引入GPIO基地址概念,建立GPIO结构体,这样每一个GPIO都可以通过
”基地址+偏移地址“的思想查找到,避免了频繁操作地址的弊端。
2)位操作思想,不能为了实现某一个功能,影响其他功能,因此位操作的
实现方式成为了程序设计中优先考虑的因素。
下面说下具体细节实现:
主要步骤如下(此处针对我使用的开发板TQ210,具体实现是一样的):
1. 通过查询开发板原理图得到两个LED的引脚分别为: GPC0_3、GPC0_4
2. 查询GPIO的基地址为:0xE0200000
3. 设置功能寄存器GPC0CON为输出 :因为输出为0001=Output
4. 则32位的2进制值为:xxxx xxxx xxxx 0001 0001 xxxx xxxx xxxx
5. 设置完模式为输出:仍需设置到底是低电平输出,还是高电平输出。
6.设置组控制器:GPC0DAT 为高点亮LED
则32位的2进制值为:xxxx xxxx xxxx 0001 0001 xxxx xxxx xxxx
设置组控制器:GPC0DAT 为低熄灭LED
则32位的2进制值为:xxxx xxxx xxxx 0000 0000 xxxx xxxx xxxx
(x代表未知,即保留其原有的状态)
具体程序分为以下几个程序:
1.start.S汇编文件 主要功能跳到C语言main函数
2.main.c 主程序 调用 led相关程序 延时程序等
3.map.lds 链接脚本文件 控制程序文件顺序
4.Makefie文件
5.led.c led.h LED相关设置
6.cpu_io.h 地址赋值等相关操作
7.gpio.h gpio结构体等
具体程序代码如下:
start.S
.global _start
.global main
_start :
bl main
loop:
b loop
.end
main.c
//main.c
#include "led.h"
#include "cpu_io.h"
static void mydelay()
{
volatile unsigned int i=0xfffff;
while(i--);
}
void led_test()
{
led_init();
while(1)
{
led_blink(1);
mydelay();
led_blink(0);
mydelay();
}
}
int main()
{
led_test();
return 0;
}
led.c
#include "gpio.h"
#include "led.h"
#include "cpu_io.h"
void led_init(void)
{
struct s5pv210_gpio *gpio_base=(struct s5pv210_gpio *) S5PV210_GPIO_BASE;
unsigned int var;
var =_REG(&gpio_base->gpio_c0.con);
var &=~(0xFF<<(4*3)); //1111 1111 0000 0000 0000
var |= (0x11<<(4*3)); //0001 0001 0000 0000 0000
writel(var,&gpio_base->gpio_c0.con); //11000
}
void led_blink(int status)
{
struct s5pv210_gpio *gpio_base=(struct s5pv210_gpio *) S5PV210_GPIO_BASE;
unsigned int var ;
if(status)
{
var = _REG(&gpio_base->gpio_c0.dat);
var &=~0x18; //00011000
writel(var,&gpio_base->gpio_c0.dat);
}
else
{
var = _REG(&gpio_base->gpio_c0.dat);
var |=0x18;
writel(var,&gpio_base->gpio_c0.dat);
}
}
map.lds
OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. =0x0;
. =ALIGN(4);
.text :
{
start.o
*(.text)
}
. =ALIGN(4);
.rodata :
{
*(.rodata)
}
. =ALIGN(4);
.data :
{
*(.data)
}
. =ALIGN(4);
.bss :
{
*(.bss)
}
}
led.h
#ifndef LED_H
#define LED_H
void led_init(void);
void led_blink(int status);
#endif
gpio.h
#ifndef _ASM_ARCH_GPIO_H
#define _ASM_ARCH_GPIO_H
struct s5pc1xx_gpio_bank{
unsigned int con;
unsigned int dat;
unsigned int pull;
unsigned int drv;
unsigned int pdn_con;
unsigned int pdn_pull;
unsigned char res1[8];
};
struct s5pv210_gpio{
struct s5pc1xx_gpio_bank gpio_a0;
struct s5pc1xx_gpio_bank gpio_a1;
struct s5pc1xx_gpio_bank gpio_b;
struct s5pc1xx_gpio_bank gpio_c0;
struct s5pc1xx_gpio_bank gpio_c1;
struct s5pc1xx_gpio_bank gpio_d0;
struct s5pc1xx_gpio_bank gpio_d1;
struct s5pc1xx_gpio_bank gpio_e0;
struct s5pc1xx_gpio_bank gpio_e1;
struct s5pc1xx_gpio_bank gpio_f0;
struct s5pc1xx_gpio_bank gpio_f1;
struct s5pc1xx_gpio_bank gpio_f2;
struct s5pc1xx_gpio_bank gpio_f3;
struct s5pc1xx_gpio_bank gpio_g0;
struct s5pc1xx_gpio_bank gpio_g1;
struct s5pc1xx_gpio_bank gpio_g2;
struct s5pc1xx_gpio_bank gpio_g3;
struct s5pc1xx_gpio_bank gpio_i;
struct s5pc1xx_gpio_bank gpio_j0;
struct s5pc1xx_gpio_bank gpio_j1;
struct s5pc1xx_gpio_bank gpio_j2;
struct s5pc1xx_gpio_bank gpio_j3;
struct s5pc1xx_gpio_bank gpio_j4;
};
#define S5PV210_GPIO_BASE (0xE0200000)
#endif
cpu_io.h
#ifndef _S5PV210_CPU_H
#define _S5PV210_CPU_H
#define _REG(x) (*(volatile unsigned int *)(x))
#define readb(a) (*(volatile unsigned char *)(a))
#define readw(a) (*(volatile unsigned short *)(a))
#define readl(a) (*(volatile unsigned int *)(a))
#define writeb(v, a) (*(volatile unsigned char *)(a) = v)
#define writew(v, a) (*(volatile unsigned short *)(a) = v)
#define writel(v, a) (*(volatile unsigned int *)(a) = v)
#endif
以上就是实现LED闪烁的全部思路思想,还是要感谢Rocky大神讲解的如此细致,
让我收获了很多,以上内容进攻学习交流,如有错误,还请批评指正。