跳转至

SPI 代码

组件架构

- 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

注意,在驱动程序中,我们使用了 ESP-IDF 内置的 driver 库中的spi和gpio相关函数,因此,我们需要在 CMakeLists.txt 文件的 REQUIRES 字段中指明这个依赖关系。

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