stm32之hal库spi驱动封装(实现阻塞,中断,dma三种方式)

前言

  1. 配置功能参考rt-thread驱动代码
  2. 将中断配置和dma配置单独分开管理

代码

中断管理

头文件

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-5-3     shchl   first version
 */

#ifndef TX_STM32_F4_DRV_NVIC_OS_H
#define TX_STM32_F4_DRV_NVIC_OS_H
#include "drv_common.h"

void stm32_nvic_common_enable(uint32_t instance,uint32_t preempt,uint32_t sub);
void stm32_nvic_common_disable(uint32_t instance);
uint8_t stm32_nvic_common_enabled_check(uint32_t instance);
#endif //TX_STM32_F4_DRV_NVIC_OS_H

源文件

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-5-3     shchl   first version
 */

#include "drv_nvic_os.h"

enum stm32_irq_op_enum {
    OPEN_IRQn,
    CLOSE_IRQn,
    READ_IRQn
};

/**
 * @brief (适用于大部分配置)
 * @param instance
 * @param preempt
 * @param sub
 * @param open_flag
 */
static uint32_t stm32_nvic_common(uint32_t instance, uint32_t preempt, uint32_t sub, enum stm32_irq_op_enum mode) {
    uint32_t irq;
    switch (instance) {
#define irq_set(IRQn) {irq=IRQn;}break
        case (uint32_t) SPI1: irq_set(SPI1_IRQn);
        case (uint32_t) SPI2: irq_set(SPI2_IRQn);
        case (uint32_t) SPI3: irq_set(SPI3_IRQn);
        case (uint32_t) USART1: irq_set(USART1_IRQn);
        case (uint32_t) USART2: irq_set(USART2_IRQn);
        case (uint32_t) USART3: irq_set(USART3_IRQn);
        case (uint32_t) UART4: irq_set(UART4_IRQn);
        case (uint32_t) UART5: irq_set(UART5_IRQn);
        case (uint32_t) DMA2_Stream0: irq_set(DMA2_Stream0_IRQn);
        case (uint32_t) DMA2_Stream1: irq_set(DMA2_Stream1_IRQn);
        case (uint32_t) DMA2_Stream2: irq_set(DMA2_Stream2_IRQn);
        case (uint32_t) DMA2_Stream3: irq_set(DMA2_Stream3_IRQn);
        case (uint32_t) DMA2_Stream4: irq_set(DMA2_Stream4_IRQn);
        case (uint32_t) DMA2_Stream5: irq_set(DMA2_Stream5_IRQn);
        case (uint32_t) DMA2_Stream6: irq_set(DMA2_Stream6_IRQn);
        case (uint32_t) DMA2_Stream7: irq_set(DMA2_Stream7_IRQn);
        case (uint32_t) DMA1_Stream0: irq_set(DMA1_Stream0_IRQn);
        case (uint32_t) DMA1_Stream1: irq_set(DMA1_Stream1_IRQn);
        case (uint32_t) DMA1_Stream2: irq_set(DMA1_Stream2_IRQn);
        case (uint32_t) DMA1_Stream3: irq_set(DMA1_Stream3_IRQn);
        case (uint32_t) DMA1_Stream4: irq_set(DMA1_Stream4_IRQn);
        case (uint32_t) DMA1_Stream5: irq_set(DMA1_Stream5_IRQn);
        case (uint32_t) DMA1_Stream6: irq_set(DMA1_Stream6_IRQn);
        case (uint32_t) DMA1_Stream7: irq_set(DMA1_Stream7_IRQn);
        default: {
            return UINT32_MAX;
        }

    }
#undef  irq_set

    switch (mode) {

        case OPEN_IRQn: {
            HAL_NVIC_SetPriority(irq, preempt, sub);
            HAL_NVIC_EnableIRQ(irq);
        }
            break;
        case CLOSE_IRQn: {
            HAL_NVIC_DisableIRQ(irq);
        }
            break;
        default: {
            break;
        }
    }

    return irq;
}


/**
 * @brief 中断使能
 * @param instance
 * @param preempt
 * @param sub
 */
void stm32_nvic_common_enable(uint32_t instance, uint32_t preempt, uint32_t sub) {

    stm32_nvic_common(instance, preempt, sub, OPEN_IRQn);
}

void stm32_nvic_common_disable(uint32_t instance) {
    stm32_nvic_common(instance, 0, 0, CLOSE_IRQn);
}
/**
 * @brief nvic 启用状态检测
 * @param instance
 * @return 0 未启用,1 启用
 */
uint8_t stm32_nvic_common_enabled_check(uint32_t instance) {
    uint32_t irq = stm32_nvic_common(instance, 0, 0, READ_IRQn);
    return NVIC_GetEnableIRQ(irq);
}

DMA管理

头文件

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-5-3     shchl   first version
 */

#ifndef TX_STM32_F4_DRV_DMA_OS_H
#define TX_STM32_F4_DRV_DMA_OS_H

#include "drv_common.h"

struct stm32_dma_info {
    uint32_t instance;
    DMA_HandleTypeDef *dma_tx;
    DMA_HandleTypeDef *dma_rx;
};

struct stm32_dma_info *dma_info_get(uint32_t instance);

void dma_clk_enable(DMA_HandleTypeDef *handle);
#endif //TX_STM32_F4_DRV_DMA_OS_H

源文件

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-5-3     shchl   first version
 */

#include "drv_dma_os.h"

static DMA_HandleTypeDef spi1_dma_tx = {.Instance=DMA2_Stream3, .Init.Channel=DMA_CHANNEL_3};
static DMA_HandleTypeDef spi1_dma_rx = {.Instance=DMA2_Stream0, .Init.Channel=DMA_CHANNEL_3};
static struct stm32_dma_info dma_info_map[] = {
        {(uint32_t) SPI1, &spi1_dma_tx, &spi1_dma_rx}

};
#define DMA_MAP_CNT ( sizeof(dma_info_map)/ sizeof(dma_info_map[0]))

struct stm32_dma_info *dma_info_get(uint32_t instance) {
    for (int i = 0; i < DMA_MAP_CNT; ++i) {
        if (dma_info_map[i].instance == instance) {
            return dma_info_map + i;
        }
    }
    return NULL;
}

void dma_clk_enable(DMA_HandleTypeDef *handle) {
    switch ((uint32_t) handle->Instance) {
        case (uint32_t) DMA2_Stream0:
        case (uint32_t) DMA2_Stream1:
        case (uint32_t) DMA2_Stream2:
        case (uint32_t) DMA2_Stream3:
        case (uint32_t) DMA2_Stream4:
        case (uint32_t) DMA2_Stream5:
        case (uint32_t) DMA2_Stream6:
        case (uint32_t) DMA2_Stream7:
            __HAL_RCC_DMA2_CLK_ENABLE();
            break;
        case (uint32_t) DMA1_Stream0:
        case (uint32_t) DMA1_Stream1:
        case (uint32_t) DMA1_Stream2:
        case (uint32_t) DMA1_Stream3:
        case (uint32_t) DMA1_Stream4:
        case (uint32_t) DMA1_Stream5:
        case (uint32_t) DMA1_Stream6:
        case (uint32_t) DMA1_Stream7:
            __HAL_RCC_DMA1_CLK_ENABLE();
            break;
        default:

            return;

    }


}


void DMA2_Stream0_IRQHandler(void) {
    TX_INTERRUPT_SAVE_AREA
    TX_DISABLE
    HAL_DMA_IRQHandler(&spi1_dma_rx);
    TX_RESTORE
}

void DMA2_Stream3_IRQHandler(void) {
    TX_INTERRUPT_SAVE_AREA
    TX_DISABLE
    HAL_DMA_IRQHandler(&spi1_dma_tx);
    TX_RESTORE
}

SPI驱动

头文件

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-5-3     shchl   first version
 */

#ifndef TX_STM32_F4_DRV_SPI_OS_H
#define TX_STM32_F4_DRV_SPI_OS_H

#include "drv_common.h"

#define SPI_CONTROLLER_NUM 1

/**
 * At CPOL=0 the base value of the clock is zero
 *  - For CPHA=0, data are captured on the clock's rising edge (low->high transition)
 *    and data are propagated on a falling edge (high->low clock transition).
 *  - For CPHA=1, data are captured on the clock's falling edge and data are
 *    propagated on a rising edge.
 * At CPOL=1 the base value of the clock is one (inversion of CPOL=0)
 *  - For CPHA=0, data are captured on clock's falling edge and data are propagated
 *    on a rising edge.
 *  - For CPHA=1, data are captured on clock's rising edge and data are propagated
 *    on a falling edge.
 */
#define SPI_CPHA     (1<<0)                             /* bit[0]:CPHA, clock phase */
#define SPI_CPOL     (1<<1)                             /* bit[1]:CPOL, clock polarity */

#define SPI_LSB      (0<<2)                             /* bit[2]: 0-LSB */
#define SPI_MSB      (1<<2)                             /* bit[2]: 1-MSB */

#define SPI_MASTER   (0<<3)                             /* SPI master device */
#define SPI_SLAVE    (1<<3)                             /* SPI slave device */

#define SPI_CS_HIGH  (1<<4)                             /* Chipselect active high */
#define SPI_NO_CS    (1<<5)                             /* No chipselect */
#define SPI_3WIRE    (1<<6)                             /* SI/SO pin shared */
#define SPI_READY    (1<<7)                             /* Slave pulls low to pause */

#define SPI_MODE_MASK    (SPI_CPHA | SPI_CPOL | SPI_MSB | SPI_SLAVE | SPI_CS_HIGH | SPI_NO_CS | SPI_3WIRE | SPI_READY)

#define SPI_MODE_0       (0 | 0)                        /* CPOL = 0, CPHA = 0 */
#define SPI_MODE_1       (0 | SPI_CPHA)              /* CPOL = 0, CPHA = 1 */
#define SPI_MODE_2       (SPI_CPOL | 0)                 /* CPOL = 1, CPHA = 0 */
#define SPI_MODE_3       (SPI_CPOL | SPI_CPHA)         /* CPOL = 1, CPHA = 1 */

// 预留 锁对象
#define spi_lock_init(controller) ((controller)->lock_obj)
#define spi_lock(controller)
#define spi_unlock(controller)

struct stm32_spi_configuration {
    uint8_t mode;
    uint8_t data_width;
    uint16_t reserved;
    uint32_t max_hz;
};

struct stm32_spi_controller {
    SPI_HandleTypeDef handle;
    uint8_t mode;
    volatile uint32_t cpt_flag; /*完成标志位*/
    struct {
        GPIO_TypeDef *port;
        uint32_t pin;
    } cs;

    void *lock_obj;
};
struct spi_message {
    const void *send_buf;
    void *recv_buf;
    size_t length;
    struct spi_message *next;
    unsigned cs_take: 1;
    unsigned cs_release: 1;
};

void bsp_SpiConfig(SPI_TypeDef *spi, struct stm32_spi_configuration *cfg);
void bsp_SpiDmaEnable(SPI_TypeDef *spi, uint8_t tx_dma_flag, uint8_t rx_dma_flag);
void bsp_SpiDmaParSet(SPI_TypeDef *spi, DMA_InitTypeDef *tx_cfg, DMA_InitTypeDef *rx_cfg);
void bsp_SpiCsParSet(SPI_TypeDef *spi, GPIO_TypeDef *port, uint32_t pin);
void bsp_InitSpi(SPI_TypeDef *spi, uint8_t it_flag);
HAL_StatusTypeDef stm32_spi_data_trans(SPI_TypeDef *spi, uint8_t *write_buf, uint8_t *read_buf, uint16_t len);
uint32_t stm32_spi_trans(SPI_TypeDef *spi, struct spi_message *msg);


// 扩展函数



struct spi_message *spi_transfer_message(SPI_TypeDef *spi, struct spi_message *message);

/* send data then receive data from SPI device */
uint8_t spi_send_then_recv(SPI_TypeDef *spi,
                           const void *send_buf, size_t send_length,
                           void *recv_buf, size_t recv_length);

uint8_t spi_send_then_send(SPI_TypeDef *spi,
                           const void *send_buf1, size_t send_length1,
                           const void *send_buf2, size_t send_length2);

uint32_t spi_transfer(SPI_TypeDef *spi, const void *send_buf, void *recv_buf, size_t length);

uint8_t spi_sendrecv8(SPI_TypeDef *spi, uint8_t senddata, uint8_t *recvdata);

inline rt_size_t spi_recv(SPI_TypeDef *spi, void *recv_buf, size_t length) {
    return spi_transfer(spi, RT_NULL, recv_buf, length);
}
inline rt_size_t spi_send(SPI_TypeDef *spi,  const void *send_buf, size_t length) {
    return spi_transfer(spi, send_buf, RT_NULL, length);
}
#endif //TX_STM32_F4_DRV_SPI_OS_H

源文件

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-5-3     shchl   first version
 */

#include "drv_spi_os.h"
#include "drv_dma_os.h"
#include "drv_gpio.h"
#include "drv_nvic_os.h"


enum {
    TRANSFER_WAIT,
    TRANSFER_COMPLETE,
    TRANSFER_ERROR
};


enum {
    SPI1_IDX = 0,
    SPI2_IDX = 1,
    SPI3_IDX = 2,
};




static struct stm32_spi_controller controller[SPI_CONTROLLER_NUM] = {0};


static inline int spi_idx_get(SPI_TypeDef *spi) {
#define spi_ret_idx(v) {return v;} break
    switch ((uint32_t) spi) {
        case (uint32_t) SPI1: spi_ret_idx(SPI1_IDX);
        case (uint32_t) SPI2: spi_ret_idx(SPI2_IDX);
        case (uint32_t) SPI3: spi_ret_idx(SPI3_IDX);
    }
#undef spi_ret_idx
    return -1;
}

/**
 * @brief 初始化cs 引脚
 * @param spi
 */
static void spi_cs_pin_init(SPI_TypeDef *spi) {
    int idx;
    idx = spi_idx_get(spi);
    if (idx < 0 || idx >= SPI_CONTROLLER_NUM)return;
    if (controller[idx].cs.port) {
        GPIO_InitTypeDef gpio_init;
        bsp_GpioClkEnable(controller[idx].cs.port); /* 打开GPIO时钟 */
        gpio_init.Mode = GPIO_MODE_OUTPUT_PP;    /* 设置推挽输出 */
        gpio_init.Pull = GPIO_NOPULL;            /* 上下拉电阻不使能 */
        gpio_init.Speed = GPIO_SPEED_HIGH;    /* GPIO速度等级 */
        gpio_init.Pin = controller[idx].cs.pin;
        HAL_GPIO_Init(controller[idx].cs.port, &gpio_init);

        if (controller[idx].mode & SPI_CS_HIGH) {
            HAL_GPIO_WritePin(controller[idx].cs.port, controller[idx].cs.pin, GPIO_PIN_RESET);
        } else {
            HAL_GPIO_WritePin(controller[idx].cs.port, controller[idx].cs.pin, GPIO_PIN_SET);
        }
    }

}

static inline void *stm32_spi_lock_init(struct stm32_spi_controller *control) {
    return spi_lock_init(control);
}

static inline void stm32_spi_lock(struct stm32_spi_controller *control) {
    spi_lock(control);
}

static inline void stm32_spi_unlock(struct stm32_spi_controller *control) {
    spi_unlock(control);
}


/**
 * @brief spi dma tx 默认配置
 * @param dma_tx
 */
static inline void spi_dma_tx_default_set(DMA_HandleTypeDef *dma_tx) {
    /* SPI DMA发送配置(INSTANCE 和 Channel 在外部配置,禁止内部设置) */
    dma_tx->Init.FIFOMode = DMA_FIFOMODE_DISABLE;    /* 禁止FIFO*/
    dma_tx->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; /* 禁止FIFO此位不起作用,用于设置阀值 */
    dma_tx->Init.MemBurst = DMA_MBURST_SINGLE;        /* 禁止FIFO此位不起作用,用于存储器突发 */
    dma_tx->Init.PeriphBurst = DMA_PBURST_SINGLE;        /* 禁止FIFO此位不起作用,用于外设突发 */
    dma_tx->Init.Direction = DMA_MEMORY_TO_PERIPH;    /* 传输方向是从存储器到外设 */
    dma_tx->Init.PeriphInc = DMA_PINC_DISABLE;        /* 外设地址自增禁止 */
    dma_tx->Init.MemInc = DMA_MINC_ENABLE;         /* 存储器地址自增使能 */
    dma_tx->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;     /* 外设数据传输位宽选择字节,即8bit */
    dma_tx->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;     /* 存储器数据传输位宽选择字节,即8bit */
    dma_tx->Init.Mode = DMA_NORMAL;              /* 正常模式 */
    dma_tx->Init.Priority = DMA_PRIORITY_MEDIUM;    /* 优先级中 */
}

static inline void spi_dma_rx_default_set(DMA_HandleTypeDef *dma_rx) {
    /* SPI DMA接收配置(INSTANCE 和 Channel 在外部配置,禁止内部设置) */
    dma_rx->Init.FIFOMode = DMA_FIFOMODE_DISABLE;   /* 禁止FIFO*/
    dma_rx->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;/* 禁止FIFO此位不起作用,用于设置阀值 */
    dma_rx->Init.MemBurst = DMA_MBURST_SINGLE;       /* 禁止FIFO此位不起作用,用于存储器突发 */
    dma_rx->Init.PeriphBurst = DMA_PBURST_SINGLE;       /* 禁止FIFO此位不起作用,用于外设突发 */
    dma_rx->Init.Direction = DMA_PERIPH_TO_MEMORY;   /* 传输方向从外设到存储器 */
    dma_rx->Init.PeriphInc = DMA_PINC_DISABLE;       /* 外设地址自增禁止 */
    dma_rx->Init.MemInc = DMA_MINC_ENABLE;        /* 存储器地址自增使能 */
    dma_rx->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;    /* 外设数据传输位宽选择字节,即8bit */
    dma_rx->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;    /* 存储器数据传输位宽选择字节,即8bit */
    dma_rx->Init.Mode = DMA_NORMAL;             /* 正常模式 */
    dma_rx->Init.Priority = DMA_PRIORITY_MEDIUM;      /* 优先级低 */
}

/**
 * @brief spi 参数设置
 * @param spi
 * @param cfg
 */
void bsp_SpiConfig(SPI_TypeDef *spi, struct stm32_spi_configuration *cfg) {
    int idx;
    idx = spi_idx_get(spi);
    if (idx < 0 || idx >= SPI_CONTROLLER_NUM)return;
    SPI_HandleTypeDef *spi_handle = &(controller[idx].handle);

    if (cfg == NULL) {
        struct stm32_spi_configuration spi_conf;
        {
            spi_conf.mode = SPI_MASTER | SPI_MSB | SPI_MODE_0;
            spi_conf.data_width = 8;
            spi_conf.max_hz = 20 * 1000 * 1000;
        }
        cfg = &spi_conf;
    }
    controller[idx].mode = cfg->mode;
    spi_handle->Instance = spi;
    spi_handle->Init.Mode = cfg->mode & SPI_SLAVE ? SPI_MODE_SLAVE : SPI_MODE_MASTER;
    spi_handle->Init.Direction = cfg->mode & SPI_3WIRE ? SPI_DIRECTION_1LINE : SPI_DIRECTION_2LINES;
    spi_handle->Init.DataSize = cfg->data_width == 8 ? SPI_DATASIZE_8BIT : SPI_DATASIZE_16BIT;
    spi_handle->Init.CLKPhase = cfg->mode & SPI_CPHA ? SPI_PHASE_2EDGE : SPI_PHASE_1EDGE;
    spi_handle->Init.CLKPolarity = cfg->mode & SPI_CPOL ? SPI_POLARITY_HIGH : SPI_POLARITY_LOW;
    spi_handle->Init.FirstBit = cfg->mode & SPI_MSB ? SPI_FIRSTBIT_MSB : SPI_FIRSTBIT_LSB;
    spi_handle->Init.NSS = cfg->mode & SPI_NO_CS ? SPI_NSS_HARD_OUTPUT : SPI_NSS_SOFT;
    uint32_t SPI_APB_CLOCK = HAL_RCC_GetPCLK2Freq();
    if (cfg->max_hz >= SPI_APB_CLOCK / 2) {
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
    } else if (cfg->max_hz >= SPI_APB_CLOCK / 4) {
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
    } else if (cfg->max_hz >= SPI_APB_CLOCK / 8) {
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
    } else if (cfg->max_hz >= SPI_APB_CLOCK / 16) {
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
    } else if (cfg->max_hz >= SPI_APB_CLOCK / 32) {
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
    } else if (cfg->max_hz >= SPI_APB_CLOCK / 64) {
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
    } else if (cfg->max_hz >= SPI_APB_CLOCK / 128) {
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
    } else {
        /*  min prescaler 256 */
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
    }
    spi_handle->Init.TIMode = SPI_TIMODE_DISABLE;
    spi_handle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    spi_handle->State = HAL_SPI_STATE_RESET;

}


/**
 * @brief spi dma 启用设置
 * @param spi
 * @param tx_dma_flag 0: 不启用; 1:启用
 * @param rx_dma_flag 0: 不启用; 1:启用
 */
void bsp_SpiDmaEnable(SPI_TypeDef *spi, uint8_t tx_dma_flag, uint8_t rx_dma_flag) {
    int idx;
    idx = spi_idx_get(spi);
    if (idx < 0 || idx >= SPI_CONTROLLER_NUM)return;

    struct stm32_dma_info *info = dma_info_get((uint32_t) spi);
    if (info == NULL) {
        Error_Handler();
        return;
    }

    if (tx_dma_flag) {
        controller[idx].handle.hdmatx = info->dma_tx;
        info->dma_tx->Parent = &(controller[idx].handle);
    }
    if (rx_dma_flag) {
        controller[idx].handle.hdmarx = info->dma_rx;
        info->dma_rx->Parent = &(controller[idx].handle);
    }
}

/**
 * @brief spi dma 参数配置
 * @param spi
 * @param tx_cfg dma发送 null 使用默认配置
 * @param rx_cfg dma接收 null 使用默认配置
 */
void bsp_SpiDmaParSet(SPI_TypeDef *spi, DMA_InitTypeDef *tx_cfg, DMA_InitTypeDef *rx_cfg) {
    int idx;
    idx = spi_idx_get(spi);
    if (idx < 0 || idx >= SPI_CONTROLLER_NUM)return;
    SPI_HandleTypeDef *spi_handle = &(controller[idx].handle);

    if (spi_handle->hdmatx) {
        if (tx_cfg == NULL) {
            spi_dma_tx_default_set(spi_handle->hdmatx);
        } else {
            spi_handle->hdmatx->Init.FIFOMode = tx_cfg->FIFOMode;    /* 禁止FIFO*/
            spi_handle->hdmatx->Init.FIFOThreshold = tx_cfg->FIFOThreshold; /* 禁止FIFO此位不起作用,用于设置阀值 */
            spi_handle->hdmatx->Init.MemBurst = tx_cfg->MemBurst;        /* 禁止FIFO此位不起作用,用于存储器突发 */
            spi_handle->hdmatx->Init.PeriphBurst = tx_cfg->PeriphBurst;        /* 禁止FIFO此位不起作用,用于外设突发 */
            spi_handle->hdmatx->Init.Direction = tx_cfg->Direction;    /* 传输方向是从存储器到外设 */
            spi_handle->hdmatx->Init.PeriphInc = tx_cfg->PeriphInc;        /* 外设地址自增禁止 */
            spi_handle->hdmatx->Init.MemInc = tx_cfg->MemInc;         /* 存储器地址自增使能 */
            spi_handle->hdmatx->Init.PeriphDataAlignment = tx_cfg->PeriphDataAlignment;     /* 外设数据传输位宽选择字节,即8bit */
            spi_handle->hdmatx->Init.MemDataAlignment = tx_cfg->MemDataAlignment;     /* 存储器数据传输位宽选择字节,即8bit */
            spi_handle->hdmatx->Init.Mode = tx_cfg->Mode;              /* 正常模式 */
            spi_handle->hdmatx->Init.Priority = tx_cfg->Priority;    /* 优先级中 */
        }

    }

    if (spi_handle->hdmarx) {

        if (rx_cfg == NULL) {
            spi_dma_rx_default_set(spi_handle->hdmarx);
        } else {
            spi_handle->hdmarx->Init.FIFOMode = rx_cfg->FIFOMode;    /* 禁止FIFO*/
            spi_handle->hdmarx->Init.FIFOThreshold = rx_cfg->FIFOThreshold; /* 禁止FIFO此位不起作用,用于设置阀值 */
            spi_handle->hdmarx->Init.MemBurst = rx_cfg->MemBurst;        /* 禁止FIFO此位不起作用,用于存储器突发 */
            spi_handle->hdmarx->Init.PeriphBurst = rx_cfg->PeriphBurst;        /* 禁止FIFO此位不起作用,用于外设突发 */
            spi_handle->hdmarx->Init.Direction = rx_cfg->Direction;    /* 传输方向是从存储器到外设 */
            spi_handle->hdmarx->Init.PeriphInc = rx_cfg->PeriphInc;        /* 外设地址自增禁止 */
            spi_handle->hdmarx->Init.MemInc = rx_cfg->MemInc;         /* 存储器地址自增使能 */
            spi_handle->hdmarx->Init.PeriphDataAlignment = rx_cfg->PeriphDataAlignment;     /* 外设数据传输位宽选择字节,即8bit */
            spi_handle->hdmarx->Init.MemDataAlignment = rx_cfg->MemDataAlignment;     /* 存储器数据传输位宽选择字节,即8bit */
            spi_handle->hdmarx->Init.Mode = rx_cfg->Mode;              /* 正常模式 */
            spi_handle->hdmarx->Init.Priority = rx_cfg->Priority;    /* 优先级中 */
        }

    }


}

/**
 * @brief 使能引脚配置
 * @param spi
 * @param port
 * @param pin
 */
void bsp_SpiCsParSet(SPI_TypeDef *spi, GPIO_TypeDef *port, uint32_t pin) {
    int idx;
    idx = spi_idx_get(spi);
    if (idx < 0 || idx >= SPI_CONTROLLER_NUM)return;

    controller[idx].cs.port = port;
    controller[idx].cs.pin = pin;

}




/**
 * @brief 初始化spi
 * @param spi
 */
void bsp_InitSpi(SPI_TypeDef *spi, uint8_t it_flag) {
    int idx;
    idx = spi_idx_get(spi);
    if (idx < 0 || idx >= SPI_CONTROLLER_NUM)return;
    // lock 配置
    controller[idx].lock_obj = stm32_spi_lock_init(&(controller[idx]));

    // cs 配置
    spi_cs_pin_init(spi);
    HAL_SPI_Init(&(controller[idx].handle));
    if (controller[idx].handle.hdmatx) {
        // 启用
        stm32_nvic_common_enable((uint32_t) (controller[idx].handle.hdmatx->Instance), 1, 0);
    }
    if (controller[idx].handle.hdmarx) {
        stm32_nvic_common_enable((uint32_t) (controller[idx].handle.hdmarx->Instance), 1, 0);
    }
    if (it_flag) {
        // 开启中断
        stm32_nvic_common_enable((uint32_t) spi, 2, 0);
    }


}

/**
 * @brief stm32 spi 数据传输
 * @param spi 
 * @param write_buf 
 * @param read_buf 
 * @param len 
 * @return 
 */
HAL_StatusTypeDef stm32_spi_data_trans(SPI_TypeDef *spi, uint8_t *write_buf, uint8_t *read_buf, uint16_t len) {
    HAL_StatusTypeDef state = HAL_ERROR;
    int idx;
    idx = spi_idx_get(spi);
    if (idx < 0 || idx >= SPI_CONTROLLER_NUM)return HAL_ERROR;
    SPI_HandleTypeDef *handle_ptr = &(controller[idx].handle);
    ATOMIC_SET_BIT(controller[idx].cpt_flag, TRANSFER_WAIT);
    // 判断是否为dma方式
    if (write_buf && read_buf) {
        if (handle_ptr->hdmatx && handle_ptr->hdmarx) {
            state = HAL_SPI_TransmitReceive_DMA(handle_ptr, write_buf, read_buf, len);
        } else if (stm32_nvic_common_enabled_check((uint32_t) spi)) {
            state = HAL_SPI_TransmitReceive_IT(handle_ptr, write_buf, read_buf, len);
        } else {
            state = HAL_SPI_TransmitReceive(handle_ptr, write_buf, read_buf, len, 1000);
            controller[idx].cpt_flag = state == HAL_OK ? TRANSFER_COMPLETE : TRANSFER_ERROR;
        }
    } else if (write_buf) {
        if (handle_ptr->hdmatx) {
            state = HAL_SPI_Transmit_DMA(handle_ptr, write_buf, len);
        } else if (stm32_nvic_common_enabled_check((uint32_t) spi)) {
            state = HAL_SPI_Transmit_IT(handle_ptr, write_buf, len);
        } else {
            state = HAL_SPI_Transmit(handle_ptr, write_buf, len, 1000);
            controller[idx].cpt_flag = state == HAL_OK ? TRANSFER_COMPLETE : TRANSFER_ERROR;
        }
    } else if (read_buf) {
        if (handle_ptr->hdmarx) {
            state = HAL_SPI_Receive_DMA(handle_ptr, read_buf, len);
        } else if (stm32_nvic_common_enabled_check((uint32_t) spi)) {
            state = HAL_SPI_Receive_IT(handle_ptr, read_buf, len);
        } else {
            state = HAL_SPI_Receive(handle_ptr, read_buf, len, 1000);
            controller[idx].cpt_flag = state == HAL_OK ? TRANSFER_COMPLETE : TRANSFER_ERROR;
        }
    }

    return state;
}

/**
 * @brief spi 消息传输(带cs)
 * @param spi
 * @param msg 消息
 * @return
 */
uint32_t stm32_spi_trans(SPI_TypeDef *spi, struct spi_message *msg) {
    int idx;
    idx = spi_idx_get(spi);
    if (idx < 0 || idx >= SPI_CONTROLLER_NUM)return 0;
    rt_size_t message_length, already_send_length;
    rt_uint16_t send_length;
    rt_uint8_t *recv_buf;
    const uint8_t *send_buf;
    struct stm32_spi_controller *control = &controller[idx];

    if (msg->cs_take && !(control->mode & SPI_NO_CS)) {
        {
            if (control->mode & SPI_CS_HIGH)
                HAL_GPIO_WritePin(control->cs.port, control->cs.pin, GPIO_PIN_SET);
            else
                HAL_GPIO_WritePin(control->cs.port, control->cs.pin, GPIO_PIN_RESET);

        }
    }
    message_length = msg->length;
    while (message_length) {
        /* the HAL library use uint16 to save the data length */
        if (message_length > 65535) {
            send_length = 65535;
            message_length = message_length - 65535;
        } else {
            send_length = message_length;
            message_length = 0;
        }

        /* calculate the start address */
        already_send_length = msg->length - send_length - message_length;
        send_buf = (uint8_t *) msg->send_buf + already_send_length;
        recv_buf = (uint8_t *) msg->recv_buf + already_send_length;

        stm32_spi_data_trans(spi, (uint8_t *) send_buf, recv_buf, send_length);

        while (control->cpt_flag == TRANSFER_WAIT);

        if (control->cpt_flag == TRANSFER_ERROR) {
            msg->length = 0;
        }
    }

    if (msg->cs_release && !(control->mode & SPI_NO_CS)) {
        {
            if (control->mode & SPI_CS_HIGH)
                HAL_GPIO_WritePin(control->cs.port, control->cs.pin, GPIO_PIN_RESET);
            else
                HAL_GPIO_WritePin(control->cs.port, control->cs.pin, GPIO_PIN_SET);
        }
    }


    return msg->length;
}


__attribute__((used)) void SPI1_IRQHandler(void) {
    TX_INTERRUPT_SAVE_AREA
    TX_DISABLE
    HAL_SPI_IRQHandler(&controller[SPI1_IDX].handle);
    TX_RESTORE
}
//__attribute__((used)) void SPI2_IRQHandler(void) {
//    TX_INTERRUPT_SAVE_AREA
//    TX_DISABLE
//    HAL_SPI_IRQHandler(&controller[SPI2_IDX].handle);
//    TX_RESTORE
//}
//__attribute__((used)) void SPI3_IRQHandler(void) {
//    TX_INTERRUPT_SAVE_AREA
//    TX_DISABLE
//    HAL_SPI_IRQHandler(&controller[SPI3_IDX].handle);
//    TX_RESTORE
//}

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) {
    struct stm32_spi_controller *control = rt_container_of(hspi, struct stm32_spi_controller, handle);
    control->cpt_flag = TRANSFER_COMPLETE;
}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) {
    struct stm32_spi_controller *control = rt_container_of(hspi, struct stm32_spi_controller, handle);
    control->cpt_flag = TRANSFER_COMPLETE;
}

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
    struct stm32_spi_controller *control = rt_container_of(hspi, struct stm32_spi_controller, handle);
    control->cpt_flag = TRANSFER_COMPLETE;
}
/**
  * @brief  SPI error callback.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @retval None
  */
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) {
    // todo 错误记录
    struct stm32_spi_controller *control = rt_container_of(hspi, struct stm32_spi_controller, handle);
    control->cpt_flag = TRANSFER_ERROR;
}

static void spi_lock_get(SPI_TypeDef *spi) {
    int idx;
    idx = spi_idx_get(spi);
    if (idx < 0 || idx >= SPI_CONTROLLER_NUM)return;
    stm32_spi_lock(&controller[idx]);
}

static void spi_lock_put(SPI_TypeDef *spi) {
    int idx;
    idx = spi_idx_get(spi);
    if (idx < 0 || idx >= SPI_CONTROLLER_NUM)return;
    stm32_spi_unlock(&controller[idx]);
}

struct spi_message *spi_transfer_message(SPI_TypeDef *spi, struct spi_message *message) {
    uint32_t result;
    struct spi_message *index;
    /* get first message */
    index = message;
    spi_lock_get(spi);
    /* transmit each SPI message */
    while (index != RT_NULL) {
        /* transmit SPI message */
        result = stm32_spi_trans(spi, index);
        if (result != index->length) {
            LOG_E("transfer error");
            break;
        }
        index = index->next;
    }

    spi_lock_put(spi);
    return index;


}

/**
 * @brief
 * @param spi
 * @param send_buf
 * @param send_length
 * @param recv_buf
 * @param recv_length
 * @return ok : 0  or fail
 */
uint8_t spi_send_then_recv(SPI_TypeDef *spi,
                           const void *send_buf, size_t send_length,
                           void *recv_buf, size_t recv_length) {


    uint8_t result = 0;
    struct spi_message message;
    spi_lock_get(spi);
    {

        /* send data */
        message.send_buf = send_buf;
        message.recv_buf = RT_NULL;
        message.length = send_length;
        message.cs_take = 1;
        message.cs_release = 0;
        message.next = RT_NULL;


        if (stm32_spi_trans(spi, &message) != message.length) {
            LOG_E("SPI device  transfer failed");
            result = 1;
            goto __exit;
        }

        /* recv data */
        message.send_buf = RT_NULL;
        message.recv_buf = recv_buf;
        message.length = recv_length;
        message.cs_take = 0;
        message.cs_release = 1;
        message.next = RT_NULL;
        if (stm32_spi_trans(spi, &message) != message.length) {
            LOG_E("SPI device  transfer failed");
            goto __exit;
        }

        result = RT_EOK;
    }

    __exit:
    spi_lock_put(spi);
    return result;
}

/**
 * @brief
 * @param spi
 * @param send_buf
 * @param send_length
 * @param recv_buf
 * @param recv_length
 * @return ok : 0  or fail
 */
uint8_t spi_send_then_send(SPI_TypeDef *spi, const void *send_buf1, size_t send_length1, const void *send_buf2,
                           size_t send_length2) {
    uint8_t result = 0;
    struct spi_message message;
    spi_lock_get(spi);
    {

        /* send data1 */
        message.send_buf = send_buf1;
        message.recv_buf = RT_NULL;
        message.length = send_length1;
        message.cs_take = 1;
        message.cs_release = 0;
        message.next = RT_NULL;
        if (stm32_spi_trans(spi, &message) != message.length) {
            LOG_E("SPI device  transfer failed");
            result = 1;
            goto __exit;
        }
        /* send data2 */
        message.send_buf = send_buf2;
        message.recv_buf = RT_NULL;
        message.length = send_length2;
        message.cs_take = 0;
        message.cs_release = 1;
        message.next = RT_NULL;

        if (stm32_spi_trans(spi, &message) != message.length) {
            LOG_E("SPI device  transfer failed");
            result = 1;
            goto __exit;
        }
        result = 0;
    }

    __exit:
    spi_lock_put(spi);

    return result;
}

uint32_t spi_transfer(SPI_TypeDef *spi, const void *send_buf, void *recv_buf, size_t length) {
    uint32_t result;
    struct spi_message message;
    spi_lock_get(spi);
    {
        /* initial message */
        message.send_buf = send_buf;
        message.recv_buf = recv_buf;
        message.length = length;
        message.cs_take = 1;
        message.cs_release = 1;
        message.next = RT_NULL;

        /* transfer message */
        if (stm32_spi_trans(spi, &message) != message.length) {
            LOG_E("SPI device  transfer failed");
            result = 0;
            goto __exit;
        }
        result = message.length;
    }

    __exit:
    spi_lock_put(spi);

    return result;
}

uint8_t spi_sendrecv8(SPI_TypeDef *spi, uint8_t senddata, uint8_t *recvdata) {
   return spi_transfer(spi, &senddata, recvdata, 1);
}

SPI的IO驱动

//
// Created by shchl on 2024/3/20.
//
#include "board.h"
#include "drv_nvic_os.h"
#include "drv_dma_os.h"

/**
* @brief SPI MSP Initialization
* This function configures the hardware resources used in this example
* @param hspi: SPI handle pointer
* @retval None
*/
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if(hspi->Instance==SPI1)
    {
        /* USER CODE END SPI1_MspInit 0 */
        /* Peripheral clock enable */
        __HAL_RCC_SPI1_CLK_ENABLE();

        __HAL_RCC_GPIOB_CLK_ENABLE();
        /**SPI1 GPIO Configuration
        PB3     ------> SPI1_SCK
        PB4     ------> SPI1_MISO
        PB5     ------> SPI1_MOSI
        */
        GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        // dma
        if (hspi->hdmatx) {
            dma_clk_enable(hspi->hdmatx);
            HAL_DMA_Init(hspi->hdmatx);
        }
        if (hspi->hdmarx) {
            dma_clk_enable(hspi->hdmarx);
            HAL_DMA_Init(hspi->hdmarx);
        }


    }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi){



    if(hspi->Instance==SPI1)
    {
        __HAL_RCC_SPI1_CLK_DISABLE();
        /**SPI1 GPIO Configuration
        PB3     ------> SPI1_SCK
        PB4     ------> SPI1_MISO
        PB5     ------> SPI1_MOSI
        */
        HAL_GPIO_DeInit(GPIOB,  GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5);
        // dma
        if (hspi->hdmatx) {
            HAL_DMA_DeInit(hspi->hdmatx);
        }
        if (hspi->hdmarx) {
            HAL_DMA_DeInit(hspi->hdmarx);
        }

    }
    
    
}

测试

  1. 说明,如果dma和中断同时打开,底层逻辑优先采用dma的方式

使用DMA的方式,中断关闭(推荐,如果使用dma的话,中断就没有必要打开)

    bsp_SpiConfig(SPI1, NULL);
    bsp_SpiDmaEnable(SPI1, 1, 1);
    bsp_SpiDmaParSet(SPI1,NULL,NULL);
    bsp_SpiCsParSet(SPI1, GPIOB, GPIO_PIN_14);
    bsp_InitSpi(SPI1, 0);

使用DMA的方式。中断打开

    bsp_SpiConfig(SPI1, NULL);
    bsp_SpiDmaEnable(SPI1, 1, 1);
    bsp_SpiDmaParSet(SPI1,NULL,NULL);
    bsp_SpiCsParSet(SPI1, GPIOB, GPIO_PIN_14);
    bsp_InitSpi(SPI1, 1);

使用中断的方式.DMA关闭

    bsp_SpiConfig(SPI1, NULL);
    bsp_SpiDmaEnable(SPI1, 0, 0);
    bsp_SpiDmaParSet(SPI1,NULL,NULL);
    bsp_SpiCsParSet(SPI1, GPIOB, GPIO_PIN_14);
    bsp_InitSpi(SPI1, 1);

使用阻塞的方式

    bsp_SpiConfig(SPI1, NULL);
    bsp_SpiDmaEnable(SPI1, 0, 0);
    bsp_SpiDmaParSet(SPI1,NULL,NULL);
    bsp_SpiCsParSet(SPI1, GPIOB, GPIO_PIN_14);
    bsp_InitSpi(SPI1, 0);

测试例程

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-5-2     shchl   first version
 */
#include "test_inc.h"



struct rt_spi_device *spi_device = RT_NULL;
static rt_err_t w25q128_tx_rx(uint8_t *send, uint16_t send_len, uint8_t *rec, uint16_t rec_len) {
    if (send && rec) {
        return spi_send_then_recv(SPI1, send, send_len, rec, rec_len);
    } else if (send) {
        return spi_send(SPI1, (const void *) send, send_len) == send_len ? RT_EOK : RT_EIO;
    }
    return spi_recv(SPI1, rec, rec_len) == rec_len ? RT_EOK : RT_EIO;
}
uint16_t w25q128_read_deviceID() {
    uint8_t cmd[4] = {0x90, 00, 00, 00};
    uint8_t rec[2];
    if (w25q128_tx_rx(cmd, 4, rec, 2) != RT_EOK) return 0;
    return (uint16_t) (rec[0] << 8 | rec[1]);
}
int spi_dev_tst() {
    LOG_D("issd12:%#x\r\n", w25q128_read_deviceID());
    LOG_D("...............");

    return 0;
}

TX_TST_EXPORT(spi_dev_tst);



结果

在这里插入图片描述

总结

  1. 此版本的驱动,并没有做相关宏定义的显示,所以可以直接通过参数配置来进行切换,如果需要限定的话,可以根据以上代码进行调整。这里只添加了spi1,如果需要其他的spi,需要添加spi硬件部分io,dma配置部分,spi中断部分即可,整体的spi逻辑框架无需修改
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

詩不诉卿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值