ESP32-C3: драйвер SPI Master |
Добавил(а) microsin | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Драйвер SPI Master это код библиотек ESP-IDF для управления периферийными устройствами SPI, которые функционируют как главное устройство на шине. На кристалле ESP32-C3 интегрировано 2 периферийных устройства SPI. SPI0/1 используются внутренне для доступа к подключенной памяти flash (эта память может быть как внутренняя, так внешняя). Оба этих контроллера используют общие выводы корпуса чипа для сигналов шины SPI (VDD_SPI, FLASH_HOLD#, FLASH_WP#, FLASH_CS#, FLASH_SCK, FLASH_SDI, FLASH_SDO, подробнее см. [2, 3]). Существует специальный арбитр, который определяет, какой из блоков SPI0 и SPI1 работает с этими внешними выводами в любой момент времени. В настоящее время драйвер SPI Master не поддерживает шину SPI1. Расшифровка общих терминов, относящихся к драйверу SPI master, приведены в следующей таблице.
[Возможности драйвера SPI master] Драйвер SPI master обслуживает коммуникации между хостами и устройствами. Поддерживаются следующие функциональные возможности: · Многопоточность. Предупреждение: у драйвера SPI master существует концепция подключения нескольких устройств к одной шине (совместное использование одного периферийного устройства ESP32-C3 SPI). Пока к каждому устройству осуществляется доступ только из одной задачи, драйвер считается безопасным для многопоточного окружения (thread safe). Однако если несколько задач пытаются обращаться к одному и тому же устройству SPI, то драйвер становится не потокобезопасным (not thread-safe). В этом случае рекомендуются варианты решения проблемы: · Переписать приложение таким образом, чтобы одновременно к каждому периферийному устройству SPI обращалась только одна задача. Вы можете использовать spi_bus_config_t::isr_cpu_id, чтобы зарегистрировать SPI ISR для одного и того же ядра CPU как задачи, относящиеся к периферийному устройству SPI, чтобы обеспечить безопасность потоков. Для реализации переключения различных устройств, подключенных к разным драйверам, включая SPI Master, SPI Flash, и т. п., применяется блокировка на каждой шине SPI (SPI bus lock). Драйверы могут подключать свои устройства к шине с помощью арбитража путем блокировки. Каждая блокировка шины инициализируется зарегистрированной службой фоновых операций (background service, BG). Все устройства, которые запрашивают транзакции на шине, должны ждать, пока BG не будет успешно запрещена. BG является кэшем для шины SPI1. Блокировка шины запретит кэш перед началом операции с устройством, и разрешит её снова после отого, как устройство осободит блокировку. Ни одному из устройств на SPI1 не разрешается использовать ISR, поскольку бессмысленно для задачи уступать контекст для других задач, когда кэш запрещен. Драйвер SPI Master не поддерживает шину SPI1. Только драйвер SPI Flash может подключиться к этой шине. Для других шин драйвер может зарегистрировать ISR в качестве BG. Если задача (task) устройства запрашивает исключительный доступ к шине, то bus lock заблокирует выполнение задачи, запретит ISR, и разблокирует выполнение задачи. После того, как задача освободит блокировку, блокировка будет пытаться заново разрешить ISR, если в ISR все еще существуют ожидающие транзакции. [Транзакции SPI] Транзакция на шине SPI состоит из 5 фаз, показанных в следующей таблице. Любая из этих фаз может быть пропущена.
Атрибуты транзакции определяются структурой конфигурации шины spi_bus_config_t, структурой конфигурации устройства spi_device_interface_config_t, и структурй конфигурации транзакции spi_transaction_t. Хост SPI может посылать полнодуплексные транзакции, во время которых фазы чтения и записи происходят одновременно. Общая длина транзакции определяется следующими полями структур: spi_device_interface_config_t::command_bits В то же время поле spi_transaction_t::rxlength определяет только длину данных, принятых в буфер. В полнодуплексных транзакциях фазы чтения и записи не одновременные (происходят в одном направлении). Длины фаз чтения и записи определяются соответственно spi_transaction_t::length и spi_transaction_t::rxlength. Фазы command и address опциональны, поскольку не каждое устройство SPI требует предварительной команды и/или адреса. Как отражается в конфигурации устройства: если spi_device_interface_config_t::command_bits и/или spi_device_interface_config_t::address_bits установлены в 0, то не будет фазы command и/или address. Фазы чтения (read) и записи (write) также могут быть опциональными, поскольку не каждая транзакция может требовать одновременных записи и чтения данных. Если поле spi_transaction_t::rx_buffer установлено в NULL, и SPI_TRANS_USE_RXDATA не установлен, то фаза чтения пропускается. Если поле spi_transaction_t::tx_buffer установлено в NULL, и SPI_TRANS_USE_TXDATA не установлен, то фаза записи пропускается. Драйвер поддеживает 2 типа транзакций interrupt и polling. Программист может выбрать для каждого устройства свой тип транзакции. Если ваше устройство требует транзакций обоих типов, см. врезку "Замечания по отправке смешанных транзакций на одно и то же устройство SPI". Interrupt-транзакции. Транзакции с прерываниями заблокируют подпрограмму, которая вызвала эту транзакцию, пока транзакция не завершится. Таким образом, этот тип транзакций позволяет CPU выполнять другие задачи. Задача приложения может поставить в очередь несколько транзакций, и драйвер будет автоматически их обрабатывать по одной в обработчике прерывания (interrupt service routine, ISR). Это позволит задаче переключиться на другие процедуры, пока не завершаться все транзакции. Polling-транзакции. Транзакции с опросом статуса (polling) не используют прерывания. Подпрограмма, вызывавшая транзакцию, опрашивает биты состояния хоста (SPI Host status), пока транзакция не завершится. Все задачи, которые используют interrupt-транзакции могут блокироваться на очереди. В этой точке они должны будут ждать, пока ISR не запустится дважды перед завершением транзакции. Polling-транзакции экономят время, затрачиваемое на обработку очереди и переключение контекста, что уменьшает время транзакции. Недостаток polling-транзакции в том, что CPU занят, пока выполняются транзакции. Подпрограмма spi_device_polling_end() вносит накладные расходы как минимум 1 мкс для разблокировки других задач, когда транзакция завершается. Настоятельно рекомендуется обернуть последовательность polling-транзакций функциями spi_device_acquire_bus() и spi_device_release_bus(), чтобы избежать этих накладных расходов. Для дополнительной информации см. "Bus Acquiring". Transaction Line Mode. Поддерживаемые линейные режимы шины для ESP32-C3 перечислены в следующей таблице. Для упрощения использования этих режимов установите флаги в поле flags структуры spi_transaction_t, как показано в столбце "Transaction Flag". Ширина шины данных указана в столбцах Command, Address и Data. Если вы хотите проверить, установлены ли соответствующие выводы IO или нет, см. поле flags структуры spi_bus_config_t как показано в столбце "Флаг настройки Bus IO".
#define SPI_TRANS_MODE_DIO (1<<0) ///< Передача/прием данных в 2-битном режиме #define SPI_TRANS_MODE_QIO (1<<1) ///< Передача/прием данных в 4-битном режиме #define SPI_TRANS_USE_RXDATA (1<<2) ///< Прием данных в буфер rx_data (поле структуры /// spi_transaction_t) вместо буфера rx_buffer. #define SPI_TRANS_USE_TXDATA (1<<3) ///< Передача из буфера tx_data (поле структуры /// spi_transaction_t) вместо tx_buffer. Когда /// используется этот флаг, не устанавливайте // значение указателя tx_buffer. #define SPI_TRANS_MODE_DIOQIO_ADDR (1<<4) ///< Также адрес передачи в режиме, выбранном /// SPI_MODE_DIO/SPI_MODE_QIO #define SPI_TRANS_VARIABLE_CMD (1<<5) ///< Использовать command_bits в структуре /// spi_transaction_ext_t вместо значения /// по умолчанию в spi_device_interface_config_t. #define SPI_TRANS_VARIABLE_ADDR (1<<6) ///< Использовать address_bits в структуре /// spi_transaction_ext_t вместо значения /// по умолчанию в spi_device_interface_config_t. #define SPI_TRANS_VARIABLE_DUMMY (1<<7) ///< Использовать dummy_bits в структуре /// spi_transaction_ext_t вместо значения /// по умолчанию в spi_device_interface_config_t. #define SPI_TRANS_CS_KEEP_ACTIVE (1<<8) ///< Удерживать CS активным после передачи данных. #define SPI_TRANS_MULTILINE_CMD (1<<9) ///< Сигналы данных, используемые на фазе команды /// те же самые, что и на фазе данных (иначе /// только сигналы данных используются на /// фазе команды). #define SPI_TRANS_MODE_OCT (1<<10) ///< Передача/прием данных в 8-битном режиме. #define SPI_TRANS_MULTILINE_ADDR SPI_TRANS_MODE_DIOQIO_ADDR ///< Сигналы данных, используемые /// на фазе адреса, те же самые, что и на фазе /// данных (иначе только сигналы данных /// используются на фазе адреса). Поле uint32_t flags описывает возможности шины, проверяемые драйвером. В это поле записывается объединенные по OR значения флагов SPICOMMON_BUSFLAG_*. SPICOMMON_BUSFLAG_SLAVE Инициализирует I/O в подчиненном режиме (slave mode). SPICOMMON_BUSFLAG_MASTER Инициализирует I/O в главном режиме (master mode). SPICOMMON_BUSFLAG_IOMUX_PINS Проверка использования iomux выводов. Или показывает, что выводы сконфигурированы через мультиплексор ввода/вывода (IO mux) вместо матрицы портов (GPIO matrix). SPICOMMON_BUSFLAG_GPIO_PINS Принуждает маршрутизировать сигналы через матрицу портов (GPIO matrix). Или показывает, что выводы маршрутизируются через GPIO matrix. SPICOMMON_BUSFLAG_SCLK Проверяет существование вывода SCLK. Или показывает, инициализирован ли сигнал тактов SPI. SPICOMMON_BUSFLAG_MISO Проверяет существование вывода MISO. Или показывает, инициализирован ли сигнал MISO. SPICOMMON_BUSFLAG_MOSI Проверяет существование вывода MOSI. Или показывает, инициализирован ли сигнал MOSI. SPICOMMON_BUSFLAG_DUAL Проверяет, могут ли выводы MOSI и MISO работать на вывод. Или показывает, может ли шина работать в режиме DIO. SPICOMMON_BUSFLAG_WPHD Проверяет существование выводов WP и HD. Или показывает, что выводы WP и HD инициализированы. SPICOMMON_BUSFLAG_QUAD Проверяет существование выводов MOSI/MISO/WP/HD в качестве выходов. Или показывает, может ли шина работать в режиме QIO. SPICOMMON_BUSFLAG_IO4_IO7 Проверяет существование выводов IO4~IO7. Или показывает, что выводы IO4~IO7 инициализированы. SPICOMMON_BUSFLAG_OCTAL Проверяет существование выводов MOSI, MISO, WP, HD, SPIIO4, SPIIO5, SPIIO6, SPIIO7 в качестве выходов. Или показывает, может ли шина работать в 8-битном режиме (octal mode). SPICOMMON_BUSFLAG_NATIVE_PINS Проверяет существование выводов в традиционном режиме. Фазы Command и Address. Во время фаз команды и адреса поля spi_transaction_t::cmd и spi_transaction_t::addr посылаются на шину, в это время ничего с шины не считывается. Длины по умолчанию для фаз command и address устанавливаются в spi_device_interface_config_t путем вызова spi_bus_add_device(). Если флаги SPI_TRANS_VARIABLE_CMD и SPI_TRANS_VARIABLE_ADDR в поле spi_transaction_t::flags не установлены, то драйвер автоматически установит длины этих фаз в значения по умолчанию во время инициализации устройства. Если длины фаз command и address должны быть переменными, то декларируйте структуру spi_transaction_ext_t, установите флаги SPI_TRANS_VARIABLE_CMD и/или SPI_TRANS_VARIABLE_ADDR в поле spi_transaction_ext_t::base и сконфигурируйте остальную часть base как обычно. Затем длина каждой фазы будет равна полям spi_transaction_ext_t::command_bits и spi_transaction_ext_t::address_bits в структуре spi_transaction_ext_t. Если фазы command и address phase должны использовать одно и то же количество сигналов, что и фаза данных, то нужно установить SPI_TRANS_MULTILINE_CMD и/или SPI_TRANS_MULTILINE_ADDR в поле flags структуры spi_transaction_t. См. также выше секцию "Transaction Line Mode". Фазы Write и Read. Обычно данные, которые нужно послать в устройство или получить из устройства будут записаны или прочитаны из блока памяти, определяемого полями spi_transaction_t::tx_buffer и spi_transaction_t::rx_buffer. Если DMA разрешен для передачи, то буферы должны быть: 1. Выделены во внутренней памяти (обычно это IRAM), которая допускает обращения для прямого достуа (DMA-capable internal memory). Если разрешена внешняя PSRAM, то это означает использование pvPortMallocCaps(size, MALLOC_CAP_DMA). 2. Выровненные на байтовый адрес, нацело делящийся на 4 (32-bit aligned), и длина буфера в байтах также должна делиться нацело на 4. Если эти требования не удовлетворяются, то то эффективность транзакций снизится, потому что будут вовлекаться дополнительные операции по выделению временных буферов и копированию в них данных. Если используются больше одной линии данных для передачи, то установите флаг SPI_DEVICE_HALFDUPLEX в поле flags структуры spi_device_interface_config_t. И поле flags в структуре spi_transaction_t должно быть установлено, как это описано выше в секции "Transaction Line Mode". Примечание: не поддерживаются полудуплексные транзакции, на которых одновременно действуют фазы read и write. Для этого используйте полнодуплексный режим. Bus Acquiring. Иногда вам может потребоваться посылать транзакции SPI эксклюзивно и непрерывно, чтобы они занимали минимально возможное время. Для этого можно использовать захват шины (bus acquiring), что помогает приостановить транзакции (обоих типов, как polling, так и interrupt) для других устройств, пока шина не будет освобождена. Чтобы захватить (acquire) и освободить (release) шину, используйте функции spi_device_acquire_bus() и spi_device_release_bus(). [Использование драйвера SPI master] 1. Инициализируйте шину SPI вызовом spi_bus_initialize(). Убедитесь в правильной установке выводов I/O в структуре spi_bus_config_t. Сигналы, которые не нужны, установите в -1. 2. Зарегистрируйте устройство, подключенное к шине, для драйвера путем вызова функции spi_bus_add_device(). Убедитесь, что сконфигурировали любые тайминги, требуемые для устройства, с помощью параметра dev_config. Теперь вы должны получить дескриптор (handle) устройства, который будет использоваться для транзакций с ним. 3. Чтобы взаимодействовать с устройством через драйвер, заполните одну или большее количество структур spi_transaction_t любыми требыемыми для транзакции параметрами. Затем отправьте структуры либо с использованием polling-транзакции, либо interrupt-транзакции: Interrupt. Либо поставьте все транзакции в очередь вызовом функции spi_device_queue_trans() и впоследствии запрашивайте результат их выполнения с помощью функции spi_device_get_trans_result(), либо обрабатывайте все запросы синхронно, путем передачи их в функцию spi_device_transmit(). Polling. Вызовите функцию spi_device_polling_transmit() для отправки транзакций с опросом (polling). Альтернативно, если вы хотите что-нибудь вставить между ними, используйте spi_device_polling_start() и spi_device_polling_end(). 4. (Не обязательно) Для выполнения обратных (back-to-back) транзакций с устройством вызовите функцию spi_device_acquire_bus() перед отправкой транзакций, и spi_device_release_bus() после отправки транзакций. 5. (Не обязательно) Для выгрузки драйвера для определенного устройства вызовите spi_bus_remove_device(), передав в неё в качестве аргумента дескриптор (handle) устройства. 6. (Не обязательно) Чтобы удалить драйвер для шины, проверьте, что нет больше подключенных драйверов, и вызовите spi_bus_free(). Код примера для драйвера SPI master можно найти в директории peripherals/spi_master среди примеров кода ESP-IDF. Транзакции данных, не превышающих 32 бита. Когда размер транзакций данных в битах равен 32 или меньше, выделение специального буфера для них не будет оптимальным решением. Вместо этого данные можно напрямую сохранить в структуру транзакции. Для передаваемых данных этого можно достичт использованием поля spi_transaction_t::tx_data, и установкой на передаче флага SPI_TRANS_USE_TXDATA. Для принимаемых данных используйте spi_transaction_t::rx_data, и установите SPI_TRANS_USE_RXDATA. В обоих случаях не трокайте поля spi_transaction_t::tx_buffer или spi_transaction_t::rx_buffer, потому что будут использоваться те же самые ячейки памяти spi_transaction_t::tx_data и spi_transaction_t::rx_data. Транзакции с целочисленными данными, отличающимися от uint8_t. Хост SPI читает данные из памяти и записывает данные в память байт за байтом. По умолчанию данные посылаются старшим битом (most significant bit, MSB) вперед, поскольку обратный порядок (когда младший бит LSB идет первым) используется в редких случаях. Если должно быть отправлено значение, меньшее чем 8 бит, то биты должны быть записаны в память так, чтобы бит MSB (старший бит) был первым. Например, если надо послать 0b00010, то это значение нужно записать в переменную uint8_t, и длину для чтения надо установить на 5 бит. Устройство все еще примет 8 бит с 3 дополнительными "случайными" битами, так что чтение должно быть выполнено корректно. В дополнение к сказанному ESP32-C3 это чип с архитектурой little-endian [4]. Это означает, что самый младший значащий байт переменных uint16_t и uint32_t сохраняется по самому малому адремсу. Таким образом, если в памяти сохранено uint16_t, то сначала будут отправлены биты [7:0] этого числа, а за ними биты [15:8]. Для случаев, когда данные для отправки должны имеит размер, отличающийся от массивов uint8_t, можно использовать следующие макросы для преобразования данных в формат, который можно напрямую послать драйверу SPI: SPI_SWAP_DATA_TX для передаваемых данных, SPI_SWAP_DATA_RX для принимаемых данных. Чтобы снизить сложность кода, посылайте на устройство транзакции только одного типа (interrupt или polling). Однако все еще есть возможность посылать попеременно interrupt-транзакции и polling-транзакции. Здесь объясняется, как это можно сделать. Polling-транзакции должны инициироваться только после того, как завершены все polling-транзакции и interrupt-транзакции. Поскольку не завершенная polling-транзакция блокирует другие транзакции, не забудьте вызвать spi_device_polling_end() после spi_device_polling_start(), чтобы позволить использовать шину другим транзакциями или устройствам. Помните, что если здесь не нужно переключаться на другие задачи во время вашей polling-транзакции, то вы можете инициировать транзакцию через spi_device_polling_transmit(), чтобы она была завершена автоматически. Выполняющиеся polling-транзакции нарушаются работой ISR для размещения interrupt-транзакций. Перед тем как вызвать spi_device_polling_start() всегда убедитесь, что все interrupt-транзакции, отправленные в ISR, были завершены. Для этого вызывайте spi_device_get_trans_result() пока не будут возвращены все транзакции. Чтобы лучше контролировать последовательность вызова функций, посылайте смешанные транзакции в одно и то же устройство только в пределах одной задачи (task). GPIO Matrix и IO_MUX. Большинство сигналов периферийного устройства чипа напрямую соединены с их выделенными выводами IO_MUX. Однако сигналы также могут быть направлены на любой доступный вывод с помощью обходного пути, с помощью GPIO matrix. Если хотя бы один сигнал периферийного устройства направлен через GPIO matrix, то все его сигналы будут направлены через GPIO matrix. Когда хост SPI установлен на частоту 80 МГц или ниже, то роутинг выводов SPI через GPIO matrix будет вести себя так же, как и с роутингом через IO_MUX. В следущей таблице показан роутинг выводов IO_MUX для шины SPI.
Примечание (*): только первое устройство, подключенное к шине, может использовать вывод CS0. [Замечания по скорости передачи] Существуют 3 фактора, ограничивающие скорость передачи: · Интервал транзакции. Основной параметр, ограничивающий скорость передачи для больших транзакций - тактовая частота. Для нескольких малентких транзакций скорость передачи определяется главным образом интервалами между транзакциями. Длительность транзакции. Длительность транзакции включает настройку регистров периферийного устройства SPI, коирование данных в FIFO или настройку связей DMA, и время транзакции SPI. Interrupt-транзакции позволяют добавить некоторые дополнительную накладные расходы, чтобы приспособить учесть стоимость очередей FreeRTOS и время, необходимое для переключения между задачами и ISR. Для interrupt-транзакций CPU может переключаться на другие задачи, когда транзакция находится в процессе выпоолнения. Это экономит время CPU, но увеличивает время транзакции (см. выше описание в секции "Interrupt-транзакции"). Для polling-транзакций задача не блокируется, однако имеется возможность опроса статуса транзакции, чтобы определить момент её завершения (см. выше описание в секции "Polling-транзакции"). Если DMA разрешен, то настройка связанного списка транзакции требует около 2 мкс на транзакцию. Когда master передает данные, он автоматически считывает данные из связанного списка. Если DMA не разрешен, то CPU сам должен записать и прочитать каждый байт FIFO. Обычно это происходит быстрее, чем 2 мкс, однако длина транзакции ограничена 64 байтами как для записи, так и для чтения. Типовые длительности транзакции для одного байта данных показаны ниже. Interrupt-транзакция с DMA: 28 мкс. Тактовая частота SPI. Источник тактов периферийных устройств GPSPI может быть выбран установкой spi_device_handle_t::cfg::clock_source. Поддерживаемые источники тактов определены в spi_clock_source_t. По умолчанию драйвер установит spi_device_handle_t::cfg::clock_source в значение SPI_CLK_SRC_DEFAULT. Это обычно означает самую высокую частоту среди источников тактирования GPSPI. Реальное значение тактовой частоты при этом зависит от используемой модели чипа. Реальная тактовая частота устройства может быть не точно равна установленному вами значению, она будет пересчитана драйвером для достижения самого ближайшего, аппаратно совместимого значения, и не больше, чем частота источника тактов. Вы можете вызвать spi_device_get_actual_freq(), чтобы узнать реальную частоту тактов SPI, вычисленную драйвером. Теоретический максимум скорости передачи для фазы Write/Read может быть вычислен по следующей таблице:
Вычисление скорости передачи других фаз (command, address, dummy) аналогичное. Промахи кэша. Конфигурация по умолчанию помещает в IRAM только код ISR. Другие связанные с SPI функции, включая сам драйвер и callback, могут быть подвержены промахам кэша, потому что выполнение кода будет приостанавливаться на подкачку инструкций из flash. Для того, чтобы весь драйвер SPI поместить в IRAM, выберите CONFIG_SPI_MASTER_IN_IRAM, и поместите свои callback-функции и код, который они вызывают, также в IRAM, это предотвратит промахи кэша и связанные с этим задержки. Примечание: поскольку реализация драйвера SPI основана на FreeRTOS API, для использования CONFIG_SPI_MASTER_IN_IRAM вы не должны разрешать CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH. Для interrupt-транзакцйи общая цена в микросекундах составит 20+8n/Fspi на одну трназакцию (здесь n это количество байт, Fspi частота тактов SPI в МГц). Соответственно скорость передачи в МГц составит n/(20+8n/Fspi). Пример скорости передачи на тактовой частоте 8 МГц SCLK показан в следующей таблице.
Когда длина данных транзакции невысока, повышается цена интервала транзакции. Если это возможно, попробуйте слить несколько коротких транзакций в одну, чтобы достичь самой высокой скорости передачи. Обратите внимание, что по умолчанию ISR запрещен во время операций с flash. Чтобы сохранить отправку во время операций с flash, разрешите CONFIG_SPI_MASTER_ISR_IN_IRAM и установите ESP_INTR_FLAG_IRAM в поле spi_bus_config_t::intr_flags. В этом случае все транзакции, поставленные в очередь перед началом операций с flash, будут обработаны ISR параллельно. Также имейте в виду, что callback-функция каждого устройства и вызываемые из неё функции должны находиться в IRAM, или ваша callback-функция упадет из-за промаха кэша. Для дополнительной информации см. врезку "Конкурентный доступ к flash на SPI1" из статьи [5]. Пример приложения. Пример кода, использующего полудуплексный режим SPI master для чтения/записи AT93C46D EEPROM (8-битный режим) можно найти в директории peripherals/spi_master/hd_eeprom среди примеров ESP-IDF. Выбор режима SPI (CPHA и CPOL). У библиотеки драйвера SPI Master в системе программирования ESP-IDF есть одна неприятная особенность - невозможность управлять начальным и конечным состоянием сигнала данных - это состояние всегда лог. 1, лог. 0 сделать нельзя. Таким образом, нельзя выполнить полноценную инверсию сигнала данных, управляя настройками CPHA и CPOL (задаются полем mode структуры конфигурации spi_device_interface_config_t). С подобной проблемой пользователи библиотеки уже сталкивались [6]. [Справочник по API] В таблицах ниже приведено общее описание API драйвера SPI Master. Полное описание структур, типов, перечислений и макросов см. в документации [1]. Общие определения. Заголовочный файл components/hal/include/hal/spi_types.h. Компонент драйвера. Описание функций компонента находится в файле components/driver/spi/include/driver/spi_common.h.
SPI Master. Заголовочный файл components/driver/spi/include/driver/spi_master.h.
[Ссылки] 1. ESP32-C3 SPI Master Driver site:espressif.com. |