当前位置: 首页 > 工具软件 > Flip timer > 使用案例 >

sp4418实现使用c++内存映射实现GPIO、Timer、PWM访问控制

尹正奇
2023-12-01
说明:本文代码由本人编写,可以作为sp4418c++标准库使用,可以作为应用开发者的参考代码,你也可以通过此代码扩展出更多的外设库。本文如需使用转载请给博主留言告知并说明出处,欢迎各位一起讨论。
缘由:网上没有使用c++实现内存映射,其实c++实现代码清晰易读,使用方便,而且具有很高的复用性和兼容性,可以在多平台的应用。
用法:将如下代码拷贝到板子的linux上然后保存成xxx.cpp然后编译运行即可。其中main函数是本人使用的实例代码,包含了GPIO、Timer、pwm,具体用到哪个注释掉其他代码打开相应的注释即可。
/*
 * 基于NanoPc-T2 Debian系统上的内存映射操作
 * 1、本实例为使用寄存器方式输出GPIO口,一条指令的速度可以达到20ns,
 * Author:http://blog.csdn.net/haohaojian
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

#ifndef __SP4418_FRIENDLY_
#define __SP4418_FRIENDLY_

#define uint8 unsigned char
#define bool char
#define true 1
#define false 0
#endif

#define uint32  intptr_t

#define MAP_SIZE (getpagesize())

class S5P4418{
public:

	static int dev_fd;
	S5P4418()
	{
		openMM();
	}

	~S5P4418()
	{
		closeMM();
	}
	static void openMM()
	{
		dev_fd = open("/dev/mem", O_RDWR | O_NONBLOCK);
		if (dev_fd < 0)
		{
			printf("open(/dev/mem) failed.");
		}
	}

	static void closeMM()
	{
		if(dev_fd){
			close(dev_fd);
			dev_fd = 0;
		}
	}

	static intptr_t getMapBase(intptr_t baseAddr)
	{
		intptr_t base = (intptr_t)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, S5P4418::dev_fd, baseAddr);
	    return base;
	}

	static void deleteMapBase(size_t  base);

	static uint32* Register(size_t mem, uint32 offset);
};

int S5P4418::dev_fd = 0;

 void S5P4418::deleteMapBase(size_t  base)
{
	munmap((intptr_t *)base,(size_t)MAP_SIZE);
}

 uint32* S5P4418::Register(size_t mem, uint32 offset)
{
	if (mem == 0)
		return NULL;
	return  (uint32 *)(mem + offset);
}



/*GPIO */
#define BaseGPIO  0xC001A000

enum{
INPUT = 0, OUTPUT
};

enum {
	PA = 0, PB, PC, PD, PE
};

enum {
	Fun_0 = 0, Fun_1, Fun_2, Fun_3
};

enum {
	PULLDOWN = 0, PULLUP, PULLDEFAULT
};

class PORT
{
public:
	PORT(uint8 PORTx)
	{
		intptr_t BaseADDR = 0;
		intptr_t Reg = 0;

		BaseADDR = BaseGPIO + (0x1000 * (uint32)(PORTx));
		this->hMem = S5P4418::getMapBase(BaseADDR);

		//Reg = (BaseADDR & 0x00000FFF);
		Reg = 0;
		OUT = S5P4418::Register(hMem, Reg+0x0000);
		OUTENB = S5P4418::Register(this->hMem, Reg+0x0004);
		DETMODE[0] = S5P4418::Register(this->hMem, Reg+0x0008);
		DETMODE[1] = S5P4418::Register(this->hMem, Reg+0x000C);
		INTENB = S5P4418::Register(this->hMem, Reg+0x0010);
		DET = S5P4418::Register(this->hMem, Reg+0x0014);
		PAD = S5P4418::Register(this->hMem, Reg+0x0018);
		ALTFN[0] = S5P4418::Register(this->hMem, Reg+0x0020);
		ALTFN[1] = S5P4418::Register(this->hMem, Reg+0x0024);
		DETMODEEX = S5P4418::Register(this->hMem, Reg+0x0028);
		DETENB = S5P4418::Register(this->hMem, Reg+0x003C);
		SLEW = S5P4418::Register(this->hMem, Reg+0x0040);
		SLEWDEF = S5P4418::Register(this->hMem, Reg+0x0044);
		DRV[0] = S5P4418::Register(this->hMem, Reg+0x0050);
		DRV[1] = S5P4418::Register(this->hMem, Reg+0x0048);
		DRVDEF[0] = S5P4418::Register(this->hMem, Reg+0x0054);
		DRVDEF[1] = S5P4418::Register(this->hMem, Reg+0x004C);
		PULLSEL = S5P4418::Register(this->hMem, Reg+0x0058);
		PULLDEF = S5P4418::Register(this->hMem, Reg+0x005C);
		PULLENB = S5P4418::Register(this->hMem, Reg+0x0060);
		PULLENBDEF = S5P4418::Register(this->hMem, Reg+0x0064);
	}
	~PORT(){
		if(hMem)
		S5P4418::deleteMapBase(hMem);
	}

	intptr_t hMem;

	uint32 *OUT;//输出口
	uint32 * OUTENB;//输出使能,共32位
	uint32 * DETMODE[2];
	uint32 * INTENB;
	uint32 * DET;
	uint32 * PAD;
	uint32 * ALTFN[2];
	uint32 * DETMODEEX;
	uint32 * DETENB;
	uint32 * SLEW;
	uint32 * SLEWDEF;
	uint32 * DRV[2];
	uint32 * DRVDEF[2];
	uint32 * PULLSEL;
	uint32 * PULLDEF;
	uint32 * PULLENB;
	uint32 * PULLENBDEF;

	void SetData(uint32 Data);
	uint32 GetData();
};

void PORT::SetData(uint32 Data)
{
	*OUT = Data;
}

uint32 PORT::GetData()
{
	return *OUT;
}

class GPIO{
public:
	PORT * Port;
	uint8 Pin;
	uint32 Bit;

	void SetFun(uint8 FUNx);
	void SetDir(uint8 IO );
	void SetDrv();
	void SetPull(uint8 Pull );
	void SetSlew(bool Slew ) ;
	bool GetSlew();
	void SetData(bool Data );
	bool GetData();
	void Flip();
	/*
	 * PORTx:对应A,B,C,D,E
	 * PINx:对应0-31*/
	GPIO(uint8 PORTx ,uint8 PINx)
	{
		Pin = 0;
		Bit = 0;
		Port = new PORT(PORTx );
		this->Pin = PINx;
		this->Bit = (0x1 << PINx);

		*this->Port->SLEWDEF &= ~this->Bit;
	}
	~GPIO(){
		delete Port;
	}
};

void GPIO::SetFun(uint8 FUNx) {
	switch (Pin) {
	case 0:
    case 1:
	case 2:
	case 3:
	case 4:
	case 5:
	case 6:
	case 7:
	case 8:
	case 9:
    case 10:
	case 11:
	case 12:
	case 13:
	case 14:
	case 15:
		*Port->ALTFN[0] &= ~(0x3 << (Pin * 2));
		*Port->ALTFN[0] |= (uint32)(FUNx << (Pin * 2));
		break;
	default:
		*Port->ALTFN[1] &= ~(0x3 << ((Pin - 16) * 2));
		*Port->ALTFN[1] |= (uint32)(FUNx << ((Pin - 16) * 2));
		break;
	}
}

 void GPIO::SetDir(uint8 IO ) {
	switch (IO) {
	case INPUT:
		*Port->OUTENB &= ~Bit;
		break;
	case OUTPUT:
		*Port->OUTENB |= Bit;
		break;
	}
}

void GPIO::SetDrv() {

}

void GPIO::SetPull(uint8 Pull ) {
	switch (Pull) {
	case PULLDOWN:
		*Port->PULLENB &= ~Bit;
		*Port->PULLDEF |= Bit;
		break;
	case PULLUP:
		*Port->PULLENB |= Bit;
		*Port->PULLDEF |= Bit;
		break;
	case PULLDEFAULT:
		*Port->PULLENB &= ~Bit;
		break;
	}
}

void GPIO::SetSlew(bool Slew ) {

	*Port->SLEWDEF |= Bit;
	switch (Slew) {
	case true:
		*Port->SLEW &= ~Bit;
		break;
	case false:
		*Port->SLEW |= Bit;
		break;
	default:
		break;
	}
}

bool GPIO::GetSlew() {
	return ((*Port->SLEWDEF & Bit) == Bit) && ((*Port->SLEW & Bit) == 0);
}

void GPIO::SetData(bool Data ) {
	switch (Data) {
	case true:
		*Port->OUT |= Bit;
		break;
	case false:
		*Port->OUT &= ~Bit;
		break;
	}
}

bool GPIO::GetData(){
	return (*Port->OUT & Bit) == Bit;
}

void GPIO::Flip() {;
	*Port->OUT ^= Bit;
}
/* GPIO END   */

/*定时器*/
long BaseTIMER = 0xC0017000;
enum{
	TIMER_0 = 0, TIMER_1, TIMER_2, TIMER_3, TIMER_4
};

class TIMER {
public:
	TIMER(uint8 TIMERx ,bool FunPWM );
	~TIMER(){
		if(hMem)S5P4418::deleteMapBase(hMem);
		if(gpio)delete gpio;
	}
	uint8 timerX;
	uint32 hMem;
	GPIO	*gpio;

	uint32 * TCFG[2];
	uint32 * TCON;
	uint32 * TCNTB;
	uint32 * TCMPB;
	uint32 * TCNTO;
	uint32 * TINT;

	void Start();
	void Stop();
	void SetAutoReload(bool AutoReload);
	void SetDivider(uint8 Divider);
	void SetPrescale(uint8 Prescale);
	void SetDuration(uint32 Duration);
	void SetCompare(uint32 Compare );
	uint32 GetCount();
	uint32 getTest();
    uint32 getCount(uint8 timerX);
};

TIMER::TIMER(uint8 TIMERx ,bool FunPWM ){
	timerX = TIMERx;
	gpio = NULL;
	if(FunPWM)
	BaseTIMER = 0xC0018000;
	hMem = S5P4418::getMapBase(BaseTIMER);
	TCFG[0] = 	S5P4418::Register(hMem, 0x00);
	TCFG[1] = 	S5P4418::Register(hMem, 0x04);
	TCON = 		S5P4418::Register(hMem, 0x08);

	switch (TIMERx)
	{
	case TIMER_0:
	case TIMER_1:
	case TIMER_2:
	case TIMER_3:
		TCNTB = S5P4418::Register(hMem, 0x0C + (uint32)(TIMERx * 0x0C));
		TCMPB = S5P4418::Register(hMem, 0x10 + (uint32)(TIMERx * 0x0C));
		TCNTO = S5P4418::Register(hMem, 0x14 + (uint32)(TIMERx * 0x0C));
		break;
	case TIMER_4:
		TCNTB = S5P4418::Register(hMem, 0x3C);
		TCNTO = S5P4418::Register(hMem, 0x40);
		break;
	}
	printf("timerX:%d\n",timerX);
	printf("offset is:%x\n",0x14 + (uint32)(TIMERx * 0x0C));

	TINT = S5P4418::Register(hMem, 0x44);

	if (FunPWM) {
		switch (TIMERx) {
			case TIMER_2:
				gpio = new GPIO(PC, 14);
				gpio->SetFun(Fun_2);
				gpio->SetDir(OUTPUT);
//					printf("gpio->Port->hMem:%X\n",gpio->Port->hMem);
				*TCON &= ~(0x1 << 13);
				*TCON |= (0x1 << 14);
				break;
		}
	}
}
uint32 TIMER::getCount(uint8 timerX)
{
    uint32 * addr = NULL;
    addr = S5P4418::Register(hMem, 0x14 + (uint32)(timerX * 0x0C));
    return *addr;
}

void TIMER::Start() {
	switch (timerX) {
		case 0:
			*TCON |= 0x1;
			break;
		case 1:
		case 2:
		case 3:
		case 4:
			*TCON |= (0x1 << (timerX * 4 + 4));
			break;
	}
}

void TIMER::Stop() {
	switch (timerX) {
		case 0:
			*TCON &= ~0x1;break;
		case 1:
		case 2:
		case 3:
		case 4:
			*TCON &= ~(0x1 << (timerX * 4 + 4));break;
	}
}

void TIMER::SetAutoReload(bool AutoReload) {
	if (AutoReload)
	{
		switch (timerX) {
			case 0: *TCON |= (0x1 << 3);break;
			case 1: *TCON |= (0x1 << 11);break;
			case 2: *TCON |= (0x1 << 15);break;
			case 3: *TCON |= (0x1 << 19);break;
			case 4: *TCON |= (0x1 << 22);break;
		}
	} else
	{
		switch (timerX) {
			case 0: *TCON &= ~(0x1 << 3);break;
			case 1: *TCON &= ~(0x1 << 11);break;
			case 2: *TCON &= ~(0x1 << 15);break;
			case 3: *TCON &= ~(0x1 << 19);break;
			case 4: *TCON &= ~(0x1 << 22);break;
		}
	}
}

void TIMER::SetDivider(uint8 Divider) {
	*TCFG[1] &= ~(0xF << (timerX * 4));
	*TCFG[1] |= (uint32(Divider & 0x7) << (timerX * 4));
}

void TIMER::SetPrescale(uint8 Prescale) {
	switch (timerX) {
		case 0:
		case 1:
			*TCFG[0] &= ~0xFF;
			*TCFG[0] |= uint32(Prescale);
			break;
		case 2:
		case 3:
		case 4:
			*TCFG[0] &= ~(0xFF << 8);
			*TCFG[0] |= uint32(Prescale << 8);
			break;
	}
}

void TIMER::SetDuration(uint32 Duration) {
	*TCNTB = Duration;
}

void TIMER::SetCompare(uint32 Compare ) {
	*TCMPB = Compare;
}

uint32 TIMER::GetCount() {
	return *TCNTO;
}

uint32 TIMER::getTest()
{
	return *TCNTO;
}

/* 毫秒级 延时 */
void Sleep(int ms)
{
    struct timeval delay;
    delay.tv_sec = 0;
    delay.tv_usec = ms * 1000; // 20 ms
    select(0, NULL, NULL, NULL, &delay);
}

int main(int argc, char **argv)
{
	S5P4418 * s5p4418 = new(S5P4418);
/*gpio例子,点亮/关闭Led
	GPIO * gpio = new GPIO(PB,12);
	gpio->SetFun(Fun_2);
	gpio->SetDir(OUTPUT);
	gpio->Flip();
	delete gpio;
*/

/*pwm例子*/
	int k = 0;
    int max = 0;
	TIMER * PWM2 = new TIMER(TIMER_2, true);
	
	PWM2->Stop();
	printf("TCON Value:%X\n",PWM2->TCON);
	printf("TCON:%X\n",*PWM2->TCON);
	PWM2->SetAutoReload(true);
	PWM2->SetDivider(3);
	PWM2->SetPrescale(0xFF);
	PWM2->SetDuration(0xffffff);
	PWM2->SetCompare(0xfffff);
	PWM2->Start();
	printf("6*PWM2->TCON:%X\n",*PWM2->TCON);
	printf("GetCount:%d\n",PWM2->GetCount());
	printf("GetCount:%d\n",PWM2->GetCount());


/*内存映射pwm遍历例子
    while(k < 5)
    {
    	for(int i = 0; i < 4; i ++)
		{
			printf("%dtimer count is:%d\n",i,PWM2->getCount(i));
		}
    	printf("\n");
    	Sleep(200);
    	k++;
    }
*/
	PWM2->Stop();
	delete PWM2;

	delete s5p4418;
    return 0;
}
 类似资料: