commit d8d032938cc526ebf5a063f7bfeb54e5e6def311 Author: User <> Date: Tue Jul 30 17:08:45 2019 +0200 Uiteindelijk project diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cd42ee3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +bin/ +obj/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ee2e388 --- /dev/null +++ b/Makefile @@ -0,0 +1,56 @@ +DTSNAME = BB-BONE-IRMUX +DTSFILE = $(DTSNAME)-00A0.dts + +LIB_PATH = . +LIBRARIES = pthread prussdrv glib-2.0 +INCLUDES = . include /usr/include/glib-2.0 /usr/lib/glib-2.0/include +OBJ_PATH = obj/ +SRC_PATH = src/ +TARGET_PATH = bin/ + +CC = $(CROSS_COMPILE)gcc +PASM = pasm + +all: directories pinmux stop rawtiming read_signal ircommander + +# Dit target is voor het automatisch instellen van debug-variabelen. +debug: + make CFLAGS=-DDEBUG PFLAGS=-DDEBUG DTSNAME=BB-BONE-IRDEBUG all + +directories: + mkdir -p $(OBJ_PATH) $(TARGET_PATH) + +authkeys: + ssh-keygen -t rsa + ssh $(SSHHOST) mkdir -p .ssh + cat ~/.ssh/id_rsa.pub | ssh $(SSHHOST) 'cat >> .ssh/authorized_keys' + +# De target (linkerhand) zou een resulterend bestand moeten zijn zodat make kan +# controleren of er opnieuw gecompileerd moet worden. +# Nu worden alles telkens gecompileerd. +pinmux: $(SRC_PATH)$(DTSFILE) + dtc -O dtb -o $(OBJ_PATH)$(DTSFILE:%.dts=%.dtbo) -b 0 -@ $(SRC_PATH)$(DTSFILE) + cp $(OBJ_PATH)$(DTSFILE:%.dts=%.dtbo) /lib/firmware + +stop: $(SRC_PATH)stop.c + $(CC) $(INCLUDES:%=-I%) $(CFLAGS) -c -o $(OBJ_PATH)$@.o $(SRC_PATH)$@.c + $(CC) $(OBJ_PATH)$@.o $(LIB_PATH:%=-L%) $(LIBRARIES:%=-l%) -o $(TARGET_PATH)$@ + +rawtiming: $(SRC_PATH)rawtiming.c $(SRC_PATH)rawtiming.p + $(PASM) $(PFLAGS) -b $(SRC_PATH)$@.p $(TARGET_PATH)$@ + $(CC) $(INCLUDES:%=-I%) $(CFLAGS) -c -o $(OBJ_PATH)$@.o $(SRC_PATH)$@.c + $(CC) $(OBJ_PATH)$@.o $(LIB_PATH:%=-L%) $(LIBRARIES:%=-l%) -o $(TARGET_PATH)$@ + +read_signal: $(SRC_PATH)read_signal.c $(SRC_PATH)read_signal.p + $(PASM) $(PFLAGS) -b $(SRC_PATH)$@.p $(TARGET_PATH)$@ + $(CC) $(INCLUDES:%=-I%) $(CFLAGS) -c -o $(OBJ_PATH)$@.o $(SRC_PATH)$@.c + $(CC) $(OBJ_PATH)$@.o $(LIB_PATH:%=-L%) $(LIBRARIES:%=-l%) -o $(TARGET_PATH)$@ + +ircommander: $(SRC_PATH)ircommander.c $(SRC_PATH)ircommander.p + $(PASM) $(PFLAGS) -b $(SRC_PATH)$@.p $(TARGET_PATH)$@ + $(CC) $(INCLUDES:%=-I%) $(CFLAGS) -c -o $(OBJ_PATH)$@.o $(SRC_PATH)$@.c + $(CC) $(OBJ_PATH)$@.o $(LIB_PATH:%=-L%) $(LIBRARIES:%=-l%) -o $(TARGET_PATH)$@ + +clean: + # verwijder de root-slash uit het pad voor het geval een gebruiker dom bezig is + rm -rf $(OBJ_PATH:/%=%) $(TARGET_PATH:/%=%) diff --git a/config/ircommander.example.conf b/config/ircommander.example.conf new file mode 100644 index 0000000..01cd362 --- /dev/null +++ b/config/ircommander.example.conf @@ -0,0 +1,37 @@ +[General] +assignNewCommands=true +repetitionTolerance=2 + +[Commands] +A00202A201A1=xdotool keydown Alt; xdotool key Tab +A00202A23616=xdotool key Right +A00202A21636=xdotool key Up +A00202A27656=xdotool key Left +A00202A25676=xdotool key Down +A00202A23191=xdotool key Return; xdotool keyup Alt +A00202A26ACA=xdotool key Alt+F3 +A00202A211B1=xdotool key Escape +A002029C2937=xdotool key Tab +A002029C4957=xdotool key Shift+Tab +A00202A22000=xdotool key Alt+Left +A00202A26040=xdotool key Alt+Right +A00202800200=xdotool key XF86AudioRaiseVolume +A00202804240=xdotool key XF86AudioLowerVolume +A00202802624=xdotool key XF86AudioMute +A00202A20020=xdotool key XF86AudioStop +A00202A23010=xdotool key XF86AudioPause +A00202A22808=xdotool key XF86AudioPlay +A00202A200A0=xdotool key Alt+F4 +A002029C041A=xdotool key 1; espeak one +A002029C445A=xdotool key 2; espeak two +A002029C243A=xdotool key 3; espeak three +A002029C647A=xdotool key 4; espeak four +A002029C140A=xdotool key 5; espeak five +A002029C544A=xdotool key 6; espeak six +A002029C342A=xdotool key 7; espeak seven +A002029C746A=xdotool key 8; espeak eight +A002029C0C12=xdotool key 9; espeak nine +A002029C4C52=xdotool key 0; espeak zero +A00202A256F6=(echo 1 > /sys/class/gpio/gpio45/value; sleep 1; echo 0 > /sys/class/gpio/gpio45/value)& +A00202A27BDB=(echo 0 > /sys/class/gpio/gpio46/value; sleep 1; echo 1 > /sys/class/gpio/gpio46/value)& + diff --git a/doc/TSOP1138.pdf b/doc/TSOP1138.pdf new file mode 100644 index 0000000..7e224b2 Binary files /dev/null and b/doc/TSOP1138.pdf differ diff --git a/doc/images/flow_diagram.png b/doc/images/flow_diagram.png new file mode 100644 index 0000000..968f19b Binary files /dev/null and b/doc/images/flow_diagram.png differ diff --git a/doc/images/tsop1138_block_diagram.png b/doc/images/tsop1138_block_diagram.png new file mode 100644 index 0000000..62b2096 Binary files /dev/null and b/doc/images/tsop1138_block_diagram.png differ diff --git a/doc/opstelling.jpg b/doc/opstelling.jpg new file mode 100644 index 0000000..ec856b3 Binary files /dev/null and b/doc/opstelling.jpg differ diff --git a/doc/rawtiming_analyse.xlsx b/doc/rawtiming_analyse.xlsx new file mode 100644 index 0000000..58f5b39 Binary files /dev/null and b/doc/rawtiming_analyse.xlsx differ diff --git a/doc/verslag.pdf b/doc/verslag.pdf new file mode 100644 index 0000000..658f696 Binary files /dev/null and b/doc/verslag.pdf differ diff --git a/doc/verslag.tex b/doc/verslag.tex new file mode 100644 index 0000000..5fd5eea --- /dev/null +++ b/doc/verslag.tex @@ -0,0 +1,87 @@ +\documentclass[twocolumn]{article} +\usepackage[utf8]{inputenc} +\usepackage[dutch]{babel} +\usepackage{enotez} +\usepackage[hidelinks]{hyperref} +\usepackage{graphicx} +\usepackage{caption} + +%Instellingen +\DeclareTranslation{Dutch}{enotez-title}{\section{Verwijzingen}} +\graphicspath{ {images/} } + +\title{Verslag IRCommander} +\author{Frank Wibbelink} +\date{\today} +\setcounter{tocdepth}{3} + +\begin{document} +\maketitle + +\begin{abstract} +\end{abstract} + +\tableofcontents + +\section{Opdracht} +Dit verslag behandelt de eindopdracht van CAO2. Het doel van de opdracht is kennismaken met microcontrollers en digitale signaalverwerking. Ik heb deze opdracht ingevuld met het uitlezen van een afstandsbediening op een \emph{BeagleBone Black} (BBB). + +\section{Achtergrond} + +\subsection{PRU} +De PRU (2 aanwezig op de BBB) is een realtimeprocessor die los van de CPU (en daarmee de kernel) draait op 200 MHz. Deze processor doet niet aan pipelining en de instructieset bestaat uit load/store, branching, bit shifts en optellen/aftrekken, waarvan de meeste 1 klokcyclus kosten om uit te voeren. Er zijn 32 registers beschikbaar (geen ingebouwde stack of window) en een tabel met veelgebruikte offsets en verder vindt alle communicatie via I\textsuperscript{2}C plaats. Dit betekent voor de PRU-code dat er specifieke geheugenadressen --uit de voorgenoemde tabel-- gebruikt moeten worden om naartoe te schrijven of van te lezen. Hoewel er een C-compiler voor de PRU door TI wordt geleverd, is het aanvankelijk handiger voor dit project om code in PASM te schrijven, om zeker te zijn van de timing.\\ +De I/O-pinnen op het bord zijn op meerdere manieren te gebruiken, waaronder GPIO --pin wordt gekoppeld aan een geheugenadres-- en rechtstreeks naar r30 (output) of r31 (input) op een van de PRU's. De modus voor een pin kan worden ingesteld met een \emph{device tree overlay}. Ik heb hier een simpele editor voor gemaakt, \emph{tools/pinselect.html}, op basis van de tabel van Derek Molloy\endnote{http://derekmolloy.ie/beaglebone/beaglebone-gpio-programming-on-arm-embedded-linux/}. + +\subsection{Device Tree} +De Flattened Device Tree\endnote{https://en.wikipedia.org/wiki/Device\_tree} is een datastructuur om onderdelen van de hardware van een computer te beschrijven. Het is bedoeld als een nieuwe abstractielaag waardoor drivers los komen te staan van de kernel, opdat er niet voor elke SoC of andere hardware een nieuwe kernel geleverd hoeft te worden.\\ +Bijkomend voordeel is dat er \emph{overlay}s --extra stukken device tree-- ingeladen kunnen worden terwijl het systeem draait. Voor de BBB betekent dit dat de I/O-pinnen die normaal voor HDMI worden ingezet, ook te gebruiken zijn voor GPIO door de overlay uit te laden en een andere in te laden. + +\subsection{Infraroodsensor} +De gebruikte infraroodsensor (\emph{TSOP1238}) bestaat hoofdzakelijk uit een 38 KHz band-pass-filter met wat componenten om basisstraling te filteren en het signaal te normaliseren. Dit wordt vervolgens aan een transistor gehangen die open gaat als het signaal hoog is. De output-pin is met een grote weerstand verbonden aan de 3,3 V en wordt geaard als de transistor geleidt (open is). Zie \emph{doc/TSOP1138.pdf} voor de datasheet van een vergelijkbare sensor.\\ +Er is voor gekozen om het signaal niet te inverteren met nog een weerstand en transistor, maar om in de PRU-code met het geïnverteerde signaal te werken. + +\begin{figure}[h] + \begin{center} + \includegraphics[width=1\columnwidth]{tsop1138_block_diagram} + \end{center} + \caption{Diagram TSOP1138} +\end{figure} + + +\subsection{Infraroodprotocol} +Infraroodprotocollen bestaan uit een digitaal signaal dat met \emph{on-off keying} op een draaggolf van ongeveer 38KHz wordt gezet. Praktisch elke fabrikant of zelfs elke productlijn heeft een eigen techniek om het digitale signaal op te bouwen. In dit geval is het protocol van een afstandsbediening van Panasonic bestudeerd.\\ +Met \emph{rawtiming} is gekeken hoe de knopcodes worden gemoduleerd. Uit analyse (zie \emph{doc/rawtiming\_analyse.xlsx}) volgt dat on-off keying op een schaal van >0,1ms gebeurt en er grofweg 3 categorieën voor zijn: kort, lang en "begin". Verder is een hoog signaal altijd kort, wat erop neerkomt dat alleen de duur van een laag signaal informatie draagt. Tot slot bestaat een pakket altijd uit 48 lage en 49 hoge signalen. Dit komt overeen met het protocol zoals beschreven in Arduino-IRremote\endnote{https://github.com/shirriff/Arduino-IRremote/blob/master/IRremote.cpp}.\\ +Met de indeling in 3 categorieën kunnen pakketten worden uitgelezen. De basis hiervoor is te zien in \emph{read\_signal}. Dit programma leest IR-pakketten en toont ze op het scherm. + +\section{Programma} + +\subsection{Compilatie} +Voor het compileren van de C-code zijn gcc, glib en make nodig. Om te cross-compileren vanaf andere architecturen is de variabele \emph{CROSS\_COMPILE=arm-arago-linux-gnueabi-} en de SDK van TI nodig.\\ +Voor de PRU-code zijn make en pasm nodig, waarvan de laatste beschikbaar is via de am335x\_pru\_package\endnote{https://github.com/beagleboard/am335x\_pru\_package/ tree/master/pru\_sw/utils/pasm\_source}. +Om de Device Tree Overlay (\emph{BB-BONE-IRMUX-00A0.dts}) te compileren is de Device Tree Compiler nodig. Het programma heeft in sommige distributies een patch nodig.\endnote{https://eewiki.net/display/linuxonarm/BeagleBone+Black\# BeagleBoneBlack-Upgradedistro\%22device-tree-compiler\%22package} + +\subsection{Werking} +Allereerst moet de device tree overlay voor de I/O-pinnen (1 pin in dit geval) en de PRU ingeladen worden. Dit wordt gedaan door "BB-BONE-IRMUX" naar \emph{/sys/devices/bone\_capemgr.*/slots} te sturen. Zie ook \emph{tools/laad\_overlay}.\\ +Hierna kan \emph{ircommander} worden opgestart. Dit programma laadt het configuratiebestand en de PRU-driver in. Vervolgens wordt het PRU-programma ingeladen en uitgevoerd. Dit programma leest continu de IR-sensor uit tot er een volledig pakket is gelezen, waarna hij het als een uint64 in de buffer zet. De buffer is een eenvoudige cyclische array van 256 elementen. Zodra de buffer is geüpdatet (of er gebleken is dat hij vol zit), verstuurt de PRU een interrupt naar de CPU.\\ +Ondertussen wacht het hoofdprogramma op interrupts van de PRU en zoekt de bijbehorende tekst voor de nieuwe pakketten in de buffer. Als er geen tekst te vinden is en de configuratie bevat \emph{assignNewCommands=true}, vraagt het programma om een nieuwe tekst in te voeren.\\ +Door als tekst een commando op te geven en de uitvoer te pipen naar de shell (of naar een shell over SSH), is de afstandsbediening te gebruiken voor het opstarten van programma's en voor mediatoetsen. Dit is te zien in \emph{config/ircommander.example.conf}, \emph{tools/ircommander\_groepscomputer} en de demovideo. + +\begin{figure}[h] + \begin{center} + \includegraphics[width=1\columnwidth]{flow_diagram} + \end{center} + \caption{Gegevensstroom in een voorbeeldopstelling (\emph{tools/ircommander\_groepscomputer})} +\end{figure} + +\section{Toekomstige verbeteringen} +Er kan op een aantal punten verbetering gebracht worden in het programma: +\begin{itemize} + \item Lopend gemiddelde: de PRU-code leest de gemiddelde waarde momenteel uit door de pin een aantal keer uit te lezen in vaste blokken. Door ruis (vooral bij zonlicht) lezen kleine blokken wel eens de verkeerde waarde uit, terwijl grote blokken geen signalen kunnen herkennen als de afstandsbediening het signaal verandert halverwege een blok. Met een lopend gemiddelde kan het exacte moment worden bepaald waarop de sensor van hoog naar laag wisselt en vice versa. Als alternatief kan natuurlijk ook een analoog circuit worden gebouwd. + \item Meerdere modi: het C-programma staat nu één commando per knopcode toe. Door knoppen (of commando's op de standaardinvoer) toe te wijzen aan het wisselen van de modus, kan een knop meerdere resultaten geven. Hoewel deze functie ook kan worden vervuld door het programma waar naar gepiped wordt, leidt dit tot onduidelijke commando's in de huidige opzet, waarin gepiped wordt naar bash. + \item Het omzetten van knopcodes naar commando's outsourcen: het stateless knopcodes omzetten naar tekst kan ook met \emph{sed} uitgevoerd worden. Hierdoor wordt het programma compacter en de afhankelijkheid van glib vervalt. Om het bovenstaande punt ook te verwerken, is \emph{sed} alleen niet voldoende. +\end{itemize} + +\printendnotes + +\end{document} + diff --git a/include/pruss_intc_mapping.h b/include/pruss_intc_mapping.h new file mode 100644 index 0000000..29afffc --- /dev/null +++ b/include/pruss_intc_mapping.h @@ -0,0 +1,104 @@ +/* + * pruss_intc_mapping.h + * + * Example PRUSS INTC mapping for the application + * + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * +*/ + +/* + * ============================================================================ + * Copyright (c) Texas Instruments Inc 2010-11 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ +*/ + +#define AM33XX +#ifdef AM33XX +#define PRU0_PRU1_INTERRUPT 17 +#define PRU1_PRU0_INTERRUPT 18 +#define PRU0_ARM_INTERRUPT 19 +#define PRU1_ARM_INTERRUPT 20 +#define ARM_PRU0_INTERRUPT 21 +#define ARM_PRU1_INTERRUPT 22 +#else +#define PRU0_PRU1_INTERRUPT 32 +#define PRU1_PRU0_INTERRUPT 33 +#define PRU0_ARM_INTERRUPT 34 +#define PRU1_ARM_INTERRUPT 35 +#define ARM_PRU0_INTERRUPT 36 +#define ARM_PRU1_INTERRUPT 37 +#endif +#define CHANNEL0 0 +#define CHANNEL1 1 +#define CHANNEL2 2 +#define CHANNEL3 3 +#define CHANNEL4 4 +#define CHANNEL5 5 +#define CHANNEL6 6 +#define CHANNEL7 7 +#define CHANNEL8 8 +#define CHANNEL9 9 + +#define PRU0 0 +#define PRU1 1 +#define PRU_EVTOUT0 2 +#define PRU_EVTOUT1 3 +#define PRU_EVTOUT2 4 +#define PRU_EVTOUT3 5 +#define PRU_EVTOUT4 6 +#define PRU_EVTOUT5 7 +#define PRU_EVTOUT6 8 +#define PRU_EVTOUT7 9 + +#define PRU0_HOSTEN_MASK 0x0001 +#define PRU1_HOSTEN_MASK 0x0002 +#define PRU_EVTOUT0_HOSTEN_MASK 0x0004 +#define PRU_EVTOUT1_HOSTEN_MASK 0x0008 +#define PRU_EVTOUT2_HOSTEN_MASK 0x0010 +#define PRU_EVTOUT3_HOSTEN_MASK 0x0020 +#define PRU_EVTOUT4_HOSTEN_MASK 0x0040 +#define PRU_EVTOUT5_HOSTEN_MASK 0x0080 +#define PRU_EVTOUT6_HOSTEN_MASK 0x0100 +#define PRU_EVTOUT7_HOSTEN_MASK 0x0200 + + +#define PRUSS_INTC_INITDATA { \ +{ PRU0_PRU1_INTERRUPT, PRU1_PRU0_INTERRUPT, PRU0_ARM_INTERRUPT, PRU1_ARM_INTERRUPT, ARM_PRU0_INTERRUPT, ARM_PRU1_INTERRUPT, (char)-1 }, \ +{ {PRU0_PRU1_INTERRUPT,CHANNEL1}, {PRU1_PRU0_INTERRUPT, CHANNEL0}, {PRU0_ARM_INTERRUPT,CHANNEL2}, {PRU1_ARM_INTERRUPT, CHANNEL3}, {ARM_PRU0_INTERRUPT, CHANNEL0}, {ARM_PRU1_INTERRUPT, CHANNEL1}, {-1,-1}}, \ + { {CHANNEL0,PRU0}, {CHANNEL1, PRU1}, {CHANNEL2, PRU_EVTOUT0}, {CHANNEL3, PRU_EVTOUT1}, {-1,-1} }, \ + (PRU0_HOSTEN_MASK | PRU1_HOSTEN_MASK | PRU_EVTOUT0_HOSTEN_MASK | PRU_EVTOUT1_HOSTEN_MASK) /*Enable PRU0, PRU1, PRU_EVTOUT0 */ \ +} \ + diff --git a/include/prussdrv.h b/include/prussdrv.h new file mode 100644 index 0000000..c99f4e1 --- /dev/null +++ b/include/prussdrv.h @@ -0,0 +1,203 @@ +/* + * prussdrv.h + * + * Describes PRUSS userspace driver for Industrial Communications + * + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * +*/ + +/* + * ============================================================================ + * Copyright (c) Texas Instruments Inc 2010-11 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ +*/ + +#ifndef _PRUSSDRV_H +#define _PRUSSDRV_H + +#include + +#if defined (__cplusplus) +extern "C" { +#endif + +#define NUM_PRU_HOSTIRQS 8 +#define NUM_PRU_HOSTS 10 +#define NUM_PRU_CHANNELS 10 +#define NUM_PRU_SYS_EVTS 64 + +#define PRUSS0_PRU0_DATARAM 0 +#define PRUSS0_PRU1_DATARAM 1 +#define PRUSS0_PRU0_IRAM 2 +#define PRUSS0_PRU1_IRAM 3 + +#define PRUSS_V1 1 // AM18XX +#define PRUSS_V2 2 // AM33XX + +//Available in AM33xx series - begin +#define PRUSS0_SHARED_DATARAM 4 +#define PRUSS0_CFG 5 +#define PRUSS0_UART 6 +#define PRUSS0_IEP 7 +#define PRUSS0_ECAP 8 +#define PRUSS0_MII_RT 9 +#define PRUSS0_MDIO 10 +//Available in AM33xx series - end + +#define PRU_EVTOUT_0 0 +#define PRU_EVTOUT_1 1 +#define PRU_EVTOUT_2 2 +#define PRU_EVTOUT_3 3 +#define PRU_EVTOUT_4 4 +#define PRU_EVTOUT_5 5 +#define PRU_EVTOUT_6 6 +#define PRU_EVTOUT_7 7 + + typedef struct __sysevt_to_channel_map { + short sysevt; + short channel; + } tsysevt_to_channel_map; + typedef struct __channel_to_host_map { + short channel; + short host; + } tchannel_to_host_map; + typedef struct __pruss_intc_initdata { + //Enabled SYSEVTs - Range:0..63 + //{-1} indicates end of list + char sysevts_enabled[NUM_PRU_SYS_EVTS]; + //SysEvt to Channel map. SYSEVTs - Range:0..63 Channels -Range: 0..9 + //{-1, -1} indicates end of list + tsysevt_to_channel_map sysevt_to_channel_map[NUM_PRU_SYS_EVTS]; + //Channel to Host map.Channels -Range: 0..9 HOSTs - Range:0..9 + //{-1, -1} indicates end of list + tchannel_to_host_map channel_to_host_map[NUM_PRU_CHANNELS]; + //10-bit mask - Enable Host0-Host9 {Host0/1:PRU0/1, Host2..9 : PRUEVT_OUT0..7} + unsigned int host_enable_bitmask; + } tpruss_intc_initdata; + + int prussdrv_init(void); + + int prussdrv_open(unsigned int host_interrupt); + + /** Return version of PRU. This must be called after prussdrv_open. */ + int prussdrv_version(); + + /** Return string description of PRU version. */ + const char* prussdrv_strversion(int version); + + int prussdrv_pru_reset(unsigned int prunum); + + int prussdrv_pru_disable(unsigned int prunum); + + int prussdrv_pru_enable(unsigned int prunum); + int prussdrv_pru_enable_at(unsigned int prunum, size_t addr); + + int prussdrv_pru_write_memory(unsigned int pru_ram_id, + unsigned int wordoffset, + const unsigned int *memarea, + unsigned int bytelength); + + int prussdrv_pruintc_init(const tpruss_intc_initdata *prussintc_init_data); + + /** Find and return the channel a specified event is mapped to. + * Note that this only searches for the first channel mapped and will not + * detect error cases where an event is mapped erroneously to multiple + * channels. + * @return channel-number to which a system event is mapped. + * @return -1 for no mapping found + */ + short prussdrv_get_event_to_channel_map( unsigned int eventnum ); + + /** Find and return the host interrupt line a specified channel is mapped + * to. Note that this only searches for the first host interrupt line + * mapped and will not detect error cases where a channel is mapped + * erroneously to multiple host interrupt lines. + * @return host-interrupt-line to which a channel is mapped. + * @return -1 for no mapping found + */ + short prussdrv_get_channel_to_host_map( unsigned int channel ); + + /** Find and return the host interrupt line a specified event is mapped + * to. This first finds the intermediate channel and then the host. + * @return host-interrupt-line to which a system event is mapped. + * @return -1 for no mapping found + */ + short prussdrv_get_event_to_host_map( unsigned int eventnum ); + + int prussdrv_map_l3mem(void **address); + + int prussdrv_map_extmem(void **address); + + unsigned int prussdrv_extmem_size(void); + + int prussdrv_map_prumem(unsigned int pru_ram_id, void **address); + + int prussdrv_map_peripheral_io(unsigned int per_id, void **address); + + unsigned int prussdrv_get_phys_addr(const void *address); + + void *prussdrv_get_virt_addr(unsigned int phyaddr); + + /** Wait for the specified host interrupt. + * @return the number of times the event has happened. */ + unsigned int prussdrv_pru_wait_event(unsigned int host_interrupt); + + int prussdrv_pru_event_fd(unsigned int host_interrupt); + + int prussdrv_pru_send_event(unsigned int eventnum); + + /** Clear the specified event and re-enable the host interrupt. */ + int prussdrv_pru_clear_event(unsigned int host_interrupt, + unsigned int sysevent); + + int prussdrv_pru_send_wait_clear_event(unsigned int send_eventnum, + unsigned int host_interrupt, + unsigned int ack_eventnum); + + int prussdrv_exit(void); + + int prussdrv_exec_program(int prunum, const char *filename); + int prussdrv_exec_program_at(int prunum, const char *filename, size_t addr); + + int prussdrv_exec_code(int prunum, const unsigned int *code, int codelen); + int prussdrv_exec_code_at(int prunum, const unsigned int *code, int codelen, size_t addr); + int prussdrv_load_data(int prunum, const unsigned int *code, int codelen); + int prussdrv_load_datafile(int prunum, const char *filename); + +#if defined (__cplusplus) +} +#endif +#endif diff --git a/src/BB-BONE-IRDEBUG-00A0.dts b/src/BB-BONE-IRDEBUG-00A0.dts new file mode 100644 index 0000000..e1ce525 --- /dev/null +++ b/src/BB-BONE-IRDEBUG-00A0.dts @@ -0,0 +1,45 @@ +/dts-v1/; +/plugin/; +/ { + compatible = "ti,beaglebone", "ti,beaglebone-black"; + /* identification */ + part-number = "BB-BONE-IRDEBUG"; + version = "00A0"; + exclusive-use = + /* the physical pins used: */ + "P8.11", + "P8.12", + "P8.15", + "P8.16", + + /* Activate both PRUs */ + "pru0"; + + /* fragment 0: the pin muxes */ + fragment@0 { + target = <&am33xx_pinmux>; + __overlay__ { + pru_pins: pinmux_pru_pins { + pinctrl-single,pins = < + 0x034 0x7 + 0x030 0x6 + 0x03c 0x26 + 0x038 0x7 + >; + }; + }; + }; + + /* fragment 2: enable PRU and assign the pins */ + fragment@2 { + target = <&pruss>; + __overlay__ { + /* enable pru subsytem - equivalent to 'modprobe uio_pruss' */ + status = "okay"; + + pinctrl-names = "default"; + /* assign pins to the subsystem */ + pinctrl-0 = <&pru_pins>; + }; + }; +}; \ No newline at end of file diff --git a/src/BB-BONE-IRMUX-00A0.dts b/src/BB-BONE-IRMUX-00A0.dts new file mode 100644 index 0000000..19e2021 --- /dev/null +++ b/src/BB-BONE-IRMUX-00A0.dts @@ -0,0 +1,39 @@ +/dts-v1/; +/plugin/; +/ { + compatible = "ti,beaglebone", "ti,beaglebone-black"; + /* identification */ + part-number = "BB-BONE-IRMUX"; + version = "00A0"; + exclusive-use = + /* the physical pins used: */ + "P8.15", + + /* Activate both PRUs */ + "pru0"; + + /* fragment 0: the pin muxes */ + fragment@0 { + target = <&am33xx_pinmux>; + __overlay__ { + pru_pins: pinmux_pru_pins { + pinctrl-single,pins = < + 0x03c 0x26 + >; + }; + }; + }; + + /* fragment 2: enable PRU and assign the pins */ + fragment@2 { + target = <&pruss>; + __overlay__ { + /* enable pru subsytem - equivalent to 'modprobe uio_pruss' */ + status = "okay"; + + pinctrl-names = "default"; + /* assign pins to the subsystem */ + pinctrl-0 = <&pru_pins>; + }; + }; +}; \ No newline at end of file diff --git a/src/_ircommander.c b/src/_ircommander.c new file mode 100644 index 0000000..994139d --- /dev/null +++ b/src/_ircommander.c @@ -0,0 +1,171 @@ +/** + * ircommander.c + * + * Dit programma leest de IR-signalen van panasonic-afstandsbedieningen + * en voert de bijbehorende commando's uit zoals opgegeven in + * config/ircommander.conf + * + * Het programma beschouwt het PRU-geheugen als een grote + * uint64-array met de lengte op index 0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __DEBUG +#define DEBUG_PRINTF(FORMAT, ...) fprintf(stderr, FORMAT, ## __VA_ARGS__) +#else +#define DEBUG_PRINTF(FORMAT, ...) +#endif + +tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; +GKeyFile *keyfile; +GKeyFileFlags flags = G_KEY_FILE_NONE; +GError *error; +int programming_mode = 0; + +struct option options[] = { + {"help" , no_argument, 0, 'h'}, + {"program", no_argument, 0, 'p'}, + {"config" , required_argument, 0, 'c'} +}; + +void poll(void *addr) { + unsigned int index = 0, repetition = 0; + unsigned int *length = addr; + unsigned long long *array = (unsigned long long*)(length+1); + + unsigned long long keycode, previous_keycode; + char keycode_string[20]; + char *command; + size_t command_length = 200; + char *newline_address; + + while (1) { + // Wacht op een interrupt van de PRU + prussdrv_pru_wait_event (PRU_EVTOUT_0); + prussdrv_pru_clear_event (PRU_EVTOUT_0, PRU0_ARM_INTERRUPT); + + // Lees alle nieuwe commando's + for (; index < *length; ++index) { + keycode = array[index & ((1<<8)-1)]; + sprintf(keycode_string, "%llX", keycode); + + // Vergeef de gebruiker die de knop iets te lang indrukt + if (keycode == previous_keycode) { + if (++repetition <= 2) + continue; + } + else { + previous_keycode = keycode; + repetition = 0; + } + + DEBUG_PRINTF(stderr, "Nieuwe keycode %s.\n", keycode_string); + + if (!g_key_file_has_key(keyfile, "Commands", keycode_string, NULL) && programming_mode) { + fprintf(stderr, "Voer het commando voor %s in:\n", keycode_string); + command = g_malloc(command_length); + + fprintf(stderr, "keycode_string r %d is %s \n", __LINE__, keycode_string); + if (getline(&command, &command_length, stdin) != -1) { + fprintf(stderr, "keycode_string r %d is %s \n", __LINE__, keycode_string); + // Haal de newline uit het commando + if (newline_address = strchr(command, '\n')) + *newline_address = '\0'; + + fprintf(stderr, "keycode_string r %d is %s \n", __LINE__, keycode_string); + fprintf(stderr, "g_key_file_set_string(keyfile, \"Commands\", \"%s\", \"%s\");\n", keycode_string, command); + g_key_file_set_string(keyfile, "Commands", keycode_string, command); + fprintf(stderr, "g_key_file_save_to_file(keyfile, \"../config/ircommander.conf\", NULL);\n"); + g_key_file_save_to_file(keyfile, "../config/ircommander.conf", NULL); + } + g_free(command); + } + + if (g_key_file_has_key(keyfile, "Commands", keycode_string, NULL)) { + command = g_key_file_get_string(keyfile, "Commands", keycode_string, NULL); + printf("%s\n", command); + fflush(stdout); // het programma wil niet flushen ondanks de newline + DEBUG_PRINTF(stderr, "Commando \"%s\" verstuurd.\n", command); + g_free(command); + } + } + } +} + +int main(int argc, char *argv[]) +{ + switch (getopt_long(argc, argv, "hpc:", options, NULL)) { + case 'h': + printf("ircommander [-h | --help] [-p | --program] [-cfile | --config file]\n"); + printf("-h display this help\n"); + printf("-p bind commands to new keys\n"); + printf("-c file select a different config file [not implemented]\n"); + return 0; + break; + + case 'p': + programming_mode = 1; + fprintf(stderr, "Programma geopend voor nieuwe toetsencombinaties\n"); + break; + } + + void *prumem_address; +/* + // Koppel het programma los van de sessie d.m.v. een fork + pid_t pid = fork(); + + if (pid < 0) + exit(EXIT_FAILURE); + + if (pid > 0) { + printf("Module gestart met pid %d", pid); + exit(EXIT_SUCCESS); + } + + if (setsid() < 0) + exit(EXIT_FAILURE); +*/ + + keyfile = g_key_file_new(); + if (!g_key_file_load_from_file(keyfile, "../config/ircommander.conf", flags, &error)) { + fprintf(stderr, error->message); + } + + prussdrv_init(); + + // Open de PRU zonder speciale interrupts en laad de mmap + if (prussdrv_open(PRU_EVTOUT_0)) + { + fprintf(stderr, "prussdrv_open open failed\n"); + return 1; + } + + // Start de interrupt controller + prussdrv_pruintc_init(&pruss_intc_initdata); + + // Maak een koppeling met het geheugen van de PRU + prussdrv_map_prumem(PRUSS0_PRU0_DATARAM, &prumem_address); + + // Zet de lengte van de array expliciet op 0 + ((unsigned int*)prumem_address)[0] = 0; + + // Zet het PRU-programma aan + prussdrv_exec_program(PRU0, "./ircommander.bin"); + + // Start het pollen van het PRU-geheugen + poll(prumem_address); + + // Zet de PRU uit en stop de driver + prussdrv_pru_disable(PRU0); + prussdrv_exit(); + + return 0; +} diff --git a/src/_rawtiming.p b/src/_rawtiming.p new file mode 100644 index 0000000..a60ec80 --- /dev/null +++ b/src/_rawtiming.p @@ -0,0 +1,55 @@ +.origin 0 +.entrypoint START + +#include "stddef.hp" +#define P8_11 r30.t15 +#define P8_12 r30.t14 +#define P8_15 r31.t15 +#define P8_16 r31.t14 + +// counter: +#define counter r1 +#define length r2 +#define last r3 +#define temp r4 +#define output r30 +#define input r31 + +IIC: + // Activeer de I2C-bus + LBCO r0, CONST_PRUCFG, 4, 4 + CLR r0, r0, 4 + SBCO r0, CONST_PRUCFG, 4, 4 + +START: + ZERO &r0, 4*11 // Leeg registers 0 t/m 10 + ZERO &output, 4 + MOV last, input + + // Zet een 0 in de array + ADD length, length, 1 + LSL temp, length, 2 + SBCO r0, CONST_PRUDRAM, temp, 4 + SBCO length, CONST_PRUDRAM, 0, 4 + + +REPEAT: + XOR temp, input, last //5 ns + MOV last, input //10 ns + QBBS CHANGED, temp.t15 //15 ns + UNCHANGED: + ADD counter, counter, 25 //20 ns + QBA REPEAT //25 ns + CHANGED: + ADD length, length, 1 //20 ns + LSL temp, length, 2 //25 ns + QBBS HIGH, P8_15 //30 ns + LOW: //35 ns + QBA ENDIF + HIGH: + SET counter.t30 + ENDIF: + SBCO counter, CONST_PRUDRAM, temp, 4 //45 ns + SBCO length, CONST_PRUDRAM, 0, 4 //55 ns + LDI counter, 65 //60 ns + QBA REPEAT //65 ns diff --git a/src/ircommander.c b/src/ircommander.c new file mode 100644 index 0000000..f1ec501 --- /dev/null +++ b/src/ircommander.c @@ -0,0 +1,165 @@ +/** + * ircommander.c + * + * Dit programma leest de IR-signalen van panasonic-afstandsbedieningen + * en zet de bijbehorende tekst op de standaarduitvoer zoals opgegeven in + * config/ircommander.conf + * + * ircommander.conf bevat ook de instelling voor het live toevoegen + * van commando's en de tolerantie voor het lang indrukken van een knop + * + * Het programma beschouwt het PRU-geheugen als een uint64-vector + * van 256 elementen voorafgegaan door een uint32 voor de lengte. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#define DEBUG_PRINTF(FORMAT, ...) fprintf(stderr, FORMAT, ## __VA_ARGS__) +#else +#define DEBUG_PRINTF(FORMAT, ...) +#endif + +// Flexibele arrays (C99) zijn nodig om de buffer(-code) simpel te houden +typedef struct _SimpleBuffer { + unsigned int write_pos; + unsigned int read_pos; + unsigned long long array[]; +} SimpleBuffer; + +void poll(GKeyFile *keyfile, int tolerance, bool edit_mode, SimpleBuffer *buffer); +bool assign_command(GKeyFile *keyfile, char *keycode_string); +bool check_repetition(const unsigned long long keycode, const int tolerance); + +int main() { + tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; + GKeyFile *keyfile = g_key_file_new(); + GKeyFileFlags flags = G_KEY_FILE_NONE; + GError *error; + bool edit_mode; + int repetition_tolerance; + SimpleBuffer *buffer; + + // Laad het configuratiebestand in + if (!g_key_file_load_from_file(keyfile, "../config/ircommander.conf", flags, &error)) + fprintf(stderr, error->message); + + edit_mode = g_key_file_get_boolean(keyfile, "General", "assignNewCommands", NULL); + repetition_tolerance = g_key_file_get_integer(keyfile, "General", "repetitionTolerance", NULL); + + prussdrv_init(); + + // Open de PRU zonder speciale interrupts en laad de mmap + if (prussdrv_open(PRU_EVTOUT_0)) + { + fprintf(stderr, "prussdrv_open open failed\n"); + return 1; + } + + // Start de interrupt controller + prussdrv_pruintc_init(&pruss_intc_initdata); + + // Maak een koppeling met het geheugen van de PRU + prussdrv_map_prumem(PRUSS0_PRU0_DATARAM, (void**)(&buffer)); + + // Zet de indices op 0 + buffer->write_pos = 0; + buffer->read_pos = 0; + + // Zet het PRU-programma aan + prussdrv_exec_program(PRU0, "./ircommander.bin"); + + // Start het pollen van het PRU-geheugen + poll(keyfile, repetition_tolerance, edit_mode, buffer); + + // Zet de PRU uit en stop de driver + prussdrv_pru_disable(PRU0); + prussdrv_exit(); + + return 0; +} + +void poll(GKeyFile *keyfile, int tolerance, bool edit_mode, SimpleBuffer *buffer) { + unsigned long long keycode; + char keycode_string[20]; + char *command; + + while (1) { + // Wacht op een interrupt van de PRU + prussdrv_pru_wait_event(PRU_EVTOUT_0); + prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT); + + // Lees alle nieuwe commando's + while(buffer->read_pos != buffer->write_pos) { + buffer->read_pos = (buffer->read_pos+1) & ((1<<8)-1); + keycode = buffer->array[buffer->read_pos]; + sprintf(keycode_string, "%llX", keycode); + + // Vergeef de gebruiker die de knop iets te lang indrukt + if (!check_repetition(keycode, tolerance)) + continue; + + DEBUG_PRINTF("Nieuwe keycode %s.\n", keycode_string); + + if (!g_key_file_has_key(keyfile, "Commands", keycode_string, NULL) && edit_mode) + assign_command(keyfile, keycode_string); + + if (g_key_file_has_key(keyfile, "Commands", keycode_string, NULL)) { + command = g_key_file_get_string(keyfile, "Commands", keycode_string, NULL); + + // Voer het commando uit en forceer het flushen van de uitvoer + printf("%s\n", command); + fflush(stdout); + + DEBUG_PRINTF("Commando \"%s\" verstuurd.\n", command); + g_free(command); + } + } + + DEBUG_PRINTF("read_pos: %d, write_pos: %d, adressen: %X, %X, %X\n", buffer->read_pos, buffer->write_pos, &(buffer->read_pos), &(buffer->write_pos), buffer->array); + } +} + +bool assign_command(GKeyFile *keyfile, char *keycode_string) { + char *new_command = NULL; + char *newline_address; + size_t command_length; + + fprintf(stderr, "Voer het commando voor %s in:\n", keycode_string); + + if (getline(&new_command, &command_length, stdin) != -1) { + // Haal de newline uit het commando + if (newline_address = strchr(new_command, '\n')) + *newline_address = '\0'; + + // Voeg het commando to aan de database en sla deze direct op + DEBUG_PRINTF("\"[Commands] %s = %s\" ingevoerd.\n", keycode_string, new_command); + g_key_file_set_string(keyfile, "Commands", keycode_string, new_command); + g_key_file_save_to_file(keyfile, "../config/ircommander.conf", NULL); + + free(new_command); + } +} + +bool check_repetition(const unsigned long long keycode, const int tolerance) { + static unsigned int repetition = 0; + static unsigned long long previous_keycode; + + if (keycode == previous_keycode) { + if (++repetition <= tolerance) + return false; + } + else { + previous_keycode = keycode; + repetition = 0; + } + return true; +} diff --git a/src/ircommander.hp b/src/ircommander.hp new file mode 100644 index 0000000..78b3cf3 --- /dev/null +++ b/src/ircommander.hp @@ -0,0 +1,65 @@ +#define P8_11 r30.t15 +#define P8_12 r30.t14 +#define P8_15 15 +#define P8_16 14 + +#define shortcnt r1 +#define total r2 +#define timer r3 +#define previous r4 +#define current r5 +#define nextbit r6 +#define lowbits r7 +#define highbits r8 +#define temp r10 +#define write_pos r11 +#define read_pos r12 +#define offset r13 +#define output r30 +#define input r31 + +// Lengte van de cyclus in 2^n om een gemiddelde uitslag te bepalen +#define shortcycle 3 + +.macro INC +.mparam target, amount=1 + ADD target, target, amount +.endm + +.macro ISHI +.mparam target, source, bit + LSR target, source, bit + AND target, target, 1 +.endm + +#ifdef DEBUG + .macro add_bit + .mparam value + SET P8_11 + MOV temp, value + QBEQ P8OFF, temp, 1 + CLR P8_11 + P8OFF: + QBNE _ENDIF, nextbit, 32 + CLR P8_12 + MOV highbits, lowbits + ZERO &lowbits, 4 + _ENDIF: + + LSL lowbits, lowbits, 1 + INC lowbits, value + INC nextbit + .endm +#else + .macro add_bit + .mparam value + QBNE _ENDIF, nextbit, 16 + MOV highbits, lowbits + ZERO &lowbits, 4 + _ENDIF: + + LSL lowbits, lowbits, 1 + INC lowbits, value + INC nextbit + .endm +#endif diff --git a/src/ircommander.p b/src/ircommander.p new file mode 100644 index 0000000..09cc85e --- /dev/null +++ b/src/ircommander.p @@ -0,0 +1,103 @@ +.setcallreg r0.w0 +.origin 0 +.entrypoint START + +#include "stddef.hp" +#include "ircommander.hp" + +START: + IIC: + // Activeer de I2C-bus + LBCO temp, CONST_PRUCFG, 4, 4 + CLR temp, temp, 4 + SBCO temp, CONST_PRUCFG, 4, 4 + + ZERO &r0, 4*16 // Leeg registers 0 t/m 15 + ISHI previous, input, P8_15 + + + SHORTLOOP: //duur: 5*(5*2^shortcycle) ns + INC shortcnt + ISHI temp, input, P8_15 + INC total, temp + QBGT SHORTLOOP, shortcnt, 1< +#include +#include +#include +#include + +tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; + +void poll(unsigned int *addr) { + int offset = 1; + int debugprint = 0; + + while (1) { + //Controleer of er nieuwe data klaar staat + //en zet het op het scherm + for (; offset <= addr[0]; ++offset) + printf("%d: %u, ", offset, addr[offset]); + + //Print elke halve seconde wat debuginformatie + if (++debugprint > 500) { + debugprint = 0; + printf("length: %u, ", addr[0]); + } + + usleep(1000); + } +} + +int main (void) +{ + unsigned int *prumem_address; + + prussdrv_init(); + + //Open de PRU zonder uitgaande events en laad de mmaps + if (prussdrv_open(PRU_EVTOUT_0)) + { + printf("prussdrv_open open failed\n"); + return 1; + } + + //Start de interrupt controller + prussdrv_pruintc_init(&pruss_intc_initdata); + + //Maak een koppeling met het geheugen van de PRU + prussdrv_map_prumem(PRUSS0_PRU0_DATARAM, (void**)&prumem_address); + + //Zet de lengte van de array expliciet op 0 + prumem_address[0] = 0; + + //Zet het PRU-programma aan + prussdrv_exec_program(PRU0, "./rawtiming.bin"); + + //Start het pollen van het PRU-geheugen + poll(prumem_address); + + //Zet de PRU uit en stop de driver + prussdrv_pru_disable(PRU0); + prussdrv_exit(); + + return 0; +} diff --git a/src/rawtiming.p b/src/rawtiming.p new file mode 100644 index 0000000..c55ff7d --- /dev/null +++ b/src/rawtiming.p @@ -0,0 +1,87 @@ +.origin 0 +.entrypoint START + +#include "stddef.hp" +#define P8_11 r30.t15 +#define P8_12 r30.t14 +#define P8_15 15 +#define P8_16 14 + +#define shortcnt r1 +#define timer r2 +#define length r3 +#define previous r4 +#define current r5 +#define total r6 +#define temp r10 +#define output r30 +#define input r31 + +// Lengte van de cyclus in 2^n om een gemiddelde uitslag te bepalen +#define shortcycle 3 + +.macro INC +.mparam target, amount=1 + ADD target, target, amount +.endm + +.macro ISHI +.mparam target, source, bit + LSR target, source, bit + AND target, target, 1 +.endm + +IIC: + // Activeer de I2C-bus + LBCO r0, CONST_PRUCFG, 4, 4 + CLR r0, r0, 4 + SBCO r0, CONST_PRUCFG, 4, 4 + +START: + ZERO &r0, 4*11 // Leeg registers 0 t/m 10 + ISHI previous, input, P8_15 + + // Zet een 0 in de array + INC length + LSL temp, length, 2 + SBCO r0, CONST_PRUDRAM, temp, 4 + SBCO length, CONST_PRUDRAM, 0, 4 + + +SHORTLOOP: //duur: 5*(5*2^shortcycle) ns + INC shortcnt + ISHI temp, input, P8_15 + INC total, temp + QBGT SHORTLOOP, shortcnt, 1< +#include +#include +#include +#include + +tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; + +void poll(void *addr) { + unsigned int index = 0; + unsigned int *length = addr; + unsigned long long *array = (unsigned long long*)(length+1); + + while (1) { + //Controleer of er nieuwe data klaar staat + //en zet het op het scherm + for (; index < *length; ++index) + printf("%u: %llX\n", index, array[index & ((1<<8)-1)]); + + usleep(1000); + } +} + +int main (void) +{ + void *prumem_address; + + prussdrv_init(); + + //Open de PRU zonder uitgaande events en laad de mmaps + if (prussdrv_open(PRU_EVTOUT_0)) + { + printf("prussdrv_open open failed\n"); + return 1; + } + + //Start de interrupt controller + prussdrv_pruintc_init(&pruss_intc_initdata); + + //Maak een koppeling met het geheugen van de PRU + prussdrv_map_prumem(PRUSS0_PRU0_DATARAM, &prumem_address); + + //Zet de lengte van de array expliciet op 0 + ((unsigned int*)prumem_address)[0] = 0; + + //Zet het PRU-programma aan + prussdrv_exec_program(PRU0, "./read_signal.bin"); + + //Start het pollen van het PRU-geheugen + poll(prumem_address); + + //Zet de PRU uit en stop de driver + prussdrv_pru_disable(PRU0); + prussdrv_exit(); + + return 0; +} diff --git a/src/read_signal.hp b/src/read_signal.hp new file mode 100644 index 0000000..119ca72 --- /dev/null +++ b/src/read_signal.hp @@ -0,0 +1,64 @@ +#define P8_11 r30.t15 +#define P8_12 r30.t14 +#define P8_15 15 +#define P8_16 14 + +#define shortcnt r1 +#define total r2 +#define timer r3 +#define previous r4 +#define current r5 +#define nextbit r6 +#define lowbits r7 +#define highbits r8 +#define temp r10 +#define length r11 +#define offset r12 +#define output r30 +#define input r31 + +// Lengte van de cyclus in 2^n om een gemiddelde uitslag te bepalen +#define shortcycle 3 + +.macro INC +.mparam target, amount=1 + ADD target, target, amount +.endm + +.macro ISHI +.mparam target, source, bit + LSR target, source, bit + AND target, target, 1 +.endm + +#ifdef DEBUG + .macro add_bit + .mparam value + SET P8_11 + MOV temp, value + QBEQ P8OFF, temp, 1 + CLR P8_11 + P8OFF: + QBNE _ENDIF, nextbit, 32 + CLR P8_12 + MOV highbits, lowbits + ZERO &lowbits, 4 + _ENDIF: + + LSL lowbits, lowbits, 1 + INC lowbits, value + INC nextbit + .endm +#else + .macro add_bit + .mparam value + QBNE _ENDIF, nextbit, 16 + MOV highbits, lowbits + ZERO &lowbits, 4 + _ENDIF: + + LSL lowbits, lowbits, 1 + INC lowbits, value + INC nextbit + .endm +#endif diff --git a/src/read_signal.p b/src/read_signal.p new file mode 100644 index 0000000..faa55f4 --- /dev/null +++ b/src/read_signal.p @@ -0,0 +1,88 @@ +.setcallreg r0.w0 +.origin 0 +.entrypoint START + +#include "stddef.hp" +#include "read_signal.hp" + +START: + IIC: + // Activeer de I2C-bus + LBCO temp, CONST_PRUCFG, 4, 4 + CLR temp, temp, 4 + SBCO temp, CONST_PRUCFG, 4, 4 + + ZERO &r0, 4*16 // Leeg registers 0 t/m 15 + ISHI previous, input, P8_15 + + + SHORTLOOP: //duur: 5*(5*2^shortcycle) ns + INC shortcnt + ISHI temp, input, P8_15 + INC total, temp + QBGT SHORTLOOP, shortcnt, 1< +#include +#include +#include + +tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; + +int main (void) +{ + prussdrv_init(); + + //Open de PRU zonder uitgaande events en laad de mmaps + if (prussdrv_open(PRU_EVTOUT_0)) + { + printf("prussdrv_open open failed\n"); + return 1; + } + + //Start de interrupt controller + prussdrv_pruintc_init(&pruss_intc_initdata); + + //Schakel mogelijke interrupts uit + prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT); + + //Zet de PRU uit en stop de driver + prussdrv_pru_disable(PRU0); + prussdrv_exit(); + + return(0); +} diff --git a/tools/ircommander_lokaal b/tools/ircommander_lokaal new file mode 100644 index 0000000..05242b7 --- /dev/null +++ b/tools/ircommander_lokaal @@ -0,0 +1,3 @@ +#!/bin/sh +cd ../bin/ +./ircommander | $SHELL diff --git a/tools/laad_overlay b/tools/laad_overlay new file mode 100644 index 0000000..a03d32c --- /dev/null +++ b/tools/laad_overlay @@ -0,0 +1,12 @@ +# Het pad bevat een asterisk omdat het getal afhankelijk is van de boot- +# volgorde van het systeem. +SLOTS=`ls /sys/devices/bone_capemgr.*/slots` +DTSNAME="BB-BONE-IRMUX" + +# De overlay kan maar een keer geladen worden, omdat de tweede keer de +# geheugenadressen in de driver niet meer kloppen. +if cat $SLOTS | grep $DTSNAME &>/dev/null; then + echo "$DTSNAME is al geladen." +else + echo $DTSNAME > $SLOTS +fi