1693|0

1668

帖子

0

TA的资源

五彩晶圆(初级)

楼主
 

MSP430与MMC/SD卡接口设计 [复制链接]

这是一个MSP430与MMC/SD卡接口设计,提供纯源代码。真正DIY设计!
  由Rolf Freitag先生提供。
原文:A self documenting project (C source code) for reading/writing on MMC/SD cards in spi mode and with a hello world LED as output. The code works with many MMC/SD cards but not all; it is beta. The reasons are that some waiting times are not limited in the standard and that the cards are a little outside the standard specifications.
For a release version, which does not cost much and which has a mapping layer for reading/writing 1..512 Bytes starting at any address, you can contact me.
In 2003 TI planned to release an application note to this code but it seems that plan died.
I published the code under a beerware license:
     main.c  mmc.c  mmc.h  led.c  led.h

main.c
/*********************************************************

Program for Communikation of an MSP430F149 and an MMC via SPI in unprotected Mode.
Sytem quartz: 8 MHz, layout: see mmc.h.

Version 0.02 from 11. May 2003

Status: Everything works, but approx. 2 % of all MMC/SDCs do need some longer waiting cycles,
because some times are not limitated in the standards and every card is not strictly standard
conforming; they all do need more waiting cycles as specified in the standards.
*********************************************************/
/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 43):
 * Rolf Freitag (webmaster at true-random.com) wrote this file.
 * As long as you retain this notice you can do whatever
 * the LGPL (Lesser GNU public License) allows with this stuff.
 * If you think this stuff is worth it, you can send me money via
 * paypal or if we met some day you can buy me a beer in return.
 * ----------------------------------------------------------------------------
 */
#include  <msp430x14x.h>
#include  <string.h>
#include "mmc.h"
#include "led.h"

extern char card_state;

extern char mmc_buffer[512];

char card_state = 0;                              // card state: 0: not found, 1 found (init successfull)
unsigned long loop;

void main (void)
{
  volatile unsigned char dco_cnt = 255;

  BCSCTL1 &= ~XT2OFF;                             // XT2on
  do                                              // wait for MCLK from quartz
  {
    IFG1 &= ~OFIFG;                               // Clear OSCFault flag
    for (dco_cnt = 0xff; dco_cnt > 0; dco_cnt--); // Time for flag to set
  }
  while ((IFG1 & OFIFG) != 0);                    // OSCFault flag still set?

  WDTCTL = WDTPW + WDTHOLD;                       // Stop WDT

  BCSCTL1 = 0x07;                                 // LFXT1: XT2on: LF quartz for MCLK

  BCSCTL2 = SELM1 + SELS;                         // LFXT2: use HF quartz (XT2)

  DCOCTL = 0xe0;

  P3SEL = 0x00;
  P3DIR = 0xcf;
  P3OUT = 0x0f;

  // Port 4 Function           Dir     On/Off
  //         4.0-Led red       Out       0 - off   1 - On
  //         4.1-Led green     Out       0 - off   1 - On
  //         4.5-CardDetected   ?        0 - ?     1 - ?
  //         4.6-WriteProtected ?        0 - ?     1 - ?
  // D 7 6 5 4 3 2 1 0
  P4SEL = 0x00;                                   //   0 0 0 0 0 0 0 0
  P4DIR = 0x03;                                   //   0 0 0 0 0 0 1 1
  P4OUT = 0x00;

  // Port 5 Function           Dir       On/Off
  //         5.1-Dout          Out       0 - off    1 - On
  //         5.2-Din           Inp       0 - off    1 - On
  //         5.3-Clk           Out       -
  //         5.4-mmcCS         Out       0 - Active 1 - none Active

  P5SEL = 0x00;
  P5DIR = 0xff;
  P5OUT = 0xfe;

  P6SEL = 0x00;
  P6OUT = 0x00;
  P6DIR = 0xff;

  ADC12IE = 0;
  ADC12IFG = 0;

  initLED();
  for (;;)
  {
    // switch on red led to indicate -> insert card

    // #ifdef DeBuG0
    RED_LED_ON();
    GREEN_LED_OFF();
    // Card insert?
    while(P4IN&0x20);
    //switch off both led's
    GREEN_LED_OFF();
    RED_LED_OFF();
    //init mmc card
    if (initMMC() == MMC_SUCCESS)                 // card found
    {
      card_state |= 1;
      GREEN_LED_ON();
      // Read Out Card Type and print it or trace memory
      memset(&mmc_buffer,0,512);
      mmcReadRegister (10, 16);
      mmc_buffer[7]=0;
      // PLease mofify based on your Compiler sim io function
      // debug_printf("Multi Media Card Name: %s",&mmc_buffer[3]);

      // Fill first Block (0) with 'A'
      memset(&mmc_buffer,'A',512);                //set breakpoint and trace mmc_buffer contents
      mmcWriteBlock(0x00);
      // Fill second Block (1)-AbsAddr 512 with 'B'
      memset(&mmc_buffer,'B',512);
      mmcWriteBlock(512);

      // Read first Block back to buffer
      memset(&mmc_buffer,0x00,512);
      mmcReadBlock(0x00,512);
      memset(&mmc_buffer,0x00,512);               //set breakpoint and trace mmc_buffer contents
      mmcReadBlock(512,512);
      memset(&mmc_buffer,0x00,512);               //set breakpoint and trace mmc_buffer contents
    }

    else
    {
      //Error card not detected or rejected during writing
      // switch red led on
      card_state = 0;                             // no card
      RED_LED_ON();
    }

    // #endif

  }
  //  return;
}

mmc.h
/*
  mmc.h: Dekcarations for Communikation with the MMC (see mmc.c) in unprotected spi mode.

Pin configuration at MSP430F149:
--------------------------------
  MC                    MC Pin          MMC                      MMC Pin
  P5.4                  48              ChipSelect               1
  P5.1 / SlaveInMasterOut 45            DataIn                   2
  .                                     GND                      3 (0 V)
  .                                     VDD                      4 (3.3 V)
  P5.3 UCLK1 / SlaveCLocK 47            Clock                    5
  .                                     GND                      6 (0 V)
  P5.2 / SlaveOutMasterIn 46            DataOut                  7
  P5.4                                  CardDetect with pullup
---------------------------------------------------------------------

 Revisions
 Date           Author                                  Revision
 11. May 2003           Rolf Freitag                            0.02
(2004: corrected MC pin numbers (switched only 45, 46))
*/
/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 44):
 * Rolf Freitag (webmaster at true-random.com) wrote this file.
 * As long as you retain this notice you can do whatever
 * the LGPL (Lesser GNU public License) allows with this stuff.
 * If you think this stuff is worth it, you can send me money via
 * paypal or if we met some day you can buy me a beer in return.
 * ----------------------------------------------------------------------------
 */
#ifndef _MMCLIB_H
#define _MMCLIB_H

#ifndef TXEPT                                     // transmitter-empty flag
#define TEXPT 0x01
#endif

// macro defines
#define HIGH(a) ((a>>8)&0xFF)                     // high byte from word
#define LOW(a) (a&0xFF)                           // low byte from word

#define CS_LOW()  P5OUT &= ~0x10                  // Card Select
#define CS_HIGH() P5OUT |= 0x10                   // Card Deselect
#define SPI_RXC (IFG2 & URXIFG1)
#define SPI_TXC (IFG2 & UTXIFG1)

#define SPI_RX_COMPLETE (IFG2 & URXIFG1)
#define SPI_TX_READY (IFG2 & UTXIFG1)

#define DUMMY 0xff

// Tokens (nessisary because at nop/idle (and CS active) only 0xff is on the data/command line)
#define MMC_START_DATA_BLOCK_TOKEN    0xfe        // Data token start byte, Start Single Block Read
#define MMC_START_DATA_MULTIPLE_BLOCK_READ  0xfe  // Data token start byte, Start Multiple Block Read
#define MMC_START_DATA_BLOCK_WRITE    0xfe        // Data token start byte, Start Single Block Write
#define MMC_START_DATA_MULTIPLE_BLOCK_WRITE 0xfc  // Data token start byte, Start Multiple Block Write
#define MMC_STOP_DATA_MULTIPLE_BLOCK_WRITE  0xfd  // Data toke stop byte, Stop Multiple Block Write

// an affirmative R1 response (no errors)
#define MMC_R1_RESPONSE       0x00

// this variable will be used to track the current block length
// this allows the block length to be set only when needed
// unsigned long _BlockLength = 0;

// error/success codes
#define MMC_SUCCESS           0x00
#define MMC_BLOCK_SET_ERROR   0x01
#define MMC_RESPONSE_ERROR    0x02
#define MMC_DATA_TOKEN_ERROR  0x03
#define MMC_INIT_ERROR        0x04
#define MMC_CRC_ERROR         0x10
#define MMC_WRITE_ERROR       0x11
#define MMC_OTHER_ERROR       0x12
#define MMC_TIMEOUT_ERROR     0xFF

// commands: first bit 0 (start bit), second 1 (transmission bit); CMD-number + 0ffsett 0x40
#define MMC_GO_IDLE_STATE   0x40                  //CMD0
#define MMC_SEND_OP_COND  0x41                    //CMD1
#define MMC_READ_CSD    0x49                      //CMD9
#define MMC_SEND_CID    0x4a                      //CMD10
#define MMC_STOP_TRANSMISSION   0x4c              //CMD12
#define MMC_SEND_STATUS   0x4d                    //CMD13
#define MMC_SET_BLOCKLEN  0x50                    //CMD16 Set block length for next read/write
#define MMC_READ_SINGLE_BLOCK   0x51              //CMD17 Read block from memory
#define MMC_READ_MULTIPLE_BLOCK 0x52              //CMD18
#define MMC_CMD_WRITEBLOCK  0x54                  //CMD20 Write block to memory
#define MMC_WRITE_BLOCK   0x58                    //CMD25
#define MMC_WRITE_MULTIPLE_BLOCK 0x59             //CMD??
#define MMC_WRITE_CSD     0x5b                    //CMD27 PROGRAM_CSD
#define MMC_SET_WRITE_PROT  0x5c                  //CMD28
#define MMC_CLR_WRITE_PROT  0x5d                  //CMD29
#define MMC_SEND_WRITE_PROT   0x5e                //CMD30
#define MMC_TAG_SECTOR_START  0x60                //CMD32
#define MMC_TAG_SECTOR_END  0x61                  //CMD33
#define MMC_UNTAG_SECTOR  0x62                    //CMD34
#define MMC_TAG_EREASE_GROUP_START 0x63           //CMD35
#define MMC_TAG_EREASE_GROUP_END 0x64             //CMD36
#define MMC_UNTAG_EREASE_GROUP  0x65              //CMD37
#define MMC_EREASE    0x66                        //CMD38
#define MMC_READ_OCR    0x67                      //CMD39
#define MMC_CRC_ON_OFF    0x68                    //CMD40

//TI added sub function for top two spi_xxx

// mmc init
char initMMC (void);
// send command to MMC
void mmcSendCmd (const char cmd, unsigned long data, const char crc);
// set MMC block length of count=2^n Byte
char mmcSetBlockLength (const unsigned long);
// read a size Byte big block beginning at the address.
char mmcReadBlock(const unsigned long address, const unsigned long count);
// write a 512 Byte big block beginning at the (aligned) adress
char mmcWriteBlock (const unsigned long address);
// Register arg1 der Laenge arg2 auslesen (into the buffer)
char mmcReadRegister(const char, const unsigned char);
#endif                                            /* _MMCLIB_H */

mmc.c
// mmc.c : MultiMediaCard functions: init, read, write ...
// Works also with SC cars. Modes: SPI mode.
//
// Rolf Freitag 5/2003
//
/* See also:
http://www.sandisk.com/pdf/oem/ProdManualSDCardv1.9.pdf Sandisk SD card product manual
http://www.sandisk.com/pdf/oem/ProdManualminiSDv1.1.pdf MiniSD card
http://www.sandisk.com/download/Product%20Manuals/Product%20ManualSDCardv1.7.pdf Older SD card
http://www.compile-it.com/support/crndatasheets/MMC%20ADAPTER.pdf
*/

/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 44):
 * Rolf Freitag (webmaster at true-random.com) wrote this file.
 * As long as you retain this notice you can do whatever
 * the LGPL (Lesser GNU public License) allows with this stuff.
 * If you think this stuff is worth it, you can send me money via
 * paypal or if we met some day you can buy me a beer in return.
 * ----------------------------------------------------------------------------
 */

// MMC Lib
#ifndef _MMCLIB_C
#define _MMCLIB_C
//---------------------------------------------------------------------
#include "mmc.h"
#include "led.h"

#include  "MSP430x14x.H"
#include  "math.h"
#include  "string.h"

char mmcGetResponse(void);
char mmcGetXXResponse(const char resp);
char mmcCheckBusy(void);

void initSPI (void);
unsigned char spiSendByte(const unsigned char data);

char mmc_buffer[512] =                            // Buffer for mmc i/o for data and registers
{
  0
};

extern char card_state;                           // 0 for no card found, 1 for card found (init successfull)

//---------------------------------------------------------------------

// setup usart1 in spi mode
void initSPI (void)
{
  ME2 |= USPIE1;                                  // Enable USART1 SPI mode
  UTCTL1 = CKPH | SSEL1 | SSEL0 | STC;            // SMCLK, 3-pin mode, clock idle low, data valid on rising edge, UCLK delayed
  UBR01 = 0x02;                                   // 0x02: UCLK/2 (4 MHz), works also with 3 and 4
  UBR11 = 0x00;                                   // -"-
  UMCTL1 = 0x00;                                  // no modulation
  UCTL1 = CHAR | SYNC | MM;                       // 8-bit SPI Master **SWRST**
  P5SEL |= 0x0E;                                  // P5.1-3 SPI option select
  P5DIR |= 0x01;                                  // P5.0 output direction
  P5OUT = 0xff;
  while (!(IFG2 & UTXIFG1));                      // USART1 TX buffer ready (empty)?
  // debug_printf("init......SPI");
}


// Initialisieren
char initMMC (void)
{

  //raise SS and MOSI for 80 clock cycles
  //SendByte(0xff) 10 times with SS high
  //RAISE SS
  int i;
  char response=0x01;

  // debug_printf("Start iniMMC......");
  initSPI();
  //initialization sequence on PowerUp
  CS_HIGH();
  for(i=0;i<=9;i++)
    spiSendByte(0xff);
  CS_LOW();
  //Send Command 0 to put MMC in SPI mode
  mmcSendCmd(0x00,0,0x95);
  //Now wait for READY RESPONSE
  if(mmcGetResponse()!=0x01);
  //       debug_printf("no responce");

  while(response==0x01)
  {
    //  debug_printf("Sending Command 1");
    CS_HIGH();
    spiSendByte(0xff);
    CS_LOW();
    mmcSendCmd(0x01,0x00,0xff);
    response=mmcGetResponse();
  }
  CS_HIGH();
  spiSendByte(0xff);
  // debug_printf("MMC INITIALIZED AND SET TO SPI MODE PROPERLY.");
  return MMC_SUCCESS;
}


// Ti added mmc Get Responce
char mmcGetResponse(void)
{
  //Response comes 1-8bytes after command
  //the first bit will be a 0
  //followed by an error code
  //data will be 0xff until response
  int i=0;

  char response;

  while(i<=64)
  {
    response=spiSendByte(0xff);
    if(response==0x00)break;
    if(response==0x01)break;
    i++;
  }
  return response;
}


char mmcGetXXResponse(const char resp)
{
  //Response comes 1-8bytes after command
  //the first bit will be a 0
  //followed by an error code
  //data will be 0xff until response
  int i=0;

  char response;

  while(i<=500)
  {
    response=spiSendByte(0xff);
    if(response==resp)break;
    i++;
  }
  return response;
}


char mmcCheckBusy(void)
{
  //Response comes 1-8bytes after command
  //the first bit will be a 0
  //followed by an error code
  //data will be 0xff until response
  int i=0;

  char response;
  char rvalue;
  while(i<=64)
  {
    response=spiSendByte(0xff);
    response &= 0x1f;
    switch(response)
    {
      case 0x05: rvalue=MMC_SUCCESS;break;
      case 0x0b: return(MMC_CRC_ERROR);
      case 0x0d: return(MMC_WRITE_ERROR);
      default:
        rvalue = MMC_OTHER_ERROR;
        break;
    }
    if(rvalue==MMC_SUCCESS)break;
    i++;
  }
  i=0;
  do
  {
    response=spiSendByte(0xff);
    i++;
  }while(response==0);
  return response;
}


// The card will respond with a standard response token followed by a data
// block suffixed with a 16 bit CRC.

// Ti Modification: long int -> long ; int -> long
char mmcReadBlock(const unsigned long address, const unsigned long count)
{
  unsigned long i = 0;
  char rvalue = MMC_RESPONSE_ERROR;

  // Set the block length to read
  if (mmcSetBlockLength (count) == MMC_SUCCESS)   // block length could be set
  {
    // SS = LOW (on)
    CS_LOW ();
    // send read command MMC_READ_SINGLE_BLOCK=CMD17
    mmcSendCmd (17,address, 0xFF);
    // Send 8 Clock pulses of delay, check if the MMC acknowledged the read block command
    // it will do this by sending an affirmative response
    // in the R1 format (0x00 is no errors)
    if (mmcGetResponse() == 0x00)
    {
      // now look for the data token to signify the start of
      // the data
      if (mmcGetXXResponse(MMC_START_DATA_BLOCK_TOKEN) == MMC_START_DATA_BLOCK_TOKEN)
      {
        // clock the actual data transfer and receive the bytes; spi_read automatically finds the Data Block
        for (i = 0; i < 512; i++)
          mmc_buffer = spiSendByte(0xff);      // is executed with card inserted

        // get CRC bytes (not really needed by us, but required by MMC)
        spiSendByte(0xff);
        spiSendByte(0xff);
        rvalue = MMC_SUCCESS;
      }
      else
      {
        // the data token was never received
        rvalue = MMC_DATA_TOKEN_ERROR;            // 3
      }
    }
    else
    {
      // the MMC never acknowledge the read command
      rvalue = MMC_RESPONSE_ERROR;                // 2
    }
  }
  else
  {
    rvalue = MMC_BLOCK_SET_ERROR;                 // 1
  }
  CS_HIGH ();
  spiSendByte(0xff);
  return rvalue;
}                                                 // mmc_read_block


//---------------------------------------------------------------------
// Ti Modification: long int -> long
char mmcWriteBlock (const unsigned long address)
{
  unsigned long i = 0;
  char rvalue = MMC_RESPONSE_ERROR;               // MMC_SUCCESS;
  char c = 0x00;

  // Set the block length to read
  if (mmcSetBlockLength (512) == MMC_SUCCESS)     // block length could be set
  {
    // SS = LOW (on)
    CS_LOW ();
    // send write command
    mmcSendCmd (24,address, 0xFF);

    // check if the MMC acknowledged the write block command
    // it will do this by sending an affirmative response
    // in the R1 format (0x00 is no errors)
    if (mmcGetXXResponse(MMC_R1_RESPONSE) == MMC_R1_RESPONSE)
    {
      spiSendByte(0xff);
      // send the data token to signify the start of the data
      spiSendByte(0xfe);
      // clock the actual data transfer and transmitt the bytes
      for (i = 0; i < 512; i++)
        spiSendByte(mmc_buffer);               // mmc_buffer;       Test: i & 0xff
      // put CRC bytes (not really needed by us, but required by MMC)
      spiSendByte(0xff);
      spiSendByte(0xff);
      // read the data response xxx0<status>1 : status 010: Data accected, status 101: Data
      //   rejected due to a crc error, status 110: Data rejected due to a Write error.
      mmcCheckBusy();
    }
    else
    {
      // the MMC never acknowledge the write command
      rvalue = MMC_RESPONSE_ERROR;                // 2
    }
  }
  else
  {
    rvalue = MMC_BLOCK_SET_ERROR;                 // 1
  }
  // give the MMC the required clocks to finish up what ever it needs to do
  //  for (i = 0; i < 9; ++i)
  //    spiSendByte(0xff);

  CS_HIGH ();
  // Send 8 Clock pulses of delay.
  spiSendByte(0xff);
  return rvalue;
}                                                 // mmc_write_block


//---------------------------------------------------------------------
void mmcSendCmd (const char cmd, unsigned long data, const char crc)
{
  char frame[6];
  char temp;
  int i;

  frame[0]=(cmd|0x40);
  for(i=3;i>=0;i--)
  {
    temp=(char)(data>>(8*i));
    frame[4-i]=(temp);
  }
  frame[5]=(crc);
  for(i=0;i<6;i++)
    spiSendByte(frame);
}


//--------------- set blocklength 2^n ------------------------------------------------------
// Ti Modification: long int-> long
char mmcSetBlockLength (const unsigned long blocklength)
{
  char rValue = MMC_TIMEOUT_ERROR;
  char i = 0;

  // SS = LOW (on)
  CS_LOW ();

  // Set the block length to read
  //MMC_SET_BLOCKLEN =CMD16
  mmcSendCmd(16, blocklength, 0xFF);

  // get response from MMC - make sure that its 0x00 (R1 ok response format)
  if(mmcGetResponse()!=0x00);

  CS_HIGH ();

  // Send 8 Clock pulses of delay.
  spiSendByte(0xff);

  return MMC_SUCCESS;
}                                                 // block_length


//TI added substitution routine for spi_read and spi_write

unsigned char spiSendByte(const unsigned char data)
{
  while ((IFG2&UTXIFG1) ==0);                     // wait while not ready / for RX
  TXBUF1 = data;                                  // write
  while ((IFG2 & URXIFG1)==0);                    // wait for RX buffer (full)
  return (RXBUF1);
}


// Reading the contents of the CSD and CID registers in SPI mode is a simple
// read-block transaction.

char mmcReadRegister (const char cmd_register, const unsigned char length)
{
  char uc = 0;
  char rvalue = MMC_TIMEOUT_ERROR;
  //  char i = 0;

  if (mmcSetBlockLength (length) == MMC_SUCCESS)
  {
    CS_LOW ();
    // CRC not used: 0xff as last byte
    mmcSendCmd(cmd_register, 0x000000, 0xff);

    // wait for response
    // in the R1 format (0x00 is no errors)
    if (mmcGetResponse() == 0x00)
    {
      if (mmcGetXXResponse(0xfe)== 0xfe)
        for (uc = 0; uc < length; uc++)
          mmc_buffer[uc] = spiSendByte(0xff);
      // get CRC bytes (not really needed by us, but required by MMC)
      spiSendByte(0xff);
      spiSendByte(0xff);
    }
    else
      rvalue = MMC_RESPONSE_ERROR;
    // CS = HIGH (off)
    CS_HIGH ();

    // Send 8 Clock pulses of delay.
    spiSendByte(0xff);
  }
  CS_HIGH ();
  return rvalue;
}                                                 // mmc_read_register


//---------------------------------------------------------------------
#endif                                            /* _MMCLIB_C */

led.h
/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 43):
 * Rolf Freitag (webmaster at true-random.com) wrote this file.
 * As long as you retain this notice you can do whatever
 * the LGPL (Lesser GNU public License) allows with this stuff.
 * If you think this stuff is worth it, you can send me money via
 * paypal or if we met some day you can buy me a beer in return.
 * ----------------------------------------------------------------------------
 */
#ifndef _LED_H
#define _LED_H
#include  <msp430x14x.h>

#define GREEN_LED_ON()  P4OUT |=  0x02
#define GREEN_LED_OFF() P4OUT &= ~0x02

#define RED_LED_ON()    P4OUT |=  0x01
#define RED_LED_OFF()   P4OUT &= ~0x01

void initLED(void);
#endif

led.c
/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 44):
 * Rolf Freitag (webmaster at true-random.com) wrote this file.
 * As long as you retain this notice you can do whatever
 * the LGPL (Lesser GNU public License) allows with this stuff.
 * If you think this stuff is worth it, you can send me money via
 * paypal or if we met some day you can buy me a beer in return.
 * ----------------------------------------------------------------------------
 */
#include  <msp430x14x.h>

void initLED(void)
{
  P4DIR |= 0x03;
  P4SEL &= ~0x03;
  P4OUT = 0x03;
}
 

 
点赞 关注

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表