eCos学习笔记

作者tag: ecos  s3c44b0x CSDN 推荐tag: c#  arm  redboot  hal 
<script type="text/javascript">function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</script>


ecos port to s3c44b0x 总结

WinMe + cygwin + gcc 2.95.2 + ARM s3c44b0x (21ic Study Board)

Board:  2Mbytes flash (startaddress 0)
        8Mbytes sdram (startaddress 0x0c000000)
        second uart , first uart not use

还没有最后完成,目前还有一些问题。写此文的目的一是帮助
初学者快速入门,另外也是寻求帮助,还有就是自我总结。

所有软件都假定安装在e盘

1、cygwin
   默认下载不包括GCC,要选DEVEL下的一些工具。
   
2、ecos2.0bl  
   从sources.redhat.com/ecos下载,或者从它的FTP下载。
   执行Tools/Bin/Platforms.reg即可,无须安装。
   为EcosConfigTool创建桌面图标,运行它。提示指定Packages
   目录,也就是ECOS目录:e:/ecos-2.0b1。这也可以在菜单
   Build/Repository中设置。还要设置Tools/Paths/User Tools
   为e:/Cygwin/bin。
   
3、gcc2.95.2 + Insight5.0
   从sources.redhat.com/ecos下载,或者从它的FTP下载。
   安装严格按照网站上说明。注意:如果你在autoexec.bat
   中设置了tmp或temp等,要把它去掉,再重启动。
   EcosConfigTool设置Tools/Paths/Build Tools为
     E:/cygwin/tools/H-i686-pc-cygwin/bin
   
4、cygwin设置
   cygwin中运行mount,会显示一些信息。
   mount有binmode和textmode,ECOS不支持binmode,
   最好把它们都改成textmode。否则ECOS编译怎么都通过不了,
   到时不要说ECOS有BUG啊。
   注册表中,HKEY_LOCAL_MACHINE/Software/Cygnus Solutions/Cygwin/mounts v2
   可以看到MOUNT的东西都在此,将其flags从0x10改成8就可以了。
   
5、port s3c44b0x
   4510和44b0应该是最接近的,所以从E7T改最方便。
   建立packages/hal/arm/study目录
   拷贝packages/hal/arm/e7t目录下的东西。
   建立packages/devs/serial/arm/study目录(串口驱动,redboot不用)
   拷贝packages/devs/serial/arm/e7t目录下的东西。
   按照E:/ecos-2.0b1/doc/html/ref/hal-porting-platform.html
   提示修改。
   
   study目录结构如下:
      cdl        ---------   hal_arm_study.cdl        CYGNUM_HAL_ARM_study_CLOCK_SPEED
                                  改成60000000时钟频率
     
      include    ---------   pkgconf  -------        6个存储空间配置文件
                             hal_cache.h          cache配置,少许修改
                             hal_diag.h            不用动
                             hal_platform_ints.h    中断配置,中断在寄存器中
                                             对应的位,ADC为0,EXT0为25
                             hal_platform_setup.h    CYGHWR_LED_MACRO灯指示,可以为空的宏
                                             PLATFORM_SETUP1很重要,硬件初始化都在这儿
                             plf_io.h            IO口名称,麻烦事儿
                             plf_stub.h            不用动
                             
      misc    ----------   需要哪些包,在此说明                            
     
      src       ----------   flash_cksum.tcl        不用动
                       hal_diag.c            redboot用这些函数和GDB通讯
                                       SIO_BRDDIV计算方式变了。
                                       UART_LCON和4510有差异。
                                       hal_diag_led做成空的算了
                       redboot_module.c        不用动
                       study_misc.c        hal_clock_initialize,ECOS的
                                       TICK就是用它初始化的。4510定时器32为,
                                       44b0是16位,需要点技巧。
                                       hal_delay_us好象REDBOOT用了一下,调试
                                       REDBOOT时可把它屏蔽掉,第一条语句为return.
                                       hal_IRQ_handler寻找是那一个中断。
                                       hal_interrupt_acknowledge清I_ISPC

6、redboot
   菜单Build/Templates hadeware选arm-study packages选redboot  
   设置ecos hal --> arm arckitecture --> arm study evalution board :
             startup type                :  RAM/ROM   启动方式
             debug serial port                :  0/1         串口
             console/gdb serial port baud rate        :  115200    波特率
             cpu clock speed                :  60000000  时钟频率
             real-time clock constants
                   -----  real-time clock denominator    : 100         TICK为100HZ
                   -----  real-time clock period                 自动计算          

   最开始调试REDBOOT,选RAM方式较好,这时可以用SDT/ADS进行调试。
   hal_platform_setup.h / PLATFORM_SETUP1 此时最好去掉下句:
      #if defined(CYG_HAL_STARTUP_ROM) || defined(CYG_HAL_STARTUP_ROMRAM)
   这样就可以RAM方式也调用PLATFORM_SETUP1进行初始化硬件了。
   redboot.bin是从hal/arm/arch/v2_0b1/src/vectors.S --> reset_vector处
   开始执行。可以看到LED 7 --> LED 1 将初始化分割成几段,由于是反汇编调试,
   我们可以从LED ?看出执行到哪儿来了。
   初始化完后会调用redboot/v2_0b1/src/main.c --> cyg_start,这时候会显示
   一些信息。注意它会调用study_misc.c --> hal_delay_us函数,刚开始可以将
   此函数第一条语句写成return,等redboot信息显示出来后再调试此函数。
   RAM方式调试OK后,再作成ROM方式,烧到FLASH中。

7、ecos library
   菜单Build/Templates hadeware选arm-study packages选default
   设置ecos hal --> rom monitor support --> enable use of virtual vector table
           --> Initialize whole of virtual vector = true
   如果不设置它,printf会死掉,不知道为什么,它还不是默认的,我花了大半天才试出
   来的。
   设置ecos hal --> arm arckitecture --> arm study evalution board :
           -->  startup type =  RAM
   注意:redboot已经占用了一些RAM了,mlt_arm_study_ram.ldi中SECTION_rom_vectors
   应该为0x0c100000,而不是0x0c000000,否则会和redboot冲突(自我理解)。
   菜单Build/Library生成ECOS库。暂时不要用Build/Tests,太慢了。

8、application
   编写一个hello程序。
   编写一个编译文件。
   arm-elf-gcc -g -Wl,-Map,mapfile -I/ecos-e/ecosprj/ecoslib_install/include hello.c
        -L/ecos-e/ecosprj/ecoslib_install/lib -Ttarget.ld -nostdlib
  说明:ecos-e其实就是e盘。
        ecosprj刚才的库就放在这儿了。
        ecoslib_include  ecoslib_install :ecoslib是建库时的名称。
        -Wl,-Map,mapfile : -Wl是传参数到linker,-Map,mapfile产生mapfile文件,可以看看
                            你的函数、变量对应的地址。
 
  然后会生成a.out  ELF文件,大概1M多吧。
    (可以用arm-elf-objcopy -O binary a.out a.bin  转换格式,几十K而已。)
 
  执行arm-elf-gdb -nw a.out。我的Insight不知道怎么启动不了,只好用命令行了。
      set remotebaud 115200
      target remote /dev/ttyS0    返回一些内容,例如:0x2ffc ??()
      load              下载程序,有点慢哦。
      break main          设置断点
      cont              开始执行
      step              可跟踪进入函数
      next              逐行执行

9、tests
   菜单build/tests编译一个多小时(C433),会生成一堆exe文件,但是不知为什么ECOS不认,
   将一些exe文件扩展名去掉,一点一点测试吧。
   tools/platforms从e7t拷贝成study
   tools/run tests会提示没有编译完全,选NO不理它。慢慢测试吧
   
10、问题
   我测试时发现有很多不能通过,大多跟时间有关,后来发现s3c44b0x有INTCON控制irq/fiq,
   而4510没有,改了之后发现GDB中break main , cont,怎么也不会执行到main处,死掉了。
   但是break cyg_start,cont,没有问题,然后用step一条一条执行却完全可以到main,而且
   main运行没有问题。但是时间计数器依然没有记数,定时器intpnd置了位,intmsk已经清零,
   但是就是没有中断发生。
   哪位大虾帮帮忙吧,愿意研究ecos port to s3c44b0x的,可以向我索要测试未完全通过的
   程序,只想要结果的,等解决问题之后再上传。
   

以上很多是自我理解,可能不对,如有错误请指出。

ecos port to s3c44b0x 总结 (二)
ecos port to s3c44b0x 总结 (二)
于成功实现了移植工作,上次留下的问题也解决了(上载区不能用,没法上传)。

上次是中断出了问题,所以所有和时间方面的函数都不能通过。这主要是因为
ecos默认零地址是ram,应用程序执行时,首先执行Vectors.S,此函数将处于
ram中的中断向量改成指向自身,中断就可以正常工作了。而我的板上零地址
是FLASH,没有办法更改,才造成中断就死机。

为此将Vectors.S改动如下:

        .global __exception_handlers
__exception_handlers:
        ldr     pc,.reset_vector                // 0x00
        ldr     pc,.undefined_instruction       // 0x04
        ldr     pc,.software_interrupt          // 0x08
        ldr     pc,.abort_prefetch              // 0x0C
        ldr     pc,.abort_data                  // 0x10
        .word   0                               // unused
// 改动
#ifdef CYG_HAL_STARTUP_RAM
        ldr     pc,.IRQ                         // 0x18
        ldr     pc,.FIQ                         // 0x1C
#else
        ldr     pc,=0x0c100018
        ldr     pc,=0x0c10001c
#endif       

        .global vectors
vectors:
    UNMAPPED_PTR(reset_vector)              // 0x20
    PTR(undefined_instruction)              // 0x24
    PTR(software_interrupt)                 // 0x28
    PTR(abort_prefetch)                     // 0x2C
    PTR(abort_data)                         // 0x30
        .word   0                               // 0x34

// 改动
#ifdef CYG_HAL_STARTUP_RAM
    PTR(IRQ)                                // 0x38
    PTR(FIQ)                                // 0x3c
#else
    .word 0x0c100038
    .word 0x0c10003c
#endif       

(我们假设没有RAM_ROM方式)
上面的程序有两个地方判断CYG_HAL_STARTUP_RAM。
当定义了CYG_HAL_STARTUP_ROM时,中断向量指向0x0c1000??,上次已经讲过,
Ram中的程序放在0x0c100000处。这样irq/fiq发生时,先跳到0x000000??,再
转移到0x0c1000??,就转移到了你的应用程序的向量区,中断就能正常工作了。
当定义了CYG_HAL_STARTUP_RAM时,中断向量指向自身中断服务程序。中断发
生时,已经从rom处跳到了ram区应用程序的中断向量区,现在就可以跳到中断
服务程序处了。

学习ecos我们首先要使redboot工作,redboot可以配合arm-elf-gdb调试你的
应用程序。redboot一般不使用中断,所以我们可以把它的BIN文件放到RAM中
调试,调试可以用ADS/SDT等工具,其实也就是调试vectors.S。redboot提示
信息,你输入help命令如果有反映,redboot应该就没有问题了。接下来就可
以把redboot放到rom中零地址处,这时irq/fiq指到了0x0c1000??,也就是你
的应用程序。因此有两次Build过程,第一次选RAM,第二次选ROM。第一次要
注意:
文件 hal//arm//study//v2_0b1//include//hal_platform_setup.h

#if defined(CYG_HAL_STARTUP_ROM) || defined(CYG_HAL_STARTUP_ROMRAM)
#define PLATFORM_SETUP1
....

只有定义ROM方式才会定义PLATFORM_SETUP1,PLATFORM_SETUP1是初始化硬件
的,此时你的ROM未必有程序初始化硬件,所以最好刚开始无论ram/rom方式
都定义PLATFORM_SETUP1。等redboot for ram调试好再改回来。

现在板上FLASH有了redboot,我们快要可以编程序用它进行调试了。不过编
程序前你得先建好库(假设命名ecoslib)。
Build//Templates选ARM Study board + default,redboot在ROM中,应用程序
当然要在RAM中了。然后Build//Library,现在就可以编程序,用arm-elf-gdb
可以进行源程序调试。
你编写的hello程序如果工作正常,就可以开始完整的测试了,Build//Tests,
很长时间之后,就编译出了EXE程序,Tools//Run Tests进行测试。
vectors.S只是把irq/fiq指向了RAM,其它异常没有,所以except1和kexcept1
不能通过,我现在还没相好要不要把其它异常也指向RAM,以后再说吧。
另外就是测试时每测一个程序后出现提示确认是否复位,这时候要将板复位或
断电->上电,再按确认。其实测试完一个程序后GDB会发给一个BREAK包给
redboot,如果你建redboot时选了ecos hal//source level debugging support//
include gdb ecternal break support for stubs,这时redboot会有一个中断
程序监视串口,一接收到BREAK包就自动复位。但是现在中断指向了RAM,所以
只好手动复位了。(自我理解)

让你的产品带个redboot,好象不太好吧,我们还得建个库(假设命名applib)。
这时候vectors.S要还原,我们要建立ROM程序,但不是redboot,中断向量要指向
自己。和上面ecoslib编译过程一样,但要选ROM,不需要测试了(也测试不了)。
把你的应用程序和这个库再编译一次,生成的程序用arm-elf-objcopy转成bin,
然后烧到ROM,不要redboot应用程序也一样工作。



最后:
去掉redboot for ram,我们现在有了三个库;
1、redboot for rom    将bin文件写入FLASH就可以不管它了。
2、ecoslib        应用程序和它编译,生成的程序放在RAM,用于调试。
3、applib        应用程序和它编译,生成的程序放在ROM,用于发行。

我们有两个Vectors.S,一个用于redboote和ecoslib,另一个用于applib。

注意:
1、WallClock是用定时器模拟的,以后再编个驱动程序吧。
2、我的库里面没有加入tty、ser0、ser1等,测试可能是不完全的。
3、没有加入FLASH工具,redboot没有此命令。
4、串行口驱动程序不能肯定完全测试过。

问题:
1、测试时需要手动复位,还不敢肯定其原因。
2、由于ecos老认为零地址是RAM,vectors.S会进行写入操作,现在零地址是
   ROM,反正也写不进去。ecos带的platforms零地址都是RAM,我不知道别人
   是怎么处理此问题的。
3、vectors.S中,使用了 .section ".fixed_vectors"
   英文说明:
       "Vectors" - fixed location data items
       This section contains any data which might be shared between
       an eCos application and any other environment, e.g. the debug
       ROM.                       
   可能用于redboot和应用程序通讯的,要求ldi文件不管是ROM还是RAM,
   fixed_vectors地址要相同。我本来以为可解决中断问题,但是不行,不知道
   它是干什么的。

ecos port to s3c44b0x 总结 (三)    MiniGUI移植
有了操作系统,要是没有GUI也挺没意思,所以我在移植GUI上下了一些功夫。
其实ecos带了一个MicroWindows,是用于SA11X0的,不过目前只支持16位色,
改成256色问题不会太大。我把它用到S3C44BOX上,编译了一个DEMO程序,大
概BIN文件是800多K吧,记不清了,至少是这么多。后来发现MicroWindows没
有菜单,感觉控件支持确实少了点。难怪有人说MicroWin偏重底层,MiniGUI
偏重界面了。不过现在有人将FLTK移植到了MicroWin,控件应该不是问题,
FLTK带了60多个控件呢,只是麻烦了点。ecos带的MicroWin没有中文支持,
想想还是算了,干脆转向MiniGUI。
以前知道一些MiniGUI,还在REDHAT上装了一次,初步了解了它的结构。它是
基于消息的,有WIN32接口,目前有Thread和Lite版,代码90%以上相同,而
早期版本是Thread的,新版本两套都有。MiniGUI抛弃了传统的C/S结构,而使
用线程,因此速度快了许多。但线程会引起不稳定,因此Lite版又使用微C/S,
也就是少量数据通过C/S,大量数据还是通过线程,所以在速度和稳定性上折中
了。
由于MiniGUI用到了大量的LINUX特性,而ecos还不能算是LINUX,所以移植工作
不可能一帆风顺。新版的MiniGUI同时具有Thread和Lite,无疑增加了复杂度,
所以我选择了较早版本。要知道早期MiniGUI就是应用于数控机床的,只是随着
它的发展,有点逐步脱离嵌入式应用的迹象,而和桌面系统越来越融合了。
www.minigui.org上除了早期的DOS版,也就是0.9.96最老了,好象它还是最后
一个thread版,就是它了。
首先我们要准备ECOS库,选择posix模板,为后面的编译工作准备*.h文件。
下载:    libminigui-0.9.96.tar.gz    源程序
   minigui-fonts-0.9.96.tar.gz    字库
   minigui-imetabs-0.9.96.tar.gz    输入法
   minigui-res-0.9.96.tar.gz    资源文件
   miniguiapps-0.9.96.tar.gz    DEMO
   
要修改的也就是libminigui文件SRC目录的内容,共12个目录:
   control        控件实现,基本不需修改
   font        字库支持,基本不需修改
   gal        图形抽象层,要修改
   gdi        图形设备接口,基本不需修改
   gui        图形用户接口,基本不需修改
   ial        输入抽象层,要修改
   image        各种图形文件格式实现
   ime        输入法接口
   include       
   kernel        核心:初始化,输入输出处理
   main        main函数
   misc        ETC文件处理函数等等
   
我们要处理的是C文件,大约100个。
   dir *.c /s /b > Makefile
将目录底下的C文件名全部放到文件Makefile中,省得输入了。然后在各个文件名
前面加上arm-elf-gcc -c 和一些选项,注意要指向ECOS库头文件所在目录,稍加
修改成为一个makefile类型文件。运行make看看结果,完全通过的用#注释或删除。
这样要编译的文件就会逐渐减少。没有编译通过的记录原因,一般都是头文件找不
到。MiniGUI用到了大量的头文件,有很多是不需要的,例如:
   sys/mman.h    sys/io.h    sys/kd.h    sys/param.h
   linux/keyboard.h    
sys/times.h    用 times.h     代替
malloc.h    用 stdlib.h     代替
去掉一些头文件引用后,又会有一些文件编译通过。最后通不过的也就是ECOS不具
有的函数,我们需要用其它的函数替换。
   1、kernel/time.c    没有setitimeval函数,我只好创建了一个myTimerThread
                   线程,每隔一个tick发送一个消息。我对linux/ecos编程
                   还不是太熟,不知道还有没有更好的方法。
   2、kernel/init.c    没有gettimeofday函数,用cyg_current_time替代。
               没有pthread_kill_other_threads_np,估计是杀掉其它线
               程吧!不知道嵌入式系统是否还需要经常关闭GUI,先放一
               边吧,如果确实需要,就加入kill线程desktop、parsor、
               timer、mytimer。
   3、mywindow/filedlg.c     没有lstat,用stat替代。没有getpwuid,直接用
               “/”目录替代。
   4、misc/misc.c    修改LookForEtcFile函数,只在"/etc/"目录寻找MiniGUI.cfg。
               去掉tone函数。
               SetvalueToEtcFile函数中调用tmpfile,只好用rand算出一个
               tmpfile。还要注意这是romfs不能写的,所以只是实现了功能。
               要想用的话,还要加入其它fs.
   5、ial/native/native.c    去掉set_leds。
   6、gal/native/native.c    去掉关于vtswitch所有部分。嵌入式控制系统不需要
               虚拟控制台。
   7、config.h        控制编译的选项。
   
其实这些工作5.1时就差不多完成了,非典时期的假期只好呆在屋里移植minigui了。只是
后来两个月实在有些忙,我是做IC设计的,公司接了几个大定单,只好把这事放一边了。
现在都忘记了当时改了些什么,上面几条是当时记录的,可能还有没记下来的。
然后加入GAL/IAL。刚开始调试程序,IAL就不要加了,先把图形显示出来再说。由于0.9.96
版本驱动太少,所以我又从以前下载的1.2.1中拷出来了一些。IAL就用Dummy_IAL,GAL要自
己改。s3c44b0x.c就是我修改得来的,目前支持16级灰度和256色。
s3c44b0x GAL驱动说明:
   1、s3c44b0x_internal.h    定义LCD大小、颜色
   2、s3c44b0x.h        两个全局函数引用
   3、s3c44b0x.c        驱动
         FrameBuffer:两种定义方式,一种用数组,编译器决定地址;另一种自己定义地
         址。自己定义地址用于调试初期,这时候不需要LCD显示屏,用SDT/ADS运行BIN文
         件,然后从FrameBuffer的地址中取出显示数据。假设我们要调试256色驱动,LCD
         为320X240,可以先用windows的画图存一个颜色、尺寸一样的文件,然后把取出的
         显示数据用ULTRAEDIT替换该图形文件的数据,注意BMP存放数据是倒着存放的,因
         此还要作个X翻转。这样我们就无须LCD就可以调试了。16级灰度方法一样。
         如果用数组,要注意对齐,首先要半字对齐,其次还要不能跨越4M空间。
        
         initlcd:硬件初始化。我的44B0板是3.3v,但LCD屏是南亚5V的,因此在中间加了
         74HC14施密特非门,LCDCON1要设置反相位。由于系统是小端的,LCDSADDR2的BSWP
         要置位。PDATC的b15位控制ON/OFF。
        
所有的C文件都能单独编译后,就可以开始加到ECOS里了。做个简单的CDL文件,一个minigui
模板,就可以开始编译库了。
我们还要准备rom文件系统,minigui需要一些文件:配置、图形资源、字库、输入法等等。
我把它们都放到了romfs目录下:
   mk_romfs.exe    将romfs目录转化成BIN
   file2c.tcl    将BIN转化成H文件
   gen        批处理,从目录直接到H文件
   romfs        数据目录
       etc    配置文件
       fonts    字库
       ime    输入法
       res    
           app    应用程序的资源:bomb/notebook
           ...
romfs有两种方式。一种是直接烧到FLASH固定地址,另一种作成数组放到H文件,由编译器决定
地址。我选后一种,方便调试,不过做产品时烧到FLASH好一些。数组大了编译慢,传起来也麻
烦。各有优缺点吧!
现在可以编译bomb/notebook调试了。
图象显示正确后,就要加入IAL输入驱动了。我编了一个PCSIM模拟驱动,上位机用VB5编写,在
框内移动/按下鼠标,程序会从串口发送数据,格式为:
   鼠标:    1LMRxxyy   0xxxxxxx  0yyyyyyy
   键盘:    11111111   0000000k  0kkkkkkk
pcsim.c从串口读数据,确定鼠标位置。目前只对鼠标处理,键盘麻烦了点,还没管它。
注意read读数据是non-blocking的,因此要选:
serial device drivers/
   support non-blocking read and write calls
   hardware serial device drivers  波特率设置成9600,VB5不支持高速的
打开"/dev/ser0"    要用O_NONBLOCK方式。
romfs的配置文件要改,H文件要重新生成,config.h要修改。
重新编译bomb,可以开始扫雷了!
bomb.bin    767k
通过mapfile估计:    
bomb         20k
minigui        270k
ecos        100k
romfs        330k    宋体12X12,没加输入法
如果不算汉字库,只有400K,不到MicroWindows的一半。
不足之处:
1、minigui定义了17种系统颜色,所以我用单色屏作了16级灰度,但效果很糟糕。可能用4级灰度
  说不定要好一些,反正一个应用程序也不会用那么多颜色的。
2、44B0X显示空间4M为一BANK,FrameBuffer不能卡在4M地址上。解决这一问题有两种方法:分配
  两倍空间:FrameBuffer[2][MAX_X*MAX_Y/8*PIXELBPP],FrameBuffer[0]、FrameBuffer[1]总有
  一个不会卡在4M地址上;动态两次分配,第一次malloc后如果发现此问题,则再分配一次,然
  后释放前一次分配的空间。我没试过。
3、速度有些慢。我用的是21ic上买的学习板,它把存储器接成16位的,系统性能肯定会降低很多,
  鼠标移动时它的箭头有点闪,bomb新游戏开始时刷新屏幕都可以看得到过程。谁接成32位的可以
  看看速度怎么样。
此移植未做完全测试,请小心使用,本人不负任何责任。
wen_jian_1973@163.com

 

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1480563

 
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值