Uiteindelijk project

This commit is contained in:
User 2019-07-30 17:08:45 +02:00
commit d8d032938c
28 changed files with 1645 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
bin/
obj/

56
Makefile Normal file
View File

@ -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:/%=%)

View File

@ -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)&

BIN
doc/TSOP1138.pdf Normal file

Binary file not shown.

BIN
doc/images/flow_diagram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

BIN
doc/opstelling.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

BIN
doc/rawtiming_analyse.xlsx Normal file

Binary file not shown.

BIN
doc/verslag.pdf Normal file

Binary file not shown.

87
doc/verslag.tex Normal file
View File

@ -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}

View File

@ -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 */ \
} \

203
include/prussdrv.h Normal file
View File

@ -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 <sys/types.h>
#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

View File

@ -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>;
};
};
};

View File

@ -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>;
};
};
};

171
src/_ircommander.c Normal file
View File

@ -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 <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include <prussdrv.h>
#include <pruss_intc_mapping.h>
#include <getopt.h>
#include <glib.h>
#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;
}

55
src/_rawtiming.p Normal file
View File

@ -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

165
src/ircommander.c Normal file
View File

@ -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 <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <stdbool.h>
#include <prussdrv.h>
#include <pruss_intc_mapping.h>
#include <glib.h>
#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;
}

65
src/ircommander.hp Normal file
View File

@ -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

103
src/ircommander.p Normal file
View File

@ -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<<shortcycle
CHECKVALUE: //duur: 5*(5*2^shortcycle+6) ns
ZERO &shortcnt, 4
INC timer, 5*(5*(1<<shortcycle)+6)
LSR current, total, (shortcycle-1)
ZERO &total, 4
MIN current, current, 1 //de maximale waarde voor total leidt tot current=10b i.p.v. current=1b
QBEQ SHORTLOOP, current, previous
//duur: niet meer relevant op deze schaal, dus deze code tellen we niet mee
NEWVALUE:
MOV previous, current
MOV temp, 1500000
QBGT ENDIF1, timer, temp
CALL STARTSIGNAL
ENDIF1:
MOV temp, 1000000
QBGT ENDIF2, timer, temp
CALL LONGSIGNAL
ENDIF2:
MOV temp, 1000000
QBLE ENDIF3, timer, temp
CALL SHORTSIGNAL
ENDIF3:
ZERO &timer, 4
QBA SHORTLOOP
STARTSIGNAL:
// Voor debugging:
CLR P8_12
ZERO &lowbits, 8
ZERO &nextbit, 4
RET
SHORTSIGNAL:
QBEQ ENDIF4, current, 0
QBGT ENDIF5, nextbit, 48
// Hoog, kort signaal en 48 bits ontvangen: pakket klaar
// Voor debugging:
SET P8_12
LBCO write_pos, CONST_PRUDRAM, 0, 4
LBCO read_pos, CONST_PRUDRAM, 4, 4
INC write_pos
AND write_pos, write_pos, (1<<8)-1
// Kijk of de buffer vol zit
QBEQ ENDIF6, read_pos, write_pos
LSL offset, write_pos, 3
INC offset, 8
SBCO lowbits, CONST_PRUDRAM, offset, 8
SBCO write_pos, CONST_PRUDRAM, 0, 4
ENDIF6:
// Interrupt naar de CPU (ongeacht de status van de buffer)
MOV R31.b0, PRU0_ARM_INTERRUPT+16
ZERO &nextbit, 4
ENDIF5:
// Hoog, kort signaal: doe niets
RET
ENDIF4:
// Laag, kort signaal: 0 wegschrijven
add_bit 0
RET
LONGSIGNAL:
QBEQ ENDIF7, current, 0
// Hoog, lang signaal: doe niets
RET
ENDIF7:
// Laag, lang signaal: 1 wegschrijven
add_bit 1
RET

73
src/rawtiming.c Normal file
View File

@ -0,0 +1,73 @@
/**
* rawtiming.c
*
* Dit programma leest de stand van de infraroodsensor uit en
* zet de tijd tussen wisselingen op de standaarduitvoer.
* Bit 30 geeft de nieuwe stand van de sensor aan (laag of hoog).
*
* Het programma beschouwt het PRU-geheugen als een grote
* uint32-array met de lengte op index 0.
*/
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <prussdrv.h>
#include <pruss_intc_mapping.h>
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;
}

87
src/rawtiming.p Normal file
View File

@ -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<<shortcycle
LONGLOOP: //duur: 5*(5*2^shortcycle+6) ns
ZERO &shortcnt, 4
INC timer, 5*(5*(1<<shortcycle)+6)
LSR current, total, (shortcycle-1)
ZERO &total, 4
MIN current, current, 1 //de maximale waarde voor total leidt tot current=10b i.p.v. current=1b
QBEQ SHORTLOOP, current, previous
NEWVALUE: //duur: timer+5*15 ns
MOV previous, current
INC timer, 5*15
LSL temp, current, 30
OR timer, timer, temp
//debug naar LED
QBBS SETHI, current.t0
SETLO:
SET P8_11
QBA ENDIF
SETHI:
CLR P8_11
QBA ENDIF
ENDIF:
INC length
LSL temp, length, 2
SBCO timer, CONST_PRUDRAM, temp, 4
SBCO length, CONST_PRUDRAM, 0, 4
ZERO &timer, 4
QBA SHORTLOOP

67
src/read_signal.c Normal file
View File

@ -0,0 +1,67 @@
/**
* read_signal.c
*
* Dit programma leest de IR-signalen van panasonic-afstandsbedieningen
* en zet de code op de standaarduitvoer.
*
* Het programma beschouwt het PRU-geheugen als een grote
* uint64-array met de lengte op index 0.
*/
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <prussdrv.h>
#include <pruss_intc_mapping.h>
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;
}

64
src/read_signal.hp Normal file
View File

@ -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

88
src/read_signal.p Normal file
View File

@ -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<<shortcycle
CHECKVALUE: //duur: 5*(5*2^shortcycle+6) ns
ZERO &shortcnt, 4
INC timer, 5*(5*(1<<shortcycle)+6)
LSR current, total, (shortcycle-1)
ZERO &total, 4
MIN current, current, 1 //de maximale waarde voor total leidt tot current=10b i.p.v. current=1b
QBEQ SHORTLOOP, current, previous
NEWVALUE:
MOV previous, current
MOV temp, 1500000
QBGT ENDIF1, timer, temp
CALL STARTSIGNAL
ENDIF1:
MOV temp, 1000000
QBGT ENDIF2, timer, temp
CALL LONGSIGNAL
ENDIF2:
MOV temp, 1000000
QBLE ENDIF3, timer, temp
CALL SHORTSIGNAL
ENDIF3:
ZERO &timer, 4
QBA SHORTLOOP
STARTSIGNAL:
SET P8_12
ZERO &lowbits, 8
ZERO &nextbit, 4
RET
SHORTSIGNAL:
QBEQ ENDIF4, current, 0
QBGT ENDIF5, nextbit, 48
// Hoog signaal, 48 bits geschreven
LBCO length, CONST_PRUDRAM, 0, 4
AND length, length, (1<<8)-1
LSL offset, length, 3
INC offset, 4
INC length
SBCO lowbits, CONST_PRUDRAM, offset, 8
SBCO length, CONST_PRUDRAM, 0, 4
ZERO &nextbit, 4
ENDIF5:
RET
ENDIF4:
// Laag, kort signaal, 0 wegschrijven
add_bit 0
RET
LONGSIGNAL:
QBEQ ENDIF7, current, 0
RET
ENDIF7:
// Laag, lang signaal, 1 wegschrijven
add_bit 1
RET

89
src/stddef.hp Normal file
View File

@ -0,0 +1,89 @@
// Bij elkaar gesprokkeld van verschillende headerbestanden.
// *
// * ============================================================================
// * Copyright (c) Texas Instruments Inc 2010-12
// *
// * 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.
// * ============================================================================
// *
// *****************************************************************************/
// (C) Copyright 2012, Texas Instruments, Inc
//
// author M. Watkins
// *****************************************************************************/
#ifndef __STDDEF_HP__
#define __STDDEF_HP__
// Definitions
#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
#define CONST_PRUCFG C4
#define CONST_PRUDRAM C24
#define CONST_PRUSHAREDRAM C28
#define CONST_L3RAM C30
#define CONST_DDR C31
#define GER_OFFSET 0x10
#define HIESR_OFFSET 0x34
#define SICR_OFFSET 0x24
#define EISR_OFFSET 0x28
#define INTC_CHNMAP_REGS_OFFSET 0x0400
#define INTC_HOSTMAP_REGS_OFFSET 0x0800
#define INTC_HOSTINTPRIO_REGS_OFFSET 0x0900
#define INTC_HOSTNEST_REGS_OFFSET 0x1100
// Address for the Constant table Block Index Register (CTBIR)
#define CTBIR 0x22020
// Address for the Constant table Programmable Pointer Register 0(CTPPR_0)
#define CTPPR_0 0x22028
// Address for the Constant table Programmable Pointer Register 1(CTPPR_1)
#define CTPPR_1 0x2202C
// Macros
.macro LD32
.mparam dst,src
LBBO dst,src,#0x00,4
.endm
.macro LD16
.mparam dst,src
LBBO dst,src,#0x00,2
.endm
.macro LD8
.mparam dst,src
LBBO dst,src,#0x00,1
.endm
.macro ST32
.mparam src,dst
SBBO src,dst,#0x00,4
.endm
.macro ST16
.mparam src,dst
SBBO src,dst,#0x00,2
.endm
.macro ST8
.mparam src,dst
SBBO src,dst,#0x00,1
.endm
#endif // __STDDEF_HP__

30
src/stop.c Normal file
View File

@ -0,0 +1,30 @@
#include <stdio.h>
#include <unistd.h>
#include <prussdrv.h>
#include <pruss_intc_mapping.h>
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);
}

3
tools/ircommander_lokaal Normal file
View File

@ -0,0 +1,3 @@
#!/bin/sh
cd ../bin/
./ircommander | $SHELL

12
tools/laad_overlay Normal file
View File

@ -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