Forum: Mikrocontroller und Digitale Elektronik STM32F4Discovery & AT42Qt1070 Kein ACK


von Lang (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

um meine Schaltung und Platinenlayout zu prüfen, habe ich den AT42QT1070 
an einen STM32F4 Discovery angeschaltet.

Beschaltung (mehrfach geprüft/gemessen)
Discovery -> AT42Qt1070
GND -> Pin2 & Pin14
+3V -> Pin1 (100n Blockkondensator in unmittelbarer Nähe zu Pin1&14)
PinB6 -> Pin3 (SDA)
PinB9 -> Pin 6 (SCL)
PinB0 -> Pin 5 (change)

At42Qt Pin4 Floating. Vormals hatte ich Pin4 vom At42 direkt auf +3V 
gelegt, habe die Leiterbahn aber unterbrochen, da im Datenblatt immer 
ein Widerstand gegen Vdd abgebildet ist (laut Db ist aber eine direkte 
Beschaltung kein Problem). Um einen Hardware-Reset durchführen zu 
können, werde ich im finalen Layout dann den Widerstand vorsehen.

SDA und SCL habe ich jeweils per 4K7 auf +3V gezogen.

Nach einem anfänglichen Lötfehler (Brücke), der dazu führte das ich kein 
EV5 Event bekam, bin ich dann wenigstens über EV5 hinweg gekommen und 
beim Debuggen bin ich dann bis zum Senden der 7bit Adresse gelangt.

Folgende Initialisierung nutze ich:
1
void initI2C() {
2
  GPIO_InitTypeDef GPIO_InitStruct; // this is for the GPIO pins used as I2C1SDA and I2C1SCL
3
  I2C_InitTypeDef I2C_InitStruct; // this is for the I2C1 initialization
4
5
  /* enable APB1 peripheral clock for I2C1*/
6
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
7
8
  /* enable the peripheral clock for the pins used by
9
     PB6 for I2C SCL and PB9 for I2C1_SDL*/
10
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
11
12
  /* This sequence sets up the I2C1SDA and I2C1SCL pins
13
   * so they work correctly with the I2C1 peripheral
14
   */
15
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_9; // Pins 6(I2C1_SCL) and 7(I2C1_SDA)
16
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // the pins are configured as alternate function so the USART peripheral has access to them
17
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;// this defines the IO speed and has nothing to do with the baudrate!
18
  GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;// this defines the output type as open drain
19
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;// this activates the pullup resistors on the IO pins
20
  GPIO_Init(GPIOB, &GPIO_InitStruct);// now all the values are passed to the GPIO_Init()
21
22
  /* The I2C1_SCL and I2C1_SDA pins are now connected to their AF
23
   * so that the I2C1 can take over control of the
24
   * pins
25
   */
26
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1); //
27
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);
28
29
  /* Configure I2C1 */
30
  I2C_DeInit(I2C1);
31
32
  /* Set the I2C structure parameters */
33
  I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
34
  I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
35
  I2C_InitStruct.I2C_OwnAddress1 = 0xEE;
36
  I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
37
  I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
38
  I2C_InitStruct.I2C_ClockSpeed = 30000; //moderat, keine Eile geboten...
39
40
  /* Enable the I2C peripheral */
41
  I2C_Cmd(I2C1, ENABLE);
42
  /* Initialize the I2C peripheral w/ selected parameters */
43
  I2C_Init(I2C1,&I2C_InitStruct);
44
}

Folgende Write-Methode:
1
int8_t writeI2C(uint8_t address, uint8_t dataAddress, uint8_t value) {
2
  volatile int16_t ret_wert=0;
3
  volatile uint32_t timeout=I2C1_TIMEOUT;
4
5
  // Start-Sequenz
6
  I2C_GenerateSTART(I2C1, ENABLE);
7
8
  timeout=I2C1_TIMEOUT;
9
  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) {
10
    if(timeout!=0)
11
      timeout--;
12
    else
13
      return(-1);
14
  }
15
16
  // Slave-Adresse senden (write)
17
  I2C_Send7bitAddress(I2C1, address, I2C_Direction_Transmitter);
18
19
  timeout=I2C1_TIMEOUT;
20
  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {
21
    if(timeout!=0)
22
      timeout--;
23
    else
24
      return(-2);
25
  }
26
27
  // ADDR-Flag löschen
28
  I2C1->SR2;
29
30
  timeout=I2C1_TIMEOUT;
31
  while (!I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE)) {
32
    if(timeout!=0)
33
      timeout--;
34
    else
35
      return(-3);
36
  }
37
38
  // Adresse senden
39
  I2C_SendData(I2C1, dataAddress);
40
41
  timeout=I2C1_TIMEOUT;
42
  while (!I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE)) {
43
    if(timeout!=0)
44
      timeout--;
45
    else
46
      return(-4);
47
  }
48
49
  // Daten senden
50
  I2C_SendData(I2C1, value);
51
52
  timeout=I2C1_TIMEOUT;
53
  while ((!I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE)) || (!I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF))) {
54
    if(timeout!=0) timeout--;
55
    else return(-5);
56
  }
57
58
  // Stop-Sequenz
59
  I2C_GenerateSTOP(I2C1, ENABLE);
60
61
  ret_wert=0; // alles ok
62
63
  return(ret_wert);
64
}

In der main wird dann folgendes aufgerufen (verschiedene Adressen, um 
sicher zu gehen), um einen initialen Software-Reset des AT42 
durchzuführen:
1
initI2C();
2
volatile int8_t retValue = writeI2C((0x1B << 1), 0x39, 0xFF); //reset device; sieht gut auf dem Logik-Analyzer aus (0x36, bit0 = 0, da schreiben)
3
retValue = writeI2C(0x1B, 0x39, 0xFF); //reset device, nicht schön, 0x1A übertragen wird.

Mein Logikanalyzer (siehe Beispiel als Anhang) sagt mir bei allen 
gesendeten Adressen immer, dass kein ACK erfolgt. Im Programm geht er 
auch auf einen Timeout bei "-2", also kein Event nach dem Senden der 
Adresse.

Nachdem quasi nichts funktioniert, habe ich mal die Spannungen am AT42 
gemessen:
Pin1 ~2,95V
Pin3 ~2,25V
Pin6 ~2,25V

Evtl. sind 4k7 zuviel. Ich werde morgen mal 1K ausprobieren.

Hat irgend jemand eine Idee, was ich falsch mache, bzw. was ich noch 
überprüfen kann/sollte?

Besten Dank um voraus.
Jörg

von Lang (Gast)


Lesenswert?

Sorry, beim Schreiben habe ich doch PinB6 und PinB9 miteinander 
vertauscht.
Sind aber anders herum beschalten (hatte aber zur Vorsicht mal beide 
getauscht und kein anderes Ergebnis bekommen).

von Felix Adam (Gast)


Lesenswert?

Wenn dein Schaltplan komplett ist, dann ist der /RESET offen und nicht 
per Pullup auf high gezogen.
Der Chip bleibt wohl einfach im Reset.

von Lang (Gast)


Lesenswert?

Hmm, habe gerade nochmal versucht im Datenblatt zu finden, dass man den 
auch nicht beschalten braucht, aber hab nix gefunden.

Werde morgen einen Widerstand anlöten und gleichzeitig einen für Change 
einbauen (das geht glücklicherweise einfacher per Breadboard)

Melde mich morgen mit neuen Erkenntnissen.

Vorerst besten Dank bis dahin.

Grüße
Jörg

von Lang (Gast)


Lesenswert?

Doch, jetzt habe ich es wieder.

/RESET - if unused connect to OPEN. /RESET – has internal pull-up 60 
kOhm resistor

von Felix Adam (Gast)


Lesenswert?

Nach nochmaligem Lesen fiel mir auf, dass deine Adresse wohl noch um 1 
nach links geschoben werden muss. Das R/W-Bit kommt nämlich noch vor dem 
NACK, ist aber bei dir Teil der Adresse, oder?

von Felix Adam (Gast)


Lesenswert?

Die Adresse behandelst du im Code auch scheinbar unterschiedlich:
1
volatile int8_t retValue = writeI2C((0x1B << 1), 0x39, 0xFF); //reset device; sieht gut auf dem Logik-Analyzer aus (0x36, bit0 = 0, da schreiben)
2
retValue = writeI2C(0x1B, 0x39, 0xFF); //reset device, nicht schön, 0x1A übertragen wird.

Bei der unteren Zeile wird die Adresse nicht geschoben.

von Lang (Gast)


Lesenswert?

Der AT42 hat die feste Adresse 0x1B.
Da ich gelesen habe, das in der Bibliothek in bestimmten Versionen das 
erste Bit  (Bit0)  überschrieben wird, habe ich in der ersten Zeile die 
Adresse um 1 Bit geshiftet. Kein ACK vom Device, daher der Test der 
zweiten Zeile ohne Shift. Aber auch hier kein ACK.

von Felix Adam (Gast)


Lesenswert?

Im Diagramm vom Logikanalyzer ist die Adresse jedenfalls nicht um 1 nach 
links geschoben worden.

von Lang (Gast)



Lesenswert?

So, habe heute mal 1K für SDA und SCL genutzt. Damit komme ich dann an 
den Pins auf 2,7V bei Vdd 2,95V.

Pin4 (/RESET) des AT42 hab ich per 10K auf Vdd gezogen. Messe dort auch 
~2,7V. /CHANGE habe ich auf floating gelassen.

Anbei die Versuche mit verschiedenster Adressierung.

Keine Antwort. Vielleicht ist der Chip übern Jordan. Muss mal schauen ob 
ich noch einen rum liegen habe.

Es sei denn, ich hab noch immer einen Schnitzer in meiner Anwendung?

Gruß
Jörg

von Felix Adam (Gast)


Lesenswert?

Bei den beiden linken Bildern ist die Adresse jetzt richtig.

Im Datenblatt ist in allen Beispielschaltungen extern immer ein Pullup 
am Reset. Bevor du den Chip auslötest, würde ich vorschlagen, diesen 
Widerstand auch nochmal extern dran zu hängen. Vielleicht ist es ja doch 
das Problem, auch wenn im Datenblatt ein interner Pullup erwähnt wird.

Ansonsten ist mir leider nichts aufgefallen, was den Fehler produzieren 
könnte.

von Lang (Gast)


Lesenswert?

Okay,  dann ist es wohl der Chip. Hatte ja wie geschrieben den /Reset 
auf Vdd per 10k gezogen und geprüft.

Schade, ist schwierig an die Dinger zu kommen....

von Pete K. (pete77)


Lesenswert?

Vielleicht mag er das hier nicht:
I2C_InitStruct.I2C_ClockSpeed = 30000;

Setz das mal auf 100K hoch.

von Pete K. (pete77)


Lesenswert?

Hier gibt es ein Tutorial:
http://diller-technologies.de/stm32.html#i2c_config

Da wird das noch gesetzt: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | 
RCC_APB2Periph_AFIO, ENABLE);

Und die NVIC-Routinen sehe ich auch nicht bei Dir.

von Lang (Gast)


Lesenswert?

Pete K. schrieb:
> Hier gibt es ein Tutorial:
> http://diller-technologies.de/stm32.html#i2c_config
>
> Da wird das noch gesetzt: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |
> RCC_APB2Periph_AFIO, ENABLE);
>
> Und die NVIC-Routinen sehe ich auch nicht bei Dir.

Das Tutorial bezieht sich auf einen anderen stm32. Die Unterschiede 
können wie bei Diller erwähnt nicht unerheblich sein. Gerade bei den 
clocks...

Nichts desto trotz prüfe ich mal, ob die nvic Routinen möglich und 
sinnvoll sein könnten.

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.