全志V3s V3x F1C200S等都适用
驱动点灯
led.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#define DEV_MAJOR 200 /* 主设备号 */
#define DEV_NAME "myled" /* 设备名 */
#define PB_CFG0_REG 0x01C20800 + 1 * 0x24 //PB配置寄存器 A:0 B:1 C:2 ....
#define PB_DATA_REG 0x01C20800 + 1 * 0x34 //PB数据寄存器 A:0 B:1 C:2 ....
#define PIN_N 5 //第5个引脚
#define N (PIN_N % 8 * 4) //引脚x : x % 8 * 4
volatile unsigned int *gpio_con = NULL;
volatile unsigned int *gpio_dat = NULL;
/*打开设备*/
static int led_open (struct inode *node, struct file *filp)
{
if (gpio_con) {
/*打开成功*/
}
else {
return -1;
}
return 0;
}
/*写设备*/
static ssize_t led_write (struct file *filp, const char __user *buf, size_t size, loff_t *off)
{
unsigned char val;
copy_from_user(&val, buf, 1);
if (val)
{
*gpio_dat |= (1 << PIN_N);//引脚5设置1
}
else
{
*gpio_dat &= ~(1 << PIN_N);//引脚5设置0
}
return 1;
}
/*关闭设备*/
static int led_release (struct inode *node, struct file *filp)
{
return 0;
}
/*
* 设备操作函数结构体
*/
static struct file_operations myled_oprs = {
.owner = THIS_MODULE,
.open = led_open,
.write = led_write,
.release = led_release,
};
/* 设备初始化 */
static int myled_init(void)
{
int ret;
ret = register_chrdev(DEV_MAJOR, DEV_NAME, &myled_oprs);
if (ret < 0) {
printk(KERN_ERR "fail\n");
return -1;
}
printk(KERN_ERR "init \n");
gpio_con = (volatile unsigned int *)ioremap(PB_CFG0_REG, 1);
//选择1
gpio_dat = (volatile unsigned int *)ioremap(PB_DATA_REG, 1);
//选择2
//gpio_dat = gpio_con + 4; //数据寄存器 指针+4是移动了4*4=16个字节 原来是0x24 现在是0x34
*gpio_con &= ~(7 << N); //7=111 取反000 20:22设置000 默认是0x7=111 失能
*gpio_con |= (1 << N); //设置输出 20:22设置001
*gpio_dat &= ~(1 << PIN_N); //第5个引脚初始化设置0
return 0;
}
static void __exit myled_exit(void)
{
/* 注销字符设备驱动 */
unregister_chrdev(DEV_MAJOR, DEV_NAME);
printk("exit!\r\n");
}
//注册模块加载函数
module_init(myled_init);
//卸载模块加载函数
module_exit(myled_exit);
//开源信息
MODULE_LICENSE("GPL");
//作者
MODULE_AUTHOR("Lv129");
Makefile
ifneq ($(KERNELRELEASE),)
#kbuild syntax. dependency relationshsip of files and target modules are listed here.
obj-m := led.o
else
PWD:= $(shell pwd)
KDIR := /home/lzq/desktop/129/linux-5.10
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
rm -rf .*.cmd *.o *.mod.c .tmp_versions *.mod *.symvers *.order
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions *.mod *.symvers *.order
endif
测试应用
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
/* ledtest on
* * ledtest off
* */
int main(int argc, char **argv)
{
int fd;
int a;
unsigned char val = 1;
if (argc != 3)
{
printf("Usage :\n");
printf("%s your_dev <on|off>\n", argv[0]);
return 0;
}
fd = open(argv[1], O_RDWR);
if (fd < 0)
{
printf("can't open!\n");
}
if (strcmp(argv[2], "on") == 0)
{
val = 1;
}
else
{
val = 0;
}
write(fd, &val, 1);
/* 关闭设备 */
a = close(fd);
if(a < 0){
printf("Can't\r\n");
return -1;
}
return 0;
}
Makefile
EXEC = led_test
OBJS = led_test.o
CROSS = arm-linux-gnueabihf-
CC = $(CROSS)gcc
STRIP = $(CROSS)strip
CFLAGS = -Wall -g -O2
all: clean $(EXEC)
$(EXEC):$(OBJS)
$(CC) $(CFLAGS) -o $@ $(OBJS)
$(STRIP) $@
clean:
-rm -f $(EXEC) *.o
离线
两个重要的寄存器
配置引脚
写入数据
离线
make 获取led.ko 和可执行的led_test 弄到板子上
先查看已经注册的设备号 发现里面没有200
root@lzq:/test# cat /proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
14 sound
29 fb
81 video4linux
89 i2c
90 mtd
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
212 DVB
226 drm
248 rpmb
249 ttyGS
250 bsg
251 watchdog
252 media
253 rtc
254 gpiochip
Block devices:
8 sd
65 sd
66 sd
67 sd
68 sd
69 sd
70 sd
71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc
259 blkext
root@lzq:/test#
加载内核驱动 再次查看 出现200 myled
root@lzq:/test# insmod led.ko
root@lzq:/test# cat /proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
14 sound
29 fb
81 video4linux
89 i2c
90 mtd
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
200 myled
212 DVB
226 drm
248 rpmb
249 ttyGS
250 bsg
251 watchdog
252 media
253 rtc
254 gpiochip
创建设备
root@lzq:/test# mknod /dev/myled c 200 0
root@lzq:/test# ls /dev/myled
/dev/myled
root@lzq:/test#
测试
root@lzq:/test# ./led_test /dev/myled on
root@lzq:/test# ./led_test /dev/myled off
root@lzq:/test#
创建脚本测试
vim run.sh
chmod +x run.sh
./run.sh
run.sh
#!/bin/bash
while(true)
do
./led_test /dev/myled on
sleep 0.3
./led_test /dev/myled off
sleep 0.3
done
效果(PB5是屏幕背光的引脚)
卸载驱动 删除设备
rmmod myled
rm /dev/myled
最近编辑记录 资本家大善人 (2021-12-19 18:07:05)
离线
应用点灯
应用层直接用C操作
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#define GPIO_REG_BASE 0x01C20800 //GPIO物理基地址 (小页4kb)
#define MAP_SIZE 0x400 //MMU页大小
#define GPIO_BASE_OFFSET (GPIO_REG_BASE & 0X00000FFF) //GPIO基地址偏移计算
#define GPIO_PAGE_OFFSET (GPIO_REG_BASE & 0XFFFFF000) //获得页偏移
/**********************修改的************************/
#define rPB_CFG0 0X24 //PB_CFG0寄存器地址偏移
#define rPB_DAT 0X34 //PB_DAT寄存器地址偏移
/***************************************************/
int led_on(unsigned char *MAP_BASE);
int led_off(unsigned char *MAP_BASE);
int main(int argc, char **argv)
{
static int dev_fd;
unsigned char *map_base;
if(argc!=2 || (strcmp(argv[1],"on") && strcmp(argv[1],"off"))){
printf("argv_error!please input 'on' or 'off'!\n");
exit (0);
}
dev_fd = open("/dev/mem", O_RDWR );
if (dev_fd < 0){
printf("open(/dev/mem) failed.\n");
return 0;
}
map_base = (unsigned char *)mmap(NULL, 0x400,PROT_READ | PROT_WRITE, MAP_SHARED,dev_fd, GPIO_PAGE_OFFSET); //把物理地址映射到虚拟地址
if(!strcmp(argv[1],"on")) led_on(map_base); //点亮LED
if(!strcmp(argv[1],"off")) led_off(map_base);//关闭LED
if(dev_fd) close(dev_fd);
munmap(map_base,MAP_SIZE);//解除映射关系
return 0;
}
//led_on
int led_on(unsigned char *MAP_BASE)
{
unsigned int PB_CFG0,PB_DAT;
PB_CFG0=*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPB_CFG0);
PB_DAT=*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPB_DAT);
*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPB_CFG0)=((PB_CFG0 & 0XFF0FFFFF)|0X00100000);//PB5 第6个引脚
*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPB_DAT)=((PB_DAT & 0XFFFFFFDF)|0X00000020);
}
//led_off
int led_off(unsigned char *MAP_BASE)
{
unsigned int PB_CFG0,PB_DAT;
PB_CFG0=*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPB_CFG0);
PB_DAT=*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPB_DAT);
*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPB_CFG0)=((PB_CFG0 & 0XFF0FFFFF)|0X00100000);//PB5 第6个引脚
*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPB_DAT)=((PB_DAT & 0XFFFFFFDF));
}
编译运行
arm-linux-gnueabihf-gcc led.c -o led
./led on
./led off
离线
另一种驱动代码(用到了GPIO的函数),会自动在/dev下创建设备
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <mach/gpio.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/device.h> // 内核源码里创建/移除设备,产生热插拔事件的函数class
#define MYMA 200
#define MYMI 3333
#define COUNT 1
#define LED_IO GPIOB(5)//注意修改! 对应开发板上的led灯引脚
dev_t devid; //用于存放设备号
struct cdev mycdev;
static struct class *mycls;
//打开设备文件时开启中断
static int myopen(struct inode *ind,struct file *fl)
{
int ret;
ret = gpio_request(LED_IO, "led_0"); //请求gpio口,tldev则是为其取一个名字。
if(ret<0)
goto err0;
gpio_direction_output(LED_IO, 0); //配置gpio口为输出,先输出低电平
return 0;
err0:
return ret;
}
static ssize_t mywrite(struct file *fl,const char *__user buf,size_t len,loff_t *off)
{
char stat;
copy_from_user(&stat,buf,sizeof(char));
if(stat)
gpio_set_value(LED_IO,1);
else
gpio_set_value(LED_IO,0);
return 0;
}
//关闭设备文件时释放中断
static int myclose(struct inode *inode,struct file *fl)
{
gpio_set_value(LED_IO,0);
gpio_free(LED_IO);
return 0;
}
static struct file_operations fops= {
.owner = THIS_MODULE,
.open = myopen,
.write = mywrite,
.release= myclose,
};
static int __init test_init(void)
{
int ret;
devid = MKDEV(MYMA, MYMI); //生成一个设备号
ret = register_chrdev_region(devid, COUNT, DEVNAME); //name设备名(用于查看用, 长度不能超过64字节 )
if (ret < 0)
goto err0;
cdev_init(&mycdev, &fops);
mycdev.owner = THIS_MODULE;
ret = cdev_add(&mycdev, devid, COUNT);
if (ret < 0)
goto err1;
mycls= class_create(THIS_MODULE,"mykeycls");
if(mycls== NULL)
goto err2;
device_create(mycls,NULL,devid,NULL,DEVNAME);
return 0;
err2:
cdev_del(&mycdev);
err1:
unregister_chrdev_region(devid, COUNT);
err0:
return ret;
}
static void __exit test_exit(void)
{
device_destroy(mycls,devid);
class_destroy(mycls);
unregister_chrdev_region(devid, COUNT);
cdev_del(&mycdev);
gpio_free(LED_IO); //释放gpio
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xxx");
MODULE_DESCRIPTION("led");
MODULE_VERSION("v0.0");
Makefile 和一楼的一样
make报错出现无#include <mach/gpio.h>
解决:
1.将内核源码中的如图文件夹复制到arch/arm/include/
这是linux3.4中的,我的是linux5.10,没有该文件夹
2.在内核源码arch/arm/include/下创建mach文件夹
创建gpio.h
/*
* arch/arm/mach-sunxi/include/mach/gpio.h
*
* Copyright(c) 2013-2015 Allwinnertech Co., Ltd.
* http://www.allwinnertech.com
*
* Author: sunny <sunny@allwinnertech.com>
*
* allwinner sunxi gpio defines.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/slab.h>
#ifndef __SUNXI_MACH_GPIO_H
#define __SUNXI_MACH_GPIO_H
/* pin group base number name space,
* the max pin number : 26*32=832.
*/
#define SUNXI_PINCTRL "sunxi-pinctrl"
#define SUNXI_BANK_SIZE 32
#define SUNXI_PA_BASE 0
#define SUNXI_PB_BASE 32
#define SUNXI_PC_BASE 64
#define SUNXI_PD_BASE 96
#define SUNXI_PE_BASE 128
#define SUNXI_PF_BASE 160
#define SUNXI_PG_BASE 192
#define SUNXI_PH_BASE 224
#define SUNXI_PI_BASE 256
#define SUNXI_PJ_BASE 288
#define SUNXI_PK_BASE 320
#define SUNXI_PL_BASE 352
#define SUNXI_PM_BASE 384
#define SUNXI_PN_BASE 416
#define SUNXI_PO_BASE 448
#define AXP_PIN_BASE 1024
#define SUNXI_PIN_NAME_MAX_LEN 8
/* sunxi gpio name space */
#define GPIOA(n) (SUNXI_PA_BASE + (n))
#define GPIOB(n) (SUNXI_PB_BASE + (n))
#define GPIOC(n) (SUNXI_PC_BASE + (n))
#define GPIOD(n) (SUNXI_PD_BASE + (n))
#define GPIOE(n) (SUNXI_PE_BASE + (n))
#define GPIOF(n) (SUNXI_PF_BASE + (n))
#define GPIOG(n) (SUNXI_PG_BASE + (n))
#define GPIOH(n) (SUNXI_PH_BASE + (n))
#define GPIOI(n) (SUNXI_PI_BASE + (n))
#define GPIOJ(n) (SUNXI_PJ_BASE + (n))
#define GPIOK(n) (SUNXI_PK_BASE + (n))
#define GPIOL(n) (SUNXI_PL_BASE + (n))
#define GPIOM(n) (SUNXI_PM_BASE + (n))
#define GPION(n) (SUNXI_PN_BASE + (n))
#define GPIOO(n) (SUNXI_PO_BASE + (n))
#define GPIO_AXP(n) (AXP_PIN_BASE + (n))
/* sunxi specific input/output/eint functions */
#define SUNXI_PIN_INPUT_FUNC (0)
#define SUNXI_PIN_OUTPUT_FUNC (1)
#define SUNXI_PIN_EINT_FUNC (6)
#define SUNXI_PIN_IO_DISABLE (7)
/* axp group base number name space,
* axp pinctrl number space coherent to sunxi-pinctrl.
*/
#define AXP_PINCTRL "axp-pinctrl"
#define AXP_CFG_GRP (0xFFFF)
#define AXP_PIN_INPUT_FUNC (0)
#define AXP_PIN_OUTPUT_FUNC (1)
#define IS_AXP_PIN(pin) (pin >= AXP_PIN_BASE)
/* sunxi specific pull up/down */
enum sunxi_pull_up_down {
SUNXI_PULL_DISABLE = 0,
SUNXI_PULL_UP,
SUNXI_PULL_DOWN,
};
/* sunxi specific data types */
enum sunxi_data_type {
SUNXI_DATA_LOW = 0,
SUNXI_DATA_HIGH = 0,
};
/* sunxi specific pull status */
enum sunxi_pin_pull {
SUNXI_PIN_PULL_DISABLE = 0x00,
SUNXI_PIN_PULL_UP = 0x01,
SUNXI_PIN_PULL_DOWN = 0x02,
SUNXI_PIN_PULL_RESERVED = 0x03,
};
/* sunxi specific driver levels */
enum sunxi_pin_drv_level {
SUNXI_DRV_LEVEL0 = 10,
SUNXI_DRV_LEVEL1 = 20,
SUNXI_DRV_LEVEL2 = 30,
SUNXI_DRV_LEVEL3 = 40,
};
/* sunxi specific data bit status */
enum sunxi_pin_data_status {
SUNXI_PIN_DATA_LOW = 0x00,
SUNXI_PIN_DATA_HIGH = 0x01,
};
/* sunxi pin interrupt trigger mode */
enum sunxi_pin_int_trigger_mode {
SUNXI_PIN_EINT_POSITIVE_EDGE = 0x0,
SUNXI_PIN_EINT_NEGATIVE_EDGE = 0x1,
SUNXI_PIN_EINT_HIGN_LEVEL = 0x2,
SUNXI_PIN_EINT_LOW_LEVEL = 0x3,
SUNXI_PIN_EINT_DOUBLE_EDGE = 0x4
};
/* the source clock of pin int */
enum sunxi_pin_int_source_clk {
SUNXI_PIN_INT_SRC_CLK_32K = 0x0,
SUNXI_PIN_INT_SRC_CLK_24M = 0x1
};
static inline int sunxi_gpio_to_name(int gpio, char *name)
{
int bank, index;
if (!name) {
return -EINVAL;
}
if (IS_AXP_PIN(gpio)) {
/* axp gpio name like this : GPIO0/GPIO1/.. */
index = gpio - AXP_PIN_BASE;
sprintf(name, "GPIO%d", index);
} else {
/* sunxi gpio name like this : PA0/PA1/PB0 */
bank = gpio / SUNXI_BANK_SIZE;
index = gpio % SUNXI_BANK_SIZE;
sprintf(name, "P%c%d", ('A' + bank), index);
}
return 0;
}
#endif /* __SUNXI_MACH_GPIO_H */
测试代码
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
int main(int argc, char** argv)
{
int fd;
char LED_ON=1,LED_OFF=0,flag=0;
fd = open("/dev/tldev", O_RDWR);
if (fd < 0)
{
perror("open");
}
while (1)
{
write(fd,&LED_ON,1); //led灯亮
sleep(1);
write(fd,&LED_OFF,1); //led灯灭
sleep(1);
}
return 0;
}
运行后LED交替亮灭1s
本人已经验证成功
最近编辑记录 资本家大善人 (2021-12-19 18:24:23)
离线
给楼主打CALL 学习了,是时候给板子加个外设接口了呀
离线
其他:
V3s设备树点灯—冷月枫啊
V3s内核定时器驱动LED—冷月枫啊
V3S Platform 驱动led—冷月枫啊
V3S 驱动key—冷月枫啊
如何使用linux系统自带的led驱动—Smalld_cat
最近编辑记录 资本家大善人 (2021-12-19 18:45:35)
离线
应用层pwm点灯
PB5引脚有pwm功能,我们可以通过它来调节背光灯亮度
#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 PIO_CFG_OFF 0x24 //配置
#define PIO_DAT_OFF 0x34 //数据
#define PWM_ADDR_OFF 0x1400
#define PWM_CH1_OFF 0x08 //pwm1
#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 *pwm1_period = NULL;
uint32_t T = 1000; //周期
int main(int argc , char **argv)
{
int mem_fd;
int duty=200;
if (argc!=2)
{
printf("./backlight level (level:0~100)\n");
exit(-1);
}
duty = T - atol(argv[1])*10;
if ((mem_fd = open("/dev/mem", O_RDWR)) < 0)
{
//printf("open error\r\n");
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\r\n");
close(mem_fd);
exit(-1);
}
//printf("base_map:0x%.8X\n", (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\n", (uint32_t)gpio_map);
gpio_cfg = (uint32_t)gpio_map + PIO_CFG_OFF; //gpioB控制寄存器地址
//printf("gpio_cfg:0x%.8X\n", (uint32_t)gpio_cfg);
gpio_dat = (uint32_t)gpio_map + PIO_DAT_OFF; //gpioB数据寄存器地址
//printf("gpio_dat:0x%.8X\n", (uint32_t)gpio_dat);
/*PB5点灯*/
(*gpio_cfg) &= ~((unsigned int)7 << 20); //先将对应位置0 //
(*gpio_cfg) |= ((unsigned int)1 << 20); //PB5 设定out //模式in out pwm
// (*gpio_dat) &= ~(1 << 5); //开灯
// sleep(1);
// (*gpio_dat) |= (1<<5);
// sleep(1);
/**
* PWM波配置顺序
* 1.GPIO 配置PWM输出模式
* 2.PWM 预分頻
* 3.PWM 总周期
* 4.PWM 活跃周期
* 5.PWM 使能
*/
//PB5设定PWM输出
(*gpio_cfg) &= ~((unsigned int)7 << 20); //置20:22 000
(*gpio_cfg) |= ((unsigned int)2 << 20); //PB5 2=010 设定20:22 010 pwm1模式
//我们需要的地址是0x01C21400,所以要再加上地址偏移量
pwm_base_map = (uint32_t)base_map + PWM_ADDR_OFF; //pwm_base_map也是pwm控制寄存器 初始值是0x00000000
//printf("pwm_base_map:0x%.8X\n", (uint32_t)pwm_base_map);
/*首先设置pwm1 预分頻*/ //PWM_CH1_PRESCAL
(*pwm_base_map) &= ~((uint32_t)15 << 15); //先将15~18位置0
(*pwm_base_map) |= (uint32_t)0 << 15; //将15~18位设置为 0000 ---> 对应分頻120 24m/120=200k
/*可能要设置SCLK_CH1_GATING为mask*/
(*pwm_base_map) &= ~((uint32_t)1 << 21); //先将第21位置0
(*pwm_base_map) |= (uint32_t)1 << 21; //将第21位置1 ---> 设置为自定义预分頻系数
/**
* 具体的总周期时间的作用需要进一步测试
* 注意:要活动周期设置好之后使能PWM通道
* 这样才会有正确输出,并且之后直接修改寄存器的值就可以修改占空比。
* */
/*再设置pwm1占空比*/
pwm1_period = (uint32_t)pwm_base_map + PWM_CH1_OFF; //pwm1_period设置pwm_CH1的占空比寄存器
//printf("pwm1_period:0x%.8X\n", (uint32_t)pwm1_period);
/*先设置总周期*/ //PWM周期的计算应该是这样 OSC 24MHz / Pre-scalar / (entire cycles + 1)
(*pwm1_period) &= ~((uint32_t)65535 << 16); //将31~16位置零
(*pwm1_period) |= (uint32_t)T << 16; // 现在设置整个周期65535
/*再设置活跃周期 活跃周期要小于总周期*/
(*pwm1_period) &= ~((uint32_t)65535 << 0); //将15~0位置零
(*pwm1_period) |= (uint32_t)duty << 0; //将15~0位置为2500 现在设置活跃周期为35535
/*最后应该设置PWM_CH1_EN为enable*/
(*pwm_base_map) &= ~((uint32_t)1 << 19); //先将第4位置0 ---> disable
(*pwm_base_map) |= (uint32_t)1 << 19; //将第4位置1 ---> enable pwm1
//printf("PWM ENABLE DUTY:%d\n",duty);
munmap(base_map, Page_Size);
//printf("munmap success!\n");
return 0;
}
0.配置
1.分频
pass自定义
2.周期
3.使能
测试
#!/bin/bash
t=0
while(true)
do
#sleep 0.001
.backlight $t
echo $((t++))
if [ $t == 101 ];then
t=0
echo "ok"
fi
done
效果
最近编辑记录 资本家大善人 (2021-12-19 19:18:24)
离线
这个如何编译到内核里面有没有例子呀,好期待哦
离线
这个如何编译到内核里面有没有例子呀,好期待哦
参考其他资料改改就行,内核源码里创建led文件夹,放源码,改Makefile,menuconfig选上,最后编译就行
离线
不需要改设备树么
离线
不需要改设备树么
这个帖子提供了好多种点灯的方法,没提到设备树的都不用改
离线
离线
用了楼主的方法尝试V3S pwm点灯,成功了,简单看了源码请问原理是不是直接在应用层操作底层寄存器?我想了解下linux的存储机制,既直接操作寄存器的原理,如何搜索关键字学习呢
/dev/mem设备+mmap+文件读写+数据手册
离线
led驱动编译到内核
在如图路径中放入led.c驱动代码 Kconfig Makefile
led.c
查看一楼
Kconfig
menu "led driver"
config LED
tristate"myled"
default y
endmenu
Makefile
obj-$(CONFIG_LED)+=led.o
修改char路径下的Kconfig和Makefile
在endmenu前加入
source "drivers/char/led/Kconfig"
obj-$(CONFIG_LED) += led/
make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j12
替换原来的zImage
启动系统查看加载的模块 200 myled
root@lzq:~# cat /proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
29 fb
81 video4linux
89 i2c
90 mtd
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
200 myled
212 DVB
226 drm
248 rpmb
249 ttyGS
250 bsg
251 watchdog
252 media
253 rtc
254 gpiochip
Block devices:
8 sd
65 sd
66 sd
67 sd
68 sd
69 sd
70 sd
71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc
259 blkext
最后手动创建myled的设备(代码里可自动创建),参考帖子里的教程
离线
这个如何编译到内核里面有没有例子呀,好期待哦
已更新,请查收
离线
离线
离线
sunxiang 说:这个如何编译到内核里面有没有例子呀,好期待哦
已更新,请查收
这样就从寄存器到应用程序全部讲清楚了,给大善点赞,这个才是linux入门的好帖子。
离线
离线
资本家大善人 说:sunxiang 说:这个如何编译到内核里面有没有例子呀,好期待哦
已更新,请查收
这样就从寄存器到应用程序全部讲清楚了,给大善点赞,这个才是linux入门的好帖子。
已经将led编译到内核里啦,然后每次上电就添加一次节点,然后自动执行脚本,led闪烁起来了。这样就好像又回到了单片机,哈哈。
离线
@sunxiang
驱动程序里可以自动生成设备文件,网上找找例程,改改,4楼里也有
最近编辑记录 资本家大善人 (2021-12-27 00:40:17)
离线
就是大善的这个参考资料,直接这样改吗,不需要 gpios= <&pio 1 5 GPIO_ACTIVE_LOW>;这一行吗, status=“okay”这个也没有提到哪个io呀,我有点懵。
离线
点灯就是开始,接下来timer,pwm,spi,adc,exit,sdio,usb,,,,这样就慢慢入门啦
最近编辑记录 sunxiang (2021-12-29 19:08:06)
离线
大善人这个资料真的不错,这是真真的入门好贴,感谢分享
离线
大善人赶紧发布下一阶段的教程啊,pwm spi 串口 usb,嗷嗷待哺
离线
坐等后续其他外设
离线
@资本家大善人
老哥 你3楼的那个方法,适用于V3S嘛
另外没有看出来你那个点亮的哪个gpio呀怎么更改要设置的gpio呀
都试用啊
离线
大善人赶紧发布下一阶段的教程啊,pwm spi 串口 usb,嗷嗷待哺
pwm出了啊,其他的没引出外设
离线
gpio 驱动可能是 linux 下最特异的驱动,每个应用的需求都不一样,而每个应用都会用到。
linux 下有没有通用的 gpio 驱动?
离线
单片机上点灯就非常简单,在LINUX下面这么复杂。
离线
应该以后能够参考,先收藏,希望用到时还能找到
离线
I would be happy if you can assit with that on tinaLinux with F133 board MQ-R i have - GPIO setting.
离线
很有助于学习Linux内核
离线
#define N (PIN_N % 8 * 4) //引脚x : x % 8 * 4
请问这个引脚怎么得来的? 比如我用的是PG6引脚,请问PIN_N应该怎么设置?
离线
#define N (PIN_N % 8 * 4) //引脚x : x % 8 * 4
请问这个引脚怎么得来的? 比如我用的是PG6引脚,请问PIN_N应该怎么设置?
#define PB_CFG0_REG 0x01C20800 + 1 * 0x24 //PB配置寄存器 A:0 B:1 C:2 ....
#define PB_DATA_REG 0x01C20800 + 1 * 0x34 //PB数据寄存器 A:0 B:1 C:2 ....
#define PIN_N 5 //第5个引脚
PG6
==>
#define PG_CFG0_REG 0x01C20800 + 6 * 0x24 //PG配置寄存器 A:0 B:1 C:2 D3 E4 F5 G6 ....
#define PG_DATA_REG 0x01C20800 + 6 * 0x34 //PG数据寄存器 A:0 B:1 C:2 ....
#define PIN_N 6 //第6个引脚
离线
@资本家大善人
楼主确实是大善人。
我对楼主的程序稍微做了些修改。
我的开发板是Nano Neo,我用的是PG11的引脚,但是寄存器计算公式和楼主代码不一致,我没有计算,我直接用了基址寄存器地址+偏移量。因为PG11根据公式,计算出来的寄存器地址是第0个配置寄存器地址,而PG11要通过第1个配置寄存器进行配置。
感谢楼主。
离线