freertos_f407/User/system/bsp/spis.c

291 lines
7.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "spis.h"
#include "delay.h"
#define SPI_TIMEOUT 2000
/**
* @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 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 用于将SPI串行外围接口设备的复位RST引脚设置为高
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_rdy_high(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
if (handle->gpios.rdy != NULL)
{
handle->gpios.rdy->set(*handle->gpios.rdy);
}
}
/**
* @brief 用于将SPI串行外围接口设备的复位RST引脚设置为低
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_rdy_low(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
if (handle->gpios.rdy != NULL)
{
handle->gpios.rdy->reset(*handle->gpios.rdy);
}
}
/**
* @brief 用于将SPI串行外围接口设备的芯片选择CS引脚设置为高
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_cs_high(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
if (handle->gpios.cs != NULL)
{
handle->gpios.cs->set(*handle->gpios.cs);
spi_delay(handle);
}
}
/**
* @brief 用于将SPI串行外围接口设备的芯片选择CS引脚设置为低
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_cs_low(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
if (handle->gpios.cs != NULL)
{
handle->gpios.cs->reset(*handle->gpios.cs);
spi_delay(handle);
}
}
/**
* @brief 用于将SPI串行外围接口设备的时钟SCK引脚设置为高
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_mosi_high(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
if (handle->gpios.mosi != NULL)
{
handle->gpios.mosi->set(*handle->gpios.mosi);
}
}
/**
* @brief 用于将SPI串行外围接口设备的输出MOSI引脚设置为低
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_mosi_low(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
if (handle->gpios.mosi != NULL)
{
handle->gpios.mosi->reset(*handle->gpios.mosi);
}
}
/**
* @brief 用于将SPI串行外围接口设备的时钟SCK引脚设置为高
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_sck_high(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
if (handle->gpios.sck != NULL)
{
handle->gpios.sck->set(*handle->gpios.sck);
}
}
/**
* @brief 用于将SPI串行外围接口设备的时钟SCK引脚设置为低
* @param {spi_id_e} id
* @return {*}
*/
static inline void spi_sck_low(spi_t *handle)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
if (handle->gpios.sck != NULL)
{
handle->gpios.sck->reset(*handle->gpios.sck);
}
}
/**
* @brief 用于读取SPI串行外围接口设备的输入MISO引脚的电平
* @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);
}
/**
* @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
{
uint8_t rx_data = 0;
if (HAL_SPI_TransmitReceive(handle->spi, &tx_data, &rx_data, 1, SPI_TIMEOUT) != HAL_OK)
{
// 处理错误
return 0xff;
}
return rx_data;
}
}
/**
* @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总线设备句柄
* @param {SPI_HandleTypeDef} *spi SPI总线的寄存器结构体指针
* @return {*} 无
* @note: 该函数用于设置SPI总线的硬件模式。它首先断言handle不为空然后断言spix不为空。接着将handle的simulate_gpio设置为FALSE并将spix的地址赋值给handle->spix。最后调用SPI_ENABLE函数启用SPI总线。
*/
static void _hardware_enable(spi_t *handle, SPI_HandleTypeDef *spi)
{
DBG_ASSERT(handle != NULL __DBG_LINE);
DBG_ASSERT(spi != NULL __DBG_LINE);
handle->simualte_gpio = FALSE;
handle->spi = spi;
__HAL_SPI_ENABLE(handle->spi);
}
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->interface.hardware_enable = _hardware_enable;
if (spi_type == SPI_TYPE_NORMAL)
{
}
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;
}