返回列表 发帖

从一张图分析SD卡识别模式阶段的原理和驱动调试分析

从一张图分析SD卡识别模式阶段的原理和驱动调试分析

从一张图分析SD卡识别模式阶段的原理和驱动调试分析

嵌入式开发联盟 mcuos.com 原创

osboymcuos.com@gmail.com




近期调试和编写SD卡驱动,在做SD卡培训的时候画的一张图,了解初始化阶段的codes和协议原理真的很重要,否则会经常遇到SD卡经常不能识别的问题就没有办法调试了。




(1)图中的Y轴坐标表示SD卡支持的电压,一般都是2.7-3.6v之间。X轴为时间坐标。
(2)power up time阶段:

这段时间为插上SD卡,到sd卡的的供电电压达到最低要求电压的这段时间。这个时候sd clock还没正常提供,处于禁止状态,Linux在这段时间内delay 10ms。

(3)supply ramp up time阶段:

(2)(3)阶段时间段,对应Linux mmc子系统的codes为:

  1. /*
  2. * Apply power to the MMC stack.  This is a two-stage process.
  3. * First, we enable power to the card without the clock running.
  4. * We then wait a bit for the power to stabilise.  Finally,
  5. * enable the bus drivers and clock to the card.
  6. *
  7. * We must _NOT_ enable the clock prior to power stablising.
  8. *
  9. * If a host does all the power sequencing itself, ignore the
  10. * initial MMC_POWER_UP stage.
  11. */
  12. static void mmc_power_up(struct mmc_host *host)
  13. {
  14. int bit;
  15. /* If ocr is set, we use it */
  16. if (host->ocr)
  17.   bit = ffs(host->ocr) - 1;
  18. else
  19.   bit = fls(host->ocr_avail) - 1;
  20. host->ios.vdd = bit;
  21. if (mmc_host_is_spi(host)) {
  22.   host->ios.chip_select = MMC_CS_HIGH;
  23.   host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
  24. } else {
  25.   host->ios.chip_select = MMC_CS_DONTCARE;
  26.   host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
  27. }
  28. host->ios.power_mode = MMC_POWER_UP;
  29. host->ios.bus_width = MMC_BUS_WIDTH_1;
  30. host->ios.timing = MMC_TIMING_LEGACY;
  31. mmc_set_ios(host);//这段code被调用之前,为状态(2)power up time时间段,这段时间内host->ios.clock被设置为0.
  32. /*
  33.   * This delay should be sufficient to allow the power supply
  34.   * to reach the minimum voltage.
  35.   */
  36. mmc_delay(10);
  37. host->ios.clock = host->f_init;
  38. host->ios.power_mode = MMC_POWER_ON;
  39. mmc_set_ios(host);//这段code之前属于supply ramp up time阶段,这段时间内host->ios.clock被设置为最小值,我们在驱动中会设置这个值,这个值应该小于等于400KHZ.
  40. /*
  41.   * This delay must be at least 74 clock sizes, or 1 ms, or the
  42.   * time required to reach a stable voltage.
  43.   */
  44. mmc_delay(10);//这个延时是等sd host给出74个clocks。74个clocks期间CMD线拉高,这个时候不能发送任何命令给SD卡。这个延时过后,系统就可以发送命令给sd card了。
  45. }
复制代码

(4)CMD0阶段

对应linux驱动中的code为:

  1. int mmc_go_idle(struct mmc_host *host)
  2. {
  3. int err;
  4. struct mmc_command cmd;
  5. /*
  6.   * Non-SPI hosts need to prevent chipselect going active during
  7.   * GO_IDLE; that would put chips into SPI mode.  Remind them of
  8.   * that in case of hardware that won't pull up DAT3/nCS otherwise.
  9.   *
  10.   * SPI hosts ignore ios.chip_select; it's managed according to
  11.   * rules that must accomodate non-MMC slaves which this layer
  12.   * won't even know about.
  13.   */
  14. #if 0
  15. if (!mmc_host_is_spi(host)) {
  16.   mmc_set_chip_select(host, MMC_CS_HIGH);
  17.   mmc_delay(1);
  18. }
  19. #endif
  20. memset(&cmd, 0, sizeof(struct mmc_command));
  21. cmd.opcode = MMC_GO_IDLE_STATE;
  22. cmd.arg = 0;
  23. cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
  24. err = mmc_wait_for_cmd(host, &cmd, 0);
  25. mmc_delay(1);
  26. if (!mmc_host_is_spi(host)) {
  27.   mmc_set_chip_select(host, MMC_CS_DONTCARE);
  28.   mmc_delay(1);
  29. }
  30. host->use_spi_crc = 0;
  31. return err;
  32. }
复制代码

这段时间sd进入idle状态。

(5)CMD8阶段

sd host发送cmd8来check sd host端支持的电压 host->ocr_avail是否被sd卡支持,如果sd支持的话那么在cmd8的response中会返回这些支持的值,并且返回写入cmd8命令中的test_pattern值。否则就表示不支持sd host的电压范围。对应的linux mmc驱动代码为:



  1. int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
  2. {
  3. struct mmc_command cmd;
  4. int err;
  5. static const u8 test_pattern = 0xAA;
  6. u8 result_pattern;
  7. /*
  8.   * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
  9.   * before SD_APP_OP_COND. This command will harmlessly fail for
  10.   * SD 1.0 cards.
  11.   */
  12. cmd.opcode = SD_SEND_IF_COND;
  13. cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
  14. cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
  15. err = mmc_wait_for_cmd(host, &cmd, 0);
  16. if (err)
  17.   return err;
  18. if (mmc_host_is_spi(host))
  19.   result_pattern = cmd.resp[1] & 0xFF;
  20. else
  21.   result_pattern = cmd.resp[0] & 0xFF;
  22. if (result_pattern != test_pattern)
  23.   return -EIO;
  24. return 0;
  25. }
复制代码



(6) ACMD41阶段

(1)这个阶段设置ACMD41的参数OCR=0,为了去获得SD卡自身支持的电压范围值。然后与 host->ocr_avail,SD host所能支持的电压范围取交集,如果交集为空,则返回匹配失败。

  1. int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
  2. {
  3. struct mmc_command cmd;
  4. int i, err = 0;
  5. BUG_ON(!host);
  6. memset(&cmd, 0, sizeof(struct mmc_command));
  7. cmd.opcode = SD_APP_OP_COND;
  8. if (mmc_host_is_spi(host))
  9.   cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */
  10. else
  11.   cmd.arg = ocr;
  12. cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
  13. for (i = 100; i; i--) {
  14.   err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES);
  15.   if (err)
  16.    break;
  17.   /* if we're just probing, do a single pass */
  18.   if (ocr == 0)
  19.    break;
  20.   /* otherwise wait until reset completes */
  21.   if (mmc_host_is_spi(host)) {
  22.    if (!(cmd.resp[0] & R1_SPI_IDLE))
  23.     break;
  24.   } else {
  25.    if (cmd.resp[0] & MMC_CARD_BUSY)
  26.     break;
  27.   }
  28.   err = -ETIMEDOUT;
  29.   mmc_delay(10);
  30. }
  31. if (rocr && !mmc_host_is_spi(host))
  32.   *rocr = cmd.resp[0];
  33. return err;
  34. }
复制代码


(7) CMD2阶段


通过这个命令或者所有SD卡的 Menufacory id ,Product id等卡的信息。



  1. int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
  2. {
  3. int err;
  4. struct mmc_command cmd;
  5. BUG_ON(!host);
  6. BUG_ON(!cid);
  7. memset(&cmd, 0, sizeof(struct mmc_command));
  8. cmd.opcode = MMC_ALL_SEND_CID;
  9. cmd.arg = 0;
  10. cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
  11. err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
  12. if (err)
  13.   return err;
  14. memcpy(cid, cmd.resp, sizeof(u32) * 4);
  15. return 0;
  16. }
复制代码


(8)CMD3取得卡的相对地址,进入数据传输模式,点对点的传输。


  1. int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
  2. {
  3. int err;
  4. struct mmc_command cmd;
  5. BUG_ON(!host);
  6. BUG_ON(!rca);
  7. memset(&cmd, 0, sizeof(struct mmc_command));
  8. cmd.opcode = SD_SEND_RELATIVE_ADDR;
  9. cmd.arg = 0;
  10. cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
  11. err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
  12. if (err)
  13.   return err;
  14. *rca = cmd.resp[0] >> 16;
  15. return 0;
  16. }
复制代码


从CMD3之后,sd卡进入数据传输模式。开始读写。
附件: 您需要登录才可以下载或查看附件。没有帐号?本站只开放邀请码注册,QQ:82475491,索要邀请码
分享到: QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友

返回列表
网页右侧QQ悬浮滚动在线客服
网页右侧QQ悬浮滚动在线客服