使用Ai8051模拟fx2lafw设备制作简易逻辑分析仪(抛砖引玉)
最近在学习USB通信相关的知识,联想到Ai8051有usb,也有40M主频,能不能模拟网上24M那种赛普拉斯单片机的逻辑分析仪呢。
试了一下还真行,虽然性能差了不是一星半点,但是真能跑。
先放张能跑的图,上位机使用的是开源的pulseView
通过抓包和查看fx2lafw固件的源码可以知道,sigrok使用libusb,通过厂商描述符与下位机通信。
设备描述符,配置描述符和字符串照抄源码即可,由于成品逻辑分析仪是高速设备,所以对应的端点描述符最大包要从512改为64
setup相关配置照抄USBCDC官方例程即可。
需要添加的是厂商描述符的处理,
固件中相关源码
BOOL handle_vendorcommand(BYTE cmd)
{
/* Protocol implementation */
switch (cmd) {
case CMD_START:
/* Tell hardware we are ready to receive data. */
vendor_command = cmd;
EP0BCL = 0;
SYNCDELAY();
return TRUE;
case CMD_GET_FW_VERSION:
send_fw_version();
return TRUE;
case CMD_GET_REVID_VERSION:
send_revid_version();
return TRUE;
}
return FALSE;
}
这里cmd是一个结构体
struct cmd_start_acquisition {
uint8_t flags;
uint8_t sample_delay_h;
uint8_t sample_delay_l;
};
flags是为30M主频还是48M主频,sample_delay是主频/采样率-1,我这里固定主频为40M,将他的采样率转化为40M的定时器计数
void cmd_start_over()
{
//还原采样率
u32 u32Samplerate;
//接收采样率 单位Hz 定时器设置值
u16 u16Delay;
//未添加错误处理
u16Delay=cmdStartInfo.sample_delay_h;
u16Delay<<=8;
u16Delay+=cmdStartInfo.sample_delay_l;
u16Delay++;
//1<<6
if(cmdStartInfo.flags==0x40)//48M基准
{
//delay = SR_MHZ(48) / samplerate - 1;
u32Samplerate=48000000UL/u16Delay;
}
else//30M基准0<<6
{
u32Samplerate=30000000UL/u16Delay;
}
//初始化缓存
Buffer_Init();
//启动定时器
Timer0_Start(u32Samplerate);
}
//启动定时器
void Timer0_Start(uint32_t xHz) //可配置频率@40.000MHz
{
uint32_t reload;
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
// 计算重载值
// 系统时钟频率为40MHz,1T模式下每个时钟周期为1/40MHz = 0.025us
// 定时周期 = 1/xHz 秒 = (1/xHz)*1000000 us
// 需要的时钟周期数 = (定时周期)/0.025 = (1000000/xHz)/0.025 = 40000000/xHz
// 由于定时器是16位向上计数,重载值 = 65536 - (40000000/xHz)
reload = 65536UL - (40000000UL / xHz);
TL0 = reload; //设置定时初始值低字节
TH0 = reload >> 8; //设置定时初始值高字节
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
定时器启动后就开始进行采样,采样数据8通道占1个字节,0通道是bit0,7通道是bit7。
Ai8051有一个32K大小的xdata内存,尽可能分一个大的环形缓冲区,一个指针读,一个指针写,到达末尾就返回初始,这样可以最大限度利用缓冲区。
//定时器中断,填入数据
void Timer0_Isr(void) interrupt 1
{
BYTE xdata *nextPtr = wPtr + 1;
if (nextPtr >= bufferEnd) {// 指针回绕
nextPtr = RxBuffer;
}
if (nextPtr == rPtr) {// 缓冲区满
//memOver=1;
Timer0_Stop();
}
*wPtr = P1;
u16Remain--;//剩余空间-1
u16Available++;
wPtr = nextPtr;//指针+1
}
在主循环中,只需要不停的发送这些数据就可以了。
//判断usb空闲
if(!UsbInBusy)
{
//已用空间达到64
if(u16Available>=64)
{
//发送数据
EUSB =0;
UsbInBusy=1;
usb_write_reg(INDEX, 2);
for(i=0;i<64;i++)
{
usb_write_reg(FIFO2, *rPtr);//发送接收到的数据
rPtr++;
if (rPtr >= bufferEnd) {// 指针回绕
rPtr = RxBuffer;
}
}
u16Remain+=64;//剩余空间+64
u16Available-=64;
usb_write_reg(INCSR1, INIPRDY);
while (usb_read_reg(INCSR1) & INIPRDY);
usb_write_reg(INCSR1, INIPRDY);
EUSB = 1;
}
}
代码比较简单,基本上就是拿官方例程改了改,不过现在的版本还有很大问题
可能是有丢包或者其他情况,500K和1M采的数据完全不可用,降到250K才可用,并且受到通信速度和算法垃圾的影响,1M采样率只能采30ms,500K采样率可采120ms,250K及以下可以长时间采集
就这样吧,抛砖引玉,等一个感兴趣的大佬来优化了
最后,使用方法参考网上卖的20左右的逻辑分析仪,源码见附件
25.7.13
调整了定时器0的中断优先级
在P01增加了一个100K占空比50%的pwm测试波形
修复了P35没有时钟输出的bug
目前来说500K虽然只能112ms,还比较稳定,可用
参考文档、视频
Ai8051产品规格书
https://www.stcaimcu.com/data/download/Datasheet/AI8051U.pdf
USB拓展库及使用示例 | 本贴 咨询 USB,基本帮您把USB程序开发完成
https://www.stcaimcu.com/thread-16791-1-1.html
STCAI 官方usb课程
视频教学:【USB 原理及实战,16课时】,大学标准课程,有配套书籍 - USB:USB-CDC虚拟串口/就是串口,一箭双雕之USB转双串口,[鼠标+键盘]的HID复合设备 国芯技术交流网站 - AI32位8051交流社区
上位机通信源码
https://github.com/sigrokproject ... rc/hardware/fx2lafw
下位机固件源码
https://github.com/sigrokproject ... fx2lafw/tree/master
忘了说了p10-p17是0-7通道,p35是定时器输出端 精神可嘉,值得鼓励!
虽然cy7c68013A是51核,而且是20年前的老产品,但它的USB接口是2.0高速接口,支持480Mbps,USB单元设置了一个GPIF接口,通过外部EEPROM配置为IO映射GPIPF的方式通信,完全不需要单片机核的介入,类似纯物理搬运IO状态,所以能到24MHz采样速率。
而这种模拟的方式受限因素就多了,软件参与过多,而且缓冲机制也会造成一定的数据延迟,做USB接口的高速IO板卡还算是能实用,但做逻辑分析仪的话瓶颈就放在那,优化空间也不是很大。 晓飛飛 发表于 2025-7-13 00:55
精神可嘉,值得鼓励!
虽然cy7c68013A是51核,而且是20年前的老产品,但它的USB接口是2.0高速接口,支持480 ...
是的,看了固件的源码,那个芯片io单独编程直连USB-DMA发送,这个主要还是学习usb的作品,本来想着能识别出来就完事了,没想到还真能跑 量了一下逻辑分析仪的正规产品,引脚是有一个100k左右的上拉的,所以P1引脚应设为准双向口,对外输出1。这样抗干扰能力有所提升,再也不会相邻悬空口也出现采集的干扰波形了
页:
[1]