1
0
mirror of https://github.com/danog/fast-gpio.git synced 2024-11-26 20:04:37 +01:00

Initial commit of fast-gpio, gpio read and write is implemented, pwm implemented as well

This commit is contained in:
greenbreakfast 2015-09-12 16:51:25 +08:00
parent 81222cb01f
commit 9d3d06ced7
9 changed files with 536 additions and 0 deletions

3
common_commands.txt Normal file
View File

@ -0,0 +1,3 @@
rm -rf fast-gpio ; wget http://119.9.75.206:8080/fast-gpio ; chmod +x fast-gpio
ubus call expled set '{"red":0,"green":0,"blue":0}'

34
include/fastgpio.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef _FAST_GPIO_H_
#define _FAST_GPIO_H_
#include <module.h>
#define REGISTER_BLOCK_ADDR 0x18040000
#define REGISTER_BLOCK_SIZE 0x30
#define REGISTER_OE_OFFSET 0
#define REGISTER_IN_OFFSET 1
#define REGISTER_OUT_OFFSET 2
#define REGISTER_SET_OFFSET 3
#define REGISTER_CLEAR_OFFSET 4
class FastGpio : public Module {
public:
FastGpio(void);
~FastGpio(void);
int SetDirection (int pinNum, int bOutput);
int Set (int pinNum, int value);
int Read (int pinNum, int &value);
private:
// private functions
int pinNumber;
};
#endif // _FAST_GPIO_H_

46
include/fastpwm.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef _FAST_PWM_H_
#define _FAST_PWM_H_
#include <module.h>
#include <fastgpio.h>
#include <unistd.h>
#define DEFAULT_FREQ 200
#define DEFAULT_DUTY_CYCLE 50
class FastPwm : public Module {
public:
FastPwm(void);
FastPwm(int freq, int duty);
~FastPwm(void);
void Reset (void);
void Pwm (int pinNum);
void Pwm (int pinNum, int freq, int duty);
private:
// private functions
void _SetupPeriods (int frequency, int duty);
void _Sleep (double length);
void _Pwm (int pinNum);
// private members
FastGpio gpio;
int bSetup;
double freq;
double dutyCycle;
double period;
double periodLow;
double periodHigh;
};
#endif // _FAST_PWM_H_

42
include/module.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef _MODULE_H_
#define _MODULE_H_
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
class Module {
public:
Module(void);
~Module(void);
void SetVerbosity (int input);
void SetVerbosity (bool input);
void SetDebugMode (int input);
void SetDebugMode (bool input);
protected:
// protected functions
int _SetupAddress (unsigned long int blockBaseAddr, unsigned long int blockSize);
void _WriteReg (unsigned long int registerOffset, unsigned long int value);
unsigned long int _ReadReg (unsigned long int registerOffset);
void _SetBit (unsigned long int &regVal, int bitNum, int value);
// protected members
int verbosityLevel;
int debugLevel;
volatile unsigned long int *regAddress;
};
#endif // _MODULE_H_

42
makefile Normal file
View File

@ -0,0 +1,42 @@
# This is the main compiler
CXX := g++
# CXX := clang --analyze # and comment out the linker last line for sanity
SRCDIR := src
INCDIR := include
BUILDDIR := build
BINDIR := bin
TARGET := $(BINDIR)/fast-gpio
SRCEXT := cpp
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
CXXFLAGS := -g # -Wall
#LIB := -pthread -lmongoclient -L lib -lboost_thread-mt -lboost_filesystem-mt -lboost_system-mt
INC := $(shell find $(INCDIR) -maxdepth 1 -type d -exec echo -I {} \;)
$(TARGET): $(OBJECTS)
@mkdir -p $(BINDIR)
@echo " Linking..."
@echo " $(CXX) $^ -o $(TARGET) $(LIB)"; $(CXX) $^ -o $(TARGET) $(LIB)
$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
@mkdir -p $(dir $@)
@echo " $(CXX) $(CXXFLAGS) $(INC) -c -o $@ $<"; $(CXX) $(CXXFLAGS) $(INC) -c -o $@ $<
clean:
@echo " Cleaning...";
@echo " $(RM) -r $(BUILDDIR) $(BINDIR)"; $(RM) -r $(BUILDDIR) $(BINDIR)
bla:
@echo "$(BLA)"
# Tests
tester:
$(CXX) $(CXXFLAGS) test/tester.cpp $(INC) $(LIB) -o bin/tester
# Spikes
#ticket:
# $(CXX) $(CXXFLAGS) spikes/ticket.cpp $(INC) $(LIB) -o bin/ticket
.PHONY: clean

72
src/fastgpio.cpp Normal file
View File

@ -0,0 +1,72 @@
#include <fastgpio.h>
FastGpio::FastGpio(void)
{
// setup the memory address space
_SetupAddress(REGISTER_BLOCK_ADDR, REGISTER_BLOCK_SIZE);
}
FastGpio::~FastGpio(void)
{
// nothing for now
}
// public functions
int FastGpio::SetDirection(int pinNum, int bOutput)
{
unsigned long int regVal;
// read the current input and output settings
regVal = _ReadReg(REGISTER_OE_OFFSET);
if (verbosityLevel > 0) printf("Direction setting read: 0x%08lx\n", regVal);
// set the OE for this pin
_SetBit(regVal, pinNum, bOutput);
if (verbosityLevel > 0) printf("Direction setting write: 0x%08lx\n", regVal);
// write the new register value
_WriteReg(REGISTER_OE_OFFSET, regVal);
return (EXIT_SUCCESS);
}
int FastGpio::Set(int pinNum, int value)
{
unsigned long int regAddr;
unsigned long int regVal;
if (value == 0 ) {
// write to the clear register
regAddr = REGISTER_CLEAR_OFFSET;
}
else {
// write to the set register
regAddr = REGISTER_SET_OFFSET;
}
// put the desired pin value into the register
regVal = (0x1 << pinNum);
// write to the register
_WriteReg (regAddr, regVal);
return EXIT_SUCCESS;
}
int FastGpio::Read(int pinNum, int &value)
{
unsigned long int regVal;
// read the current value of all pins
regVal = _ReadReg (REGISTER_IN_OFFSET);
// find the value of the specified pin
value = ((regVal >> pinNum) & 0x1);
return EXIT_SUCCESS;
}

99
src/fastpwm.cpp Normal file
View File

@ -0,0 +1,99 @@
#include <fastpwm.h>
FastPwm::FastPwm(void)
{
Reset();
}
FastPwm::FastPwm(int freq, int duty)
{
Reset();
// setup the pwm info
_SetupPeriods(freq, duty);
}
FastPwm::~FastPwm(void)
{
// nothing for now
}
void FastPwm::Reset(void)
{
bSetup = 0;
}
void FastPwm::_SetupPeriods(int frequency, int duty)
{
double dutyCycleInv;
// convert the datatypes
freq = (double) frequency;
dutyCycle = (double)duty / 100.0f;
// find the period (in ms)
period = (1.0f/freq) * 1000;
// find the low and high periods based on the duty-cycle
periodHigh = period * dutyCycle;
periodLow = period - periodHigh; //can also be: period * (1.0f - dutyCycle);
// note that setup has occured
bSetup = 1;
if (verbosityLevel > 0) {
printf ( "PWM Setup:: frequency = %d, duty-cycle = %d%%\nperiod = %.2f, period hi = %.2f, period lo = %.2f\n",
frequency,
duty,
period,
periodHigh,
periodLow
);
}
}
void FastPwm::Pwm (int pinNum)
{
if (bSetup == 0) {
_SetupPeriods(DEFAULT_FREQ, DEFAULT_DUTY_CYCLE);
}
// run the pwm
_Pwm(pinNum);
}
void FastPwm::Pwm (int pinNum, int freq, int duty)
{
_SetupPeriods(freq, duty);
// run the pwm
_Pwm(pinNum);
}
void FastPwm::_Pwm (int pinNum)
{
// set the pin to output
gpio.SetDirection(pinNum, 1);
// start the loop
while (1) {
//// HIGH part of cycle
gpio.Set(pinNum, 1);
_Sleep(periodHigh);
// LOW part of cycle
if (dutyCycle <= 0.95f) {
gpio.Set(pinNum, 0);
_Sleep(periodLow);
}
}
}
void FastPwm::_Sleep (double length)
{
// sleep function uses microseconds
int value = (int)(length * 1000);
usleep(value);
}

97
src/main.cpp Normal file
View File

@ -0,0 +1,97 @@
#include <stdlib.h>
#include <cstdio>
#include <cstring>
#include <fastgpio.h>
#include <fastpwm.h>
int main(int argc, char* argv[])
{
int status = 0;
int cmd = -1;
int pinNum;
int value;
int freq, duty;
FastGpio gpioObj;
FastPwm pwmObj;
int verbosity = 1;
int debugLevel = 0;
// object setup
gpioObj.SetVerbosity(verbosity);
gpioObj.SetDebugMode(debugLevel);
pwmObj.SetVerbosity(verbosity);
pwmObj.SetDebugMode(debugLevel);
if ( argc != 3 &&
argc != 4 &&
argc != 5
)
{
printf("Usage:\n");
printf("\t%s read <gpio>\n", argv[0]);
printf("\t%s set <gpio> <value>\n", argv[0]);
printf("\t%s pwm <gpio> <freq> <duty>\n", argv[0]);
return EXIT_SUCCESS;
}
// parse the command line arguments
// arg1 - command: read, set
// arg2 - gpio pin number
// arg3 - value to write in case of set
if (verbosity > 0) printf("Parsing arguments:\n");
if (strcmp(argv[1], "set") == 0 ) {
cmd = 0;
// get the write value
value = atoi(argv[3]);
}
else if (strcmp(argv[1], "read") == 0 ) {
cmd = 1;
}
else if (strcmp(argv[1], "pwm") == 0 ) {
cmd = 2;
// get the freq and duty values
freq = atoi(argv[3]);
duty = atoi(argv[4]);
}
else {
return EXIT_FAILURE;
}
// get the pin number
pinNum = atoi(argv[2]);
// object operations
switch (cmd) {
case 0:
if (verbosity > 0) printf("Setting GPIO%d to %d\n", pinNum, value);
gpioObj.SetDirection(pinNum, 1); // set to output
gpioObj.Set(pinNum, value);
break;
case 1:
gpioObj.Read(pinNum, value);
if (verbosity > 0) printf("Read GPIO%d: %d\n", pinNum, value);
break;
case 2:
pwmObj.Pwm(pinNum, freq, duty);
default:
break;
}
return 0;
}

101
src/module.cpp Normal file
View File

@ -0,0 +1,101 @@
#include <module.h>
Module::Module(void)
{
// not verbose by default
verbosityLevel = 0;
// not in debug mode by default
debugLevel = 0;
}
Module::~Module(void)
{
// nothing for now
}
// Debug Functions
void Module::SetVerbosity (int input)
{
verbosityLevel = input;
}
void Module::SetVerbosity (bool input)
{
verbosityLevel = (input ? 1 : 0);
}
void Module::SetDebugMode (int input)
{
debugLevel = input;
}
void Module::SetDebugMode (bool input)
{
debugLevel = (input ? 1 : 0);
}
// Register access
int Module::_SetupAddress(unsigned long int blockBaseAddr, unsigned long int blockSize)
{
int m_mfd;
if (debugLevel == 0)
{
if ((m_mfd = open("/dev/mem", O_RDWR)) < 0)
{
return EXIT_FAILURE; // maybe return -1
}
regAddress = (unsigned long*)mmap ( NULL,
blockSize,
PROT_READ|PROT_WRITE,
MAP_SHARED,
m_mfd,
blockBaseAddr
);
close(m_mfd);
if (regAddress == MAP_FAILED)
{
return EXIT_FAILURE; // maybe return -2
}
}
return EXIT_SUCCESS; // regAddress is now populated
}
void Module::_WriteReg(unsigned long int registerOffset, unsigned long int value)
{
if (verbosityLevel > 0) printf("Writing register 0x%08lx with data 0x%08lx \n", (regAddress + registerOffset), value);
*(regAddress + registerOffset) = value;
}
unsigned long int Module::_ReadReg(unsigned long int registerOffset)
{
unsigned long int value = 0x0;
// read the value
value = *(regAddress + registerOffset);
if (verbosityLevel > 0) printf("Read register 0x%08lx, data: 0x%08lx \n", (regAddress + registerOffset), value);
return(value);
}
// change the value of a single bit
void Module::_SetBit(unsigned long int &regVal, int bitNum, int value)
{
if (value == 1) {
regVal |= (1 << bitNum);
}
else {
regVal &= ~(1 << bitNum);
}
// try this out
// regVal ^= (-value ^ regVal) & (1 << bitNum);
}