时钟对于电子设备来说都是非常重要的,它是传输数据的一个基准,如果没有这个基准的话将导致系统的混乱。
S3C2440的频率有两种输入方式:外部时钟源和内部晶振(如下图)
输入的频率一般是比较低的比如2440的就只有12M,而2440的主频可以达到460M,这就需要对输入频率通过PLL锁相环进行倍频
先来看下这个CLOCK的结果图:
从上面的结果图可以看出输入频率OSC首先经过MPLL倍频
整个系统时钟主要有几个组成:FCLK,HCLK,PCLK
FCLK:是个cpu提供时钟
HCLK:用于AHB总线,中断控制器,LCD控制器,内存控制器提供时钟
PCLK:用于APB总线,通常给IIC,WDT,IIS,ADC, UART, GPIO, RTC and SPI.等外设提供时钟
下面是整个时钟系统的几种工作方式:正常,空闲,慢,睡眠模式。
慢模式:也就是没有通过MPLL倍频,直接就由外部时钟源或者内部晶振来提供时钟,所以系统的功耗有时钟源来决定
设置系统时钟主要配置几个寄存器:
MPLLCON:设置P,S,M的值
CLKDIVN:设置FCLK,HCLK,PCLK的比例关系
MPLL和UPLL的计算公式不同:
Mpll = (2*m * Fin) / (p * 2s)
m = M (the value for divider M)+ 8, p = P (the value for divider P) + 2,s = SDIV
UPLL Control Register
Upll = (m * Fin) / (p * 2S)
m = (MDIV + 8), p = (PDIV + 2), s = SDIV
另外需要特别注意的一点,如果直接采用上面的式子计算输出频率很可能出错,因为会发生溢出,故采用下面的式子:
FOUT = 2 * m * (Fin/100) / (p*2S)×100,
下面是核心代码:
//为了使FCLK=400Mhz,我们取m=92,p=1,s=1.也可以根据手册p255频率表中的数值,
//但是没有400Mhz的组合。可以选接近的
rMPLLCON = 92<<12 | 1<<4 |1 ;
rCLKDIVN = 2<<1 | 1; //FCLK:HCLK:PCLK = 1:4:8
rCAMDIVN = 0<<9 ; //配置CLKDIVN[2:1]与改位有关,可参考手册说明
m = (rMPLLCON>>12) &0xff ;
p = (rMPLLCON>>4) & 0x3f;
s = rMPLLCON & 0x3;
FCLK = ((m+8) * 2 * (FIN/100)) / ( (p+2) * (1 << s))*100;
PCLK = FCLK >>3;
调试程序时,我们可以使用查看变量的方法,但是还是不能离开调试信息的打印。。。。。在开始其他实验时,首先把uart功能实验,方便调试。
1.UART 支持中断模式和DMA模式
2.如果是使用系统时钟,UART最高能支持115.2k/s的数据传输,如果是使用外部的时钟,速度将更高,每道uart有FIFO模式和非FIFO模式,在FIFO模式中有两个64字节的FIFO分别用于接收和发送数据,在非FIFO模式中只有1字节的缓存区
3.下面是uart的结果图
4..从上面的结构图可以看出,UART由:波特率发生器,发送缓存和接收缓存,控制单元四个部分组成,波特率发生器可以是系统时钟(PCLK,FCLK/N)或者外部时钟(UEXTCLK),发送器和接收器各包含一个64字节的FIFO和数据移位器。要发送数据时,先将数据写入到FIFO接着在发送前复制到发送移位器中,随后将数据从发送数据引脚(TXDn)移出;接收数据时,从接收数据引脚(RXDn)移入收到的数据,接着从移位器复制到FIFO。
5.
在串行通讯处理中,常常看到硬件流控制(RTS/CTS)和软件流控制(XON/XOFF)这两个选项,这就是两个流控制的选项,目前流控制主要应用于调制解调器的数据通讯中
硬件流控制常用的有RTS/CTS流控制和DTR/DSR(数据终端就绪/数据设置就绪)流控制。
由于电缆线的限制,我们在普通的控制通讯中一般不用硬件流控制,而用软件流控制。一般通过XON/XOFF来实现软件流控制。常用方法是:当接收端的输入缓冲区内数据量超过设定的高位时,就向数据发送端发出XOFF字符(十进制的19或Control-S,设备编程说明书应该有详细阐述),发送端收到XOFF字符后就立即停止发送数据;当接收端的输入缓冲区内数据量低于设定的低位时,就向数据发送端发出XON字符(十进制的17或Control-Q),发送端收到XON字符后就立即开始发送数据。一般可以从设备配套源程序中找到发送的是什么字符。
应该注意,若传输的是二进制数据,标志字符也有可能在数据流中出现而引起误操作,这是软件流控制的缺陷,而硬件流控制不会有这个问题。
在2440中,只有当CTS信号有效才可以发送数据,CTS有效表明其他的UART的FIFO准备好接收数据,在接收数据之前,RTS应该是有效的,并且FIFO应该是大于32字节,否则为非有效状态
注意:2440的UART 2不支持自动流控制(AFC)
6.LoopBack操作模式:
S3C2410 CPU的UART提供了一种测试模式,也就是这里所说的LoopBack模式。在设计系统的具体应用时,为了判断通讯故障是由于外部的数据链路上的问题,还是CPU内驱动程序或CPU本身的问题,这就需要采用LoopBack模式来进行测试。在LoopBack模式中,资料发送端TXD在UART内部就从逻辑上与接收端RXD连在一起,并可以来验证资料的收发是否正常。
7.uart波特率计算公式:
UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
For example, if the baud-rate is 115200 bps and UART clock is 40 MHz, UBRDIVn is:
UBRDIVn = (int)(40000000 / (115200 x 16) ) -1
= (int)(21.7) -1 [round to the nearest whole number]
= 22 -1 = 21
8.核心代码:
#include "uart.h"
#include "2440addr.h"
#include
#include
#include
#include
#include
#include
//端口和波特率初始化
void uart_init(int baud)
{
int i;
//*** PORT H GROUP
//Ports : GPH10 GPH9 GPH8 GPH7 GPH6 GPH5 GPH4 GPH3 GPH2 GPH1 GPH0
//Signal : CLKOUT1 CLKOUT0 UCLK nCTS1 nRTS1 RXD1 TXD1 RXD0 TXD0 nRTS0 nCTS0
//Binary : 00 , 00 00 , 00 00 , 00 00 , 10 10 , 10 10
rGPHCON = 0xaa ;
//rGPHCON = 0x2a0aaa ;
rGPHUP = 0x7ff; // The pull up function is disabled GPH[10:0]
// 0 0 000 0 11
rULCON0 = 0x3;//Line control register : Normal,No parity,1 stop,8 bits
// [15:12] [11:10] [9] [8] [7] [6] [5] [4] [3:2] [1:0]
// 00 1 0 0 1 0 0 01 01
rUCON0 =0x245;
rUFCON0 = 0x0; //不使用FIFO
rUMCON0 = 0x00; // 不使用流控
rUBRDIV0=( (int)(PCLK/16./baud+0.5) -1 ); //Baud rate divisior register 0
for(i=0;i<100;i++);
}
//字节发送
void uart_send_byte(int data)
{
if(data == 'n') { //结束符
while(!(rUTRSTAT0 &0x2)) ; //等待发送缓冲区为空
WrUTXH0('r'); //直接写数据到UTXH0寄存器中
}
//特别需要注意下面的语句不是用else和if并列
while(!(rUTRSTAT0 &0x2)) ; //等待发送缓冲区为空
WrUTXH0(data);
}
//发送字符串
void uart_send_string(char *string)
{
while(*string)
uart_send_byte(*string++);
}
//实现类似printf函数变量输出
void uart_printf(char *fmt,...)
{
va_list ap;
char string[256];
va_start(ap,fmt);
vsprintf(string,fmt,ap);
uart_send_string(string);
va_end(ap);
}
//从终端读取单个字符
char uart_getch(void)
{
while(!(rUTRSTAT0 &0x1)) ; //等待接收缓冲区中不为空
return RdURXH0(); //直接返回接收数据寄存器URXH0中的值
}
//获取数据
char uart_get_key(void)
{
if(rUTRSTAT0 &0x1) //检查buffer中是否有数据
return RdURXH0();
else
return 0;
}
//从终端得到一个字符串,保存到string中
void uart_get_string(char *string)
{
char *string2 = string;
char c;
while((c = uart_get_key())!='r') //回车
{
if(c == 'b') { //backspace
if((int)string2 < (int)string) {
uart_printf("b b"); //删除最后一个字符
string --;
}
} else {
-
*string++ = c;