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 Driver on r_dmac.
Configuration | Options | Default | Description |
General > Name | Name must be a valid C symbol | g_transfer0 | Module name. |
General > Channel | Must be a valid integer between 0 and 15. | 0 | Specify the hardware channel. |
General > Activation Source | Refer to the RZA Configuration tool for available options. | SOFTWARE_TRIGGER | Select the DMAC transfer start event. |
General > DMAC Mode |
| Register Mode | Select DMAC Mode. |
General > Channel Priority |
| module.driver.transfer_on_dmac.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 |
| Fixed | Select the address mode for the destination. |
Register Mode > Source Address Mode |
| Fixed | 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 > 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 31 | 24 | Select the transfer end interrupt priority. |
The DMAC peripheral module uses ICLK as the clock source. The ICLK frequency is set by using the Clocks tab of the FSP Configuration editor prior to a build, or by using the CGC module at run-time.
This module does not use I/O pins.
The DMAC Module supports two modes of operation.
In Link mode, a DMA transfer is performed by reading a descriptor placed in the RAM area as the transfer information setting value. The descriptor is configured by dmac_link_cfg_t struct. For more information see 'Link Mode' section in the RZ microprocessor manual.
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_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 (UINTPTR_MAX > UINT32_MAX)
uint8_t g_src0[TRANSFER_LENGTH_0] BSP_ALIGN_VARIABLE(64) __attribute__((section("UNCACHED_BSS")));
uint8_t g_dest0[TRANSFER_LENGTH_0] BSP_ALIGN_VARIABLE(64) __attribute__((section("UNCACHED_BSS")));
uint8_t g_src1[TRANSFER_LENGTH_1] BSP_ALIGN_VARIABLE(64) __attribute__((section("UNCACHED_BSS")));
uint8_t g_dest1[TRANSFER_LENGTH_1] BSP_ALIGN_VARIABLE(64) __attribute__((section("UNCACHED_BSS")));
uint8_t g_src2[TRANSFER_LENGTH_2] BSP_ALIGN_VARIABLE(64) __attribute__((section("UNCACHED_BSS")));
uint8_t g_dest2[TRANSFER_LENGTH_2] BSP_ALIGN_VARIABLE(64) __attribute__((section("UNCACHED_BSS")));
dmac_link_cfg_t transfer0_descriptor BSP_ALIGN_VARIABLE (64) __attribute__((section("UNCACHED_BSS"))) =
{
.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,
};
dmac_link_cfg_t transfer1_descriptor BSP_ALIGN_VARIABLE (64) __attribute__((section("UNCACHED_BSS"))) =
{
.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,
};
dmac_link_cfg_t transfer2_descriptor BSP_ALIGN_VARIABLE (64) __attribute__((section("UNCACHED_BSS"))) =
{
.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 (UINTPTR_MAX > UINT32_MAX)
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)
{
}
}