From 9d3d06ced7e651428df06f19003d0b85b3b28628 Mon Sep 17 00:00:00 2001 From: greenbreakfast Date: Sat, 12 Sep 2015 16:51:25 +0800 Subject: [PATCH] Initial commit of fast-gpio, gpio read and write is implemented, pwm implemented as well --- common_commands.txt | 3 ++ include/fastgpio.h | 34 +++++++++++++++ include/fastpwm.h | 46 ++++++++++++++++++++ include/module.h | 42 ++++++++++++++++++ makefile | 42 ++++++++++++++++++ src/fastgpio.cpp | 72 +++++++++++++++++++++++++++++++ src/fastpwm.cpp | 99 +++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 97 ++++++++++++++++++++++++++++++++++++++++++ src/module.cpp | 101 ++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 536 insertions(+) create mode 100644 common_commands.txt create mode 100644 include/fastgpio.h create mode 100644 include/fastpwm.h create mode 100644 include/module.h create mode 100644 makefile create mode 100644 src/fastgpio.cpp create mode 100644 src/fastpwm.cpp create mode 100644 src/main.cpp create mode 100644 src/module.cpp diff --git a/common_commands.txt b/common_commands.txt new file mode 100644 index 0000000..8f29291 --- /dev/null +++ b/common_commands.txt @@ -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}' \ No newline at end of file diff --git a/include/fastgpio.h b/include/fastgpio.h new file mode 100644 index 0000000..cb29ed3 --- /dev/null +++ b/include/fastgpio.h @@ -0,0 +1,34 @@ +#ifndef _FAST_GPIO_H_ +#define _FAST_GPIO_H_ + +#include + + +#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_ \ No newline at end of file diff --git a/include/fastpwm.h b/include/fastpwm.h new file mode 100644 index 0000000..9c3a460 --- /dev/null +++ b/include/fastpwm.h @@ -0,0 +1,46 @@ +#ifndef _FAST_PWM_H_ +#define _FAST_PWM_H_ + +#include +#include + +#include + + +#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_ \ No newline at end of file diff --git a/include/module.h b/include/module.h new file mode 100644 index 0000000..ae7d6b8 --- /dev/null +++ b/include/module.h @@ -0,0 +1,42 @@ +#ifndef _MODULE_H_ +#define _MODULE_H_ + +#include +#include +#include +#include +#include +#include +#include + + + + + +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_ \ No newline at end of file diff --git a/makefile b/makefile new file mode 100644 index 0000000..bf6ea10 --- /dev/null +++ b/makefile @@ -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 diff --git a/src/fastgpio.cpp b/src/fastgpio.cpp new file mode 100644 index 0000000..d31a699 --- /dev/null +++ b/src/fastgpio.cpp @@ -0,0 +1,72 @@ +#include + +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; +} + + diff --git a/src/fastpwm.cpp b/src/fastpwm.cpp new file mode 100644 index 0000000..32c5b75 --- /dev/null +++ b/src/fastpwm.cpp @@ -0,0 +1,99 @@ +#include + +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); +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..83e1b2e --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,97 @@ +#include +#include +#include + +#include +#include + + + +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 \n", argv[0]); + printf("\t%s set \n", argv[0]); + printf("\t%s pwm \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; +} \ No newline at end of file diff --git a/src/module.cpp b/src/module.cpp new file mode 100644 index 0000000..a651553 --- /dev/null +++ b/src/module.cpp @@ -0,0 +1,101 @@ +#include + +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); +}