龙芯技术社区
直播中

马博

13年用户 71经验值
擅长:操作系统/软件 EDA/IC/PCB设计 微处理器/微控制 数字及可编程逻辑 模拟与电源 基础元器件 操作系统/软件 EDA/IC/PCB设计 微处理器/微控制 数字及可编程逻辑 模拟与电源 基础元器件 操作系统/软件 EDA/IC/PCB设计 微处理器/微控制 数字及可编程逻辑 模拟与电源 基础元器件 操作系统/软件 EDA/IC/PCB设计 微处理器/微控制 数字及可编程逻辑 模拟与电源 基础元器件 操作系统/软件 EDA/IC/PCB设计 微处理器/微控制 数字及可编程逻辑 模拟与电源 基础元器件 操作系统/软件 EDA/IC/PCB设计 微处理器/微控制 数字及可编程逻辑 模拟与电源 基础元器件 操作系统/软件 EDA/IC/PCB设计 微处理器/微控制 数字及可编程逻辑 模拟与电源 基础元器件 操作系统/软件 EDA/IC/PCB设计 微处理器/微控制 数字及可编程逻辑 模拟与电源 基础元器件 操作系统/软件 EDA/IC/PCB设计 微处理器/微控制 数字及可编程逻辑 模拟与电源 基础元器件 操作系统/软件 EDA/IC/PCB设计 微处理器/微控制 数字及可编程逻辑 模拟
私信 关注
[2K系列]

【龙芯2K0300蜂鸟板试用】第八篇 龙芯2K0300蜂鸟板--PWM点灯

这周一直趁着工作闲暇时间,缓慢推进龙芯2k0300蜂鸟板的评测工作,现在总结一下。

一. PWM设备

通过厂商提供的用户手册可知龙芯2k0300 SOC片内总共有4个pwm控制器,并且在对应linux内核的设备树中导出了,所以用户直接使用即可。如图1和图2所示。
1.png
2.png

图1 设备树中PWM引脚相关定义

二.PWM操作

接下来便可以用最简单的sysfs方式对PWM进行操作了。如下图3所示,可以看出龙芯2k0300 SOC片内总共有4个PWM控制器,分别对应的pwmchip0~pwmchip3。
3.png

图3 PWM控制器对应的设备文件路径

进入任意一个PWM控制器设备可以查看其对应的属性文件,如图4所示。
4.png

图4 PWM3设备下的属性文件

对用户而言,重点关注export、npwm和unexport三个文件即可。

1.export:顾名思义就是输出,即将当前设备输出。

2.npwm:表示当前PWM设备共有几路通道。如下图5所示,通过命令查看龙芯2k0300 SOC片内PWM3只有1路PWM通道。
5.png

图5 PWM3设备下对应1路通道。

3.unxport:搭配export使用,即将之前导出的设备删除掉。

继续查看导出的PWM3控制器对应的通道有什么属性文件了(因为只有1路通道,所以默认是以0作标识的,即PWM0),如图6所示。
6.png

可以看到导出的PWM3控制器对应的PWM0通道总共有7个属性文件。如果操作过pwm控制器,尤其是裸机下或者stm32中的pwm控制器,想必这些名字会给人一种似曾相识的感觉,估计不用过多解释就知道应该操作那几个文件,以及如何操作了:通常就是先使能时钟并设置引脚(这里龙芯2k0300 SOC已经默认设置好了),所以只需设置周期、占空比,再使能输出即可,当不用时,去使能即可)。

1.enable:使能对应通道:“0”禁止,1“使能”。

2.period:设置pwm的周期。注意这里是以ns来作计数单位的。

3.duty_cycle:设置pwm的占空比。注意这里是以ns来作计数单位的。

4.polarity:设置pwm极性。通过示波器可以查看下信号。

具体操作可以如下图7所示。尝试写入1000000000ns(1秒)周期和500000000(0.5秒)占空比,成功让对应的LED灯进行了0.5秒亮和0.5秒灭的操作。
7.png

图7 通过pwm通道输出信号。

三. 编制对应的PWM驱动文件

有了以上的测试,接下来便可以将其编制成PWM驱动文件以供后续使用。

1.工程文件的组成,如图8所示。
8.png

图8 工程的组成

2.PWM.H

#ifndef __PWM_H_
#define __PWM_H_

int pwm_init(int channel);
int pwm_deinit(int channel);
int pwm_period(int channel, const char* period);
int pwm_duty(int channel, const char*  duty);
//0--normal
//1--inversed
int pwm_polarity(int channel, const int polarity);
int pwm_enable(int channel);
int pwm_disable(int channel);

#endif

3.PWM.C

#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include "include/pwm.h"

int pwm_init(int channel)
{
	int fd;
	
	switch(channel)
	{
	case 0:
		fd = open("/sys/class/pwm/pwmchip0/export", O_WRONLY);
		if(fd < 0)
			return 1;
		write(fd, "0", 1);

		fd = open("/sys/class/pwm/pwmchip0/pwm0/enable", O_WRONLY);
		if(fd < 0)
			return 2;
		write(fd, "0", 1);

		break;
	case 1:
		fd = open("/sys/class/pwm/pwnchip1/export", O_WRONLY);
		if(fd < 0)
			return 3;
		write(fd, "0", 1);

		fd = open("/sys/class/pwm/pwmchip1/pwm0/enable", O_WRONLY);
		if(fd < 0)
			return 4;
		write(fd, "0", 1);

		break;
	case 2:
		fd = open("/sys/class/pwm/pwmchip2/export", O_WRONLY);
		if(fd < 0)
			return 5;
		write(fd, "0", 1);

		fd = open("/sys/class/pwm/pwmchip2/pwm0/enable", O_WRONLY);
		if(fd < 0)
			return 6;
		write(fd, "0", 1);

		break;
	case 3:
		fd = open("/sys/class/pwm/pwmchip3/export", O_WRONLY);
		if(fd < 0)
			return 7;
		write(fd, "0", 1);

		fd = open("/sys/class/pwm/pwmchip3/pwm0/enable", O_WRONLY);
		if(fd < 0)
			return 8;
		write(fd, "0", 1);		

		break;
	default:
		break;
	}
	
	close(fd);	
	
	return 0;
}

int pwm_deinit(int channel)
{
	int fd;
	
	switch(channel)
	{
	case 0:
		fd = open("/sys/class/pwm/pwmchip0/unexport", O_WRONLY);
		if(fd < 0)
			return 21;
		write(fd, "0", 1);

		break;
	case 1:
		fd = open("/sys/class/pwm/pwmchip1/unexport", O_WRONLY);
		if(fd < 0)
			return 22;
		write(fd, "0", 1);

		break;
	case 2:
		fd = open("/sys/class/pwm/pwmchip2/unexport", O_WRONLY);
		if(fd < 0)
			return 23;
		write(fd, "0", 1);

		break;
	case 3:
		fd = open("/sys/class/pwm/pwmchip3/unexport", O_WRONLY);
		if(fd < 0)
			return 24;
		write(fd, "0", 1);

		break;
	default:
		break;
	}
 
	close(fd);	
	
	return 0;
}

int pwm_period(int channel, const char* period)
{
	int fd;
	
	switch(channel)
	{
	case 0:
		fd = open("/sys/class/pwm/pwmchip0/pwm0/period", O_WRONLY);
		if(fd < 0)
			return 31;
		write(fd, period, sizeof(period));		

		break;
	case 1:
		fd = open("/sys/class/pwm/pwmchip1/pwm0/period", O_WRONLY);
		if(fd < 0)
			return 32;
		write(fd, period, sizeof(period));

		break;
	case 2:
		fd = open("/sys/class/pwm/pwmchip2/pwm0/period", O_WRONLY);
		if(fd < 0)
			return 33;
		write(fd, period, sizeof(period));

		break;
	case 3:
		fd = open("/sys/class/pwm/pwmchip3/pwm0/period", O_WRONLY);
		if(fd < 0)
			return 34;
		write(fd, period, sizeof(period));

		break;
	default:
		break;
	}

	close(fd);

	return 0;
}

int pwm_duty(int channel, const char* duty)
{
	int fd;
	
	switch(channel)
	{
	case 0:
		fd = open("/sys/class/pwm/pwmchip0/pwm0/duty_cycle", O_WRONLY);
		if(fd < 0)
			return 41;
		write(fd, duty, sizeof(duty));		

		break;
	case 1:
		fd = open("/sys/class/pwm/pwmchip1/pwm0/duty_cycle", O_WRONLY);
		if(fd < 0)
			return 42;
		write(fd, duty, sizeof(duty));

		break;
	case 2:
		fd = open("/sys/class/pwm/pwmchip2/pwm0/duty_cycle", O_WRONLY);
		if(fd < 0)
			return 43;
		write(fd, duty, sizeof(duty));

		break;
	case 3:
		fd = open("/sys/class/pwm/pwmchip3/pwm0/duty_cycle", O_WRONLY);
		if(fd < 0)
			return 44;
		write(fd, duty, sizeof(duty));

		break;
	default:
		break;
	}

	close(fd);

	return 0;
}
//0--normal
//1--inversed
int pwm_polarity(int channel, const int polarity)
{
	int fd;
	
	switch(channel)
	{
	case 0:
		fd = open("/sys/class/pwm/pwmchip0/pwm0/polarity", O_WRONLY);
		if(fd < 0)
			return 51;
		switch(polarity)
		{
		case 0:
			write(fd, "normal", sizeof("normal"));		
			break;
		case 1:
			write(fd, "inversed", sizeof("inversed"));	
			break;	
		default:
			break;
		}	
		break;
	case 1:
		fd = open("/sys/class/pwm/pwmchip1/pwm0/polarity", O_WRONLY);
		if(fd < 0)
			return 52;
		switch(polarity)
		{
		case 0:
			write(fd, "normal", sizeof("normal"));		
			break;
		case 1:
			write(fd, "inversed", sizeof("inversed"));	
			break;	
		default:
			break;
		}	

		break;
	case 2:
		fd = open("/sys/class/pwm/pwmchip2/pwm0/polarity", O_WRONLY);
		if(fd < 0)
			return 53;
		switch(polarity)
		{
		case 0:
			write(fd, "normal", sizeof("normal"));		
			break;
		case 1:
			write(fd, "inversed", sizeof("inversed"));	
			break;	
		default:
			break;
		}	

		break;
	case 3:
		fd = open("/sys/class/pwm/pwmchip3/pwm0/polarity", O_WRONLY);
		if(fd < 0)
			return 54;
		switch(polarity)
		{
		case 0:
			write(fd, "normal", sizeof("normal"));		
			break;
		case 1:
			write(fd, "inversed", sizeof("inversed"));	
			break;	
		default:
			break;
		}	

		break;
	default:
		break;
	}

	close(fd);

	return 0;
}

int pwm_enable(int channel)
{
	int fd;
	
	switch(channel)
	{
	case 0:
		fd = open("/sys/class/pwm/pwmchip0/pwm0/enable", O_WRONLY);
		if(fd < 0)
			return 61;
		write(fd, "1", 1);

		break;
	case 1:
		fd = open("/sys/class/pwm/pwmchip1/pwm0/enable", O_WRONLY);
		if(fd < 0)
			return 62;
		write(fd, "1", 1);

		break;
	case 2:
		fd = open("/sys/class/pwm/pwmchip2/pwm0/enable", O_WRONLY);
		if(fd < 0)
			return 63;
		write(fd, "1", 1);

		break;
	case 3:
		fd = open("/sys/class/pwm/pwmchip3/pwm0/enable", O_WRONLY);
		if(fd < 0)
			return 64;
		write(fd, "1", 1);

		break;
	default:
		break;
	}
 
	close(fd);	
	
	return 0;
}


int pwm_disable(int channel)
{
	int fd;
	
	switch(channel)
	{
	case 0:
		fd = open("/sys/class/pwm/pwmchip0/pwm0/enable", O_WRONLY);
		if(fd < 0)
			return 71;
		write(fd, "0", 1);

		break;
	case 1:
		fd = open("/sys/class/pwm/pwmchip1/pwm0/enable", O_WRONLY);
		if(fd < 0)
			return 72;
		write(fd, "0", 1);

		break;
	case 2:
		fd = open("/sys/class/pwm/pwmchip2/pwm0/enable", O_WRONLY);
		if(fd < 0)
			return 73;
		write(fd, "0", 1);

		break;
	case 3:
		fd = open("/sys/class/pwm/pwmchip3/pwm0/enable", O_WRONLY);
		if(fd < 0)
			return 74;
		write(fd, "0", 1);

		break;
	default:
		break;
	}
 
	close(fd);	
	
	return 0;
}

4.main.c:相对简单的用来测试下pwm通道。

#include <stdio.h>
#include <unistd.h>
#include "include/pwm.h"

int main(int argc, char *argv[])
{	
	int channel , polarity;
	char*  period;
	char*   duty ;
	printf("This is pwm demo\\\\n");

	while(1){
		printf("Please input the channel: (0 ~ 3)\\\\n");
		scanf("%d", &channel);

		printf("Please input the period: \\\\n");
		scanf("%s", &period);

		printf("Please input the duty: \\\\n");
		scanf("%s", &duty);

		printf("Please input the nomarl(0) or polarity(1): \\\\n");
		scanf("%d", &polarity);
		
		pwm_init(channel);
		pwm_period(channel, period);
		pwm_duty(channel, duty);
		pwm_polarity(channel, polarity);
		pwm_enable(channel);

		getchar();

	}
       return 0;
}

5.Makefile文件

Target = pwm_demo
ARCH = loongarch
CC = loongarch64-linux-gnu-gcc

build_dir = build_$(ARCH)
src_dir =  source
inc_dir = include .

source = $(foreach dir,$(src_dir),$(wildcard $(dir)/*.c))
object = $(patsubst %.c,$(build_dir)/%.o,$(notdir $(source)))
include = $(foreach dir,$(inc_dir),$(wildcard $(dir)/*.h))
CFLAGS = $(patsubst %, -I%, $(inc_dir))
$(build_dir)/$(Target) : $(object)  | create_build
	$(CC) $^ -o $@ 
$(build_dir)/%.o : $(src_dir)/%.c $(include) | create_build
	$(CC) -c $(CFLAGS) $< -o $@ 
.PHONY:clean cleanall check create_build
clean:
	rm -rf $(build_dir)
cleanall:
	rm -rf build_x86 build_arm
check:
	[url=home.php?mod=space&uid=70594]@echo[/url] $(CFLAGS)
	@echo $(CURDIR)
	@echo $(src_dir)
	@echo $(source)
	@echo $(object)
create_build:
	[url=home.php?mod=space&uid=2293869]@MKDIR[/url] -p $(build_dir)

5.测试效果如下视频所示。

PWM点灯

更多回帖

发帖
×
20
完善资料,
赚取积分