STM32与esp32通过SPI通讯

一,实验背景

        stm32做主机,esp32做从机

        通过网络助手发送tcp数据给esp32,esp32拉低握手线,stm32检测到握手线后发送spi时钟,

接收esp32发送过来的spi数据,并进行回发,esp32收到spi数据后转发到网络上

二,实验结果

        

三,stm32主机代码

        使用野火的w25q64例程进行简单修改

 /**
  ******************************************************************************
  * @file    main.c
  * @author  fire
  * @version V1.0
  * @date    2013-xx-xx
  * @brief   华邦 8M串行flash测试,并将测试信息通过串口1在电脑的超级终端中打印出来
  ******************************************************************************
  * @attention
  *
  * 实验平台:野火 F103-霸道 STM32 开发板 
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  ******************************************************************************
  */ 
#include "stm32f10x.h"
#include "./usart/bsp_usart.h"
#include "./led/bsp_led.h"
#include "./flash/bsp_spi_flash.h"
#include "spi.h"
#include "string.h"
#include <stdio.h>
int main()
{
	u8 sendbuf[128]={0},tm[128];
	u8 recvbuf[128]={0};

	int i;
	unsigned int delay=10000000;	
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_Config();
	

	SPI_FLASH_Init();

 	RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOA , ENABLE );

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	
	printf("master ready\n");
	  /*选择 FLASH: CS 低 */
	  SPI_FLASH_CS_LOW();
	SPI_FLASH_SendByte(0x5a);

		sendbuf[0]=0x5a;
		sendbuf[1]=0x55;
		sendbuf[2]=0x0c;
		sendbuf[3]=0x00;
		sendbuf[4]=0x01;
		sendbuf[5]=0x01;
		sendbuf[6]=0x18;
		sendbuf[7]=0x01;
		sendbuf[8]=0x01;
		sendbuf[9]=0x08;
		sendbuf[10]=0x00;
		sendbuf[11]=0x00;
		sendbuf[12]=0x03;
		sendbuf[13]=0x02;
	while(1)
	{
		
	   if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2))
		{
			// GPIO 2为高电平
			printf("GPIO_Pin_2 get high\n");
		}
		else
		{
			// GPIO 2为低电平
					//sprintf(tm, "Hello, I am a master!");
		//spi_Read_Buf(0x61,tm,16);//接收esp32传输回来的内容		printf("%s\n",tm);
		
			for(i=0;i<14;i++)
			{
				recvbuf[i]=SPI_FLASH_SendByte(sendbuf[i]);
			}
			printf("GPIO_Pin_2 get low\n");
			sprintf(tm,"0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n",
						recvbuf[0],recvbuf[1],recvbuf[2],recvbuf[3],recvbuf[4],recvbuf[5],
						recvbuf[6],recvbuf[7],recvbuf[8],recvbuf[9],recvbuf[10],recvbuf[12]);
			printf("recvbuf=%s",tm);

		}
		
		//pritnf(tm,"hello i am master");

		

		/*
		while(delay)
		{
			delay--;
		}
		delay=10000000;
		*/
	}
}

四,esp32从机配置

        



//Main application
void Bsp_Spi_Slave_Init(void)
{
    esp_err_t ret;

    //Configuration for the SPI bus
    spi_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 interface
    spi_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 line
    gpio_config_t io_conf=
    {
        .intr_type=GPIO_INTR_DISABLE,
        .mode=GPIO_MODE_OUTPUT,
        .pin_bit_mask=(1<<GPIO_HANDSHAKE)
    };

    //Configure handshake line as output
    gpio_config(&io_conf);
    GPIO_OUT_SET_REG |=1 << GPIO_HANDSHAKE_BIT;
    //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 interface
    ret=spi_slave_initialize(HSPI_HOST, &buscfg, &slvcfg, 1);
    assert(ret==ESP_OK);



}

五,主机使用更高级STM32H7系列出现问题,从机必须使用回调函数才能通讯正常
        在回调函数修改握手线比自己添加快

/* 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, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS 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"

#include "hal/gpio_hal.h"
#include "soc/gpio_reg.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.
*/
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
#define GPIO_HANDSHAKE 2
#define GPIO_MOSI 					23//12
#define GPIO_MISO 					19//13
#define GPIO_SCLK 					18//15
#define GPIO_CS 					5//14

#elif CONFIG_IDF_TARGET_ESP32C3
#define GPIO_HANDSHAKE 3
#define GPIO_MOSI 7
#define GPIO_MISO 2
#define GPIO_SCLK 6
#define GPIO_CS 10

#elif CONFIG_IDF_TARGET_ESP32S3
#define GPIO_HANDSHAKE 2
#define GPIO_MOSI 11
#define GPIO_MISO 13
#define GPIO_SCLK 12
#define GPIO_CS 10

#endif //CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2


#ifdef CONFIG_IDF_TARGET_ESP32
#define RCV_HOST    HSPI_HOST

#else
#define RCV_HOST    SPI2_HOST

#endif

#define GPIO_OUT_SET_REG   (*((volatile uint32_t*)GPIO_OUT_W1TS_REG)) // GPIO Output Register
// 瀵勫瓨鍣ㄥ畾涔?
#define GPIO_OUT_CLEAR_REG  (*((volatile uint32_t*)GPIO_OUT_W1TC_REG)) // GPIO Output Register

#define GPIO_HANDSHAKE_BIT 2 // GPIO_HANDSHAKE 寮曡剼鐨勪綅鍋忕Щ




//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)
{
    // 灏?GPIO_HANDSHAKE 寮曡剼璁剧疆涓洪珮鐢靛钩
    //uint32_t mask = 1 << GPIO_HANDSHAKE_BIT;
    //GPIO_OUT_W1TS_REG = mask;

    //gpio_set_level(GPIO_HANDSHAKE, 1);
    GPIO_OUT_CLEAR_REG|=1 << GPIO_HANDSHAKE_BIT;
    //gpio_hal_set_level(gpio_context.gpio_hal, GPIO_HANDSHAKE, 1);
}

//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)
{
    //gpio_set_level(GPIO_HANDSHAKE, 0);
    //gpio_hal_set_level(gpio_context.gpio_hal, GPIO_HANDSHAKE, 0);
    // 灏?GPIO_HANDSHAKE 寮曡剼璁剧疆涓轰綆鐢靛钩
    //uint32_t mask = 1 << GPIO_HANDSHAKE_BIT;
    //GPIO_OUT_W1TC_REG = mask;
    GPIO_OUT_CLEAR_REG|=1 << GPIO_HANDSHAKE_BIT;

}


unsigned short ModBusCRC16(unsigned char *data, unsigned int len)
{
    unsigned short i, j, tmp, CRC16;

    CRC16 = 0xFFFF;             //CRC瀵勫瓨鍣ㄥ垵濮嬪€?
    for (i = 0; i < len; i++)
    {
        CRC16 ^= data[i];
        for (j = 0; j < 8; j++)
        {
            tmp = (unsigned int)(CRC16 & 0x0001);
            CRC16 >>= 1;
            if (tmp == 1)
            {
                CRC16 ^= 0xA001;    //寮傛垨澶氶」寮?
            }
        }
    }
/*鏍规嵁闇€瑕佸缁撴灉杩涜澶勭悊*/
//    data[i++] = (unsigned char) (CRC16 & 0x00FF);
//    data[i++] = (unsigned char) ((CRC16 & 0xFF00)>>8);
    return CRC16;
}

//Main application
void app_main(void)
{
    int n=0;
    esp_err_t ret;

    //Configuration for the SPI bus
    spi_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 interface
    spi_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 line
    gpio_config_t io_conf=
    {
        .intr_type=GPIO_INTR_DISABLE,
        .mode=GPIO_MODE_OUTPUT,
        .pin_bit_mask=(1<<GPIO_HANDSHAKE)
    };

    //Configure handshake line as output
    gpio_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 interface
    ret=spi_slave_initialize(HSPI_HOST, &buscfg, &slvcfg, 1);
    assert(ret==ESP_OK);

    //WORD_ALIGNED_ATTR char recvbuf[2048]="";
#define RXBUFFER_SIZE (4092 * 1)
    WORD_ALIGNED_ATTR char *recvbuf = heap_caps_malloc(RXBUFFER_SIZE,MALLOC_CAP_DMA);
    WORD_ALIGNED_ATTR char *sendbuf = heap_caps_malloc(RXBUFFER_SIZE,MALLOC_CAP_DMA);
    memset(recvbuf, 0, 33);
    spi_slave_transaction_t t;
    memset(&t, 0, sizeof(t));
    static unsigned int SendDataCnt = 0;
    static unsigned int Time1 = 0;
    static unsigned int Time2 = 0;
    memset(recvbuf, 0, RXBUFFER_SIZE);
    memset(sendbuf, 0x10, RXBUFFER_SIZE);
			sendbuf[0]=0x5a;
			sendbuf[1]=0x55;
			sendbuf[2]=0x0c;
			sendbuf[3]=0x00;
			sendbuf[4]=0x01;
			sendbuf[5]=0x01;
			sendbuf[6]=0x18;
			sendbuf[7]=0x01;
			sendbuf[8]=0x01;
			sendbuf[9]=0x08;
			sendbuf[10]=0x00;
			sendbuf[11]=0x00;
			sendbuf[12]=0x03;
			sendbuf[13]=0x02;


	
    t.length=(14)*8;
    t.tx_buffer=sendbuf;
    t.rx_buffer=recvbuf;
    while(1)
    {
        //Clear receive buffer, set send buffer to something sane

        // sprintf(sendbuf, "This is the receiver, sending data for transmission number %04d.", n);

        //Set up a transaction of 128 bytes to send/receive

        /* This call enables the SPI slave interface to send/receive to the sendbuf and recvbuf. The transaction is
        initialized by the SPI master, however, so it will not actually happen until the master starts a hardware transaction
        by 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 transfer
        data.
        */
        //GPIO_OUT_CLEAR_REG|=1 << GPIO_HANDSHAKE_BIT;
        ret=spi_slave_transmit(HSPI_HOST, &t, portMAX_DELAY);
        if(ret == ESP_OK)
        {
			
            //ESP_LOGI("ESP32","spi_slave_transmit FIRST OK ");
			unsigned short packageLen=recvbuf[2]|recvbuf[3]<<8;
            ESP_LOGI("ESP32","packageLen= %d\r\n",packageLen);
            ESP_LOG_BUFFER_HEX("1 recvbuf:",recvbuf,14);
			//鎺ユ敹鍓╀綑鐨勬暟鎹?
			/*
			t.length=(packageLen-2)*8;
            ret=spi_slave_transmit(HSPI_HOST, &t, portMAX_DELAY);
            if(ret == ESP_OK)
            {
                ESP_LOGI("ESP32","spi_slave_transmit SECONED OK ");

            }
            */
            
            memcpy(sendbuf,recvbuf,packageLen+2); 


            ret=spi_slave_transmit(HSPI_HOST, &t, portMAX_DELAY);
            if(ret == ESP_OK)
            {
                ESP_LOGI("ESP32","spi_slave_transmit SECONED OK ");
                ESP_LOG_BUFFER_HEX("2 recvbuf:",recvbuf,14);
				memset(sendbuf, 0, packageLen+2);
            }
			GPIO_OUT_SET_REG |=1 << GPIO_HANDSHAKE_BIT;
			vTaskDelay(1000);				 
        }
        /*
        if(ret == ESP_OK)
        {
            SendDataCnt+=(t.trans_len/8);
            ESP_LOGI("ESP32","recvbuf[0] = %x\r\n",recvbuf[0]);
            ESP_LOGI("ESP32","recvbuf[1] = %x\r\n",recvbuf[1]);
            //ESP_LOGI("ESP32","recvbuf[2] = %x\r\n",recvbuf[2]);
            //ESP_LOGI("ESP32","recvbuf[3] = %x\r\n",recvbuf[3]);
            //ESP_LOGI("ESP32","recvbuf[4] = %x\r\n",recvbuf[4]);
            //ESP_LOGI("ESP32","recvbuf[5] = %x\r\n",recvbuf[5]);
            //ESP_LOGI("ESP32","recvbuf[6] = %x\r\n",recvbuf[6]);

            //ESP_LOGI("ESP32","recvbuf[%d] = %x\r\n",RXBUFFER_SIZE - 1,recvbuf[RXBUFFER_SIZE -1]);
            //ESP_LOGI("ESP32","trans_len = %d\r\n",t.trans_len);
            //ESP_LOGI("ESP32","SendDataCnt = %d\r\n",SendDataCnt);
        }
        Time2 = esp_log_timestamp();

        if((Time2 - Time1) > 1000)
        {
            //SendDataCnt /= 8;//bytes//
            float TCP_Speed = ((float)SendDataCnt)/((float)(Time2 - Time1)/1000.0f); //bytes/s/
            //ESP_LOGI("ESP32","SendDataCnt = %d\r\n",SendDataCnt);
            ESP_LOGI("ESP32","SPI speed = %f kB/s\r\n",TCP_Speed / 1024.0f);

            Time1 = Time2;
            SendDataCnt = 0;
        }
        */

        //vTaskDelay( 1);
        //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("Received: %s\n", recvbuf);
        // n++;
    }

}

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值