返回顶部
首页 > 资讯 > 操作系统 >Linux下如何进行SPI驱动
  • 791
分享到

Linux下如何进行SPI驱动

2023-06-15 14:06:04 791人浏览 独家记忆
摘要

linux下如何进行SPI驱动,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1. SPI总线1.1. SPI总线概述SPI,是英语Serial Peripheral &nb

linux下如何进行SPI驱动,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

1. SPI总线

1.1. SPI总线概述

SPI,是英语Serial Peripheral  interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在  EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。SPI总线的构成及信号类型如图1-1所示:

  • MOSI – 主设备数据输出,从设备数据输入 对应MOSI master output slave input

  • MISO – 主设备数据输入,从设备数据输出 对应MISO master input slave output

  • CLK – 时钟信号,由主设备产生

  • nCS – 从设备使能信号,由主设备控制

Linux下如何进行SPI驱动

图1-1 SPI总线模型

1.2. SPI总线时序

SPI接口在Master控制下产生的从设备使能信号和时钟信号,两个双向移位寄存器按位传输进行数据交换,传输数据高位在前(MSB  first),低位在后。如下图所示,在CLK的下降沿上数据改变,上升沿一位数据被存入移位寄存器。

Linux下如何进行SPI驱动

图1-2 spi传输时序图

在一个SPI时钟周期内,会完成如下操作:(1)Master通过MOSI线发送1位数据,同时Slave通过MOSI线读取这1位数据;(2)Slave通过MISO线发送1位数据,同时Master通过MISO线读取这1位数据。Master和Slave各有一个移位寄存器,如图1-3所示,而且这两个移位寄存器连接成环状。依照CLK的变化,数据以MSB  first的方式依次移出Master寄存器和Slave寄存器,并且依次移入Slave寄存器和Master寄存器。当寄存器中的内容全部移出时,相当于完成了两个寄存器内容的交换。

Linux下如何进行SPI驱动  

1.3. SPI总线传输模式

SPI总线传输一共有4种模式,这4种模式分别由时钟极性(CPOL,Clock  Polarity)和时钟相位(CPHA,Clock  Phase)来定义,其中CPOL参数规定了SCK时钟信号空闲状态的电平,CPHA规定了数据是在SCK时钟的上升沿被采样还是下降沿被采样。这四种模式的时序图如下图1-4所示:

Linux下如何进行SPI驱动
  • 模式0:CPOL= 0,CPHA=0。CLK串行时钟线空闲是为低电平,数据在SCK时钟的上升沿被采样,数据在CLK时钟的下降沿切换

  • 模式1:CPOL= 0,CPHA=1。CLK串行时钟线空闲是为低电平,数据在SCK时钟的下降沿被采样,数据在CLK时钟的上升沿切换

  • 模式2:CPOL= 1,CPHA=0。CLK串行时钟线空闲是为高电平,数据在SCK时钟的下降沿被采样,数据在CLK时钟的上升沿切换

  • 模式3:CPOL= 1,CPHA=1。CLK串行时钟线空闲是为高电平,数据在SCK时钟的上升沿被采样,数据在CLK时钟的下降沿切换  其中比较常用的模式是模式0和模式3。为了更清晰的描述SPI总线的时序,下面展现了模式0下的SPI时序图1-5:

 Linux下如何进行SPI驱动

图1-5 mode0下的SPI时序图

1.4. SPI总线的优缺点

(1) 在点对点的通信中,SPI接口不需要进行寻址操作,且为全双工通信,显得简单高效。(2)  SPI接口没有指定的流控制,没有应答机制确认是否接收到数据。

2. Linux SPI 框架

2.1. 软件架构

Linux系统对spi设备具有很好的支持,linux系统下的spi驱动程序从逻辑上可以分为3个部分:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. spi核心(SPI Core):SPI Core是Linux内核用来维护和管理spi的核心部分,SPI Core提供操作接口函数,允许一个spi  master,spi driver和spi device初始化时在SPI Core中进行注册,以及退出时进行注销。

  3. spi控制器驱动(SPI Master Driver):SPI Master针对不同类型的spi控制器硬件,实现spi总线的硬件访问操作。SPI  Master通过接口函数向SPI Core注册一个控制器。

  4. spi设备驱动(SPI Device Driver):SPI Driver是对应于spi设备端的驱动程序,通过接口函数向SPI Core进行注册,SPI  Driver的作用是将spi设备挂接到spi总线上;Linux的软件架构图如图2-1所示:

 Linux下如何进行SPI驱动

图2-1 spi软件架构图

2.2. 初始化及退出流程

2.2.1. 注册spi控制器

注册spi控制器到内核分为两个阶段:第一个阶段,使用spi_alloc_master,分配一个spi_master的空间,具体流程如图2-2所示:

Linux下如何进行SPI驱动

第二阶段,使用spi_reGISter_master将第一阶段分配的spi_master注册到内核中,具体流程如2-3所示:

Linux下如何进行SPI驱动

2.2.2. 注销spi控制器

spi控制器注销的流程如图2-4所示:

Linux下如何进行SPI驱动

2.3. 关键数据结构

2.3.1. spi_device

struct spi_device {         struct device         dev;               u32                     max_speed_hz;            u8                      chip_select;               u8                      mode; #define SPI_CPHA        0x01                     #define SPI_CPOL        0x02                     #define SPI_MODE_0      (0|0)                    #define SPI_MODE_1      (0|SPI_CPHA) #define SPI_MODE_2      (SPI_CPOL|0) #define SPI_MODE_3      (SPI_CPOL|SPI_CPHA) #define SPI_CS_HIGH     0x04                     #define SPI_LSB_FIRST   0x08                     #define SPI_3WIRE       0x10                     #define SPI_LOOP        0x20                     #define SPI_NO_CS       0x40                     #define SPI_READY       0x80                             u8                      bits_per_Word;             int                     irq;         void                    *controller_state;          void                    *controller_data;            char                    modalias[SPI_NAME_SIZE];          int                     cs_gpio;                   };

spi_device代表一个外围spi设备,由master controller  driver注册完成后扫描BSP中注册设备产生的设备链表并向spi_bus注册产生。在内核中,每个spi_device代表一个物理的spi设备。

2.3.2. spi_driver

struct spi_driver {         const struct spi_device_id *id_table;           int                     (*probe)(struct spi_device *spi);         int                     (*remove)(struct spi_device *spi);         void                    (*shutdown)(struct spi_device *spi);         int                     (*suspend)(struct spi_device *spi, pm_message_t mesg);         int                     (*resume)(struct spi_device *spi);         struct device_driver    driver; };

spi_driver代表一个SPI protocol drivers,即外设驱动

2.3.3. struct spi_master

struct spi_master {         struct device   dev;            struct list_head list;           s16                     bus_num;                    u16                     num_chipselect;                    u16                     dma_alignment;                   u16                     mode_bits;                      u32                     bits_per_word_mask;                   u16                     flags;  #define SPI_MASTER_NO_RX        BIT(1)           #define SPI_MASTER_NO_TX        BIT(2)                             spinlock_t              bus_lock_spinlock;         struct mutex            bus_lock_mutex;                   bool                    bus_lock_flag;                   int                     (*setup)(struct spi_device *spi);                    int                     (*transfer)(struct spi_device *spi,                                                 struct spi_message *mesg);                        void                    (*cleanup)(struct spi_device *spi);                    bool                      queued;          struct kthread_worker  kworker;          struct task_struct     *kworker_task;         struct kthread_work    pump_messages;          spinlock_t               queue_lock;         struct list_head        queue;          struct spi_message     *cur_msg;         bool                       busy; /忙状态*/         bool                       running;          bool                       rt;           int (*prepare_transfer_hardware)(struct spi_master *master);          int (*transfer_one_message)(struct spi_master *master, struct spi_message *mesg);        int (*unprepare_transfer_hardware)(struct spi_master *master);                   int                     *cs_gpiOS; };

spi_master代表一个spi控制器。

2.3.4. struct spi_message 和spi_transfer

要完成和SPI设备的数据传输工作,我们还需要另外两个数据结构:spi_message和spi_transfer。

spi_message包含了一个的spi_transfer结构序列,一旦控制器接收了一个spi_message,其中的spi_transfer应该按顺序被发送,并且不能被其它spi_message打断,所以我们认为spi_message就是一次SPI数据交换的原子操作。下面我们看看这两个数据结构的定义:

struct spi_message :

struct spi_message {         struct list_head        transfers;            struct spi_device       *spi;          unsigned                is_dma_mapped:1;                               void                    (*complete)(void *context);         void                    *context;          unsigned                actual_length;          int                     status;                    struct list_head        queue;         void                    *state; };

链表字段queue用于把该结构挂在代表控制器的spi_master结构的queue字段上,控制器上可以同时被加入多个spi_message进行排队。另一个链表字段transfers则用于链接挂在本message下的spi_tranfer结构。complete回调函数则会在该message下的所有spi_transfer都被传输完成时被调用,以便通知协议驱动处理接收到的数据以及准备下一批需要发送的数据。我们再来看看spi_transfer结构:spi_transfer

struct spi_transfer {                  const void     *tx_buf;          void            *rx_buf;          unsigned        len;           dma_addr_t      tx_dma;          dma_addr_t      rx_dma;             unsigned        cs_change:1;          u8              bits_per_word;          u16             delay_usecs;          u32             speed_hz;   #ifdef CONFIG_SPI_LOMBO         struct lombo_spi_operate_para *esop; #endif          struct list_head transfer_list;   };

首先,transfer_list链表字段用于把该transfer挂在一个spi_message结构中,tx_buf和rx_buf提供了非dma模式下的数据缓冲区地址,len则是需要传输数据的长度,tx_dma和rx_dma则给出了dma模式下的缓冲区地址。原则来讲,spi_transfer才是传输的最小单位,之所以又引进了spi_message进行打包,我觉得原因是:有时候希望往spi设备的多个不连续的地址(或寄存器)一次性写入,如果没有spi_message进行把这样的多个spi_transfer打包,因为通常真正的数据传送工作是在另一个内核线程(工作队列)中完成的,不打包的后果就是会造成更多的进程切换,效率降低,延迟增加,尤其对于多个不连续地址的小规模数据传送而言就更为明显。

2.3.5. spi_board_info

struct spi_board_info {                  char            modalias[SPI_NAME_SIZE];           const void      *platfORM_data;          void            *controller_data;          int             irq;                   u32             max_speed_hz;                     u16             bus_num;          u16             chip_select;                    u8              mode;            };

2.4. 数据传输流程

整体的数据传输流程大致上是这样的:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. 定义一个spi_message结构;

  3. 用spi_message_init函数初始化spi_message;

  4. 定义一个或数个spi_transfer结构,初始化并为数据准备缓冲区并赋值给spi_transfer相应的字段(tx_buf,rx_buf等);

  5. 通过spi_message_init函数把这些spi_transfer挂在spi_message结构下;

  6. 如果使用同步方式,调用spi_sync(),如果使用异步方式,调用spi_async();(我调试外设时,只使用过spi_sync

传输示意图如图2-5所示:

Linux下如何进行SPI驱动

2.4.1. 数据准备

2.4.1.1. spi_message_init

static inline void spi_message_init(struct spi_message *m) {  memset(m, 0, sizeof *m);  INIT_LIST_HEAD(&m->transfers); }

初始化spi_message:清空message,初始化transfers链表头。

2.4.1.2. spi_message_add_tail

static inline void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m) {  list_add_tail(&t->transfer_list, &m->transfers); }

将spi_transfer加入到spi_message的链表尾部。

2.4.2. 数据传输

SPI数据传输可以有两种方式:同步方式和异步方式。所谓同步方式是指数据传输的发起者必须等待本次传输的结束,期间不能做其它事情,用代码来解释就是,调用传输的函数后,直到数据传输完成,函数才会返回。而异步方式则正好相反,数据传输的发起者无需等待传输的结束,数据传输期间还可以做其它事情,用代码来解释就是,调用传输的函数后,函数会立刻返回而不用等待数据传输完成,我们只需设置一个回调函数,传输完成后,该回调函数会被调用以通知发起者数据传送已经完成。同步方式简单易用,很适合处理那些少量数据的单次传输。但是对于数据量大、次数多的传输来说,异步方式就显得更加合适。对于SPI控制器来说,要支持异步方式必须要考虑以下两种状况:

  • 对于同一个数据传输的发起者,既然异步方式无需等待数据传输完成即可返回,返回后,该发起者可以立刻又发起一个message,而这时上一个message还没有处理完。

  • 对于另外一个不同的发起者来说,也有可能同时发起一次message传输请求 首先分析spi_sync()接口的实现流程,如图2-6:

Linux下如何进行SPI驱动

其次分析spi_async_locked接口的实现流程,如图2-7所示:

Linux下如何进行SPI驱动  

spi_queued_transfer接口的实现流程如图3-8所示:

Linux下如何进行SPI驱动

spi_pump_messages函数的处理流程如图3-9所示:

Linux下如何进行SPI驱动

图中transfer_one_message是spi控制器驱动要实现的,主要功能是处理spi_message中的每个spi_transfer。

2.5. 关键函数解析

2.5.1. spi_alloc_master

原型:

struct spi_master *spi_alloc_master(struct device *dev, unsigned size)

功能:分配一个spi_master结构体指针。

参数:dev:spi控制器device指针 size :分配的driver-private data大小

返回值 :成功,返回spi_master指针;否则返回NULL

2.5.2. spi_register_master

原型:

int spi_register_master(struct spi_master *master)

功能 注册spi控制器驱动到内核。

参数 master:spi_master指针

返回值 成功,返回0;否则返回错误码

2.5.3. spi_unregister_master

原型:

void spi_unregister_master(struct spi_master *master)

功能 注销spi控制器驱动。

参数 master:spi_master指针

返回值 无

3. Demo

#include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/init.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/gpio.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/of_gpio.h> #include <linux/semaphore.h> #include <linux/timer.h> #include <linux/i2c.h> #include <linux/spi/spi.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_gpio.h> #include <linux/platform_device.h> #include <asm/Mach/map.h> #include <asm/uaccess.h> #include <asm/io.h> #include "icm20608reg.h"  #define ICM20608_CNT 1 #define ICM20608_NAME "icm20608"  struct icm20608_dev {  dev_t devid;      struct cdev cdev;     struct class *class;    struct device *device;    struct device_node *nd;    int major;       void *private_data;     int cs_gpio;      signed int gyro_x_adc;    signed int gyro_y_adc;    signed int gyro_z_adc;    signed int accel_x_adc;    signed int accel_y_adc;    signed int accel_z_adc;    signed int temp_adc;   };  static struct icm20608_dev icm20608dev;   static int icm20608_read_regs(struct icm20608_dev *dev, u8 reg, void *buf, int len) {  int ret;  unsigned char txdata[len];  struct spi_message m;  struct spi_transfer *t;  struct spi_device *spi = (struct spi_device *)dev->private_data;   gpio_set_value(dev->cs_gpio, 0);      t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);      txdata[0] = reg | 0x80;    t->tx_buf = txdata;     t->len = 1;       spi_message_init(&m);    spi_message_add_tail(t, &m);  ret = spi_sync(spi, &m);      txdata[0] = 0xff;     t->rx_buf = buf;     t->len = len;      spi_message_init(&m);    spi_message_add_tail(t, &m);  ret = spi_sync(spi, &m);    kfree(t);           gpio_set_value(dev->cs_gpio, 1);      return ret; }   static s32 icm20608_write_regs(struct icm20608_dev *dev, u8 reg, u8 *buf, u8 len) {  int ret;   unsigned char txdata[len];  struct spi_message m;  struct spi_transfer *t;  struct spi_device *spi = (struct spi_device *)dev->private_data;   t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);   gpio_set_value(dev->cs_gpio, 0);        txdata[0] = reg & ~0x80;   t->tx_buf = txdata;     t->len = 1;       spi_message_init(&m);    spi_message_add_tail(t, &m);  ret = spi_sync(spi, &m);      t->tx_buf = buf;     t->len = len;      spi_message_init(&m);    spi_message_add_tail(t, &m);  ret = spi_sync(spi, &m);    kfree(t);       gpio_set_value(dev->cs_gpio, 1);  return ret; }   static unsigned char icm20608_read_onereg(struct icm20608_dev *dev, u8 reg) {  u8 data = 0;  icm20608_read_regs(dev, reg, &data, 1);  return data; }     static void icm20608_write_onereg(struct icm20608_dev *dev, u8 reg, u8 value) {  u8 buf = value;  icm20608_write_regs(dev, reg, &buf, 1); }   void icm20608_readdata(struct icm20608_dev *dev) {  unsigned char data[14];  icm20608_read_regs(dev, ICM20_ACCEL_XOUT_H, data, 14);   dev->accel_x_adc = (signed short)((data[0] << 8) | data[1]);   dev->accel_y_adc = (signed short)((data[2] << 8) | data[3]);   dev->accel_z_adc = (signed short)((data[4] << 8) | data[5]);   dev->temp_adc    = (signed short)((data[6] << 8) | data[7]);   dev->gyro_x_adc  = (signed short)((data[8] << 8) | data[9]);   dev->gyro_y_adc  = (signed short)((data[10] << 8) | data[11]);  dev->gyro_z_adc  = (signed short)((data[12] << 8) | data[13]); }   static int icm20608_open(struct inode *inode, struct file *filp) {  filp->private_data = &icm20608dev;   return 0; }   static ssize_t icm20608_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off) {  signed int data[7];  long err = 0;  struct icm20608_dev *dev = (struct icm20608_dev *)filp->private_data;   icm20608_readdata(dev);  data[0] = dev->gyro_x_adc;  data[1] = dev->gyro_y_adc;  data[2] = dev->gyro_z_adc;  data[3] = dev->accel_x_adc;  data[4] = dev->accel_y_adc;  data[5] = dev->accel_z_adc;  data[6] = dev->temp_adc;  err = copy_to_user(buf, data, sizeof(data));  return 0; }   static int icm20608_release(struct inode *inode, struct file *filp) {  return 0; }   static const struct file_operations icm20608_ops = {  .owner = THIS_MODULE,  .open = icm20608_open,  .read = icm20608_read,  .release = icm20608_release, };   void icm20608_reginit(void) {  u8 value = 0;    icm20608_write_onereg(&icm20608dev, ICM20_PWR_MGMT_1, 0x80);  mdelay(50);  icm20608_write_onereg(&icm20608dev, ICM20_PWR_MGMT_1, 0x01);  mdelay(50);   value = icm20608_read_onereg(&icm20608dev, ICM20_WHO_AM_I);  printk("ICM20608 ID = %#X\r\n", value);    icm20608_write_onereg(&icm20608dev, ICM20_SMPLRT_DIV, 0x00);    icm20608_write_onereg(&icm20608dev, ICM20_GYRO_CONFIG, 0x18);    icm20608_write_onereg(&icm20608dev, ICM20_ACCEL_CONFIG, 0x18);    icm20608_write_onereg(&icm20608dev, ICM20_CONFIG, 0x04);     icm20608_write_onereg(&icm20608dev, ICM20_ACCEL_CONFIG2, 0x04);   icm20608_write_onereg(&icm20608dev, ICM20_PWR_MGMT_2, 0x00);    icm20608_write_onereg(&icm20608dev, ICM20_LP_MODE_CFG, 0x00);    icm20608_write_onereg(&icm20608dev, ICM20_FIFO_EN, 0x00);   }     static int icm20608_probe(struct spi_device *spi) {  int ret = 0;     if (icm20608dev.major) {   icm20608dev.devid = MKDEV(icm20608dev.major, 0);   register_chrdev_region(icm20608dev.devid, ICM20608_CNT, ICM20608_NAME);  } else {   alloc_chrdev_region(&icm20608dev.devid, 0, ICM20608_CNT, ICM20608_NAME);   icm20608dev.major = MAJOR(icm20608dev.devid);  }     cdev_init(&icm20608dev.cdev, &icm20608_ops);  cdev_add(&icm20608dev.cdev, icm20608dev.devid, ICM20608_CNT);     icm20608dev.class = class_create(THIS_MODULE, ICM20608_NAME);  if (IS_ERR(icm20608dev.class)) {   return PTR_ERR(icm20608dev.class);  }     icm20608dev.device = device_create(icm20608dev.class, NULL, icm20608dev.devid, NULL, ICM20608_NAME);  if (IS_ERR(icm20608dev.device)) {   return PTR_ERR(icm20608dev.device);  }     icm20608dev.nd = of_find_node_by_path("/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02010000");  if(icm20608dev.nd == NULL) {   printk("ecspi3 node not find!\r\n");   return -EINVAL;  }      icm20608dev.cs_gpio = of_get_named_gpio(icm20608dev.nd, "cs-gpio", 0);  if(icm20608dev.cs_gpio < 0) {   printk("can't get cs-gpio");   return -EINVAL;  }     ret = gpio_direction_output(icm20608dev.cs_gpio, 1);  if(ret < 0) {   printk("can't set gpio!\r\n");  }     spi->mode = SPI_MODE_0;   spi_setup(spi);  icm20608dev.private_data = spi;      icm20608_reginit();    return 0; }   static int icm20608_remove(struct spi_device *spi) {    cdev_del(&icm20608dev.cdev);  unregister_chrdev_region(icm20608dev.devid, ICM20608_CNT);     device_destroy(icm20608dev.class, icm20608dev.devid);  class_destroy(icm20608dev.class);  return 0; }   static const struct spi_device_id icm20608_id[] = {  {"alientek,icm20608", 0},    {} };   static const struct of_device_id icm20608_of_match[] = {  { .compatible = "alientek,icm20608" },  {  } };    static struct spi_driver icm20608_driver = {  .probe = icm20608_probe,  .remove = icm20608_remove,  .driver = {    .owner = THIS_MODULE,       .name = "icm20608",       .of_match_table = icm20608_of_match,       },  .id_table = icm20608_id, };        static int __init icm20608_init(void) {  return spi_register_driver(&icm20608_driver); }   static void __exit icm20608_exit(void) {  spi_unregister_driver(&icm20608_driver); }  module_init(icm20608_init); module_exit(icm20608_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR(yikoulinux");

关于Linux下如何进行SPI驱动问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注编程网操作系统频道了解更多相关知识。

--结束END--

本文标题: Linux下如何进行SPI驱动

本文链接: https://lsjlt.com/news/280671.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Linux下如何进行SPI驱动
    Linux下如何进行SPI驱动,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1. SPI总线1.1. SPI总线概述SPI,是英语Serial Peripheral &nb...
    99+
    2023-06-15
  • 如何进行RK3399 camera驱动开发
    如何进行RK3399 camera驱动开发,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Android camera驱动开发概述目前板子上有两路mipi rx,...
    99+
    2023-06-05
  • Linux上如何对驱动器进行分区和格式化
    这篇文章主要介绍了Linux上如何对驱动器进行分区和格式化,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。什么是块设备?硬盘驱动器通常称为“块设备”,因为硬盘驱动器在固定大小的...
    99+
    2023-06-28
  • Linux下如何安装nvidia显卡驱动
    小编给大家分享一下Linux下如何安装nvidia显卡驱动,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!环境ManjaroRTX 2060下载驱动安装包到官网上搜...
    99+
    2023-06-27
  • Linux下如何修复U盘驱动器
    这篇文章将为大家详细讲解有关Linux下如何修复U盘驱动器,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。U 盘想必在大家的日常生活和工作中都已经不可或缺了,它让我们的文件维护和转移更加方便容易。但随着频繁...
    99+
    2023-06-27
  • 如何使用springboot通过spi机制加载mysql驱动
    本篇内容介绍了“如何使用springboot通过spi机制加载mysql驱动”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!SPI是一种JDK...
    99+
    2023-06-20
  • linux下如何定时自动执行某个进程
    这篇文章给大家分享的是有关linux下如何定时自动执行某个进程的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。cron是linux下定时执行工具,可在完全无人工干预的情况下作业。可以用一下命令来手动开启或关闭该任务...
    99+
    2023-06-17
  • Linux下如何使用jenkins进行自动化部署
    这篇文章主要介绍Linux下如何使用jenkins进行自动化部署,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Jenkins是用Java语言编写的主要用于持续、自动的构建/测试软件项目、监控外部任务的运行(这个比较抽...
    99+
    2023-06-28
  • 如何使用Django进行测试驱动开发
    本篇内容介绍了“如何使用Django进行测试驱动开发”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!所谓测试驱动开发(TDD),就是先编写测试...
    99+
    2023-06-21
  • Linux如何进行自动备份
    今天就跟大家聊聊有关Linux如何进行自动备份,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。 利用的工具:rsync,ssh 特点:l检查原文件并只复制发生变化的数据块l使用ssh加...
    99+
    2023-06-17
  • 如何在Linux终端下进行BT下载
    这篇文章主要讲解了“如何在Linux终端下进行BT下载”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何在Linux终端下进行BT下载”吧!1)Linux下有许多软件可以从终端进行BT下载。...
    99+
    2023-06-10
  • Linux下如何进行文件备份
    本篇内容介绍了“Linux下如何进行文件备份”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!数据备份是容灾的基础,是指为防止系统出现操作失误或...
    99+
    2023-06-27
  • 如何在Linux中进行硬件设备的识别和驱动管理
    在Linux中进行硬件设备的识别和驱动管理通常是通过以下几种方式来实现: 使用命令行工具: lspci:用于显示系统的PCI设...
    99+
    2024-04-02
  • 如何让Linux驱动11-Linux设备驱动统一模型
    这期内容当中小编将会给大家带来有关如何让Linux驱动11-Linux设备驱动统一模型,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。1. 设备树概念1.1.设备树感性认识设备树(Device Tree),...
    99+
    2023-06-15
  • 如何在redhat linux下挂载光驱软驱?
    这篇文章主要介绍“如何在redhat linux下挂载光驱软驱?”,在日常操作中,相信很多人在如何在redhat linux下挂载光驱软驱?问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何在redhat l...
    99+
    2023-06-13
  • Linux下如何执行二进制文件
    这篇文章主要为大家展示了“Linux下如何执行二进制文件”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Linux下如何执行二进制文件”这篇文章吧。二进制文件是我们几乎每天都需要打交道的文件类型,...
    99+
    2023-06-27
  • windows网卡驱动如何下载
    这篇文章主要介绍了windows网卡驱动如何下载的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇windows网卡驱动如何下载文章都会有所收获,下面我们一起来看看吧。网卡驱动下载方法1、首先下载网卡驱动软件。2、...
    99+
    2023-06-30
  • Linux下NTFS分区如何进行写操作
    这篇文章给大家分享的是有关Linux下NTFS分区如何进行写操作的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Linux下NTFS分区的写操作只需通过简单点击即可完成。在你正常的工作中,假如你装的是双系统,其中一...
    99+
    2023-06-17
  • Linux 下如何进行自然语言处理?
    自然语言处理(Natural Language Processing,NLP)是计算机科学、人工智能和语言学领域交叉的重要研究领域。它的目标是让计算机能够理解、分析、处理和生成人类语言。在 Linux 系统下,我们可以通过各种开源 NLP...
    99+
    2023-10-10
    自然语言处理 linux spring
  • Linux下如何使用objdump进行反汇编
    小编给大家分享一下Linux下如何使用objdump进行反汇编,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!objdump命令是Linux下的反汇编目标文件或者可执行文件的命令,它以一种可阅读的格式让你更多地了解二进制文件...
    99+
    2023-06-27
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作