Skip to content

SPI CODE

Component Architecture

- driver
    - spi
        - include
            - spi.h
        - spi.c
        - CMakeLists.txt

driver/spi/CMakeLists.txt

set(src_dirs
    .
)

set(include_dirs
    include
)

set(requires
    driver
)

idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires})

Note

Note that in the drivers, we used spi and gpio related functions from the builtin driver library, therefore, we need to indicate these dependencies in the CMakeLists.txt file by adding driver to the REQUIRES field.

spi.h

/**
 * @file spi.h
 * @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg)
 * @brief
 * @version 1.0
 * @date 2024-11-18
 * @ref Alientek SPI driver
 * @copyright Copyright (c) 2024
 *
 */

#pragma once

#ifdef __cplusplus
extern "C"
{
#endif

/* Dependencies */
#include <string.h>
#include "esp_log.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"

/* GPIO Definitions */
#define SPI2_MOSI_GPIO_PIN GPIO_NUM_11 /* SPI2_MOSI */
#define SPI2_CLK_GPIO_PIN GPIO_NUM_12  /* SPI2_CLK */
#define SPI2_MISO_GPIO_PIN GPIO_NUM_13 /* SPI2_MISO */

/* SPI3 GPIO Definitions for ADXL355 */
#define SPI3_MOSI_GPIO_PIN GPIO_NUM_5  /* SPI3_MOSI */
#define SPI3_CLK_GPIO_PIN GPIO_NUM_7   /* SPI3_SCLK */
#define SPI3_MISO_GPIO_PIN GPIO_NUM_6  /* SPI3_MISO */

/* Global SPI device handles */

/* Function Prototypes */

/**
 * @brief       Initialize SPI2
 * @param       None
 * @retval      None
 */
void spi2_init(void);

/**
 * @brief       Initialize SPI3 for ADXL355
 * @param       None
 * @retval      None
 */
void spi3_init(void);

/**
 * @brief       Send command via SPI2
 * @param       handle : SPI handle
 * @param       cmd    : Command to send
 * @retval      None
 */
void spi2_write_cmd(spi_device_handle_t handle, uint8_t cmd);

/**
 * @brief       Send command via SPI3
 * @param       handle : SPI handle
 * @param       cmd    : Command to send
 * @retval      None
 */
void spi3_write_cmd(spi_device_handle_t handle, uint8_t cmd);

/**
 * @brief       Send data via SPI2
 * @param       handle : SPI handle
 * @param       data   : Data to send
 * @param       len    : Length of data to send
 * @retval      None
 */
void spi2_write_data(spi_device_handle_t handle, const uint8_t *data, int len);

/**
 * @brief       Send data via SPI3
 * @param       handle : SPI handle
 * @param       data   : Data to send
 * @param       len    : Length of data to send
 * @retval      None
 */
void spi3_write_data(spi_device_handle_t handle, const uint8_t *data, int len);

/**
 * @brief       Process data via SPI2
 * @param       handle       : SPI handle
 * @param       data         : Data to send
 * @retval      t.rx_data[0] : Received data
 */
uint8_t spi2_transfer_byte(spi_device_handle_t handle, uint8_t byte);

/**
 * @brief       Process data via SPI3
 * @param       handle       : SPI handle
 * @param       data         : Data to send
 * @retval      t.rx_data[0] : Received data
 */
uint8_t spi3_transfer_byte(spi_device_handle_t handle, uint8_t byte);

/**
 * @brief       Read data via SPI2
 * @param       handle       : SPI handle
 * @param       data         : Buffer to store received data
 * @param       len          : Length of data to read
 * @retval      None
 */
void spi2_read_data(spi_device_handle_t handle, uint8_t *data, int len);

/**
 * @brief       Read data via SPI3
 * @param       handle       : SPI handle
 * @param       data         : Buffer to store received data
 * @param       len          : Length of data to read
 * @retval      None
 */
void spi3_read_data(spi_device_handle_t handle, uint8_t *data, int len);

/**
 * @brief       Read single byte via SPI2
 * @param       handle       : SPI handle
 * @retval      Received byte
 */
uint8_t spi2_read_byte(spi_device_handle_t handle);

/**
 * @brief       Read single byte via SPI3
 * @param       handle       : SPI handle
 * @retval      Received byte
 */
uint8_t spi3_read_byte(spi_device_handle_t handle);

#ifdef __cplusplus
}
#endif

spi.c

/**
 * @file spi.c
 * @author
 * @brief
 * @version 1.0
 * @date 2024-11-18
 * @ref Alientek SPI driver
 *
 */

#include "spi.h"

#ifdef __cplusplus
extern "C"
{
#endif

/* Global SPI device handles */
// spi_device_handle_t spi3_device_handle = NULL;  // Removed, now returned via function parameter

//==============================================================================
// SPI2 FUNCTIONS
//==============================================================================

/**
 * @brief       Initialize SPI2
 * @param       None
 * @retval      None
 */
void spi2_init(void)
{
    esp_err_t ret = 0;
    spi_bus_config_t spi_bus_conf = {0};

    /* SPI bus configuration */
    spi_bus_conf.miso_io_num = SPI2_MISO_GPIO_PIN; /* SPI_MISO pin */
    spi_bus_conf.mosi_io_num = SPI2_MOSI_GPIO_PIN; /* SPI_MOSI pin */
    spi_bus_conf.sclk_io_num = SPI2_CLK_GPIO_PIN;  /* SPI_SCLK pin */
    spi_bus_conf.quadwp_io_num = -1;               /* SPI write protection signal pin, not enabled */
    spi_bus_conf.quadhd_io_num = -1;               /* SPI hold signal pin, not enabled */
    spi_bus_conf.max_transfer_sz = 160 * 80 * 2;   /* Configure maximum transfer size in bytes */

    /* Initialize SPI bus */
    ret = spi_bus_initialize(SPI2_HOST, &spi_bus_conf, SPI_DMA_CH_AUTO); /* SPI bus initialization */
    ESP_ERROR_CHECK(ret);                                                /* Check parameter values */
}

/**
 * @brief       Send command via SPI2
 * @param       handle : SPI handle
 * @param       cmd    : Command to send
 * @retval      None
 */
void spi2_write_cmd(spi_device_handle_t handle, uint8_t cmd)
{
    esp_err_t ret;
    spi_transaction_t t = {0};

    t.length = 8;                                  /* Number of bits to transmit (1 byte = 8 bits) */
    t.tx_buffer = &cmd;                            /* Fill the command */
    ret = spi_device_polling_transmit(handle, &t); /* Start transmission */
    ESP_ERROR_CHECK(ret);                          /* Usually no issues */
}

/**
 * @brief       Send data via SPI2
 * @param       handle : SPI handle
 * @param       data   : Data to send
 * @param       len    : Length of data to send
 * @retval      None
 */
void spi2_write_data(spi_device_handle_t handle, const uint8_t *data, int len)
{
    esp_err_t ret;
    spi_transaction_t t = {0};

    if (len == 0)
    {
        return; /* No data to transmit if length is 0 */
    }

    t.length = len * 8;                            /* Number of bits to transmit (1 byte = 8 bits) */
    t.tx_buffer = data;                            /* Fill the data */
    ret = spi_device_polling_transmit(handle, &t); /* Start transmission */
    ESP_ERROR_CHECK(ret);                          /* Usually no issues */
}

/**
 * @brief       Process data via SPI2
 * @param       handle       : SPI handle
 * @param       data         : Data to send
 * @retval      t.rx_data[0] : Received data
 */
uint8_t spi2_transfer_byte(spi_device_handle_t handle, uint8_t data)
{
    spi_transaction_t t;

    memset(&t, 0, sizeof(t));

    t.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA;
    t.length = 8;
    t.tx_data[0] = data;
    spi_device_transmit(handle, &t);

    return t.rx_data[0];
}

/**
 * @brief       Read data via SPI2
 * @param       handle       : SPI handle
 * @param       data         : Buffer to store received data
 * @param       len          : Length of data to read
 * @retval      None
 */
void spi2_read_data(spi_device_handle_t handle, uint8_t *data, int len)
{
    esp_err_t ret;
    spi_transaction_t t = {0};

    if (len == 0)
    {
        return; /* No data to read if length is 0 */
    }

    t.length = len * 8;                            /* Number of bits to receive (1 byte = 8 bits) */
    t.rx_buffer = data;                            /* Buffer to store received data */
    t.tx_buffer = NULL;                            /* No actual data to transmit */
    t.flags = 0;                                   /* Clear all flags */

    /* Use polling transmit for better control */
    ret = spi_device_polling_transmit(handle, &t);
    ESP_ERROR_CHECK(ret);                          /* Check for errors */
}

/**
 * @brief       Read single byte via SPI2
 * @param       handle       : SPI handle
 * @retval      Received byte
 */
uint8_t spi2_read_byte(spi_device_handle_t handle)
{
    spi_transaction_t t;

    memset(&t, 0, sizeof(t));

    t.flags = SPI_TRANS_USE_RXDATA;
    t.length = 8;
    spi_device_transmit(handle, &t);

    return t.rx_data[0];
}

//==============================================================================
// SPI3 FUNCTIONS
//==============================================================================

/**
 * @brief       Initialize SPI3 for ADXL355
 * @param       None
 * @retval      None
 */
void spi3_init(void)
{
    esp_err_t ret;
    spi_bus_config_t spi_bus_conf = {0};

    /* Step 1: Configure SPI bus parameters */
    spi_bus_conf.miso_io_num = SPI3_MISO_GPIO_PIN;    // MISO pin
    spi_bus_conf.mosi_io_num = SPI3_MOSI_GPIO_PIN;    // MOSI pin
    spi_bus_conf.sclk_io_num = SPI3_CLK_GPIO_PIN;     // SCLK pin
    spi_bus_conf.quadwp_io_num = -1;                  // Not used
    spi_bus_conf.quadhd_io_num = -1;                  // Not used
    spi_bus_conf.max_transfer_sz = 1024;              // Maximum transfer size

    /* Step 2: Initialize SPI bus (DMA disabled) */
    ret = spi_bus_initialize(SPI3_HOST, &spi_bus_conf, SPI_DMA_DISABLED);
    if (ret != ESP_OK) {
        ESP_LOGE("SPI3", "SPI bus initialization failed: %s", esp_err_to_name(ret));
        ESP_ERROR_CHECK(ret);
    }

    ESP_LOGI("SPI3", "SPI3 bus initialized successfully");
}

/**
 * @brief       Send command via SPI3
 * @param       handle : SPI handle
 * @param       cmd    : Command to send
 * @retval      None
 */
void spi3_write_cmd(spi_device_handle_t handle, uint8_t cmd)
{
    esp_err_t ret;
    spi_transaction_t t = {0};

    t.length = 8;                                  /* Number of bits to transmit (1 byte = 8 bits) */
    t.tx_buffer = &cmd;                            /* Fill the command */
    ret = spi_device_polling_transmit(handle, &t); /* Start transmission */
    ESP_ERROR_CHECK(ret);                          /* Usually no issues */
}

/**
 * @brief       Send data via SPI3
 * @param       handle : SPI handle
 * @param       data   : Data to send
 * @param       len    : Length of data to send
 * @retval      None
 */
void spi3_write_data(spi_device_handle_t handle, const uint8_t *data, int len)
{
    esp_err_t ret;
    spi_transaction_t t = {0};

    if (len == 0)
    {
        ESP_LOGW("SPI3", "Write length is 0, skipping");
        return;
    }

    ESP_LOGD("SPI3", "Writing %d bytes to SPI3", len);

    /* Configure transaction like plasmapper for write */
    t.cmd = 0;                                        /* No command bits */
    t.addr = data[0];                                 /* First byte as address */
    t.length = (len - 1) * 8;                         /* Remaining bytes as data */
    t.tx_buffer = &data[1];                           /* Data to write (excluding address) */
    t.rx_buffer = NULL;                               /* No read data */
    t.flags = 0;                                      /* Use default flags */

    ret = spi_device_polling_transmit(handle, &t);
    if (ret != ESP_OK) {
        ESP_LOGE("SPI3", "SPI3 write failed: %s", esp_err_to_name(ret));
    }
    ESP_ERROR_CHECK(ret);

    ESP_LOGD("SPI3", "Wrote %d bytes successfully", len);
}

/**
 * @brief       Process data via SPI3
 * @param       handle       : SPI handle
 * @param       data         : Data to send
 * @retval      t.rx_data[0] : Received data
 */
uint8_t spi3_transfer_byte(spi_device_handle_t handle, uint8_t data)
{
    spi_transaction_t t;

    memset(&t, 0, sizeof(t));

    t.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA;
    t.length = 8;
    t.tx_data[0] = data;
    spi_device_transmit(handle, &t);

    return t.rx_data[0];
}

/**
 * @brief       Read data via SPI3
 * @param       handle       : SPI handle
 * @param       data         : Buffer to store received data
 * @param       len          : Length of data to read
 * @retval      None
 */
void spi3_read_data(spi_device_handle_t handle, uint8_t *data, int len)
{
    esp_err_t ret;
    spi_transaction_t t = {0};

    if (len == 0)
    {
        ESP_LOGW("SPI3", "Read length is 0, skipping");
        return; /* No data to read if length is 0 */
    }

    ESP_LOGD("SPI3", "Reading %d bytes from SPI3", len);

    /* For ADXL355, we need to send a dummy byte to generate clock while reading */
    /* Configure transaction for read operation with dummy transmit */
    t.length = len * 8;                            /* Number of bits to receive (1 byte = 8 bits) */
    t.rx_buffer = data;                            /* Buffer to store received data */
    t.tx_buffer = NULL;                            /* No actual data to transmit */
    t.flags = 0;                                   /* Clear all flags */

    /* Use polling transmit for better control */
    ret = spi_device_polling_transmit(handle, &t);
    if (ret != ESP_OK) {
        ESP_LOGE("SPI3", "SPI3 read failed: %s", esp_err_to_name(ret));
    }
    ESP_ERROR_CHECK(ret);                          /* Check for errors */

    ESP_LOGD("SPI3", "Read %d bytes successfully", len);
}

/**
 * @brief       Read single byte via SPI3
 * @param       handle       : SPI handle
 * @retval      Received byte
 */
uint8_t spi3_read_byte(spi_device_handle_t handle)
{
    spi_transaction_t t;

    memset(&t, 0, sizeof(t));

    t.flags = SPI_TRANS_USE_RXDATA;
    t.length = 8;
    spi_device_transmit(handle, &t);

    return t.rx_data[0];
}

#ifdef __cplusplus
}
#endif

main.c

refer to LCD code / adxl355 code