基于STM32F103自制CMSIS-DAP下载器

strongerHuang 2020-12-02 00:00

关注+星标公众,不错过精彩内容

编排 | strongerHuang

微信公众号 | strongerHuang


市面上针对Cortex-M处理器的下载器,有很多是基于CMSIS-DAP演变而来,比如:e-Link、GD-Link等。

之前给大家分享过自制ST-Link的教程,今天继续为大家分享一篇:基于STM32F103C8,自制CMSIS-DAP下载器。


1

关于CMSIS-DAP

CMSIS-DAP是支持访问 CoreSight 调试访问端口(DAP)的固件规范和实现,以及各种Cortex处理器提供CoreSight调试和跟踪。


地址:
https://arm-software.github.io/CMSIS_5/DAP/html/index.html


CMSIS-DAP固件作为源代码提供,并且可以完全配置为新的调试单元。

这里相关的更多内容,可以参看我之前分享过的一篇文章:Cortex-M软件接口标准CMSIS那些重要内容


2

CMSIS-DAP固件

CMSIS-DAP固件Arm以源码形式提供,不存在版权问题(因为针对Arm Cortex处理器,他们还希望更多人使用)。


1.固件版本
目前有两个版本:
版本1配置使用USB HID作为与主机PC的接口。
版本2配置使用WinUSB作为与主机PC的接口,并提供高速SWO跟踪流。

2.源码位置
目前源码提供在Keil MDK V5版本,安装好Keil MDK,你在安装目录下就能找到源码。

C:\Keil_v5\ARM\Packs\ARM\CMSIS\5.7.0\CMSIS\DAP\Firmware

(目前MDK V5.33,CMSIS版本为5.7.0)


3.源码描述

从文件目录可以看出,官方源码提供了一些模板和例子。


目前只提供了LPC处理器的例子,如果你有这个处理器对应的板卡,可以直接使用该源码做一个下载调试器。(下面就针对于LPC这个例子进行“改装”)


3

配置

利用STM32CubeMX图形化配置工具,帮助用户选择单片机引脚的功能,并自动生成外设初始化代码。配置了USB、SPI1和USART1,并选择了USB的Custom HID middleware模式。GPIOB10到GPIO15被配置为JTAG调试需要的引脚。GPIOC13用于驱动单片机上的LED灯。


ST公司也开发了他们自己的JTAG调试器——STLink。当然它并不是必要的,你也可以使用J-Link或者其他种类的调试器。STLink的驱动和程序可以在ST官网上下载。在网站里还有一个基于Eclipse开发环境开发的IDE,STM32CubeMX也被包含其中。我选择的IDE是基于CodeBlocks的Embitz,IDE中的arm_none_eabi_gcc版本是5.4.1。在我完成我的CMSIS-DAP之前,我必须使用STLink来调试我的代码。现在我在使用新做出来的CMSIS-DAP结合OpenOCD进行日常的开发。


4

从CMSIS-DAP的源码开始

源码可以在官网下载:

https://github.com/ARM-software/CMSIS_5


也可以直接在 Keil MDK 安装目录下获取:

C:\Keil_v5\ARM\Packs\ARM\CMSIS\5.7.0\CMSIS\DAP


将从示例V1的头文件 DAP_config.h 开始分析。


选择LPC-Link-II V1作为我的参考是因为它是通过USB HID实现的(V2是通过WinUSB实现)。我分析的第一个文件是DAP_Config.h。第一个关键位置如下:

#ifdef _RTE_#include "RTE_Components.h"#include CMSIS_device_header#else#include "device.h" #endif

不用RTE的相关文件,创建我自己的device.h。



我将参数CPU_CLOCK重定义为72000000(72MHz)。根据文件里的注释,参数DAP_PACKET_SIZE必须重新定义为64U。我把SWO_UART改为0,这让我的工作轻松不少。参数TIMESTAMP_CLOCK也要重定义为72000000。LPC-Link-II使用Cortex-M3 的 DWT模块实现时间戳(TIMESTAMP),这也是为什么我想在CubeMX中尝试配置STM32F103的DWT。最后我自己写了一小段代码来实现这个功能(在device.c中):

CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
/**
* On Cortex-M7 core there is a LAR register in DWT domain.
* Any time we need to setup DWT registers, we MUST write
* 0xC5ACCE55 into LAR first. LAR means Lock Access Register.
*/

DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;

我定义的引脚和NXP LPCxx的完全不同。我为STM32F103重写了所有的引脚的操作代码。在DAP_Config.h这个文件中还有一些奇怪的地方,比如:

// SWCLK/TCK I/O pin -------------------------------------

/** SWCLK/TCK I/O pin: Get Input.
\return Current status of the SWCLK/TCK DAP hardware I/O pin.
*/

__STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN (void) {
return ((LPC_GPIO_PORT->PIN[PIN_SWCLK_TCK_PORT]>> PIN_SWCLK_TCK_BIT) & 1U);
}

我不明白为什么DAP的代码里需要读取SWCLK/TCK引脚的电平,这个引脚明明是被配置为推挽输出来产生时钟信号输送给JTAG从机的。从上面列出来的代码可以看出,它是希望返回当前引脚的电平值,我的实现方式稍微有点不同:

__STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN  (void) {
return (uint32_t)(JTAG_TCK_GPIO_Port->ODR & JTAG_TCK_Pin ? 1:0);
}

我返回的是当前引脚的输出值。我不确定这是否正确。在整个代码中,这句话只被DAP.c中的一个叫DAP_SWJ_Pins的函数调用了两次。我猜测DAP_SWJ_Pins这个函数是用来测试IO口是否工作正常的。

另一个奇怪的地方是PIN_nRESET_OUT

/** nRESET I/O pin: Set Output.
\param bit target device hardware reset pin status:
- 0: issue a device hardware reset.
- 1: release device hardware reset.
*/

__STATIC_FORCEINLINE void PIN_nRESET_OUT (uint32_t bit) {
if (bit) {
LPC_GPIO_PORT->DIR[PIN_nRESET_PORT] &= ~(1U <<PIN_nRESET_BIT);
LPC_GPIO_PORT->CLR[PIN_nRESET_OE_PORT] = (1U <<PIN_nRESET_OE_BIT);
} else {
LPC_GPIO_PORT->SET[PIN_nRESET_OE_PORT] = (1U <<PIN_nRESET_OE_BIT);
LPC_GPIO_PORT->DIR[PIN_nRESET_PORT] |= (1U <<PIN_nRESET_BIT);
}
}

为猜测release的意思可能是将nRESET引脚重新配置为一个失能的引脚。我的代码如下:

__STATIC_FORCEINLINE void     PIN_nRESET_OUT (uint32_t bit) {
GPIO_InitTypeDef GPIO_InitStruct = {0};

if ((bit & 1U) == 1) {
JTAG_nRESET_GPIO_Port->BSRR = JTAG_nRESET_Pin;

GPIO_InitStruct.Pin = JTAG_nRESET_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(JTAG_nRESET_GPIO_Port, &GPIO_InitStruct);
} else {
JTAG_nRESET_GPIO_Port->BRR = JTAG_nRESET_Pin;

GPIO_InitStruct.Pin = JTAG_nRESET_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(JTAG_nRESET_GPIO_Port, &GPIO_InitStruct);
}
}

给你一个特殊的提示

  • 你可能在一些地方看见我写了if(...)之类的代码,像下面这样:

  if ((bit & 1U) == 1) {
...
} else {
...
}

我使用参数bit的最低位是因为有时候这个bit既不是0也不是1,它可能是2或者其他奇怪的值,所以不要把你的代码写成这样:

  if (bit) {
...
} else {
...
}

这会出问题的!

  • osObjects.h

#ifndef __osObjects_h__
#define __osObjects_h__

#include "cmsis_os2.h"

#ifdef osObjectsExternal
extern osThreadId_t DAP_ThreadId;
#else
extern osThreadId_t DAP_ThreadId;
osThreadId_t DAP_ThreadId;
#endif

extern void DAP_Thread (void *argument);

extern void app_main (void *argument);

#endif /* __osObjects_h__ */

这是一个很简单的头文件。但它引用了另一个叫做cmsis_os2.h的头文件,这是CMSIS库的一部分,但我没有没有从CMSIS库中复制到我的工程中,因为并不是其中所有的内容我都需要。我选择写一个“假”的cmsis_os2.h头文件而不是直接使用原有的头文件。这里还有另一个叫做DAP.h的头文件,它属于DAP的核心模块,在这里面引用了cmsis_compiler.h文件,这也是CMSIS库的一部分。毫无疑问,我也写了一个“假”的cmsis_compiler.h。分析到现在,我需要创建三个头文件(device.h&cmsis_os2.h&cmsis_compiler.h)来实现我的DAP工程。

接下来我会对main.cUSBD_User_HID_0.c做一些一些简单的介绍。

  • main.c

我在尽可能地精简我下载下来的这些源文件,所以我也没有要示例工程中的rl_usb.h文件。于是我还需要一个头文件来定义一些关于USB通信的函数和参数。这里有一些来自CMSIS RTOS库的函数,其中最重要的一个是osThreadNew,在我的工程中我把它实现如下:

osThreadId_t osThreadNew(void (*func)(void *), void * n, void * ctx)
{
(void)n;

(*func)(ctx);
return 0;
}

我直接“跳转”到本需要被创建的线程函数中,这就意味着main.c中的osKernelGetState&osKernelStart&osDelay三个函数永远不会被执行。下一个重要的函数是USBD_Configured,我将在使用STM32CubeMX生成初始化代码那一节解释这个函数。

  • USBD_User_HID_0.c

我移除了RTE\USB\USBD_Config_HID_0.h并在我自己的rl_usb.h中重新定义了USBD_HID0_OUT_REPORT_MAX_SZ & USBD_HID0_IN_REPORT_MAX_SZ两个参数。

USB HID通信的核心是由两个接口中断函数管理的两个循环队列:

int32_t USBD_HID0_GetReport (uint8_t rtype, uint8_t req, uint8_t rid, uint8_t *buf) {
(void)rid;

switch (rtype) {
case HID_REPORT_INPUT:
...
break;
}
return (0);
}
bool USBD_HID0_SetReport (uint8_t rtype, uint8_t req, uint8_t rid, const uint8_t *buf, int32_t len) {
(void)req;
(void)rid;

switch (rtype) {
case HID_REPORT_OUTPUT:
...
break;
}
return true;
}

当上位机向DAP发送OUTPUT REPORT报文后,DAP会调用USBD_HID0_SetReport函数,该参数的输入形参rtype必须为HID_REPORT_OUTPUT。当DAP成功向上位机发送INPUT REPORT报文时,函数USB_HID0_GetReport被调用,该函数的输入形参rtype必须为HID_REPORT_INPUT,并且形参req必须为USBD_HID_REQ_EP_INT。这意味着我们所有的报文必须通过64B数据包大小的USB中断端点传输。

线程DAP_Thread只是一个命令判断选择器。在这个函数中有一个很重要的语句:

USBD_HID_GetReportTrigger(0U, 0U, USB_Response[n], DAP_PACKET_SIZE);

我们必须实现一个叫做USBD_HID_GetReportTrigger的函数来想上位机发送INPUT REPORT


5

使用STM32CubeMX生成初始化代码

在我的单片机上有一个8MHz的晶振,所以我选择HSE为时钟信号源。PLLMul配置为x9,得到72MHz的PLLCLK,提供给CPU和AHB/APB2总线,提供给APB1总线的PCLK1配置为36MHz。USB预分频配置为1.5分频,得到48MHz的USB时钟。SPI1配置为Full-Duplex Master,舍去NSS信号,USART1配置为Asynchronous。USB设备进一步配置为Custom HID ClassUSBD_CUSTOMHID_OUTREPORT_BUF_SIZE设置为64 Bytes。

注意
我没有修改设备的VID和PID。但我猜测有些上位机软件会检测这两个ID

如果你发现你的软件不能识别我这个CMSIS-DAP,或许你需要恰当的VID和PID。可以试试示例代码中的VID/PID,它在一个叫做USBD_Config_0.c的文件中,我的工程中没有这个文件。

有STM32CubeMX生成的代码需要一些修改。在usbd_customhid.h中,CUSTOM_HID_EPIN_SIZECUSTOM_HID_EPOUT_SIZE必须设置为0x40U。我把CUSTOM_HID_FS_BINTERVAL改为0x01来尝试提升HID的通信速度。

_USBD_CUSTOM_HID_Itf结构体中,我新增了一个成员:

typedef struct _USBD_CUSTOM_HID_Itf
{
uint8_t *pReport;
int8_t (* Init)(void);
int8_t (* DeInit)(void);
int8_t (* OutEvent)(uint8_t event_idx, uint8_t state);
/* I add an extra interface func below. Zach Lee */
int8_t (* InEvent)(uint8_t event_idx, uint8_t state);
} USBD_CUSTOM_HID_ItfTypeDef;

INPUT REPORT报文成功发给上位机时,InEvent函数应当被调用,所以usbd_customhid.c中的USBD_CUSTOM_HID_DataIn函数需要修改如下:

static uint8_t  USBD_CUSTOM_HID_DataIn(USBD_HandleTypeDef *pdev,
uint8_t epnum)
{
/* Ensure that the FIFO is empty before a new transfer, this condition could
be caused by a new transfer before the end of the previous transfer */

USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)pdev->pClassData;
hhid->state = CUSTOM_HID_IDLE;

/* I add a new interface func in the structure USBD_CUSTOM_HID_ItfTypeDef. Zach Lee */
((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->InEvent(hhid->Report_buf[0],
hhid->Report_buf[1]);

return USBD_OK;
}

设备描述符CUSTOM_HID_ReportDesc_FS被定义在usbd_suctom_hid_if.c中,我定义了一个简单的描述符:

/** Usb HID report descriptor. */
__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
/* USER CODE BEGIN 0 */ /* A minimal Report Desc with INPUT/OUTPUT/FEATURE report. Zach Lee */
0x06,0x00,0xFF, /* Usage Page (vendor defined) ($FF00) global */
0x09,0x01, /* Usage (vendor defined) ($01) local */
0xA1,0x01, /* Collection (Application) */
0x15,0x00, /* LOGICAL_MINIMUM (0) */
0x25,0xFF, /* LOGICAL_MAXIMUM (255) */
0x75,0x08, /* REPORT_SIZE (8bit) */

// Input Report
0x95,64, /* Report Length (64 REPORT_SIZE) */
0x09,0x01, /* USAGE (Vendor Usage 1) */
0x81,0x02, /* Input(data,var,absolute) */

// Output Report
0x95,64, /* Report Length (64 REPORT_SIZE) */
0x09,0x01, /* USAGE (Vendor Usage 1) */
0x91,0x02, /* Output(data,var,absolute) */

// Feature Report
0x95,64, /* Report Length (64 REPORT_SIZE) */
0x09,0x01, /* USAGE (Vendor Usage 1) */
0xB1,0x02, /* Feature(data,var,absolute) */
/* USER CODE END 0 */
0xC0 /* END_COLLECTION */
};

可能Feature Report在CMSIS-DAP中不是必要的,就留着它吧。

我在这个C文件中还实现了一个新的接口函数CUSTOM_HID_InEvent_FS

static int8_t CUSTOM_HID_InEvent_FS(uint8_t event_idx, uint8_t state);  /* An extra interface func. */

USBD_CUSTOM_HID_ItfTypeDef USBD_CustomHID_fops_FS =
{
CUSTOM_HID_ReportDesc_FS,
CUSTOM_HID_Init_FS,
CUSTOM_HID_DeInit_FS,
CUSTOM_HID_OutEvent_FS,
/* I add an extra interface func below. Zach Lee */
CUSTOM_HID_InEvent_FS
};
extern void USBD_OutEvent(void); /* Implemented in file "device.h" */

static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state)
{
/* USER CODE BEGIN 6 */
USBD_OutEvent(); /* OUTPUT REPORT was received. Zach Lee */
return (USBD_OK);
/* USER CODE END 6 */
}

extern void USBD_InEvent(void); /* Implemented in file "device.h" */

static int8_t CUSTOM_HID_InEvent_FS(uint8_t event_idx, uint8_t state)
{
/* USER CODE BEGIN extra */
USBD_InEvent(); /* INPUT REPORT has been sent. Zach Lee */
return (USBD_OK);
/* USER CODE END extra */
}

CUSTOM_HID_Init_FSCUSTOM_HID_DeInit_FS两个函数被实现为使能/失能DAP功能:

extern void USBD_HID0_Initialize (void);

static int8_t CUSTOM_HID_Init_FS(void)
{
/* USER CODE BEGIN 4 */
USBD_HID0_Initialize(); /* Initialize USB communication of DAP. Zach Lee */
return (USBD_OK);
/* USER CODE END 4 */
}

extern void USBD_HID0_Uninitialize (void);

static int8_t CUSTOM_HID_DeInit_FS(void)
{
/* USER CODE BEGIN 5 */
USBD_HID0_Uninitialize(); /* Uninitialize. Zach Lee */
return (USBD_OK);
/* USER CODE END 5 */
}


6

编写将所有源代码关联起来的桥梁

为了移除CMSIS RTOS,我写了一些函数来模拟RTOS:

/**
* Replace CMSIS RTOS api
*/

static volatile int osFlags; /* Use "volatile" to prevent GCC optimizing the code. */

void osKernelInitialize(void)
{
osFlags = 0;
return;
}
int osThreadFlagsWait(int mask, int b, int c)
{
(void)b;
(void)c;

int ret;

while((osFlags&mask) == 0)
{
;
}
ret = osFlags; osFlags &= ~mask;
return ret;
}
void osThreadFlagsSet(int tid, int f)
{
(void)tid;

osFlags |= f;
return;
}

函数USBD_ConfiguredUSBD_HID_GetReportTrigger实现如下:

intUSBD_Configured(int n){
(void)n;

return(hUsbDeviceFS.dev_state == USBD_STATE_CONFIGURED ?1:0);}
void USBD_HID_GetReportTrigger(int a, int b, void * report, int len)
{
(void)a;
(void)b;

if (USBD_OK != USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, report, len))
{
;
}
return;
}

函数USBD_CUSTOM_HID_SendReport是由STM32CubeMX生成的,它被定义在usbd_customhid.c中,我自己的事件句柄如下:

bool USBD_HID0_SetReport (uint8_t rtype, uint8_t req, uint8_t rid, const uint8_t *buf, int32_t len);

void USBD_OutEvent(void)
{
USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)hUsbDeviceFS.pClassData;
USBD_HID0_SetReport(HID_REPORT_OUTPUT, 0, 0, hhid->Report_buf, USBD_CUSTOMHID_OUTREPORT_BUF_SIZE);
}

int32_t USBD_HID0_GetReport (uint8_t rtype, uint8_t req, uint8_t rid, uint8_t *buf);

void USBD_InEvent(void)
{
int32_t len;

USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)hUsbDeviceFS.pClassData;
if ((len=USBD_HID0_GetReport(HID_REPORT_INPUT, USBD_HID_REQ_EP_INT, 0, hhid->Report_buf)) > 0)
{
USBD_HID_GetReportTrigger(0, 0, hhid->Report_buf, len);
}
}

注意
DAP.h中,这里有个名为PIN_DELAY_SLOW的函数,它原本的实现是这样的:

__STATIC_FORCEINLINE void PIN_DELAY_SLOW (uint32_t delay) {
uint32_t count;

count = delay;
while (--count);
}

这里的空循环while (–count);会被GCC优化。我在StackOverflow中找到了一个好点子,它能正常工作但不是太合适,你有更好的方法吗?

__STATIC_FORCEINLINE void PIN_DELAY_SLOW (uint32_t delay) {
uint32_t count;

count = delay;
while (--count) {
/**
* Empty loop will be totally omitted by GCC.
* Search "How to prevent GCC from optimizing out a busy wait loop?" @ StackOverflow.
* This solution isn't portable. Zach Lee
*/
__ASM("");
}
}

至此,相关源码就介绍完毕,源码文件:

http://wiki.geniekits.com/downloads


参考来源:
http://wiki.geniekits.com/doku.php?id=usb_express:cmsis-dap
https://blog.csdn.net/qq_21506881/article/details/102633184
免责声明:本文部分素材来源网络,版权归原作者所有。如涉及作品版权问题,请与我联系删除

------------ END ------------


推荐阅读:

精选汇总 | 专栏 | 目录 | 搜索

C语言结构体描述BMP的文件格式

C语言printf()函数具体解释和安全隐患


关注 微信公众号『嵌入式专栏』,底部菜单查看更多内容,回复“加群”按规则加入技术交流群。


点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。

strongerHuang 作者黄工,高级嵌入式软件工程师,分享嵌入式软硬件、物联网、单片机、开发工具、电子等内容。
评论
  • 应用环境与极具挑战性的测试需求在服务器制造领域里,系统整合测试(System Integration Test;SIT)是确保产品质量和性能的关键步骤。随着服务器系统的复杂性不断提升,包括:多种硬件组件、操作系统、虚拟化平台以及各种应用程序和服务的整合,服务器制造商面临着更有挑战性的测试需求。这些挑战主要体现在以下五个方面:1. 硬件和软件的高度整合:现代服务器通常包括多个处理器、内存模块、储存设备和网络接口。这些硬件组件必须与操作系统及应用软件无缝整合。SIT测试可以帮助制造商确保这些不同组件
    百佳泰测试实验室 2024-12-12 17:45 74浏览
  • 天问Block和Mixly是两个不同的编程工具,分别在单片机开发和教育编程领域有各自的应用。以下是对它们的详细比较: 基本定义 天问Block:天问Block是一个基于区块链技术的数字身份验证和数据交换平台。它的目标是为用户提供一个安全、去中心化、可信任的数字身份验证和数据交换解决方案。 Mixly:Mixly是一款由北京师范大学教育学部创客教育实验室开发的图形化编程软件,旨在为初学者提供一个易于学习和使用的Arduino编程环境。 主要功能 天问Block:支持STC全系列8位单片机,32位
    丙丁先生 2024-12-11 13:15 66浏览
  • 近日,搭载紫光展锐W517芯片平台的INMO GO2由影目科技正式推出。作为全球首款专为商务场景设计的智能翻译眼镜,INMO GO2 以“快、准、稳”三大核心优势,突破传统翻译产品局限,为全球商务人士带来高效、自然、稳定的跨语言交流体验。 INMO GO2内置的W517芯片,是紫光展锐4G旗舰级智能穿戴平台,采用四核处理器,具有高性能、低功耗的优势,内置超微高集成技术,采用先进工艺,计算能力相比同档位竞品提升4倍,强大的性能提供更加多样化的应用场景。【视频见P盘链接】 依托“
    紫光展锐 2024-12-11 11:50 78浏览
  • 铁氧体芯片是一种基于铁氧体磁性材料制成的芯片,在通信、传感器、储能等领域有着广泛的应用。铁氧体磁性材料能够通过外加磁场调控其导电性质和反射性质,因此在信号处理和传感器技术方面有着独特的优势。以下是对半导体划片机在铁氧体划切领域应用的详细阐述: 一、半导体划片机的工作原理与特点半导体划片机是一种使用刀片或通过激光等方式高精度切割被加工物的装置,是半导体后道封测中晶圆切割和WLP切割环节的关键设备。它结合了水气电、空气静压高速主轴、精密机械传动、传感器及自动化控制等先进技术,具有高精度、高
    博捷芯划片机 2024-12-12 09:16 87浏览
  • 时源芯微——RE超标整机定位与解决详细流程一、 初步测量与问题确认使用专业的电磁辐射测量设备,对整机的辐射发射进行精确测量。确认是否存在RE超标问题,并记录超标频段和幅度。二、电缆检查与处理若存在信号电缆:步骤一:拔掉所有信号电缆,仅保留电源线,再次测量整机的辐射发射。若测量合格:判定问题出在信号电缆上,可能是电缆的共模电流导致。逐一连接信号电缆,每次连接后测量,定位具体哪根电缆或接口导致超标。对问题电缆进行处理,如加共模扼流圈、滤波器,或优化电缆布局和屏蔽。重新连接所有电缆,再次测量
    时源芯微 2024-12-11 17:11 115浏览
  • RK3506 是瑞芯微推出的MPU产品,芯片制程为22nm,定位于轻量级、低成本解决方案。该MPU具有低功耗、外设接口丰富、实时性高的特点,适合用多种工商业场景。本文将基于RK3506的设计特点,为大家分析其应用场景。RK3506核心板主要分为三个型号,各型号间的区别如下图:​图 1  RK3506核心板处理器型号场景1:显示HMIRK3506核心板显示接口支持RGB、MIPI、QSPI输出,且支持2D图形加速,轻松运行QT、LVGL等GUI,最快3S内开
    万象奥科 2024-12-11 15:42 88浏览
  • 在智能化技术快速发展当下,图像数据的采集与处理逐渐成为自动驾驶、工业等领域的一项关键技术。高质量的图像数据采集与算法集成测试都是确保系统性能和可靠性的关键。随着技术的不断进步,对于图像数据的采集、处理和分析的需求日益增长,这不仅要求我们拥有高性能的相机硬件,还要求我们能够高效地集成和测试各种算法。我们探索了一种多源相机数据采集与算法集成测试方案,能够满足不同应用场景下对图像采集和算法测试的多样化需求,确保数据的准确性和算法的有效性。一、相机组成相机一般由镜头(Lens),图像传感器(Image
    康谋 2024-12-12 09:45 81浏览
  • 全球知名半导体制造商ROHM Co., Ltd.(以下简称“罗姆”)宣布与Taiwan Semiconductor Manufacturing Company Limited(以下简称“台积公司”)就车载氮化镓功率器件的开发和量产事宜建立战略合作伙伴关系。通过该合作关系,双方将致力于将罗姆的氮化镓器件开发技术与台积公司业界先进的GaN-on-Silicon工艺技术优势结合起来,满足市场对高耐压和高频特性优异的功率元器件日益增长的需求。氮化镓功率器件目前主要被用于AC适配器和服务器电源等消费电子和
    电子资讯报 2024-12-10 17:09 99浏览
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-11 17:58 88浏览
  • 本文介绍瑞芯微RK3588主板/开发板Android12系统下,APK签名文件生成方法。触觉智能EVB3588开发板演示,搭载了瑞芯微RK3588芯片,该开发板是核心板加底板设计,音视频接口、通信接口等各类接口一应俱全,可帮助企业提高产品开发效率,缩短上市时间,降低成本和设计风险。工具准备下载Keytool-ImportKeyPair工具在源码:build/target/product/security/系统初始签名文件目录中,将以下三个文件拷贝出来:platform.pem;platform.
    Industio_触觉智能 2024-12-12 10:27 79浏览
  • 全球智能电视时代来临这年头若是消费者想随意地从各个通路中选购电视时,不难发现目前市场上的产品都已是具有智能联网功能的智能电视了,可以宣告智能电视的普及时代已到临!Google从2021年开始大力推广Google TV(即原Android TV的升级版),其他各大品牌商也都跟进推出搭载Google TV操作系统的机种,除了Google TV外,LG、Samsung、Panasonic等大厂牌也开发出自家的智能电视平台,可以看出各家业者都一致地看好这块大饼。智能电视的Wi-Fi连线怎么消失了?智能电
    百佳泰测试实验室 2024-12-12 17:33 66浏览
  • 首先在gitee上打个广告:ad5d2f3b647444a88b6f7f9555fd681f.mp4 · 丙丁先生/香河英茂工作室中国 - Gitee.com丙丁先生 (mr-bingding) - Gitee.com2024年对我来说是充满挑战和机遇的一年。在这一年里,我不仅进行了多个开发板的测评,还尝试了多种不同的项目和技术。今天,我想分享一下这一年的故事,希望能给大家带来一些启发和乐趣。 年初的时候,我开始对各种开发板进行测评。从STM32WBA55CG到瑞萨、平头哥和平海的开发板,我都
    丙丁先生 2024-12-11 20:14 78浏览
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-12 10:13 46浏览
  • 一、SAE J1939协议概述SAE J1939协议是由美国汽车工程师协会(SAE,Society of Automotive Engineers)定义的一种用于重型车辆和工业设备中的通信协议,主要应用于车辆和设备之间的实时数据交换。J1939基于CAN(Controller Area Network)总线技术,使用29bit的扩展标识符和扩展数据帧,CAN通信速率为250Kbps,用于车载电子控制单元(ECU)之间的通信和控制。小北同学在之前也对J1939协议做过扫盲科普【科普系列】SAE J
    北汇信息 2024-12-11 15:45 114浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦