在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

【i.MX6ULL】驅(qū)動(dòng)開(kāi)發(fā)4——點(diǎn)亮LED(寄存器版)

碼農(nóng)愛(ài)學(xué)習(xí) ? 來(lái)源:碼農(nóng)愛(ài)學(xué)習(xí) ? 作者:碼農(nóng)愛(ài)學(xué)習(xí) ? 2022-05-21 21:26 ? 次閱讀

上篇文章(【i.MX6ULL】驅(qū)動(dòng)開(kāi)發(fā)3--GPIO寄存器配置原理),介紹了i.MX6ULL芯片的GPIO的工作原理與寄存器配置。

本篇,就要來(lái)實(shí)際操作一下GPIO,實(shí)現(xiàn)板子上LED燈的亮滅控制。

在介紹如何通過(guò)寄存器來(lái)控制LED之前,需要先來(lái)了解一下有關(guān)Linux地址映射相關(guān)的知識(shí)。

1 地址映射

Linux或是STM32,對(duì)于硬件的控制,本質(zhì)都是操作寄存器,在對(duì)應(yīng)的地址進(jìn)行數(shù)據(jù)的讀寫(xiě)。若是在裸機(jī)開(kāi)發(fā)中,可以控制CPU直接操作寄存器的地址,實(shí)現(xiàn)相應(yīng)的功能,其過(guò)程是這樣的:

poYBAGKI5cqAbBZXAAArtF3Tv-A952.png

linux環(huán)境,一般是不會(huì)直接訪問(wèn)物理內(nèi)存,因?yàn)槿绻脩舨恍⌒男薷牧藘?nèi)存中的數(shù)據(jù),很有可能造成錯(cuò)誤甚至系統(tǒng)崩潰。為了避免這些問(wèn)題,linux內(nèi)核便引入了MMU和TLB進(jìn)行內(nèi)存地址映射,通過(guò)訪問(wèn)虛擬地址實(shí)現(xiàn)對(duì)實(shí)際物理地址的讀寫(xiě):

pYYBAGKI5dSAAeTnAAA0oU74bLY109.png

1.1 MMU介紹

MMU,Memory Manage Unit,即內(nèi)存管理單元,它提供統(tǒng)一的內(nèi)存空間抽象,程序通過(guò)訪問(wèn)虛擬內(nèi)存中的地址,MMU將虛擬地址(Virtual Address)翻譯成實(shí)際的物理地址(Physical Address) ,之后CPU即可操作實(shí)際的物理地址。

MMU具有如下功能:

保護(hù)內(nèi)存: MMU給一些指定的內(nèi)存塊設(shè)置了讀、寫(xiě)以及可執(zhí)行的權(quán)限,這些權(quán)限存儲(chǔ)在頁(yè)表當(dāng)中,MMU會(huì)檢查CPU當(dāng)前所處的是特權(quán)模式還是用戶模式,只有和操作系統(tǒng)所設(shè)置的權(quán)限匹配才可以訪問(wèn)。

提供方便統(tǒng)一的內(nèi)存空間抽象,實(shí)現(xiàn)虛擬地址到物理地址的轉(zhuǎn)換:CPU可以運(yùn)行在虛擬的內(nèi)存當(dāng)中,虛擬內(nèi)存一般要比實(shí)際的物理內(nèi)存大很多,使得CPU可以運(yùn)行比較大的應(yīng)用程序。

1.2 TLB介紹

TLB,Translation Lookaside Buffer,即轉(zhuǎn)譯后備緩沖器,也稱頁(yè)表緩存,里面存放的是一些頁(yè)表文件(虛擬地址到物理地址的轉(zhuǎn)換表),又稱為快表技術(shù)。

當(dāng)CPU第一次查找一個(gè)虛擬地址時(shí),硬件通過(guò)3級(jí)頁(yè)表(page table)得到最終的PPN(Physical Page Number),TLB會(huì)保存虛擬地址到物理地址的映射關(guān)系。這樣在下一次訪問(wèn)同一個(gè)虛擬地址時(shí),處理器通過(guò)查看TLB來(lái)直接返回物理地址,而不需要通過(guò)page table得到結(jié)果,從而提高地址轉(zhuǎn)換的效率。

1.3 I/O映射函數(shù)

Linux內(nèi)核啟動(dòng)的時(shí)候會(huì)初始化MMU,設(shè)置好內(nèi)存映射,設(shè)置好以后CPU訪問(wèn)的都是虛擬地址。

那在程序編寫(xiě)的時(shí)候,如何進(jìn)行物理內(nèi)存和虛擬內(nèi)存之間的轉(zhuǎn)換呢?這就需要用到兩個(gè)函數(shù):ioremap和iounmap。

ioremap()

ioremap函數(shù)用將物理地址映射為虛擬地址。

#define ioremap(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE) 

/**
 * paddr: 被映射的 IO 起始地址(物理地址)
 * size: 需要映射的空間大小,以字節(jié)為單位
 * return: 一個(gè)指向__iomem類型的指針,映射成功后便返回一段虛擬地址空間的起始地址
 */
void __iomem * __arm_ioremap(phys_addr_t phys_addr, size_t size, unsigned int mtype)
{ 
	return arch_ioremap_caller(phys_addr, size, mtype, __builtin_return_address(0)); 
} 

iounmap()

iounmap函數(shù)的作用是釋放掉ioremap函數(shù)所做的映射,即反向操作,在卸載驅(qū)動(dòng)的時(shí)候需要調(diào)用。

/**
 * addr: 要取消映射的虛擬地址空間首地址
 * return: void
 */
void iounmap (volatile void __iomem *addr) 

1.4 I/O內(nèi)存訪問(wèn)函數(shù)

在使用ioremap函數(shù)將物理地址轉(zhuǎn)換成虛擬地址之后,理論上我們便可以直接讀寫(xiě) I/O 內(nèi)存,但是為了符合驅(qū)動(dòng)的跨平臺(tái)以及可移植性,我們應(yīng)該使用 linux 中指定的函數(shù)(如:iowrite8()、iowrite16()、iowrite32()、ioread8()、ioread16()、ioread32() 等)去讀寫(xiě) I/O 內(nèi)存,而非直接通過(guò)映射后的指向虛擬地址的指針進(jìn)行訪問(wèn)。讀寫(xiě) I/O 內(nèi)存的函數(shù)如下:

unsigned int ioread8(void __iomem *addr);  /*讀取一個(gè)字節(jié)*/
unsigned int ioread16(void __iomem *addr); /*讀取一個(gè)字*/
unsigned int ioread32(void __iomem *addr); /*讀取一個(gè)雙字*/

void iowrite8(u8 b, void __iomem *addr);   /*寫(xiě)入一個(gè)字節(jié)*/
void iowrite16(u16 b, void __iomem *addr); /*寫(xiě)入一個(gè)字*/
void iowrite32(u32 b, void __iomem *addr); /*寫(xiě)入一個(gè)雙字*/

對(duì)于讀I/O而言,他們都只有一個(gè) __iomem 類型指針的參數(shù),指向被映射后的地址,返回值為讀取到的數(shù)據(jù);

對(duì)于寫(xiě)I/O而言他們都有兩個(gè)參數(shù),第一個(gè)為要寫(xiě)入的數(shù)據(jù),第二個(gè)參數(shù)為要寫(xiě)入的地址,返回值為空。

與這些函數(shù)相似的還有writeb、writew、writel、readb、readw、readl 等

u8  readb(const volatile void __iomem *addr);
u16 readw(const volatile void __iomem *addr); 
u32 readl(const volatile void __iomem *addr);
    
void writeb(u8 value,  volatile void __iomem *addr); 
void writew(u16 value, volatile void __iomem *addr); 
void writel(u32 value, volatile void __iomem *addr);     

在 ARM 架構(gòu)下,writex(readx)函數(shù)與 iowritex(ioreadx)有一些區(qū)別,writex(readx)不進(jìn)行端序的檢查,而 iowritex(ioreadx)會(huì)進(jìn)行端序的檢查。

2 程序編寫(xiě)

2.1 LED驅(qū)動(dòng)程序

led驅(qū)動(dòng)也是屬于字符設(shè)備驅(qū)動(dòng)的,之前介紹了新舊兩種字符驅(qū)動(dòng)的寫(xiě)法,本篇led驅(qū)動(dòng)就按照新字符設(shè)置驅(qū)動(dòng)的寫(xiě)法來(lái)編寫(xiě)。

關(guān)于新字符設(shè)備的驅(qū)動(dòng)模塊,可參考之前的文章:【i.MX6ULL】驅(qū)動(dòng)開(kāi)發(fā)2--新字符設(shè)備開(kāi)發(fā)模板

這里再放一張新字符設(shè)備開(kāi)發(fā)的模板框架

pYYBAGIyAdiAMiETAAEM8HQykVI076.png

2.1.1 字符設(shè)備的基本框架

//字符設(shè)備結(jié)構(gòu)體
struct newchrled_dev{
	dev_t         devid;	/* 設(shè)備號(hào)   */
	struct cdev   cdev;		/* cdev     */
	struct class  *class;	/* 類       */
	struct device *device;	/* 設(shè)備     */
	int           major;	/* 主設(shè)備號(hào) */
	int           minor;	/* 次設(shè)備號(hào) */
};
struct newchrled_dev chrdevled; /* led設(shè)備 */

//打開(kāi) 讀取 寫(xiě)入 釋放, 基礎(chǔ)文件操作函數(shù)
static int chrdevled_open(struct inode *inode, struct file *filp)
{
    /*設(shè)置chrdevled為私有數(shù)據(jù)*/
    return 0;
}
static ssize_t chrdevled_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
	return 0;
}
static ssize_t chrdevled_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
	return 0;
}
static int chrdevled_release(struct inode *inode, struct file *filp)
{
	return 0;
}

//設(shè)備操作函數(shù)結(jié)構(gòu)體
static struct file_operations chrdevled_fops = {
	.owner   = THIS_MODULE,	
	.open    = chrdevled_open,
	.read    = chrdevled_read,
	.write   = chrdevled_write,
	.release = chrdevled_release,
};

//驅(qū)動(dòng)入口函數(shù)
static int __init chrdevled_init(void)
{
    /* 初始化LED */
    /* 注冊(cè)字符設(shè)備驅(qū)動(dòng)(操作chrdevled_fops) */
    return 0;
}

//驅(qū)動(dòng)出口函數(shù)
static void __exit chrdevled_exit(void)
{
    /* 取消IO映射 */
    /* 注銷(xiāo)字符設(shè)備驅(qū)動(dòng) */
}

//驅(qū)動(dòng)的入口和出口函數(shù) 
module_init(chrdevled_init);
module_exit(chrdevled_exit);

//LICENSE和作者信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xxpcb");

2.1.2 具體完善

1)GPIO寄存器宏定義

需要配置相關(guān)的寄存器,就要對(duì)照著LED這個(gè)GPIO的硬件按需配置。

有關(guān)GPIO的各種寄存器的使用原理介紹,請(qǐng)參考上篇文章的介紹。

poYBAGIzTTGAWCbZAACbd73nSec681.png
/* 寄存器物理地址 */
#define CCM_CCGR1_BASE				(0X020C406C)	
#define SW_MUX_SNVS_TAMPER3_BASE    (0X02290014)
#define SW_PAD_SNVS_TAMPER3_BASE    (0X02290058)
#define GPIO5_DR_BASE				(0X020AC000)
#define GPIO5_GDIR_BASE				(0X020AC004)

/* 映射后的寄存器虛擬地址指針 */
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_SNVS_TAMPER3;
static void __iomem *SW_PAD_SNVS_TAMPER3;
static void __iomem *GPIO5_DR;
static void __iomem *GPIO5_GDIR;

CCM 是用來(lái)進(jìn)行時(shí)鐘的使能,其寄存器包括CCGR0~CCGR6,因?yàn)長(zhǎng)ED用到GPIO屬于GPIO5,它對(duì)應(yīng)的時(shí)鐘配置寄存器就是CCM_CCGR1

MUX 是用來(lái)將IO復(fù)用為GPIO

PAD 是用來(lái)配置IO的基本參數(shù)(驅(qū)動(dòng)能力、壓擺率、上下拉等)

GPIO5_DR 數(shù)據(jù)寄存器,當(dāng)GPIO為輸出模式時(shí),用來(lái)設(shè)置對(duì)應(yīng)的高低電平

GPIO5_GDIR 方向寄存器,用來(lái)設(shè)置輸入還是輸出

以上是先對(duì)這些需要使用的寄存器的地址聲明宏定義(這些寄存器的地址可通過(guò)查閱i.MX6ULL數(shù)據(jù)手冊(cè)得到),然后再聲明對(duì)應(yīng)的虛擬地址的指針,因?yàn)長(zhǎng)inux開(kāi)始MMU后,就不能直接對(duì)寄存器的地址直接操作了,需要使用映射后的虛擬地址。

2)GPIO硬件初始化

主要包括以下幾步:

寄存器地址映射:將需要用的寄存器的物理地址映射為虛擬地址

使能GPIO1時(shí)鐘:就是配置CCM_CCGR1寄存器

設(shè)置GPIO5_IO03的復(fù)用功能:配置MUX和PAD寄存器

設(shè)置GPIO5_IO03為輸出功能:配置GPIO5_GDIR方向寄存器

初始默認(rèn)關(guān)閉LED:配置GPIO5_DR數(shù)據(jù)寄存器

具體配置過(guò)程如下,主要這里使用"與"和"或"的位運(yùn)算操作,來(lái)配置寄存器中對(duì)應(yīng)位的值。

static void led_hardware_init(void)
{
    u32 val = 0;
        
    /* 1、寄存器地址映射 */
    IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, 4);
    SW_MUX_SNVS_TAMPER3 = ioremap(SW_MUX_SNVS_TAMPER3_BASE, 4);
    SW_PAD_SNVS_TAMPER3 = ioremap(SW_PAD_SNVS_TAMPER3_BASE, 4);
    GPIO5_DR = ioremap(GPIO5_DR_BASE, 4);
    GPIO5_GDIR = ioremap(GPIO5_GDIR_BASE, 4);

    /* 2、使能GPIO1時(shí)鐘 */
    val = readl(IMX6U_CCM_CCGR1);
    val &= ~(3 << 26);    /* 清除以前的設(shè)置 */
    val |= (3 << 26);    /* 設(shè)置新值 */
    writel(val, IMX6U_CCM_CCGR1);

    /* 3、設(shè)置GPIO5_IO03的復(fù)用功能,將其復(fù)用為GPIO5_IO03,最后設(shè)置IO屬性 */
    writel(5, SW_MUX_SNVS_TAMPER3);
    
    /*寄存器SW_PAD_SNVS_TAMPER3設(shè)置IO屬性
     *bit 16:0 HYS關(guān)閉
     *bit [15:14]: 00 默認(rèn)下拉
     *bit [13]: 0 kepper功能
     *bit [12]: 1 pull/keeper使能
     *bit [11]: 0 關(guān)閉開(kāi)路輸出
     *bit [7:6]: 10 速度100Mhz
     *bit [5:3]: 110 R0/6驅(qū)動(dòng)能力
     *bit [0]: 0 低轉(zhuǎn)換率
     */
    writel(0x10B0, SW_PAD_SNVS_TAMPER3);

    /* 4、設(shè)置GPIO5_IO03為輸出功能 */
    val = readl(GPIO5_GDIR);
    val &= ~(1 << 3);    /* 清除以前的設(shè)置 */
    val |= (1 << 3);    /* 設(shè)置為輸出 */
    writel(val, GPIO5_GDIR);

    /* 5、默認(rèn)關(guān)閉LED */
    val = readl(GPIO5_DR);
    val |= (1 << 3);    
    writel(val, GPIO5_DR);
}

3)字符設(shè)備初始化

需要定義led字符設(shè)備結(jié)構(gòu)體,來(lái)管理這個(gè)led設(shè)備。

/*newchr設(shè)備結(jié)構(gòu)體 */
struct newchrled_dev{
    dev_t         devid;    /* 設(shè)備號(hào)   */
    struct cdev   cdev;     /* cdev     */
    struct class  *class;   /* 類       */
    struct device *device;  /* 設(shè)備     */
    int           major;    /* 主設(shè)備號(hào) */
    int           minor;    /* 次設(shè)備號(hào) */
};

struct newchrled_dev chrdevled; /* led設(shè)備 */

具體的led字符設(shè)備初始化流程:

初始化LED的GPIO(上面剛介紹)

創(chuàng)建設(shè)備號(hào)

初始化cdev字符設(shè)備

添加cdev字符設(shè)備

創(chuàng)建類

創(chuàng)建設(shè)備

static int __init chrdevled_init(void)
{
    /* 初始化LED */
    led_hardware_init();

    /* 注冊(cè)字符設(shè)備驅(qū)動(dòng) */
    /* 1、創(chuàng)建設(shè)備號(hào) */
    if (chrdevled.major) /* 定義了設(shè)備號(hào) */
    {
        chrdevled.devid = MKDEV(chrdevled.major, 0);
        register_chrdev_region(chrdevled.devid, chrdevled_CNT, chrdevled_NAME);
    } 
    else /* 沒(méi)有定義設(shè)備號(hào) */
    {
        alloc_chrdev_region(&chrdevled.devid, 0, chrdevled_CNT, chrdevled_NAME);    /* 申請(qǐng)?jiān)O(shè)備號(hào) */
        chrdevled.major = MAJOR(chrdevled.devid);    /* 獲取分配號(hào)的主設(shè)備號(hào) */
        chrdevled.minor = MINOR(chrdevled.devid);    /* 獲取分配號(hào)的次設(shè)備號(hào) */
    }
    printk("chrdevled major=%d,minor=%d\n",chrdevled.major, chrdevled.minor);    
    
    /* 2、初始化cdev */
    chrdevled.cdev.owner = THIS_MODULE;
    cdev_init(&chrdevled.cdev, &chrdevled_fops);
    
    /* 3、添加一個(gè)cdev */
    cdev_add(&chrdevled.cdev, chrdevled.devid, chrdevled_CNT);

    /* 4、創(chuàng)建類 */
    chrdevled.class = class_create(THIS_MODULE, chrdevled_NAME);
    if (IS_ERR(chrdevled.class)) 
    {
        return PTR_ERR(chrdevled.class);
    }

    /* 5、創(chuàng)建設(shè)備 */
    chrdevled.device = device_create(chrdevled.class, NULL, chrdevled.devid, NULL, chrdevled_NAME);
    if (IS_ERR(chrdevled.device)) 
    {
        return PTR_ERR(chrdevled.device);
    }
    
    printk("chrdevled init done!\n");
    return 0;
}

4)LED亮滅控制

驅(qū)動(dòng)程序中,對(duì)于LED的控制,可以分為兩步。

第一步是接收和解析應(yīng)用層發(fā)來(lái)的控制數(shù)據(jù)(0或1來(lái)控制亮滅),將控制參數(shù)傳遞給具體的開(kāi)關(guān)led的函數(shù):

static ssize_t chrdevled_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
    unsigned char databuf[1];
    unsigned char ledstat;
    
    /* 接收用戶空間傳遞給內(nèi)核的數(shù)據(jù)并且打印出來(lái) */
    if(0 != copy_from_user(databuf, buf, cnt))
    {
        printk("kernel recevdata failed!\n");
        return -EFAULT;
    }
    
    ledstat = databuf[0];        /* 獲取狀態(tài)值 */

    if(ledstat == LEDON) 
    {    
        led_switch(LEDON);        /* 打開(kāi)LED燈 */
        printk("led on!\n");
    } 
    else if(ledstat == LEDOFF) 
    {
        led_switch(LEDOFF);       /* 關(guān)閉LED燈 */
        printk("led off!\n");
    }
    
    return 0;
}

第二步就是根據(jù)指令參數(shù),通過(guò)控制數(shù)據(jù)寄存器GPIO5_DR來(lái)實(shí)現(xiàn)GPIO的高低電平輸出,從而實(shí)現(xiàn)LED的亮滅:

void led_switch(u8 sta)
{
    u32 val = 0;
    if(sta == LEDON) 
    {
        val = readl(GPIO5_DR);
        val &= ~(1 << 3);    
        writel(val, GPIO5_DR);
    }
    else if(sta == LEDOFF) 
    {
        val = readl(GPIO5_DR);
        val|= (1 << 3);    
        writel(val, GPIO5_DR);
    }    
}

5)驅(qū)動(dòng)退出

驅(qū)動(dòng)不再使用時(shí),需要注銷(xiāo)相關(guān)的設(shè)備:

static void led_hardware_exit(void)
{
    iounmap(IMX6U_CCM_CCGR1);
    iounmap(SW_MUX_SNVS_TAMPER3);
    iounmap(SW_PAD_SNVS_TAMPER3);
    iounmap(GPIO5_DR);
    iounmap(GPIO5_GDIR);
}

首先釋放掉這些地址映射:

static void __exit chrdevled_exit(void)
{
    /* 取消IO映射 */
    led_hardware_exit();
    
    /* 注銷(xiāo)字符設(shè)備驅(qū)動(dòng) */
    cdev_del(&chrdevled.cdev);/*  刪除cdev */
    unregister_chrdev_region(chrdevled.devid, chrdevled_CNT); /* 注銷(xiāo)設(shè)備號(hào) */

    device_destroy(chrdevled.class, chrdevled.devid);
    class_destroy(chrdevled.class);
    
    printk("chrdevled exit done!\n");
}

驅(qū)動(dòng)程序基本就是這些,完整的程序見(jiàn)我的gitee倉(cāng)庫(kù):https://gitee.com/xxpcb/imx6ull

2.2 LED應(yīng)用程序

寫(xiě)完了驅(qū)動(dòng)程序(BSP),還要寫(xiě)對(duì)應(yīng)的應(yīng)用程序(APP)。

目前的應(yīng)用程序比較簡(jiǎn)短,因?yàn)樵贚inux中,一切皆文件,所以,對(duì)于LED的控制,就是通過(guò)向文件中寫(xiě)入0或1來(lái)實(shí)現(xiàn)LED的亮滅。

先來(lái)對(duì)0和1進(jìn)行宏定義:

#define LEDOFF  0 /*長(zhǎng)滅*/
#define LEDON   1 /*長(zhǎng)亮*/

然后就是main函數(shù)了:

int main(int argc, char *argv[])
{
    int fd, retvalue;
    char *filename;
    unsigned char databuf[1];

    if(argc != 3)
    {
        printf("Error Usage!\r\n");
        return -1;
    }

    filename = argv[1];

    /* 打開(kāi)led驅(qū)動(dòng)文件 */
    fd  = open(filename, O_RDWR);
    if(fd < 0)
    {
        printf("Can't open file %s\r\n", filename);
        return -1;
    }
    
    /* 要執(zhí)行的操作:打開(kāi)或關(guān)閉 */
    databuf[0] = atoi(argv[2]); 
    
    /* 向設(shè)備驅(qū)動(dòng)(/dev/chrdevled)寫(xiě)數(shù)據(jù) */
    retvalue = write(fd, databuf, sizeof(databuf));
    if(retvalue < 0)
    {
        printf("write file %s failed!\r\n", filename);
        close(fd);
        return -1;
    }

    /* 關(guān)閉設(shè)備 */
    retvalue = close(fd);
    if(retvalue < 0)
    {
        printf("Can't close file %s\r\n", filename);
        return -1;
    }

    return 0;
}

3 實(shí)驗(yàn)測(cè)試

3.1 程序編譯與下載

再來(lái)復(fù)習(xí)一下基本步驟:

ubuntu中通過(guò)gcc交叉編譯器編譯出led的驅(qū)動(dòng)程序和應(yīng)用程序

搭建局域網(wǎng)環(huán)境(電腦和linux板子連接到同一個(gè)路由器下,Linux板子以及燒錄了鏡像文件,能夠正常運(yùn)行)

通過(guò)tftp服務(wù)將兩個(gè)文件發(fā)送到linux板子的對(duì)應(yīng)目錄中(/lib/modules/4.1.15目錄)

進(jìn)行字符設(shè)備的加載,以及文件讀寫(xiě)測(cè)試(控制led亮滅)

poYBAGIx__mAJAMxAAFqlflsgR8688.png

程序的具體編譯過(guò)程與之前的類似,這里不再贅述,可參考之前的文章(如這篇:【i.MX6ULL】驅(qū)動(dòng)開(kāi)發(fā)2--新字符設(shè)備開(kāi)發(fā)模板)

3.2 實(shí)驗(yàn)現(xiàn)象

首先來(lái)看一下板子上LED的位置,如下圖的電路上的標(biāo)號(hào)D14處:

poYBAGKI58-AARrbAAvgSp2DtwI988.png

然后在串口中,按照之前介紹字符設(shè)備的加載流程,先加載led字符設(shè)備,然后就可以下向應(yīng)用程序?qū)?或0來(lái)控制led的亮滅了。

pYYBAGKI59qAKrYyAAC-dufz6w8036.png

led點(diǎn)亮的效果如下:

poYBAGKI5-GAEdbJABaJTzrkbIo962.png

4 總結(jié)

本篇主要介紹了如何通過(guò)操作寄存器來(lái)點(diǎn)亮i.MX6ULL開(kāi)發(fā)板上的led,通過(guò)編寫(xiě)LED對(duì)應(yīng)的驅(qū)動(dòng)程序和應(yīng)用程序,實(shí)現(xiàn)程序設(shè)計(jì)的分層。

因?yàn)長(zhǎng)inux使用了MMU進(jìn)行虛擬地址管理,因此在操作寄存器時(shí),要進(jìn)行地址映射后再操作。最后通過(guò)程序的實(shí)際測(cè)試,驗(yàn)證了led的亮滅功能。

審核編輯:符乾江

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5143

    文章

    19569

    瀏覽量

    315661
  • 驅(qū)動(dòng)
    +關(guān)注

    關(guān)注

    12

    文章

    1908

    瀏覽量

    86624
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11475

    瀏覽量

    213011
收藏 人收藏

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    i.MX6ULL嵌入式Linux開(kāi)發(fā)1-uboot移植初探

    本系列教程以i.MX6ULL處理的ARM開(kāi)發(fā)板為實(shí)驗(yàn)基礎(chǔ),學(xué)習(xí)記錄嵌入式Linux開(kāi)發(fā)的各種知識(shí)與經(jīng)驗(yàn),主要內(nèi)容包括嵌入式Linux移植,嵌入式Linux
    的頭像 發(fā)表于 03-07 08:57 ?4243次閱讀
    <b class='flag-5'>i.MX6ULL</b>嵌入式Linux<b class='flag-5'>開(kāi)發(fā)</b>1-uboot移植初探

    使用i.MX6ULL開(kāi)發(fā)板進(jìn)行Linux根文件系統(tǒng)的完善

    上一篇推文講了怎么移植根文件系統(tǒng),并在i.MX6ULL開(kāi)發(fā)板中運(yùn)行起來(lái),但是會(huì)出現(xiàn)一些提示,現(xiàn)在來(lái)進(jìn)行根文件的完善。
    發(fā)表于 10-17 11:13 ?966次閱讀

    移植NXP官方linux 5.4內(nèi)核到i.MX6ULL開(kāi)發(fā)

    本文描述移植NXP官方 linux 5.4 內(nèi)核到i.MX6ULL開(kāi)發(fā)板。
    發(fā)表于 12-19 11:10 ?2341次閱讀

    I.MX6ULL終結(jié)者開(kāi)發(fā)板裸機(jī)仿真jlink調(diào)試

    I.MX6ULL‘終結(jié)者’開(kāi)發(fā)板預(yù)留了JTAG仿真接口,并給出了開(kāi)發(fā)文檔,可以實(shí)現(xiàn)在JLINK仿真條件下的單步跟蹤、斷點(diǎn)調(diào)試等功能,使得開(kāi)發(fā)
    發(fā)表于 07-07 10:56

    i.MX6ULL開(kāi)發(fā)板硬件資源

    迅為i.MX6ULL 終結(jié)者開(kāi)發(fā)板硬件資源非常豐富,幾乎將 i.MX6ULL 芯片的所有資源都擴(kuò)展引出到底板上了,底板提供了豐富的外設(shè)接口,開(kāi)發(fā)板的尺寸是 190mm*125mm,充分
    發(fā)表于 12-29 06:18

    初識(shí) i.MX6ULL 寄存器

    裸機(jī)開(kāi)發(fā)_L1_匯編LED實(shí)驗(yàn)0. 本節(jié)目標(biāo)1. 硬件層電路2. 初識(shí) i.MX6ULL 寄存器2.1 i.MX6ULL 時(shí)鐘控制
    發(fā)表于 12-20 07:13

    關(guān)于i.MX6ULL配置GPIO

    正如學(xué)習(xí)C語(yǔ)言時(shí)寫(xiě)的第一段代碼都是“HelloWorld!”,接觸一款新的處理時(shí)往往是從點(diǎn)亮一個(gè)LED開(kāi)始;而點(diǎn)亮一個(gè)LED,則需要操作這
    發(fā)表于 08-05 10:37

    飛凌i.MX6ULL開(kāi)發(fā)板的評(píng)測(cè),再次進(jìn)階擁有更高的性價(jià)比

    MCIMX6Y2開(kāi)發(fā)設(shè)計(jì),采用先進(jìn)的ARMCortex-A7內(nèi)核,運(yùn)行速度高達(dá)800MHz。i.MX6ULL應(yīng)用處理包括一個(gè)集成的電源管理模塊,降低了外接電源的復(fù)雜性,并簡(jiǎn)化了上電時(shí)
    發(fā)表于 10-27 11:55 ?1654次閱讀
    飛凌<b class='flag-5'>i.MX6ULL</b><b class='flag-5'>開(kāi)發(fā)</b>板的評(píng)測(cè),再次進(jìn)階擁有更高的性價(jià)比

    基于NXP i.MX6ULL處理的FETMX6ULL-C核心板

    合作伙伴,飛凌不負(fù)美譽(yù),基于i.MX6ULL匠心打造的FETMX6ULL-S核心板一經(jīng)問(wèn)世便好評(píng)不斷,且已有數(shù)百家來(lái)自工業(yè)、醫(yī)療、電力、物聯(lián)網(wǎng)等行業(yè)的用戶采用此款核心板快速完成了整機(jī)產(chǎn)品的開(kāi)發(fā)上市。
    發(fā)表于 04-11 15:05 ?1293次閱讀
    基于NXP <b class='flag-5'>i.MX6ULL</b>處理<b class='flag-5'>器</b>的FETMX<b class='flag-5'>6ULL</b>-C核心板

    i.MX6ULL驅(qū)動(dòng)開(kāi)發(fā)6——GPIO子系統(tǒng)點(diǎn)亮LED

    本篇介紹了使用**Pinctrl子系統(tǒng)與GPIO子系統(tǒng)**的方式來(lái)點(diǎn)亮LED,與之前的寄存器點(diǎn)亮LED與設(shè)備樹(shù)版
    的頭像 發(fā)表于 05-21 21:50 ?3536次閱讀
    【<b class='flag-5'>i.MX6ULL</b>】<b class='flag-5'>驅(qū)動(dòng)</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>6</b>——GPIO子系統(tǒng)<b class='flag-5'>點(diǎn)亮</b><b class='flag-5'>LED</b>

    基于i.MX6ULL點(diǎn)亮LED

    都說(shuō)入門(mén)一款芯片的第一步是點(diǎn)亮LED,但是i.MX6ULL入門(mén)門(mén)檻比較高,特別是通過(guò)自學(xué)入門(mén)的,這個(gè)系列已經(jīng)寫(xiě)了好久了,最近打算在項(xiàng)目不急的時(shí)候加快一下學(xué)習(xí)進(jìn)度,現(xiàn)在就開(kāi)始學(xué)習(xí)一下怎么點(diǎn)亮
    的頭像 發(fā)表于 03-06 09:09 ?1061次閱讀

    使用pinctrl和gpio子系統(tǒng)實(shí)現(xiàn)LED驅(qū)動(dòng)

    前邊已經(jīng)學(xué)了兩種點(diǎn)燈,本質(zhì)依然還是通過(guò)配置寄存器;在學(xué)習(xí)STM32的時(shí)候除了學(xué)習(xí)配置一下寄存器,基本都是使用庫(kù)來(lái)開(kāi)發(fā),那么在i.MX6ULL還使用
    的頭像 發(fā)表于 04-03 10:17 ?1744次閱讀

    【北京迅為】i.MX6ULL開(kāi)發(fā)板移植 Debian 文件系統(tǒng)

    【北京迅為】i.MX6ULL開(kāi)發(fā)板移植 Debian 文件系統(tǒng)
    的頭像 發(fā)表于 02-10 15:34 ?1459次閱讀
    【北京迅為】<b class='flag-5'>i.MX6ULL</b><b class='flag-5'>開(kāi)發(fā)</b>板移植 Debian 文件系統(tǒng)

    基于i.MX6ULL的掉電檢測(cè)設(shè)計(jì)與軟件測(cè)試

    基于i.MX6ULL的掉電檢測(cè)設(shè)計(jì)與軟件測(cè)試基于i.MX6ULL平臺(tái)設(shè)計(jì)實(shí)現(xiàn)掉電檢測(cè)功能,首先選擇一路IO,利用IO電平變化觸發(fā)中斷,在編寫(xiě)驅(qū)動(dòng)時(shí)捕獲該路GPIO的中斷,然后在中斷響應(yīng)函數(shù)中發(fā)
    的頭像 發(fā)表于 11-09 10:40 ?1138次閱讀
    基于<b class='flag-5'>i.MX6ULL</b>的掉電檢測(cè)設(shè)計(jì)與軟件測(cè)試

    【迅為電子】i.MX6UL和i.MX6ULL芯片區(qū)別與開(kāi)發(fā)板對(duì)比

    【迅為電子】i.MX6UL和i.MX6ULL芯片區(qū)別與開(kāi)發(fā)板對(duì)比
    的頭像 發(fā)表于 11-28 14:31 ?1256次閱讀
    【迅為電子】<b class='flag-5'>i.MX6</b>UL和<b class='flag-5'>i.MX6ULL</b>芯片區(qū)別與<b class='flag-5'>開(kāi)發(fā)</b>板對(duì)比
    主站蜘蛛池模板: 天天操夜夜草 | 赛罗奥特曼银河帝国普通话免费版 | 丁香婷五月 | 国产精品 视频一区 二区三区 | 性过程很黄的小说男男 | 大片毛片女女女女女女女 | 亚洲精品福利你懂 | 久久精品男人的天堂 | 欧美成人免费 | 成人久久久| 免费中国jlzzjlzz在线播放 | 手机在线看a | 日日操夜夜爽 | 久久草在线看 | 免费一级毛片清高播放 | 立即播放免费毛片一级 | 小屁孩和大人啪啪 | 亚洲 另类 在线 欧美 制服 | 88影视在线观看污污 | 天天综合色一区二区三区 | 高h上错人1v1 | 全黄性色大片 | 天天操狠狠| 变态重口极致另类在线 | 四虎影院永久网址 | 色偷偷女男人的天堂亚洲网 | 黄色网久久| 717影院理论午夜伦不卡久久 | 亚州免费一级毛片 | 午夜手机看片 | 婷婷六月综合 | 台湾av | 激情五月婷婷综合 | www激情com| 中文字幕123 | 久久久免费精品视频 | 性生i活一级一片 | 免费精品视频在线 | 一级特黄aaa大片免色 | 美女毛片在线观看 | 99香蕉国产 |