GDMA Used in DLPS

This sample illustrates the usage of GDMA in the DLPS by using UART RX GDMA.

This sample code demonstrates the communication between the chip and the PC terminal. It implements the function of receiving data via UART RX GDMA and wakes up the system using a wake-up PIN after entering DLPS mode. The system will automatically enter DLPS mode when it is idle. When data is transmitted to the chip, the wake-up PIN is first pulled low to wake up the system, allowing UART RX GDMA to continue functioning.

Users can modify some GDMA settings, including channel configuration and data transfer length, through related macro configurations. For detailed descriptions of specific macro configuration items, please refer to Configuration.

Requirements

For hardware requirements, please refer to the Requirements.

Wiring

Connect P3_1 (UART TX Pin) to the RX pin of the FT232 and P3_0 (UART RX Pin) to the TX pin of the FT232.

The hardware connection of GDMA DLPS sample code is shown in the figure below.

../../../_images/recover_from_dlps.png

GDMA DLPS Sample Code Hardware Connection Diagram

Configurations

  1. The following macros can be configured to modify the GDMA data transfer length.

    #define UART_BUFFER_SIZE        1024
    
  2. The following macros represent the parameter configurations of the allocated GDMA channel.

    #define UART_RX_DMA_CHANNEL_NUM              uart_rx_dma_ch_num
    #define UART_RX_DMA_CHANNEL                  DMA_CH_BASE(uart_rx_dma_ch_num)
    #define UART_RX_DMA_IRQ                      DMA_CH_IRQ(uart_rx_dma_ch_num)
    
  3. The following macros can be configured to modify UART and wake-up pin definitions.

    #define WAKE_UP_PIN             P0_0
    #define UART_TX_PIN             P3_1
    #define UART_RX_PIN             P3_0
    
  4. The entry function is as follows, call this function in main() to run this sample code. For more details, please refer to the Initialization.

    dlps_gdma_recover_demo();
    

Building and Downloading

For building and downloading, please refer to the Building and Downloading.

Experimental Verification

Preparation Phase

Start a PC terminal program like PuTTY or UartAssist and connect to the used COM port with the following UART settings:

  • Baud rate: 3000000.

  • 8 data bits.

  • 1 stop bit.

  • No parity.

  • No hardware flow control.

Testing Phase

  1. Press the Reset button on the EVB.

  2. After initialization is complete, the system is in idle state, it will enter DLPS mode. Observe the entering DLPS message displayed in the Debug Analyzer.

    dlps_store: enter dlps
    
  3. Pull down the wake-up PIN to wake up the system. Observe the exiting DLPS message displayed in the Debug Analyzer.

    dlps_restore: exit dlps
    
  4. Use a PC terminal program to send data to the chip, for example, send the number 1. Once the UART receives the data, it will print the following message in the Debug Analyzer.

    data_uart_handler: rx_count 1
    
  5. After the data transmission is completed, the system is in idle state and will re-enter DLPS mode.

Code Overview

This section introduces the code and process description for initialization and corresponding function implementation in the sample.

Source Code Directory

The directory for project file and source code are as follows:

  • For project directory, please refer to Source Code Directory.

  • Source code directory: sdk\src\sample\io_demo\dlps\dlps_gdma_recover_demo.c.

UART RX GDMA Initialization

The initialization flow for peripherals can refer to Initialization Flow.

  1. Call Pad_Config() and Pinmux_Config() to initialize the pin.

    static void board_dma_uart_init(void)
    {
        Pad_Config(UART_TX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_LOW);
        Pad_Config(UART_RX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW);
    
        Pinmux_Config(UART_TX_PIN, UART0_TX);
        Pinmux_Config(UART_RX_PIN, UART0_RX);
    }
    
  2. Call RCC_PeriphClockCmd() to enable the UART clock and function.

  3. Initialize the UART peripheral:

    1. Define the UART_InitTypeDef type uartInitStruct, and call UART_StructInit() to pre-fill uartInitStruct with default values.

    2. Modify the uartInitStruct parameters as needed. The UART initialization parameter configuration is shown in the table below.

    3. Call UART_Init() to initialize the UART peripheral.

    UART Initialization Parameters

    UART Hardware Parameters

    Setting in the uartInitStruct

    UART

    Div

    UART_InitTypeDef::div

    1

    Ovsr

    UART_InitTypeDef::ovsr

    8

    Ovsr_adj

    UART_InitTypeDef::ovsr_adj

    0x492

    Parity Check

    UART_InitTypeDef::parity

    UART_PARITY_NO_PARTY

    Stop Bit

    UART_InitTypeDef::stopBits

    UART_STOP_BITS_1

    Data Format

    UART_InitTypeDef::wordLen

    UART_WROD_LENGTH_8BIT

    Hardware Flow Control

    UART_InitTypeDef::autoFlowCtrl

    UART_AUTO_FLOW_CTRL_DIS

    RX Trigger Level

    UART_InitTypeDef::rxTriggerLevel

    29

    GDMA Enable

    UART_InitTypeDef::dmaEn

    ENABLE

    RX Water Level

    UART_InitTypeDef::RxWaterlevel

    1

    RX GDMA Enable

    UART_InitTypeDef::RxDmaEn

    ENABLE

  4. Call UART_INTConfig() to enable uart line status interrupt UART_INT_LINE_STS and RX idle timeout interrupt UART_INT_IDLE.

  5. Call NVIC_Init() to enable NVIC of UART.

  6. Call GDMA_channel_request to request a free GDMA channel and register the GDMA interrupt handler.

  7. Call RCC_PeriphClockCmd() to enable the GDMA clock.

  8. Initialize the GDMA peripheral:

    1. Define a GDMA_InitTypeDef type GDMA_InitStruct, and call GDMA_StructInit() to pre-fill GDMA_InitStruct with default values.

    2. Modify the GDMA_InitStruct parameters as needed. The initialization parameters for the GDMA channel are configured as shown in the table below.

    GDMA Initialization Parameters

    GDMA Hardware Parameters

    Setting in the GDMA_InitStruct

    GDMA

    Channel Num

    GDMA_InitTypeDef::GDMA_ChannelNum

    UART_RX_DMA_CHANNEL_NUM

    Transfer Direction

    GDMA_InitTypeDef::GDMA_DIR

    GDMA_DIR_PeripheralToMemory

    Buffer Size

    GDMA_InitTypeDef::GDMA_BufferSize

    UART_BUFFER_SIZE

    Source Address Increment or Decrement

    GDMA_InitTypeDef::GDMA_SourceInc

    DMA_SourceInc_Fix

    Destination Address Increment or Decrement

    GDMA_InitTypeDef::GDMA_DestinationInc

    DMA_DestinationInc_Inc

    Source Data Size

    GDMA_InitTypeDef::GDMA_SourceDataSize

    GDMA_DataSize_Byte

    Destination Data Size

    GDMA_InitTypeDef::GDMA_DestinationDataSize

    GDMA_DataSize_Byte

    Source Burst Transaction Length

    GDMA_InitTypeDef::GDMA_SourceMsize

    GDMA_Msize_1

    Destination Burst Transaction Length

    GDMA_InitTypeDef::GDMA_DestinationMsize

    GDMA_Msize_1

    Source Address

    GDMA_InitTypeDef::GDMA_SourceAddr

    UART0->RB_THR

    Destination Address

    GDMA_InitTypeDef::GDMA_DestinationAddr

    uart_receive_buf

    Source Handshake

    GDMA_InitTypeDef::GDMA_SourceHandshake

    GDMA_Handshake_UART0_RX

    1. Call GDMA_Init() to initialize the GDMA peripheral.

    2. Configure the GDMA total transfer completion interrupt: GDMA_INT_Transfer and NVIC. For NVIC-related configuration, refer to Interrupt Configuration.

  9. Call GDMA_Cmd() to enable GDMA channel for transmission.

DLPS Mode Initialization

  1. Call io_dlps_register() to initialize IO store/restore and do not need to worry about which IO peripheral requires specific handling.

  2. Call power_check_cb_register() to register inquiry callback function to DLPS Framework. This function will be called each time before entering DLPS to decide whether DLPS is allowed to enter. DLPS will be disallowed if any inquiry callback function returns false. Function uart_dlps_check_callback will be executed before entering DLPS:

  3. Call io_dlps_register_enter_cb() to register callbacks to DLPS enter stage. Function dlps_store will be executed while entering DLPS:

    1. Call Pad_PullUpOrDownValue() to config WAKE_UP_PIN pull up.

    2. Call System_WakeUpPinEnable() to to enable the wake-up function of WAKE_UP_PIN.

  4. Call io_dlps_register_exit_cb() to register callbacks to DLPS exit stage. Function dlps_restore will be executed while exiting from DLPS:

    1. Set uart_allow_enter_dlps to false to not allow the system to enter DLPS mode.

    2. Reinitialize the GDMA peripheral.

  5. Call bt_power_mode_set() to set Bluetooth MAC deep sleep mode.

  6. Call power_mode_set() to switch the system to DLPS mode.

Functional Implementation

Interrupt Handle

Pull down the wake-up PIN to wake up the system and use the PC program to send the data to the chip. When PC finishes sending data, the chip will trigger UART interrupts.

  1. Call UART_GetIID() to get the interrupt ID.

  2. If No data is received in RX idle timeout time after the RX FIFO is empty (data is received by GDMA), the UART_FLAG_RX_IDLE interrupt is triggered:

    1. Call UART_GetFlagState() to check UART_FLAG_RX_IDLE interrupt flag state.

    2. Call UART_INTConfig() to disable UART_INT_IDLE interrupt.

    3. Call GDMA_GetChannelStatus() to GDMA channel status. If channel is active, call GDMA_SuspendCmd() to suspend GDMA.

    4. Call GDMA_GetFIFOStatus() to wait GDMA FIFO empty.

    5. Call GDMA_GetTransferLen() to get GDMA transfer count.

    6. Call GDMA_Cmd() to abort GDMA.

    7. Call GDMA_SetDestinationAddress() to reconfigure the destination address of the GDMA.

    8. Call GDMA_SuspendCmd() to resume GDMA.

    9. Call GDMA_Cmd() to enable GDMA.

    10. Call UART_INTConfig() to enable UART_INT_IDLE interrupt.

    11. Set uart_allow_enter_dlps to true to allow the system to enter DLPS mode.