|
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 concept |
|
11 PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd"> |
|
12 <concept id="GUID-F461CBB3-F8D1-5961-AD51-5741143A1CB1" xml:lang="en"><title>Client of Slave Channel Tutorial</title><shortdesc>This document describes a simple implementation of a client |
|
13 of an IIC slave channel. </shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
14 <section id="GUID-803E9D3A-19F4-58EA-A3F8-1912C7223FE2"><title>Required |
|
15 background</title> <p>Before you start, you must: </p> <ul> |
|
16 <li id="GUID-E20D2D65-CB2C-52A0-B694-B26EC96B6F99"><p>Have installed |
|
17 the platform specific implementation of IIC channels that is required |
|
18 to support the IIC platform service API. </p> </li> |
|
19 <li id="GUID-F675A381-8125-5077-8D9E-70188B1ACA6C"><p>Ensure that |
|
20 the <filepath>iic.dll</filepath> has been included in the <filepath>kernel.iby</filepath> file. </p> </li> |
|
21 <li id="GUID-638684A5-4938-5F60-9BB1-97F5AFD199B4"><p>Include the <filepath>iic.h</filepath> and <filepath>iic_channel.h</filepath> header files. </p> </li> |
|
22 </ul> </section> |
|
23 <section id="GUID-D71B8CE6-AD6B-56A4-835F-44B80FB2E0A6"><title>Introduction</title> <p>An application communicates over an IIC channel by operating |
|
24 as a client of the channel. When the channel uses a slave node, a |
|
25 transmission must be conducted at the level of the transfer because |
|
26 slaves react to transfers between it and a master node. For this reason, |
|
27 a large part of the client functionality is implemented as a callback |
|
28 function which is passed to the channel object and placed on the client |
|
29 thread’s DFC queue for execution. The callback notifies the client |
|
30 of the individual transfers and is the entry point to the application |
|
31 functionality which uses the data being transmitted. The other client |
|
32 API functions control the transmission as a whole. </p> </section> |
|
33 <section id="GUID-F6E864D9-F951-4A2D-B933-166F5DE4F5C3"><title>Procedure |
|
34 for writing a client</title> <ol id="GUID-E1360AA1-59E2-53FE-9CED-967D731F17CA"> |
|
35 <li id="GUID-D8ABA659-47A9-536E-9EC6-E8741909CAFF"><p>Capture the |
|
36 channel by calling <xref href="GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF.dita#GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF/GUID-0078D2B4-07B7-3936-8CB2-6A967C9B1FCD"><apiname>IicBus::CaptureChannel()</apiname></xref>. </p> <ol id="GUID-A0A19CF5-5A45-588A-8C15-A11C12800055"> |
|
37 <li id="GUID-37BA179D-1D7F-560C-8C81-6C9EE7674459"><p>Pass the channel |
|
38 Id as its <codeph>TInt aBusId</codeph> parameter. </p> </li> |
|
39 <li id="GUID-BF8B3291-626A-59F1-897A-25A73D22FCCD"><p>Pass the channel |
|
40 configuration header as <codeph>TDes8* aConfigHdr</codeph>. </p> </li> |
|
41 <li id="GUID-E1BA9A5F-81CE-522E-8CC0-CF38D0BC474B"><p>Pass a pointer |
|
42 to the callback function as <codeph>TIicBusSlaveCallback* aCallback</codeph>. </p> </li> |
|
43 <li id="GUID-DB6262F2-51D4-5D2D-857B-7F54E6EF1521"><p>Pass the boolean <xref href="GUID-781E8158-805B-3784-8FED-D7A191822FC3.dita"><apiname>ETrue</apiname></xref> as <codeph>TBool aAsynch</codeph> to specify asynchronous |
|
44 channel capture and otherwise pass <xref href="GUID-A759CA2D-8327-348F-9337-4886E619D920.dita"><apiname>EFalse</apiname></xref>. </p> </li> |
|
45 </ol> <p><codeblock id="GUID-713BDFF9-83E2-5A63-BD3A-A36556E5A70C" xml:space="preserve"> |
|
46 TInt channelId = 0; |
|
47 // capture channel.. |
|
48 r = IicBus::CaptureChannel(TInt aBusId, &header, iSlaveCallback, channelId, aAsynch); |
|
49 if (r != KErrNone) |
|
50 { |
|
51 __KTRACE(Kern::Printf("Error capturing the channel, r %d", r)); |
|
52 } |
|
53 </codeblock> </p> <p>In synchronous transmission when the function |
|
54 returns the parameter <codeph>TInt& aChannelId</codeph> is set |
|
55 to a token value, the channel Id, which is used by the other functions |
|
56 to acquire the exclusive use of the channel. In asynchronous transmission |
|
57 the channel Id is set immediately before calling the client callback. </p> </li> |
|
58 <li id="GUID-1D366FFE-DEE0-59E1-9FC7-507C06C58964"><p>Register receive |
|
59 and transmit buffers by calling <xref href="GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF.dita#GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF/GUID-E6D971CA-E09C-36B2-92B2-759CC81AF3F1"><apiname>IicBus::RegisterRxBuffer()</apiname></xref> and <xref href="GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF.dita#GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF/GUID-E885DF1D-2192-3BC7-8165-1E5A194ABA28"><apiname>IicBus::RegisterTxBuffer()</apiname></xref>. </p> <ol id="GUID-7722A592-4EB3-5701-9F7F-79EEB8E6221D"> |
|
60 <li id="GUID-520C3DF1-91AE-5FAC-AFFC-806361672660"><p>Pass the channel |
|
61 Id as the <codeph>aChannelId</codeph> parameter. </p> </li> |
|
62 <li id="GUID-E4971790-1830-5CA3-90DB-89F3FA169758"><p>A buffer is |
|
63 represented by a descriptor containing a point to the start of the |
|
64 buffer, its total size in bytes and an indication of how much of it |
|
65 is in use. Initialise a descriptor with these values and pass it as <codeph>TPtr8 aRxBuffer</codeph>, and similarly for <codeph>TPtr8 aTxBuffer</codeph> </p> </li> |
|
66 </ol> <p><codeblock id="GUID-6585AF43-450D-5A6A-A55E-39CEDACF0CA1" xml:space="preserve"> |
|
67 TPtr8 rxBuf(0, 0); |
|
68 TPtr8 txBuf(0, 0); |
|
69 |
|
70 rxBuf.Set((TUint8*) iRxBuf.Ptr(), iSlaveBufSize, iRxBuf.MaxLength()); |
|
71 txBuf.Set((TUint8*) iTxBuf.Ptr(), iSlaveBufSize, iTxBuf.MaxLength()); |
|
72 |
|
73 r = IicBus::RegisterRxBuffer(iChannelId, rxBuf, 8, iSlaveBufSize, 0); |
|
74 if(r != KErrNone) |
|
75 { |
|
76 __KTRACE(Kern::Printf("Error Register Rx Buffer, r %d", r)); |
|
77 } |
|
78 else |
|
79 { |
|
80 r = IicBus::RegisterTxBuffer(iChannelId, txBuf, 8, iSlaveBufSize, 0); |
|
81 } |
|
82 |
|
83 return r; |
|
84 </codeblock> </p> </li> |
|
85 <li id="GUID-BC801368-74D3-504D-95D6-A802C34062C9"><p>Call <xref href="GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF.dita#GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF/GUID-8FD1E53D-5C7C-38ED-8B2C-59B4BCF8940B"><apiname>IicBus::SetNotificationTrigger()</apiname></xref>. This function informs |
|
86 the channel of the conditions under which the callback is to be called. </p> <ol id="GUID-FB921A67-1B9D-5B7A-9B9E-1587F32328A6"> |
|
87 <li id="GUID-4DB389EA-2BC7-5275-AF4C-D6EE411B2400"><p>Pass the channel |
|
88 Id as <codeph>TInt& aChannelId</codeph>. </p> </li> |
|
89 <li id="GUID-0F57322E-3D82-5E67-932C-9C6145B4E7C6"><p>The callback |
|
90 is called when the state of the channel satisfies one of a number |
|
91 of conditions called triggers which are specified in the enumeration <xref href="GUID-5216FF3E-19BA-3862-B188-A3871D7D1BF5.dita"><apiname>TIicBusSlaveTrigger</apiname></xref>. Determine which triggers are appropriate, |
|
92 create a bitmask of them and pass it as <codeph>TInt aTrigger</codeph>. </p> </li> |
|
93 </ol> <p><codeblock id="GUID-03217DC6-FD76-5786-8103-55BB847533CB" xml:space="preserve"> |
|
94 /* |
|
95 ERxAllBytes = 0x01, // Master has written the required number of bytes |
|
96 ERxUnderrun = 0x02, // Master has written less than the required number of bytes, and ceased transmitting |
|
97 ERxOverrun = 0x04, // Master has written the required number of bytes and is continuing to transmit |
|
98 ETxAllBytes = 0x08, // Master has read the required number of bytes |
|
99 ETxUnderrun = 0x10, // Master has read the required number of bytes and is continuing to read |
|
100 ETxOverrun = 0x20, // Master has read less than the required number of bytes, and ceased reading |
|
101 EGeneralBusError = 0x40, // An error has occurred during a transaction |
|
102 EAsyncCaptChan = 0x80 // Completion of asynchronous CaptureChannelr = IicBus::SetNotificationTrigger(iChannelId, aTrigger); |
|
103 */ |
|
104 r = SetNotificationTrigger(iChannelId, aTrigger); |
|
105 if (r != KErrNone) |
|
106 { |
|
107 __KTRACE(Kern::Printf("Error setting notification trigger, r %d", r)); |
|
108 } |
|
109 |
|
110 return r; |
|
111 </codeblock> </p> <p>The transmission of data will now take place, |
|
112 controlled by the mechanism of callback and triggers. Different buses |
|
113 signal that a transmission has been completed in different ways: for |
|
114 instance I2C uses a stop bit and SPI changes the voltage on Chip Select. </p> </li> |
|
115 <li id="GUID-488F34BF-E6E8-5316-8484-14560A689CD8"><p>When you have |
|
116 finished using the channel, release it by calling <xref href="GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF.dita#GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF/GUID-C1B69722-1316-3C7D-BB8B-0E54B8F44C5D"><apiname>IicBus::ReleaseChannel()</apiname></xref> with the channel Id as its argument. </p> <p><codeblock id="GUID-06528860-5B5D-5909-BBD5-BABE2146F616" xml:space="preserve"> |
|
117 r = IicBus::ReleaseChannel(iChannelId); |
|
118 if (r == KErrNone) |
|
119 { |
|
120 // resetting channel Id |
|
121 iChannelId = 0; |
|
122 if(iSlaveCallback) |
|
123 { |
|
124 // callback object no longer needed, so delete |
|
125 delete iSlaveCallback; |
|
126 iSlaveCallback = NULL; |
|
127 } |
|
128 |
|
129 } |
|
130 </codeblock> </p> </li> |
|
131 </ol> </section> |
|
132 <section id="GUID-C82AB1DF-2988-4E29-92D1-235662B0485C"><title>Next |
|
133 steps</title> <ul> |
|
134 <li id="GUID-FD946C48-CC78-5E04-A682-65DAC3CF31C2"><p>Implement the |
|
135 callback as a function containing a series of conditions on the triggers. |
|
136 Its prototype must match the typedef for (*<xref href="GUID-7EB83085-7D28-3914-802B-44D8260E9074.dita"><apiname>TIicBusSlaveCbFn</apiname></xref>). </p> <codeblock id="GUID-A0F3DD87-11B7-5AD1-B3F1-F5515B4A97BD" xml:space="preserve">typedef void (*TIicBusSlaveCbFn)(TInt /*aChannelId*/, |
|
137 TInt /*aReturn*/, |
|
138 TInt /*aTrigger*/, |
|
139 TInt16 /*aRxWords*/, |
|
140 TInt16 /*aTxWords*/, |
|
141 TAny* /*aParam*/); |
|
142 </codeblock> <p>These functions serve three purposes. </p> <ul> |
|
143 <li id="GUID-7E871B53-4DA7-5C38-9485-A7FAD2ACCC4B"><p>The callback |
|
144 must react to the completion of an asynchronous transmission between |
|
145 it and the bus master. </p> </li> |
|
146 <li id="GUID-068201FA-B27E-55F5-AF14-CBA53A8D1AAD"><p>It must implement |
|
147 the actual functionality of the application by doing something with |
|
148 the data which is written to or read from the buffers. </p> </li> |
|
149 <li id="GUID-7F9AFCB8-6C3F-51C4-B1B9-C5DA492ED039"><p>It must react |
|
150 to cases where the physical transfer of the data has not taken place |
|
151 exactly as expected. For example there may be more data to transfer |
|
152 than had been anticipated. </p> </li> |
|
153 </ul> <ul> |
|
154 <li id="GUID-74EA3A8B-8DEE-57E8-90F3-606FE671588A"><p>Implement the |
|
155 reaction to a completed asynchronous transmission as a conditional |
|
156 statement where <xref href="GUID-DAAA6E18-9E78-3ED2-A686-EC28E5C92A24.dita"><apiname>EAsyncaptChan</apiname></xref> is true. The callback |
|
157 should return and control should revert to the client. </p> <codeblock id="GUID-F6ECA83D-E4D8-5015-A88C-B76228DA74BB" xml:space="preserve"> |
|
158 // aTrigger and aReturn are the arguments provided to the clients |
|
159 // callback functions as defined by TIicBusSlaveCbFn |
|
160 if(aTrigger & (EAsyncCaptChan)) |
|
161 { |
|
162 if(aReturn == KErrCompletion) |
|
163 { |
|
164 // a is a pointer to the client's object |
|
165 // which stores the channel Id, client Id etc |
|
166 a->iChannelId = aChannelId; |
|
167 __KTRACE(Kern::Printf("channelId %d", aChannelId)); |
|
168 } |
|
169 |
|
170 Kern::RequestComplete(a->iClient, a->iSlaveReqStatus, aReturn); |
|
171 return; |
|
172 } |
|
173 </codeblock> </li> |
|
174 <li id="GUID-16448D59-2A11-5D89-806F-763D96CEFEC6"><p>Implement the |
|
175 actual functionality of the application as a conditional statement |
|
176 where <xref href="GUID-CC0F0C9A-25B6-3A18-93D1-EC0710DFB6A7.dita"><apiname>EAllBytes</apiname></xref> is true. The callback should return |
|
177 at the end of this condition. </p> <codeblock id="GUID-905D54F9-A19E-51C9-98A5-A95471BAFB53" xml:space="preserve"> |
|
178 if(aReturn & (ETxAllBytes | ERxAllBytes)) |
|
179 { |
|
180 Kern::RequestComplete(a->iClient, a->iSlaveReqStatus, KErrNone); |
|
181 } |
|
182 |
|
183 if(aTrigger & (/*ERxAllBytes |*/ ETxAllBytes)) |
|
184 { |
|
185 Kern::RequestComplete(a->iClient, a->iSlaveReqStatus, KErrNone); |
|
186 } |
|
187 } |
|
188 </codeblock> </li> |
|
189 <li id="GUID-9725BAF2-14B1-5CC7-8DE4-46FB3DDF609E"><p>Implement the |
|
190 other cases as conditional statements where the other triggers in <xref href="GUID-5216FF3E-19BA-3862-B188-A3871D7D1BF5.dita"><apiname>TIicBusSlaveTrigger</apiname></xref> are true. In the event of <xref href="GUID-1D10124D-F27E-33C3-B803-FEBDEB2B7964.dita"><apiname>EGeneralBusError</apiname></xref> the callback should simply complete. The |
|
191 other triggers involve buffer underruns and overruns which may require |
|
192 new buffers which the unexpected data can be read from and written |
|
193 to. </p> <ul> |
|
194 <li id="GUID-67BAE1C9-1A2B-524D-B3D0-7E28CC309BDA"><p>Register the |
|
195 new buffers by calling <xref href="GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF.dita#GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF/GUID-E6D971CA-E09C-36B2-92B2-759CC81AF3F1"><apiname>IicBus::RegisterRxBuffer()</apiname></xref> and <xref href="GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF.dita#GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF/GUID-E885DF1D-2192-3BC7-8165-1E5A194ABA28"><apiname>IicBus::RegisterTxBuffer()</apiname></xref> as explained before. </p> </li> |
|
196 <li id="GUID-C6711DE9-F3B1-53F2-B0F9-03B3550F1487"><p>Start data transfer |
|
197 to and from the new buffers by calling <xref href="GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF.dita#GUID-69949E47-8FDF-3651-BEEF-43726EBEB5FF/GUID-8FD1E53D-5C7C-38ED-8B2C-59B4BCF8940B"><apiname>IicBus::SetNotificationTrigger()</apiname></xref> as explained before. </p> <p>The channel is implemented as a state |
|
198 machine as illustrated. The channel starts and finishes in the <codeph>EInactive</codeph> state. During operation it alternates between |
|
199 the two states <codeph>EWaitForClient</codeph> and <codeph>EWaitForMaster</codeph> as the client notifies the channel of new triggers and the channel |
|
200 reacts to them. There is a timer on these two states and the state |
|
201 machine returns to <codeph>EInactive</codeph> either when there are |
|
202 no triggers remaining to be detected or the timers time out. When |
|
203 the client fails to respond on time it enters the state <xref href="GUID-68E03A23-AE1E-3412-B831-7770882B8C2B.dita"><apiname>EClientTimeout</apiname></xref>. </p> </li> |
|
204 </ul> <codeblock id="GUID-73A80A1E-4C07-55DB-AFCF-608B48B68460" xml:space="preserve"> |
|
205 if(aTrigger & ETxUnderrun) |
|
206 { |
|
207 TPtr8 txBuf(0, 0); |
|
208 |
|
209 txBuf.Set((TUint8*) a->iTxBuf.Ptr(), a->iTxBuf.MaxLength(), a->iTxBuf.MaxLength()); |
|
210 |
|
211 // if there is more data to transmit |
|
212 // use aTxWords as an offset.. |
|
213 if(aTxWords + 32 <= KMaxSlaveTestBufferSize) |
|
214 { |
|
215 // register the next buffer |
|
216 r = IicBus::RegisterTxBuffer(a->iChannelId, txBuf, 8, 32, aTxWords); |
|
217 // check it was successful |
|
218 if (r != KErrNone) |
|
219 { |
|
220 Kern::Printf("Error Register Tx Buffer, r %d", r); |
|
221 } |
|
222 else |
|
223 { |
|
224 // set the trigger to transmit the required number of bytes |
|
225 r = IicBus::SetNotificationTrigger(a->iChannelId, ETxAllBytes); |
|
226 // check the request was accepted |
|
227 if (r != KErrNone) |
|
228 { |
|
229 Kern::Printf("Error setting notification trigger, r %d", r); |
|
230 } |
|
231 } |
|
232 |
|
233 // updated the buffer - so return.. |
|
234 return; |
|
235 } |
|
236 } |
|
237 </codeblock> </li> |
|
238 </ul> </li> |
|
239 </ul> <fig id="GUID-2A41FE33-8734-5A13-ACB0-B971E4429C85"> |
|
240 <title> Client state machine 1 </title> |
|
241 <image href="GUID-8A78D678-D1C8-4A4E-9BF1-81C7019815C3_d0e94711_href.png" placement="inline"/> |
|
242 </fig> <fig id="GUID-2178C529-1F08-5504-9C04-C46D59F4951F"> |
|
243 <image href="GUID-4CB3C746-606F-4533-8BBB-4A1254A74772_d0e94716_href.png" placement="inline"/> |
|
244 </fig> <fig id="GUID-FB2C9F89-6148-5AE2-A07A-C0D643407044"> |
|
245 <title> Client state machine 3 </title> |
|
246 <image href="GUID-ACC010D4-B419-4CDD-8091-C85579575D46_d0e94724_href.png" placement="inline"/> |
|
247 </fig> </section> |
|
248 </conbody><related-links> |
|
249 <link href="GUID-9986DCC6-EE73-59FB-BDAC-9B09DC64FBCE.dita"><linktext>Client |
|
250 of Master Channel Tutorial</linktext></link> |
|
251 <link href="GUID-B2F86F54-EF50-56DB-ADF7-15325AC9324D.dita"><linktext>IIC |
|
252 Concepts</linktext></link> |
|
253 <link href="GUID-3A30DA16-ECA8-5639-A9DC-6BE2AD55420B.dita"><linktext>I2C |
|
254 Technology Guide</linktext></link> |
|
255 </related-links></concept> |