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...
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?)
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.
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
Hast Du evt einen externen Pull Widerstand eigebaut oder den internen Pullwiderstand des GPIO Pins aktiviert?
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...
STM32 GPIO kennt leider kein Bit fuer das invertieren des Portausganges. Die gpio-interne PullUp/Pull Down Widerstaende sollten aber das Problem erschlagen.
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.
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.