Alpine M-Bus Emulator von Arduino Pro Mini auf Esp32 dev portieren

Guten Abend,
das ist mein erster Post in diesem Forum. Ich bin weder Elektrotechniker noch Programmierer, habe aber vor einigen Jahren angefangen, mir ein paar Homebrew-Komponenten für die Hausautomatisierung zusammenzubauen und auf meine Bedürfnisse anzupassen. Ich kann einigermaßen mit dem Lötkolben umgehen, habe Multimeter und Labornetzteil, kann Code, den andere geschrieben haben, meist erfolgreich modifizieren bzw. anpassen, und auch das Kompilieren, Flashen usw. klappt normalerweise leidlich.

Allerdings habe ich als Nicht-Programmierer klare Limits, wenn es um Grundsätzliches, From-the-Scratch-Programmierung und das Zusammenspiel zwischen Hardware und Software geht… Und an einem solchen toten Punkt bin ich nun mit meinem aktuellen Projekt angelangt.

Ich möchte einen AUX-Eingang für das Originalradio meines Youngtimers (1995er Jaguar XJS) kreieren. Es handelts sich um eine Alpine HU mit 6fach-CD-Wechsler im Kofferraum. Und der so genannte M-Bus von Alpine, der für die Kommunikation zwischen HU und Wechsler zuständig ist, ist der Schlüssel für den Aux-Eingang.

Die HU schaltet das über den CD-Eingang kommende Audiosignal nur dann live, wenn sie mit dem Wechsler über den M-Bus kommunizieren kann. Daher braucht es eine Art M-Bus-Emulator, der die HU glauben lässt, die würde mit dem Wechsler „sprechen“, wodurch man sein externes Audiosignal auf die Leitung des CD-Eingangs legen kann.

Glücklicherweise musste ich das Rad nicht neu erfinden, da sich schon einige, die sich besser mit Hardware und Programmierung auskennen, mit diesem Thema befasst haben. Die „Mutter aller M-Bus-Emulatoren“ dürfte die Seite von Jörh Hohensohn sein. Da ist der Bus beschrieben, ebenso das Prinzip, wie man ihn emuliert. Leider darf ich als Neuling ich nur zwei Links im Beitrag untebringen.

Ich setze erfolgreiche Olystyles M-Bus library für Arduino mit einem Pro Mini ein (GitHub - Olstyle/MBus: Alpine MBus for Arduino); Picoharis ähnlicher Ansatz mit einem AT128 läuft bei mir ebenfalls (GitHub - picohari/atmega128_alpine-mbus-emulator: Alpine M-Bus CD Changer Emulator with ATmega128 and LCD). Für beide nutze ich die von Picohari vorgeschlagene Schaltung, um das Bussignal mit ein paar Transistoren und Widerständen in Eingang und Ausgang zu splitten. Interessanterweise funktioniert das bei mir sogar ohne dass ich die 5 Volt (bzw. 12 Volt bei Jörg Hohensohn) draufgebe.

Nun würde ich gern den nächsten Schritt gehen und A2DP Bluetooth in den M-Bus-Dongle integrieren. So könnte man z.B, die Originalknöpfe der HU – etwa die zur Auswahl der CDs 1 bis 6 – nutzen, um Befehle wie Play, Stop, Pause usw. an das verbundene Smartphone zu senden

Daher habe ich mir nun mal einen Esp32 besorgt, da er mit integriertem Bluetooth kommt und es nette Libraries für Amateure wie mich dafür gibt. Ich habe den „ESP32 NodeMCU Dev Kit C with CP2102“. Ich hoffte, dass ich Olstyle’s library (s. Link w.o.) und den Beispielcode auf dem Esp32 nutzen könnte (via Arduino IDE). Der Beispielcode, der wie gesagt auf dem Pro Mini prima läuft, ist ebenfalls dort: "independentGButtons.ino", unter "examples"

Kompilieren und Flashen klappt, aber beim Anschluss an die HU erkennt diese keinen CD-Wechsler.

Ich habe die Pin-Definitionen für IN und Out von 10 und 12 (Olstyles Pro Mini Beispiescript) zu Pins 4 und 5 für den Esp32 geändert. Nicht geändert habe ich

MBus::MBus(uint8_t in, uint8_t out)
{
	_in=in;
	_out=out;
	
	pinMode(_in, INPUT);
	pinMode(_out,OUTPUT);
}

in Mbus.cpp, da ich dachte, dass das auch für den Esp32 passen würde.

Aber ich fürchte, dass es da doch mehr zu ändern gibt, damit der Sketch auch auf dem Esp32 läuft.

Daher wäre ich sehr dankbar, wenn mal jemand, der etwas davon versteht, über den Code schauen und mir einen Tipp geben könnte…

Martin

Guten Morgen!

Von Alpine M-Bus hatte ich bislang noch nichts gelesen. Auch habe ich weder einen Youngtimer noch eine Alpine HU in einem Kofferaum oder sonstwo.

Aber ich habe einen ESP32 und einen einfachen Logikanalysator. Mit dem Testprogramm independentButtons.ino ergibt sich dieses Bild:

Für mich sieht das gut aus.

Daher wechselt mein Fokus zur Hardware. Auf der Seite The Alpine M-Bus Protocol finde ich diese Schaltung:

grafik

Links lese ich "TTL_OUTPUT", was der ESP32 nicht liefern kann.

  1. Schaltet der Transistor satt durch?
  2. Wie sieht das Signal an M-BUS aus?

Wenn Du keinen Logikanalysator oder ein Oszilloskop hast, gib ein langsam pulsierendes Signal auf den Ausgang und miß die Spannung an M-BUS. R3 muß natürlich vorhanden sein.

Was mißt Du im Vergleich zum Pro Mini?

Hallo Agmue,
herzlichen Dank dafür, dass Du Dir das trotz fehlendem Youngtimer und Alpine CD-Wechsler im Kofferraum anschaust. Ich habe die Hardware ja in der von Picohari abgewandelten Form im Einsatz:
image

Aber das scheint in der Tat auf TTL ausgelegt zu sein (musste erstmal suchen, was das ist, ich kannte es nur aus meinem Fachgebiet als "Through-the-lens"). Jörg Hohensohn schreibt dazu ja:

The bus uses a single wire and half duplex transmission. At both the radio and the CD changer end it is pulled high to about 10 volts idle level, with resistors in the range of 1800 Ohms. Both devices can now drive the bus low with their open collector outputs.

So it is not really TTL friendly. I used a piece of circuitry like below on my end, to feed it into a microcontroller

Picohari beschreibt das Prinzip so:

The signals generated by the microcontroller [OUT] are inverted: a logic "1" (5V) on the output pin pulls down LOW the line on the bus through Q1. A logic "0" will keep it HIGH by the internal pull-up resistor in the head-unit.

If the bus line goes LOW and the beginning of a logic "1" is signalled by the falling edge, R1 pulls the level on the receiving pin [IN] to HIGH and the ISR is triggered.

On the AVR ATmega128 pin PD4 is used as input for receiving packets (Input Capture Pin Timer 1: ICP1) and PD5 is configured as output pin to drive the bus line LOW.

Logikanalysator / Oszilloskop habe ich (noch) nicht. Du meinst, ich soll ein Signal auf den Ausgang der Schaltung geben, aber ohne dass das Ganze am Esp32 und am Alpine angeschlossen ist? Pulsieren könnte ich es wohl nur durch Drehen am Voltage-Regler des Netzteils.

Das sind ICs mit 5 V Versorgung und logischen Leveln. Spannung und Strom an OUT müssen Q1 zuverlässig nach GND schalten. Die Frage ist nun, ob das die 3,3 V eines ESP32-Ausgangs auch können.

Ein Programm schaltet den ESP32-Ausgang 5 Sekunden auf HIGH und 5 Sekunden auf LOW, dann hast Du genügend Zeit, mit dem Multimeter die Spannung an M-BUS zu messen.

Ok, vielen Dank. Ich werde mir jetzt erst einmal Grundkenntnisse der (Esp32-)Programmierung aneignen, denn selbst für ein Miniprogramm wie das, um einen GPIO für eine Zeit ein- und dann wieder auszuschalten muss ich erstmal recherchieren, und das ist ja auf Dauer kein Zustand. Speziell falls es dann irgendwann mal an den Bluetooth-Part geht...
Muss ich denn die 5 Volt wie auf Picoharis Schaltungsbild einspeisen? Beim Pro Mini funktioniert das wie beschrieben kpl. ohne, d.h. auch R1 wäre verzichtbar.
Ich bin jetzt allerdings erst einmal drei Tage unterwegs und werde mir dann nach Ankunft am Zielort meinen Basteltisch neu aufbauen...

Guten Morgen,
wahrscheinlich wartet Ihr schon ganz aufgeregt auf meine Messergebnisse :wink:
Leider war der Wagen (samt HU) auf besagter Tour unverschuldet in einen Unfall verwickelt und steht seitdem in der Werkstatt, da sich die Teilebeschaffung erwartungsgemäß langwierig gestaltet. Ende der Woche soll ich ihn wieder bekommen, dann geht's weiter.

Guten Abend,
den verunfallten Wagen habe ich zwar immer noch nicht wieder, konnte mir aber zumindest die Tasche mit dem Elektronikkram und das Radio holen, sodass ich endlich weitermachen kann.

Mit diesem Sketch:

#define LED 23
#define MOUT 22
void setup()
{
pinMode(LED, OUTPUT);
pinMode(MOUT, OUTPUT);
}
void loop()
{
digitalWrite(LED, HIGH);
digitalWrite(MOUT, HIGH);
delay(15000);
digitalWrite(LED, LOW);
digitalWrite(MOUT, LOW);
delay(15000);
}

(LED habe ich parallel laufen, um die Phasen zu sehen) bekomme ich an M-BUS gegen GND:
0,1 mV bei HIGH
40 mV bei LOW

Das ohne die 5V wie im Plan einzuspeisen, da die Schaltung am Arduino wie oben beschrieben ohne dies funktioniert.

Und jetzt?
Viele Grüße
Martin

R3 verringern oder Q1 durch einen Optokoppler ersetzen?

Guten Morgen,

Das sind ICs mit 5 V Versorgung und logischen Leveln. Spannung und Strom an OUT müssen Q1 zuverlässig nach GND schalten. Die Frage ist nun, ob das die 3,3 V eines ESP32-Ausgangs auch können.

sicher, dass es an den 3,3 Volt liegt? Ich frage, weil das Ganze ja auf einem Arduino Pro Mini in der 3,3 Volt-Ausführung klaglos läuft. Der sollte ja auch nur 3,3 Volt auf den Pins haben, oder?

Wie müssten denn die Messwerte im Idealfall sein?

Natürlich nicht!

Eine berechtigte Frage, da ich von 5 V ausgegangen bin, denn ich habe nur die.

Das weiß ich leider auch nicht, da ich den M-Bus ja nicht kenne. Aber Du kannst das herausfinden, in dem Du am Radio M-Bus gegen GND mißt. Das sollte ein Wert zwischen 5 und 12 V sein. Die früher übliche Elektronikspannung war 5 V, oder eben 12 V vom Auto, wenn Dein Jaguar nicht mit 6 V arbeitet. Mein erster Käfer hatte 6 V, daher erinnere ich mich an diese Möglichkeit.

Theorie: Im Radio sollte ein PullUp-Widerstand verbaut sein, der den M-Bus auf eine konstante Spannung zieht. Mit dem Transistor wird diese Spannung nach GND gezogen. Ein bipolarer Transistor besteht vereinfacht aus zwei Dioden, weshalb anstelle 0 V minimal die Diodendurchlaßspannung, ja nach Halbleitermaterial weniger als 60 mV, übrig bleibt. Wenn Q1 sperrt, liegt am M-Bus die vom Radio erzeugte Ruhespannung, also vermutlich 5 bis 12 V.

Nur zur Sicherheit, nicht dass ich da etwas falsch verstanden habe: Ich habe gemessen, ohne dass die Schaltung mit dem Radio/M-Bus verbunden war. Hätte sie sein sollen?

Das sollte ein Wert zwischen 5 und 12 V sein. Die früher übliche Elektronikspannung war 5 V, oder eben 12 V vom Auto

Ja, der hat schon 12 Volt (mehr oder weniger, da die Jaguar Elektrik von der Fa. Lucas Electrical stammt (in Fachkreisen auch "Master of Darkness" genannt ;)). Jörg H. und Picohari sprechen von ca. 10 V:

The voltage on the M-Bus is about 10V and drops off very quickly if the load is too high.

Jetzt weiß ich allerdings nicht so genau, wie/wo ich weitermachen sollte...

Ja, denn die Spannung am M-Bus kommt vom Radio.

  1. Spannung vom M-Bus am Radio ohne weitere Beschaltung messen.
  2. Pro Mini mit Schaltung an das Radio anschließen und Spannung vom M-Bus bei HIGH und LOW messen.
  3. ESP32 mit Schaltung an das Radio anschließen und Spannung vom M-Bus bei HIGH und LOW messen.

Gemessene Spannung gleich Versorgungsspannung = 12 V, fällt alle paar Sekunden für ca. 0,5 Sekunden auf 10,x V.

HIGH (LED AN): 1,2 mV
LOW (LED aus): 9,16 V

HIGH (LED AN): 1,8 mV
LOW (LED aus): 9,16 V

Scheint also bei Arduino und Esp32 vergleichbar zu schalten und wohl so, wie es soll.

Sehe ich auch so.

Jetzt die umgekehrte Richtung, also 2. und 3. wiederholen und an IN messen. Mittels digitalRead(IN-Pin) eine zweite LED schalten. Wenn die eine an ist, sollte die andere aus sein.

Wenn ich auf R1 keine 5 Volt gebe, sondern garnichts (zur Erinnerung: So funktioniert das Ganze mit dem Arduino Pro Mini, ich habe es zur Sicherheit gerade noch einmal ausprobiert), dann sieht die Spannung an MINPUT so aus:

ESP32
LED1 aus = LOW: ca. 0V
LED1 an = HIGH: steigt in 15 sec kontinuierlich auf ca. 300 mV
LED2 immer aus

Arduino Pro Mini
LED1 aus = LOW: ca. 0 V
LED1 an = HIGH: steigt in 15 sec kontinuierlich auf ca. 140 mV
LED2 immer aus

Wenn ich R1 mit den 3,3 V vom ESP32-Board beschicke (5 Volt habe ich mich nicht getraut),
LED1 aus = LOW: springt auf Werte zwischen 0 und 250 mV
LED1 an = HIGH: 3,3 Volt

Wenn ich LED 2 hier parallel an den IN-Pin anschließe, glimmt sie, wenn LED1 an ist und blinkt ca. alle 2 sec, wenn LED1 aus ist. Die Spannung am IN-Pin sinkt bei HIGH auf 1,7 Volt.

Vielleicht habe ich ja auch wieder die Messanleitung falsch verstanden. Ich habe:
-IN aus der Schaltung an Pin 21 (MINPUT), dort auch (über 330 Ohm Widerstand) LED2, dort messe ich auch die Spannung gegen GND.
-OUT an Pin 23
-LED1 an Pin 22

Sketch ist dieser:

/* ESP32 */
#define MINPUT 21
#define LED1 22
#define MOUT 23

///* Arduino Pro Mini */
//#define MINPUT 10
//#define LED1 11
//#define MOUT 12
void setup()
{
pinMode(LED1, OUTPUT);
pinMode(MOUT, OUTPUT);
pinMode(MINPUT, INPUT);
}
void loop()
{
digitalWrite(LED1, HIGH);
digitalWrite(MOUT, HIGH);
digitalRead(MINPUT);
delay(15000);
digitalWrite(LED1, LOW);
digitalWrite(MOUT, LOW);
digitalRead(MINPUT);
delay(15000);
}

Es verwirrt mich.

Das tut nichts Sinnvolles, besser:

digitalWrite( LED2, digitalRead(MINPUT) );

Danke für Deine Geduld!

2. IN-Messung esp32, 3,3 Volt auf R1
LED1 aus, LED2 an: springt zw. 10 und 100 mV
LED1 an, LED2 aus: 3,3 Volt

2. IN-Messung esp32, nichts auf R1
LED1 aus, LED2 aus: 0 Volt
LED1 an, LED2 aus: steigt bis 400mV, fällt dann ab und steigt erneut

2. IN-Messung Arduino, 3,3 Volt (von VCC Pin) auf R1
LED1 aus, LED2 an: springt zw. 10 und 100 mV
LED1 an, LED2 an: 3 Volt
LED2 ist hier also immer an, obwohl MINPUT in en mV-Bereich abfällt.

2. IN-Messung Arduino, nichts auf R1
LED1 aus, LED2 aus: 0 Volt
LED1 an, LED2 aus: steigt bis ca. 200mV

Sketch:


/* ESP32 */
//#define LED1 22
//#define LED2 19
//#define MINPUT 21
//#define MOUT 23

/* Arduino Pro Mini */
#define LED1 11
#define LED2 13
#define MINPUT 10
#define MOUT 12
void setup()
{
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(MOUT, OUTPUT);
pinMode(MINPUT, INPUT);
}
void loop()
{
digitalWrite(LED1, HIGH);
digitalWrite(MOUT, HIGH);
digitalWrite(LED2,digitalRead(MINPUT) );
delay(15000);
digitalWrite(LED1, LOW);
digitalWrite(MOUT, LOW);
digitalWrite(LED2,digitalRead(MINPUT) );
delay(15000);
}

IN- und OUT-Pins der Schaltung sind an Esp32 bzw. Arduino angeschlossen; M-BUS am Radio.

Von der springenden Spannung mal abgesehen, entspräche 1 meiner Erwartung. Warum sich 1 und 3 unterscheiden, erschließt sich mir leider überhaupt nicht. Da verbreitet sich bei mir Ratlosigkeit :roll_eyes:

Die unterscheiden sich doch garnicht so sehr, außer dass LED2 halt immer an ist. Mir ist beim Rumprobieren schon aufgefallen, dass der Arduino "träge" reagiert, d.h. etwa einen Pin-Zustand auch dann beibehält, wenn man zwischendurch die 3,3 Volt abzieht. Erst im nächsten Zyklus wird das dann "bemerkt".
Oder meinst Du die 3 vs. 3,3 Volt?

Mit delay legst Du ihn schlafen, während der Zeit tut er nichts. Das kann ich erklären.