Hallo,
ich hab ein sehr seltsames Problem mit den I²C-Funktionen des
HAL-Library.
Ich nutze den DMA-Mode für die I²C-Schnittstelle.
An der Schnittstelle hängt ein 0,96" Oled-Display mit einem SSD1306.
Pullup-Widerstände (1k2 bei 3,3V) sind auch bestückt.
Das Board ist ein MapleMini mit ST32F103C8-CPU.
Der Transfer selbst ist auch gar kein Problem, und bevor ich ein neues
Datenpaket absende, überprüf ich zunächst mit "HAL_I2C_GetState (&hi2c1)
== HAL_I2C_STATE_READY" ob der Buffer frei ist.
Das funktioniert so auch, und die Initialisierung läuft auch wie
erwartet.
In der Initialisierung läuft das noch geblockt, und ich warte vor jedem
Transfer darauf, daß der Treiber READY liefert.
Die Funktion void oled_worker() wird bei jedem Durchlauf der main-loop
einmal aufgerufen, und bei jedem Aufruf wird für eine Row im Display
(128 Byte entspr. 8 Zeilen zu 128Pixel) geprüft, ob sich was am
Pufferinhalt geändert hat, und ggf. der Transfer über I²C angestossen
(max 128 Byte + 7 Befehlsbyte).
Vor dem eigentlichen Senden prüfe ich wieder ob der Puffer frei ist.
Wenn das nicht der Fall ist, wird die Funktion beendet, (non-blocking)
und beim nächsten Aufruf wiederholt sich das Spiel bis der Puffer frei
ist.
Jetzt wirds allerdings spannend:
Wenn ich mir bei dem diesem Transfer-Kommando (ziemlich am Ende der
Datei) einen Breakpoint setze, und dann manuell fortsetze, läuft es wie
erwartet, aber wenn ich das Programm einfach starte, wird Müll auf dem
Display ausgegeben.
Es hat etwas Mühe gekostet, das Problem auf genau diesern Punkt
einzugrenzen.
Wenn ich -testweise- nach dem Send-Command ein HAL_delay() einfüge muß
das Delay min. 4 sein (zw. 3 und 4ms) damit das Programm fehlerfrei
läuft.
Wenn ich das Delay auf 3 stelle (zw. 2 und 3ms), kommen wieder falsche
Zeichen.
Der Transfer einer Zeile dauert ca. 2,7ms, was sich mit dieser Wartezeit
deckt.
Ich vermute also, daß das Send-Kommand bereits aufgerufen wird, obwohl
noch ein Transfer läuft.
Ist es möglich, daß HAL_I2C_GetState() mir falsche Daten liefert, oder
hab ich irgendwas übersehen?
Harry
1
/*
2
* oled_worker.c
3
*
4
* Created on: 17.04.2016
5
* Author: harry
6
*/
7
8
#include<string.h>
9
#include<stdlib.h>
10
#include"stm32f1xx_hal.h"
11
#include"oled.h"
12
#include"needle.h"
13
14
#define OLED_IDLE 0
15
#define OLED_UPD_PAGE 1
16
#define OLED_UPD_LINE 2
17
#define OLED_NEEDLE_MOV 3
18
#define OLED_VAL_CHG 4
19
#define OLED_LINE_PREF 5
20
21
#define NEEDLE_IDLE 0
22
#define NEEDLE_UPDATE 1
23
#define NEEDLE_
24
//#define OLED_
25
//#define OLED_
26
27
#define WRK_STAT_IDLE 0
28
#define WRK_STAT_UPDATE 1
29
#define WRK_STAT_UPD_LINE 2
30
#define WRK_STAT_UPD_COL 3
31
//#define WRK_STAT_
32
//#define WRK_STAT_
33
34
staticconstuint8_tOledInit[]=
35
{0x80,0xae,// turn off oled-display
36
0x80,0xd5,0x90,// set display clock divide ratio/oscillator frequency
37
0x80,0xa8,0x3f,// set multiplex ratio(1 to 64)
38
// 1/64 duty
39
0x80,0xd3,0,00,// set display offset
40
// not offset
41
0x80,0x8d,0x14,// set Charge Pump enable/disable
42
0x80,0x40,// set start line address
43
0x80,0xa6,// set normal display
44
0x80,0xa4,// Disable Entire Display On
45
0x80,0xa1,// set segment re-map 128 to 1
46
0x80,0xc8,// Set COM Output Scan Direction 64 to 1
47
0x80,0xda,0x12,// set com pins hardware configuration
Kann es sein, dass du dem DMA über seine Daten trampelst wärend er noch
läuft und deshalb das delay einen heilenden Effekt hat?
Entweder sehe ich es nicht, aber für mich schaut es so aus, als ob
oline_buf... beim nächsten Aufruf von oled_worker geschrieben wird bevor
getested wird ob der DMA noch aktiv ist.
Gruß
Dazu müsste man die Daten auf dem Bus mal sehen. Was ich auch schon
hatte, sind IC's deren Schnittstelle schneller ist als ihre interne
Logik. Sprich es kann auch sein, dass das Display 0,3 ms benötigt, um
die Daten, die vom I2C herein kamen zu verdauen.
NACK schrieb:> Kann es sein, dass du dem DMA über seine Daten trampelst wärend er noch> läuft und deshalb das delay einen heilenden Effekt hat?
Ja, danach sieht es aus, aber es gibt keine weiteren I²C-Aufrufe im
übrigen Programm.
Ich hab das Programm bereits auf die oben gezeigten Funktionen
reduziert.
Es wird garantiert an keiner anderen Stelle geschrieben.
fop schrieb:> Dazu müsste man die Daten auf dem Bus mal sehen. Was ich auch schon> hatte, sind IC's deren Schnittstelle schneller ist als ihre interne> Logik. Sprich es kann auch sein, dass das Display 0,3 ms benötigt, um> die Daten, die vom I2C herein kamen zu verdauen.
Das hab ich mir angeschaut, und ja, es ist so, daß zu früh gesendet
wird.
Aber warum?
Das würde bedeuten, daß die HAL_I2C_GetState nicht richtig funktioniert.
Es geht auch nicht um 0,3ms, sondern um min. 3 ms, was darauf hindeutet,
daß ich bereits sende, während die Schnitstelle noch aktiv ist.
Harry
Harry L. schrieb:> Ja, danach sieht es aus, aber es gibt keine weiteren I²C-Aufrufe im> übrigen Programm.
Ja schon, aber oled_worker selbst könnte im nächsten Zyklus über die
Daten schreiben die noch nicht komplett gesendet wurden. Probier doch
mal
"if (HAL_I2C_GetState (&hi2c1) == HAL_I2C_STATE_READY)" direkt am Anfang
zu testen bevor du irgendwas in oled_worker machst.
oled_worker() -am Ende- ist aber der einzige Ort, an dem ich auf das
I²C-Subsystem zugreife.
Natürlich könnte ich direkt am Anfang prüfen, aber genau da wollte ich
das ja nicht, da an der Stelle die meiste Rechenzeit gebraucht wird (der
Vergleich der Puffer) und das kann wunderbar geschehen, während bereits
ein Transfer läuft.
Harry
Harry L. schrieb:> oled_buf[lc][j] = oline_buf.line[i++] = PicBuf[lc][j]> & needle_buf[lc][j];
Ich habe jetzt nicht versucht die ganze Logik nachzuvollziehen, aber
kann es sein, dass du den Puffer hier schon "wieder" beschreibst,
während noch ein Transfer läuft?
Ansonsten, probier doch einfach mal den Test an den Anfang zu schieben
und schau obs dann ohne delay geht.
Nur so
NACK schrieb:> Ich habe jetzt nicht versucht die ganze Logik nachzuvollziehen, aber> kann es sein, dass du den Puffer hier schon "wieder" beschreibst,> während noch ein Transfer läuft?
Oh Mann!
Das wars!
Manchmal ist man einfach betriebsblind
Herzlichen Dank!
Da muss ich wohl mit 2 alternierenden Puffern arbeiten.
Harry