mirror of
https://github.com/danog/fast-gpio.git
synced 2024-11-30 04:19:09 +01:00
Initial commit of fast-gpio, gpio read and write is implemented, pwm implemented as well
This commit is contained in:
parent
81222cb01f
commit
9d3d06ced7
3
common_commands.txt
Normal file
3
common_commands.txt
Normal 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
34
include/fastgpio.h
Normal 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
46
include/fastpwm.h
Normal 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
42
include/module.h
Normal 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 ®Val, int bitNum, int value);
|
||||||
|
|
||||||
|
// protected members
|
||||||
|
int verbosityLevel;
|
||||||
|
int debugLevel;
|
||||||
|
|
||||||
|
volatile unsigned long int *regAddress;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _MODULE_H_
|
42
makefile
Normal file
42
makefile
Normal 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
72
src/fastgpio.cpp
Normal 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
99
src/fastpwm.cpp
Normal 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
97
src/main.cpp
Normal 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
101
src/module.cpp
Normal 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 ®Val, int bitNum, int value)
|
||||||
|
{
|
||||||
|
if (value == 1) {
|
||||||
|
regVal |= (1 << bitNum);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
regVal &= ~(1 << bitNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
// try this out
|
||||||
|
// regVal ^= (-value ^ regVal) & (1 << bitNum);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user