The supported kit list:
- SAM D21/R21/D11/L21/L22/DA1/C21 Xplained Pro
In this use case, the TC will be used to generate a PWM signal. Here the pulse width is set to one quarter of the period. Once the counter value matches the values in the Compare/Capture Value register, an event will be tiggered for a DMA memory to memory transfer. The TC module will be set up as follows:
- GCLK generator 0 (GCLK main) clock source
- 16-bit resolution on the counter
- No prescaler
- Normal PWM wave generation
- GCLK reload action
- Don't run in standby
- No inversion of waveform output
- No capture enabled
- Count upward
- Don't perform one-shot operations
- No event input enabled
- No event action
- No event generation enabled
- Counter starts on 0
- Capture compare channel 0 set to 0xFFFF/4
The DMA module is configured for:
- Move data from memory to memory
- Using peripheral trigger of TC6 Match/Compare 0
- Using DMA priority level 0
Quick Start
Prerequisites
There are no prerequisites for this use case.
Code
Add to the main application source file, before any functions, according to the kit used:
- SAM D21 Xplained Pro.
#define PWM_MODULE EXT1_PWM_MODULE
#define PWM_OUT_PIN EXT1_PWM_0_PIN
#define PWM_OUT_MUX EXT1_PWM_0_MUX
#define M2M_DMAC_TRIGGER_ID TC6_DMAC_ID_MC_0
- SAM R21 Xplained Pro.
#define PWM_MODULE EXT1_PWM_MODULE
#define PWM_OUT_PIN EXT1_PWM_0_PIN
#define PWM_OUT_MUX EXT1_PWM_0_MUX
#define M2M_DMAC_TRIGGER_ID TC3_DMAC_ID_MC_0
- SAM D11 Xplained Pro.
#define PWM_MODULE EXT1_PWM_MODULE
#define PWM_OUT_PIN EXT1_PWM_0_PIN
#define PWM_OUT_MUX EXT1_PWM_0_MUX
#define M2M_DMAC_TRIGGER_ID TC1_DMAC_ID_MC_0
- SAM L21 Xplained Pro.
#define PWM_MODULE EXT2_PWM_MODULE
#define PWM_OUT_PIN EXT2_PWM_0_PIN
#define PWM_OUT_MUX EXT2_PWM_0_MUX
#define M2M_DMAC_TRIGGER_ID TC0_DMAC_ID_MC_0
- SAM L22 Xplained Pro.
#define PWM_MODULE EXT1_PWM_MODULE
#define PWM_OUT_PIN EXT1_PWM_0_PIN
#define PWM_OUT_MUX EXT1_PWM_0_MUX
#define M2M_DMAC_TRIGGER_ID TC0_DMAC_ID_MC_0
- SAM DA1 Xplained Pro.
#define PWM_MODULE EXT1_PWM_MODULE
#define PWM_OUT_PIN EXT1_PWM_0_PIN
#define PWM_OUT_MUX EXT1_PWM_0_MUX
#define M2M_DMAC_TRIGGER_ID TC6_DMAC_ID_MC_0
- SAM HA1G16A Xplained Pro.
#define PWM_MODULE EXT1_PWM_MODULE
#define PWM_OUT_PIN EXT1_PWM_0_PIN
#define PWM_OUT_MUX EXT1_PWM_0_MUX
#define M2M_DMAC_TRIGGER_ID TC6_DMAC_ID_MC_0
- SAM C21 Xplained Pro.
#define PWM_MODULE EXT1_PWM_MODULE
#define PWM_OUT_PIN EXT1_PWM_0_PIN
#define PWM_OUT_MUX EXT1_PWM_0_MUX
#define M2M_DMAC_TRIGGER_ID TC0_DMAC_ID_MC_0
Add to the main application source file, outside of any functions: #define TRANSFER_SIZE (16)
#define TRANSFER_COUNTER (32)
static uint8_t source_memory[TRANSFER_SIZE*TRANSFER_COUNTER];
static uint8_t destination_memory[TRANSFER_SIZE*TRANSFER_COUNTER];
static volatile bool transfer_is_done = false;
DmacDescriptor example_descriptor SECTION_DMAC_DESCRIPTOR;
Copy-paste the following setup code to your user application: #define TRANSFER_SIZE (16)
#define TRANSFER_COUNTER (32)
static uint8_t source_memory[TRANSFER_SIZE*TRANSFER_COUNTER];
static uint8_t destination_memory[TRANSFER_SIZE*TRANSFER_COUNTER];
static volatile bool transfer_is_done = false;
DmacDescriptor example_descriptor SECTION_DMAC_DESCRIPTOR;
void configure_tc(void)
{
config_tc.counter_16_bit.compare_capture_channel[0] = (0xFFFF / 4);
config_tc.pwm_channel[0].enabled = true;
config_tc.pwm_channel[0].pin_out = PWM_OUT_PIN;
config_tc.pwm_channel[0].pin_mux = PWM_OUT_MUX;
tc_init(&tc_instance, PWM_MODULE, &config_tc);
}
{
transfer_is_done = true;
}
{
config.peripheral_trigger = M2M_DMAC_TRIGGER_ID;
}
void setup_dma_descriptor(DmacDescriptor *descriptor)
{
descriptor_config.block_transfer_count = TRANSFER_SIZE;
descriptor_config.source_address = (uint32_t)source_memory + TRANSFER_SIZE;
descriptor_config.destination_address =
(uint32_t)destination_memory + TRANSFER_SIZE;
}
Add to user application initialization (typically the start of main()
):
Workflow
Create variables
- Create a module software instance structure for the TC module to store the TC driver state while it is in use.
- Note
- This should never go out of scope as long as the module is in use. In most cases, this should be global.
- Create a module software instance structure for DMA resource to store the DMA resource state while it is in use.
- Note
- This should never go out of scope as long as the module is in use. In most cases, this should be global.
Configure TC
- Create a TC module configuration struct, which can be filled out to adjust the configuration of a physical TC peripheral.
- Initialize the TC configuration struct with the module's default values.
- Note
- This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
- Alter the TC settings to configure the counter width, wave generation mode, and the compare channel 0 value.
config_tc.counter_16_bit.compare_capture_channel[0] = (0xFFFF / 4);
- Alter the TC settings to configure the PWM output on a physical device pin.
config_tc.pwm_channel[0].enabled = true;
config_tc.pwm_channel[0].pin_out = PWM_OUT_PIN;
config_tc.pwm_channel[0].pin_mux = PWM_OUT_MUX;
- Configure the TC module with the desired settings.
tc_init(&tc_instance, PWM_MODULE, &config_tc);
- Enable the TC module to start the timer and begin PWM signal generation.
Configure DMA
- Create a DMA resource configuration structure, which can be filled out to adjust the configuration of a single DMA transfer.
- Initialize the DMA resource configuration struct with the module's default values.
config.peripheral_trigger = M2M_DMAC_TRIGGER_ID;
- Note
- This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
- Allocate a DMA resource with the configurations.
- Create a DMA transfer descriptor configuration structure, which can be filled out to adjust the configuration of a single DMA transfer.
- Initialize the DMA transfer descriptor configuration struct with the module's default values.
- Note
- This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
- Set the specific parameters for a DMA transfer with transfer size, source address, and destination address.
descriptor_config.block_transfer_count = TRANSFER_SIZE;
descriptor_config.source_address = (uint32_t)source_memory + TRANSFER_SIZE;
descriptor_config.destination_address =
(uint32_t)destination_memory + TRANSFER_SIZE;
- Create the DMA transfer descriptor.
- Add the DMA transfer descriptor to the allocated DMA resource.
- Register a callback to indicate transfer status.
- The transfer done flag is set in the registered callback function.
{
transfer_is_done = true;
}
Prepare data
- Setup memory content for validate transfer.
for (i = 0; i < TRANSFER_SIZE*TRANSFER_COUNTER; i++) {
source_memory[i] = i;
}
Use Case
Code
Copy-paste the following code to your user application:
for(i=0;i<TRANSFER_COUNTER;i++) {
transfer_is_done = false;
while (!transfer_is_done) {
}
example_descriptor.SRCADDR.reg += TRANSFER_SIZE;
example_descriptor.DSTADDR.reg += TRANSFER_SIZE;
}
while(1);
Workflow
- Start the loop for transfer.
for(i=0;i<TRANSFER_COUNTER;i++) {
transfer_is_done = false;
while (!transfer_is_done) {
}
example_descriptor.SRCADDR.reg += TRANSFER_SIZE;
example_descriptor.DSTADDR.reg += TRANSFER_SIZE;
}
- Set the transfer done flag as false.
transfer_is_done = false;
- Start the transfer job.
- Wait for transfer done.
while (!transfer_is_done) {
}
- Update the source and destination address for next transfer.
example_descriptor.SRCADDR.reg += TRANSFER_SIZE;
example_descriptor.DSTADDR.reg += TRANSFER_SIZE;
- Enter endless loop.