/** * \brief Trigger and wait for a successful transfer * * \param channel_num Channel number */ static void ut_edma_transfer_block(edma_channel_num_t channel_num) { /* Trigger a EDMA copy */ edma_channel_trigger_block_transfer(channel_num); /* Wait for it to finish */ while (edma_get_channel_status(channel_num) != EDMA_CH_TRANSFER_COMPLETED) { /* Intentionally left empty */ } }
/** * \internal * \brief Common EDMA channel interrupt handler * * Calls the channel callback with the channel status code. The following * status codes are possible: * - EDMA_CH_TRANSFER_COMPLETED: Transfer completed successfully * - EDMA_CH_TRANSFER_ERROR: Fault in transfer * * The optional callback used by the interrupt handler is set by the * edma_set_callback() function. * * \param num EDMA channel number to handle interrupt for */ static void edma_interrupt(const edma_channel_num_t num) { edma_channel_status_t status; EDMA_CH_t *channel; channel = edma_get_channel_address_from_num(num); status = edma_get_channel_status(num); /* Clear all interrupt flags to be sure */ channel->CTRLB |= EDMA_CH_TRNIF_bm | EDMA_CH_ERRIF_bm; if (edma_data[num].callback) { edma_data[num].callback(status); } }
/** * \brief Test the error handling of the module * * \note Test error handling by disabling a channel which is in use * * \param test Current test */ static void run_edma_error_handling_test(const struct test_case *test) { /* * Enable EDMA module, peripheral channels 0 and 1, * standard channel 2 */ edma_enable(EDMA_CHMODE_STD2_gc); /* Reset the channel */ edma_channel_reset(EDMA_CH_2); /* Set up channel 0 to do some work, check that is it busy, * change some settings and verify a transfer error */ edma_channel_write_burst_length(EDMA_CH_2, EDMA_CH_BURSTLEN_1BYTE_gc); edma_channel_write_transfer_count16(EDMA_CH_2, MEMORY_BLOCK_SIZE); edma_channel_write_src_address(EDMA_CH_2, (uint16_t)(uintptr_t)memory_block_src); edma_channel_write_dest_address(EDMA_CH_2, (uint16_t)(uintptr_t)memory_block_dest); /* Enable the channel */ edma_channel_enable(EDMA_CH_2); /* Start a block transfer */ edma_channel_trigger_block_transfer(EDMA_CH_2); /* Wait for the channel to become busy */ while (!edma_channel_is_busy(EDMA_CH_2)) { /* Intentionally left empty */ } /* Disable the channel while it is busy */ if (edma_channel_is_busy(EDMA_CH_2)) { edma_channel_disable(EDMA_CH_2); } /* Test whether the channel is in error */ test_assert_true(test, edma_get_channel_status( EDMA_CH_2) == EDMA_CH_TRANSFER_ERROR, "EDMA channel not in ERROR after disabling during transfer write"); edma_disable(); }
/** * * \brief Test search and double buffering (link) modes * * \note This function tests search and double buffering features of the EDMA * controller by configuring channel 2 searching data. In case of success, the * channel 0 is automatically (double buffering) enables (if it is * successfull) and copies a memory block. The copy is verified. * * \param test Current test case */ static void run_edma_search_dbuf_test(const struct test_case *test) { struct edma_channel_config ch0_config_params; struct edma_channel_config ch2_config_params; bool success; /* 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(&ch0_config_params, 0, sizeof(ch0_config_params)); memset(&ch2_config_params, 0, sizeof(ch2_config_params)); /* Enable EDMA module, Channels 0 and 2 in standard configuration */ edma_enable(EDMA_CHMODE_STD02_gc); /* Enable double buffering mode on channel 0 and 1 */ edma_set_double_buffer_mode(EDMA_DBUFMODE_BUF0123_gc); /* Set channel 2 to search data (last byte of memory_block_src[]) */ edma_channel_set_src_reload_mode(&ch2_config_params, EDMA_CH_RELOAD_NONE_gc); edma_channel_set_src_dir_mode(&ch2_config_params, EDMA_CH_DIR_INC_gc); edma_channel_set_dest_reload_mode(&ch2_config_params, EDMA_CH_RELOAD_NONE_gc); edma_channel_set_search_mode(&ch2_config_params, EDMA_CH_DESTDIR_MP1_gc); edma_channel_set_burst_length(&ch2_config_params, EDMA_CH_BURSTLEN_1BYTE_gc); edma_channel_set_trigger_source(&ch2_config_params, EDMA_CH_TRIGSRC_OFF_gc); edma_channel_set_transfer_count16(&ch2_config_params, MEMORY_BLOCK_SIZE); edma_channel_set_source_address(&ch2_config_params, (uint16_t)(uintptr_t)memory_block_src); edma_channel_set_search_data(&ch2_config_params, memory_block_src[MEMORY_BLOCK_SIZE - 1], 0xFF); /* Write config channel 2 */ edma_channel_write_config(EDMA_CH_2, &ch2_config_params); /* * Set channel 0 to copy from memory_block_src[] to memory_block_dest[] * once a match will occur on channel 2. There will be no transfer if no * match occurs. */ edma_channel_set_repeat(&ch0_config_params); edma_channel_set_burst_length(&ch0_config_params, EDMA_CH_BURSTLEN_2BYTE_gc); edma_channel_set_src_reload_mode(&ch0_config_params, EDMA_CH_RELOAD_TRANSACTION_gc); edma_channel_set_dest_reload_mode(&ch0_config_params, EDMA_CH_RELOAD_TRANSACTION_gc); edma_channel_set_src_dir_mode(&ch0_config_params, EDMA_CH_DIR_INC_gc); edma_channel_set_dest_dir_mode(&ch0_config_params, EDMA_CH_DESTDIR_INC_gc); edma_channel_set_trigger_source(&ch0_config_params, EDMA_CH_TRIGSRC_OFF_gc); edma_channel_set_transfer_count16(&ch0_config_params, MEMORY_BLOCK_SIZE); edma_channel_set_source_address(&ch0_config_params, (uint16_t)(uintptr_t)memory_block_src); edma_channel_set_destination_address(&ch0_config_params, (uint16_t)(uintptr_t)memory_block_dest); /* Write config channel 0 */ edma_channel_write_config(EDMA_CH_0, &ch0_config_params); /* Enable only channel 2 */ edma_channel_enable(EDMA_CH_2); /* Transfer block and wait for it to finish */ edma_channel_trigger_block_transfer(EDMA_CH_2); edma_channel_trigger_block_transfer(EDMA_CH_0); /* Wait for search completion */ while (edma_get_channel_status(EDMA_CH_2) != EDMA_CH_TRANSFER_COMPLETED) { /* Intentionally left empty */ } /* Wait for transfer completion */ while (edma_get_channel_status(EDMA_CH_0) != EDMA_CH_TRANSFER_COMPLETED) { /* Intentionally left empty */ } /* Disable EDMA */ edma_disable(); /* Verify that the search result is as expected */ success = block_compare( edma_channel_get_search_pointer(EDMA_CH_2), &memory_block_src[MEMORY_BLOCK_SIZE - 1], 1); test_assert_true(test, success, "SEARCH mode did not function properly"); /* Verify that the transfer result is as expected */ success = block_compare(memory_block_src, memory_block_dest, MEMORY_BLOCK_SIZE); test_assert_true(test, success, "DOUBLE BUFFER mode did not function properly"); }