amba H2平台用PWM控制LCD背光

守給你的承諾、 提交于 2019-12-02 19:02:06

amba H2系列CPU的GPIO口能作PWM使用的个数有限(GPIO0-GPIO3),从PRM里GPIO: Function Selection章节可以得到如何配置GPIO为PWM功能。

 

 

假设想把GPIO0配置成PWM输出,根据上图修改ambarella/boards/h2_xxx/bsp/bsp.h ,如下:

 

即DEFAULT_IOMUX_REG0_2、DEFAULT_IOMUX_REG0_1、DEFAULT_IOMUX_REG0_0的第0位要分别设为0、1、1。

一、系统层用脚本控制PWM0示例

 

echo 0 > /sys/class/pwm/pwmchip0/export
echo 5000000 > /sys/class/pwm/pwmchip0/pwm0/period (设置周期)
echo 2000000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle (设置有效时间)
echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable (使能PWM)

 

占空比= 有效时间/周期, 占空比越大,LCD背光越亮(有效时间要小于等于周期时间)。

 

为了方便使用写成脚本set_pwm.sh:

#! /bin/bash
#
# set_pwm.sh <gpio_id>  < 1 | 0 > <duty_cycle> <period>

do_cmd()
{
        local id=$1
        local ena=$2
        local d_cycle=$3
        local per=$4
        local GPIO_ROOT=/sys/class/pwm/pwmchip0
        local GPIO_DIR=$GPIO_ROOT/pwm$id

        if [[ ! -d $GPIO_DIR ]]; then
                echo $id > $GPIO_ROOT/export
        fi

        echo $ena > $GPIO_DIR/enable
        echo $per > $GPIO_DIR/period
        echo $d_cycle > $GPIO_DIR/duty_cycle
}

usage()
{
        echo " set_pwm.sh <gpio_id>  < 1 | 0 > <duty_cycle> <period>"
}

do_main()
{
        case "$2" in
                1)
                        do_cmd $1 1 $3 $4
                        ;;
                0)
                        do_cmd $1 0 $3 $4
                        ;;
                *)
                        usage
                        ;;
        esac
}

if [[ -z $4 ]]; then
        usage
else
        do_main $*
fi

 

二、写一个pwm驱动: pwm.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/pwm.h>
#include <linux/uaccess.h>


#define PWM_MAGIC 'P' //定义一个幻数
#define PWM_ON _IOW(PWM_MAGIC, 0, struct pwm_capture_t) //定义一个ioctl cmd#define PWM_OFF _IOW(PWM_MAGIC, 1, struct pwm_capture_t) //定义另一个ioctl cmd

struct pwm_device *pwm_dev_0;
struct pwm_capture_t {
    unsigned int period;
    unsigned int duty_cycle;
}pwmm;

static long pwm_ioctl(struct file *file,
        unsigned int cmd,
        unsigned long arg)
{
    int ret;
    switch(cmd) {
    case PWM_ON:
        ret = copy_from_user(&pwmm, (void *)arg, sizeof(struct pwm_capture_t));
        if (ret < 0) 
            return ret;
        ret = pwm_config(pwm_dev_0, pwmm.duty_cycle, pwmm.period);
        if (ret < 0) {
            printk("pwm_dev_0 ioctl fail");
            return 0;
        }
        pwm_enable(pwm_dev_0);
        break;
    case PWM_OFF:
        ret = copy_from_user(&pwmm, (void *)arg, sizeof(struct pwm_capture_t));
        if (ret < 0) 
            return ret;
        ret = pwm_config(pwm_dev_0, 0, pwmm.period);
        if (ret < 0) {
            printk("pwm_dev_2 ioctl fail");
            return 0;
        }
        pwm_disable(pwm_dev_0);
        break;
    }
    return 0;
}
//定义初始化硬件操作方法
static struct file_operations pwm_fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = pwm_ioctl
};
//定义初始化混杂设备对象
static struct miscdevice pwm_misc = {
    .minor = MISC_DYNAMIC_MINOR, //动态分配次设备号
    .name = "mypwm",             //dev/mypwm
    .fops = &pwm_fops 
};
static int pwm_init(void)
{
    int ret;
    printk("regisger pwm_misc device\n");
    //1.申请pwm资源,设置输出为0
    pwm_dev_0 = pwm_request(0, "pwm_0");
    if (pwm_dev_0 == NULL) {
        printk("pwm_dev_0 register fail\n");
    }


    ret = pwm_config(pwm_dev_0, 0, 500000);
    if (ret < 0) {
        printk("pwm_dev_0 config fail\n");
        return 0;
    }

    ret = pwm_enable(pwm_dev_0);
    if (ret == 0) {
        printk("pwm_dev_0 enable success\n");
    } else if (ret < 0 ) {
        printk("pwm_dev_0 enable fail\n");
        return 0;
    }
    //2.注册混杂设备
    misc_register(&pwm_misc);
    return 0;
}

static void pwm_exit(void)
{
    printk("unregister pwm_misc device\n");
    //1.卸载混杂设备
    misc_deregister(&pwm_misc);
    //2.释放pwm资源
    pwm_config(pwm_dev_0, 0, 500000);
    pwm_disable(pwm_dev_0);
    pwm_free(pwm_dev_0);

}

module_init(pwm_init);
module_exit(pwm_exit);
MODULE_LICENSE("GPL");

 

测试程序pwm_test.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#define PWM_MAGIC 'P' //定义一个幻数,要和pwm.c里定义的相同
#define PWM_ON _IOW(PWM_MAGIC, 0, struct pwm_capture_t)  //定义一个ioctl cmd, 要和pwm.c里定义的相同
#define PWM_OFF _IOW(PWM_MAGIC, 1, struct pwm_capture_t) //同上

struct pwm_capture_t {
    unsigned int period;
    unsigned int duty_cycle;
};

int main(int argc, char **argv)
{
    int fd;
    int a;
    int period, duty_cycle;
    if (argc < 4) {
        printf("usage: %s on/off duty_cycle period\n", argv[0]);
        return -1;
    }
    duty_cycle = strtol(argv[2], NULL, 10);
    period = strtol(argv[3], NULL, 10);
    if (duty_cycle > period) {
        printf("duty_cycle shouldn't larger than period\n");
        return -1;
    }
    struct pwm_capture_t pwmm = {period, duty_cycle};

    fd = open("/dev/mypwm", O_RDWR);
    if (fd < 0)
        return -1;
    while(1) {
    /*    for(a = 0; a <= period; a += 5) {
            pwmm.duty_cycle = a;
            ioctl(fd, PWM_ON, &pwmm);
            usleep(1000);
        }
        
        for(a = period; a >= 0; a -= 5) {
            pwmm.duty_cycle = a;
            ioctl(fd, PWM_ON, &pwmm);
            usleep(1000);
        }
        usleep(1000000);
    }
    */

    if (strcmp(argv[1], "on") == 0) {
        ioctl(fd, PWM_ON, &pwmm);
    } else if (strcmp(argv[1], "off") == 0) {
        ioctl(fd, PWM_OFF, &pwmm);
    } else {
        printf("invalid parameter\n");
    }


    close(fd);
    return 0;
}

 

 

 执行./pwm_test on 200000 500000,会看到LCD背光点亮,增加duty_cycle的值,背光会变得更亮。

pwm除了可以控制屏幕亮度外还可以控制风扇转速,根据cpu负载大小调整散热风扇的转速,也是一个常用的功能。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!