您的位置:首页 > 运维架构 > Linux

tiny6410裸机实验第8章--------------中断(中断版UART)

2014-03-07 12:06 281 查看
【说明】

             我们在第4章已经介绍了UART的原理,但是当时我们在发送数据的时候是用查询方式的,也就是如果FIFO满了,我们就一直循环等待,这显然太浪费时间了。这一节我们就用中断的方式操作UART,我们只介绍发送,接收其实和发送擦不多的。

 

【原理】

             6410的UART有个中断模式,记得FIFO缓冲区吗?

             1)我们将设置UART控制器根据缓冲区的内容多少来发送中断,具体地,当发送FIFO中内容数目低于一个值,就会产生一个中断

             2)我们的putc 函数不是直接往缓冲区写数据,而是放在一个我们自己定义的内存缓冲区中,其实就是一个环形队列。

             3)当中断来的时候说明FIFO中的内容数目已经低于一个值,我们就在中断处理函数中将环形队列中的数据复制到FIFO中,到FIFO满为止

             4)复制好后CPU管自己工作,UART控制器就是一个一个发送数据,当FIFO又低于一个值时,又会产生中断,我们又回到第3步。

 

【环形缓冲区】

               


                


               


               


              


             


【初始化】

                    这个寄存器我们原来只设置为0X5,现在需要把第9位设置为1,使其可以触发中断

                  


                   


                       

                     下面这个寄存器我们现在需要把第6,7位设置成01.,其实设置成别的也可以,它表示当缓冲区里面数据数目少于多少的时候产生中断

                    


                    


                     

                      在初始化的时候我们得先关闭中断,因为我们的缓冲区中根本就没有数据,什么时候打开呢?在下面的发送函数中

                     


                     


 

【中断处理函数关键代码】

                    

void irq_init(void)
{
key_irq_init();
uart_irq_init();
}

void uart_irq(void)
{
/* 调用具体的中断处理函数 */
do_uart_irq();
/* 清中断 */
VIC1ADDRESS = 0;
}

void uart_irq_init(void)
{
VIC1INTENABLE |= (1<<5); /* bit5: int_uart0 */
VIC1VECTADDR5 = uart_irq;
}

void do_irq(void)
{
int i = 0;

void (*the_isr)(void);

if (VIC0IRQSTATUS)
{
the_isr = VIC0ADDRESS;

/* 2.1 分辨是哪个中断 */
/* 2.2 调用它的处理函数 */
/* 2.3 清中断 */

the_isr();

EINT0PEND   = 0x3f;  /* 清中断 */
VIC0ADDRESS = 0;
}
else if (VIC1IRQSTATUS)
{
the_isr = VIC1ADDRESS;

/* 2.1 分辨是哪个中断 */
/* 2.2 调用它的处理函数 */
/* 2.3 清中断 */

the_isr();
}
}


 

 

【UART中断代码】

                 其他内容直接看源代码的注释比较好

                

#define ULCON0     (*((volatile unsigned long *)0x7F005000))
#define UCON0      (*((volatile unsigned long *)0x7F005004))
#define UFCON0     (*((volatile unsigned long *)0x7F005008))
#define UMCON0     (*((volatile unsigned long *)0x7F00500C))
#define UTRSTAT0   (*((volatile unsigned long *)0x7F005010))
#define UFSTAT0    (*((volatile unsigned long *)0x7F005018))
#define UTXH0      (*((volatile unsigned char *)0x7F005020))
#define URXH0      (*((volatile unsigned char *)0x7F005024))
#define UBRDIV0    (*((volatile unsigned short *)0x7F005028))
#define UDIVSLOT0  (*((volatile unsigned short *)0x7F00502C))
#define UINTP0      (*((volatile unsigned long *)0x7F005030))

#define UINTM0    (*((volatile unsigned long *)0x7F005038))

#define GPACON     (*((volatile unsigned long *)0x7F008000))

#define ENABLE_FIFO 1

static void delay(void)
{
volatile int i = 10;
while (i--);
}

void uart_tx_int_enable(void)
{
UINTM0 &= ~(1<<2);
}

void uart_tx_int_disable(void)
{
UINTM0 |= (1<<2);
}

void init_uart(void)
{
GPACON &= ~0xff;
GPACON |= 0x22;

/* ULCON0 */
ULCON0 = 0x3;  /* 数据位:8, 无较验, 停止位: 1, 8n1 */
UCON0  = 0x5 | (1<<9);  /* 使能UART发送、接收, tx interrupt request type = level */
#ifdef ENABLE_FIFO
UFCON0 = 0x07 | (1<<6); /* FIFO enable, tx fifo trigger level = 16 bytes */
#else
UFCON0 = 0x00; /* FIFO disable */
#endif
UMCON0 = 0;

/* 波特率 */
/* DIV_VAL = (PCLK / (bps x 16 ) ) - 1
* bps = 57600
* DIV_VAL = (66500000 / (115200 x 16 ) ) - 1
*         = 35.08
*/
UBRDIV0   = 35;

/* x/16 = 0.08
* x = 1
*/
UDIVSLOT0 = 0x1;
UINTM0 = 0xF;
}

unsigned char getc(void)
{
#ifdef ENABLE_FIFO
while ((UFSTAT0 & (1<<6)) == 0 && (UFSTAT0 & 0x3f) == 0)delay();
#else
while ((UTRSTAT0 & (1<<0)) == 0);
#endif

return URXH0;
}

int getc_nowait(unsigned char *pChar)
{
#ifdef ENABLE_FIFO
if ((UFSTAT0 & (1<<6)) == 0 && (UFSTAT0 & 0x3f) == 0)
#else
if ((UTRSTAT0 & (1<<0)) == 0)
#endif
{
return -1;
}
else
{
*pChar = URXH0;
return 0;
}
}

#define TX_BUF_LEN   2048
static unsigned char txbuf[2047];
static unsigned int r_idx = 0;
static unsigned int w_idx = 0;

static int isFull(void)
{
if ((w_idx + 1) % TX_BUF_LEN == r_idx)
return 1;
else
return 0;
}

static int isEmpty(void)
{
return (w_idx == r_idx);
}

static int putData(unsigned char data)
{
if (isFull())
return -1;
else
{
txbuf[w_idx] = data;
w_idx = (w_idx + 1) % TX_BUF_LEN;
return 0;
}
}

static int getData(unsigned char *pdata)
{
if (isEmpty())
{
return -1;
}
else
{
*pdata = txbuf[r_idx];
r_idx = (r_idx + 1) % TX_BUF_LEN;
return 0;
}
}

void putc(char c)
{
putData(c);    /* 把数据放到缓冲区里去 */

/* 如果"uart 发送中断"未使能的话,使能"uart 发送中断" */
uart_tx_int_enable();
}

void do_uart_irq(void)
{
int i;
int cnt;
unsigned char c;

if (UINTP0 & (1<<2))
{
/* 对于发送中断 */
if (isEmpty())
{
/* 禁止中断 */
uart_tx_int_disable();
}
else
{
/* 从环型缓冲区里取出数据, 放到TX FIFO里去 */
cnt = (UFSTAT0 >> 8) & 0x3f;
cnt = 64 - cnt;
for (i = 0; i < cnt; i++)
{
if (getData(&c) == 0)
{
UTXH0 = c;
}
else
{
break;
}
}
}
}

else if (UINTP0 & (1<<0))
{
/* 对于接收中断, 从RX FIFO里取出数据 */
}

/* 清中断 */
UINTP0 = 0xf;
}


 

                 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux 嵌入式