Ultra96 PYNQ入门之三——中断与协程
不合理的地方欢迎批评指正!!!
源代码链接:Ultra96-PYNQ_A-simple-summary
1 协程入门
个人感觉这个博主讲的挺全面的,想全面了解协程的小伙伴,可以移步如下链接
- asyncio 学习笔记:基本用法
- asyncio 学习笔记:调用定时函数
- asyncio 学习笔记:并发执行 Task
- asyncio 学习笔记:产生异步结果
- asyncio 学习笔记:控制组合式 Coroutines
- asyncio 学习笔记:同步原语
- asyncio 学习笔记:使用抽象类 Protocol 实现异步 I/O
如不想全面性了解协程这个东西,可以看下我的简练的总结,可以看懂如下的实验,只不过没法进一步个性化设计。
- 在线程中创建一个协程循环
start_loop = asyncio.get_event_loop()
- 完成协程直至返回
return_value = start_loop.run_until_complete(button_led())
- 协程中等待
await button_inter.wait_for_value_async(1)
,等待属于异步操作,并不占用CPU。可以创建多个协程,相应多个中断,这个会在后面提及。
注:目前个人感觉协程这个东西,和裸机开发中的中断还是有区别的,属于软件调度的中断?效率不咋高,所以千万不要在1秒内相应上千个中断,否则你会发现中断执行的时间还没有中断触发的时间延迟长呢。
2 PYNQ的中断使用
2.1 硬件设计
很简单的一个设计,可以在Vivado中的TCL控制台通过如下命令,进行快速重建
source 3.axi_gpio_interrupt.tcl
- button用于检测中断
- led用于显示中断的情况
button、led均用口袋仪器仿真
中断控制器这里,仅实验了默认的高电平中断,小伙伴可以尝试边沿中断,来进行实验
2.2 中断的使用
2.2.1 一个不恰当的例子
软件代码如下
import time
from pynq import Overlay
import asyncio
gpio_inter_design = Overlay("./data/3.AXI_GPIO_Interrupt.bit")
button_inter = gpio_inter_design.axi_gpio_0.Input( parent=gpio_inter_design.axi_gpio_0.channel1,
start=0, stop=1 )
led = gpio_inter_design.axi_gpio_0.Output( parent=gpio_inter_design.axi_gpio_0.channel2,
start=0, stop=1 )
async def button_led():
for i in range(10):
start = time.time()
await button_inter.wait_for_value_async(1)
led.toggle()
end = time.time()
print("中断的周期 :{}s".format(end -start))
start_loop = asyncio.get_event_loop()
return_value = start_loop.run_until_complete(button_led())
button利用信号发生器模拟,1Hz、1.8V、5%的脉冲波
实验的结果惨不忍睹
中断的周期 :0.6854667663574219s
中断的周期 :6.651878356933594e-05s
中断的周期 :5.888938903808594e-05s
中断的周期 :5.817413330078125e-05s
中断的周期 :5.888938903808594e-05s
中断的周期 :5.745887756347656e-05s
中断的周期 :5.745887756347656e-05s
中断的周期 :5.793571472167969e-05s
中断的周期 :5.817413330078125e-05s
中断的周期 :5.8650970458984375e-05s
分析原因
中断控制器采用了默认的高电平中断,即使中断之后清除中断,由于是高电平触发,中断控制器仍然定义发生了中断。
2.2.2 恰当的操作
- 软件代码如下
import time
from pynq import Overlay
import asyncio
gpio_inter_design = Overlay("./data/3.AXI_GPIO_Interrupt.bit")
button_inter = gpio_inter_design.axi_gpio_0.Input( parent=gpio_inter_design.axi_gpio_0.channel1,
start=0, stop=1 )
led = gpio_inter_design.axi_gpio_0.Output( parent=gpio_inter_design.axi_gpio_0.channel2,
start=0, stop=1 )
async def button_led():
for i in range(10):
start = time.time()
await button_inter.wait_for_value_async(1)
led.toggle()
await asyncio.sleep(0.05)
end = time.time()
print("中断的周期 :{}s".format(end -start))
start_loop = asyncio.get_event_loop()
return_value = start_loop.run_until_complete(button_led())
使用await asyncio.sleep(0.05)
跳过高电平脉冲时间,即可正确的产生中断。
- 软件输出
中断的周期 :0.1248316764831543s
中断的周期 :0.9994022846221924s
中断的周期 :0.9997074604034424s
中断的周期 :0.9996352195739746s
中断的周期 :0.999701738357544s
中断的周期 :0.9996013641357422s
中断的周期 :0.9996085166931152s
中断的周期 :1.0001087188720703s
中断的周期 :0.9996082782745361s
中断的周期 :0.9993538856506348s
同样button利用信号发生器模拟,1Hz、1.8V、5%的脉冲波,逻辑分析仪测试结果如下
这里仅演示了单高电平触发的中断,尝试利用协程实现多中断,充分利用CPU。
原创不易,严禁剽窃!
欢迎大家关注我创建的微信公众号——小白仓库
原创经验资料分享:包含但不仅限于FPGA、ARM、RISC-V、Linux、LabVIEW等软硬件开发,另外分享生活中的趣事以及感悟。目的是建立一个平台记录学习过的知识,并分享出来自认为有用的与感兴趣的道友相互交流进步。