The Direct Memory Access Controller (DMAC) transfers data from one memory location to another without using the CPU.
This module can be added to the Stacks tab via New Stack > Transfer > Transfer (r_dmac_b).
Configuration | Options | Default | Description |
General > Name | Name must be a valid C symbol | g_transfer0 | Module name. |
General > Unit | MCU Specific Options | | Specify the hardware unit. In a multi-core environment, it is recommended to open a separate unit for each core. |
General > Channel | Must be a valid integer between 0 and 15. | 0 | Specify the hardware channel. |
General > Activation Source | MCU Specific Options | | Select the DMAC transfer start event. |
General > DACK Output mode | MCU Specific Options | | Select DACK output mode. |
General > External DREQ Input Pin Select | MCU Specific Options | | Select DREQ input signal. |
General > External DACK Output Pin Select | MCU Specific Options | | Select DACK output signal. |
General > External TEND Output Pin Select | MCU Specific Options | | Select TEND output signal. |
General > External DREQ Detection Mode | MCU Specific Options | | External DREQ detection mode select.(This cannot be set on devices that do not have an external DREQ terminal) |
General > DMAC Mode |
| Register Mode | Select DMAC Mode. |
General > Channel Priority |
| module.driver.transfer_on_dmac_b.channel_priority.fixed | Channel Priority |
Register Mode > Mode |
| Normal | Select the transfer mode. |
Register Mode > Source Data Size |
-
1 Byte
-
2 Bytes
-
4 Bytes
-
8 Bytes
-
16 Bytes
-
32 Bytes
-
64 Bytes
-
128 Bytes
| 2 Bytes | Select the source data size. |
Register Mode > Destination Data Size |
-
1 Byte
-
2 Bytes
-
4 Bytes
-
8 Bytes
-
16 Bytes
-
32 Bytes
-
64 Bytes
-
128 Bytes
| 2 Bytes | Select the destination data size. |
Register Mode > Destination Address Mode |
| Incremented | Select the address mode for the destination. |
Register Mode > Source Address Mode |
| Incremented | Select the address mode for the source. |
Register Mode > DMA Activation Request Source Select |
-
Requested by a transfer source module
-
Requested by a transfer destination module
| Requested by a transfer source module | DMA Activation Request Source Select. |
Register Mode > Transfer Interval | Value must be a non-negative integer | 0 | Transfer interval |
Register Mode > Transfer Continuation |
-
DMA transfer only once
-
Transfer with Setting 1 and Setting 2 alternately
| DMA transfer only once | When Next0 Register Set Transfer completes, Next1 Register Set Transfer occurs |
Register Mode > Setting 1 Destination Address | Manual Entry | NULL | Specify the transfer destination address. |
Register Mode > Setting 1 Source Address | Manual Entry | NULL | Specify the transfer source address. |
Register Mode > Setting 1 Total Number of Transfer Bytes | Value must be a non-negative integer | 1 | Specify the total number of transfer bytes. |
Register Mode > Setting 2 Destination Address | Manual Entry | NULL | Specify the transfer destination address.(Use only when Transfer with Setting 1 and Setting 2 horizontally is selected in Transfer Continuatuion.) |
Register Mode > Setting 2 Source Address | Manual Entry | NULL | Specify the transfer source address.(Use only when Transfer with Setting 1 and Setting 2 horizontally is selected in Transfer Continuatuion.) |
Register Mode > Setting 2 Total Number of Transfer Bytes | Value must be a non-negative integer | 1 | Specify the total number of transfer bytes.(Use only when Transfer with Setting 1 and Setting 2 horizontally is selected in Transfer Continuatuion.) |
Link Mode > Descriptor | Name must be a valid C symbol | NULL | DMAC Link mode descriptor symbol name. |
Interrupts > Callback | Name must be a valid C symbol | NULL | A user callback that is called at the end of the transfer. |
Interrupts > Context | Manual Entry | NULL | Pointer to the context structure passed through the callback argument. |
Interrupts > Transfer End Interrupt Enable | MCU Specific Options | | Enable the transfer end interrupt. |
Interrupts > Transfer End Interrupt Priority | Value must be an integer between 0 and 255 | 12 | Select the transfer end interrupt priority. |
The clock sources for the DMAC peripheral module vary depending on the device. These clocks are shown in the table below.
In Register mode, a DMA transfer is performed by setting transfer information in each register. The address information of the transfer source and destination and the number of bytes to transfer, can be set up to two register sets (Next0 register set and Next1 register set), and continuous transfers can be performed alternately according to each setting. For more information, see the "Register Mode" section of the user's manual.
In Link mode, a DMA transfer is performed by reading a descriptor placed in the memory as the transfer information. The descriptor is configured by dmac_b_link_cfg_t struct. For more information, including what information can be set in the descriptor, see the "Link Mode" section of the user's manual.
The DMAC Module supports two modes of operation.
This driver only supports the transfer by non-secure access. Therefore, for slave areas with a security level set, be sure to change the slave level appropriately before performing a DMA transfer.
If CPU has built-in cache memory, the transfer source and destination should be placed to the area where the cache memory is set to disabled.
The execution of the Reload function must be completed during the transfer of Next0 or Next1. If the total number of bytes transferred is small, the next transfer may start before the function execution completes. In this case, continuous operation of DMAC transfer is not guaranteed, so when using the Reload function, it is recommended to set the number of bytes to be transferred a little longer, taking into account the bus clock frequency and interrupt processing time.
This is a basic example of minimal use of the DMAC in an application.
This is an example of an application using the DMAC link mode for continuous transfers. DMAC transfer is triggered by R_DMAC_B_SoftwareStart().
In this example, if the MMU is supported, the source and destination addresses are set to non-cached areas of system RAM.
#define TRANSFER_LENGTH_0 (2048)
#define TRANSFER_LENGTH_1 (1024)
#define TRANSFER_LENGTH_2 (512)
#define DMAC_CHCFG_SETTING_VALUE (0x80400420)
#define DMAC_CHEXT_SETTING_VALUE (0x00)
#if (BSP_FEATURE_DMAC_B_64BIT_SYSTEM == 1)
uint8_t g_src0[TRANSFER_LENGTH_0] BSP_ALIGN_VARIABLE(64)
__attribute__((section(".noncache_buffer")));
uint8_t g_dest0[TRANSFER_LENGTH_0] BSP_ALIGN_VARIABLE(64)
__attribute__((section(".noncache_buffer")));
uint8_t g_src1[TRANSFER_LENGTH_1] BSP_ALIGN_VARIABLE(64)
__attribute__((section(".noncache_buffer")));
uint8_t g_dest1[TRANSFER_LENGTH_1] BSP_ALIGN_VARIABLE(64)
__attribute__((section(".noncache_buffer")));
uint8_t g_src2[TRANSFER_LENGTH_2] BSP_ALIGN_VARIABLE(64)
__attribute__((section(".noncache_buffer")));
uint8_t g_dest2[TRANSFER_LENGTH_2] BSP_ALIGN_VARIABLE(64)
__attribute__((section(".noncache_buffer")));
{
.src_addr = 0x0,
.dest_addr = 0x0,
.transaction_byte = TRANSFER_LENGTH_0,
.channel_cfg = DMAC_CHCFG_SETTING_VALUE,
.channel_interval = 0,
.channel_extension_cfg = 0,
.next_link_addr = 0,
};
{
.src_addr = 0x0,
.dest_addr = 0x0,
.transaction_byte = TRANSFER_LENGTH_1,
.channel_cfg = DMAC_CHCFG_SETTING_VALUE,
.channel_interval = 0,
.channel_extension_cfg = 0,
.next_link_addr = 0,
};
{
.src_addr = 0x0,
.dest_addr = 0x0,
.transaction_byte = TRANSFER_LENGTH_2,
.channel_cfg = DMAC_CHCFG_SETTING_VALUE,
.channel_interval = 0,
.channel_extension_cfg = 0,
.next_link_addr = 0,
};
#else
uint8_t g_src0[TRANSFER_LENGTH_0];
uint8_t g_dest0[TRANSFER_LENGTH_0];
uint8_t g_src1[TRANSFER_LENGTH_1];
uint8_t g_dest1[TRANSFER_LENGTH_1];
uint8_t g_src2[TRANSFER_LENGTH_2];
uint8_t g_dest2[TRANSFER_LENGTH_2];
{
.p_src = (void *) ((uint32_t) &g_src0[0]),
.p_dest = (void *) ((uint32_t) &g_dest0[0]),
.transaction_byte = TRANSFER_LENGTH_0,
.channel_cfg = DMAC_CHCFG_SETTING_VALUE,
.channel_interval = 0,
.channel_extension_cfg = 0,
.p_next_link_addr = NULL,
};
{
.p_src = (void *) ((uint32_t) &g_src1[0]),
.p_dest = (void *) ((uint32_t) &g_dest1[0]),
.transaction_byte = TRANSFER_LENGTH_1,
.channel_cfg = DMAC_CHCFG_SETTING_VALUE,
.channel_interval = 0,
.channel_extension_cfg = 0,
.p_next_link_addr = NULL,
};
{
.p_src = (void *) ((uint32_t) &g_src2[0]),
.p_dest = (void *) ((uint32_t) &g_dest2[0]),
.transaction_byte = TRANSFER_LENGTH_2,
.channel_cfg = DMAC_CHCFG_SETTING_VALUE,
.channel_interval = 0,
.channel_extension_cfg = 0,
.p_next_link_addr = NULL,
};
#endif
volatile bool g_transfer_complete = false;
{
g_transfer_complete = true;
}
void dmac_link_mode_example (void)
{
for (uint32_t i = 0; i < TRANSFER_LENGTH_0; i++)
{
g_src0[i] = (uint8_t) ('A' + (i % 26));
}
for (uint32_t i = 0; i < TRANSFER_LENGTH_1; i++)
{
g_src1[i] = (uint8_t) ('A' + (i % 26));
}
for (uint32_t i = 0; i < TRANSFER_LENGTH_2; i++)
{
g_src2[i] = (uint8_t) ('A' + (i % 26));
}
#if (BSP_FEATURE_BSP_HAS_MMU_SUPPORT)
uint64_t * p_src_paddress = 0;
R_MMU_VAtoPA(NULL, (uint64_t) &g_src0[0], p_src_paddress);
transfer0_descriptor.src_addr = (uint32_t) *p_src_paddress;
uint64_t * p_dest_paddress = 0;
R_MMU_VAtoPA(NULL, (uint64_t) &g_dest0[0], p_dest_paddress);
transfer0_descriptor.dest_addr = (uint32_t) *p_dest_paddress;
uint64_t * p_next_link_paddress = 0;
R_MMU_VAtoPA(NULL, (uint64_t) &transfer1_descriptor, p_next_link_paddress);
transfer0_descriptor.next_link_addr = (uint32_t) *p_next_link_paddress;
R_MMU_VAtoPA(NULL, (uint64_t) &g_src1[0], p_src_paddress);
transfer1_descriptor.src_addr = (uint32_t) *p_src_paddress;
R_MMU_VAtoPA(NULL, (uint64_t) &g_dest1[0], p_dest_paddress);
transfer1_descriptor.dest_addr = (uint32_t) *p_dest_paddress;
R_MMU_VAtoPA(NULL, (uint64_t) &transfer2_descriptor, p_next_link_paddress);
transfer1_descriptor.next_link_addr = (uint32_t) *p_next_link_paddress;
R_MMU_VAtoPA(NULL, (uint64_t) &g_src2[0], p_src_paddress);
transfer2_descriptor.src_addr = (uint32_t) *p_src_paddress;
R_MMU_VAtoPA(NULL, (uint64_t) &g_dest2[0], p_dest_paddress);
transfer2_descriptor.dest_addr = (uint32_t) *p_dest_paddress;
#else
transfer0_descriptor.p_next_link_addr = &transfer1_descriptor;
transfer1_descriptor.p_next_link_addr = &transfer2_descriptor;
#endif
assert(FSP_SUCCESS == err);
assert(FSP_SUCCESS == err);
assert(FSP_SUCCESS == err);
while (!g_transfer_complete)
{
}
g_transfer_complete = false;
assert(FSP_SUCCESS == err);
while (!g_transfer_complete)
{
}
g_transfer_complete = false;
assert(FSP_SUCCESS == err);
while (!g_transfer_complete)
{
}
}