0.前言
最近想体验一下面试,真正收到公司通知又有点无从下手,没有做准备。但是反手一想,既然是想体验,锻炼而已,干就完了。
推荐一首歌《Timber》——MattyBRaps,也是考研时期常听的一首。
1.K2按键控制蜂鸣器
我用的是三星的S3C2410A芯片。
上个博客说了开发流程,裸机开发的步骤:需求分析,查原理图,查芯片手册,code。
1.1需求分析
过!!!
1.2查原理图
搜k2
GPX1_1(XEINT9) 这就是引脚。中间的其它过程略过。
1.3查芯片手册
1.3.1配置中断
找到GPX1_1
地址0x11000c20 4-7位写入0xf 这里面有个EXT_INT41[1] 这是对应的中断触发方式
接下来找EXT_INT41的1口
地址0x11000e04 的4-6位写入0x2 下降沿触发(这是硬件工程师告诉我们的 或者自己找所用器件的相关资料)
还有一点 这个板子默认是不中断 所以要找到中断的管脚 取消中断掩码,因为用的是EXT_INT41 所以找EXT_INT41_MASK
刚才用的是1口 所以
把这个地址的1位置0代表启用中断
1.3.2gic-->过滤
之前找到了GPX1_1这个引脚 对应XEINT9这个中断寄存器 这个XEINT9对应的就是57好中断源。
怎么知道的呢?
往下
Spi25,Gic中相关配置,所以接下来找中断控制这一章节
肯定选寄存器
选哪个 因为是57号 对应spi是25 现在又有问题 用哪个CPU呢?
用 cpu0 ,然后,
看这个
找到设置cpu0的
刚好25就在0-31之间 所以选ICDISER_CPU0
加上相应偏移地址就是找到这个1
这几步操作都是为了让57号中断源启动 , 使能57, 把地址0x10490104的25位写入1 , 为啥是25位 , 首先cpu0管了160个中断源 cpu0又分了ser01234 , 五个 ,160/5=32,所以是ser1管57号源(不是spi号), 57-32=25 所以25位写1 。
(再或者就理解为25属于ser1 所以直接就配25位)
这几步完成了使能57号。
接下来把中断源交给cpu0去
是这个。
又该选哪个 ?到这里是不是感觉可麻烦,是真麻烦
发现一共有40个 ,知道是CPU0 , 刚才说了有160个源 , 这边分成40个处理 , 160/40=4 ,所以 57在14*4=56 ,在第15个 ,又因为从零开始 , 所以 在14。
接着
我们知道是ser1(上面)所以选8-15bit位写入 写入啥
写入0x00000001 , 为啥 ,对应CPU0啊
所以就是0x10490938的8-15写入1
然后 中断给了cpu 那就要设置中断优先级
用这个
也是找14
写入也是8-15位 写什么 这个随便(0~255之间) 假如我们取12
就是0x10490438这个地址的8-15写入12
然后 57源可以中断了 接下来设置cpu0使能中断
0x10480000 的0 位 写入1
接着设置cpu0的中断优先级阈值(0-255)
0x10480004的0-7位写入ff 就代表所有中断优先级都可以通过
最后 开启GIC
0x10490000 0位写入1
1.3.3中断处理
上面已经打开了GIC 接下来需要得到中断号
0x1048000C 0-9 不写东西 等下在代码里分析
到这一步就算结束了 但是还有清理工作
1清除管脚中断标志(必须清)
因为原来用的就是INT41的1口 0x11000F44 1位写入1
最后清除GIC的57号中断标志
0x10490284 的25位写入1 代表25(spi 就是57源)清除
最后的最后 结束中断
0x10480010 的0-9写入57 彻底结束57
还有搜蜂鸣器的步骤,我跳过了,都一样的。代码中会有的。
恭喜你自己吧,都看到这里了,这么有耐心,相信会换来糖吃。
1.4代码
1.4.1汇编部分
因为这个是裸机开发,少不了汇编。是汇编配合C实现的。
.text
.global _start
_start:
b reset @reset复位
nop @undefine
nop @swi
nop @预取异常
nop @数据异常
nop @保留
b irq_handler @外中断异常 K2键外部中断
nop @快速中断异常
reset: @****1.初始化
ldr r0,=0x40008000 @设置中断向量位置 这还与软中断不一样
mcr p15,0,r0,c12,c0,0
@这个SOC有16个协处理器 ARM处理器是老大 这协处理器是老二
@这条指令是专属于协处理器指令 mcr是将ARm处理器的内容给协处理器 就是老大安排老二做事
@mrc是老二给老大传送内容 就是汇报
@为什么要用这个mcr ARM 懒呗 其实是 不能所有工作都交给ARM做 一般老大不做事 就是安排事
@p15 是第16个协处理器 交给他去做 0默认值
@r0是ARM内容 把ARM的r0里的 就是0x40008000这个地址里的东西给P15的c12寄存器
@c0 0 代表是如果c12装不下就继续往c0装
@要定义两种处理器模式下的栈 为什么要定义栈 用栈去处理函数啊 函数都是用栈实现的
@切换到irq模式 10010 IRQ
mrs r0,cpsr
bic r0,#0x1f @先把后五位清零
orr r0,#0x12 @0x12=10010 再或上
msr cpsr,r0
ldr sp,=irq_end @定义这个栈
@切换用户模式 10000 User mode;
mrs r0,cpsr
bic r0,#0x9f @9f=100 11111 把后五位清零 和第八位清零 为什么 因为用户模式下
@用户模式不可以中断 初始值是1 清零代表可以中断
orr r0,#0x10 @0x10=10000
msr cpsr,r0
ldr sp,=usr_end @定义这个栈
b main @执行完初始化 会进入主函数 等待按下按键实现中断
irq_handler:
sub lr,lr,#4 @lr-4表示当前中断点地址
stmfd sp!,{r0-r12,lr}
bl doirq
ldmfd sp!,{r0-r12, pc}^
.data
irq_start:
.space 160
irq_end:
usr_start:
.space 160
usr_end:
.end
1.4.2C部分
#define GPA1CON (*(volatile unsigned int *)0x11400020)
#define ULCON2 (*(volatile unsigned int *)0x13820000)
#define UBRDIV2 (*(volatile unsigned int *)0x13820028)
#define UFRACVAL2 (*(volatile unsigned int *)0x1382002c)
#define UCON2 (*(volatile unsigned int *)0x13820004)
#define UTRSTAT (*(volatile unsigned int *)0x13820010)
#define URXH2 (*(volatile unsigned int *)0x13820024)
#define UTXH2 (*(volatile unsigned int *)0x13820020)
//中断
#define GPX1CON (*(volatile unsigned int *)0x11000c20)
#define EXT_INT41CON (*(volatile unsigned int *)0x11000e04)
#define EXT_INT41_MASK (*(volatile unsigned int *)0x11000f04)
#define ICDISER_CPU0 (*(volatile unsigned int *)0x10490104)
#define ICDIPDR14_CPU0 (*(volatile unsigned int *)0x10490838)
#define ICDIPR14_CPU0 (*(volatile unsigned int *)0x10490438)
#define ICCICR_CPU0 (*(volatile unsigned int *)0x10480000)
#define ICCPMR_CPU0 (*(volatile unsigned int *)0x10480004)
#define ICDDCR (*(volatile unsigned int *)0x10490000)
#define ICDIAR_CPU0 (*(volatile unsigned int *)0x1048000c)
#define EXT_INT41_PAND (*(volatile unsigned int *)0x11000f44)
#define ICDICPR_CPU (*(volatile unsigned int *)0x10490284)
#define ICCEOIR_CPU0 (*(volatile unsigned int *)0x10480010)
//bzz
#define GPD0CON (*(volatile unsigned int *)0x114000a0)
#define TCFG0 (*(volatile unsigned int *)0x139d0000)
#define TCFG1 (*(volatile unsigned int *)0x139d0004)
#define TCNTB0 (*(volatile unsigned int *)0x139d000c)
#define TCMPB0 (*(volatile unsigned int *)0x139d0010)
#define TCON (*(volatile unsigned int *)0x139d0008)
static int tag=0;
void delay()
{
int i=0;
for(i=0;i<1000000;i++)
{
;
}
}
void delay_doudong(int time)
{
int i=0;
for(i=0;i<time;i++)
{
;
}
}
void init_k2() //初始化
{
GPX1CON = GPX1CON | (0xf<<4);
EXT_INT41CON = EXT_INT41CON & (~(0x7<<4)) | (0x2<<4);
EXT_INT41_MASK = EXT_INT41_MASK & (~(0x1<<1));
ICDISER_CPU0 = ICDISER_CPU0 | 0x1<<(57-32);
ICDIPDR14_CPU0 = ICDIPDR14_CPU0 & (~(0xff<<8)) |(0x1<<8);
ICDIPR14_CPU0 = ICDIPR14_CPU0 & (~(0xff<<8)) | (12<<8);
ICDIPR14_CPU0 = 1;
ICCPMR_CPU0 = 0xff;
ICDDCR = 1;
//bzz初始化
//1 配置GPD0_0为PWM输出模式
GPD0CON = GPD0CON &(~(0xf)) | 0x2;
//2 配置一级分频--》25
TCFG0 = TCFG0 &(~(0xff)) | 0x24;
//3 配置二级分频--》4
TCFG1 = TCFG1 &(~(0xf)) | 0x2;
//4 设置输入波形个数
TCNTB0 = 1912;
//5 设置输入波形中高电平的持续时间
TCMPB0 = 1912/2;
TCON = TCON | (1<<3) | (1<<1);
}
void bzz_on()
{
TCON = TCON &(~(1<<1)) | 1; // 1左移1 10 取反 01
}
void bzz_off()
{
TCON = TCON & (~(0x1 << 0));
}
void init_uart()
{
GPA1CON = GPA1CON &~(0xff) | (0x22);
ULCON2 = 0<<6 | 0<<5 |0<<2 | 0x3;
UBRDIV2=53; //整数部分
UFRACVAL2=4; //小数部分
UCON2 = UCON2 &~(0xf) | (1<<2) | 1;
}
char recv()
{
while(!(UTRSTAT&1))
{
;
}
return URXH2;
}
void send(char c)
{
while(!(UTRSTAT &(1<<1) ))
{
;
}
UTXH2 = c;
}
void doirq()
{
int num = ICDIAR_CPU0 & (0x3ff);
switch(num)
{
case 57:
{
tag++;
send('o');
send('k');
bzz_on();
//delay();
if(tag%2==0){
bzz_off();
//delay();
}
EXT_INT41_PAND = EXT_INT41_PAND | (1<<1);
ICDICPR_CPU = ICDICPR_CPU | (1<<(57-32));
}
break;
}
ICCEOIR_CPU0 = ICCEOIR_CPU0 & (~(0x3ff)) | num;
}
int main()
{
init_k2();
init_uart();
while(1)
{
;
}
}
以上就是全部代码。
1.4.3代码总结
有个问题是什么,我没有解决按键抖动的问题。其他还好。嘿嘿。
2.总结
一切代码皆逻辑。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)