看过我文章的小伙伴有的可能会有疑问,为什么用汇编,用C语言不好吗?我在这里说明一下,因为后面可能要移植UBoot最新的程序,而UBoot的程序在最初的一段是用汇编写的,所以我们这里也用汇编写,后期移植UBoot就很方便了。烧录SD的脚本和第一章点亮LED灯的一样,这里不再贴出来了,而是直接用了。
在STM32单片机里,在编写驱动前做的一件很重要的事情就是时钟树配置,这里串口驱动也是,要先配置时钟树才能配置串口,不然波特率无法计算。
从上面图可以看出,配置时钟树要先配置DMC的时钟,之后在选择左右总线。
从上面的图片可以看出,UART挂载在PERI-L时钟分支下面。
由上面图可以看出,先配置SCLKmpll时钟来源,经过锁相环电路,分频电路最终到达PERIL,而UART就挂载在这个时钟分支下面,有的小伙伴会问,那干嘛配置DMC,请看下图。
内核的时钟树下面蓝色部分有个锁相环,这个锁相环决定了SCLKmpll时钟的来源,而前面还有一个MPLL配置电路,不属于该内核。而锁相环和DMC在一个时钟树中,所以后面需要配置这个锁相环在DMC相关的寄存器中。这里还有一个问题,就是FOUTmpll怎么会配置成的800Mhz,外部时钟来源是24Mhz的有源晶振。
从上述图片可以看出来,MPLL_CON0寄存器可以配置FOUT的值,它的值决定于下面的FOUT公式,而这个公式和MPS的设置有关,而从上面MPS表可以查得,P=3,M=100,S=0时FOUT的值就是800了。
OK!总结一下配置的流程:
先配置MPLL_CON0寄存器让FOUT的值为800,在配置CLK_SRC_DMC寄存器使锁相环选定FOUTmpll为时钟来源,再配置CLK_SRC_TOP1寄存器使MUXmpll_ctrl_user_T锁相环选定SCLKmpll为时钟来源,再配置CLK_SRC_PERIL0寄存器使时钟作用于想用的UART,再配置CLK_DIV_PERIL0寄存器使DIVACLK_100把MPLL的8分频后作用于对应的UART,时钟配置到这里就结束了。之后再设置UART的触发方式,数据格式,波特率等就简单了。这里不再叙述UART的配置方法,根据源码去三星的手册中查寄存器即可。
新建文件夹及文件
mkdir uart
cd uart
touch main.S exynos4412.h uart.lds Makefile
#include "exynos4412.h"
.global _start
.word 0x2000
.word 0x0
.word 0x0
.word 0x0
_start:
ldr r10, =0x1002330c
ldr r11, [r10]
orr r11, r11,#0x300
str r11, [r10]
ldr r10, =0x11000c08
ldr r11, =0x0
str r11, [r10]
ldr r10, =GPA1CON
ldr r11, =0x222222
str r11, [r10]
ldr r10, =MPLL_CON0
ldr r11, =0x80640300
str r11, [r10]
ldr r10, =CLK_SRC_DMC
ldr r11, =0x00011000
str r11, [r10]
ldr r10, =CLK_SRC_TOP1
ldr r11, =0x01111000
str r11, [r10]
ldr r10, =CLK_SRC_PERIL0
ldr r11, =0x66666
str r11, [r10]
ldr r10, =CLK_DIV_PERIL0
ldr r11, =0x777777
str r11, [r10]
ldr r10, =UFCON2
ldr r11, =0x111
str r11, [r10]
ldr r10, =ULCON2
ldr r11, =0x3
str r11, [r10]
ldr r10, =UCON2
ldr r11, =0x3c5
str r11, [r10]
ldr r10, =UBRDIV2
ldr r11, =0x35
str r11, [r10]
ldr r10, =UFRACVAL2
ldr r11, =0x4
str r11, [r10]
ldr r10, =UTXH2
ldr r11, =0x55
str r11, [r10]
ldr r11, =0x61
str r11, [r10]
ldr r11, =0x72
str r11, [r10]
ldr r11, =0x74
str r11, [r10]
ldr r11, =0xA
str r11, [r10]
ldr r11, =0xD
str r11, [r10]
loop:
ldr r10, =GPL2CON
mov r11, #(0x01<<0)
str r11, [r10]
ldr r10, =GPL2DAT
mov r11, #0x01
str r11, [r10]
b loop
#ifndef EXYNOS4412_H
#define EXYNOS4412_H
#define GPX1CON (0x11000000+0x0c20)
#define GPX1DAT (0x11000000+0x0c24)
#define GPX1PUD (0x11000000+0x0c28)
#define GPX1DRV (0x11000000+0x0c2c)
#define GPK1CON (0x11000000+0x0060)
#define GPK1DAT (0x11000000+0x0064)
#define GPK1PUD (0x11000000+0x0068)
#define GPK1DRV (0x11000000+0x006c)
#define GPL2CON (0x11000000+0x0100)
#define GPL2DAT (0x11000000+0x0104)
#define GPL2PUD (0x11000000+0x0108)
#define GPL2DRV (0x11000000+0x010c)
//uart
// GPIO
#define GPA1CON (0x11400020)
// MPLL
#define MPLL_CON0 (0x10040108)
#define CLK_SRC_DMC (0x10040200)
#define CLK_SRC_TOP1 (0x1003C214)
// system clock
#define CLK_SRC_PERIL0 (0x1003C250)
#define CLK_DIV_PERIL0 (0x1003C550)
// UART
#define UFCON2 (0x13820008)
#define ULCON2 (0x13820000)
#define UCON2 (0x13820004)
#define UBRDIV2 (0x13820028)
#define UFRACVAL2 (0x1382002c)
#define UTXH2 (0x13820020)
#define URXH2 (0x13820024)
#define UTRSTAT2 (0x13820010)
#endif
CROSS_COMPILE = arm-linux-gnueabihf-
%.o : %.S
$(CROSS_COMPILE)gcc -o $@ $< -c
%.o : %.c
$(CROSS_COMPILE)gcc -o $@ $< -c
.PHONY: all
all : uart.elf
uart.elf : main.o uart.lds
$(CROSS_COMPILE)ld -T uart.lds -o uart.elf $^
$(CROSS_COMPILE)objcopy -O binary uart.elf uart.bin
$(CROSS_COMPILE)objdump -D uart.elf > uart.dis
.PHONY : clean
clean:
rm -rf *.o *.elf *.bin *.dis
SECTIONS
{
. = 0x02023400;
.text : {
main.o
* (.text)
}
.rodata ALIGN(4) : {
* (.rodata*)
}
.data ALIGN(4) : {
* (.data*)
}
.bss ALIGN(4) : {
* (.bss)
* (COMMON)
}
}
修改完上诉文件使用指令make生成uart.bin下面要用到
我这里的SD卡的设备节点是sdb,请根据自己的实际情况改正后烧录
cd sd_fuse/itop4412
./sd_fusing.sh /dev/sdb ../../uart.bin
这里现象就不发图片了,现象就是连接串口之后,串口助手会显示Uart四个字母,开发板有一个LED灯亮。如果有疑问,请加群讨论。
可以加入群聊:667039215找群主获取
CSDN获取:uart压缩包
github下载:git clone https://github.com/HOU1354696096/ITOP4412.git