IMX6ULL學習整理篇——Linux使用更現代的GPIO操作簡單設備

IMX6ULL學習篇——實戰:使用設備樹/Pinctl-gpio子系統驅動LED

前言

? 經過層層考驗,我們即將接近現代的LED驅動的解決方案了。那就是使用最現代的方式開發一個簡單的GPIO驅動外設。

? 如果您忘記了設備樹的相關內容,請自行到筆者的上一篇博客復習

修改我們的設備樹

? 我們現在修改我們的設備樹,在根節點下,直接添加一個myled節點,我們做了如下的添加

	myled {#address-cells = <1>;#size-cells = <1>;compatible = "charlie-led";status = "okay";reg = <0x020C406C 0x040x020E0068 0x040x020E02F4 0x040x0209C000 0x040x0209C004 0x04>;};
  1. myled:節點名稱,表示這是一個LED設備。
  2. #address-cells = <1>
    • 指定子節點中"reg"屬性的地址字段用1個32位數字表示。
  3. #size-cells = <1>
    • 指定子節點中"reg"屬性的大小字段用1個32位數字表示。
  4. compatible = "charlie-led"
    • 驅動兼容性標識,表示這個設備與"charlie-led"驅動程序兼容。
  5. status = "okay"
    • 設備狀態,表示這個設備處于啟用狀態。
  6. reg屬性:
    • 定義了5組寄存器地址和大小,每組包含:
      • 第一個數字是寄存器地址
      • 第二個數字是寄存器區域大小(這里是0x04表示4字節)
    • 具體地址:
      1. 0x020C406C - 大小為0x04
      2. 0x020E0068 - 大小為0x04
      3. 0x020E02F4 - 大小為0x04
      4. 0x0209C000 - 大小為0x04
      5. 0x0209C004 - 大小為0x04

然后重新編譯我們的設備樹文件

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs

? 將得到的設備樹放置到我們的tftp文件夾目錄下,之后使用這個新的設備樹啟動我們的Linux內核

? 啟動成功后,在設備樹的文件夾下:

cd /proc/device-tree/
/sys/firmware/devicetree/base # ls
#address-cells                 model
#size-cells                    myled
aliases                        name
backlight                      pxp_v4l2
chosen                         regulators
clocks                         reserved-memory
compatible                     soc
cpus                           sound
interrupt-controller@00a01000  spi4
memory
/sys/firmware/devicetree/base # cd myled/
/sys/firmware/devicetree/base/myled # ls
#address-cells  compatible      reg
#size-cells     name            status

? 可用看到我們的myled和下面的東西,這里都被讀取到了。下面就是直接對設備樹進行讀取和編程。

方式1:使用讀取的方式直接拿到寄存器的值

? 我們下面一個辦法就是直接通過設備樹,拿到LED外設GPIO寄存器的值

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>	
#include <asm/io.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <asm/mach/map.h>MODULE_LICENSE("GPL");
MODULE_AUTHOR("charliechen<charliechen114514@demo.com>");#define LED_DEV_NAME            ("charlies_led")
#define LED_DEV_N               (1)
/* LED Physical Address See the manual
*/
#define CCM_CCGR1_BASE          (0x020C406C)
#define GPIO1_IOLED_BASE        (0x020E0068)
#define GPIO1_IOPAD_BASE        (0x020E02F4)
#define GPIO1_IODR_BASE         (0x0209C000)
#define GPIO1_GDIR_BASE         (0x0209C004)/* mappings of the io phe*/
static void* __iomem LED_CCGR1;
static void* __iomem LEDBASE;
static void* __iomem LEDPAD_BASE;
static void* __iomem LEDDR_BASE;
static void* __iomem LEDGDIR_BASE;/* we use a device struct */
typedef struct __myled {struct cdev char_dev_handle;dev_t       dev_id;int         major;int         minor;struct class*   led_class_handle; struct device*  led_handle_device;// node infostruct device_node* node;
}MyLED;static MyLED myled;/* operations cached */
static char operations_cached[20];static void __led_turn_on(void)
{u32 val = 0;val = readl(LEDDR_BASE);val &= ~(1 << 3);writel(val, LEDDR_BASE);
}static void __led_turn_off(void)
{u32 val = 0;val = readl(LEDDR_BASE);val |= (1 << 3);writel(val, LEDDR_BASE);
}static u8 __fetch_led_status(void)
{u32 val = 0;val = readl(LEDDR_BASE);return !(val & (1 << 3));
}static void __enable_led_mappings(u32 regdata[10])
{int val = 0;pr_info("Ready to mappings the registers...\n");// LED_CCGR1 = ioremap(CCM_CCGR1_BASE, 4);// LEDBASE = ioremap(GPIO1_IOLED_BASE, 4);// LEDPAD_BASE = ioremap(GPIO1_IOPAD_BASE, 4);// LEDDR_BASE = ioremap(GPIO1_IODR_BASE, 4);// LEDGDIR_BASE = ioremap(GPIO1_GDIR_BASE, 4);LED_CCGR1 = ioremap(regdata[0], regdata[1]);LEDBASE = ioremap(regdata[2], regdata[3]);LEDPAD_BASE = ioremap(regdata[4], regdata[5]);LEDDR_BASE = ioremap(regdata[6], regdata[7]);LEDGDIR_BASE = ioremap(regdata[8], regdata[9]);pr_info("mappings the registers done!\n");pr_info("LED_CCGR1     ioremap to: %p\n", LED_CCGR1);pr_info("LEDBASE       ioremap to: %p\n", LEDBASE);pr_info("LEDPAD_BASE   ioremap to: %p\n", LEDPAD_BASE);pr_info("LEDDR_BASE    ioremap to: %p\n", LEDDR_BASE);pr_info("LEDGDIR_BASE  ioremap to: %p\n", LEDGDIR_BASE);pr_info("initialize the led registers\n");val = readl(LED_CCGR1);// clear the bitsval &= ~(3 << 26);val |= (3 << 26);writel(val, LED_CCGR1);writel(0x5, LEDBASE);writel(0x10B0, LEDPAD_BASE);val = readl(LEDGDIR_BASE);val |= 1 << 3;writel(val, LEDGDIR_BASE);pr_info("operations of led is accessable!\n");
}static void __disable_led_mappings(void)
{__led_turn_off();pr_info("set the led turning off...\n");pr_info("set the led turning off done!\n");pr_info("Ready to unmappings the registers...\n");    iounmap(LED_CCGR1);iounmap(LEDBASE);iounmap(LEDPAD_BASE);iounmap(LEDDR_BASE);iounmap(LEDGDIR_BASE);pr_info("unmappings the registers done\n");
}static ssize_t led_read(struct file* filp, char* buffer, size_t count, loff_t* ppos)
{const char* status = "opened";int ret = 0;pr_info("\nled device is reading!\n");if(!__fetch_led_status()){status = "closed";} ret = copy_to_user(buffer, status, strlen(status));if(ret < 0){pr_warn("Copy to the user failed\n");return -EFAULT;}return 0;
}static ssize_t led_write(struct file* filp,const char* buffer, size_t count, loff_t* ppos)
{int check = 0;pr_info("\nled device is ready writing!\n");check = copy_from_user(operations_cached, buffer, count);if(check < 0){pr_warn("Can not copy from user!\n");return -EFAULT;}if(!strcmp(operations_cached, "open")){__led_turn_on();}else if(!strcmp(operations_cached, "close")){__led_turn_off();}else{pr_warn("Can not find the indications operations!\n""check the business: %s", operations_cached);}return 0;
}static int led_open(struct inode* inode, struct file* filp)
{pr_info("\nled device is opened!\n");return 0;
}static int led_close(struct inode* inode, struct file* filp)
{pr_info("\nled device is released!\n");return 0;
}static const struct file_operations led_ops = {.owner = THIS_MODULE,.open = led_open,.release = led_close,.write = led_write,.read = led_read
};/* register the device */
static int __init led_init(void)
{int ret = 0;u32 regdata[10];const char* compatible;const char* status_str;// fetch platform treemyled.node = of_find_node_by_path("/myled");if(myled.node == NULL){pr_warn("can not find the myled\n");return -EINVAL;}else{pr_info("find the myled in device tree!\n");}ret = of_property_read_string(myled.node, "status", &status_str);if(ret < 0){pr_warn("can not fetch the status node info");return EINVAL;}else{pr_info("status=%s\n", status_str);}ret = of_property_read_string(myled.node, "compatible", &compatible);if(ret < 0){pr_warn("can not fetch the status node info");return EINVAL;}else{pr_info("compatible=%s\n", status_str);}    ret = of_property_read_u32_array(myled.node, "reg", regdata, 10);if(ret < 0){pr_info("failed to fetch the reg device info!\n");return -EINVAL;}else{u8 i = 0;for(i = 0; i < 10; i+=2){pr_info("reg data: %#X %#X\n", regdata[i], regdata[i + 1]);}}// create the led deviceif(myled.major){myled.dev_id = MKDEV(myled.major, 0);ret = register_chrdev_region(myled.dev_id, LED_DEV_N, LED_DEV_NAME);}else{ret = alloc_chrdev_region(&myled.dev_id, 0, LED_DEV_N, LED_DEV_NAME);myled.major = MAJOR(myled.dev_id);myled.minor = MINOR(myled.dev_id);}if(ret < 0){pr_warn("Error in registering the device! Failed to register the region\n");goto failed_register_chrdev_region;}pr_info("Success in registering the device major=%d, minor=%d\n",myled.major, myled.minor);myled.char_dev_handle.owner = THIS_MODULE;cdev_init(&(myled.char_dev_handle), &led_ops);ret = cdev_add(&(myled.char_dev_handle), myled.dev_id, LED_DEV_N);if(ret < 0){pr_warn("Failed to add chardev into the kernel_list!\n");goto failed_add_chardev;}pr_info("Prepare to create the device class file...\n");myled.led_class_handle = class_create(THIS_MODULE, LED_DEV_NAME);if(IS_ERR(myled.led_class_handle)){// class creation failed, rollback!pr_warn("Failed to create the led class handle...\n");goto failed_create_class;}myled.led_handle_device = device_create(myled.led_class_handle, NULL, myled.dev_id, "%s", LED_DEV_NAME);if(IS_ERR(myled.led_handle_device)){pr_warn("Failed to create the led device ...\n");goto failed_create_device;}__enable_led_mappings(regdata);return 0;failed_create_device:class_destroy(myled.led_class_handle);
failed_create_class:cdev_del(&(myled.char_dev_handle));
failed_add_chardev:unregister_chrdev_region(myled.dev_id, LED_DEV_N);
failed_register_chrdev_region:return -EIO;
}static void __exit led_deinit(void)
{pr_info("Ready to remove the hook of the device operating file\n");device_destroy(myled.led_class_handle, myled.dev_id);class_destroy(myled.led_class_handle);pr_info("Ready to release the char dev handle\n");cdev_del(&(myled.char_dev_handle));pr_info("Ready to unhook the device region\n");unregister_chrdev_region(myled.dev_id, LED_DEV_N);__disable_led_mappings();pr_info("Successfully unregister the device\n");
}module_init(led_init);
module_exit(led_deinit);

? 中間很長,但是只修改了led初始化的部分:

    // fetch platform treemyled.node = of_find_node_by_path("/myled");if(myled.node == NULL){pr_warn("can not find the myled\n");return -EINVAL;}else{pr_info("find the myled in device tree!\n");}ret = of_property_read_string(myled.node, "status", &status_str);if(ret < 0){pr_warn("can not fetch the status node info");return EINVAL;}else{pr_info("status=%s\n", status_str);}ret = of_property_read_string(myled.node, "compatible", &compatible);if(ret < 0){pr_warn("can not fetch the status node info");return EINVAL;}else{pr_info("compatible=%s\n", status_str);}    ret = of_property_read_u32_array(myled.node, "reg", regdata, 10);if(ret < 0){pr_info("failed to fetch the reg device info!\n");return -EINVAL;}else{u8 i = 0;for(i = 0; i < 10; i+=2){pr_info("reg data: %#X %#X\n", regdata[i], regdata[i + 1]);}}

? 讀取設備樹,第一件事情就是把節點找到了,然后這里,我們只是嘗試讀取設備樹上的葉子節點的屬性,這樣來測試我們的設備樹的節點讀取是否成功,真正設計到驅動LED本身的,還是of_property_read_u32_array讀取我們的寄存器的值,之后的事情就很簡單了,我們直接使用這些地址進行映射。

? 編譯下載得到:

/module_test # insmod led.ko 
find the myled in device tree!
status=okay
compatible=charlie-led
reg data: 0X20C406C 0X4
reg data: 0X20E0068 0X4
reg data: 0X20E02F4 0X4
reg data: 0X209C000 0X4
reg data: 0X209C004 0X4
Success in registering the device major=249, minor=0
Prepare to create the device class file...
Ready to mappings the registers...
mappings the registers done!
LED_CCGR1     ioremap to: f42c406c
LEDBASE       ioremap to: f42e0068
LEDPAD_BASE   ioremap to: f42e02f4
LEDDR_BASE    ioremap to: a08e6000
LEDGDIR_BASE  ioremap to: a08ee004
initialize the led registers
operations of led is accessable!
/module_test # ./chrdev_application /dev/charlies_led write openled device is opened!
args: 4
led device is ready writing!user process the write issue: o
led device is released!
pen
/module_test # ./chrdev_application /dev/charlies_led write closeled device is opened!
args: 4
led device is ready writing!user process the write issue: c
led device is released!
lose
/module_test # rmmod led.ko 
Ready to remove the hook of the device operating file
Ready to release the char dev handle
Ready to unhook the device region
set the led turning off...
set the led turning off done!
Ready to unmappings the registers...
unmappings the registers done
Successfully unregister the device

使用工具函數of_iomap直接映射

? 上面的方法還是很麻煩,我們可不可以直接一步到位呢?當然可以,使用of_iomap函數可以一步到位

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>	
#include <asm/io.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>MODULE_LICENSE("GPL");
MODULE_AUTHOR("charliechen<charliechen114514@demo.com>");#define LED_DEV_NAME            ("charlies_led")
#define LED_DEV_N               (1)
/* LED Physical Address See the manual
*/
#define CCM_CCGR1_BASE          (0x020C406C)
#define GPIO1_IOLED_BASE        (0x020E0068)
#define GPIO1_IOPAD_BASE        (0x020E02F4)
#define GPIO1_IODR_BASE         (0x0209C000)
#define GPIO1_GDIR_BASE         (0x0209C004)/* mappings of the io phe*/
static void* __iomem LED_CCGR1;
static void* __iomem LEDBASE;
static void* __iomem LEDPAD_BASE;
static void* __iomem LEDDR_BASE;
static void* __iomem LEDGDIR_BASE;/* we use a device struct */
typedef struct __myled {struct cdev char_dev_handle;dev_t       dev_id;int         major;int         minor;struct class*   led_class_handle; struct device*  led_handle_device;struct device_node* node;
}MyLED;static MyLED myled;/* operations cached */
static char operations_cached[20];static void __led_turn_on(void)
{u32 val = 0;val = readl(LEDDR_BASE);val &= ~(1 << 3);writel(val, LEDDR_BASE);
}static void __led_turn_off(void)
{u32 val = 0;val = readl(LEDDR_BASE);val |= (1 << 3);writel(val, LEDDR_BASE);
}static u8 __fetch_led_status(void)
{u32 val = 0;val = readl(LEDDR_BASE);return !(val & (1 << 3));
}static void __enable_led_mappings(void)
{int val = 0;pr_info("Ready to mappings the registers...\n");LED_CCGR1 = of_iomap(myled.node, 0);LEDBASE = of_iomap(myled.node, 1);LEDPAD_BASE = of_iomap(myled.node, 2);LEDDR_BASE = of_iomap(myled.node, 3);LEDGDIR_BASE = of_iomap(myled.node, 4);// LED_CCGR1 = ioremap(regdata[0], regdata[1]);// LEDBASE = ioremap(regdata[2], regdata[3]);// LEDPAD_BASE = ioremap(regdata[4], regdata[5]);// LEDDR_BASE = ioremap(regdata[6], regdata[7]);// LEDGDIR_BASE = ioremap(regdata[8], regdata[9]);pr_info("mappings the registers done!\n");pr_info("LED_CCGR1     ioremap to: %p\n", LED_CCGR1);pr_info("LEDBASE       ioremap to: %p\n", LEDBASE);pr_info("LEDPAD_BASE   ioremap to: %p\n", LEDPAD_BASE);pr_info("LEDDR_BASE    ioremap to: %p\n", LEDDR_BASE);pr_info("LEDGDIR_BASE  ioremap to: %p\n", LEDGDIR_BASE);pr_info("initialize the led registers\n");val = readl(LED_CCGR1);// clear the bitsval &= ~(3 << 26);val |= (3 << 26);writel(val, LED_CCGR1);writel(0x5, LEDBASE);writel(0x10B0, LEDPAD_BASE);val = readl(LEDGDIR_BASE);val |= 1 << 3;writel(val, LEDGDIR_BASE);pr_info("operations of led is accessable!\n");
}static void __disable_led_mappings(void)
{__led_turn_off();pr_info("set the led turning off...\n");pr_info("set the led turning off done!\n");pr_info("Ready to unmappings the registers...\n");    iounmap(LED_CCGR1);iounmap(LEDBASE);iounmap(LEDPAD_BASE);iounmap(LEDDR_BASE);iounmap(LEDGDIR_BASE);pr_info("unmappings the registers done\n");
}static ssize_t led_read(struct file* filp, char* buffer, size_t count, loff_t* ppos)
{const char* status = "opened";int ret = 0;pr_info("\nled device is reading!\n");if(!__fetch_led_status()){status = "closed";} ret = copy_to_user(buffer, status, strlen(status));if(ret < 0){pr_warn("Copy to the user failed\n");return -EFAULT;}return 0;
}static ssize_t led_write(struct file* filp,const char* buffer, size_t count, loff_t* ppos)
{int check = 0;pr_info("\nled device is ready writing!\n");check = copy_from_user(operations_cached, buffer, count);if(check < 0){pr_warn("Can not copy from user!\n");return -EFAULT;}if(!strcmp(operations_cached, "open")){__led_turn_on();}else if(!strcmp(operations_cached, "close")){__led_turn_off();}else{pr_warn("Can not find the indications operations!\n""check the business: %s", operations_cached);}return 0;
}static int led_open(struct inode* inode, struct file* filp)
{pr_info("\nled device is opened!\n");return 0;
}static int led_close(struct inode* inode, struct file* filp)
{pr_info("\nled device is released!\n");return 0;
}static const struct file_operations led_ops = {.owner = THIS_MODULE,.open = led_open,.release = led_close,.write = led_write,.read = led_read
};/* register the device */
static int __init led_init(void)
{int ret = 0;u32 regdata[10];const char* compatible;const char* status_str;// fetch platform treemyled.node = of_find_node_by_path("/myled");if(myled.node == NULL){pr_warn("can not find the myled\n");return -EINVAL;}else{pr_info("find the myled in device tree!\n");}ret = of_property_read_string(myled.node, "status", &status_str);if(ret < 0){pr_warn("can not fetch the status node info");return EINVAL;}else{pr_info("status=%s\n", status_str);}ret = of_property_read_string(myled.node, "compatible", &compatible);if(ret < 0){pr_warn("can not fetch the status node info");return EINVAL;}else{pr_info("compatible=%s\n", status_str);}    ret = of_property_read_u32_array(myled.node, "reg", regdata, 10);if(ret < 0){pr_info("failed to fetch the reg device info!\n");return -EINVAL;}else{u8 i = 0;for(i = 0; i < 10; i+=2){pr_info("reg data: %#X %#X\n", regdata[i], regdata[i + 1]);}}// create the led deviceif(myled.major){myled.dev_id = MKDEV(myled.major, 0);ret = register_chrdev_region(myled.dev_id, LED_DEV_N, LED_DEV_NAME);}else{ret = alloc_chrdev_region(&myled.dev_id, 0, LED_DEV_N, LED_DEV_NAME);myled.major = MAJOR(myled.dev_id);myled.minor = MINOR(myled.dev_id);}if(ret < 0){pr_warn("Error in registering the device! Failed to register the region\n");goto failed_register_chrdev_region;}pr_info("Success in registering the device major=%d, minor=%d\n",myled.major, myled.minor);myled.char_dev_handle.owner = THIS_MODULE;cdev_init(&(myled.char_dev_handle), &led_ops);ret = cdev_add(&(myled.char_dev_handle), myled.dev_id, LED_DEV_N);if(ret < 0){pr_warn("Failed to add chardev into the kernel_list!\n");goto failed_add_chardev;}pr_info("Prepare to create the device class file...\n");myled.led_class_handle = class_create(THIS_MODULE, LED_DEV_NAME);if(IS_ERR(myled.led_class_handle)){// class creation failed, rollback!pr_warn("Failed to create the led class handle...\n");goto failed_create_class;}myled.led_handle_device = device_create(myled.led_class_handle, NULL, myled.dev_id, "%s", LED_DEV_NAME);if(IS_ERR(myled.led_handle_device)){pr_warn("Failed to create the led device ...\n");goto failed_create_device;}__enable_led_mappings();return 0;failed_create_device:class_destroy(myled.led_class_handle);
failed_create_class:cdev_del(&(myled.char_dev_handle));
failed_add_chardev:unregister_chrdev_region(myled.dev_id, LED_DEV_N);
failed_register_chrdev_region:return -EIO;
}static void __exit led_deinit(void)
{pr_info("Ready to remove the hook of the device operating file\n");device_destroy(myled.led_class_handle, myled.dev_id);class_destroy(myled.led_class_handle);pr_info("Ready to release the char dev handle\n");cdev_del(&(myled.char_dev_handle));pr_info("Ready to unhook the device region\n");unregister_chrdev_region(myled.dev_id, LED_DEV_N);__disable_led_mappings();pr_info("Successfully unregister the device\n");
}module_init(led_init);
module_exit(led_deinit);
/module_test # insmod led.ko 
find the myled in device tree!
status=okay
compatible=charlie-led
reg data: 0X20C406C 0X4
reg data: 0X20E0068 0X4
reg data: 0X20E02F4 0X4
reg data: 0X209C000 0X4
reg data: 0X209C004 0X4
Success in registering the device major=249, minor=0
Prepare to create the device class file...
Ready to mappings the registers...
mappings the registers done!
LED_CCGR1     ioremap to: f42c406c
LEDBASE       ioremap to: f42e0068
LEDPAD_BASE   ioremap to: f42e02f4
LEDDR_BASE    ioremap to: a08e6000
LEDGDIR_BASE  ioremap to: a08ee004
initialize the led registers
operations of led is accessable!
/module_test # ./chrdev_application /dev/charlies_led write openled device is opened!
args: 4
led device is ready writing!user process the write issue: o
led device is released!
pen
/module_test # ./chrdev_application /dev/charlies_led write closeled device is opened!
args: 4
led device is ready writing!user process the write issue: c
led device is released!
lose
/module_test # rmmod led.ko 
Ready to remove the hook of the device operating file
Ready to release the char dev handle
Ready to unhook the device region
set the led turning off...
set the led turning off done!
Ready to unmappings the registers...
unmappings the registers done
Successfully unregister the device

使用pinctl和gpio子系統——LED驅動

? 對于如何初始化LED燈所使用的GPIO,整個過程可以分為幾個步驟。

首先需要修改設備樹,添加相應的節點,其中最重要的是設置reg屬性,這個屬性包含了GPIO相關的寄存器信息。接下來要獲取reg屬性中的IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03和IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03這兩個寄存器地址,并初始化它們,這兩個寄存器用于設置GPIO1_IO03這個引腳的復用功能、上下拉、速度等參數。

在完成這一步后,由于GPIO1_IO03這個引腳已經被復用為GPIO功能,因此還需要設置GPIO1_IO03相關的GPIO寄存器,也就是GPIO1_DR和GPIO1_GDIR這兩個寄存器。簡單來說,第二步完成了對GPIO1_IO03引腳的初始化,設置其復用功能等屬性,比如將其設置為GPIO功能;

而第三步則完成了對GPIO本身的初始化,設置其輸入輸出方向等。這個流程與STM32的開發類似,都是先設置引腳的復用功能、速度、上下拉等屬性,再配置對應的GPIO功能。實際上,大多數32位SOC的引腳配置都遵循這個模式,因此Linux內核專門針對引腳配置開發了pinctrl子系統,針對GPIO配置開發了gpio子系統。我們綜合應用起來,就能開發大部分的GPIO驅動的外設了。

? 要使用pinctrl 子系統,我們需要在設備樹里面設置 PIN 的配置信息,畢竟 pinctrl 子系統要根據你提供的信息來配置 PIN 功能,一般會在設備樹里面創建一個節點來描述 PIN 的配置信息。我們需要做的就是打開 imx6ull.dtsi 文件,找到一個叫做 iomuxc 的節點,我們實際上會向這里追加數據,但是不在這個文件加,而是在我們的自己的板子配置文件上加。

? 對于IMX6ULL,這個板子的配置實際上寫在了iomuxc節點下的imx6ul-evk下,我們繼續追加

				pinctrl_charliesled: ledgrp {fsl,pins = <MX6UL_PAD_GPIO1_IO03__GPIO1_IO03	0x10B0>;};

? 控制組加好了之后,我們就可以聲明我們的GPIO設備的LED節點的信息

	charliesled {#address-cells = <1>;#size-cells = <1>;compatible = "charlies-gpioled";pinctrl-names = "default";pinctrl-0 = <&pinctrl_charliesled>;led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;status = "okay";};

? 但是你需要注意的是——因為我們現在拿到的是原廠的板子,這個GPIO很有可能已經被復用了,因此,你需要做的是搜索一下板子上使用這個GPIO的設備,看看他是不是用在了自己的板子上

  • 檢查pinctrl 設置。
  • 如果這個 PIN 配置為 GPIO 的話,檢查這個 GPIO 有沒有被別的外設使用。

? 我們就是需要做這兩個事情.檢查發現:

		pinctrl_tsc: tscgrp {fsl,pins = <MX6UL_PAD_GPIO1_IO01__GPIO1_IO01	0xb0MX6UL_PAD_GPIO1_IO02__GPIO1_IO02	0xb0/* MX6UL_PAD_GPIO1_IO03__GPIO1_IO03	0xb0 */MX6UL_PAD_GPIO1_IO04__GPIO1_IO04	0xb0>;};

&tsc {pinctrl-names = "default";pinctrl-0 = <&pinctrl_tsc>;/* xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; */measure-delay-time = <0xffff>;pre-charge-time = <0xfff>;status = "okay";
};

? 一次出現了一些不該不限的東西,這些是我們使用的板子上沒有的,可以安全的注釋掉.

? 隨后編譯上傳我們的設備樹,查看是否正常.

使用GPIO驅動子系統為我們化簡驅動

我們下面就來看看我們的Linux操作系統給我們提供了啥花活。gpio_request函數用于申請一個GPIO管腳,其原型為int gpio_request(unsigned gpio, const char *label),其中gpio參數是要申請的GPIO標號(可通過of_get_named_gpio從設備樹獲取),label是為該GPIO指定的名稱,返回0表示申請成功。當不再需要使用某個GPIO時,應調用void gpio_free(unsigned gpio)函數進行釋放。

要配置GPIO方向,可以使用gpio_direction_inputgpio_direction_output函數。int gpio_direction_input(unsigned gpio)將指定GPIO設置為輸入模式,而int gpio_direction_output(unsigned gpio, int value)則將其設置為輸出模式并設置初始輸出值(value參數),兩者都返回0表示成功。

對于GPIO值的讀寫操作,gpio_get_value宏(實際調用__gpio_get_value函數)用于讀取GPIO的當前值,其原型為int __gpio_get_value(unsigned gpio),返回非負值表示讀取到的電平狀態。gpio_set_value宏(對應__gpio_set_value函數)用于設置GPIO輸出電平,原型為void __gpio_set_value(unsigned gpio, int value),無返回值。這些函數是GPIO子系統中最常用的API,涵蓋了GPIO的申請、釋放、方向配置及電平操作等基本功能。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>	
#include <asm/io.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_address.h>MODULE_LICENSE("GPL");
MODULE_AUTHOR("charliechen<charliechen114514@demo.com>");#define     LED_OFF_VALUE       (1)
#define     LED_ON_VALUE        (0)
#define     LED_CNT             (1)
#define     MY_LED_NAME         ("charliesled")static struct charlies_led_dev {dev_t           devid;struct cdev     led_cdev;struct class*   led_class;struct device*  led_device;int     led_major;int     led_minor;struct device_node* device_node;int     led_gpio_n;
}charliesled_dev;static void set_led_status(int value)
{int ret = 0;ret = gpio_direction_output(charliesled_dev.led_gpio_n, value);if(ret < 0){pr_warn("Can not set the led as turning off!\n");}return;
}static int led_open(struct inode *inode, struct file *filp){filp->private_data = &charliesled_dev; return 0;}static ssize_t led_read(struct file* filp, char* buffer, size_t count, loff_t* ppos){int ret = 0;const char* status = "opened";int gpio_current_value = 0;pr_info("Triggering the read gpio status of led!\n");gpio_current_value = gpio_get_value(charliesled_dev.led_gpio_n);if(gpio_current_value == LED_OFF_VALUE){status = "closed";}ret = copy_to_user(buffer, status, strlen(status));if(ret < 0){pr_warn("Copy to the user failed\n");return -EFAULT;}return 0;}/* operations cached */
static char operations_cached[20];
static ssize_t led_write(struct file* filp,const char* buffer, size_t count, loff_t* ppos)
{int check = 0;struct charlies_led_dev *dev = filp->private_data;pr_info("\nled device is ready writing!\n");check = copy_from_user(operations_cached, buffer, count);if(check < 0){pr_warn("Can not copy from user!\n");return -EFAULT;}if(!strcmp(operations_cached, "open")){gpio_set_value(dev->led_gpio_n, LED_ON_VALUE); }else if(!strcmp(operations_cached, "close")){gpio_set_value(dev->led_gpio_n, LED_OFF_VALUE); }else{pr_warn("Can not find the indications operations!\n""check the business: %s", operations_cached);}memset(operations_cached, 0, 20);return 0;
}static int led_release(struct inode *inode, struct file *filp)
{pr_info("Led device is released!\n");return 0;
}static struct file_operations led_op = {.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release = 	led_release,
};static int fetch_from_device_tree(void)
{charliesled_dev.device_node = of_find_node_by_path("/charliesled");if(!charliesled_dev.device_node){pr_warn("Can not find the device node!\n");return -EINVAL;}else{pr_info("we have found the target node!\n");}charliesled_dev.led_gpio_n = of_get_named_gpio(charliesled_dev.device_node, "led-gpio", 0);if(charliesled_dev.led_gpio_n < 0){pr_warn("Can not find the led-gpio property!\n");}pr_info("successfully fetch the led-gpio: %d\n", charliesled_dev.led_gpio_n);pr_info("default we turn off the led");set_led_status(LED_ON_VALUE);return 0;
}static int init_device(void)
{if(charliesled_dev.led_major){// the led device has been defined the valuecharliesled_dev.devid = MKDEV(charliesled_dev.led_major, 0);register_chrdev_region(charliesled_dev.devid, LED_CNT, MY_LED_NAME);}else{alloc_chrdev_region(&charliesled_dev.devid, 0, LED_CNT, MY_LED_NAME);charliesled_dev.led_major = MAJOR(charliesled_dev.devid);charliesled_dev.led_minor = MINOR(charliesled_dev.devid);}pr_info("Device number requires succuss: major-id: %d, minor-id: %d\n", charliesled_dev.led_major, charliesled_dev.led_minor);charliesled_dev.led_cdev.owner = THIS_MODULE;cdev_init(&charliesled_dev.led_cdev, &led_op);cdev_add(&charliesled_dev.led_cdev, charliesled_dev.devid, LED_CNT);pr_info("cdev init and add success!\n");charliesled_dev.led_class = class_create(THIS_MODULE, MY_LED_NAME);if(IS_ERR(charliesled_dev.led_class)){pr_info("class creation failed\n");return PTR_ERR(charliesled_dev.led_class);}pr_info("class creation success!\n");charliesled_dev.led_device = device_create(charliesled_dev.led_class, NULL, charliesled_dev.devid, NULL, MY_LED_NAME);if(IS_ERR(charliesled_dev.led_device)){pr_info("device creation failed\n");return PTR_ERR(charliesled_dev.led_device);}pr_info("device creation success!\n");return 0;
}static int __init led_init(void)
{int ret;pr_info("Fetching from the device tree!\n");if(fetch_from_device_tree()){pr_warn("The fetch failed!\n");return -EINVAL;}pr_info("Successfully fetch from the device tree!\n");ret = init_device();pr_info("Device init finished!\n");return ret;
}static void __exit led_exit(void)
{pr_info("LED Driver Exiting... turn off the device!\n");set_led_status(LED_OFF_VALUE);pr_info("Erase the device and classes...\n");device_destroy(charliesled_dev.led_class, charliesled_dev.devid);class_destroy(charliesled_dev.led_class);pr_info("Erase the cdev and release the dev id\n");cdev_del(&charliesled_dev.led_cdev);unregister_chrdev_region(charliesled_dev.devid, LED_CNT);pr_info("Module exit!\n");
}module_init(led_init);
module_exit(led_exit);

? 現在我們可以測試,結果照常,這里就不展示了

再試一次:BEEP驅動

? 還是一樣,我們第一步是編寫pinctl的group

		pinctrl_charliesbeep: beepgrp {fsl,pins = <MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01	0x10B0>;};	

? 然后下一步是

	charliesbeep {#address-cells = <1>;#size-cells = <1>;compatible = "charlies-gpiobeep";pinctrl-names = "default";pinctrl-0 = <&pinctrl_charliesbeep>;led-gpio = <&gpio5 1 GPIO_ACTIVE_LOW>;status = "okay";		};

? 經過我們的檢查,實際上沒有&gpio5 1和MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01的沖突,咱們直接用就好了,下一步就是稍微小小的修改一下上一個LED的驅動即可:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>	
#include <asm/io.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_address.h>MODULE_LICENSE("GPL");
MODULE_AUTHOR("charliechen<charliechen114514@demo.com>");#define     BEEPOFF_VALUE       (1)
#define     BEEPON_VALUE        (0)
#define     BEEPCNT             (1)
#define     MY_BEEPNAME         ("charliesbeep")static struct charlies_beep_dev {dev_t           devid;struct cdev     beep_cdev;struct class*   beep_class;struct device*  beep_device;int     beep_major;int     beep_minor;struct device_node* device_node;int     beep_gpio_n;
}charliesbeep_dev;static void set_beep_status(int value)
{int ret = 0;ret = gpio_direction_output(charliesbeep_dev.beep_gpio_n, value);if(ret < 0){pr_warn("Can not set the led as turning off!\n");}return;
}static int beep_open(struct inode *inode, struct file *filp){filp->private_data = &charliesbeep_dev; return 0;}static ssize_t beep_read(struct file* filp, char* buffer, size_t count, loff_t* ppos){int ret = 0;const char* status = "opened";int gpio_current_value = 0;pr_info("Triggering the read gpio status of led!\n");gpio_current_value = gpio_get_value(charliesbeep_dev.beep_gpio_n);if(gpio_current_value == BEEPOFF_VALUE){status = "closed";}ret = copy_to_user(buffer, status, strlen(status));if(ret < 0){pr_warn("Copy to the user failed\n");return -EFAULT;}return 0;}/* operations cached */
static char operations_cached[20];
static ssize_t beep_write(struct file* filp,const char* buffer, size_t count, loff_t* ppos)
{int check = 0;struct charlies_beep_dev *dev = filp->private_data;pr_info("\nled device is ready writing!\n");check = copy_from_user(operations_cached, buffer, count);if(check < 0){pr_warn("Can not copy from user!\n");return -EFAULT;}if(!strcmp(operations_cached, "open")){gpio_set_value(dev->beep_gpio_n, BEEPON_VALUE); }else if(!strcmp(operations_cached, "close")){gpio_set_value(dev->beep_gpio_n, BEEPOFF_VALUE); }else{pr_warn("Can not find the indications operations!\n""check the business: %s", operations_cached);}memset(operations_cached, 0, 20);return 0;
}static int beep_release(struct inode *inode, struct file *filp)
{pr_info("Led device is released!\n");return 0;
}static struct file_operations beep_op = {.owner = THIS_MODULE,.open = beep_open,.read = beep_read,.write = beep_write,.release = 	beep_release,
};static int fetch_from_device_tree(void)
{charliesbeep_dev.device_node = of_find_node_by_path("/charliesbeep");if(!charliesbeep_dev.device_node){pr_warn("Can not find the device node!\n");return -EINVAL;}else{pr_info("we have found the target node!\n");}charliesbeep_dev.beep_gpio_n = of_get_named_gpio(charliesbeep_dev.device_node, "led-gpio", 0);if(charliesbeep_dev.beep_gpio_n < 0){pr_warn("Can not find the led-gpio property!\n");}pr_info("successfully fetch the led-gpio: %d\n", charliesbeep_dev.beep_gpio_n);pr_info("default we turn off the led");set_beep_status(BEEPOFF_VALUE);return 0;
}static int init_device(void)
{if(charliesbeep_dev.beep_major){// the led device has been defined the valuecharliesbeep_dev.devid = MKDEV(charliesbeep_dev.beep_major, 0);register_chrdev_region(charliesbeep_dev.devid, BEEPCNT, MY_BEEPNAME);}else{alloc_chrdev_region(&charliesbeep_dev.devid, 0, BEEPCNT, MY_BEEPNAME);charliesbeep_dev.beep_major = MAJOR(charliesbeep_dev.devid);charliesbeep_dev.beep_minor = MINOR(charliesbeep_dev.devid);}pr_info("Device number requires succuss: major-id: %d, minor-id: %d\n", charliesbeep_dev.beep_major, charliesbeep_dev.beep_minor);charliesbeep_dev.beep_cdev.owner = THIS_MODULE;cdev_init(&charliesbeep_dev.beep_cdev, &beep_op);cdev_add(&charliesbeep_dev.beep_cdev, charliesbeep_dev.devid, BEEPCNT);pr_info("cdev init and add success!\n");charliesbeep_dev.beep_class = class_create(THIS_MODULE, MY_BEEPNAME);if(IS_ERR(charliesbeep_dev.beep_class)){pr_info("class creation failed\n");return PTR_ERR(charliesbeep_dev.beep_class);}pr_info("class creation success!\n");charliesbeep_dev.beep_device = device_create(charliesbeep_dev.beep_class, NULL, charliesbeep_dev.devid, NULL, MY_BEEPNAME);if(IS_ERR(charliesbeep_dev.beep_device)){pr_info("device creation failed\n");return PTR_ERR(charliesbeep_dev.beep_device);}pr_info("device creation success!\n");return 0;
}static int __init beep_init(void)
{int ret;pr_info("Fetching from the device tree!\n");if(fetch_from_device_tree()){pr_warn("The fetch failed!\n");return -EINVAL;}pr_info("Successfully fetch from the device tree!\n");ret = init_device();pr_info("Device init finished!\n");return ret;
}static void __exit beep_exit(void)
{pr_info("LED Driver Exiting... turn off the device!\n");set_beep_status(BEEPOFF_VALUE);pr_info("Erase the device and classes...\n");device_destroy(charliesbeep_dev.beep_class, charliesbeep_dev.devid);class_destroy(charliesbeep_dev.beep_class);pr_info("Erase the cdev and release the dev id\n");cdev_del(&charliesbeep_dev.beep_cdev);unregister_chrdev_region(charliesbeep_dev.devid, BEEPCNT);pr_info("Module exit!\n");
}module_init(beep_init);
module_exit(beep_exit);

? 完事!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/76046.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/76046.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/76046.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2025-04-07 NO.3 Quest3 MR 配置

文章目錄 1 MR 介紹1.1 透視1.2 場景理解1.3 空間設置 2 配置 MR 環境2.1 場景配置2.2 MR 配置 3 運行測試 配置環境&#xff1a; Windows 11Unity 6000.0.42f1Meta SDK v74.0.2Quest3 1 MR 介紹 1.1 透視 ? 透視&#xff08;Passthrough&#xff09;是將應用的背景從虛擬的…

如何在 GitHub 上開源一個小項目:從創建到長期維護的完整指南

如何在 GitHub 上開源一個小項目&#xff1a;從創建到長期維護的完整指南 適用于 個人開發者、團隊合作、企業開源&#xff0c;涵蓋 Git 基礎、GitHub 配置、最佳實踐、社區互動、自動化 CI/CD 及長期維護策略。 &#x1f4cc; 1. 注冊 GitHub 賬戶 如果你還沒有 GitHub 賬戶&…

【技術報告】GPT-4o 原生圖像生成的應用與分析

【技術報告】GPT-4o 原生圖像生成的應用與分析 1. GPT-4o 原生圖像生成簡介1.1 文本渲染能力1.2 多輪對話迭代1.3 指令遵循能力1.4 上下文學習能力1.5 跨模態知識調用1.6 逼真畫質與多元風格1.7 局限性與安全性 2. GPT-4o 技術報告2.1 引言2.2 安全挑戰、評估與緩解措施2.2.1 安…

React中的跨組件通信

在React中&#xff0c;跨組件通信有幾種常見的方式。每種方式適用于不同的場景&#xff0c;下面是幾種常見的跨組件通信方法&#xff1a; 1. 通過父子組件傳遞 Props 父組件可以通過 props 將數據傳遞給子組件&#xff0c;子組件只能接收和使用這些數據。 父組件&#xff08…

系統與網絡安全------Windows系統安全(8)

資料整理于網絡資料、書本資料、AI&#xff0c;僅供個人學習參考。 DNS DNS概述 為什么需要DNS系統 www.baidu.com與119.75.217.56&#xff0c;哪個更好記&#xff1f; 互聯網中的114查號臺/導航員 DNS&#xff08;Domian Name System&#xff0c;域名系統&#xff09;的功…

[ctfshow web入門] web16

信息收集 提示&#xff1a;對于測試用的探針&#xff0c;使用完畢后要及時刪除&#xff0c;可能會造成信息泄露 試試url/phpinfo.php url/phpsysinfo.php url/tz.php tz.php能用 點擊phpinfo&#xff0c;查看phpinfo信息&#xff0c;搜索flag&#xff0c;發現flag被保存為變量…

Go基礎一(Maps Functions 可變參數 閉包 遞歸 Range 指針 字符串和符文 結構體)

Maps 1.創建map make(map[鍵類型]值類型) 2.設置鍵值對 name[key]value; 3. name[key]獲取鍵值 3.1 key不存在 則返回 0 4.len()方法 返回 map 上 鍵值對數量 len(name) 5.delete()方法 從map中刪除 鍵值對 delete(name,key) 6.clear()方法 map中刪除所有鍵值對 clear(name) 7…

? 2025最新 | YOLO 獲取 COCO 指標終極指南 | 從標簽轉換到 COCOAPI 評估 (訓練/驗證) 全覆蓋【B 站教程詳解】

? YOLO 輕松獲取論文 COCO 指標&#xff1a;AP&#xff08;small&#xff0c;medium&#xff0c;large &#xff09;| 從標簽轉換到 COCOAPI 評估 (訓練/驗證) 全覆蓋 文章目錄 一、摘要二、為什么需要 COCO 指標評估 YOLO 模型&#xff1f;三、核心挑戰與解決方案 (視頻教程核…

ResNet改進(18):添加 CPCA通道先驗卷積注意力機制

1. CPCA 模塊 CPCA(Channel Prior Convolutional Attention)是一種結合通道先驗信息的卷積注意力機制,旨在通過顯式建模通道間關系來增強特征表示能力。 核心思想 CPCA的核心思想是將通道注意力機制與卷積操作相結合,同時引入通道先驗知識,通過以下方式優化特征學習: 通…

SpringMVC的簡單介紹

SpringMVC的簡單介紹 SpringMVC 是一個基于 Java 的 Web 框架&#xff0c;是 Spring Framework 中用于構建 Web 應用的一個核心模塊。它采用了 模型-視圖-控制器 (MVC) 設計模式&#xff0c;能夠幫助開發者更加清晰地分離業務邏輯、用戶界面和請求處理&#xff0c;從而提高應用…

MES生產工單管理系統,Java+Vue,含源碼與文檔,實現生產工單全流程管理,提升制造執行效率與精準度

前言&#xff1a; MES生產工單管理系統是制造業數字化轉型的核心工具&#xff0c;通過集成生產、數據、庫存等模塊&#xff0c;實現全流程數字化管理。以下是對各核心功能的詳細解析&#xff1a; 一、生產管理 工單全生命周期管理 創建與派發&#xff1a;根據銷售訂單或生產計…

Redis常見問題排查與解決方案指南

Redis作為高性能的內存數據庫&#xff0c;廣泛應用于緩存、隊列、實時統計等場景。但在實際使用中&#xff0c;開發者和運維人員常會遇到性能下降、內存溢出、主從同步失敗等問題。本文將針對高頻問題進行詳細分析&#xff0c;并提供對應的解決方案和預防措施&#xff0c;助你快…

目標跟蹤Deepsort算法學習2025.4.7

一.DeepSORT概述 1.1 算法定義 DeepSORT(Deep Learning and Sorting)是一種先進的多目標跟蹤算法,它結合了深度學習和傳統的目標跟蹤技術,在復雜環境下實現了高精度和魯棒性的目標跟蹤。該算法的核心思想是通過融合目標的外觀特征和運動特征,實現對多個目標的持續跟蹤,…

從零開始開發HarmonyOS應用并上架

開發環境搭建&#xff08;1-2天&#xff09; 硬件準備 操作系統&#xff1a;Windows 10 64位 或 macOS 10.13 內存&#xff1a;8GB以上&#xff08;推薦16GB&#xff09; 硬盤&#xff1a;至少10GB可用空間 軟件安裝 下載 DevEco Studio 3.1&#xff08;官網&#xff1a;…

Linux | 無頭 Linux 服務器安裝和設置

注&#xff1a;本文為 “Headless Linux” 相關文章合輯。 機翻未校。 How to Install and Set Up Headless Linux Server 如何安裝和設置無頭 Linux 服務器 Winnie Ondara Last Updated: January 31, 2023 A vast majority of Linux users are familiar with a Linux desk…

AI賦能數據庫管理“最后一公里”,融合架構重塑數據庫承載成本效能——zCloud 6.7與zData X 3.3正式發布

點擊藍字 關注我們 在數據驅動的新時代&#xff0c;數據庫的多元化和智能化已成不可逆的趨勢。3月31日&#xff0c;云和恩墨以“奇點時刻數智躍遷”為主題舉辦線上發布會&#xff0c;云和恩墨創始人兼總經理蓋國強、公司數據庫和生態產品群總經理熊軍共同帶來 zCloud 6.7與 zD…

I have something to say about Vue Node.js

關于Vue Node.js&#xff0c;我真的說了很多次了&#xff0c;讓我難以理解為啥這么粗糙的東西能流行一起。真瘋狂的世界。 vue讓感覺就像玩貓德一樣的&#xff0c;如此的瘋狂&#xff0c;天哪。睡覺了 Node.js v13 window7_nodejsv13-CSDN博客

【橘子大模型】使用streamlit來構建自己的聊天機器人(下)

一、簡介 我們之前完成了一個簡易的聊天機器人&#xff0c;但是還留下了一些問題沒有解決&#xff0c;比如如何開啟新的會話。如何切換session_id&#xff0c;如何把對話做成流式的輸出。這些我們就會在今天來完成。 二、關于新的會話和session_id from dotenv import load_…

php-cgi參數注入攻擊經歷淺談

起因&#xff1a; 阿里云服務器再次警告出現挖礦程序。上一次服務器被攻擊后&#xff0c;怕有惡意程序殘留&#xff0c;第一時間重裝了系統&#xff0c;也沒有詳查攻擊入口。不過事后還是做了一些防范&#xff0c;這臺留作公網訪問的服務器上并未保留業務數據&#xff0c;只作…

自動駕駛中的實時挑戰:如何優化車輛動力學模型

自動駕駛中的實時優化:自行車模型與雙軌模型的計算復雜度權衡 在自動駕駛領域,車輛動力學建模是實現精準控制和路徑規劃的關鍵。自行車模型和雙軌模型作為兩種主流的建模方法,在實時性需求下如何平衡計算復雜度與精確度,是工程師們必須面對的挑戰。本文將深入探討這兩種模…