Back to TILs

Esp32 with FreeRTOS using Arduino - Blink

C FreeRTOS Arduino SPI

Table of contents

File FreeRTOS_Esp32_SPI2_1.ino


#include <driver/gpio.h>
#include <driver/spi_master.h>
#include <freertos/FreeRTOS.h>

// #define MOSI 11
// #define MISO 13
// #define SCK  12
// #define SS  10

//  +------+----------+----------+----------+---------+
//  | SPI  | MOSI     | MISO     | SCLK     | CS      |
//  +------+----------+----------+----------+---------+
//  | VSPI | GPIO 23  | GPIO 19  | GPIO 18  | GPIO 5  |
//  | HSPI | GPIO 13  | GPIO 12  | GPIO 14  | GPIO 15 |
//  +------+----------+----------+----------+---------+
     
spi_device_handle_t           spi_handle;
spi_bus_config_t              spi_bus_config;
spi_device_interface_config_t spi_device_interface_config;
spi_dma_chan_t                spi_dma_chan;

TaskHandle_t spiTaskHandle = NULL;

void ledTask(void *pvParameters);
void setupSPI();

// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
void setup() {
  Serial.begin(115200); // Initialize serial communication
  Serial.print("MOSI: ");
  Serial.println(MOSI);
  Serial.print("MISO: ");
  Serial.println(MISO);
  Serial.print("SCK: ");
  Serial.println(SCK);
  Serial.print("SS: ");
  Serial.println(SS);  

  TaskFunction_t   pvTaskCode         = spiTask;
  const char      *constpcName        = "SPI Task";
  const uint32_t   usStackDepth       = 2048;
  void            *constpvParameters  = NULL;
  UBaseType_t      uxPriority         = 1;
  TaskHandle_t    *constpvCreatedTask = &spiTaskHandle;
  const BaseType_t xCoreID            = 1;

  // Create the SPI task
  xTaskCreatePinnedToCore(pvTaskCode,         // Task function
                          constpcName,        // Task name
                          usStackDepth,       // Stack size
                          constpvParameters,  // Task parameters
                          uxPriority,         // Task priority
                          constpvCreatedTask, // Task handle
                          xCoreID             // Core number to run the task on (0 or 1)
  );
}

// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
void loop() {}

// ----------------------------------------------------------------------
// Based on https://www.youtube.com/watch?v=2yY_ifE8jQw
// ----------------------------------------------------------------------
void setupSPI() {
  spi_bus_config = {.mosi_io_num = MOSI, .miso_io_num = MISO, .sclk_io_num = SCK};

  // SPI_MASTER_FREQ_40M is defined at spi_master.h
  //
  // 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.
  //
  // SPI mode, representing a pair of (CPOL, CPHA) configuration:
  // - 0: (0, 0)
  // - 1: (0, 1)
  // - 2: (1, 0)
  // - 3: (1, 1)
  //
  // 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 time
  spi_device_interface_config = {//
                                 .mode           = 0,
                                 .duty_cycle_pos = 128, // 50% positive
                                 .clock_speed_hz = SPI_MASTER_FREQ_40M,
                                 .spics_io_num   = SS,
                                 .queue_size     = 1};

  spi_dma_chan = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO, SPI_DMA_DISABLED

  spi_bus_initialize(spi_host_device_t::SPI2_HOST, &spi_bus_config, spi_dma_chan);
  spi_bus_add_device(spi_host_device_t::SPI2_HOST, &spi_device_interface_config, &spi_handle);
}

// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
void spiTask(void *pvParameters) {
  char sendbuf[128] = {0};
  char recvbuf[128] = {0};

  setupSPI();

  spi_transaction_t spi_transaction;
  memset(&spi_transaction, 0, sizeof(spi_transaction_t));

  while (1) {
    snprintf(sendbuf, sizeof(sendbuf), "Hi I am from ESP32");
    spi_transaction.length    = sizeof(sendbuf) * 8;
    spi_transaction.tx_buffer = sendbuf;
    spi_transaction.rx_buffer = recvbuf;
    spi_device_transmit(spi_handle, &spi_transaction);
    printf("Transmitted: %s\n", sendbuf);
    printf("Received: %s\n", recvbuf);
    vTaskDelay(1000 / portTICK_PERIOD_MS);
  }

  // https://youtu.be/2yY_ifE8jQw?t=703
  // Put a wire linking MISO and MOSI
  // What is sent to MOSI is get back on MISO
}

Compiling the project

# ESP32-WROOM-DA Module                              esp32:esp32:esp32da
# ESP32S3 Dev Module Octal (WROOM2)                  esp32:esp32:esp32s3-octal
# Fri3d Badge 2024 (ESP32-S3-WROOM-1)                esp32:esp32:fri3d_2024_esp32s3
# uPesy ESP32 Wroom DevKit                           esp32:esp32:uPesy_wroom

BOARD?= esp32:esp32:esp32da
PORT?= /dev/ttyUSB0
BAUD?= 115200
PROJECT_NAME?= FreeRTOS_Esp32_blink

all:
	$(Q)echo "Compiling $(PROJECT_NAME)..."
	$(Q)mkdir -p out
	$(Q)arduino-cli compile \
		--clean \
		--fqbn $(BOARD) \
		--output-dir out \
		$(PROJECT_NAME).ino
	$(MAKE) til
	$(MAKE) til_copy

clean:
	$(RM) -r out
	$(RM) -r til

Update config, toolchain, libraries

.PHONY: update
update:
	$(Q)echo create config at /home/geraldo/.arduino15/arduino-cli.yaml
	$(Q)arduino-cli config init || echo Config file already exists
	$(Q)arduino-cli config set network.connection_timeout 600s
	$(Q)cat /home/geraldo/.arduino15/arduino-cli.yaml
	$(Q)arduino-cli core update-index
	$(Q)arduino-cli core install arduino:avr
	$(Q)arduino-cli core install esp32:esp32
	$(Q)arduino-cli upgrade

Upload binary to the board

.PHONY: upload
upload:
	$(Q)arduino-cli upload \
		$(shell pwd) \
		--input-dir out/ \
		--port $(PORT) \
		--fqbn $(BOARD) \
		--verbose \
		--verify

Open serial monitor in another terminal

.PHONY: serial
serial:
	$(Q)xfce4-terminal -x picocom $(PORT) \
		--baud $(BAUD) \
		--echo \
		--exit-after 10000