Menu Close

RISC-V UART中断设计与应用(3)软件工程主函数

1. fii_uart1.c

 

相关参考文章:

RISC-V教学教案

 

fii_uart1.c主要用来实现fii_uart1.h中的声明UART1_IRQ_register函数

 

#include <stdio.h>

#include <stdint.h>

#include "fii_uart1.h" 

#include "platform.h"



//函数的参数列表中有波特率,奇偶校检,中断类型,停止位个数,接收水印阈值,发送水印阈值和中断使能

void UART1_IRQ_register( u32_t uart1_baud_rate, u32_t uart1_parity, u32_t irq_mask,

E_UART1_NSTOP nstop, E_RXCTRL rxwm, E_TXCTRL txwm, E_UART1_IRQ_SW uart1_sw)

{

//设置波特率

UART1_REG(UART1_DIV) = uart1_baud_rate;

//设置奇偶校检位

UART1_REG(UART1_LCR) = uart1_parity;


//设置停止位

if(nstop == UART1_NSTOP_1)

UART1_REG(UART1_TX_CTRL) &= ~(1UL << 1);                  //nstop位为0 ====> 1位停止位

else

UART1_REG(UART1_TX_CTRL) |= (1UL << 1);                   //nstop位为1 ====>2位停止位


//设置水印阈值

//设置前先清除之前的水印阈值

UART1_REG(UART1_TX_CTRL) &= ~(7UL << 16);                //清除bit 16-18, 7UL -->3'b111

UART1_REG(UART1_RX_CTRL) &= ~(7UL << 16);


UART1_REG(UART1_TX_CTRL) |= (txwm.txctrl_reg);            //发送水印位


UART1_REG(UART1_RX_CTRL) |= (rxwm.rxctrl_reg);            //接收水印位


//中断使能

if(uart1_sw == UART1_IRQ_DIS)        //中断禁止

UART1_REG(UART1_IE) &= ~(1UL << irq_mask);

else                                //启用中断

UART1_REG(UART1_IE) |= (1UL << irq_mask);


return;

}

 

2.main.c

这里对主函数的设计为: 设置好水印阈值中断后,每进入rx中断,会将接收到的数据(实验中由串口调试工具SSCOM连接串口发送数据)全写入heap中,并打开tx中断。进入tx中断后会将heap中rx写入的数据全读出来,发送出去,并打开rx中断。heap的空间用malloc()函数来分配,并且运用了三个指针,一起组合用于heap中数据的读写。

此外在之前介绍过的PLIC软件搭建,以及外部中断源中的GPIO和PWM软件工程的基础上,这里将会只说明主函数中和之前相比新添加的部分。之前的PLIC软件工程详情见RISC-V教学教案(点击这里)中的18-21节,如图1所示。

 

PLIC相关文章

图1 RISC-V教学教案中PLIC相关的文章

 

#include <stdio.h>

#include <stdlib.h>               //malloc是标准函数库中的子函数

#include "umm_heap.h"             //用于malloc函数

#include "fii_types.h"

#include "platform.h"

#include "plic_driver.h"



#define  NOP_DELAY  0x400000

#define  MEM_SIZE 0x120

#define  FIFO_SIZE 0x100


//声明global变量,用于水印阈值的配置

E_RXCTRL rxwm;

E_TXCTRL txwm;



//声明使用外部的函数

extern void trap_entry();


//声明3个全局的字符指针,用于heap的读写

unsigned char *glb_p;             //rx使用

unsigned char *glb_k;             //tx使用

unsigned char *glb_end;           //内存的末尾



//rx接收数据,写入内存

void memory_input (void)

{

unsigned int temp;             //用于读出rx数据和fifo空

if(glb_p == NULL)             //如果内存分配为0

{

printf("\r\n No valid memry \r\n");

return;

}

else if(glb_p == glb_end)           //如果rx指针已经到了内存分配的末尾

printf("\r\n Momery is full!!!\r\n");

else

{

temp = UART1_REG(UART1_RX_DATA);           //读出rx数据和fifo空

while(temp != UART1_RX_FIFO_EMPTY)         //如果fifo不为空,即rx数据有效

{


*glb_p = temp;                            //写入内存

glb_p++;                                  //指针移动到下一个没有写入的内存区域

temp = UART1_REG(UART1_RX_DATA);          //读出下一次的rx数据和fifo空,用于下一次循环的判断

}

//将tx中断打开

UART1_IRQ_register( BAUD_RATE_115200, ODD_PARITY, UART1_TXWM_MASK,

UART1_NSTOP_1, rxwm, txwm, UART1_IRQ_EN);

}

return;

}




//tx读出内存数据,并发送出去

void memory_output (void)

{

unsigned char temp;


if(glb_k == NULL)      //如果内存分配为0

{

printf("\r\n No valid memry \r\n");

return;

}

else if(glb_k >= glb_p)          //如果rx指针已经到了tx指针的地点,即内存中的数据已经读完

printf("\r\n Momery is empty!!!\r\n");

else

{

while(glb_k < glb_p)                      //当还有数据可读时

{

temp = *glb_k;                            //读出当前指针的数据

UART1_REG(UART1_TX_DATA) = temp ;         //写入TXDATA寄存器

glb_k++;                                  //移动指针到下一个未读数据的内存区域

}

//打开rx的中断

UART1_IRQ_register( BAUD_RATE_115200, ODD_PARITY, UART1_RXWM_MASK,

UART1_NSTOP_1, rxwm, txwm, UART1_IRQ_EN);

}

return;

}



//UART1中断处理函数

void uart1_handler(void) {

//判断UART1中断的原因:校检错误/tx水印/rx水印

unsigned int irq_case;

irq_case = UART1_REG(UART1_IP);

switch(irq_case)   //判断中断原因

{


case 0x2:                //rx水印

printf("\r\n UART1 receive watermark interrupt\r\n");

//清除UART1中断

UART1_REG(UART1_IC) |= 1 << UART1_RXWM_MASK;

//禁用rxwm中断

UART1_REG(UART1_IE) &= ~(1UL << UART1_RXWM_MASK);

memory_input();     //进入内存写入函数

break;


case 0x1:               //tx水印

printf("\r\n UART1 transmit watermark interrupt\r\n");

//清除UART1中断

UART1_REG(UART1_IC) |= 1 << UART1_TXWM_MASK;

//禁用txwm中断

UART1_REG(UART1_IE) &= ~(1UL << UART1_TXWM_MASK);

memory_output();       //进入读出内存函数

break;


case 0x4:            //校检错误

printf("\r\n UART1 transmit parity error\r\n");

//清除UART1中断

UART1_REG(UART1_IC) |= 1 << UART1_PERROR_MASK;

//禁用校检错误中断

UART1_REG(UART1_IE) &= ~(1UL << UART1_PERROR_MASK);

break;


default:         //不是以上列出的中断

printf("\r\n No UART1 interrupt\r\n");

break;

}

return;

};


//初始化函数

void _init(void)

{

//启用TXCTRL和RXCTRL的txen和rxen位

UART1_REG(UART1_TX_CTRL) |= UART1_TXEN;

UART1_REG(UART1_RX_CTRL) |= UART1_RXEN;


// 禁用UART1中断

UART1_REG(UART1_IE) = 0;


write_csr(mtvec, &trap_entry);//全局中断入口 

    return;

}




//中断配置函数

void IRQ_register (){

// 直到设置完成,禁用机器和计时器中断。

clear_csr(mie, MIP_MEIP);  // 禁用外部中断

clear_csr(mie, MIP_MTIP);  // 禁用定时器中断


for (int ii = 0; ii < PLIC_NUM_INTERRUPTS; ii ++){

g_ext_interrupt_handlers[ii] = no_interrupt_handler;

}



//UART1中断处理

g_ext_interrupt_handlers[INT_UART1_BASE] = uart1_handler;


// 必须同时在UART1级别和PLIC级别启用中断

enable_plic_int(INT_UART1_BASE);


// 中断优先级必须设置在0以上,才能触发中断

PLIC_set_priority(&g_plic, INT_UART1_BASE, 3);


//--------------------------UART1级别设置中断------------------------------

txwm.bit.txwm_bit = 0x3;    //定义tx水印阈值

rxwm.bit.rxwm_bit = 0x7; //定义rx水印阈值


//将TX的波特率设置为115200,奇校检,一位停止位,水印阈值为3

UART1_IRQ_register( BAUD_RATE_115200, ODD_PARITY, UART1_TXWM_MASK,

UART1_NSTOP_1, rxwm, txwm, UART1_IRQ_EN);


//将RX的波特率设置为115200,奇校检,一位停止位,水印阈值为7

UART1_IRQ_register( BAUD_RATE_115200, ODD_PARITY, UART1_RXWM_MASK,

UART1_NSTOP_1, rxwm, txwm, UART1_IRQ_EN);


/----------------------------UART1级别设置中断结束--------------------------


//  启用MIE中的机器模式下的外部中断位

set_csr(mie, MIP_MEIP);



// 启用机器模式全局中断

set_csr(mstatus, MSTATUS_MIE);

}



//主函数

int main(void)

{

//初始化内存

mm_heap_initialize();


glb_p = malloc (MEM_SIZE);             //分配内存给global指针ptr, glb_p

glb_k = glb_p;                         //刚开始,两个指针指向一个内存地点

glb_end = glb_p + MEM_SIZE;            //将glb_end指针指向内存末尾



//调用初始化函数

_init();

printf("\r\nRun Segment Timer IRQ Program \r\n");


//调用中断配置函数

IRQ_register();


while ( 1 )

{

    asm("nop");

}

}
Posted in C语言, RISC-V, RISC-V 外设, RISC-V 教案, 应用开发, 教材与教案, 文章, 编程语言

发表评论

相关链接