搜索
bottom↓
回复: 20

基于Beaglebone Black学习ARM-LINUX嵌入式系统之二——JTAG调试

[复制链接]

出150入640汤圆

发表于 2019-8-11 16:12:37 | 显示全部楼层 |阅读模式
本帖最后由 dragonlands 于 2019-8-11 16:14 编辑

第6章JTAG调试
本章节将介绍如何使用TI官方的CCS开发工具及XDS100V2仿真器连接龙泉BB板的JTAG接口进行软件调试。
5.1  准备工作
一、准备硬件:龙泉BB板一块,5V电源适配器,XDS100V2仿真器(也可以用其它的型号的仿真器,如JLINK、XDS100V3、XDS560、Hawk等等,但目前只测过XDS100V2,推荐用这个型号),USB转UART线。请将SD卡启动跳线短接,连接好所有线缆(龙泉BB板上是JTAG接口是20PIN,XDS100V2的接口是14PIN,请按原理图一一对应接上,余下的6PIN不用连接)。
二、准备软件:CCS5.5(也可以用更高版本,但作者只亲自测试过5.5版),AM335x的Startware及BBB的patch。建议WINDOWS版和LINUX版都安装。安装程序自带XDS100V2的驱动程序,无需另外安装。如需要调试u-boot,请自行准备LINUX开发环境。
WINDOWS下安装好后示例代码如下图:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg
5.2 Startware中的BBB示例代码调试。
打开CCS,把CCS的Workspace切换到以下目录:D:\program\ti\am335x\build\armv7a\cgt_ccs\am335x\beaglebone
以gpioLEDBlink为例,工程属性设置如下图。
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image004.jpg
图:工程属性设置
请注意上图中的编译器版本改为V5.1.1,connection即是仿真器,改为xds100v2,板子改为beaglebone_black(cortex A)。此处若选Cortex-M,可能是用来调试其中的PRU。检查并更正include路径,检查并更正lib路径。注意此工程需要四个库:system,utils,drivers,platform(先import和编译这几个库)。
Build完毕,debug as CC debug session即可开始调试,光标定位在main()第一行。如下图:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image006.jpg
按F6单步运行,运行到下图位置,蓝色LED D4会变亮。
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image008.jpg
再往下运行,此灯会灭。
5.3 u-boot调试。
u-boot调试比较复杂。一般来说,应该安装linux版的CCS进行调试,然而,跨平台的CCS也支持用WINDOWS版CCS调试LINUX主机里面的u-boot。两种方式都需要用LINUX主机去编译u-boot。也许可以用cygwin在WINDOWS下编译,但需要修改makefile,非常麻烦,故而不推荐这种方式。
5.3.1 龙泉BBB的LINUX启动过程
AM335xLinux的启动主要包括ROM,SPL, U-Boot 和kernel四个启动步骤:
一、ROM code
ROMcode是固化在芯片内部的代码,当上电时序正确,而且晶振等芯片启动所需的条件都具备时,AM335x会从ROM code开始运行。
ROMcode首先会读取sys_boot引脚上的配置,以确定存放SPL的存储器,或者可以获取SPL的外设。
具体可以参考AM335x technical reference manual中的第26章 Initialization。
ROMcode会从相应的地方读取/获取SPL,并运行SPL。
二、SPL
SPL和U-Boot 是bootloader的两个阶段。这里分为两个阶段的原因是, ROMcode中不会配置DDR,时钟等最小系统,所以ROM code只能把bootloader加载到片上SRAM中,而片上SRAM对成本影响很大,所以通常很小,例如在AM335x上只有64K,不足够放下整个U-Boot,所以将U-Boot分成两部分,SPL和U-Boot。
SPL主要的职责就是初始化DDR,时钟等最小系统,以读取U-Boot,并加载到DDR中。具体来看,SPL 由ROMcode加载到片上SRAM的起始位置,也就是0x402F0400。SPL会进一步对芯片进行配置,主要包括以下几个方面以完成其主要职责:
Ø  配置ARM core。 主要包括对中断向量表,cache,MMU等的配置。
Ø  配置时钟系统,主要是PLL等。这个是配置各个功能模块的基础。
Ø  配置UART,timer等。主要用于输出必要的调试信息,或者提供些时钟工具。
Ø  配置I2C和PMIC。这个主要是为了配置电源管理芯片。
Ø  配置DDR。
Ø  配置 U-Boot所在的存储器或者外设。
完成配置后,SPL会读取U-Boot,并运行U-Boot。
三、U-Boot
U-Boot主要的工作就是正确加载Kernel。和SPL类似,U-Boot也是要加载下一个阶段的image,但是U-Boot提供了更多外设的支持和更多的调试工具。所以,U-Boot也要进行各个模块的配置,上述SPL配置的部分, 除了DDR外,U-Boot也会根据需求重新配置(这里重置主要是U-Boot是一个开源工程,其要兼容某些特殊的芯片,从而需要做重载)。此外,U-Boot也会对网口,SD卡等根据需求进行配置。
U-Boot和SPL的工作流程比有一点是有较大差异的,就是会对自身进行一次重载。这个在后面介绍U-Boot调试的时候,会有具体介绍。
完成配置后,U-Boot 会从相应的存储器或者外设读取Kernel,并传递参数给kernel,运行kernel。
四、Kernel
Kernel运行起来就代表Linux运行起来了,表明了启动过程的结束。
1.2           U-Boot/SPL 调试代码的准备
1.2.1下载U-Boot/SPL 代码
U-Boot/SPL的代码在一个包里面,通过编译宏来分别编译。目前TI U-Boot/SPL 代码发布主要有两个渠道,具体如下
A.   通过Git开源的方式发布:
git://arago-project.org/git/projects/U-Boot-am33x.git
可以获取最新的代码,包含了最新的bug的修复。
B.   通过TI的官网的EZSDK发布:
http://software-dl.ti.com/dsps/dsps_public_sw/am_bu/sdk/AM335xSDK/latest/index_FDS.html
EZSDK是正式发布的软件包,经过全面测试,性能稳定,U-Boot/SPL在board-support 目录中。可以选择EZSDK作为开发的基础代码。当有问题时, 可到GIT上查找最新的代码是否有bug fix。
5.3.2 U-Boot/SPL的编译
为了便于用CCS进行调试, 在编译上需要注意两点,其一,是要加入调试信息,就是为了加入symbol等信息;其二,去掉编译器的性能优化编译选项,这个主要是因为,优化后的代码执行顺序相对C代码会有调整。
针对这两点,在Uboot/SPL中,需要在config.mk中进行修改:
A.   在CFLAG 和 AFLAG中加入调试编译选项,从而加入调试信息:
278ALL_AFLAGS = $(AFLAGS)$(AFLAGS_$(BCURDIR)/$(@F)) $(AFLAGS_$(BCURDIR))–g
279ALL_CFLAGS = $(CFLAGS)$(CFLAGS_$(BCURDIR)/$(@F)) $(CFLAGS_$(BCURDIR))–g
B.   去掉 CFLAG中的编译选项, -O2(U-Boot中默认是-O2)
61HOSTCFLAGS  =-Wall-Wstrict-prototypes -fomit-frame-pointer
5.3.3 可执行文件
经过编译后,就会生成可执行文件,也就是我们通常所说的image,这里会生成的image主要用AM335xLinux启动的两个阶段,MLO(SPL)和U-Boot。
这里,SPL生成的image在am335x/U-Boot-am33x/am335x/spl中,
A.  am335/U-Boot-am33x/MLO 负责AM335x启动的第一阶段。
B.  U-Boot-spl 作为带有调试信息的image,可以在CCS中用作导入调试信息。
C.  U-Boot-spl.bin 包含有调试信息,是调试时需要的image。
D.  U-Boot-spl.map 这个文件里面存储了spl的memory map信息,可以找到各函数入口的地址。
U-Boot生成的image在U-Boot-am33x/am335x中,具体如下:
A.  U-Boot.img负责AM335x启动的第二阶段
B.  U-Boot 包含有调试信息,属于ELF格式,是调试时需要的image。
C.  U-Boot.map这个文件里面存储了U-Boot的memory map信息,可以找到各函数入口的地址
5.3.4导入CCS代码。
     在CCS中, Menu File ->Import … 选择 Makefile 方式导入,如下图所示:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image010.jpg
在ezsdk中,U-Boot/SPL所对应的Makefile的具体路径如下:
/home/sitara/ti-sdk-am335x-evm-05.05.00.00/board-support/U-Boot-2011.09-psp04.06.00.08,笔者的则是Z:\lsbbb\uboot,其中Z是用samba通过网络共享给windows映射的盘符,建议用这种方式,因为导入后CCS需要以相对路径的方式载入所有源代码。
如前面所提到,U-Boot 和SPL的源码在同一个文件夹的,通过不同的Makefile管理不同的编译宏来区分的。这里导入的是U-Boot的代码对应的Makefile,会相应的导入U-Boot对应的预编译选项,因为其包含了所有的代码。而对于SPL,也会相应的一起带入,只是在CCS中看到的代码的宏定义有些不对,但这个不影响调试。
5.3.5 CCS 连接 AM335x.
主要分成仿真器的连接,target连接和Debug配置等几部分:
一、仿真器的连接
1.CCS的配置
    CCS的配置主要包括Target的配置和连接两部分。
A.Target 配置
Target的配置包含两个部分,一个是仿真器(XDS100v2),另一个就是SOC(AM335x)。具体操作如下:
        i.      View -> Target Configurations
       ii.      点右键选择New TargetConfiguration.
       iii.新建一个叫做AM3352的target.
       iv.connection选择 Texas Instruments XDS100v2 USB Emulator.
       vi.在Board or Device 中选择AM3352.
       vii.点击Save 保存。
       viii.点击Test Connection 看是否能够正常连接。
配置target成功后,会看到如下界面
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image012.jpg
二、Target 连接
A.右键选中Target Configurations中已配置好的target:AM3352.ccxml, 在右键菜单中选择LaunchSelectedConfiguration,连接成功后,可以得到下图
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image014.jpg
    此时,PC 和仿真器以及仿真器和SOC的JTAG连接成功,但是ARMcore还没有连上。从图中可以看到,有多个core的配置选项,由于U-Boot/SPL, Linux 运行在ARM coretex-A8 core上,这里只关注ARM core。
B.在Debug窗口中,右键点击CortxA8 core, 选择Connect Target. 连接成功后,如下图所示:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image016.jpg
此时,已经成功连上AM335x的Cortex-A8 core了。
三、Debug配置
这里的debug配置,是对emulator连上core后行为的设置。     可以通过菜单run-debugconfiguration,得到以下界面:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image018.jpg
在该页配置中,在调试过程需要调整的就是Auto Run Options,可以根据需要设置,当加载了image后,core自动运行到指定的symbol,并且被JTAG接口所停住
5.3.6 SPL的调试
     调试U-Boot/SPL 的方式有两种,主要涉及如何加载image:一种是把image通过JTAG下载到片上RAM或者DDR中,然后导入symbol,重置 PC指针到image的入口处,进行调试;另一种,把image烧到SD卡或者其他启动存储器上,启动板子,通过JTAG停住core的PC指针,导入symbol,重置 PC指针到image的入口处,进行调试。
下面会在具体步骤中说明这两种方式如何操作:
     A.    下载SPL image到AM335x中。
如果AM335x是从SD卡方式启动,此时SPL image已经被ROM code成功读到片上 RAM中,就不需要加载 SPL image了。
如果选择SPL image通过CCS下载,鼠标左键选择CortxA8 core , 然后在CCS菜单中,Tools -> Load Memory, 选择编译好的SPL imageU-Boot-spl.bin,如下图所示:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image020.jpg
    选择加载的地址。由于加载的U-Boot-spl.bin是RAW data,所以需要指定load address,这个地址就是SPL的入口地址,对于AM335x,SPL的入口地址是 0x402F0400,对应的宏定义为CONFIG_SPL_TEXT_BASE, 该宏定义在include/configs/am335x_evm.h中。通过编译出的map文件U-Boot-spl.map也可以查到,是__start symbol对应的地址。
     设定加载image内型。由于所有的代码都是运行在ARM(32bit)模式下。所以Type-size也要设成32bit。设置界面如下:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image022.jpg
      最后点击Finish,SPL就会被load到片上RAM中了。如果在console窗口中有错误信息,需要把SPL image重新加载一遍。
     B.    加载 symbol。
在上一步里,只是加载了RAW image,还没有加载调试所需要的带有调试信息的symbol。
    可以通过Run ->Load -> Load Symbols 加载symbol信息,界面如下:
这里选择的是带有symbol信息的U-Boot-spl.
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image024.jpg
     C.    设置Cortex-A8 core到ARM状态。
ARMcore 启动后,默认在Thumb(16bit)模式下,如前面所说,需要将其切换到ARM(32bit)下。具体做法是,View->Registers,展开CPSR寄存器,把T位设置为0。界面如下:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image026.jpg
     D.    SPL的单步调试。
a.     从SPL编译的memory map可知,SPL从0x402f0400开始执行,所以首先就要把寄存器PC的值设为0x402f0400。可以通过View->Registers中设置PC指针的值即可, 界面如下,将红色框里面的改为0x402f0400即可。
b.   点击Debug窗口(view->debug)上tool bar中的汇编单步按钮,如下图所示,就开始调试了。
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image028.gif
这时,在反汇编窗口(view->disassembly)中,如下图所示,看到的是汇编代码,而且在编辑窗口这边看不到源码。这是由于开始执行的代码在/arch/arm/cpu/armv7/start.s 中,反汇编和汇编一样,所以没有显示源码。
    同时,可以看到PC指针运行到0x402f0458处。这里只是单步执行了一条指令,为什么跳过了这么大块地址?这里的单步运行,指令地址空间跳转了n指令,而不是一条指令,这是因为0x402f0400处存放的是异常中断向量表,通过默认启动的入口跳到reset symbol对应的地址了,也就是在0x402f0400处跳转到0x402f0458了,具体代码(arch/arm/cpu/armv7/start.S)如下:
      _start: b   reset
reset:                                                                        
      bl save_boot_params      
    接下来,可以在C代码中设置断点,进行调试了。有两点值得注意:
    i.如果编译的时候,交叉编译器的性能优化选项是开着的,那么优化后编译生成的代码,其执行循序和C源码有差别,这时设置断点时,其实际的位置不会很准。所以,这里可以根据需要,决定是否关闭-O2选项。
    ii.在CCS中,把core停下来时,CCS会根据image中调试信息所包含的源码路径,找到对应的源码和symbol。由于U-Boot/SPL是在Linux中编译,所以其路径都是Linux下的路径,所以Linux版本的CCS可以直接找到对应的源码,而对于Windows版本的CCS不能直接找到,需要通过手动找到源码,但是找到一个文件的源码后,CCS会根据相对路径找到其他文件。除了这点外,Linux和Windows的CCS配置使用是一样的。
5.3.7 U-Boot的调试
总体来说, U-Boot的调试过程和SPL调试过程是类似的,这里主要说明不同的几点:
A.从AM335x的启动过程可知,U-Boot是运行在DDR中的,而DDR是由SPL来初始化的,SPL还会初始化相关底层功能。所以,加载U-Boot前,先加载并运行SPL。
B.此版本的UBOOT使用了FDT(扁平设备树文件)。编译后的文件意义如下
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image030.gif
所以我们需要导入u-boot.bin文件,此文件包含了uboot和.dtb所有信息。这是和不使用设备树的uboot的调试不同之处。
C.UBOOT代码执行过程中会有重定位操作,在board_init_f和board_init_f之间的relocate_code中实现。这个版本中的relocaddr= 0x8FF57000。为了能够调试重定位前、后的两部分代码。在LOADsymbols时,通过offset来区分。
1、调试relocation之前的 UBOOT代码
(1)加载U-Boot-spl.bin
(2)运行U-Boot-spl.bin之后立刻停住,如下所示
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image032.gif
(3)加载u-boot.bin,start address: CONFIG_SYS_TEXT_BASE          0x80800000 file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image034.gif
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image036.gif
(4)load symbols->u-boot
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image038.gif
加载完成后界面如下:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image040.gif
可以看到起始地址是0x80800000,还可以看到相应的源文件vectors.s
(5)设置断点
找到重定位前的C函数board_init_f,打断点,如下;
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image042.gif
点击运行后看到停在断点处,如下图所示:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image044.gif
(6)单步调试执行
    至此,可以单步执行相应的代码调试。
注意:这样就可以调试relocate_code之前的代码。
2、调试relocation之后的 UBOOT代码
参考relocation之前的调试方法,relocation之后的 UBOOT代码调试在第(4)步有区别,之前(1)(2)(3)步一样,体现为加载symbols时有offset,offset这里为relocaddr   = 0x8FF57000。
如下图所示:
(4)load symbols->u-boot
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image046.gif
加载之后界面如下:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image048.gif
与relocation之前的调试步骤对比,在这时并不能看到相应的源码或文件,我的理解是因为在此时符号表被加载到了0x8FF57000,固在0x80800000看不到相应代码(symbols)。不过没关系,这里我们只是为了调试relocation之后的代码。
(5)设置断点
在board_init_r函数中打断点
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image050.gif
点击运行,会看到代码停在断点处。如下图所示:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image052.gif
此时,就可以通过单步运行来进行相关代码调试。


文中图片可能显示不正常,本想一个个地插入或修正,但是太辛苦了,于是上传PDF格式的附件,请多包涵!



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

如果想吃一顿饺子,就得从冰箱里取出肉,剁馅儿,倒面粉、揉面、醒面,擀成皮儿,下锅……
一整个繁琐流程,就是为了出锅时那一嘴滚烫流油的热饺子。

如果这个过程,禁不住饿,零食下肚了,饺子出锅时也就不香了……《非诚勿扰3》

出0入0汤圆

发表于 2019-8-11 16:57:22 | 显示全部楼层
写教程真不容易,给楼主点个赞

出40入45汤圆

发表于 2019-8-11 16:59:56 | 显示全部楼层
写教程真不容易,给楼主点个赞 +1

出150入640汤圆

 楼主| 发表于 2019-8-11 17:02:12 | 显示全部楼层
矩阵时间 发表于 2019-8-11 16:59
写教程真不容易,给楼主点个赞 +1

谢谢支持!!!

出0入0汤圆

发表于 2019-8-11 18:59:28 | 显示全部楼层
linux感觉调试机器码的调试用的还真不多,用gdb都不多,不是串口打印就是log输出

出150入640汤圆

 楼主| 发表于 2019-8-11 20:18:46 | 显示全部楼层
Vmao 发表于 2019-8-11 18:59
linux感觉调试机器码的调试用的还真不多,用gdb都不多,不是串口打印就是log输出 ...

恩,TI的CCS调试方式不一样滴。反正我觉得这么多厂家,就TI的开发工具最齐全!

出0入22汤圆

发表于 2019-8-11 20:56:07 来自手机 | 显示全部楼层
据说有人用jlink调试335x,我没有成功,而用xds100成功的将3358裸奔了一下。

出0入0汤圆

发表于 2019-8-11 23:02:04 | 显示全部楼层
虽然不用,支持一下!

出150入640汤圆

 楼主| 发表于 2019-8-11 23:36:49 | 显示全部楼层
zxq6 发表于 2019-8-11 20:56
据说有人用jlink调试335x,我没有成功,而用xds100成功的将3358裸奔了一下。

要另外装一个JLINK的驱动,CCS没有自带。

出0入0汤圆

发表于 2019-8-12 10:10:11 | 显示全部楼层
楼主,这个仿真器不便宜吧?要是能用JLINK那就容易玩了。

出150入640汤圆

 楼主| 发表于 2019-8-12 11:54:16 | 显示全部楼层
Excellence 发表于 2019-8-12 10:10
楼主,这个仿真器不便宜吧?要是能用JLINK那就容易玩了。

xds100v2不贵,100大洋以下,JLINK也可以,但我没有测试过

出0入0汤圆

发表于 2019-8-12 12:21:41 来自手机 | 显示全部楼层
楼主,你的板子哪里可以买?

出0入0汤圆

发表于 2019-8-12 13:18:33 | 显示全部楼层
官方的3358,能使用这个教程吗?

出150入640汤圆

 楼主| 发表于 2019-8-12 14:11:20 | 显示全部楼层
nust-奔跑 发表于 2019-8-12 13:18
官方的3358,能使用这个教程吗?

也可以的,只要JTAG接口留出来了

出0入0汤圆

发表于 2019-8-23 10:14:45 来自手机 | 显示全部楼层
标记下  以后用得着

出0入0汤圆

发表于 2019-8-23 12:14:12 | 显示全部楼层
多谢分享

出150入640汤圆

 楼主| 发表于 2019-8-23 15:11:19 | 显示全部楼层
rniu 发表于 2019-8-12 12:21
楼主,你的板子哪里可以买?

看我的签名档

出0入0汤圆

发表于 2019-9-11 20:11:07 来自手机 | 显示全部楼层
本帖最后由 HongSSCC 于 2019-9-11 23:15 编辑

請問教程中的symbol是指什麼?
Sorry, 不会收回,只好再发一次

出0入0汤圆

发表于 2019-9-11 20:12:41 来自手机 | 显示全部楼层
请问教程中的symbol是指什么?

出150入640汤圆

 楼主| 发表于 2019-9-11 21:46:07 | 显示全部楼层
HongSSCC 发表于 2019-9-11 20:12
请问教程中的symbol是指什么?

普遍地说,debug symbol(调试符号)是一种能够从对象文件(object file)的符号表(symbol table)中获取其余信息的符号。所谓其余信息,即是指二进制源代码中的变量名称、标识符名称等等。

对象文件(就是.o后缀的文件),你可以参考这个网页链接(其实不了解也问题不大)。程序从源代码到执行需要有多个过程,对象文件就是其中的一个状态。而一般情况下可执行文件为了节省空间,是不会记录源代码中的变量名的,debug symbol就是用来记录源代码中的变量名的,一般是调试程序崩溃时用得上。

不一定准确,参考维基百科(ljbd)

附原文:

A debug symbol is a special kind of symbol that attaches additional information to the symbol table of an object file, such as a shared library or an executable. This information allows a symbolic debugger to gain access to information from the source code of the binary, such as the names of identifiers, including variables and routines.

The symbolic information may be compiled together with the module's binary file, or distributed in a separate file, or simply discarded during the compilation and/or linking.

This information can be helpful while trying to investigate and fix a crashing application or any other fault.

出0入0汤圆

发表于 2019-9-11 23:31:08 | 显示全部楼层
感谢解惑
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 00:24

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表