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

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

3天内不再提示

以RISC-V架构的D1 Dock Pro和D1 Nezha开发板

芯片开放社区 来源:玄铁杯第二届RISC-V应用创 作者:玄铁杯第二届RIS 2022-12-19 10:20 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

本项目以RISC-V架构的D1 Dock Pro和D1 Nezha开发板为硬件平台,应用物联网区块链技术,设计开发一套分布式能源智慧管理小型示范系统,在该系统上实现能源生产和消费数据的实时监测。该项目在“玄铁杯第二届RISC-V应用创新大赛”活动中荣获一等奖。

关于分布式能源智慧管理和M2M交易系统的技术细节,请看本文详细介绍。

01项目介绍

能源和环保是关乎人类未来的重要课题。为实现碳中和目标,大力发展可再生清洁能源以替代传统化石能源,提高能源系统监控和消费的智能化水平,是可行的重要途径之一。本项目以RISC-V架构的D1 Dock Pro和D1 Nezha开发板为硬件平台,应用物联网和区块链技术,设计开发一套分布式能源智慧管理小型示范系统,在该系统上实现能源生产和消费数据的实时监测。

02技术方案

项目使用 D1 Dock Pro 开发板设计开发一款专用网关,实时采集电池控制器、气象环境传感器等其它传感器的数据,并通过无线通信方式(WiFi)以HTTP协议或MQTT协议将传感器数据上传至物联网后台。

17570832-7f43-11ed-8abf-dac502259ad0.jpg  

图1.专用网关示意

1791faaa-7f43-11ed-8abf-dac502259ad0.jpg

图2.专用网关实物图

智能开关用于能源消费端,实现对能源消费者(电器负载)的供电控制、电能消费数据的采集和传输等功能。该智能开关基于 D1 Dock Pro 开发板进行设计开发,通过开发板的I/O口控制继电器、UART接收电能计量模块的数据。设计一个扩展电路板与开发板配合使用,扩展电路板集成电能计量模块、继电器等。本文设计的智慧开关的功能主要是控制电器开关与计量电器用电参数以及环境参数并上传到云端服务器。

17c2c180-7f43-11ed-8abf-dac502259ad0.jpg

图3.智能开关示意图

17f22718-7f43-11ed-8abf-dac502259ad0.jpg

图4.智能开关实物图

03核心业务代码

3.1智能开关电能采集分析

// sensor variable
float sensor_data[9] = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9};
int recv_cmd; 
unsigned long Voltage_data, Current_data, Power_data, Energy_data, Pf_data, CO2_data, HZ;

// read the consumer date
void read_consumer_data(void)
{

//send the instruction
unioncrc_data
{
unsigned int word16;
unsigned char byte[2];
} crc_now;

tx_buffer[0] = 0x01;
tx_buffer[1] = 0x03;
tx_buffer[2] = 0x01;
tx_buffer[3] = 0x00;
tx_buffer[4] = 0x02;
tx_buffer[5] = 0x08;
crc_now.word16 = chk_crc(tx_buffer, 6);
tx_buffer[6] = crc_now.byte[1];//CRC verification
tx_buffer[7] = crc_now.byte[0];

ret = csi_uart_send_async(&g_uart, tx_buffer,8);
//wait until send finished
while(1) {
if (tx_async_flag) {
tx_async_flag = 0;
break;
}
}

printf("send succeed
");
   ret = csi_uart_receive_async(&g_uart, rx_buffer, 1);
   //wait until receieve  finished
   while(1) {
//   printf("not_receieved
");
   aos_msleep(200);
     if (rx_async_flag) {
         break;
     }
   }


  printf("Line 358: got data");
  parse_data();
  publish_sensor_data(client, "publish");
  
}

//analyze the consumer date
void parse_data(void)
{
csi_error_t ret;
unsigned char i;
union crc_data
{
unsigned int word16;
unsigned char byte[2];
} crc_now;

if (rx_async_flag == 1){ // check if receieve finished
rx_async_flag = 0;
if ((rx_buffer[0] == 0x01)) { //check the ID of the device
crc_now.word16 = chk_crc(rx_buffer, recieve_data_num - 2);//crc verification
if ((crc_now.byte[0] == rx_buffer[recieve_data_num - 1]) && (crc_now.byte[1] == rx_buffer[recieve_data_num - 2])) {
//parse voltage
Voltage_data = (((unsigned long)(rx_buffer[3])) << 24) | (((unsigned long)(rx_buffer[4])) << 16) | (((unsignedlong)(rx_buffer[5])) << 8) | rx_buffer[6];
sensor_data[0] = (float)(Voltage_data * 0.0001);

//parse current
Current_data = (((unsigned long)(rx_buffer[7])) << 24) | (((unsigned long)(rx_buffer[8])) << 16) | (((unsignedlong)(rx_buffer[9])) << 8) | rx_buffer[10];
sensor_data[1] = (float)(Current_data * 0.0001);

//parse power
Power_data = (((unsignedlong)(rx_buffer[11])) << 24) | (((unsigned long)(rx_buffer[12])) << 16) | (((unsignedlong)(rx_buffer[13])) << 8) | rx_buffer[14];
sensor_data[2] = (float)(Power_data * 0.0001);

//parse energy
Energy_data = (((unsignedlong)(rx_buffer[15])) << 24) | (((unsigned long)(rx_buffer[16])) << 16) | (((unsignedlong)(rx_buffer[17])) << 8) | rx_buffer[18];
sensor_data[3] = (float)(Energy_data * 0.0001);

//parse power factor
Pf_data = (((unsignedlong)(rx_buffer[19])) << 24) | (((unsigned long)(rx_buffer[20])) << 16) | (((unsignedlong)(rx_buffer[21])) << 8) | rx_buffer[22];
sensor_data[4] = (float)(Pf_data * 0.001);

//parse CO2
CO2_data = (((unsigned long)(rx_buffer[23])) << 24) | (((unsigned long)(rx_buffer[24])) << 16) | (((unsignedlong)(rx_buffer[25])) << 8) | rx_buffer[26];
sensor_data[5] = (float)(CO2_data * 0.0001);

//parse frequency of the Single phase alternating current
HZ = (((unsigned long)(rx_buffer[31])) << 24) | (((unsigned long)(rx_buffer[32])) << 16) | (((unsignedlong)(rx_buffer[33])) << 8) | rx_buffer[34];
sensor_data[6] = (float)(HZ * 0.01);

} else {
printf("CRC_error
");
}
}

} else {
printf("receieve_not_finished
");
  }
}
// EOF uart

3.2MQTT电能数据上云

// mqtt 
char pub_topic[] = "wattnode/data"; 
char sub_topic[] = "wattnode/cmd"; 
mqtt_client_t *client;
int is_mqtt_ready = 0;

void mqtt_do_connect(mqtt_client_t *client);
static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags);
void publish_sensor_data(mqtt_client_t *client, void *arg);

/* Called when publish is complete either with sucess or failure */
static void mqtt_pub_request_cb(void *arg, err_t result)
{
  if(result != ERR_OK) {
    printf("Publish result: %d
", result);
  }
}

/* The idea is to demultiplex topic and create some reference to be used in data callbacks
   Example here uses a global variable, better would be to use a member in arg
   If RAM and CPU budget allows it, the easiest implementation might be to just take a copy of
   the topic string and use it in mqtt_incoming_data_cb
*/
static int inpub_id;
static void mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len)
{
  printf("Incoming publish at topic %s with total length %u
", topic, (unsigned int)tot_len);

  /* Decode topic string into a user defined reference */
  if(strcmp(topic, "print_payload") == 0) {
    inpub_id = 0;
  } else if(topic[0] == 'A') {
    /* All topics starting with 'A' might bwhile(1)e handled at the same way */
    inpub_id = 1;
  } else {
    /* For all other topics */
    inpub_id = 2;
  }
}

static void mqtt_sub_request_cb(void *arg, err_t result)
{
  /* Just print the result code here for simplicity, 
     normal behaviour would be to take some action if subscribe fails like 
     notifying user, retry subscribe or disconnect from server */
    printf("Subscribe result: %d
", result);
}

static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status)
{
  err_t err;
  if(status == MQTT_CONNECT_ACCEPTED) {
    printf("mqtt_connection_cb: Successfully connected
");
    
    /* Setup callback for incoming publish requests */
    mqtt_set_inpub_callback(client, mqtt_incoming_publish_cb, mqtt_incoming_data_cb, arg);
    
    /* Subscribe to a topic named "subtopic" with QoS level 1, call mqtt_sub_request_cb with result */ 
    err = mqtt_subscribe(client, sub_topic, 1, mqtt_sub_request_cb, arg);

    if(err != ERR_OK) {
      printf("mqtt_subscribe return: %d
", err);
    }

    printf("ready to read data");

    is_mqtt_ready = 1;

  } else {
    printf("mqtt_connection_cb: Disconnected, reason: %d
", status);
    
    /* Its more nice to be connected, so try to reconnect */
    mqtt_do_connect(client);
  }  
}

static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags)
{
  printf("Incoming publish payload with length %d, flags %u
", len, (unsigned int)flags);

  if(flags & MQTT_DATA_FLAG_LAST) {
    /* Last fragment of payload received (or whole part if payload fits receive buffer
       See MQTT_VAR_HEADER_BUFFER_LEN)  */

    /* Call function or do action depending on reference, in this case inpub_id */
    if(inpub_id == 0) {
      /* Don't trust the publisher, check zero termination */
      if(data[len-1] == 0) {
        //printf("mqtt_incoming_data_cb: %s
", (const char *)data);
      }
    } else if(inpub_id == 1) {
      /* Call an 'A' function... */
    } else {
    //   printf("mqtt_incoming_data_cb: Ignoring payload...
");
        // printf("mqtt_incoming_data_cb: %s
", (const char *)data);
        recv_cmd = atoi((const char *)data);



        printf("receive data: %d
", recv_cmd);
    
    }
  } else {
    /* Handle fragmented payload, store in buffer, write to file or whatever */
  }
}

void publish_sensor_data(mqtt_client_t *client, void *arg)
{
    err_t err;
    u8_t qos = 0; /* 0 1 or 2, see MQTT specification */
    u8_t retain = 0; /* No don't retain such crappy payload... */

    const int LEN = 9;
    // cat all float data to string
    char sep = ';';
    // char *prefix = "data=";
    char *prefix = "";
    char _str_data[10];
    char post_str[128];

    strcpy(post_str, prefix);
    for (int i = 0; i < LEN-1; i++) {
        sprintf(_str_data, "%.3f", sensor_data[i]);
        _str_data[strlen(_str_data)-1] = sep;
        strcat(post_str, _str_data);
    }

    sprintf(_str_data, "%.3f", sensor_data[LEN-1]);
    strcat(post_str, _str_data);

    err = mqtt_publish(client, pub_topic, post_str, strlen(post_str), qos, retain, mqtt_pub_request_cb, arg);
    if(err != ERR_OK) {
        printf("Publish err: %d
", err);
    }
}

void mqtt_do_connect(mqtt_client_t *client)
{
    struct mqtt_connect_client_info_t ci;
    err_t err;

    ip4_addr_t ip_addr;
    IP4_ADDR(&ip_addr, 106, 14, 44, 95);

    /* Setup an empty client info structure */
    memset(&ci, 0, sizeof(ci));

    /* Minimal amount of information required is client identifier, so set it here */ 
    ci.client_id = "wattnode1";

    /* Initiate client and connect to server, if this fails immediately an error code is returned
        otherwise mqtt_connection_cb will be called with connection result after attempting 
        to establish a connection with the server. 
        For now MQTT version 3.1.1 is always used */

    err = mqtt_client_connect(client, &ip_addr, MQTT_PORT, mqtt_connection_cb, 0, &ci);

    /* For now just print the result code if something goes wrong */
    if(err != ERR_OK) {
        printf("mqtt_connect return %d
", err);
    }
}

static void mqtt_main_task(void *d)
{
    printf("Enter mqtt_main_task
");
    // mqtt_client_t *client = mqtt_client_new();
    client = mqtt_client_new();
    if(client != NULL) {
        mqtt_do_connect(client);
    }
}
// EOF mqtt

3.3智能开关

// switch variable
const int SWITCH_PIN = PC1;
static csi_gpio_pin_t pin;
#define GPIO_CHECK_RETURN(ret)           
    do {                                 
        if (ret != CSI_OK) {             
            return -1;                   
        }                                
    } while(0);

//init the switch
void switch_init()
{
  ret = csi_gpio_pin_init(&pin, SWITCH_PIN);
  GPIO_CHECK_RETURN(ret);

  /* Set output mode */
  ret = csi_gpio_pin_dir(&pin, GPIO_DIRECTION_OUTPUT);
  GPIO_CHECK_RETURN(ret);
}
// EOF switch

3.4串口处理部分

// uart variable
static csi_uart_t g_uart;
static volatile uint8_t rx_async_flag = 0;
static volatile uint8_t tx_async_flag = 0;
static uint8_t tx_buffer[140];
static uint8_t rx_buffer[140];
int recieve_data_num = 37;
#define DATE_UART_BAUDRATE   4800
#define DATE_UART_IDX 5
#define UART_CHECK_RETURN(ret)                      
        do {                                        
            if (ret != CSI_OK) {                    
                return -1;                          
            }                                       
        } while(0);

// crc function
unsigned int calc_crc(unsigned char crcbuf, unsigned int crc);
unsigned int chk_crc(unsigned char* buf, unsigned char len);

//task
static aos_task_t task_date_uart5;

void date_uart5_entry()
{
   
while(1)
{
switch(recv_cmd){
case 0:
break;
case 1:
csi_gpio_pin_write(&pin, GPIO_PIN_HIGH);
recv_cmd = 0;
break;
case 2:
csi_gpio_pin_write(&pin, GPIO_PIN_LOW);
recv_cmd = 0;
break;
case 3:
read_consumer_data();
recv_cmd = 0;
break;
default:
break;

}//eof switch

aos_msleep(2000);
    }//eof while
}//eof func

//callback function of uart
static void uart_event_cb(csi_uart_t *uart, csi_uart_event_t event, void *arg)
{
  switch (event) {
    case UART_EVENT_SEND_COMPLETE:
      tx_async_flag = 1;
      break;

    case UART_EVENT_RECEIVE_COMPLETE:
      rx_async_flag = 1;
      break;

    default:
      break;
  }//eof switch
}//eof func


void uart_init()
{
  csi_pin_set_mux(PB4, PB4_UART5_TX);
  csi_pin_set_mux(PB5, PB5_UART5_RX);

  /* init uart, DATE_UART_IDX == 5 */
  ret = csi_uart_init(&g_uart, DATE_UART_IDX);
  UART_CHECK_RETURN(ret);

  /* set uart baudrate */
  ret = csi_uart_baud(&g_uart, DATE_UART_BAUDRATE);
  UART_CHECK_RETURN(ret);

  /* set uart format */
  ret = csi_uart_format(&g_uart, UART_DATA_BITS_8, UART_PARITY_NONE, UART_STOP_BITS_1);
  UART_CHECK_RETURN(ret);

  /* attach callback to uart device */
  ret = csi_uart_attach_callback(&g_uart, uart_event_cb, NULL);
  UART_CHECK_RETURN(ret);

}



// calculate crc function
unsigned int calc_crc(unsigned char crcbuf, unsigned int crc)
{
unsigned char i;
unsigned char chk;
crc = crc ^ crcbuf; for (i = 0; i < 8; i++)
{
chk = (unsigned char)(crc & 1);
crc = crc >> 1;
crc = crc & 0x7fff;
if (chk == 1) crc = crc ^ 0xa001;
crc = crc & 0xffff;
}
return crc;
}

// verify crc function
unsigned int chk_crc(unsigned char* buf, unsigned char len)
{
unsigned char hi, lo;
unsigned int i;
unsigned int crc;
crc = 0xFFFF;
for (i = 0; i < len; i++)
{
crc = calc_crc(*buf, crc);
buf++;
}

hi = (unsigned char)(crc % 256);
lo = (unsigned char)(crc / 256);
crc = (((unsigned int)(hi)) << 8) | lo;
return crc;
}

3.5主函数

int main(void)
{
  cxx_system_init();
  board_yoc_init();

  switch_init();
  uart_init();
    
  /* Subscribe */
  event_subscribe(EVENT_NETMGR_GOT_IP, network_event, NULL);
  event_subscribe(EVENT_NETMGR_NET_DISCON, network_event, NULL);
  
  aos_task_new_ext(&task_date_uart5, "task_date_uart5", date_uart5_entry, NULL, 4096, AOS_DEFAULT_APP_PRI);
//  aos_task_new_ext(&uart5_proc, "uart5_proc", data_proc, NULL, 1024, 30);
  
  app_wifi_init();

  // while (1) {
  //   if (is_mqtt_ready == 1) {
  //   //   read_consumer_data();
  //     printf("OK");
  //     // aos_msleep(1000);
  //   }
  //   // test_uart();
    
  //   // aos_msleep(2000);
  // }
}

04问题汇总

uart的配置

在官方的GitBook中对驱动函数进行了详细地讲解并附有相关例程:文档首页· GitBook (t-head.cn)

但并未对具体的底层配置修改进行说明,在一开始编写串口部分的代码时,一直未能成功初始化并调通串口,在工程师的帮助之下对D1 dock pro的底层配置有了一定的了解。这里以led_demo为例,演示如何在此基础之上成功配置uart5。

改动1

181fac06-7f43-11ed-8abf-dac502259ad0.png

改动2

184a2e5e-7f43-11ed-8abf-dac502259ad0.png

改动3

189f4ca4-7f43-11ed-8abf-dac502259ad0.png

改动4

191571cc-7f43-11ed-8abf-dac502259ad0.png

做完以上三处改动,即可参考UART·GitBook(t-head.cn)中的使用示例对uart5进行验证,注意需要先csi_pin_set_mux(PB4,PB4_UART5_TX);和csi_pin_set_mux(PB5,PB5_UART5_RX);

05项目总结

“我们对‘碳中和’比较感兴趣,学校也鼓励我们探索交叉学科,我负责系统架构搭建和区块链技术,另外两位队员负责硬件编程及网页编程。从最初简单的能源物联网演示,到利用区块链技术实现M2M自主交易,我们做了很多讨论和尝试,终于在RISC-V平台上跑通了程序!”“萌新队”队长、华东师范大学大四学生龚丹妮说。

审核编辑 :李倩

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

    关注

    0

    文章

    110

    浏览量

    12016
  • 开发板
    +关注

    关注

    25

    文章

    6140

    浏览量

    113706
  • RISC-V
    +关注

    关注

    48

    文章

    2809

    浏览量

    51977

原文标题:应用速递 | 摘得头奖的小队究竟是做了什么项目?

文章出处:【微信号:芯片开放社区,微信公众号:芯片开放社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    探索RISC-V在机器人领域的潜力

    探索RISC-V在机器人领域的潜力 测评人:洄溯 测评时间: 2025年11月 测评对象: MUSE Pi Pro开发板(基于进迭时空K1系列高性能
    发表于 12-03 14:40

    全志D1开发板(哪吒 RISCV64)开箱评测

    1.概述 作为主打RISC-V架构芯片的国产开发板,哪吒开发板这次的发布也算是良心之作。随着第一批板子的公
    发表于 10-31 07:50

    d1哪吒开发板的启动流程分析

    1.本文概述 2.D1上电后启动的第一个程序 3.启动SPL 4.启动opensbi 5.裸机程序的编写 6.小结 1.本文概述 从RISCV生态的角度上来看,D1哪吒
    发表于 10-29 06:44

    WEMOS D1 R32 用Arduino IDE 点灯程序 及搭建

    https://v.kuaishou.com/J43p6seX D1 R32 "Arduino IDE "闪烁 该作品在快手被播放过1次,点击链接,打开【快手】直接观看!
    的头像 发表于 10-27 14:51 255次阅读

    【匠芯创D133CBS KunLun Pi开发板试用体验】1开发板开箱及介绍

    应用于工业 HMI、 网关、串口屏等泛工业和智慧家居领域。 D133CBS RISC-V KunLun Pi V1.0 是一款基于 D13x 芯片的人机交互应用
    发表于 09-05 13:49

    【BPI-CanMV-K230D-Zero开发板体验】开箱以及开发板简介

    感谢香蕉派+发烧友组织的活动。 Banana Pi BPI-CanMV-K230D-Zero 采用嘉楠科技 K230D RISC-V芯片设计,探索 RISC-V Vector1.0 的
    发表于 08-25 22:49

    Comake D1 开发板 快速开始

    本文档介绍了COMAKEPID1开发板的快速入门指南,包括硬件连接、AlkaidSDK环境搭建和示例程序开发。该开发板基于Pcupid系列SoC芯片,支持丰富的外设功能,适用于智能音频
    的头像 发表于 08-25 15:49 578次阅读
    Comake <b class='flag-5'>D1</b> <b class='flag-5'>开发板</b> 快速开始

    Comake PI D1开箱使用体验分享

    一颗针对智慧视觉、智慧音频、智能机器人、小屏显示等应用的AI主控芯片SSD2355,并搭配该芯片重磅推出了Comake PI D1开发板,结合Comake 开发者社区的高效在线服务及AI 模型资源
    发表于 08-21 15:37

    匠芯创D133CBS RISC-V KunLun Pi V1.0开发板开发资料

    开发板简介 D13x 是 ArtInChip 一款基于 RISC-V 的高性能、国产自主、工业级全高清显示与智能控制 MCU,配备强大的 2D 图形加速处理器、 PNG 解码、JPEG
    发表于 07-15 17:27

    搭载双核玄铁C908  RISC-V CPU,BPI-CanMV-K230D-Zero开发板试用

    K230D Zero  开发板。这款创新的开发板是由嘉楠科技与香蕉派开源社区联合设计研发,搭载了先进的勘智 K230D 芯片。 K230D
    的头像 发表于 06-05 16:49 1305次阅读
    搭载双核玄铁C908  <b class='flag-5'>RISC-V</b> CPU,BPI-CanMV-K230<b class='flag-5'>D</b>-Zero<b class='flag-5'>开发板</b>试用

    【免费试用】开发板评测大赛开启!OH 、RISC-V、Rockchip顶级开发板等你试用~

    道OpenHarmony、RISC-V、Rockchip(下称RK)全面覆盖前沿技术方向,等你用代码与创意点燃科技未来!——点击开发板图片立即申请————点击开发板图片立即申请———
    的头像 发表于 06-05 08:05 770次阅读
    【免费试用】<b class='flag-5'>开发板</b>评测大赛开启!OH 、<b class='flag-5'>RISC-V</b>、Rockchip顶级<b class='flag-5'>开发板</b>等你试用~

    关税取消后,国产的这款RISC-V开发板能否称霸市场?进迭时空Muse Pi Pro开发板

    在电子科技领域,一款国产开发板近期悄然崭露头角,吸引了全球的目光。它就是由国产 RISC-V 芯片设计公司进迭时空推出的 Muse Pi Pro 开发板。在当今处理器设计领域,ARM
    的头像 发表于 05-20 09:49 889次阅读
    关税取消后,国产的这款<b class='flag-5'>RISC-V</b><b class='flag-5'>开发板</b>能否称霸市场?进迭时空Muse Pi <b class='flag-5'>Pro</b><b class='flag-5'>开发板</b>

    请问TVP5158分辨率D1与HalfD1是如何转换的?

    这段时间在调试TVP5158模拟视频采集芯片,发现输出数据有三种分辨率D1、HalfD1和CIF,手册上面只是说明了D1、HalfD1和CIF三者的水平像素点和垂直行数的关系,但是这
    发表于 12-23 06:31

    RISC-V架构及MRS开发环境回顾

    ,华为海思转向了开源指令集架构RISC-V,针对鸿蒙操作系统的开发者发布了首款RISC-V开发板Hi3861。Hi3861针对的是物联网市场
    发表于 12-16 23:08

    SiFive 推出高性能 Risc-V CPU 开发板 HiFive Premier P550

    “  HiFive Premier P550:世界上性能最高的 RISC-V CPU 开发板 Mini-DTX 外形提供高性能 Linux 开发平台,支持下一波
    的头像 发表于 12-16 11:16 2699次阅读
    SiFive 推出高性能 <b class='flag-5'>Risc-V</b> CPU <b class='flag-5'>开发板</b> HiFive Premier P550