• mmap()


    活动地址:CSDN21天学习挑战赛

    前言

    之前,我们使用 devmem 命令的方式和在内核空间使用 ioremap() 的方式,操作寄存器,实现了控制 LED 亮灭的功能。
    今天,我们使用一种在用户空间操作寄存器的方法来实现该功能,用到的函数就是 mmap()。

    mmap()

    函数原型如下

    void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
    
    • 1

    参数:
    addr:映射区的开始地址,设置为 0 时表示由系统决定映射区的起始地址。需要按照页面大小对齐,否则会出错。
    length:映射区的长度。长度以字节为单位,不足一内存页按一内存页处理。
    prot:期望的内存保护标志,类似于可读可写等
    flags:指定映射对象的类型
    fd:文件标识符
    offset:被映射对象内容的起点,需要按照页面大小对齐,否则会出错。

    返回值:

    成功时,mmap() 返回被映射区的地址,
    失败时,mmap() 返回 MAP_FAILED,错误原因记录于 errno。

    示例

    led_mem.c

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define BCM2837_GPIOFS_BASE 0x3F200000
    #define GPIO_CLR_REG_OFFSET 0x28
    #define GPIO_SET_REG_OFFSET 0x1C
    #define BLOCK_SIZE 			(4 * 1024)
    
    int main(int argc, char *argv[])
    {
    	int mem_fd;
    	void *gpio_base_map;
    	int i;
    
    	mem_fd = open("/dev/mem", O_RDWR | O_NDELAY);
    	if (mem_fd < 0) {
    		perror("open /dev/mem");
    		return -1;
    	}
    
    	gpio_base_map = mmap(NULL, BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, BCM2837_GPIOFS_BASE);
    
    	close(mem_fd);
    
    	if (gpio_base_map == MAP_FAILED) {
    		printf("mmap error %d\n", (int)gpio_base_map);
    		return -1;
    	}
    
    	for (i = 0; i < 10; i++) {
    		*(volatile unsigned int *)(gpio_base_map + GPIO_CLR_REG_OFFSET) = 0x7F;
    		printf("led on\n");
    		usleep(200000);
    
    		*(volatile unsigned int *)(gpio_base_map + GPIO_SET_REG_OFFSET) = 0x7F;
    		printf("led off\n");
    		usleep(200000);
    	}
    
    	munmap(gpio_base_map, BLOCK_SIZE);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    Makefile

    CROSS_COMPILE=/home/liyongjun/project/board/buildroot/RPi3/host/bin/arm-buildroot-linux-uclibcgnueabihf-
    
    all:
    	$(CROSS_COMPILE)gcc -Wall led_mem.c -o led_mem.out
    
    • 1
    • 2
    • 3
    • 4

    测试

    在 ubuntu 上交叉编译

    $ make
    /home/liyongjun/project/board/buildroot/RPi3/host/bin/arm-buildroot-linux-uclibcgnueabihf-gcc -Wall led_mem.c -o led_mem.out
    $ cp led_mem.out ~/tftp/
    
    • 1
    • 2
    • 3

    在树莓派上下载、运行

    # tftp -gr led_mem.out 192.168.31.223
    # chmod +x led_mem.out
    # ./led_mem.out 
    led on
    led off
    led on
    led off
    led on
    led off
    led on
    led off
    led on
    led off
    led on
    led off
    led on
    led off
    led on
    led off
    led on
    led off
    led on
    led off
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    请添加图片描述

  • 相关阅读:
    《Java》深浅拷贝解析(还不会区分深浅拷贝吗?快进来)
    单线程的JS中Vue导致的“线程安全”问题
    【C++】二叉搜索树Binary Search Tree
    STM32物联网项目-低功耗模式
    ESP32下的ble数据notify收发(支持ESP-IDF4.4\ESPIDF5.1)
    软件设计师中级
    Grads:绘制风流畅
    JavaScript变量和作用域简介
    xorm源码学习
    自然语言处理学习笔记-lecture5-语言模型02
  • 原文地址:https://blog.csdn.net/lyndon_li/article/details/126293393