diff -r 89d6a7a84779 -r 25a17d01db0c Symbian3/PDK/Source/GUID-F461CBB3-F8D1-5961-AD51-5741143A1CB1.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Symbian3/PDK/Source/GUID-F461CBB3-F8D1-5961-AD51-5741143A1CB1.dita Fri Jan 22 18:26:19 2010 +0000 @@ -0,0 +1,264 @@ + + + + + +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 +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 +IIC Master Channel Implementation Tutorial +IIC Guide + +SPI Technology +Guide +I2C Technology +Guide +
\ No newline at end of file