---------------------------写在前面
已经好久没有玩单片机了,之前玩的stm32根本就不算是学习,只是单纯地使用之前学过的51知识和调用原子的库函数,菜得一匹。有什么不对的地方,还请大家指正,谢谢。
参考:
http://wiki.friendlyarm.com/wiki/index.php/NanoPC-T2/zh#.E7.BC.96.E8.AF.91U-Boot
开发板是使用友善之臂的nanoPc T2,Soc是S5P4418,其他的外设自己看wiki吧,上面都有。我觉得挺不错的,虽然我就只用过这家的,但是用起来还是不错的。
http://weibo.com/p/1001603914482173772682
这是我参考的例程,虽然我没有进去看,(因为我没有微博。。。。)但是我有他的全部相关资料源码,就是整理的微博上的。叫做迪卡大佬,强得一匹。
----------------------------正文
我将以串口波特率的修改,中断,定时器,进行总结,以上均为参考迪卡大佬的文章学之。
一、串口波特率
在我们进行测试的时候,nano与pc串口通信的波特滤是115200,我们没有进行设置,那这些信息从哪来的呢?别忘了,我们还有没能碰的2ndboot,那就他里面的程序指令的功能效果。我们通过我们自己写程序来修改串口波特率。首先,我们与pc通信,是通过引脚rx tx这两个引脚进行收发的,这里也涉及了外部引脚,即GPIO的配置问题。
ok,一步步来,首先查原理图
ok,这样我们就知道了,与外部相接的UART是UART0,他是GPIOD18,所以,我们先查看他的引脚复用情况,可以先查GPIOD14 18 因为你不知道他在里面叫什么名字,使用搜索的时候可能会出现搜不到的情况,所以我们搜GPIOD14 18,
这样我们就知道了UARTTXD0的复用功能号为Function1,即为01,同时我们也知道了引脚号为18,再查
这个又能查出他的寄存器的地址了,所以给他赋值为5:4=01,即,第5、4位为01,该引脚为UART0功能。然后RT也是相同的方法进行寻找和设置。ok,继续,TX是输出,RX是输入,那么继续配置他的输入输出寄存器,还是一些使能开关的配置等等,这些都是可以在datasheet上查的到的。然后就是时钟了,波特率必然又时钟的。
这是在datasheet上查到的,如果我们要设置9600的波特率的话,时钟需要大于3.6864MHZ,迪卡大佬的例子里使用了10M,那么我们也使用10M吧,那么我们就可以反推出Baud Rate Divisor=941.104167,他又两个寄存器,一个放16bit的整数部分,一个放6bit的小数部分,941的16进制为0x41,0.104167的二进制为0x000110,不断二乘,保留6位,这里是有误差的,但也是不可避免的。好了,我们就可以对其进行配置了。然后设置停止位啊,清除标志位啊,巴拉巴拉的。ok,这就可以用了。
好,怎么使用呢?我们发送出去,我们要把数据放在数据寄存器中,供其发送,即UARTDR寄存器,OK了。这就可以使用了。
二、定时器
这个就很简单了,我也没仔细看,就和设置UART的波特率的相似,找到相应的寄存器,进行配置就ok了,pwm也没有详细看看他有没有很方便的功能引脚,直接输出pwm,还是用定时器来模拟的。
三、中断
关于中断,我理解得不太深。现在我还没有找到CPSR寄存器是在哪,搜技术文档也没找着。先放着吧,等以后再说。
哎,看不懂啊。。。那一堆英文文档讲得都是啥啊GIC啊,什么玩意儿啊。。。。不懂不懂。看看能不能强行使用。
我们使用VIC吧:
中断源有64 个,[31:0]是一组为CH0,,[63:32]是一组为CH1
VICIRQSTATUS 只读读取的为IRQ 中断状态,受屏蔽位影响
VICFIQSTATUS 只读读取的为FIQ 中断状态,受屏蔽位影响
VICRAWINTR 只读就像英文表达一样,是生的中断(没有经过加工的,被屏蔽之前的)
VICINTSELECT 用来选择中断源,中断时为IRQ 还是FIQ
VICINTENABLE 用来设置某一位中断允许
VICINTENCLEAR 用来设置某一位中断禁止
VICSOFTINT 用来设置某一位软件中断允许
VICSOFTINTCLEAR 用来设置某一位软件中断禁止
VICPROTECTION 保护模式不用管它啦
VICSWPRIORITYMASK 16 个中断优先级屏蔽
VICVECTPRIORITYDAISY 向量中断优先级菊花链用户可以通过编程选择16 个向量中断优
先级中任意一个优先级为(看不懂)
VICVECTADDR0-31 一共32 个寄存器,用来存放ISR 向量的地址,只有相关中断寄存器disable
时才能写入,切记
如果系统不支持中断向量地址,VICECTADDR 寄存器可以被编程为中断源端口数字,这样可
以容易的被确定
VICVECTPRIORITY0-31 一共32 个寄存器,选择中断优先级
VICADDDRESS 当前active ISR,复位值为0x00000000,读可以读到ISR 地址,并设置当前中
断被服务
以上是我直接从迪卡大佬那搬来的
汇编那里看不懂啊,不过没时间了,工作一天了。。。有点累。讲一下大致思想吧。应该能用。
An FIQ or an IRQ (interrupt requests) are signaled by the Interrupt Controller to CPU. After arbitrating multiple
requests from internal peripherals and GPIO, the Controller requests an interrupt.
9.4.1 Interrupt Flow Sequence Using AHB
The following procedure shows the sequence for the IRQ interrupt flow:
An IRQ interrupt occurs.
The ARM processor branches to the IRQ interrupt vector
Stack the workspace so that IRQ interrupts can be re-enabled later.
Perform a dummy read to the VICADDRESS Register to set up priority status control in the VIC.
Read the VICIRQSTATUS Register and determine which interrupt sources have to be service.
Execute the ISR. At the beginning of the ISR, the interrupt of the processor can be re-enabled so that a higher
priority interrupt can be serviced.
Clear the requesting interrupt in the peripheral, or write to the VICSOFTINTCLEAR Register if the request was
generated by a software interrupt.
Disable the interrupt on the processor and restore the workspace.
Write to the VICADDRESS Register. This clears the respective interrupt in the internal interrupt priority
hardware.
Return from the interrupt. This re-enables the interrupts.
The following procedure shows the sequence for the FIQ interrupt flow.
An FIQ interrupt occurs.
The ARM processor branches to the FIQ interrupt vector.
Branch to the ISR.
Execute the ISR.
Clear the requesting interrupt in the peripheral, or write to the VICSOFTINTCLEAR Register if the request was
generated by a software interrupt.
Disable the interrupts and restore the workspace.
Return from the interrupt. This re-enables the interrupts
应该这个就是介绍FIQ IRQ的了吧,有空再翻译吧。先mark。
我们现在只需要知道有两个中断方式,可以设定。然后查询interrupt source 可知:
7 UART0 UART0 interrupt中断源。只要有串口信息就会触发中断,注意一下几个语句:
VICVECTADDR7_CH0 = (unsigned int)UART0_ISR; //UART0_ISR这个是中断服务函数,把这个函数的入口地址赋给了VICVECTADDR7_CH0
if((addrCH0!=0) && (VICIRQSTTUS_CH0 & (1<<7) )) //判断标志有触发中断
{
/*UART0*/
p_func = (void(*)())addr_CH0;//读取ISR地址,把地址传给函数指针,就可以调用这个中断服务函数了。
}
汇编就看不懂了。。。。。
reset:
/* 设置向量基址寄存器 */
ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0
mrc p15, 0, r0, c1, c0, 0
bic r0, #(1<<13)
mcr p15, 0, r0, c1, c0, 0
/*开irq和fiq*/
mrs r5, cpsr @读取cpsr->r5
bic r5, r5, #0xc0 @允许irq和fiq
msr cpsr, r5
/*跳入C语言main程序*/
bl main
/*main执行完毕后,重新执行*/
b reset
do_irqs: @将irq程序放在这儿
ldr sp, =0xffff9970 @随便找了个应该用不到的地址来做栈区
sub lr,lr,#4
stmfd sp!,{r0-r12,lr}
bl do_irq
ldmfd sp!,{r0-r12,pc}^
看注释能知道是怎么回事,如果让自己写的话,那就写不出来了。这就有有点尴尬了。中断还是难的啊。。。。不过给自己的时间有点少了,等下次再接触这方面的东西再撸把。