Linux S3C2440 学习笔记03

编译过程

预处理,编译,汇编,链接
最后生成可执行文件

预处理:处理语法错误,把宏展开,把头文件包含进来

.c
预处理
.i
.i
编译
.s 汇编代码
.s
汇编
.o object
.o
链接
可执行程序
gcc
编译器
x86 windows 应用程序VC6.0
x86 ubuntu应用程序gcc
arm裸机arm-linux-gcc
gcc常用选项
选项功能
无参数生成a.out的可执行程序
-v查看gcc编译器版本,显示gcc执行时的详细过程
-o指定输出文件名(不能跟源文件同名,会产生覆盖)
-E只预处理,不会编译,汇编,链接
-S只编译,不会汇编和链接
-c编译和汇编,不会连接
动/静态链接

动态链接使用动态链接库进行链接,生成的程序在执行的时候加载所需的动态库才能运行,动态链接生成的程序体积较小,但是必须依赖所需的动态库,否则无法执行

静态链接使用静态链接库进行链接,生成的程序包含程序运行所需的全部库,可以直接运行,不过静态链接生成的程序体积较大

Makefile

组织管理文件。

规则执行的条件:

  1. 目标文件不存在
  2. 某个依赖文件比目标文件新。

执行命令make,后面可以跟目标名 。如果没有,默认第一个目标。

通配符
test: a.o b.o c.o
	gcc -o test $^

%.o : %.c
	gcc -c -o $@ $<


# $@  表示目标文件
# $^  表示所有的依赖文件
# $<  表示第一个依赖文件
# $?  表示比目标还要新的依赖文件列表
假想目标
test: a.o b.o c.o
	gcc -o test $^

%.o : %.c
	gcc -c -o $@ $<

clean:
	rm *.o test

# $@  表示目标文件
# $^  表示所有的依赖文件
# $<  表示第一个依赖文件
# $?  表示比目标还要新的依赖文件列表

#定义为假想目标,实际文件中有`同名`clean文件也可以执行
.PHONY: clean

变量
test: a.o b.o c.o
	gcc -o test $^

%.o : %.c
	gcc -c -o $@ $<

clean:
	rm *.o test

# $@  表示目标文件
# $^  表示所有的依赖文件
# $<  表示第一个依赖文件
# $?  表示比目标还要新的依赖文件列表

#定义为假想目标,实际文件中有`同名`clean文件也可以执行
.PHONY: clean

函数

A=a b c

# $(foreach var,list,text)

#B=$(foreach f,$(A),c.o)
#输出:B=c.o c.o c.o

B=$(foreach f,$(A),$(f).o)
#输出:B=a.o b.o c.o
C=a v/ b c/
#从列表里取出符合 %/格式的所有值,out取出不符合的值
D= $(filter %/,$(C))
E=$(filter-out %/,$(C))

#符合格式的文件
files = $(wildcard *.c)

#从这些文件里取出真实存在的文件
files2 = a.c b.c c.c d.c e.c
files3 = $(wildcard $(files2))

# $(patsubst pattern,replacement,$(var))
dep_files = $(patsubst %.c,%.d,$(files2))

all:
	@echo B=$(B)
	@echo D=$(D)
	@echo E=$(E)
	@echo files=$(files)
	@echo files3=$(files3)
	@echo dep_files=$(dep_files)

# $(wildcard pattern)

最终完善版Makefile
objs = a.o b.o c.o 

# ↓依赖文件 使用文件把.o文件替换成.d文件
dep_files := $(patsubst %,%.d,$(objs))

# 确定文件存在
dep_files := $(wildcard $(dep_files))

# 要求GCC将所有的警告当成错误进行处理,b.c c.c要包含stdio.h
CFLAGS = -Werror

# I指定头文件包含目录
INC = -I ./include

# test依赖于.o文件,于是向下查找
All:${objs}
	gcc -o test $^

#这变量如果不等于空就包含他进去
# ifneq ($(dep_files))
# include $(dep_files)
# endif

# .o文件依赖于.c于是执行命令

#关键命令
# gcc -M c.c 打印出依赖
# gcc -M -MF c.d c.c 把依赖写入文件c.d
# gcc -c -o c.o c.c -MD -MF c.d
# $@  表示目标文件
# $^  表示所有的依赖文件
# $<  表示第一个依赖文件
# $?  表示比目标还要新的依赖文件列表

# -MD -MF 编译.o文件,把依赖写入文件c.d
%.o:%.c
	gcc $(INC) $(CFLAGS) -c -o $@ $< -MD -MF $@.d

clean:
	rm *.o test

distclean:
	rm $(dep_files)

.PHONY:clean
    
ARM时钟体系

Sytem on chip

CPU:FCLK (functional clock)
AHB总线:HCLK高速设备使用高速时钟
APB总线:PCLK低速设备使用高速时钟
手册1-4~1-5

S3C2440没开启时钟前默认使用12M晶振效率低下,超频后最高可达400M.

在这里插入图片描述
FCLK = 400M
在这里插入图片描述

HCLK=FCLK/4
PCLK=FCLK/4/2=HCLK/2
P7-25
在这里插入图片描述

时钟源:12M晶振
PLL:锁相环

示例

//.text 指定了后续编译出来的内容放在代码段
.text
.global _start

//_start是一个函数的起始地址,也是编译、链接后程序的起始地址。由于程序是通过加载器来加载的,必须要找到 _start名字的函数,
//因此_start必须定义成全局的,以便存在于编译后的全局符合表中,供属其它程序【如加载器】寻找到。
_start:
    //关闭看门狗
    ldr r0,=0x53000000
    ldr r1,=0
    str r1,[r0]

    //设置MPLL,FCLK:HCLK:PCLK =400M:100M:50M
    //LOCKTIME(0X4C000000)=0XFFFFFFFF
    ldr r0, =0X4C000000
    ldr r1, =0xffffffff
    str r1, [r0]

    //CLKDIVN(0x4c000014)=0x5,tFCL:tHCLK:tPCLK 1:4:8
    ldr r0, =0x4c000014
    ldr r1, =0x5
    str r1, [r0]

    //设置CPU工作于异步模式
    mrc p15,0,r0,c1,c0,0
    orr r0,r0,#0xc000000
    mcr p15,0,r0,c1,c0,0

    //设置MPLLCON(0x4C000004)=(92<<2)|(1<<4)|(1<<0)
    //m=MDIV+8=92+8=100
    //p=PDIV+2=1+2=3
    //s=SDIV=1
    //FCLK=2*m*Fin/(p*2^s)=2*100*12/(3*2^1)=400M
    ldr r0, =0x4C000004
    ldr r1, =(92<<2)|(1<<4)|(1<<0)
    str r1, [r0]

    //一旦设置PLL,就会锁定lock time直到pll 输出稳定
    //然后CPU工作于新的频率

//设置内存 sp 栈 nand启动时,nand大小是4K,所以把栈设置在内存的顶部
    ldr sp, =4096
    
//nor 启动
    ldr sp, = 0x40000000+4096

//传参
    mov r0,#4 
//调用Main 跳转过去执行Main 并把返回的地址保存到lr里面
    bl main

// 死循环 b常用于不返回的跳转
halt:
    b halt

var=start.o led.o 

all:${var}
	arm-linux-ld -Ttext 0 ${var} -o led.elf
	arm-linux-objcopy -O binary -S led.elf a.bin
%.o:%.c 
	arm-linux-gcc -c $< -o $@
%.o:%.S
	arm-linux-gcc -c $< -o $@ 
clean:
	rm *.bin *.o *.elf *.dis
编写Makefile 出现问题总结

我调试了2个多小时,淦!

  1. 链接时要注意顺序
  2. .S 和 .c文件要分开写
var=start.o led.o 
//`连接时要注意顺序`
all:${var}
	arm-linux-ld -Ttext 0 ${var} -o led.elf
	arm-linux-objcopy -O binary -S led.elf a.bin
//.S 和 .c文件要分开写
%.o:%.c 
	arm-linux-gcc -c $< -o $@
%.o:%.S
	arm-linux-gcc -c $< -o $@ 
clean:
	rm *.bin *.o *.elf *.dis
串口发送接收简单配置

串口运行在低速总线上,50M频率

/*
 * @Description: 
 * @Author: ou
 * @Date: 2022-02-05 17:12:09
 * @LastEditTime: 2022-02-05 20:30:07
 * @LastEditors: ou
 */
#include "s3c2440_soc.h"


void uart0_init()
{
/* 设置引脚用于串口 */
	/* GPH2,3用于TxD0, RxD0 */
	GPHCON &= ~((0xf<<4));
	GPHCON |= ((0xa<<4));

	GPHUP &= ~((3<<2));  /* 使能内部上拉 */
	
	/* 设置波特率 */
	/* UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
	 *  UART clock = 50M
	 *  UBRDIVn = (int)( 50000000 / ( 115200 x 16) ) –1 = 26
	 */
	UCON0 = 0x5; /* PCLK,中断/查询模式 :不断读取某一个数据位*/
	UBRDIV0 = 26;

	/* 设置数据格式 */
	ULCON0 = 0x3; /* 8n1: 8个数据位, 无较验位, 1个停止位 */
}

void my_putchar(unsigned char c)
{
	/* UTRSTAT0 */
	/* UTXH0 */
	while (!(UTRSTAT0 & (1<<2)));
	UTXH0 = c;
}

int getchar()
{
    while (!(UTRSTAT0 & 1));
	return URXH0;
}

int puts(const char* s)
{
    while (*s)
	{
		my_putchar(*s++);
	}
}
/*
 * @Description: 
 * @Author: ou
 * @Date: 2022-02-05 17:11:33
 * @LastEditTime: 2022-02-05 20:29:07
 * @LastEditors: ou
 */
#include "uart.h"
#include "s3c2440_soc.h"

void delay(int d)
{
    while(d--);
}

int main()
{
  unsigned char c;
  uart0_init();
  puts("hello ouou20220205\n");
  while(1)
  {
    c = getchar();
		my_putchar(c);
  }
    return 0;
}
自行实现printf相关前置知识学习示例
/*
 * @Description:
 * @Author: ou
 * @Date: 2022-02-05 21:46:26
 * @LastEditTime: 2022-02-05 23:55:10
 * @LastEditors: ou
 */
#include <stdio.h>
#include <stdarg.h>

// GCC默认4字节对齐
//__attribute__((packed)),让所作用的结构体取消在编译过程中的优化对齐,
//按照实际占用字节数进行对齐

//__attribute((aligned(n))),让所作用的结构体成员对齐在n字节边界上。
//如果结构体中有成员变量的字节长度大于n,则按照最大成员变量的字节长度来算
struct person
{
    /* data */
    char *name;
    int age;
    char score;
};

struct person1
{
    /* data */
    char *name;
    int age;
    char score;
} __attribute__((packed));

struct person2
{
    /* data */
    char *name;
    int age;
    char score;
} __attribute__((aligned(2)));

//...传参
// gcc -m32 -o push_test push_test.c
int push_test(const char *format, ...)
{
    char *p = (char *)&format;
    int i;
    struct person per;

    va_list vp;
    va_start(vp, format);
    int k = va_arg(vp, int);
    printf("\nk:%d\n", k);

    //存在字节对齐需要写int
    struct person per2 = va_arg(vp, struct person);
    printf("\nname:%s\n", per2.name);
    printf("\nage:%d\n", per2.age);
    printf("\nscore:%c\n", per2.score);
    va_end(vp);

    // printf("arg1:%s\n",format);
    // //p=p+sizeof(char*);
    // i=*((int*)(p+sizeof(char*)));
    // printf("arg2:%d\n",i);

    // p=(p+sizeof(char*))+sizeof(int);
    // per=*((struct person*)p);
    // printf("%s,%d,%c",per.name,per.age,per.score);
    // return 0;
}

int main(int argc, char **argv)
{
    struct person per = {"123", 22, 'A'};
    push_test("abcd", 123, per);

    printf("\n%d\n", sizeof(struct person));
    printf("\n%d\n", sizeof(struct person1));
    printf("\n%d\n", sizeof(struct person2));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ou.cs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值