Перейти к содержанию
    

Проблема с Link List в DMA

Доброго времени суток!

 

Нужно в LPC2478 копировать блоки данных из памяти в память через DMA контроллер.

Все делаю, как прописано в мануале:

- подаю питание на DMA

- енаблю сам DMA

- очищаю регистры запросов прерываний на нужном канале

- устанавливаю адреса исходных и целевых данных на нужном канале

- устанавливаю адрес заранее записанного на флэшку связанного списка

- устанавливаю необходимые параметры размеров трансферов

- енаблю канал

 

В результате, первый блок копируется нормально, но ко второму элементу связанного списка DMA почему-то не доходит. Я уже не знаю что курить, кто сталкивался с такой проблемой- пожалуйста,поделитесь опытом.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопрос разрешился - память, куда я записывал список была недоступна для DMA). Странно, что при таком неправильном размещении списка, контроллер DMA не кидал ошибок.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Столкнулся с такой же проблемой!

Сейчас стоит LPC2468 ‘-’ Initial device revision (но там вроде с DMA ошибок у них не было).

 

Пробовал для On-chip RAM 0x7FD00000 - 0x7FD03FFF USB RAM (16 kB) и Off-Chip Memory 0xA0000000 - 0xAFFFFFFF Dynamic memory bank 0.

 

Для обоих результат такой-же, как и у Novichok1 - копируется только первый блок, но память-то я разрешенную для использования DMA использую.

Ели не сложно - взгляните свежим взглядом - где-то я что-то упускаю...

 

#define MEMORY_SOURCE		 0x7FD00000
#define MEMORY_DESTINATION	0x7FD01000
#define TRANSFER_SIZE		 16

int main(void)
{
 volatile unsigned int   chain_arr[3][4];
 unsigned char		  *temp1_ptr;
 unsigned char		  *temp2_ptr;
 unsigned int			i;


 // set buffers

 temp1_ptr = (U8*)MEMORY_SOURCE;
 temp2_ptr = (U8*)MEMORY_DESTINATION;
 for (i = 0; i < 200; ++i)
 {
temp1_ptr[i] = i;
temp2_ptr[i] = 0;
 }


 // set chain list

 chain_arr[0][0] = MEMORY_SOURCE;
 chain_arr[0][1] = MEMORY_DESTINATION;
 chain_arr[0][2] = (unsigned int)&chain_arr[1][0];
 chain_arr[0][3] = (TRANSFER_SIZE & 0x0FFF)//set the transfer size
			  | (1u << 12)			  //Source burst size
			  | (1u << 15)			  //destination burst size
			  | (0u << 18)			  //Source width
			  | (0u << 21)			  //destination width
			  | (1u << 26)			  //Source increment
			  | (1u << 27)			  //Destination increment
			  | (0u << 31);			 //interrupt

 chain_arr[1][0] = MEMORY_SOURCE + 32;
 chain_arr[1][1] = MEMORY_DESTINATION + 32;
 chain_arr[1][2] = (unsigned int)&chain_arr[2][0];
 chain_arr[1][3] = (TRANSFER_SIZE & 0x0FFF)//set the transfer size
			  | (1u << 12)			  //Source burst size
			  | (1u << 15)			  //destination burst size
			  | (0u << 18)			  //Source width
			  | (0u << 21)			  //destination width
			  | (1u << 26)			  //Source increment
			  | (1u << 27)			  //Destination increment
			  | (0u << 31);			 //interrupt

 chain_arr[2][0] = MEMORY_SOURCE + 64;
 chain_arr[2][1] = MEMORY_DESTINATION + 64;
 chain_arr[2][2] = 0;
 chain_arr[2][3] = (TRANSFER_SIZE & 0x0FFF)//set the transfer size
			  | (1u << 12)			  //Source burst size
			  | (1u << 15)			  //destination burst size
			  | (0u << 18)			  //Source width
			  | (0u << 21)			  //destination width
			  | (1u << 26)			  //Source increment
			  | (1u << 27)			  //Destination increment
			  | (1u << 31);			 //interrupt


 // enable GPDMA

 PCONP |= (0x1<<29);						   // Power up the GPDMA
 GPDMA_CONFIG = 0x01;						  // Enable the GPDMA

 while (!(GPDMA_CONFIG & 0x01));				// Wait until the GPDMA is operational

 // configure and start GPDMA
 GPDMA_INT_TCCLR	 = 0x01;				// Clear the interrupt status bits
 GPDMA_INT_ERR_CLR   = 0x01;
 GPDMA_CH0_SRC	   = chain_arr[0][0];		// Load source start address into Channel 0
 GPDMA_CH0_DEST	  = chain_arr[0][1];		// Load destination start address into Channel 0

 GPDMA_CH0_CTRL	  = chain_arr[0][3];		//set the transfer size and settings

 GPDMA_CH0_LLI	   = chain_arr[0][2];			// next item to transfer
 GPDMA_CH0_CFG	  |= 0x08001;			// Start the channel transfer


 while (!GPDMA_RAW_INT_TCSTAT);		  //Wait until the transfer has finished


 for(;;);

 return 0;
}

 

Список вроде правильный формируется :

post-52034-1251761899_thumb.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так мне и не удалось по-нормальному запустить DMA...

 

Пытался запустить пример к книге The insiders guide to the NXP LPC2300 2400 Based Microcontrollers.

Для запуска под keil пришлось:

- добавить объявление unsigned int *Buffer1,*Buffer2;

- заменить GPDMA_CH0_LLI = (unsigned int *) item1; на GPDMA_CH0_LLI = (unsigned int) item1;

 

В результате - все как и раньше - копируется только первый блок из 0x7FD00000 в 0x7FD00500, а уже из 0x7FD00000 в 0x7FD00600 копирования не происходит...

Ну и ес-но виснет на while ( !GPDMA_RAW_INT_CSTAT );

 

#include "lpc230x.h"
#define DMA_SRC			0x7FD00000
#define DMA_DST			0x7FD00500
#define DMA_SIZE		0x100

unsigned int i;
unsigned int *Buffer1,*Buffer2;
volatile unsigned int item1[4] = {0x7FD00000,0x7FD00600,0,0x8C4A4000};

int main (void)
{
  T0TCR 		= 0x00000002;			           //Reset counter and prescaler
  Buffer1 = (unsigned int *)DMA_SRC;    //Set the start address of the source buffer
 Buffer2 = (unsigned int *)DMA_DST;    //Set the start address of the destination buffer

 for ( i = 0; i < DMA_SIZE/4; i++ )    //Initilise the buffers
 {
	*Buffer1 = i;
	*Buffer2 = 0;
	Buffer1++;
	Buffer2++;
}

PCONP |= (0x1<<29);                      // Power up the GPDMA
GPDMA_CONFIG = 0x01;	                   // Enable the GPDMA
while ( !(GPDMA_CONFIG & 0x01) );        // Wait until the GPDMA is operational

   GPDMA_INT_CCLR = 0x01;                   //Clear the interrupt status bits
   GPDMA_INT_ERR_CLR = 0x01;
   GPDMA_CH0_SRC = DMA_SRC;                 //Load buffer1 start address into Channel 0
GPDMA_CH0_DEST = DMA_DST;                //Load buffer2 start address into Channel0
GPDMA_CH0_CTRL = ((DMA_SIZE/4) & 0x0FFF) //set the transfer size
               | (0x04 << 12)            // Source burst size 
               | (0x04 << 15)            //destination burst size  
		           | (0x02 << 18)            //Source width
		           | (0x02 << 21)            //destination width
		           | (1 << 26)               //Source increment
		           | (1 << 27)               //Destination increment
		           | (0<<31);                //Enable the terminal count interrupt	
GPDMA_CH0_LLI = (unsigned int) item1;

T0TCR 		   = 0x00000001;			         //enable timer
GPDMA_CH0_CFG |= 0x08001;                //Start the channel zero transfer

while ( !GPDMA_RAW_INT_CSTAT );          //Wait until the transfer has finished
T0TCR 		= 0x00000000;			             //disable timer
T0TCR 		= 0x00000002;			             //Reset counter and prescaler



while(1)
   {
       ;
   }

return (0);    
}

Пробовал массив размещать в "разрешенной" для DMA памяти - по адресу 0x7FD00700 - результат тот-же...

 

Что нужно сделать, что б заставить копировать несколько блоков? Может у кого-то есть работающий пример?

Изменено пользователем i.cf

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мда... Судя по обилию ответов, за более чем двухлетнее существование семейства, с List в DMA так никто и не работал... :unsure:

 

Выкладываю рабочий пример для будущих поколений.

example1.zip

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Был бы смысл в копировании память-память, мож кто бы и работал.

Немало дополнительной периферии подключают через контроллер внешней памяти. Причем объемы данных, которые приходится гонять подчас оказываются не малыми. Тут-то как раз и есть смысл использовать DMA для копирования память-память.

Изменено пользователем i.cf

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Также есть смысл при реализации буферизации дисплея, более чем одного порядка.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Столкнулся с проблемой, не получается запустить DMA на LPC2478 и LPC2378. Не хочет работать с SSP1, хотя с SSP0 работает нормально. Причем ошибки в инициализации SSP нет, так как при работе SSP1 с такой же конфигурацией но без DMA, все ok.

 

char dma_src[sSP_BUFSIZE] __attribute__((at(0x7FD00000)));
char dma_dst[sSP_BUFSIZE] __attribute__((at(0x7FD01000)));

static DWORD SSP1Init( void )
{
 BYTE i, Dummy = Dummy;

 /* enable clock to SSP1 for security reason. By default, it's enabled already */

 PCONP |= (1 << 10);
 PINSEL0 &= !( 0xFF << 12 );
 PINSEL0 |=  ( 0xAA << 12 );


 /* Set DSS data to 8-bit, Frame format SPI, CPOL = 0, CPHA = 0, and SCR is 15 */
 SSP1CR0 = 0x0707;

 /* SSPCPSR clock prescale register, master mode, minimum divisor is 0x02 */
#if LOOPBACK_MODE
 SSP1CPSR = 0x2;
#else
 /* Much slower clock is needed in order to test serial EEPROM. */
 SSP1CPSR = 0x40;
#endif

 for ( i = 0; i < FIFOSIZE; i++ )
 {
Dummy = SSP1DR;		/* clear the RxFIFO */
 }

 if ( install_irq( SSP1_INT, (void *)SSP1Handler, HIGHEST_PRIORITY ) == FALSE )
 {
return (FALSE);
 }

 /* Device select as master, SSP Enabled */
#if LOOPBACK_MODE
 SSP1CR1 = SSPCR1_LBM | SSPCR1_SSE;
#else
 SSP1CR1 = SSPCR1_SSE;
#endif
 /* Set SSPINMS registers to enable interrupts */
 /* enable all error related interrupts */
 SSP1IMSC = SSPIMSC_RORIM | SSPIMSC_RTIM;
 return( TRUE );
}

/*****************************************************************************
** Function name:		LoopbackTest
**
** Descriptions:		Loopback test
**				
** parameters:			None
** Returned value:		None
** 
*****************************************************************************/
void DMATest( void )
{
  DWORD i;
  volatile DWORD cnt;

  PCONP |= (1 << 29);	/* Enable GPDMA clock */
  /* Ch0 set for M2P transfer from mempry to SSP1. */
GPDMA_CH0_SRC = (unsigned long)dma_src;
GPDMA_CH0_DEST = SSP1DR;
/* The burst size is set to 8, the size is 8 bit too. */
/* Terminal Count Int enable */
GPDMA_CH0_CTRL =  (SSP_BUFSIZE & 0x0FFF) 
				| (0x02 << 12) 
				| (0x02 << 15)
				| (0x01 << 26) 
				| 0x80000000;

GPDMA_CH0_CFG =   (0x01 << 16) 		/* Lock bit */ 
				| (0x01 << 15)		/* Terminal count interrupt mask. */
				| (0x05 << 11)		/* Flow control and transfer type. M2P*/
				| (0x00 << 6 )		/* Destination peripheral. */
				| (0x02 << 1 ) 		/* SSP1 Tx. */
				| (0x01 << 0 ); 	/* Channel enabled. */


  /* Ch1 set for P2M transfer from SSP1 to memory. */
GPDMA_CH1_SRC = SSP1DR;
GPDMA_CH1_DEST = (unsigned long)dma_dst;
/* The burst size is set to 8, the size is 8 bit too. */
/* Terminal Count Int enable */
GPDMA_CH1_CTRL =  (SSP_BUFSIZE & 0x0FFF) 
				| (0x02 << 12) 
				| (0x02 << 15)
				| (0x01 << 27) 
				| 0x80000000;

GPDMA_CH1_CFG =   (0x01 << 16) 		/* Lock bit */ 
				| (0x01 << 15)		/* Terminal count interrupt mask. */
				| (0x06 << 11)		/* Flow control and transfer type. P2M*/
				| (0x00 << 6 )		/* Destination peripheral. */
				| (0x03 << 1 ) 		/* SSP1 Rx. */
				| (0x01 << 0 ); 	/* Channel enabled. */


GPDMA_CONFIG = 0x01;	/* Enable DMA channels, little endian */

while ( !(GPDMA_CONFIG & 0x01) );	

  if ( install_irq( GPDMA_INT, (void *)DMAHandler, HIGHEST_PRIORITY ) == FALSE ) {
	while (1)
		/* PANIC */;
  }

  /* Enable DMA TX and RX on SSP1 */
  SSP1DMACR = 0x03;
  cnt = 0x10000;
  while ( cnt-- )
  ;
  /* verifying, ignore the difference in the first two bytes */
  for ( i = 0; i < SSP_BUFSIZE; i++ ){
	if ( dma_dst[i] != dma_src[i] ){
		while (1)
			/* PANIC */; /* Verification failed */
	}
  }
  return; 
}

void SSP1Send( BYTE *buf, DWORD Length )
{
 DWORD i;
 BYTE Dummy = Dummy;

 for ( i = 0; i < Length; i++ )
 {
/* Move on only if NOT busy and TX FIFO not full. */
while ( (SSP1SR & (SSPSR_TNF|SSPSR_BSY)) != SSPSR_TNF );
SSP1DR = *buf;
buf++;
#if !LOOPBACK_MODE
while ( (SSP1SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE );
/* Whenever a byte is written, MISO FIFO counter increments, Clear FIFO 
on MISO. Otherwise, when SSP0Receive() is called, previous data byte
is left in the FIFO. */
Dummy = SSP1DR;
#else
/* Wait until the Busy bit is cleared. */
while ( SSP1SR & SSPSR_BSY );
#endif
 }
 return; 
}

/******************************************************************************
**   Main Function  main()
******************************************************************************/
int main (void)
{
  DWORD i;

  SSP1Init();	

  while (1) {
	for ( i = 0; i < SSP_BUFSIZE; i++ ) {
		dma_src[i] = 0xAA;
		dma_dst[i] = 0x00;
	  }
	  DMATest();
	//SSP1Send( ((BYTE *)DMA_SRC), SSP_BUFSIZE );
}

}

Изменено пользователем IgorKossak
codebox тег для оформления длинного кода

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мда... Судя по обилию ответов, за более чем двухлетнее существование семейства, с List в DMA так никто и не работал... :unsure:

 

Выкладываю рабочий пример для будущих поколений.

 

по поводу связанных списков. может уже и ненадо но все равно напишу. дма контроллер вистит наглухо при использовании списков и режима передач big - endian. т. е. если его переключить в другой режим все становится на свои места и начинает работать

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...