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

news2024/11/20 20:19:05

前言

  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逻辑框架无需修改

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【AIGC】本地部署 ollama + open-webui

在之前的篇章《【AIGC】本地部署 ollama(gguf) 与项目整合》中我们已经使用 ollama 部署了一个基于预量化&#xff08;gguf&#xff09;的 Qwen1.5 模型&#xff0c;这个模型除了提供研发使用外&#xff0c;我还想提供给公司内部使用&#xff0c;因此还需要一个 ui 交互界面。 …

2003-2022年各省对外直接投资存量/省对外直接投资流量/省OFDI流量/省OFDI存量数据

2003-2022年各省对外直接投资存量、省对外直接投资流量、省OFDI流量、省OFDI存量数据 1、时间&#xff1a;2003-2022年 2、来源&#xff1a;对外直接投资公报 3、范围&#xff1a;31省 4、指标&#xff1a;省对外直接投资流量/OFDI流量、省对外直接投资存量/OFDI存量 5、指…

OpenCV(三)—— 车牌筛选

本篇文章要介绍如何对从候选车牌中选出最终进行字符识别的车牌。 无论是通过 Sobel 还是 HSV 计算出的候选车牌都可能不止一个&#xff0c;需要对它们进行评分&#xff0c;选出最终要进行识别的车牌。这个过程中会用到两个理论知识&#xff1a;支持向量机和 HOG 特征。 1、支…

爬虫自动化之drissionpage实现随时切换代理ip

目录 一、视频二、dp首次启动设置代理三、dp利用插件随时切换代理一、视频 视频直接点击学习SwitchyOmega插件使用其它二、dp首次启动设置代理 from DrissionPage import ChromiumPage, ChromiumOptions from loguru

MySQL与金蝶云星空对接集成执行查询语句-v2打通销售退货新增V1

MySQL与金蝶云星空对接集成执行查询语句-v2打通销售退货新增V1 数据源系统:MySQL mysql是一个关系数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;所谓的关系型数据库&#xff0c;是建立在关系模型基础上的数据库&#xff0c;借助于集合代数等数学概念和方法来处理数…

深度解析 Spring 源码:探寻Bean的生命周期

文章目录 一、 Bean生命周期概述二、Bean生命周期流程图三、Bean生命周期验证3.1 代码案例3.2 执行结果 四、Bean生命周期源码4.1 setBeanName()4.2 setBeanFactory()4.3 setApplicationContext()4.4 postProcessBeforeInitialization()4.5 afterPropertiesSet()4.6 postProces…

npm安装依赖报错解决办法

项目场景&#xff1a; 安装gitee上的开源vue3TS项目&#xff0c;npm安装依赖报错 问题描述 克隆项目到VSCode之后&#xff0c;使用npm install安装依赖&#xff0c;报错 npm install npm ERR! code ENOENT npm ERR! syscall open npm ERR! path Y:\WebStudyBlog\MovieWeb/p…

【Linux】学习笔记

文章目录 [toc]第一章&#xff1a;基础篇01|课程介绍02|内容综述03|什么是Linux04|Linux的内核版本及常见发行版内核版本发行版本Red Hat Enterprise LinuxFedoraCentOSDebianUbuntu 05|安装VirtualBox虚拟机VirtualBox下载url 06|在虚拟机中安装Linux系统Linux安装镜像下载 07…

基于OpenCv的图像傅里叶变换

⚠申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xff0c;请标注链接地址。 全文共计3077字&#xff0c;阅读大概需要3分钟 &#x1f308;更多学习内容&#xff0c; 欢迎&#x1f44f;关注&#x1f440;【文末】我的个人微信公众号&#xf…

【C++并发编程】(四)条件变量

文章目录 &#xff08;四&#xff09;条件变量 &#xff08;四&#xff09;条件变量 条件变量&#xff08;Condition Variable&#xff09;用于线程间的同步&#xff0c;允许一个或多个线程在特定条件不满足时等待&#xff0c;并在条件满足时被其他线程唤醒。C标准库中提供了的…

D3CTF2024

文章目录 前言notewrite_flag_where【复现】D3BabyEscapePwnShell 前言 本次比赛笔者就做出两道简单题&#xff0c;但队里师傅太快了&#xff0c;所以也没我啥事。然后 WebPwn 那题命令行通了&#xff0c;但是浏览器不会调试&#xff0c;然后就简单记录一下。 note 只开了 N…

【热门话题】如何构建具有高度扩展性的系统

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 如何构建具有高度扩展性的系统引言一、理解扩展性1.1 扩展性的定义1.2 扩展性的…

3GPP官网下载协议步骤

1.打开官网 https://www.3gpp.org/ 2.点击 3.在界面选择要找的series&#xff0c;跳转到查找界面 以V2X通信协议为例&#xff0c;论文中通常会看到许多应用&#xff1a; [7] “Study on evaluation methodology of new Vehicle-to-Everything (V2X) use cases for LTE and NR…

2-手工sql注入(进阶篇) sqlilabs靶场1-4题

1. 阅读&#xff0c;学习本章前&#xff0c;可以先去看看基础篇&#xff1a;1-手工sql注入(基础篇)-CSDN博客 2. 本章通过对sqlilabs靶场的实战&#xff0c;关于sqlilabs靶场的搭建&#xff1a;Linux搭建靶场-CSDN博客 3. 本章会使用到sqlmap&#xff0c;关于sqlmap的命令&…

C 深入指针(2)

目录 1 野指针 1.1 成因 1.2 如何规避野指针 2 assert 断言 2.1 用法 2.2 assert 的优点 2.1 assert 的缺点 3 小注解 3.1 Debug 和 Release 1 野指针 【概念】&#xff1a; 野指针就是指针指向的位置是不可知的&#xff08;随机的、不正确的、没有明确限制的&#…

解决windows下无法安装Hyper-V

在windows中打开hyper-v的办法如下&#xff1a;&#xff08;但不适用无法安装hyper-v的windows系统如win10家庭版&#xff09; 通过「控制面板」是启用 Hyper-V 最直接的方法&#xff1a; 1 使用Windows R快捷键打开「运行」对话框&#xff0c;执行appwiz.cpl以打开「控制面…

关于win平台c语言引入开源库的问题与解决

许久不写博客&#xff0c;五一还在加班&#xff0c;就浅浅写一篇吧 最近除了做物联网平台 还对网关二次开发程序做了修改&#xff0c;网关的二次开发去年年底的时候做过&#xff0c;但是当时的逻辑不是十分完善&#xff0c;差不多已经过了半年了&#xff0c;很多细节已经忘记了…

Java--方法的使用

1.1什么是方法 方法顾名思义就是解决问题的办法&#xff0c;在程序员写代码的时候&#xff0c;会遇到很多逻辑结构一样&#xff0c;解决相同问题时&#xff0c;每次都写一样的代码&#xff0c;这会使代码看起来比较绒余&#xff0c;代码量也比较多&#xff0c;为了解决这个问题…

VBA 根据表格指定列拆分多sheet

一. 需求 ⏹ 根据部分列&#xff0c;拆分数据到多个sheet页 二. 代码 ⏹ 重点代码摘要 CreateObject("scripting.dictionary")&#xff1a;创建一个字典对象&#xff0c;相当于Java中的MapDim aRef() As String&#xff1a;定义一个存储字符串类型的数组ReDim aRe…

Linux学习之IP协议

前言&#xff1a; 在学习IP协议i前&#xff0c;我们其实知道网络协议栈是一层层的&#xff0c;上层封装好之后就传给下层&#xff0c;对于我们治安学习到的TCP协议&#xff0c;在对数据进行封装之后&#xff0c;并不是直接就将数据进行传输&#xff0c;而是交给下一层网络层进…