zoukankan      html  css  js  c++  java
  • v3s PWM 使用mmap方式操作PWM

      这几天清明放假回家,感觉不做点事很有罪恶感,为了在V3S上实现PWM驱动,首先我要先知道PWM的寄存器使用方法。所以就写了这个测试程序。

    1.思路

      (1).首先映射寄存器。查看了V3S的datasheet,发现这个芯片的PWM输出不需要通过定时器就可以实现,

    这个还是比较好的。所以我需要映射一个GPIO寄存器以及一个PWM寄存器。

      (2).映射好了寄存器之后

      /*
      * PWM波配置顺序
      * 1.GPIO 配置PWM输出模式
      * 2.PWM 配置预分頻
      * 3.PWM 配置总周期
      * 4.PWM 配置活跃周期
      * 5.PWM 使能
      */
    2.代码 
    pwm_test.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <unistd.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    #include <string.h>
    
    #define PIO_BASE_ADDR 0x01C20000
    #define PIO_ADDR_OFF 0x800
    #define PWM_ADDR_OFF 0x1400
    #define PIO_CFG_OFF 0x24
    #define PIO_DAT_OFF 0x34
    #define PWM_CH0_OFF 0x04
    #define Page_Size (4096 * 2)
    
    uint32_t *base_map = NULL;
    uint32_t *gpio_map = NULL;
    uint32_t *gpio_cfg = NULL;
    uint32_t *gpio_dat = NULL;
    uint32_t *pwm_base_map = NULL;
    uint32_t *pwm0_period = NULL;
    
    int main(void)
    {
        int mem_fd;
        int duty=1000;
        if ((mem_fd = open("/dev/mem", O_RDWR)) < 0)
        {
            printf("open error
    ");
            exit(-1);
        }
        //mmap(系统自动分配内存地址,映射区长度“内存页的整数倍”,选择可读可写,MAP_SHARED=与其他所有映射到这个对象的进程共享空间,文件句柄,被映射内容的起点)
        //offest 映射物理内存的话,必须页对其!!!   所以这个起始地址应该是0x1000的整数倍,那么明显0x01C20800需要减去0x800才是整数倍!
        if ((base_map = (uint32_t *)mmap(NULL, Page_Size, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, PIO_BASE_ADDR)) == NULL)
        {
            printf("mmap error
    ");
            close(mem_fd);
            exit(-1);
        }
        printf("base_map:0x%.8X
    ", (uint32_t)base_map);
    
        close(mem_fd);                                //映射好之后就可以关闭文件?
                                                      //这里已经将0x1c20000的地址映射到了内存中,但是我们需要的地址是0x01C20800,所以要再加上地址偏移量~
        gpio_map = (uint32_t)base_map + PIO_ADDR_OFF; //加上偏移量必选先把他转化成unsigend int才可以相加
        printf("gpio_map:0x%.8X
    ", (uint32_t)gpio_map);
    
        gpio_cfg = (uint32_t)gpio_map + PIO_CFG_OFF; //gpioB控制寄存器地址
        printf("gpio_cfg:0x%.8X
    ", (uint32_t)gpio_cfg);
    
        gpio_dat = (uint32_t)gpio_map + PIO_DAT_OFF; //gpioB数据寄存器地址
        printf("gpio_dat:0x%.8X
    ", (uint32_t)gpio_dat);
    
        /*PB4点灯*/
        (*gpio_cfg) &= ~((unsigned int)7 << 16); //先将对应位置0
        (*gpio_cfg) |= ((unsigned int)1 << 16);  //PB5 设定out
        (*gpio_dat) &= ~(1 << 4); //开灯
        sleep(3);
    /**
     * PWM波配置顺序
     * 1.GPIO 配置PWM输出模式
     * 2.PWM 预分頻 
     * 3.PWM 总周期
     * 4.PWM 活跃周期
     * 5.PWM 使能
     */
        //PB4设定PWM输出
        (*gpio_cfg) &= ~((unsigned int)7 << 16);
        (*gpio_cfg) |= ((unsigned int)2 << 16); //PB4 设定PWM0模式
        //我们需要的地址是0x01C21400,所以要再加上地址偏移量
        pwm_base_map = (uint32_t)base_map + PWM_ADDR_OFF; //pwm_base_map也是pwm控制寄存器 初始值是0x00000000
        printf("pwm_base_map:0x%.8X
    ", (uint32_t)pwm_base_map);
    
        /*首先设置PWM0 预分頻*/                  //PWM_CH0_PRESCAL
        (*pwm_base_map) &= ~((uint32_t)15 << 0); //先将0~3位置0
        (*pwm_base_map) |= (uint32_t)8 << 0;     //将0~3位设置为 1000 ---> 对应分頻12k-->2K Hz
        /*可能要设置SCLK_CH0_GATING为mask*/
        (*pwm_base_map) &= ~((uint32_t)1 << 6); //先将第6位置0 
        (*pwm_base_map) |= (uint32_t)1 << 6; //将第6位置1 ---> 设置为自定义预分頻系数
    /**
     * 具体的总周期时间的作用需要进一步测试
     * 注意:要活动周期设置好之后使能PWM通道
     * 这样才会有正确输出,并且之后直接修改寄存器的值就可以修改占空比。
     * */
        /*再设置pwm0占空比*/
        pwm0_period = (uint32_t)pwm_base_map + PWM_CH0_OFF; //pwm0_period设置pwm_ch0的占空比寄存器
        printf("pwm0_period:0x%.8X
    ", (uint32_t)pwm0_period);
    
        /*先设置总周期*/ //PWM周期的计算应该是这样 OSC 24MHz / Pre-scalar / (entire cycles + 1)
        (*pwm0_period) &= ~((uint32_t)65535 << 16); //将31~16位置零    //24Mhz / 12K / (1999+1) =1s
        (*pwm0_period) |= (uint32_t)1999 << 16; // 现在设置整个周期65535
    
        /*再设置活跃周期  活跃周期要小于总周期*/
        (*pwm0_period) &= ~((uint32_t)65535 << 0); //将15~0位置零
        (*pwm0_period) |= (uint32_t)duty << 0; //将15~0位置为2500 现在设置活跃周期为35535
    
        /*最后应该设置PWM_CH0_EN为enable*/
        (*pwm_base_map) &= ~((uint32_t)1 << 4); //先将第4位置0 ---> disable
        (*pwm_base_map) |= (uint32_t)1 << 4;    //将第4位置1 ---> enable PWM0  
        printf("PWM ENABLE DUTY:%d
    ",duty);
        sleep(5);
    
        duty=1800;
        /*再设置活跃周期  活跃周期要小于总周期*/
        (*pwm0_period) &= ~((uint32_t)65535 << 0); //将15~0位置零
        (*pwm0_period) |= (uint32_t)duty << 0; //将15~0位置为2500 现在设置活跃周期为10000
        printf("PWM ENABLE DUTY:%d
    ",duty);
        sleep(5);
    
    
        munmap(base_map, Page_Size);
        printf("munmap success!
    ");
        return 0;
    }

    Makefile

    TARGET        = pwm_test    #可执行文件名称
    
    ########################编译参数############################
    CC            = arm-linux-gnueabihf-gcc 
    CXX           = arm-linux-gnueabihf-g++ 
    DEFINES       = 
    CFLAGS        = -pipe -g -Wall -W -fPIE $(DEFINES)
    CXXFLAGS      = -pipe -g -Wall -W -fPIE $(DEFINES)
    INCPATH       = -I. 
    PWD =$(shell pwd)  #当前路径
    FILE_PWD=$(strip $(PWD))
    LICHEDIR := /root/
    
    
    ########################编译文件############################
    SOURCES       = ./pwm_test.c 
    OBJECTS       = pwm_test.o
    
    $(TARGET) : $(OBJECTS)
            $(CC) -o $(TARGET) $(OBJECTS)
    pwm_test.o : pwm_test.c
            $(CC) $(include) $(CFLAGS) -c pwm_test.c 
    
    .PHONY : clean
    clean :
            rm  $(OBJECTS) $(TARGET)
    install:
            scp $(FILE_PWD)/$(TARGET) root@172.24.41.12:$(LICHEDIR)

    3.实验结果与总结

      编译,拷贝到板子里面运行之后感觉到闪烁频率为1s。并且占空比可控。

      我上面操作寄存器的,大家有兴趣的可以看看那V3S的datasheet。

      这里这个pre-scalar位 以及 period位。经过我的实践,发现这个应该和stm32差不多。

      都是 总频率/预分频/(总周期+1)。我这里设置的是 24MHz÷12K÷(1999+1)= 1Hz

      这个芯片应该和全志H2、H3差不多的配置。接下来可以选择写一个好一点的应用层操作库,也可以选择写一个驱动。

  • 相关阅读:
    85. Maximal Rectangle
    120. Triangle
    72. Edit Distance
    39. Combination Sum
    44. Wildcard Matching
    138. Copy List with Random Pointer
    91. Decode Ways
    142. Linked List Cycle II
    异或的性质及应用
    64. Minimum Path Sum
  • 原文地址:https://www.cnblogs.com/ZQQH/p/8733510.html
Copyright © 2011-2022 走看看