PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] XMEGA/XPLAINED: DMA Zugriff auf SDRAM läuft nicht



erik_wolfram
21.07.2014, 07:30
Hallo,

leider stehe ich schon wieder vor einem neuen Problem - mir gelingt es nicht per DMA in den SDRAM zu schreiben.
Hierzu habe ich zunächst das Tutorial "AVR1312: Using the XMEGA External Bus Interface" abgearbeitet welches ohne Probleme lief.

Beim DMA-Zugriff funktioniert das leider nicht. Nach längerem Suchen ist mir dann aufgefallen, dass die Funktion DMA_SetupBlock() aus dem Tutorial "AVR1514: XMEGA-A1 Xplained Training - Direct Memory Access Controller" nur bis 16 Bit Addressen ausgeführt war. Dementsprechend habe ich die Funktion für 24-Bit Addressen modifiziert. Die erste Addresse wird auch beschrieben, aber alle weiteren Folgeaddressen bleiben per DMA unbeschrieben. Die Inkrementierung der Addressen ist im entsprechenden DMA-Kanal vorgenommen.

Hier mal ein Auszug meines Codes:


#define SDRAM_SIZE 0x800000UL // Größe des benötigten SDRAMs
#define MEMORY_BLOCK 0 // MEMORY_BLOCK = (16MB/RAM_SIZE - 1)
uint32_t SDRAM_ADDR = (SDRAM_SIZE * MEMORY_BLOCK); // Addresse des SDRAM-Bereichs

DMA_CH_t * SDRAMChannel = &DMA.CH0;

void initSDRAM()
{
// Bus Pins als Ausgang, außer die Datenleitungen (DQ0-DQ3)
PORTH.DIR = 0xFF;
PORTK.DIR = 0xFF;
PORTJ.DIR = 0xF0;

EBI_Enable( EBI_SDDATAW_4BIT_gc, // Datengröße 4 Bit
EBI_LPCMODE_ALE1_gc,
EBI_SRMODE_ALE12_gc,
EBI_IFMODE_3PORT_gc );

EBI_EnableSDRAM( EBI_CS_ASPACE_8MB_gc, /* 8 MB address space. */
SDRAM_ADDR, /* Base address. */
false, /* 2 cycle CAS Latency. */
true, /* 12 Row bits. */
EBI_SDCOL_10BIT_gc, /* 10 Column bits. */
EBI_MRDLY_2CLK_gc, /* 2 cycle Mode Register Delay. (min 2CLK) */
EBI_ROWCYCDLY_1CLK_gc, /* 1 cycle Row Cycle Delay. */
EBI_RPDLY_1CLK_gc, /* 1 cycle Row to Pre-charge Delay. (min 37ns) */
EBI_WRDLY_2CLK_gc, /* 2 cycle Write Recovery Delay. (1CLK + 7ns)*/
EBI_ESRDLY_1CLK_gc, /* 1 cycle Exit Self Refresh to Active Delay. (min 67ns) */
EBI_ROWCOLDLY_1CLK_gc, /* 1 cycle Row to Column Delay. (min 15ns) */
0x001F, /* 31 cycle Refresh Period (max 15.625us). */
0x00C8 ); /* 200 cycle Initialization Delay (min 100us). */

delay_us( 100 );
}

void SetupSDRAMChannel( DMA_CH_t * dmaChannel )
{
TCF1.CNT = 0x62;

dmaChannel->SRCADDR0 = (( (uint16_t) (void *) &TCF1.CNT) >> 0*8 ) & 0xFF;
dmaChannel->SRCADDR1 = (( (uint16_t) (void *) &TCF1.CNT) >> 1*8 ) & 0xFF;
dmaChannel->SRCADDR2 = 0;

// 24-Bit Addresse muss manuell gesetzt werden
dmaChannel->DESTADDR0 = (( (uint32_t) SDRAM_ADDR) >> 0*8 ) & 0xFF;
dmaChannel->DESTADDR1 = (( (uint32_t) SDRAM_ADDR) >> 1*8 ) & 0xFF;
dmaChannel->DESTADDR2 = (( (uint32_t) SDRAM_ADDR) >> 2*8 ) & 0xFF;

dmaChannel->ADDRCTRL = DMA_CH_SRCRELOAD_NONE_gc | DMA_CH_SRCDIR_FIXED_gc | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_INC_gc;
dmaChannel->TRFCNT = 1;
dmaChannel->CTRLA |= DMA_CH_BURSTLEN_1BYTE_gc;

DMA_EnableSingleShot( dmaChannel );
DMA_SetTriggerSource( dmaChannel, DMA_CH_TRIGSRC_TCC0_OVF_gc );
}

ISR( TCC0_OVF_vect ){}

ISR( TCC1_OVF_vect ){}

void SetUpAllTimers( void )
{
TCC1.PER = 1000; // Überlauf bei Grenzwert der zu nehmenden Samples
TCC1.CNT = 48; // 0
EVSYS_SetEventSource( 0, EVSYS_CHMUX_TCC0_OVF_gc ); // Event channel 0 erfasst die Überläufe des Timers TCC1
TCC1.CTRLA = TC_CLKSEL_EVCH0_gc; // Als clock source wird der event channel 0 gesetzt

TCC0.PER = 1000;
// Timer Iinterupt aktivieren und Priorität setzten
TCC0.INTCTRLA = TC_OVFINTLVL_MED_gc;
// annährend gleichzeitiges Starten der Timer mit Prescaler von 1
TCC0.CTRLA = (TCC0.CTRLA & ~TC0_CLKSEL_gm) | TC_CLKSEL_DIV1_gc;
}

int main( void )
{
// SDRAM initialisieren
initSDRAM();

for (uint32_t i = 0; i < 5; i++) {
__far_mem_write( i + SDRAM_ADDR, 0x65 );
}

DMA_Enable();

// DMA-Kanäle initialisieren
SetupSDRAMChannel( SDRAMChannel );

// DMA-Kanäle starten
DMA_EnableChannel( SDRAMChannel );

SetUpAllTimers();

// Warten bis 10 Werte im SDRAM
while( TCC1.CNT < 10){}

uint8_t result;

for (uint8_t i = 0; i < 5; i++)
{
result = __far_mem_read( i + SDRAM_ADDR );
.... // AUsgabe
}
....


Die SDRAM zugriffe mit den vorgefertigten Funktionen funktionieren - in den Funktionen wird nochmal betont, dass GCC die 24 Bit Addressen nicht unterstützt.

Ich hoffe es sieht jemand den Fehler. Ich habe hierzu schon die Application Notes durchgearbeitet - bin aber leider nicht fündig geworden.

Gruß Erik


[EDIT] Erhöhe ich den Trafficcount TRFCNT im DMA - so werden die folgenden Addressen entsprechend mit dem gleichen Wert beschrieben..

[EDIT No.2] Es tut mir leid - nach langem Suchen habe ich den Fehler gefunden. Beim Kopieren/Ändern der Funktion DMA_SetupBlock habe ich TRFCNT ausversehen auf 1 gesetzt - da muss natürlich die 0 für unendich hin.
Meinetwegen kann dieses Thema gerne wieder gelöscht werden - ich sehe hier leider keine Möglichkeit das selbst zu tun.