基于S3C2440的嵌入式Linux驱动——MMC/SD子系统解读(一)

发布者:huijiazi5210最新更新时间:2017-09-23 来源: eefocus关键字:S3C2440  Linux驱动  MMC  SD子系统 手机看文章 扫描二维码
随时随地手机看文章

本文的内容基于如下硬件和软件平台:

目标平台:TQ2440

CPU:s3c2440

内核版本:3.12.5

基于SD规范4.10,即《SD Specifications Part 1 Physical Layer Simplified Specification Version 4.10》。

一、MMC子系统构架

待写。。。

二、主要数据结构

待写。。。

三、MMC子系统初始化

首先看看子系统是如何初始化的,完成哪些工作。

代码位于linux/drivers/mmc/core/core.c。


  1. static int __init mmc_init(void)  

  2. {  

  3.     int ret;  

  4.   

  5.     /* 创建一个工作队列*/  

  6.     workqueue = alloc_ordered_workqueue("kmmcd", 0);  

  7.     if (!workqueue)  

  8.         return -ENOMEM;  

  9.   

  10.     /* 注册mmc总线,总线提供probe方法 

  11.        并直接在内部调用驱动probe方法*/  

  12.     ret = mmc_register_bus();  

  13.     if (ret)  

  14.         goto destroy_workqueue;  

  15.       

  16.     /* 注册名为mmc_host的类*/  

  17.     ret = mmc_register_host_class();  

  18.     if (ret)  

  19.         goto unregister_bus;  

  20.   

  21.     /* 注册sdio总线,总线提供probe方法 

  22.        并直接在内部调用驱动probe方法*/  

  23.     ret = sdio_register_bus();  

  24.     if (ret)  

  25.         goto unregister_host_class;  

  26.   

  27.     return 0;  

  28.   

  29. unregister_host_class:  

  30.     mmc_unregister_host_class();  

  31. unregister_bus:  

  32.     mmc_unregister_bus();  

  33. destroy_workqueue:  

  34.     destroy_workqueue(workqueue);  

  35.   

  36.     return ret;  

  37. }  


代码首先注册了一个工作队列,这个工作队列将用于扫描sd卡设备。我们会在后面进行说明。

工作对类已内核线程的形式运行,可以用ps命令看到名为[kmmcd]的内核线程。

接着注册了两条名为mmc和sdio的总线,以及一个名为mmc_host的类。具体代码如下:


  1. static struct bus_type mmc_bus_type = {  

  2.     .name       = "mmc",  

  3.     .dev_attrs  = mmc_dev_attrs,  

  4.     .match      = mmc_bus_match,  

  5.     .uevent     = mmc_bus_uevent,  

  6.     .probe      = mmc_bus_probe,  

  7.     .remove     = mmc_bus_remove,  

  8.     .shutdown   = mmc_bus_shutdown,  

  9.     .pm     = &mmc_bus_pm_ops,  

  10. };  

  11.   

  12. int mmc_register_bus(void)  

  13. {  

  14.     return bus_register(&mmc_bus_type);  

  15. }  


  1. static struct class mmc_host_class = {  

  2.     .name        = "mmc_host",  

  3.     .dev_release    = mmc_host_classdev_release,  

  4. };  

  5.   

  6. int mmc_register_host_class(void)  

  7. {  

  8.     return class_register(&mmc_host_class);  

  9. }  


  1. static struct bus_type sdio_bus_type = {  

  2.     .name        = "sdio",  

  3.     .dev_attrs    = sdio_dev_attrs,  

  4.     .match        = sdio_bus_match,  

  5.     .uevent        = sdio_bus_uevent,  

  6.     .probe        = sdio_bus_probe,  

  7.     .remove        = sdio_bus_remove,  

  8.     .pm        = SDIO_PM_OPS_PTR,  

  9. };  

  10.   

  11. int sdio_register_bus(void)  

  12. {  

  13.     return bus_register(&sdio_bus_type);  

  14. }  

  15.   

  16. static struct class mmc_host_class = {  

  17.     .name        = "mmc_host",  

  18.     .dev_release    = mmc_host_classdev_release,  

  19. };  

  20.   

  21. int mmc_register_host_class(void)  

  22. {  

  23.     return class_register(&mmc_host_class);  

  24. }  


熟悉Linux的设备驱动模型的同学对这些肯定非常熟悉。总线和类的注册只是调用了相应的接口,这些就不再赘述了。

其次,sdio总线不是我们关心的。我们只关心mmc总线。首先来看看mmc总线的match方法:

代码位于linux/drivers/mmc/core/bus.c。


  1. /* 

  2.  * This currently matches any MMC driver to any MMC card - drivers 

  3.  * themselves make the decision whether to drive this card in their 

  4.  * probe method. 

  5.  */  

  6. static int mmc_bus_match(struct device *dev, struct device_driver *drv)  

  7. {  

  8.     return 1;  

  9. }  

match返回居然直接返回了1。这表示任意的驱动都能和mmc卡设备成功匹配。

从注释中我们也能看出,驱动的probe方法将会决定驱动是否能真正的匹配这个mmc卡设备。

熟悉设备驱动模型的可能知道,随着match返回1表示匹配成功后,将会调用总线提供的probe方法。接着我们来看下mmc总线的probe方法。

代码位于linux/drivers/mmc/core/bus.c。


  1. static int mmc_bus_probe(struct device *dev)  

  2. {  

  3.     struct mmc_driver *drv = to_mmc_driver(dev->driver);  

  4.     struct mmc_card *card = mmc_dev_to_card(dev);  

  5.   

  6.     return drv->probe(card);  

  7. }  

从这里我们可以看到在mmc的probe方法中直接调用了驱动probe方法,这也验证了刚才注释中所说的话。

从上面分析可以看出,子系统初始化代码仅仅注册了两条总线和一个类,并建立了一个工作队列。


四、核心层与控制器层间的接口API

MMC核心层要和SD卡设备进行通信,为了完成这一个工作需要将CMD或者ACMD命令通过MMC/SD控制器发送给SD卡。

那么MMC核心层如何将通信的数据包交给MMC/SD控制器,并让后者去发送呢?

MMC通过函数mmc_wait_for_req完成这个工作,我们来看下这个函数。

4.1 mmc_wait_for_req 函数

下列代码位于linux/drivers/mmc/core/core.c。


  1. /** 

  2.  *  mmc_wait_for_req - start a request and wait for completion 

  3.  *  @host: MMC host to start command 

  4.  *  @mrq: MMC request to start 

  5.  * 

  6.  *  Start a new MMC custom command request for a host, and wait 

  7.  *  for the command to complete. Does not attempt to parse the 

  8.  *  response. 

  9.  */  

  10. void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)  

  11. {  

  12.     __mmc_start_req(host, mrq);  

  13.     mmc_wait_for_req_done(host, mrq);  

  14. }  

  15. EXPORT_SYMBOL(mmc_wait_for_req);  


    通过注释可以发现,该函数会阻塞并等待request的完成。 


   该函数分两步走,第一步调用__mmc_start_req发送命令,第二部调用 mmc_wait_for_req_done等待命令完成。

   分别来看下这两个函数 :


  1. static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)  

  2. {  

  3.     /* 初始化completion,并设置done方法*/  

  4.     init_completion(&mrq->completion);  

  5.     mrq->done = mmc_wait_done;  

  6.     /* 如果mmc已经被拔出,设置错误并返回错误*/  

  7.     if (mmc_card_removed(host->card)) {  

  8.         mrq->cmd->error = -ENOMEDIUM;  

  9.         complete(&mrq->completion);  

  10.         return -ENOMEDIUM;  

  11.     }  

  12.     /* 发送命令 */  

  13.     mmc_start_request(host, mrq);  

  14.     return 0;  

  15. }   


该函数首先初始化了completion并设置了mrq->done方法为mmc_wait_done函数,该函数如下。


  1. static void mmc_wait_done(struct mmc_request *mrq)  

  2. {  

  3.     complete(&mrq->completion);  

  4. }  

这边使用completion的目的是为了等待request发送的完成。


在第二步mmc_wait_for_req_done中会使用wait_for_completion函数等待mmc控制器完成request,控制器驱动在完成request的发送后,会调用mrq->done方法来激活处于等待中的wait_for_completion函数。

随后函数会首先检查sd卡是否已被拔出,如果卡都被拔出了则没有必要发送request,可以直接调用copletion函数告之相关的等待函数,并设置error值然后返回错误。


  1. #define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))  


如果sd卡存在,则调用mmc_start_request函数发送request,该函数如下:


  1. static void  

  2. mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)  

  3. {  

  4. #ifdef CONFIG_MMC_DEBUG  

  5.     unsigned int i, sz;  

  6.     struct scatterlist *sg;  

  7. #endif  

  8.   

  9.     if (mrq->sbc) {  

  10.         pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",  

  11.              mmc_hostname(host), mrq->sbc->opcode,  

  12.              mrq->sbc->arg, mrq->sbc->flags);  

  13.     }  

  14.   

  15.     pr_debug("%s: starting CMD%u arg %08x flags %08x\n",  

  16.          mmc_hostname(host), mrq->cmd->opcode,  

  17.          mrq->cmd->arg, mrq->cmd->flags);  

  18.   

  19.     if (mrq->data) {  

  20.         pr_debug("%s:     blksz %d blocks %d flags %08x "  

  21.             "tsac %d ms nsac %d\n",  

  22.             mmc_hostname(host), mrq->data->blksz,  

  23.             mrq->data->blocks, mrq->data->flags,  

  24.             mrq->data->timeout_ns / 1000000,  

  25.             mrq->data->timeout_clks);  

  26.     }  

  27.   

  28.     if (mrq->stop) {  

  29.         pr_debug("%s:     CMD%u arg %08x flags %08x\n",  

  30.              mmc_hostname(host), mrq->stop->opcode,  

  31.              mrq->stop->arg, mrq->stop->flags);  

  32.     }  

  33.   

  34.     WARN_ON(!host->claimed);  

  35.   

  36.     mrq->cmd->error = 0;  

  37.     mrq->cmd->mrq = mrq;  

  38.     if (mrq->data) {  

  39.         BUG_ON(mrq->data->blksz > host->max_blk_size);  

  40.         BUG_ON(mrq->data->blocks > host->max_blk_count);  

  41.         BUG_ON(mrq->data->blocks * mrq->data->blksz >  

  42.             host->max_req_size);  

  43.   

  44. #ifdef CONFIG_MMC_DEBUG  

  45.         sz = 0;  

  46.         for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i)  

  47.             sz += sg->length;  

  48.         BUG_ON(sz != mrq->data->blocks * mrq->data->blksz);  

  49. #endif  

  50.   

  51.         mrq->cmd->data = mrq->data;  

  52.         mrq->data->error = 0;  

  53.         mrq->data->mrq = mrq;  

  54.         if (mrq->stop) {  

  55.             mrq->data->stop = mrq->stop;  

  56.             mrq->stop->error = 0;  

  57.             mrq->stop->mrq = mrq;  

  58.         }  

  59.     }  

  60.     mmc_host_clk_hold(host);  

  61.     led_trigger_event(host->led, LED_FULL);  

  62.     /* 发送request*/  

  63.     host->ops->request(host, mrq);  

  64. }  

该函数会打印一堆信息,然后清除cmd->error,并绑定cmd和mrq,接着如果mrq是请求数据


mmc_host_clk_hold函数是通过宏CONFIG_MMC_CLKGATE来进行使能的,这个宏默认是不打开的,具体就不分析了,简要说下这个宏的作用。

这个宏的作用是使能时钟门控功能,这个功能在不需要MMC控制器工作的时候,停止MMC控制器,以节省功耗。

随后会调用led_trigger_event触发led事件,这个牵涉到Led子系统,就不进行说明了。

顺便提一句,s3c2440的mmc控制器驱动并没有使用这个led触发功能,也就是说host->led是为空的。

最后调用了mmc控制器驱动提供的request方法发送request。

这里需要注意下函数指针的形参:一个为host表示mmc控制器,一个为mrq表示request(请求)。

很显然,要求host指向的mmc控制器发送mrq指向的请求,同时,也可以看出所有传递到mmc控制器驱动的请求都是使用struct mmc_request结构体进行封装的。

至此,第一步完成,接着我们来看第二步:


  1. static void mmc_wait_for_req_done(struct mmc_host *host,  

  2.                   struct mmc_request *mrq)  

  3. {  

  4.     struct mmc_command *cmd;  

  5.   

  6.     while (1) {  

  7.         wait_for_completion(&mrq->completion);  

  8.   

  9.         cmd = mrq->cmd;  

  10.   

  11.         /* 

  12.          * If host has timed out waiting for the sanitize 

  13.          * to complete, card might be still in programming state 

  14.          * so let's try to bring the card out of programming 

  15.          * state. 

  16.          */  

  17.         if (cmd->sanitize_busy && cmd->error == -ETIMEDOUT) {  

  18.             if (!mmc_interrupt_hpi(host->card)) {  

  19.                 pr_warning("%s: %s: Interrupted sanitize\n",  

  20.                        mmc_hostname(host), __func__);  

  21.                 cmd->error = 0;  

  22.                 break;  

  23.             } else {  

  24.                 pr_err("%s: %s: Failed to interrupt sanitize\n",  

  25.                        mmc_hostname(host), __func__);  

  26.             }  

  27.         }  

  28.         if (!cmd->error || !cmd->retries ||  

  29.             mmc_card_removed(host->card))  

  30.             break;  

  31.   

  32.         pr_debug("%s: req failed (CMD%u): %d, retrying...\n",  

  33.              mmc_hostname(host), cmd->opcode, cmd->error);  

  34.         cmd->retries--;  

  35.         cmd->error = 0;  

  36.                 /* 没有成功,尝试再次发送request*/  

  37.                 host->ops->request(host, mrq);  

  38.     }  

  39. }  

这个函数首先调用了wait_for_completion来等待mmc控制器驱动调用mmc_wait_done来唤醒自己。


被唤醒后会执行一系列检查,如果request成功发送,则会break,并直接返回。

如果没有发送成功,只要retries非0,则会尝试再次调用mmc控制器驱动的request方法再次发送。

4.2 CMD和ACMD发送函数

通过4.1小结,我们知道MMC核心层如何将request交给MMC控制器驱动,并由后者发送该request给sd卡。

通过SD卡规范,我们知道有两种形式的命令,一种为CMD,而另一种为ACMD。

MMC子系统提供了两个函数来完成这两命令的发送,分别是mmc_wait_for_cmd和mmc_wait_for_app_cmd。

先来看下CMD的发送函数:

下列代码位于linux/drivers/mmc/core/core.c。


  1. /** 

  2.  *  mmc_wait_for_cmd - start a command and wait for completion 

  3.  *  @host: MMC host to start command 

  4.  *  @cmd: MMC command to start 

  5.  *  @retries: maximum number of retries 

  6.  * 

  7.  *  Start a new MMC command for a host, and wait for the command 

  8.  *  to complete.  Return any error that occurred while the command 

  9.  *  was executing.  Do not attempt to parse the response. 

  10.  */  

  11. int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)  

  12. {  

  13.     struct mmc_request mrq = {NULL};  

  14.   

  15.     WARN_ON(!host->claimed);  

  16.   

  17.     /* 清空应答 */  

  18.     memset(cmd->resp, 0, sizeof(cmd->resp));  

  19.     cmd->retries = retries;  

  20.   

  21.     /* 保存命令*/  

  22.     mrq.cmd = cmd;  

  23.     cmd->data = NULL;  

  24.   

  25.     /* 发送命令并等待response */  

  26.     mmc_wait_for_req(host, &mrq);  

  27.   

  28.     return cmd->error;  

  29. }  

有了4.1小结的分析,这个函数还是比较简单的。


该函数首先清空命令的应答数据(resp),并保存命令(cmd)到mrq中,随后调用4.1小节中的mmc_wait_for_req函数发送CMD。

从这个函数的形参我们可以看出:所有需要发送的CMD都由mmc_command进行封装,在函数内部被mmc_request 
结构体进行再次封装,并将mmc_request交给MMC控制器驱动完成CMD的发送。

接着看下ACMD命令的发送函数mmc_wait_for_app_cmd:

下列代码位于Linux/drivers/mmc/core/sd_ops.h。


  1. /** 

  2.  *  mmc_wait_for_app_cmd - start an application command and wait for 

  3.                    completion 

  4.  *  @host: MMC host to start command 

  5.  *  @card: Card to send MMC_APP_CMD to 

  6.  *  @cmd: MMC command to start 

  7.  *  @retries: maximum number of retries 

  8.  * 

  9.  *  Sends a MMC_APP_CMD, checks the card response, sends the command 

  10.  *  in the parameter and waits for it to complete. Return any error 

  11.  *  that occurred while the command was executing.  Do not attempt to 

  12.  *  parse the response. 

  13.  */  

  14. int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,  

  15.     struct mmc_command *cmd, int retries)  

  16. {  

  17.     struct mmc_request mrq = {NULL};  

  18.   

  19.     int i, err;  

  20.   

  21.     BUG_ON(!cmd);  

  22.     BUG_ON(retries < 0);  

  23.   

  24.     err = -EIO;  

  25.   

  26.     /* 

  27.      * We have to resend MMC_APP_CMD for each attempt so 

  28.      * we cannot use the retries field in mmc_command. 

  29.      */  

  30.     for (i = 0;i <= retries;i++) {  

  31.         /* 发送CMD55*/  

  32.         err = mmc_app_cmd(host, card);  

  33.         if (err) {  

  34.             /* no point in retrying; no APP commands allowed */  

  35.             if (mmc_host_is_spi(host)) {  

  36.                 if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)  

  37.                     break;  

  38.             }  

  39.             continue;  

  40.         }  

  41.   

  42.         memset(&mrq, 0, sizeof(struct mmc_request));  

  43.   

  44.         memset(cmd->resp, 0, sizeof(cmd->resp));  

  45.         cmd->retries = 0;  

  46.   

  47.         mrq.cmd = cmd;  

  48.         cmd->data = NULL;  

  49.   

  50.         /* 发送ACMDx*/  

  51.         mmc_wait_for_req(host, &mrq);  

  52.   

  53.         err = cmd->error;  

  54.         /* 发送成功,直接break并返回*/  

  55.         if (!cmd->error)  

  56.             break;  

  57.   

  58.         /* no point in retrying illegal APP commands */  

  59.         if (mmc_host_is_spi(host)) {  

  60.             if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)  

  61.                 break;  

  62.         }  

  63.     }  

  64.   

  65.     return err;  

  66. }  

  67.   

  68. EXPORT_SYMBOL(mmc_wait_for_app_cmd);  

该函数的形参cmd保存了代发送的ACMD命令。


根据SD卡规范的要求:在发送ACMD命令只前,需要发送CMD55,以表示后面一个命令为AMD命令。

所以,该函数首先调用mmc_app_cmd函数来发送CMD55命令,我们来看下这个函数:


  1. int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)  

  2. {  

  3.     int err;  

  4.     struct mmc_command cmd = {0};  

  5.   

  6.     BUG_ON(!host);  

  7.     BUG_ON(card && (card->host != host));  

  8.   

  9.     cmd.opcode = MMC_APP_CMD;   /* CMD55 */  

  10.   

  11.     if (card) {  

  12.         cmd.arg = card->rca << 16; /* 卡地址*/  

  13.         cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;  

  14.     } else {  

  15.         cmd.arg = 0;    /* 卡地址*/  

  16.         cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR;  

  17.     }  

  18.   

  19.     /* 发送cmd并等待(阻塞方式)*/  

  20.     err = mmc_wait_for_cmd(host, &cmd, 0);  

  21.     if (err)  

  22.         return err;  

  23.   

  24.     /* Check that card supported application commands */  

  25.     /* 检查card status第5位,判断SD卡是否支持ACMD*/  

  26.     if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD))  

  27.         return -EOPNOTSUPP;  

  28.   

  29.     return 0;  

  30. }  

  31. EXPORT_SYMBOL_GPL(mmc_app_cmd);  

先来看下SD规范中关于CMD55的说明:




从上述命令说明中,我们可以看出:

1)该命令为ac类型命令,也就是点对点命令,并且在DAT信号线上没有数据传输。

2)其次,该命令的参数(31位至16位)为RCA,也就是卡的地址。

3)最后,命令的应答数据格式为R1。

回到函数中。

cmd.arg为发送命令的参数,函数首先设置了命令的参数为sd卡地址(RCA),这符合上面的描述。

随后调用了之前分析的mmc_wait_for_cmd函数发送CMD55命令。

上面提到CMD55命令的响应为R1,其格式如下:


其中32bit的card status作为响应数据被保存在resp数组中。

card status的具体位定义请查看SD规范的4.10.1小结。

最后检查CMD55的响应来判断SD卡是否支持ACMD命令。

CMD55发送成功后,返回到mmc_wait_for_app_cmd函数中。

接着,cmd被保存到mrq.cmd 中,并调用mmc_wait_for_req中发送ACMD命令。


五、小结

    本问主要对MMC子系统架构进行了简单的介绍,并给出了一些关键数据结构。同时,对MMC子系统的初始化过程进行了简单分析,最后,重点介绍了CMD和ACMD命令的发送函数。


关键字:S3C2440  Linux驱动  MMC  SD子系统 引用地址:基于S3C2440的嵌入式Linux驱动——MMC/SD子系统解读(一)

上一篇:基于S3C2440的嵌入式Linux驱动——MMC/SD子系统解读(二)
下一篇:基于S3C2440的嵌入式Linux驱动——AT24C02(EEPROM I2C接口)驱动解读

推荐阅读最新更新时间:2024-03-16 15:38

MMC卡的文件系统及其实现方法
多媒体卡MMC(MultiMedia Card)是由美国SanDisk公司和德国Simens公司于1997年共同开发推出的一种多功能存卡。内置控制电路,可以使用在手机、数码相机、MP3、PDA等多种数字设备上,可反复记录30万次。现在市场上的主流容量有128 MB~2 GB。    文中首先介绍单片机对SPI协议下的MMC卡的底层读写操作,然后分析MMC卡文件系统的结构,最后详细说明MMC卡文件的创建、读写、删除等操作。该方法可应用到与Windows有交互的嵌入式系统中,便于文件的统一管理。    1 单片机与MMC卡的接口    1.1 单片机与MMC卡的接口电路 接口电路采用的是Philips公司的增强型LPC93x系列
[单片机]
<font color='red'>MMC</font>卡的文件系统及其实现方法
基于S3C2440处理器和WinCE的智能车载仪表设计
  随着高性能电子显示技术的发展,汽车仪表电子化的程度越来越高。国内外已开发出了多功能全电子显示仪表、平视显示仪表、汽车导航系统、行车记录仪等高技术产品。未来,车用电子化嵌入式仪表具有以下优点:提供大量复杂的信息,使汽车的电子控制程度越来越高;满足小型、轻量化的要求,使有限的驾驶空间更人性化;高精度和高可靠性实现汽车仪表的电子化,降低了故障的发生率;设有在线故障诊断系统,一旦汽车发生故障,可以找到故障来源,方便维修;外形设计自由度高,汽车仪表盘造型美观。基于以上优点,汽车会越来越多地采用各种用途的电子化仪表。造型新颖、功能强大的嵌入式电子化仪表将是今后车用仪表的发展趋势和潮流。    1 智能车载仪表系统结构   本智能车载仪
[单片机]
基于<font color='red'>S3C2440</font>处理器和WinCE的智能车载仪表设计
S3C2440裸机------触摸屏_利用ADC读取触摸屏坐标
前面我们在按下触摸屏时只是打印调试信息,现在我们再按下的中断处理函数里面增加ADC的配置代码,当我们按下后利用ADC读取触摸屏的坐标。 #include ../s3c2440_soc.h #define ADC_INT_BIT (10) #define TC_INT_BIT (9) #define INT_ADC_TC (31) /* ADCTSC's bits */ #define WAIT_PEN_DOWN (0 8) #define WAIT_PEN_UP (1 8) #define YM_ENABLE (1 7) #define YM_DISABLE (0 7) #de
[单片机]
s3c2440——按键中断
s3c2440的异常向量表: IRQ中断地址是0x18.所以,根据之前的异常处理方式,我们编写启动文件: 为什么需要lr减4,可以参考这篇文章: http://blog.csdn.net/zzsfqiuyigui/article/details/23334177 这是为了保证,当cpu正在执行某条指令时被中断打断,中断返回的时候,要继续执行这条被打断的指令,如果不减去4,cpu处理完中断之后,将会在被打断执行的这条指令的下一条指令开始执行(因为lr_irq保存的是下一条指令执行的地址),就会丢失掉这个被打断指令的执行,所以,保存中断处理完毕的返回地址很重要。 void handle_irq_c(void) {
[单片机]
<font color='red'>s3c2440</font>——按键中断
基于S3C2440处理器SPI移植全过程
环境 硬件:S3C2440(ARM920T) 嵌入式操作系统:Linux2.6.24内核 文件系统:Yaffs2文件系统 服务器:SuSe10.0 Linux服务器 第一步:内核配置 需要在内核中选择以上几个选项: 很多网友发邮件说Linux2.6.24内核在SPI选项上未发现有Samsung S3C2440 series SPI 或 Samsung S3C24XX series SPI 和User mode SPI device driver support这两个选项。 其实在Linux2.6.24内核里已经兼容了对SPI的操作。只是在Linux2.6.24/drivers/spi/Kconfig中未能选中此选项
[单片机]
基于<font color='red'>S3C2440</font>处理器SPI移植全过程
uboot-2011.12移植到S3C2440(序二)—— binutils二进制工具集与u-boot
概述 binutils是一组二进制工具集,它包括addr2line、ar、gprof、nm、objcopy、objdumpr、ranlib、size、strings、strip等。 ar软件 ar用于建立、修改、提取库文件。ar至少需要两个参数才能运行,比如: $ ar rv libtest.a add.o minus.o 是指将add.o、minus.o做成库文件libtest.a。其中r是指将文件列表插入归档文件,v是指得到操作版本号。 这样我们引用库文件的时候就可以使用: $ gcc -o test test.c -ltest nm软件 nm软件的作用是现实目标文件的信息和属性,比如: $ nm test.o
[单片机]
ARM-Linux驱动相关头文件知识点
#include linux/***.h 在linux-2.6.31/include/linux下面寻找源文件 #include asm/***.h 在linux-2.6.31/arch/arm/include/asm下面寻找源文件 #include mach/***.h 在linux-2.6.31/arch/arm/mach-s3c2410/include/mach下面寻找源文件 #include plat/regs-adc.h 在linux-2.6.31/arch/arm/plat-s3c/include/plat下面寻找源文件 ---------------------------------------------
[单片机]
基于WinCE的嵌入式视频数据采集系统设计
  随着嵌入式技术的不断发展,各种嵌入式微处理器和控制器不断出现,并广泛应用于工控、通信、PDA、安保等领域。基于ARM920t内核的嵌入式微处理器S3C2440,以其良好的数据处理能力、低功耗、小体积、支持多种嵌入式操作系统(如WinCE、Linux)、集成多种外设(如I2C控制器、LCD控制器等)等优点,广泛应用于手持设备等。WinCE操作系统具有内核可剪裁、实时性好、支持多种通信、模块化设计、具有丰富的API等特点,广泛用于嵌入式实时操作系统。这里提出的嵌入式图像数据采集系统是某“纳米技术与微系统”实验室开发的“嵌入式传感测控系统”中实现图像采集功能的子系统,该系统是以S3C2440为硬件核心,以WinCE为软件平台,能实时
[嵌入式]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多精选电路图
换一换 更多 相关热搜器件
更多每日新闻
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved