AN220191 How to use direct memory access (DMA) controller in TRAVEO™ T2G family
About this document
Scope and purpose
This application note describes how to use DMA controllers (P-DMA and M-DMA) in TRAVEO™ T2G family MCUs. DMA controllers can transfer data from a source to a destination without CPU intervention. The application note illustrates how to configure DMA for peripheral-to-memory, memory-to-peripheral, and memory- to-memory data transfers.
Associated part family
TRAVEO™ T2G family CYT2/CYT3/CYT4 series.
Intended audience
This document is intended for anyone using TRAVEO™ T2G family CYT2/3/4 series.
Introduction
This application note describes how to use the direct memory access (DMA) controller in TRAVEO™ T2G family MCUs.
DMA controllers can seamlessly transfer data between memory and on-chip peripherals, or between memories without CPU intervention. This allows the CPU to handle other tasks while the DMA controller transfers data.
Both P-DMA and M-DMA have multiple independent DMA channels. Each DMA channel has a separate DMA request input that initiates the transaction and can independently transfer data. See the device datasheet for the number of DMA channels available for each device.
This series supports two types of DMA controllers: Peripheral DMA (P-DMA) and Memory DMA (M-DMA). P-DMA is used for peripheral-to-memory and memory-to- peripheral low-latency data transfers for many channels. MDMA is used for memory-to-memory high-memory-bandwidth data transfer for a small number of channels.
These DMA controllers have a descriptor that specifies the transfer operation, and it corresponds flexibly to various applications. Descriptors can be chained; it is possible to have circular lists.
This application note explains the functioning of DMA controllers in the series, initial configuration, and data transfer operations with use cases.
To understand the functionality described and terminology used in this application note, see the “Direct Memory Access” chapter of the architecture technical reference manual (TRM).
Features
Table 1 compares P-DMA with M-DMA, which have similar registers and descriptor structures.
Table 1. P-DMA/M-DMA Features
Feature | P-DMA | M-DMA |
---|---|---|
Focuses on | Low latency | High memory bandwidth |
Useful for | Transfer between peripheral and memory | Transfer between memories |
Transfer engine | Shared all channels | Dedicated for each channel |
Transfer size | 8-bit, 16-bit, 32-bit | 8-bit, 16-bit, 32-bit |
Channel priority |
| Four levels |
Descriptor type |
|
|
Descriptor |
|
|
Trigger input |
|
|
P-DMA can be also used for transfers between memories, but the transfer bandwidth may not be enough when compared with M-DMA. M-DMA can also be used for transfers between memory and peripherals, but the transfer latency may not be low when compared with P-DMA.
In P-DMA, when preemptable, a higher-priority pending channel can preempt the current channel between single transfers. M-DMA does not have the preemptable functionality because it would degrade the overall memory bandwidth.
The descriptor determines the DMA transfer specification. The descriptor type determines the type of DMA transfer operation. Both DMAs support single transfer, 1D transfer, and 2D transfer as descriptor types. In addition, P-DMA supports CRC transfer, while M-DMA supports memory copy and scatter. See section Descriptor type for details of each descriptor type. Descriptors can be chained by storing the pointer of the next descriptor in the current descriptor. A descriptor chain is also referred to as a descriptor list.
Trigger inputs such as hardware trigger, software trigger, and trigger output (tr_out) are input via the trigger multiplexer, which is a peripheral function outside DMA. The trigger multiplexer routes triggers from potential sources to destinations. See the “Trigger Multiplexer” chapter of the architecture TRM for more details.
P-DMA supports hardware trigger, software trigger, and trigger output (tr_out) as trigger inputs, while M-DMA supports only software trigger and trigger output (tr_out). See the device datasheet for hardware triggers available. The software trigger is implemented by the trigger multiplexer function. Both DMAs can use the trigger output as their own input trigger. See section Trigger functionality for each trigger functionality.
Block diagram
Figure 1 shows the P-DMA block diagram.
Figure 1. P-DMA block diagramM-DMA block diagram
P-DMA consists of channels (CH0 – CHn), a pending trigger block, priority decoder, data transfer engine, and the interrupt logic. The P-DMA transfer engine is shared by all channels. See the architecture TRM for details of each block.
As mentioned earlier, P-DMA trigger inputs can be a hardware trigger, software trigger, or trigger output (tr_out). These triggers are input via the trigger multiplexer.
The trigger output (tr_out) can be used as its own trigger input, or it can be used as the trigger input to trigger different transfers of other channels.
The memory that is used to store descriptors is outside the DMA block. When the transfer engine activates the next pending channel, the transfer engine reads the descriptor corresponding to the channel from the memory and starts the transfer.
Figure 2 shows M-DMA block diagram.
Figure 2. M-DMA block diagram
The M-DMA block consists of the channel logic, priority decoder, and registers. The channel logic itself stores the pending trigger and hosts the current channel state and data transfer engine. M-DMA has transfer engines dedicated for each channel. See the architecture TRM for details of each block.
As trigger inputs, M-DMA supports software trigger and its own trigger output (tr_out). These trigger inputs are input via the trigger multiplexer. Note that unlike P-DMA, M-DMA does not support hardware triggers.
Operation overview
Figure 3 shows how to configure P-DMA and M-DMA.
Figure 3. General configuration of P-DMA/M-DMA
In this example, channel, descriptor, and channel enable are configured for each channel. It is also possible to configure all channels to be used within each step.
A peripheral trigger is required after setting the corresponding DMA channel.
Disable/enable P-DMA/M-DMA
P-DMA and M-DMA can be enabled/disabled using the respective bits as shown in Table 2. The default setting after reset is ‘0’ (Disabled).
Table 2. P-DMA/M-DMA Disable/Enable
DMA type | Register (bit) | Description |
---|---|---|
P-DMA | DW_CTL.ENABLED (bit31) | 0: Disable, 1: Enable |
M-DMA | DMAC_CTL.ENABLED (bit31) | 0: Disable, 1: Enable |
Configure channel
In this step, P-DMA/M-DMA channel settings such as the channel priority and pointer address of the descriptor corresponding to the channel are configured.
In addition, in P-DMA, the preemptable function and CRC calculation mode for CRC transfer are configured, if necessary.
Table 3 and Table 4 show the registers that are used for configuring a channel in P-DMA and M-DMA, respectively. The registers corresponding to the channel number are configured. See the architecture TRM and registers technical reference manual (registers TRM) for more details.
Table 3. Channel configuration for P-DMA
Register (bit) | Description |
---|---|
DW_CH_STRUCT_CH_CURR_PTR | Sets the channel current descriptor pointer. Software needs to initialize this register. |
DW_CH_STRUCT_CH_CTL.PREEMPTABLE (bit11) | Specifies whether the channel is preemptable. |
DW_CH_STRUCT_CH_CTL.PRIO (bit9:8) | Sets the channel priority. |
DW_CH_STRUCT_CH_IDX.X_IDX (bit7:0) | Sets the X indices of the channel into the current descriptor. Software needs to initialize this register. |
DW_CH_STRUCT_CH_IDX_Y_IDX (bit15:0) | Sets the Y indices of the channel into the current descriptor. Software needs to initialize this register. |
Required only for CRC transfer: | |
DW_CRC_CTL.DATA_REVERSE (bit0) | Specifies the bit order (MSb or LSb first) in which a data byte is processed. |
DW_CRC_CTL.REM_REVERSE (bit8) | Specifies whether the remainder is bit reversed. |
DW_CRC_DATA_CTL.DATA_XOR (bit7:0) | Sets the byte mask with which each data byte is XORed. You can choose this 8-bit value randomly. |
DW_CRC_POL_CTL.POLYNOMIAL | Sets the CRC polynomial. |
DW_CRC_LFSR_CTL.LFSR32 | Sets the seed value for CRC calculation. |
DW_CRC_REM_CTL.REM_XOR | Sets a mask with which the CRC_LFSR_CTL.LFSR32 register is XORed. |
Table 4. Channel configuration for M-DMA
Register (bit) | Description |
---|---|
DMAC_CH_CH_CURR_PTR | Sets the channel current descriptor pointer. Software needs to initialize this register. |
DMAC_CH_CH_CTL.PRIO (bit9:8) | Sets the channel priority. |
Configure descriptor
In this step, the descriptor is configured. The descriptor specifies the DMA channel’s transfer details. A descriptor is stored in the memory outside DMA and read by the transfer engine. The transfer engine transfers the data according to the descriptor. The descriptor pointer position for each channel is stored in the descriptor pointer register (see section Configure channel).
Figure 4 shows the descriptor structure for P-DMA and M-DMA. The P-DMA descriptor consists of six 32-bit words, while the M-DMA descriptor consists of eight 32-bit words. However, descriptors of both DMAs have similar functions.
Figure 4. P-DMA/M-DMA descriptor structure
Configure descriptor parameters
- Descriptor control : This word describes DMA parameters such as descriptor type, transfer size, trigger-in/out, and interrupt setting.
- Source address and destination address : These words specify the base addresses of the source and destination locations.
- X loop control and X loop count : These words control the loop in 1D transfer or the inner loop in 2D transfer. The X loop control specifies the increment of the source and destination addresses for each X loop iteration. The X loop count specifies the number of iterations of the X loop.
- Y loop control and Y loop count : These words control the outer loop in 2D transfer. The Y loop control specifies the increment of the source and destination addresses for each Y loop iteration. The Y loop count specifies the number of iterations of the Y loop.
- Descriptor next pointer : This word specifies the address of the next descriptor. Descriptors can be chained by storing the descriptor of the next pointer in the current descriptor. The last descriptor in the descriptor list has ‘0’ (NULL) in this word.
See the architecture TRM and registers TRM for descriptor details.
The number of descriptor words used varies depending on the descriptor type. A word address is shifted forward if there is any unused descriptor word.
Descriptor type
This section explains the descriptor type, which determines the type of DMA transfer.
P-DMA has four descriptor types, and M-DMA has five descriptor types. The number of descriptor words used varies depending on the descriptor type. Table 5 shows each descriptor type. In Table 5, the transfer example column shows the outline and pseudocode of each descriptor type. The Using Descriptor column shows the descriptor word used by the descriptor types in each DMA. Note that a word address is shifted forward if there is any unused descriptor word.
Table 5. P-DMA/M-DMA transfer example and using descriptor for each
descriptor type
Descriptor type | Transfer example | Using descriptor | |
---|---|---|---|
P-DMA | M-DMA | ||
Single transfer | This transfers a single data element :
| ||
1D transfer | One-dimensional “for loop” transfer :
| ||
2D transfer | Two-dimensional “for loop” transfer :
| ||
CRC transfer | Calculate CRC of the specified area. Note that for CRC transfer, CRC must be configured with memory mapped I/O (MMIO) registers. | Not supported | |
Memory copy | One-dimensional “for loop” transfer :
| Not supported | |
Scatter | Write a set of 32-bit data elements, whose addresses are “scattered” around one-dimensional “for loop” transfer.
| Not supported |
Trigger functionality
This section explains the trigger function. Trigger input, trigger output (tr_out), and interrupt are controlled by the descriptor.
A trigger input activates DMA channel transfer. The trigger output (tr_out) and interrupt are output when the transfer is complete. The trigger operation is specified by TR_IN_TYPE, TR_OUT_TYPE, and INTR_TYPE in the descriptor. Trigger input, trigger output (tr_out), and interrupt can be configured independently for each channel. See the registers TRM for descriptor details.
- There are four types of trigger input operations:
- Type 0: Trigger results in the execution of a single transfer.
- Type 1: Trigger results in the execution of a single 1D transfer.
- Type 2: Trigger results in the execution of the current descriptor.
- Type 3: Trigger results in the execution of a descriptor list.
- There are four types of trigger outputs and interrupt timing:
- Type 0: Output trigger or interrupt is generated after a single transfer.
- Type 1: Output trigger or interrupt is generated after a single 1D transfer.
- Type 2: Output trigger or interrupt is generated after the execution of the current descriptor.
- Type 3: Output trigger or interrupt is generated after the execution of a descriptor list.
Examples for trigger functionality
This section provides examples for different trigger functions. The descriptor list for the following examples is composed of chaining two descriptors (Descriptor 0 and Descriptor 1) in a 2D transfer.
Example 1 :
This example describes the operation of a Type 0 trigger. Figure 5 shows the operation of the trigger input and trigger output or interrupt in Type 0 trigger.
Figure 5. Trigger operation example 1
When the trigger input is set in Type 0 trigger, P-DMA/M-DMA performs a single transfer with every trigger input. Therefore, 16 trigger inputs are required to complete Descriptor 0.
When trigger outputs and interrupts are set in Type 0 trigger, the trigger output, interrupt, or both are output each time a single transfer is completed. Therefore, trigger output, interrupt, or both are output 16 times with the completion of Descriptor 0.
Example 2 :
This example describes the Type 1 trigger operation. Figure 6 shows the operation of trigger input and trigger output or interrupt in Type 1 trigger.
Figure 6. Trigger operation example 2
When trigger input is set in Type 1 trigger, P-DMA/M-DMA performs a 1D transfer with the trigger input. If the next trigger occurs again, P-DMA/M-DMA performs a 1D transfer. Therefore, two trigger inputs are required to complete Descriptor 0.
When trigger outputs and interrupts are set in Type 1 trigger, trigger output, interrupt, or both are output each time a 1D transfer is completed. Therefore, trigger output, interrupt, or both are output twice with the completion of Descriptor 0.
Example 3 :
This example describes the operation of Type 2 trigger. Figure 7 shows the operation of the trigger input and trigger output or interrupt in Type 2 trigger.
Figure 7. Trigger operation example 3
When the trigger input is set in Type 2 trigger, P-DMA/M-DMA executes the current descriptor (here: Descriptor 0) with the trigger input. If the next trigger input occurs, P-DMA/M-DMA executes the next descriptor (here: Descriptor 1). Therefore, two trigger inputs are required to complete the descriptor list.
When trigger outputs and interrupts are set in Type 2 trigger, trigger output, interrupt, or both are output each time a current descriptor transfer is completed. Therefore, trigger output, interrupt, or both are output twice with the completion of the descriptor list.
Example 4 :
This example describes the operation of Type 3 trigger. Figure 8 shows the operation of the trigger input and trigger output or interrupt in Type 3 trigger.
Figure 8. Trigger operation example 4
When the trigger input is set in Type 3 trigger, P-DMA/M-DMA executes the complete descriptor list with each trigger input. Therefore, one trigger input is required to complete the descriptor list.
When trigger outputs and interrupts are set in Type 3 trigger, the trigger output, interrupt, or both are output when descriptor list transfer is completed. Therefore, the trigger output and/or interrupt are output once with the completion of the descriptor list.
Disable/enable P-DMA/M-DMA channel
P-DMA and M-DMA can be configured/programmed to execute multiple independent data transfers. Each data transfer is managed by a channel.
In DMA channel configuration, the DMA channel must be disabled during the configuration, and enabled after configuring the channel. Table 6 shows the registers used for enabling or disabling a DMA channel.
The number of channels varies for different part numbers. See the device datasheet for the number of available channels.
Table 6. Disable/enable P-DMA/M-DMA channel
DMA type | Register (bit) | Description |
---|---|---|
P-DMA | DW_CH_STRUCT_CH_CTL.ENABLED (bit31) | 0: Disable, 1: Enable |
M-DMA | DMAC_CH_CH_CTL.ENABLED (bit31) | 0: Disable, 1: Enable |
P-DMA use cases
This section describes how to use Smart I/O using the sample driver library (SDL). The code snippets in this application note are part of SDL. See Other references for the SDL.
SDL has a configuration part and a driver part. The configuration part mainly configures the parameter values for the desired operation. The driver part configures each register based on the parameter values in the configuration part. You can configure the configuration part according to your system.
In this example, CYT2B7 series is used.
1D transfer (memory-to-peripheral)
Overview
This is an example of transferring the transmit data from the memory to TX- FIFO by DMA when using the SCB UART mode. In this case, the UART uses an 8-bit data frame, and starts the transmission when the data is written to the FIFO. The number of bytes to be transmitted is 16 and the TX FIFO setting is 128 elements-deep with 8-bit data elements. See the “Serial Communications Block (SCB)” chapter of the architecture TRM for more details.
P-DMA starts the transfer with a software trigger from the CPU, and generates an interrupt to the CPU after transferring all data into the transmit FIFO.
Figure 9 shows the data transfer.
Figure 9. Use case of a memory-to-peripheral (1D transfer) using UART in SCB
(0) Configure P-DMA according to Initial configuration of channel registers Initial configuration of channel registers, and configure the SCB and trigger multiplexer.
(1) CPU notifies a software trigger to P-DMA via the trigger multiplexer.
(2) P-DMA reads the descriptor from the specified area (Descriptor Pointer) when activating the next pending channel.
(3) P-DMA reads data (d0) from the source address (RAM base address).
(4) P-DMA writes the read data (d0) to the destination address (SCB_TX_FIFO_WR). After that, P-DMA increments the source address by 0x01, but there is no increment of the destination address. Then, P-DMA reads the data (d1) from the source address (RAM base address +0x01) and writes it to the destination address (SCB_TX_FIFO_WR) again. P-DMA repeats from (3) to (4) until d15 data is transferred.
(5) P-DMA notifies the CPU with an interrupt when the transfer of all data is completed.
Initialize the channel registers and set the descriptor as follows.
Initial configuration of channel registers
This section describes the initialization of the P-DMA channel and descriptor of this use case.
Figure 10 shows the setting procedure for P-DMA.
Figure 10. Setting procedure for P-DMA
Configuration and example code
Table 7 lists the parameters and Table 8 lists the functions of the configuration part in SDL for P-DMA.
Table 7. List of DMA configuration Parameters
Parameters | Description | Value |
---|---|---|
DW_CHANNEL | Defines P-DMA channel | 7ul |
DW_CH_INTR | Defines P-DMA channel interrupt | cpuss_interrupts_dw1_7_IRQn |
DW_SW_TRIG | Defines P-DMA SW Trigger | TRIG_OUT_MUX_1_PDMA1_TR_IN7 |
.PDMA_Descriptor | P-DMA current descriptor pointer | &dwUartTxDescr |
.preemptable | Channel preemptable | 0ul |
.priority | Channel priority | 0ul |
.enable | Channel enable | 1ul |
.deact | DESCR_CTL WAIT_FOR_DEACT | 0ul |
.intrType | DESCR_CTL INTR_TYPE | CY_PDMA_INTR_DESCR_CMPLT |
.trigoutType | DESCR_CTL TR_OUT_TYPE | CY_PDMA_TRIGOUT_DESCR_CMPLT |
.chStateAtCmplt | DESCR_CTL CH_DISABLE | CY_PDMA_CH_DISABLED |
.triginType | DESCR_CTL TR_IN_TYPE | CY_PDMA_TRIGIN_DESCR |
.dataSize | DESCR_CTL DATA_SIZE | CY_PDMA_BYTE |
.srcTxfrSize | DESCR_CTL SRC_TRANSFER_SIZE | 0ul |
.destTxfrSize | DESCR_CTL DST_TRANSFER_SIZE | 1ul |
.descrType | DESCR_CTL DESCR_TYPE | CY_PDMA_1D_TRANSFER |
.srcAddr | DESCR_SRC | (void *)g_uart_tx_buffer |
.destAddr | DESCR_DST | (void *)&CY_USB_SCB_TYPE->unTX_FIFO_WR.u32Register |
.srcXincr | DESCR_X_CTL SRC_X_INCR | 1ul |
.destXincr | DESCR_X_CTL DST_X_INCR | 0ul |
.xCount | DESCR_X_CTL X_COUNT | UART_TX_BUFFER_SIZE |
.descrNext | DESCR_NEXT_PTR | NULL |
Table 8. List of DMA configuration functions
Functions | Description | Remarks |
---|---|---|
DW1_Ch_IntHandler() | Handler for P-DMA1 interrupts | See Code Listing 3 |
Cy_PDMA_Disable() | Configures P-DMA disable | Write to P-DMA_CTL_ENABLED bit. See Code Listing 6 |
Cy_PDMA_Chnl_DeInit() | Resets P-DMA to default values | Clears all the content of registers corresponding to the channel. See Code Listing 7 |
Cy_PDMA_Descr_Init() | Configures P-DMA descriptor initialize | See Code Listing 8 |
Cy_PDMA_Chnl_Init() | Configures P-DMA channel initialize | See Code Listing 9 |
Cy_PDMA_Chnl_Enable() | Configures P-DMA channel enable | See Code Listing 10 |
Cy_PDMA_Chnl_SetInterruptMask() | Configures P-DMA channel interrupt mask | See Code Listing 11 |
Cy_PDMA_Enable() | Configures P-DMA enable | Write to P-DMA_CTL_ENABLED bit. See Code Listing 12 |
Cy_SysInt_InitIRQ() | Configures interrupt | |
Cy_SysInt_SetSystemIrqVector() | Configures Interrupt vector | |
NVIC_EnableIRQ() | NVIC Enable interrupt | |
Cy_TrigMux_SwTrigger() | Generates a Software trigger | |
Cy_PDMA_Chnl_GetInterruptStatusMasked() | Returns logical and of corresponding INTR and INTR_MASK fields in a single load operation | See code Listing 4 |
Cy_PDMA_Chnl_ClearInterrupt() | Configures P-DMA channel clears the interrupt status | See Code Listing 5 |
Code Listing 1 demonstrates an example program to 1D Transfer (Memory-to- Peripheral). See the architecture TRM and application note for GPIO, UART, and clock configuration.
The following description will help you understand the register notation of the driver part of SDL:
-
base signifies the pointer to the DMA register base address.
-
base-> CH_STRUCT[idx].unCH_CTL.u32Register is the DWx_CH_STRUCT[idx] register mentioned in the registers TRM. Other registers are also described in the same manner. “x” signifies the port suffix number and “idx” signifies the register index number.
-
To improve the register setting performance, the SDL writes a complete 32-bit data to the register. Each bit field is generated and written to the register as the final 32-bit data.
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.u32Register; pstcPDMA->CH_STRUCT[chNum].unCH_IDX.u32Register; pstcPDMA->CH_STRUCT[chNum].unCH_CURR_PTR.u32Register; pstcPDMA->CH_STRUCT[chNum].unINTR_MASK.u32Register; pstcPDMA->CH_STRUCT[chNum].unINTR_SET.u32Register;
See cyip_dw_v2.h under hdr/rev_x/ip for more information on the union and structure representation of registers.
Code Listing 1 Example to 1D transfer (memory-to-peripheral)
/* Define DW channel
Define DW channel interrupt
Define DW SW Trigger */
#define DW_CHANNEL 7ul
#define DW_CH_INTR cpuss_interrupts_dw1_7_IRQn
#define DW_SW_TRIG TRIG_OUT_MUX_1_PDMA1_TR_IN7
void DW1_Ch_IntHandler(void); /* See Code Listing 3. */
int main(void)
{
:
/* (1) Disable P-DMA. See Code Listing 6.
(2) Resets P-DMA to default values. See Code Listing 7.
(3) Configures P-DMA descriptor initialize. See Code Listing 8.
(4) Enable P-DMA channel. See Code Listing 10.
(5) Enable P-DMA. See Code Listing 12 */
/* Initialize & Enable DMA */
Cy_PDMA_Disable(DW1);
Cy_PDMA_Chnl_DeInit(DW1, DW_CHANNEL);
Cy_PDMA_Descr_Init(&dwUartTxDescr, &dw1ChUartTxConfig);
Cy_PDMA_Chnl_Init(DW1, DW_CHANNEL, &dwUartTxConfig);
Cy_PDMA_Chnl_Enable(DW1, DW_CHANNEL);
Cy_PDMA_Chnl_SetInterruptMask(DW1, DW_CHANNEL);
Cy_PDMA_Enable(DW1);
/* Prepare source buffer data */
for(uint32_t i = 0ul; i < UART_TX_BUFFER_SIZE; i++)
{
g_uart_tx_buffer[i] = (i + 48ul); /* ASCII Code '0','1','2' ... */
}
/* Interrupt Initialization */
Cy_SysInt_InitIRQ(&stc_sysint_irq_cfg);
/* Configures interrupt */
Cy_SysInt_SetSystemIrqVector(stc_sysint_irq_cfg.sysIntSrc, DW1_Ch_IntHandler);
NVIC_EnableIRQ(stc_sysint_irq_cfg.intIdx);
/* SW Trigger */
/* Generates a software trigger */
Cy_TrigMux_SwTrigger(DW_SW_TRIG, TRIGGER_TYPE_EDGE, 1ul);
for(;;);
}
Code Listing 2 P-DMA channel, descriptor configuration
/**
* \var uint8_t g_uart_tx_buffer
* \brief UART TX buffer
*/
uint8_t g_uart_tx_buffer[UART_TX_BUFFER_SIZE] = { 0ul }; /* Variable for source address TX_buffer */
/**
* \var cy_stc_pdma_descr_t dwUartTxDescr /* Variable for P-DMA descriptor */
* \brief PDMA descriptor
*/
static cy_stc_pdma_descr_t dwUartTxDescr;
/**
* \var cy_stc_pdma_chnl_config_t dwUartTxConfig
* \brief PDMA configuration */
/* Configure P-DMA channel */
const cy_stc_pdma_chnl_config_t dwUartTxConfig =
{
.PDMA_Descriptor = &dwUartTxDescr,
.preemptable = 0ul,
.priority = 0ul,
.enable = 1ul,
};
/**
* \var cy_stc_pdma_descr_config_t dw1ChUartTxConfig
* \brief PDMA descriptor configuration */
static cy_stc_pdma_descr_config_t dw1ChUartTxConfig =
{
.deact = 0ul, /* Configure P-DMA descriptor */
.intrType = CY_PDMA_INTR_DESCR_CMPLT, /* Configure P-DMA descriptor */
.trigoutType = CY_PDMA_TRIGOUT_DESCR_CMPLT, /* Configure P-DMA descriptor */
.chStateAtCmplt = CY_PDMA_CH_DISABLED, /* Configure P-DMA descriptor */
.triginType = CY_PDMA_TRIGIN_DESCR, /* Configure P-DMA descriptor */
.dataSize = CY_PDMA_BYTE, /* Configure P-DMA descriptor */
.srcTxfrSize = 0ul, // same as "dataSize" /* Configure P-DMA descriptor */
.destTxfrSize = 1ul, // 32bit width /* Configure P-DMA descriptor */
.descrType = CY_PDMA_1D_TRANSFER, /* Configure P-DMA descriptor */
.srcAddr = (void *)g_uart_tx_buffer, /* Configure P-DMA descriptor */
.destAddr = (void *)&CY_USB_SCB_TYPE->unTX_FIFO_WR.u32Register, /* Configure P-DMA descriptor */
.srcXincr = 1ul, /* Configure P-DMA descriptor */
.destXincr = 0ul, /* Configure P-DMA descriptor */
.xCount = UART_TX_BUFFER_SIZE, /* Configure P-DMA descriptor */
.descrNext = NULL /* Configure P-DMA descriptor */
};
/**
* \var cy_stc_sysint_irq_t stc_sysint_irq_cfg
* \brief IRQ DMA configuration */
/* Configure interrupt */
static const cy_stc_sysint_irq_t stc_sysint_irq_cfg =
{
.sysIntSrc = DW_CH_INTR,
.intIdx = CPUIntIdx2_IRQn,
.isEnabled = true,
};
Code Listing 3 DW1_Ch_IntHandler()
void DW1_Ch_IntHandler(void)
{
uint32_t masked;
masked = Cy_PDMA_Chnl_GetInterruptStatusMasked(DW1, DW_CHANNEL); /* See code Listing 4. */
if ((masked & CY_PDMA_INTRCAUSE_COMPLETION) != 0ul)
{
/* Clear Complete DMA interrupt flag */
Cy_PDMA_Chnl_ClearInterrupt(DW1, DW_CHANNEL); /* See Code Listing 5. */
}
else
{
CY_ASSERT(false);
}
}
Code Listing 4 Cy_PDMA_Chnl_GetInterruptStatusMasked()
__STATIC_INLINE uint32_t Cy_PDMA_Chnl_GetInterruptStatusMasked(const volatile stc_DW_t *pstcPDMA, uint32_t chNum)
{
return (pstcPDMA->CH_STRUCT[chNum].unINTR_MASKED.u32Register);
Code Listing 5 Cy_PDMA_Chnl_ClearInterrupt()
void Cy_PDMA_Chnl_ClearInterrupt(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
{
pstcPDMA->CH_STRUCT[chNum].unINTR.u32Register = CY_PDMA_INTR_BIT_MASK;
/* Readback of the register is required by hardware. */
(void) pstcPDMA->CH_STRUCT[chNum].unINTR.u32Register;
}
Code Listing 6 Cy_PDMA_Disable()
void Cy_PDMA_Disable(volatile stc_DW_t *pstcPDMA)
{
pstcPDMA->unCTL.stcField.u1ENABLED = 0ul; /* Write to P-DMA_CTL_ENABLED bit */
}
Code Listing 7 Cy_PDMA_Chnl_DeInit()
void Cy_PDMA_Chnl_DeInit(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
/* Resets P-DMA to default value */
{
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unCH_IDX.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unCH_CURR_PTR.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unINTR_MASK.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unINTR_SET.u32Register = 0ul;
}
Code Listing 8 Cy_PDMA_Descr_Init()
cy_en_pdma_status_t Cy_PDMA_Descr_Init(cy_stc_pdma_descr_t* descriptor, const cy_stc_pdma_descr_config_t* config)
{
cy_en_pdma_status_t retVal = CY_PDMA_ERR_UNC;
if ((descriptor != NULL) && (config != NULL))
{
descriptor->unPDMA_DESCR_CTL.stcField.u2WAIT_FOR_DEACT = config->deact;
descriptor->unPDMA_DESCR_CTL.stcField.u2INTR_TYPE = config->intrType;
descriptor->unPDMA_DESCR_CTL.stcField.u2TR_OUT_TYPE = config->trigoutType;
descriptor->unPDMA_DESCR_CTL.stcField.u2TR_IN_TYPE = config->triginType;
descriptor->unPDMA_DESCR_CTL.stcField.u1SRC_TRANSFER_SIZE = config->srcTxfrSize;
descriptor->unPDMA_DESCR_CTL.stcField.u1DST_TRANSFER_SIZE = config->destTxfrSize;
descriptor->unPDMA_DESCR_CTL.stcField.u1CH_DISABLE = config->chStateAtCmplt;
descriptor->unPDMA_DESCR_CTL.stcField.u2DATA_SIZE = config->dataSize;
descriptor->unPDMA_DESCR_CTL.stcField.u2DESCR_TYPE = config->descrType;
descriptor->u32PDMA_DESCR_SRC = (uint32_t)config->srcAddr;
descriptor->u32PDMA_DESCR_DST = (uint32_t)config->destAddr;
switch(config->descrType)
{
case (uint32_t)CY_PDMA_SINGLE_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_PDMA_1D_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.stcField.u12SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u12DST_X_INCR = (uint32_t)config->destXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u8X_COUNT = (uint32_t)((config->xCount) - 1ul);
descriptor->unPDMA_DESCR_Y_CTL.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_PDMA_CRC_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.stcField.u12SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u12DST_X_INCR = 0ul;
descriptor->unPDMA_DESCR_X_CTL.stcField.u8X_COUNT = (uint32_t)((config->xCount) - 1ul);
descriptor->unPDMA_DESCR_Y_CTL.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_PDMA_2D_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.stcField.u12SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u12DST_X_INCR = (uint32_t)config->destXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u8X_COUNT = (uint32_t)((config->xCount) - 1ul);
descriptor->unPDMA_DESCR_Y_CTL.stcField.u12SRC_Y_INCR = (uint32_t)config->srcYincr;
descriptor->unPDMA_DESCR_Y_CTL.stcField.u12DST_Y_INCR = (uint32_t)config->destYincr;
descriptor->unPDMA_DESCR_Y_CTL.stcField.u8Y_COUNT = (uint32_t)((config->yCount) - 1ul);
descriptor->u32PDMA_DESCR_NEXT_PTR = (uint32_t)config->descrNext;
break;
}
default:
{
/* Unsupported type of descriptor */
break;
}
}
retVal = CY_PDMA_SUCCESS;
}
else
{
retVal = CY_PDMA_INVALID_INPUT_PARAMETERS;
}
return retVal;
}
Code Listing 9 Cy_PDMA_Chnl_Init()
cy_en_pdma_status_t Cy_PDMA_Chnl_Init(volatile stc_DW_t *pstcPDMA, uint32_t chNum, const cy_stc_pdma_chnl_config_t* chnlConfig)
{
cy_en_pdma_status_t retVal = CY_PDMA_ERR_UNC;
if ((pstcPDMA != NULL) && (chnlConfig != NULL))
{
/* Set current descriptor */
pstcPDMA->CH_STRUCT[chNum].unCH_CURR_PTR.u32Register = (uint32_t)chnlConfig->PDMA_Descriptor;
/* Set if the channel is preemtable */
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u1PREEMPTABLE = chnlConfig->preemptable;
/* Set channel priority */
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u2PRIO = chnlConfig->priority;
/* Set enabled status */
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u1ENABLED = chnlConfig->enable;
retVal = CY_PDMA_SUCCESS;
}
else
{
retVal = CY_PDMA_INVALID_INPUT_PARAMETERS;
}
return (retVal);
}
Code Listing 10 Cy_PDMA_Chnl_Enable()
__STATIC_INLINE void Cy_PDMA_Chnl_Enable(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
{
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u1ENABLED = 1ul;
}
Code Listing 11 Cy_PDMA_Chnl_SetInterruptMask()
__STATIC_INLINE void Cy_PDMA_Chnl_SetInterruptMask(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
{
pstcPDMA->CH_STRUCT[chNum].unINTR_MASK.u32Register = CY_PDMA_INTR_BIT_MASK;
}
Code Listing 12 Cy_PDMA_Enable()
void Cy_PDMA_Enable(volatile stc_DW_t *pstcPDMA)
{
pstcPDMA->unCTL.stcField.u1ENABLED = 1ul; // Write to P-DMA_CTL_ENABLED bit //
}
1D transfer (peripheral-to-memory)
Overview
This is an example of transferring input states of multiple ports to the memory (RAM) with a periodic trigger. A TCPWM is used for generating the periodic trigger. See the “Timer, Counter, and PWM” chapter of the architecture TRM for more details.
The port input state is stored in the memory with the periodic timing set in TCPWM. As a result, the CPU can know the port state at a specified time by reading the memory without the CPU having to access the port register. This is useful when storing the port state before transitioning to a low-power mode.
In this case, P-DMA transfers the GPIO_PRT_IN register data to RAM. The number of registers to be transferred is 23. (from Port 0 to Port 22). GPIO_PRT_IN registers exist at intervals of 0x80. P-DMA generates an interrupt after data is transferred from all registers. Figure 11 shows the data transfer.
Figure 11. Operation of 1D transfer (peripheral-to-memory)
(0) Configure P-DMA according to Initial configuration for P-DMA. In addition, configure the TCPWM and trigger multiplexer.
(1) The CPU starts the TCPWM timer.
(2) TCPWM outputs the trigger to P-DMA via the trigger multiplexer when it reaches the specified count value (overflow).
(3) P-DMA reads the descriptor from the specified area (Descriptor Pointer) when accepting the transfer.
(4) P-DMA reads the data from the source address (GPIO_PRT0_IN), and writes the read data to the destination address (RAM base address). After that, P-DMA increments the source address by 0x80 and the destination address by 0x04. Then, P-DMA reads the data from the source address (GPIO_PRT1_IN) and writes it to the destination address (RAM base address +0x04) again.
(5) P-DMA notifies the CPU with an interrupt when all transfers are completed.
(6) The CPU accepts the interrupt and reads the port states in the RAM.
When the TCPWM outputs the trigger again, steps (3) to (6) are repeated.
Initial configuration for P-DMA
This section describes the initialization of the P-DMA channel and descriptor of this use case.
Figure 12 shows the setting procedure for P-DMA.
Figure 12. Setting procedure for P-DMA
Configuration and example code
Table 9 lists the parameters and Table 10 lists the functions of the configuration part in SDL for DMA.
Table 9. List of DMA configuration parameters
Parameters | Description | Value |
---|---|---|
TCPWMx_GRPx_CNTx_COUNTER | Defines TCPWM using counter | TCPWM0_GRP0_CNT0 |
DW_CHANNEL | Defines P-DMA channel | 8ul |
TCPWM_TO_MUX_TRIG | Defines trigger TCPWM to multiplexer | TRIG_IN_MUX_3_TCPWM_16_TR_OUT00 |
MUX_TO_PDMA_TRIG | Defines trigger multiplexer to P-DMA | TRIG_OUT_MUX_3_PDMA0_TR_IN8 |
DW_CH_INTR | Defines P-DMA channel interrupt | cpuss_interrupts_dw0_8_IRQn |
DST_BUFFER_SIZE | Defines destination buffer size | 23ul |
.PDMA_Descriptor | P-DMA current descriptor pointer | &dwTcpwmDescr |
.preemptable | Channel preemptable | 0ul |
.priority | Channel priority | 0ul |
.enable | Channel enable | 1ul |
.deact | DESCR_CTL WAIT_FOR_DEACT | 0ul |
.intrType | DESCR_CTL INTR_TYPE | CY_PDMA_INTR_X_LOOP_CMPLT |
.trigoutType | DESCR_CTL TR_OUT_TYPE | CY_PDMA_TRIGOUT_X_LOOP_CMPLT |
.chStateAtCmplt | DESCR_CTL CH_DISABLE | CY_PDMA_CH_ENABLED |
.triginType | DESCR_CTL TR_IN_TYPE | CY_PDMA_TRIGIN_DESCR |
.dataSize | DESCR_CTL DATA_SIZE | CY_PDMA_WORD |
.srcTxfrSize | DESCR_CTL SRC_TRANSFER_SIZE | 0ul |
.destTxfrSize | DESCR_CTL DST_TRANSFER_SIZE | 0ul |
.descrType | DESCR_TYPE | CY_PDMA_1D_TRANSFER |
.srcAddr | DESCR_SRC | (void *)&GPIO_PRT0->unIN.u32Register |
.destAddr | DESCR_DST | (void *)g_DestBuffer |
.srcXincr | DESCR_X_CTL SRC_X_INCR | 32ul |
destXincr | DESCR_X_CTL DST_X_INCR | 1ul |
.xCount | DESCR_X_CTL X_COUNT | DST_BUFFER_SIZE |
.descrNext | DESCR_NEXT_PTR | &dwTcpwmDescr |
Table 10. List of DMA configuration functions
Functions | Description | Remarks |
---|---|---|
DW0_Ch_IntHandler() | Handler for P-DMA0 interrupts | See Code Listing 15 |
Counter_Handler() | Handler for TCPWM Counter interrupts | See Code Listing 18 |
Cy_SysInt_InitIRQ() | Configures interrupt | |
Cy_SysInt_SetSystemIrqVector() | Configures interrupt vector | |
NVIC_SetPriority() | NVIC set priority | |
NVIC_EnableIRQ() | NVIC enable interrupt | |
Cy_PDMA_Disable() | Configures P-DMA disable | Write to P-DMA_CTL_ENABLED bit. See Code Listing 19 |
Cy_PDMA_Chnl_DeInit() | Resets P-DMA to default values | Clears all the content of registers corresponding to the channel See Code Listing 20 |
Cy_PDMA_Descr_Init() | Configures P-DMA descriptor initialize | See Code Listing 21 |
Cy_PDMA_Chnl_Init() | Configures P-DMA channel initialize | See Code Listing 22 |
Cy_PDMA_Chnl_Enable() | Configures P-DMA channel enable | See Code Listing 23 |
Cy_PDMA_Chnl_SetInterruptMask() | Configures P-DMA channel interrupt mask | See Code Listing 24 |
Cy_PDMA_Enable() | Configures P-DMA enable | Write to DW_CTL_ENABLED bit See Code Listing 25 |
Cy_TrigMux_Connect() | Trigger multiplexer initialization | |
Cy_Tcpwm_TriggerStart() | TCPWM start | |
Cy_PDMA_Chnl_GetInterruptStatusMasked() | Returns logical and of corresponding INTR and INTR_MASK fields in a single load operation | See Code Listing 16 |
Cy_PDMA_Chnl_ClearInterrupt() | Configures P-DMA channel clears the interrupt status | See Code Listing 17 |
Cy_Tcpwm_Counter_ClearCC0_Intr() | Clear TCPWM CC0 interrupt flag |
Code Listing 13 demonstrates an example program to 1D transfer (peripheral-to- memory). See the architecture TRM and application note for GPIO, TCPWM and Clock configuration.
Code Listing 13 Example to 1D transfer (peripheral -to- memory)
#define TCPWMx_GRPx_CNTx_COUNTER TCPWM0_GRP0_CNT0 /* Write to P-DMA_CTL_ENABLED bit */
/* Define P-DMA channel
Define Trigger TCPWM to MUX
Define Trigger MUX to P-DMA
Define P-DMA channel interrupt
Define DST buffer size */
#define DW_CHANNEL 8ul
#define TCPWM_TO_MUX_TRIG TRIG_IN_MUX_3_TCPWM_16_TR_OUT00
#define MUX_TO_PDMA_TRIG TRIG_OUT_MUX_3_PDMA0_TR_IN8
#define DW_CH_INTR cpuss_interrupts_dw0_8_IRQn
#define DST_BUFFER_SIZE 23ul
void DW0_Ch_IntHandler(void); /* See Code Listing 15 */
void Counter_Handler(void); /* See Code Listing 18 */
int main(void)
{
:
/* (1) Disable P-DMA. See Code Listing 19.
(2) Resets P-DMA to default values. See Code Listing 20.
(3) Configures P-DMA descriptor initialize. See Code Listing 21.
(4) Enable P-DMA channel. See Code Listing 23.
(5) Enable P-DMA. See Code Listing 25. */
/* Initialize & Enable DMA */
Cy_PDMA_Disable(DW0);
Cy_PDMA_Chnl_DeInit(DW0, DW_CHANNEL);
Cy_PDMA_Descr_Init(&dwTcpwmDescr, &dw0ChTcpwmConfig);
Cy_PDMA_Chnl_Init(DW0, DW_CHANNEL, &dwTcpwmConfig);
Cy_PDMA_Chnl_Enable(DW0, DW_CHANNEL);
Cy_PDMA_Chnl_SetInterruptMask(DW0, DW_CHANNEL);
Cy_PDMA_Enable(DW0);
/* Trigger Multiplexer Initialization */
/* TCPWM To DW */
Cy_TrigMux_Connect(TCPWM_TO_MUX_TRIG, MUX_TO_PDMA_TRIG, CY_TR_MUX_TR_INV_DISABLE, TRIGGER_TYPE_LEVEL, 0ul);
/* Interrupt Initialization */
Cy_SysInt_InitIRQ(&stc_sysint_irq_cfg);
Cy_SysInt_SetSystemIrqVector(stc_sysint_irq_cfg.sysIntSrc, DW0_Ch_IntHandler); /* See Configures interrupt */
NVIC_SetPriority(stc_sysint_irq_cfg.intIdx, 0ul);
NVIC_EnableIRQ(stc_sysint_irq_cfg.intIdx);
/* TCPWM Start */
Cy_Tcpwm_TriggerStart(TCPWMx_GRPx_CNTx_COUNTER); /* See TCPWM start */
for(;;);
}
Code Listing 14 P-DMA Channel, descriptor configuration
/**
* \var cy_stc_pdma_descr_t dwTcpwmDescr
* \brief PDMA descriptor */
static cy_stc_pdma_descr_t dwTcpwmDescr; /* Variable for source address TX_buffer */
/**
* \var cy_stc_pdma_chnl_config_t dwTcpwmConfig
* \brief PDMA configuration */
/* Configure P-DMA channel */
const cy_stc_pdma_chnl_config_t dwTcpwmConfig =
{
.PDMA_Descriptor = &dwTcpwmDescr,
.preemptable = 0ul,
.priority = 0ul,
.enable = 1ul,
};
/**
* \var cy_stc_pdma_descr_config_t dw0ChTcpwmConfig
* \brief PDMA descriptor configuration */
static cy_stc_pdma_descr_config_t dw0ChTcpwmConfig =
/* Configure P-DMA descriptor */
{
.deact = 0ul,
.intrType = CY_PDMA_INTR_X_LOOP_CMPLT,
.trigoutType = CY_PDMA_TRIGOUT_X_LOOP_CMPLT,
.chStateAtCmplt = CY_PDMA_CH_ENABLED,
.triginType = CY_PDMA_TRIGIN_DESCR,
.dataSize = CY_PDMA_WORD,
.srcTxfrSize = 0ul, /* Same as dataSize */
.destTxfrSize = 0ul, /* Same as dataSize */
.descrType = CY_PDMA_1D_TRANSFER,
.srcAddr = (void *)&GPIO_PRT0->unIN.u32Register,
.destAddr = (void *)g_DestBuffer,
.srcXincr = 32ul, /* address +80h */
.destXincr = 1ul, /* address +04h */
.xCount = DST_BUFFER_SIZE,
.descrNext = &dwTcpwmDescr
};
/**
* \var cy_stc_sysint_irq_t stc_sysint_irq_cfg
* \brief IRQ DMA configuration */
/* Configure interrupt */
static const cy_stc_sysint_irq_t stc_sysint_irq_cfg =
{
.sysIntSrc = DW_CH_INTR,
.intIdx = CPUIntIdx2_IRQn,
.isEnabled = true,
};
Code Listing 15 DW0_Ch_IntHandler()
void DW0_Ch_IntHandler(void)
{
uint32_t masked;
masked = Cy_PDMA_Chnl_GetInterruptStatusMasked(DW0, DW_CHANNEL); /* See Code Listing 16. */
if ((masked & CY_PDMA_INTRCAUSE_COMPLETION) != 0ul)
{
/* Clear Complete DMA interrupt flag */
Cy_PDMA_Chnl_ClearInterrupt(DW0, DW_CHANNEL); /*See Code Listing 17.*/
/* Read the port status */
for(uint8_t portcnt = 0; portcnt < DST_BUFFER_SIZE; portcnt++)
{
g_portStatus[portcnt] = g_DestBuffer[portcnt];
}
}
else
{
CY_ASSERT(false);
}
}
Code Listing 16 Cy_PDMA_Chnl_GetInterruptStatusMasked()
__STATIC_INLINE uint32_t Cy_PDMA_Chnl_GetInterruptStatusMasked(const volatile stc_DW_t *pstcPDMA, uint32_t chNum)
{
return (pstcPDMA->CH_STRUCT[chNum].unINTR_MASKED.u32Register);
}
Code Listing 17 Cy_PDMA_Chnl_ClearInterrupt()
void Cy_PDMA_Chnl_ClearInterrupt(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
{
pstcPDMA->CH_STRUCT[chNum].unINTR.u32Register = CY_PDMA_INTR_BIT_MASK;
/* Readback of the register is required by hardware. */
(void) pstcPDMA->CH_STRUCT[chNum].unINTR.u32Register;
}
Code Listing 18 Counter_Handler()
void Counter_Handler(void)
{
if(Cy_Tcpwm_Counter_GetCC0_IntrMasked(TCPWMx_GRPx_CNTx_COUNTER))
{
/* Clear TCPWM CC0 interrupt flag Group#0 Counter#0 */
Cy_Tcpwm_Counter_ClearCC0_Intr(TCPWMx_GRPx_CNTx_COUNTER);
/* user program here.. */
}
}
Code Listing 19 Cy_PDMA_Disable()
void Cy_PDMA_Disable(volatile stc_DW_t *pstcPDMA)
{
pstcPDMA->unCTL.stcField.u1ENABLED = 0ul; /* Write to P-DMA_CTL_ENABLED bit */
}
Code Listing 20 Cy_PDMA_Chnl_DeInit()
void Cy_PDMA_Chnl_DeInit(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
/* Resets P-DMA to default value */
{
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unCH_IDX.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unCH_CURR_PTR.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unINTR_MASK.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unINTR_SET.u32Register = 0ul;
}
Code Listing 21 Cy_PDMA_Descr_Init()
cy_en_pdma_status_t Cy_PDMA_Descr_Init(cy_stc_pdma_descr_t* descriptor, const cy_stc_pdma_descr_config_t* config)
{
cy_en_pdma_status_t retVal = CY_PDMA_ERR_UNC;
if ((descriptor != NULL) && (config != NULL))
{
descriptor->unPDMA_DESCR_CTL.stcField.u2WAIT_FOR_DEACT = config->deact;
descriptor->unPDMA_DESCR_CTL.stcField.u2INTR_TYPE = config->intrType;
descriptor->unPDMA_DESCR_CTL.stcField.u2TR_OUT_TYPE = config->trigoutType;
descriptor->unPDMA_DESCR_CTL.stcField.u2TR_IN_TYPE = config->triginType;
descriptor->unPDMA_DESCR_CTL.stcField.u1SRC_TRANSFER_SIZE = config->srcTxfrSize;
descriptor->unPDMA_DESCR_CTL.stcField.u1DST_TRANSFER_SIZE = config->destTxfrSize;
descriptor->unPDMA_DESCR_CTL.stcField.u1CH_DISABLE = config->chStateAtCmplt;
descriptor->unPDMA_DESCR_CTL.stcField.u2DATA_SIZE = config->dataSize;
descriptor->unPDMA_DESCR_CTL.stcField.u2DESCR_TYPE = config->descrType;
descriptor->u32PDMA_DESCR_SRC = (uint32_t)config->srcAddr;
descriptor->u32PDMA_DESCR_DST = (uint32_t)config->destAddr;
switch(config->descrType)
{
case (uint32_t)CY_PDMA_SINGLE_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_PDMA_1D_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.stcField.u12SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u12DST_X_INCR = (uint32_t)config->destXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u8X_COUNT = (uint32_t)((config->xCount) - 1ul);
descriptor->unPDMA_DESCR_Y_CTL.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_PDMA_CRC_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.stcField.u12SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u12DST_X_INCR = 0ul;
descriptor->unPDMA_DESCR_X_CTL.stcField.u8X_COUNT = (uint32_t)((config->xCount) - 1ul);
descriptor->unPDMA_DESCR_Y_CTL.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_PDMA_2D_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.stcField.u12SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u12DST_X_INCR = (uint32_t)config->destXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u8X_COUNT = (uint32_t)((config->xCount) - 1ul);
descriptor->unPDMA_DESCR_Y_CTL.stcField.u12SRC_Y_INCR = (uint32_t)config->srcYincr;
descriptor->unPDMA_DESCR_Y_CTL.stcField.u12DST_Y_INCR = (uint32_t)config->destYincr;
descriptor->unPDMA_DESCR_Y_CTL.stcField.u8Y_COUNT = (uint32_t)((config->yCount) - 1ul);
descriptor->u32PDMA_DESCR_NEXT_PTR = (uint32_t)config->descrNext;
break;
}
default:
{
/* Unsupported type of descriptor */
break;
}
}
retVal = CY_PDMA_SUCCESS;
}
else
{
retVal = CY_PDMA_INVALID_INPUT_PARAMETERS;
}
return retVal;
}
Code Listing 22 Cy_PDMA_Chnl_Init()
cy_en_pdma_status_t Cy_PDMA_Chnl_Init(volatile stc_DW_t *pstcPDMA, uint32_t chNum, const cy_stc_pdma_chnl_config_t* chnlConfig)
{
cy_en_pdma_status_t retVal = CY_PDMA_ERR_UNC;
if ((pstcPDMA != NULL) && (chnlConfig != NULL))
{
/* Set current descriptor */
pstcPDMA->CH_STRUCT[chNum].unCH_CURR_PTR.u32Register = (uint32_t)chnlConfig->PDMA_Descriptor;
/* Set if the channel is preemtable */
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u1PREEMPTABLE = chnlConfig->preemptable;
/* Set channel priority */
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u2PRIO = chnlConfig->priority;
/* Set enabled status */
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u1ENABLED = chnlConfig->enable;
retVal = CY_PDMA_SUCCESS;
}
else
{
retVal = CY_PDMA_INVALID_INPUT_PARAMETERS;
}
return (retVal);
}
Code Listing 23 Cy_PDMA_Chnl_Enable()
__STATIC_INLINE void Cy_PDMA_Chnl_Enable(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
{
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u1ENABLED = 1ul;
}
Code Listing 24 Cy_PDMA_Chnl_SetInterruptMask()
__STATIC_INLINE void Cy_PDMA_Chnl_SetInterruptMask(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
{
pstcPDMA->CH_STRUCT[chNum].unINTR_MASK.u32Register = CY_PDMA_INTR_BIT_MASK;
}
Code Listing 25 Cy_PDMA_Enable()
void Cy_PDMA_Enable(volatile stc_DW_t *pstcPDMA)
{
pstcPDMA->unCTL.stcField.u1ENABLED = 1ul; /* Write to P-DMA_CTL_ENABLED bit */
}
Descriptor chaining
Overview
This is an example of descriptor chaining by storing the pointer of the next descriptor (DESCR_NEXT_PTR) in the current descriptor.
This example uses two descriptors: Descriptor 0 and Descriptor 1. Both descriptors are for a 1D transfer that transfers multiple port input states to the memory (RAM) with a periodic trigger from the TCPWM. However, Descriptor 0 has RAM base address 0 as the destination address, and Descriptor 1 has RAM base address 1 as the destination address.
P-DMA transfers multiple port input states to the memory (RAM) with a periodic trigger from the TCPWM. P-DMA notifies the interrupt to the CPU when the transfer is completed. The pointer to the next descriptor (DESCR_NEXT_PTR) in the descriptor (Descriptor 0) of this transfer is set to a pointer to another descriptor (Descriptor 1). As a result, P-DMA can start the Descriptor 1 transfer when Descriptor 0 transfer completes. Descriptor 0 and Descriptor 1 have different destination addresses.
P-DMA allows data of the same port address to be transferred to different RAM addresses. In other words, it can have a double buffer. In this case, Descriptor 0 and Descriptor 1 are chained with each other, and Descriptor 0 and Descriptor 1 have a circular list.
Figure 13 shows 1D transfer with descriptor chaining.
Figure 13. 1D transfer with descriptor chaining
(0) Configure P-DMA according to the usage example. In addition, configure the TCPWM and trigger multiplexer.
(1) The CPU starts the TCPWM timer.
(2) The TCPWM outputs the trigger to P-DMA via the trigger multiplexer when it reaches the specified count value (overflow).
(3) P-DMA reads the descriptor from the specified area (Descriptor Pointer 0) when activating the next pending transfer.
(4) P-DMA reads the data from the source address (GPIO_PRT0_IN), and writes the read data to the destination address (RAM base address 0). After that, P-DMA increments the source address by 0x80 and the destination address by 0x04. Then, P-DMA reads the data from the source address (GPIO_PRT1_IN) and writes it to the destination address (RAM base address 0 +0x04) again.
(5) P-DMA notifies the CPU with an interrupt when all transfers are completed.
(6) The TCPWM outputs the trigger to P-DMA when it reaches the specified count value (overflow) again.
(7) P-DMA reads the descriptor from the pointer defined by the next descriptor pointer in its own descriptor (Descriptor Pointer 1) when accepting the transfer.
(8) P-DMA reads the data from the source address (GPIO_PRT0_IN), and writes the read data to the destination address (RAM base address 1). After that, P-DMA increments the source address by 0x80 and the destination address by 0x04. Then, P-DMA reads the data from the source address (GPIO_PRT1_IN) and writes it to the destination address (RAM base address 1 +0x04) again.
(9) P-DMA notifies the CPU through an interrupt when all transfers are completed. Descriptor 1 chains to Descriptor 0. Therefore, when the TCPWM outputs the trigger again, steps from (3) are repeated.
Note: The TCPWM count period must always be longer than the time required by DMA to transfer all data.
Initial configuration
This section describes the initialization of the P-DMA channel and descriptor of this use case.
Figure 14 shows the setting procedure for P-DMA.
Figure 14. Setting procedure for P-DMA
Configuration and example code
Table 11 lists the parameters and Table 12 lists the functions of the configuration part in SDL for DMA.
Table 11. List of DMA configuration parameters
Parameters | Description | Value |
---|---|---|
TCPWMx_GRPx_CNTx_COUNTER | Defines TCPWM using counter | TCPWM0_GRP0_CNT0 |
DW_CHANNEL | Defines P-DMA channel | 8ul |
TCPWM_TO_MUX_TRIG | Defines trigger TCPWM to Multiplexer | TRIG_IN_MUX_3_TCPWM_16_TR_OUT00 |
MUX_TO_PDMA_TRIG | Defines trigger multiplexer to P-DMA | TRIG_OUT_MUX_3_PDMA0_TR_IN8 |
DW_CH_INTR | Defines P-DMA channel interrupt | cpuss_interrupts_dw0_8_IRQn |
DST_BUFFER_SIZE | Defines Destination buffer size | 23ul |
DST_BUFFER_NUMBER | Defines Destination buffer number | 2ul |
.PDMA_Descriptor | P-DMA current descriptor pointer | dwTcpwmDescr |
.preemptable | Channel preemptable | 0ul |
.priority | Channel priority | 0ul |
.enable | Channel enable | 1ul |
.deact | DESCR_CTL WAIT_FOR_DEACT | 0ul |
.intrType | DESCR_CTL INTR_TYPE | CY_PDMA_INTR_X_LOOP_CMPLT |
.trigoutType | DESCR_CTL TR_OUT_TYPE | CY_PDMA_TRIGOUT_X_LOOP_CMPLT |
.chStateAtCmplt | DESCR_CTL CH_DISABLE | CY_PDMA_CH_ENABLED |
.triginType | DESCR_CTL TR_IN_TYPE | CY_PDMA_TRIGIN_DESCR |
.dataSize | DESCR_CTL DATA_SIZE | CY_PDMA_WORD |
.srcTxfrSize | DESCR_CTL SRC_TRANSFER_SIZE | 0ul |
.destTxfrSize | DESCR_CTL DST_TRANSFER_SIZE | 0ul |
.descrType | DESCR_CTL DESCR_TYPE | CY_PDMA_1D_TRANSFER |
.srcAddr | DESCR_SRC | (void *)&GPIO_PRT0->unIN.u32Register |
.destAddr | DESCR_DST | (void *)g_DestBuffer0 .srcXincr |
.srcXincr | DESCR_X_CTL SRC_X_INCR | 32ul |
.destXincr | DESCR_X_CTL DST_X_INCR | 1ul |
.xCount | DESCR_X_CTL X_COUNT | DST_BUFFER_SIZE |
.descrNext | DESCR_NEXT_PTR | NULL |
Table 12. List of DMA configuration functions
Functions | Description | Remarks |
---|---|---|
DW0_Ch_IntHandler() | Handler for P-DMA0 interrupts | See Code Listing 28 |
Counter_Handler() | Handler for TCPWM counter interrupts | |
Cy_SysInt_InitIRQ() | Configures interrupt | |
Cy_SysInt_SetSystemIrqVector() | Configures Interrupt vector | |
NVIC_SetPriority() | NVIC set priority | |
NVIC_EnableIRQ() | NVIC enable interrupt | |
Cy_PDMA_Disable() | Configures P-DMA disable | Write to P-DMA_CTL_ENABLED bit. See Code Listing 32 |
Cy_PDMA_Chnl_DeInit() | Resets P-DMA to default values | Clears all the content of registers corresponding to the channel. See Code Listing 33 |
Cy_PDMA_Descr_Init() | Configures P-DMA descriptor initialize | See Code Listing 34 |
Cy_PDMA_Chnl_Init() | Configures P-DMA channel initialize | See Code Listing 35 |
Cy_PDMA_Chnl_Enable() | Configures P-DMA channel enable | See Code Listing 36 |
Cy_PDMA_Chnl_SetInterruptMask() | Configures P-DMA channel interrupt mask | See Code Listing 37 |
Cy_PDMA_Enable() | Configures P-DMA enable | Write to P-DMA_CTL_ENABLED bit. See Code Listing 38 |
Cy_TrigMux_Connect() | Trigger Multiplexer Initialization | |
Cy_Tcpwm_TriggerStart() | TCPWM Start | -- |
CyPDMA_Chnl GetInterruptStatusMasked() | Returns logical and of corresponding INTR and INTR_MASK fields in a single load operation | See Code Listing 29 |
Cy_PDMA_Chnl_ClearInterrupt() | Configures P-DMA channel clears the interrupt status | See Code Listing 30 |
Cy_Tcpwm_Counter_ClearCC0_Intr() | Clear TCPWM CC0 interrupt flag |
Code Listing 26 demonstrates an example program to Descriptor Chaining. See the architecture TRM and application note for GPIO, TCPWM, and Clock configuration.
Code Listing 26 Example to descriptor chaining
#define TCPWMx_GRPx_CNTx_COUNTER TCPWM0_GRP0_CNT0 /*Define TCPWM using counter*/
#define DW_CHANNEL 8ul
#define TCPWM_TO_MUX_TRIG TRIG_IN_MUX_3_TCPWM_16_TR_OUT00
/* Define P-DMA channel, Trigger, P-DMA channel interrupt */
#define MUX_TO_PDMA_TRIG TRIG_OUT_MUX_3_PDMA0_TR_IN8
#define DW_CH_INTR cpuss_interrupts_dw0_8_IRQn
/* Define DST buffer size, DST buffer number */
#define DST_BUFFER_SIZE 23ul
#define DST_BUFFER_NUMBER 2ul
void DW0_Ch_IntHandler(void); /* See Code Listing 28 */
void Counter_Handler(void); /* See Code Listing 31 */
int main(void)
{
:
/* Initialize & Enable DMA */
Cy_PDMA_Disable(DW0);
/* (1) Disable P-DMA. See Code Listing 32.
(2) Resets P-DMA to default values. See Code Listing 33. */
Cy_PDMA_Chnl_DeInit(DW0, DW_CHANNEL);
for(uint32_t i = 0ul; i < DST_BUFFER_NUMBER; i++)
{
if((i + 1ul) == DST_BUFFER_NUMBER)
{
/* Last descriptor */
/* (4) Configures P-DMA descriptor 1. See Code Listing 34. */
dw0ChTcpwmConfig.chStateAtCmplt = CY_PDMA_CH_ENABLED;
dw0ChTcpwmConfig.destAddr = &g_DestBuffer1[0];
dw0ChTcpwmConfig.descrNext = &dwTcpwmDescr[i - (DST_BUFFER_NUMBER-1)];
}
else
{
/* (3) Configures P-DMA descriptor 0. See Code Listing 34. */
dw0ChTcpwmConfig.chStateAtCmplt = CY_PDMA_CH_ENABLED;
dw0ChTcpwmConfig.destAddr = &g_DestBuffer0[0];
dw0ChTcpwmConfig.descrNext = &dwTcpwmDescr[i + 1ul];
}
Cy_PDMA_Descr_Init(&dwTcpwmDescr[i], &dw0ChTcpwmConfig);
}
Cy_PDMA_Chnl_Init(DW0, DW_CHANNEL, &dwTcpwmConfig);
Cy_PDMA_Chnl_Enable(DW0, DW_CHANNEL);
/* (5) Enable P-DMA channel. See Code Listing 36. (6) Enable P-DMA. Code Listing 38. */
Cy_PDMA_Chnl_SetInterruptMask(DW0, DW_CHANNEL);
Cy_PDMA_Enable(DW0);
/* Trigger Multiplexer Initialization */
/* TCPWM To DW */
Cy_TrigMux_Connect(TCPWM_TO_MUX_TRIG, MUX_TO_PDMA_TRIG, CY_TR_MUX_TR_INV_DISABLE, TRIGGER_TYPE_LEVEL, 0ul);
/* Interrupt Initialization */
Cy_SysInt_InitIRQ(&stc_sysint_irq_cfg);
/* Configures Interrupt */
Cy_SysInt_SetSystemIrqVector(stc_sysint_irq_cfg.sysIntSrc, DW0_Ch_IntHandler);
NVIC_SetPriority(stc_sysint_irq_cfg.intIdx, 0ul);
NVIC_EnableIRQ(stc_sysint_irq_cfg.intIdx);
/* TCPWM Start */
Cy_Tcpwm_TriggerStart(TCPWMx_GRPx_CNTx_COUNTER); /* TCPWM start */
for(;;);
}
Code Listing 27 P-DMA Channel, descriptor configuration
/**
* \var cy_stc_pdma_descr_t dwTcpwmDescr
* \brief PDMA descriptor
*/
static cy_stc_pdma_descr_t dwTcpwmDescr[DST_BUFFER_NUMBER];
/**
* \var cy_stc_pdma_chnl_config_t dwTcpwmConfig
* \brief PDMA configuration */
/* Configure P-DMA channel */
const cy_stc_pdma_chnl_config_t dwTcpwmConfig =
{
.PDMA_Descriptor = dwTcpwmDescr,
.preemptable = 0ul,
.priority = 0ul,
.enable = 1ul,
};
/**
* \var cy_stc_pdma_descr_config_t dw0ChTcpwmConfig
* \brief PDMA descriptor configuration */
static cy_stc_pdma_descr_config_t dw0ChTcpwmConfig =
/* Configure P-DMA descriptor */
{
.deact = 0ul,
.intrType = CY_PDMA_INTR_X_LOOP_CMPLT,
.trigoutType = CY_PDMA_TRIGOUT_X_LOOP_CMPLT,
.chStateAtCmplt = CY_PDMA_CH_ENABLED,
.triginType = CY_PDMA_TRIGIN_DESCR,
.dataSize = CY_PDMA_WORD,
.srcTxfrSize = 0ul, /* Same as dataSize */
.destTxfrSize = 0ul, /* Same as dataSize */
.descrType = CY_PDMA_1D_TRANSFER,
.srcAddr = (void *)&GPIO_PRT0->unIN.u32Register,
.destAddr = (void *)g_DestBuffer0,
.srcXincr = 32ul, /* address +80h */
.destXincr = 1ul, /* address +04h */
.xCount = DST_BUFFER_SIZE,
.descrNext = NULL /* will be updated in run time */
};
/**
* \var cy_stc_sysint_irq_t stc_sysint_irq_cfg
* \brief IRQ DMA configuration */
static const cy_stc_sysint_irq_t stc_sysint_irq_cfg =
/* Configure Interrupt */
{
.sysIntSrc = DW_CH_INTR,
.intIdx = CPUIntIdx2_IRQn,
.isEnabled = true,
};
Code Listing 28 DW0_Ch_IntHandler()
void DW0_Ch_IntHandler(void)
{
uint32_t masked;
masked = Cy_PDMA_Chnl_GetInterruptStatusMasked(DW0, DW_CHANNEL); /*See Code Listing 29.*/
if ((masked & CY_PDMA_INTRCAUSE_COMPLETION) != 0ul)
{
/* Clear Complete DMA interrupt flag */
Cy_PDMA_Chnl_ClearInterrupt(DW0, DW_CHANNEL); /* See Code Listing 30. */
/* Read the port status */
for(uint8_t portcnt = 0; portcnt < DST_BUFFER_SIZE; portcnt++)
{
g_portStatus[portcnt] = g_DestBuffer[portcnt];
}
}
else
{
CY_ASSERT(false);
}
}
Code Listing 29 Cy_PDMA_Chnl_GetInterruptStatusMasked()
__STATIC_INLINE uint32_t Cy_PDMA_Chnl_GetInterruptStatusMasked(const volatile stc_DW_t *pstcPDMA, uint32_t chNum)
{
return (pstcPDMA->CH_STRUCT[chNum].unINTR_MASKED.u32Register);
}
Code Listing 30 Cy_PDMA_Chnl_ClearInterrupt()
void Cy_PDMA_Chnl_ClearInterrupt(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
{
pstcPDMA->CH_STRUCT[chNum].unINTR.u32Register = CY_PDMA_INTR_BIT_MASK;
/* Readback of the register is required by hardware. */
(void) pstcPDMA->CH_STRUCT[chNum].unINTR.u32Register;
}
Code Listing 31 Counter_Handler()
void Counter_Handler(void)
{
if(Cy_Tcpwm_Counter_GetCC0_IntrMasked(TCPWMx_GRPx_CNTx_COUNTER))
{
/* Clear TCPWM CC0 interrupt flag Group#0 Counter#0 */
Cy_Tcpwm_Counter_ClearCC0_Intr(TCPWMx_GRPx_CNTx_COUNTER);
/* user program here.. */
}
}
Code Listing 32 Cy_PDMA_Disable()
void Cy_PDMA_Disable(volatile stc_DW_t *pstcPDMA)
{
pstcPDMA->unCTL.stcField.u1ENABLED = 0ul; /* Write to P-DMA_CTL_ENABLED bit */
}
Code Listing 33 Cy_PDMA_Chnl_DeInit()
void Cy_PDMA_Chnl_DeInit(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
/* Resets PDMA to default value */
{
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unCH_IDX.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unCH_CURR_PTR.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unINTR_MASK.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unINTR_SET.u32Register = 0ul;
Code Listing 34 Cy_PDMA_Descr_Init()
cy_en_pdma_status_t Cy_PDMA_Descr_Init(cy_stc_pdma_descr_t* descriptor, const cy_stc_pdma_descr_config_t* config)
{
cy_en_pdma_status_t retVal = CY_PDMA_ERR_UNC;
if ((descriptor != NULL) && (config != NULL))
{
descriptor->unPDMA_DESCR_CTL.stcField.u2WAIT_FOR_DEACT = config->deact;
descriptor->unPDMA_DESCR_CTL.stcField.u2INTR_TYPE = config->intrType;
descriptor->unPDMA_DESCR_CTL.stcField.u2TR_OUT_TYPE = config->trigoutType;
descriptor->unPDMA_DESCR_CTL.stcField.u2TR_IN_TYPE = config->triginType;
descriptor->unPDMA_DESCR_CTL.stcField.u1SRC_TRANSFER_SIZE = config->srcTxfrSize;
descriptor->unPDMA_DESCR_CTL.stcField.u1DST_TRANSFER_SIZE = config->destTxfrSize;
descriptor->unPDMA_DESCR_CTL.stcField.u1CH_DISABLE = config->chStateAtCmplt;
descriptor->unPDMA_DESCR_CTL.stcField.u2DATA_SIZE = config->dataSize;
descriptor->unPDMA_DESCR_CTL.stcField.u2DESCR_TYPE = config->descrType;
descriptor->u32PDMA_DESCR_SRC = (uint32_t)config->srcAddr;
descriptor->u32PDMA_DESCR_DST = (uint32_t)config->destAddr;
switch(config->descrType)
{
case (uint32_t)CY_PDMA_SINGLE_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_PDMA_1D_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.stcField.u12SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u12DST_X_INCR = (uint32_t)config->destXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u8X_COUNT = (uint32_t)((config->xCount) - 1ul);
descriptor->unPDMA_DESCR_Y_CTL.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_PDMA_CRC_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.stcField.u12SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u12DST_X_INCR = 0ul;
descriptor->unPDMA_DESCR_X_CTL.stcField.u8X_COUNT = (uint32_t)((config->xCount) - 1ul);
descriptor->unPDMA_DESCR_Y_CTL.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_PDMA_2D_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.stcField.u12SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u12DST_X_INCR = (uint32_t)config->destXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u8X_COUNT = (uint32_t)((config->xCount) - 1ul);
descriptor->unPDMA_DESCR_Y_CTL.stcField.u12SRC_Y_INCR = (uint32_t)config->srcYincr;
descriptor->unPDMA_DESCR_Y_CTL.stcField.u12DST_Y_INCR = (uint32_t)config->destYincr;
descriptor->unPDMA_DESCR_Y_CTL.stcField.u8Y_COUNT = (uint32_t)((config->yCount) - 1ul);
descriptor->u32PDMA_DESCR_NEXT_PTR = (uint32_t)config->descrNext;
break;
}
default:
{
/* Unsupported type of descriptor */
break;
}
}
retVal = CY_PDMA_SUCCESS;
}
else
{
retVal = CY_PDMA_INVALID_INPUT_PARAMETERS;
}
return retVal;
}
Code Listing 35 Cy_PDMA_Chnl_Init()
cy_en_pdma_status_t Cy_PDMA_Chnl_Init(volatile stc_DW_t *pstcPDMA, uint32_t chNum, const cy_stc_pdma_chnl_config_t* chnlConfig)
{
cy_en_pdma_status_t retVal = CY_PDMA_ERR_UNC;
if ((pstcPDMA != NULL) && (chnlConfig != NULL))
{
/* Set current descriptor */
pstcPDMA->CH_STRUCT[chNum].unCH_CURR_PTR.u32Register = (uint32_t)chnlConfig->PDMA_Descriptor;
/* Set if the channel is preemtable */
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u1PREEMPTABLE = chnlConfig->preemptable;
/* Set channel priority */
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u2PRIO = chnlConfig->priority;
/* Set enabled status */
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u1ENABLED = chnlConfig->enable;
retVal = CY_PDMA_SUCCESS;
}
else
{
retVal = CY_PDMA_INVALID_INPUT_PARAMETERS;
}
return (retVal);
}
Code Listing 36 Cy_PDMA_Chnl_Enable()
__STATIC_INLINE void Cy_PDMA_Chnl_Enable(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
{
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u1ENABLED = 1ul;
}
Code Listing 37 Cy_PDMA_Chnl_SetInterruptMask()
__STATIC_INLINE void Cy_PDMA_Chnl_SetInterruptMask(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
{
pstcPDMA->CH_STRUCT[chNum].unINTR_MASK.u32Register = CY_PDMA_INTR_BIT_MASK;
}
Code Listing 38 Cy_PDMA_Enable()
void Cy_PDMA_Enable(volatile stc_DW_t *pstcPDMA)
{
pstcPDMA->unCTL.stcField.u1ENABLED = 1ul; /* Write to P-DMA_CTL_ENABLED bit */
}
2D transfer (peripheral-to-memory)
Overview
This example shows how the result of an ADC group conversion is stored to the memory. See the “SAR ADC” chapter of the architecture TRM for more details.
The conversion result is grouped for each channel and stored in the memory. In this example, the ADC converts three channels CH_0, CH_1, and CH_2 by group conversion at a specified period. P-DMA stores the three group conversion results in the memory for each channel with the ADC conversion completion trigger.
Figure 15 shows how 2D transfer works.
Figure 15. 2D transfer (peripheral-to-memory)
(0) Configure P-DMA according to the usage example. In addition, configure the ADC and trigger multiplexer.
(1) The CPU starts ADC group conversion.
(2) The ADC outputs the trigger to P-DMA via the trigger multiplexer when group conversion is completed.
(3) P-DMA reads the descriptor from the specified area (Descriptor Pointer) when accepting the transfer.
(4) P-DMA reads the data from the source address (CH_0_RESULT), and writes the read data to the destination address (RAM base address).
(5) P-DMA increments the source address by 0x40 and the destination address by 0x20. Then, P-DMA reads the data from the source address (CH_1_RESULT) and writes it to the destination address (RAM base address 0 +0x20).
(6) P-DMA increments the source address by 0x40 and the destination address by 0x20. Then, P-DMA reads the data from the source address (CH_2_RESULT) and writes it to the destination address (RAM base address 0 +0x40). When the next trigger occurs, P-DMA increments the RAM base address by 0x04 and repeats from (4).
(7) P-DMA notifies the CPU with an interrupt after transferring CH_ 2 conversion result 2.
In this case, three triggers are required for completing the descriptor.
Initial configuration
This section describes the initialization of the P-DMA channel and descriptor of this use case.
Figure 16 shows the setting procedure for P-DMA.
Figure 16. Setting procedure for P-DMA
Configuration and example code
Table 13 lists the parameters and Table 14 lists the functions of the configuration part in SDL for DMA.
Table 13. List of DMA configuration parameters
Parameters | Description | Value |
---|---|---|
ADC_MACRO | Defines ADC macro | PASS0_SAR0 |
ADC_GROUP_NUMBER_OF_CHANNELS | Defines ADC group number | 3ul |
ADC_LOGICAL_CHANNEL | Defines ADC logical channel | 0ul |
ADC_GROUP_FIRST_CHANNEL | Defines ADC group first channel | ADC_LOGICAL_CHANNEL |
ADC_GROUP_LAST_CHANNEL | Defines ADC group last channel | (ADC_GROUP_FIRST_CHANNEL + ADC_GROUP_NUMBER_OF_CHANNELS - 1ul) |
ADC_CH_INTR_BASE | Defines ADC channel interrupt | pass_0_interrupts_sar_0_IRQn |
BUFFER_SIZE_IN_WORD | Defines buffer size | 25ul |
BUFFER_SIZE_IN_BYTE | Defines buffer size | (BUFFER_SIZE_IN_WORD * 4ul) |
DW_CHANNEL | Defines P-DMA channel | 27ul |
DW_CH_INTR | Defines P-DMA channel interrupt | cpuss_interrupts_dw0_27_IRQn |
ADC_TO_DMA_TRIG | Defines trigger ADC to DMA | TRIG_OUT_1TO1_2_PASS_CH_DONE_TO_PDMA02 |
.PDMA_Descriptor | P-DMA current descriptor pointer | & |
.preemptable | Channel preemptable | 0ul |
.priority | Channel priority | 0ul |
.enable | Channel enable | 1ul |
.deact | DESCR_CTL WAIT_FOR_DEACT | 0ul |
.intrType | DESCR_CTL INTR_TYPE | CY_PDMA_INTR_DESCR_CMPLT |
.trigoutType | DESCR_CTL TR_OUT_TYPE | CY_PDMA_TRIGOUT_DESCR_CMPLT |
.chStateAtCmplt | DESCR_CTL CH_DISABLE | CY_PDMA_CH_ENABLED |
.triginType | DESCR_CTL TR_IN_TYPE | CY_PDMA_TRIGIN_XLOOP |
.dataSize | DESCR_CTL DATA_SIZE | CY_PDMA_WORD |
.srcTxfrSize | DESCR_CTL SRC_TRANSFER_SIZE | 0ul, /_ as specified in DATA_SIZE _/ |
.destTxfrSize | DESCR_CTL DST_TRANSFER_SIZE | 0ul, /_ as specified in DATA_SIZE _/ |
.descrType | DESCR_CTL DESCR_TYPE | CY_PDMA_2D_TRANSFER |
.srcAddr | DESCR_SRC | (void *)&ADC_MACRO->CH[ADC_GROUP_FIRST_CHANNEL].unRESULT.u32Register |
.destAddr | DESCR_DST | (void *)g_DestBuffer |
.srcXincr | DESCR_X_CTL SRC_X_INCR | 16ul |
.destXincr | DESCR_X_CTL DST_X_INCR | 8ul |
.xCount | DESCR_X_CTL X_COUNT | ADC_GROUP_NUMBER_OF_CHANNELS |
.srcYincr | DESCR_Y_CTL SRC_Y_INCR | 0ul |
.destYincr | DESCR_Y_CTL DST_Y_INCR | 1ul |
.yCount | DESCR_Y_CTL Y_COUNT | 3ul |
.descrNext | DESCR_NEXT_PTR | &stcDescr |
Table 14. List of DMA configuration functions
Functions | Description | Remarks |
---|---|---|
DW0_Ch_IntHandler() | Handler for P-DMA0 interrupts | See Code Listing 41 |
Cy_SysInt_InitIRQ() | Configures interrupt | |
Cy_SysInt_SetSystemIrqVector() | Configures interrupt vector | |
NVIC_SetPriority() | NVIC set priority | |
NVIC_EnableIRQ() | NVIC enable interrupt | |
Cy_PDMA_Disable() | Configures P-DMA disable | Write to P-DMA_CTL_ENABLED bit. See Code Listing 44 |
Cy_PDMA_Chnl_DeInit() | Resets P-DMA to default values | See Code Listing 45 |
Cy_PDMA_Descr_Init() | Configures P-DMA descriptor initialize | See Code Listing 46 |
Cy_PDMA_Chnl_Init() | Configures P-DMA channel initialize | See Code Listing 47 |
Cy_PDMA_Chnl_Enable() | Configures P-DMA channel enable | See Code Listing 48 |
Cy_PDMA_Chnl_SetInterruptMask() | Configures P-DMA channel interrupt mask | See Code Listing 49 |
Cy_PDMA_Enable() | Configures P-DMA enable | Write to P-DMA_CTL_ENABLED bit. See Code Listing 50 |
Cy_TrigMux_Connect1To1() | Trigger multiplexer initialization | |
Cy_PDMA_Chnl_GetInterruptStatusMasked() | Returns logical and of corresponding INTR and INTR_MASK fields in a single load operation | See Code Listing 42 |
Cy_PDMA_Chnl_ClearInterrupt() | Configures P-DMA channel clears the interrupt status | See Code Listing 43 |
Cy_Adc_Channel_SoftwareTrigger() | ADC software start trigger |
Code Listing 39 demonstrates an example program to 2D transfer (peripheral-to- memory). See the architecture TRM and application note for GPIO, ADC and Clock configuration.
Code Listing 39 Example to 2D transfer (Peripheral-to-Memory)
#define ADC_MACRO PASS0_SAR0
#define ADC_GROUP_NUMBER_OF_CHANNELS (3ul) /* Define ADC macro, ADC group number */
/* ADC logical channel to be used */
#define ADC_LOGICAL_CHANNEL 0ul
/* Define ADC logical channel, ADC group first channel, ADC group last channel, ADC channel interrupt */
#define ADC_GROUP_FIRST_CHANNEL ADC_LOGICAL_CHANNEL
#define ADC_GROUP_LAST_CHANNEL (ADC_GROUP_FIRST_CHANNEL + ADC_GROUP_NUMBER_OF_CHANNELS - 1ul)
#define ADC_CH_INTR_BASE pass_0_interrupts_sar_0_IRQn
#define BUFFER_SIZE_IN_WORD 25ul
/* Define buffer size, P-DMA channel, P-DMA channel interrupt, Trigger */
#define BUFFER_SIZE_IN_BYTE (BUFFER_SIZE_IN_WORD * 4ul)
#define DW_CHANNEL 27ul
#define DW_CH_INTR cpuss_interrupts_dw0_27_IRQn
#define ADC_TO_DMA_TRIG TRIG_OUT_1TO1_2_PASS_CH_DONE_TO_PDMA02
void DW0_Ch_IntHandler(void); /* See Code Listing 41. */
int main(void)
{
:
/* (1) Disable P-DMA. See Code Listing 44.
(2) Resets P-DMA to default values. See Code Listing 45.
(3) Configures P-DMA descriptor initialize. See Code Listing 46.
(4) Enable P-DMA channel. See Code Listing 47.
(5) Enable P-DMA. See Code Listing 50. */
/* Initialize & Enable DW */
Cy_PDMA_Disable(DW0);
Cy_PDMA_Chnl_DeInit(DW0, DW_CHANNEL);
Cy_PDMA_Descr_Init(&stcDescr,&stcDmaDescrConfig);
Cy_PDMA_Chnl_Init(DW0, DW_CHANNEL, &chnlConfig);
Cy_PDMA_Chnl_Enable(DW0, DW_CHANNEL);
Cy_PDMA_Chnl_SetInterruptMask(DW0, DW_CHANNEL);
Cy_PDMA_Enable(DW0);
/* Trigger MUX */
Cy_TrigMux_Connect1To1( ADC_TO_DMA_TRIG,
CY_TR_MUX_TR_INV_DISABLE,
TRIGGER_TYPE_EDGE,
0ul);
/* Interrupt Initialization */
Cy_SysInt_InitIRQ(&stc_sysint_irq_cfg);
Cy_SysInt_SetSystemIrqVector(stc_sysint_irq_cfg.sysIntSrc, DW0_Ch_IntHandler);
/* Configures interrupt */
NVIC_SetPriority(stc_sysint_irq_cfg.intIdx, 0ul);
NVIC_EnableIRQ(stc_sysint_irq_cfg.intIdx);
/* Issue SW trigger */
/* Generates a software trigger */
Cy_Adc_Channel_SoftwareTrigger(&ADC_MACRO->CH[ADC_GROUP_FIRST_CHANNEL]);
for(;;);
}
Code Listing 40 P-DMA Channel, Descriptor configuration
/**
* \var uint32_t g_DestBuffer
* \brief DMA Destination buffer
*/
static uint32_t g_DestBuffer[BUFFER_SIZE_IN_BYTE] = {0ul};
/**
* \var cy_stc_pdma_descr_t stcDescr
* \brief PDMA descriptor
*/
static cy_stc_pdma_descr_t stcDescr;
/**
* \var cy_stc_pdma_chnl_config_t chnlConfig
* \brief PDMA configuration
*/
static const cy_stc_pdma_chnl_config_t chnlConfig =
/* Configure P-DMA channel */
{
.PDMA_Descriptor = &stcDescr,
.preemptable = 0ul,
.priority = 0ul,
.enable = 1ul,
};
/**
* \var cy_stc_pdma_descr_config_t stcDmaDescrConfig
* \brief PDMA descriptor configuration
*/
static const cy_stc_pdma_descr_config_t stcDmaDescrConfig =
/* Configure P-DMA descriptor */
{
.deact = 0ul,
.intrType = CY_PDMA_INTR_DESCR_CMPLT,
.trigoutType = CY_PDMA_TRIGOUT_DESCR_CMPLT,
.chStateAtCmplt = CY_PDMA_CH_ENABLED,
.triginType = CY_PDMA_TRIGIN_XLOOP,
.dataSize = CY_PDMA_WORD,
.srcTxfrSize = 0ul, /* as specified in DATA_SIZE */
.destTxfrSize = 0ul, /* as specified in DATA_SIZE */
.descrType = CY_PDMA_2D_TRANSFER,
.srcAddr = (void *)&ADC_MACRO->CH[ADC_GROUP_FIRST_CHANNEL].unRESULT.u32Register,
.destAddr = (void *)g_DestBuffer,
.srcXincr = 16ul, /* address +40h */
.destXincr = 8ul, /* address +20h */
.xCount = ADC_GROUP_NUMBER_OF_CHANNELS,
.srcYincr = 0ul, /* Not increments */
.destYincr = 1ul, /* Destination address +4h */
.yCount = 3ul, /* Store results for three times */
.descrNext = &stcDescr
};
/**
* \var cy_stc_sysint_irq_t stc_sysint_irq_cfg
* \brief IRQ DMA configuration
*/
static const cy_stc_sysint_irq_t stc_sysint_irq_cfg =
/* Configure interrupt */
{
.sysIntSrc = DW_CH_INTR,
.intIdx = CPUIntIdx2_IRQn,
.isEnabled = true,
};
Code Listing 41 DW0_Ch_IntHandler()
void DW0_Ch_IntHandler(void)
{
uint32_t masked;
masked = Cy_PDMA_Chnl_GetInterruptStatusMasked(DW0, DW_CHANNEL); /* See Code Listing 42. */
if ((masked & CY_PDMA_INTRCAUSE_COMPLETION) != 0ul)
{
/* Clear Complete DMA interrupt flag */
Cy_PDMA_Chnl_ClearInterrupt(DW0, DW_CHANNEL); /*See Code Listing 43.*/
/* Read the port status */
for(uint8_t portcnt = 0; portcnt < DST_BUFFER_SIZE; portcnt++)
{
g_portStatus[portcnt] = g_DestBuffer[portcnt];
}
}
else
{
CY_ASSERT(false);
}
}
Code Listing 42 Cy_PDMA_Chnl_GetInterruptStatusMasked()
__STATIC_INLINE uint32_t Cy_PDMA_Chnl_GetInterruptStatusMasked(const volatile stc_DW_t *pstcPDMA, uint32_t chNum)
{
return (pstcPDMA->CH_STRUCT[chNum].unINTR_MASKED.u32Register);
}
Code Listing 43 Cy_PDMA_Chnl_ClearInterrupt()
void Cy_PDMA_Chnl_ClearInterrupt(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
{
pstcPDMA->CH_STRUCT[chNum].unINTR.u32Register = CY_PDMA_INTR_BIT_MASK;
/* Readback of the register is required by hardware. */
(void) pstcPDMA->CH_STRUCT[chNum].unINTR.u32Register;
}
Code Listing 44 Cy_PDMA_Disable()
void Cy_PDMA_Disable(volatile stc_DW_t *pstcPDMA)
{
pstcPDMA->unCTL.stcField.u1ENABLED = 0ul; /* Write to P-DMA_CTL_ENABLED bit */
}
Code Listing 45 Cy_PDMA_Chnl_DeInit()
void Cy_PDMA_Chnl_DeInit(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
/* Resets P-DMA to default value */
{
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unCH_IDX.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unCH_CURR_PTR.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unINTR_MASK.u32Register = 0ul;
pstcPDMA->CH_STRUCT[chNum].unINTR_SET.u32Register = 0ul;
}
Code Listing 46 Cy_PDMA_Descr_Init()
cy_en_pdma_status_t Cy_PDMA_Descr_Init(cy_stc_pdma_descr_t* descriptor, const cy_stc_pdma_descr_config_t* config)
{
cy_en_pdma_status_t retVal = CY_PDMA_ERR_UNC;
if ((descriptor != NULL) && (config != NULL))
{
descriptor->unPDMA_DESCR_CTL.stcField.u2WAIT_FOR_DEACT = config->deact;
descriptor->unPDMA_DESCR_CTL.stcField.u2INTR_TYPE = config->intrType;
descriptor->unPDMA_DESCR_CTL.stcField.u2TR_OUT_TYPE = config->trigoutType;
descriptor->unPDMA_DESCR_CTL.stcField.u2TR_IN_TYPE = config->triginType;
descriptor->unPDMA_DESCR_CTL.stcField.u1SRC_TRANSFER_SIZE = config->srcTxfrSize;
descriptor->unPDMA_DESCR_CTL.stcField.u1DST_TRANSFER_SIZE = config->destTxfrSize;
descriptor->unPDMA_DESCR_CTL.stcField.u1CH_DISABLE = config->chStateAtCmplt;
descriptor->unPDMA_DESCR_CTL.stcField.u2DATA_SIZE = config->dataSize;
descriptor->unPDMA_DESCR_CTL.stcField.u2DESCR_TYPE = config->descrType;
descriptor->u32PDMA_DESCR_SRC = (uint32_t)config->srcAddr;
descriptor->u32PDMA_DESCR_DST = (uint32_t)config->destAddr;
switch(config->descrType)
{
case (uint32_t)CY_PDMA_SINGLE_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_PDMA_1D_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.stcField.u12SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u12DST_X_INCR = (uint32_t)config->destXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u8X_COUNT = (uint32_t)((config->xCount) - 1ul);
descriptor->unPDMA_DESCR_Y_CTL.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_PDMA_CRC_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.stcField.u12SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u12DST_X_INCR = 0ul;
descriptor->unPDMA_DESCR_X_CTL.stcField.u8X_COUNT = (uint32_t)((config->xCount) - 1ul);
descriptor->unPDMA_DESCR_Y_CTL.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_PDMA_2D_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.stcField.u12SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u12DST_X_INCR = (uint32_t)config->destXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u8X_COUNT = (uint32_t)((config->xCount) - 1ul);
descriptor->unPDMA_DESCR_Y_CTL.stcField.u12SRC_Y_INCR = (uint32_t)config->srcYincr;
descriptor->unPDMA_DESCR_Y_CTL.stcField.u12DST_Y_INCR = (uint32_t)config->destYincr;
descriptor->unPDMA_DESCR_Y_CTL.stcField.u8Y_COUNT = (uint32_t)((config->yCount) - 1ul);
descriptor->u32PDMA_DESCR_NEXT_PTR = (uint32_t)config->descrNext;
break;
}
default:
{
/* Unsupported type of descriptor */
break;
}
}
retVal = CY_PDMA_SUCCESS;
}
else
{
retVal = CY_PDMA_INVALID_INPUT_PARAMETERS;
}
return retVal;
}
Code Listing 47 Cy_PDMA_Chnl_Init()
cy_en_pdma_status_t Cy_PDMA_Chnl_Init(volatile stc_DW_t *pstcPDMA, uint32_t chNum, const cy_stc_pdma_chnl_config_t* chnlConfig)
{
cy_en_pdma_status_t retVal = CY_PDMA_ERR_UNC;
if ((pstcPDMA != NULL) && (chnlConfig != NULL))
{
/* Set current descriptor */
pstcPDMA->CH_STRUCT[chNum].unCH_CURR_PTR.u32Register = (uint32_t)chnlConfig->PDMA_Descriptor;
/* Set if the channel is preemtable */
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u1PREEMPTABLE = chnlConfig->preemptable;
/* Set channel priority */
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u2PRIO = chnlConfig->priority;
/* Set enabled status */
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u1ENABLED = chnlConfig->enable;
retVal = CY_PDMA_SUCCESS;
}
else
{
retVal = CY_PDMA_INVALID_INPUT_PARAMETERS;
}
return (retVal);
}
Code Listing 48 Cy_PDMA_Chnl_Enable()
__STATIC_INLINE void Cy_PDMA_Chnl_Enable(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u1ENABLED = 1ul;
}
Code Listing 49 Cy_PDMA_Chnl_SetInterruptMask()
__STATIC_INLINE void Cy_PDMA_Chnl_SetInterruptMask(volatile stc_DW_t *pstcPDMA, uint32_t chNum)
{
pstcPDMA->CH_STRUCT[chNum].unINTR_MASK.u32Register = CY_PDMA_INTR_BIT_MASK;
}
Code Listing 50 Cy_PDMA_Enable()
void Cy_PDMA_Enable(volatile stc_DW_t *pstcPDMA)
{
pstcPDMA->unCTL.stcField.u1ENABLED = 1ul; /* Write to P-DMA_CTL_ENABLED bit */
}
CRC transfer
Overview
This section describes an example of CRC transfer. CRC transfer is a P-DMA- specific descriptor type. CRC transfer calculates the CRC in the area that is specified by the source address and size, and transfers the result to the destination address.
This is an example of program code validation in the flash with CRC transfer. The CPU calculates the CRC of the program code area with P-DMA before program execution. CRC calculation is performed by using CRC32. When the result of CRC calculation matches the expected value, the CPU starts the execution of the program. In this example, note that it is necessary to prepare for the expected value of the program code.
See the architecture TRM for details of CRC parameters that can be set by P-DMA.
Figure 17 shows a use case of a CRC transfer.
Figure 17. Use case of CRC transfer
(0) Configure P-DMA according to the usage example.
(1) CPU notifies a software trigger to P-DMA via the trigger multiplexer.
(2) P-DMA reads the descriptor from the specified area (Descriptor Pointer) when accepting the transfer.
(3) P-DMA reads the data from the source address (code base address).
(4) P-DMA inputs the read data to the CRC calculator, and reads the data again after incrementing the address. P-DMA repeats (4) until it reaches the area specified by the transfer size (code size).
(5) When CRC calculation of the specified area is completed, the result is transferred to the destination address (RAM base address).
(6) P-DMA notifies an interrupt to the CPU.
When the CPU accepts an interrupt, it compares the result with the expected value. When it matches, CPU starts program execution. If it does not match, CPU transfers to safe operation mode.
Initial configuration
This section describes the initialization of the P-DMA channel and descriptor of this use case.
Figure 18 shows the setting procedure for P-DMA.
Figure 18. Setting procedure for P-DMA
Configuration and example code
Table 15 lists the parameters and Table 16 lists the functions of the configuration part in SDL for DMA.
Table 15. List of DMA configuration parameters
Parameters | Description | Value |
---|---|---|
BUFFER_SIZE | Defines buffer size | 5 |
DW_CHANNEL | Defines DW channel | 0 |
EXPECTED_RESULT_VALUE | Defines result value | (0x3C4687AFUL) |
.data_reverse | Least significant bit (bit 0) first | 1 |
.rem_reverse | Remainder is bit reversed | 1 |
.data_xor | Each data byte is XORed with 00h | 0 |
.polynomial | CRC32: POLYNOMIAL | 0x04c11db7 |
.lfsr32 | Seed value | 0xFFFFFFFF |
.rem_xor | CRC_LFSR_CTL.LFSR32 register is XORed with FFFFh | 0xFFFFFFFF |
.PDMA_Descriptor | P-DMA current descriptor pointer | &stcDescr |
.preemptable | Channel preemptable | 0 |
.priority | Channel priority | 0 |
.enable | Channel enable | 1 |
.deact | DESCR_CTL WAIT_FOR_DEACT | 0 |
.intrType | DESCR_CTL INTR_TYPE | CY_PDMA_INTR_1ELEMENT_CMPLT |
.trigoutType | DESCR_CTL TR_OUT_TYPE | CY_PDMA_TRIGOUT_1ELEMENT_CMPLT |
.chStateAtCmplt | DESCR_CTL CH_DISABLE | CY_PDMA_CH_DISABLED |
.triginType | DESCR_CTL TR_IN_TYPE | CY_PDMA_TRIGIN_DESCR |
.dataSize | DESCR_CTL DATA_SIZE | CY_PDMA_BYTE |
.srcTxfrSize | DESCR_CTL SRC_TRANSFER_SIZE | 0 |
.destTxfrSize | DESCR_CTL DST_TRANSFER_SIZE | 0 |
.descrType | DESCR_CTL DESCR_TYPE | CY_PDMA_CRC_TRANSFER |
.srcAddr | DESCR_SRC | (void*) au8SrcBuffer |
.destAddr | DESCR_DST | 0 |
.srcXincr | DESCR_X_CTL SRC_X_INCR | 1 |
.destXincr | DESCR_X_CTL DST_X_INCR | 1 |
.xCount | DESCR_X_CTL X_COUNT | BUFFER_SIZE |
.srcYincr | DESCR_Y_CTL SRC_Y_INCR | 0 |
.destYincr | DESCR_Y_CTL DST_Y_INCR | 0 |
.yCount | DESCR_Y_CTL Y_COUNT | 0 |
Table 16. List of DMA configuration functions
Functions | Description | Remarks |
---|---|---|
Cy_GPIO_Pin_Init() | Configures GPIO pin | |
Cy_PDMA_Disable() | Configures P-DMA disable | Write to P-DMA_CTL_ENABLED bit. See Code Listing 53 |
Cy_PDMA_CRC_Config() | Configures P-DMA CRC | See Code Listing 54 |
Cy_PDMA_Descr_Init() | Configures P-DMA descriptor initialize | See Code Listing 55 |
Cy_PDMA_Chnl_Init() | Configures P-DMA channel initialize | See Code Listing 56 |
Cy_PDMA_Enable() | Configures P-DMA enable | Write to P-DMA_CTL_ENABLED bit. See Code Listing 57 |
Cy_TrigMux_SwTrigger() | Generates a Software trigger |
Code Listing 51 demonstrates an example program to 2D transfer (peripheral-to- memory). See the architecture TRM and application note for GPIO and Clock configuration.
Code Listing 51 Example to CRC transfer
/* Define buffer size
Define P-DMA channel
Define result value */
#define BUFFER_SIZE 5
#define DW_CHANNEL 0
#define EXPECTED_RESULT_VALUE (0x3C4687AFUL)
int main(void)
{
:
/* Place your initialization/startup code here (e.g. MyInst_Start()) */
Cy_GPIO_Pin_Init(CY_LED8_PORT, CY_LED8_PIN, &user_led8_port_pin_cfg);
Cy_PDMA_Disable(pstcDW);
Cy_PDMA_CRC_Config( pstcDW,
&stcCrcConfig);
/* (1) Disable P-DMA. See Code Listing 53.
(2) Configures P-DMA CRC. See Code Listing 54.
(3) Configures P-DMA descriptor initialize. See Code Listing 55.
(4) Enable P-DMA channel. See Code Listing 56.
(5) Enable P-DMA. See Code Listing 57 */
stcDmaDescrConfig.destAddr = (void *)&pstcDW->unCRC_LFSR_CTL.u32Register;
Cy_PDMA_Descr_Init(&stcDescr,&stcDmaDescrConfig);
Cy_PDMA_Chnl_Init( pstcDW,
DW_CHANNEL,
(const cy_stc_pdma_chnl_config_t*) &chnlConfig);
Cy_PDMA_Enable(pstcDW);
/* (1) Disable P-DMA. See Code Listing 53.
(2) Configures P-DMA CRC. See Code Listing 54.
(3) Configures P-DMA descriptor initialize. See Code Listing 55.
(4) Enable P-DMA channel. See Code Listing 56.
(5) Enable P-DMA. See Code Listing 57 */
/*Trigger DMA by SW*/
Cy_TrigMux_SwTrigger(TRIG_OUT_MUX_0_PDMA0_TR_IN0,
TRIGGER_TYPE_CPUSS_DW0_TR_IN__EDGE,
1); /*output*/
//Wait for completion
while(pstcDW->CH_STRUCT[DW_CHANNEL].unCH_CTL.stcField.u1ENABLED)
{
u32Time++;
}
u32CrcResult = Cy_PDMA_GetCrcRemainderResult(pstcDW);
CY_ASSERT(u32CrcResult == EXPECTED_RESULT_VALUE);
}
Code Listing 52 P-DMA Channel, Descriptor configuration
static volatile stc_DW_t* pstcDW = DW0;
static cy_stc_pdma_descr_t stcDescr;
const uint8_t au8SrcBuffer[] = {0x12,0x34,0x56,0x78,0x9a};
const cy_stc_pdma_crc_config_t stcCrcConfig = {
.data_reverse = 1,
.rem_reverse = 1,
.data_xor = 0,
.polynomial = 0x04c11db7,
.lfsr32 = 0xFFFFFFFF,
.rem_xor = 0xFFFFFFFF,
};
const cy_stc_pdma_chnl_config_t chnlConfig = {
.PDMA_Descriptor= &stcDescr,
.preemptable = 0,
.priority = 0,
.enable = 1, /*enabled after initialization*/
};
static uint32_t u32Time = 0;
static cy_stc_pdma_descr_config_t stcDmaDescrConfig= {
.deact = 0, /*Do not wait for trigger de-activation*/
.intrType = CY_PDMA_INTR_1ELEMENT_CMPLT,
.trigoutType = CY_PDMA_TRIGOUT_1ELEMENT_CMPLT,
.chStateAtCmplt = CY_PDMA_CH_DISABLED,
.triginType = CY_PDMA_TRIGIN_DESCR,
.dataSize = CY_PDMA_BYTE,
.srcTxfrSize = 0, /*= dataSize*/
.destTxfrSize = 0, /*= dataSize*/
.descrType = CY_PDMA_CRC_TRANSFER,
.srcAddr = (void*) au8SrcBuffer,
.destAddr = 0, //below initialized
.srcXincr = 1,
.destXincr = 1,
.xCount = BUFFER_SIZE,
.srcYincr = 0,
.destYincr = 0,
.yCount = 0,
};
Code Listing 53 Cy_PDMA_Disable()
void Cy_PDMA_Disable(volatile stc_DW_t *pstcPDMA)
{
pstcPDMA->unCTL.stcField.u1ENABLED = 0ul; /* Write to P-DMA_CTL_ENABLED bit */
}
Code Listing 54 Cy_PDMA_CRC_Config()
void Cy_PDMA_CRC_Config ( volatile stc_DW_t * pstcPDMA,
const cy_stc_pdma_crc_config_t* pstcCrcConfig)
{
/* Configures P-DMA CRC */
pstcPDMA->unCRC_CTL.stcField.u1DATA_REVERSE = pstcCrcConfig->data_reverse;
pstcPDMA->unCRC_CTL.stcField.u1REM_REVERSE = pstcCrcConfig->rem_reverse;
pstcPDMA->unCRC_DATA_CTL.stcField.u8DATA_XOR = pstcCrcConfig->data_xor;
pstcPDMA->unCRC_LFSR_CTL.stcField.u32LFSR32 = pstcCrcConfig->lfsr32;
pstcPDMA->unCRC_POL_CTL.stcField.u32POLYNOMIAL = pstcCrcConfig->polynomial;
pstcPDMA->unCRC_REM_CTL.stcField.u32REM_XOR = pstcCrcConfig->rem_xor;
}
Code Listing 55 Cy_PDMA_Descr_Init()
cy_en_pdma_status_t Cy_PDMA_Descr_Init(cy_stc_pdma_descr_t* descriptor, const cy_stc_pdma_descr_config_t* config)
{
cy_en_pdma_status_t retVal = CY_PDMA_ERR_UNC;
if ((descriptor != NULL) && (config != NULL))
{
descriptor->unPDMA_DESCR_CTL.stcField.u2WAIT_FOR_DEACT = config->deact;
descriptor->unPDMA_DESCR_CTL.stcField.u2INTR_TYPE = config->intrType;
descriptor->unPDMA_DESCR_CTL.stcField.u2TR_OUT_TYPE = config->trigoutType;
descriptor->unPDMA_DESCR_CTL.stcField.u2TR_IN_TYPE = config->triginType;
descriptor->unPDMA_DESCR_CTL.stcField.u1SRC_TRANSFER_SIZE = config->srcTxfrSize;
descriptor->unPDMA_DESCR_CTL.stcField.u1DST_TRANSFER_SIZE = config->destTxfrSize;
descriptor->unPDMA_DESCR_CTL.stcField.u1CH_DISABLE = config->chStateAtCmplt;
descriptor->unPDMA_DESCR_CTL.stcField.u2DATA_SIZE = config->dataSize;
descriptor->unPDMA_DESCR_CTL.stcField.u2DESCR_TYPE = config->descrType;
descriptor->u32PDMA_DESCR_SRC = (uint32_t)config->srcAddr;
descriptor->u32PDMA_DESCR_DST = (uint32_t)config->destAddr;
switch(config->descrType)
{
case (uint32_t)CY_PDMA_SINGLE_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_PDMA_1D_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.stcField.u12SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u12DST_X_INCR = (uint32_t)config->destXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u8X_COUNT = (uint32_t)((config->xCount) - 1ul);
descriptor->unPDMA_DESCR_Y_CTL.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_PDMA_CRC_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.stcField.u12SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u12DST_X_INCR = 0ul;
descriptor->unPDMA_DESCR_X_CTL.stcField.u8X_COUNT = (uint32_t)((config->xCount) - 1ul);
descriptor->unPDMA_DESCR_Y_CTL.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_PDMA_2D_TRANSFER:
{
descriptor->unPDMA_DESCR_X_CTL.stcField.u12SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u12DST_X_INCR = (uint32_t)config->destXincr;
descriptor->unPDMA_DESCR_X_CTL.stcField.u8X_COUNT = (uint32_t)((config->xCount) - 1ul);
descriptor->unPDMA_DESCR_Y_CTL.stcField.u12SRC_Y_INCR = (uint32_t)config->srcYincr;
descriptor->unPDMA_DESCR_Y_CTL.stcField.u12DST_Y_INCR = (uint32_t)config->destYincr;
descriptor->unPDMA_DESCR_Y_CTL.stcField.u8Y_COUNT = (uint32_t)((config->yCount) - 1ul);
descriptor->u32PDMA_DESCR_NEXT_PTR = (uint32_t)config->descrNext;
break;
}
default:
{
/* Unsupported type of descriptor */
break;
}
}
retVal = CY_PDMA_SUCCESS;
}
else
{
retVal = CY_PDMA_INVALID_INPUT_PARAMETERS;
}
return retVal;
}
Code Listing 56 Cy_PDMA_Chnl_Init()
cy_en_pdma_status_t Cy_PDMA_Chnl_Init(volatile stc_DW_t *pstcPDMA, uint32_t chNum, const cy_stc_pdma_chnl_config_t* chnlConfig)
{
cy_en_pdma_status_t retVal = CY_PDMA_ERR_UNC;
if ((pstcPDMA != NULL) && (chnlConfig != NULL))
{
/* Set current descriptor */
pstcPDMA->CH_STRUCT[chNum].unCH_CURR_PTR.u32Register = (uint32_t)chnlConfig->PDMA_Descriptor;
/* Set if the channel is preemtable */
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u1PREEMPTABLE = chnlConfig->preemptable;
/* Set channel priority */
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u2PRIO = chnlConfig->priority;
/* Set enabled status */
pstcPDMA->CH_STRUCT[chNum].unCH_CTL.stcField.u1ENABLED = chnlConfig->enable;
retVal = CY_PDMA_SUCCESS;
}
else
{
retVal = CY_PDMA_INVALID_INPUT_PARAMETERS;
}
return (retVal);
}
Code Listing 57 Cy_PDMA_Enable()
void Cy_PDMA_Enable(volatile stc_DW_t *pstcPDMA)
{
pstcPDMA->unCTL.stcField.u1ENABLED = 1ul; /* Write to P-DMA_CTL_ENABLED bit */
}
M-DMA use case
This section describes how to use Smart I/O using the sample driver library (SDL). The code snippets in this application note are part of SDL. See Other references for the SDL.
SDL has a configuration part and a driver part. The configuration part mainly configures the parameter values for the desired operation. The driver part configures each register based on the parameter values in the configuration part. You can configure the configuration part according to your system.
In this example, CYT2B7 series is used.
Memory-to-memory (memory copy)
This section describes an example of memory copy. Memory copy is an M-DMA- specific descriptor type. This is a special 1D transfer. Memory copy transfer data from the area specified by the source address and size to the destination address.
This is an example of data transfer from flash to RAM. This descriptor type is useful for copying the program code for RAM execution and copying the vector table. In the memory copy example, consecutive flash memory areas are transferred to RAM.
Figure 19 shows a use case of memory-to-memory transfer using memory copy.
Figure 19. Use case of memory-to-memory using memory copy
(0) Set M-DMA according to the usage example setting.
(1) CPU notifies a software trigger to M-DMA via the trigger multiplexer.
(2) M-DMA reads the descriptor from the specified area (Descriptor Pointer) when accepting the transfer.
(3) M-DMA reads the data from the source address (code base address).
(4) M-DMA writes the read data to the destination address (RAM base address). After that, increment the source address and destination address. M-DMA repeats (3) (4) until it reaches the area specified by the transfer size (code size).
(5) When memory copy of the specified area is completed, M-DMA notifies an interrupt to CPU.
Initial configuration
This section describes the initialization of the M-DMA channel and descriptor of this use case.
Figure 20 shows the setting procedure for M-DMA.
Figure 20. Setting procedure for M-DMA
Configuration and example code
Table 17 lists the parameters and Table 18 lists the functions of the configuration part in SDL for M-DMA.
Table 17. List of DMA configuration parameters
Parameters | Description | Value |
---|---|---|
BUFFER_SIZE | Defines buffer size | 36 |
DMAC_CHANNEL | Defines M-DMA channel | 0 |
.MDMA_Descriptor | M-DMA current descriptor pointer | &stcDescr |
.preemptable | Channel preemptable | 0 |
.priority | Channel priority | 0 |
.enable | Channel enable | 1 |
.deact | DESCR_CTL WAIT_FOR_DEACT | 0 |
.intrType | DESCR_CTL INTR_TYPE | CY_PDMA_INTR_1ELEMENT_CMPLT |
.trigoutType | DESCR_CTL TR_OUT_TYPE | CY_PDMA_TRIGOUT_1ELEMENT_CMPLT |
.chStateAtCmplt | DESCR_CTL CH_DISABLE | CY_MDMA_CH_DISABLED |
.triginType | DESCR_CTL TR_IN_TYPE | CY_PDMA_TRIGIN_DESCR |
.dataSize | DESCR_CTL DATA_SIZE | CY_MDMA_BYTE |
.srcTxfrSize | DESCR_CTL SRC_TRANSFER_SIZE | 0 |
.destTxfrSize | DESCR_CTL DST_TRANSFER_SIZE | 0 |
.descrType | DESCR_CTL DESCR_TYPE | CY_MDMA_1D_TRANSFER |
.srcAddr | DESCR_SRC | au8SrcBuffer |
.destAddr | DESCR_DST | au8DestBuffer |
.srcXincr | DESCR_X_INCR SRC_X_INCR | 1 |
.destXincr | DESCR_X_INCR DST_X_INCR | 1 |
.xCount | DESCR_X_SIZE X_COUNT | BUFFER_SIZE |
.srcYincr | DESCR_Y_INCR SRC_Y_INCR | 0 |
.destYincr | DESCR_Y_INCR DST_Y_INCR | 0 |
.yCount | DESCR_Y_SIZE Y_COUNT | 0 |
.descrNext | DESCR_NEXT_PTR | 0 |
Table 18. List of DMA configuration functions
Functions | Description | Remarks |
---|---|---|
Cy_MDMA_Disable() | Configures M-DMA disable | Write to M-DMA_CTL_ENABLED bit. See Code Listing 60 |
Cy_MDMA_Descr_Init() | Configures M-DMA descriptor initialize | See Code Listing 61 |
Cy_MDMA_Chnl_Init() | Configures M-DMA channel initialize | See Code Listing 62 |
Cy_MDMA_Chnl_Enable() | Configures M-DMA channel enable | See Code Listing 63 |
Cy_MDMA_Enable() | Configures M-DMA enable | Write to M-DMA_CTL_ENABLED bit. See Code Listing 64 |
Cy_TrigMux_SwTrigger() | Generates a Software trigger |
Code Listing 58 demonstrates an example program to 2D transfer (peripheral-to- memory). See the architecture TRM and application note for GPIO and clock configuration.
Code Listing 58 Example to M-DMA Transfer
/* Define buffer size
Define DMAC channel */
#define BUFFER_SIZE 36
#define DMAC_CHANNEL 0
int main(void)
{
:
uint32_t i;
uint8_t *p_src;
__enable_irq(); /* Enable global interrupts. */
/*******/
/* DMA */
/*******/
/* Initialie & Enable DMA */
/* (1) Disable M-DMA. See Code Listing 60
(2) Configures M-DMA channel initialize. See Code Listing 62
(3) Configures M-DMA descriptor initialize. See Code Listing 61
(4) Enable M-DMA channel. See Code Listing 63
(5) Enable M-DMA. See Code Listing 64 */
Cy_MDMA_Disable(DMAC);
Cy_MDMA_Descr_Init(&stcDescr,&stcDmaDescrConfig);
Cy_MDMA_Chnl_Init( DMAC,
DMAC_CHANNEL,
(const cy_stc_mdma_chnl_config_t*) &chnlConfig);
Cy_MDMA_Chnl_Enable( DMAC, DMAC_CHANNEL);
Cy_MDMA_Enable(DMAC);
/* for test */
p_src = &au8SrcBuffer[0];
for (i=0; i<BUFFER_SIZE; i++) {
*p_src++ = i;
au8DestBuffer[i] = 0;
}
/***************/
/* Trigger MUX */
/***************/
Cy_TrigMux_SwTrigger( TRIG_OUT_MUX_2_MDMA_TR_IN0,
TRIGGER_TYPE_CPUSS_DMAC_TR_IN__EDGE,
1u);
for(;;)
{
}
}
Code Listing 59 M-DMA Channel, descriptor configuration
static uint8_t au8DestBuffer[BUFFER_SIZE] = {0};
static uint8_t au8SrcBuffer[BUFFER_SIZE];
static cy_stc_mdma_descr_t stcDescr;
/* Configure M-DMA channel */
const cy_stc_mdma_chnl_config_t chnlConfig = {
/* CURR_PTR */ .MDMA_Descriptor = &stcDescr,
.preemptable = 0,
.priority = 0,
.enable = 1,
};
/* Configure M-DMA descriptor */
static cy_stc_mdma_descr_config_t stcDmaDescrConfig = {
/* DESCR_CTL WAIT_FOR_DEACT */ .deact = 0,
/* DESCR_CTL INTR_TYPE */ .intrType = CY_PDMA_INTR_1ELEMENT_CMPLT,
/* DESCR_CTL TR_OUT_TYPE */ .trigoutType = CY_PDMA_TRIGOUT_1ELEMENT_CMPLT,
/* DESCR_CTL CH_DISABLE */ .chStateAtCmplt = CY_MDMA_CH_DISABLED,
/* DESCR_CTL TR_IN_TYPE */ .triginType = CY_PDMA_TRIGIN_DESCR,
/* DESCR_CTL DATA_SIZE */ .dataSize = CY_MDMA_BYTE,
/* DESCR_CTL SRC_TRANSFER_SIZE */ .srcTxfrSize = 0,
/* DESCR_CTL DST_TRANSFER_SIZE */ .destTxfrSize = 0,
/* DESCR_CTL DESCR_TYPE */ .descrType = CY_MDMA_1D_TRANSFER,
/* DESCR_SRC */ .srcAddr = au8SrcBuffer,
/* DESCR_DST */ .destAddr = au8DestBuffer,
/* DESCR_X_INCR SRC_X_INCR */ .srcXincr = 1,
/* DESCR_X_INCR DST_X_INCR */ .destXincr = 1,
/* DESCR_X_SIZE X_COUNT */ .xCount = BUFFER_SIZE,
/* DESCR_Y_INCR SRC_Y_INCR */ .srcYincr = 0,
/* DESCR_Y_INCR DST_Y_INCR */ .destYincr = 0,
/* DESCR_Y_SIZE Y_COUNT */ .yCount = 0,
/* DESCR_NEXT_PTR */ .descrNext = 0
};
Code Listing 60 Cy_MDMA_Disable()
void Cy_MDMA_Disable(volatile stc_DMAC_t *pstcMDMA)
{
pstcMDMA->unCTL.stcField.u1ENABLED = 0ul; /* Write to M-DMA_CTL_ENABLED bit */
}
Code Listing 61 Cy_MDMA_Descr_Init()
cy_en_mdma_status_t Cy_MDMA_Descr_Init(cy_stc_mdma_descr_t* descriptor, const cy_stc_mdma_descr_config_t* config)
{
cy_en_mdma_status_t retVal = CY_MDMA_ERR_UNC;
if ((descriptor != NULL) && (config != NULL))
{
/* Descriptor[0] */
descriptor->unMDMA_DESCR_CTL.stcField.u2WAIT_FOR_DEACT = config->deact;
descriptor->unMDMA_DESCR_CTL.stcField.u2INTR_TYPE = config->intrType;
descriptor->unMDMA_DESCR_CTL.stcField.u2TR_OUT_TYPE = config->trigoutType;
descriptor->unMDMA_DESCR_CTL.stcField.u2TR_IN_TYPE = config->triginType;
descriptor->unMDMA_DESCR_CTL.stcField.u1DATA_PREFETCH = config->dataPrefetch;
descriptor->unMDMA_DESCR_CTL.stcField.u2DATA_SIZE = config->dataSize;
descriptor->unMDMA_DESCR_CTL.stcField.u1CH_DISABLE = config->chStateAtCmplt;
descriptor->unMDMA_DESCR_CTL.stcField.u1SRC_TRANSFER_SIZE = config->srcTxfrSize;
descriptor->unMDMA_DESCR_CTL.stcField.u1DST_TRANSFER_SIZE = config->destTxfrSize;
descriptor->unMDMA_DESCR_CTL.stcField.u3DESCR_TYPE = config->descrType;
/* Descriptor[1] */
descriptor->u32MDMA_DESCR_SRC = (uint32_t)config->srcAddr;
/* after 3rd word of descriptor depends on descriptor type */
switch(config->descrType)
{
case (uint32_t)CY_MDMA_SINGLE_TRANSFER:
{
/* Descriptor[2] */
descriptor->u32MDMA_DESCR_DST = (uint32_t)config->destAddr;
/* Descriptor[3] -> NEXT_PTR */
descriptor->unMDMA_DESCR_X_SIZE.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_MDMA_1D_TRANSFER:
{
/* Descriptor[2] */
descriptor->u32MDMA_DESCR_DST = (uint32_t)config->destAddr;
/* Descriptor[3] */
descriptor->unMDMA_DESCR_X_SIZE.stcField.u16X_COUNT = (uint32_t)((config->xCount) - 1ul);
/* Descriptor[4] */
descriptor->unMDMA_DESCR_X_INCR.stcField.u16SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unMDMA_DESCR_X_INCR.stcField.u16DST_X_INCR = (uint32_t)config->destXincr;
/* Descriptor[5] -> NEXT_PTR */
descriptor->unMDMA_DESCR_Y_SIZE.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_MDMA_2D_TRANSFER:
{
/* Descriptor[2] */
descriptor->u32MDMA_DESCR_DST = (uint32_t)config->destAddr;
/* Descriptor[3] */
descriptor->unMDMA_DESCR_X_SIZE.stcField.u16X_COUNT = (uint32_t)((config->xCount) - 1ul);
/* Descriptor[4] */
descriptor->unMDMA_DESCR_X_INCR.stcField.u16SRC_X_INCR = (uint32_t)config->srcXincr;
descriptor->unMDMA_DESCR_X_INCR.stcField.u16DST_X_INCR = (uint32_t)config->destXincr;
/* Descriptor[5] */
descriptor->unMDMA_DESCR_Y_SIZE.stcField.u16Y_COUNT = (uint32_t)((config->yCount) - 1ul);
/* Descriptor[6] */
descriptor->unMDMA_DESCR_Y_INCR.stcField.u16SRC_Y_INCR = (uint32_t)config->srcYincr;
descriptor->unMDMA_DESCR_Y_INCR.stcField.u16DST_Y_INCR = (uint32_t)config->destYincr;
/* Descriptor[7] */
descriptor->u32MDMA_DESCR_NEXT_PTR = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_MDMA_MEMORY_COPY_TRANSFER:
{
/* Descriptor[2] */
descriptor->u32MDMA_DESCR_DST = (uint32_t)config->destAddr;
/* Descriptor[3] */
descriptor->unMDMA_DESCR_X_SIZE.stcField.u16X_COUNT = (uint32_t)((config->xCount) - 1ul);
/* Descriptor[4] -> NEXT_PTR */
descriptor->unMDMA_DESCR_X_INCR.u32Register = (uint32_t)config->descrNext;
break;
}
case (uint32_t)CY_MDMA_SCATTER_TRANSFER:
{
/* Descriptor[2] -> X_SIZE */
descriptor->u32MDMA_DESCR_DST = (uint32_t)((config->xCount) - 1ul);
/* Descriptor[3] -> NEXT_PTR */
descriptor->unMDMA_DESCR_X_SIZE.u32Register = (uint32_t)config->descrNext;
break;
}
default:
{
/* Unsupported type of descriptor */
break;
}
}
retVal = CY_MDMA_SUCCESS;
}
else
{
retVal = CY_MDMA_INVALID_INPUT_PARAMETERS;
}
return retVal;
}
Code Listing 62 Cy_MDMA_Chnl_Init()
cy_en_mdma_status_t Cy_MDMA_Chnl_Init(volatile stc_DMAC_t *pstcMDMA, uint32_t chNum, const cy_stc_mdma_chnl_config_t* chnlConfig)
{
cy_en_mdma_status_t retVal = CY_MDMA_ERR_UNC;
if ((pstcMDMA != NULL) && (chnlConfig != NULL))
{
/* Set current descriptor */
pstcMDMA->CH[chNum].unCURR.u32Register = (uint32_t)chnlConfig->MDMA_Descriptor;
/* Set if the channel is preemptable */
/* There is no the parameter in MDMA */
/* Set channel priority */
pstcMDMA->CH[chNum].unCTL.stcField.u2PRIO = chnlConfig->priority;
/* Set enabled status */
pstcMDMA->CH[chNum].unCTL.stcField.u1ENABLED = chnlConfig->enable;
retVal = CY_MDMA_SUCCESS;
}
else
{
retVal = CY_MDMA_INVALID_INPUT_PARAMETERS;
}
return (retVal);
}
Code Listing 63 CyMDMA_Chnl Enable()
__STATIC_INLINE void Cy_MDMA_Chnl_Enable(volatile stc_DMAC_t *pstcMDMA, uint32_t chNum)
{
pstcMDMA->CH[chNum].unCTL.stcField.u1ENABLED = 1ul;
}
Code Listing 64 CyMDMA Enable()
void Cy_MDMA_Enable(volatile stc_DMAC_t *pstcMDMA)
{
pstcMDMA->unCTL.stcField.u1ENABLED = 1ul; /* Write to M-DMA_CTL_ENABLED bit */
}
Glossary
Terms | Description |
---|---|
DMA controller | Direct memory access controller |
P-DMA | Peripheral DMA |
M-DMA | Memory DMA |
Single transfer | This transfers a single data element (8-bit, 16-bit, or 32-bit). See the “Descriptors” section in the Direct Memory Access chapter of the architecture TRM for details. |
1D transfer | This performs a one-dimensional "for loop" (described in C). See the “Descriptors” section in the Direct Memory Access chapter of the architecture TRM for details. |
2D transfer | This performs a two-dimensional "for loop" (described in C). See the “Descriptors” section in the Direct Memory Access chapter of the architecture TRM for details. |
CRC transfer | This performs a one-dimensional “for loop” similar to the 1D transfer. However, the source data is not transferred to a destination. A CRC is calculated over the source data. Only P-DMA is supported. See the “Descriptors” section in the Direct Memory Access chapter of the architecture TRM for details. |
Memory copy | This is a special case of 1D transfer. Only M-DMA is supported. See the “Descriptors” section in the Direct Memory Access chapter of the architecture TRM for details. |
Scatter | This descriptor type is intended to write a set of 32-bit data elements, whose addresses are “scattered” around the address space. Only M-DMA is supported. See the “Descriptors” section in the Direct Memory Access chapter of the architecture TRM for details. |
Descriptor | A descriptor specifies the details of data transfer of DMA channels. See the “Descriptors” section in the Direct Memory Access chapter of the architecture TRM for details. |
Descriptor chain | A DMA channel executes the next descriptor specified in the current descriptor when it completes executing the descriptor. See the “Descriptors” section in the Direct Memory Access chapter of the architecture TRM for details. |
Descriptor list | Same as descriptor chain. |
Descriptor pointer | The start address of the memory where the descriptor is stored. See the “Descriptors” section in the Direct Memory Access chapter of the architecture TRM for details. |
Descriptor type | The transfer operation type performed by DMA. See the “Descriptors” section in the Direct Memory Access chapter of the architecture TRM for details. |
Descriptor word | The composition element of the descriptor. There are descriptor control, source/destination address, X/Y loop control, and descriptor next pointer. See the “P-DMA Descriptor Structure” and “M-DMA Descriptor Structure” section in the Direct Memory Access chapter of the architecture TRM for details. |
Preemptable | P-DMA specific functions. See the “Channels” section in the Direct Memory Access chapter of the architecture TRM for details. |
MMIO | Memory Mapped I/O |
ADC | Analog-to-digital converter. See the “SAR ADC” chapter of the architecture TRM for details. |
SCB | Serial Communications Block. See the “Serial Communications Block (SCB)” chapter of the architecture TRM for details. |
TCPWM | Timer, Counter, and Pulse Width Modulator. See the “Timer, Counter, and PWM” chapter of the architecture TRM for details. |
Trigger multiplexer | A trigger multiplexer routes triggers from a source peripheral to a destination. See the “Trigger Multiplexer” chapter of the architecture TRM for details. |
References
The following are the TRAVEO™ T2G family series datasheets and technical reference manuals. Contact Technical Support to obtain these documents.
- Device datasheets
- CYT2B7 datasheet 32-bit Arm® Cortex®-M4F microcontroller TRAVEO™ T2G family
- CYT2B9 datasheet 32-bit Arm® Cortex®-M4F microcontroller TRAVEO™ T2G family
- CYT4BF datasheet 32-bit Arm® Cortex®-M7 microcontroller TRAVEO™ T2G family
- CYT4DN datasheet 32-bit Arm® Cortex®-M7 microcontroller TRAVEO™ T2G family (Doc No. 002-24601)
- CYT3BB/4BB datasheet 32-bit Arm® Cortex®-M7 microcontroller TRAVEO™ T2G family
- CYT3DL datasheet 32-bit Arm® Cortex®-M7 microcontroller TRAVEO™ T2G family (Doc No. 002-27763)
- Technical reference manuals
- Body controller entry family
- Body controller high family
- Cluster 2D family
- TRAVEO™ T2G automotive cluster 2D family architecture technical reference manual (TRM) (Doc No. 002-25800)
- TRAVEO™ T2G automotive cluster 2D registers technical reference manual (TRM) for CYT4DN (Doc No. 002-25923)
- TRAVEO™ T2G automotive cluster 2D registers technical reference manual (TRM) for CYT 3DL (Doc No. 002-29854)
- Application notes
Other references
A sample driver library (SDL) including startup as sample software to access various peripherals is provided. SDL also serves as a reference, to customers, for drivers that are not covered by the official AUTOSAR products. The SDL cannot be used for production purposes as it does not qualify to any automotive standards. The code snippets in this application note are part of the SDL. Contact Technical Support to obtain the SDL.
Revision history
Document version | Date of release | Description of changes |
---|---|---|
** | 2018-06-09 | New application note. |
*A | 2018-06-12 | Updated associated part family as “TRAVEO™ T2G family CYT2B series”. Changed target part numbers from “CYT2B5/B7 series” to “CYT2B series” in all instances across the document. |
*B | 2019-03-26 | Updated associated part family as “TRAVEO™ T2G family CYT2B/CYT4B series”. Added target part numbers “CYT4B series” related information in all instances across the document. Updated operation overview: Updated configure channel: Updated “Table 3. channel configuration for P-DMA”. Updated P-DMA use cases: Updated CRC transfer: Updated initial configuration: Updated description (correction of errors in CRC register name). |
*C | 2019-02-10 | Updated associated part family as “TRAVEO™ T2G family CYT2B/CYT4B/CYT4D series”. Added target part numbers “CYT4D series” related information in all instances across the document. Added the setting flow of DW_CH_STRUCT_CH_IDX into channel configuration for P-DMA in all instances across the document. Updated operation overview: Updated configure channel: Updated “Table 3. channel configuration for P-DMA”. Updated “Table 4. channel configuration for M-DMA”. |
*D | 2020-03-19 | Updated associated part family as “TRAVEO™ T2G family CYT2/CYT3/CYT4 series”. Changed target part numbers from “CYT2B/CYT4B/CYT4D series” to “CYT2/ CYT4 series” in all instances across the document. Added target part numbers “CYT3 series” related information in all instances across the document. |
*E | 2021-03-29 | Updated to Infineon template. |
*F | 2021-07-09 | Added example of SDL code and description in all instances. |
*G | 2023-11-10 | Template update; no content update |