Menu Close

RISC-V C Programming 2 (1)Segment Display Project

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)
    } 
}

 

Posted in Application and Development, Articles, C Language, Embedded Programming Language, RISC-V, RISC-V Textbook, Textbook and Training Project

Related Articles

Leave a Reply

Your email address will not be published.

Leave the field below empty!