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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

有哪些软件可以使用云渲染?

随着技术的发展&#xff0c;云渲染已成为动画制作人员与设计师重要的渲染助手。它可结合云端强大的计算机能力&#xff0c;帮助渲染人员高速的完成渲染任务&#xff0c;大幅度节省时间和本地计算资源。它们以用户友好的界面、强大灵活的渲染能力&#xff0c;满足了各类专业渲染…

ESP8266固件烧写

概述 因为手上有块闲置的ESP8266开发板&#xff0c;想着拿来倒腾一下WIFI探针&#xff0c;倒腾了一阵测试成功&#xff0c;博文记录用以备忘 硬件 ESP8266 NodeMCU 环境 Windows 11 步骤 1.下载esp32_win32_msys2_environment_and_toolchain-20181001.zip 2.下载xtensa…

Facebook革命:数字社交的全新篇章

随着互联网的不断普及和科技的飞速发展&#xff0c;社交媒体已经成为现代社会不可或缺的一部分。在众多社交媒体平台中&#xff0c;Facebook以其广泛的用户群体和强大的功能而备受瞩目。然而&#xff0c;Facebook并非止步于现状&#xff0c;而是正在掀起一场数字社交的革命&…

Kafka应用Demo:按主题订阅消费消息

安装环境 Kafka安装可参考官方网站的指导(https://kafka.apache.org/quickstart), 按步骤解压压缩包&#xff0c;修改配置。然后再启动zookeeper和kafka-server即可。 需要注意的一点&#xff1a;如果是在VMware虚拟机上启动的kafka, 需要修改一下server.properties配置文件&am…

vue组件传参数

在使用vue3进行开发的时候&#xff0c;我们一定绕不开的一个技术栈&#xff0c;就是组件传参。接下来我将介绍在vue3中如何运用这项技术。 在组件传参数中&#xff0c;分为两类&#xff0c;父传子参&#xff0c;或子传父参。需要了解的两个方法就是defineProps和defineEmits。…

【快捷部署】022_ZooKeeper(3.5.8)

&#x1f4e3;【快捷部署系列】022期信息 编号选型版本操作系统部署形式部署模式复检时间022ZooKeeper3.5.8Ubuntu 20.04tar包单机2024-05-07 一、快捷部署 #!/bin/bash ################################################################################# # 作者&#xff…

【Linux 命令操作】如何在 Linux 中使用多行注释呢?

文章目录 1. 给代码进行多行注释2. 给代码取消多行注释 1. 给代码进行多行注释 &#x1f427;① 首先用 vim 打开代码&#xff0c;按 Esc进入命令模式(Normal mode)&#xff1b; &#x1f427;② 然后按住 ctrl v 进入列模式&#xff1b; &#x1f427;③ 再通过按 h(左)、j(…

牛客网刷题 | BC80 奇偶统计

目前主要分为三个专栏&#xff0c;后续还会添加&#xff1a; 专栏如下&#xff1a; C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读&#xff01; 初来乍到&#xff0c;如有错误请指出&#xff0c;感谢&#xff01; 描述 任意输入一个正整数…

Databend 开源周报第 143 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 了解 Databend …

后端开发面经系列 -- 滴滴C++一面面经

滴滴C一面面经 公众号&#xff1a;阿Q技术站 来源&#xff1a;https://www.nowcoder.com/feed/main/detail/38cf9704ef084e27903d2204352835ef 1、const在C和C区别&#xff0c;const定义的类成员变量如何初始化&#xff1f; 区别 C中的const&#xff1a; 在C中&#xff0c;c…

STM32单片机ADC功能详解

文章目录 1. ADC概述 2. ADC结构图 3. 引脚定义 4. 转换模式 5. 数据对齐 6. 转换时间 7. 硬件电路 8. STM32使用ADC单/多通道检测数据 1. ADC概述 功能&#xff1a;ADC是一个将模拟信号&#xff08;如电压&#xff09;转换为数字信号的设备。在微控制器中&#xff0c…

Vitis HLS 学习笔记--理解串流Stream(1)

目录 1. 介绍 2. 示例 2.1 代码解析 2.2 串流数据类型 2.3 综合报告 3. 总结 1. 介绍 在Vitis HLS中&#xff0c;hls::stream是一个用于在C/C中进行高级合成的关键数据结构。它类似于C标准库中的std::stream&#xff0c;但是专门设计用于硬件描述语言&#xff08;如Veri…

六级段落匹配

一个段落最多匹配2个句子 一个段落对应&#xff1a;0-2 适当放题 找到三个对应点就可以选 每看三个句子划关键词之后再自己回忆一遍关键词&#xff0c;看了36 37 38 就复述一遍关键词看了39 40 41就又从36开始复述关键词&#xff08;334&#xff09;看到最后一句话就又从头…

Linux实操之常用指令详解

文章目录 vi 和 vimvi 和 vim 基本使用 开机、重启和用户登录注销关机&重启命令用户登录和注销 用户管理基本介绍基本语法细节说明修改密码删除用户查询用户信息指令切换用户查看当前用户/登录用户用户组 实用指令指定运行级别帮助指令文件目录类时间和日期类搜索查找类压缩…

Python | Leetcode Python题解之第74题搜索二维矩阵

题目&#xff1a; 题解&#xff1a; class Solution:def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:row,col len(matrix),len(matrix[0])row_l,row_r 0,row-1while row_l < row_r:m (row_lrow_r)//2if target < matrix[m][0]:row_r m-1…

ICode国际青少年编程竞赛- Python-1级训练场-变量练习

ICode国际青少年编程竞赛- Python-1级训练场-变量练习 1、 a 8 for i in range(8):Dev.step(a)Dev.turnRight()a - 12、 a 3 for i in range(4):Dev.step(a)Dev.turnRight()a a 1 Dev.step(5)3、 a 4 for i in range(4):Dev.step(2)Dev.step(-5)Dev.step(3)Spaceship.…

JVM学习笔记【基础篇:垃圾回收】

自动垃圾回收 C/C的内存管理 ⚫ 在C/C这类没有自动垃圾回收机制的语言中&#xff0c;一个对象如果不再使用&#xff0c;需要手动释放&#xff0c;否则就会出现 内存泄漏。我们称这种释放对象的过程为垃圾回收&#xff0c;而需要程序员编写代码进行回收的方式为手动回收。 ⚫ …

ue引擎游戏开发笔记(34)——建立射击映射,并添加特效

1.需求分析&#xff1a; 准备处理射击系统&#xff0c;首先角色需要能射击&#xff0c;有反馈&#xff0c;先建立角色与控制器之间的映射&#xff0c;并添加简单特效&#xff0c;证明映射已经建立。 2.操作实现&#xff1a; 1.首先常规建立映射流程&#xff0c;具体可参考笔记…

线性表--数据结构设计与操作

单链表 1.单链表的定义&#xff1a; typedef struct LNode{Elemtype data;struct Lnode *next; }LNode ,*LinkList;//单链表的数据结构&#xff08;手写&#xff09; #include<iostream> #include<vector> #include<algorithm>typedef int TypeElem; //单链表…

如何解决3D模型变黑或贴图不显示的问题---模大狮模型网

在进行3D建模和视觉渲染时&#xff0c;经常会遇到模型表面变黑或贴图不显示的问题&#xff0c;这可能严重影响最终视觉效果的质量。这些问题通常与材质设置、光照配置或文件路径错误有关。本文将探讨几种常见原因及其解决方法&#xff0c;帮助3D艺术家和开发者更有效地处理这些…