diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-F461CBB3-F8D1-5961-AD51-5741143A1CB1.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-F461CBB3-F8D1-5961-AD51-5741143A1CB1.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,255 @@ + + + + + +Client of Slave Channel TutorialThis document describes a simple implementation of a client +of an IIC slave channel. +
Required +background

Before you start, you must:

    +
  • Have installed +the platform specific implementation of IIC channels that is required +to support the IIC platform service API.

  • +
  • Ensure that +the iic.dll has been included in the kernel.iby file.

  • +
  • Include the iic.h and iic_channel.h header files.

  • +
+
Introduction

An application communicates over an IIC channel by operating +as a client of the channel. When the channel uses a slave node, a +transmission must be conducted at the level of the transfer because +slaves react to transfers between it and a master node. For this reason, +a large part of the client functionality is implemented as a callback +function which is passed to the channel object and placed on the client +thread’s DFC queue for execution. The callback notifies the client +of the individual transfers and is the entry point to the application +functionality which uses the data being transmitted. The other client +API functions control the transmission as a whole.

+
Procedure +for writing a client
    +
  1. Capture the +channel by calling IicBus::CaptureChannel().

      +
    1. Pass the channel +Id as its TInt aBusId parameter.

    2. +
    3. Pass the channel +configuration header as TDes8* aConfigHdr.

    4. +
    5. Pass a pointer +to the callback function as TIicBusSlaveCallback* aCallback.

    6. +
    7. Pass the boolean ETrue as TBool aAsynch to specify asynchronous +channel capture and otherwise pass EFalse.

    8. +

    + TInt channelId = 0; + // capture channel.. + r = IicBus::CaptureChannel(TInt aBusId, &header, iSlaveCallback, channelId, aAsynch); + if (r != KErrNone) + { + __KTRACE(Kern::Printf("Error capturing the channel, r %d", r)); + } +

    In synchronous transmission when the function +returns the parameter TInt& aChannelId is set +to a token value, the channel Id, which is used by the other functions +to acquire the exclusive use of the channel. In asynchronous transmission +the channel Id is set immediately before calling the client callback.

  2. +
  3. Register receive +and transmit buffers by calling IicBus::RegisterRxBuffer() and IicBus::RegisterTxBuffer().

      +
    1. Pass the channel +Id as the aChannelId parameter.

    2. +
    3. A buffer is +represented by a descriptor containing a point to the start of the +buffer, its total size in bytes and an indication of how much of it +is in use. Initialise a descriptor with these values and pass it as TPtr8 aRxBuffer, and similarly for TPtr8 aTxBuffer

    4. +

    + TPtr8 rxBuf(0, 0); + TPtr8 txBuf(0, 0); + + rxBuf.Set((TUint8*) iRxBuf.Ptr(), iSlaveBufSize, iRxBuf.MaxLength()); + txBuf.Set((TUint8*) iTxBuf.Ptr(), iSlaveBufSize, iTxBuf.MaxLength()); + + r = IicBus::RegisterRxBuffer(iChannelId, rxBuf, 8, iSlaveBufSize, 0); + if(r != KErrNone) + { + __KTRACE(Kern::Printf("Error Register Rx Buffer, r %d", r)); + } + else + { + r = IicBus::RegisterTxBuffer(iChannelId, txBuf, 8, iSlaveBufSize, 0); + } + + return r; +

  4. +
  5. Call IicBus::SetNotificationTrigger(). This function informs +the channel of the conditions under which the callback is to be called.

      +
    1. Pass the channel +Id as TInt& aChannelId.

    2. +
    3. The callback +is called when the state of the channel satisfies one of a number +of conditions called triggers which are specified in the enumeration TIicBusSlaveTrigger. Determine which triggers are appropriate, +create a bitmask of them and pass it as TInt aTrigger.

    4. +

    +/* + ERxAllBytes = 0x01, // Master has written the required number of bytes + ERxUnderrun = 0x02, // Master has written less than the required number of bytes, and ceased transmitting + ERxOverrun = 0x04, // Master has written the required number of bytes and is continuing to transmit + ETxAllBytes = 0x08, // Master has read the required number of bytes + ETxUnderrun = 0x10, // Master has read the required number of bytes and is continuing to read + ETxOverrun = 0x20, // Master has read less than the required number of bytes, and ceased reading + EGeneralBusError = 0x40, // An error has occurred during a transaction + EAsyncCaptChan = 0x80 // Completion of asynchronous CaptureChannelr = IicBus::SetNotificationTrigger(iChannelId, aTrigger); +*/ + r = SetNotificationTrigger(iChannelId, aTrigger); + if (r != KErrNone) + { + __KTRACE(Kern::Printf("Error setting notification trigger, r %d", r)); + } + + return r; +

    The transmission of data will now take place, +controlled by the mechanism of callback and triggers. Different buses +signal that a transmission has been completed in different ways: for +instance I2C uses a stop bit and SPI changes the voltage on Chip Select.

  6. +
  7. When you have +finished using the channel, release it by calling IicBus::ReleaseChannel() with the channel Id as its argument.

    + r = IicBus::ReleaseChannel(iChannelId); + if (r == KErrNone) + { + // resetting channel Id + iChannelId = 0; + if(iSlaveCallback) + { + // callback object no longer needed, so delete + delete iSlaveCallback; + iSlaveCallback = NULL; + } + + } +

  8. +
+
Next +steps
    +
  • Implement the +callback as a function containing a series of conditions on the triggers. +Its prototype must match the typedef for (*TIicBusSlaveCbFn).

    typedef void (*TIicBusSlaveCbFn)(TInt /*aChannelId*/, + TInt /*aReturn*/, + TInt /*aTrigger*/, + TInt16 /*aRxWords*/, + TInt16 /*aTxWords*/, + TAny* /*aParam*/); +

    These functions serve three purposes.

      +
    • The callback +must react to the completion of an asynchronous transmission between +it and the bus master.

    • +
    • It must implement +the actual functionality of the application by doing something with +the data which is written to or read from the buffers.

    • +
    • It must react +to cases where the physical transfer of the data has not taken place +exactly as expected. For example there may be more data to transfer +than had been anticipated.

    • +
      +
    • Implement the +reaction to a completed asynchronous transmission as a conditional +statement where EAsyncaptChan is true. The callback +should return and control should revert to the client.

      + // aTrigger and aReturn are the arguments provided to the clients + // callback functions as defined by TIicBusSlaveCbFn + if(aTrigger & (EAsyncCaptChan)) + { + if(aReturn == KErrCompletion) + { + // a is a pointer to the client's object + // which stores the channel Id, client Id etc + a->iChannelId = aChannelId; + __KTRACE(Kern::Printf("channelId %d", aChannelId)); + } + + Kern::RequestComplete(a->iClient, a->iSlaveReqStatus, aReturn); + return; + } +
    • +
    • Implement the +actual functionality of the application as a conditional statement +where EAllBytes is true. The callback should return +at the end of this condition.

      + if(aReturn & (ETxAllBytes | ERxAllBytes)) + { + Kern::RequestComplete(a->iClient, a->iSlaveReqStatus, KErrNone); + } + + if(aTrigger & (/*ERxAllBytes |*/ ETxAllBytes)) + { + Kern::RequestComplete(a->iClient, a->iSlaveReqStatus, KErrNone); + } + } +
    • +
    • Implement the +other cases as conditional statements where the other triggers in TIicBusSlaveTrigger are true. In the event of EGeneralBusError the callback should simply complete. The +other triggers involve buffer underruns and overruns which may require +new buffers which the unexpected data can be read from and written +to.

        +
      • Register the +new buffers by calling IicBus::RegisterRxBuffer() and IicBus::RegisterTxBuffer() as explained before.

      • +
      • Start data transfer +to and from the new buffers by calling IicBus::SetNotificationTrigger() as explained before.

        The channel is implemented as a state +machine as illustrated. The channel starts and finishes in the EInactive state. During operation it alternates between +the two states EWaitForClient and EWaitForMaster as the client notifies the channel of new triggers and the channel +reacts to them. There is a timer on these two states and the state +machine returns to EInactive either when there are +no triggers remaining to be detected or the timers time out. When +the client fails to respond on time it enters the state EClientTimeout.

      • +
      + if(aTrigger & ETxUnderrun) + { + TPtr8 txBuf(0, 0); + + txBuf.Set((TUint8*) a->iTxBuf.Ptr(), a->iTxBuf.MaxLength(), a->iTxBuf.MaxLength()); + + // if there is more data to transmit + // use aTxWords as an offset.. + if(aTxWords + 32 <= KMaxSlaveTestBufferSize) + { + // register the next buffer + r = IicBus::RegisterTxBuffer(a->iChannelId, txBuf, 8, 32, aTxWords); + // check it was successful + if (r != KErrNone) + { + Kern::Printf("Error Register Tx Buffer, r %d", r); + } + else + { + // set the trigger to transmit the required number of bytes + r = IicBus::SetNotificationTrigger(a->iChannelId, ETxAllBytes); + // check the request was accepted + if (r != KErrNone) + { + Kern::Printf("Error setting notification trigger, r %d", r); + } + } + + // updated the buffer - so return.. + return; + } + } +
    • +
  • +
+ Client state machine 1 + + + + + Client state machine 3 + +
+
+Client +of Master Channel Tutorial +IIC +Concepts +I2C +Technology Guide +
\ No newline at end of file