概要
1、vscode开发环境搭建
2、EtherCAT与RK3562通讯测试
3、编程IGH主站+HPM极限通讯测试
4、ADC+EUI显示测试
5、ADC远采系统
1.vscode开发环境搭建
1.1 SDK包下载
SDK包:
- SDK
- 编译链
- 驱动下载器的openocd(配置文件在sdk文件夹下,不在ocd工程里)配置文件
- python3
- cmake + ninja + 其他编译脚本
- FTDI驱动
官方开发指定用的是 SEGGER Embedded studio ,但由于对eclipse系的东西实在没有好感,于是摸索使用vscode开发的方法。
1.2 工程
从SDK目录下 hpm_sdk\samples\ 拉取任意工程,我这里拉了GPIO工程
在VSCODE中安装需要的扩展:
·Cortex-Debug
·CMake Tool

3.配置系统的 SDK路径、交叉编译链路径、python3、ninja 几个环境.
但由于我不想往系统的PATH里面添加太多环境,于是在项目根目录加CMakePresets.json
{
"version":3,
"configurePresets":[
{
"name":"tinnu-path",
"displayName":"tinnu独立环境",
"description":"正在使用编译器",
"binaryDir":"${sourceDir}/out/build/${presetName}",
"generator":"Ninja",
"environment":{
"GNURISCV_TOOLCHAIN_PATH":"E:/sdkpath/toolchains/rv32imac_zicsr_zifencei_multilib_b_ext-win",
"HPM_SDK_BASE":"E:/sdkpath/hpm_sdk",
"PATH":"E:/sdkpath/tools/python3;E:/sdkpath/tools/ninja;"
},
"cacheVariables":{
"CM***E_INSTALL_PREFIX":"${sourceDir}/out/install/${presetName}",
"CM***E_C_COMPILER":"E:/sdkpath/toolchains/rv32imac_zicsr_zifencei_multilib_b_ext-win/bin/riscv32-unknown-elf-gcc.exe",
"CM***E_CXX_COMPILER":"E:/sdkpath/toolchains/rv32imac_zicsr_zifencei_multilib_b_ext-win/bin/riscv32-unknown-elf-g++.exe",
"HPM_BUILD_TYPE":"flash_xip",
"CM***E_BUILD_TYPE":"debug"
}
}
]
}
如果不配置CMakePresets.json,要么就改系统环境变量,要么在CMakeList.txt里面加入ENV,但PATH的修改还是需要加环境变量,在CMakeList.txt里面加不生效:
set(ENV{GNURISCV_TOOLCHAIN_PATH}"E:/sdkpath/toolchains/rv32imac_zicsr_zifencei_multilib_b_ext-win")
set(ENV{HPM_SDK_BASE}"E:/sdkpath/hpm_sdk/")
4.配置cmake路径
如果也不希望在系统层面安装cmake,或者以前安装过其他版本的cmake,可以选择在工程内配置特定版本的cmake,这里就配置官方提供的版本:
创建/打开 .vscode/setting.json
"cmake.cmakePath":"E:/sdkpath/tools/cmake/bin/cmake.exe",
"cmake.additionalCompilerSearchDirs":[
"E:/sdkpath/toolchains/rv32imac_zicsr_zifencei_multilib_b_ext-win/bin"
]
5.配置编译类型为xip。打开 .vscode/setting.json
"cmake.defaultVariants":{
"buildType":{
"default":"debug",
"description":"The build type.",
"choices":{
"flash_xip":{
"short":"flash_xip",
"long":"flash_xip.",
"buildType":"flash_xip"
}
}
}
}
6.配置编译宏。打开 .vscode/setting.json
"cmake.configureArgs":[
"-DBOARD=hpm5e00evk"
]
7.编译
1.3 调试
将开发板 DEBUG USB 口插入电脑
安装调试器的驱动,调试器为板载FT2232HL,官方SDK打包下面: ./tools/FTDI_InstallDriver
-注意,由于WIN11的BUG,每次重新插入USB后(注意,是插入USB后!)都需要重新安装驱动,否则不识别
打开官方下载软件,官方SDK打包根目录下的 ./start_gui
点击 Launch GDB Server 这是集成了启动openocd的命令,具体命令会在点击后出现,可以在powershell里面手动执行

配置vscode调试设置:
-创建/打开 .vscode/launch.json
{
"configurations":[
{
"name":"remote",
"cwd":"${workspaceRoot}",
"type":"cortex-debug",
"request":"launch",
"servertype":"external",
"gdbTarget":"localhost:3333",
"device":"hpm5e00",
"executable":"build/output/demo.elf",
"runToEntryPoint":"main",
"gdbPath":"E:/sdkpath/toolchains/rv32imac_zicsr_zifencei_multilib_b_ext-win/bin/riscv32-unknown-elf-gdb.exe",
"targetId":"hpm5e00"
}
]
}
点击F5即可启动调试


2.Ethercat与RK3562通讯测试
2.1 Ethercat与RK3562通讯测试
下载 SSC TOOL
我以前开发 Ethercat 使用的是5.12版本的SSC TOOL ,但是发现这个版本加载 HPM 的xml后无法在创建工程时显示配置,看了下教程,是使用5.13版本的。
由于官方下载渠道的SSC TOOL是需要ETG会员账号,之前了解过这个账号应该是要每年给德国公司交钱才行。只能找些别的渠道,最终找到gitcode。你还真别说,gitcode的baba虽然掉钱眼里,还爬虫github出过丑闻,但对于个人开发者来说,他确实是提供了一个不错的渠道。
V5.13
https://gitcode.com/open-source-toolkit/a3990
V5.12
https://gitcode.com/open-source-toolkit/9f481
git clone
https://gitcode.com/open-source-toolkit/a3990.git
下载ethercat上位机软件
最官方的肯定是倍福自己的TwinCAT下载。
https://tr.beckhoff.com.cn/login/index.php
- 但老实说,官方的东西虽然UI,但概念上还是有些晦涩和难找的。尤其是最新的 TwinCAT3 还是附加在 Visual Studio 的,可能对于纯粹的嵌入式开发者来说问题不大(只要你的硬盘没被各种版本的vivado塞满),但对于广泛开发上下位机的小伙伴就不太友好了,嵌入到 Visual Studio 里面可能会对 Visual Studio 本身的环境产生某些不可估计的掣肘。
- 另外就是这个软件安装起来还是比较麻烦的,还吃网卡类型。当初第一次接触的时候,半天扫不到下位机。让下位机厂家帮忙调试半天都搞不定,最后重启一下突然好了……
另外就是使用嵌入式开发板,刷入 linux-rt 使用 igh 上位机用命令行测试。我个人感觉这个方法还是比较简便的(如果省略掉编译linux-rt内核与交叉编译igh主站驱动的工作)
主站准备
我以前开发ethercat的时候就安装过 TwinCAT3 ,不再赘述(太过麻烦,不想回忆了)
另外手头有创龙的 3562EVM 板卡,刚好官方适配了 Linux-RT + IGH Ethercat 主站,以下分别测试
2.2 下位机软件生成编译
项目创建配置
把 /hpm_sdk\samples\ethercat\ecat_io、/hpm_sdk\samples\ethercat\port 拉出来单独一个文件夹
按照之前设置 CMakePresets.json
{
"version":3,
"configurePresets":[
{
"name":"tinnu-path",
"displayName":"tinnu独立环境",
"description":"正在使用编译器",
"binaryDir":"${sourceDir}/out/build/${presetName}",
"generator":"Ninja",
"environment":{
"GNURISCV_TOOLCHAIN_PATH":"E:/sdkpath/toolchains/rv32imac_zicsr_zifencei_multilib_b_ext-win",
"HPM_SDK_BASE":"E:/sdkpath/hpm_sdk",
"PATH":"E:/sdkpath/tools/python3;E:/sdkpath/tools/ninja;"
},
"cacheVariables":{
"CM***E_INSTALL_PREFIX":"${sourceDir}/out/install/${presetName}",
"CM***E_C_COMPILER":"E:/sdkpath/toolchains/rv32imac_zicsr_zifencei_multilib_b_ext-win/bin/riscv32-unknown-elf-gcc.exe",
"CM***E_CXX_COMPILER":"E:/sdkpath/toolchains/rv32imac_zicsr_zifencei_multilib_b_ext-win/bin/riscv32-unknown-elf-g++.exe",
"HPM_BUILD_TYPE":"flash_xip",
"CM***E_BUILD_TYPE":"debug"
}
}
]
}
按照上一篇帖子,设置 .vscode/setting.json
生成 SSC 源码
倍福为了把 ethercat 这只现金奶牛牢牢掌握在自己手里,相关的源码必须用他们的软件生成。因此HPM方面的例程是缺了这块源码的(这个对于其他的芯片也都是这样的,开发过ethercat就会知道)
上面下载了SSC TOOL,把HPM专用的设置导入SSC TOOL。
- Tool->Options->Configurations里面,点击+号,导入SDK里的配置文件:/hpm_sdk\samples\ethercat\ecat_io下面的SSC\Config\HPM_ECAT_IO_Config

创建SSC工程:File->New->custom 选择刚导入的HPM配置

导入应用:Tool->Application->Import

生成C代码

拉到/hpm_sdk\samples\ethercat\ecat_io\SSC下面
补丁说明
官网教程里面提到了需要打补丁但实测下来,打补丁反而会导致下位机卡在INIT里面,不打反而是正常的。
2.3 调试
编译下载调试
编译后,按照上一篇帖子,设置 .vscode/launch.json
打开官方下载软件,官方SDK打包根目录下的 ./start_gui
- 点击 Launch GDB Server 这是集成了启动openocd的命令,具体命令会在点击后出现,可以在powershell里面手动执行

点击F5
使用创龙3562+IGH扫描设备
扫描从站

扫描EEPROM SII表
bin/ethercat sii_read -p 0 -v
SII Area:
800c8166000000001234000000007700
4d504800010000000100000000000000
00000000000000000000000000000000
00108000801080000400000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
0000000000000000000000000f000100
SII Category0x000a(STRINGS),71words
080b454341545f4465766963650a6469
676974616c5f696f0853796e6368726f
6e0b534d2d53796e6368726f6e21496e
707574436f756e7465722070726f6365
73732064617461206d617070696e670c
496e707574436f756e746572224f7574
707574436f756e7465722070726f6365
73732064617461206d617070696e670d
4f7574707574436f756e74657200
SII Category0x001e(General),16words
01000202002300000000000c00000100
11000000000000000000000000000000
SII Category0x0028(FMMU),2words
010203ff
SII Category0x0029(SyncM),16words
00108000260001018010800022000102
00110400640001030014040020000104
SII Category0x0032(TXPDO),8words
001a0103000500000060000607200000
SII Category0x0033(RXPDO),8words
00160102000700001070000807200000
SII Category0x003c(DC),12words
00000000000000000000000000000000
0000030400000000
(1) 设备基础信息(SII Header)
厂商ID:0x000c80(十六进制) → Beckhoff Automation GmbH(标准EtherCAT厂商代码)
产品码:0x00006681 → 特定设备型号标识符(需查Beckhoff文档确认具体型号)
版本号:0x00007700 → 硬件版本V7.7
序列号:0x00001234 → 设备唯一序列号4660
EEPROM配置校验:末字节0x0001表示校验通过
(2)字符串描述(Category 0x000a: STRINGS)
解码后关键标识:
设备名称:"ECAT_Device"(45 43 41 54 5f 44 65 76 69 63 65)
功能描述:
- "digital_io" → 数字输入/输出模块
- "Synchron" & "SM-Synchron" → 支持同步功能
- "InputCounter process data mapping" → 输入计数器PDO映射
- "OutputCounter process data mapping" → 输出计数器PDO映射
(3)同步管理器配置(Category 0x0029: SyncM)
4个同步管理器定义:

(4)分布式时钟配置(Category 0x003c: DC)
关键值:0x0304
- 比特0-2:0x04 → 支持DC同步模式
- 比特3-7:0x03 → 时钟精度±50ns(高精度级别)
(5)FMMU配置(Category 0x0028)
字段:01 02 03 ff
- FMMU0:启用,逻辑→物理地址映射
- FMMU1:启用,方向为输入
- FMMU2:启用,用于同步状态管理
- 0xFF:填充终止符
读寄存器
上面分析过,输入是 0x1400 ,我们可以看一下:
- 进入OP模式bin/ethercat state -p 0 OP
- bin/ethercat reg_read -p 0 -t uint32 0x1400

使用TWinCAT扫描设备
扫描从站



监控输入

设置输出

3.编程IGH主站+HPM极限通讯测试
上文中使用TWinCAT和IGH主站命令行进行简单的读取,但工程应用还是需要嵌入到程序中。
接下来,我们使用RK3562+LINUX RT+IGH主站的库,编程轮询读写HPM从站,并测试通讯的极限速度。
3.1 配置查询
从站配置
#./ethercat slaves-v
=Master0,Slave0=
Alias:13330
Device:Main
State:SAFEOP+ERROR
Flag:E
Identity:
Vendor Id:0x0048504d
Product code:0x00000001
Revision number:0x00000001
Serial number:0x00000000
DL information:
FMMU bit operation:no
Distributed clocks:yes,64bit
DC system time transmission delay:0ns
Port Type Link Loop Signal NextSlave RxTime[ns] Diff[ns] NextDc[ns]
0 MII up open yes -402292431400
1 MII down closed no ----
2 MII down closed no ----
3 N/A down closed no ----
Mailboxes:
Bootstrap RX:0x0000/0,TX:0x0000/0
Standard RX:0x1000/128,TX:0x1080/128
Supported protocols:CoE
General:
Group:ECAT_Device
Image name:
Order number:digital_io
Device name:digital_io
CoE details:
Enable SDO:yes
Enable SDO Info:yes
Enable PDO Assign:no
Enable PDO Configuration:no
Enable Upload at startup:no
Enable SDO complete access:yes
Flags:
Enable SafeOp:no
Enable notLRW:no
Current consumption:0mA
PDO配置
#bin/ethercat cstruct
/* Master 0, Slave 0, "digital_io"
* Vendor ID: 0x0048504d
* Product code: 0x00000001
* Revision number: 0x00000001
*/
ec_pdo_entry_info_tslave_0_pdo_entries[]={
{0x7010,0x00,32},/* OutputCounter */
{0x6000,0x00,32},/* InputCounter */
};
ec_pdo_info_tslave_0_pdos[]={
{0x1600,1,slave_0_pdo_entries+0},/* OutputCounter process data mapping */
{0x1a00,1,slave_0_pdo_entries+1},/* InputCounter process data mapping */
};
ec_sync_info_tslave_0_syncs[]={
{0,EC_DIR_OUTPUT,0,NULL,EC_WD_DISABLE},
{1,EC_DIR_INPUT,0,NULL,EC_WD_DISABLE},
{2,EC_DIR_OUTPUT,1,slave_0_pdos+0,EC_WD_ENABLE},
{3,EC_DIR_INPUT,1,slave_0_pdos+1,EC_WD_DISABLE},
{0xff}
};
PDO映射
#./ethercat pdos-p0
SM0:PhysAddr0x1000,DefaultSize 128,ControlRegister0x26,Enable1
SM1:PhysAddr0x1080,DefaultSize 128,ControlRegister0x22,Enable1
SM2:PhysAddr0x1100,DefaultSize 4,ControlRegister0x64,Enable1
RxPDO0x1600"OutputCounter process data mapping"
PDO entry0x7010:00,32bit,"OutputCounter"
SM3:PhysAddr0x1400,DefaultSize 4,ControlRegister0x20,Enable1
TxPDO0x1a00"InputCounter process data mapping"
PDO entry0x6000:00,32bit,"InputCounter"
3.2 IGH主站配置
主站工程创建
拉取IGH主站源码,在 examples 下有例程。其中 rtai 这类的是高实时性要求的情况,需要编译为内核模块注册进内核里,用起来比较麻烦,特别是一些现有的项目里面想要迁移ethercat的话,还是使用 user 比较好。
拷贝 examples/dc_user 例程到独立目录,配置CMakeLists指定igh主站编译主机里面的cmake,然后在TARGET_LINK_LIBRARIES里面添加EtherLab:
include(/home/user/toolchain/rk/3562rt/ethercat/install/lib/cmake/ethercat/ethercat-config.cmake)
TARGET_LINK_LIBRARIES(${PROJECT_NAME}PRIVATE
-lpthread-lssl-lcrypto-lrt
EtherLab::ethercat)
主站配置与从站地址定位
首先获取配置句柄 ec_slave_config_t
通过 ethercat slaves -v 可以获取 Alias Vendor Id Product code 填进 ecrt_master_slave_config 的参数里。
然后配置需要读取的寄存器,获取偏移位置:
通过 ethercat pdos -p 0 可以获取 PDO entry 信息,填入 ecrt_slave_config_reg_pdo_entry 的参数里面。
主站轮询读取
先接收EtherCAT数据
ecrt_master_receive(master);
ecrt_domain_process(domain1);
使用 EC_READ_U32 和 EC_WRITE_U32 修改寄存器数据
修改之后发送回去EtherCAT从站
ecrt_domain_queue(domain1);
ecrt_master_send(master);
3.3 主从站极限速度测试
主站配置用于检测的翻转IO
初始化
board_init();
gpio_set_pin_output_with_initial(HPM_GPIO0,GPIO_DI_GPIOC,10,0);
gpio_set_pin_output_with_initial(HPM_GPIO0,GPIO_DI_GPIOB,30,0);
gpio_set_pin_output_with_initial(HPM_GPIO0,GPIO_DI_GPIOB,31,0);
这里使用逻辑分析仪监视这些IO的电平
独立一个程序测试IO翻转
intmain(void)
{
uint8_tstatus;
board_init();
gpio_set_pin_output_with_initial(HPM_GPIO0,GPIO_DI_GPIOB,31,0);
gpio_set_pin_input(HPM_GPIO0,GPIO_DI_GPIOC,8);
while(1)
{
status=gpio_read_pin(HPM_GPIO0,GPIO_DI_GPIOC,8);
gpio_write_pin(HPM_GPIO0,GPIO_DI_GPIOB,31,!status);
}
}
测试发现,翻转速度达到纳秒级,足够进行ethercat翻转实验
配置ethercat模拟EEPROM读写控制的函数
staticUINT8 pin2_level=0;
staticUINT32 counter=0;
voidAPPL_SetLed(UINT32 value)
{
UINT8 led0=((value&1)? BOARD_ECAT_OUT_ON_LEVEL:!BOARD_ECAT_OUT_ON_LEVEL);
UINT8 led1=((value&2)? BOARD_ECAT_OUT_ON_LEVEL:!BOARD_ECAT_OUT_ON_LEVEL);
UINT8 led2=((value&4)? BOARD_ECAT_OUT_ON_LEVEL:!BOARD_ECAT_OUT_ON_LEVEL);
gpio_write_pin(BOARD_ECAT_OUT1_GPIO,BOARD_ECAT_OUT1_GPIO_PORT_INDEX,BOARD_ECAT_OUT1_GPIO_PIN_INDEX,led0);
gpio_write_pin(BOARD_ECAT_OUT2_GPIO,BOARD_ECAT_OUT2_GPIO_PORT_INDEX,BOARD_ECAT_OUT2_GPIO_PIN_INDEX,led1);
gpio_write_pin(HPM_GPIO0,GPIO_DI_GPIOB,30,led2);
gpio_write_pin(HPM_GPIO0,GPIO_DI_GPIOB,31,!led2);
}
UINT32APPL_GetDipSw(void)
{
UINT8 pin0_level=gpio_read_pin(BOARD_ECAT_IN1_GPIO,BOARD_ECAT_IN1_GPIO_PORT_INDEX,BOARD_ECAT_IN1_GPIO_PIN_INDEX);
UINT8 pin1_level=gpio_read_pin(BOARD_ECAT_IN2_GPIO,BOARD_ECAT_IN2_GPIO_PORT_INDEX,BOARD_ECAT_IN2_GPIO_PIN_INDEX);
// UINT8 pin2_level = gpio_read_pin(HPM_GPIO0, GPIO_DI_GPIOC, 8);
pin2_level=!pin2_level;
UINT32 val=pin0_level<<0|pin1_level<<1|pin2_level<<2;
gpio_write_pin(HPM_GPIO0,GPIO_DI_GPIOC,10,pin2_level);
if((counter++&0xFFF)==0)
{
printf("poll count: %X\n",counter);
}
returnval;
}
读写极限测试
通过修改主站代码。
while(1)
{
// 1. 等待下一个周期
wakeupTime=timespec_add(wakeupTime,cycletime);
clock_nanosleep(CLOCK_TO_USE,TIMER_ABSTIME,&wakeupTime,NULL);
clock_gettime(CLOCK_TO_USE,¤tTime);
counter++;
if(DIFF_NS(lastFlipTime,currentTime)>=1000000000)
{
printf("counter: %d(%d)\n",counter,counter2);
counter=0;
counter2=0;
lastFlipTime=currentTime;
}
// 2. 接收EtherCAT数据
ecrt_master_receive(master);
ecrt_domain_process(domain1);
// 3. 读取所有16个模拟量输入通道
// for (int i = 0; i < 16; i++)
inti=0;
{
// 获取当前通道的偏移量
offset=analog_in_offsets[i];
// 从域数据中读取16位值
fresh_pd=ecrt_domain_data(domain1);
raw_value=EC_READ_U32(fresh_pd+offset);
if(raw_value!=raw_valueo)
{
raw_valueo=raw_value;
raw_write=raw_value;
counter2++;
}
}
EC_WRITE_U32(fresh_pd+et_output_offsets,raw_write);
ecrt_domain_queue(domain1);
ecrt_master_send(master);
}
分别使用1ms周期、300us周期对从站进行轮询,PB30都能跟上PC10,这证明了两件事
- 当前架构下, ethercat 能够满足300us轮询。
- 一旦主站发起通讯,从站会按照主站的轮询速度刷新数据。(这个我做过打印测试,在主站程序不运行的时候,从站是满速刷新,一旦主站发起通讯,就按照主站速度刷新)
以下是使用逻辑分析仪测试的结果
分析
首先明确,当前例程的从站是先读后写:
voidAPPL_Application(void)
{
InputCounter0x6000=APPL_GetDipSw();
APPL_SetLed((UINT32)OutputCounter0x7010);
}
根据时序图分析,可得:从站的处理逻辑是:在主站进行了一次读写后,在刷新缓存(即模拟的EEPROM),而非每次主站的请求到达才调用 APPL_SetLed、APPL_GetDipSw 获取数据。这种缓存刷新机制有效避免数据轮询的时间开销。
纯写极限测试
主站不管从站是否来得及刷新,拼命写,测试最高可以到33us左右,我这里测试了一个50us:
while(1)
{
// 1. 等待下一个周期
wakeupTime=timespec_add(wakeupTime,cycletime);
clock_nanosleep(CLOCK_TO_USE,TIMER_ABSTIME,&wakeupTime,NULL);
clock_gettime(CLOCK_TO_USE,¤tTime);
counter++;
if(DIFF_NS(lastFlipTime,currentTime)>=1000000000)
{
printf("counter: %d(%d)\n",counter,counter2);
counter=0;
counter2=0;
lastFlipTime=currentTime;
}
// 2. 接收EtherCAT数据
ecrt_master_receive(master);
ecrt_domain_process(domain1);
// 3. 读取所有16个模拟量输入通道
// for (int i = 0; i < 16; i++)
inti=0;
{
// 获取当前通道的偏移量
offset=analog_in_offsets[i];
// 从域数据中读取16位值
fresh_pd=ecrt_domain_data(domain1);
raw_value=EC_READ_U32(fresh_pd+offset);
}
// 5. 准备并发送输出数据
raw_write=raw_write?0:0x7;
EC_WRITE_U32(fresh_pd+et_output_offsets,raw_write);
ecrt_domain_queue(domain1);
ecrt_master_send(master);
}
4.ADC+EUI显示测试
4.1 EUI
HPM有个专门串行驱动外部数码管(如 74 系列的 595 芯片)的EUI外设,可以在占用少量IO口的情况下驱动大量数码管。
相关例程在 hpm_sdk\components\segment_led\ 下。
我们使用这个驱动库,需要在 CMakeLists.txt 里面添加
set(CONFIG_HPM_SEGMENT_LED1)
这就自动把从模块加载进工程中编译。
初始化
init_eui_pins(BOARD_EUI);
clock_add_to_group(BOARD_EUI_CLOCK_NAME,0);
uint32_ts_eui_clock_freq=clock_get_frequency(BOARD_EUI_CLOCK_NAME);
init_eui_config();
segment_led_config_eui_instance(BOARD_EUI,s_eui_clock_freq);
segment_led_config_blink_period(500,500);
可以通过 segment_led_config_disp_blink 函数设置哪些位闪动。
通过 segment_led_set_disp_data 设置指定数码管显示。
后面对ADC结果显示,需要对字符串显示进行封装:
staticinlinevoidsegment_led_set_disp_dataX(uint8_tindex,chariid,intisDot)
{
if(iid<'0'||iid>'F')
iid=0;
else
iid=iid-'0';
segment_led_set_disp_data(index,s_disp_code_8_seg[iid]|(isDot?BOARD_EUI_SEG_DP_BIT_MASK:0));
}
staticvoidupdate_seg_led_disp_dataX(charshow[],intdotId)
{
segment_led_set_disp_dataX(0,show[0],dotId 0);
segment_led_set_disp_dataX(1,show[1],dotId 1);
segment_led_set_disp_dataX(2,show[2],dotId 2);
segment_led_set_disp_dataX(3,show[3],dotId 3);
segment_led_set_disp_dataX(4,show[4],dotId==4);
}
4.2 ADC测试
例程默认ADC初始化流程:
/* ADC pin initialization */
board_init_adc16_pins();
/* ADC clock initialization */
board_init_adc_clock(BOARD_APP_ADC16_BASE,true);
/* ADC16 common initialization */
init_common_config(conv_mode);
/* ADC16 read patter and DMA initialization */
init_period_config();
board_init_adc16_pins 所定义的引脚为 IOC_PAD_PF26。
由于官方没有提供原理图,无法得知PF26具体连接到哪里,只能根据 IO文档 猜测。

看描述应该是两个类似天线SMA接口(红色标注),但手上没有这种差分线。这里还标注了J3[6]的位置,J3是下面的电机接口排针。J3[6]应该就是第六根,丝印为ADC_C。
在while循环里面轮询获取当前的ADC值,并转化为字符串存储在全局变量 bShowValue 中:
voidperiod_handler(void)
{
uint16_tresult;
doublevalue;
adc16_get_prd_result(BOARD_APP_ADC16_BASE,BOARD_APP_ADC16_CH_1,&result);
value=result*3.3/0xFFFF;
snprintf(bShowValue,32,"%.4f",value);
}
4.3 整合显示
通过数码管显示当前采样:
b=strcspn(bShowValue,".");
strncpy(tShow,bShowValue,5);
if(b<5)
{
strncpy(tShow+b,bShowValue+b+1,5-b);
}
update_seg_led_disp_dataX(tShow,b-1);
引出3.3V,采用电阻进行分压。用ADC_C分别测试两个分压的采样:

测试效果

5.ADC远采系统
项目功能:3562主站,通过ethercat 远采HPM从站的ADC码值,输出到CSV文件,通过WPS生成点图观察
5.1 HPM从机端驱动
加快ADC采样周期,假设HPM设置200HMz运行,ADC周期触发需要以100K分频才能跟得上1ms的通讯周期:
215∗3=98304
配置函数修改:
voidinit_period_config(void)
{
adc16_channel_config_tch_cfg;
adc16_prd_config_tprd_cfg;
/* get a default channel config */
adc16_get_channel_default_config(&ch_cfg);
/* initialize an ADC channel */
ch_cfg.ch =BOARD_APP_ADC16_CH_1;
ch_cfg.sample_cycle=APP_ADC16_CH_SAMPLE_CYCLE;
adc16_init_channel(BOARD_APP_ADC16_BASE,&ch_cfg);
prd_cfg.ch =BOARD_APP_ADC16_CH_1;
prd_cfg.prescale =15;/* Set pider: 2^22 clocks */
prd_cfg.period_count=3;/* 104.86ms when AHB clock at 200MHz is ADC clock source */
adc16_set_prd_config(BOARD_APP_ADC16_BASE,&prd_cfg);
}
修改上传数据,在函数APPL_Application中:
InputCounter0x6000=result*3.3/0xFFFF*1000;
5.2 主机端
读取反馈数据,输出到CSV文件:
offset=analog_in_offsets[0];
fresh_pd=ecrt_domain_data(domain1);
uint32_tva=EC_READ_U32(fresh_pd+offset);
printf("ADC %d mV\n",va);
bQueue.push(va);
if(bQueue.size()>2000)
{
// 输出到CSV文件
staticintfile_index=0;
charfilename[64];
sprintf(filename,"data_output_%d.csv",file_index++);
FILE*fp=fopen(filename,"w");
if(fp){
fprintf(fp,"Value\n");
while(!bQueue.empty()){
fprintf(fp,"%d\n",bQueue.front());
bQueue.pop();
}
fclose(fp);
printf("Data saved to %s\n",filename);
}else{
printf("Failed to create file %s\n",filename);
// 清空队列
while(!bQueue.empty()){
bQueue.pop();
}
}
}
5.3 测试环境
使用一个ICL8038作为正弦波形发生源:

输入上次ADC项目同一端口:

5.4 输出效果

文章来源:EEFocus
开发者ID:day_day
推荐阅读:







