说明:本文代码由本人编写,可以作为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;
}