增加BSP文件

This commit is contained in:
许晟昊 2025-04-28 12:52:42 +08:00
parent c9dc76f048
commit 8cc4b48b5e
20 changed files with 1999 additions and 1 deletions

View File

@ -1,5 +1,10 @@
# 驱动列表 # 目录说明
手册:驱动文件对应的芯片手册
bsp部分驱动中用到的底层实现
# 驱动列表
| 驱动 | 分类 | 驱动方式 | 功能 | | 驱动 | 分类 | 驱动方式 | 功能 |
| ------------ | -------- | -------- | ------------------- | | ------------ | -------- | -------- | ------------------- |

76
bsp/gpios.c Normal file
View File

@ -0,0 +1,76 @@
#include "gpios.h"
#include "gpio.h"
/**
* @brief GPIO引脚为高电平
* @param {gpio_t} gpio - GPIO对象
* @note: GPIO引脚为高电平
*/
static void _set(gpio_t gpio)
{
GPIO_SET(gpio.port, gpio.pin);
}
/**
* @brief GPIO引脚为低电平
* @param {gpio_t} gpio - GPIO对象
* @note: GPIO引脚为低电平
*/
static void _reset(gpio_t gpio)
{
GPIO_RESET(gpio.port, gpio.pin);
}
/**
* @brief GPIO引脚状态
* @param {gpio_t} gpio - GPIO对象
* @note: GPIO引脚的状态
*/
static void _toggle(gpio_t gpio)
{
GPIO_TOGGLE(gpio.port, gpio.pin);
}
/**
* @brief GPIO引脚状态
* @param {gpio_t} gpio - GPIO对象
* @return {*} - GPIO引脚当前状态01
* @note: GPIO引脚的状态01
*/
static uint8_t _read(gpio_t gpio)
{
return (uint8_t)GPIO_READ(gpio.port, gpio.pin);
}
/**
* @brief GPIO对象
* @param {GPIO_TypeDef} *port - GPIO寄存器指针
* @param {uint16_t} pin -
* @return {gpio_t *} - GPIO对象指针
* @note: GPIO对象GPIO功能
*/
gpio_t *gpio_create(GPIO_TypeDef *port, uint16_t pin)
{
gpio_t *gpio = (gpio_t *)osel_mem_alloc(sizeof(gpio_t));
DBG_ASSERT(gpio != NULL __DBG_LINE);
gpio->port = port;
gpio->pin = pin;
gpio->set = _set;
gpio->reset = _reset;
gpio->toggle = _toggle;
gpio->read = _read;
return gpio;
}
/**
* @brief GPIO对象
* @param {gpio_t} *gpio - GPIO对象指针
* @return {*}
* @note: GPIO对象使
*/
void gpio_free(gpio_t *gpio)
{
if (gpio != NULL)
{
osel_mem_free(gpio);
}
}

144
bsp/gpios.h Normal file
View File

@ -0,0 +1,144 @@
/**
* @file gpios.h
* @brief Header file for GPIO configuration and control.
*
* This file contains the declarations and definitions for GPIO configuration and control functions.
*
* @author xxx
* @date 2023-12-27 14:44:03
* @version 1.0
* @copyright Copyright (c) 2024 by xxx, All Rights Reserved.
*/
#ifndef __GPIOS_H__
#define __GPIOS_H__
#include "lib.h"
#include "main.h"
/**
* @brief Set the GPIO pin to high.
*
* @param port The GPIO port.
* @param pin The GPIO pin.
*/
#define GPIO_SET(port, pin) (LL_GPIO_SetOutputPin(port, pin))
/**
* @brief Set the GPIO pin to low.
*
* @param port The GPIO port.
* @param pin The GPIO pin.
*/
#define GPIO_RESET(port, pin) (LL_GPIO_ResetOutputPin(port, pin))
/**
* @brief Toggle the state of the GPIO pin.
*
* @param port The GPIO port.
* @param pin The GPIO pin.
*/
#define GPIO_TOGGLE(port, pin) (LL_GPIO_TogglePin(port, pin))
/**
* @brief Read the state of the GPIO pin.
*
* @param port The GPIO port.
* @param pin The GPIO pin.
* @return The state of the GPIO pin (1 if high, 0 if low).
*/
#define GPIO_READ(port, pin) (LL_GPIO_IsInputPinSet(port, pin))
/**
* @brief Set the GPIO pin as input.
*
* @param port The GPIO port.
* @param pin The GPIO pin.
*/
#define GPIO_SET_INPUT(port, pin) (LL_GPIO_SetPinMode(port, pin, LL_GPIO_MODE_INPUT))
/**
* @brief Set the GPIO pin as output.
*
* @param port The GPIO port.
* @param pin The GPIO pin.
*/
#define GPIO_SET_OUTPUT(port, pin) \
do \
{ \
LL_GPIO_SetPinMode(port, pin, LL_GPIO_MODE_OUTPUT); \
} while (0)
/**
* @brief Set the GPIO pin as alternate function.
*
* @param port The GPIO port.
* @param pin The GPIO pin.
*/
#define GPIO_SET_ALTERNATE(port, pin) (LL_GPIO_SetPinMode(port, pin, LL_GPIO_MODE_ALTERNATE))
/**
* @brief Set the GPIO pin as analog.
*
* @param port The GPIO port.
* @param pin The GPIO pin.
*/
#define GPIO_SET_ANALOG(port, pin) \
do \
{ \
LL_GPIO_SetPinMode(port, pin, LL_GPIO_MODE_ANALOG); \
} while (0)
/**
* @brief Structure representing a GPIO pin.
*/
typedef struct GPIO
{
GPIO_TypeDef *port; ///< The GPIO port.
uint16_t pin; ///< The GPIO pin.
/**
* @brief Set the GPIO pin to high.
*
* @param gpio The GPIO pin.
*/
void (*set)(struct GPIO gpio);
/**
* @brief Set the GPIO pin to low.
*
* @param gpio The GPIO pin.
*/
void (*reset)(struct GPIO gpio);
/**
* @brief Toggle the state of the GPIO pin.
*
* @param gpio The GPIO pin.
*/
void (*toggle)(struct GPIO gpio);
/**
* @brief Read the state of the GPIO pin.
*
* @param gpio The GPIO pin.
* @return The state of the GPIO pin (1 if high, 0 if low).
*/
uint8_t (*read)(struct GPIO gpio);
} gpio_t;
/**
* @brief Create a GPIO pin.
*
* @param port The GPIO port.
* @param pin The GPIO pin.
* @return The created GPIO pin.
*/
extern gpio_t *gpio_create(GPIO_TypeDef *port, uint16_t pin);
/**
* @brief Free the memory allocated for a GPIO pin.
*
* @param gpio The GPIO pin to free.
*/
extern void gpio_free(gpio_t *gpio);
#endif ///< __GPIOS_H__

669
bsp/i2cs.c Normal file
View File

@ -0,0 +1,669 @@
#include "i2cs.h"
#include "main.h"
static inline void delay(i2c_t *handle); // 延时函数
static inline void _ack(i2c_t *handle); // 应答
static inline void _nack(i2c_t *handle); // 非应答
/**
* @brief I2C总线
* @param {i2c_t} *handle - I2C总线句柄
* @note: I2C总线的操作线
*/
static void _start(i2c_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
// 获取gpios指针
i2c_gpio_group_t *gpios = &handle->gpios;
// 获取scl指针
gpio_t *scl = gpios->scl;
// 获取sda指针
gpio_t *sda = gpios->sda;
// 设置sda
gpios->sda->set(*sda);
// 设置scl
gpios->scl->set(*scl);
// 延时
delay(handle);
// 重置sda
gpios->sda->reset(*sda);
// 延时
delay(handle);
// 重置scl
gpios->scl->reset(*scl);
// 延时
delay(handle);
}
/**
* @brief I2C总线
* @param {i2c_t} *handle - I2C总线句柄
* @note: I2C总线的操作线
*/
static void _stop(i2c_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
i2c_gpio_group_t *gpios = &handle->gpios;
gpio_t *scl = gpios->scl;
gpio_t *sda = gpios->sda;
gpios->scl->reset(*scl);
gpios->sda->reset(*sda);
delay(handle);
gpios->scl->set(*scl);
gpios->sda->set(*sda);
delay(handle);
}
/**
* @brief
* @param {i2c_t} *handle - I2C总线句柄
* @return {BOOL} - TRUEFALSE
* @note: I2C总线上发送的应答信号
*/
static BOOL _wait_ack(i2c_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
uint8_t count = 0;
i2c_gpio_group_t *gpios = &handle->gpios;
gpio_t *scl = gpios->scl;
gpio_t *sda = gpios->sda;
gpios->sda->set(*sda);
gpios->scl->set(*scl);
delay(handle);
while (gpios->sda->read(*sda))
{
count++;
if (count > 250)
{
_stop(handle);
return FALSE;
}
}
gpios->scl->reset(*scl);
delay(handle);
return TRUE;
}
/**
* @brief
* @param {i2c_t} *handle - I2C总线句柄
* @param {BOOL} ack -
* @return {uint8_t} -
* @note: I2C总线上读取一个字节
*/
static uint8_t _read_byte(i2c_t *handle, BOOL ack)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
uint8_t i = 0, receive = 0;
i2c_gpio_group_t *gpios = &handle->gpios;
gpio_t *scl = gpios->scl;
gpio_t *sda = gpios->sda;
for (i = 0; i < 8; i++)
{
gpios->sda->set(*sda);
gpios->scl->set(*scl);
receive <<= 1;
delay(handle);
if (gpios->sda->read(*sda))
receive++;
gpios->scl->reset(*scl);
delay(handle);
}
if (TRUE == ack)
{
_ack(handle);
}
else
{
_nack(handle);
}
return receive;
}
/**
* @brief I2C总线上
* @param {i2c_t} *handle I2C总线的句柄
* @param {uint8_t} data
* @return {*}
* @note: I2C总线上发送一个字节的数据1SDA为1SDA为0SCL为11msSCL为01msSDA为1
*/
static void _write_byte(i2c_t *handle, uint8_t data)
{
// 定义变量i
uint8_t i = 0;
// 断言参数handle不为空
DBG_ASSERT(handle != NULL __DBG_LINE);
// 定义变量gpios
i2c_gpio_group_t *gpios = &handle->gpios;
// 定义变量scl
gpio_t *scl = gpios->scl;
// 定义变量sda
gpio_t *sda = gpios->sda;
// 遍历每一位
for (i = 0; i < 8; i++)
{
// 如果data的最低位为1
if (data & 0x80)
{
// 设置sda的状态为1
gpios->sda->set(*sda);
}
// 否则设置sda的状态为0
else
{
// 设置sda的状态为0
gpios->sda->reset(*sda);
}
// 设置scl的状态为1
gpios->scl->set(*scl);
// 延时1ms
delay(handle);
// 将data右移1位
data <<= 1;
// 设置scl的状态为0
gpios->scl->reset(*scl);
// 延时1ms
delay(handle);
// 如果i等于7
if (i == 7)
{
// 设置sda的状态为1
gpios->sda->set(*sda);
}
}
}
/**
* @brief I2C总线上
* @param {i2c_t} *handle I2C总线的句柄
* @param {uint16_t} data
* @return {*}
* @note: I2C总线上发送一个字节的数据1SDA为1SDA为0SCL为11msSCL为01msSDA为1
*/
static void _write_word(i2c_t *handle, uint16_t data)
{
// 循环写入2个字节
for (uint8_t i = 0; i < 2; i++)
{
// 将data的第i个字节写入i2c接口
_write_byte(handle, (uint8_t)(data >> (8 * i)));
// 等待ACK
_wait_ack(handle);
}
}
/**
* @brief I2C总线设备
* @param {i2c_gpio_group_t} gpios I2C总线的GPIO配置
* @param {uint16_t} delay_ticks I2C总线的延时参数
* @return {i2c_t *} I2C总线设备句柄
* @note: I2C总线设备i2c_t结构体gpios和delay_ticks的内存地址复制到handle结构体中handle结构体定义了startstopwait_ackread_bytewrite_byte和write_word函数handle结构体
*/
i2c_t *i2c_create(i2c_gpio_group_t gpios, uint16_t delay_ticks)
{
// 创建一个i2c_t结构体
i2c_t *handle = (i2c_t *)osel_mem_alloc(sizeof(i2c_t));
// 将gpios的内存地址复制到handle结构体中
osel_memcpy((uint8_t *)&handle->gpios, (uint8_t *)&gpios, sizeof(i2c_gpio_group_t));
// 将delay_ticks的内存地址复制到handle结构体中
handle->delay_ticks = delay_ticks;
// 创建一个start函数
handle->interface.start = _start;
// 创建一个stop函数
handle->interface.stop = _stop;
// 创建一个wait_ack函数
handle->interface.wait_ack = _wait_ack;
// 创建一个read_byte函数
handle->interface.read_byte = _read_byte;
// 创建一个write_byte函数
handle->interface.write_byte = _write_byte;
// 创建一个write_word函数
handle->interface.write_word = _write_word;
handle->dead_count = 0;
// 返回handle结构体
return handle;
}
/**
* @brief I2C器件地址
* @param {i2c_t} *handle
* @param {uint8_t} w_address
* @param {uint8_t} r_address
* @return {*}
* @note
*/
void i2c_dma_set_address(i2c_t *handle, uint8_t w_address, uint8_t r_address)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
handle->w_address = w_address;
handle->r_address = r_address;
}
/**
* @brief I2C总线设备
* @param {i2c_t} *handle I2C总线设备句柄
* @return {*}
* @note: I2C总线设备handle是否为空GPIOhandle的内存
*/
void i2c_free(i2c_t *handle)
{
// 如果handle不为空则释放所有的gpio
if (NULL != handle)
{
gpio_free(handle->gpios.scl);
gpio_free(handle->gpios.sda);
osel_mem_free(handle);
}
}
/**
* @brief I2C DMA TX回调函数
* @param {i2c_t} handle
* @return {*}
* @note
*/
void i2c_dma_callback(i2c_t *handle)
{
// 检查输入参数是否为空
DBG_ASSERT(handle != NULL __DBG_LINE);
// 清除传输完成标志位
if (handle->dma_tx_cb != NULL)
{
handle->dma_tx_cb(handle);
}
if (handle->dma_rx_cb != NULL)
{
handle->dma_rx_cb(handle);
}
}
#if defined(STM32L4xx_LL_I2C_H)
static void i2c_reset(i2c_t *handle);
static BOOL _read_mem_dma(i2c_t *handle, uint16_t mem_address, uint16_t mem_addsize, uint8_t *data, uint16_t size);
static BOOL _write_mem_dma(i2c_t *handle, uint16_t mem_address, uint16_t mem_addsize, uint8_t *data, uint16_t size);
/**
* @brief I2C总线设备 DMA
* @param {I2C_TypeDef} *i2c
* @param {DMA_TypeDef} *dma
* @param {uint16_t} rxsize
* @param {uint32_t} dma_rx_channel
* @param {uint16_t} txsize
* @param {uint32_t} dma_tx_channel
* @return {*}
* @note
*/
i2c_t *i2c_create_dma(I2C_TypeDef *i2c, DMA_TypeDef *dma, uint16_t rxsize, uint32_t dma_rx_channel,
i2cs_dma_callback *dma_rx_cb, uint16_t txsize, uint32_t dma_tx_channel, i2cs_dma_callback *dma_tx_cb)
{
i2c_t *handle = (i2c_t *)osel_mem_alloc(sizeof(i2c_t));
handle->i2c = i2c;
handle->dma = dma;
handle->dma_rx_channel = dma_rx_channel;
handle->dma_tx_channel = dma_tx_channel;
handle->rxbuf = (uint8_t *)osel_mem_alloc(rxsize);
handle->txbuf = (uint8_t *)osel_mem_alloc(txsize);
handle->rxsize = rxsize;
handle->txsize = txsize;
handle->tx_dma_ok = TRUE;
handle->interface.write_mem_dma = _write_mem_dma;
handle->interface.read_mem_dma = _read_mem_dma;
if (dma_rx_cb != NULL)
{
handle->dma_rx_cb = dma_rx_cb;
}
if (dma_tx_cb != NULL)
{
handle->dma_tx_cb = dma_tx_cb;
}
LL_DMA_DisableChannel(dma, dma_tx_channel);
LL_DMA_DisableChannel(dma, dma_rx_channel);
// TX
uint8_t *pTransmitBuffer = handle->txbuf;
LL_DMA_ConfigTransfer(dma, dma_tx_channel, LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PRIORITY_HIGH | LL_DMA_MODE_NORMAL | LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);
LL_DMA_ConfigAddresses(dma, dma_tx_channel, (uint32_t)pTransmitBuffer, (uint32_t)LL_I2C_DMA_GetRegAddr(i2c, LL_I2C_DMA_REG_DATA_TRANSMIT), LL_DMA_GetDataTransferDirection(dma, dma_tx_channel));
LL_DMA_SetPeriphRequest(dma, dma_tx_channel, LL_DMA_REQUEST_3);
// RX
uint8_t *pReceiveBuffer = handle->rxbuf;
LL_DMA_ConfigTransfer(dma, dma_rx_channel, LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_PRIORITY_HIGH | LL_DMA_MODE_NORMAL | LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);
LL_DMA_ConfigAddresses(dma, dma_rx_channel, (uint32_t)LL_I2C_DMA_GetRegAddr(i2c, LL_I2C_DMA_REG_DATA_RECEIVE), (uint32_t)pReceiveBuffer, LL_DMA_GetDataTransferDirection(dma, dma_rx_channel));
LL_DMA_SetPeriphRequest(dma, dma_rx_channel, LL_DMA_REQUEST_3);
LL_DMA_EnableIT_TC(dma, dma_tx_channel);
LL_DMA_EnableIT_TE(dma, dma_tx_channel);
LL_DMA_EnableIT_TC(dma, dma_rx_channel);
LL_DMA_EnableIT_TE(dma, dma_rx_channel);
LL_I2C_EnableDMAReq_TX(i2c);
LL_I2C_EnableDMAReq_RX(i2c);
LL_I2C_Enable(i2c);
return handle;
}
/**
* @brief 使DMA从特定内存地址读取数据
* @param {i2c_t} *handle i2c_t结构体I2C的配置信息
* @param {uint16_t} dev_address 7
* @param {uint16_t} mem_address
* @param {uint16_t} mem_addsize
* @param {uint8_t} *data
* @param {uint16_t} size
* @return {*}
* @note
*/
static BOOL _read_mem_dma(i2c_t *handle, uint16_t mem_address, uint16_t mem_addsize, uint8_t *data, uint16_t size)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
DBG_ASSERT(data != NULL __DBG_LINE);
if (LL_I2C_IsActiveFlag_BUSY(handle->i2c) == 1)
{
i2c_reset(handle); // xsh:重置I2C,修复一段时间后无法读写的问题
return FALSE;
}
uint16_t count = 2000;
handle->txsize = 0;
handle->tx_dma_ok = FALSE;
handle->rx_dma_ok = FALSE;
for (uint8_t i = mem_addsize; i > 0; i--)
{
handle->txbuf[handle->txsize++] = (uint8_t)(mem_address >> (8 * (i - 1)));
}
LL_DMA_SetDataLength(handle->dma, handle->dma_tx_channel, handle->txsize);
LL_DMA_EnableChannel(handle->dma, handle->dma_tx_channel);
LL_I2C_HandleTransfer(handle->i2c, handle->w_address, LL_I2C_ADDRSLAVE_7BIT, handle->txsize, LL_I2C_MODE_SOFTEND, LL_I2C_GENERATE_START_WRITE);
count = 2000;
while (!handle->tx_dma_ok)
{
if (count-- == 0)
{
handle->tx_dma_ok = TRUE;
return FALSE;
}
}
count = 2000;
while (LL_I2C_IsActiveFlag_TC(handle->i2c) != 1)
{
if (count-- == 0)
{
handle->tx_dma_ok = TRUE;
return FALSE;
}
}
handle->tx_dma_ok = FALSE;
handle->rx_dma_ok = FALSE;
handle->rxsize = size;
osel_memset(handle->rxbuf, 0, handle->rxsize);
LL_DMA_DisableChannel(handle->dma, handle->dma_tx_channel);
LL_DMA_SetDataLength(handle->dma, handle->dma_rx_channel, handle->rxsize);
LL_DMA_EnableChannel(handle->dma, handle->dma_rx_channel);
LL_I2C_HandleTransfer(handle->i2c, handle->r_address, LL_I2C_ADDRSLAVE_7BIT, handle->rxsize, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_RESTART_7BIT_READ);
count = 2000;
while (!LL_I2C_IsActiveFlag_STOP(handle->i2c))
{
if (count-- == 0)
{
handle->tx_dma_ok = TRUE;
return FALSE;
}
}
LL_DMA_DisableChannel(handle->dma, handle->dma_rx_channel);
LL_I2C_ClearFlag_STOP(handle->i2c);
osel_memcpy(data, handle->rxbuf, handle->rxsize);
return TRUE;
}
/**
* @brief 使DMA将数据写入特定内存地址
* @param {i2c_t} *handle i2c_t结构体I2C的配置信息
* @param {uint16_t} dev_address 7
* @param {uint16_t} mem_address
* @param {uint16_t} mem_addsize
* @param {uint8_t} *data
* @param {uint16_t} size
* @return {*}
* @note
*/
static BOOL _write_mem_dma(i2c_t *handle, uint16_t mem_address, uint16_t mem_addsize, uint8_t *data, uint16_t size)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
DBG_ASSERT(data != NULL __DBG_LINE);
uint16_t count = 2000;
if (LL_I2C_IsActiveFlag_BUSY(handle->i2c) == 1)
{
i2c_reset(handle); // xsh:重置I2C,修复一段时间后无法读写的问题
return FALSE;
}
handle->txsize = 0;
handle->tx_dma_ok = FALSE;
for (uint8_t i = mem_addsize; i > 0; i--)
{
handle->txbuf[handle->txsize++] = (uint8_t)(mem_address >> (8 * (i - 1)));
}
osel_memcpy(&handle->txbuf[handle->txsize], data, size);
handle->txsize += size;
LL_DMA_SetDataLength(handle->dma, handle->dma_tx_channel, handle->txsize);
LL_DMA_EnableChannel(handle->dma, handle->dma_tx_channel);
LL_I2C_HandleTransfer(handle->i2c, handle->w_address, LL_I2C_ADDRSLAVE_7BIT, handle->txsize, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_WRITE);
count = 2000;
while (!handle->tx_dma_ok)
{
if (count-- == 0)
{
handle->tx_dma_ok = TRUE;
return FALSE;
}
}
count = 2000;
while (!LL_I2C_IsActiveFlag_STOP(handle->i2c))
{
if (count-- == 0)
{
handle->tx_dma_ok = TRUE;
return FALSE;
}
}
LL_DMA_DisableChannel(handle->dma, handle->dma_tx_channel);
LL_I2C_ClearFlag_STOP(handle->i2c);
return TRUE;
}
/**
* @brief I2C重置
* @param {I2C_TypeDef} *I2Cx
* @return {*}
* @note I2C总线死锁问题
*/
static void i2c_reset(i2c_t *handle)
{
LL_I2C_Disable(handle->i2c);
LL_I2C_Enable(handle->i2c);
handle->dead_count++;
}
/**
* @brief I2C
* @param {i2c_t} *handle
* @return {*}
* @note
*/
void i2c_ev_callback(i2c_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
if (LL_I2C_IsActiveFlag_ADDR(handle->i2c))
{
/* Verify the Address Match with the OWN Slave address */
if (LL_I2C_GetAddressMatchCode(handle->i2c) == handle->w_address || LL_I2C_GetAddressMatchCode(handle->i2c) == handle->r_address)
{
/* Verify the transfer direction, a write direction, Slave enters receiver mode */
if (LL_I2C_GetTransferDirection(handle->i2c) == LL_I2C_DIRECTION_WRITE)
{
/* Clear ADDR flag value in ISR register */
LL_I2C_ClearFlag_ADDR(handle->i2c);
/* Enable Receive Interrupt */
LL_I2C_EnableIT_RX(handle->i2c);
}
else if (LL_I2C_GetTransferDirection(handle->i2c) == LL_I2C_DIRECTION_READ)
{
/* Clear ADDR flag value in ISR register */
LL_I2C_ClearFlag_ADDR(handle->i2c);
/* Enable Transmit Interrupt */
LL_I2C_EnableIT_TX(handle->i2c);
}
}
else
{
/* Clear ADDR flag value in ISR register */
LL_I2C_ClearFlag_ADDR(handle->i2c);
/* Call Error function */
DBG_ASSERT(FALSE __DBG_LINE);
}
}
/* Check NACK flag value in ISR register */
else if (LL_I2C_IsActiveFlag_NACK(handle->i2c))
{
/* End of Transfer */
LL_I2C_ClearFlag_NACK(handle->i2c);
}
/* Check RXNE flag value in ISR register */
else if (LL_I2C_IsActiveFlag_RXNE(handle->i2c))
{
/* Call function Slave Reception Callback */
}
/* Check TXIS flag value in ISR register */
else if (LL_I2C_IsActiveFlag_TXIS(handle->i2c))
{
/* Call function Slave Ready to Transmit Callback */
}
/* Check STOP flag value in ISR register */
else if (LL_I2C_IsActiveFlag_STOP(handle->i2c))
{
/* End of Transfer */
LL_I2C_ClearFlag_STOP(handle->i2c);
/* Check TXE flag value in ISR register */
if (!LL_I2C_IsActiveFlag_TXE(handle->i2c))
{
/* Flush TX buffer */
LL_I2C_ClearFlag_TXE(handle->i2c);
}
/* Call function Slave Complete Callback */
}
/* Check TXE flag value in ISR register */
else if (!LL_I2C_IsActiveFlag_TXE(handle->i2c))
{
/* Do nothing */
/* This Flag will be set by hardware when the TXDR register is empty */
/* If needed, use LL_I2C_ClearFlag_TXE() interface to flush the TXDR register */
}
else
{
/* Call Error function */
DBG_ASSERT(FALSE __DBG_LINE);
}
}
#endif
/*下面是内部实现方法*/
/**
* @brief 使NOPcountNOP指令的数量使
* @param {uint16_t} count NOP指令的数量
* @return {*}
*/
static inline void delay(i2c_t *handle)
{
// 断言参数handle不为空
DBG_ASSERT(handle != NULL __DBG_LINE);
// 定义循环计数变量count
uint16_t count = 0;
// 设置循环计数变量count的值为handle->delay_ticks
count = handle->delay_ticks;
// 循环计数变量count的值直到count的值为0
while (count--)
{
// 每次循环调用__NOP()函数
__NOP();
}
}
/**
* @brief ACK信号
* @param {i2c_t} *handle I2C总线的句柄
* @return {*}
* @note: I2C总线上发送ACK信号handle不为空gpios和sclsda的指针sda1msscl为11msscl
*/
static inline void _ack(i2c_t *handle)
{
// 断言handle不为空
DBG_ASSERT(handle != NULL __DBG_LINE);
// 获取gpios指针
i2c_gpio_group_t *gpios = &handle->gpios;
// 获取scl指针
gpio_t *scl = gpios->scl;
// 获取sda指针
gpio_t *sda = gpios->sda;
// 重置sda
gpios->sda->reset(*sda);
// 延时
delay(handle);
// 设置scl
gpios->scl->set(*scl);
// 延时
delay(handle);
// 重置scl
gpios->scl->reset(*scl);
}
/**
* @brief NACK信号
* @param {i2c_t} *handle I2C总线的句柄
* @return {*}
* @note: I2C总线上发送NACK信号handle不为空gpios和sclsda的指针sda为11msscl为11msscl
*/
static inline void _nack(i2c_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
// 获取gpios指针
i2c_gpio_group_t *gpios = &handle->gpios;
// 获取scl指针
gpio_t *scl = gpios->scl;
// 获取sda指针
gpio_t *sda = gpios->sda;
// 设置sda引脚
gpios->sda->set(*sda);
// 等待延时
delay(handle);
// 设置scl引脚
gpios->scl->set(*scl);
// 等待延时
delay(handle);
// 重置scl引脚
gpios->scl->reset(*scl);
}

127
bsp/i2cs.h Normal file
View File

@ -0,0 +1,127 @@
/**
* @file i2cs.h
* @brief Header file for I2C Slave module.
*
* This file contains the declarations and definitions for the I2C Slave module.
* It provides functions to initialize and configure the I2C peripheral as a slave,
* as well as functions to send and receive data over the I2C bus.
*
* @author xxx
* @date 2023-12-27 14:44:03
* @version 1.0
* @copyright Copyright (c) 2024 by xxx, All Rights Reserved.
*/
#ifndef __I2CS_H__
#define __I2CS_H__
#include "lib.h"
#include "gpios.h"
/**
* @file i2cs.h
* @brief Header file containing the definition of the I2C slave (I2CS) structure and related functions.
*/
typedef struct I2CS i2c_t;
typedef void i2cs_dma_callback(i2c_t *handle);
typedef struct
{
void (*start)(i2c_t *handle); ///< Function pointer to start the I2C communication.
void (*stop)(i2c_t *handle); ///< Function pointer to stop the I2C communication.
BOOL(*wait_ack)
(i2c_t *handle); ///< Function pointer to wait for the acknowledgment from the I2C bus.
void (*write_byte)(i2c_t *handle, uint8_t data); ///< Function pointer to write a byte of data to the I2C bus.
uint8_t (*read_byte)(i2c_t *handle, BOOL ack); ///< Function pointer to read a byte of data from the I2C bus.
void (*write_word)(i2c_t *handle, uint16_t data); ///< Function pointer to write two bytes of data to the I2C bus.
BOOL(*write_mem_dma)
(i2c_t *handle, uint16_t mem_address, uint16_t mem_addsize, uint8_t *data, uint16_t size); ///< Function pointer to write multiple bytes of data to a memory address using DMA.
BOOL(*read_mem_dma)
(i2c_t *handle, uint16_t mem_address, uint16_t mem_addsize, uint8_t *data, uint16_t size); ///< Function pointer to read multiple bytes of data from a memory address using DMA.
} i2c_interface_t;
typedef struct
{
struct GPIO *scl; ///< Pointer to the GPIO pin used for the I2C clock (SCL).
struct GPIO *sda; ///< Pointer to the GPIO pin used for the I2C data (SDA).
} i2c_gpio_group_t;
struct I2CS
{
///< Analog part definition
i2c_gpio_group_t gpios; ///< Structure containing the GPIO pins used for the I2C communication.
uint16_t delay_ticks; ///< Number of NOP instructions to delay the I2C communication.
///< Hardware part definition
I2C_TypeDef *i2c; ///< Pointer to the I2C peripheral.
DMA_TypeDef *dma; ///< Pointer to the DMA peripheral.
uint32_t dma_rx_channel; ///< DMA channel used for receiving data.
uint32_t dma_tx_channel; ///< DMA channel used for transmitting data.
uint8_t *rxbuf; ///< Pointer to the receive buffer.
uint16_t rxsize; ///< Size of the receive buffer.
uint8_t *txbuf; ///< Pointer to the transmit buffer.
uint16_t txsize; ///< Size of the transmit buffer.
uint8_t w_address; ///< 7-bit write address.
uint8_t r_address; ///< 7-bit read address.
__IO BOOL rx_dma_ok; ///< Flag indicating the completion of receive DMA.
__IO BOOL tx_dma_ok; ///< Flag indicating the completion of transmit DMA.
i2cs_dma_callback *dma_rx_cb; ///< Callback function called when receive DMA is completed.
i2cs_dma_callback *dma_tx_cb; ///< Callback function called when transmit DMA is completed.
i2c_interface_t interface; ///< Structure containing the function pointers for the I2C interface.
uint16_t dead_count; ///< Counter for the number of deadlocks.
};
/**
* @brief Creates an I2C slave instance with GPIO pins for clock and data.
* @param gpios The GPIO pins used for the I2C communication.
* @param delay_ticks The number of NOP instructions to delay the I2C communication.
* @return A pointer to the created I2C slave instance.
*/
extern i2c_t *i2c_create(i2c_gpio_group_t gpios, uint16_t delay_ticks);
/**
* @brief Creates an I2C slave instance with DMA support.
* @param i2c Pointer to the I2C peripheral.
* @param dma Pointer to the DMA peripheral.
* @param rxsize Size of the receive buffer.
* @param dma_rx_channel DMA channel used for receiving data.
* @param dma_rx_cb Callback function called when receive DMA is completed.
* @param txsize Size of the transmit buffer.
* @param dma_tx_channel DMA channel used for transmitting data.
* @param dma_tx_cb Callback function called when transmit DMA is completed.
* @return A pointer to the created I2C slave instance.
*/
extern i2c_t *i2c_create_dma(I2C_TypeDef *i2c, DMA_TypeDef *dma, uint16_t rxsize, uint32_t dma_rx_channel,
i2cs_dma_callback *dma_rx_cb, uint16_t txsize, uint32_t dma_tx_channel, i2cs_dma_callback *dma_tx_cb);
/**
* @brief Sets the write and read addresses for the I2C slave instance with DMA support.
* @param handle Pointer to the I2C slave instance.
* @param w_address 7-bit write address.
* @param r_address 7-bit read address.
*/
extern void i2c_dma_set_address(i2c_t *handle, uint8_t w_address, uint8_t r_address);
/**
* @brief Frees the resources used by the I2C slave instance.
* @param handle Pointer to the I2C slave instance.
*/
extern void i2c_free(i2c_t *handle);
/**
* @brief Callback function called when an I2C event occurs.
* @param handle Pointer to the I2C slave instance.
*/
extern void i2c_ev_callback(i2c_t *handle);
/**
* @brief Callback function called when an I2C DMA event occurs.
* @param handle Pointer to the I2C slave instance.
*/
extern void i2c_dma_callback(i2c_t *handle);
#endif ///< __I2CS_H__

1
bsp/readme.md Normal file
View File

@ -0,0 +1 @@

811
bsp/spis.c Normal file
View File

@ -0,0 +1,811 @@
#include "spis.h"
#include "delay.h"
#define SPI_TIMEOUT 2000
#define CMD_RDSR 0x05 /*!< Read Status Register instruction */
#define CMD_WRSR 0x01 /*!< Write Status Register instruction */
#define CMD_WREN 0x06 /*!< Write enable instruction */
#define CMD_WRDI 0x04 /*!< Write disable instruction */
#define CMD_READ 0x03 /*!< Read from Memory instruction */
#define CMD_WRITE 0x02 /*!< Write to Memory instruction */
#define DUMMY_BYTE 0xA5 ///< 虚拟字节
static inline void spi_delay(spi_t *handle); // 延时函数
static inline void spi_rdy_high(spi_t *handle); // RDY高电平
static inline void spi_rdy_low(spi_t *handle); // RDY低电平
static inline void spi_cs_high(spi_t *handle); // CS高电平
static inline void spi_cs_low(spi_t *handle); // CS低电平
static inline void spi_mosi_high(spi_t *handle); // MOSI高电平
static inline void spi_mosi_low(spi_t *handle); // MOSI低电平
static inline void spi_sck_high(spi_t *handle); // SCK高电平
static inline void spi_sck_low(spi_t *handle); // SCK低电平
static inline uint8_t spi_miso_read(spi_t *handle); // 读取MISO电平
static uint8_t spi_read_write_byte(spi_t *handle, uint8_t tx_data); // 读写一个字节
static void spi_reset(spi_t *handle); // 复位
static BOOL spi_write(spi_t *handle, uint32_t write_addr, uint8_t *data, uint16_t length); // 写数据
static BOOL spi_read(spi_t *handle, uint32_t write_addr, uint8_t *data, uint16_t length); // 读数据
static void spi_write_reg(spi_t *handle, uint8_t reg, uint8_t data); // 写寄存器
static uint8_t spi_read_reg(spi_t *handle, uint8_t reg); // 读寄存器
static void _hardware_enable(spi_t *handle, SPI_TypeDef *spi); // 硬件SPI
static void _dma_enable(spi_t *handle, DMA_TypeDef *dma, uint32_t dma_rx_channel, spis_dma_callback *dma_rx_cb,
uint32_t dma_tx_channel, spis_dma_callback *dma_tx_cb); // DMA SPI
static void _spi_dma_callback(spi_t *handle); // DMA发送完成回调
static BOOL _spi_dma_send(spi_t *handle, uint8_t *data, uint16_t length); // DMA发送数据
static uint8_t _read_drdy(spi_t *handle); // 读取DRDY电平
static uint8_t _write_regs(spi_t *handle, uint8_t reg, uint8_t *data, uint8_t len); // 写多个寄存器
static uint8_t _read_regs(spi_t *handle, uint8_t reg, uint8_t *data, uint8_t len); // 读多个寄存器
static uint8_t _spi_write_reg(spi_t *handle, uint8_t reg, uint8_t data); // 写单个寄存器
static uint8_t _spi_read_reg(spi_t *handle, uint8_t reg); // 读单个寄存器
static uint8_t _spi_write_cmd(spi_t *handle, uint8_t cmd); // 写命令
static uint8_t _spi_write_data(spi_t *handle, uint8_t *data, uint16_t len); // 写数据
/**
* @brief SPI总线设备
* @param {spi_type_e} spi_type SPI总线的类型
* @param {spi_gpio_group_t} gpios SPI总线的GPIO配置
* @param {uint16_t} delay_ticks SPI总线的延时参数
* @return {*} SPI总线设备句柄
* @note: SPI总线设备spi_type在有效的范围内spi_t结构体gpios和delay_ticks的内存地址复制到handle结构体中spi_type的值handle结构体
*/
spi_t *spi_create(spi_type_e spi_type, spi_gpio_group_t gpios, uint16_t delay_ticks)
{
DBG_ASSERT(spi_type < SPI_TYPE_MAX __DBG_LINE);
spi_t *handle = (spi_t *)osel_mem_alloc(sizeof(spi_t));
osel_memcpy((uint8_t *)&handle->gpios, (uint8_t *)&gpios, sizeof(spi_gpio_group_t));
handle->delay_ticks = delay_ticks;
handle->spi_type = spi_type;
handle->simualte_gpio = TRUE;
handle->interface.hardware_enable = _hardware_enable;
handle->interface.dma_enable = _dma_enable;
handle->interface.spi_dma_send = _spi_dma_send;
handle->interface.spi_dma_callback = _spi_dma_callback;
if (spi_type == SPI_TYPE_NORMAL)
{
handle->interface.u.normal.write_reg = _spi_write_reg;
handle->interface.u.normal.read_reg = _spi_read_reg;
handle->interface.u.normal.write_regs = _write_regs;
handle->interface.u.normal.read_regs = _read_regs;
handle->interface.u.normal.read_drdy = _read_drdy;
handle->interface.u.normal.spi_send = spi_read_write_byte;
handle->interface.u.normal.spi_reset = spi_reset;
handle->interface.u.normal.spi_read = spi_read;
handle->interface.u.normal.spi_write = spi_write;
handle->interface.u.normal.spi_write_reg = spi_write_reg;
handle->interface.u.normal.spi_read_reg = spi_read_reg;
handle->cfg.cmd_rdsr = CMD_RDSR;
handle->cfg.cmd_wrsr = CMD_WRSR;
handle->cfg.cmd_wren = CMD_WREN;
handle->cfg.cmd_wrdi = CMD_WRDI;
handle->cfg.cmd_read = CMD_READ;
handle->cfg.cmd_write = CMD_WRITE;
handle->cfg.dummy_byte = DUMMY_BYTE;
handle->cfg.continuous_write = FALSE;
}
else if (spi_type == SPI_TYPE_LCD)
{
handle->interface.u.lcd.write_cmd = _spi_write_cmd;
handle->interface.u.lcd.write_data = _spi_write_data;
}
else
{
DBG_ASSERT(FALSE __DBG_LINE);
}
return handle;
}
void spi_free(spi_t *handle)
{
if (handle != NULL)
{
gpio_free(handle->gpios.cs);
gpio_free(handle->gpios.rdy);
gpio_free(handle->gpios.rst);
gpio_free(handle->gpios.mosi);
gpio_free(handle->gpios.miso);
gpio_free(handle->gpios.sck);
osel_mem_free(handle);
}
}
/**
* @brief SPI模式
* @param {spi_t} *handle SPI总线设备句柄
* @param {SPI_TypeDef} *spi SPI总线的寄存器结构体指针
* @return {*}
* @note: SPI总线的硬件模式handle不为空spix不为空handle的simulate_gpio设置为FALSEspix的地址赋值给handle->spixSPI_ENABLE函数启用SPI总线
*/
static void _hardware_enable(spi_t *handle, SPI_TypeDef *spi)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
DBG_ASSERT(spi != NULL __DBG_LINE);
handle->simualte_gpio = FALSE;
handle->spi = spi;
SPI_ENABLE(spi);
}
static void _dma_enable(spi_t *handle, DMA_TypeDef *dma, uint32_t dma_rx_channel, spis_dma_callback *dma_rx_cb,
uint32_t dma_tx_channel, spis_dma_callback *dma_tx_cb)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
DBG_ASSERT(dma != NULL __DBG_LINE);
DBG_ASSERT(handle->spi != NULL __DBG_LINE);
handle->dma = dma;
handle->dma_rx_channel = dma_rx_channel;
handle->dma_tx_channel = dma_tx_channel;
handle->rx_dma_ok = TRUE;
handle->tx_dma_ok = TRUE;
if (dma_rx_cb != NULL)
{
handle->dma_rx_cb = dma_rx_cb;
}
if (dma_tx_cb != NULL)
{
handle->dma_tx_cb = dma_tx_cb;
}
LL_DMA_SetPeriphAddress(dma, dma_tx_channel, LL_SPI_DMA_GetRegAddr(handle->spi));
LL_DMA_ClearFlag_GI1(dma);
LL_DMA_ClearFlag_TC1(dma);
LL_DMA_EnableIT_TC(dma, dma_tx_channel);
LL_SPI_EnableDMAReq_TX(handle->spi);
LL_SPI_Enable(handle->spi);
}
static void _spi_dma_callback(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
if (handle->dma_tx_cb != NULL)
{
handle->dma_tx_cb(handle);
}
if (handle->dma_rx_cb != NULL)
{
handle->dma_rx_cb(handle);
}
}
static BOOL _spi_dma_send(spi_t *handle, uint8_t *data, uint16_t length)
{
handle->tx_dma_ok = FALSE;
LL_DMA_DisableChannel(handle->dma, handle->dma_tx_channel);
LL_DMA_SetMemoryAddress(handle->dma, handle->dma_tx_channel, (uint32_t)data);
LL_DMA_SetDataLength(handle->dma, handle->dma_tx_channel, length);
LL_DMA_EnableChannel(handle->dma, handle->dma_tx_channel);
uint16_t i = 0;
while (handle->tx_dma_ok == FALSE)
{
i++;
if (i > 50000)
{
__NOP();
break;
}
}
return handle->tx_dma_ok == TRUE ? TRUE : FALSE;
}
/**
* @brief
* @param {spi_t} *handle SPI总线设备句柄
* @return {uint8_t}
* @note: SPI总线的数据准备好信号handle不为空handle的gpios.rdy的读取结果
*/
static uint8_t _read_drdy(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
return handle->gpios.rdy->read(*handle->gpios.rdy);
}
/**
* @brief
* @param {spi_t} *handle SPI总线设备句柄
* @param {uint8_t} reg
* @param {uint8_t} data
* @return {*}
* @note: SPI总线的单个寄存器handle不为空data不为空SPI总线的CS引脚设置为低电平SPI总线的CS引脚设置为高电平
*/
static uint8_t _write_regs(spi_t *handle, uint8_t reg, uint8_t *data, uint8_t len)
{
uint8_t status = 0;
DBG_ASSERT(handle != NULL __DBG_LINE);
DBG_ASSERT(data != NULL __DBG_LINE);
DBG_ASSERT(len != 0 __DBG_LINE);
spi_cs_low(handle);
status = spi_read_write_byte(handle, reg); // 发送寄存器号
while (len--)
{
spi_read_write_byte(handle, *data); // 写入寄存器的值
data++;
}
spi_cs_high(handle);
return status;
}
/**
* @brief
* @param {spi_t} *handle SPI总线设备句柄
* @param {uint8_t} reg
* @param {uint8_t} *data
* @param {uint8_t} len
* @return {uint8_t}
* @note: SPI总线的多个寄存器handle不为空data不为空len大于0SPI总线的CS引脚设置为低电平SPI总线的CS引脚设置为高电平
*/
static uint8_t _read_regs(spi_t *handle, uint8_t reg, uint8_t *data, uint8_t len)
{
uint8_t status = 0;
DBG_ASSERT(handle != NULL __DBG_LINE);
DBG_ASSERT(data != NULL __DBG_LINE);
DBG_ASSERT(len != 0 __DBG_LINE);
spi_cs_low(handle);
status = spi_read_write_byte(handle, reg);
for (uint8_t i = 0; i < len; i++)
{
data[i] = spi_read_write_byte(handle, 0xff); // 读出数据
}
spi_cs_high(handle);
return status;
}
/**
* @brief
* @param {spi_t} *handle SPI总线设备句柄
* @param {uint8_t} reg
* @param {uint8_t} data
* @return {*}
* @note: SPI总线的单个寄存器handle不为空SPI总线的CS引脚设置为低电平SPI总线的CS引脚设置为高电平
*/
static uint8_t _spi_write_reg(spi_t *handle, uint8_t reg, uint8_t data)
{
uint8_t status = 0;
DBG_ASSERT(handle != NULL __DBG_LINE);
spi_cs_low(handle);
status = spi_read_write_byte(handle, reg); // 发送寄存器号
spi_read_write_byte(handle, data); // 写入寄存器的值
spi_cs_high(handle);
return status;
}
/**
* @brief
* @param {spi_t} *handle SPI总线设备句柄
* @param {uint8_t} reg
* @return {*}
* @note: SPI总线的单个寄存器handle不为空SPI总线的CS引脚设置为低电平SPI总线的CS引脚设置为高电平
*/
static uint8_t _spi_read_reg(spi_t *handle, uint8_t reg)
{
uint8_t reg_val = 0;
DBG_ASSERT(handle != NULL __DBG_LINE);
spi_cs_low(handle);
spi_read_write_byte(handle, reg); // 发送寄存器号
reg_val = spi_read_write_byte(handle, 0);
spi_cs_high(handle);
return reg_val;
}
/**
* @brief
* @param {spi_t} *handle SPI总线设备句柄
* @param {uint8_t} cmd
* @return {*}
* @note: SPI总线的命令handle不为空SPI总线的RDY引脚设置为低电平SPI总线的CS引脚设置为高电平
*/
static uint8_t _spi_write_cmd(spi_t *handle, uint8_t cmd)
{
uint8_t status = 0;
DBG_ASSERT(handle != NULL __DBG_LINE);
spi_rdy_low(handle);
spi_cs_low(handle);
status = spi_read_write_byte(handle, cmd); // 发送命令
spi_cs_high(handle);
return status;
}
/**
* @brief
* @param {spi_t} *handle SPI总线设备句柄
* @param {uint8_t} *data
* @param {uint16_t} len
* @return {*}
* @note: SPI总线的数据handle不为空SPI总线的RDY引脚设置为高电平SPI总线的CS引脚设置为高电平
*/
static uint8_t _spi_write_data(spi_t *handle, uint8_t *data, uint16_t len)
{
uint8_t status = 0;
DBG_ASSERT(handle != NULL __DBG_LINE);
spi_rdy_high(handle);
spi_cs_low(handle);
for (uint16_t i = 0; i < len; i++)
{
status = spi_read_write_byte(handle, *data);
data++;
}
spi_cs_high(handle);
return status;
}
/**
* @brief SPI延时函数
* @param {spi_t} *handle SPI总线设备句柄
* @return {*}
* @note: SPI总线的延时handle不为空handle的delay_ticks的值NOP指令
*/
static inline void spi_delay(spi_t *handle)
{
uint16_t count = 0;
DBG_ASSERT(handle != NULL __DBG_LINE);
count = handle->delay_ticks;
if (count > 0)
{
while (count--)
{
__NOP();
}
}
}
static BOOL spi_wait_flag(spi_t *handle, uint32_t flag, uint32_t timeout)
{
uint32_t i = 0;
DBG_ASSERT(handle != NULL __DBG_LINE);
if (flag == LL_SPI_SR_TXE)
{
while (LL_SPI_IsActiveFlag_TXE(handle->spi) == 0)
{
if (i++ > timeout)
{
return FALSE; // 超时
}
else
{
__NOP();
}
}
}
else if (flag == LL_SPI_SR_RXNE)
{
while (LL_SPI_IsActiveFlag_RXNE(handle->spi) == 0)
{
if (i++ > timeout)
{
return FALSE; // 超时
}
else
{
__NOP();
}
}
}
else if (flag == LL_SPI_SR_BSY)
{
while (LL_SPI_IsActiveFlag_BSY(handle->spi) == 0)
{
if (i++ > timeout)
{
return FALSE; // 超时
}
else
{
__NOP();
}
}
}
else
{
DBG_ASSERT(FALSE __DBG_LINE);
}
return TRUE; // 成功
}
/**
* @brief
* @param {spi_t} *handle SPI总线设备句柄
* @param {uint8_t} tx_data
* @return {*}
* @note: SPI总线的读写一个字节handle不为空handle的simulate_gpio的值SPI或硬件SPI
*/
static uint8_t spi_read_write_byte(spi_t *handle, uint8_t tx_data)
{
uint8_t bit_ctr;
uint8_t rdata = 0xff;
DBG_ASSERT(handle != NULL __DBG_LINE);
if (handle->simualte_gpio == TRUE)
{
// 模拟SPI
for (bit_ctr = 0; bit_ctr < 8; bit_ctr++)
{
spi_sck_low(handle);
spi_delay(handle);
if (tx_data & 0x80)
spi_mosi_high(handle);
else
spi_mosi_low(handle);
spi_delay(handle);
spi_sck_high(handle);
spi_delay(handle);
tx_data = (tx_data << 1);
rdata = rdata << 1;
if (NULL != handle->gpios.miso->port)
{
if (spi_miso_read(handle) == 1)
rdata += 0x01;
}
}
return (rdata);
}
else
{
LL_SPI_TransmitData8(handle->spi, tx_data);
if (spi_wait_flag(handle, LL_SPI_SR_RXNE, SPI_TIMEOUT) == FALSE)
{
return 0xff;
}
rdata = LL_SPI_ReceiveData8(handle->spi);
return rdata;
}
}
static void _write_enable(spi_t *handle)
{
handle->gpios.cs->reset(*handle->gpios.cs);
handle->interface.u.normal.spi_send(handle, handle->cfg.cmd_wren);
handle->gpios.cs->set(*handle->gpios.cs);
}
static void _write_disable(spi_t *handle)
{
handle->gpios.cs->reset(*handle->gpios.cs);
handle->interface.u.normal.spi_send(handle, handle->cfg.cmd_wrdi);
handle->gpios.cs->set(*handle->gpios.cs);
}
static uint8_t _read_status(spi_t *handle)
{
uint8_t data;
handle->gpios.cs->reset(*handle->gpios.cs);
handle->interface.u.normal.spi_send(handle, handle->cfg.cmd_rdsr);
data = handle->interface.u.normal.spi_send(handle, handle->cfg.dummy_byte);
handle->gpios.cs->set(*handle->gpios.cs);
return data;
}
static void _ready(spi_t *handle)
{
uint16_t count = 0;
while (_read_status(handle) & 0x01)
{
if (count++ > 20000)
{
break;
}
else
{
__NOP();
}
}
}
static BOOL spi_write(spi_t *handle, uint32_t write_addr, uint8_t *data, uint16_t length)
{
BOOL ret = TRUE;
uint8_t cnt = 0; // 返回值检查
DBG_ASSERT(handle != NULL __DBG_LINE);
DBG_ASSERT(data != NULL __DBG_LINE);
DBG_ASSERT(length > 0 __DBG_LINE);
DBG_ASSERT(handle->cfg.page_size > 0 __DBG_LINE);
uint32_t page_size = handle->cfg.page_size;
_write_enable(handle); // 写入使能命令
handle->gpios.cs->reset(*handle->gpios.cs); // 设置CS引脚为低电平准备开始SPI通信
cnt = handle->interface.u.normal.spi_send(handle, handle->cfg.cmd_write); // 发送写入命令
if (cnt == 0)
{
return FALSE;
}
if (handle->cfg.address_bytes == 2)
{
cnt = handle->interface.u.normal.spi_send(handle, write_addr >> 8); // 发送高位地址
if (cnt == 0)
{
return FALSE;
}
cnt = handle->interface.u.normal.spi_send(handle, write_addr); // 发送低位地址
if (cnt == 0)
{
return FALSE;
}
}
else
{
cnt = handle->interface.u.normal.spi_send(handle, write_addr >> 16);
if (cnt == 0)
{
return FALSE;
}
cnt = handle->interface.u.normal.spi_send(handle, write_addr >> 8);
if (cnt == 0)
{
return FALSE;
}
cnt = handle->interface.u.normal.spi_send(handle, write_addr);
if (cnt == 0)
{
return FALSE;
}
}
while (length--)
{
cnt = handle->interface.u.normal.spi_send(handle, *data); // 发送一个字节数据
if (cnt == 0)
{
return FALSE;
}
data++;
if (handle->cfg.continuous_write == FALSE)
{
write_addr++;
if (((write_addr % page_size) == 0) && (length > 0))
{
// 一页写完
handle->gpios.cs->set(*handle->gpios.cs); // 设置CS引脚为高电平完成SPI通信
_ready(handle);
_write_enable(handle); // 写入使能命令
handle->gpios.cs->reset(*handle->gpios.cs); // 设置CS引脚为低电平准备开始SPI通信
cnt = handle->interface.u.normal.spi_send(handle, handle->cfg.cmd_write); // 发送写入命令
if (cnt == 0)
{
return FALSE;
}
if (handle->cfg.address_bytes == 2)
{
cnt = handle->interface.u.normal.spi_send(handle, write_addr >> 8); // 发送高位地址
if (cnt == 0)
{
return FALSE;
}
cnt = handle->interface.u.normal.spi_send(handle, write_addr); // 发送低位地址
if (cnt == 0)
{
return FALSE;
}
}
else
{
cnt = handle->interface.u.normal.spi_send(handle, write_addr >> 16);
if (cnt == 0)
{
return FALSE;
}
cnt = handle->interface.u.normal.spi_send(handle, write_addr >> 8);
if (cnt == 0)
{
return FALSE;
}
cnt = handle->interface.u.normal.spi_send(handle, write_addr);
if (cnt == 0)
{
return FALSE;
}
}
}
}
}
handle->gpios.cs->set(*handle->gpios.cs); // 设置CS引脚为高电平完成SPI通信
_ready(handle);
_write_disable(handle);
return ret;
}
static void spi_write_reg(spi_t *handle, uint8_t reg, uint8_t value)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
_write_enable(handle); // 写入使能命令
handle->interface.u.normal.write_reg(handle, reg, value);
_ready(handle);
_write_disable(handle); // 写入禁止命令
}
static uint8_t spi_read_reg(spi_t *handle, uint8_t reg)
{
uint8_t data;
handle->gpios.cs->reset(*handle->gpios.cs);
handle->interface.u.normal.spi_send(handle, reg);
data = handle->interface.u.normal.spi_send(handle, handle->cfg.dummy_byte);
handle->gpios.cs->set(*handle->gpios.cs);
return data;
}
static BOOL spi_read(spi_t *handle, uint32_t read_addr, uint8_t *data, uint16_t length)
{
BOOL ret = TRUE;
uint8_t cnt = 0; // 返回值检查
DBG_ASSERT(handle != NULL __DBG_LINE);
DBG_ASSERT(data != NULL __DBG_LINE);
DBG_ASSERT(length > 0 __DBG_LINE);
handle->gpios.cs->reset(*handle->gpios.cs); // 设置CS引脚为低电平准备开始SPI通信
cnt = handle->interface.u.normal.spi_send(handle, handle->cfg.cmd_read); // 发送读取命令
if (cnt == 0)
{
return FALSE;
}
if (handle->cfg.address_bytes == 2)
{
cnt = handle->interface.u.normal.spi_send(handle, read_addr >> 8); // 发送高位地址
if (cnt == 0)
{
return FALSE;
}
cnt = handle->interface.u.normal.spi_send(handle, read_addr); // 发送低位地址
if (cnt == 0)
{
return FALSE;
}
}
else
{
cnt = handle->interface.u.normal.spi_send(handle, read_addr >> 16);
if (cnt == 0)
{
return FALSE;
}
cnt = handle->interface.u.normal.spi_send(handle, read_addr >> 8);
if (cnt == 0)
{
return FALSE;
}
cnt = handle->interface.u.normal.spi_send(handle, read_addr);
if (cnt == 0)
{
return FALSE;
}
}
for (uint16_t i = 0; i < length; i++) // 循环读取数据
{
data[i] = handle->interface.u.normal.spi_send(handle, handle->cfg.dummy_byte); // 发送空字节,读取实际数据
}
handle->gpios.cs->set(*handle->gpios.cs); // 设置CS引脚为高电平完成SPI通信
return ret;
}
static void spi_reset(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
handle->gpios.cs->reset(*handle->gpios.cs);
delay_tick(10);
handle->gpios.cs->set(*handle->gpios.cs);
delay_tick(10);
}
/**
* @brief SPIRST
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_rdy_high(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
handle->gpios.rdy->set(*handle->gpios.rdy);
}
/**
* @brief SPIRST
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_rdy_low(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
handle->gpios.rdy->reset(*handle->gpios.rdy);
}
/**
* @brief SPICS
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_cs_high(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
handle->gpios.cs->set(*handle->gpios.cs);
spi_delay(handle);
}
/**
* @brief SPICS
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_cs_low(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
handle->gpios.cs->reset(*handle->gpios.cs);
spi_delay(handle);
}
/**
* @brief SPISCK
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_mosi_high(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
handle->gpios.mosi->set(*handle->gpios.mosi);
}
/**
* @brief SPIMOSI
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_mosi_low(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
handle->gpios.mosi->reset(*handle->gpios.mosi);
}
/**
* @brief SPISCK
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_sck_high(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
handle->gpios.sck->set(*handle->gpios.sck);
}
/**
* @brief SPISCK
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_sck_low(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
handle->gpios.sck->reset(*handle->gpios.sck);
}
/**
* @brief SPIMISO
* @param {spi_id_e} id
* @return {*}
*/
static inline uint8_t spi_miso_read(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
return handle->gpios.miso->read(*handle->gpios.miso);
}

165
bsp/spis.h Normal file
View File

@ -0,0 +1,165 @@
/**
* @file spis.h
* @brief SPI驱动, SPI设备的读写操作
*
* This file contains the SPI driver used for reading and writing operations on SPI devices.
*
* @date 2023-08-01
* @version 1.0
*
* @note This file is part of the STM32 controller-v2 project.
*
*/
#ifndef __SPIS_H__
#define __SPIS_H__
#include "lib.h"
#include "gpios.h"
#define SPI_ENABLE(SPIX) LL_SPI_Enable(SPIX)
typedef struct SPIS spi_t;
typedef void spis_dma_callback(spi_t *handle);
/**
* @brief SPI type enumeration
*/
typedef enum
{
SPI_TYPE_NORMAL = 0, ///< SPI1:NORMAL
SPI_TYPE_LCD, ///< SPI2:LCD
SPI_TYPE_MAX,
} spi_type_e;
/**
* @brief SPI GPIO group structure
*/
typedef struct
{
gpio_t *mosi; ///< MOSI
gpio_t *miso; ///< MISO
gpio_t *sck; ///< SCK
gpio_t *cs; ///< CS
gpio_t *rst; ///< RST
gpio_t *rdy; ///< DRDY
} spi_gpio_group_t;
/**
* @brief SPI normal interface structure
*/
typedef struct
{
uint8_t (*write_reg)(spi_t *handle, uint8_t reg, uint8_t data); ///< Write a single register via SPI
uint8_t (*read_reg)(spi_t *handle, uint8_t reg); ///< Read the value of a single register via SPI
uint8_t (*read_drdy)(spi_t *handle); ///< Get the value of the SPI DRDY pin
uint8_t (*write_regs)(spi_t *handle, uint8_t reg, uint8_t *data, uint8_t len); ///< Write multiple registers via SPI
uint8_t (*read_regs)(spi_t *handle, uint8_t reg, uint8_t *data, uint8_t len); ///< Read multiple registers via SPI
uint8_t (*spi_send)(spi_t *handle, uint8_t data); ///< Send data via SPI
void (*spi_reset)(spi_t *handle); ///< Reset SPI
BOOL(*spi_write)
(spi_t *handle, uint32_t write_addr, uint8_t *data, uint16_t length); ///< Write data via SPI
BOOL(*spi_read)
(spi_t *handle, uint32_t read_addr, uint8_t *data, uint16_t length); ///< Read data via SPI
void (*spi_write_reg)(spi_t *handle, uint8_t reg, uint8_t data); ///< Write a single register via SPI
uint8_t (*spi_read_reg)(spi_t *handle, uint8_t reg); ///< Read a single register via SPI
} spi_normal_interface_t;
/**
* @brief SPI LCD interface structure
*/
typedef struct
{
uint8_t (*write_cmd)(spi_t *handle, uint8_t cmd); ///< Write a command via SPI
uint8_t (*write_data)(spi_t *handle, uint8_t *data, uint16_t len); ///< Write data via SPI
} spi_lcd_interface_t;
/**
* @brief SPI interface structure
*/
typedef struct
{
union
{
spi_normal_interface_t normal;
spi_lcd_interface_t lcd;
} u;
void (*hardware_enable)(spi_t *handle, SPI_TypeDef *spi); ///< Enable hardware SPI
void (*dma_enable)(spi_t *handle, DMA_TypeDef *dma, uint32_t dma_rx_channel, spis_dma_callback *dma_rx_cb,
uint32_t dma_tx_channel, spis_dma_callback *dma_tx_cb); ///< Enable DMA SPI
void (*spi_dma_callback)(spi_t *spi); ///< DMA send completion callback
BOOL(*spi_dma_send)
(spi_t *handle, uint8_t *data, uint16_t length); ///< DMA send
} spi_interface_t;
/**
* @brief SPI structure
*/
typedef struct SPIS spi_t;
/**
* @brief SPI DMA callback function
*/
typedef void spis_dma_callback(spi_t *handle);
typedef struct
{
// CMD
uint8_t cmd_rdsr; ///< Read Status Register instruction
uint8_t cmd_wrsr; ///< Write Status Register instruction
uint8_t cmd_wren; ///< Write enable instruction
uint8_t cmd_wrdi; ///< Write disable instruction
uint8_t cmd_read; ///< Read from Memory instruction
uint8_t cmd_write; ///< Write to Memory instruction
uint8_t dummy_byte; ///< Dummy byte
uint8_t address_bytes;
uint32_t page_size;
uint32_t total_size;
uint8_t ticks; ///< Delay in NOP ticks
BOOL continuous_write; ///< Continuous write
} spi_normal_config_t;
struct SPIS
{
spi_type_e spi_type; ///< SPI type
uint16_t delay_ticks; ///< Delay in NOP ticks
spi_gpio_group_t gpios; ///< SPI GPIOs
spi_interface_t interface; ///< SPI interface
SPI_TypeDef *spi; ///< SPI peripheral
BOOL simualte_gpio; ///< Simulate GPIO
spi_normal_config_t cfg; ///< Normal SPI configuration
///< DMA
DMA_TypeDef *dma; ///< External setting
uint32_t dma_rx_channel; ///< External setting
uint32_t dma_tx_channel; ///< External setting
__IO BOOL rx_dma_ok;
__IO BOOL tx_dma_ok;
spis_dma_callback *dma_rx_cb; ///< DMA receive callback function
spis_dma_callback *dma_tx_cb; ///< DMA send callback function
void *params; ///< 扩展参数
};
/**
* @brief Create a new SPI instance
*
* @param spi_type The type of SPI
* @param gpios The SPI GPIO group
* @param delay_ticks The delay in NOP ticks
* @return spi_t* The created SPI instance
*/
extern spi_t *spi_create(spi_type_e spi_type, spi_gpio_group_t gpios, uint16_t delay_ticks);
/**
* @brief Free the SPI instance
*
* @param spi The SPI instance to free
*/
extern void spi_free(spi_t *spi);
#endif ///< __SPIS_H__