Руководство по разработке SPI для Linux
Руководство по разработке SPI для Linux

Каталог статей

Руководство по разработке SPI для Linux

1 Предисловие

1.1 Введение в документ

представлять SPI Модуль метода изиспользовать,удобныйоткрытьразработчикииспользовать。

1.2 Целевые читатели

Разработчик/сопровождающий драйвера для модуля SPI.

1.3 Область применения

Таблица 1-1: Список применимой продукции

Версия ядра

файл драйвера

Linux-4.9

spi-sunxi.c

Linux-5.4

spi-sunxi.c

2 Введение в модуль

2.1 Знакомство с функциями модуля

SPI — это высокоскоростная и высокоэффективная технология последовательного интерфейса. Обычно он состоит из ведущего модуля и одного или нескольких ведомых модулей. Главный модуль выбирает ведомый модуль для синхронной связи для завершения обмена данными. Он широко используется между АЦП, ЖК-дисплеем и другим оборудованием и MCU. Spi-контроллер Allwinner поддерживает следующие функции:

Полнодуплексный синхронный последовательный интерфейс.

поддерживать 5 выбор источника синхронизации.

поддерживать master и slave Две конфигурации.

четыре cs Выбор фильмаподдерживать。

8bit Ширина и 64 байт fifo глубина.

cs и clk Из полярности и фазы можно Конфигурация.

поддерживатьиспользовать DMA。

поддерживатьчетыре вида общениямодель.

Массовое производство поддерживаетMAXиз io ставка 100MHz。

поддерживать 3 Линия, 4 Проволока SPI модель.

Поддерживает длину кадра данных программируемой последовательной линии: 0~32 бита.

поддерживать Standard SPI/Dual-Output/Dual-input SPI/Dual i/O SPI/ и Quad-Output/Quad Input SPI。

2.2 Введение в связанные термины

2.2.1 Аппаратная терминология

Таблица 2-1: Аппаратная терминология

термин

Объяснение

SPI

Последовательный периферийный интерфейс, синхронный последовательный периферийный интерфейс

2.2.2 Терминология программного обеспечения

​ поверхность 2-2: программное обеспечениетермин

термин

Объяснение

Sunxi

Относится к серии аппаратных платформ SOC компании Allwinner.

SPI Master

SPI-мастер

SPI Device

Относится к внешнему устройству SPI.

2.3 Введение в настройку модуля

2.3.1 инструкции по настройке дерева устройств

безразличный Sunxi В аппаратной платформе SPI Количество контроллеров также варьируется, но для каждого SPI Для контроллера параметры конфигурации середина дерева устройств существования аналогичны, файл дерева устройств платформы имеет путь для: kernel/Версия ядра/arch/arm64(32 рычаг битовой платформы)/boot/dts/sunxi/CHIP.dtsi(CHIP — это кодовое название НИОКР, например sun50iw10p1 и т. д.), для настройки Для SPI1 это выглядит следующим образом:

Язык кода:javascript
копировать
spi1: spi@05011000 {
    #address-cells = <1>;
    #size-cells = <0>;
    compatible = "allwinner,sun50i-spi";          //Специально для устройства, используется для привязки драйвера и устройства
    device_type = "spi1";                         //Имя узла устройства
    reg = <0x0 0x05011000 0x0 0x1000>;            // Конфигурация всех проводных регистров
    interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;//общий Проволокасередина Номер перерыва、тип разрыва середина
    clocks = <&clk_pll_periph0>, <&clk_spi1>;     //Устройствоиспользования часов
    clock-frequency = <100000000>;                //Контроллер тактовой частоты
    pinctrl-names = "default", "sleep";           //ControlleruseizPin name
    pinctrl-0 = <&spi1_pins_a &spi1_pins_b>;      //контроллериспользоватьизpinступня Конфигурация    pinctrl-1 = <&spi1_pins_c>;                   //контроллериспользоватьизpinступня Конфигурация    spi1_cs_number = <1>;                         //Количество контактов контроллера cs
    spi1_cs_bitmap = <1>;                       /* cs0- 0x1; cs1-0x2, cs0&cs1-0x3. */
    status = "disabled";                          //Включен ли контроллер
};

существовать Linux-5.4 версия ядра, с Linux-4.9 Конфигурация ядра немного другая, в основном существует clock и dma По конфигурации:

Язык кода:javascript
копировать
spi1: spi@4026000 {
    #address-cells = <1>;
    #size-cells = <0>;
    compatible = "allwinner,sun20i-spi";  //Специально для устройства, используется для привязки драйвера и устройства
    reg = <0x0 0x04026000 0x0 0x1000>;    //Имя узла устройства 
    interrupts-extended = <&plic0 32 IRQ_TYPE_LEVEL_HIGH>;//общий Проволокасередина Номер перерыва、тип разрыва середина
    clocks = <&ccu CLK_PLL_PERIPH0>, <&ccu CLK_SPI1>, <&ccu CLK_BUS_SPI1>;//оборудованиеиспользовать изчас    clock-names = "pll", "mod", "bus";  //Устройствоиспользования часовимя
    resets = <&ccu RST_BUS_SPI1>;       //Устройство сбрасывает часы
    clock-frequency = <100000000>;      //Контроллер тактовой частоты
    spi1_cs_number = <1>;               //Количество контактов контроллера cs
    spi1_cs_bitmap = <1>;               /* cs0- 0x1; cs1-0x2, cs0&cs1-0x3. */
    dmas = <&dma 23>, <&dma 23>;        //Контроллериспользуетиздмс номер канала
    dma-names = "tx", "rx";             //Номер канала использования контроллера соответствует названию
    status = "disabled";                //Включен ли контроллер
};

для Понятносуществовать SPI Общий код драйвера Проволока середина отличает каждого человека SPI Контроллер, необходимый для существования Device Tree в aliases для каждого узла SPI Указанный псевдоним узла:

Язык кода:javascript
копировать
aliases {
    soc_spi0 = &spi0;
    soc_spi1 = &spi1;
    ...
};

Форма псевдонима представляет собой строку “spi” Сложите последовательные числа из цифр, существуют SPI Драйвер Total Profila середина доступен через of_alias_get_id() Функция получает соответствующее SPI Контроллер имеет цифровой номер, что позволяет различать каждый SPI контроллер.

в Версия ядрадля Linux-4.9 из spi1_pins_a, spi1_pins_b из Конфигурацияпуть к файлудля kernel/linux-4.9/arch/arm64(32 Битовая платформа Arm)/boot/dts/sunxi/xxx-pinctrl.dtsi, конкретная конфигурация выглядит следующим образом:

Язык кода:javascript
копировать
spi1_pins_a: spi1@0 {
    allwinner,pins = "PH4", "PH5", "PH6";
    allwinner,pname = "spi1_sclk", "spi1_mosi", 
                      "spi1_miso"; 
    allwinner,function = "spi1";
    allwinner,muxsel = <2>;
    allwinner,drive = <1>;
    allwinner,pull = <0>;
};

spi1_pins_b: spi1@1 {
    allwinner,pins = "PH3";
    allwinner,pname = "spi1_cs0";
    allwinner,function = "spi1";
    allwinner,muxsel = <2>;
    allwinner,drive = <1>;
    allwinner,pull = <1>; // only CS should be pulled up
};

spi1_pins_c: spi1@2 {
    allwinner,pins = "PH3", "PH4", "PH5", "PH6";
    allwinner,function = "io_disabled";
    allwinner,muxsel = <7>;
    allwinner,drive = <1>;
    allwinner,pull = <0>;
};

Версия ядра для Linux-5.4 из spi1_pins_a, spi1_pins_b из конкретной конфигурации следующим образом:

Язык кода:javascript
копировать
spi1_pins_a: spi1@0 {
    pins = "PD11", "PD12", "PD13";
    function = "spi1";
    drive-strength = <10>;
};

spi1_pins_b: spi1@1 {
    pins = "PD10"; 
    function = "spi1";
    drive-strength = <10>;
    bias-pull-up; /* only CS should be pulled up */
};

spi1_pins_c: spi1@2 {
    pins = "PD10", "PD11", "PD12", "PD13";
    function = "gpio_in";
};
2.3.2 Инструкции по настройке board.dts

board.dts Используется для сохранения различий между устройствами платформы на уровне платы из информации и дополнений (например, demo Доска, демо2.0 Доска, версия 1 доска и т. д.), на нее будет наложена находящаяся внутри информация. device tree Информация о конфигурации по умолчанию.

board.dts из Путь для/device/config/chips/{IC}/configs/{BOARD}/board.dts, в SPI1 из Конкретная конфигурация следующая:

иллюстрировать

существовать Linux-5.4 Версия ядросерединапара board.dts Грамматика была изменена таким образом, что узлы с одинаковым именем больше не подпадают под действие и поддерживаются. “&” Узел ссылки на символ.

Язык кода:javascript
копировать
&spi1 {
    clock-frequency = <100000000>;
    pinctrl-0 = <&spi1_pins_a &spi1_pins_b>;
    pinctrl-1 = <&spi1_pins_c>;
    pinctrl-names = "default", "sleep";
    spi_slave_mode = <0>;
    status = "disabled";

    spi_board1@0 {
        device_type = "spi_board1";
        compatible = "rohm,dh2228fv";
        spi-max-frequency = <0x5f5e100>;
        reg = <0x0>;
        spi-rx-bus-width = <0x4>;
        spi-tx-bus-width = <0x4>;
        status = "disabled";
    };
};

Обратите внимание: если вы хотите использовать spi slave режим, пожалуйста, поставьте spi_slave_mode = <0> Изменить на: spi_slave_mode = <1>。

spi_board1 также имеет некоторые настраиваемые параметры, такие как:

spi-cpha и spi-cpol: конфигурация spi из Четыре вида модели передачи.

spi-cs-high: конфигурация cs Когда вывод находится в допустимом состоянии, он находится на уровне «из».

spi1_pins_a, spi1_pins_b, spi1_pins_c Конкретная конфигурация следующая:

Язык кода:javascript
копировать
spi1_pins_a: spi1@0 {
    pins = "PD11", "PD12", "PD13","PD14", "PD15"; /*clk mosi miso hold wp*/
    function = "spi1";
    drive-strength = <10>;
};

spi1_pins_b: spi1@1 {
    pins = "PD10";
    function = "spi1";
    drive-strength = <10>;
    bias-pull-up; // only CS should be pulled up
};

spi1_pins_c: spi1@2 {
    allwinner,pins = "PD10", "PD11", "PD12", "PD13","PD14", "PD15";
    allwinner,function = "gpio_in";
    allwinner,muxsel = <0>;
    drive-strength = <10>;
};
2.3.3 Инструкции по настройке менюconfig

существует командная строка середина для входа в ядро linux каталог, выполнить make ARCH=arm64 menuconfig(32 Битовая система make ARCH=arm menuconfig) Войдите в основной интерфейс конфигурации (Linux-5.4 Версия выполнение ядра: ./build.sh Menuconfig) и выполните следующие действия.

Выберите опцию «Драйверы устройств», чтобы перейти на следующий уровень конфигурации, как показано на рисунке ниже.

Рисунок 2-1: Параметры конфигурации драйверов устройств

Выберите опцию поддержки SPI, чтобы перейти на следующий уровень конфигурации, как показано на рисунке ниже.

Рисунок 2-2: Параметры конфигурации поддержки SPI

Выберите опцию SUNXI SPI Controller, и вы сможете скомпилировать его непосредственно в ядро ​​или скомпилировать в модуль. Как показано ниже.

Рисунок 2-3: Параметры конфигурации контроллера SUNXI SPI

Если ты хочешь отпустить spi из Некоторые отладочные отпечатки, которые можно выбрать Debug support for SPI drivers。

2.4 Введение в структуру исходного кода

SPI Полный драйвер Проволока из исходного кода находится в ядре. drivers/spi В каталоге:

Язык кода:javascript
копировать
 drivers/spi/
  ├── spi-sunxi.c // Код драйвера контроллера SPI платформы Sunxi
  ├── spi-sunxi.h // Драйвер контроллера SPI для платформыSunxi определяет некоторые макросы и структуры данных.

2.5 Введение в структуру драйверов

Архитектура SPI в Linux разделена на три уровня, как показано на рисунке ниже.

Рисунок 2-4: Схема архитектуры Linux SPI

2.5.1 Пользовательское пространство

включить всеиспользовать SPI Устройство из приложения, существующее. Этот уровень пользователей может действовать в соответствии со своими реальными потребностями. spi Устройство выполняет некоторую специальную обработку, которая в данный момент неизвестна драйверу контроллера. Специфические функции устройства, SPI Конкретные функции устройства дополняются программами пользовательского уровня. Например, и MTD взаимодействие слоев, чтобы SPI ловитьиз устройства хранения данных для индивидуальной файловой системы, иTTY Дескриптор взаимодействия с подсистемой SPI Устройство реализовано как TTY Взаимодействие устройства и сетевой подсистемы поставит индивидуальное SPI Устройство реализовано как сетевое оборудование и т.д. Конечно, если это индивидуальная собственность. SPI Для оборудования мы также можем реализовать собственный драйвер протокола в соответствии с требованиями протокола оборудования. При этом мы не используем эту часть фокуса на。

2.5.2 Пространство ядра

пространство ядра мы также разделим на три части:

2.5.2.1 Уровень драйвера контроллера SPI

Учитывая дажеловитьсуществовать SPI Из-за изменчивости устройства на контроллере, существующее ядро ​​не оснащено соответствующим драйвером протокола, для В этом случае ядро ​​для мы подготовили универсальный из SPI драйвер устройства, универсальный драйвер устройства, который обеспечивает контроль над пользовательским пространством SPI Управление по управлению ловить портом, конкретная работа по управлению протоколом и передаче данных передается пользователю. Пространство комплектуется в соответствии со спецификой существующего оборудования, таким образом середина может использоваться только в синхронном методе. SPI устройства обмениваются данными, поэтому к обычно используется для некоторого простого SPI с небольшим объемом данных. оборудование.

Этот слой соответствует нашему ядру. spidev.c этотиндивидуальныйстандартныйиз spi Драйвер устройства, или наша компания из spi–nand.c,поддерживать spi Соглашение из nand Водитель и т. д. Для конкретного из SPI Оборудование для реализации конкретных функций, в том числе read,write а также ioctl Подождите, пока пользовательский уровень изловит порт. СПИ Общий драйвер Проволока в основном реализован для конкретных SPI Контроллер из всех методов чтения и записи Проволока и зарегистрируйтесь Linux Ядро из SPI Архитектура,СПИ Периферийные устройства могут пройти SPI Архитектура дополняет оборудование и полную адаптацию Проволокаиз. Однако сам общий драйвер Проволока не осуществляет никакой связи. Он только обеспечивает реализацию связи и ждет, пока драйвер устройства вызовет свои функции. СПИ Core из Руководство просто заблокировало это SPI Общий драйвер Проволока из разницы, которая составляет SPI Драйвер устройства может игнорировать различные общие различия контроллера и не должен учитывать, как они работают. обеспечение Устройство связииз Подробнее.

2.5.2.2 Уровень инкапсуляции общего интерфейса SPI

Чтобы упростить SPI Программирование драйверов также снижает степень связи между драйвером протокола и драйвером контроллера. Ядро инкапсулирует некоторые общие операции драйвера контроллера и драйвера протокола в стандартные интерфейсы, а также некоторые общие логические операции обработки. SPI Универсальный ловить изоляционный слой рта. Преимущество этого заключается в том, что драйверу контроллера достаточно реализовать стандартные обратные вызовы порта. API и поместите его на общий уровень порта без необходимости напрямую взаимодействовать с драйвером уровня протокола. Что касается драйвера уровня протокола, его необходимо предоставить только через общий уровень интерфейса ловить. API Вы можете завершить регистрацию драйвера устройства и передать уровень универсального порта ловить из API. Полная передача данных без каких-либо усилий на SPI Подробности реализации драйвера контроллера. Этот слой соответствует драйверу spi.c Файл является собственным файлом ядра.

2.5.2.3 Уровень драйвера контроллера SPI

Чтобы упростить SPI Программирование драйверов также снижает степень связи между драйвером протокола и драйвером контроллера. Ядро инкапсулирует некоторые общие операции драйвера контроллера и драйвера протокола в стандартные интерфейсы, а также некоторые общие логические операции обработки. SPI Универсальный ловить изоляционный слой рта. Преимущество этого заключается в том, что драйверу контроллера достаточно реализовать стандартные обратные вызовы порта. API и поместите его на общий уровень порта без необходимости напрямую взаимодействовать с драйвером уровня протокола. Что касается драйвера уровня протокола, его необходимо предоставить только через общий уровень интерфейса ловить. API Вы можете завершить устройство и драйвер из-за регистрации и пройти универсальный уровень ловить порт из API Полная передача данных без каких-либо усилий на SPI Подробности реализации драйвера контроллера.

Этот слой является предметом нашего внимания, существование которого будет подробно описано в следующей статье.

2.5.3 Аппаратное обеспечение

Этот уровень представляет собой реальное физическое устройство, включая нас. spi Контроллер Также контроллер подключается индивидуально для каждого spi суб-устройство, через spi Всего Проволока может и cpu Выполните взаимодействие с данными.

3 Описание интерфейса

3.1 Интерфейс регистрации устройства

ловитьопределение ртасуществовать include/linux/spi/spi.h, в основном включает spi_register_driver и spi_unregister_driver ловитьрот,в Даватьвне Понятнобыстрыйзарегистрироватьсяиз SPI Драйвер устройства и макрос модуль_spi_driver(), определенный следующим образом:

Язык кода:javascript
копировать
#define module_spi_driver(__spi_driveSPI \
module_driver(__spi_driver, spi_register_driver, \
	spi_unregister_driver)
3.1.1 spi_register_driver()

Прототип функции: int spi_register_driver(struct spi_driver *sdrv)

Описание функции: Зарегистрируйте SPI Драйвер устройства.

параметриллюстрировать:

sdrv,spi_driver типизобратитесь игла, в комплекте SPI Название оборудования, зонд и другая информация об интерфейсе.

Возвращаемое значение: возврат 0 поверхность указывает на успех, возврат других значений указывает на неудачу.

3.1.2 spi_unregister_driver()

Прототип функции: void spi_unregister_driver(struct spi_driver *sdrv)

Описание функции: выйти из системы SPI Драйвер устройства.

параметриллюстрировать:

sdrv,spi_driver типизобратитесь игла, в комплекте SPI Название оборудования, зонд и другая информация об интерфейсе.

Возвращаемое значение: Нет

3.2 Интерфейс передачи данных

SPI Драйвер устройстваиспользовать “struct spi_message” К SPI Общий запрос Проволока на чтение и запись ввод/вывод. один spi_message содержит последовательность операций, каждая операция называется spi_transfer, так удобно SPI Полный серединный серийный драйвер Проволоки выполняет индивидуальную атомарную последовательность. Очередь процесса Проволока ядра реализует асинхронную передачу из функции для той же индивидуальной передачи данных из инициатора. Поскольку асинхронному методу не нужно ждать завершения передачи данных, прежде чем он сможет вернуться, после возврата инициатор может это сделать. немедленно инициировать еще одного человека сообщение, а в это время предыдущее message Еще не закончено. для другого индивидуального другого инициатора, также возможно инициировать его одновременно message Запрос на трансфер.

Рисунок 3-1: Процесс передачи данных Linux SPI

Язык кода:javascript
копировать
struct spi_transfer {
    const void *tx_buf;
    void *rx_buf;
    unsigned len;
    dma_addr_t tx_dma;
    dma_addr_t rx_dma;
    unsigned cs_change:1;
    u8 bits_per_word;
    u16 delay_usecs;
    u32 speed_hz;
    struct list_head transfer_list;
};

struct spi_message {
    struct list_head transfers;
    struct spi_device *spi;
    unsigned is_dma_mapped:1;
    void (*complete)(void *context);
    void *context;
    unsigned actual_length;
    int status;
    struct list_head queue;
    void *state;
};
3.2.1 spi_message_init()

Прототип функции: void spi_message_init(struct spi_message *m)

Описание функции: Инициализация SPI message Структура, в основном очистка и инициализация transfer очередь.

параметриллюстрировать:

m:spi_message типизобратитесь игла.

Возвращаемое значение: Нет

3.2.2 spi_message_add_tail()

Прототип функции: void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)

Описание функции: К SPI message Добавьте один в transfer。

параметриллюстрировать:

t: обратитесь к КДобавить в SPI transfer структура;

m:spi_message типизобратитесь игла.

Возвращаемое значение: Нет

3.2.3 spi_sync()

Прототип функции: int spi_sync(struct spi_device *spi, struct spi_message *message)

Описание функции: запуск и ожидание SPI общий Проволока Законченныйобратитесь к Конечноиз SPI message。

параметриллюстрировать:

spi,обратитесь к Ктекущийиз SPI оборудование;

m,spi_message типизобратитесь к Игла, в ожидании из SPI transfer очередь.

Возвращаемое значение: 0, успех меньше; 0, не удалось.

4 примера использования модуля

4.1 Пример собственного драйвера ядра

файл драйверасуществовать driver/spi/spidev.c, этот драйвер Linux Ядро поставляется с индивидуальным spidev Универсальный драйвер. в вызове spi_register_driver() зарегистрироваться SPI Драйвер, удобный для использования в реализации SPI message Данные чтения и записи.

Язык кода:javascript
копировать
static int __init spidev_init(void)
{ 
    int status;

    /* Claim our 256 reserved device numbers. Then register a class
     * that will key udev/mdev to add/remove /dev nodes. Last, register
     * the driver which manages those device numbers. 
     */
    BUILD_BUG_ON(N_SPI_MINORS > 256);
    status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
    if (status < 0)
        return status;

    spidev_class = class_create(THIS_MODULE, "spidev");
    if (IS_ERR(spidev_class)) {
        unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
        return PTR_ERR(spidev_class);
    }

    status = spi_register_driver(&spidev_spi_driver);
    if (status < 0) {
        class_destroy(spidev_class);
        unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
    }
    return status;
}
module_init(spidev_init);

static void __exit spidev_exit(void)
{
    spi_unregister_driver(&spidev_spi_driver);
    class_destroy(spidev_class);
    unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
}
module_exit(spidev_exit);

Также необходимо соответствующее существование из spi Контроллер dts плюс ниже spi Описание информации о субустройстве, конкретная информация о конфигурации следующая:

Язык кода:javascript
копировать
&spi1 {
    clock-frequency = <100000000>;
    pinctrl-0 = <&spi1_pins_a &spi1_pins_b>;
    pinctrl-1 = <&spi1_pins_c>;
    pinctrl-names = "default", "sleep";
    spi_slave_mode = <0>;
    status = "disabled";
    
    spi_board1@0 {
        device_type = "spi_board1";
        compatible = "rohm,dh2228fv";
        spi-max-frequency = <0x5f5e100>;
        reg = <0x0>;
        spi-rx-bus-width = <0x4>;
        spi-tx-bus-width = <0x4>;
        status = "disabled";
    };
};

для spi Контроллерописыватьсуществоватьэтотвнутри Нетповтори еще разиззаявление,этотвнутрииз spi_board1@0 Это наш виртуальный индивидуальный spi подчиненное устройство,

device_type : поверхность Указывает тип оборудования из;

compatible : Информация о соответствии драйвера;

spi-max-frequency : Максимальная частота ведомого устройства;

reg : Ведомое устройство по адресу регистра;

spi-rx-bus-width: При чтении данных с ведомого устройстваиспользоватьиз data данные Проволокаиндивидуальныйчисло;

spi-tx-bus-width : При записи данных на ведомое устройствоиспользоватьиз data данные Проволокаиндивидуальныйчисло;

status :Состояние ведомого устройства;

существовать menuconfig(Device Drivers->SPI Настройте в поддержке) User mode SPI device driver support параметры.

Рисунок 4-1: Спайдев

После компиляции и записи прошивки файловая система маленького компьютера будет /dev. Найдено в каталоге spidevX.0(X=0~2) оборудование, может spidevX.0 Выполнять операции чтения и записи. Или сипользовать Linux Принесите свой собственный spi инструмент:существовать tina/lichee/linux-5.4/tools в каталоге, Выполните следующую команду:

Язык кода:javascript
копировать
make spi

Тогда он будет существовать в исполняемом файле tina/lichee/linux-5.4/tools/spi/spidev_test.,Скопируйте в корневую файловую систему мини-машины середина.,Для проверки выполните следующую команду:

Язык кода:javascript
копировать
/spidev_test -D /dev/spidevX.0

4.2 Пример драйвера ведомого режима

нуждатьсясуществовать board.dts серединасоответствующийиз SPI Конфигурация узла узла spi_slave_mode = <1>。

4.2.1 Ведомый записывает данные

Если взять в качестве примера устройство spidev1.0, оно отправляет десять данных от 0 до 9:

Язык кода:javascript
копировать
#define DEVICE_NAME "/dev/spidev1.0"
#define HEAD_LEN 5
#define PKT_MAX_LEN 0x40
#define STATUS_LEN 0x01

#define SUNXI_OP_WRITE 0x01
#define SUNXI_OP_READ 0x03

#define STATUS_WRITABLE 0x02
#define STATUS_READABLE 0x04

#define WRITE_DELAY 200
#define READ_DELAY 100000

void dump_data(unsigned char *buf, unsigned int len)
{
    unsigned int i;
    unsigned char tmp[len*2], cnt = 0;

    for (i = 0; i < len; i++) {
        if (i%0x10== 0)
	        cnt += sprintf(tmp + cnt, "0x%08x: ", i);

        cnt += sprintf(tmp + cnt, "%02x ", buf[i]);

        if ( (i%0x10== 0x0f) || (i == (len -1)) ) {
            printf("%s\n", tmp);
            cnt = 0;
        }
    }
}

void batch_rand(char *buf, unsigned int length)
{
    unsigned int i;
    srand(time(0));

    for(i = 0; i < length; i++) {
	    *(buf + i) = rand() % 256;
    }
}

int main(int argc, const char *argv[])
{
    unsigned int length = 0, test_len;
    char wbuf_head[HEAD_LEN] = {SUNXI_OP_WRITE, 0x00, 0x00, 0x00, 0x00};
    char rbuf_head[HEAD_LEN] = {SUNXI_OP_READ, 0x00, 0x00, 0x00, 0x00};
    char wbuf[PKT_MAX_LEN], rbuf[PKT_MAX_LEN], i, time;
    int fd, ret;

	test_len = 10;//send 10 numbers
	if (test_len > PKT_MAX_LEN) {
		printf("invalid argument, numbers must less 64B\n");
		return -1;
	}

    wbuf_head[4] = test_len;
    rbuf_head[4] = test_len;

	for (i = 0; i < test_len; i++)
		wbuf[i] = i;
	printf("wbuf:\n");
	dump_data(wbuf, test_len);

    fd = open(DEVICE_NAME, O_RDWR);
    if (fd <= 0) {
        printf("Fail to to open %s\n", DEVICE_NAME);
        ret = -1;
	    return ret;
    }

    {//write
        if (write(fd, wbuf_head, HEAD_LEN) != HEAD_LEN) {
            printf("W Fail to write head\n");
            ret = -1;
            goto err;
    	} else
	        printf("W write head successful\n");

    	usleep(WRITE_DELAY);

        if (write(fd, wbuf, test_len) != test_len) {
            printf("W Fail to write data\n");
            ret = -1;
            goto err;
        } else
            printf("W write data successful\n");

        usleep(READ_DELAY);
    }

err:
    if (fd > 0)
        close(fd);

    return ret;
}
4.2.2 Ведомое устройство считывает данные

На примере устройства spidev1.0 прочитайте десять данных:

Язык кода:javascript
копировать
#define DEVICE_NAME "/dev/spidev1.0"
#define HEAD_LEN 5
#define PKT_MAX_LEN 0x40
#define STATUS_LEN 0x01

#define SUNXI_OP_WRITE 0x01
#define SUNXI_OP_READ 0x03

#define STATUS_WRITABLE 0x02
#define STATUS_READABLE 0x04

#define WRITE_DELAY 200
#define READ_DELAY 100000

void dump_data(unsigned char *buf, unsigned int len)
{
    unsigned int i;
    unsigned char tmp[len*2], cnt = 0;

    for (i = 0; i < len; i++) {
        if (i%0x10== 0)
	        cnt += sprintf(tmp + cnt, "0x%08x: ", i);

        cnt += sprintf(tmp + cnt, "%02x ", buf[i]);

        if ( (i%0x10== 0x0f) || (i == (len -1)) ) {
            printf("%s\n", tmp);
            cnt = 0;
        }
    }
}

void batch_rand(char *buf, unsigned int length)
{
    unsigned int i;
    srand(time(0));

    for(i = 0; i < length; i++) {
	    *(buf + i) = rand() % 256;
    }
}

int main(int argc, const char *argv[])
{
    unsigned int length = 0, test_len;
    char wbuf_head[HEAD_LEN] = {SUNXI_OP_WRITE, 0x00, 0x00, 0x00, 0x00};
    char rbuf_head[HEAD_LEN] = {SUNXI_OP_READ, 0x00, 0x00, 0x00, 0x00};
    char wbuf[PKT_MAX_LEN], rbuf[PKT_MAX_LEN], i, time;
    int fd, ret;

    test_len = 10;
    if (test_len > PKT_MAX_LEN) {
        printf("inval argument, numbers must less 64B\n");
        return -1;
    }

    wbuf_head[4] = test_len;
    rbuf_head[4] = test_len;

    fd = open(DEVICE_NAME, O_RDWR);
    if (fd <= 0) {
        printf("Fail to to open %s\n", DEVICE_NAME);
        ret = -1;
        return ret;
    }

    {//read
        if (write(fd, rbuf_head, HEAD_LEN) != HEAD_LEN) {
            printf("R Fail to write head\n");
            ret = -1;
            goto err;
        } else
	        printf("R write head successful\n");

        usleep(READ_DELAY);

        if (read(fd, rbuf, test_len) != test_len) {
            printf("R Fail to read data\n");
            ret = -1;
            goto err;
        } else
            printf("R read data successful\n");

            usleep(READ_DELAY);

    }

    printf("rbuf:\n");
    dump_data(rbuf, test_len);

err:
	if (fd > 0)
    	close(fd);

    return ret;
}
4.2.3 Slave использовать & тест
4.2.3.1 Настройка среды
4.2.3.1.1 Аппаратная среда

Этот тестиспользовать две открытые доски для волос, чтобы построить окружающую среду, одну, чтобы сделать хозяина рабом.

Воля MASTER и SLAVE из SPI1 из CS、CLK Соедините их по имени, МАСТЕР. из MOSI забрать РАБ из MOSI,MASTER из MISO ловить SLAVE из MISO,Волядве частиоткрытьобщая основа доски для волос。

4.2.3.1.2 Menuconfig

бить открыть menuconfig из CONFIG_SPI_SUNXI и CONFIG_SPI_SPIDEV, как показано на рисунке ниже.

Рисунок 4-2: конфигурация меню

4.2.3.1.3 DTS

Путь в дереве устройств: device/config/chips/xxx(t507)/configs/xxx(demo2.0)/board.dts, добавьте следующие узлы:

Язык кода:javascript
копировать
spi1: spi@05011000 {
    pinctrl-0 = <&spi1_pins_a &spi1_pins_b>;
    pinctrl-1 = <&spi1_pins_c>;
    spi_slave_mode = <0>;
    status = "okay";
    spi_board1 {
        device_type = "spi_board1";
        compatible = "rohm,dh2228fv";
        spi-max-frequency = <30000000>;
        reg = <0x0>;
        spi-rx-bus-width = <0x1>;
        spi-tx-bus-width = <0x1>;
    };
};

Примечание: spi_slave_mode = <0> для Master Конфигурация spi_slave_mode; = <1>,для Slave Конфигурация

4.2.3.2 тест

Установить отдельно Master и Salve из DTS, скомпилируйте соответствующую прошивку и запишите прошивку.

4.2.3.2.1 Slave

Slave Выполните на терминале следующую команду: битьоткрыть Slave отладочная печать, чтобы вы могли видеть данные чтения и записи.

4.2.3.3 результаты испытаний

Исходные данные Maset и целевые данные бьют данные печати согласованными, то есть проверка поверхности прошла успешно.

Язык кода:javascript
копировать
--------------------------------------------
				  n test
--------------------------------------------
W write head successful
W write data successful
source data:
0x00000000: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a
0x00000010: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a
R write head successful
R read data successful
target data:
0x00000000: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a
0x00000010: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a
slave function [PASS]
4.2.3.4 Инструкции по настройке

Пользователи могут настраивать функции подчиненного устройства для работы в подчиненном режиме. устройство, нужно отправить 5 индивидуальный byte из запроса на операцию, иллюстрируем следующим образом:

Нет. 1 индивидуальный Байт: код операции

Язык кода:javascript
копировать
SUNXI_OP_WRITE 0x01
SUNXI_OP_READ 0x03
//Чтение и запись относятся к мастеру

Нет. 2~4 индивидуальный Байт: адрес (2 это адрес старшего порядка)

Нет. 5 Давать Байт: длина (длина должна быть меньше 64Byte)

4.2.3.4.1 Добавление кода операции

Сейчас существуют только операции чтения и записи.,Саморазвитие пользователя,существоватьdrivers/spi/spi-sunxi.c функция issunxi_spi_slave_handle_head середина добавляет команду, соответствующую функции операции

Язык кода:javascript
копировать
if (head->op_code == SUNXI_OP_WRITE) {
	sunxi_spi_slave_cpu_rx_config(sspi);
} else if (head->op_code == SUNXI_OP_READ) {
	sunxi_spi_slave_cpu_tx_config(sspi);
} else {
    dprintk(DEBUG_INFO, "[spi%d] pkt head opcode err\n", sspi->master->bus_num);
    ret = -1;
    goto err1;
}
4.2.3.4.2 Адрес и кэш

Нет. 2~4 индивидуальный Byte из адреса следует обратиться к Определены данные кэша чтения и записи, макрос размера кэша существуетdrivers/spi/spi-slave-protocol.hсередина определен, пользователь задает его сам, единица измерения Byte

Язык кода:javascript
копировать
#define STORAGE_SIZE 128

4.2.3.4.3 длина

Читать и записывать каждый раз длины данных требуется менее 64 байта, из-за SPI RX/TX из FIFO Размер кэшадля 64Byte, для того, чтобы один конец устройства не забирал данные вовремя во время чтения и записи. buf Переполнение, для одной передачи требуется длина меньше 64 байта, если вы хотите читать и писать больше, чем 64Byte Данные могут передаваться несколькими пакетами, и проблем не будет, если смещение адреса хорошее.

5 FAQ

5.1 Узел отладки

5.1.1 /sys/module/spi_sunxi/parameters/debug

По умолчанию debug для 1,Нетбитьоткрытьотладочная информация。

Язык кода:javascript
копировать
echo 255 > /sys/module/spi_sunxi/parameters/debug

Вы можете битьоткрыть отладочную информацию.

5.1.2 /sys/devices/platform/soc/spi1/info

Этот файл узла может распечатать текущий SPI1 канал какое-то аппаратное предоставление информации о ресурсах.

Язык кода:javascript
копировать
cat /sys/devices/platform/soc/spi1/info
5.1.3 /sys/devices/platform/soc/spi1/status

Этот файл узла может распечатать текущий SPI1 рядиз Некоторая информация о рабочем состоянии,включать Контроллер Каждое значение регистра。

Язык кода:javascript
копировать
cat /sys/devices/platform/soc/spi1/status

5.2 Часто задаваемые вопросы

5.3 Настройка включения в dts не вступает в силу

Проблемное явление:существовать board.dts середина Конфигурация spi из statue состояниедля "окей", но в придачу Linux Ядро найдено Спи-контроллер не включен. Анализ проблемы: Возможно, статус «Конфигурация» неправильный или возникла ошибка «Используйте другие контроллеры, такие как spi0。

Действия по устранению неполадок:

шаг 1: Проблема такого рода обычно возникает из-за того, что ваше устройство зависит от другого устройства в существующем дереве устройств, но это отдельное устройство выходит из строя. probe Успех, в результате чего ваше устройство не сможет зонд. Рекомендуется spi Зависимость dma Устраните неполадки модуля и проверьте dma существовать menuconfig середина Будь тобитьоткрыть;

шаг 2:существовать Найдите .sunxi.dts в каталоге out/. И битьоткрыть:

Язык кода:javascript
копировать
find -name ".sunxi.dts"

Найдите соответствующий из узла в существующем файле и проверьте, успешен ли соответствующий из spi.

шаг 3:существоватьмаленький письменный стол uboot Консоль проходит fdt list spi* Представление команд dts, включен ли SPI Успех (статус = "окей"), если еще отключить, это возможно spi существовать uboot Этап disable Выпало (нормально spi0 Сохраню Дават flash использовать,spi0 встречасуществовать uboot сцена закрыта).

5.4 Неисправность передачи данных SPI-Flash

Признак: данные записи и чтения несовместимы.

шаг 1: Проведите проверку совместимости. к nor flash дляпример,Некоторые материалы несовместимы,Вызовет ошибки чтения и записи. В это время вы можете сначала подтвердить, указаны ли в списке материалы следующего элемента. Если не существовать,Попробуйте изменить материал и сделать это снова.

шаг 2: Отладка драйверов. Масштаб проблем этого типа относительно велик, но их можно отслеживать и устранять с помощью базовых методов отладки. Общая идея состоит в том, чтобы распечатать данные битьоткрыть и посмотреть, перенесётся ли записанное из значения в SPI Общая обработка драйвера Проволока, внешний вид тот же SPI Общий драйвер Проволока только что прочитал данные и проверил, согласованы ли ранее записанные и распечатанные данные, чтобы определить, какое соединение вызвало ошибку чтения и записи. Этот метод можно распространить на другие уровни. Убедитесь, что это уровень файловой системы или уровень. МТД Слой, ИПИ Всегда возникают проблемы с чтением или записью на уровне драйвера Проволоки.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose