CAN232/CANUSB调查

最近研究了一下廉价CAN分析设备的原理,顺便明白了和CAN-OE设备的差距真的是天上地下.不过存在着不少优点还是可以学习的.下面是商品链接:

https://www.can232.com/

从名字上就可以看出这是一个串口到can数据包的转换工具,但是搜索很久都没找到通信协议,插在电脑上也不会主动发送消息,正在我百思不得其解的时候,发现了Linux内核里面有个叫做slcan的驱动模块,里面写着CAN232设备的网址.于是先调查下slcan是个什么东西.

slcan

全名 serial line CAN interface driver ,正好是CAN232设备的支持模块,需要配合slcand来使用(位于can=utils程序中).

初始化slcan很简单,正常初始化即可,但是如果我们把CAN232换成普通串口进行抓包,也是可以初始化的o.o

因此在打开设备时候可以捕获到下面数据(结尾均为0x0d,即’\r’):

C
S6
F
O

根据slcand的代码,可以判断相应字母(区分大小写)的意思,每个命令0x0d结尾

C -> 关闭
S6 -> 速度500k (参考: https://elinux.org/Bringing_CAN_interface_up#SLCAN_based_Interfaces)
F ->  获取状态
O -> 打开设备
// 下面这些也是代码中描述的协议
L -> 只听模式
s -> 设置波特率

//数据报文(大写代表扩展帧,小写代表数据帧)
t 数据帧
r 远程帧

//回复结尾
0x0d 正常
            异常(我忘了o.o,回头再试一下)

z 发送成功

因此,随便一个串口只要按照上面格式发送数据就可以被linux转换为CAN消息.当然这样的协议存在明显的缺点,即抗干扰能力差(不过CAN232采用了FTDI的串口芯片,一般实验室情况下稳定性足够了).

最后补上一张串口助手模拟的CAN.

slcanfd

这个串口模块非常古老,因此不支持CAN-FD的协议,但是内核驱动写的很清晰易懂,配合虚拟串口回环和cangen工具,制作了一个支持CAN-FD的驱动https://github.com/feilongfl/slcanfd.

首先模块名字改成了slcanfd,编译安装并手动加载即可使用slcand进行启动.(注意卸载slcan模块,否则会冲突)

后续可以考虑修改下slcand工具,增加下数据速度设置.在stm32G431上配合usb cdc跟fdcan做个usbcanfd(淘宝好像也有现成的,不过我想玩玩画板子,4层板都快成白菜价了)

发送接收展示:

pc发送不加速canfd
pc发送加速canfd
pc发送普通CAN(兼容原格式)
串口发送(CANFD Only)
串口发送(CANFD+CAN)

顺便wakatime也挺好玩的,能看到调查这堆东西花了多少时间:

FT4232H体验记录

体验背景

对于单片机来讲,串口通信是比较方便的接口了,打印log什么的不需要自己写上位机,网上串口助手一大把,随便找个就行,比较适合嵌入式项目的前期调试使用。

但是,随着嵌入式芯片的速度不断提高,产生的log越来越多,串口也需要比较高的速度,前段时间给mcu的串口终端通信压力测试时候,用国产山寨pl2303把速度设到921600才能给mcu一点压力。

并且新的项目需要更加快速的log速度,于是我开始寻找更加快速的串口。首先想到的是以前玩px4时候用的ft232高贵的三十多块钱的串口,速度好像3m左右来着,当年也没什么特殊需求,也没在速度这边做研究。于是打开FTDI的官网,发现最大速度12m,而且还有更加高贵的版本,70多块的ft4232,相当于4个ft232的版本。更加新一代的产品ft4233在当前(2020/5/1)还没有发售,比ft232支持了typec的pd功能(其实这个更符合我的需求,奈何淘宝没有,之后联络供应商可能会有其他回答)

体验(踩坑)历程

  1. 淘宝卖家发来的是没有焊接引脚的版本,对于我这种手残党,直接翻车。
正面
背面

清晰可见电容扭曲,因为我焊接引脚时候焊锡落在在电容上,两个电容是我后焊上去的,折腾了好久。如果不是测试用,强烈不建议购买这种,做工很差,pcb特别薄,而且明显的拼版,掰开后没打磨,在从usb拔出时候极易割伤手指(我已经被割伤了)。四周尖角,扎人。非要买的话,建议一起买个锉刀,打磨下。

2. 驱动的话,windows 10manjaro linux基本都能自己驱动,不用折腾,连接在PC上4个COM口,linux的话lsusb出现一个设备,/dev/ttyUSB出现4个,在我这边测试都是从小到大对应ABCD,没有出现反人类情况。

3. 新的FTDI芯片可以通过FT PROG对eeprom进行配置。这个软件只能windows运行。

FT Prog

这个软件在点击扫描时候有可能闪退(比如我这),通过上面命令行执行SCAN命令,可以看到错误

对这个错误进行搜索,可以查询到这是一个已知的问题,https://www.ftdicommunity.com/index.php?topic=39.0

简单来说就是和我的鼠标冲突(因为我键盘使用ps2接口,不使用USB HID协议),于是拔下鼠标,按F5然后再把鼠标插上就可以正常工作了,这里根据需要设置即可,不过感觉设置没什么作用,可能是因为我还没有测试D2XX接口。

4 通过串口助手进行发送测试,波特率直接测试12000000,通信没什么问题,回环和逻辑分析仪都没什么问题,但是循环发送速度特别慢,约几kb/s,让人难以接受,在网络上搜索没什么有效的结果,于是上逻辑分析仪进行测试。

overview
两包数据间隔时间

可以看到每次传输都是比较快的,但是在中间等待了很长时间才进行下一次传输,于是猜测串口助手影响,使用golang写(抄)了如下测试代码。

package main

import (
    "flag"
    "github.com/tarm/goserial"
    "github.com/larspensjo/config"
    "os"
    "log"
)

var (
    conFile = flag.String("configfile","/config.ini","config file")
)

var TOPIC = make(map[string]string)

func main() {
    file, _ := os.Getwd()
    cfg, err := config.ReadDefault(file + *conFile)

    id, err := cfg.String("COM","COMID")
    baud, err := cfg.Int("COM","BAUD")
    c := &serial.Config{Name: id, Baud: baud}
    s, err := serial.OpenPort(c)

    if err != nil {
        log.Fatal(err)
    }

	data := []byte("0")

	for i:=0; i< 1000000; i++ {
		_, err := s.Write(data)
		
		if err != nil {
			log.Fatal(err)
		}
	}

}
[COM]
COMID=COM17
BAUD=12000000

依旧间隔很久,肉眼可见的等待时间,怀疑驱动层或者goserial或者windows系统对串口处理有问题(linux尚未测试,c语言串口也需要测试一下),于是对每次传输字节数量进行增加,得到下面波形,可见大数据是可以高速通信的。

传输大byte
放大一点

接收的话12m的波特率没什么问题,可以正常看到数据,没发现丢包情况,不过看串口助手cpu占用率挺高,快占满一个核心了,估计自制串口通讯工具时候也需要注意这一点,把串口接收单独一个线程,防止丢数据。

启动电平时间

这方面应该跟板载电容大小有关,但是作为淘宝货,应该也是直接抄的公版电路,所以对启动电平的测量也能在一定程度上说明一定问题,对今后串口下载电路的实现可以起到一定的借鉴作用.因为这个板子没有usb的电压接口,只能采取测量ldo的3v3输出.

可以看到上电初期时序,做下载电路的话,dtr时间最长.适合作为rst使用.大约40us左右,rts可以作为类似与stm32的boot0一样的存在,用于选择引导位置.

stm32g431系列PD编译踩坑

最近开始研究了一下stm32cube,发现挺好用的,就是bug太多,经常生成的工程不能编译.

我一般选择生成makefile,这样对自动集成比较友好.方便后续迭代.

cube配置

没有硬件,电路在不断改设计(这个是我随便画得,不一定能运行,没看手册),暂定这么分配管脚.这次主要是测试编译和接口,为以后开发踩下坑

芯片支持usbfs和fdcan,可以做个canfd数据分析,省下周立功两千多大洋(感觉周立功的东西去个0差不多),vector这种级别的比不了还是买吧.

而且支持双向USBPD,可以做快充,或者大功率耗电.看了下st的pd视频,估计未来的st芯片系列都会带有这个模块.

cube坑和注意事项

  1. pd快充的硬件模块ucpd必须要手动开启中断和DMA,增加USBPD中间件并不会自动配置.
  2. GUI_INTERFACE启用后可以对PD进行debug,ST有一个上位机PD工具
  3. USBPD开启TRACE_EMB,并且TRACE_EMB模块打开可以在串口debug,也可以在GUI看到.

生成代码的坑

这坑就大了…

Makefile上

  1. IDrivers/CMSIS/Include这里多一行,生成工程经常遇到,老错误了
  2. 下面这段
LIBS = -lc -lm -lnosys  \
-lUSBPDCORE_PD3_FULL_CM4_wc32.a
LIBDIR =  \
-LMiddlewares/ST/STM32_USBPD_Library/Core/lib

把链接文件当库用了…应当是下面这样:

LIBS = -lc -lm -lnosys \
Middlewares/ST/STM32_USBPD_Library/Core/lib/USBPDCORE_PD3_FULL_CM4_wc32.a

LIBDIR = 

3. 修改下面编译阶段,加入ccache可以加快编译,毕竟整个库几乎不用改.不然每次修改makefile都会全部重新构建.

4. cube配置后可能有重复的文件加进去,导致一堆符号重复,删除重复即可

库BUG

经过上面反复折腾,如果你在cube配置时选择双向(dual)PD你会看到下面错误:

/usr/bin/ccache arm-none-eabi-gcc -c -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -DUSE_FULL_LL_DRIVER -DUSBPD_PORT_COUNT=1 -D_RTOS -D_DRP -D_TRACE -D_GUI_INTERFACE -DUSBPDCORE_LIB_PD3_FULL -DUSE_HAL_DRIVER -DSTM32G431xx -IInc -IDrivers/STM32G4xx_HAL_Driver/Inc -IDrivers/STM32G4xx_HAL_Driver/Inc/Legacy -IUtilities/GUI_INTERFACE -IUtilities/TRACER_EMB -IMiddlewares/Third_Party/FreeRTOS/Source/include -IMiddlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 -IMiddlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F -IMiddlewares/ST/STM32_USBPD_Library/Core/inc -IMiddlewares/ST/STM32_USBPD_Library/Devices/STM32G4XX/inc -IMiddlewares/ST/STM32_USBPD_Library/../../../Drivers/STM32G4xx_HAL_Driver/Inc -IMiddlewares/ST/STM32_USB_Device_Library/Core/Inc -IMiddlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc -IDrivers/CMSIS/Device/ST/STM32G4xx/Include -IDrivers/CMSIS/Include -Og -Wall -fdata-sections -ffunction-sections -g -gdwarf-2 -MMD -MP -MF"build/usbpd_cad_hw_if.d" -Wa,-a,-ad,-alms=build/usbpd_cad_hw_if.lst Middlewares/ST/STM32_USBPD_Library/Devices/STM32G4XX/src/usbpd_cad_hw_if.c -o build/usbpd_cad_hw_if.o
Middlewares/ST/STM32_USBPD_Library/Devices/STM32G4XX/src/usbpd_cad_hw_if.c:167:17: warning: 'ManageStateDetached_SNK' used but never defined
  167 | static uint32_t ManageStateDetached_SNK(uint8_t PortNum);
      |                 ^~~~~~~~~~~~~~~~~~~~~~~
arm-none-eabi-gcc build/main.o build/app_freertos.o build/usbpd.o build/usbpd_dpm_user.o build/usbpd_pwr_user.o build/usbpd_pwr_if.o build/usbpd_vdm_user.o build/usbpd_dpm_core.o build/usb_device.o build/usbd_conf.o build/usbd_desc.o build/usbd_cdc_if.o build/stm32g4xx_it.o build/stm32g4xx_hal_msp.o build/stm32g4xx_hal_timebase_tim.o build/stm32g4xx_ll_utils.o build/stm32g4xx_ll_exti.o build/stm32g4xx_hal_gpio.o build/stm32g4xx_hal_pcd.o build/stm32g4xx_hal_pcd_ex.o build/stm32g4xx_ll_usb.o build/stm32g4xx_hal.o build/stm32g4xx_hal_rcc.o build/stm32g4xx_hal_rcc_ex.o build/stm32g4xx_hal_flash.o build/stm32g4xx_hal_flash_ex.o build/stm32g4xx_hal_flash_ramfunc.o build/stm32g4xx_hal_exti.o build/stm32g4xx_hal_dma.o build/stm32g4xx_hal_dma_ex.o build/stm32g4xx_hal_pwr.o build/stm32g4xx_hal_pwr_ex.o build/stm32g4xx_hal_cortex.o build/stm32g4xx_hal_adc.o build/stm32g4xx_hal_adc_ex.o build/stm32g4xx_ll_adc.o build/stm32g4xx_hal_crc.o build/stm32g4xx_hal_crc_ex.o build/stm32g4xx_hal_dac.o build/stm32g4xx_hal_dac_ex.o build/stm32g4xx_hal_fdcan.o build/stm32g4xx_hal_i2c.o build/stm32g4xx_hal_i2c_ex.o build/stm32g4xx_hal_smbus.o build/stm32g4xx_hal_i2s.o build/stm32g4xx_hal_iwdg.o build/stm32g4xx_ll_lpuart.o build/stm32g4xx_ll_gpio.o build/stm32g4xx_ll_dma.o build/stm32g4xx_hal_uart.o build/stmle32g4xx_hal_uart_ex.o build/stm32g4xx_hal_rng.o build/stm32g4xx_hal_rtc.o build/stm32g4xx_hal_rtc_ex.o build/stm32g4xx_hal_spi.o build/stm32g4xx_hal_spi_ex.o build/stm32g4xx_hal_tim.o build/stm32g4xx_hal_tim_ex.o build/stm32g4xx_ll_pwr.o build/stm32g4xx_ll_usart.o build/stm32g4xx_ll_ucpd.o build/system_stm32g4xx.o build/croutine.o build/event_groups.o build/list.o build/queue.o build/stream_buffer.o build/tasks.o build/timers.o build/cmsis_os2.o build/heap_4.o build/port.o build/usbpd_trace.o build/usbpd_cad_hw_if.o build/usbpd_hw.o build/usbpd_hw_if_it.o build/usbpd_phy.o build/usbpd_phy_hw_if.o build/usbpd_pwr_hw_if.o build/usbpd_timersserver.o build/stm32g4xx_ll_tim.o build/usbd_core.o build/usbd_ctlreq.o build/usbd_ioreq.o build/usbd_cdc.o build/data_struct_tlv.o build/bsp_gui.o build/gui_api.o build/tracer_emb.o build/tracer_emb_hw.o build/stm32g4xx_ll_rcc.o build/startup_stm32g431xx.o -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -specs=nano.specs -TSTM32G431RBTx_FLASH.ld  -lc -lm -lnosys Middlewares/ST/STM32_USBPD_Library/Core/lib/USBPDCORE_PD3_FULL_CM4_wc32.a -Wl,-Map=build/sthub.map,--cref -Wl,--gc-sections -o build/sthub.elf
/usr/lib/gcc/arm-none-eabi/9.3.0/../../../../arm-none-eabi/bin/ld: build/usbpd_cad_hw_if.o: in function `ManageStateDetached_DRP':
/home/feilong/workspace/sthub/prj/stm32g431rbtx/Middlewares/ST/STM32_USBPD_Library/Devices/STM32G4XX/src/usbpd_cad_hw_if.c:1137: undefined reference to `ManageStateDetached_SNK'
collect2: error: ld returned 1 exit status
make: *** [Makefile:260:build/sthub.elf] 错误 1

这个问题我猜了好久,因为之前的链接库错误,我一直在找这个库在那个lib里面,就差对全系统文件进行objdump了,后来突然发现这个ManageStateDetached_SNK函数就在报错的那个文件里面.不过是这么写的

#if defined(_SNK)
static uint32_t ManageStateDetached_SNK(uint8_t PortNum)
{

看来ST是认为这个函数只有在sink时候才应该编译,但按照名字来看双向接口应该也有这个功能.于是修改成下面这样,编译之.

#if defined(_DRP) || defined(_SNK)
static uint32_t ManageStateDetached_SNK(uint8_t PortNum)
{

然后编译成功了.

不过至于能不能正常工作,这个就需要之后硬件完成后在测试了.

使用vscode作为zephyr调试环境(基于stm32f746g-discovery)

前提条件west debug能正常工作,如果不能的话,请参考官方文档进行配置.

安装插件,大概下面这些.

cortex-debug,C/C++, Native Debug,arm

配置cortex-debug

settings.json里面加上下面两行

{
    "cortex-debug.armToolchainPath": "/opt/zephyr-sdk/arm-zephyr-eabi/bin/",
    "cortex-debug.armToolchainPrefix": "arm-zephyr-eabi"
}

工程配置

下面这些参考了github,各种文档汇总而成.

launch.json

{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "cortex-debug",
            "request": "launch",
            "servertype": "openocd",
            "cwd": "${workspaceRoot}",
            "executable": "${workspaceFolder}/build/zephyr/zephyr.elf",
            "name": "stm32f746g-discovery",
            "device": "STM32F746NG",
            "configFiles": [
                "${workspaceFolder}/boards/arm/stm32f746g_disco/support/openocd.cfg"
            ]
        }
    ]
}

c_cpp_properties.json

{
    "env": {
        "myZephyrSourcePath": "/home/feilong/workspace/zephyrproject/zephyr/",
        "myZephyrSDKPath": "/opt/zephyr-sdk"
    },
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${myZephyrSourcePath}/include/",
                "${myZephyrSourcePath}/lib/libc/minimal/include/",
                "${myZephyrSourcePath}/arch/arm/include/",
                "${myZephyrSourcePath}/build/zephyr/include/generated/"
            ],
            "compilerPath": "${myZephyrSDKPath}/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc",
            "cStandard": "c11",
            "cppStandard": "c++17",
            "intelliSenseMode": "gcc-x64"
        }
    ],
    "version": 4
}

west build之后f5就可以了.

记切换Cimoc至AndoridX库

前几天更新Cimoc的时候,随手把Android SDK加了1,之后发现被提示要切换到AndroidX库,以前的库要废弃了。本文依旧是面向Google搜索编程(笑),不过搜的有点多,记不太清都从哪里查的资料了。

过程记录

  1. 首先根据别人写的方法(Google官方也有写),使用Android Studio的refactor中的迁移选项,自动转换到AndroidX库。之后编译,挂了,一点也不意外:)
  2. 好象是直接执行`./gradlew assembleDebug`找到了ButterKnife是导致依赖出现问题的元凶。搜了一下,升到最新版。
  3. 之后再编译,被报出了一个JDK的问题,好象是有个jar找不到。搜了搜,貌似是openjdk不完整,执行`yay -S jdk8-openjdk`(arch系linux)安装jdk。
  4. 升级了之后又出现了ButterKnife.findById被废弃,按照https://github.com/feilongfl/Cimoc/commit/c11b06bb027bfeb5f70dc40cba9005fe7160ee8a修改(stackoverflow的老兄们太硬核了,看了半天没看懂o.o,最后自己试了一下,才明白大佬们写的是什么)
  5. 还有错,搜索后加入compileOptions
  6. 印象里还有错,然后把剩下的依赖都更新成了最新版
  7. emmm,好像就这么多,然后就跑起来了,体积大了一点,应该是依赖们都越来越大了。

目前不确定是否有bug,先放成测试版,挂着测试几天。

Android 切换R8混淆器

之前一直没抽出空来,终于过年得到了额外假期关心下大家健康,前两天把之前鸽了好久的Cimoc更新了一下。目前大多数源都可以使用了,有几个源网站失效准备删去,修复了几个,大部分貌似都能用,几个不能用的先搁置几天。

今天抽时间更新了程序的依赖以及适配了Android Q,并且切换到R8混淆器。

效果

通过R8混淆器的使用,编译速度由10min缩短至5min左右(travis ci集成时间),体积缩小170kb左右(由于后面将android support库切换为AndroidX库,依赖更新,折腾完后比原先涨了100k左右)

过程记录

本来R8早在19年就已经被Google设置成为了默认的混淆器,但是由于咕咕咕,以及不常写Android软件,当时的处理是关掉R8,仍保持原有混淆策略。

这次,首先在debug模式启用混淆,启用R8,进行编译,得到了闪退的程序,查看logcat的堆栈信息可知,由于GreenDAO的崩溃导致闪退。

通过面向Google搜索的编程(参考https://juejin.im/post/5d5fb53b51882554a13f8b6a),做出补丁https://github.com/feilongfl/Cimoc/commit/a51f39c406ae9762190f379400491f1b2f108324

再次测试,OK不闪退了,面向Google编程结束。

存储鼠标位置,便于多屏幕/窗口切换

最近研究了下AutoHotKey这个小玩具,跟高中时代玩过的AutoIt很像,不过这边更侧重于全局热键的实现。

前几天也把多年不用的C#重新用了下,四处抄抄代码做了个跟按键精灵类似的东西,突然想到AutoIt这个老物,于是又搜索了下又没有什么更好地方案,毕竟AutoIt印象里体积比较大,而且闭源。

具体对比可以参考 https://ui.vision/blog/ahk-vs-autoit/

工具介绍

这个工具的功能是每按一次热键将鼠标位置保存,并切换到原来位置。

主要用途是简化多屏幕/多窗口远距离频繁移动。

比如debug时有两个窗口,一边是代码,另一边是调试中的程序,在两个屏幕反复移动比较累(懒癌晚期),所以可以用一个快捷键快速切换位置。

源码

更新: https://gist.github.com/feilongfl/8bb1799565ad74495f4140591d686cbd#file-mouseswitch-ahk


#SingleInstance force

; global val define
global mouseSwitch = -1

; set pixel pos base on screen
CoordMode, Mouse, Screen
CoordMode, ToolTip, Screen

; work func
cahngeMouseStatus()
{
    static xpos = 0
    static ypos = 0

    ; intial script varbal
    if(mouseSwitch = -1) {
        ; save omuse pos
        MouseGetPos, xpos, ypos
        ToolTip, %msg% , %xpos%, %ypos%
        ; initial mouse index
        mouseSwitch = false
    }

    mouseSwitch := mouseSwitch = true ? false : true
    ; get mouse pos
    MouseGetPos, xpos_t, ypos_t
    ; pop old pos
    MouseMove, %xpos%, %ypos%
    ; push origin pos
    xpos = %xpos_t%
    ypos = %ypos_t%
    ; showTips
    msg = %mouseSwitch%: %xpos% %ypos%
    ToolTip, %msg% , %xpos%, %ypos%
}

; reg hotkey
; trig
CapsLock:: cahngeMouseStatus()

; clear
^CapsLock:: 
    ToolTip
    mouseSwitch = -1
    return

; capslock
+CapsLock::
    SetCapsLockState % !GetKeyState("CapsLock", "T")
    return
    

捡了个ebaz4205玩玩

今天随便刷了刷手机,发祥fpga也有矿了…然后随手一搜发现好久前就有了,闲鱼上入了两片玩玩

手里的下载器是10pin的,还要买个转接板子,于是说100块的zynq体验之旅开始

接下来等待到货,顺便前几天为了给cuda腾地方,随手又把vivado给删了,这两天还要再安上,我觉得我可能需要一个大号的固态来放/opt