Нет данных 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

0 ответов

Другие вопросы по тегам