Linux 中的dmaengine显着简化了为使用 DMA 的设备编写驱动程序,特别是如果它们支持和使用分散-聚集 (SG) 传输。
然而,如果这种传输的长度事先未知,则存在问题。这种情况相当普遍。在 USB 传输或 AXI Stream 传输的情况下可能会发生这种情况。对于 AXI Stream 连接的设备,应通过将 tlast 信号设置为“1”来终止传输。驱动程序应该为尽可能长的传输准备缓冲区,但在传输完成后,它应该能够找到实际传输的字节数。不幸的是,似乎没有记录的方法来读取已完成传输的长度。
单一传导表示用SG-表,即后来转化为dma_async_tx_descriptor,使用dmaengine_prep_slave_sg功能,提交给DMA层(例如像在这里),最后经由调度执行dma_async_issue_pending。之后,只能通过 dmaengine_prep_slave_sg 函数返回的 dma_cookie 访问传输描述符。
为 USB 传输报告了确定传输实际长度的问题,并提出了将该字段添加到 dma_async_tx_descriptor的补丁transferred
。然而,该提议被拒绝了,经过讨论后,基于使用dmaengine_tx_status并检查返回的dma_tx_state结构中的字段 的解决方案。residue
不幸的是,所提议的解决方案似乎既不适用于 4.4 内核(用于 Xilinx SoC 器件),也不适用于最新的 4.7 内核。无论实际传输的字节数是多少,在完成传输的情况下,该residue
字段都设置为 0。
所以我的问题是:如何在 dmaengine 兼容驱动程序中可靠地确定已完成的 SG DMA 传输中实际传输的字节数?
附注。Xilinx 论坛上也提出了有关与 AXI DMA IP 核相关的更多 Xilinx 特定细节的问题。
我需要实现一个具有多个退出点的不确定循环。不幸的是,最明显的解决方案 - REPEAT - UNTIL with multiple WHILE 在 Gforth 和 swapforth 中都不起作用(当然,下面示例中的循环可以用 DO - LOOP 实现。但是,该代码只是一个演示。真正的问题与嵌入式系统中的硬件控制有关,因此循环确实必须是不确定的):
: test1 ( step -- step count )
0
begin
over +
dup .
dup 20 < while
dup 13 = while
repeat
;
3 test1
Run Code Online (Sandbox Code Playgroud)
在“Thinking Forth”中引用了摩尔的声明:
很多时候条件语句被用来跳出循环。可以通过具有多个退出点的循环来避免这种特殊用途。这是一个实时主题,因为在 poly-Forth 中存在多个 WHILE 结构,但还没有渗透到 Forth '83。这是在同一个 REPEAT 中定义多个 WHILE 的简单方法。此外,[Forth, Inc.] 的 Dean Sanderson 发明了一种新结构,该结构将两个出口点引入 DO LOOP。鉴于这种结构,您将进行更少的测试。
不幸的是我没有找到院长的解决方案。是否有任何可移植的方式在 Forth 的无限循环中实现多个退出点?
我使用 Forth(即Swapforth)通过 I2C配置某些硬件。我有一句话:
i2c1-send ( reg-address byte -- )
Run Code Online (Sandbox Code Playgroud)
将一个字节写入某个芯片的特定内部寄存器。初始化序列很长,因此由于内存消耗,如下实现它是不可行的。
: i2c1-init
$1201 $10 i2c1-send
$2130 $43 i2c1-send
[...]
$0231 $43 i2c1-send
;
Run Code Online (Sandbox Code Playgroud)
我创建了一个实现,该实现创建了一个结构,该结构包含第一个单元格中的序列长度和下一个单元格中的三个字节。(请注意,i2c1-send 只是一个占位符,允许您在没有我的硬件的情况下对其进行测试)。
: i2c1-send ( reg_addr byte -- )
\ It is just a placeholder to show what will be written in HW
swap
." addr=" hex . ." val=" . decimal CR
;
: i2c1: ( "<spaces>name" -- )
create here $326e9 0 ,
does> dup cell+ swap
@ 0 do
dup …
Run Code Online (Sandbox Code Playgroud)