|
1 <?xml version="1.0" encoding="utf-8"?> |
|
2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. --> |
|
3 <!-- This component and the accompanying materials are made available under the terms of the License |
|
4 "Eclipse Public License v1.0" which accompanies this distribution, |
|
5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". --> |
|
6 <!-- Initial Contributors: |
|
7 Nokia Corporation - initial contribution. |
|
8 Contributors: |
|
9 --> |
|
10 <!DOCTYPE task |
|
11 PUBLIC "-//OASIS//DTD DITA Task//EN" "task.dtd"> |
|
12 <task id="GUID-FA026EBD-7867-4A2C-9FA4-EC70A5243526" xml:lang="en"><title>Transferring Data with DMA</title><shortdesc>Explains how to transfer data using DMA.</shortdesc><prolog><metadata><keywords/></metadata></prolog><taskbody> |
|
13 <prereq id="GUID-FCC97364-77B5-4AB9-AEBD-0F63500A522D"><p>The client |
|
14 will typically have a DMA class containing pointers to:</p><ul> |
|
15 <li><p>a <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita"><apiname>TDmaChannel</apiname></xref> object, </p> </li> |
|
16 <li><p>one or more <xref href="GUID-780F4D53-5546-3B69-B328-0226C70EBDE2.dita"><apiname>DDmaRequest</apiname></xref> objects, </p></li> |
|
17 <li><p>a <xref href="GUID-E675237D-0D05-30A3-9B82-DDD3D0F41E79.dita"><apiname>TDfcQueue</apiname></xref> object, and</p></li> |
|
18 <li><p>a callback which returns when the data transfer completes (successfully |
|
19 or not).</p></li> |
|
20 </ul><p>These classes are discussed in <xref href="GUID-D5ED62EB-744D-42EB-B8CF-D5623BDA5B38.dita">DMA OS Interface</xref>.</p></prereq> |
|
21 <context id="GUID-EAC78622-0692-4FBE-81FE-553F838A77DD"><p>To allow |
|
22 a client application to receive or transmit a block of data by DMA |
|
23 you set up a transfer between a source or a destination buffer and |
|
24 a source or a destination peripheral. Data is copied between the client |
|
25 process and kernel memory by IPC form data transfer between two buffers. |
|
26 When a shared chunk or a shared data buffer is used, copying of data |
|
27 to kernel memory is required. At the level of implementation there |
|
28 is no difference between receiving and transmitting. Client drivers |
|
29 using DMA sometimes have separate receive and transmit functions defined |
|
30 from the driver point of view.</p><p>You transfer data in this sequence:</p><ul> |
|
31 <li><p>Open a DMA channel.</p></li> |
|
32 <li><p>Fragment the data if necessary.</p></li> |
|
33 <li><p>Queue the transfer.</p></li> |
|
34 <li><p>Close the channel.</p></li> |
|
35 </ul><p>Example code in this tutorial is taken from the <xref href="GUID-8CC3B265-C29E-3FDB-ACE8-ACC49B9E69D5.dita"><apiname>DMemoryCardDma</apiname></xref> class which transfers data to and from MMC cards by DMA.</p></context> |
|
36 <steps id="GUID-4DD07DEC-6017-4237-BE46-1D69E5FBD744-GENID-1-2-1-10-1-5-1-5-1-1-7-1-9-1-7-1-3-3"> |
|
37 <step id="GUID-9A69E5AD-E938-4092-A8C2-CB65C37C8962-GENID-1-2-1-10-1-5-1-5-1-1-7-1-9-1-7-1-3-3-1"><cmd>Initialize |
|
38 the client object by allocating a request and setting buffers.</cmd> |
|
39 <info><codeblock xml:space="preserve"> //pre-allocate space for DDmaRequest |
|
40 iDMARequest = (DDmaRequest*)Kern::AllocZ(sizeof(DDmaRequest)); |
|
41 |
|
42 // Check Buffer Length |
|
43 if (aBuffLen) |
|
44 { |
|
45 // Set Buffer Start |
|
46 iBufferStart = (TUint32)aBuffer; |
|
47 // Set Buffer End |
|
48 iBufferEnd = iBufferStart + aBuffLen; |
|
49 // Set DFC Queue |
|
50 iDfcQue = aDfcQue; |
|
51 |
|
52 return KErrNone; |
|
53 } |
|
54 </codeblock></info> |
|
55 <stepresult>The client object is now initialized.</stepresult> |
|
56 </step> |
|
57 <step id="GUID-9A69E5AD-E938-4092-A8C2-CB65C37C8962-GENID-1-2-1-10-1-5-1-5-1-1-7-1-9-1-7-1-3-3-2"><cmd>Open the |
|
58 channel by creating an <xref href="GUID-4057074E-2543-3F01-B24A-7FF8A19F79AF.dita"><apiname>SCreateInfo</apiname></xref> object and initializing |
|
59 it as follows:</cmd> |
|
60 <substeps id="GUID-53B21565-D779-4B76-A8BA-8C9059CB15B4"> |
|
61 <substep id="GUID-3620E00A-FDE2-4EA3-9FB2-9D67AD0370AC"><cmd>Set the <xref href="GUID-B05C7976-F917-3CFC-9979-86FAC864CB4E.dita"><apiname>iCookie</apiname></xref> member to a platform specific channel identifier.</cmd> |
|
62 </substep> |
|
63 <substep id="GUID-1890DE64-D53B-4003-9419-ECC778D663FB"><cmd>Set the <xref href="GUID-84246C3A-C8C9-3839-B8C1-8BF05C826338.dita"><apiname>iDesCount</apiname></xref> member to the number of descriptors the channel |
|
64 can use.</cmd> |
|
65 <info><p>The value should be set to a value based on number of simultaneous |
|
66 transfers, transfer length and type of memory used for transfer. If |
|
67 you select too high a value, no descriptors will be left for other |
|
68 clients, and if you select too low a value the transfer may fail. </p></info> |
|
69 </substep> |
|
70 <substep id="GUID-FF5BB11D-C922-47A1-ADB8-1A7321C0931F"><cmd>Set the <xref href="GUID-D9C831A3-4841-3E4F-BFEC-8D3997BEEFFF.dita"><apiname>iDfcPriority</apiname></xref> member to the DFC priority. </cmd> |
|
71 </substep> |
|
72 <substep id="GUID-F1D4A3C1-6E81-4FA4-99D0-E127FCD2C004"><cmd>Set the <xref href="GUID-EC191BDB-5C89-3359-9C45-748C96EF08C1.dita"><apiname>iDfcQueue</apiname></xref> member to the client class queue: it will be |
|
73 used to service transfer completion events.</cmd> |
|
74 </substep> |
|
75 </substeps> |
|
76 <stepxmp><codeblock xml:space="preserve"> // Open and configure the channel |
|
77 if (!iDMAChannelOpen) |
|
78 { |
|
79 if (!iDfcQue) |
|
80 return KErrGeneral; |
|
81 |
|
82 TDmaChannel::SCreateInfo info; |
|
83 |
|
84 info.iCookie = (TUint32)iChannelId; |
|
85 info.iDesCount = 3; |
|
86 info.iDfcPriority = 3; |
|
87 info.iDfcQ = iDfcQue; |
|
88 |
|
89 </codeblock></stepxmp> |
|
90 <stepresult>The channel is now initialized.</stepresult> |
|
91 </step> |
|
92 <step id="GUID-9A69E5AD-E938-4092-A8C2-CB65C37C8962-GENID-1-2-1-10-1-5-1-5-1-1-7-1-9-1-7-1-3-3-3"><cmd>Pass the <xref href="GUID-4057074E-2543-3F01-B24A-7FF8A19F79AF.dita"><apiname>SCreateInfo</apiname></xref> object and a channel ID to the <xref href="GUID-20D0D10F-3401-3F72-8AF6-DC35F6025DC2.dita"><apiname>Open()</apiname></xref> function of <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita"><apiname>TDmaChannel</apiname></xref> to open a DMA channel.</cmd> |
|
93 <info><p> This is not necessary if the channel is already open due |
|
94 to a previous transfer request by the same application on the same |
|
95 channel.</p></info> |
|
96 <stepxmp><codeblock xml:space="preserve"> // Open DMA Channel |
|
97 r = TDmaChannel::Open(info, iDMAChannel); |
|
98 |
|
99 if (r) |
|
100 return r; |
|
101 |
|
102 // Set DMA Channel Open |
|
103 iDMAChannelOpen = ETrue; |
|
104 </codeblock></stepxmp> |
|
105 <info>At what point you open the channel depends on platform configuration. |
|
106 If a channel is dedicated to a particular function such as USB, it |
|
107 is typically opened by the channel constructor method and closed by |
|
108 the destructor as there is never any contention for it. In other cases, |
|
109 you must open the channel at the start of a transfer and close it |
|
110 at the end.</info> |
|
111 <stepresult>The channel is now open.</stepresult> |
|
112 </step> |
|
113 <step id="GUID-9A69E5AD-E938-4092-A8C2-CB65C37C8962-GENID-1-2-1-10-1-5-1-5-1-1-7-1-9-1-7-1-3-3-4"><cmd>Call the <xref href="GUID-27816E89-D612-30BE-BC4B-50B892223918.dita"><apiname>Fragment()</apiname></xref> function of <xref href="GUID-780F4D53-5546-3B69-B328-0226C70EBDE2.dita"><apiname>DDmaRequest</apiname></xref> to |
|
114 fragment the data.</cmd> |
|
115 <info>:If your buffers are cacheable you must flush them before a |
|
116 write transfer and both before and after a read transfer, using these |
|
117 functions of the <xref href="GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F.dita"><apiname>Cache</apiname></xref> class:<ul> |
|
118 <li><p><codeph>Cache::SyncMemoryBeforeDmaWrite()</codeph> (takes source |
|
119 buffer as argument)</p></li> |
|
120 <li><p><codeph>Cache::SyncMemoryBeforeDmaRead()</codeph> (takes destination |
|
121 buffer as argument)</p></li> |
|
122 <li><p><codeph>Cache::SyncMemoryAfterDmaRead()</codeph> (takes destination |
|
123 buffer as argument)</p></li> |
|
124 </ul></info> |
|
125 <stepresult>The data is now fragmented.</stepresult> |
|
126 </step> |
|
127 <step id="GUID-99DC4339-5C3E-42AC-BE71-5FED662A6C3A"><cmd>Call the <xref href="GUID-78F37FB6-1286-39CD-80A5-24DA9F27A9AF.dita"><apiname>Queue()</apiname></xref> function of <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita"><apiname>TDmaChannel</apiname></xref> to queue |
|
128 the data on the channel.</cmd> |
|
129 <stepxmp><codeblock xml:space="preserve"> TInt retval = KErrNone; |
|
130 |
|
131 if (iDMABusy) |
|
132 { |
|
133 if (iDMAChannel) |
|
134 { |
|
135 iDMAChannel->CancelAll(); |
|
136 } |
|
137 } |
|
138 |
|
139 iDMABusy = ETrue; |
|
140 |
|
141 iDMAReadStarted = EFalse; |
|
142 |
|
143 if (!iDMAChannelOpen) |
|
144 { |
|
145 retval = Open(); |
|
146 } |
|
147 |
|
148 if (iDMAChannelOpen) |
|
149 { |
|
150 iDMADestination = aDest; |
|
151 iDMACount = aCount; |
|
152 |
|
153 // aDest cached, ivalidate RAM |
|
154 Cache::SyncMemoryBeforeDmaRead(aDest, aCount); |
|
155 retval = iDMARequest ? iDMARequest->Fragment(EDmaSDMMC, aDest, aCount, KDmaMemDest | KDmaIncDest, 0 /* no HW Flags*/) : KErrGeneral; |
|
156 |
|
157 if (retval) |
|
158 { |
|
159 return retval; |
|
160 } |
|
161 |
|
162 iDMAReadStarted = ETrue; |
|
163 if (iDMARequest) |
|
164 { |
|
165 iDMARequest->Queue(); |
|
166 } |
|
167 } |
|
168 </codeblock></stepxmp> |
|
169 <stepresult><p>The data is now queued on the channel.</p></stepresult> |
|
170 </step> |
|
171 <step id="GUID-DA024D3E-F088-4BEC-BC20-DD467D11928F"><cmd>Close the |
|
172 channel. First check whether the channel is busy and take appropriate |
|
173 action if it is (in the following example code you cancel all pending |
|
174 transfers). Then call the <xref href="GUID-01D2AF56-21E1-3FF3-BF86-0C356A1658EF.dita"><apiname>Close()</apiname></xref> function of <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita"><apiname>TDmaChannel</apiname></xref>.</cmd> |
|
175 <stepxmp><codeblock xml:space="preserve"> if (iDMAChannelOpen && iDMAChannel && !iDMABusy) |
|
176 { |
|
177 iDMAChannel->CancelAll(); |
|
178 iDMARequestsCount = 0; // All DMA requests have been now canceled! |
|
179 |
|
180 if (iDMARequest) |
|
181 { |
|
182 //just call destructor explicitly and the object can reused |
|
183 iDMARequest->~DDmaRequest(); |
|
184 } |
|
185 ... |
|
186 iDMAChannel->Close(); |
|
187 </codeblock></stepxmp> |
|
188 <stepresult><p>The channel is now closed.</p></stepresult> |
|
189 </step> |
|
190 </steps> |
|
191 <result id="GUID-7BF6DAFD-2B40-4F3F-889D-F8FDDEFF091C"><p>You have |
|
192 now conducted a data transfer by DMA.</p></result> |
|
193 </taskbody></task> |