【JZ2440筆記】串口通信

目錄

一、前言

二、實驗目標

三、串口資源介紹

四、程序編寫

五、實驗總結


一、前言

串口通信是嵌入式開發中非常常見的調試工具接口,我們大都通過串口的打印輸出來確定程序的運行狀況,無論是在單片機還是在各種ARM處理器上,基本上都會有串口這個外設,以下是S3C2440的串口調試過程。

 

二、實驗目標

通過JZ2440上的串口0實驗與PC機的串口通信,波特率爲115200、無奇偶校驗位,8個數據位,1個停止位,並且開發板將串口助手發送的數據原樣返回給串口助手。

 

三、串口資源介紹

1、開發板連線

S3C2440有三個串口模塊,分別爲UART0、UART1和UART2,JZ2440開發板將這三個串口全部引出到排針,其中UART0還通過PL2303芯片轉出了一個micro USB接口,原理圖如下:

 

2、S3C2440串口介紹

串口模塊方框圖如下:

串口模塊可以通過PCLK、FCLK/n或UEXTCLK來提供運行時鐘,每個串口通道都有64字節的發送緩衝寄存器和64字節的接收緩衝寄存器,這些緩衝寄存器可以通過配置選擇使用或者不使用,同時串口模塊還支持中斷和DMA傳輸,這些附加功能跟單片機一模一樣。另外串口模塊還可以配置位紅外模式來使用。

 

3、串口寄存器配置

串口的波特率和分頻之間的計算公式如下:

UBRDIVn = (int)( UART 時鐘 / ( 波特率 × 16) ) - 1

舉個例子:如果波特率爲 115200 bps 並且 UART 時鐘爲 40 MHz,則 UBRDIVn 爲:

UBRDIVn = (int)(40000000 / (115200 x 16) ) - 1

= (int)(21.7) - 1 [ 取最接近的整數]

= 22 - 1 = 21

當然,由於取整的原因,以上計算是有一定誤差的,手冊上建議的誤差是UART 幀誤差應該小於 1.87%(3/160)。波特率設置的寄存器如下:

我們使用串口0只需要設置ULCON0,波特率爲115200、無奇偶校驗位,8個數據位,1個停止位,所以ULCON0的配置爲0x03。

接下來是UCON寄存器:

因爲使用的是PCLK作爲串口工作時鐘,所以FCLK Divider不用管,Clock Selection設爲0,Tx Interrupt Type設爲0不使用發送FIFO,Rx Interrupt Type設爲0不使用接收FIFO,Transmit Mode 設置爲01,Receive Mode設置爲01。這樣UCON0寄存器就設置爲0x05。

還有波特率分頻設置:

UBRDIV0 = (PCLK_SPEED / (115200 * 16)) - 1,PCLK_SPEED爲50MHz,所以UBRDIV0爲26。

配置好了上述寄存器後,我們還需要有標誌位來判斷什麼時候接收到了數據,什麼時候發送完成了數據,有如下的狀態寄存器:

要發送的數據需要寫到UTXH0 寄存器中,接收數據可以從URXH0中獲得。

 

四、程序編寫

程序分爲以下幾個文件:

head.S;啓動文件。

init.c:關閉看門狗,初始化時鐘的函數。

uart.c:串口相關配置。

uart.h:串口頭文件。

main.c:主函數。

Makefile:編譯程序。

每個文件具體內容如下:

head.S

@*************************************************************************
@ File:head.S
@ 功能:設置FCLK到400MHz,然後初始化串口
@*************************************************************************       
.text
.global _start
_start:

	ldr	    sp, =4096                       @設置堆棧,因爲要調用C語言函數 
	bl	    disable_watch_dog               @關WATCH DOG
	bl	    init_system_clk                 @初始化系統時鐘,FCLK=400MHz,HCLK=100MHz,PCLK=50MHz
    bl      main                            @跳轉執行main函數

halt_loop:
    b       halt_loop


init.c



/* WOTCH DOG register */
#define REG_WTCON               (*(volatile unsigned long *)0x53000000)

/* Sys Clk Config */
#define REG_CLKDIVN             (*(volatile unsigned long *)0x4C000014)
#define REG_CAMDIVN             (*(volatile unsigned long *)0x4C000018)
#define REG_MPLLCON             (*(volatile unsigned long *)0x4C000004)

void disable_watch_dog();
void init_system_clk();

/*上電後,WATCH DOG默認是開着的,要把它關掉 */
void disable_watch_dog()
{
	REG_WTCON	= 0;
}

void init_system_clk()
{
    //HCLK = FCLK/4, 當 CAMDIVN[9] = 0 時
    //PCLK 設置爲 HCLK/2 
    //完成配置FCLK : HCLK : PCLK = 1 : 1/4 : 1/8,DIVN_UPLL是USB的時鐘不用管
    REG_CLKDIVN = (2 << 1) | (1 << 0);

    /* 如果HDIVN非0,CPU的總線模式應該從“fast bus mode”變爲“asynchronous bus mode” */
__asm__(
    "mrc    p15, 0, r1, c1, c0, 0\n"        /* 讀出控制寄存器 */ 
    "orr    r1, r1, #0xc0000000\n"          /* 設置爲“asynchronous bus mode” */
    "mcr    p15, 0, r1, c1, c0, 0\n"        /* 寫入控制寄存器 */
    );

    //m=MDIV+8, p=PDIV+2, s=SDIV, Mpll = ( 2 × m × Fin ) / ( p × 2^s )
    //FCLK = (2 * (92 + 8) * 12000000) / ((1 + 2) * 2) = 400000000 = 400MHz
    //配置完MPLL後時鐘停振,CPU停止運行等待時鐘輸出穩定,之後FCLK=400MHz,HCLK=100MHz,PCLK=50MHz */
    REG_MPLLCON = (92<<12)|(1<<4)|(1<<0);
}

uart.c

#include "uart.h"

void init_uart(DWORD buadrate)
{
    //Step1,配置GPIO,GPH3(RXD0),GPH2(TXD0)
    //清除相關配置位
    REG_GPHCON &= ~((DWORD)(3 << (2*3)) | (3 << (2*2)));
    REG_GPHDAT &= ~((DWORD)(1 << 3) | (1 << 2));
    REG_GPHUP &= ~((DWORD)(1 << 3) | (1 << 2));
    //設置相關配置位
    REG_GPHCON |= ((DWORD)2 << (2*3)) | (2 << (2*2));
    REG_GPHDAT |= ((DWORD)1 << 3) | (1 << 2);
    REG_GPHUP |= ((DWORD)1 << 3) | (1 << 2);

    //無校驗,1個停止位,8個數據位
    REG_ULCON0 = 0x03;
    //發送和接受設置爲查詢/中斷模式
    REG_UCON0 = 0x05;
    //不使用FIFO
    REG_UFCON0 = 0;
    //不使用流控
    REG_UMCON0 = 0;

    //UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
    REG_UBRDIV0 = (PCLK_SPEED / (115200 * 16)) - 1;
}

void uart_send(BYTE ch)
{
    while(!(REG_UTRSTAT0 & (1 << 2)))
    {
        ;
    }

    REG_UTXH0 = ch;
}

BYTE uart_receive()
{
    while(!(REG_UTRSTAT0 & (1 << 0)))
    {
        ;
    }

    return REG_URXH0;
}

uart.h

#ifndef _UART_H_
#define _UART_H_

#define BYTE unsigned char
#define WORD unsigned short
#define DWORD unsigned int

/* Uart Config */
#define PCLK_SPEED              50000000

#define REG_GPHCON              (*(volatile unsigned long *)0x56000070)
#define REG_GPHDAT              (*(volatile unsigned long *)0x56000074)
#define REG_GPHUP               (*(volatile unsigned long *)0x56000078)

#define REG_ULCON0              (*(volatile unsigned long *)0x50000000)
#define REG_UCON0               (*(volatile unsigned long *)0x50000004)
#define REG_UFCON0              (*(volatile unsigned long *)0x50000008)
#define REG_UMCON0              (*(volatile unsigned long *)0x5000000C)

#define REG_UTXH0               (*(volatile unsigned long *)0x50000020)
#define REG_URXH0               (*(volatile unsigned long *)0x50000024)

#define REG_UBRDIV0             (*(volatile unsigned long *)0x50000028)

#define REG_UTRSTAT0            (*(volatile unsigned long *)0x50000010)

void init_uart(DWORD buadrate);
void uart_send(BYTE ch);
BYTE uart_receive();

#endif

main.c

#include "uart.h"

void wait(volatile unsigned long dly)
{
	for(; dly > 0; dly--);
}

int main()
{
	init_uart(115200);

	while(1)
	{		
		uart_send(uart_receive());
	}
	
	return 0;
}



Makefile

objs := head.o init.o uart.o main.o

uart.bin: $(objs)

	arm-linux-ld -Ttext 0x0000000 -g -o uart_elf $^
	arm-linux-objcopy -O binary -S uart_elf $@
	arm-linux-objdump -D -m arm uart_elf > uart.dis
	
%.o:%.c
	arm-linux-gcc -Wall -O2 -c -o $@ $<

%.o:%.S
	arm-linux-gcc -Wall -O2 -c -o $@ $<

clean:
	rm -f uart.bin uart_elf uart.dis *.o	

最後,將所有源文件拷貝到linux下,執行make命令後,將生成的bin文件燒寫到開發板NandFlash中,選擇開發板nand啓動後,連接串口線到串口0,使用串口助手可以看見實驗現象,串口助手發送的所有數據被原樣返回。

 

五、實驗總結

串口的配置方式和寄存器基本都和單片機的一樣,也就那些基本的操作。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章