diff --git a/api/maa.h b/api/maa.h index 824841e..f5ef581 100644 --- a/api/maa.h +++ b/api/maa.h @@ -27,6 +27,7 @@ #include "i2c.h" #include "i2cslave.h" #include "gpio.h" +#include "pwm.h" #define MAA_LIBRARY_VERSION 1 diff --git a/api/pwm.h b/api/pwm.h new file mode 100644 index 0000000..d57fc7a --- /dev/null +++ b/api/pwm.h @@ -0,0 +1,139 @@ +/* + * Author: Thomas Ingleby + * + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#include +#include + +namespace maa { + +/** A PWM object, used for interacting with PWM output. + * + * Example: + * @code + * // Set up PWM object then cycle percentage 0-100. + * + * #include "maa.h" + * + * PWM pwm(3); + * + * int main() { + * pwm.period_us(7968750i); //Max Galileo Rev D + * pwm.enable(1); + * + * float value = 0; + * while(1) { + * pwm.write(value); + * sleep(0.5); + * if(value == 1.0) { + * value = 0; + * } else { + * value = value +0.1; + * } + * } + * } + * @endcode + */ +class PWM { + +private: + int chipid, pin; + FILE *duty_fp; + + void write_period(int period); + void write_duty(int duty); + int setup_duty_fp(); + int get_period(); + int get_duty(); + +public: + + /** Create an PWM object + * + * @param chipid The chip in which the following pin is on. + * @param pin The PWM channel to operate on + */ + PWM(int chipid, int pin); + + /** Set the ouput duty-cycle percentage, as a float + * + * @param percentage A floating-point value representing percentage of output. + * The value should lie between 0.0f (representing on 0%) and 1.0f + * Values above or below this range will be set at either 0.0f or 1.0f. + */ + void write(float percentage); + + /** Read the ouput duty-cycle percentage, as a float + * + * @return percentage A floating-point value representing percentage of output. + * The value should lie between 0.0f (representing on 0%) and 1.0f + * Values above or below this range will be set at either 0.0f or 1.0f. + */ + float read(); + + /** Set the PWM period as seconds represented in a float + * + * @param seconds Peroid represented as a float in seconds. + */ + void period(float seconds); + + /** Set period. milli-oseconds. + * @param ms milli-seconds for period. + */ + void period_ms(int ms); + + /** Set period. microseconds + * @param ns microseconds as period. + */ + void period_us(int us); + + /** Set pulsewidth, As represnted by seconds in a (float). + * @param seconds The duration of a pulse + */ + void pulsewidth(float seconds); + + /** Set pulsewidth. Milliseconds + * @param ms milliseconds for pulsewidth. + */ + void pulsewidth_ms(int ms); + + /** Set pulsewidth, microseconds. + * @param us microseconds for pulsewidth. + */ + void pulsewidth_us(int us); + + /** Set the enable status of the PWM pin. None zero will assume on with output being driven. + * and 0 will disable the output. + * @param enable enable status of pin + */ + void enable(int enable); + + /** Close and unexport the PWM pin. + */ + void close(); + +}; +} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index a0db23a..430c18e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,7 +1,9 @@ add_executable (readi2c readi2c.cpp) add_executable (hellomaa hellomaa.cpp) +add_executable (cycle-pwm3 cycle-pwm3.cpp) include_directories(${PROJECT_SOURCE_DIR}/api ${PROJECT_SOURCE_DIR}/include) target_link_libraries (hellomaa maa) target_link_libraries (readi2c maa) +target_link_libraries (cycle-pwm3 maa) diff --git a/examples/cycle-pwm3.cpp b/examples/cycle-pwm3.cpp new file mode 100644 index 0000000..a24dce9 --- /dev/null +++ b/examples/cycle-pwm3.cpp @@ -0,0 +1,24 @@ +#include + +#include "maa.h" + +int +main () +{ + maa::PWM pwm(0, 3); + pwm.period_us(200); + pwm.enable(1); + + float value = 0.0f; + + while(1) { + value = value + 0.01f; + pwm.write(value); + usleep(50000); + if (value >= 1.0f) { + value = 0.0f; + } + float output = pwm.read(); + } + return 0; +} diff --git a/examples/python/cycle-pwm3.py b/examples/python/cycle-pwm3.py new file mode 100644 index 0000000..e5f7a3b --- /dev/null +++ b/examples/python/cycle-pwm3.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 + +import pymaa as maa +import time + +x = maa.PWM(0,3) +x.enable(1); +x.period_us(20) +value= 0.0 + +while True: + x.write(value) + time.sleep(0.2) + value = value +0.01 + if value >= 1: + value = 0.0 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f2babf1..c77b504 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,6 +9,7 @@ set (maa_LIB_SRCS ${PROJECT_SOURCE_DIR}/src/i2c/i2cslave.cxx ${PROJECT_SOURCE_DIR}/src/i2c/smbus.c ${PROJECT_SOURCE_DIR}/src/gpio/gpio.c + ${PROJECT_SOURCE_DIR}/src/pwm/pwm.cxx ) add_library (maa STATIC ${maa_LIB_SRCS}) diff --git a/src/pwm/pwm.cxx b/src/pwm/pwm.cxx new file mode 100644 index 0000000..bd1fecd --- /dev/null +++ b/src/pwm/pwm.cxx @@ -0,0 +1,205 @@ +/* + * Author: Thomas Ingleby + * + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "pwm.h" + +using namespace maa; + +PWM::PWM(int chipin, int pinin) +{ + chipid = chipin; + pin = pinin; + + FILE *export_f; + char buffer[64]; + snprintf(buffer, 64, "/sys/class/pwm/pwmchip%d/export", chipid); + + if((export_f = fopen(buffer, "w")) == NULL) { + fprintf(stderr, "Failed to open export for writing!\n"); + } else { + fprintf(export_f, "%d", pin); + fclose(export_f); + setup_duty_fp(); + } +} + +void +PWM::write(float percentage) +{ + write_duty(percentage*get_period()); +} + +float +PWM::read() +{ + float output = get_duty() / (float) get_period(); + return output; +} + +void +PWM::period(float seconds) +{ + period_ms(seconds*1000); +} + +void +PWM::period_ms(int ms) +{ + period_us(ms*1000); +} + +void +PWM::period_us(int us) +{ + write_period(us*1000); +} + +void +PWM::pulsewidth(float seconds) +{ + pulsewidth_ms(seconds*1000); +} + +void +PWM::pulsewidth_ms(int ms) +{ + pulsewidth_us(ms*1000); +} + +void +PWM::pulsewidth_us(int us) +{ + write_duty(us*1000); +} + +void +PWM::enable(int enable) +{ + int status; + if(enable != 0) { + status = 1; + } else { + status = enable; + } + FILE *enable_f; + char bu[64]; + sprintf(bu, "/sys/class/pwm/pwmchip%d/pwm%d/enable", chipid, pin); + + if((enable_f = fopen(bu, "w")) == NULL) { + fprintf(stderr, "Failed to open export for writing!\n"); + } else { + fprintf(enable_f, "%d", status); + fclose(enable_f); + } + //Do Something +} + +void +PWM::close() +{ + enable(0); + FILE *unexport_f; + char buffer[64]; + snprintf(buffer, 64, "/sys/class/pwm/pwmchip%d/unexport", chipid); + + if((unexport_f = fopen(buffer, "w")) == NULL) { + fprintf(stderr, "Failed to open unexport for writing!\n"); + } else { + fprintf(unexport_f, "%d", pin); + fclose(unexport_f); + } +} + +void +PWM::write_period(int period) +{ + FILE *period_f; + char bu[64]; + sprintf(bu, "/sys/class/pwm/pwmchip%d/pwm%d/period", chipid, pin); + + if((period_f = fopen(bu, "r+b")) == NULL) { + fprintf(stderr, "Failed to open period for writing!\n"); + } else { + fprintf(period_f, "%d", period); + fclose(period_f); + } +} + +void +PWM::write_duty(int duty) +{ + if(duty_fp == NULL) { + setup_duty_fp(); + } + fprintf(duty_fp, "%d", duty); + rewind(duty_fp); + fflush(duty_fp); +} + +int +PWM::setup_duty_fp() +{ + char bu[64]; + sprintf(bu, "/sys/class/pwm/pwmchip%d/pwm%d/duty_cycle", chipid, pin); + + if((duty_fp = fopen(bu, "r+b")) == NULL) { + return 1; + } else { + return 0; + } + return 1; +} + +int +PWM::get_period() +{ + FILE *period_f; + char bu[64]; + char output[16]; + + sprintf(bu, "/sys/class/pwm/pwmchip%d/pwm%d/period", chipid, pin); + if((period_f = fopen(bu, "rb")) == NULL) { + fprintf(stderr, "Failed to open period for reading!\n"); + return 0; + } else { + fgets(output, 16, period_f); + fclose(period_f); + return atoi(output); + } +} + +int +PWM::get_duty() +{ + if(duty_fp == NULL) { + setup_duty_fp(); + } + char output[16]; + fgets(output, 16, duty_fp); + fseek(duty_fp, SEEK_SET, 0); + return atoi(output); +}