Forum: Mikrocontroller und Digitale Elektronik AD9833 mittels STM32F072 per SPI ansteuern


von David K. (dekay)


Angehängte Dateien:

Lesenswert?

Hallo Community,

vielleicht kann mir jemand bei meinem Problem behilflich sein. Ich habe 
schon einige Forenbeiträge hier durchgelesen, diese haben mir auch sehr 
geholfen jedoch spuckt meine SPI-Schnittstelle immer noch nichts aus.

Ich möchte den AD9833 wie oben bereits beschrieben mit einem Cortex M0 
über SPI ansteuern. Ich möchte nur an den AD9833 senden, also 
Transmission only. Derzeit versuche ich nur das SPI zu initialisieren 
und über MOSI in einer Schleife Daten zu senden.

Jedoch kann ich mittels Oszilloskop nichts an MOSI oder SCK messen, 
außer "rauschen" ist da nichts.

Oben im Anhang habe ich die Codes eingefügt, werde aber auch hier 
nochmal Teile einbinden.

initialisierung meines NSS, ich möchte NSS mittels normalem GPIO-Port 
auf Low bzw. High setzen.
1
void initNSS()
2
{
3
  //RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
4
5
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;   //Pin auswählen
6
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //Als Ausgang deklarieren
7
  GPIO_InitStructure.GPIO_OType= GPIO_OType_PP; // Push-pull gibt definiert High oder Low aus
8
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50MHz als Takt
10
  GPIO_Init(GPIOA, &GPIO_InitStructure);
11
12
  GPIO_ResetBits(GPIOA, GPIO_Pin_6); // NSS Standardmäßig auf 0 setzen
13
}

Danach initialisiere ich die anderen GPIO-Pins Mosi und SCK und verweise 
sie als AF auf die SPI1:
1
void initSPI_Pins()
2
{
3
  //RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
4
  
5
  // Pin 5 SCK initialisieren
6
7
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
8
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
9
  GPIO_InitStructure.GPIO_OType= GPIO_OType_PP; // Push-pull gibt definiert High oder Low aus
10
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // pull up
11
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
12
  GPIO_Init(GPIOA, &GPIO_InitStructure);
13
14
  // Pin 7 MOSI initialisieren#
15
16
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
17
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
18
  GPIO_InitStructure.GPIO_OType= GPIO_OType_PP; // Push-pull gibt definiert High oder Low aus
19
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // Pull up
20
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
21
  GPIO_Init(GPIOA, &GPIO_InitStructure);
22
23
  // Connect SPI Pins to AF1
24
25
  GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_1);
26
  GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_1);
27
}

Anschließend initialisiere ich die SPI:
1
void initSPI()
2
{
3
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
4
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
5
  SPI_I2S_DeInit(SPI1); //Reset des SPI1-Registers#
6
7
  initNSS();
8
    initSPI_Pins();
9
10
11
  SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx; //Transmission Only
12
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
13
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 8b = 1Byte 16b = 2Byte
14
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;    //FSYNC aktiv (fallende FLanke) muss SCLK währenddessen High sein
15
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;  //Daten werden mit der fallenden Flanle der Clock übertragen.
16
  SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;  //NSS deaktiviert
17
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
18
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
19
  SPI_InitStructure.SPI_CRCPolynomial = 7;
20
  SPI_Init(SPI1,&SPI_InitStructure);
21
22
//  IS_SPI_NSS_INTERNAL(SPI_NSSInternalSoft_Set); //Interner NSS auf High für Master /notwendig?
23
  SPI_SSOutputCmd(SPI1,ENABLE);
24
25
  SPI_RxFIFOThresholdConfig(SPI1, SPI_RxFIFOThreshold_QF); //Flag RXNE wird gesetzt nach zwei Byte HF /ein Byte QF
26
  SPI_CalculateCRC(SPI1,DISABLE); //Deaktiviert CRC calculation
27
  SPI_Cmd(SPI1,ENABLE); // AKtiviert die SPI1-Schnittstelle
28
29
}

Hier meine Funktion zum schreiben:
1
void DDS_write(uint16_t data)
2
{
3
  //SPI_RxFIFOThresholdConfig(SPI1, SPI_RxFIFOThreshold_HF);
4
    GPIO_ResetBits(GPIOA, GPIO_Pin_6); // NSS aktiveren
5
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); //wait buffer empty
6
    SPI_I2S_SendData16(SPI1, data);
7
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); //wait finish sending
8
    GPIO_SetBits(GPIOA, GPIO_Pin_6); // NSS deaktivieren
9
}

Und hier meine Main-Funktion:
1
int main(void)
2
{
3
  SystemInit();
4
  LED_Init();
5
  initSPI();
6
7
  data = 0b01010101;
8
9
10
    while(1)
11
    {
12
13
        DDS_write(data); // Signal zum testen
14
    }
15
}

Wäre nett wenn mir vielleicht jemand weiterhelfen könnte, sieht was ich 
falsch gemacht oder vergessen habe. Vielen Dank schonmal für eure Hilfe!

von holger (Gast)


Lesenswert?

>  SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;  //NSS deaktiviert

  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;  //NSS deaktiviert

Folgende einfach erstmal weglassen:

//  IS_SPI_NSS_INTERNAL(SPI_NSSInternalSoft_Set); //Interner NSS auf 
High für Master /notwendig?
  SPI_SSOutputCmd(SPI1,ENABLE);
  SPI_RxFIFOThresholdConfig(SPI1, SPI_RxFIFOThreshold_QF); //Flag RXNE 
wird gesetzt nach zwei Byte HF /ein Byte QF

  SPI_CalculateCRC(SPI1,DISABLE); //Deaktiviert CRC calculation

von W.S. (Gast)


Lesenswert?

David K. schrieb:
> SPI_InitStructure.SPI_

Mein lieber David, wenn ich so etwas lesen muß, wird mir schlecht. 
Definiere die betreffenden Pins erstmal ganz einfach als GPIO und mache 
das Ganze zunächst ganz simpel zu Fuß per Software, also dediziert 
Pin_high..Pin_low und so. Lies dazu das Manual zum betreffenden IC.

Wenn dann dein DDS läuft und die richtige Wellenform ausspuckt, kannst 
du immer noch die SPI-Schnittstelle anwerfen - aber geh dir nicht selber 
auf die Nerven mit dieser unsäglichen bescheuerten ST-Lib und ihren 
verquollenen hirnrissigen Pseudo-Schnittstellen a la XYZ_Initstructure 
und so. Das Zeugs hat noch nie wa getaugt und wird bis in Ewigkeit 
nichts taugen.

W.S.

von nur ein ganz normaler Mensch (Gast)


Lesenswert?

W.S. schrieb:
> Mein lieber David, wenn ich so etwas lesen muß, wird mir schlecht.

Guten Tag verehrter Herr / Frau W.S. :

Gleiches gilt, wenn ich Beitragseinleitungen wie siese lesen muß.

Wenn der STM32 Ihren anforderungen nicht genügt, gut.
Wenn Sie eine passende Alternative gefunden haben, besser.
Wenn jeder, die güt Ihn am geeigneteste Lösung finden darf, ideal.

von nur ein ganz normaler Mensch (Gast)


Lesenswert?

Hallo David.K;

wenn ich nix überlesen habe hast du das "Clock" Signal vergessen:
Auszug aus meinem (mit STM32Cube) erzeugten Code:
Nur Auszüge ;-)


.....
 /**SPI1 GPIO Configuration
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    PA7     ------> SPI1_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
.................

Warum fehlt NSS:
1. Funktioniert bei mir derzeit niur, wenn ich das NSS / CS = Chop 
select Signal selber steuere, mag aber eher daran liegen das ich selber 
ncoh Anfänger bin ;-).
.....
  NSS / CS wie folgt deklariert:
  /*Configure GPIO pin : PA4 */
  GPIO_InitStruct.Pin = GPIO_PIN_4;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
.....

ImMeinen Fall folgt daraus die SPI Config wie folgt:

.....
hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLED;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
  HAL_SPI_Init(&hspi1);
......


Ein paar allgemeine Tips:

1. Logic / Busanalyser verwenden.

Ein solches Gerät erscheint mir hierfür hilfreich, im Zweifel ergänzend 
zum Oszi.

Weil: Ich habe (Werbung) ein Zeroplus LogiCube, welches nicht nur 
Anzeigt, ob auf dem SPI Bus "etwas" passiert, sondern was.

Warum ist das Wichtig:
a) zum Test ob/ wie Hardware oder Software NSS (besser) funktioniert.
b) Nicht jeder Chip mit SPI unterstützt jeden Mode =
Kombination aus   "CLKPolarity" und "CLKPhase".

c) Mit welcher absoluten Geschwindigkeit arbeitet dein SPI
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;

--> Bezogen auf die Taktrate des Pheripheriebusses !

Also:
Wenn du die grundlegende Funktion der GPIO Pins des STM32 verstanden 
hast (W.S ;-))

1. Datenblatt des Controllers und  AD9833 lesen

--> Es ist eben auch wichtig, was mann, wie , in welcher Reihenfolge 
liesßt und sendet.
Wie beschrieben: Ein Busanalyser zeigt dier auch die gesendeten Daten 
an, nicht nur ein "Muster".


2. Nochmal versuchen

3. Nicht den Mut verlieren.


Nochmehr Tips:

1. Ich finde den Konfigurator "STM32CubeMX" hilfreich.
Insbesondere zum Einstellen der Taktraten.
2. Achte darauf die richtige Version der Cube Library zu verwenden.


Ich hoffe ich konnte etwas weiterhelfen

von nur ein ganz normaler Mensch (Gast)


Lesenswert?

Hallo David;
"Derzeit versuche ich nur das SPI zu initialisieren
und über MOSI in einer Schleife Daten zu senden."
"SPI_InitStructure.SPI_Mode = SPI_Mode_Master;"



Wenn ich nix überlesen habe:

MOSI: Master Out --> Slave In
MISO: Master In <-- Slave Out

Wie beschrieben, dir fehlt mindestens mal der Empfänger ?! ;-)
Oder anders:
Senden auf MOSI, mag ohne Teilnehmer funktionieren

Aber: Wenn kein Slave da ist, wer soll auf MISO zurücksenden ?

Lösungsansatze:
1.Prüfe die Konfiguration mit Angeschlossenenen AD9833 (auch mit 
Software NSS /CS)

2. Verwende eine zweiten Microcontroller als Slave.

3. Vewrnde den zweiten SPI Port deines Controllers als "Slave"

hoffe nochmals das das für dich / Sie hilfreich war ;-)

Gruß

von David K. (dekay)


Lesenswert?

Hallo erstmal vielen vielen dank für die vielen Kommentare und das ihr 
mir alle versucht zu Helfen sehr freundlich.

Ich werde natürlich gleich sofort versuchen ob einige Lösungsansätze 
funktionieren.

Aber ich möchte nochmal darauf hinweisen das ich nur senden möchte an 
den AD9833
1
  SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx; //Transmission Only

Weil soweit ich das sehe, erhalte ich von dem AD9833 keine brauchbaren 
informationen oder sehe ich das falsch?
Er hat auch quasi nur einen Data Anschluss. Somit möchte ich nur senden.

Aber derzeit ist es ja so, dass ich zumindest am Discovery Board die SCK 
oder MOSI messen müsste, wenn ich in einer schleife dauernd Daten sende.

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.