Forum: Mikrocontroller und Digitale Elektronik STM32F030 SPI+DMA nach Transferende = Highlevel?


von Markus M. (adrock)


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...

von Clemens L. (c_l)


Lesenswert?

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?)

von Markus M. (adrock)


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.

von Stefan K. (stefan64)


Lesenswert?

Wie wäre es, statt dem Transferende einfach noch ein paar Null-Bytes 
auszugeben?
Der DMA kann einen solchen Block dann ständig round-robin ausgeben. Neu 
daten werden in einen 2. Block gekippt und sobald der voll ist, wird der 
DMA auf den neuen Block umgschaltet.

Gruß, Stefan

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Hast Du evt einen externen Pull Widerstand eigebaut oder den internen 
Pullwiderstand des GPIO Pins aktiviert?

von Basti (Gast)


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...

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

STM32 GPIO kennt leider kein Bit fuer das invertieren des Portausganges. 
Die gpio-interne PullUp/Pull Down Widerstaende sollten aber das Problem 
erschlagen.

von Markus M. (adrock)


Angehängte Dateien:

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.

von Markus M. (adrock)


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.

: Bearbeitet durch User
von Basti (Gast)


Lesenswert?

Wenn der STM kein Invertierer am GPIO kennt, dann bau halt ein kleines 
Logikgatter hinter den Port... man muss ja nicht alles in Software 
erschlagen...

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.