📄 dma_systems.html
字号:
<span class="br0">{</span> <span class="kw4">char</span> mybuffer<span class="br0">[</span><span class="nu0">1024</span> * <span class="nu0">32</span><span class="br0">]</span>; <span class="kw4">int</span> mysize = <span class="nu0">1024</span> * <span class="nu0">32</span>; <span class="kw4">int</span> ret; <span class="co1">// lets ask for the DMA channel</span> ret = request_dma<span class="br0">(</span>CH_SPI,<span class="st0">"BF533 SPI Test"</span><span class="br0">)</span>; <span class="kw1">if</span> <span class="br0">(</span> ret < <span class="nu0">0</span> <span class="br0">)</span> <span class="br0">{</span> printk<span class="br0">(</span><span class="st0">" Unable to get DMA channel<span class="es0">\n</span>"</span><span class="br0">)</span>; <span class="kw1">return</span> <span class="nu0">1</span>; <span class="br0">}</span> <span class="co1">// turn off the DMA channel</span> disable_dma<span class="br0">(</span>CH_SPI<span class="br0">)</span>; <span class="co1">// set up the dma config</span> <span class="co1">// WNR We are going to write to memory</span> <span class="co1">// RESTART throw away any old data in the fifo</span> <span class="co1">// Enable Interrupts</span> set_dma_config<span class="br0">(</span>CH_SPI, <span class="br0">(</span> WNR | RESTART | DI_EN <span class="br0">)</span><span class="br0">)</span>; <span class="co1">// set address to drop data into</span> set_dma_start_address<span class="br0">(</span>CH_SPI, <span class="br0">(</span><span class="kw4">unsigned</span> <span class="kw4">long</span><span class="br0">)</span>&mybuffer<span class="br0">)</span>; <span class="co1">// set the transfer size in bytes</span> set_dma_x_count<span class="br0">(</span>CH_SPI,size<span class="br0">)</span>; <span class="co1">// set the X modify ( dont worry about Y for this one )</span> set_dma_x_modify<span class="br0">(</span>CH_SPI,<span class="nu0">1</span><span class="br0">)</span>; <span class="co1">// sync the cores up</span> __builtin_bfin_ssync<span class="br0">(</span><span class="br0">)</span>; <span class="co1">// off we go</span> enable_dma<span class="br0">(</span>CH_SPI<span class="br0">)</span>;</pre><p>Since this is going to use interrupts then the interrupt routine must be associated with the DMA channel.</p><pre class="code c"> <span class="co1">// set the IRQ callback</span> set_dma_callback<span class="br0">(</span>CH_SPI,<span class="br0">(</span><span class="kw4">void</span>*<span class="br0">)</span>myirq,mydata<span class="br0">)</span>;</pre><p>The IRQ routine could look like this. It simply clears the irq status.</p><pre class="code c"><span class="kw4">static</span> irqreturn_t myirq<span class="br0">(</span> <span class="kw4">int</span> irq, <span class="kw4">void</span> * data , <span class="kw4">struct</span> pt_regs *regs <span class="br0">)</span><span class="br0">{</span> unsigend <span class="kw4">short</span> mystat; mystat = get_dma_curr_irqstat<span class="br0">(</span>CH_SPI<span class="br0">)</span>; clear_dma_irqstat<span class="br0">(</span>CH_SPI<span class="br0">)</span>; wake_up_interruptible<span class="br0">(</span>&mywaiting_task<span class="br0">)</span>; <span class="kw1">return</span> IRQ_HANDLED;<span class="br0">}</span></pre></div><!-- SECTION [6840-8460] --><h3><a name="flow_types" id="flow_types">Flow Types</a></h3><div class="level3"><p> The above example used the most basic method to control the DMA device. The registers were loaded manually with configuration values and the DMA device enabled.</p><p>There is a collection of other methods to set the device up for more complex transfers. These may use blocks of data ( called descriptors ) that are automatically loaded into the configuration registers. One or more Descriptors can be chained together for complex data movements.</p><p>There are 5 different ways the DMA controller can be set up. These as called Flow types </p><ul><li class="level1"><div class="li"> FLOW_STOP - Stop after the current job </div></li><li class="level1"><div class="li"> FLOW_AUTO - Autobuffer, Repeat the current transfer until stopped </div></li><li class="level1"><div class="li"> FLOW_ARRAY - Use a sequential list of descriptors</div></li><li class="level1"><div class="li"> FLOW_SMALL - Use a linked list of small descriptors</div></li><li class="level1"><div class="li"> FLOW_LARGE - Use a linked list of large descriptors</div></li></ul><p> The flow type can be defined in a CONFIG word in a descriptor so the modes can be mixed and the operation quite complex.</p></div><!-- SECTION [8461-9418] --><h3><a name="descriptors" id="descriptors">Descriptors</a></h3><div class="level3"><p> This are used to control the DMA channel and allow a complex stream of data packet to be assembled if required.</p><p>One descriptor can point to another. If required they can be in a loop with the last pointing to the first. The contents of the descriptor are read into the DMA controller’s configuration registers as it starts</p><pre class="code"> * Array - Simple Sequential array of descriptors in memory* Small Descriptor - the High address word does not change just the Low addr word is in the memory array* Large Descriptor Both High and Low address words are in the memory array.</pre><p> The Descriptor is defined in the FLOW bytes in the DMA CONFIG register This config word may be updated in the descriptor.</p><p>So in the array case all the descriptors follow each other in memory. The CURR_DESC_PTR register must be set up and the DMA enabled.</p><p>The only difference between th Small and Large Descriptor modes is the restriction that all the descriptors must reside in the same 64K memory area defined by the High Memory word. In these cases the NEXT_DESC_PTR is set up to point to the first descriptor in the array.</p><p>One other slight complexity in the descriptor business is the fact the DMA controller does not have to read ALL of the words in the descriptor array. The NDSIZE part of the CONFIG Register contains the number of elements to read into the DMA controller for this operation. (Question if only part of a descriptor is used, does the next array descriptor start after the last word has been read or at the next descriptor boundary.)</p></div><!-- SECTION [9419-10978] --><h3><a name="descriptor_memory_layout" id="descriptor_memory_layout">Descriptor Memory Layout</a></h3><div class="level3"><p> Simple array descriptor: </p><pre class="code c"><span class="kw4">typedef</span> <span class="kw4">struct</span> _dmasgarray_t <span class="br0">{</span> <span class="kw4">unsigned</span> <span class="kw4">long</span> start_addr; <span class="kw4">unsigned</span> <span class="kw4">short</span> cfg; <span class="kw4">unsigned</span> <span class="kw4">short</span> x_count; <span class="kw4">unsigned</span> <span class="kw4">short</span> x_modify; <span class="kw4">unsigned</span> <span class="kw4">short</span> y_count; <span class="kw4">unsigned</span> <span class="kw4">short</span> y_modify;<span class="br0">}</span> dmasgarray_t;</pre><p>Small Descriptor (all in the same 64K page): </p><pre class="code c"><span class="kw4">typedef</span> <span class="kw4">struct</span> _dmasgsmall_t <span class="br0">{</span> <span class="kw4">unsigned</span> <span class="kw4">short</span> next_desc_addr_lo; <span class="kw4">unsigned</span> <span class="kw4">short</span> start_addr_lo; <span class="kw4">unsigned</span> <span class="kw4">short</span> start_addr_hi; <span class="kw4">unsigned</span> <span class="kw4">short</span> cfg; <span class="kw4">unsigned</span> <span class="kw4">short</span> x_count; <span class="kw4">unsigned</span> <span class="kw4">short</span> x_modify; <span class="kw4">unsigned</span> <span class="kw4">short</span> y_count; <span class="kw4">unsigned</span> <span class="kw4">short</span> y_modify;<span class="br0">}</span> dmasgsmall_t;</pre><p>Large Descriptor: </p><pre class="code c"><span class="kw4">typedef</span> <span class="kw4">struct</span> _dmasglarge_t <span class="br0">{</span> <span class="kw4">unsigned</span> <span class="kw4">long</span> next_desc_addr; <span class="kw4">unsigned</span> <span class="kw4">long</span> start_addr; <span class="kw4">unsigned</span> <span class="kw4">short</span> cfg; <span class="kw4">unsigned</span> <span class="kw4">short</span> x_count; <span class="kw4">unsigned</span> <span class="kw4">short</span> x_modify; <span class="kw4">unsigned</span> <span class="kw4">short</span> y_count; <span class="kw4">unsigned</span> <span class="kw4">short</span> y_modify;<span class="br0">}</span> dmasglarge_t;</pre></div><!-- SECTION [10979-11995] --><h3><a name="descriptor_api" id="descriptor_api">Descriptor API</a></h3><div class="level3"><ul><li class="level1"><div class="li"> set_desc_startaddr(void *pDescriptor, unsigned long startaddr, int flowtype);</div></li><li class="level1"><div class="li"> set_desc_xcount(void *pDescriptor, unsigned short x_count, int flowtype);</div></li><li class="level1"><div class="li"> set_desc_xmodify(void *pDescriptor, unsigned short x_modify, int flowtype);</div></li><li class="level1"><div class="li"> set_desc_ycount(void *pDescriptor, unsigned short y_count, int flowtype);</div></li><li class="level1"><div class="li"> set_desc_ymodify(void *pDescriptor, unsigned short y_modify, int flowtype);</div></li><li class="level1"><div class="li"> add_descriptor(void *pNewdescriptor, int channel_number, int flowtype);</div></li></ul></div><!-- SECTION [11996-12496] --><h3><a name="x_and_y_values" id="x_and_y_values">X and Y Values</a></h3><div class="level3"><p> The next topic describes how array data can be transferred via a DMA. Consider a data array of 16 bytes followed by 20 bytes of data that we don’t want There are 40 sets of data to be recorded.</p><p>The DMA transfer is to create a continuous block of just the data we want ( the 16 bytes ) and we want to skip the 20 ignored bytes.</p><p>In this case we want to read the first 16 bytes and then bump the next address pointer by 20.</p><p>To do this we would set up the following values: </p><ul><li class="level1"><div class="li"> X_MODIFY = 1 we want to skip one byte at a time</div></li><li class="level1"><div class="li"> X_COUNT = 16 do a Y_MODIFY after 16</div></li><li class="level1"><div class="li"> Y_MODIFY = 20 skip the next 20 bytes</div></li><li class="level1"><div class="li"> Y_COUNT = 40 we want 40 data sets.</div></li></ul></div><!-- SECTION [12497-13176] --><h3><a name="dma_priority" id="dma_priority">DMA Priority</a></h3><div class="level3"><p> The DMA system has a default priority define by the DMA Channel number </p><ul><li class="level1"><div class="li"> 0 PPI - highest</div></li><li class="level1"><div class="li"> 1 SPORT0RX </div></li><li class="level1"><div class="li"> 2 SPORT0TX</div></li><li class="level1"><div class="li"> 3 SPORT1RX </div></li><li class="level1"><div class="li"> 4 SPORT1TX</div></li><li class="level1"><div class="li"> 5 SPI </div></li><li class="level1"><div class="li"> 6 UART RX</div></li><li class="level1"><div class="li"> 7 UART TX</div></li><li class="level1"><div class="li"> 8 MEM DMA0 Dest</div></li><li class="level1"><div class="li"> 9 MEM DMA0 Source</div></li><li class="level1"><div class="li"> 10 MEM DMA1 Dest</div></li><li class="level1"><div class="li"> 11 MEM DMA1 Source</div></li></ul><p>With the exception of the MEM DMA channels the others can have their priority changed by modifying the DMAx_PERIPHERAL_MAP register.</p><p>You must change two at a time , make sure that both the DMA channels are disabled and that you swap their priorities. This makes sure that no two enabled DMA channels have the same DMA number and priority.</p><p>There are also a series of traffic control registers to manage bus data flow with multiple DMA channels running. These controls can manage data bursts through the system. </p><p>Read the Hardware Manual for more details. </p></div><!-- SECTION [13177-] --></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -