Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Baremetal xv6 ported to milkv duo #4

Open
wants to merge 10 commits into
base: riscv
Choose a base branch
from

Conversation

BigBrotherJu
Copy link

烧录

执行根目录下的 script,提供 sd 卡的设备文件名,如 ./script /dev/sdb,产生的二进制文件路径为 port/image/output/milkv-duo.img

驱动

  • i2c

    SOC 提供了 5 个 i2c controller,开发板从 controller 0、1、3 引出引脚。

    驱动支持每次控制 i2c 0、1、2、3、4 中的任意 1 个,ioctl 配置 slave 地址,并 read write 值。

    为了演示方便,测试示例只驱动 i2c 1。

    测试示例需要连接陀螺仪传感器 MPU6050,可以获得三轴加速度和角速度(数据为未经处理的原始数据)。

  • uart

    SOC 提供了 5 个 uart controller,开发板对 5 个 controller 都提供引脚。

    uart 0 与 console 相连,不被驱动。

    驱动支持每次控制 uart 1、2、3、4 中的任意 1 个,ioctl 配置 uart 参数,并 read write 值。

    为了演示方便,测试示例只驱动 uart 4。

    测试示例需要把开发板的 uart 4 连接到电脑的串口工具中。一串字符会先被输出到串口工具中,然后我们可以在串口工具中打字,打字的长度由测试示例的第一个参数决定,串口工具中输入的字符会重新在串口工具中显示。

  • adc

    SOC 提供了 1 个 adc controller,开发板从这个 controller 引出引脚。

    驱动支持每次控制这个 controller 的任意 1 个 channel,并 read 值。

    为了演示方便,测试示例只驱动 channel 1。

    测试示例会读 10 次 channel 1 的输入值,可以将 3.3v 输入 channel 1 然后取消输入,观察 channel 1 读取到的数字量的变化。

  • pwm

    SOC 提供了 4 个 pwm controller,开发板从 controller 1 和 2 引出引脚。

    驱动支持每次控制任意 1 个 controller 的任意 1 个 channel,ioctl 配置并使能 channel。

    为了演示方便,测试示例只驱动 pwm5(pwm 1 的 channel 1)。

    测试示例需要连接 DF9GMS 180 微型舵机,可以对 pwm5 设置不同的 duty,使舵机的舵进行不同角度旋转。

  • gpio

    SOC 提供了 4 个 gpio controller,开发板从 4 个 controller 都有引出 gpio 引脚。

    驱动支持每次控制任意 1 个 controller 的任意 1 个 channel,ioctl 配置为输入或输出,并 read 或 write 值。

    为了演示方便,测试示例只驱动开发板上的 GP0(gpio 0 的 channel 28)和 GP25(gpio 2 的 channel 24)。

    测试示例会先使开发板的蓝色 led 进行闪烁,然后读取 10 次 GP0 处的输入。GP0 的原始输入是 1,接地后输入为 0。

  • spi

    SOC 提供了 4 个 spi controller,开发板从 controller 2 引出引脚。

    驱动支持每次控制任意 1 个 controller,ioctl 配置模式与频率,并启动读写。

    为了演示方便,测试示例只驱动 spi 2。

    测试示例为 spi 回环测试,需要短接 spi 2 的两个数据引脚。发出的数据会一摸一样得被接收到。

@BigBrotherJu
Copy link
Author

BigBrotherJu commented Mar 1, 2024

引脚分配

图中黑框圈出的引脚即为测试示例测试的引脚,已配置好引脚复用,将对应外设连接即可测试。

image

示例

  • 每个驱动对应的示例用户程序为 xxxtest,已包含在镜像中,开发板上电以后即可执行
  • pwm 驱动舵机示例:https://youtu.be/HcWbFNFGxGc
  • i2c 驱动陀螺仪示例:https://youtu.be/O51iY6FCdak
  • 其他驱动示例没有特殊外设,可以自行验证
  • uart0 的配置是 115200、8 data bits、1 stop bit、no parity,uart4 的配置可在 user/uarttest.c 中自行更改,默认与 uart0 配置相同,在使用 uart0 uart4 时可能需要在串口工具中将输入串口工具的 lf 转换成 crlf

@shiptux
Copy link

shiptux commented Mar 26, 2024

尊敬的参赛选手,您好。
本次锦标赛您所提交的 PR 初步复测结果如 https://github.com/plctlab/rvspoc/blob/main/Results/Verifications/P2308/README.md 所示。如有任何异议请回复本条评论。如确认无误请回复 “确认无误”,感谢您的配合。

@BigBrotherJu
Copy link
Author

尊敬的参赛选手,您好。 本次锦标赛您所提交的 PR 初步复测结果如 https://github.com/plctlab/rvspoc/blob/main/Results/Verifications/P2308/README.md 所示。如有任何异议请回复本条评论。如确认无误请回复 “确认无误”,感谢您的配合。

@shiptux 您好,我有几个问题:

  1. 我的 i2c 是否通过了测试?

    我看到我的 pr 验证结果中 i2c 后面没有打上 OK,而我的其他驱动验证条目是有 OK 的,如 UART OK。但是,我看到所有选手的验证结果表格中我的 i2c 打上了 Y。这是否意味着我的 i2c 驱动通过了测试?

    如果评委觉得我的 i2c 驱动及测试用例有问题,可以看我拍的用 i2c 接口驱动陀螺仪的视频:https://youtu.be/O51iY6FCdak

  2. 我认为 pr2 没有提供 uart 驱动及测试用例

    赛题产出及评分要求的第 2 条为:支持基础外设驱动主要包括 UART、GPIO、I2C、SPI、ADC、PWM 并编写相应示例。

    但是,根据 pr2 makefile 的 diff,pr2 并没有提供 uart 驱动及测试用例。

    在 Linux 下,一个常规使用 uart 的用户程序如下所示。而在 xv6 下,用户也应该能够进行类似的操作,即配置一个 uart 控制器的各项参数(波特率、stop bit、parity bit 等),并从这个 uart 接收数据或向这个 uart 发送数据。我提供了 uart 的驱动以及用户使用程序,但是 pr2 好像没有。

    #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <errno.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <termios.h>
    #include <stdlib.h>
    
    /* set_opt(fd,115200,8,'N',1) */
    int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
    {
        struct termios newtio,oldtio;
        
        if ( tcgetattr( fd,&oldtio) != 0) { 
            perror("SetupSerial 1");
            return -1;
        }
        
        bzero( &newtio, sizeof( newtio ) );
        newtio.c_cflag |= CLOCAL | CREAD; 
        newtio.c_cflag &= ~CSIZE; 
    
        newtio.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/
        newtio.c_oflag  &= ~OPOST;   /*Output*/
    
        switch( nBits )
        {
        case 7:
            newtio.c_cflag |= CS7;
        break;
        case 8:
            newtio.c_cflag |= CS8;
        break;
        }
    
        switch( nEvent )
        {
        case 'O':
            newtio.c_cflag |= PARENB;
            newtio.c_cflag |= PARODD;
            newtio.c_iflag |= (INPCK | ISTRIP);
        break;
        case 'E': 
            newtio.c_iflag |= (INPCK | ISTRIP);
            newtio.c_cflag |= PARENB;
            newtio.c_cflag &= ~PARODD;
        break;
        case 'N': 
            newtio.c_cflag &= ~PARENB;
        break;
        }
    
        switch( nSpeed )
        {
        case 2400:
            cfsetispeed(&newtio, B2400);
            cfsetospeed(&newtio, B2400);
        break;
        case 4800:
            cfsetispeed(&newtio, B4800);
            cfsetospeed(&newtio, B4800);
        break;
        case 9600:
            cfsetispeed(&newtio, B9600);
            cfsetospeed(&newtio, B9600);
        break;
        case 115200:
            cfsetispeed(&newtio, B115200);
            cfsetospeed(&newtio, B115200);
        break;
        default:
            cfsetispeed(&newtio, B9600);
            cfsetospeed(&newtio, B9600);
        break;
        }
        
        if( nStop == 1 )
            newtio.c_cflag &= ~CSTOPB;
        else if ( nStop == 2 )
            newtio.c_cflag |= CSTOPB;
        
        newtio.c_cc[VMIN]  = 1;  /* 读数据时的最小字节数: 没读到这些数据我就不返回! */
        newtio.c_cc[VTIME] = 0; /* 等待第1个数据的时间: 
                                 * 比如VMIN设为10表示至少读到10个数据才返回,
                                 * 但是没有数据总不能一直等吧? 可以设置VTIME(单位是10秒)
                                 * 假设VTIME=1,表示: 
                                 *    10秒内一个数据都没有的话就返回
                                 *    如果10秒内至少读到了1个字节,那就继续等待,完全读到VMIN个数据再返回
                                 */
    
        tcflush(fd,TCIFLUSH);
        
        if((tcsetattr(fd,TCSANOW,&newtio))!=0)
        {
            perror("com set error");
            return -1;
        }
        //printf("set done!\n");
        return 0;
    }
    
    int open_port(char *com)
    {
        int fd;
        //fd = open(com, O_RDWR|O_NOCTTY|O_NDELAY);
        fd = open(com, O_RDWR|O_NOCTTY);
        if (-1 == fd){
            return(-1);
        }
        
    	if(fcntl(fd, F_SETFL, 0)<0) /* 设置串口为阻塞状态*/
    	{
    		printf("fcntl failed!\n");
    		return -1;
    	}
      
    	return fd;
    }
    
    
    /*
     * ./serial_send_recv <dev>
     */
    int main(int argc, char **argv)
    {
        int fd;
        int iRet;
        char c;
    
        /* 1. open */
    
        /* 2. setup 
         * 115200,8N1
         * RAW mode
         * return data immediately
         */
    
        /* 3. write and read */
        
        if (argc != 2)
        {
            printf("Usage: \n");
            printf("%s </dev/ttySAC1 or other>\n", argv[0]);
            return -1;
        }
    
        fd = open_port(argv[1]);
        if (fd < 0)
        {
            printf("open %s err!\n", argv[1]);
            return -1;
        }
    
        iRet = set_opt(fd, 115200, 8, 'N', 1);
        if (iRet)
        {
            printf("set port err!\n");
            return -1;
        }
    
        printf("Enter a char: ");
        while (1)
        {
            scanf("%c", &c);
            iRet = write(fd, &c, 1);
            iRet = read(fd, &c, 1);
            if (iRet == 1)
                printf("get: %02x %c\n", c, c);
            else
                printf("can not get data\n");
        }
    
        return 0;
    }

@shiptux
Copy link

shiptux commented Mar 26, 2024

2. uart

选手,您好。主要以表格为统一。您的 I2C 是通过验证的。下面的验证过程中能从日志看出已经明显读出了数据。至于这里的 OK 是我们在验证过程中的标记,由于验证并没有在一个自然天内完成,涉及到设备采购等。这里漏了一个 OK, 对于给您带来的误解深感抱歉。稍后我会增添一个 PR 添加上这个 OK.

shiptux added a commit to shiptux/rvspoc that referenced this pull request Mar 26, 2024
shiptux added a commit to rv2036/rvspoc that referenced this pull request Mar 26, 2024
@shiptux
Copy link

shiptux commented Mar 26, 2024

  • uart 0 与 console 相连,不被驱动。

选手您好。 针对您提出的问题关于 PR2 的 UART 是否实现的情况:

  1. PR2 和您的 PR4 都实现了 kernel/uart.c ,可以用于日志获取和日志登陆。
  2. 您额外实现了 uart_dev.c 支持驱动和配置额外的 uart 引脚。

由于我们的赛题中没有明确规定和描述 uart 的交付和判定细节,关于我们的赛题评定规则此部分需要等待之后的评委进行讨论和完善。

感谢您完成的这部分工作,以及发现和提出的这个问题。

@xhackerustc
Copy link

简单说一句:xv6本身的shell console就是uart测试用例,shell下console能输入输出即可验uart驱动和测试用例

@xhackerustc
Copy link

"测试示例需要把开发板的 uart 4 连接到电脑的串口工具中。一串字符会先被输出到串口工具中,然后我们可以在串口工具中打字,打字的长度由测试示例的第一个参数决定,串口工具中输入的字符会重新在串口工具中显示。" 这一步对于验证串口来说与用串口工具minicom/putty接console操作并无区别

@BigBrotherJu
Copy link
Author

选手您好。 针对您提出的问题关于 PR2 的 UART 是否实现的情况:

  1. PR2 和您的 PR4 都实现了 kernel/uart.c ,可以用于日志获取和日志登陆。
  2. 您额外实现了 uart_dev.c 支持驱动和配置额外的 uart 引脚。

由于我们的赛题中没有明确规定和描述 uart 的交付和判定细节,关于我们的赛题评定规则此部分需要等待之后的评委进行讨论和完善。

@shiptux 您好,我附上了产出及评分要求。

您说的第一点,以及 pr2 选手说的「简单说一句:xv6本身的shell console就是uart测试用例,shell下console能输入输出即可验uart驱动和测试用例」对应要求第一条中的「UART 通讯」。

您说的第二点对应要求第二条中的「支持基础外设驱动包括 UART 并编写相应示例」。我只是按照赛题要求进行实现,并没有额外完成任务。

而且我认为赛题中的「uart 的交付和判定细节」已经描述得很清晰了,首先要支持 xv6 的 console(即要求第一条中的「UART 通讯」),然后要支持驱动 UART 并附带用户程序示例(即要求第二条)。

如果当初在制定赛题要求时,第二条中没有包括 UART,那我才是「额外实现了 uart_dev.c 支持驱动和配置额外的 uart 引脚」。

image

@xhackerustc
Copy link

uart使用的相应示例xv6本身就有,这就不用额外编写。这个话题不会再评论

@shiptux
Copy link

shiptux commented Mar 27, 2024

选手们,你们好。上述意见均已收集并汇总提交给评委进行讨论。预计最迟下周一会有反馈。

@BigBrotherJu
Copy link
Author

@shiptux 你好,有说法吗

@shiptux
Copy link

shiptux commented Apr 1, 2024

@shiptux 你好,有说法吗

选手您好,很抱歉,目前针对此项目还没有讨论出结论。预期在本周内会有进一步的信息给出。

@shiptux
Copy link

shiptux commented Apr 3, 2024

选手您好:

  1. 经过评委会的分析确认,最终按照「实质性完成」判定分类思想,认定为完成了 PR2的内置 shell console 模式的 UART 判定为验证通过。
  2. 由于P2308有多个评分点,UART 单项的判定结果(及权重)不会改变P2308赛题的冠军判定。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants