Files
CCU621M/BSP/spi/spi1_reserve_SE.c

330 lines
9.5 KiB
C

/*!
\file spi1_fixed.c
\brief SPI1 configuration file (Corrected Version)
\version 2026-03-09, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, GigaDevice Semiconductor Inc.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
#include "spi1_fixed.h"
#include <stdio.h>
#include "gd32h7xx.h"
/* 私有变量 */
static uint8_t spi1_initialized = 0;
/*!
\brief configure SPI1 GPIO peripheral
\param[in] none
\param[out] none
\retval none
\note SPI1引脚配置:
- SPI1_NSS -> PA8 (软件控制)
- SPI1_SCK -> PA9 (AF5)
- SPI1_MISO -> PG2 (AF5)
- SPI1_MOSI -> PG3 (AF5)
*/
void spi1_gpio_config(void)
{
/* 使能GPIO时钟 */
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOG);
/* 使能SPI1时钟 */
rcu_periph_clock_enable(RCU_SPI1);
/* 配置SPI1时钟源 */
rcu_spi_clock_config(IDX_SPI1, RCU_SPISRC_PLL0Q);
/* 配置NSS引脚 (PA8) - 软件控制,GPIO输出模式 */
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_8);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_8);
/* 默认拉高,不选中从设备 */
gpio_bit_set(GPIOA, GPIO_PIN_8);
/* 配置SPI1引脚复用功能 */
gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_9); // SCK
gpio_af_set(GPIOG, GPIO_AF_5, GPIO_PIN_2 | GPIO_PIN_3); // MISO, MOSI
/* 配置SCK引脚 (PA9) - 复用功能输出 */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_9);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_9);
/* 配置MISO引脚 (PG2) - 复用功能输入 */
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_2);
/* 配置MOSI引脚 (PG3) - 复用功能输出 */
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_3);
}
/*!
\brief configure SPI1 peripheral
\param[in] none
\param[out] none
\retval none
\note SPI1基本配置,使用8位数据,MSB先行,主模式
*/
void spi1_config(void)
{
spi_parameter_struct spi_init_struct;
/* 去初始化SPI1 */
spi_i2s_deinit(SPI1);
/* 初始化SPI参数结构体 */
spi_struct_para_init(&spi_init_struct);
/* SPI1参数配置 */
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; // 全双工模式
spi_init_struct.device_mode = SPI_MASTER; // 主模式
spi_init_struct.data_size = SPI_DATASIZE_8BIT; // 8位数据帧 (修正: frame_size -> data_size)
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE; // 时钟极性低,第一边沿采样
spi_init_struct.nss = SPI_NSS_SOFT; // 软件NSS控制
spi_init_struct.prescale = SPI_PSC_16; // 16分频
spi_init_struct.endian = SPI_ENDIAN_MSB; // MSB先行
/* 初始化SPI1 */
spi_init(SPI1, &spi_init_struct);
/* 使能字节访问 */
spi_byte_access_enable(SPI1);
/* 使能NSS输出 (虽然使用软件控制,但保持兼容性) */
spi_nss_output_enable(SPI1);
}
/*!
\brief SPI1完整初始化
\param[in] none
\param[out] none
\retval 0: 成功, -1: 失败
\note 完整的SPI1初始化流程
*/
int spi1_init(void)
{
if(spi1_initialized) {
return 0; // 已初始化
}
/* 配置GPIO */
spi1_gpio_config();
/* 配置SPI外设 */
spi1_config();
/* 使能SPI1 */
spi_enable(SPI1);
spi1_initialized = 1;
return 0;
}
/*!
\brief SPI1去初始化
\param[in] none
\param[out] none
\retval none
\note 禁用SPI1并复位相关配置
*/
void spi1_deinit(void)
{
/* 禁用SPI1 */
spi_disable(SPI1);
/* 去初始化SPI1 */
spi_i2s_deinit(SPI1);
/* NSS引脚拉高 */
gpio_bit_set(GPIOA, GPIO_PIN_8);
spi1_initialized = 0;
}
/*!
\brief SPI1发送数据
\param[in] data: 要发送的数据
\param[out] none
\retval none
\note 阻塞式发送
*/
void spi1_send_data(uint8_t data)
{
/* 等待发送缓冲区为空 */
while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_TP));
/* 发送数据 (修正API名称) */
spi_i2s_data_transmit(SPI1, data);
}
/*!
\brief SPI1接收数据
\param[in] none
\param[out] none
\retval 接收到的数据
\note 阻塞式接收
*/
uint8_t spi1_receive_data(void)
{
/* 等待接收缓冲区非空 */
while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_RP));
/* 接收数据 (修正API名称) */
return (uint8_t)spi_i2s_data_receive(SPI1);
}
/*!
\brief SPI1发送接收数据
\param[in] tx_data: 要发送的数据
\param[out] none
\retval 接收到的数据
\note 全双工通信,同时发送和接收
*/
uint8_t spi1_transmit_receive(uint8_t tx_data)
{
/* 等待发送缓冲区为空 */
while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_TP));
/* 发送数据 (修正API名称) */
spi_i2s_data_transmit(SPI1, tx_data);
/* 等待接收缓冲区非空 */
while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_RP));
/* 接收数据 (修正API名称) */
return (uint8_t)spi_i2s_data_receive(SPI1);
}
/*!
\brief SPI1发送数据块
\param[in] data: 数据缓冲区指针
\param[in] size: 数据大小
\param[out] none
\retval 0: 成功, -1: 参数错误
*/
int spi1_send_buffer(uint8_t *data, uint16_t size)
{
if(!data || size == 0) {
return -1;
}
for(uint16_t i = 0; i < size; i++) {
spi1_send_data(data[i]);
}
return 0;
}
/*!
\brief SPI1接收数据块
\param[in] data: 数据缓冲区指针
\param[in] size: 数据大小
\param[out] none
\retval 0: 成功, -1: 参数错误
*/
int spi1_receive_buffer(uint8_t *data, uint16_t size)
{
if(!data || size == 0) {
return -1;
}
for(uint16_t i = 0; i < size; i++) {
data[i] = spi1_receive_data();
}
return 0;
}
/*!
\brief SPI1片选控制
\param[in] enable: 1-选中从设备, 0-取消选中
\param[out] none
\retval none
\note 软件控制NSS信号
*/
void spi1_nss_control(uint8_t enable)
{
if(enable) {
/* 拉低NSS,选中从设备 */
gpio_bit_reset(GPIOA, GPIO_PIN_8);
} else {
/* 拉高NSS,取消选中从设备 */
gpio_bit_set(GPIOA, GPIO_PIN_8);
}
}
/*!
\brief 检查SPI1是否已初始化
\param[in] none
\param[out] none
\retval 1: 已初始化, 0: 未初始化
*/
uint8_t spi1_is_initialized(void)
{
return spi1_initialized;
}
/*!
\brief SPI1中断处理函数
\param[in] none
\param[out] none
\retval none
\note 需要在SPI1_IRQHandler中调用此函数
*/
void spi1_irq_handler(void)
{
/* 检查接收缓冲区非空中断标志 */
if(spi_i2s_interrupt_flag_get(SPI1, SPI_I2S_INT_FLAG_RP)) {
/* 读取接收数据,清除中断标志 */
uint8_t data = (uint8_t)spi_i2s_data_receive(SPI1);
/* 这里可以添加数据处理逻辑,例如存储到接收缓冲区 */
(void)data; /* 避免未使用变量警告 */
}
/* 检查发送缓冲区空中断标志 */
if(spi_i2s_interrupt_flag_get(SPI1, SPI_I2S_INT_FLAG_TP)) {
/* 这里可以添加发送数据处理逻辑 */
}
/* 检查错误中断标志 */
if(spi_i2s_interrupt_flag_get(SPI1, SPI_I2S_INT_FLAG_CRCERR)) {
/* CRC错误处理 */
spi_i2s_flag_clear(SPI1, SPI_FLAG_CRCERR);
}
if(spi_i2s_interrupt_flag_get(SPI1, SPI_I2S_INT_FLAG_RXORERR)) {
/* 溢出错误处理 */
spi_i2s_flag_clear(SPI1, SPI_FLAG_RXORERR);
}
if(spi_i2s_interrupt_flag_get(SPI1, SPI_I2S_INT_FLAG_TXURERR)) {
/* 欠载错误处理 */
spi_i2s_flag_clear(SPI1, SPI_FLAG_TXURERR);
}
}