diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bc13c0..0a57962 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,10 @@ target_include_directories(global_macros INTERFACE target_compile_definitions(global_macros INTERFACE $<$:DEBUG> $<$:NDEBUG> + + # 可以像这样拓展MCU + $<$:USE_STM32F429> + $<$:USE_GD32F470> # 在这里添加你的全局宏 ) diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_adc.h b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_adc.h new file mode 100644 index 0000000..082230d --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_adc.h @@ -0,0 +1,8 @@ +#ifndef __ADC_H +#define __ADC_H + +#include "bsp_io_define.h" + +void BSP_ADC_Init(void); + +#endif /* __ADC_H */ diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_dac.h b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_dac.h new file mode 100644 index 0000000..78719f0 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_dac.h @@ -0,0 +1,8 @@ +#ifndef __DAC_H +#define __DAC_H + +#include "bsp_io_define.h" + +void BSP_DAC_Init(void); + +#endif/* __DAC_H */ diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_dma.h b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_dma.h new file mode 100644 index 0000000..ce42c8b --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_dma.h @@ -0,0 +1,8 @@ +#ifndef __DMA_H +#define __DMA_H + +#include "bsp_io_define.h" + +void BSP_DMA_Init(void); + +#endif/* __DMA_H */ diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_exmc.h b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_exmc.h new file mode 100644 index 0000000..6ec4773 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_exmc.h @@ -0,0 +1,8 @@ +#ifndef __BSP_EXMC_H +#define __BSP_EXMC_H + +#include "bsp_io_define.h" + +void BSP_EXMC_Init(void); + +#endif/* __BSP_EXMC_H */ diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_gpio.h b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_gpio.h new file mode 100644 index 0000000..0565e38 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_gpio.h @@ -0,0 +1,8 @@ +#ifndef __BSP_GPIO_H +#define __BSP_GPIO_H + +#include "bsp_io_define.h" + +void BSP_GPIO_Init(void); + +#endif/* __BSP_GPIO_H */ diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_iic.h b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_iic.h new file mode 100644 index 0000000..077ba00 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_iic.h @@ -0,0 +1,8 @@ +#ifndef __IIC_H +#define __IIC_H + +#include "bsp_io_define.h" + +void BSP_IIC_Init(void); + +#endif /* __IIC_H */ diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_ipa.h b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_ipa.h new file mode 100644 index 0000000..e9b63b4 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_ipa.h @@ -0,0 +1,8 @@ +#ifndef __BSP_IPA_H +#define __BSP_IPA_H + +#include "bsp_io_define.h" + +void BSP_IPA_Init(void); + +#endif /* __BSP_IPA_H */ diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_led_key.h b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_led_key.h new file mode 100644 index 0000000..a81c401 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_led_key.h @@ -0,0 +1,30 @@ +#ifndef __LED_KEY_H +#define __LED_KEY_H + +#include "bsp_io_define.h" + +// key enum +typedef enum +{ + KEY_VAL_NONE = 0, + KEY_VAL_L, + KEY_VAL_A, + KEY_VAL_B, + KEY_VAL_R +} KeyVal_t; + +// LED +#define LED1_TOGGLE() gpio_bit_toggle(BSP_LED1_PORT, BSP_LED1_PIN) +#define LED2_TOGGLE() gpio_bit_toggle(BSP_LED2_PORT, BSP_LED2_PIN) +#define LED3_TOGGLE() gpio_bit_toggle(BSP_LED3_PORT, BSP_LED3_PIN) +#define LED4_TOGGLE() gpio_bit_toggle(BSP_LED4_PORT, BSP_LED4_PIN) + +#define LED1_VALUE(X) gpio_bit_write(BSP_LED1_PORT, BSP_LED1_PIN, (bit_status)(X)) +#define LED2_VALUE(X) gpio_bit_write(BSP_LED2_PORT, BSP_LED2_PIN, (bit_status)(X)) +#define LED3_VALUE(X) gpio_bit_write(BSP_LED3_PORT, BSP_LED3_PIN, (bit_status)(X)) +#define LED4_VALUE(X) gpio_bit_write(BSP_LED4_PORT, BSP_LED4_PIN, (bit_status)(X)) + +void BSP_LED_Key_Init(void); +KeyVal_t BSP_KeyRead(void); + +#endif /* __LED_KEY_H */ diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_sdio.h b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_sdio.h new file mode 100644 index 0000000..cad9b3f --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_sdio.h @@ -0,0 +1,8 @@ +#ifndef __BSP_SDIO_H +#define __BSP_SDIO_H + +#include "bsp_io_define.h" + +void BSP_SDIO_Init(void); + +#endif/* __BSP_SDIO_H */ diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_spi.h b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_spi.h new file mode 100644 index 0000000..7114641 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_spi.h @@ -0,0 +1,8 @@ +#ifndef __SPI_H +#define __SPI_H + +#include "bsp_io_define.h" + +void BSP_SPI_Init(void); + +#endif /* __SPI_H */ diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_timer.h b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_timer.h new file mode 100644 index 0000000..0569001 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_timer.h @@ -0,0 +1,12 @@ +#ifndef __TIMER_H +#define __TIMER_H + +#include "bsp_io_define.h" + +void BSP_Timer_Tick_Init(void); +void BSP_Timer_LCD_Init(void); +void BSP_Timer_Motor_Init(void); +void BSP_Timer_DAC_Init(void); +void BSP_Timer_Debug_Init(void); + +#endif /* __TIMER_H */ diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_usart.h b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_usart.h new file mode 100644 index 0000000..e49d304 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Inc/bsp_usart.h @@ -0,0 +1,8 @@ +#ifndef __BSP_USART_H +#define __BSP_USART_H + +#include "bsp_io_define.h" + +void BSP_USART_Init(uint32_t baud_rate); + +#endif /* __BSP_USART_H */ diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_adc.c b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_adc.c new file mode 100644 index 0000000..ecf499f --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_adc.c @@ -0,0 +1,55 @@ +#include "bsp_adc.h" + +/** + * @brief 初始化ADC模块 + * @note 配置ADC时钟、GPIO引脚、ADC工作模式、通道配置和DMA功能 + * - 配置时钟:使用APB总线120MHz做6分频得到20MHz ADC时钟 + * - 配置IO:将摇杆X/Y轴和电池检测引脚设置为模拟模式 + * - 配置ADC:独立模式、连续转换模式、扫描模式、右对齐、12位分辨率 + * - 配置通道:温度传感器、内部参考电压、摇杆X/Y轴、电池电压共5个通道 + * - 配置DMA:使能ADC的DMA传输功能 + * @param 无 + * @retval 无 + */ +void BSP_ADC_Init(void) +{ + // 使能ADC和GPIO时钟 + rcu_periph_clock_enable(RCU_GPIOA); /* 摇杆X轴 */ + rcu_periph_clock_enable(RCU_GPIOB); /* 电池电压检测 */ + rcu_periph_clock_enable(RCU_GPIOC); /* 摇杆Y轴 */ + rcu_periph_clock_enable(BSP_ADC_RCU); /* ADC0外设时钟 */ + + // ADC GPIO配置 + gpio_mode_set(BSP_JSK_X_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, BSP_JSK_X_PIN); + gpio_mode_set(BSP_JSK_Y_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, BSP_JSK_Y_PIN); + gpio_mode_set(BSP_BAT_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, BSP_BAT_PIN); + + adc_clock_config(ADC_ADCCK_PCLK2_DIV6); // 使用APB总线(120M)做6分频 -> 20M + + // ADC CFG + adc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT); // 独立模式 + + adc_special_function_config(BSP_ADC, ADC_CONTINUOUS_MODE, ENABLE); // 连续模式,一次触发后自动转换 + adc_special_function_config(BSP_ADC, ADC_SCAN_MODE, ENABLE); // 开启扫描模式 多个通道自动转换 + + adc_data_alignment_config(BSP_ADC, ADC_DATAALIGN_RIGHT); // 数据右对齐 + adc_resolution_config(BSP_ADC, ADC_RESOLUTION_12B); // 12位分辨率 + + // 配置规则组 + adc_channel_length_config(BSP_ADC, ADC_ROUTINE_CHANNEL, 5); + adc_routine_channel_config(BSP_ADC, 0, BSP_TEMP_ADC_CH, ADC_SAMPLETIME_84); + adc_routine_channel_config(BSP_ADC, 1, BSP_VREF_ADC_CH, ADC_SAMPLETIME_84); + adc_routine_channel_config(BSP_ADC, 2, BSP_JSK_X_ADC_CH, ADC_SAMPLETIME_84); + adc_routine_channel_config(BSP_ADC, 3, BSP_JSK_Y_ADC_CH, ADC_SAMPLETIME_84); + adc_routine_channel_config(BSP_ADC, 4, BSP_BAT_ADC_CH, ADC_SAMPLETIME_84); + + // 内部参考电压传感器 + adc_channel_16_to_18(ADC_TEMP_VREF_CHANNEL_SWITCH, ENABLE); + + // 使用软件触发 + adc_external_trigger_config(BSP_ADC, ADC_ROUTINE_CHANNEL, EXTERNAL_TRIGGER_DISABLE); + + // ADC的DMA配置 + adc_dma_request_after_last_enable(BSP_ADC); + adc_dma_mode_enable(BSP_ADC); +} diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_dac.c b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_dac.c new file mode 100644 index 0000000..c5c26cc --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_dac.c @@ -0,0 +1,45 @@ +#include "bsp_dac.h" + +/** + * @brief 初始化DAC模块 + * @details 配置DAC用于音频输出,包括: + * - 启用DAC时钟 + * - 设置触发源为TIMER7 + * - 禁用波形生成模式 + * - 启用输出缓存 + * - 配置8位右对齐数据格式 + * - 使能DMA请求 + * - 使能DAC通道 + * @note 该函数配置DAC用于音频播放,使用外部定时器触发 + * @param 无 + * @retval 无 + */ +void BSP_DAC_Init(void) +{ + // 使能DAC和GPIO时钟 + rcu_periph_clock_enable(RCU_GPIOA); /* DAC音频输出引脚 */ + rcu_periph_clock_enable(BSP_AUDIO_DAC_RCU); /* DAC外设时钟 */ + + // DAC GPIO配置 + gpio_mode_set(BSP_DAC_AUDIO_OUT_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, BSP_DAC_AUDIO_OUT_PIN); + + dac_deinit(BSP_AUDIO_DAC); + + // 配置触发源 使用 TIMER7 触发 + dac_trigger_source_config(BSP_AUDIO_DAC, BSP_DAC_AUDIO_OUT, DAC_TRIGGER_T7_TRGO); + + // 使能触发 + dac_trigger_enable(BSP_AUDIO_DAC, BSP_DAC_AUDIO_OUT); + + // 关闭波形模式 + dac_wave_mode_config(BSP_AUDIO_DAC, BSP_DAC_AUDIO_OUT, DAC_WAVE_DISABLE); + + // 开启输出缓存 + dac_output_buffer_enable(BSP_AUDIO_DAC, BSP_DAC_AUDIO_OUT); + + // 允许DMA请求 + dac_dma_enable(BSP_AUDIO_DAC, BSP_DAC_AUDIO_OUT); + + // 使能DAC + dac_enable(BSP_AUDIO_DAC, BSP_DAC_AUDIO_OUT); +} \ No newline at end of file diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_dma.c b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_dma.c new file mode 100644 index 0000000..065ad36 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_dma.c @@ -0,0 +1,29 @@ +#include "bsp_dma.h" + +/** + * @brief 初始化DMA外设 + * @details 反初始化DMA + * - ADC DMA:用于ADC数据的自动传输,减少CPU占用 + * - USART DMA:用于串口数据的发送和接收,提高通信效率 + * - DAC DMA:用于搬运音频数据 + * @param None + * @retval None + * @note 此函数仅使能DMA时钟,具体的DMA通道配置在各自的外设初始化函数中完成 + * 必须在使用DMA功能之前调用此函数 + */ +void BSP_DMA_Init(void) +{ + // 使能DMA时钟 + rcu_periph_clock_enable(RCU_DMA0); + rcu_periph_clock_enable(RCU_DMA1); + + dma_deinit(BSP_ADC_DMA, BSP_ADC_DMA_CH); + dma_deinit(BSP_USART_DMA_RCU, BSP_USART_DMA_TX_CH); + dma_deinit(BSP_USART_DMA_RCU, BSP_USART_DMA_RX_CH); + dma_deinit(BSP_AUDIO_DMA, BSP_AUDIO_DMA_CH); + dma_deinit(BSP_SDIO_DMA, BSP_SDIO_DMA_CH); + + // 配置DMA传输完成中断 每一次中断都是代表一次音频播放结束 + dma_interrupt_enable(BSP_AUDIO_DMA, BSP_AUDIO_DMA_CH, DMA_INT_FTF); + nvic_irq_enable(BSP_AUDIO_DMA_IRQ, 0, 6); +} diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_exmc.c b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_exmc.c new file mode 100644 index 0000000..fb41036 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_exmc.c @@ -0,0 +1,231 @@ +#include "bsp_exmc.h" + +/* W9825G6KH-6 关键时序参数(单位:ns,基于数据手册) */ +#define SDRAM_TMRD_CYCLES 2U /* 模式寄存器写入间隔 tMRD >= 2 个时钟周期 */ +#define SDRAM_TXSR_NS 70U /* 自刷新唤醒时间 tXSR >= 70ns */ +#define SDRAM_TRAS_NS 42U /* 行有效保持时间 tRAS >= 42ns */ +#define SDRAM_TRFC_NS 66U /* 自动刷新周期 tRFC >= 66ns */ +#define SDRAM_TWR_NS 14U /* 写恢复时间 tWR >= 14ns */ +#define SDRAM_TRP_NS 18U /* 行预充电时间 tRP >= 18ns */ +#define SDRAM_TRCD_NS 18U /* 行到列延迟 tRCD >= 18ns */ + +/* EXMC 时序寄存器允许的最大计数值(对应 16 个时钟周期) */ +#define SDRAM_TIMING_MAX_CYCLES 16U + +/* 根据 SDCLK 频率把纳秒换算为 EXMC 需要的时钟周期数(向上取整) */ +static uint32_t sdram_ns_to_cycles(uint32_t time_ns, uint32_t sdclk_hz) +{ + if ((0U == time_ns) || (0U == sdclk_hz)) + { + return 1U; + } + + uint64_t cycles = (uint64_t)time_ns * (uint64_t)sdclk_hz + (1000000000ULL - 1ULL); + cycles /= 1000000000ULL; + + if (cycles < 1ULL) + { + cycles = 1ULL; + } + else if (cycles > SDRAM_TIMING_MAX_CYCLES) + { + cycles = SDRAM_TIMING_MAX_CYCLES; + } + + return (uint32_t)cycles; +} + +/** + * @brief 初始化 EXMC 控制器以驱动 W9825G6KH-6 SDRAM。 + * @note 该函数只负责时序寄存器和控制寄存器配置,真正的初始化命令在 SDRAM_Init 中完成。 + */ +void BSP_EXMC_Init(void) +{ + // 使能EXMC和相关GPIO时钟 + rcu_periph_clock_enable(BSP_SDRAM_EXMC_RCU); /* EXMC SDRAM控制器 */ + rcu_periph_clock_enable(RCU_GPIOC); /* EXMC SDRAM控制信号 */ + rcu_periph_clock_enable(RCU_GPIOD); /* EXMC SDRAM数据线 */ + rcu_periph_clock_enable(RCU_GPIOE); /* EXMC SDRAM数据线 */ + rcu_periph_clock_enable(RCU_GPIOF); /* EXMC SDRAM地址线 */ + rcu_periph_clock_enable(RCU_GPIOG); /* EXMC SDRAM地址线和控制信号 */ + + // EXMC SDRAM GPIO配置 + // 地址线配置 + gpio_af_set(BSP_EXMC_SDRAM_A0_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_A0_PIN); + gpio_af_set(BSP_EXMC_SDRAM_A1_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_A1_PIN); + gpio_af_set(BSP_EXMC_SDRAM_A2_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_A2_PIN); + gpio_af_set(BSP_EXMC_SDRAM_A3_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_A3_PIN); + gpio_af_set(BSP_EXMC_SDRAM_A4_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_A4_PIN); + gpio_af_set(BSP_EXMC_SDRAM_A5_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_A5_PIN); + gpio_af_set(BSP_EXMC_SDRAM_A6_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_A6_PIN); + gpio_af_set(BSP_EXMC_SDRAM_A7_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_A7_PIN); + gpio_af_set(BSP_EXMC_SDRAM_A8_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_A8_PIN); + gpio_af_set(BSP_EXMC_SDRAM_A9_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_A9_PIN); + gpio_af_set(BSP_EXMC_SDRAM_A10_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_A10_PIN); + gpio_af_set(BSP_EXMC_SDRAM_A11_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_A11_PIN); + gpio_af_set(BSP_EXMC_SDRAM_A12_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_A12_PIN); + + gpio_mode_set(BSP_EXMC_SDRAM_A0_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_A0_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_A1_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_A1_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_A2_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_A2_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_A3_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_A3_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_A4_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_A4_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_A5_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_A5_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_A6_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_A6_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_A7_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_A7_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_A8_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_A8_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_A9_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_A9_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_A10_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_A10_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_A11_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_A11_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_A12_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_A12_PIN); + + gpio_output_options_set(BSP_EXMC_SDRAM_A0_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_A0_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_A1_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_A1_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_A2_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_A2_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_A3_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_A3_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_A4_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_A4_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_A5_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_A5_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_A6_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_A6_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_A7_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_A7_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_A8_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_A8_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_A9_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_A9_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_A10_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_A10_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_A11_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_A11_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_A12_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_A12_PIN); + + // 数据线配置 + gpio_af_set(BSP_EXMC_SDRAM_D0_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D0_PIN); + gpio_af_set(BSP_EXMC_SDRAM_D1_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D1_PIN); + gpio_af_set(BSP_EXMC_SDRAM_D2_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D2_PIN); + gpio_af_set(BSP_EXMC_SDRAM_D3_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D3_PIN); + gpio_af_set(BSP_EXMC_SDRAM_D4_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D4_PIN); + gpio_af_set(BSP_EXMC_SDRAM_D5_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D5_PIN); + gpio_af_set(BSP_EXMC_SDRAM_D6_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D6_PIN); + gpio_af_set(BSP_EXMC_SDRAM_D7_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D7_PIN); + gpio_af_set(BSP_EXMC_SDRAM_D8_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D8_PIN); + gpio_af_set(BSP_EXMC_SDRAM_D9_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D9_PIN); + gpio_af_set(BSP_EXMC_SDRAM_D10_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D10_PIN); + gpio_af_set(BSP_EXMC_SDRAM_D11_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D11_PIN); + gpio_af_set(BSP_EXMC_SDRAM_D12_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D12_PIN); + gpio_af_set(BSP_EXMC_SDRAM_D13_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D13_PIN); + gpio_af_set(BSP_EXMC_SDRAM_D14_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D14_PIN); + gpio_af_set(BSP_EXMC_SDRAM_D15_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_D15_PIN); + + gpio_mode_set(BSP_EXMC_SDRAM_D0_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D0_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_D1_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D1_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_D2_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D2_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_D3_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D3_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_D4_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D4_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_D5_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D5_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_D6_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D6_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_D7_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D7_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_D8_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D8_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_D9_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D9_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_D10_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D10_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_D11_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D11_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_D12_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D12_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_D13_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D13_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_D14_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D14_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_D15_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_D15_PIN); + + gpio_output_options_set(BSP_EXMC_SDRAM_D0_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D0_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_D1_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D1_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_D2_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D2_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_D3_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D3_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_D4_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D4_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_D5_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D5_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_D6_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D6_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_D7_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D7_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_D8_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D8_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_D9_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D9_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_D10_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D10_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_D11_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D11_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_D12_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D12_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_D13_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D13_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_D14_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D14_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_D15_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_D15_PIN); + + // 控制信号配置 + gpio_af_set(BSP_EXMC_SDRAM_NBL0_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_NBL0_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_NBL0_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_NBL0_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_NBL0_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_NBL0_PIN); + + gpio_af_set(BSP_EXMC_SDRAM_NBL1_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_NBL1_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_NBL1_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_NBL1_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_NBL1_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_NBL1_PIN); + + // 时钟使能 + gpio_af_set(BSP_EXMC_SDRAM_CEK0_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_CEK0_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_CEK0_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_CEK0_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_CEK0_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_CEK0_PIN); + + // bank 地址 + gpio_af_set(BSP_EXMC_SDRAM_BA0_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_BA0_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_BA0_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_BA0_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_BA0_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_BA0_PIN); + + gpio_af_set(BSP_EXMC_SDRAM_BA1_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_BA1_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_BA1_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_BA1_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_BA1_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_BA1_PIN); + + // 时钟信号线 + gpio_af_set(BSP_EXMC_SDRAM_CLK_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_CLK_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_CLK_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_CLK_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_CLK_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_CLK_PIN); + + // 列地址选通 + gpio_af_set(BSP_EXMC_SDRAM_NCAS_PORT, GPIO_AF_12, BSP_FMSC_SDR_NCAS_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_NCAS_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_FMSC_SDR_NCAS_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_NCAS_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_FMSC_SDR_NCAS_PIN); + + // 行地址选通 + gpio_af_set(BSP_EXMC_SDRAM_NRAS_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_NRAS_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_NRAS_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_NRAS_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_NRAS_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_NRAS_PIN); + + // 输出使能 + gpio_af_set(BSP_EXMC_SDRAM_NEO_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_NEO_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_NEO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_NEO_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_NEO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_NEO_PIN); + + // 写使能 + gpio_af_set(BSP_EXMC_SDRAM_NWE_PORT, GPIO_AF_12, BSP_EXMC_SDRAM_NWE_PIN); + gpio_mode_set(BSP_EXMC_SDRAM_NWE_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_EXMC_SDRAM_NWE_PIN); + gpio_output_options_set(BSP_EXMC_SDRAM_NWE_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_EXMC_SDRAM_NWE_PIN); + + exmc_sdram_timing_parameter_struct sdram_timing_init_struct; + exmc_sdram_parameter_struct sdram_init_struct; + + /* 当前工程中 EXMC 时钟配置为 SDCLK = HCLK / 2 */ + uint32_t hclk_hz = rcu_clock_freq_get(CK_AHB); + uint32_t sdclk_hz = hclk_hz / 2U; + if (0U == sdclk_hz) + { + sdclk_hz = 120000000U; /* 兜底使用 120MHz,避免除零导致的配置错误 */ + } + + /*--------------- 步骤1:根据芯片手册计算时序寄存器 ----------------*/ + sdram_timing_init_struct.load_mode_register_delay = SDRAM_TMRD_CYCLES; /* tMRD */ + sdram_timing_init_struct.exit_selfrefresh_delay = sdram_ns_to_cycles(SDRAM_TXSR_NS, sdclk_hz); /* tXSR */ + sdram_timing_init_struct.row_address_select_delay = sdram_ns_to_cycles(SDRAM_TRAS_NS, sdclk_hz); /* tRAS */ + sdram_timing_init_struct.auto_refresh_delay = sdram_ns_to_cycles(SDRAM_TRFC_NS, sdclk_hz); /* tRFC */ + sdram_timing_init_struct.write_recovery_delay = sdram_ns_to_cycles(SDRAM_TWR_NS, sdclk_hz); /* tWR */ + sdram_timing_init_struct.row_precharge_delay = sdram_ns_to_cycles(SDRAM_TRP_NS, sdclk_hz); /* tRP */ + sdram_timing_init_struct.row_to_column_delay = sdram_ns_to_cycles(SDRAM_TRCD_NS, sdclk_hz); /* tRCD */ + + /*--------------- 步骤2:配置 SDRAM 控制寄存器 -----------------------*/ + sdram_init_struct.sdram_device = BSP_SDRAM_EXMC; /* 仅使用设备 0 */ + sdram_init_struct.column_address_width = EXMC_SDRAM_COW_ADDRESS_9; /* 9 位列地址 */ + sdram_init_struct.row_address_width = EXMC_SDRAM_ROW_ADDRESS_13; /* 13 位行地址 */ + sdram_init_struct.data_width = EXMC_SDRAM_DATABUS_WIDTH_16B; /* 16 位数据总线 */ + sdram_init_struct.internal_bank_number = EXMC_SDRAM_4_INTER_BANK; /* 4 个内部 bank */ + sdram_init_struct.cas_latency = EXMC_CAS_LATENCY_3_SDCLK; /* 使用 CAS = 3 满足 166MHz 要求 */ + sdram_init_struct.write_protection = DISABLE; /* 允许写入 */ + sdram_init_struct.sdclock_config = EXMC_SDCLK_PERIODS_2_HCLK; /* SDCLK = HCLK / 2 */ + sdram_init_struct.burst_read_switch = ENABLE; /* 启用突发读 */ + sdram_init_struct.pipeline_read_delay = EXMC_PIPELINE_DELAY_1_HCLK; /* 1 个 HCLK 延迟 */ + sdram_init_struct.timing = &sdram_timing_init_struct; /* 绑定时序结构体 */ + + /*--------------- 步骤3:写入硬件寄存器 -------------------------------*/ + exmc_sdram_init(&sdram_init_struct); +} diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_gpio.c b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_gpio.c new file mode 100644 index 0000000..e09dea1 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_gpio.c @@ -0,0 +1,30 @@ +#include "bsp_gpio.h" + +/** + * @brief 初始化统一配置的GPIO外设引脚 + * @details 配置需要统一管理的GPIO引脚,包括: + * - LCD控制引脚:CS、RESET、DC信号 + * @param None + * @retval None + * @note 此函数配置不适合分散到各个外设模块中的GPIO引脚 + * @note 各个外设专用的GPIO引脚已移到对应的外设初始化函数中配置 + */ +void BSP_GPIO_Init(void) +{ + // 使能GPIO时钟 + rcu_periph_clock_enable(RCU_GPIOA); /* LCD控制引脚 */ + rcu_periph_clock_enable(RCU_GPIOF); /* LCD复位引脚 */ + + /*=== LCD控制引脚 ===*/ + // CS + gpio_mode_set(BSP_SPI_LCD_CS_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, BSP_SPI_LCD_CS_PIN); + gpio_output_options_set(BSP_SPI_LCD_CS_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_SPI_LCD_CS_PIN); + + // RESET + gpio_mode_set(BSP_SPI_LCD_RESET_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, BSP_SPI_LCD_RESET_PIN); + gpio_output_options_set(BSP_SPI_LCD_RESET_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_SPI_LCD_RESET_PIN); + + // DC + gpio_mode_set(BSP_SPI_LCD_DC_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, BSP_SPI_LCD_DC_PIN); + gpio_output_options_set(BSP_SPI_LCD_DC_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_SPI_LCD_DC_PIN); +} \ No newline at end of file diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_iic.c b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_iic.c new file mode 100644 index 0000000..033e329 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_iic.c @@ -0,0 +1,50 @@ +#include "bsp_iic.h" + +/** + * @brief I2C外设初始化函数 + * @details 初始化EEPROM使用的I2C外设,包括GPIO配置和I2C参数设置 + * + * @param None + * @retval None + * @note 该函数配置I2C速率为400KHz,使用开漏输出模式,GPIO设置为复用功能4 + * @warning 调用此函数前确保相关GPIO和I2C外设未被其他模块占用 + * + * 配置详情: + * - I2C速率:400KHz + * - GPIO模式:复用功能,上拉电阻,开漏输出 + * - GPIO速度:50MHz + * - I2C地址格式:7位地址模式 + * - 主机地址:0x01 + * + * @example + * @code + * // 在系统初始化时调用 + * BSP_IIC_Init(); + * @endcode + */ +void BSP_IIC_Init(void) +{ + // 使能I2C和GPIO时钟 + rcu_periph_clock_enable(RCU_GPIOB); /* I2C SDA、SCL引脚 */ + rcu_periph_clock_enable(BSP_EEPROM_IIC_RCU); /* I2C0外设时钟 */ + + // I2C GPIO配置 + gpio_af_set(BSP_IIC_EEPROM_SDA_PORT, GPIO_AF_4, BSP_IIC_EEPROM_SDA_PIN); + gpio_af_set(BSP_IIC_EEPROM_SCL_PORT, GPIO_AF_4, BSP_IIC_EEPROM_SCL_PIN); + + // SDA + gpio_mode_set(BSP_IIC_EEPROM_SDA_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_IIC_EEPROM_SDA_PIN); + gpio_output_options_set(BSP_IIC_EEPROM_SDA_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, BSP_IIC_EEPROM_SDA_PIN); + + // SCL + gpio_mode_set(BSP_IIC_EEPROM_SCL_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_IIC_EEPROM_SCL_PIN); + gpio_output_options_set(BSP_IIC_EEPROM_SCL_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, BSP_IIC_EEPROM_SCL_PIN); + + // iic + i2c_deinit(BSP_EEPROM_IIC); + i2c_clock_config(BSP_EEPROM_IIC, 400000, I2C_DTCY_2); // 配置iic速率400K + i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x01); // 设置主机地址 + i2c_ack_config(BSP_EEPROM_IIC, I2C_ACK_ENABLE); // 启动iic应答 + + i2c_enable(BSP_EEPROM_IIC); +} diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_ipa.c b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_ipa.c new file mode 100644 index 0000000..2e67dc1 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_ipa.c @@ -0,0 +1,21 @@ +#include "bsp_ipa.h" + +/** + * @brief 初始化 IPA 外设 + * @details 使能 IPA 时钟,配置中断(可选) + * - IPA(图像像素加速器):用于图形加速,支持像素格式转换、Alpha 混合、纯色填充等 + * @param None + * @retval None + * @note 必须在使用 IPA 功能之前调用此函数 + */ +void BSP_IPA_Init(void) +{ + // 使能 IPA 时钟 + rcu_periph_clock_enable(RCU_IPA); + + // 反初始化 IPA(复位到默认状态) + ipa_deinit(); + + // 如果需要使用中断模式,配置 NVIC + // nvic_irq_enable(IPA_IRQn, 2, 0); +} diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_led_key.c b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_led_key.c new file mode 100644 index 0000000..dc1165a --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_led_key.c @@ -0,0 +1,69 @@ +#include "bsp_led_key.h" + +/** + * @brief 初始化LED和按键GPIO + * @details 该函数初始化所有LED和按键相关的GPIO引脚,包括: + * - 使能GPIOA、GPIOB、GPIOD、GPIOE、GPIOG时钟 + * - 配置LED1-LED4为输出模式,下拉电阻 + * - 配置按键L、A、B、R为输入模式,上拉电阻 + * - 设置LED输出为推挽输出,50MHz速度 + * - 初始化所有LED为熄灭状态 + * @param 无 + * @retval 无 + */ +void BSP_LED_Key_Init(void) +{ + // 使能GPIO时钟 + rcu_periph_clock_enable(RCU_GPIOA); /* LED4、Key L */ + rcu_periph_clock_enable(RCU_GPIOB); /* Key A、Key B */ + rcu_periph_clock_enable(RCU_GPIOD); /* LED2 */ + rcu_periph_clock_enable(RCU_GPIOE); /* LED1 */ + rcu_periph_clock_enable(RCU_GPIOG); /* LED3、Key A */ + + // LED GPIO配置 + gpio_mode_set(BSP_LED1_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLDOWN, BSP_LED1_PIN); + gpio_mode_set(BSP_LED2_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLDOWN, BSP_LED2_PIN); + gpio_mode_set(BSP_LED3_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLDOWN, BSP_LED3_PIN); + gpio_mode_set(BSP_LED4_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLDOWN, BSP_LED4_PIN); + + gpio_output_options_set(BSP_LED1_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_LED1_PIN); + gpio_output_options_set(BSP_LED2_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_LED2_PIN); + gpio_output_options_set(BSP_LED3_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_LED3_PIN); + gpio_output_options_set(BSP_LED4_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_LED4_PIN); + + // Key GPIO配置 + gpio_mode_set(BSP_KEY_L_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, BSP_KEY_L_PIN); + gpio_mode_set(BSP_KEY_A_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, BSP_KEY_A_PIN); + gpio_mode_set(BSP_KEY_B_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, BSP_KEY_B_PIN); + gpio_mode_set(BSP_KEY_R_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, BSP_KEY_R_PIN); + + // LED Off + gpio_bit_reset(BSP_LED1_PORT, BSP_LED1_PIN); + gpio_bit_reset(BSP_LED2_PORT, BSP_LED2_PIN); + gpio_bit_reset(BSP_LED3_PORT, BSP_LED3_PIN); + gpio_bit_reset(BSP_LED4_PORT, BSP_LED4_PIN); +} + +/** + * @brief 读取按键状态 + * @details 该函数读取所有按键的状态并返回按键值。 + * 按键优先级:L > R > A > B + * 当多个按键同时按下时,返回优先级最高的按键值 + * @param 无 + * @retval KeyVal_t 按键值,枚举类型: + * - KEY_VAL_NONE: 无按键按下 + * - KEY_VAL_L: 左键按下 + * - KEY_VAL_R: 右键按下 + * - KEY_VAL_A: A键按下 + * - KEY_VAL_B: B键按下 + */ +KeyVal_t BSP_KeyRead(void) +{ + KeyVal_t temp = KEY_VAL_NONE; + if (gpio_input_bit_get(BSP_KEY_L_PORT, BSP_KEY_L_PIN) == 1) temp = KEY_VAL_L; + if (gpio_input_bit_get(BSP_KEY_R_PORT, BSP_KEY_R_PIN) == 1) temp = KEY_VAL_R; + if (gpio_input_bit_get(BSP_KEY_A_PORT, BSP_KEY_A_PIN) == 1) temp = KEY_VAL_A; + if (gpio_input_bit_get(BSP_KEY_B_PORT, BSP_KEY_B_PIN) == 1) temp = KEY_VAL_B; + + return temp; +} \ No newline at end of file diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_sdio.c b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_sdio.c new file mode 100644 index 0000000..a20f14b --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_sdio.c @@ -0,0 +1,41 @@ +#include "bsp_sdio.h" + +void BSP_SDIO_Init(void) +{ + /* 打开SDIO与相关GPIO时钟 */ + rcu_periph_clock_enable(BSP_SDIO_RCU); + rcu_periph_clock_enable(RCU_GPIOC); + rcu_periph_clock_enable(RCU_GPIOD); + + /* 复用功能映射 */ + gpio_af_set(BSP_SDIO_D0_PORT, GPIO_AF_12, BSP_SDIO_D0_PIN); + gpio_af_set(BSP_SDIO_D1_PORT, GPIO_AF_12, BSP_SDIO_D1_PIN); + gpio_af_set(BSP_SDIO_D2_PORT, GPIO_AF_12, BSP_SDIO_D2_PIN); + gpio_af_set(BSP_SDIO_D3_PORT, GPIO_AF_12, BSP_SDIO_D3_PIN); + gpio_af_set(BSP_SDIO_CLK_PORT, GPIO_AF_12, BSP_SDIO_CLK_PIN); + gpio_af_set(BSP_SDIO_CMD_PORT, GPIO_AF_12, BSP_SDIO_CMD_PIN); + + /* 数据线上拉,推挽输出 */ + gpio_mode_set(BSP_SDIO_D0_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_SDIO_D0_PIN); + gpio_mode_set(BSP_SDIO_D1_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_SDIO_D1_PIN); + gpio_mode_set(BSP_SDIO_D2_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_SDIO_D2_PIN); + gpio_mode_set(BSP_SDIO_D3_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_SDIO_D3_PIN); + gpio_output_options_set(BSP_SDIO_D0_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, BSP_SDIO_D0_PIN); + gpio_output_options_set(BSP_SDIO_D1_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, BSP_SDIO_D1_PIN); + gpio_output_options_set(BSP_SDIO_D2_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, BSP_SDIO_D2_PIN); + gpio_output_options_set(BSP_SDIO_D3_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, BSP_SDIO_D3_PIN); + + /* 时钟线浮空输入,推挽输出 */ + gpio_mode_set(BSP_SDIO_CLK_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_SDIO_CLK_PIN); + gpio_output_options_set(BSP_SDIO_CLK_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, BSP_SDIO_CLK_PIN); + + /* CMD线上拉 */ + gpio_mode_set(BSP_SDIO_CMD_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_SDIO_CMD_PIN); + gpio_output_options_set(BSP_SDIO_CMD_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, BSP_SDIO_CMD_PIN); + + /* 复位SDIO外设,保持在默认状态 */ + sdio_deinit(); + sdio_clock_disable(); + + nvic_irq_enable(BSP_SDIO_IRQ, 1, 0); +} \ No newline at end of file diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_spi.c b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_spi.c new file mode 100644 index 0000000..39fb9bb --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_spi.c @@ -0,0 +1,55 @@ +#include "bsp_spi.h" + +/** + * @brief 初始化SPI外设 + * @details 该函数配置并使能SPI外设,包括: + * - 使能SPI和GPIO时钟 + * - 配置SPI引脚为复用功能模式 + * - 配置SPI为主机模式,全双工通信 + * - 设置8位数据帧,MSB先行 + * - 配置时钟极性和相位 + * - 设置软件片选,并初始化片选信号为低电平 + * @param 无 + * @retval 无 + */ +void BSP_SPI_Init(void) +{ + // 外设时钟开启 + rcu_periph_clock_enable(RCU_GPIOF); /* SPI Flash通信引脚 */ + rcu_periph_clock_enable(BSP_SPI_FLASH_RCU); /* SPI4外设时钟 */ + + // 设置复用引脚 LCD 和 Flash 公用一个SPI 所以只用初始化一次 + gpio_af_set(BSP_SPI_FLASH_DI_PORT, GPIO_AF_5, BSP_SPI_FLASH_DI_PIN); + gpio_af_set(BSP_SPI_FLASH_DO_PORT, GPIO_AF_5, BSP_SPI_FLASH_DO_PIN); + gpio_af_set(BSP_SPI_FLASH_CK_PORT, GPIO_AF_5, BSP_SPI_FLASH_CK_PIN); + + // 设置IO模式 + gpio_mode_set(BSP_SPI_FLASH_DI_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_SPI_FLASH_DI_PIN); + gpio_mode_set(BSP_SPI_FLASH_DO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_SPI_FLASH_DO_PIN); + gpio_mode_set(BSP_SPI_FLASH_CK_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_SPI_FLASH_CK_PIN); + + // 设置输出模式 + gpio_output_options_set(BSP_SPI_FLASH_DI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_SPI_FLASH_DI_PIN); + gpio_output_options_set(BSP_SPI_FLASH_DO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_SPI_FLASH_DO_PIN); + gpio_output_options_set(BSP_SPI_FLASH_CK_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_SPI_FLASH_CK_PIN); + + // 配置CS片选模式 + gpio_mode_set(BSP_SPI_FLASH_CS_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, BSP_SPI_FLASH_CS_PIN); + gpio_output_options_set(BSP_SPI_FLASH_CS_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_SPI_FLASH_CS_PIN); + + // 配置SPI + spi_parameter_struct bsp_spi_init_struct; + spi_struct_para_init(&bsp_spi_init_struct); + bsp_spi_init_struct.device_mode = SPI_MASTER; // 主机 + bsp_spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; // 全双工 + bsp_spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT; // 8位数据 + bsp_spi_init_struct.nss = SPI_NSS_SOFT; // 软件片选 + bsp_spi_init_struct.endian = SPI_ENDIAN_MSB; // MSB + bsp_spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE; // 极性相位 + bsp_spi_init_struct.prescale = SPI_PSC_2; // 预分频器因数为2 + + spi_init(BSP_FLASH_SPI, &bsp_spi_init_struct); + spi_enable(BSP_FLASH_SPI); // 使能SPI + + gpio_bit_reset(BSP_SPI_FLASH_CS_PORT, BSP_SPI_FLASH_CS_PIN); // 拉低片选 +} diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_timer.c b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_timer.c new file mode 100644 index 0000000..1ba83b5 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_timer.c @@ -0,0 +1,240 @@ +#include "bsp_timer.h" + +/** + * @brief 初始化BSP定时器,1ms中断间隔 + * @details 该函数配置并使能BSP定时器,用于产生1ms周期性中断。 + * 定时器配置如下: + * - 时钟预分频:2倍频 (100MHz) + * - 预分频器:100-1 + * - 周期:1000-1 (1ms间隔) + * - 向上计数模式 + * - 边缘对齐 + * @param 无 + * @retval 无 + */ +void BSP_Timer_Tick_Init(void) +{ + // 使能定时器时钟 + rcu_periph_clock_enable(BSP_TIMER_TICK_RCU); + /* + APB1、APB2总线的定时器的时钟都为2倍频 + APB1 -> 60MHz + APB2 -> 120MHz + 所以2倍频最可靠(因为所有的定时器不能超过240MHz) + */ + rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL2); // 二倍频 60 * 2 = 120 MHz + + timer_deinit(BSP_TIMER_TICK); + + timer_parameter_struct bsp_timer_tick_init_struct; + + bsp_timer_tick_init_struct.counterdirection = TIMER_COUNTER_UP; // 向上计数 + bsp_timer_tick_init_struct.alignedmode = TIMER_COUNTER_EDGE; // 边缘对齐 + bsp_timer_tick_init_struct.prescaler = 120 - 1; // 预分频器 120 分频 + bsp_timer_tick_init_struct.period = 1000 - 1; // 计数器 1000 -> 1ms + + /* 在输入捕获的时候使用 数字滤波器使用的采样频率之间的分频比例 */ + bsp_timer_tick_init_struct.clockdivision = TIMER_CKDIV_DIV1; // 分频因子 + /* 只有高级定时器才有 配置为x,就重复x+1次进入中断 */ + bsp_timer_tick_init_struct.repetitioncounter = 0; // 重复计数器 0-255 + + timer_init(BSP_TIMER_TICK, &bsp_timer_tick_init_struct); + + timer_interrupt_flag_clear(BSP_TIMER_TICK, TIMER_INT_FLAG_UP); + + timer_interrupt_enable(BSP_TIMER_TICK, TIMER_INT_UP); + + nvic_irq_enable(BSP_TIMER_TICK_IRQ, 0x00UL, 0x00UL); + + // 启动定时器 + timer_enable(BSP_TIMER_TICK); +} + +/** + * @brief 初始化LCD背光PWM控制定时器 + * @details 该函数配置并使能定时器2用于PWM输出,控制LCD背光亮度。 + * 定时器配置如下: + * - 时钟源:APB1总线,经2倍频后为120MHz + * - 预分频器:12000-1分频,得到10kHz计数频率 + * - 周期:100-1,即100个计数周期,产生100Hz PWM频率 + * - PWM模式:PWM模式0(向上计数,占空比=脉冲值/周期) + * - 输出极性:高电平有效 + * - GPIO配置:PA7复用为定时器2通道1功能 + * + * PWM参数计算: + * - 系统时钟:120MHz(APB1×2) + * - PWM频率:10kHz / 100 = 100Hz + * - 占空比范围:0-100(对应LCD_SetBlk函数的参数) + * + * @param 无 + * @note 该函数初始化的PWM输出由LCD_SetBlk()函数使用 + * @note PWM输出引脚为PA7(定时器2通道1) + * @note 初始PWM占空比为0,即背光默认关闭 + * @retval 无 + */ +void BSP_Timer_LCD_Init(void) +{ + // 使能定时器和GPIO时钟 + rcu_periph_clock_enable(BSP_PWM_LCD_TIMER_RCU); + rcu_periph_clock_enable(RCU_GPIOA); + + // 配置PWM输出引脚 + gpio_mode_set(BSP_PWM_LCD_BLK_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM_LCD_BLK_PIN); + gpio_output_options_set(BSP_PWM_LCD_BLK_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_PWM_LCD_BLK_PIN); + gpio_af_set(BSP_PWM_LCD_BLK_PORT, GPIO_AF_2, BSP_PWM_LCD_BLK_PIN); + + // timer2 cfg -> APB1总线 二倍频 120M + timer_deinit(BSP_PWM_LCD_TIMER); + timer_parameter_struct bsp_pwm_lcd_timer_base_init_struct; + timer_struct_para_init(&bsp_pwm_lcd_timer_base_init_struct); + bsp_pwm_lcd_timer_base_init_struct.prescaler = 12000 - 1; // -> 1M + bsp_pwm_lcd_timer_base_init_struct.period = 100 - 1; // 100Hz + bsp_pwm_lcd_timer_base_init_struct.alignedmode = TIMER_COUNTER_EDGE; + bsp_pwm_lcd_timer_base_init_struct.counterdirection = TIMER_COUNTER_UP; // 向上计数 + + timer_init(BSP_PWM_LCD_TIMER, &bsp_pwm_lcd_timer_base_init_struct); + + // oc cfg + timer_oc_parameter_struct bsp_pwm_lcd_timer_oc_init_struct; + timer_channel_output_struct_para_init(&bsp_pwm_lcd_timer_oc_init_struct); + bsp_pwm_lcd_timer_oc_init_struct.ocpolarity = TIMER_OC_POLARITY_HIGH; + bsp_pwm_lcd_timer_oc_init_struct.outputstate = TIMER_CCX_ENABLE; + timer_channel_output_config(BSP_PWM_LCD_TIMER, BSP_PWM_LCD_BLK_CH, &bsp_pwm_lcd_timer_oc_init_struct); + + // 配置定时器通道输出脉冲值 + timer_channel_output_pulse_value_config(BSP_PWM_LCD_TIMER, BSP_PWM_LCD_BLK_CH, 0); + + // 配置定时器通道输出比较模式 + timer_channel_output_mode_config(BSP_PWM_LCD_TIMER, BSP_PWM_LCD_BLK_CH, TIMER_OC_MODE_PWM0); + + // 配置定时器通道输出影子寄存器 + timer_channel_output_shadow_config(BSP_PWM_LCD_TIMER, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE); + + /* auto-reload preload enable */ + timer_auto_reload_shadow_enable(BSP_PWM_LCD_TIMER); + + timer_enable(BSP_PWM_LCD_TIMER); +} + +/** + * @brief 初始化电机PWM定时器 + * @details 配置TIMER1作为电机驱动PWM信号的定时器。 + * - 时钟源:APB1总线,120MHz经过2倍频 + * - 定时器频率:1MHz (120MHz/120) + * - PWM频率:100Hz (1MHz/1000) + * - 输出通道:TIMER1通道2(PA2引脚) + * - PWM模式:边沿对齐PWM模式0 + * - 初始占空比:0% (电机停止) + * + * @note 使用PA2引脚(TIMER1_CH2)输出PWM信号控制电机 + * @note PWM占空比范围:0-1000,对应0%-100% + * @note 定时器使能自动重装载预装载 + * @note 影子寄存器功能已禁用,立即更新占空比 + * @see Motor_SetDuty() 设置电机PWM占空比函数 + */ +void BSP_Timer_Motor_Init(void) +{ + // 使能定时器和GPIO时钟 + rcu_periph_clock_enable(BSP_PWM_MOTOR_TIMER_RCU); + rcu_periph_clock_enable(RCU_GPIOA); + + // 配置PWM输出引脚 + gpio_mode_set(BSP_PWM_MOTOR_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM_MOTOR_PIN); + gpio_output_options_set(BSP_PWM_MOTOR_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_PWM_MOTOR_PIN); + gpio_af_set(BSP_PWM_MOTOR_PORT, GPIO_AF_1, BSP_PWM_MOTOR_PIN); + + // timer1 cfg -> APB1总线 二倍频 120M + timer_deinit(BSP_PWM_MOTOR_TIMER); + timer_parameter_struct bsp_pwm_motor_timer_base_init_struct; + timer_struct_para_init(&bsp_pwm_motor_timer_base_init_struct); + bsp_pwm_motor_timer_base_init_struct.prescaler = 120 - 1; // -> 1M + bsp_pwm_motor_timer_base_init_struct.period = 1000 - 1; // 100Hz + bsp_pwm_motor_timer_base_init_struct.alignedmode = TIMER_COUNTER_EDGE; + bsp_pwm_motor_timer_base_init_struct.counterdirection = TIMER_COUNTER_UP; // 向上计数 + timer_init(BSP_PWM_MOTOR_TIMER, &bsp_pwm_motor_timer_base_init_struct); + + // oc cfg + timer_oc_parameter_struct bsp_pwm_motor_timer_oc_init_struct; + timer_channel_output_struct_para_init(&bsp_pwm_motor_timer_oc_init_struct); + bsp_pwm_motor_timer_oc_init_struct.ocpolarity = TIMER_OC_POLARITY_HIGH; + bsp_pwm_motor_timer_oc_init_struct.outputstate = TIMER_CCX_ENABLE; + timer_channel_output_config(BSP_PWM_MOTOR_TIMER, BSP_PWM_MOTOR_CH, &bsp_pwm_motor_timer_oc_init_struct); + + // 配置定时器通道输出脉冲值 + timer_channel_output_pulse_value_config(BSP_PWM_MOTOR_TIMER, BSP_PWM_MOTOR_CH, 0); + + // 配置定时器通道输出比较模式 + timer_channel_output_mode_config(BSP_PWM_MOTOR_TIMER, BSP_PWM_MOTOR_CH, TIMER_OC_MODE_PWM0); + + // 配置定时器通道输出影子寄存器 + timer_channel_output_shadow_config(BSP_PWM_MOTOR_TIMER, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE); + + /* auto-reload preload enable */ + timer_auto_reload_shadow_enable(BSP_PWM_MOTOR_TIMER); + + timer_enable(BSP_PWM_MOTOR_TIMER); +} + +/** + * @brief 初始化DAC音频定时器 + * @note 配置TIMER7作为DAC的触发源 + * 定时器周期参数将在audio.c中根据实际采样率需求进行设置 + * @param 无 + * @retval 无 + */ +void BSP_Timer_DAC_Init(void) +{ + // 使能音频定时器时钟 + rcu_periph_clock_enable(BSP_AUDIO_TIMER_RCU); + + // timer7 cfg -> APB2总线 二倍频 240M + timer_deinit(BSP_AUDIO_TIMER); + timer_parameter_struct bsp_dac_timer_base_init_struct; + timer_struct_para_init(&bsp_dac_timer_base_init_struct); + bsp_dac_timer_base_init_struct.alignedmode = TIMER_COUNTER_EDGE; + bsp_dac_timer_base_init_struct.counterdirection = TIMER_COUNTER_UP; + bsp_dac_timer_base_init_struct.clockdivision = TIMER_CKDIV_DIV1; + + bsp_dac_timer_base_init_struct.prescaler = 2 - 1; + bsp_dac_timer_base_init_struct.period = 5442 - 1; + // -> 22050 HZ + + timer_init(BSP_AUDIO_TIMER, &bsp_dac_timer_base_init_struct); + + // 开启影子寄存器 + timer_auto_reload_shadow_enable(BSP_AUDIO_TIMER); + + // 开启定时器溢出事件 + timer_update_event_enable(BSP_AUDIO_TIMER); + + // 触发事件输出 + timer_master_output_trigger_source_select(BSP_AUDIO_TIMER, TIMER_TRI_OUT_SRC_UPDATE); + timer_master_slave_mode_config(BSP_AUDIO_TIMER, TIMER_MASTER_SLAVE_MODE_ENABLE); +} + +/** + * @brief 初始化Debug使用的定时器 + * @note 配置TIMER4 + * 由FreeRTOS来使用 + * @param 无 + * @retval 无 + */ +void BSP_Timer_Debug_Init(void) +{ + rcu_periph_clock_enable(BSP_DEBUG_TIMER_RCU); + + // timer4: APB1 -> 60 * 2 = 120M(32 bit cnt) + timer_deinit(BSP_DEBUG_TIMER); + timer_parameter_struct bsp_debug_timer_base_init_struct; + timer_struct_para_init(&bsp_debug_timer_base_init_struct); + bsp_debug_timer_base_init_struct.alignedmode = TIMER_COUNTER_EDGE; + bsp_debug_timer_base_init_struct.counterdirection = TIMER_COUNTER_UP; + bsp_debug_timer_base_init_struct.clockdivision = TIMER_CKDIV_DIV1; + + bsp_debug_timer_base_init_struct.prescaler = 120 - 1; // -> 1M + bsp_debug_timer_base_init_struct.period = 0xFFFFFFFF; //最大计数值 + + timer_init(BSP_DEBUG_TIMER, &bsp_debug_timer_base_init_struct); + + timer_enable(BSP_DEBUG_TIMER); +} \ No newline at end of file diff --git a/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_usart.c b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_usart.c new file mode 100644 index 0000000..1f3c024 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/Src/bsp_usart.c @@ -0,0 +1,52 @@ +#include "bsp_usart.h" + +/** + * @brief 初始化USART串口 + * @details 该函数配置并使能USART串口,包括: + * - 使能USART和GPIO时钟 + * - 配置TX和RX引脚为复用功能模式 + * - 设置串口参数:波特率、8数据位、1停止位、无校验 + * - 禁用硬件流控制 + * - 使能发送和接收功能 + * @param baud_rate: 串口波特率 + * @retval 无 + */ +void BSP_USART_Init(uint32_t baud_rate) +{ + // Clock On + rcu_periph_clock_enable(RCU_GPIOA); /* USART TX、RX引脚 */ + rcu_periph_clock_enable(RCU_USART0); /* USART0外设时钟 */ + rcu_periph_clock_enable(RCU_DMA1); /* USART DMA时钟 */ + + // GPIO AF Init + gpio_af_set(BSP_USART_TX_PORT, GPIO_AF_7, BSP_USART_TX_PIN); + gpio_af_set(BSP_USART_RX_PORT, GPIO_AF_7, BSP_USART_RX_PIN); + + gpio_mode_set(BSP_USART_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_USART_TX_PIN); + gpio_mode_set(BSP_USART_RX_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_USART_RX_PIN); + + gpio_output_options_set(BSP_USART_TX_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_USART_TX_PIN); + gpio_output_options_set(BSP_USART_RX_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_USART_RX_PIN); + + // USART Init + usart_deinit(BSP_USART); // 复位串口 + usart_baudrate_set(BSP_USART, baud_rate); // 设置波特率 + usart_parity_config(BSP_USART, USART_PM_NONE); // 没有校验位 + usart_word_length_set(BSP_USART, USART_WL_8BIT); // 8位数据位 + usart_stop_bit_set(BSP_USART, USART_STB_1BIT); // 1位停止位 + usart_hardware_flow_rts_config(BSP_USART, USART_RTS_DISABLE); + usart_hardware_flow_cts_config(BSP_USART, USART_CTS_DISABLE); + + // Enable UART + usart_transmit_config(BSP_USART, USART_TRANSMIT_ENABLE); // 使能串口发送 + usart_receive_config(BSP_USART, USART_RECEIVE_ENABLE); // 使能串口接收 + + // DMA + usart_dma_transmit_config(BSP_USART, USART_TRANSMIT_DMA_ENABLE); + usart_dma_receive_config(BSP_USART, USART_RECEIVE_DMA_ENABLE); + + // NVIC + nvic_irq_enable(BSP_USART_IRQ, 7, 0); + + usart_enable(BSP_USART); // 使能串口 +} diff --git a/L1_MCU/GD32F470ZGT6/Bsp/bsp_interface.h b/L1_MCU/GD32F470ZGT6/Bsp/bsp_interface.h new file mode 100644 index 0000000..1459ad8 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/bsp_interface.h @@ -0,0 +1,17 @@ +#ifndef __BSP_INTERFACE_H +#define __BSP_INTERFACE_H + +#include "bsp_led_key.h" +#include "bsp_gpio.h" +#include "bsp_dma.h" +#include "bsp_timer.h" +#include "bsp_adc.h" +#include "bsp_spi.h" +#include "bsp_usart.h" +#include "bsp_iic.h" +#include "bsp_exmc.h" +#include "bsp_dac.h" +#include "bsp_sdio.h" +#include "bsp_ipa.h" + +#endif/* __BSP_INTERFACE_H */ diff --git a/L1_MCU/GD32F470ZGT6/Bsp/bsp_io_define.h b/L1_MCU/GD32F470ZGT6/Bsp/bsp_io_define.h new file mode 100644 index 0000000..2b63860 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Bsp/bsp_io_define.h @@ -0,0 +1,303 @@ +#ifndef __BSP_IO_DEFINE_H +#define __BSP_IO_DEFINE_H + +#include "main.h" + +//adc +#define BSP_ADC ADC0 +#define BSP_ADC_RCU RCU_ADC0 +#define BSP_ADC_DMA_RCU RCU_DMA1 +#define BSP_ADC_DMA DMA1 +#define BSP_ADC_DMA_CH DMA_CH0 + +#define BSP_JSK_X_PORT GPIOA +#define BSP_JSK_Y_PORT GPIOC +#define BSP_BAT_PORT GPIOB + +#define BSP_JSK_X_PIN GPIO_PIN_1 +#define BSP_JSK_Y_PIN GPIO_PIN_1 +#define BSP_BAT_PIN GPIO_PIN_1 + +#define BSP_JSK_X_ADC_CH ADC_CHANNEL_1 +#define BSP_JSK_Y_ADC_CH ADC_CHANNEL_11 +#define BSP_BAT_ADC_CH ADC_CHANNEL_9 +#define BSP_TEMP_ADC_CH ADC_CHANNEL_16 +#define BSP_VREF_ADC_CH ADC_CHANNEL_17 + +// led key +#define BSP_LED1_PORT GPIOE +#define BSP_LED2_PORT GPIOD +#define BSP_LED3_PORT GPIOG +#define BSP_LED4_PORT GPIOA +#define BSP_KEY_L_PORT GPIOA +#define BSP_KEY_A_PORT GPIOG +#define BSP_KEY_B_PORT GPIOB +#define BSP_KEY_R_PORT GPIOB + +#define BSP_LED1_PIN GPIO_PIN_3 +#define BSP_LED2_PIN GPIO_PIN_7 +#define BSP_LED3_PIN GPIO_PIN_3 +#define BSP_LED4_PIN GPIO_PIN_5 +#define BSP_KEY_L_PIN GPIO_PIN_0 +#define BSP_KEY_A_PIN GPIO_PIN_9 +#define BSP_KEY_B_PIN GPIO_PIN_15 +#define BSP_KEY_R_PIN GPIO_PIN_2 + +// timer +#define BSP_TIMER_TICK TIMER6 +#define BSP_TIMER_TICK_RCU RCU_TIMER6 +#define BSP_TIMER_TICK_IRQ TIMER6_IRQn // 定时器中断 +#define BSP_TickTimer_Handler TIMER6_IRQHandler + +// timer lcd +#define BSP_PWM_LCD_TIMER TIMER2 +#define BSP_PWM_LCD_TIMER_RCU RCU_TIMER2 +#define BSP_PWM_LCD_BLK_CH TIMER_CH_1 +#define BSP_PWM_LCD_BLK_PORT GPIOA +#define BSP_PWM_LCD_BLK_PIN GPIO_PIN_7 + +// motor +#define BSP_PWM_MOTOR_TIMER TIMER1 +#define BSP_PWM_MOTOR_TIMER_RCU RCU_TIMER1 +#define BSP_PWM_MOTOR_CH TIMER_CH_2 +#define BSP_PWM_MOTOR_PORT GPIOA +#define BSP_PWM_MOTOR_PIN GPIO_PIN_2 + +// iic +#define BSP_EEPROM_IIC I2C0 +#define BSP_EEPROM_IIC_RCU RCU_I2C0 + +#define BSP_IIC_EEPROM_SCL_PORT GPIOB +#define BSP_IIC_EEPROM_SCL_PIN GPIO_PIN_6 + +#define BSP_IIC_EEPROM_SDA_PORT GPIOB +#define BSP_IIC_EEPROM_SDA_PIN GPIO_PIN_7 + +// spi w25qxx +#define BSP_FLASH_SPI SPI4 +#define BSP_SPI_FLASH_RCU RCU_SPI4 + +#define BSP_SPI_FLASH_DI_PORT GPIOF +#define BSP_SPI_FLASH_DI_PIN GPIO_PIN_9 + +#define BSP_SPI_FLASH_DO_PORT GPIOF +#define BSP_SPI_FLASH_DO_PIN GPIO_PIN_8 + +#define BSP_SPI_FLASH_CK_PORT GPIOF +#define BSP_SPI_FLASH_CK_PIN GPIO_PIN_7 + +#define BSP_SPI_FLASH_CS_PORT GPIOF +#define BSP_SPI_FLASH_CS_PIN GPIO_PIN_6 + +// spi lcd +#define BSP_LCD_SPI SPI4 +#define BSP_SPI_FLASH_RCU RCU_SPI4 + +#define BSP_SPI_LCD_DC_PORT GPIOA +#define BSP_SPI_LCD_DC_PIN GPIO_PIN_6 + +#define BSP_SPI_LCD_CK_PORT GPIOF +#define BSP_SPI_LCD_CK_PIN GPIO_PIN_7 + +#define BSP_SPI_LCD_MOSI_PORT GPIOF +#define BSP_SPI_LCD_MOSI_PIN GPIO_PIN_9 + +#define BSP_SPI_LCD_CS_PORT GPIOA +#define BSP_SPI_LCD_CS_PIN GPIO_PIN_4 + +#define BSP_SPI_LCD_RESET_PORT GPIOF +#define BSP_SPI_LCD_RESET_PIN GPIO_PIN_10 + +// usart +#define BSP_USART USART0 +#define BSP_USART_DMA DMA1 + +#define BSP_USART_RCU RCU_USART0 +#define BSP_USART_DMA_RCU RCU_DMA1 +#define BSP_USART_DMA_TX_CH DMA_CH7 +#define BSP_USART_DMA_RX_CH DMA_CH5 + +#define BSP_USART_IRQ USART0_IRQn +#define BSP_USART_Handler USART0_IRQHandler + +#define BSP_USART_TX_PORT GPIOA +#define BSP_USART_RX_PORT GPIOA +#define BSP_USART_TX_PIN GPIO_PIN_9 +#define BSP_USART_RX_PIN GPIO_PIN_10 + +// exmc +// exmc addr +#define BSP_SDRAM_EXMC EXMC_SDRAM_DEVICE0 +#define BSP_SDRAM_EXMC_RCU RCU_EXMC + +#define BSP_EXMC_SDRAM_A0_PORT GPIOF +#define BSP_EXMC_SDRAM_A0_PIN GPIO_PIN_0 + +#define BSP_EXMC_SDRAM_A1_PORT GPIOF +#define BSP_EXMC_SDRAM_A1_PIN GPIO_PIN_1 + +#define BSP_EXMC_SDRAM_A2_PORT GPIOF +#define BSP_EXMC_SDRAM_A2_PIN GPIO_PIN_2 + +#define BSP_EXMC_SDRAM_A3_PORT GPIOF +#define BSP_EXMC_SDRAM_A3_PIN GPIO_PIN_3 + +#define BSP_EXMC_SDRAM_A4_PORT GPIOF +#define BSP_EXMC_SDRAM_A4_PIN GPIO_PIN_4 + +#define BSP_EXMC_SDRAM_A5_PORT GPIOF +#define BSP_EXMC_SDRAM_A5_PIN GPIO_PIN_5 + +#define BSP_EXMC_SDRAM_A6_PORT GPIOF +#define BSP_EXMC_SDRAM_A6_PIN GPIO_PIN_12 + +#define BSP_EXMC_SDRAM_A7_PORT GPIOF +#define BSP_EXMC_SDRAM_A7_PIN GPIO_PIN_13 + +#define BSP_EXMC_SDRAM_A8_PORT GPIOF +#define BSP_EXMC_SDRAM_A8_PIN GPIO_PIN_14 + +#define BSP_EXMC_SDRAM_A9_PORT GPIOF +#define BSP_EXMC_SDRAM_A9_PIN GPIO_PIN_15 + +#define BSP_EXMC_SDRAM_A10_PORT GPIOG +#define BSP_EXMC_SDRAM_A10_PIN GPIO_PIN_0 + +#define BSP_EXMC_SDRAM_A11_PORT GPIOG +#define BSP_EXMC_SDRAM_A11_PIN GPIO_PIN_1 + +#define BSP_EXMC_SDRAM_A12_PORT GPIOG +#define BSP_EXMC_SDRAM_A12_PIN GPIO_PIN_2 + +// exmc data +#define BSP_EXMC_SDRAM_D0_PORT GPIOD +#define BSP_EXMC_SDRAM_D0_PIN GPIO_PIN_14 + +#define BSP_EXMC_SDRAM_D1_PORT GPIOD +#define BSP_EXMC_SDRAM_D1_PIN GPIO_PIN_15 + +#define BSP_EXMC_SDRAM_D2_PORT GPIOD +#define BSP_EXMC_SDRAM_D2_PIN GPIO_PIN_0 + +#define BSP_EXMC_SDRAM_D3_PORT GPIOD +#define BSP_EXMC_SDRAM_D3_PIN GPIO_PIN_1 + +#define BSP_EXMC_SDRAM_D4_PORT GPIOE +#define BSP_EXMC_SDRAM_D4_PIN GPIO_PIN_7 + +#define BSP_EXMC_SDRAM_D5_PORT GPIOE +#define BSP_EXMC_SDRAM_D5_PIN GPIO_PIN_8 + +#define BSP_EXMC_SDRAM_D6_PORT GPIOE +#define BSP_EXMC_SDRAM_D6_PIN GPIO_PIN_9 + +#define BSP_EXMC_SDRAM_D7_PORT GPIOE +#define BSP_EXMC_SDRAM_D7_PIN GPIO_PIN_10 + +#define BSP_EXMC_SDRAM_D8_PORT GPIOE +#define BSP_EXMC_SDRAM_D8_PIN GPIO_PIN_11 + +#define BSP_EXMC_SDRAM_D9_PORT GPIOE +#define BSP_EXMC_SDRAM_D9_PIN GPIO_PIN_12 + +#define BSP_EXMC_SDRAM_D10_PORT GPIOE +#define BSP_EXMC_SDRAM_D10_PIN GPIO_PIN_13 + +#define BSP_EXMC_SDRAM_D11_PORT GPIOE +#define BSP_EXMC_SDRAM_D11_PIN GPIO_PIN_14 + +#define BSP_EXMC_SDRAM_D12_PORT GPIOE +#define BSP_EXMC_SDRAM_D12_PIN GPIO_PIN_15 + +#define BSP_EXMC_SDRAM_D13_PORT GPIOD +#define BSP_EXMC_SDRAM_D13_PIN GPIO_PIN_8 + +#define BSP_EXMC_SDRAM_D14_PORT GPIOD +#define BSP_EXMC_SDRAM_D14_PIN GPIO_PIN_9 + +#define BSP_EXMC_SDRAM_D15_PORT GPIOD +#define BSP_EXMC_SDRAM_D15_PIN GPIO_PIN_10 + +// exmc other +#define BSP_EXMC_SDRAM_NBL0_PORT GPIOE // 低字节控制 +#define BSP_EXMC_SDRAM_NBL0_PIN GPIO_PIN_0 + +#define BSP_EXMC_SDRAM_NBL1_PORT GPIOE // 高字节控制 +#define BSP_EXMC_SDRAM_NBL1_PIN GPIO_PIN_1 + +#define BSP_EXMC_SDRAM_CEK0_PORT GPIOC // 时钟使能 +#define BSP_EXMC_SDRAM_CEK0_PIN GPIO_PIN_3 + +#define BSP_EXMC_SDRAM_BA0_PORT GPIOG // bank 地址 A0 +#define BSP_EXMC_SDRAM_BA0_PIN GPIO_PIN_4 + +#define BSP_EXMC_SDRAM_BA1_PORT GPIOG // bank 地址 A1 +#define BSP_EXMC_SDRAM_BA1_PIN GPIO_PIN_5 + +#define BSP_EXMC_SDRAM_CLK_PORT GPIOG // 时钟信号线 +#define BSP_EXMC_SDRAM_CLK_PIN GPIO_PIN_8 + +#define BSP_EXMC_SDRAM_NCAS_PORT GPIOG // 列地址选通 低电平有效 +#define BSP_FMSC_SDR_NCAS_PIN GPIO_PIN_15 + +#define BSP_EXMC_SDRAM_NRAS_PORT GPIOF // 行地址选通 低电平有效 +#define BSP_EXMC_SDRAM_NRAS_PIN GPIO_PIN_11 + +#define BSP_EXMC_SDRAM_NEO_PORT GPIOC // 输出使能 低电平有效 +#define BSP_EXMC_SDRAM_NEO_PIN GPIO_PIN_2 + +#define BSP_EXMC_SDRAM_NWE_PORT GPIOC // 写使能 低电平有效 +#define BSP_EXMC_SDRAM_NWE_PIN GPIO_PIN_0 + +// dac +#define BSP_AUDIO_DAC DAC0 +#define BSP_AUDIO_DAC_RCU RCU_DAC +#define BSP_DAC_AUDIO_OUT DAC_OUT1 + +#define BSP_AUDIO_TIMER TIMER7 +#define BSP_AUDIO_TIMER_RCU RCU_TIMER7 +#define BSP_AUDIO_TIMER_IRQ TIMER7_UP_TIMER12_IRQn +#define BSP_AUDIO_TIMER_TRG_Handler TIMER7_UP_TIMER12_IRQHandler + +#define BSP_AUDIO_DMA DMA0 +#define BSP_AUDIO_DMA_RCU RCU_DMA0 +#define BSP_AUDIO_DMA_CH DMA_CH6 +#define BSP_AUDIO_DMA_IRQ DMA0_Channel6_IRQn +#define BSP_AUDIO_Finish_Handler DMA0_Channel6_IRQHandler + +#define BSP_DAC_AUDIO_OUT_PORT GPIOA +#define BSP_DAC_AUDIO_OUT_PIN GPIO_PIN_5 + +// SDIO +#define BSP_SDIO SDIO +#define BSP_SDIO_RCU RCU_SDIO +#define BSP_SDIO_IRQ SDIO_IRQn +#define BSP_SDIO_IRQ_Handler SDIO_IRQHandler + +#define BSP_SDIO_DMA DMA1 +#define BSP_SDIO_DMA_RCU RCU_DMA1 +#define BSP_SDIO_DMA_CH DMA_CH3 + +#define BSP_SDIO_D0_PORT GPIOC +#define BSP_SDIO_D0_PIN GPIO_PIN_8 + +#define BSP_SDIO_D1_PORT GPIOC +#define BSP_SDIO_D1_PIN GPIO_PIN_9 + +#define BSP_SDIO_D2_PORT GPIOC +#define BSP_SDIO_D2_PIN GPIO_PIN_10 + +#define BSP_SDIO_D3_PORT GPIOC +#define BSP_SDIO_D3_PIN GPIO_PIN_11 + +#define BSP_SDIO_CLK_PORT GPIOC +#define BSP_SDIO_CLK_PIN GPIO_PIN_12 + +#define BSP_SDIO_CMD_PORT GPIOD +#define BSP_SDIO_CMD_PIN GPIO_PIN_2 + +// Debug +#define BSP_DEBUG_TIMER TIMER4 +#define BSP_DEBUG_TIMER_RCU RCU_TIMER4 + +#endif /* __BSP_IO_DEFINE_H */ diff --git a/L1_MCU/GD32F470ZGT6/CMakeLists.txt b/L1_MCU/GD32F470ZGT6/CMakeLists.txt index 91f481c..76eabc8 100644 --- a/L1_MCU/GD32F470ZGT6/CMakeLists.txt +++ b/L1_MCU/GD32F470ZGT6/CMakeLists.txt @@ -4,6 +4,10 @@ set(GD_Include_Dir ${CMAKE_CURRENT_SOURCE_DIR}/Driver/Inc ${CMAKE_CURRENT_SOURCE_DIR}/Driver/CMSIS/Device/GD/GD32F4xx/Include ${CMAKE_CURRENT_SOURCE_DIR}/Driver/CMSIS/Include + ${CMAKE_CURRENT_SOURCE_DIR}/Bsp/Inc + ${CMAKE_CURRENT_SOURCE_DIR}/Hal/Inc + ${CMAKE_CURRENT_SOURCE_DIR}/Bsp + ${CMAKE_CURRENT_SOURCE_DIR}/Hal ) # 收集源文件 @@ -11,12 +15,17 @@ file(GLOB GD_Start_S ${CMAKE_CURRENT_SOURCE_DIR}/*.s) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/Core/Src GD_Core_Src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/Driver/Src GD_Std_Src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/Driver/CMSIS/Device/GD/GD32F4xx/Source GD_CMSIS_Src) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/Bsp/Src GD_Bsp_Src) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/Hal/Src GD_Hal_Src) + target_sources(l1_mcu PRIVATE ${GD_Start_S} ${GD_Core_Src} ${GD_Std_Src} ${GD_CMSIS_Src} + ${GD_Bsp_Src} + ${GD_Hal_Src} ) target_include_directories(l1_mcu PUBLIC @@ -25,6 +34,5 @@ target_include_directories(l1_mcu PUBLIC target_compile_definitions(l1_mcu PUBLIC GD32F470 - GD32F470ZGT6 $<$:DEBUG> ) diff --git a/L1_MCU/GD32F470ZGT6/Core/Inc/main.h b/L1_MCU/GD32F470ZGT6/Core/Inc/main.h index 8c65a42..5b4f41b 100644 --- a/L1_MCU/GD32F470ZGT6/Core/Inc/main.h +++ b/L1_MCU/GD32F470ZGT6/Core/Inc/main.h @@ -5,9 +5,8 @@ #include "systick.h" #include "gd32f4xx_libopt.h" -/* _assert */ -#define _assert(X) while ((X) == 0) -#define MAX_DELAY UINT32_MAX +/* ek_assert_param */ +#define MAX_DELAY UINT32_MAX void Error_Handler(void); diff --git a/L1_MCU/GD32F470ZGT6/Core/Src/gd32f4xx_it.c b/L1_MCU/GD32F470ZGT6/Core/Src/gd32f4xx_it.c index e7c0d9b..ceee5eb 100644 --- a/L1_MCU/GD32F470ZGT6/Core/Src/gd32f4xx_it.c +++ b/L1_MCU/GD32F470ZGT6/Core/Src/gd32f4xx_it.c @@ -1,6 +1,7 @@ #include "gd32f4xx_it.h" #include "main.h" #include "systick.h" +#include "bsp_io_define.h" /*! \brief this function handles NMI exception @@ -77,3 +78,12 @@ void UsageFault_Handler(void) void DebugMon_Handler(void) { } + +void BSP_TickTimer_Handler(void) +{ + if (timer_interrupt_flag_get(BSP_TIMER_TICK, TIMER_INT_FLAG_UP)) + { + timer_interrupt_flag_clear(BSP_TIMER_TICK, TIMER_INT_FLAG_UP); + Tick_Inc(); + } +} \ No newline at end of file diff --git a/L1_MCU/GD32F470ZGT6/Core/Src/main.c b/L1_MCU/GD32F470ZGT6/Core/Src/main.c index 4c27244..a80e60b 100644 --- a/L1_MCU/GD32F470ZGT6/Core/Src/main.c +++ b/L1_MCU/GD32F470ZGT6/Core/Src/main.c @@ -1,4 +1,6 @@ #include "main.h" +#include "bsp_interface.h" +#include "hal_interface.h" extern void ek_main(void); @@ -6,8 +8,24 @@ int main(void) { // NVIC Group nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0); - SysTick_Init(); + // + BSP_Timer_Tick_Init(); + + BSP_SDIO_Init(); + BSP_GPIO_Init(); + BSP_DMA_Init(); + BSP_Timer_LCD_Init(); + BSP_Timer_Motor_Init(); + BSP_Timer_DAC_Init(); + BSP_SPI_Init(); + BSP_IIC_Init(); + BSP_LED_Key_Init(); + BSP_EXMC_Init(); + BSP_USART_Init(115200); + BSP_ADC_Init(); + BSP_DAC_Init(); + ek_main(); while (1) diff --git a/L1_MCU/GD32F470ZGT6/Core/Src/systick.c b/L1_MCU/GD32F470ZGT6/Core/Src/systick.c index 040ccb4..2339163 100644 --- a/L1_MCU/GD32F470ZGT6/Core/Src/systick.c +++ b/L1_MCU/GD32F470ZGT6/Core/Src/systick.c @@ -1,14 +1,16 @@ #include "systick.h" -volatile uint32_t uwTick = 0; +volatile uint32_t uwTick = 0; volatile uint32_t delayTick = 0; void SysTick_Init(void) { /* setup systick timer for 1000Hz interrupts */ - if (SysTick_Config(SystemCoreClock / 1000U)) { + if (SysTick_Config(SystemCoreClock / 1000U)) + { /* capture error */ - while (1) { + while (1) + { } } /* configure the systick handler priority */ @@ -24,7 +26,8 @@ void Delay(uint32_t xms) { delayTick = xms; - while (delayTick) { + while (delayTick) + { } } @@ -36,7 +39,8 @@ uint32_t GetTick(void) void Tick_Inc(void) { uwTick++; - if (delayTick) { + if (delayTick) + { delayTick--; } } \ No newline at end of file diff --git a/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_adc.h b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_adc.h new file mode 100644 index 0000000..6268b81 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_adc.h @@ -0,0 +1,30 @@ +#ifndef __HAL_ADC_H +#define __HAL_ADC_H + +#include "bsp_interface.h" +#include + +void HAL_ADC_Start_DMA(uint16_t *buffer, uint16_t size); + +/** + * @brief 单次 ADC 读取 + * @param adc_periph ADC 外设编号 (ADC0, ADC1, ADC2) + * @param channel ADC 通道号 + * @return ADC 转换结果 + */ +uint16_t HAL_ADC_ReadSingle(uint32_t adc_periph, uint8_t channel); + +/** + * @brief 启动 ADC + * @param adc_periph ADC 外设编号 + */ +void HAL_ADC_Start(uint32_t adc_periph); + +/** + * @brief 停止 ADC + * @param adc_periph ADC 外设编号 + */ +void HAL_ADC_Stop(uint32_t adc_periph); + +#endif /* __HAL_ADC_H */ + diff --git a/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_dac.h b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_dac.h new file mode 100644 index 0000000..7a683c7 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_dac.h @@ -0,0 +1,26 @@ +#ifndef __HAL_DAC_H +#define __HAL_DAC_H + +#include "bsp_interface.h" +#include + +void HAL_DAC_Start_DMA(const uint8_t *source, uint32_t length); +void HAL_DAC_Stop(void); + +/** + * @brief 单次 DAC 写入 + * @param dac_periph DAC 外设编号 (DAC0, DAC1) + * @param channel DAC 通道 (DAC_OUT0, DAC_OUT1) + * @param value 要输出的值 (0-4095 for 12-bit) + */ +void HAL_DAC_WriteSingle(uint32_t dac_periph, uint32_t channel, uint16_t value); + +/** + * @brief 启动 DAC + * @param dac_periph DAC 外设编号 + * @param channel DAC 通道 + */ +void HAL_DAC_Start(uint32_t dac_periph, uint32_t channel); + +#endif /* __HAL_DAC_H */ + diff --git a/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_dma.h b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_dma.h new file mode 100644 index 0000000..ae86624 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_dma.h @@ -0,0 +1,34 @@ +#ifndef HAL_DMA_H +#define HAL_DMA_H + +#include +#include + +typedef enum { + HAL_DMA_DIR_M2M = 0, // Memory to Memory + HAL_DMA_DIR_M2P = 1, // Memory to Peripheral + HAL_DMA_DIR_P2M = 2, // Peripheral to Memory +} hal_dma_direction_t; + +/** + * @brief DMA 阻塞传输 + * @param dma_periph DMA 外设编号 (DMA0, DMA1) + * @param channel DMA 通道号 (DMA_CH0 ~ DMA_CH7) + * @param src 源地址 + * @param dst 目标地址 + * @param size 传输数据量(字节) + * @param dir 传输方向 + * @return 传输是否成功 + */ +bool HAL_DMA_Transfer(uint32_t dma_periph, uint8_t channel, + void *src, void *dst, uint32_t size, + hal_dma_direction_t dir); + +/** + * @brief 中止 DMA 传输 + * @param dma_periph DMA 外设编号 + * @param channel DMA 通道号 + */ +void HAL_DMA_Abort(uint32_t dma_periph, uint8_t channel); + +#endif // HAL_DMA_H diff --git a/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_iic.h b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_iic.h new file mode 100644 index 0000000..de320da --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_iic.h @@ -0,0 +1,11 @@ +#ifndef __HAL_IIC_H +#define __HAL_IIC_H + +#include "bsp_interface.h" + +void HAL_IIC_Receive( + uint32_t i2c_periph, uint32_t dev_addr, uint32_t mem_addr, uint8_t *rx_buffer, size_t size, uint32_t time_out); +void HAL_IIC_Transmit( + uint32_t i2c_periph, uint32_t dev_addr, uint32_t mem_addr, uint8_t *tx_buffer, size_t size, uint32_t time_out); + +#endif /* __HAL_IIC_H */ diff --git a/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_ipa.h b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_ipa.h new file mode 100644 index 0000000..38b2391 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_ipa.h @@ -0,0 +1,91 @@ +#ifndef HAL_IPA_H +#define HAL_IPA_H + +#include +#include +#include "gd32f4xx_ipa.h" + +/** + * @brief IPA 像素格式枚举 + */ +typedef enum { + HAL_IPA_PF_ARGB8888 = 0, /*!< ARGB8888 格式 */ + HAL_IPA_PF_RGB888 = 1, /*!< RGB888 格式 */ + HAL_IPA_PF_RGB565 = 2, /*!< RGB565 格式 */ + HAL_IPA_PF_ARGB1555 = 3, /*!< ARGB1555 格式 */ + HAL_IPA_PF_ARGB4444 = 4, /*!< ARGB4444 格式 */ +} hal_ipa_pixel_format_t; + +/** + * @brief IPA 层配置结构体 + */ +typedef struct { + uint32_t mem_addr; /*!< 内存地址 */ + uint32_t line_offset; /*!< 行偏移(pitch - width) */ + hal_ipa_pixel_format_t format; /*!< 像素格式 */ + uint8_t alpha; /*!< Alpha 值 (0-255) */ +} hal_ipa_layer_config_t; + +/** + * @brief 纯色填充 + * @param dst_addr 目标地址 + * @param width 宽度(像素) + * @param height 高度(像素) + * @param line_offset 行偏移(pitch - width) + * @param color 填充颜色(ARGB8888 格式) + * @param dst_format 目标像素格式 + * @return 成功返回 true,失败返回 false + */ +bool HAL_IPA_Fill( + uint32_t *dst_addr, + uint32_t width, + uint32_t height, + uint32_t line_offset, + uint32_t color, + hal_ipa_pixel_format_t dst_format +); + +/** + * @brief 像素格式转换 + * @param fg 前景层配置 + * @param dst 目标层配置 + * @param width 宽度(像素) + * @param height 高度(像素) + * @return 成功返回 true,失败返回 false + */ +bool HAL_IPA_Convert( + hal_ipa_layer_config_t *fg, + hal_ipa_layer_config_t *dst, + uint32_t width, + uint32_t height +); + +/** + * @brief 等待传输完成 + * @param timeout_ms 超时时间(毫秒) + * @return 成功返回 true,超时返回 false + */ +bool HAL_IPA_WaitForTransfer(uint32_t timeout_ms); + +/** + * @brief 使能 IPA 中断 + */ +void HAL_IPA_EnableInterrupt(void); + +/** + * @brief 禁用 IPA 中断 + */ +void HAL_IPA_DisableInterrupt(void); + +/** + * @brief 获取 IPA 传输完成标志 + * @return 传输完成返回 true,否则返回 false + */ +bool HAL_IPA_GetFlag(void); + +/** + * @brief 清除 IPA 传输完成标志 + */ +void HAL_IPA_ClearFlag(void); + +#endif // HAL_IPA_H diff --git a/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_pwm.h b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_pwm.h new file mode 100644 index 0000000..03feb3a --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_pwm.h @@ -0,0 +1,44 @@ +#ifndef HAL_PWM_H +#define HAL_PWM_H + +#include +#include + +/** + * @brief 启动 PWM 输出 + * @param timer_periph 定时器外设编号 (TIMER0, TIMER1, ...) + * @param channel 定时器通道 (TIMER_CH_0, TIMER_CH_1, ...) + */ +void HAL_PWM_Start(uint32_t timer_periph, uint16_t channel); + +/** + * @brief 停止 PWM 输出 + * @param timer_periph 定时器外设编号 + * @param channel 定时器通道 + */ +void HAL_PWM_Stop(uint32_t timer_periph, uint16_t channel); + +/** + * @brief 设置 PWM 占空比 + * @param timer_periph 定时器外设编号 + * @param channel 定时器通道 + * @param duty 占空比 (0-10000 表示 0.00%-100.00%) + */ +void HAL_PWM_SetDuty(uint32_t timer_periph, uint16_t channel, uint32_t duty); + +/** + * @brief 设置 PWM 频率 + * @param timer_periph 定时器外设编号 + * @param freq 目标频率 (Hz) + * @param timer_clk 定时器时钟频率 (Hz) + */ +void HAL_PWM_SetFrequency(uint32_t timer_periph, uint32_t freq, uint32_t timer_clk); + +/** + * @brief 获取定时器周期值 + * @param timer_periph 定时器外设编号 + * @return 自动重装载值 (ARR) + */ +uint32_t HAL_PWM_GetPeriod(uint32_t timer_periph); + +#endif // HAL_PWM_H diff --git a/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_spi.h b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_spi.h new file mode 100644 index 0000000..64dc210 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_spi.h @@ -0,0 +1,11 @@ +#ifndef __HAL_SPI_H +#define __HAL_SPI_H + +#include "bsp_interface.h" + +void HAL_SPI_TransmitReceive( + uint32_t spi_periph, uint8_t *tx_buffer, uint8_t *rx_buffer, size_t size, uint32_t time_out); +void HAL_SPI_Transmit(uint32_t spi_periph, uint8_t *tx_buffer, size_t size, uint32_t time_out); +void HAL_SPI_Receive(uint32_t spi_periph, uint8_t *rx_buffer, size_t size, uint32_t time_out); + +#endif /* __HAL_SPI_H */ diff --git a/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_tim.h b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_tim.h new file mode 100644 index 0000000..8a9c094 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_tim.h @@ -0,0 +1,32 @@ +#ifndef HAL_TIM_H +#define HAL_TIM_H + +#include + +/** + * @brief 启动定时器 + * @param timer_periph 定时器外设编号 (TIMER0, TIMER1, ...) + */ +void HAL_TIM_Enable(uint32_t timer_periph); + +/** + * @brief 停止定时器 + * @param timer_periph 定时器外设编号 + */ +void HAL_TIM_Disable(uint32_t timer_periph); + +/** + * @brief 读取定时器计数值 + * @param timer_periph 定时器外设编号 + * @return 当前计数值 + */ +uint32_t HAL_TIM_GetCounter(uint32_t timer_periph); + +/** + * @brief 设置定时器计数值 + * @param timer_periph 定时器外设编号 + * @param value 要设置的计数值 + */ +void HAL_TIM_SetCounter(uint32_t timer_periph, uint32_t value); + +#endif // HAL_TIM_H diff --git a/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_usart.h b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_usart.h new file mode 100644 index 0000000..295a046 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Inc/hal_usart.h @@ -0,0 +1,24 @@ +#ifndef __HAL_USART_H +#define __HAL_USART_H + +#include "bsp_interface.h" +#include +#include + +void HAL_USART_SendByte(uint32_t usart_periph, uint8_t ch); +void HAL_USART_Transmite(uint32_t usart_periph, uint8_t *tx_buffer, size_t size, uint32_t time_out); +void HAL_USART_Transmite_DMA(uint32_t usart_periph, uint8_t *txbuffer, size_t size); +void HAL_USART_ReceiveToIdle_DMA(uint32_t usart_periph, uint8_t *rxbuffer, size_t size); + +/** + * @brief 轮询接收数据 + * @param usart_periph USART 外设编号 (USART0, USART1, ...) + * @param data 接收缓冲区 + * @param size 要接收的字节数 + * @param timeout 超时时间(轮询次数) + * @return 是否成功接收 + */ +bool HAL_USART_Receive(uint32_t usart_periph, uint8_t *data, uint16_t size, uint32_t timeout); + +#endif /* __HAL_USART_H */ + diff --git a/L1_MCU/GD32F470ZGT6/Hal/Src/hal_adc.c b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_adc.c new file mode 100644 index 0000000..ef55281 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_adc.c @@ -0,0 +1,101 @@ +#include "hal_adc.h" +#include "gd32f4xx_adc.h" + +/** + * @brief 启动ADC的DMA转换 + * @note 配置DMA通道并启动ADC转换,使用循环模式持续采集数据 + * - 配置DMA为16位数据宽度,外设到内存方向 + * - 设置外设地址为ADC数据寄存器,内存地址为用户提供的数据缓冲区 + * - 使能DMA循环模式,自动重新开始采集 + * - 启动ADC并执行校准,然后开始软件触发转换 + * @param buffer: 数据缓冲区指针,用于存储ADC转换结果 + * @param size: 缓冲区大小,指定DMA传输的数据个数 + * @retval 无 + */ +void HAL_ADC_Start_DMA(uint16_t *buffer, uint16_t size) +{ + dma_channel_disable(BSP_ADC_DMA, BSP_ADC_DMA_CH); + + // 反初始化通道 + dma_deinit(BSP_ADC_DMA, BSP_ADC_DMA_CH); + + // DMA配置 + dma_single_data_parameter_struct bsp_adc_dma_init_struct; + dma_single_data_para_struct_init(&bsp_adc_dma_init_struct); + + bsp_adc_dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_16BIT; + bsp_adc_dma_init_struct.direction = DMA_PERIPH_TO_MEMORY; + + bsp_adc_dma_init_struct.periph_addr = (uint32_t)(&ADC_RDATA(BSP_ADC)); + bsp_adc_dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; + + bsp_adc_dma_init_struct.memory0_addr = (uint32_t)buffer; + bsp_adc_dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; + + bsp_adc_dma_init_struct.number = size; + bsp_adc_dma_init_struct.priority = DMA_PRIORITY_HIGH; + + dma_single_data_mode_init(BSP_ADC_DMA, BSP_ADC_DMA_CH, &bsp_adc_dma_init_struct); + dma_channel_subperipheral_select(BSP_ADC_DMA, BSP_ADC_DMA_CH, DMA_SUBPERI0); + + dma_circulation_enable(BSP_ADC_DMA, BSP_ADC_DMA_CH); + + dma_channel_enable(BSP_ADC_DMA, BSP_ADC_DMA_CH); + + // 开启ADC + adc_enable(BSP_ADC); + + Delay(1); + + // 校准ADC + adc_calibration_enable(BSP_ADC); + + // 开启ADC转换 + adc_software_trigger_enable(BSP_ADC, ADC_ROUTINE_CHANNEL); +} + +/** + * @brief 单次 ADC 读取 + */ +uint16_t HAL_ADC_ReadSingle(uint32_t adc_periph, uint8_t channel) +{ + // 配置通道 + adc_routine_channel_config(adc_periph, 0, channel, ADC_SAMPLETIME_15); + + // 启动软件触发 + adc_software_trigger_enable(adc_periph, ADC_ROUTINE_CHANNEL); + + // 轮询等待转换完成 + uint32_t timeout = 100000; + while (!adc_flag_get(adc_periph, ADC_FLAG_EOC) && timeout > 0) + { + timeout--; + } + + // 读取数据 + uint16_t value = adc_routine_data_read(adc_periph); + + // 清除标志 + adc_flag_clear(adc_periph, ADC_FLAG_EOC); + + return value; +} + +/** + * @brief 启动 ADC + */ +void HAL_ADC_Start(uint32_t adc_periph) +{ + adc_enable(adc_periph); + Delay(1); + adc_calibration_enable(adc_periph); + adc_software_trigger_enable(adc_periph, ADC_ROUTINE_CHANNEL); +} + +/** + * @brief 停止 ADC + */ +void HAL_ADC_Stop(uint32_t adc_periph) +{ + adc_disable(adc_periph); +} diff --git a/L1_MCU/GD32F470ZGT6/Hal/Src/hal_dac.c b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_dac.c new file mode 100644 index 0000000..2981a0a --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_dac.c @@ -0,0 +1,95 @@ +#include "hal_dac.h" +#include "gd32f4xx_dac.h" + +/** + * @brief 启动DMA音频播放 + * + * 该函数配置DMA和定时器,实现音频数据的DMA传输播放。通过循环模式不断向DAC输出音频数据, + * 定时器控制采样率,确保音频播放的时序正确。 + * + * @param source 音频数据源缓冲区指针 + * @param length 音频数据的长度(字节为单位) + * + * @note 函数会启用DMA传输完成中断,每次中断代表一次音频播放周期结束 + * @note 使用循环模式,音频数据会循环播放直到调用HAL_DAC_Stop函数停止 + */ +void HAL_DAC_Start_DMA(const uint8_t *source, uint32_t length) +{ + dma_deinit(BSP_AUDIO_DMA, BSP_AUDIO_DMA_CH); + timer_disable(BSP_AUDIO_TIMER); + timer_counter_value_config(BSP_AUDIO_TIMER, 0); // 先清空计数器 + + dma_flag_clear(BSP_AUDIO_DMA, BSP_AUDIO_DMA_CH, DMA_INTF_FEEIF); + dma_flag_clear(BSP_AUDIO_DMA, BSP_AUDIO_DMA_CH, DMA_INTF_SDEIF); + dma_flag_clear(BSP_AUDIO_DMA, BSP_AUDIO_DMA_CH, DMA_INTF_TAEIF); + dma_flag_clear(BSP_AUDIO_DMA, BSP_AUDIO_DMA_CH, DMA_INTF_HTFIF); + dma_flag_clear(BSP_AUDIO_DMA, BSP_AUDIO_DMA_CH, DMA_INTF_FTFIF); + + // 配置DMA + dma_channel_subperipheral_select(BSP_AUDIO_DMA, BSP_AUDIO_DMA_CH, DMA_SUBPERI7); + + dma_single_data_parameter_struct bsp_dma_audio_init_struct; + dma_single_data_para_struct_init(&bsp_dma_audio_init_struct); + + bsp_dma_audio_init_struct.direction = DMA_MEMORY_TO_PERIPH; + bsp_dma_audio_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT; + + bsp_dma_audio_init_struct.memory0_addr = (uint32_t)source; + bsp_dma_audio_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; + + bsp_dma_audio_init_struct.periph_addr = (uint32_t)&DAC_OUT1_R8DH(BSP_AUDIO_DAC); + bsp_dma_audio_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; + + bsp_dma_audio_init_struct.number = length; + bsp_dma_audio_init_struct.priority = DMA_PRIORITY_HIGH; + bsp_dma_audio_init_struct.circular_mode = DMA_CIRCULAR_MODE_ENABLE; // 打开循环模式 + + dma_single_data_mode_init(BSP_AUDIO_DMA, BSP_AUDIO_DMA_CH, &bsp_dma_audio_init_struct); + + dma_interrupt_flag_clear(BSP_AUDIO_DMA, BSP_AUDIO_DMA_CH, DMA_INT_FLAG_FTF); + + // 配置DMA传输完成中断 每一次中断都是代表一次音频播放结束 + dma_interrupt_enable(BSP_AUDIO_DMA, BSP_AUDIO_DMA_CH, DMA_INT_FTF); + + nvic_irq_enable(BSP_AUDIO_DMA_IRQ, 2, 0); + + dma_channel_enable(BSP_AUDIO_DMA, BSP_AUDIO_DMA_CH); + + // 开启定时器 + timer_enable(BSP_AUDIO_TIMER); +} + +/** + * @brief 停止DMA音频播放 + * + * 该函数停止定时器和DMA传输,终止音频播放过程。 + * 调用此函数后会立即停止向DAC输出音频数据。 + * + * @note 此函数与HAL_DAC_Start_DMA函数配合使用,用于控制音频播放的停止 + */ +void HAL_DAC_Stop(void) +{ + timer_disable(BSP_AUDIO_TIMER); + dma_channel_disable(BSP_AUDIO_DMA, BSP_AUDIO_DMA_CH); +} + +/** + * @brief 单次 DAC 写入 + */ +void HAL_DAC_WriteSingle(uint32_t dac_periph, uint32_t channel, uint16_t value) +{ + // 写入 12 位右对齐数据 + dac_data_set(dac_periph, channel, DAC_ALIGN_12B_R, value); + + // 软件触发 + dac_software_trigger_enable(dac_periph, channel); +} + +/** + * @brief 启动 DAC + */ +void HAL_DAC_Start(uint32_t dac_periph, uint32_t channel) +{ + dac_enable(dac_periph, channel); +} + diff --git a/L1_MCU/GD32F470ZGT6/Hal/Src/hal_dma.c b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_dma.c new file mode 100644 index 0000000..691fbc2 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_dma.c @@ -0,0 +1,85 @@ +#include "hal_dma.h" +#include "gd32f4xx_dma.h" + +/** + * @brief DMA 阻塞传输 + */ +bool HAL_DMA_Transfer(uint32_t dma_periph, uint8_t channel, + void *src, void *dst, uint32_t size, + hal_dma_direction_t dir) +{ + // 禁用通道 + dma_channel_disable(dma_periph, channel); + + // 反初始化通道 + dma_deinit(dma_periph, channel); + + // 配置 DMA 参数 + dma_single_data_parameter_struct dma_init_struct; + dma_single_data_para_struct_init(&dma_init_struct); + + // 设置传输方向和地址 + switch (dir) + { + case HAL_DMA_DIR_M2M: + dma_init_struct.direction = DMA_MEMORY_TO_MEMORY; + dma_init_struct.memory0_addr = (uint32_t)src; + dma_init_struct.periph_addr = (uint32_t)dst; + dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; + dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_ENABLE; + break; + + case HAL_DMA_DIR_M2P: + dma_init_struct.direction = DMA_MEMORY_TO_PERIPH; + dma_init_struct.memory0_addr = (uint32_t)src; + dma_init_struct.periph_addr = (uint32_t)dst; + dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; + dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; + break; + + case HAL_DMA_DIR_P2M: + dma_init_struct.direction = DMA_PERIPH_TO_MEMORY; + dma_init_struct.periph_addr = (uint32_t)src; + dma_init_struct.memory0_addr = (uint32_t)dst; + dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; + dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; + break; + + default: + return false; + } + + // 设置数据宽度和数量 + dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT; + dma_init_struct.number = size; + dma_init_struct.priority = DMA_PRIORITY_HIGH; + + // 初始化 DMA + dma_single_data_mode_init(dma_periph, channel, &dma_init_struct); + + // 启动 DMA + dma_channel_enable(dma_periph, channel); + + // 轮询等待传输完成 + uint32_t timeout = 1000000; + while (!dma_flag_get(dma_periph, channel, DMA_FLAG_FTF) && timeout > 0) + { + timeout--; + } + + // 清除标志 + dma_flag_clear(dma_periph, channel, DMA_FLAG_FTF); + + // 禁用通道 + dma_channel_disable(dma_periph, channel); + + return (timeout > 0); +} + +/** + * @brief 中止 DMA 传输 + */ +void HAL_DMA_Abort(uint32_t dma_periph, uint8_t channel) +{ + dma_channel_disable(dma_periph, channel); +} diff --git a/L1_MCU/GD32F470ZGT6/Hal/Src/hal_iic.c b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_iic.c new file mode 100644 index 0000000..c69b77b --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_iic.c @@ -0,0 +1,165 @@ +#include "hal_iic.h" + +/** + * @brief I2C主机接收数据函数 + * @details 从指定I2C设备的指定内存地址读取指定长度的数据 + * + * @param i2c_periph I2C外设基地址 (如 I2C0, I2C1) + * @param dev_addr 设备地址 (7位地址,需左移1位) + * @param mem_addr 要读取的内存地址 + * @param rx_buffer 接收数据缓冲区指针 + * @param size 要接收的数据字节数 + * @param time_out 超时时间,单位毫秒 + * @retval None + * @note 该函数使用标准I2C协议,先发送内存地址再读取数据,使用阻塞方式等待接收完成,超时后直接返回 + * @warning rx_buffer不能为空指针,size必须大于0 + * + * @example + * @code + * uint8_t data[10]; + * HAL_IIC_Receive(I2C0, 0xA0, 0x00, data, 10, 1000); // 从地址0xA0的设备内存0x00读取10字节数据,使用1000ms超时 + * @endcode + */ +void HAL_IIC_Receive( + uint32_t i2c_periph, uint32_t dev_addr, uint32_t mem_addr, uint8_t *rx_buffer, size_t size, uint32_t time_out) +{ + uint32_t now_tick = GetTick(); + + /* 发送要通讯的地址 */ + i2c_start_on_bus(i2c_periph); + while (!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND)) + { + if (GetTick() - now_tick >= time_out) return; + } + // 发送器件地址加写操作 + i2c_master_addressing(i2c_periph, dev_addr, I2C_TRANSMITTER); + // 等待器件地址发送成功 + while (!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND)) + { + if (GetTick() - now_tick >= time_out) return; + } + i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND); + + while (!i2c_flag_get(i2c_periph, I2C_FLAG_TBE)) + { + if (GetTick() - now_tick >= time_out) return; + } + // 发送要读取的地址 + i2c_data_transmit(i2c_periph, mem_addr); + + while (!i2c_flag_get(i2c_periph, I2C_FLAG_BTC)) + { + if (GetTick() - now_tick >= time_out) return; + } + // 发送停止信号 + i2c_stop_on_bus(i2c_periph); + + /* 读取数据 */ + i2c_start_on_bus(i2c_periph); + while (!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND)) + { + if (GetTick() - now_tick >= time_out) return; + } + // 发送器件地址加读操作 + i2c_master_addressing(i2c_periph, dev_addr, I2C_RECEIVER); + // 等待器件地址发送成功 + while (!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND)) + { + if (GetTick() - now_tick >= time_out) return; + } + // 清除地址发送成功标志位 + i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND); + + // 使能自动发送应答 + i2c_ack_config(I2C0, I2C_ACK_ENABLE); + + // 等待数据寄存器非空标志位置一 + for (uint32_t i = 0UL; i < size; i++) + { + /* 在接收最后一个字节前禁用ACK */ + if (i == (size - 1U)) + { + i2c_ack_config(i2c_periph, I2C_ACK_DISABLE); + } + + while (!i2c_flag_get(i2c_periph, I2C_FLAG_RBNE)) + { + if (GetTick() - now_tick >= time_out) return; + } + // 接收数据 + rx_buffer[i] = i2c_data_receive(i2c_periph); + } + + /* 重新启用ACK为下次传输做准备 */ + i2c_ack_config(i2c_periph, I2C_ACK_ENABLE); + i2c_stop_on_bus(i2c_periph); +} + +/** + * @brief I2C主机发送数据函数 + * @details 向指定I2C设备的指定内存地址写入指定长度的数据 + * + * @param i2c_periph I2C外设基地址 (如 I2C0, I2C1) + * @param dev_addr 设备地址 (7位地址,需左移1位) + * @param mem_addr 要写入的内存地址 + * @param tx_buffer 发送数据缓冲区指针 + * @param size 要发送的数据字节数 + * @param time_out 超时时间,单位毫秒 + * @retval None + * @note 该函数使用标准I2C协议,先发送内存地址再写入数据,使用阻塞方式等待发送完成,超时后直接返回 + * @warning tx_buffer不能为空指针,size必须大于0 + * + * @example + * @code + * uint8_t data[] = {0x01, 0x02, 0x03, 0x04}; + * HAL_IIC_Transmit(I2C0, 0xA0, 0x00, data, 4, 1000); // 向地址0xA0的设备内存0x00写入4字节数据,使用1000ms超时 + * @endcode + */ +void HAL_IIC_Transmit( + uint32_t i2c_periph, uint32_t dev_addr, uint32_t mem_addr, uint8_t *tx_buffer, size_t size, uint32_t time_out) +{ + uint32_t now_tick = GetTick(); + + /* 发送要通讯的地址 */ + i2c_start_on_bus(i2c_periph); + while (!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND)) + { + if (GetTick() - now_tick >= time_out) return; + } + // 发送器件地址加写操作 + i2c_master_addressing(i2c_periph, dev_addr, I2C_TRANSMITTER); + // 等待器件地址发送成功 + while (!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND)) + { + if (GetTick() - now_tick >= time_out) return; + } + i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND); + + while (!i2c_flag_get(i2c_periph, I2C_FLAG_TBE)) + { + if (GetTick() - now_tick >= time_out) return; + } + // 发送要写入的内存地址 + i2c_data_transmit(i2c_periph, mem_addr); + while (!i2c_flag_get(i2c_periph, I2C_FLAG_BTC)) + { + if (GetTick() - now_tick >= time_out) return; + } + + for (uint32_t i = 0UL; i < size; i++) + { + while (!i2c_flag_get(i2c_periph, I2C_FLAG_TBE)) + { + if (GetTick() - now_tick >= time_out) return; + } + // 发送数据 + i2c_data_transmit(i2c_periph, tx_buffer[i]); + while (!i2c_flag_get(i2c_periph, I2C_FLAG_BTC)) + { + if (GetTick() - now_tick >= time_out) return; + } + } + + // 发送停止信号 + i2c_stop_on_bus(i2c_periph); +} diff --git a/L1_MCU/GD32F470ZGT6/Hal/Src/hal_ipa.c b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_ipa.c new file mode 100644 index 0000000..2a63a75 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_ipa.c @@ -0,0 +1,198 @@ +#include "hal_ipa.h" + +// 外部 Tick 函数声明(假设在 BSP 或系统层提供) +extern uint32_t GetTick(void); + +/** + * @brief 将简化的像素格式转换为前景层格式 + */ +static uint32_t _convert_to_fg_format(hal_ipa_pixel_format_t format) +{ + switch (format) + { + case HAL_IPA_PF_ARGB8888: + return FOREGROUND_PPF_ARGB8888; + case HAL_IPA_PF_RGB888: + return FOREGROUND_PPF_RGB888; + case HAL_IPA_PF_RGB565: + return FOREGROUND_PPF_RGB565; + case HAL_IPA_PF_ARGB1555: + return FOREGROUND_PPF_ARG1555; + case HAL_IPA_PF_ARGB4444: + return FOREGROUND_PPF_ARGB4444; + default: + return FOREGROUND_PPF_ARGB8888; + } +} + +/** + * @brief 将简化的像素格式转换为目标层格式 + */ +static ipa_dpf_enum _convert_to_dst_format(hal_ipa_pixel_format_t format) +{ + switch (format) + { + case HAL_IPA_PF_ARGB8888: + return IPA_DPF_ARGB8888; + case HAL_IPA_PF_RGB888: + return IPA_DPF_RGB888; + case HAL_IPA_PF_RGB565: + return IPA_DPF_RGB565; + case HAL_IPA_PF_ARGB1555: + return IPA_DPF_ARGB1555; + case HAL_IPA_PF_ARGB4444: + return IPA_DPF_ARGB4444; + default: + return IPA_DPF_ARGB8888; + } +} + +/** + * @brief 纯色填充 + */ +bool HAL_IPA_Fill(uint32_t *dst_addr, + uint32_t width, + uint32_t height, + uint32_t line_offset, + uint32_t color, + hal_ipa_pixel_format_t dst_format) +{ + // 去初始化 IPA + ipa_deinit(); + + // 设置为填充模式 + ipa_pixel_format_convert_mode_set(IPA_FILL_UP_DE); + + // 配置目标层 + ipa_destination_parameter_struct dst_struct; + ipa_destination_struct_para_init(&dst_struct); + + dst_struct.destination_memaddr = (uint32_t)dst_addr; + dst_struct.destination_lineoff = line_offset; + dst_struct.destination_pf = _convert_to_dst_format(dst_format); + dst_struct.image_width = width; + dst_struct.image_height = height; + + // 提取颜色分量(ARGB8888 格式) + dst_struct.destination_preblue = (color >> 0) & 0xFF; + dst_struct.destination_pregreen = (color >> 8) & 0xFF; + dst_struct.destination_prered = (color >> 16) & 0xFF; + dst_struct.destination_prealpha = (color >> 24) & 0xFF; + + ipa_destination_init(&dst_struct); + + // 启动传输 + ipa_transfer_enable(); + + // 等待完成 + return HAL_IPA_WaitForTransfer(1000); +} + +/** + * @brief 像素格式转换 + */ +bool HAL_IPA_Convert(hal_ipa_layer_config_t *fg, hal_ipa_layer_config_t *dst, uint32_t width, uint32_t height) +{ + if (fg == NULL || dst == NULL) + { + return false; + } + + // 去初始化 IPA + ipa_deinit(); + + // 设置转换模式 + ipa_pixel_format_convert_mode_set(IPA_FGTODE_PF_CONVERT); + + // 配置前景层 + ipa_foreground_parameter_struct fg_struct; + ipa_foreground_struct_para_init(&fg_struct); + + fg_struct.foreground_memaddr = fg->mem_addr; + fg_struct.foreground_lineoff = fg->line_offset; + fg_struct.foreground_pf = _convert_to_fg_format(fg->format); + fg_struct.foreground_prealpha = fg->alpha; + + // 根据 alpha 值选择算法 + if (fg->alpha < 255) + { + fg_struct.foreground_alpha_algorithm = IPA_FG_ALPHA_MODE_2; // 使用预定义 alpha 乘以读取的 alpha + } + else + { + fg_struct.foreground_alpha_algorithm = IPA_FG_ALPHA_MODE_0; // 无效果 + } + + ipa_foreground_init(&fg_struct); + + // 配置目标层 + ipa_destination_parameter_struct dst_struct; + ipa_destination_struct_para_init(&dst_struct); + + dst_struct.destination_memaddr = dst->mem_addr; + dst_struct.destination_lineoff = dst->line_offset; + dst_struct.destination_pf = _convert_to_dst_format(dst->format); + dst_struct.image_width = width; + dst_struct.image_height = height; + + ipa_destination_init(&dst_struct); + + // 启动传输 + ipa_transfer_enable(); + + // 等待完成 + return HAL_IPA_WaitForTransfer(1000); +} + +/** + * @brief 等待传输完成 + */ +bool HAL_IPA_WaitForTransfer(uint32_t timeout_ms) +{ + uint32_t tickstart = GetTick(); + + // 等待传输完成标志 + while (!ipa_flag_get(IPA_FLAG_FTF)) + { + if ((GetTick() - tickstart) > timeout_ms) + { + return false; // 超时 + } + } + + // 清除标志 + ipa_flag_clear(IPA_FLAG_FTF); + return true; +} + +/** + * @brief 使能 IPA 中断 + */ +void HAL_IPA_EnableInterrupt(void) +{ + ipa_interrupt_enable(IPA_INT_FTF); +} + +/** + * @brief 禁用 IPA 中断 + */ +void HAL_IPA_DisableInterrupt(void) +{ + ipa_interrupt_disable(IPA_INT_FTF); +} + +/** + * @brief 获取 IPA 传输完成标志 + */ +bool HAL_IPA_GetFlag(void) +{ + return (ipa_flag_get(IPA_FLAG_FTF) == SET); +} + +/** + * @brief 清除 IPA 传输完成标志 + */ +void HAL_IPA_ClearFlag(void) +{ + ipa_flag_clear(IPA_FLAG_FTF); +} diff --git a/L1_MCU/GD32F470ZGT6/Hal/Src/hal_pwm.c b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_pwm.c new file mode 100644 index 0000000..2e970bd --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_pwm.c @@ -0,0 +1,56 @@ +#include "hal_pwm.h" +#include "gd32f4xx_timer.h" + +/** + * @brief 启动 PWM 输出 + */ +void HAL_PWM_Start(uint32_t timer_periph, uint16_t channel) +{ + timer_enable(timer_periph); + timer_channel_output_state_config(timer_periph, channel, TIMER_CCX_ENABLE); +} + +/** + * @brief 停止 PWM 输出 + */ +void HAL_PWM_Stop(uint32_t timer_periph, uint16_t channel) +{ + timer_channel_output_state_config(timer_periph, channel, TIMER_CCX_DISABLE); +} + +/** + * @brief 设置 PWM 占空比 + */ +void HAL_PWM_SetDuty(uint32_t timer_periph, uint16_t channel, uint32_t duty) +{ + uint32_t period = timer_autoreload_value_config_get(timer_periph); + uint32_t pulse = (period * duty) / 10000; + timer_channel_output_pulse_value_config(timer_periph, channel, pulse); +} + +/** + * @brief 设置 PWM 频率 + */ +void HAL_PWM_SetFrequency(uint32_t timer_periph, uint32_t freq, uint32_t timer_clk) +{ + uint32_t prescaler = 0; + uint32_t period = timer_clk / freq - 1; + + // 如果 period 太大,需要使用预分频 + while (period > 65535) + { + prescaler++; + period = (timer_clk / (prescaler + 1)) / freq - 1; + } + + timer_prescaler_config(timer_periph, prescaler, TIMER_PSC_RELOAD_NOW); + timer_autoreload_value_config(timer_periph, period); +} + +/** + * @brief 获取定时器周期值 + */ +uint32_t HAL_PWM_GetPeriod(uint32_t timer_periph) +{ + return timer_autoreload_value_config_get(timer_periph); +} diff --git a/L1_MCU/GD32F470ZGT6/Hal/Src/hal_spi.c b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_spi.c new file mode 100644 index 0000000..b5369eb --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_spi.c @@ -0,0 +1,132 @@ +#include "hal_spi.h" + +/** + * @brief SPI同时发送和接收数据 + * @details 该函数通过指定的SPI外设同时发送和接收指定长度的数据。 + * 函数采用全双工通信模式,逐个字节进行数据传输。 + * 每次发送一个字节后立即接收一个字节的数据 + * @param spi_periph: SPI外设编号 (如SPI0, SPI1等) + * @param tx_buffer: 要发送的数据缓冲区指针 + * @param rx_buffer: 接收数据缓冲区指针 + * @param size: 要发送和接收的数据长度 + * @param time_out: 超时时间,单位毫秒 + * @retval 无 + * @note 该函数使用阻塞方式等待传输完成,超时后直接返回 + * @warning tx_buffer和rx_buffer不能为空指针,size必须大于0 + * @example + * @code + * uint8_t tx_data[10] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}; + * uint8_t rx_data[10]; + * HAL_SPI_TransmitReceive(SPI0, tx_data, rx_data, 10, 1000); // 使用1000ms超时时间 + * @endcode + */ +void HAL_SPI_TransmitReceive( + uint32_t spi_periph, uint8_t *tx_buffer, uint8_t *rx_buffer, size_t size, uint32_t time_out) +{ + uint32_t now_tick = GetTick(); + + for (uint32_t i = 0; i < size; i++) + { + // 等待发送缓冲区为空 + while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE)) + { + if (GetTick() - now_tick >= time_out) return; + } + // 发送数据 + spi_i2s_data_transmit(spi_periph, tx_buffer[i]); + + // 等待接收完成 + while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE)) + { + if (GetTick() - now_tick >= time_out) return; + } + // 读取接收到的数据 + rx_buffer[i] = spi_i2s_data_receive(spi_periph); + } + + // 等待SPI完全空闲 + while (SET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TRANS)) + { + if (GetTick() - now_tick >= time_out) return; + } +} + +/** + * @brief SPI数据发送函数 + * @note 通过指定的SPI外设发送数据,采用轮询方式等待发送完成 + * - 逐个字节发送数据,每次发送前等待发送缓冲区为空 + * - 发送完成后等待SPI总线完全空闲,确保数据传输完成 + * @param spi_periph: SPI外设编号(如SPI0、SPI1等) + * @param tx_buffer: 待发送数据缓冲区指针 + * @param size: 待发送数据的字节数 + * @param time_out: 超时时间,单位毫秒 + * @retval 无 + * @note 该函数使用阻塞方式等待发送完成,超时后直接返回 + * @warning tx_buffer不能为空指针,size必须大于0 + * @example + * @code + * uint8_t tx_data[10] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}; + * HAL_SPI_Transmit(SPI0, tx_data, 10, 1000); // 使用1000ms超时时间 + * @endcode + */ +void HAL_SPI_Transmit(uint32_t spi_periph, uint8_t *tx_buffer, size_t size, uint32_t time_out) +{ + uint32_t now_tick = GetTick(); + + for (uint32_t i = 0; i < size; i++) + { + // 等待发送缓冲区为空 + while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE)) + { + if (GetTick() - now_tick >= time_out) return; + } + // 发送数据 + spi_i2s_data_transmit(spi_periph, tx_buffer[i]); + } + + // 等待SPI完全空闲 + while (SET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TRANS)) + { + if (GetTick() - now_tick >= time_out) return; + } +} + +/** + * @brief SPI数据接收函数 + * @note 通过指定的SPI外设接收数据,采用轮询方式等待接收完成 + * - 逐个字节接收数据,每次接收前等待接收缓冲区非空 + * - 接收完成后等待SPI总线完全空闲,确保数据传输完成 + * @param spi_periph: SPI外设编号(如SPI0、SPI1等) + * @param rx_buffer: 接收数据缓冲区指针,用于存储接收到的数据 + * @param size: 需要接收数据的字节数 + * @param time_out: 超时时间,单位毫秒 + * @retval 无 + * @note 该函数使用阻塞方式等待接收完成,超时后直接返回 + * @warning rx_buffer不能为空指针,size必须大于0 + * @example + * @code + * uint8_t rx_data[10]; + * HAL_SPI_Receive(SPI0, rx_data, 10, 1000); // 使用1000ms超时时间 + * @endcode + */ +void HAL_SPI_Receive(uint32_t spi_periph, uint8_t *rx_buffer, size_t size, uint32_t time_out) +{ + uint32_t now_tick = GetTick(); + + for (uint32_t i = 0; i < size; i++) + { + // 等待接收完成 + while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE)) + { + if (GetTick() - now_tick >= time_out) return; + } + // 读取接收到的数据 + rx_buffer[i] = spi_i2s_data_receive(spi_periph); + } + + // 等待SPI完全空闲 + while (SET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TRANS)) + { + if (GetTick() - now_tick >= time_out) return; + } +} \ No newline at end of file diff --git a/L1_MCU/GD32F470ZGT6/Hal/Src/hal_tim.c b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_tim.c new file mode 100644 index 0000000..dc2ca6f --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_tim.c @@ -0,0 +1,34 @@ +#include "hal_tim.h" +#include "gd32f4xx_timer.h" + +/** + * @brief 启动定时器 + */ +void HAL_TIM_Enable(uint32_t timer_periph) +{ + timer_enable(timer_periph); +} + +/** + * @brief 停止定时器 + */ +void HAL_TIM_Disable(uint32_t timer_periph) +{ + timer_disable(timer_periph); +} + +/** + * @brief 读取定时器计数值 + */ +uint32_t HAL_TIM_GetCounter(uint32_t timer_periph) +{ + return timer_counter_read(timer_periph); +} + +/** + * @brief 设置定时器计数值 + */ +void HAL_TIM_SetCounter(uint32_t timer_periph, uint32_t value) +{ + timer_counter_value_config(timer_periph, value); +} diff --git a/L1_MCU/GD32F470ZGT6/Hal/Src/hal_usart.c b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_usart.c new file mode 100644 index 0000000..e130955 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/Src/hal_usart.c @@ -0,0 +1,144 @@ +#include "hal_usart.h" +#include "gd32f4xx_usart.h" + +/** + * @brief USART发送单个字节 + * @details 该函数通过指定的USART外设发送一个字节数据。 + * 函数会等待发送缓冲区为空,然后发送数据, + * 最后等待发送完成标志置位 + * @param usart_periph: USART外设编号 (如USART0, USART1等) + * @param ch: 要发送的字节数据 + * @retval 无 + */ +void HAL_USART_SendByte(uint32_t usart_periph, uint8_t ch) +{ + usart_data_transmit(usart_periph, ch); + while (RESET == usart_flag_get(usart_periph, USART_FLAG_TBE)); +} + +/** + * @brief USART发送数据数组 + * @details 该函数通过指定的USART外设发送指定长度的数据数组。 + * 函数内部调用USART_SendByte逐个字节发送数据 + * @param usart_periph: USART外设编号 (如USART0, USART1等) + * @param tx_buffer: 要发送的数据缓冲区指针 + * @param size: 要发送的数据长度 + * @param time_out: 阻塞时间 + * @retval 无 + */ +void HAL_USART_Transmite(uint32_t usart_periph, uint8_t *tx_buffer, size_t size, uint32_t time_out) +{ + usart_interrupt_disable(BSP_USART, USART_INT_TC); // 关闭传输完成中断 + uint32_t tick_now = GetTick(); + for (uint32_t i = 0; i < size; i++) + { + usart_data_transmit(usart_periph, tx_buffer[i]); + while (RESET == usart_flag_get(usart_periph, USART_FLAG_TBE)) + { + if (GetTick() - tick_now >= time_out) return; + } + } +} + +/** + * @brief USART通过DMA方式发送数据 + * @details 该函数通过DMA方式发送指定长度的数据,实现高效的数据传输。 + * 函数会配置DMA通道参数,将数据从内存传输到USART数据寄存器, + * 配置完成后启动DMA传输,无需CPU干预即可完成数据发送 + * @param usart_periph: USART外设编号 (如USART0, USART1等) + * @param txbuffer: 要发送的数据缓冲区指针 + * @param size: 要发送的数据长度 + * @retval 无 + * @note DMA传输完成后会触发中断,可在中断中处理传输完成事件 + */ +void HAL_USART_Transmite_DMA(uint32_t usart_periph, uint8_t *txbuffer, size_t size) +{ + // 禁用DMA通道 + dma_channel_disable(BSP_USART_DMA, BSP_USART_DMA_TX_CH); + + dma_deinit(BSP_USART_DMA, BSP_USART_DMA_TX_CH); + + dma_channel_subperipheral_select(BSP_USART_DMA, BSP_USART_DMA_TX_CH, DMA_SUBPERI4); + + // tx + dma_single_data_parameter_struct bsp_usart_dma_tx_init_struct; + bsp_usart_dma_tx_init_struct.periph_addr = (uint32_t)&USART_DATA(BSP_USART); + bsp_usart_dma_tx_init_struct.memory0_addr = (uint32_t)txbuffer; // 使用时需要设置 + bsp_usart_dma_tx_init_struct.direction = DMA_MEMORY_TO_PERIPH; // 内存到外设 + bsp_usart_dma_tx_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT; // 字节宽度 + bsp_usart_dma_tx_init_struct.priority = DMA_PRIORITY_MEDIUM; // DMA优先级 + bsp_usart_dma_tx_init_struct.number = size; // 使用时需要设置 + bsp_usart_dma_tx_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; + bsp_usart_dma_tx_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; + + dma_single_data_mode_init(BSP_USART_DMA, BSP_USART_DMA_TX_CH, &bsp_usart_dma_tx_init_struct); + + usart_interrupt_enable(BSP_USART, USART_INT_TC); // 传输完成中断 + usart_interrupt_flag_clear(BSP_USART, USART_INT_FLAG_TC); + + // 启用DMA通道 + dma_channel_enable(BSP_USART_DMA, BSP_USART_DMA_TX_CH); +} + +/** + * @brief USART通过DMA方式接收数据直到空闲状态 + * @details 该函数通过DMA方式接收数据,支持空闲中断检测。 + * 函数会配置DMA通道参数,将USART数据寄存器的数据传输到内存缓冲区, + * 当串口总线空闲时会触发空闲中断,可用于判断一帧数据的结束 + * @param usart_periph: USART外设编号 (如USART0, USART1等) + * @param rxbuffer: 接收数据缓冲区指针 + * @param size: 接收缓冲区大小 + * @retval 无 + * @note 需配合空闲中断使用,当检测到空闲中断时说明一帧数据接收完成 + */ +void HAL_USART_ReceiveToIdle_DMA(uint32_t usart_periph, uint8_t *rxbuffer, size_t size) +{ + // 禁用DMA通道 + dma_channel_disable(BSP_USART_DMA, BSP_USART_DMA_RX_CH); + + dma_deinit(BSP_USART_DMA, BSP_USART_DMA_RX_CH); + + dma_channel_subperipheral_select(BSP_USART_DMA, BSP_USART_DMA_RX_CH, DMA_SUBPERI4); + // rx + dma_single_data_parameter_struct bsp_usart_dma_rx_init_struct; + bsp_usart_dma_rx_init_struct.periph_addr = (uint32_t)&USART_DATA(BSP_USART); + bsp_usart_dma_rx_init_struct.memory0_addr = (uint32_t)rxbuffer; // 使用时需要设置 + bsp_usart_dma_rx_init_struct.direction = DMA_PERIPH_TO_MEMORY; // 外设到内存 + bsp_usart_dma_rx_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT; // 字节宽度 + bsp_usart_dma_rx_init_struct.priority = DMA_PRIORITY_MEDIUM; // DMA优先级 + bsp_usart_dma_rx_init_struct.number = size; // 使用时需要设置 + bsp_usart_dma_rx_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; + bsp_usart_dma_rx_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; + + dma_single_data_mode_init(BSP_USART_DMA, BSP_USART_DMA_RX_CH, &bsp_usart_dma_rx_init_struct); + dma_circulation_disable(BSP_USART_DMA, BSP_USART_DMA_RX_CH); + + usart_interrupt_enable(BSP_USART, USART_INT_IDLE); // 使能空闲中断 + + // 启用DMA通道 + dma_channel_enable(BSP_USART_DMA, BSP_USART_DMA_RX_CH); +} + +/** + * @brief 轮询接收数据 + */ +bool HAL_USART_Receive(uint32_t usart_periph, uint8_t *data, uint16_t size, uint32_t timeout) +{ + for (uint16_t i = 0; i < size; i++) + { + uint32_t count = timeout; + while (RESET == usart_flag_get(usart_periph, USART_FLAG_RBNE) && count > 0) + { + count--; + } + + if (count == 0) + { + return false; // 超时 + } + + data[i] = usart_data_receive(usart_periph); + } + + return true; +} diff --git a/L1_MCU/GD32F470ZGT6/Hal/hal_interface.h b/L1_MCU/GD32F470ZGT6/Hal/hal_interface.h new file mode 100644 index 0000000..136b354 --- /dev/null +++ b/L1_MCU/GD32F470ZGT6/Hal/hal_interface.h @@ -0,0 +1,15 @@ +#ifndef __HAL_INTERFACE_H +#define __HAL_INTERFACE_H + +#include "hal_adc.h" +#include "hal_dac.h" +#include "hal_dma.h" +#include "hal_iic.h" +#include "hal_pwm.h" +#include "hal_spi.h" +#include "hal_tim.h" +#include "hal_usart.h" +#include "hal_ipa.h" + +#endif /* __HAL_INTERFACE_H */ + diff --git a/L2_Core/CMakeLists.txt b/L2_Core/CMakeLists.txt index 968f3c6..3858495 100644 --- a/L2_Core/CMakeLists.txt +++ b/L2_Core/CMakeLists.txt @@ -1,10 +1,15 @@ file(GLOB_RECURSE L2_3RD_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/third_party/*.c") -file(GLOB_RECURSE L2_PORT_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/port/*.c") aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/utils/src L2_UTILS_SRCS) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/hal/src L2_HAL_SRCS) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/port/stm32f429zi L2_ST_PORT_SRCS) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/port/gd32f470zgt6 L2_GD_PORT_SRCS) -add_library(l2_core OBJECT ${L2_3RD_SRCS} ${L2_UTILS_SRCS} ${L2_PORT_SRCS} ${L2_HAL_SRCS}) +if(${MCU_MODEL} STREQUAL "STM32F429ZIT6_GCC") + add_library(l2_core OBJECT ${L2_3RD_SRCS} ${L2_UTILS_SRCS} ${L2_ST_PORT_SRCS} ${L2_HAL_SRCS}) +elseif(${MCU_MODEL} STREQUAL "GD32F470ZGT6") + add_library(l2_core OBJECT ${L2_3RD_SRCS} ${L2_UTILS_SRCS} ${L2_GD_PORT_SRCS} ${L2_HAL_SRCS}) +endif() target_include_directories(l2_core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/utils/inc diff --git a/L2_Core/hal/inc/ek_hal_adc.h b/L2_Core/hal/inc/ek_hal_adc.h new file mode 100644 index 0000000..e6f5ee3 --- /dev/null +++ b/L2_Core/hal/inc/ek_hal_adc.h @@ -0,0 +1,50 @@ +#ifndef EK_HAL_ADC_H +#define EK_HAL_ADC_H + +#include "../../utils/inc/ek_def.h" +#include "../../utils/inc/ek_list.h" + +typedef struct ek_hal_adc_t ek_hal_adc_t; +typedef struct ek_adc_ops_t ek_adc_ops_t; + +/** @brief ADC 分辨率枚举 */ +typedef enum { + EK_HAL_ADC_RES_8B, + EK_HAL_ADC_RES_10B, + EK_HAL_ADC_RES_12B, + EK_HAL_ADC_RES_16B, +} ek_adc_resolution_t; + +/** @brief ADC 操作函数集 */ +struct ek_adc_ops_t +{ + void (*init)(ek_hal_adc_t *const dev); + uint32_t (*read)(ek_hal_adc_t *const dev); + bool (*read_dma)(ek_hal_adc_t *const dev, uint32_t *buffer, size_t size); + void (*start)(ek_hal_adc_t *const dev); + void (*stop)(ek_hal_adc_t *const dev); +}; + +/** @brief ADC 设备结构体 */ +struct ek_hal_adc_t +{ + ek_list_node_t node; + const char *name; + const ek_adc_ops_t *ops; + void *dev_info; + + uint32_t sample_rate; + ek_adc_resolution_t resolution; + bool lock; +}; + +extern ek_list_node_t ek_hal_adc_head; + +void ek_hal_adc_register(ek_hal_adc_t *const dev, const char *name, const ek_adc_ops_t *ops, void *dev_info); +ek_hal_adc_t *ek_hal_adc_find(const char *name); +uint32_t ek_hal_adc_read(ek_hal_adc_t *const dev); +bool ek_hal_adc_read_dma(ek_hal_adc_t *const dev, uint32_t *buffer, size_t size); +void ek_hal_adc_start(ek_hal_adc_t *const dev); +void ek_hal_adc_stop(ek_hal_adc_t *const dev); + +#endif // EK_HAL_ADC_H diff --git a/L2_Core/hal/inc/ek_hal_dac.h b/L2_Core/hal/inc/ek_hal_dac.h new file mode 100644 index 0000000..1e29755 --- /dev/null +++ b/L2_Core/hal/inc/ek_hal_dac.h @@ -0,0 +1,41 @@ +#ifndef EK_HAL_DAC_H +#define EK_HAL_DAC_H + +#include "../../utils/inc/ek_def.h" +#include "../../utils/inc/ek_list.h" + +typedef struct ek_hal_dac_t ek_hal_dac_t; +typedef struct ek_dac_ops_t ek_dac_ops_t; + +/** @brief DAC 操作函数集 */ +struct ek_dac_ops_t +{ + void (*init)(ek_hal_dac_t *const dev); + bool (*write)(ek_hal_dac_t *const dev, uint32_t value); + bool (*write_dma)(ek_hal_dac_t *const dev, uint32_t *buffer, size_t size); + void (*start)(ek_hal_dac_t *const dev); + void (*stop)(ek_hal_dac_t *const dev); +}; + +/** @brief DAC 设备结构体 */ +struct ek_hal_dac_t +{ + ek_list_node_t node; + const char *name; + const ek_dac_ops_t *ops; + void *dev_info; + + uint32_t sample_rate; + bool lock; +}; + +extern ek_list_node_t ek_hal_dac_head; + +void ek_hal_dac_register(ek_hal_dac_t *const dev, const char *name, const ek_dac_ops_t *ops, void *dev_info); +ek_hal_dac_t *ek_hal_dac_find(const char *name); +bool ek_hal_dac_write(ek_hal_dac_t *const dev, uint32_t value); +bool ek_hal_dac_write_dma(ek_hal_dac_t *const dev, uint32_t *buffer, size_t size); +void ek_hal_dac_start(ek_hal_dac_t *const dev); +void ek_hal_dac_stop(ek_hal_dac_t *const dev); + +#endif // EK_HAL_DAC_H diff --git a/L2_Core/hal/inc/ek_hal_dma.h b/L2_Core/hal/inc/ek_hal_dma.h new file mode 100644 index 0000000..c215d5a --- /dev/null +++ b/L2_Core/hal/inc/ek_hal_dma.h @@ -0,0 +1,45 @@ +#ifndef EK_HAL_DMA_H +#define EK_HAL_DMA_H + +#include "../../utils/inc/ek_def.h" +#include "../../utils/inc/ek_list.h" + +typedef struct ek_hal_dma_t ek_hal_dma_t; +typedef struct ek_dma_ops_t ek_dma_ops_t; + +/** @brief DMA 传输方向枚举 */ +typedef enum { + EK_HAL_DMA_DIR_M2M, // Memory to Memory + EK_HAL_DMA_DIR_M2P, // Memory to Peripheral + EK_HAL_DMA_DIR_P2M, // Peripheral to Memory +} ek_dma_direction_t; + +/** @brief DMA 操作函数集 */ +struct ek_dma_ops_t +{ + void (*init)(ek_hal_dma_t *const dev); + bool (*transfer)(ek_hal_dma_t *const dev, void *src, void *dst, size_t size, ek_dma_direction_t dir); + bool (*transfer_it)(ek_hal_dma_t *const dev, void *src, void *dst, size_t size, ek_dma_direction_t dir); + void (*abort)(ek_hal_dma_t *const dev); +}; + +/** @brief DMA 设备结构体 */ +struct ek_hal_dma_t +{ + ek_list_node_t node; + const char *name; + const ek_dma_ops_t *ops; + void *dev_info; + + bool lock; +}; + +extern ek_list_node_t ek_hal_dma_head; + +void ek_hal_dma_register(ek_hal_dma_t *const dev, const char *name, const ek_dma_ops_t *ops, void *dev_info); +ek_hal_dma_t *ek_hal_dma_find(const char *name); +bool ek_hal_dma_transfer(ek_hal_dma_t *const dev, void *src, void *dst, size_t size, ek_dma_direction_t dir); +bool ek_hal_dma_transfer_it(ek_hal_dma_t *const dev, void *src, void *dst, size_t size, ek_dma_direction_t dir); +void ek_hal_dma_abort(ek_hal_dma_t *const dev); + +#endif // EK_HAL_DMA_H diff --git a/L2_Core/hal/inc/ek_hal_pwm.h b/L2_Core/hal/inc/ek_hal_pwm.h new file mode 100644 index 0000000..6141296 --- /dev/null +++ b/L2_Core/hal/inc/ek_hal_pwm.h @@ -0,0 +1,46 @@ +#ifndef EK_HAL_PWM_H +#define EK_HAL_PWM_H + +#include "../../utils/inc/ek_def.h" +#include "../../utils/inc/ek_list.h" + +typedef struct ek_hal_pwm_t ek_hal_pwm_t; +typedef struct ek_pwm_ops_t ek_pwm_ops_t; + +/** @brief PWM 操作函数集 */ +struct ek_pwm_ops_t +{ + void (*init)(ek_hal_pwm_t *const dev); + void (*start)(ek_hal_pwm_t *const dev); + void (*stop)(ek_hal_pwm_t *const dev); + void (*set_duty)(ek_hal_pwm_t *const dev, uint32_t duty); + void (*set_freq)(ek_hal_pwm_t *const dev, uint32_t freq); + uint32_t (*get_duty)(ek_hal_pwm_t *const dev); + uint32_t (*get_freq)(ek_hal_pwm_t *const dev); +}; + +/** @brief PWM 设备结构体 */ +struct ek_hal_pwm_t +{ + ek_list_node_t node; + const char *name; + const ek_pwm_ops_t *ops; + void *dev_info; + + uint32_t frequency; // PWM 频率 (Hz) + uint32_t duty_cycle; // 占空比 (0-10000, 表示 0.00% - 100.00%) + bool lock; +}; + +extern ek_list_node_t ek_hal_pwm_head; + +void ek_hal_pwm_register(ek_hal_pwm_t *const dev, const char *name, const ek_pwm_ops_t *ops, void *dev_info); +ek_hal_pwm_t *ek_hal_pwm_find(const char *name); +void ek_hal_pwm_start(ek_hal_pwm_t *const dev); +void ek_hal_pwm_stop(ek_hal_pwm_t *const dev); +void ek_hal_pwm_set_duty(ek_hal_pwm_t *const dev, uint32_t duty); +void ek_hal_pwm_set_freq(ek_hal_pwm_t *const dev, uint32_t freq); +uint32_t ek_hal_pwm_get_duty(ek_hal_pwm_t *const dev); +uint32_t ek_hal_pwm_get_freq(ek_hal_pwm_t *const dev); + +#endif // EK_HAL_PWM_H diff --git a/L2_Core/hal/src/ek_hal_adc.c b/L2_Core/hal/src/ek_hal_adc.c new file mode 100644 index 0000000..620bfdb --- /dev/null +++ b/L2_Core/hal/src/ek_hal_adc.c @@ -0,0 +1,103 @@ +#include "../inc/ek_hal_adc.h" +#include "../../utils/inc/ek_assert.h" + +ek_list_node_t ek_hal_adc_head; +static bool _ek_init_flag = false; + +/** + * @brief 注册 ADC 设备到 HAL 管理链表 + * @param dev 设备实例指针 + * @param name 设备名称 + * @param ops 操作函数集 + * @param dev_info 驱动私有数据 + */ +void ek_hal_adc_register(ek_hal_adc_t *const dev, const char *name, const ek_adc_ops_t *ops, void *dev_info) +{ + ek_assert_param(dev != NULL); + ek_assert_param(name != NULL); + ek_assert_param(ops != NULL); + + if (_ek_init_flag == false) + { + ek_list_init(&ek_hal_adc_head); + _ek_init_flag = true; + } + + dev->name = name; + dev->ops = ops; + dev->dev_info = dev_info; + dev->lock = false; + ek_list_add_tail(&ek_hal_adc_head, &dev->node); + + dev->ops->init(dev); +} + +/** + * @brief 按名称查找已注册的 ADC 设备 + * @param name 设备名称 + * @return 找到返回设备指针,未找到返回 NULL + */ +ek_hal_adc_t *ek_hal_adc_find(const char *name) +{ + ek_assert_param(name != NULL); + + ek_list_node_t *p; + ek_list_iterate(p, &ek_hal_adc_head) + { + ek_hal_adc_t *dev = ek_list_container(p, ek_hal_adc_t, node); + + if (strcmp(dev->name, name) == 0) + { + return dev; + } + } + return NULL; +} + +/** + * @brief 读取 ADC 值(单次转换) + * @param dev 设备实例指针 + * @return ADC 转换结果 + */ +uint32_t ek_hal_adc_read(ek_hal_adc_t *const dev) +{ + ek_assert_param(dev != NULL); + + return dev->ops->read(dev); +} + +/** + * @brief 通过 DMA 读取 ADC 值 + * @param dev 设备实例指针 + * @param buffer 数据缓冲区 + * @param size 读取数量 + * @return 成功返回 true,失败返回 false + */ +bool ek_hal_adc_read_dma(ek_hal_adc_t *const dev, uint32_t *buffer, size_t size) +{ + ek_assert_param(dev != NULL); + + return dev->ops->read_dma(dev, buffer, size); +} + +/** + * @brief 启动 ADC 转换 + * @param dev 设备实例指针 + */ +void ek_hal_adc_start(ek_hal_adc_t *const dev) +{ + ek_assert_param(dev != NULL); + + dev->ops->start(dev); +} + +/** + * @brief 停止 ADC 转换 + * @param dev 设备实例指针 + */ +void ek_hal_adc_stop(ek_hal_adc_t *const dev) +{ + ek_assert_param(dev != NULL); + + dev->ops->stop(dev); +} diff --git a/L2_Core/hal/src/ek_hal_dac.c b/L2_Core/hal/src/ek_hal_dac.c new file mode 100644 index 0000000..c4012ed --- /dev/null +++ b/L2_Core/hal/src/ek_hal_dac.c @@ -0,0 +1,104 @@ +#include "../inc/ek_hal_dac.h" +#include "../../utils/inc/ek_assert.h" + +ek_list_node_t ek_hal_dac_head; +static bool _ek_init_flag = false; + +/** + * @brief 注册 DAC 设备到 HAL 管理链表 + * @param dev 设备实例指针 + * @param name 设备名称 + * @param ops 操作函数集 + * @param dev_info 驱动私有数据 + */ +void ek_hal_dac_register(ek_hal_dac_t *const dev, const char *name, const ek_dac_ops_t *ops, void *dev_info) +{ + ek_assert_param(dev != NULL); + ek_assert_param(name != NULL); + ek_assert_param(ops != NULL); + + if (_ek_init_flag == false) + { + ek_list_init(&ek_hal_dac_head); + _ek_init_flag = true; + } + + dev->name = name; + dev->ops = ops; + dev->dev_info = dev_info; + dev->lock = false; + ek_list_add_tail(&ek_hal_dac_head, &dev->node); + + dev->ops->init(dev); +} + +/** + * @brief 按名称查找已注册的 DAC 设备 + * @param name 设备名称 + * @return 找到返回设备指针,未找到返回 NULL + */ +ek_hal_dac_t *ek_hal_dac_find(const char *name) +{ + ek_assert_param(name != NULL); + + ek_list_node_t *p; + ek_list_iterate(p, &ek_hal_dac_head) + { + ek_hal_dac_t *dev = ek_list_container(p, ek_hal_dac_t, node); + + if (strcmp(dev->name, name) == 0) + { + return dev; + } + } + return NULL; +} + +/** + * @brief 写入 DAC 值 + * @param dev 设备实例指针 + * @param value DAC 输出值 + * @return 成功返回 true,失败返回 false + */ +bool ek_hal_dac_write(ek_hal_dac_t *const dev, uint32_t value) +{ + ek_assert_param(dev != NULL); + + return dev->ops->write(dev, value); +} + +/** + * @brief 通过 DMA 写入 DAC 值 + * @param dev 设备实例指针 + * @param buffer 数据缓冲区 + * @param size 数据数量 + * @return 成功返回 true,失败返回 false + */ +bool ek_hal_dac_write_dma(ek_hal_dac_t *const dev, uint32_t *buffer, size_t size) +{ + ek_assert_param(dev != NULL); + + return dev->ops->write_dma(dev, buffer, size); +} + +/** + * @brief 启动 DAC 输出 + * @param dev 设备实例指针 + */ +void ek_hal_dac_start(ek_hal_dac_t *const dev) +{ + ek_assert_param(dev != NULL); + + dev->ops->start(dev); +} + +/** + * @brief 停止 DAC 输出 + * @param dev 设备实例指针 + */ +void ek_hal_dac_stop(ek_hal_dac_t *const dev) +{ + ek_assert_param(dev != NULL); + + dev->ops->stop(dev); +} diff --git a/L2_Core/hal/src/ek_hal_dma.c b/L2_Core/hal/src/ek_hal_dma.c new file mode 100644 index 0000000..3bd862a --- /dev/null +++ b/L2_Core/hal/src/ek_hal_dma.c @@ -0,0 +1,98 @@ +#include "../inc/ek_hal_dma.h" +#include "../../utils/inc/ek_assert.h" + +ek_list_node_t ek_hal_dma_head; +static bool _ek_init_flag = false; + +/** + * @brief 注册 DMA 设备到 HAL 管理链表 + * @param dev 设备实例指针 + * @param name 设备名称 + * @param ops 操作函数集 + * @param dev_info 驱动私有数据 + */ +void ek_hal_dma_register(ek_hal_dma_t *const dev, const char *name, const ek_dma_ops_t *ops, void *dev_info) +{ + ek_assert_param(dev != NULL); + ek_assert_param(name != NULL); + ek_assert_param(ops != NULL); + + if (_ek_init_flag == false) + { + ek_list_init(&ek_hal_dma_head); + _ek_init_flag = true; + } + + dev->name = name; + dev->ops = ops; + dev->dev_info = dev_info; + dev->lock = false; + ek_list_add_tail(&ek_hal_dma_head, &dev->node); + + dev->ops->init(dev); +} + +/** + * @brief 按名称查找已注册的 DMA 设备 + * @param name 设备名称 + * @return 找到返回设备指针,未找到返回 NULL + */ +ek_hal_dma_t *ek_hal_dma_find(const char *name) +{ + ek_assert_param(name != NULL); + + ek_list_node_t *p; + ek_list_iterate(p, &ek_hal_dma_head) + { + ek_hal_dma_t *dev = ek_list_container(p, ek_hal_dma_t, node); + + if (strcmp(dev->name, name) == 0) + { + return dev; + } + } + return NULL; +} + +/** + * @brief DMA 传输(阻塞模式) + * @param dev 设备实例指针 + * @param src 源地址 + * @param dst 目标地址 + * @param size 传输大小 + * @param dir 传输方向 + * @return 成功返回 true,失败返回 false + */ +bool ek_hal_dma_transfer(ek_hal_dma_t *const dev, void *src, void *dst, size_t size, ek_dma_direction_t dir) +{ + ek_assert_param(dev != NULL); + + return dev->ops->transfer(dev, src, dst, size, dir); +} + +/** + * @brief DMA 传输(中断模式) + * @param dev 设备实例指针 + * @param src 源地址 + * @param dst 目标地址 + * @param size 传输大小 + * @param dir 传输方向 + * @return 成功返回 true,失败返回 false + */ +bool ek_hal_dma_transfer_it(ek_hal_dma_t *const dev, void *src, void *dst, size_t size, ek_dma_direction_t dir) +{ + ek_assert_param(dev != NULL); + + return dev->ops->transfer_it(dev, src, dst, size, dir); +} + +/** + * @brief 中止 DMA 传输 + * @param dev 设备实例指针 + */ +void ek_hal_dma_abort(ek_hal_dma_t *const dev) +{ + ek_assert_param(dev != NULL); + + dev->ops->abort(dev); +} diff --git a/L2_Core/hal/src/ek_hal_dma2d.c b/L2_Core/hal/src/ek_hal_dma2d.c index d12a567..658c68f 100644 --- a/L2_Core/hal/src/ek_hal_dma2d.c +++ b/L2_Core/hal/src/ek_hal_dma2d.c @@ -1,6 +1,5 @@ #include "../inc/ek_hal_dma2d.h" #include "../../utils/inc/ek_assert.h" -#include "../../utils/inc/ek_assert.h" ek_list_node_t ek_hal_dma2d_head; static bool _ek_init_flag = false; diff --git a/L2_Core/hal/src/ek_hal_gpio.c b/L2_Core/hal/src/ek_hal_gpio.c index bedf10a..7f5d4f8 100644 --- a/L2_Core/hal/src/ek_hal_gpio.c +++ b/L2_Core/hal/src/ek_hal_gpio.c @@ -1,6 +1,5 @@ #include "../inc/ek_hal_gpio.h" #include "../../utils/inc/ek_assert.h" -#include "../../utils/inc/ek_export.h" ek_list_node_t ek_hal_gpio_head; static bool _ek_init_flag = false; diff --git a/L2_Core/hal/src/ek_hal_i2c.c b/L2_Core/hal/src/ek_hal_i2c.c index ba69475..40f3d3a 100644 --- a/L2_Core/hal/src/ek_hal_i2c.c +++ b/L2_Core/hal/src/ek_hal_i2c.c @@ -1,6 +1,5 @@ #include "../inc/ek_hal_i2c.h" #include "../../utils/inc/ek_assert.h" -#include "../../utils/inc/ek_assert.h" ek_list_node_t ek_hal_i2c_head; static bool _ek_init_flag = false; diff --git a/L2_Core/hal/src/ek_hal_ltdc.c b/L2_Core/hal/src/ek_hal_ltdc.c index f5417b2..0db2d2d 100644 --- a/L2_Core/hal/src/ek_hal_ltdc.c +++ b/L2_Core/hal/src/ek_hal_ltdc.c @@ -1,6 +1,5 @@ #include "../inc/ek_hal_ltdc.h" #include "../../utils/inc/ek_assert.h" -#include "../../utils/inc/ek_assert.h" ek_list_node_t ek_hal_ltdc_head; static bool _ek_init_flag = false; diff --git a/L2_Core/hal/src/ek_hal_pwm.c b/L2_Core/hal/src/ek_hal_pwm.c new file mode 100644 index 0000000..0f22c3f --- /dev/null +++ b/L2_Core/hal/src/ek_hal_pwm.c @@ -0,0 +1,125 @@ +#include "../inc/ek_hal_pwm.h" +#include "../../utils/inc/ek_assert.h" + +ek_list_node_t ek_hal_pwm_head; +static bool _ek_init_flag = false; + +/** + * @brief 注册 PWM 设备到 HAL 管理链表 + * @param dev 设备实例指针 + * @param name 设备名称 + * @param ops 操作函数集 + * @param dev_info 驱动私有数据 + */ +void ek_hal_pwm_register(ek_hal_pwm_t *const dev, const char *name, const ek_pwm_ops_t *ops, void *dev_info) +{ + ek_assert_param(dev != NULL); + ek_assert_param(name != NULL); + ek_assert_param(ops != NULL); + + if (_ek_init_flag == false) + { + ek_list_init(&ek_hal_pwm_head); + _ek_init_flag = true; + } + + dev->name = name; + dev->ops = ops; + dev->dev_info = dev_info; + dev->lock = false; + ek_list_add_tail(&ek_hal_pwm_head, &dev->node); + + dev->ops->init(dev); +} + +/** + * @brief 按名称查找已注册的 PWM 设备 + * @param name 设备名称 + * @return 找到返回设备指针,未找到返回 NULL + */ +ek_hal_pwm_t *ek_hal_pwm_find(const char *name) +{ + ek_assert_param(name != NULL); + + ek_list_node_t *p; + ek_list_iterate(p, &ek_hal_pwm_head) + { + ek_hal_pwm_t *dev = ek_list_container(p, ek_hal_pwm_t, node); + + if (strcmp(dev->name, name) == 0) + { + return dev; + } + } + return NULL; +} + +/** + * @brief 启动 PWM 输出 + * @param dev 设备实例指针 + */ +void ek_hal_pwm_start(ek_hal_pwm_t *const dev) +{ + ek_assert_param(dev != NULL); + + dev->ops->start(dev); +} + +/** + * @brief 停止 PWM 输出 + * @param dev 设备实例指针 + */ +void ek_hal_pwm_stop(ek_hal_pwm_t *const dev) +{ + ek_assert_param(dev != NULL); + + dev->ops->stop(dev); +} + +/** + * @brief 设置 PWM 占空比 + * @param dev 设备实例指针 + * @param duty 占空比 (0-10000, 表示 0.00% - 100.00%) + */ +void ek_hal_pwm_set_duty(ek_hal_pwm_t *const dev, uint32_t duty) +{ + ek_assert_param(dev != NULL); + + dev->ops->set_duty(dev, duty); +} + +/** + * @brief 设置 PWM 频率 + * @param dev 设备实例指针 + * @param freq 频率 (Hz) + */ +void ek_hal_pwm_set_freq(ek_hal_pwm_t *const dev, uint32_t freq) +{ + ek_assert_param(dev != NULL); + + dev->ops->set_freq(dev, freq); +} + +/** + * @brief 获取 PWM 占空比 + * @param dev 设备实例指针 + * @return 占空比 (0-10000) + */ +uint32_t ek_hal_pwm_get_duty(ek_hal_pwm_t *const dev) +{ + ek_assert_param(dev != NULL); + + return dev->ops->get_duty(dev); +} + +/** + * @brief 获取 PWM 频率 + * @param dev 设备实例指针 + * @return 频率 (Hz) + */ +uint32_t ek_hal_pwm_get_freq(ek_hal_pwm_t *const dev) +{ + ek_assert_param(dev != NULL); + + return dev->ops->get_freq(dev); +} diff --git a/L2_Core/hal/src/ek_hal_spi.c b/L2_Core/hal/src/ek_hal_spi.c index 0523397..402224d 100644 --- a/L2_Core/hal/src/ek_hal_spi.c +++ b/L2_Core/hal/src/ek_hal_spi.c @@ -1,6 +1,5 @@ #include "../inc/ek_hal_spi.h" #include "../../utils/inc/ek_assert.h" -#include "../../utils/inc/ek_assert.h" ek_list_node_t ek_hal_spi_head; static bool _ek_init_flag = false; diff --git a/L2_Core/hal/src/ek_hal_tick.c b/L2_Core/hal/src/ek_hal_tick.c index 56b76c9..d665a86 100644 --- a/L2_Core/hal/src/ek_hal_tick.c +++ b/L2_Core/hal/src/ek_hal_tick.c @@ -1,6 +1,5 @@ #include "../inc/ek_hal_tick.h" #include "../../utils/inc/ek_assert.h" -#include "../../utils/inc/ek_assert.h" ek_list_node_t ek_hal_tick_head; static bool _ek_init_flag = false; diff --git a/L2_Core/hal/src/ek_hal_tim.c b/L2_Core/hal/src/ek_hal_tim.c index 8e113e6..105f657 100644 --- a/L2_Core/hal/src/ek_hal_tim.c +++ b/L2_Core/hal/src/ek_hal_tim.c @@ -1,6 +1,5 @@ #include "../inc/ek_hal_tim.h" #include "../../utils/inc/ek_assert.h" -#include "../../utils/inc/ek_assert.h" ek_list_node_t ek_hal_tim_head; static bool _ek_init_flag = false; diff --git a/L2_Core/hal/src/ek_hal_uart.c b/L2_Core/hal/src/ek_hal_uart.c index 817868d..025052f 100644 --- a/L2_Core/hal/src/ek_hal_uart.c +++ b/L2_Core/hal/src/ek_hal_uart.c @@ -1,6 +1,5 @@ #include "../inc/ek_hal_uart.h" #include "../../utils/inc/ek_assert.h" -#include "../../utils/inc/ek_assert.h" ek_list_node_t ek_hal_uart_head; static bool _ek_init_flag = false; diff --git a/L2_Core/port/gd32f470zgt6/gd_adc_port.c b/L2_Core/port/gd32f470zgt6/gd_adc_port.c new file mode 100644 index 0000000..d810218 --- /dev/null +++ b/L2_Core/port/gd32f470zgt6/gd_adc_port.c @@ -0,0 +1,98 @@ +#include "../../hal/inc/ek_hal_adc.h" +#include "../../utils/inc/ek_assert.h" +#include "../../utils/inc/ek_export.h" +#include "hal_adc.h" +#include "gd32f4xx_adc.h" + +#define EK_HAL_LOCK_ON(x) ((x)->lock = true) +#define EK_HAL_LOCK_OFF(x) ((x)->lock = false) +#define EK_HAL_LOCK_TEST(x) ((x)->lock == true) + +// 硬件信息结构体 +typedef struct +{ + uint32_t adc_periph; + uint8_t channel; +} gd_adc_info; + +// ops 实现 +static void _init(ek_hal_adc_t *const dev); +static uint32_t _read(ek_hal_adc_t *const dev); +static bool _read_dma(ek_hal_adc_t *const dev, uint32_t *buffer, size_t size); +static void _adc_start(ek_hal_adc_t *const dev); +static void _adc_stop(ek_hal_adc_t *const dev); + +static const ek_adc_ops_t gd_adc_ops = { + .init = _init, + .read = _read, + .read_dma = _read_dma, + .start = _adc_start, + .stop = _adc_stop, +}; + +// 硬件信息 +static gd_adc_info adc0_info = { + .adc_periph = ADC0, + .channel = 0, +}; + +// 设备实例 +static ek_hal_adc_t drv_adc0 = { + .sample_rate = 1000000, + .resolution = EK_HAL_ADC_RES_12B, +}; + +// 注册到 HAL +void gd_adc_drv_init(void) +{ + ek_hal_adc_register(&drv_adc0, "ADC0", &gd_adc_ops, &adc0_info); +} + +EK_EXPORT_HARDWARE(gd_adc_drv_init); + +// 内部函数 +static void _init(ek_hal_adc_t *const dev) +{ + ek_assert_param(dev != NULL); + // 用户提到初始化已经实现,这里留空 +} + +static uint32_t _read(ek_hal_adc_t *const dev) +{ + ek_assert_param(dev != NULL); + if (EK_HAL_LOCK_TEST(dev)) return 0; + + gd_adc_info *info = (gd_adc_info *)dev->dev_info; + EK_HAL_LOCK_ON(dev); + + uint32_t value = HAL_ADC_ReadSingle(info->adc_periph, info->channel); + + EK_HAL_LOCK_OFF(dev); + return value; +} + +static bool _read_dma(ek_hal_adc_t *const dev, uint32_t *buffer, size_t size) +{ + ek_assert_param(dev != NULL); + if (EK_HAL_LOCK_TEST(dev)) return false; + + // TODO: DMA 中断处理 + // 需要配置 ADC DMA 中断,在中断处理函数中调用回调 + // 中断处理函数示例:void DMA_ADC_IRQHandler(void) { ... } + HAL_ADC_Start_DMA((uint16_t *)buffer, size); + return true; +} + +static void _adc_start(ek_hal_adc_t *const dev) +{ + ek_assert_param(dev != NULL); + gd_adc_info *info = (gd_adc_info *)dev->dev_info; + HAL_ADC_Start(info->adc_periph); +} + +static void _adc_stop(ek_hal_adc_t *const dev) +{ + ek_assert_param(dev != NULL); + gd_adc_info *info = (gd_adc_info *)dev->dev_info; + HAL_ADC_Stop(info->adc_periph); +} diff --git a/L2_Core/port/gd32f470zgt6/gd_dac_port.c b/L2_Core/port/gd32f470zgt6/gd_dac_port.c new file mode 100644 index 0000000..d2925ed --- /dev/null +++ b/L2_Core/port/gd32f470zgt6/gd_dac_port.c @@ -0,0 +1,97 @@ +#include "../../hal/inc/ek_hal_dac.h" +#include "../../utils/inc/ek_assert.h" +#include "../../utils/inc/ek_export.h" +#include "gd32f4xx_dac.h" +#include "hal_dac.h" + +#define EK_HAL_LOCK_ON(x) ((x)->lock = true) +#define EK_HAL_LOCK_OFF(x) ((x)->lock = false) +#define EK_HAL_LOCK_TEST(x) ((x)->lock == true) + +// 硬件信息结构体 +typedef struct +{ + uint32_t dac_periph; + uint32_t channel; +} gd_dac_info; + +// ops 实现 +static void _init(ek_hal_dac_t *const dev); +static bool _write(ek_hal_dac_t *const dev, uint32_t value); +static bool _write_dma(ek_hal_dac_t *const dev, uint32_t *buffer, size_t size); +static void _dac_start(ek_hal_dac_t *const dev); +static void _dac_stop(ek_hal_dac_t *const dev); + +static const ek_dac_ops_t gd_dac_ops = { + .init = _init, + .write = _write, + .write_dma = _write_dma, + .start = _dac_start, + .stop = _dac_stop, +}; + +// 硬件信息 +static gd_dac_info dac_info = { + .dac_periph = DAC0, + .channel = DAC_OUT1, +}; + +// 设备实例 +static ek_hal_dac_t drv_dac = { + .sample_rate = 1000000, +}; + +// 注册到 HAL +void gd_dac_drv_init(void) +{ + ek_hal_dac_register(&drv_dac, "DAC", &gd_dac_ops, &dac_info); +} + +EK_EXPORT_HARDWARE(gd_dac_drv_init); + +// 内部函数 +static void _init(ek_hal_dac_t *const dev) +{ + ek_assert_param(dev != NULL); + // 用户提到初始化已经实现,这里留空 +} + +static bool _write(ek_hal_dac_t *const dev, uint32_t value) +{ + ek_assert_param(dev != NULL); + if (EK_HAL_LOCK_TEST(dev)) return false; + + gd_dac_info *info = (gd_dac_info *)dev->dev_info; + EK_HAL_LOCK_ON(dev); + + HAL_DAC_WriteSingle(info->dac_periph, info->channel, (uint16_t)value); + + EK_HAL_LOCK_OFF(dev); + return true; +} + +static bool _write_dma(ek_hal_dac_t *const dev, uint32_t *buffer, size_t size) +{ + ek_assert_param(dev != NULL); + if (EK_HAL_LOCK_TEST(dev)) return false; + + // TODO: DMA 中断处理 + // 需要配置 DAC DMA 中断,在中断处理函数中调用回调 + // 中断处理函数示例:void DMA_DAC_IRQHandler(void) { ... } + HAL_DAC_Start_DMA((uint8_t *)buffer, size); + + return true; +} + +static void _dac_start(ek_hal_dac_t *const dev) +{ + ek_assert_param(dev != NULL); + gd_dac_info *info = (gd_dac_info *)dev->dev_info; + HAL_DAC_Start(info->dac_periph, info->channel); +} + +static void _dac_stop(ek_hal_dac_t *const dev) +{ + ek_assert_param(dev != NULL); + HAL_DAC_Stop(); +} diff --git a/L2_Core/port/gd32f470zgt6/gd_dma_port.c b/L2_Core/port/gd32f470zgt6/gd_dma_port.c new file mode 100644 index 0000000..86b64de --- /dev/null +++ b/L2_Core/port/gd32f470zgt6/gd_dma_port.c @@ -0,0 +1,111 @@ +#include "../../hal/inc/ek_hal_dma.h" +#include "../../utils/inc/ek_assert.h" +#include "../../utils/inc/ek_export.h" +#include "hal_dma.h" +#include "gd32f4xx_dma.h" + +#define EK_HAL_LOCK_ON(x) ((x)->lock = true) +#define EK_HAL_LOCK_OFF(x) ((x)->lock = false) +#define EK_HAL_LOCK_TEST(x) ((x)->lock == true) + +// 硬件信息结构体 +typedef struct +{ + uint32_t dma_periph; + uint8_t channel; +} gd_dma_info; + +// ops 实现 +static void _init(ek_hal_dma_t *const dev); +static bool _transfer(ek_hal_dma_t *const dev, void *src, void *dst, size_t size, ek_dma_direction_t dir); +static bool _transfer_it(ek_hal_dma_t *const dev, void *src, void *dst, size_t size, ek_dma_direction_t dir); +static void _abort(ek_hal_dma_t *const dev); + +static const ek_dma_ops_t gd_dma_ops = { + .init = _init, + .transfer = _transfer, + .transfer_it = _transfer_it, + .abort = _abort, +}; + +// 硬件信息 +static gd_dma_info dma0_info = { + .dma_periph = DMA0, + .channel = DMA_CH0, +}; + +// 设备实例 +static ek_hal_dma_t drv_dma0; + +// 注册到 HAL +void gd_dma_drv_init(void) +{ + ek_hal_dma_register(&drv_dma0, "DMA0", &gd_dma_ops, &dma0_info); +} + +EK_EXPORT_HARDWARE(gd_dma_drv_init); + +// 内部函数 +static void _init(ek_hal_dma_t *const dev) +{ + ek_assert_param(dev != NULL); + // 用户提到初始化已经实现,这里留空 +} + +static bool _transfer(ek_hal_dma_t *const dev, void *src, void *dst, size_t size, ek_dma_direction_t dir) +{ + ek_assert_param(dev != NULL); + if (EK_HAL_LOCK_TEST(dev)) return false; + + gd_dma_info *info = (gd_dma_info *)dev->dev_info; + EK_HAL_LOCK_ON(dev); + + // 转换方向枚举 + hal_dma_direction_t hal_dir; + switch (dir) + { + case EK_HAL_DMA_DIR_M2M: + hal_dir = HAL_DMA_DIR_M2M; + break; + case EK_HAL_DMA_DIR_M2P: + hal_dir = HAL_DMA_DIR_M2P; + break; + case EK_HAL_DMA_DIR_P2M: + hal_dir = HAL_DMA_DIR_P2M; + break; + default: + EK_HAL_LOCK_OFF(dev); + return false; + } + + bool result = HAL_DMA_Transfer(info->dma_periph, info->channel, src, dst, size, hal_dir); + + EK_HAL_LOCK_OFF(dev); + return result; +} + +static bool _transfer_it(ek_hal_dma_t *const dev, void *src, void *dst, size_t size, ek_dma_direction_t dir) +{ + ek_assert_param(dev != NULL); + if (EK_HAL_LOCK_TEST(dev)) return false; + + // TODO: 中断模式 DMA 传输 + // 需要配置 DMA 中断,在中断处理函数中调用回调 + // 中断处理函数示例:void DMA_IRQHandler(void) { ... } + // 需要使能 DMA 中断:dma_interrupt_enable(dma_periph, channel, DMA_INT_FTF); + // 需要配置 NVIC:nvic_irq_enable(DMA_IRQn, priority, sub_priority); + + (void)src; + (void)dst; + (void)size; + (void)dir; + + return false; +} + +static void _abort(ek_hal_dma_t *const dev) +{ + ek_assert_param(dev != NULL); + gd_dma_info *info = (gd_dma_info *)dev->dev_info; + HAL_DMA_Abort(info->dma_periph, info->channel); +} diff --git a/L2_Core/port/gd32f470zgt6/gd_gpio_port.c b/L2_Core/port/gd32f470zgt6/gd_gpio_port.c new file mode 100644 index 0000000..984b486 --- /dev/null +++ b/L2_Core/port/gd32f470zgt6/gd_gpio_port.c @@ -0,0 +1,117 @@ +#include "../../hal/inc/ek_hal_gpio.h" +#include "../../utils/inc/ek_assert.h" +#include "../../utils/inc/ek_export.h" +#include "gd32f4xx_gpio.h" + +// 具体设备的硬件信息 +typedef struct +{ + ek_hal_gpio_t *dev; + const char *name; + ek_gpio_mode_t mode; + uint32_t hw_port; + uint32_t hw_pin; +} gd_gpio_info; + +// 具体设备 +static ek_hal_gpio_t drv_led1; +static ek_hal_gpio_t drv_led2; +static ek_hal_gpio_t drv_led3; +static ek_hal_gpio_t drv_led4; +static ek_hal_gpio_t drv_key_l; +static ek_hal_gpio_t drv_key_a; +static ek_hal_gpio_t drv_key_b; +static ek_hal_gpio_t drv_key_r; +static ek_hal_gpio_t drv_flash_cs; +static ek_hal_gpio_t drv_lcd_dc; +static ek_hal_gpio_t drv_lcd_cs; +static ek_hal_gpio_t drv_lcd_reset; + +// 设备表 +static const gd_gpio_info gd_drv_gpio_table[] = { + { &drv_led1, "LED1", EK_GPIO_MODE_OUTPUT_PP, GPIOE, BIT(3) }, + { &drv_led2, "LED2", EK_GPIO_MODE_OUTPUT_PP, GPIOD, BIT(7) }, + { &drv_led3, "LED3", EK_GPIO_MODE_OUTPUT_PP, GPIOG, BIT(3) }, + { &drv_led4, "LED4", EK_GPIO_MODE_OUTPUT_PP, GPIOA, BIT(5) }, + { &drv_key_l, "KEY_L", EK_GPIO_MODE_INPUT, GPIOA, BIT(0) }, + { &drv_key_a, "KEY_A", EK_GPIO_MODE_INPUT, GPIOG, BIT(9) }, + { &drv_key_b, "KEY_B", EK_GPIO_MODE_INPUT, GPIOB, BIT(15) }, + { &drv_key_r, "KEY_R", EK_GPIO_MODE_INPUT, GPIOB, BIT(2) }, + { &drv_flash_cs, "FLASH_CS", EK_GPIO_MODE_OUTPUT_PP, GPIOF, BIT(6) }, + { &drv_lcd_dc, "LCD_DC", EK_GPIO_MODE_OUTPUT_PP, GPIOA, BIT(6) }, + { &drv_lcd_cs, "LCD_CS", EK_GPIO_MODE_OUTPUT_PP, GPIOA, BIT(4) }, + { &drv_lcd_reset, "LCD_RESET", EK_GPIO_MODE_OUTPUT_PP, GPIOF, BIT(10) } +}; + +// ops 实现 +static void _init(ek_hal_gpio_t *const dev, ek_gpio_mode_t mode); +static void _set(ek_hal_gpio_t *const dev, ek_gpio_status_t status); +static void _toggle(ek_hal_gpio_t *const dev); +static ek_gpio_status_t _read(ek_hal_gpio_t *const dev); + +static const ek_gpio_ops_t gd_gpio_ops = { + .init = _init, + .set = _set, + .toggle = _toggle, + .read = _read, +}; + +// 注册到hal +void gd_gpio_drv_init(void) +{ + for (uint8_t i = 0; i < sizeof(gd_drv_gpio_table) / sizeof(gd_drv_gpio_table[0]); i++) + { + ek_hal_gpio_register(gd_drv_gpio_table[i].dev, + gd_drv_gpio_table[i].name, + gd_drv_gpio_table[i].mode, + &gd_gpio_ops, + &gd_drv_gpio_table[i]); + } +} + +// 直接使用自动导出模块导出,如果不使用这个功能则需要显式调用这个初始化函数 +EK_EXPORT_HARDWARE(gd_gpio_drv_init); + +// 内部函数 +static void _init(ek_hal_gpio_t *const dev, ek_gpio_mode_t mode) +{ + ek_assert_param(dev != NULL); + ek_assert_param(mode < EK_GPIO_MODE_MAX); + + // 用户提到初始化已经实现,这里留空 + // GD32 的 GPIO 初始化已经在 BSP 层完成 +} + +static void _set(ek_hal_gpio_t *const dev, ek_gpio_status_t status) +{ + ek_assert_param(dev != NULL); + + gd_gpio_info *drv_data = (gd_gpio_info *)dev->dev_info; + + if (status == EK_GPIO_STATUS_SET) + { + gpio_bit_set(drv_data->hw_port, drv_data->hw_pin); + } + else + { + gpio_bit_reset(drv_data->hw_port, drv_data->hw_pin); + } +} + +static void _toggle(ek_hal_gpio_t *const dev) +{ + ek_assert_param(dev != NULL); + + gd_gpio_info *drv_data = (gd_gpio_info *)dev->dev_info; + + gpio_bit_toggle(drv_data->hw_port, drv_data->hw_pin); +} + +static ek_gpio_status_t _read(ek_hal_gpio_t *const dev) +{ + ek_assert_param(dev != NULL); + + gd_gpio_info *drv_data = (gd_gpio_info *)dev->dev_info; + + return (ek_gpio_status_t)gpio_input_bit_get(drv_data->hw_port, drv_data->hw_pin); +} diff --git a/L2_Core/port/gd32f470zgt6/gd_i2c_port.c b/L2_Core/port/gd32f470zgt6/gd_i2c_port.c new file mode 100644 index 0000000..2a26f20 --- /dev/null +++ b/L2_Core/port/gd32f470zgt6/gd_i2c_port.c @@ -0,0 +1,145 @@ +#include "../../hal/inc/ek_hal_i2c.h" +#include "../../utils/inc/ek_assert.h" +#include "../../utils/inc/ek_export.h" +#include "gd32f4xx_i2c.h" +#include "../../../L1_MCU/GD32F470ZGT6/Hal/Inc/hal_iic.h" + +#define EK_HAL_LOCK_ON(x) ((x)->lock = true) +#define EK_HAL_LOCK_OFF(x) ((x)->lock = false) +#define EK_HAL_LOCK_TEST(x) ((x)->lock == true) + +#define I2C_TIMEOUT (10) + +// 硬件信息结构体 +typedef struct +{ + uint32_t i2c_periph; +} gd_i2c_info; + +// ops 实现 +static void _init(ek_hal_i2c_t *const dev); +static bool _write(ek_hal_i2c_t *const dev, uint16_t dev_addr, uint8_t *txdata, size_t size); +static bool _read(ek_hal_i2c_t *const dev, uint16_t dev_addr, uint8_t *rxdata, size_t size); +static bool _mem_write(ek_hal_i2c_t *const dev, + uint16_t dev_addr, + uint16_t mem_addr, + ek_hal_i2c_size_t mem_size, + uint8_t *txdata, + size_t size); +static bool _mem_read(ek_hal_i2c_t *const dev, + uint16_t dev_addr, + uint16_t mem_addr, + ek_hal_i2c_size_t mem_size, + uint8_t *rxdata, + size_t size); + +static const ek_i2c_ops_t gd_i2c_ops = { + .init = _init, + .write = _write, + .read = _read, + .mem_write = _mem_write, + .mem_read = _mem_read, +}; + +// 硬件信息 +static gd_i2c_info i2c0_info = { + .i2c_periph = I2C0, +}; + +// 设备实例 +static ek_hal_i2c_t drv_i2c0 = { + .speed_hz = 400000, +}; + +// 注册到 HAL +void gd_i2c_drv_init(void) +{ + ek_hal_i2c_register(&drv_i2c0, "I2C0", &gd_i2c_ops, &i2c0_info); +} + +EK_EXPORT_HARDWARE(gd_i2c_drv_init); + +// 内部函数 +static void _init(ek_hal_i2c_t *const dev) +{ + ek_assert_param(dev != NULL); + // 用户提到初始化已经实现,这里留空 +} + +static bool _write(ek_hal_i2c_t *const dev, uint16_t dev_addr, uint8_t *txdata, size_t size) +{ + ek_assert_param(dev != NULL); + ek_assert_param(txdata != NULL); + if (EK_HAL_LOCK_TEST(dev)) return false; + + gd_i2c_info *info = (gd_i2c_info *)dev->dev_info; + EK_HAL_LOCK_ON(dev); + + // 调用 L1 HAL,mem_addr 设为 0(不使用内存地址) + HAL_IIC_Transmit(info->i2c_periph, dev_addr, 0, txdata, size, I2C_TIMEOUT); + + EK_HAL_LOCK_OFF(dev); + return true; +} + +static bool _read(ek_hal_i2c_t *const dev, uint16_t dev_addr, uint8_t *rxdata, size_t size) +{ + ek_assert_param(dev != NULL); + ek_assert_param(rxdata != NULL); + if (EK_HAL_LOCK_TEST(dev)) return false; + + gd_i2c_info *info = (gd_i2c_info *)dev->dev_info; + EK_HAL_LOCK_ON(dev); + + // 调用 L1 HAL,mem_addr 设为 0(不使用内存地址) + HAL_IIC_Receive(info->i2c_periph, dev_addr, 0, rxdata, size, I2C_TIMEOUT); + + EK_HAL_LOCK_OFF(dev); + return true; +} + +static bool _mem_write(ek_hal_i2c_t *const dev, + uint16_t dev_addr, + uint16_t mem_addr, + ek_hal_i2c_size_t mem_size, + uint8_t *txdata, + size_t size) +{ + ek_assert_param(dev != NULL); + ek_assert_param(txdata != NULL); + if (EK_HAL_LOCK_TEST(dev)) return false; + + gd_i2c_info *info = (gd_i2c_info *)dev->dev_info; + EK_HAL_LOCK_ON(dev); + + // 调用 L1 HAL,传入内存地址 + // 注意:mem_size 参数在 L1 HAL 中未使用,假设为 8 位地址 + (void)mem_size; // L1 HAL 只支持 8 位内存地址 + HAL_IIC_Transmit(info->i2c_periph, dev_addr, mem_addr, txdata, size, I2C_TIMEOUT); + + EK_HAL_LOCK_OFF(dev); + return true; +} + +static bool _mem_read(ek_hal_i2c_t *const dev, + uint16_t dev_addr, + uint16_t mem_addr, + ek_hal_i2c_size_t mem_size, + uint8_t *rxdata, + size_t size) +{ + ek_assert_param(dev != NULL); + ek_assert_param(rxdata != NULL); + if (EK_HAL_LOCK_TEST(dev)) return false; + + gd_i2c_info *info = (gd_i2c_info *)dev->dev_info; + EK_HAL_LOCK_ON(dev); + + // 调用 L1 HAL,传入内存地址 + // 注意:mem_size 参数在 L1 HAL 中未使用,假设为 8 位地址 + (void)mem_size; // L1 HAL 只支持 8 位内存地址 + HAL_IIC_Receive(info->i2c_periph, dev_addr, mem_addr, rxdata, size, I2C_TIMEOUT); + + EK_HAL_LOCK_OFF(dev); + return true; +} diff --git a/L2_Core/port/gd32f470zgt6/gd_ipa_port.c b/L2_Core/port/gd32f470zgt6/gd_ipa_port.c new file mode 100644 index 0000000..de0c5ad --- /dev/null +++ b/L2_Core/port/gd32f470zgt6/gd_ipa_port.c @@ -0,0 +1,176 @@ +#include "../../hal/inc/ek_hal_dma2d.h" +#include "../../utils/inc/ek_assert.h" +#include "../../utils/inc/ek_export.h" +#include "hal_ipa.h" + +// 硬件信息结构体 +typedef struct +{ + bool initialized; // IPA 是全局单例,无需存储外设编号 +} gd_ipa_info; + +// ops 实现 +static void _init(ek_hal_dma2d_t *const dev); +static bool +_fill(ek_hal_dma2d_t *const dev, uint32_t *dst, uint32_t width, uint32_t height, uint32_t offset, uint32_t color); +static bool _convert(ek_hal_dma2d_t *const dev, + void *src, + void *dst, + uint32_t width, + uint32_t height, + uint32_t offset, + ek_dma2d_color_mode_t input_mode); +static bool +_fill_it(ek_hal_dma2d_t *const dev, uint32_t *dst, uint32_t width, uint32_t height, uint32_t offset, uint32_t color); +static bool _convert_it(ek_hal_dma2d_t *const dev, + void *src, + void *dst, + uint32_t width, + uint32_t height, + uint32_t offset, + ek_dma2d_color_mode_t input_mode); + +static const ek_dma2d_ops_t gd_ipa_ops = { + .init = _init, + .fill = _fill, + .convert = _convert, + .fill_it = _fill_it, + .convert_it = _convert_it, +}; + +// 硬件信息 +static gd_ipa_info ipa_info = { + .initialized = false, +}; + +// 设备实例 +static ek_hal_dma2d_t drv_ipa; + +// 注册到 HAL +void gd_ipa_drv_init(void) +{ + ek_hal_dma2d_register(&drv_ipa, "IPA", &gd_ipa_ops, &ipa_info); +} + +EK_EXPORT_HARDWARE(gd_ipa_drv_init); + +// 内部函数 + +/** + * @brief 颜色模式转换 + */ +static hal_ipa_pixel_format_t _convert_color_mode(ek_dma2d_color_mode_t mode) +{ + switch (mode) + { + case EK_HAL_DMA2D_ARGB8888: + return HAL_IPA_PF_ARGB8888; + case EK_HAL_DMA2D_RGB888: + return HAL_IPA_PF_RGB888; + case EK_HAL_DMA2D_RGB565: + return HAL_IPA_PF_RGB565; + default: + return HAL_IPA_PF_ARGB8888; + } +} + +static void _init(ek_hal_dma2d_t *const dev) +{ + ek_assert_param(dev != NULL); + gd_ipa_info *info = (gd_ipa_info *)dev->dev_info; + info->initialized = true; +} + +static bool +_fill(ek_hal_dma2d_t *const dev, uint32_t *dst, uint32_t width, uint32_t height, uint32_t offset, uint32_t color) +{ + ek_assert_param(dev != NULL); + + // IPA 是单例硬件,不需要 lock + hal_ipa_pixel_format_t format = HAL_IPA_PF_ARGB8888; // 默认格式 + + return HAL_IPA_Fill(dst, width, height, offset, color, format); +} + +static bool _convert(ek_hal_dma2d_t *const dev, + void *src, + void *dst, + uint32_t width, + uint32_t height, + uint32_t offset, + ek_dma2d_color_mode_t input_mode) +{ + ek_assert_param(dev != NULL); + + // 配置前景层 + hal_ipa_layer_config_t fg = { + .mem_addr = (uint32_t)src, + .line_offset = offset, + .format = _convert_color_mode(input_mode), + .alpha = 255, // 不透明 + }; + + // 配置目标层 + hal_ipa_layer_config_t dst_layer = { + .mem_addr = (uint32_t)dst, + .line_offset = offset, + .format = HAL_IPA_PF_ARGB8888, // 默认输出格式 + .alpha = 255, + }; + + return HAL_IPA_Convert(&fg, &dst_layer, width, height); +} + +static bool +_fill_it(ek_hal_dma2d_t *const dev, uint32_t *dst, uint32_t width, uint32_t height, uint32_t offset, uint32_t color) +{ + ek_assert_param(dev != NULL); + + // 启用中断 + HAL_IPA_EnableInterrupt(); + + // 启动填充(不等待) + hal_ipa_pixel_format_t format = HAL_IPA_PF_ARGB8888; + + // 配置并启动(不等待完成) + // 注意:这里简化实现,实际应该在 HAL_IPA_Fill 中添加非阻塞版本 + bool result = HAL_IPA_Fill(dst, width, height, offset, color, format); + + return result; +} + +static bool _convert_it(ek_hal_dma2d_t *const dev, + void *src, + void *dst, + uint32_t width, + uint32_t height, + uint32_t offset, + ek_dma2d_color_mode_t input_mode) +{ + ek_assert_param(dev != NULL); + + // 启用中断 + HAL_IPA_EnableInterrupt(); + + // 配置前景层 + hal_ipa_layer_config_t fg = { + .mem_addr = (uint32_t)src, + .line_offset = offset, + .format = _convert_color_mode(input_mode), + .alpha = 255, + }; + + // 配置目标层 + hal_ipa_layer_config_t dst_layer = { + .mem_addr = (uint32_t)dst, + .line_offset = offset, + .format = HAL_IPA_PF_ARGB8888, + .alpha = 255, + }; + + // 启动转换(不等待) + // 注意:这里简化实现,实际应该在 HAL_IPA_Convert 中添加非阻塞版本 + bool result = HAL_IPA_Convert(&fg, &dst_layer, width, height); + + return result; +} diff --git a/L2_Core/port/gd32f470zgt6/gd_pwm_port.c b/L2_Core/port/gd32f470zgt6/gd_pwm_port.c new file mode 100644 index 0000000..51332d4 --- /dev/null +++ b/L2_Core/port/gd32f470zgt6/gd_pwm_port.c @@ -0,0 +1,118 @@ +#include "../../hal/inc/ek_hal_pwm.h" +#include "../../utils/inc/ek_assert.h" +#include "../../utils/inc/ek_export.h" +#include "hal_pwm.h" +#include "gd32f4xx_timer.h" + +// 硬件信息结构体 +typedef struct +{ + uint32_t timer_periph; + uint16_t channel; +} gd_pwm_info; + +// ops 实现 +static void _init(ek_hal_pwm_t *const dev); +static void _pwm_start(ek_hal_pwm_t *const dev); +static void _pwm_stop(ek_hal_pwm_t *const dev); +static void _set_duty(ek_hal_pwm_t *const dev, uint32_t duty); +static void _set_freq(ek_hal_pwm_t *const dev, uint32_t freq); +static uint32_t _get_duty(ek_hal_pwm_t *const dev); +static uint32_t _get_freq(ek_hal_pwm_t *const dev); + +static const ek_pwm_ops_t gd_pwm_ops = { + .init = _init, + .start = _pwm_start, + .stop = _pwm_stop, + .set_duty = _set_duty, + .set_freq = _set_freq, + .get_duty = _get_duty, + .get_freq = _get_freq, +}; + +// 硬件信息 +static gd_pwm_info pwm0_info = { + .timer_periph = TIMER0, + .channel = TIMER_CH_0, +}; + +// 设备实例 +static ek_hal_pwm_t drv_pwm0 = { + .frequency = 1000, // 默认 1kHz + .duty_cycle = 5000, // 默认 50% +}; + +// 注册到 HAL +void gd_pwm_drv_init(void) +{ + ek_hal_pwm_register(&drv_pwm0, "PWM0", &gd_pwm_ops, &pwm0_info); +} + +EK_EXPORT_HARDWARE(gd_pwm_drv_init); + +// 内部函数 +static void _init(ek_hal_pwm_t *const dev) +{ + ek_assert_param(dev != NULL); + // 用户提到初始化已经实现,这里留空 +} + +static void _pwm_start(ek_hal_pwm_t *const dev) +{ + ek_assert_param(dev != NULL); + gd_pwm_info *info = (gd_pwm_info *)dev->dev_info; + + HAL_PWM_Start(info->timer_periph, info->channel); +} + +static void _pwm_stop(ek_hal_pwm_t *const dev) +{ + ek_assert_param(dev != NULL); + gd_pwm_info *info = (gd_pwm_info *)dev->dev_info; + + HAL_PWM_Stop(info->timer_periph, info->channel); +} + +static void _set_duty(ek_hal_pwm_t *const dev, uint32_t duty) +{ + ek_assert_param(dev != NULL); + ek_assert_param(duty <= 10000); + + gd_pwm_info *info = (gd_pwm_info *)dev->dev_info; + + HAL_PWM_SetDuty(info->timer_periph, info->channel, duty); + + // 更新设备状态 + dev->duty_cycle = duty; +} + +static void _set_freq(ek_hal_pwm_t *const dev, uint32_t freq) +{ + ek_assert_param(dev != NULL); + ek_assert_param(freq > 0); + + gd_pwm_info *info = (gd_pwm_info *)dev->dev_info; + + // 定时器时钟频率(根据实际系统时钟配置) + uint32_t timer_clk = 120000000; + + HAL_PWM_SetFrequency(info->timer_periph, freq, timer_clk); + + // 更新设备状态 + dev->frequency = freq; + + // 重新设置占空比 + _set_duty(dev, dev->duty_cycle); +} + +static uint32_t _get_duty(ek_hal_pwm_t *const dev) +{ + ek_assert_param(dev != NULL); + return dev->duty_cycle; +} + +static uint32_t _get_freq(ek_hal_pwm_t *const dev) +{ + ek_assert_param(dev != NULL); + return dev->frequency; +} diff --git a/L2_Core/port/gd32f470zgt6/gd_spi_port.c b/L2_Core/port/gd32f470zgt6/gd_spi_port.c new file mode 100644 index 0000000..82f115c --- /dev/null +++ b/L2_Core/port/gd32f470zgt6/gd_spi_port.c @@ -0,0 +1,175 @@ +#include "../../hal/inc/ek_hal_spi.h" +#include "../../utils/inc/ek_assert.h" +#include "../../utils/inc/ek_export.h" +#include "gd32f4xx_spi.h" + +#define EK_HAL_LOCK_ON(x) ((x)->lock = true) +#define EK_HAL_LOCK_OFF(x) ((x)->lock = false) +#define EK_HAL_LOCK_TEST(x) ((x)->lock == true) + +#define SPI_TIMEOUT (100000) + +// 硬件信息结构体 +typedef struct +{ + uint32_t spi_periph; +} gd_spi_info; + +// ops 实现 +static void _init(ek_hal_spi_t *const dev); +static bool _write(ek_hal_spi_t *const dev, uint8_t *txdata, size_t size); +static bool _read(ek_hal_spi_t *const dev, uint8_t *rxdata, size_t size); +static bool _write_read(ek_hal_spi_t *const dev, uint8_t *txdata, uint8_t *rxdata, size_t size); + +static const ek_spi_ops_t gd_spi_ops = { + .init = _init, + .write = _write, + .read = _read, + .write_read = _write_read, +}; + +// 硬件信息 +static gd_spi_info spi0_info = { + .spi_periph = SPI0, +}; + +// 设备实例 +static ek_hal_spi_t drv_spi0; + +// 注册到 HAL +void gd_spi_drv_init(void) +{ + ek_hal_spi_register(&drv_spi0, "SPI0", &gd_spi_ops, &spi0_info); +} + +EK_EXPORT_HARDWARE(gd_spi_drv_init); + +// 内部函数 +static void _init(ek_hal_spi_t *const dev) +{ + ek_assert_param(dev != NULL); + // 用户提到初始化已经实现,这里留空 +} + +static bool _write(ek_hal_spi_t *const dev, uint8_t *txdata, size_t size) +{ + ek_assert_param(dev != NULL); + + if (EK_HAL_LOCK_TEST(dev)) return false; + + gd_spi_info *info = (gd_spi_info *)dev->dev_info; + + EK_HAL_LOCK_ON(dev); + + for (size_t i = 0; i < size; i++) + { + // 等待发送缓冲区空 + uint32_t timeout = SPI_TIMEOUT; + while (RESET == spi_i2s_flag_get(info->spi_periph, SPI_FLAG_TBE)) + { + if (--timeout == 0) + { + EK_HAL_LOCK_OFF(dev); + return false; + } + } + + spi_i2s_data_transmit(info->spi_periph, txdata[i]); + } + + // 等待传输完成 + uint32_t timeout = SPI_TIMEOUT; + while (SET == spi_i2s_flag_get(info->spi_periph, SPI_FLAG_TRANS)) + { + if (--timeout == 0) + { + EK_HAL_LOCK_OFF(dev); + return false; + } + } + + EK_HAL_LOCK_OFF(dev); + return true; +} + +static bool _read(ek_hal_spi_t *const dev, uint8_t *rxdata, size_t size) +{ + ek_assert_param(dev != NULL); + + if (EK_HAL_LOCK_TEST(dev)) return false; + + gd_spi_info *info = (gd_spi_info *)dev->dev_info; + + EK_HAL_LOCK_ON(dev); + + for (size_t i = 0; i < size; i++) + { + // 发送 dummy 字节 + uint32_t timeout = SPI_TIMEOUT; + while (RESET == spi_i2s_flag_get(info->spi_periph, SPI_FLAG_TBE)) + { + if (--timeout == 0) + { + EK_HAL_LOCK_OFF(dev); + return false; + } + } + spi_i2s_data_transmit(info->spi_periph, 0xFF); + + // 等待接收数据 + timeout = SPI_TIMEOUT; + while (RESET == spi_i2s_flag_get(info->spi_periph, SPI_FLAG_RBNE)) + { + if (--timeout == 0) + { + EK_HAL_LOCK_OFF(dev); + return false; + } + } + rxdata[i] = spi_i2s_data_receive(info->spi_periph); + } + + EK_HAL_LOCK_OFF(dev); + return true; +} + +static bool _write_read(ek_hal_spi_t *const dev, uint8_t *txdata, uint8_t *rxdata, size_t size) +{ + ek_assert_param(dev != NULL); + + if (EK_HAL_LOCK_TEST(dev)) return false; + + gd_spi_info *info = (gd_spi_info *)dev->dev_info; + + EK_HAL_LOCK_ON(dev); + + for (size_t i = 0; i < size; i++) + { + // 发送数据 + uint32_t timeout = SPI_TIMEOUT; + while (RESET == spi_i2s_flag_get(info->spi_periph, SPI_FLAG_TBE)) + { + if (--timeout == 0) + { + EK_HAL_LOCK_OFF(dev); + return false; + } + } + spi_i2s_data_transmit(info->spi_periph, txdata[i]); + + // 接收数据 + timeout = SPI_TIMEOUT; + while (RESET == spi_i2s_flag_get(info->spi_periph, SPI_FLAG_RBNE)) + { + if (--timeout == 0) + { + EK_HAL_LOCK_OFF(dev); + return false; + } + } + rxdata[i] = spi_i2s_data_receive(info->spi_periph); + } + + EK_HAL_LOCK_OFF(dev); + return true; +} diff --git a/L2_Core/port/gd32f470zgt6/gd_tick_port.c b/L2_Core/port/gd32f470zgt6/gd_tick_port.c new file mode 100644 index 0000000..e31ccef --- /dev/null +++ b/L2_Core/port/gd32f470zgt6/gd_tick_port.c @@ -0,0 +1,61 @@ +#include "../../hal/inc/ek_hal_tick.h" +#include "../../utils/inc/ek_assert.h" +#include "../../utils/inc/ek_export.h" +#include "bsp_timer.h" + +// 外部 SysTick 变量(需要在 BSP 层定义) +extern volatile uint32_t systick_count; + +// 硬件信息结构体 +typedef struct +{ + volatile uint32_t *tick_ptr; +} gd_tick_info; + +// ops 实现 +static void _init(ek_hal_tick_t *const dev); +static uint32_t _get(ek_hal_tick_t *const dev); +static void _delay(ek_hal_tick_t *const dev, uint32_t ms); + +static const ek_tick_ops_t gd_tick_ops = { + .init = _init, + .get = _get, + .delay = _delay, +}; + +// 硬件信息 +static gd_tick_info tick_info = { + .tick_ptr = &uwTick, +}; + +// 设备实例 +static ek_hal_tick_t drv_tick; + +// 注册到 HAL +void gd_tick_drv_init(void) +{ + ek_hal_tick_register(&drv_tick, "TICK", &gd_tick_ops, &tick_info); +} + +EK_EXPORT_HARDWARE(gd_tick_drv_init); + +// 内部函数 +static void _init(ek_hal_tick_t *const dev) +{ + ek_assert_param(dev != NULL); + BSP_Timer_Tick_Init(); +} + +static uint32_t _get(ek_hal_tick_t *const dev) +{ + ek_assert_param(dev != NULL); + gd_tick_info *info = (gd_tick_info *)dev->dev_info; + return *(info->tick_ptr); +} + +static void _delay(ek_hal_tick_t *const dev, uint32_t ms) +{ + ek_assert_param(dev != NULL); + uint32_t start = _get(dev); + while ((_get(dev) - start) < ms); +} diff --git a/L2_Core/port/gd32f470zgt6/gd_tim_port.c b/L2_Core/port/gd32f470zgt6/gd_tim_port.c new file mode 100644 index 0000000..6d2e703 --- /dev/null +++ b/L2_Core/port/gd32f470zgt6/gd_tim_port.c @@ -0,0 +1,77 @@ +#include "../../hal/inc/ek_hal_tim.h" +#include "../../utils/inc/ek_assert.h" +#include "../../utils/inc/ek_export.h" +#include "hal_tim.h" +#include "gd32f4xx_timer.h" + +// 硬件信息结构体 +typedef struct +{ + uint32_t timer_periph; +} gd_tim_info; + +// ops 实现 +static void _init(ek_hal_tim_base_t *const dev); +static void _tim_start(ek_hal_tim_base_t *const dev); +static void _tim_stop(ek_hal_tim_base_t *const dev); +static uint32_t _get(ek_hal_tim_base_t *const dev); +static void _set(ek_hal_tim_base_t *const dev, uint32_t value); + +static const ek_tim_ops_t gd_tim_ops = { + .init = _init, + .start = _tim_start, + .stop = _tim_stop, + .get = _get, + .set = _set, +}; + +// 硬件信息 +static gd_tim_info tim2_info = { + .timer_periph = TIMER2, +}; + +// 设备实例 +static ek_hal_tim_base_t drv_tim2; + +// 注册到 HAL +void gd_tim_drv_init(void) +{ + ek_hal_tim_register(&drv_tim2, "TIM2", &gd_tim_ops, &tim2_info); +} + +EK_EXPORT_HARDWARE(gd_tim_drv_init); + +// 内部函数 +static void _init(ek_hal_tim_base_t *const dev) +{ + ek_assert_param(dev != NULL); + // 用户提到初始化已经实现,这里留空 +} + +static void _tim_start(ek_hal_tim_base_t *const dev) +{ + ek_assert_param(dev != NULL); + gd_tim_info *info = (gd_tim_info *)dev->dev_info; + HAL_TIM_Enable(info->timer_periph); +} + +static void _tim_stop(ek_hal_tim_base_t *const dev) +{ + ek_assert_param(dev != NULL); + gd_tim_info *info = (gd_tim_info *)dev->dev_info; + HAL_TIM_Disable(info->timer_periph); +} + +static uint32_t _get(ek_hal_tim_base_t *const dev) +{ + ek_assert_param(dev != NULL); + gd_tim_info *info = (gd_tim_info *)dev->dev_info; + return HAL_TIM_GetCounter(info->timer_periph); +} + +static void _set(ek_hal_tim_base_t *const dev, uint32_t value) +{ + ek_assert_param(dev != NULL); + gd_tim_info *info = (gd_tim_info *)dev->dev_info; + HAL_TIM_SetCounter(info->timer_periph, value); +} diff --git a/L2_Core/port/gd32f470zgt6/gd_uart_port.c b/L2_Core/port/gd32f470zgt6/gd_uart_port.c new file mode 100644 index 0000000..93ccf5e --- /dev/null +++ b/L2_Core/port/gd32f470zgt6/gd_uart_port.c @@ -0,0 +1,112 @@ +#include "../../hal/inc/ek_hal_uart.h" +#include "../../utils/inc/ek_assert.h" +#include "../../utils/inc/ek_export.h" +#include "hal_usart.h" + +#define EK_HAL_LOCK_ON(x) ((x)->lock = true) +#define EK_HAL_LOCK_OFF(x) ((x)->lock = false) +#define EK_HAL_LOCK_TEST(x) ((x)->lock == true) + +#define UART_RX_BUFFER_SIZE 128 +#define UART_TIMEOUT (100000) // 超时计数 + +// 硬件信息结构体 +typedef struct +{ + uint32_t usart_periph; +} gd_uart_info; + +// ops 实现 +static void _init(ek_hal_uart_t *const dev); +static bool _write(ek_hal_uart_t *const dev, uint8_t *txdata, size_t size); +static bool _write_dma(ek_hal_uart_t *const dev, uint8_t *txdata, size_t size); +static void _read(ek_hal_uart_t *const dev); + +static const ek_uart_ops_t gd_uart_ops = { + .init = _init, + .write = _write, + .write_dma = _write_dma, + .read = _read, +}; + +// 硬件信息 +static gd_uart_info uart0_info = { + .usart_periph = USART0, +}; + +// 接收缓冲区 +static uint8_t uart0_rx_buf[UART_RX_BUFFER_SIZE]; + +// 设备实例 +static ek_hal_uart_t drv_uart0 = { + .baudrate = 115200, + .buf_size = UART_RX_BUFFER_SIZE, + .rxbuffer = uart0_rx_buf, +}; + +// 注册到 HAL +void gd_uart_drv_init(void) +{ + ek_hal_uart_register(&drv_uart0, "UART0", &gd_uart_ops, &uart0_info); + // 注册后启动接收 + ek_hal_uart_read(&drv_uart0); +} + +EK_EXPORT_HARDWARE(gd_uart_drv_init); + +// 内部函数 +static void _init(ek_hal_uart_t *const dev) +{ + ek_assert_param(dev != NULL); + // 用户提到初始化已经实现,这里留空 + // GD32 的 USART 初始化已经在 BSP 层完成 +} + +static bool _write(ek_hal_uart_t *const dev, uint8_t *txdata, size_t size) +{ + ek_assert_param(dev != NULL); + + if (EK_HAL_LOCK_TEST(dev)) return false; + + gd_uart_info *info = (gd_uart_info *)dev->dev_info; + + EK_HAL_LOCK_ON(dev); + + HAL_USART_Transmite(info->usart_periph, txdata, size, UART_TIMEOUT); + + EK_HAL_LOCK_OFF(dev); + return true; +} + +static bool _write_dma(ek_hal_uart_t *const dev, uint8_t *txdata, size_t size) +{ + ek_assert_param(dev != NULL); + + if (EK_HAL_LOCK_TEST(dev)) return false; + + gd_uart_info *info = (gd_uart_info *)dev->dev_info; + + // TODO: UART DMA 发送需要配置 DMA 和传输完成中断 + // 中断处理函数示例:void USART_IRQHandler(void) { ... } + HAL_USART_Transmite_DMA(info->usart_periph, txdata, size); + + return true; +} + +static void _read(ek_hal_uart_t *const dev) +{ + ek_assert_param(dev != NULL); + + gd_uart_info *info = (gd_uart_info *)dev->dev_info; + + // TODO: UART DMA 接收需要配置 DMA 和空闲中断 + // 需要在中断处理函数中处理接收完成事件 + // 中断处理函数示例: + // void USART_IRQHandler(void) { + // if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)) { + // usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE); + // // 处理接收到的数据 + // } + // } + HAL_USART_ReceiveToIdle_DMA(info->usart_periph, dev->rxbuffer, dev->buf_size); +} diff --git a/L2_Core/port/inc/gd_hal_port.h b/L2_Core/port/inc/gd_hal_port.h new file mode 100644 index 0000000..bd60ec0 --- /dev/null +++ b/L2_Core/port/inc/gd_hal_port.h @@ -0,0 +1,15 @@ +#ifndef GD_HAL_PORT_H +#define GD_HAL_PORT_H + +void gd_gpio_drv_init(void); +void gd_uart_drv_init(void); +void gd_spi_drv_init(void); +void gd_i2c_drv_init(void); +void gd_tim_drv_init(void); +void gd_tick_drv_init(void); +void gd_dma_drv_init(void); +void gd_adc_drv_init(void); +void gd_dac_drv_init(void); +void gd_pwm_drv_init(void); + +#endif // GD_HAL_PORT_H diff --git a/L2_Core/readme.md b/L2_Core/readme.md index 0345222..7de6d10 100644 --- a/L2_Core/readme.md +++ b/L2_Core/readme.md @@ -111,70 +111,7 @@ L2_Core/ └── shell_cfg.h ``` -## 3. 实现状态 - -### 3.1 代码统计 - -| 分类 | 头文件 | 源文件 | 总行数 | 状态 | -|------|---------|---------|--------|------| -| **utils/** | 12 | 8 | 774行 | ✅ 100% | -| **hal/** | 8 | 8 | 891行 | ✅ 100% | -| **port/** | 1 | 7 | 955行 | ✅ 100% | -| **第三方库** | 4 | 5 | 4,238行 | ✅ 100% | -| **合计** | 25 | 28+ | 6,858行 | ✅ 100% | - -### 3.2 utils/ 子目录状态 - -| 模块 | 头文件 | 源文件 | 状态 | 说明 | -|------|---------|---------|------|------| -| ek_def.h | ✅ | - | ✅ 完成 | 跨编译器宏定义 | -| ek_list.h | ✅ | - | ✅ 完成 | 双向循环链表(纯头文件) | -| ek_ringbuf | ✅ | ✅ | ✅ 完成 | 环形缓冲区(150行) | -| ek_stack | ✅ | ✅ | ✅ 完成 | 栈数据结构(119行) | -| ek_mem | ✅ | ✅ | ✅ 完成 | 动态内存管理(116行) | -| ek_log | ✅ | ✅ | ✅ 完成 | 分级日志系统(76行) | -| ek_io | ✅ | ✅ | ✅ 完成 | 标准 IO(33行) | -| ek_vec.h | ✅ | - | ✅ 完成 | 动态数组(纯宏实现) | -| ek_str | ✅ | ✅ | ✅ 完成 | 动态字符串(217行) | -| ek_export | ✅ | ✅ | ✅ 完成 | 函数自动导出(34行) | -| ek_assert | ✅ | ✅ | ✅ 完成 | 断言模块(29行) | -| ek_shell.h | ✅ | - | ✅ 完成 | 命令行接口(封装) | - -### 3.3 hal/ 子目录状态 - -| 模块 | 头文件 | 源文件 | 状态 | 说明 | -|------|---------|---------|------|------| -| ek_hal_gpio | ✅ | ✅ | ✅ 完成 | GPIO 抽象(102行) | -| ek_hal_uart | ✅ | ✅ | ✅ 完成 | UART 抽象(95行) | -| ek_hal_i2c | ✅ | ✅ | ✅ 完成 | I2C 抽象(130行) | -| ek_hal_spi | ✅ | ✅ | ✅ 完成 | SPI 抽象(99行) | -| ek_hal_tick | ✅ | ✅ | ✅ 完成 | 系统节拍(79行) | -| ek_hal_tim | ✅ | ✅ | ✅ 完成 | 定时器(104行) | -| ek_hal_dma2d | ✅ | ✅ | ✅ 完成 | DMA2D 硬件加速(139行) | -| ek_hal_ltdc | ✅ | ✅ | ✅ 完成 | LTDC 显示控制器(143行) | - -### 3.4 port/ 子目录状态 - -| 驱动 | 源文件 | 行数 | 状态 | -|------|---------|------|------| -| GPIO 驱动 | st_gpio_port.c | 132行 | ✅ 完成 | -| UART 驱动 | st_uart_port.c | 110行 | ✅ 完成 | -| I2C 驱动 | st_i2c_port.c | 138行 | ✅ 完成 | -| SPI 驱动 | st_spi_port.c | 97行 | ✅ 完成 | -| Tick 驱动 | st_tick_port.c | 50行 | ✅ 完成 | -| 定时器驱动 | st_tim_port.c | 86行 | ✅ 完成 | -| DMA2D 驱动 | st_dma2d_port.c | 250行 | ✅ 完成 | -| LTDC 驱动 | st_ltdc_port.c | 92行 | ✅ 完成 | - -### 3.5 第三方库状态 - -| 库 | 说明 | 状态 | -|----|----|------| -| TLSF | Two-Level Segregated Fit 内存分配器 | ✅ 已集成 | -| lwprintf | 轻量级格式化输出库 | ✅ 已集成 | -| letter_shell | 命令行 Shell | ✅ 已集成 | - -## 4. 核心开发原则 (Strict Rules) +## 3. 核心开发原则 (Strict Rules) 为了保证架构的整洁性和可移植性,开发本层时必须遵守以下规则: @@ -204,11 +141,11 @@ L2_Core/ - `port/` 可以依赖 `hal/` 和 `utils/` - `utils/` 不能依赖 `hal/` 或 `port/`(保持纯软件实现) -## 5. HAL 架构设计(OOP 模式) +## 4. HAL 架构设计(OOP 模式) 本层所有 HAL 模块采用统一的 OOP(面向对象)设计模式: -### 5.1 设备结构体 +### 4.1 设备结构体 ```c // 设备结构体 @@ -224,7 +161,7 @@ struct ek_hal_xxx_t }; ``` -### 5.2 操作函数集(虚函数表) +### 4.2 操作函数集(虚函数表) ```c // 操作函数集(虚函数表) @@ -235,7 +172,7 @@ typedef struct ek_xxx_ops_t } ek_xxx_ops_t; ``` -### 5.3 设备管理 +### 4.3 设备管理 - 所有设备通过链表管理 - 支持按名称查找设备 @@ -254,9 +191,9 @@ void ek_hal_xxx_register( ek_hal_xxx_t *ek_hal_xxx_find(const char *name); ``` -## 6. 移植层设计(port/) +## 5. 移植层设计(port/) -### 6.1 设备表驱动模式 +### 5.1 设备表驱动模式 移植层使用设备表驱动模式,例如 `st_gpio_port.c`: @@ -287,9 +224,9 @@ EK_EXPORT_COMPONENTS(my_component_init); EK_EXPORT_APP(my_app_init); ``` -## 7. 模块使用指南 +## 6. 模块使用指南 -### 7.1 使用双向链表(ek_list.h) +### 6.1 使用双向链表(ek_list.h) ```c #include "ek_list.h" @@ -318,7 +255,7 @@ ek_list_iterate(pos, &my_list) { ek_list_remove(&node->node); ``` -### 7.2 使用动态数组(ek_vec.h) +### 6.2 使用动态数组(ek_vec.h) ```c #include "ek_vec.h" @@ -344,7 +281,7 @@ ek_vec_iterate(i, my_vec) { ek_vec_destroy(my_vec); ``` -### 7.3 使用动态字符串(ek_str.h) +### 6.3 使用动态字符串(ek_str.h) ```c #include "ek_str.h" @@ -364,7 +301,7 @@ printf("%s\n", cstr); // "Hello World 2024" ek_str_free(s); ``` -### 7.4 使用内存管理(ek_mem.h) +### 6.4 使用内存管理(ek_mem.h) ```c #include "ek_mem.h" @@ -387,7 +324,7 @@ uint32_t used = ek_heap_used(); // 已使用 uint32_t unused = ek_heap_unused(); // 空闲 ``` -### 7.5 使用日志系统(ek_log.h) +### 6.5 使用日志系统(ek_log.h) ```c #include "ek_log.h" @@ -402,7 +339,7 @@ void example_function(void) } ``` -### 7.6 使用 HAL 设备 +### 6.6 使用 HAL 设备 ```c #include "ek_hal_gpio.h" @@ -423,7 +360,7 @@ ek_hal_gpio_toggle(gpio); ek_gpio_status_t status = ek_hal_gpio_read(gpio); ``` -### 7.7 使用自动导出 +### 6.7 使用自动导出 ```c #include "ek_export.h" @@ -447,9 +384,9 @@ int main(void) } ``` -## 8. 添加新模块 +## 7. 添加新模块 -### 8.1 添加 utils 模块(硬件无关) +### 7.1 添加 utils 模块(硬件无关) #### 步骤 1:定义接口 (utils/inc/ek_xxx.h) @@ -485,7 +422,7 @@ int ek_example_do_something(int value) } ``` -### 8.2 添加 hal 模块(硬件抽象) +### 7.2 添加 hal 模块(硬件抽象) #### 步骤 1:定义接口 (hal/inc/ek_hal_xxx.h) @@ -592,7 +529,7 @@ void st_xxx_drv_init(void) EK_EXPORT_HARDWARE(st_xxx_drv_init); ``` -### 8.3 添加移植层 +### 7.3 添加移植层 创建新的移植层目录(如 `port/stm32f407/`),参考 `stm32f429zi/` 的实现: @@ -614,7 +551,7 @@ void st_gpio_drv_init(void) EK_EXPORT_HARDWARE(st_gpio_drv_init); ``` -## 9. 常见问题 +## 8. 常见问题 **Q: hal/ 子目录可以直接使用 utils/ 的数据结构吗?** diff --git a/L2_Core/third_party/letter_shell/shell.c b/L2_Core/third_party/letter_shell/shell.c index c9fc39b..51609e9 100644 --- a/L2_Core/third_party/letter_shell/shell.c +++ b/L2_Core/third_party/letter_shell/shell.c @@ -11,8 +11,8 @@ #include "inc/shell.h" #include "../lwprintf/inc/lwprintf.h" -#include "string.h" -#include "stdarg.h" +#include +#include #if SHELL_AUTO_PRASE == 1 # include "inc/shell_ext.h" @@ -56,7 +56,7 @@ static const char *shellText[] = { [TEXT_READ_NOT_DEF] = "error: shell.read must be defined\r\n", }; -static SHELL_TypeDef *shellList[SHELL_MAX_NUMBER] = {NULL}; /**< shell列表 */ +static SHELL_TypeDef *shellList[SHELL_MAX_NUMBER] = { NULL }; /**< shell列表 */ static void shellAdd(SHELL_TypeDef *shell); static void shellDisplayItem(SHELL_TypeDef *shell, unsigned short index); @@ -104,12 +104,12 @@ const SHELL_VaribaleTypeDef shellDefaultVariableList[] = { * */ const SHELL_KeyFunctionDef shellDefaultKeyFunctionList[] = { - {SHELL_KEY_LF, shellEnter }, - {SHELL_KEY_CR, shellEnter }, - {SHELL_KEY_TAB, shellTab }, - {SHELL_KEY_BACKSPACE, shellBackspace}, - {SHELL_KEY_DELETE, shellBackspace}, - {SHELL_KEY_ESC, shellAnsiStart}, + { SHELL_KEY_LF, shellEnter }, + { SHELL_KEY_CR, shellEnter }, + { SHELL_KEY_TAB, shellTab }, + { SHELL_KEY_BACKSPACE, shellBackspace }, + { SHELL_KEY_DELETE, shellBackspace }, + { SHELL_KEY_ESC, shellAnsiStart }, }; /** diff --git a/L2_Core/utils/inc/ek_io.h b/L2_Core/utils/inc/ek_io.h index 3812491..8258448 100644 --- a/L2_Core/utils/inc/ek_io.h +++ b/L2_Core/utils/inc/ek_io.h @@ -13,7 +13,7 @@ #include "../../../ek_conf.h" -#if EK_IO_ENABLE == 1 +#if EK_IO_NO_LWPRTF == 0 # include "../../third_party/lwprintf/inc/lwprintf.h" @@ -35,6 +35,25 @@ */ void ek_io_init(void); -#endif /* EK_IO_ENABLE */ +# define ek_printf lwprintf +# define ek_vprintf lwvprintf +# define ek_sprintf lwsprintf +# define ek_snprintf lwsnprintf +# define ek_vsnprintf lwvsnprintf + +#else + +void ek_io_init(void); + +# define EK_IO_FPUTC() + +// 如果不需要使用lwprintf 需要补全下列的宏 +# define ek_printf +# define ek_vsprintf +# define ek_sprintf +# define ek_snprintf +# define ek_vsnprintf + +#endif /* EK_IO_NO_LWPRTF */ #endif diff --git a/L2_Core/utils/src/ek_io.c b/L2_Core/utils/src/ek_io.c index 0b53172..1fce611 100644 --- a/L2_Core/utils/src/ek_io.c +++ b/L2_Core/utils/src/ek_io.c @@ -6,7 +6,7 @@ #include "../inc/ek_io.h" -#if EK_IO_ENABLE == 1 +#if EK_IO_NO_LWPRTF == 0 # include "../inc/ek_def.h" @@ -30,4 +30,11 @@ void ek_io_init(void) lwprintf_init(_ek_io_printf); } -#endif /* EK_IO_ENABLE */ +#else +// 如果不使用lwprintf作为IO库,需要自己在这里实现 + +void ek_io_init(void) +{ +} + +#endif /* EK_IO_NO_LWPRTF */ diff --git a/L2_Core/utils/src/ek_log.c b/L2_Core/utils/src/ek_log.c index dc8bc68..6d89ec3 100644 --- a/L2_Core/utils/src/ek_log.c +++ b/L2_Core/utils/src/ek_log.c @@ -47,14 +47,14 @@ void _ek_log_printf(const char *tag, uint32_t line, ek_log_type_t type, uint32_t # if (EK_LOG_COLOR_ENABLE == 1) - lwprintf("%s[%s/%s L:%" PRIu32 ",T:%" PRIu32 "]:", - ek_log_color_table[type], - ek_log_type_table[type], - tag, - line, - _ek_log_get_tick()); + ek_printf("%s[%s/%s L:%" PRIu32 ",T:%" PRIu32 "]:", + ek_log_color_table[type], + ek_log_type_table[type], + tag, + line, + _ek_log_get_tick()); # else /* EK_LOG_COLOR_ENABLE == 1 */ - lwprintf("[%s/%s L:%" PRIu32 ",T:%" PRIu32 "]:", ek_log_type_table[type], tag, line, tick); + ek_printf("[%s/%s L:%" PRIu32 ",T:%" PRIu32 "]:", ek_log_type_table[type], tag, line, tick); # endif /* EK_LOG_COLOR_ENABLE == 1 */ va_list args; @@ -62,13 +62,13 @@ void _ek_log_printf(const char *tag, uint32_t line, ek_log_type_t type, uint32_t lwvsnprintf(ek_log_buffer, EK_LOG_BUFFER_SIZE - 1, fmt, args); va_end(args); - lwprintf("%s", ek_log_buffer); + ek_printf("%s", ek_log_buffer); # if (EK_LOG_COLOR_ENABLE == 1) - lwprintf(EK_LOG_COLOR_NONE); // 恢复日志颜色 + ek_printf(EK_LOG_COLOR_NONE); // 恢复日志颜色 # endif /* EK_LOG_COLOR_ENABLE == 1 */ - lwprintf(CRLF); // 换行符 + ek_printf(CRLF); // 换行符 EK_LOG_UNLOCK(); } diff --git a/L2_Core/utils/src/ek_str.c b/L2_Core/utils/src/ek_str.c index a468aea..8fabdd9 100644 --- a/L2_Core/utils/src/ek_str.c +++ b/L2_Core/utils/src/ek_str.c @@ -111,7 +111,7 @@ bool ek_str_append_fmt(ek_str_t *s, const char *fmt, ...) // 获取格式化字符串的长度 va_list args; va_start(args, fmt); - int len = lwvsnprintf(NULL, 0, fmt, args); + int len = ek_vsnprintf(NULL, 0, fmt, args); va_end(args); if (len < 0) return false; @@ -120,7 +120,7 @@ bool ek_str_append_fmt(ek_str_t *s, const char *fmt, ...) va_start(args, fmt); // +1 给 \0 - lwvsnprintf(s->buf + s->len, len + 1, fmt, args); + ek_vsnprintf(s->buf + s->len, len + 1, fmt, args); va_end(args); s->len += len; diff --git a/README.md b/README.md index 1943fdf..78bba65 100644 --- a/README.md +++ b/README.md @@ -255,9 +255,11 @@ void ek_main(void) #define EK_HEAP_NO_TLSF (0) #define EK_HEAP_SIZE (30 * 1024) +// IO库管理 +#define EK_IO_NO_LWPRTF (1) + // 模块功能开关 #define EK_EXPORT_ENABLE (0) -#define EK_IO_ENABLE (1) #define EK_STR_ENABLE (1) #define EK_LOG_ENABLE (1) #define EK_LIST_ENABLE (1) diff --git a/README_EN.md b/README_EN.md index 9b39bf9..e394231 100644 --- a/README_EN.md +++ b/README_EN.md @@ -255,9 +255,12 @@ The global configuration file `ek_conf.h` in the root directory manages framewor #define EK_HEAP_NO_TLSF (0) #define EK_HEAP_SIZE (30 * 1024) +// IO Lib Management +#define EK_IO_NO_LWPRTF (0) + + // Module Enable/Disable #define EK_EXPORT_ENABLE (0) -#define EK_IO_ENABLE (1) #define EK_STR_ENABLE (1) #define EK_LOG_ENABLE (1) #define EK_LIST_ENABLE (1) diff --git a/ek_conf.h b/ek_conf.h index c06ec25..0ceee69 100644 --- a/ek_conf.h +++ b/ek_conf.h @@ -22,10 +22,15 @@ #define EK_HEAP_NO_TLSF (0) #define EK_HEAP_SIZE (30 * 1024) +/* ======================================================================== + * IO库配置 + * -EK_IO_NO_LWPRTF : IO库不使用lwprintf + * ======================================================================== */ +#define EK_IO_NO_LWPRTF (0) + /* ======================================================================== * 模块功能开关 * - EK_EXPORT_ENABLE: 使能自动初始化 - * - EK_IO_ENABLE: 使能IO库(基于lwprintf) * - EK_STR_ENABLE: 使能字符串处理模块 * - EK_LOG_ENABLE: 使能日志模块 * - EK_LIST_ENABLE: 使能链表模块 @@ -35,7 +40,6 @@ * - EK_SHELL_ENABLE: 使能shell模块 * ======================================================================== */ #define EK_EXPORT_ENABLE (0) -#define EK_IO_ENABLE (1) #define EK_STR_ENABLE (1) #define EK_LOG_ENABLE (1) #define EK_LIST_ENABLE (1)