SOC串口的配置
SOC串口的配置
1 UART工作原理
SoC共集成了12路的UART。这12路UART均可以配置为智能UART模式,由于我们的驱动是透传数据通信,所以不使用到智能模式。12路UART可以独立并行工作,每一路UART都有一个独立的FIFO,其大小为4k*8bit,发送和接收各为2k*8bit;通讯数据格式可以配置,默认是一个起始位、八位数据位、无校验、一个停止位;通讯波特率可通过软件设置,典型的波特率为38.4Kbps、76.8Kbps、115.2Kbps、614.4Kbps;最高波特率1Mbps;具有相应的通讯发送和接收的握手标志;通讯接收错误、发送FIFO变空以及接收FIFO达到阈值都会产生中断,并可通过软件查询内部的中断标志寄存器获得中断源信息;可以和通用的异步串行通讯控制器进行正常的通讯。其体系结构如图1所示。
图1 UART体系结构
数据接收先通过缓存FIFO,然后进入到接收链路,进行滤波后送入到控制器,数据发送通过发送链路到发送缓存FIFO,信号输出。
2 配置流程
Soc的UART支持非智能模式和智能模式,我们使用非智能模式,其配置流程如下:
- 配置UART的时钟使能,配置外设时钟使能寄存器(0x40C00000)的15-4bit为0xfff,使能12路串口时钟。
- 配置UART的时钟源选择,配置外设配置寄存器(0x40C00004)的第4位为1,选择UART模块时钟为AHB模块主时钟.
- 配置串口引脚复用寄存器IOMUX的3-0bit为0x0,配置为UART串口引脚功能。
- 复位UART功能,向UART串口命令寄存器CMD中写入0xff,并且进行延时等待复位完成。
- 配置UART的波特率,,先分析PLL主时钟的设置数值,如果是旁路时钟的话,通过外设时钟直接计算波特率数值,如果是锁相环时钟的话,通过主时钟的数值计算波特率数值,其波特率数值计算公式为:(PERIPHERAL_CLK/(16*BaudRate)) & 0xff;PERIPHERAL_CLK表示串口外设时钟,旁路为50MHz,主时钟模式为主时钟的1/2。
- 配置UART为非智能模式,1个停止位,偶校验,FIFO模式,正常工作模式,并且使能接收功能,配置通用控制寄存器UCR(0bit为0x0,3-1为0x0,8bit为0x0,9bit为0,10bit为1,11bit为0)。
- 如果使用中断,配置FIFO阈值寄存器ITL,范围是1-2048。
- 如果使用中断,配置串口中断使能寄存器IER,配置1bit为1使能达到阈值触发中断。
- 如果使用中断,中断服务函数中读取中断标志寄存器清除中断标识。
- 如果使用中断,配置对应中断ID(uart0-uart11为62-73)号对应的中断分配器寄存器和CPU中断接口控制器寄存器。
- 串口发送函数的设计,轮询获取UART状态寄存器的数值,如果串口发送FIFO满了就不写数据到发送FIFO中,如果发送FIFO不满则将数据写入到发送FIFO中。
- 串口接收函数的设计,轮询获取UART状态寄存器的数值,如果串口接收FIFO不空就将接收FIFO中所有的数据全部读出给用户,如果接收FIFO空了,就不读数据给用户。
3 数据结构封装
根据UART模块寄存器地址在内存分配图中的分布,将其地址定义为整型宏定义,将寄存器定义为各位各个功能位域的结构联合体。这样子将整型地址转换成寄存器的结构联合体指针,就能够通过寄存器位域去编写底层驱动了,图1表示宏定义寄存器的定义和类型转换,图2表示寄存器结构联合体定义。
图1
图2
附录:源码
soc_uart.h头文件:
/*
* soc_uart.h
*
* Created on: 2020年5月25日
* Author: dz
*/
#ifndef COMMON_SOC_UART_H_
#define COMMON_SOC_UART_H_
#include "soc.h"
/*-------------------------校验模式----------------------------*/
typedef enum
{
even_parity = 0, //接收发送均为偶校验
odd_parity = 1, //接收发送均为奇校验
txeven_rxodd_parity = 2, //发送偶校验,接收奇校验
txodd_rxeven_parity = 3, //发送奇校验,接收偶校验
txeven_rxnone_parity = 4, //发送偶校验,接收无校验
txodd_rxnone_parity = 5, //发送奇校验,接收无校验
none_parity = 6, //不产生校验
} UART_PARITY_TYPE;
/*-------------------------停止位个数----------------------------*/
typedef enum
{
one_stop = 0, //1位停止位
two_stop = 1, //2位停止位
} UART_STOP_TYPE;
typedef struct _Uart_Config_Type{
Uint32 BaudRate;
UART_STOP_TYPE stop; //停止位个数
UART_PARITY_TYPE parity; //奇偶校验模式
BOOL isLoop; //是否自环模式
BOOL isIntelligenceMode; //是否智能工作模式
BOOL isEnableReceived; //是否使能接收
BOOL isRamMode; //是否使用RAM模式
}Uart_Config_Type;
Uint32 FIND_UART(Uint8 Numb,REG_UART_TYPE** UARTx);
Uint32 UART_GetFlagStatus(Uint8 Numb,UCRUSR_REG *ucr_value);
Uint32 UART_SendData(Uint8 Numb, Uint8* buff, Uint32 length);
Uint32 UART_ReceiveData(Uint8 Numb, Uint8* buff, Uint32* length);
void UART_Init(Uint8 Numb,Uint32 BaudRate,Uint32 parity);
void UART_INT_Enable(Uint8 Numb, Uint32 type);
Uint8 UART_Get_IntStatus(Uint8 Numb);
#endif /* COMMON_SOC_UART_H_ */
soc_uart.c驱动源文件:
/*
* soc_uart.c
*
* Created on: 2020年5月25日
* Author: dz
*/
#include "soc_uart.h"
Uint32 FIND_UART(Uint8 Numb,REG_UART_TYPE** UARTx)
{
if(Numb > 11)
{
return 2;
}
switch(Numb)
{
case 0:
{
*UARTx = REG_UART0;
}break;
case 1:
{
*UARTx = REG_UART1;
}break;
case 2:
{
*UARTx = REG_UART2;
}break;
case 3:
{
*UARTx = REG_UART3;
}break;
case 4:
{
*UARTx = REG_UART4;
}break;
case 5:
{
*UARTx = REG_UART5;
}break;
case 6:
{
*UARTx = REG_UART6;
}break;
case 7:
{
*UARTx = REG_UART7;
}break;
case 8:
{
*UARTx = REG_UART8;
}break;
case 9:
{
*UARTx = REG_UART9;
}break;
case 10:
{
*UARTx = REG_UART10;
}break;
case 11:
{
*UARTx = REG_UART11;
}break;
default:
{
*UARTx = REG_UART0;
}
break;
}
return 0;
}
Uint32 UART_GetFlagStatus(Uint8 Numb,UCRUSR_REG *ucr_value)
{
REG_UART_TYPE* Uart;
Uint32 rel = 0;
rel = FIND_UART(Numb,&Uart);
if(rel == 0)
{
ucr_value->all = Uart->UCR.all;
}
else
{
return rel;
}
return 0;
}
Uint32 UART_SendData(Uint8 Numb, Uint8* buff, Uint32 length)
{
Uint32 i = 0;
Uint32 Flag_Full = 0;
REG_UART_TYPE* Uart;
Uint32 rel = 0;
UCRUSR_REG ucr_reg;
if((length<1)||(length>255))
return 4;
rel = FIND_UART(Numb,&Uart);
if(rel == 0)
{
do
{
UART_GetFlagStatus(Numb,&ucr_reg);
Flag_Full = ucr_reg.bit1.FIFOTF;
if(1 == Flag_Full)
{
return 5;
}
else
{
Uart->FIFO = *(buff+i);
i = i + 1;
}
}while(i < length);
}
else
{
return rel;
}
return 0;
}
Uint32 UART_ReceiveData(Uint8 Numb, Uint8* buff, Uint32* length)
{
Uint32 rel = 0;
REG_UART_TYPE* Uart;
UCRUSR_REG ucr_reg;
Uint32 Length_Tmp = 0;
Uint32 Flag_Empty = 1;
Uint32 Flag_Error = 0;
rel = FIND_UART(Numb,&Uart);
if(rel == 0)
{
do
{
UART_GetFlagStatus(Numb,&ucr_reg);
Flag_Empty = ucr_reg.bit1.FIFORE;
Flag_Error |= ucr_reg.bit1.PE;
if(0 == Flag_Empty)
{
*(buff + Length_Tmp) = Uart->FIFO;
Length_Tmp = Length_Tmp + 1;
}
}while((Length_Tmp < 255) && (0 == Flag_Empty));
*length = Length_Tmp;
if(0 == Length_Tmp)
{
return 6;
}
if(1 == Flag_Error)
{
return 9;
}
}
else
{
return rel;
}
return 0;
}
void delay(int count)
{
while(count--);
}
void UART_Init(Uint8 Numb,Uint32 BaudRate,Uint32 parity)
{
REG_UART_TYPE* Uart;
Uint32 rel = 0;
Uint32 bypass, fbdiv, refdiv, PERIPHERAL_CLK,main_clk_temp;
Uart_Config_Type Uart_Config_Value;
Uart_Config_Value.BaudRate = BaudRate;
Uart_Config_Value.isEnableReceived = true;
Uart_Config_Value.isIntelligenceMode = flase;
Uart_Config_Value.isLoop = flase;
Uart_Config_Value.isRamMode = flase;
if(parity == 2)
{
Uart_Config_Value.parity = even_parity;
}
else if(parity == 3)
{
Uart_Config_Value.parity = odd_parity;
}
else
{
Uart_Config_Value.parity = none_parity;
}
Uart_Config_Value.stop = one_stop;
rel = FIND_UART(Numb,&Uart);
if(rel == 0)
{
//1,选择UART时钟源
BASE_AHB->PeriphConfig.bit.UARTCLKSEL = 0x1;
//2,配置UART时钟使能
BASE_AHB->PeriphClken.bit.UART = 0xfff;
//3,配置管脚复用
UART_IOMUX->bit.UART01 = 0X0;
UART_IOMUX->bit.UART23 = 0X0;
UART_IOMUX->bit.UART45 = 0X0;
UART_IOMUX->bit.UART67 = 0X0;
//4,复位uart
Uart->CMD = 0xff;
delay(0x100);
//5,配置波特率
//解析PLL主时钟寄存器数值
bypass = BASE_AHB->PllMain.bit.BYPASS;
fbdiv = BASE_AHB->PllMain.bit.FBDIV;
refdiv = BASE_AHB->PllMain.bit.REFDIV;
if(bypass == 1)
{
PERIPHERAL_CLK = 50000000;
Uart->BRSR = (PERIPHERAL_CLK/(16*(Uart_Config_Value.BaudRate))) & 0xff;
}
else
{
main_clk_temp = (fbdiv/refdiv) *(50000000/2); //计算系统主时钟
PERIPHERAL_CLK = main_clk_temp/2; //AHB挂载的外设时钟为系统主时钟的一半
Uart->BRSR = (PERIPHERAL_CLK/(16*(Uart_Config_Value.BaudRate))) & 0xff; // BRSR<=0xff
}
//6,配置非智能模式,1个停止位,偶校验,FIFO模式,正常模式,使能接收
Uart->UCR.bit0.MODE = Uart_Config_Value.isIntelligenceMode;
Uart->UCR.bit0.STOPBITS = Uart_Config_Value.stop;
Uart->UCR.bit0.PAR = Uart_Config_Value.parity;
Uart->UCR.bit0.FIFO = Uart_Config_Value.isRamMode;
Uart->UCR.bit0.LOOP = Uart_Config_Value.isLoop;
Uart->UCR.bit0.RXEN = Uart_Config_Value.isEnableReceived;
//7,配置FIFO阈值
Uart->ITL = 200;
}
else
{
return;
}
}
void UART_INT_Enable(Uint8 Numb, Uint32 type)
{
REG_UART_TYPE* Uart;
Uint32 rel = 0;
rel = FIND_UART(Numb,&Uart);
if(rel == 0)
{
Uart->IER.all = type;
}
else
{
return;
}
}
Uint8 UART_Get_IntStatus(Uint8 Numb)
{
REG_UART_TYPE* Uart;
Uint32 rel = 0;
Uint8 status = 0;
rel = FIND_UART(Numb,&Uart);
if(rel == 0)
{
status = Uart->IFR.bit.RECVC;
}
else
{
return -1;
}
return status;
}