Forum: Mikrocontroller und Digitale Elektronik STM32F4 - DMA read GPIO_IDR to RAM


von Sebastian (Gast)


Lesenswert?

Hallo Zusammen,

ich sitze schon einige Stunden/Tage an einem Problem das mich zum 
verzweifeln bring. Ich versuche mit einem STM32 (NUCLEO - F429 Board) 
das Input Register vom Port E in den Ram zu schreiben. Leider ohne 
Erfolg. Der DMA wird durch ein Timer Input Capture Event getriggert. 
Der Timer triggert mit einer Frequenz von 6 MHz.

Wenn ich den DMA aktiviere setzt er sofort das transfer error interrupt 
flag (TEIF4) für den verwendeten Stream (Stream4) und schaltet sich ab.
Ich bin bereits das Reference Manual RM0090 mehrere Male diesbezüglich 
durchgegangen. Leider finde ich dort nichts brauchbares bzgl. dieses 
Error Flags. " A bus error occurs during a DMA read or a write access" 
ist auch nicht wirklich hilfreich.

Das ist mein erstes mal das ich den DMA verwende und hoffe das mir 
jemand einen Tipp geben kann was ich falsch mache. Ich habe noch die 
relevanten Codeabschnitte beigefügt:

Peripherie Clock aktivieren:
1
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOE, ENABLE);
2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
3
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
4
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

Globale Variable deklarieren:
1
// Image buffer
2
volatile uint16_t frame_buffer[IMG_ROWS * IMG_COLUMNS];

GPIO Pins und DMA configurieren:
1
 ///////////////// DMA configuration ///////////////////////
2
    ///////////////////////////////////////////////////////////
3
    /* Init PE8-PE15 for DMA source */
4
GPIO_StructInit(GPIO_InitStructure);
5
GPIO_InitStructure.GPIO_Pin = 0xFF00;       // Pin8 .. Pin15
6
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
7
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
8
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
9
GPIO_Init(GPIOE,&GPIO_InitStructure);
10
11
DMA_StructInit(&DMA_InitStructure);
12
DMA_Cmd(DMA1_Stream4, DISABLE);
13
while (DMA1_Stream4->CR & DMA_SxCR_EN);
14
DMA_InitStructure.DMA_Channel = DMA_Channel_5;    // TIM3_CH1 as Trigger
15
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(GPIOE->IDR);  //address should be 0x40021011 but IDR allows only word read
16
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&frame_buffer[0];    //frame buffer in RAM
17
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;     //direction of transfer
18
DMA_InitStructure.DMA_BufferSize = IMG_ROWS * IMG_COLUMNS / 2;      //define size of buffer
19
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
20
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
21
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;   //not sure
22
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;  
23
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;               //using of non circular mode
24
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
25
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;           //enable FIFO mode
26
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;   //
27
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
28
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
29
DMA_Init(DMA1_Stream4, &DMA_InitStructure);
30
//Note: stream is activated later
31
TIM_DMACmd(TIM3, TIM_DMA_CC1, ENABLE);      //Capture/Compare 1 DMA request enable

Der DMA wird später im Code aktiviert:
1
DMA1->HIFCR = DMA_FLAG_FEIF4|DMA_FLAG_DMEIF4|DMA_FLAG_TEIF4|DMA_FLAG_HTIF4|DMA_FLAG_TCIF4;   //clear all event flags of stream 4
2
DMA_Cmd(DMA1_Stream4, ENABLE);

den Timer code habe ich weggelassen, da dieser funktioniert. Ich hoffe 
ich habe nichts vergessen. Ich verwende zum Teil die Standard Lib von 
ST.

Vielen Dank schon mal

Sebastian
von Kasus (Gast)


Lesenswert?

Hast Du schon einen Word-Zugriff ausbrobiert? Ich weiß nicht ob man 
Register halbwortbreit adressieren kann.
von W.S. (Gast)


Lesenswert?

Sebastian schrieb:
> A bus error occurs during a DMA

Wieso reicht dir das denn nicht? Dein DMA greift auf eine nicht 
existierende Adresse zu oder er greift auf eine unzulässige Weise 
drauf zu, also z.B. unaligneter Wortzugriff oder unzulässige 
Zugriffsbreite.

W.S.
von Sebastian (Gast)


Lesenswert?

Hallo

Danke für die Antworten.

Kasus:
>Ich weiß nicht ob man Register halbwortbreit adressieren kann

Ich habe dazu das RM0090 befragt und feststellen müssen das deine 
Vermutung richtig ist.
GPIOx_IDR - These bits are read-only and can be accessed in word mode 
only.

W.S.:
>unaligneter Wortzugriff oder unzulässige Zugriffsbreite.

ich nutze die Register Startadresse als Zugriffsadresse also denke ich 
das diese ausscheidet. Mit Zugriffsbreite meinst du das ich nur das 
komplette Register lesen darf also ein word, richtig?

Ich werde heute abend noch ein bischen mit den Einstellungen "spielen" 
und mich nochmal etwas genauer in die FIFO Geschichte einlesen.
Word nach Word kopieren (ohne FIFO) funktioniert irgendwie auch nicht.

Ich berichte sobald ich etwas Neues weiß.

Grüße
von Sebastian (Gast)


Lesenswert?

Hallo

Danke für die Tipps. Habs endlich zum laufen bekommen.

Habe das Kapitel DMA im RM0090 zich mal durchgelesen, mir aber nie 
Abbildung 34 auf Seite 308 richtig angeschaut. Dort kann man erkennen 
das DMA1 keinen Zugriff auf AHB1 Peripherals hat, jedenfalls 
interpretiere ich das so. Die GPIO Ports hängen allerdings am AHB1 
Clock.

Lange Rede kurzer Sinn ich kann jetzt mittels DMA2 auf das IDR Register 
von Port C zugreifen und die Daten werden in mein Bufferarray verschoben 
(mit und ohne FIFO).

Im Nachhinein ganz leicht :)

Grüße

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