linux platform架构下I2C接口驱动开发

目录

概述

1 认识I2C协议

1.1 初识I2C

1.2 I2C物理层

1.3 I2C协议分析

1.3.1 Start、Stop、ACK 信号

1.3.2 I2C协议的操作流程

1.3.3 操作I2C注意的问题

2 linux platform驱动开发

2.1 更新设备树

2.1.1 添加驱动节点

2.1.2 编译.dts

2.1.3 更新板卡中的.dtb

2.2 驱动程序设计要点

2.2.1  match设备节点

2.2.2 读写函数的注意点

2.2.2.1 读函数

2.2.2.1 写函数

3 驱动程序实现

3.1 编写驱动程序

3.2 编写Makefile 

3.3 编译驱动

4 测试

4.1 编写测试代码

4.2 编写测试程序的Makefile

4.3 编译和运行测试代码


概述

       本文主要详细介绍了I2C的知识,使用linux platform驱动架构开发一个基于i2c接口的驱动程序,其中包括编写和更新设备树文件,搭建驱动架构,编写驱动代码和测试代码。本文还是以AT24C02为例,介绍linux platform驱动下i2c类型设备驱动程序的设计方法。并介绍如何使用read和write函数来实现eeprom的读/写功能。 

1 认识I2C协议

1.1 初识I2C

     I2C 通讯协议(Inter-Integrated Circuit)是由 Philips 公司开发的一种简单、双向二线制同步串行总线, 只需要两根线即可在连接于总线上的器件之间传送信息。I2C 协议占用引脚特别少, 硬件实现简单, 可扩展型强, 现在被广泛地使用在系统内多个集成电路(IC)间的通讯。

1.2 I2C物理层

I2C 通讯设备之间的常用连接方式

物理层结构有如下特点:

1) 一条I2C总线上可以挂载多个设备,不同的设备地址必须不同

2)I2C总线由两条物理线路构成,分别为SCL和SDA,SCL为同步时钟线,SDA为数据线路

3)I2C可支持3中工作模式:标准模式(100k bit/ s),快速模式( 400k bit/ s),高速模式( 3.4M bit/ s)

1.3 I2C协议分析

完整的I2C工作时序图:

1.3.1 Start、Stop、ACK 信号

Start信号:

在空闲状态时,SDA为高电平,SCL也为高电平。当有数据需要传输时,Master首先发起start信号,SDA: 1-->0, SCL: 1

Stop信号:

数据传输完成后,SDA: 0-->1, SCL: 1

ACK信号:

      在I2C协议中,数据传输的单位为byte, 传输完成一个数据时,需要8个bit, 在第9个bit( SCL电平: 0-->1)时,SDA : 0。该信号为ACK信号。

1.3.2 I2C协议的操作流程

需要注意的是I2C协议传输数据以字节为单位,每个字节有8个bit,传输完成一个字节后,还会发发送一个响应信号,即ACK信号,所以,其完成一个byte传输,实际需要9个bit。

Step-1:   Master 发起Start信号 , SDA: 1---> 0, SCL: 1

Step-2: 传输数据,当SCL: 0 ->1, SDA发送一个bit,总共8个bit

Step-3:    ACK信号,SCL: 0->1, SDA 1->0

Step-4:    传送下一个数据(循环执行: step-2 - > step-3)

Step-5:    Master 发起Stop信号,SDA: 0--->1, SCL: 1

1.3.3 操作I2C注意的问题

1)空闲状态时,SDA=1, SCL1 =1

2)  SCL 电平 0 ->1变化后,高电平保持期间,SDA上的数据才为有效bit

2 linux platform驱动开发

2.1 更新设备树

2.1.1 添加驱动节点

AT24C02引脚和IMX.6ULL引脚对应关系:

AT24C02   IO IMX.6ULL PIN
SCLI2C2_SCL
SDAI2C2_SDA

.dts文件路径:/home/mftang/linux_workspace/study_atk_dl6y2c/kernel/atk-dl6u2c/arch/arm/boot/dts/imx6ull-14x14-evk.dts

在.dts文件中添加如下代码:

    at24c02: at24c02@50 {
        compatible = "atk-dl6y2c,at24c02";
        reg = <0x50>;
    };

其在imx6ull-14x14-evk.dts中位置:

2.1.2 编译.dts

编译.dts文件,并把编译生成的.dtb文件发送到NFS共享目录下,便于在板卡中操作该文件。

1)在内核根目录下使用如下命令编译.dts文件

make dtbs

2) 复制 .dtb 文件至NFS共享目录

cp arch/arm/boot/dts/imx6ull-14x14-emmc-4.3-480x272-c.dtb  /home/mftang/nfs/atk_dl6y2c/

2.1.3 更新板卡中的.dtb

复制.dtb文件到相应的运行目录,然后重新板卡

cp /mnt/atk_dl6y2c/imx6ull-14x14-emmc-4.3-480x272-c.dtb /run/media/mmcblk1p1

reboot板卡后,内核会重新读取.dtb文件。然后在/proc/device-tree目录下查看板卡device tree,使用如下命令:

cd /sys/bus/i2c/devices
ls

查看地址下设备名称

cat 1-0050/name

2.2 驱动程序设计要点

2.2.1  match设备节点

在板卡的.dts 文件中,定义的设备节点为:

在设备驱动,需要设计相应的匹配表来match该信息,驱动程序的代码如下:

static const struct of_device_id atk_dl6y2c_at24cxx[] = {
    { .compatible = "atk-dl6y2c,at24c02" },
    { },
};

static const struct i2c_device_id at24c02_ids[] = {
    { "xxxxyyy",  (kernel_ulong_t)NULL },
    { /* END OF LIST */ }
};

/*  platform_driver */
static struct i2c_driver at24cxx_driver = {
    .probe      = at24cxx_probe,
    .remove     = at24cxx_remove,
    .driver     = {
        .name   = "atk_at24cxx",
        .of_match_table = atk_dl6y2c_at24cxx,
    },
    .id_table = at24c02_ids,
};

2.2.2 读写函数的注意点

2.2.2.1 读函数

         为了实现随机读取EEPROM中的数据,在用户层需要传递一个地址字节,于是该接口设计如下:

int at24cxx_read( unsigned char address, unsigned char *buff, unsigned int len)
{
    int ret;
    unsigned char addrbuff[1];
    struct i2c_msg msg[2];
    struct i2c_client *client = at24cxxdev.client;

    addrbuff[0] = address;
    /* msg[0]为发送要读取的首地址 */
    msg[0].addr = client->addr;            /* at24c02 地址 */
    msg[0].flags = 0;                      /* 标记为发送数据 */
    msg[0].buf = addrbuff;                 /* 读取的首地址 */
    msg[0].len = 1;                         /* reg长度*/

    /* msg[1]读取数据 */
    msg[1].addr = client->addr;             /* at24c02 地址 */
    msg[1].flags = I2C_M_RD;                /* 标记为读取数据*/
    msg[1].buf = buff;                      /* 读取数据缓冲区 */
    msg[1].len = len;                       /* 要读取的数据长度*/

    ret = i2c_transfer(client->adapter, msg, 2);
    mdelay(20);
    
    if(ret < 0){
        printk("i2c rd failed=%d len=%d\n",ret, len);
    }
    
    return ret;
}

       和设备层相关的read 函数中,使用copy_from_user, 以得到用户层传递进来的参数,具体实现如下:

static ssize_t at24cxx_drv_read(struct file *file, char __user *buf, 
                                size_t size, loff_t *offset)
{
    unsigned char tempbuff[size];
    unsigned char kernel_buf[1];
    int err, i;
    unsigned char addr;
    
    // get address here
    err = copy_from_user(kernel_buf, buf,1);
    
    addr = kernel_buf[0];
    at24cxx_read( addr, tempbuff, size );
    size = copy_to_user(buf, tempbuff, size);
    
    return size;
}
2.2.2.1 写函数

        要实现随机写AT24C02内存的功能,就需要写数据时,先传递给它一个地址,然后在写数据,所以在驱动程序是这样实现该功能的:
 

int at24cxx_write(  unsigned char *buff, unsigned int len)
{
    int ret;
    struct i2c_msg msg[1];
    struct i2c_client *client = at24cxxdev.client;

    /* msg[0]为发送要写的首地址 */
    msg[0].addr = client->addr;       /* at24c02 地址 */
    msg[0].flags = 0;                 /* 标记为发送数据 */
    msg[0].buf = buff;                /* 写的首地址 */
    msg[0].len = len;                 /* 数据长度*/
    
    ret = i2c_transfer(client->adapter, msg, 1);
    mdelay(20);
    if(ret < 0) 
    {
        printk("i2c write failed=%d len=%d\n",ret, len);
    }
    
    return ret;
}

和driver 层相关的write函数如下,其中buff中的数据包含两部分:

 buf[0] : 为地址信息,

buf[1 ~ n ] :user层要写的data数据:

static ssize_t at24cxx_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
    unsigned char kernel_buf[size];
    int err, i;

    size = copy_from_user(kernel_buf, buf, size);
    at24cxx_write(kernel_buf, size );
    
    return size;
}

3 驱动程序实现

3.1 编写驱动程序

创建一个.c 文件,编写代码。详细驱动代码如下:

/***************************************************************
Copyright  2024-2029. All rights reserved.
文件名     : drv_15_at24cxx.c
作者       : tangmingfei2013@126.com
版本       : V1.0
描述       : at24cxx 驱动程序
其他       : 无
日志       : 初版V1.0 2024/1/30  

使用方法:
1) 在.dts文件中定义节点信息
    at24c02: at24c02@50 {
        compatible = "atk-dl6y2c,at24c02";
        reg = <0x50>;
    };
    
2) 在驱动匹配列表 
static const struct of_device_id at24cxx_of_match[] = {
    { .compatible = "atk-dl6y2c,at24c02" },
    { } // Sentinel
};
***************************************************************/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ktime.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/irq.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/i2c.h>

#define DEVICE_NAME      "at24cxx"     // dev/at24cxx


/* at24cxxdev设备结构体 */
struct at24cxxstru_dev{
    dev_t   devid;                /* 设备号         */
    struct  cdev cdev;            /* cdev           */
    struct  class *class;         /* 类             */
    struct  device *device;       /* 设备           */
    int     major;                /* 主设备号       */
    struct  device_node *node;    /* at24cxx设备节点 */
    struct i2c_client *client;
};

/* read or write at24cxx structure */

static struct at24cxxstru_dev at24cxxdev;

/*
    at24cxx driver 
*/
int at24cxx_read( unsigned char address, unsigned char *buff, unsigned int len)
{
    int ret;
    unsigned char addrbuff[1];
    struct i2c_msg msg[2];
    struct i2c_client *client = at24cxxdev.client;

    addrbuff[0] = address;
    /* msg[0]为发送要读取的首地址 */
    msg[0].addr = client->addr;            /* at24c02 地址 */
    msg[0].flags = 0;                      /* 标记为发送数据 */
    msg[0].buf = addrbuff;                 /* 读取的首地址 */
    msg[0].len = 1;                         /* reg长度*/

    /* msg[1]读取数据 */
    msg[1].addr = client->addr;             /* at24c02 地址 */
    msg[1].flags = I2C_M_RD;                /* 标记为读取数据*/
    msg[1].buf = buff;                      /* 读取数据缓冲区 */
    msg[1].len = len;                       /* 要读取的数据长度*/

    ret = i2c_transfer(client->adapter, msg, 2);
    mdelay(20);
    
    if(ret < 0){
        printk("i2c rd failed=%d len=%d\n",ret, len);
    }
    
    return ret;
}

int at24cxx_write(  unsigned char *buff, unsigned int len)
{
    int ret;
    struct i2c_msg msg[1];
    struct i2c_client *client = at24cxxdev.client;

    /* msg[0]为发送要写的首地址 */
    msg[0].addr = client->addr;       /* at24c02 地址 */
    msg[0].flags = 0;                 /* 标记为发送数据 */
    msg[0].buf = buff;                /* 写的首地址 */
    msg[0].len = len;                 /* 数据长度*/
    
    ret = i2c_transfer(client->adapter, msg, 1);
    mdelay(20);
    if(ret < 0) 
    {
        printk("i2c write failed=%d len=%d\n",ret, len);
    }
    
    return ret;
}

/*
    linux driver 驱动接口: 
    实现对应的open/read/write等函数,填入file_operations结构体
*/
static ssize_t at24cxx_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
    unsigned char tempbuff[size];
    unsigned char kernel_buf[1];
    int err, i;
    unsigned char addr;
    
    // get address here
    err = copy_from_user(kernel_buf, buf,1);
    
    addr = kernel_buf[0];
    at24cxx_read( addr, tempbuff, size );
    size = copy_to_user(buf, tempbuff, size);
    
    return size;
}

static ssize_t at24cxx_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
    unsigned char kernel_buf[size];
    int err, i;

    size = copy_from_user(kernel_buf, buf, size);
    at24cxx_write(kernel_buf, size );
    
    return size;
}



static int at24cxx_drv_close(struct inode *node, struct file *file)
{
    printk(" %s line %d \r\n",  __FUNCTION__, __LINE__);

    return 0;
}

static int at24cxx_drv_open(struct inode *inode, struct file *filp)
{
    return 0;
}

/* 
    定义driver的file_operations结构体
*/
static struct file_operations at24cxx_fops = {
    .owner   = THIS_MODULE,
    .read    = at24cxx_drv_read,
    .write   = at24cxx_drv_write,
    .open    = at24cxx_drv_open,

    .release = at24cxx_drv_close,
};


/* 1. 从platform_device获得GPIO
 * 2. gpio=>irq
 * 3. request_irq
 */
static int at24cxx_probe( struct i2c_client *client, const struct i2c_device_id *id )
{
    printk("at24cxx driver and device was matched!\r\n");
    
    /* 1. 获得硬件信息 */
    at24cxxdev.client = client;
    
    /* register file_operations  */
    at24cxxdev.major = register_chrdev( 0, 
                                        DEVICE_NAME,     /* device name */
                                        &at24cxx_fops);  

    /* create the device class  */
    at24cxxdev.class = class_create(THIS_MODULE, "at24cxx_class");
    
    if (IS_ERR(at24cxxdev.class)) {
        printk("%s line %d\n", __FUNCTION__, __LINE__);
        unregister_chrdev( at24cxxdev.major, DEVICE_NAME);
        return PTR_ERR( at24cxxdev.class );
    }
    
    /* 2. device_create */
    device_create( at24cxxdev.class, NULL, 
                   MKDEV( at24cxxdev.major, 0 ), NULL, 
                   DEVICE_NAME);        // device name 
    
    return 0;
}

static int at24cxx_remove(struct i2c_client *client)
{
    printk("%s line %d\n", __FUNCTION__, __LINE__);
    
    device_destroy( at24cxxdev.class, MKDEV( at24cxxdev.major, 0));
    class_destroy(at24cxxdev.class);
    unregister_chrdev(at24cxxdev.major, DEVICE_NAME);
    
    return 0;
}


static const struct of_device_id atk_dl6y2c_at24cxx[] = {
    { .compatible = "atk-dl6y2c,at24c02" },
    { },
};

static const struct i2c_device_id at24c02_ids[] = {
    { "xxxxyyy",  (kernel_ulong_t)NULL },
    { /* END OF LIST */ }
};

/* 1. 定义platform_driver */
static struct i2c_driver at24cxx_driver = {
    .probe      = at24cxx_probe,
    .remove     = at24cxx_remove,
    .driver     = {
        .name   = "atk_at24cxx",
        .of_match_table = atk_dl6y2c_at24cxx,
    },
    .id_table = at24c02_ids,
};

/* 
  2. 在入口函数注册platform_driver 
*/
static int __init at24cxx_init(void)
{
    int err;
    
    printk("%s line %d\n",__FUNCTION__, __LINE__);
     
    err = i2c_add_driver(&at24cxx_driver); 
    
    return err;
}

/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
 *    卸载platform_driver
 */
static void __exit at24cxx_exit(void)
{
    printk("%s line %d\n", __FUNCTION__, __LINE__);

    i2c_del_driver(&at24cxx_driver);
}

/*
 4. 驱动入口和出口函数
*/
module_init(at24cxx_init);
module_exit(at24cxx_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("tangmingfei2013@126.com");

3.2 编写Makefile 

在驱动程序的同级目录下创建Makefile文件,然后编写代码 

PWD := $(shell pwd)

KERNEL_DIR=/home/mftang/linux_workspace/study_atk_dl6y2c/kernel/atk-dl6u2c
ARCH=arm
CROSS_COMPILE=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-

export  ARCH  CROSS_COMPILE

obj-m:= drv_15_at24cxx.o

all:
	$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules


clean:
	rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions *.order *.symvers

3.3 编译驱动

      使用Make命令编译驱动程序,然后将生成的.ko文件copy到NFS共享目录下,然后在板卡中安装该驱动。

使用 insmod 安装该驱动,安装成功后,会出现如下信息:

4 测试

编写一个测试程序,实现AT24CXX连续数据的读写功能

4.1 编写测试代码

创建一个.c文件,编写如下代码:

/***************************************************************
Copyright  2024-2029. All rights reserved.
文件名     : test_15_at24cxx.c
作者       : tangmingfei2013@126.com
版本       : V1.0
描述       : 测试at24cxx驱动程序
其他       : 无
日志       : 初版V1.0 2024/02/15
***************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/fs.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <time.h>

#define DEV_FILE                     "/dev/at24cxx"

int main(void)
{
    int fd, ret;
    int i = 0;
    unsigned char databuff[9];
    unsigned char rdatabuff[8];

    fd = open(DEV_FILE, O_RDWR);
    if (fd == -1){
        printf("can not open file: %s \n", DEV_FILE);
        return -1;
    }
    
    printf("write to at24cxx:  \r\n ");
    for( i=0; i< sizeof(databuff); i++ )
    {
        databuff[i] = i;
        printf(" %x \t ", databuff[i]);
    }
    
    printf(" \r\n \r\n ");
    ret = write(fd, databuff, sizeof(databuff)); 
    if( ret < 0 )
    {
       printf("%d %s %s i2c device write data failure: %s\n",
              __LINE__,  __FILE__, __FUNCTION__, strerror(errno));
       close(fd);
       return -1;
    }
    
    rdatabuff[0] = 0;   // 读数据,起始地址
    ret =  read( fd, rdatabuff, sizeof(rdatabuff));
    if( ret < 0 )
    {
       printf("%d %s %s i2c device read data failure: %s\n",
              __LINE__,  __FILE__, __FUNCTION__, strerror(errno));
       close(fd);
       return -1;
    }
    
    printf("read from at24cxx: \r\n ");
    for( i=0; i< sizeof(rdatabuff); i++ )
    {
        printf(" %x \t ", rdatabuff[i]);
    }
    printf(" \r\n \r\n ");
    
    close(fd);

    return 0;
}

4.2 编写测试程序的Makefile

在测试程序的同级目录下创建一个Makefile文件,实现如下代码:

CFLAGS= -Wall -O2
CC=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc
STRIP=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip


test_15_at24cxx: test_15_at24cxx.o
	$(CC) $(CFLAGS) -o test_15_at24cxx test_15_at24cxx.o
	$(STRIP) -s test_15_at24cxx

clean:
	rm -f test_15_at24cxx test_15_at24cxx.o

4.3 编译和运行测试代码

      使用make编译测试代码,然后将生成的可执行文件copy到NFS的共享目录下。在板卡中运行该测试程序:

运行该程序后可以看见:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/400878.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

观察者模式, 发布-订阅模式, 监听器模式

观察者模式, 发布-订阅模式, 监听器模式 观察者模式 观察者模式是一种行为型设计模式, 定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新 角色模型和结构图 在观察者模式中&#xff0c;只有两种…

⭐北邮复试刷题LCR 018. 验证回文串__双指针 (力扣119经典题变种挑战)

LCR 018. 验证回文串 给定一个字符串 s &#xff0c;验证 s 是否是 回文串 &#xff0c;只考虑字母和数字字符&#xff0c;可以忽略字母的大小写。 本题中&#xff0c;将空字符串定义为有效的 回文串 。 示例 1: 输入: s “A man, a plan, a canal: Panama” 输出: true 解释…

【PX4SimulinkGazebo联合仿真】在Simulink中使用ROS2控制无人机沿自定义圆形轨迹飞行并在Gazebo中可视化

在Simulink中使用ROS2控制无人机沿自定义圆形轨迹飞行并在Gazebo中可视化 系统架构Matlab官方例程Control a Simulated UAV Using ROS 2 and PX4 Bridge运行所需的环境配置PX4&Simulink&Gazebo联合仿真实现方法建立Simulink模型并完成基本配置整体框架各子系统实现原理…

【Vuforia+Unity】AR05-实物3D模型识别功能实现

对于3D物体的识别&#xff0c;可以是虚拟的也可以是实物的&#xff0c;但是对于虚拟的三维模型意义不大&#xff0c;我们完全可以把三维模型放在屏幕上截一张图&#xff0c;以图片识别的方式召唤数字内容&#xff0c;不过在虚拟现实中或许有用。 因此本文探讨的技术路线主要是…

Docker之查看并获取最新Ubuntu镜像(十)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

【快速搞定Webpack5】修改输出文件目录及自动清理上次打包文件(五)

介绍 默认情况下webpack打包后&#xff0c;我们的图片和js等文件都会被打包到dist目录下&#xff0c;文件多了混淆在一起一方面不利于文件的查找和管理&#xff0c;另外一方面看上去也不美观。 所以今天我们学习的内容就是控制输出后的文件进入不同的目录。 一、配置 新增4…

Nginx配置组成与性能调优

目录 一、Nginx配置介绍 1. 模块组成 2. 图示 3. 相关框架 二. 配置调优 1. 全局配置 1.1 关闭版本和修改版本 1.2 修改启动的进程数 1.3 cpu与work进程绑定 1.4 pid路径 1.5 nginx进程的优先级&#xff08;work进程的优先级&#xff09; 1.6 调试work进程打开的文…

npm run dev和npm run serve两个命令的区别

npm run dev和npm run serve两个命令的区别 前端开发过程中运行Vue项目的时候&#xff0c;有时候使用npm run serve命令可以启动项目&#xff0c;有时候却会报错&#xff1b;有时候使用npm run dev命令可以启动项目&#xff0c;有时候却也会报错。是什么原因造成这种情况呢&am…

问题:Spark SQL 读不到 Flink 写入 Hudi 表的新数据,打开新 Session 才可见

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

4、电源管理入门之子系统reset

目录 1. 简介 2. consumer-驱动软件 3. provider-reset驱动 3.1 整体介绍 3.2 reset复位API说明 之前的文章电源管理入门-1关机重启详解介绍了整机SoC的重启也可以说是reset,那么子系统的reset,例如某个驱动(网卡、USB等)或者某个子系统(NPU、ISP等运行在独立的M核或…

5、电源管理入门之 arm-scmi和mailbox核间通信

目录 1. 整体架构介绍 2 Linux中reset模块 2.1 Reset consumer 2.2 Reset provider 3. Linux SCMI reset通信 3.1 SCMI reset协议初始化 3.2 SCMI reset消息收发 4. SCP中reset 4.1 固件新增module 4.2 scmi_reset_domain初始化 4.3 scmi_reset_domain消息处理 4.3…

排序算法1:冒泡排序、快速排序、插入排序

排序算法&#xff1a;交换类排序&#xff0c;插入类排序、选择类排序、归并类排序 交换类排序&#xff1a;冒泡排序、快速排序 一、冒泡排序 #include <stdio.h> #include <stdlib.h> #include <time.h> typedef int ElemType; typedef struct{ElemType *e…

linux CentOs 安装docker 推荐生产环境使用

目录 1. 在CentOs上安装docker所需的系统环境 2. 卸载旧版本 2.1 查看是否已安装docker 2.2 卸载已安装的docker 3. 安装方式 3.1 使用rpm存储库安装(推荐使用该方法) 3.2 从包中安装 4. 开始docker 1. 在CentOs上安装docker所需的系统环境 需要以下CentOS版本之一的维…

压缩感知的图像仿真(MATLAB源代码)

压缩感知是一种用于高效获取和表示信号的技术&#xff0c;它可以显著减少数据的采样和传输量&#xff0c;同时保持对信号的高质量恢复能力。在压缩感知中&#xff0c;信号被表示为其在一个稀疏基中的稀疏线性组合。通过仅使用少量的随机投影测量&#xff0c;就能够捕捉信号的大…

Vue状态管理库-Pinia

一、Pinia是什么&#xff1f; Pinia 是 Vue 的专属状态管理库&#xff0c;它允许支持跨组件或页面共享状态&#xff0c;即共享数据&#xff0c;他的初始设计目的是设计一个支持组合式API的 Vue 状态管理库&#xff08;因为vue3一个很大的改变就是组合式API&#xff09;,当然这…

【数学建模入门】

数学建模入门 数学建模需要的学科知识怎么学习数学模型如何读好一篇优秀论文数学建模赛题常见类别数学建模常见问题数学建模组队和分工数学建模准备工作 数学建模需要的学科知识 怎么学习数学模型 &#x1f4a6;推荐阅读书籍&#xff1a; 《数学建模算法与应用》&#xff0c;…

tensorboard的用法

部分测试代码&#xff1a; from torch.utils.tensorboard import SummaryWriter import numpy as np from PIL import Image import torch import cv2 as cv import matplotlib.pyplot as plt from torch import nn from torchvision import datasetsdef functiontools():writ…

ros自定义action记录

文章目录 自定义action1. 定义action文件2. 修改 package.xml3. 修改 CMakeLists.txt4. 运行 catkin build4. simple_action_server.py5. simple_action_client.py 测试 自定义action ros 版本&#xff1a;kinetic 自定义test包的文件结构如下 |-- test | |-- CMakeLists.t…

Django使用Celery异步

安装包 pip install celerypip install eventlet 1.在项目文件的根目录下创建目录结果 2. 在main.py文件中 # !/usr/bin/env python # -*-coding:utf-8 -*-""" # Author &#xff1a;skyTree # version &#xff1a;python 3.11 # Description&#…

el-table同时固定左列和右列时,出现错误情况

最近遇到一个问题,就是需求是要求表格同时固定序号列和操作列,我们用的是饿了么组件库的el-table,如下图,出现了错误情况: 解决方法就是使用doLayout方法: 如果使用了keep-alive,可以在activated里执行doLayout方法: activated() {this.$nextTick(() => {this.$ref…
最新文章