Arduino Ethernet (KEIN Shield!) und TLC5940. ist das möglich?

Hat jemand schon einmal das Arduino Ethernet (nicht das Shield, sondern das Board, wo der Ethernetpart integriert ist. siehe Foto, oder hier: http://arduino.cc/en/Main/ArduinoBoardEthernet) gemeinsam mit dem TLC5940 Led-Driver zum Laufen gebracht?
Ich würde gerne das ArduinoEthernet als Webserver nutzen, welcher dann über den TLC5940 mehrere RGB-LEDs steuert.
Beides einzeln funktioniert perfekt, aber gemeinsam bringe ich es einfach nicht zustande.
Leider finde ich nur Anleitungen/Tipps betreffend Ethernet-Shield, wo man angeblich Pins verbiegen und etwas an der Ethernet-Library ändern muss, nur das kann ich mangels Ethernet-Shield nicht ausprobieren, und besonders schön finde ich den “Hack” auch nicht.

Kann man das nicht softwareseitig lösen, oder mit “softeren” Tricks?
Soweit ich sehen konnte, kommen sich die beiden betreffend SPI in die Quere, aber ich bin Arduino-Anfänger und habe noch relativ wenig Ahnung bzw tue mir mit den Begrifflichkeiten noch etwas schwer. Aber das wird hoffentlich noch.

Bin für jede Hilfe oder Richtungsweisung dankbar!

Du musst nur die Pin-Belegung ändern und die Bibliothek entsprechend anpassen, dann ist das mit dem Arduino Ethernet kein Problem. Hardware-Anpassungen (Pin verbiegen, etc.) weil man die Software nicht ändern will, ist definitiv nicht das, was Du machen willst.

Soweit ich sehen konnte, kommen sich die beiden betreffend SPI in die Quere

Der Entwickler des Treibers auf GitHub (den Du übrigens vergessen hast zu verlinken) hat einfach nicht so weit gedacht, dass die SPI Pins gebraucht werden könnten und hat seine Bibliothek mit diesen Defaults ausgestattet. Zum Glück war er aber so intelligent, dass er #defines genommen hat, die man relativ einfach ändern kann.
Du kannst in pinouts/ATmega_xx8.h die Pin-Belegung anpassen, indem Du die Port- und Bit-Nummern änderst.

Edit: Filepfad korrigiert.

Vielen Dank für diesen Wegweiser! ...das werde ich ausprobieren, sehen wie ich damit zurecht komme (auch wenn es jetzt für mich als Laien gar nicht einfach klingt) und werde dann berichten.

Die Library hatte ich übrigens von hier: Google Code Archive - Long-term storage for Google Code Project Hosting.
...aber durch deinen Tipp betreffend GitHub hab ich dann das gefunden: GitHub - ColinHarrington/TLC5940-Arduino: TLC5940 Arduino

Ups, ich hatte mir auch den Code auf code.google.com angesehen und meine Kommentare waren dazu. Sorry, hatte den GitHub noch in den Suchresultaten und war darum wohl verwirrt.

Edit: Sieht aber nach der Vorgängerversion des Codes auf Google aus.

Ich habe nun versucht, die tlc_config.h entsprechend anzupassen, und mir ist es zumindest gelungen, im bitbang-Modus die Pins 11 und 13 frei zu bekommen, indem ich diese auf Pin 2 und 7 verfrachtet habe.
Da steht jetzt:

#define DATA_TRANSFER_MODE    TLC_BITBANG
/** SIN (TLC pin 26) */
#define SIN_PIN        PD2
#define SIN_PORT       PORTD
#define SIN_DDR        DDRD
/** SCLK (TLC pin 25) */
#define SCLK_PIN       PD7
#define SCLK_PORT      PORTD
#define SCLK_DDR       DDRD

Hier ist die Map, die mir dabei geholfen hat: http://brittonkerin.com/cduino/pin_map.html

Jetzt würde meiner Theorie nach nur noch der Pin 10 fehlen, um dazu parallel auch den webserver darauf zu betreiben.
...nur es gelingt mir einfach nicht diesen in irgendeiner Weise zu beinflußen.
Egal wo ich etwas ändere, ob in pinouts/ATmega_xx8.h oder in der tlc_config.h, es hat zeigt einfach keine Wirkung. Der Anschluss für BLANK bleibt einfach bei Pin 10.

Außerdem bekomme ich die ganze Sache NUR mit der "alten" Library zum laufen. Die Version von GitHub hat in der Tlc5940.cpp ein paar zeilen auskommentiert, ohne die das bei mir einfach nicht funktionieren will. Ich verwende daher die alte Version, und denke nicht, dass die Änderungen in der neuen Version irgendeine brauchbare Wirkung bei einem Arduino-Ethernet-Board haben (bitte mich zu korrigieren sollte ich da komplett falsch liegen).

...in pinouts/ATmega_xx8.h steht außerdem "SPI and timer pins for the ATmega168/48/88. Don't edit these. All changeable pins are defined in tlc_config.h".
Nur da komme ich eben nicht weiter, weil BLANK auf Pin 10 bleibt hartnäckig dort liegen.

noch eine Idee?

Der BLANK-Pin wird nicht direkt angesprochen, sondern mit einem PWM-Signal belegt. Aus dem Datasheet werde ich aber nicht wirklich schlau, warum dies notwendig sein soll. Ich würde mal versuchen, die XLAT und BLANK auf den selben Pin zu connecten, wenn das nicht geht, BLANK auf GND zu ziehen. Wenn das nicht fruchtet, müssen wir evtl. einen Timer-Interrupt installieren, damit wir den Pin frei bekommen. Ich könnte auch mal schauen, ob wir Timer1 und Timer2 vertauschen könnten, dann wären Pin 2, 3 und 9 belegt und Pin 10 wäre frei.

Der PWM des TLC ist nicht freilaufend indem man ihm einen Takt gibt sondern mittels GSCLK und BLANK gesteuert.
An GSCLK müssen 4096 Impulse gesendet werden und dann, damit der PWMzyklus wieder startet, braucht es einen Impuls am BLANK Pin. Nur so gibt der TLC ein PWM-Signal an seine Ausgänge.
Grüße Uwe

Die TLC Bibliothek nutzt die verfügbaren Timer-Resourcen des ATmega328 ziemlich aus, Umstellungen der Timer sind nicht so einfach möglich. Da nur Timer1 zwei Output Compare Register und ein konfigurierbares TOP hat, können die Timer1 und Timer2 nicht einfach getauscht werden.
Aufgrund des Timing-Diagrams im Datasheet könnte aber der Trick mit der ISR funktionieren.

In Tlc5940.cpp muss die ISR angepasst werden:

/** Interrupt for XLAT pulses and BLANK line */
ISR(TIMER1_OVF_vect)
{
    BLANK_PORT |= _BV(BLANK_PIN);
    if (tlc_needXLAT) {
        XLAT_PORT |= _BV(XLAT_PIN);
        XLAT_PORT &= ~_BV(XLAT_PIN);
    }
    tlc_needXLAT = 0;
    BLANK_PORT &= ~_BV(BLANK_PIN);
    if (tlc_onUpdateFinished) {
        sei();
        tlc_onUpdateFinished();
    }
}

in der selben Datei die Initialisierung:

    setAll(initialValue);
    update();
    disable_XLAT_pulses();
    set_XLAT_interrupt();
    tlc_needXLAT = 0;
    pulse_pin(XLAT_PORT, XLAT_PIN);


    /* Timer Setup */

    /* Timer 1 - BLANK / XLAT */
    TCCR1A = 0;  // no output on OC1B, BLANK and XLAT is handled in ISR
    TCCR1B = _BV(WGM13);   // Phase/freq correct PWM, ICR1 top
    ICR1 = TLC_PWM_PERIOD; // see tlc_config.h

in Tcl5940.h muss dafür gesorgt werden, dass der Interrupt immer ausgeführt wird:

/** Enables the Timer1 Overflow interrupt, which will fire after an XLAT
    pulse */
#define set_XLAT_interrupt()    TIFR1 |= _BV(TOV1); TIMSK1 = _BV(TOIE1)
/** Disables any Timer1 interrupts */
#define clear_XLAT_interrupt()  

#endif

/** Enables the output of XLAT pulses */
#define enable_XLAT_pulses()    
/** Disables the output of XLAT pulses */
#define disable_XLAT_pulses()

Das Timing auf dem BLANK-Ausgang ändert sich zwar geringfügig, aber einen Versuch ist es wert. Wenn ich nichts übersehen habe, könnte es funktionieren. Du solltest dann die Pins XLAT und BLANK auch frei definieren können. Der Nachteil: Du hast deutlich mehr Interrupts, der Prozessor ist also etwas mehr beschäftigt.

@pylon: sensationell!
(Unter anderem) mit deiner grandiosen Hilfe ist es mir nun gelungen, den Webserver parallel zum TLC5940 zu verwenden!

Ich habe die Library deinen Vorgaben entsprechend modifiziert und mit diesem Arduino-Sketch getestet:

#include <Ethernet.h>
#include <SPI.h>
#include "Tlc5940.h"

boolean reading = false;
byte ip[] = { 192, 168, 1, 70 };
byte gateway[] = { 192, 168, 1, 1 };
byte subnet[] = { 255, 255, 255, 0 };
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };  
EthernetServer server = EthernetServer(80);

void setup(){
	Serial.begin(9600);

	Tlc.init();

	Ethernet.begin(mac, ip, gateway, subnet);
	server.begin();

	Serial.println(Ethernet.localIP());
}

void loop(){
	EthernetClient client = server.available();
	if (client) {
		boolean currentLineIsBlank = true;
		boolean sentHeader = false;

		while (client.connected()) {
			if (client.available()) {
				if(!sentHeader){
					client.println("HTTP/1.1 200 OK");
					client.println("Content-Type: text/html");
					client.println();
					sentHeader = true;
				}

		        char c = client.read();

				if (reading && c == ' ') reading = false;
				if (c == '?') reading = true; //found the ?, begin reading the info

				if(reading){
					Serial.print(c);

					switch (c) {
						case '0':
							ledStepper(-1);
							client.println("Toggle LEDs from 16-0.");
						break;
						case '1':
							ledStepper(1);
							client.println("Toggle LEDs from 16-0.");
						break;
					}

				}
				if (c == '\n' && currentLineIsBlank) break;
				if (c == '\n') {
					currentLineIsBlank = true;
				} else if (c != '\r') {
					currentLineIsBlank = false;
				}
			}
		}
		delay(1); // give the web browser time to receive the data
		client.stop(); // close the connection:
	} 
}

void ledStepper(int _direction) {
	int channel = 0;
	if (_direction != 1) {
		channel = 16;
	}
	for (int count = 0; count < 16; count++) {
		Tlc.clear();
		Tlc.set(channel - 1, 1000);
		Tlc.set(channel, 4095);
		if (channel != 16 - 1) {
			Tlc.set(channel + 1, 1000);
		}
		Tlc.update();
		channel = channel += _direction;
		delay(75);
	}
}

…und diese Konfiguration verwende ich in tlc_config.h:

#define DATA_TRANSFER_MODE    TLC_BITBANG
/** SIN (TLC pin 26) */
#define SIN_PIN        PD2	// Arduino-Pin 2
#define SIN_PORT       PORTD
#define SIN_DDR        DDRD
/** SCLK (TLC pin 25) */
#define SCLK_PIN       PD7	// Arduino-Pin 7
#define SCLK_PORT      PORTD
#define SCLK_DDR       DDRD
/** BLANK (TLC pin 23) */
#define BLANK_PIN      PD5	// Arduino-Pin 5
#define BLANK_PORT     PORTD
#define BLANK_DDR      DDRD

Wenn man das ganze dann so verkabelt wie auf dem Bild zu sehen, und im Browser http://192.168.1.70/?1 oder http://192.168.1.70/?0 aufruft, laufen die LEDs (Angeschlossen an den PWM-Kanälen 1-16 des TLC5940) einmal hinauf oder hinunter.

soweit so gut! DANKE!

Für mich ergeben sich dadurch aber auch folgende Fragen:

  1. Ist es möglich, dass sich aus dieser Lösung, die man doch eher als Workaround bezeichnen kann, irgendwelche Stabilitätsprobleme ergeben?

  2. Welcher Nachteil ergibt sich aus “deutlich mehr Interrupts” noch, außer einer höheren Prozessorbelastung?

  3. Außerdem schreibst du:

Das Timing auf dem BLANK-Ausgang ändert sich zwar geringfügig

Was bedeutet das dann in der Praxis bzw welche Auswirkungen hat das möglicherweise?

Tlc5940_mod.zip (64.6 KB)

  1. Ist eigentlich nicht zu erwarten. Den Code könnte man etwas sauberer machen, indem man z.B. die (jetzt) leeren Makros entfernt, aber zu Laufzeit sind eigentlich keine negativen Effekte zu erwarten.

  2. Das wird erst relevant, wenn Du andere zeitkritische Sachen machen willst. Eine SoftwareSerial-Instanz könnte z.B. mehr Probleme verursachen, aber die würde wahrscheinlich schon mit der ursprünglichen Implementation nicht sauber zusammenarbeiten.

  3. Da der Chip mit diesem Timing zu funktionieren scheint, dürfte es keine weiteren Auswirkungen haben. Ich habe die Timing-Details im Datasheet nicht angeschaut oder das exakte Timing des von mir zusammengeschusterten Codes ausgerechnet, es hätte ja sein können, dass ich irgendwo ein Limit über- oder unterschritten habe und es deshalb nicht funktionierte. Dass sich das jetzt noch ändert, ist sehr unwahrscheinlich.