Как исправить драйвер SPI, который всегда не проходит проверку в драйвере SPI ядра Linux - PullRequest
2 голосов
/ 17 апреля 2019

Я использую встроенный Linux (4.14.16), созданный с помощью Yocto (Pyro).Я работаю на специальной плате с i.MX6DL, а SPI подключен к FPGA (Xilinx Artix 7).В настоящее время я пишу класс, который является частью уровня абстракции, поэтому этот код находится поверх драйверов Linux.Это не драйвер устройства Linux.SPI работает;Я могу запрограммировать FPGA с помощью сценария оболочки и видеть трафик SPI, если эхо-данные передаются в /dev/spi1.0 (FPGA выводит SPI в заголовок, к которому подключен анализатор).

Проблема в том, что когда я использую свой драйвер для чтения регистров в ПЛИС, он ничего не отправляет;передача SPI не происходит.

Я немного покопался в драйверах spidev и spi в Linux, и я вижу, что он проваливает вызов __spi_validate в drivers / spi / spi.c прямо под комментарием /* check transfer rx_nbits */.Что контролирует эти биты?Все на нашей плате - один бит данных за такт, у нас нет quad-spi.

Вот код, о котором идет речь:

#include "os/drivers/buses/linuxos/spi_driver.h"

#include <fcntl.h>
#include <sstream>
#include <stdio.h>
#include <unistd.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>

namespace os
{
namespace drivers
{
namespace buses
{
namespace linuxos
{
spi_driver::spi_driver(int bus_id, int cs_index, std::uint32_t speed_bps) :
    m_speed_bps(speed_bps)
{
    std::stringstream descriptor;
    descriptor << "/dev/spidev" << bus_id << '.' << cs_index;
    m_device_file_descriptor = descriptor.str();
}

bool spi_driver::transfer(const unsigned char *out_data, unsigned char *in_data, size_t size_in_bytes)
{
    int spi_file_handle = open(m_device_file_descriptor.c_str(), O_RDWR);
    bool success = (spi_file_handle >= 0);

    if (success)
    {
        printf("spidev opened\n");
        struct spi_ioc_transfer transfer_parameters;
        transfer_parameters.tx_buf = reinterpret_cast<unsigned long>(out_data);
        transfer_parameters.rx_buf = reinterpret_cast<unsigned long>(in_data);
        transfer_parameters.len = size_in_bytes;
        transfer_parameters.speed_hz = m_speed_bps;
        transfer_parameters.bits_per_word = 0;
        // transfer_parameters.cs_change = 0;
        // transfer_parameters.delay_usecs = 0;

        int ioctl_return = ioctl(spi_file_handle, SPI_IOC_MESSAGE(1), &transfer_parameters);

        printf("spidev ioctl returned %d\n", ioctl_return);

        success = (ioctl_return > 0);

        printf("Received data: ");
        for (unsigned int i = 0; i < size_in_bytes; i++)
        {
            printf("%02x ", in_data[i]);
        }
        printf("\n");
    }

    close(spi_file_handle);

    return success;
}
}
}
}
}

Я не уверен, что это актуально (SPI, кажется, работает ...), но вот часть SPI дерева устройств.

&ecspi2 {
    cs-gpios = <&gpio5 12 GPIO_ACTIVE_HIGH>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_ecspi2 &pinctrl_ecspi2_cs>;
    status = "okay";

    simulator-fpga {
        compatible = "mi,simulator-fpga";
        spi-max-frequency = <8000000>;
        reg = <0>;
    };
};

mi, simulator-fpga был добавлен в совместимую строку универсального драйвера spidev, поскольку он печатает ошибку, если вы используете spidev напрямую, но это универсальное устройство spidev.

Я пробовал просто использовать функции чтения и записи Linux, которые работали (я видел трафик на анализаторе SPI), но мне нужны полнодуплексные передачи, которые нельзя сделать с помощью этого метода.

Редактировать: Если кому-то интересно, что выводят эти операторы printf, вот что я получаю из них:

spidev opened
spidev ioctl returned -1
Received data: 00 00 00 00 00 00 00 00

Полученные данные имеют правильную длину для отправляемого сообщения.Я не уверен, почему это возвращает -1 для возвращаемого значения, ошибка, выдаваемая в spi.c в ядре, равна -22 (EINVAL / Invalid аргумент), как отмечено выше.

1 Ответ

0 голосов
/ 22 апреля 2019

Так что я не уверен, почему это требуется, но эта версия драйвера, кажется, работает.Я добавил все дополнительные ioctl, которые были в в этом примере. Хотя моя ПЛИС все еще не любит вывод (даже при том, что он работал нормально с 3.14), он выглядит корректно на логическом анализаторе и через анализатор протокола.

#include "os/drivers/buses/linuxos/spi_driver.h"

#include <fcntl.h>
#include <sstream>
#include <stdio.h>
#include <unistd.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>

namespace os
{
namespace drivers
{
namespace buses
{
namespace linuxos
{
spi_driver::spi_driver(int bus_id, int cs_index, std::uint32_t speed_bps) :
    m_speed_bps(speed_bps)
{
    std::stringstream descriptor;
    descriptor << "/dev/spidev" << bus_id << '.' << cs_index;
    m_device_file_descriptor = descriptor.str();
}

bool spi_driver::transfer(const unsigned char *out_data, unsigned char *in_data, size_t size_in_bytes)
{
    int spi_file_handle = open(m_device_file_descriptor.c_str(), O_RDWR);
    bool success = (spi_file_handle >= 0);

    const std::uint8_t mode = 3;
    const std::uint8_t bits = 8;
    int ioctl_return = 0;

    if (success)
    {
        ioctl_return = ioctl(spi_file_handle, SPI_IOC_WR_MODE, &mode);
        if (ioctl_return != 0)
            success = false;

        ioctl_return = ioctl(spi_file_handle, SPI_IOC_RD_MODE, &mode);
        if (ioctl_return != 0)
            success = false;

        ioctl_return = ioctl(spi_file_handle, SPI_IOC_WR_BITS_PER_WORD, &bits);
        if (ioctl_return != 0)
            success = false;

        ioctl_return = ioctl(spi_file_handle, SPI_IOC_RD_BITS_PER_WORD, &bits);
        if (ioctl_return != 0)
            success = false;

        ioctl_return = ioctl(spi_file_handle, SPI_IOC_WR_MAX_SPEED_HZ, &m_speed_bps);
        if (ioctl_return != 0)
            success = false;

        ioctl_return = ioctl(spi_file_handle, SPI_IOC_RD_MAX_SPEED_HZ, &m_speed_bps);
        if (ioctl_return != 0)
            success = false;
    }

    if (success)
    {
        struct spi_ioc_transfer tr;
        tr.tx_buf = reinterpret_cast<unsigned long>(out_data);
        tr.rx_buf = reinterpret_cast<unsigned long>(in_data);
        tr.len = size_in_bytes;
        tr.delay_usecs = 0;
        tr.speed_hz = 0;
        tr.bits_per_word = 0;

        ioctl_return = ioctl(spi_file_handle, SPI_IOC_MESSAGE(1), &tr);
        success = (ioctl_return != 1);
    }

    close(spi_file_handle);

    return success;
}
}
}
}
}
...