3.1 AXI Timer
3.1.1 Timer 寄存器映射
查看该 IP 的所有寄存器映射,非常方便。
print(timer0.register_map)
print(timer1.register_map)
---
RegisterMap {
TCSR0 = Register(MDT0=0, UDT0=1, GENT0=1, CAPT0=0, ARHT0=0, LOAD0=0, ENIT0=1, ENT0=0, T0INT=0, PWMA0=0, ENALL=0, CASC=0),
TLR0 = Register(TCLR0=100000000),
TCR0 = Register(TCR0=4294967295),
TCSR1 = Register(MDT1=0, UDT1=0, GENT1=0, CAPT1=0, ARHT1=0, LOAD1=0, ENIT1=0, ENT1=0, T1INT=0, PWMA1=0, ENALL=0),
TLR1 = Register(TCLR1=0),
TCR1 = Register(TCR1=0)
}
RegisterMap {
TCSR0 = Register(MDT0=0, UDT0=1, GENT0=0, CAPT0=0, ARHT0=0, LOAD0=0, ENIT0=1, ENT0=0, T0INT=0, PWMA0=0, ENALL=0, CASC=0),
TLR0 = Register(TCLR0=200000000),
TCR0 = Register(TCR0=4294967295),
TCSR1 = Register(MDT1=0, UDT1=0, GENT1=0, CAPT1=0, ARHT1=0, LOAD1=0, ENIT1=0, ENT1=0, T1INT=0, PWMA1=0, ENALL=0),
TLR1 = Register(TCLR1=0),
TCR1 = Register(TCR1=0)
}
3.1.2 Timer 中断信息
本例中使用了两个 Timer,可以查看各自的信息:
timer0 = ol.axi_timer_0
timer0._interrupts
---
{'interrupt': {'controller': 'axi_intc_0',
'index': 0,
'fullpath': 'axi_timer_0/interrupt'}}
timer1 = ol.axi_timer_1
timer1._interrupts
---
{'interrupt': {'controller': 'axi_intc_0',
'index': 1,
'fullpath': 'axi_timer_1/interrupt'}}
或者通过 ol.interrupt_pins 查看:
ol.interrupt_pins
---
controller:"axi_intc_0"
index:0
fullpath:"axi_timer_0/interrupt"
controller:"axi_intc_0"
index:0
fullpath:"xlconcat_0/In0"
controller:"axi_intc_0"
index:1
fullpath:"axi_timer_1/interrupt"
controller:"axi_intc_0"
index:1
fullpath:"xlconcat_0/In1"
3.1.3 脉冲信号
1)单个脉冲信号
timer0.register_map.TLR0 = 100_000_000 # Timmer Load Register
timer0.register_map.TCSR0.LOAD0 = 1 # TLR -> TCR
timer0.register_map.TCSR0.LOAD0 = 0 # 启动计数(TCSR0.ENT0)前,应清除此位
timer0.register_map.TCSR0.ARHT0 = 0 # 0 = Hold counter
timer0.register_map.TCSR0.GENT0 = 1 # 1 = Enables generate_out
timer0.register_map.TCSR0.ENIT0 = 1 # 1 = Enable Interrupt
timer0.register_map.TCSR0.UDT0 = 1 # 1 = Down Count
timer0.register_map.TCSR0.ENT0 = 1 # 1 = Enable Timmer
print('timer0 configured')
2)生成周期性的脉冲信号,参考以下代码:
timer0.register_map.TLR0 = 100_000_000 # Timmer Load Register
timer0.register_map.TCSR0.LOAD0 = 1 # TLR -> TCR
timer0.register_map.TCSR0.LOAD0 = 0 # 启动计数(TCSR0.ENT0)前,应清除此位
timer0.register_map.TCSR0.ARHT0 = 1 # 1 = Reload generate value
timer0.register_map.TCSR0.GENT0 = 1 # 1 = Enables generate_out
timer0.register_map.TCSR0.ENIT0 = 1 # 1 = Enable Interrupt
timer0.register_map.TCSR0.UDT0 = 1 # 1 = Down Count
timer0.register_map.TCSR0.ENT0 = 1 # 1 = Enable Timmer
print('timer0 configured')
3.2 PYNQ 中断示例
import pynq
import asyncio
import nest_asyncio
# 允许嵌套的事件循环
nest_asyncio.apply()
ol = pynq.Overlay('min6.bit')
ol.ip_dict
timer0 = ol.axi_timer_0
timer1 = ol.axi_timer_1
intc = ol.axi_intc_0
def intr_done():
timer0.register_map.TCSR0.T0INT = 1 # Clear T0INT,清除中断标志
timer0.register_map.TCSR0.ENT0 = 0 # 0 = Disable Timmer
timer1.register_map.TCSR0.T0INT = 1 # Clear T0INT,清除中断标志
timer1.register_map.TCSR0.ENT0 = 0 # 0 = Disable Timmer
intc.register_map.IAR = 0x03 # Clear interrupt
async def wait_for_timer0(cycles):
print('timer0 start')
timer0.register_map.TLR0 = cycles # Timmer Load Register
timer0.register_map.TCSR0.LOAD0 = 1 # TLR -> TCR
timer0.register_map.TCSR0.LOAD0 = 0 # 启动计数(TCSR0.ENT0)前,应清除此位
timer0.register_map.TCSR0.ARHT0 = 0 # 0 = Hold counter
timer0.register_map.TCSR0.GENT0 = 1 # 1 = Enable generate_out
timer0.register_map.TCSR0.ENIT0 = 1 # 1 = Enable Interrupt
timer0.register_map.TCSR0.UDT0 = 1 # 1 = Down Count
timer0.register_map.TCSR0.ENT0 = 1 # 1 = Enable Timmer
await timer0.interrupt.wait()
timer0.register_map.TCSR0.ENT0 = 0 # 0 = Disable Timmer
timer0.register_map.TCSR0.T0INT = 1 # Clear T0INT,清除中断标志
print('timer0 done')
async def wait_for_timer1(cycles):
print('timer1 start')
timer1.register_map.TLR0 = cycles # Timmer Load Register
timer1.register_map.TCSR0.LOAD0 = 1 # TLR -> TCR
timer1.register_map.TCSR0.LOAD0 = 0 # 启动计数(TCSR0.ENT0)前,应清除此位
timer1.register_map.TCSR0.ARHT0 = 0 # 0 = Hold counter
timer1.register_map.TCSR0.GENT0 = 0 # 0 = Disable generate_out
timer1.register_map.TCSR0.ENIT0 = 1 # 1 = Enable Interrupt
timer1.register_map.TCSR0.UDT0 = 1 # 1 = Down Count
timer1.register_map.TCSR0.ENT0 = 1 # 1 = Enable Timmer
await timer1.interrupt.wait()
timer1.register_map.TCSR0.ENT0 = 0 # 0 = Disable Timmer
timer1.register_map.TCSR0.T0INT = 1 # Clear T0INT,清除中断标志
print('timer1 done')
async def main():
task0 = asyncio.create_task(wait_for_timer0(100_000_000)) # 2s Max 4_294_967_295 cycles
task1 = asyncio.create_task(wait_for_timer1(200_000_000)) # 4s
await task0
await task1
intr_done()
asyncio.run(main())
PYNQ 框架中的硬件中断,不同于传统微控制器的中断服务程序(ISR),PYNQ 使用 Python 的异步编程模式来处理中断,这种方法更加灵活和高级。
PYNQ 中的中断处理机制:使用异步等待。
通过使用 asyncio 库中的 await 关键字,可以异步等待中断事件,Python 代码可以在不阻塞整个程序的情况下,等待硬件事件的发生。
await timer0.interrupt.wait()
这行代码实际上是在等待来自 timer 的中断信号。当中断发生时(计时器达到预设的计数值),这个等待状态会结束,程序将继续执行下一行代码。这与传统的中断服务程序在概念上有些相似,但在实现上更加现代和适合高级语言。
优势:
非阻塞:使用异步等待中断使得CPU可以在中断未发生时处理其他任务,这在多任务环境中非常有用。
简化的错误处理和资源管理:在 Python 的异步环境中,错误处理和资源管理可以通过现代编程实践(如上下文管理、异常处理等)来实现,这比传统的 ISR 中的错误处理和资源管理要简单和安全。