Krumeltee

-> Elektronik, Mikrocontroller und Retro-Computing <-

Archive for the ‘Uncategorized’ Category

Generator für Sinus-Tabellen in C

Posted by krumeltee - 26. Dezember 2012

Ab und zu braucht man eine Sinus-Tabelle in seinem Programm um aufwendigem Berechnen zur Laufzeit zu entgehen. Hierfür habe ich mir mal dieses kleine Tool geschrieben.

Compiliert wird es ganz einfach mit „gcc -lm sintab_generator.c -o sintab_generator“. Die Maths-Library ist die einzige Abhängigkeit hierfür, die aber schon in der glibc bzw. Standard-C-Library mit drin steckt.

„./sintab_generator –help“ listet alle Möglichkeiten auf.
Ein Beispiel für eine 8-Bit Tabelle, nur Positive Zahlen (Signal-Null liegt bei Amplitude/2 und nicht bei 0), Amplitude Max. 255, 128 Werte:
„./sintab_generator -d 16 -A 0xff -l 128 -c“
Diese Tabelle könnte so von einem DA Wandler am AVR ausgegeben werden. Ein Einfacher DA-Wandler wäre z.B. nur ein Portpin+RC-Glied mittels PWM.

/* simple generator for sine tables to include in c code
 *
 * (c) 2012 nils stec
 *
 * license: GPL
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <sys/types.h>
#include <math.h>

#define DT_8            1
#define DT_16           2
#define DT_32           4
#define DT_DOUBLE       16
#define DT_SIGNED       0
#define DT_UNSIGNED     1

void help();
void gen_table(unsigned int len, unsigned int amplitude, int offset, int sign, int datatype, int comment);

int main(int argc, char **argv) {
        int i;

        unsigned int len = 32;
        unsigned int amp = 0;
        int off = 0;
        int sign = DT_SIGNED;
        int datatype = DT_8;
        int comment = 0;

        int itemp;
        unsigned long int ultemp;
        long int ltemp;
        unsigned int calc_temp;

        for(i = 0; i < argc; i++) {
                if(!(strcmp(argv[i], "-u"))) {          // only unsigned values
                        sign = DT_UNSIGNED;
                } else if( (!(strcmp(argv[i], "-h"))) || (!(strcmp(argv[i], "--help"))) ) {
                        help();
                        exit(0);
                } else if(!(strcmp(argv[i], "-c"))) {   // add comment
                        comment = 1;
                } else if(!(strcmp(argv[i], "-o"))) {   // offset DEC
                        if(argv[i+1] == NULL) {
                                printf("\nyou'll need to give me an offset!\n\n");
                                exit(1);
                        }
                        ltemp = strtol(argv[i+1], NULL, 10);
                        if(ltemp == 0) {
                                printf("\nzero-offset not allowed!\n\n");
                                exit(1);
                        }
                        off = (int)ltemp;
                } else if(!(strcmp(argv[i], "-a"))) {   // amplitude DEC
                        if(argv[i+1] == NULL) {
                                printf("\nyou'll need to give me max. amplitude!\n\n");
                                exit(1);
                        }
                        ltemp = strtol(argv[i+1], NULL, 10);
                        if(ltemp < 2) { 
                                printf("\namplitude negative or too small!\n\n");
                                exit(1);
                        }
                        amp = (unsigned int)ltemp;
                } else if(!(strcmp(argv[i], "-O"))) {   // offset HEX
                        if(argv[i+1] == NULL) {
                                printf("\nyou'll need to give me an offset in hex!\n\n");
                                exit(1);
                        }
                        ltemp = strtol(argv[i+1], NULL, 16);
                        if(ltemp == 0) {
                                printf("\nzero-offset not allowed!\n\n");
                                exit(1);
                        }
                        off = (int)ltemp;
                } else if(!(strcmp(argv[i], "-A"))) {   // amplitude HEX
                        if(argv[i+1] == NULL) {
                                printf("\nyou'll need to give me max. amplitude in hex!\n\n");
                                exit(1);
                        }
                        ltemp = strtol(argv[i+1], NULL, 16);
                        if(ltemp < 2) {   
                                printf("\namplitude negative or too small!\n\n");
                                exit(1);
                        }
                        amp = (unsigned int)ltemp;
                } else if(!(strcmp(argv[i], "-l"))) {   // length
                        if(argv[i+1] == NULL) {
                                printf("\nyou'll need to give me the length!\n\n");
                                exit(1);
                        }
                        ltemp = strtol(argv[i+1], NULL, 10);
                        if(ltemp < 2) {   
                                printf("\ntoo short!\n\n");
                                exit(1);
                        }
                        if((ltemp%2) != 0) {
                                printf("\nlen has to be a power of 2!\n\n");
                                exit(1);
                        }
                        len = (unsigned int)ltemp;
                } else if(!(strcmp(argv[i], "-d"))) {   // datatype
                        if(argv[i+1] == NULL) {
                                printf("\nyou'll need to give me a datatype!\n\n");
                                exit(1);
                        }
                        ultemp = strtoul(argv[i+1], NULL, 10);
                        itemp = (int)ultemp;
                        switch(itemp) {
                                case 8:
                                        datatype = DT_8;
                                        break;
                                case 16:
                                        datatype = DT_16;
                                        break;
                                case 32:
                                        datatype = DT_32;
                                        break;
                                default:
                                        if(strcmp(argv[i+1], "double") == 0) {
                                                datatype = DT_DOUBLE;
                                        } else {
                                                printf("\nwrong datatype!\n\n");
                                                help();
                                                exit(1);
                                        }
                                        break;
                        }
                }

        }

        printf("\n");

        switch(datatype) {
                case DT_8:
                        ultemp = 0xff;
                        ltemp = 0xff;
                        break;
                case DT_16:
                        ultemp = 0xffff;
                        ltemp = 0xffff;
                        break;
                case DT_32:
                        ultemp = 0xffffffff;
                        ltemp = 0xffffffff;
                        break;
                case DT_DOUBLE:
                        break;
        }

        if(datatype != DT_DOUBLE) {
                if(off < 0) calc_temp = (unsigned int)off * -1;
                else calc_temp = (unsigned int)off;

                if((calc_temp+amp) > ultemp) {
                        printf("\ndatatype too small to hold your sine!\n\n");
                        exit(-1);
                }
        }
        gen_table(len, amp, off, sign, datatype, comment);
        return 0;
}

void help() {
        printf("c sine table generator 0.01 [(c) 2012, nils stec]\n\n");
        printf("  -d 8/16/32/double      datatypes: int8_t,int16_t,int32_t,double\n");
        printf("  -u                     force unsigned values (signal zero is at max_amplitude/2)\n");
        printf("  -o offset              offset DECIMAL\n");
        printf("  -O offset              offset HEX\n");
        printf("  -a max_amplitude       max amplitude DECIMAL\n");
        printf("  -A max_amplitude       max amplitude HEX\n");
        printf("  -l len                 length\n");
        printf("  -c                     add comment\n");
        return;
}

void gen_table(unsigned int len, unsigned int amplitude, int offset, int sign, int datatype, int comment) {
        double sine;
        int n, i;
        uint32_t table_entry;

        if(sign == DT_UNSIGNED) {                               // if we want unsigned data, we have to pull our sine higher than zero
                while((int)(offset-amplitude)<0) offset++;
        }

        if(comment) {
                printf("/* sine table, ");

                if(datatype != DT_DOUBLE) { 
                        printf("max amplitude %d, ", amplitude);
                        printf("offset %d, ", offset);
                }
                printf("%d entries, size in memory: %dbytes */\n", len, datatype*len);

        }

        if(datatype != DT_DOUBLE) {
                if(sign==DT_UNSIGNED) printf("u");
                switch(datatype) {
                        case DT_8:
                                printf("int8_t sine_table[%d] = {\n", len);
                                break;
                        case DT_16:
                                printf("int16_t sine_table[%d] = {\n", len);
                                break;
                        case DT_32:
                                printf("int32_t sine_table[%d] = {\n", len);
                                break;
                }

        } else printf("double sine_table[%d] = {\n", len);

        n = 0;
        while(n < len) {
                printf("");
                for(i = 0; i < 8; i++) {
                        sine = sin(2.0*M_PI*n/len);
                        switch(datatype) {
                                case DT_DOUBLE:
                                        printf("%f", sine);
                                        break;
                                default:
                                        table_entry = (sine*(double)amplitude)+offset;
                                        printf("%d", table_entry);
                                        break;
                        }
                        n++;
                        if(n < len) printf(", ");
                }
                printf("\n");
        }
        printf("};\n\n");
}
Advertisements

Posted in Uncategorized | Leave a Comment »

Grasshopper I²C Quickstart

Posted by krumeltee - 3. August 2011

Nachdem ich eine ganze Weile suchen und ausprobieren musste, wie man I²C mit dem /dev-Interface auf dem Grasshopper zum Laufen bekommt, schreibe ich das nun hier auch mal auf.

Der Text hier bezieht auf das Board mit dem Originalkernel im Auslieferungszustand, also eine Art „Quickstarting with I²C“ 🙂

Das Problem war, dass er zwar das I²C-„Host-Device“ erkannt hat, aber keine /dev-Node erstellt hat und wenn ich diese von Hand erstellt habe, dann gings nicht.

Die Lösung liegt darin, die Treiber in der richtigen Reihenfolge zu laden.

$ modprobe i2c-atmeltwi
$ modprobe i2c-core
$ modprobe i2c-dev

Nun kann man nachsehen, ob das I²C-/dev-Gerät erstellt worden ist:

$ ls -al /dev/i2c*
crw-r--r--    1 root     root      89,   0 Dec 31  2006 /dev/i2c-0

Sollte dabei nicht herauskommen, kann man die Device-Node von Hand anlegen:

$ mknod /dev/i2c-0 89 0 b

Nun kann man z.B. so den Bus durchsuchen lassen:

$ ./i2cdetect -y -r 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- 28 -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- 44 -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

Bei mir sind zu dem Zeitpunkt die Adressen $28 und $44 belegt gewesen, ein MAX127 AD-Wandler und ein MAX6956 20-Port LED Treiber/IO-Expander.
i2cdetect ist ein Teil von i2ctools und leider nicht von Haus aus auf dem Board. Ich habe es übersetzt, eingetütet und ihr könnt es hier herunterladen. Auf dem Board entpacken und ausführen.

Um die Treiber und die Device-Node automatisch laden und anlegen zu lassen, muss man den „autostart“ des Board ein wenig bearbeiten:

$ vi /etc/rc.d/S50i2c.sh

„i“ drücken (starten des eingabe modus)

#!/bin/sh
 case "$1" in
 start|"")
 echo Starting i2c driver
 modprobe i2c-atmeltwi
 modprobe i2c-core
 modprobe i2c-dev
 mknod /dev/i2c-0 89 0 c
 ;;
 stop)
 ;;
 *)
 echo "Usage: $0 [start|stop]"
 exit 255
 ;;
 esac
return 0

:wq tippen (beenden von vi und speichern)

$ chmod +x /etc/rc.d/S50i2c
Ab jetzt wird bei jedem Neustart der Treiber automatisch richtig geladen.

Posted in Uncategorized | Leave a Comment »

MAX520 I²C, 4 Channel, 8Bit, DA-Wandler

Posted by krumeltee - 28. Juli 2011

Hier mal ein kleiner Codeschnipsel und Schaltplan wie man einen MAX520 DA-Wandler zum Laufen bekommt.

Der Wert an den Ausgängen geht von 0 bis REFx, sprich, legt man an die Referenz für einen Ausgang 5 Volt an, geht dieser Ausgang von 0 bis 5V.

Da dies ein 8 Bit DAC ist, wird der Bereich in 256 Schritte eingeteilt. Will man nun die Ausgangsspannung errechnen, rechnet man das so:

REFx/256*WERT

Ist REF 2,5V und der WERT ist 127, dann bekommt man 1,24Volt.

Im Grunde also ganz einfach.

Noch einfacher ist der Quellcode, welcher die Fleury I²C Library benutzt:

#define DAC_CH0 0x00
#define DAC_CH1 0x01
#define DAC_CH2 0x02
#define DAC_CH3 0x03

#define DAC_ADDRESS 0x5e

void set_max520(unsigned char address, unsigned char channel, unsigned char value) {
    if(channel > 0x03) return;
    i2c_start(address);
    i2c_write(channel);
    i2c_write(value);
    i2c_stop();
    return;
}

/* setzen des DAC Ausgangs 0 auf den Wert 127 */
set_max520(0x5e, DAC_CH0, 127);

 

Und zum Schluss noch ein Foto:

Posted in Uncategorized | Leave a Comment »

Die Konsole etwas „aufpeppen“

Posted by krumeltee - 24. Februar 2011

Die sehr magere Konsole von busybox ist gewöhnungsbedürftig, wenn man sonst mit Linux auf „normalen“ PCs zu tun hat, das ändert man aber leicht in ein paar Minuten.

Als erstes installiert man die coreutils (ls, dd, usw.) von gnu und die bash:

$ apt-get install coreutils-gnu bash3

Wenn er nicht automatisch fragen sollte, ob man die bash als standard-Shell haben möchte, dann einfach von Hand ändern:

$ vi /etc/passwd

Dort dann „i“ für Einfügen (insert) drücken und mit den Pfeilen zur root und dann zur user Zeile navigieren und das „/bin/sh“ durch „/bin/bash“ ersetzen:

root:XxXXXXYXxYYXX:0:0:root:/root:/bin/sh
user:xXXxYYXxXYXXX:29999:29999::/home/user:/bin/sh

wird zu:

root:XxXXXXYXxYYXX:0:0:root:/root:/bin/bash
user:xXXxYYXxXYXXX:29999:29999::/home/user:/bin/bash

Wenn das getan ist ESC drücken, „:wq“ tippen und ENTER drücken.

Um nun die coreutils-gnu zu benutzen, sollte man sich aliase einrichten. Die coreutils-gnu ermöglichen z.B. farbige ls-Ausgaben. Die scirpte, welche beim Starten der bash ausgeführt werden liegen in „/etc/profile.d/„.

Hier erstellt man eine neue Datei:

vi /etc/profile.d/bashrc.sh
^^ "i" drücken, das tippen:
alias ls="gls --color"
alias la="gls --color -a"
alias lla="gls --color -l -a"
alias ll="gls --color -l"
^^ ESC drücken, ":wq" tippen, ENTER drücken

Sämtliche Tools aus den coreutils-gnu beginnen mit „g“ am Anfang, also gls, gdd, gcat, gecho, ggrep, gegrep, …
Hier haben wir uns jetzt aliase eingerichtet, dass er bei ls das gls nimmt, mit farbigem Output, so sieht das nun aus:

 

Wer die SDK-Repos, wie im GCC Artikel beschrieben, installiert hat, kann sich auch einen vollwertigen vim installieren (inkl. Syntax Highlighting :)), der sieht so aus:

 

Mit dem GCC drauf installiert compiliert die Datei auch genau so 🙂

Posted in Uncategorized | Leave a Comment »

Die LEDs und die Kerneltrigger genau erklärt

Posted by krumeltee - 24. Februar 2011

Hier werde ich kurz aber genau erklären, wie die verschiedenen LED-Trigger zu verwenden sind und was diese machen.

Da die RGB-Led anderweitig, nämlich durch das MCE gesteuert wird, werde ich nur zu den Keyboard LEDs was schreiben. Wer die RGB verwenden will, kann sich das aber genauso durchlesen, ist das Selbe.

 

Der LED-Treiber vom Linux-Kernel lässt sich im Verzeichnis „/sys/class/leds/“ steuern. Dort sind verschiedene Verzeichnisse, welche die verschiedenen LEDs darstellen:

Die Tastatur LEDs sind lp5523:kb1 … lp5523:kb6, kb6 ist ganz links, kb1 ist ganz rechts auf der Tastatur.

Nun gehen wir einfach mal in ein Verzeichnis, lassen uns die Trigger anzeigen, die verfügbar sind und stellen erstmal auf Herzschlag. Der Herzschlag ist eine mathematische Funktion, die die CPU-Auslastung nimmt und darüber dann die Geschwindigkeit des Triggers bestimmt.

In der Datei „brightness“ kann man die Helligkeit einstellen, in dem man Werte von 0 bis 255 hineinschreibt.

Um das Geblinke wieder auszumachen einfach wieder „none“ mit statt „heatbeat“ hineinschreiben.

 

Nun eine kleine Erklärung der verschiedenen Trigger:

  • mmc0/mmc1

Diese beiden Trigger lassen die LED bei „Festplattenzugriff“ auf die Geräte mmc0 und mmc1 blinken. So wie es aussieht ist aus sich des LED-Treiber aber die Reihenfolge vertauscht, kein Problem, tut nichts zur Sache, nur sollte man das wissen. Ich hab‘ mich erstmal gewundert warum nichts ging…

Im Linux sonst ist mmc0 der interne 32gb Speicher und mmc1 die SD-Karte. Für den LED-Treiber ist mmc1 der interne Speicher und mmc0 die SD-Karte.

  • keyb

Höchstwahrscheinlich Tastatureingabe, allerdings blinkt bei mir nichts, wenn ich die Tastensperre reinmache, wahrscheinlich weil die Tastatur dann aus ist *augenroll*. Wenn ich die Tastensperre rausmache, ist die Beleucht dauern-an, deshalb wird sich da ja dann auch nichts tun… Vielleicht weiss ja einer eine Lösung!

  • heartbeat

Wie schon gesagt, umso höher die CPU-Belastung umso schneller blinkt die LED, für die heartbeat eingestellt wurde.

  • timer

Timer ist der einzige Trigger, der sich einstellen lässt. Sobald man diesen aktiviert hat, erstellt der Treiber zwei neue Dateien, in denen man in Millisekunden angeben kann, wie lange die LED an und wie lange sie auch sein soll:

Posted in Uncategorized | Leave a Comment »

Herzschlagvibrator

Posted by krumeltee - 23. Februar 2011

Wer den CPU-Herzschlag (wird schneller bei Belastung) auf dem Vibrator des Handys „überwachen“ will, gibt das im X-Terminal ein:

$ sudo gainroot
$echo "heartbeat" > /sys/class/leds/twl4030:vibrator/trigger

wieder aus geht’s so:

$ sudo gainroot
$echo "none" > /sys/class/leds/twl4030:vibrator/trigger

 

Posted in Uncategorized | Leave a Comment »