Forum: Mikrocontroller und Digitale Elektronik OLED M204 von EA Initialisierungsproblem


von Wolfram L. (amazon)


Angehängte Dateien:

Lesenswert?

Hallo, jetzt habe ich doch recht viele Stunden in die Programmierung des 
folgenden Displays gesteckt:
https://www.lcd-module.de/fileadmin/pdf/doma/oledm204-a.pdf
Leider bekomme ich dem Ding keinen Buchstaben entlockt - nicht mal ein 
Cursorblinken. Mittels STM32 und SPI habe ich die folgende Sequenz 
gesendet:
1
void init_oled_m204(void)
2
{
3
  oled_cs_low;
4
  delay_us(100);
5
  oled_m204_send_startbyte();
6
  delay_us(100);
7
  oled_m204_send_cmd(0x3A);
8
  oled_m204_send_cmd(0x09);
9
  oled_m204_send_cmd(0x05);
10
  oled_m204_send_cmd(0x38);
11
  oled_m204_send_cmd(0x3A);
12
  oled_m204_send_cmd(0x72);
13
  oled_m204_send_data(0x00);
14
  oled_m204_send_cmd(0x38);
15
  oled_m204_send_cmd(0x0D);
16
  oled_m204_send_cmd(0x01);
17
  oled_cs_high;
18
}
19
void oled_m204_send_startbyte(void) {
20
  SPI_I2S_SendData(SPI1,0x5F );// Data mode is 01011111 = 0x5F
21
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); 
22
// 1 when empty register
23
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY));  
24
// 0 when transmission is finished
25
}
26
27
void oled_m204_send_data(uint8_t byte) {
28
  SPI_I2S_SendData(SPI1,byte & 0x0F );
29
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // 1 when empty register
30
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY));  // 0 when transmission is finished
31
32
  SPI_I2S_SendData(SPI1,byte>>4 & 0x0F );
33
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // 1 when empty register
34
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY));  // 0 when transmission is finished
35
}
36
void oled_m204_send_cmd(uint8_t byte) {
37
  SPI_I2S_SendData(SPI1,byte & 0x0F );
38
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // 1 when empty register
39
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY));  // 0 when transmission is finished
40
41
  SPI_I2S_SendData(SPI1,byte>>4 & 0x0F );
42
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // 1 when empty register
43
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY));  // 0 when transmission is finished
44
}
Das Datenblatt ist an sich ja doch recht einfach und auch der Link auf 
den eigentlichen Controller habe ich mehrfach durchgearbeitet. Irgendwas 
habe ich wohl übersehen.
Mittels Logicanalyser habe ich mir die Signale und Pegel ebenfalls 
angeschaut und kontrolliert.
Ich wollte jetzt nicht das ganze Program posten, aber fragen ob 
vielleicht jemand schonmal erfolgreich das Display programmiert hat.

: Bearbeitet durch User
von Erklehr Behr (Gast)


Lesenswert?

Wolfram L. schrieb:
> Ich wollte jetzt nicht das ganze Program posten, aber fragen ob
> vielleicht jemand schonmal erfolgreich das Display programmiert hat.

Nö, hab ich nicht. Aber es gibt offene Fragen da du nicht die
komplette SPI Geschichte mitgeliefert hast.

- Hast du die Bit-Reihenfolge korrekt eingestellt? Der Display-
Controller verlangt un (!) -üblicherweise das LSBit zuerst.
Das kann man schon mal übersehen ...

- Hast du Clock-Polartität und Clock-Phase korrekt initialisiert?
Es wird zwar von SPI Mode 3 gesprochen welcher eingestellt werden
soll, jedoch streiten sich die Programmierer manchmal welcher
Phase und Polarität das entspricht. Deswegen schaue ich mir
Protokoll-Diagramme genau an und stelle meine SPI so ein dass
sie der Spezifikation entsprechen.

von Wolfram L. (amazon)


Lesenswert?

1
void init_spi(void){
2
  // SPI Connections
3
  //  D6  : PA8   CS
4
  //  D10  : PA4   SPI1 NSS
5
  //  D11  : PA7   MOSI1
6
  //  D12  : PA6  MISO1
7
  //  D13  : PA5   SCK
8
  uint16_t SPI_Mode;
9
  //TM_SPI_Mode_t  SPI_mode;
10
  SPI_InitTypeDef  SPI_InitStructure;
11
12
  RCC_PCLK2Config(RCC_HCLK_Div8);    // set clock division of PCLK2
13
14
  // enable GPIOA, GPIOC and SPI1 clock
15
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC| RCC_APB2Periph_SPI1, ENABLE);
16
  RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
17
  //SPI MasterOutSerialIn Port
18
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_7;
19
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
20
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
21
  GPIO_Init(GPIOC, &GPIO_InitStructure);
22
23
24
  // When using more devices on SPI bus use Chip Select line
25
  // GPIOA_Pin_4 = RS GPIOA_Pin_8 = CS
26
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4 | GPIO_Pin_8 | GPIO_Pin_9;
27
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
28
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
29
30
  //GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
31
  GPIO_Init(GPIOA, &GPIO_InitStructure);
32
33
  // Configure SPI1 pins: SCK, MISO and MOSI
34
  // SCK and MOSI pins as Alternate Function Push Pull
35
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
36
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
37
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
38
  GPIO_Init(GPIOA, &GPIO_InitStructure);
39
40
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
41
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
42
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
43
  GPIO_Init(GPIOA, &GPIO_InitStructure);
44
45
  //SPI1 Bus setup
46
  //SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
47
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
48
  //SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
49
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
50
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
51
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
52
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
53
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
54
55
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
56
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
57
58
  SPI_Mode=3;
59
  if (SPI_Mode == 0) {
60
      SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
61
      SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
62
    } else if (SPI_Mode == 1) {
63
      SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
64
      SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
65
    } else if (SPI_Mode == 2) {
66
      SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
67
      SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
68
    } else if (SPI_Mode == 3) {
69
      SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
70
      SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
71
    }
72
73
74
75
76
77
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
78
  //SPI_InitStructure.SPI_CRCPolynomial = 7;
79
  SPI_Init(SPI1, &SPI_InitStructure);
80
  SPI_Cmd(SPI1, ENABLE);
81
82
  SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_TXE, ENABLE);
83
}
Und hier die Initialisierungsroutine des SPI Bus.
Habe jetzt nochmal den Clockmode angepasst, das war schon mal ein guter 
Tip.  Das "SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;" ist zwar 
korrekt gesetzt, aber ich sehe tatsächlich im Logicanalyser immer die 
gleiche Bitreihenfolge - egal wie ich das LSB-Flag setze ob MSB oder 
LSB. Gibts da noch einen Schalter ?

von Erklehr Behr (Gast)


Angehängte Dateien:

Lesenswert?

Nachträglich dein Analyzer-Diagram betrachtend schickst du wohl
tatsächlich das MSBit zuerst, so zeigt es jedenfalls die
Dekodierung deines Analyzers.

Ausserdem gibt es offensichtlich ein Timing-Problem. Darauf
weisen die kleinen Nadeln hin die dein Diagramm zeigt. Da
sollte man doch im Detail mit einem Oszilloskop hinschauen,
ein Logik-Analysator taugt da nicht.

von spess53 (Gast)


Lesenswert?

Hi

>Ausserdem gibt es offensichtlich ein Timing-Problem. Darauf
>weisen die kleinen Nadeln hin die dein Diagramm zeigt.

Kann aber auch ein Problem mit den Pegeln sein. Das Diagramm stammt von 
einem LOgicPort. Da gibt es einige Stellen an denen man drehen kann.

MfG Spess

von Erklehr Behr (Gast)


Lesenswert?

spess53 schrieb:
> Da gibt es einige Stellen an denen man drehen kann.

Ja schon klar. Man dreht einfach solange bis man keine
Nadeln mehr sieht und schon hat sich das Timing-Problem
in Luft aufgelöst.

von Wolfram L. (amazon)


Lesenswert?

Erklehr Behr schrieb:
> spess53 schrieb:
>> Da gibt es einige Stellen an denen man drehen kann.
>
> Ja schon klar. Man dreht einfach solange bis man keine
> Nadeln mehr sieht und schon hat sich das Timing-Problem
> in Luft aufgelöst.

Hallo,
es ist in der Tat so, das der Logicport manchmal glitches sieht die 
NICHT da sind. Da dreht man an dem Trigger Schwellwert und er zeigt 
glitches an. Hab aber jetzt nochmal mal mit Scope 4Gs/s und Scope 
geschaut, und die Signalform ist korrekt.

von Wolfram L. (amazon)


Angehängte Dateien:

Lesenswert?

Hallo,
ich habs nochmal kontrolliert, so wie ich es sehe ist die Bitorder des 
SPI Telegrams für den SSD1311 falsch herum (siehe Datenblattauszug). 
Allerdings bekomme ich die durch
1
...
2
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
nicht gedreht. Irgendwie wird das im STM32 ignoriert. Hat dazu jemand 
eine Idee ?

von Wolfram L. (amazon)


Angehängte Dateien:

Lesenswert?

Wolfram L. schrieb:
> Hallo,
> ich habs nochmal kontrolliert, so wie ich es sehe ist die Bitorder des
> SPI Telegrams für den SSD1311 falsch herum (siehe Datenblattauszug).
> Allerdings bekomme ich die durch
>
1
> ...
2
> SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
3
>
> nicht gedreht. Irgendwie wird das im STM32 ignoriert. Hat dazu jemand
> eine Idee ?

Also wenn man Tomaten auf den Augen hat...
im SPI Initialisierungscode steht ganz unten noch:
1
 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
Sobald man das auf
1
 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
setzt funktionierts wie es soll.
Hatte ich wohl irgendwann zum testen reingesetzt..
Hier für andere die richtige Intialisierungssequenz
1
void init_spi(void){
2
  // SPI Connections
3
  //  D6  : PA8   CS
4
  //  D10  : PA4   SPI1 NSS
5
  //  D11  : PA7   MOSI1
6
  //  D12  : PA6  MISO1
7
  //  D13  : PA5   SCK
8
  uint16_t SPI_Mode;
9
  //TM_SPI_Mode_t  SPI_mode;
10
  SPI_InitTypeDef  SPI_InitStructure;
11
12
  RCC_PCLK2Config(RCC_HCLK_Div8);    // set clock division of PCLK2
13
14
  // enable GPIOA, GPIOC and SPI1 clock
15
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC| RCC_APB2Periph_SPI1, ENABLE);
16
  RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
17
  //SPI MasterOutSerialIn Port
18
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_7;
19
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
20
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
21
  GPIO_Init(GPIOC, &GPIO_InitStructure);
22
23
24
  // When using more devices on SPI bus use Chip Select line
25
  // GPIOA_Pin_4 = RS GPIOA_Pin_8 = CS
26
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_0; //Pin 9 = cs oled Pin 0 = Oled reset
27
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
28
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
29
30
  //GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
31
  GPIO_Init(GPIOA, &GPIO_InitStructure);
32
33
  // Configure SPI1 pins: SCK, MISO and MOSI
34
  // SCK and MOSI pins as Alternate Function Push Pull
35
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
36
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
37
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
38
  GPIO_Init(GPIOA, &GPIO_InitStructure);
39
40
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
41
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
42
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
43
  GPIO_Init(GPIOA, &GPIO_InitStructure);
44
45
  //SPI1 Bus setup
46
  //SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
47
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
48
  //SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
49
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
50
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
51
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
52
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
53
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
54
55
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
56
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
57
58
  SPI_Mode=3;
59
  if (SPI_Mode == 0) {
60
      SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
61
      SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
62
    } else if (SPI_Mode == 1) {
63
      SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
64
      SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
65
    } else if (SPI_Mode == 2) {
66
      SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
67
      SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
68
    } else if (SPI_Mode == 3) {
69
      SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
70
      SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
71
    }
72
73
  //SPI_InitStructure.SPI_CRCPolynomial = 7;
74
  SPI_Init(SPI1, &SPI_InitStructure);
75
  SPI_Cmd(SPI1, ENABLE);
76
  SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_TXE, ENABLE);
77
}

von Wolfram L. (amazon)


Lesenswert?

Noch ein Hinweis:
Man muss dem Display leider ein "richtiges" Reset über den RESET Pin 
senden - Minimum 1ms "Low". Ein RC Glied tuts leider nicht, das war auch 
noch wichtig!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.