>>Drew的主頁---->程序示例
程序示例
這里是一些程序示例和源碼解釋.一些相關(guān)程序代碼會陸續(xù)補上.相關(guān)問題可參見硬件驅(qū)動
系統(tǒng)初始化
系統(tǒng)初始化對不同的CPU,基本步驟是類似的.
系統(tǒng)初始化的主要步驟如下
- 啟動
- 關(guān)閉中斷
- 放boot type到堆棧
- 清空緩存
VxWorks 系統(tǒng)的 PowerPC BSP,系統(tǒng)開機后執(zhí)行的第一個函數(shù) romInit(),在ROM的起點,這里是使用的PowerPC匯編語言
/* 定義內(nèi)部函數(shù) internals */ .globl romInit /* start of system code */ .globl _romInit /* start of system code */
/* 定義外部函數(shù) externals */ .extern romStart /* system initialization routine */
.text .align 2
/******************************************************************************* * * romInit ( int startType /@ only used by 2nd entry point @/ ) */
romInit: _romInit: bl cold /* 冷啟動 */ bl warm /* 熱啟動 */
cold: li p5, BOOT_COLD bl start /* skip over next instruction */
warm: or p5, p0, p0 /* startType to p5 */
start: /* 此處是系統(tǒng)啟動開始 */
/* 屏蔽MSR中CE,EE位,關(guān)閉所有的外部中斷 /* * Disable external interrupts */
mfmsr p0 /* p0 = msr */ INT_MASK (p0, p1) /* mask EE and CE bit */ ori p1,p1,_PPC_MSR_ME /* enable machine checks */ mtmsr p1 /* msr = p1 */ isync
/* 下面兩步是按照硬件定義初始化一些SPR,DCR寄存器,置0或置1
/* SPR是特殊功能寄存器,DCR為設(shè)備控制寄存器,還有MSR機器狀態(tài)寄存器,這些是PowerPC內(nèi)核中很重要的寄存器
/* 初始化SPR,DCR寄存器置0 * Initalize registers that need to be set to zero. */
addi r4,r0,0x0000 mtspr SGR,r4 /* 解鎖所有存儲區(qū)域 SPR 中 SGR 位置0 */ mtspr ESR, r4 /* SPR中的錯誤狀態(tài)位 ESR 清0 */ mtspr TCR, r4 /* 關(guān)閉所有的 timers */ mtspr PIT, r4 /* 清0 PIT timer */ mtdcr UICER, r4 /* 關(guān)閉中斷控制器(UIC)中的所有中斷 */ mtspr XER, r4 /* 清0 integer exception 寄存器 */
/* 初始化另一些SPR,DCR寄存器置1 * Initalize registers that need to be cleared with 0xFFFFFFFF. */
addis r4,r0,0xffff ori r4,r4,0xffff mtspr TSR, r4 /* timer */ mtspr DBSR, r4 /* 調(diào)試狀態(tài)位置1 */ mtdcr UICSR, r4 /* 清除中斷控制器(UIC)中的所有 pending 中斷 */ mtdcr dmasr, r4 /* DMA狀態(tài)寄存器置1 */
/* PowerPC405用兩個緩存,一個是16K指令緩存(ICU),一個是6K數(shù)據(jù)緩存(DCU),下面是清空著兩個緩存,并根據(jù)硬件設(shè)置緩存 */
/* 清空指令緩存 */ /*BESR type regs ZZZZZZZZZZZZ * Invalidate the entire instruction cache. This can be done * with a single iccci instruction in the processor core. */
iccci r0, r0
/*清空數(shù)據(jù)緩存 * Invalidate the entire data cache. * The 405 processor core in the 405GP has 128 congruence classes. * Each cache line in the 405 processor is 32 bytes. */
/* * Turn the instruction cache on for faster boot-up. * Also, the icache is needed to help initialize Bank 0 * of the EBC to speed up accesses to flash. * address space 0x00000000-0x07ffffff is cached * address space 0xf8000000-0xffffffff is cached */
lis p0, HIADJ(_PPC403_ICCR_DEFAULT_VAL) addi p0, p0, LO(_PPC403_ICCR_DEFAULT_VAL) mtspr _PPC403_ICCR, p0 isync
/* 初始化外部總線控制器(EBC),跳轉(zhuǎn)指令BL,執(zhí)行extBusCntlrInit * /
bl extBusCntlrInit
/* * Now that the EBC Bank 0 has been set up, turn the I-cache off if * i-cache was not specified in config.h. It is also invalidated * again. */
#ifndef USER_I_CACHE_ENABLE li p0, 0 /* clear p0 */ mtspr _PPC403_ICCR, p0 /* turn off i-cache */ isync iccci r0, r0 /* invalidate the I-cache again */ #endif
/* 初始化和SDRAM相關(guān)的IIC(inter-integrated circut)寄存器IIC0, * Initialize IIC0 for use in automatic SDRAM configuration */
#ifdef LOCAL_MEM_AUTOSIZE bl iic0Init #endif
/* 初始化SDRAM,BL跳轉(zhuǎn)執(zhí)行sdramInit * Configure the SDRAM controller only if this is a cold boot. * If the SDRAM controller is reinitialized on a warm boot, the * boot line will get wiped out because of the ECC SDRAM memory * initialization. */
li p0, BOOT_COLD and. p0, p0, p5 /* p5 is saved at the entry of romInit */ beq skip
bl sdramInit
skip:
/* * Clear the CPU reservation bit */
li r0, 0 lwarx p0, r0, r0 stwcx. p0, r0, r0
#ifdef PPC405GP_REVA /* 設(shè)置中斷向量表到0x0000 */ li p0, 0x2100/4 mtctr p0 lis p0, WALNUT_EVPR_VAL li p1, 0x0000 zeroOut: stw p1,0x0(p0) addi p0, p0, 4 bdnz zeroOut #endif
/* 初始化堆棧 /* Initialize the stack pointer (r1) */
lis sp, HIADJ(STACK_ADRS) addi sp, sp, LO(STACK_ADRS)
#if FALSE /* SDA not supported */ /* initialize r2 and r13 according to EABI standard */
lis r2, HIADJ(_SDA2_BASE_) addi r2, r2, LO(_SDA2_BASE_) lis r13, HIADJ(_SDA_BASE_) addi r13, r13, LO(_SDA_BASE_) #endif
/* 得到C程序romStart()在ROM中的地址,保證romInit執(zhí)行結(jié)束后,系統(tǒng)跳轉(zhuǎn)執(zhí)行romStart()
/* calculate C entry point: routine - entry point + ROM base */
lis p1, HIADJ(romStart) /* p1 = romstart */ addi p1, p1, LO(romStart)
lis p2, HIADJ(romInit) /* p2 = romInit */ addi p2, p2, LO(romInit)
/* ROM_TEXT_ADRS為ROM的入口地址,在文件makefile定義,為0xfff80100 lis p3, HIADJ(ROM_TEXT_ADRS) /* p3 = ROM_TEXT_ADRS */ addi p3, p3, LO(ROM_TEXT_ADRS)
subf p1, p2, p1 /* p1 = p1 - p2 */ add p1, p1, p3 /* p1 = p1 + p3 */ /* p1中是romStart()的地址,這里把這個地址放到連接寄存器LR中. mtlr p1 /* link register = C entry point */
or p0, p5, p5 /* p0 = startType */ addi sp, sp, -FRAMEBASESZ /* get frame stack */
/* 跳轉(zhuǎn)到LR中romStart()的地址,執(zhí)行romStart() blr /* branch to link register */
返回頁首
硬件中斷
中斷的產(chǎn)生和VxWorks系統(tǒng)的中斷操作:
一般中斷的產(chǎn)生是由硬件定義的,如串口中斷的定義:
1.接收中斷:當(dāng)接收中斷使能,接收數(shù)據(jù)存儲器 RxData 存在有效數(shù)據(jù),則產(chǎn)生中斷. 2.發(fā)送中斷:當(dāng)發(fā)送中斷使能,發(fā)送數(shù)據(jù)存儲器 TxData 為空,則產(chǎn)生中斷.
|

硬件發(fā)送中斷產(chǎn)生邏輯示意 |

硬件接收中斷產(chǎn)生邏輯示意 |
所以要產(chǎn)生一個串口中斷,主要有兩步:
1.使能這兩個串口中斷,RX Enable,TX Enable,函數(shù)intEnable(). 2.用intConnect()登記中斷號,和相應(yīng)的中斷例程ISR.
|
程序示例
在VxWorks系統(tǒng)上登記,使能串口中斷
intConnect((VOIDFUNCPTR *)5,ComISR,0); //登記中斷服務(wù)程序ComISR()到外部中斷號5,
intEnable((VOIDFUNCPTR *)5); //使能外部中斷5
//enable 使能 UART1 這里直接用32位地址表示了 *(unsigned long *)0x20000014 &= ~0x01000100; //INT_FORCE use pending *(unsigned long *)0x20000010 = 0x01000100; //INT_PENDING clear *(unsigned long *)0x20000018 = 0x01000100; //INT_MASK only enable UART1 RX
//control register 使能 RX TX *(unsigned long *)0x20000068 = 0x00070007; //RX and TX ENABLE
//divider register,baut rate 19200 設(shè)置波特率 *(unsigned long *)0x2000006c = 59;
//完成, 這樣當(dāng)串口有中斷發(fā)生時,硬件系統(tǒng)會自動跳轉(zhuǎn)到中斷號5的地址0x18,調(diào)用程序ComISP().
注意:中斷程序不能單步執(zhí)行,或跟蹤調(diào)試,中斷服務(wù)程序中與函數(shù)庫或系統(tǒng)有關(guān)的函數(shù)不可用如print()等,因為中斷調(diào)用時,所有其它的任務(wù)都被掛起停止運行.
返回頁首
VxWorks系統(tǒng)的網(wǎng)絡(luò)驅(qū)動(END)
VxWorks網(wǎng)絡(luò)配置參見VxWorks網(wǎng)絡(luò)驅(qū)動配置及分析
VxWorks系統(tǒng)網(wǎng)絡(luò)驅(qū)動在BSP中完成,寫驅(qū)動時應(yīng)參考BSP develop kit,在VxWorks中叫做END( Enhanced Network Driver),編寫程序使用由VxWorks定義的MUX接口
MUX是數(shù)據(jù)鏈路層和網(wǎng)絡(luò)協(xié)議層之間的接口
主要調(diào)用過程和步驟如下:
VxWorks系統(tǒng)執(zhí)行的第一個任務(wù)target\config\all\usrConfig.c文件中 usrRoot()=======>>
target\src\config\usrNetwork.c文件(該文件初始化TCP/IP)中 usrNetInit(BOOT_LINE_ADRS)(該函數(shù)作用是添加MUX END)========>>
pcooki = pCookie = muxDevLoad(pDevTbl->unit,.....)其中pDevTbl在BSP網(wǎng)絡(luò)配置文件configNet.h中定義.END_TBL_ENTRY endDevTbl[]={...},該表定義了網(wǎng)絡(luò)設(shè)備的具體參數(shù),在這里調(diào)用了網(wǎng)絡(luò)驅(qū)動
END_TBL_ENTRY endDevTbl [] = { {0, IBM_EMAC_LOAD_FUNC, IBM_EMAC_LOAD_STR_0, TRUE, NULL, FALSE}, {0, END_TBL_END, NULL, 0, NULL, FALSE}, }; 其中IBM_EMAC_LOAD_FUNC就是 ibmEmacEndLoad()
========>>muxDevStart(pcooki)==========>>ibmEmacEndLoad()
ibmEmacEndLoad()初始化系統(tǒng)為網(wǎng)絡(luò)驅(qū)動運行做準(zhǔn)備
MUX調(diào)用ibmEmacStart()
ibmEmacStart() 登記中斷服務(wù)程序ibmEmacInit(),啟動設(shè)備運行在中斷模式下.
LOCAL STATUS ibmEmacStart ( EMAC_DRV_CTRL * pDrvCtrl ) { int rc;
SYS_INT_CONNECT (pDrvCtrl, ibmEmacInt, pDrvCtrl, &rc); SYS_OUT_LONG(pDrvCtrl, EMAC_ISR, 0xFFFFFFFF); SYS_INT_ENABLE ();
/* Allow MAL EOB and Descriptor error interrupts */
malChannelIntMaskSet(MAL_TX_TYPE, pDrvCtrl->txChn0MalChannel, MAL_EOB_INT_EN | MAL_DE_INT_EN | MAL_SERR_INT_EN);
malChannelIntMaskSet(MAL_RX_TYPE, pDrvCtrl->rxChn0MalChannel, MAL_EOB_INT_EN | MAL_DE_INT_EN | MAL_SERR_INT_EN);
return (OK); }
中斷服務(wù)程序ibmEmacInit() 處理EMAC控制器的中斷,主要是 TX,RX狀態(tài)錯誤
LOCAL void ibmEmacInt ( EMAC_DRV_CTRL * pDrvCtrl ) { UINT isrReg;
/* Read the EMAC interrupt status register */
SYS_IN_LONG(pDrvCtrl, EMAC_ISR, isrReg); pDrvCtrl->errorEmac = isrReg;
/* * Check to see if there was a TX error. If there was, the Dead bit * will be set. Clear the status bits for the TX error, and clear the dead * bit. Keep count of these errors in the main device structure. */
if (isrReg & EMAC_ISR_TX_INTS) { pDrvCtrl->intErrorTX++; SYS_OUT_LONG(pDrvCtrl, EMAC_ISR, EMAC_ISR_TX_INTS); }
/* * Check to see if there was a RX error. Clear the status bits for the RX * error. Keep count of these errors in the main device structure. */
if (isrReg & EMAC_ISR_RX_INTS) { pDrvCtrl->intErrorRX++; SYS_OUT_LONG(pDrvCtrl, EMAC_ISR, EMAC_ISR_RX_INTS); }
return; }
(未完)
Cillus網(wǎng)卡CS8900A Linux驅(qū)動
下面是我為一個網(wǎng)友解釋的CS8900A網(wǎng)卡驅(qū)動文件中的部分函數(shù),操作系統(tǒng)為ucLinux,CPU是國內(nèi)常用的Motorola龍珠系列MC68EZ328(16M),相比PowerPC和ARM來說,它的結(jié)構(gòu)簡單,不帶MMU,較易理解
CS8900A是一個16位網(wǎng)卡,支持ISA總線,10-BastT.
static inline void outw(unsigned short value,unsigned int addr) { unsigned short newvalue; unsigned char *_src=(unsigned char*)(&value),*_dest=(unsigned char*)(&newvalue);
//這里為什么要交換一下?
////++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //這里不是交換,而是賦值,將16位分成兩個8位的數(shù)組,分別賦值,16位寄存器是只有后8位可讀寫, //前8位是寄存器ID,所以這里吧后8位放在前面"_dest[0]=_src[1];" //然后通過I/O口,賦給相應(yīng)的存儲器,即"*(volatile unsigned short*)addr=newvalue;" ///+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_dest[0]=_src[1]; _dest[1]=_src[0]; *(volatile unsigned short*)addr=newvalue; }
static int cs89x0_probe1(struct device *dev, int ioaddr) { struct net_local *lp; static unsigned version_printed = 0; int i; unsigned rev_type = 0;
irq2dev_map[0] = dev;
/* set up the chip select */
//下面這一段該怎么理解?看不懂阿 ////++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //這里是對CPU進行操作,對cs89進行初始化,我沒有見到你的硬件原理圖,我只能按CPU //的結(jié)構(gòu)定義來解釋一下,你要想搞清楚,只有看硬件原理圖,還要參考CPU的硬件手冊 ////++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//連通PORT F I/O功能管腳1,SEL1(-IRQ5/PF1), *(volatile unsigned char *)0xfffff42b |= 0x02; /* output /sleep */ //設(shè)置PORT F 管腳0為輸出,輸出高電平 *(volatile unsigned short *)0xfffff428 |= 0x0101; /* not sleeping */
//連通PORT F 中斷功能管腳1,SEL1(-IRQ5/PF1) *(volatile unsigned char *)0xfffff42b &= ~0x02; /* input irq5 */ //PORT F 管腳1,SEL1(-IRQ5/PF1) 為輸入方式,置低電平有效 *(volatile unsigned short *)0xfffff428 &= ~0x0202; /* irq5 fcn on */ //在寄存器CSGBB中定義片選及cs89的基地址為:0x10000000.++++非常重要+++++++ *(volatile unsigned short *)0xfffff102 = 0x8000; /* 0x04000000 */ //在寄存器CSB中,片選使能,cs89地址空間大小(1M),數(shù)據(jù)線寬16位,6個等待周期,FLASH..., //非保護存儲空間(128K)...... *(volatile unsigned short *)0xfffff112 = 0x01e7; /* 128k, 2ws, FLASH, en */ //對PORT G操作........ *(volatile unsigned int *)0xfffff430 = 0x023c3d0a; ////++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //這是I/O模式的主要的兩個PORT口,一個是地址口,一個是數(shù)據(jù)口,這里對0x22操作, //中斷IRQ0 ///+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ *(volatile unsigned short*)0x1000030a=0x2200; *(volatile unsigned short*)0x1000030c=0;
//*(volatile unsigned short *)0xfffff302 |= 0x0080; ......................
.....................
void reset_chip(struct device *dev) { int reset_start_time; writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);
/* wait 30 ms */ current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + 3; schedule();
/* Wait until the chip is reset */ //這里jiffies說是timestamp,時間標(biāo)記,這個變量和current //都在哪里定義? //jiffies主要起什么作用? ////+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //這里是個延時等待,reset以后必須有等待,以便reset徹底完成,在reset過程中所有寄存器是關(guān)閉的 //不但對cs89,對其他芯片也是一樣的 ///++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ reset_start_time = jiffies; while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time< 2); }
static int net_open(struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int result = 0; int i;
write_irq(dev, lp->chip_type, 0);
irq2dev_map[/* FIXME */ 0] = dev; writereg(dev, PP_BusCTL, 0); /* ints off! */
//這里和上面那個一樣,怎么看懂? ////++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //這里也是CPU對CS89操作,我也根據(jù)CPU硬件手冊給你大概說一下 ///+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//中斷信號,正電平觸發(fā)(POL5) *(volatile unsigned short *)0xfffff302 |= 0x0080; /* +ve pol irq */
//調(diào)整PORT G的輸入輸出狀態(tài),及設(shè)置管腳相應(yīng)的電平信號 *(volatile unsigned int *)0xfffff430 = 0x023c3d0a; /* low -> high */ *(volatile unsigned int *)0xfffff430 = 0x023e3d0a; *(volatile unsigned int *)0xfffff430 = 0x023c3d0a; /* high -> low */
////++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //這是I/O模式的主要的兩個PORT口,一個是地址口,一個是數(shù)據(jù)口,這里對0x22操作, //中斷IRQ0 ///+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ *(volatile unsigned short *)0x1000030a = 0x2200; /* index window, REG index : 0022h */ *(volatile unsigned short *)0x1000030c = 0x0000; /* data window, REG data : 0000h,irq0 */ .........................
.........................
static void net_rx(struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; struct sk_buff *skb; int status, length;
//下面兩行怎么右邊是一樣的? //是作者寫錯了嗎? ////++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++| //不是,這是一個包中前后不同的兩個數(shù)據(jù),前一個數(shù)據(jù)是該數(shù)據(jù)包的狀態(tài),后一個是數(shù)據(jù)包的長度 ////++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ status = inw(ioaddr + RX_FRAME_PORT); length = inw(ioaddr + RX_FRAME_PORT); if ((status & RX_OK) == 0) { lp->stats.rx_errors++; if (status & RX_RUNT) lp->stats.rx_length_errors++; if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++; if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT))) /* per str 172 */ lp->stats.rx_crc_errors++; if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++; return; }
......................
static int set_mac_address(struct device *dev, void *addr) { int i; if (dev->start) return -EBUSY; if(get_arena_addr()) { memcpy(dev->dev_addr,0x1100000,6); } else { //這里的00hhcnl和前面 //出現(xiàn)的00hhcn是什么意思? ////+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //注意:在這里他更改了網(wǎng)卡的MAC值,隨便給了一個值"0x00,0x00,‘h‘,h‘,‘c‘,‘n‘", //不過這個48位值必須是世界唯一的,或者用網(wǎng)卡自帶的也可以.我不能確定是否eeprom中有信息, //你可以用示波器量一下EEDI管腳,若為高電平,則EEPROM用到了,否則,他們根本沒有用EEPROM. ///++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ unsigned char mac[]={0,0,‘h‘,‘h‘,‘c‘,‘n‘}; memcpy(dev->dev_addr,mac,6); } printk("%s: Setting MAC address to ", dev->name); for (i = 0; i < 6; i++) printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]); printk(".\n"); /* set the Ethernet address */ for (i=0; i < ETH_ALEN/2; i++) writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
return 0; }
返回頁首
LCD 與觸摸屏
返回頁首
Modem撥號
Modem撥號程序步驟如下
1. off hook,發(fā)出摘機命令(ATH1\r), 等待modem返回狀態(tài),如果是"OK",則表示成功.進行第二步. 2. on hook 發(fā)出掛機命令(ATH\r), 等待modem返回狀態(tài),如果是"OK",則表示成功.進行第三步. 3. off hook,dialing,摘機撥號(ATDT....\r), 等待modem返回狀態(tài),如果是"CONNECT",則表示成功.進行第四步. 4. send data,發(fā)送數(shù)據(jù).
最好按上述步驟一步一步調(diào),并要等待正確的返回值后再進行下一步.
具體程序例子如下,撥號:
// 清空接收FIFO REG(FCR, nsChan) |=FCR_RXCLR; // 等待,直到清空為止 while((REG(FCR, nsChan) & FCR_RXCLR) != 0x00); // 撥號 while(atdt1[i]!=0) { // 檢查發(fā)送FIFO是否準(zhǔn)備好,為空 while((REG(LSR, nsChan) & LSR_THRE) == 0x00); // 在發(fā)送FIFO中放入數(shù)據(jù) REG(THR, nsChan) = atdt1[i]; i++; } // 等待是否有數(shù)據(jù)到達,即modem返回數(shù)據(jù). while((REG(LSR, nsChan) & LSR_DR) == 0x00); // 接收數(shù)據(jù)并判斷返回值 response[i-19]=REG(RBR,nsChan); if(response[0]!=0x43) .................. else .................. // 如果返回值是"connect", while(*data!=0) { while((REG(LSR, nsChan) & LSR_THRE) == 0x00); REG(THR, nsChan) = *data++; } 其他步驟基本一樣.
這是在ARM7上做的modem驅(qū)動,硬件設(shè)計方法是modem集成在主板上,沒有用串口,modem是用片選地址直接對硬件操作的.
返回頁首
RTC
返回頁首
|