0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于小凌派RK2206开发板的EEPROM存储案例

老渔翁 来源:xxl1925 作者:xxl1925 2022-04-18 10:01 次阅读

一、简介

在实际的应用中,保存在RAM中的数据掉电后就丢失了,保存在FLASH中的数据又不能随意改变,也就是不能用它来记录变化的数值。但是在某些特定场合,我们又确实需要记录下某些数据,而它们还时常需要改变或更新,掉电之后数据还不能丢失。比如,我们的家用电表度数,电视机里边的频道记忆,一般都是使用EEPROM来保存数据,特点就是掉电后存储的数据不丢失。

EEPROM (Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器。是一种掉电后数据不丢失的存储芯片。EEPROM可以在电脑上或专用设备上擦除已有信息,重新编程。一般用在即插即用。一般情况下,EEPROM拥有30万到100万次的寿命,也就是它可以反复写入30~100万次,而读取次数是无限的。

本文基于瑞芯微RK2206芯片 + Harmony LiteOS操作系统,通过i2c总线控制EEPROM读写。

二、硬件电路设计

我使用的EEPROM型号是K24C02,它是一个常用的基于IIC通信协议的EEPROM元件,例如ATMEL公司的AT24C02、CATALYST公司的CAT24C02和ST公司的ST24C02等芯片。IIC是一个通信协议,它拥有严密的通信时序逻辑要求,而EEPROM是一个元件,只是这个元件采样了IIC协议的接口单片机相连而已,二者并没有必然的联系,EEPROM可以用其它接口,I2C也可以用在其它很多器件上。根据K24C02芯片手册,可获知如下:

(1)K24C02芯片的从设备地址。因本章节采用的2Kbit的EEPROM,所以该芯片I2C从设备地址为0x51。如下图所示:

poYBAGJZJ1mANuFJAABd-7ruzCE909.png

图K24C02的从设备地址图

(2)K24C02芯片的读操作

K24C02芯片的读操作共分为3种,分别为当前地址读(Current Address Read)、随机读(Random Read)和连续读(Sequential Read)。

其中,当前地址读(Current Address Read)操作是控制i2c与K24C02通信,通信内容为:从设备地址(1个字节,bit0为1,表示读) + 数据(1个字节,K24C02发送给CPU的存储内容)。该读操作没有附带EEPROM的存储地址,存储地址是由上一次存储地址累加而来。如下图所示:

poYBAGJZKMOAao4iAABzX0JsFXM824.png

图 K24C02的当前地址读操作

而随机读操作则控制i2c与K24C02进行2次通信:

第1次i2c通信:从设备地址(1个字节,bit0为0,表示写) + 存储地址(1个字节,CPU发送给K24C02的存储地址)

第2次i2c通信:从设备地址(1个字节,bit0为1,表示读) + 数据(1个字节,K24C02发送给CPU的存储内容)。

具体数据传输如下图所示:

pYYBAGJZKO2AGN_0AACWYOUF6ew781.png

图 K24C02的随机地址读操作

连续读操作(Sequential Read)则控制控制i2c往K24C02发送N个字节,通信内容为:从设备地址(bit0为1,表示读) + N个数据(K24C02发送给CPU)。具体数据传输如下图所示:

poYBAGJZJ7uAJCgjAACNk3By7Wg161.png

图 K24C02的连续读操作

(3)K24C02芯片的写操作

K24C02芯片写数据操作可分为2种,分别为字节写操作(Byte Write)和页写操作(Page Write)。

其中,字节写操作(Byte Write)控制i2c与K24C02通信,通信内容为:从设备地址(1个字节,bit0为0,表示写) + 存储地址(1个字节) + 数据(1个字节,CPU发送给K24C0的存储内容)。具体数据传输如下图所示:

pYYBAGJZJ9-AYEhLAABljTReqeM948.png

图 K24C02的字节写操作

页写操作(Page Write)则控制i2c与K24C02通信,通信内容为:从设备地址(1个字节,bit0为0,表示写) + 存储地址(1个字节) + 数据(N个字节,CPU发送给K24C0的存储内容)。其中,存储数据的N个字节,N不能超过Page大小(K24C02的页大小为8个字节)。

三、程序设计

程序控制RK2206芯片的I2C与K24C02芯片通信,每5秒往某一块存储空间(该存储空间地址依次累加)写入不同数据,然后再读取出来。

1、主程序设计

如图所示为EEPROM存储主程序流程图,开机LiteOS系统初始化后,进入主程序后。主程序首先初始化i2c总线。其次,程序进入主循环,每5秒将不同的数据写入到一块存储空间,然后再读取回去。其中,存储空间地址每次循环都累加32,数据也随着循环而累加1。

pYYBAGJZKReABri2AABbTIyKOfw297.png
图主程序流程图

while (1)
  {
    printf("************ Eeprom Process ************\n");
    printf("BlockSize = 0x%x\n", eeprom_get_blocksize());
    
    /* 写EEPROM */
    memset(buffer, 0, sizeof(buffer));
    for (unsigned int i = 0; i < FOR_CHAR; i++)
        {
            buffer[i] = data_offset + i;
            printf("Write Byte: %d = %c\n", addr_offset + i, buffer[i]);
        }
        ret = eeprom_write(addr_offset, buffer, FOR_CHAR);
        if (ret != FOR_CHAR)
        {
            printf("EepromWrite failed(%d)\n", ret);
        }
        
        /* 读EEPROM */
        memset(buffer, 0, sizeof(buffer));
        ret = eeprom_read(addr_offset, buffer, FOR_CHAR);
        if (ret != FOR_CHAR)
        {
            printf("Read Bytes: failed!\n");
        }
        else
        {
            for (unsigned int i = 0; i < FOR_CHAR; i++)
            {
                printf("Read Byte: %d = %c\n", addr_offset + i, buffer[i]);
            }
        }
        
        data_offset++;
        if (data_offset >= CHAR_END)
    {
      data_offset = CHAR_START;
    }
    
    addr_offset += FOR_ADDRESS;
    if (addr_offset >= 200)
    {
      addr_offset = 0;
    }
    printf("\n");
    
    LOS_Msleep(5000);
  }

2、EEPROM初始化程序设计

主程序通过控制RK2206芯片的接口对i2c总线进行初始化。

#define EEPROM_I2C_BUS     0
#define EEPROM_I2C_ADDRESS   0x51

static I2cBusIo m_i2cBus = {
  .scl = {.gpio = GPIO0_PA1, .func = MUX_FUNC3, .type = PULL_NONE, .drv = DRIVE_KEEP, .dir = LZGPIO_DIR_KEEP, .val = LZGPIO_LEVEL_KEEP},
  .sda = {.gpio = GPIO0_PA0, .func = MUX_FUNC3, .type = PULL_NONE, .drv = DRIVE_KEEP, .dir = LZGPIO_DIR_KEEP, .val = LZGPIO_LEVEL_KEEP},
  .id = FUNC_ID_I2C0,
  .mode = FUNC_MODE_M2,
};

static unsigned int m_i2c_freq = 100000;


unsigned int eeprom_init()
{
  if (I2cIoInit(m_i2cBus) != LZ_HARDWARE_SUCCESS) {
    printf("%s, %d: I2cIoInit failed!\n", __FILE__, __LINE__);
    return __LINE__;
  }
  if (LzI2cInit(EEPROM_I2C_BUS, m_i2c_freq) != LZ_HARDWARE_SUCCESS) {
    printf("%s, %d: I2cInit failed!\n", __FILE__, __LINE__);
    return __LINE__;
  }

  /* GPIO0_A0 => I2C1_SDA_M1 */
  PinctrlSet(GPIO0_PA0, MUX_FUNC3, PULL_NONE, DRIVE_KEEP);
  /* GPIO0_A1 => I2C1_SCL_M1 */
PinctrlSet(GPIO0_PA1, MUX_FUNC3, PULL_NONE, DRIVE_KEEP);

  return 0;
}

3、EEPROM读操作程序设计

蜂鸣器控制程序当开启蜂鸣器时,打开蜂鸣器,并且设置PWM波的周期为100毫秒,其中占空比50%;当关闭蜂鸣器时,则停止蜂鸣器。

#define EEPROM_I2C_BUS     0
#define EEPROM_I2C_ADDRESS   0x51

/* EEPROM型号:K24C02,2Kbit(256Byte),32页,每页8个字节(Byte) */
#define EEPROM_ADDRESS_MAX   256
#define EEPROM_PAGE       8

unsigned int eeprom_readbyte(unsigned int addr, unsigned char *data)
{
  unsigned int ret = 0;
  unsigned char buffer[1];
  LzI2cMsg msgs[2];

  /* K24C02的存储地址是0~255 */
  if (addr >= EEPROM_ADDRESS_MAX) {
    printf("%s, %s, %d: addr(0x%x) >= EEPROM_ADDRESS_MAX(0x%x)\n", __FILE__, __func__, __LINE__, addr, EEPROM_ADDRESS_MAX);
    return 0;
}

  buffer[0] = (unsigned char)addr;
  msgs[0].addr = EEPROM_I2C_ADDRESS;
  msgs[0].flags = 0;
  msgs[0].buf = &buffer[0];
  msgs[0].len = 1;
  msgs[1].addr = EEPROM_I2C_ADDRESS;
  msgs[1].flags = I2C_M_RD;
  msgs[1].buf = data;
  msgs[1].len = 1;
 ret = LzI2cTransfer(EEPROM_I2C_BUS, msgs, 2);
 if (ret != LZ_HARDWARE_SUCCESS) {
   printf("%s, %s, %d: LzI2cTransfer failed(%d)!\n", __FILE__, __func__, __LINE__, ret);
   return 0;
 }

 return 1;
}

unsigned int eeprom_read(unsigned int addr, unsigned char *data, unsigned int data_len) 
{
  unsigned int ret = 0;

  if (addr >= EEPROM_ADDRESS_MAX) {
    printf("%s, %s, %d: addr(0x%x) >= EEPROM_ADDRESS_MAX(0x%x)\n", __FILE__, __func__, __LINE__, addr, EEPROM_ADDRESS_MAX);
    return 0;
}

  if ((addr + data_len) > EEPROM_ADDRESS_MAX) {
    printf("%s, %s, %d: addr + len(0x%x) > EEPROM_ADDRESS_MAX(0x%x)\n", __FILE__, __func__, __LINE__, addr + data_len, EEPROM_ADDRESS_MAX);
    return 0;
}  

  ret = eeprom_readbyte(addr, data);
  if (ret != 1) {
    printf("%s, %s, %d: EepromReadByte failed(%d)\n", __FILE__, __func__, __LINE__, ret);
    return 0;
}

  if (data_len > 1) {
    ret = LzI2cRead(EEPROM_I2C_BUS, EEPROM_I2C_ADDRESS, &data[1], data_len - 1);
    if (ret < 0) {
            printf("%s, %s, %d: LzI2cRead failed(%d)!\n", __FILE__, __func__, __LINE__, ret);
            return 0;
        }
}

    return data_len;
}

4、EEPROM写操作程序设计

主程序根据存储地址、存储数据和数据长度的不同,选用字节写操作或页写操作。具体源代码如下所示:

#define EEPROM_I2C_BUS     0
#define EEPROM_I2C_ADDRESS   0x51

/* EEPROM型号:K24C02,2Kbit(256Byte),32页,每页8个字节(Byte) */
#define EEPROM_ADDRESS_MAX   256
#define EEPROM_PAGE       8

unsigned int eeprom_writebyte(unsigned int addr, unsigned char data)
{
  unsigned int ret = 0;
  LzI2cMsg msgs[1];
  unsigned char buffer[2];

  /* K24C02的存储地址是0~255 */
  if (addr >= EEPROM_ADDRESS_MAX) {
    printf("%s, %s, %d: addr(0x%x) >= EEPROM_ADDRESS_MAX(0x%x)\n", __FILE__, __func__, __LINE__, addr, EEPROM_ADDRESS_MAX);
    return 0;
}

  buffer[0] = (unsigned char)(addr & 0xFF);
  buffer[1] = data;

  msgs[0].addr = EEPROM_I2C_ADDRESS;
  msgs[0].flags = 0;
  msgs[0].buf = &buffer[0];
  msgs[0].len = 2;
  ret = LzI2cTransfer(EEPROM_I2C_BUS, msgs, 1);
  if (ret != LZ_HARDWARE_SUCCESS) {
   printf("%s, %s, %d: LzI2cTransfer failed(%d)!\n", __FILE__, __func__, __LINE__, ret);
   return 0;
}

  /* K24C02芯片需要时间完成写操作,在此之前不响应其他操作*/
  eeprog_delay_usec(1000);
  return 1;
}

unsigned int eeprom_writepage(unsigned int addr, unsigned char *data, unsigned int data_len)
{
  unsigned int ret = 0;
  LzI2cMsg msgs[1];
  unsigned char buffer[EEPROM_PAGE + 1];
  
  /* K24C02的存储地址是0~255 */
  if (addr >= EEPROM_ADDRESS_MAX) {
    printf("%s, %s, %d: addr(0x%x) >= EEPROM_ADDRESS_MAX(0x%x)\n", __FILE__, __func__, __LINE__, addr, EEPROM_ADDRESS_MAX);
    return 0;
  }

  if ((addr % EEPROM_PAGE) != 0) {
    printf("%s, %s, %d: addr(0x%x) is not page addr(0x%x)\n", __FILE__, __func__, __LINE__, addr, EEPROM_PAGE);
    return 0;
}

  if ((addr + data_len) > EEPROM_ADDRESS_MAX) {
    printf("%s, %s, %d: addr + data_len(0x%x) > EEPROM_ADDRESS_MAX(0x%x)\n", __FILE__, __func__, __LINE__, addr + data_len, EEPROM_ADDRESS_MAX);
    return 0;
}

  if (data_len > EEPROM_PAGE) {
    printf("%s, %s, %d: data_len(%d) > EEPROM_PAGE(%d)\n", __FILE__, __func__, __LINE__, data_len, EEPROM_PAGE);
    return 0;
}

  buffer[0] = addr;
  memcpy(&buffer[1], data, data_len);
  msgs[0].addr = EEPROM_I2C_ADDRESS;
  msgs[0].flags = 0;
  msgs[0].buf = &buffer[0];
  msgs[0].len = 1 + data_len;
  ret = LzI2cTransfer(EEPROM_I2C_BUS, msgs, 1);
  if (ret != LZ_HARDWARE_SUCCESS) {
   printf("%s, %s, %d: LzI2cTransfer failed(%d)!\n", __FILE__, __func__, __LINE__, ret);
   return 0;
}

  /* K24C02芯片需要时间完成写操作,在此之前不响应其他操作*/
  eeprog_delay_usec(1000);
  return data_len;
}

unsigned int eeprom_write(unsigned int addr, unsigned char *data, unsigned int data_len)
{
  unsigned int ret = 0;
  unsigned int offset_current = 0;
  unsigned int page_start, page_end;
  unsigned char is_data_front = 0;
  unsigned char is_data_back = 0;
  unsigned int len;

  if (addr >= EEPROM_ADDRESS_MAX) {
    printf("%s, %s, %d: addr(0x%x) >= EEPROM_ADDRESS_MAX(0x%x)\n", __FILE__, __func__, __LINE__, addr, EEPROM_ADDRESS_MAX);
    return 0;
}

  if ((addr + data_len) > EEPROM_ADDRESS_MAX) {
    printf("%s, %s, %d: addr + len(0x%x) > EEPROM_ADDRESS_MAX(0x%x)\n", __FILE__, __func__, __LINE__, addr + data_len, EEPROM_ADDRESS_MAX);
    return 0;
}

  /* 判断addr是否是页地址 */
  page_start = addr / EEPROM_PAGE;
  if ((addr % EEPROM_PAGE) != 0) {
    page_start += 1;
    is_data_front = 1;
}

  /* 判断addr + data_len是否是页地址 */
  page_end = (addr + data_len) / EEPROM_PAGE;
  if ((addr + data_len) % EEPROM_PAGE != 0) {
    page_end += 1;
    is_data_back = 1;
}

  offset_current = 0;
  
  /* 处理前面非页地址的数据,如果是页地址则不执行 */
  for (unsigned int i = addr; i < (page_start * EEPROM_PAGE); i++) {
        ret = eeprom_writebyte(i, data[offset_current]);
        if (ret != 1) {
            printf("%s, %s, %d: EepromWriteByte failed(%d)\n", __FILE__, __func__, __LINE__, ret);
            return offset_current;
        }
        offset_current++;
}

    /* 处理后续的数据,如果数据长度不足一个Page,则不执行 */
    for (unsigned int page = page_start; page < page_end; page++) {
        len = EEPROM_PAGE;
        if ((page == (page_end - 1)) && (is_data_back)) {
            len = (addr + data_len) % EEPROM_PAGE;
        }
    
        ret = eeprom_writepage(page * EEPROM_PAGE, &data[offset_current], len);
        if (ret != len) {
            printf("%s, %s, %d: EepromWritePage failed(%d)\n", __FILE__, __func__, __LINE__, ret);
            return offset_current;
        }
        offset_current += EEPROM_PAGE;
}

    return data_len;

四、编译过程

1、搭建和下载源代码

我已将OpenHarmony源代码上传到Gitee社区中,大家可以根据以下网址下载。

https://gitee.com/Lockzhiner-Electronics/lockzhiner-rk2206-openharmony3.0lts

注意:编译环境可根据以下网址来操作:https://gitee.com/Lockzhiner-Electronics/lockzhiner-rk2206-openharmony3.0lts/blob/master/vendor/lockzhiner/rk2206/README_zh.md

2、打开sdk下面路径的文件

/vendor/lockzhiner/rk2206/samples/b3_eeprom/eeprom_example.c

注意:Gitee上的EEPROM案例为通用案例,请大家根据上述的需求修改相关源代码。

3、修改编译脚本

修改 vendor/lockzhiner/rk2206/sample 路径下 BUILD.gn 文件,指定 eeprom_example 参与编译。

"./b3_eeprom:eeprom_example",

修改 device/lockzhiner/rk2206/sdk_liteos 路径下 Makefile 文件,添加 -leeprom_example 参与编译。

hardware_LIBS = -lhal_iothardware -lhardware -leeprom_example

4、编译固件

hb set -root .

hb set

hb build -f

5、烧写固件

请参考Gitee网址的说明手册(“烧录打印”章节):https://gitee.com/Lockzhiner-Electronics/lockzhiner-rk2206-openharmony3.0lts/blob/master/device/rockchip/README_zh.md

五、实验结果

程序编译烧写到开发板后,按下开发板的RESET按键,通过串口软件查看日志如下:

************ Eeprom Process ************
BlockSize = 0x8
Write Byte: 3 = !
Write Byte: 4 = "
Write Byte: 5 = #
Write Byte: 6 = $
Write Byte: 7 = %
Write Byte: 8 = &
Write Byte: 9 = '
Write Byte: 10 = (
Write Byte: 11 = )
Write Byte: 12 = *
Write Byte: 13 = +
Write Byte: 14 = ,
Write Byte: 15 = -
Write Byte: 16 = .
Write Byte: 17 = /
Write Byte: 18 = 0
Write Byte: 19 = 1
Write Byte: 20 = 2
Write Byte: 21 = 3
Write Byte: 22 = 4
Write Byte: 23 = 5
Write Byte: 24 = 6
Write Byte: 25 = 7
Write Byte: 26 = 8
Write Byte: 27 = 9
Write Byte: 28 = :
Write Byte: 29 = ;
Write Byte: 30 = <
Write Byte: 31 = =
Write Byte: 32 = >
Read Byte: 3 = !
Read Byte: 4 = "
Read Byte: 5 = #
Read Byte: 6 = $
Read Byte: 7 = %
Read Byte: 8 = &
Read Byte: 9 = '
Read Byte: 10 = (
Read Byte: 11 = )
Read Byte: 12 = *
Read Byte: 13 = +
Read Byte: 14 = ,
Read Byte: 15 = -
Read Byte: 16 = .
Read Byte: 17 = /
Read Byte: 18 = 0
Read Byte: 19 = 1
Read Byte: 20 = 2
Read Byte: 21 = 3
Read Byte: 22 = 4
Read Byte: 23 = 5
Read Byte: 24 = 6
Read Byte: 25 = 7
Read Byte: 26 = 8
Read Byte: 27 = 9
Read Byte: 28 = :
Read Byte: 29 = ;
Read Byte: 30 = <
Read Byte: 31 = =
Read Byte: 32 = >
......

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • EEPROM
    +关注

    关注

    9

    文章

    926

    浏览量

    80304
  • 开发板
    +关注

    关注

    25

    文章

    4426

    浏览量

    93938
  • RK2206
    +关注

    关注

    0

    文章

    34

    浏览量

    1639
  • 小凌派
    +关注

    关注

    0

    文章

    27

    浏览量

    1140
收藏 人收藏

    评论

    相关推荐

    小凌派RK2206开发板EEPROM存储案例详解

    需要改变或更新,掉电之后数据还不能丢失。比如,我们的家用电表度数,电视机里边的频道记忆,一般都是使用EEPROM来保存数据,特点就是掉电后存储的数据不丢失。 EEPROM (Electrically Erasable Progr
    发表于 04-15 19:10 2026次阅读
    小凌派<b class='flag-5'>RK2206</b><b class='flag-5'>开发板</b><b class='flag-5'>EEPROM</b><b class='flag-5'>存储</b>案例详解

    RK2206鸿蒙开发板新品首发试用

    鸿蒙开发板 瑞芯微RK2206 OpenHarmony系统 E53 loT物联网了解更多&amp;gt;&amp;gt;
    发表于 03-28 17:12

    RK2206鸿蒙开发板原理图硬件资料分享

    RK2206鸿蒙开发板原理图和硬件datasheet资料分享,需要的自取~
    发表于 04-01 17:16

    RK2206鸿蒙开发板原理图硬件资料

    RK2206鸿蒙开发板原理图和硬件datasheet资料分享,需要的自取~
    发表于 04-01 17:39

    轻量系统开发套件介绍:睿智捷 | 小-RK2206 开发板套件

    睿智捷 | 小-RK2206 开发板套件是由福州市睿智捷电子有限公司出品,主控器为瑞芯微
    发表于 04-21 13:39

    【小RK2206开发板试用体验】安装编译环境的分享

    : hb build -f 然后就OK了。[OHOS INFO] lockzhiner-rk2206 build success到这里编译环境就可以。【思考】对于这个ubuntu下的编译环境的建立,还得花点心思才行。要几个视频、文档结合来看。最后希望大家上手小
    发表于 05-01 14:39

    【小RK2206开发板试用体验】2、开箱及hello

    \lockzhiner-rk2206\images5、下载固件:6、下载成功后就可以看到串口打印了:总结:今天第一次拿开发板,对于
    发表于 05-02 14:54

    【小RK2206开发板试用体验】开发环境搭建流程——小白版

    非常感谢发烧友论坛和智电子,感谢王工等大佬的指导以下会使用图片,尽可能详细到每一步给大家演示流程(流程和图片见附件word)主要参考教程智电子/小-
    发表于 05-08 01:32

    【小RK2206开发板试用体验】第2章 源码编译与固件下载

    开发环境:开发系统:Ubuntu 20.04开发板:小-RK2206
    发表于 05-08 14:02

    【小RK2206开发板试用体验】第3章 应用开发

    开发环境:开发系统:Ubuntu 20.04开发板:小-RK2206
    发表于 05-08 14:07

    【小RK2206开发板试用体验】鸿蒙应用开发和鸿蒙线程创建

    开发系统:Ubuntu 20.04开发板:小-RK2206开发板OpenHARMony版本:
    发表于 05-25 01:32

    【小RK2206开发板试用体验】第5章 使用WiFi联网

    开发环境:开发系统:Ubuntu 20.04开发板:小-RK2206
    发表于 05-27 23:00

    【小RK2206开发板试用体验】二运行

    入手后,我申请的是人体感应套件,所以首先 查询资料docsoard硬件原理图小开发板原理图只提供底板的原理图,核心原理图可在开发板
    发表于 06-02 10:23

    【小RK2206开发板试用体验】OpenHarmony华为云IoT应用开发-智慧井盖

    本帖最后由 周安平 于 2022-6-4 10:07 编辑 【小RK2206开发板试用体验】OpenHarmony华为云IoT应用开发
    发表于 06-03 20:48

    RK2206开发板搭载OpenHarmony操作系统简介

    1、小-RK2206开发板简介小-RK2206
    发表于 07-28 17:28