Skip to content
Addio edited this page Nov 2, 2021 · 7 revisions

This is a WIP

It is recommended to only use DMA for large transfers, as setting up each transfer takes a lot of CPU instructions.

Usage

Initialization

Initializing GeNETiCC for use with DMA is very simple(as long as your system is already supported, info on how to integrate your system here.).

First enable DMA by setting GENETICC_USE_DMA in "geneticc_config.h" to true. DMA functions will now be available to use.

Then in your setup routine, simply call geneticc_dma_init(). Without calling geneticc_dma_init, DMA functions will use standard memcpy/memove functions.

To disable the use of DMA at runtime, you can call geneticc_dma_disable(), and to reenable call geneticc_dma_enable().

User Callbacks

Callbacks can be used to find out when a transfer has finished, or if the DMA module had an error. Error is not currently implemented

Here is an example of how to register the callback, and track when a transfer has completed

#include "geneticc/geneticc_master.h"

//Transfer done user callback.
void geneticc_dma_transfer_done(const geneticc_dma_transfer_t* transfer)
{
	#if GENETICC_DMA_AUTOFREE_TRANSFER == false
	//geneticc_dma_delete_transfer must be called if you have registered the callback or you will have a memory leak.
	//If the callback is not registered, it will be freed internally(unless the "no_delete" flag is set).
	if(transfer->flags.no_delete)
	geneticc_dma_delete_transfer(transfer);	
	#endif
}

//Sub-transfer done user callback.
void geneticc_dma_subtransfer_done(const geneticc_dma_subtransfer_t* subtransfer)
{
	//Do stuff
}

int main(void)
{
	/*Setup routine*/

	//Initialize DMA
	geneticc_dma_init();
	geneticc_dma_register_user_callbacks(DMA_CB_TRANSFER_DONE, geneticc_dma_transfer_done);
	geneticc_dma_register_user_callbacks(DMA_CB_SUBTRANSFER_DONE, geneticc_dma_subtransfer_done);

	//DMA is now initialized.

	int length = 400; //Needs to be long enough to not finish before waiting statement.
	int array[length];

	//Populate the array with something
	for(int i = 0; i < length ; i++)
	{
		array[i] = i;
	}

	//Create a list which will we use to execute a DMA function with.
	LIST_PTR list = new_List(sizeof(int));


	List_DMA_AddRange(list, array);


	/*Do other stuff while transfer is running*/

	//Wait for DMA transfer to finish.
        //Used the destination to find the transfer
	geneticc_dma_wait_for_transfer(list);

	while(1)
	{
		/*Main Loop*/
	}

}

As of now, most DMA macros are located in "geneticc_list.h," more info here.


Transfer System

It is not recommended to use the Transfer System outside of GeNETiCC's internal functions.

The transfer system is how the library schedules internal calls to the DMA engine.

Every time you make a call to a DMA Macro/Function, it will create 1 transfer, and at least 1 subtransfer.

The transfer is then registered, which lets the transfer system know its waiting to start. If there are other transfers running, it will start when they have finished, and if there are no transfers running, it will be sent to the DMA engine, 1 sub-transfer at a time and in order.

When the sub-transfer has completed, the transfer will check to see if it has any more sub-transfers that are waiting. If there is, it will send the next one. When all sub-transfers have completed, if the user has registered the transfer_done user callback, it will pass the transfer to the callback, and then free/delete the transfer depending on the DMA configuration.

Currently only 1 DMA channel is supported, but multiple channels will be added in the future, to save time from having to configure the DMA engine every transfer.

Transfer (geneticc_dma_transfer_t)

Sub-Transfer (geneticc_dma_subtransfer_t)

Beatsize

The beatsize is simply how many bytes are transferred every DMA cycle.

Transactions

Transactions are how many times the DMA engine has to access memory to complete the transfer.

Even when calling a DMA Macro or Function, it is not guaranteed to use the DMA engine. The DMA engine will only be used if the minimum transaction count is met.

If the transaction count is not met, it will use standard memcpy/memmove function, but you will still have a performance hit over the non DMA macros, as the transfers are still created and registered, which takes time.

The minimum transaction count can be changed by editing GENETICC_DMA_MIN_TRANSACTION_COUNT in "geneticc/dma/geneticc_dma_config.h."

The transaction count is calculated by taking the transaction size (in bytes), and dividing by the beatsize.

Below GENETICC_DMA_MIN_TRANSACTION_COUNT you may have noticed GENETICC_DMA_SYNC_MIN_TRANSACTION_COUNT. You can force all non DMA Macros/Functions to use DMA synchronously. In most cases DMA is slower than CPU transfers, so synchronous operation is not recommended, but is still available for the rare cases DMA is faster. To force synchronous DMA, set GENETICC_FORCE_SYNCHRONOUS_DMA which is located in "geneticc/geneticc_memory.h" to true.

Configuring your project

Atmel Studio

Coming Soon

Configuring a new System

Coming Soon

Types

geneticc_dma_beatsize_t

Used to reconfigure the DMA hardware.

The maximum beatsize must be set in geneticc_dma.h using GENETICC_DMA_MAX_BEATSIZE for every system

enum geneticc_dma_beatsize
{
	BEATSIZE_MAX = 0,	//The maximum beatsize for the system.
	BEATSIZE_BYTE = 1,
	BEATSIZE_WORD = 2,
	BEATSIZE_DWORD = 4,
	BEATSIZE_QWORD = 8
};
typedef uint8_t geneticc_dma_beatsize_t;

geneticc_dma_control_reg

Flags used to control GeNETiCC's DMA system, and keep track of the state.

typedef struct
{
	bool initialized			: 1;	//Initialization routine has been run.
	bool enabled				: 1;	//DMA use is enabled.
	bool transferring			: 1;	//A transfer is currently active.
	bool sync_trans				: 1;	//The current running transfer is synchronous.
	bool sync_waiting			: 1;	//A synchronous transfer is waiting to start.
	//unsigned int async_waiting		: 1;	//An async transfer is in the list.
	unsigned int 				: 2;	/*Reserved*/
	//geneticc_dma_beatsize_t beatsize	: 2;
}geneticc_dma_control_reg;

geneticc_dma_transfer_t

Used to keep a record of the source and destination address, as well as hold, and keep track of sub-transfers.

typedef struct
{
	list_t	subtransfers;				//list of geneticc_dma_subtransfer_t
	ARRAY_PTR src;					//Pointer to the source array
	ARRAY_PTR dest;					//Pointer to the destination array			
	size_t size;					//The total size of the src array, NOT how many bytes are being transferred
	unsigned int subtran_count		: 8;	//Sub-transfer count
	unsigned int complete_count		: 8;	//How many sub-transfers have finished?
	geneticc_dma_transfer_flags_t flags;
}geneticc_dma_transfer_t;

geneticc_dma_transfer_flags_t

typedef struct
{
	bool start			: 1;	//Is the transfer waiting to start.
	bool ready			: 1;	//Is the transfer initialized?
	bool running			: 1;	//Have we started to send sub-transfers to the DMA engine?
	bool complete			: 1;	//Have all the sub-transfers finished?
	bool freesrc			: 1;	//Should the source be freed upon completion?
	bool no_delete			: 1;	//Should the transfer not be deleted upon completion, or if failed to start?
	unsigned int : 3;
}geneticc_dma_transfer_flags_t;	

geneticc_dma_subtransfer_t

Holds data which is used to configure the DMA engine.

typedef struct
{
	geneticc_dma_transfer_t* parent;	//Parent transfer
	ARRAY_PTR src;				//Source address
	ARRAY_PTR dest;				//Destination address
	size_t size;				//Transfer size
	geneticc_dma_subtransfer_flags_t flags;	//Status/Control Flags
}geneticc_dma_subtransfer_t;

geneticc_dma_subtransfer_flags_t

Contains flags used to configure the DMA engine, as well as keep track of the sub-transfer status.

typedef struct  
{
	//uint8_t channel;						//Currently only 1 channel supported.
	//int8_t index;							//Use to make sure transfers run in order. *Currently subtransfers run in order. When multiple channels are supported, this will come into play.
	bool running					: 1;		//Has the sub-transfer been sent to the DMA engine?
	bool complete					: 1;		//Has the sub-transfer finished?
	bool overlap					: 1;		//This src and dest overlap. (This will send without DMA, used for when transfers must be sent in order.)
	bool freesrc					: 1;		//Should the source be freed upon completion? (Warning! Make sure other transfers do not share the source)
	bool no_incsrc					: 1;		//When true, DMA will not increment the source address.
	bool no_incdest					: 1;		//When true, DMA will not increment the destination address.
	unsigned int					: 2;
_t beatsize;
}geneticc_dma_subtransfer_flags_t;

geneticc_dma_cb_type

Used to register user callbacks.

enum geneticc_dma_cb_type
{
	#warning reminder to implement error callback.
	DMA_CB_TRANSFER_DONE,
	DMA_CB_SUBTRANSFER_DONE,
	DMA_CB_ERROR		//Not implemented yet
	//DMA_CB_CHANNEL_SUSPEND	//Unsupported
};