Hallo.
Ich versuche mich gerade daran mit dem STM32F3 Discovery Board meinen
ersten 32-Bit ARM zu programmieren. Bis jetzt habe ich erfolgreich die
onboard LED's mit einem Timer blinken lassen. jetzt möchte ich als
Vorbereitung auf mein nächstes Projekt den I2C Bus verwenden. Als
Einstieg hab ich drei LED's an den MCP23017 Port Expander gehängt und
möchte die zum leuchten bringen.
Allerdrings scheitert es wohl schon am richtigen Initialisieren vom I2C
Bus.
Ich möchte den I2C_2 Bus nehmen an PinA09 und PinA10. Ich habe diverse
Codeschnipsel für die STM32F Serie im Internet gefunden und meiner
Meinung nach müsste ich zumindest am Clock Pin den Takt messen können,
jedoch zeigt mein Oszilliskop nur dauerhaft 3 Volt an und das Programm
bleibt beim Debuggen bei der Überprüfung des transmit interrupted flags
hängen. Auch am Datenpin messe ich nur konstante 3V von den 1kOhm
Pull-Up Widerständen.
Hier ist mein Code
1
intmain(void)
2
{
3
4
5
SystemInit();//System Clock auf Extern, also 72MHz einstellen
Ich Messe am IC ca. 2,95V benutze aber zur Spannungsversorgung vom IC
die 3V output von dem Board und das BOard ist üer den ST-Link USB am PC
angeschlossen. Das sollte eigentlich ja passen.
Auf dem F4 Disco Board initialisiere ich zuerst den Port und dann das
I²C Interface, das klappt so. Evtl. (ich habs andersrum nie ausprobiert)
solltest du das auch so machen.
Ausserdem fehlt mir in deiner Schreibroutine das Erzeugen der Stop
Bedingung(?). Hier mal ein Stückchen Code für I2C1 auf dem F4,
ursprünglich von Uwe B:
Entschuldigung, dass ich mich erst so spät wieder melde. Ich hatte die
Tage nicht viel Zeit zum programmieren und werde wohl die nächsten Tage
auch nicht dazu kommen.
Wie dem auch sei, erstmal zu hp-freund. Die delayzeit sind takte und
keine mS. Der delay ist ca 1 Sekunde und ich hab mit der Zahl auch schon
LEDs im 1 Sekunden Takt bekommen blinken lassen.
Dann zu Matthias Sch. Ich muss bei dem Code erstmal einige Flags
umbenennen, da die bei dem F3 anders heißen und danach kann ich sagen ob
mir das geholfen hat, aber trotzdem schon mal danke, dass du den Code
hier gepostet hast.
Ich hab auch nochmal eine allgemeine Frage. Muss nicht sobald ich den
I2C initialisiert habe beim SCL pin der 100kHz Takt Anliegen? Ich messe
da zumindest vom Start des Controllers bis zu dem punkt, an dem er fest
hängt keinen Takt.
Guten Tag.
Ich hab das Problem gerade selbst mit Hilfe des I2C Examples von der
CooCox IDE, die ich benutze, lösen können.
Das Problem war, dass bei dem STM32F3 nicht die I2C_Flag_... sondern
I2C_ISR_... Flags abgefragt werden müssen.
Hier für alle, die durch fleißiges Googeln hier drauf stoßen nochmal
mein funktionierender Code.
Hallo Zusammen!
Ich verwende das STM32F3 Discoveryboard und versuche den
LidarLite-Sensor über I2C2 auch an denselben Pins zu initialisieren. Der
Sensor verfügt über interne 4.7k PullUp-Widerstände. Ich nutze CooCox in
der Version 1.7.8 zum Programmieren und Debuggen.
Das obige Programm habe ich praktisch 1zu1 übernommen, bei mir hängt es
sich allerdings an genau derselben Stelle auf, an der es bei Killerawft
zuerst aufhing, obwohl ich den überarbeiteten Code übernommen habe. Im
main geht die Initialisierung durch, die Lidar_Write-Funktion hängt sich
allerdings bei der ersten Flag-Abfrage auf.
Ich sitze schon den 2. Tag an dem Problem die Kommunikation zu
initialisieren und komme nicht weiter.
Würdet ihr mir bitte dabei helfen Fehlerquellen auszuschließen? Ich gehe
mittlerweile davon aus, dass es sich um ein Hardwareproblem handeln
muss!?
Anbei mein Code:
DEFINES
1
#include"stm32f30x_gpio.h"
2
#include"stm32f30x_rcc.h"
3
#include"stm32f30x_i2c.h"
4
5
#include"stm32f30x.h"
6
#include<stddef.h>
7
#include<stdlib.h>
8
#include<stdbool.h>
9
10
/* Define LEDs */
11
12
#define LIDARLite_ADDRESS 0x62 // Default I2C Address of LIDAR-Lite (7bit)
13
#define LIDARLite_WRITE 0xC4 // Default Write Address of LIDAR-Lite.
14
#define LIDARLite_READ 0xC5 // Default Read Address of LIDAR-Lite.
Am Ende war es ein Hardwareproblem.
Der Sensor hat seine Versorgungsspannung (5V) über ein externes Netzteil
erhalten, das wohl zu einem leichten Einbruch auf der Clockleitung
geführt hat, bevor der erste Clockimpuls kam. Die Grenzschwelle des
Sensors scheint wohl sehr niedrig zu sein, da sie den Impuls erkannt
haben muss. Der Sensor lieferte nur ein Nack.
Durch Verwendung der 5V-Versorgungsspannung auf dem Board wird nun das
Ack geliefert.
Hi, ich habe ebenfalls das Problem, dass ich das Lidar Lite 2 über I2C
im STM32 steuern möchte.
Ich nutze allerdings die CPAL von ST.
Das Initialisieren des I2C1-Devices im STM32 funktioniert.
Ich bekomme nach den Funktionen
i2cdevInit() und CPAL_I2C_IsDeviceReady() die Bestätigung.
Beim eigentlichen Lese- oder Schreibzugriff bekomme ich allerdings
sofort ein NACK und alle weiteren Operationen sind obsolet.
Ich arbeite ebenfalls mit einer externen Spannungsversorgung.
Über Hilfe würde ich mich sehr freuen.
Viele Grüße,
Che
Hi!
Verschicken die CPAL Funktionen ein Signal über I2C? Wenn ja, bekommst
du da ein ACK? Falls sie kein Signal über I2C schicken, werden sie wohl
den Bus initialisieren.
Es ist höchstwahrscheinlich ein Hardwareproblem. Schau dir mal die
folgende Inetseite an:
http://www.i2c-bus.org/i2c-primer/common-problems/
Oder passe Rp an:
http://www.i2c-bus.org/i2c-primer/typical-i2c-bus-setup/
Musst du ein externes Netzteil benutzen? Ändere Kabellängen.
Probier auf jeden Mal als Erstes die Spannungsversorgung vom Board um
den Sensor in Betrieb zu nehmen. Als PullUps sorgten bei mir 2,2k für
ein sauberes Signal.
Viel Glück, viel Erfolg!
Hi,
als allererstes vielen Dank für deine Antwort.
Die CPAL-Bibliothek ist ein abstraktes Interface um die I2C-Geräte zu
initialisieren, drauf zu schreiben und zu lesen.
Leider habe ich kein I2C-Analysegerät (allerdings ein analoges
Oszilloskop [VOLTCRAFT 632FG]), deswegen kann ich nicht bestätigen, dass
mein STM32 tatsächlich ein I2C-Signal aussendet.
Da die Bibliothek so abstrakt ist, kann ich nicht nachvollziehen welche
genauen Signale überhaupt versendet werden, und wie ich einzelne Bits
schicke etc.
Ich arbeite auch nicht mit dem o.g. Discovery Board. Der STM32 ist Teil
der Crazyflie 2.0 [Link: https://www.bitcraze.io/crazyflie-2/], deswegen
muss ich die externe Spannungsquelle nutzen (Vcc liefert mir nur 3.0V).
Evtl baue ich später einen Hochsetzsteller ein...
Die Seite, die du empfohlen hast, habe ich angeschaut.
*Die Spannungsversorgung aus dem Netzteil sollte stabil sein.
*Kabellängen habe ich gerade varriert, leider ohne Erfolg.
*Die Pullups habe ich auf ca. 3k gesetzt, allerdings glaube ich, dass
das System so konfiguriert ist, dass der SDA intern schon einen Pullup
hat (laut Entwicklern
(https://forum.bitcraze.io/viewtopic.php?f=6&t=1733&start=20)).
*Wie checke ich denn, ob die I2C-Supply-Voltages kompatibel sind? Ich
dachte, die wären genormt.
Hast du vielleicht noch einen Tipp? Ich könnte mir auch vorstellen, auf
die CPAL zu verzichten. Allerdings kann ich mir gerade noch nicht
vorstellen, wie ich die Kommunikation dann ins Gesamtsystem einbinde
(FreeRTOS).
Viele Grüße,
Che
Benutz mal LIDARLITE_ADDRESS, die Beschreibung des Herstellers mit den
Read und Write Addressen ist irreführend, da das neunte Bit vom
Addressat geliefert wird(N/ACK). Vielleicht löst das bereits dein
Problem.
Ich benutze noch die StdPeriphLib. Die CPAL wurde erst vor Kurzem
eingeführt. Ich habe mich auch kurz damit befasst, bin aber dann doch
lieber konservativ geblieben. Welche Software benutzt dein Crazyfly?
Wenn andere Sensorik bereits implementiert ist, kannst du das im
entsprechenden .c-File nachschauen ob die StdPeriphLib bereits benutzt
wird. Das ist wohl eher wahrscheinlich, da deine Software wohl schon
seid geraumer Zeit verwendet wird. Ein RTOS hin oder her.
Bei einem RTOS werden Tasks initialisiert in denen deine Funktionen
ausgeführt werden. Die stm32f3-spezifischen Funktionen, wie die
i2c-initialisierung, wird vorher definiert. Wenn deine Software nicht
auf CPAL beruht, muss die CPAL mit eingebunden werden. Das frisst
sicherlich einige Ressourcen. Bedenke, das bei einem Softwareprojekt wie
bei deinem der Flash schnell gefüllt sein kann.
Viele Grüße
Den Tipp, die Adresse zu shiften, habe ich direkt ausprobiert. Ich
bekomme immernoch den Errorcallback 0x0400
https://github.com/bitcraze/crazyflie-firmware/blob/master/lib/STM32_CPAL_Driver/inc/cpal_i2c.h#L104
Bitcraze hat ein Interface geschrieben, dass nochmal über der
CPAL-Bibliothek liegt. Diese Zugriffsfunktionen shiften die Adresse
ebenfalls, deswegen bin ich unsicher, ob das Vorherige shiften notwendig
ist. Was meinst du dazu?
Beispiel:
Auf der Crazyflie ist noch ein anderes I2C-Device (IMU) verbaut, das
wird ebenfalls per CPAL implementiert. Das EEPROM im übrigen auch.
So wie ich das sehe, ist die StdPeriphLib auch verfügbar, ob die
irgendwo genutzt wird, habe ich noch nicht gecheckt.
Es handelt sich auch um den STM32F405. Aber die Bibliotheken sind alle
vorhanden, glaube nicht, dass das eine Rolle spielt (nur FYI).
Ich würde jetzt als nächsten Ansatz das Lidar per StdPeriphLib versuchen
einzubinden. Oder mache ich da jetzt einen Denkfehler?
Viele Grüße,
Che.
Ja, das shiften wird in der Funktion bereits ausgeführt.
Der eignetliche Transfer findet in der Funktion i2cdevReadTransfer
statt. Überprüfe die Funktion darauf ob sie tatsächlich nach der
Registeraddressierung eine STOP und eine START-Kondition ausführt:
http://lidarlite.com/docs/v2/i2c_protocol_summary/
Es könnte nämlich sein, dass das NACK dann ankommt, wenn das anders
ausgeführt wird. Diese Vorgehensweise ist nicht immer so.
Testest du immer die Read-Funktion? Nimm die WriteFunktion um weitere
Fehlerquellen auszuschliessen. Du solltest auch erstmal den Sensor
konfigurieren, mit 0x00 an 0x00(Default).
(siehe configure-Funktion:
https://github.com/PulsedLight3D/LIDARLite_v2_Arduino_Library/blob/master/LIDARLite/LIDARLite.cpp)
Auf der Crazyfly könnte der andere I2C-Bus für die erwähnten Devices
benutzt werden. Stelle sicher, dass der I2C-Bus, den du benutzt
initialisiert wird.
Wie gesagt, es ist aller Wahrscheinlichkeit nach ein Hardwareproblem,
daher eine andere Library zu benutzen unnötig, es wird wieder auf das
NACK hinauslaufen. Nimm das Oszilloskop und schau das Signal an. Achte
auch darauf, dass bei der Write-Funktion der Bus seine 100kHZ hat. Wenn
die Vorraussetzungen stimmen, dann liegt es an der ext.
Spannungsversorgung.
Hast du ein anderes Dev.Kit zur Verfügung? Ein Discoveryboard vllt?
Teste auch mal den PWM-Output um die Funktion des Lidarsensors zu
verifizieren. Hast du eine andere Spannungsquelle? Akku, oder ein Board
mit Spannungswandlern?
Wie man sieht, geht das Durchreichen von "dev" hier weiter. Konditionen
werden erst in der CPAL gesetzt.
Die Funktion CPAL_I2C_Read() hat ca 250 Zeilen mit vielen If-Defs.
Ich versuche mal den meiner Meinung nach wesentlichen Teil zu
extrahieren:
1
...
2
...
3
#ifdef CPAL_I2C_MASTER_MODE
4
/* If "No Memory Address" Option Bit is not selected and Master Mode selected */
Reicht es also aus, vor dem
__CPAL_I2C_HAL_START(pDevInitStruct->CPAL_Dev);
ein
__CPAL_I2C_HAL_STOP(pDevInitStruct->CPAL_Dev);
zu setzen?
Ich teste das, bevor ich deine anderen Tipps durcharbeite.
PS.
Die i2cdevReadTransfer habe ich bereits umgeändert, ich habe die
NOSTOP-Option auskommentiert.
Seit dem ändert sich das Verhalten folgendermaßen.
*Kein NACK mehr bei schreiben von 0x04 auf 0x00 (Lesemodus des Lidar
aktivieren lt. Handbuch).
*Kein Nack mehr bei lesen von diversen Registern, allerdings sind alle
Werte aus allen Registern und Adressen dann null.
*Nach ein paar Zyklen bekomme ich schließlich manchmal doch noch ein
NACK-Fehler, woraufhin alle Register den Wert 32 bekommen [0x20 Hex =
0010 0000]
BIS AUF das Statusregister 0x01. Dort habe ich den Dezimalen Wert 224
[0xE0 = 1110 0000]. Lt. Handbuch wäre das sogar ein halbwegs plausibler
Wert.
Na das sieht doch schon mal gut aus!
Was die Statusbits bedeuten, kann nachgeschlagen werden:
(0x01 - Mode/Status (control_reg[1]:):
http://lidarlite.com/docs/v2/registers/)
Ich würde jetzt eine einzelne Distanzmessung vornehmen:
siehe distance - Funktion
(https://github.com/PulsedLight3D/LIDARLite_v2_Arduino_Library/blob/master/LIDARLite/LIDARLite.cpp)
Passen die Distanzwerte in etwa? Die Distance-Write-Anweisung führt zu
einer Akquirierungsanweisung. Je nachdem wie die Licht und
Signalstärkeverhältnisse sind kann eine Akquirierung bis zu 20ms
andauern. Hierzu werden intern mehrere Messungen vorgenommen. Die
Messung ist vollendet sobald eines der Status-Overflow-Flags gesetzt
wird(zu schlechte Verhältnisse führen zu einer fehlerhaften Messung(bsp.
>4000cm)ohne setzen eines der Bytes). Entweder Flag überprüfen und dann
mit der ReadFunktion 2 Bytes von 0x8f auslesen, oder eine Mindestzeit
abwarten. Das Auslesen des Registers während der nicht abgeschlossenen
Akquirierung führt zu möglicherweise fehlerhaften Werten.
Viel Erfolg!
So, also die CPAL-Funktion kann ich natürlich nicht einfach ändern, da
die Bibliothek ja noch von dem anderen o.g. Gerät verwendet wird. Wenn
ich da einfach ein STOP einfüge funktioniert das natürlich nicht mehr.
Ich habe das Lidar auf meinem Raspberry mit derselben Konfiguration
erfolgreich getestet. Externe Spannungsquelle, Raspi und Lidar nur per
SDA, Clock und GND verbunden.
Wie teste ich denn mit dem Analogen Oszi auf die richtige Frequent beim
Schreiben? Bräuchte da vielleicht noch einen Hinweis.
LG,
Che.
Da haben unsere Antworten sich überschnitten.
Also ich habe auch die Higher und Lower Abstandsregister ausgelesen
(habe aber bei beiden den Wert 0, wo er eigentlich etwas drin stehen
haben müsste).
Ich bin mir noch nicht sicher, ob die Software-Konfiguration schon so
stimmt.
Beim Oszi Wellenlänge ausmessen und Frequenz bestimmen: f=1/lambda
Wenn die Register 0 wiedergeben, was sagt das Bit3 des Stausbytes?
Sicher, dass du die Write und Read-Anweisungen korrekt ausführst? Falls
es immer noch nicht klappt, füg mal den entsprechenden Code an. Dann
kann man sich das anschauen.
Im Anhang meine .c Datei und ein Screenshot von der Konsolenausgabe
(konnte ich leider nicht anders einbinden, da meine Virtuelle Maschine
kein C&P zulässt).
Ein paar 0-Zyklen habe ich aus der Ausgabe gelöscht um auch den Fehler
darzustellen.
In void rangeInit(void) liefert lidarInit(I2C1_DEV); oder lidarTest();
I2C connection FAIL!?
Du solltest die Konfiguration in deiner Initialisierung vornehmen, da du
sonst in der While-Schleife immer wieder neu konfigurierst.
In der While-Schleife einfach mal nur:
Akquierierungsanweisung, und auslesen.
Ist uint16_t registerAddr tatsächlich 16bit lang?
In der Funktion lidar_getRegister() übergibst du nur registerAddr, aber
nicht I2Cx und devAddr. Das musst du anpassen, so kann das gar nicht
funktionieren. Sieht lidar_setRegister() auch so aus? Die Parameter
müssen korrekt an i2cdevRead/Write weitergegeben werden.
Benutze lieber vorerst die auskommentierten Funktionen
Bei der ReadFunktion den 5. Parameter nicht vergessen: Du kannst auch
gleich 2 bytes aus 0x8f lesen.
Und bitte nicht immer den FPGA Resetten:
Einmal konfigurieren und dann in der Schleife erstmal
Akquirierungsanweisung und auslesen.
lidarTest() liefert I2C connection FAIL. Ich habe die Funktion aus einem
anderen I2C-Device kopiert (von Bitcraze), ganz verstanden habe ich es
nicht, daher hab ichs gerade wieder rausgeworfen.
In dem Code, den ich angehängt hatte, sind die Resets vom FPGA
auskommentiert. Leider ist das Kommentierungszeichen nach links
verrutscht, sorry dafür. Oder meintest du noch eine andere Stelle?
Ich habe jetzt den Reset in der Init-Funktion stehen.
Im Loop lediglich die Prints, den Acquisition (write) und den Read.
Ich bekomme da jedoch von dem Register im Data dann immernoch die 0.
Die uint16 habe ich auf uint8 geändert.
rv schrieb:> In der Funktion lidar_getRegister() übergibst du nur registerAddr, aber> nicht I2Cx und devAddr. Das musst du anpassen, so kann das gar nicht> funktionieren. Sieht lidar_setRegister() auch so aus? Die Parameter> müssen korrekt an i2cdevRead/Write weitergegeben werden.
Ich habe hier die lidar.c nicht gepostet. Da habe ich einen Platzhalter
für I2C1 definiert, damit man auch die anderen beiden Devices benutzen
kann. Das Prinzip habe ich ebenfalls von Bitcraze übernommen.
Bevor der Code näher untersucht wird:
Hast du das I2C-Signal bereits mit dem Oszilloskop verifiziert?
Bitte als Erstes nachholen um zu überprüfen, ob der Code wirklich das
tut was er soll und was du denkst, das er macht.
Vielleicht hast du ja auch Zugriff auf einen Analyzer wie bspw.
IKALOGIC, ist aber nicht absolut notwendig.
Ich weiß nicht genau, was ich mit dem Oszilloskop messen soll. Das es
sich um ein Analogmessgerät handelt, hatte ich ja schon erwähnt.
Ich dachte, damit lassen sich nur periodische Signale darstellen.
Also könnte ich höchstens das Clock-Signal verifizieren, aber wie genau?
Ich bekomme immer nur kleine Bursts angezeigt, ungefähr im Abstand der
Zykluszeit meiner Task. Aber ob die Frequenz stimmt, kann ich nicht
sagen.
Viele Grüße
Du kannst beide Signale triggern. Dann die Auflösung verändern um die
"Bursts" genauer anzuschauen. Lerne den Umgang mit dem Oszi, es ist
neben dem Multimeter das wichtigste Messinstrument eines Elektronikers!
Hi, ich musste etwas rumfrickeln, damit das Signal stabil bleibt.
So siehts jedenfalls aus, unten ist das Clock-Signal und oben das
Data-Signal zu sehen.
Mir scheint es, als wäre die Ausgabe des STM32 in Ordnung, allerdings
bekomme ich vom Lidar keinerlei Rückmeldung.
Viele Grüße
Ich habe gerade keine Kamera da um dir zu zeigen, wie das aussehen
sollte.
Ich kann es nicht genau erkennen, aber verändert sich die Frequenz auf
der Clockleitung?
Hast du noch ein zweites Signal auf der Leitung? -> DC-Signal bei SDA ab
ca. der Hälfte.
Das sieht insgesamt nicht gesund aus.
Zunächst mal die Frage: Sind noch andere Devices an dem Bus
angeschlossen, oder besteht die Kommunikation nur mit dem LidarSensor?
Falls noch andere Devices am Bus liegen, abschalten. Nur die Komm. mit
dem LidarSensor verifizieren.
Allgemein würde ich empfehlen den LidarSensor unabhängig von der
CrazyflySoftware zu testen, da es ja auf Anhieb nicht funktioniert. So
werden einige Fehlerquellen ausgeschlossen.
-> Eigenes Projekt nur für den Lidar aufsetzen.
Man könnte es annehmen, dem Bild zufolge, dass sich die Clock verändert.
Aber kann das nicht auch an der Triggerung liegen?
Die Leitung sollte exklusiv für das Lidar genutzt werden. Ich habe kein
zweites Device dranhängen.
Ich würde als nächsten Schritt meine betreuende Professorin fragen, ob
ich ein STM32 Dev Kit gesponsort bekomme, das Lidar erstmal nur mit dem
STM32 zu testen scheint mir auch der sinnvollste Weg.
Falls du eine Kamera organisieren kannst (evtl vom Smartphone?) würde
ich mich trotzdem noch über ein Foto freuen.
Viele Grüße
Es sieht so aus, als würde die CPAL keine STOP-Condition nach dem lesen
senden. Deswegen bekommt man keine Werte zurück, da das Lidar nach bzw
vor jedem Vorgang ein STOP braucht.