Initial commit: CCU621_M firmware project with BLE debug link support.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,330 @@
|
||||
/*!
|
||||
\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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user