STM32H743开发板移植micropython并外扩32M的SQPI flash和32M的SDRAM


  自从去年接触到micropython后就痴迷上了它,因为它能够将python代码在单片机上运行,虽然不能支持所有的python库,但作为一般应用的电子控制系统来说已经足够了,使编程和调试效率大大提高。
  一直想自己来设计制作一套机器人控制器,对我这个有强迫症人来说,机器人主控单片机一定要选用主频最高的,Flash和RAM也要尽可以的大,虽然市面上有树莓派等高配置的开发板,但需要装操作系统,用起来很麻烦,对于简单的控制我还是喜欢跑裸机。因此我准备在正点原子的阿波罗STM32H743开发板上移植micropython,这块开发板的核心板用的是STM32H743IIT6,搭配了Winbond 25Q256 32M的QSPI flash和Winbond W9825G6KH-6 32M的16位SDRAM。
  前期已经在STM32H429DISC和NUCLEO_H743ZI开发板上移植过micropython,但总没有配置成功QSPI flash和SDRAM,最近买了OpenMV 4P,它上面已经集成好32M的QSPI和32位的32M SDRAM,也是在micropython基础上开发的,同时也看到micropython支持STM32F429DISC和STM32F7DISC开发板外部SDRAM的相关文章及源码,也就是说外扩QSPI和SDRAM从技术角度上没问题了,这为我带了希望。
  参照STM32F429DISC、STM32F7DISC开发板和OpenMV 4P的源码,经过两天照猫画虎移植试验终于成功,现将移植过程记录下来,以供大家参考:

一、搭建编译环境

.  编译环境最好是Linux系统,windows系统用户可以安装ubuntu虚拟机,安装方法参考这篇文章:《在win10的ubuntu子系统下编译micropython》
  我用的服务器ubuntu16.04环境,后续操作方法是一样的。
  还需要安装一个文本编辑器,建议安装vim,vim是linux下最好用的文本编辑器了,要用命令操作,非常高效,用命令sudo apt-get install vim安装,具体使用方法去百度吧。

二、修改源码

1.复制源码

.  在这之前一定要git好micropython源码,包括子模块。先复制一份NUCLEO_H743ZI的源码。在micropython根目录输入命令:

cd ports/stm32/boards           //进入开发板目录
cp NUCLEO_H743ZI/ MYBOARD/      //复制NUCLEO_H743ZI的源码到MYBOARD目录
cd MYBOARD                      //进入自己的开发板目录
vim mpconfigboard.h             //修改mpconfigboard.h配置文件

“MYBOARD"这个文件夹名可以改成自己想要的名字,也是将来编译时的主板名称

2.修改源码

2.1修改mpconfigboard.h文件

.  修改mpconfigboard.h配置文件,主要修改开发板名称、配置时钟参数、定义QSPI和SDRAM接口以及配置相关参数,这个配置文件支持32位的SDRAM,这块开发板上是16位的,暂时把D16~D31的注释掉,其他外设我暂时注释掉不调,后续根据需要再打开设置,修改后的mpconfigboard.h源码如下:

#define MICROPY_HW_BOARD_NAME       "MYBOARD"   //开发板名子自己随意
#define MICROPY_HW_MCU_NAME         "STM32H743"
#define MICROPY_HW_ENABLE_RTC       (1)
#define MICROPY_HW_ENABLE_RNG       (1)
#define MICROPY_HW_ENABLE_TIMER     (1)
#define MICROPY_HW_ENABLE_ADC       (1)
#define MICROPY_HW_ENABLE_DAC       (1)
#define MICROPY_HW_ENABLE_USB       (1)
#define MICROPY_HW_ENABLE_SDCARD    (0)  
#define MICROPY_HW_HAS_SWITCH       (1)
#define MICROPY_HW_HAS_FLASH        (1)
#define MICROPY_FATFS_EXFAT         (1)

#define MICROPY_BOARD_EARLY_INIT    NUCLEO_H743ZI_board_early_init
void NUCLEO_H743ZI_board_early_init(void);

// The board has an 25MHz HSE, the following gives 480MHz CPU speed
#define MICROPY_HW_CLK_PLLM (5)   //配置成480M主频
#define MICROPY_HW_CLK_PLLN (192)
#define MICROPY_HW_CLK_PLLP (2)
#define MICROPY_HW_CLK_PLLQ (4)
#define MICROPY_HW_CLK_PLLR (2)

// The USB clock is set using PLL3 ,USB的主频必须是48M
#define MICROPY_HW_CLK_PLL3M (5)
#define MICROPY_HW_CLK_PLL3N (48)
#define MICROPY_HW_CLK_PLL3P (2)
#define MICROPY_HW_CLK_PLL3Q (5)
#define MICROPY_HW_CLK_PLL3R (2)
// 4 wait states
#define MICROPY_HW_FLASH_LATENCY    FLASH_LATENCY_4


// UART config
#define MICROPY_HW_UART2_TX         (pin_A2)
#define MICROPY_HW_UART2_RX         (pin_A3)
//#define MICROPY_HW_UART2_RTS        (pin_D4)
//#define MICROPY_HW_UART2_CTS        (pin_D3)
#define MICROPY_HW_UART3_TX         (pin_B10)
#define MICROPY_HW_UART3_RX         (pin_B11)
//#define MICROPY_HW_UART5_TX         (pin_B6)
//#define MICROPY_HW_UART5_RX         (pin_B12)
//#define MICROPY_HW_UART6_TX         (pin_C6)
//#define MICROPY_HW_UART6_RX         (pin_C7)
//#define MICROPY_HW_UART7_TX         (pin_F7)
//#define MICROPY_HW_UART7_RX         (pin_F6)
//#define MICROPY_HW_UART8_TX         (pin_E1)
//#define MICROPY_HW_UART8_RX         (pin_E0)

#define MICROPY_HW_UART_REPL        PYB_UART_3
#define MICROPY_HW_UART_REPL_BAUD   115200

// I2C busses
//#define MICROPY_HW_I2C1_SCL         (pin_B8)
//#define MICROPY_HW_I2C1_SDA         (pin_B9)
//#define MICROPY_HW_I2C2_SCL         (pin_F1)
//#define MICROPY_HW_I2C2_SDA         (pin_F0)
//#define MICROPY_HW_I2C4_SCL         (pin_F14)
//#define MICROPY_HW_I2C4_SDA         (pin_F15)

// SPI
//#define MICROPY_HW_SPI3_NSS         (pin_A4)
//#define MICROPY_HW_SPI3_SCK         (pin_B3)
//#define MICROPY_HW_SPI3_MISO        (pin_B4)
//#define MICROPY_HW_SPI3_MOSI        (pin_B5)

// USRSW is pulled low. Pressing the button makes the input go high.
#define MICROPY_HW_USRSW_PIN        (pin_A0)
#define MICROPY_HW_USRSW_PULL       (GPIO_NOPULL)
#define MICROPY_HW_USRSW_EXTI_MODE  (GPIO_MODE_IT_RISING)
#define MICROPY_HW_USRSW_PRESSED    (1)

// LEDs
#define MICROPY_HW_LED1             (pin_B1)    // green
#define MICROPY_HW_LED2             (pin_B0)    // blue
//#define MICROPY_HW_LED3           (pin_B14)   // red
#define MICROPY_HW_LED_OFF(pin)     (mp_hal_pin_high(pin))
#define MICROPY_HW_LED_ON(pin)      (mp_hal_pin_low(pin))

// USB config
#define MICROPY_HW_USB_FS              (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
#define MICROPY_HW_USB_OTG_ID_PIN      (pin_A10)

// FDCAN bus
/*#define MICROPY_HW_CAN1_NAME  "FDCAN1"
#define MICROPY_HW_CAN1_TX    (pin_D1)
#define MICROPY_HW_CAN1_RX    (pin_D0)
*/
// SD card detect switch
//#define MICROPY_HW_SDCARD_DETECT_PIN        (pin_G2)
//#define MICROPY_HW_SDCARD_DETECT_PULL       (GPIO_PULLUP)
//#define MICROPY_HW_SDCARD_DETECT_PRESENT    (GPIO_PIN_RESET)


// Use external SPI flash for storage
#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0)

// QSPI Flash 256MBits
#define MICROPY_HW_SPIFLASH_SIZE_BITS   (256 * 1024 * 1024)
#define MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 (28)
#define MICROPY_HW_QSPIFLASH_CS         (pin_B6)
#define MICROPY_HW_QSPIFLASH_SCK        (pin_B2)
#define MICROPY_HW_QSPIFLASH_IO0        (pin_F8)
#define MICROPY_HW_QSPIFLASH_IO1        (pin_F9)
#define MICROPY_HW_QSPIFLASH_IO2        (pin_F7)
#define MICROPY_HW_QSPIFLASH_IO3        (pin_F6)

// block device config for SPI flash
extern const struct _mp_spiflash_config_t spiflash_config;
extern struct _spi_bdev_t spi_bdev;
#define MICROPY_HW_BDEV_IOCTL(op, arg) ( \
    (op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \
    (op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \
    spi_bdev_ioctl(&spi_bdev, (op), (arg)) \
)
#define MICROPY_HW_BDEV_READBLOCKS(dest, bl, n) spi_bdev_readblocks(&spi_bdev, (dest), (bl), (n))
#define MICROPY_HW_BDEV_WRITEBLOCKS(src, bl, n) spi_bdev_writeblocks(&spi_bdev, (src), (bl), (n))


// Use external SDRAM
#define MICROPY_HW_SDRAM_SIZE               (32 * 1024 * 1024)
#define MICROPY_HW_SDRAM_STARTUP_TEST       (1)
#define MICROPY_HEAP_START  ((sdram_valid) ? sdram_start() : &_heap_start)
#define MICROPY_HEAP_END    ((sdram_valid) ? sdram_end() : &_heap_end)
//上面两行很关键,是得到RAM起止地址的,如果没有这两行将来就只能识别到内置RAM
// Timing configuration for 240MHz/2=120MHz (8.3ns)
#define MICROPY_HW_SDRAM_CLOCK_PERIOD       2 
#define MICROPY_HW_SDRAM_CAS_LATENCY        2
#define MICROPY_HW_SDRAM_FREQUENCY          (120000) // 120 MHz
#define MICROPY_HW_SDRAM_TIMING_TMRD        (2)
#define MICROPY_HW_SDRAM_TIMING_TXSR        (8)
#define MICROPY_HW_SDRAM_TIMING_TRAS        (6)
#define MICROPY_HW_SDRAM_TIMING_TRC         (6)
#define MICROPY_HW_SDRAM_TIMING_TWR         (2)
#define MICROPY_HW_SDRAM_TIMING_TRP         (2)
#define MICROPY_HW_SDRAM_TIMING_TRCD        (2)

// 16-bit SDRAM
#define MICROPY_HW_SDRAM_ROW_BITS_NUM       13
#define MICROPY_HW_SDRAM_MEM_BUS_WIDTH      16
#define MICROPY_HW_SDRAM_REFRESH_CYCLES     8192
#define MICROPY_HW_SDRAM_COLUMN_BITS_NUM    9
#define MICROPY_HW_SDRAM_INTERN_BANKS_NUM   4
#define MICROPY_HW_SDRAM_RPIPE_DELAY        1
#define MICROPY_HW_SDRAM_RBURST             (1)
#define MICROPY_HW_SDRAM_WRITE_PROTECTION   (0)
#define MICROPY_HW_SDRAM_AUTOREFRESH_NUM    (8)
#define MICROPY_HW_SDRAM_BURST_LENGTH       1
#define MICROPY_HW_SDRAM_REFRESH_RATE       (64) // ms

#define MICROPY_HW_FMC_SDCKE0   (pin_C3)
#define MICROPY_HW_FMC_SDNE0    (pin_C2)
#define MICROPY_HW_FMC_SDCLK    (pin_G8)
#define MICROPY_HW_FMC_SDNCAS   (pin_G15)
#define MICROPY_HW_FMC_SDNRAS   (pin_F11)
#define MICROPY_HW_FMC_SDNWE    (pin_C0)
#define MICROPY_HW_FMC_BA0      (pin_G4)
#define MICROPY_HW_FMC_BA1      (pin_G5)
#define MICROPY_HW_FMC_NBL0     (pin_E0)
#define MICROPY_HW_FMC_NBL1     (pin_E1)
//#define MICROPY_HW_FMC_NBL2     (pin_I4)
//#define MICROPY_HW_FMC_NBL3     (pin_I5)
#define MICROPY_HW_FMC_A0       (pin_F0)
#define MICROPY_HW_FMC_A1       (pin_F1)
#define MICROPY_HW_FMC_A2       (pin_F2)
#define MICROPY_HW_FMC_A3       (pin_F3)
#define MICROPY_HW_FMC_A4       (pin_F4)
#define MICROPY_HW_FMC_A5       (pin_F5)
#define MICROPY_HW_FMC_A6       (pin_F12)
#define MICROPY_HW_FMC_A7       (pin_F13)
#define MICROPY_HW_FMC_A8       (pin_F14)
#define MICROPY_HW_FMC_A9       (pin_F15)
#define MICROPY_HW_FMC_A10      (pin_G0)
#define MICROPY_HW_FMC_A11      (pin_G1)
#define MICROPY_HW_FMC_A12      (pin_G2)
#define MICROPY_HW_FMC_D0       (pin_D14)
#define MICROPY_HW_FMC_D1       (pin_D15)
#define MICROPY_HW_FMC_D2       (pin_D0)
#define MICROPY_HW_FMC_D3       (pin_D1)
#define MICROPY_HW_FMC_D4       (pin_E7)
#define MICROPY_HW_FMC_D5       (pin_E8)
#define MICROPY_HW_FMC_D6       (pin_E9)
#define MICROPY_HW_FMC_D7       (pin_E10)
#define MICROPY_HW_FMC_D8       (pin_E11)
#define MICROPY_HW_FMC_D9       (pin_E12)
#define MICROPY_HW_FMC_D10      (pin_E13)
#define MICROPY_HW_FMC_D11      (pin_E14)
#define MICROPY_HW_FMC_D12      (pin_E15)
#define MICROPY_HW_FMC_D13      (pin_D8)
#define MICROPY_HW_FMC_D14      (pin_D9)
#define MICROPY_HW_FMC_D15      (pin_D10)
//如果是32位SDRAM需要设置以下端口
/*#define MICROPY_HW_FMC_D16      (pin_H8)
#define MICROPY_HW_FMC_D17      (pin_H9)
#define MICROPY_HW_FMC_D18      (pin_H10)
#define MICROPY_HW_FMC_D19      (pin_H11)
#define MICROPY_HW_FMC_D20      (pin_H12)
#define MICROPY_HW_FMC_D21      (pin_H13)
#define MICROPY_HW_FMC_D22      (pin_H14)
#define MICROPY_HW_FMC_D23      (pin_H15)
#define MICROPY_HW_FMC_D24      (pin_I0)
#define MICROPY_HW_FMC_D25      (pin_I1)
#define MICROPY_HW_FMC_D26      (pin_I2)
#define MICROPY_HW_FMC_D27      (pin_I3)
#define MICROPY_HW_FMC_D28      (pin_I6)
#define MICROPY_HW_FMC_D29      (pin_I7)
#define MICROPY_HW_FMC_D30      (pin_I9)
#define MICROPY_HW_FMC_D31      (pin_I10)*/

2.2修改stm32h7xx_hal_conf.h文件

.  接下来修改stm32h7xx_hal_conf.h文件里的外部时钟频率,修改为25M:

// Oscillator values in Hz
#define HSE_VALUE (25000000)

2.3修改pins.csv文件

.  再修改pins.csv文件里LED、按键等引脚定义,增加QSPI和SDRAM端口引脚定义,其他外设引脚暂时没设置,可根据需要修改,我修改后的文件如下:

A0	PA3
A1	PC0
A2	PC3
A3	PB1
A4	PC2
A5	PF10
A6	PF4
A7	PF5
A8	PF6
D0	PB7
D1	PB6
D2	PG14
D3	PE13
D4	PE14
D5	PE11
D6	PE9
D7	PG12
D8	PF3
D9	PD15
D10	PD14
D11	PB5
D12	PA6
D13	PA7
D14	PB9
D15	PB8
D16	PC6
D17	PB15
D18	PB13
D19	PB12
D20	PA15
D21	PC7
D22	PB5
D23	PB3
D24	PA4
D25	PB4
D26	PG6
D27	PB2
D28	PD13
D29	PD12
D30	PD11
D31	PE2
D32	PA0
D33	PB0
D34	PE0
D35	PB11
D36	PB10
D37	PE15
D38	PE6
D39	PE12
D40	PE10
D41	PE7
D42	PE8
D43	PC8
D44	PC9
D45	PC10
D46	PC11
D47	PC12
D48	PD2
D49	PG2
D50	PG3
D51	PD7
D52	PD6
D53	PD5
D54	PD4
D55	PD3
D56	PE2
D57	PE4
D58	PE5
D59	PE6
D60	PE3
D61	PF8
D62	PF7
D63	PF9
D64	PG1
D65	PG0
D66	PD1
D67	PD0
D68	PF0
D69	PF1
D70	PF2
D71	PE9
D72	PB2
DAC1	PA4
DAC2	PA5
LED1	PB1
LED2	PB0
SW	PA0
SD_D0	PC8
SD_D1	PC9
SD_D2	PC10
SD_D3	PC11
SD_CMD	PD2
SD_CK	PC12
SD_SW	PG2
OTG_FS_POWER	PG6
OTG_FS_OVER_CURRENT	PG7
USB_VBUS	PA9
USB_ID	PA10
USB_DM	PA11
USB_DP	PA12
UART2_TX	PA2
UART2_RX	PA3
UART3_TX	PB10
UART3_RX	PB11
QSPIFLASH_CS	PB6
QSPIFLASH_SCK	PB2
QSPIFLASH_IO0	PF8
QSPIFLASH_IO1	PF9
QSPIFLASH_IO2	PF7
QSPIFLASH_IO3	PF6
SDRAM_SDCKE0	PC3
SDRAM_SDNE0	PC2
SDRAM_SDCLK	PG8
SDRAM_SDNCAS	PG15
SDRAM_SDNRAS	PF11
SDRAM_SDNWE	PC0
SDRAM_BA0	PG4
SDRAM_BA1	PG5
SDRAM_NBL0	PE0
SDRAM_NBL1	PE1
SDRAM_A0	PF0
SDRAM_A1	PF1
SDRAM_A2	PF2
SDRAM_A3	PF3
SDRAM_A4	PF4
SDRAM_A5	PF5
SDRAM_A6	PF12
SDRAM_A7	PF13
SDRAM_A8	PF14
SDRAM_A9	PF15
SDRAM_A10	PG0
SDRAM_A11	PG1
SDRAM_A12	PG2
SDRAM_D0	PD14
SDRAM_D1	PD15
SDRAM_D2	PD0
SDRAM_D3	PD1
SDRAM_D4	PE7
SDRAM_D5	PE8
SDRAM_D6	PE9
SDRAM_D7	PE10
SDRAM_D8	PE11
SDRAM_D9	PE12
SDRAM_D10	PE13
SDRAM_D11	PE14
SDRAM_D12	PE15
SDRAM_D13	PD8
SDRAM_D14	PD9
SDRAM_D15	PD10

2.4修改board_init.c文件

.  打开board_init.c文件增加QSPI flash需要的头文件和配置函数,注释掉USB_PowerSwitchOn这几行,这是NUCLEO_H743ZI开发板的OTG电源开启代码,可以把这个函数删掉,同时要把mpconfigboard.h文件里的这两行注释掉或删除:

#define MICROPY_BOARD_EARLY_INIT    NUCLEO_H743ZI_board_early_init
void NUCLEO_H743ZI_board_early_init(void);

我这里先保留函数,以后有啥初始化的代码可以放在这里。代码如下:

#include "py/mphal.h"
#include "qspi.h"
#include "storage.h"
void NUCLEO_H743ZI_board_early_init(void) {
    // Turn off the USB switch
    //#define USB_PowerSwitchOn pin_G6
    //mp_hal_pin_output(USB_PowerSwitchOn);
    //mp_hal_pin_low(USB_PowerSwitchOn);
}
char _ffs_cache;
STATIC const mp_soft_qspi_obj_t qspi_bus = {
    .cs  = MICROPY_HW_QSPIFLASH_CS,
    .clk = MICROPY_HW_QSPIFLASH_SCK,
    .io0 = MICROPY_HW_QSPIFLASH_IO0,
    .io1 = MICROPY_HW_QSPIFLASH_IO1,
    .io2 = MICROPY_HW_QSPIFLASH_IO2,
    .io3 = MICROPY_HW_QSPIFLASH_IO3,
};
const mp_spiflash_config_t spiflash_config = {
    .bus_kind = MP_SPIFLASH_BUS_QSPI,
    .bus.u_qspi.data = (void*)&qspi_bus,
    .bus.u_qspi.proto = &qspi_proto,
    //NOTE: The FFS cache is not used when QSPI is enabled.
    .cache = (mp_spiflash_cache_t *) &_ffs_cache,
};
spi_bdev_t spi_bdev;

2.5修改sdram.c文件

.  另外,要STM32H7支持SDRAM还需修改ports/stm32下的sdram.c文件,这也是最关键的一步,在static void sdram_init_seq(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *command)初始化序列函数里(244行)找到#if defined (STM32F7)改为:

#if (defined(STM32F7) || defined(STM32H7))   //增加对STM32H7的支持

.  目的是让初化序列后设置SDRAM的起始地址,如果没有这一步骤将来只能看到内置的RAM,我之前一直没成功就差在这个步骤上。

三、编译源码并测试

1.编译源码

.   至此源码已经修改完成,接下来就开始编译下载测试。回到micropython根目录,输入下面命令开始编译源码:

make -C ports/stm32 BOARD=MYBOARD

.  编译结束后会在ports/stm32/build-MYBOARD文件夹下得到firmware.dfu、firmware.hex等固件文件,hex文件可以用ST-Link下载器下载到芯片里,我选择dfu模式下载,只需要用USB线即可。将这几个文件传到电脑桌面上,虚拟机里传文件到本机windows电脑里的方法参照前面搭建编译环境里的链接文章。

2.下载固件

.  打开DfuSe Demo软件(如果没有这个软件可以另外下载安装),拔下BOOT0的路线帽,用杜邦线将阿波罗STM32H743开发板的RST和BOOT0连在一起再开电,插上USB线进入DFU下载模式。点Choose选择刚才传过来的firmware.dfu固件文件,再点Upgrade下载到芯片里。
在这里插入图片描述
在这里插入图片描述

.  下载结束后关掉电源,将RST和BOOT0的路线去掉,插上BOOT0和GND的路线帽,再用一根杜邦线将3.3V和PA9引脚相连,这是插入USB线的识别端口,也可以在mpconfigboard.h文件里的USB config中修改。
在这里插入图片描述

// USB config
#define MICROPY_HW_USB_FS              (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)  //这里可以改为其它端口
#define MICROPY_HW_USB_OTG_ID_PIN      (pin_A10)

3.上电测试

.  下一步插上USB线连接到电脑上会出现一个32M容量虚拟磁盘PYBFLASH,写的python代码就可以存入boot.py和main.py运行了。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  另外在设备管理器里能看到有一个虚拟串口:Pyboard USB Comm Port(COM_X),这个串口名称是可以自己修改的,在虚拟磁盘的pybcdc.inf里最下面找到

DESCRIPTION="Pyboard USB Comm Port"

.  修改成自己想显示的内容,然后更新驱动程序选中刚修改的那个文件即可。
  再来测试SDRAM扩展成功没,用SecureCRT软件连接,配置好串口参数,在REPL里输入:

import pyb,gc
pyb.info()

回车能看主板信息:
在这里插入图片描述
输入:

gc.mem_free()

.  能看到SDRAM剩余32M内存容量,说明SDRAM扩展成功。
  至此,STM32H743移植micropython并扩展32M QSPI Flash和32M SDRAM全部成功,micropython板其他功能大家自己去玩吧。
  版权声明:本文未经本人同意不得转载或用于其它目的

  • 9
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值