查看“︁Demo:DMA”︁的源代码
←
Demo:DMA
跳转到导航
跳转到搜索
因为以下原因,您没有权限编辑该页面:
不允许您执行您所请求的操作。
您可以查看和复制此页面的源代码。
=== Demo介绍: === 这部分代码保存在SDK下的:/examples/peripherals/dma/ 中。展示了不同模式下的dma运行情况,测试dma外设的功能完整性。 在该SDK中,dma的搬运行为被构建成一个LLI,系统根据LLI不断向下搬运直到最终节点。 === dma_normal: === 该部分代码测试了内存到内存的基本dma运送。共搬运数据三组,字节对齐为32位。搬运模式为一次性搬运。 '''数据字节对齐式初始化:''' 这里这里以32位对齐是为了配合后面DMA读取。<syntaxhighlight lang="c" line="1"> static __attribute((aligned(32))) uint8_t src1_buffer[DMA_BUFFER_LENGTH]; static __attribute((aligned(32))) uint8_t src2_buffer[DMA_BUFFER_LENGTH]; static __attribute((aligned(32))) uint8_t src3_buffer[DMA_BUFFER_LENGTH]; static __attribute((aligned(32))) uint8_t dst1_buffer[DMA_BUFFER_LENGTH]; static __attribute((aligned(32))) uint8_t dst2_buffer[DMA_BUFFER_LENGTH]; static __attribute((aligned(32))) uint8_t dst3_buffer[DMA_BUFFER_LENGTH]; </syntaxhighlight>'''DMA配置解析:''' 方向配置为:内存到内存; 优先级都配置为: 0,是最高优先级; 目标和源数据指针都为递增; 突发传输次数配置都为 1; 数据宽度都为 32位置。<syntaxhighlight lang="c" line="1"> config.direction = DMA_MEMORY_TO_MEMORY; config.src_req = 0; config.dst_req = 0; config.src_addr_inc = DMA_ADDR_INCREMENT_ENABLE; config.dst_addr_inc = DMA_ADDR_INCREMENT_ENABLE; config.src_burst_count = DMA_BURST_INCR1; config.dst_burst_count = DMA_BURST_INCR1; config.src_width = DMA_DATA_WIDTH_32BIT; config.dst_width = DMA_DATA_WIDTH_32BIT; </syntaxhighlight> ==== '''突发次数:''' ==== 突发次数就是突发传输,是指在DMA占用总线时,一个周期里读或者写的次数。注意,虽然双方都配置了突发次数,但是'''并不是同时进行而是先读后写'''。 比如,源数据的突发传输次数设定为4,目标写的突发次数为2,则是先读取四次,然后再写入两次。'''''这里的突发读/写每次都会出发指针的递增'''''。 ==== '''部分输出:''' ==== <syntaxhighlight lang="bash" line="1"> =========================== uart sig1:ffffffff, sig2:0000f32f clock gen1:9ffffffd, gen2:0fff0c11 xtal:40000000Hz(crystal) board init done =========================== dma memory case: tc done tc done tc done copy finished with time=353us case end </syntaxhighlight> === dma_normal_cycle: === 该部分代码和上述代码的配置一致,但是该代码为循环搬运。 不同的地方在于:<syntaxhighlight lang="c" line="1"> int used_count = bflb_dma_channel_lli_reload(dma0_ch0, lli, 20, transfers, 3); bflb_dma_channel_lli_link_head(dma0_ch0, lli, used_count); //该函数将链表进行了头尾相接 bflb_dma_channel_start(dma0_ch0); </syntaxhighlight>'''链表头尾相接变成了环''',所以程序将会重复循环搬运构建的链表内的所有item。 ==== '''部分输出:''' ==== <syntaxhighlight lang="bash" line="1"> tc done tc done tc done tc done tc done tc done tc done tc done tc done tc done tc done tc done tc done tc done tc done tc done tc done tc done end </syntaxhighlight>按照demo,应该触发一百次中断函数,所以应该有100次 tc done === dma_reduce_or_add: === 这部分代码主要展示了两个模式在不同的情况下的应用,并且展示了普通模式下当目标数据和源数据宽度不同时应该怎么传输数据和当应该使用模式但没有使用时会产生什么样的负面效果。 ==== '''Add与Reduce模式说明:''' ==== Add和Reduce模式从狭义来判断是当目标数据宽度和源数据宽度不匹配时使用。 但事实并不仅仅如此,'''本demo在第一段代码的配置中就展示了即使数据宽度不匹配也可以在normal模式下通过设置配置来运行''':<syntaxhighlight lang="c" line="1"> config.direction = DMA_MEMORY_TO_MEMORY; config.src_req = 0; config.dst_req = 0; config.src_addr_inc = DMA_ADDR_INCREMENT_ENABLE; config.dst_addr_inc = DMA_ADDR_INCREMENT_ENABLE; config.src_burst_count = DMA_BURST_INCR1; config.dst_burst_count = DMA_BURST_INCR4; config.src_width = DMA_DATA_WIDTH_32BIT; config.dst_width = DMA_DATA_WIDTH_8BIT; </syntaxhighlight>通过设定 burst 突发次数来配合宽度,最终使得:'''源宽度*突发次数 = 目标宽度*突发次数''' <big>则可以完整的将数据正确的传输过去</big>。 <big>那什么情况下使用Add和Reduce?</big> 答案是要'''参考数据总量''',比如:<syntaxhighlight lang="c"> /* Disable reduce mode and enable add mode, src_width = 8bit, dst_width = 32bit, nbytes = 65, transfer length = nbytes + 3 = 68 byte, multiple of dst_width */ bflb_dma_feature_control(dma0_ch0, DMA_CMD_SET_REDUCE_MODE, 0); bflb_dma_feature_control(dma0_ch0, DMA_CMD_SET_ADD_MODE, 1); config.src_burst_count = DMA_BURST_INCR4; config.dst_burst_count = DMA_BURST_INCR1; config.src_width = DMA_DATA_WIDTH_8BIT; config.dst_width = DMA_DATA_WIDTH_32BIT; bflb_dma_channel_init(dma0_ch0, &config); bflb_dma_channel_tcint_mask(dma0_ch0, false); transfers[0].nbytes = DMA_TRANSFER_LENGTH + 1; //这里更改设置总传输量为65字节 bflb_dma_channel_lli_reload(dma0_ch0, lli, 20, transfers, 1); bflb_dma_channel_start(dma0_ch0); </syntaxhighlight>当目标数据宽度是32位4字节,而源数据的宽度是8位一字节,'''拿65/4 = 16 余下 1,也就是说最后一次传输会仅仅传输一字节数据向一个宽度为四字节的变量'''。假设这里不是变量而是寄存器,那么就有可能写不进去(可能识别错误)。那么<big>'''Add在这里的作用就是:字节对齐'''</big>。它会自动补全后面的数据,也就是补出来3字节的数据,''这就是什么注释中说最后的实际传输数据是65 + 3= 68 byte。'' 而Reduce模式,在本demo中仅仅是测试,没有给出实际的需求场景。 在实际场景中的应用一般是在如下情况:假设当目标宽度为32位,数据源宽度为8位,读取总量设定为61字节。 61 / 4 = 15 余下 1。此时必须再次读取,但是读取的四字节中只有一字节要使用,假设寄存器读取后就会复位,那么这里就会错误操作。所以reduce模式就可以在这种情况下使用,它会规定用户设定的传输总量为最大读取字节数,<big>'''reduce的作用就是:防止过量读取。'''</big> 在配置上可以参考这个: {| class="wikitable" !模式 !适用场景 !配置公式 !效果 |- |Reduce |<nowiki>源宽度 > 目标宽度 || 不希望过度读取</nowiki> |nbytes = 期望 + 目标宽度 |实际传输 = 期望 |- |Add |<nowiki>目标宽度 > 源宽度 || 需要字节对齐写入数据</nowiki> |nbytes = 期望 |实际传输 = 对齐(期望) |} ==== 部分输出: ==== <syntaxhighlight lang="bash" line="1"> =========================== uart sig1:ffffffff, sig2:0000f32f clock gen1:9ffffffd, gen2:0fff0c11 xtal:40000000Hz(crystal) board init done =========================== dma memory case: tc done Check over tc done Check over tc done Correct, meaningless data. index: 65, src: 0x41, dst: 0x31 Correct, meaningless data. index: 66, src: 0x42, dst: 0x32 Correct, meaningless data. index: 67, src: 0x43, dst: 0x33 Check over tc done Check over end </syntaxhighlight>可以看到在最终的没有添加add模式的情况下,出现了无意义数据。
返回
Demo:DMA
。
导航菜单
个人工具
登录
命名空间
页面
讨论
大陆简体
查看
阅读
查看源代码
查看历史
更多
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息