Now you can download a copy of these docs so you can use them offline! Download now
SPI.cpp
00001 /*----------------------------------------------------------------------------*/ 00002 /* Copyright (c) FIRST 2008. All Rights Reserved. */ 00003 /* Open Source Software - may be modified and shared by FRC teams. The code */ 00004 /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */ 00005 /*----------------------------------------------------------------------------*/ 00006 00007 #include "SPI.h" 00008 00009 #include "ChipObject/tSPI.h" 00010 #include "DigitalInput.h" 00011 #include "DigitalOutput.h" 00012 #include "Synchronized.h" 00013 #include "WPIErrors.h" 00014 00015 #include <math.h> 00016 #include <usrLib.h> 00017 00018 SEM_ID SPI::m_semaphore = NULL; 00019 00029 SPI::SPI(DigitalOutput &clk, DigitalOutput &mosi, DigitalInput &miso) 00030 { 00031 Init(&clk, &mosi, &miso); 00032 } 00033 00043 SPI::SPI(DigitalOutput *clk, DigitalOutput *mosi, DigitalInput *miso) 00044 { 00045 Init(clk, mosi, miso); 00046 } 00047 00055 SPI::SPI(DigitalOutput &clk, DigitalOutput &mosi) 00056 { 00057 Init(&clk, &mosi, NULL); 00058 } 00059 00067 SPI::SPI(DigitalOutput *clk, DigitalOutput *mosi) 00068 { 00069 Init(clk, mosi, NULL); 00070 } 00071 00079 SPI::SPI(DigitalOutput &clk, DigitalInput &miso) 00080 { 00081 Init(&clk, NULL, &miso); 00082 } 00083 00091 SPI::SPI(DigitalOutput *clk, DigitalInput *miso) 00092 { 00093 Init(clk, NULL, miso); 00094 } 00095 00099 SPI::~SPI() 00100 { 00101 delete m_spi; 00102 } 00103 00113 void SPI::Init(DigitalOutput *clk, DigitalOutput *mosi, DigitalInput *miso) 00114 { 00115 if (m_semaphore == NULL) 00116 { 00117 m_semaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE); 00118 } 00119 00120 tRioStatusCode localStatus = NiFpga_Status_Success; 00121 m_spi = tSPI::create(&localStatus); 00122 wpi_setError(localStatus); 00123 00124 m_config.BusBitWidth = 8; 00125 m_config.ClockHalfPeriodDelay = 0; 00126 m_config.MSBfirst = 0; 00127 m_config.DataOnFalling = 0; 00128 m_config.LatchFirst = 0; 00129 m_config.LatchLast = 0; 00130 m_config.FramePolarity = 0; 00131 m_config.WriteOnly = miso ? 0 : 1; 00132 m_config.ClockPolarity = 0; 00133 00134 m_channels.SCLK_Channel = clk->GetChannelForRouting(); 00135 m_channels.SCLK_Module = clk->GetModuleForRouting(); 00136 m_channels.SS_Channel = 0; 00137 m_channels.SS_Module = 0; 00138 00139 if (mosi) 00140 { 00141 m_channels.MOSI_Channel = mosi->GetChannelForRouting(); 00142 m_channels.MOSI_Module = mosi->GetModuleForRouting(); 00143 } 00144 else 00145 { 00146 m_channels.MOSI_Channel = 0; 00147 m_channels.MOSI_Module = 0; 00148 } 00149 00150 if (miso) 00151 { 00152 m_channels.MISO_Channel = miso->GetChannelForRouting(); 00153 m_channels.MISO_Module = miso->GetModuleForRouting(); 00154 } 00155 else 00156 { 00157 m_channels.MISO_Channel = 0; 00158 m_channels.MISO_Module = 0; 00159 } 00160 00161 m_ss = NULL; 00162 } 00163 00170 void SPI::SetBitsPerWord(UINT32 bits) 00171 { 00172 m_config.BusBitWidth = bits; 00173 } 00174 00181 UINT32 SPI::GetBitsPerWord() 00182 { 00183 return m_config.BusBitWidth; 00184 } 00185 00192 void SPI::SetClockRate(double hz) 00193 { 00194 int delay = 0; 00195 // TODO: compute the appropriate values based on digital loop timing 00196 if (hz <= 76628.4) 00197 { 00198 double v = (1.0/hz)/1.305e-5; 00199 int intv = (int)v; 00200 if (v-intv > 0.5) 00201 delay = intv; 00202 else 00203 delay = intv-1; 00204 } 00205 if (delay > 255) 00206 { 00207 wpi_setWPIError(SPIClockRateTooLow); 00208 delay = 255; 00209 } 00210 m_config.ClockHalfPeriodDelay = delay; 00211 } 00212 00217 void SPI::SetMSBFirst() 00218 { 00219 m_config.MSBfirst = 1; 00220 } 00221 00226 void SPI::SetLSBFirst() 00227 { 00228 m_config.MSBfirst = 0; 00229 } 00230 00235 void SPI::SetSampleDataOnFalling() 00236 { 00237 m_config.DataOnFalling = 1; 00238 } 00239 00244 void SPI::SetSampleDataOnRising() 00245 { 00246 m_config.DataOnFalling = 0; 00247 } 00248 00260 void SPI::SetSlaveSelect(DigitalOutput *ss, tFrameMode mode, bool activeLow) 00261 { 00262 if (ss) 00263 { 00264 m_channels.SS_Channel = ss->GetChannelForRouting(); 00265 m_channels.SS_Module = ss->GetModuleForRouting(); 00266 } 00267 else 00268 { 00269 m_channels.SS_Channel = 0; 00270 m_channels.SS_Module = 0; 00271 } 00272 m_ss = ss; 00273 00274 switch (mode) 00275 { 00276 case kChipSelect: 00277 m_config.LatchFirst = 0; 00278 m_config.LatchLast = 0; 00279 break; 00280 case kPreLatchPulse: 00281 m_config.LatchFirst = 1; 00282 m_config.LatchLast = 0; 00283 break; 00284 case kPostLatchPulse: 00285 m_config.LatchFirst = 0; 00286 m_config.LatchLast = 1; 00287 break; 00288 case kPreAndPostLatchPulse: 00289 m_config.LatchFirst = 1; 00290 m_config.LatchLast = 1; 00291 break; 00292 } 00293 00294 m_config.FramePolarity = activeLow ? 1 : 0; 00295 } 00296 00308 void SPI::SetSlaveSelect(DigitalOutput &ss, tFrameMode mode, bool activeLow) 00309 { 00310 SetSlaveSelect(&ss, mode, activeLow); 00311 } 00312 00324 DigitalOutput *SPI::GetSlaveSelect(tFrameMode *mode, bool *activeLow) 00325 { 00326 if (mode != NULL) 00327 { 00328 *mode = (tFrameMode) (m_config.LatchFirst | (m_config.LatchLast << 1)); 00329 } 00330 if (activeLow != NULL) 00331 { 00332 *activeLow = m_config.FramePolarity != 0; 00333 } 00334 return m_ss; 00335 } 00336 00341 void SPI::SetClockActiveLow() 00342 { 00343 m_config.ClockPolarity = 1; 00344 } 00345 00350 void SPI::SetClockActiveHigh() 00351 { 00352 m_config.ClockPolarity = 0; 00353 } 00354 00358 void SPI::ApplyConfig() 00359 { 00360 Synchronized sync(m_semaphore); 00361 00362 tRioStatusCode localStatus = NiFpga_Status_Success; 00363 m_spi->writeConfig(m_config, &localStatus); 00364 m_spi->writeChannels(m_channels, &localStatus); 00365 m_spi->strobeReset(&localStatus); 00366 wpi_setError(localStatus); 00367 } 00368 00375 UINT16 SPI::GetOutputFIFOAvailable() 00376 { 00377 tRioStatusCode localStatus = NiFpga_Status_Success; 00378 UINT16 result = m_spi->readAvailableToLoad(&localStatus); 00379 wpi_setError(localStatus); 00380 return result; 00381 } 00382 00389 UINT16 SPI::GetNumReceived() 00390 { 00391 tRioStatusCode localStatus = NiFpga_Status_Success; 00392 UINT16 result = m_spi->readReceivedElements(&localStatus); 00393 wpi_setError(localStatus); 00394 return result; 00395 } 00396 00402 bool SPI::IsDone() 00403 { 00404 tRioStatusCode localStatus = NiFpga_Status_Success; 00405 bool result = m_spi->readStatus_Idle(&localStatus); 00406 wpi_setError(localStatus); 00407 return result; 00408 } 00409 00416 bool SPI::HadReceiveOverflow() 00417 { 00418 tRioStatusCode localStatus = NiFpga_Status_Success; 00419 bool result = m_spi->readStatus_ReceivedDataOverflow(&localStatus); 00420 wpi_setError(localStatus); 00421 return result; 00422 } 00423 00431 void SPI::Write(UINT32 data) 00432 { 00433 if (m_channels.MOSI_Channel == 0 && m_channels.MOSI_Module == 0) 00434 { 00435 wpi_setWPIError(SPIWriteNoMOSI); 00436 return; 00437 } 00438 00439 Synchronized sync(m_semaphore); 00440 00441 while (GetOutputFIFOAvailable() == 0) 00442 taskDelay(NO_WAIT); 00443 00444 tRioStatusCode localStatus = NiFpga_Status_Success; 00445 m_spi->writeDataToLoad(data, &localStatus); 00446 m_spi->strobeLoad(&localStatus); 00447 wpi_setError(localStatus); 00448 } 00449 00463 UINT32 SPI::Read(bool initiate) 00464 { 00465 if (m_channels.MISO_Channel == 0 && m_channels.MISO_Module == 0) 00466 { 00467 wpi_setWPIError(SPIReadNoMISO); 00468 return 0; 00469 } 00470 00471 tRioStatusCode localStatus = NiFpga_Status_Success; 00472 UINT32 data; 00473 { 00474 Synchronized sync(m_semaphore); 00475 00476 if (initiate) 00477 { 00478 m_spi->writeDataToLoad(0, &localStatus); 00479 m_spi->strobeLoad(&localStatus); 00480 } 00481 00482 // Do we have anything ready to read? 00483 if (GetNumReceived() == 0) 00484 { 00485 if (!initiate && IsDone() && GetOutputFIFOAvailable() == kTransmitFIFODepth) 00486 { 00487 // Nothing to read: error out 00488 wpi_setWPIError(SPIReadNoData); 00489 return 0; 00490 } 00491 00492 // Wait for the transaction to complete 00493 while (GetNumReceived() == 0) 00494 taskDelay(NO_WAIT); 00495 } 00496 00497 m_spi->strobeReadReceivedData(&localStatus); 00498 data = m_spi->readReceivedData(&localStatus); 00499 } 00500 wpi_setError(localStatus); 00501 00502 return data; 00503 } 00504 00508 void SPI::Reset() 00509 { 00510 tRioStatusCode localStatus = NiFpga_Status_Success; 00511 m_spi->strobeReset(&localStatus); 00512 wpi_setError(localStatus); 00513 } 00514 00518 void SPI::ClearReceivedData() 00519 { 00520 tRioStatusCode localStatus = NiFpga_Status_Success; 00521 m_spi->strobeClearReceivedData(&localStatus); 00522 wpi_setError(localStatus); 00523 }
Generated on Thu Jan 12 2012 22:35:24 for WPILibC++ by
1.7.1