1. 8051核

1.1. 8051核

LubanCat-P1基于Sophgo SG2000 SoC,多核架构信息:

  • 一个T-Head C906 64-bit RISC-V CPU核(1GHz)

  • 一个ARM Cortex-A53 CPU核(1GHz)

  • 一个T-Head C906 64位RISC-V核(700Mhz)

  • 一个8051 8-bit低功耗mcu核(25-300MHz)

C906 riscv大核和A53核可以运行Linux系统,C906 riscv小核可以运行Freertos,8051核可以运行裸机。

8051子系统位于由RTC独立供电的模块中,该子系统配置有8051、I2C/UART/SPI NOR/SD 控制器、定时器/WDT、中断管理和Mailbox IP。 系统软件可以使用8051管理唤醒条件并在睡眠模式下唤醒系统,并通过外设控制器与外部设备通信。

默认分配给8051核的运行内存为512kb,可修改SDK进行调整。

1.2. 8051核运行测试

1.2.1. 获取源码

1
git clone https://gitee.com/LubanCat/lubancat_sg2000_code_storage.git

8051部分代码为于:lubancat_sg2000_code_storage/quick_start/8051/

目录说明如下:

  • doc:d8051手册

  • firmware:编译好的固件

  • sdcc:驱动文件和测试代码

  • tools:编译工具和核心启动源码

1.2.2. 编译程序

在firmware目录下已经有编译好的固件,可直接使用测试,以下介绍如何编译源码:

1、8051_up

8051_up用于自动更新固件并启动8051核。

进入lubancat_sg2000_code_storage/quick_start/8051/tools/8051_up目录,执行编译:

1
2
3
4
5
6
7
8
#编译
make

#如果是交叉编译,需指定TOOLCHAIN_PREFIX变量,修改makefile,指定编译器绝对路径
TOOLCHAIN_PREFIX = /home/guest/sg200x/host-tools/gcc/riscv64-linux-musl-x86_64/bin/riscv64-unknown-linux-musl-
CC = $(TOOLCHAIN_PREFIX)gcc
#编译
make

生成的8051_up就是需要的可执行程序。

2、mars_mcu_fw.bin

mars_mcu_fw.bin为8051程序固件,需要在虚拟机或者服务器进行编译,在板卡无法编译。

进入lubancat_sg2000_code_storage/quick_start/8051/sdcc/mars/project/base_project目录,执行编译:

1
2
#编译
make

生成的output/mars_mcu_fw.bin就是需要的固件。

其中8051/sdcc/mars/project/base_project/src/main.c就是程序的主体部分。

1.2.3. 运行测试

如果没有编译,可直接使用lubancat_sg2000_code_storage/quick_start/8051/firmware目录下编译好的。

1、将mars_mcu_fw.bin放到板卡的 /lib/firmware/ 目录下。

2、将8051_up传输到板卡任意目录,lubancat_sg2000_code_storage/quick_start/8051/firmware/8051_boot_cfg.ini放到与8051_up同级目录下。

1
2
3
4
5
6
7
8
9
#添加执行权限并运行
sudo chmod 777 8051_up
sudo ./8051_up

#信息输出如下
8051 will boot on address 9ff80000
load mcu fw: /lib/firmware/mars_mcu_fw.bin
size = 7827
done

其中8051_boot_cfg.ini定义了8051核启动的地址,为0x9ff80000,加载固件/lib/firmware/mars_mcu_fw.bin

3、创建blink.sh,内容如下:

1
2
3
4
5
6
7
while true
do
    devmem 0x05026020 w 6
    sleep 1
    devmem 0x05026020 w 7
    sleep 1
done

4、运行:

由于Linux驱动层已经占用sys_led,需要先释放占用,执行以下命令:

1
2
3
4
5
#释放占用
sudo sh -c "echo 0 > /sys/class/leds/sys_status_led/brightness"

#如果需要恢复则执行
sudo sh -c "echo heartbeat > /sys/class/leds/sys_status_led/trigger"

运行blink.sh:

1
2
3
4
5
6
7
8
9
#添加执行权限并运行
sudo chmod 777 blink.sh
sudo ./blink.sh

#信息输出如下
LED_GPIO->HIGH
LED_GPIO->LOW
LED_GPIO->HIGH
LED_GPIO->LOW

5、实验现象

系统sys_led会1s周期交替亮灭。

1.2.4. 程序说明

8051/sdcc/mars/project/base_project/src/main.c就是程序的主体部分,截取部分内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
void main(void)
{
    uint32_t i2c_cmd = 0xffffffff;
    uint32_t suspend_mode = 0x0;
    uint8_t rw = 0xff;
    uint8_t reg = 0xff;
    uint8_t value = 0xff;
    uint32_t reg_val = 0xff;
    uint32_t fsm_state = 0x0;

    //CKCON = 0x7;
    /* init dw uart*/
#ifdef CONFIG_PUTCHAR_DW_UART
    //dw_uart_init();
#endif
    // printf("cvitek mcu init2 %s\n", __TIME__);
    mmio_write_32(RTC_INFO0, 0x8051);

    /* init interrupt controller */
    dw_ictl_init();

    /* enable interrupt controller*/
    ap2rtc_irq_init();
    irq_enable();

    while(1) {

        rw = mmio_read_32(RTC_INFO1); // 0x05026020
        //printf("case1 uart test\n");
        switch (rw) {

        case 0x0: /* uart test */
            printf("case1 uart test\n");
            mmio_write_32(RTC_INFO1, 0xff);
            break;

        case 0x1:   /* i2c test */
        #if 1
            cv_i2c_pinmux_io_switch(1);
            reset_i2c_cmd();
            if (!cv_i2c_is_busy()) {
                delay_us(2);
                cv_i2c_master_write(0x90, 0x11);
            } else {
                mmio_write_32(RTC_INFO2, 0x66666666);
                printf("RTC_I2C is busy or corrupted\n");
            }
            mmio_write_32(RTC_INFO1, 0xff);
        #endif
            break;

        case 0x2: /* wdg test */
            pwr_wdt_start();
            mmio_write_32(RTC_INFO1, 0xff);
            break;

        case 0x3: /* wdg test */
            dw_wdt_ping();
            mmio_write_32(RTC_INFO1, 0xff);
            break;

        case 0x4: /* wdg test */
            dw_wdt_rst();
            mmio_write_32(RTC_INFO1, 0xff);
            break;

        case 0x5: /* wdg test */
            dw_wdt_rst_realease();
            mmio_write_32(RTC_INFO1, 0xff);
            break;

        case 0x6: /* gpio_high */
            set_gpio_direction(GPIO1_BASE,11,GPIO_DIRECTION_OUT);
            set_gpio_level(GPIO1_BASE,11,GPIO_LEVEL_HIGH);
            mmio_write_32(RTC_INFO1, 0xff);
            printf("LED_GPIO->HIGH\n");
            break;

        case 0x7: /* gpio_low */
            set_gpio_direction(GPIO1_BASE,11,GPIO_DIRECTION_OUT);
            set_gpio_level(GPIO1_BASE,11,GPIO_LEVEL_LOW);
            mmio_write_32(RTC_INFO1, 0xff);
            printf("LED_GPIO->LOW\n");
            break;

        default:
            break;
        }
    }
}

初始化完成后会不断读取RTC_INFO1寄存器的值,然后执行对于的代码。

RTC_INFO1寄存器值可以查阅sg2000_trm_cn.pdf手册找到相关地址定义,手册在资料网盘/5-数据手册目录中。

RTC_INFO1寄存器位于RTC寄存器,基地址为0x05026000,偏移地址为0x020。

所以blink.sh中通过devmem工具修改0x05026020寄存器地址的值为6/7,就会执行led控制部分程序,控制引脚高低电平。