STM32_SPI_ESP32_SPI


Transmisia unor date pe SPI de la STM32F103C6 la ESP32

Acest proiect realizează interfațarea între două microcontrolere,STM32F103C6 și ESP32, pentru a transfera date utilizând Protocolul de Interfață Serială (SPI). Datele sunt preluate de la un potentiometru
conectat la STM32F103C6 și sunt trimise către ESP32, care mai departe  poate folosi informațiile pentru controlul altor dispozitive. STM32F103C6 va acționa ca dispozitiv master SPI, iar ESP32 ca dispozitiv slave.

Acest proiect demonstrează un mod eficient de a conecta și de a comunica între două microcontrolere, STM32F103C6 și ESP32, folosind protocolul SPI. Rezultatele obținute pot servi drept bază pentru dezvoltarea deaplicații mai complexe, ce necesită transfer rapid și fiabil de date.

Etape de Implementare

  • Configurarea Hardware-ului:
    • Conectarea potentiometrului la intrarea analogică a STM32F103C6.
    • Conectarea pinii SPI între STM32 și ESP32. Asigurați-vă că există o conexiune stabilă între MOSI, MISO, SCK și SS (Chip Select).
    • ESP32 – STM32
      • D23(MOSI) – B5 (MOSI1)
      • D19 (MISO) – B4 (MISO1)
      • D18 (SCK) – B3 (SCK1)
      • D5 (CS) – A15 (NSS1)
  • Configurarea STM32F103C6:
    • Programarea STM32 pentru a citi valorile de la potentiometru folosind ADC (MX_ADC2_Init();) (Convertor Analog-Digital), un ADC foarte performant care oferă valori pe 16 biți la o viteză considerabilă.
    • Configurarea interfeței SPI ( MX_SPI1_Init();)  pentru a trimite datele către ESP32.
    • Crearea unei funcții de transmisie SPI care trimite datele de la ADC către ESP32 (vezi funția main de mai jos).
  • Configurarea ESP32:
    • Configurarea interfeței SPI pentru a primi datele de la STM32 folosind lib-ul ESP32SPISlave.
    • Programarea pentru a citi datele primite și pentru a le procesa sau afișa (vezi funcția loop).
    • Utilizarea unui serial monitor pentru a verifica datele primite de la STM32 (vezi Serial).
  • Validare și Testare:
    • Testarea transmisiei SPI pentru a verifica dacă datele sunt transmise corect.
    • Validarea datelor primite pe ESP32 pentru a asigura acuratețea acestora.
    • Testarea sistemului în diverse condiții pentru a verifica stabilitatea și fiabilitatea

Componente

Schema electronică/sistem

STM32_SPI_ESP32_SPI

STM32_SPI_ESP32_SPI
Conexiuni STM32 si ESP32
Conexiuni STM32 si ESP32

Cod de test

Codul care rulează pe STM32 (Master)


/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dma.h"
#include "spi.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "string.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
int counter =0;
uint16_t pot_value;

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC2_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */
  /* Run the ADC calibration */
  if (HAL_ADCEx_Calibration_Start(&hadc2) != HAL_OK)
  {
    /* Calibration Error */
    Error_Handler();
  }
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  HAL_ADC_Start(&hadc2);
	  HAL_ADC_PollForConversion(&hadc2,1000);
	  pot_value=HAL_ADC_GetValue(&hadc2);


	  HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
	  //HAL_GPIO_ReadPin(POT_PIN_GPIO_Port, POT_PIN_Pin);
	  HAL_Delay(50);
	  // Transmite counter-ul pe SPI (16-bit)
	  uint16_t dataToSend = pot_value;

	  // Chip select pe LOW pentru începutul transmisiei
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);

	  // Transmitere pe SPI
	  HAL_SPI_Transmit(&hspi1, (uint8_t *)&dataToSend, 1, HAL_MAX_DELAY);

	  // Chip select pe HIGH pentru finalul transmisiei
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);

	  // Așteapta inainte de urmatoarea iterație
	  HAL_Delay(50); // Interval intre incrementari si transmisii

 }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
  PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
/** Configure pins as
        * Analog
        * Input
        * Output
        * EVENT_OUT
        * EXTI
        * Free pins are configured automatically as Analog (this feature is enabled through
        * the Code Generation settings)
*/
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(LED_PIN_GPIO_Port, LED_PIN_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = LED_PIN_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(LED_PIN_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : PC14 PC15 */
  GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pins : PA5 PA6 PA7 PA8
                           PA9 PA10 PA11 PA12 */
  GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8
                          |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PB0 PB1 PB2 PB10
                           PB11 PB12 PB13 PB14
                           PB15 PB6 PB7 PB8
                           PB9 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10
                          |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14
                          |GPIO_PIN_15|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8
                          |GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}

/* ADC2 init function */
void MX_ADC2_Init(void)
{

  /* USER CODE BEGIN ADC2_Init 0 */

  /* USER CODE END ADC2_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC2_Init 1 */

  /* USER CODE END ADC2_Init 1 */

  /** Common config
  */
  hadc2.Instance = ADC2;
  hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc2.Init.ContinuousConvMode = ENABLE;
  hadc2.Init.DiscontinuousConvMode = DISABLE;
  hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc2.Init.NbrOfConversion = 3;
  if (HAL_ADC_Init(&hadc2) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_3;
  sConfig.Rank = ADC_REGULAR_RANK_2;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_4;
  sConfig.Rank = ADC_REGULAR_RANK_3;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC2_Init 2 */

  /* USER CODE END ADC2_Init 2 */

}
/* SPI1 init function */
void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

Codul care rulează pe ESP32 (Slave)


/*
; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:esp32doit-devkit-v1]
platform = espressif32
board = esp32doit-devkit-v1
framework = arduino
upload_port = COM9
monitor_port = COM9
monitor_speed = 115200
lib_deps = hideakitai/ESP32SPISlave@^0.2.0
*/
#include "ESP32SPISlave.h"

ESP32SPISlave slave;

static constexpr uint32_t BUFFER_SIZE{8};
uint8_t spi_slave_tx_buf[BUFFER_SIZE];
uint8_t spi_slave_rx_buf[BUFFER_SIZE];

#define LED 2
void setup()
{
  Serial.begin(115200);
  delay(2000);
  pinMode(LED, OUTPUT);
  // begin() after setting
  // VSPI = CS:  5, CLK: 18, MOSI: 23, MISO: 19
  slave.setDataMode(SPI_MODE0);

  slave.begin(VSPI); // you can use VSPI like this
  Serial.println("VSPI with SPI_MODE0 configured! ");
  // clear buffers
  memset(spi_slave_tx_buf, 0, BUFFER_SIZE);
  memset(spi_slave_rx_buf, 0, BUFFER_SIZE);
}

void loop()
{
  // if there is no transaction in queue, add transaction
  if (slave.remained() == 0)
  {
    slave.queue(spi_slave_rx_buf, spi_slave_tx_buf, BUFFER_SIZE);
  }
  // if transaction has completed from master,
  // available() returns size of results of transaction,
  // and buffer is automatically updated
  char data;
  while (slave.available())
  {
    // show received data
    Serial.print("Pot value Received: ");
    uint16_t receveived_word1 = (spi_slave_rx_buf[0] <<  8) | (spi_slave_rx_buf[1]);
    uint16_t receveived_word2 = (spi_slave_rx_buf[2] << 8) | (spi_slave_rx_buf[3]);
    uint16_t receveived_word3 = (spi_slave_rx_buf[4] << 8) | (spi_slave_rx_buf[5]);
    uint16_t receveived_word4 = (spi_slave_rx_buf[6] << 8) | (spi_slave_rx_buf[7]);

    Serial.println(receveived_word1);
    Serial.println(receveived_word2);
    Serial.println(receveived_word3);
    Serial.println(receveived_word4);

    if (receveived_word1 > 2000)
    {
      Serial.println("Setting LED active HIGH ");
      digitalWrite(LED, HIGH);
    }
    else
    {
      Serial.println("Setting LED active LOW ");
      digitalWrite(LED, LOW);
    }
    Serial.println("");
    slave.pop();
  }

}

Date le primite de ESP32 (în dreapta)
Datele primite de ESP32 (în stânga)
STM32 breakpoint
STM32 breakpoint

Documentație proiect

Afiliere eMag

Linkurile de la secțiunea “Componente” conțin adresa mea de afiliere la eMag.ro, iar dacă cumperi folosind aceste linkuri vei susține blogul meu, iar 10 % din donații se vor direcționa pentru fundația dăruiește viată. Mulțumesc !

Mulțumesc pentru atenție!

Pentru întrebări și/sau consultanță tehnică vă stau la dispoziție pe blog mai jos în secțiunea de comentarii sau pe email simedruflorin@automatic-house.ro.

O zi plăcută tuturor !

Back to top of page

De Florin Simedru

Autor

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *


The reCAPTCHA verification period has expired. Please reload the page.