HPM6750

1、背 景

在我的某个项目中由于希望把板子做的小一点,所以选择了 BGA196 封装的 HPM6750IAN2 芯片,在画板子的过程中,注意到相比 BGA289 封装的 HPM6750IVM2 芯片,其并没有引出 XPI0 CA 端口的引脚,如下图所示。所以最后选择了 XPI0 的 CB 端口用于连接 NOR Flash。

1.png

部分引脚复用功能(来源:HPM6750数据手册)

2.png

XPI 部分原理图

2、问 题

在 HPM6750EVKMINI 评估板中使用了 XPI0 CA 端口作为连接串行 NOR Flash 的引脚(芯片的默认配置),在芯片上电启动的过程中,芯片内部的 BootROM 会根据 OTP 配置初始化 XPI 控制器,从 Flash 0x400 的地址读取 XPI NOR 配置选项,并按照读取的配置选项将 XPI 配置为指定的工作模式,然后重新检测 Flash 是否存在,从 Flash 中加载镜像完成剩余启动步骤。

3.png

因此为了实现从 XPI0 CB 端口启动,我们需要修改 OTP 中的对应字段和启动镜像中的 XPI NOR 配置选项。

3、OTP 烧写

通过查阅 HPM6750 的参考手册,发现控制 BootROM 启动时指定 Flash 连接方式的为以下几个字段:

4.png

5.png

因此在本例中,需要仅需修改 XPI_PORT_SEL 字段为 1,让 BootROM 从 CB_CS0 端口启动即可。

将 BOOT 拨码开关调至 BOOT_MODE[1:0]=0b10,以 ISP 模式启动,将 USB0 连接至 PC,然后打开 HPMicro 量产工具,选择对应的 USB 设备点击 连接,连接成功后如下图所示。

6.png

注意:
OTP 操作需谨慎!!!
OTP 操作需谨慎!!!
OTP 操作需谨慎!!!
在 OTP 操作 ⻚⾯中,点击 刷新 读取当前芯⽚中 OTP 的数据,看到 Word 24 的值为 0x00000000 ,也就是从 XPI0 CA 端⼝的第⼀组引脚启动。

7.png

切换至 写视图,点击 添加 Words,在弹出的对话框中按照下图输入,即:将 Word 24 的 bit 6 置 1,从 CB_CS0 端口启动。点击确定后,再次确认数据是否有误,确认无误后点击 写入。

8.png

写入完成后切换回 写视图,点击 刷新,可以看到 Word 24 已经变为期望值。

9.png

将拨码开关拨回 XPI NOR 启动后复位芯片,可使用逻辑分析仪观察 XPI0_CB_SCLK 引脚在上电时的电平,如可以观察到对应的时钟信号,证明 OTP 设置已经生效。

4、修改 XPI NOR 配置选项

在 BootROM 检测到 Flash 后,会从 0x400 读取 XPI NOR 配置选项重新配置 XPI,为了确保 XPI 重新配置后仍能检测到 Flash,需要对默认配置进行修改。根据参考手册,配置选项的定义如下:

10.png

11.png

12.png

当我们使用 CMake 配置项目,并设置 CMAKE_BUILD_TYPE为 flash_xip 时,生成的 SES(Segger Embedded Studio)工程会使用 flash_xip.icf 链接脚本,以将各个 section 链接至 Flash 中。可以在如下菜单中打开链接脚本。

13.png

在 flash_xip.icf中,可以看到在 XPI0 的基地址偏移 0x400 处定义了存放 NOR_CFG_OPTION 的区域,对应的 section 为 .nor_cfg_option。

14.png

15.png

使用快捷键 Ctrl+Shift+F 全局搜索 .nor_cfg_option,可以在 board.c 中找到对应的配置选项。

16.png

为了避免修改 SDK 中的文件,我选择在项目文件夹下新建一个 board文件夹,并复制 hpm6750evkmini 的板级文件,重新命名为 myboard,此时项目结构如下:

├── src/

│   ├── board/

│   │   └── myboard/

│   │       ├── CMakeLists.txt

│   │       ├── board.c

│   │       ├── board.h

│   │       ├── myboard.yaml

│   │       ├── pinmux.c

│   │       └── pinmux.h

│   └── app.c

└── CMakeLists.txt

在 CMake 初始化时使用 BOARD_SEARCH_PATH 将 board 文件夹添加至搜索路径中(需使用 SDK 1.2.0): 

cmake -Bbuild -DBOARD=myboard -DBOARD_SEARCH_PATH=./src/board -GNinja -DCMAKE_BUILD_TY
PE=flash_xip

使用 SES 打开工程,可以看到 board.c 被添加到项目中。

17.png

同样的,在 XPI 配置选项中也要使用 XPI0 CB_CS0 端口,所以需要将 Header[3:0] 改为 2,Option[11:8] 改为 1。即:

__attribute__ ((section(".nor_cfg_option"))) const uint32_t option[4] = {0xfcf90002, 0
x00000007, 0x00000100, 0x0};

修改完成后重新进行编译,得到生成的 .bin文件。

5、烧 录

使用 HPMicro Programmer 进行烧录前,需要将 Connection Selection改为 CB_CS0,同时为了确保后续 Flash 能切换至四线模式(Quad SPI),还需要根据使用的 Flash 设置 Quad Enable Sequence,借助 BootROM 将 Flash 的 QE 标志位置位。这里我使用的是 GD25Q40C 系列 Flash,查阅 datasheet 可知 QE 位于 Status Register 2 的 bit1,因此这里我选择 At bit1 in Status Register2。由于 QE 是 非易失 的,掉电后数据不会丢失,因此我们仅需在烧录时设置一次,在 XPI NOR 配置选项中可以不用设置 Quad Enable Sequence 字段。

18.png

19.pngStatus Register 中的 QE 位

20.png

选择编译生成的.bin 文件后,程序会自动设置烧写地址,随后点击烧录。烧录成功后恢复启动模式拨码开关,然后复位芯片,正常情况下程序就会运行了。

21.png

来源:先楫半导体HPMicro

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 69

随着物联网的蓬勃发展,数字化和智能化逐渐渗透到工业领域,从而促进了人类、机器、产品和系统之间的更紧密协作。智能物联系统使得物理世界和数字世界紧密结合,为制造流程带来了更高效、更可靠和更具成本优势的变革,开启了工业4.0时代的大门。

先楫半导体的高性能MCU芯片系列产品具备卓越的扩展性、优质的品质和可靠性,满足了工业领域各类应用的需求,加速了工业4.0的进程,并推动了国产芯片的发展。在这一趋势下,好上好与先楫半导体携手推出了基于HPM6750的工业核心板模组,为工业领域的应用客户提供更快速的解决方案实施。这一模组的推出将有助于工业领域应用的客户朋友们更加迅速地实现他们的方案。

1.png

HPM6750

HPM6750核心板集成了电源管理、SDRAM、Flash等多种器件,并支持RGB屏显。其通讯接口包括Ethernet、CAN-FD、UART、I2C、SPI等多种接口。该核心板采用了6层板PCB工艺和LGA封装,有效降低了用户对PCB布局的要求。而紧凑的42x33mm尺寸,可以满足各种小尺寸PCB的需求。

产品性能

  • 高达 816MHZ的运行主频

  • 集成32MB SDRAM和16MB QSPI Flash

  • 支持多种文件系统操作 SD/SDHC/SDXC/TF 卡、U 盘读写

  • 支持 2路 10/100Mbps 以太网接口,且其中1路可支持1000Mbps

  • 支持 2 路集成PHY的高速USB

  • 支持 RGB 屏接口,支持高达1366x768 60 fps 的显示需求

  • 支持 1 路 DVP8bit 并行摄像头接入

  • 支持 4xCAN FD,17路UART,4路SPI和4路I2C

  • 支持 UART、SPI、I2C、16bit-ADC 等通用接口

  • 支持 2xDMIC、1xAMIC语音检测

  • 支持 4x8 通道互补 PWM,4路正交编码接口

  • 支持16bit ADC采样,4组模拟比较器

  • 集成高效率 DCDC 转换器和 LDO,支持5V或3.3V单电源供电

应用领域

2.jpg

来源:先楫半导体HPMicro

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 32

简介

本文主要介绍了HPM6750的控制器局域网CAN(以下简称CAN控制器)的概述以及基于HPM-SDK CAN控制器的开发指导(包括实现CAN2.0、CAN-FD)。

CAN控制器

1. 概述

CAN 是 Controller Area Network 的缩写(以下称为 CAN),是 ISO 国际标准化的串行通信协议。HPM6750 MCU搭载了4路CAN控制器,CAN0/CAN1/CAN2/CAN3,它们具有如下特性:

● 支持 CAN 2.0B 协议,支持多达 8 字节的数据载荷, 数据速率可达 1Mbit/s;

● 支持 CAN FD 协议,支持多达 64 字节的数据载荷, 数据速率可达 2.5Mbit/s;

● 支持 1 ∼ 1/256 的波特率预分频,灵活配置波特率;

● 16 个接收缓冲器;

– FIFO 方式;

– 错误或者不被接收的数据不会覆盖存储的消息;

● 1 个高优先主发送缓冲器 PTB;

● 8 个副发送缓冲器 STB;

– FIFO 方式;

– 优先级仲裁方式;

● 16 组独立的筛选器;

– 支持 11 位标准 ID 和 29 位扩展 ID;

– 可编程 ID CODE 位以及 MASK 位;

● PTB/STB 均支持支持单次发送模式;

● 支持静默模式;

● 支持回环模式;

● 支持待机模式;

● 支持捕捉传输的错误种类以及定位仲裁失败位置;

● 可编程的错误警告值;

● 支持 ISO11898-4 规定时间触发 CAN 以及接收时间戳可配置停止位:1位,1.5位或者2位。

2. 系统框图

1.png

3. 管脚

2.png

CAN控制器功能开发指引

1. API功能描述

CAN开发主要使用以下接口:

//获取CAN默认配置
hpm_stat_t can_get_default_config(can_config_t *config);
//CAN 初始化接口
hpm_stat_t can_init(CAN_Type *base, can_config_t *config, uint32_t src_clk_freq);
//接收过滤器配置
hpm_stat_t can_set_filter(CAN_Type *base, const can_filter_config_t *config);
//CAN 数据发送接口(阻塞模式)
hpm_stat_t can_send_message_blocking(CAN_Type *base, const can_transmit_buf_t *message);
//CAN高优先级数据发送接口(PTB 阻塞模式)
hpm_stat_t can_send_high_priority_message_blocking(CAN_Type *base, const can_transmit_buf_t *message);
//CAN 数据接收接口(阻塞模式)
hpm_stat_t can_receive_message_blocking(CAN_Type *base, can_receive_buf_t *message);
//CAN 数据接收接口(非租塞模式)
hpm_stat_t can_read_received_message(CAN_Type *base, can_receive_buf_t *message);
//设置发送补偿及使能(CAN-FD高速率使用,TDC)
void can_set_transmitter_delay_compensation(CAN_Type *base, uint8_t sample_point, bool enable);

2. API数据结构

2.1 CAN配置

typedef struct{    
  union{        
    struct {           
      //当禁用use_lowlevel_timing_setting时,以下参数有效。            
      uint32_t baudrate;  //CAN 2.0波特率设定            
      uint32_t baudrate_fd; // CAN-FD波特率设定,当enable_canfd使能才有效                       
      uint16_t can20_samplepoint_min; //CAN 2.0最小采样点(0~1000)                       
      uint16_t can20_samplepoint_max; //CAN 2.0最大采样点(0~1000)            
      uint16_t canfd_samplepoint_min; //CAN-FD 最小采样点(0~1000)            
      uint16_t canfd_samplepoint_max; //CAN-FD 最大采样点(0~1000)        
    };        
    struct {
      //当启用use_lowlevel_timing_setting时,以下参数有效。            
      can_bit_timing_param_t can_timing;  //CAN2.0 位时间参数            
      can_bit_timing_param_t canfd_timing; //CAN-FD 位时间参数        
    };    
  };
can_loopback_mode_t loopback_mode;    //CAN回环模式,默认是正常模式
bool use_lowlevel_timing_setting;     //是否启用位时间参数设定     
bool enable_canfd;   //是否启用CAN-FD     
bool enable_self_ack;   //是否启用自ACK帧
bool disable_re_transmission_for_ptb;  //是否禁用高优先级PTB发送重传, false:单发模式 true:重传模式
bool disable_re_transmission_for_stb;  //是否禁用STP发送重传, false:单发模式, true:重传模式
uint16_t filter_list_num;   //接受过滤器list总数
can_filter_config_t *filter_list;  //接受过滤器list指针
} can_config_t;

2.2 CAN过滤配置

/** 
    * @brief CAN acceptance filter modes 
    */
typedef enum _can_filter_mode {    
    can_filter_mode_both_frames,                //标准格式和扩展格式过滤选模式
    can_filter_mode_standard_frames,            //标准格式过滤模式
    can_filter_mode_extended_frames,            //扩展格式过滤模式
} can_filter_mode_t;

/** 
    * @brief CAN acceptance configuration 
*/
typedef struct {
    uint16_t index;                             //过滤器index
    can_filter_mode_t mode;                 //过滤器模式     
    bool enable;                               //过滤器是否使能     
    uint32_t code;                              //ID code     
    uint32_t mask;                              //ID mask
} can_filter_config_t;

2.3 CAN发送

/** 
    * @brief CAN transmit buffer data structure 
*/
typedef union _can_tx_buf {
uint32_t buffer[18];    //发送 buffer,由于是联合体,和下面的共享一块内存区域,buffer大小:4*18=72
struct {        
        struct {            
                uint32_t id: 29;                      //CAN ID            
                uint32_t : 1;            
                uint32_t transmit_timestamp_enable: 1;  //时间戳使能        
         };        
         struct {            
                 uint32_t dlc: 4;                        //数据长度            
                 uint32_t bitrate_switch: 1;             //bitrate开关            
                 uint32_t canfd_frame: 1;                //can-fd标识位            
                 uint32_t remote_frame: 1;               //remote 标识位            
                 uint32_t extend_id: 1;                  //扩展ID            
                 uint32_t : 24;        
          };        
          uint8_t data[];                             //数据指针    
     };
} can_transmit_buf_t;

2.4 CAN接收

/** 
    * @brief CAN receive buffer data structure 
    */
    typedef union _can_rx_buf {    
        uint32_t buffer[20];           //接收buffer,由于是联合体,和下面的数据共享一块内存区域    
        struct {        
            struct {            
                uint32_t id: 29;        //can id            
                uint32_t : 1;            
                uint32_t error_state_indicator: 1;  //错误状态指示        
            };        
            struct {            
                uint32_t dlc: 4;                   //数据长度            
                uint32_t bitrate_switch: 1;        //bitrate开关            
                uint32_t canfd_frame: 1;           //canfd 标识            
                uint32_t remote_frame: 1;          //remote标识            
                uint32_t extend_id: 1;             //扩展ID            
                uint32_t : 4;            
                uint32_t loopback_message: 1;      //回环数据标识            
                uint32_t error_type: 3;            //错误类型            
                uint32_t cycle_time: 16;           //cycle time        
            };        
            uint8_t data[];                        //数据指针    
        };
} can_receive_buf_t;

3. 配置流程

CAN控制器的CAN2.0和CAN-FD配置流程如下图。

3.png

4. 样例

4.1 内部回环样例

需求:

1.CAN-FD协议

2.波特率2.5Mbps

3.内部回环模式

4.数据载荷64字节

5.遍历can-id从0~2047(11位标准ID)

6.每帧数据确保不同

7.阻塞发送、非阻塞接收(非中断模式)

8.对比接收和发送的数据包是否相等,并输出结果

void board_can_loopback_test(void)
{    
    bool result;    
    uint32_t error_cnt = 0;    
    uint32_t can_src_clk_freq;    
    can_config_t can_config;    
    board_init_can(BOARD_APP_CAN_BASE);    
    can_src_clk_freq = board_init_can_clock(BOARD_APP_CAN_BASE);    
    can_config.baudrate = 1000000; /* 1Mbps */    
    can_config.baudrate_fd = 2500000; /*5Mbps*/    
    can_config.loopback_mode = can_loopback_internal; //内部回环    
    can_config.enable_canfd = true;    
    hpm_stat_t status = can_init(BOARD_APP_CAN_BASE, &can_config, can_src_clk_freq);    
    if (status != status_success) {        
        printf("CAN initialization failed, error code: %d\n", status);        
        return;    
    }    
    can_transmit_buf_t tx_buf;    
    can_receive_buf_t rx_buf;    
    memset(&tx_buf, 0, sizeof(tx_buf));    
    memset(&rx_buf, 0, sizeof(rx_buf));    
    tx_buf.dlc = can_payload_size_64;    
    tx_buf.canfd_frame = 1;    
    tx_buf.bitrate_switch = 1;    
    for (uint32_t i = 0; i < 2048; i++) {        
        tx_buf.id = i;        
        for (uint32_t j = 0; j < 64u; j++) {            
            tx_buf.data[j] = (uint8_t)i + j + 1;        
        }        
        can_send_message_blocking(BOARD_APP_CAN_BASE, &tx_buf);        
        can_read_received_message(BOARD_APP_CAN_BASE, &rx_buf);        
        result = can_buf_compare(&tx_buf, &rx_buf);        
        if (!result) {            
            error_cnt++;            
            can_set_transmitter_delay_compensation(BOARD_APP_CAN_BASE, 64, true);            
            hpm_stat_t status = can_init(BOARD_APP_CAN_BASE, &can_config, can_src_clk_freq);            
            if (status != status_success) {                
                printf("CAN initialization failed, error code: %d\n", status);                
                return;            
            }            
            printf("ID=%08x, result:%s\n", rx_buf.id, result ? "passed": "failed");        
        }    
    }    
    printf("    CAN loopback test for extend frame %s, error_cnt:%d\n", error_cnt == 0 ? "passed" : "failed", error_cnt);
}

4.2 两路闭环收发样例

需求:

1.CAN2.0协议

2.波特率1000000,1Mbps

3.CAN0发送,CAN1接收

4.数据载荷8字节

5.CAN0阻塞发送,CAN1阻塞接收

6.对比CAN0发送包和CAN1接收包是否相同,并输出结果

7.压测100次,输出最终结果

void can0_can1_rxrx_loop_test(void)
{    
    pm_stat_t status;    
    can_config_t can_config;    
    bool use_canfd = false;    
    can_get_default_config(&can_config);    
    can_config.baudrate = 1000000; /* 1Mbps */    
    can_config.baudrate_fd = 5000000; /* 2Mbps */    
    can_config.enable_canfd = use_canfd;    
    board_init_can(HPM_CAN0);    
    board_init_can(HPM_CAN1);    
    uint32_t can_src_clk_freq0 = board_init_can_clock(HPM_CAN0);    
    uint32_t can_src_clk_freq1 = board_init_can_clock(HPM_CAN1);    
    hpm_stat_t status0 = can_init(HPM_CAN0, &can_config, can_src_clk_freq0);    
    if (status0 != status_success) {        
        printf("CAN initialization failed, error code: %d\n", status0);        
        return;    
    }    
    hpm_stat_t status1 = can_init(HPM_CAN1, &can_config, can_src_clk_freq1);    
    if (status1 != status_success) {        
        printf("CAN initialization failed, error code: %d\n", status1);        
        return;    
    }    
    printf("CMD_STA_CMD_CTRL(0xA0)= %08x\n", HPM_CAN0->CMD_STA_CMD_CTRL);    
    printf("F_PRESC               = %08x\n", HPM_CAN0->F_PRESC);    
    printf("S_PRESC               = %08x\n", HPM_CAN0->S_PRESC);    
    printf("TDC                   = %08x\n", HPM_CAN0->TDC);    
    uint32_t error_cnt = 0;    bool result = false;    can_transmit_buf_t tx_buf;    
    can_receive_buf_t rx_buf; memset(&tx_buf, 0, sizeof(tx_buf));    
    memset(&rx_buf, 0, sizeof(rx_buf));    
    tx_buf.id = 0x101;    uint32_t id_max;    
    if (!use_canfd) {        
        tx_buf.dlc = can_payload_size_8;        
        id_max = 8;    
    } else {        
        tx_buf.dlc = can_payload_size_8;        
        id_max = 64;        
        tx_buf.canfd_frame = 1;        
        tx_buf.bitrate_switch = 1;    
    }    
    for(int index = 0; index < 100; index++)    
    {            
        for (uint32_t i = 0; i < id_max; i++){            
            tx_buf.data[i] = (uint8_t)(index+i);        
        }        
        can_send_high_priority_message_blocking(HPM_CAN0, &tx_buf);        
        can_receive_message_blocking(HPM_CAN1, &rx_buf);        
        result = can_buf_compare(&tx_buf, &rx_buf);        
        if (!result) {            
            error_cnt++;            
            printf("    CAN0->CAN1 for standard frame %s\n", result ? "passed" : "failed");        
        }        
        can_receive_message_blocking(HPM_CAN0, &rx_buf);        
        result = can_buf_compare(&tx_buf, &rx_buf);        
        if (!result) {            
            error_cnt++;            
            printf("    CAN1->CAN0 for standard frame %s\n", result ? "passed" : "failed");        
        }    
    }    
    printf("    CAN can0 can1 rxrx loop test for result: %s, error_cnt:%d\n", error_cnt == 0 ? "passed" : "failed", error_cnt);
}

4.3 四路收发样例

需求:

1.CAN-FD协议

2.波特率2.5Mbps

3.数据载荷64字节

4.启用中断接收

5.CAN0/CAN1/CAN2/CAN3顺序发送数据

6.确保CAN0/CAN1/CAN2/CAN3 can-id不同

7.确保每次发送的数据包内容不同

8.分别对比每次一路CAN发送数据包和其它三路CAN接收的数据包是否相同,并输出结果

9.压测100次,并输出结果

static can_info_t s_can_info[] = {        
    { .can_base = HPM_CAN0 },        
    { .can_base = HPM_CAN1 },
#if defined(HPM_CAN2)        
    { .can_base = HPM_CAN2 },
#endif
#if defined (HPM_CAN3)        
    { .can_base = HPM_CAN3 },
#endif
};
volatile static bool has_new_rcv_msg_array[4];
volatile static can_receive_buf_t s_can_rx_buf_array[4];
SDK_DECLARE_EXT_ISR_M(IRQn_CAN0, board_can_isr0);
SDK_DECLARE_EXT_ISR_M(IRQn_CAN1, board_can_isr1);
SDK_DECLARE_EXT_ISR_M(IRQn_CAN2, board_can_isr2);
SDK_DECLARE_EXT_ISR_M(IRQn_CAN3, board_can_isr3);
void board_can_isr0(void)
{    
    uint8_t flags = can_get_tx_rx_flags(HPM_CAN0);    
    if ((flags & CAN_EVENT_RECEIVE) != 0) {        
        can_read_received_message(HPM_CAN0, (can_receive_buf_t *)&s_can_rx_buf_array[0]);        
        has_new_rcv_msg_array[0] = true;    
    }    
    can_clear_tx_rx_flags(HPM_CAN0, flags);
}
void board_can_isr1(void){    
    uint8_t flags = can_get_tx_rx_flags(HPM_CAN1);    
    if ((flags & CAN_EVENT_RECEIVE) != 0) {        
        can_read_received_message(HPM_CAN1, (can_receive_buf_t *)&s_can_rx_buf_array[1]);        
        has_new_rcv_msg_array[1] = true;    
    }    
    can_clear_tx_rx_flags(HPM_CAN1, flags);
}
void board_can_isr2(void)
{    
    uint8_t flags = can_get_tx_rx_flags(HPM_CAN2);    
    if ((flags & CAN_EVENT_RECEIVE) != 0) {        
        can_read_received_message(HPM_CAN2, (can_receive_buf_t *)&s_can_rx_buf_array[2]);        
        has_new_rcv_msg_array[2] = true;    
    }    
    can_clear_tx_rx_flags(HPM_CAN2, flags);
}
void board_can_isr3(void)
{    
    uint8_t flags = can_get_tx_rx_flags(HPM_CAN3);    
    if ((flags & CAN_EVENT_RECEIVE) != 0) {        
        can_read_received_message(HPM_CAN3, (can_receive_buf_t *)&s_can_rx_buf_array[3]);        
        has_new_rcv_msg_array[3] = true;    
    }    
    can_clear_tx_rx_flags(HPM_CAN3, flags);
}
void board_can0_1_2_3_txrx_loop_test(void){    
    hpm_stat_t status;    
    can_config_t can_config;    
    bool use_canfd = true;    
    can_get_default_config(&can_config);    
    can_config.baudrate = 1000000; /* 1Mbps */    
    can_config.baudrate_fd = 2500000; /* 5Mbps */    
    can_config.enable_canfd = use_canfd;    
    /* Initialize CAN */    
    for (uint32_t i=0; i < ARRAY_SIZE(s_can_info); i++) {        
        can_info_t  *info = &s_can_info[i];        
        board_init_can(info->can_base);        
        info->clock_freq = board_init_can_clock(info->can_base);        
        status = can_init(info->can_base, &can_config,  info->clock_freq);        
        if (status != status_success) {            
            printf("CAN %d initialization failed, error code: %d\n", i, status);            
            return;        
        }        
        printf("CMD_STA_CMD_CTRL(0xA0)= %08x\n", info->can_base->CMD_STA_CMD_CTRL);        
        printf("F_PRESC               = %08x\n", info->can_base->F_PRESC);        
        printf("S_PRESC               = %08x\n", info->can_base->S_PRESC);        
        printf("TDC                   = %08x\n", info->can_base->TDC);        
        can_enable_tx_rx_irq(info->can_base, CAN_EVENT_RECEIVE);    
    }    
    intc_m_enable_irq_with_priority(IRQn_CAN0, 1);    
    intc_m_enable_irq_with_priority(IRQn_CAN1, 1);    
    intc_m_enable_irq_with_priority(IRQn_CAN2, 1);    
    intc_m_enable_irq_with_priority(IRQn_CAN3, 1);

  
  uint32_t error_cnt = 0;    
  bool result = false;    
  can_transmit_buf_t tx_buf[4];    
  uint32_t data_max;    
  memset(tx_buf, 0, sizeof(tx_buf));    
  for(int i = 0; i < 4; i ++)    
  {        
      tx_buf[i].id = i+1;        
      if (!use_canfd) {            
          tx_buf[i].dlc = can_payload_size_8;            
          data_max = 8;        
      } else {            
          tx_buf[i].canfd_frame = 1;            
          tx_buf[i].bitrate_switch = 1;            
          tx_buf[i].dlc = can_payload_size_64;            
          data_max = 64;        
      }    
  }    
      for(int index = 0; index < 100; index++)    
      {        
          for(uint32_t can_i = 0; can_i < 4; can_i++)        
          {            
              for (uint32_t i = 0; i < data_max; i++) {                
                  tx_buf[can_i].data[i] = (uint8_t)(index+can_i+i);            
              }        
          }        
          for(uint32_t can_i = 0; can_i < 4; can_i++)        
          {            
              can_send_high_priority_message_blocking(s_can_info[can_i].can_base, &tx_buf[can_i]);            
              for(int j= 1; j < 4; j++)            
              {                
                  printf("recv canid:%d\n", (can_i+j)%4);                
                  while(!has_new_rcv_msg_array[(can_i+j)%4])                
                  {                
                  }                
                  has_new_rcv_msg_array[(can_i+j)%4] = false;                
                  result = can_buf_compare(&tx_buf[can_i], &s_can_rx_buf_array[(can_i+j)%4]);                
                  if (!result) {                    
                      error_cnt++;                
                  }                
                  printf("  CAN%d->CAN%d for standard frame %s\n", can_i, (can_i+j)%4, result ? "passed" : "failed");            
              }        
          }    
      }    
      printf("    CAN can0 can1 rxrx loop test for result: %s, error_cnt:%d\n", error_cnt == 0 ? "passed" : "failed", error_cnt);
}

划重点

使用HPM6750的CAN控制器,可以轻松实现4路CAN2.0/CAN-FD同时收发数据,易于实现CAN网络隔离以及网络中继的复杂需求,实现了工业网关的功能。

来源:先楫芯上人

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 68

本文摘自先楫开发者@xiashuang 的测评内容,分享了 先楫HPM6750 如何赋能 ADS1263 实现32位高精度数据采集及处理 ,来看看吧!

---------------  以下为测评内容 ---------------

(本期测评开发板为 HPM6750EVK)

据官方用户手册, TI 的32位ADC:ADS1263 性能很强,最高采样到38.4k(26us),需要的处理器性能必须要具有很强的运算功能,正好试下HPM6750,于是画了一块PCB板,经过一周的等待终于到了,焊接了必要的元件就开干!

1.jpg

2.jpg 

为了先验证板子的情况,先用软件模拟 SPI 进行实验,需要 7 根信号线进行连接通讯,定义的GPIO如下:

*RST---------PE25
*DRDY--------PE26
*MISO--------SPI2.MISO  PB25
*MOSI--------SPI2.MOSI  PB22
*SCK---------SPI2.SCK   PB21
*CS----------PF1
*START-------PF4

先初始化IO口,时钟的开启已经在board_init()中完成,所以指示配置一下寄存器就行

/*设置IO口为通用IO*/  
HPM_IOC->PAD[IOC_PAD_PE25].FUNC_CTL = IOC_PE25_FUNC_CTL_GPIO_E_25;     
HPM_IOC->PAD[IOC_PAD_PE26].FUNC_CTL = IOC_PE26_FUNC_CTL_GPIO_E_26;    
HPM_IOC->PAD[IOC_PAD_PB25].FUNC_CTL = IOC_PB25_FUNC_CTL_GPIO_B_25;    
HPM_IOC->PAD[IOC_PAD_PB22].FUNC_CTL = IOC_PB22_FUNC_CTL_GPIO_B_22;    
HPM_IOC->PAD[IOC_PAD_PB21].FUNC_CTL = IOC_PB21_FUNC_CTL_GPIO_B_21;    
HPM_IOC->PAD[IOC_PAD_PF01].FUNC_CTL = IOC_PF01_FUNC_CTL_GPIO_F_01;    
HPM_IOC->PAD[IOC_PAD_PF04].FUNC_CTL = IOC_PF04_FUNC_CTL_GPIO_F_04;
/*配置输入输出*/    
    /*ps-上下拉电阻 PE-上下拉开关 SMT-施密特 DS-驱动强度 OD-开漏  MS-电压选择*/    
    uint32_t pad_ctl_out = IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1);    
    uint32_t pad_ctl_in = IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1)|IOC_PAD_PAD_CTL_SMT_SET(1);    
    gpio_set_pin_output_with_initial(HPM_GPIO0, GPIO_DO_GPIOE, 25, 1);    
    gpio_set_pin_output_with_initial(HPM_GPIO0, GPIO_DO_GPIOB, 22, 1);    
    gpio_set_pin_output_with_initial(HPM_GPIO0, GPIO_DO_GPIOB, 21, 1);    
    gpio_set_pin_output_with_initial(HPM_GPIO0, GPIO_DO_GPIOF, 01, 1);    
    gpio_set_pin_output_with_initial(HPM_GPIO0, GPIO_DO_GPIOF, 04, 1);    
    HPM_IOC->PAD[IOC_PAD_PE25].PAD_CTL = pad_ctl_out;    
    HPM_IOC->PAD[IOC_PAD_PB22].PAD_CTL = pad_ctl_out;    
    HPM_IOC->PAD[IOC_PAD_PB21].PAD_CTL = pad_ctl_out;    
    HPM_IOC->PAD[IOC_PAD_PF01].PAD_CTL = pad_ctl_out;    
    HPM_IOC->PAD[IOC_PAD_PF04].PAD_CTL = pad_ctl_out;
    
     HPM_IOC->PAD[IOC_PAD_PE26].PAD_CTL = pad_ctl_in;    
     HPM_IOC->PAD[IOC_PAD_PB25].PAD_CTL = pad_ctl_in;

 相应的IO输出及输入读取如下:

#define ADS1263_RESET_H gpio_write_pin(HPM_GPIO0, GPIO_DO_GPIOE, 25, 1)
#define ADS1263_RESET_L gpio_write_pin(HPM_GPIO0, GPIO_DO_GPIOE, 25, 0)
#define ADS1263_START_H gpio_write_pin(HPM_GPIO0, GPIO_DO_GPIOF, 4, 1)
#define ADS1263_START_L gpio_write_pin(HPM_GPIO0, GPIO_DO_GPIOF, 4, 0)
#define ADS1263_CS_H    gpio_write_pin(HPM_GPIO0, GPIO_DO_GPIOF, 1, 1)
#define ADS1263_CS_L    gpio_write_pin(HPM_GPIO0, GPIO_DO_GPIOF, 1, 0)
#define ADS1263_SCLK_H  gpio_write_pin(HPM_GPIO0, GPIO_DO_GPIOB, 21, 1)
#define ADS1263_SCLK_L  gpio_write_pin(HPM_GPIO0, GPIO_DO_GPIOB, 21, 0)
#define ADS1263_DIN_H   gpio_write_pin(HPM_GPIO0, GPIO_DO_GPIOB, 22, 1)
#define ADS1263_DIN_L   gpio_write_pin(HPM_GPIO0, GPIO_DO_GPIOB, 22, 0)
#define ADS1263_DOUT    gpio_read_pin(HPM_GPIO0, GPIO_DI_GPIOB, 25)
#define ADS1263_DRDY    gpio_read_pin(HPM_GPIO0, GPIO_DI_GPIOE, 26)

初始化ADS1263

int init_ads1263(void)

{    
    printf("*************************************************************\r\n");    
    printf("*                                                           *\r\n");    
    printf("* ADS1263 TEST ^_^                                          *\r\n");    
    printf("*                                                           *\r\n");    
    printf("*************************************************************\r\n");
    
   GPIO_Configuration();    
   ADS1263_INIT();//ADS1263初始化    
   ADS1263_CS_L;    
   Delay(0xf);       
   ADS1263_WRITE(0x08);//START1 command,当START引脚为低电平时,可由此命令启动ADC1的转换。    
   ADS1263_CS_H;    
   Delay(0xf);    
   return 0;
}
读取AD值
int read_ads1263(void)
{    
    if(ADS1263_DRDY != 1)    
    {        
        ADS1263_CS_L;        
        Delay(0xf);        
        ADS1263_WRITE(0x12);//读取ADC1        
        STATUS=ADS1263_READ_REG();        
        ADC1_DATA=ADS1263_READ();        
        checksum = ADS1263_READ_REG();        
        ADS1263_CS_H;         
        count++;        
        D[47]++;        
        if(D[76] > 0)        
        {            
            ADC1_DATA = Filter_ch1(ADC1_DATA,D[76],D[77]);        
         }        
         ADC1_DATA = CELL_ADSOURSE_FILTER(ADC1_DATA,D[78],D[79]);
      
      mv_Now = ADC1_DATA / 2147483648.0 * 2500 / 32;//mv数        
      //测试重量参数        
      Weight = (mv_Now - mv_Zero)/ 10.0f * mv_Full * mv_Cali;        
      INT32toREG(ADC1_DATA,&D[0]);//源码        
      FP32toREG(mv_Now,&D[2]);//mv数        
      FP32toREG(Weight,&D[4]);//重量        
      //校秤参数        
      mv_Zero = REGtoFP32(&D[70]);//mv零点        
      mv_Full = REGtoFP32(&D[72]);//满量程        
      mv_Cali = REGtoFP32(&D[74]);//校准系数    
        
      return ADC1_DATA;   
   }    
   else        
       return 0;
}

利用上次移植的modbus 裸机例子,在主循环中不断查询AD状态读取。

连接好线,接上称重传感器开始测试

3.jpg

MODBUS上位机画面,使用50kg C3电阻应变桥式称重传感器采样400次精度在±1g,后来降低采样到60次/s,滑动平均5次,精度在±0.2g 。

4.png

逻辑分析仪抓取波形图。采用软件模拟SPI,速度在3M左右,读取命令+状态+4字节数据+校验共7个字节数据在20.5us左右

5.png

 【实验总结】

HPM6750 在配置IO时要注意名称,因为IO引脚较多,宏定义也比较多,在初始化容易写错(这次因为IO编号写错导致两个IO口没有输出,查了1个多小时)。看来图形化代码工具还是很有必要的(*悄咪咪告诉你们,先楫图形化代码工具已经上线使用中啦);

HPM6750 的驱动强度和施密特单独出来和I.MX RT系列比较像增加了IO控制的灵活性,PCB上高速信号的抗信号反射电阻和驱动限流电阻都可以省去了,等以后试下芯片的施密特能否代替外部输入上的 74HC14;

HPM6750 运算速度很快,等以后试试高阶FIR看看;

ADS1263 的高速采样及其以来模拟电源的纹波,对内部DCDC电源还是要增加滤波器,采样60HZ对50-hz和60hz纹波抑制后精度一下就上来了;

来源:先楫芯上人

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 263

本文导读

HPM6750支持jlink、dap和ft2232等多种调试方式,本文将对这几种调试方式展开介绍,方便大家灵活选用不同的调试方式。

硬件

本文所使用的开发板为HPM6750EVK。JTAG接口如图右下角所示,在外接使用JLINK或DAP时使用排线直接连接到开发板即可。

1.png

使用外接调试器时需要确保板载调试器不工作,因此可通过断开R111电阻来断开板载调试器的电源。

2.png

通过丝印图可轻易找到该电阻位于ft2232调试器上方。

3.png

JLINK 调试

使用数据线连接电脑和jlink后打开设备管理器,可以看到当前已成功识别到J-Link driver。

4.png

由于openocd无法通过jlink的驱动连接到芯片,因此需要借助Zadig将jlink驱动转换为WinUSB。打开Zadig后点击Options打开菜单栏并勾选上List All Devices显示所有驱动。

5.jpg

点击打开驱动下拉框,找到jlink设备。

6.jpg

确认设备选择正确后点击Replace Driver修改jlink为WinUSB。

7.jpg

修改成功后重新打开设备管理器,此时J-Link driver已被成功修改为BULK interface。

8.png

此时打开工程,通过鼠标右键工程名并点击Options打开工程配置。

9.jpg

在Debug目录中选择GDB Server,然后双击GDB Server Command Line打开修改窗口并将ft2232修改为jlink,最后全部点击OK保存退出。

10.png

使用排线连接好jlink和开发板后,通过打开菜单栏的Debug点击Go运行调试后,光标成功停在main函数即表明jlink调试功能已正常使用。

11.jpg

DAP 调试

连接电脑和DAP后,打开设备管理器会看到“通用串行总线控制器”中多了一个设备,通过查看详细信息可确认DAP已成功连接。

12.png

与jlink不同的是openocd支持使用dap,因此不需要修改usb驱动可直接打开工程配置,把原来的ft2232或jlink修改为cmsis_dap,保存退出,使用排线连接好dap和开发板后就可以直接通过dap进行调试了。

13.png

FT2232 调试

FT2232是HPM6750EVK开发板的板载调试器,使用的时候仅需要使用一条Type-C线与电脑连接即可(接大负载需额外供电)。如果之前使用过JLINK或DAP进行调试,请将电阻R111焊回去以确保FT2232供电正常,此时如有外接的调试器也请将其断开。

14.jpg

打开Zadig查看设备列表,能看到两个Dual RS232-HS设备,这里也选择编号较小的 Interface 0。然后点击Replace Driver安装驱动。

15.jpg

新创建的工程默认GDB Server就是ft2232无需修改,如果前面测试JLINK或DAP的时候修改过该配置,请将其重新修改为ft2232。

16.jpg

驱动验证

较简单的验证方式可在连接好开发板后,打开SEGGER Embedded Studio直接点击Debug – Go进入调试,代码自动编译下载后断点停在main函数说明驱动配置成功。

17.jpg

进入调试模式失败时,Output会有相关的信息提示。此时请仔细检查接线和上述驱动安装过程是否有问题。

18.jpg

想要查看更多连接信息可使用第二种验证方式,双击sdk根目录下的start_cmd.cmd打开调试窗口。

19.jpg

输入

set OPENOCD_SCRIPTS=%HPM_SDK_BASE%\boards\openocd

设置名为OPENOCD_SCRIPTS的环境变量:

20.png

然后输入

openocd -f probes/ft2232.cfg -f soc/hpm6750-single-core.cfg

运行openocd,如连接成功将如下所示打印相关信息:

21.png

当调试失败时,调试窗口也会打印错误信息。相较于使用SEGGER Embedded Studio,这里显示的调试信息更详细,有助于更快地排查出问题。

22.png

至此,三种调试方式已经介绍完了,你偏向使用哪一种呢?

来源:立功科技

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 977

简介

本文主要介绍了HPM6750的控制器局域网CAN(以下简称CAN控制器)的概述以及基于HPM-SDK CAN控制器的开发指导(包括实现CAN2.0、CAN-FD)。

CAN控制器

1. 概述

CAN 是 Controller Area Network 的缩写(以下称为 CAN),是 ISO 国际标准化的串行通信协议。HPM6750 MCU搭载了4路CAN控制器,CAN0/CAN1/CAN2/CAN3,它们具有如下特性:

● 支持 CAN 2.0B 协议,支持多达 8 字节的数据载荷, 数据速率可达 1Mbit/s;

● 支持 CAN FD 协议,支持多达 64 字节的数据载荷, 数据速率可达 2.5Mbit/s;

● 支持 1 ∼ 1/256 的波特率预分频,灵活配置波特率;

● 16 个接收缓冲器;

– FIFO 方式;

– 错误或者不被接收的数据不会覆盖存储的消息;

● 1 个高优先主发送缓冲器 PTB;

● 8 个副发送缓冲器 STB;

– FIFO 方式;

– 优先级仲裁方式;

● 16 组独立的筛选器;

– 支持 11 位标准 ID 和 29 位扩展 ID;

– 可编程 ID CODE 位以及 MASK 位;

● PTB/STB 均支持支持单次发送模式;

● 支持静默模式;

● 支持回环模式;

● 支持待机模式;

● 支持捕捉传输的错误种类以及定位仲裁失败位置;

● 可编程的错误警告值;

● 支持 ISO11898-4 规定时间触发 CAN 以及接收时间戳可配置停止位:1位,1.5位或者2位。

2. 系统框图

1.png

3. 管脚

2.png

CAN控制器功能开发指引

1. API功能描述

CAN开发主要使用以下接口:

//获取CAN默认配置
hpm_stat_t can_get_default_config(can_config_t *config);
//CAN 初始化接口
hpm_stat_t can_init(CAN_Type *base, can_config_t *config, uint32_t src_clk_freq);
//接收过滤器配置
hpm_stat_t can_set_filter(CAN_Type *base, const can_filter_config_t *config);
//CAN 数据发送接口(阻塞模式)
hpm_stat_t can_send_message_blocking(CAN_Type *base, const can_transmit_buf_t *message);
//CAN高优先级数据发送接口(PTB 阻塞模式)
hpm_stat_t can_send_high_priority_message_blocking(CAN_Type *base, const can_transmit_buf_t *message);
//CAN 数据接收接口(阻塞模式)
hpm_stat_t can_receive_message_blocking(CAN_Type *base, can_receive_buf_t *message);
//CAN 数据接收接口(非租塞模式)
hpm_stat_t can_read_received_message(CAN_Type *base, can_receive_buf_t *message);
//设置发送补偿及使能(CAN-FD高速率使用,TDC)
void can_set_transmitter_delay_compensation(CAN_Type *base, uint8_t sample_point, bool enable);

2. API数据结构

2.1 CAN配置

typedef struct {    
   union {        
      struct {           
         //当禁用use_lowlevel_timing_setting时,以下参数有效。            
         uint32_t baudrate;  //CAN 2.0波特率设定            
         uint32_t baudrate_fd; // CAN-FD波特率设定,当enable_canfd使能才有效                       
         uint16_t can20_samplepoint_min; //CAN 2.0最小采样点(0~1000)                       
         uint16_t can20_samplepoint_max; //CAN 2.0最大采样点(0~1000)            
         uint16_t canfd_samplepoint_min; //CAN-FD 最小采样点(0~1000)            
         uint16_t canfd_samplepoint_max; //CAN-FD 最大采样点(0~1000)        
      };        
      struct {
//当启用use_lowlevel_timing_setting时,以下参数有效。            
         can_bit_timing_param_t can_timing;  //CAN2.0 位时间参数            
         can_bit_timing_param_t canfd_timing; //CAN-FD 位时间参数        
      };    
   };
can_loopback_mode_t loopback_mode;    //CAN回环模式,默认是正常模式
bool use_lowlevel_timing_setting;     //是否启用位时间参数设定     
   bool enable_canfd;   //是否启用CAN-FD     
   bool enable_self_ack;   //是否启用自ACK帧
bool disable_re_transmission_for_ptb;  //是否禁用高优先级PTB发送重传, false:单发模式 true:重传模式
bool disable_re_transmission_for_stb;  //是否禁用STP发送重传, false:单发模式, true:重传模式
uint16_t filter_list_num;   //接受过滤器list总数can_filter_config_t *filter_list;  //接受过滤器list指针
} can_config_t;

2.2 CAN过滤配置

/** 
 * @brief CAN acceptance filter modes 
 */
typedef enum _can_filter_mode {    
    can_filter_mode_both_frames,                //标准格式和扩展格式过滤选模式
can_filter_mode_standard_frames,            //标准格式过滤模式
can_filter_mode_extended_frames,            //扩展格式过滤模式
} can_filter_mode_t;


/** 
 * @brief CAN acceptance configuration 
 */
typedef struct {
uint16_t index;                             //过滤器index
can_filter_mode_t mode;                 //过滤器模式     
     bool enable;                               //过滤器是否使能     
     uint32_t code;                              //ID code     
     uint32_t mask;                              //ID mask
} can_filter_config_t;

2.3 CAN发送

/** 
 * @brief CAN transmit buffer data structure 
 */
typedef union _can_tx_buf {
uint32_t buffer[18];    //发送 buffer,由于是联合体,和下面的共享一块内存区域,buffer大小:4*18=72
struct {        
        struct {            
           uint32_t id: 29;                      //CAN ID            
           uint32_t : 1;            
           uint32_t transmit_timestamp_enable: 1;  //时间戳使能        
        };        
        struct {            
           uint32_t dlc: 4;                        //数据长度            
           uint32_t bitrate_switch: 1;             //bitrate开关            
           uint32_t canfd_frame: 1;                //can-fd标识位            
           uint32_t remote_frame: 1;               //remote 标识位            
           uint32_t extend_id: 1;                  //扩展ID            
           uint32_t : 24;        
        };        
        uint8_t data[];                             //数据指针    
     };
} can_transmit_buf_t;

2.4 CAN接收

/** 
 * @brief CAN receive buffer data structure 
*/
typedef union _can_rx_buf {    
    uint32_t buffer[20];           //接收buffer,由于是联合体,和下面的数据共享一块内存区域    
    struct {        
        struct {            
            uint32_t id: 29;        //can id            
            uint32_t : 1;            
            uint32_t error_state_indicator: 1;  //错误状态指示        
        };        
        struct {            
            uint32_t dlc: 4;                   //数据长度            
            uint32_t bitrate_switch: 1;        //bitrate开关            
            uint32_t canfd_frame: 1;           //canfd 标识            
            uint32_t remote_frame: 1;          //remote标识            
            uint32_t extend_id: 1;             //扩展ID            
            uint32_t : 4;            
            uint32_t loopback_message: 1;      //回环数据标识            
            uint32_t error_type: 3;            //错误类型            
            uint32_t cycle_time: 16;           //cycle time        
        };        
        uint8_t data[];                        //数据指针    
    };
} can_receive_buf_t;

3. 配置流程

CAN控制器的CAN2.0和CAN-FD配置流程如下图。

3.png

4. 样例

4.1 内部回环样例

需求:

1.CAN-FD协议

2.波特率2.5Mbps

3.内部回环模式

4.数据载荷64字节

5.遍历can-id从0~2047(11位标准ID)

6.每帧数据确保不同

7.阻塞发送、非阻塞接收(非中断模式)

8.对比接收和发送的数据包是否相等,并输出结果

 void board_can_loopback_test(void)
 {    
     bool result;    
     uint32_t error_cnt = 0;    
     uint32_t can_src_clk_freq;    
     can_config_t can_config;    
     board_init_can(BOARD_APP_CAN_BASE);    
     can_src_clk_freq = board_init_can_clock(BOARD_APP_CAN_BASE);    
     can_config.baudrate = 1000000; /* 1Mbps */    
     can_config.baudrate_fd = 2500000; /*5Mbps*/    
     can_config.loopback_mode = can_loopback_internal; //内部回环    
     can_config.enable_canfd = true;    
     hpm_stat_t status = can_init(BOARD_APP_CAN_BASE, &can_config, can_src_clk_freq);    
     if (status != status_success) {        
          printf("CAN initialization failed, error code: %d\n", status);        
          return;    
     }    
     can_transmit_buf_t tx_buf;    
     can_receive_buf_t rx_buf;    
     memset(&tx_buf, 0, sizeof(tx_buf));    
     memset(&rx_buf, 0, sizeof(rx_buf));    
     tx_buf.dlc = can_payload_size_64;    
     tx_buf.canfd_frame = 1;    
     tx_buf.bitrate_switch = 1;    
     for (uint32_t i = 0; i < 2048; i++) {        
           tx_buf.id = i;        
           for (uint32_t j = 0; j < 64u; j++) {            
                tx_buf.data[j] = (uint8_t)i + j + 1;        
           }        
           can_send_message_blocking(BOARD_APP_CAN_BASE, &tx_buf);        
           can_read_received_message(BOARD_APP_CAN_BASE, &rx_buf);        
           result = can_buf_compare(&tx_buf, &rx_buf);        
           if (!result) {            
                error_cnt++;            
                can_set_transmitter_delay_compensation(BOARD_APP_CAN_BASE, 64, true);            
                hpm_stat_t status = can_init(BOARD_APP_CAN_BASE, &can_config, can_src_clk_freq);            
                if (status != status_success) {                
                     printf("CAN initialization failed, error code: %d\n", status);                
                     return;            
                }            
                printf("ID=%08x, result:%s\n", rx_buf.id, result ? "passed": "failed");        
           }    
      }    
      printf("    CAN loopback test for extend frame %s, error_cnt:%d\n", error_cnt == 0 ? "passed" : "failed", error_cnt);
}

4.2 两路闭环收发样例

需求:

1.CAN2.0协议

2.波特率1000000,1Mbps

3.CAN0发送,CAN1接收

4.数据载荷8字节

5.CAN0阻塞发送,CAN1阻塞接收

6.对比CAN0发送包和CAN1接收包是否相同,并输出结果

7.压测100次,输出最终结果

void can0_can1_rxrx_loop_test(void)
{    
   pm_stat_t status;    
   can_config_t can_config;    
   bool use_canfd = false;    
   can_get_default_config(&can_config);    
   can_config.baudrate = 1000000; /* 1Mbps */    
   can_config.baudrate_fd = 5000000; /* 2Mbps */    
   can_config.enable_canfd = use_canfd;    
   board_init_can(HPM_CAN0);    
   board_init_can(HPM_CAN1);   
   uint32_t can_src_clk_freq0 = board_init_can_clock(HPM_CAN0);    
   uint32_t can_src_clk_freq1 = board_init_can_clock(HPM_CAN1);    
   hpm_stat_t status0 = can_init(HPM_CAN0, &can_config, can_src_clk_freq0);    
   if (status0 != status_success) {        
      printf("CAN initialization failed, error code: %d\n", status0);        
      return;    
   }    
   hpm_stat_t status1 = can_init(HPM_CAN1, &can_config, can_src_clk_freq1);    
   if (status1 != status_success) {        
      printf("CAN initialization failed, error code: %d\n", status1);        
      return;    
   }    
   printf("CMD_STA_CMD_CTRL(0xA0)= %08x\n", HPM_CAN0->CMD_STA_CMD_CTRL);    
   printf("F_PRESC               = %08x\n", HPM_CAN0->F_PRESC);    
   printf("S_PRESC               = %08x\n", HPM_CAN0->S_PRESC);    
   printf("TDC                   = %08x\n", HPM_CAN0->TDC);    
   uint32_t error_cnt = 0;    
   bool result = false;    
   can_transmit_buf_t tx_buf;    
   can_receive_buf_t rx_buf; 
      memset(&tx_buf, 0, sizeof(tx_buf));    
   memset(&rx_buf, 0, sizeof(rx_buf));    
   tx_buf.id = 0x101;    
   uint32_t id_max;    
   if (!use_canfd) {        
        tx_buf.dlc = can_payload_size_8;        
        id_max = 8;    
   } else {        
        tx_buf.dlc = can_payload_size_8;        
        id_max = 64;        
        tx_buf.canfd_frame = 1;        
        tx_buf.bitrate_switch = 1;    
   }    
   for(int index = 0; index < 100; index++)    
   {        
       for (uint32_t i = 0; i < id_max; i++) {            
            tx_buf.data[i] = (uint8_t)(index+i);        
       }        
       can_send_high_priority_message_blocking(HPM_CAN0, &tx_buf);        
       can_receive_message_blocking(HPM_CAN1, &rx_buf);        
       result = can_buf_compare(&tx_buf, &rx_buf);        
       if (!result) {            
            error_cnt++;            
            printf("    CAN0->CAN1 for standard frame %s\n", result ? "passed" : "failed");        
       }        
       can_receive_message_blocking(HPM_CAN0, &rx_buf);        
       result = can_buf_compare(&tx_buf, &rx_buf);        
       if (!result) {            
            error_cnt++;            
            printf("    CAN1->CAN0 for standard frame %s\n", result ? "passed" : "failed");        
       }    
  }    
  printf("    CAN can0 can1 rxrx loop test for result: %s, error_cnt:%d\n", error_cnt == 0 ? "passed" : "failed", error_cnt);
}

4.3 四路收发样例

需求:

1.CAN-FD协议

2.波特率2.5Mbps

3.数据载荷64字节

4.启用中断接收

5.CAN0/CAN1/CAN2/CAN3顺序发送数据

6.确保CAN0/CAN1/CAN2/CAN3 can-id不同

7.确保每次发送的数据包内容不同

8.分别对比每次一路CAN发送数据包和其它三路CAN接收的数据包是否相同,并输出结果

9.压测100次,并输出结果

static can_info_t s_can_info[] = {        
         { .can_base = HPM_CAN0 },        
         { .can_base = HPM_CAN1 },
#if defined(HPM_CAN2)        
         { .can_base = HPM_CAN2 },
#endif
#if defined (HPM_CAN3)        
         { .can_base = HPM_CAN3 },
#endif
};
volatile static bool has_new_rcv_msg_array[4];
volatile static can_receive_buf_t s_can_rx_buf_array[4];
SDK_DECLARE_EXT_ISR_M(IRQn_CAN0, board_can_isr0);
SDK_DECLARE_EXT_ISR_M(IRQn_CAN1, board_can_isr1);
SDK_DECLARE_EXT_ISR_M(IRQn_CAN2, board_can_isr2);
SDK_DECLARE_EXT_ISR_M(IRQn_CAN3, board_can_isr3);
void board_can_isr0(void)
{    
     uint8_t flags = can_get_tx_rx_flags(HPM_CAN0);    
     if ((flags & CAN_EVENT_RECEIVE) != 0) {        
          can_read_received_message(HPM_CAN0, (can_receive_buf_t *)&s_can_rx_buf_array[0]);        
          has_new_rcv_msg_array[0] = true;    
     }    
     can_clear_tx_rx_flags(HPM_CAN0, flags);
}
void board_can_isr1(void)
{    
     uint8_t flags = can_get_tx_rx_flags(HPM_CAN1);    
     if ((flags & CAN_EVENT_RECEIVE) != 0) {        
          can_read_received_message(HPM_CAN1, (can_receive_buf_t *)&s_can_rx_buf_array[1]);        
          has_new_rcv_msg_array[1] = true;    
     }    
     can_clear_tx_rx_flags(HPM_CAN1, flags);
}
void board_can_isr2(void)
{    
     uint8_t flags = can_get_tx_rx_flags(HPM_CAN2);    
     if ((flags & CAN_EVENT_RECEIVE) != 0) {        
          can_read_received_message(HPM_CAN2, (can_receive_buf_t *)&s_can_rx_buf_array[2]);        
          has_new_rcv_msg_array[2] = true;    
     }    
          can_clear_tx_rx_flags(HPM_CAN2, flags);
}
void board_can_isr3(void)
{    
     uint8_t flags = can_get_tx_rx_flags(HPM_CAN3);    
     if ((flags & CAN_EVENT_RECEIVE) != 0) {        
          can_read_received_message(HPM_CAN3, (can_receive_buf_t *)&s_can_rx_buf_array[3]);        
          has_new_rcv_msg_array[3] = true;    
     }    
     can_clear_tx_rx_flags(HPM_CAN3, flags);
}
void board_can0_1_2_3_txrx_loop_test(void)
{    
     hpm_stat_t status;    
     can_config_t can_config;    
     bool use_canfd = true;    
     can_get_default_config(&can_config);    
     can_config.baudrate = 1000000; /* 1Mbps */    
     can_config.baudrate_fd = 2500000; /* 5Mbps */    
     can_config.enable_canfd = use_canfd;    
     /* Initialize CAN */    
     for (uint32_t i=0; i < ARRAY_SIZE(s_can_info); i++) {        
          can_info_t  *info = &s_can_info[i];        
          board_init_can(info->can_base);        
          info->clock_freq = board_init_can_clock(info->can_base);        
          status = can_init(info->can_base, &can_config,  info->clock_freq);        
          if (status != status_success) {            
               printf("CAN %d initialization failed, error code: %d\n", i, status);            
               return;        
          }        
          printf("CMD_STA_CMD_CTRL(0xA0)= %08x\n", info->can_base->CMD_STA_CMD_CTRL);        
          printf("F_PRESC               = %08x\n", info->can_base->F_PRESC);        
          printf("S_PRESC               = %08x\n", info->can_base->S_PRESC);        
          printf("TDC                   = %08x\n", info->can_base->TDC);        
          can_enable_tx_rx_irq(info->can_base, CAN_EVENT_RECEIVE);    
          }    
          intc_m_enable_irq_with_priority(IRQn_CAN0, 1);    
          intc_m_enable_irq_with_priority(IRQn_CAN1, 1);    
          intc_m_enable_irq_with_priority(IRQn_CAN2, 1);    
          intc_m_enable_irq_with_priority(IRQn_CAN3, 1);
          
    uint32_t error_cnt = 0;    
    bool result = false;    
    can_transmit_buf_t tx_buf[4];    
    uint32_t data_max;    
    memset(tx_buf, 0, sizeof(tx_buf));    
    for(int i = 0; i < 4; i ++)    
    {        
        tx_buf[i].id = i+1;        
        if (!use_canfd) {            
             tx_buf[i].dlc = can_payload_size_8;            
             data_max = 8;        
        } else {            
             tx_buf[i].canfd_frame = 1;            
             tx_buf[i].bitrate_switch = 1;            
             tx_buf[i].dlc = can_payload_size_64;            
             data_max = 64;        
        }    
    }    
    for(int index = 0; index < 100; index++)    
    {        
        for(uint32_t can_i = 0; can_i < 4; can_i++)        
        {            
            for (uint32_t i = 0; i < data_max; i++) {                
                 tx_buf[can_i].data[i] = (uint8_t)(index+can_i+i);            
             }        
        }        
        for(uint32_t can_i = 0; can_i < 4; can_i++)        
        {            
            can_send_high_priority_message_blocking(s_can_info[can_i].can_base, &tx_buf[can_i]);            
            for(int j= 1; j < 4; j++)            
            {                
                printf("recv canid:%d\n", (can_i+j)%4);                
                while(!has_new_rcv_msg_array[(can_i+j)%4])                
                {                
                }                
                has_new_rcv_msg_array[(can_i+j)%4] = false;                
                result = can_buf_compare(&tx_buf[can_i], &s_can_rx_buf_array[(can_i+j)%4]);                
                if (!result) {                    
                     error_cnt++;                
                }                
                printf("  CAN%d->CAN%d for standard frame %s\n", can_i, (can_i+j)%4, result ? "passed" : "failed");            
            }        
        }    
   }    
   printf("    CAN can0 can1 rxrx loop test for result: %s, error_cnt:%d\n", error_cnt == 0 ? "passed" : "failed", error_cnt);
}

划重点

使用HPM6750的CAN控制器,可以轻松实现4路CAN2.0/CAN-FD同时收发数据,易于实现CAN网络隔离以及网络中继的复杂需求,实现了工业网关的功能。

来源:先楫芯上人

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 146

本文内容来自先楫开发者 @Xusiwei1236,介绍了如何在HPM6750上运行边缘AI框架,感兴趣的小伙伴快点来看看。

---------------  以下为测评内容 ---------------

TFLM是什么?

你或许都听说过TensorFlow——由谷歌开发并开源的一个机器学习库,它支持模型训练和模型推理。

今天介绍的TFLM,全称是TensorFlow Lite for Microcontrollers,翻译过来就是“针对微控制器的TensorFlow Lite”。那TensorFlow Lite又是什么呢?

TensorFlow Lite(通常简称TFLite)其实是TensorFlow团队为了将模型部署到移动设备而开发的一套解决方案,通俗的说就是手机版的TensorFlow。下面是TensorFlow官网上关于TFLite的一段介绍:

“TensorFlow Lite 是一组工具,可帮助开发者在移动设备、嵌入式设备和 loT 设备上运行模型,以便实现设备端机器学习。”

而我们今天要介绍的TensorFlow Lite for Microcontrollers(TFLM)则是 TensorFlow Lite的微控制器版本。这里是官网上的一段介绍:

“ TensorFlow Lite for Microcontrollers (以下简称TFLM)是 TensorFlow Lite 的一个实验性移植版本,它适用于微控制器和其他一些仅有数千字节内存的设备。它可以直接在“裸机”上运行,不需要操作系统支持、任何标准 C/C++ 库和动态内存分配。核心运行时(core runtime)在 Cortex M3 上运行时仅需 16KB,加上足以用来运行语音关键字检测模型的操作,也只需 22KB 的空间。”

这三者一脉相承,都出自谷歌,区别是TensorFlow同时支持训练和推理,而后两者只支持推理。TFLite主要用于支持手机、平板等移动设备,TFLM则可以支持单片机。从发展历程上来说,后两者都是TensorFlow项目的“支线项目”。或者说这三者是一个树形的发展过程,具体来说,TFLite是从TensorFlow项目分裂出来的,TFLite-Micro是从TFLite分裂出来的,目前是三个并行发展的。在很长一段时间内,这三个项目的源码都在一个代码仓中维护,从源码目录的包含关系上来说,TensorFlow包含后两者,TFLite包含tflite-micro。

HPM SDK中的TFLM

  • TFLM中间件

HPM SDK中集成了TFLM中间件(类似库,但是没有单独编译为库),位于hpm_sdk\middleware子目录:

1.png

这个子目录的代码是由TFLM开源项目裁剪而来,删除了很多不需要的文件。

  • TFLM示例

HPM SDK中也提供了TFLM示例,位于hpm_sdk\samples\tflm子目录:

2.png

示例代码是从官方的persion_detection示例修改而来,添加了摄像头采集图像和LCD显示结果。

由于我手里没有配套的摄像头和显示屏,所以本篇没有以这个示例作为实验。

在HPM6750上运行TFLM基准测试

接下来以person detection benchmark为例,讲解如何在HPM6750上运行TFLM基准测试。

  • 将person detection benchmark源代码添加到HPM SDK环境

按照如下步骤,在HPM SDK环境中添加person detection benchmark源代码文件:

1、在HPM SDK的samples子目录创建tflm_person_detect_benchmark目录,并在其中创建src目录;

2、从上文描述的已经运行过person detection benchmark的tflite-micro目录中拷贝如下文件到src目录:

  • tensorflow\lite\micro\benchmarks\person_detection_benchmark.cc

  • tensorflow\lite\micro\benchmarks\micro_benchmark.h

  • tensorflow\lite\micro\examples\person_detection\model_settings.h

  • tensorflow\lite\micro\examples\person_detection\model_settings.cc

3、在src目录创建testdata子目录,并将tflite-micro目录下如下目录中的文件拷贝全部到testdata中:

  1. tensorflow\lite\micro\tools\make\gen\linux_x86_64_default\genfiles\tensorflow\lite\micro\examples\person_detection\testdata

4、修改person_detection_benchmark.cc、model_settings.cc、no_person_image_data.cc、person_image_data.cc 文件中部分#include预处理指令的文件路径(根据拷贝后的相对路径修改);

5、person_detection_benchmark.cc文件中,main函数的一开始添加一行board_init();、顶部添加一行#include "board.h”

  • 添加CMakeLists.txt和app.yaml文件

在src平级创建CMakeLists.txt文件,内容如下:

cmake_minimum_required(VERSION 3.13)

set(CONFIG_TFLM 1)

find_package(hpm-sdk REQUIRED HINTS $ENV{HPM_SDK_BASE})
project(tflm_person_detect_benchmark)
set(CMAKE_CXX_STANDARD 11)

sdk_app_src(src/model_settings.cc)
sdk_app_src(src/person_detection_benchmark.cc)
sdk_app_src(src/testdata/no_person_image_data.cc)
sdk_app_src(src/testdata/person_image_data.cc)
sdk_app_inc(src)sdk_ld_options("-lm")
sdk_ld_options("--std=c++11")
sdk_compile_definitions(__HPMICRO__)
sdk_compile_definitions(-DINIT_EXT_RAM_FOR_DATA=1)
# sdk_compile_options("-mabi=ilp32f")
# sdk_compile_options("-march=rv32imafc")
sdk_compile_options("-O2")
# sdk_compile_options("-O3")
set(SEGGER_LEVEL_O3 1)
generate_ses_project()

在src平级创建app.yaml文件,内容如下:

dependency:  
   - tflm
  • 编译和运行TFLM基准测试

接下来就是大家熟悉的——编译运行了。首先,使用generate_project生产项目:

3.png

接着,将HPM6750开发板连接到PC,在Embedded Studio中打卡刚刚生产的项目:

4.png

这个项目因为引入了TFLM的源码,文件较多,所以右边的源码导航窗里面的Indexing要执行很久才能结束。

然后,就可以使用F7编译、F5调试项目了:

5.png

编译完成后,先打卡串口终端连接到设备串口,波特率115200。启动调试后,直接继续运行,就可以在串口终端中看到基准测试的输出了:

============================== 
hpm6750evkmini clock summary
==============================
cpu0:            816000000Hz
cpu1:            816000000H
zaxi0:            200000000Hz
axi1:            200000000Hz
axi2:            200000000Hz
ahb:             200000000Hz
mchtmr0:         24000000Hz
mchtmr1:         1000000Hz
xpi0:            133333333Hz
xpi1:            400000000Hz
dram:            166666666Hz
display:         74250000Hz
cam0:            59400000Hz
cam1:            59400000Hz
jpeg:            200000000Hz
pdma:            200000000Hz
=============================

----------------------------------------------------------------------
$$\   $$\ $$$$$$$\  $$\      $$\ $$\
$$ |  $$ |$$  __$$\ $$$\    $$$ |\__|
$$ |  $$ |$$ |  $$ |$$$$\  $$$$ |$$\  $$$$$$$\  $$$$$$\   $$$$$$\
$$$$$$$$ |$$$$$$$  |$$\$$\$$ $$ |$$ |$$  _____|$$  __$$\ $$  __$$\
$$  __$$ |$$  ____/ $$ \$$$  $$ |$$ |$$ /      $$ |  \__|$$ /  $$ |
$$ |  $$ |$$ |      $$ |\$  /$$ |$$ |$$ |      $$ |      $$ |  $$ |
$$ |  $$ |$$ |      $$ | \_/ $$ |$$ |\$$$$$$$\ $$ |      \$$$$$$  |
\__|  \__|\__|      \__|     \__|\__| \_______|\__|       \______/
----------------------------------------------------------------------

InitializeBenchmarkRunner took 114969 ticks (4 ms).
WithPersonDataIterations(1) took 10694521 ticks (445 ms)
DEPTHWISE_CONV_2D took 275798 ticks (11 ms).
DEPTHWISE_CONV_2D took 280579 ticks (11 ms).
CONV_2D took 516051 ticks (21 ms).
DEPTHWISE_CONV_2D took 139000 ticks (5 ms).
CONV_2D took 459646 ticks (19 ms).
DEPTHWISE_CONV_2D took 274903 ticks (11 ms).
CONV_2D took 868518 ticks (36 ms).
DEPTHWISE_CONV_2D took 68180 ticks (2 ms).
CONV_2D took 434392 ticks (18 ms).
DEPTHWISE_CONV_2D took 132918 ticks (5 ms).
CONV_2D took 843014 ticks (35 ms).
DEPTHWISE_CONV_2D took 33228 ticks (1 ms).
CONV_2D took 423288 ticks (17 ms).
DEPTHWISE_CONV_2D took 62040 ticks (2 ms).
CONV_2D took 833033 ticks (34 ms).
DEPTHWISE_CONV_2D took 62198 ticks (2 ms).
CONV_2D took 834644 ticks (34 ms).
DEPTHWISE_CONV_2D took 62176 ticks (2 ms).
CONV_2D took 838212 ticks (34 ms).
DEPTHWISE_CONV_2D took 62206 ticks (2 ms).
CONV_2D took 832857 ticks (34 ms).
DEPTHWISE_CONV_2D took 62194 ticks (2 ms).
CONV_2D took 832882 ticks (34 ms).
DEPTHWISE_CONV_2D took 16050 ticks (0 ms).
CONV_2D took 438774 ticks (18 ms).
DEPTHWISE_CONV_2D took 27494 ticks (1 ms).
CONV_2D took 974362 ticks (40 ms).
AVERAGE_POOL_2D took 2323 ticks (0 ms).
CONV_2D took 1128 ticks (0 ms).
RESHAPE took 184 ticks (0 ms).
SOFTMAX took 2249 ticks (0 ms).

NoPersonDataIterations(1) took 10694160 ticks (445 ms)
DEPTHWISE_CONV_2D took 274922 ticks (11 ms).
DEPTHWISE_CONV_2D took 281095 ticks (11 ms).
CONV_2D took 515380 ticks (21 ms).
DEPTHWISE_CONV_2D took 139428 ticks (5 ms).
CONV_2D took 460039 ticks (19 ms).
DEPTHWISE_CONV_2D took 275255 ticks (11 ms).
CONV_2D took 868787 ticks (36 ms).
DEPTHWISE_CONV_2D took 68384 ticks (2 ms).
CONV_2D took 434537 ticks (18 ms).
DEPTHWISE_CONV_2D took 133071 ticks (5 ms).
CONV_2D took 843202 ticks (35 ms).
DEPTHWISE_CONV_2D took 33291 ticks (1 ms).
CONV_2D took 423388 ticks (17 ms).
DEPTHWISE_CONV_2D took 62190 ticks (2 ms).
CONV_2D took 832978 ticks (34 ms).
DEPTHWISE_CONV_2D took 62205 ticks (2 ms).
CONV_2D took 834636 ticks (34 ms).
DEPTHWISE_CONV_2D took 62213 ticks (2 ms).
CONV_2D took 838212 ticks (34 ms).
DEPTHWISE_CONV_2D took 62239 ticks (2 ms).
CONV_2D took 832850 ticks (34 ms).
DEPTHWISE_CONV_2D took 62217 ticks (2 ms).
CONV_2D took 832856 ticks (34 ms).
DEPTHWISE_CONV_2D took 16040 ticks (0 ms).
CONV_2D took 438779 ticks (18 ms).
DEPTHWISE_CONV_2D took 27481 ticks (1 ms).
CONV_2D took 974354 ticks (40 ms).
AVERAGE_POOL_2D took 1812 ticks (0 ms).
CONV_2D took 1077 ticks (0 ms).
RESHAPE took 341 ticks (0 ms).
SOFTMAX took 901 ticks (0 ms).

WithPersonDataIterations(10) took 106960312 ticks (4456 ms)

NoPersonDataIterations(10) took 106964554 ticks (4456 ms)

可以看到,在HPM6750EVKMINI开发板上,连续运行10次人像检测模型,总体耗时4456毫秒,每次平均耗时445.6毫秒。

在树莓派3B+上运行TFLM基准测试

  • 在树莓派上运行TFLM基准测试

树莓派3B+上可以和PC上类似,直接运行PC端的测试命令,得到基准测试结果:

6.png

可以看到,在树莓派3B+上的,对于有人脸的图片,连续运行10次人脸检测模型,总体耗时4186毫秒,每次平均耗时418.6毫秒;对于无人脸的图片,连续运行10次人脸检测模型,耗时4190毫秒,每次平均耗时419毫秒。

  • HPM6750和树莓派3B+、AMD R7 4800H上的基准测试结果对比

这里将HPM6750EVKMINI开发板、树莓派3B+和AMD R7 4800H上运行人脸检测模型的平均耗时结果汇总如下:

7.png

可以看到,在TFLM人脸检测模型计算场景下,HPM6750EVKMINI和树莓派3B+成绩相当。虽然HPM6750的816MHz CPU频率比树莓派3B+搭载的BCM2837 Cortex-A53 1.4GHz的主频低,但是在单核心计算能力上没有相差太多。

这里树莓派3B+上的TFLM基准测试程序是运行在64位Debian Linux发行版上的,而HPM6750上的测试程序是直接运行在裸机上的。由于操作系统内核中任务调度器的存在,会对CPU的计算能力带来一定损耗。所以,这里进行的并不是一个严格意义上的对比测试,测试结果仅供参考。

(本文参考链接:http://m.eeworld.com.cn/bbs_thread-1208270-1-1.html

直接转载来源:先楫芯上人

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 289

页面

订阅 RSS - HPM6750