FUNgi(第二版)工作日志

目录

09.30

10.01

10.02

10.03

10.04

10.05

10.06

10.07

10.08

10.09

10.10

10.11

10.12

10.13

10.14

09.30

FUNgi 又要拉出来遛了,暂定 10 月 9 日开始运输展品。和 Y 商量着趁机执行前些时候想好的改进计划,提升一些稳定性。

前些天找到校内基础工业训练中心表面贴装实训室的老师,那个焊接技术给我看得一愣一愣的。拿着《身体红绿灯》重制第二版的电路板,用一根针把导电纱线穿过孔里(笑死,谁想得到针线包最大的用场是皮尺用来量电子元件尺寸、针用来穿导电纱线呢……),试了一下竟然可以完美地隔空传感。那这个原型是不是就算是做完了?

纱线接近传感点亮小灯🎞0930-Proximity.mp4(989 KiB, 00:18, 960x540)

我的设想是把导电纱线(传感电极)旁边的电阻拆掉,直接连上导线伸出来,接到电容传感芯片 MPR121 上面。也就是说原本是电极接电阻接 GPIO,现在是电极接 MPR121。这样一来,即使启用保底方案换回 RC 网络,也只需要重新设计电路板、在发射端串联一个大电阻,不必再次拆开。至少可以把之前断掉的线(一个 Bongo、一个抠抠与几个拉伸铃铛)修好,因此总是不会错的。不过听说拆开会很麻烦呢。

总之先开始下单再说,上次《身体红绿灯》重制剩下两块 MPR121,可以少订一些。不过马上就是假期了,大概也发不了货吧。

订单 1(淘宝店家 S)

  • MPR121QR2 × 4

订单 2(淘宝店家 Y)

  • 贴片电阻包:0805 ± 1%
  • 贴片电阻包:0603 ± 5%
  • 贴片电容包:0805 ± 5%
  • 贴片电容包:0603 ± 5%

过了一会儿想想还是该留点冗余,不然要是芯片损坏就很难办了。撤回订单 1 并重新下单。

订单 1A(淘宝店家 S)

  • MPR121QR2 × 10

10.01

和 Y 联系之前合作的毛纺城的玲玲阿姨,确认可以工作,但是阿姨白天要上班,只有晚上有空。计划过两天从 Y 所在的研究院把装置搬出来,乘车前往阿姨家中对接工作。

之前学习过 Adafruit Wave Shield🪐 的设计,Ada 直接在 DAC 后用了一个运放(TS922 或 TL072P)向扬声器输出。不过前些时候在洞洞板上的实验总是在奇怪的地方削波——不接扬声器时输出波形正确,但是一旦接上扬声器,波形就会变形、截断。振幅减小时好一些。也许是输出电流不足的缘故?TS922 双运放的合计输出电流是 160 mA。但也不知道是不是芯片被我乱接的时候搞坏了……明明人家 Wave Shield 做得就很不错哎。

凌晨草草画完了电路原理图,用的放大器仍然是 TS922。不管那么多了。

电路原理图。

深夜下单元器件。

订单 3(淘宝店家 J)

  • USB-C 插座:卧式插孔支撑 16P 10 只 × 1
  • 贴片 TVS 管:SMBJ5.0CA 50 只 × 1
  • 贴片无源晶振:3225,8 MHz 5 只 × 1
  • 贴片电容:0805,100 nF ± 10%,50 V 100 只 × 1
  • 贴片电解电容:1000 µF,6.3 V 10 只 × 1

订单 4(淘宝店家 D)

  • TS922IDT × 1
  • STM32F103C6T6A × 2
  • W25Q32JVSSIQ × 2

10.02

下午跑去实验室,下定决心一鼓作气搞明白放大器的问题。

之前用洞洞板搭了一个放大器电路,把数模转换器 MCP4921 和运算放大器 TS922 接在一起,可以用 SPI 输入 PCM 信号给喇叭,当然也可以直接把模拟信号戳在运放的输入引脚上。截断的问题就是在这块板上定位的,今天的实验也在其上展开。

洞洞板原型电路。

从架子上搬出波形发生器,穷尽各种参数,最终认为大约确实是输出电流不足的缘故。

拼图。上:波形发生器;下:示波器上被截断的波形。

原本拿着一个新买的同款运放,焊上分线板、费劲拿着仅有的 2 mm 排针掰开硬是一个个塞进 2.54 mm 的孔距,打算重新试一下,结果一下子就不小心把电源极性戳反了,后续的输出波形看上去很不对劲,不知道是不是坏了。算啦,找个专门为喇叭设计的放大器多好。

于是关掉信号发生器与示波器,坐在工作台前挑了半天元器件。在 Mouser 上面搜了一圈,找到一个 MAX9759ETE 似乎很合适(而且比需要的更强大),虽然比想象中贵一些,不过还是立刻打开某宝,撤回订单 1A,追加 MAX9759ETE。过了一会儿再次撤回,追加另一款 rail-to-rail、输出电流足够大的运放 AD8531,作为后备方案。就怕万一呀。

订单 1B(淘宝店家 S)

  • MAX9759ETE × 2
  • MPR121QR2 × 12
  • MCP4921T-E/MS × 1
  • STM32F103C6T6A × 2
  • AD8531ARTZ (A0P) × 2

10.03

Y 说假期研究院不上班,只能节后再取出装置。不过我订购的元器件也未必那么快就能收到,我还想趁着毛绒外壳拆开的时候测试一下灵敏度呢,不然心里总是没底。虽然到时也许会非常非常紧张,但无所谓了,先做着再说。

订单 3A(淘宝店家 J)

  • (追加)USB-C 插座:贴片 16P 10 只 × 1
  • (追加)贴片钽电容:3216(A 型),22 µF ± 10%,16 V 5 只 × 1
  • (追加)贴片钽电容:3216(A 型),1 µF ± 10%,16 V 5 只 × 1
  • (移除)贴片电解电容:1000 µF

画板子的时候为了把电极接孔均匀地排列在周围,以及为了制造间隔准确的弧形迹线,写了 Python 脚本计算各种坐标,批量生成内容粘贴到 KiCad 设计文件里。

不小心熬了个大夜,基本画完了整块电路板。

电路原理图节选。
圆形电路板效果图。

10.04

下午订单 2(元件包)发货。

补上电路板余下的部分,继续写 Python 脚本计算(至少我觉得还算)好看的环形铺铜区域。傍晚画完付印。

USB 插座的尺寸其实不太确定,特别是为垂直于电路板伸出的脚所留的小孔位置,要是对不上可就糟糕了。给订单 3A 的店家发消息询问是否有图纸,但是没有得到回复。也许假期不上班吧,但如果确实如此的话还得等那么多天呢。不知道怎么办,感觉很不保险的样子。

10.05

早晨躺在床上猛然睁眼,意识到闪存芯片没加去耦电容。这可是 18 MHz 的信号哎。

焦虑地上网搜索“不加去耦电容会发生什么”,搜了半天感觉完全没法放心。唉,改吧。

上午订单 4(放大器、微控制器、闪存)发货。

下午订单 1B(各种芯片)发货。客服发来消息说音频放大器 MAX9759ETE+T 订不到货了,只能退款。有点出乎意料,不过既然电路板都改了,正好可以趁机换一个更合适的选型。找到 Adafruit 的 Class D 音频放大模块🪐,里面用的放大器是 PAM8302,迅速抄上作业。

昨天的板子已经发货了。不过按现在的状况……可能更用不上啦。

不过还是在立创商城下单原本挑中的放大器 MAX9759 备用,加上新方案的 PAM8302。忽然想起 USB 插座那笔订单不知什么时候才能发货,而且也没拿到尺寸图,也不知道 16 pin 的封装自己到底能不能顺利焊好,保险起见顺带挑了一个 6 pin 的 USB-C 插座。

订单 5(立创商城)

之前画的 USB 插座封装是 16 pin 的,需要修改。紧赶慢赶,对着插座的机械图纸狂抄封装尺寸。傍晚七点改完板子,因为不知道再晚是不是会影响交期,选择紧急踩点提交。歇了歇了。

电路原理图。
圆形电路板效果图。

10.06

早上订单 5(USB 贴片插座等)发货。

中午和 Y 讨论一些具体安排上的问题,包括拆卸与内部导线焊接的工作。表面上十分冷静,说什么“两个人一起拆装,一分钟一个,一小时就做完了”,实际上心里一点底气都没有,感觉好像什么都望不到结果,不知道是否能顺利完成。退堂鼓咚咚地敲,只能更努力地把自己颤抖的歌声投得更远、去盖过那声音,蒙住眼睛,使劲劝说自己不要放弃、还有希望。

午饭时纠结许久许久,终于和 Y 说自己在想是不是有可能展完回来再改。元件预计两天后才能到,装置拆装等各种事情几乎不可能在一天之内完成。也许可以先用之前悬挂七个 Arduino 的办法先拿去按时开展,大不了我们先自己调好软硬件,中间找个闭展日或者人少的日子拿出来装上。这样的话至少可以保证稳妥…… Y 说主要问题是有些杜邦线断在了排针座里面,不过这个问题其实很容易解决,剥下绝缘层重新焊一下就好。确实很可行呢。

思来想去,似乎真的没有别的办法,来不及了。这打乱一切安排的“假期”啊。

走出食堂想着,虽然很遗憾,但也许总算是可以暂时歇一会儿了。但是好不甘心……

几分钟后 Y 回复:10 月 9 日只是运输,10–12 日才是布展。一下子豁然开朗了!决定继续做。

改版后的电路板今天下午就已经飞速完工发货。整理出最后缺的几个零部件,在之前去过许多次的一家发货超快的店铺下单。(细导线原本有一卷,可是被我彻底弄丢了,只好放弃挣扎重新购买。开始怀疑自己是不是和电子元器件八字不合,永远都在弄丢各种东西……)

订单 6(淘宝店家 Z)

  • 贴片 TVS 管:SMBJ5.0CA 20 只 × 1
  • 贴片钽电容:3216(A 型),22 µF,16 V 5 只 × 1
  • 贴片无源晶振:3225,12 MHz 5 只 × 1
  • 细导线(OK 线):30 AWG 200 米 × 1 卷
  • W25Q32JVSSIQ × 1

果然迅速发货,几小时后就收到了提示信息。

第一批板子傍晚送达。不过既然是后备方案,而且元件都没送到,还是可以心安理得地放松的。晚上网友聚会时惊觉……

拼图。上:圆形电路板,周围四分之三圈分布着圆孔,周围颜色略有不同,区域呈“C”形;下:“C”形的楼层平面图,与电路板上的形状几乎一致。

10.07

收到订单 3A 店家的回复说“早上好,稍等发给你哦”(指图纸)。

这么看那边确实是假期过后才上班,可是我之前点了一次“催发货”按钮,然后平台过了两天就说判定店家未按时发货,还给了我赔付,与订单总额比起来已经是很大的数额了。我觉得非常不好意思,跟客服问了半天怎么办,似乎中间还转手了一人(重新发送了“您好”),然而两人似乎并没有理解我要做什么。其实我也不知道,把赔付款退给他们吗?但也不知道这个到底是不是他们在出钱。唉,算了。希望确实是平台付的,平台没有针对假期去设计完善的发货时间机制,确实是该担责。

不过订单里的部件都已经从其他途径备齐了。满怀愧疚撤回订单。

上午订单 2(元件包)送达,暂未取件。

下午试着整理出最近一直在想的串流解码方案。大致思想是用两级计时器中断嵌套,高频的一级负责合成采样,同时从闪存读取原始 QOA🪐 数据(因为 DAC 和闪存要共用同一个 SPI 接口,为保证传输不被打断,只好放在同一级);低频的一级负责发现尚未解码的数据,并完成解码,这一部分可以被任意打断。用原子式标志位来标记状态即可。

时钟中断时序图。TIM3 以 1200 Hz 频率触发,负责解码数据;更高优先级的 TIM2 以 24 kHz 频率触发,依次负责输出采样、合成采样、读取数据。

至于耗时,每个采样有 1 / 24 kHz = 41.67 µs = 3000 个周期的时间,其中 DAC 的 SPI 通信占用 16 / 18 MHz ≈ 1 µs,剩余的时间足够从闪存读 40 µs × 18 MHz = 720 bits,也就是 225 个采样。如果读取量略少一些,平均留给每个采样的解码时间很容易就绰绰有余。如果每个输出采样间隔期间至多处理一个通道的数据读出(多个通道自然形成轮流),就可以实现更多通道的复音合成。

在实验室做了写入闪存用的工具,在开发板上调试完成。目的是把计算机上的文件内容“上传”至主控,通过主控向闪存写入。原理是在程序内留下擦写的子过程(flash_erase_64kflash_test_write),由计算机上的工具程序把原始文件数据拼在一起,批量输出 GDB 指令去调用这些子过程。整个操作序列在一个空循环入口 flash_test_write_breakpoint() 处的断点触发。

闪存操作序列生成工具👾gen-flash-gdbinit.c(2.7 KiB)

傍晚订单 5(USB 贴片插座等)送达,暂未取件。

晚上和 Y 去取到装置,然后乘车前往阿姨家。

放置于玻璃门外墙角灯光下的毛绒玩具,一旁堆放着两叠深绿色爬爬毯。

和阿姨确认了工作安排,任务是拆开整个装置的外壳,露出内面,然后我们再次来访并修改内部电路,最后再由阿姨缝起来。因为当时所有的部分都缝在一起并加固,所以这次的工程量很大,尤其体现在拆的工作量上。

阿姨最近还要在毛纺城上班,只能晚上加班做,预计需要两三天。阿姨说,要是没法按时做完的话熬夜也得做完;然而今天有些高血压、头疼,所以要等第二天才能开工。我赶忙说不用不用,时间不是那么紧张——不然我的压力也得大上天。约定于第三天(10 月 10 日)晚上交接,最终在 12 日上午前完成。

在阿姨家还听说了许多有趣的事。阿姨了解电子电路,会修家电、修电视。阿姨经常为服装系的课题与设计完成手工,接过许多特殊要求的合作,说自己“就喜欢有挑战性的工作”。当时 Y 第一次前往毛纺城时,是阿姨先叫住 Y 询问课题细节。以前北京服装学院想请阿姨去做一门实训课的老师,但阿姨觉得太远了,身体状况吃不消,所以没有去。

然而就是这样一位传奇般的阿姨,说“年纪大了,只能帮着给年轻人的想法做做实现的工作,自己想不到那些”。可是我们就太年轻了,什么经验都没有,笨手笨脚的。我觉得各自做好自己最擅长的事情就很好嘛,哪里只是“有想法”的人才有功劳呢!

回到学校,深夜在开发板上确认中断嵌套配置,让一个长时间持续的 TIM3 时钟中断例程被 TIM2 打断,只需要配置好中断优先级,一切就都十分顺利。程序实现上感觉模模糊糊的地方到此应该算是扫清啦。

10.08

早上订单 1B(各种芯片)送达。

假期后的第一天,发消息练习校内工业训练中心的 Z 老师,想请老师帮忙焊接芯片。老师说只有今天上午有空,之后都有课,答应我可以马上帮忙。

——于是火速爬下床,飞奔去快递点签收芯片,然后赶往训练中心大楼。临近中午下班时间总算是赶到了。再一次感叹焊接技术之神奇。

焊上几块芯片的电路板。

下午尝试用开发板接入 µQOA 程序库🪐,在微控制器上解码音频数据。

傍晚订单 6(飞线等)送达。

10.09

中午取到订单 2(元件包)与订单 5(飞线等)包裹。

下午开工焊接。仔细看看元件包里的元件,怎么还有被切成半块的,好惨。

卷轴段边缘被切得只剩半块的贴片电阻。

虽然出师不利,整块板上的第一个元件 C7 就焊得发黑,但不久便渐入佳境,很快完成主控的组装。晶振(HSE)似乎还有些问题,主控自己切换到了内置晶振(HSI),主频因此从程序中设置的 72 MHz 降低到 64 MHz,但至少可以开始运行了。

完成半数元件组装的电路板。
连接上计算机的电路板,计算机屏幕上正确显示出调试信息。

继续焊接闪存芯片、放大器、USB 接口,以及其余所有离散元件。然而再次上电前的最终测试发现板上电源短路。十分苦恼地去吃饭,路上查了好久有没有什么办法排查这种问题。查到一个看上去最有戏的是毫欧计,但手头也没有这种东西。唉。

饭后取到下午送达的订单 4(放大器、微控制器、闪存)包裹,然后回到实验室。

瞪着一排电容,一个个重新焊过去,短路问题仍然存在。正气馁时忽然灵光闪现,难道问题出在芯片上?引脚间距最小的是 DAC。细细一看,果然有两个脚之间有着细若游丝、若有若无的连锡。修复后短路问题消失,长出一口气。

晶振的问题也得到定位——底部引脚的焊锡纷纷碰到晶振顶面,这一面是导电材料,导致输入输出引脚都接地了。修复后外部晶振顺利运作。由于晶振频率 12 MHz 不同于 HAL 库的默认频率 8 MHz,若要保证 HAL_RCC_GetHCLKFreq() 读取的频率正确,需要修改全局预处理符号 HSE_VALUE 的值并重新编译 HAL 库。在 platformio.ini 中增加编译器选项 build_flags = -D HSE_VALUE=12000000

闪烁小灯🎞1009-Blink.mp4(249 KiB, 00:05, 540x960)

深夜回宿舍时把所有元件和电路板放在自行车筐里,一路震过去,想着正好测试一下抗震性能。结果板子没出事,倒是那个复刻版 ST-Link 插上电脑没反应了。也许十块钱的小玩意确实很难保证可靠性吧。有点难办呢……

忽然想起前些天冲动消费买过一个 nanoDAP 仿真器🪐。翻出来看到几个熟悉的 SWD 信号名称标识,悬着的心放下了几分;接上电脑,稍加修改 OpenOCD 参数就可以如往常一样工作了。呼。

不过这样一来就没有调试打印可用了。原本的 ST-Link 参照网上的资料🪐修改过,支持 SWV 输出调试,nanoDAP 固件不支持这个。这方面只好先将就了。

重新下单仿真器,加上一根 USB 线,顺便挑了另一个不同的扬声器准备对比试试。

订单 7(淘宝店家 Z)

  • USB-C 数据线:1 米,2 A × 1
  • 扬声器:4 Ω,3 W × 1
  • ST-Link 仿真器 × 1

10.10

早上订单 7(USB 线等)发货。

桌面上近处摆放着电路板,覆盖着印有条码的元件包装袋;远处覆盖着同为绿色的黄瓜,覆盖着印有条码的保鲜膜。

真就看什么都像是吧!

开始调试板上的 SPI 通信。首先很快调通了 DAC 的输出。接下来是闪存,SPI 接收到的数据永远是“1”,于是搬出示波器,单次触发捕获到 SPI 信号,发现闪存的 SDO 确实有信号输出,然而主控收到的却一直是高电平。仔细一看,似乎这个引脚有虚焊的迹象。修复后就能顺利工作啦。

电路板侧面照片,画面中央一块芯片的引脚焊点凹凸不平。

注意看,这个焊点(2 号引脚)叫 DO (IO1),它虚掉了

在实验室大声播放洒水车音乐。(我知道走音了啦,对不起……)

《真善美的小世界》🎞1010-Tune.mp4(841 KiB, 00:12, 480x270)

虽然进度不错,但闪存的内容还是有些不对劲,似乎每次写入的前 4 KiB 都是 0xFF(255),不知道是出了什么问题。莫非是翻新芯片原本的保护功能没关掉?在数据手册里一顿翻找,又确认了很多遍手里芯片的状态标志位,明明没有开启保护才对。而且 GDB 打断点期间写入的一部分是能正常读出来的,玄之又玄。

临近晚上七点终于放弃,开始收拾,马上要触发去阿姨家里了。强迫自己冷静下来思考还缺什么——好像只差剥线钳了。虽然剪刀和指甲也不是不能用,但为了效率和熬夜时长着想……正好遇见最近同样经常出现在焊接工作台上的另一课题组的一位老师,从对方的工具百宝箱中借到了剥线钳和剪线钳。

打包工具,带上电烙铁、锡丝、吸锡线、导线、剪线钳、剥线钳、万用表,独自出发。Y 正在另一个项目做用户实验,感觉很忙的样子。

装有各种工具的两个塑料袋。

出发前需要先前往 Y 的工作室取出一大袋棉花。因为 Y 忙着实验没法快速回复,我似乎给自己找到一个拖延的理由,在工作室坐下来准备调试闪存问题——等一下,现在调这个怎么想都是很糟糕的安排啊!应该在附近翻一翻然后早点出发!

于是赶紧收起刚打开的电脑,翻到棉花,心一横赶紧出发。闪存……只能暂时别想了吧。大不了前 4 KiB 不用了。

路上非常慌张,担心一会儿要怎么面对阿姨和拆下的材料,面对泼出去的这一滩水。我其实很不擅长在这种安静的环境下与人一言不发地相处,束手束脚的,更何况我们还给阿姨添了那么多麻烦、阿姨又工作得那么认真。太惶恐了。而且我也不知道自己的选择是否正确、不知道最终是否能如预期一般顺利运作,甚至不知道今晚我带上的工具是否够用;现在一个浩大的工程正因为我这个不知是否正确的决定而进行中,已经耗费了大量人力与时间的资源,而未来也将继续吞下同样的数量。这个项目现在就是离弦之箭、破釜沉舟,没有任何回头路,只能硬着头皮把它推过这几天。

出租车司机师傅给家里打了个电话,不小心窥见了另一个家庭生活的一角。我的生活,甚至安全,短暂地和这位陌生人捆绑在了一起,另一个家庭也许正在期待着家人顺利完成工作、平安归来,这莫名让我有些放下心来。

然而坐在后座想着没调完的装置、没底气的决策依据,一股黏稠、阻塞的力量一下子冲上心口,喘不过气。以为自己要忍不住吐了。赶紧告诉自己,深呼吸,放松,放松。Panic attack 难道就是这样的吗……?又或者是晕车?

放松,放松。很快到达目的地,下车,深呼吸,放空脑袋,沿着三天前经过的路走去。

阿姨家里的装置已经变成几摊毛绒空壳,以及另一大袋棉花。装置内面的杜邦线已经基本剪断,只留下短短的线头。看到装置里的一切似乎有了些安心感。真的和阿姨说上话了,也就放松下来进入了状态。阿姨翻开门口附近的一张折叠桌、打开天花板上的灯,自己坐在一旁拿着几个斗状区的毛绒小零件缝缝补补起来。我也顺利开工拆起那些电阻、剪下焊起那些导线。

拆开的彩色毛绒外壳,以及固定于内部表面的洞洞板。

思索了许久要如何修改连接,费尽心思终于想明白。就是把连接纱线的剩余杜邦线和电阻元件剪断,然后在空出的位置直接焊上导线嘛!

示意图。每根导电纱线相连的杜邦线被剪断、电阻被拆下;一旁则各自重新引出白色细导线。
洞洞板背面。每根导电纱线相连的杜邦线被剪断、电阻被拆下;一旁则各自重新引出白色细导线。

万事开头难,过了一个多小时才处理好第一块洞洞板。不过很快就能在 25 分钟之内完成一块了。

阿姨拿出一盒巧克力说,“我们都不敢多吃,你这种瘦小孩就可以多吃。”

阿姨问我是学什么专业,我迟疑半晌,欲言又止——现在这样的紧张心态,也许没法支撑我轻松地和阿姨展开聊什么交叉学科啊、本科啊辅修啊。于是我只好简单地说,“也是信息艺术设计。”阿姨恍然大悟:“噢,你们是同学!”虽然没有看到阿姨的表情,但从语气上看来,也许她确实发现了其中有些端倪。算了,就等有机会再聊啦,先把手头的工作做完。

中途一边做着一边还听到了八卦,比如有位学计算机的女生来找阿姨说想学编织,因为想给男朋友织围巾。阿姨从正针反针开始教起,她学得飞快,不久就能织得很不错了。毕竟是博士生,学习能力一定没问题——然而就是这样的一名才子,却选择毕业之后回家当全职主妇!照顾男友!听到这我就受不了了,捶胸顿足,“她男朋友是谁啊!值得她此般牺牲!”“学好了拿去干嘛不好偏要作这种用途!”——是,工作是没有高低之分,她可能也真的很爱男友,可这简直是浪费呀。她的教育与才华给了她创造更大价值、实现更多理想的能力,现在却就这样全部白白丢掉了。不知道这位男友到底是何方神圣。阿姨也跟着感叹。“不知道她父母是不是也脑子进水了,放任她这样。”(有点意外阿姨会说得那么狠呢。)

阿姨端详着摆满元器件的圆板,感叹道,“现在这些集成块都太厉害了,一个个都那么小那么精致,这估计也都是机器人焊的吧”—— 2023 年 10 月 10 日晚在阿姨家确诊机器人。阿姨听闻后直夸“太棒了”。不过手工方面肯定还是阿姨更厉害,估计一学就能会吧。

晚上十一点,工作有条不紊地继续,阿姨缝完手头的毛绒小零件便一起加入,把导线比划出合适的长度剪下、捆成一捆捆,进度越来越快。我说,“争取今天之内能完成吧!”阿姨却一直说不用着急。唉,还是比想象中要慢呢,都已经在耽误人家睡觉了,原本还妄想着可以早点结束让阿姨今晚就开始缝……

最后的几根纱线通过热熔胶与此前的导线(杜邦线)固定,但是拆下之后那些纱线一碰烙铁就会断开,即使最低温(250℃——几乎快要没法融化焊锡的温度)也是如此,完全没法连回板上。给 Y 打了个视频电话,原来当时纱线并没有焊接,直接绕在孔里粘上热熔胶就固定住了。

外壳引出的纱线用热熔胶固定在洞洞板上,然后连接至杜邦线。

参考图

然而手头没有热熔胶,我正烦恼怎么才能稳定地固定好,阿姨便很快提出首先可以打结延长纱线,然后把纱线穿过洞洞板的通孔再次打结固定,最后从另一侧用焊锡连接导线,依靠孔的覆铜来达成电气连接,避免直接加热到纱线。简直是太神奇了,针法又给看得我一愣一愣的,不知怎么来回穿几下勾几下就连上了。永远佩服在任何一件事上熟练到这种程度的前辈们。

借助洞洞板相连的导电纱线与细导线。

凌晨一点收工。阿姨塞过来几块巧克力,嘱咐我回到学校发消息报个平安。真温暖呀。

10.11

布展前的最后一天。调通了串流采样器。

播放音乐🎞1011-Freedom.mp4(1.3 MiB, 00:22, 480x270)

乐曲是梅干茶漬け(Umeboshi Chazuke)的 FREEDOM DiVE↓(Dear Mr.X Remix)。四年前调那个树莓派裸机音频播放库 AMPi🪐 的时候用的也是同一首乐曲。感觉这种高低音兼具、覆盖各种波形的芯片音乐很适合用来测试压缩算法和小喇叭呢。

不过 MPR121 传感器的连接似乎不是很稳定。I²C 启动时经常丢失应答,而且 1 号芯片(U4)的所有读数都是 0,虽然状态信息完全正确,甚至指示自动校准成功(ACFF = ARFF = Ex_OOR = 0),但所有充电配置 CDCx、CDTx 以及读数 EFDx 都是 0。

丢失应答的问题大约是总线电容偏大的缘故,I²C 上拉电阻拉高信号的速度不够,需要降低其阻值。Texas Instruments 有一份很实用的上拉阻值速查文档 SLVA689 I2C Bus Pullup Resistor Calculation🪐,是非常方便的参考。在原本的 4.7 kΩ 上面各自叠起一个 2 kΩ,如此并联得到 1.4 kΩ 的阻值。这样就可以在 400 kHz 的时钟频率下支持大约 200 pF 的总线电容,经测试确实解决了丢失应答的问题。

近距离拍摄的电路板上的元件。

R7 与 R8 被盖住前沐浴的最后一次强光

然而零读数的问题迟迟没有眉目,尽管怀疑是参考电压电流的问题,可是对着 VREG 和 REXT 两个引脚的阻容元件反复检查、重新焊接,均无果而终。和 Z 老师联系,约在两天后拿去请老师帮忙检查。不过我是不希望当时板子还在学校里啦……剩下五块芯片 60 个通道应该也是够的吧,实在不够战略性放弃几个算了。

闪存的问题倒是越来越奇怪了,现在变成前 64 KiB 都不好用了。猛然发现我写的闪存块擦除过程长这样——

void flash_erase_4k(uint32_t addr)
{
  addr %= 0x1000;
  // ...
  uint8_t op_sector_erase[] = {
    0x20, // Sector Erase
    (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, (addr >> 0) & 0xFF,
  };
  flash_cmd(op_sector_erase);
  // ...

addr 取模 0x1000……?等于 0?合着之前所有的擦除都在擦第一块啊?被自己气笑了。所以之后变成 64 KiB 是因为中途改用了 64K 块擦除指令啊!唉,就是这破 bug 害得我差点吐在车上……

傍晚早早离开实验室,临走前蹲点等到上次的老师请求借用剥线钳。老师说今晚要用,用完之后放在桌面上,需要我明天早上多跑一趟来取。圆满解决啦。

虽然我已经不太有压力,只剩下对电容传感是否足够灵敏的隐隐担忧,但是不知道玲玲阿姨那边如何呢。好担心,千万不要熬大夜呀……

说起来,仿真器和 USB 线都没有拿到,要是明天布展的话,也许只能靠断点来检查读数了。绕来绕去,还是 print 调试法管用,又灵活又方便,调试器那么复杂,到头来还是得为 print 让路嘛!

10.12

早上七点半被闹钟吵醒,从 Y 处听闻阿姨还没完成,本准备昏昏睡去,被 Y 制止:“阿姨说九点多!先别睡。”

啊……

过了一会儿真的就如期出发了,出发前跑去食堂,上次来食堂吃早饭还是上次。接着飞奔去实验室拿到剥线钳。

前往阿姨家的路上我拿出电路板递到前座,给好奇的 Y 解释上面每一块芯片的作用;司机师傅听闻便忍不住见缝插针向电路板瞟过来。莫非司机也是有故事的人?不久我又拿出喇叭接上中间的孔,芯片音乐在车厢里飘。不一会儿师傅幽幽地发话:“女孩子喜欢玩电子,挺少见哪。”

我慌忙摆手,“说不上喜欢啦,不过是想做些作品时被迫营业罢了。”

师傅笑笑,“少做点焊接,松香那些东西(后面没听清楚)。”

后来我们提起人工费真是很贵(这次给玲玲阿姨的报酬逾千元,虽然与工作量相比并不多),对着各自可怜的补贴薪资感叹,师傅又顺势加入对话,聊了些诸如“免费劳动力总好过廉价劳动力”之类的话题。确实如此呢……

不一会儿到达目的地阿姨家,向师傅告别。不愧是北京的出租车司机。

阿姨已经去上班,仍然在家的叔叔将缝合好的装置交给我们。到最后也不知道是不是熬了大夜呢……也不好意思多问,唉。

重新打车前往展览场地。车停在热闹的市中心,周围人来人往,看来真是个好地方。场地位于广场的地下二层,在楼梯上走着走着,恍惚间仿佛回到了暑假的展览。是不是睡太少了。

进门却只见一片空白,装展品的箱子堆放在地上,墙面空荡荡的,有些地方还在粉刷。明天是开展日来着?我是不是真的穿越回暑假了……?

听工作人员说确实是延期了,安排明后天布展,16 日开展。今天未必能腾出地方给我们工作。

不知哪里冒出一个负责人模样的老师(姑且称其为 A),问我们这个装置是什么,并说可以做小点然后量产。然后赶紧说是开玩笑,现在这样挺好的。不过我们也是认真考虑过的哦,怎么说呢,也许 A 还是有些洞见在的?

既然没法工作,那就算啦。和 Y 简单合计传感单体的数目,并数了一下伸出的导线,数量都是 59,恰好能由五块传感芯片的 60 个通道完全覆盖。真是巧得很。接着把装置寄存在场地角落便匆匆离开。

堆在墙角的油画与套着黑色大塑料袋的毛绒玩具装置。

艺术,艺术

和 Y 在周围逛了一小圈,拜访了香氛艺术馆和 MUJI HOTEL。附近的氛围真不错,很适合闲逛的样子。只可惜最近一点都闲不下来。

下午回到学校和训练中心的另一位老师 Q 联系,问有没有可能给电路板做一个 3D 打印的外壳,得到肯定的答复。说干就干,立刻开始下载 FreeCAD,在晚上训练中心的课上画完了外壳,与 Q 老师约好第二天来打印,顺便找 Z 老师检查电路板(居然那么顺利!)。

圆形外壳白模效果图,分为上下两部分,通过卡槽相连,顶面有一个洞,侧面留出窄缝。

晚上订单 7(USB 线等)送达。一切都在按部就班地向最理想的方向前进呢!

10.13

早上拜访训练中心大楼,但是表贴的 Z 老师似乎忙得团团转,站在门外看了一会儿便离开,给老师留言说下午也可以。然后找 Q 老师操作打印机。

切片工具显示要 7 小时,盯了一会儿感觉底面的支撑平台(Raft)似乎过于厚了,便现场学习 Raft、Brim 和 Skirt 的区别,最终认为可以选择 Brim。时间降至 5 个半小时。

3D 打印模型处理软件界面。显示需 5 小时 39 分钟。

然后便是饭点,打印机不能在无人看管的状态下运行,故没有启动。收到 Z 老师消息说临时忙了起来,而且下午有课,脱不开身了。明天一大早就要去布展,只好先不考虑那边的问题啦,等展览结束拿回来再说。

下午取到订单 7(USB 线等)包裹,然后回到训练中心,启动打印机。

3D 打印机状态显示屏。

自己在一旁调程序,尝试加上自动重校准功能(读数超出范围时触发 MPR121 的自动配置),以保证更稳定地长期运行。

然而过了许久,打印机里面还是只有两圈断断续续的圆环。该不会是喷头堵住了吧?赶紧去找老师,得到答复确实如此(并且被指出不等冷却直接关机的错误操作)。忽然想起开机前的面板上已经有一小坨黑色树脂材料,该不会是它的缘故吧。不太懂呢。

修复过后已是下午,剩余的时间不足以完成打印了,只好暂时搁置。

新的仿真器还没来得及作修改,仍然不支持 SWV 调试输出。考虑到现场调试还是需要持续输出传感读数以便观察,晚上临睡前做了一个模拟调试输出的方案。原本考虑过 semihosting🪐,但它需要修改链接器参数,在 PlatformIO 工作流中并不方便。自制的方案虽然很慢,但只需要普通的 GDB。原理是修改 SWV 单字符输出例程,保存输出内容,在每行结尾调用一个子过程 swv_trap_line()

static inline void swv_putchar(uint8_t c)
{
  // 取消原本的 SWV 输出
  // ITM_SendChar(c);
  if (c == '\n') {
    swv_buf[swv_buf_ptr++] = '\0';
    swv_trap_line();
    swv_buf_ptr = 0;
  } else if (swv_buf_ptr < (sizeof swv_buf) - 1) {
    swv_buf[swv_buf_ptr++] = c;
  }
}

然后在 gdbinit 配置里用断点触发指令:

b swv_trap_line
commands
  silent
  printf "%s\n", swv_buf
  continue
end

用 GDB 调试时就会自动打印并继续了。

一切都就绪啦。

10.14

两人一早乘坐地铁出发。在北京这种地方居然能在一小时内抵达,真是少见。

今天的任务是把装置内引出的导线焊在电路板周围的孔上,然后调试灵敏度;最后上传声音并对接传感器,完成播放。

桌上的毛绒装置底部与电路板。

胜利会师!

先迅速完成喇叭与导线的焊接。途中艰难分辨哪些是同一捆——到后来有些散开的实在辨别不清,而纱线的电阻与接触质量又不一定足够万用表蜂鸣档位,决定直接放弃、以任意顺序连接传感引脚,大不了在程序中多写几个范围。

装置底面布口袋中伸出的一捆捆白色导线焊接在电路板周围的孔中。
连接数十根导线的电路板特写。

尝试读出读数,屏幕上的变化十分明显。用手机备忘录记下每个区域对应的引脚编号范围。

激动之余,悬着的心终于放了下来。其实严格来说,原型到这才算真正全部完成呢。

用手触摸装置感应区域,一旁的电脑屏幕上显示许多读数。

在附近找了一家面馆吃饭,下午回到场地继续工作。

首先是补全缺失的弹跳声音,在拉扯铃铛时播放。带来的电脑不常用于制作声音,上面的 GarageBand 也没有声音库。正准备尝试上网搜索时 Y 拿出自己的笔记本电脑,上面的 GarageBand 可以正常使用。火速用吉他滑音搓出几个调皮的“弹跳”音效。

把所有声音放进 QOA 压缩,再用之前的脚本上传,一切正常。

弹跳音效🎞1014-Bend.mp4(135 KiB, 00:03, 960x540)

Y 最近很辛苦的样子,到这时已经在一旁的沙发上睡着了。正好,上传声音、改写程序、调整阈值的工作都可以悄悄完成。只是场馆里的老师们似乎非常关心我们的进度,每小时都有人来问我们“布展进度如何”——其实我们是在现场制作哒!作为整个展览唯一的互动装置,还蹲在这里现场干活,简直就是显眼包。

时间来到晚上七点,我们把装置搬到预定的展位。工作也进入收尾阶段。仍然确实的部分包括毛绒揉搓区域的噪声、弦乐的淡入淡出效果,以及拉扯铃铛时的音效。

毛绒揉搓区域的传感数值很奇怪,四处乱跳;触摸时有的电极读数增加,有的减小,不可捉摸。我灵机一动,想到可以把整片区域的十个电极读数值全部加起来,这样大约只要检测总和的变化量就可以判断触发——我兴奋地嚷嚷:“哈哈哈!我是个天才!

——四下寂静无声,好像只有最后这一句话在空荡荡的场馆里飘。

“啊不是,也没有,不是那个意思……”我慌忙给自己找台阶下(什么糟糕的台阶)。你们工作人员怎么都不说话的!快说话啊!别看我啊!

总之把算法改成求和、又试了试截尾平均,效果都不尽如人意,数字仍然乱飞,很难分辨是否是误触。不知道是不是这次拆开把线搞乱了,搭在一起的导电线头太多了。

突发奇想翻出之前 Arduino 版本的程序,原来当时的做法也是加起来。看来我过了那么久还是一点没变呢!啊不是,那为什么当时就那么灵敏啊。哎,算了,战略性放弃。弦乐的淡入淡出倒是容易做,很快完工。

途中 U3 莫名也开始读数为 0,与 U4 的表现完全一致。正准备继续“战略性放弃”时,模糊的印象浮上面前——前些天焊接时似乎确实漏掉了一个点。居然能正确运作那么长时间也真是够奇妙的。

布袋中的电路板特写,其中一个电容的一侧完全没有焊锡。

注意看,这个电容叫 C14,它有一个脚根本没有焊

修复后一切恢复正常。虚惊一场。

这时冒出一个 A,和其他人一样询问我们的进度,然后用如往常一般的亲切语气说希望我们尽快,“我们这里是有时间节点的,九点钟之前需要整体检查一遍”。

我小声嘀咕:就这还时间节点啊,怎么不提你们不告诉我们安排,还擅自延期,害得我们白跑一趟呢!现在反倒知道节点了!不给你们这个展做了,要做我们拿回去自己做。

在 Y 的劝说下还是做完了拉扯铃铛的音效,结果出乎意料地有趣。原本在拉伸期间也设计了音效(最后的“ber~”之前的“呜——”声音),但因为一心只想快点收工,没来得及摸清读数变化规律,便选择搁置。

急着下班的后果就是在程序里直接写 ber 这种词……

static int8_t ber_ch = -1;
static uint8_t ber_timestamp;
// ...
if (ber_ch != -1 && sampler.channels[ber_ch].enabled != ber_timestamp)
  ber_ch = -1;
拉扯效果🎞1014-Bounce.mp4(1.0 MiB, 00:17, 270x480)

在站台四周铺好草绿色地毯,一旁的电视也已经就位。插上电源,一切顺利运转。

摆放在展台上的毛绒玩具装置。

无论如何,总算是可以收工啦。

拼图,火锅与鸡蛋虾球。
permalink | by Ayu