Forum: Mikrocontroller und Digitale Elektronik SPI-Schnittstelle Befehl: SPI_I2S_SendData(spi2, data)


von Alex W. (scipio)


Lesenswert?

Hallo,

ich habe mal eine Verständnisfrage zu diesem, im Betreff genannten, 
Befehl. Was passiert, wenn ich dem Befehl, mit der Variabel data, ein 8 
Bit langes Wort (Byte) übergebe? Beipielsweise so etwas hier 00100010.
Wird dieses unverändert übertragen oder werden da Bits vorne oder hinten 
angehängt, da etwa nur eine bestimmte Wortlänge z.B.: 16 Bit (Word) 
übertragen werden kann.

MfG Scipio

von Jim M. (turboj)


Lesenswert?

Use the source, luke. Die Peripherial Lib wird als C Code ausgeliefert, 
da kann man einfach mal reinschauen und mit dem dicken Manual 
vergleichen.

Mir scheint außerdem, dass Du mal in ein gutes C Buch reinschauen 
solltest,
denn 00100010 wird als oktaler Wert in C behandelt und entspricht 32776. 
Das passt nicht in ein Byte.

Zu Deiner Frage mal eine Gegenfrage: Was passiert denn in C, wenn man 
eine Byte (char) Variable einem Integer (int) zuweist?

von Alex W. (scipio)


Lesenswert?

Hi,

erst einmal danke für deine Antwort. Ich sollte vielleicht etwas mehr 
darüber verraten, was ich eigentlich vor habe. Ich möchte mit der einer 
der SPI-Schnittstellen eine STM32L152RBT6 eine Phase Lock Loop 
(ADF4360-4) Konfigurieren. (Ich hänge das Datenblatt an) Dieser Chip hat 
3 24 Bit Latches. Diese müssen über eine SPI Schnittstelle mit Werten 
geladen werden.
(Als Information zum Nachschlagen, die Latches hießen R-Counter, 
N-counter und Control)

Um die ganze Sache noch etwas schwieriger zu machen, scheint die 
SPI-Schnittstelle der ADF4360-4 keine Standartausführung zu sein. Sie 
verfügt, wie im Datenblatt zu sehen ist, über einen mit LE bezeichneten 
Pin. Mit diesem komme ich nicht wirklich zurecht. Auf diesen Pin muss 
ich, jedesmal, wenn ein Register fertig geladen ist, kurz mit High 
belegt werden. Dies scheint mir nicht unbedingt zum Standard einer 
SPI-Schnittstelle zu gehören. Im Forum von Analog Divices will mir 
keiner antworten....

Ich gebe es offen zu, dass ich nicht sonderlich bewandert in solchen 
Dingen bin. Ich habe leider auch einiges wieder vergessen. Das ändert 
aber nichts an der Tatsache, dass für das Problem eine Lösung her muss.

Nun zu deiner Frage: Laut meinem C-Buch "C kurz und gut" wird, wenn eine 
Variable mit dem Typ char den Typ int zuweist, wird eine 
Ganzzahl-Erweiterung durchgeführt. Da der Datentyp char einen kleineren 
Umfang hat als der Datentyp int. Andersherum können Informationen 
verloren gehen. Die zusätzliche Bytes werden als höherwertige Bytes 
angefügt.

von isidor (Gast)


Lesenswert?

Alex W. schrieb:
> Um die ganze Sache noch etwas schwieriger zu machen, scheint die
> SPI-Schnittstelle der ADF4360-4 keine Standartausführung zu sein. Sie
> verfügt, wie im Datenblatt zu sehen ist, über einen mit LE bezeichneten
> Pin.

Das ist nicht schwierig.

Wenn du Zugriff auf den SS (Slave Select) deines Controllers
hast dann benutze ihn dazu den LE zu betätigen. Das bedeutet
(für jeden 24-Bit Registerzugriff):

- LE low
- SPI Daten 24 Bit senden
- LE high
- Minimalzeit für LE warten (siehe ADF4360)
- LE Low

Der CE (Chip enable) muss während dieses Zyklus aktiv high sein,
kann aber auch statisch immer high bleiben.
Damit hast du ein ADF4360 Register gültig beschrieben.

Falls es diese Möglichkeit (den SS zu "misbrauchen") nicht gibt
musst du einen anderen Portpin als Ausgang definieren und diesen
benutzen um LE auf die oben angegebene Weise zu steuern.

von Alex W. (scipio)


Angehängte Dateien:

Lesenswert?

@isidor:

Sehr schön, das klinkt schon nach dem, was ich in mein Programm 
geschrieben habe. Oder wenigstens nach dem was ich beabsichtigt habe.
Aber machen wir es doch einfach mal konkret:
1
 
2
// Zu beginn erst einmal die Zuweisung der Pins (sind in einem eigenen Header untergebracht)
3
4
#define LE       GPIO_Pin_10    //PA10  SPI-PLL
5
#define DATA             GPIO_Pin_7    //PA7  SPI-PLL
6
#define CLK      GPIO_Pin_5    //PA5  SPI-PLL 
7
#define CE       GPIO_Pin_0    //PC0   PLL-Aktiv
8
9
10
// Es folgt die Initialiesierung der 
11
void SPI3_Init()
12
{
13
    GPIO_InitTypeDef GPIO_InitStructure;
14
    NVIC_InitTypeDef NVIC_InitStructure;
15
    SPI_InitTypeDef SPI_InitStructure;
16
    DMA_InitTypeDef DMA_InitStructure;
17
18
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); //
19
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
20
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
21
22
    GPIO_InitStructure.GPIO_Pin = CE;
23
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
24
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
25
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
26
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
27
    GPIO_Init(GPIOC, &GPIO_InitStructure);
28
    GPIO_ResetBits(GPIOC, CE);
29
30
    GPIO_InitStructure.GPIO_Pin = (MUXOUT);
31
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
32
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
33
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
34
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
35
    GPIO_Init(GPIOC, &GPIO_InitStructure);
36
37
    GPIO_InitStructure.GPIO_Pin =  (LE|DATA|CLK);
38
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //output mode
39
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //output type: push pull
40
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
41
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
42
    GPIO_Init(GPIOB, &GPIO_InitStructure);
43
44
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI1); 
45
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_SPI1); 
46
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI1);
47
48
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
49
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
50
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
51
    SPI_InitStructure.SPI_CRCPolynomial = 0;
52
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
53
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
54
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
55
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
56
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
57
    SPI_Init(SPI1, &SPI_InitStructure);
58
59
    SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Tx, ENABLE); 
60
} 
61
62
void ConfigPLL(){
63
  
64
  /*Dieses Array enthält die Registerbelegung in 9 Abschnitten mit je 8 Bit. Ich bin mir mittlerweile nicht mal mehr sicher, ob ich die einzelnen Register wirklich in 8 Bit große Einheiten aufteilen muss.
65
  */
66
  uint8_t x[9] = {00100000, 00001010, 00000110, 01000001, 11000100, 00101000, 00010000, 00001010, 00000110}; 
67
68
  SPI_Cmd(SPI3, ENABLE);
69
70
  GPIO_WriteBit(GPIOB, CE, SET);
71
72
  int t;
73
  t=0;
74
  int ti;
75
  ti=1;
76
77
78
  while(t < sizeof(x));
79
  {
80
    //Im Example, welches ich finden konnte war dies so angegeben, aber brauch ich dass, was hier im auskommentierten Bereich steht wirklich?
81
    //Es scheint sich um eine Art Adressierung zu handeln
82
  /*SPI_I2S_SendData(SPI3, 0x3);
83
84
    while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET)
85
      ;
86
87
    SPI_I2S_SendData(SPI3, 0x4);
88
89
    while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) == RESET)
90
      ;
91
  */ 
92
  SPI_I2S_SendData(SPI3, x[t]);
93
94
  t++;
95
96
  if(ti > 2){
97
    //nach jedem dritten 8Bit block soll der LE Pin kurz aktiviert werden, die Zeit soll 20 ns betragen.
98
    //Da ich keinen so kleinen Timer finden konnte, hoffe ich dass dies ausreicht.
99
    GPIO_WriteBit(GPIOB, LE,SET);
100
101
    GPIO_WriteBit(GPIOB,LE, RESET);
102
    ti = 0;
103
  }
104
ti++;
105
  }
106
  ti++;
107
  SPI_Cmd(SPI3, DISABLE);
108
109
110
}

Das ist die Funktion, wie ich sie geschrieben habe, samt Initialisierung 
der SPI-Schnittstelle und Pin-Belegung.
Die bei gelegten Dokumente sind das Manual des Mikrocontrollers, aus 
welchem sich die Pin-Belegung ableitet, eines welches das 
Evaluationboard zeigt, welches ich verwende, und zuletzt noch das 
Datenblatt der ADF4360-4. Die SPI-Schnittstelle ist zum senden 
initialisiert, sie braucht keine Daten zu empfangen.

von Jim M. (turboj)


Lesenswert?

Alex W. schrieb:
> /*Dieses Array enthält die Registerbelegung in 9 Abschnitten mit je 8
> Bit. Ich bin mir mittlerweile nicht mal mehr sicher, ob ich die
> einzelnen Register wirklich in 8 Bit große Einheiten aufteilen muss.
>   */
>   uint8_t x[9] = {00100000, 00001010, 00000110, 01000001, 11000100,
> 00101000, 00010000, 00001010, 00000110};


Auch wenn da nur Nullen und Einsen stehen, sind das noch lange keine 
Binärwerte. Bei den führenden Nullen interpretiert der Compiler 
Oktalwerte, bei führenden Einsen Dezimalwerte. Lies endlich ein C-Buch! 
Viele der Zahlen passen nicht in 8 Bits.

Gewöhne Dir besser mal an, Binärwerte als Hex aufzuschreiben,
z.B: 0b00100000 = 0x2F

Binärwerte sind oft scheisse zu lesen, weil man zuviele Stellen 
überblicken muss. Bei Hex hat man für jedes Nibble eine eigene Zahl. Das 
bedeutet auch, dass man mit etwas Übung den Wert jedes einzelnen Bits 
direkt ablesen kann.

Was mir auch einfällt: Schau nach, ob SPI_I2S_SendData() überhaupt bis 
zum Ende der Übertragung wartet. Oftmals kommen solche Funktionen schon 
nach dem Schreiben des DR Registers zurück, das wäre zu früh - die 
Übertagung läuft dann noch.

von Alex W. (scipio)


Lesenswert?

@Jim Meba:

Ich habe schon verstanden, was du mir gesagt hast. Ich hatte die 
Änderung der Werte erst vorgenommen, nach dem ich den Code hier 
eingestellt habe.

Mittlerweile funktioniert die PLL einwandfrei. Danke für deine Hilfe.

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.