粤嵌6818开发板嵌入式Linux开发之内存映射

一、内存映射

1.内存映射的概念

把文件的一个区间映射到进程的虚拟地址空间 ,获得一段虚拟地址, 实现文件磁盘地址和这一段虚拟地址的一一对映关系。(即往这段虚拟地址写入数据,就相当于往这个文件中写入数据)

2.内存映射与普通文件IO的区别

例如:想把一些数据写入到文件中。

普通文件IO:

open()访问文件 -> 得到一个文件描述符fd -> 直接往文件描述符fd写入数据就可以了 -> 关闭文件描述符fd。

内存映射:

open()访问文件 -> 得到一个文件描述符fd -> 根据文件描述符fd去内存空间上映射一块空间,得到一个地址p -> 用户只需要将数据拷贝到内存空间上就可以了 -> 对应的文件就会有相应的变化 -> 撤销映射 -> 关闭文件描述符fd。

使用内存映射刷图片的优点:相对普通文件IO虽然代码步骤增加了,但是刷图的速度会更快。

3.内存映射相关函数

  • 内存映射函数 mmap的用法

man 2 mmap

头文件:

#include <sys/mman.h>

函数原型:

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

返回值类型:void *

返回值:

           成功:返回指向映射空间首地址的指针

           失败:MAP_FAILED

形参一:

           addr:映射空间首地址,一般设置NULL,让系统决定

形参二:

            length:设置映射空间的大小 在这里我们是800 * 480 * 4字节

形参三:

            prot:映射空间权限

                      PROT_READ 可读

                      PROT_WRITE 可写

                      常用这两个,如果需要可读可写,只需要将两个或上即可

形参四:

            flags:映射空间属性

                       MAP_SHARED:共享属性 (打开文件方式需要可读可写)

形参五:

             fd:想要映射的文件对应文件描述符(先打开文件,才可以映射)

形参六:

            offset:被映射文件的映射位置的偏移量(相对于映射空间的首地址),设置0

  • 取消映射函数 munmap的用法

头文件:

#include <sys/mman.h>

函数原型:

int munmap(void *addr, size_t length);

返回值类型:int

返回值:

          成功:0

          失败:-1

形参一:

           addr:需要取消的映射空间的首地址

形参二:

​          length:需要取消的映射空间的大小 在这里我们是800 * 480 * 4字节

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>

int main(int argc, char *argv[])
{
    // 1、打开fb0、bmp文件
    int lcd_fd = open("/dev/fb0", O_RDWR);
    if (lcd_fd == -1) 
    {
        printf("open lcd error!\n");
        return -1;  
    }
    int bmp_fd = open("./123.bmp", O_RDONLY);
    if (bmp_fd == -1) 
    {
        printf("open bmp error!\n");
        return -1;  
    }
    // 2、读取bmp文件的数据
    char bmp_buf[800*480*3];
    lseek(bmp_fd, 54, SEEK_SET);  // 跳过bmp文件头和信息头
    read(bmp_fd, bmp_buf, 800*480*3);  // 读取bmp文件数据到bmp_buf

    //3、数据处理
    int lcd_buf[800*480];
    int x,y;
    for (y = 0; y < 480; y++)
    {
        for (x = 0; x < 800; x++)
        {
            lcd_buf[800*(479-y)+x]    =   bmp_buf[3*(800*y+x)] | bmp_buf[3*(800*y+x)+1]<<8 | bmp_buf[3*(800*y+x)+2]<<16;
        }  
    }
    
    //4、内存映射
    int *p = (int *)mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd, 0);
    if (p == MAP_FAILED)
    {       
        printf("mmap error!\n");
        return -1;  
    }

    // 5、将数据拷贝到映射空间
    int n;
    for(n=0;n<800*480;n++)
    {
        *(p+n) = lcd_buf[n];
    }

    /*
    p    --->   lcd_buf[0]
    p+1  --->   lcd_buf[1]
    p+2  --->   lcd_buf[2]

    p+n  --->   lcd_buf[n]
    */
   
    // 6、关闭fb0、bmp文件、取消映射
    munmap(p, 800*480*4);
    close(lcd_fd); 
    close(bmp_fd);
    return 0;
}  

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值