ESP32外设学习部分--SPI篇

SPI学习

前言

我个人以为开始学习一个新的单片机最好的方法就是先把他各个外设给跑一遍,整体了解一下他的功能,由此记录一下我学习ESP32外设的过程,防止以后忘记。

SPI 配置步骤

SPI总线初始化

    spi_bus_config_t buscfg = {.miso_io_num = PIN_NUM_MISO,.mosi_io_num = PIN_NUM_MOSI,.sclk_io_num = PIN_NUM_CLK,.quadwp_io_num = -1,.quadhd_io_num = -1,.max_transfer_sz = PARALLEL_LINES * 320 * 2 + 8};

点击进入可以查看结构体中的内容如下

typedef struct {union {int mosi_io_num;    ///< GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used.int data0_io_num;   ///< GPIO pin for spi data0 signal in quad/octal mode, or -1 if not used.};union {int miso_io_num;    ///< GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used.int data1_io_num;   ///< GPIO pin for spi data1 signal in quad/octal mode, or -1 if not used.};int sclk_io_num;      ///< GPIO pin for SPI Clock signal, or -1 if not used.union {int quadwp_io_num;  ///< GPIO pin for WP (Write Protect) signal, or -1 if not used.int data2_io_num;   ///< GPIO pin for spi data2 signal in quad/octal mode, or -1 if not used.};union {int quadhd_io_num;  ///< GPIO pin for HD (Hold) signal, or -1 if not used.int data3_io_num;   ///< GPIO pin for spi data3 signal in quad/octal mode, or -1 if not used.};int data4_io_num;     ///< GPIO pin for spi data4 signal in octal mode, or -1 if not used.int data5_io_num;     ///< GPIO pin for spi data5 signal in octal mode, or -1 if not used.int data6_io_num;     ///< GPIO pin for spi data6 signal in octal mode, or -1 if not used.int data7_io_num;     ///< GPIO pin for spi data7 signal in octal mode, or -1 if not used.int max_transfer_sz;  ///< Maximum transfer size, in bytes. Defaults to 4092 if 0 when DMA enabled, or to `SOC_SPI_MAXIMUM_BUFFER_SIZE` if DMA is disabled.uint32_t flags;       ///< Abilities of bus to be checked by the driver. Or-ed value of ``SPICOMMON_BUSFLAG_*`` flags.esp_intr_cpu_affinity_t  isr_cpu_id;    ///< Select cpu core to register SPI ISR.int intr_flags;       /**< Interrupt flag for the bus to set the priority, and IRAM attribute, see*  ``esp_intr_alloc.h``. Note that the EDGE, INTRDISABLED attribute are ignored*  by the driver. Note that if ESP_INTR_FLAG_IRAM is set, ALL the callbacks of*  the driver, and their callee functions, should be put in the IRAM.*/} spi_bus_config_t;

可以看到上面可以配置的内容非常多,可以配置三线四线SPI,但是我们本次主要学习两线的就可以了,用不到的管脚直接配置-1就OK了。

添加SPI设备

    spi_device_interface_config_t devcfg = {#ifdef CONFIG_LCD_OVERCLOCK.clock_speed_hz = 26 * 1000 * 1000,     //Clock out at 26 MHz#else.clock_speed_hz = 10 * 1000 * 1000,     //Clock out at 10 MHz#endif.mode = 0,                              //SPI mode 0.spics_io_num = PIN_NUM_CS,             //CS pin.queue_size = 7,                        //We want to be able to queue 7 transactions at a time.pre_cb = lcd_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line};

然后配置spi_device_interface_config_t 这个结构体,老规矩继续看一下这个结构体中的内容

typedef struct {uint8_t command_bits;           ///< Default amount of bits in command phase (0-16), used when ``SPI_TRANS_VARIABLE_CMD`` is not used, otherwise ignored.uint8_t address_bits;           ///< Default amount of bits in address phase (0-64), used when ``SPI_TRANS_VARIABLE_ADDR`` is not used, otherwise ignored.uint8_t dummy_bits;             ///< Amount of dummy bits to insert between address and data phaseuint8_t mode;                   /**< SPI mode, representing a pair of (CPOL, CPHA) configuration:- 0: (0, 0)- 1: (0, 1)- 2: (1, 0)- 3: (1, 1)*/spi_clock_source_t clock_source;///< Select SPI clock source, `SPI_CLK_SRC_DEFAULT` by default.uint16_t duty_cycle_pos;        ///< Duty cycle of positive clock, in 1/256th increments (128 = 50%/50% duty). Setting this to 0 (=not setting it) is equivalent to setting this to 128.uint16_t cs_ena_pretrans;       ///< Amount of SPI bit-cycles the cs should be activated before the transmission (0-16). This only works on half-duplex transactions.uint8_t cs_ena_posttrans;       ///< Amount of SPI bit-cycles the cs should stay active after the transmission (0-16)int clock_speed_hz;             ///< SPI clock speed in Hz. Derived from `clock_source`.int input_delay_ns;             /**< Maximum data valid time of slave. The time required between SCLK and MISOvalid, including the possible clock delay from slave to master. The driver uses this value to give an extradelay before the MISO is ready on the line. Leave at 0 unless you know you need a delay. For better timingperformance at high frequency (over 8MHz), it's suggest to have the right value.*/int spics_io_num;               ///< CS GPIO pin for this device, or -1 if not useduint32_t flags;                 ///< Bitwise OR of SPI_DEVICE_* flagsint queue_size;                 ///< Transaction queue size. This sets how many transactions can be 'in the air' (queued using spi_device_queue_trans but not yet finished using spi_device_get_trans_result) at the same timetransaction_cb_t pre_cb;   /**< Callback to be called before a transmission is started.**  This callback is called within interrupt*  context should be in IRAM for best*  performance, see "Transferring Speed"*  section in the SPI Master documentation for*  full details. If not, the callback may crash*  during flash operation when the driver is*  initialized with ESP_INTR_FLAG_IRAM.*/transaction_cb_t post_cb;  /**< Callback to be called after a transmission has completed.**  This callback is called within interrupt*  context should be in IRAM for best*  performance, see "Transferring Speed"*  section in the SPI Master documentation for*  full details. If not, the callback may crash*  during flash operation when the driver is*  initialized with ESP_INTR_FLAG_IRAM.*/} spi_device_interface_config_t;

可以看到这个结构体里面的参数也是比较多的,但是我们主要关注的其实就是clock_speed_hz,mode,spics_io_num,这几个参数,这几个也是我们在STM32上最熟悉的;当然如果需要驱动LCD我们可能还需要控制一个DC脚,这时候也可以关注一下pre_cb这个参数,这个是在启用SPI传输前的回调,我们可以用它来控制下个发的是command还是data。

初始化总线

    //Initialize the SPI busret = spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO);

用上面的函数就可以初始化我们配置好的SPI总线。

入参的选择

typedef enum {SPI_DMA_DISABLED = 0,     ///< Do not enable DMA for SPI#if CONFIG_IDF_TARGET_ESP32SPI_DMA_CH1      = 1,     ///< Enable DMA, select DMA Channel 1SPI_DMA_CH2      = 2,     ///< Enable DMA, select DMA Channel 2#endifSPI_DMA_CH_AUTO  = 3,     ///< Enable DMA, channel is automatically selected by driver} spi_common_dma_t;

前两个其实都不用讲,都是我们配置好的。最后一个要看下如果选择了DMA通道,发送的数据就要需要是被存储在DMA可以访问的内存中,不然容易出现问题。
添加设备

    //Attach the LCD to the SPI busret = spi_bus_add_device(SPI2_HOST, &devcfg, &spi);

用上面的函数就可以添加我们的SPI设备了

数据发送

数据发送的时候我们可以使用两个函数来发送我们的数据

spi_device_queue_trans 函数和spi_device_polling_transmit函数的区别

spi_device_queue_transspi_device_polling_transmit 都是ESP32 SPI主机驱动程序中用于发送SPI事务的函数,但它们在传输方式和使用场景上有所不同:

esp_err_t SPI_MASTER_ATTR spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait)esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_transmit(spi_device_handle_t handle, spi_transaction_t* trans_desc)
  1. spi_device_queue_trans

    • 这个函数用于将SPI事务添加到中断传输队列中。
    • 调用这个函数后,当前线程可以继续执行其他任务,而SPI传输将在后台通过中断服务程序异步处理。
    • 它允许多个事务排队,适合于需要连续发送多个SPI事务的场景,或者当需要在传输之间插入其他代码时。
    • 事务完成后,需要使用spi_device_get_trans_result函数来获取事务的结果。
    • 这种方式适用于非阻塞传输,可以提高CPU的利用率。
  2. spi_device_polling_transmit

    • 这个函数用于发送轮询模式下的SPI事务,调用后会等待事务完成并返回结果。
    • 在轮询模式下,CPU会一直等待直到SPI事务完成,期间不能执行其他任务,这可能会导致CPU资源的浪费。
    • 它适合于对实时性要求较高的场合,或者当需要在事务之间精确控制时序时。
    • 如果需要在传输中间插入其他代码,可以使用spi_device_polling_startspi_device_polling_end两个函数来实现。

总结来说,spi_device_queue_trans提供了一种非阻塞的、异步的SPI传输方式,适合于多任务环境和需要高CPU利用率的场景;而spi_device_polling_transmit提供了一种同步的、阻塞的传输方式,适合于对时序要求严格的场合。开发者可以根据具体的应用需求选择合适的函数。

struct spi_transaction_t {uint32_t flags;                 ///< Bitwise OR of SPI_TRANS_* flagsuint16_t cmd;                   /**< Command data, of which the length is set in the ``command_bits`` of spi_device_interface_config_t.**  <b>NOTE: this field, used to be "command" in ESP-IDF 2.1 and before, is re-written to be used in a new way in ESP-IDF 3.0.</b>**  Example: write 0x0123 and command_bits=12 to send command 0x12, 0x3_ (in previous version, you may have to write 0x3_12).*/uint64_t addr;                  /**< Address data, of which the length is set in the ``address_bits`` of spi_device_interface_config_t.**  <b>NOTE: this field, used to be "address" in ESP-IDF 2.1 and before, is re-written to be used in a new way in ESP-IDF3.0.</b>**  Example: write 0x123400 and address_bits=24 to send address of 0x12, 0x34, 0x00 (in previous version, you may have to write 0x12340000).*/size_t length;                  ///< Total data length, in bitssize_t rxlength;                ///< Total data length received, should be not greater than ``length`` in full-duplex mode (0 defaults this to the value of ``length``).void *user;                     ///< User-defined variable. Can be used to store eg transaction ID.union {const void *tx_buffer;      ///< Pointer to transmit buffer, or NULL for no MOSI phaseuint8_t tx_data[4];         ///< If SPI_TRANS_USE_TXDATA is set, data set here is sent directly from this variable.};union {void *rx_buffer;            ///< Pointer to receive buffer, or NULL for no MISO phase. Written by 4 bytes-unit if DMA is used.uint8_t rx_data[4];         ///< If SPI_TRANS_USE_RXDATA is set, data is received directly to this variable};} ;        //the rx data should start from a 32-bit aligned address to get around dma issue.

同样的使用上面两个函数我们都需要传递这个结构体来指示一些东西

flags:SPI 事务标志位,可以使用 SPI_TRANS_* 宏定义进行设置。这些标志位用于控制事务的行为,例如是否使用 DMA、是否在事务结束后保持 CS 信号等

length:本次发送的总数据长度,以位为单位。SPI 最多一次可传输 64 字节(65536 位)数据,如果需要传输更多数据,建议使用 DMA

user:用户定义的变量,可以用于存储事务 ID 等信息

tx_buffer:发送数据缓冲区指针,如果不需要发送数据,则设置为 NULL

rx_buffer:接收数据缓冲区指针,如果不需要接收数据,则设置为 NULL,在 DMA 使用时,每次读取 4 字节

最终代码


void lcd_spi_pre_transfer_callback(spi_transaction_t *t){int dc=(int)t->user;gpio_set_level(PIN_NUM_DC, dc);//  printf("DC get 1\n");}void send_non_blocking(spi_device_handle_t spi,uint8_t *data,uint16_t len){esp_err_t ret;static spi_transaction_t trans;memset(&trans, 0, sizeof(trans));       //Zero out the transactiontrans.length=8*len;trans.flags = 0; //undo SPI_TRANS_USE_TXDATA flagtrans.tx_buffer = data;ret=spi_device_queue_trans(spi, &trans, portMAX_DELAY);}spi_device_handle_t spi;uint8_t spi_send[5] DMA_ATTR = {0x23,0x12,0x37,0x44,0x55};void tx_spi_init(void){esp_err_t ret;spi_bus_config_t buscfg = {.miso_io_num = PIN_NUM_MISO,.mosi_io_num = PIN_NUM_MOSI,.sclk_io_num = PIN_NUM_CLK,.quadwp_io_num = -1,.quadhd_io_num = -1,.max_transfer_sz = 16 * 320 * 2 + 8};spi_device_interface_config_t devcfg = {#ifdef CONFIG_LCD_OVERCLOCK.clock_speed_hz = 26 * 1000 * 1000,     //Clock out at 26 MHz#else.clock_speed_hz = 1 * 1000 * 1000,     //Clock out at 10 MHz#endif.mode = 3,                              //SPI mode 0.spics_io_num = PIN_NUM_CS,             //CS pin.queue_size = 7,                        //We want to be able to queue 7 transactions at a time.pre_cb = lcd_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line};//Initialize the SPI busret = spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);ESP_ERROR_CHECK(ret);//Attach the LCD to the SPI busret = spi_bus_add_device(SPI2_HOST, &devcfg, &spi);ESP_ERROR_CHECK(ret);}void spi_test(void)
{send_non_blocking(spi,spi_send,5);
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/489301.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3+setup使用rtsp视频流实现实时监控,全屏,拍摄,自动拍摄等功能(纯前端)

vue3setup使用rtsp视频流实现实时监控&#xff0c;全屏&#xff0c;拍摄&#xff0c;自动拍摄等功能(纯前端) 概要 本文介绍了如何在Vue应用中通过WebRTC技术获取摄像头的rtsp视频流&#xff0c;同时展示了实时监控&#xff0c;全屏&#xff0c;拍摄&#xff0c;自动拍摄等功…

【源码阅读系列】(五)进程间通信(二)

进程间通信(二) 这一部分主要会介绍Android中特有的几个IPC机制。分别是: Intent、Binder、AIDL、ContentProvider https://juejin.cn/post/7244018340880007226 https://juejin.cn/post/6844903764986462221 Binder https://juejin.cn/post/7244018340880007226 https://j…

机器学习(ML)在发射机识别与资源管理的应用

电子战&#xff08;EW&#xff09;涉及在受干扰的频谱环境中&#xff0c;通过多个无线电频率传感和发射平台进行非合作交互。操作人员需要管理频谱资源、共享关键情报&#xff0c;并有效干扰威胁发射器。现代RF系统的复杂性和威胁发射器的敏捷性&#xff0c;要求系统能够以机器…

高项 - 信息化发展

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 博文更新参考时间点&#xff1a;2024-11-09 高项 - 章节与知识点汇总&#xff1a;点击跳转 文章目录 高项 - 信息化发展信息与信息化信息信息系统信息化 现代化基础设施新型基础设施建设工业互联网车联网 现代化创…

TaskBuilder内设置任擎服务器

TaskBuilder内设置任擎服务器 在使用TaskBuilder进行软件开发时&#xff0c;必须要先连接到任擎服务器&#xff08;后续文档所说的服务器如果不特别注明&#xff0c;皆指任擎服务器&#xff09;才能继续操作&#xff0c;因为使用TaskBuilder开发所需的数据模型、后台服务和前端…

六、nginx负载均衡

负载均衡&#xff1a;将四层或者七层的请求分配到多台后端的服务器上。 从而分担整个业务的负载。提高系统的稳定性&#xff0c;也可以提高高可用&#xff08;备灾&#xff0c;其中一台后端服务器如果发生故障不影响整体业务&#xff09;. 负载均衡的算法 round robin 轮询 r…

代码随想录训练营第十七天| 654.最大二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树

654.最大二叉树 题目链接/文章讲解&#xff1a; 代码随想录 视频讲解&#xff1a;又是构造二叉树&#xff0c;又有很多坑&#xff01;| LeetCode&#xff1a;654.最大二叉树_哔哩哔哩_bilibili 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子…

面向对象进阶:多态

黑马程序员Java个人笔记 BV17F411T7Ao p129~132 目录 多态 多态调用成员的特点 调用成员变量 调用成员方法 理解 多态的优势 解耦合 多态的弊端 解决方案&#xff1a;强制类型转换 instanceof jdk14新特性&#xff0c;将判断和强转放一起 总结 多态 多态调…

系统思考沙盘模拟

今天《收获季节》沙盘模拟的第一天课程圆满结束&#xff0c;不仅从管理技巧的角度深入展开&#xff0c;还让大家体验了决策带来的直接影响。明天&#xff0c;我们将带领学员从系统思考和全局视角来重新审视这些问题&#xff0c;找到更深层的因果关系和系统性改进的思路。期待更…

AI 赋能直播新玩法 —— 无人直播,它到底藏着多少未知?

​ 在数字浪潮汹涌澎湃的时代&#xff0c;直播领域正历经一场前所未有的变革&#xff0c;AI 赋能的无人直播宛如一颗神秘新星&#xff0c;闯入大众视野&#xff0c;撩拨着人们的好奇心&#xff0c;可它究竟潜藏着多少待解谜团&#xff0c;尚无人能完全洞悉。 从技术的幽微深处…

【深度学习】热力图绘制

热力图&#xff08;Heatmap&#xff09;是一种数据可视化方法&#xff0c;通过颜色来表示数据矩阵中的数值大小&#xff0c;以便更直观地展示数据的分布和模式。热力图在许多领域中都有应用&#xff0c;尤其在统计分析、机器学习、数据挖掘等领域&#xff0c;能够帮助我们快速识…

ssm-springmvc-学习笔记

简介 简单的来说&#xff0c;就是一个在表述层负责和前端数据进行交互的框架 帮我们简化了许多从前端获取数据的步骤 springmvc基本流程 用户在原本的没有框架的时候请求会直接调用到controller这个类&#xff0c;但是其步骤非常繁琐 所以我们就使用springmvc进行简化 当用…

Axure原型设计:打造科技感可视化大屏元件

在数字化时代&#xff0c;数据可视化大屏已成为企业展示数据、监控业务状态的重要工具。一个设计精良的大屏不仅要有丰富的信息展示&#xff0c;更需具备强烈的科技感&#xff0c;以吸引观众的注意力并提升数据解读的效率。Axure&#xff0c;作为一款功能强大的原型设计工具&am…

supervision - 好用的计算机视觉 AI 工具库

Supervision库是一款出色的Python计算机视觉低代码工具&#xff0c;其设计初衷在于为用户提供一个便捷且高效的接口&#xff0c;用以处理数据集以及直观地展示检测结果。简化了对象检测、分类、标注、跟踪等计算机视觉的开发流程。开发者仅需加载数据集和模型&#xff0c;就能轻…

探索 Cesium 的未来:3D Tiles Next 标准解析

探索 Cesium 的未来&#xff1a;3D Tiles Next 标准解析 随着地理信息系统&#xff08;GIS&#xff09;和 3D 空间数据的快速发展&#xff0c;Cesium 作为领先的开源 3D 地球可视化平台&#xff0c;已成为展示大规模三维数据和进行实时渲染的强大工具。近年来&#xff0c;随着…

Launcher启动流程

Launcher启动流程分2个阶段&#xff1a; AMS systemReady() 会启动一个临时Activity&#xff1a;com.android.settings.FallbackHome&#xff0c;如下流程等到用户解锁成功后&#xff0c;FallbackHome轮询到有可用的RealHome包&#xff0c;会销毁掉自己&#xff0c;AMS发现没有…

链式栈的实现及其应用

目录 一、链式栈结构模型 二、链式栈的实现 2.1创建 2.2压栈 2.3出栈 2.4判断栈是否为空 2.5查看栈顶 2.6释放栈 三、应用 链式栈实际上就是基于链表&#xff0c;压栈和弹栈可分别看作头插和头删&#xff0c;链表尾部就是栈底&#xff0c;头指针就是栈顶指针 一、链式…

视频监控汇聚平台方案设计:Liveweb视频智能监管系统方案技术特点与应用

随着科技的发展&#xff0c;视频监控平台在各个领域的应用越来越广泛。然而&#xff0c;当前的视频监控平台仍存在一些问题&#xff0c;如视频质量不高、监控范围有限、智能化程度不够等。这些问题不仅影响了监控效果&#xff0c;也制约了视频监控平台的发展。 为了解决这些问…

Ubuntu 20.04LTS 系统离线安装5.7.44mysql数据库

Ubuntu 20.04LTS 系统离线安装5.7.44mysql数据库 环境下载 MySQL 5.7.44 包安装标题检查服务是否启动成功遇到的问题登陆&修改密码&远程访问 环境 操作系统&#xff1a;Ubuntu 20.04.4 LTS 数据库&#xff1a;MySQL 5.7.34 内核版本&#xff1a;x86_64&#xff08;amd…