说在最前:下面把主要代码都已经附上,如果有人想要完整的工程文件(包括ESP-IDF和KEIL5和STM32CUBEMX的工程)请移步下载链接:

完整资源下载

如果你自己写的,有bug无法解决,请参考,下面的文章:

含泪Debug:STM32与ESP32 SPI通信避坑

我先极其粗浅的介绍一下SPI通信:

四线SPI通信:SPI_SCLK用于传递时钟信号,SPI_CS用于传递片选信号(低有效),MOSI为主机的输出、从机的输入,MISO为主机的输入、从机的输出。

四线SPI的数据交换:CS片选信号,用于使能从设备接收数据;主从设备在SPI_SCLK时钟信号的驱动下,如下图的方式交换数据。

实现的时候,STM32与ESP32是轮询式的:

HAL_SPI_Transmit(&hspi5,ptr,128,0xffff);
ret=spi_slave_transmit(RCV_HOST, &t, portMAX_DELAY);

所以,为了保证二者能够转备好在同一时刻进行数据的交换,就需要握手协议。

(以半双工,STM32做master为例)如何握手呢?ESP32-IDF例程中的代码如下:

//Called after a transaction is queued and ready for pickup by master. We use this to set the handshake line high.
void my_post_setup_cb(spi_slave_transaction_t *trans) {WRITE_PERI_REG(GPIO_OUT_W1TS_REG, (1<<GPIO_HANDSHAKE));
}//Called after transaction is sent/received. We use this to set the handshake line low.
void my_post_trans_cb(spi_slave_transaction_t *trans) {WRITE_PERI_REG(GPIO_OUT_W1TC_REG, (1<<GPIO_HANDSHAKE));
}

也就是说,ESP32每次请求数据前,先把HANDSHAKE引脚拉高,请求后把HANDSHAKE拉低。如果STM32想给ESP32发送数据的话,就要检测ESP32是否准备好,也就是检测HANDSHAKE的电平值,如果为高电平才可以发送。

话不多说直接上代码:

ESP-IDF版本为v4.0.1(如果不能编译可能你们的版本太高了),在例程的基础上略微改动

/* SPI Slave example, receiver (uses SPI Slave driver to communicate with sender)This example code is in the Public Domain (or CC0 licensed, at your option.)Unless required by applicable law or agreed to in writing, thissoftware is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES ORCONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "lwip/igmp.h"#include "esp_wifi.h"
#include "esp_system.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "soc/rtc_periph.h"
#include "driver/spi_slave.h"
#include "esp_log.h"
#include "esp_spi_flash.h"
#include "driver/gpio.h"/*
SPI receiver (slave) example.This example is supposed to work together with the SPI sender. It uses the standard SPI pins (MISO, MOSI, SCLK, CS) to
transmit data over in a full-duplex fashion, that is, while the master puts data on the MOSI pin, the slave puts its own
data on the MISO pin.This example uses one extra pin: GPIO_HANDSHAKE is used as a handshake pin. After a transmission has been set up and we're
ready to send/receive data, this code uses a callback to set the handshake pin high. The sender will detect this and start
sending a transaction. As soon as the transaction is done, the line gets set low again.
*//*
Pins in use. The SPI Master can use the GPIO mux, so feel free to change these if needed.
*/
#define GPIO_HANDSHAKE 2
#define GPIO_MOSI 5
#define GPIO_MISO 17
#define GPIO_SCLK 16
#define GPIO_CS 4#ifdef CONFIG_IDF_TARGET_ESP32
#define RCV_HOST    HSPI_HOST
#define DMA_CHAN    2#elif defined CONFIG_IDF_TARGET_ESP32S2
#define RCV_HOST    SPI2_HOST
#define DMA_CHAN    RCV_HOST#endif//Called after a transaction is queued and ready for pickup by master. We use this to set the handshake line high.
void my_post_setup_cb(spi_slave_transaction_t *trans) {WRITE_PERI_REG(GPIO_OUT_W1TS_REG, (1<<GPIO_HANDSHAKE));
}//Called after transaction is sent/received. We use this to set the handshake line low.
void my_post_trans_cb(spi_slave_transaction_t *trans) {WRITE_PERI_REG(GPIO_OUT_W1TC_REG, (1<<GPIO_HANDSHAKE));
}//Main application
void app_main(void)
{int n=0;esp_err_t ret;//Configuration for the SPI busspi_bus_config_t buscfg={.mosi_io_num=GPIO_MOSI,.miso_io_num=GPIO_MISO,.sclk_io_num=GPIO_SCLK,.quadwp_io_num = -1,.quadhd_io_num = -1,};//Configuration for the SPI slave interfacespi_slave_interface_config_t slvcfg={.mode=0,.spics_io_num=GPIO_CS,.queue_size=3,.flags=0,.post_setup_cb=my_post_setup_cb,.post_trans_cb=my_post_trans_cb};//Configuration for the handshake linegpio_config_t io_conf={.intr_type=GPIO_INTR_DISABLE,.mode=GPIO_MODE_OUTPUT,.pin_bit_mask=(1<<GPIO_HANDSHAKE)};//Configure handshake line as outputgpio_config(&io_conf);//Enable pull-ups on SPI lines so we don't detect rogue pulses when no master is connected.gpio_set_pull_mode(GPIO_MOSI, GPIO_PULLUP_ONLY);gpio_set_pull_mode(GPIO_SCLK, GPIO_PULLUP_ONLY);gpio_set_pull_mode(GPIO_CS, GPIO_PULLUP_ONLY);//Initialize SPI slave interfaceret=spi_slave_initialize(RCV_HOST, &buscfg, &slvcfg, DMA_CHAN);assert(ret==ESP_OK);WORD_ALIGNED_ATTR char sendbuf[129]="";//WORD_ALIGNED_ATTR char recvbuf[129]="";//memset(recvbuf, 0, 33);//spi_slave_transaction_t t;memset(&t, 0, sizeof(t));//memset(recvbuf, 0xA5, 128);////sprintf(sendbuf, "This is the receiver, sending data for transmission number %04d.", n);//Set up a transaction of 128 bytes to send/receive//t.length=128*8;//t.tx_buffer=sendbuf;//t.rx_buffer=recvbuf;while(1) {//Clear receive buffer, set send buffer to something sanememset(recvbuf, 0xA5, 129);////sprintf(sendbuf, "This is the receiver, sending data for transmission number %04d.", n);//Set up a transaction of 128 bytes to send/receivet.length=128*8;t.tx_buffer=sendbuf;t.rx_buffer=recvbuf;/* This call enables the SPI slave interface to send/receive to the sendbuf and recvbuf. The transaction isinitialized by the SPI master, however, so it will not actually happen until the master starts a hardware transactionby pulling CS low and pulsing the clock etc. In this specific example, we use the handshake line, pulled up by the.post_setup_cb callback that is called as soon as a transaction is ready, to let the master know it is free to transferdata.*/ret=spi_slave_transmit(RCV_HOST, &t, portMAX_DELAY);//spi_slave_transmit does not return until the master has done a transmission, so by here we have sent our data and//received data from the master. Print it.printf("receive:%s\r\n", recvbuf);n++;}}

STM32的版本为STM32F446,只发配置的主要部分:spi.c

/********************************************************************************* File Name          : SPI.c* Description        : This file provides code for the configuration*                      of the SPI instances.******************************************************************************* @attention** <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.* All rights reserved.</center></h2>** This software component is licensed by ST under BSD 3-Clause license,* the "License"; You may not use this file except in compliance with the* License. You may obtain a copy of the License at:*                        opensource.org/licenses/BSD-3-Clause********************************************************************************//* Includes ------------------------------------------------------------------*/
#include "spi.h"/* USER CODE BEGIN 0 *//* USER CODE END 0 */SPI_HandleTypeDef hspi2;/* SPI2 init function */
void MX_SPI2_Init(void)
{hspi2.Instance = SPI2;hspi2.Init.Mode = SPI_MODE_MASTER;hspi2.Init.Direction = SPI_DIRECTION_2LINES;hspi2.Init.DataSize = SPI_DATASIZE_8BIT;hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;hspi2.Init.NSS = SPI_NSS_SOFT;hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;hspi2.Init.TIMode = SPI_TIMODE_DISABLE;hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;hspi2.Init.CRCPolynomial = 10;if (HAL_SPI_Init(&hspi2) != HAL_OK){Error_Handler();}}void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(spiHandle->Instance==SPI2){/* USER CODE BEGIN SPI2_MspInit 0 *//* USER CODE END SPI2_MspInit 0 *//* SPI2 clock enable */__HAL_RCC_SPI2_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/**SPI2 GPIO Configuration    PB13     ------> SPI2_SCKPB15     ------> SPI2_MOSI */GPIO_InitStruct.Pin = SPI_SCLK_Pin|SPI_MOSI_Pin;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* USER CODE BEGIN SPI2_MspInit 1 *//* USER CODE END SPI2_MspInit 1 */}
}void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{if(spiHandle->Instance==SPI2){/* USER CODE BEGIN SPI2_MspDeInit 0 *//* USER CODE END SPI2_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_SPI2_CLK_DISABLE();/**SPI2 GPIO Configuration    PB13     ------> SPI2_SCKPB15     ------> SPI2_MOSI */HAL_GPIO_DeInit(GPIOB, SPI_SCLK_Pin|SPI_MOSI_Pin);/* USER CODE BEGIN SPI2_MspDeInit 1 *//* USER CODE END SPI2_MspDeInit 1 */}
} /* USER CODE BEGIN 1 *//* USER CODE END 1 *//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
  /* USER CODE BEGIN WHILE */__HAL_UART_ENABLE(&huart3);hspi2.Instance->CR1 |= (1<<6);  // 打开SPEGPIOB->ODR|=1UL<<0;int count=0;unsigned char wr_buff[128]={0};while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */GPIOB->ODR^=1UL<<0;snprintf((char *)wr_buff,128,"THIS_IS_STM32_SENDING_NUM:%d\n",count);spi_send_128(wr_buff);
count++;}/* USER CODE END 3 */

ESP32与STM32的SPI半双工通信与握手协议讲解(附代码)相关推荐

  1. 【嵌入式】STM32实现SPI双机通信的一些细节(2)片选总结

    [嵌入式]STM32实现SPI双机通信的一些细节(2)SPI软硬件片选总结 SPI片选总结 坑爹的手册示意图 理想中的硬件片选 主机软件片选就对了 从机硬件片选 从机软件片选 代码 主机软件片选SPI ...

  2. 两块STM32之间 SPI DMA通信

    @[两块STM32之间 SPI DMA通信] 这里讲的是两块STM32F407板子的互相通讯,折腾了3天,终于比较清楚了,特此记录. 两块板子互相通讯,除了SPI的接线,肯定还有其他信号线,必须注意这 ...

  3. STM32双机SPI全双工通信

    (基于STM32F407的SPI全双工通信时序不同步问题!!) 首先吐槽一波,调一个星期的SPI,始终没有很好的效果. 网上有很多SPI主从通信的例子,但是两片STM32单片机进行通信,基本很少,就算 ...

  4. stm32 硬件spi半双工三线的一些研究心得

    a7105可以使用四线spi,或者3线spi, 但是之前都是使用3线的软件模拟的三线spi的,所以不想改其它代码了,就想可以提高一个spi的读写速度,原来软件方式的读写速度,在48Mhz的03x下面, ...

  5. STM32的SPI模式读写FLASH芯片全面讲解

    SPI协议简介 SPI协议,即串行外围设备接口,是一种告诉全双工的通信总线,它被广泛地使用在ADC,LCD等设备与MCU间通信的场合. SPI信号线 SPI包含4条总线,分别为SS,SCK,MOSI, ...

  6. linux通过spi和stm32通信,双STM32通过SPI进行通信

    楼主谢谢(一直想用双stm32通信然而一直不太清楚) 谢谢分享谢谢分享谢谢分享 谢谢分享谢谢分享                       谢谢分享 谢谢分享谢谢分享                ...

  7. STM32学习笔记:读写内部Flash(介绍+附代码)

    一.介绍 首先我们需要了解一个内存映射: stm32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实际的flash大小,不同的芯片flash大小不同. RAM起 ...

  8. 9、STM32的PWM的原理与使用(内附代码)

    1.PWM是什么? 是脉冲宽度调制,简称脉宽调制.利用微处理器数字输出对模拟电路进行控制的一种有效的技术,就是对脉冲宽度的控制. 这里说的脉冲,就是我们产生的方波.方波就是N个这样的周期连续的产生. ...

  9. 基于STM32的SPI基本介绍

    STM32---SPI(DMA)通信的总结(库函数操作) 本文主要由7项内容介绍SPI并会在最后附上测试源码供参考: 1.     SPI的通信协议 2.     SPI通信初始化(以STM32为从机 ...

最新文章

  1. 微生物组数据库(http://egcloud.cib.cn)正式上线
  2. 精致3D图片切换效果,最适合企业产品展示
  3. sap系统搭建教程_Nios ii最小系统搭建教程
  4. 【django轻量级框架】View与Model交互(模块的交互关系)
  5. http中post和get方法区别
  6. java中CyclicBarrier的使用
  7. RHCSA 系列(十四): 在 RHEL 7 中设置基于 LDAP 的认证
  8. 分享一篇关于饿了么的需求文档
  9. 如何理解SVM | 支持向量机之我见
  10. excel导入到mysql
  11. 笔记下UltraEdit的一些常用使用技巧
  12. 我从佛学里悟到的自由
  13. 懒加载和预加载的区别_类的动态创建(ro,rw)amp; 懒加载类和非懒加载类底层加载的区别 amp; 类和分类的搭配分析...
  14. 最新MT2503_GPS调试工具资料下载
  15. JDK、Neo4j下载、安装、运行及问题
  16. sis最新ip地址2020入口一_2020云南高考成绩公布时间最新 云南高考查成绩方式入口大全...
  17. PCB多层板设计技巧
  18. QT教程:QT的基本了解
  19. python xlsx转xls_Python 批量将xls文件转换为xlsx
  20. 你的工作表现是否成熟,用这4条检验自己

热门文章

  1. 压力测试工具Apache JMeter:4:压力测试报告说明与使用技巧
  2. Navicat 15中文安装教程
  3. 基于Android的便签设计(一)
  4. matlab e52pt,帮我看看Matlab怎么改这个错误?
  5. 超融合之VMware vSAN企业级超融合解决方案
  6. 从零开始的机器人操作系统(ROS)(0)机器人漫谈以及双系统安装
  7. Apache Doris在蜀海供应链的实践
  8. 计算机二级office公式汇总,计算机二级Office2010Eexcel公式汇总
  9. windows和android双系统平板,安卓+windows双系统平板的“得与失”
  10. cad画不规则实体_cad画不规则曲线的方法步骤图