/** * \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"); } }
/** * \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"); }