手上有个4MB的SPI接口的Nor Flash芯片,很早之前就想在Linux上调试一把了,今天花了一上午的时间终于搞定了,其实蛮简单的,因为内核已经support了这款芯片,所以也没花多少时间。

1.先看SPI Nor Flash的硬件接口:

我的板子是标准SPI,那么这里就多出来了2个PIN需要处理,WP和HOLD脚,先看Spec说明:

如上WP是低电平有效,也就是说要为高电平才能正常操作芯片


如上HOLD要为高电平才能正常操作芯片

那么简单了,只需要将HOLD和WP和VCC(3.3V)接在一起就OK了

2. 代码编写
Linux内核中本身也是支持winbond的flash芯片的,其中也有例程代码:

drivers\mtd\devices\m25p80.c

而我们只需要参照这个文件改下即可,如下是我的代码:

drivers\mtd\devices\w25q32jv.c

/** MTD SPI driver for ST w25qxx (and similar) serial flash chips** Author: Mike Lavender, mike@steroidmicros.com** Copyright (c) 2005, Intec Automation Inc.** Some parts are based on lart.c by Abraham Van Der Merwe** Cleaned up and generalized based on mtd_dataflash.c** This code is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License version 2 as* published by the Free Software Foundation.**/#include <linux/err.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/device.h>#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/mtd/spi-nor.h>#define MAX_CMD_SIZE        6#define SPI_TRANSFER_TEST
#ifdef SPI_TRANSFER_TEST
#include <linux/types.h>
#include <linux/spi/spidev.h>struct w25q {struct spi_device   *spi;struct device  *dev;struct spi_nor     spi_nor;u8          command[MAX_CMD_SIZE];char *rx_buffer;int rx_len;char *tx_buffer;int tx_len;int speed_hz;
};static unsigned bufsiz = 4096;
struct w25q* W25Q = NULL;#else
struct w25q {struct spi_device  *spi;struct spi_nor     spi_nor;u8          command[MAX_CMD_SIZE];
};
#endifstatic int w25q32jv_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
{struct w25q *flash = nor->priv;struct spi_device *spi = flash->spi;int ret;ret = spi_write_then_read(spi, &code, 1, val, len);if (ret < 0)dev_err(&spi->dev, "error %d reading %x\n", ret, code);return ret;
}static void w25q_addr2cmd(struct spi_nor *nor, unsigned int addr, u8 *cmd)
{/* opcode is in cmd[0] */cmd[1] = addr >> (nor->addr_width * 8 -  8);cmd[2] = addr >> (nor->addr_width * 8 - 16);cmd[3] = addr >> (nor->addr_width * 8 - 24);cmd[4] = addr >> (nor->addr_width * 8 - 32);
}static int w25q_cmdsz(struct spi_nor *nor)
{return 1 + nor->addr_width;
}static int w25q32jv_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
{struct w25q *flash = nor->priv;struct spi_device *spi = flash->spi;flash->command[0] = opcode;if (buf)memcpy(&flash->command[1], buf, len);return spi_write(spi, flash->command, len + 1);
}static ssize_t w25q32jv_write(struct spi_nor *nor, loff_t to, size_t len,const u_char *buf)
{struct w25q *flash = nor->priv;struct spi_device *spi = flash->spi;unsigned int inst_nbits, addr_nbits, data_nbits, data_idx;struct spi_transfer t[3] = {};struct spi_message m;int cmd_sz = w25q_cmdsz(nor);ssize_t ret;/* get transfer protocols. */inst_nbits = spi_nor_get_protocol_inst_nbits(nor->write_proto);addr_nbits = spi_nor_get_protocol_addr_nbits(nor->write_proto);data_nbits = spi_nor_get_protocol_data_nbits(nor->write_proto);spi_message_init(&m);if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)cmd_sz = 1;flash->command[0] = nor->program_opcode;w25q_addr2cmd(nor, to, flash->command);t[0].tx_buf = flash->command;t[0].tx_nbits = inst_nbits;t[0].len = cmd_sz;spi_message_add_tail(&t[0], &m);/* split the op code and address bytes into two transfers if needed. */data_idx = 1;if (addr_nbits != inst_nbits) {t[0].len = 1;t[1].tx_buf = &flash->command[1];t[1].tx_nbits = addr_nbits;t[1].len = cmd_sz - 1;spi_message_add_tail(&t[1], &m);data_idx = 2;}t[data_idx].tx_buf = buf;t[data_idx].tx_nbits = data_nbits;t[data_idx].len = len;spi_message_add_tail(&t[data_idx], &m);ret = spi_sync(spi, &m);if (ret)return ret;ret = m.actual_length - cmd_sz;if (ret < 0)return -EIO;return ret;
}/** Read an address range from the nor chip.  The address range* may be any size provided it is within the physical boundaries.*/
static ssize_t w25q32jv_read(struct spi_nor *nor, loff_t from, size_t len,u_char *buf)
{struct w25q *flash = nor->priv;struct spi_device *spi = flash->spi;unsigned int inst_nbits, addr_nbits, data_nbits, data_idx;struct spi_transfer t[3];struct spi_message m;unsigned int dummy = nor->read_dummy;ssize_t ret;int cmd_sz;/* get transfer protocols. */inst_nbits = spi_nor_get_protocol_inst_nbits(nor->read_proto);addr_nbits = spi_nor_get_protocol_addr_nbits(nor->read_proto);data_nbits = spi_nor_get_protocol_data_nbits(nor->read_proto);/* convert the dummy cycles to the number of bytes */dummy = (dummy * addr_nbits) / 8;if (spi_flash_read_supported(spi)) {struct spi_flash_read_message msg;memset(&msg, 0, sizeof(msg));msg.buf = buf;msg.from = from;msg.len = len;msg.read_opcode = nor->read_opcode;msg.addr_width = nor->addr_width;msg.dummy_bytes = dummy;msg.opcode_nbits = inst_nbits;msg.addr_nbits = addr_nbits;msg.data_nbits = data_nbits;ret = spi_flash_read(spi, &msg);if (ret < 0)return ret;return msg.retlen;}spi_message_init(&m);memset(t, 0, (sizeof t));flash->command[0] = nor->read_opcode;w25q_addr2cmd(nor, from, flash->command);t[0].tx_buf = flash->command;t[0].tx_nbits = inst_nbits;t[0].len = w25q_cmdsz(nor) + dummy;spi_message_add_tail(&t[0], &m);/** Set all dummy/mode cycle bits to avoid sending some manufacturer* specific pattern, which might make the memory enter its Continuous* Read mode by mistake.* Based on the different mode cycle bit patterns listed and described* in the JESD216B specification, the 0xff value works for all memories* and all manufacturers.*/cmd_sz = t[0].len;memset(flash->command + cmd_sz - dummy, 0xff, dummy);/* split the op code and address bytes into two transfers if needed. */data_idx = 1;if (addr_nbits != inst_nbits) {t[0].len = 1;t[1].tx_buf = &flash->command[1];t[1].tx_nbits = addr_nbits;t[1].len = cmd_sz - 1;spi_message_add_tail(&t[1], &m);data_idx = 2;}t[data_idx].rx_buf = buf;t[data_idx].rx_nbits = data_nbits;t[data_idx].len = min3(len, spi_max_transfer_size(spi),spi_max_message_size(spi) - cmd_sz);spi_message_add_tail(&t[data_idx], &m);ret = spi_sync(spi, &m);if (ret)return ret;ret = m.actual_length - cmd_sz;if (ret < 0)return -EIO;return ret;
}#ifdef SPI_TRANSFER_TEST
static ssize_t
spidev_sync(struct w25q *spidev, struct spi_message *message)
{DECLARE_COMPLETION_ONSTACK(done);int status;struct spi_device *spi;spi = spidev->spi;if (spi == NULL)status = -ESHUTDOWN;elsestatus = spi_sync(spi, message);if (status == 0)status = message->actual_length;return status;
}static int spidev_message(struct w25q *spidev,struct spi_ioc_transfer *u_xfers, unsigned n_xfers)
{struct spi_message msg;struct spi_transfer *k_xfers;struct spi_transfer    *k_tmp;struct spi_ioc_transfer *u_tmp;unsigned      n, total, tx_total, rx_total;u8         *tx_buf, *rx_buf;int            status = -EFAULT;spi_message_init(&msg);k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);if (k_xfers == NULL)return -ENOMEM;/* Construct spi_message, copying any tx data to bounce buffer.* We walk the array of user-provided transfers, using each one* to initialize a kernel version of the same transfer.*/tx_buf = spidev->tx_buffer;rx_buf = spidev->rx_buffer;total = 0;tx_total = 0;rx_total = 0;for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;n > 0;n--, k_tmp++, u_tmp++) {k_tmp->len = u_tmp->len;total += k_tmp->len;/* Since the function returns the total length of transfers* on success, restrict the total to positive int values to* avoid the return value looking like an error.  Also check* each transfer length to avoid arithmetic overflow.*/if (total > INT_MAX || k_tmp->len > INT_MAX) {status = -EMSGSIZE;goto done;}if (u_tmp->rx_buf) {/* this transfer needs space in RX bounce buffer */rx_total += k_tmp->len;if (rx_total > bufsiz) {status = -EMSGSIZE;goto done;}k_tmp->rx_buf = (void *)(u_xfers->rx_buf);//rx_buf += k_tmp->len;}if (u_tmp->tx_buf) {/* this transfer needs space in TX bounce buffer */tx_total += k_tmp->len;if (tx_total > bufsiz) {status = -EMSGSIZE;goto done;}k_tmp->tx_buf = tx_buf;strncpy(tx_buf,(char *)u_tmp->tx_buf,u_tmp->len);tx_buf += k_tmp->len;}k_tmp->cs_change = !!u_tmp->cs_change;k_tmp->tx_nbits = u_tmp->tx_nbits;k_tmp->rx_nbits = u_tmp->rx_nbits;k_tmp->bits_per_word = u_tmp->bits_per_word;k_tmp->delay_usecs = u_tmp->delay_usecs;k_tmp->speed_hz = u_tmp->speed_hz;if (!k_tmp->speed_hz)k_tmp->speed_hz = spidev->speed_hz;spi_message_add_tail(k_tmp, &msg);}status = spidev_sync(spidev, &msg);if (status < 0){printk("%s LINE = %d\n",__func__,__LINE__);goto done;}status = total;done:kfree(k_xfers);return status;
}int transfer_demo(struct w25q *flash)
{int ret = 0;u8 recevie_buf[4] = {0x0};u8 send_buf[4] = {0x0};struct spi_ioc_transfer tr = {.tx_buf = (unsigned long)send_buf,   //定义发送缓冲区指针.rx_buf = (unsigned long)recevie_buf,   //定义接收缓冲区指针.len = 4,         .delay_usecs = 0,.speed_hz = 1000000,.bits_per_word = 8,};   W25Q = flash;W25Q->dev = &flash->spi->dev;W25Q->tx_buffer = kmalloc(bufsiz, GFP_KERNEL);if (!W25Q->tx_buffer) {dev_err(&W25Q->spi->dev, "alloc tx_buffer failed\n");return -ENOMEM;}W25Q->rx_buffer = kmalloc(bufsiz, GFP_KERNEL);if (!W25Q->rx_buffer) {dev_err(&W25Q->spi->dev, "alloc rx_buffer failed\n");return -ENOMEM;}send_buf[0] = 0x9f;ret = spidev_message(W25Q,&tr,1);printk("transfer_demo result : %02x:%02x:%02x\n",recevie_buf[1],recevie_buf[2],recevie_buf[3]);return ret;
}#endif/** board specific setup should have ensured the SPI clock used here* matches what the READ command supports, at least until this driver* understands FAST_READ (for clocks over 25 MHz).*/
static int w25q_probe(struct spi_device *spi)
{struct flash_platform_data *data;struct w25q *flash;struct spi_nor *nor;struct spi_nor_hwcaps hwcaps = {.mask = SNOR_HWCAPS_READ |SNOR_HWCAPS_READ_FAST |SNOR_HWCAPS_PP,};char *flash_name;int ret;data = dev_get_platdata(&spi->dev);flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);if (!flash)return -ENOMEM;nor = &flash->spi_nor;/* install the hooks */nor->read = w25q32jv_read;nor->write = w25q32jv_write;nor->write_reg = w25q32jv_write_reg;nor->read_reg = w25q32jv_read_reg;nor->dev = &spi->dev;spi_nor_set_flash_node(nor, spi->dev.of_node);nor->priv = flash;spi_set_drvdata(spi, flash);flash->spi = spi;if (spi->mode & SPI_RX_QUAD) {hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;if (spi->mode & SPI_TX_QUAD)hwcaps.mask |= (SNOR_HWCAPS_READ_1_4_4 |SNOR_HWCAPS_PP_1_1_4 |SNOR_HWCAPS_PP_1_4_4);} else if (spi->mode & SPI_RX_DUAL) {hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;if (spi->mode & SPI_TX_DUAL)hwcaps.mask |= SNOR_HWCAPS_READ_1_2_2;}if (data && data->name)nor->mtd.name = data->name;/* For some (historical?) reason many platforms provide two different* names in flash_platform_data: "name" and "type". Quite often name is* set to "w25q32jv" and then "type" provides a real chip name.* If that's the case, respect "type" and ignore a "name".*/if (data && data->type)flash_name = data->type;else if (!strcmp(spi->modalias, "spi-nor"))flash_name = NULL; /* auto-detect */elseflash_name = spi->modalias;#ifdef SPI_TRANSFER_TESTret = transfer_demo(flash);
#endifret = spi_nor_scan(nor, flash_name, &hwcaps);if (ret)return ret;return mtd_device_register(&nor->mtd, data ? data->parts : NULL,data ? data->nr_parts : 0);
}static int w25q_remove(struct spi_device *spi)
{struct w25q    *flash = spi_get_drvdata(spi);/* Clean up MTD stuff. */return mtd_device_unregister(&flash->spi_nor.mtd);
}/** Do NOT add to this array without reading the following:** Historically, many flash devices are bound to this driver by their name. But* since most of these flash are compatible to some extent, and their* differences can often be differentiated by the JEDEC read-ID command, we* encourage new users to add support to the spi-nor library, and simply bind* against a generic string here (e.g., "jedec,spi-nor").** Many flash names are kept here in this list (as well as in spi-nor.c) to* keep them available as module aliases for existing platforms.*/
static const struct spi_device_id w25q_ids[] = {/** Allow non-DT platform devices to bind to the "spi-nor" modalias, and* hack around the fact that the SPI core does not provide uevent* matching for .of_match_table*/{"spi-nor"},/** Entries not used in DTs that should be safe to drop after replacing* them with "spi-nor" in platform data.*/{"s25sl064a"}, {"w25x16"},   {"w25q10"},   {"w25qx64"},/** Entries that were used in DTs without "jedec,spi-nor" fallback and* should be kept for backward compatibility.*/{"at25df321a"},   {"at25df641"},    {"at26df081a"},{"mx25l4005a"},  {"mx25l1606e"},   {"mx25l6405d"},   {"mx25l12805d"},{"mx25l25635e"},{"mx66l51235l"},{"n25q064"},    {"n25q128a11"},   {"n25q128a13"},   {"n25q512a"},{"s25fl256s1"},    {"s25fl512s"},    {"s25sl12801"},   {"s25fl008k"},{"s25fl064k"},{"sst25vf040b"},{"sst25vf016b"},{"sst25vf032b"},{"sst25wf040"},{"w25q40"},    {"w25q32jv"}, {"w25q16"},   {"w25q32"},{"w25q64"},  {"w25q128"},{"w25x80"}, {"w25x32"},   {"w25q32"},   {"w25q32dw"},{"w25q80bl"},  {"w25q128"},  {"w25q256"},/* Flashes that can't be detected using JEDEC */{"w25q05-nonjedec"},   {"w25q10-nonjedec"},  {"w25q20-nonjedec"},{"w25q40-nonjedec"},    {"w25q32jv-nonjedec"},    {"w25q16-nonjedec"},{"w25q32-nonjedec"},    {"w25q64-nonjedec"},  {"w25q128-nonjedec"},/* Everspin MRAMs (non-JEDEC) */{ "mr25h256" }, /* 256 Kib, 40 MHz */{ "mr25h10" },  /*   1 Mib, 40 MHz */{ "mr25h40" },  /*   4 Mib, 40 MHz */{ },
};
MODULE_DEVICE_TABLE(spi, w25q_ids);static const struct of_device_id w25q_of_table[] = {/** Generic compatibility for SPI NOR that can be identified by the* JEDEC READ ID opcode (0x9F). Use this, if possible.*/{ .compatible = "w25q32jv,spi-nor" },{}
};
MODULE_DEVICE_TABLE(of, w25q_of_table);static struct spi_driver w25q32jv_driver = {.driver = {.name   = "w25q32jv",.of_match_table = w25q_of_table,},.id_table    = w25q_ids,.probe  = w25q_probe,.remove   = w25q_remove,/* REVISIT: many of these chips have deep power-down modes, which* should clearly be entered on suspend() to minimize power use.* And also when they're otherwise idle...*/
};static int __init w25q32jv_init(void)
{int status;status = spi_register_driver(&w25q32jv_driver);if (status < 0) {pr_err("w25q32jv_driver init failed\n");return status;}pr_err("w25q32jv_driver init success\n");return status;
}
module_init(w25q32jv_init);static void __exit w25q32jv_exit(void)
{pr_err("w25q32jv_driver exit\n");spi_unregister_driver(&w25q32jv_driver);
}
module_exit(w25q32jv_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mike Lavender");
MODULE_DESCRIPTION("MTD SPI driver for ST w25qxx flash chips");

如果不在支持列表,那么切记要修改下面这支文件

drivers\mtd\spi-nor\spi-nor.c

static const struct flash_info spi_nor_ids[] = {...{ "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },...
}

我这颗刚好内核中已经有了,省了这一步

3. 修改dtsi文件

spiflash: spiflash@1 {#address-cells = <1>;#size-cells = <1>;compatible = "w25q32jv,spi-nor";reg = <0>; //注意片选不要和该总线上的其他设备冲突,当前 CS 低电平有效status = "okay";spi-max-frequency = <10000000>;mode = <0>;partition@0 {reg = <0x0 0x1000000>;label = "spi-flash";};
};

4. 查看内核Log,确认是否已经识别到了

root@NanoPi-NEO:/home# insmod w25q32jv.ko
[ 2006.334004] w25q32jv spi0.0: JEDEC id bytes: ef, 40, 16
[ 2006.348647] w25q32jv_driver init success
root@NanoPi-NEO:/home# dmesg -c
[ 2006.333526] __spi_register_driver LINE = 398
[ 2006.333896] transfer_demo result : ef:40:16
[ 2006.334004] w25q32jv spi0.0: JEDEC id bytes: ef, 40, 16
[ 2006.339365] w25q32jv spi0.0: w25q32 (4096 Kbytes)
[ 2006.345831] 1 ofpart partitions found on MTD device spi0.0
[ 2006.345846] Creating 1 MTD partitions on "spi0.0":
[ 2006.345865] 0x000000000000-0x000001000000 : "spi-flash"
[ 2006.345871] mtd: partition "spi-flash" extends beyond the end of device "spi0
[ 2006.348647] w25q32jv_driver init success

Perfect,内核已经成功识别芯片,并为我创建了一个分区

我们还可以再看下mtd信息,进一步确认

root@NanoPi-NEO:/home# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00400000 00001000 "spi-flash"

各字段解释如下:

size:分区大小(字节),当前spi flash为4M
erasesize:单次最小擦除字节数,(当前4K)

5. 格式化分区,挂载磁盘

flash_erase /dev/mtd0 0 0

然后挂载分区到mnt目录

mount -t jffs2 /dev/mtdblock0 /mnt

root@NanoPi-NEO:/home# mount -t jffs2 /dev/mtdblock0 /mnt
root@NanoPi-NEO:/home# cd /mnt/
root@NanoPi-NEO:/mnt# ls
root@NanoPi-NEO:/mnt#

创建一个文件,并向里面写入内容

root@NanoPi-NEO:/mnt# touch hello.txt
root@NanoPi-NEO:/mnt# echo hello > hello.txt
root@NanoPi-NEO:/mnt# cat hello.txt
hello

随后umount掉mnt分区

root@NanoPi-NEO:/mnt# cd ..
root@NanoPi-NEO:/# umount /mnt/
root@NanoPi-NEO:/#

之后重启终端,重新挂载分区到mnt目录,确认文件已经成功写入

root@NanoPi-NEO:/# mount -t jffs2 /dev/mtdblock0 /mnt
root@NanoPi-NEO:/# cd mnt/
root@NanoPi-NEO:/mnt# ls
hello.txt
root@NanoPi-NEO:/mnt# cat hello.txt
hello
root@NanoPi-NEO:/mnt#

SPI Nor Flash在Linux下调试相关推荐

  1. linux下调试core dump方式汇总,工作必备技能

    缘起 调试,是开发流程中一个非常重要的环节.每个程序员都应,具备调试代码的能力,尤其对于从事 Linux 下的开发的读者. 从事 linux 下后台开发,有时候会遇到程序突然崩溃的情况,也没有任何日志 ...

  2. Linux下调试器工作原理

    Linux下调试器工作原理之一-基础篇 介绍关于Linux下的调试器实现的主要组成部分--ptrace系统调用.本文中出现的代码都在32位的Ubuntu系统上开发.请注意,这里出现的代码是同平台紧密相 ...

  3. linux下调试thread 类_linux下GDB调试

    linux下GDB是一个非常强大的调试工具,但是他不像vs一样具有强大的图形界面,基本都靠命令来进行调试,对于新手来说也算是个坎.下面就跟大家一起探究一下gdb这个强大的调试工具. 1.开启core ...

  4. linux opera flash插件,Linux下64位的Firefox、Opera浏览器安装Flash插件

    Linux下,64位的Firefox.Opera等浏览器默认搜索到的Flash插件是32位的,安装之后也不能正常工作. 需要手工安装一下. 1.下载插件 使用浏览器下载: 到Adobe的站点上下载64 ...

  5. linux下调试thread 类_在 RISC-V 芯片 GD32V 上运行 RT-Thread

    在 RISC-V 芯片 GD32V 上运行 RT-Thread GD32VF103 开发板 去年九月份的时候 RT-Thread 的 Andy Chen 组织定做了一块 GD32V 开发板,托 And ...

  6. Linux下调试器GDB的简单使用图解

    gdb是一个由GNU开源组织发布的.UNIX/LINUX操作系统下的.基于命令行的.功能强大的程序调试工具. 当前是虚拟机上的Ubuntu系统:敲Ctrl+Alt+t,打开控制台终端: which g ...

  7. python手机编程调试_在Linux下调试Python代码的各种方法

    这是一个我用于调试或分析工具概述,不一定是完整全面,如果你知道更好的工具,请在评论处标记. 日志 是的,的确,不得不强调足够的日志记录对应用程序是多么的重要.您应该记录重要的东西,如果你的记录足够好的 ...

  8. Linux下调试1588单步时间戳报文

    欢迎淘宝搜索飞灵科技,我司相关新产品陆续上线. 这几天在为一个网络控制器实现IEEE 1588单步时间戳的驱动,几经调试终于完工了.顺便分享一下调试方法,当然如果你想玩1588的单步时间戳,首先得有支 ...

  9. linux中调试脚本,在Linux下调试 Shell 脚本

    在大多数编程语言中都有调试工具可用于调试. 调试工具可以运行需要调试的程序或脚本,使我们可以在运行时检查脚本或程序的内部执行过程. 在shell脚本中我们没有任何调试工具,只能借助命令行选项(-n,- ...

  10. Linux下调试python

    原文地址:http://www.cnblogs.com/chinasun021/archive/2013/03/19/2969107.html 先找了段简单的测试程序: 复制代码 !/usr/bin/ ...

最新文章

  1. 磁盘管理命令:du df
  2. 微信小程序,时间戳和日期格式互相转化
  3. python教程timeit模块的使用教程
  4. 安卓重构系列-01使用Kotlin开发第一个Demo
  5. APF filter到底支持多复杂的条件
  6. 二维碰撞检测matlab,二维平面内的碰撞检测【二】
  7. 【C++】 12_经典问题解析 一
  8. 使用yuicompressor 压缩js, CSS
  9. 系统分析员备考之经济管理篇(一)
  10. HCIE-Security Day9:5个实验理解NAT Server
  11. Centos yum 命令行 安装KDE Desktop
  12. MATLAB 2016b--神经网络工具箱中BP网络的实现
  13. 【成神之路】Mysql相关面试题
  14. 旅人随笔[02] 量子物理的故事
  15. php递归遍历出文件夹下的所有文件和删除文件夹下的所有文件
  16. 矩形区域的泊松方程,深度学习模拟差分法
  17. 使用auto.js模拟手动点击芭芭农场任务(芭芭农场自动脚本)
  18. Flink的非Barrier对齐可以优化高反压
  19. DDOS攻击 — 棋牌游戏创业公司的生死劫
  20. 敢达决战服务器维护,敢达决战2月24日全区全服更新公告

热门文章

  1. freeCodeCamp:Confirm the Ending
  2. wireshark解密本地https流量笔记
  3. linux 64位操作系统安装32位运行库
  4. c#文件流读取编码问题(转)新增加一个方法解决不带BOM的问题
  5. 封装dialog弹窗
  6. 设计模式学习与应用——单例模式
  7. 2017.11.21 MS Power BI training
  8. System Security Services Daemon(SSSD)系统安全服务守护进程
  9. 处理 Vue-Router + Webpack 动态加载的一些小问题
  10. Android Studio建立百度地图步骤及导航无语音解决方法