Hallo Forum,
ich bin gerade dabei, mit meinem STM8S103F3P6 als Master eine SPI
Verbindung aufzubauen, leider klappt das nicht ganz. Ehrlich gesagt ist
das Datenblatt auch ziemlich verwirrend.
Ich habe mir auch schon die einzelnen Pins (MOSI, CLK, CS) auf dem Logic
Analyzer anzeigen lassen, leider ist da nichts passiert.
muss ich das SSM-Bit im SPI-CR2 Register auf '0' setzen, damit der
Controller den Chip-Select automatisch auf high / low schaltet?
Das mache ich mit:
1
SPI->CR2=0b00000000;
allerdings ändert sich am 'CS' pin trotzdem nichts? Warum?
Edit:
Okay, ich hab jetzt versucht, den CS-Pin manuell high/low zu schalten,
jetzt passiert etwas sehr seltsames, das ist mein Code:
1
intmain(){
2
initSPIMaster();
3
while(1){
4
GPIOA->ODR&=~(1<<CS);//turn CS low
5
SPITransmit(0x2D);
6
SPITransmit(0x08);
7
GPIOA->ODR|=(1<<CS);//turn CS high
8
delay_ms(100);
9
}
10
}
Den Signalverlauf seht ihr im 2.Bild.
Nun stellt sich die Frage: Warum geht CS mittendrinn high obwohl er es
doch erst nach dem Übertragen der 16bit tuen soll? Wie man aber sieht,
gibt es noch einen Flankenwechsel obwohl CS schon wieder high ist?
Okay, ich hab das Problem des CS-Pins gefunden:
Man muss zuerst prüfen, ob der MC noch busy ist:
1
voidSPITransmit(uint8_tdata){
2
while(!(SPI->SR&(1<<1))){
3
nop();//wait until transmit buffer is empty
4
}
5
SPI->DR=data;
6
while((SPI->SR&(1<<7))){
7
nop();//wait until not busy
8
}
9
}
Nun der nächste Fehler:
Ich versuche nun eine Funktion zu erstellen, die mir den übergebenen
Wert in das SPI-Register schiebt, so sieht die Funktion aus:
1
voidgetValueFromRegister(uint8_treg,uint8_t*val){
2
uint8_ttransmitValue=(0x80®);
3
uint8_treceivedValue=0;
4
5
GPIOA->ODR&=~(1<<CS);//CS high
6
SPITransmit(transmitValue);//write 'read' command
7
receivedValue=SPIReceive();
8
GPIOA->ODR|=(1<<CS);//CS low
9
10
delay_ms(10);
11
*val=receivedValue;
12
}
Auf meinem Logic-Analyzer erscheint auf MOSI leider kein Signal, auf SCK
und CS dagegen schon. Sobald ich das hier:
1
SPITransmit(transmitValue);//write 'read' command
in das hier:
1
SPITransmit(0x3B);//write 'read' command
ändere, erscheint dagegen schon ein Signal auf dem MOSI Pin, so wie es
eigentlich sein soll. Warum hat das SPI-Register Probleme mit Variablen?
Edit: okay, sorry. Problem gelöst, so sollte es eigentlich lauten:
Das lesen der Daten klappt allerdings ganz und gar nicht. Jetzt heißt es
natürlich raten, ob das am Sensor (ADXL345) oder an meiner SPI
Konfiguration liegt. Egal was mich mache, ich bekomme für alle 3 Achsen
2313 auf der Konsole ausgegeben.
Meine Funktion zum Lesen:
1
uint8_tSPIReceive(){
2
while((SPI->SR&(1<<7))){
3
nop();//wait until not busy
4
}
5
while(!(SPI->SR&(1<<0))){
6
nop();//wait until receive buffer is not empty
7
}
8
return(SPI->DR);
9
}
Diese Funktion wird von getValueFromRegister aufgerufen, die ich in
meinem letzten Beitrag schon gepostet habe.
Das hier ist die Funktion, die die Beschleunigungswerte für X,Y & Z
liefert:
1
voidgetXYZValues(int16_t*x,int16_t*y,int16_t*z){
2
uint8_tx0,x1,y0,y1,z0,z1;
3
getValueFromRegister(0x32,&x0);
4
getValueFromRegister(0x33,&x1);
5
getValueFromRegister(0x34,&y0);
6
getValueFromRegister(0x35,&y1);
7
getValueFromRegister(0x36,&z0);
8
getValueFromRegister(0x37,&z1);
9
10
*x=(x1<<8)|x0;
11
*y=(y1<<8)|y0;
12
*z=(z1<<8)|z0;
13
}
Es handelt sich um vorzeichenbehaftete Zahlen und die Daten einer Achse
bestehen aus High- und Low Byte.
Wie kann ich jetzt rausfinden, was nicht passt? Logic Analyzer geht
schlecht, weil der kein Signal durchschleift.
Das einzige, was ich mir noch vorstellen könnte, das ich falsch gemacht
habe, ist die Polarität mit CPOL und CPHA. Laut Datenblatt des
ADXL345:
1
The timing scheme follows clock polarity
2
(CPOL) = 1 and clock phase (CPHA) = 1.
Aber die habe ich auch im CR1 Register gesetzt...
Edit: Okay, irgendwas liefert der ADXL345 doch, wenn ich das Kabel
abstecke, bekomme ich -1 als Wert für X,Y&Z.
So sieht das Signal vom SDO-Pin des ICs aus:
Hm, das DEVID Register kann ich erfolgreich auslesen, es kommt auch
der richtige Wert zurück (229 dezimal).
Was stimmt dann mit dem auslesen der Koordinaten nicht?
Edit: Hm, es könnte sein, dass im Register einfach keine neuen Daten
vorliegen bzw. ich sogar die Daten lese, die ich eigentlich schreiben
wollte (da ja ein Register für Transmit und Receive verwendet wird).
Oder wird das Register nach jedem Lesevorgang gelöscht?
Edit_2:
Wenn ich meine SPIReceive Funktion so schreibe:
1
uint8_tSPIReceive(){
2
uint8_tregisterValue;
3
registerValue=(SPI->DR);
4
returnregisterValue;
5
}
bekomme ich den Wert 0 (logisch).
Wenn ich die Funktion dagegen so schreibe:
1
uint8_tSPIReceive(){
2
uint8_tregisterValue;
3
while(!(SPI->SR&(1<<0))){
4
nop();//wait until receive buffer is not empty
5
}
6
registerValue=(SPI->DR);
7
returnregisterValue;
8
}
Bekomme ich den dezimalen Wert 2827 für alle Achsen.
Wenn ich sie wiederum so schreibe:
Ich hab nun überprüft, ob vllt. doch CPHA oder CPOL die Ursache sind.
Dafür hab ich 4 Versuche gemacht.
1. Versuch (CPOL auf '0', CPHA auf '1'):
Die übertragenen Werte ändern sich sobald ich den Sensor bewege, der
Wert des DEVIDs Registers ist falsch bzw. er ändert sich sogar auch,
wenn ich den Sensor bewege?
2. Versuche (CPOL auf '1', CPHA auf '0'):
Das gleiche wie bei [1.]
3. Versuch (CPOL auf '0', CPHA auf '0'):
Das gleiche wie bei [1.]
Nur wenn ich CPOL und CPHA aktiviere, wird die DEVID richtig mit 229
ausgelesen. Hier ändern sich die Werte allerdings nicht.
Kann mir wirklich keiner helfen?
Ich versuche aktuell, das ganze mit den Funktionen aus der STM Standard
Peripheral Library zu machen, allerdings bekomme ich beim Aufrufen einer
Funktion aus der *stm8s_spi.h* bereits diese Fehlermeldung beim
Kompilieren:
1
#error clnk Debug\adxl345_spi.lkf:1 symbol _SPI_DeInit not defined (Debug\main.o )