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; }
这里对主函数的设计为: 设置好水印阈值中断后,每进入rx中断,会将接收到的数据(实验中由串口调试工具SSCOM连接串口发送数据)全写入heap中,并打开tx中断。进入tx中断后会将heap中rx写入的数据全读出来,发送出去,并打开rx中断。heap的空间用malloc()函数来分配,并且运用了三个指针,一起组合用于heap中数据的读写。
此外在之前介绍过的PLIC软件搭建,以及外部中断源中的GPIO和PWM软件工程的基础上,这里将会只说明主函数中和之前相比新添加的部分。之前的PLIC软件工程详情见RISC-V教学教案(点击这里)中的18-21节,如图1所示。
图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"); } }
声明:文章来源于IC知识库,本文内容及配图的版权归版权所有人所有,内容仅代表作者个人观点,不代表本网站观点或证实其内容的真实性。对于本网刊载的各类评论非本网评论员评论,仅代表评论者个人观点,并不代表本网证实或赞成其描述。如其他媒体、网站或个人转载使用,需保留本网注明的“稿件来源”,并自负法律责任。本文转载仅为更好的传播行业信息,若有内容图片侵权或者其他问题,请及时通过邮件联系我们,以便做侵删处理。