1.Schematics Analysis
Direct to Table of Contents:
RISC-V Syllabus
Segment display will be used in the following projects, so an analysis of schematics is helpful to understand the variable assignments when writing the C programs.
Segment display have two types of FPGA wiring, location selection and segment selection. Since location selection is connected to P-channel field-effect transistor (FET), the gate must be more negative than the source for a typically 0.78V , so that VCC can flow through the segment display. Thus to lit the segment display, location selection must be in low voltage. Similarly, if the segment selection is also in low voltage (assume the corresponding location selection is in low voltage, so that the VCC could flow through the segment display), so there is a voltage difference between segment selection and VCC, VCC could flow from the right side of the segment display to the left side. On the opposite, if segment selection is in high voltage, there is no voltage difference between the left and right side of the segment display, and thus the segment display will be off.
Figure 1 Segment display wiring of schematics
2.Address Map
Here is a screenshot of the address allocation, which is helpful when writing the C project, as shown in Figure 2.
Address range Detail Description Read/Write Size
Figure 2 Address allocation
3.RISCV_seg_cnt Project
As shown in Figure 3, firstly, select the tab of the Freedom Studio under File > Import, the import window will pop up. Under the General tab, choose Existing Projects into Workspace, and click Next. In Figure 4, browse for the designed projects, click Copy projects into workspace box, and click Finish. Then RISCV_seg_cnt project will appear under Project Explorer tab as shown in Figure 5.
Figure 3 Import window (1)
Figure 4 Import window (2)
Figure 5 RISCV_seg_cnt in Project Explorer
After adding the project into the workspace, right click the project folder under Project Explorer, click Clean Project (do it every time before actually building the projects). Then click Build Project. After the console displays “ Build Finished”, click Refresh to refresh the project as shown in Figure 6 and Figure 7. Then to start debugging, right click the project, and select Debug As > Debug Configurations.
Figure 6 Clean, build and refresh the project
Figure 7 Debug
Figure 8 Debug Configurations
In the pop up windows as shown in Figure 8, set up the debug configuration as stated in C programming 1. Under GDB OpenOCD Debugging, add a new launch configuration by clicking the icon on the top left corner. Usually after building projects, with refresh, the C/C++ Application row will fill up the corresponding *.elf file automatically. If not, click Search Project under the blank, to search for the *.elf file. Or else, use Browse button to find the *.elf file under debug folder (this will be an absolute path). After all done of those, click Debug to load the program. Assuming the RISCV FII-PRX100-S XILINX FPGA Board is programmed with FII-RISCV3.01, the experiment phenomena can be observed that the segment display will continue counting.
Next, the detailed explanation of the software code to lit the segment display will be commented in each code block. They are as follows:
- Platform.h
#ifndef __PLATFORM_H #define __PLATFORM_H #ifdef __cplusplus extern "C" { #endif #include "fii_types.h" //data type definition #include "fii_gpio.h" //gpio definition #include "fii_uart.h" //uart definition #include "fii_irq.h" //interrupt definition #include "encoding.h" //parameter definition #define RAM_ADDR 0x90000000 //define DTCM address //define a convenient way to access the address #define GPIO_REG(offset) (*(volatile unsigned int *)(GPIO_ADDR + offset)) #define RAM_REG(offset) (*(volatile unsigned int *)(RAM_ADDR + offset)) #define UART_REG(offset) (*(volatile unsigned int *)(UART_BASE + offset)) #define TIME_REG(offset) (*(volatile unsigned int *)(TIME_ADDR + offset)) #ifdef __cplusplus } #endif #endif // __PLATFORM_H
- Fii_types.h
/* C type | Bytes in RV32 | Bytes in RV64 char | 1 | 1 short | 2 | 2 int | 4 | 4 long | 4 | 8 long long | 8 | 8 void* | 4 | 8 float | 4 | 4 double | 8 | 8 long double | 16 | 16 */ //declare FII data types, aim to eliminate the conflict when cooperating with others #ifndef __FII_TYPES_H #define __FII_TYPES_H #ifdef __cplusplus extern "C" { #endif #define RV_TYPE RV32 //define FII-RISCV CPU to be 32 bits typedef unsigned int uintptr_t; typedef unsigned long long u64_t; typedef unsigned int u32_t; typedef unsigned short u16_t; typedef unsigned char u8_t; typedef long long s64_t; typedef int s32_t; typedef short s16_t; typedef char s8_t; #if 0 #if (RV_TYPE == RV32) typedef unsigned long u32_t; typedef long s32_t; #elif (RV_TYPE == RV64) typedef unsigned long u64_t; typedef long s64_t; #endif #endif #ifdef __cplusplus } #endif #endif // __FII_TYPES_H
- Fii_gpio.h
#ifndef __FII_GPIO_H #define __FII_GPIO_H #ifdef __cplusplus extern "C" { #endif //declare the segment display fonts //the actual value is related to FII-RISCV gpio definition //EXAMPLE: 8-seg display //SEG_C:0X39 //DP G F E D C B A //0 0 1 1 1 0 0 1 #define SEG_S 0x6D #define SEG_A 0x77 #define SEG_B 0x7C #define SEG_C 0x39 #define SEG_D 0x5E #define SEG_E 0x79 #define SEG_F 0x71 #define SEG_0 0x3F #define SEG_1 0x06 #define SEG_2 0x5B #define SEG_3 0x4F #define SEG_4 0x66 #define SEG_5 0x6D #define SEG_6 0x7D #define SEG_7 0x07 #define SEG_8 0x7F #define SEG_9 0x67 #define SEG_j 0x40 #define SEG_p 0x80 #define SEG__ 0x00 #define BYTE_DELAY 0x00200000 // macro definition #define GPIO_ADDR 0xf0000000 //define GPIO base address //define offset address related to the GPIO base address #define LED_VAL 0x00 //LED value #define LED_DIR 0x04 //LED direction (I/O) #define SEAT_VAL 0x08 //segment location (one of six segment display) #define SEAT_DIR 0x0C //segment location direction (I/O) #define SEG_VAL 0x10 //segment selection (A,B,C,D,E,F,G,DP) #define SEG_DIR 0x14 //segment selection direction (I/O) #define BUT_VAL 0x18 //button value #define BUT_DIR 0x1C //button direction (I/O) //=============================================== //=============================================== #define SEG_POS 0x07 #ifdef __cplusplus } #endif #endif /* end __FII_GPIO_H */
- Fii_uart.h
#ifndef __FII_UART_H #define __FII_UART_H #ifdef __cplusplus extern "C" { #endif //=============================================== #define UART_BASE 0xe0000000 //define UART base address //define offset address related to the UART base address #define UART_VER 0x00 //define UART version #define UART_RUN 0x04 //define UART enable #define UART_DATA 0x08 //define UART data #define UART_RDY 0x0C //define UART ready (read only) //=============================================== int send_to_uart(const void* ptr, int len); //declaration of UART send function //=============================================== #ifdef __cplusplus } #endif #endif /* __FII_UART_H */
- Main.c
#include <stdio.h> //include the standard I/O library, mainly used to declare printf function #include "platform.h" //user defined function in C library, including GPIO configuration, definition of the memory, //and related subfunctions and parameters #define NOP_DELAY 0x100 //define a macro const unsigned char font[] = //declaration of an array of indexing the segment display font, here hexadecimal (0~f) is used { SEG_0, SEG_1, SEG_2, SEG_3, SEG_4, SEG_5, SEG_6, SEG_7, SEG_8, SEG_9, SEG_A, SEG_B, SEG_C, SEG_D, SEG_E, SEG_F }; //function used to delay void delay_cnt (int cnt) { u32_t I; for(i = 0; i < cnt ; i ++ ) asm("nop"); return; }; int main(void) //define main function { //initialization segment display unsigned int curr_seat = 0x01; //segment display initial location (the right most segment display) unsigned int char_num = 0; //segment display initial value unsigned int curr_num = 0; //lit time for segment display unsigned int char_pos = 0; //array index for segment display font //UART output printf("\r\nRiscV Program : Display segment number and print it. \r\n"); //initialization GPIO (*(volatile unsigned int *)(GPIO_ADDR + LED_VAL)) = ~0L; //led_value is 0, negation is applied for the LED wiring on schematics (*(volatile unsigned int *)(GPIO_ADDR + LED_DIR)) = 0; //LED's direction is output (*(volatile unsigned int *)(GPIO_ADDR + SEAT_DIR)) = 0; //segment location value's direction is output (*(volatile unsigned int *)(GPIO_ADDR + SEG_DIR)) = 0; //segment selection value's direction is output while ( 1 ) //main loop { (*(volatile unsigned int *)(GPIO_ADDR + SEG_VAL)) = ~font[char_pos & 0xf]; //set the segment display index //negation is applied for the wiring on schematics (*(volatile unsigned int *)(GPIO_ADDR + SEAT_VAL)) = ~curr_seat; //set the segment display location //negation is applied for the wiring on schematics delay_cnt (NOP_DELAY); //set time delay curr_seat = curr_seat << 1; //shift the lit segment display to the left 1 bit if(curr_seat == 0x40) //decision making, if the segment display location is the left most { curr_seat = 0x01; //reset it to the right most curr_num ++ ; //counter +1 if(curr_num % 1000 == 9) //prevent multiple print, print once every 1000 iterations { char_num ++ ; //segment display value +1 printf("seg cnt num = 0x%06x \r\n", char_num); } char_pos = char_num; //pass the segment display value to the index font } else char_pos = char_pos >> 4; //right shift the current segment display value by 4 (hexadecimal by 1 bit) } }