Forum: Mikrocontroller und Digitale Elektronik I2C stehe auf dem Schlauch (CC430)


von I2C (Gast)


Lesenswert?

Hallo,

vielleicht stehe ich etwas auf dem Schlauch, aber wie genau löse ich bei 
dem CC430 einen ACK-Signal beim I2C aus?

Schreibt man einfach ein UCB0CTL1 &=~ UCTCNACK, oder geschieht das ACK 
automatisch, nachdem 8 Datenbytes angekommen sind?

DANKE!

von Klaus R. (klara)


Lesenswert?

Hallo I2C,
ein wenig Code würde Dein Problem hier besser beschreiben.

Ich habe mir mal meinen Code für einen MSP430F2013 angesehen. Danach 
wird nach jedem empfangen Byte ein Ack gesendet und zum Schluss ein 
NAck.

#####################################
 case 6: // Receive Data Ack/Nack bit
    if (WriteMode)
      USICTL0 &= ~USIOE;         // SDA = input
    else
    {
      USICTL0 |= USIOE;          // SDA = output
      OutCode[pntOutCode++] = USISRL; // Lesen des empfangenen Bytes
      if (LoopsToRead > 0)
      {
        USISRL = 0x00;           // Send Ack,
        USICNT |= 0x01;          // Bit counter = 1, send Ack bit
        I2C_State = 8;           // Go to next state
        break;
      }
      USISRL = 0xFF;             // Send NAck, hier generell senden,
    }
    USICNT |= 0x01;              // Bit counter = 1, receive (N)Ack bit
    I2C_State = 8;               // Go to next state: check (N)Ack
    break;
#####################################

Dieser Code ist zwar den rudimentären Samples von TI entnommen, wurde 
von mir aber für Rx und Tx zusammengefasst und etwas ergänzt. Die 
damalige I2C-Lib bekam ich nicht zum Laufen. Heute sieht das aber 
bestimmt anders aus. Versuch mal die Lib einzusetzen.

mfg klaus.

von Clemens L. (c_l)


Lesenswert?

USI (F2xx) ist nicht das gleiche wie USCI (CC430).

Siehe Abschnitt 24.3.4.1.2 und Abbildung 4-10 des User's Guide.
Ein ACK wird automatisch gesendet, wenn im Eingabepuffer Platz ist, weil 
deine Software das vorherige Byte aus UCBxRXBUF gelesen hat.
(Und mehr als ein Byte wird nicht gepuffert.)

von Klaus R. (klara)


Lesenswert?

Hallo Clemens,
ich bin zwar nicht der Ersteller des Threads aber ich werde mich 
demnächst auch mit einem cc430x513x befassen. Ich weiss noch welchen 
Aufwand (Try/Error) ich 2007/2008 betreiben musste um aus den 
TI-Samples, die sehr rudimentär gehalten waren und noch sind, etwas 
Lauffähiges wie für einen TMP102, bzw. dem DS1631, hinzubekommen.

In den TI-Samples wird zwar beschrieben wie man ein Byte zum Slave 
sendet, aber auch nur das. Und im anderen Sample, wie man ein Byte 
empfängt. Ja, und dann bastele mal dies zusammen zu einem Code und das 
noch für 16Bit-Anworten des Slave. Für einen damaligen Anfänger etwas 
Anspruchsvolles.

Ich habe mich in den letzten Tagen wieder wegen dem cc430x513x durchs 
Internet gewühlt um ein paar Samples zufinden. Vielleicht suche ich an 
den falschen Stellen.

Mir ging es für das erste darum:
-Über I2C bei einem TMP102 (12 Bit Temperatursensor) den Messvorgang
 einleiten
-Empfang der 2 Byte des Sensors

Beim MSP430F2013 läuft mein Code seit Jahren einwandfrei. Der 
Sample-Code für den cc430x513x sieht etwas anders aus.

Kannst Du mir Quellen nennen die mir weiterhelfen könnten?
mfg klaus

von Clemens L. (c_l)


Lesenswert?

Normalerweise empfehle ich driverlib:
http://www.ti.com/tool/mspdriverlib
entweder direkt, oder den Quellcode als Vorlage nehmen.

Die CC430-Familie wird zwar von driverlib nicht direkt unterstützt, aber
das USCI-Modul ist das gleiche wie in der F5xx-Familie.
Siehe examples/MSP430F5xx_5xx/usci_b_i2c/ und
driverlib/MSP430F5xx_5xx/usci_b_i2c.*.

Für den TMP102 muss man ein Byte schreiben und dann sofort zwei Bytes
lesen. Das wären USCI_B_I2C_masterMultiByteSendStart() (nicht
…SingleByte(), damit kein STOP gesendet wird), und wenn das erledigt
ist, USCI_B_I2C_masterMultiByteReceiveStart(), und dann im Interrupt
USCI_B_I2C_masterMultiByteReceiveNext() oder
USCI_B_I2C_masterMultiByteReceiveFinish().

Und wenn das nicht weiter hilft, musst du dein Englisch ausgraben und
auf http://e2e.ti.com/support/microcontrollers/msp430/ nachfragen.

: Bearbeitet durch User
von I2C (Gast)


Lesenswert?

Nun,

Eine weitere Frage zur Adressinitialisierung:
Ich möchte den HTU21D Feuchte-Sensor ansteuern.

Dieser hat laut Datenblatt die 7Bit-Adresse 0x40

Für einen Schreib-Vorgang wird er mit 0x80 und für einen Lesevorgang mit 
0x81 angesprochen, da das Direction-Bit am Ende mit angefügt wird.

Der CC430 möchte die Slave Adresse wissen. Schreibe ich in das 
I2CSAx-Register nun 0x80, 0x81 oder 0x40 hinein?

von Clemens L. (c_l)


Lesenswert?

Das hättest du einfach im User's Guide, Abschnitt 24.4.9, nachlesen
können:
> The I2CSAx bits contain the slave address of the external device to be
> addressed by the USCI_Bx module. It is only used in master mode.
> The address is right justified. In 7-bit slave addressing mode, bit 6
> is the MSB and bits 9-7 are ignored.

von I2C (Gast)


Lesenswert?

danke dir, also schreibe ich die 0x40 in das Register.

Allerdings entstehen aus der 7-Bit Adressierung bzw. aus dem Verfahren 
des CC430 für mich noch einige weitere Fragen:



Im Datenblatt des Sensors HTU21D steht in der Beispielsequenz, dass zum 
Ansprechen folgendes nötig ist:

[S][I2C Adresse + Write] ---ACK--- [COMMAND] ---ACK--- [S][I2C ADRESSE + 
READ]

d.h. ich muss eine Startsequenz, dann die Adresse mit einem 
Schreibbefehl abgeben, auf die Bestätigung warten, sodann den 
eigentlichen Messbefehl abgeben, erneut auf Bestätigung warten, dann 
einen erneuten Startvorgang initiieren und den Sensor nochmal mit einem 
Lesevorgang ansprechen und nach dem ACK sodann warten, bis der Sensor 
fertig ist.

Übersetzt muss ich also folgende Signale auf die Datenleitung legen:

[S][0x80]---ACK---[0xE5]---ACK---[S][0x81]---ACK...wait

Die Datenleitung erhält also die Bytes 0x80 / 0x81 obwohl die Adresse 
eigentlich 0x40 ist.


Nun frage ich mich:
Wozu das ganze? der CC430 hat das I2CSAx-Register, welches explizit die 
7-Bit Adresse des Slave Device aufnehmen kann.
Wozu muss bzw. kann ich meinem Controller (Master) mitteilen, welche 
Adresse mein Sensor besitzt?
Würde es nicht zum Ansprechen des Sensors genügen, einfach, die 0x80 in 
den UCB0TXBUF zu schreiben?
was macht der CC430 Controller mit der 0x40, die ich in obigem Register 
mit angeben kann?

von Klaus R. (klara)


Lesenswert?

Clemens L. schrieb:
> Normalerweise empfehle ich driverlib:
> http://www.ti.com/tool/mspdriverlib
> entweder direkt, oder den Quellcode als Vorlage nehmen.
>
> Die CC430-Familie wird zwar von driverlib nicht direkt unterstützt, aber
> das USCI-Modul ist das gleiche wie in der F5xx-Familie.
> Siehe examples/MSP430F5xx_5xx/usci_b_i2c/ und
> driverlib/MSP430F5xx_5xx/usci_b_i2c.*.

Das Beispiel driverlib/MSP430F5xx_5xx/usci_b_i2c.* hatte ich mir gestern 
schon mal angeschaut ...
>
> Für den TMP102 muss man ein Byte schreiben und dann sofort zwei Bytes
> lesen. Das wären USCI_B_I2C_masterMultiByteSendStart() (nicht
> …SingleByte(), damit kein STOP gesendet wird), und wenn das erledigt
> ist, USCI_B_I2C_masterMultiByteReceiveStart(), und dann im Interrupt
> USCI_B_I2C_masterMultiByteReceiveNext() oder
> USCI_B_I2C_masterMultiByteReceiveFinish().
>
... aber erst jetzt bin ich mir sicher es verstanden zu haben. Die LIB 
vereinfacht in der Tat den Umgang mit I2C.

> Und wenn das nicht weiter hilft, musst du dein Englisch ausgraben und
> auf http://e2e.ti.com/support/microcontrollers/msp430/ nachfragen.

Ja, das wird sich manchmal nicht vermeiden lassen.
Nochmals Danke, Du hast mir sehr geholfen.

mfg klaus

von Clemens L. (c_l)


Lesenswert?

I2C schrieb:
> Wozu muss bzw. kann ich meinem Controller (Master) mitteilen, welche
> Adresse mein Sensor besitzt?

Der Controller sendet nach dem START automatisch die Slave-Adresse.

> was macht der CC430 Controller mit der 0x40, die ich in obigem Register
> mit angeben kann?

Er sendet es auf dem Bus, und hängt das R/W-Bit an.

: Bearbeitet durch User
von I2C (Gast)


Lesenswert?

Danke dir Clemens,

d.h. nach dem [Start] wird das erste Byte bereits automatisch gesendet, 
wobei die 7 Bit-Adresse automatisch um 1 Bit verlängert wird, so dass 
ein ganzes Byte entsteht?

Frage:
Dieser Automatismus funktioniert aber nur bei dem ersten Byte, und es 
wird immer nur die "0" zum Schreiben ergänzt, richtig?

Alle weiteren Bytes  Befehle  oder Auslesewünsche muss ich nach dem 
erhalten des ersten ACK manuell in den UCB0TXBUF schreiben?

von Klaus R. (klara)


Lesenswert?

Hallo I2C,
wenn Du die I2C-Lib verwendest dann hast Du mit den Registern direkt 
nichts mehr zu tun.
mfg klaus

von Clemens L. (c_l)


Lesenswert?

Im I²C-Protokoll muss das erste Byte immer die Slave-Adresse sein,
deshalb kann der Controller sie automatisch senden. Die anderen Bytes
hängen von der Anwendung ab.

Der ergänzte Bit ist 0 beim Schreiben und 1 beim Lesen. (Auch bei einer
Lese-Transaktion sendet der Master die Slave-Adresse.)

Die oben erwähnten Links gelten auch für dich.

von I2C (Gast)


Lesenswert?

ok, hab I2C eben noch nie benutzt und muss nun erstmal die Grundlagen 
verstehen.

Das R/W Bit wird also durch das UCTR bestimmt. Da muss man auch erst mal 
drauf kommen.
Eine Suche nach dem "R/W bit" im Family Guide führt zumindest nicht zu 
dieser Erkenntnis...

von I2C (Gast)


Lesenswert?

Das hier habe ich aus dem Family Guide:

> USCI module checks if the bus is available,
> generates the START condition,
> and transmits the slave address.
> The UCTXIFG bit is set when the START
> condition is generated and the first
> data to be transmitted can be written
> into UCBxTXBUF

Die Startbedingung (UCTXSTT = high) wird beim Empfangen eines ACK 
gelöscht.

Der Family Guide weist darauf hin, dass das UCTXIFG ein rw-1 Bit ist, 
d.h. es ist immer high solange der TX-Buffer leer ist.

Frage: Geht der Controller dann bei gesetztem TXIE in die ISR?

Wie verhindere ich denn, dass dort kein permanentes Trap durch Sprünge 
in die ISR stattfindet?

von Clemens L. (c_l)


Lesenswert?

I2C schrieb:
> Der Family Guide weist darauf hin, dass das UCTXIFG ein rw-1 Bit ist,
> d.h. es ist immer high solange der TX-Buffer leer ist.
>
> Frage: Geht der Controller dann bei gesetztem TXIE in die ISR?
>
> Wie verhindere ich denn, dass dort kein permanentes Trap durch Sprünge
> in die ISR stattfindet?

Indem du etwas in the TX-Buffer schreibst, oder STOP sendest.

Beim STOP musst du das Interrupt-Flag manuell zurücksetzen.
Aus driverlib:
1
    //Send stop condition.
2
    HWREG8(baseAddress + OFS_UCBxCTL1) |= UCTXSTP;
3
4
    //Clear transmit interrupt flag before enabling interrupt again
5
    HWREG8(baseAddress + OFS_UCBxIFG) &= ~(UCTXIFG);

von I2C (Gast)


Lesenswert?

...so, so langsam mache Ich Fortschritte:

Eine kurze Frage:

Ist es richtig, dass das ACK ein "low" auf der Datenleitung erzeugt?


Ich habe hier ozisllografiert und das was ich auf den BUS lege macht nur 
Sinn, wenn ACK = low bedeutet, und zwar für einen Takt lang...

von Clemens L. (c_l)


Lesenswert?

Das Datashit des HTU21D zeigt es nicht, aber in Bild 24-3 in Abschnitt 
24.3.2 des CC430 User's Guide sieht man es.

von NXP (Gast)


Lesenswert?

I2C schrieb:
> d.h. nach dem [Start] wird das erste Byte bereits automatisch gesendet,
> wobei die 7 Bit-Adresse automatisch um 1 Bit verlängert wird, so dass
> ein ganzes Byte entsteht?

Nein.

Das erste, automatisch gesendete Byte wird aus (7-Bit)-I2C Adresse und 
R/W-Bit zusammengesetzt. Da wird keine Adresse verlängert.

In der I2C-Spezifikation findest du das alles beschrieben (Fig.9+10)
http://www.nxp.com/documents/user_manual/UM10204.pdf

von I2C (Gast)


Lesenswert?

so, die Sendesequenz hin schaffe ich, aber mit der Antwort stimmt 
irgendetwas nicht:

Senden tue ich:

[S][1000.0000]{0-ACK}[1110.0011]{0-ACK}[S][1000.0001]{0-ACK}


In eckigen Klammern die Sequenz vom CC430 ausgehend und in geschweiften 
Klammern die Acknowledges vom HTU21D


Der Code triggert eine Temperaturmessung, die nach ca. 42ms 
abgeschlossen sein soll.
Die Datenleitung ist also die ganze Zeit high und der Takt auf low.

Nach den 42ms sehe ich dann ein Signal auf dem Bus, und zwar geht die 
Taktleitung wieder auf low sowie die Clock fängt an zu laufen, dann sehe 
ich folgendes Signal:

1100.0100.1100.100

Danach bleibt Takt und Datenleitung auf low.

In der Sequenz erkenne ich aufgrund der komischen Zahl an Bits (15 
Stück) keine Acknowledges und kann es daher nicht übersetzen...
Ich hätte eigentlich 27 Bits erwartet...

Woran mag das liegen?

von Klaus R. (klara)


Lesenswert?

I2C schrieb:
> so, die Sendesequenz hin schaffe ich, aber mit der Antwort stimmt
> irgendetwas nicht:
>
> Senden tue ich:
>
> [S][1000.0000]{0-ACK}[1110.0011]{0-ACK}[S][1000.0001]{0-ACK}
>

So wie ich das sehe hast Du den Mode "No Hold Master communication 
sequence" gewählt. In dieser Tabelle sehe ich den Verlauf etwas anders.

[S][1000.0000]{0-ACK}[1110.0011]{0-ACK}
[S][1000.0001]{0-NACK}
[S][1000.0001]{0-ACK}

mfg klaus

von I2C (Gast)


Lesenswert?

Das zweite Byte, dass ich sende beinhaltet den Befehl: 1110.0011 = 0xE3. 
Dies ist eine Hold-Master-Sequence.

von I2C (Gast)


Lesenswert?

Nebenfrage:
Muss ich für den hold-master-mode den synchronen oder den asynchronen 
Modus aktivieren?
Hat dies einen Einfluss, oder ist das die falsche Fährte?

von Clemens L. (c_l)


Lesenswert?

I2C schrieb:
> Nach den 42ms sehe ich dann ein Signal auf dem Bus, und zwar geht die
> Taktleitung wieder auf low sowie die Clock fängt an zu laufen, dann sehe
> ich folgendes Signal:
>
> 1100.0100.1100.100

Mehr als 8 Bit sollten ohne ACK des Masters nicht gesendet werden.
Kannst du uns mal zeigen, was das Oszilloskop dazu sagt?

von Klaus R. (klara)


Lesenswert?

Hallo Clemens,

> Mehr als 8 Bit sollten ohne ACK des Masters nicht gesendet werden.
Ist aber so, siehe Datenblatt.

http://www.meas-spec.com/downloads/HTU21D.pdf, Seite 12.
mfg klaus

von Clemens L. (c_l)


Lesenswert?

Klaus Ra. schrieb:
> Ist aber so, siehe Datenblatt.
> http://www.meas-spec.com/downloads/HTU21D.pdf, Seite 12.

Auf Seite 12 wird "No Hold master" beschrieben, was hier aber nicht
verwendet wird.

Und nirgendwo sehe ich mehr als 8 Datenbits vor einem ACK.

von Klaus R. (klara)


Lesenswert?

Clemens L. schrieb:
> Klaus Ra. schrieb:
>> Ist aber so, siehe Datenblatt.
>> http://www.meas-spec.com/downloads/HTU21D.pdf, Seite 12.
>
> Auf Seite 12 wird "No Hold master" beschrieben, was hier aber nicht
> verwendet wird.
>
Jau, ich habe mich mit dem F3 vertan.
mfg klaus

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.