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!
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.
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.)
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
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.
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?
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.
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?
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
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.
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?
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.
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...
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?
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
...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...
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
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?
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
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?
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?
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
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