接触嵌入式一段时间以来,总是不断的在寻找一个正确的学习方式,寻找一个既有前途又有钱途的方向,并没有认真的去做好手上的事情。而近段时间的生活很学习也让我悟出了一个道理:认真做好现在手头上的每一件事情,才是目前最重要的事情。妄想着寻找一个最火的方向,不脚踏实地的走路,只会跌倒的更痛。
所以我决定,细心的学习一些简单,但又必须懂的知识,写一些简单的代码。努力的将自己的缺点和错过的知识补上去。KEEP IT SIMPLE AND STUPID 是当务之急。
导师总是喜欢讲嵌入式分三个层面,应用层、硬件支撑层、硬件层。我更喜欢纵向的去学习一个方面的知识,从一个硬件的说明书,到驱动,到应用。
下面是NAND FLASH 学习笔记:
从main函数开始分析,VIVI支持写FLASH 功能,所以在进入VIVI的时候肯定是实现了NAND FLASH 的读写的功能。Main函数的第五步里对内存技术设备进行了初始化,代码为:ret = mtd_dev_init();
/* * Initialise */ extern int mtd_init(void); int mtd_dev_init(void) { int ret = 0; #ifdef CONFIG_DEBUG printk("Initialize MTD device\n"); #endif ret = mtd_init(); #ifdef CONFIG_MTD_CFI add_command(&flash_cmd); #endif return ret; }
这个函数在Mtdcore.c中,对MTD进行初始化.mtd_init()的实现和开发板相关,在s3c2410_flash.c中。代码如下:int mtd_init(void) { int ret; #ifdef CONFIG_MTD_CFI ret = cfi_init(); #endif #ifdef CONFIG_MTD_SMC ret = smc_init(); #endif #ifdef CONFIG_S3C2410_AMD_BOOT ret = amd_init(); #endif //add by threewater UpdateMtd(); if (ret) { mymtd = NULL; return ret; } return 0;
其中真正执行的有smc_init() UpdateMtd();
smc应该是samsung manufactory chip.static int smc_init(void) { struct nand_chip *this; u_int16_t nfconf; /* Allocate memory for MTD device structure and private data */ mymtd = mmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip)); if (!mymtd) { printk("Unable to allocate S3C2410 NAND MTD device structure.\n"); return -ENOMEM; } /* Get pointer to private data */ this = (struct nand_chip *)(&mymtd[1]); /* Initialize structures */ memset((char *)mymtd, 0, sizeof(struct mtd_info)); memset((char *)this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ mymtd->priv = this; /* set NAND Flash controller */ nfconf = NFCONF; /* NAND Flash controller enable */ nfconf |= NFCONF_FCTRL_EN; /* Set flash memory timing */ nfconf &= ~NFCONF_TWRPH1; /* 0x0 */ nfconf |= NFCONF_TWRPH0_3; /* 0x3 */ nfconf &= ~NFCONF_TACLS; /* 0x0 */ NFCONF = nfconf; /* Set address of NAND IO lines */ this->hwcontrol = smc_hwcontrol; this->write_cmd = write_cmd; this->write_addr = write_addr; this->read_data = read_data; this->write_data = write_data; this->wait_for_ready = wait_for_ready; /* Chip Enable -> RESET -> Wait for Ready -> Chip Disable */ this->hwcontrol(NAND_CTL_SETNCE); this->write_cmd(NAND_CMD_RESET); this->wait_for_ready(); this->hwcontrol(NAND_CTL_CLRNCE); smc_insert(this); return 0; }
该段代码是对mtd结构体的初始化。包括了:结构体空间分配,结构体中元操作的定义。注意最后一个函数的调用不可忽视,其实smc_insert函数的作用不容小觑,它扫描了预先定义好的一些数据,并对MTD结构体的成员进行赋值。inline int smc_insert(struct nand_chip *this) { /* Scan to find existance of the device */ if (smc_scan(mymtd)) { return -ENXIO; } /* Allocate memory for internal data buffer */ this->data_buf = mmalloc(sizeof(u_char) * (mymtd->oobblock + mymtd->oobsize)); if (!this->data_buf) { printk("Unable to allocate NAND data buffer for S3C2410.\n"); this->data_buf = NULL; return -ENOMEM; } return 0; }上面的smc_scan代码如下,与FLASH芯片代码有关的代码,除了在s3c2410_flash.c中,还在smc_core.c中。该函数的功能根据预定义好的nand_flash_dev结构体扫描,当扫描出来的制造商ID ,设备ID 和预定义的值一样时,就对MTD结构体进行赋值。这样基本上一个flash的属性描述就到此结束了。
TO BE CONTINUE,下面讲下操作代码。int smc_scan(struct mtd_info *mtd) { int i, nand_maf_id, nand_dev_id; struct nand_chip *this = mtd->priv; /* Select the device */ nand_select(); /* Send the command for reading device ID */ nand_command(mtd, NAND_CMD_READID, 0x00, -1); this->wait_for_ready(); /* Read manufacturer and device IDs */ nand_maf_id = this->read_data(); nand_dev_id = this->read_data(); /* Print and sotre flash device information */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { if (nand_maf_id == nand_flash_ids[i].manufacture_id && nand_dev_id == nand_flash_ids[i].model_id) { #ifdef USE_256BYTE_NAND_FLASH if (!mtd->size) { mtd->name = nand_flash_ids[i].name; mtd->erasesize = nand_flash_ids[i].erasesize; mtd->size = (1 << nand_flash_ids[i].chipshift); mtd->eccsize = 256; if (nand_flash_ids[i].page256) { mtd->oobblock = 256; mtd->oobsize = 8; this->page_shift = 8; } else { mtd->oobblock = 512; mtd->oobsize = 16; this->page_shift = 9; } this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)]; } #else if (!(mtd->size) && !(nand_flash_ids[i].page256)) { mtd->name = nand_flash_ids[i].name; mtd->erasesize = nand_flash_ids[i].erasesize; mtd->size = (1 << nand_flash_ids[i].chipshift); mtd->eccsize = 256; mtd->oobblock = 512; mtd->oobsize = 16; this->page_shift = 9; this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)]; } #endif printk("NAND device: Manufacture ID:" \ " 0x%02x, Chip ID: 0x%02x (%s)\n", nand_maf_id, nand_dev_id, mtd->name); break; } } /* De-select the device */ nand_deselect(); /* Print warning message for no device */ if (!mtd->size) { printk("No NAND device found!!!\n"); return 1; } /* Fill in remaining MTD driver data */ mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC; mtd->module = NULL; mtd->ecctype = MTD_ECC_SW; mtd->erase = nand_erase; mtd->point = NULL; mtd->unpoint = NULL; mtd->read = nand_read; mtd->write = nand_write; mtd->read_ecc = nand_read_ecc; mtd->write_ecc = nand_write_ecc; mtd->read_oob = nand_read_oob; mtd->write_oob = nand_write_oob; mtd->lock = NULL; mtd->unlock = NULL; /* Return happy */ return 0; }