1. fii_uart1.c
Related reference articles:
RISC-V teaching plan
fii_uart1.c is mainly used to implement the declared UART1_IRQ_register function in fii_uart1.h
#include <stdio.h> #include <stdint.h> #include "fii_uart1.h" #include "platform.h" /* The parameter list of the function includes baud rate, parity check, interrupt type, number of stop bits, receive watermark threshold, transmit watermark threshold and interrupt enable */ 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) { //set baud rate UART1_REG(UART1_DIV) = uart1_baud_rate; //Set the parity bit UART1_REG(UART1_LCR) = uart1_parity; //set stop bit if(nstop == UART1_NSTOP_1) UART1_REG(UART1_TX_CTRL) &= ~(1UL << 1); //nstop bit is 0 ====> 1 bit stop bit else UART1_REG(UART1_TX_CTRL) |= (1UL << 1); //nstop bit is 1 ====> 2 bit stop bits //Set the watermark threshold //Clear the previous watermark threshold before setting UART1_REG(UART1_TX_CTRL) &= ~(7UL << 16); // clear bits 16-18, 7UL --> 3'b111 UART1_REG(UART1_RX_CTRL) &= ~(7UL << 16); UART1_REG(UART1_TX_CTRL) |= (txwm.txctrl_reg); // send watermark bit UART1_REG(UART1_RX_CTRL) |= (rxwm.rxctrl_reg); //Receive watermark bit //interrupt enable if(uart1_sw == UART1_IRQ_DIS) //interrupt disable UART1_REG(UART1_IE) &= ~(1UL << irq_mask); else //enable interrupt UART1_REG(UART1_IE) |= (1UL << irq_mask); return; }
2.main.c
The design of the main function here is: after setting the watermark threshold interrupt, every time the rx interrupt is entered, the received data (the data sent by the serial port debugging tool SSCOM connected to the serial port in the experiment) will be written into the heap, and the tx interrupt will be turned on. After entering the tx interrupt, the data written by rx in the heap will be read out, sent out, and the rx interrupt will be turned on. The heap space is allocated with the malloc() function, and three pointers are used, which are combined together for reading and writing data in the heap.
In addition, based on the PLIC software construction introduced before, and the GPIO and PWM software engineering in the external interrupt source, only the newly added parts in the main function will be described here. The previous PLIC software engineering details are shown in Sections 18-21 in the RISC-V teaching plan (click here ), as shown in Figure 1.
Figure 1 PLIC-related articles in the RISC-V teaching plan
#include <stdio.h> #include <stdlib.h> //malloc is a subfunction in the standard function library #include "umm_heap.h" //For malloc function #include "fii_types.h" #include "platform.h" #include "plic_driver.h" #define NOP_DELAY 0x400000 #define MEM_SIZE 0x120 #define FIFO_SIZE 0x100 //Declare global variables for configuration of watermark thresholds E_RXCTRL rxwm; E_TXCTRL txwm; //declare the external function extern void trap_entry(); //Declare 3 global character pointers for heap reading and writing unsigned char *glb_p; //rx use unsigned char *glb_k; //tx use unsigned char *glb_end; //end of memory //rx receives data and writes to memory void memory_input (void) { unsigned int temp; // used to read rx data and fifo empty if(glb_p == NULL) // if the memory allocation is 0 { printf("\r\n No valid memry \r\n"); return; } else if(glb_p == glb_end) // if the rx pointer has reached the end of the memory allocation printf("\r\n Momery is full!!!\r\n"); else { temp = UART1_REG(UART1_RX_DATA); //Read rx data and fifo empty while(temp != UART1_RX_FIFO_EMPTY) //If fifo is not empty, rx data is valid { *glb_p = temp; //write to memory glb_p++; //The pointer moves to the next unwritten memory area temp = UART1_REG(UART1_RX_DATA); //Read out the next rx data and fifo empty for the judgment of the next loop } //Turn on tx interrupt UART1_IRQ_register( BAUD_RATE_115200, ODD_PARITY, UART1_TXWM_MASK, UART1_NSTOP_1, rxwm, txwm, UART1_IRQ_EN); } return; } //tx reads the memory data and sends it out void memory_output (void) { unsigned char temp; if(glb_k == NULL) //if the memory allocation is 0 { printf("\r\n No valid memry \r\n"); return; } else if(glb_k >= glb_p) //If the rx pointer has reached the location of the tx pointer, that is, the data in the memory has been read printf("\r\n Momery is empty!!!\r\n"); else { while(glb_k < glb_p) //when there is still data to read { temp = *glb_k; //Read the data of the current pointer UART1_REG(UART1_TX_DATA) = temp ; //Write to TXDATA register glb_k++; //move pointer to next unread data memory area } //Open the interrupt of rx UART1_IRQ_register( BAUD_RATE_115200, ODD_PARITY, UART1_RXWM_MASK, UART1_NSTOP_1, rxwm, txwm, UART1_IRQ_EN); } return; } //UART1 interrupt handler void uart1_handler(void) { //Determine the reason for the UART1 interrupt: check error/tx watermark/rx watermark unsigned int irq_case; irq_case = UART1_REG(UART1_IP); switch(irq_case) // Determine the reason for the interruption { case 0x2: //rx watermark printf("\r\n UART1 receive watermark interrupt\r\n"); //Clear UART1 interrupt UART1_REG(UART1_IC) |= 1 << UART1_RXWM_MASK; // disable rxwm interrupt UART1_REG(UART1_IE) &= ~(1UL << UART1_RXWM_MASK); memory_input(); //Enter the memory write function break; case 0x1: //tx watermark printf("\r\n UART1 transmit watermark interrupt\r\n"); //Clear UART1 interrupt UART1_REG(UART1_IC) |= 1 << UART1_TXWM_MASK; // disable txwm interrupt UART1_REG(UART1_IE) &= ~(1UL << UART1_TXWM_MASK); memory_output(); //Enter the read memory function break; case 0x4: //check error printf("\r\n UART1 transmit parity error\r\n"); //Clear UART1 interrupt UART1_REG(UART1_IC) |= 1 << UART1_PERROR_MASK; // disable check error interrupt UART1_REG(UART1_IE) &= ~(1UL << UART1_PERROR_MASK); break; default: // not the interrupts listed above printf("\r\n No UART1 interrupt\r\n"); break; } return; }; //initialization function void _init(void) { //Enable the txen and rxen bits of TXCTRL and RXCTRL UART1_REG(UART1_TX_CTRL) |= UART1_TXEN; UART1_REG(UART1_RX_CTRL) |= UART1_RXEN; // disable UART1 interrupt UART1_REG(UART1_IE) = 0; write_csr(mtvec, &trap_entry);//Global interrupt entry return; } //interrupt configuration function void IRQ_register (){ // Until setup is complete, disable machine and timer interrupts. clear_csr(mie, MIP_MEIP); // disable external interrupt clear_csr(mie, MIP_MTIP); // disable timer interrupt for (int ii = 0; ii < PLIC_NUM_INTERRUPTS; ii ++){ g_ext_interrupt_handlers[ii] = no_interrupt_handler; } //UART1 interrupt handling g_ext_interrupt_handlers[INT_UART1_BASE] = uart1_handler; // Interrupts must be enabled at both the UART1 level and the PLIC level enable_plic_int(INT_UART1_BASE); // The interrupt priority must be set above 0 to trigger an interrupt PLIC_set_priority(&g_plic, INT_UART1_BASE, 3); //--------------------------UART1 level set interrupt------------------------------ txwm.bit.txwm_bit = 0x3; // Define tx watermark threshold rxwm.bit.rxwm_bit = 0x7; // define the rx watermark threshold //Set the baud rate of TX to 115200, odd check, one stop bit, and the watermark threshold is 3 UART1_IRQ_register( BAUD_RATE_115200, ODD_PARITY, UART1_TXWM_MASK, UART1_NSTOP_1, rxwm, txwm, UART1_IRQ_EN); //Set the baud rate of RX to 115200, odd check, one stop bit, and the watermark threshold is 7 UART1_IRQ_register( BAUD_RATE_115200, ODD_PARITY, UART1_RXWM_MASK, UART1_NSTOP_1, rxwm, txwm, UART1_IRQ_EN); //----------------------------UART1 level set interrupt end-------------------------- // Enable external interrupt bit in machine mode in MIE set_csr(mie, MIP_MEIP); // Enable machine mode global interrupts set_csr(mstatus, MSTATUS_MIE); } // main function int main(void) { //initialize memory mm_heap_initialize(); glb_p = malloc (MEM_SIZE); // allocate memory to the global pointer ptr, glb_p glb_k = glb_p; // At the beginning, two pointers point to a memory location glb_end = glb_p + MEM_SIZE; // point the glb_end pointer to the end of memory //call the initialization function _init(); printf("\r\nRun Segment Timer IRQ Program \r\n"); //Call the interrupt configuration function IRQ_register(); while ( 1 ) { asm("nop"); } }
Engineering code download: