#include <uart0.h>
#include <s3c2440.h>
#include <irq.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
/*
* ULCON0
* UCON0
* UFCON0
*/
#define RB_NEXT(id) (id == (RB_SIZE - 1) ? 0 : (id + 1))
RB_OBJ rb_sendbuff;
RB_OBJ rb_recbbuff;
//缓冲区初始化
void rb_init()
{
rb_sendbuff.bufMax = RB_SIZE;
rb_sendbuff.w_id = 0;
rb_sendbuff.r_id = 0;
rb_recbbuff.bufMax = RB_SIZE;
rb_recbbuff.w_id = 0;
rb_recbbuff.r_id = 0;
}
//读取共享FIFO中未发送的数据个数
int rb_datasize(struct RB_OBJ_T *obj)
{
if(obj->w_id == obj->r_id)//是否相等
{
return 0;
}
if(obj->w_id > obj->r_id)//wid是否在rid前边
{
return (obj->w_id - obj->r_id);
}
return (obj->bufMax - obj->r_id + obj->w_id);//wid是否转了一圈回来后在rid后边
}
/*************************不带FIFO模式**********************************/
void init_nofifo_uart0(void)
{
//普通模式,无奇偶校验,一个停止位,8个数据位
ULCON0 = 0x03;
//指定发送器的引脚为TXD0
GPHCON &= ~(0x3 << 4);
GPHCON |= 2 << 4;
GPHUP &= ~(1 << 2); //使能上拉功能,作用:防止信号受干扰
//指定接收器的引脚为RXD0
GPHCON &= ~(0x3 << 6);
GPHCON |= 2 << 6;
GPHUP &= ~(1 << 3);
//配置波特率选择时钟
UCON0 = 0x5; // 波特率为115200bit/s
UBRDIV0 = (int)(68*1000*1000)/(115200*16)-1;
//指定非FIFO模式
UFCON0 = 0x0; //关闭FIFO模式
}
void send_nofifo_uart0(char data)
{
UTXH0 = data; //UTXH0用在没有FIFO下
}
char recv_nofifo_uart0(void)
{
while(!(UTRSTAT0 & (1 << 0)))
{
continue;
}
//判断下有没有数据进来
return (char)URXH0;
}
/***************** FIFO模式***********************/
void init_uart0(void)
{
//指定发送器的引脚为TXD0
GPHCON &= ~(0x3 << 4);
GPHCON |= 2 << 4;
GPHUP &= ~(1 << 2); //使能上拉功能,作用:稳定信号电压
//指定接收器的引脚为RXD0
GPHCON &= ~(0x3 << 6);
GPHCON |= 2 << 6;
GPHUP &= ~(1 << 3);
//数据帧格式ULCON0
ULCON0 &= ~(0x1 << 6);//正常模式
ULCON0 &= ~(0x7 << 3);//无校验
ULCON0 &= ~(1 << 2);//一个停止位
ULCON0 &= ~(0x3 << 0); //8个数据位
ULCON0 |= 0x3 << 0;
//波特率:115200bps
UBRDIV0 = (int)(68*1000*1000)/(115200*16) - 1;
//配置UART0的控制器 UCON0
UCON0 &= ~(0x3 << 10); //PCLK时钟
UCON0 |= 0x2 << 10;
UCON0 &= ~(0x1 << 9); //发送脉冲
UCON0 &= ~(0x1 << 8); //接收脉冲
UCON0 |= (0x1 << 7); //超时打开
UCON0 &= ~(0x1 << 6); //不使用错误检测
UCON0 &= ~(0x1 << 5); //正常模式(不使用换回模式)
UCON0 &= ~(0x1 << 4); //不使用断点
UCON0 &= ~(0x3 << 2); //指定发送模式
UCON0 |= 0x1 << 2;
UCON0 &= ~(0x3 << 0); //指定接收模式
UCON0 |= 0x1 << 0;
//配置数据缓冲区 UFCON0
UFCON0 &= ~(0x3 << 6);
UFCON0 |= 0x1 << 6; //指定发送缓冲区的深度16
UFCON0 &= ~(0x3 << 4);
UFCON0 |= 0x3 << 4; //指定接收缓冲区的深度32
UFCON0 &= ~(0x1 << 2); //发送FIFO自动清除
UFCON0 &= ~(0x1 << 1); //接收FIFO自动清除
UFCON0 |= 0x1 << 0; //使用FIFO
//流控:禁用
UMCON1 = 0;
//安装中断
irq_Install(IRQ_SUB_TXD0, irq_isr_send);
irq_Install(IRQ_SUB_RXD0, irq_isr_recv);
irq_Install(IRQ_SUB_ERR0, irq_isr_recv);
rb_init();
}
//将共享FIFO中的数据往FIFO中写入
void irq_isr_send (void)
{
//拷贝数据到FIFO当中,FIFO寄存器
//FIFO缓冲区是否满
while (!(UFSTAT0 & (0x1 << 14)))
{
if (rb_sendbuff.r_id == rb_sendbuff.w_id) //说明无数据再发送
{
break;
}
else
{
if ((UTRSTAT0 & 4) != 0 )
{
UTXH0 = rb_sendbuff.buff[rb_sendbuff.r_id];
rb_sendbuff.r_id = RB_NEXT(rb_sendbuff.r_id);
}
}
}
}
//将用户需要发送的数据往共享FIFO中写入
int UART0_SendBuff(char *data, int len)
{
if (RB_SIZE - rb_datasize(&rb_sendbuff) <= len) //说明共享FIFO中无足够大的空间容下len长度的数据
{
return 0;
}
if (RB_SIZE - rb_sendbuff.w_id >= len) //判断当前位置到末尾能否容下len长度的数据
{
memcpy(&rb_sendbuff.buff[rb_sendbuff.w_id], data, len);
rb_sendbuff.w_id += len;
if (rb_sendbuff.w_id == RB_SIZE)
{
rb_sendbuff.w_id = 0;
}
}
else
{
memcpy(&rb_sendbuff.buff[rb_sendbuff.w_id], data, RB_SIZE - rb_sendbuff.w_id);
memcpy(&rb_sendbuff.buff[0], data + RB_SIZE - rb_sendbuff.w_id, len - RB_SIZE - rb_sendbuff.w_id);
rb_sendbuff.w_id = len - RB_SIZE - rb_sendbuff.w_id;
}
irq_isr_send();
return 1;
}
//将数据从FIFO中取出到共享FIFO中
void irq_isr_recv(void)
{
int icount = 0;
char ch;
icount = UFSTAT0 & 0x3f;
while (icount != 0)
{
if (rb_recbbuff.r_id - rb_recbbuff.w_id == 1) //说明共享FIFO满了
{
break;
}
ch = (char)URXH0;
rb_recbbuff.buff[rb_recbbuff.w_id] = ch;
rb_recbbuff.w_id = RB_NEXT(rb_recbbuff.w_id);
icount--;
}
}
int UART0_RecvBuff(char *data, int len)
{
if (len <= 0)
{
return 0;
}
if (rb_datasize(&rb_recbbuff) >= len)
{
if(rb_recbbuff.r_id < rb_recbbuff.w_id)
{
memcpy(data, &rb_recbbuff.buff[rb_recbbuff.r_id], len);
rb_recbbuff.r_id += len;
if (rb_recbbuff.r_id == RB_SIZE)
{
rb_recbbuff.r_id = 0;
}
}
else
{
memcpy(data, &rb_recbbuff.buff[rb_recbbuff.r_id], RB_SIZE - rb_recbbuff.r_id);
memcpy(data + RB_SIZE - rb_recbbuff.r_id, &rb_recbbuff.buff[0], len - RB_SIZE - rb_recbbuff.r_id);
rb_recbbuff.r_id = len - RB_SIZE - rb_recbbuff.r_id;
}
}
else
{
return 0;
}
return len;
}
int uart_print(char *fmt, ...)
{
va_list ap;
char tmpstr[256];
int n;
va_start(ap, fmt);
n = _vsnprintf(tmpstr, 255, fmt, ap);
va_end(ap);
if (n <= -1 || n >= 255)
{
return -1;
}
tmpstr[255] = '\0';
UART0_SendBuff(tmpstr, n);
return n;
}