# HG changeset patch # User Lukasz Forynski # Date 1290127422 0 # Node ID fdfa12d9a47aeee224f41ae29c6a884cc8d1b2a6 # Parent 35fb7dda225ac69d836385f775b8c8f781d6be34 SPI update: fixed pin and zero-lengh transfer bugs, added asynchronous trasaction example (test) diff -r 35fb7dda225a -r fdfa12d9a47a omap3530/beagle_drivers/byd_touch/common/controller.h --- a/omap3530/beagle_drivers/byd_touch/common/controller.h Sat Nov 06 15:14:41 2010 +0000 +++ b/omap3530/beagle_drivers/byd_touch/common/controller.h Fri Nov 19 00:43:42 2010 +0000 @@ -44,9 +44,7 @@ const TUint KDataReadyPin = 133; // DAV connected to the GPIO133 (Expansion header pin 15) const TUint KSpiModule = 2; // McSPI3 -const TUint KSpiSlaveAddr0 = 2; // for data18-data23 pin functions slave address 2=>CS0.. -const TUint KSpiSlaveAddr1 = 3; // ..slave address 3=>CS1 (pref!) -const TUint KSpiSlaveAddr = KSpiSlaveAddr1; +const TUint KSpiSlaveAddr = 3; // ..slave address 3=> spi taken to 'dvi_data18-dvi_data_23' pins const TConfigSpiV01 KHeader = diff -r 35fb7dda225a -r fdfa12d9a47a omap3530/beagleboard/rom/kernel.iby --- a/omap3530/beagleboard/rom/kernel.iby Sat Nov 06 15:14:41 2010 +0000 +++ b/omap3530/beagleboard/rom/kernel.iby Fri Nov 19 00:43:42 2010 +0000 @@ -35,7 +35,7 @@ extension[VARID]=\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_LED.DLL \sys\bin\led.dll extension[VARID]=\Epoc32\Release\ARMV5\##BUILD##\_omap3530_I2C.DLL \sys\bin\i2c.DLL -// Uncommnet to include West Bridge Astoria Symbian Storage driver +// Uncommnet to include West Bridge Astoria Symbian Storage driver //extension[VARID]=\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_WB.DLL \sys\bin\wb.dll //extension[VARID]=\epoc32\release\ARMV5\##BUILD##\wb.dll \sys\bin\wb.dll @@ -45,7 +45,9 @@ #include #include +#ifdef BYD_LCD extension[VARID]=\Epoc32\Release\ARMV5\##BUILD##\_##VARIANT##_byd_xyin.dll \sys\bin\byd_xyin.dll +#endif device[VARID]=\Epoc32\Release\ARMV5\##BUILD##\_omap3530_EUART.PDD \sys\bin\euart.pdd device[VARID]=\Epoc32\Release\ARMV5\##BUILD##\ECOMM.LDD \sys\bin\ecomm.ldd @@ -78,7 +80,7 @@ // Estart data= \epoc32\rom\beagle\estart.txt \sys\data\estart.txt -// Uncommnet to include West Bridge Astoria Symbian Storage driver +// Uncommnet to include West Bridge Astoria Symbian Storage driver //extension[VARID]=\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_MEDWB.PDD \sys\bin\medwb.pdd device[VARID]=\epoc32\release\##KMAIN##\##BUILD##\PIPELIB.LDD \sys\bin\pipelib.ldd extension[VARID]=\epoc32\release\##KMAIN##\##BUILD##\EXSTART.DLL \sys\bin\exstart.dll diff -r 35fb7dda225a -r fdfa12d9a47a omap3530/omap3530_drivers/spi/master.cpp --- a/omap3530/omap3530_drivers/spi/master.cpp Sat Nov 06 15:14:41 2010 +0000 +++ b/omap3530/omap3530_drivers/spi/master.cpp Fri Nov 19 00:43:42 2010 +0000 @@ -15,14 +15,16 @@ // Implementation of IIC master channel for a SPI bus. // -#define DBGPRINT(x) -#define DBG_ERR(x) x #ifdef _DEBUG +#define DBGPRINT(x) //x #define DEBUG_ONLY(x) //x +#define DBG_ERR(x) x #else #define DEBUG_ONLY(x) +#define DBGPRINT(x) +#define DBG_ERR(x) #endif @@ -188,8 +190,9 @@ // reconfigure pins if needed.. if(slavePinSet != iCurrSlavePinSet) { + DeactivateSpiPins(iChannelNumber, iCurrSlavePinSet); + SetupSpiPins(iChannelNumber, slavePinSet); iCurrSlavePinSet = slavePinSet; - SetupSpiPins(iChannelNumber, iCurrSlavePinSet); } // store configuration parameters @@ -410,9 +413,12 @@ // Store the current address and ending address for Transmission - they are required by the ISR and DFC iTxData = (TInt8*) desBufPtr->Ptr(); iTxDataEnd = (TInt8*) (iTxData + desBufPtr->Length()); - if ((TInt)iTxDataEnd % iWordSize) + if (((TInt)iTxDataEnd == (TInt)iTxData) || // buffer empty + (TInt)iTxDataEnd % iWordSize) // or wrong size / word length combination { - DBG_ERR(Kern::Printf("Wrong configuration - word size does not match buffer length")); + DBG_ERR(if ((TInt)iTxDataEnd == (TInt)iTxData) Kern::Printf("Zero-length buffer used for transfer..")); + DBG_ERR(if ((TInt)iTxDataEnd % iWordSize) Kern::Printf("Wrong configuration - word size does not match buffer length")); + ExitComplete(KErrArgument, EFalse); return KErrArgument; } @@ -440,6 +446,14 @@ // Store the current address and ending address for Reception - they are required by the ISR and DFC iRxData = (TInt8*) aBufPtr->Ptr(); iRxDataEnd = (TInt8*) (iRxData + aBufPtr->Length()); + if (((TInt)iRxDataEnd == (TInt)iRxData) || // buffer empty + (TInt)iRxDataEnd % iWordSize) // or wrong size / word length combination + { + DBG_ERR(if ((TInt)iRxDataEnd == (TInt)iRxData) Kern::Printf("Zero-length buffer used for transfer..")); + DBG_ERR(if ((TInt)iRxDataEnd % iWordSize) Kern::Printf("Wrong configuration - word size does not match buffer length")); + ExitComplete(KErrArgument, EFalse); + return KErrArgument; + } DBGPRINT(Kern::Printf("Rx: Start: %x, End %x, bytes %d", iRxData, iRxDataEnd, aBufPtr->Length())); diff -r 35fb7dda225a -r fdfa12d9a47a omap3530/omap3530_drivers/spi/omap3530_spi.inl --- a/omap3530/omap3530_drivers/spi/omap3530_spi.inl Sat Nov 06 15:14:41 2010 +0000 +++ b/omap3530/omap3530_drivers/spi/omap3530_spi.inl Fri Nov 19 00:43:42 2010 +0000 @@ -44,7 +44,7 @@ __ASSERT_DEBUG(csConf.iAddress, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // don't try to use non-existing CS! // now switch the pin mode back to the SPI - SCM::SetPadConfig(csConf.iAddress, csConf.iMswLsw, csConf.iFlags | SCM::EInputEnable); // revert to intended mode + SCM::SetPadConfig(csConf.iAddress, csConf.iMswLsw, csConf.iFlags); } @@ -76,6 +76,22 @@ } } +// McSPI3 can have 3 different pin configuration, but only one can be active at the time. +// for that reason, before switching to different mode -at least SOMI has to be deactivated +// otherwise the newly activated pin does not work (why??). Changing these pins to the GPIO (mode 4) +inline void DeactivateSpiPins(TUint aModule, TUint aPinSetId = 0) + { + __ASSERT_DEBUG(aModule < KMaxSpiChannelsPerModule, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // aChannel > module channels + __ASSERT_DEBUG(aModule != 2 ? !aPinSetId : ETrue, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // only channel 3 supports other pin configurations + + const TSpiPinConfig& pinCnf = ModulePinConfig[aModule + aPinSetId]; + + SCM::SetPadConfig(pinCnf.iClk.iAddress, pinCnf.iClk.iMswLsw, SCM::EMode4 | SCM::EInputEnable); + SCM::SetPadConfig(pinCnf.iSimo.iAddress, pinCnf.iSimo.iMswLsw, SCM::EMode4 | SCM::EInputEnable); + SCM::SetPadConfig(pinCnf.iSomi.iAddress, pinCnf.iSomi.iMswLsw, SCM::EMode4 | SCM::EInputEnable); + } + + // helper function - returns appropriate value for the register for a given mode inline TUint32 SpiClkMode(TSpiClkMode aClkMode) { diff -r 35fb7dda225a -r fdfa12d9a47a omap3530/omap3530_drivers/spi/test/d_spi_client_m.cpp --- a/omap3530/omap3530_drivers/spi/test/d_spi_client_m.cpp Sat Nov 06 15:14:41 2010 +0000 +++ b/omap3530/omap3530_drivers/spi/test/d_spi_client_m.cpp Fri Nov 19 00:43:42 2010 +0000 @@ -208,16 +208,6 @@ r = FullDuplexMultiple(); break; } - case RSpiClientTest::EHalfDuplexExtendable: - { - r = HalfDuplexExtendable(); - break; - } - case RSpiClientTest::EFullDuplexExtendable: - { - r = FullDuplexExtendable(); - break; - } default: { @@ -242,47 +232,47 @@ { case RSpiClientTest::EAsyncHalfDuplexSingleWrite: { - r = KErrNotSupported; // AsyncHalfDuplexSingleWrite(aStatus); + r = AsyncHalfDuplexSingleWrite(aStatus); break; } case RSpiClientTest::EAsyncHalfDuplexMultipleWrite: { - r = KErrNotSupported; // AsyncHalfDuplexMultipleWrite(aStatus); + r = AsyncHalfDuplexMultipleWrite(aStatus); break; } case RSpiClientTest::EAsyncHalfDuplexSingleRead: { - r = KErrNotSupported; // AsyncHalfDuplexSingleRead(aStatus); + r = AsyncHalfDuplexSingleRead(aStatus); break; } case RSpiClientTest::EAsyncHalfDuplexMultipleRead: { - r = KErrNotSupported; // AsyncHalfDuplexMultipleRead(aStatus); + r = AsyncHalfDuplexMultipleRead(aStatus); break; } case RSpiClientTest::EAsyncHalfDuplexMultipleWriteRead: { - r = KErrNotSupported; // AsyncHalfDuplexMultipleWriteRead(aStatus); + r = AsyncHalfDuplexMultipleWriteRead(aStatus); break; } case RSpiClientTest::EAsyncFullDuplexSingle: { - r = KErrNotSupported; // AsyncFullDuplexSingle(aStatus); + r = AsyncFullDuplexSingle(aStatus); break; } case RSpiClientTest::EAsyncFullDuplexMultiple: { - r = KErrNotSupported; // AsyncFullDuplexMultiple(aStatus); + r = AsyncFullDuplexMultiple(aStatus); break; } case RSpiClientTest::EAsyncHalfDuplexExtendable: { - r = KErrNotSupported; // AsyncHalfDuplexExtendable(aStatus); + r = KErrNotSupported; // AsyncHalfDuplexExtendable(aStatus); TODO Not implemented yet.. break; } case RSpiClientTest::EAsyncFullDuplexExtendable: { - r = KErrNotSupported; // AsyncFullDuplexExtendable(aStatus); + r = KErrNotSupported; // AsyncFullDuplexExtendable(aStatus); TODO Not implemented yet.. break; } default: @@ -357,6 +347,7 @@ return r; } + // test half duplex write: // - one transaction with more write transfers // - synchronous use - all buffers / transfer objects / transactions - on the stack @@ -696,9 +687,10 @@ // initially filled with. (i.e. as nothing was driving the SOMI line - rx will count that as 0 sent over the bus) // see top of this file and IsLoobackAvailable() function description for more details. TBool checkReceivedMatchesSent = IsLoopbackAvailable(); - if(!checkReceivedMatchesSent) + { Kern::Printf("!Warning: %s (%d): not using local-loop for duplex test", __FILE__, __LINE__); + } for (int i = 0; i < KBuffLength; i++) { @@ -861,13 +853,160 @@ return r; } -TInt DSpiClientChannel::HalfDuplexExtendable() +// test asynchronous transactions. +// For these transactions - all objects: buffers, transfers and transactions have to be allocated on the heap. +// At the momment there is no way of extracting pointers to these objects from the transaction +// pointer by the client (this it TODO and it's currently being addressed as an architectural change). +// For that reason pointers to these dynamic objects have to be stored by the client, so that +// he could access these from the request, read the data (for RX request) and de-allocate/re-use them +// in next transactions. +// In order to achieve that (until the PIL will support above 'TODO') the templated wrapper class is used +// to manage all these pointers, i.e.: TTransactionWrapper (see header file) + + +// Callback for Master's asynchronous transactions - called when transaction has been finished +void DSpiClientChannel::SingleHalfDuplexTransCallback(TIicBusTransaction* aTransaction, + TInt aBusId, + TInt aResult, + TAny* aParam) + { + LOG_FUNCTION_ENTRY; + TTransactionWrapper<1> *twr = (TTransactionWrapper<1>*)aParam; + + if(aResult == KErrNone) + { + // if this was a read request (AsyncHalfDuplexSingleRead)- read received data: + HBuf8* rxBuffer = twr->GetRxBuffer(0); + if(rxBuffer) + { + HBuf8& buffer = *rxBuffer; // a reference to avoid writing: "(*rxBuffer)[0]" below.. + for(TInt i= 0; i < rxBuffer->Length(); i++) + { + // check if the data is correct.. + if(buffer[i] == 0x55) + { + aResult = KErrCorrupt; + break; + } + } + } + } + + // complete request.. informing the client on the result. + Kern::RequestComplete(twr->iClient, twr->iReqStatus, aResult); + + // now can finally delete the wrapper- this will release all memory it holds + delete twr; + + // and delete transaction + delete aTransaction; + } + + +// Test Asynchronous Transaction +TInt DSpiClientChannel::AsyncHalfDuplexSingleWrite(TRequestStatus* aStatus) + { + TInt r = KErrNoMemory; + + // 0. prepare busId - i.e. select module / channel and bus type + TUint32 busId = 0; + SET_BUS_TYPE(busId, DIicBusChannel::ESpi); + SET_CHAN_NUM(busId, 2); // THis is the ModuleNumber, i.e. McSPIx (minus one), e.g. 2 for McSPI3 + SET_SLAVE_ADDR(busId, 0); // THis is the ChannelNumber (Slave number of the above McSPIx) + + // 1. create header + const TConfigSpiV01 KHeader = + { + ESpiWordWidth_8, //iWordWidth + 3000000, //iClkSpeed + ESpiPolarityLowRisingEdge, //iClkMode + 5000, // iTimeoutPeriod + EBigEndian, // iEndianness + EMsbFirst, //iBitOrder + 0, //iTransactionWaitCycles + ESpiCSPinActiveLow //iCsPinActiveMode + }; + // TConfigSpiBufV01 is a TPckgBuf + TConfigSpiBufV01* spiHeader = new TConfigSpiBufV01(KHeader); + + const TInt KTrasferBufferLength = 64; + if(spiHeader) + { + // 2. create wrapper to store pointers to transfer buffers and objects.. + TTransactionWrapper<1> *twr = new TTransactionWrapper<1>(iClient, aStatus, spiHeader); + if(twr) + { + // 3. Create the transaction callback object (here we are using this driver's dfcque but it could be any + // other one (providing thread synchronization etc..) + TIicBusCallback *callback = new TIicBusCallback(SingleHalfDuplexTransCallback, (TAny*)twr, iDfcQ, 5); + + // 4. create buffer for transaction (and store it in a wrapper class) + HBuf8* txBuf = HBuf8::New(KTrasferBufferLength); + twr->iTxBuffers[0] = txBuf; + for(TInt i = 0; i < KTrasferBufferLength; i++) + { + txBuf->Append(i); // append some data to send.. + } + + // 5. create transfer (and store it in a wrapper class) + TIicBusTransfer* txTransfer = new TIicBusTransfer(TIicBusTransfer::EMasterWrite, 8, txBuf); + twr->iTxTransfers[0] = txTransfer; + + // 6. create transaction (no need to store it in the wrapper - this pointer is always passed to the + // callback (TODO: and only this could be really used in the callback...it's annoying that it's not yet!) + TIicBusTransaction* transaction = new TIicBusTransaction(spiHeader, txTransfer); + + // lazy approach - check result of all allocations here.. + if(twr && callback && txBuf && txTransfer && transaction) + { + r = IicBus::QueueTransaction(busId, transaction, callback); + } + else // ..and cleanup on error.. + { + r = KErrNoMemory; + } + } + + if(r != KErrNone) + { + delete twr; // this will clean all that was allocated already.. + } + } + + LOG_FUNCTION_RETURN; + return r; + } + +TInt DSpiClientChannel::AsyncHalfDuplexSingleRead(TRequestStatus* aStatus) { return KErrNotSupported; // TODO: not implemented yet.. } -TInt DSpiClientChannel::FullDuplexExtendable() +TInt DSpiClientChannel::AsyncHalfDuplexMultipleWrite(TRequestStatus* aStatus) + { + return KErrNotSupported; // TODO: not implemented yet.. + } + + +TInt DSpiClientChannel::AsyncHalfDuplexMultipleRead(TRequestStatus* aStatus) { return KErrNotSupported; // TODO: not implemented yet.. } +TInt DSpiClientChannel::AsyncHalfDuplexMultipleWriteRead(TRequestStatus* aStatus) + { + return KErrNotSupported; // TODO: not implemented yet.. + } + +TInt DSpiClientChannel::AsyncFullDuplexSingle(TRequestStatus* aStatus) + { + return KErrNotSupported; // TODO: not implemented yet.. + } + +TInt DSpiClientChannel::AsyncFullDuplexMultiple(TRequestStatus* aStatus) + { + return KErrNotSupported; // TODO: not implemented yet.. + } + + + diff -r 35fb7dda225a -r fdfa12d9a47a omap3530/omap3530_drivers/spi/test/d_spi_client_m.h --- a/omap3530/omap3530_drivers/spi/test/d_spi_client_m.h Sat Nov 06 15:14:41 2010 +0000 +++ b/omap3530/omap3530_drivers/spi/test/d_spi_client_m.h Fri Nov 19 00:43:42 2010 +0000 @@ -174,15 +174,87 @@ TInt HalfDuplexMultipleWriteRead(); TInt FullDuplexSingle(); TInt FullDuplexMultiple(); - TInt HalfDuplexExtendable(); - TInt FullDuplexExtendable(); + // set of example transfers with transactions queued asynchronously + // callback for asynchronous transactions.. + static void SingleHalfDuplexTransCallback(TIicBusTransaction* aTransaction, + TInt aBusId, + TInt aResult, + TAny* aParam); + // test functions.. + TInt AsyncHalfDuplexSingleWrite(TRequestStatus* aStatus); + TInt AsyncHalfDuplexSingleRead(TRequestStatus* aStatus); + TInt AsyncHalfDuplexMultipleWrite(TRequestStatus* aStatus); + TInt AsyncHalfDuplexMultipleRead(TRequestStatus* aStatus); + TInt AsyncHalfDuplexMultipleWriteRead(TRequestStatus* aStatus); + TInt AsyncFullDuplexSingle(TRequestStatus* aStatus); + TInt AsyncFullDuplexMultiple(TRequestStatus* aStatus); private: - TRequestStatus iStatus; DThread* iClient; }; +// template for wrapper class used in asynchronous transactions in order to manage +// pointers to buffers and allocated objects (to further access the data/release memory) + +template +class TTransactionWrapper + { +public: + TTransactionWrapper(DThread* aClient, TRequestStatus* aReqStatus, TConfigSpiBufV01* aHeader) : + iHeader(aHeader), + iCallback(NULL), + iClient(aClient), + iReqStatus(aReqStatus) + { + } + + TTransactionWrapper() : iHeader(NULL), iCallback(NULL), iClient(NULL), iReqStatus(NULL) + { + for(TUint i = 0; i < Size; ++i) + { + iTxBuffers[i] = NULL; + iRxBuffers[i] = NULL; + iTxTransfers[i] = NULL; + iRxTransfers[i] = NULL; + } + } + + inline HBuf8* GetRxBuffer(TInt index) + { + __ASSERT_DEBUG(index < Size, Kern::Fault("d_spi_client.h, line: %d", __LINE__)); + return iRxBuffers[index]; + } + + // destructor - to clean up all the objects.. + inline ~TTransactionWrapper() + { + // it is safe to call delete on a 'NULL' pointer + delete iHeader; + delete iCallback; + for(TUint i = 0; i < Size; ++i) + { + delete iTxBuffers[i]; + delete iTxTransfers[i]; + delete iRxBuffers[i]; + delete iRxTransfers[i]; + } + } + + // store all object used by transaction + TConfigSpiBufV01* iHeader; + TIicBusCallback *iCallback; + HBuf8* iTxBuffers[Size]; + HBuf8* iRxBuffers[Size]; + TIicBusTransfer* iTxTransfers[Size]; + TIicBusTransfer* iRxTransfers[Size]; + + // also store client and request information + DThread* iClient; + TRequestStatus* iReqStatus; + }; + + // Below is additional stuff for testing with local loopback // the IsLoopbackAvailable function checks if McSPI3 is configured to use pins from extension header // (Beagleboard) and if these pins are physically connected (e.g. with jumper)- in order to determine diff -r 35fb7dda225a -r fdfa12d9a47a omap3530/omap3530_drivers/spi/test/t_spi_client_m.cpp --- a/omap3530/omap3530_drivers/spi/test/t_spi_client_m.cpp Sat Nov 06 15:14:41 2010 +0000 +++ b/omap3530/omap3530_drivers/spi/test/t_spi_client_m.cpp Fri Nov 19 00:43:42 2010 +0000 @@ -69,10 +69,9 @@ void TestSynchronousOperation() { - test.Next(_L("TestSynchronousOperation()")); + test.Next(_L("TestSynchronousOperations:")); test.Next(_L("HalfDuplexSingleWrite()")); - while(1) TestError(testLdd.HalfDuplexSingleWrite()); test.Next(_L("HalfDuplexMultipleWrite()")); @@ -94,20 +93,34 @@ TestError(testLdd.FullDuplexMultiple()); } +void TestAsynchronousOperation() + { + test.Next(_L("Test_AsynchronousOperations:")); + + TRequestStatus status; + + test.Next(_L("HalfDuplexSingleWrite()")); + testLdd.HalfDuplexSingleWrite(status); + User::WaitForRequest(status); // wait for completion.. + if(status != KErrNone) + { + test.Printf(_L("Error was %d"), status.Int()); + test(EFalse); + } + + } TInt E32Main() { test.Title(); test.Start(_L("Testing SPI..")); - PrepareDriver(); TestSynchronousOperation(); + TestAsynchronousOperation(); ReleaseDriver(); - test.End(); - return KErrNone; }