Using DMA Descriptors to receive Data bigger than 1024 bytes (LPC55S69)

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

Using DMA Descriptors to receive Data bigger than 1024 bytes (LPC55S69)

29件の閲覧回数
Kanstrit
Contributor I

 

Hello Community, 

I was having difficulties to find a way to receive big amounts of data (over 2000 bytes) via DMA to my LPC55S69 board, considering that DMA has a maximum transfer size of 1024 bytes.

I had a look at example "usart_dma_double_buffer_transfer" however some functions were outdated, considering for example:

DMA_PrepareTransfer() became DMA_PrepareChannelTransfer(), DMA_SubmitTransfer() became DMA_SubmitChannelTransfer() and DMA_CreateDescriptor() became DMA_SetupDescriptor(). So i was a bit lost filling the new input parameters of these new functions that did not appear in the example, mostly the parameter "xfercfg" Transfer configuration for DMA descriptor present in new DMA_SetupDescriptor().

 

I also had a look at example "dma_channel_chain" which also helped me to get another view on some of the new functions, however it was not exactly what i was looking for. 

 

In addition i took a look at the article DMA Ping-Pong application - NXP Community however it was not exactly compatible to the LPC board i was using.

 

After putting altogether the information from what i could acquire online and smashing my head a bit against the keyboard i finally made it to arrive to the point i wanted, receiving big amounts of data via DMA. (Saving data in 3 different buffers, each with 1024 bytes of size)

 

So i'm using this opportunity to share the code in the hope of being helpful or giving some guidance to maybe someone that finds itself in the same road i was before. Also trying to give back a bit from all the things i have learned from this beautiful community.

 

(Hope that is fine that this is posted here, considering is not exactly a question, but is also a topic open for discussions).

Best of luck!

 

#include "fsl_usart_dma.h"
#include "fsl_dma.h"

#define NUMBER_DESCRIPTORS	3
#define DESCRIPTOR_TRANSFER_SIZE 1024
#define RX_BUFFER_SIZE 1024

uint8_t g_data_buffer[RX_BUFFER_SIZE];

uint8_t g_data_1[RX_BUFFER_SIZE];
uint8_t g_data_2[RX_BUFFER_SIZE];
uint8_t g_data_3[RX_BUFFER_SIZE];


/* Custom Descriptors (Must be 16-byte aligned) */
SDK_ALIGN(dma_descriptor_t g_Desc[NUMBER_DESCRIPTORS], 16);
/* equal to writing:
__attribute__((aligned(FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE))) dma_descriptor_t g_Desc[NUMBER_DESCRIPTORS] = {0};
or
DMA_ALLOCATE_LINK_DESCRIPTORS_AT_NONCACHEABLE(g_Desc, NUMBER_DESCRIPTORS);
*/


/*             Function definitions
****************************************************************************/


//Initialising Rx DMA to receive data bigger than 1024 bytes.
void init_USART_DMA(void){

	//Channel configuration for DMA descriptor

	dma_channel_config_t channelConfig;

	/* 1. System/Peripheral Level Init */
	// Done in peripheral.c, initialized the functions USART_Init(), DMA_EnableChannel(), DMA_CreateHandle(), USART_TransferCreateHandleDMA().


	/*I have not used the function DMA_SubmitChannelDescriptor(), by giving as input the g_ChannelTable, as it would not allow to receive data.
	the g_ChannelTable variable should be initalized as follow:
	 //Allocates the mandatory, 512-byte aligned master table in RAM used by the hardware to manage all DMA channels
	SDK_ALIGN(dma_descriptor_t g_ChannelTable[FSL_FEATURE_DMA_MAX_CHANNELS], 512);
	then call the function here in the code

	DMA_SubmitChannelDescriptor(FLEXCOMM5_USB_PC_RX_Handle,g_ChannelTable);
	*/

	/* 2. Enable USART RX DMA requests */
	 USART_EnableRxDMA(FLEXCOMM5_USB_PC_PERIPHERAL, true);

	 /* 3. Prepare the Descriptor Configuration Variable Flags */
	 //Intermediate Descriptors, where it jumps from one to another
	 /* Common XFER configuration options for intermediate descriptors (1, 2,...) */
	 /* reload = true (keeps the chain moving to the next descriptor) */
	 /* intA = false (we only want the final interrupt when everything is done) */

	 uint32_t intermediatexfercfg = DMA_CHANNEL_XFER(
	         true,                          	/* reload: true to move to the next descriptor */
	         false,                           	/* clrTrig: false */
	         false,                           	/* intA: false */
	         false,                          	/* intB: false */
	         sizeof(uint8_t),                	/* width: 1 byte for USART char processing */
	         kDMA_AddressInterleave0xWidth,  	/* srcInc: 0x (read from fixed USART FIFO address) */
	         kDMA_AddressInterleave1xWidth,  	/* dstInc: 1x (increment buffer pointer by 1 byte) */
			 DESCRIPTOR_TRANSFER_SIZE          	/* totalBytes: DESCRIPTOR_TRANSFER_SIZE */
	     );

	 //Final Descriptor, where it stops jumping to another descriptor
	 /* Final XFER configuration options for the last descriptor */
	 /* reload = false (this is the end of the chain)  */
	 /* clrTrig = true (stop the DMA hardware channel) */
	 /* intA = true (fire the completion interrupt)    */
	 uint32_t finalxfercfg = DMA_CHANNEL_XFER(
			 false,                          /* reload: false because this is the terminal descriptor */
			 true,                           /* clrTrig: true to clear peripheral hardware requests */
			 true,                           /* intA: true to fire our completion interrupt */
			 false,                          /* intB: false */
			 sizeof(uint8_t),                /* width: 1 byte for USART char processing */
			 kDMA_AddressInterleave0xWidth,  /* srcInc: 0x (read from fixed USART FIFO address) */
			 kDMA_AddressInterleave1xWidth,  /* dstInc: 1x (increment buffer pointer by 1 byte) */
			 DESCRIPTOR_TRANSFER_SIZE        /* totalBytes: DESCRIPTOR_TRANSFER_SIZE */
		 );

	 /* 4. Configure the Custom Descriptors structure */
	 //Descriptor #0
	 DMA_SetupDescriptor(
		 &g_Desc[0],
		 intermediatexfercfg,
		 (void *)&FLEXCOMM5_USB_PC_PERIPHERAL->FIFORD,    	/* Source address: USART FIFO Read Register */
	 &g_data_1[0],            			 					/* Destination address: RAM buffer */
		 &g_Desc[1]                     					/* Point to next descriptor */
	 );

	 //Descriptor #1
	 DMA_SetupDescriptor(
		 &g_Desc[1],
		 intermediatexfercfg,
		 (void *)&FLEXCOMM5_USB_PC_PERIPHERAL->FIFORD,    	/* Source address: USART FIFO Read Register */
		 &g_data_2[0],            			 				/* Destination address: RAM buffer */
		 &g_Desc[2]                     					/* Point to next descriptor */
	 );

	 //Descriptor #2 (final)
	 DMA_SetupDescriptor(
		 &g_Desc[2],
		 finalxfercfg,
		 (void *)&FLEXCOMM5_USB_PC_PERIPHERAL->FIFORD,    	/* Source address: USART FIFO Read Register */
		 &g_data_3[0],            			 				/* Destination address: RAM buffer */
		 NULL                      							/* Final descriptor, does not move to another*/
	 );

	  /* 5. Set up Head Transfer to execute first descriptor first */
	  /* Point the initial hardware channel block straight to the first buffer to save data */
	 DMA_PrepareChannelTransfer(
		 &channelConfig,                						/* 1. Pointer to configuration structure */
			(void *)&FLEXCOMM5_USB_PC_PERIPHERAL->FIFORD,    	/* 2. Source start address */
			(void *)&g_data_1[0],             				    /* 3. Destination start address */
			DMA_CHANNEL_XFER(               					/* 4. Initial transfer settings bitmask */
				true,                       					/*    reload: true to step into linked descriptor */
				false,
				false,
				false,
				sizeof(uint8_t),
				kDMA_AddressInterleave0xWidth,
				kDMA_AddressInterleave1xWidth,
				DESCRIPTOR_TRANSFER_SIZE
			),
			kDMA_PeripheralToMemory,        /* 5. Transfer type enum path */
			NULL,                           /* 6. Hardware Trigger parameters (NULL uses default peripheral request) */
			&g_Desc[1]            			 /* 7. Address of next descriptor. (including already 2nd descriptor,
												as this will already transfer all the data to begining of rxBuffer like first descriptor would have done*/
		);

	 DMA_SubmitChannelTransfer(&FLEXCOMM5_USB_PC_RX_Handle,&channelConfig);

	 DMA_StartTransfer(&FLEXCOMM5_USB_PC_RX_Handle);

}

 

ラベル(2)
タグ(2)
0 件の賞賛
返信
0 返答(返信)