Hallo allerseits
Ich will mit dem ET-STM32F ARM Kit von http://www.ett.co.th/ einen
Drucksensor über I2C auslesen.
Kurz zu meiner Clockkonfiguration:
HSE mit25MHz
SYSCLOCK = 72
HCLK = 72MHz
PCLK1 = 36MHz
PCLK2 = 72MHz
Meine Konfiguration:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/* Reset I2Cx IP */
//RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
/* Release reset signal of I2Cx IP */
//RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_OwnAddress1 = 0x00; //Eigene Adresse
für Slave oder Multimaster betrieb, ansonsten irrelevant
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_Ack = I2C_Ack_Disable;
I2C_InitStructure.I2C_AcknowledgedAddress =
I2C_AcknowledgedAddress_7bit; //Adress-Modus, normalerweise 7-Bit
I2C_InitStructure.I2C_ClockSpeed = 400000;
//Taktgeschwindigkeit von SCL, hier 50kHz
I2C_Init(I2C1, &I2C_InitStructure);
I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, DISABLE); //Keine
Interrupts
I2C_Cmd(I2C1, ENABLE);
Code im main:
Input: (I2C1,0x40,I2C_Direction_Transmitter)
void I2C_start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction){
// wait until I2C1 is not busy any more
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
// Send I2C1 START condition
I2C_GenerateSTART(I2Cx, ENABLE);
// wait for I2C1 EV5
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
// Send slave Address for write
I2C_Send7bitAddress(I2Cx, address, direction);
/* wait for I2Cx EV6, check if
* either Slave has acknowledged Master transmitter or
* Master receiver mode, depending on the transmission
* direction
*/
if(direction == I2C_Direction_Transmitter){
while(!I2C_CheckEvent(I2Cx,
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //Hier bleibt er hängen
}
else if(direction == I2C_Direction_Receiver){
while(!I2C_CheckEvent(I2Cx,
I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
}
}
Hardware:
SCL und SDA sind jeweils mit einem 10k auf Masse gezogen.
Was funktioniert:
Die Register des I2C1 werden erfolgreich gesetzt. Ich arbeite mit Keil
sehe dies also im Debugger. CCR etc. alles richtig..
Nach der Initalisierung liegen SCL und SDA auf 3.28V, habe leider nur
ein Multimeter und kein Oszi.
Wenn ich die Startkondition machen will, funktioniert das auch alles.
Busy, MSL und SB werden gesetzt.
SCL fällt auf 0V SDA auf 0.13V was doch auch noch im Rahmen sein sollte
oder?
Wenn ich jetzt die Adresse ins DR-Reg schiebe funzt das auch, allerdings
krieg ich dann grad nen AF-Error.
Ich bin ehrlich komplett ratlos was falsch ist. Habe das ganze auch
schon mit nem Arduino getestet und der Sensor funktioniert wunderbar.
Falls jemand auch Keil benutzt kann ich ihm gerne auch mein Projekt
schicken.
Ich bin gerade echt am verzweifeln, bin da schon seit 3 Tagen dran, wenn
jemand also iwie Zeit für ne Teamviewer/Sykpe Sitzung hätte oder
irgendwelche Ideen hat, wäre ich schwer dankbar :)
Gruss und Dank
Felix
Bernd M. schrieb:> SDA und SCL benötigen 4k7 Pullups (open drain)
Wieso?
Die sind doch nur dafür da, die Leitungen "default" auf High zu setzen,
damit sie per open-drain wieder runter gezogen werden.
Egal habs jetzt mal ausprobiert und funzt immer noch net. Nebenbei das
Arduino Mega benutzt auch 10k auf SCL/SDA.
Ergänzung:
Da PB6/PB7 auf einem RS232-Modul verbunden sind(was ja eigentlich egal
sein sollte) habe ich die Pins jetzt mal auf PB8/PB geremapt, was aber
auch nich half.
Einziger Unterschied Low liegt jetzt bei 0.05V, High bei 3.28V unter
Nutzung von 4K7.
Felix C. schrieb:> SCL und SDA sind jeweils mit einem 10k auf Masse gezogen.Felix C. schrieb:> Wieso?>> Die sind doch nur dafür da, die Leitungen "default" auf High zu setzen,> damit sie per open-drain wieder runter gezogen werden.
Die Pullup sind Arbeitswiderstände, ohne die der I2C nicht funktioniert.
Die 4k7 sind ein Erfahrungswert, er kann irgendwo zwischen 1k und 100k
liegen, je nach Buseigenschaften. Die Pullup kann man auch exakt
berechnen.
http://www.nxp.com/documents/user_manual/UM10204.pdf
Und noch eine übersichtliche Darstellung des I2c:
https://de.wikipedia.org/wiki/I%C2%B2C
Bernd M. schrieb:> Die Pullup sind Arbeitswiderstände, ohne die der I2C nicht funktioniert.> Die 4k7 sind ein Erfahrungswert, er kann irgendwo zwischen 1k und 100k> liegen, je nach Buseigenschaften. Die Pullup kann man auch exakt> berechnen.
Danke für den Einwand, auch wenn er mir kein Stück weiterhilft, da ich
ja bereits schrieb, dass das System bereits mit 10k funktioniert hat.
4k7 wurden wie bereits beschrieben ebenfalls ausprobiert.
Falls jemand ein Keil Projekt oder Beispielcode hat, für egal was für
eine I2C Anwendung wäre ich extrem dankbar. Da ich soqieso nicht über
das Addressieren des Sensors hinauskomme, könnte ich die Adresse ja
schnell anpassen.
Felix C. schrieb:> Hardware:> SCL und SDA sind jeweils mit einem 10k auf Masse gezogen.
Aber das ein Pullup gegen VCC geht und nicht gegen Masse, darin stimmen
wir überein?
Ich habe hier einen STM32L151 als I2C Master im polling an laufen, ist
zwar ein anderer uC aber alles sehr ähnlich:
Der Init Struct sieht folgendermaßen aus:
Ich habe zwei getrennte Funktionen zum Schreiben und Lesen. Die sind
dicht an die STM lib angelehnt, ohne Aufrufe in die STM lib. Ich poste
die beiden Funktionen, weil ich nicht die Muße habe, deinen Code, der
augenscheinlich nicht der verwendete Code ist, im Zusammenhang mit der
STM lib zu analysieren:
/* Clear ADDR Flag by reading SR1 then SR2 registers (SR1 have already been read) */
85
(void)I2C_MASTER->SR2;
86
87
idx=0;
88
while(idx<length){
89
/* wait until data was received */
90
while(READ_BIT(I2C_MASTER->SR1,I2C_SR1_RXNE)==0);
91
92
/* read data byte */
93
buffer[idx]=I2C_MASTER->DR;
94
idx++;
95
96
if(idx>=length-1){
97
/* generate last byte and STOP condition */
98
CLEAR_BIT(I2C_MASTER->CR1,I2C_CR1_ACK);
99
SET_BIT(I2C_MASTER->CR1,I2C_CR1_STOP);
100
}
101
}
102
103
retVal=0;
104
}
105
106
returnretVal;
107
}
Ist Folgendes in Deinem Code berücksichtigt, sollte eigentlich durch die
STM lib geschehen:
"Note: Reading I2C_SR2 after reading I2C_SR1 clears the ADDR flag, even
if the ADDR flag was set after reading I2C_SR1. Consequently, I2C_SR2
must be read only when ADDR is found set in I2C_SR1 or when the STOPF
bit is cleared."
Läßt Du dir Registerinhalte des I2C anzeigen? Beim Durchsteppen ist das
ein Problem. Der Debugger liest das SR2 als erster, dann kommt dein
Programm und der Inhalt ist bereits verändert.
Evtl. ist dein I2C Slave mittlerweile in einem undefinierten Zustand,
ich hatte das mit dem DS3231. Eine mögliche Lösung ist hier zu finden:
http://www.forward.com.au/pfod/ArduinoProgramming/I2C_ClearBus/index.html
Zur Analyse was wirklich auf dem I2C geschiet ist ein LogicAnalyzer von
Vorteil.