Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/omega2-pwm.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2017-07-22 00:50:41 +0300
committerAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2017-07-22 00:50:41 +0300
commit78af5ffc16e291845098b5386c6b45d4b4c52efd (patch)
tree6b1fb31be3d6d3a0d16ce5cf2fc5c13dc412ac47
parent0bed6cf4d559fdb87d497028a9672b8e2beda3d0 (diff)
First commit
-rw-r--r--Makefile18
-rw-r--r--pwm.c177
2 files changed, 195 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a157cee
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,18 @@
+TARGET = pwm
+OBJ = pwm.o
+
+#export STAGING_DIR = ~/openwrt/staging_dir
+#TOOLCHAIN_DIR = $(STAGING_DIR)/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2
+#LDCFLAGS = -L$(TOOLCHAIN_DIR)/usr/lib
+#LD_LIBRARY_PATH = $(TOOLCHAIN_DIR)/usr/lib
+
+CC = mipsel-openwrt-linux-gcc
+
+all: $(TARGET)
+
+$(TARGET): $(OBJ)
+ . ./env
+ $(CC) $(LCDFLAGS) -o $@ $^
+
+clean:
+ rm -f $(TARGET) *~ \#*\# *.o
diff --git a/pwm.c b/pwm.c
new file mode 100644
index 0000000..63e0fff
--- /dev/null
+++ b/pwm.c
@@ -0,0 +1,177 @@
+/*
+ * pwm.c: Simple program control hardware PWM on Omega2
+ *
+ * Copyright (C) 2017, Alexey 'Cluster' Avdyukhin (clusterrr@clusterrr.com)
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <inttypes.h>
+
+#define printerr(fmt,...) do { fprintf(stderr, fmt, ## __VA_ARGS__); fflush(stderr); } while(0)
+
+#define PWM_ENABLE 0x10005000 // PWM Enable register
+#define PWM0_CON 0x10005010 // PWM0 Control register
+#define PWM0_HDURATION 0x10005014 // PWM0 High Duration register
+#define PWM0_LDURATION 0x10005018 // PWM0 Low Duration register
+#define PWM0_GDURATION 0x1000501C // PWM0 Guard Duration register
+#define PWM0_SEND_DATA0 0x10005030 // PWM0 Send Data0 register
+#define PWM0_SEND_DATA1 0x10005034 // PWM0 Send Data1 register
+#define PWM0_WAVE_NUM 0x10005038 // PWM0 Wave Number register
+#define PWM0_DATA_WIDTH 0x1000503C // PWM0 Data Width register
+#define PWM0_THRESH 0x10005040 // PWM0 Thresh register
+#define PWM0_SEND_WAVENUM 0x10005044 // PWM0 Send Wave Number register
+
+uint32_t devmem(uint32_t target, uint8_t size, uint8_t write, uint32_t value)
+{
+ int fd;
+ void *map_base, *virt_addr;
+ uint32_t pagesize = (unsigned)getpagesize(); /* or sysconf(_SC_PAGESIZE) */
+ uint32_t map_size = pagesize;
+ uint32_t offset;
+ uint32_t result;
+
+ offset = (unsigned int)(target & (pagesize-1));
+ if (offset + size > pagesize ) {
+ // Access straddles page boundary: add another page:
+ map_size += pagesize;
+ }
+
+ fd = open("/dev/mem", O_RDWR | O_SYNC);
+ if (fd == -1) {
+ printerr("Error opening /dev/mem (%d) : %s\n", errno, strerror(errno));
+ exit(1);
+ }
+
+ map_base = mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd,
+ target & ~((typeof(target))pagesize-1));
+ if (map_base == (void *) -1) {
+ printerr("Error mapping (%d) : %s\n", errno, strerror(errno));
+ exit(1);
+ }
+
+ virt_addr = map_base + offset;
+
+ if (write)
+ {
+ switch (size) {
+ case 1:
+ *((volatile uint8_t *) virt_addr) = value;
+ break;
+ case 2:
+ *((volatile uint16_t *) virt_addr) = value;
+ break;
+ case 4:
+ *((volatile uint32_t *) virt_addr) = value;
+ break;
+ }
+ }
+
+ switch (size) {
+ case 1:
+ result = *((volatile uint8_t *) virt_addr);
+ break;
+ case 2:
+ result = *((volatile uint16_t *) virt_addr);
+ break;
+ case 4:
+ result = *((volatile uint32_t *) virt_addr);
+ break;
+ }
+
+ if (munmap(map_base, map_size) != 0) {
+ printerr("ERROR munmap (%d) %s\n", errno, strerror(errno));
+ exit(1);
+ }
+ close(fd);
+
+ return result;
+}
+
+static void usage(const char *cmd)
+{
+ fprintf(stderr,
+ "\nUsage:\t%s pwm <channel> <frequency> <duty>\n",
+ "\nUsage:\t%s melody <channel> <frequency> <duration_ms> [<frequency> <duration_ms> [<frequency> <duration_ms> ...]]\n",
+ "\n",
+ cmd, cmd);
+}
+
+static void pwm(uint8_t channel, uint32_t freq, uint8_t duty)
+{
+ uint32_t enable = devmem(PWM_ENABLE, 4, 0, 0);
+
+ enable &= ~((uint32_t)(1<<channel));
+ devmem(PWM_ENABLE, 4, 1, enable);
+
+ // Need to disable PWM?
+ if (!freq)
+ return;
+
+ uint32_t reg_offset = 0x40 * channel;
+
+ uint32_t duration = 100000 / freq;
+ uint32_t duration0 = duration * duty / 100;
+ uint32_t duration1 = duration * (100-duty) / 100;
+
+ devmem(PWM0_CON + reg_offset, 4, 1, 0x7000);
+ devmem(PWM0_HDURATION + reg_offset, 4, 1, duration1-1);
+ devmem(PWM0_LDURATION + reg_offset, 4, 1, duration0-1);
+ devmem(PWM0_GDURATION + reg_offset, 4, 1, duration / 2 - 1);
+ devmem(PWM0_SEND_DATA0 + reg_offset, 4, 1, 0x55555555);
+ devmem(PWM0_SEND_DATA1 + reg_offset, 4, 1, 0x55555555);
+ devmem(PWM0_WAVE_NUM + reg_offset, 4, 1, 0);
+
+ enable |= 1<<channel;
+ devmem(PWM_ENABLE, 4, 1, enable);
+}
+
+int main(int argc, char **argv)
+{
+ const char *progname = argv[0];
+ if (argc < 3)
+ {
+ usage(progname);
+ exit(2);
+ }
+
+ uint8_t channel;
+ uint32_t freq;
+ uint8_t duty = 50;
+
+ if (sscanf(argv[1], "%d", &channel) != 1)
+ {
+ fprintf(stderr, "Invalid number\n");
+ exit(1);
+ }
+
+ if (sscanf(argv[2], "%d", &freq) != 1)
+ {
+ fprintf(stderr, "Invalid number\n");
+ exit(1);
+ }
+
+ if (argc >= 4)
+ {
+ if (sscanf(argv[3], "%d", &duty) != 1)
+ {
+ fprintf(stderr, "Invalid number\n");
+ exit(1);
+ }
+ }
+
+ pwm(channel, freq, duty);
+
+ return 0;
+}