Hi,
I have a DMA job set up, which consists of four resources. Each resource transfers a buffer of a couple of hundred bytes over to SERCOM1. I use software triggering for the transfer. The first time I want to transfer (the first buffer) I call dma_start_transfer_job() and the data gets transferred. Following I call dma_resume_job() to transfer the next buffer. This works perfectly. However, there is the case that the controller needs to resets is complete state and start all over again, starting with the first buffer. This can happen at any time, but the DMA will always be in SUSPEND state (so there is currently no transfer going on). To reset the DMA I tried calling dma_abort_job() and dma_start_transfer_job() once I want to send the fist buffer. This does not seem to work. The data is not transferred to the SERCOM1 data register and the state of the DMA is always BUSY after that. dma_start_transfer_job() however returns OK.
Below is a simple test snipped that shows the problem.
stateUSARTDMA = dma_get_job_status(&usart_dma_resource_tx); // OK stateUSARTDMA = dma_start_transfer_job(&usart_dma_resource_tx); // OK, data transferred delay_ms(10); stateUSARTDMA = dma_get_job_status(&usart_dma_resource_tx); // SUSPEND dma_resume_job(&usart_dma_resource_tx); // data transferred delay_ms(10); stateUSARTDMA = dma_get_job_status(&usart_dma_resource_tx); // SUSPEND dma_abort_job(&usart_dma_resource_tx); delay_ms(10); stateUSARTDMA = dma_get_job_status(&usart_dma_resource_tx); // ABORDTED stateUSARTDMA = dma_start_transfer_job(&usart_dma_resource_tx); // OK, no data transferred delay_ms(10); stateUSARTDMA = dma_get_job_status(&usart_dma_resource_tx); // BUSY
Below is the code for the initialization of the DMA:
// USART: Set up DMA resource for transmitting struct dma_resource_config config_usart_dma_resource; dma_get_config_defaults(&config_usart_dma_resource); config_usart_dma_resource.peripheral_trigger = SERCOM1_DMAC_ID_TX; config_usart_dma_resource.trigger_action = DMA_TRIGGER_ACTION_BEAT; dma_allocate(&usart_dma_resource_tx, &config_usart_dma_resource); // USART: Set up USART DMA descriptors for each buffer struct dma_descriptor_config usart_dma_descriptor_config; dma_descriptor_get_config_defaults(&usart_dma_descriptor_config); usart_dma_descriptor_config.beat_size = DMA_BEAT_SIZE_BYTE; usart_dma_descriptor_config.dst_increment_enable = false; usart_dma_descriptor_config.block_transfer_count = sizeof(packetADC_t); usart_dma_descriptor_config.step_size = DMA_ADDRESS_INCREMENT_STEP_SIZE_1; usart_dma_descriptor_config.destination_address = (uint32_t)(®_SERCOM1_USART_DATA); usart_dma_descriptor_config.block_action = DMA_BLOCK_ACTION_SUSPEND; for(int i = 0; i < ADC_BLOCK_COUNT; i++) { usart_dma_descriptor_config.source_address = ((uint32_t)(&(vibBlockList[i])))+sizeof(packetADC_t); if(i+1 != ADC_BLOCK_COUNT) usart_dma_descriptor_config.next_descriptor_address = (uint32_t)&(usart_dma_descriptor_list[i+1]); else usart_dma_descriptor_config.next_descriptor_address = (uint32_t)&(usart_dma_descriptor_list[0]); dma_descriptor_create(&(usart_dma_descriptor_list[i]), &usart_dma_descriptor_config); } dma_add_descriptor(&usart_dma_resource_tx, &(usart_dma_descriptor_list[0])); dma_register_callback(&usart_dma_resource_tx, usart_tx_done, DMA_CALLBACK_CHANNEL_SUSPEND); dma_enable_callback(&usart_dma_resource_tx, DMA_CALLBACK_CHANNEL_SUSPEND);
Any thoughts?