STM32F030 SPI+DMA nach Transferende = Highlevel?

OP #4320800
Lesenswert?

Hi,

habe auf dem STM32F030 ein SPI per DMA realisiert. Es funktioniert auch 
alles, nur nach dem Ende des DMA-Transfers hat der SPI immer high level, 
auch wenn die letzten ausgegebenen Bits "0" waren.

Ist das normal? Wenn ich nach dem DMA-Transfer ohne DMA mehrere (eins 
reicht nicht!) weitere 0-Bytes per SPI ausgebe, bleibt der Pegel danach 
low.

Der Code verwendet direkt die Register ohne CMSIS, ich liefere ihn gerne 
nach (habe jetzt gerade kein Zugriff), aber vlt. hatte ja jemand schon 
den gleichen Effekt...
OP #4320949
Lesenswert?

Clemens L. schrieb:
> Markus M. schrieb:
>> nach dem Ende des DMA-Transfers hat der SPI immer high level
>
> Welches der beiden Signale? (Und warum stört dich das?)

Es geht um das Datensignal, also nicht Clock.

Es stört mich, weil ich den SPI benutze um ein asynchrones Signal zu 
generieren für die Ansteuerung von WS2812 LEDs. Am Ende des Bitstreams 
erwarten diese einen Low-Pegel.

Den UART kann ich dafür nicht verwenden, da er immer zwingend 
Start/Stopbits sendet. Ich könnte es auch ohne DMA machen, aber gerade 
die DMA macht es elegant.
Gast #4321066
Lesenswert?

Wie wäre es den Portausgang zu invertieren... Die Daten dann natürlich 
auch entsprechend anders in den Buffer packen und du kannst den DMA 
verwenden...

Jedenfalls hab ich das vor Monden mit einem XMega ebenfalls so getan...
OP #4321761
Lesenswert?

Hi,

also es liegt ja nicht am Pullup/Pulldown. Wenn ich die Daten direkt in 
das Datenregister schreibe verhält sich der SPI ja korrekt.

Nur am Ende des DMA-Transfers setzt er den Ausgang auf High.

Hier ist ein Stück Code, welches mein Problem verdeutlicht:
1
static uint8_t serialBuf[] = { 0b10101010 };
2

3
   /* Initialize hardware */
4

5
  RCC->AHBENR |= RCC_AHBENR_GPIOAEN|RCC_AHBENR_DMA1EN;  /* Enable GPIO A, DMA */
6
  RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;        /* Enable SPI1 */
7

8
  GPIOA->MODER |= GPIO_MODER_MODER7_1;       /* Set PA7 to alternate function */
9
  GPIOA->AFR[0] = 0;
10

11
  /* Setup SPI */
12

13
   /* We are running at 48 MHz, so set divider to /16, so we have 0.33 us bit length */
14

15
  SPI1->CR1 = SPI_CR1_BIDIMODE|SPI_CR1_BIDIOE|SPI_CR1_SPE|SPI_CR1_BR_0|SPI_CR1_BR_1|SPI_CR1_MSTR|SPI_CR1_SSM|SPI_CR1_SSI;
16
  SPI1->CR2 = SPI_CR2_DS_0|SPI_CR2_DS_1|SPI_CR2_DS_2|SPI_CR2_TXDMAEN;
17

18
   /* Do DMA! */
19

20
   while(1) {
21

22
  DMA1_Channel3->CPAR = &(SPI1->DR);
23
  DMA1_Channel3->CMAR = serialBuf;
24
  DMA1_Channel3->CCR = DMA_CCR_PL_0|DMA_CCR_PL_1|DMA_CCR_MINC|DMA_CCR_DIR;
25
  DMA1_Channel3->CNDTR = sizeof(serialBuf);
26
   DMA1->IFCR = DMA_IFCR_CGIF3;
27
  DMA1_Channel3->CCR |= DMA_CCR_EN;
28
  while((DMA1->ISR & DMA_ISR_TCIF3) == 0);
29
  DMA1_Channel3->CCR &= ~DMA_CCR_EN;
30

31
   for(int X = 0; X < 100000; X++);       // some delay...
32

33
   }

Im ersten Anhang ist das Signal, welches dieser Code erzeugt. Der SPI 
arbeitet so wie konfiguriert als MSB first, d.h. ich würde erwarten das 
der Ausgang nach dem letzten Bit low bleibt.

Ich dachte nun auch, ich würde einfach noch ein Nullbyte 
hinterherschicken und alles ist gut, also die Zeile mit den Daten so 
verändert:
1
  static uint8_t serialBuf[] = { 0b10101010, 0 };

Das erzeugt dann das Signal im zweiten Anhang, was noch merkwürdiger 
ist. D.h. er setzt nach Abschluss des DMA den SPI offenbar explizit auf 
high.
Angehängte Dateien:
OP #4321782
Lesenswert?

Achja, wenn ich die Daten manuell schreibe tritt das Problem auch auf.

Sende ich allerdings ZWEI Nullbytes hintereinander, bleibt der SPI 
danach auf low.

Ich verstehe das Verhalten nicht, aber es mag sein das in dem Kontext 
der Zustand des SPI MOSI Ausgangs garnicht definiert ist, da ja kein 
Clocksignal mehr kommt solange keine neuen SPI-Daten gesendet werden.

Der korrekte Weg wäre somit wohl nach dem Senden der Daten den Ausgang 
direkt per GPIO auf low zu setzen.

Oder die Lösung von Stefan mit dem zweiten DMA, aber der STM32F030 kann 
glaube ich kein DMA double buffering, müsste man dann also tatsächlich 
per ISR anstoßen.

Danke - somit ist mein Problem geklärt und gelöst.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren