Linux内核4.14版本——SPI NOR子系统(2)——spi-nor.c分析
1. 简介
2. spi_nor_scan
2.1 检查结构体struct spi_nor是否合格,匹配支持的nor flash ID得到info
2.1.1 spi_nor_check
2.1.2 spi_nor_read_id
2.1.3 struct flash_info
2.2 初始化结构体struct spi_nor_flash_parameter变量params
2.3 设置保护bit、mtd相关的结构体
2.4 spi_nor_setup
2.5 设置地址宽度
2.6 s3an_nor_scan
1. 简介
前面已经介绍了spi-nor子系统的由来,现在我们来看看spi-nor子系统的代码。spi-nor的核心结构体是以下代码:
struct spi_nor {struct mtd_info mtd;struct mutex lock;struct device *dev;u32 page_size;u8 addr_width;u8 erase_opcode;u8 read_opcode;u8 read_dummy;u8 program_opcode;enum spi_nor_protocol read_proto;enum spi_nor_protocol write_proto;enum spi_nor_protocol reg_proto;bool sst_write_second;u32 flags;u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE];int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);ssize_t (*read)(struct spi_nor *nor, loff_t from,size_t len, u_char *read_buf);ssize_t (*write)(struct spi_nor *nor, loff_t to,size_t len, const u_char *write_buf);int (*erase)(struct spi_nor *nor, loff_t offs);int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len);int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);void *priv;
};
mtd: 指向mtd_info结构体,我们知道所有的存储设备,最终都有可以挂载到mtd子系统中。
lock: 读/写/擦除/锁定/解锁操作的锁定
dev: 指向spi设备或spi nor控制器设备。
page_size: SPI NOR的页面大小
addr_width: 地址字节数
erase_opcode: 用于擦除扇区的操作码
read_opcode: 读操作码
read_dummy: 读取操作所需的dummy数
program_opcode: program操作码
sst_write_second: used by the SST write operation
flags: 当前SPI-NOR的标志选项(SNOR\u F\ux*)。
read_proto: 用于读取操作的SPI协议
write_proto: 用于写操作的SPI协议
reg_proto 用于读\写\擦除操作的SPI协议
cmd_buf: used by the write_reg
这里有一个enum spi_nor_protocol说明一下,如下所示。
enum spi_nor_protocol {SNOR_PROTO_1_1_1 = SNOR_PROTO_STR(1, 1, 1),SNOR_PROTO_1_1_2 = SNOR_PROTO_STR(1, 1, 2),SNOR_PROTO_1_1_4 = SNOR_PROTO_STR(1, 1, 4),SNOR_PROTO_1_1_8 = SNOR_PROTO_STR(1, 1, 8),SNOR_PROTO_1_2_2 = SNOR_PROTO_STR(1, 2, 2),SNOR_PROTO_1_4_4 = SNOR_PROTO_STR(1, 4, 4),SNOR_PROTO_1_8_8 = SNOR_PROTO_STR(1, 8, 8),SNOR_PROTO_2_2_2 = SNOR_PROTO_STR(2, 2, 2),SNOR_PROTO_4_4_4 = SNOR_PROTO_STR(4, 4, 4),SNOR_PROTO_8_8_8 = SNOR_PROTO_STR(8, 8, 8),SNOR_PROTO_1_1_1_DTR = SNOR_PROTO_DTR(1, 1, 1),SNOR_PROTO_1_2_2_DTR = SNOR_PROTO_DTR(1, 2, 2),SNOR_PROTO_1_4_4_DTR = SNOR_PROTO_DTR(1, 4, 4),SNOR_PROTO_1_8_8_DTR = SNOR_PROTO_DTR(1, 8, 8),
};
这个协议是该spi-nor所使用的协议,是1线、4线、8线等协议,初始值就是默认值。
查看include\linux\mtd\spi-nor.h文件,只有一个对外开放的函数spi_nor_scan,这个也是我们分析的重点。
/*** spi_nor_scan() - scan the SPI NOR* @nor: the spi_nor structure* @name: the chip type name* @hwcaps: the hardware capabilities supported by the controller driver** The drivers can use this fuction to scan the SPI NOR.* In the scanning, it will try to get all the necessary information to* fill the mtd_info{} and the spi_nor{}.** The chip type name can be provided through the @name parameter.** Return: 0 for success, others for failure.*/
int spi_nor_scan(struct spi_nor *nor, const char *name,const struct spi_nor_hwcaps *hwcaps);
可以看出,对于spi-nor子系统来说,结构体struct spi_nor和struct spi_nor_hwcaps是最主要的设置目标,这个先不管。spi-nor子系统会根据这两个结构体来进行设置一些东西。下面具体分析这个函数。
2. spi_nor_scan
这个函数比较长,我们分几段来看。
2.1 检查结构体struct spi_nor是否合格,匹配支持的nor flash ID得到info
int spi_nor_scan(struct spi_nor *nor, const char *name,const struct spi_nor_hwcaps *hwcaps)
{struct spi_nor_flash_parameter params;const struct flash_info *info = NULL;struct device *dev = nor->dev;struct mtd_info *mtd = &nor->mtd;struct device_node *np = spi_nor_get_flash_node(nor);int ret;int i;ret = spi_nor_check(nor);if (ret)return ret;/* Reset SPI protocol for all commands. */nor->reg_proto = SNOR_PROTO_1_1_1;nor->read_proto = SNOR_PROTO_1_1_1;nor->write_proto = SNOR_PROTO_1_1_1;if (name)info = spi_nor_match_id(name);/* Try to auto-detect if chip name wasn't specified or not found */if (!info)info = spi_nor_read_id(nor);if (IS_ERR_OR_NULL(info))return -ENOENT;........
}
检查结构体struct spi_nor是否合格,设置读写的协议为SNOR_PROTO_1_1_1,匹配支持的nor flash ID得到info。
2.1.1 spi_nor_check
static int spi_nor_check(struct spi_nor *nor)
{if (!nor->dev || !nor->read || !nor->write ||!nor->read_reg || !nor->write_reg) {pr_err("spi-nor: please fill all the necessary fields!\n");return -EINVAL;}return 0;
}
spi_nor_check函数主要检查上层函数传递下来的变量是否设置了必要的变量,这些是编写驱动必须要实现的部分。
2.1.2 spi_nor_read_id
static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
{int tmp;u8 id[SPI_NOR_MAX_ID_LEN];const struct flash_info *info;tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);if (tmp < 0) {dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);return ERR_PTR(tmp);}for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) {info = &spi_nor_ids[tmp];if (info->id_len) {if (!memcmp(info->id, id, info->id_len))return &spi_nor_ids[tmp];}}dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",id[0], id[1], id[2]);return ERR_PTR(-ENODEV);
}
通过调用控制器提供的read_reg函数,读取flash的JEDEC ID,并且从spi_nor_ids匹配是否支持该flash。我们简单看看spi_nor_ids这个全局变量。
static const struct flash_info spi_nor_ids[] = {.........{"gd25q128", INFO(0xc84018, 0, 64 * 1024, 256,SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)},......
};
宏INFO定义如下:
宏INFO定义如下。
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \.id = { \((_jedec_id) >> 16) & 0xff, \((_jedec_id) >> 8) & 0xff, \(_jedec_id) & 0xff, \((_ext_id) >> 8) & 0xff, \(_ext_id) & 0xff, \}, \.id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))), \.sector_size = (_sector_size), \.n_sectors = (_n_sectors), \.page_size = 256, \.flags = (_flags),
我们以gd25q128这个flash为例,最终的展开是:
static const struct flash_info spi_nor_ids[] = {.........{"gd25q128", .id = {c8,40,18,0,0},.id_len = 3,.sector_size = 64 * 1024,.n_sectors = 256,.page_size = 256,.flag = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB},......
};
2.1.3 struct flash_info
从2.1.2小节我们可以看出,如果我们要写一个nor flash的驱动,我们必须把这个nor flash的基本信息填充到spi_nor_ids这个数组中。下面我们看一下这个结构体,具体的分析我们下面在做。
struct flash_info {char *name;/** This array stores the ID bytes.* The first three bytes are the JEDIC ID.* JEDEC ID zero means "no ID" (mostly older chips).*/u8 id[SPI_NOR_MAX_ID_LEN];u8 id_len;/* The size listed here is what works with SPINOR_OP_SE, which isn't* necessarily called a "sector" by the vendor.*/unsigned sector_size;u16 n_sectors;u16 page_size;u16 addr_width;u16 flags;
#define SECT_4K BIT(0) /* SPINOR_OP_BE_4K works uniformly */
#define SPI_NOR_NO_ERASE BIT(1) /* No erase command needed */
#define SST_WRITE BIT(2) /* use SST byte programming */
#define SPI_NOR_NO_FR BIT(3) /* Can't do fastread */
#define SECT_4K_PMC BIT(4) /* SPINOR_OP_BE_4K_PMC works uniformly */
#define SPI_NOR_DUAL_READ BIT(5) /* Flash supports Dual Read */
#define SPI_NOR_QUAD_READ BIT(6) /* Flash supports Quad Read */
#define USE_FSR BIT(7) /* use flag status register */
#define SPI_NOR_HAS_LOCK BIT(8) /* Flash supports lock/unlock via SR */
#define SPI_NOR_HAS_TB BIT(9) /** Flash SR has Top/Bottom (TB) protect* bit. Must be used with* SPI_NOR_HAS_LOCK.*/
#define SPI_S3AN BIT(10) /** Xilinx Spartan 3AN In-System Flash* (MFR cannot be used for probing* because it has the same value as* ATMEL flashes)*/
#define SPI_NOR_4B_OPCODES BIT(11) /** Use dedicated 4byte address op codes* to support memory size above 128Mib.*/
#define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */
#define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */
#define USE_CLSR BIT(14) /* use CLSR command */
#define SPI_NOR_OCTAL_READ BIT(15) /* Flash supports Octal Read */
};
2.2 初始化结构体struct spi_nor_flash_parameter变量params
int spi_nor_scan(struct spi_nor *nor, const char *name,const struct spi_nor_hwcaps *hwcaps)
{struct spi_nor_flash_parameter params;......../** Make sure the XSR_RDY flag is set before calling* spi_nor_wait_till_ready(). Xilinx S3AN share MFR* with Atmel spi-nor*/if (info->flags & SPI_S3AN)nor->flags |= SNOR_F_READY_XSR_RDY;/* Parse the Serial Flash Discoverable Parameters table. */ret = spi_nor_init_params(nor, info, ¶ms);if (ret)return ret;.......ret = spi_nor_setup(nor, info, ¶ms, hwcaps);.......
}
根据2.1节得到的flash info信息,设置初始化params。
struct spi_nor_flash_parameter {u64 size;u32 page_size;struct spi_nor_hwcaps hwcaps;struct spi_nor_read_command reads[SNOR_CMD_READ_MAX];struct spi_nor_pp_command page_programs[SNOR_CMD_PP_MAX];int (*quad_enable)(struct spi_nor *nor);
};static int spi_nor_init_params(struct spi_nor *nor,const struct flash_info *info,struct spi_nor_flash_parameter *params)
{/* Set legacy flash parameters as default. */memset(params, 0, sizeof(*params));/* Set SPI NOR sizes. */params->size = (u64)info->sector_size * info->n_sectors;params->page_size = info->page_size;/* (Fast) Read settings. */params->hwcaps.mask |= SNOR_HWCAPS_READ;spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ],0, 0, SPINOR_OP_READ,SNOR_PROTO_1_1_1);if (!(info->flags & SPI_NOR_NO_FR)) {params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST;spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_FAST],0, 8, SPINOR_OP_READ_FAST,SNOR_PROTO_1_1_1);}if (info->flags & SPI_NOR_DUAL_READ) {params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_2],0, 8, SPINOR_OP_READ_1_1_2,SNOR_PROTO_1_1_2);}if (info->flags & SPI_NOR_QUAD_READ) {params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_4],0, 8, SPINOR_OP_READ_1_1_4,SNOR_PROTO_1_1_4);}if (info->flags & SPI_NOR_OCTAL_READ) {params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8;spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_8],0, 8, SPINOR_OP_READ_1_1_8,SNOR_PROTO_1_1_8);}/* Page Program settings. */params->hwcaps.mask |= SNOR_HWCAPS_PP;spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP],SPINOR_OP_PP, SNOR_PROTO_1_1_1);/* Select the procedure to set the Quad Enable bit. */if (params->hwcaps.mask & (SNOR_HWCAPS_READ_QUAD |SNOR_HWCAPS_PP_QUAD)) {switch (JEDEC_MFR(info)) {case SNOR_MFR_MACRONIX:params->quad_enable = macronix_quad_enable;break;case SNOR_MFR_MICRON:break;case SNOR_MFR_GIGADEVICE:params->quad_enable = spansion_read_cr_quad_enable;break;default:/* Kept only for backward compatibility purpose. */params->quad_enable = spansion_quad_enable;break;}}/* Override the parameters with data read from SFDP tables. */nor->addr_width = 0;nor->mtd.erasesize = 0;if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_OCTAL_READ)) &&!(info->flags & SPI_NOR_SKIP_SFDP)) {struct spi_nor_flash_parameter sfdp_params;memcpy(&sfdp_params, params, sizeof(sfdp_params));if (spi_nor_parse_sfdp(nor, &sfdp_params)) {nor->addr_width = 0;nor->mtd.erasesize = 0;} else {memcpy(params, &sfdp_params, sizeof(*params));}}return 0;
}
这个比较简单,根据flag的标志,设置params中的变量,主要设置的是该nor flash的硬件能力集。例如,上面的例子中我们的flash info的flag为
.flag = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB
有一个地方需要注意的是,使能Quad Enable bit位。
/* Select the procedure to set the Quad Enable bit. */if (params->hwcaps.mask & (SNOR_HWCAPS_READ_QUAD |SNOR_HWCAPS_PP_QUAD)) {switch (JEDEC_MFR(info)) {case SNOR_MFR_MACRONIX:params->quad_enable = macronix_quad_enable;break;case SNOR_MFR_MICRON:break;case SNOR_MFR_GIGADEVICE:params->quad_enable = spansion_read_cr_quad_enable;break;default:/* Kept only for backward compatibility purpose. */params->quad_enable = spansion_quad_enable;break;}}
read sfdp相关信息。
/* Override the parameters with data read from SFDP tables. */nor->addr_width = 0;nor->mtd.erasesize = 0;if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_OCTAL_READ)) &&!(info->flags & SPI_NOR_SKIP_SFDP)) {struct spi_nor_flash_parameter sfdp_params;memcpy(&sfdp_params, params, sizeof(sfdp_params));if (spi_nor_parse_sfdp(nor, &sfdp_params)) {nor->addr_width = 0;nor->mtd.erasesize = 0;} else {memcpy(params, &sfdp_params, sizeof(*params));}}
2.3 设置保护bit、mtd相关的结构体
int spi_nor_scan(struct spi_nor *nor, const char *name,const struct spi_nor_hwcaps *hwcaps)
{...../** Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up* with the software protection bits set*/if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||JEDEC_MFR(info) == SNOR_MFR_INTEL ||JEDEC_MFR(info) == SNOR_MFR_SST ||info->flags & SPI_NOR_HAS_LOCK) {write_enable(nor);write_sr(nor, 0);spi_nor_wait_till_ready(nor);}if (!mtd->name)mtd->name = dev_name(dev);mtd->priv = nor;mtd->type = MTD_NORFLASH;mtd->writesize = 1;mtd->flags = MTD_CAP_NORFLASH;mtd->size = params.size;mtd->_erase = spi_nor_erase;mtd->_read = spi_nor_read;/* NOR protection support for STmicro/Micron chips and similar */if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||info->flags & SPI_NOR_HAS_LOCK) {nor->flash_lock = stm_lock;nor->flash_unlock = stm_unlock;nor->flash_is_locked = stm_is_locked;}if (nor->flash_lock && nor->flash_unlock && nor->flash_is_locked) {mtd->_lock = spi_nor_lock;mtd->_unlock = spi_nor_unlock;mtd->_is_locked = spi_nor_is_locked;}/* sst nor chips use AAI word program */if (info->flags & SST_WRITE)mtd->_write = sst_write;elsemtd->_write = spi_nor_write;if (info->flags & USE_FSR)nor->flags |= SNOR_F_USE_FSR;if (info->flags & SPI_NOR_HAS_TB)nor->flags |= SNOR_F_HAS_SR_TB;if (info->flags & NO_CHIP_ERASE)nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;if (info->flags & USE_CLSR)nor->flags |= SNOR_F_USE_CLSR;if (info->flags & SPI_NOR_NO_ERASE)mtd->flags |= MTD_NO_ERASE;mtd->dev.parent = dev;nor->page_size = params.page_size;mtd->writebufsize = nor->page_size;if (np) {/* If we were instantiated by DT, use it */if (of_property_read_bool(np, "m25p,fast-read"))params.hwcaps.mask |= SNOR_HWCAPS_READ_FAST;elseparams.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;} else {/* If we weren't instantiated by DT, default to fast-read */params.hwcaps.mask |= SNOR_HWCAPS_READ_FAST;}/* Some devices cannot do fast-read, no matter what DT tells us */if (info->flags & SPI_NOR_NO_FR)params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;....
}
2.4 spi_nor_setup
int spi_nor_scan(struct spi_nor *nor, const char *name,const struct spi_nor_hwcaps *hwcaps)
{...../** Configure the SPI memory:* - select op codes for (Fast) Read, Page Program and Sector Erase.* - set the number of dummy cycles (mode cycles + wait states).* - set the SPI protocols for register and memory accesses.* - set the Quad Enable bit if needed (required by SPI x-y-4 protos).*/ret = spi_nor_setup(nor, info, ¶ms, hwcaps);.......
}
2.5 设置地址宽度
int spi_nor_scan(struct spi_nor *nor, const char *name,const struct spi_nor_hwcaps *hwcaps)
{.....if (nor->addr_width) {/* already configured from SFDP */} else if (info->addr_width) {nor->addr_width = info->addr_width;} else if (mtd->size > 0x1000000) {/* enable 4-byte addressing if the device exceeds 16MiB */nor->addr_width = 4;if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||info->flags & SPI_NOR_4B_OPCODES)spi_nor_set_4byte_opcodes(nor, info);elseset_4byte(nor, info, 1);} else {nor->addr_width = 3;}.......
}
如果nor flash的大小超过16M,那么必须使用4根地址线才能访问全部的flash空间。
2.6 s3an_nor_scan
int spi_nor_scan(struct spi_nor *nor, const char *name,const struct spi_nor_hwcaps *hwcaps)
{.....if (info->flags & SPI_S3AN) {ret = s3an_nor_scan(info, nor);if (ret)return ret;}.......
}
s3an_nor_scan后面再说。
Linux内核4.14版本——SPI NOR子系统(2)——spi-nor.c分析相关推荐
- Linux内核4.14版本:ARM64的内核启动过程(二)——start_kernel
目录 1. rest_init 2. init 进程(kernel_init) 2.1 kernel_init_freeable 2.1.1 do_basic_setup 2.1.2 prepare_ ...
- Linux内核4.14版本——watchdog看门狗框架分析
目录 0 简介 1. 设备的注册 1.1 dw_wdt_drv_probe 1.2 watchdog_register_device 1.3 __watchdog_register_device 1. ...
- Linux内核4.14版本——DMA Engine框架分析(6)-实战(测试dma驱动)
1. dw-axi-dmac驱动 2. dma的测试程序 2.1 内核程序 2.2 用户测试程序 1. dw-axi-dmac驱动 dw-axi-dmac驱动4.14版本没有,是从5.4版本移植的,基 ...
- Linux内核4.14版本——alsa框架分析(1)—alsa简介
目录 一,ALSA声音编程介绍 二,ALSA历史 三,数字音频基础 四,ALSA基础 五,ALSA体系结构 六,设备命名 七,声音缓存和数据传输 八,Over and Under Run 九,一个典型 ...
- Linux内核4.14版本——drm框架分析(1)——drm简介
目录 1. DRM简介(Direct Rendering Manager) 1.1 DRM发展历史 1.2 DRM架构对比FB架构优势 1.3 DRM图形显示框架 1.4 DRM图形显示框架涉及元素 ...
- Linux内核4.14版本——SPI NOR子系统(3)——cadence-quadspi.c分析
目录 1. 芯片简介 1.1 模块与接口 1.2 访问模式 2. DTS 2.1 reg 2.2 cdns,trigger-address 2.3 匹配DTS的驱动程序入口 3. cqspi_prob ...
- Linux内核4.14版本——GPIO子系统(1)——gpiolib分析
目录 1.简述 2.Gpiolib 相关数据结构分析 2.1 gpio_chip 结构 2.2 gpio_desc 结构 2.3 gpio_device 结构 3 Gpiolib 对接芯片底层 3.1 ...
- Linux内核4.14版本——Nand子系统(1)——hisi504_nand.c分析
1. 简介 2. DTS 3. hisi_nfc_probe函数 3.1 获取dts中的资源 3.2 设置nand-chip结构体中必要的字段 3.3 nand_scan_ident扫描识别nand控 ...
- Linux内核4.14版本——mmc框架_软件总体架构
目录 1. 前言 2. 软件架构 3. 工作流程 4. mmc设备 4.1 mmc type card 4.2 sd type card 4.3 sdio type card 5. mmc协议 5.1 ...
最新文章
- 第一次用写一个3d轮播
- Oracle AWR 报告中 No data exists for this section of the report 说明
- 罗斯霍曼理工学院计算机毕业生,全美最强STEM大学,了解一下?
- 恒驰机器人_恒大汽车基地:2545台机器人为恒驰“效力”
- 【Object类、日期、StringBuilder】
- Spring Boot 单元测试详解+实战教程
- 【PAT甲级最新题解】PAT甲级2020.7月春季考试满分题解(附代码)
- Redis3.2.5部署(单节点)
- LeetCode 1992. 找到所有的农场组(BFS)
- MATLAB 【学习视频推荐】——新手必备
- Java排序算法-桶排序
- python3x菜鸟教程_菜鸟教程python3
- 实战 用Python放一场浪漫的烟花秀
- SQL 触发器 简记
- mount挂载不上,不提示任何信息
- TMS320C5509A 控制DDS AD9854芯片进行AM幅度调制时的FIR滤波处理
- 奈奎斯特定理和香农定理解释
- 10天精读掌握:计算机组成与设计COAD:Patterson and Hennessy 第7天 2018/11.1
- Xilinx SDK编译Microblaze时出错
- 配置了Maven环境变量后,cmd中mvn -v一直报“mvn不是内部命令”
热门文章
- MATLAB与DSP(C6657)的TCP/IP通信实现
- 【TIC6657 DSP学习笔记】01 工程创建与代码编写——以点亮LED为例
- TensorFlow深度学习:3.API示范
- html5不断切换的场景,HTML5场景: 沉舟侧畔千帆过(漂浮和沉没的帆船)
- 轻松解决夜神逍遥模拟器模拟器等模拟器无法连接问题
- div做表格 html5,div+css制作表格
- bcb6 连接mysql_BCB6常见问题
- ENGLISH资料收集(3)-英语日期的正确表达
- 卡方分布(Chi-Squared Distribution)
- android应用市场汇总