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;}breakcase (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_setswitch (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_AREATX_DISABLEHAL_DMA_IRQHandler(&spi1_dma_rx);TX_RESTORE
}void DMA2_Stream3_IRQHandler(void) {TX_INTERRUPT_SAVE_AREATX_DISABLEHAL_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;} breakswitch ((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_idxreturn -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);elseHAL_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);elseHAL_GPIO_WritePin(control->cs.port, control->cs.pin, GPIO_PIN_SET);}}return msg->length;
}__attribute__((used)) void SPI1_IRQHandler(void) {TX_INTERRUPT_SAVE_AREATX_DISABLEHAL_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 ConfigurationPB3     ------> SPI1_SCKPB4     ------> SPI1_MISOPB5     ------> 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);// dmaif (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 ConfigurationPB3     ------> SPI1_SCKPB4     ------> SPI1_MISOPB5     ------> SPI1_MOSI*/HAL_GPIO_DeInit(GPIOB,  GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5);// dmaif (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逻辑框架无需修改

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/685871.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python图形复刻——绘制母亲节花束

各位小伙伴&#xff0c;好久不见&#xff0c;今天学习用Python绘制花束。 有一种爱&#xff0c;不求回报&#xff0c;有一种情&#xff0c;无私奉献&#xff0c;这就是母爱。祝天下妈妈节日快乐&#xff0c;幸福永远&#xff01; 图形展示&#xff1a; 代码展示&#xff1a; …

06.线程同步

互斥锁&#xff08;互斥量&#xff09; 描述 一个进程下的线程是共享资源的&#xff0c;通信便利的同时也造成了许多麻烦&#xff0c;线程程和线程之间如果同时访问一块资源就会出错&#xff0c;所以要引入一个互斥变量给它加锁&#xff0c;让它去协同不同线程程之间的访问&am…

【软件测试】3.开发模型

目录 1.常见的开发模型 1.1瀑布模型 1.2螺旋模型 1.3增量模型和迭代模型 1.4敏捷模型 1.4.1特点&#xff1a; 1.5Scrum模型&#xff08;三个角色和五个重要会议&#xff09; 1.5.1三个角色&#xff1a; 1.5.2Scrum工作流程&#xff08;五个会议&#xff09; 1.6测试模…

Unreal Engine(虚幻引擎)的版本特点

Unreal Engine&#xff08;虚幻引擎&#xff09;是Epic Games开发的游戏引擎&#xff0c;广泛应用于游戏开发、影视制作、建筑设计、虚拟现实等领域。Unreal Engine版本指的是该引擎的发布版本&#xff0c;不同版本之间在功能、性能和稳定性等方面存在差异。北京木奇移动技术有…

【JavaScript】内置对象 - 数组对象 ① ( 数组简介 | 数组创建 | 数组类型检测 )

文章目录 一、数组对象1、数组简介2、数组创建3、数组检测 - Array.isArray() 方法4、数组检测 - instanceof 运算符 Array 数组对象参考文档 : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array 一、数组对象 1、数组简介 在 JavaScr…

【vulhub靶场】Apache 中间件漏洞复现

【vulhub靶场】Apache 中间件漏洞复现 一、Apache HTTPD 换行解析漏洞&#xff08;CVE-2017-15715&#xff09;1. 漏洞详情2. 影响版本3. 漏洞复现 二、Apache多后缀解析漏洞&#xff08;apache_parsing_vulnerability&#xff09;1. 漏洞详情2. 漏洞复现 三、Apache HTTP Serv…

JDK不同版本里中国夏令时时间

什么是夏令时&#xff1f; 夏令时&#xff0c;&#xff08;Daylight Saving Time&#xff1a;DST&#xff09;&#xff0c;也叫夏时制&#xff0c;又称“日光节约时制”和“夏令时间”&#xff0c;是一种为节约能源而人为规定地方时间的制度&#xff0c;在这一制度实行期间所采…

day2_greedyIntervalsLRU/LFU

二、贪心算法之区间调度问题 0.计算一个区间集合中无重复的区间的最大数量(模板) public int intervalSchedule(int[][] intvs) {if (intvs.length 0) return 0;// 按 end 升序排序Arrays.sort(intvs, (a, b) -> Integer.compare(a[1], b[1]));// 至少有一个区间不相交in…

摩菲Murphy显示器显示表 总线编程器维修PV780B

Murphy仪器维修包括&#xff1a;摩菲数字显示器&#xff1b;摩菲监视仪表&#xff1b;摩菲CAN总线控制器等维修 维修故障包括&#xff1a;黑屏、指示灯无显示&#xff0c;触摸屏上电无反应&#xff0c; 上电蓝屏、白屏&#xff0c;通电几分钟后屏幕变为蓝屏&#xff0c;主板故…

java中的oop(三)、构造器、javabean、uml类图、this、继承

!! 有get/set方法的情况基本就是说要搞个私有属性&#xff0c;不直接对外开放&#xff1b; 构造器 Person p new Person(); //其中的Person();就是构造器&#xff1b;---造对象&#xff1b;Constructor–建设者&#xff0c;建造者&#xff1b; 作用 搭配new 创建类的&…

DS:顺序表、单链表的相关OJ题训练(2)

欢迎各位来到 Harper.Lee 的学习世界&#xff01; 博主主页传送门&#xff1a;Harper.Lee的博客主页 想要一起进步的uu欢迎来后台找我哦&#xff01; 一、力扣--141. 环形链表 题目描述&#xff1a;给你一个链表的头节点 head &#xff0c;判断链表中是否有环。如果链表中有某个…

java数据结构之数组系统了解

1.数组介绍 数组就是一个存储数据的容器&#xff0c;容器的长度固定、存储元素的数据类型固定。 跟变量加以区分&#xff1a;变量也可以存储数据&#xff0c;但是只能存一个值。当要存的数据比较多的时候&#xff0c;用变量就不方便了。我们就可以使用数组来存储。 1.1数组…