由此可知,uart0分别对应s5pv4418的GPIO14和GPIO18,先记住这两个引脚,一会编程时,还要用到。
根据以前的文章,我们还是先建立几个裸机测试程序,把它链接接到2ndboot后面,由2ndboot来加载它,并把控制权交给它来执行。
根据s5pv4418的datasheet,在使用uart进行串口通讯前,我们需要做些准备工作:
众所周知,由于
ARM处理器的好多引脚都是复用的,所以我们在使用它内部集成的控制器的时候,需要对这些控制器做初始化。当然usart也不例外。
这些初始化工作,主要就是配置引脚功能、时钟源及时钟源的频率、根据串口通讯频率,对时钟源进行分频,取出串口通讯需要的频率,设计串口通讯的数据帧格式。
下面程序参考了哀其不幸大侠的程序,在此表示感谢,没有前辈们的无私奉献,不知我们要走多少弯路才能打到这里。
主要的过程就是配置相关寄存器,
1.、设置引脚,UART0的RX、TX对应引脚是gpio14,gpio18,分别设置成输入模式、输出模式,且都设置成UART
通信功能。
2、 选择时钟脉冲源并使能时钟,由2ndboot初始化过程的打印信息可以知道各个Pll时钟脉冲源的频率分别被初始化为
PLL0: 550000000 PLL1: 1200000000 PLL2: 800000000 PLL3:612000000 , 这里选择PLL0即频率550MHz,
3、 对PLL0分频和设置UART波特率,采用55分频因数,得到10MHz,我们的UART实验采用115200的波特率,
根据公式:波特率分频因数=UART时钟/(16*波特率) 得到分频因数为5.42534722。
分频因数由整数和分数部分组成(即BRDI和BRDF),从结果可知BRDI=5,BRDF计算公式为m=integer(BRDF*2n+0.5),n=32,
得到m为27,写入寄存器中时m要减1。
4、设置UART0:奇偶校验禁止,1位停止位,8位数据,使能FIFO、UART0接收和发送功能。
主要的配置就是这些,当然其他的cpu初始化等等都是要做好的,说实话,初始化工作还是比较繁琐的。
本来想自己从头写一个完整的串口通讯程序的,后来偶然看到了x4418团队的串口例程,就打消了这个念头。思量一下,暂时还达不到他们的水平,写出来有误导读者的嫌疑,不如就拿他们的做例子吧!。在这里向x4418的攻城狮致敬,正是因为前辈们的心辛勤劳动,才让我们的学习之路平坦无比。
X4418的例程包括: main.c,main.h,
在主程序main中调用各个部分的初始化函数,进行整个系统的初始化工作
Main.c
#include
extern int tester_serial_stdio(int argc, char * argv[]);
static void do_system_initial(
void)
{
malloc_init();
s5p4418_clk_init();
s5p4418_irq_init();
s5p4418_gpiochip_init();
s5p4418_pwm_init();
s5p4418_serial_initial();
s5p4418_tick_initial();
s5p4418_tick_delay_initial();
s5p4418_fb_initial();
led_initial();
beep_initial();
key_initial();
}
int main(int argc, char * argv[])
{
do_system_initial();
tester_serial_stdio(argc, argv);
return 0;
}
我们着重看看串口的初始化过程:
s5p4418_serial_initial();
它位于s5p4418-serial.c中,程序如下:
#include
static void s5p4418_serial_init(int ch)
{
switch(ch)
{
case 0:
clk_enable("GATE-UART0");
gpio_set_cfg(S5P4418_GPIOD(14),0x1);
gpio_set_cfg(S5P4418_GPIOD(18), 0x1);
gpio_set_direction(S5P4418_GPIOD(14), GPIO_DIRECTION_INPUT);
gpio_set_direction(S5P4418_GPIOD(18), GPIO_DIRECTION_OUTPUT);
break;
case 1:
clk_enable("GATE-UART1");
gpio_set_cfg(S5P4418_GPIOD(15), 0x1);
gpio_set_cfg(S5P4418_GPIOD(19), 0x1);
gpio_set_direction(S5P4418_GPIOD(15), GPIO_DIRECTION_INPUT);
gpio_set_direction(S5P4418_GPIOD(19), GPIO_DIRECTION_OUTPUT);
break;
case 2:
clk_enable("GATE-UART2");
gpio_set_cfg(S5P4418_GPIOD(16), 0x1);
gpio_set_cfg(S5P4418_GPIOD(20), 0x1);
gpio_set_direction(S5P4418_GPIOD(16), GPIO_DIRECTION_INPUT);
gpio_set_direction(S5P4418_GPIOD(20), GPIO_DIRECTION_OUTPUT);
break;
case 3:
clk_enable("GATE-UART3");
gpio_set_cfg(S5P4418_GPIOD(17), 0x1);
gpio_set_cfg(S5P4418_GPIOD(21), 0x1);
gpio_set_direction(S5P4418_GPIOD(17), GPIO_DIRECTION_INPUT);
gpio_set_direction(S5P4418_GPIOD(21), GPIO_DIRECTION_OUTPUT);
break;
default:
return;
}
s5p4418_serial_setup(ch, B115200, DATA_BITS_8, PARITY_NONE, STOP_BITS_1);
}
void s5p4418_serial_initial(void)
{
s5p4418_serial_init(0);
s5p4418_serial_init(1);
s5p4418_serial_init(2);
s5p4418_serial_init(3);
}
bool_t s5p4418_serial_setup(int ch, enum baud_rate_t baud, enum data_bits_t data, enum parity_bits_t parity, enum stop_bits_t stop)
{
u32_t base =S5P4418_UART0_BASE;
u32_t ibaud, divider,fraction;
u32_t temp, remainder;
u8_t data_bit_reg,parity_reg, stop_bit_reg;
u64_t uclk;
switch(ch)
{
case 0:
base = S5P4418_UART0_BASE;
break;
case 1:
base = S5P4418_UART1_BASE;
break;
case 2:
base = S5P4418_UART2_BASE;
break;
case 3:
base = S5P4418_UART3_BASE;
break;
default:
break;
}
switch(baud)
{
case B50:
ibaud = 50;
break;
case B75:
ibaud = 75;
break;
case B110:
ibaud = 110;
break;
case B134:
ibaud = 134;
break;
case B200:
ibaud = 200;
break;
case B300:
ibaud = 300;
break;
case B600:
ibaud = 600;
break;
case B1200:
ibaud = 1200;
break;
case B1800:
ibaud = 1800;
break;
case B2400:
ibaud = 2400;
break;
case B4800:
ibaud = 4800;
break;
case B9600:
ibaud = 9600;
break;
case B19200:
ibaud = 19200;
break;
case B38400:
ibaud = 38400;
break;
case B57600:
ibaud = 57600;
break;
case B76800:
ibaud = 76800;
break;
case B115200:
ibaud = 115200;
break;
case B230400:
ibaud = 230400;
break;
case B380400:
ibaud = 380400;
break;
case B460800:
ibaud = 460800;
break;
case B921600:
ibaud = 921600;
break;
default:
return FALSE;
}
switch(data)
{
case DATA_BITS_5:
data_bit_reg = 0x0;
break;
case DATA_BITS_6:
data_bit_reg = 0x1;
break;
case DATA_BITS_7:
data_bit_reg = 0x2;
break;
case DATA_BITS_8:
data_bit_reg = 0x3;
break;
default:
return FALSE;
}
switch(parity)
{
case PARITY_NONE:
parity_reg = 0x0;
break;
case PARITY_EVEN:
parity_reg = 0x2;
break;
case PARITY_ODD:
parity_reg = 0x1;
break;
default:
return FALSE;
}
switch(stop)
{
case STOP_BITS_1:
stop_bit_reg = 0; break;
case STOP_BITS_1_5:
return -1;
case STOP_BITS_2:
stop_bit_reg = 1; break;
default:
return -1;
}
switch(ch)
{
case 0:
uclk = clk_get_rate("GATE-UART0");
break;
case 1:
uclk = clk_get_rate("GATE-UART1");
break;
case 2:
uclk = clk_get_rate("GATE-UART2");
break;
case 3:
uclk = clk_get_rate("GATE-UART3");
break;
default:
return FALSE;
}
/*
* IBRD = UART_CLK / (16 * BAUD_RATE)
* FBRD = ROUND((64 * MOD(UART_CLK, (16 * BAUD_RATE))) / (16 *BAUD_RATE))
*/
temp = 16 * ibaud;
divider = (u32_t)(uclk / temp);
remainder = (u32_t)(uclk % temp);
temp = (8 * remainder) / ibaud;
fraction = (temp >> 1) + (temp & 1);
write32(phys_to_virt(base + UART_IBRD), divider);
write32(phys_to_virt(base + UART_FBRD), fraction);
write32(phys_to_virt(base + UART_LCRH), (1 << 4) |(data_bit_reg<<5 | stop_bit_reg<<3 | parity_reg<<1));
return TRUE;
}
ssize_t s5p4418_serial_read(int ch, u8_t * buf, size_t count)
{
u32_t base =S5P4418_UART0_BASE;
ssize_t i;
switch(ch)
{
case 0:
base = S5P4418_UART0_BASE;
break;
case 1:
base = S5P4418_UART1_BASE;
break;
case 2:
base = S5P4418_UART2_BASE;
break;
case 3:
base = S5P4418_UART3_BASE;
break;
default:
break;
}
for(i = 0; i < count; i++)
{
if( !(read8(phys_to_virt(base + UART_FR)) & UART_FR_RXFE) )
buf = read8(phys_to_virt(base + UART_DATA));
else
break;
}
return i;
}
ssize_t s5p4418_serial_write(int ch, u8_t * buf, size_t count)
{
u32_t base =S5P4418_UART0_BASE;
ssize_t i;
switch(ch)
{
case 0:
base = S5P4418_UART0_BASE;
break;
case 1:
base = S5P4418_UART1_BASE;
break;
case 2:
base = S5P4418_UART2_BASE;
break;
case 3:
base = S5P4418_UART3_BASE;
break;
default:
break;
}
for(i = 0; i < count; i++)
{
while( (read8(phys_to_virt(base + UART_FR)) & UART_FR_TXFF) );
write8(phys_to_virt(base + UART_DATA), buf);
}
return i;
}
ssize_t s5p4418_serial_write_string(int ch, const char * buf)
{
return s5p4418_serial_write(ch,(u8_t *)buf, strlen(buf));
}
X4418把5个串口都做了初始化,我们用的是第一个uart0,注意看跟uart0有关的红颜色标记的部分。
从串口寄存器配置,到串口波特率配置一应俱全。
在此给x4418的前辈点个赞,程序写的规规矩矩,很值得后来者学习。具体程序不一一解读了,自己看程序吧!
限于本文篇幅,又需要此测试程序的,请私信给我。
在pc端连接好交叉串口线,通讯参数:115200,8N1,无 。
下面是程序运行结果的串口显示信息: