创建
This commit is contained in:
commit
da43152a7e
3380 files changed
+1128754
No files matched your search
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2026, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2026-02-11 RealThread first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
#include <drv_common.h>
|
||||
|
||||
#ifndef RT_WEAK
|
||||
#define RT_WEAK rt_weak
|
||||
#endif
|
||||
|
||||
RT_WEAK void rt_hw_board_init()
|
||||
{
|
||||
/* Heap initialization */
|
||||
#if defined(RT_USING_HEAP)
|
||||
rt_system_heap_init((void *) HEAP_BEGIN, (void *) HEAP_END);
|
||||
#endif
|
||||
|
||||
extern void hw_board_init();
|
||||
hw_board_init();
|
||||
|
||||
/* Set the shell console output device */
|
||||
#if defined(RT_USING_DEVICE) && defined(RT_USING_CONSOLE)
|
||||
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
|
||||
#endif
|
||||
|
||||
/* Board underlying hardware initialization */
|
||||
#ifdef RT_USING_COMPONENTS_INIT
|
||||
rt_components_board_init();
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,543 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2026, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2026-02-11 RealThread first version
|
||||
*/
|
||||
|
||||
#ifndef __BOARD_H__
|
||||
#define __BOARD_H__
|
||||
|
||||
#ifdef SOC_SERIES_GD32H75E
|
||||
#include <gd32h75e.h>
|
||||
#include "gd32h75e_exti.h"
|
||||
#else
|
||||
#include <gd32h7xx.h>
|
||||
#include "gd32h7xx_exti.h"
|
||||
#endif
|
||||
#include <drv_gpio.h>
|
||||
#include "drv_legacy.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/*-------------------------- CHIP CONFIG BEGIN --------------------------*/
|
||||
|
||||
#define CHIP_FAMILY_GD32
|
||||
#define CHIP_SERIES_GD32H7
|
||||
#define CHIP_NAME_GD32H75EYMJ7
|
||||
|
||||
/*-------------------------- CHIP CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- ROM/RAM CONFIG BEGIN --------------------------*/
|
||||
|
||||
#define ROM_START ((uint32_t)0x8000000)
|
||||
#define ROM_SIZE (3840 * 1024)
|
||||
#define ROM_END ((uint32_t)(ROM_START + ROM_SIZE))
|
||||
|
||||
#define RAM_START (0x24000000)
|
||||
#define RAM_SIZE (512 * 1024)
|
||||
#define RAM_END (RAM_START + RAM_SIZE)
|
||||
|
||||
/*-------------------------- ROM/RAM CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- UART CONFIG BEGIN --------------------------*/
|
||||
|
||||
/** After configuring corresponding UART or UART DMA, you can use it.
|
||||
*
|
||||
* STEP 1, define macro define related to the serial port opening based on the serial port number
|
||||
* such as #define BSP_USING_UART1
|
||||
*
|
||||
* STEP 2, according to the corresponding pin of serial port, define the related serial port information macro
|
||||
* such as #define BSP_UART1_TX_PIN "PA9"
|
||||
* #define BSP_UART1_RX_PIN "PA10"
|
||||
*
|
||||
* STEP 3, if you want using SERIAL DMA, you must open it in the RT-Thread Settings.
|
||||
* RT-Thread Setting -> Components -> Device Drivers -> Serial Device Drivers -> Enable Serial DMA Mode
|
||||
*
|
||||
* STEP 4, according to serial port number to define serial port tx/rx DMA function in the board.h file
|
||||
* such as #define BSP_UART1_RX_USING_DMA
|
||||
*
|
||||
*/
|
||||
|
||||
#define BSP_USING_UART1
|
||||
#define BSP_UART1_TX_PIN "PA9"
|
||||
#define BSP_UART1_RX_PIN "PA10"
|
||||
|
||||
/*-------------------------- UART CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- I2C CONFIG BEGIN --------------------------*/
|
||||
|
||||
/** How to enable and configure I2C (hardware)
|
||||
*
|
||||
* STEP 1, enable the I2C driver in RT-Thread Settings.
|
||||
* e.g. Components -> Device Drivers -> Using I2C device drivers
|
||||
*
|
||||
* STEP 2, turn on the I2C instance by defining the related macro, and prefer the
|
||||
* default board-level settings provided in i2c_config.h.
|
||||
* e.g. #define BSP_USING_I2C1
|
||||
*
|
||||
* STEP 3, if you accept the default pins in i2c_config.h, you are done. No further
|
||||
* pin configuration is required here.
|
||||
*
|
||||
* STEP 4, to override pins, set the port pins below for your MCU package according
|
||||
* to the datasheet (GD32H759xx Datasheet 2.6.3. GD32H759xx pin alternate functions):
|
||||
* e.g. #define BSP_I2C1_SCL_PIN "PH4"
|
||||
* #define BSP_I2C1_SDA_PIN "PB11"
|
||||
*
|
||||
* STEP 5, to override alternate function (AF), set the AF macro below in this file
|
||||
* according to the datasheet (GD32H759xx Datasheet 2.6.3. GD32H759xx pin alternate functions):
|
||||
* e.g. #define BSP_I2C1_AFIO "AF4"
|
||||
*
|
||||
* Notes:
|
||||
* - For details on using the I2C device, refer to the documentation center at the following link:
|
||||
* - https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/i2c/i2c
|
||||
* - If using the default configuration in i2c_config.h, just add the device macro (e.g., BSP_USING_I2C1) in board.h.
|
||||
* - To use custom pins, follow the definitions below.
|
||||
*/
|
||||
|
||||
/*----------------------- Driver configuration example ----------------------*/
|
||||
/* #define BSP_USING_I2C1 */
|
||||
/* #define BSP_I2C1_SCL_PIN "PH4" */
|
||||
/* #define BSP_I2C1_SDA_PIN "PB11" */
|
||||
/* #define BSP_I2C1_AFIO "AF4" */
|
||||
|
||||
/*---------- Configure your desired device here as described above ---------*/
|
||||
/* USER CODE BEGIN */
|
||||
|
||||
/* USER CODE END */
|
||||
|
||||
/*-------------------------- I2C CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- SPI CONFIG BEGIN --------------------------*/
|
||||
|
||||
/** How to enable and configure SPI (hardware)
|
||||
*
|
||||
* STEP 1, enable the SPI driver in RT-Thread Settings.
|
||||
* e.g. Components -> Device Drivers -> Using SPI Bus/Device drivers
|
||||
*
|
||||
* STEP 2, turn on the SPI instance by defining the related macro, and prefer the
|
||||
* default board-level settings provided in spi_config.h.
|
||||
* e.g. #define BSP_USING_SPI1
|
||||
*
|
||||
* STEP 3, if you accept the default pins in spi_config.h, you are done. No further
|
||||
* pin configuration is required here.
|
||||
*
|
||||
* STEP 4, to override pins, set the port pins below for your MCU package according
|
||||
* to the datasheet (GD32H759xx Datasheet 2.6.3. GD32H759xx pin alternate functions):
|
||||
* e.g. #define BSP_SPI1_SCK_PIN "PB13"
|
||||
* #define BSP_SPI1_MISO_PIN "PB14"
|
||||
* #define BSP_SPI1_MOSI_PIN "PB15"
|
||||
*
|
||||
* STEP 5, to override alternate function (AF), set the AF macro below in this file
|
||||
* according to the datasheet (GD32H759xx Datasheet 2.6.3. GD32H759xx pin alternate functions):
|
||||
* e.g. #define BSP_SPI1_AFIO "AF5"
|
||||
*
|
||||
* Notes:
|
||||
* - For details on using the SPI device, refer to the documentation center at the following link:
|
||||
* - https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/spi/spi
|
||||
* - If using the default configuration in spi_config.h, just add the device macro (e.g., BSP_USING_SPI1) in board.h.
|
||||
* - To use custom pins, follow the definitions below.
|
||||
*/
|
||||
|
||||
/*----------------------- Driver configuration example ----------------------*/
|
||||
/* #define BSP_USING_SPI1 */
|
||||
/* #define BSP_SPI1_SCK_PIN "PB13" */
|
||||
/* #define BSP_SPI1_MISO_PIN "PB14" */
|
||||
/* #define BSP_SPI1_MOSI_PIN "PB15" */
|
||||
/* #define BSP_SPI1_AFIO "AF5" */
|
||||
|
||||
/*---------- Configure your desired device here as described above ---------*/
|
||||
/* USER CODE BEGIN */
|
||||
|
||||
/* USER CODE END */
|
||||
|
||||
/*-------------------------- SPI CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- PWM CONFIG BEGIN --------------------------*/
|
||||
|
||||
/** How to enable and configure PWM (hardware)
|
||||
*
|
||||
* STEP 1, enable the PWM driver in RT-Thread Settings.
|
||||
* e.g. Components -> Device Drivers -> Using PWM device drivers
|
||||
*
|
||||
* STEP 2, turn on the PWM instance by defining the related macro, and prefer the
|
||||
* default board-level settings provided in pwm_config.h.
|
||||
* e.g. #define BSP_USING_PWM0
|
||||
*
|
||||
* STEP 3, if you accept the default pins in pwm_config.h, you are done. No further
|
||||
* pin configuration is required here.
|
||||
*
|
||||
* STEP 4, to override pins, set the port pins below for your MCU package according
|
||||
* to the datasheet (GD32H759xx Datasheet 2.6.3. GD32H759xx pin alternate functions):
|
||||
* e.g. #define BSP_PWM0_PIN "PC7"
|
||||
* #define BSP_PWM0_CHANNEL 3
|
||||
*
|
||||
* STEP 5, to override alternate function (AF), set the AF macro below in this file
|
||||
* according to the datasheet (GD32H759xx Datasheet 2.6.3. GD32H759xx pin alternate functions):
|
||||
* e.g. #define BSP_PWM0_AFIO "AF1"
|
||||
*
|
||||
* Notes:
|
||||
* - For details on using the PWM device, refer to the documentation center at the following link:
|
||||
* - https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/pwm/pwm
|
||||
* - If using the default configuration in pwm_config.h, just add the device macro (e.g., BSP_USING_PWM0) in board.h.
|
||||
* - To use custom pins, follow the definitions below.
|
||||
*/
|
||||
|
||||
/*----------------------- PWM Driver configuration example ----------------------*/
|
||||
/* #define BSP_USING_PWM0 */
|
||||
/* #define BSP_PWM0_PIN "PC7" */
|
||||
/* #define BSP_PWM0_CHANNEL 3 */
|
||||
/* #define BSP_PWM0_AFIO "AF1" */
|
||||
|
||||
/*---------- Configure your desired device here as described above ---------*/
|
||||
/* USER CODE BEGIN */
|
||||
|
||||
/* USER CODE END */
|
||||
|
||||
/*-------------------------- PWM CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- ADC CONFIG BEGIN --------------------------*/
|
||||
|
||||
/** How to enable and configure ADC
|
||||
*
|
||||
* STEP 1, enable the ADC driver in RT-Thread Settings.
|
||||
* e.g. Components -> Device Drivers -> Using ADC device drivers
|
||||
*
|
||||
* STEP 2, turn on the ADC instance by defining the related macro.
|
||||
* e.g. #define BSP_USING_ADC0
|
||||
*
|
||||
* Notes:
|
||||
* - For details on using the ADC device, refer to the documentation center at the following link:
|
||||
* - https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/adc/adc
|
||||
* - The ADC pins are defined in adc_config.h.
|
||||
* - To view the corresponding pins and channels, refer to the GD32H759xx Datasheet.
|
||||
*/
|
||||
|
||||
/*----------------------- ADC Driver configuration example ----------------------*/
|
||||
/* #define BSP_USING_ADC0 */
|
||||
|
||||
/*---------- Configure your desired device here as described above ---------*/
|
||||
/* USER CODE BEGIN */
|
||||
|
||||
/* USER CODE END */
|
||||
|
||||
/*-------------------------- ADC CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- DAC CONFIG BEGIN --------------------------*/
|
||||
|
||||
/** How to enable and configure DAC
|
||||
*
|
||||
* STEP 1, enable the DAC driver in RT-Thread Settings.
|
||||
* e.g. Components -> Device Drivers -> Using DAC device drivers
|
||||
*
|
||||
* STEP 2, turn on the DAC instance by defining the related macro, and prefer the
|
||||
* default board-level settings provided in dac_config.h.
|
||||
* e.g. #define BSP_USING_DAC0
|
||||
*
|
||||
* STEP 3, if you accept the default pins in dac_config.h, you are done. No further
|
||||
* pin configuration is required here.
|
||||
*
|
||||
* STEP 4, to override pins, set the port pins below for your MCU package according
|
||||
* to the datasheet (GD32H759xx Datasheet 2.6.3. GD32H759xx pin alternate functions):
|
||||
* e.g. #define BSP_DAC0_PIN "PA4"
|
||||
* #define BSP_DAC0_CHANNEL DAC_OUT0
|
||||
*
|
||||
* Notes:
|
||||
* - For details on using the DAC device, refer to the documentation center at the following link:
|
||||
* - https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/dac/dac
|
||||
* - If using the default configuration in dac_config.h, just add the device macro (e.g., BSP_USING_DAC0) in board.h.
|
||||
* - To use custom pins, follow the definitions below.
|
||||
*/
|
||||
|
||||
/*-----------------------DAC Driver configuration example ----------------------*/
|
||||
/* #define BSP_USING_DAC0 */
|
||||
/* #define BSP_DAC0_PIN "PA4" */
|
||||
/* #define BSP_DAC0_CHANNEL DAC_OUT0 */
|
||||
|
||||
/*---------- Configure your desired device here as described above ---------*/
|
||||
/* USER CODE BEGIN */
|
||||
|
||||
/* USER CODE END */
|
||||
|
||||
/*-------------------------- DAC CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- WDT CONFIG BEGIN --------------------------*/
|
||||
|
||||
/** How to enable and configure WDT
|
||||
*
|
||||
* STEP 1, enable the WDT driver in RT-Thread Settings.
|
||||
* e.g. Components -> Device Drivers -> Using Watchdog device drivers
|
||||
*
|
||||
* Notes:
|
||||
* - For details on using the WDT device, refer to the documentation center at the following link:
|
||||
* - https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/watchdog/watchdog
|
||||
*/
|
||||
|
||||
/*-------------------------- WDT CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- HARDWARE TIMER CONFIG BEGIN --------------------------*/
|
||||
|
||||
/** if you want to use hardware timer you can use the following instructions.
|
||||
*
|
||||
* STEP 1, enable the hardware timer driver in RT-Thread Settings.
|
||||
* e.g. Components -> Device Drivers -> Using hardware timer device drivers
|
||||
*
|
||||
* STEP 2, define macro related to the hwtimer
|
||||
* such as #define BSP_USING_HWTIMER0
|
||||
*
|
||||
* Notes:
|
||||
* - The macro definitions and device names for the hardware timer are defined in drv_hwtimer.c.
|
||||
* - For details on using the hardware timer device, refer to the documentation center at the following link:
|
||||
* - https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/hwtimer/hwtimer
|
||||
*/
|
||||
|
||||
/*-----------------------HARDWARE TIMER configuration example ----------------------*/
|
||||
/* #define BSP_USING_HWTIMER0 */
|
||||
|
||||
/*---------- Configure your desired device here as described above ---------*/
|
||||
/* USER CODE BEGIN */
|
||||
|
||||
/* USER CODE END */
|
||||
|
||||
/*-------------------------- HARDWARE TIMER CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- RTC CONFIG BEGIN --------------------------*/
|
||||
|
||||
/** How to enable and configure RTC
|
||||
*
|
||||
* STEP 1, enable the RTC driver in RT-Thread Settings.
|
||||
* e.g. Components -> Device Drivers -> Using RTC device drivers
|
||||
*
|
||||
* STEP 2, define macro related to the RTC
|
||||
* such as #define BSP_USING_ALARM0
|
||||
*
|
||||
* Notes:
|
||||
* - The macro definitions and device names for the RTC are defined in drv_rtc.c.
|
||||
* - For details on using the RTC device, refer to the documentation center at the following link:
|
||||
* - https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/rtc/rtc
|
||||
*/
|
||||
|
||||
/*-----------------------RTC configuration example ----------------------*/
|
||||
/* #define BSP_USING_ALARM0 */
|
||||
|
||||
/*---------- Configure your desired device here as described above ---------*/
|
||||
/* USER CODE BEGIN */
|
||||
|
||||
/* USER CODE END */
|
||||
|
||||
/*-------------------------- RTC CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- SDIO CONFIG BEGIN --------------------------*/
|
||||
|
||||
/** How to enable and configure SDIO
|
||||
* STEP 1, enable the SDIO driver in RT-Thread Settings.
|
||||
* e.g. Components -> Device Drivers -> Using SD/EMMC device drivers
|
||||
* STEP 2, enable the DFS driver in RT-Thread Settings.
|
||||
* e.g. Components -> DFS -> Using DFS device drivers
|
||||
* STEP 3, enable the elm-Fatfs driver in RT-Thread Settings.
|
||||
* e.g. Components -> DFS -> Using elm-Fatfs device drivers
|
||||
*
|
||||
* Notes:
|
||||
* - The SDIO pin configuration is implemented in the gpio_config() function
|
||||
* located in drv_sdio.c.
|
||||
* - Before using the SDIO interface, please consult the MCU datasheet and ensure
|
||||
* that all related pins are configured according to the hardware requirements.
|
||||
* - If custom pins are needed, update the configuration inside gpio_config()
|
||||
* accordingly.
|
||||
*/
|
||||
|
||||
/*-------------------------- SDIO CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- CAN CONFIG BEGIN --------------------------*/
|
||||
|
||||
/** How to enable and configure CAN
|
||||
*
|
||||
* STEP 1, enable the CAN driver in RT-Thread Settings.
|
||||
* e.g. Components -> Device Drivers -> Using CAN device drivers
|
||||
*
|
||||
* STEP 2, turn on the CAN instance by defining the related macro, and prefer the
|
||||
* default board-level settings provided in can_config.h.
|
||||
* e.g. #define BSP_USING_CAN0
|
||||
*
|
||||
* STEP 3, if you accept the default pins in can_config.h, you are done. No further
|
||||
* pin configuration is required here.
|
||||
*
|
||||
* STEP 4, to override pins, set the port pins below for your MCU package according
|
||||
* to the datasheet (GD32H759xx Datasheet 2.6.3. GD32H759xx pin alternate functions):
|
||||
* e.g. #define BSP_CAN0_RX_PIN "PD0"
|
||||
* #define BSP_CAN0_TX_PIN "PD1"
|
||||
*
|
||||
* STEP 5, to override alternate function (AF), set the AF macro below in this file
|
||||
* according to the datasheet (GD32H759xx Datasheet 2.6.3. GD32H759xx pin alternate functions):
|
||||
* e.g. #define BSP_CAN0_AFIO "AF9"
|
||||
*
|
||||
* Notes:
|
||||
* - For details on using the CAN device, refer to the documentation center at the following link:
|
||||
* - https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/can/can
|
||||
* - If using the default configuration in can_config.h, just add the device macro (e.g., BSP_USING_CAN0) in board.h.
|
||||
* - To use custom pins, follow the definitions below.
|
||||
*/
|
||||
|
||||
/*-----------------------CAN Driver configuration example ----------------------*/
|
||||
/* #define BSP_USING_CAN0 */
|
||||
/* #define BSP_CAN0_RX_PIN "PD0" */
|
||||
/* #define BSP_CAN0_TX_PIN "PD1" */
|
||||
/* #define BSP_CAN0_AFIO "AF9" */
|
||||
|
||||
/*---------- Configure your desired device here as described above ---------*/
|
||||
/* USER CODE BEGIN */
|
||||
|
||||
/* USER CODE END */
|
||||
|
||||
/*-------------------------- CAN CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- LCD CONFIG BEGIN --------------------------*/
|
||||
|
||||
/** How to enable and configure LCD
|
||||
* STEP 1, enable the SDIO driver in RT-Thread Settings.
|
||||
* e.g. Components -> Device Drivers -> Using LCD device drivers
|
||||
*
|
||||
* Notes:
|
||||
* - The LCD pin configuration is implemented in the tli_gpio_config() function
|
||||
* located in drv_lcd.c.
|
||||
* - Before using the LCD, please consult the MCU datasheet and ensure that all
|
||||
* related pins are configured according to the hardware requirements.
|
||||
* - If custom pins are needed, update the configuration inside tli_gpio_config()
|
||||
* accordingly.
|
||||
*/
|
||||
|
||||
/*-------------------------- LCD CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- ETH CONFIG BEGIN --------------------------*/
|
||||
|
||||
/** if you want to use eth you can use the following instructions.
|
||||
*
|
||||
* STEP 1, enable the network interface device in RT-Thread Settings.
|
||||
* e.g. Components -> Network -> Enable network interface device
|
||||
*
|
||||
* STEP 2, enable the socket abstraction layer in RT-Thread Settings.
|
||||
* e.g. Components -> Network -> SAL: socket abstraction layer
|
||||
*
|
||||
* STEP 3, select the lwip stack and features you need:
|
||||
* e.g. Components -> Network -> LwIP: light weight TCP/IP stack
|
||||
*
|
||||
* STEP 4, configure MPU settings for Ethernet DMA descriptors and buffers:
|
||||
* Check and modify the enet_mpu_config() function in drivers/drv_enet.c:
|
||||
* - Configure MPU region for DMA descriptors and Rx/Tx buffers (0x30000000)
|
||||
* - Set appropriate memory attributes (bufferable, non-cacheable, non-shareable)
|
||||
* - Ensure MPU region size matches your actual buffer requirements
|
||||
*
|
||||
* STEP 5, configure Ethernet GPIO pins according to your hardware design:
|
||||
* Check and modify the enet_gpio_config() function in drivers/rtt/include/config/enet_config.h:
|
||||
* - Verify all MII/RMII/RGMII interface pins are correctly configured
|
||||
* - Check clock output configuration (such as: PA8 for PHY reference clock)
|
||||
* - Ensure correct alternate function (such as: AF11 for Ethernet pins)
|
||||
* - Configure PHY reset pin if required by your hardware
|
||||
*
|
||||
* Notes:
|
||||
* - The pin configuration in enet_gpio_config() must match your actual hardware design and PCB layout
|
||||
* - MPU configuration in enet_mpu_config() is critical for proper DMA operation
|
||||
* - For MII/RMII/RGMII interface, ensure all required pins are properly configured in enet_gpio_config()
|
||||
* - Refer to GD32H7xx datasheet for Ethernet pin alternate function mapping
|
||||
* - Refer to PHY chip datasheet for specific configuration requirements
|
||||
*/
|
||||
|
||||
/*-------------------------- ETH CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- USB HOST CONFIG BEGIN --------------------------*/
|
||||
|
||||
/** How to enable and configure USB Host (hardware)
|
||||
*
|
||||
* STEP 1, enable the USB Host driver in RT-Thread Settings.
|
||||
* e.g. Components -> Device Drivers -> Using USB -> USB Host
|
||||
*
|
||||
* STEP 2, select the USB Host stack and drivers you need:
|
||||
* e.g. USB Host -> Using USB Host
|
||||
* USB Host -> Using USB Host -> Enable UDisk Drivers
|
||||
* USB Host -> Using USB Host -> Enable HID Drivers
|
||||
*
|
||||
* STEP 3, define the basic USB configuration macros in board.h:
|
||||
* e.g. #define BSP_USING_USB // Enable USB peripheral
|
||||
* #define USE_USBHS0 // Enable USBHS0 instance
|
||||
*
|
||||
* STEP 4, select USB speed mode in board.h:
|
||||
* For High Speed (HS) mode:
|
||||
* e.g. #define USE_USB_HS
|
||||
* For Full Speed (FS) mode:
|
||||
* e.g. #define USE_USB_FS
|
||||
*
|
||||
* STEP 5, verify and modify the VBUS power switch configuration in the hardware driver:
|
||||
* Check and modify the following definitions in drivers/usb/gd32h7_usb_hw.c:
|
||||
* e.g. #define HOST_POWERSW_PORT_RCC RCU_GPIOG
|
||||
* #define HOST_POWERSW_PORT GPIOG
|
||||
* #define HOST_POWERSW_VBUS GPIO_PIN_7
|
||||
* Ensure these definitions match your actual hardware design and pin connections.
|
||||
*
|
||||
* Notes:
|
||||
* - USB HS (High Speed) requires external PHY and supports 480 Mbps data rate
|
||||
* - USB FS (Full Speed) uses internal PHY and supports 12 Mbps data rate
|
||||
* - The pin configuration depends on the specific USB instance (USBHS0/USBHS1) and package type
|
||||
* - The HOST_POWERSW_VBUS configuration in gd32h7_usb_hw.c must match your actual hardware design
|
||||
* - Refer to GD32H7xx datasheet for the specific pin alternate function mapping
|
||||
*/
|
||||
|
||||
/*----------------------- Driver configuration example ----------------------*/
|
||||
/* Basic USB configuration in board.h */
|
||||
/* #define BSP_USING_USB */
|
||||
/* #define USE_USBHS0 | #define USE_USBHS1 */
|
||||
/* #define USE_USB_HS | #define USE_USB_FS */
|
||||
|
||||
/*-------------------------- USB HOST CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- USB DEVICE CONFIG BEGIN --------------------------*/
|
||||
|
||||
/** How to enable and configure USB Device (hardware)
|
||||
*
|
||||
* STEP 1, enable the USB Device driver in RT-Thread Settings.
|
||||
* e.g. Components -> Device Drivers -> Using USB -> USB Device
|
||||
*
|
||||
* STEP 2, select the USB Device stack and device classes you need:
|
||||
* e.g. USB Device -> Using USB Device
|
||||
* USB Device -> Using USB Device -> Enable CDC Virtual Com Port
|
||||
* USB Device -> Using USB Device -> Enable Mass Storage Gadget
|
||||
* USB Device -> Using USB Device -> Enable HID Gadget
|
||||
* -> ...
|
||||
*
|
||||
* STEP 3, define the basic USB configuration macros in board.h:
|
||||
* e.g. #define BSP_USING_USB // Enable USB peripheral
|
||||
* #define USE_USBHS0 // Enable USBHS0 instance
|
||||
*
|
||||
* STEP 4, select USB speed mode in board.h:
|
||||
* For High Speed (HS) mode:
|
||||
* e.g. #define USE_USB_HS
|
||||
* For Full Speed (FS) mode:
|
||||
* e.g. #define USE_USB_FS
|
||||
*
|
||||
* Notes:
|
||||
* - USB HS (High Speed) requires external PHY and supports 480 Mbps data rate
|
||||
* - USB FS (Full Speed) uses internal PHY and supports 12 Mbps data rate
|
||||
* - The pin configuration depends on the specific USB instance (USBHS0/USBHS1) and package type
|
||||
* - The DEVICE_VBUS configuration in gd32h7_usb_hw.c must match your actual hardware design
|
||||
* - For CDC Virtual Com Port, additional configurations may be needed in the device class settings
|
||||
* - Refer to GD32H7xx datasheet for the specific pin alternate function mapping
|
||||
*/
|
||||
|
||||
/*----------------------- Driver configuration example ----------------------*/
|
||||
/* Basic USB configuration in board.h */
|
||||
/* #define BSP_USING_USB */
|
||||
/* #define USE_USBHS0 | #define USE_USBHS1 */
|
||||
/* #define USE_USB_HS | #define USE_USB_FS */
|
||||
|
||||
/*-------------------------- USB DEVICE CONFIG END --------------------------*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BOARD_H__ */
|
||||
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-10-15 LZerro first version
|
||||
* 2025-10-22 kurisaw optimize multi-channel GPIO configuration
|
||||
*/
|
||||
|
||||
#include "drv_adc.h"
|
||||
#include "adc_config.h"
|
||||
|
||||
#define DBG_TAG "drv.adc"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#ifdef RT_USING_ADC
|
||||
|
||||
#if defined(BSP_USING_ADC0)
|
||||
struct rt_adc_device adc0;
|
||||
#endif
|
||||
|
||||
#if defined(BSP_USING_ADC1)
|
||||
struct rt_adc_device adc1;
|
||||
#endif
|
||||
|
||||
#if defined(BSP_USING_ADC2)
|
||||
struct rt_adc_device adc2;
|
||||
#endif
|
||||
|
||||
static const struct gd32_adc adc_obj[] = {
|
||||
#ifdef BSP_USING_ADC0
|
||||
ADC0_CONFIG,
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_ADC1
|
||||
ADC1_CONFIG,
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_ADC2
|
||||
ADC2_CONFIG,
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief ADC MSP Initialization
|
||||
* This function configures the hardware resources.
|
||||
* @param adc_clk, pin_name
|
||||
* @retval None
|
||||
*/
|
||||
static void gd32_adc_gpio_init(rcu_periph_enum adc_clk, const char *pin_name)
|
||||
{
|
||||
rt_uint32_t port, pin;
|
||||
rcu_periph_enum gpio_periph;
|
||||
|
||||
/* Skip if no valid pin name */
|
||||
if (pin_name == RT_NULL || rt_strcmp(pin_name, "-1") == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parse pin configuration */
|
||||
if (get_pin_config(pin_name, &port, &pin, &gpio_periph) == -RT_ERROR)
|
||||
{
|
||||
LOG_E("Failed to get pin config for %s", pin_name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enable ADC clock */
|
||||
rcu_periph_clock_enable(adc_clk);
|
||||
|
||||
/* Enable GPIO clock */
|
||||
rcu_periph_clock_enable(gpio_periph);
|
||||
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32E23x || defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E
|
||||
/* Configure ADC pin as analog mode */
|
||||
gpio_mode_set(port, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, pin);
|
||||
#else
|
||||
/* Configure ADC pin as analog input */
|
||||
gpio_init(port, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, pin);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ADC enable
|
||||
* This function enables ADC.
|
||||
* @param device, channel, enabled
|
||||
* @retval None
|
||||
*/
|
||||
static rt_err_t gd32_adc_enabled(struct rt_adc_device *device, rt_int8_t channel, rt_bool_t enabled)
|
||||
{
|
||||
uint32_t adc_periph;
|
||||
struct gd32_adc *adc = (struct gd32_adc *)device->parent.user_data;
|
||||
|
||||
if (channel >= MAX_EXTERN_ADC_CHANNEL)
|
||||
{
|
||||
LOG_E("invalid channel");
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
adc_periph = (uint32_t)(adc->adc_periph);
|
||||
|
||||
if (enabled == ENABLE)
|
||||
{
|
||||
#if defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E
|
||||
/* Disable ADC first */
|
||||
adc_disable(adc_periph);
|
||||
#endif
|
||||
|
||||
/* Initialize pin */
|
||||
gd32_adc_gpio_init(adc->adc_clk, adc->adc_pins[channel]);
|
||||
|
||||
#if defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E
|
||||
/* Configure clock, ADC0/1 max clock config 72M, ADC2 80M */
|
||||
adc_clock_config(adc_periph, ADC_CLK_SYNC_HCLK_DIV6);
|
||||
|
||||
/* Set ADC resolution */
|
||||
adc_resolution_config(adc_periph, ADC_RESOLUTION_12B);
|
||||
#endif
|
||||
|
||||
/* Set ADC data alignment mode */
|
||||
#if defined SOC_SERIES_GD32E23x
|
||||
adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
|
||||
#else
|
||||
adc_data_alignment_config(adc_periph, ADC_DATAALIGN_RIGHT);
|
||||
#endif
|
||||
|
||||
/* Set as regular channel */
|
||||
#if defined SOC_SERIES_GD32F4xx
|
||||
adc_channel_length_config(adc_periph, ADC_ROUTINE_CHANNEL, 1);
|
||||
adc_external_trigger_source_config(adc_periph, ADC_ROUTINE_CHANNEL, ADC_EXTTRIG_ROUTINE_EXTI_11);
|
||||
adc_external_trigger_config(adc_periph, ADC_ROUTINE_CHANNEL, ENABLE);
|
||||
#elif defined SOC_SERIES_GD32H75E
|
||||
adc_channel_length_config(adc_periph, ADC_ROUTINE_CHANNEL, 1);
|
||||
adc_external_trigger_config(adc_periph, ADC_ROUTINE_CHANNEL, ENABLE);
|
||||
#elif defined SOC_SERIES_GD32E23x
|
||||
adc_channel_length_config(ADC_REGULAR_CHANNEL, 1);
|
||||
adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE);
|
||||
adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);
|
||||
#elif defined SOC_SERIES_GD32H7xx
|
||||
adc_channel_length_config(adc_periph, ADC_REGULAR_CHANNEL, 1);
|
||||
#else
|
||||
adc_channel_length_config(adc_periph, ADC_REGULAR_CHANNEL, 1);
|
||||
adc_external_trigger_source_config(adc_periph, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);
|
||||
adc_external_trigger_config(adc_periph, ADC_REGULAR_CHANNEL, ENABLE);
|
||||
#endif
|
||||
|
||||
#if defined SOC_SERIES_GD32E23x
|
||||
adc_enable();
|
||||
#else
|
||||
adc_enable(adc_periph);
|
||||
#endif
|
||||
|
||||
/* Delay for ADC startup */
|
||||
rt_thread_mdelay(1);
|
||||
|
||||
/* Calibrate ADC */
|
||||
#if defined SOC_SERIES_GD32E23x
|
||||
adc_calibration_enable();
|
||||
#elif defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E
|
||||
adc_calibration_mode_config(adc_periph, ADC_CALIBRATION_OFFSET);
|
||||
adc_calibration_number(adc_periph, ADC_CALIBRATION_NUM1);
|
||||
adc_calibration_enable(adc_periph);
|
||||
#else
|
||||
adc_calibration_enable(adc_periph);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined SOC_SERIES_GD32E23x
|
||||
adc_disable();
|
||||
#else
|
||||
adc_disable(adc_periph);
|
||||
#endif
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert ADC.
|
||||
* This function gets ADC value.
|
||||
* @param device, channel, value
|
||||
* @retval None
|
||||
*/
|
||||
static rt_err_t gd32_adc_convert(struct rt_adc_device *device, rt_int8_t channel, rt_uint32_t *value)
|
||||
{
|
||||
uint32_t adc_periph;
|
||||
uint32_t timeout = 0;
|
||||
struct gd32_adc *adc = (struct gd32_adc *)(device->parent.user_data);
|
||||
|
||||
if (!value)
|
||||
{
|
||||
LOG_E("invalid param");
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
adc_periph = (uint32_t)(adc->adc_periph);
|
||||
|
||||
#if defined SOC_SERIES_GD32E23x
|
||||
adc_flag_clear(ADC_FLAG_EOC | ADC_FLAG_STRC);
|
||||
#else
|
||||
adc_flag_clear(adc_periph, ADC_FLAG_EOC | ADC_FLAG_STRC);
|
||||
#endif
|
||||
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32H75E
|
||||
adc_routine_channel_config(adc_periph, 0, channel, 480);
|
||||
adc_software_trigger_enable(adc_periph, ADC_ROUTINE_CHANNEL);
|
||||
#elif defined SOC_SERIES_GD32E23x
|
||||
adc_regular_channel_config(0, channel, ADC_SAMPLETIME_13POINT5);
|
||||
adc_software_trigger_enable(ADC_REGULAR_CHANNEL);
|
||||
#elif defined SOC_SERIES_GD32H7xx
|
||||
adc_regular_channel_config(adc_periph, 0, channel, 480);
|
||||
adc_software_trigger_enable(adc_periph, ADC_REGULAR_CHANNEL);
|
||||
#else
|
||||
adc_regular_channel_config(adc_periph, 0, channel, ADC_SAMPLETIME_13POINT5);
|
||||
adc_software_trigger_enable(adc_periph, ADC_REGULAR_CHANNEL);
|
||||
#endif
|
||||
|
||||
/* Wait for conversion complete */
|
||||
#if defined SOC_SERIES_GD32E23x
|
||||
while (!adc_flag_get(ADC_FLAG_EOC))
|
||||
#else
|
||||
while (!adc_flag_get(adc_periph, ADC_FLAG_EOC))
|
||||
#endif
|
||||
{
|
||||
if (timeout >= 100)
|
||||
{
|
||||
#if defined SOC_SERIES_GD32E23x
|
||||
adc_flag_clear(ADC_FLAG_EOC | ADC_FLAG_STRC);
|
||||
#else
|
||||
adc_flag_clear(adc_periph, ADC_FLAG_EOC | ADC_FLAG_STRC);
|
||||
#endif
|
||||
LOG_E("Convert Timeout");
|
||||
return -RT_ETIMEOUT;
|
||||
}
|
||||
|
||||
timeout++;
|
||||
rt_thread_delay(1);
|
||||
}
|
||||
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32H75E
|
||||
*value = adc_routine_data_read(adc_periph);
|
||||
adc_flag_clear(adc_periph, ADC_FLAG_EOC | ADC_FLAG_STRC);
|
||||
#elif defined SOC_SERIES_GD32E23x
|
||||
*value = adc_regular_data_read();
|
||||
adc_flag_clear(ADC_FLAG_EOC | ADC_FLAG_STRC);
|
||||
#else
|
||||
*value = adc_regular_data_read(adc_periph);
|
||||
adc_flag_clear(adc_periph, ADC_FLAG_EOC | ADC_FLAG_STRC);
|
||||
#endif
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static struct rt_adc_ops gd32_adc_ops = {
|
||||
.enabled = gd32_adc_enabled,
|
||||
.convert = gd32_adc_convert,
|
||||
};
|
||||
|
||||
static int rt_hw_adc_init(void)
|
||||
{
|
||||
int ret, i = 0;
|
||||
|
||||
syscfg_analog_switch_enable(SYSCFG_PA0_ANALOG_SWITCH);
|
||||
syscfg_analog_switch_enable(SYSCFG_PA1_ANALOG_SWITCH);
|
||||
syscfg_analog_switch_enable(SYSCFG_PC2_ANALOG_SWITCH);
|
||||
syscfg_analog_switch_enable(SYSCFG_PC3_ANALOG_SWITCH);
|
||||
|
||||
for (; i < sizeof(adc_obj) / sizeof(adc_obj[0]); i++)
|
||||
{
|
||||
ret = rt_hw_adc_register(adc_obj[i].adc,
|
||||
(const char *)adc_obj[i].device_name,
|
||||
&gd32_adc_ops, &adc_obj[i]);
|
||||
if (ret != RT_EOK)
|
||||
{
|
||||
/* TODO err handler */
|
||||
LOG_E("failed register %s, err=%d", adc_obj[i].device_name, ret);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
INIT_BOARD_EXPORT(rt_hw_adc_init);
|
||||
#endif
|
||||
@@ -0,0 +1,788 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-12-30 qingsong.yin first version
|
||||
* 2024-03-07 qingsong.yin for CAN20kBaud/CAN10kBaud
|
||||
* 2024-09-09 qingsong.yin for CANFD and DMA
|
||||
* 2025-10-22 WangShun compatible with RT-Studio
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "drv_can.h"
|
||||
#include "can_config.h"
|
||||
|
||||
#ifdef RT_USING_CAN
|
||||
#if defined(BSP_USING_CAN0) || defined(BSP_USING_CAN1) || defined(BSP_USING_CAN2)
|
||||
|
||||
#define LOG_TAG "drv_can"
|
||||
#include <drv_log.h>
|
||||
|
||||
#ifdef BSP_USING_CAN0
|
||||
struct rt_can_device dev_can0;
|
||||
#endif
|
||||
#ifdef BSP_USING_CAN1
|
||||
struct rt_can_device dev_can1;
|
||||
#endif
|
||||
#ifdef BSP_USING_CAN2
|
||||
struct rt_can_device dev_can2;
|
||||
#endif
|
||||
|
||||
static gd32_can_struct can_obj[] = {
|
||||
#ifdef BSP_USING_CAN0
|
||||
CAN0_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_CAN1
|
||||
CAN1_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_CAN2
|
||||
CAN2_CONFIG,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* baud calculation example */
|
||||
#if defined(SOC_SERIES_GD32H75E) || defined(SOC_SERIES_GD32H7xx) /* APB2 300MHz(max) */
|
||||
static const struct gd32_baud_rate_tab can_baud_rate_tab[] = {
|
||||
/* baud, sjw, prop, seg1, seg2, prescaler */
|
||||
{ CAN1MBaud, 1, 20, 27, 12, 5 },
|
||||
{ CAN800kBaud, 1, 2, 9, 3, 25 },
|
||||
{ CAN500kBaud, 1, 2, 5, 2, 60 },
|
||||
{ CAN250kBaud, 1, 2, 5, 2, 120 },
|
||||
{ CAN125kBaud, 1, 2, 5, 2, 240 },
|
||||
{ CAN100kBaud, 1, 2, 5, 2, 300 },
|
||||
{ CAN50kBaud, 1, 2, 5, 2, 600 },
|
||||
{ CAN20kBaud, 1, 14, 25, 10, 300 },
|
||||
{ CAN10kBaud, 1, 14, 25, 10, 600 },
|
||||
};
|
||||
|
||||
#ifdef RT_CAN_USING_CANFD
|
||||
static const gd32_fd_data_baud_t can_fd_data_baud_tab[] = {
|
||||
/* baud, sjw, prop, seg1, seg2, prescaler */
|
||||
{ CANFD_5MBaud, 1, 2, 7, 2, 5 }, /* 5Mbps */
|
||||
{ CANFD_4MBaud, 1, 3, 8, 3, 5 }, /* 4Mbps */
|
||||
{ CANFD_3MBaud, 1, 4, 11, 4, 5 }, /* 3Mbps */
|
||||
{ CANFD_2MBaud, 1, 6, 17, 6, 5 }, /* 2Mbps */
|
||||
{ CANFD_1MBaud, 1, 20, 27, 12, 5 }, /* 1Mbps: Total Tq=60, SamplePoint≈80% */
|
||||
{ CANFD_800kBaud, 1, 2, 9, 3, 25 }, /* 800kbps */
|
||||
{ CANFD_500kBaud, 1, 2, 5, 2, 60 }, /* 500kbps */
|
||||
{ CANFD_250kBaud, 1, 2, 5, 2, 120 }, /* 250kbps */
|
||||
{ CANFD_125kBaud, 1, 2, 5, 2, 240 }, /* 125kbps */
|
||||
{ CANFD_100kBaud, 1, 2, 5, 2, 300 }, /* 100kbps */
|
||||
{ CANFD_50kBaud, 1, 2, 5, 2, 600 }, /* 50kbps */
|
||||
{ CANFD_20kBaud, 1, 14, 25, 10, 300 }, /* 20kbps */
|
||||
{ CANFD_10kBaud, 1, 14, 25, 10, 600 }, /* 10kbps */
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static rt_uint32_t get_can_baud_index(rt_uint32_t baud)
|
||||
{
|
||||
rt_uint32_t len, index;
|
||||
|
||||
len = sizeof(can_baud_rate_tab) / sizeof(can_baud_rate_tab[0]);
|
||||
for (index = 0; index < len; index++)
|
||||
{
|
||||
if (can_baud_rate_tab[index].baud_rate == baud)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return 0; /* default baud is CAN1MBaud */
|
||||
}
|
||||
|
||||
rt_weak void can_gpio_config(void)
|
||||
{
|
||||
int i;
|
||||
rt_uint32_t tx_port, rx_port;
|
||||
rt_uint32_t tx_pin, rx_pin;
|
||||
rt_uint32_t pin_af;
|
||||
rcu_periph_enum tx_periph, rx_periph;
|
||||
|
||||
#ifdef BSP_USING_CAN0
|
||||
rcu_can_clock_config(IDX_CAN0, RCU_CANSRC_APB2);
|
||||
rcu_periph_clock_enable(RCU_CAN0);
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_CAN1
|
||||
rcu_can_clock_config(IDX_CAN1, RCU_CANSRC_APB2);
|
||||
rcu_periph_clock_enable(RCU_CAN1);
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_CAN2
|
||||
rcu_can_clock_config(IDX_CAN2, RCU_CANSRC_APB2);
|
||||
rcu_periph_clock_enable(RCU_CAN2);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < sizeof(can_obj) / sizeof(can_obj[0]); i++)
|
||||
{
|
||||
get_pin_config(can_obj[i].tx_pin_name, &tx_port, &tx_pin, &tx_periph);
|
||||
get_pin_config(can_obj[i].rx_pin_name, &rx_port, &rx_pin, &rx_periph);
|
||||
pin_alternate_config(can_obj[i].alternate, &pin_af);
|
||||
|
||||
rcu_periph_clock_enable(tx_periph);
|
||||
rcu_periph_clock_enable(rx_periph);
|
||||
|
||||
gpio_output_options_set(tx_port, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, tx_pin);
|
||||
gpio_mode_set(tx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, tx_pin);
|
||||
gpio_af_set(tx_port, pin_af, tx_pin);
|
||||
|
||||
gpio_output_options_set(rx_port, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, rx_pin);
|
||||
gpio_mode_set(rx_port, GPIO_MODE_AF, GPIO_PUPD_PULLUP, rx_pin);
|
||||
gpio_af_set(rx_port, pin_af, rx_pin);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t gd32_can_configure(struct rt_can_device *can, struct can_configure *cfg)
|
||||
{
|
||||
gd32_can_struct *drv_can = (gd32_can_struct *)can->parent.user_data;
|
||||
rt_uint32_t baud_index;
|
||||
|
||||
RT_ASSERT(can);
|
||||
RT_ASSERT(cfg);
|
||||
RT_ASSERT(drv_can);
|
||||
|
||||
/* init can gpio and enable can clock */
|
||||
can_gpio_config();
|
||||
|
||||
/* initialize CAN register */
|
||||
can_deinit(drv_can->can_periph);
|
||||
/* initialize CAN */
|
||||
can_struct_para_init(CAN_INIT_STRUCT, &drv_can->can_init);
|
||||
/* initialize CAN parameters */
|
||||
drv_can->can_init.internal_counter_source = CAN_TIMER_SOURCE_BIT_CLOCK;
|
||||
drv_can->can_init.self_reception = DISABLE;
|
||||
drv_can->can_init.mb_tx_order = CAN_TX_HIGH_PRIORITY_MB_FIRST;
|
||||
drv_can->can_init.mb_tx_abort_enable = ENABLE;
|
||||
drv_can->can_init.local_priority_enable = DISABLE;
|
||||
drv_can->can_init.mb_rx_ide_rtr_type = CAN_IDE_RTR_FILTERED;
|
||||
drv_can->can_init.mb_remote_frame = CAN_STORE_REMOTE_REQUEST_FRAME;
|
||||
drv_can->can_init.rx_private_filter_queue_enable = ENABLE;
|
||||
drv_can->can_init.edge_filter_enable = DISABLE;
|
||||
drv_can->can_init.protocol_exception_enable = DISABLE;
|
||||
drv_can->can_init.rx_filter_order = CAN_RX_FILTER_ORDER_MAILBOX_FIRST;
|
||||
drv_can->can_init.memory_size = CAN_MEMSIZE_32_UNIT;
|
||||
/* filter configuration */
|
||||
drv_can->can_init.mb_public_filter = 0U;
|
||||
/* can baud config */
|
||||
baud_index = get_can_baud_index(cfg->baud_rate);
|
||||
drv_can->can_init.resync_jump_width = can_baud_rate_tab[baud_index].resync_jump_width;
|
||||
drv_can->can_init.prop_time_segment = can_baud_rate_tab[baud_index].prop_time_segment;
|
||||
drv_can->can_init.time_segment_1 = can_baud_rate_tab[baud_index].time_segment_1;
|
||||
drv_can->can_init.time_segment_2 = can_baud_rate_tab[baud_index].time_segment_2;
|
||||
drv_can->can_init.prescaler = can_baud_rate_tab[baud_index].prescaler;
|
||||
|
||||
if (can_init(drv_can->can_periph, &drv_can->can_init) != SUCCESS)
|
||||
{
|
||||
LOG_E("can init error");
|
||||
return RT_ERROR;
|
||||
}
|
||||
|
||||
#ifdef RT_CAN_USING_CANFD
|
||||
/* Configure CANFD if enabled in user config */
|
||||
drv_can->fd_enabled = 0;
|
||||
can_struct_para_init(CAN_FD_INIT_STRUCT, &drv_can->can_fd_init);
|
||||
if (cfg->enable_canfd)
|
||||
{
|
||||
/* default: enable bitrate switch and ISO mode */
|
||||
drv_can->can_fd_init.bitrate_switch_enable = ENABLE;
|
||||
drv_can->can_fd_init.iso_can_fd_enable = ENABLE;
|
||||
/* select mailbox data size according to arbitration len requirement; default 64 bytes */
|
||||
drv_can->can_fd_init.mailbox_data_size = CAN_MAILBOX_DATA_SIZE_8_BYTES;
|
||||
drv_can->can_fd_init.tdc_enable = DISABLE;
|
||||
drv_can->can_fd_init.tdc_offset = 0U;
|
||||
if (cfg->use_bit_timing)
|
||||
{
|
||||
/* Arbitration timing has been already applied by classic init; now apply data phase */
|
||||
drv_can->can_fd_init.resync_jump_width = cfg->canfd_timing.num_sjw;
|
||||
drv_can->can_fd_init.prop_time_segment = cfg->canfd_timing.num_sspoff; /* heuristic if library expects prop vs seg1 */
|
||||
drv_can->can_fd_init.time_segment_1 = cfg->canfd_timing.num_seg1;
|
||||
drv_can->can_fd_init.time_segment_2 = cfg->canfd_timing.num_seg2;
|
||||
drv_can->can_fd_init.prescaler = cfg->canfd_timing.prescaler;
|
||||
}
|
||||
else if (cfg->baud_rate_fd)
|
||||
{
|
||||
/* Simple reuse arbitration timing table for data speed if user sets baud_rate_fd as multiple (rough placeholder) */
|
||||
/* NOTE: For precise FD data phase user should set use_bit_timing */
|
||||
drv_can->can_fd_init.resync_jump_width = 1;
|
||||
drv_can->can_fd_init.prop_time_segment = 2;
|
||||
drv_can->can_fd_init.time_segment_1 = 5;
|
||||
drv_can->can_fd_init.time_segment_2 = 2;
|
||||
drv_can->can_fd_init.prescaler = 15; /* placeholder from example */
|
||||
}
|
||||
can_fd_config(drv_can->can_periph, &drv_can->can_fd_init);
|
||||
drv_can->fd_enabled = 1;
|
||||
}
|
||||
#else
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
/* Rxfifo configuration */
|
||||
drv_can->can_fifo.dma_enable = DISABLE;
|
||||
drv_can->can_fifo.filter_format_and_number = CAN_RXFIFO_FILTER_A_NUM_40;
|
||||
drv_can->can_fifo.fifo_public_filter = 0;
|
||||
can_rx_fifo_config(drv_can->can_periph, &drv_can->can_fifo);
|
||||
#endif
|
||||
#endif /* RT_CAN_USING_CANFD */
|
||||
for (uint8_t i = 0; i < 16; i++)
|
||||
{
|
||||
can_struct_para_init(CAN_MDSC_STRUCT, &drv_can->rx_message[i]);
|
||||
drv_can->rx_message[i].rtr = 0U;
|
||||
drv_can->rx_message[i].ide = 0U;
|
||||
drv_can->rx_message[i].code = CAN_MB_RX_STATUS_EMPTY;
|
||||
/* rx mailbox */
|
||||
drv_can->rx_message[i].id = 0x55U;
|
||||
#if defined(SOC_SERIES_GD32H7xx)
|
||||
drv_can->rx_message[i].data = (uint32_t *)(drv_can->fd_rx_buf[i]);
|
||||
#elif defined(SOC_SERIES_GD32H75E)
|
||||
memcpy(drv_can->rx_message[i].data, drv_can->fd_rx_buf[i], sizeof(drv_can->rx_message[i].data));
|
||||
#endif
|
||||
can_mailbox_config(drv_can->can_periph, i, &drv_can->rx_message[i]);
|
||||
}
|
||||
|
||||
/* clear msg16-31 for tx */
|
||||
CAN_STAT(drv_can->can_periph) = BITS(16, 31);
|
||||
|
||||
/* can mode config */
|
||||
switch (cfg->mode)
|
||||
{
|
||||
case RT_CAN_MODE_NORMAL:
|
||||
drv_can->mode = CAN_NORMAL_MODE;
|
||||
break;
|
||||
case RT_CAN_MODE_LISTEN:
|
||||
drv_can->mode = CAN_MONITOR_MODE;
|
||||
break;
|
||||
case RT_CAN_MODE_LOOPBACK:
|
||||
drv_can->mode = CAN_LOOPBACK_SILENT_MODE;
|
||||
break;
|
||||
case RT_CAN_MODE_LOOPBACKANLISTEN:
|
||||
drv_can->mode = CAN_LOOPBACK_SILENT_MODE;
|
||||
break;
|
||||
default:
|
||||
drv_can->mode = CAN_NORMAL_MODE;
|
||||
break;
|
||||
}
|
||||
can_operation_mode_enter(drv_can->can_periph, drv_can->mode);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t gd32_can_control(struct rt_can_device *can, int cmd, void *arg)
|
||||
{
|
||||
rt_uint32_t baud_index;
|
||||
rt_uint32_t argval;
|
||||
gd32_can_struct *drv_can = (gd32_can_struct *)can->parent.user_data;
|
||||
|
||||
RT_ASSERT(can != RT_NULL);
|
||||
RT_ASSERT(drv_can != RT_NULL);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case RT_DEVICE_CTRL_CLR_INT:
|
||||
argval = (rt_uint32_t)arg;
|
||||
if (argval == RT_DEVICE_FLAG_INT_RX)
|
||||
{
|
||||
CAN_INTEN(drv_can->can_periph) &= ~BITS(0, 15);
|
||||
if (CAN0 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_disable(CAN0_RX_IRQn);
|
||||
}
|
||||
else if (CAN1 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_disable(CAN1_RX_IRQn);
|
||||
}
|
||||
else if (CAN2 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_disable(CAN2_RX_IRQn);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not reach */
|
||||
}
|
||||
}
|
||||
else if (argval == RT_DEVICE_FLAG_INT_TX)
|
||||
{ //int tx
|
||||
CAN_INTEN(drv_can->can_periph) &= ~BITS(15, 31);
|
||||
if (CAN0 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_disable(CAN0_TX_IRQn);
|
||||
}
|
||||
else if (CAN1 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_disable(CAN1_TX_IRQn);
|
||||
}
|
||||
else if (CAN2 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_disable(CAN2_TX_IRQn);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not reach */
|
||||
}
|
||||
}
|
||||
else if (argval == RT_DEVICE_CAN_INT_ERR)
|
||||
{ //int error
|
||||
can_interrupt_disable(drv_can->can_periph, CAN_INT_ERR_SUMMARY);
|
||||
if (CAN0 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_disable(CAN0_Error_IRQn);
|
||||
}
|
||||
else if (CAN1 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_disable(CAN1_Error_IRQn);
|
||||
}
|
||||
else if (CAN2 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_disable(CAN2_Error_IRQn);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not reach */
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RT_DEVICE_CTRL_SET_INT:
|
||||
argval = (rt_uint32_t)arg;
|
||||
if (argval == RT_DEVICE_FLAG_INT_RX)
|
||||
{
|
||||
CAN_INTEN(drv_can->can_periph) |= BITS(0, 15);
|
||||
|
||||
if (CAN0 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_enable(CAN0_RX_IRQn, 15, 0);
|
||||
}
|
||||
else if (CAN1 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_enable(CAN1_RX_IRQn, 15, 0);
|
||||
}
|
||||
else if (CAN2 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_enable(CAN2_RX_IRQn, 15, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not reach */
|
||||
}
|
||||
}
|
||||
else if (argval == RT_DEVICE_FLAG_INT_TX)
|
||||
{
|
||||
CAN_INTEN(drv_can->can_periph) |= BITS(16, 31);
|
||||
if (CAN0 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_enable(CAN0_TX_IRQn, 15, 0);
|
||||
}
|
||||
else if (CAN1 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_enable(CAN1_TX_IRQn, 15, 0);
|
||||
}
|
||||
else if (CAN2 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_enable(CAN2_TX_IRQn, 15, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not reach */
|
||||
}
|
||||
}
|
||||
else if (argval == RT_DEVICE_CAN_INT_ERR)
|
||||
{
|
||||
can_interrupt_enable(drv_can->can_periph, CAN_INT_ERR_SUMMARY);
|
||||
if (CAN0 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_enable(CAN0_ERROR_IRQn, 15, 0);
|
||||
}
|
||||
else if (CAN1 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_enable(CAN1_ERROR_IRQn, 15, 0);
|
||||
}
|
||||
else if (CAN2 == drv_can->can_periph)
|
||||
{
|
||||
nvic_irq_enable(CAN2_ERROR_IRQn, 15, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not reach */
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RT_CAN_CMD_SET_FILTER:
|
||||
{
|
||||
drv_can->filter_cb = (void (*)(uint32_t can_periph))arg;
|
||||
if (drv_can->filter_cb)
|
||||
{
|
||||
drv_can->filter_cb(drv_can->can_periph);
|
||||
}
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
struct rt_can_filter_config *filter_cfg;
|
||||
|
||||
filter_cfg = (struct rt_can_filter_config *)arg;
|
||||
can_operation_mode_enter(drv_can->can_periph, CAN_INACTIVE_MODE);
|
||||
CAN_RFIFOPUBF(drv_can->can_periph) = 0xFFFFFFFF;
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
can_private_filter_config(drv_can->can_periph, i, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
for (i = 0; i < filter_cfg->count; i++)
|
||||
{
|
||||
if (filter_cfg->items[i].hdr_bank == -1)
|
||||
{
|
||||
can_private_filter_config(drv_can->can_periph, i, filter_cfg->items[i].mask);
|
||||
drv_can->fifo_element[i].extended_frame = filter_cfg->items[i].ide;
|
||||
drv_can->fifo_element[i].remote_frame = filter_cfg->items[i].rtr;
|
||||
drv_can->fifo_element[i].id = filter_cfg->items[i].id;
|
||||
}
|
||||
else
|
||||
{
|
||||
can_private_filter_config(drv_can->can_periph, filter_cfg->items[i].hdr_bank, filter_cfg->items[i].mask);
|
||||
drv_can->fifo_element[filter_cfg->items[i].hdr_bank].extended_frame = filter_cfg->items[i].ide;
|
||||
drv_can->fifo_element[filter_cfg->items[i].hdr_bank].remote_frame = filter_cfg->items[i].rtr;
|
||||
drv_can->fifo_element[filter_cfg->items[i].hdr_bank].id = filter_cfg->items[i].id;
|
||||
}
|
||||
}
|
||||
can_rx_fifo_filter_table_config(drv_can->can_periph, drv_can->fifo_element);
|
||||
can_rx_fifo_clear(drv_can->can_periph);
|
||||
can_operation_mode_enter(drv_can->can_periph, drv_can->mode);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case RT_CAN_CMD_SET_MODE:
|
||||
argval = (rt_uint32_t)arg;
|
||||
if (argval != drv_can->device->config.mode)
|
||||
{
|
||||
/* can mode config */
|
||||
switch (argval)
|
||||
{
|
||||
case RT_CAN_MODE_NORMAL:
|
||||
drv_can->mode = CAN_NORMAL_MODE;
|
||||
break;
|
||||
case RT_CAN_MODE_LISTEN:
|
||||
drv_can->mode = CAN_MONITOR_MODE;
|
||||
break;
|
||||
case RT_CAN_MODE_LOOPBACK:
|
||||
drv_can->mode = CAN_LOOPBACK_SILENT_MODE;
|
||||
break;
|
||||
case RT_CAN_MODE_LOOPBACKANLISTEN:
|
||||
drv_can->mode = CAN_LOOPBACK_SILENT_MODE;
|
||||
break;
|
||||
default:
|
||||
return RT_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (SUCCESS == can_operation_mode_enter(drv_can->can_periph, drv_can->mode))
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return RT_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RT_CAN_CMD_SET_BAUD:
|
||||
argval = (rt_uint32_t)arg;
|
||||
if (argval != CAN1MBaud &&
|
||||
argval != CAN800kBaud &&
|
||||
argval != CAN500kBaud &&
|
||||
argval != CAN250kBaud &&
|
||||
argval != CAN125kBaud &&
|
||||
argval != CAN100kBaud &&
|
||||
argval != CAN50kBaud &&
|
||||
argval != CAN20kBaud &&
|
||||
argval != CAN10kBaud)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
if (argval != drv_can->device->config.baud_rate)
|
||||
{
|
||||
baud_index = get_can_baud_index(argval);
|
||||
drv_can->can_init.resync_jump_width = can_baud_rate_tab[baud_index].resync_jump_width;
|
||||
drv_can->can_init.prop_time_segment = can_baud_rate_tab[baud_index].prop_time_segment;
|
||||
drv_can->can_init.time_segment_1 = can_baud_rate_tab[baud_index].time_segment_1;
|
||||
drv_can->can_init.time_segment_2 = can_baud_rate_tab[baud_index].time_segment_2;
|
||||
drv_can->can_init.prescaler = can_baud_rate_tab[baud_index].prescaler;
|
||||
can_operation_mode_enter(drv_can->can_periph, CAN_INACTIVE_MODE);
|
||||
CAN_BT(drv_can->can_periph) &= ~(CAN_BT_BAUDPSC | CAN_BT_SJW | CAN_BT_PTS | CAN_BT_PBS1 | CAN_BT_PBS2);
|
||||
CAN_BT(drv_can->can_periph) |= (uint32_t)(BT_BAUDPSC(drv_can->can_init.prescaler - 1U) |
|
||||
BT_SJW((uint32_t)drv_can->can_init.resync_jump_width - 1U) |
|
||||
BT_PTS((uint32_t)drv_can->can_init.prop_time_segment - 1U) |
|
||||
BT_PBS1((uint32_t)drv_can->can_init.time_segment_1 - 1U) |
|
||||
BT_PBS2((uint32_t)drv_can->can_init.time_segment_2 - 1U));
|
||||
can_operation_mode_enter(drv_can->can_periph, drv_can->mode);
|
||||
}
|
||||
break;
|
||||
case RT_CAN_CMD_SET_PRIV:
|
||||
{
|
||||
}
|
||||
break;
|
||||
case RT_CAN_CMD_GET_STATUS:
|
||||
{
|
||||
}
|
||||
break;
|
||||
#ifdef RT_CAN_USING_CANFD
|
||||
case RT_CAN_CMD_SET_CANFD:
|
||||
{
|
||||
/* enable or disable CANFD dynamically */
|
||||
rt_uint32_t enable = (rt_uint32_t)arg;
|
||||
can_operation_mode_enter(drv_can->can_periph, CAN_INACTIVE_MODE);
|
||||
if (enable)
|
||||
{
|
||||
drv_can->fd_enabled = 1;
|
||||
drv_can->can_fd_init.bitrate_switch_enable = ENABLE;
|
||||
drv_can->can_fd_init.iso_can_fd_enable = ENABLE;
|
||||
drv_can->can_fd_init.mailbox_data_size = CAN_MAILBOX_DATA_SIZE_16_BYTES;
|
||||
drv_can->can_fd_init.tdc_enable = DISABLE;
|
||||
drv_can->can_fd_init.tdc_offset = 0U;
|
||||
can_fd_config(drv_can->can_periph, &drv_can->can_fd_init);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no direct API to disable FD; re-init classic CAN */
|
||||
drv_can->fd_enabled = 0;
|
||||
}
|
||||
can_operation_mode_enter(drv_can->can_periph, drv_can->mode);
|
||||
}
|
||||
break;
|
||||
case RT_CAN_CMD_SET_BAUD_FD:
|
||||
{
|
||||
rt_uint32_t data_baud;
|
||||
int found;
|
||||
unsigned k;
|
||||
data_baud = (rt_uint32_t)arg;
|
||||
if (!drv_can->fd_enabled || data_baud == 0)
|
||||
break;
|
||||
found = -1;
|
||||
for (k = 0; k < (sizeof(can_fd_data_baud_tab) / sizeof(can_fd_data_baud_tab[0])); k++)
|
||||
{
|
||||
if (can_fd_data_baud_tab[k].baud == data_baud)
|
||||
{
|
||||
found = (int)k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found < 0)
|
||||
break; /* unsupported */
|
||||
can_operation_mode_enter(drv_can->can_periph, CAN_INACTIVE_MODE);
|
||||
drv_can->can_fd_init.resync_jump_width = can_fd_data_baud_tab[found].sjw;
|
||||
drv_can->can_fd_init.prop_time_segment = can_fd_data_baud_tab[found].prop;
|
||||
drv_can->can_fd_init.time_segment_1 = can_fd_data_baud_tab[found].seg1;
|
||||
drv_can->can_fd_init.time_segment_2 = can_fd_data_baud_tab[found].seg2;
|
||||
drv_can->can_fd_init.prescaler = can_fd_data_baud_tab[found].prescaler;
|
||||
can_fd_config(drv_can->can_periph, &drv_can->can_fd_init);
|
||||
can_operation_mode_enter(drv_can->can_periph, drv_can->mode);
|
||||
}
|
||||
break;
|
||||
#endif /* RT_CAN_USING_CANFD */
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_ssize_t gd32_can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t boxno)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
gd32_can_struct *drv_can = (gd32_can_struct *)can->parent.user_data;
|
||||
struct rt_can_msg *tx_msg = (struct rt_can_msg *)buf;
|
||||
|
||||
RT_ASSERT(can != RT_NULL);
|
||||
RT_ASSERT(buf != RT_NULL);
|
||||
RT_ASSERT(drv_can != RT_NULL);
|
||||
RT_ASSERT(tx_msg != RT_NULL);
|
||||
|
||||
/* transmit message */
|
||||
for (i = 16; i < 31; i++)
|
||||
{
|
||||
if (0U == (CAN_STAT(drv_can->can_periph) & BIT(i)))
|
||||
{
|
||||
/* initialize transmit message */
|
||||
drv_can->tx_message[i].rtr = tx_msg->rtr;
|
||||
drv_can->tx_message[i].ide = tx_msg->ide;
|
||||
drv_can->tx_message[i].esi = 0U;
|
||||
drv_can->tx_message[i].code = CAN_MB_TX_STATUS_DATA;
|
||||
drv_can->tx_message[i].brs = tx_msg->brs;
|
||||
drv_can->tx_message[i].fdf = tx_msg->fd_frame;
|
||||
drv_can->tx_message[i].prio = tx_msg->priv;
|
||||
drv_can->tx_message[i].data_bytes = tx_msg->len; /* classic frame length or already set for FD */
|
||||
|
||||
#if defined(SOC_SERIES_GD32H7xx)
|
||||
drv_can->tx_message[i].data = (uint32_t *)tx_msg->data;
|
||||
#elif defined(SOC_SERIES_GD32H75E)
|
||||
memcpy(drv_can->tx_message[i].data, tx_msg->data, sizeof(drv_can->tx_message[i].data));
|
||||
#endif
|
||||
drv_can->tx_message[i].id = tx_msg->id;
|
||||
can_mailbox_config(drv_can->can_periph, i, &drv_can->tx_message[i]);
|
||||
return RT_EOK;
|
||||
}
|
||||
}
|
||||
return RT_EFULL;
|
||||
}
|
||||
|
||||
static rt_ssize_t gd32_can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t boxno)
|
||||
{
|
||||
gd32_can_struct *drv_can = (gd32_can_struct *)can->parent.user_data;
|
||||
struct rt_can_msg *pmsg = (struct rt_can_msg *)buf;
|
||||
RT_ASSERT(can);
|
||||
RT_ASSERT(pmsg);
|
||||
|
||||
uint8_t i;
|
||||
/* receive data */
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (drv_can->rx_message_valid[i] == 1)
|
||||
{
|
||||
drv_can->rx_message_valid[i] = 0;
|
||||
pmsg->id = drv_can->rx_message[i].id;
|
||||
pmsg->ide = drv_can->rx_message[i].ide;
|
||||
pmsg->rtr = drv_can->rx_message[i].rtr;
|
||||
pmsg->len = drv_can->rx_message[i].data_bytes;
|
||||
pmsg->priv = 0;
|
||||
pmsg->hdr_index = i;
|
||||
#ifdef RT_CAN_USING_CANFD
|
||||
pmsg->fd_frame = drv_can->rx_message[i].fdf;
|
||||
pmsg->brs = drv_can->rx_message[i].brs;
|
||||
#endif
|
||||
rt_memcpy(pmsg->data, drv_can->rx_message[i].data, pmsg->len);
|
||||
return RT_EOK;
|
||||
}
|
||||
}
|
||||
return RT_EEMPTY;
|
||||
}
|
||||
|
||||
static const struct rt_can_ops _can_ops = {
|
||||
gd32_can_configure,
|
||||
gd32_can_control,
|
||||
gd32_can_sendmsg,
|
||||
gd32_can_recvmsg,
|
||||
};
|
||||
|
||||
static void _can_rx_tx_isr(struct rt_can_device *can)
|
||||
{
|
||||
uint8_t i;
|
||||
gd32_can_struct *drv_can = (gd32_can_struct *)can->parent.user_data;
|
||||
RT_ASSERT(can != RT_NULL);
|
||||
RT_ASSERT(drv_can != RT_NULL);
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (CAN_STAT(drv_can->can_periph) & BIT(i))
|
||||
{
|
||||
can_mailbox_receive_data_read(drv_can->can_periph, i, &drv_can->rx_message[i]);
|
||||
drv_can->rx_message_valid[i] = 1;
|
||||
rt_hw_can_isr(can, RT_CAN_EVENT_RX_IND);
|
||||
CAN_STAT(drv_can->can_periph) = BIT(i); /* Clear the status bit */
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 16; i < 31; i++)
|
||||
{
|
||||
if (0U != (CAN_STAT(drv_can->can_periph) & BIT(i)))
|
||||
{
|
||||
CAN_STAT(drv_can->can_periph) = BIT(i);
|
||||
rt_hw_can_isr(can, RT_CAN_EVENT_TX_DONE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _can_sce_isr(struct rt_can_device *can)
|
||||
{
|
||||
gd32_can_struct *drv_can = (gd32_can_struct *)can->parent.user_data;
|
||||
rt_uint32_t err_code;
|
||||
|
||||
RT_ASSERT(can != RT_NULL);
|
||||
RT_ASSERT(drv_can != RT_NULL);
|
||||
|
||||
if (SET == can_interrupt_flag_get(drv_can->can_periph, CAN_INT_FLAG_ERR_SUMMARY))
|
||||
{
|
||||
can_interrupt_flag_clear(drv_can->can_periph, CAN_INT_FLAG_ERR_SUMMARY);
|
||||
err_code = GET_BITS(CAN_ERR1(drv_can->can_periph), 10U, 15U);
|
||||
|
||||
if (err_code & CAN_ERR1_FMERR)
|
||||
{
|
||||
can->status.formaterrcnt++;
|
||||
}
|
||||
|
||||
if (err_code & CAN_ERR1_CRCERR)
|
||||
{
|
||||
can->status.crcerrcnt++;
|
||||
}
|
||||
|
||||
if (err_code & CAN_ERR1_ACKERR)
|
||||
{
|
||||
can->status.ackerrcnt++;
|
||||
}
|
||||
can->status.errcode = err_code;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BSP_USING_CAN0
|
||||
void CAN0_Message_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
_can_rx_tx_isr(&dev_can0);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
void CAN0_Error_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
_can_sce_isr(&dev_can0);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif /* BSP_USING_CAN0 */
|
||||
|
||||
#ifdef BSP_USING_CAN1
|
||||
void CAN1_Message_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
_can_rx_tx_isr(&dev_can1);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
void CAN1_Error_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
_can_sce_isr(&dev_can1);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif /* BSP_USING_CAN1 */
|
||||
|
||||
#ifdef BSP_USING_CAN2
|
||||
void CAN2_Message_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
_can_rx_tx_isr(&dev_can2);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
void CAN2_Error_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
_can_sce_isr(&dev_can2);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif /* BSP_USING_CAN2 */
|
||||
|
||||
int rt_hw_can_init(void)
|
||||
{
|
||||
int i;
|
||||
struct can_configure config = CANDEFAULTCONFIG;
|
||||
config.privmode = RT_CAN_MODE_NOPRIV;
|
||||
config.ticks = 50;
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
config.maxhdr = 40;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < sizeof(can_obj) / sizeof(can_obj[0]); i++)
|
||||
{
|
||||
can_obj[i].device->config = config;
|
||||
rt_hw_can_register(can_obj[i].device, can_obj[i].name, &_can_ops, &can_obj[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_BOARD_EXPORT(rt_hw_can_init);
|
||||
|
||||
#endif /* defined(BSP_USING_CAN0) || defined(BSP_USING_CAN1) || defined(BSP_USING_CAN2) */
|
||||
#endif /*RT_USING_CAN*/
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-11-7 SummerGift first version
|
||||
*/
|
||||
|
||||
#include "drv_common.h"
|
||||
#include "board.h"
|
||||
|
||||
#ifdef RT_USING_SERIAL
|
||||
#ifdef RT_USING_SERIAL_V2
|
||||
#include "drv_usart_v2.h"
|
||||
#else
|
||||
#include "drv_usart.h"
|
||||
#endif /* RT_USING_SERIAL */
|
||||
#endif /* RT_USING_SERIAL_V2 */
|
||||
|
||||
#define DBG_TAG "drv_common"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
static void reboot(uint8_t argc, char **argv)
|
||||
{
|
||||
rt_hw_cpu_reset();
|
||||
}
|
||||
MSH_CMD_EXPORT(reboot, Reboot System);
|
||||
#endif /* RT_USING_FINSH */
|
||||
|
||||
/**
|
||||
* @brief This function is executed in case of error occurrence.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void Error_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN Error_Handler */
|
||||
/* User can add his own implementation to report the HAL error return state */
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
/* USER CODE END Error_Handler */
|
||||
}
|
||||
|
||||
/** System Clock Configuration
|
||||
*/
|
||||
void SystemClock_Config(void)
|
||||
{
|
||||
SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the timer interrupt service routine.
|
||||
*
|
||||
*/
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
|
||||
rt_tick_increase();
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will initial gd32 board.
|
||||
*/
|
||||
void hw_board_init()
|
||||
{
|
||||
/* NVIC Configuration */
|
||||
#define NVIC_VTOR_MASK 0x3FFFFF80
|
||||
#ifdef VECT_TAB_RAM
|
||||
/* Set the Vector Table base location at 0x10000000 */
|
||||
SCB->VTOR = (0x10000000 & NVIC_VTOR_MASK);
|
||||
#else /* VECT_TAB_FLASH */
|
||||
/* Set the Vector Table base location at 0x08000000 */
|
||||
SCB->VTOR = (0x08000000 & NVIC_VTOR_MASK);
|
||||
#endif
|
||||
|
||||
/* Enable IChace */
|
||||
SCB_EnableICache();
|
||||
|
||||
/* Enable DChace */
|
||||
SCB_EnableDCache();
|
||||
|
||||
SystemClock_Config();
|
||||
|
||||
/* Pin driver initialization is open by default */
|
||||
#ifdef RT_USING_PIN
|
||||
extern int rt_hw_pin_init(void);
|
||||
rt_hw_pin_init();
|
||||
#endif
|
||||
|
||||
/* USART driver initialization is open by default */
|
||||
#ifdef RT_USING_SERIAL
|
||||
extern int rt_hw_usart_init(void);
|
||||
rt_hw_usart_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-10-11 kurisaw first version
|
||||
*/
|
||||
|
||||
#include "drv_dac.h"
|
||||
#include "dac_config.h"
|
||||
|
||||
#ifdef RT_USING_DAC
|
||||
|
||||
#define DBG_TAG "drv.dac"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
static struct gd32_dac gd32_dac_obj[] = {
|
||||
|
||||
#ifdef BSP_USING_DAC0
|
||||
DAC0_CONFIG,
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_DAC1
|
||||
DAC1_CONFIG,
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
/* DAC initialization status */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t dac_periph;
|
||||
rt_bool_t initialized;
|
||||
} DAC_INIT_STATUS;
|
||||
|
||||
static DAC_INIT_STATUS dac_init_status[] = {
|
||||
#if defined(DAC0)
|
||||
{ DAC0, RT_FALSE },
|
||||
#elif defined(DAC1)
|
||||
{ DAC1, RT_FALSE },
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Private functions */
|
||||
static void gd32_dac_hw_init(struct gd32_dac *gd32_dac)
|
||||
{
|
||||
rt_uint32_t dac_port, dac_pin;
|
||||
rcu_periph_enum dac_periph;
|
||||
|
||||
/* Get pin configuration */
|
||||
if (get_pin_config(gd32_dac->pin_name, &dac_port, &dac_pin, &dac_periph) == -RT_ERROR)
|
||||
{
|
||||
LOG_E("Failed to get pin config for %s", gd32_dac->pin_name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enable clocks */
|
||||
rcu_periph_clock_enable(RCU_DAC);
|
||||
rcu_periph_clock_enable(dac_periph);
|
||||
|
||||
/* Configure GPIO as analog mode for DAC output */
|
||||
gpio_mode_set(dac_port, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, dac_pin);
|
||||
|
||||
LOG_D("DAC GPIO %s configured", gd32_dac->pin_name);
|
||||
}
|
||||
|
||||
static void dac_initialize(uint32_t dac_periph)
|
||||
{
|
||||
/* Check if DAC is already initialized */
|
||||
for (int i = 0; i < sizeof(dac_init_status) / sizeof(dac_init_status[0]); i++)
|
||||
{
|
||||
if (dac_init_status[i].dac_periph == dac_periph && !dac_init_status[i].initialized)
|
||||
{
|
||||
/* Initialize DAC */
|
||||
dac_deinit(dac_periph);
|
||||
|
||||
/* DAC trigger disable for both channels */
|
||||
dac_trigger_disable(dac_periph, gd32_dac_obj[i].channel);
|
||||
|
||||
/* DAC wave mode disable for both channels */
|
||||
dac_wave_mode_config(dac_periph, gd32_dac_obj[i].channel, DAC_WAVE_DISABLE);
|
||||
|
||||
#if defined(SOC_SERIES_GD32F10x) || defined(SOC_SERIES_GD32F20x) || defined(SOC_SERIES_GD32F30x) || defined(SOC_SERIES_GD32F4xx) || defined(SOC_SERIES_GD32F5xx) || defined(SOC_SERIES_GD32E50x)
|
||||
/* DAC output buffer enable */
|
||||
dac_output_buffer_enable(dac_periph, gd32_dac_obj[i].channel);
|
||||
#endif
|
||||
|
||||
#if defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E)
|
||||
/* DAC mode configuration - normal mode with buffer enabled */
|
||||
dac_mode_config(dac_periph, gd32_dac_obj[i].channel, NORMAL_PIN_BUFFON);
|
||||
#endif
|
||||
|
||||
dac_init_status[i].initialized = RT_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t drv_dac_enabled(struct rt_dac_device *device, rt_uint32_t channel)
|
||||
{
|
||||
struct gd32_dac *dac_dev = (struct gd32_dac *)device;
|
||||
|
||||
/* Validate channel */
|
||||
if (channel != DAC_OUT0 && channel != DAC_OUT1)
|
||||
{
|
||||
LOG_E("Invalid DAC channel: %d", channel);
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
/* Enable DAC channel */
|
||||
dac_enable(dac_dev->dac_periph, (uint8_t)channel);
|
||||
LOG_D("DAC %s channel %d enabled", dac_dev->name, channel);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t drv_dac_disabled(struct rt_dac_device *device, rt_uint32_t channel)
|
||||
{
|
||||
struct gd32_dac *dac_dev = (struct gd32_dac *)device;
|
||||
|
||||
/* Validate channel */
|
||||
if (channel != DAC_OUT0 && channel != DAC_OUT1)
|
||||
{
|
||||
LOG_E("Invalid DAC channel: %d", channel);
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
/* Disable DAC channel */
|
||||
dac_disable(dac_dev->dac_periph, (uint8_t)channel);
|
||||
LOG_D("DAC %s channel %d disabled", dac_dev->name, channel);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t drv_dac_convert(struct rt_dac_device *device, rt_uint32_t channel, rt_uint32_t *value)
|
||||
{
|
||||
struct gd32_dac *dac_dev = (struct gd32_dac *)device;
|
||||
|
||||
if (value == RT_NULL)
|
||||
{
|
||||
LOG_E("DAC value pointer is NULL");
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
/* Validate channel */
|
||||
if (channel != DAC_OUT0 && channel != DAC_OUT1)
|
||||
{
|
||||
LOG_E("Invalid DAC channel: %d", channel);
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
/* Check value range for 12-bit DAC */
|
||||
if (*value > 4095)
|
||||
{
|
||||
LOG_E("DAC value %u exceeds maximum 4095", *value);
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
/* Set DAC data with 12-bit right aligned */
|
||||
dac_data_set(dac_dev->dac_periph, (uint8_t)channel, DAC_ALIGN_12B_R, (uint16_t)(*value));
|
||||
LOG_D("DAC %s channel %d set to value %u", dac_dev->name, channel, *value);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t drv_dac_set_mode(struct rt_dac_device *device, rt_uint32_t channel, rt_uint32_t mode)
|
||||
{
|
||||
struct gd32_dac *dac_dev = (struct gd32_dac *)device;
|
||||
|
||||
if (channel != DAC_OUT0 && channel != DAC_OUT1)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
dac_mode_config(dac_dev->dac_periph, channel, mode);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static struct rt_dac_ops drv_ops = {
|
||||
.disabled = drv_dac_disabled,
|
||||
.enabled = drv_dac_enabled,
|
||||
.convert = drv_dac_convert,
|
||||
};
|
||||
|
||||
static int drv_dac_init(void)
|
||||
{
|
||||
int i, result = RT_EOK;
|
||||
|
||||
for (i = 0; i < sizeof(gd32_dac_obj) / sizeof(gd32_dac_obj[0]); i++)
|
||||
{
|
||||
/* Initialize DAC hardware - GPIO configuration */
|
||||
gd32_dac_hw_init(&gd32_dac_obj[i]);
|
||||
|
||||
/* Initialize DAC peripheral if not already initialized */
|
||||
dac_initialize(gd32_dac_obj[i].dac_periph);
|
||||
|
||||
/* Register DAC device */
|
||||
if (rt_hw_dac_register(&gd32_dac_obj[i].dac_device, gd32_dac_obj[i].name,
|
||||
&drv_ops, RT_NULL) == RT_EOK)
|
||||
{
|
||||
LOG_D("%s register success (channel %d)",
|
||||
gd32_dac_obj[i].name, gd32_dac_obj[i].channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("%s register failed", gd32_dac_obj[i].name);
|
||||
result = -RT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
INIT_DEVICE_EXPORT(drv_dac_init);
|
||||
|
||||
#endif /* RT_USING_DAC */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,945 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#include <rtdevice.h>
|
||||
#include <rthw.h>
|
||||
#include <rtconfig.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef RT_USING_PIN
|
||||
|
||||
#include "drv_gpio.h"
|
||||
|
||||
static const struct pin_index pins[] = {
|
||||
#ifdef GPIOA
|
||||
GD32_PIN(0, A, 0),
|
||||
GD32_PIN(1, A, 1),
|
||||
GD32_PIN(2, A, 2),
|
||||
GD32_PIN(3, A, 3),
|
||||
GD32_PIN(4, A, 4),
|
||||
GD32_PIN(5, A, 5),
|
||||
GD32_PIN(6, A, 6),
|
||||
GD32_PIN(7, A, 7),
|
||||
GD32_PIN(8, A, 8),
|
||||
GD32_PIN(9, A, 9),
|
||||
GD32_PIN(10, A, 10),
|
||||
GD32_PIN(11, A, 11),
|
||||
GD32_PIN(12, A, 12),
|
||||
GD32_PIN(13, A, 13),
|
||||
GD32_PIN(14, A, 14),
|
||||
GD32_PIN(15, A, 15),
|
||||
#endif
|
||||
#ifdef GPIOB
|
||||
GD32_PIN(16, B, 0),
|
||||
GD32_PIN(17, B, 1),
|
||||
GD32_PIN(18, B, 2),
|
||||
GD32_PIN(19, B, 3),
|
||||
GD32_PIN(20, B, 4),
|
||||
GD32_PIN(21, B, 5),
|
||||
GD32_PIN(22, B, 6),
|
||||
GD32_PIN(23, B, 7),
|
||||
GD32_PIN(24, B, 8),
|
||||
GD32_PIN(25, B, 9),
|
||||
GD32_PIN(26, B, 10),
|
||||
GD32_PIN(27, B, 11),
|
||||
GD32_PIN(28, B, 12),
|
||||
GD32_PIN(29, B, 13),
|
||||
GD32_PIN(30, B, 14),
|
||||
GD32_PIN(31, B, 15),
|
||||
#endif
|
||||
#ifdef GPIOC
|
||||
GD32_PIN(32, C, 0),
|
||||
GD32_PIN(33, C, 1),
|
||||
GD32_PIN(34, C, 2),
|
||||
GD32_PIN(35, C, 3),
|
||||
GD32_PIN(36, C, 4),
|
||||
GD32_PIN(37, C, 5),
|
||||
GD32_PIN(38, C, 6),
|
||||
GD32_PIN(39, C, 7),
|
||||
GD32_PIN(40, C, 8),
|
||||
GD32_PIN(41, C, 9),
|
||||
GD32_PIN(42, C, 10),
|
||||
GD32_PIN(43, C, 11),
|
||||
GD32_PIN(44, C, 12),
|
||||
GD32_PIN(45, C, 13),
|
||||
GD32_PIN(46, C, 14),
|
||||
GD32_PIN(47, C, 15),
|
||||
#endif
|
||||
#ifdef GPIOD
|
||||
GD32_PIN(48, D, 0),
|
||||
GD32_PIN(49, D, 1),
|
||||
GD32_PIN(50, D, 2),
|
||||
GD32_PIN(51, D, 3),
|
||||
GD32_PIN(52, D, 4),
|
||||
GD32_PIN(53, D, 5),
|
||||
GD32_PIN(54, D, 6),
|
||||
GD32_PIN(55, D, 7),
|
||||
GD32_PIN(56, D, 8),
|
||||
GD32_PIN(57, D, 9),
|
||||
GD32_PIN(58, D, 10),
|
||||
GD32_PIN(59, D, 11),
|
||||
GD32_PIN(60, D, 12),
|
||||
GD32_PIN(61, D, 13),
|
||||
GD32_PIN(62, D, 14),
|
||||
GD32_PIN(63, D, 15),
|
||||
#endif
|
||||
#ifdef GPIOE
|
||||
GD32_PIN(64, E, 0),
|
||||
GD32_PIN(65, E, 1),
|
||||
GD32_PIN(66, E, 2),
|
||||
GD32_PIN(67, E, 3),
|
||||
GD32_PIN(68, E, 4),
|
||||
GD32_PIN(69, E, 5),
|
||||
GD32_PIN(70, E, 6),
|
||||
GD32_PIN(71, E, 7),
|
||||
GD32_PIN(72, E, 8),
|
||||
GD32_PIN(73, E, 9),
|
||||
GD32_PIN(74, E, 10),
|
||||
GD32_PIN(75, E, 11),
|
||||
GD32_PIN(76, E, 12),
|
||||
GD32_PIN(77, E, 13),
|
||||
GD32_PIN(78, E, 14),
|
||||
GD32_PIN(79, E, 15),
|
||||
#endif
|
||||
#ifdef GPIOF
|
||||
GD32_PIN(80, F, 0),
|
||||
GD32_PIN(81, F, 1),
|
||||
GD32_PIN(82, F, 2),
|
||||
GD32_PIN(83, F, 3),
|
||||
GD32_PIN(84, F, 4),
|
||||
GD32_PIN(85, F, 5),
|
||||
GD32_PIN(86, F, 6),
|
||||
GD32_PIN(87, F, 7),
|
||||
GD32_PIN(88, F, 8),
|
||||
GD32_PIN(89, F, 9),
|
||||
GD32_PIN(90, F, 10),
|
||||
GD32_PIN(91, F, 11),
|
||||
GD32_PIN(92, F, 12),
|
||||
GD32_PIN(93, F, 13),
|
||||
GD32_PIN(94, F, 14),
|
||||
GD32_PIN(95, F, 15),
|
||||
#endif
|
||||
#ifdef GPIOG
|
||||
GD32_PIN(96, G, 0),
|
||||
GD32_PIN(97, G, 1),
|
||||
GD32_PIN(98, G, 2),
|
||||
GD32_PIN(99, G, 3),
|
||||
GD32_PIN(100, G, 4),
|
||||
GD32_PIN(101, G, 5),
|
||||
GD32_PIN(102, G, 6),
|
||||
GD32_PIN(103, G, 7),
|
||||
GD32_PIN(104, G, 8),
|
||||
GD32_PIN(105, G, 9),
|
||||
GD32_PIN(106, G, 10),
|
||||
GD32_PIN(107, G, 11),
|
||||
GD32_PIN(108, G, 12),
|
||||
GD32_PIN(109, G, 13),
|
||||
GD32_PIN(110, G, 14),
|
||||
GD32_PIN(111, G, 15),
|
||||
#endif
|
||||
#ifdef GPIOH
|
||||
GD32_PIN(112, H, 0),
|
||||
GD32_PIN(113, H, 1),
|
||||
GD32_PIN(114, H, 2),
|
||||
GD32_PIN(115, H, 3),
|
||||
GD32_PIN(116, H, 4),
|
||||
GD32_PIN(117, H, 5),
|
||||
GD32_PIN(118, H, 6),
|
||||
GD32_PIN(119, H, 7),
|
||||
GD32_PIN(120, H, 8),
|
||||
GD32_PIN(121, H, 9),
|
||||
GD32_PIN(122, H, 10),
|
||||
GD32_PIN(123, H, 11),
|
||||
GD32_PIN(124, H, 12),
|
||||
GD32_PIN(125, H, 13),
|
||||
GD32_PIN(126, H, 14),
|
||||
GD32_PIN(127, H, 15),
|
||||
#endif
|
||||
#ifdef GPIOI
|
||||
GD32_PIN(128, I, 0),
|
||||
GD32_PIN(129, I, 1),
|
||||
GD32_PIN(130, I, 2),
|
||||
GD32_PIN(131, I, 3),
|
||||
GD32_PIN(132, I, 4),
|
||||
GD32_PIN(133, I, 5),
|
||||
GD32_PIN(134, I, 6),
|
||||
GD32_PIN(135, I, 7),
|
||||
GD32_PIN(136, I, 8),
|
||||
GD32_PIN(137, I, 9),
|
||||
GD32_PIN(138, I, 10),
|
||||
GD32_PIN(139, I, 11),
|
||||
GD32_PIN(140, I, 12),
|
||||
GD32_PIN(141, I, 13),
|
||||
GD32_PIN(142, I, 14),
|
||||
GD32_PIN(143, I, 15),
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined SOC_SERIES_GD32E23x
|
||||
static const struct pin_irq_map pin_irq_map[] = {
|
||||
{ GPIO_PIN_0, EXTI0_1_IRQn },
|
||||
{ GPIO_PIN_1, EXTI0_1_IRQn },
|
||||
{ GPIO_PIN_2, EXTI2_3_IRQn },
|
||||
{ GPIO_PIN_3, EXTI2_3_IRQn },
|
||||
{ GPIO_PIN_4, EXTI4_15_IRQn },
|
||||
{ GPIO_PIN_5, EXTI4_15_IRQn },
|
||||
{ GPIO_PIN_6, EXTI4_15_IRQn },
|
||||
{ GPIO_PIN_7, EXTI4_15_IRQn },
|
||||
{ GPIO_PIN_8, EXTI4_15_IRQn },
|
||||
{ GPIO_PIN_9, EXTI4_15_IRQn },
|
||||
{ GPIO_PIN_10, EXTI4_15_IRQn },
|
||||
{ GPIO_PIN_11, EXTI4_15_IRQn },
|
||||
{ GPIO_PIN_12, EXTI4_15_IRQn },
|
||||
{ GPIO_PIN_13, EXTI4_15_IRQn },
|
||||
{ GPIO_PIN_14, EXTI4_15_IRQn },
|
||||
{ GPIO_PIN_15, EXTI4_15_IRQn },
|
||||
};
|
||||
#else
|
||||
static const struct pin_irq_map pin_irq_map[] = {
|
||||
{ GPIO_PIN_0, EXTI0_IRQn },
|
||||
{ GPIO_PIN_1, EXTI1_IRQn },
|
||||
{ GPIO_PIN_2, EXTI2_IRQn },
|
||||
{ GPIO_PIN_3, EXTI3_IRQn },
|
||||
{ GPIO_PIN_4, EXTI4_IRQn },
|
||||
{ GPIO_PIN_5, EXTI5_9_IRQn },
|
||||
{ GPIO_PIN_6, EXTI5_9_IRQn },
|
||||
{ GPIO_PIN_7, EXTI5_9_IRQn },
|
||||
{ GPIO_PIN_8, EXTI5_9_IRQn },
|
||||
{ GPIO_PIN_9, EXTI5_9_IRQn },
|
||||
{ GPIO_PIN_10, EXTI10_15_IRQn },
|
||||
{ GPIO_PIN_11, EXTI10_15_IRQn },
|
||||
{ GPIO_PIN_12, EXTI10_15_IRQn },
|
||||
{ GPIO_PIN_13, EXTI10_15_IRQn },
|
||||
{ GPIO_PIN_14, EXTI10_15_IRQn },
|
||||
{ GPIO_PIN_15, EXTI10_15_IRQn },
|
||||
};
|
||||
#endif
|
||||
|
||||
struct rt_pin_irq_hdr pin_irq_hdr_tab[] = {
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
{ -1, 0, RT_NULL, RT_NULL },
|
||||
};
|
||||
|
||||
#define ITEM_NUM(items) sizeof(items) / sizeof(items[0])
|
||||
|
||||
/**
|
||||
* @brief get pin
|
||||
* @param pin
|
||||
* @retval None
|
||||
*/
|
||||
const struct pin_index *get_pin(rt_uint8_t pin)
|
||||
{
|
||||
const struct pin_index *index;
|
||||
|
||||
if (pin < ITEM_NUM(pins))
|
||||
{
|
||||
index = &pins[pin];
|
||||
if (index->index == -1)
|
||||
index = RT_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = RT_NULL;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int get_pin_config(const char *pin_name, uint32_t *port, uint32_t *pin, rcu_periph_enum *clk)
|
||||
{
|
||||
if (pin_name == NULL || port == NULL || pin == NULL || clk == NULL)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
if (strlen(pin_name) < 3 || pin_name[0] != 'P')
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
char port_letter = pin_name[1];
|
||||
switch (port_letter)
|
||||
{
|
||||
#ifdef GPIOA
|
||||
case 'A':
|
||||
*port = GPIOA;
|
||||
*clk = RCU_GPIOA;
|
||||
break;
|
||||
#endif /* GPIOA */
|
||||
#ifdef GPIOB
|
||||
case 'B':
|
||||
*port = GPIOB;
|
||||
*clk = RCU_GPIOB;
|
||||
break;
|
||||
#endif /* GPIOB */
|
||||
#ifdef GPIOC
|
||||
case 'C':
|
||||
*port = GPIOC;
|
||||
*clk = RCU_GPIOC;
|
||||
break;
|
||||
#endif /* GPIOC */
|
||||
#ifdef GPIOD
|
||||
case 'D':
|
||||
*port = GPIOD;
|
||||
*clk = RCU_GPIOD;
|
||||
break;
|
||||
#endif /* GPIOD */
|
||||
#ifdef GPIOE
|
||||
case 'E':
|
||||
*port = GPIOE;
|
||||
*clk = RCU_GPIOE;
|
||||
break;
|
||||
#endif /* GPIOE */
|
||||
#ifdef GPIOF
|
||||
case 'F':
|
||||
*port = GPIOF;
|
||||
*clk = RCU_GPIOF;
|
||||
break;
|
||||
#endif /* GPIOF */
|
||||
#ifdef GPIOG
|
||||
case 'G':
|
||||
*port = GPIOG;
|
||||
*clk = RCU_GPIOG;
|
||||
break;
|
||||
#endif /* GPIOG */
|
||||
#ifdef GPIOH
|
||||
case 'H':
|
||||
*port = GPIOH;
|
||||
*clk = RCU_GPIOH;
|
||||
break;
|
||||
#endif /* GPIOH */
|
||||
#ifdef GPIOI
|
||||
case 'I':
|
||||
*port = GPIOI;
|
||||
*clk = RCU_GPIOI;
|
||||
break;
|
||||
#endif /* GPIOI */
|
||||
#ifdef GPIOJ
|
||||
case 'J':
|
||||
*port = GPIOJ;
|
||||
*clk = RCU_GPIOJ;
|
||||
break;
|
||||
#endif /* GPIOJ */
|
||||
#ifdef GPIOK
|
||||
case 'K':
|
||||
*port = GPIOK;
|
||||
*clk = RCU_GPIOK;
|
||||
break;
|
||||
#endif /* GPIOK */
|
||||
default:
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
int pin_num = atoi(pin_name + 2);
|
||||
if (pin_num < 0 || pin_num > 15)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
*pin = GPIO_PIN_0 << pin_num;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pin_alternate_config(const char *alternate, uint32_t *af)
|
||||
{
|
||||
if (alternate == NULL || af == NULL)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
if (alternate[0] != 'A' || alternate[1] != 'F')
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
int af_num = atoi(alternate + 2);
|
||||
if (af_num < 0 || af_num > 15)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
switch (af_num)
|
||||
{
|
||||
case 0:
|
||||
*af = GPIO_AF_0;
|
||||
break;
|
||||
case 1:
|
||||
*af = GPIO_AF_1;
|
||||
break;
|
||||
case 2:
|
||||
*af = GPIO_AF_2;
|
||||
break;
|
||||
case 3:
|
||||
*af = GPIO_AF_3;
|
||||
break;
|
||||
case 4:
|
||||
*af = GPIO_AF_4;
|
||||
break;
|
||||
case 5:
|
||||
*af = GPIO_AF_5;
|
||||
break;
|
||||
case 6:
|
||||
*af = GPIO_AF_6;
|
||||
break;
|
||||
case 7:
|
||||
*af = GPIO_AF_7;
|
||||
break;
|
||||
case 8:
|
||||
*af = GPIO_AF_8;
|
||||
break;
|
||||
case 9:
|
||||
*af = GPIO_AF_9;
|
||||
break;
|
||||
case 10:
|
||||
*af = GPIO_AF_10;
|
||||
break;
|
||||
case 11:
|
||||
*af = GPIO_AF_11;
|
||||
break;
|
||||
case 12:
|
||||
*af = GPIO_AF_12;
|
||||
break;
|
||||
case 13:
|
||||
*af = GPIO_AF_13;
|
||||
break;
|
||||
case 14:
|
||||
*af = GPIO_AF_14;
|
||||
break;
|
||||
case 15:
|
||||
*af = GPIO_AF_15;
|
||||
break;
|
||||
default:
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set pin mode
|
||||
* @param dev, pin, mode
|
||||
* @retval None
|
||||
*/
|
||||
static void gd32_pin_mode(rt_device_t dev, rt_base_t pin, rt_uint8_t mode)
|
||||
{
|
||||
const struct pin_index *index = RT_NULL;
|
||||
rt_uint32_t pin_mode = 0;
|
||||
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E || defined SOC_SERIES_GD32F5xx || defined SOC_SERIES_GD32E23x
|
||||
rt_uint32_t pin_pupd = 0, pin_odpp = 0;
|
||||
#endif
|
||||
|
||||
index = get_pin(pin);
|
||||
if (index == RT_NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* GPIO Periph clock enable */
|
||||
rcu_periph_clock_enable(index->clk);
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E || defined SOC_SERIES_GD32F5xx || defined SOC_SERIES_GD32E23x
|
||||
pin_mode = GPIO_MODE_OUTPUT;
|
||||
#else
|
||||
pin_mode = GPIO_MODE_OUT_PP;
|
||||
#endif
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case PIN_MODE_OUTPUT:
|
||||
/* output setting */
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E || defined SOC_SERIES_GD32F5xx || defined SOC_SERIES_GD32E23x
|
||||
pin_mode = GPIO_MODE_OUTPUT;
|
||||
pin_pupd = GPIO_PUPD_NONE;
|
||||
pin_odpp = GPIO_OTYPE_PP;
|
||||
#else
|
||||
pin_mode = GPIO_MODE_OUT_PP;
|
||||
#endif
|
||||
break;
|
||||
case PIN_MODE_OUTPUT_OD:
|
||||
/* output setting: od. */
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E || defined SOC_SERIES_GD32F5xx || defined SOC_SERIES_GD32E23x
|
||||
pin_mode = GPIO_MODE_OUTPUT;
|
||||
pin_pupd = GPIO_PUPD_NONE;
|
||||
pin_odpp = GPIO_OTYPE_OD;
|
||||
#else
|
||||
pin_mode = GPIO_MODE_OUT_OD;
|
||||
#endif
|
||||
break;
|
||||
case PIN_MODE_INPUT:
|
||||
/* input setting: not pull. */
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E || defined SOC_SERIES_GD32F5xx || defined SOC_SERIES_GD32E23x
|
||||
pin_mode = GPIO_MODE_INPUT;
|
||||
pin_pupd = GPIO_PUPD_PULLUP | GPIO_PUPD_PULLDOWN;
|
||||
#else
|
||||
pin_mode = GPIO_MODE_IN_FLOATING;
|
||||
#endif
|
||||
break;
|
||||
case PIN_MODE_INPUT_PULLUP:
|
||||
/* input setting: pull up. */
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E || defined SOC_SERIES_GD32F5xx || defined SOC_SERIES_GD32E23x
|
||||
pin_mode = GPIO_MODE_INPUT;
|
||||
pin_pupd = GPIO_PUPD_PULLUP;
|
||||
#else
|
||||
pin_mode = GPIO_MODE_IPU;
|
||||
#endif
|
||||
break;
|
||||
case PIN_MODE_INPUT_PULLDOWN:
|
||||
/* input setting: pull down. */
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E || defined SOC_SERIES_GD32F5xx || defined SOC_SERIES_GD32E23x
|
||||
pin_mode = GPIO_MODE_INPUT;
|
||||
pin_pupd = GPIO_PUPD_PULLDOWN;
|
||||
#else
|
||||
pin_mode = GPIO_MODE_IPD;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32F5xx || defined SOC_SERIES_GD32E23x
|
||||
gpio_mode_set(index->gpio_periph, pin_mode, pin_pupd, index->pin);
|
||||
if (pin_mode == GPIO_MODE_OUTPUT)
|
||||
{
|
||||
gpio_output_options_set(index->gpio_periph, pin_odpp, GPIO_OSPEED_50MHZ, index->pin);
|
||||
}
|
||||
#elif defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E
|
||||
gpio_mode_set(index->gpio_periph, pin_mode, pin_pupd, index->pin);
|
||||
if (pin_mode == GPIO_MODE_OUTPUT)
|
||||
{
|
||||
gpio_output_options_set(index->gpio_periph, pin_odpp, GPIO_OSPEED_60MHZ, index->pin);
|
||||
}
|
||||
#else
|
||||
gpio_init(index->gpio_periph, pin_mode, GPIO_OSPEED_50MHZ, index->pin);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief pin write
|
||||
* @param dev, pin, valuie
|
||||
* @retval None
|
||||
*/
|
||||
static void gd32_pin_write(rt_device_t dev, rt_base_t pin, rt_uint8_t value)
|
||||
{
|
||||
const struct pin_index *index = RT_NULL;
|
||||
|
||||
index = get_pin(pin);
|
||||
if (index == RT_NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_bit_write(index->gpio_periph, index->pin, (bit_status)value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief pin read
|
||||
* @param dev, pin
|
||||
* @retval None
|
||||
*/
|
||||
static rt_ssize_t gd32_pin_read(rt_device_t dev, rt_base_t pin)
|
||||
{
|
||||
rt_ssize_t value = PIN_LOW;
|
||||
const struct pin_index *index = RT_NULL;
|
||||
|
||||
index = get_pin(pin);
|
||||
if (index == RT_NULL)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
value = gpio_input_bit_get(index->gpio_periph, index->pin);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief bit2bitno
|
||||
* @param bit
|
||||
* @retval None
|
||||
*/
|
||||
rt_inline rt_int32_t bit2bitno(rt_uint32_t bit)
|
||||
{
|
||||
rt_uint8_t i;
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
if ((0x01 << i) == bit)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief pin write
|
||||
* @param pinbit
|
||||
* @retval None
|
||||
*/
|
||||
rt_inline const struct pin_irq_map *get_pin_irq_map(rt_uint32_t pinbit)
|
||||
{
|
||||
rt_int32_t map_index = bit2bitno(pinbit);
|
||||
if (map_index < 0 || map_index >= ITEM_NUM(pin_irq_map))
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
return &pin_irq_map[map_index];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief pin irq attach
|
||||
* @param device, pin, mode
|
||||
* @retval None
|
||||
*/
|
||||
static rt_err_t gd32_pin_attach_irq(struct rt_device *device, rt_base_t pin,
|
||||
rt_uint8_t mode, void (*hdr)(void *args), void *args)
|
||||
{
|
||||
const struct pin_index *index = RT_NULL;
|
||||
rt_base_t level;
|
||||
rt_int32_t hdr_index = -1;
|
||||
|
||||
index = get_pin(pin);
|
||||
if (index == RT_NULL)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
hdr_index = bit2bitno(index->pin);
|
||||
if (hdr_index < 0 || hdr_index >= ITEM_NUM(pin_irq_map))
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (pin_irq_hdr_tab[hdr_index].pin == pin &&
|
||||
pin_irq_hdr_tab[hdr_index].hdr == hdr &&
|
||||
pin_irq_hdr_tab[hdr_index].mode == mode &&
|
||||
pin_irq_hdr_tab[hdr_index].args == args)
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
if (pin_irq_hdr_tab[hdr_index].pin != -1)
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
return -RT_EFULL;
|
||||
}
|
||||
pin_irq_hdr_tab[hdr_index].pin = pin;
|
||||
pin_irq_hdr_tab[hdr_index].hdr = hdr;
|
||||
pin_irq_hdr_tab[hdr_index].mode = mode;
|
||||
pin_irq_hdr_tab[hdr_index].args = args;
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief pin irq detach
|
||||
* @param device, pin
|
||||
* @retval None
|
||||
*/
|
||||
static rt_err_t gd32_pin_detach_irq(struct rt_device *device, rt_base_t pin)
|
||||
{
|
||||
const struct pin_index *index = RT_NULL;
|
||||
rt_base_t level;
|
||||
rt_int32_t hdr_index = -1;
|
||||
|
||||
index = get_pin(pin);
|
||||
if (index == RT_NULL)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
hdr_index = bit2bitno(index->pin);
|
||||
if (hdr_index < 0 || hdr_index >= ITEM_NUM(pin_irq_map))
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (pin_irq_hdr_tab[hdr_index].pin == -1)
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
return RT_EOK;
|
||||
}
|
||||
pin_irq_hdr_tab[hdr_index].pin = -1;
|
||||
pin_irq_hdr_tab[hdr_index].hdr = RT_NULL;
|
||||
pin_irq_hdr_tab[hdr_index].mode = 0;
|
||||
pin_irq_hdr_tab[hdr_index].args = RT_NULL;
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief pin irq enable
|
||||
* @param device, pin, enabled
|
||||
* @retval None
|
||||
*/
|
||||
static rt_err_t gd32_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled)
|
||||
{
|
||||
const struct pin_index *index;
|
||||
const struct pin_irq_map *irqmap;
|
||||
rt_base_t level;
|
||||
rt_int32_t hdr_index = -1;
|
||||
exti_trig_type_enum trigger_mode;
|
||||
|
||||
index = get_pin(pin);
|
||||
if (index == RT_NULL)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
if (enabled == PIN_IRQ_ENABLE)
|
||||
{
|
||||
hdr_index = bit2bitno(index->pin);
|
||||
if (hdr_index < 0 || hdr_index >= ITEM_NUM(pin_irq_map))
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (pin_irq_hdr_tab[hdr_index].pin == -1)
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
irqmap = &pin_irq_map[hdr_index];
|
||||
|
||||
switch (pin_irq_hdr_tab[hdr_index].mode)
|
||||
{
|
||||
case PIN_IRQ_MODE_RISING:
|
||||
trigger_mode = EXTI_TRIG_RISING;
|
||||
break;
|
||||
case PIN_IRQ_MODE_FALLING:
|
||||
trigger_mode = EXTI_TRIG_FALLING;
|
||||
break;
|
||||
case PIN_IRQ_MODE_RISING_FALLING:
|
||||
trigger_mode = EXTI_TRIG_BOTH;
|
||||
break;
|
||||
default:
|
||||
rt_hw_interrupt_enable(level);
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E || defined SOC_SERIES_GD32F5xx
|
||||
rcu_periph_clock_enable(RCU_SYSCFG);
|
||||
#elif defined SOC_SERIES_GD32E23x
|
||||
rcu_periph_clock_enable(RCU_CFGCMP);
|
||||
#else
|
||||
rcu_periph_clock_enable(RCU_AF);
|
||||
#endif
|
||||
|
||||
/* enable and set interrupt priority */
|
||||
#if defined SOC_SERIES_GD32E23x
|
||||
nvic_irq_enable(irqmap->irqno, 5U);
|
||||
#else
|
||||
nvic_irq_enable(irqmap->irqno, 5U, 0U);
|
||||
#endif
|
||||
/* connect EXTI line to GPIO pin */
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E || defined SOC_SERIES_GD32F5xx || defined SOC_SERIES_GD32E23x
|
||||
syscfg_exti_line_config(index->port_src, index->pin_src);
|
||||
#else
|
||||
gpio_exti_source_select(index->port_src, index->pin_src);
|
||||
#endif
|
||||
|
||||
/* configure EXTI line */
|
||||
exti_init((exti_line_enum)(index->exit_line), EXTI_INTERRUPT, trigger_mode);
|
||||
exti_interrupt_flag_clear((exti_line_enum)(index->exit_line));
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
else if (enabled == PIN_IRQ_DISABLE)
|
||||
{
|
||||
irqmap = get_pin_irq_map(index->pin);
|
||||
if (irqmap == RT_NULL)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
nvic_irq_disable(irqmap->irqno);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
const static struct rt_pin_ops gd32_pin_ops = {
|
||||
.pin_mode = gd32_pin_mode,
|
||||
.pin_write = gd32_pin_write,
|
||||
.pin_read = gd32_pin_read,
|
||||
.pin_attach_irq = gd32_pin_attach_irq,
|
||||
.pin_detach_irq = gd32_pin_detach_irq,
|
||||
.pin_irq_enable = gd32_pin_irq_enable,
|
||||
RT_NULL,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief pin write
|
||||
* @param irqno
|
||||
* @retval None
|
||||
*/
|
||||
rt_inline void pin_irq_hdr(int irqno)
|
||||
{
|
||||
if (pin_irq_hdr_tab[irqno].hdr)
|
||||
{
|
||||
pin_irq_hdr_tab[irqno].hdr(pin_irq_hdr_tab[irqno].args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief gd32 exit interrupt
|
||||
* @param exti_line
|
||||
* @retval None
|
||||
*/
|
||||
void GD32_GPIO_EXTI_IRQHandler(rt_int8_t exti_line)
|
||||
{
|
||||
#if defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E)
|
||||
exti_line_enum pin_exti_line = exti_line;
|
||||
#else
|
||||
exti_line_enum pin_exti_line = 1 << exti_line;
|
||||
#endif
|
||||
|
||||
if (RESET != exti_interrupt_flag_get(pin_exti_line))
|
||||
{
|
||||
pin_irq_hdr(exti_line);
|
||||
exti_interrupt_flag_clear(pin_exti_line);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined SOC_SERIES_GD32E23x
|
||||
void EXTI0_1_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
|
||||
GD32_GPIO_EXTI_IRQHandler(0);
|
||||
GD32_GPIO_EXTI_IRQHandler(1);
|
||||
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
void EXTI2_3_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
|
||||
GD32_GPIO_EXTI_IRQHandler(2);
|
||||
GD32_GPIO_EXTI_IRQHandler(3);
|
||||
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
void EXTI4_15_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
|
||||
GD32_GPIO_EXTI_IRQHandler(4);
|
||||
GD32_GPIO_EXTI_IRQHandler(5);
|
||||
GD32_GPIO_EXTI_IRQHandler(6);
|
||||
GD32_GPIO_EXTI_IRQHandler(7);
|
||||
GD32_GPIO_EXTI_IRQHandler(8);
|
||||
GD32_GPIO_EXTI_IRQHandler(9);
|
||||
GD32_GPIO_EXTI_IRQHandler(10);
|
||||
GD32_GPIO_EXTI_IRQHandler(11);
|
||||
GD32_GPIO_EXTI_IRQHandler(12);
|
||||
GD32_GPIO_EXTI_IRQHandler(13);
|
||||
GD32_GPIO_EXTI_IRQHandler(14);
|
||||
GD32_GPIO_EXTI_IRQHandler(15);
|
||||
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#else
|
||||
void EXTI0_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
GD32_GPIO_EXTI_IRQHandler(0);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
void EXTI1_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
GD32_GPIO_EXTI_IRQHandler(1);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
void EXTI2_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
GD32_GPIO_EXTI_IRQHandler(2);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
void EXTI3_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
GD32_GPIO_EXTI_IRQHandler(3);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
void EXTI4_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
GD32_GPIO_EXTI_IRQHandler(4);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
void EXTI5_9_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
GD32_GPIO_EXTI_IRQHandler(5);
|
||||
GD32_GPIO_EXTI_IRQHandler(6);
|
||||
GD32_GPIO_EXTI_IRQHandler(7);
|
||||
GD32_GPIO_EXTI_IRQHandler(8);
|
||||
GD32_GPIO_EXTI_IRQHandler(9);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
void EXTI10_15_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
GD32_GPIO_EXTI_IRQHandler(10);
|
||||
GD32_GPIO_EXTI_IRQHandler(11);
|
||||
GD32_GPIO_EXTI_IRQHandler(12);
|
||||
GD32_GPIO_EXTI_IRQHandler(13);
|
||||
GD32_GPIO_EXTI_IRQHandler(14);
|
||||
GD32_GPIO_EXTI_IRQHandler(15);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
|
||||
int rt_hw_pin_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = rt_device_pin_register("pin", &gd32_pin_ops, RT_NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
INIT_BOARD_EXPORT(rt_hw_pin_init);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-02-25 iysheng first version
|
||||
* 2025-10-22 kurisaw optimized configuration
|
||||
*/
|
||||
|
||||
#include <board.h>
|
||||
#include <rtdevice.h>
|
||||
#include "drv_hwtimer.h"
|
||||
#include "hwtimer_config.h"
|
||||
|
||||
#ifdef RT_USING_HWTIMER
|
||||
|
||||
/*
|
||||
* static void __set_timerx_freq
|
||||
* Set freq with timerx
|
||||
*
|
||||
* @param timerx the pointer of TIMER_TypeDef
|
||||
* @param freq of the timer clock
|
||||
* @retval None
|
||||
*/
|
||||
static void __set_timerx_freq(uint32_t timerx, uint32_t freq)
|
||||
{
|
||||
uint32_t ap1freq, ap2freq;
|
||||
uint16_t prescaler;
|
||||
uint32_t temp;
|
||||
uint32_t timesel;
|
||||
uint32_t APBPSC_limit;
|
||||
uint32_t multiple;
|
||||
timesel = RCU_CFG1 & RCU_CFG1_TIMERSEL;
|
||||
if (timesel == 0)
|
||||
{
|
||||
multiple = 2;
|
||||
APBPSC_limit = 0b100;
|
||||
}
|
||||
else
|
||||
{
|
||||
multiple = 4;
|
||||
APBPSC_limit = 0b101;
|
||||
}
|
||||
/* APB1 */
|
||||
if (!(timerx & (1 << 16)))
|
||||
{
|
||||
ap1freq = rcu_clock_freq_get(CK_APB1);
|
||||
/* Check if APB1 is divided */
|
||||
temp = RCU_CFG0 & RCU_CFG0_APB1PSC;
|
||||
temp >>= (__builtin_ctz(temp));
|
||||
/* When the division factor is less than expected, the clock frequency equals AHB clock, otherwise needs multiplication */
|
||||
prescaler = (temp <= APBPSC_limit) ? (rcu_clock_freq_get(CK_AHB) / freq - 1) : ((ap1freq * multiple) / freq - 1);
|
||||
}
|
||||
else /* APB2 */
|
||||
{
|
||||
ap2freq = rcu_clock_freq_get(CK_APB2);
|
||||
/* Check if APB2 is divided */
|
||||
temp = RCU_CFG0 & RCU_CFG0_APB2PSC;
|
||||
temp >>= (__builtin_ctz(temp));
|
||||
/* When the division factor is less than expected, the clock frequency equals AHB clock, otherwise needs multiplication */
|
||||
prescaler = (temp <= APBPSC_limit) ? (rcu_clock_freq_get(CK_AHB) / freq - 1) : ((ap2freq * multiple) / freq - 1);
|
||||
}
|
||||
timer_prescaler_config(timerx, prescaler, TIMER_PSC_RELOAD_NOW);
|
||||
}
|
||||
|
||||
static void gd32_hwtimer_init(struct rt_hwtimer_device *timer, rt_uint32_t state)
|
||||
{
|
||||
uint32_t timer_base = (uint32_t)timer->parent.user_data;
|
||||
timer_parameter_struct initpara;
|
||||
if (state)
|
||||
{
|
||||
/* Set internal clock source */
|
||||
timer_internal_clock_config(timer_base);
|
||||
/* Initialize timer configuration */
|
||||
timer_struct_para_init(&initpara);
|
||||
/* Set maximum timer period */
|
||||
initpara.period = timer->info->maxcnt;
|
||||
/* Configure timer */
|
||||
timer_init(timer_base, &initpara);
|
||||
/* Set timer input frequency */
|
||||
__set_timerx_freq(timer_base, timer->info->maxfreq);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t gd32_hwtimer_start(struct rt_hwtimer_device *timer,
|
||||
rt_uint32_t cnt, rt_hwtimer_mode_t mode)
|
||||
{
|
||||
uint32_t timer_base = (uint32_t)timer->parent.user_data;
|
||||
if (mode == HWTIMER_MODE_ONESHOT)
|
||||
{
|
||||
timer_single_pulse_mode_config(timer_base, TIMER_SP_MODE_SINGLE);
|
||||
}
|
||||
else if (mode == HWTIMER_MODE_PERIOD)
|
||||
{
|
||||
timer_single_pulse_mode_config(timer_base, TIMER_SP_MODE_REPETITIVE);
|
||||
}
|
||||
/* Reset timer count value */
|
||||
timer_counter_value_config(timer_base, 0);
|
||||
/* Set timer auto-reload value */
|
||||
timer_autoreload_value_config(timer_base, cnt - 1);
|
||||
/* Enable timer */
|
||||
timer_enable(timer_base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gd32_hwtimer_stop(struct rt_hwtimer_device *timer)
|
||||
{
|
||||
uint32_t timer_base = (uint32_t)timer->parent.user_data;
|
||||
timer_disable(timer_base);
|
||||
}
|
||||
|
||||
static rt_uint32_t gd32_hwtimer_count_get(struct rt_hwtimer_device *timer)
|
||||
{
|
||||
uint32_t timer_base = (uint32_t)timer->parent.user_data;
|
||||
rt_uint32_t count;
|
||||
count = timer_counter_read(timer_base);
|
||||
return count;
|
||||
}
|
||||
|
||||
static rt_err_t gd32_hwtimer_control(struct rt_hwtimer_device *timer, rt_uint32_t cmd,
|
||||
void *args)
|
||||
{
|
||||
int ret = RT_EOK;
|
||||
rt_int32_t freq;
|
||||
switch (cmd)
|
||||
{
|
||||
case HWTIMER_CTRL_FREQ_SET:
|
||||
freq = *(rt_uint32_t *)args;
|
||||
__set_timerx_freq((uint32_t)timer->parent.user_data, freq);
|
||||
break;
|
||||
default:
|
||||
rt_kprintf("invalid cmd:%x\n", cmd);
|
||||
ret = -RT_EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct rt_hwtimer_ops g_gd32_hwtimer_ops = {
|
||||
gd32_hwtimer_init,
|
||||
gd32_hwtimer_start,
|
||||
gd32_hwtimer_stop,
|
||||
gd32_hwtimer_count_get,
|
||||
gd32_hwtimer_control,
|
||||
};
|
||||
|
||||
static gd32_hwtimer_device g_gd32_hwtimer[] = {
|
||||
#ifdef BSP_USING_HWTIMER0
|
||||
HWTIMER0_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER1
|
||||
HWTIMER1_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER2
|
||||
HWTIMER2_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER3
|
||||
HWTIMER3_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER4
|
||||
HWTIMER4_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER5
|
||||
HWTIMER5_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER6
|
||||
HWTIMER6_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER7
|
||||
HWTIMER7_CONFIG,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef BSP_USING_HWTIMER0
|
||||
void TIMER0_UP_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM0_INDEX].hwtimer_dev);
|
||||
timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM0_INDEX].hwtimer_dev.parent.user_data, TIMER_INT_UP);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER1
|
||||
void TIMER1_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM1_INDEX].hwtimer_dev);
|
||||
timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM1_INDEX].hwtimer_dev.parent.user_data, TIMER_INT_UP);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER2
|
||||
void TIMER2_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM2_INDEX].hwtimer_dev);
|
||||
timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM2_INDEX].hwtimer_dev.parent.user_data, TIMER_INT_UP);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER3
|
||||
void TIMER3_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM3_INDEX].hwtimer_dev);
|
||||
timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM3_INDEX].hwtimer_dev.parent.user_data, TIMER_INT_UP);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER4
|
||||
void TIMER4_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM4_INDEX].hwtimer_dev);
|
||||
timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM4_INDEX].hwtimer_dev.parent.user_data, TIMER_INT_UP);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER5
|
||||
void TIMER5_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM5_INDEX].hwtimer_dev);
|
||||
timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM5_INDEX].hwtimer_dev.parent.user_data, TIMER_INT_UP);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER6
|
||||
void TIMER6_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM6_INDEX].hwtimer_dev);
|
||||
timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM6_INDEX].hwtimer_dev.parent.user_data, TIMER_INT_UP);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER7
|
||||
void TIMER7_UP_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
rt_device_hwtimer_isr(&g_gd32_hwtimer[TIM7_INDEX].hwtimer_dev);
|
||||
timer_flag_clear((uint32_t)g_gd32_hwtimer[TIM7_INDEX].hwtimer_dev.parent.user_data, TIMER_INT_UP);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rt_hwtimer_init(void)
|
||||
{
|
||||
int ret = 0, i = 0;
|
||||
for (; i < sizeof(g_gd32_hwtimer) / sizeof(g_gd32_hwtimer[0]); i++)
|
||||
{
|
||||
g_gd32_hwtimer[i].hwtimer_dev.ops = &g_gd32_hwtimer_ops;
|
||||
g_gd32_hwtimer[i].hwtimer_dev.info = &g_gd32_hwtimer[i].hwtimer_info;
|
||||
/* Enable clock */
|
||||
rcu_periph_clock_enable(g_gd32_hwtimer[i].hw_data.rcu);
|
||||
/* Set timer interrupt priority */
|
||||
NVIC_SetPriority(g_gd32_hwtimer[i].hw_data.irqn, 0);
|
||||
/* Enable NVIC */
|
||||
NVIC_EnableIRQ(g_gd32_hwtimer[i].hw_data.irqn);
|
||||
/* Enable timer interrupt */
|
||||
timer_interrupt_enable(g_gd32_hwtimer[i].hw_data.reg_base, TIMER_INT_UP);
|
||||
/* Register device to system */
|
||||
ret = rt_device_hwtimer_register(&g_gd32_hwtimer[i].hwtimer_dev,
|
||||
g_gd32_hwtimer[i].dev_name, (void *)g_gd32_hwtimer[i].hw_data.reg_base);
|
||||
if (RT_EOK != ret)
|
||||
{
|
||||
rt_kprintf("failed register %s, err=%d\n", g_gd32_hwtimer[i].dev_name,
|
||||
ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
INIT_BOARD_EXPORT(rt_hwtimer_init);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,622 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-12-20 BruceOu the first version
|
||||
* 2025-10-10 WangShun compatible with RT-Studio
|
||||
*/
|
||||
|
||||
#include "drv_i2c.h"
|
||||
#include "i2c_config.h"
|
||||
|
||||
#ifdef RT_USING_I2C
|
||||
|
||||
#define DBG_TAG "drv.i2c"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#if !defined(BSP_USING_I2C0) && !defined(BSP_USING_I2C1) && !defined(BSP_USING_I2C2) && !defined(BSP_USING_I2C3) && \
|
||||
!defined(BSP_USING_I2C4) && !defined(BSP_USING_I2C5)
|
||||
#error "Please define at least one BSP_USING_I2Cx"
|
||||
/* this driver can be disabled at menuconfig → RT-Thread Components → Device Drivers */
|
||||
#endif
|
||||
|
||||
#if defined(BSP_USING_I2C0)
|
||||
struct rt_i2c_bus_device i2c0;
|
||||
#endif /* BSP_USING_I2C0 */
|
||||
|
||||
#if defined(BSP_USING_I2C1)
|
||||
struct rt_i2c_bus_device i2c1;
|
||||
#endif /* BSP_USING_I2C1 */
|
||||
|
||||
#if defined(BSP_USING_I2C2)
|
||||
struct rt_i2c_bus_device i2c2;
|
||||
#endif /* BSP_USING_I2C2 */
|
||||
|
||||
#if defined(BSP_USING_I2C3)
|
||||
struct rt_i2c_bus_device i2c3;
|
||||
#endif /* BSP_USING_I2C3 */
|
||||
|
||||
#if defined(BSP_USING_I2C4)
|
||||
struct rt_i2c_bus_device i2c4;
|
||||
#endif /* BSP_USING_I2C4 */
|
||||
|
||||
#if defined(BSP_USING_I2C5)
|
||||
struct rt_i2c_bus_device i2c5;
|
||||
#endif /* BSP_USING_I2C5 */
|
||||
|
||||
#if defined(SOC_SERIES_GD32F5xx)
|
||||
#define i2c_flag_get_gd i2c_add_flag_get
|
||||
#define i2c_timing_config_gd i2c_add_timing_config
|
||||
#define i2c_master_clock_config_gd i2c_add_master_clock_config
|
||||
#define i2c_enable_gd i2c_add_enable
|
||||
#define i2c_flag_clear_gd i2c_add_flag_clear
|
||||
#define i2c_stop_on_bus_gd i2c_add_stop_on_bus
|
||||
#define i2c_transfer_byte_number_config_gd i2c_add_transfer_byte_number_config
|
||||
#define i2c_start_on_bus_gd i2c_add_start_on_bus
|
||||
#define i2c_address10_enable_gd i2c_add_address10_enable
|
||||
#define i2c_address10_disable_gd i2c_add_address10_disable
|
||||
#define i2c_master_addressing_gd i2c_add_master_addressing
|
||||
#define i2c_data_transmit_gd i2c_add_data_transmit
|
||||
#define i2c_data_receive_gd i2c_add_data_receive
|
||||
|
||||
#define I2C_FLAG_RBNE_GD I2C_ADD_FLAG_RBNE
|
||||
#define I2C_STAT_GD I2C_ADD_STAT
|
||||
#define I2C_STAT_TBE_GD I2C_ADD_STAT_TBE
|
||||
#define I2C_STAT_TI_GD I2C_ADD_STAT_TI
|
||||
#define I2C_MASTER_RECEIVE_GD I2C_ADD_MASTER_RECEIVE
|
||||
#define I2C_MASTER_TRANSMIT_GD I2C_ADD_MASTER_TRANSMIT
|
||||
#define I2C_FLAG_I2CBSY_GD I2C_ADD_FLAG_I2CBSY
|
||||
#define I2C_FLAG_TC_GD I2C_ADD_FLAG_TC
|
||||
#define I2C_FLAG_TI_GD I2C_ADD_FLAG_TI
|
||||
#define I2C_FLAG_STPDET_GD I2C_ADD_FLAG_STPDET
|
||||
|
||||
#else
|
||||
|
||||
#define i2c_flag_get_gd i2c_flag_get
|
||||
#define i2c_timing_config_gd i2c_timing_config
|
||||
#define i2c_master_clock_config_gd i2c_master_clock_config
|
||||
#define i2c_enable_gd i2c_enable
|
||||
#define i2c_flag_clear_gd i2c_flag_clear
|
||||
#define i2c_data_receive_gd i2c_data_receive
|
||||
#define i2c_data_transmit_gd i2c_data_transmit
|
||||
#define i2c_address10_enable_gd i2c_address10_enable
|
||||
#define i2c_address10_disable_gd i2c_address10_disable
|
||||
#define i2c_master_addressing_gd i2c_master_addressing
|
||||
#define i2c_transfer_byte_number_config_gd i2c_transfer_byte_number_config
|
||||
#define i2c_start_on_bus_gd i2c_start_on_bus
|
||||
#define i2c_stop_on_bus_gd i2c_stop_on_bus
|
||||
|
||||
#if defined(SOC_SERIES_GD32E51x)
|
||||
|
||||
#undef i2c_flag_get_gd
|
||||
#undef i2c_flag_clear_gd
|
||||
#undef i2c_master_addressing_gd
|
||||
#define i2c_flag_get_gd i2c2_flag_get
|
||||
#define i2c_flag_clear_gd i2c2_flag_clear
|
||||
#define i2c_master_addressing_gd i2c2_master_addressing
|
||||
|
||||
#undef I2C_STAT_GD
|
||||
#undef I2C_STAT_TBE_GD
|
||||
#undef I2C_STAT_TI_GD
|
||||
#define I2C_STAT_GD I2C2_STAT
|
||||
#define I2C_STAT_TBE_GD I2C2_STAT_TBE
|
||||
#define I2C_STAT_TI_GD I2C2_STAT_TI
|
||||
|
||||
#undef I2C_MASTER_RECEIVE_GD
|
||||
#undef I2C_MASTER_TRANSMIT_GD
|
||||
#define I2C_MASTER_RECEIVE_GD I2C2_MASTER_RECEIVE
|
||||
#define I2C_MASTER_TRANSMIT_GD I2C2_MASTER_TRANSMIT
|
||||
|
||||
#undef I2C_FLAG_RBNE_GD
|
||||
#undef I2C_FLAG_I2CBSY_GD
|
||||
#undef I2C_FLAG_TC_GD
|
||||
#undef I2C_FLAG_TI_GD
|
||||
#undef I2C_FLAG_STPDET_GD
|
||||
#define I2C_FLAG_RBNE_GD I2C2_FLAG_RBNE
|
||||
#define I2C_FLAG_I2CBSY_GD I2C2_FLAG_I2CBSY
|
||||
#define I2C_FLAG_TC_GD I2C2_FLAG_TC
|
||||
#define I2C_FLAG_TI_GD I2C2_FLAG_TI
|
||||
#define I2C_FLAG_STPDET_GD I2C2_FLAG_STPDET
|
||||
/* also needed in write path */
|
||||
#define I2C_FLAG_TBE_GD I2C2_FLAG_TBE
|
||||
|
||||
#else
|
||||
#define I2C_FLAG_RBNE_GD I2C_FLAG_RBNE
|
||||
#define I2C_STAT_GD I2C_STAT
|
||||
#define I2C_STAT_TBE_GD I2C_STAT_TBE
|
||||
#define I2C_STAT_TI_GD I2C_STAT_TI
|
||||
#define I2C_MASTER_RECEIVE_GD I2C_MASTER_RECEIVE
|
||||
#define I2C_MASTER_TRANSMIT_GD I2C_MASTER_TRANSMIT
|
||||
#define I2C_FLAG_I2CBSY_GD I2C_FLAG_I2CBSY
|
||||
#define I2C_FLAG_TC_GD I2C_FLAG_TC
|
||||
#define I2C_FLAG_TI_GD I2C_FLAG_TI
|
||||
#define I2C_FLAG_STPDET_GD I2C_FLAG_STPDET
|
||||
/* used in write path */
|
||||
#define I2C_FLAG_TBE_GD I2C_FLAG_TBE
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SOC_SERIES_GD32F5xx)
|
||||
#define IS_I2C_LEGACY(periph) ((periph) == I2C0 || (periph) == I2C1 || (periph) == I2C2)
|
||||
#elif defined(SOC_SERIES_GD32F4xx)
|
||||
#define IS_I2C_LEGACY(periph) (1)
|
||||
#elif defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E) || defined(SOC_SERIES_GD32L23x)
|
||||
#define IS_I2C_LEGACY(periph) (0)
|
||||
#elif defined(SOC_SERIES_GD32E51x)
|
||||
#define IS_I2C_LEGACY(periph) ((periph) == I2C0 || (periph) == I2C1)
|
||||
#endif
|
||||
|
||||
static const struct gd32_i2c_bus gd_i2c_config[] = {
|
||||
#ifdef BSP_USING_I2C0
|
||||
I2C0_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_I2C1
|
||||
I2C1_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_I2C2
|
||||
I2C2_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_I2C3
|
||||
I2C3_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_I2C4
|
||||
I2C4_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_I2C5
|
||||
I2C5_CONFIG,
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This function initializes the i2c pin.
|
||||
* @param i2c
|
||||
* @retval None
|
||||
*/
|
||||
static void gd32_i2c_gpio_init(const struct gd32_i2c_bus *i2c)
|
||||
{
|
||||
rt_uint32_t scl_port, sda_port;
|
||||
rt_uint32_t scl_pin, sda_pin;
|
||||
rt_uint32_t pin_af;
|
||||
rcu_periph_enum scl_periph, sda_periph;
|
||||
|
||||
if (get_pin_config(i2c->scl_pin_name, &scl_port, &scl_pin, &scl_periph) == -RT_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_pin_config(i2c->sda_pin_name, &sda_port, &sda_pin, &sda_periph) == -RT_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pin_alternate_config(i2c->alternate, &pin_af);
|
||||
|
||||
/* enable I2C and GPIO clock */
|
||||
rcu_periph_clock_enable(scl_periph);
|
||||
rcu_periph_clock_enable(sda_periph);
|
||||
rcu_periph_clock_enable(i2c->per_clk);
|
||||
|
||||
/* configure I2C_SCL as alternate function push-pull */
|
||||
|
||||
#if defined(SOC_SERIES_GD32E51x)
|
||||
|
||||
gpio_init(scl_port, GPIO_MODE_AF_OD, GPIO_OSPEED_10MHZ, scl_pin);
|
||||
gpio_init(sda_port, GPIO_MODE_AF_OD, GPIO_OSPEED_10MHZ, sda_pin);
|
||||
|
||||
if (!IS_I2C_LEGACY(i2c->i2c_periph))
|
||||
{
|
||||
rcu_periph_clock_enable(RCU_AF);
|
||||
gpio_afio_port_config(AFIO_PA8_I2C2_CFG, ENABLE);
|
||||
gpio_afio_port_config(AFIO_PC9_I2C2_CFG, ENABLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
i2c_deinit(i2c->i2c_periph);
|
||||
}
|
||||
|
||||
/* configure remap function */
|
||||
if (i2c->i2c_remap != 0)
|
||||
{
|
||||
rcu_periph_clock_enable(RCU_AF);
|
||||
gpio_pin_remap_config(i2c->i2c_remap, ENABLE);
|
||||
}
|
||||
|
||||
gpio_init(scl_port, GPIO_MODE_AF_OD, GPIO_OSPEED_10MHZ, scl_pin);
|
||||
gpio_init(sda_port, GPIO_MODE_AF_OD, GPIO_OSPEED_10MHZ, sda_pin);
|
||||
|
||||
/* configure alternate1 function */
|
||||
if (pin_af != 0 || pin_af != 0)
|
||||
{
|
||||
rcu_periph_clock_enable(RCU_AF);
|
||||
gpio_afio_port_config(pin_af, ENABLE);
|
||||
gpio_afio_port_config(pin_af, ENABLE);
|
||||
}
|
||||
|
||||
i2c_deinit(i2c->i2c_periph);
|
||||
|
||||
#else
|
||||
gpio_af_set(scl_port, pin_af, scl_pin);
|
||||
gpio_mode_set(scl_port, GPIO_MODE_AF, GPIO_PUPD_PULLUP, scl_pin);
|
||||
#if defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E)
|
||||
gpio_output_options_set(scl_port, GPIO_OTYPE_OD, GPIO_OSPEED_60MHZ, scl_pin);
|
||||
/* configure I2C_SDA as alternate function push-pull */
|
||||
gpio_af_set(sda_port, pin_af, sda_pin);
|
||||
gpio_mode_set(sda_port, GPIO_MODE_AF, GPIO_PUPD_PULLUP, sda_pin);
|
||||
gpio_output_options_set(sda_port, GPIO_OTYPE_OD, GPIO_OSPEED_60MHZ, sda_pin);
|
||||
#else
|
||||
gpio_output_options_set(scl_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, scl_pin);
|
||||
/* configure I2C_SDA as alternate function push-pull */
|
||||
gpio_af_set(sda_port, pin_af, sda_pin);
|
||||
gpio_mode_set(sda_port, GPIO_MODE_AF, GPIO_PUPD_PULLUP, sda_pin);
|
||||
gpio_output_options_set(sda_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, sda_pin);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief read data.
|
||||
* @param i2c_periph
|
||||
* @param *p_buffer
|
||||
* @param data_byte
|
||||
* @retval None
|
||||
*/
|
||||
static uint8_t gd32_i2c_read(rt_uint32_t i2c_periph, rt_uint8_t *p_buffer, rt_uint16_t data_byte)
|
||||
{
|
||||
if (data_byte == 0)
|
||||
return 1;
|
||||
/* while there is data to be read */
|
||||
|
||||
while (data_byte)
|
||||
{
|
||||
#if defined(SOC_SERIES_GD32F5xx) || defined(SOC_SERIES_GD32F4xx) || defined(SOC_SERIES_GD32E51x)
|
||||
if (IS_I2C_LEGACY(i2c_periph))
|
||||
{
|
||||
if (3 == data_byte)
|
||||
{
|
||||
/* wait until BTC bit is set */
|
||||
while (!i2c_flag_get(i2c_periph, I2C_FLAG_BTC))
|
||||
;
|
||||
/* disable acknowledge */
|
||||
i2c_ack_config(i2c_periph, I2C_ACK_DISABLE);
|
||||
}
|
||||
|
||||
if (2 == data_byte)
|
||||
{
|
||||
/* wait until BTC bit is set */
|
||||
while (!i2c_flag_get(i2c_periph, I2C_FLAG_BTC))
|
||||
;
|
||||
/* send a stop condition to I2C bus */
|
||||
i2c_stop_on_bus(i2c_periph);
|
||||
}
|
||||
/* wait until RBNE bit is set */
|
||||
if (i2c_flag_get(i2c_periph, I2C_FLAG_RBNE))
|
||||
{
|
||||
/* read a byte from the EEPROM */
|
||||
*p_buffer = i2c_data_receive(i2c_periph);
|
||||
/* point to the next location where the byte read will be saved */
|
||||
p_buffer++;
|
||||
/* decrement the read bytes counter */
|
||||
data_byte--;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* wait until the RBNE bit is set */
|
||||
while (!i2c_flag_get_gd(i2c_periph, I2C_FLAG_RBNE_GD))
|
||||
;
|
||||
|
||||
/* read a byte */
|
||||
*p_buffer = i2c_data_receive_gd(i2c_periph);
|
||||
/* point to the next location where the byte read will be saved */
|
||||
p_buffer++;
|
||||
/* decrement the read bytes counter */
|
||||
data_byte--;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief write data.
|
||||
* @param i2c_periph
|
||||
* @param *p_buffer
|
||||
* @param data_byte
|
||||
* @retval None
|
||||
*/
|
||||
static uint8_t gd32_i2c_write(rt_uint32_t i2c_periph, uint8_t *p_buffer, uint16_t data_byte)
|
||||
{
|
||||
if (data_byte == 0)
|
||||
return 1;
|
||||
|
||||
while (data_byte)
|
||||
{
|
||||
#if defined(SOC_SERIES_GD32F5xx) || defined(SOC_SERIES_GD32F4xx) || defined(SOC_SERIES_GD32E51x)
|
||||
if (IS_I2C_LEGACY(i2c_periph))
|
||||
{
|
||||
/* data transmission */
|
||||
i2c_data_transmit(i2c_periph, *p_buffer);
|
||||
/* point to the next byte to be written */
|
||||
p_buffer++;
|
||||
/* decrement the write bytes counter */
|
||||
data_byte--;
|
||||
/* wait until the TI bit is set */
|
||||
while (!i2c_flag_get(i2c_periph, I2C_FLAG_BTC))
|
||||
;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if defined(SOC_SERIES_GD32F5xx) || defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E) || defined(SOC_SERIES_GD32L23x) || defined(SOC_SERIES_GD32E51x)
|
||||
/* wait until the transmit data buffer is empty */
|
||||
I2C_STAT_GD(i2c_periph) |= I2C_STAT_TBE_GD;
|
||||
while (!i2c_flag_get_gd(i2c_periph, I2C_FLAG_TBE))
|
||||
;
|
||||
|
||||
while (data_byte)
|
||||
{
|
||||
/* wait until the TI bit is set */
|
||||
while (!i2c_flag_get_gd(i2c_periph, I2C_FLAG_TI_GD))
|
||||
;
|
||||
/* data transmission */
|
||||
i2c_data_transmit(i2c_periph, *p_buffer);
|
||||
/* point to the next byte to be written */
|
||||
p_buffer++;
|
||||
/* decrement the write bytes counter */
|
||||
data_byte--;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (data_byte != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_ssize_t gd32_i2c_master_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num)
|
||||
{
|
||||
static struct rt_i2c_msg *msg;
|
||||
|
||||
rt_uint32_t i, w_total_byte = 0, r_total_byte = 0;
|
||||
rt_err_t ret = RT_ERROR;
|
||||
|
||||
RT_ASSERT(bus != RT_NULL);
|
||||
|
||||
struct gd32_i2c_bus *gd32_i2c = (struct gd32_i2c_bus *)bus->priv;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
msg = &msgs[i];
|
||||
|
||||
if (msg->flags & RT_I2C_RD)
|
||||
{
|
||||
r_total_byte += msg->len;
|
||||
}
|
||||
else
|
||||
{
|
||||
w_total_byte += msg->len;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
msg = &msgs[i];
|
||||
if (!(msg->flags & RT_I2C_NO_START))
|
||||
{
|
||||
#if defined(SOC_SERIES_GD32F5xx) || defined(SOC_SERIES_GD32F4xx) || defined(SOC_SERIES_GD32E51x)
|
||||
if (IS_I2C_LEGACY(gd32_i2c->i2c_periph))
|
||||
{
|
||||
if (msg->flags & RT_I2C_RD)
|
||||
{
|
||||
if (i2c_flag_get(gd32_i2c->i2c_periph, I2C_FLAG_I2CBSY))
|
||||
{
|
||||
i2c_stop_on_bus(gd32_i2c->i2c_periph);
|
||||
}
|
||||
/* enable acknowledge */
|
||||
i2c_ack_config(gd32_i2c->i2c_periph, I2C_ACK_ENABLE);
|
||||
/* i2c master sends start signal only when the bus is idle */
|
||||
while (i2c_flag_get(gd32_i2c->i2c_periph, I2C_FLAG_I2CBSY))
|
||||
;
|
||||
/* send the start signal */
|
||||
i2c_start_on_bus(gd32_i2c->i2c_periph);
|
||||
/* i2c master sends START signal successfully */
|
||||
while (!i2c_flag_get(gd32_i2c->i2c_periph, I2C_FLAG_SBSEND))
|
||||
;
|
||||
|
||||
i2c_master_addressing(gd32_i2c->i2c_periph, msg->addr, I2C_RECEIVER);
|
||||
|
||||
while (!i2c_flag_get(gd32_i2c->i2c_periph, I2C_FLAG_ADDSEND))
|
||||
;
|
||||
/* address flag set means i2c slave sends ACK */
|
||||
i2c_flag_clear(gd32_i2c->i2c_periph, I2C_FLAG_ADDSEND);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure slave address */
|
||||
while (i2c_flag_get(gd32_i2c->i2c_periph, I2C_FLAG_I2CBSY))
|
||||
;
|
||||
//i2c_transfer_byte_number_config(gd32_i2c->i2c_periph, w_total_byte);
|
||||
/* send a start condition to I2C bus */
|
||||
i2c_start_on_bus(gd32_i2c->i2c_periph);
|
||||
while (!i2c_flag_get(gd32_i2c->i2c_periph, I2C_FLAG_SBSEND))
|
||||
;
|
||||
|
||||
i2c_master_addressing(gd32_i2c->i2c_periph, msg->addr, I2C_TRANSMITTER);
|
||||
while (!i2c_flag_get(gd32_i2c->i2c_periph, I2C_FLAG_ADDSEND))
|
||||
;
|
||||
|
||||
i2c_flag_clear(gd32_i2c->i2c_periph, I2C_FLAG_ADDSEND);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if defined(SOC_SERIES_GD32F5xx) || defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E) || defined(SOC_SERIES_GD32L23x) || defined(SOC_SERIES_GD32E51x)
|
||||
if (msg->flags & RT_I2C_ADDR_10BIT)
|
||||
{
|
||||
/* enable 10-bit addressing mode in master mode */
|
||||
i2c_address10_enable_gd(gd32_i2c->i2c_periph);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* disable 10-bit addressing mode in master mode */
|
||||
i2c_address10_disable_gd(gd32_i2c->i2c_periph);
|
||||
}
|
||||
|
||||
if (msg->flags & RT_I2C_RD)
|
||||
{
|
||||
/* configure slave address */
|
||||
i2c_master_addressing_gd(gd32_i2c->i2c_periph, msg->addr, I2C_MASTER_RECEIVE_GD);
|
||||
|
||||
i2c_transfer_byte_number_config_gd(gd32_i2c->i2c_periph, r_total_byte);
|
||||
/* send a start condition to I2C bus */
|
||||
i2c_start_on_bus_gd(gd32_i2c->i2c_periph);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure slave address */
|
||||
i2c_master_addressing_gd(gd32_i2c->i2c_periph, msg->addr, I2C_MASTER_TRANSMIT_GD);
|
||||
while (i2c_flag_get_gd(gd32_i2c->i2c_periph, I2C_FLAG_I2CBSY_GD))
|
||||
;
|
||||
i2c_transfer_byte_number_config_gd(gd32_i2c->i2c_periph, w_total_byte);
|
||||
/* send a start condition to I2C bus */
|
||||
i2c_start_on_bus_gd(gd32_i2c->i2c_periph);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (msg->flags & RT_I2C_RD)
|
||||
{
|
||||
if (gd32_i2c_read(gd32_i2c->i2c_periph, msg->buf, msg->len) != 0)
|
||||
{
|
||||
LOG_E("i2c bus read failed,i2c bus stop!");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gd32_i2c_write(gd32_i2c->i2c_periph, msg->buf, msg->len) != 0)
|
||||
{
|
||||
LOG_E("i2c bus write failed,i2c bus stop!");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#if defined(SOC_SERIES_GD32F5xx) || defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E) || defined(SOC_SERIES_GD32L23x) || defined(SOC_SERIES_GD32E51x)
|
||||
if (!IS_I2C_LEGACY(gd32_i2c->i2c_periph))
|
||||
{
|
||||
if (r_total_byte != 0)
|
||||
{
|
||||
while (!i2c_flag_get_gd(gd32_i2c->i2c_periph, I2C_FLAG_TC_GD))
|
||||
;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
ret = i;
|
||||
|
||||
out:
|
||||
#if defined(SOC_SERIES_GD32F5xx) || defined(SOC_SERIES_GD32F4xx) || defined(SOC_SERIES_GD32E51x)
|
||||
if (IS_I2C_LEGACY(gd32_i2c->i2c_periph))
|
||||
{
|
||||
if (!(msg->flags & RT_I2C_NO_STOP))
|
||||
{
|
||||
if (msg->flags & RT_I2C_RD)
|
||||
{
|
||||
while ((I2C_CTL0(gd32_i2c->i2c_periph) & I2C_CTL0_STOP))
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* send a stop condition to I2C bus */
|
||||
i2c_stop_on_bus(gd32_i2c->i2c_periph);
|
||||
/* wait until stop condition generate */
|
||||
while ((I2C_CTL0(gd32_i2c->i2c_periph) & I2C_CTL0_STOP))
|
||||
;
|
||||
/* clear the STPDET bit */
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if defined(SOC_SERIES_GD32F5xx) || defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E) || defined(SOC_SERIES_GD32L23x) || defined(SOC_SERIES_GD32E51x)
|
||||
if (!(msg->flags & RT_I2C_NO_STOP))
|
||||
{
|
||||
while (!i2c_flag_get_gd(gd32_i2c->i2c_periph, I2C_FLAG_TC_GD))
|
||||
;
|
||||
/* send a stop condition to I2C bus */
|
||||
i2c_stop_on_bus_gd(gd32_i2c->i2c_periph);
|
||||
/* wait until stop condition generate */
|
||||
while (!i2c_flag_get_gd(gd32_i2c->i2c_periph, I2C_FLAG_STPDET_GD))
|
||||
;
|
||||
/* clear the STPDET bit */
|
||||
i2c_flag_clear_gd(gd32_i2c->i2c_periph, I2C_FLAG_STPDET_GD);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct rt_i2c_bus_device_ops i2c_ops = {
|
||||
.master_xfer = gd32_i2c_master_xfer,
|
||||
.slave_xfer = RT_NULL,
|
||||
.i2c_bus_control = RT_NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief I2C initialization function
|
||||
* @param None
|
||||
* @retval RT_EOK indicates successful initialization.
|
||||
*/
|
||||
int rt_hw_i2c_init(void)
|
||||
{
|
||||
rt_size_t obj_num = sizeof(gd_i2c_config) / sizeof(gd_i2c_config[0]);
|
||||
|
||||
for (int i = 0; i < obj_num; i++)
|
||||
{
|
||||
gd32_i2c_gpio_init(&gd_i2c_config[i]);
|
||||
|
||||
/* configure I2C timing. I2C speed clock=400kHz*/
|
||||
#if defined(SOC_SERIES_GD32F5xx) || defined(SOC_SERIES_GD32F4xx) || defined(SOC_SERIES_GD32E51x)
|
||||
if (IS_I2C_LEGACY(gd_i2c_config[i].i2c_periph))
|
||||
{
|
||||
i2c_clock_config(gd_i2c_config[i].i2c_periph, 100000, I2C_DTCY_2);
|
||||
i2c_mode_addr_config(gd_i2c_config[i].i2c_periph, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0xa0);
|
||||
i2c_enable(gd_i2c_config[i].i2c_periph);
|
||||
i2c_ack_config(gd_i2c_config[i].i2c_periph, I2C_ACK_ENABLE);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if defined(SOC_SERIES_GD32F5xx) || defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E) || defined(SOC_SERIES_GD32L23x) || defined(SOC_SERIES_GD32E51x)
|
||||
i2c_timing_config_gd(gd_i2c_config[i].i2c_periph, 0x1, 0x7, 0);
|
||||
i2c_master_clock_config_gd(gd_i2c_config[i].i2c_periph, 0x2D, 0x87);
|
||||
|
||||
/* enable I2C1 */
|
||||
i2c_enable_gd(gd_i2c_config[i].i2c_periph);
|
||||
#endif
|
||||
}
|
||||
|
||||
gd_i2c_config[i].i2c_bus->ops = &i2c_ops;
|
||||
gd_i2c_config[i].i2c_bus->priv = (void *)&gd_i2c_config[i];
|
||||
|
||||
rt_i2c_bus_device_register(gd_i2c_config[i].i2c_bus, gd_i2c_config[i].device_name);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
INIT_BOARD_EXPORT(rt_hw_i2c_init);
|
||||
|
||||
#endif /* RT_USING_I2C */
|
||||
|
||||
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "drv_lcd.h"
|
||||
|
||||
#ifdef RT_USING_LCD
|
||||
|
||||
#define DBG_TAG "drv_lcd"
|
||||
#define DBG_LVL DBG_LOG
|
||||
#include <rtdbg.h>
|
||||
|
||||
struct drv_lcd_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
struct rt_device_graphic_info lcd_info;
|
||||
};
|
||||
|
||||
static uint16_t *frame_buffer = RT_NULL;
|
||||
struct drv_lcd_device _lcd = { 0 };
|
||||
RGB color_write = { 0, 0xFF, 0xFF, 0xFF };
|
||||
RGB color_black = { 0, 0x00, 0x00, 0x00 };
|
||||
RGB color_red = { 0, 0xFF, 0x00, 0x00 };
|
||||
RGB color_blue = { 0, 0x00, 0x00, 0xFF };
|
||||
RGB color_green = { 0, 0x00, 0xFF, 0x00 };
|
||||
RGB color_yellow = { 0, 0xFF, 0xFF, 0x00 };
|
||||
RGB color_cyan = { 0, 0x00, 0xFF, 0xFF };
|
||||
RGB color_magenta = { 0, 0xFF, 0x00, 0xFF };
|
||||
RGB color_orange = { 0, 0xFF, 0xA5, 0x00 };
|
||||
RGB color_purple = { 0, 0x80, 0x00, 0x80 };
|
||||
RGB color_gray = { 0, 0x80, 0x80, 0x80 };
|
||||
RGB color_lightgray = { 0, 0xD3, 0xD3, 0xD3 };
|
||||
RGB color_darkgray = { 0, 0x40, 0x40, 0x40 };
|
||||
RGB color_brown = { 0, 0xA5, 0x2A, 0x2A };
|
||||
RGB color_pink = { 0, 0xFF, 0xC0, 0xCB };
|
||||
RGB color_gold = { 0, 0xFF, 0xD7, 0x00 };
|
||||
RGB color_silver = { 0, 0xC0, 0xC0, 0xC0 };
|
||||
|
||||
static void framebuffer_init(void);
|
||||
static void tli_config(RGB *blackground_color);
|
||||
static void tli_gpio_config(void);
|
||||
|
||||
rt_err_t drv_lcd_init(rt_device_t dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t drv_lcd_open(rt_device_t dev, rt_uint16_t oflag)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t drv_lcd_close(rt_device_t dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_ssize_t drv_lcd_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_ssize_t drv_lcd_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t drv_lcd_control(struct rt_device *device, int cmd, void *args)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case RTGRAPHIC_CTRL_GET_INFO:
|
||||
{
|
||||
struct rt_device_graphic_info *info = (struct rt_device_graphic_info *)args;
|
||||
|
||||
RT_ASSERT(info != RT_NULL);
|
||||
info->pixel_format = _lcd.lcd_info.pixel_format;
|
||||
info->bits_per_pixel = _lcd.lcd_info.bits_per_pixel;
|
||||
info->width = _lcd.lcd_info.width;
|
||||
info->height = _lcd.lcd_info.height;
|
||||
info->framebuffer = _lcd.lcd_info.framebuffer;
|
||||
}
|
||||
break;
|
||||
case RTGRAPHIC_CTRL_RECT_UPDATE:
|
||||
tli_reload_config(TLI_REQUEST_RELOAD_EN);
|
||||
break;
|
||||
default:
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int hw_drv_lcd_init(void)
|
||||
{
|
||||
// malloc frame buffer
|
||||
frame_buffer = rt_malloc(ACTIVE_WIDTH * ACTIVE_HEIGHT * PRE_PIXEL_BYTES);
|
||||
framebuffer_init();
|
||||
|
||||
_lcd.parent.type = RT_Device_Class_Graphic;
|
||||
_lcd.parent.init = drv_lcd_init;
|
||||
_lcd.parent.open = drv_lcd_open;
|
||||
_lcd.parent.close = drv_lcd_close;
|
||||
_lcd.parent.read = drv_lcd_read;
|
||||
_lcd.parent.write = drv_lcd_write;
|
||||
_lcd.parent.control = drv_lcd_control;
|
||||
|
||||
_lcd.lcd_info.framebuffer = (rt_uint8_t *)frame_buffer;
|
||||
_lcd.lcd_info.width = LCD_WIGHT;
|
||||
_lcd.lcd_info.height = LCD_HIGHT;
|
||||
_lcd.lcd_info.bits_per_pixel = PRE_PIXEL_BYTES * 8;
|
||||
_lcd.lcd_info.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565;
|
||||
|
||||
/* configure TLI peripheral */
|
||||
tli_config(&color_write);
|
||||
|
||||
/* enable TLI layers */
|
||||
tli_layer_enable(LAYER0);
|
||||
tli_reload_config(TLI_REQUEST_RELOAD_EN);
|
||||
/* enable TLI */
|
||||
tli_enable();
|
||||
|
||||
rt_device_register(&_lcd.parent, "lcd", RT_DEVICE_FLAG_RDWR);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
INIT_APP_EXPORT(hw_drv_lcd_init);
|
||||
|
||||
static void framebuffer_init(void)
|
||||
{
|
||||
for (uint32_t y = 0; y < ACTIVE_HEIGHT; ++y)
|
||||
{
|
||||
for (uint32_t x = 0; x < ACTIVE_WIDTH; ++x)
|
||||
{
|
||||
frame_buffer[y * ACTIVE_WIDTH + x] = 0xFFFF;
|
||||
}
|
||||
}
|
||||
SCB_CleanInvalidateDCache();
|
||||
}
|
||||
|
||||
static void tli_gpio_config(void)
|
||||
{
|
||||
/* enable GPIO clock */
|
||||
rcu_periph_clock_enable(RCU_GPIOA);
|
||||
rcu_periph_clock_enable(RCU_GPIOB);
|
||||
rcu_periph_clock_enable(RCU_GPIOC);
|
||||
rcu_periph_clock_enable(RCU_GPIOD);
|
||||
rcu_periph_clock_enable(RCU_GPIOE);
|
||||
rcu_periph_clock_enable(RCU_GPIOF);
|
||||
rcu_periph_clock_enable(RCU_GPIOH);
|
||||
rcu_periph_clock_enable(RCU_GPIOG);
|
||||
|
||||
/* configure HSYNC(PE15), VSYNC(PA7), PCLK(PG7) */
|
||||
gpio_af_set(GPIOE, GPIO_AF_10, GPIO_PIN_15);
|
||||
gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_7);
|
||||
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_7);
|
||||
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_15);
|
||||
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_15);
|
||||
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_7);
|
||||
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_7);
|
||||
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_7);
|
||||
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_7);
|
||||
|
||||
/* configure LCD_R7(PG6), LCD_R6(PH12), LCD_R5(PH11), LCD_R4(PA5), LCD_R3(PH9),LCD_R2(PH8),
|
||||
LCD_R1(PH3), LCD_R0(PH2) */
|
||||
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_6);
|
||||
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_12);
|
||||
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_11);
|
||||
gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_5);
|
||||
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_9);
|
||||
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_8);
|
||||
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_3);
|
||||
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_2);
|
||||
|
||||
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6);
|
||||
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_6);
|
||||
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_12);
|
||||
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_12);
|
||||
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11);
|
||||
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_11);
|
||||
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
|
||||
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_5);
|
||||
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_9);
|
||||
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_9);
|
||||
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_8);
|
||||
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_8);
|
||||
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
|
||||
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_3);
|
||||
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_2);
|
||||
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_2);
|
||||
|
||||
/* configure LCD_G7(PD3), LCD_G6(PC7), LCD_G5(PC1), LCD_G4(PH15), LCD_G3(PH14), LCD_G2(PH13),LCD_G1(PB0), LCD_G0(PB1) */
|
||||
gpio_af_set(GPIOD, GPIO_AF_14, GPIO_PIN_3);
|
||||
gpio_af_set(GPIOC, GPIO_AF_14, GPIO_PIN_7);
|
||||
gpio_af_set(GPIOC, GPIO_AF_14, GPIO_PIN_1);
|
||||
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_15);
|
||||
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_14);
|
||||
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_13);
|
||||
gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_0);
|
||||
gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_1);
|
||||
|
||||
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
|
||||
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_3);
|
||||
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_7);
|
||||
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_7);
|
||||
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1);
|
||||
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_1);
|
||||
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_15);
|
||||
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_15);
|
||||
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14);
|
||||
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_14);
|
||||
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13);
|
||||
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_13);
|
||||
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0);
|
||||
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_0);
|
||||
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1);
|
||||
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_1);
|
||||
|
||||
/* configure LCD_B7(PB9), LCD_B6(PB8), LCD_B5(PB5), LCD_B4(PC11), LCD_B3(PG11),LCD_B2(PG10), LCD_B1(PG12), LCD_B0(PG14) */
|
||||
gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_9);
|
||||
gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_8);
|
||||
gpio_af_set(GPIOB, GPIO_AF_3, GPIO_PIN_5);
|
||||
gpio_af_set(GPIOC, GPIO_AF_14, GPIO_PIN_11);
|
||||
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_11);
|
||||
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_10);
|
||||
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_12);
|
||||
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_14);
|
||||
|
||||
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_9);
|
||||
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_9);
|
||||
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_8);
|
||||
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_8);
|
||||
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
|
||||
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_5);
|
||||
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11);
|
||||
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_11);
|
||||
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11);
|
||||
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_11);
|
||||
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10);
|
||||
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_10);
|
||||
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_12);
|
||||
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_12);
|
||||
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14);
|
||||
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_14);
|
||||
|
||||
/* configure LCD_DE(PF10) */
|
||||
gpio_af_set(GPIOF, GPIO_AF_14, GPIO_PIN_10);
|
||||
gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10);
|
||||
gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_10);
|
||||
/* LCD PWM BackLight(PG13) */
|
||||
gpio_mode_set(GPIOG, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_13);
|
||||
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_13);
|
||||
gpio_bit_set(GPIOG, GPIO_PIN_13);
|
||||
}
|
||||
|
||||
static void tli_config(RGB *blackground_color)
|
||||
{
|
||||
tli_parameter_struct tli_init_struct;
|
||||
tli_layer_parameter_struct tli_layer_init_struct;
|
||||
|
||||
rcu_periph_clock_enable(RCU_TLI);
|
||||
tli_gpio_config();
|
||||
|
||||
rcu_pll_input_output_clock_range_config(IDX_PLL2, RCU_PLL2RNG_1M_2M, RCU_PLL2VCO_192M_836M);
|
||||
if (ERROR == rcu_pll2_config(25, 192, 3, 3, 3))
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
rcu_pll_clock_output_enable(RCU_PLL2R);
|
||||
rcu_tli_clock_div_config(RCU_PLL2R_DIV8);
|
||||
|
||||
rcu_osci_on(RCU_PLL2_CK);
|
||||
|
||||
if (ERROR == rcu_osci_stab_wait(RCU_PLL2_CK))
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/* configure TLI parameter struct */
|
||||
tli_init_struct.signalpolarity_hs = TLI_HSYN_ACTLIVE_LOW;
|
||||
tli_init_struct.signalpolarity_vs = TLI_VSYN_ACTLIVE_LOW;
|
||||
tli_init_struct.signalpolarity_de = TLI_DE_ACTLIVE_LOW;
|
||||
tli_init_struct.signalpolarity_pixelck = TLI_PIXEL_CLOCK_TLI;
|
||||
|
||||
/* LCD display timing configuration */
|
||||
tli_init_struct.synpsz_hpsz = HORIZONTAL_SYNCHRONOUS_PULSE - 1;
|
||||
tli_init_struct.synpsz_vpsz = VERTICAL_SYNCHRONOUS_PULSE - 1;
|
||||
tli_init_struct.backpsz_hbpsz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH - 1;
|
||||
tli_init_struct.backpsz_vbpsz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH - 1;
|
||||
tli_init_struct.activesz_hasz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH + ACTIVE_WIDTH - 1;
|
||||
tli_init_struct.activesz_vasz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH + ACTIVE_HEIGHT -
|
||||
1;
|
||||
tli_init_struct.totalsz_htsz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH + ACTIVE_WIDTH +
|
||||
HORIZONTAL_FRONT_PORCH - 1;
|
||||
tli_init_struct.totalsz_vtsz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH + ACTIVE_HEIGHT +
|
||||
VERTICAL_FRONT_PORCH - 1;
|
||||
/* configure LCD background R,G,B values */
|
||||
tli_init_struct.backcolor_red = blackground_color->R;
|
||||
tli_init_struct.backcolor_green = blackground_color->G;
|
||||
tli_init_struct.backcolor_blue = blackground_color->B;
|
||||
tli_init(&tli_init_struct);
|
||||
|
||||
/* TLI layer configuration */
|
||||
tli_layer_init_struct.layer_window_leftpos = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH;
|
||||
tli_layer_init_struct.layer_window_rightpos = (480 + HORIZONTAL_SYNCHRONOUS_PULSE +
|
||||
HORIZONTAL_BACK_PORCH - 1);
|
||||
tli_layer_init_struct.layer_window_toppos = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH;
|
||||
tli_layer_init_struct.layer_window_bottompos = (272 + VERTICAL_SYNCHRONOUS_PULSE +
|
||||
VERTICAL_BACK_PORCH - 1);
|
||||
tli_layer_init_struct.layer_ppf = LAYER_PPF_RGB565;
|
||||
tli_layer_init_struct.layer_sa = 255;
|
||||
tli_layer_init_struct.layer_default_blue = 0x0;
|
||||
tli_layer_init_struct.layer_default_green = 0x0;
|
||||
tli_layer_init_struct.layer_default_red = 0x0;
|
||||
tli_layer_init_struct.layer_default_alpha = 0x00;
|
||||
tli_layer_init_struct.layer_acf1 = LAYER_ACF1_SA;
|
||||
tli_layer_init_struct.layer_acf2 = LAYER_ACF2_SA;
|
||||
tli_layer_init_struct.layer_frame_bufaddr = (uint32_t)frame_buffer;
|
||||
tli_layer_init_struct.layer_frame_line_length = ((480 * 2) + 7);
|
||||
tli_layer_init_struct.layer_frame_buf_stride_offset = (480 * 2);
|
||||
tli_layer_init_struct.layer_frame_total_line_number = 272;
|
||||
tli_layer_init(LAYER0, &tli_layer_init_struct);
|
||||
}
|
||||
|
||||
void lcd_draw_picture(uint32_t picture_addr, uint32_t picture_width, uint32_t picture_height, uint32_t picture_x, uint32_t picture_y)
|
||||
{
|
||||
ipa_destination_parameter_struct ipa_destination_init_struct;
|
||||
ipa_foreground_parameter_struct ipa_fg_init_struct;
|
||||
|
||||
uint16_t *_address = &frame_buffer[picture_y * ACTIVE_WIDTH + picture_x];
|
||||
uint32_t line_offset = ACTIVE_WIDTH - picture_width;
|
||||
|
||||
rcu_periph_clock_enable(RCU_IPA);
|
||||
|
||||
ipa_deinit();
|
||||
/* configure IPA pixel format convert mode */
|
||||
ipa_pixel_format_convert_mode_set(IPA_FGTODE);
|
||||
/* configure destination pixel format */
|
||||
ipa_destination_init_struct.destination_pf = IPA_DPF_RGB565;
|
||||
/* configure destination memory base address */
|
||||
ipa_destination_init_struct.destination_memaddr = (uint32_t)_address;
|
||||
/* configure destination pre-defined alpha value RGB */
|
||||
ipa_destination_init_struct.destination_pregreen = 0;
|
||||
ipa_destination_init_struct.destination_preblue = 0;
|
||||
ipa_destination_init_struct.destination_prered = 0;
|
||||
ipa_destination_init_struct.destination_prealpha = 0;
|
||||
/* configure destination line offset */
|
||||
ipa_destination_init_struct.destination_lineoff = line_offset;
|
||||
/* configure height of the image to be processed */
|
||||
ipa_destination_init_struct.image_height = picture_height;
|
||||
/* configure width of the image to be processed */
|
||||
ipa_destination_init_struct.image_width = picture_width;
|
||||
ipa_destination_init_struct.image_rotate = DESTINATION_ROTATE_0;
|
||||
ipa_destination_init_struct.image_hor_decimation = DESTINATION_HORDECIMATE_DISABLE;
|
||||
ipa_destination_init_struct.image_ver_decimation = DESTINATION_VERDECIMATE_DISABLE;
|
||||
/* IPA destination initialization */
|
||||
ipa_destination_init(&ipa_destination_init_struct);
|
||||
|
||||
/* configure IPA foreground */
|
||||
ipa_fg_init_struct.foreground_memaddr = picture_addr;
|
||||
ipa_fg_init_struct.foreground_pf = FOREGROUND_PPF_RGB565;
|
||||
ipa_fg_init_struct.foreground_alpha_algorithm = IPA_FG_ALPHA_MODE_0;
|
||||
ipa_fg_init_struct.foreground_prealpha = 0x0;
|
||||
ipa_fg_init_struct.foreground_lineoff = 0x0;
|
||||
ipa_fg_init_struct.foreground_preblue = 0x0;
|
||||
ipa_fg_init_struct.foreground_pregreen = 0x0;
|
||||
ipa_fg_init_struct.foreground_prered = 0x0;
|
||||
/* foreground initialization */
|
||||
ipa_foreground_init(&ipa_fg_init_struct);
|
||||
|
||||
/* start transfer */
|
||||
ipa_transfer_enable();
|
||||
while (RESET == ipa_interrupt_flag_get(IPA_INT_FLAG_FTF))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_draw_point(uint32_t point_x, uint32_t point_y, RGB *color)
|
||||
{
|
||||
frame_buffer[point_y * ACTIVE_WIDTH + point_x] = to_RGB565(color);
|
||||
}
|
||||
|
||||
uint32_t to_RGB565(RGB *color)
|
||||
{
|
||||
uint32_t res = ((uint32_t)(color->R & 0xF8) << 8) | ((uint32_t)(color->G & 0xFC) << 3) | ((uint32_t)(color->B & 0xF8) >> 3);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* RT_USING_LCD */
|
||||
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-06-05 zengjianwei first version
|
||||
* 2025-06-23 Yucai Liu Support for non-complementary PWM output with advanced timers
|
||||
* 2025-10-11 kurisaw compatible with RT-Studio
|
||||
*/
|
||||
|
||||
#include "drv_pwm.h"
|
||||
#include "pwm_config.h"
|
||||
|
||||
#ifdef RT_USING_PWM
|
||||
|
||||
#define DBG_TAG "drv.pwm"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define MAX_PERIOD 65535
|
||||
#define MIN_PERIOD 3
|
||||
#define MIN_PULSE 2
|
||||
|
||||
static struct gd32_pwm gd32_pwm_obj[] = {
|
||||
|
||||
#ifdef BSP_USING_PWM0
|
||||
PWM0_CONFIG,
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_PWM1
|
||||
PWM1_CONFIG,
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_PWM2
|
||||
PWM2_CONFIG,
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_PWM3
|
||||
PWM3_CONFIG,
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_PWM4
|
||||
PWM4_CONFIG,
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_PWM5
|
||||
PWM5_CONFIG,
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_PWM6
|
||||
PWM6_CONFIG,
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_PWM7
|
||||
PWM7_CONFIG,
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rt_uint32_t timer_periph;
|
||||
rt_bool_t initialized;
|
||||
} TIMER_INIT_STATUS;
|
||||
|
||||
static TIMER_INIT_STATUS timer_init_status[] = {
|
||||
{ TIMER0, RT_FALSE },
|
||||
{ TIMER1, RT_FALSE },
|
||||
{ TIMER2, RT_FALSE },
|
||||
{ TIMER3, RT_FALSE },
|
||||
{ TIMER4, RT_FALSE },
|
||||
{ TIMER5, RT_FALSE },
|
||||
{ TIMER6, RT_FALSE },
|
||||
{ TIMER7, RT_FALSE },
|
||||
};
|
||||
|
||||
static void gd32_pwm_init(struct gd32_pwm *gd32_pwm)
|
||||
{
|
||||
rt_uint32_t pwm_port, pwm_pin;
|
||||
rcu_periph_enum pwm_periph;
|
||||
rt_uint32_t pin_af;
|
||||
|
||||
if (get_pin_config(gd32_pwm->pin_name, &pwm_port, &pwm_pin, &pwm_periph) == -RT_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pin_alternate_config(gd32_pwm->alternate, &pin_af);
|
||||
|
||||
/* enable timer clock */
|
||||
rcu_periph_clock_enable(gd32_pwm->timer_clk);
|
||||
rcu_periph_clock_enable(pwm_periph);
|
||||
|
||||
/* GPIO pin configuration */
|
||||
gpio_af_set(pwm_port, pin_af, pwm_pin);
|
||||
gpio_mode_set(pwm_port, GPIO_MODE_AF, GPIO_PUPD_NONE, pwm_pin);
|
||||
#if defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E)
|
||||
gpio_output_options_set(pwm_port, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, pwm_pin);
|
||||
#else
|
||||
gpio_output_options_set(pwm_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, pwm_pin);
|
||||
#endif
|
||||
}
|
||||
|
||||
static rt_err_t drv_pwm_enable(struct gd32_pwm *pwm_dev, struct rt_pwm_configuration *configuration, rt_bool_t enable)
|
||||
{
|
||||
if (!enable)
|
||||
{
|
||||
timer_channel_output_state_config(pwm_dev->timer_periph, configuration->channel, TIMER_CCX_DISABLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (configuration->complementary == RT_TRUE)
|
||||
{
|
||||
timer_channel_output_state_config(pwm_dev->timer_periph, configuration->channel - 1, TIMER_CCXN_ENABLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
timer_channel_output_state_config(pwm_dev->timer_periph, configuration->channel, TIMER_CCX_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t drv_pwm_get(struct gd32_pwm *pwm_dev, struct rt_pwm_configuration *configuration)
|
||||
{
|
||||
rt_uint64_t tim_clock;
|
||||
rt_uint16_t psc;
|
||||
rt_uint32_t chxcv;
|
||||
|
||||
tim_clock = rcu_clock_freq_get(CK_SYS);
|
||||
|
||||
psc = timer_prescaler_read(pwm_dev->timer_periph);
|
||||
if (psc == TIMER_CKDIV_DIV2)
|
||||
{
|
||||
tim_clock = tim_clock / 2;
|
||||
}
|
||||
else if (psc == TIMER_CKDIV_DIV4)
|
||||
{
|
||||
tim_clock = tim_clock / 4;
|
||||
}
|
||||
|
||||
chxcv = timer_channel_capture_value_register_read(pwm_dev->timer_periph, configuration->channel);
|
||||
/* Convert nanosecond to frequency and duty cycle. 1s = 1 * 1000 * 1000 * 1000 ns */
|
||||
tim_clock /= 1000000UL;
|
||||
configuration->period = (TIMER_CAR(pwm_dev->timer_periph) + 1) * (psc + 1) * 1000UL / tim_clock;
|
||||
configuration->pulse = (chxcv + 1) * (psc + 1) * 1000UL / tim_clock;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t drv_pwm_set(struct gd32_pwm *pwm_dev, struct rt_pwm_configuration *configuration)
|
||||
{
|
||||
rt_uint32_t period, pulse;
|
||||
rt_uint64_t tim_clock, psc;
|
||||
|
||||
tim_clock = rcu_clock_freq_get(CK_SYS);
|
||||
|
||||
/* Convert nanosecond to frequency and duty cycle. 1s = 1 * 1000 * 1000 * 1000 ns */
|
||||
tim_clock /= 1000000UL;
|
||||
period = (unsigned long long)configuration->period * tim_clock / 1000ULL;
|
||||
psc = period / MAX_PERIOD + 1;
|
||||
period = period / psc;
|
||||
|
||||
timer_prescaler_config(pwm_dev->timer_periph, psc - 1, TIMER_PSC_RELOAD_NOW);
|
||||
|
||||
if (period < MIN_PERIOD)
|
||||
{
|
||||
period = MIN_PERIOD;
|
||||
}
|
||||
|
||||
timer_autoreload_value_config(pwm_dev->timer_periph, period - 1);
|
||||
|
||||
pulse = (unsigned long long)configuration->pulse * tim_clock / psc / 1000ULL;
|
||||
if (pulse < MIN_PULSE)
|
||||
{
|
||||
pulse = MIN_PULSE;
|
||||
}
|
||||
else if (pulse > period)
|
||||
{
|
||||
pulse = period;
|
||||
}
|
||||
|
||||
timer_channel_output_pulse_value_config(pwm_dev->timer_periph, configuration->channel, pulse);
|
||||
timer_counter_value_config(pwm_dev->timer_periph, 0);
|
||||
|
||||
/* Update frequency value */
|
||||
timer_event_software_generate(pwm_dev->timer_periph, TIMER_EVENT_SRC_UPG);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
|
||||
{
|
||||
struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
|
||||
struct gd32_pwm *pwm_dev = (struct gd32_pwm *)device;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case PWM_CMD_ENABLE:
|
||||
return drv_pwm_enable(pwm_dev, configuration, RT_TRUE);
|
||||
case PWM_CMD_DISABLE:
|
||||
return drv_pwm_enable(pwm_dev, configuration, RT_FALSE);
|
||||
case PWM_CMD_SET:
|
||||
return drv_pwm_set(pwm_dev, configuration);
|
||||
case PWM_CMD_GET:
|
||||
return drv_pwm_get(pwm_dev, configuration);
|
||||
default:
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static struct rt_pwm_ops drv_ops = {
|
||||
.control = drv_pwm_control
|
||||
};
|
||||
|
||||
static void timer_initialize(uint32_t timer_periph)
|
||||
{
|
||||
timer_oc_parameter_struct timer_ocintpara;
|
||||
timer_parameter_struct timer_initpara;
|
||||
|
||||
/* Check if timer is already initialized */
|
||||
for (int i = 0; i < sizeof(timer_init_status) / sizeof(timer_init_status[0]); i++)
|
||||
{
|
||||
if (timer_init_status[i].timer_periph == timer_periph && !timer_init_status[i].initialized)
|
||||
{
|
||||
/* TIMER configuration */
|
||||
timer_initpara.prescaler = 119;
|
||||
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
|
||||
timer_initpara.counterdirection = TIMER_COUNTER_UP;
|
||||
timer_initpara.period = 15999;
|
||||
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
|
||||
timer_initpara.repetitioncounter = 0;
|
||||
timer_init(timer_periph, &timer_initpara);
|
||||
|
||||
/* CHX configuration in PWM mode */
|
||||
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
|
||||
timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
|
||||
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
|
||||
timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
|
||||
timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
|
||||
timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
|
||||
timer_channel_output_config(gd32_pwm_obj[i].timer_periph, gd32_pwm_obj[i].channel, &timer_ocintpara);
|
||||
|
||||
timer_init_status[i].initialized = RT_TRUE;
|
||||
|
||||
/* Configure channel output */
|
||||
timer_channel_output_pulse_value_config(gd32_pwm_obj[i].timer_periph,
|
||||
gd32_pwm_obj[i].channel, 7999);
|
||||
timer_channel_output_mode_config(gd32_pwm_obj[i].timer_periph,
|
||||
gd32_pwm_obj[i].channel, TIMER_OC_MODE_PWM0);
|
||||
timer_channel_output_shadow_config(gd32_pwm_obj[i].timer_periph,
|
||||
gd32_pwm_obj[i].channel, TIMER_OC_SHADOW_DISABLE);
|
||||
|
||||
/* Enable timer */
|
||||
timer_primary_output_config(timer_periph, ENABLE);
|
||||
/* auto-reload preload enable */
|
||||
timer_auto_reload_shadow_enable(gd32_pwm_obj[i].timer_periph);
|
||||
timer_enable(timer_periph);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int drv_pwm_init(void)
|
||||
{
|
||||
int i, result = RT_EOK;
|
||||
|
||||
for (i = 0; i < sizeof(gd32_pwm_obj) / sizeof(gd32_pwm_obj[0]); i++)
|
||||
{
|
||||
/* Initialize PWM hardware */
|
||||
gd32_pwm_init(&gd32_pwm_obj[i]);
|
||||
|
||||
/* Initialize timer if not already initialized */
|
||||
timer_initialize(gd32_pwm_obj[i].timer_periph);
|
||||
|
||||
/* Register PWM device */
|
||||
if (rt_device_pwm_register(&gd32_pwm_obj[i].pwm_device, gd32_pwm_obj[i].name,
|
||||
&drv_ops, RT_NULL) == RT_EOK)
|
||||
{
|
||||
LOG_D("%s register success", gd32_pwm_obj[i].name);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("%s register failed", gd32_pwm_obj[i].name);
|
||||
result = -RT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
INIT_DEVICE_EXPORT(drv_pwm_init);
|
||||
|
||||
#endif /* RT_USING_PWM */
|
||||
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-01-25 iysheng first version
|
||||
* 2025-09-25 kurisaw adapt to rt_rtc_ops interface
|
||||
* 2025-09-25 kurisaw add alarm interrupt support
|
||||
*/
|
||||
|
||||
#include <board.h>
|
||||
#include <rtdevice.h>
|
||||
#include <rthw.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define DBG_TAG "drv.rtc"
|
||||
#define DBG_LVL DBG_LOG
|
||||
#include <rtdbg.h>
|
||||
|
||||
#ifdef RT_USING_RTC
|
||||
|
||||
#if defined(RT_USING_ALARM)
|
||||
#if defined(BSP_USING_ALARM0) && defined(BSP_USING_ALARM1)
|
||||
#error "Only supports using one alarm at a time."
|
||||
#elif !defined(BSP_USING_ALARM0) && !defined(BSP_USING_ALARM1)
|
||||
#error "Please Enable RTC alarm define (BSP_USING_ALARM0 | BSP_USING_ALARM1)"
|
||||
#elif defined(BSP_USING_ALARM0)
|
||||
#define BSP_ALARM_FLAG RTC_FLAG_ALARM0
|
||||
#define BSP_RTC_ALARM RTC_ALARM0
|
||||
#define BSP_RTC_INT_ALARM RTC_INT_ALARM0
|
||||
#elif defined(BSP_USING_ALARM1)
|
||||
#define BSP_ALARM_FLAG RTC_FLAG_ALARM1
|
||||
#define BSP_RTC_ALARM RTC_ALARM1
|
||||
#define BSP_RTC_INT_ALARM RTC_INT_ALARM1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E)
|
||||
|
||||
#define rtc_year year
|
||||
#define rtc_month month
|
||||
#define rtc_date date
|
||||
#define rtc_day_of_week day_of_week
|
||||
#define rtc_hour hour
|
||||
#define rtc_minute minute
|
||||
#define rtc_second second
|
||||
#define rtc_display_format display_format
|
||||
|
||||
#endif
|
||||
|
||||
static time_t get_rtc_timestamp(void);
|
||||
static rt_err_t set_rtc_timestamp(time_t time_stamp);
|
||||
|
||||
/**
|
||||
* @brief Helper function: Convert BCD value to binary.
|
||||
* @param val: BCD value.
|
||||
* @return Binary value.
|
||||
*/
|
||||
static rt_uint8_t bcd_to_bin(rt_uint8_t val)
|
||||
{
|
||||
return (val & 0x0F) + ((val >> 4) & 0x0F) * 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function: Convert binary to BCD.
|
||||
* @param val: Binary value.
|
||||
* @return BCD value.
|
||||
*/
|
||||
static rt_uint8_t bin_to_bcd(rt_uint8_t val)
|
||||
{
|
||||
return ((val / 10) << 4) | (val % 10);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_ALARM
|
||||
/* RTC device for alarm callback */
|
||||
static rt_device_t g_rtc_device = RT_NULL;
|
||||
|
||||
/**
|
||||
* @brief RTC Alarm Interrupt Handler
|
||||
*/
|
||||
void RTC_Alarm_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
|
||||
/* Check if alarm interrupt occurred */
|
||||
if (rtc_flag_get(RTC_FLAG_ALARM0) != RESET)
|
||||
{
|
||||
/* Clear alarm flag */
|
||||
rtc_flag_clear(RTC_FLAG_ALARM0);
|
||||
exti_flag_clear(EXTI_17);
|
||||
|
||||
/* Notify RTC framework about alarm event */
|
||||
if (g_rtc_device != RT_NULL)
|
||||
{
|
||||
rt_alarm_update(g_rtc_device, 1);
|
||||
}
|
||||
LOG_D("RTC Alarm0 triggered");
|
||||
}
|
||||
|
||||
if (rtc_flag_get(RTC_FLAG_ALARM1) != RESET)
|
||||
{
|
||||
/* Clear alarm flag */
|
||||
rtc_flag_clear(RTC_FLAG_ALARM1);
|
||||
exti_flag_clear(EXTI_17);
|
||||
|
||||
/* Notify RTC framework about alarm event */
|
||||
if (g_rtc_device != RT_NULL)
|
||||
{
|
||||
rt_alarm_update(g_rtc_device, 1);
|
||||
}
|
||||
LOG_D("RTC Alarm1 triggered");
|
||||
}
|
||||
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif /* RT_USING_ALARM */
|
||||
|
||||
static rt_err_t gd_rtc_init(void)
|
||||
{
|
||||
/* Enable PMU and backup domain clocks */
|
||||
rcu_periph_clock_enable(RCU_PMU);
|
||||
pmu_backup_write_enable();
|
||||
|
||||
/* Enable BKP and RTC clocks */
|
||||
#ifdef SOC_SERIES_GD32F10x
|
||||
rcu_periph_clock_enable(RCU_BKPI);
|
||||
#else
|
||||
rcu_periph_clock_enable(RCU_RTC);
|
||||
#endif
|
||||
|
||||
/* Check if RTC is already initialized by backup domain reset */
|
||||
if (RTC_STAT & RTC_STAT_INITF)
|
||||
{
|
||||
LOG_D("RTC already initialized");
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/* Reset backup domain only if RTC is not running */
|
||||
if ((RTC_STAT & RTC_STAT_RSYNF) == 0)
|
||||
{
|
||||
rcu_bkp_reset_enable();
|
||||
rcu_bkp_reset_disable();
|
||||
|
||||
/* Re-enable clocks after reset */
|
||||
#ifdef SOC_SERIES_GD32F10x
|
||||
rcu_periph_clock_enable(RCU_BKPI);
|
||||
#else
|
||||
rcu_periph_clock_enable(RCU_RTC);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Use LSE (32.768kHz) as RTC clock source */
|
||||
#define PRESCALER_S 0xFF
|
||||
#define PRESCALER_A 0x7F
|
||||
|
||||
rcu_osci_on(RCU_LXTAL);
|
||||
if (rcu_osci_stab_wait(RCU_LXTAL) != SUCCESS)
|
||||
{
|
||||
LOG_E("LSE oscillator failed to stabilize");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
|
||||
LOG_D("RTC clock source: LSE (32.768kHz)");
|
||||
|
||||
/* Wait for RTC registers synchronization */
|
||||
if (rtc_register_sync_wait() != SUCCESS)
|
||||
{
|
||||
LOG_E("RTC register synchronization failed");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/* Set default time if RTC is not initialized */
|
||||
if ((RTC_DATE == 0) || (RTC_TIME == 0))
|
||||
{
|
||||
time_t default_time = 1704067200; /* 2024-01-01 00:00:00 */
|
||||
if (set_rtc_timestamp(default_time) != RT_EOK)
|
||||
{
|
||||
LOG_E("Failed to set default RTC time");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
LOG_D("RTC set to default time: 2024-01-01 00:00:00");
|
||||
}
|
||||
|
||||
LOG_D("RTC initialization successful");
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static time_t get_rtc_timestamp(void)
|
||||
{
|
||||
struct tm tm_new = {0};
|
||||
rtc_parameter_struct rtc_current_time;
|
||||
|
||||
/* Wait for register synchronization before reading */
|
||||
if (rtc_register_sync_wait() != SUCCESS)
|
||||
{
|
||||
LOG_E("RTC sync failed before reading time");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtc_current_time_get(&rtc_current_time);
|
||||
|
||||
/* Convert BCD to binary and adjust year/month values */
|
||||
tm_new.tm_year = bcd_to_bin(rtc_current_time.rtc_year) + 100; /* RTC year starts from 2000 */
|
||||
tm_new.tm_mon = bcd_to_bin(rtc_current_time.rtc_month) - 1; /* tm_mon: 0-11 */
|
||||
tm_new.tm_mday = bcd_to_bin(rtc_current_time.rtc_date);
|
||||
tm_new.tm_hour = bcd_to_bin(rtc_current_time.rtc_hour);
|
||||
tm_new.tm_min = bcd_to_bin(rtc_current_time.rtc_minute);
|
||||
tm_new.tm_sec = bcd_to_bin(rtc_current_time.rtc_second);
|
||||
|
||||
/* Convert weekday: RTC uses 1-7 (Monday-Sunday), tm uses 0-6 (Sunday-Saturday) */
|
||||
uint8_t rtc_wday = bcd_to_bin(rtc_current_time.rtc_day_of_week);
|
||||
tm_new.tm_wday = (rtc_wday == 7) ? 0 : rtc_wday; /* Sunday conversion */
|
||||
|
||||
/* Calculate day of year */
|
||||
tm_new.tm_yday = 0; /* Will be calculated by timegm */
|
||||
tm_new.tm_isdst = 0; /* No daylight saving */
|
||||
|
||||
/* Use timegm instead of mktime to avoid timezone issues */
|
||||
return timegm(&tm_new);
|
||||
}
|
||||
|
||||
static rt_err_t gd_get_secs(time_t *sec)
|
||||
{
|
||||
if (sec == RT_NULL)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
*sec = get_rtc_timestamp();
|
||||
LOG_D("RTC: get timestamp %lu", *sec);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t set_rtc_timestamp(time_t time_stamp)
|
||||
{
|
||||
struct tm now;
|
||||
rtc_parameter_struct rtc_init_struct;
|
||||
ErrStatus status;
|
||||
|
||||
/* Use gmtime_r for thread safety */
|
||||
gmtime_r(&time_stamp, &now);
|
||||
|
||||
if (now.tm_year < 100)
|
||||
{
|
||||
LOG_E("Year must be >= 2000");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/* Convert to BCD format */
|
||||
rtc_init_struct.rtc_year = bin_to_bcd(now.tm_year - 100); /* RTC year: 0-99 (2000-2099) */
|
||||
rtc_init_struct.rtc_month = bin_to_bcd(now.tm_mon + 1); /* RTC month: 1-12 */
|
||||
rtc_init_struct.rtc_date = bin_to_bcd(now.tm_mday);
|
||||
|
||||
/* Convert weekday: tm_wday 0-6 (Sun-Sat) to RTC 1-7 (Mon-Sun) */
|
||||
rtc_init_struct.rtc_day_of_week = bin_to_bcd(now.tm_wday == 0 ? 7 : now.tm_wday);
|
||||
|
||||
rtc_init_struct.rtc_hour = bin_to_bcd(now.tm_hour);
|
||||
rtc_init_struct.rtc_minute = bin_to_bcd(now.tm_min);
|
||||
rtc_init_struct.rtc_second = bin_to_bcd(now.tm_sec);
|
||||
rtc_init_struct.rtc_display_format = RTC_24HOUR;
|
||||
|
||||
/* Use default prescaler values */
|
||||
rtc_init_struct.factor_asyn = PRESCALER_A;
|
||||
rtc_init_struct.factor_syn = PRESCALER_S;
|
||||
rtc_init_struct.am_pm = RTC_AM;
|
||||
|
||||
status = rtc_init(&rtc_init_struct);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
LOG_E("RTC time set failed: %d", status);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/* Wait for synchronization after setting time */
|
||||
if (rtc_register_sync_wait() != SUCCESS)
|
||||
{
|
||||
LOG_E("RTC sync failed after setting time");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
LOG_D("RTC time set successfully: %lu", time_stamp);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t gd_set_secs(time_t *sec)
|
||||
{
|
||||
if (sec == RT_NULL)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
rt_err_t result = set_rtc_timestamp(*sec);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
LOG_D("RTC: set rtc_time %lu", *sec);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("RTC: set rtc_time failed %lu", *sec);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_ALARM
|
||||
static rt_err_t gd_get_alarm(struct rt_rtc_wkalarm *alarm)
|
||||
{
|
||||
if (alarm == RT_NULL)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
rtc_alarm_struct rtc_alarm;
|
||||
|
||||
/* Get current alarm configuration */
|
||||
rtc_alarm_get(BSP_RTC_ALARM, &rtc_alarm);
|
||||
|
||||
/* Convert RTC alarm to RT-Thread alarm format */
|
||||
alarm->tm_hour = bcd_to_bin(rtc_alarm.alarm_hour);
|
||||
alarm->tm_min = bcd_to_bin(rtc_alarm.alarm_minute);
|
||||
alarm->tm_sec = bcd_to_bin(rtc_alarm.alarm_second);
|
||||
|
||||
|
||||
/* Check if alarm is enabled */
|
||||
alarm->enable = (RTC_CTL & (BSP_RTC_ALARM == RTC_ALARM0 ? RTC_CTL_ALRM0EN : RTC_CTL_ALRM1EN)) ? 1 : 0;
|
||||
|
||||
LOG_D("RTC: get alarm %02d:%02d:%02d, enable: %d",
|
||||
alarm->tm_hour, alarm->tm_min, alarm->tm_sec, alarm->enable);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t gd_set_alarm(struct rt_rtc_wkalarm *alarm)
|
||||
{
|
||||
if (alarm == RT_NULL)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
rtc_alarm_struct rtc_alarm;
|
||||
|
||||
rtc_alarm_disable(BSP_RTC_ALARM);
|
||||
/* Initialize alarm structure */
|
||||
rtc_alarm.alarm_mask = RTC_ALARM_ALL_MASK;
|
||||
rtc_alarm.weekday_or_date = RTC_ALARM_DATE_SELECTED;
|
||||
rtc_alarm.alarm_day = 1; /* Not used when mask is set to ALL_MASK */
|
||||
rtc_alarm.alarm_hour = bin_to_bcd(alarm->tm_hour);
|
||||
rtc_alarm.alarm_minute = bin_to_bcd(alarm->tm_min);
|
||||
rtc_alarm.alarm_second = bin_to_bcd(alarm->tm_sec);
|
||||
rtc_alarm.am_pm = RTC_AM;
|
||||
|
||||
/* Configure alarm */
|
||||
rtc_alarm_config(BSP_RTC_ALARM, &rtc_alarm);
|
||||
|
||||
/* Enable or disable alarm */
|
||||
if (alarm->enable)
|
||||
{
|
||||
/* Clear any pending alarm flag first */
|
||||
rtc_flag_clear(BSP_ALARM_FLAG);
|
||||
|
||||
/* Clear EXTI line 17 flag */
|
||||
exti_flag_clear(EXTI_17);
|
||||
|
||||
/* Enable RTC alarm interrupt */
|
||||
rtc_interrupt_enable(BSP_RTC_INT_ALARM);
|
||||
|
||||
/* Enable alarm */
|
||||
rtc_alarm_enable(BSP_RTC_ALARM);
|
||||
|
||||
/* Configure EXTI line 17 for RTC alarm interrupt */
|
||||
exti_init(EXTI_17, EXTI_INTERRUPT, EXTI_TRIG_RISING);
|
||||
|
||||
/* Enable RTC Alarm global interrupt in NVIC */
|
||||
nvic_irq_enable(RTC_Alarm_IRQn, 0, 0);
|
||||
|
||||
LOG_D("RTC Alarm enabled with interrupt");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Disable alarm interrupt first */
|
||||
rtc_interrupt_disable(BSP_RTC_INT_ALARM);
|
||||
|
||||
/* Disable alarm */
|
||||
rtc_alarm_disable(BSP_RTC_ALARM);
|
||||
|
||||
/* Clear alarm flag */
|
||||
rtc_flag_clear(BSP_ALARM_FLAG);
|
||||
exti_flag_clear(EXTI_17);
|
||||
|
||||
LOG_D("RTC Alarm disabled");
|
||||
}
|
||||
|
||||
LOG_D("RTC: set alarm %02d:%02d:%02d, enable: %d",
|
||||
alarm->tm_hour, alarm->tm_min, alarm->tm_sec, alarm->enable);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
#endif /* RT_USING_ALARM */
|
||||
|
||||
static const struct rt_rtc_ops gd_rtc_ops =
|
||||
{
|
||||
.init = gd_rtc_init,
|
||||
.get_secs = gd_get_secs,
|
||||
.set_secs = gd_set_secs,
|
||||
#ifdef RT_USING_ALARM
|
||||
.set_alarm = gd_set_alarm,
|
||||
.get_alarm = gd_get_alarm,
|
||||
#endif
|
||||
};
|
||||
|
||||
static rt_rtc_dev_t gd_rtc_dev;
|
||||
|
||||
static int rt_hw_rtc_init(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
gd_rtc_dev.ops = &gd_rtc_ops;
|
||||
|
||||
result = rt_hw_rtc_register(&gd_rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR, RT_NULL);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
LOG_E("RTC register failed: %d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_ALARM
|
||||
/* Store RTC device for alarm callback */
|
||||
g_rtc_device = rt_device_find("rtc");
|
||||
if (g_rtc_device == RT_NULL)
|
||||
{
|
||||
LOG_W("RTC device not found for alarm callback");
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG_D("RTC hardware init success");
|
||||
return RT_EOK;
|
||||
}
|
||||
INIT_DEVICE_EXPORT(rt_hw_rtc_init);
|
||||
|
||||
#endif /* RT_USING_RTC */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,640 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-12-20 BruceOu first implementation
|
||||
* 2025-10-10 WangShun compatible with RT-Studio
|
||||
*/
|
||||
#include "drv_spi.h"
|
||||
#include "spi_config.h"
|
||||
|
||||
#ifdef RT_USING_SPI
|
||||
|
||||
#if defined(BSP_USING_SPI0) || defined(BSP_USING_SPI1) || defined(BSP_USING_SPI2) || defined(BSP_USING_SPI3) || defined(BSP_USING_SPI4) || defined(BSP_USING_SPI5)
|
||||
|
||||
#define DBG_TAG "drv.spi"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#ifdef BSP_USING_SPI0
|
||||
static struct rt_spi_bus spi_bus0;
|
||||
#endif
|
||||
#ifdef BSP_USING_SPI1
|
||||
static struct rt_spi_bus spi_bus1;
|
||||
#endif
|
||||
#ifdef BSP_USING_SPI2
|
||||
static struct rt_spi_bus spi_bus2;
|
||||
#endif
|
||||
#ifdef BSP_USING_SPI3
|
||||
static struct rt_spi_bus spi_bus3;
|
||||
#endif
|
||||
#ifdef BSP_USING_SPI4
|
||||
static struct rt_spi_bus spi_bus4;
|
||||
#endif
|
||||
#ifdef BSP_USING_SPI5
|
||||
static struct rt_spi_bus spi_bus5;
|
||||
#endif
|
||||
|
||||
#ifdef RT_SPI_USING_DMA
|
||||
gd32_spi_dma spi_dma[] = {
|
||||
|
||||
{
|
||||
DMA0,
|
||||
DMA_CH2,
|
||||
DMA_CH3,
|
||||
DMA_REQUEST_SPI0_TX,
|
||||
DMA_REQUEST_SPI0_RX,
|
||||
DMA_INTF_FTFIF,
|
||||
|
||||
0
|
||||
},
|
||||
|
||||
{
|
||||
DMA0,
|
||||
DMA_CH2,
|
||||
DMA_CH3,
|
||||
DMA_REQUEST_SPI1_TX,
|
||||
DMA_REQUEST_SPI1_RX,
|
||||
DMA_INTF_FTFIF,
|
||||
|
||||
0
|
||||
},
|
||||
|
||||
{
|
||||
DMA0,
|
||||
DMA_CH2,
|
||||
DMA_CH3,
|
||||
DMA_REQUEST_SPI2_TX,
|
||||
DMA_REQUEST_SPI2_RX,
|
||||
DMA_INTF_FTFIF,
|
||||
|
||||
0
|
||||
},
|
||||
|
||||
{
|
||||
DMA0,
|
||||
DMA_CH2,
|
||||
DMA_CH3,
|
||||
DMA_REQUEST_SPI3_TX,
|
||||
DMA_REQUEST_SPI3_RX,
|
||||
DMA_INTF_FTFIF,
|
||||
|
||||
0
|
||||
},
|
||||
|
||||
{
|
||||
DMA0,
|
||||
DMA_CH2,
|
||||
DMA_CH3,
|
||||
DMA_REQUEST_SPI4_TX,
|
||||
DMA_REQUEST_SPI4_RX,
|
||||
DMA_INTF_FTFIF,
|
||||
|
||||
0
|
||||
},
|
||||
|
||||
{
|
||||
DMA0,
|
||||
DMA_CH2,
|
||||
DMA_CH3,
|
||||
DMA_REQUEST_SPI5_TX,
|
||||
DMA_REQUEST_SPI5_RX,
|
||||
DMA_INTF_FTFIF,
|
||||
|
||||
0
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct gd32_spi spi_bus_obj[] = {
|
||||
#ifdef BSP_USING_SPI0
|
||||
SPI0_BUS_CONFIG,
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_SPI1
|
||||
SPI1_BUS_CONFIG,
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_SPI2
|
||||
SPI2_BUS_CONFIG,
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_SPI3
|
||||
SPI3_BUS_CONFIG,
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_SPI4
|
||||
SPI4_BUS_CONFIG,
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_SPI5
|
||||
SPI5_BUS_CONFIG,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* private rt-thread spi ops function */
|
||||
static rt_err_t spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
|
||||
static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message);
|
||||
|
||||
static struct rt_spi_ops gd32_spi_ops = {
|
||||
.configure = spi_configure,
|
||||
.xfer = spixfer,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief SPI Initialization
|
||||
* @param gd32_spi: SPI BUS
|
||||
* @retval None
|
||||
*/
|
||||
static void gd32_spi_init(struct gd32_spi *gd32_spi)
|
||||
{
|
||||
rt_uint32_t sck_port, miso_port, mosi_port;
|
||||
rt_uint32_t sck_pin, miso_pin, mosi_pin;
|
||||
rcu_periph_enum sck_periph, miso_periph, mosi_periph;
|
||||
rt_uint32_t pin_af;
|
||||
|
||||
if (get_pin_config(gd32_spi->sck_pin_name, &sck_port, &sck_pin, &sck_periph) == -RT_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_pin_config(gd32_spi->miso_pin_name, &miso_port, &miso_pin, &miso_periph) == -RT_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_pin_config(gd32_spi->mosi_pin_name, &mosi_port, &mosi_pin, &mosi_periph) == -RT_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pin_alternate_config(gd32_spi->alternate, &pin_af);
|
||||
|
||||
/* enable SPI clock */
|
||||
rcu_periph_clock_enable(gd32_spi->spi_clk);
|
||||
rcu_periph_clock_enable(sck_periph);
|
||||
rcu_periph_clock_enable(miso_periph);
|
||||
rcu_periph_clock_enable(mosi_periph);
|
||||
|
||||
/*GPIO pin configuration*/
|
||||
gpio_af_set(sck_port, pin_af, sck_pin);
|
||||
gpio_af_set(miso_port, pin_af, miso_pin);
|
||||
gpio_af_set(mosi_port, pin_af, mosi_pin);
|
||||
gpio_mode_set(sck_port, GPIO_MODE_AF, GPIO_PUPD_NONE, sck_pin);
|
||||
gpio_mode_set(miso_port, GPIO_MODE_AF, GPIO_PUPD_NONE, miso_pin);
|
||||
gpio_mode_set(mosi_port, GPIO_MODE_AF, GPIO_PUPD_NONE, mosi_pin);
|
||||
gpio_output_options_set(sck_port, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, sck_pin);
|
||||
gpio_output_options_set(miso_port, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, miso_pin);
|
||||
gpio_output_options_set(mosi_port, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, mosi_pin);
|
||||
}
|
||||
|
||||
static rt_err_t spi_configure(struct rt_spi_device *device,
|
||||
struct rt_spi_configuration *configuration)
|
||||
{
|
||||
struct rt_spi_bus *spi_bus = (struct rt_spi_bus *)device->bus;
|
||||
struct gd32_spi *spi_device = (struct gd32_spi *)spi_bus->parent.user_data;
|
||||
spi_parameter_struct spi_init_struct;
|
||||
uint32_t spi_periph = spi_device->spi_periph;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(configuration != RT_NULL);
|
||||
|
||||
/* Init SPI */
|
||||
gd32_spi_init(spi_device);
|
||||
|
||||
#if defined SOC_SERIES_GD32H7xx || defined(SOC_SERIES_GD32H75E)
|
||||
/* data_width */
|
||||
if (configuration->data_width >= 4 && configuration->data_width <= 32)
|
||||
{
|
||||
spi_init_struct.data_size = CFG0_DZ(configuration->data_width - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
#else
|
||||
/* data_width */
|
||||
if (configuration->data_width <= 8)
|
||||
{
|
||||
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
|
||||
}
|
||||
else if (configuration->data_width <= 16)
|
||||
{
|
||||
spi_init_struct.frame_size = SPI_FRAMESIZE_16BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* baudrate */
|
||||
{
|
||||
rcu_clock_freq_enum spi_src;
|
||||
uint32_t spi_apb_clock;
|
||||
uint32_t max_hz;
|
||||
|
||||
max_hz = configuration->max_hz;
|
||||
|
||||
LOG_D("sys freq: %d\n", rcu_clock_freq_get(CK_SYS));
|
||||
LOG_D("CK_APB2 freq: %d\n", rcu_clock_freq_get(CK_APB2));
|
||||
LOG_D("max freq: %d\n", max_hz);
|
||||
|
||||
#if defined SOC_SERIES_GD32E23x
|
||||
spi_src = CK_APB2;
|
||||
#else
|
||||
if (spi_periph == SPI1 || spi_periph == SPI2)
|
||||
{
|
||||
spi_src = CK_APB1;
|
||||
}
|
||||
else
|
||||
{
|
||||
spi_src = CK_APB2;
|
||||
}
|
||||
#endif
|
||||
spi_apb_clock = rcu_clock_freq_get(spi_src);
|
||||
|
||||
if (max_hz >= spi_apb_clock / 2)
|
||||
{
|
||||
spi_init_struct.prescale = SPI_PSC_2;
|
||||
}
|
||||
else if (max_hz >= spi_apb_clock / 4)
|
||||
{
|
||||
spi_init_struct.prescale = SPI_PSC_4;
|
||||
}
|
||||
else if (max_hz >= spi_apb_clock / 8)
|
||||
{
|
||||
spi_init_struct.prescale = SPI_PSC_8;
|
||||
}
|
||||
else if (max_hz >= spi_apb_clock / 16)
|
||||
{
|
||||
spi_init_struct.prescale = SPI_PSC_16;
|
||||
}
|
||||
else if (max_hz >= spi_apb_clock / 32)
|
||||
{
|
||||
spi_init_struct.prescale = SPI_PSC_32;
|
||||
}
|
||||
else if (max_hz >= spi_apb_clock / 64)
|
||||
{
|
||||
spi_init_struct.prescale = SPI_PSC_64;
|
||||
}
|
||||
else if (max_hz >= spi_apb_clock / 128)
|
||||
{
|
||||
spi_init_struct.prescale = SPI_PSC_128;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* min prescaler 256 */
|
||||
spi_init_struct.prescale = SPI_PSC_256;
|
||||
}
|
||||
} /* baudrate */
|
||||
|
||||
switch (configuration->mode & RT_SPI_MODE_3)
|
||||
{
|
||||
case RT_SPI_MODE_0:
|
||||
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
|
||||
break;
|
||||
case RT_SPI_MODE_1:
|
||||
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;
|
||||
break;
|
||||
case RT_SPI_MODE_2:
|
||||
spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_1EDGE;
|
||||
break;
|
||||
case RT_SPI_MODE_3:
|
||||
spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* MSB or LSB */
|
||||
if (configuration->mode & RT_SPI_MSB)
|
||||
{
|
||||
spi_init_struct.endian = SPI_ENDIAN_MSB;
|
||||
}
|
||||
else
|
||||
{
|
||||
spi_init_struct.endian = SPI_ENDIAN_LSB;
|
||||
}
|
||||
|
||||
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
|
||||
spi_init_struct.device_mode = SPI_MASTER;
|
||||
spi_init_struct.nss = SPI_NSS_SOFT;
|
||||
|
||||
spi_crc_off(spi_periph);
|
||||
|
||||
#if defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E)
|
||||
/* enable SPI byte access */
|
||||
spi_byte_access_enable(spi_periph);
|
||||
/* enable SPI NSS output */
|
||||
spi_nss_output_enable(spi_periph);
|
||||
#endif
|
||||
|
||||
/* init SPI */
|
||||
spi_init(spi_periph, &spi_init_struct);
|
||||
/* Enable SPI_MASTER */
|
||||
spi_enable(spi_periph);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#ifdef RT_SPI_USING_DMA
|
||||
static rt_err_t dma_spi_config(struct rt_spi_device *device, struct rt_spi_message *message)
|
||||
{
|
||||
struct rt_spi_bus *spi_bus = (struct rt_spi_bus *)device->bus;
|
||||
struct gd32_spi *spi_device = (struct gd32_spi *)spi_bus->parent.user_data;
|
||||
rt_uint8_t *recv_ptr_dma = RT_NULL;
|
||||
rt_uint8_t *send_ptr_dma = RT_NULL;
|
||||
|
||||
dma_single_data_parameter_struct dma_init_struct;
|
||||
/* deinitialize DMA registers of a channel */
|
||||
dma_deinit(spi_device->spi_dma->dma_periph, spi_device->spi_dma->txdma_ch);
|
||||
dma_deinit(spi_device->spi_dma->dma_periph, spi_device->spi_dma->rxdma_ch);
|
||||
dma_single_data_para_struct_init(&dma_init_struct);
|
||||
|
||||
/* SPI transmit DMA config */
|
||||
dma_init_struct.request = spi_device->spi_dma->dma_mux_req_tx;
|
||||
dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
|
||||
if (message->send_buf == RT_NULL)
|
||||
{
|
||||
dma_init_struct.memory0_addr = (uint32_t)send_ptr_dma;
|
||||
}
|
||||
else
|
||||
{
|
||||
dma_init_struct.memory0_addr = (uint32_t)message->send_buf;
|
||||
}
|
||||
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
|
||||
dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
|
||||
dma_init_struct.number = message->length;
|
||||
dma_init_struct.periph_addr = (uint32_t)&SPI_TDATA(spi_device->spi_periph);
|
||||
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
|
||||
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
|
||||
dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;
|
||||
dma_single_data_mode_init(spi_device->spi_dma->dma_periph, spi_device->spi_dma->txdma_ch, &dma_init_struct);
|
||||
dma_flag_clear(spi_device->spi_dma->dma_periph, spi_device->spi_dma->txdma_ch, DMA_FLAG_FTF);
|
||||
dma_flag_clear(spi_device->spi_dma->dma_periph, spi_device->spi_dma->txdma_ch, DMA_FLAG_HTF);
|
||||
dma_flag_clear(spi_device->spi_dma->dma_periph, spi_device->spi_dma->txdma_ch, DMA_FLAG_FEE);
|
||||
|
||||
/* SPI receive DMA config */
|
||||
dma_init_struct.request = spi_device->spi_dma->dma_mux_req_rx;
|
||||
dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
|
||||
if (message->recv_buf == RT_NULL)
|
||||
{
|
||||
dma_init_struct.memory0_addr = (uint32_t)recv_ptr_dma;
|
||||
}
|
||||
else
|
||||
{
|
||||
dma_init_struct.memory0_addr = (uint32_t)message->recv_buf;
|
||||
}
|
||||
dma_init_struct.periph_addr = (uint32_t)&SPI_RDATA(spi_device->spi_periph);
|
||||
dma_init_struct.priority = DMA_PRIORITY_HIGH;
|
||||
dma_single_data_mode_init(spi_device->spi_dma->dma_periph, spi_device->spi_dma->rxdma_ch, &dma_init_struct);
|
||||
dma_flag_clear(spi_device->spi_dma->dma_periph, spi_device->spi_dma->rxdma_ch, DMA_FLAG_FTF);
|
||||
dma_flag_clear(spi_device->spi_dma->dma_periph, spi_device->spi_dma->rxdma_ch, DMA_FLAG_HTF);
|
||||
dma_flag_clear(spi_device->spi_dma->dma_periph, spi_device->spi_dma->rxdma_ch, DMA_FLAG_FEE);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message)
|
||||
{
|
||||
struct rt_spi_bus *gd32_spi_bus = (struct rt_spi_bus *)device->bus;
|
||||
struct gd32_spi *spi_device = (struct gd32_spi *)gd32_spi_bus->parent.user_data;
|
||||
struct rt_spi_configuration *config = &device->config;
|
||||
uint32_t spi_periph = spi_device->spi_periph;
|
||||
|
||||
RT_ASSERT(device != NULL);
|
||||
RT_ASSERT(message != NULL);
|
||||
|
||||
#ifdef RT_SPI_USING_DMA
|
||||
dma_spi_config(device, message);
|
||||
#endif
|
||||
|
||||
/* take CS */
|
||||
if (message->cs_take && !(device->config.mode & RT_SPI_NO_CS) && (device->cs_pin != PIN_NONE))
|
||||
{
|
||||
if (device->config.mode & RT_SPI_CS_HIGH)
|
||||
{
|
||||
rt_pin_write(device->cs_pin, PIN_HIGH);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_pin_write(device->cs_pin, PIN_LOW);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_D("%s transfer prepare and start", spi_device->bus_name);
|
||||
LOG_D("%s sendbuf: %X, recvbuf: %X, length: %d",
|
||||
spi_device->bus_name,
|
||||
(uint32_t)message->send_buf,
|
||||
(uint32_t)message->recv_buf, message->length);
|
||||
|
||||
{
|
||||
if (config->data_width <= 8)
|
||||
{
|
||||
const rt_uint8_t *send_ptr = message->send_buf;
|
||||
rt_uint8_t *recv_ptr = message->recv_buf;
|
||||
rt_uint32_t size = message->length;
|
||||
|
||||
LOG_D("spi poll transfer start: %d\n", size);
|
||||
|
||||
while (size--)
|
||||
{
|
||||
rt_uint8_t data = 0xFF;
|
||||
|
||||
if (send_ptr != RT_NULL)
|
||||
{
|
||||
data = *send_ptr++;
|
||||
}
|
||||
|
||||
/* Todo: replace register read/write by gd32f4 lib */
|
||||
/* Wait until the transmit buffer is empty */
|
||||
#if defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E)
|
||||
spi_master_transfer_start(spi_periph, SPI_TRANS_START);
|
||||
while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TP))
|
||||
;
|
||||
#else
|
||||
while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE))
|
||||
;
|
||||
#endif
|
||||
/* Send the byte */
|
||||
spi_i2s_data_transmit(spi_periph, data);
|
||||
|
||||
/* Wait until a data is received */
|
||||
#if defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E)
|
||||
while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RP))
|
||||
;
|
||||
#else
|
||||
while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE))
|
||||
;
|
||||
#endif
|
||||
/* Get the received data */
|
||||
data = spi_i2s_data_receive(spi_periph);
|
||||
|
||||
if (recv_ptr != RT_NULL)
|
||||
{
|
||||
*recv_ptr++ = data;
|
||||
}
|
||||
}
|
||||
LOG_D("spi poll transfer finsh\n");
|
||||
}
|
||||
else if (config->data_width <= 16)
|
||||
{
|
||||
const rt_uint16_t *send_ptr = message->send_buf;
|
||||
rt_uint16_t *recv_ptr = message->recv_buf;
|
||||
rt_uint32_t size = message->length;
|
||||
|
||||
while (size--)
|
||||
{
|
||||
rt_uint16_t data = 0xFF;
|
||||
|
||||
if (send_ptr != RT_NULL)
|
||||
{
|
||||
data = *send_ptr++;
|
||||
}
|
||||
|
||||
/* Wait until the transmit buffer is empty */
|
||||
#if defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E)
|
||||
spi_master_transfer_start(spi_periph, SPI_TRANS_START);
|
||||
while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TP))
|
||||
;
|
||||
#else
|
||||
while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE))
|
||||
;
|
||||
#endif
|
||||
/* Send the byte */
|
||||
spi_i2s_data_transmit(spi_periph, data);
|
||||
|
||||
/* Wait until a data is received */
|
||||
#if defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E)
|
||||
while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RP))
|
||||
;
|
||||
#else
|
||||
while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE))
|
||||
;
|
||||
#endif
|
||||
/* Get the received data */
|
||||
data = spi_i2s_data_receive(spi_periph);
|
||||
|
||||
if (recv_ptr != RT_NULL)
|
||||
{
|
||||
*recv_ptr++ = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if defined SOC_SERIES_GD32H7xx || defined(SOC_SERIES_GD32H75E)
|
||||
else if (config->data_width <= 32)
|
||||
{
|
||||
const rt_uint32_t *send_ptr = message->send_buf;
|
||||
rt_uint32_t *recv_ptr = message->recv_buf;
|
||||
rt_uint32_t size = message->length;
|
||||
/* SPI master start transfer */
|
||||
spi_master_transfer_start(spi_periph, SPI_TRANS_START);
|
||||
while (size--)
|
||||
{
|
||||
rt_uint32_t data = 0xFF;
|
||||
|
||||
if (send_ptr != RT_NULL)
|
||||
{
|
||||
data = *send_ptr++;
|
||||
}
|
||||
|
||||
/* Wait until the transmit buffer is empty */
|
||||
while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TP))
|
||||
;
|
||||
/* Send the byte */
|
||||
spi_i2s_data_transmit(spi_periph, data);
|
||||
|
||||
/* Wait until a data is received */
|
||||
while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RP))
|
||||
;
|
||||
/* Get the received data */
|
||||
data = spi_i2s_data_receive(spi_periph);
|
||||
|
||||
if (recv_ptr != RT_NULL)
|
||||
{
|
||||
*recv_ptr++ = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* release CS */
|
||||
if (message->cs_release && !(device->config.mode & RT_SPI_NO_CS) && (device->cs_pin != PIN_NONE))
|
||||
{
|
||||
if (device->config.mode & RT_SPI_CS_HIGH)
|
||||
rt_pin_write(device->cs_pin, PIN_LOW);
|
||||
else
|
||||
rt_pin_write(device->cs_pin, PIN_HIGH);
|
||||
}
|
||||
|
||||
return message->length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach the spi device to SPI bus, this function must be used after initialization.
|
||||
*/
|
||||
rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_base_t cs_pin)
|
||||
{
|
||||
RT_ASSERT(bus_name != RT_NULL);
|
||||
RT_ASSERT(device_name != RT_NULL);
|
||||
|
||||
rt_err_t result;
|
||||
struct rt_spi_device *spi_device;
|
||||
|
||||
/* attach the device to spi bus*/
|
||||
spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
|
||||
RT_ASSERT(spi_device != RT_NULL);
|
||||
|
||||
if (cs_pin != PIN_NONE)
|
||||
{
|
||||
/* initialize the cs pin && select the slave*/
|
||||
rt_pin_mode(cs_pin, PIN_MODE_OUTPUT);
|
||||
rt_pin_write(cs_pin, PIN_HIGH);
|
||||
}
|
||||
|
||||
result = rt_spi_bus_attach_device_cspin(spi_device, device_name, bus_name, cs_pin, RT_NULL);
|
||||
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
LOG_E("%s attach to %s faild, %d\n", device_name, bus_name, result);
|
||||
}
|
||||
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
LOG_D("%s attach to %s done", device_name, bus_name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int rt_hw_spi_init(void)
|
||||
{
|
||||
int result = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(spi_bus_obj) / sizeof(spi_bus_obj[0]); i++)
|
||||
{
|
||||
spi_bus_obj[i].spi_bus->parent.user_data = (void *)&spi_bus_obj[i];
|
||||
|
||||
result = rt_spi_bus_register(spi_bus_obj[i].spi_bus, spi_bus_obj[i].bus_name, &gd32_spi_ops);
|
||||
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
LOG_D("%s bus init done", spi_bus_obj[i].bus_name);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
INIT_BOARD_EXPORT(rt_hw_spi_init);
|
||||
|
||||
#endif /* BSP_USING_SPI0 || BSP_USING_SPI1 || BSP_USING_SPI2 || BSP_USING_SPI3 || BSP_USING_SPI4 || BSP_USING_SPI5 */
|
||||
#endif /* RT_USING_SPI */
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-01-25 iysheng first version
|
||||
* 2025-10-09 kurisaw fix inaccurate WDT clock timeout feeding issue
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <rthw.h>
|
||||
#include <board.h>
|
||||
|
||||
#define DBG_TAG "drv.wdt"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#ifdef RT_USING_WDT
|
||||
|
||||
/* User-configurable macros for WDT clock source and prescaler */
|
||||
/* Default select oscillator type: RCU_IRC32K */
|
||||
#define WDT_OSCI_TYPE RCU_IRC32K
|
||||
|
||||
/* Prescaler divider value (must match WDT_PSC_VALUE) */
|
||||
#define WDT_PSC_DIVIDER 256U
|
||||
/* Prescaler register value */
|
||||
#define WDT_PSC_VALUE FWDGT_PSC_DIV256
|
||||
|
||||
/* Derived values */
|
||||
#define WDT_CLOCK_FREQ IRC32K_VALUE
|
||||
|
||||
#define WDT_TICK_HZ (WDT_CLOCK_FREQ / WDT_PSC_DIVIDER)
|
||||
#define WDT_MAX_RELOAD_VALUE 0xfffU
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct rt_watchdog_device wdt;
|
||||
rt_uint32_t min_threshold_s;
|
||||
rt_uint32_t max_threshold_s;
|
||||
rt_uint32_t current_threshold_s;
|
||||
} gd32_wdt_device_t;
|
||||
|
||||
static gd32_wdt_device_t g_wdt_dev;
|
||||
|
||||
static rt_err_t gd32_wdt_init(rt_watchdog_t *wdt)
|
||||
{
|
||||
#if defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E)
|
||||
/* Enable and wait for oscillator stabilization */
|
||||
rcu_osci_on(WDT_OSCI_TYPE);
|
||||
if (ERROR == rcu_osci_stab_wait(WDT_OSCI_TYPE))
|
||||
{
|
||||
LOG_E("failed init %u clock for free watchdog.", WDT_OSCI_TYPE);
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Calculate thresholds */
|
||||
g_wdt_dev.min_threshold_s = 1U;
|
||||
g_wdt_dev.max_threshold_s = ((WDT_MAX_RELOAD_VALUE + 1U) * WDT_PSC_DIVIDER) / WDT_CLOCK_FREQ;
|
||||
LOG_I("WDT clock: %u Hz (tick: %u Hz), threshold section [%u, %u]",
|
||||
WDT_CLOCK_FREQ, WDT_TICK_HZ,
|
||||
g_wdt_dev.min_threshold_s, g_wdt_dev.max_threshold_s);
|
||||
|
||||
/* Configure FWDGT with max timeout */
|
||||
fwdgt_write_enable();
|
||||
if (fwdgt_config(WDT_MAX_RELOAD_VALUE, WDT_PSC_VALUE) != SUCCESS)
|
||||
{
|
||||
LOG_E("failed to configure FWDGT");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
fwdgt_enable();
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t gd32_wdt_control(rt_watchdog_t *wdt, int cmd, void *arg)
|
||||
{
|
||||
rt_uint32_t param;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case RT_DEVICE_CTRL_WDT_KEEPALIVE:
|
||||
fwdgt_counter_reload();
|
||||
break;
|
||||
case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
|
||||
param = *(rt_uint32_t *)arg;
|
||||
if ((param > g_wdt_dev.max_threshold_s) ||
|
||||
(param < g_wdt_dev.min_threshold_s))
|
||||
{
|
||||
LOG_E("invalid param@%u (out of [%u, %u])", param,
|
||||
g_wdt_dev.min_threshold_s, g_wdt_dev.max_threshold_s);
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_wdt_dev.current_threshold_s = param;
|
||||
rt_uint32_t reload_value = (param * WDT_TICK_HZ) - 1U;
|
||||
fwdgt_write_enable();
|
||||
if (fwdgt_config(reload_value, WDT_PSC_VALUE) != SUCCESS)
|
||||
{
|
||||
LOG_E("failed to set timeout %u s", param);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
fwdgt_write_disable();
|
||||
}
|
||||
break;
|
||||
case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
|
||||
*(rt_uint32_t *)arg = g_wdt_dev.current_threshold_s;
|
||||
break;
|
||||
case RT_DEVICE_CTRL_WDT_START:
|
||||
fwdgt_enable();
|
||||
break;
|
||||
default:
|
||||
LOG_W("This command is not supported.");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static struct rt_watchdog_ops g_wdt_ops = {
|
||||
gd32_wdt_init,
|
||||
gd32_wdt_control,
|
||||
};
|
||||
|
||||
static int rt_hw_wdt_init(void)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
|
||||
g_wdt_dev.wdt.ops = &g_wdt_ops;
|
||||
/* register watchdog device */
|
||||
if (rt_hw_watchdog_register(&g_wdt_dev.wdt, "wdt",
|
||||
RT_DEVICE_FLAG_DEACTIVATE, RT_NULL) != RT_EOK)
|
||||
{
|
||||
LOG_E("wdt device register failed.");
|
||||
ret = -RT_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_D("wdt device register success.");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
INIT_PREV_EXPORT(rt_hw_wdt_init);
|
||||
#endif
|
||||
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-10-15 LZerro compatible with RT-Studio
|
||||
* 2025-10-22 kurisaw optimize multi-channel GPIO configuration
|
||||
*/
|
||||
|
||||
#ifndef __ADC_CONFIG_H__
|
||||
#define __ADC_CONFIG_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "drv_adc.h"
|
||||
|
||||
#ifdef RT_USING_ADC
|
||||
#define MAX_EXTERN_ADC_CHANNEL 20
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_ADC0
|
||||
#ifdef BSP_ADC0_CH0_PIN
|
||||
#define ADC0_CH0_PIN BSP_ADC0_CH0_PIN
|
||||
#else
|
||||
#define ADC0_CH0_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH1_PIN
|
||||
#define ADC0_CH1_PIN BSP_ADC0_CH1_PIN
|
||||
#else
|
||||
#define ADC0_CH1_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH2_PIN
|
||||
#define ADC0_CH2_PIN BSP_ADC0_CH2_PIN
|
||||
#else
|
||||
#define ADC0_CH2_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH3_PIN
|
||||
#define ADC0_CH3_PIN BSP_ADC0_CH3_PIN
|
||||
#else
|
||||
#define ADC0_CH3_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH4_PIN
|
||||
#define ADC0_CH4_PIN BSP_ADC0_CH4_PIN
|
||||
#else
|
||||
#define ADC0_CH4_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH5_PIN
|
||||
#define ADC0_CH5_PIN BSP_ADC0_CH5_PIN
|
||||
#else
|
||||
#define ADC0_CH5_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH6_PIN
|
||||
#define ADC0_CH6_PIN BSP_ADC0_CH6_PIN
|
||||
#else
|
||||
#define ADC0_CH6_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH7_PIN
|
||||
#define ADC0_CH7_PIN BSP_ADC0_CH7_PIN
|
||||
#else
|
||||
#define ADC0_CH7_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH8_PIN
|
||||
#define ADC0_CH8_PIN BSP_ADC0_CH8_PIN
|
||||
#else
|
||||
#define ADC0_CH8_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH9_PIN
|
||||
#define ADC0_CH9_PIN BSP_ADC0_CH9_PIN
|
||||
#else
|
||||
#define ADC0_CH9_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH10_PIN
|
||||
#define ADC0_CH10_PIN BSP_ADC0_CH10_PIN
|
||||
#else
|
||||
#define ADC0_CH10_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH11_PIN
|
||||
#define ADC0_CH11_PIN BSP_ADC0_CH11_PIN
|
||||
#else
|
||||
#define ADC0_CH11_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH12_PIN
|
||||
#define ADC0_CH12_PIN BSP_ADC0_CH12_PIN
|
||||
#else
|
||||
#define ADC0_CH12_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH13_PIN
|
||||
#define ADC0_CH13_PIN BSP_ADC0_CH13_PIN
|
||||
#else
|
||||
#define ADC0_CH13_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH14_PIN
|
||||
#define ADC0_CH14_PIN BSP_ADC0_CH14_PIN
|
||||
#else
|
||||
#define ADC0_CH14_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH15_PIN
|
||||
#define ADC0_CH15_PIN BSP_ADC0_CH15_PIN
|
||||
#else
|
||||
#define ADC0_CH15_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH16_PIN
|
||||
#define ADC0_CH16_PIN BSP_ADC0_CH16_PIN
|
||||
#else
|
||||
#define ADC0_CH16_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH17_PIN
|
||||
#define ADC0_CH17_PIN BSP_ADC0_CH17_PIN
|
||||
#else
|
||||
#define ADC0_CH17_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH18_PIN
|
||||
#define ADC0_CH18_PIN BSP_ADC0_CH18_PIN
|
||||
#else
|
||||
#define ADC0_CH18_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC0_CH19_PIN
|
||||
#define ADC0_CH19_PIN BSP_ADC0_CH19_PIN
|
||||
#else
|
||||
#define ADC0_CH19_PIN RT_NULL
|
||||
#endif
|
||||
|
||||
#ifndef ADC0_CONFIG
|
||||
#define ADC0_CONFIG \
|
||||
{ \
|
||||
ADC0, \
|
||||
RCU_ADC0, \
|
||||
{ \
|
||||
ADC0_CH0_PIN, \
|
||||
ADC0_CH1_PIN, \
|
||||
ADC0_CH2_PIN, \
|
||||
ADC0_CH3_PIN, \
|
||||
ADC0_CH4_PIN, \
|
||||
ADC0_CH5_PIN, \
|
||||
ADC0_CH6_PIN, \
|
||||
ADC0_CH7_PIN, \
|
||||
ADC0_CH8_PIN, \
|
||||
ADC0_CH9_PIN, \
|
||||
ADC0_CH10_PIN, \
|
||||
ADC0_CH11_PIN, \
|
||||
ADC0_CH12_PIN, \
|
||||
ADC0_CH13_PIN, \
|
||||
ADC0_CH14_PIN, \
|
||||
ADC0_CH15_PIN, \
|
||||
ADC0_CH16_PIN, \
|
||||
ADC0_CH17_PIN, \
|
||||
ADC0_CH18_PIN, \
|
||||
ADC0_CH19_PIN, \
|
||||
}, \
|
||||
&adc0, \
|
||||
"adc0", \
|
||||
}
|
||||
#endif /* ADC0_CONFIG */
|
||||
#endif /* BSP_USING_ADC0 */
|
||||
|
||||
#ifdef BSP_USING_ADC1
|
||||
#ifdef BSP_ADC1_CH0_PIN
|
||||
#define ADC1_CH0_PIN BSP_ADC1_CH0_PIN
|
||||
#else
|
||||
#define ADC1_CH0_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH1_PIN
|
||||
#define ADC1_CH1_PIN BSP_ADC1_CH1_PIN
|
||||
#else
|
||||
#define ADC1_CH1_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH2_PIN
|
||||
#define ADC1_CH2_PIN BSP_ADC1_CH2_PIN
|
||||
#else
|
||||
#define ADC1_CH2_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH3_PIN
|
||||
#define ADC1_CH3_PIN BSP_ADC1_CH3_PIN
|
||||
#else
|
||||
#define ADC1_CH3_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH4_PIN
|
||||
#define ADC1_CH4_PIN BSP_ADC1_CH4_PIN
|
||||
#else
|
||||
#define ADC1_CH4_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH5_PIN
|
||||
#define ADC1_CH5_PIN BSP_ADC1_CH5_PIN
|
||||
#else
|
||||
#define ADC1_CH5_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH6_PIN
|
||||
#define ADC1_CH6_PIN BSP_ADC1_CH6_PIN
|
||||
#else
|
||||
#define ADC1_CH6_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH7_PIN
|
||||
#define ADC1_CH7_PIN BSP_ADC1_CH7_PIN
|
||||
#else
|
||||
#define ADC1_CH7_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH8_PIN
|
||||
#define ADC1_CH8_PIN BSP_ADC1_CH8_PIN
|
||||
#else
|
||||
#define ADC1_CH8_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH9_PIN
|
||||
#define ADC1_CH9_PIN BSP_ADC1_CH9_PIN
|
||||
#else
|
||||
#define ADC1_CH9_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH10_PIN
|
||||
#define ADC1_CH10_PIN BSP_ADC1_CH10_PIN
|
||||
#else
|
||||
#define ADC1_CH10_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH11_PIN
|
||||
#define ADC1_CH11_PIN BSP_ADC1_CH11_PIN
|
||||
#else
|
||||
#define ADC1_CH11_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH12_PIN
|
||||
#define ADC1_CH12_PIN BSP_ADC1_CH12_PIN
|
||||
#else
|
||||
#define ADC1_CH12_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH13_PIN
|
||||
#define ADC1_CH13_PIN BSP_ADC1_CH13_PIN
|
||||
#else
|
||||
#define ADC1_CH13_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH14_PIN
|
||||
#define ADC1_CH14_PIN BSP_ADC1_CH14_PIN
|
||||
#else
|
||||
#define ADC1_CH14_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH15_PIN
|
||||
#define ADC1_CH15_PIN BSP_ADC1_CH15_PIN
|
||||
#else
|
||||
#define ADC1_CH15_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH16_PIN
|
||||
#define ADC1_CH16_PIN BSP_ADC1_CH16_PIN
|
||||
#else
|
||||
#define ADC1_CH16_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH17_PIN
|
||||
#define ADC1_CH17_PIN BSP_ADC1_CH17_PIN
|
||||
#else
|
||||
#define ADC1_CH17_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH18_PIN
|
||||
#define ADC1_CH18_PIN BSP_ADC1_CH18_PIN
|
||||
#else
|
||||
#define ADC1_CH18_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC1_CH19_PIN
|
||||
#define ADC1_CH19_PIN BSP_ADC1_CH19_PIN
|
||||
#else
|
||||
#define ADC1_CH19_PIN RT_NULL
|
||||
#endif
|
||||
|
||||
#ifndef ADC1_CONFIG
|
||||
#define ADC1_CONFIG \
|
||||
{ \
|
||||
ADC1, \
|
||||
RCU_ADC1, \
|
||||
{ \
|
||||
ADC1_CH0_PIN, \
|
||||
ADC1_CH1_PIN, \
|
||||
ADC1_CH2_PIN, \
|
||||
ADC1_CH3_PIN, \
|
||||
ADC1_CH4_PIN, \
|
||||
ADC1_CH5_PIN, \
|
||||
ADC1_CH6_PIN, \
|
||||
ADC1_CH7_PIN, \
|
||||
ADC1_CH8_PIN, \
|
||||
ADC1_CH9_PIN, \
|
||||
ADC1_CH10_PIN, \
|
||||
ADC1_CH11_PIN, \
|
||||
ADC1_CH12_PIN, \
|
||||
ADC1_CH13_PIN, \
|
||||
ADC1_CH14_PIN, \
|
||||
ADC1_CH15_PIN, \
|
||||
ADC1_CH16_PIN, \
|
||||
ADC1_CH17_PIN, \
|
||||
ADC1_CH18_PIN, \
|
||||
ADC1_CH19_PIN, \
|
||||
}, \
|
||||
&adc1, \
|
||||
"adc1", \
|
||||
}
|
||||
#endif /* ADC1_CONFIG */
|
||||
#endif /* BSP_USING_ADC1 */
|
||||
|
||||
#ifdef BSP_USING_ADC2
|
||||
#ifdef BSP_ADC2_CH0_PIN
|
||||
#define ADC2_CH0_PIN BSP_ADC2_CH0_PIN
|
||||
#else
|
||||
#define ADC2_CH0_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH1_PIN
|
||||
#define ADC2_CH1_PIN BSP_ADC2_CH1_PIN
|
||||
#else
|
||||
#define ADC2_CH1_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH2_PIN
|
||||
#define ADC2_CH2_PIN BSP_ADC2_CH2_PIN
|
||||
#else
|
||||
#define ADC2_CH2_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH3_PIN
|
||||
#define ADC2_CH3_PIN BSP_ADC2_CH3_PIN
|
||||
#else
|
||||
#define ADC2_CH3_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH4_PIN
|
||||
#define ADC2_CH4_PIN BSP_ADC2_CH4_PIN
|
||||
#else
|
||||
#define ADC2_CH4_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH5_PIN
|
||||
#define ADC2_CH5_PIN BSP_ADC2_CH5_PIN
|
||||
#else
|
||||
#define ADC2_CH5_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH6_PIN
|
||||
#define ADC2_CH6_PIN BSP_ADC2_CH6_PIN
|
||||
#else
|
||||
#define ADC2_CH6_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH7_PIN
|
||||
#define ADC2_CH7_PIN BSP_ADC2_CH7_PIN
|
||||
#else
|
||||
#define ADC2_CH7_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH8_PIN
|
||||
#define ADC2_CH8_PIN BSP_ADC2_CH8_PIN
|
||||
#else
|
||||
#define ADC2_CH8_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH9_PIN
|
||||
#define ADC2_CH9_PIN BSP_ADC2_CH9_PIN
|
||||
#else
|
||||
#define ADC2_CH9_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH10_PIN
|
||||
#define ADC2_CH10_PIN BSP_ADC2_CH10_PIN
|
||||
#else
|
||||
#define ADC2_CH10_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH11_PIN
|
||||
#define ADC2_CH11_PIN BSP_ADC2_CH11_PIN
|
||||
#else
|
||||
#define ADC2_CH11_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH12_PIN
|
||||
#define ADC2_CH12_PIN BSP_ADC2_CH12_PIN
|
||||
#else
|
||||
#define ADC2_CH12_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH13_PIN
|
||||
#define ADC2_CH13_PIN BSP_ADC2_CH13_PIN
|
||||
#else
|
||||
#define ADC2_CH13_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH14_PIN
|
||||
#define ADC2_CH14_PIN BSP_ADC2_CH14_PIN
|
||||
#else
|
||||
#define ADC2_CH14_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH15_PIN
|
||||
#define ADC2_CH15_PIN BSP_ADC2_CH15_PIN
|
||||
#else
|
||||
#define ADC2_CH15_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH16_PIN
|
||||
#define ADC2_CH16_PIN BSP_ADC2_CH16_PIN
|
||||
#else
|
||||
#define ADC2_CH16_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH17_PIN
|
||||
#define ADC2_CH17_PIN BSP_ADC2_CH17_PIN
|
||||
#else
|
||||
#define ADC2_CH17_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH18_PIN
|
||||
#define ADC2_CH18_PIN BSP_ADC2_CH18_PIN
|
||||
#else
|
||||
#define ADC2_CH18_PIN RT_NULL
|
||||
#endif
|
||||
#ifdef BSP_ADC2_CH19_PIN
|
||||
#define ADC2_CH19_PIN BSP_ADC2_CH19_PIN
|
||||
#else
|
||||
#define ADC2_CH19_PIN RT_NULL
|
||||
#endif
|
||||
|
||||
#ifndef ADC2_CONFIG
|
||||
#define ADC2_CONFIG \
|
||||
{ \
|
||||
ADC2, \
|
||||
RCU_ADC2, \
|
||||
{ \
|
||||
ADC2_CH0_PIN, \
|
||||
ADC2_CH1_PIN, \
|
||||
ADC2_CH2_PIN, \
|
||||
ADC2_CH3_PIN, \
|
||||
ADC2_CH4_PIN, \
|
||||
ADC2_CH5_PIN, \
|
||||
ADC2_CH6_PIN, \
|
||||
ADC2_CH7_PIN, \
|
||||
ADC2_CH8_PIN, \
|
||||
ADC2_CH9_PIN, \
|
||||
ADC2_CH10_PIN, \
|
||||
ADC2_CH11_PIN, \
|
||||
ADC2_CH12_PIN, \
|
||||
ADC2_CH13_PIN, \
|
||||
ADC2_CH14_PIN, \
|
||||
ADC2_CH15_PIN, \
|
||||
ADC2_CH16_PIN, \
|
||||
ADC2_CH17_PIN, \
|
||||
ADC2_CH18_PIN, \
|
||||
ADC2_CH19_PIN, \
|
||||
}, \
|
||||
&adc2, \
|
||||
"adc2", \
|
||||
}
|
||||
#endif /* ADC2_CONFIG */
|
||||
#endif /* BSP_USING_ADC2 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __ADC_CONFIG_H__
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-10-22 WangShun compatible with RT-Studio
|
||||
*/
|
||||
|
||||
#ifndef __CAN_CONFIG_H__
|
||||
#define __CAN_CONFIG_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(BSP_USING_CAN0)
|
||||
#ifndef BSP_CAN0_RX_PIN
|
||||
#define BSP_CAN0_RX_PIN "PD0"
|
||||
#define BSP_CAN0_TX_PIN "PD1"
|
||||
#define BSP_CAN0_AFIO "AF9"
|
||||
#endif /* BSP_CAN0_RX_PIN */
|
||||
#ifndef CAN0_CONFIG
|
||||
#define CAN0_CONFIG \
|
||||
{ \
|
||||
.name = "can0", \
|
||||
.can_periph = CAN0, \
|
||||
.tx_pin_name = BSP_CAN0_TX_PIN, \
|
||||
.rx_pin_name = BSP_CAN0_RX_PIN, \
|
||||
.alternate = BSP_CAN0_AFIO, \
|
||||
.device = &dev_can0, \
|
||||
}
|
||||
#endif /* CAN0_CONFIG */
|
||||
#endif /* BSP_USING_CAN0 */
|
||||
|
||||
#if defined(BSP_USING_CAN1)
|
||||
#ifndef BSP_CAN1_RX_PIN
|
||||
#define BSP_CAN1_RX_PIN "PB5"
|
||||
#define BSP_CAN1_TX_PIN "PB6"
|
||||
#define BSP_CAN1_AFIO "AF9"
|
||||
#endif /* BSP_CAN0_RX_PIN */
|
||||
#ifndef CAN1_CONFIG
|
||||
#define CAN1_CONFIG \
|
||||
{ \
|
||||
.name = "can1", \
|
||||
.can_periph = CAN1, \
|
||||
.tx_pin_name = BSP_CAN1_TX_PIN, \
|
||||
.rx_pin_name = BSP_CAN1_RX_PIN, \
|
||||
.alternate = BSP_CAN1_AFIO, \
|
||||
.device = &dev_can1, \
|
||||
}
|
||||
#endif /* CAN1_CONFIG */
|
||||
#endif /* BSP_USING_CAN1 */
|
||||
|
||||
#if defined(BSP_USING_CAN2)
|
||||
#ifndef BSP_CAN2_RX_PIN
|
||||
#define BSP_CAN2_RX_PIN "PD12"
|
||||
#define BSP_CAN2_TX_PIN "PD13"
|
||||
#define BSP_CAN2_AFIO "AF5"
|
||||
#endif /* BSP_CAN2_RX_PIN */
|
||||
#ifndef CAN2_CONFIG
|
||||
#define CAN2_CONFIG \
|
||||
{ \
|
||||
.name = "can2", \
|
||||
.can_periph = CAN2, \
|
||||
.tx_pin_name = BSP_CAN2_TX_PIN, \
|
||||
.rx_pin_name = BSP_CAN2_RX_PIN, \
|
||||
.alternate = BSP_CAN2_AFIO, \
|
||||
.device = &dev_can2, \
|
||||
}
|
||||
#endif /* CAN2_CONFIG */
|
||||
#endif /* BSP_USING_CAN2 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CAN_CONFIG_H__ */
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-10-11 kurisaw first version
|
||||
*/
|
||||
|
||||
#ifndef __DAC_CONFIG_H__
|
||||
#define __DAC_CONFIG_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_DAC0
|
||||
|
||||
#ifndef DAC0_CONFIG
|
||||
#define DAC0_CONFIG \
|
||||
{ \
|
||||
.dac_periph = DAC0, \
|
||||
.name = "dac0", \
|
||||
.pin_name = BSP_DAC0_PIN, \
|
||||
.channel = BSP_DAC0_CHANNEL, \
|
||||
}
|
||||
#endif /* DAC0_CONFIG */
|
||||
#endif /* BSP_USING_DAC0 */
|
||||
|
||||
#ifdef BSP_USING_DAC1
|
||||
|
||||
#ifndef DAC1_CONFIG
|
||||
#define DAC1_CONFIG \
|
||||
{ \
|
||||
.dac_periph = DAC0, \
|
||||
.name = "dac1", \
|
||||
.pin_name = BSP_DAC1_PIN, \
|
||||
.channel = BSP_DAC1_CHANNEL, \
|
||||
}
|
||||
#endif /* DAC1_CONFIG */
|
||||
#endif /* BSP_USING_DAC1 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__DAC_CONFIG_H__ */
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-10 kurisaw ENET configuration
|
||||
*/
|
||||
|
||||
#ifndef __ENET_CONFIG_H__
|
||||
#define __ENET_CONFIG_H__
|
||||
|
||||
#include "drv_enet.h"
|
||||
#if defined(RT_USING_SAL) && defined(RT_USING_NETDEV) && defined(RT_USING_LWIP)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ENET pin configuration table for RMII interface */
|
||||
const struct enet_pin_config enet0_pins[] =
|
||||
{
|
||||
/* ETH_RMII_REF_CLK */ {"PA1", "AF11"},
|
||||
/* ETH_MDIO */ {"PA2", "AF11"},
|
||||
/* ETH_RMII_CRS_DV */ {"PA7", "AF11"},
|
||||
/* ETH_RMII_TX_EN */ {"PG11", "AF11"},
|
||||
/* ETH_RMII_TXD0 */ {"PB12", "AF11"},
|
||||
/* ETH_RMII_TXD1 */ {"PG12", "AF11"},
|
||||
/* ETH_MDC */ {"PC1", "AF11"},
|
||||
/* ETH_RMII_RXD0 */ {"PC4", "AF11"},
|
||||
/* ETH_RMII_RXD1 */ {"PC5", "AF11"},
|
||||
};
|
||||
|
||||
/* Clock output pin for PHY */
|
||||
const struct enet_pin_config enet_clock_pin = {
|
||||
"PA8", "AF0" /* Clock output for PHY */
|
||||
};
|
||||
|
||||
/* ENET configuration */
|
||||
const struct enet_config enet0_cfg = {
|
||||
.pins = enet0_pins,
|
||||
.pin_count = sizeof(enet0_pins) / sizeof(enet0_pins[0]),
|
||||
.enet_periph = ENET0,
|
||||
.enet_clk = RCU_ENET0,
|
||||
.enet_tx_clk = RCU_ENET0TX,
|
||||
.enet_rx_clk = RCU_ENET0RX,
|
||||
.phy_interface = SYSCFG_ENET_PHY_RMII,
|
||||
.speed = GPIO_OSPEED_100_220MHZ,
|
||||
.otype = GPIO_OTYPE_PP,
|
||||
.pupd = GPIO_PUPD_NONE,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RT_USING_SAL && RT_USING_NETDEV && RT_USING_LWIP */
|
||||
#endif /* __ENET_CONFIG_H__ */
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-10-22 kurisaw initial commit
|
||||
*/
|
||||
|
||||
#ifndef __HWTIMER_CONFIG_H__
|
||||
#define __HWTIMER_CONFIG_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "drv_hwtimer.h"
|
||||
|
||||
#ifdef BSP_USING_HWTIMER0
|
||||
#ifndef HWTIMER0_CONFIG
|
||||
#define HWTIMER0_CONFIG \
|
||||
{ \
|
||||
"timer0", \
|
||||
{ \
|
||||
TIMER0, \
|
||||
TIMER0_UP_IRQn, \
|
||||
RCU_TIMER0, \
|
||||
}, \
|
||||
{ 0 }, \
|
||||
{ \
|
||||
10000000, /* max frequency */ \
|
||||
1000, /* min frequency */ \
|
||||
0xFFFF, /* 16-bit counter */ \
|
||||
HWTIMER_CNTMODE_UP, /* count up mode */ \
|
||||
}, \
|
||||
}
|
||||
#endif /* HWTIMER0_CONFIG */
|
||||
#endif /* BSP_USING_HWTIMER0 */
|
||||
|
||||
#ifdef BSP_USING_HWTIMER1
|
||||
#ifndef HWTIMER1_CONFIG
|
||||
#define HWTIMER1_CONFIG \
|
||||
{ \
|
||||
"timer1", \
|
||||
{ \
|
||||
TIMER1, \
|
||||
TIMER1_IRQn, \
|
||||
RCU_TIMER1, \
|
||||
}, \
|
||||
{ 0 }, \
|
||||
{ \
|
||||
10000000, \
|
||||
1000, \
|
||||
0xFFFFFFFF, /* 32-bit counter */ \
|
||||
HWTIMER_CNTMODE_UP, \
|
||||
}, \
|
||||
}
|
||||
#endif /* HWTIMER1_CONFIG */
|
||||
#endif /* BSP_USING_HWTIMER1 */
|
||||
|
||||
#ifdef BSP_USING_HWTIMER2
|
||||
#ifndef HWTIMER2_CONFIG
|
||||
#define HWTIMER2_CONFIG \
|
||||
{ \
|
||||
"timer2", \
|
||||
{ \
|
||||
TIMER2, \
|
||||
TIMER2_IRQn, \
|
||||
RCU_TIMER2, \
|
||||
}, \
|
||||
{ 0 }, \
|
||||
{ \
|
||||
10000000, \
|
||||
1000, \
|
||||
0xFFFF, /* 16-bit counter */ \
|
||||
HWTIMER_CNTMODE_UP, \
|
||||
}, \
|
||||
}
|
||||
#endif /* HWTIMER2_CONFIG */
|
||||
#endif /* BSP_USING_HWTIMER2 */
|
||||
|
||||
#ifdef BSP_USING_HWTIMER3
|
||||
#ifndef HWTIMER3_CONFIG
|
||||
#define HWTIMER3_CONFIG \
|
||||
{ \
|
||||
"timer3", \
|
||||
{ \
|
||||
TIMER3, \
|
||||
TIMER3_IRQn, \
|
||||
RCU_TIMER3, \
|
||||
}, \
|
||||
{ 0 }, \
|
||||
{ \
|
||||
10000000, \
|
||||
1000, \
|
||||
0xFFFF, /* 16-bit counter */ \
|
||||
HWTIMER_CNTMODE_UP, \
|
||||
}, \
|
||||
}
|
||||
#endif /* HWTIMER3_CONFIG */
|
||||
#endif /* BSP_USING_HWTIMER3 */
|
||||
|
||||
#ifdef BSP_USING_HWTIMER4
|
||||
#ifndef HWTIMER4_CONFIG
|
||||
#define HWTIMER4_CONFIG \
|
||||
{ \
|
||||
"timer4", \
|
||||
{ \
|
||||
TIMER4, \
|
||||
TIMER4_IRQn, \
|
||||
RCU_TIMER4, \
|
||||
}, \
|
||||
{ 0 }, \
|
||||
{ \
|
||||
10000000, \
|
||||
1000, \
|
||||
0xFFFFFFFF, /* 32-bit counter */ \
|
||||
HWTIMER_CNTMODE_UP, \
|
||||
}, \
|
||||
}
|
||||
#endif /* HWTIMER4_CONFIG */
|
||||
#endif /* BSP_USING_HWTIMER4 */
|
||||
|
||||
#ifdef BSP_USING_HWTIMER5
|
||||
#ifndef HWTIMER5_CONFIG
|
||||
#define HWTIMER5_CONFIG \
|
||||
{ \
|
||||
"timer5", \
|
||||
{ \
|
||||
TIMER5, \
|
||||
TIMER5_IRQn, \
|
||||
RCU_TIMER5, \
|
||||
}, \
|
||||
{ 0 }, \
|
||||
{ \
|
||||
10000000, \
|
||||
1000, \
|
||||
0xFFFFFFFF, /* 32-bit counter */ \
|
||||
HWTIMER_CNTMODE_UP, \
|
||||
}, \
|
||||
}
|
||||
#endif /* HWTIMER5_CONFIG */
|
||||
#endif /* BSP_USING_HWTIMER5 */
|
||||
|
||||
#ifdef BSP_USING_HWTIMER6
|
||||
#ifndef HWTIMER6_CONFIG
|
||||
#define HWTIMER6_CONFIG \
|
||||
{ \
|
||||
"timer6", \
|
||||
{ \
|
||||
TIMER6, \
|
||||
TIMER6_IRQn, \
|
||||
RCU_TIMER6, \
|
||||
}, \
|
||||
{ 0 }, \
|
||||
{ \
|
||||
10000000, \
|
||||
1000, \
|
||||
0xFFFFFFFF, /* 32-bit counter */ \
|
||||
HWTIMER_CNTMODE_UP, \
|
||||
}, \
|
||||
}
|
||||
#endif /* HWTIMER6_CONFIG */
|
||||
#endif /* BSP_USING_HWTIMER6 */
|
||||
|
||||
#ifdef BSP_USING_HWTIMER7
|
||||
#ifndef HWTIMER7_CONFIG
|
||||
#define HWTIMER7_CONFIG \
|
||||
{ \
|
||||
"timer7", \
|
||||
{ \
|
||||
TIMER7, \
|
||||
TIMER7_UP_IRQn, \
|
||||
RCU_TIMER7, \
|
||||
}, \
|
||||
{ 0 }, \
|
||||
{ \
|
||||
10000000, \
|
||||
1000, \
|
||||
0xFFFF, /* 16-bit counter */ \
|
||||
HWTIMER_CNTMODE_UP, \
|
||||
}, \
|
||||
}
|
||||
#endif /* HWTIMER7_CONFIG */
|
||||
#endif /* BSP_USING_HWTIMER7 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HWTIMER_CONFIG_H__ */
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-10-10 WangShun compatible with RT-Studio
|
||||
*/
|
||||
|
||||
#ifndef __I2C_CONFIG_H__
|
||||
#define __I2C_CONFIG_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_I2C0
|
||||
#ifndef BSP_I2C0_SCL_PIN
|
||||
#define BSP_I2C0_SCL_PIN "PB6"
|
||||
#define BSP_I2C0_SDA_PIN "PB7"
|
||||
#define BSP_I2C0_AFIO "AF4"
|
||||
#endif /* BSP_I2C0_SCL_PIN */
|
||||
#ifndef I2C0_CONFIG
|
||||
#define I2C0_CONFIG \
|
||||
{ \
|
||||
.i2c_periph = I2C0, \
|
||||
.per_clk = RCU_I2C0, \
|
||||
.scl_pin_name = BSP_I2C0_SCL_PIN, \
|
||||
.sda_pin_name = BSP_I2C0_SDA_PIN, \
|
||||
.alternate = BSP_I2C0_AFIO, \
|
||||
.i2c_bus = &i2c0, \
|
||||
.device_name = "i2c0", \
|
||||
}
|
||||
#endif /* I2C0_CONFIG */
|
||||
#endif /* BSP_USING_I2C0 */
|
||||
|
||||
#ifdef BSP_USING_I2C1
|
||||
#ifndef BSP_I2C1_SCL_PIN
|
||||
#define BSP_I2C1_SCL_PIN "PH4"
|
||||
#define BSP_I2C1_SDA_PIN "PB11"
|
||||
#define BSP_I2C1_AFIO "AF4"
|
||||
#endif /* BSP_I2C1_SCL_PIN */
|
||||
#ifndef I2C1_CONFIG
|
||||
#define I2C1_CONFIG \
|
||||
{ \
|
||||
.i2c_periph = I2C1, \
|
||||
.per_clk = RCU_I2C1, \
|
||||
.scl_pin_name = BSP_I2C1_SCL_PIN, \
|
||||
.sda_pin_name = BSP_I2C1_SDA_PIN, \
|
||||
.alternate = BSP_I2C1_AFIO, \
|
||||
.i2c_bus = &i2c1, \
|
||||
.device_name = "i2c1", \
|
||||
}
|
||||
#endif /* I2C1_CONFIG */
|
||||
#endif /* BSP_USING_I2C1 */
|
||||
|
||||
#ifdef BSP_USING_I2C2
|
||||
#ifndef BSP_I2C2_SCL_PIN
|
||||
#define BSP_I2C2_SCL_PIN "PA8"
|
||||
#define BSP_I2C2_SDA_PIN "PC9"
|
||||
#define BSP_I2C2_AFIO "AF4"
|
||||
#endif /* BSP_I2C2_SCL_PIN */
|
||||
#ifndef I2C2_CONFIG
|
||||
#define I2C2_CONFIG \
|
||||
{ \
|
||||
.i2c_periph = I2C2, \
|
||||
.per_clk = RCU_I2C2, \
|
||||
.scl_pin_name = BSP_I2C2_SCL_PIN, \
|
||||
.sda_pin_name = BSP_I2C2_SDA_PIN, \
|
||||
.alternate = BSP_I2C2_AFIO, \
|
||||
.i2c_bus = &i2c2, \
|
||||
.device_name = "i2c2", \
|
||||
}
|
||||
#endif /* I2C2_CONFIG */
|
||||
#endif /* BSP_USING_I2C2 */
|
||||
|
||||
#ifdef BSP_USING_I2C3
|
||||
#ifndef BSP_I2C3_SCL_PIN
|
||||
#define BSP_I2C3_SCL_PIN "PD12"
|
||||
#define BSP_I2C3_SDA_PIN "PD13"
|
||||
#define BSP_I2C3_AFIO "AF4"
|
||||
#endif /* BSP_I2C3_SCL_PIN */
|
||||
#ifndef I2C3_CONFIG
|
||||
#define I2C3_CONFIG \
|
||||
{ \
|
||||
.i2c_periph = I2C3, \
|
||||
.per_clk = RCU_I2C3, \
|
||||
.scl_pin_name = BSP_I2C3_SCL_PIN, \
|
||||
.sda_pin_name = BSP_I2C3_SDA_PIN, \
|
||||
.alternate = BSP_I2C3_AFIO, \
|
||||
.i2c_bus = &i2c3, \
|
||||
.device_name = "i2c3", \
|
||||
}
|
||||
#endif /* I2C3_CONFIG */
|
||||
#endif /* BSP_USING_I2C3 */
|
||||
|
||||
#ifdef BSP_USING_I2C4
|
||||
#ifndef BSP_I2C4_SCL_PIN
|
||||
#define BSP_I2C4_SCL_PIN "PG7"
|
||||
#define BSP_I2C4_SDA_PIN "PG8"
|
||||
#define BSP_I2C4_AFIO "AF6"
|
||||
#endif /* BSP_I2C4_SCL_PIN */
|
||||
#ifndef I2C4_CONFIG
|
||||
#define I2C4_CONFIG \
|
||||
{ \
|
||||
.i2c_periph = I2C4, \
|
||||
.per_clk = RCU_I2C4, \
|
||||
.scl_pin_name = BSP_I2C4_SCL_PIN, \
|
||||
.sda_pin_name = BSP_I2C4_SDA_PIN, \
|
||||
.alternate = BSP_I2C4_AFIO, \
|
||||
.i2c_bus = &i2c4, \
|
||||
.device_name = "i2c4", \
|
||||
}
|
||||
#endif /* I2C4_CONFIG */
|
||||
#endif /* BSP_USING_I2C4 */
|
||||
|
||||
#ifdef BSP_USING_I2C5
|
||||
#ifndef BSP_I2C5_SCL_PIN
|
||||
#define BSP_I2C5_SCL_PIN "PF11"
|
||||
#define BSP_I2C5_SDA_PIN "PF12"
|
||||
#define BSP_I2C5_AFIO "AF4"
|
||||
#endif /* BSP_I2C5_SCL_PIN */
|
||||
#ifndef I2C5_CONFIG
|
||||
#define I2C5_CONFIG \
|
||||
{ \
|
||||
.i2c_periph = I2C5, \
|
||||
.per_clk = RCU_I2C5, \
|
||||
.scl_pin_name = BSP_I2C5_SCL_PIN, \
|
||||
.sda_pin_name = BSP_I2C5_SDA_PIN, \
|
||||
.alternate = BSP_I2C5_AFIO, \
|
||||
.i2c_bus = &i2c5, \
|
||||
.device_name = "i2c5", \
|
||||
}
|
||||
#endif /* I2C5_CONFIG */
|
||||
#endif /* BSP_USING_I2C5 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__I2C_CONFIG_H__ */
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-10-11 kurisaw compatible with RT-Studio
|
||||
*/
|
||||
|
||||
#ifndef __PWM_CONFIG_H__
|
||||
#define __PWM_CONFIG_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_PWM0
|
||||
|
||||
#ifndef PWM0_CONFIG
|
||||
#define PWM0_CONFIG \
|
||||
{ \
|
||||
.timer_periph = TIMER0, \
|
||||
.name = "pwm0", \
|
||||
.timer_clk = RCU_TIMER0, \
|
||||
.pin_name = BSP_PWM0_PIN, \
|
||||
.channel = BSP_PWM0_CHANNEL, \
|
||||
.alternate = BSP_PWM0_AFIO, \
|
||||
}
|
||||
#endif /* PWM0_CONFIG */
|
||||
#endif /* BSP_USING_PWM0 */
|
||||
|
||||
#ifdef BSP_USING_PWM1
|
||||
|
||||
#ifndef PWM1_CONFIG
|
||||
#define PWM1_CONFIG \
|
||||
{ \
|
||||
.timer_periph = TIMER1, \
|
||||
.name = "pwm1", \
|
||||
.timer_clk = RCU_TIMER1, \
|
||||
.pin_name = BSP_PWM1_PIN, \
|
||||
.channel = BSP_PWM1_CHANNEL, \
|
||||
.alternate = BSP_PWM1_AFIO, \
|
||||
}
|
||||
#endif /* PWM1_CONFIG */
|
||||
#endif /* BSP_USING_PWM1 */
|
||||
|
||||
#ifdef BSP_USING_PWM2
|
||||
|
||||
#ifndef PWM2_CONFIG
|
||||
#define PWM2_CONFIG \
|
||||
{ \
|
||||
.timer_periph = TIMER2, \
|
||||
.name = "pwm2", \
|
||||
.timer_clk = RCU_TIMER2, \
|
||||
.pin_name = BSP_PWM2_PIN, \
|
||||
.channel = BSP_PWM2_CHANNEL, \
|
||||
.alternate = BSP_PWM2_AFIO, \
|
||||
}
|
||||
#endif /* PWM2_CONFIG */
|
||||
#endif /* BSP_USING_PWM2 */
|
||||
|
||||
#ifdef BSP_USING_PWM3
|
||||
|
||||
#ifndef PWM3_CONFIG
|
||||
#define PWM3_CONFIG \
|
||||
{ \
|
||||
.timer_periph = TIMER3, \
|
||||
.name = "pwm3", \
|
||||
.timer_clk = RCU_TIMER3, \
|
||||
.pin_name = BSP_PWM3_PIN, \
|
||||
.channel = BSP_PWM3_CHANNEL, \
|
||||
.alternate = BSP_PWM3_AFIO, \
|
||||
}
|
||||
#endif /* PWM3_CONFIG */
|
||||
#endif /* BSP_USING_PWM3 */
|
||||
|
||||
#ifdef BSP_USING_PWM4
|
||||
|
||||
#ifndef PWM4_CONFIG
|
||||
#define PWM4_CONFIG \
|
||||
{ \
|
||||
.timer_periph = TIMER4, \
|
||||
.name = "pwm4", \
|
||||
.timer_clk = RCU_TIMER4, \
|
||||
.pin_name = BSP_PWM4_PIN, \
|
||||
.channel = BSP_PWM4_CHANNEL, \
|
||||
.alternate = BSP_PWM4_AFIO, \
|
||||
}
|
||||
#endif /* PWM4_CONFIG */
|
||||
#endif /* BSP_USING_PWM4 */
|
||||
|
||||
#ifdef BSP_USING_PWM5
|
||||
|
||||
#ifndef PWM5_CONFIG
|
||||
#define PWM5_CONFIG \
|
||||
{ \
|
||||
.timer_periph = TIMER5, \
|
||||
.name = "pwm5", \
|
||||
.timer_clk = RCU_TIMER5, \
|
||||
.pin_name = BSP_PWM5_PIN, \
|
||||
.channel = BSP_PWM5_CHANNEL, \
|
||||
.alternate = BSP_PWM5_AFIO, \
|
||||
}
|
||||
#endif /* PWM5_CONFIG */
|
||||
#endif /* BSP_USING_PWM5 */
|
||||
|
||||
#ifdef BSP_USING_PWM6
|
||||
|
||||
#ifndef PWM6_CONFIG
|
||||
#define PWM6_CONFIG \
|
||||
{ \
|
||||
.timer_periph = TIMER6, \
|
||||
.name = "pwm6", \
|
||||
.timer_clk = RCU_TIMER6, \
|
||||
.pin_name = BSP_PWM6_PIN, \
|
||||
.channel = BSP_PWM6_CHANNEL, \
|
||||
.alternate = BSP_PWM6_AFIO, \
|
||||
}
|
||||
#endif /* PWM6_CONFIG */
|
||||
#endif /* BSP_USING_PWM6 */
|
||||
|
||||
#ifdef BSP_USING_PWM7
|
||||
|
||||
#ifndef PWM7_CONFIG
|
||||
#define PWM7_CONFIG \
|
||||
{ \
|
||||
.timer_periph = TIMER7, \
|
||||
.name = "pwm7", \
|
||||
.timer_clk = RCU_TIMER7, \
|
||||
.pin_name = BSP_PWM7_PIN, \
|
||||
.channel = BSP_PWM7_CHANNEL, \
|
||||
.alternate = BSP_PWM7_AFIO, \
|
||||
}
|
||||
#endif /* PWM7_CONFIG */
|
||||
#endif /* BSP_USING_PWM7 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__PWM_CONFIG_H__ */
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-11-06 SummerGift first version
|
||||
* 2019-01-03 zylx modify DMA support
|
||||
* 2025-10-10 WangShun compatible with RT-Studio
|
||||
*/
|
||||
|
||||
#ifndef __SPI_CONFIG_H__
|
||||
#define __SPI_CONFIG_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef RT_SPI_USING_DMA
|
||||
#define IF_SPI_DMA(x) x
|
||||
#else
|
||||
#define IF_SPI_DMA(x)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_SPI0
|
||||
#ifndef BSP_SPI0_SCK_PIN
|
||||
#define BSP_SPI0_SCK_PIN "PA5"
|
||||
#define BSP_SPI0_MISO_PIN "PA6"
|
||||
#define BSP_SPI0_MOSI_PIN "PA7"
|
||||
#define BSP_SPI0_AFIO "AF5"
|
||||
#endif /* BSP_SPI0_SCK_PIN */
|
||||
|
||||
#ifndef SPI0_BUS_CONFIG
|
||||
#define SPI0_BUS_CONFIG \
|
||||
{ \
|
||||
.spi_periph = SPI0, \
|
||||
.bus_name = "spi0", \
|
||||
.spi_clk = RCU_SPI0, \
|
||||
.spi_bus = &spi_bus0, \
|
||||
.sck_pin_name = BSP_SPI0_SCK_PIN, \
|
||||
.miso_pin_name = BSP_SPI0_MISO_PIN, \
|
||||
.mosi_pin_name = BSP_SPI0_MOSI_PIN, \
|
||||
.alternate = BSP_SPI0_AFIO, \
|
||||
IF_SPI_DMA(.spi_dma = &spi_dma[0]) \
|
||||
}
|
||||
#endif /* SPI0_BUS_CONFIG */
|
||||
#endif /* BSP_USING_SPI0 */
|
||||
|
||||
#ifdef BSP_USING_SPI1
|
||||
#ifndef BSP_SPI1_SCK_PIN
|
||||
#define BSP_SPI1_SCK_PIN "PB13"
|
||||
#define BSP_SPI1_MISO_PIN "PB14"
|
||||
#define BSP_SPI1_MOSI_PIN "PB15"
|
||||
#define BSP_SPI1_AFIO "AF5"
|
||||
#endif /* BSP_SPI1_SCK_PIN */
|
||||
|
||||
#ifndef SPI1_BUS_CONFIG
|
||||
#define SPI1_BUS_CONFIG \
|
||||
{ \
|
||||
.spi_periph = SPI1, \
|
||||
.bus_name = "spi1", \
|
||||
.spi_clk = RCU_SPI1, \
|
||||
.spi_bus = &spi_bus1, \
|
||||
.sck_pin_name = BSP_SPI1_SCK_PIN, \
|
||||
.miso_pin_name = BSP_SPI1_MISO_PIN, \
|
||||
.mosi_pin_name = BSP_SPI1_MOSI_PIN, \
|
||||
.alternate = BSP_SPI1_AFIO, \
|
||||
IF_SPI_DMA(.spi_dma = &spi_dma[1]) \
|
||||
}
|
||||
#endif /* SPI1_BUS_CONFIG */
|
||||
#endif /* BSP_USING_SPI1 */
|
||||
|
||||
#ifdef BSP_USING_SPI2
|
||||
#ifndef BSP_SPI2_SCK_PIN
|
||||
#define BSP_SPI2_SCK_PIN "PB3"
|
||||
#define BSP_SPI2_MISO_PIN "PB4"
|
||||
#define BSP_SPI2_MOSI_PIN "PB5"
|
||||
#define BSP_SPI2_AFIO "AF6"
|
||||
#endif /* BSP_SPI1_SCK_PIN */
|
||||
|
||||
#ifndef SPI2_BUS_CONFIG
|
||||
#define SPI2_BUS_CONFIG \
|
||||
{ \
|
||||
.spi_periph = SPI2, \
|
||||
.bus_name = "spi2", \
|
||||
.spi_clk = RCU_SPI2, \
|
||||
.spi_bus = &spi_bus2, \
|
||||
.sck_pin_name = BSP_SPI2_SCK_PIN, \
|
||||
.miso_pin_name = BSP_SPI2_MISO_PIN, \
|
||||
.mosi_pin_name = BSP_SPI2_MOSI_PIN, \
|
||||
.alternate = BSP_SPI2_AFIO, \
|
||||
IF_SPI_DMA(.spi_dma = &spi_dma[2]) \
|
||||
}
|
||||
#endif /* SPI2_BUS_CONFIG */
|
||||
#endif /* BSP_USING_SPI2 */
|
||||
|
||||
#ifdef BSP_USING_SPI3
|
||||
#ifndef BSP_SPI3_SCK_PIN
|
||||
#define BSP_SPI3_SCK_PIN "PE12"
|
||||
#define BSP_SPI3_MISO_PIN "PE13"
|
||||
#define BSP_SPI3_MOSI_PIN "PE14"
|
||||
#define BSP_SPI3_AFIO "AF5"
|
||||
#endif /* BSP_SPI3_SCK_PIN */
|
||||
|
||||
#ifndef SPI3_BUS_CONFIG
|
||||
#define SPI3_BUS_CONFIG \
|
||||
{ \
|
||||
.spi_periph = SPI3, \
|
||||
.bus_name = "spi3", \
|
||||
.spi_clk = RCU_SPI3, \
|
||||
.spi_bus = &spi_bus3, \
|
||||
.sck_pin_name = BSP_SPI3_SCK_PIN, \
|
||||
.miso_pin_name = BSP_SPI3_MISO_PIN, \
|
||||
.mosi_pin_name = BSP_SPI3_MOSI_PIN, \
|
||||
.alternate = BSP_SPI3_AFIO, \
|
||||
IF_SPI_DMA(.spi_dma = &spi_dma[3]) \
|
||||
}
|
||||
#endif /* SPI3_BUS_CONFIG */
|
||||
#endif /* BSP_USING_SPI3 */
|
||||
|
||||
#ifdef BSP_USING_SPI4
|
||||
#ifndef BSP_SPI4_SCK_PIN
|
||||
#define BSP_SPI4_SCK_PIN "PF7"
|
||||
#define BSP_SPI4_MISO_PIN "PF8"
|
||||
#define BSP_SPI4_MOSI_PIN "PF9"
|
||||
#define BSP_SPI4_AFIO "AF5"
|
||||
#endif /* BSP_SPI4_SCK_PIN */
|
||||
|
||||
#ifndef SPI4_BUS_CONFIG
|
||||
#define SPI4_BUS_CONFIG \
|
||||
{ \
|
||||
.spi_periph = SPI4, \
|
||||
.bus_name = "spi4", \
|
||||
.spi_clk = RCU_SPI4, \
|
||||
.spi_bus = &spi_bus4, \
|
||||
.sck_pin_name = BSP_SPI4_SCK_PIN, \
|
||||
.miso_pin_name = BSP_SPI4_MISO_PIN, \
|
||||
.mosi_pin_name = BSP_SPI4_MOSI_PIN, \
|
||||
.alternate = BSP_SPI4_AFIO, \
|
||||
IF_SPI_DMA(.spi_dma = &spi_dma[4]) \
|
||||
}
|
||||
#endif /* SPI4_BUS_CONFIG */
|
||||
#endif /* BSP_USING_SPI4 */
|
||||
|
||||
#ifdef BSP_USING_SPI5
|
||||
#ifndef BSP_SPI5_SCK_PIN
|
||||
#define BSP_SPI5_SCK_PIN "PG13"
|
||||
#define BSP_SPI5_MISO_PIN "PG12"
|
||||
#define BSP_SPI5_MOSI_PIN "PG14"
|
||||
#define BSP_SPI5_AFIO "AF5"
|
||||
#endif /* BSP_SPI5_SCK_PIN */
|
||||
|
||||
#ifndef SPI5_BUS_CONFIG
|
||||
#define SPI5_BUS_CONFIG \
|
||||
{ \
|
||||
.spi_periph = SPI5, \
|
||||
.bus_name = "spi5", \
|
||||
.spi_clk = RCU_SPI5, \
|
||||
.spi_bus = &spi_bus5, \
|
||||
.sck_pin_name = BSP_SPI5_SCK_PIN, \
|
||||
.miso_pin_name = BSP_SPI5_MISO_PIN, \
|
||||
.mosi_pin_name = BSP_SPI5_MOSI_PIN, \
|
||||
.alternate = BSP_SPI5_AFIO, \
|
||||
IF_SPI_DMA(.spi_dma = &spi_dma[5]) \
|
||||
}
|
||||
#endif /* SPI5_BUS_CONFIG */
|
||||
#endif /* BSP_USING_SPI5 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__SPI_CONFIG_H__ */
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-10-30 SummerGift first version
|
||||
* 2019-01-03 zylx modify dma support
|
||||
* 2025-10-09 WangShun compatible with RT-Studio
|
||||
*/
|
||||
|
||||
#ifndef __UART_CONFIG_H__
|
||||
#define __UART_CONFIG_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef BSP_UART0_AFIO
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32F5xx || defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E
|
||||
#define BSP_UART0_AFIO "AF4"
|
||||
#elif defined SOC_SERIES_GD32E23x
|
||||
#define BSP_UART0_AFIO "AF1"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef BSP_UART1_AFIO
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32F5xx || defined SOC_SERIES_GD32H7xx || defined SOC_SERIES_GD32H75E
|
||||
#define BSP_UART1_AFIO "AF7"
|
||||
#elif defined SOC_SERIES_GD32E23x
|
||||
#define BSP_UART1_AFIO "AF1"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef BSP_UART2_AFIO
|
||||
#define BSP_UART2_AFIO "AF7"
|
||||
#endif
|
||||
|
||||
#ifndef BSP_UART3_AFIO
|
||||
#define BSP_UART3_AFIO "AF8"
|
||||
#endif
|
||||
|
||||
#ifndef BSP_UART4_AFIO
|
||||
#define BSP_UART4_AFIO "AF8"
|
||||
#endif
|
||||
|
||||
#ifndef BSP_UART5_AFIO
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32F5xx
|
||||
#define BSP_UART5_AFIO "AF8"
|
||||
#elif defined (SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E)
|
||||
#define BSP_UART5_AFIO "AF7"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef BSP_UART6_AFIO
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32F5xx
|
||||
#define BSP_UART6_AFIO "AF8"
|
||||
#elif defined (SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E)
|
||||
#define BSP_UART6_AFIO "AF7"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef BSP_UART7_AFIO
|
||||
#define BSP_UART7_AFIO "AF8"
|
||||
#endif
|
||||
|
||||
#if defined(BSP_USING_UART0)
|
||||
#ifndef UART0_CONFIG
|
||||
#define UART0_CONFIG \
|
||||
{ \
|
||||
.uart_periph = USART0, \
|
||||
.irqn = USART0_IRQn, \
|
||||
.per_clk = RCU_USART0, \
|
||||
.tx_pin_name = BSP_UART0_TX_PIN, \
|
||||
.rx_pin_name = BSP_UART0_RX_PIN, \
|
||||
.alternate = BSP_UART0_AFIO, \
|
||||
.serial = &serial0, \
|
||||
.device_name = "uart0", \
|
||||
}
|
||||
#endif /* UART0_CONFIG */
|
||||
#endif /* BSP_USING_UART0 */
|
||||
|
||||
#if defined(BSP_USING_UART1)
|
||||
#ifndef UART1_CONFIG
|
||||
#define UART1_CONFIG \
|
||||
{ \
|
||||
.uart_periph = USART1, \
|
||||
.irqn = USART1_IRQn, \
|
||||
.per_clk = RCU_USART1, \
|
||||
.tx_pin_name = BSP_UART1_TX_PIN, \
|
||||
.rx_pin_name = BSP_UART1_RX_PIN, \
|
||||
.alternate = BSP_UART1_AFIO, \
|
||||
.serial = &serial1, \
|
||||
.device_name = "uart1", \
|
||||
}
|
||||
#endif /* UART1_CONFIG */
|
||||
#endif /* BSP_USING_UART1 */
|
||||
|
||||
#if defined(BSP_USING_UART2)
|
||||
#ifndef UART2_CONFIG
|
||||
#define UART2_CONFIG \
|
||||
{ \
|
||||
.uart_periph = USART2, \
|
||||
.irqn = USART2_IRQn, \
|
||||
.per_clk = RCU_USART2, \
|
||||
.tx_pin_name = BSP_UART2_TX_PIN, \
|
||||
.rx_pin_name = BSP_UART2_RX_PIN, \
|
||||
.alternate = BSP_UART2_AFIO, \
|
||||
.serial = &serial2, \
|
||||
.device_name = "uart2", \
|
||||
}
|
||||
#endif /* UART2_CONFIG */
|
||||
#endif /* BSP_USING_UART2 */
|
||||
|
||||
#if defined(BSP_USING_UART3)
|
||||
#ifndef UART3_CONFIG
|
||||
#define UART3_CONFIG \
|
||||
{ \
|
||||
.uart_periph = UART3, \
|
||||
.irqn = UART3_IRQn, \
|
||||
.per_clk = RCU_UART3, \
|
||||
.tx_pin_name = BSP_UART3_TX_PIN, \
|
||||
.rx_pin_name = BSP_UART3_RX_PIN, \
|
||||
.alternate = BSP_UART3_AFIO, \
|
||||
.serial = &serial3, \
|
||||
.device_name = "uart3", \
|
||||
}
|
||||
#endif /* UART3_CONFIG */
|
||||
#endif /* BSP_USING_UART3 */
|
||||
|
||||
#if defined(BSP_USING_UART4)
|
||||
#ifndef UART4_CONFIG
|
||||
#define UART4_CONFIG \
|
||||
{ \
|
||||
.uart_periph = UART4, \
|
||||
.irqn = UART4_IRQn, \
|
||||
.per_clk = RCU_UART4, \
|
||||
.tx_pin_name = BSP_UART4_TX_PIN, \
|
||||
.rx_pin_name = BSP_UART4_RX_PIN, \
|
||||
.alternate = BSP_UART4_AFIO, \
|
||||
.serial = &serial4, \
|
||||
.device_name = "uart4", \
|
||||
}
|
||||
#endif /* UART4_CONFIG */
|
||||
#endif /* BSP_USING_UART4 */
|
||||
|
||||
#if defined(BSP_USING_UART5)
|
||||
#ifndef UART5_CONFIG
|
||||
#define UART5_CONFIG \
|
||||
{ \
|
||||
.uart_periph = USART5, \
|
||||
.irqn = USART5_IRQn, \
|
||||
.per_clk = RCU_USART5, \
|
||||
.tx_pin_name = BSP_UART5_TX_PIN, \
|
||||
.rx_pin_name = BSP_UART5_RX_PIN, \
|
||||
.alternate = BSP_UART5_AFIO, \
|
||||
.serial = &serial5, \
|
||||
.device_name = "uart5", \
|
||||
}
|
||||
#endif /* UART5_CONFIG */
|
||||
#endif /* BSP_USING_UART5 */
|
||||
|
||||
#if defined(BSP_USING_UART6)
|
||||
#ifndef UART6_CONFIG
|
||||
#define UART6_CONFIG \
|
||||
{ \
|
||||
.uart_periph = UART6, \
|
||||
.irqn = UART6_IRQn, \
|
||||
.per_clk = RCU_UART6, \
|
||||
.tx_pin_name = BSP_UART6_TX_PIN, \
|
||||
.rx_pin_name = BSP_UART6_RX_PIN, \
|
||||
.alternate = BSP_UART6_AFIO, \
|
||||
.serial = &serial6, \
|
||||
.device_name = "uart6", \
|
||||
}
|
||||
#endif /* UART6_CONFIG */
|
||||
#endif /* BSP_USING_UART6 */
|
||||
|
||||
#if defined(BSP_USING_UART7)
|
||||
#ifndef UART7_CONFIG
|
||||
#define UART7_CONFIG \
|
||||
{ \
|
||||
.uart_periph = UART7, \
|
||||
.irqn = UART7_IRQn, \
|
||||
.per_clk = RCU_UART7, \
|
||||
.tx_pin_name = BSP_UART7_TX_PIN, \
|
||||
.rx_pin_name = BSP_UART7_RX_PIN, \
|
||||
.alternate = BSP_UART7_AFIO, \
|
||||
.serial = &serial7, \
|
||||
.device_name = "uart7", \
|
||||
}
|
||||
#endif /* UART7_CONFIG */
|
||||
#endif /* BSP_USING_UART7 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __UART_CONFIG_H__ */
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-05-03 BruceOu first implementation
|
||||
* 2025-10-22 kurisaw optimize multi-channel GPIO configuration
|
||||
*/
|
||||
|
||||
#ifndef __DRV_ADC_H__
|
||||
#define __DRV_ADC_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
#include "drv_gpio.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_EXTERN_ADC_CHANNEL 20
|
||||
|
||||
/* gd32 adc driver class */
|
||||
struct gd32_adc
|
||||
{
|
||||
uint32_t adc_periph;
|
||||
rcu_periph_enum adc_clk;
|
||||
const char *adc_pins[MAX_EXTERN_ADC_CHANNEL];
|
||||
struct rt_adc_device *adc;
|
||||
char *device_name;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DRV_ADC_H__ */
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#ifndef __DRV_CAN_H__
|
||||
#define __DRV_CAN_H__
|
||||
|
||||
#include <rtdevice.h>
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_CAN
|
||||
/* Aliases for __IRQn */
|
||||
#if defined(BSP_USING_CAN0) || defined(BSP_USING_CAN1) || defined(BSP_USING_CAN2)
|
||||
/* BSP_USING_CAN0 */
|
||||
#define CAN0_TX_IRQn CAN0_Message_IRQn
|
||||
#define CAN0_RX_IRQn CAN0_Message_IRQn
|
||||
#define CAN0_ERROR_IRQn CAN0_Error_IRQn
|
||||
/* BSP_USING_CAN1 */
|
||||
#define CAN1_TX_IRQn CAN1_Message_IRQn
|
||||
#define CAN1_RX_IRQn CAN1_Message_IRQn
|
||||
#define CAN1_ERROR_IRQn CAN1_Error_IRQn
|
||||
/* BSP_USING_CAN2 */
|
||||
#define CAN2_TX_IRQn CAN2_Message_IRQn
|
||||
#define CAN2_RX_IRQn CAN2_Message_IRQn
|
||||
#define CAN2_ERROR_IRQn CAN2_Error_IRQn
|
||||
#endif
|
||||
|
||||
struct gd32_baud_rate_tab
|
||||
{
|
||||
uint32_t baud_rate;
|
||||
uint8_t resync_jump_width;
|
||||
uint8_t prop_time_segment;
|
||||
uint8_t time_segment_1;
|
||||
uint8_t time_segment_2;
|
||||
uint32_t prescaler;
|
||||
};
|
||||
#ifdef RT_CAN_USING_CANFD
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rt_uint32_t baud;
|
||||
rt_uint8_t sjw;
|
||||
rt_uint8_t prop;
|
||||
rt_uint8_t seg1;
|
||||
rt_uint8_t seg2;
|
||||
rt_uint16_t prescaler;
|
||||
} gd32_fd_data_baud_t;
|
||||
|
||||
enum CANFD_BAUD
|
||||
{
|
||||
CANFD_5MBaud = 5000UL * 1000, /* 5 MBit/sec */
|
||||
CANFD_4MBaud = 4000UL * 1000, /* 4 MBit/sec */
|
||||
CANFD_3MBaud = 3000UL * 1000, /* 3 MBit/sec */
|
||||
CANFD_2MBaud = 2000UL * 1000, /* 2 MBit/sec */
|
||||
CANFD_1MBaud = 1000UL * 1000, /* 1 MBit/sec */
|
||||
CANFD_800kBaud = 1000UL * 800, /* 800 kBit/sec */
|
||||
CANFD_500kBaud = 1000UL * 500, /* 500 kBit/sec */
|
||||
CANFD_250kBaud = 1000UL * 250, /* 250 kBit/sec */
|
||||
CANFD_125kBaud = 1000UL * 125, /* 125 kBit/sec */
|
||||
CANFD_100kBaud = 1000UL * 100, /* 100 kBit/sec */
|
||||
CANFD_50kBaud = 1000UL * 50, /* 50 kBit/sec */
|
||||
CANFD_20kBaud = 1000UL * 20, /* 20 kBit/sec */
|
||||
CANFD_10kBaud = 1000UL * 10 /* 10 kBit/sec */
|
||||
};
|
||||
#endif
|
||||
|
||||
/* gd32 can device */
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
const char *tx_pin_name; /* can pin name */
|
||||
const char *rx_pin_name; /* rx pin name */
|
||||
const char *alternate;
|
||||
uint32_t can_periph;
|
||||
can_parameter_struct can_init;
|
||||
can_fifo_parameter_struct can_fifo;
|
||||
can_operation_modes_enum mode;
|
||||
can_mailbox_descriptor_struct tx_message[16];
|
||||
can_mailbox_descriptor_struct rx_message[16];
|
||||
rt_uint8_t rx_message_valid[16];
|
||||
void (*filter_cb)(uint32_t can_periph);
|
||||
#ifdef RT_CAN_USING_CANFD
|
||||
can_fd_parameter_struct can_fd_init;
|
||||
rt_uint8_t fd_enabled;
|
||||
rt_uint8_t fd_rx_buf[16][64];
|
||||
#endif
|
||||
struct rt_can_device *device; /* can device */
|
||||
} gd32_can_struct;
|
||||
|
||||
void can_gpio_config(void);
|
||||
int rt_hw_can_init(void);
|
||||
#endif /* RT_USING_CAN */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DRV_CAN_H__ */
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-09-0 WangShun first implementation
|
||||
*/
|
||||
|
||||
#ifndef __DRV_COMMON_H__
|
||||
#define __DRV_COMMON_H__
|
||||
|
||||
#include "drv_usart.h"
|
||||
#include "drv_gpio.h"
|
||||
#include <board.h>
|
||||
|
||||
#define GD32_FLASH_START_ADRESS ROM_START
|
||||
#define GD32_FLASH_SIZE ROM_SIZE
|
||||
#define GD32_FLASH_END_ADDRESS ROM_END
|
||||
|
||||
#define GD32_SRAM_SIZE RAM_SIZE
|
||||
#define GD32_SRAM_START RAM_START
|
||||
#define GD32_SRAM_END RAM_END
|
||||
|
||||
#ifdef __ARMCC_VERSION
|
||||
extern int Image$$RW_IRAM1$$ZI$$Limit;
|
||||
#define HEAP_BEGIN (&Image$$RW_IRAM1$$ZI$$Limit)
|
||||
#elif __ICCARM__
|
||||
#pragma section="HEAP"
|
||||
#define HEAP_BEGIN (__segment_end("HEAP"))
|
||||
#else
|
||||
extern int __bss_end;
|
||||
#define HEAP_BEGIN (&__bss_end)
|
||||
#endif
|
||||
|
||||
#define HEAP_END GD32_SRAM_END
|
||||
|
||||
#endif /* __DRV_COMMON_H__ */
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* drv_config.h for GD32 platform
|
||||
*/
|
||||
#ifndef __DRV_CONFIG_H__
|
||||
#define __DRV_CONFIG_H__
|
||||
|
||||
#include <board.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Include peripheral configuration headers under drivers/include/config */
|
||||
#include "config/uart_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DRV_CONFIG_H__ */
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-10-11 kurisaw first version
|
||||
*/
|
||||
|
||||
#ifndef __DRV_DAC_H__
|
||||
#define __DRV_DAC_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(RT_USING_DAC)
|
||||
|
||||
/* gd32 dac driver class */
|
||||
struct gd32_dac
|
||||
{
|
||||
struct rt_dac_device dac_device;
|
||||
uint32_t dac_periph;
|
||||
char *name;
|
||||
const char *pin_name;
|
||||
rt_int16_t channel;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DRV_DAC_H__ */
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-03-19 Evlers first implementation
|
||||
*/
|
||||
|
||||
#ifndef _DRV_DMA_H_
|
||||
#define _DRV_DMA_H_
|
||||
|
||||
|
||||
#if defined SOC_SERIES_GD32E23x
|
||||
#define DRV_DMA_CONFIG(chx) \
|
||||
(struct dma_config)
|
||||
{ \
|
||||
.periph = DMA, \
|
||||
.rcu = RCU_DMA, \
|
||||
.channel = DMA_CH##chx, \
|
||||
.irq = ((chx) == 0 ? DMA_Channel0_IRQn : \
|
||||
(chx) == 1 ? DMA_Channel1_2_IRQn : \
|
||||
(chx) == 2 ? DMA_Channel1_2_IRQn : \
|
||||
(chx) == 3 ? DMA_Channel3_4_IRQn : \
|
||||
(chx) == 4 ? DMA_Channel3_4_IRQn : (IRQn_Type)0) \
|
||||
}
|
||||
struct dma_config
|
||||
{
|
||||
uint32_t periph;
|
||||
rcu_periph_enum rcu;
|
||||
dma_channel_enum channel;
|
||||
IRQn_Type irq;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#define DRV_DMA_CONFIG(dmax, chx, subx) { \
|
||||
.periph = DMA##dmax, \
|
||||
.channel = DMA_CH##chx, \
|
||||
.rcu = RCU_DMA##dmax, \
|
||||
.subperiph = DMA_SUBPERI##subx, \
|
||||
.irq = DMA##dmax##_Channel##chx##_IRQn, \
|
||||
}
|
||||
|
||||
struct dma_config
|
||||
{
|
||||
uint32_t periph;
|
||||
rcu_periph_enum rcu;
|
||||
dma_channel_enum channel;
|
||||
dma_subperipheral_enum subperiph;
|
||||
IRQn_Type irq;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _DRV_DMA_H_ */
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-10 kurisaw the first version
|
||||
*/
|
||||
|
||||
#ifndef __DRV_ENET_H__
|
||||
#define __DRV_ENET_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <board.h>
|
||||
|
||||
#if defined(RT_USING_SAL) && defined(RT_USING_NETDEV) && defined(RT_USING_LWIP)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "gd32h7xx.h"
|
||||
#include "synopsys_emac.h"
|
||||
|
||||
#define EMAC_RXBUFNB 5
|
||||
#define EMAC_TXBUFNB 5
|
||||
|
||||
#define EMAC_PHY_AUTO 0
|
||||
#define EMAC_PHY_10MBIT 1
|
||||
#define EMAC_PHY_100MBIT 2
|
||||
|
||||
#define MAX_ADDR_LEN 6
|
||||
|
||||
/* ENET pin configuration structure */
|
||||
struct enet_pin_config
|
||||
{
|
||||
const char *pin_name; /* Pin name in format "PxY" */
|
||||
const char *alternate; /* Alternate function in format "AFx" */
|
||||
};
|
||||
|
||||
/* ENET configuration structure */
|
||||
struct enet_config
|
||||
{
|
||||
const struct enet_pin_config *pins;
|
||||
uint32_t pin_count;
|
||||
uint32_t enet_periph;
|
||||
rcu_periph_enum enet_clk;
|
||||
rcu_periph_enum enet_tx_clk;
|
||||
rcu_periph_enum enet_rx_clk;
|
||||
uint32_t phy_interface;
|
||||
uint32_t speed; /* GPIO speed - common for all pins */
|
||||
uint8_t otype; /* Output type - common for all pins */
|
||||
uint8_t pupd; /* Pull-up/pull-down - common for all pins */
|
||||
};
|
||||
|
||||
struct gd32_emac
|
||||
{
|
||||
/* inherit from Ethernet device */
|
||||
struct eth_device parent;
|
||||
|
||||
__ALIGNED(4)
|
||||
rt_uint8_t phy_mode;
|
||||
/* interface address info. */
|
||||
__ALIGNED(4)
|
||||
rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */
|
||||
|
||||
const struct enet_pin_config *pins;
|
||||
uint32_t pin_count;
|
||||
struct rt_synopsys_eth *ETHERNET_MAC;
|
||||
IRQn_Type ETHER_MAC_IRQ;
|
||||
|
||||
EMAC_DMADESCTypeDef *DMATxDescToSet;
|
||||
EMAC_DMADESCTypeDef *DMARxDescToGet;
|
||||
|
||||
#pragma pack(4)
|
||||
EMAC_DMADESCTypeDef DMARxDscrTab[EMAC_RXBUFNB];
|
||||
#pragma pack(4)
|
||||
EMAC_DMADESCTypeDef DMATxDscrTab[EMAC_TXBUFNB];
|
||||
#pragma pack(4)
|
||||
rt_uint8_t Rx_Buff[EMAC_RXBUFNB][EMAC_MAX_PACKET_SIZE];
|
||||
#pragma pack(4)
|
||||
rt_uint8_t Tx_Buff[EMAC_TXBUFNB][EMAC_MAX_PACKET_SIZE];
|
||||
|
||||
struct rt_semaphore tx_buf_free;
|
||||
};
|
||||
|
||||
/* Function declarations */
|
||||
rt_err_t gd32_enet_gpio_init(struct gd32_emac *emac);
|
||||
const struct enet_config *gd32_get_enet_config(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RT_USING_SAL && RT_USING_NETDEV && RT_USING_LWIP */
|
||||
#endif /* __DRV_ENET_H__ */
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-08-20 BruceOu the first version
|
||||
*/
|
||||
|
||||
#ifndef __DRV_GPIO_H__
|
||||
#define __DRV_GPIO_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined SOC_SERIES_GD32F10x
|
||||
#include "gd32f10x_gpio.h"
|
||||
#elif defined SOC_SERIES_GD32F20x
|
||||
#include "gd32f20x_gpio.h"
|
||||
#elif defined SOC_SERIES_GD32F30x
|
||||
#include "gd32f30x_gpio.h"
|
||||
#elif defined SOC_SERIES_GD32F4xx
|
||||
#include "gd32f4xx_gpio.h"
|
||||
#elif defined SOC_SERIES_GD32H7xx
|
||||
#include "gd32h7xx_gpio.h"
|
||||
#elif defined SOC_SERIES_GD32H75e
|
||||
#include "gd32h75e_gpio.h"
|
||||
#elif defined SOC_SERIES_GD32E50x
|
||||
#include "gd32e50x_gpio.h"
|
||||
#elif defined SOC_SERIES_GD32F5xx
|
||||
#include "gd32f5xx_gpio.h"
|
||||
#elif defined SOC_SERIES_GD32E23x
|
||||
#include "gd32e23x_gpio.h"
|
||||
#endif
|
||||
|
||||
#define __GD32_PORT(port) GPIO##port
|
||||
|
||||
#if defined SOC_SERIES_GD32F4xx || defined SOC_SERIES_GD32F5xx || defined SOC_SERIES_GD32E23x || defined SOC_SERIES_GD32H75E || defined SOC_SERIES_GD32H7xx
|
||||
#define GD32_PIN(index, port, pin) {index, RCU_GPIO##port, \
|
||||
GPIO##port, GPIO_PIN_##pin, \
|
||||
EXTI_SOURCE_GPIO##port, \
|
||||
EXTI_SOURCE_PIN##pin, \
|
||||
EXTI_##pin}
|
||||
#else
|
||||
#define GD32_PIN(index, port, pin) {index, RCU_GPIO##port, \
|
||||
GPIO##port, GPIO_PIN_##pin, \
|
||||
GPIO_PORT_SOURCE_GPIO##port, \
|
||||
GPIO_PIN_SOURCE_##pin}
|
||||
|
||||
#endif
|
||||
|
||||
#define GD32_PIN_DEFAULT {-1, (rcu_periph_enum)0, 0, 0, 0, 0}
|
||||
|
||||
#define GET_PIN(PORTx,PIN) (rt_base_t)((16 * ( ((rt_base_t)__GD32_PORT(PORTx) - (rt_base_t)GPIO_BASE)/(0x0400UL) )) + PIN)
|
||||
|
||||
#define PIN_PORT(pin) ((uint8_t)(((pin) >> 4) & 0xFu))
|
||||
#define PIN_NO(pin) ((uint8_t)((pin) & 0xFu))
|
||||
|
||||
#define PIN_GDPORT(pin) (GPIO_BASE + (0x400u * PIN_PORT(pin)))
|
||||
#define PIN_GDPIN(pin) ((uint16_t)(1u << PIN_NO(pin)))
|
||||
|
||||
struct pin_index
|
||||
{
|
||||
rt_int16_t index;
|
||||
rcu_periph_enum clk;
|
||||
rt_uint32_t gpio_periph;
|
||||
rt_uint32_t pin;
|
||||
rt_uint8_t port_src;
|
||||
rt_uint8_t pin_src;
|
||||
rt_uint32_t exit_line;
|
||||
};
|
||||
|
||||
struct pin_irq_map
|
||||
{
|
||||
rt_uint16_t pinbit;
|
||||
IRQn_Type irqno;
|
||||
};
|
||||
|
||||
int get_pin_config(const char *pin_name, uint32_t *port, uint32_t *pin, rcu_periph_enum *clk);
|
||||
int pin_alternate_config(const char *alternate, uint32_t *af);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DRV_GPIO_H__ */
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-10-22 kurisaw first version
|
||||
*/
|
||||
|
||||
#ifndef __DRV_HWTIMER_H__
|
||||
#define __DRV_HWTIMER_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_HWTIMER
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t reg_base;
|
||||
IRQn_Type irqn;
|
||||
rcu_periph_enum rcu;
|
||||
} gd32_hwtimer_data;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char dev_name[RT_NAME_MAX];
|
||||
const gd32_hwtimer_data hw_data;
|
||||
rt_hwtimer_t hwtimer_dev;
|
||||
const struct rt_hwtimer_info hwtimer_info;
|
||||
} gd32_hwtimer_device;
|
||||
|
||||
enum timer_index
|
||||
{
|
||||
#ifdef BSP_USING_HWTIMER0
|
||||
TIM0_INDEX,
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER1
|
||||
TIM1_INDEX,
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER2
|
||||
TIM2_INDEX,
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER3
|
||||
TIM3_INDEX,
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER4
|
||||
TIM4_INDEX,
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER5
|
||||
TIM5_INDEX,
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER6
|
||||
TIM6_INDEX,
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER7
|
||||
TIM7_INDEX,
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DRV_HWTIMER_H__ */
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-12-20 BruceOu the first version
|
||||
* 2025-10-10 WangShun compatible with RT-Studio
|
||||
*/
|
||||
|
||||
#ifndef __DRV_I2C__
|
||||
#define __DRV_I2C__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
#include <rtdevice.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* GD32 i2c driver */
|
||||
struct gd32_i2c_bus
|
||||
{
|
||||
uint32_t i2c_periph;
|
||||
rcu_periph_enum per_clk;
|
||||
|
||||
const char *scl_pin_name; /* scl pin name */
|
||||
const char *sda_pin_name; /* sda pin name */
|
||||
const char *alternate; /* afio name */
|
||||
|
||||
struct rt_i2c_bus_device *i2c_bus;
|
||||
char *device_name;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DRV_I2C__ */
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#ifndef __DRV_LCD_H__
|
||||
#define __DRV_LCD_H__
|
||||
|
||||
#include <board.h>
|
||||
|
||||
#if defined(SOC_SERIES_GD32H7xx)
|
||||
#include "gd32h7xx_tli.h"
|
||||
#include "gd32h7xx_ipa.h"
|
||||
#endif
|
||||
|
||||
#define HORIZONTAL_SYNCHRONOUS_PULSE 41
|
||||
#define HORIZONTAL_BACK_PORCH 2
|
||||
#define ACTIVE_WIDTH 480
|
||||
#define HORIZONTAL_FRONT_PORCH 2
|
||||
|
||||
#define VERTICAL_SYNCHRONOUS_PULSE 10
|
||||
#define VERTICAL_BACK_PORCH 2
|
||||
#define ACTIVE_HEIGHT 272
|
||||
#define VERTICAL_FRONT_PORCH 2
|
||||
|
||||
#define LCD_WIGHT ACTIVE_WIDTH
|
||||
#define LCD_HIGHT ACTIVE_HEIGHT
|
||||
#define PIXEL_FORMAT LAYER_PPF_RGB565
|
||||
#define PRE_PIXEL_BYTES 2
|
||||
|
||||
typedef struct _RGB_DATA
|
||||
{
|
||||
uint8_t Alpha;
|
||||
uint8_t R;
|
||||
uint8_t G;
|
||||
uint8_t B;
|
||||
} RGB;
|
||||
|
||||
extern RGB color_write;
|
||||
extern RGB color_black;
|
||||
extern RGB color_red;
|
||||
extern RGB color_blue;
|
||||
extern RGB color_green;
|
||||
extern RGB color_yellow;
|
||||
extern RGB color_cyan;
|
||||
extern RGB color_magenta;
|
||||
extern RGB color_orange;
|
||||
extern RGB color_purple;
|
||||
extern RGB color_gray;
|
||||
extern RGB color_lightgray;
|
||||
extern RGB color_darkgray;
|
||||
extern RGB color_brown;
|
||||
extern RGB color_pink;
|
||||
extern RGB color_gold;
|
||||
extern RGB color_silver;
|
||||
|
||||
void lcd_draw_picture(uint32_t picture_addr, uint32_t picture_width, uint32_t picture_height, uint32_t picture_x, uint32_t picture_y);
|
||||
void lcd_draw_point(uint32_t point_x, uint32_t point_y, RGB *color);
|
||||
uint32_t to_RGB565(RGB *color);
|
||||
|
||||
#endif // __DRV_LCD_H__
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-09-12 RTT the first version
|
||||
*/
|
||||
#ifndef DRIVERS_DRV_LEGACY_H_
|
||||
#define DRIVERS_DRV_LEGACY_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "rtdef.h"
|
||||
|
||||
#if RTTHREAD_VERSION <= 40101
|
||||
#if defined(RT_USING_LIBC) && !defined(RT_USING_NANO)
|
||||
typedef size_t rt_size_t; /**< Type for size number */
|
||||
typedef ssize_t rt_ssize_t; /**< Used for a count of bytes or an error indication */
|
||||
#else
|
||||
typedef rt_base_t rt_ssize_t; /**< Used for a count of bytes or an error indication */
|
||||
#endif /* defined(RT_USING_LIBC) && !defined(RT_USING_NANO) */
|
||||
#else
|
||||
#define RT_SECTION rt_section
|
||||
#define RT_WEAK rt_weak
|
||||
#define RT_USED rt_used
|
||||
#ifndef ALIGN
|
||||
#define ALIGN rt_align
|
||||
#endif
|
||||
#endif /* RTTHREAD_VERSION <= RT_VERSION_CHECK(4, 1, 1) */
|
||||
|
||||
#endif /* DRIVERS_DRV_LEGACY_H_ */
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-11-15 SummerGift first version
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE: DO NOT include this file on the header file.
|
||||
*/
|
||||
|
||||
#ifndef LOG_TAG
|
||||
#define DBG_TAG "drv"
|
||||
#else
|
||||
#define DBG_TAG LOG_TAG
|
||||
#endif /* LOG_TAG */
|
||||
|
||||
#ifdef DRV_DEBUG
|
||||
#define DBG_LVL DBG_LOG
|
||||
#else
|
||||
#define DBG_LVL DBG_INFO
|
||||
#endif /* DRV_DEBUG */
|
||||
|
||||
#include <rtdbg.h>
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-10-11 kurisaw compatible with RT-Studio
|
||||
*/
|
||||
|
||||
#ifndef __DRV_PWM_H__
|
||||
#define __DRV_PWM_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(RT_USING_PWM)
|
||||
|
||||
/* gd32 pwm driver class */
|
||||
struct gd32_pwm
|
||||
{
|
||||
struct rt_device_pwm pwm_device;
|
||||
uint32_t timer_periph;
|
||||
char *name;
|
||||
rcu_periph_enum timer_clk;
|
||||
const char *pin_name;
|
||||
rt_int16_t channel;
|
||||
const char *alternate;
|
||||
};
|
||||
|
||||
rt_err_t rt_hw_pwm_init(void);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DRV_PWM_H__ */
|
||||
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#ifndef __SDCARD_H_
|
||||
#define __SDCARD_H_
|
||||
|
||||
#include <board.h>
|
||||
|
||||
#if defined(SOC_SERIES_GD32F10x)
|
||||
#include "gd32f10x_sdio.h"
|
||||
#include "gd32f10x_dma.h"
|
||||
#elif defined(SOC_SERIES_GD32F20x)
|
||||
#include "gd32f20x_sdio.h"
|
||||
#include "gd32f20x_dma.h"
|
||||
#elif defined(SOC_SERIES_GD32F30x)
|
||||
#include "gd32f30x_sdio.h"
|
||||
#include "gd32f30x_dma.h"
|
||||
#elif defined(SOC_SERIES_GD32F4xx)
|
||||
#include "gd32f4xx_sdio.h"
|
||||
#include "gd32f4xx_dma.h"
|
||||
#elif defined(SOC_SERIES_GD32H7xx)
|
||||
#include "gd32h7xx_sdio.h"
|
||||
#include "gd32h7xx_dma.h"
|
||||
#endif
|
||||
|
||||
// #define USE_18V_SWITCH /* use SD Transceiver 1.8V mode */
|
||||
|
||||
#define SDIO_PERI_CLOCK RCU_SDIO0
|
||||
#define SDIO_GPIO_CLK RCU_GPIOC
|
||||
#define SDIO_GPIO_CMD RCU_GPIOD
|
||||
#define SDIO_GPIO_D0 RCU_GPIOB
|
||||
#define SDIO_GPIO_D1 RCU_GPIOC
|
||||
#define SDIO_GPIO_D2 RCU_GPIOC
|
||||
#define SDIO_GPIO_D3 RCU_GPIOC
|
||||
|
||||
#define SDIO_CLK_PORT GPIOC
|
||||
#define SDIO_CLK_PIN GPIO_PIN_12
|
||||
#define SDIO_CMD_PORT GPIOD
|
||||
#define SDIO_CMD_PIN GPIO_PIN_2
|
||||
#define SDIO_D0_PORT GPIOB
|
||||
#define SDIO_D0_PIN GPIO_PIN_13
|
||||
#define SDIO_D1_PORT GPIOC
|
||||
#define SDIO_D1_PIN GPIO_PIN_9
|
||||
#define SDIO_D2_PORT GPIOC
|
||||
#define SDIO_D2_PIN GPIO_PIN_10
|
||||
#define SDIO_D3_PORT GPIOC
|
||||
#define SDIO_D3_PIN GPIO_PIN_11
|
||||
|
||||
/* SD memory card bus commands index */
|
||||
#define SD_CMD_GO_IDLE_STATE ((uint8_t)0) /* CMD0, GO_IDLE_STATE */
|
||||
#define SD_CMD_ALL_SEND_CID ((uint8_t)2) /* CMD2, ALL_SEND_CID */
|
||||
#define SD_CMD_SEND_RELATIVE_ADDR ((uint8_t)3) /* CMD3, SEND_RELATIVE_ADDR */
|
||||
#define SD_CMD_SET_DSR ((uint8_t)4) /* CMD4, SET_DSR */
|
||||
#define SD_CMD_SWITCH_FUNC ((uint8_t)6) /* CMD6, SWITCH_FUNC */
|
||||
#define SD_CMD_SELECT_DESELECT_CARD ((uint8_t)7) /* CMD7, SELECT_DESELECT_CARD */
|
||||
#define SD_CMD_SEND_IF_COND ((uint8_t)8) /* CMD8, SEND_IF_COND */
|
||||
#define SD_CMD_SEND_CSD ((uint8_t)9) /* CMD9, SEND_CSD */
|
||||
#define SD_CMD_SEND_CID ((uint8_t)10) /* CMD10, SEND_CID */
|
||||
#define SD_CMD_VOLATAGE_SWITCH ((uint8_t)11) /* CMD11, SD_CMD_VOLATAGE_SWITCH */
|
||||
#define SD_CMD_STOP_TRANSMISSION ((uint8_t)12) /* CMD12, STOP_TRANSMISSION */
|
||||
#define SD_CMD_SEND_STATUS ((uint8_t)13) /* CMD13, SEND_STATUS */
|
||||
#define SD_CMD_GO_INACTIVE_STATE ((uint8_t)15) /* CMD15, GO_INACTIVE_STATE */
|
||||
#define SD_CMD_SET_BLOCKLEN ((uint8_t)16) /* CMD16, SET_BLOCKLEN */
|
||||
#define SD_CMD_READ_SINGLE_BLOCK ((uint8_t)17) /* CMD17, READ_SINGLE_BLOCK */
|
||||
#define SD_CMD_READ_MULTIPLE_BLOCK ((uint8_t)18) /* CMD18, READ_MULTIPLE_BLOCK */
|
||||
#define SD_SEND_TUNING_PATTERN ((uint8_t)19) /* CMD19, SEND_TUNING_PATTERN */
|
||||
#define SD_CMD_WRITE_BLOCK ((uint8_t)24) /* CMD24, WRITE_BLOCK */
|
||||
#define SD_CMD_WRITE_MULTIPLE_BLOCK ((uint8_t)25) /* CMD25, WRITE_MULTIPLE_BLOCK */
|
||||
#define SD_CMD_PROG_CSD ((uint8_t)27) /* CMD27, PROG_CSD */
|
||||
#define SD_CMD_SET_WRITE_PROT ((uint8_t)28) /* CMD28, SET_WRITE_PROT */
|
||||
#define SD_CMD_CLR_WRITE_PROT ((uint8_t)29) /* CMD29, CLR_WRITE_PROT */
|
||||
#define SD_CMD_SEND_WRITE_PROT ((uint8_t)30) /* CMD30, SEND_WRITE_PROT */
|
||||
#define SD_CMD_ERASE_WR_BLK_START ((uint8_t)32) /* CMD32, ERASE_WR_BLK_START */
|
||||
#define SD_CMD_ERASE_WR_BLK_END ((uint8_t)33) /* CMD33, ERASE_WR_BLK_END */
|
||||
#define SD_CMD_ERASE ((uint8_t)38) /* CMD38, ERASE */
|
||||
#define SD_CMD_LOCK_UNLOCK ((uint8_t)42) /* CMD42, LOCK_UNLOCK */
|
||||
#define SD_CMD_APP_CMD ((uint8_t)55) /* CMD55, APP_CMD */
|
||||
#define SD_CMD_GEN_CMD ((uint8_t)56) /* CMD56, GEN_CMD */
|
||||
|
||||
/* SD memory card application specific commands index */
|
||||
#define SD_APPCMD_SET_BUS_WIDTH ((uint8_t)6) /* ACMD6, SET_BUS_WIDTH */
|
||||
#define SD_APPCMD_SD_STATUS ((uint8_t)13) /* ACMD13, SD_STATUS */
|
||||
#define SD_APPCMD_SEND_NUM_WR_BLOCKS ((uint8_t)22) /* ACMD22, SEND_NUM_WR_BLOCKS */
|
||||
#define SD_APPCMD_SET_WR_BLK_ERASE_COUNT ((uint8_t)23) /* ACMD23, SET_WR_BLK_ERASE_COUNT */
|
||||
#define SD_APPCMD_SD_SEND_OP_COND ((uint8_t)41) /* ACMD41, SD_SEND_OP_COND */
|
||||
#define SD_APPCMD_SET_CLR_CARD_DETECT ((uint8_t)42) /* ACMD42, SET_CLR_CARD_DETECT */
|
||||
#define SD_APPCMD_SEND_SCR ((uint8_t)51) /* ACMD51, SEND_SCR */
|
||||
|
||||
/* card command class */
|
||||
#define SD_CCC_SWITCH BIT(10) /* class 10 */
|
||||
#define SD_CCC_IO_MODE BIT(9) /* class 9 */
|
||||
#define SD_CCC_APPLICATION_SPECIFIC BIT(8) /* class 8 */
|
||||
#define SD_CCC_LOCK_CARD BIT(7) /* class 7 */
|
||||
#define SD_CCC_WRITE_PROTECTION BIT(6) /* class 6 */
|
||||
#define SD_CCC_ERASE BIT(5) /* class 5 */
|
||||
#define SD_CCC_BLOCK_WRITE BIT(4) /* class 4 */
|
||||
#define SD_CCC_BLOCK_READ BIT(2) /* class 2 */
|
||||
#define SD_CCC_BASIC BIT(0) /* class 0 */
|
||||
|
||||
/* SD card data transmission mode */
|
||||
#define SD_DMA_MODE ((uint32_t)0x00000000) /* DMA mode */
|
||||
#define SD_POLLING_MODE ((uint32_t)0x00000001) /* polling mode */
|
||||
|
||||
/* lock unlock status */
|
||||
#define SD_LOCK ((uint8_t)0x05) /* lock the SD card */
|
||||
#define SD_UNLOCK ((uint8_t)0x02) /* unlock the SD card */
|
||||
|
||||
#define SD_SDSC ((uint32_t)0x00000000U) /*!< SD Standard Capacity <2G*/
|
||||
#define SD_SDHC_SDXC ((uint32_t)0x00000001U) /*!< SD High Capacity <32G, SD Extended Capacity <2T */
|
||||
|
||||
#define SD_SPEED_DEFAULT ((uint32_t)0x00000000U) /*!< maintain current speed , clock frequency max value 25M*/
|
||||
#define SD_SPEED_HIGH ((uint32_t)0x00000001U) /*!< switch high speed, clock frequency max value 50M */
|
||||
#define SD_SPEED_SDR25 ((uint32_t)0x80FFFF01U) /*!< switch UHS-I SDR25 speed, clock frequency max value 50M */
|
||||
#define SD_SPEED_SDR50 ((uint32_t)0x80FF1F02U) /*!< switch UHS-I SDR50 speed, clock frequency max value 104M */
|
||||
#define SD_SPEED_SDR104 ((uint32_t)0x80FF1F03U) /*!< switch UHS-I SDR104 speed, clock frequency max value 208M */
|
||||
#define SD_SPEED_DDR50 ((uint32_t)0x80FF1F04U) /*!< switch UHS-I DDR speed , clock frequency max value 50M */
|
||||
|
||||
/* supported memory cards types */
|
||||
typedef enum
|
||||
{
|
||||
SDIO_STD_CAPACITY_SD_CARD_V1_1 = 0, /* standard capacity SD card version 1.1 */
|
||||
SDIO_STD_CAPACITY_SD_CARD_V2_0, /* standard capacity SD card version 2.0 */
|
||||
SDIO_STD_CAPACITY_SD_CARD_V3_0, /* standard capacity SD card version 3.0 */
|
||||
SDIO_HIGH_CAPACITY_SD_CARD, /* high capacity SD card */
|
||||
SDIO_SECURE_DIGITAL_IO_CARD, /* secure digital IO card */
|
||||
SDIO_SECURE_DIGITAL_IO_COMBO_CARD, /* secure digital IO combo card */
|
||||
SDIO_MULTIMEDIA_CARD, /* multimedia card */
|
||||
SDIO_HIGH_CAPACITY_MULTIMEDIA_CARD, /* high capacity multimedia card */
|
||||
SDIO_HIGH_SPEED_MULTIMEDIA_CARD /* high speed multimedia card */
|
||||
} sdio_card_type_enum;
|
||||
|
||||
/* card identification (CID) register */
|
||||
typedef struct
|
||||
{
|
||||
__IO uint8_t mid; /* manufacturer ID */
|
||||
__IO uint16_t oid; /* OEM/application ID */
|
||||
__IO uint32_t pnm0; /* product name */
|
||||
__IO uint8_t pnm1; /* product name */
|
||||
__IO uint8_t prv; /* product revision */
|
||||
__IO uint32_t psn; /* product serial number */
|
||||
__IO uint16_t mdt; /* manufacturing date */
|
||||
__IO uint8_t cid_crc; /* CID CRC7 checksum */
|
||||
} sd_cid_struct;
|
||||
|
||||
/* CSD register (CSD version 1.0 and 2.0) */
|
||||
typedef struct
|
||||
{
|
||||
__IO uint8_t csd_struct; /* CSD struct */
|
||||
__IO uint8_t taac; /* data read access-time */
|
||||
__IO uint8_t nsac; /* data read access-time in CLK cycles */
|
||||
__IO uint8_t tran_speed; /* max. data transfer rate */
|
||||
__IO uint16_t ccc; /* card command classes */
|
||||
__IO uint8_t read_bl_len; /* max. read data block length */
|
||||
__IO uint8_t read_bl_partial; /* partial blocks for read allowed */
|
||||
__IO uint8_t write_blk_misalign; /* write block misalignment */
|
||||
__IO uint8_t read_blk_misalign; /* read block misalignment */
|
||||
__IO uint8_t dsp_imp; /* DSR implemented */
|
||||
__IO uint32_t c_size; /* device size, 12 bits in CSD version 1.0, 22 bits in CSD version 2.0 */
|
||||
__IO uint8_t vdd_r_curr_min; /* max. read current @VDD min, CSD version 1.0 */
|
||||
__IO uint8_t vdd_r_curr_max; /* max. read current @VDD max, CSD version 1.0 */
|
||||
__IO uint8_t vdd_w_curr_min; /* max. write current @VDD min, CSD version 1.0 */
|
||||
__IO uint8_t vdd_w_curr_max; /* max. write current @VDD max, CSD version 1.0 */
|
||||
__IO uint8_t c_size_mult; /* device size multiplier, CSD version 1.0 */
|
||||
__IO uint8_t erase_blk_en; /* erase single block enable */
|
||||
__IO uint8_t sector_size; /* erase sector size */
|
||||
__IO uint8_t wp_grp_size; /* write protect group size */
|
||||
__IO uint8_t wp_grp_enable; /* write protect group enable */
|
||||
__IO uint8_t r2w_factor; /* write speed factor */
|
||||
__IO uint8_t write_bl_len; /* max. write data block length */
|
||||
__IO uint8_t write_bl_partial; /* partial blocks for write allowed */
|
||||
__IO uint8_t file_format_grp; /* file format group */
|
||||
__IO uint8_t copy_flag; /* copy flag (OTP) */
|
||||
__IO uint8_t perm_write_protect; /* permanent write protection */
|
||||
__IO uint8_t tmp_write_protect; /* temporary write protection */
|
||||
__IO uint8_t file_format; /* file format */
|
||||
__IO uint8_t csd_crc; /* CSD CRC checksum */
|
||||
} sd_csd_struct;
|
||||
|
||||
/* information of card */
|
||||
typedef struct
|
||||
{
|
||||
sd_cid_struct card_cid; /* CID register */
|
||||
sd_csd_struct card_csd; /* CSD register */
|
||||
sdio_card_type_enum card_type; /* card tpye */
|
||||
uint32_t card_capacity; /* card capacity */
|
||||
uint32_t card_blocksize; /* card block size */
|
||||
uint16_t card_rca; /* card relative card address */
|
||||
} sd_card_info_struct;
|
||||
|
||||
/* SD error flags */
|
||||
typedef enum
|
||||
{
|
||||
SD_OUT_OF_RANGE = 0, /* command's argument was out of range */
|
||||
SD_ADDRESS_ERROR, /* misaligned address which did not match the block length */
|
||||
SD_BLOCK_LEN_ERROR, /* transferred block length is not allowed for the card or the number of transferred bytes does not match the block length */
|
||||
SD_ERASE_SEQ_ERROR, /* an error in the sequence of erase command occurs */
|
||||
SD_ERASE_PARAM, /* an invalid selection of write-blocks for erase occurred */
|
||||
SD_WP_VIOLATION, /* attempt to program a write protect block or permanent write protected card */
|
||||
SD_LOCK_UNLOCK_FAILED, /* sequence or password error has been detected in lock/unlock card command */
|
||||
SD_COM_CRC_ERROR, /* CRC check of the previous command failed */
|
||||
SD_ILLEGAL_COMMAND, /* command not legal for the card state */
|
||||
SD_CARD_ECC_FAILED, /* card internal ECC was applied but failed to correct the data */
|
||||
SD_CC_ERROR, /* internal card controller error */
|
||||
SD_GENERAL_UNKNOWN_ERROR, /* general or unknown error occurred during the operation */
|
||||
SD_CSD_OVERWRITE, /* read only section of the CSD does not match the card content or an attempt to reverse the copy or permanent WP bits was made */
|
||||
SD_WP_ERASE_SKIP, /* only partial address space was erased or the temporary or permanent write protected card was erased */
|
||||
SD_CARD_ECC_DISABLED, /* command has been executed without using internal ECC */
|
||||
SD_ERASE_RESET, /* erase sequence was cleared before executing because an out of erase sequence command was received */
|
||||
SD_AKE_SEQ_ERROR, /* error in the sequence of the authentication process */
|
||||
|
||||
SD_CMD_CRC_ERROR, /* command response received (CRC check failed) */
|
||||
SD_DATA_CRC_ERROR, /* data block sent/received (CRC check failed) */
|
||||
SD_CMD_RESP_TIMEOUT, /* command response timeout */
|
||||
SD_DATA_TIMEOUT, /* data timeout */
|
||||
SD_TX_UNDERRUN_ERROR, /* transmit FIFO underrun error occurs */
|
||||
SD_RX_OVERRUN_ERROR, /* received FIFO overrun error occurs */
|
||||
SD_START_BIT_ERROR, /* start bit error in the bus */
|
||||
|
||||
SD_VOLTRANGE_INVALID, /* the voltage range is invalid */
|
||||
SD_PARAMETER_INVALID, /* the parameter is invalid */
|
||||
SD_OPERATION_IMPROPER, /* the operation is improper */
|
||||
SD_FUNCTION_UNSUPPORTED, /* the function is unsupported */
|
||||
SD_ERROR, /* an error occurred */
|
||||
SD_DMA_ERROR, /* an error when idma transfer */
|
||||
SD_OK /* no error occurred */
|
||||
} sd_error_enum;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SD_NO_TRANSFER = 0, /* no data transfer is acting */
|
||||
SD_TRANSFER_IN_PROGRESS /* data transfer is in progress */
|
||||
} sd_transfer_state_enum;
|
||||
|
||||
/* function declarations */
|
||||
/* initialize the SD card and make it in standby state */
|
||||
sd_error_enum sd_init(uint32_t SDIO);
|
||||
/* initialize the card and get CID and CSD of the card */
|
||||
sd_error_enum sd_card_init(uint32_t SDIO);
|
||||
/* configure the clock and the work voltage, and get the card type */
|
||||
sd_error_enum sd_power_on(uint32_t SDIO);
|
||||
/* close the power of SDIO */
|
||||
sd_error_enum sd_power_off(uint32_t SDIO);
|
||||
|
||||
/* configure the bus mode */
|
||||
sd_error_enum sd_bus_mode_config(uint32_t SDIO, uint32_t busmode, uint32_t speed);
|
||||
/* configure the mode of transmission */
|
||||
sd_error_enum sd_transfer_mode_config(uint32_t txmode);
|
||||
|
||||
/* read a block data into a buffer from the specified address of a card */
|
||||
sd_error_enum sd_block_read(uint32_t SDIO, uint32_t *preadbuffer, uint32_t readaddr, uint16_t blocksize);
|
||||
/* read multiple blocks data into a buffer from the specified address of a card */
|
||||
sd_error_enum sd_multiblocks_read(uint32_t SDIO, uint32_t *preadbuffer, uint32_t readaddr, uint16_t blocksize, uint32_t blocksnumber);
|
||||
/* write a block data to the specified address of a card */
|
||||
sd_error_enum sd_block_write(uint32_t SDIO, uint32_t *pwritebuffer, uint32_t writeaddr, uint16_t blocksize);
|
||||
/* write multiple blocks data to the specified address of a card */
|
||||
sd_error_enum sd_multiblocks_write(uint32_t SDIO, uint32_t *pwritebuffer, uint32_t writeaddr, uint16_t blocksize, uint32_t blocksnumber);
|
||||
/* erase a continuous area of a card */
|
||||
sd_error_enum sd_erase(uint32_t SDIO, uint32_t startaddr, uint32_t endaddr);
|
||||
/* process all the interrupts which the corresponding flags are set */
|
||||
sd_error_enum sd_interrupts_process(uint32_t SDIO);
|
||||
|
||||
/* select or deselect a card */
|
||||
sd_error_enum sd_card_select_deselect(uint32_t SDIO, uint16_t cardrca);
|
||||
/* get the card status whose response format R1 contains a 32-bit field */
|
||||
sd_error_enum sd_cardstatus_get(uint32_t SDIO, uint32_t *pcardstatus);
|
||||
/* get the SD status, the size of the SD status is one data block of 512 bit */
|
||||
sd_error_enum sd_sdstatus_get(uint32_t SDIO, uint32_t *psdstatus);
|
||||
/* stop an ongoing data transfer */
|
||||
sd_error_enum sd_transfer_stop(uint32_t SDIO);
|
||||
/* lock or unlock a card */
|
||||
sd_error_enum sd_lock_unlock(uint32_t SDIO, uint8_t lockstate);
|
||||
|
||||
/* get the data transfer state */
|
||||
sd_transfer_state_enum sd_transfer_state_get(uint32_t SDIO);
|
||||
/* get SD card capacity(KB) */
|
||||
uint32_t sd_card_capacity_get(uint32_t SDIO);
|
||||
/* get the detailed information of the SD card based on received CID and CSD */
|
||||
sd_error_enum sd_card_information_get(uint32_t SDIO, sd_card_info_struct *pcardinfo);
|
||||
|
||||
/* switch 1.8V power level of SD card */
|
||||
sd_error_enum sd_card_voltage_switch(uint32_t SDIO);
|
||||
|
||||
#ifdef USE_18V_SWITCH
|
||||
/* configure CPDM */
|
||||
void cpdm_config(void);
|
||||
/* perform sampling point tuning using tuning command */
|
||||
sd_error_enum sd_tuning(uint32_t SDIO);
|
||||
#endif /* USE_18V_SWITCH */
|
||||
|
||||
#endif /* __SDCARD_H_ */
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-12-20 BruceOu first implementation
|
||||
* 2025-10-10 WangShun compatible with RT-Studio
|
||||
*/
|
||||
|
||||
#ifndef __DRV_SPI_H__
|
||||
#define __DRV_SPI_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RT_SPI_USING_DMA
|
||||
|
||||
#if !defined(SOC_SERIES_GD32H7xx) && !defined(SOC_SERIES_GD32H75E)
|
||||
#undef RT_SPI_USING_DMA
|
||||
#endif
|
||||
|
||||
struct gd32_spi_cs
|
||||
{
|
||||
uint32_t GPIOx;
|
||||
uint32_t GPIO_Pin;
|
||||
};
|
||||
|
||||
#ifdef RT_SPI_USING_DMA
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* dma peripheral */
|
||||
uint32_t dma_periph;
|
||||
/* dma txchannel */
|
||||
dma_channel_enum txdma_ch;
|
||||
/* dma rxchannel */
|
||||
dma_channel_enum rxdma_ch;
|
||||
/* tx dma request */
|
||||
uint32_t dma_mux_req_tx;
|
||||
/* rx dma request */
|
||||
uint32_t dma_mux_req_rx;
|
||||
/* dma flag */
|
||||
uint32_t rx_flag;
|
||||
/* setting receive len */
|
||||
rt_size_t setting_recv_len;
|
||||
|
||||
} gd32_spi_dma;
|
||||
#endif
|
||||
|
||||
/* gd32 spi dirver class */
|
||||
struct gd32_spi
|
||||
{
|
||||
uint32_t spi_periph;
|
||||
char *bus_name;
|
||||
rcu_periph_enum spi_clk;
|
||||
struct rt_spi_bus *spi_bus;
|
||||
const char *sck_pin_name; /* sck pin name */
|
||||
const char *miso_pin_name; /* miso pin name */
|
||||
const char *mosi_pin_name; /* mosi pin name */
|
||||
const char *alternate; /* afio mode */
|
||||
#ifdef RT_SPI_USING_DMA
|
||||
gd32_spi_dma *spi_dma;
|
||||
#endif
|
||||
};
|
||||
|
||||
rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_base_t cs_pin);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DRV_SPI_H__ */
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-08-20 BruceOu first implementation
|
||||
* 2025-10-09 WangShun compatible with RT-Studio
|
||||
*/
|
||||
|
||||
#ifndef __DRV_USART_H__
|
||||
#define __DRV_USART_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !defined(SOC_SERIES_GD32H7xx) || !defined(SOC_SERIES_GD32H75E)
|
||||
#undef RT_SERIAL_USING_DMA
|
||||
#endif
|
||||
#define UART_ENABLE_IRQ(n) NVIC_EnableIRQ((n))
|
||||
#define UART_DISABLE_IRQ(n) NVIC_DisableIRQ((n))
|
||||
|
||||
#ifdef RT_SERIAL_USING_DMA
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* dma peripheral */
|
||||
uint32_t dma_periph;
|
||||
/* dma channel */
|
||||
dma_channel_enum dma_ch;
|
||||
#if defined(SOC_SERIES_GD32H7xx) || defined(SOC_SERIES_GD32H75E)
|
||||
/* rx dma request */
|
||||
uint32_t dma_mux_req_rx;
|
||||
#endif
|
||||
/* dma flag */
|
||||
uint32_t rx_flag;
|
||||
/* dma irq channel */
|
||||
uint8_t rx_irq_ch;
|
||||
/* setting receive len */
|
||||
rt_size_t setting_recv_len;
|
||||
/* last receive index */
|
||||
rt_size_t last_recv_index;
|
||||
} gd32_uart_dma;
|
||||
|
||||
#endif
|
||||
/* GD32 uart driver */
|
||||
|
||||
struct gd32_uart
|
||||
{
|
||||
uint32_t uart_periph; /* Instance */
|
||||
IRQn_Type irqn; /* irqn */
|
||||
rcu_periph_enum per_clk; /* uart_clk */
|
||||
|
||||
const char *tx_pin_name; /* tx pin name */
|
||||
const char *rx_pin_name; /* rx pin name */
|
||||
const char *alternate; /* rx pin name */
|
||||
|
||||
#ifdef RT_SERIAL_USING_DMA
|
||||
gd32_uart_dma *uart_dma;
|
||||
#ifdef RT_SERIAL_USING_TX_DMA
|
||||
gd32_uart_dma *uart_tx_dma;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct rt_serial_device * serial; /* serial device */
|
||||
char *device_name;
|
||||
};
|
||||
|
||||
int rt_hw_usart_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DRV_USART_H__ */
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#ifndef __DRV_OTGFS_DEV_H__
|
||||
#define __DRV_OTGFS_DEV_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "drv_usb_dev.h"
|
||||
|
||||
void usbd_reset_callback(void);
|
||||
|
||||
void usbd_setup_stage_callback(struct urequest *setup_packet);
|
||||
|
||||
void usbd_data_in_stage_callback(uint8_t epnum, uint16_t data_count);
|
||||
|
||||
void usbd_data_out_stage_callback(uint8_t epnum, uint16_t data_count);
|
||||
|
||||
void usbd_set_connection_state(uint8_t state);
|
||||
|
||||
int gd_usbd_register(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#ifndef __DRV_OTGFS_HOST_H__
|
||||
#define __DRV_OTGFS_HOST_H__
|
||||
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "drv_usb_host.h"
|
||||
#include "drv_usbh_transc.h"
|
||||
#include "drv_usbh_pipe.h"
|
||||
|
||||
#define OTG_FS_PORT 1
|
||||
|
||||
#if defined(BSP_USING_USB) && defined(RT_USING_USB_HOST)
|
||||
|
||||
void usbh_connect_callback(usb_core_driver *hhcd);
|
||||
|
||||
void usbh_disconnect_callback(usb_core_driver *hhcd);
|
||||
|
||||
void usbh_hc_notifyurbchange_callback(usb_core_driver *hhcd, uint8_t chnum, usb_urb_state urb_state);
|
||||
|
||||
int gd_usbh_register(void);
|
||||
|
||||
#endif /* BSP_USING_USB && RT_USING_USB_HOST */
|
||||
#endif
|
||||
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#ifndef DRV_USB_CORE_H
|
||||
#define DRV_USB_CORE_H
|
||||
|
||||
#include "drv_usb_regs.h"
|
||||
|
||||
#define USB_FS_EP0_MAX_LEN 64U /*!< maximum packet size of endpoint 0 */
|
||||
#define HC_MAX_PACKET_COUNT 140U /*!< maximum packet count */
|
||||
|
||||
#define EP_ID(x) ((uint8_t)((x) & 0x7FU)) /*!< endpoint number */
|
||||
#define EP_DIR(x) ((uint8_t)((x) >> 7)) /*!< endpoint direction */
|
||||
|
||||
typedef struct urequest usb_req;
|
||||
|
||||
enum _usb_eptype
|
||||
{
|
||||
USB_EPTYPE_CTRL = 0U, /*!< control endpoint type */
|
||||
USB_EPTYPE_ISOC = 1U, /*!< isochronous endpoint type */
|
||||
USB_EPTYPE_BULK = 2U, /*!< bulk endpoint type */
|
||||
USB_EPTYPE_INTR = 3U, /*!< interrupt endpoint type */
|
||||
USB_EPTYPE_MASK = 3U /*!< endpoint type mask */
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USB_OTG_OK = 0U, /*!< USB OTG status OK */
|
||||
USB_OTG_FAIL /*!< USB OTG status fail */
|
||||
} usb_otg_status;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USB_OK = 0U, /*!< USB status OK */
|
||||
USB_FAIL /*!< USB status fail */
|
||||
} usb_status;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USB_USE_FIFO, /*!< USB use FIFO transfer mode */
|
||||
USB_USE_DMA /*!< USB use DMA transfer mode */
|
||||
} usb_transfer_mode;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LPM_L0 = 0U, /*!< on */
|
||||
LPM_L1, /*!< LPM L1 sleep */
|
||||
LPM_L2, /*!< suspend */
|
||||
LPM_L3, /*!< off */
|
||||
} usb_lpm_state;
|
||||
|
||||
enum usb_ctl_status
|
||||
{
|
||||
USB_CTL_IDLE = 0U, /*!< USB control transfer idle state */
|
||||
USB_CTL_DATA_IN, /*!< USB control transfer data IN state */
|
||||
USB_CTL_LAST_DATA_IN, /*!< USB control transfer last data IN state */
|
||||
USB_CTL_DATA_OUT, /*!< USB control transfer data OUT state */
|
||||
USB_CTL_LAST_DATA_OUT, /*!< USB control transfer last data OUT state */
|
||||
USB_CTL_STATUS_IN, /*!< USB control transfer status IN state*/
|
||||
USB_CTL_STATUS_OUT /*!< USB control transfer status OUT state */
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LPM_L0_ACTIVE = 0U, /*!< on */
|
||||
LPM_L1_ACTIVE, /*!< LPM L1 sleep */
|
||||
} usb_lpm_type;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t core_enum; /*!< USB core type */
|
||||
uint8_t core_speed; /*!< USB core speed */
|
||||
uint8_t num_pipe; /*!< USB host channel numbers */
|
||||
uint8_t num_ep; /*!< USB device endpoint numbers */
|
||||
uint8_t transfer_mode; /*!< USB transfer mode */
|
||||
uint8_t phy_itf; /*!< USB core PHY interface */
|
||||
uint8_t sof_enable; /*!< USB SOF output */
|
||||
uint8_t low_power; /*!< USB low power */
|
||||
uint8_t lpm_enable; /*!< USB link power mode(LPM) */
|
||||
uint8_t vbus_sensing_enable; /*!< USB VBUS sensing feature */
|
||||
uint8_t use_dedicated_ep1; /*!< USB dedicated endpoint1 interrupt */
|
||||
uint8_t use_external_vbus; /*!< enable or disable the use of the external VBUS */
|
||||
uint32_t base_reg; /*!< base register address */
|
||||
} usb_core_basic;
|
||||
|
||||
#ifdef USE_DEVICE_MODE
|
||||
|
||||
/* USB descriptor */
|
||||
typedef struct _usb_desc
|
||||
{
|
||||
uint8_t *dev_desc; /*!< device descriptor */
|
||||
uint8_t *config_desc; /*!< configuration descriptor */
|
||||
uint8_t *bos_desc; /*!< BOS descriptor */
|
||||
|
||||
#ifdef USE_USB_HS
|
||||
uint8_t *other_speed_config_desc; /*!< other speed configuration descriptor */
|
||||
uint8_t *qualifier_desc; /*!< qualifier descriptor */
|
||||
#endif
|
||||
|
||||
void * const *strings; /*!< string descriptor */
|
||||
} usb_desc;
|
||||
|
||||
/* USB power management */
|
||||
typedef struct _usb_pm
|
||||
{
|
||||
uint8_t power_mode; /*!< power mode */
|
||||
uint8_t power_low; /*!< power low */
|
||||
uint8_t dev_remote_wakeup; /*!< remote wakeup */
|
||||
uint8_t remote_wakeup_on; /*!< remote wakeup on */
|
||||
usb_lpm_state lpm_state; /*!< LPM state */
|
||||
uint32_t BESL; /*!< BESL value */
|
||||
} usb_pm;
|
||||
|
||||
/* USB control information */
|
||||
typedef struct _usb_control
|
||||
{
|
||||
usb_req req; /*!< USB standard device request */
|
||||
|
||||
uint8_t ctl_state; /*!< USB control transfer state */
|
||||
uint8_t ctl_zlp; /*!< zero length package */
|
||||
} usb_control;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t num : 4U; /*!< the endpoint number.it can be from 0 to 6 */
|
||||
uint8_t pad : 3U; /*!< padding between number and direction */
|
||||
uint8_t dir : 1U; /*!< the endpoint direction */
|
||||
} ep_addr;
|
||||
|
||||
uint8_t ep_type; /*!< USB endpoint type */
|
||||
uint8_t ep_stall; /*!< USB endpoint STALL status */
|
||||
|
||||
uint8_t frame_num; /*!< number of frame */
|
||||
uint16_t max_len; /*!< maximum packet length */
|
||||
|
||||
/* transaction level variables */
|
||||
uint8_t *xfer_buf; /*!< transmit buffer */
|
||||
uint32_t xfer_len; /*!< transmit buffer length */
|
||||
uint32_t xfer_count; /*!< transmit buffer count */
|
||||
|
||||
uint32_t remain_len; /*!< remain packet length */
|
||||
|
||||
uint32_t dma_addr; /*!< DMA address */
|
||||
} usb_transc;
|
||||
|
||||
typedef struct _usb_core_driver usb_dev;
|
||||
|
||||
typedef struct _usb_class_core
|
||||
{
|
||||
uint8_t alter_set; /*!< alternative set */
|
||||
uint8_t command; /*!< device class request command */
|
||||
|
||||
uint8_t (*init)(usb_dev *udev, uint8_t config_index); /*!< initialize handler */
|
||||
uint8_t (*deinit)(usb_dev *udev, uint8_t config_index); /*!< de-initialize handler */
|
||||
uint8_t (*req_proc)(usb_dev *udev, usb_req *req); /*!< device request handler */
|
||||
uint8_t (*set_intf)(usb_dev *udev, usb_req *req); /*!< device set interface callback */
|
||||
uint8_t (*ctlx_in)(usb_dev *udev); /*!< device control IN callback */
|
||||
uint8_t (*ctlx_out)(usb_dev *udev); /*!< device control OUT callback */
|
||||
uint8_t (*data_in)(usb_dev *udev, uint8_t ep_num); /*!< device data IN handler */
|
||||
uint8_t (*data_out)(usb_dev *udev, uint8_t ep_num); /*!< device data OUT handler */
|
||||
uint8_t (*SOF)(usb_dev *udev); /*!< start of frame handler */
|
||||
uint8_t (*incomplete_isoc_in)(usb_dev *udev); /*!< incomplete synchronization IN transfer handler */
|
||||
uint8_t (*incomplete_isoc_out)(usb_dev *udev); /*!< incomplete synchronization OUT transfer handler */
|
||||
} usb_class_core;
|
||||
|
||||
typedef struct _usb_perp_dev
|
||||
{
|
||||
uint8_t config; /*!< configuration */
|
||||
uint8_t dev_addr; /*!< device address */
|
||||
|
||||
__IO uint8_t cur_status; /*!< current status */
|
||||
__IO uint8_t backup_status; /*!< backup status */
|
||||
|
||||
usb_transc transc_in[USBHS_MAX_TX_FIFOS]; /*!< endpoint IN transaction */
|
||||
usb_transc transc_out[USBHS_MAX_TX_FIFOS]; /*!< endpoint OUT transaction */
|
||||
|
||||
usb_pm pm; /*!< power management */
|
||||
usb_control control; /*!< USB control information */
|
||||
usb_desc *desc; /*!< USB descriptors pointer */
|
||||
usb_class_core *class_core; /*!< class driver */
|
||||
void *class_data[4]; /*!< class data pointer */
|
||||
void *user_data; /*!< user data pointer */
|
||||
void *pdata; /*!< reserved data pointer */
|
||||
} usb_perp_dev;
|
||||
|
||||
#endif /* USE_DEVICE_MODE */
|
||||
|
||||
#ifdef USE_HOST_MODE
|
||||
|
||||
typedef enum _usb_pipe_status
|
||||
{
|
||||
PIPE_IDLE = 0U, /*!< host pipe IDLE status */
|
||||
PIPE_XF, /*!< host pipe transfer completed status */
|
||||
PIPE_HALTED, /*!< host pipe halted status */
|
||||
PIPE_NAK, /*!< host pipe NAK status */
|
||||
PIPE_NYET, /*!< host pipe NYET status */
|
||||
PIPE_STALL, /*!< host pipe STALL status */
|
||||
PIPE_TRACERR, /*!< host pipe transaction error status */
|
||||
PIPE_BBERR, /*!< host pipe babble error status */
|
||||
PIPE_REQOVR, /*!< host pipe frame overrun status */
|
||||
PIPE_DTGERR, /*!< host pipe data toggle error status */
|
||||
} usb_pipe_status;
|
||||
|
||||
typedef enum _usb_pipe_mode
|
||||
{
|
||||
PIPE_PERIOD = 0U, /*!< USB host pipe PERIOD mode */
|
||||
PIPE_NON_PERIOD = 1U /*!< USB host pipe NOT PERIOD mode */
|
||||
} usb_pipe_mode;
|
||||
|
||||
typedef enum _usb_urb_state
|
||||
{
|
||||
URB_IDLE = 0U, /*!< USB URB IDLE state */
|
||||
URB_DONE, /*!< USB URB DONE state */
|
||||
URB_NOTREADY, /*!< USB URB NOT READY state */
|
||||
URB_ERROR, /*!< USB URB ERROR state */
|
||||
URB_STALL, /*!< USB URB STALL state */
|
||||
URB_PING /*!< USB URB PING state */
|
||||
} usb_urb_state;
|
||||
|
||||
typedef struct _usb_pipe
|
||||
{
|
||||
uint8_t in_used; /*!< pipe used */
|
||||
uint8_t dev_addr; /*!< USB device address */
|
||||
uint32_t dev_speed; /*!< USB device speed */
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t num; /*!< endpoint numbers */
|
||||
uint8_t dir; /*!< endpoint direction */
|
||||
uint8_t type; /*!< endpoint transfer type */
|
||||
uint16_t mps; /*!< endpoint max packet size */
|
||||
} ep;
|
||||
|
||||
__IO uint8_t supp_ping; /*!< host pipe support PING */
|
||||
__IO uint8_t do_ping; /*!< host pipe do PING */
|
||||
__IO uint32_t DPID; /*!< data PID */
|
||||
|
||||
uint8_t *xfer_buf; /*!< USB transfer buffer */
|
||||
uint32_t xfer_len; /*!< USB transfer length */
|
||||
uint32_t xfer_count; /*!< USB transfer count */
|
||||
|
||||
uint8_t data_toggle_in; /*!< toggle DATA IN */
|
||||
uint8_t data_toggle_out; /*!< toggle DATA OUT */
|
||||
|
||||
__IO uint32_t err_count; /*!< error count */
|
||||
__IO usb_pipe_status pp_status; /*!< USB pipe status */
|
||||
__IO usb_urb_state urb_state; /*!< USB URB state */
|
||||
} usb_pipe;
|
||||
|
||||
typedef struct _usb_host_drv
|
||||
{
|
||||
__IO uint32_t connect_status; /*!< connect status */
|
||||
__IO uint32_t port_enabled; /*!< USB port enable */
|
||||
__IO uint32_t backup_xfercount[USBHS_MAX_TX_FIFOS]; /*!< USB backup transfer data count */
|
||||
|
||||
usb_pipe pipe[USBHS_MAX_TX_FIFOS]; /*!< USB host pipe handles */
|
||||
void *data; /*!< user data pointer */
|
||||
} usb_host_drv;
|
||||
|
||||
#endif /* USE_HOST_MODE */
|
||||
|
||||
typedef struct _usb_core_driver
|
||||
{
|
||||
usb_core_basic bp; /*!< USB basic parameters */
|
||||
usb_core_regs regs; /*!< USB registers */
|
||||
|
||||
#ifdef USE_DEVICE_MODE
|
||||
usb_perp_dev dev; /*!< USB peripheral device */
|
||||
#endif /* USE_DEVICE_MODE */
|
||||
|
||||
#ifdef USE_HOST_MODE
|
||||
usb_host_drv host; /*!< USB peripheral host */
|
||||
#endif /* USE_HOST_MODE */
|
||||
} usb_core_driver;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BCD_NONE = 0,
|
||||
BCD_SDP,
|
||||
BCD_DCP,
|
||||
BCD_CDP,
|
||||
BCD_PS2,
|
||||
BCD_ERROR
|
||||
} bcd_type;
|
||||
|
||||
/* static inline function definitions */
|
||||
|
||||
/*!
|
||||
\brief get the global interrupts
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[out] none
|
||||
\retval interrupt status
|
||||
*/
|
||||
__STATIC_INLINE uint32_t usb_coreintr_get(usb_core_regs *usb_regs)
|
||||
{
|
||||
uint32_t reg_data = usb_regs->gr->GINTEN;
|
||||
|
||||
reg_data &= usb_regs->gr->GINTF;
|
||||
|
||||
return reg_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set USB RX FIFO size
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[in] size: assigned FIFO size
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_set_rxfifo(usb_core_regs *usb_regs, uint16_t size)
|
||||
{
|
||||
usb_regs->gr->GRFLEN = size;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable the global interrupts
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_globalint_enable(usb_core_regs *usb_regs)
|
||||
{
|
||||
/* enable USB global interrupt */
|
||||
usb_regs->gr->GAHBCS |= GAHBCS_GINTEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable the global interrupts
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_globalint_disable(usb_core_regs *usb_regs)
|
||||
{
|
||||
/* disable USB global interrupt */
|
||||
usb_regs->gr->GAHBCS &= ~GAHBCS_GINTEN;
|
||||
}
|
||||
|
||||
/* function declarations */
|
||||
/* configures USB parameters */
|
||||
void usb_para_init(usb_core_driver *core, uint32_t usb_periph, uint32_t usb_speed);
|
||||
/* configure core capabilities */
|
||||
usb_status usb_basic_init(usb_core_basic *usb_basic, usb_core_regs *usb_regs);
|
||||
/*initializes the USB controller registers and prepares the core device mode or host mode operation*/
|
||||
usb_status usb_core_init(usb_core_basic usb_basic, usb_core_regs *usb_regs);
|
||||
/* write a packet into the TX FIFO associated with the endpoint */
|
||||
usb_status usb_txfifo_write(usb_core_regs *usb_regs, uint8_t *src_buf, uint8_t fifo_num, uint16_t byte_count);
|
||||
/* read a packet from the RX FIFO associated with the endpoint */
|
||||
void *usb_rxfifo_read(usb_core_regs *usb_regs, uint8_t *dest_buf, uint16_t byte_count);
|
||||
/* flush a TX FIFO or all TX FIFOs */
|
||||
usb_status usb_txfifo_flush(usb_core_regs *usb_regs, uint8_t fifo_num);
|
||||
/* flush the entire RX FIFO */
|
||||
usb_status usb_rxfifo_flush(usb_core_regs *usb_regs);
|
||||
/* set endpoint or channel TX FIFO size */
|
||||
void usb_set_txfifo(usb_core_regs *usb_regs, uint8_t fifo, uint16_t size);
|
||||
/* set USB current mode */
|
||||
void usb_curmode_set(usb_core_regs *usb_regs, uint8_t mode);
|
||||
void usb_clock_active(usb_core_driver *udev);
|
||||
|
||||
#endif /* DRV_USB_CORE_H */
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#ifndef DRV_USB_DEV_H
|
||||
#define DRV_USB_DEV_H
|
||||
|
||||
#include "drv_usb_core.h"
|
||||
|
||||
#if defined(BSP_USING_USB) && defined(RT_USING_USB_DEVICE)
|
||||
|
||||
#define EP_IN(x) ((uint8_t)(0x80U | (x))) /*!< device IN endpoint */
|
||||
#define EP_OUT(x) ((uint8_t)(x)) /*!< device OUT endpoint */
|
||||
#define EP_MAX_PACKET_SIZE_MASK 0x07FFU /*!< endpoint maximum packet size mask */
|
||||
|
||||
#define USB_MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
/* static inline function definitions */
|
||||
|
||||
/*!
|
||||
\brief configure the USB device to be disconnected
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_dev_disconnect(usb_core_driver *udev)
|
||||
{
|
||||
udev->regs.dr->DCTL |= DCTL_SD;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the USB device to be connected
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_dev_connect(usb_core_driver *udev)
|
||||
{
|
||||
udev->regs.dr->DCTL &= ~DCTL_SD;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set the USB device address
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] dev_addr: device address for setting
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_devaddr_set(usb_core_driver *udev, uint8_t dev_addr)
|
||||
{
|
||||
udev->regs.dr->DCFG &= ~DCFG_DAR;
|
||||
udev->regs.dr->DCFG |= (uint32_t)dev_addr << 4;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read device all OUT endpoint interrupt register
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval interrupt status
|
||||
*/
|
||||
__STATIC_INLINE uint32_t usb_oepintnum_read(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t value = udev->regs.dr->DAEPINT;
|
||||
|
||||
value &= udev->regs.dr->DAEPINTEN;
|
||||
|
||||
return (value & DAEPINT_OEPITB) >> 16;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read device OUT endpoint interrupt flag register
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[out] none
|
||||
\retval interrupt status
|
||||
*/
|
||||
__STATIC_INLINE uint32_t usb_oepintr_read(usb_core_driver *udev, uint8_t ep_num)
|
||||
{
|
||||
uint32_t value = udev->regs.er_out[ep_num]->DOEPINTF;
|
||||
|
||||
value &= udev->regs.dr->DOEPINTEN;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read device all IN endpoint interrupt register
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval interrupt status
|
||||
*/
|
||||
__STATIC_INLINE uint32_t usb_iepintnum_read(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t value = udev->regs.dr->DAEPINT;
|
||||
|
||||
value &= udev->regs.dr->DAEPINTEN;
|
||||
|
||||
return value & DAEPINT_IEPITB;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set remote wakeup signaling
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_rwkup_set(usb_core_driver *udev)
|
||||
{
|
||||
if (udev->dev.pm.dev_remote_wakeup)
|
||||
{
|
||||
/* enable remote wakeup signaling */
|
||||
udev->regs.dr->DCTL |= DCTL_RWKUP;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief reset remote wakeup signaling
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_rwkup_reset(usb_core_driver *udev)
|
||||
{
|
||||
if (udev->dev.pm.dev_remote_wakeup)
|
||||
{
|
||||
/* disable remote wakeup signaling */
|
||||
udev->regs.dr->DCTL &= ~DCTL_RWKUP;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable USB BCD function
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_bcd_enable(usb_core_driver *udev)
|
||||
{
|
||||
udev->regs.gr->GCCFG |= GCCFG_BCDEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable USB BCD function
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_bcd_disable(usb_core_driver *udev)
|
||||
{
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_BCDEN;
|
||||
}
|
||||
|
||||
/* function declarations */
|
||||
/* initialize USB core registers for device mode */
|
||||
usb_status usb_devcore_init(usb_core_driver *udev);
|
||||
/* enable the USB device mode interrupts */
|
||||
usb_status usb_devint_enable(usb_core_driver *udev);
|
||||
/* active the USB endpoint 0 transaction */
|
||||
usb_status usb_transc0_active(usb_core_driver *udev, usb_transc *transc);
|
||||
/* active the USB transaction */
|
||||
usb_status usb_ep_active(usb_core_driver *udev, uint8_t ep_addr, uint8_t ep_mps, uint8_t ep_attr);
|
||||
/* deactivate the USB transaction */
|
||||
usb_status usb_ep_deactivate(usb_core_driver *udev, uint8_t ep_addr);
|
||||
/* configure USB transaction to start IN transfer */
|
||||
usb_status usb_ep_inxfer(usb_core_driver *udev, uint8_t ep_addr, uint8_t *buf, uint16_t count);
|
||||
/* configure USB transaction to start OUT transfer */
|
||||
usb_status usb_ep_outxfer(usb_core_driver *udev, uint8_t ep_addr, uint8_t *buf, uint16_t count);
|
||||
/* set the USB transaction STALL status */
|
||||
usb_status usb_ep_stall(usb_core_driver *udev, uint8_t ep_addr);
|
||||
/* clear the USB transaction STALL status */
|
||||
usb_status usb_ep_clrstall(usb_core_driver *udev, uint8_t ep_addr);
|
||||
/* read device IN endpoint interrupt flag register */
|
||||
uint32_t usb_iepintr_read(usb_core_driver *udev, uint8_t ep_num);
|
||||
/* configures OUT endpoint 0 to receive SETUP packets */
|
||||
void usb_ctlep_startout(usb_core_driver *udev);
|
||||
/* active remote wakeup signaling */
|
||||
void usb_rwkup_active(usb_core_driver *udev);
|
||||
/* active USB core clock */
|
||||
void usb_clock_active(usb_core_driver *udev);
|
||||
/* USB device suspend */
|
||||
void usb_dev_suspend(usb_core_driver *udev);
|
||||
/* stop the device and clean up FIFOs */
|
||||
void usb_dev_stop(usb_core_driver *udev);
|
||||
/* USB battery charging detect operation */
|
||||
bcd_type usbd_bcd_detect(usb_core_driver *udev);
|
||||
|
||||
#endif /* BSP_USING_USB && RT_USING_USB_DEVICE */
|
||||
|
||||
#endif /* DRV_USB_DEV_H */
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#ifndef DRV_USB_HOST_H
|
||||
#define DRV_USB_HOST_H
|
||||
|
||||
#include "drv_usb_core.h"
|
||||
|
||||
#if defined(BSP_USING_USB) && defined(RT_USING_USB_HOST)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USBH_OK = 0U,
|
||||
USBH_BUSY,
|
||||
USBH_FAIL,
|
||||
USBH_NOT_SUPPORTED,
|
||||
USBH_UNRECOVERED_ERROR,
|
||||
USBH_SPEED_UNKNOWN_ERROR,
|
||||
USBH_APPLY_DEINIT
|
||||
} usbh_status;
|
||||
|
||||
/*!
|
||||
\brief get USB even frame
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval USB even frame state
|
||||
*/
|
||||
__STATIC_INLINE uint8_t usb_frame_even(usb_core_driver *udev)
|
||||
{
|
||||
return (uint8_t) !(udev->regs.hr->HFINFR & 0x01U);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read USB port
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval port status
|
||||
*/
|
||||
__STATIC_INLINE uint32_t usb_port_read(usb_core_driver *udev)
|
||||
{
|
||||
return *udev->regs.HPCS & ~(HPCS_PE | HPCS_PCD | HPCS_PEDC);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get USB current speed
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval USB current speed
|
||||
*/
|
||||
__STATIC_INLINE uint32_t usb_curspeed_get(usb_core_driver *udev)
|
||||
{
|
||||
return *udev->regs.HPCS & HPCS_PS;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get USB current frame
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval USB current frame
|
||||
*/
|
||||
__STATIC_INLINE uint32_t usb_curframe_get(usb_core_driver *udev)
|
||||
{
|
||||
return (udev->regs.hr->HFINFR & 0xFFFFU);
|
||||
}
|
||||
|
||||
/* function declarations */
|
||||
/* initializes USB core for host mode */
|
||||
usb_status usb_host_init(usb_core_driver *udev);
|
||||
/* control the VBUS to power */
|
||||
void usb_portvbus_switch(usb_core_driver *udev, uint8_t state);
|
||||
/* reset host port */
|
||||
uint32_t usb_port_reset(usb_core_driver *udev);
|
||||
/* initialize host pipe */
|
||||
usb_status usb_pipe_init(usb_core_driver *udev, uint8_t pipe_num);
|
||||
/* prepare host pipe for transferring packets */
|
||||
usb_status usb_pipe_xfer(usb_core_driver *udev, uint8_t pipe_num);
|
||||
/* halt host pipe */
|
||||
usb_status usb_pipe_halt(usb_core_driver *udev, uint8_t pipe_num);
|
||||
/* configure host pipe to do ping operation */
|
||||
usb_status usb_pipe_ping(usb_core_driver *udev, uint8_t pipe_num);
|
||||
/* stop the USB host and clean up FIFO */
|
||||
void usb_host_stop(usb_core_driver *udev);
|
||||
|
||||
#endif /* BSP_USING_USB && RT_USING_USB_HOST */
|
||||
|
||||
#endif /* DRV_USB_HOST_H */
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#ifndef DRV_USB_HW_H
|
||||
#define DRV_USB_HW_H
|
||||
|
||||
#include "drv_usb_core.h"
|
||||
|
||||
/* function declarations */
|
||||
/* configure USB clock */
|
||||
void usb_rcu_config(void);
|
||||
/* configure USB data line GPIO */
|
||||
void usb_gpio_config(void);
|
||||
/* configure USB interrupt */
|
||||
void usb_intr_config(void);
|
||||
/* initializes delay unit using Timer2 */
|
||||
void usb_timer_init(void);
|
||||
/* delay in microseconds */
|
||||
void usb_udelay(const uint32_t usec);
|
||||
/* delay in milliseconds */
|
||||
void usb_mdelay(const uint32_t msec);
|
||||
|
||||
/* configure USB clock */
|
||||
void pllusb_rcu_config(uint32_t usb_periph);
|
||||
|
||||
#ifdef USE_HOST_MODE
|
||||
/* configure systick */
|
||||
void systick_config(void);
|
||||
/* configure USB VBus */
|
||||
void usb_vbus_config(void);
|
||||
/* drive USB VBus */
|
||||
void usb_vbus_drive(uint8_t State);
|
||||
#endif /* USE_HOST_MODE */
|
||||
|
||||
#endif /* DRV_USB_HW_H */
|
||||
@@ -0,0 +1,728 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#ifndef DRV_USB_REGS_H
|
||||
#define DRV_USB_REGS_H
|
||||
|
||||
#include "usb_conf.h"
|
||||
|
||||
#define USBHS0 USBHS_BASE
|
||||
#define USBHS1 (USBHS_BASE + 0x00040000U)
|
||||
|
||||
#define USBHS0_REG_BASE USBHS0 /*!< base address of USBHS0 registers */
|
||||
#define USBHS1_REG_BASE USBHS1 /*!< base address of USBHS1 registers */
|
||||
|
||||
/* register definition */
|
||||
|
||||
#define USBHS_MAX_TX_FIFOS 16U /*!< FIFO number */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__IO uint32_t GOTGCS; /*!< USB global OTG control and status register 000h */
|
||||
__IO uint32_t GOTGINTF; /*!< USB global OTG interrupt flag register 004h */
|
||||
__IO uint32_t GAHBCS; /*!< USB global AHB control and status register 008h */
|
||||
__IO uint32_t GUSBCS; /*!< USB global USB control and status register 00Ch */
|
||||
__IO uint32_t GRSTCTL; /*!< USB global reset control register 010h */
|
||||
__IO uint32_t GINTF; /*!< USB global interrupt flag register 014h */
|
||||
__IO uint32_t GINTEN; /*!< USB global interrupt enable register 018h */
|
||||
__IO uint32_t GRSTATR; /*!< USB receive status debug read register 01Ch */
|
||||
__IO uint32_t GRSTATP; /*!< USB receive status and pop register 020h */
|
||||
__IO uint32_t GRFLEN; /*!< USB global receive FIFO length register 024h */
|
||||
__IO uint32_t DIEP0TFLEN_HNPTFLEN; /*!< USB device IN endpoint 0/host non-periodic transmit FIFO length register 028h */
|
||||
__IO uint32_t HNPTFQSTAT; /*!< USB host non-periodic FIFO/queue status register 02Ch */
|
||||
uint32_t Reserved30[2]; /*!< Reserved 030h */
|
||||
__IO uint32_t GCCFG; /*!< USB global core configuration register 038h */
|
||||
__IO uint32_t CID; /*!< USB core ID register 03Ch */
|
||||
uint32_t Reserved40[5]; /*!< Reserved 040h-053h */
|
||||
__IO uint32_t GLPMCFG; /*!< LPM configuration register 54h */
|
||||
__IO uint32_t PWRD; /*!< power down register 58h */
|
||||
uint32_t Reserved5C; /*!< Reserved 5Ch */
|
||||
__IO uint32_t ADPCTL; /*!< ADP control and status register 60h */
|
||||
uint32_t Reserved64[3]; /*!< Reserved 64h-6Fh */
|
||||
__IO uint32_t PHYCTL; /*!< USBHS PHY control register 70h */
|
||||
uint32_t Reserved74[35]; /*!< Reserved 74h-FFh */
|
||||
__IO uint32_t HPTFLEN; /*!< USB host periodic transmit FIFO length register 100h */
|
||||
__IO uint32_t DIEPTFLEN[15]; /*!< USB device IN endpoint transmit FIFO length register 104h */
|
||||
} usb_gr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__IO uint32_t HCTL; /*!< USB host control register 400h */
|
||||
__IO uint32_t HFT; /*!< USB host frame interval register 404h */
|
||||
__IO uint32_t HFINFR; /*!< USB host frame information remaining register 408h */
|
||||
uint32_t Reserved40C; /*!< Reserved 40Ch */
|
||||
__IO uint32_t HPTFQSTAT; /*!< USB host periodic transmit FIFO/queue status register 410h */
|
||||
__IO uint32_t HACHINT; /*!< USB host all channels interrupt register 414h */
|
||||
__IO uint32_t HACHINTEN; /*!< USB host all channels interrupt enable register 418h */
|
||||
} usb_hr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__IO uint32_t HCHCTL; /*!< USB host channel control register 500h */
|
||||
__IO uint32_t HCHSTCTL; /*!< Reserved 504h */
|
||||
__IO uint32_t HCHINTF; /*!< USB host channel interrupt flag register 508h */
|
||||
__IO uint32_t HCHINTEN; /*!< USB host channel interrupt enable register 50Ch */
|
||||
__IO uint32_t HCHLEN; /*!< USB host channel transfer length register 510h */
|
||||
__IO uint32_t HCHDMAADDR; /*!< USB host channel-x DMA address register 514h*/
|
||||
uint32_t Reserved[2];
|
||||
} usb_pr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__IO uint32_t DCFG; /*!< USB device configuration register 800h */
|
||||
__IO uint32_t DCTL; /*!< USB device control register 804h */
|
||||
__IO uint32_t DSTAT; /*!< USB device status register 808h */
|
||||
uint32_t Reserved0C; /*!< Reserved 80Ch */
|
||||
__IO uint32_t DIEPINTEN; /*!< USB device IN endpoint common interrupt enable register 810h */
|
||||
__IO uint32_t DOEPINTEN; /*!< USB device OUT endpoint common interrupt enable register 814h */
|
||||
__IO uint32_t DAEPINT; /*!< USB device all endpoints interrupt register 818h */
|
||||
__IO uint32_t DAEPINTEN; /*!< USB device all endpoints interrupt enable register 81Ch */
|
||||
uint32_t Reserved20; /*!< Reserved 820h */
|
||||
uint32_t Reserved24; /*!< Reserved 824h */
|
||||
__IO uint32_t DVBUSDT; /*!< USB device VBUS discharge time register 828h */
|
||||
__IO uint32_t DVBUSPT; /*!< USB device VBUS pulsing time register 82Ch */
|
||||
uint32_t Reserved30; /*!< Reserved 830h */
|
||||
__IO uint32_t DIEPFEINTEN; /*!< USB Device IN endpoint FIFO empty interrupt enable register 834h */
|
||||
__IO uint32_t DEP1INT; /*!< USB device endpoint 1 interrupt register 838h */
|
||||
__IO uint32_t DEP1INTEN; /*!< USB device endpoint 1 interrupt enable register 83Ch */
|
||||
uint32_t Reserved40; /*!< Reserved 840h */
|
||||
__IO uint32_t DIEP1INTEN; /*!< USB device IN endpoint-1 interrupt enable register 844h */
|
||||
uint32_t Reserved48[15]; /*!< Reserved 848-880h */
|
||||
__IO uint32_t DOEP1INTEN; /*!< USB device OUT endpoint-1 interrupt enable register 884h */
|
||||
} usb_dr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__IO uint32_t DIEPCTL; /*!< USB device IN endpoint control register 900h + (EpNum * 20h) + 00h */
|
||||
uint32_t Reserved04; /*!< Reserved 900h + (EpNum * 20h) + 04h */
|
||||
__IO uint32_t DIEPINTF; /*!< USB device IN endpoint interrupt flag register 900h + (EpNum * 20h) + 08h */
|
||||
uint32_t Reserved0C; /*!< Reserved 900h + (EpNum * 20h) + 0Ch */
|
||||
__IO uint32_t DIEPLEN; /*!< USB device IN endpoint transfer length register 900h + (EpNum * 20h) + 10h */
|
||||
__IO uint32_t DIEPDMAADDR; /*!< Device IN endpoint-x DMA address register 900h + (EpNum * 20h) + 14h */
|
||||
__IO uint32_t DIEPTFSTAT; /*!< USB device IN endpoint transmit FIFO status register 900h + (EpNum * 20h) + 18h */
|
||||
} usb_erin;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__IO uint32_t DOEPCTL; /*!< USB device IN endpoint control register B00h + (EpNum * 20h) + 00h */
|
||||
uint32_t Reserved04; /*!< Reserved B00h + (EpNum * 20h) + 04h */
|
||||
__IO uint32_t DOEPINTF; /*!< USB device IN endpoint interrupt flag register B00h + (EpNum * 20h) + 08h */
|
||||
uint32_t Reserved0C; /*!< Reserved B00h + (EpNum * 20h) + 0Ch */
|
||||
__IO uint32_t DOEPLEN; /*!< USB device IN endpoint transfer length register B00h + (EpNum * 20h) + 10h */
|
||||
__IO uint32_t DOEPDMAADDR; /*!< Device OUT endpoint-x DMA address register B00h + (EpNum * 20h) + 0Ch */
|
||||
} usb_erout;
|
||||
|
||||
typedef struct _usb_regs
|
||||
{
|
||||
usb_gr *gr; /*!< USBHS global registers */
|
||||
usb_dr *dr; /*!< device control and status registers */
|
||||
usb_hr *hr; /*!< host control and status registers */
|
||||
usb_erin *er_in[8]; /*!< USB device IN endpoint register */
|
||||
usb_erout *er_out[8]; /*!< USB device OUT endpoint register */
|
||||
usb_pr *pr[16]; /*!< USB Host channel-x control register */
|
||||
|
||||
__IO uint32_t *HPCS; /*!< USB host port control and status register */
|
||||
__IO uint32_t *DFIFO[USBHS_MAX_TX_FIFOS];
|
||||
__IO uint32_t *PWRCLKCTL; /*!< USB power and clock control register */
|
||||
} usb_core_regs;
|
||||
|
||||
/* global OTG control and status register bits definitions */
|
||||
#define GOTGCS_OV BIT(20) /*!< select OTG version */
|
||||
#define GOTGCS_BSV BIT(19) /*!< B-Session Valid */
|
||||
#define GOTGCS_ASV BIT(18) /*!< A-session valid */
|
||||
#define GOTGCS_DI BIT(17) /*!< debounce interval */
|
||||
#define GOTGCS_IDPS BIT(16) /*!< id pin status */
|
||||
#define GOTGCS_EHE BIT(12) /*!< embedded host enable */
|
||||
#define GOTGCS_DHNPEN BIT(11) /*!< device HNP enable */
|
||||
#define GOTGCS_HHNPEN BIT(10) /*!< host HNP enable */
|
||||
#define GOTGCS_HNPREQ BIT(9) /*!< HNP request */
|
||||
#define GOTGCS_HNPS BIT(8) /*!< HNP successes */
|
||||
#define GOTGCS_BVOV BIT(7) /*!< override value of B-peripheral session valid */
|
||||
#define GOTGCS_BVOE BIT(6) /*!< override enable of B-peripheral session valid */
|
||||
#define GOTGCS_AVOV BIT(5) /*!< override value of A-peripheral session valid */
|
||||
#define GOTGCS_AVOE BIT(4) /*!< override enable of A-peripheral session valid */
|
||||
#define GOTGCS_VOV BIT(3) /*!< override value of VBUS valid */
|
||||
#define GOTGCS_VOE BIT(2) /*!< override enable of VBUS valid */
|
||||
#define GOTGCS_SRPREQ BIT(1) /*!< SRP request */
|
||||
#define GOTGCS_SRPS BIT(0) /*!< SRP successes */
|
||||
|
||||
/* global OTG interrupt flag register bits definitions */
|
||||
#define GOTGINTF_IDCHG BIT(20) /*!< ID input change */
|
||||
#define GOTGINTF_DF BIT(19) /*!< debounce finish */
|
||||
#define GOTGINTF_ADTO BIT(18) /*!< A-device timeout */
|
||||
#define GOTGINTF_HNPDET BIT(17) /*!< host negotiation request detected */
|
||||
#define GOTGINTF_HNPEND BIT(9) /*!< HNP end */
|
||||
#define GOTGINTF_SRPEND BIT(8) /*!< SRP end */
|
||||
#define GOTGINTF_SESEND BIT(2) /*!< session end */
|
||||
|
||||
/* global AHB control and status register bits definitions */
|
||||
#define GAHBCS_PTXFTH BIT(8) /*!< periodic Tx FIFO threshold */
|
||||
#define GAHBCS_TXFTH BIT(7) /*!< tx FIFO threshold */
|
||||
#define GAHBCS_DMAEN BIT(5) /*!< DMA function Enable */
|
||||
#define GAHBCS_BURST BITS(1, 4) /*!< the AHB burst type used by DMA */
|
||||
#define GAHBCS_GINTEN BIT(0) /*!< global interrupt enable */
|
||||
|
||||
/* global USB control and status register bits definitions */
|
||||
#define GUSBCS_FDM BIT(30) /*!< force device mode */
|
||||
#define GUSBCS_FHM BIT(29) /*!< force host mode */
|
||||
#define GUSBCS_ULPIEOI BIT(21) /*!< ULPI external over-current indicator */
|
||||
#define GUSBCS_ULPIEVD BIT(20) /*!< ULPI external VBUS driver */
|
||||
#define GUSBCS_UTT BITS(10, 13) /*!< USB turnaround time */
|
||||
#define GUSBCS_HNPCEN BIT(9) /*!< HNP capability enable */
|
||||
#define GUSBCS_SRPCEN BIT(8) /*!< SRP capability enable */
|
||||
#define GUSBCS_EMBPHY_FS BIT(6) /*!< embedded FS PHY selected */
|
||||
#define GUSBCS_EMBPHY_HS BIT(5) /*!< embedded HS PHY selected */
|
||||
#define GUSBCS_HS_CUR_FE BIT(4) /*!< HS current software enable */
|
||||
#define GUSBCS_TOC BITS(0, 2) /*!< timeout calibration */
|
||||
|
||||
/* global reset control register bits definitions */
|
||||
#define GRSTCTL_DMAIDL BIT(31) /*!< DMA idle state */
|
||||
#define GRSTCTL_DMABSY BIT(30) /*!< DMA busy */
|
||||
#define GRSTCTL_TXFNUM BITS(6, 10) /*!< tx FIFO number */
|
||||
#define GRSTCTL_TXFF BIT(5) /*!< tx FIFO flush */
|
||||
#define GRSTCTL_RXFF BIT(4) /*!< rx FIFO flush */
|
||||
#define GRSTCTL_HFCRST BIT(2) /*!< host frame counter reset */
|
||||
#define GRSTCTL_HCSRST BIT(1) /*!< HCLK soft reset */
|
||||
#define GRSTCTL_CSRST BIT(0) /*!< core soft reset */
|
||||
|
||||
/* global interrupt flag register bits definitions */
|
||||
#define GINTF_WKUPIF BIT(31) /*!< wakeup interrupt flag */
|
||||
#define GINTF_SESIF BIT(30) /*!< session interrupt flag */
|
||||
#define GINTF_DISCIF BIT(29) /*!< disconnect interrupt flag */
|
||||
#define GINTF_IDPSC BIT(28) /*!< id pin status change */
|
||||
#define GINTF_LPMIF BIT(27) /*!< LPM interrupt flag */
|
||||
#define GINTF_PTXFEIF BIT(26) /*!< periodic tx FIFO empty interrupt flag */
|
||||
#define GINTF_HCIF BIT(25) /*!< host channels interrupt flag */
|
||||
#define GINTF_HPIF BIT(24) /*!< host port interrupt flag */
|
||||
#define GINTF_PXNCIF BIT(21) /*!< periodic transfer not complete interrupt flag */
|
||||
#define GINTF_ISOONCIF BIT(21) /*!< isochronous OUT transfer not complete interrupt flag */
|
||||
#define GINTF_ISOINCIF BIT(20) /*!< isochronous IN transfer not complete interrupt flag */
|
||||
#define GINTF_OEPIF BIT(19) /*!< OUT endpoint interrupt flag */
|
||||
#define GINTF_IEPIF BIT(18) /*!< IN endpoint interrupt flag */
|
||||
#define GINTF_EOPFIF BIT(15) /*!< end of periodic frame interrupt flag */
|
||||
#define GINTF_ISOOPDIF BIT(14) /*!< isochronous OUT packet dropped interrupt flag */
|
||||
#define GINTF_ENUMFIF BIT(13) /*!< enumeration finished */
|
||||
#define GINTF_RST BIT(12) /*!< USB reset */
|
||||
#define GINTF_SP BIT(11) /*!< USB suspend */
|
||||
#define GINTF_ESP BIT(10) /*!< early suspend */
|
||||
#define GINTF_GONAK BIT(7) /*!< global OUT NAK effective */
|
||||
#define GINTF_GNPINAK BIT(6) /*!< global IN non-periodic NAK effective */
|
||||
#define GINTF_NPTXFEIF BIT(5) /*!< non-periodic tx FIFO empty interrupt flag */
|
||||
#define GINTF_RXFNEIF BIT(4) /*!< rx FIFO non-empty interrupt flag */
|
||||
#define GINTF_SOF BIT(3) /*!< start of frame */
|
||||
#define GINTF_OTGIF BIT(2) /*!< OTG interrupt flag */
|
||||
#define GINTF_MFIF BIT(1) /*!< mode fault interrupt flag */
|
||||
#define GINTF_COPM BIT(0) /*!< current operation mode */
|
||||
|
||||
/* global interrupt enable register bits definitions */
|
||||
#define GINTEN_WKUPIE BIT(31) /*!< wakeup interrupt enable */
|
||||
#define GINTEN_SESIE BIT(30) /*!< session interrupt enable */
|
||||
#define GINTEN_DISCIE BIT(29) /*!< disconnect interrupt enable */
|
||||
#define GINTEN_IDPSCIE BIT(28) /*!< id pin status change interrupt enable */
|
||||
#define GINTEN_LPMIE BIT(27) /*!< LPM interrupt enable */
|
||||
#define GINTEN_PTXFEIE BIT(26) /*!< periodic tx FIFO empty interrupt enable */
|
||||
#define GINTEN_HCIE BIT(25) /*!< host channels interrupt enable */
|
||||
#define GINTEN_HPIE BIT(24) /*!< host port interrupt enable */
|
||||
#define GINTEN_IPXIE BIT(21) /*!< periodic transfer not complete interrupt enable */
|
||||
#define GINTEN_ISOONCIE BIT(21) /*!< isochronous OUT transfer not complete interrupt enable */
|
||||
#define GINTEN_ISOINCIE BIT(20) /*!< isochronous IN transfer not complete interrupt enable */
|
||||
#define GINTEN_OEPIE BIT(19) /*!< OUT endpoints interrupt enable */
|
||||
#define GINTEN_IEPIE BIT(18) /*!< IN endpoints interrupt enable */
|
||||
#define GINTEN_EOPFIE BIT(15) /*!< end of periodic frame interrupt enable */
|
||||
#define GINTEN_ISOOPDIE BIT(14) /*!< isochronous OUT packet dropped interrupt enable */
|
||||
#define GINTEN_ENUMFIE BIT(13) /*!< enumeration finish enable */
|
||||
#define GINTEN_RSTIE BIT(12) /*!< USB reset interrupt enable */
|
||||
#define GINTEN_SPIE BIT(11) /*!< USB suspend interrupt enable */
|
||||
#define GINTEN_ESPIE BIT(10) /*!< early suspend interrupt enable */
|
||||
#define GINTEN_GONAKIE BIT(7) /*!< global OUT NAK effective interrupt enable */
|
||||
#define GINTEN_GNPINAKIE BIT(6) /*!< global non-periodic IN NAK effective interrupt enable */
|
||||
#define GINTEN_NPTXFEIE BIT(5) /*!< non-periodic Tx FIFO empty interrupt enable */
|
||||
#define GINTEN_RXFNEIE BIT(4) /*!< receive FIFO non-empty interrupt enable */
|
||||
#define GINTEN_SOFIE BIT(3) /*!< start of frame interrupt enable */
|
||||
#define GINTEN_OTGIE BIT(2) /*!< OTG interrupt enable */
|
||||
#define GINTEN_MFIE BIT(1) /*!< mode fault interrupt enable */
|
||||
|
||||
/* global receive status read and pop register bits definitions */
|
||||
#define GRSTATRP_RPCKST BITS(17, 20) /*!< received packet status */
|
||||
#define GRSTATRP_DPID BITS(15, 16) /*!< data PID */
|
||||
#define GRSTATRP_BCOUNT BITS(4, 14) /*!< byte count */
|
||||
#define GRSTATRP_CNUM BITS(0, 3) /*!< channel number */
|
||||
#define GRSTATRP_EPNUM BITS(0, 3) /*!< endpoint number */
|
||||
|
||||
/* global receive FIFO length register bits definitions */
|
||||
#define GRFLEN_RXFD BITS(0, 15) /*!< rx FIFO depth */
|
||||
|
||||
/* host non-periodic transmit FIFO length register bits definitions */
|
||||
#define HNPTFLEN_HNPTXFD BITS(16, 31) /*!< non-periodic Tx FIFO depth */
|
||||
#define HNPTFLEN_HNPTXRSAR BITS(0, 15) /*!< non-periodic Tx RAM start address */
|
||||
|
||||
/* USB IN endpoint 0 transmit FIFO length register bits definitions */
|
||||
#define DIEP0TFLEN_IEP0TXFD BITS(16, 31) /*!< IN Endpoint 0 Tx FIFO depth */
|
||||
#define DIEP0TFLEN_IEP0TXRSAR BITS(0, 15) /*!< IN Endpoint 0 TX RAM start address */
|
||||
|
||||
/* host non-periodic transmit FIFO/queue status register bits definitions */
|
||||
#define HNPTFQSTAT_NPTXRQTOP BITS(24, 30) /*!< top entry of the non-periodic Tx request queue */
|
||||
#define HNPTFQSTAT_NPTXRQS BITS(16, 23) /*!< non-periodic Tx request queue space */
|
||||
#define HNPTFQSTAT_NPTXFS BITS(0, 15) /*!< non-periodic Tx FIFO space */
|
||||
#define HNPTFQSTAT_CNUM BITS(27, 30) /*!< channel number*/
|
||||
#define HNPTFQSTAT_EPNUM BITS(27, 30) /*!< endpoint number */
|
||||
#define HNPTFQSTAT_TYPE BITS(25, 26) /*!< token type */
|
||||
#define HNPTFQSTAT_TMF BIT(24) /*!< terminate flag */
|
||||
|
||||
/* global core configuration register bits definitions */
|
||||
#define GCCFG_VDEN BIT(21) /*!< enable of VBUS sensing comparator to detect VBUS valid */
|
||||
#define GCCFG_SOFOEN BIT(20) /*!< SOF output enable */
|
||||
#define GCCFG_PWRON BIT(16) /*!< power on */
|
||||
#define GCCFG_SDMEN BIT(15) /*!< secondary detection mode enable */
|
||||
#define GCCFG_PEMEN BIT(14) /*!< primary detection mode enable */
|
||||
#define GCCFG_DCDEN BIT(13) /*!< data connect detection mode enable */
|
||||
#define GCCFG_BCDEN BIT(12) /*!< battery charging detection enable */
|
||||
#define GCCFG_PS2F BIT(3) /*!< PS2 detection status */
|
||||
#define GCCFG_SDF BIT(2) /*!< secondary detection status */
|
||||
#define GCCFG_PDF BIT(1) /*!< primary detection status */
|
||||
#define GCCFG_DCDF BIT(0) /*!< battery connect detection status */
|
||||
|
||||
/* core ID register bits definitions */
|
||||
#define CID_CID BITS(0, 31) /*!< core ID */
|
||||
|
||||
/* global core LPM configuration register bits definitions */
|
||||
#define GLPMCFG_BESLEN BIT(28) /*!< LPM Errata selection enable */
|
||||
#define GLPMCFG_LPMRCS BITS(25, 27) /*!< LPM retry count status */
|
||||
#define GLPMCFG_LPMSND BIT(24) /*!< send LPM transaction */
|
||||
#define GLPMCFG_LPMRC BITS(21, 23) /*!< LPM retry count */
|
||||
#define GLPMCFG_LPMCHI BITS(17, 20) /*!< channel number index */
|
||||
#define GLPMCFG_RSOK BIT(16) /*!< Resume can be sent after sleep state */
|
||||
#define GLPMCFG_LPMSLPS BIT(15) /*!< sleep status */
|
||||
#define GLPMCFG_LPMRSP BITS(13, 14) /*!< response of LPM */
|
||||
#define GLPMCFG_DSEN BIT(12) /*!< deep sleep enable */
|
||||
#define GLPMCFG_BESLTH BITS(8, 11) /*!< BESL threshold */
|
||||
#define GLPMCFG_SSEN BIT(7) /*!< shallow sleep enable */
|
||||
#define GLPMCFG_REW BIT(6) /*!< bRemoteWake value */
|
||||
#define GLPMCFG_BESL BITS(2, 5) /*!< best effort service latency */
|
||||
#define GLPMCFG_ACKLPM BIT(1) /*!< ACK in LPM transaction enable */
|
||||
#define GLPMCFG_LPMEN BIT(0) /*!< LPM enable */
|
||||
|
||||
/* power down register bits definition */
|
||||
#define PWRD_ADPF BIT(23) /*!< ADP event interrupt flag */
|
||||
#define PWRD_ADPMEN BIT(0) /*!< ADP module enable */
|
||||
|
||||
/* ADP control and status register bits definition */
|
||||
#define ADPCTL_RWR BITS(27, 28) /*!< read and write request */
|
||||
#define ADPCTL_ADPTFM BIT(26) /*!< the mask of ADP timeout interrupt flag */
|
||||
#define ADPCTL_ADPSNFM BIT(25) /*!< the mask of ADP sense interrupt flag */
|
||||
#define ADPCTL_ADPPRFM BIT(24) /*!< the mask of ADP probe interrupt flag */
|
||||
#define ADPCTL_ADPTF BIT(23) /*!< ADP timeout interrupt flag */
|
||||
#define ADPCTL_ADPSNF BIT(22) /*!< ADP sense interrupt flag */
|
||||
#define ADPCTL_ADPPRF BIT(21) /*!< ADP probe interrupt flag */
|
||||
#define ADPCTL_ADPEN BIT(20) /*!< ADP enable */
|
||||
#define ADPCTL_ADPRST BIT(19) /*!< ADP reset */
|
||||
#define ADPCTL_SNEN BIT(18) /*!< ADP sense enable */
|
||||
#define ADPCTL_PREN BIT(17) /*!< ADP probe enable */
|
||||
#define ADPCTL_CHGT BITS(6, 16) /*!< the latest time that VBUS ramps from VADPSINK to VADPPRB */
|
||||
#define ADPCTL_PERPR BITS(4, 5) /*!< period of probe */
|
||||
#define ADPCTL_RESOPR BITS(2, 3) /*!< the resolution of CHGT value */
|
||||
#define ADPCTL_DSCHGPR BITS(0, 1) /*!< Time of probe discharge */
|
||||
|
||||
/* USBHS PHY control register bits definitions */
|
||||
#define PHYCTL_HS_CALEN BIT(31) /*!< HS PHY calibration enable */
|
||||
#define PHYCTL_HS_CALR BITS(25, 30) /*!< HS PHY calibration value */
|
||||
#define PHYCTL_HS_RCALR BITS(21, 24) /*!< HS PHY R calibration value */
|
||||
#define PHYCTL_SQUECH BIT(16) /*!< HS PHY squech flag */
|
||||
#define PHYCTL_HS_BIST_DONE BIT(15) /*!< HS PHY bist finished flag */
|
||||
#define PHYCTL_HS_BIST_SUCCESS BIT(14) /*!< HS PHY bist success flag */
|
||||
#define PHYCTL_HS_BIST_FAIL BIT(13) /*!< HS PHY bist fail flag */
|
||||
#define PHYCTL_HS_BIST_PKT_SEL BITS(11, 12) /*!< HS PHY bist packet select */
|
||||
#define PHYCTL_HS_BIST_SEED BITS(3, 10) /*!< HS PHY bist seed */
|
||||
#define PHYCTL_HS_BIST_EN BIT(2) /*!< HS PHY bist enable */
|
||||
#define PHYCTL_HS_BIST_RESET BIT(1) /*!< HS PHY bist logic reset */
|
||||
#define PHYCTL_HS_BIST_START BIT(0) /*!< HS PHY bist start */
|
||||
|
||||
/* host periodic transmit FIFO length register bits definitions */
|
||||
#define HPTFLEN_HPTXFD BITS(16, 31) /*!< host periodic Tx FIFO depth */
|
||||
#define HPTFLEN_HPTXFSAR BITS(0, 15) /*!< host periodic Tx RAM start address */
|
||||
|
||||
/* device IN endpoint transmit FIFO length register bits definitions */
|
||||
#define DIEPTFLEN_IEPTXFD BITS(16, 31) /*!< IN endpoint Tx FIFO x depth */
|
||||
#define DIEPTFLEN_IEPTXRSAR BITS(0, 15) /*!< IN endpoint FIFOx Tx x RAM start address */
|
||||
|
||||
/* host control register bits definitions */
|
||||
#define HCTL_SPDFSLS BIT(2) /*!< speed limited to FS and LS */
|
||||
|
||||
/* host frame interval register bits definitions */
|
||||
#define HFT_FRI BITS(0, 15) /*!< frame interval */
|
||||
|
||||
/* host frame information remaining register bits definitions */
|
||||
#define HFINFR_FRT BITS(16, 31) /*!< frame remaining time */
|
||||
#define HFINFR_FRNUM BITS(0, 15) /*!< frame number */
|
||||
|
||||
/* host periodic transmit FIFO/queue status register bits definitions */
|
||||
#define HPTFQSTAT_PTXREQT BITS(24, 31) /*!< top entry of the periodic Tx request queue */
|
||||
#define HPTFQSTAT_PTXREQS BITS(16, 23) /*!< periodic Tx request queue space */
|
||||
#define HPTFQSTAT_PTXFS BITS(0, 15) /*!< periodic Tx FIFO space */
|
||||
#define HPTFQSTAT_OEFRM BIT(31) /*!< odd/eveb frame */
|
||||
#define HPTFQSTAT_CNUM BITS(27, 30) /*!< channel number */
|
||||
#define HPTFQSTAT_EPNUM BITS(27, 30) /*!< endpoint number */
|
||||
#define HPTFQSTAT_TYPE BITS(25, 26) /*!< token type */
|
||||
#define HPTFQSTAT_TMF BIT(24) /*!< terminate flag */
|
||||
|
||||
#define TFQSTAT_TXFS BITS(0, 15)
|
||||
#define TFQSTAT_CNUM BITS(27, 30)
|
||||
|
||||
/* host all channels interrupt register bits definitions */
|
||||
#define HACHINT_HACHINT BITS(0, 15) /*!< host all channel interrupts */
|
||||
|
||||
/* host all channels interrupt enable register bits definitions */
|
||||
#define HACHINTEN_CINTEN BITS(0, 15) /*!< channel interrupt enable */
|
||||
|
||||
/* host port control and status register bits definitions */
|
||||
#define HPCS_PS BITS(17, 18) /*!< port speed */
|
||||
#define HPCS_PTEST BITS(13, 16) /*!< port test control */
|
||||
#define HPCS_PP BIT(12) /*!< port power */
|
||||
#define HPCS_PLST BITS(10, 11) /*!< port line status */
|
||||
#define HPCS_PRST BIT(8) /*!< port reset */
|
||||
#define HPCS_PSP BIT(7) /*!< port suspend */
|
||||
#define HPCS_PREM BIT(6) /*!< port resume */
|
||||
#define HPCS_PEDC BIT(3) /*!< port enable/disable change */
|
||||
#define HPCS_PE BIT(2) /*!< port enable */
|
||||
#define HPCS_PCD BIT(1) /*!< port connect detected */
|
||||
#define HPCS_PCST BIT(0) /*!< port connect status */
|
||||
|
||||
/* host channel-x control register bits definitions */
|
||||
#define HCHCTL_CEN BIT(31) /*!< channel enable */
|
||||
#define HCHCTL_CDIS BIT(30) /*!< channel disable */
|
||||
#define HCHCTL_ODDFRM BIT(29) /*!< odd frame */
|
||||
#define HCHCTL_DAR BITS(22, 28) /*!< device address */
|
||||
#define HCHCTL_MPC BITS(20, 21) /*!< multiple packet count */
|
||||
#define HCHCTL_EPTYPE BITS(18, 19) /*!< endpoint type */
|
||||
#define HCHCTL_LSD BIT(17) /*!< low-speed device */
|
||||
#define HCHCTL_EPDIR BIT(15) /*!< endpoint direction */
|
||||
#define HCHCTL_EPNUM BITS(11, 14) /*!< endpoint number */
|
||||
#define HCHCTL_MPL BITS(0, 10) /*!< maximum packet length */
|
||||
|
||||
/* host channel-x split transaction register bits definitions */
|
||||
#define HCHSTCTL_SPLEN BIT(31) /*!< enable high-speed split transaction */
|
||||
#define HCHSTCTL_CSPLT BIT(16) /*!< complete-split enable */
|
||||
#define HCHSTCTL_ISOPCE BITS(14, 15) /*!< isochronous OUT payload continuation encoding */
|
||||
#define HCHSTCTL_HADDR BITS(7, 13) /*!< HUB address */
|
||||
#define HCHSTCTL_PADDR BITS(0, 6) /*!< port address */
|
||||
|
||||
/* host channel-x interrupt flag register bits definitions */
|
||||
#define HCHINTF_DTER BIT(10) /*!< data toggle error */
|
||||
#define HCHINTF_REQOVR BIT(9) /*!< request queue overrun */
|
||||
#define HCHINTF_BBER BIT(8) /*!< babble error */
|
||||
#define HCHINTF_USBER BIT(7) /*!< USB bus Error */
|
||||
#define HCHINTF_NYET BIT(6) /*!< NYET */
|
||||
#define HCHINTF_ACK BIT(5) /*!< ACK */
|
||||
#define HCHINTF_NAK BIT(4) /*!< NAK */
|
||||
#define HCHINTF_STALL BIT(3) /*!< STALL */
|
||||
#define HCHINTF_DMAER BIT(2) /*!< DMA error */
|
||||
#define HCHINTF_CH BIT(1) /*!< channel halted */
|
||||
#define HCHINTF_TF BIT(0) /*!< transfer finished */
|
||||
|
||||
/* host channel-x interrupt enable register bits definitions */
|
||||
#define HCHINTEN_DTERIE BIT(10) /*!< data toggle error interrupt enable */
|
||||
#define HCHINTEN_REQOVRIE BIT(9) /*!< request queue overrun interrupt enable */
|
||||
#define HCHINTEN_BBERIE BIT(8) /*!< babble error interrupt enable */
|
||||
#define HCHINTEN_USBERIE BIT(7) /*!< USB bus error interrupt enable */
|
||||
#define HCHINTEN_NYETIE BIT(6) /*!< NYET interrupt enable */
|
||||
#define HCHINTEN_ACKIE BIT(5) /*!< ACK interrupt enable */
|
||||
#define HCHINTEN_NAKIE BIT(4) /*!< NAK interrupt enable */
|
||||
#define HCHINTEN_STALLIE BIT(3) /*!< STALL interrupt enable */
|
||||
#define HCHINTEN_DMAERIE BIT(2) /*!< DMA error interrupt enable */
|
||||
#define HCHINTEN_CHIE BIT(1) /*!< channel halted interrupt enable */
|
||||
#define HCHINTEN_TFIE BIT(0) /*!< transfer finished interrupt enable */
|
||||
|
||||
/* host channel-x transfer length register bits definitions */
|
||||
#define HCHLEN_PING BIT(31) /*!< PING token request */
|
||||
#define HCHLEN_DPID BITS(29, 30) /*!< data PID */
|
||||
#define HCHLEN_PCNT BITS(19, 28) /*!< packet count */
|
||||
#define HCHLEN_TLEN BITS(0, 18) /*!< transfer length */
|
||||
|
||||
/* host channel-x DMA address register bits definitions */
|
||||
#define HCHDMAADDR_DMAADDR BITS(0, 31) /*!< DMA address */
|
||||
|
||||
#define PORT_SPEED(x) (((uint32_t)(x) << 17U) & HPCS_PS) /*!< Port speed */
|
||||
|
||||
#define PORT_SPEED_HIGH PORT_SPEED(0U) /*!< high speed */
|
||||
#define PORT_SPEED_FULL PORT_SPEED(1U) /*!< full speed */
|
||||
#define PORT_SPEED_LOW PORT_SPEED(2U) /*!< low speed */
|
||||
|
||||
#define PIPE_CTL_DAR(x) (((uint32_t)(x) << 22U) & HCHCTL_DAR) /*!< device address */
|
||||
#define PIPE_CTL_EPTYPE(x) (((uint32_t)(x) << 18U) & HCHCTL_EPTYPE) /*!< endpoint type */
|
||||
#define PIPE_CTL_EPNUM(x) (((uint32_t)(x) << 11U) & HCHCTL_EPNUM) /*!< endpoint number */
|
||||
#define PIPE_CTL_EPDIR(x) (((uint32_t)(x) << 15U) & HCHCTL_EPDIR) /*!< endpoint direction */
|
||||
#define PIPE_CTL_EPMPL(x) (((uint32_t)(x) << 0U) & HCHCTL_MPL) /*!< maximum packet length */
|
||||
#define PIPE_CTL_LSD(x) (((uint32_t)(x) << 17U) & HCHCTL_LSD) /*!< low-Speed device */
|
||||
|
||||
#define PIPE_XFER_PCNT(x) (((uint32_t)(x) << 19U) & HCHLEN_PCNT) /*!< packet count */
|
||||
#define PIPE_XFER_DPID(x) (((uint32_t)(x) << 29U) & HCHLEN_DPID) /*!< data PID */
|
||||
|
||||
#define PIPE_DPID_DATA0 PIPE_XFER_DPID(0) /*!< DATA0 */
|
||||
#define PIPE_DPID_DATA1 PIPE_XFER_DPID(2) /*!< DATA1 */
|
||||
#define PIPE_DPID_DATA2 PIPE_XFER_DPID(1) /*!< DATA2 */
|
||||
#define PIPE_DPID_SETUP PIPE_XFER_DPID(3) /*!< MDATA (non-control)/SETUP (control) */
|
||||
|
||||
extern const uint32_t PIPE_DPID[2];
|
||||
|
||||
/* device configuration registers bits definitions */
|
||||
#define DCFG_EOPFT BITS(11, 12) /*!< end of periodic frame time */
|
||||
#define DCFG_DAR BITS(4, 10) /*!< device address */
|
||||
#define DCFG_NZLSOH BIT(2) /*!< non-zero-length status OUT handshake */
|
||||
#define DCFG_DS BITS(0, 1) /*!< device speed */
|
||||
|
||||
/* device control registers bits definitions */
|
||||
#define DCTL_L1RJCT BIT(18) /*!< deep sleep reject */
|
||||
#define DCTL_POIF BIT(11) /*!< power-on initialization finished */
|
||||
#define DCTL_CGONAK BIT(10) /*!< clear global OUT NAK */
|
||||
#define DCTL_SGONAK BIT(9) /*!< set global OUT NAK */
|
||||
#define DCTL_CGINAK BIT(8) /*!< clear global IN NAK */
|
||||
#define DCTL_SGINAK BIT(7) /*!< set global IN NAK */
|
||||
#define DCTL_DTEST BITS(4, 6) /*!< device test control */
|
||||
#define DCTL_GONS BIT(3) /*!< global OUT NAK status */
|
||||
#define DCTL_GINS BIT(2) /*!< global IN NAK status */
|
||||
#define DCTL_SD BIT(1) /*!< soft disconnect */
|
||||
#define DCTL_RWKUP BIT(0) /*!< remote wakeup */
|
||||
|
||||
/* device status registers bits definitions */
|
||||
#define DSTAT_FNRSOF BITS(8, 21) /*!< the frame number of the received SOF. */
|
||||
#define DSTAT_ES BITS(1, 2) /*!< enumerated speed */
|
||||
#define DSTAT_SPST BIT(0) /*!< suspend status */
|
||||
|
||||
/* device IN endpoint common interrupt enable registers bits definitions */
|
||||
#define DIEPINTEN_NAKEN BIT(13) /*!< NAK handshake sent by USBHS interrupt enable bit */
|
||||
#define DIEPINTEN_TXFEEN BIT(7) /*!< transmit FIFO empty interrupt enable bit */
|
||||
#define DIEPINTEN_IEPNEEN BIT(6) /*!< IN endpoint NAK effective interrupt enable bit */
|
||||
#define DIEPINTEN_EPTXFUDEN BIT(4) /*!< endpoint Tx FIFO underrun interrupt enable bit */
|
||||
#define DIEPINTEN_CITOEN BIT(3) /*!< control In Timeout interrupt enable bit */
|
||||
#define DIEPINTEN_EPDISEN BIT(1) /*!< endpoint disabled interrupt enable bit */
|
||||
#define DIEPINTEN_TFEN BIT(0) /*!< transfer finished interrupt enable bit */
|
||||
|
||||
/* device OUT endpoint common interrupt enable registers bits definitions */
|
||||
#define DOEPINTEN_NYETEN BIT(14) /*!< NYET handshake is sent interrupt enable bit */
|
||||
#define DOEPINTEN_BTBSTPEN BIT(6) /*!< back-to-back SETUP packets interrupt enable bit */
|
||||
#define DOEPINTEN_EPRXFOVREN BIT(4) /*!< endpoint Rx FIFO overrun interrupt enable bit */
|
||||
#define DOEPINTEN_STPFEN BIT(3) /*!< SETUP phase finished interrupt enable bit */
|
||||
#define DOEPINTEN_EPDISEN BIT(1) /*!< endpoint disabled interrupt enable bit */
|
||||
#define DOEPINTEN_TFEN BIT(0) /*!< transfer finished interrupt enable bit */
|
||||
|
||||
/* device all endpoints interrupt registers bits definitions */
|
||||
#define DAEPINT_OEPITB BITS(16, 23) /*!< device all OUT endpoint interrupt bits */
|
||||
#define DAEPINT_IEPITB BITS(0, 7) /*!< device all IN endpoint interrupt bits */
|
||||
|
||||
/* device all endpoints interrupt enable registers bits definitions */
|
||||
#define DAEPINTEN_OEPIE BITS(16, 23) /*!< OUT endpoint interrupt enable */
|
||||
#define DAEPINTEN_IEPIE BITS(0, 7) /*!< IN endpoint interrupt enable */
|
||||
|
||||
/* device VBUS discharge time registers bits definitions */
|
||||
#define DVBUSDT_DVBUSDT BITS(0, 15) /*!< device VBUS discharge time */
|
||||
|
||||
/* device VBUS pulsing time registers bits definitions */
|
||||
#define DVBUSPT_DVBUSPT BITS(0, 11) /*!< device VBUS pulsing time */
|
||||
|
||||
/* device IN endpoint FIFO empty interrupt enable register bits definitions */
|
||||
#define DIEPFEINTEN_IEPTXFEIE BITS(0, 5) /*!< IN endpoint Tx FIFO empty interrupt enable bits */
|
||||
|
||||
/* device endpoint 0 control register bits definitions */
|
||||
#define DEP0CTL_EPEN BIT(31) /*!< endpoint enable */
|
||||
#define DEP0CTL_EPD BIT(30) /*!< endpoint disable */
|
||||
#define DEP0CTL_SNAK BIT(27) /*!< set NAK */
|
||||
#define DEP0CTL_CNAK BIT(26) /*!< clear NAK */
|
||||
#define DIEP0CTL_TXFNUM BITS(22, 25) /*!< tx FIFO number */
|
||||
#define DEP0CTL_STALL BIT(21) /*!< STALL handshake */
|
||||
#define DOEP0CTL_SNOOP BIT(20) /*!< snoop mode */
|
||||
#define DEP0CTL_EPTYPE BITS(18, 19) /*!< endpoint type */
|
||||
#define DEP0CTL_NAKS BIT(17) /*!< NAK status */
|
||||
#define DEP0CTL_EPACT BIT(15) /*!< endpoint active */
|
||||
#define DEP0CTL_MPL BITS(0, 1) /*!< maximum packet length */
|
||||
|
||||
/* device endpoint x control register bits definitions */
|
||||
#define DEPCTL_EPEN BIT(31) /*!< endpoint enable */
|
||||
#define DEPCTL_EPD BIT(30) /*!< endpoint disable */
|
||||
#define DEPCTL_SODDFRM BIT(29) /*!< set odd frame */
|
||||
#define DEPCTL_SD1PID BIT(29) /*!< set DATA1 PID */
|
||||
#define DEPCTL_SEVNFRM BIT(28) /*!< set even frame */
|
||||
#define DEPCTL_SD0PID BIT(28) /*!< set DATA0 PID */
|
||||
#define DEPCTL_SNAK BIT(27) /*!< set NAK */
|
||||
#define DEPCTL_CNAK BIT(26) /*!< clear NAK */
|
||||
#define DIEPCTL_TXFNUM BITS(22, 25) /*!< tx FIFO number */
|
||||
#define DEPCTL_STALL BIT(21) /*!< STALL handshake */
|
||||
#define DOEPCTL_SNOOP BIT(20) /*!< snoop mode */
|
||||
#define DEPCTL_EPTYPE BITS(18, 19) /*!< endpoint type */
|
||||
#define DEPCTL_NAKS BIT(17) /*!< NAK status */
|
||||
#define DEPCTL_EOFRM BIT(16) /*!< even/odd frame */
|
||||
#define DEPCTL_DPID BIT(16) /*!< endpoint data PID */
|
||||
#define DEPCTL_EPACT BIT(15) /*!< endpoint active */
|
||||
#define DEPCTL_MPL BITS(0, 10) /*!< maximum packet length */
|
||||
|
||||
/* device IN endpoint-x interrupt flag register bits definitions */
|
||||
#define DIEPINTF_NAK BIT(13) /*!< NAK handshake sent by USBHS */
|
||||
#define DIEPINTF_TXFE BIT(7) /*!< transmit FIFO empty */
|
||||
#define DIEPINTF_IEPNE BIT(6) /*!< IN endpoint NAK effective */
|
||||
#define DIEPINTF_EPTXFUD BIT(4) /*!< endpoint Tx FIFO underrun */
|
||||
#define DIEPINTF_CITO BIT(3) /*!< control In Timeout interrupt */
|
||||
#define DIEPINTF_EPDIS BIT(1) /*!< endpoint disabled */
|
||||
#define DIEPINTF_TF BIT(0) /*!< transfer finished */
|
||||
|
||||
/* device OUT endpoint-x interrupt flag register bits definitions */
|
||||
#define DOEPINTF_NYET BIT(14) /*!< NYET handshake is sent */
|
||||
#define DOEPINTF_BTBSTP BIT(6) /*!< back-to-back SETUP packets */
|
||||
#define DOEPINTF_EPRXFOVR BIT(4) /*!< endpoint Rx FIFO overrun */
|
||||
#define DOEPINTF_STPF BIT(3) /*!< SETUP phase finished */
|
||||
#define DOEPINTF_EPDIS BIT(1) /*!< endpoint disabled */
|
||||
#define DOEPINTF_TF BIT(0) /*!< transfer finished */
|
||||
|
||||
/* device IN endpoint 0 transfer length register bits definitions */
|
||||
#define DIEP0LEN_PCNT BITS(19, 20) /*!< packet count */
|
||||
#define DIEP0LEN_TLEN BITS(0, 6) /*!< transfer length */
|
||||
|
||||
/* device OUT endpoint 0 transfer length register bits definitions */
|
||||
#define DOEP0LEN_STPCNT BITS(29, 30) /*!< SETUP packet count */
|
||||
#define DOEP0LEN_PCNT BIT(19) /*!< packet count */
|
||||
#define DOEP0LEN_TLEN BITS(0, 6) /*!< transfer length */
|
||||
|
||||
/* device OUT endpoint-x transfer length register bits definitions */
|
||||
#define DOEPLEN_RXDPID BITS(29, 30) /*!< received data PID */
|
||||
#define DOEPLEN_STPCNT BITS(29, 30) /*!< SETUP packet count */
|
||||
#define DIEPLEN_MCNT BITS(29, 30) /*!< multi count */
|
||||
#define DEPLEN_PCNT BITS(19, 28) /*!< packet count */
|
||||
#define DEPLEN_TLEN BITS(0, 18) /*!< transfer length */
|
||||
|
||||
/* device IN endpoint-x DMA address register bits definitions */
|
||||
#define DIEPDMAADDR_DMAADDR BITS(0, 31) /*!< DMA address */
|
||||
|
||||
/* device OUT endpoint-x DMA address register bits definitions */
|
||||
#define DOEPDMAADDR_DMAADDR BITS(0, 31) /*!< DMA address */
|
||||
|
||||
/* device IN endpoint-x transmit FIFO status register bits definitions */
|
||||
#define DIEPTFSTAT_IEPTFS BITS(0, 15) /*!< IN endpoint Tx FIFO space remaining */
|
||||
|
||||
/* USB power and clock registers bits definition */
|
||||
#define PWRCLKCTL_DSLEEP BIT(7) /*!< PHY is in deep sleep status */
|
||||
#define PWRCLKCTL_SSLEEP BIT(6) /*!< PHY is in shallow sleep status */
|
||||
#define PWRCLKCTL_SCGEN BIT(5) /*!< When this bit is set, the internal clock gating is enabled */
|
||||
#define PWRCLKCTL_SUSP BIT(4) /*!< PHY is in suspend status */
|
||||
#define PWRCLKCTL_SHCLK BIT(1) /*!< stop HCLK */
|
||||
#define PWRCLKCTL_SUCLK BIT(0) /*!< stop the USB clock */
|
||||
|
||||
#define RSTAT_GOUT_NAK 1U /*!< global OUT NAK (triggers an interrupt) */
|
||||
#define RSTAT_DATA_UPDT 2U /*!< OUT data packet received */
|
||||
#define RSTAT_XFER_COMP 3U /*!< OUT transfer completed (triggers an interrupt) */
|
||||
#define RSTAT_SETUP_COMP 4U /*!< SETUP transaction completed (triggers an interrupt) */
|
||||
#define RSTAT_SETUP_UPDT 6U /*!< SETUP data packet received */
|
||||
|
||||
#define DSTAT_EM_HS_PHY_30MHZ_60MHZ 0U /*!< USB enumerate speed use high-speed PHY clock in 30MHz or 60MHz */
|
||||
#define DSTAT_EM_FS_PHY_30MHZ_60MHZ 1U /*!< USB enumerate speed use full-speed PHY clock in 30MHz or 60MHz */
|
||||
#define DSTAT_EM_LS_PHY_6MHZ 2U /*!< USB enumerate speed use low-speed PHY clock in 6MHz */
|
||||
#define DSTAT_EM_FS_PHY_48MHZ 3U /*!< USB enumerate speed use full-speed PHY clock in 48MHz */
|
||||
|
||||
#define DPID_DATA0 0U /*!< device endpoint data PID is DATA0 */
|
||||
#define DPID_DATA1 2U /*!< device endpoint data PID is DATA1 */
|
||||
#define DPID_DATA2 1U /*!< device endpoint data PID is DATA2 */
|
||||
#define DPID_MDATA 3U /*!< device endpoint data PID is MDATA */
|
||||
|
||||
#define GAHBCS_DMAINCR(regval) (GAHBCS_BURST & ((regval) << 1U)) /*!< AHB burst type used by DMA */
|
||||
|
||||
#define DMA_INCR0 GAHBCS_DMAINCR(0U) /*!< single burst type used by DMA*/
|
||||
#define DMA_INCR1 GAHBCS_DMAINCR(1U) /*!< 4-beat incrementing burst type used by DMA */
|
||||
#define DMA_INCR4 GAHBCS_DMAINCR(3U) /*!< 8-beat incrementing burst type used by DMA */
|
||||
#define DMA_INCR8 GAHBCS_DMAINCR(5U) /*!< 16-beat incrementing burst type used by DMA */
|
||||
#define DMA_INCR16 GAHBCS_DMAINCR(7U) /*!< 32-beat incrementing burst type used by DMA */
|
||||
|
||||
#define DCFG_PFRI(regval) (DCFG_EOPFT & ((regval) << 11U)) /*!< end of periodic frame time configuration */
|
||||
|
||||
#define FRAME_INTERVAL_80 DCFG_PFRI(0U) /*!< 80% of the frame time */
|
||||
#define FRAME_INTERVAL_85 DCFG_PFRI(1U) /*!< 85% of the frame time */
|
||||
#define FRAME_INTERVAL_90 DCFG_PFRI(2U) /*!< 90% of the frame time */
|
||||
#define FRAME_INTERVAL_95 DCFG_PFRI(3U) /*!< 95% of the frame time */
|
||||
|
||||
#define DCFG_DEVSPEED(regval) (DCFG_DS & ((regval) << 0U)) /*!< device speed configuration */
|
||||
|
||||
#define USB_SPEED_INP_HIGH DCFG_DEVSPEED(0U) /*!< device internal PHY high speed */
|
||||
#define USB_SPEED_INP_FULL DCFG_DEVSPEED(1U) /*!< device internal PHY full speed */
|
||||
|
||||
#define DEP0_MPL(regval) (DEP0CTL_MPL & ((regval) << 0U)) /*!< maximum packet length configuration */
|
||||
|
||||
#define EP0MPL_64 DEP0_MPL(0U) /*!< maximum packet length 64 bytes */
|
||||
#define EP0MPL_32 DEP0_MPL(1U) /*!< maximum packet length 32 bytes */
|
||||
#define EP0MPL_16 DEP0_MPL(2U) /*!< maximum packet length 16 bytes */
|
||||
#define EP0MPL_8 DEP0_MPL(3U) /*!< maximum packet length 8 bytes */
|
||||
|
||||
#define DOEP0_TLEN(regval) (DOEP0LEN_TLEN & ((regval) << 0U)) /*!< Transfer length */
|
||||
#define DOEP0_PCNT(regval) (DOEP0LEN_PCNT & ((regval) << 19U)) /*!< Packet count */
|
||||
#define DOEP0_STPCNT(regval) (DOEP0LEN_STPCNT & ((regval) << 29U)) /*!< SETUP packet count */
|
||||
|
||||
#define GRXSTS_PKTSTS_IN 2U
|
||||
#define GRXSTS_PKTSTS_IN_XFER_COMP 3U
|
||||
#define GRXSTS_PKTSTS_DATA_TOGGLE_ERR 5U
|
||||
#define GRXSTS_PKTSTS_CH_HALTED 7U
|
||||
|
||||
#define DEVICE_MODE 0U /*!< device mode */
|
||||
#define HOST_MODE 1U /*!< host mode */
|
||||
#define OTG_MODE 2U /*!< OTG mode */
|
||||
|
||||
#define HCTL_30_60MHZ 0U /*!< USB clock 30-60MHZ */
|
||||
#define HCTL_48MHZ 1U /*!< USB clock 48MHZ */
|
||||
#define HCTL_6MHZ 2U /*!< USB clock 6MHZ */
|
||||
|
||||
#define USBHS_MAX_PACKET_SIZE 512U /*!< USBHS max packet size */
|
||||
#define USBHS_MAX_CHANNEL_COUNT 16U /*!< USBHS host channel count */
|
||||
#define USBHS_MAX_EP_COUNT 8U /*!< USBHS device endpoint count */
|
||||
#define USBHS_MAX_FIFO_WORDLEN 1280U /*!< USBHS max fifo size in words */
|
||||
|
||||
#define USB_DATA_FIFO_OFFSET 0x1000U /*!< USB data fifo offset */
|
||||
#define USB_DATA_FIFO_SIZE 0x1000U /*!< USB data fifo size */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USB_EMBEDDED_PHY_FS = 0U, /*!< USB embedded FS PHY */
|
||||
USB_EMBEDDED_PHY_HS, /*!< USB embedded HS PHY */
|
||||
USB_ULPI_PHY_EXTERNAL /*!< USB external ULPI PHY */
|
||||
} usb_phy_enum;
|
||||
|
||||
enum usb_reg_offset
|
||||
{
|
||||
USB_REG_OFFSET_CORE = 0x0000U, /*!< global OTG control and status register */
|
||||
USB_REG_OFFSET_DEV = 0x0800U, /*!< device mode control and status registers */
|
||||
USB_REG_OFFSET_EP = 0x0020U, /*!< offset of each endpoint */
|
||||
USB_REG_OFFSET_EP_IN = 0x0900U, /*!< device IN endpoint 0 control register */
|
||||
USB_REG_OFFSET_EP_OUT = 0x0B00U, /*!< device OUT endpoint 0 control register */
|
||||
USB_REG_OFFSET_HOST = 0x0400U, /*!< host control register */
|
||||
USB_REG_OFFSET_CH = 0x0020U, /*!< offset of each channel */
|
||||
USB_REG_OFFSET_PORT = 0x0440U, /*!< host port control and status register */
|
||||
USB_REG_OFFSET_CH_INOUT = 0x0500U, /*!< host channel-x control registers */
|
||||
USB_REG_OFFSET_PWRCLKCTL = 0x0E00U /*!< power and clock register */
|
||||
};
|
||||
|
||||
enum USB_SPEED
|
||||
{
|
||||
USB_SPEED_UNKNOWN = 0, /*!< USB speed unknown */
|
||||
USB_SPEED_LOW, /*!< USB speed low */
|
||||
USB_SPEED_FULL, /*!< USB speed full */
|
||||
USB_SPEED_HIGH /*!< USB speed high */
|
||||
};
|
||||
|
||||
#define EP0_OUT ((uint8_t)0x00U) /*!< endpoint out 0 */
|
||||
#define EP0_IN ((uint8_t)0x80U) /*!< endpoint in 0 */
|
||||
#define EP1_OUT ((uint8_t)0x01U) /*!< endpoint out 1 */
|
||||
#define EP1_IN ((uint8_t)0x81U) /*!< endpoint in 1 */
|
||||
#define EP2_OUT ((uint8_t)0x02U) /*!< endpoint out 2 */
|
||||
#define EP2_IN ((uint8_t)0x82U) /*!< endpoint in 2 */
|
||||
#define EP3_OUT ((uint8_t)0x03U) /*!< endpoint out 3 */
|
||||
#define EP3_IN ((uint8_t)0x83U) /*!< endpoint in 3 */
|
||||
#define EP4_OUT ((uint8_t)0x04U) /*!< endpoint out 4 */
|
||||
#define EP4_IN ((uint8_t)0x84U) /*!< endpoint in 4 */
|
||||
#define EP5_OUT ((uint8_t)0x05U) /*!< endpoint out 5 */
|
||||
#define EP5_IN ((uint8_t)0x85U) /*!< endpoint in 5 */
|
||||
#define EP6_OUT ((uint8_t)0x06U) /*!< endpoint out 6 */
|
||||
#define EP6_IN ((uint8_t)0x86U) /*!< endpoint in 6 */
|
||||
#define EP7_OUT ((uint8_t)0x06U) /*!< endpoint out 7 */
|
||||
#define EP7_IN ((uint8_t)0x86U) /*!< endpoint in 7 */
|
||||
|
||||
#endif /* DRV_USB_REGS_H */
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#ifndef DRV_USBD_INT_H
|
||||
#define DRV_USBD_INT_H
|
||||
|
||||
#include "drv_usb_core.h"
|
||||
#include "drv_usb_dev.h"
|
||||
|
||||
/* function declarations */
|
||||
#ifdef USB_DEDICATED_EP1_ENABLED
|
||||
/* USB dedicated OUT endpoint 1 interrupt service routine handler */
|
||||
uint32_t usbd_int_dedicated_ep1out(usb_core_driver *udev);
|
||||
/* USB dedicated IN endpoint 1 interrupt service routine handler */
|
||||
uint32_t usbd_int_dedicated_ep1in(usb_core_driver *udev);
|
||||
#endif /* USB_DEDICATED_EP1_ENABLED */
|
||||
|
||||
/* USB device-mode interrupts global service routine handler */
|
||||
void usbd_isr(usb_core_driver *udev);
|
||||
|
||||
#endif /* DRV_USBD_INT_H */
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#ifndef DRV_USBH_INT_H
|
||||
#define DRV_USBH_INT_H
|
||||
|
||||
#include "drv_usb_host.h"
|
||||
|
||||
/* handle global host interrupt */
|
||||
uint32_t usbh_isr(usb_core_driver *udev);
|
||||
|
||||
#endif /* DRV_USBH_INT_H */
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#ifndef __DRV_USBH_PIPE_H
|
||||
#define __DRV_USBH_PIPE_H
|
||||
|
||||
#include "drv_usb_host.h"
|
||||
|
||||
#define HC_MAX 8U
|
||||
|
||||
#define HC_OK 0x0000U
|
||||
#define HC_USED 0x8000U
|
||||
#define HC_ERROR 0xFFFFU
|
||||
#define HC_USED_MASK 0x7FFFU
|
||||
|
||||
/* allocate a new pipe */
|
||||
uint8_t usbh_pipe_allocate(usb_core_driver *pudev, uint8_t ep_addr);
|
||||
|
||||
/* delete all USB host pipe */
|
||||
uint8_t usbh_pipe_delete(usb_core_driver *pudev);
|
||||
|
||||
/* free a pipe */
|
||||
uint8_t usbh_pipe_free(usb_core_driver *pudev, uint8_t pp_num);
|
||||
|
||||
/* create a pipe */
|
||||
uint8_t usbh_pipe_create(usb_core_driver *pudev,
|
||||
uint8_t dev_addr,
|
||||
uint8_t dev_speed,
|
||||
uint8_t pp_num,
|
||||
uint8_t ep_num,
|
||||
uint8_t ep_type,
|
||||
uint16_t ep_mpl);
|
||||
|
||||
/* modify a pipe */
|
||||
uint8_t usbh_pipe_update(usb_core_driver *pudev,
|
||||
uint8_t pp_num,
|
||||
uint8_t dev_addr,
|
||||
uint32_t dev_speed,
|
||||
uint16_t ep_mpl);
|
||||
|
||||
#endif /* __DRV_USBH_PIPE_H */
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#ifndef __DRV_USBH_TRANSC_H
|
||||
#define __DRV_USBH_TRANSC_H
|
||||
|
||||
#include "drv_usb_host.h"
|
||||
|
||||
#if defined(BSP_USING_USB) && defined(RT_USING_USB_HOST)
|
||||
|
||||
/* send the setup packet to the USB device */
|
||||
usbh_status usbh_ctlsetup_send(usb_core_driver *pudev, uint8_t *buf, uint8_t pp_num);
|
||||
|
||||
/* send a data packet to the USB device */
|
||||
usbh_status usbh_data_send(usb_core_driver *pudev, uint8_t *buf, uint8_t pp_num, uint16_t len);
|
||||
|
||||
/* receive a data packet from the USB device */
|
||||
usbh_status usbh_data_recev(usb_core_driver *pudev, uint8_t *buf, uint8_t pp_num, uint16_t len);
|
||||
|
||||
/* get USB URB state */
|
||||
static inline usb_urb_state usbh_urbstate_get(usb_core_driver *pudev, uint8_t pp_num)
|
||||
{
|
||||
return pudev->host.pipe[pp_num].urb_state;
|
||||
}
|
||||
|
||||
/* get USB transfer data count */
|
||||
static inline uint32_t usbh_xfercount_get(usb_core_driver *pudev, uint8_t pp_num)
|
||||
{
|
||||
return pudev->host.backup_xfercount[pp_num];
|
||||
}
|
||||
|
||||
#endif /* BSP_USING_USB && RT_USING_USB_HOST */
|
||||
#endif /* __DRV_USBH_TRANSC_H */
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#ifndef USB_CONF_H
|
||||
#define USB_CONF_H
|
||||
|
||||
#include <board.h>
|
||||
|
||||
#if defined(BSP_USING_USB)
|
||||
|
||||
#if defined(SOC_SERIES_GD32H75E)
|
||||
#include "gd32h75e.h"
|
||||
#elif defined(SOC_SERIES_GD32H7xx)
|
||||
#include "gd32h7xx.h"
|
||||
#endif
|
||||
/* USB Core and PHY interface configuration */
|
||||
|
||||
/* USB HS PHY CONFIGURATION */
|
||||
|
||||
/* on-chip full-speed USB PHY */
|
||||
#ifdef USE_USB_FS
|
||||
#define OC_FS_PHY
|
||||
#endif
|
||||
|
||||
/* on-chip high-speed USB PHY */
|
||||
#ifdef USE_USB_HS
|
||||
#define OC_HS_PHY
|
||||
#endif /* USE_USB_HS */
|
||||
|
||||
#if defined(RT_USING_USB_DEVICE)
|
||||
|
||||
#define USB_SOF_OUTPUT 0U
|
||||
|
||||
/* USB FIFO size config */
|
||||
#define RX_FIFO_SIZE 512U
|
||||
#define TX0_FIFO_SIZE 128U
|
||||
#define TX1_FIFO_SIZE 384U
|
||||
#define TX2_FIFO_SIZE 0U
|
||||
#define TX3_FIFO_SIZE 0U
|
||||
#define TX4_FIFO_SIZE 0U
|
||||
#define TX5_FIFO_SIZE 0U
|
||||
#define TX6_FIFO_SIZE 0U
|
||||
#define TX7_FIFO_SIZE 0U
|
||||
|
||||
#elif defined(RT_USING_USB_HOST)
|
||||
|
||||
#define USBH_USE_RTOS
|
||||
#define USB_SOF_OUTPUT 1U
|
||||
|
||||
/* USB FIFO size config */
|
||||
#define USB_RX_FIFO_SIZE 512
|
||||
#define USB_HTX_NPFIFO_SIZE 256
|
||||
#define USB_HTX_PFIFO_SIZE 256
|
||||
#endif
|
||||
|
||||
/* General USB Configuration */
|
||||
#define USB_LOW_POWER 0U
|
||||
|
||||
/* if uncomment it, need jump to USB JP */
|
||||
//#define VBUS_SENSING_ENABLED
|
||||
|
||||
//#define USB_INTERNAL_DMA_ENABLED
|
||||
//#define USB_DEDICATED_EP1_ENABLED
|
||||
/* End General USB Configuration */
|
||||
|
||||
#ifdef USE_ULPI_PHY
|
||||
#define USB_EXTERNAL_ULPI_PHY_ENABLED
|
||||
#else
|
||||
#ifdef OC_FS_PHY
|
||||
#define USB_EMBEDDED_FS_PHY_ENABLED
|
||||
#elif defined(OC_HS_PHY)
|
||||
#define USB_EMBEDDED_HS_PHY_ENABLED
|
||||
#else
|
||||
#error "PHY is not selected"
|
||||
#endif /* OC_FS_PHY */
|
||||
#endif /* USE_ULPI_PHY */
|
||||
|
||||
#if defined(RT_USING_USB_HOST)
|
||||
#define USE_HOST_MODE
|
||||
#elif defined(RT_USING_USB_DEVICE)
|
||||
#define USE_DEVICE_MODE
|
||||
#else
|
||||
#warning "Please select the USB mode as USBD or USBH; otherwise, the USE_OTG_MODE will be enabled by default."
|
||||
#define USE_OTG_MODE
|
||||
#endif
|
||||
|
||||
#ifndef OC_FS_PHY
|
||||
#ifndef OC_HS_PHY
|
||||
#error "OC_FS_PHY or OC_HS_PHY should be defined!"
|
||||
#endif
|
||||
#endif /* OC_FS_PHY */
|
||||
|
||||
#ifndef RT_USING_USB_DEVICE
|
||||
#ifndef RT_USING_USB_HOST
|
||||
#error "RT_USING_USB_DEVICE or RT_USING_USB_HOST should be defined!"
|
||||
#endif
|
||||
#endif /* USE_DEVICE_MODE */
|
||||
|
||||
#ifndef USE_USB_HS
|
||||
#ifndef USE_USB_FS
|
||||
#error "USE_USB_HS or USE_USB_FS should be defined!"
|
||||
#endif
|
||||
#endif /* USE_USB_HS */
|
||||
|
||||
/* all variables and data structures during the transaction process should be 4-bytes aligned */
|
||||
#if defined(__GNUC__) /* GNU Compiler */
|
||||
#define __ALIGN_END __attribute__((aligned(4)))
|
||||
#define __ALIGN_BEGIN
|
||||
#else
|
||||
#define __ALIGN_END
|
||||
|
||||
#if defined(__CC_ARM) /* ARM Compiler */
|
||||
#define __ALIGN_BEGIN __align(4)
|
||||
#elif defined(__ICCARM__) /* IAR Compiler */
|
||||
#define __ALIGN_BEGIN
|
||||
#elif defined(__TASKING__)/* TASKING Compiler */
|
||||
#define __ALIGN_BEGIN __align(4)
|
||||
#endif /* __CC_ARM */
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
/* __packed keyword used to decrease the data type alignment to 1-byte */
|
||||
#if defined(__GNUC__) /* GNU Compiler */
|
||||
#ifndef __packed
|
||||
#define __packed __unaligned
|
||||
#endif
|
||||
#elif defined(__TASKING__) /* TASKING Compiler */
|
||||
#define __packed __unaligned
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#endif /* BSP_USING_USB */
|
||||
|
||||
#endif /* USB_CONF_H */
|
||||
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#if defined(RT_USING_SAL) && defined(RT_USING_NETDEV) && defined(RT_USING_LWIP)
|
||||
|
||||
#include "synopsys_emac.h"
|
||||
#include "gd32h7xx_enet.h"
|
||||
|
||||
/* The state of enet initialization */
|
||||
volatile uint32_t enet_init_state = 0;
|
||||
|
||||
/* Global pointers on Tx and Rx descriptor used to track transmit and receive descriptors */
|
||||
extern EMAC_DMADESCTypeDef *DMATxDescToSet;
|
||||
extern EMAC_DMADESCTypeDef *DMARxDescToGet;
|
||||
|
||||
/**
|
||||
* Initializes the ETHERNET peripheral according to the specified
|
||||
*/
|
||||
rt_uint32_t EMAC_init(struct rt_synopsys_eth *ETHERNET_MAC, rt_uint32_t SystemCoreClock)
|
||||
{
|
||||
/*-------------------------------- Reset ethernet -------------------------------*/
|
||||
enet_deinit(ENET0);
|
||||
enet_software_reset(ENET0);
|
||||
|
||||
/* configure the parameters which are usually less cared for enet initialization */
|
||||
enet_initpara_config(HALFDUPLEX_OPTION, ENET_CARRIERSENSE_DISABLE | ENET_RECEIVEOWN_ENABLE | ENET_RETRYTRANSMISSION_DISABLE | ENET_BACKOFFLIMIT_10 | ENET_DEFERRALCHECK_DISABLE);
|
||||
|
||||
/*-------------------------------- Initialize ENET ------------------------------*/
|
||||
#ifdef RT_LWIP_USING_HW_CHECKSUM
|
||||
enet_init_state = enet_init(ENET0, ENET_AUTO_NEGOTIATION, ENET_AUTOCHECKSUM_DROP_FAILFRAMES, ENET_BROADCAST_FRAMES_PASS);
|
||||
#else
|
||||
enet_init_state = enet_init(ENET0, ENET_AUTO_NEGOTIATION, ENET_NO_AUTOCHECKSUM, ENET_BROADCAST_FRAMES_PASS);
|
||||
#endif
|
||||
if (SUCCESS != enet_init_state)
|
||||
{
|
||||
rt_kprintf("enet init failed. \r\n");
|
||||
return EMAC_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Return Ethernet configuration success */
|
||||
return EMAC_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the specified ETHERNET DMA interrupts.
|
||||
*/
|
||||
void EMAC_INT_config(struct rt_synopsys_eth *ETHERNET_MAC, rt_uint32_t EMAC_DMA_IT, rt_bool_t NewState)
|
||||
{
|
||||
if (NewState)
|
||||
{
|
||||
/* Enable the selected ETHERNET DMA interrupts */
|
||||
ETHERNET_MAC->IER |= EMAC_DMA_IT;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Disable the selected ETHERNET DMA interrupts */
|
||||
ETHERNET_MAC->IER &= (~(rt_uint32_t)EMAC_DMA_IT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the selected MAC address.
|
||||
*/
|
||||
void EMAC_MAC_Addr_config(struct rt_synopsys_eth *ETHERNET_MAC, rt_uint32_t MacAddr, rt_uint8_t *Addr)
|
||||
{
|
||||
rt_uint32_t value;
|
||||
|
||||
/* Calculate the selectecd MAC address high register */
|
||||
value = ((rt_uint32_t)Addr[5] << 8) | (rt_uint32_t)Addr[4];
|
||||
/* Load the selectecd MAC address high register */
|
||||
//(*(volatile rt_uint32_t *) (EMAC_MAC_ADDR_HBASE + MacAddr)) = value;
|
||||
ETHERNET_MAC->MARs[MacAddr].MARH = value;
|
||||
/* Calculate the selectecd MAC address low register */
|
||||
value = ((rt_uint32_t)Addr[3] << 24) | ((rt_uint32_t)Addr[2] << 16) | ((rt_uint32_t)Addr[1] << 8) | Addr[0];
|
||||
|
||||
/* Load the selectecd MAC address low register */
|
||||
//(*(volatile rt_uint32_t *) (EMAC_MAC_ADDR_LBASE + MacAddr)) = value;
|
||||
ETHERNET_MAC->MARs[MacAddr].MARL = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the MAC transmission.
|
||||
*/
|
||||
void EMAC_MACTransmissionCmd(struct rt_synopsys_eth *ETHERNET_MAC, rt_bool_t NewState)
|
||||
{
|
||||
if (NewState)
|
||||
{
|
||||
/* Enable the MAC transmission */
|
||||
ETHERNET_MAC->MCR |= EMAC_MACCR_TE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Disable the MAC transmission */
|
||||
ETHERNET_MAC->MCR &= ~EMAC_MACCR_TE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the ETHERNET transmit FIFO.
|
||||
*/
|
||||
void EMAC_FlushTransmitFIFO(struct rt_synopsys_eth *ETHERNET_MAC)
|
||||
{
|
||||
/* Set the Flush Transmit FIFO bit */
|
||||
ETHERNET_MAC->OMR |= EMAC_DMAOMR_FTF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the MAC reception.
|
||||
*/
|
||||
void EMAC_MACReceptionCmd(struct rt_synopsys_eth *ETHERNET_MAC, rt_bool_t NewState)
|
||||
{
|
||||
if (NewState)
|
||||
{
|
||||
/* Enable the MAC reception */
|
||||
ETHERNET_MAC->MCR |= EMAC_MACCR_RE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Disable the MAC reception */
|
||||
ETHERNET_MAC->MCR &= ~EMAC_MACCR_RE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the DMA transmission.
|
||||
*/
|
||||
void EMAC_DMATransmissionCmd(struct rt_synopsys_eth *ETHERNET_MAC, rt_bool_t NewState)
|
||||
{
|
||||
if (NewState)
|
||||
{
|
||||
/* Enable the DMA transmission */
|
||||
ETHERNET_MAC->OMR |= EMAC_DMAOMR_ST;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Disable the DMA transmission */
|
||||
ETHERNET_MAC->OMR &= ~EMAC_DMAOMR_ST;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the DMA reception.
|
||||
*/
|
||||
void EMAC_DMAReceptionCmd(struct rt_synopsys_eth *ETHERNET_MAC, rt_bool_t NewState)
|
||||
{
|
||||
if (NewState)
|
||||
{
|
||||
/* Enable the DMA reception */
|
||||
ETHERNET_MAC->OMR |= EMAC_DMAOMR_SR;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Disable the DMA reception */
|
||||
ETHERNET_MAC->OMR &= ~EMAC_DMAOMR_SR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables ENET MAC and DMA reception/transmission
|
||||
*/
|
||||
void EMAC_start(struct rt_synopsys_eth *ETHERNET_MAC)
|
||||
{
|
||||
/* Enable transmit state machine of the MAC for transmission on the MII */
|
||||
EMAC_MACTransmissionCmd(ETHERNET_MAC, RT_TRUE);
|
||||
/* Flush Transmit FIFO */
|
||||
enet_txfifo_flush(ENET0);
|
||||
/* Enable receive state machine of the MAC for reception from the MII */
|
||||
EMAC_MACReceptionCmd(ETHERNET_MAC, RT_TRUE);
|
||||
|
||||
/* Start DMA transmission */
|
||||
EMAC_DMATransmissionCmd(ETHERNET_MAC, RT_TRUE);
|
||||
/* Start DMA reception */
|
||||
EMAC_DMAReceptionCmd(ETHERNET_MAC, RT_TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the ETHERNET's DMA interrupt pending bit.
|
||||
*/
|
||||
void EMAC_clear_pending(struct rt_synopsys_eth *ETHERNET_MAC, rt_uint32_t pending)
|
||||
{
|
||||
/* Clear the selected ETHERNET DMA IT */
|
||||
ETHERNET_MAC->SR = (rt_uint32_t)pending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the DMA Transmission by writing to the DmaRxPollDemand register
|
||||
* (the data written could be anything). This forces the DMA to resume reception.
|
||||
*/
|
||||
void EMAC_resume_reception(struct rt_synopsys_eth *ETHERNET_MAC)
|
||||
{
|
||||
ETHERNET_MAC->RPDR = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the DMA Transmission by writing to the DmaTxPollDemand register
|
||||
* (the data written could be anything). This forces the DMA to resume transmission.
|
||||
*/
|
||||
void EMAC_resume_transmission(struct rt_synopsys_eth *ETHERNET_MAC)
|
||||
{
|
||||
ETHERNET_MAC->TPDR = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a PHY register
|
||||
*/
|
||||
rt_uint16_t EMAC_PHY_read(struct rt_synopsys_eth *ETHERNET_MAC, rt_uint16_t PHYAddress, rt_uint16_t PHYReg)
|
||||
{
|
||||
rt_uint32_t value = 0;
|
||||
volatile rt_uint32_t timeout = 0;
|
||||
|
||||
/* Get the ETHERNET MACMIIAR value */
|
||||
value = ETHERNET_MAC->GAR;
|
||||
/* Keep only the CSR Clock Range CR[2:0] bits value */
|
||||
value &= ~MACMIIAR_CR_MASK;
|
||||
/* Prepare the MII address register value */
|
||||
value |= (((rt_uint32_t)PHYAddress << 11) & EMAC_MACMIIAR_PA); /* Set the PHY device address */
|
||||
value |= (((rt_uint32_t)PHYReg << 6) & EMAC_MACMIIAR_MR); /* Set the PHY register address */
|
||||
value &= ~EMAC_MACMIIAR_MW; /* Set the read mode */
|
||||
value |= EMAC_MACMIIAR_MB; /* Set the MII Busy bit */
|
||||
/* Write the result value into the MII Address register */
|
||||
ETHERNET_MAC->GAR = value;
|
||||
/* Check for the Busy flag */
|
||||
do
|
||||
{
|
||||
timeout++;
|
||||
value = ETHERNET_MAC->GAR;
|
||||
} while ((value & EMAC_MACMIIAR_MB) && (timeout < (rt_uint32_t)PHY_READ_TO));
|
||||
/* Return ERROR in case of timeout */
|
||||
if (timeout == PHY_READ_TO)
|
||||
{
|
||||
return (rt_uint16_t)EMAC_ERROR;
|
||||
}
|
||||
|
||||
/* Return data register value */
|
||||
return (rt_uint16_t)(ETHERNET_MAC->GDR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to a PHY register
|
||||
*/
|
||||
rt_uint32_t EMAC_PHY_write(struct rt_synopsys_eth *ETHERNET_MAC, rt_uint16_t PHYAddress, rt_uint16_t PHYReg, rt_uint16_t PHYValue)
|
||||
{
|
||||
rt_uint32_t value = 0;
|
||||
volatile rt_uint32_t timeout = 0;
|
||||
|
||||
/* Get the ETHERNET MACMIIAR value */
|
||||
value = ETHERNET_MAC->GAR;
|
||||
/* Keep only the CSR Clock Range CR[2:0] bits value */
|
||||
value &= ~MACMIIAR_CR_MASK;
|
||||
/* Prepare the MII register address value */
|
||||
value |= (((rt_uint32_t)PHYAddress << 11) & EMAC_MACMIIAR_PA); /* Set the PHY device address */
|
||||
value |= (((rt_uint32_t)PHYReg << 6) & EMAC_MACMIIAR_MR); /* Set the PHY register address */
|
||||
value |= EMAC_MACMIIAR_MW; /* Set the write mode */
|
||||
value |= EMAC_MACMIIAR_MB; /* Set the MII Busy bit */
|
||||
/* Give the value to the MII data register */
|
||||
ETHERNET_MAC->GDR = PHYValue;
|
||||
/* Write the result value into the MII Address register */
|
||||
ETHERNET_MAC->GAR = value;
|
||||
/* Check for the Busy flag */
|
||||
do
|
||||
{
|
||||
timeout++;
|
||||
value = ETHERNET_MAC->GAR;
|
||||
} while ((value & EMAC_MACMIIAR_MB) && (timeout < (rt_uint32_t)PHY_WRITE_TO));
|
||||
/* Return ERROR in case of timeout */
|
||||
if (timeout == PHY_WRITE_TO)
|
||||
{
|
||||
return EMAC_ERROR;
|
||||
}
|
||||
|
||||
/* Return SUCCESS */
|
||||
return EMAC_SUCCESS;
|
||||
}
|
||||
#endif /* RT_USING_SAL && RT_USING_NETDEV && RT_USING_LWIP */
|
||||
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#include "drv_otghs_dev.h"
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "board.h"
|
||||
#include "drv_usb_hw.h"
|
||||
|
||||
#if defined(BSP_USING_USB) && defined(RT_USING_USB_DEVICE)
|
||||
|
||||
usb_core_driver gd_usb_core;
|
||||
|
||||
static struct udcd _gd_udc;
|
||||
|
||||
#ifdef USE_USB_FS
|
||||
static struct ep_id _ep_pool[] = {
|
||||
{ 0x0, USB_EP_ATTR_CONTROL, USB_DIR_INOUT, 64, ID_ASSIGNED },
|
||||
{ 0x1, USB_EP_ATTR_BULK, USB_DIR_IN, 64, ID_UNASSIGNED },
|
||||
{ 0x1, USB_EP_ATTR_BULK, USB_DIR_OUT, 64, ID_UNASSIGNED },
|
||||
{ 0x2, USB_EP_ATTR_INT, USB_DIR_IN, 64, ID_UNASSIGNED },
|
||||
{ 0x2, USB_EP_ATTR_INT, USB_DIR_OUT, 64, ID_UNASSIGNED },
|
||||
{ 0x3, USB_EP_ATTR_BULK, USB_DIR_IN, 64, ID_UNASSIGNED },
|
||||
{ 0x3, USB_EP_ATTR_BULK, USB_DIR_OUT, 64, ID_UNASSIGNED },
|
||||
{ 0xFF, USB_EP_ATTR_TYPE_MASK, USB_DIR_MASK, 0, ID_ASSIGNED },
|
||||
};
|
||||
#elif defined USE_USB_HS
|
||||
static struct ep_id _ep_pool[] = {
|
||||
{ 0x0, USB_EP_ATTR_CONTROL, USB_DIR_INOUT, 64, ID_ASSIGNED },
|
||||
{ 0x1, USB_EP_ATTR_BULK, USB_DIR_IN, 64, ID_UNASSIGNED },
|
||||
{ 0x1, USB_EP_ATTR_BULK, USB_DIR_OUT, 512, ID_UNASSIGNED },
|
||||
{ 0x2, USB_EP_ATTR_INT, USB_DIR_IN, 512, ID_UNASSIGNED },
|
||||
{ 0x2, USB_EP_ATTR_INT, USB_DIR_OUT, 512, ID_UNASSIGNED },
|
||||
{ 0x3, USB_EP_ATTR_BULK, USB_DIR_IN, 512, ID_UNASSIGNED },
|
||||
{ 0x3, USB_EP_ATTR_BULK, USB_DIR_OUT, 512, ID_UNASSIGNED },
|
||||
{ 0xFF, USB_EP_ATTR_TYPE_MASK, USB_DIR_MASK, 0, ID_ASSIGNED },
|
||||
};
|
||||
#endif
|
||||
|
||||
void usbd_reset_callback(void)
|
||||
{
|
||||
rt_usbd_reset_handler(&_gd_udc);
|
||||
}
|
||||
|
||||
void usbd_setup_stage_callback(struct urequest *setup_packet)
|
||||
{
|
||||
rt_usbd_ep0_setup_handler(&_gd_udc, setup_packet);
|
||||
}
|
||||
|
||||
void usbd_data_in_stage_callback(uint8_t epnum, uint16_t data_count)
|
||||
{
|
||||
if (epnum == 0)
|
||||
{
|
||||
rt_usbd_ep0_in_handler(&_gd_udc);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_usbd_ep_in_handler(&_gd_udc, 0x80 | epnum, data_count);
|
||||
}
|
||||
}
|
||||
|
||||
void usbd_connect_callback(void)
|
||||
{
|
||||
rt_usbd_connect_handler(&_gd_udc);
|
||||
}
|
||||
|
||||
void usbd_sof_callback(void)
|
||||
{
|
||||
rt_usbd_sof_handler(&_gd_udc);
|
||||
}
|
||||
|
||||
void usbd_disconnect_callback(void)
|
||||
{
|
||||
rt_usbd_disconnect_handler(&_gd_udc);
|
||||
}
|
||||
|
||||
void usbd_data_out_stage_callback(uint8_t epnum, uint16_t data_count)
|
||||
{
|
||||
if (epnum == 0)
|
||||
{
|
||||
rt_usbd_ep0_out_handler(&_gd_udc, data_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_usbd_ep_out_handler(&_gd_udc, epnum, data_count);
|
||||
}
|
||||
}
|
||||
|
||||
void usbd_set_connection_state(uint8_t state)
|
||||
{
|
||||
if (state == 1)
|
||||
{
|
||||
usb_dev_connect(&gd_usb_core);
|
||||
|
||||
usb_mdelay(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_dev_disconnect(&gd_usb_core);
|
||||
|
||||
usb_mdelay(3);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t _ep_set_stall(rt_uint8_t address)
|
||||
{
|
||||
usb_ep_stall(&gd_usb_core, address);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t _ep_clear_stall(rt_uint8_t address)
|
||||
{
|
||||
usb_ep_clrstall(&gd_usb_core, address);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t _set_address(rt_uint8_t address)
|
||||
{
|
||||
usb_devaddr_set(&gd_usb_core, address);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t _set_config(rt_uint8_t address)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t _ep_enable(uep_t ep)
|
||||
{
|
||||
RT_ASSERT(ep != RT_NULL);
|
||||
RT_ASSERT(ep->ep_desc != RT_NULL);
|
||||
|
||||
usb_ep_active(&gd_usb_core,
|
||||
ep->ep_desc->bEndpointAddress,
|
||||
ep->ep_desc->wMaxPacketSize,
|
||||
ep->ep_desc->bmAttributes);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t _ep_disable(uep_t ep)
|
||||
{
|
||||
RT_ASSERT(ep != RT_NULL);
|
||||
RT_ASSERT(ep->ep_desc != RT_NULL);
|
||||
|
||||
usb_ep_deactivate(&gd_usb_core, ep->ep_desc->bEndpointAddress);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_ssize_t _ep_read(rt_uint8_t address, void *buffer)
|
||||
{
|
||||
rt_size_t size = 0;
|
||||
RT_ASSERT(buffer != RT_NULL);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static rt_ssize_t _ep_read_prepare(rt_uint8_t address, void *buffer, rt_size_t size)
|
||||
{
|
||||
usb_ep_outxfer(&gd_usb_core, address, buffer, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static rt_ssize_t _ep_write(rt_uint8_t address, void *buffer, rt_size_t size)
|
||||
{
|
||||
usb_ep_inxfer(&gd_usb_core, address, buffer, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static rt_err_t _ep0_send_status(void)
|
||||
{
|
||||
usb_ep_inxfer(&gd_usb_core, 0, NULL, 0);
|
||||
|
||||
usb_ctlep_startout(&gd_usb_core);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t _suspend(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t _wakeup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t _init(rt_device_t device)
|
||||
{
|
||||
usb_rcu_config();
|
||||
|
||||
usb_timer_init();
|
||||
|
||||
#ifdef USE_USBHS0
|
||||
|
||||
#ifdef USE_USB_FS
|
||||
usb_para_init(&gd_usb_core, USBHS0, USB_SPEED_FULL);
|
||||
#endif
|
||||
|
||||
#ifdef USE_USB_HS
|
||||
usb_para_init(&gd_usb_core, USBHS0, USB_SPEED_HIGH);
|
||||
#endif
|
||||
|
||||
#endif /* USE_USBHS0 */
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
|
||||
#ifdef USE_USB_FS
|
||||
usb_para_init(&gd_usb_core, USBHS1, USB_SPEED_FULL);
|
||||
#endif
|
||||
|
||||
#ifdef USE_USB_HS
|
||||
usb_para_init(&gd_usb_core, USBHS1, USB_SPEED_HIGH);
|
||||
#endif
|
||||
|
||||
#endif /* USE_USBHS1 */
|
||||
|
||||
/* configure USB capabilites */
|
||||
usb_basic_init(&gd_usb_core.bp, &gd_usb_core.regs);
|
||||
|
||||
usb_globalint_disable(&gd_usb_core.regs);
|
||||
|
||||
/* initailizes the USB core*/
|
||||
usb_core_init(gd_usb_core.bp, &gd_usb_core.regs);
|
||||
|
||||
/* set device disconnect */
|
||||
usbd_set_connection_state(0);
|
||||
|
||||
usb_curmode_set(&gd_usb_core.regs, DEVICE_MODE);
|
||||
|
||||
/* initailizes device mode */
|
||||
usb_devcore_init(&gd_usb_core);
|
||||
|
||||
usb_globalint_enable(&gd_usb_core.regs);
|
||||
|
||||
/* set device connect */
|
||||
usbd_set_connection_state(1);
|
||||
|
||||
#ifdef USE_USB_HS
|
||||
#ifdef USE_USBHS0
|
||||
pllusb_rcu_config(USBHS0);
|
||||
#endif
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
pllusb_rcu_config(USBHS1);
|
||||
#endif
|
||||
#endif /* USE_USB_HS */
|
||||
|
||||
usb_intr_config();
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
const static struct udcd_ops _udc_ops = {
|
||||
_set_address,
|
||||
_set_config,
|
||||
_ep_set_stall,
|
||||
_ep_clear_stall,
|
||||
_ep_enable,
|
||||
_ep_disable,
|
||||
_ep_read_prepare,
|
||||
_ep_read,
|
||||
_ep_write,
|
||||
_ep0_send_status,
|
||||
_suspend,
|
||||
_wakeup,
|
||||
};
|
||||
|
||||
int gd_usbd_register(void)
|
||||
{
|
||||
rt_memset((void *)&_gd_udc, 0, sizeof(struct udcd));
|
||||
_gd_udc.parent.type = RT_Device_Class_USBDevice;
|
||||
_gd_udc.parent.init = _init;
|
||||
_gd_udc.parent.user_data = NULL;
|
||||
_gd_udc.ops = &_udc_ops;
|
||||
/* Register endpoint infomation */
|
||||
_gd_udc.ep_pool = _ep_pool;
|
||||
_gd_udc.ep0.id = &_ep_pool[0];
|
||||
|
||||
rt_device_register((rt_device_t)&_gd_udc, "usbd", 0);
|
||||
rt_usb_device_init();
|
||||
return RT_EOK;
|
||||
}
|
||||
INIT_DEVICE_EXPORT(gd_usbd_register);
|
||||
|
||||
#ifdef RT_USB_DEVICE_HID
|
||||
|
||||
void usbd_hid_send(uint8_t *buffer, uint16_t size)
|
||||
{
|
||||
struct hid_s
|
||||
{
|
||||
struct rt_device parent;
|
||||
struct ufunction *func;
|
||||
uep_t ep_in;
|
||||
uep_t ep_out;
|
||||
int status;
|
||||
rt_uint16_t protocol;
|
||||
rt_uint8_t report_buf[64];
|
||||
struct rt_messagequeue hid_mq;
|
||||
};
|
||||
|
||||
udevice_t device = RT_NULL;
|
||||
uintf_t intf;
|
||||
ufunction_t func;
|
||||
|
||||
struct hid_s *hiddev;
|
||||
|
||||
device = rt_usbd_find_device(&_gd_udc);
|
||||
|
||||
intf = rt_usbd_find_interface(device, 0, &func);
|
||||
|
||||
if (RT_NULL != intf)
|
||||
{
|
||||
hiddev = (struct hid_s *)func->user_data;
|
||||
|
||||
hiddev->parent.write(&hiddev->parent, 0, buffer, size);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* BSP_USING_USB && RT_USING_USB_DEVICE */
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#include "drv_otghs_host.h"
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "board.h"
|
||||
|
||||
#include "drv_usb_hw.h"
|
||||
|
||||
#if defined(BSP_USING_USB) && defined(RT_USING_USB_HOST)
|
||||
|
||||
#define OTG_FS_PORT 1
|
||||
|
||||
usb_core_driver gd_usb_core;
|
||||
|
||||
static struct rt_completion urb_completion;
|
||||
static volatile rt_bool_t connect_status = RT_FALSE;
|
||||
|
||||
void usbh_connect_callback(usb_core_driver *hhcd)
|
||||
{
|
||||
uhcd_t hcd = (uhcd_t)hhcd->host.data;
|
||||
if (!connect_status)
|
||||
{
|
||||
connect_status = RT_TRUE;
|
||||
rt_usbh_root_hub_connect_handler(hcd, OTG_FS_PORT, RT_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void usbh_disconnect_callback(usb_core_driver *hhcd)
|
||||
{
|
||||
uhcd_t hcd = (uhcd_t)hhcd->host.data;
|
||||
if (connect_status)
|
||||
{
|
||||
connect_status = RT_FALSE;
|
||||
rt_usbh_root_hub_disconnect_handler(hcd, OTG_FS_PORT);
|
||||
}
|
||||
}
|
||||
|
||||
void usbh_hc_notifyurbchange_callback(usb_core_driver *hhcd, uint8_t chnum, usb_urb_state urb_state)
|
||||
{
|
||||
rt_completion_done(&urb_completion);
|
||||
}
|
||||
|
||||
static rt_err_t drv_reset_port(rt_uint8_t port)
|
||||
{
|
||||
usb_port_reset(&gd_usb_core);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int drv_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeout)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
uint8_t dir = (pipe->ep.bEndpointAddress & 0x80) >> 7;
|
||||
|
||||
if (!connect_status)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
rt_completion_init(&urb_completion);
|
||||
|
||||
if (dir == 0)
|
||||
{
|
||||
if (token == 0)
|
||||
{
|
||||
usbh_ctlsetup_send(&gd_usb_core, buffer, pipe->pipe_index);
|
||||
}
|
||||
else
|
||||
{
|
||||
usbh_data_send(&gd_usb_core, buffer, pipe->pipe_index, nbytes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
usbh_data_recev(&gd_usb_core, buffer, pipe->pipe_index, nbytes);
|
||||
}
|
||||
|
||||
|
||||
rt_completion_wait(&urb_completion, timeout);
|
||||
|
||||
rt_thread_mdelay(1);
|
||||
|
||||
if (usbh_urbstate_get(&gd_usb_core, pipe->pipe_index) == URB_NOTREADY)
|
||||
{
|
||||
if (pipe->ep.bmAttributes == USB_EP_ATTR_INT)
|
||||
{
|
||||
rt_thread_delay((pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) > 0 ? (pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) : 1);
|
||||
}
|
||||
|
||||
usb_pipe_halt(&gd_usb_core, pipe->pipe_index);
|
||||
|
||||
usbh_pipe_create(&gd_usb_core,
|
||||
pipe->inst->address,
|
||||
(uint8_t)PORT_SPEED_FULL,
|
||||
pipe->pipe_index,
|
||||
pipe->ep.bEndpointAddress,
|
||||
pipe->ep.bmAttributes,
|
||||
pipe->ep.wMaxPacketSize);
|
||||
continue;
|
||||
}
|
||||
else if (usbh_urbstate_get(&gd_usb_core, pipe->pipe_index) == URB_STALL)
|
||||
{
|
||||
pipe->status = UPIPE_STATUS_STALL;
|
||||
if (pipe->callback != RT_NULL)
|
||||
{
|
||||
pipe->callback(pipe);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
else if (usbh_urbstate_get(&gd_usb_core, pipe->pipe_index) == URB_ERROR)
|
||||
{
|
||||
pipe->status = UPIPE_STATUS_ERROR;
|
||||
if (pipe->callback != RT_NULL)
|
||||
{
|
||||
pipe->callback(pipe);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
else if (usbh_urbstate_get(&gd_usb_core, pipe->pipe_index) == URB_DONE)
|
||||
{
|
||||
pipe->status = UPIPE_STATUS_OK;
|
||||
if (pipe->callback != RT_NULL)
|
||||
{
|
||||
pipe->callback(pipe);
|
||||
}
|
||||
if (pipe->ep.bEndpointAddress & 0x80)
|
||||
{
|
||||
return usbh_xfercount_get(&gd_usb_core, pipe->pipe_index);
|
||||
}
|
||||
return nbytes;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static rt_uint16_t pipe_index = 0;
|
||||
static rt_uint8_t drv_get_free_pipe_index()
|
||||
{
|
||||
rt_uint8_t idx;
|
||||
for (idx = 1; idx < 16; idx++)
|
||||
{
|
||||
if (!(pipe_index & (0x01 << idx)))
|
||||
{
|
||||
pipe_index |= (0x01 << idx);
|
||||
return (idx - 1);
|
||||
}
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static void drv_free_pipe_index(rt_uint8_t index)
|
||||
{
|
||||
pipe_index &= ~(0x01 << index);
|
||||
}
|
||||
|
||||
static rt_err_t drv_open_pipe(upipe_t pipe)
|
||||
{
|
||||
pipe->pipe_index = drv_get_free_pipe_index();
|
||||
|
||||
usbh_pipe_create(&gd_usb_core,
|
||||
pipe->inst->address,
|
||||
(uint8_t)PORT_SPEED_FULL,
|
||||
pipe->pipe_index,
|
||||
pipe->ep.bEndpointAddress,
|
||||
pipe->ep.bmAttributes,
|
||||
pipe->ep.wMaxPacketSize);
|
||||
|
||||
/* Set DATA0 PID token*/
|
||||
if (gd_usb_core.host.pipe[pipe->pipe_index].ep.dir)
|
||||
{
|
||||
gd_usb_core.host.pipe[pipe->pipe_index].data_toggle_in = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
gd_usb_core.host.pipe[pipe->pipe_index].data_toggle_out = 0;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t drv_close_pipe(upipe_t pipe)
|
||||
{
|
||||
usb_pipe_halt(&gd_usb_core, pipe->pipe_index);
|
||||
|
||||
drv_free_pipe_index(pipe->pipe_index);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
struct uhcd_ops _uhcd_ops = {
|
||||
drv_reset_port,
|
||||
drv_pipe_xfer,
|
||||
drv_open_pipe,
|
||||
drv_close_pipe,
|
||||
};
|
||||
|
||||
static rt_err_t gd32_hcd_init(rt_device_t device)
|
||||
{
|
||||
usb_rcu_config();
|
||||
|
||||
usb_timer_init();
|
||||
|
||||
/* configure GPIO pin used for switching VBUS power and charge pump I/O */
|
||||
usb_vbus_config();
|
||||
|
||||
uint8_t i = 0U;
|
||||
|
||||
#ifdef USE_USBHS0
|
||||
|
||||
#ifdef USE_USB_FS
|
||||
usb_para_init(&gd_usb_core, USBHS0, USB_SPEED_FULL);
|
||||
#endif
|
||||
|
||||
#ifdef USE_USB_HS
|
||||
usb_para_init(&gd_usb_core, USBHS0, USB_SPEED_HIGH);
|
||||
#endif
|
||||
|
||||
#endif /* USE_USBHS0 */
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
|
||||
#ifdef USE_USB_FS
|
||||
usb_para_init(&gd_usb_core, USBHS1, USB_SPEED_FULL);
|
||||
#endif
|
||||
|
||||
#ifdef USE_USB_HS
|
||||
usb_para_init(&gd_usb_core, USBHS1, USB_SPEED_HIGH);
|
||||
#endif
|
||||
|
||||
#endif /* USE_USBHS1 */
|
||||
|
||||
gd_usb_core.host.connect_status = 0U;
|
||||
|
||||
for (i = 0U; i < USBHS_MAX_TX_FIFOS; i++)
|
||||
{
|
||||
gd_usb_core.host.pipe[i].err_count = 0U;
|
||||
gd_usb_core.host.pipe[i].pp_status = PIPE_IDLE;
|
||||
gd_usb_core.host.backup_xfercount[i] = 0U;
|
||||
}
|
||||
|
||||
gd_usb_core.host.pipe[0].ep.mps = 8U;
|
||||
|
||||
usb_basic_init(&gd_usb_core.bp, &gd_usb_core.regs);
|
||||
|
||||
usb_globalint_disable(&gd_usb_core.regs);
|
||||
|
||||
usb_core_init(gd_usb_core.bp, &gd_usb_core.regs);
|
||||
|
||||
#ifndef USE_OTG_MODE
|
||||
usb_curmode_set(&gd_usb_core.regs, HOST_MODE);
|
||||
#endif /* USE_OTG_MODE */
|
||||
|
||||
usb_host_init(&gd_usb_core);
|
||||
|
||||
usb_globalint_enable(&gd_usb_core.regs);
|
||||
|
||||
#ifdef USE_USB_HS
|
||||
#ifdef USE_USBHS0
|
||||
pllusb_rcu_config(USBHS0);
|
||||
#elif defined USE_USBHS1
|
||||
pllusb_rcu_config(USBHS1);
|
||||
#else
|
||||
#endif
|
||||
#endif /* USE_USB_HS */
|
||||
|
||||
/* enable interrupts */
|
||||
usb_intr_config();
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int gd_usbh_register(void)
|
||||
{
|
||||
rt_err_t res = -RT_ERROR;
|
||||
|
||||
uhcd_t uhcd = (uhcd_t)rt_malloc(sizeof(struct uhcd));
|
||||
if (uhcd == RT_NULL)
|
||||
{
|
||||
rt_kprintf("uhcd malloc failed\r\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_memset((void *)uhcd, 0, sizeof(struct uhcd));
|
||||
uhcd->parent.type = RT_Device_Class_USBHost;
|
||||
uhcd->parent.init = gd32_hcd_init;
|
||||
uhcd->parent.user_data = &gd_usb_core;
|
||||
|
||||
uhcd->ops = &_uhcd_ops;
|
||||
uhcd->num_ports = OTG_FS_PORT;
|
||||
gd_usb_core.host.data = uhcd;
|
||||
|
||||
res = rt_device_register(&uhcd->parent, "usbh", RT_DEVICE_FLAG_DEACTIVATE);
|
||||
if (res != RT_EOK)
|
||||
{
|
||||
rt_kprintf("register usb host failed res = %d\r\n", res);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_usb_host_init("usbh");
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
INIT_DEVICE_EXPORT(gd_usbh_register);
|
||||
|
||||
#endif /* BSP_USING_USB && RT_USING_USB_HOST */
|
||||
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#include "drv_usb_hw.h"
|
||||
#include "drv_usb_core.h"
|
||||
|
||||
#if defined(BSP_USING_USB)
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static void usb_core_reset(usb_core_regs *usb_regs);
|
||||
|
||||
/*!
|
||||
\brief configures USB parameters
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] usb_periph: USBHSx(x=0,1)
|
||||
\param[in] usb_speed: USB speed type (full-speed or high-speed)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_para_init(usb_core_driver *udev, uint32_t usb_periph, uint32_t usb_speed)
|
||||
{
|
||||
usb_core_basic *usb_basic = &udev->bp;
|
||||
|
||||
/* configure USB default transfer mode as FIFO mode */
|
||||
usb_basic->transfer_mode = (uint8_t)USB_USE_FIFO;
|
||||
|
||||
/* USB default speed is full-speed */
|
||||
usb_basic->core_speed = (uint8_t)USB_SPEED_FULL;
|
||||
|
||||
/* USB basic register address setting */
|
||||
switch (usb_periph)
|
||||
{
|
||||
case USBHS0:
|
||||
usb_basic->base_reg = (uint32_t)USBHS0_REG_BASE;
|
||||
break;
|
||||
case USBHS1:
|
||||
usb_basic->base_reg = (uint32_t)USBHS1_REG_BASE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* set the host channel numbers */
|
||||
usb_basic->num_pipe = USBHS_MAX_CHANNEL_COUNT;
|
||||
|
||||
/* set the device endpoint numbers */
|
||||
usb_basic->num_ep = USBHS_MAX_EP_COUNT;
|
||||
|
||||
if (USB_SPEED_HIGH == usb_speed)
|
||||
{
|
||||
#ifdef USB_EXTERNAL_ULPI_PHY_ENABLED
|
||||
usb_basic->phy_itf = USB_ULPI_PHY_EXTERNAL;
|
||||
#endif /* USB_EXTERNAL_ULPI_PHY_ENABLED */
|
||||
|
||||
#ifdef USB_EMBEDDED_HS_PHY_ENABLED
|
||||
usb_basic->phy_itf = USB_EMBEDDED_PHY_HS;
|
||||
#endif /* USB_EMBEDDED_HS_PHY_ENABLED */
|
||||
}
|
||||
else if (USB_SPEED_FULL == usb_speed)
|
||||
{
|
||||
#ifdef USB_EMBEDDED_FS_PHY_ENABLED
|
||||
usb_basic->phy_itf = USB_EMBEDDED_PHY_FS;
|
||||
#endif /* USB_EMBEDDED_FS_PHY_ENABLED */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
#ifdef USB_INTERNAL_DMA_ENABLED
|
||||
usb_basic->transfer_mode = USB_USE_DMA;
|
||||
#endif /* USB_INTERNAL_DMA_ENABLED */
|
||||
|
||||
usb_basic->sof_enable = (uint8_t)USB_SOF_OUTPUT;
|
||||
usb_basic->low_power = (uint8_t)USB_LOW_POWER;
|
||||
|
||||
#if (1U == LPM_ENABLED)
|
||||
usb_basic->lpm_enable = 1U;
|
||||
#endif /* LPM_ENABLED */
|
||||
}
|
||||
/*!
|
||||
\brief configure USB core basic
|
||||
\param[in] usb_basic: pointer to USB capabilities
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_basic_init(usb_core_basic *usb_basic, usb_core_regs *usb_regs)
|
||||
{
|
||||
/* assign main registers address */
|
||||
*usb_regs = (usb_core_regs){
|
||||
.gr = (usb_gr *)(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_CORE),
|
||||
.hr = (usb_hr *)(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_HOST),
|
||||
.dr = (usb_dr *)(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_DEV),
|
||||
|
||||
.HPCS = (uint32_t *)(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_PORT),
|
||||
.PWRCLKCTL = (uint32_t *)(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_PWRCLKCTL)
|
||||
};
|
||||
|
||||
/* assign device endpoint registers address */
|
||||
for (uint8_t i = 0U; i < usb_basic->num_ep; i++)
|
||||
{
|
||||
usb_regs->er_in[i] = (usb_erin *)(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_EP_IN + (i * (uint32_t)USB_REG_OFFSET_EP));
|
||||
|
||||
usb_regs->er_out[i] = (usb_erout *)(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_EP_OUT + (i * (uint32_t)USB_REG_OFFSET_EP));
|
||||
}
|
||||
|
||||
/* assign host pipe registers address */
|
||||
for (uint8_t i = 0U; i < usb_basic->num_pipe; i++)
|
||||
{
|
||||
usb_regs->pr[i] = (usb_pr *)(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_CH_INOUT + (i * (uint32_t)USB_REG_OFFSET_CH));
|
||||
|
||||
usb_regs->DFIFO[i] = (uint32_t *)(usb_basic->base_reg + (uint32_t)USB_DATA_FIFO_OFFSET + (i * (uint32_t)USB_DATA_FIFO_SIZE));
|
||||
}
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initializes the USB controller registers and
|
||||
prepares the core device mode or host mode operation
|
||||
\param[in] usb_basic: pointer to USB capabilities
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_core_init(usb_core_basic usb_basic, usb_core_regs *usb_regs)
|
||||
{
|
||||
if (USB_ULPI_PHY_EXTERNAL == usb_basic.phy_itf)
|
||||
{
|
||||
usb_regs->gr->GCCFG &= ~GCCFG_PWRON;
|
||||
|
||||
usb_regs->gr->GUSBCS &= ~(GUSBCS_EMBPHY_HS | GUSBCS_EMBPHY_FS);
|
||||
|
||||
if (usb_basic.sof_enable)
|
||||
{
|
||||
usb_regs->gr->GCCFG |= GCCFG_SOFOEN;
|
||||
}
|
||||
|
||||
/* initialize the ULPI interface */
|
||||
usb_regs->gr->GUSBCS &= ~GUSBCS_ULPIEOI;
|
||||
|
||||
#ifdef USBHS_EXTERNAL_VBUS_ENABLED
|
||||
/* use external VBUS driver */
|
||||
usb_regs->gr->GUSBCS |= GUSBCS_ULPIEVD;
|
||||
#else
|
||||
/* use internal VBUS driver */
|
||||
usb_regs->gr->GUSBCS &= ~GUSBCS_ULPIEVD;
|
||||
#endif /* USBHS_EXTERNAL_VBUS_ENABLED */
|
||||
|
||||
/* soft reset the core */
|
||||
usb_core_reset(usb_regs);
|
||||
}
|
||||
else if (USB_EMBEDDED_PHY_HS == usb_basic.phy_itf)
|
||||
{
|
||||
usb_regs->gr->GUSBCS |= GUSBCS_EMBPHY_HS;
|
||||
|
||||
/* soft reset the core */
|
||||
usb_core_reset(usb_regs);
|
||||
|
||||
usb_regs->gr->GCCFG = 0U;
|
||||
|
||||
#ifdef VBUS_SENSING_ENABLED
|
||||
/* active the transceiver and enable VBUS sensing */
|
||||
usb_regs->gr->GCCFG |= GCCFG_VDEN | GCCFG_PWRON;
|
||||
#else
|
||||
#ifdef USE_HOST_MODE
|
||||
usb_regs->gr->GOTGCS |= GOTGCS_AVOV | GOTGCS_AVOE;
|
||||
#endif /* USE_HOST_MODE */
|
||||
|
||||
#ifdef USE_DEVICE_MODE
|
||||
usb_regs->gr->GOTGCS |= GOTGCS_BVOV | GOTGCS_BVOE;
|
||||
#endif /* USE_DEVICE_MODE */
|
||||
|
||||
/* active the transceiver */
|
||||
usb_regs->gr->GCCFG |= GCCFG_PWRON;
|
||||
#endif /* VBUS_SENSING_ENABLED */
|
||||
|
||||
if (usb_basic.sof_enable)
|
||||
{
|
||||
usb_regs->gr->GCCFG |= GCCFG_SOFOEN;
|
||||
}
|
||||
|
||||
usb_mdelay(20U);
|
||||
}
|
||||
else if (USB_EMBEDDED_PHY_FS == usb_basic.phy_itf)
|
||||
{
|
||||
usb_regs->gr->GUSBCS |= GUSBCS_EMBPHY_FS;
|
||||
|
||||
/* soft reset the core */
|
||||
usb_core_reset(usb_regs);
|
||||
|
||||
#ifdef VBUS_SENSING_ENABLED
|
||||
/* active the transceiver and enable VBUS sensing */
|
||||
usb_regs->gr->GCCFG |= GCCFG_VDEN | GCCFG_PWRON;
|
||||
#else
|
||||
#ifdef USE_HOST_MODE
|
||||
usb_regs->gr->GOTGCS |= GOTGCS_AVOV | GOTGCS_AVOE;
|
||||
#endif /* USE_HOST_MODE */
|
||||
|
||||
#ifdef USE_DEVICE_MODE
|
||||
usb_regs->gr->GOTGCS |= GOTGCS_BVOV | GOTGCS_BVOE;
|
||||
#endif /* USE_DEVICE_MODE */
|
||||
|
||||
/* active the transceiver */
|
||||
usb_regs->gr->GCCFG |= GCCFG_PWRON;
|
||||
#endif /* VBUS_SENSING_ENABLED */
|
||||
|
||||
/* enable SOF output */
|
||||
if (usb_basic.sof_enable)
|
||||
{
|
||||
usb_regs->gr->GCCFG |= GCCFG_SOFOEN;
|
||||
}
|
||||
|
||||
usb_mdelay(20U);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
if ((uint8_t)USB_USE_DMA == usb_basic.transfer_mode)
|
||||
{
|
||||
usb_regs->gr->GAHBCS &= ~GAHBCS_BURST;
|
||||
usb_regs->gr->GAHBCS |= DMA_INCR8 | GAHBCS_DMAEN;
|
||||
}
|
||||
|
||||
#ifdef USE_OTG_MODE
|
||||
|
||||
/* enable USB OTG features */
|
||||
usb_regs->gr->GUSBCS |= GUSBCS_HNPCEN | GUSBCS_SRPCEN;
|
||||
|
||||
/* enable the USB wakeup and suspend interrupts */
|
||||
usb_regs->gr->GINTF = 0xBFFFFFFFU;
|
||||
|
||||
usb_regs->gr->GINTEN = GINTEN_WKUPIE | GINTEN_SPIE |
|
||||
GINTEN_OTGIE | GINTEN_SESIE | GINTEN_IDPSCIE;
|
||||
|
||||
#endif /* USE_OTG_MODE */
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief write a packet into the TX FIFO associated with the endpoint
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[in] src_buf: pointer to source buffer
|
||||
\param[in] fifo_num: FIFO number which is in (0..5)
|
||||
\param[in] byte_count: packet byte count
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_txfifo_write(usb_core_regs *usb_regs,
|
||||
uint8_t *src_buf,
|
||||
uint8_t fifo_num,
|
||||
uint16_t byte_count)
|
||||
{
|
||||
uint32_t word_count = (byte_count + 3U) / 4U;
|
||||
|
||||
__IO uint32_t *fifo = usb_regs->DFIFO[fifo_num];
|
||||
|
||||
while (word_count-- > 0U)
|
||||
{
|
||||
*fifo = *((__IO uint32_t *)src_buf);
|
||||
|
||||
src_buf += 4U;
|
||||
}
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read a packet from the Rx FIFO associated with the endpoint
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[in] dest_buf: pointer to destination buffer
|
||||
\param[in] byte_count: packet byte count
|
||||
\param[out] none
|
||||
\retval void type pointer
|
||||
*/
|
||||
void *usb_rxfifo_read(usb_core_regs *usb_regs, uint8_t *dest_buf, uint16_t byte_count)
|
||||
{
|
||||
__IO uint32_t word_count = (byte_count + 3U) / 4U;
|
||||
__IO uint32_t *fifo = usb_regs->DFIFO[0];
|
||||
|
||||
while (word_count-- > 0U)
|
||||
{
|
||||
*(__IO uint32_t *)dest_buf = *fifo;
|
||||
|
||||
dest_buf += 4U;
|
||||
}
|
||||
|
||||
return ((void *)dest_buf);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief flush a TX FIFO or all TX FIFOs
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[in] fifo_num: FIFO number which is in (0..5)
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_txfifo_flush(usb_core_regs *usb_regs, uint8_t fifo_num)
|
||||
{
|
||||
usb_regs->gr->GRSTCTL = ((uint32_t)fifo_num << 6) | GRSTCTL_TXFF;
|
||||
|
||||
/* wait for TX FIFO flush bit is set */
|
||||
while (usb_regs->gr->GRSTCTL & GRSTCTL_TXFF)
|
||||
{
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
/* wait for 3 PHY clocks*/
|
||||
usb_udelay(3U);
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief flush the entire RX FIFO
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_rxfifo_flush(usb_core_regs *usb_regs)
|
||||
{
|
||||
usb_regs->gr->GRSTCTL = GRSTCTL_RXFF;
|
||||
|
||||
/* wait for RX FIFO flush bit is set */
|
||||
while (usb_regs->gr->GRSTCTL & GRSTCTL_RXFF)
|
||||
{
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
/* wait for 3 PHY clocks */
|
||||
usb_udelay(3U);
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set endpoint or channel TX FIFO size
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[in] fifo: TX FIFO number
|
||||
\param[in] size: assigned TX FIFO size
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_set_txfifo(usb_core_regs *usb_regs, uint8_t fifo, uint16_t size)
|
||||
{
|
||||
uint32_t tx_offset = usb_regs->gr->GRFLEN;
|
||||
|
||||
if (0U == fifo)
|
||||
{
|
||||
usb_regs->gr->DIEP0TFLEN_HNPTFLEN = ((uint32_t)size << 16) | tx_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
tx_offset += (usb_regs->gr->DIEP0TFLEN_HNPTFLEN) >> 16;
|
||||
|
||||
for (uint8_t i = 0U; i < (fifo - 1U); i++)
|
||||
{
|
||||
tx_offset += (usb_regs->gr->DIEPTFLEN[i] >> 16);
|
||||
}
|
||||
|
||||
usb_regs->gr->DIEPTFLEN[fifo - 1U] = ((uint32_t)size << 16) | tx_offset;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set USB current mode
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[in] mode: USB current mode
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_curmode_set(usb_core_regs *usb_regs, uint8_t mode)
|
||||
{
|
||||
usb_regs->gr->GUSBCS &= ~(GUSBCS_FDM | GUSBCS_FHM);
|
||||
|
||||
if (DEVICE_MODE == mode)
|
||||
{
|
||||
usb_regs->gr->GUSBCS |= GUSBCS_FDM;
|
||||
}
|
||||
else if (HOST_MODE == mode)
|
||||
{
|
||||
usb_regs->gr->GUSBCS |= GUSBCS_FHM;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* OTG mode and other mode can not be here! */
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure USB core to soft reset
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usb_core_reset(usb_core_regs *usb_regs)
|
||||
{
|
||||
/* enable core soft reset */
|
||||
usb_regs->gr->GRSTCTL |= GRSTCTL_CSRST;
|
||||
|
||||
/* wait for the core to be soft reset */
|
||||
while (usb_regs->gr->GRSTCTL & GRSTCTL_CSRST)
|
||||
{
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
/* wait for additional 3 PHY clocks */
|
||||
usb_udelay(3U);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief active USB core clock
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_clock_active(usb_core_driver *udev)
|
||||
{
|
||||
if (udev->bp.low_power)
|
||||
{
|
||||
if (udev->regs.dr->DSTAT & DSTAT_SPST)
|
||||
{
|
||||
/* un-gate USB Core clock */
|
||||
*udev->regs.PWRCLKCTL &= ~(PWRCLKCTL_SHCLK | PWRCLKCTL_SUCLK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* BSP_USING_USB */
|
||||
@@ -0,0 +1,755 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#include "drv_usb_hw.h"
|
||||
#include "drv_usb_dev.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(BSP_USING_USB) && defined(RT_USING_USB_DEVICE)
|
||||
|
||||
/* endpoint 0 max packet length */
|
||||
static const uint8_t EP0_MAXLEN[4] = {
|
||||
[DSTAT_EM_HS_PHY_30MHZ_60MHZ] = EP0MPL_64,
|
||||
[DSTAT_EM_FS_PHY_30MHZ_60MHZ] = EP0MPL_64,
|
||||
[DSTAT_EM_FS_PHY_48MHZ] = EP0MPL_64,
|
||||
[DSTAT_EM_LS_PHY_6MHZ] = EP0MPL_8
|
||||
};
|
||||
|
||||
/* USB endpoint TX FIFO size */
|
||||
static uint16_t USBHS_TX_FIFO_SIZE[USBHS_MAX_EP_COUNT] = {
|
||||
(uint16_t)TX0_FIFO_SIZE,
|
||||
(uint16_t)TX1_FIFO_SIZE,
|
||||
(uint16_t)TX2_FIFO_SIZE,
|
||||
(uint16_t)TX3_FIFO_SIZE,
|
||||
(uint16_t)TX4_FIFO_SIZE,
|
||||
(uint16_t)TX5_FIFO_SIZE,
|
||||
(uint16_t)TX6_FIFO_SIZE,
|
||||
(uint16_t)TX7_FIFO_SIZE,
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief initialize USB core registers for device mode
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_devcore_init(usb_core_driver *udev)
|
||||
{
|
||||
uint8_t i = 0U;
|
||||
|
||||
/* restart the PHY clock (maybe don't need to...) */
|
||||
*udev->regs.PWRCLKCTL = 0U;
|
||||
|
||||
/* configure periodic frame interval to default value */
|
||||
udev->regs.dr->DCFG &= ~DCFG_EOPFT;
|
||||
udev->regs.dr->DCFG |= FRAME_INTERVAL_80;
|
||||
|
||||
udev->regs.dr->DCFG &= ~DCFG_DS;
|
||||
|
||||
if (USB_EMBEDDED_PHY_HS == udev->bp.phy_itf)
|
||||
{
|
||||
udev->regs.dr->DCFG |= USB_SPEED_INP_HIGH;
|
||||
}
|
||||
else if (USB_EMBEDDED_PHY_FS == udev->bp.phy_itf)
|
||||
{
|
||||
udev->regs.dr->DCFG |= USB_SPEED_INP_FULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
/* set RX FIFO size */
|
||||
usb_set_rxfifo(&udev->regs, (uint16_t)RX_FIFO_SIZE);
|
||||
|
||||
/* set endpoint 0 to 3's TX FIFO length and RAM address */
|
||||
for (i = 0U; i < USBHS_MAX_EP_COUNT; i++)
|
||||
{
|
||||
usb_set_txfifo(&udev->regs, i, USBHS_TX_FIFO_SIZE[i]);
|
||||
}
|
||||
|
||||
/* make sure all FIFOs are flushed */
|
||||
|
||||
/* flush all TX FIFOs */
|
||||
(void)usb_txfifo_flush(&udev->regs, 0x10U);
|
||||
|
||||
/* flush entire RX FIFO */
|
||||
(void)usb_rxfifo_flush(&udev->regs);
|
||||
|
||||
/* clear all pending device interrupts */
|
||||
udev->regs.dr->DIEPINTEN = 0U;
|
||||
udev->regs.dr->DOEPINTEN = 0U;
|
||||
udev->regs.dr->DAEPINT = 0xFFFFFFFFU;
|
||||
udev->regs.dr->DAEPINTEN = 0U;
|
||||
|
||||
/* configure all IN/OUT endpoints */
|
||||
for (i = 0U; i < udev->bp.num_ep; i++)
|
||||
{
|
||||
if (udev->regs.er_in[i]->DIEPCTL & DEPCTL_EPEN)
|
||||
{
|
||||
udev->regs.er_in[i]->DIEPCTL |= DEPCTL_EPD | DEPCTL_SNAK;
|
||||
}
|
||||
else
|
||||
{
|
||||
udev->regs.er_in[i]->DIEPCTL = 0U;
|
||||
}
|
||||
|
||||
/* set IN endpoint transfer length to 0 */
|
||||
udev->regs.er_in[i]->DIEPLEN = 0U;
|
||||
|
||||
/* clear all pending IN endpoint interrupts */
|
||||
udev->regs.er_in[i]->DIEPINTF = 0xFFU;
|
||||
|
||||
if (udev->regs.er_out[i]->DOEPCTL & DEPCTL_EPEN)
|
||||
{
|
||||
udev->regs.er_out[i]->DOEPCTL |= DEPCTL_EPD | DEPCTL_SNAK;
|
||||
}
|
||||
else
|
||||
{
|
||||
udev->regs.er_out[i]->DOEPCTL = 0U;
|
||||
}
|
||||
|
||||
/* set OUT endpoint transfer length to 0 */
|
||||
udev->regs.er_out[i]->DOEPLEN = 0U;
|
||||
|
||||
/* clear all pending OUT endpoint interrupts */
|
||||
udev->regs.er_out[i]->DOEPINTF = 0xFFU;
|
||||
}
|
||||
|
||||
udev->regs.dr->DIEPINTEN |= DIEPINTEN_EPTXFUDEN;
|
||||
|
||||
(void)usb_devint_enable(udev);
|
||||
|
||||
/* configure LPM function */
|
||||
if (1U == udev->bp.lpm_enable)
|
||||
{
|
||||
udev->dev.pm.lpm_state = LPM_L0;
|
||||
udev->regs.gr->GLPMCFG = GLPMCFG_LPMEN | GLPMCFG_ACKLPM | GLPMCFG_BESLEN;
|
||||
}
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable the USB device mode interrupts
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_devint_enable(usb_core_driver *udev)
|
||||
{
|
||||
/* clear any pending USB OTG interrupts */
|
||||
udev->regs.gr->GOTGINTF = 0xFFFFFFFFU;
|
||||
|
||||
/* clear any pending interrupts */
|
||||
udev->regs.gr->GINTF = 0xBFFFFFFFU;
|
||||
|
||||
/* enable the USB wakeup and suspend interrupts */
|
||||
udev->regs.gr->GINTEN = GINTEN_WKUPIE | GINTEN_SPIE;
|
||||
|
||||
/* enable device_mode-related interrupts */
|
||||
if ((uint8_t)USB_USE_FIFO == udev->bp.transfer_mode)
|
||||
{
|
||||
udev->regs.gr->GINTEN |= GINTEN_RXFNEIE;
|
||||
}
|
||||
|
||||
udev->regs.gr->GINTEN |= GINTEN_RSTIE | GINTEN_ENUMFIE | GINTEN_IEPIE |
|
||||
GINTEN_OEPIE | GINTEN_SOFIE | GINTEN_ISOONCIE | GINTEN_ISOINCIE;
|
||||
|
||||
#ifdef VBUS_SENSING_ENABLED
|
||||
udev->regs.gr->GINTEN |= GINTEN_SESIE | GINTEN_OTGIE;
|
||||
#endif /* VBUS_SENSING_ENABLED */
|
||||
|
||||
if (1U == udev->bp.lpm_enable)
|
||||
{
|
||||
udev->regs.gr->GINTEN |= GINTEN_LPMIE;
|
||||
}
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief active the USB endpoint0 transaction
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] transc: the USB endpoint0 transaction
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_transc0_active(usb_core_driver *udev, usb_transc *transc)
|
||||
{
|
||||
__IO uint32_t *reg_addr = NULL;
|
||||
|
||||
uint32_t enum_speed = udev->regs.dr->DSTAT & DSTAT_ES;
|
||||
|
||||
/* get the endpoint number */
|
||||
uint8_t ep_num = transc->ep_addr.num;
|
||||
|
||||
if (ep_num)
|
||||
{
|
||||
/* not endpoint 0 */
|
||||
return USB_FAIL;
|
||||
}
|
||||
|
||||
if (transc->ep_addr.dir)
|
||||
{
|
||||
reg_addr = &udev->regs.er_in[0]->DIEPCTL;
|
||||
}
|
||||
else
|
||||
{
|
||||
reg_addr = &udev->regs.er_out[0]->DOEPCTL;
|
||||
}
|
||||
|
||||
/* endpoint 0 is activated after USB clock is enabled */
|
||||
*reg_addr &= ~(DEPCTL_MPL | DEPCTL_EPTYPE | DIEPCTL_TXFNUM);
|
||||
|
||||
/* set endpoint 0 maximum packet length */
|
||||
*reg_addr |= EP0_MAXLEN[enum_speed];
|
||||
|
||||
/* activate endpoint */
|
||||
*reg_addr |= ((uint32_t)transc->ep_type << 18) | ((uint32_t)ep_num << 22) | DEPCTL_SD0PID | DEPCTL_EPACT;
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief active the USB transaction
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] transc: the USB transaction
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
usb_status usb_ep_active(usb_core_driver *udev, uint8_t ep_addr, uint8_t ep_mps, uint8_t ep_attr)
|
||||
{
|
||||
__IO uint32_t *reg_addr = NULL;
|
||||
uint32_t epinten = 0U;
|
||||
uint32_t enum_speed = udev->regs.dr->DSTAT & DSTAT_ES;
|
||||
|
||||
usb_transc *transc = NULL;
|
||||
|
||||
/* get the endpoint number */
|
||||
uint8_t ep_num = EP_ID(ep_addr);
|
||||
|
||||
/* enable endpoint interrupt number */
|
||||
if (EP_DIR(ep_addr))
|
||||
{
|
||||
reg_addr = &udev->regs.er_in[ep_num]->DIEPCTL;
|
||||
epinten = 1U << ep_num;
|
||||
transc = &udev->dev.transc_in[ep_num];
|
||||
}
|
||||
else
|
||||
{
|
||||
reg_addr = &udev->regs.er_out[ep_num]->DOEPCTL;
|
||||
epinten = 1U << (16U + ep_num);
|
||||
transc = &udev->dev.transc_out[ep_num];
|
||||
}
|
||||
|
||||
*transc = (usb_transc){ 0 };
|
||||
|
||||
transc->max_len = ep_mps;
|
||||
transc->ep_type = ep_attr & USB_EPTYPE_MASK;
|
||||
|
||||
/* if the endpoint is not active, need change the endpoint control register */
|
||||
if (!(*reg_addr & DEPCTL_EPACT))
|
||||
{
|
||||
*reg_addr &= ~(DEPCTL_MPL | DEPCTL_EPTYPE | DIEPCTL_TXFNUM);
|
||||
|
||||
/* set endpoint maximum packet length */
|
||||
if (0U == ep_num)
|
||||
{
|
||||
*reg_addr |= EP0_MAXLEN[enum_speed];
|
||||
}
|
||||
else
|
||||
{
|
||||
*reg_addr |= transc->max_len;
|
||||
}
|
||||
|
||||
/* activate endpoint */
|
||||
*reg_addr |= ((uint32_t)transc->ep_type << 18) | ((uint32_t)ep_num << 22) | DEPCTL_SD0PID | DEPCTL_EPACT;
|
||||
}
|
||||
|
||||
#ifdef USB_DEDICATED_EP1_ENABLED
|
||||
if (1U == ep_num)
|
||||
{
|
||||
udev->regs.dr->DEP1INTEN |= epinten;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* enable the interrupts for this endpoint */
|
||||
udev->regs.dr->DAEPINTEN |= epinten;
|
||||
}
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief deactivate the USB transaction
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] transc: the USB transaction
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
usb_status usb_ep_deactivate(usb_core_driver *udev, uint8_t ep_addr)
|
||||
{
|
||||
uint32_t epinten = 0U;
|
||||
|
||||
uint8_t ep_num = EP_ID(ep_addr);
|
||||
|
||||
/* disable endpoint interrupt number */
|
||||
if (EP_DIR(ep_addr))
|
||||
{
|
||||
epinten = 1U << ep_num;
|
||||
|
||||
udev->regs.er_in[ep_num]->DIEPCTL &= ~DEPCTL_EPACT;
|
||||
}
|
||||
else
|
||||
{
|
||||
epinten = 1U << (ep_num + 16U);
|
||||
|
||||
udev->regs.er_out[ep_num]->DOEPCTL &= ~DEPCTL_EPACT;
|
||||
}
|
||||
|
||||
#ifdef USB_DEDICATED_EP1_ENABLED
|
||||
if (1U == ep_num)
|
||||
{
|
||||
udev->regs.dr->DEP1INTEN &= ~epinten;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* disable the interrupts for this endpoint */
|
||||
udev->regs.dr->DAEPINTEN &= ~epinten;
|
||||
}
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure USB transaction to start IN transfer
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] transc: the USB IN transaction
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_ep_inxfer(usb_core_driver *udev, uint8_t ep_addr, uint8_t *buf, uint16_t count)
|
||||
{
|
||||
usb_status status = USB_OK;
|
||||
uint8_t ep_num = EP_ID(ep_addr);
|
||||
|
||||
__IO uint32_t epctl = udev->regs.er_in[ep_num]->DIEPCTL;
|
||||
__IO uint32_t eplen = udev->regs.er_in[ep_num]->DIEPLEN;
|
||||
|
||||
usb_transc *transc = &udev->dev.transc_in[ep_num];
|
||||
|
||||
eplen &= ~(DEPLEN_TLEN | DEPLEN_PCNT);
|
||||
|
||||
transc->xfer_len = count;
|
||||
transc->xfer_buf = buf;
|
||||
transc->xfer_count = 0U;
|
||||
|
||||
/* zero length packet or endpoint 0 */
|
||||
if (0U == count)
|
||||
{
|
||||
/* set transfer packet count to 1 */
|
||||
eplen |= 1U << 19;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set transfer packet count */
|
||||
if (0U == ep_num)
|
||||
{
|
||||
transc->xfer_len = USB_MIN(count, transc->max_len);
|
||||
|
||||
eplen |= 1U << 19;
|
||||
}
|
||||
else
|
||||
{
|
||||
eplen |= ((count - 1 + transc->max_len) / transc->max_len) << 19;
|
||||
}
|
||||
|
||||
/* set endpoint transfer length */
|
||||
eplen |= count;
|
||||
|
||||
if ((uint8_t)USB_EPTYPE_ISOC == transc->ep_type)
|
||||
{
|
||||
eplen |= DIEPLEN_MCNT & (1U << 29);
|
||||
}
|
||||
}
|
||||
|
||||
udev->regs.er_in[ep_num]->DIEPLEN = eplen;
|
||||
|
||||
if ((uint8_t)USB_EPTYPE_ISOC == transc->ep_type)
|
||||
{
|
||||
if (((udev->regs.dr->DSTAT & DSTAT_FNRSOF) >> 8) & 0x01U)
|
||||
{
|
||||
epctl |= DEPCTL_SEVNFRM;
|
||||
}
|
||||
else
|
||||
{
|
||||
epctl |= DEPCTL_SODDFRM;
|
||||
}
|
||||
}
|
||||
|
||||
if ((uint8_t)USB_USE_DMA == udev->bp.transfer_mode)
|
||||
{
|
||||
udev->regs.er_in[ep_num]->DIEPDMAADDR = transc->dma_addr;
|
||||
}
|
||||
|
||||
/* enable the endpoint and clear the NAK */
|
||||
epctl |= DEPCTL_CNAK | DEPCTL_EPEN;
|
||||
|
||||
udev->regs.er_in[ep_num]->DIEPCTL = epctl;
|
||||
|
||||
if ((uint8_t)USB_USE_FIFO == udev->bp.transfer_mode)
|
||||
{
|
||||
if ((uint8_t)USB_EPTYPE_ISOC != transc->ep_type)
|
||||
{
|
||||
/* enable the TX FIFO empty interrupt for this endpoint */
|
||||
if (count > 0U)
|
||||
{
|
||||
udev->regs.dr->DIEPFEINTEN |= 1U << ep_num;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)usb_txfifo_write(&udev->regs, transc->xfer_buf, ep_num, (uint16_t)transc->xfer_len);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure USB transaction to start OUT transfer
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] transc: the USB OUT transaction
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
usb_status usb_ep_outxfer(usb_core_driver *udev, uint8_t ep_addr, uint8_t *buf, uint16_t count)
|
||||
{
|
||||
usb_status status = USB_OK;
|
||||
|
||||
uint8_t ep_num = EP_ID(ep_addr);
|
||||
|
||||
uint32_t epctl = udev->regs.er_out[ep_num]->DOEPCTL;
|
||||
uint32_t eplen = udev->regs.er_out[ep_num]->DOEPLEN;
|
||||
|
||||
usb_transc *transc = &udev->dev.transc_out[ep_num];
|
||||
|
||||
transc->xfer_buf = buf;
|
||||
transc->xfer_len = count;
|
||||
|
||||
eplen &= ~(DEPLEN_TLEN | DEPLEN_PCNT);
|
||||
|
||||
/* zero length packet or endpoint 0 */
|
||||
if ((0U == count) || (0U == ep_num))
|
||||
{
|
||||
/* set the transfer length to max packet size */
|
||||
eplen |= transc->max_len;
|
||||
|
||||
/* set the transfer packet count to 1 */
|
||||
eplen |= 1U << 19;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure the transfer size and packet count as follows:
|
||||
* pktcnt = N
|
||||
* xfersize = N * maxpacket
|
||||
*/
|
||||
uint32_t packet_count = (count + transc->max_len - 1) / transc->max_len;
|
||||
|
||||
eplen |= packet_count << 19;
|
||||
eplen |= packet_count * transc->max_len;
|
||||
}
|
||||
|
||||
udev->regs.er_out[ep_num]->DOEPLEN = eplen;
|
||||
|
||||
if ((uint8_t)USB_USE_DMA == udev->bp.transfer_mode)
|
||||
{
|
||||
udev->regs.er_out[ep_num]->DOEPDMAADDR = transc->dma_addr;
|
||||
}
|
||||
|
||||
if ((uint8_t)USB_EPTYPE_ISOC == transc->ep_type)
|
||||
{
|
||||
if (transc->frame_num)
|
||||
{
|
||||
epctl |= DEPCTL_SD1PID;
|
||||
}
|
||||
else
|
||||
{
|
||||
epctl |= DEPCTL_SD0PID;
|
||||
}
|
||||
}
|
||||
|
||||
/* enable the endpoint and clear the NAK */
|
||||
epctl |= DEPCTL_EPEN | DEPCTL_CNAK;
|
||||
|
||||
udev->regs.er_out[ep_num]->DOEPCTL = epctl;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set the USB transaction STALL status
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] transc: the USB transaction
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
usb_status usb_ep_stall(usb_core_driver *udev, uint8_t ep_addr)
|
||||
{
|
||||
__IO uint32_t *reg_addr = NULL;
|
||||
|
||||
uint8_t ep_num = EP_ID(ep_addr);
|
||||
|
||||
if (EP_DIR(ep_addr))
|
||||
{
|
||||
reg_addr = &(udev->regs.er_in[ep_num]->DIEPCTL);
|
||||
|
||||
/* set the endpoint disable bit */
|
||||
if (*reg_addr & DEPCTL_EPEN)
|
||||
{
|
||||
*reg_addr |= DEPCTL_EPD;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set the endpoint STALL bit */
|
||||
reg_addr = &(udev->regs.er_out[ep_num]->DOEPCTL);
|
||||
}
|
||||
|
||||
/* set the endpoint STALL bit */
|
||||
*reg_addr |= DEPCTL_STALL;
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear the USB transaction STALL status
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] transc: the USB transaction
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_ep_clrstall(usb_core_driver *udev, uint8_t ep_addr)
|
||||
{
|
||||
__IO uint32_t *reg_addr = NULL;
|
||||
uint32_t ep_type = 0U;
|
||||
|
||||
uint8_t ep_num = EP_ID(ep_addr);
|
||||
|
||||
if (EP_DIR(ep_addr))
|
||||
{
|
||||
reg_addr = &(udev->regs.er_in[ep_num]->DIEPCTL);
|
||||
}
|
||||
else
|
||||
{
|
||||
reg_addr = &(udev->regs.er_out[ep_num]->DOEPCTL);
|
||||
}
|
||||
|
||||
/* clear the endpoint STALL bit */
|
||||
*reg_addr &= ~DEPCTL_STALL;
|
||||
|
||||
ep_type = (DEPCTL_EPTYPE & *reg_addr) >> 18;
|
||||
|
||||
/* reset data PID of the periodic endpoints */
|
||||
if (((uint8_t)USB_EPTYPE_INTR == ep_type) || ((uint8_t)USB_EPTYPE_BULK == ep_type))
|
||||
{
|
||||
*reg_addr |= DEPCTL_SD0PID;
|
||||
}
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read device IN endpoint interrupt flag register
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[out] none
|
||||
\retval interrupt value
|
||||
*/
|
||||
uint32_t usb_iepintr_read(usb_core_driver *udev, uint8_t ep_num)
|
||||
{
|
||||
__IO uint32_t value = 0U;
|
||||
uint32_t fifoemptymask, commonintmask;
|
||||
|
||||
commonintmask = udev->regs.dr->DIEPINTEN;
|
||||
fifoemptymask = udev->regs.dr->DIEPFEINTEN;
|
||||
|
||||
/* check FIFO empty interrupt enable bit */
|
||||
commonintmask |= ((fifoemptymask >> ep_num) & 0x1U) << 7;
|
||||
|
||||
value = udev->regs.er_in[ep_num]->DIEPINTF & commonintmask;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configures OUT endpoint 0 to receive SETUP packets
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_ctlep_startout(usb_core_driver *udev)
|
||||
{
|
||||
/* set OUT endpoint 0 receive length to 24 bytes, 1 packet and 3 SETUP packets */
|
||||
udev->regs.er_out[0]->DOEPLEN = DOEP0_TLEN(8U * 3U) | DOEP0_PCNT(1U) | DOEP0_STPCNT(3U);
|
||||
|
||||
if ((uint8_t)USB_USE_DMA == udev->bp.transfer_mode)
|
||||
{
|
||||
udev->regs.er_out[0]->DOEPDMAADDR = (uint32_t)&udev->dev.control.req;
|
||||
|
||||
/* endpoint enable */
|
||||
udev->regs.er_out[0]->DOEPCTL |= DEPCTL_EPACT | DEPCTL_EPEN;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief active remote wakeup signaling
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_rwkup_active(usb_core_driver *udev)
|
||||
{
|
||||
if (udev->dev.pm.dev_remote_wakeup)
|
||||
{
|
||||
if (udev->regs.dr->DSTAT & DSTAT_SPST)
|
||||
{
|
||||
if (udev->bp.low_power)
|
||||
{
|
||||
/* ungate USB core clock */
|
||||
*udev->regs.PWRCLKCTL &= ~(PWRCLKCTL_SHCLK | PWRCLKCTL_SUCLK);
|
||||
}
|
||||
|
||||
/* active remote wakeup signaling */
|
||||
udev->regs.dr->DCTL |= DCTL_RWKUP;
|
||||
|
||||
usb_mdelay(5U);
|
||||
|
||||
udev->regs.dr->DCTL &= ~DCTL_RWKUP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief USB device suspend
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_dev_suspend(usb_core_driver *udev)
|
||||
{
|
||||
__IO uint32_t devstat = udev->regs.dr->DSTAT;
|
||||
|
||||
if ((devstat & DSTAT_SPST) && (udev->bp.low_power))
|
||||
{
|
||||
/* switch-off the USB clocks */
|
||||
*udev->regs.PWRCLKCTL |= PWRCLKCTL_SHCLK;
|
||||
|
||||
/* enter DEEP_SLEEP mode with LDO in low power mode */
|
||||
pmu_to_deepsleepmode(WFI_CMD);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief stop the device and clean up FIFOs
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_dev_stop(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
udev->dev.cur_status = 1U;
|
||||
|
||||
/* clear all interrupt flag and enable bits */
|
||||
for (i = 0U; i < udev->bp.num_ep; i++)
|
||||
{
|
||||
udev->regs.er_in[i]->DIEPINTF = 0xFFU;
|
||||
udev->regs.er_out[i]->DOEPINTF = 0xFFU;
|
||||
}
|
||||
|
||||
udev->regs.dr->DIEPINTEN = 0U;
|
||||
udev->regs.dr->DOEPINTEN = 0U;
|
||||
udev->regs.dr->DAEPINTEN = 0U;
|
||||
udev->regs.dr->DAEPINT = 0xFFFFFFFFU;
|
||||
|
||||
/* flush the FIFO */
|
||||
(void)usb_rxfifo_flush(&udev->regs);
|
||||
(void)usb_txfifo_flush(&udev->regs, 0x10U);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief usb battery charging detect operation
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval bcd type
|
||||
*/
|
||||
bcd_type usbd_bcd_detect(usb_core_driver *udev)
|
||||
{
|
||||
udev->regs.gr->GCCFG |= GCCFG_DCDEN;
|
||||
|
||||
usb_mdelay(1000U);
|
||||
|
||||
if (0U == (udev->regs.gr->GCCFG & GCCFG_DCDF))
|
||||
{
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_DCDEN;
|
||||
|
||||
return BCD_ERROR;
|
||||
}
|
||||
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_DCDEN;
|
||||
usb_mdelay(20U);
|
||||
udev->regs.gr->GCCFG |= GCCFG_PEMEN;
|
||||
usb_mdelay(50U);
|
||||
|
||||
if (udev->regs.gr->GCCFG & GCCFG_PDF)
|
||||
{
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_PEMEN;
|
||||
usb_mdelay(20U);
|
||||
udev->regs.gr->GCCFG |= GCCFG_SDMEN;
|
||||
usb_mdelay(50U);
|
||||
|
||||
if (udev->regs.gr->GCCFG & GCCFG_SDF)
|
||||
{
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_SDMEN;
|
||||
usb_mdelay(20U);
|
||||
|
||||
return BCD_DCP;
|
||||
}
|
||||
else
|
||||
{
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_SDMEN;
|
||||
usb_mdelay(20U);
|
||||
|
||||
return BCD_CDP;
|
||||
}
|
||||
}
|
||||
else if (udev->regs.gr->GCCFG & GCCFG_PS2F)
|
||||
{
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_PEMEN;
|
||||
usb_mdelay(20U);
|
||||
|
||||
return BCD_PS2;
|
||||
}
|
||||
else
|
||||
{
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_PEMEN;
|
||||
usb_mdelay(20U);
|
||||
|
||||
return BCD_SDP;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* BSP_USING_USB && RT_USING_USB_DEVICE */
|
||||
@@ -0,0 +1,448 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#include "drv_usb_hw.h"
|
||||
#include "drv_usb_host.h"
|
||||
|
||||
#if defined(BSP_USING_USB) && defined(RT_USING_USB_HOST)
|
||||
|
||||
const uint32_t PIPE_DPID[2] = {
|
||||
PIPE_DPID_DATA0,
|
||||
PIPE_DPID_DATA1
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief initializes USB core for host mode
|
||||
\param[in] udev: pointer to selected USB host
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_host_init(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t i = 0U, inten = 0U;
|
||||
|
||||
uint32_t nptxfifolen = 0U;
|
||||
uint32_t ptxfifolen = 0U;
|
||||
|
||||
/* restart the PHY Clock */
|
||||
*udev->regs.PWRCLKCTL = 0U;
|
||||
|
||||
/* support HS, FS and LS */
|
||||
udev->regs.hr->HCTL &= ~HCTL_SPDFSLS;
|
||||
|
||||
/* set RX FIFO size */
|
||||
udev->regs.gr->GRFLEN = USB_RX_FIFO_SIZE;
|
||||
|
||||
/* set non-periodic TX FIFO size and address */
|
||||
nptxfifolen |= USB_RX_FIFO_SIZE;
|
||||
nptxfifolen |= USB_HTX_NPFIFO_SIZE << 16;
|
||||
udev->regs.gr->DIEP0TFLEN_HNPTFLEN = nptxfifolen;
|
||||
|
||||
/* set periodic TX FIFO size and address */
|
||||
ptxfifolen |= USB_RX_FIFO_SIZE + USB_HTX_PFIFO_SIZE;
|
||||
ptxfifolen |= USB_HTX_PFIFO_SIZE << 16;
|
||||
udev->regs.gr->HPTFLEN = ptxfifolen;
|
||||
|
||||
#ifdef USE_OTG_MODE
|
||||
/* clear host set HNP enable in the usb_otg control register */
|
||||
udev->regs.gr->GOTGCS &= ~GOTGCS_HHNPEN;
|
||||
#endif /* USE_OTG_MODE */
|
||||
|
||||
/* make sure the FIFOs are flushed */
|
||||
|
||||
/* flush all TX FIFOs in device or host mode */
|
||||
usb_txfifo_flush(&udev->regs, 0x10U);
|
||||
|
||||
/* flush the entire RX FIFO */
|
||||
usb_rxfifo_flush(&udev->regs);
|
||||
|
||||
/* disable all interrupts */
|
||||
udev->regs.gr->GINTEN = 0U;
|
||||
|
||||
/* clear any pending USB OTG interrupts */
|
||||
udev->regs.gr->GOTGINTF = 0xFFFFFFFFU;
|
||||
|
||||
/* enable the USB wakeup and suspend interrupts */
|
||||
udev->regs.gr->GINTF = 0xBFFFFFFFU;
|
||||
|
||||
/* clear all pending host channel interrupts */
|
||||
for (i = 0U; i < udev->bp.num_pipe; i++)
|
||||
{
|
||||
udev->regs.pr[i]->HCHINTF = 0xFFFFFFFFU;
|
||||
udev->regs.pr[i]->HCHINTEN = 0U;
|
||||
}
|
||||
|
||||
#ifndef USE_OTG_MODE
|
||||
usb_portvbus_switch(udev, 1U);
|
||||
#endif /* USE_OTG_MODE */
|
||||
|
||||
udev->regs.gr->GINTEN = GINTEN_WKUPIE | GINTEN_SPIE;
|
||||
|
||||
/* enable host_mode-related interrupts */
|
||||
if (USB_USE_FIFO == udev->bp.transfer_mode)
|
||||
{
|
||||
inten = GINTEN_RXFNEIE;
|
||||
}
|
||||
|
||||
/* configure USBHS interrupts */
|
||||
inten |= GINTEN_HPIE | GINTEN_HCIE | GINTEN_ISOINCIE;
|
||||
udev->regs.gr->GINTEN |= inten;
|
||||
|
||||
inten = GINTEN_DISCIE | GINTEN_SOFIE;
|
||||
udev->regs.gr->GINTEN &= ~inten;
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief control the VBUS to power
|
||||
\param[in] udev: pointer to selected USB host
|
||||
\param[in] state: VBUS state
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_portvbus_switch(usb_core_driver *udev, uint8_t state)
|
||||
{
|
||||
uint32_t port = 0U;
|
||||
|
||||
/* enable or disable the external charge pump */
|
||||
usb_vbus_drive(state);
|
||||
|
||||
/* turn on the host port power. */
|
||||
port = usb_port_read(udev);
|
||||
|
||||
if ((!(port & HPCS_PP)) && (1U == state))
|
||||
{
|
||||
port |= HPCS_PP;
|
||||
}
|
||||
|
||||
if ((port & HPCS_PP) && (0U == state))
|
||||
{
|
||||
port &= ~HPCS_PP;
|
||||
}
|
||||
|
||||
*udev->regs.HPCS = port;
|
||||
|
||||
usb_mdelay(200U);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief reset host port
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
uint32_t usb_port_reset(usb_core_driver *udev)
|
||||
{
|
||||
__IO uint32_t port = usb_port_read(udev);
|
||||
|
||||
*udev->regs.HPCS = port | HPCS_PRST;
|
||||
|
||||
usb_mdelay(20U); /* see note */
|
||||
|
||||
*udev->regs.HPCS = port & ~HPCS_PRST;
|
||||
|
||||
usb_mdelay(20U);
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize host pipe
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] pipe_num: host pipe number which is in (0..7)
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_pipe_init(usb_core_driver *udev, uint8_t pipe_num)
|
||||
{
|
||||
usb_status status = USB_OK;
|
||||
|
||||
__IO uint32_t pp_ctl = 0U;
|
||||
__IO uint32_t pp_inten = HCHINTEN_TFIE;
|
||||
|
||||
usb_pipe *pp = &udev->host.pipe[pipe_num];
|
||||
|
||||
/* clear old interrupt conditions for this host channel */
|
||||
udev->regs.pr[pipe_num]->HCHINTF = 0xFFFFFFFFU;
|
||||
|
||||
if (USB_USE_DMA == udev->bp.transfer_mode)
|
||||
{
|
||||
pp_inten |= HCHINTEN_DMAERIE;
|
||||
}
|
||||
|
||||
if (pp->ep.dir)
|
||||
{
|
||||
pp_inten |= HCHINTEN_BBERIE;
|
||||
}
|
||||
|
||||
/* enable channel interrupts required for this transfer */
|
||||
switch (pp->ep.type)
|
||||
{
|
||||
case USB_EPTYPE_CTRL:
|
||||
case USB_EPTYPE_BULK:
|
||||
pp_inten |= HCHINTEN_STALLIE | HCHINTEN_USBERIE | HCHINTEN_DTERIE | HCHINTEN_NAKIE;
|
||||
|
||||
if (!pp->ep.dir)
|
||||
{
|
||||
if (PORT_SPEED_HIGH == pp->dev_speed)
|
||||
{
|
||||
pp_inten |= HCHINTEN_NYETIE;
|
||||
pp_inten |= HCHINTEN_ACKIE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_INTR:
|
||||
pp_inten |= HCHINTEN_STALLIE | HCHINTEN_USBERIE | HCHINTEN_DTERIE | HCHINTEN_NAKIE | HCHINTEN_REQOVRIE;
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_ISOC:
|
||||
pp_inten |= HCHINTEN_REQOVRIE | HCHINTEN_ACKIE;
|
||||
|
||||
if (pp->ep.dir)
|
||||
{
|
||||
pp_inten |= HCHINTEN_USBERIE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
udev->regs.pr[pipe_num]->HCHINTEN = pp_inten;
|
||||
|
||||
/* enable the top level host channel interrupt */
|
||||
udev->regs.hr->HACHINTEN |= 1U << pipe_num;
|
||||
|
||||
/* make sure host channel interrupts are enabled */
|
||||
udev->regs.gr->GINTEN |= GINTEN_HCIE;
|
||||
|
||||
/* program the host channel control register */
|
||||
pp_ctl |= PIPE_CTL_DAR(pp->dev_addr);
|
||||
pp_ctl |= PIPE_CTL_EPNUM(pp->ep.num);
|
||||
pp_ctl |= PIPE_CTL_EPDIR(pp->ep.dir);
|
||||
pp_ctl |= PIPE_CTL_EPTYPE(pp->ep.type);
|
||||
pp_ctl |= PIPE_CTL_LSD(PORT_SPEED_LOW == pp->dev_speed);
|
||||
|
||||
pp_ctl |= pp->ep.mps;
|
||||
pp_ctl |= ((uint32_t)(USB_EPTYPE_INTR == pp->ep.type) << 29) & HCHCTL_ODDFRM;
|
||||
|
||||
udev->regs.pr[pipe_num]->HCHCTL = pp_ctl;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief prepare host channel for transferring packets
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] pipe_num: host pipe number which is in (0..7)
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_pipe_xfer(usb_core_driver *udev, uint8_t pipe_num)
|
||||
{
|
||||
usb_status status = USB_OK;
|
||||
|
||||
uint16_t dword_len = 0U;
|
||||
uint16_t packet_count = 0U;
|
||||
|
||||
__IO uint32_t pp_ctl = 0U;
|
||||
|
||||
usb_pipe *pp = &udev->host.pipe[pipe_num];
|
||||
|
||||
uint16_t max_packet_len = pp->ep.mps;
|
||||
|
||||
/* compute the expected number of packets associated to the transfer */
|
||||
if (pp->xfer_len > 0U)
|
||||
{
|
||||
packet_count = (uint16_t)((pp->xfer_len + max_packet_len - 1U) / max_packet_len);
|
||||
|
||||
if (packet_count > HC_MAX_PACKET_COUNT)
|
||||
{
|
||||
packet_count = HC_MAX_PACKET_COUNT;
|
||||
pp->xfer_len = (uint16_t)(packet_count * max_packet_len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_count = 1U;
|
||||
}
|
||||
|
||||
if (pp->ep.dir)
|
||||
{
|
||||
pp->xfer_len = (uint16_t)(packet_count * max_packet_len);
|
||||
}
|
||||
|
||||
/* initialize the host channel transfer information */
|
||||
udev->regs.pr[pipe_num]->HCHLEN = pp->xfer_len | pp->DPID | PIPE_XFER_PCNT(packet_count);
|
||||
|
||||
if (USB_USE_DMA == udev->bp.transfer_mode)
|
||||
{
|
||||
udev->regs.pr[pipe_num]->HCHDMAADDR = (unsigned int)pp->xfer_buf;
|
||||
}
|
||||
|
||||
pp_ctl = udev->regs.pr[pipe_num]->HCHCTL;
|
||||
|
||||
if (usb_frame_even(udev))
|
||||
{
|
||||
pp_ctl |= HCHCTL_ODDFRM;
|
||||
}
|
||||
else
|
||||
{
|
||||
pp_ctl &= ~HCHCTL_ODDFRM;
|
||||
}
|
||||
|
||||
/* set host channel enabled */
|
||||
pp_ctl |= HCHCTL_CEN;
|
||||
pp_ctl &= ~HCHCTL_CDIS;
|
||||
|
||||
udev->regs.pr[pipe_num]->HCHCTL = pp_ctl;
|
||||
|
||||
if (USB_USE_FIFO == udev->bp.transfer_mode)
|
||||
{
|
||||
if ((0U == pp->ep.dir) && (pp->xfer_len > 0U))
|
||||
{
|
||||
switch (pp->ep.type)
|
||||
{
|
||||
/* non-periodic transfer */
|
||||
case USB_EPTYPE_CTRL:
|
||||
case USB_EPTYPE_BULK:
|
||||
dword_len = (uint16_t)((pp->xfer_len + 3U) / 4U);
|
||||
|
||||
/* check if there is enough space in FIFO space */
|
||||
if (dword_len > (udev->regs.gr->HNPTFQSTAT & HNPTFQSTAT_NPTXFS))
|
||||
{
|
||||
/* need to process data in nptxfempty interrupt */
|
||||
udev->regs.gr->GINTEN |= GINTEN_NPTXFEIE;
|
||||
}
|
||||
break;
|
||||
|
||||
/* periodic transfer */
|
||||
case USB_EPTYPE_INTR:
|
||||
case USB_EPTYPE_ISOC:
|
||||
dword_len = (uint16_t)((pp->xfer_len + 3U) / 4U);
|
||||
|
||||
/* check if there is enough space in FIFO space */
|
||||
if (dword_len > (udev->regs.hr->HPTFQSTAT & HPTFQSTAT_PTXFS))
|
||||
{
|
||||
/* need to process data in ptxfempty interrupt */
|
||||
udev->regs.gr->GINTEN |= GINTEN_PTXFEIE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* write packet into the TX FIFO */
|
||||
usb_txfifo_write(&udev->regs, pp->xfer_buf, pipe_num, (uint16_t)pp->xfer_len);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief halt pipe
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] pipe_num: host pipe number which is in (0..7)
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_pipe_halt(usb_core_driver *udev, uint8_t pipe_num)
|
||||
{
|
||||
__IO uint32_t pp_ctl = udev->regs.pr[pipe_num]->HCHCTL;
|
||||
|
||||
uint8_t ep_type = (uint8_t)((pp_ctl & HCHCTL_EPTYPE) >> 18U);
|
||||
|
||||
pp_ctl |= HCHCTL_CEN | HCHCTL_CDIS;
|
||||
|
||||
switch (ep_type)
|
||||
{
|
||||
case USB_EPTYPE_CTRL:
|
||||
case USB_EPTYPE_BULK:
|
||||
if (0U == (udev->regs.gr->HNPTFQSTAT & HNPTFQSTAT_NPTXFS))
|
||||
{
|
||||
pp_ctl &= ~HCHCTL_CEN;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_INTR:
|
||||
case USB_EPTYPE_ISOC:
|
||||
if (0U == (udev->regs.hr->HPTFQSTAT & HPTFQSTAT_PTXFS))
|
||||
{
|
||||
pp_ctl &= ~HCHCTL_CEN;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
udev->regs.pr[pipe_num]->HCHCTL = pp_ctl;
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure host pipe to do ping operation
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] pipe_num: host pipe number which is in (0..7)
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_pipe_ping(usb_core_driver *udev, uint8_t pipe_num)
|
||||
{
|
||||
uint32_t pp_ctl = 0U;
|
||||
|
||||
udev->regs.pr[pipe_num]->HCHLEN = HCHLEN_PING;
|
||||
|
||||
pp_ctl = udev->regs.pr[pipe_num]->HCHCTL;
|
||||
|
||||
pp_ctl |= HCHCTL_CEN;
|
||||
pp_ctl &= ~HCHCTL_CDIS;
|
||||
|
||||
udev->regs.pr[pipe_num]->HCHCTL = pp_ctl;
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief stop the USB host and clean up FIFO
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_host_stop(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t i;
|
||||
__IO uint32_t pp_ctl = 0U;
|
||||
|
||||
udev->regs.hr->HACHINTEN = 0x0U;
|
||||
udev->regs.hr->HACHINT = 0xFFFFFFFFU;
|
||||
|
||||
/* flush out any leftover queued requests. */
|
||||
for (i = 0U; i < udev->bp.num_pipe; i++)
|
||||
{
|
||||
pp_ctl = udev->regs.pr[i]->HCHCTL;
|
||||
|
||||
pp_ctl &= ~(HCHCTL_CEN | HCHCTL_EPDIR);
|
||||
pp_ctl |= HCHCTL_CDIS;
|
||||
|
||||
udev->regs.pr[i]->HCHCTL = pp_ctl;
|
||||
}
|
||||
|
||||
/* flush the FIFO */
|
||||
usb_rxfifo_flush(&udev->regs);
|
||||
usb_txfifo_flush(&udev->regs, 0x10U);
|
||||
}
|
||||
|
||||
#endif /* BSP_USING_USB && RT_USING_USB_HOST */
|
||||
@@ -0,0 +1,703 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#include "drv_usbd_int.h"
|
||||
#include "drv_otghs_dev.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(BSP_USING_USB) && defined(RT_USING_USB_DEVICE)
|
||||
|
||||
static const uint8_t USB_SPEED[4] = {
|
||||
[DSTAT_EM_HS_PHY_30MHZ_60MHZ] = (uint8_t)USB_SPEED_HIGH,
|
||||
[DSTAT_EM_FS_PHY_30MHZ_60MHZ] = (uint8_t)USB_SPEED_FULL,
|
||||
[DSTAT_EM_FS_PHY_48MHZ] = (uint8_t)USB_SPEED_FULL,
|
||||
[DSTAT_EM_LS_PHY_6MHZ] = (uint8_t)USB_SPEED_LOW
|
||||
};
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static uint32_t usbd_int_epout(usb_core_driver *udev);
|
||||
static uint32_t usbd_int_epin(usb_core_driver *udev);
|
||||
static uint32_t usbd_int_rxfifo(usb_core_driver *udev);
|
||||
static uint32_t usbd_int_reset(usb_core_driver *udev);
|
||||
static uint32_t usbd_int_enumfinish(usb_core_driver *udev);
|
||||
static uint32_t usbd_int_suspend(usb_core_driver *udev);
|
||||
static uint32_t usbd_int_wakeup(usb_core_driver *udev);
|
||||
|
||||
#if (1U == LPM_ENABLED)
|
||||
static uint32_t usbd_int_lpm(usb_core_driver *udev, usb_lpm_type active_type);
|
||||
#endif /* LPM_ENABLED */
|
||||
|
||||
static uint32_t usbd_emptytxfifo_write(usb_core_driver *udev, uint32_t ep_num);
|
||||
|
||||
/*!
|
||||
\brief USB device-mode interrupts global service routine handler
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usbd_isr(usb_core_driver *udev)
|
||||
{
|
||||
if (HOST_MODE != (udev->regs.gr->GINTF & GINTF_COPM))
|
||||
{
|
||||
uint32_t intr = udev->regs.gr->GINTF;
|
||||
intr &= udev->regs.gr->GINTEN;
|
||||
|
||||
/* there are no interrupts, avoid spurious interrupt */
|
||||
if (!intr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* OUT endpoints interrupts */
|
||||
if (intr & GINTF_OEPIF)
|
||||
{
|
||||
(void)usbd_int_epout(udev);
|
||||
}
|
||||
|
||||
/* IN endpoints interrupts */
|
||||
if (intr & GINTF_IEPIF)
|
||||
{
|
||||
(void)usbd_int_epin(udev);
|
||||
}
|
||||
|
||||
/* suspend interrupt */
|
||||
if (intr & GINTF_SP)
|
||||
{
|
||||
(void)usbd_int_suspend(udev);
|
||||
}
|
||||
|
||||
/* wakeup interrupt */
|
||||
if (intr & GINTF_WKUPIF)
|
||||
{
|
||||
(void)usbd_int_wakeup(udev);
|
||||
}
|
||||
|
||||
/* start of frame interrupt */
|
||||
if (intr & GINTF_SOF)
|
||||
{
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_SOF;
|
||||
}
|
||||
|
||||
/* receive FIFO not empty interrupt */
|
||||
if (intr & GINTF_RXFNEIF)
|
||||
{
|
||||
(void)usbd_int_rxfifo(udev);
|
||||
}
|
||||
|
||||
/* USB reset interrupt */
|
||||
if (intr & GINTF_RST)
|
||||
{
|
||||
(void)usbd_int_reset(udev);
|
||||
}
|
||||
|
||||
/* enumeration has been done interrupt */
|
||||
if (intr & GINTF_ENUMFIF)
|
||||
{
|
||||
(void)usbd_int_enumfinish(udev);
|
||||
}
|
||||
|
||||
/* incomplete synchronization IN transfer interrupt*/
|
||||
if (intr & GINTF_ISOINCIF)
|
||||
{
|
||||
if (NULL != udev->dev.class_core->incomplete_isoc_in)
|
||||
{
|
||||
(void)udev->dev.class_core->incomplete_isoc_in(udev);
|
||||
}
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_ISOINCIF;
|
||||
}
|
||||
|
||||
/* incomplete synchronization OUT transfer interrupt*/
|
||||
if (intr & GINTF_ISOONCIF)
|
||||
{
|
||||
if (NULL != udev->dev.class_core->incomplete_isoc_out)
|
||||
{
|
||||
(void)udev->dev.class_core->incomplete_isoc_out(udev);
|
||||
}
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_ISOONCIF;
|
||||
}
|
||||
|
||||
#if (1U == LPM_ENABLED)
|
||||
if (intr & GINTF_LPMIF)
|
||||
{
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_LPMIF;
|
||||
|
||||
udev->dev.pm.BESL = (udev->regs.gr->GLPMCFG & GLPMCFG_BESL) >> 2U;
|
||||
udev->dev.pm.dev_remote_wakeup = (udev->regs.gr->GLPMCFG & GLPMCFG_REW) >> 6U;
|
||||
|
||||
if (LPM_L0 == udev->dev.pm.lpm_state)
|
||||
{
|
||||
udev->dev.pm.lpm_state = LPM_L1;
|
||||
usbd_int_lpm(udev, LPM_L1_ACTIVE);
|
||||
}
|
||||
else
|
||||
{
|
||||
udev->dev.pm.lpm_state = LPM_L0;
|
||||
usbd_int_lpm(udev, LPM_L0_ACTIVE);
|
||||
}
|
||||
}
|
||||
#endif /* LPM_ENABLED */
|
||||
|
||||
#ifdef VBUS_SENSING_ENABLED
|
||||
|
||||
/* session request interrupt */
|
||||
if (intr & GINTF_SESIF)
|
||||
{
|
||||
udev->regs.gr->GINTF = GINTF_SESIF;
|
||||
}
|
||||
|
||||
/* OTG mode interrupt */
|
||||
if (intr & GINTF_OTGIF)
|
||||
{
|
||||
if (udev->regs.gr->GOTGINTF & GOTGINTF_SESEND)
|
||||
{
|
||||
}
|
||||
|
||||
/* clear OTG interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_OTGIF;
|
||||
}
|
||||
#endif /* VBUS_SENSING_ENABLED */
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief indicates that an OUT endpoint has a pending interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint32_t usbd_int_epout(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t epintnum = 0U;
|
||||
uint8_t ep_num = 0U;
|
||||
|
||||
for (epintnum = usb_oepintnum_read(udev); epintnum; epintnum >>= 1)
|
||||
{
|
||||
if (epintnum & 0x01U)
|
||||
{
|
||||
__IO uint32_t oepintr = usb_oepintr_read(udev, ep_num);
|
||||
|
||||
/* transfer complete interrupt */
|
||||
if (oepintr & DOEPINTF_TF)
|
||||
{
|
||||
/* clear the bit in DOEPINTF for this interrupt */
|
||||
udev->regs.er_out[ep_num]->DOEPINTF = DOEPINTF_TF;
|
||||
|
||||
if ((uint8_t)USB_USE_DMA == udev->bp.transfer_mode)
|
||||
{
|
||||
__IO uint32_t eplen = udev->regs.er_out[ep_num]->DOEPLEN;
|
||||
|
||||
udev->dev.transc_out[ep_num].xfer_count = udev->dev.transc_out[ep_num].max_len -
|
||||
(eplen & DEPLEN_TLEN);
|
||||
}
|
||||
|
||||
/* inform upper layer: data ready */
|
||||
usbd_data_out_stage_callback(ep_num, udev->dev.transc_out[ep_num].xfer_len);
|
||||
|
||||
if ((uint8_t)USB_USE_DMA == udev->bp.transfer_mode)
|
||||
{
|
||||
if ((0U == ep_num) && ((uint8_t)USB_CTL_STATUS_OUT == udev->dev.control.ctl_state))
|
||||
{
|
||||
usb_ctlep_startout(udev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* SETUP phase finished interrupt (control endpoints) */
|
||||
if (oepintr & DOEPINTF_STPF)
|
||||
{
|
||||
/* inform the upper layer that a SETUP packet is available */
|
||||
usbd_setup_stage_callback((struct urequest *)&udev->dev.control.req);
|
||||
|
||||
udev->regs.er_out[ep_num]->DOEPINTF = DOEPINTF_STPF;
|
||||
}
|
||||
}
|
||||
|
||||
ep_num++;
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief indicates that an IN endpoint has a pending interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint32_t usbd_int_epin(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t epintnum = 0U;
|
||||
uint8_t ep_num = 0U;
|
||||
|
||||
for (epintnum = usb_iepintnum_read(udev); epintnum; epintnum >>= 1)
|
||||
{
|
||||
if (epintnum & 0x1U)
|
||||
{
|
||||
__IO uint32_t iepintr = usb_iepintr_read(udev, ep_num);
|
||||
|
||||
if (iepintr & DIEPINTF_TF)
|
||||
{
|
||||
udev->regs.er_in[ep_num]->DIEPINTF = DIEPINTF_TF;
|
||||
|
||||
/* data transmission is completed */
|
||||
usbd_data_in_stage_callback(ep_num, udev->dev.transc_in[ep_num].xfer_len);
|
||||
|
||||
if ((uint8_t)USB_USE_DMA == udev->bp.transfer_mode)
|
||||
{
|
||||
if ((0U == ep_num) && ((uint8_t)USB_CTL_STATUS_IN == udev->dev.control.ctl_state))
|
||||
{
|
||||
usb_ctlep_startout(udev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (iepintr & DIEPINTF_TXFE)
|
||||
{
|
||||
usbd_emptytxfifo_write(udev, (uint32_t)ep_num);
|
||||
|
||||
udev->regs.er_in[ep_num]->DIEPINTF = DIEPINTF_TXFE;
|
||||
}
|
||||
}
|
||||
|
||||
ep_num++;
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the RX status queue level interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint32_t usbd_int_rxfifo(usb_core_driver *udev)
|
||||
{
|
||||
usb_transc *transc = NULL;
|
||||
|
||||
uint8_t data_PID = 0U;
|
||||
uint32_t bcount = 0U;
|
||||
|
||||
__IO uint32_t devrxstat = 0U;
|
||||
|
||||
/* disable the RX status queue non-empty interrupt */
|
||||
udev->regs.gr->GINTEN &= ~GINTEN_RXFNEIE;
|
||||
|
||||
/* get the status from the top of the FIFO */
|
||||
devrxstat = udev->regs.gr->GRSTATP;
|
||||
|
||||
uint8_t ep_num = (uint8_t)(devrxstat & GRSTATRP_EPNUM);
|
||||
|
||||
transc = &udev->dev.transc_out[ep_num];
|
||||
|
||||
bcount = (devrxstat & GRSTATRP_BCOUNT) >> 4;
|
||||
data_PID = (uint8_t)((devrxstat & GRSTATRP_DPID) >> 15);
|
||||
|
||||
switch ((devrxstat & GRSTATRP_RPCKST) >> 17)
|
||||
{
|
||||
case RSTAT_GOUT_NAK:
|
||||
break;
|
||||
|
||||
case RSTAT_DATA_UPDT:
|
||||
if (bcount > 0U)
|
||||
{
|
||||
(void)usb_rxfifo_read(&udev->regs, transc->xfer_buf, (uint16_t)bcount);
|
||||
|
||||
transc->xfer_buf += bcount;
|
||||
transc->xfer_count += bcount;
|
||||
}
|
||||
break;
|
||||
|
||||
case RSTAT_XFER_COMP:
|
||||
/* trigger the OUT endpoint interrupt */
|
||||
break;
|
||||
|
||||
case RSTAT_SETUP_COMP:
|
||||
/* trigger the OUT endpoint interrupt */
|
||||
break;
|
||||
|
||||
case RSTAT_SETUP_UPDT:
|
||||
if ((0U == transc->ep_addr.num) && (8U == bcount) && (DPID_DATA0 == data_PID))
|
||||
{
|
||||
/* copy the SETUP packet received in FIFO into the setup buffer in RAM */
|
||||
(void)usb_rxfifo_read(&udev->regs, (uint8_t *)&udev->dev.control.req, (uint16_t)bcount);
|
||||
|
||||
transc->xfer_count += bcount;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* enable the RX status queue level interrupt */
|
||||
udev->regs.gr->GINTEN |= GINTEN_RXFNEIE;
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB reset interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static uint32_t usbd_int_reset(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
/* clear the remote wakeup signaling */
|
||||
udev->regs.dr->DCTL &= ~DCTL_RWKUP;
|
||||
|
||||
/* flush the TX FIFO */
|
||||
(void)usb_txfifo_flush(&udev->regs, 0U);
|
||||
|
||||
for (i = 0U; i < udev->bp.num_ep; i++)
|
||||
{
|
||||
udev->regs.er_in[i]->DIEPINTF = 0xFFU;
|
||||
udev->regs.er_out[i]->DOEPINTF = 0xFFU;
|
||||
}
|
||||
|
||||
/* clear all pending device endpoint interrupts */
|
||||
udev->regs.dr->DAEPINT = 0xFFFFFFFFU;
|
||||
|
||||
/* enable endpoint 0 interrupts */
|
||||
udev->regs.dr->DAEPINTEN = 1U | (1U << 16U);
|
||||
|
||||
/* enable OUT endpoint interrupts */
|
||||
udev->regs.dr->DOEPINTEN = DOEPINTEN_STPFEN | DOEPINTEN_TFEN;
|
||||
|
||||
#ifdef USB_DEDICATED_EP1_ENABLED
|
||||
udev->regs.dr->DOEP1INTEN = DOEPINTEN_STPFEN | DOEPINTEN_TFEN;
|
||||
#endif
|
||||
|
||||
/* enable IN endpoint interrupts */
|
||||
udev->regs.dr->DIEPINTEN = DIEPINTEN_TFEN;
|
||||
|
||||
#ifdef USB_DEDICATED_EP1_ENABLED
|
||||
udev->regs.dr->DIEP1INTEN = DIEPINTEN_TFEN;
|
||||
#endif
|
||||
|
||||
/* reset device address */
|
||||
udev->regs.dr->DCFG &= ~DCFG_DAR;
|
||||
|
||||
/* configure endpoint 0 to receive SETUP packets */
|
||||
usb_ctlep_startout(udev);
|
||||
|
||||
/* clear USB reset interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_RST;
|
||||
|
||||
usb_ep_active(udev, 0x00, USB_FS_EP0_MAX_LEN, USB_EPTYPE_CTRL);
|
||||
usb_ep_active(udev, 0x80, USB_FS_EP0_MAX_LEN, USB_EPTYPE_CTRL);
|
||||
|
||||
usbd_reset_callback();
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB speed enumeration finish interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static uint32_t usbd_int_enumfinish(usb_core_driver *udev)
|
||||
{
|
||||
uint8_t enum_speed = (uint8_t)((udev->regs.dr->DSTAT & DSTAT_ES) >> 1);
|
||||
|
||||
udev->regs.dr->DCTL &= ~DCTL_CGINAK;
|
||||
udev->regs.dr->DCTL |= DCTL_CGINAK;
|
||||
|
||||
udev->regs.gr->GUSBCS &= ~GUSBCS_UTT;
|
||||
|
||||
/* set USB turn-around time based on device speed and PHY interface */
|
||||
if ((uint8_t)USB_SPEED_HIGH == USB_SPEED[enum_speed])
|
||||
{
|
||||
udev->bp.core_speed = (uint8_t)USB_SPEED_HIGH;
|
||||
|
||||
udev->regs.gr->GUSBCS |= 0x09U << 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
udev->bp.core_speed = (uint8_t)USB_SPEED_FULL;
|
||||
|
||||
udev->regs.gr->GUSBCS |= 0x05U << 10;
|
||||
}
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_ENUMFIF;
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief USB suspend interrupt handler
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint32_t usbd_int_suspend(usb_core_driver *udev)
|
||||
{
|
||||
__IO uint8_t low_power = udev->bp.low_power;
|
||||
__IO uint8_t suspend = (uint8_t)(udev->regs.dr->DSTAT & DSTAT_SPST);
|
||||
|
||||
udev->dev.backup_status = udev->dev.cur_status;
|
||||
|
||||
if (low_power && suspend)
|
||||
{
|
||||
/* switch-off the USB clocks */
|
||||
*udev->regs.PWRCLKCTL |= PWRCLKCTL_SUCLK | PWRCLKCTL_SHCLK;
|
||||
|
||||
/* enter DEEP_SLEEP mode with LDO in low power mode */
|
||||
pmu_to_deepsleepmode(WFI_CMD);
|
||||
}
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_SP;
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief USB wakeup interrupt handler
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint32_t usbd_int_wakeup(usb_core_driver *udev)
|
||||
{
|
||||
__IO uint8_t low_power = udev->bp.low_power;
|
||||
__IO uint8_t remote_wakeup = udev->dev.pm.dev_remote_wakeup;
|
||||
|
||||
#if (1U == LPM_ENABLED)
|
||||
if (LPM_L1 == udev->dev.pm.lpm_state)
|
||||
{
|
||||
udev->dev.pm.lpm_state = LPM_L0;
|
||||
usbd_int_lpm(udev, LPM_L0_ACTIVE);
|
||||
}
|
||||
else
|
||||
#endif /* LPM_ENABLED */
|
||||
{
|
||||
if (remote_wakeup && low_power)
|
||||
{
|
||||
/* resume MCU CLK */
|
||||
|
||||
/* reset SLEEPDEEP bit of Cortex-M33 system control register */
|
||||
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
|
||||
}
|
||||
|
||||
usb_clock_active(udev);
|
||||
|
||||
/* inform upper layer by the resume event */
|
||||
udev->dev.cur_status = udev->dev.backup_status;
|
||||
}
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_WKUPIF;
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
#ifdef USB_DEDICATED_EP1_ENABLED
|
||||
|
||||
/*!
|
||||
\brief USB dedicated OUT endpoint 1 interrupt service routine handler
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
uint32_t usbd_int_dedicated_ep1out(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t oepintr = 0U;
|
||||
uint32_t oeplen = 0U;
|
||||
|
||||
oepintr = udev->regs.er_out[1]->DOEPINTF;
|
||||
oepintr &= udev->regs.dr->DOEP1INTEN;
|
||||
|
||||
/* transfer complete */
|
||||
if (oepintr & DOEPINTF_TF)
|
||||
{
|
||||
/* clear the bit in DOEPINTn for this interrupt */
|
||||
udev->regs.er_out[1]->DOEPINTF = DOEPINTF_TF;
|
||||
|
||||
if (USB_USE_DMA == udev->bp.transfer_mode)
|
||||
{
|
||||
oeplen = udev->regs.er_out[1]->DOEPLEN;
|
||||
|
||||
/* ToDo : handle more than one single MPS size packet */
|
||||
udev->dev.transc_out[1].xfer_count = udev->dev.transc_out[1].max_len -
|
||||
(oeplen & DEPLEN_TLEN);
|
||||
}
|
||||
|
||||
/* RX COMPLETE */
|
||||
usbd_out_transc(udev, 1U);
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief USB dedicated IN endpoint 1 interrupt service routine handler
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
uint32_t usbd_int_dedicated_ep1in(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t inten, intr, emptyen;
|
||||
|
||||
inten = udev->regs.dr->DIEP1INTEN;
|
||||
emptyen = udev->regs.dr->DIEPFEINTEN;
|
||||
|
||||
inten |= ((emptyen >> 1U) & 0x1U) << 7U;
|
||||
|
||||
intr = udev->regs.er_in[1]->DIEPINTF & inten;
|
||||
|
||||
if (intr & DIEPINTF_TF)
|
||||
{
|
||||
udev->regs.dr->DIEPFEINTEN &= ~(0x1U << 1U);
|
||||
|
||||
udev->regs.er_in[1]->DIEPINTF = DIEPINTF_TF;
|
||||
|
||||
/* TX COMPLETE */
|
||||
usbd_in_transc(udev, 1U);
|
||||
}
|
||||
|
||||
if (intr & DIEPINTF_TXFE)
|
||||
{
|
||||
usbd_emptytxfifo_write(udev, 1U);
|
||||
|
||||
udev->regs.er_in[1]->DIEPINTF = DIEPINTF_TXFE;
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if (1U == LPM_ENABLED)
|
||||
|
||||
/*!
|
||||
\brief USB LPM interrupt handler
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] active_type: active type
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg LPM_L0_ACTIVE: select L0 to active
|
||||
\arg LPM_L1_ACTIVE: select L1 to active
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint32_t usbd_int_lpm(usb_core_driver *udev, usb_lpm_type active_type)
|
||||
{
|
||||
__IO uint8_t low_power = udev->bp.low_power;
|
||||
__IO uint8_t suspend = (uint8_t)(udev->regs.dr->DSTAT & DSTAT_SPST);
|
||||
__IO uint8_t is_configured = (udev->dev.cur_status == (uint8_t)USBD_CONFIGURED) ? 1U : 0U;
|
||||
|
||||
switch (active_type)
|
||||
{
|
||||
case LPM_L0_ACTIVE:
|
||||
udev->dev.cur_status = udev->dev.backup_status;
|
||||
|
||||
/* switch-on the OTG clocks */
|
||||
usb_clock_active(udev);
|
||||
|
||||
if (low_power)
|
||||
{
|
||||
/* resume MCU CLK */
|
||||
|
||||
/* reset SLEEPDEEP bit of Cortex-M7 system control register */
|
||||
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
|
||||
}
|
||||
break;
|
||||
|
||||
case LPM_L1_ACTIVE:
|
||||
udev->dev.backup_status = udev->dev.cur_status;
|
||||
udev->dev.cur_status = (uint8_t)USBD_SUSPENDED;
|
||||
|
||||
/* add delay */
|
||||
usb_mdelay(300U);
|
||||
|
||||
/* switch-off the OTG clocks */
|
||||
*udev->regs.PWRCLKCTL |= PWRCLKCTL_SUCLK | PWRCLKCTL_SHCLK;
|
||||
|
||||
if (low_power)
|
||||
{
|
||||
/* enter DEEP_SLEEP mode with LDO in low power mode */
|
||||
pmu_to_deepsleepmode(WFI_CMD);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
#endif /* LPM_ENABLED */
|
||||
|
||||
/*!
|
||||
\brief check FIFO for the next packet to be loaded
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint identifier which is in (0..5)
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static uint32_t usbd_emptytxfifo_write(usb_core_driver *udev, uint32_t ep_num)
|
||||
{
|
||||
uint32_t len;
|
||||
uint32_t word_count;
|
||||
|
||||
usb_transc *transc = &udev->dev.transc_in[ep_num];
|
||||
|
||||
len = transc->xfer_len - transc->xfer_count;
|
||||
|
||||
/* get the data length to write */
|
||||
if (len > transc->max_len)
|
||||
{
|
||||
len = transc->max_len;
|
||||
}
|
||||
|
||||
word_count = (len + 3U) / 4U;
|
||||
|
||||
while (((udev->regs.er_in[ep_num]->DIEPTFSTAT & DIEPTFSTAT_IEPTFS) >= word_count) &&
|
||||
(transc->xfer_count < transc->xfer_len))
|
||||
{
|
||||
len = transc->xfer_len - transc->xfer_count;
|
||||
|
||||
if (len > transc->max_len)
|
||||
{
|
||||
len = transc->max_len;
|
||||
}
|
||||
|
||||
/* write FIFO in word(4bytes) */
|
||||
word_count = (len + 3U) / 4U;
|
||||
|
||||
/* write the FIFO */
|
||||
(void)usb_txfifo_write(&udev->regs, transc->xfer_buf, (uint8_t)ep_num, (uint16_t)len);
|
||||
|
||||
transc->xfer_buf += len;
|
||||
transc->xfer_count += len;
|
||||
|
||||
if (transc->xfer_count == transc->xfer_len)
|
||||
{
|
||||
/* disable the device endpoint FIFO empty interrupt */
|
||||
udev->regs.dr->DIEPFEINTEN &= ~(0x01U << ep_num);
|
||||
}
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
#endif /* BSP_USING_USB && RT_USING_USB_DEVICE */
|
||||
@@ -0,0 +1,693 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#include "drv_usbh_int.h"
|
||||
#include "drv_otghs_host.h"
|
||||
|
||||
#if defined(__CC_ARM) /*!< ARM compiler */
|
||||
#pragma O0
|
||||
#elif defined(__GNUC__) /*!< GNU compiler */
|
||||
#pragma GCC optimize("O0")
|
||||
#elif defined(__TASKING__) /*!< TASKING compiler */
|
||||
#pragma optimize = 0
|
||||
#endif /* __CC_ARM */
|
||||
|
||||
#if defined(BSP_USING_USB) && defined(RT_USING_USB_HOST)
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static uint32_t usbh_int_port(usb_core_driver *udev);
|
||||
static uint32_t usbh_int_pipe(usb_core_driver *udev);
|
||||
static uint32_t usbh_int_pipe_in(usb_core_driver *udev, uint32_t pp_num);
|
||||
static uint32_t usbh_int_pipe_out(usb_core_driver *udev, uint32_t pp_num);
|
||||
static uint32_t usbh_int_rxfifonoempty(usb_core_driver *udev);
|
||||
static uint32_t usbh_int_txfifoempty(usb_core_driver *udev, usb_pipe_mode pp_mode);
|
||||
|
||||
/*!
|
||||
\brief handle global host interrupt
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
uint32_t usbh_isr(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t retval = 0U;
|
||||
|
||||
__IO uint32_t intr = 0U;
|
||||
|
||||
/* check if host mode */
|
||||
if (HOST_MODE == (udev->regs.gr->GINTF & GINTF_COPM))
|
||||
{
|
||||
intr = usb_coreintr_get(&udev->regs);
|
||||
|
||||
if (!intr)
|
||||
{
|
||||
return 0U;
|
||||
}
|
||||
|
||||
if (intr & GINTF_SOF)
|
||||
{
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_SOF;
|
||||
}
|
||||
|
||||
if (intr & GINTF_RXFNEIF)
|
||||
{
|
||||
retval |= usbh_int_rxfifonoempty(udev);
|
||||
}
|
||||
|
||||
if (intr & GINTF_NPTXFEIF)
|
||||
{
|
||||
retval |= usbh_int_txfifoempty(udev, PIPE_NON_PERIOD);
|
||||
}
|
||||
|
||||
if (intr & GINTF_PTXFEIF)
|
||||
{
|
||||
retval |= usbh_int_txfifoempty(udev, PIPE_PERIOD);
|
||||
}
|
||||
|
||||
if (intr & GINTF_HCIF)
|
||||
{
|
||||
retval |= usbh_int_pipe(udev);
|
||||
}
|
||||
|
||||
if (intr & GINTF_HPIF)
|
||||
{
|
||||
retval |= usbh_int_port(udev);
|
||||
}
|
||||
|
||||
if (intr & GINTF_WKUPIF)
|
||||
{
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_WKUPIF;
|
||||
}
|
||||
|
||||
if (intr & GINTF_DISCIF)
|
||||
{
|
||||
if ((*udev->regs.HPCS & HPCS_PCST) == 0)
|
||||
{
|
||||
usbh_disconnect_callback(udev);
|
||||
}
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_DISCIF;
|
||||
}
|
||||
|
||||
if (intr & GINTF_ISOONCIF)
|
||||
{
|
||||
udev->regs.pr[0]->HCHCTL |= HCHCTL_CEN | HCHCTL_CDIS;
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_ISOONCIF;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB pipe halt
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] pp_num: pp_num: host channel number which is in (0..7)
|
||||
\param[in] pp_int: pipe interrupt
|
||||
\param[in] pp_status: pipe status
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static inline void usb_pp_halt(usb_core_driver *udev,
|
||||
uint8_t pp_num,
|
||||
uint32_t pp_int,
|
||||
usb_pipe_status pp_status)
|
||||
{
|
||||
udev->regs.pr[pp_num]->HCHINTEN |= HCHINTEN_CHIE;
|
||||
|
||||
usb_pipe_halt(udev, pp_num);
|
||||
|
||||
udev->regs.pr[pp_num]->HCHINTF = pp_int;
|
||||
|
||||
udev->host.pipe[pp_num].pp_status = pp_status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the host port interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
#if defined(__ICCARM__) /*!< IAR compiler */
|
||||
#pragma optimize = none
|
||||
#endif /* __ICCARM */
|
||||
static uint32_t usbh_int_port(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t retval = 0U;
|
||||
|
||||
__IO uint32_t port_state = *udev->regs.HPCS;
|
||||
|
||||
__IO uint32_t port_reset = 0U;
|
||||
|
||||
/* clear the interrupt bit in GINTF */
|
||||
port_state &= ~(HPCS_PE | HPCS_PCD | HPCS_PEDC);
|
||||
|
||||
/* port connect detected */
|
||||
if (*udev->regs.HPCS & HPCS_PCD)
|
||||
{
|
||||
port_state |= HPCS_PCD;
|
||||
|
||||
if ((*udev->regs.HPCS & HPCS_PCST) == HPCS_PCST)
|
||||
{
|
||||
usbh_connect_callback(udev);
|
||||
}
|
||||
|
||||
retval |= 1U;
|
||||
}
|
||||
|
||||
/* port enable changed */
|
||||
if (*udev->regs.HPCS & HPCS_PEDC)
|
||||
{
|
||||
port_state |= HPCS_PEDC;
|
||||
|
||||
if (*udev->regs.HPCS & HPCS_PE)
|
||||
{
|
||||
uint32_t port_speed = usb_curspeed_get(udev);
|
||||
|
||||
udev->host.connect_status = 1U;
|
||||
|
||||
if (PORT_SPEED_LOW == port_speed)
|
||||
{
|
||||
udev->regs.hr->HFT = 6000U;
|
||||
}
|
||||
else if (PORT_SPEED_FULL == port_speed)
|
||||
{
|
||||
udev->regs.hr->HFT = 48000U;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
port_reset = 1U;
|
||||
|
||||
udev->regs.gr->GINTEN |= GINTEN_DISCIE | GINTEN_SOFIE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no operation */
|
||||
}
|
||||
}
|
||||
|
||||
if (1U == port_reset)
|
||||
{
|
||||
usb_port_reset(udev);
|
||||
}
|
||||
|
||||
/* clear port interrupts */
|
||||
*udev->regs.HPCS = port_state;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle all host channels interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint32_t usbh_int_pipe(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t pp_num = 0U;
|
||||
uint32_t retval = 0U;
|
||||
|
||||
for (pp_num = 0U; pp_num < udev->bp.num_pipe; pp_num++)
|
||||
{
|
||||
if ((udev->regs.hr->HACHINT & HACHINT_HACHINT) & (1UL << pp_num))
|
||||
{
|
||||
if (udev->regs.pr[pp_num]->HCHCTL & HCHCTL_EPDIR)
|
||||
{
|
||||
retval |= usbh_int_pipe_in(udev, pp_num);
|
||||
}
|
||||
else
|
||||
{
|
||||
retval |= usbh_int_pipe_out(udev, pp_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the IN channel interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] pp_num: host channel number which is in (0..7)
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
#if defined(__ICCARM__) /*!< IAR compiler */
|
||||
#pragma optimize = none
|
||||
#endif /* __ICCARM */
|
||||
static uint32_t usbh_int_pipe_in(usb_core_driver *udev, uint32_t pp_num)
|
||||
{
|
||||
usb_pr *pp_reg = udev->regs.pr[pp_num];
|
||||
usb_pipe *pp = &udev->host.pipe[pp_num];
|
||||
|
||||
uint32_t intr_pp = pp_reg->HCHINTF;
|
||||
intr_pp &= pp_reg->HCHINTEN;
|
||||
|
||||
uint8_t ep_type = (uint8_t)((pp_reg->HCHCTL & HCHCTL_EPTYPE) >> 18);
|
||||
|
||||
if (intr_pp & HCHINTF_ACK)
|
||||
{
|
||||
pp_reg->HCHINTF = HCHINTF_ACK;
|
||||
}
|
||||
else if (intr_pp & HCHINTF_STALL)
|
||||
{
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_STALL, PIPE_STALL);
|
||||
pp_reg->HCHINTF = HCHINTF_NAK;
|
||||
|
||||
/* note: When there is a 'STALL', reset also NAK,
|
||||
else, the udev->host.pp_status = HC_STALL
|
||||
will be overwritten by 'NAK' in code below */
|
||||
intr_pp &= ~HCHINTF_NAK;
|
||||
}
|
||||
else if (intr_pp & HCHINTF_DTER)
|
||||
{
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_DTER, PIPE_DTGERR);
|
||||
pp_reg->HCHINTF = HCHINTF_NAK;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
if (intr_pp & HCHINTF_REQOVR)
|
||||
{
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_REQOVR, PIPE_REQOVR);
|
||||
}
|
||||
else if (intr_pp & HCHINTF_TF)
|
||||
{
|
||||
if ((uint8_t)USB_USE_DMA == udev->bp.transfer_mode)
|
||||
{
|
||||
udev->host.backup_xfercount[pp_num] = pp->xfer_len - (pp_reg->HCHLEN & HCHLEN_TLEN);
|
||||
}
|
||||
|
||||
pp->pp_status = PIPE_XF;
|
||||
pp->err_count = 0U;
|
||||
|
||||
pp_reg->HCHINTF = HCHINTF_TF;
|
||||
|
||||
switch (ep_type)
|
||||
{
|
||||
case USB_EPTYPE_CTRL:
|
||||
case USB_EPTYPE_BULK:
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_NAK, PIPE_XF);
|
||||
|
||||
pp->data_toggle_in ^= 1U;
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_INTR:
|
||||
case USB_EPTYPE_ISOC:
|
||||
pp_reg->HCHCTL |= HCHCTL_ODDFRM;
|
||||
pp->urb_state = URB_DONE;
|
||||
|
||||
#ifdef USBH_USE_RTOS
|
||||
usbh_hc_notifyurbchange_callback(udev, pp_num, pp->urb_state);
|
||||
#endif /* USBH_USE_RTOS */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (intr_pp & HCHINTF_CH)
|
||||
{
|
||||
pp_reg->HCHINTEN &= ~HCHINTEN_CHIE;
|
||||
|
||||
switch (pp->pp_status)
|
||||
{
|
||||
case PIPE_XF:
|
||||
pp->urb_state = URB_DONE;
|
||||
break;
|
||||
|
||||
case PIPE_STALL:
|
||||
pp->urb_state = URB_STALL;
|
||||
break;
|
||||
|
||||
case PIPE_TRACERR:
|
||||
case PIPE_DTGERR:
|
||||
pp->err_count = 0U;
|
||||
pp->urb_state = URB_ERROR;
|
||||
|
||||
pp->data_toggle_in ^= 1U;
|
||||
break;
|
||||
|
||||
case PIPE_IDLE:
|
||||
case PIPE_HALTED:
|
||||
case PIPE_NAK:
|
||||
case PIPE_NYET:
|
||||
case PIPE_BBERR:
|
||||
case PIPE_REQOVR:
|
||||
default:
|
||||
if ((uint8_t)USB_EPTYPE_INTR == ep_type)
|
||||
{
|
||||
pp->data_toggle_in ^= 1U;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef USBH_USE_RTOS
|
||||
usbh_hc_notifyurbchange_callback(udev, pp_num, pp->urb_state);
|
||||
#endif /* USBH_USE_RTOS */
|
||||
|
||||
pp_reg->HCHINTF = HCHINTF_CH;
|
||||
}
|
||||
else if (intr_pp & HCHINTF_USBER)
|
||||
{
|
||||
pp->err_count++;
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_USBER, PIPE_TRACERR);
|
||||
}
|
||||
else if (intr_pp & HCHINTF_NAK)
|
||||
{
|
||||
pp_reg->HCHINTF = HCHINTF_NAK;
|
||||
switch (ep_type)
|
||||
{
|
||||
case USB_EPTYPE_CTRL:
|
||||
case USB_EPTYPE_BULK:
|
||||
/* re-activate the channel */
|
||||
pp_reg->HCHCTL = (pp_reg->HCHCTL | HCHCTL_CEN) & ~HCHCTL_CDIS;
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_INTR:
|
||||
pp_reg->HCHINTEN |= HCHINTEN_CHIE;
|
||||
|
||||
(void)usb_pipe_halt(udev, (uint8_t)pp_num);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
pp->pp_status = PIPE_NAK;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the OUT channel interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] pp_num: host channel number which is in (0..7)
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
#if defined(__ICCARM__) /*!< IAR compiler */
|
||||
#pragma optimize = none
|
||||
#endif /* __ICCARM */
|
||||
static uint32_t usbh_int_pipe_out(usb_core_driver *udev, uint32_t pp_num)
|
||||
{
|
||||
usb_pr *pp_reg = udev->regs.pr[pp_num];
|
||||
usb_pipe *pp = &udev->host.pipe[pp_num];
|
||||
|
||||
uint32_t intr_pp = pp_reg->HCHINTF;
|
||||
intr_pp &= pp_reg->HCHINTEN;
|
||||
|
||||
if (intr_pp & HCHINTF_ACK)
|
||||
{
|
||||
if (1U == udev->host.pipe[pp_num].do_ping)
|
||||
{
|
||||
udev->host.pipe[pp_num].do_ping = 0U;
|
||||
pp->err_count = 0U;
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_ACK, PIPE_NAK);
|
||||
}
|
||||
|
||||
pp_reg->HCHINTF = HCHINTF_ACK;
|
||||
}
|
||||
else if (intr_pp & HCHINTF_STALL)
|
||||
{
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_STALL, PIPE_STALL);
|
||||
}
|
||||
else if (intr_pp & HCHINTF_DTER)
|
||||
{
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_DTER, PIPE_DTGERR);
|
||||
pp_reg->HCHINTF = HCHINTF_NAK;
|
||||
}
|
||||
else if (intr_pp & HCHINTF_REQOVR)
|
||||
{
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_REQOVR, PIPE_REQOVR);
|
||||
}
|
||||
else if (intr_pp & HCHINTF_TF)
|
||||
{
|
||||
pp->err_count = 0U;
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_TF, PIPE_XF);
|
||||
}
|
||||
else if (intr_pp & HCHINTF_NAK)
|
||||
{
|
||||
if (0U == udev->host.pipe[pp_num].do_ping)
|
||||
{
|
||||
if (1U == udev->host.pipe[pp_num].supp_ping)
|
||||
{
|
||||
udev->host.pipe[pp_num].do_ping = 1U;
|
||||
}
|
||||
}
|
||||
|
||||
pp->err_count = 0U;
|
||||
if (USB_USE_FIFO == udev->bp.transfer_mode)
|
||||
{
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_NAK, PIPE_NAK);
|
||||
}
|
||||
else
|
||||
{
|
||||
pp_reg->HCHINTF = HCHINTF_NAK;
|
||||
}
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_NAK, PIPE_NAK);
|
||||
}
|
||||
else if (intr_pp & HCHINTF_USBER)
|
||||
{
|
||||
pp->err_count++;
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_USBER, PIPE_TRACERR);
|
||||
}
|
||||
else if (intr_pp & HCHINTF_NYET)
|
||||
{
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_NYET, PIPE_NYET);
|
||||
|
||||
pp->err_count = 0U;
|
||||
}
|
||||
else if (intr_pp & HCHINTF_CH)
|
||||
{
|
||||
udev->regs.pr[pp_num]->HCHINTEN &= ~HCHINTEN_CHIE;
|
||||
|
||||
switch (pp->pp_status)
|
||||
{
|
||||
case PIPE_XF:
|
||||
pp->urb_state = URB_DONE;
|
||||
|
||||
if ((uint8_t)USB_EPTYPE_BULK == ((pp_reg->HCHCTL & HCHCTL_EPTYPE) >> 18U))
|
||||
{
|
||||
pp->data_toggle_out ^= 1U;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIPE_NAK:
|
||||
pp->urb_state = URB_NOTREADY;
|
||||
break;
|
||||
|
||||
case PIPE_NYET:
|
||||
pp->urb_state = URB_DONE;
|
||||
|
||||
if ((uint8_t)USB_EPTYPE_BULK == ((pp_reg->HCHCTL & HCHCTL_EPTYPE) >> 18U))
|
||||
{
|
||||
pp->data_toggle_out ^= 1U;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIPE_STALL:
|
||||
pp->urb_state = URB_STALL;
|
||||
break;
|
||||
|
||||
case PIPE_TRACERR:
|
||||
if (3U == pp->err_count)
|
||||
{
|
||||
pp->urb_state = URB_ERROR;
|
||||
pp->err_count = 0U;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIPE_IDLE:
|
||||
case PIPE_HALTED:
|
||||
case PIPE_BBERR:
|
||||
case PIPE_REQOVR:
|
||||
case PIPE_DTGERR:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef USBH_USE_RTOS
|
||||
usbh_hc_notifyurbchange_callback(udev, pp_num, pp->urb_state);
|
||||
#endif /* USBH_USE_RTOS */
|
||||
|
||||
pp_reg->HCHINTF = HCHINTF_CH;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the RX FIFO non-empty interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
#if defined(__ICCARM__) /*!< IAR compiler */
|
||||
#pragma optimize = none
|
||||
#endif /* __ICCARM */
|
||||
static uint32_t usbh_int_rxfifonoempty(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t count = 0U, xfer_count = 0U;
|
||||
|
||||
__IO uint8_t pp_num = 0U;
|
||||
__IO uint32_t rx_stat = 0U;
|
||||
|
||||
/* disable the RX status queue level interrupt */
|
||||
udev->regs.gr->GINTEN &= ~GINTEN_RXFNEIE;
|
||||
|
||||
rx_stat = udev->regs.gr->GRSTATP;
|
||||
pp_num = (uint8_t)(rx_stat & GRSTATRP_CNUM);
|
||||
|
||||
switch ((rx_stat & GRSTATRP_RPCKST) >> 17)
|
||||
{
|
||||
case GRXSTS_PKTSTS_IN:
|
||||
count = (rx_stat & GRSTATRP_BCOUNT) >> 4;
|
||||
|
||||
/* read the data into the host buffer. */
|
||||
if ((NULL != udev->host.pipe[pp_num].xfer_buf) && (count > 0U))
|
||||
{
|
||||
(void)usb_rxfifo_read(&udev->regs, udev->host.pipe[pp_num].xfer_buf, (uint16_t)count);
|
||||
|
||||
/* manage multiple transfer packet */
|
||||
udev->host.pipe[pp_num].xfer_buf += count;
|
||||
udev->host.pipe[pp_num].xfer_count += count;
|
||||
|
||||
xfer_count = udev->host.pipe[pp_num].xfer_count;
|
||||
|
||||
udev->host.backup_xfercount[pp_num] = xfer_count;
|
||||
|
||||
if (udev->regs.pr[pp_num]->HCHLEN & HCHLEN_PCNT)
|
||||
{
|
||||
/* re-activate the channel when more packets are expected */
|
||||
uint32_t pp_ctl = udev->regs.pr[pp_num]->HCHCTL;
|
||||
|
||||
pp_ctl |= HCHCTL_CEN;
|
||||
pp_ctl &= ~HCHCTL_CDIS;
|
||||
|
||||
udev->regs.pr[pp_num]->HCHCTL = pp_ctl;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GRXSTS_PKTSTS_IN_XFER_COMP:
|
||||
break;
|
||||
|
||||
case GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
|
||||
count = (rx_stat & GRSTATRP_BCOUNT) >> 4;
|
||||
|
||||
while (count > 0U)
|
||||
{
|
||||
rx_stat = udev->regs.gr->GRSTATP;
|
||||
count--;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRXSTS_PKTSTS_CH_HALTED:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* enable the RX status queue level interrupt */
|
||||
udev->regs.gr->GINTEN |= GINTEN_RXFNEIE;
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the TX FIFO empty interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] pp_mode: pipe mode
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
#if defined(__ICCARM__) /*!< IAR compiler */
|
||||
#pragma optimize = none
|
||||
#endif /* __ICCARM */
|
||||
static uint32_t usbh_int_txfifoempty(usb_core_driver *udev, usb_pipe_mode pp_mode)
|
||||
{
|
||||
uint8_t pp_num = 0U;
|
||||
uint16_t word_count = 0U, len = 0U;
|
||||
__IO uint32_t *txfiforeg = 0U, txfifostate = 0U;
|
||||
|
||||
if (PIPE_NON_PERIOD == pp_mode)
|
||||
{
|
||||
txfiforeg = &udev->regs.gr->HNPTFQSTAT;
|
||||
}
|
||||
else if (PIPE_PERIOD == pp_mode)
|
||||
{
|
||||
txfiforeg = &udev->regs.hr->HPTFQSTAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0U;
|
||||
}
|
||||
|
||||
txfifostate = *txfiforeg;
|
||||
|
||||
pp_num = (uint8_t)((txfifostate & TFQSTAT_CNUM) >> 27);
|
||||
|
||||
word_count = (uint16_t)(udev->host.pipe[pp_num].xfer_len + 3U) / 4U;
|
||||
|
||||
while (((txfifostate & TFQSTAT_TXFS) >= word_count) && (0U != udev->host.pipe[pp_num].xfer_len))
|
||||
{
|
||||
len = (uint16_t)(txfifostate & TFQSTAT_TXFS) * 4U;
|
||||
|
||||
if (len > udev->host.pipe[pp_num].xfer_len)
|
||||
{
|
||||
/* last packet */
|
||||
len = (uint16_t)udev->host.pipe[pp_num].xfer_len;
|
||||
|
||||
if (PIPE_NON_PERIOD == pp_mode)
|
||||
{
|
||||
udev->regs.gr->GINTEN &= ~GINTEN_NPTXFEIE;
|
||||
}
|
||||
else
|
||||
{
|
||||
udev->regs.gr->GINTEN &= ~GINTEN_PTXFEIE;
|
||||
}
|
||||
}
|
||||
|
||||
word_count = (uint16_t)((udev->host.pipe[pp_num].xfer_len + 3U) / 4U);
|
||||
usb_txfifo_write(&udev->regs, udev->host.pipe[pp_num].xfer_buf, pp_num, len);
|
||||
|
||||
udev->host.pipe[pp_num].xfer_buf += len;
|
||||
udev->host.pipe[pp_num].xfer_len -= len;
|
||||
udev->host.pipe[pp_num].xfer_count += len;
|
||||
|
||||
txfifostate = *txfiforeg;
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
#endif /* BSP_USING_USB && RT_USING_USB_HOST */
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#include "drv_usbh_pipe.h"
|
||||
|
||||
#if defined(BSP_USING_USB) && defined(RT_USING_USB_HOST)
|
||||
|
||||
static uint16_t usbh_freepipe_get(usb_core_driver *pudev);
|
||||
|
||||
/*!
|
||||
\brief create a pipe
|
||||
\param[in] pudev: pointer to usb core instance
|
||||
\param[in] pp_num: pipe number
|
||||
\param[in] udev: USB device
|
||||
\param[in] ep_type: endpoint type
|
||||
\param[in] ep_mpl: endpoint max packet length
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
uint8_t usbh_pipe_create(usb_core_driver *pudev,
|
||||
uint8_t dev_addr,
|
||||
uint8_t dev_speed,
|
||||
uint8_t pp_num,
|
||||
uint8_t ep_num,
|
||||
uint8_t ep_type,
|
||||
uint16_t ep_mpl)
|
||||
{
|
||||
usb_pipe *pp = &pudev->host.pipe[pp_num];
|
||||
|
||||
pp->dev_addr = dev_addr;
|
||||
pp->dev_speed = dev_speed;
|
||||
pp->ep.num = ep_num & 0x7FU;
|
||||
pp->ep.type = ep_type;
|
||||
pp->ep.mps = ep_mpl;
|
||||
|
||||
if (((USB_EPTYPE_BULK == pp->ep.type) || (USB_EPTYPE_CTRL == pp->ep.type)))
|
||||
{
|
||||
pp->supp_ping = (uint8_t)(pp->dev_speed == PORT_SPEED_HIGH);
|
||||
}
|
||||
|
||||
if (0x80U == (ep_num & 0x80U))
|
||||
{
|
||||
pp->ep.dir = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pp->ep.dir = 0;
|
||||
}
|
||||
|
||||
usb_pipe_init(pudev, pp_num);
|
||||
|
||||
return HC_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief modify a pipe
|
||||
\param[in] pudev: pointer to usb core instance
|
||||
\param[in] pp_num: pipe number
|
||||
\param[in] dev_addr: device address
|
||||
\param[in] dev_speed: device speed
|
||||
\param[in] ep_type: endpoint type
|
||||
\param[in] ep_mpl: endpoint max packet length
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
uint8_t usbh_pipe_update(usb_core_driver *pudev,
|
||||
uint8_t pp_num,
|
||||
uint8_t dev_addr,
|
||||
uint32_t dev_speed,
|
||||
uint16_t ep_mpl)
|
||||
{
|
||||
usb_pipe *pp = &pudev->host.pipe[pp_num];
|
||||
|
||||
if ((pp->dev_addr != dev_addr) && (dev_addr))
|
||||
{
|
||||
pp->dev_addr = dev_addr;
|
||||
}
|
||||
|
||||
if ((pp->dev_speed != dev_speed) && (dev_speed))
|
||||
{
|
||||
pp->dev_speed = dev_speed;
|
||||
}
|
||||
|
||||
if ((pp->ep.mps != ep_mpl) && (ep_mpl))
|
||||
{
|
||||
pp->ep.mps = ep_mpl;
|
||||
}
|
||||
|
||||
usb_pipe_init(pudev, pp_num);
|
||||
|
||||
return HC_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief allocate a new pipe
|
||||
\param[in] pudev: pointer to usb core instance
|
||||
\param[in] ep_addr: endpoint address
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
uint8_t usbh_pipe_allocate(usb_core_driver *pudev, uint8_t ep_addr)
|
||||
{
|
||||
uint16_t pp_num = usbh_freepipe_get(pudev);
|
||||
|
||||
if (HC_ERROR != pp_num)
|
||||
{
|
||||
pudev->host.pipe[pp_num].in_used = 1U;
|
||||
pudev->host.pipe[pp_num].ep.dir = EP_DIR(ep_addr);
|
||||
pudev->host.pipe[pp_num].ep.num = EP_ID(ep_addr);
|
||||
}
|
||||
|
||||
return pp_num;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief free a pipe
|
||||
\param[in] pudev: pointer to usb core instance
|
||||
\param[in] pp_num: pipe number
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
uint8_t usbh_pipe_free(usb_core_driver *pudev, uint8_t pp_num)
|
||||
{
|
||||
if (pp_num < HC_MAX)
|
||||
{
|
||||
pudev->host.pipe[pp_num].in_used = 0U;
|
||||
}
|
||||
|
||||
return USBH_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief delete all USB host pipe
|
||||
\param[in] pudev: pointer to usb core instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
uint8_t usbh_pipe_delete(usb_core_driver *pudev)
|
||||
{
|
||||
uint8_t pp_num = 0U;
|
||||
|
||||
for (pp_num = 2U; pp_num < HC_MAX; pp_num++)
|
||||
{
|
||||
pudev->host.pipe[pp_num] = (usb_pipe){ 0 };
|
||||
}
|
||||
|
||||
return USBH_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get a free pipe number for allocation
|
||||
\param[in] pudev: pointer to usb core instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint16_t usbh_freepipe_get(usb_core_driver *pudev)
|
||||
{
|
||||
uint8_t pp_num = 0U;
|
||||
|
||||
for (pp_num = 0U; pp_num < HC_MAX; pp_num++)
|
||||
{
|
||||
if (pudev->host.pipe[pp_num].in_used == 0U)
|
||||
{
|
||||
return pp_num;
|
||||
}
|
||||
}
|
||||
|
||||
return HC_ERROR;
|
||||
}
|
||||
|
||||
#endif /* BSP_USING_USB && RT_USING_USB_HOST */
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#include "drv_usbh_transc.h"
|
||||
|
||||
#if defined(BSP_USING_USB) && defined(RT_USING_USB_HOST)
|
||||
|
||||
#define USB_SETUP_PACKET_LEN 8U
|
||||
|
||||
/*!
|
||||
\brief prepare a pipe and start a transfer
|
||||
\param[in] pudev: pointer to usb core instance
|
||||
\param[in] pp_num: pipe number
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint32_t usbh_request_submit(usb_core_driver *pudev, uint8_t pp_num)
|
||||
{
|
||||
pudev->host.pipe[pp_num].urb_state = URB_IDLE;
|
||||
pudev->host.pipe[pp_num].xfer_count = 0U;
|
||||
|
||||
return usb_pipe_xfer(pudev, pp_num);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief send the setup packet to the USB device
|
||||
\param[in] pudev: pointer to usb core instance
|
||||
\param[in] buf: data buffer which will be sent to USB device
|
||||
\param[in] pp_num: pipe number
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usbh_status usbh_ctlsetup_send(usb_core_driver *pudev, uint8_t *buf, uint8_t pp_num)
|
||||
{
|
||||
usb_pipe *pp = &pudev->host.pipe[pp_num];
|
||||
|
||||
pp->DPID = PIPE_DPID_SETUP;
|
||||
pp->xfer_buf = buf;
|
||||
pp->xfer_len = USB_SETUP_PACKET_LEN;
|
||||
|
||||
return (usbh_status)usbh_request_submit(pudev, pp_num);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief send a data packet to the USB device
|
||||
\param[in] pudev: pointer to usb core instance
|
||||
\param[in] buf: data buffer which will be sent to USB device
|
||||
\param[in] pp_num: pipe number
|
||||
\param[in] len: length of the data to be sent
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usbh_status usbh_data_send(usb_core_driver *pudev, uint8_t *buf, uint8_t pp_num, uint16_t len)
|
||||
{
|
||||
usb_pipe *pp = &pudev->host.pipe[pp_num];
|
||||
|
||||
pp->xfer_buf = buf;
|
||||
pp->xfer_len = len;
|
||||
|
||||
switch (pp->ep.type)
|
||||
{
|
||||
case USB_EPTYPE_CTRL:
|
||||
if (0U == len)
|
||||
{
|
||||
pp->data_toggle_out = 1U;
|
||||
}
|
||||
|
||||
pp->DPID = PIPE_DPID[pp->data_toggle_out];
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_INTR:
|
||||
pp->DPID = PIPE_DPID[pp->data_toggle_out];
|
||||
|
||||
pp->data_toggle_out ^= 1U;
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_BULK:
|
||||
pp->DPID = PIPE_DPID[pp->data_toggle_out];
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_ISOC:
|
||||
pp->DPID = PIPE_DPID[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
usbh_request_submit(pudev, pp_num);
|
||||
|
||||
return USBH_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief receive a data packet from the USB device
|
||||
\param[in] pudev: pointer to usb core instance
|
||||
\param[in] buf: data buffer which will be received from USB device
|
||||
\param[in] pp_num: pipe number
|
||||
\param[in] len: length of the data to be received
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usbh_status usbh_data_recev(usb_core_driver *pudev, uint8_t *buf, uint8_t pp_num, uint16_t len)
|
||||
{
|
||||
usb_pipe *pp = &pudev->host.pipe[pp_num];
|
||||
|
||||
pp->xfer_buf = buf;
|
||||
pp->xfer_len = len;
|
||||
|
||||
switch (pp->ep.type)
|
||||
{
|
||||
case USB_EPTYPE_CTRL:
|
||||
pp->DPID = PIPE_DPID[1];
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_INTR:
|
||||
pp->DPID = PIPE_DPID[pp->data_toggle_in];
|
||||
|
||||
/* Toggle DATA PID */
|
||||
pp->data_toggle_in ^= 1U;
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_BULK:
|
||||
pp->DPID = PIPE_DPID[pp->data_toggle_in];
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_ISOC:
|
||||
pp->DPID = PIPE_DPID[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
usbh_request_submit(pudev, pp_num);
|
||||
|
||||
return USBH_OK;
|
||||
}
|
||||
|
||||
#endif /* BSP_USING_USB && RT_USING_USB_HOST */
|
||||
@@ -0,0 +1,733 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-11-07 RealThread the first version
|
||||
*/
|
||||
|
||||
#include "drv_usb_hw.h"
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <board.h>
|
||||
|
||||
#if defined(BSP_USING_USB)
|
||||
|
||||
#define TIM_MSEC_DELAY 0x01U
|
||||
#define TIM_USEC_DELAY 0x02U
|
||||
|
||||
#if defined(RT_USING_USB_HOST)
|
||||
#ifndef USE_ULPI_PHY
|
||||
|
||||
#ifdef USE_USBHS0
|
||||
#if defined(SOC_SERIES_GD32H75E)
|
||||
#define HOST_POWERSW_PORT_RCC RCU_GPIOG
|
||||
#define HOST_POWERSW_PORT GPIOG
|
||||
#define HOST_POWERSW_VBUS GPIO_PIN_8
|
||||
#elif defined(SOC_SERIES_GD32H7xx)
|
||||
#warning "Please refer to the relevant sections in the chip manual to redefine the pins."
|
||||
#define HOST_POWERSW_PORT_RCC RCU_GPIOB
|
||||
#define HOST_POWERSW_PORT GPIOB
|
||||
#define HOST_POWERSW_VBUS GPIO_PIN_13
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
#define HOST_POWERSW_PORT_RCC RCU_GPIOG
|
||||
#define HOST_POWERSW_PORT GPIOG
|
||||
#define HOST_POWERSW_VBUS GPIO_PIN_7
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifdef USE_USBHS0
|
||||
#define HOST_POWERSW_PORT_RCC RCU_GPIOC
|
||||
#define HOST_POWERSW_PORT GPIOC
|
||||
#define HOST_POWERSW_VBUS GPIO_PIN_7
|
||||
#endif
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
#define HOST_POWERSW_PORT_RCC RCU_GPIOC
|
||||
#define HOST_POWERSW_PORT GPIOC
|
||||
#define HOST_POWERSW_VBUS GPIO_PIN_9
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#define HOST_SOF_OUTPUT_RCC RCC_APB2PERIPH_GPIOA
|
||||
#define HOST_SOF_PORT GPIOA
|
||||
#define HOST_SOF_SIGNAL GPIO_PIN_8
|
||||
#endif
|
||||
|
||||
__IO uint32_t delay_time = 0U;
|
||||
__IO uint16_t timer_prescaler = 23U;
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static void hw_time_set(uint8_t unit);
|
||||
static void hw_delay(uint32_t ntime, uint8_t unit);
|
||||
|
||||
/*!
|
||||
\brief configure USB GPIO
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_gpio_config(void)
|
||||
{
|
||||
#ifdef USE_USBHS0
|
||||
rcu_periph_clock_enable(RCU_GPIOA);
|
||||
rcu_periph_clock_enable(RCU_GPIOB);
|
||||
rcu_periph_clock_enable(RCU_GPIOC);
|
||||
|
||||
/* ULPI_STP(PC0) GPIO pin configuration */
|
||||
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0);
|
||||
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, GPIO_PIN_0);
|
||||
|
||||
/* ULPI_CK(PA5) GPIO pin configuration */
|
||||
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
|
||||
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, GPIO_PIN_5);
|
||||
|
||||
/* ULPI_NXT(PC3) GPIO pin configuration */
|
||||
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
|
||||
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, GPIO_PIN_3);
|
||||
|
||||
/* ULPI_DIR(PC2) GPIO pin configuration */
|
||||
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_2);
|
||||
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, GPIO_PIN_2);
|
||||
|
||||
/* ULPI_D1(PB0), ULPI_D2(PB1), ULPI_D3(PB10), ULPI_D4(PB11) \
|
||||
ULPI_D5(PB12), ULPI_D6(PB13) and ULPI_D7(PB5) GPIO pin configuration */
|
||||
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE,
|
||||
GPIO_PIN_0 |
|
||||
GPIO_PIN_1 | GPIO_PIN_10 | GPIO_PIN_11);
|
||||
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ,
|
||||
GPIO_PIN_12 |
|
||||
GPIO_PIN_13 | GPIO_PIN_5);
|
||||
|
||||
/* ULPI_D0(PA3) GPIO pin configuration */
|
||||
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
|
||||
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, GPIO_PIN_3);
|
||||
|
||||
gpio_af_set(GPIOA, GPIO_AF_10, GPIO_PIN_5);
|
||||
gpio_af_set(GPIOB, GPIO_AF_10, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_5 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13);
|
||||
gpio_af_set(GPIOC, GPIO_AF_10, GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_3);
|
||||
|
||||
#endif /* USE_USBHS0 */
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
rcu_periph_clock_enable(RCU_GPIOH);
|
||||
rcu_periph_clock_enable(RCU_GPIOG);
|
||||
|
||||
/* ULPI_STP(PH2) GPIO pin configuration */
|
||||
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_2);
|
||||
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, GPIO_PIN_2);
|
||||
|
||||
|
||||
/* ULPI_CK(PH5) GPIO pin configuration */
|
||||
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
|
||||
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, GPIO_PIN_5);
|
||||
|
||||
/* ULPI_NXT(PH4) GPIO pin configuration */
|
||||
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_4);
|
||||
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, GPIO_PIN_4);
|
||||
|
||||
/* ULPI_DIR(PH3) GPIO pin configuration */
|
||||
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
|
||||
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, GPIO_PIN_3);
|
||||
|
||||
/* ULPI_D0(PH6) GPIO pin configuration */
|
||||
/* ULPI_D1(PH7), ULPI_D2(PH8), ULPI_D3(PH9), ULPI_D4(PH10) \
|
||||
ULPI_D5(PH11), ULPI_D6(PH12) and ULPI_D7(PG5) GPIO pin configuration */
|
||||
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE,
|
||||
GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 |
|
||||
GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
|
||||
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ,
|
||||
GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 |
|
||||
GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
|
||||
|
||||
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
|
||||
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, GPIO_PIN_5);
|
||||
|
||||
gpio_af_set(GPIOG, GPIO_AF_8, GPIO_PIN_5);
|
||||
gpio_af_set(GPIOH, GPIO_AF_8, GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
|
||||
#endif /* USE_USBHS1 */
|
||||
}
|
||||
|
||||
extern usb_core_driver gd_usb_core;
|
||||
|
||||
#ifdef USE_USBHS0
|
||||
/*!
|
||||
\brief this function handles USBHS0 interrupt
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void USBHS0_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
|
||||
#if defined(RT_USING_USB_DEVICE)
|
||||
usbd_isr(&gd_usb_core);
|
||||
#else
|
||||
usbh_isr(&gd_usb_core);
|
||||
#endif
|
||||
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
#endif /* USE_USBHS0 */
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
/*!
|
||||
\brief this function handles USBHS1 interrupt
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void USBHS1_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
|
||||
#if defined(RT_USING_USB_DEVICE)
|
||||
usbd_isr(&gd_usb_core);
|
||||
#else
|
||||
usbh_isr(&gd_usb_core);
|
||||
#endif
|
||||
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
#endif /* USE_USBHS1 */
|
||||
|
||||
/*!
|
||||
\brief resume MCU clock
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void resume_mcu_clk(void)
|
||||
{
|
||||
/* enable HXTAL */
|
||||
rcu_osci_on(RCU_HXTAL);
|
||||
|
||||
/* wait till HXTAL is ready */
|
||||
while (RESET == rcu_flag_get(RCU_FLAG_HXTALSTB))
|
||||
{
|
||||
}
|
||||
|
||||
/* enable PLL */
|
||||
rcu_osci_on(RCU_PLL0_CK);
|
||||
|
||||
/* wait till PLL is ready */
|
||||
while (RESET == rcu_flag_get(RCU_FLAG_PLL0STB))
|
||||
{
|
||||
}
|
||||
|
||||
/* select PLL as system clock source */
|
||||
rcu_system_clock_source_config(RCU_CKSYSSRC_PLL0P);
|
||||
|
||||
/* wait till PLL is used as system clock source */
|
||||
while (RCU_SCSS_PLL0P != rcu_system_clock_source_get())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_USBHS0
|
||||
/*!
|
||||
\brief this function handles USBHS0 wakeup interrupt request
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void USBHS0_WKUP_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
|
||||
if (gd_usb_core.bp.low_power)
|
||||
{
|
||||
resume_mcu_clk();
|
||||
|
||||
#ifndef USE_IRC48M
|
||||
rcu_usb48m_clock_config(IDX_USBHS0, RCU_USB48MSRC_PLL0R);
|
||||
#else
|
||||
/* enable IRC48M clock */
|
||||
rcu_osci_on(RCU_IRC48M);
|
||||
|
||||
/* wait till IRC48M is ready */
|
||||
while (SUCCESS != rcu_osci_stab_wait(RCU_IRC48M))
|
||||
{
|
||||
}
|
||||
|
||||
rcu_ck48m_clock_config(RCU_CK48MSRC_IRC48M);
|
||||
#endif /* USE_IRC48M */
|
||||
|
||||
rcu_periph_clock_enable(RCU_USBHS0);
|
||||
|
||||
usb_clock_active(&gd_usb_core);
|
||||
}
|
||||
|
||||
exti_interrupt_flag_clear(EXTI_31);
|
||||
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
#endif /* USE_USBHS0 */
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
/*!
|
||||
\brief this function handles USBHS1 wakeup interrupt request
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void USBHS1_WKUP_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
|
||||
if (gd_usb_core.bp.low_power)
|
||||
{
|
||||
resume_mcu_clk();
|
||||
|
||||
#ifndef USE_IRC48M
|
||||
rcu_usb48m_clock_config(IDX_USBHS0, RCU_USB48MSRC_PLL0R);
|
||||
#else
|
||||
/* enable IRC48M clock */
|
||||
rcu_osci_on(RCU_IRC48M);
|
||||
|
||||
/* wait till IRC48M is ready */
|
||||
while (SUCCESS != rcu_osci_stab_wait(RCU_IRC48M))
|
||||
{
|
||||
}
|
||||
|
||||
rcu_ck48m_clock_config(RCU_CK48MSRC_IRC48M);
|
||||
#endif /* USE_IRC48M */
|
||||
|
||||
rcu_periph_clock_enable(RCU_USBHS1);
|
||||
|
||||
usb_clock_active(&gd_usb_core);
|
||||
}
|
||||
|
||||
exti_interrupt_flag_clear(EXTI_32);
|
||||
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
#endif /* USE_USBHS1 */
|
||||
|
||||
#ifdef USB_DEDICATED_EP1_ENABLED
|
||||
|
||||
#ifdef USE_USBHS0
|
||||
/*!
|
||||
\brief this function handles USBHS0 dedicated endpoint 1 OUT interrupt request.
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void USBHS0_EP1_OUT_IRQHandler(void)
|
||||
{
|
||||
usbd_int_dedicated_ep1out(&cdc_acm);
|
||||
}
|
||||
|
||||
#endif /* USE_USBHS0 */
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
/*!
|
||||
\brief this function handles USBHS1 dedicated endpoint 1 OUT interrupt request.
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void USBHS1_EP1_OUT_IRQHandler(void)
|
||||
{
|
||||
usbd_int_dedicated_ep1out(&cdc_acm);
|
||||
}
|
||||
|
||||
#endif /* USE_USBHS1 */
|
||||
|
||||
#ifdef USE_USBHS0
|
||||
/*!
|
||||
\brief this function handles USBHS0 dedicated endpoint 1 IN interrupt request
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void USBHS0_EP1_IN_IRQHandler(void)
|
||||
{
|
||||
usbd_int_dedicated_ep1in(&cdc_acm);
|
||||
}
|
||||
|
||||
#endif /* USE_USBHS0 */
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
/*!
|
||||
\brief this function handles USBHS1 dedicated endpoint 1 IN interrupt request
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void USBHS1_EP1_IN_IRQHandler(void)
|
||||
{
|
||||
usbd_int_dedicated_ep1in(&cdc_acm);
|
||||
}
|
||||
|
||||
#endif /* USE_USBHS1 */
|
||||
|
||||
#endif /* USB_DEDICATED_EP1_ENABLED */
|
||||
|
||||
/*!
|
||||
\brief configure USB clock
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_rcu_config(void)
|
||||
{
|
||||
pmu_usb_regulator_enable();
|
||||
pmu_usb_voltage_detector_enable();
|
||||
while (SET != pmu_flag_get(PMU_FLAG_USB33RF))
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef USE_USB_FS
|
||||
|
||||
#ifndef USE_IRC48M
|
||||
|
||||
/* configure the pll1 input and output clock range */
|
||||
rcu_pll_input_output_clock_range_config(IDX_PLL1, RCU_PLL1RNG_4M_8M, RCU_PLL1VCO_192M_836M);
|
||||
|
||||
rcu_pll1_config(5, 96, 2, 10, 2);
|
||||
/* enable PLL1Q clock output */
|
||||
rcu_pll_clock_output_enable(RCU_PLL1Q);
|
||||
rcu_osci_on(RCU_PLL1_CK);
|
||||
|
||||
#ifdef USE_USBHS0
|
||||
rcu_usbhs_pll1qpsc_config(IDX_USBHS0, RCU_USBHSPSC_DIV1);
|
||||
|
||||
rcu_usb48m_clock_config(IDX_USBHS0, RCU_USB48MSRC_PLL1Q);
|
||||
#endif /* USE_USBHS0 */
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
rcu_usbhs_pll1qpsc_config(IDX_USBHS1, RCU_USBHSPSC_DIV1);
|
||||
|
||||
rcu_usb48m_clock_config(IDX_USBHS1, RCU_USB48MSRC_PLL1Q);
|
||||
#endif /* USE_USBHS1 */
|
||||
|
||||
#else
|
||||
/* enable IRC48M clock */
|
||||
rcu_osci_on(RCU_IRC48M);
|
||||
|
||||
/* wait till IRC48M is ready */
|
||||
while (SUCCESS != rcu_osci_stab_wait(RCU_IRC48M))
|
||||
{
|
||||
}
|
||||
|
||||
rcu_ck48m_clock_config(RCU_CK48MSRC_IRC48M);
|
||||
|
||||
#ifdef USE_USBHS0
|
||||
rcu_usb48m_clock_config(IDX_USBHS0, RCU_USB48MSRC_IRC48M);
|
||||
#endif /* USE_USBHS0 */
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
rcu_usb48m_clock_config(IDX_USBHS1, RCU_USB48MSRC_IRC48M);
|
||||
#endif /* USE_USBHS1 */
|
||||
|
||||
#endif /* USE_IRC48M */
|
||||
|
||||
#endif /* USE_USB_FS */
|
||||
|
||||
#ifdef USE_USBHS0
|
||||
rcu_periph_clock_enable(RCU_USBHS0);
|
||||
#endif /* USE_USBHS0 */
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
rcu_periph_clock_enable(RCU_USBHS1);
|
||||
#endif /* USE_USBHS1 */
|
||||
|
||||
#ifdef USE_ULPI_PHY
|
||||
#ifdef USE_USBHS0
|
||||
rcu_periph_clock_enable(RCU_USBHS0ULPI);
|
||||
#endif
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
rcu_periph_clock_enable(RCU_USBHS1ULPI);
|
||||
#endif
|
||||
#endif /* USE_ULPI_PHY */
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure USB interrupt
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_intr_config(void)
|
||||
{
|
||||
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
|
||||
|
||||
#ifdef USE_USBHS0
|
||||
nvic_irq_enable((uint8_t)USBHS0_IRQn, 3U, 0U);
|
||||
#endif /* USE_USBHS0 */
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
nvic_irq_enable((uint8_t)USBHS1_IRQn, 3U, 0U);
|
||||
#endif /* USE_USBHS0 */
|
||||
|
||||
/* enable the power module clock */
|
||||
rcu_periph_clock_enable(RCU_PMU);
|
||||
|
||||
#ifdef USE_USBHS0
|
||||
/* USB wakeup EXTI line configuration */
|
||||
exti_interrupt_flag_clear(EXTI_31);
|
||||
exti_init(EXTI_31, EXTI_INTERRUPT, EXTI_TRIG_RISING);
|
||||
exti_interrupt_enable(EXTI_31);
|
||||
|
||||
nvic_irq_enable((uint8_t)USBHS0_WKUP_IRQn, 1U, 0U);
|
||||
#endif /* USE_USBHS0 */
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
/* USB wakeup EXTI line configuration */
|
||||
exti_interrupt_flag_clear(EXTI_32);
|
||||
exti_init(EXTI_32, EXTI_INTERRUPT, EXTI_TRIG_RISING);
|
||||
exti_interrupt_enable(EXTI_32);
|
||||
|
||||
nvic_irq_enable((uint8_t)USBHS1_WKUP_IRQn, 1U, 0U);
|
||||
#endif /* USE_USBHS1 */
|
||||
|
||||
#ifdef USB_DEDICATED_EP1_ENABLED
|
||||
|
||||
#ifdef USE_USBHS0
|
||||
nvic_irq_enable((uint8_t)USBHS0_EP1_OUT_IRQn, 1U, 0U);
|
||||
nvic_irq_enable((uint8_t)USBHS0_EP1_IN_IRQn, 1U, 0U);
|
||||
#endif /* USE_USBHS0 */
|
||||
|
||||
#ifdef USE_USBHS1
|
||||
nvic_irq_enable((uint8_t)USBHS1_EP1_OUT_IRQn, 1U, 0U);
|
||||
nvic_irq_enable((uint8_t)USBHS1_EP1_IN_IRQn, 1U, 0U);
|
||||
#endif /* USE_USBHS1 */
|
||||
|
||||
#endif /* USB_DEDICATED_EP1_ENABLED */
|
||||
}
|
||||
|
||||
|
||||
#if defined(RT_USING_USB_HOST)
|
||||
/*!
|
||||
\brief drives the VBUS signal through GPIO
|
||||
\param[in] state: VBUS states
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_vbus_drive(uint8_t state)
|
||||
{
|
||||
if (0U == state)
|
||||
{
|
||||
/* disable is needed on output of the power switch */
|
||||
gpio_bit_reset(HOST_POWERSW_PORT, HOST_POWERSW_VBUS);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* enable the power switch by driving the enable high */
|
||||
gpio_bit_set(HOST_POWERSW_PORT, HOST_POWERSW_VBUS);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configures the GPIO for the VBUS
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_vbus_config(void)
|
||||
{
|
||||
rcu_periph_clock_enable(HOST_POWERSW_PORT_RCC);
|
||||
|
||||
/* USBFS_VBUS_CTRL(PD13) GPIO pin configuration */
|
||||
gpio_mode_set(HOST_POWERSW_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, HOST_POWERSW_VBUS);
|
||||
gpio_output_options_set(HOST_POWERSW_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, HOST_POWERSW_VBUS);
|
||||
|
||||
/* by default, disable is needed on output of the power switch */
|
||||
usb_vbus_drive(0U);
|
||||
|
||||
/* delay is need for stabilizing the VBUS low in reset condition,
|
||||
* when VBUS = 1 and reset-button is pressed by user
|
||||
*/
|
||||
usb_mdelay(200);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(BSP_USING_TIMER2) && defined(BSP_USING_USB)
|
||||
#error "Timer2 has been occupied by USB. Please select another timer resource."
|
||||
#endif
|
||||
/*!
|
||||
\brief initializes delay unit using Timer2
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_timer_init(void)
|
||||
{
|
||||
/* configure the priority group to 2 bits */
|
||||
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
|
||||
|
||||
/* enable the TIM2 global interrupt */
|
||||
nvic_irq_enable((uint8_t)TIMER2_IRQn, 1U, 0U);
|
||||
|
||||
rcu_periph_clock_enable(RCU_TIMER2);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief delay in microseconds
|
||||
\param[in] usec: value of delay required in microseconds
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_udelay(const uint32_t usec)
|
||||
{
|
||||
hw_delay(usec, TIM_USEC_DELAY);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief delay in milliseconds
|
||||
\param[in] msec: value of delay required in milliseconds
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_mdelay(const uint32_t msec)
|
||||
{
|
||||
hw_delay(msec, TIM_MSEC_DELAY);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief time base IRQ
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_timer_irq(void)
|
||||
{
|
||||
if (RESET != timer_interrupt_flag_get(TIMER2, TIMER_INT_UP))
|
||||
{
|
||||
timer_interrupt_flag_clear(TIMER2, TIMER_INT_UP);
|
||||
|
||||
if (delay_time > 0x00U)
|
||||
{
|
||||
delay_time--;
|
||||
}
|
||||
else
|
||||
{
|
||||
timer_disable(TIMER2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TIMER2_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
|
||||
usb_timer_irq();
|
||||
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief delay routine based on TIMER2
|
||||
\param[in] ntime: delay Time
|
||||
\param[in] unit: delay Time unit = miliseconds / microseconds
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void hw_delay(uint32_t ntime, uint8_t unit)
|
||||
{
|
||||
delay_time = ntime;
|
||||
|
||||
hw_time_set(unit);
|
||||
|
||||
while (0U != delay_time)
|
||||
{
|
||||
}
|
||||
|
||||
timer_disable(TIMER2);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configures TIMER2 for delay routine based on TIMER2
|
||||
\param[in] unit: msec /usec
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void hw_time_set(uint8_t unit)
|
||||
{
|
||||
timer_parameter_struct timer_basestructure;
|
||||
|
||||
timer_disable(TIMER2);
|
||||
timer_interrupt_disable(TIMER2, TIMER_INT_UP);
|
||||
|
||||
if (TIM_USEC_DELAY == unit)
|
||||
{
|
||||
timer_basestructure.period = 9U;
|
||||
}
|
||||
else if (TIM_MSEC_DELAY == unit)
|
||||
{
|
||||
timer_basestructure.period = 9999U;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
timer_basestructure.prescaler = timer_prescaler;
|
||||
timer_basestructure.alignedmode = TIMER_COUNTER_EDGE;
|
||||
timer_basestructure.counterdirection = TIMER_COUNTER_UP;
|
||||
timer_basestructure.clockdivision = TIMER_CKDIV_DIV1;
|
||||
timer_basestructure.repetitioncounter = 0U;
|
||||
|
||||
timer_init(TIMER2, &timer_basestructure);
|
||||
|
||||
timer_interrupt_flag_clear(TIMER2, TIMER_INT_UP);
|
||||
|
||||
timer_auto_reload_shadow_enable(TIMER2);
|
||||
|
||||
/* TIMER IT enable */
|
||||
timer_interrupt_enable(TIMER2, TIMER_INT_UP);
|
||||
|
||||
/* TIMER2 enable counter */
|
||||
timer_enable(TIMER2);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the PLL of USB
|
||||
\param[in] usb_periph: USBHS0 or USBHS1
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void pllusb_rcu_config(uint32_t usb_periph)
|
||||
{
|
||||
if (USBHS0 == usb_periph)
|
||||
{
|
||||
rcu_pllusb0_config(RCU_PLLUSBHSPRE_HXTAL, RCU_PLLUSBHSPRE_DIV5, RCU_PLLUSBHS_MUL96, RCU_USBHS_DIV8);
|
||||
RCU_ADDCTL1 |= RCU_ADDCTL1_PLLUSBHS0EN;
|
||||
while (0U == (RCU_ADDCTL1 & RCU_ADDCTL1_PLLUSBHS0STB))
|
||||
{
|
||||
}
|
||||
|
||||
rcu_usbhs_clock_selection_enable(IDX_USBHS0);
|
||||
rcu_usb48m_clock_config(IDX_USBHS0, RCU_USB48MSRC_PLLUSBHS);
|
||||
rcu_usbhs_clock_config(IDX_USBHS0, RCU_USBHSSEL_60M);
|
||||
}
|
||||
else
|
||||
{
|
||||
rcu_pllusb1_config(RCU_PLLUSBHSPRE_HXTAL, RCU_PLLUSBHSPRE_DIV5, RCU_PLLUSBHS_MUL96, RCU_USBHS_DIV8);
|
||||
RCU_ADDCTL1 |= RCU_ADDCTL1_PLLUSBHS1EN;
|
||||
while (0U == (RCU_ADDCTL1 & RCU_ADDCTL1_PLLUSBHS1STB))
|
||||
{
|
||||
}
|
||||
|
||||
rcu_usbhs_clock_selection_enable(IDX_USBHS1);
|
||||
rcu_usb48m_clock_config(IDX_USBHS1, RCU_USB48MSRC_PLLUSBHS);
|
||||
rcu_usbhs_clock_config(IDX_USBHS1, RCU_USBHSSEL_60M);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* BSP_USING_USB */
|
||||
Reference in new issue
Block a user