mini2440之2440init.s启动文件分析

mini2440之2440init.s启动文件分析
2011年05月18日
  ;=========================================
  ; NAME: 2440INIT.S
  ; DESC: C start up codes
  ; Configure memory, ISR ,stacks
  ; Initialize C-variables
  ; HISTORY:
  ; 2002.02.25:kwtark: ver 0.0
  ; 2002.03.20:purnnamu: Add some functions for testing STOP,Sleep mode
  ; 2003.03.14:DonGo: Modified for 2440.
  ;=========================================
  ;//GET类似于C语言的include,option.inc文件内定义了一些全局变量,memcfg.inc文件内定义了关于内存bank的符号和数字常量,2440addr.inc文件内定义了用于汇编的s3c2440寄存器变量和地址
  GET option.inc
  GET memcfg.inc
  GET 2440addr.inc
  BIT_SELFREFRESH EQU (1内存
  AREA Init,CODE,READONLY ;//这表明下面的是一个名为Init的代码段
  ENTRY ;//定义程序的入口(调试用)
  EXPORT __ENTRY ;//导出符号_ENTRY,但在那用到就还没查明
  __ENTRY
  ResetEntry
  ;1)The code, which converts to Big-endian, should be in little endian code.
  ;2)The following little endian code will be compiled in Big-Endian mode.
  ; The code byte order should be changed as the memory bus width.
  ;3)The pseudo instruction,DCD can not be used here because the linker generates error.
  ASSERT :DEF:ENDIAN_CHANGE ;//判断模式改变是否定义过(ASSERT是伪指令,:DEF:lable判断lable是否定义过了)
  [ ENDIAN_CHANGE;//下面是大小端的一个判断,在Option.inc里已经设为FALSE
  ASSERT :DEF:ENTRY_BUS_WIDTH
  [ ENTRY_BUS_WIDTH=32
  b ChangeBigEndian ;DCD 0xea000007
  ]
  [ ENTRY_BUS_WIDTH=16
  andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00
  ]
  [ ENTRY_BUS_WIDTH=8
  streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea
  ]
  |
  b ResetHandler;//中断向量表 --设成FALSE的话就来到这了,转跳到复位程序入口
  ]
  b HandlerUndef ;handler for Undefined mode //转跳到Undefined mode程序入口
  b HandlerSWI ;handler for SWI interrupt //转跳到SWI 中断程序入口
  b HandlerPabort ;handler for PAbort //转跳到PAbort(指令异常)程序入口
  b HandlerDabort ;handler for DAbort //转跳到DAbort(数据异常)程序入口
  b . ;reserved //保留
  b HandlerIRQ ;handler for IRQ interrupt //转跳到IRQ 中断程序入口
  b HandlerFIQ ;handler for FIQ interrupt //转跳到FIQ 中断程序入口
  ;@0x20
  b EnterPWDN ; Must be @0x20.
  ;//==================================================================================
  ;//下面是改变大小端的程序,这里采用直接定义机器码的方式,至说为什么这么做就得问三星了
  ;//反正我们程序里这段代码也不会去执行,不用去管它
  ;//==================================================================================
  ChangeBigEndian
  ;@0x24
  [ ENTRY_BUS_WIDTH=32
  DCD 0xee110f10 ;0xee110f10 => mrc p15,0,r0,c1,c0,0
  DCD 0xe3800080 ;0xe3800080 => orr r0,r0,#0x80; //Big-endian
  DCD 0xee010f10 ;0xee010f10 => mcr p15,0,r0,c1,c0,0
  ]
  [ ENTRY_BUS_WIDTH=16
  DCD 0x0f10ee11
  DCD 0x0080e380
  DCD 0x0f10ee01
  ]
  [ ENTRY_BUS_WIDTH=8
  DCD 0x100f11ee
  DCD 0x800080e3
  DCD 0x100f01ee
  ]
  DCD 0xffffffff ;swinv 0xffffff is similar with NOP and run well in both endian mode.
  DCD 0xffffffff
  DCD 0xffffffff
  DCD 0xffffffff
  DCD 0xffffffff
  b ResetHandler
  HandlerFIQ HANDLER HandleFIQ
  HandlerIRQ HANDLER HandleIRQ
  HandlerUndef HANDLER HandleUndef
  HandlerSWI HANDLER HandleSWI
  HandlerDabort HANDLER HandleDabort
  HandlerPabort HANDLER HandlePabort
  ;===================================================================================
  ;//这一段程序是用来进行第二次查表的过程了.
  ;//如果说第一次查表是由硬件来完成的,那这一次查表就是由软件来实现的了.
  ;//为什么要查两次表??
  ;//没有办法,ARM把所有的中断都归纳成一个IRQ中断异常和一个FIRQ中断异常
  ;//第一次查表主要是查出是什么异常,可我们总要知道是这个中断异常中的什么中断呀!
  ;//没办法了,再查一次表呗!
  ;===================================================================================
  IsrIRQ
  sub sp,sp,#4 ;reserved for PC //预留一个值来保存 服务子程序的地址
  stmfd sp!,{r8-r9} ; //将r8 r9入栈
  ldr r9,=INTOFFSET ;//偏移量
  ldr r9,[r9]
  ldr r8,=HandleEINT0
  add r8,r8,r9,lsl #2 ;//将INTOFFSET和HandleEINT0结合起来
  ldr r8,[r8] ;//装入中断服务程序的入口
  str r8,[sp,#8] ;//str不是入栈,只是把r0值放到 sp+8 这个地址上面
  ldmfd sp!,{r8-r9,pc} ;//一个个出栈
  LTORG ;//声明文字池,因为我们用了ldr伪指令
  ;=======
  ; ENTRYY//(好了,我们的CPU要在这复位了.)
  ;=======
  ResetHandler
  ldr r0,=WTCON ;watch dog disable //关开门狗
  ldr r1,=0x0
  str r1,[r0]
  ldr r0,=INTMSK
  ldr r1,=0xffffffff ;all interrupt disable //关中断
  str r1,[r0]
  ldr r0,=INTSUBMSK
  ldr r1,=0x7fff ;all sub interrupt disable //关子中断
  str r1,[r0]
  [ {TRUE} ;//点LED灯
  ;rGPFDAT = (rGPFDAT & ~(0xf1 ; means Fclk:Hclk is not 1:1.
  ; bl MMU_SetAsyncBusMode ;//MMU_SetAsyncBusMode在4k以后,所以现在还不能调用
  ; |
  ; bl MMU_SetFastBusMode ; default value.
  ; ]
  ;program has not been copied, so use these directly
  [ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1.//意思是 Fclk:Hclk 不是 1:1.
  mrc p15,0,r0,c1,c0,0
  orr r0,r0,#0xc0000000;R1_nF:OR:R1_iA
  mcr p15,0,r0,c1,c0,0
  |
  mrc p15,0,r0,c1,c0,0
  bic r0,r0,#0xc0000000;R1_iA:OR:R1_nF
  mcr p15,0,r0,c1,c0,0
  ]
  ;Configure UPLL //配置 UPLL
  ldr r0,=UPLLCON
  ldr r1,=((U_MDIV内存控制器等寄存器的值,因为这些寄存器是连续排列的,所以采用如下办法对这些
  ;//寄存器进行连续设置.其中用到了SMRDATA的数据,这在代码后面有定义
  ;Set memory control registers //给adram的寄存器赋值
  ;ldr r0,=SMRDATA
  adrl r0, SMRDATA ;be careful! //得到SMRDATA的首地址
  ldr r1,=BWSCON ;BWSCON Address //得到BWSCON的地址
  add r2, r0, #52 ;End address of SMRDATA
  ;//用于把(存储器总线宽度&等待控制寄存器BWSCON,Bank控制寄存器BANKCON0-5) 赋值
  0
  ldr r3, [r0], #4
  str r3, [r1], #4
  cmp r2, r0
  bne %B0
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;;;;;;;;;;;; When EINT0 is pressed, Clear SDRAM
  ;//如果 EINT0 产生(这中断就是我们按键产生的), 就清除SDRAM ,不过好像没人会在这个时候按
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ; check if EIN0 button is pressed
  ldr r0,=GPFCON
  ldr r1,=0x0
  str r1,[r0]
  ldr r0,=GPFUP
  ldr r1,=0xff
  str r1,[r0]
  ldr r1,=GPFDAT
  ldr r0,[r1]
  bic r0,r0,#(0x1e内存的代码
  ldr r0,=GPFCON
  ldr r1,=0x55aa
  str r1,[r0]
  ; ldr r0,=GPFUP
  ; ldr r1,=0xff
  ; str r1,[r0]
  ldr r0,=GPFDAT
  ldr r1,=0x0
  str r1,[r0] ;LED=****
  mov r1,#0
  mov r2,#0
  mov r3,#0
  mov r4,#0
  mov r5,#0
  mov r6,#0
  mov r7,#0
  mov r8,#0
  ldr r9,=0x4000000 ;64MB ;//清零内存
  ldr r0,=0x30000000
  0
  stmia r0!,{r1-r8} ;//stm出栈,把r1-r8的值赋到r0上,然后r0+4
  subs r9,r9,#32
  bne %B0
  ;Clear SDRAM End
  1
  ;Initialize stacks//初始化各种处理器模式下的堆栈
  bl InitStacks
  ;===========================================================
  ldr r0, =BWSCON
  ldr r0, [r0]
  ands r0, r0, #6 ;OM[1:0] != 0, NOR FLash boot //从norflash启动就跳转到copy_proc_beg
  bne copy_proc_beg ;do not read nand flash
  adr r0, ResetEntry ;OM[1:0] == 0, NAND FLash boot//从nandflash启动
  cmp r0, #0
  ;if use Multi-ice //在进行比较,是否入口地址是在0处
  ;//如果不是,则表示主板设置了从NAND启动,但这个程序由于其它原因, 并没有从NAND从启动,这种情况最有可能的原因就是用仿真器.
  bne copy_proc_beg ;do not read nand flash for boot//仿真器也不需要在NAND FLASH启动
  ;nop
  ;===========================================================
  ;//bl 带返回的跳转指令
  ;//l 决定是否保存返回地址。当有l时,当前的PC寄存器的值将保存到lr寄存器中
  ;// 当无l时,指令仅执行跳转,当前的PC寄存器的值将不会保存到lr寄存器中
  nand_boot_beg
  [ {TRUE}
  bl CopyProgramFromNand //把nandflash中的程序全部copy到sdram中,从???
  |
  mov r5, #NFCONF ;//首先设定NAND的一些控制寄存器
  ;set timing value
  ldr r0, =(7运行,由ldr加载的r9的值还是定位在内存. ???
  2
  ands r0, r8, #0x1f;//r8为0x1f(32)的整数倍-1,eq有效,ne无效
  bne %F3 ;//这句的意思是对每个块(32页)进行检错
  mov r0, r8 ;//r8->r0
  bl CheckBadBlk ;//检查NAND的坏区
  cmp r0, #0 ;//比较r0和0
  addne r8, r8, #32 ;//存在坏块的话就跳过这个坏块
  bne %F4 ;//没有的话就跳到标号4处
  3
  mov r0, r8 ;//当前页号->r0
  mov r1, r9 ;//当前目标地址->r1
  bl ReadNandPage ;//读取该页的NAND数据到RAM
  add r9, r9, #512 ;//每一页的大小是512Bytes
  add r8, r8, #1 ;//r8指向下一页
  4
  cmp r8, #5120 ;//比较是否读完5120页即128KBytes
  bcc %B2 ;//如果r8小于256(没读完),就返回前面的标号2处
  mov r5, #NFCONF ;DsNandFlash
  ldr r0, [r5, #4]
  bic r0, r0, #1
  str r0, [r5, #4]
  ]
  ldr pc, =copy_proc_beg ;//ldr指令 加载了绝对地址,现在pc指向的是sdram中的copy_proc_beg,程序在sdram上运行了
  ;===========================================================
  copy_proc_beg
  adr r0, ResetEntry ;//程序在sdram上运行了,该取值方式 取到的地址就是相对于pc的偏移地址了也就是0x30000000
  ;//这里应该注意,使用的是adr,而不是ldr。使用ldr说明ResetEntry是个绝对地址,这个地址是在程序链接的时候
  ;//确定的。而使用adr则说明ResetEntry的地址和当前代码的执行位置有关,它是一个相对的地址。比如这段代码
  ;//在stepingstone里面执行,那么ResetEntry的地址就是零。如果在sdRAM里执行,那么ResetEntry就应是sdRAM的一个
  ;//地址,应该等于RO base 为0x30000000。
  ldr r2, BaseOfROM ;//0x30000000 ldr 是把BaseOfROM(一地址)中的值放到r2中
  cmp r0, r2
  ldreq r0, TopOfROM ;//相等就跳转 相等说明程序是从nandflash或者sdram中运行的。不相等是从norflash运行的
  beq InitRam
  ldr r3, TopOfROM ;//以下代码是针对代码在NOR FLASH时的拷贝方法,这个程序 从norflash也要copy程序
  0
  ldmia r0!, {r4-r7} ;//搬运代码
  stmia r2!, {r4-r7}
  cmp r2, r3
  bcc %B0
  sub r2, r2, r3 ;//上面拷贝时每次拷贝4个双字(32位)大小,但是RO段大小不一定是4的整数倍,所以可能多拷贝了几个双字大小,r2-r3得到多拷贝的个数
  sub r0, r0, r2 ;//r0-(r2-r3)可以使r0指向在boot nand中RO的结束地址
  InitRam //复制SW区域
  ldr r2, BaseOfBSS
  ldr r3, BaseOfZero
  0
  cmp r2, r3;//比较BaseOfBSS和BaseOfZero
  ldrcc r1, [r0], #4
  strcc r1, [r2], #4
  bcc %B0
  mov r0, #0
  ldr r3, EndOfBSS
  1
  cmp r2, r3
  strcc r0, [r2], #4
  bcc %B1
  ldr pc, =%F2 ;goto compiler address
  2
  ; [ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1.
  ; bl MMU_SetAsyncBusMode
  ; |
  ; bl MMU_SetFastBusMode ; default value.
  ; ]
  ; bl Led_Test
  ;===========================================================
  ; //进入C语言前的最后一步了,就是把我们用说查二级向量表的中断例程安装到一级向量表(异常向量表)里.
  ; Setup IRQ handler
  ldr r0,=HandleIRQ ;This routine is needed
  ldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c
  str r1,[r0] //把IsrIRQ的地址放到HandleIRQ中
  ; ;Copy and paste RW data/zero initialized data
  ; ldr r0, =|Image$$RO$$Limit| ; Get pointer to ROM data
  ; ldr r1, =|Image$$RW$$Base| ; and RAM copy
  ; ldr r3, =|Image$$ZI$$Base|
  ;
  ; ;Zero init base => top of initialised data
  ; cmp r0, r1 ; Check that they are different
  ; beq %F2
  ;1
  ; cmp r1, r3 ; Copy init data
  ; ldrcc r2, [r0], #4 ;--> LDRCC r2, [r0] + ADD r0, r0, #4
  ; strcc r2, [r1], #4 ;--> STRCC r2, [r1] + ADD r1, r1, #4
  ; bcc %B1
  ;2
  ; ldr r1, =|Image$$ZI$$Limit| ; Top of zero init segment
  ; mov r2, #0
  ;3
  ; cmp r3, r1 ; Zero init
  ; strcc r2, [r3], #4
  ; bcc %B3
  [ :LNOT:THUMBCODE
  bl Main ;Do not use main() because ......
  ;ldr pc, =Main ;
  b .
  ]
  [ THUMBCODE ;for start-up code for Thumb mode
  orr lr,pc,#1
  bx lr
  CODE16
  bl Main ;Do not use main() because ......
  b .
  CODE32
  ]
  ;function initializing stacks
  InitStacks ;//-----------------------7个模式堆栈初始化
  ;Do not use DRAM,such as stmfd,ldmfd......
  ;SVCstack is initialized before
  ;Under toolkit ver 2.5, 'msr cpsr,r1' can be used instead of 'msr cpsr_cxsf,r1'
  mrs r0,cpsr ;//cpsr为状态寄存器
  bic r0,r0,#MODEMASK ;//清空低5位的数据
  orr r1,r0,#UNDEFMODE|NOINT
  msr cpsr_cxsf,r1 ;UndefMode
  ldr sp,=UndefStack ; UndefStack=0x33FF_5C00
  orr r1,r0,#ABORTMODE|NOINT
  msr cpsr_cxsf,r1 ;AbortMode
  ldr sp,=AbortStack ; AbortStack=0x33FF_6000
  orr r1,r0,#IRQMODE|NOINT
  msr cpsr_cxsf,r1 ;IRQMode
  ldr sp,=IRQStack ; IRQStack=0x33FF_7000
  orr r1,r0,#FIQMODE|NOINT
  msr cpsr_cxsf,r1 ;FIQMode
  ldr sp,=FIQStack ; FIQStack=0x33FF_8000
  bic r0,r0,#MODEMASK|NOINT
  orr r1,r0,#SVCMODE
  msr cpsr_cxsf,r1 ;SVCMode
  ldr sp,=SVCStack ; SVCStack=0x33FF_5800
  ;USER mode has not be initialized.
  mov pc,lr
  ;The LR register will not be valid if the current mode is not SVC mode.
  ;===========================================================
  [ {TRUE}
  |
  ReadNandID
  mov r7,#NFCONF
  ldr r0,[r7,#4] ;NFChipEn();
  bic r0,r0,#2
  str r0,[r7,#4]
  mov r0,#0x90 ;WrNFCmd(RdIDCMD);
  strb r0,[r7,#8]
  mov r4,#0 ;WrNFAddr(0);
  strb r4,[r7,#0xc]
  1 ;while(NFIsBusy());
  ldr r0,[r7,#0x20]
  tst r0,#1
  beq %B1
  ldrb r0,[r7,#0x10] ;id = RdNFDat()5
  strb r1,[r5,#0xc] ;WrNFAddr(5);(6) 6->5
  strb r0,[r5,#0xc] ;WrNFAddr(addr)
  mov r1,r0,lsr #8 ;WrNFAddr(addr>>8)
  strb r1,[r5,#0xc]
  cmp r6,#0 ;if(NandAddr)
  movne r0,r0,lsr #16 ;WrNFAddr(addr>>16)
  strneb r0,[r5,#0xc]
  ; bl WaitNandBusy ;WaitNFBusy()
  ;do not use WaitNandBusy, after WaitNandBusy will read part A!
  mov r0, #100
  1
  subs r0, r0, #1
  bne %B1
  2
  ldr r0, [r5, #0x20]
  tst r0, #1
  beq %B2
  ldrb r0, [r5,#0x10] ;RdNFDat()
  sub r0, r0, #0xff
  mov r1,#0 ;WrNFCmd(READCMD0)
  strb r1,[r5,#8]
  ldr r1,[r5,#4] ;NFChipDs()
  orr r1,r1,#2
  str r1,[r5,#4]
  mov pc, r7
  ReadNandPage
  mov r7,lr
  mov r4,r1
  mov r5,#NFCONF
  ldr r1,[r5,#4] ;NFChipEn()
  bic r1,r1,#2
  str r1,[r5,#4]
  mov r1,#0 ;WrNFCmd(READCMD0)
  strb r1,[r5,#8]
  strb r1,[r5,#0xc] ;WrNFAddr(0)
  strb r0,[r5,#0xc] ;WrNFAddr(addr)
  mov r1,r0,lsr #8 ;WrNFAddr(addr>>8)
  strb r1,[r5,#0xc]
  cmp r6,#0 ;if(NandAddr)
  movne r0,r0,lsr #16 ;WrNFAddr(addr>>16)
  strneb r0,[r5,#0xc]
  ldr r0,[r5,#4] ;InitEcc()
  orr r0,r0,#0x10
  str r0,[r5,#4]
  bl WaitNandBusy ;WaitNFBusy()
  mov r0,#0 ;for(i=0; iSST39VF1601
  ;GCS1->16c550
  ;GCS2->IDE
  ;GCS3->CS8900
  ;GCS4->DM9000
  ;GCS5->CF Card
  ;GCS6->SDRAM
  ;GCS7->unused
  SMRDATA DATA ;//这是一块连续的地址,用于存放 存储器总线宽度&等待控制寄存器BWSCON,Bank控制寄存器BANKCON0-5
  ; Memory configuration should be optimized for best performance
  ; The following parameter is not optimized.
  ; Memory access cycle parameter strategy
  ; 1) The memory settings is safe parameters even at HCLK=75Mhz.
  ; 2) SDRAM refresh period is for HCLKSCLK, SCLK1:0->SCLK, SCKE:0->=SCKE.
  str r0,[r1]
  ;Set memory control registers
  ldr r0,=SMRDATA ;be careful! //得到SMRDATA的首地址
  ldr r1,=BWSCON ;BWSCON Address //得到BWSCON的地址
  add r2, r0, #52 ;End address of SMRDATA
  0
  ldr r3, [r0], #4
  str r3, [r1], #4
  cmp r2, r0
  bne %B0
  mov r1,#256
  0 subs r1,r1,#1 ;1) wait until the SelfRefresh is released.
  bne %B0
  ldr r1,=GSTATUS3 ;GSTATUS3 has the start address just after SLEEP wake-up
  ldr r0,[r1]
  mov pc,r0
  ;=====================================================================
  ; Clock division test
  ; Assemble code, because VSYNC time is very short
  ;=====================================================================
  EXPORT CLKDIV124
  EXPORT CLKDIV144
  CLKDIV124
  ldr r0, = CLKDIVN
  ldr r1, = 0x3 ; 0x3 = 1:2:4
  str r1, [r0]
  ; wait until clock is stable
  nop
  nop
  nop
  nop
  nop
  ldr r0, = REFRESH ;//SDRAM刷新控制寄存器
  ldr r1, [r0]
  bic r1, r1, #0xff
  bic r1, r1, #(0x7<<8) ;//设置刷新计数的值
  orr r1, r1, #0x470 ;// REFCNT135
  str r1, [r0]
  nop
  nop
  nop
  nop
  nop
  mov pc, lr
  CLKDIV144
  ldr r0, = CLKDIVN
  ldr r1, = 0x4 ; 0x4 = 1:4:4
  str r1, [r0]
  ; wait until clock is stable
  nop
  nop
  nop
  nop
  nop
  ldr r0, = REFRESH
  ldr r1, [r0]
  bic r1, r1, #0xff
  bic r1, r1, #(0x7<<8)
  orr r1, r1, #0x630 ; REFCNT675 - 1520
  str r1, [r0]
  nop
  nop
  nop
  nop
  nop
  mov pc, lr
  ALIGN
  AREA RamData, DATA, READWRITE ;//相应中断跳转的地址存放处
  ^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00
  HandleReset # 4
  HandleUndef # 4
  HandleSWI # 4
  HandlePabort # 4
  HandleDabort # 4
  HandleReserved # 4
  HandleIRQ # 4
  HandleFIQ # 4
  ;Do not use the label 'IntVectorTable',
  ;The value of IntVectorTable is different with the address you think it may be.
  ;IntVectorTable
  ;@0x33FF_FF20
  HandleEINT0 # 4
  HandleEINT1 # 4
  HandleEINT2 # 4
  HandleEINT3 # 4
  HandleEINT4_7 # 4
  HandleEINT8_23 # 4
  HandleCAM # 4 ; Added for 2440.
  HandleBATFLT # 4
  HandleTICK # 4
  HandleWDT # 4
  HandleTIMER0 # 4
  HandleTIMER1 # 4
  HandleTIMER2 # 4
  HandleTIMER3 # 4
  HandleTIMER4 # 4
  HandleUART2 # 4
  ;@0x33FF_FF60
  HandleLCD # 4
  HandleDMA0 # 4
  HandleDMA1 # 4
  HandleDMA2 # 4
  HandleDMA3 # 4
  HandleMMC # 4
  HandleSPI0 # 4
  HandleUART1 # 4
  HandleNFCON # 4 ; Added for 2440.
  HandleUSBD # 4
  HandleUSBH # 4
  HandleIIC # 4
  HandleUART0 # 4
  HandleSPI1 # 4
  HandleRTC # 4
  HandleADC # 4
  ;@0x33FF_FFA0
  END
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值