Нет данных MISO и SCLK на низком уровне после WR с использованием spidev из пользовательской области
Я пытаюсь общаться через SPI в пользовательском пространстве Linux, используяspidev
Водитель. Физически этот интерфейс SPI представляет собой шину 4 (SCLK
,CS
, , ).
Для этого я приложил к своемуdts
соответствующий узел в соответствующем чипе. После загрузки Linux устройство становится доступным.
С использованиемc++
и согласноspi-test
Например, я обработал его как символьное устройство, поэтому я открываю его, требую полнодуплексную передачу и закрываю его (с соответствующими вызовами дляopen
,ioctl/spi_ioc_transfer
иclose
примитивы). Установленная конфигурация шины8
бит на слово при максимальной частоте1.29 MHz
и в режиме0
(другими словами,CPHA=CPOL=0
).
Затем с помощью осциллографа я вижу, что мой запрос присутствует в файле , но я не вижу никакого ответа в файле . Что мне не хватает?
В случае, если это поможет, я вижу, что тактовый сигнал падает уровень сразу после отправки данных черезMOSI
, поэтому имеет смысл, что я не получаю никаких данных вMISO
.
Кроме того, я проверил, что максимальная частота, а также все настройки были установлены правильно. У меня также есть baremetal-приложение, правильно использующее шину, поэтому любой аппаратный сбой исключен.
Spi.hpp
#pragma once
#include <string>
#include <sys/ioctl.h>
#include <cstring>
#include <fcntl.h>
#include <unistd.h>
#include <linux/spi/spidev.h>
#include <drivers/common/literals.hpp>
#include <drivers/common/Utils.hpp>
namespace interfaces
{
namespace spi
{
namespace lnx
{
enum class Mode
{
ZERO = SPI_MODE_0,
ONE = SPI_MODE_1,
TWO = SPI_MODE_2,
THREE = SPI_MODE_3
};
enum class Bpw
{
BITS_8 = 8,
BITS_16 = 16
};
enum class State
{
CLOSED,
OPEN
};
class Spi
{
public:
explicit Spi( const std::string& aDevice )
{
memset( &theFrame, 0, sizeof( struct spi_ioc_transfer ) );
theFileDescriptor = -1;
theState = State::CLOSED;
theFrame[0].delay_usecs = 0;
// Do keep CS activated
theFrame[0].cs_change = 0;
if( setDevice( aDevice ) != ErrorCode::OPERATION_SUCESS )
{
trace( DEBUG_GENERAL, "error setting device\r\n" );
}
if( setMode( Mode::ZERO ) != ErrorCode::OPERATION_SUCESS )
{
trace( DEBUG_GENERAL, "error setting mode\r\n" );
}
if( setBitsPerWord( Bpw::BITS_8 ) != ErrorCode::OPERATION_SUCESS )
{
trace( DEBUG_GENERAL, "error setting bpw\r\n" );
}
// Set the SPI device pre-scaler to divide by 128
// (SPI_CLK_FREQ_HZ = 166 MHz) to transfer below 2MHz clock rate.
if( setMaxSpeedHz( ( 166 / 128.0 ) * 1000000 ) != ErrorCode::OPERATION_SUCESS )
{
trace( DEBUG_GENERAL, "error setting maximum speed\r\n" );
}
}
virtual ~Spi( void )
{
if( theState != State::CLOSED && theFileDescriptor != -1 )
{
if( close() != ErrorCode::OPERATION_SUCESS )
{
trace(
DEBUG_GENERAL,
"error closing device %s\r\n",
theDevice.c_str() );
}
}
}
Spi( const Spi& ) = delete;
Spi& operator=( const Spi& ) = delete;
inline std::string getDevice( void )
{
return this->theDevice;
}
inline ErrorCode setDevice( const std::string& aDevice )
{
ErrorCode anErrorCode = ErrorCode::CANT_CONFIGURE_INTERFACE;
if( theState != State::CLOSED && theFileDescriptor != -1 )
{
if ( close() != ErrorCode::OPERATION_SUCESS )
{
goto exit;
}
}
this->theDevice = aDevice;
anErrorCode = open();
exit:
return std::move( anErrorCode );
}
inline ErrorCode setMode( const Mode& aMode )
{
ErrorCode anErrorCode = ErrorCode::CANT_CONFIGURE_INTERFACE;
if( theState != State::CLOSED && theFileDescriptor != -1 )
{
if( ::ioctl(
theFileDescriptor,
SPI_IOC_WR_MODE32,
&aMode ) != -1 )
{
auto aResult = getMode();
if( aResult.first == ErrorCode::OPERATION_SUCESS &&
aResult.second == aMode )
{
anErrorCode = ErrorCode::OPERATION_SUCESS;
trace(
DEBUG_INFO,
"mode set to %d\r\n",
aMode );
}
else
{
close();
trace(
DEBUG_GENERAL,
"mode incongruence\r\n" );
}
}
else
{
close();
trace(
DEBUG_GENERAL,
"failed setting mode\r\n" );
}
}
return std::move( anErrorCode );
}
inline std::pair<ErrorCode, Mode> getMode( void )
{
Mode aMode;
ErrorCode anErrorCode = ErrorCode::CANT_CONFIGURE_INTERFACE;
if( theState != State::CLOSED && theFileDescriptor != -1 )
{
if( ::ioctl(
theFileDescriptor,
SPI_IOC_RD_MODE32,
&aMode ) != -1 )
{
anErrorCode = ErrorCode::OPERATION_SUCESS;
}
else
{
trace(
DEBUG_GENERAL,
"failed reading mode\r\n" );
}
}
return std::make_pair( anErrorCode, aMode );
}
inline ErrorCode setBitsPerWord( const Bpw& aBitsPerWord )
{
ErrorCode anErrorCode = ErrorCode::CANT_CONFIGURE_INTERFACE;
if( theState != State::CLOSED && theFileDescriptor != -1 )
{
if( ::ioctl(
theFileDescriptor,
SPI_IOC_WR_BITS_PER_WORD,
&aBitsPerWord ) != -1 )
{
auto aResult = getBitsPerWord();
if( aResult.first == ErrorCode::OPERATION_SUCESS &&
aResult.second == aBitsPerWord )
{
anErrorCode = ErrorCode::OPERATION_SUCESS;
theFrame[0].bits_per_word =
static_cast<uint8_t>( aBitsPerWord );
trace(
DEBUG_INFO,
"bpw set to %d\r\n",
aBitsPerWord );
}
else
{
close();
trace(
DEBUG_GENERAL,
"bpw incongruence\r\n" );
}
}
else
{
close();
trace(
DEBUG_GENERAL,
"failed setting bpw\r\n" );
}
}
return std::move( anErrorCode );
}
inline std::pair<ErrorCode, Bpw> getBitsPerWord( void )
{
uint8_t aBitsPerWord;
ErrorCode anErrorCode = ErrorCode::CANT_CONFIGURE_INTERFACE;
if( theState != State::CLOSED && theFileDescriptor != -1 )
{
if( ::ioctl(
theFileDescriptor,
SPI_IOC_RD_BITS_PER_WORD,
&aBitsPerWord ) != -1 )
{
anErrorCode = ErrorCode::OPERATION_SUCESS;
}
else
{
trace(
DEBUG_GENERAL,
"failed reading bpw\r\n" );
}
}
return std::make_pair(
anErrorCode,
static_cast<Bpw>( aBitsPerWord ) );
}
inline ErrorCode setMaxSpeedHz( const uint32_t aSpeed )
{
ErrorCode anErrorCode = ErrorCode::CANT_CONFIGURE_INTERFACE;
if( theState != State::CLOSED && theFileDescriptor != -1 )
{
if( ::ioctl(
theFileDescriptor,
SPI_IOC_WR_MAX_SPEED_HZ,
&aSpeed ) != -1 )
{
auto aResult = getMaxSpeedHz();
if( aResult.first == ErrorCode::OPERATION_SUCESS &&
aResult.second == aSpeed )
{
anErrorCode = ErrorCode::OPERATION_SUCESS;
theFrame[0].speed_hz = aSpeed;
trace(
DEBUG_INFO,
"maximum speed set to %d Hz\r\n",
aSpeed );
}
else
{
close();
trace(
DEBUG_GENERAL,
"maximum speed incongruence\r\n" );
}
}
else
{
close();
trace(
DEBUG_GENERAL,
"failed setting maximum speed\r\n" );
}
}
return std::move( anErrorCode );
}
inline std::pair<ErrorCode, uint32_t> getMaxSpeedHz( void )
{
uint32_t aSpeed;
ErrorCode anErrorCode = ErrorCode::CANT_CONFIGURE_INTERFACE;
if( theState != State::CLOSED && theFileDescriptor != -1 )
{
if( ::ioctl(
theFileDescriptor,
SPI_IOC_RD_MAX_SPEED_HZ,
&aSpeed ) != -1 )
{
anErrorCode = ErrorCode::OPERATION_SUCESS;
}
else
{
trace(
DEBUG_GENERAL,
"failed setting maximum speed\r\n" );
}
}
return std::make_pair( anErrorCode, aSpeed );
}
std::pair<ErrorCode, std::vector<uint8_t>> transfer(
const std::vector<uint8_t>& aBuffer,
uint32_t aLenght );
std::pair<ErrorCode, std::vector<uint8_t>>
read( uint32_t aLenght );
ErrorCode write( const std::vector<uint8_t>& aBuffer );
private:
ErrorCode open( void );
ErrorCode close( void );
int32_t theFileDescriptor;
std::string theDevice;
struct spi_ioc_transfer theFrame[1];
State theState;
};
} // end namespace lnx
} // end namespace spi
} // end namespace interfaces
Spi.cpp
#include <interfaces/lnx/Spi.hpp>
namespace interfaces
{
namespace spi
{
namespace lnx
{
ErrorCode Spi::open( void )
{
ErrorCode anErrorCode = ErrorCode::CANT_OPEN_DEV;
if( !theDevice.empty() )
{
theFileDescriptor = ::open(
theDevice.c_str(), O_SYNC | O_RDWR );
if( theFileDescriptor != -1 )
{
anErrorCode = ErrorCode::OPERATION_SUCESS;
theState = State::OPEN;
trace(
DEBUG_INFO,
"device %s opened\r\n",
theDevice.c_str() );
}
else
{
trace(
DEBUG_GENERAL,
"device %s could not be opened\r\n",
theDevice.c_str() );
}
}
return std::move( anErrorCode );
}
ErrorCode Spi::close( void )
{
ErrorCode anErrorCode = ErrorCode::CANT_CLOSE_DEV;
if( theState != State::CLOSED && theFileDescriptor != -1 )
{
if( ::close( theFileDescriptor ) == 0 )
{
anErrorCode = ErrorCode::OPERATION_SUCESS;
theFileDescriptor = -1;
theState = State::CLOSED;
trace(
DEBUG_INFO,
"device %s closed\r\n",
theDevice.c_str() );
}
}
return std::move( anErrorCode );
}
std::pair<ErrorCode, std::vector<uint8_t>> Spi::transfer(
const std::vector<uint8_t>& aRequest, uint32_t aLenght )
{
std::vector<uint8_t> aBuffer( aLenght, 0xFF );
ErrorCode anErrorCode = ErrorCode::CANT_READ_FROM_INTERFACE;
if( aRequest.empty() || aLenght <= 0 )
{
trace(
DEBUG_GENERAL,
"provided arguments not complains the conditions\r\n" );
goto exit;
}
if( theState != State::CLOSED && theFileDescriptor != -1 )
{
theFrame[0].tx_buf = reinterpret_cast<uintptr_t>( aRequest.data() );
theFrame[0].rx_buf = reinterpret_cast<uintptr_t>( &aBuffer[0] );
// Length of the command to write/read
theFrame[0].len = aLenght;
if( ::ioctl(
theFileDescriptor,
SPI_IOC_MESSAGE( 1 ),
&theFrame ) < 1 )
{
trace(
DEBUG_GENERAL,
"failed doing full duplex transfer\r\n" );
}
else
{
anErrorCode = ErrorCode::OPERATION_SUCESS;
vprint( aBuffer.data(), aBuffer.size() );
}
}
exit:
return std::make_pair( anErrorCode, aBuffer );
}
std::pair<ErrorCode, std::vector<uint8_t>>
Spi::read( uint32_t aLenght )
{
std::vector<uint8_t> aBuffer( aLenght, 0xFF );
ErrorCode anErrorCode = ErrorCode::CANT_READ_FROM_INTERFACE;
if( aLenght <= 0 )
{
trace(
DEBUG_GENERAL,
"provided arguments not complains the conditions\r\n" );
goto exit;
}
if( theState != State::CLOSED && theFileDescriptor != -1 )
{
theFrame[0].tx_buf = static_cast<uintptr_t>( NULL );
theFrame[0].rx_buf = reinterpret_cast<uintptr_t>( &aBuffer[0] );
theFrame[0].len = aLenght;
if( ::ioctl(
theFileDescriptor,
SPI_IOC_MESSAGE( 1 ),
&theFrame ) < 1 )
{
trace(
DEBUG_GENERAL,
"failed receiving message\r\n" );
}
else
{
anErrorCode = ErrorCode::OPERATION_SUCESS;
vprint( aBuffer.data(), aBuffer.size() );
}
}
exit:
return std::make_pair( anErrorCode, aBuffer );
}
ErrorCode Spi::write( const std::vector<uint8_t>& aBuffer )
{
ErrorCode anErrorCode = ErrorCode::CANT_WRITE_TO_INTERFACE;
if( aBuffer.empty() )
{
trace(
DEBUG_GENERAL,
"provided arguments not complains the conditions\r\n" );
goto exit;
}
if( theState != State::CLOSED && theFileDescriptor != -1 )
{
theFrame[0].tx_buf = reinterpret_cast<uintptr_t>( aBuffer.data() );
theFrame[0].rx_buf = static_cast<uintptr_t>( NULL );
theFrame[0].len = aBuffer.size();
if( ::ioctl(
theFileDescriptor,
SPI_IOC_MESSAGE( 1 ),
&theFrame ) < 1 )
{
trace(
DEBUG_GENERAL,
"failed sending message\r\n" );
}
else
{
anErrorCode = ErrorCode::OPERATION_SUCESS;
vprint( aBuffer.data(), aBuffer.size() );
}
}
exit:
return std::move( anErrorCode );
}
} // end namespace lnx
} // end namespace spi
} // end namespace interfaces
myboard.dts
...
&spi0 {
num-cs = <2>;
spi-cpol = <0>;
spi-cpha = <0>;
status = "okay";
spidev@0 {
compatible = "xlnx,spidev";
reg = <0>;
spi-max-frequency = <1296875>;
};
};
...
я используюtransfer
функция для достижения моей цели в течениеlnx-xlnx 4.14