Esempio n. 1
0
/**
 * \brief Access AES module with DMA support
 *
 * \note Read STATE using DMA channel 0.
 * Check DMA driver example for more information about DMA usage.
 *
 */
static void aes_dma_output(void)
{
	// Make sure config is all zeroed out so we don't get any stray bits
	memset(&config, 0, sizeof(config));

	dma_enable();
	dma_channel_set_burst_length(&config, DMA_CH_BURSTLEN_1BYTE_gc);
	dma_channel_set_transfer_count(&config, BLOCK_LENGTH);
	dma_channel_set_src_reload_mode(&config, DMA_CH_SRCRELOAD_NONE_gc);
	dma_channel_set_dest_reload_mode(&config, DMA_CH_DESTRELOAD_NONE_gc);
	dma_channel_set_src_dir_mode(&config, DMA_CH_SRCDIR_FIXED_gc);
	dma_channel_set_dest_dir_mode(&config, DMA_CH_DESTDIR_INC_gc);
	dma_channel_set_source_address(&config, (uint16_t)(uintptr_t)&AES_STATE);
	dma_channel_set_destination_address(&config,
		(uint16_t)(uintptr_t)single_ans);
	dma_channel_write_config(DMA_CHANNEL_N, &config);

	// Use the configuration above by enabling the DMA channel in use.
	dma_channel_enable(DMA_CHANNEL_N);

	/*
	 * Trigger a manual start since there is no trigger sources used in
	 * this example.
	 */
	dma_channel_trigger_block_transfer(DMA_CHANNEL_N);
	while (!(DMA_CH0_CTRLB & DMA_CH_TRNIF_bm));
	DMA_CH0_CTRLB |= DMA_CH_TRNIF_bm;

	dma_disable();
}
Esempio n. 2
0
/**
 * \brief main function
 */
int main(void)
{
	struct dma_channel_config config;
	uint32_t                  checksum;

	pmic_init();
	board_init();
	sysclk_init();
	sleepmgr_init();

	// Randomly selected data
	source[0] = 0xAA;
	source[1] = 0xBB;
	source[2] = 0xCC;
	source[3] = 0xDD;
	source[4] = 0xEE;
	source[5] = 0xFF;

	// Calculate checksum for the data
	checksum = crc_io_checksum((void*)source, 6, CRC_16BIT);
	// Append the checksum to the data, big endian
	crc16_append_value(checksum, source+6);

	//Enable the CRC module for DMA
	crc_dma_checksum_start(DMA_CHANNEL, CRC_16BIT);

	// Enable DMA
	dma_enable();

	// Set callback function for DMA completion
	dma_set_callback(DMA_CHANNEL, example_crc_dma_transfer_done);

	// Make sure config is all zeroed out so we don't get any stray bits
	memset(&config, 0, sizeof(config));

	/**
	 * This example will configure a DMA channel with the following
	 * settings:
	 *  - Low interrupt priority
	 *  - 1 byte burst length
	 *  - DMA_BUFFER_SIZE bytes for each transfer
	 *  - Reload source and destination address at end of each transfer
	 *  - Increment source and destination address during transfer
	 *  - Source address is set to \ref source
	 *  - Destination address is set to \ref destination
	 */
	dma_channel_set_interrupt_level(&config, PMIC_LVL_LOW);
	dma_channel_set_burst_length(&config, DMA_CH_BURSTLEN_1BYTE_gc);
	dma_channel_set_transfer_count(&config, DMA_BUFFER_SIZE);
	dma_channel_set_src_reload_mode(&config,
			DMA_CH_SRCRELOAD_TRANSACTION_gc);
	dma_channel_set_dest_reload_mode(&config,
			DMA_CH_DESTRELOAD_TRANSACTION_gc);
	dma_channel_set_src_dir_mode(&config, DMA_CH_SRCDIR_INC_gc);
	dma_channel_set_dest_dir_mode(&config, DMA_CH_DESTDIR_INC_gc);
	dma_channel_set_source_address(&config, (uint16_t)(uintptr_t)source);
	dma_channel_set_destination_address(&config,
			(uint16_t)(uintptr_t)destination);
	dma_channel_write_config(DMA_CHANNEL, &config);

	// Use the configuration above by enabling the DMA channel in use.
	dma_channel_enable(DMA_CHANNEL);

	// Enable interrupts
	cpu_irq_enable();

	// Trigger the DMA transfer
	dma_channel_trigger_block_transfer(DMA_CHANNEL);

	// Light the first LED to indicate that the DMA has started.
	gpio_set_pin_low(LED0_GPIO);

	while (true) {
		/*
		 * Force a NOP instruction for an eventual placement of a debug
		 * session breakpoint.
		 */
		asm("nop\n");
	}
}
Esempio n. 3
0
/**
 *
 * \brief Test double buffering mode
 *
 * \note This function tests the double buffering feature of the DMA
 * controller by configuring channel 0 and 1 to do the same copy,
 * and verify that the channels enable each other according to
 * the double buffering process.
 *
 * \param test   Current test case
 */
static void run_dma_double_buffering_test(const struct test_case *test)
{
	struct dma_channel_config config_params;
	bool success = true; /* Assume everything goes well */

	/* Fill source block with pattern data */
	set_buffer(memory_block_src, 0x00);
	block_fill(memory_block_src, MEMORY_BLOCK_SIZE);

	/* Null out the destination block */
	set_buffer(memory_block_dest, 0x00);

	/* Null out the config params */
	memset(&config_params, 0, sizeof(config_params));

	/* Enable DMA */
	dma_enable();

	/* Enable double buffering mode on channel 0 and 1 */
	dma_set_double_buffer_mode(DMA_DBUFMODE_CH01_gc);

	/* Set channel 1 to copy from memory_block_src to memory_block_dest */
	dma_channel_set_src_reload_mode(&config_params,
			DMA_CH_SRCRELOAD_NONE_gc);
	dma_channel_set_src_dir_mode(&config_params,
			DMA_CH_SRCDIR_INC_gc);
	dma_channel_set_dest_reload_mode(&config_params,
			DMA_CH_DESTRELOAD_NONE_gc);
	dma_channel_set_dest_dir_mode(&config_params,
			DMA_CH_DESTDIR_INC_gc);
	dma_channel_set_burst_length(&config_params,
			DMA_CH_BURSTLEN_1BYTE_gc);
	dma_channel_set_transfer_count(&config_params,
			MEMORY_BLOCK_SIZE);
	dma_channel_set_source_address(&config_params,
			(uint16_t)(uintptr_t)memory_block_src);
	dma_channel_set_destination_address(&config_params,
			(uint16_t)(uintptr_t)memory_block_dest);
	dma_channel_set_repeats(&config_params,
			DOUBLE_BUFFER_REPEATS);

	/* Write config and enable */
	dma_channel_write_config(DMA_CHANNEL_0, &config_params);
	dma_channel_write_config(DMA_CHANNEL_1, &config_params);

	/* Enable only channel 0 */
	dma_channel_enable(DMA_CHANNEL_0);

	/* Transfer block and wait for it to finish */
	dma_channel_trigger_block_transfer(DMA_CHANNEL_0);

	while (dma_get_channel_status(DMA_CHANNEL_0) !=
			DMA_CH_TRANSFER_COMPLETED) {
		/* Intentionally left empty */
	}

	/*
	 * If double buffering is working, channel 1
	 * will be enabled now by the controller
	 */
	if (!(dma_channel_is_enabled(DMA_CHANNEL_1))) {
		success = false;
	}

	/*
	 * Disable channel 0, transfer channel 1,
	 * and verify that channel 0 is enabled again by the controller
	 */
	dma_channel_disable(DMA_CHANNEL_0);

	/* Transfer block and wait for it to finish */
	dma_channel_trigger_block_transfer(DMA_CHANNEL_1);

	while (dma_get_channel_status(DMA_CHANNEL_1) !=
			DMA_CH_TRANSFER_COMPLETED) {
		/* Intentionally left empty */
	}

	/* Verify that channel 0 is enabled again */
	if (!(dma_channel_is_enabled(DMA_CHANNEL_0))) {
		success = false;
	}

	test_assert_true(test, success,
			"Double buffering mode did not function properly");
}
Esempio n. 4
0
/**
 * \brief Test read from fixed location, trigger from timer and callback
 *
 * \note This test sets up a timer to trigger the DMA module,
 * which in turn reads the timer_overflow_counter variable and writes
 * it to memory sequentially. It then checks to see that the memory block
 * written is sequential according to the overflow count.
 *
 * \param test              Current test
 */
static void run_dma_triggered_with_callback(const struct test_case *test)
{
	struct dma_channel_config config_params;
	bool success;

	/* Null the buffer */
	set_buffer(dest_block_tc, 0x0000);

	/* Null out the config parameter struct */
	memset(&config_params, 0, sizeof(config_params));

	/*
	 * Enable the timer, and set it to count up.
	 * When it overflows, it triggers the DMA to
	 * read timer_overflow_counter. */
	tc_enable(&TIMER);

	tc_set_direction(&TIMER, TC_UP);
	tc_write_period(&TIMER, TIMER_PERIOD);

	tc_set_resolution(&TIMER, TIMER_RESOLUTION);

	tc_set_overflow_interrupt_level(&TIMER, PMIC_LVL_LOW);
	tc_set_overflow_interrupt_callback(&TIMER, timer_overflow_callback);

	/* Enable the DMA module */
	dma_enable();

	/* Set callback for transfer done */
	dma_set_callback(DMA_CHANNEL_0, dma_transfer_is_complete);

	/* Set low interrupt level */
	dma_channel_set_interrupt_level(&config_params, PMIC_LVL_LOW);

	/* Set up the DMA to read the timer value
	 *
	 * - Single shot transfer mode
	 * - Two byte (16-bit) burst length
	 * - Increment on source and destination
	 * - Reload on burst for source
	 * - No reload for destination
	 */
	dma_channel_set_single_shot(&config_params);
	dma_channel_set_burst_length(&config_params,
			DMA_CH_BURSTLEN_1BYTE_gc);
	dma_channel_set_src_reload_mode(&config_params,
			DMA_CH_SRCRELOAD_BURST_gc);
	dma_channel_set_src_dir_mode(&config_params,
			DMA_CH_SRCDIR_FIXED_gc);
	dma_channel_set_dest_reload_mode(&config_params,
			DMA_CH_DESTRELOAD_NONE_gc);
	dma_channel_set_dest_dir_mode(&config_params,
			DMA_CH_DESTDIR_INC_gc);

	/* Set trigger source to TCC0's overflow */
	dma_channel_set_trigger_source(&config_params,
			DMA_CH_TRIGSRC_TCC0_OVF_gc);

	/* Transfer DEST_BLOCK_TC_SIZE bytes */
	dma_channel_set_transfer_count(&config_params,
			DEST_BLOCK_TC_SIZE);

	/* Set address */
	dma_channel_set_source_address(&config_params,
			(uint16_t)(uintptr_t)&timer_overflow_counter);
	dma_channel_set_destination_address(&config_params,
			(uint16_t)(uintptr_t)dest_block_tc);

	/* Reset the channel */
	dma_channel_reset(DMA_CHANNEL_0);

	/* Write the config */
	dma_channel_write_config(DMA_CHANNEL_0, &config_params);

	/* Enable the channel */
	dma_channel_enable(DMA_CHANNEL_0);

	/* Wait for transfer to finish */
	while (!dma_has_completed) {
		/* Intentionally left empty */
	}

	/* Disable DMA */
	dma_disable();

	/* Verify that the result is as expected */
	success = block_compare(dest_block_tc,
			expected_result_tc, DEST_BLOCK_TC_SIZE);

	test_assert_true(test, success, "Result is not as expected");
}
Esempio n. 5
0
/**
 *
 * \brief Set DMA configuration, and read it back
 *
 * \note This function writes a configuration to the DMA
 * controller, and reads it back to verify settings have
 * been correctly set.
 *
 * \param test   Current test case
 */
static void run_dma_config_interface_test(const struct test_case *test)
{
	struct dma_channel_config config_params;
	struct dma_channel_config read_config;

	const uint16_t transfer_count = 1024;
	const uint8_t repeats         = 64;
	uint8_t channel_index;

#ifdef CONFIG_HAVE_HUGEMEM
	hugemem_ptr_t dest_huge_addr  = HUGEMEM_NULL;
	hugemem_ptr_t src_huge_addr   = HUGEMEM_NULL;

	hugemem_write32(dest_huge_addr, 0xABCD1234);
	hugemem_write32(src_huge_addr, 0xAAAABBBB);
#else
	const uint16_t dest_addr      = 0xBEEF;
	const uint16_t src_addr       = 0xABCD;
#endif

	memset(&config_params, 0, sizeof(config_params));

	dma_enable();

	/* Apply some parameters */
	dma_channel_set_burst_length(&config_params,
			DMA_CH_BURSTLEN_4BYTE_gc);
	dma_channel_set_single_shot(&config_params);
	dma_channel_set_interrupt_level(&config_params,
			PMIC_LVL_HIGH);
	dma_channel_set_src_reload_mode(&config_params,
			DMA_CH_SRCRELOAD_BLOCK_gc);
	dma_channel_set_dest_reload_mode(&config_params,
			DMA_CH_DESTRELOAD_BURST_gc);
	dma_channel_set_src_dir_mode(&config_params,
			DMA_CH_SRCDIR_DEC_gc);
	dma_channel_set_dest_dir_mode(&config_params,
			DMA_CH_DESTDIR_DEC_gc);
	dma_channel_set_trigger_source(&config_params,
			DMA_CH_TRIGSRC_TCC0_CCA_gc);
	dma_channel_set_transfer_count(&config_params,
			transfer_count);
	dma_channel_set_repeats(&config_params,
			repeats);

#ifdef CONFIG_HAVE_HUGEMEM
	dma_channel_set_destination_hugemem(&config_params, dest_huge_addr);
	dma_channel_set_source_hugemem(&config_params, src_huge_addr);
#else
	dma_channel_set_destination_address(&config_params, dest_addr);
	dma_channel_set_source_address(&config_params, src_addr);
#endif

	/* Loop through all channels, read back config from them, and verify */
	for (channel_index = 0; channel_index < DMA_NUMBER_OF_CHANNELS; channel_index++) {
		dma_channel_write_config(channel_index, &config_params);

		/* Null out the read_config struct */
		memset(&read_config, 0, sizeof(read_config));

		/* Read the config back from the module */
		dma_channel_read_config(channel_index, &read_config);

		test_assert_true(test,
				read_config.addrctrl == config_params.addrctrl,
				"CH %d: Address control register does not match configuration",
				channel_index);

		test_assert_true(test, read_config.ctrla == config_params.ctrla,
				"CH %d: Control register A does not match configuration",
				channel_index);

		test_assert_true(test,
				read_config.repcnt == config_params.repcnt,
				"CH %d: Repeat counter register does not match configuration",
				channel_index);

		test_assert_true(test,
				read_config.trfcnt == config_params.trfcnt,
				"CH %d: Transfer counter register does not"
				" match configuration", channel_index);

		test_assert_true(test,
				read_config.trigsrc == config_params.trigsrc,
				"CH %d: Trigger source register does not match configuration",
				channel_index);

#ifdef CONFIG_HAVE_HUGEMEM
		test_assert_true(test,
				read_config.destaddr == config_params.destaddr,
				"CH %d: Destination address register does not"
				" match configuration", channel_index);

		test_assert_true(test,
				read_config.srcaddr == config_params.srcaddr,
				"CH %d: Source address register does not match configuration",
				channel_index);
#else
		test_assert_true(test,
				read_config.destaddr16 == config_params.destaddr16,
				"CH %d: DESTADDR16 does not match configuration",
				channel_index);

		test_assert_true(test,
				read_config.srcaddr16 == config_params.srcaddr16,
				"CH %d: SRCADDR16 does not match configuration");
#endif
	}

	/* Reset the channel */
	dma_channel_reset(DMA_CHANNEL_0);

	/* Check set and unset single shot */
	memset(&config_params, 0, sizeof(config_params));
	memset(&read_config, 0, sizeof(read_config));

	dma_channel_set_single_shot(&config_params);

	dma_channel_write_config(DMA_CHANNEL_0, &config_params);
	dma_channel_read_config(DMA_CHANNEL_0, &read_config);

	test_assert_true(test, read_config.ctrla == config_params.ctrla,
			"Single shot mode not set correctly");

	memset(&config_params, 0, sizeof(config_params));
	dma_channel_unset_single_shot(&config_params);

	dma_channel_write_config(DMA_CHANNEL_0, &config_params);
	dma_channel_read_config(DMA_CHANNEL_0, &read_config);

	test_assert_true(test, read_config.ctrla == config_params.ctrla,
			"Single shot mode not unset correctly");

	/* Reset it again, and test the direct configuration functions */
	memset(&read_config, 0, sizeof(read_config));

	dma_channel_write_burst_length(DMA_CHANNEL_0, DMA_CH_BURSTLEN_4BYTE_gc);
	dma_channel_write_transfer_count(DMA_CHANNEL_0, transfer_count);
	dma_channel_write_repeats(DMA_CHANNEL_0, repeats);

#ifdef CONFIG_HAVE_HUGEMEM
	dma_channel_write_source_hugemem(DMA_CHANNEL_0, src_huge_addr);
	dma_channel_write_destination_hugemem(DMA_CHANNEL_0, dest_huge_addr);
#else
	dma_channel_write_source(DMA_CHANNEL_0, src_addr);
	dma_channel_write_destination(DMA_CHANNEL_0, dest_addr);
#endif

	/* Verify that settings have been set correctly */
	dma_channel_read_config(DMA_CHANNEL_0, &read_config);

	test_assert_true(test,
			(read_config.ctrla & DMA_CH_BURSTLEN_gm)
			== DMA_CH_BURSTLEN_4BYTE_gc,
			"Read burst length does not match configuration");

	test_assert_true(test, read_config.trfcnt == transfer_count,
			"Read transfer count does not match configuration");

	test_assert_true(test, read_config.repcnt == repeats,
			"Read repeat value does not match configuration");

#ifdef CONFIG_HAVE_HUGEMEM
	test_assert_true(test, read_config.srcaddr == src_huge_addr,
			"Read source address does not match configuration");

	test_assert_true(test, read_config.destaddr == dest_huge_addr,
			"Read destination address does not match configuration");
#else
	test_assert_true(test, read_config.srcaddr16 == src_addr,
			"Read source address does not match configuration");

	test_assert_true(test, read_config.destaddr16 == dest_addr,
			"Read destination address does not match configuration");
#endif

	dma_disable();
}
Esempio n. 6
0
/**
 * \brief Test different directions on all channels
 *
 * \note This test copies the source memory block into the destination block
 * in different ways.
 *
 * \param test              Current test
 */
static void run_dma_direction_test(const struct test_case *test)
{
	struct dma_channel_config config_params;
	uint8_t channel_index;
	bool success = true; /* Assume everything goes well */

	/* Fill the source block with our known pattern */
	set_buffer(memory_block_src, 0x00);
	block_fill(memory_block_src, MEMORY_BLOCK_SIZE);

	/* Null out the config params */
	memset(&config_params, 0, sizeof(config_params));

	/* Enable DMA */
	dma_enable();

	/* No reload on source and destination */
	dma_channel_set_src_reload_mode(&config_params,
			DMA_CH_SRCRELOAD_NONE_gc);
	dma_channel_set_dest_reload_mode(&config_params,
			DMA_CH_DESTRELOAD_NONE_gc);
	dma_channel_set_transfer_count(&config_params,
			MEMORY_BLOCK_SIZE);
	dma_channel_set_burst_length(&config_params,
			DMA_CH_BURSTLEN_1BYTE_gc);

	/* Test a memory transfer on all channels */
	for (channel_index = 0; channel_index < DMA_NUMBER_OF_CHANNELS;
			channel_index++) {
		/* Reset channel and write the configuration */
		dma_channel_reset(channel_index);
		/* Increment source, increment destination */
		dma_channel_set_src_dir_mode(&config_params,
				DMA_CH_SRCDIR_INC_gc);
		dma_channel_set_dest_dir_mode(&config_params,
				DMA_CH_DESTDIR_INC_gc);
		/* Data starts from the first byte */
		dma_channel_set_source_address(&config_params,
				(uint16_t)(uintptr_t)memory_block_src);
		dma_channel_set_destination_address(&config_params,
				(uint16_t)(uintptr_t)memory_block_dest);

		/* Write the config */
		dma_channel_write_config(channel_index, &config_params);

		/* Clear destination */
		set_buffer(memory_block_dest, 0x00);

		/* Enable channel, transfer, and disable it */
		dma_channel_enable(channel_index);
		dma_transfer_block(channel_index);
		dma_channel_disable(channel_index);

		/* Check that source and destination are equal */
		success = block_compare(memory_block_src,
				memory_block_dest, MEMORY_BLOCK_SIZE);

		if (!success) {
			break;
		}

		/* Reset channel and write the configuration */
		dma_channel_reset(channel_index);
		/* Decrement source, increment destination */
		dma_channel_set_src_dir_mode(&config_params,
				DMA_CH_SRCDIR_DEC_gc);
		dma_channel_set_dest_dir_mode(&config_params,
				DMA_CH_DESTDIR_INC_gc);
		/* Data starts from the first byte */
		dma_channel_set_source_address(&config_params,
				(uint16_t)(uintptr_t)
				(memory_block_src + MEMORY_BLOCK_SIZE - 1));
		dma_channel_set_destination_address(&config_params,
				(uint16_t)(uintptr_t)memory_block_dest);

		/* Write the config */
		dma_channel_write_config(channel_index, &config_params);

		/* Clear destination */
		set_buffer(memory_block_dest, 0x00);

		/* Enable channel, transfer, and disable it */
		dma_channel_enable(channel_index);
		dma_transfer_block(channel_index);
		dma_channel_disable(channel_index);

		/* Check that destination is the reverse of source */
		success = block_compare_reverse(memory_block_src,
				memory_block_dest, MEMORY_BLOCK_SIZE);

		if (!success) {
			break;
		}

		/* Reset channel and write the configuration */
		dma_channel_reset(channel_index);
		/* Decrement source, increment destination */
		dma_channel_set_src_dir_mode(&config_params,
				DMA_CH_SRCDIR_INC_gc);
		dma_channel_set_dest_dir_mode(&config_params,
				DMA_CH_DESTDIR_DEC_gc);
		/* Data starts from the first byte */
		dma_channel_set_source_address(&config_params,
				(uint16_t)(uintptr_t)memory_block_src);
		dma_channel_set_destination_address(&config_params,
				(uint16_t)(uintptr_t)
				(memory_block_dest + MEMORY_BLOCK_SIZE - 1));

		/* Write the config */
		dma_channel_write_config(channel_index, &config_params);

		/* Clear destination */
		set_buffer(memory_block_dest, 0x00);

		/* Enable channel, transfer, and disable it */
		dma_channel_enable(channel_index);
		dma_transfer_block(channel_index);
		dma_channel_disable(channel_index);

		/* Check that destination is the reverse of source */
		success = block_compare_reverse(memory_block_src,
				memory_block_dest, MEMORY_BLOCK_SIZE);

		if (!success) {
			break;
		}

		/* Reset channel and write the configuration */
		dma_channel_reset(channel_index);
		/* Decrement source, Decrement destination */
		dma_channel_set_src_dir_mode(&config_params,
				DMA_CH_SRCDIR_DEC_gc);
		dma_channel_set_dest_dir_mode(&config_params,
				DMA_CH_DESTDIR_DEC_gc);
		/* Data starts from the first byte */
		dma_channel_set_source_address(&config_params,
				(uint16_t)(uintptr_t)
				(memory_block_src + MEMORY_BLOCK_SIZE - 1));
		dma_channel_set_destination_address(&config_params,
				(uint16_t)(uintptr_t)
				(memory_block_dest + MEMORY_BLOCK_SIZE - 1));

		/* Write the config */
		dma_channel_write_config(channel_index, &config_params);

		/* Clear destination */
		set_buffer(memory_block_dest, 0x00);

		/* Enable channel, transfer, and disable it */
		dma_channel_enable(channel_index);
		dma_transfer_block(channel_index);
		dma_channel_disable(channel_index);

		/* Check that source and destination are equal */
		success = block_compare(memory_block_src,
				memory_block_dest, MEMORY_BLOCK_SIZE);

		if (!success) {
			break;
		}
	}

	/* Disable DMA */
	dma_disable();

	test_assert_true(test, success,
			"DMA direction copy test failed on channel %d",
			channel_index);
}