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