IO

This document is intended to help beginners quickly become familiar with the peripherals of RTK MCU. It introduces various peripherals, including PINMUX, PAD, GPIO, TIMER, PWM, UART, GDMA, I2C, SPI, IR, RTC, LPC, 3-wire SPI, CapTouch, ADC, QDEC, KeyScan, SLEEP LED, I2S, SDIO peripherals. Additionally, this document covers an IO demo project, peripheral functions and features, hardware-related knowledge, peripheral operation flow, and corresponding demo code.

Each chapter is mainly divided into the following aspects to introduce peripherals.

  • Peripheral function description

  • Peripheral feature description

  • Introduction to hardware protocols

  • Basic hardware information of peripherals

  • Operation flow

  • Sample code description

Requirements

The sample supports the following development kits:

Hardware Platforms

Board Name

Build Target

RTL87x3E HDK

RTL87x3E EVB

io_demo_2M_bank0
io_demo_4M_bank0
io_demo_16M_bank0

RTL87x3D HDK

RTL87x3D EVB

io_demo_16M_bank0
io_demo_cs_16M_bank0

RTL87x3EP HDK

RTL87x3EP EVB

io_demo_4M_bank0
io_demo_16M_bank0

When built for an xxx_2M_xxx build target, the sample is configured to compile and run with a 2M flash map.

When built for an xxx_4M_xxx build target, the sample is configured to compile and run with a 4M flash map.

When built for an xxx_16M_xxx build target, the sample is configured to compile and run with a 16M flash map.

To quickly set up the development environment, please refer to the detailed instructions provided in Quick Start.

Configurations

Users can modify the macro definitions shown below in the sample code to configure the pins used in the example. For specific pin definitions, please refer to the list below:

#define UART_TX_PIN         P3_1
#define UART_RX_PIN         P3_0
#define UART_CTS_PIN        P0_0
#define UART_RTS_PIN        P0_1

Building and Downloading

The detailed information about building and downloading can be found in Building and Downloading.

This sample can be found under board\evb\io_demo in the SDK folder structure. Take the project rtl87x3e_io_demo.uvprojx and target io_demo_16M_bank0 as an example, to build and run the sample with the Keil development environment. Follow the steps listed below:

  1. Open rtl87x3e_io_demo.uvprojx.

  2. Choose the build target io_demo_16M_bank0.

  3. Build the target.

    After a successful compilation, the APP bin file io_demo_bank0_MP-v0.0.0.0-xxx.bin will be generated in the directory bin\rtl87x3e\flash_16M\bank0.

  4. Download the generated APP bin io_demo_bank0_MP-v0.0.0.0-xxx.bin into the EVB board.

  5. Press the reset button on the EVB board.

Experimental Verification

The detailed test procedure can be found in the list below:

Code Overview

The IO demo application overview will be introduced according to the following parts:

Source Code Directory

IO demo project shows how to use peripherals to communicate with other devices. A specific peripheral and its usage scenario can be changed to demonstrate, with its source files added to the build target and its demo functions called in main(). This section describes the project directory and project structure. The reference files directory is as follows:

  • Project directory: board\evb\io_demo.

  • Project source code directory: src\sample\io_demo.

Source files in the sample project are currently categorized into several groups as below.

└── Project: io_demo_16M_bank0
   ├── include                          ROM UUID header files. Users do not need to modify it.
   ├── lib                              Includes all binary symbol files that user application is built on.
   ├── cmsis                            The cmsis source code. Users do not need to modify it.
   ├── io_driver                        The IO driver code. Users do not need to modify it.
   ├── io_hal                           The IO HAL layer code. Users do not need to modify it.
   ├── app                              The application source code.
   ├── adc                              The ADC demo source code.
   ├── gdma                             The GDMA demo source code.
   ├── gpio                             The GPIO demo source code.
   ├── i2c                              The I2C demo source code.
   ├── ir                               The IR demo source code.
   ├── keyscan                          The KeyScan demo source code. RTL87x3EP doesn’t support it.
   ├── led                              The LED demo source code.
   ├── lpc                              The LPC demo source code.
   ├── qdec                             The QDEC demo source code.
   ├── rtc                              The RTC demo source code.
   ├── sdio                             The SDIO demo source code.
   ├── spi                              The SPI demo source code.
   ├── spi3w                            The 3-wire SPI demo source code. Only RTL87x3D supports it.
   ├── tim                              The TIMER and PWM demo source code.
   ├── uart                             The UART demo source code.
   ├── ctc                              The CapTouch demo source code. Only RTL87x3E supports it.
   ├── i2s                              The I2S demo source code.
   ├── dlps                             The DLPS demo source code.
   └── spi_external_flash               The SPI external flash demo source code.

Source Code Overview

This section describes some parts of the source code used in the application of this project.

Initialization

The main function is invoked when the application is powered on or the chip is reset, and it performs the following initialization functions:

RAM_TEXT_SECTION
int main(void)
{
    __enable_irq();
    WDG_Disable();

    IO_PRINT_INFO0("Hello io demo !");

    extern void gpio_int_demo(void);
    gpio_int_demo();

    os_sched_start();
}

The gpio_int_demo() function can be replaced by the demo entry function in the demo files, such as adc_demo() in the adc_demo.c file. Note that each demo entry function is independent of each other.

Initialization Flow

Peripheral initialization mainly consists of the following components:

  1. Set peripheral PINMUX and PAD.

  2. Enable peripheral clock signal.

  3. Set peripheral initialization parameters.

  4. Enable peripheral.

The initialization procedure is shown in the following figure, where ‘XXX’ is the name of the peripheral to be initialized, such as GPIO, I2C, or SPI.

Clock Configuration

Enable GPIO clock by calling RCC_PeriphClockCmd() function.

RCC_PeriphClockCmd(APBPeriph_GPIO, APBPeriph_GPIO_CLOCK, ENABLE);
PINMUX Configuration

Configure PINMUX status of the pin by calling Pinmux_Config() function.

/* Configure Pin P0_5 as GPIO function */
Pinmux_Config(P0_5, DWGPIO);

For optional pin values and map GPIO please reference the file below.

RTL87x3E: inc\rtl87x3e\platform\rtl876x.h

RTL87x3D: inc\rtl87x3d\platform\pin_def.h

RTL87x3EP: inc\rtl87x3ep\platform\pin_def.h

PAD Configuration

Configure the PAD status of the pin by calling Pad_Config() function.

Pad_Config(P0_5, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_HIGH);
Interrupt Configuration

Enable IRQ interrupt by calling NVIC_Init() function.

NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = GPIO5_IRQ;
NVIC_InitStruct.NVIC_IRQChannelPriority = 5;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);

Note

User IRQ priority should be set higher than 2 (priority lower than OS lock base priority), and less than 7 (system PendSV/SysTick ISR priority).

Initialize Peripheral

Initialize the peripheral by calling XXX_Init for each peripheral, and ‘XXX’ is the name of the peripheral to be initialized.

GPIOx_Init();
Disable Peripheral

Disable the peripheral by calling XXX_DeInit for each peripheral, and ‘XXX’ is the name of the peripheral to be disabled.

GPIOx_DeInit();

PINMUX and PAD

PAD Demo Code Support List

Demo 1

dlps_gpio_wk_demo.c

Sample Purpose

Demonstrates how PAD wakes up the system from DLPS mode.

Brief Introduction

This sample code demonstrates how PAD wakes up the system. TEST_Pin is set to low-level wake-up. The system will enter DLPS mode automatically while it’s in idle state. When TEST_Pin is pulled down to low level, the system is woken up.

File Path

sdk\src\sample\io_demo\dlps\dlps_gpio_wk_demo.c

Function Entry

dlps_gpio_wk_demo()

Pin Definition

#define TEST_Pin P0_0

Hardware Connection

When the system needs to be woken up, connect M0_0 to GND on EVB.

Expected Result

1. Press the reset button on the EVB, the string ‘dlps_store: enter dlps’ will be printed in Debug Analyzer, and the system will enter DLPS mode.
2. Then connect M0_0 to GND, the system will be woken up and print the string ‘dlps_restore: exit dlps’ in Debug Analyzer.

Function Description

PINMUX is an abbreviation for pin multiplexing. Because the SoC has a limited number of pins, pin multiplexing allows the SoC to use the limited pins for various functions, such as SPI, I2C, and GPIO.

PAD is used to control the behavior of a pin, such as pull-up or pull-down, output high or low level, and wake-up functions.

As shown in the figure below. The PINMUX circuit and IO modules are in the core domain and will be powered down during low power mode, so they cannot work during low power mode. The PAD circuit is in the AON domain and will not be powered down during low power mode, so the PAD can work normally during low power mode. The PAD is mainly used to maintain the pin output state or wake up the system in low power mode.

The PAD can be configured as PINMUX mode and software mode. Only when the PAD is set to PINMUX mode, can this pin be connected to the core domain to achieve pin multiplexing.

PAD Feature List

  • Two operating modes: PINMUX mode and software mode.

  • Configurable pin pull-up or pull-down resistors.

  • Configurable pin independently output high or low level in software mode.

  • Keep power during DLPS/power down mode, powered off in ship mode.

  • Wake up the system from DLPS and power down mode from high or low triggers on all the pins.

Hybrid PAD Usage

The Hybrid PAD can be configured in digital mode or analog mode. Configure the mode of the hybrid PAD by calling Pad_AnalogMode() function.

/* Configure MIC1_P as analog mode */
Pad_AnalogMode(MIC1_P, PAD_ANALOG_MODE);

When the hybrid PAD is configured in digital mode (GPIO, I2C, etc), the ‘AVCCDRV always on’ option needs to be configured as ‘Always active’ on the MCUConfig Tool.

Note

  1. RTL87x3D hybrid PAD: LOUT_N, P_UART, ROUT_N, ROUT_P, MIC1_N, MIC1_P, MIC2_N, MIC2_P, MIC3_N, MIC3_P, MIC4_N, MIC4_P, MIC5_N, MIC5_P, MIC6_N, MIC6_P, AUX_R, AUX_L, MICBIAS.

  2. RTL87x3E hybrid PAD: AUX_R, AUX_L, MIC1_P, MIC1_N, MIC2_P, MIC2_N, MICBIAS, LOUT_P, LOUT_N, ROUT_P, ROUT_N, MIC3_P, MIC3_N.

  3. RTL87x3EP hybrid PAD: DAOUT_P, DAOUT_N, MIC1_P, MIC1_N, MIC2_P, MIC2_N, MICBIAS.

GPIO

GPIO Demo Code Support List

Demo 1

gpio_input_demo.c

Sample Purpose

Demonstrates GPIO input mode.

Brief Introduction

This sample code demonstrates how to get the input level value of GPIO.

File Path

sdk\src\sample\io_demo\gpio\input\gpio_input_demo.c

Function Entry

gpio_input_demo()

GPIO Direction

Input mode

Pin Definition

#define TEST_Pin     ADC_1

Expected Result

Press the reset button on the EVB, the string ‘gpio_test: gpio_value 1’ will be printed in Debug Analyzer.

Demo 2

gpio_output_demo.c

Sample Purpose

Demonstrates GPIO output mode.

Brief Introduction

This sample code demonstrates how to use GPIO to output high and low levels.

File Path

sdk\src\sample\io_demo\gpio\output\gpio_output_demo.c

Function Entry

gpio_output_demo()

GPIO Direction

Output mode

Hardware Connection

As shown in GPIO Hardware Connection Diagram. On EVB, connect P0_1 and LED1, and connect P0_2 and LED2.

Pin Definition

#define TEST_PIN     P0_1
#define TEST_PIN_2     P0_2

Expected Result

Press the reset button on the EVB. LED1 and LED2 will light up or off when the output level is selected as high or low.

Demo 3

gpioab_output_demo.c

Sample Purpose

Demonstrates GPIOx output mode whether the pin belongs to GPIOA or B.

Brief Introduction

This sample code demonstrates the GPIOx output function. The output level value can be detected by connecting with LED.

File Path

sdk\src\sample\io_demo\gpio\output\gpio_a_b\gpioab_output_demo.c

Function Entry

gpioab_output_demo()

GPIO Direction

Output mode

Hardware Connection

As shown in GPIO Hardware Connection Diagram. On EVB, connect P4_3 and LED1.

Pin Definition

#define TEST_Pin     P4_3

Expected Result

Press the reset button on the EVB. LED1 will light up or off when the gpio_pin_bit is selected to Set or Reset.

Demo 4

gpioab_output_group_demo.c

Sample Purpose

Demonstrates GPIOx group output mode whether the pins belong to GPIOA or B.

Brief Introduction

This sample code demonstrates the GPIOx group output function. These output level values can be detected by connecting with LED.

File Path

sdk\src\sample\io_demo\gpio\output\gpio_a_b\gpioab_output_group_demo.c

Function Entry

gpioab_output_group_demo()

GPIO Direction

Output mode

Hardware Connection

As shown in GPIO Hardware Connection Diagram. On EVB, connect LED and test pin.

Expected Result

Press the reset button on the EVB. The LED will light up or off when the gpio_pin_bit is selected to Set or Reset.

Demo 5

gpio_int_demo.c

Sample Purpose

Demonstrates GPIO used as a key by edge trigger mode with hardware debounce.

Brief Introduction

This sample code demonstrates the detection of GPIO input through interrupt. When the button is pressed (such as P1_0 changing from high level to low level), the falling edge of GPIO is detected, and the GPIO interrupt is triggered. Then switch the edge trigger, after the button is released (P1_0 changes from low level to high level), the GPIO interrupt is triggered again.

File Path

sdk\src\sample\io_demo\gpio\interrupt\gpio_int_demo.c

Function Entry

gpio_int_demo()

GPIO Direction

Input mode

Hardware Connection

As shown in GPIO Hardware Connection Diagram. On EVB, connect P1_0, P1_1, P2_1, P2_2 to KEY1 ~ KEY4 respectively.

Pin Definition

#define GPIO_DEMO_INPUT_PIN0     P1_0
#define GPIO_DEMO_INPUT_PIN1     P1_1
#define GPIO_DEMO_INPUT_PIN2     P2_1
#define GPIO_DEMO_INPUT_PIN3     P2_2

Expected Result

Press the reset button on the EVB. Press KEY1 ~ KEY4: string ‘gpio_isr_cb: pin_name P1_0, gpio_level 0’ ‘gpio_isr_cb: pin_name P1_1, gpio_level 1’ ‘gpio_isr_cb: pin_name P2_1, gpio_level 0’ ‘gpio_isr_cb: pin_name P2_2, gpio_level 1’ will be printed in Debug Analyzer. Release KEY1 ~ KEY4: string ‘gpio_isr_cb: pin_name P1_0, gpio_level 1’ ‘gpio_isr_cb: pin_name P1_1, gpio_level 0’ ‘gpio_isr_cb: pin_name P2_1, gpio_level 1’ ‘gpio_isr_cb: pin_name P2_2, gpio_level 0’ will be printed in Debug Analyzer.

Demo 6

pad_int_demo.c

Sample Purpose

Demonstrates PAD interrupt mode to realize key detection.

Brief Introduction

This sample code demonstrates key detection by PAD interrupt mode. When the button is pressed (such as P1_0 changing from high level to low level), the low level of the pin is detected, and the system handler is triggered. Then switch the level trigger, after the button is released (P1_0 changes from low level to high level), the system handler is triggered again.

File Path

sdk\src\sample\io_demo\gpio\interrupt\pad_int_demo.c

Function Entry

pad_int_demo()

GPIO Direction

Input mode

Hardware Connection

As shown in GPIO Hardware Connection Diagram. On EVB, connect P1_0, P1_1, P2_1, P2_2 to KEY1 ~ KEY4 respectively.

Pin Definition

#define GPIO_DEMO_INPUT_PIN0     P1_0
#define GPIO_DEMO_INPUT_PIN1     P1_1
#define GPIO_DEMO_INPUT_PIN2     P2_1
#define GPIO_DEMO_INPUT_PIN3     P2_2

Expected Result

Press the reset button on the EVB. Press KEY1: string ‘system_handler: pin0 interrupt triggered, pin_0_state 0’ will be printed in Debug Analyzer. Release KEY1: string ‘system_handler: pin0 interrupt triggered, pin_0_state 1’ will be printed in Debug Analyzer.

Demo 7

gpio_key.c

Sample Purpose

Demonstrates GPIO used as a key by level trigger mode with TIMER debounce.

Brief Introduction

This sample code demonstrates the detection of GPIO input through interrupt. When the button is pressed (P0_0 changes from high level to low level), the low level of GPIO is detected, and the GPIO interrupt is triggered. Then restart the TIMER in the GPIO handler, after the 30ms debounce time, enter the TIMER handler to switch the level trigger, when the button is released (P1_0 changes from low level to high level), the GPIO interrupt is triggered again. Then the TIMER restarts again.

File Path

sdk\src\sample\io_demo\gpio\key\level_tim\gpio_key.c

Function Entry

gpio_key()

GPIO Direction

Input mode

Hardware Connection

As shown in GPIO Hardware Connection Diagram. On EVB, connect P0_0 and KEY1.

Pin Definition

#define KEY_PIN     ADC_0

Expected Result

Press the reset button on the EVB. Press KEY1: string ‘key_handler: key_status 0’ ‘debounce_hw_timer_callback: Key press’ will be printed in Debug Analyzer. Release KEY1: string ‘key_handler: key_status 1’ ‘debounce_hw_timer_callback: Key release’ will be printed in Debug Analyzer.

Demo 8

gpio_edge_key.c

Sample Purpose

Demonstrates GPIO used as a key by edge trigger mode with hardware debounce.

Brief Introduction

This sample code demonstrates the detection of GPIO input through interrupt. When the button is pressed (P0_0 changes from high level to low level), the falling edge of GPIO is detected, and the GPIO interrupt is triggered. Then switch the edge trigger, after the button is released (P0_0 changes from low level to high level), the GPIO interrupt is triggered again.

File Path

sdk\src\sample\io_demo\gpio\key\edge\gpio_edge_key.c

Function Entry

gpio_edge_key()

GPIO Direction

Input mode

Hardware Connection

As shown in GPIO Hardware Connection Diagram. On EVB, connect P0_0 and KEY1.

Pin Definition

#define KEY_PIN     ADC_0

Expected Result

Press the reset button on the EVB. Press KEY1: string ‘key_handler: Key press’ will be printed in Debug Analyzer. Release KEY1: string ‘key_handler: Key release’ will be printed in Debug Analyzer.

Demo 9

dma_tim_demo.c

Sample Purpose

Demonstrates how GDMA controls GPIO output.

Brief Introduction

This sample code demonstrates how to use TIMER to toggle GDMA to control GPIO to output high and low levels of specified lengths.

File Path

sdk\src\sample\io_demo\gdma\multiblock_tim_gpio\dma_tim_demo.c

GPIO Direction

Output mode

GDMA Direction

Memory to Peripheral

Function Entry

ma_tim_demo()

Pin Definition

#define PIN_OUT     ADC_2

Expected Result

Press the reset button on the EVB. Use a Logic Analyzer to capture the waveform of P0_2, and the output waveform results of single-block or multi-block are shown in GPIO GDMA Result Diagram.

Function Description

The GPIO integrated core is programmable general-purpose input/output. Each GPIO pin can be configured by software as an output, input, or interrupt peripheral function.

Feature List

  • 32 independently configured GPIO signals in every port, with independently controllable signal bits.

  • Support hardware and software control.

  • Support input and output control.

  • Support level-triggered and edge-triggered interrupts.

  • Support low and high level-triggered interrupts.

  • Support rising and falling edge-triggered interrupts.

  • Support both-edge-triggered interrupts.

  • Support hardware debounce function.

  • Support GPIO+TIMER+GDMA function.

Note

  1. RTL87x3D supports 3 ports. RTL87x3E and RTL87x3EP support 2 ports.

  2. When the GPIO is controlled by GDMA, it should be configured in hardware mode.

GPIO Initialization Flow

The GPIO initialization flow is shown in the following figure.

Input Mode

The codes below demonstrate the operation flow of GPIO in input mode.

hal_gpio_init();
hal_gpio_init_pin(TEST_Pin, GPIO_TYPE_AUTO, GPIO_DIR_INPUT, GPIO_PULL_UP);

gpio_value = hal_gpio_get_input_level(TEST_Pin);

Output Mode

The codes below demonstrate the operation flow of GPIO in output mode.

hal_gpio_init();
hal_gpio_init_pin(TEST_PIN, GPIO_TYPE_CORE, GPIO_DIR_OUTPUT, GPIO_PULL_UP);
hal_gpio_init_pin(TEST_PIN_2, GPIO_TYPE_AON, GPIO_DIR_OUTPUT, GPIO_PULL_UP);

for (uint16_t i = 0; i < 10; i++)
{
    hal_gpio_set_level(TEST_PIN, GPIO_LEVEL_LOW);
    hal_gpio_set_level(TEST_PIN_2, GPIO_LEVEL_LOW);
    hal_gpio_set_level(TEST_PIN, GPIO_LEVEL_HIGH);
    hal_gpio_set_level(TEST_PIN_2, GPIO_LEVEL_HIGH);
}

Interrupt Mode

The codes below demonstrate the operation flow of GPIO in interrupt mode.

hal_gpio_init();
hal_gpio_int_init();
hal_gpio_set_debounce_time(30);

hal_gpio_init_pin(GPIO_DEMO_INPUT_PIN0, GPIO_TYPE_AUTO, GPIO_DIR_INPUT, GPIO_PULL_UP);
hal_gpio_init_pin(GPIO_DEMO_INPUT_PIN1, GPIO_TYPE_AUTO, GPIO_DIR_INPUT, GPIO_PULL_DOWN);
hal_gpio_init_pin(GPIO_DEMO_INPUT_PIN2, GPIO_TYPE_AUTO, GPIO_DIR_INPUT, GPIO_PULL_UP);
hal_gpio_init_pin(GPIO_DEMO_INPUT_PIN3, GPIO_TYPE_AUTO, GPIO_DIR_INPUT, GPIO_PULL_DOWN);

hal_gpio_set_up_irq(GPIO_DEMO_INPUT_PIN0, GPIO_IRQ_EDGE, GPIO_IRQ_ACTIVE_LOW, true);
hal_gpio_set_up_irq(GPIO_DEMO_INPUT_PIN1, GPIO_IRQ_EDGE, GPIO_IRQ_ACTIVE_HIGH, true);
hal_gpio_set_up_irq(GPIO_DEMO_INPUT_PIN2, GPIO_IRQ_EDGE, GPIO_IRQ_ACTIVE_LOW, true);
hal_gpio_set_up_irq(GPIO_DEMO_INPUT_PIN3, GPIO_IRQ_EDGE, GPIO_IRQ_ACTIVE_HIGH, true);

hal_gpio_register_isr_callback(GPIO_DEMO_INPUT_PIN0, gpio_isr_cb, GPIO_DEMO_INPUT_PIN0);
hal_gpio_register_isr_callback(GPIO_DEMO_INPUT_PIN1, gpio_isr_cb, GPIO_DEMO_INPUT_PIN1);
hal_gpio_register_isr_callback(GPIO_DEMO_INPUT_PIN2, gpio_isr_cb, GPIO_DEMO_INPUT_PIN2);
hal_gpio_register_isr_callback(GPIO_DEMO_INPUT_PIN3, gpio_isr_cb, GPIO_DEMO_INPUT_PIN3);

hal_gpio_irq_enable(GPIO_DEMO_INPUT_PIN0);
hal_gpio_irq_enable(GPIO_DEMO_INPUT_PIN1);
hal_gpio_irq_enable(GPIO_DEMO_INPUT_PIN2);
hal_gpio_irq_enable(GPIO_DEMO_INPUT_PIN3);

TIMER and PWM

TIMER and PWM Demo Code Support List

Demo 1

tim_demo.c

Sample Purpose

Demonstrates how TIMER module works in reload mode and it will trigger the interrupt every 3 seconds.

File Path

sdk\src\sample\io_demo\tim\interrupt\tim_demo.c

Function Entry

tim_demo()

Timeout

3 seconds

Expected Result

Print string ‘demo_hw_timer_callback’ in Debug Analyzer every 3 seconds.

Demo 2

pwm_demo.c

Sample Purpose

Demonstrates PWM output, PWM complementary output, and deadzone.

File Path

sdk\src\sample\io_demo\tim\pwm\pwm_demo.c

Function Entry

pwm_demo()

Pin Definition

#define PWM_OUT_PIN     ADC_0
#define PWM_OUT_PIN_P     ADC_2
#define PWM_OUT_PIN_N     ADC_3

Hardware Connection

Connect M0_0 of EVB to channel 0 of the logic analyzer, connect M0_2 of EVB to channel 1 of the logic analyzer, and connect M0_3 of EVB to channel 2 of the logic analyzer.

Expected Result

The waveforms displayed by channels 0/1/2 of the logic analyzer are shown in PWM Demo Expected Result Diagram.

Demo 3

led_demo_task.c
sw_led_demo.c
sw_led_demo.h

Sample Purpose

Demonstrates how to achieve the effect of breath and blink LED with PWM.

File Path

sdk\src\sample\io_demo\led\led_demo_task.c
sdk\src\sample\io_demo\led\sw_led_demo.c
sdk\src\sample\io_demo\led\sw_led_demo.h

Function Entry

led_demo_task()

Pin Definition

#define LED_OUT_0     ADC_1
#define LED_OUT_1     P2_1
#define LED_OUT_2     P2_2

Hardware Connection

On EVB, connect M2_1 to LED0, connect M2_2 to LED1, and connect M2_7 to LED2.

Expected Result

LEDs turn from dark to bright and then from bright to dark with the effect of breath light.

Function Description

The TIMER consists of a 32-bit automatic load counter. Each TIMER is completely independent and does not share any resources. They can operate synchronously together. The TIMER can operate in two modes: user-defined count mode and free-running mode. In user-defined count mode, the TIMER counts down from the value set by the user. In free-running mode, the TIMER counts down from 0xffffffff. When the TIMER counter is enabled after being reset or disabled, the TIMER counts down from its initial value, and when it reaches 0, an interrupt is triggered.

Feature List

  • Two operation modes: user-defined count mode and free-running mode.

  • TIMER counter width: 32 bits.

  • Support PWM output mode.

  • TIMER 2 and TIMER 3 support PWM complementary output mode.

  • TIMER 2 and TIMER 3 support deadzone.

  • TIMER 2 and TIMER 3 support emergency stop control.

Note

  1. RTL87x3D supports up to 16 TIMER, 12 of which can be used for application.

  2. RTL87x3E supports up to 8 TIMER, 5 of which can be used for application.

  3. RTL87x3EP supports up to 12 TIMER, 9 of which can be used for application, but only 5 of which can be used for the PWM function.

  4. TIMER 0 and TIMER 1 are reserved for low stack. TIMER 7 is reserved for log time stamp.

TIMER Operation Flow

The codes below demonstrate the TIMER operation flow. For details, please refer to src\sample\io_demo\tim\interrupt\tim_demo.c.

void tim_driver_init(void)
{
    /* Create the timer, user-defined mode, the period is 3 seconds. */
    demo_timer_handle = hw_timer_create("demo_hw_timer", 3000 * 1000, true, demo_hw_timer_callback);
    if (demo_timer_handle == NULL)
    {
        IO_PRINT_ERROR0("tim_driver_init: fail to create hw timer, check hw timer usage");
        return;
    }

    IO_PRINT_TRACE1("tim_driver_init: create hw timer instance successfully, id %d",
                    hw_timer_get_id(demo_timer_handle));

    /* Start the specified timer */
    hw_timer_start(demo_timer_handle);
}

When the TIMER counter reaches to zero, the interrupt will be triggered and the callback will be executed. The codes below demonstrate the TIMER callback handle flow.

void demo_hw_timer_callback(T_HW_TIMER_HANDLE handle)
{
    //Add User code here
    IO_PRINT_TRACE0("demo_hw_timer_callback");
}

PWM Operation Flow

The codes below demonstrate the PWM operation flow. For details, please refer to src\sample\io_demo\tim\pwm\pwm_demo.c.

static void driver_pwm_init(void)
{
    T_PWM_CONFIG demo_pwm_deadzone_para;

    /* Create the PWM, high-level time is 2 seconds, low-level time is 2 seconds */
    demo_pwm_handle = pwm_create("demo_pwm", PWM_HIGH_LEVEL_CNT, PWM_LOW_LEVEL_CNT, false);
    if (demo_pwm_handle == NULL)
    {
        IO_PRINT_ERROR0("driver_pwm_init: Fail to create pwm handle");
        return;
    }

    /* Configure PIN ADC_0 as PWM output */
    pwm_pin_config(demo_pwm_handle, PWM_OUT_PIN, PWM_FUNC);
    /* Start the specified PWM */
    pwm_start(demo_pwm_handle);

    /* Create the PWM, deadzone is enabled. */
    demo_pwm_deadzone_handle = pwm_create("demo_pwm_deadzone", PWM_HIGH_LEVEL_CNT, PWM_LOW_LEVEL_CNT,
                                          true);
    if (demo_pwm_deadzone_handle == NULL)
    {
        IO_PRINT_ERROR0("driver_pwm_init: Fail to create pwm deadzone handle");
        return;
    }

    /* Set high-level time */
    demo_pwm_deadzone_para.pwm_high_count = PWM_HIGH_LEVEL_CNT;
    /* Set low-level time */
    demo_pwm_deadzone_para.pwm_low_count = PWM_LOW_LEVEL_CNT;
    /* Enable deadzone */
    demo_pwm_deadzone_para.pwm_deadzone_enable = ENABLE;
    /* Configure PWM clock source as 1MHz */
    demo_pwm_deadzone_para.clock_source = PWM_CLOCK_1M;
    /* Set deadzone size count, count frequency is 32K */
    demo_pwm_deadzone_para.pwm_deadzone_size = PWM_DEADZONE_SIZE_CNT;
    /* Configure PWM_P emergency stop state as low-level */
    demo_pwm_deadzone_para.pwm_p_stop_state = PWM_DEAD_ZONE_STOP_LOW;
    /* Configure PWM_N emergency stop state as high-level */
    demo_pwm_deadzone_para.pwm_n_stop_state = PWM_DEAD_ZONE_STOP_HIGH;
    /* Initialize PWM */
    pwm_config(demo_pwm_deadzone_handle, &demo_pwm_deadzone_para);

    /* Configure PIN ADC_2 as PWM_P output */
    pwm_pin_config(demo_pwm_deadzone_handle, PWM_OUT_PIN_P, PWM_FUNC_P);
    /* Configure PIN ADC_3 as PWM_N output */
    pwm_pin_config(demo_pwm_deadzone_handle, PWM_OUT_PIN_N, PWM_FUNC_N);
    /* Start the specified PWM */
    pwm_start(demo_pwm_deadzone_handle);
}

UART

UART Demo Code Support List

Demo 1

uart_polling_demo.c

Sample Purpose

Demonstrate how UART sends and receives data in polling mode.

Brief Introduction

This sample code demonstrates the communication between chip and PC. PC transmits some data to chip and then chip returns the same data received to PC.

File Path

sdk\src\sample\io_demo\uart\polling\uart_polling_demo.c

Function Entry

uart_polling_demo()

Hardware Connection

As shown in UART Demo 1/2/3/5 Hardware Connection Diagram.
RTL87x3E: On EVB, TX is connected to M3_0, RX is connected to M3_1, FT_VIO is connected to VIO1, and CON3 is connected to PC.
RTL87x3D: On EVB, TXD is connected to M3_0, RXD is connected to M3_1, FT_VIO is connected to VIO1, and P2 is connected to PC.

UART TX Pin Definition

#define UART_TX_PIN P3_1

UART RX Pin Definition

#define UART_RX_PIN P3_0

UART ID

UART0

Baud Rate

115200

Parity Check

No Parity

Data Format

8-Bit

Stop Bit

1-Bit

Hardware Flow Control

None

Expected Result

1. Press the reset button on the EVB, string ‘### Welcome to use RealTek Bumblebee ###\r\n’ will be displayed in UART debug tool.
2. Use UART debug tool to send data to chip, then chip will send the received same data back to PC and display the data in UART debug tool.

Demo 2

uart_demo.c

Sample Purpose

Demonstrate how UART receives data in interrupt mode.

Brief Introduction

This sample code demonstrates the communication between chip and PC. PC transmits some data to chip and then chip returns the same data received to PC.

File Path

sdk\src\sample\io_demo\uart\interrupt\uart_demo.c

Function Entry

uart_demo()

Hardware Connection

As shown in UART Demo 1/2/3/5 Hardware Connection Diagram.
RTL87x3E: On EVB, TX is connected to M3_0, RX is connected to M3_1, FT_VIO is connected to VIO1, and CON3 is connected to PC.
RTL87x3D: On EVB, TXD is connected to M3_0, RXD is connected to M3_1, FT_VIO is connected to VIO1, and P2 is connected to PC.

UART TX Pin Definition

#define UART_TX_PIN P3_1

UART RX Pin Definition

#define UART_RX_PIN P3_0

UART ID

UART0

Baud Rate

115200

Parity Check

No Parity

Data Format

8-Bit

Stop Bit

1-Bit

Hardware Flow Control

None

Expected Result

1. Press the reset button on the EVB, string ‘### Welcome to use RealTek Bumblebee ###\r\n’ will be displayed in UART debug tool.
2. Use UART debug tool to send data to chip, then chip will send the received same data plus string ‘\r\n’ back to PC and display the data in UART debug tool.

Demo 3

uart_tx_demo.c

Sample Purpose

Demonstrate how UART sends data in interrupt mode.

Brief Introduction

This sample code demonstrates the communication between chip and PC. Chip transmits some data to PC.

File Path

sdk\src\sample\io_demo\uart\interrupt\uart_tx_demo.c

Function Entry

uart_tx_demo()

Hardware Connection

As shown in UART Demo 1/2/3/5 Hardware Connection Diagram.
RTL87x3E: On EVB, TX is connected to M3_0, RX is connected to M3_1, FT_VIO is connected to VIO1, and CON3 is connected to PC.
RTL87x3D: On EVB, TXD is connected to M3_0, RXD is connected to M3_1, FT_VIO is connected to VIO1, and P2 is connected to PC.

UART TX Pin Definition

#define UART_TX_PIN P3_1

UART RX Pin Definition

#define UART_RX_PIN P3_0

UART ID

UART0

Baud Rate

115200

Parity Check

No Parity

Data Format

8-Bit

Stop Bit

1-Bit

Hardware Flow Control

None

Expected Result

Press the reset button on the EVB, string ‘### Welcome to use RealTek Bumblebee ###\r\n’ will be displayed in UART debug tool.

Demo 4

uart_fc_demo.c

Sample Purpose

Demonstrate how UART sends and receives data with hardware flow control.

Brief Introduction

This sample code demonstrates the communication between chip and PC. PC transmits some data to chip and then chip returns the same data received to PC.

File Path

sdk\src\sample\io_demo\uart\hw_flow_control\uart_fc_demo.c

Function Entry

uart_fc_demo()

Hardware Connection

As shown in UART Demo 4 Hardware Connection Diagram.
RTL87x3E: On EVB, TX is connected to M3_0, RX is connected to M3_1, RTS is connected to M0_0, CTS is connected to M0_1, FT_VIO is connected to VIO1, and CON3 is connected to PC.
RTL87x3D: On EVB, TXD is connected to M3_0, RXD is connected to M3_1, RTS is connected to M0_0, CTS is connected to M0_1, FT_VIO is connected to VIO1, and P2 is connected to PC.

UART TX Pin Definition

#define UART_TX_PIN P3_1

UART RX Pin Definition

#define UART_RX_PIN P3_0

UART CTS Pin Definition

#define UART_CTS_PIN P0_0

UART RTS Pin Definition

#define UART_RTS_PIN P0_1

UART ID

UART0

Baud Rate

115200

Parity Check

No Parity

Data Format

8-Bit

Stop Bit

1-Bit

Hardware Flow Control

CTS and RTS Flow Control.

Expected Result

1. Press the reset button on the EVB, string ‘### Uart demo–Auto Hardware Flow Contrl ###\r\n’ will be displayed in UART debug tool.
2. Use UART debug tool to send data to chip, then chip will send the received same data plus string ‘\r\n’ back to PC and display the data in UART debug tool.

Demo 5

dlps_uart_demo.c

Sample Purpose

Demonstrates how UART wakes up the system from DLPS mode.

Brief Introduction

This sample code demonstrates the communication between chip and PC. It realizes the function that transmits and receives data through UART and wakes up the system by UART after entering DLPS mode. System will enter DLPS mode automatically while it is in idle state. When some data is sent to chip, UART_RX_PIN will be pulled down to low level and wake up system to rebuild communication between PC and chip.

File Path

sdk\src\sample\io_demo\uart\dlps\dlps_uart_demo.c

Function Entry

dlps_uart_demo()

Hardware Connection

As shown in UART Demo 1/2/3/5 Hardware Connection Diagram.
RTL87x3E: On EVB, TX is connected to M3_0, RX is connected to M3_1, FT_VIO is connected to VIO1, and CON3 is connected to PC.
RTL87x3D: On EVB, TXD is connected to M3_0, RXD is connected to M3_1, FT_VIO is connected to VIO1, and P2 is connected to PC.

UART TX Pin Definition

#define UART_TX_PIN P3_1

UART RX Pin Definition

#define UART_RX_PIN P3_0

UART ID

UART2

Baud Rate

115200

Parity Check

No Parity

Data Format

8-Bit

Stop Bit

1-Bit

Hardware Flow Control

None

Expected Result

1. Press the reset button on the EVB, string ‘### Welcome to use RealTek Bumblebee ###\r\n’ will be displayed in UART debug tool.
2. When system is in idle state, it will enter DLPS mode automatically.
3. The first group of data will be sent to chip to wake up system and then data can be transmitted normally. Chip will send the data same as the data received back to PC, which will be displayed in UART debug tool.

Demo 6

adp_1wire_uart_demo.c

Sample Purpose

Demonstrates how adapter one-wire works.

Brief Introduction

This sample code demonstrates how adapter one-wire works. When the adapter plugs in, it works as UART RX. When the adapter plugs out, it works as GPIO.

File Path

sdk\src\sample\io_demo\adp_1wire\adp_1wire_uart_demo.c

Function Entry

adp_1wire_uart_demo()

Hardware Connection

As shown in UART Demo 6 Hardware Connection Diagram. On EVB, TX of FT232 is connected to VADP.
RTL87x3E: On EVB, the capacitance of ADPIN on PCB needs to be replaced by 100pF.
RTL87x3D: The daughter board changes C186 to 100pf. The motherboard removes C164, DP38 and C71, and raises VAUX1 to 3.3V, connecting VIO4 to VAUX1

UART RX Pin Definition

RTL87x3D: #define ADP_PIN P_UART
RTL87x3E: #define ADP_PIN P10_0

UART ID

UART0

Baud Rate

9600

Parity Check

No Parity

Data Format

8-Bit

Stop Bit

1-Bit

Hardware Flow Control

None

Expected Result

1. Press the reset button on the EVB.
2. When the TX of FT232 is connected to VADP, the string ‘adp_io_in_out: adp io in’ will be displayed in Debug Analyzer, and chip can receive uart data from PC.
3. When the TX of FT232 is disconnected from VADP, the string ‘adp_io_in_out: adp io out’ will be displayed in Debug Analyzer.

Function Description

UART provides a flexible method for full-duplex data exchange with external devices. The UART utilizes a fractional baud rate generator to provide a wide range of baud rate options. It supports half-duplex single-wire communication. UART can also be used with GDMA to achieve high-speed data communication..

Feature List

  • Support 1-bit or 2-bit stop bit.

  • Support 7-bit or 8-bit data format.

  • Support odd or even parity.

  • Support hardware flow control.

  • Programmable baud rate.

  • Support GDMA.

  • Support one-wire UART.

Note

RTL87x3D supports 4 UART. RTL87x3E and RTL87x3EP support 3 UART. UART1 is used as log UART.

Data Format

The schematic diagram of the 7-bit data format is shown in the following figure.

The schematic diagram of the 8-bit data format is shown in the following figure.

Parity Check

  • Odd Parity

    Odd parity means that the number of ‘1’ in the data bits and check bit is odd. When the number of ‘1’ in the data bits is odd, the check bit is ‘0’; otherwise, it is ‘1’.

  • Even Parity

    Even parity means that the number of ‘1’ in the data bits and check bit is even. When the number of ‘1’ in the data bits is even, the check bit is ‘0’; otherwise, it is ‘1’.

Hardware Flow Control

The schematic diagram of hardware flow control is shown in the following figure.

  • RTS Flow Control

    When the UART receiver is ready to accept new data, RTS becomes valid, and the low level is valid. When the number of data in the RX FIFO reaches the set RX trigger level, RTS becomes invalid (high level is invalid), thereby indicating that it is desired to stop data transmission at the end of the current frame.

  • CTS Flow Control

    The transmitter checks the CTS before sending the next frame. If CTS is valid (low level is valid), the next data is sent; otherwise, the next frame data is not sent. If the CTS becomes invalid (high level is invalid) during transmission, the transmission is stopped after the current transmission is completed.

Baud Rate

Set the baud rate by configuring the variables div, ovsr, and ovsr_adj. UART baud rate table is shown below.

Baud Rate

Variable div

Variable ovsr

Variable ovsr_adj

1200

2589

7

0x7F7

9600

271

10

0x24A

14400

271

5

0x222

19200

123

11

0x6FF

28800

82

11

0x6FF

38400

85

7

0x222

57600

41

11

0x6FF

76800

35

9

0x7EF

115200

20

12

0x252

128000

25

7

0x555

153600

15

12

0x252

230400

10

12

0x252

460800

5

12

0x252

500000

8

5

0

921600

3

9

0x2AA

1000000

4

5

0

1382400

2

9

0x2AA

1444400

2

8

0x5F7

1500000

2

8

0x492

1843200

2

5

0x3F7

2000000

2

5

0

2100000

2

14

0x400

2764800

1

9

0x2AA

3000000

1

8

0x492

Initialization Flow

UART initialization flow is shown in the following figure.

The codes below demonstrate the UART interrupt handle flow.

/* Enable UART0 clock */
RCC_PeriphClockCmd(APBPeriph_UART0, APBPeriph_UART0_CLOCK, ENABLE);

UART_InitTypeDef uartInitStruct;
/* Fill each UART_InitTypeDef member variable with its default value */
UART_StructInit(&uartInitStruct);

/* Change default rx trigger level */
uartInitStruct.rxTriggerLevel = UART_RX_FIFO_TRIGGER_LEVEL_14BYTE;

UART_Init(UART0, &uartInitStruct);

//enable rx interrupt and line status interrupt
UART_INTConfig(UART0, UART_INT_RD_AVA | UART_INT_LINE_STS | UART_INT_IDLE, ENABLE);

RamVectorTableUpdate(UART0_VECTORn, (IRQ_Fun)Data_Uart_Handler);

NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = UART0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);

Receive Data by Interrupt Mode

UART interrupt handle flow is shown in the following figure.

The codes below demonstrate the UART interrupt handle flow.

void data_uart_handler(void)
{
    uint8_t event = IO_DEMO_EVENT_UART_RX;
    uint32_t int_status = 0;
    uint8_t recv_len;
    uint8_t line_status = 0;

    if (UART_GetFlagState(UART0, UART_FLAG_RX_IDLE) == SET)
    {
        UART_INTConfig(UART0, UART_INT_IDLE, DISABLE);
        if (os_msg_send(io_queue_handle, &event, 0) == false)
        {
            IO_PRINT_ERROR0("data_uart_handler: Send Queue Error");
        }
        //user code here

        UART_INTConfig(UART0, UART_INT_IDLE, ENABLE);
    }

    /* read interrupt id */
    int_status = UART_GetIID(UART0);

    switch (int_status)
    {
    /* tx fifo empty, not enable */
    case UART_INT_ID_TX_EMPTY:
        break;

    /* rx data available */
    case UART_INT_ID_RX_LEVEL_REACH:
        recv_len = UART_GetRxFIFOLen(UART0);
        UART_ReceiveData(UART0, &RxBuffer[RxCount], recv_len);
        RxCount += recv_len;
        break;

    case UART_INT_ID_RX_TMEOUT:
        recv_len = UART_GetRxFIFOLen(UART0);
        UART_ReceiveData(UART0, &RxBuffer[RxCount], recv_len);
        RxCount += recv_len;

        break;

    /* receive line status interrupt */
    case UART_INT_ID_LINE_STATUS:
        line_status = UART_GetLineStatus(UART0);
        IO_PRINT_ERROR1("data_uart_handler: line_status 0x%x", line_status);
        UART_SendByte(UART0, line_status);
        break;

    default:
        break;
    }

    return;
}

Send Data

UART interrupt handle flow is shown in the following figure.

The codes below demonstrate the UART interrupt handle flow.

static void uart_send_data(uint8_t *buf, uint32_t len)
{
    uint32_t tx_len = len > UART_TX_FIFO_SIZE ? UART_TX_FIFO_SIZE : len;

    UART_SendData(UART0, buf, tx_len);

    uart_tx_curr_addr = buf + tx_len;
    uart_tx_len = len - tx_len;

    UART_INTConfig(UART0, UART_INT_FIFO_EMPTY, ENABLE);
}

static void uart0_interrupt_handler(void)
{
    uint32_t int_status = 0;

    /* read interrupt id */
    int_status = UART_GetIID(UART0);

    switch (int_status)
    {
    /* tx fifo empty */
    case UART_INT_ID_TX_EMPTY:
        UART_INTConfig(UART0, UART_INT_FIFO_EMPTY, DISABLE);
        UART_GetIID(UART0);
        if (uart_tx_len)
        {
            uart_send_data(uart_tx_curr_addr, uart_tx_len);
        }
        break;

    /* rx data available */
    case UART_INT_ID_RX_LEVEL_REACH:
        break;

    case UART_INT_ID_RX_TMEOUT:
        break;

    /* receive line status interrupt */
    case UART_INT_ID_LINE_STATUS:
        break;

    default:
        break;
    }
    return;
}

GDMA

GDMA Demo Code Support List

Demo 1

gdma_demo.c

Sample Purpose

Demonstrate memory to memory by GDMA.

Brief Introduction

This sample code demonstrates memory to memory by GDMA. The data in GDMA_SendBuffer is transferred to GDMA_RecvBuffer.

File Path

sdk\src\sample\io_demo\gdma\memtomem\gdma_demo.c

Function Entry

gdma_demo()

GDMA DIR

GDMA_DIR_MemoryToMemory

GDMA BufferSize

100

GDMA SourceInc

DMA_SourceInc_Inc

GDMA DestinationInc

DMA_DestinationInc_Inc

GDMA SourceDataSize

GDMA_DataSize_Byte

GDMA DestinationDataSize

GDMA_DataSize_Byte

GDMA SourceMsize

GDMA_Msize_1

GDMA DestinationMsize

GDMA_Msize_1

GDMA SourceAddr

GDMA_SendBuffer

GDMA DestinationAddr

GDMA_RecvBuffer

Expected Result

1. Press the reset button on the EVB.
2. The data in GDMA_RecvBuffer is the same as in GDMA_SendBuffer.

Demo 2

dma_multiblock_demo.c

Sample Purpose

Demonstrate how GDMA multi-block function works.

Brief Introduction

This sample code demonstrates how GDMA multi-block function works. The data in GDMA_SendBuffer is transferred to GDMA_RecvBuffer.

File Path

sdk\src\sample\io_demo\gdma\multiblock\dma_multiblock_demo.c

Function Entry

dma_multiblock_demo()

GDMA DIR

GDMA_DIR_MemoryToMemory

GDMA BufferSize

100

GDMA SourceInc

DMA_SourceInc_Inc

GDMA DestinationInc

DMA_DestinationInc_Inc

GDMA SourceDataSize

GDMA_DataSize_Byte

GDMA DestinationDataSize

GDMA_DataSize_Byte

GDMA SourceMsize

GDMA_Msize_1

GDMA DestinationMsize

GDMA_Msize_1

GDMA SourceAddr

GDMA_SendBuffer

GDMA DestinationAddr

GDMA_RecvBuffer

GDMA Multi-Block Mode

LLI_TRANSFER

Expected Result

1. Press the reset button on the EVB.
2. The data in GDMA_RecvBuffer is the same as in GDMA_SendBuffer.

Demo 3

dma_scrgar_demo.c

Sample Purpose

Demonstrate memory to memory transfer by scatter/gather GDMA.

Brief Introduction

This sample code demonstrates how GDMA scatter/gather function works. The data in GDMA_SendBuffer_5 is transferred to GDMA_RecvBuffer_5.

File Path

sdk\src\sample\io_demo\gdma\multiblock\dma_scrgar_demo.c

Function Entry

dma_scrgar_demo()

GDMA DIR

GDMA_DIR_MemoryToMemory

GDMA BufferSize

20

GDMA SourceInc

DMA_SourceInc_Inc

GDMA DestinationInc

DMA_DestinationInc_Inc

GDMA SourceDataSize

GDMA_DataSize_Byte

GDMA DestinationDataSize

GDMA_DataSize_Byte

GDMA SourceMsize

GDMA_Msize_1

GDMA DestinationMsize

GDMA_Msize_1

GDMA SourceAddr

GDMA_SendBuffer_5

GDMA DestinationAddr

GDMA_RecvBuffer_5

GDMA Scatter Mode

ENABLE

GDMA Scatter Count

4

GDMA Scatter Interval

4

Expected Result

1. Press the reset button on the EVB.
2. The data in GDMA_SendBuffer_5 is transferred to GDMA_RecvBuffer_5 in 4-byte packets and with 4-byte intervals.

Demo 4

uart_rx_dma.c

Sample Purpose

Demonstrate how UART receives data by GDMA.

Brief Introduction

This sample code demonstrates the communication between chip and PC. PC transmits some data to chip.

File Path

sdk\src\sample\io_demo\gdma\uart_idle_rx\uart_rx_dma.c

Function Entry

uart_rx_dma()

Hardware Connection

As shown in UART Demo 1/2/3/5 Hardware Connection Diagram.
RTL87x3E: On EVB, TX is connected to M3_0, RX is connected to M3_1, FT_VIO is connected to VIO1, and CON3 is connected to PC.
RTL87x3D: On EVB, TXD is connected to M3_0, RXD is connected to M3_1, FT_VIO is connected to VIO1, and P2 is connected to PC.

UART TX Pin Definition

#define UART_TX_PIN P3_1

UART RX Pin Definition

#define UART_RX_PIN P3_0

UART ID

UART0

Baud Rate

3000000

Parity Check

No Parity

Data Format

8-Bit

Stop Bit

1-Bit

Hardware Flow Control

None

Expected Result

1. Press the reset button on the EVB, string ‘### Welcome to use RealTek Bumblebee ###\r\n’ will be displayed in UART debug tool.
2. Use UART debug tool to send data to chip, then data will be stored in array uart_receive_buf.

Demo 5

uart_tx_gdma.c

Sample Purpose

Demonstrate how UART sends data by GDMA.

Brief Introduction

This sample code demonstrates the communication between chip and PC. Chip transmits some data to PC.

File Path

sdk\src\sample\io_demo\gdma\uart_tx\uart_tx_gdma.c

Function Entry

uart_tx_gdma()

Hardware Connection

As shown in UART Demo 1/2/3/5 Hardware Connection Diagram.
RTL87x3E: On EVB, TX is connected to M3_0, RX is connected to M3_1, FT_VIO is connected to VIO1, and CON3 is connected to PC.
RTL87x3D: On EVB, TXD is connected to M3_0, RXD is connected to M3_1, FT_VIO is connected to VIO1, and P2 is connected to PC.

UART TX Pin Definition

#define UART_TX_PIN P3_1

UART RX Pin Definition

#define UART_RX_PIN P3_0

UART ID

UART0

Baud Rate

115200

Parity Check

No Parity

Data Format

8-Bit

Stop Bit

1-Bit

Hardware Flow Control

None

Expected Result

Press the reset button on the EVB, string ‘### Welcome to use RealTek Bumblebee ###\r\n’ will be displayed in UART debug tool.

Demo 6

adc_gdma_demo.c

Sample Purpose

Demonstrate how ADC samples data in continuous mode by GDMA.

Brief Introduction

Use continuous mode of ADC peripheral to measure voltage on P0_0 and P0_1.

File Path

sdk\src\sample\io_demo\gdma\adc_dma\adc_gdma_demo.c

Function Entry

adc_gdma_demo()

Pre-Condition

Turn off ‘Charger auto enable’ and ‘Battery detection support’ on the MCUConfig Tool.

Channel

ADC0
ADC1

External Channel Input Mode

ADC0 and ADC1 are divide mode.

Hardware Connection

Connect M0_0 and M0_1 of EVB to external DC voltage source. Input voltage of M0_0 and M0_1 must range from 0 to 3.3V.

Expected Result

Press the reset button on the EVB, ADC starts continuous sampling, and sample rawdata will be stored in array ADC_Buffer.

Demo 7

i2c_dma_demo.c

Sample Purpose

Demonstrate how I2C master and slave work in GDMA mode.

Brief Introduction

This sample code demonstrates the communication between I2C master and slave in GDMA mode. Master will read data from slave.

File Path

sdk\src\sample\io_demo\gdma\i2c_dma\MasterRx+SlaveTx\i2c_dma_demo.c

Function Entry

i2c_dma_demo()

Hardware Connection

As shown in I2C GDMA Hardware Connection Diagram. On EVB, connect P0_0 to P1_0, connect P0_1 to P1_1.

I2C Master SCL Pin Definition

#define I2C1_SCL P0_1

I2C Master SDA Pin Definition

#define I2C1_SDA P0_0

I2C Slave SCL Pin Definition

#define I2C0_SCL P1_1

I2C Slave SDA Pin Definition

#define I2C0_SDA P1_0

I2C Master ID

I2C1

I2C Slave ID

I2C0

Clock Speed

400000

Address Mode

7-Bit

Slave Address

0x50

ACK

ACK Enable

GDMA DIR

Master: GDMA_DIR_PeripheralToMemory
Slave: GDMA_DIR_MemoryToPeripheral

GDMA BufferSize

#define TEST_SIZE 255

GDMA SourceInc

Master: DMA_SourceInc_Fix
Slave: DMA_SourceInc_Inc

GDMA DestinationInc

Master: DMA_DestinationInc_Inc
Slave: DMA_DestinationInc_Fix

GDMA SourceDataSize

Master: GDMA_DataSize_Byte
Slave: GDMA_DataSize_HalfWord

GDMA DestinationDataSize

Master: GDMA_DataSize_Byte
Slave: GDMA_DataSize_HalfWord

GDMA SourceMsize

GDMA_Msize_4

GDMA DestinationMsize

GDMA_Msize_4

GDMA SourceAddr

Master: &(I2C1->IC_DATA_CMD)
Slave: sendbuf

GDMA DestinationAddr

Master: readbuf
Slave: &(I2C0->IC_DATA_CMD)

GDMA SourceHandshake

Master: GDMA_Handshake_I2C1_RX

GDMA DestHandshake

Slave: GDMA_Handshake_I2C0_TX

Expected Result

1. Press the reset button on the EVB.
2. Strings ‘i2c0_handler: I2C_INT_RD_REQ’, ‘i2c_tx_dma_handler’, ‘i2c_rx_dma_handler’, ‘i2c1_handler: I2C1 stop detect’ will be displayed in Debug Analyzer in order.

Demo 8

dlps_gdma_recover_demo.c

Sample Purpose

Demonstrate how GDMA recovers from DLPS.

Brief Introduction

This sample code demonstrates how GDMA recovers from DLPS. The UART can receive data through GDMA when the chip wakes up from DLPS.

File Path

sdk\src\sample\io_demo\dlps\dlps_gdma_recover_demo.c

Function Entry

dlps_gdma_recover_demo()

Hardware Connection

As shown in GDMA Recover From DLPS Hardware Connection Diagram.
RTL87x3E: On EVB, TX is connected to M3_0, RX is connected to M3_1, FT_VIO is connected to VIO1, CON3 is connected to PC, and wake up pin is connected to P0_0.
RTL87x3D: On EVB, TXD is connected to M3_0, RXD is connected to M3_1, FT_VIO is connected to VIO1, P2 is connected to PC, and wake up pin is connected to P0_0.

UART TX Pin Definition

#define UART_TX_PIN P3_1

UART RX Pin Definition

#define UART_RX_PIN P3_0

UART ID

UART0

Baud Rate

3000000

Parity Check

No Parity

Data Format

8-Bit

Stop Bit

1-Bit

Hardware Flow Control

None

Expected Result

1. Press the reset button on the EVB, string ‘### Welcome to use RealTek Bumblebee ###\r\n’ will be displayed in UART debug tool.
2. Use UART debug tool to send data to chip, then data will be stored in array uart_receive_buf.

Demo 9

spi_dma_demo.c

Sample Purpose

Demonstrate how SPI sends and receives data in master mode by GDMA.

File Path

sdk\src\sample\io_demo\gdma\spi_dma\spi_dma_demo.c

Function Entry

spi_dma_demo()

Hardware Connection

As shown in SPI Demo 4 Hardware Connection Diagram. Connect M0_1 to CS of SPI slave device, connect M0_0 to SCK of SPI slave device, connect M1_0 to MISO of SPI slave device, and connect M1_1 to MOSI of SPI slave device.

SPI CS Pin Definition

#define PIN_SPI1_CS P0_1

SPI SCK Pin Definition

#define PIN_SPI1_SCK P0_0

SPI MOSI Pin Definition

#define PIN_SPI1_MOSI P1_0

SPI MISO Pin Definition

#define PIN_SPI1_MISO P1_1

SPI ID

SPI1

Mode

Master

Speed

400000

Data Size

8-Bit

Expected Result

1. Press the reset button on the EVB, the data in array sendbuf is sent to SPI slave device and prints the string ‘spi_tx_dma_handler’ in the Debug Analyzer.
2. After the slave device receives the data, the slave device sends data to the chip, the chip stores the received data in array readbuf and prints the string ‘spi_rx_dma_handler’ in the Debug Analyzer.

Function Description

GDMA is used to provide high-speed data transfer between peripherals and memory or between memory and memory. The data transfer can be done independently of the CPU to reduce the CPU overhead.

Each channel of the GDMA controller can handle requests from one or more peripherals for memory access. The GDMA controller has an arbitrator to coordinate the priority of each GDMA request.

Feature List

  • Programmable transfer type for each channel: memory to memory, memory to peripheral, peripheral to memory, peripheral to peripheral.

  • Programmable source and destination addresses for each channel.

  • Address increment, or fixed.

  • Programmable burst transaction size for each channel.

  • Support transfer abort/suspend function.

  • Programmable channel priority.

  • Independent interrupts and control bit for every channel.

  • Support single-block and multi-block transfer.

  • Support scatter and gather transfer.

Note

RTL87x3D supports 16 channels, if using SPI high-speed mode, please use channel 0 and 1. RTL87x3E supports 9 channels, RTL87x3EP supports 12 channels.

Parameter Significance

  1. GDMA_ChannelNum

    Channel numbers can be 0 to 15.

  2. GDMA_DIR

    The transfer direction can be memory to memory or memory to peripheral or peripheral to memory or peripheral to peripheral.

  3. GDMA_SourceInc

    Indicates whether to increment the source address on every source transfer.

  4. GDMA_DestinationInc

    Indicates whether to increment the destination address on every destination transfer.

  5. GDMA_SourceDataSize

    Source single transaction size in bytes:

    src_single_size_bytes = GDMA_SourceDataSize

  6. GDMA_DestinationDataSize

    Destination single transaction size in bytes:

    dst_single_size_bytes = GDMA_DestinationDataSize

  7. GDMA_SourceMsize

    Source burst transaction size in bytes:

    src_burst_size_bytes = GDMA_SourceMsize * src_single_size_bytes

  8. GDMA_DestinationMsize

    Destination burst transaction size in bytes:

    dst_burst_size_bytes = GDMA_DestinationMsize * dst_single_size_bytes

  9. GDMA_BufferSize

    The total number of bytes to be transferred in a block is:

    blk_size_bytes_dma = GDMA_BufferSize * src_single_size_bytes

Note

The above parameter configuration needs to satisfy the following formula:

GDMA_SourceDataSize * GDMA_SourceMsize = GDMA_DestinationDataSize * GDMA_DestinationMsize

Waterlevel Setting

Handshaking interfaces are used at the transaction level to control the flow of single or burst transactions. Waterlevel is mainly divided into TX FIFO waterlevel and RX FIFO waterlevel. When the effective data amount in the FIFO reaches the set value of waterlevel, a burst transmission is initiated. GDMA_SourceMsize, GDMA_DestinationMsize, GDMA_SourceDataSize, GDMA_DestinationDataSize and peripheral waterlevel setting table is presented below.

IO

Dir

Peripheral
GDMA
waterlevel

GDMA_
SourceMsize

GDMA_
DestinationMsize

GDMA_
SourceDataSize

GDMA_
DestinationDataSize

UART

TX

.TxWaterlevel
= 12

1

4

Word

Byte

RX

.RxWaterlevel
= 4

4

1

Byte

Word

SPI
Master

TX

.SPI_TxWaterlevel
= 24

4

8

Word

HalfWord

RX

.SPI_RxWaterlevel
= 7

8

4

HalfWord

Word

TX

.SPI_TxWaterlevel
= 28

1

4

Word

Byte

RX

.SPI_RxWaterlevel
= 3

4

1

Byte

Word

SPI
Slave

TX

.SPI_TxWaterlevel
= 58

1

4

Word

Byte

RX

.SPI_RxWaterlevel
= 3

4

1

Byte

Word

I2C

TX

.I2C_TxWaterlevel
= 14

4

8

Word

HalfWord

RX

.I2C_RxWaterlevel
= 3

4

1

Byte

Word

ADC

.adcBurstSize
= 8

8

8

HalfWord

HalfWord

SPI_HS

TX

.SPI_TxWaterlevel
= 25

32

32

Byte

Byte

RX

.SPI_RxWaterlevel
= 31

32

32

Byte

Byte

GDMA Single-Block Transfer Initialization Flow

The initialization flow of GDMA single-block transfer is shown in the following figure.

The codes below demonstrate the GDMA single-block transfer.

uint16_t i = 0;
RCC_PeriphClockCmd(APBPeriph_GDMA, APBPeriph_GDMA_CLOCK, ENABLE);
GDMA_InitTypeDef GDMA_InitStruct;

if (!GDMA_channel_request(&mem_to_mem_dma_ch_num, demo_dma_handler, true))
{
    return;
}

/*--------------initialize test buffer---------------------*/
for (i = 0; i < 100; i++)
{
    GDMA_SendBuffer[i] = (i & 0xff);
}
for (i = 0; i < 100; i++)
{
    GDMA_RecvBuffer[i] = 0;
}

GDMA_StructInit(&GDMA_InitStruct);
GDMA_InitStruct.GDMA_ChannelNum      = DEMO_DMA_CHANNEL_NUM;
GDMA_InitStruct.GDMA_DIR             = GDMA_DIR_MemoryToMemory;
GDMA_InitStruct.GDMA_BufferSize      = 100;//determine total transfer size
GDMA_InitStruct.GDMA_SourceInc       = DMA_SourceInc_Inc;
GDMA_InitStruct.GDMA_DestinationInc  = DMA_DestinationInc_Inc;
GDMA_InitStruct.GDMA_SourceDataSize  = GDMA_DataSize_Byte;
GDMA_InitStruct.GDMA_DestinationDataSize = GDMA_DataSize_Byte;
GDMA_InitStruct.GDMA_SourceMsize      = GDMA_Msize_1;
GDMA_InitStruct.GDMA_DestinationMsize = GDMA_Msize_1;
GDMA_InitStruct.GDMA_SourceAddr      = (uint32_t)GDMA_SendBuffer;
GDMA_InitStruct.GDMA_DestinationAddr = (uint32_t)GDMA_RecvBuffer;
GDMA_Init(DEMO_DMA_CHANNEL, &GDMA_InitStruct);

/*-----------------GDMA IRQ init-------------------*/
NVIC_InitTypeDef nvic_init_struct;
nvic_init_struct.NVIC_IRQChannel         = DEMO_DMA_IRQ;
nvic_init_struct.NVIC_IRQChannelCmd      = (FunctionalState)ENABLE;
nvic_init_struct.NVIC_IRQChannelPriority = 3;
NVIC_Init(&nvic_init_struct);

GDMA_INTConfig(DEMO_DMA_CHANNEL_NUM, GDMA_INT_Block, ENABLE);
GDMA_Cmd(DEMO_DMA_CHANNEL_NUM, ENABLE);

I2C

I2C Demo Code Support List

Demo 1

i2c_demo.c

Sample Purpose

Demonstrate how I2C writes and reads data in interrupt mode.

Brief Introduction

This sample code demonstrates the communication between the chip and I2C slave. The chip writes some data to I2C slave and then chip reads data from I2C slave.

File Path

sdk\src\sample\io_demo\i2c\interrupt\i2c_demo.c

Function Entry

i2c_demo()

Hardware Connection

As shown in I2C Demo 1/2/3 Hardware Connection Diagram. On EVB, connect P0_0 to the SCL of the I2C slave, connect P0_1 to the SDA of the I2C slave.

I2C SCL Pin Definition

#define PIN_I2C0_SCL P0_0

I2C SDA Pin Definition

#define PIN_I2C0_SDA P0_1

I2C ID

I2C0

Clock Speed

100000

Device Mode

Master

Address Mode

7 Bit

Slave Address

0x50

ACK

ACK Enable

Expected Result

1. Press the reset button on the EVB, the I2C slave will receive data 0xaa and 0xbb, and the chip will receive four bytes from the I2C slave.
2. When the I2C transmission ends, the string ‘i2c0_handler: I2C0 stop detect’ will be displayed in the Debug Analyzer.

Demo 2

i2c_mw_demo.c

Sample Purpose

Demonstrate I2C master write function.

Brief Introduction

This sample code demonstrates the I2C master write function. The chip transmits some data to the I2C slave.

File Path

sdk\src\sample\io_demo\i2c\master_write\i2c_mw_demo.c

Function Entry

i2c_mw_demo()

Hardware Connection

As shown in I2C Demo 1/2/3 Hardware Connection Diagram. On EVB, connect P0_0 to the SCL of the I2C slave, connect P0_1 to the SDA of the I2C slave.

I2C SCL Pin Definition

#define PIN_I2C1_SCL P0_0

I2C SDA Pin Definition

#define PIN_I2C1_SDA P0_1

I2C ID

I2C1

Clock Speed

400000

Device Mode

Master

Address Mode

7 Bit

Slave Address

#define ADDR 0x08

ACK

ACK Enable

Expected Result

1. Press the reset button on the EVB, the I2C slave will receive data 0xaa, 0xbb, 0x66, 0x68, 0x77, 0x88.
2. If the I2C transfer fails, the string ‘i2c_mw_demo: Send failed’ will be displayed in the Debug Analyzer.

Demo 3

i2c_polling_demo.c

Sample Purpose

Demonstrate how I2C writes and reads data in polling mode.

Brief Introduction

This sample code demonstrates the communication between the chip and the I2C slave. The chip writes some data to the I2C slave and then the chip reads data from the I2C slave.

File Path

sdk\src\sample\io_demo\i2c\polling\i2c_polling_demo.c

Function Entry

i2c_polling_demo()

Hardware Connection

As shown in I2C Demo 1/2/3 Hardware Connection Diagram. On EVB, connect P0_0 to the SCL of the I2C slave, connect P0_1 to the SDA of the I2C slave.

I2C SCL Pin Definition

#define PIN_I2C1_SCL P0_0

I2C SDA Pin Definition

#define PIN_I2C1_SDA P0_1

I2C ID

I2C1

Clock Speed

400000

Device Mode

Master

Address Mode

7 Bit

Slave Address

#define ADDR 0x08

ACK

ACK Enable

Expected Result

1. Press the reset button on the EVB, the I2C slave will receive data 0xaa and 0xbb, and the chip will receive four bytes from the I2C slave.
2. If the I2C transfer fails, the string ‘i2c_polling_demo: Send failed’ will be displayed in the Debug Analyzer.

Demo 4

i2c_slave_demo.c

Sample Purpose

Demonstrate how I2C slave works.

Brief Introduction

This sample code demonstrates the communication between the chip and I2C master. The chip can read data from the I2C master and write data to the I2C master.

File Path

sdk\src\sample\io_demo\i2c\slave\i2c_slave_demo.c

Function Entry

i2c_slave_demo()

Hardware Connection

As shown in I2C Demo 4 Hardware Connection Diagram. On EVB, connect P0_0 to the SCL of the I2C master. On EVB, connect P0_1 to the SDA of the I2C master.

I2C SCL Pin Definition

#define PIN_I2C1_SCL P0_0

I2C SDA Pin Definition

#define PIN_I2C1_SDA P0_1

I2C ID

I2C1

Clock Speed

100000

Device Mode

Slave

Address Mode

7 Bit

Slave Address

0x50

ACK

ACK Enable

Expected Result

1. Press the reset button on the EVB.
2. If the I2C master sends a read request, the master will receive data 0x66.
3. If the I2C master sends a write command, the received data will be displayed in the Debug Analyzer.

Function Description

The I2C bus is a two-wire serial interface, consisting of a serial data line (SDA) and a serial clock (SCL). These wires carry information between the devices connected to the bus. Each device is recognized by a unique address and can operate as either a transmitter or receiver, depending on the function of the device. Devices can also be considered masters or slaves when performing data transfers. A master is a device that initiates a data transfer on the bus and generates the clock signals to permit that transfer. At that time, any device addressed is considered a slave.

Feature List

  • Up to 3 I2C.

  • Two-wire I2C serial interface: consists of a serial data line (SDA) and a serial clock (SCL).

  • Support master and slave mode.

  • Support 7/10-bit addressing mode.

  • Support standard mode (0 to 100Kb/s).

  • Support fast mode (less than or equal to 400Kb/s) or fast mode plus (less than or equal to 1000Kb/s).

  • Interrupt or polling mode operation.

  • Support GDMA.

I2C Transfer Protocol

Each byte sent on the SDA line must be 8 bits. There is no limit to the number of bytes that can be sent per transfer, and each byte must be followed by a response bit. The most significant bit (MSB) of the data is transmitted first. If the slave needs to complete some other functions, such as an internal interrupt service routine, it can receive or send the next complete data byte. The clock line SCL can be kept low to force the master to enter the wait state. When the slave is ready to receive the next data byte and release the clock line SCL, the data transfer continues.

Master Mode

7-Bit Addressing Mode

Master Write

Master-transmitter transmits to slave-receiver with a 7-bit slave address. The transfer direction is not changed. All data is transmitted in byte format, with no limit on the number of bytes transferred per data transfer. After the master sends the address and read/write bit or the master transmits a byte of data to the slave, the slave-receiver must respond with the acknowledge signal (ACK). When a slave-receiver does not respond with an ACK pulse, the master aborts the transfer by issuing a stop condition. The slave must leave the SDA line high so that the master can abort the transfer.

Master Read

In the first response, master-transmitter becomes master-receiver, and slave-receiver becomes slave-transmitter, and the first response is still generated by the slave. If the master is receiving data, the master responds to the slave-transmitter with an acknowledge pulse after a byte of data has been received, except for the last byte. This (NACK) is the way the master-receiver notifies the slave-transmitter that this is the last byte. The slave-transmitter relinquishes the SDA line after detecting the no acknowledge (NACK) so that the master can issue a stop condition.

Master Repeat Read

When performing a write-before-read operation, both the start condition and the slave address are sent repeatedly, but the read/write bit is reversed.

10-Bit Addressing Mode

Master Write

Master-transmitter transmits to slave-receiver with a 10-bit slave address. The transfer direction is not changed.

Master Read

Master-transmitter transmits to slave-receiver with a 10-bit slave address. The transfer direction is changed after the second read/write bit, master-transmitter becomes master-receiver, and slave-receiver becomes slave-transmitter.

Master Repeat Read

The master sends data to the slave and then reads data from the same slave. The transfer direction is changed after the second read/write bit.

I2C Clock Speed Setting Instructions

The I2C clock speed is related to the SCL rising time, which is affected by the pull-up resistor and capacitor. Users can configure the variable I2C_RisingTimeNs to calibrate the I2C clock speed. The default value of I2C_RisingTimeNs for RTL87x3D is 100, and the default value of I2C_RisingTimeNs for RTL87x3E and RTL87x3EP is 50. The following example demonstrates the calibration method of the I2C clock speed, taking the I2C source clock as 40MHz, the I2C clock speed as 400KHz, and the I2C_RisingTimeNs as 100.

  1. Set the variable I2C_RisingTimeNs to 100.

  2. Measure the I2C clock speed. For example, if the actual frequency measured is 411KHz, the period is: 1/411KHz = 2433 ns.

  3. Calculate the actual value of I2C_RisingTimeNs.

    1. SCL Low Time = SCL Low Period - SCL Falling Time + SCL Rising Time

    2. SCL High Time = SCL High Period + SCL Falling Time

    3. SCL Frequency = 1 / (SCL High Time + SCL Low Time)

    4. According to the formulas a to c, SCL Period = SCL Low Period + SCL High Period + SCL Rising Time

    5. SCL Low Period(ns) + SCL High Period(ns) = SCL Period(ns) - I2C_RisingTimeNs configured in the APP = 2500 - 100 = 2400

    6. Actual I2C_RisingTimeNs = Actual period - (SCL Low Period + SCL High Period) = 2433 - 2400 = 33

    7. Because the clock source of I2C is set to 40MHz, the precision of the I2C clock is 25ns. So the setting I2C_RisingTimeNs needs to be aligned to 25ns.

Master Mode Initialization Flow

I2C master mode initialization flow is shown in the following figure.

The codes below demonstrate the I2C master mode initialization flow.

void driver_i2c_init(void)
{
    RCC_PeriphClockCmd(APBPeriph_I2C1, APBPeriph_I2C1_CLOCK, ENABLE);

    I2C_InitTypeDef  I2C_InitStructure;
    I2C_StructInit(&I2C_InitStructure);

    I2C_InitStructure.I2C_ClockSpeed = 400000;
    I2C_InitStructure.I2C_DeviveMode = I2C_DeviveMode_Master;
    I2C_InitStructure.I2C_AddressMode = I2C_AddressMode_7BIT;
    I2C_InitStructure.I2C_SlaveAddress = ADDR;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;

    I2C_Init(I2C1, &I2C_InitStructure);

    I2C_Cmd(I2C1, ENABLE);
}

Slave Mode Initialization Flow

I2C slave mode initialization flow is shown in the following figure.

The codes below demonstrate the I2C slave mode initialization flow.

RCC_PeriphClockCmd(APBPeriph_I2C1, APBPeriph_I2C1_CLOCK, ENABLE);

I2C_InitTypeDef  I2C_InitStructure;
I2C_StructInit(&I2C_InitStructure);

I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_InitStructure.I2C_DeviveMode = I2C_DeviveMode_Slave;
I2C_InitStructure.I2C_AddressMode = I2C_AddressMode_7BIT;
I2C_InitStructure.I2C_SlaveAddress = 0x50;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;

I2C_Init(I2C1, &I2C_InitStructure);

/* Config I2C interrupt */
I2C_INTConfig(I2C1, I2C_INT_RD_REQ | I2C_INT_RX_FULL | I2C_INT_STOP_DET, ENABLE);

NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = I2C1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);

I2C_Cmd(I2C1, ENABLE);

Master Write

The codes below demonstrate the operation flow of I2C sending data in master mode.

uint8_t I2C_WriteBuf[16] = {0xaa, 0xbb, 0x66, 0x68, 0x77, 0x88};

if (I2C_Success != I2C_MasterWrite(I2C1, I2C_WriteBuf, 6))
{
    IO_PRINT_ERROR0("i2c_mw_demo: Send failed");

    //Check Event
    if (I2C_CheckEvent(I2C1, ABRT_7B_ADDR_NOACK) == SET)
    {
        IO_PRINT_ERROR0("i2c_mw_demo: Wrong addr");
    }
    if (I2C_CheckEvent(I2C1, ABRT_GCALL_NOACK) == SET)
    {
        IO_PRINT_ERROR0("i2c_mw_demo: General call nack");
    }
    I2C_SendCmd(I2C1, I2C_WRITE_CMD, 0, I2C_STOP_ENABLE);
    I2C_Cmd(I2C1, DISABLE);
    I2C_Cmd(I2C1, ENABLE);
    I2C_MasterWrite(I2C1, I2C_WriteBuf, 6);
}

Master Repeat Read

The codes below demonstrate the operation flow of I2C send and receive data in master mode.

uint8_t I2C_WriteBuf[16] = {0xaa, 0xbb, 0x66, 0x68, 0x77, 0x88};
uint8_t I2C_ReadBuf[16] = {0, 0, 0, 0};

if (I2C_Success != I2C_RepeatRead(I2C1, I2C_WriteBuf, 2, I2C_ReadBuf, 4))
{
    IO_PRINT_ERROR0("i2c_polling_demo: Send failed");

    //Check Event
    if (I2C_CheckEvent(I2C1, ABRT_7B_ADDR_NOACK) == SET)
    {
        IO_PRINT_ERROR0("i2c_polling_demo: Wrong addr");
    }
    if (I2C_CheckEvent(I2C1, ABRT_GCALL_NOACK) == SET)
    {
        IO_PRINT_ERROR0("i2c_polling_demo: General call nack");
    }
}

SPI

SPI Demo Code Support List

Demo 1

spi_switchcs_demo.c

Sample Purpose

Demonstrate how SPI dynamically switches CS signals.

File Path

sdk\src\sample\io_demo\spi\dynamic_switch_cs\spi_switchcs_demo.c

Function Entry

spi_switchcs_demo()

Hardware Connection

As shown in SPI Demo 1 Hardware Connection Diagram. Connect M1_3 to CS of SPI slave device 0, connect M1_4 to CS of SPI slave device 1, connect M1_5 to CS of SPI slave device 2, connect M1_0 to SCK of SPI slave device 0/1/2, connect M1_1 to MISO of SPI slave device 0/1/2, and connect M1_2 to MOSI of SPI slave device 0/1/2.

SPI CS0 Pin Definition

#define PIN_SPI1_CS0 P1_3

SPI CS1 Pin Definition

#define PIN_SPI1_CS1 P1_4

SPI CS2 Pin Definition

#define PIN_SPI1_CS2 P1_5

SPI SCK Pin Definition

#define PIN_SPI1_SCK P1_0

SPI MOSI Pin Definition

#define PIN_SPI1_MOSI P1_1

SPI MISO Pin Definition

#define PIN_SPI1_MISO P1_2

SPI ID

SPI1

Mode

Master

Speed

400000

Data Size

8-Bit

Expected Result

1. Press the reset button on the EVB. The data in array SPI_WriteBuf is sent to SPI slave device 0.
2. Then the data in array SPI_WriteBuf is sent to SPI slave device 1.
3. Then the data in array SPI_WriteBuf is sent to SPI slave device 2.

Demo 2

spi_master_eeprom_mode_demo.c

Sample Purpose

Demonstrate how SPI receives data with EEPROM mode by GDMA in master mode.

File Path

sdk\src\sample\io_demo\spi\eeprom\spi_master_eeprom_mode_demo.c

Function Entry

spi_master_eeprom_mode_demo()

Hardware Connection

As shown in SPI Demo 2/6 Hardware Connection Diagram. Connect M0_3 to CS of SPI slave device, connect M0_0 to SCK of SPI slave device, connect M0_1 to MISO of SPI slave device, and connect M0_2 to MOSI of SPI slave device.

SPI CS Pin Definition

#define PIN_SPI_CS P0_3

SPI SCK Pin Definition

#define PIN_SPI_SCK P0_0

SPI MOSI Pin Definition

#define PIN_SPI_MOSI P0_1

SPI MISO Pin Definition

#define PIN_SPI_MISO P0_2

SPI ID

SPI1

Mode

Master

Speed

400000

Data Size

8-Bit

Expected Result

Print string ‘spi_master_rx_dma_handler’ and the received data in Debug Analyzer.

Demo 3

external_flash.c
external_flash.h
external_flash_test.c
external_flash_test.h

Sample Purpose

Demonstrate how the chip communicates with external flash by SPI.

File Path

sdk\src\sample\io_demo\spi\external_flash\external_flash.c
sdk\src\sample\io_demo\spi\external_flash\external_flash.h
sdk\src\sample\io_demo\spi\external_flash\external_flash_test.c
sdk\src\sample\io_demo\spi\external_flash\external_flash_test.h

Function Entry

ext_flash_spi_test_code()

Hardware Connection

As shown in SPI Demo 3 Hardware Connection Diagram. Connect M5_1 to CS of external flash, connect M5_0 to SCK of external flash, connect M5_3 to MISO of external flash, and connect M5_2 to MOSI of external flash, connect M5_5 to HOLD of external flash.

SPI CS Pin Definition

#define FLASH_CS P5_1

SPI SCK Pin Definition

#define FLASH_SCK P5_0

SPI MOSI Pin Definition

#define FLASH_MOSI P5_2

SPI MISO Pin Definition

#define FLASH_MISO P5_3

FLASH HOLD Pin Definition

#define FLASH_HOLD P5_5

SPI ID

SPI0

Mode

Master

Speed

400000

Data Size

8-Bit

Expected Result

1. Print string ‘flash_test_task: test_case 1 success’ in Debug Analyzer.
2. Print string ‘flash_test_task: test_case 2 success’ in Debug Analyzer.
3. Print string ‘flash_test_task: test_case 3 success’ in Debug Analyzer.

Demo 4

spi_master_demo.c

Sample Purpose

Demonstrate how SPI sends data by polling and receives data by interrupt in master mode.

File Path

sdk\src\sample\io_demo\spi\interrupt\spi_master_demo.c

Function Entry

spi_master_demo()

Hardware Connection

As shown in SPI Demo 4 Hardware Connection Diagram. Connect M0_1 to CS of SPI slave device, connect M0_0 to SCK of SPI slave device, connect M1_0 to MISO of SPI slave device, and connect M1_1 to MOSI of SPI slave device.

SPI CS Pin Definition

#define PIN_SPI1_CS P0_1

SPI SCK Pin Definition

#define PIN_SPI1_SCK P0_0

SPI MOSI Pin Definition

#define PIN_SPI1_MOSI P1_0

SPI MISO Pin Definition

#define PIN_SPI1_MISO P1_1

SPI ID

SPI1

Mode

Master

Speed

400000

Data Size

8-Bit

Expected Result

1. Press the reset button on the EVB. The data in array SPI_WriteBuf is sent to SPI slave device.
2. After the slave device receives the data, the slave device sends data to the chip. The chip stores the received data in array SPI_ReadINTBuf.

Demo 5

spi_demo.c

Sample Purpose

Demonstrate how SPI sends and receives data by polling in master mode.

File Path

sdk\src\sample\io_demo\spi\polling\spi_demo.c

Function Entry

spi_demo()

Hardware Connection

As shown in SPI Demo 5 Hardware Connection Diagram. Connect M1_5 to CS of SPI slave device, connect M1_2 to SCK of SPI slave device, connect M1_3 to MISO of SPI slave device, and connect M1_4 to MOSI of SPI slave device.

SPI CS Pin Definition

#define PIN_SPI1_CS P1_5

SPI SCK Pin Definition

#define PIN_SPI1_SCK P1_2

SPI MOSI Pin Definition

#define PIN_SPI1_MOSI P1_3

SPI MISO Pin Definition

#define PIN_SPI1_MISO P1_4

SPI ID

SPI1

Mode

Master

Speed

400000

Data Size

8-Bit

Expected Result

1. Press the reset button on the EVB. The data in array SPI_WriteBuf is sent to SPI slave device.
2. After the slave device receives the data, the slave device sends data to the chip. The chip stores the received data in array SPI_ReadBuf.

Demo 6

spi_master_rx_only_mode_demo.c

Sample Purpose

Demonstrate how SPI receives data with receive only mode by GDMA in master mode.

File Path

sdk\src\sample\io_demo\spi\receive_only\spi_master_rx_only_mode_demo.c

Function Entry

spi_master_rx_only_mode_demo()

Hardware Connection

As shown in SPI Demo 2/6 Hardware Connection Diagram. Connect M0_3 to CS of SPI slave device, connect M0_0 to SCK of SPI slave device, connect M0_1 to MISO of SPI slave device, and connect M0_2 to MOSI of SPI slave device.

SPI CS Pin Definition

#define PIN_SPI_CS P0_3

SPI SCK Pin Definition

#define PIN_SPI_SCK P0_0

SPI MOSI Pin Definition

#define PIN_SPI_MOSI P0_1

SPI MISO Pin Definition

#define PIN_SPI_MISO P0_2

SPI ID

SPI1

Mode

Master

Speed

400000

Data Size

8-Bit

Expected Result

Print string ‘spi_master_rx_dma_handler’ and the received data in Debug Analyzer.

Demo 7

spi_slave_demo.c

Sample Purpose

Demonstrate how SPI receives data by interrupt in slave mode.

File Path

sdk\src\sample\io_demo\spi\slave\spi_slave_demo.c

Function Entry

spi_slave_demo()

Hardware Connection

As shown in SPI Demo 7 Hardware Connection Diagram. Connect MIC2_N to CS of SPI master device, connect MIC1_P to SCK of SPI master device, connect MIC2_P to MISO of SPI master device, and connect MIC1_N to MOSI of SPI master device.

SPI CS Pin Definition

#define PIN_SPI0_CS MIC2_N

SPI SCK Pin Definition

#define PIN_SPI0_SCK MIC1_P

SPI MOSI Pin Definition

#define PIN_SPI0_MOSI MIC2_P

SPI MISO Pin Definition

#define PIN_SPI0_MISO MIC1_N

SPI ID

SPI0

Mode

Slave

Data Size

8-Bit

Expected Result

Master device sends data to the chip. The chip stores the received data in array SPI_ReadINTBuf and prints the received data in Debug Analyzer.

Demo 8

spi_slave_gpio_demo.c

Sample Purpose

Demonstrate how SPI sends data in slave mode by interrupt.

File Path

sdk\src\sample\io_demo\spi\slave\spi_slave_gpio_demo.c

Function Entry

spi_slave_gpio_demo()

Hardware Connection

As shown in SPI Demo 8 Hardware Connection Diagram. Connect M1_4 to M1_0, connect M1_7 to M1_3, connect M1_5 to M1_2, connect M1_6 to M1_1, and connect M2_3 to M2_4.

SPI0 CS Pin Definition

#define SPI0_CS P1_3

SPI0 SCK Pin Definition

#define SPI0_SCK P1_0

SPI0 MOSI Pin Definition

#define SPI0_MOSI P1_1

SPI0 MISO Pin Definition

#define SPI0_MISO P1_2

SPI1 CS Pin Definition

#define SPI1_CS P1_7

SPI1 SCK Pin Definition

#define SPI1_SCK P1_4

SPI1 MOSI Pin Definition

#define SPI1_MOSI P1_5

SPI1 MISO Pin Definition

#define SPI1_MISO P1_6

SPI ID

SPI0
SPI1

Mode

SPI1 is master, SPI0 is slave.

Speed

100000

Data Size

8-Bit

Expected Result

1. Master device sends data to slave. The slave stores the received data in array SPI_ReadINTBuf and prints the received data in Debug Analyzer.
2. Slave device sends data to master. The master stores the received data in array SPI1_ReadINTBuf and prints the received data in Debug Analyzer.

Demo 9

spi_slave_write_demo.c

Sample Purpose

Demonstrate how SPI sends data in slave mode by GDMA.

File Path

sdk\src\sample\io_demo\spi\slave\spi_slave_write_demo.c

Function Entry

spi_slave_write_demo()

Hardware Connection

As shown in SPI Demo 9 Hardware Connection Diagram. Connect M2_2 to CS of SPI master device, connect M1_0 to SCK of SPI master device, connect M1_1 to MISO of SPI master device, and connect M2_1 to MOSI of SPI master device.

SPI CS Pin Definition

#define PIN_SPI_CS P2_2

SPI SCK Pin Definition

#define PIN_SPI_SCK P1_0

SPI MOSI Pin Definition

#define PIN_SPI_MOSI P1_1

SPI MISO Pin Definition

#define PIN_SPI_MISO P2_1

SPI ID

SPI0

Mode

Slave

Data Size

8-Bit

Expected Result

1. The data in array sendbuf is sent to SPI master device and prints the string ‘spi_slave_tx_dma_handler’ in Debug Analyzer.
2. When master device sends data to the chip, the chip stores the received data in array SPI_ReadINTBuf and prints the string ‘spi_slave_handler’ and the received data in Debug Analyzer.

Demo 10

spi0_hs_dma_demo.c

Sample Purpose

Demonstrate how SPI0 sends and receives data in high-speed mode.

File Path

sdk\src\sample\io_demo\spi\spi0_hs\spi0_hs_dma_demo.c

Function Entry

spi0_hs_dma_demo()

Hardware Connection

As shown in SPI Demo 10 Hardware Connection Diagram. Connect M1_2 to CS of SPI slave device, connect M1_3 to SCK of SPI slave device, connect M1_4 to MISO of SPI slave device, and connect M1_5 to MOSI of SPI slave device.

SPI CS Pin Definition

#define SPI0_HS_CS P1_2

SPI SCK Pin Definition

#define SPI0_HS_SCK P1_3

SPI MOSI Pin Definition

#define SPI0_HS_MOSI P1_4

SPI MISO Pin Definition

#define SPI0_HS_MISO P1_5

SPI ID

SPI0

Mode

Master

Speed

40MHz

Data Size

8-Bit

Expected Result

1. Press the reset button on the EVB and the data in array sendbuf is sent to SPI slave device and print the string ‘spi_tx_dma_handler’ in Debug Analyzer.
2. After the slave device receives the data, the slave device sends data to the chip. The chip stores the received data in array readbuf and prints the string ‘spi_rx_dma_handler’ and the received data in Debug Analyzer.

Demo 11

spi2spi_auto_reload_dma.c

Sample Purpose

Demonstrate how SPI0 reads data and SPI1 sends data by GDMA.

File Path

sdk\src\sample\io_demo\spi\spi2spi_auto_reload_dma\spi2spi_auto_reload_dma.c

Function Entry

spi2spi_auto_reload_dma()

Hardware Connection

As shown in SPI Demo 11/12 Hardware Connection Diagram. Connect M1_7 to CS of SPI slave device 0, connect M1_4 to SCK of SPI slave device 0, connect M1_5 to MISO of SPI slave device 0, and connect M1_6 to MOSI of SPI slave device 0. Connect M2_5 to CS of SPI slave device 1, connect M2_2 to SCK of SPI slave device 1, connect M2_3 to MISO of SPI slave device 1, and connect M2_4 to MOSI of SPI slave device 1.

SPI0 CS Pin Definition

#define PIN_SPI0_CS P1_7

SPI0 SCK Pin Definition

#define PIN_SPI0_SCK P1_4

SPI0 MOSI Pin Definition

#define PIN_SPI0_MOSI P1_5

SPI0 MISO Pin Definition

#define PIN_SPI0_MISO P1_6

SPI1 CS Pin Definition

#define PIN_SPI1_CS P2_5

SPI1 SCK Pin Definition

#define PIN_SPI1_SCK P2_2

SPI1 MOSI Pin Definition

#define PIN_SPI1_MOSI P2_3

SPI1 MISO Pin Definition

#define PIN_SPI1_MISO P2_4

SPI ID

SPI0
SPI1

Mode

Master

Speed

400000

Data Size

8-Bit

Expected Result

SPI0 reads data from SPI slave device 0 and SPI1 sends the same data to SPI slave device 1.

Demo 12

spi2spi_dma_demo.c

Sample Purpose

Demonstrate how SPI0 reads data and SPI1 sends data by auto-reload GDMA.

File Path

sdk\src\sample\io_demo\spi\spi2spi_dma\spi2spi_dma_demo.c

Function Entry

spi2spi_dma_demo()

Hardware Connection

As shown in SPI Demo 11/12 Hardware Connection Diagram. Connect M1_7 to CS of SPI slave device 0, connect M1_4 to SCK of SPI slave device 0, connect M1_5 to MISO of SPI slave device 0, and connect M1_6 to MOSI of SPI slave device 0. Connect M2_5 to CS of SPI slave device 1, connect M2_2 to SCK of SPI slave device 1, connect M2_3 to MISO of SPI slave device 1, and connect M2_4 to MOSI of SPI slave device 1.

SPI0 CS Pin Definition

#define PIN_SPI0_CS P1_7

SPI0 SCK Pin Definition

#define PIN_SPI0_SCK P1_4

SPI0 MOSI Pin Definition

#define PIN_SPI0_MOSI P1_5

SPI0 MISO Pin Definition

#define PIN_SPI0_MISO P1_6

SPI1 CS Pin Definition

#define PIN_SPI1_CS P2_5

SPI1 SCK Pin Definition

#define PIN_SPI1_SCK P2_2

SPI1 MOSI Pin Definition

#define PIN_SPI1_MOSI P2_3

SPI1 MISO Pin Definition

#define PIN_SPI1_MISO P2_4

SPI ID

SPI0
SPI1

Mode

Master

Speed

400000

Data Size

8-Bit

Expected Result

SPI0 reads data from SPI slave device 0 and SPI1 sends the same data to SPI slave device 1.

Demo 13

spi_slave_rx_dma_hs_demo.c

Sample Purpose

Demonstrate how SPI0 slave reads data at high speed in GDMA mode.

File Path

sdk\src\sample\io_demo\spi\slave\spi_slave_rx_dma_hs_demo.c

Function Entry

spi_slave_rx_dma_hs_demo()

Hardware Connection

As shown in SPI Demo 13/14 Hardware Connection Diagram. Connect M1_1 to the CS of the SPI master device, connect M0_0 to the SCK of the SPI master device, connect M0_1 to the MISO of the SPI master device, and connect M1_0 to the MOSI of the SPI master device.

SPI CS Pin Definition

#define PIN_SPI_CS P1_1

SPI SCK Pin Definition

#define PIN_SPI_SCK P0_0

SPI MOSI Pin Definition

#define PIN_SPI_MOSI P1_0

SPI MISO Pin Definition

#define PIN_SPI_MISO P0_1

SPI ID

SPI0

Mode

Slave

Speed

10MHz

Data Size

8-Bit

Expected Result

Print the string ‘spi_slave_rx_dma_handler! rx_len_all 1000’ and the received data in Debug Analyzer.

Demo 14

spi_slave_tx_dma_hs_demo.c

Sample Purpose

Demonstrate how SPI0 slave sends data at high speed in GDMA mode.

File Path

sdk\src\sample\io_demo\spi\slave\spi_slave_tx_dma_hs_demo.c

Function Entry

spi_slave_tx_dma_hs_demo()

Hardware Connection

As shown in SPI Demo 13/14 Hardware Connection Diagram. Connect M1_1 to the CS of the SPI master device, connect M0_0 to the SCK of the SPI master device, connect M0_1 to the MISO of the SPI master device, and connect M1_0 to the MOSI of the SPI master device.

SPI CS Pin Definition

#define PIN_SPI_CS P1_1

SPI SCK Pin Definition

#define PIN_SPI_SCK P0_0

SPI MOSI Pin Definition

#define PIN_SPI_MOSI P1_0

SPI MISO Pin Definition

#define PIN_SPI_MISO P0_1

SPI ID

SPI0

Mode

Slave

Speed

10MHz

Data Size

8-Bit

Expected Result

The data in the array sendbuf is sent to the SPI master device and prints the string ‘spi_slave_tx_dma_handler! tx_len_all 1000’ in Debug Analyzer.

Demo 15

spi_rgb_polling_demo.c

Sample Purpose

Demonstrate how SPI1 uses one data line to control the LED in polling mode.

File Path

sdk\src\sample\io_demo\spi\polling\spi_rgb_polling_demo.c

Function Entry

spi_rgb_polling_demo()

Hardware Connection

Connect M1_0 to the LED controller.

SPI MOSI Pin Definition

#define PIN_SPI1_MOSI P1_0

SPI ID

SPI1

Mode

Master

Speed

10MHz

Data Size

8-Bit

Expected Result

Press the reset button on the EVB, the data in the array SPI_WriteBuf is sent to the LED controller. Adjust rgb_data to light up different lights.

Demo 16

spi_rgb_interrupt_demo.c

Sample Purpose

Demonstrate how SPI1 uses one data line to control the LED in interrupt mode.

File Path

sdk\src\sample\io_demo\spi\interrupt\spi_rgb_interrupt_demo.c

Function Entry

spi_rgb_interrupt_demo()

Hardware Connection

Connect M1_0 to the LED controller.

SPI MOSI Pin Definition

#define PIN_SPI_MOSI P1_0

SPI ID

SPI1

Mode

Master

Speed

10MHz

Data Size

8-Bit

Expected Result

Press the reset button on the EVB, the data in the array SPI_WriteBuf is sent to the LED controller and prints the string ‘spi_tx_handler: SPI TX FIFO Empty’ in Debug Analyzer. Adjust rgb_data to light up different lights.

Demo 17

spi_rgb_dma_demo.c

Sample Purpose

Demonstrate how SPI1 uses one data line to control the LED in GDMA mode.

File Path

sdk\src\sample\io_demo\gdma\spi_dma\spi_rgb_dma_demo.c

Function Entry

spi_rgb_dma_demo()

Hardware Connection

Connect M1_0 to the LED controller.

SPI MOSI Pin Definition

#define PIN_SPI_MOSI P1_0

SPI ID

SPI1

Mode

Master

Speed

10MHz

Data Size

8-Bit

Expected Result

Press the reset button on the EVB, the data in the array SPI_WriteBuf is sent to the LED controller and prints the string ‘spi_tx_dma_handler’ in Debug Analyzer. Adjust rgb_data to light up different lights.

Function Description

SPI allows the chip to communicate with external devices in half/full duplex, synchronous, and serial modes.

Feature List

  • Support master and slave modes.

  • Four transfer modes: full-duplex, TX only, RX only, EEPROM.

  • Support 4-bit to 32-bit data size in master mode.

  • Support 4-bit to 16-bit data size in slave mode.

  • Support up to 3 slave devices in master mode.

  • Support GDMA.

The maximum SPI clock supported by SPI in master mode and slave mode is as follows:

IC Type

SPI0 Master Max Clock (MHz)

SPI1 Master Max Clock (MHz)

SPI2 Master Max Clock (MHz)

SPI0 Slave Max Clock (MHz)

RTL87x3E

50 (with dedicated I/Os)
10 (with general I/Os)

20 (with dedicated I/Os)
10 (with general I/Os)

20 (with dedicated I/Os)
10 (with general I/Os)

10

TL87x3EP

50 (with dedicated I/Os)
10 (with general I/Os)

20 (with dedicated I/Os)
10 (with general I/Os)

20 (with dedicated I/Os)
10 (with general I/Os)

10

RTL87x3D

40 (with dedicated I/Os)
10 (with general I/Os)

20 (with dedicated I/Os)
10 (with general I/Os)

20 (with dedicated I/Os)
10 (with general I/Os)

10

Note

  1. RTL87x3D, RTL87x3E, and RTL87x3EP support 3 SPI. SPI0 supports master mode and slave mode. SPI1 and SPI2 only support master mode.

  2. SPI0 and SPI1 support 3 slave devices in master mode, and SPI2 supports 1 slave device in master mode.

  3. If the user needs to operate flash and read data from flash, it is recommended to use SPI_Direction_EEPROM mode. In this mode, the SPI controller will automatically supplement the padding bits needed for reading back. Set the read data length by SPI_SetReadLen() before reading from flash, then the result of SPI_GetRxFIFOLen() will equal this value. If SPI_Direction_FullDuplex mode is used when operating flash, it needs to supplement the padding bits manually, and the number of bytes should be equal to the read data length. In this way, the result of SPI_GetRxFIFOLen() is the total length of padding bits and data to read. SPI_SetReadLen() is just for SPI_Direction_EEPROM mode.

  4. SPI support up to 50MHz(SPI0 of RTL87x3E and RTL87x3EP), 40MHz(SPI0 of RTL87x3D) and 20MHz(SPI1 and SPI2) with dedicated I/Os, support 10MHz with general I/Os. For dedicated I/O, please refer to the HDK related documentation.

SPI Communication Sequence Diagram

SPI supports mode 0 to mode 3:

SPI Mode

Clock Polarity (CPOL)

Clock Phase (CPHA)

Mode 0

0

0

Mode 1

0

1

Mode 2

1

0

Mode 3

1

1

SPI Initialization Flow

SPI initialization flow is shown in the following figure.

The codes below demonstrate the SPI initialization flow.

void driver_spi_init(void)
{
    /* turn on SPI clock */
    RCC_PeriphClockCmd(APBPeriph_SPI1, APBPeriph_SPI1_CLOCK, ENABLE);

    SPI_InitTypeDef  SPI_InitStructure;
    SPI_StructInit(&SPI_InitStructure);

    SPI_InitStructure.SPI_Direction   = SPI_Direction_FullDuplex;
    SPI_InitStructure.SPI_Mode        = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize    = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL        = SPI_CPOL_High;
    SPI_InitStructure.SPI_CPHA        = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_BaudRatePrescaler  = 100;
    SPI_InitStructure.SPI_FrameFormat = SPI_Frame_Motorola;

    SPI_Init(SPI1, &SPI_InitStructure);
    SPI_Cmd(SPI1, ENABLE);
}

SPI External Flash

This section introduces how to communicate with external flash by SPI. Please refer to SPI Sample Code 3 Description for demo code and refer to SPI Demo 3 Hardware Connection Diagram for hardware connection.

Hardware Connection

Users need to modify the pins related to external flash in the code according to the hardware design. The macro definition below shows the pins defined in the code.

#define FLASH_SCK                   P5_0
#define FLASH_MOSI                  P5_2
#define FLASH_MISO                  P5_3
#define FLASH_CS                    P5_1
#define FLASH_HOLD                  P5_5

Demo Code

Users can implement functions to communicate with external flash by referring to the demo code in SPI Sample Code 3 Description.

Commands for External Flash

Different flash models may have different commands, and users can modify the following definitions according to the flash specifications.

typedef enum
{
    EXT_FLASH_WRITE_STATUS_CMD      = 0x01,
    EXT_FLASH_PROGRAM_CMD           = 0x02,
    EXT_FLASH_READ_CMD              = 0x03,
    EXT_FLASH_WRITE_DISABLE_CMD     = 0x04,
    EXT_FLASH_READ_STATUS_CMD       = 0x05,
    EXT_FLASH_WRITE_ENABLE_CMD      = 0x06,
    EXT_FLASH_SECTOR_ERASE_CMD      = 0x20,
    EXT_FLASH_BLOCK_ERASE_32_CMD    = 0x52,
    EXT_FLASH_CHIP_ERASE_CMD        = 0x60,
    EXT_FLASH_BLOCK_ERASE_64_CMD    = 0xd8,
    EXT_FLASH_READ_ID_CMD           = 0x9F,
    EXT_FLASH_RELEASE_DEEP_SLEEP    = 0xAB,
    EXT_FLASH_DEEP_SLEEP            = 0xB9,
    EXT_FLASH_SOFTWARE_RESET_ENABLE = 0x66,
    EXT_FLASH_SOFTWARE_RESET        = 0x99,
} EXT_FLASH_OPERATION_CMD;
Initialization of External Flash

Users can refer to the following function to initialize external flash. In this function, it will initialize SPI and reset external flash.

void ext_flash_spi_init(void)
Erase External Flash

Users can refer to the following function to erase external flash. Sector, block, and chip are the three common erase commands used for flash.

EXT_FLASH_SPI_OPERATION_STATUS ext_flash_spi_erase(uint32_t address, EXT_FLASH_OPERATION_CMD mode)
Write External Flash

Users can refer to the following function to write external flash by polling mode.

EXT_FLASH_SPI_OPERATION_STATUS ext_flash_spi_page_program(uint32_t address, uint8_t *psendBuf, uint16_t len)

Users can refer to the following function to write external flash by interrupt mode.

EXT_FLASH_SPI_OPERATION_STATUS ext_flash_spi_page_program_by_interrupt(uint32_t address, uint8_t *psendBuf, uint16_t len)

Users can refer to the following function to write external flash by GDMA mode.

EXT_FLASH_SPI_OPERATION_STATUS ext_flash_spi_page_program_by_dma(uint32_t address, uint8_t *psendBuf, uint16_t len)
Read External Flash

Users can refer to the following function to read external flash by polling mode.

EXT_FLASH_SPI_OPERATION_STATUS ext_flash_spi_read(uint32_t address, uint8_t *pStoreBuf, uint16_t len)

Users can refer to the following function to read external flash by interrupt mode.

EXT_FLASH_SPI_OPERATION_STATUS ext_flash_spi_read_by_interrupt(uint32_t address, uint8_t *pStoreBuf, uint16_t len)

Users can refer to the following function to read external flash by GDMA mode.

EXT_FLASH_SPI_OPERATION_STATUS ext_flash_spi_read_by_dma(uint32_t address, uint8_t *pStoreBuf, uint16_t len)

SPI Slave Note

The SPI slave does not support TX FIFO underflow conditions. The TX FIFO needs to be filled with data before the SPI master starts the transfer. There are two methods to avoid this condition:

  1. Send data to the SPI slave TX FIFO before transmission, then toggle a GPIO to notify the SPI master to send data. For the specific implementation, please refer to the demo code in src\sample\io_demo\spi\slave\spi_slave_gpio_demo.c.

  2. Use GDMA for the SPI slave to send data: Enable TX GDMA immediately after SPI slave init to ensure that there is always data in the SPI slave TX FIFO.

Note

If TX FIFO underflow occurs, users can reset SPI slave to recover.

For details, please refer to src\sample\io_demo\spi\slave\spi_slave_tx_dma_hs_demo.c.

SPI GDMA Flow Based on GPIO Indication

This section introduces SPI slave transfers based on GPIO Indication when communicating with the SPI master in GDMA mode. The SPI slave must send data to the TX FIFO before the SPI master starts to communicate with the SPI slave; otherwise, it will trigger TX FIFO underflow error interrupt for the SPI slave. Users can use GPIO to control the timing between the SPI master and the SPI slave. A GPIO pin needs to be toggled for the SPI slave to indicate that the TX data is ready, and the SPI master can transfer data afterward. For the detailed flow, please refer to SPI MISO Flow Chart.

SPI GDMA Note

If SPI is operated in CPU mode with GDMA handshake enabled, it may cause GDMA to get the false signal. So if it’s needed for SPI to read or write by GDMA after CPU mode, the GDMA handshake must be reset before starting GDMA.

SPI_GDMACmd(FLASH_SPI, SPI_GDMAReq_Rx, DISABLE);
SPI_GDMACmd(FLASH_SPI, SPI_GDMAReq_Rx, ENABLE);
GDMA_Cmd(SPI_RX_DMA_CHANNEL_NUM, ENABLE);

SPI Slave High Speed

The SPI slave needs to adjust the slow clock to support high speed, as shown in SPI Slow Clock Settings in RTL87x3E and SPI Slow Clock Settings in RTL87x3D.

For details, please refer to the demo code in src\sample\io_demo\spi\slave\spi_slave_tx_dma_hs_demo.c

and src\sample\io_demo\spi\slave\spi_slave_rx_dma_hs_demo.c.

SPI Clock Div

SPI Clock

Slave RX Slow Clock

Slave TX Slow Clock

16

2.5MHz

/

1.25MHz

10

4MHz

/

1.25MHz

8

5MHz

/

2.5MHz

4

10MHz

2.5M

4MHz

SPI Clock Div

SPI Clock

Slave TX Slow Clock

8

5MHz

2.5MHz

4

10MHz

5MHz

IR

IR Demo Code Support List

Demo 1

ir_send_polling_mode_demo.c

Sample Purpose

Demonstrate how IR sends data by polling mode.

File Path

sdk\src\sample\io_demo\ir\send\ir_send_polling_mode_demo.c

Function Entry

ir_send_polling_mode_demo()

Hardware Connection

Connect M2_2 to channel 0 of the logic analyzer.

Pin Definition

#define IR_SEND_PIN     P2_2

Expected Result

The waveform displayed by channel 0 of the logic analyzer is shown in IR Demo 1 Expected Result Diagram.

Demo 2

ir_send_interrupt_demo.c

Sample Purpose

Demonstrate how IR sends data by interrupt mode.

File Path

sdk\src\sample\io_demo\ir\send\ir_send_interrupt_demo.c

Function Entry

ir_send_interrupt_demo()

Hardware Connection

Connect M2_2 to channel 0 of the logic analyzer.

Pin Definition

#define IR_SEND_PIN     P2_2

Expected Result

The waveform displayed by channel 0 of the logic analyzer is shown in IR Demo 2 Expected Result Diagram.

Demo 3

ir_receive_demo.c

Sample Purpose

Demonstrate how IR receives data by interrupt mode.

File Path

sdk\src\sample\io_demo\ir\receive\ir_receive_demo.c

Function Entry

ir_receive_demo()

Hardware Connection

Connect M0_2 to the receiving end of the IR transceiver module, connect VCC of EVB to VCC of IR transceiver module, and connect GND of EVB to GND of IR transceiver module.

Pin Definition

#define IR_RECV_PIN     P0_2

Expected Result

Send IR data to the IR transceiver module by IR remote control. The received data is stored in array IR_DataStruct.irBuf.

Demo 4

ir_pulse_detection_demo.c

Sample Purpose

Demonstrate the pulse detection of duty and frequency of a PWM with IR.

File Path

sdk\src\sample\io_demo\ir\pulse_detection\ir_pulse_detection_demo.c

Function Entry

ir_pulse_detection_demo()

Hardware Connection

Connect M2_1 to PWM output.

Pin Definition

#define IR_RECV_PIN     P2_1

Expected Result

Print PWM frequency, high level count, and low level count information in Debug Analyzer.

Demo 5

ir_nec_protocol.c
ir_nec_protocol.h

Sample Purpose

Demonstrates encoding and decoding data by NEC protocol.

File Path

sdk\src\sample\io_demo\ir\protocol\ir_nec_protocol.c
sdk\src\sample\io_demo\ir\protocol\ir_nec_protocol.h

Function Entry

IR_NECEncode()
IR_NECDecode()

Expected Result

Call the API IR_NECEncode() and encode the data by the NEC protocol. Call the API IR_NECDecode() and decode the data by the NEC protocol.

Function Description

The infrared module can realize infrared wireless communication with adjacent devices.

Feature List

  • Configurable carrier frequency.

  • Configurable carrier duty cycle.

  • Configurable carrier ON/OFF time.

  • Hardware controlled waveform output.

  • Support any infrared communication protocol.

  • Support GDMA.

  • RX mode and TX mode cannot work at the same time.

  • IR module must be reset when switching between RX mode and TX mode.

IR TX

The schematic diagram of IR TX is shown in the figure below.

Send Data Operation Flow

IR Initialization Flow

IR initialization flow is shown in the following figure.

The codes below demonstrate the IR initialization flow.

/* Enable IR clock */
RCC_PeriphClockCmd(APBPeriph_IR, APBPeriph_IR_CLOCK, ENABLE);

/* Initialize IR */
IR_InitTypeDef IR_InitStruct;
IR_StructInit(&IR_InitStruct);
IR_InitStruct.IR_Freq           = 38;
IR_InitStruct.IR_DutyCycle      = 2; /* !< 1/2 duty cycle */
IR_InitStruct.IR_Mode           = IR_MODE_TX;
IR_InitStruct.IR_TxInverse      = IR_TX_DATA_NORMAL;
IR_InitStruct.IR_TxIdleLevel    = IR_IDLE_OUTPUT_LOW;
IR_InitStruct.IR_TxFIFOThrLevel = IR_TX_FIFO_THR_LEVEL;
IR_Init(&IR_InitStruct);

/* Configure NVIC */
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = IR_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 2;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);

IR Send Data Operation Flow

IR send data operation flow is shown in the following figure.

The codes below demonstrate the IR send data operation flow.

/* Buffer which stores encoded data */
IR_DataTypeDef IR_DataStruct;
/* Number of data which has been sent */
uint8_t tx_count = 0;

/* Data to send */
uint8_t ir_code[2] = {0x16, 0x28};

/* Make sure TX FIFO is empty */
IR_ClearTxFIFO();

/* Encode by NEC protocol */
IR_NECEncode(38, ir_code[0], ir_code[1], &IR_DataStruct);

/* Start to send the first bytes of encoded data */
IR_SendBuf(IR_DataStruct.irBuf, IR_TX_FIFO_SIZE, DISABLE);

/* Record the number which has been sent */
tx_count = IR_TX_FIFO_SIZE;

/* Enable IR threshold interrupt. When TX FIFO offset <= threshold value, trigger interrupt*/
IR_INTConfig(IR_INT_TF_LEVEL, ENABLE);

/* Must fill TX FIFO first */
IR_Cmd(IR_MODE_TX, ENABLE);

IR Interrupt Handle Flow

IR interrupt handle flow is shown in the following figure.

The codes below demonstrate the IR interrupt handle flow.

void ir_handler(void)
{
    /* Continue to send by interrupt */
    if (IR_GetINTStatus(IR_INT_TF_LEVEL) == SET)
    {
        IR_MaskINTConfig(IR_INT_TF_LEVEL, ENABLE);
        /* The remaining data is larger than the TX FIFO length */
        if ((NEC_LENGTH - tx_count) >= IR_TX_FIFO_SIZE)
        {
            IR_SendBuf(IR_DataStruct.irBuf + tx_count, (IR_TX_FIFO_SIZE - IR_TX_FIFO_THR_LEVEL), DISABLE);
            tx_count += (IR_TX_FIFO_SIZE - IR_TX_FIFO_THR_LEVEL);
        }
        else if ((NEC_LENGTH - tx_count) > 0)
        {
            /* The remaining data is less than the TX FIFO length */

            /*  Configure TX threshold level to zero and trigger interrupt when TX FIFO is empty */
            IR_SetTxThreshold(0);
            IR_SendBuf(IR_DataStruct.irBuf + tx_count, NEC_LENGTH - tx_count, ENABLE);
            tx_count += (NEC_LENGTH - tx_count);
        }
        else
        {
            /* Tx completed */
            uint8_t event = IO_DEMO_EVENT_IR_TX;
            /* Disable IR tx empty interrupt */
            IR_INTConfig(IR_INT_TF_LEVEL, DISABLE);
            tx_count = 0;
            if (os_msg_send(io_queue_handle, &event, 0) == false)
            {
                IO_PRINT_ERROR0("ir_handler: Send queue error");
            }
        }

        /* Clear threshold interrupt */
        IR_ClearINTPendingBit(IR_INT_TF_LEVEL_CLR);
        /* Unmask IR interrupt */
        IR_MaskINTConfig(IR_INT_TF_LEVEL, DISABLE);
    }
}

Receive Data Operation Flow

IR Initialization Flow

IR initialization flow is shown in the following figure.

The codes below demonstrate the IR initialization operation flow.

/* Enable IR clock */
RCC_PeriphClockCmd(APBPeriph_IR, APBPeriph_IR_CLOCK, ENABLE);

/* Initialize IR */
IR_InitTypeDef IR_InitStruct;
IR_StructInit(&IR_InitStruct);

IR_InitStruct.IR_Freq               = 38;/* IR carrier frequency is 38KHz */
IR_InitStruct.IR_DutyCycle          = 2;/* Duty ratio = 1/IR_DutyCycle */
IR_InitStruct.IR_Mode               = IR_MODE_RX;/* IR receiving mode */
IR_InitStruct.IR_RxStartMode        = IR_RX_AUTO_MODE;
IR_InitStruct.IR_RxFIFOThrLevel     = IR_RX_FIFO_THR_LEVEL; /* Configure RX FIFO threshold level to trigger IR_INT_RF_LEVEL interrupt */
IR_InitStruct.IR_RxFIFOFullCtrl     = IR_RX_FIFO_FULL_DISCARD_NEWEST;/* Discard the latest received data if RX FIFO is full */
IR_InitStruct.IR_RxTriggerMode      = IR_RX_RISING_EDGE;/* Configure trigger type */
IR_InitStruct.IR_RxFilterTime       = IR_RX_FILTER_TIME_50ns;/* If high to low or low to high transition time <= 50ns, filter it out. */
IR_InitStruct.IR_RxCntThrType       = IR_RX_Count_Low_Level;/* IR_RX_Count_Low_Level is counting low level */
IR_InitStruct.IR_RxCntThr           = 0x23a;/* Configure RX counter threshold. You can use it to decide to stop receiving IR data */
IR_Init(&IR_InitStruct);

/* Enable IR threshold interrupt. When RX FIFO offset >= threshold value, trigger interrupt*/
/* Enable IR counter threshold interrupt to stop receiving data */
IR_INTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, ENABLE);
IR_MaskINTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, DISABLE);

/* Configure NVIC */
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = IR_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 2;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);

IR_ClearRxFIFO();
IR_Cmd(IR_MODE_RX, ENABLE);

IR Receive Data Operation Flow

IR receive data operation flow is shown in the following figure.

The codes below demonstrate the IR receive data operation flow.

/* Wait for receiving the whole IR packets */
/* This is just a demo. You can send message from IR interrupt handler */
while (rx_count <= NEC_LENGTH - 5) {;};

if (IR_SUCCEED != IR_NECDecode(38, &address, &cmd, &IR_DataStruct))
{
    // Decoding error!
}
else
{
    // Decoding success!
}

IR Interrupt Handle Flow

IR interrupt handle flow is shown in the following figure.

The codes below demonstrate the IR interrupt handle flow.

void ir_handler(void)
{
    uint16_t len = 0;

    /* Receive by interrupt */
    if (IR_GetINTStatus(IR_INT_RF_LEVEL) == SET)
    {
        IR_MaskINTConfig(IR_INT_RF_LEVEL, ENABLE);
        len = IR_GetRxDataLen();
        IR_ReceiveBuf(IR_DataStruct.irBuf + rx_count, len);
        IR_DataStruct.bufLen += len;
        rx_count += len;
        IR_ClearINTPendingBit(IR_INT_RF_LEVEL_CLR);
        IR_MaskINTConfig(IR_INT_RF_LEVEL, DISABLE);
    }

    /* Stop to receive IR data */
    if (IR_GetINTStatus(IR_INT_RX_CNT_THR) == SET)
    {
        IR_MaskINTConfig(IR_INT_RX_CNT_THR, ENABLE);
        /* Read remaining data */
        len = IR_GetRxDataLen();
        IR_ReceiveBuf(IR_DataStruct.irBuf + rx_count, len);
        IR_DataStruct.bufLen += len;
        rx_count += len;
        IR_ClearINTPendingBit(IR_INT_RX_CNT_THR_CLR);
        IR_MaskINTConfig(IR_INT_RX_CNT_THR, DISABLE);
    }
}

RTC

RTC Demo Code Support List

Demo 1

rtc_demo.c

Sample Purpose

Demonstrate RTC comparator function.

File Path

sdk\src\sample\io_demo\rtc\comparator\rtc_demo.c

Function Entry

rtc_demo()

Expected Result

Print string ‘rtc_handler’ in Debug Analyzer every 1536ms.

Demo 2

rtc_overflow_demo.c

Sample Purpose

Demonstrate RTC count overflow function.

File Path

sdk\src\sample\io_demo\rtc\overflow\rtc_overflow_demo.c

Function Entry

rtc_overflow_demo()

Expected Result

For RTL87x3D, rtc_handler function is executed every 134217.728s. For RTL87x3E, rtc_handler function is executed every 524.288s.

Demo 3

rtc_tick_demo.c

Sample Purpose

Demonstrate RTC tick function.

File Path

sdk\src\sample\io_demo\rtc\tick\rtc_tick_demo.c

Function Entry

rtc_tick_demo()

Expected Result

rtc_handler function is executed every 31.25us.

Demo 4

rtc_clock_demo.c
rtc_clock_demo.h

Sample Purpose

Demonstrate RTC calendar functionality.

File Path

sdk\src\sample\io_demo\rtc\clock\rtc_clock_demo.c
sdk\src\sample\io_demo\rtc\clock\rtc_clock_demo.h

Function Entry

rtc_clock_demo()

Expected Result

1. Press the reset button on the EVB, string ‘rtc_clock_sys_update: year 2022, month 9, day 29, hour 0, minute 1, second 0’ will be printed in Debug Analyzer.
2. Print the time information log in Debug Analyzer every one minute.

Demo 5

rtc_in_power_down_mode.c

Sample Purpose

Demonstrate RTC work in power down mode.

File Path

sdk\src\sample\io_demo\rtc\power_down\rtc_in_power_down_mode.c

Function Entry

rtc_in_power_down_mode()

Expected Result

1. When system is in idle state, it will enter power down mode automatically and print string ‘app_dlps_enter_callback: 10 sec’ in Debug Analyzer.
2. After 10 seconds, the system wakes up and prints string ‘rtc_handler: RTC_INT_CMP0’ and string ‘rtc_handler: RTC_INT_CMP_1’ in Debug Analyzer.

Function Description

RTC is an independent timer. RTC has a set of continuous counting counters to provide a calendar clock. It can be converted into the current time and date of the system by querying the counter value.

Feature List

  • 32KHz clock source.

  • 24-bit read-only counter (RTL87x3E and RTL87x3EP), 32-bit read-only counter (RTL87x3D).

  • 12-bit prescaler.

  • Support 4 comparator interrupts.

  • Support overflow interrupt, indicating that the counter overflows and wraps around to 0.

  • Support tick interrupt.

  • Support wake-up system from low power mode.

  • Support 8 comparators.

  • 4 comparators can only be used to trigger wake-up.

  • 4 comparators can be used to trigger wake-up and CPU NVIC.

Comparator Function Operation Flow

RTC comparator function initialization flow is shown in the following figure.

The codes below demonstrate the RTC comparator function initialization flow.

void driver_rtc_init(void)
{
    RTC_DeInit();
    RTC_SetPrescaler(RTC_PRESCALER_VALUE);
    RTC_SetComp(RTC_COMP_INDEX, RTC_COMP_VALUE);
    RTC_MaskINTConfig(RTC_INT_CMP_1, DISABLE);
    RTC_CompINTConfig(RTC_INT_CMP_1, ENABLE);
    RamVectorTableUpdate(RTC_VECTORn, RTC_Handler);

    /* Configure RTC interrupt */
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = RTC_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

    /* Start RTC */
    RTC_SystemWakeupConfig(ENABLE);
    RTC_RunCmd(ENABLE);
}

RTC interrupt handle flow is shown in the following figure.

The codes below demonstrate the RTC interrupt handle flow.

void rtc_handler(void)
{
    IO_PRINT_TRACE0("rtc_handler");
    if (RTC_GetINTStatus(RTC_INT_CMP_1) == SET)
    {
        RTC_SetComp(RTC_COMP_INDEX, RTC_GetCounter() + RTC_COMP_VALUE);
        RTC_ClearCompINT(RTC_COMP_INDEX);
    }
}

Overflow Function Operation Flow

RTC overflow function initialization flow is shown in the following figure.

The codes below demonstrate the RTC overflow function initialization flow.

void driver_rtc_init(void)
{
    RTC_DeInit();
    RTC_SetPrescaler(RTC_PRESCALER_VALUE);
    RTC_MaskINTConfig(RTC_INT_OVF, DISABLE);

    RamVectorTableUpdate(RTC_VECTORn, rtc_handler);

    /* Config RTC interrupt */
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = RTC_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 2;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

    /* Start RTC */
    RTC_RunCmd(ENABLE);
}

RTC interrupt handle flow is shown in the following figure.

The codes below demonstrate the RTC interrupt handle flow.

void rtc_handler(void)
{
    /* RTC overflow interrupt handle */
    if (RTC_GetINTStatus(RTC_INT_OVF) == SET)
    {
        // Add application code here

        RTC_ClearOverFlowINT();
    }
}

Tick Function Operation Flow

RTC tick function initialization flow is shown in the following figure.

The codes below demonstrate the RTC tick function initialization flow.

void driver_rtc_init(void)
{
    RTC_DeInit();
    RTC_SetPrescaler(RTC_PRESCALER_VALUE);
    RTC_MaskINTConfig(RTC_INT_TICK, DISABLE);
    RTC_TickINTConfig(ENABLE);
    
    RamVectorTableUpdate(RTC_VECTORn, rtc_handler);

    /* Config RTC interrupt */
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = RTC_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 2;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

    /* Start RTC */
    RTC_RunCmd(ENABLE);
}

RTC interrupt handle flow is shown in the following figure.

The codes below demonstrate the RTC interrupt handle flow.

void rtc_handler(void)
{
    /* RTC overflow interrupt handle */
    if (RTC_GetINTStatus(RTC_INT_TICK) == SET)
    {
        // Add application code here

        RTC_ClearTickINT();
    }
}

LPC

LPC Demo Code Support List

Demo 1

lpc_comparator_demo.c

Sample Purpose

Demonstrate LPC comparator function.

File Path

sdk\src\sample\io_demo\lpc\comparator\lpc_comparator_demo.c

Function Entry

lpc_comparator_demo()

Hardware Connection

Connect M0_0 of EVB to an external DC voltage source.

Expected Result

Adjust the DC voltage source repeatedly, when the input voltage on M0_0 is detected to be higher than 400mV for 4 times, the string ‘lpc_rtc_handler: lpc_counter_value 4’ will be printed on Debug Analyzer.

Demo 2

lpc_peri_vol_demo.c

Sample Purpose

Demonstrate LPC voltage detection function.

File Path

sdk\src\sample\io_demo\lpc\voltage_detection\lpc_peri_vol_demo.c

Function Entry

lpc_peri_vol_demo()

Hardware Connection

Connect M0_0 of EVB to an external DC voltage source.

Expected Result

Adjust the DC voltage source, when the input voltage on M0_0 is detected to be lower than 800mV for 6 times, the string ‘lpc_handler: lpc_counter_value 6’ will be printed on Debug Analyzer.

Demo 3

lpc_rtc_vol_demo.c

Sample Purpose

Demonstrate LPC voltage detection function.

File Path

sdk\src\sample\io_demo\lpc\voltage_detection\lpc_rtc_vol_demo.c

Function Entry

lpc_rtc_vol_demo()

Hardware Connection

Connect M0_0 of EVB to an external DC voltage source.

Expected Result

Adjust the DC voltage source, when the input voltage on M0_0 is detected to be higher than 1200mV for 5 times, the string ‘lpc_rtc_handler: lpc_counter_value 5’ will be printed on Debug Analyzer.

Function Description

LPC can be used for voltage detection and counting. When the LPC detects that the input voltage exceeds the set voltage threshold, the system will trigger the interrupt. LPC can be used to count the number of times the input voltage exceeds the set voltage threshold. When the count value exceeds the set value of the comparator, the interrupt will be triggered.

Comparator Function Operation Flow

LPC comparator function initialization flow is shown in the following figure.

The codes below demonstrate the LPC comparator function initialization flow.

void driver_lpc_init(void)
{
    LPC_InitTypeDef LPC_InitStruct;
    LPC_StructInit(&LPC_InitStruct);
    LPC_InitStruct.LPC_Channel   = LPC_CAPTURE_PIN;
    LPC_InitStruct.LPC_Edge      = LPC_Vin_Over_Vth;
    LPC_InitStruct.LPC_Threshold = LPC_400_mV;
    LPC_Init(&LPC_InitStruct);

    LPC_CounterReset();
    LPC_WriteComparator(LPC_COMP_VALUE);
    LPC_INTConfig(LPC_INT_COUNT_COMP, ENABLE);

#if (TARGET_RTL87X3E == 1 || CONFIG_SOC_SERIES_RTL8773E == 1)
    RTC_CpuNVICEnable(ENABLE);
    RamVectorTableUpdate(RTC_VECTORn, lpc_rtc_handler);
    /* Config LPC interrupt */
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = RTC_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
#else
    LPC_INTConfig(LPC_INT_VOLTAGE_COMP, ENABLE);
    RamVectorTableUpdate(LPCOMP_VECTORn, lpc_rtc_handler);
    /* Config LPC interrupt */
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = LPCOMP_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
#endif

    LPC_Cmd(ENABLE);
    LPC_CounterCmd(ENABLE);
}

LPC comparator function interrupt handle flow is shown in the figure below.

The codes below demonstrate the LPC comparator function interrupt handle flow.

void lpc_rtc_handler(void)
{
    uint16_t lpc_counter_value = 0;

    IO_PRINT_INFO0("lpc_rtc_handler");

    /* LPC counter comparator interrupt */
    if (LPC_GetINTStatus(LPC_INT_COUNT_COMP) == SET)
    {
        lpc_counter_value = LPC_ReadCounter();
        IO_PRINT_INFO1("lpc_rtc_handler: lpc_counter_value %d", lpc_counter_value);

        LPC_WriteComparator(lpc_counter_value + LPC_COMP_VALUE);
        LPC_ClearINTPendingBit(LPC_INT_COUNT_COMP);
    }
}

Voltage Detection Function Operation Flow

The codes below demonstrate the LPC voltage detection function initialization flow.

void driver_lpc_init(void)
{
    LPC_InitTypeDef LPC_InitStruct;
    LPC_StructInit(&LPC_InitStruct);
    LPC_InitStruct.LPC_Channel   = LPC_CAPTURE_PIN;
    LPC_InitStruct.LPC_Edge      = LPC_Vin_Below_Vth;
    LPC_InitStruct.LPC_Threshold = LPC_800_mV;
    LPC_Init(&LPC_InitStruct);

    LPC_CounterReset();
    LPC_WriteComparator(LPC_COMP_VALUE);
    LPC_INTConfig(LPC_INT_COUNT_COMP, ENABLE);

#if (TARGET_RTL87X3E == 1 || CONFIG_SOC_SERIES_RTL8773E == 1)
    RTC_CpuNVICEnable(ENABLE);
    RamVectorTableUpdate(RTC_VECTORn, lpc_handler);
    /* Config LPC interrupt */
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = RTC_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
#else
    LPC_INTConfig(LPC_INT_VOLTAGE_COMP, ENABLE);
    RamVectorTableUpdate(LPCOMP_VECTORn, lpc_handler);
    /* Config LPC interrupt */
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = LPCOMP_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
#endif

    LPC_Cmd(ENABLE);
    LPC_CounterCmd(ENABLE);
}

The codes below demonstrate the LPC voltage detection function interrupt handle flow.

void lpc_handler(void)
{
    if (LPC_GetINTStatus(LPC_INT_COUNT_COMP) == SET)
    {
        IO_PRINT_INFO1("lpc_handler: lpc_counter_value %d", LPC_ReadCounter());
        LPC_CounterReset();
        LPC_ClearINTPendingBit(LPC_INT_COUNT_COMP);//Add Application code here
        //Add Application code here
    }
}

3-Wire SPI

3-Wire SPI Demo Code Support List

Demo 1

spi3wire_demo.c

Sample Purpose

Demonstrate how 3-wire SPI single write and read data.

Brief Introduction

Use 3-wire SPI for data transmission with PMW3610DM-SUDU mouse sensor. Obtain PMW3610DM-SUDU ID, check whether ID is correct, and print corresponding information in Debug Analyzer.

File Path

sdk\src\sample\io_demo\spi3w\polling\spi3wire_demo.c

Function Entry

spi3wire_demo()

CS Pin Definition

#define SPI_3WIRE_CS_PIN P0_2

DIO Pin Definition

#define SPI_3WIRE_DATA_PIN P0_1

SCLK Pin Definition

#define SPI_3WIRE_CLK_PIN P0_0

Speed

800KHz

Read Delay Time

2.5us

Hardware Connection

As shown in 3-Wire SPI Demo Hardware Connection Diagram. Connect M0_0 of EVB to SCLK of sensor, connect M0_1 of EVB to SDIO of sensor, connect M0_2 of EVB to NCS of sensor, connect GND of EVB to GND of sensor, connect U_5V_FT of EVB to 5V of sensor.

Expected Result

Press the reset button on the EVB, if the data transmission is successful, the string ‘spi3wire_demo: Read mouse sensor ID success’ will be printed in Debug Analyzer; otherwise, the string ‘spi3wire_demo: Read mouse sensor ID error’ will be printed in Debug Analyzer.

Function Description

3-Wire SPI is used to connect 3-wire SPI interfaces such as CS/DIO/SCLK and has single wire, single/burst read function. It is also possible to adjust the desired delay timing between read/write.

Note

Only RTL87x3D supports 3-wire SPI.

Feature List

  • Support 2-wire and 3-wire communication.

  • Support single write and read.

  • Support burst read.

  • Configurable delay between write and read.

3-Wire SPI Data Format

The data contains two bytes, the first byte is the address bit, the highest bit is the read/write control bit, and the second byte is the data byte. As shown below:

3-Wire SPI Write Operation

Write data from the controller to the sensor, only supports single write mode, as shown in the figure below. No delay needs to be added between the address byte and the data byte.

3-Wire SPI Read Operation

Single Read Mode

Between the first byte (address byte) and the second byte (data byte), a delay of ‘T-hold’ needs to be added. This delay is configured by SPI3WIRE_ReadDelay.

Burst Read Mode

In burst read mode, SPI can continuously read multiple bytes of data. Between the first byte (address byte) and the second byte (data byte 0), a delay of ‘T-hold’ needs to be added. This delay is configured by SPI3WIRE_ReadDelay. There is no delay between the third byte (data byte 1) and the second byte (data byte 0) until the end of a burst read.

Initialization Operation Flow

3-Wire SPI initialization flow is shown in the following figure.

The codes below demonstrate the 3-wire SPI initialization flow.

/* Enable 3-wire SPI clock */
RCC_PeriphClockCmd(APBPeriph_SPI2W, APBPeriph_SPI2W_CLOCK, ENABLE);

/* Initialize 3-wire SPI */
SPI3WIRE_InitTypeDef SPI3WIRE_InitStruct;
SPI3WIRE_StructInit(&SPI3WIRE_InitStruct);

SPI3WIRE_InitStruct.SPI3WIRE_SysClock       = 20000000;
SPI3WIRE_InitStruct.SPI3WIRE_Speed          = 800000;
SPI3WIRE_InitStruct.SPI3WIRE_Mode           = SPI3WIRE_3WIRE_MODE;
/* delay time = (SPI3WIRE_ReadDelay +1)/(2*SPI3WIRE_Speed). The delay time from the end of address phase to the start of read data phase */
//delay time = (0x03 + 1)/(2 * speed) = 2.5us
SPI3WIRE_InitStruct.SPI3WIRE_ReadDelay      = 0x3;
SPI3WIRE_InitStruct.SPI3WIRE_OutputDelay    = SPI3WIRE_OE_DELAY_NONE;
SPI3WIRE_InitStruct.SPI3WIRE_ExtMode        = SPI3WIRE_NORMAL_MODE;
SPI3WIRE_Init(&SPI3WIRE_InitStruct);

Send Data Operation Flow

3-Wire SPI sends data operation flow is shown in the following figure.

The codes below demonstrate the 3-wire SPI send data operation flow.

bool Mouse_SingleWrite(uint8_t address, uint8_t data)
{
    uint32_t timeout = 0;
    
    /* Check SPI busy or not */
    while (SPI3WIRE_GetFlagStatus(SPI3WIRE_FLAG_BUSY) == SET)
    {
        timeout++;
        if (timeout > 0x1ffff)
        {
            return false;
        }
    }
    
    /* Write data */
    SPI3WIRE_StartWrite(address, data);
    
    timeout = 0;
    /* Wait for communication to end */
    while (SPI3WIRE_GetFlagStatus(SPI3WIRE_FLAG_BUSY) == SET)
    {
        timeout++;
        if (timeout > 0x1ffff)
        {
            return false;
        }
    }
    return true;
}

Receive Data Operation Flow

3-Wire SPI receives data operation flow is shown in the following figure.

The codes below demonstrate the 3-wire SPI receives data operation flow.

uint8_t Mouse_SingleRead(uint8_t address)
{
    uint8_t reg_value = 0;
    uint32_t timeout = 0;

    /* Check SPI busy or not */
    while (SPI3WIRE_GetFlagStatus(SPI3WIRE_FLAG_BUSY) == SET)
    {
        timeout++;
        if (timeout > 0x1ffff)
        {
            break;
        }
    }

    /* Clear Receive data length */
    SPI3WIRE_ClearRxDataLen();
    SPI3WIRE_StartRead(address, 1);

    timeout = 0;
    /* Wait for the end of communication */
    while (SPI3WIRE_GetFlagStatus(SPI3WIRE_FLAG_BUSY) == SET)
    {
        timeout++;
        if (timeout > 0x1ffff)
        {
            break;
        }
    }

    /* Get the length of received data */
    while (SPI3WIRE_GetRxDataLen() == 0);
    /* Read data */
    SPI3WIRE_ReadBuf(&reg_value, 1);
    
    return reg_value;
}

CapTouch

CapTouch Demo Code Support List

Demo 1

cap_touch_demo.c

Sample Purpose

Demonstrates CapTouch how to detect finger touch and proximity by interrupt.

Brief Introduction

This sample code demonstrates CapTouch’s detection of finger touch and proximity through interrupts. In CapTouch interrupt handler, 4 channels can be detected, whether there is finger press/release/false touch/over noise threshold.

File Path

sdk\src\sample\io_demo\\captouch\cap_touch_demo.c

Function Entry

cap_touch_demo()

Channel pin location

Channel 0: P0_0
Channel 1: P0_1
Channel 2: P0_2
Channel 3: P0_3

Expected Result

Press the reset button on the EVB. When the channel pin is pressed/released, the interrupt status will be printed in Debug Analyzer.

Function Description

Capacitive touch controller uses a single pin and measures the capacitance between the capacitive sensor pin and ground. Capacitive touch controller uses changes in capacitance to detect the presence of a finger on or near a touch surface.

The sensor parasitic capacitance is called CP. When fingers touch or approach the sensor’s surface, it forms a simple parallel plate capacitor with the sensor pad through the overlay. The result is called finger capacitance CF, it increases the measured capacitance CS: CS = CP + CF.

In the initial state, an amount of charge is built-up on an untouched sensor to set the sensor’s reference level, CS=CP. As the finger makes contact with the sensor, it couples with the electric field of the sensor. This results in a drop of that sensor’s charge - since a portion of that charge is drained off through the finger to ground. Further charge transfers (conversions) from that sensor result in a reduced signal level compared to the untouched state.

Capacitive touch controller as CapTouch System shows is implemented by oversampling a high sensitivity ADC which only requires 1-pin per channel. The ADC will capture the voltage of both the reference level (baseline) and the signal level and transform them into digital raw data. If the difference between the reference level and the signal level is greater than the user-determined finger touch threshold, a touch is detected, and at the same time, a touch interrupt will be sent to the MCU to wake up the top system or other operations.

Capacitive touch controller supports up to 4 capacitive sensing inputs, which offers a wide detection range of capacitance, and best-in-class liquid tolerance. With the smart calibration function enabled, all channels’ sensitivity or thresholds could be adjusted individually according to different noise environments. Both of baseline value and the absolute finger touch threshold value will be calibrated automatically to adapt to environmental variation. The capacitive controller offers an adjustable scan period, resulting in lower power consumption.

Note

RTL87x3E supports CapTouch, RTL87x3D and RTL87x3EP don’t support CapTouch.

Feature List

  • Support 4 capacitive sensor channels.

  • Support wide parasitic capacitance range for each channel: 5~45pF (5uA sensitivity).

  • Support both finger touch detection and proximity detection.

  • Programmable enable/disable for each channel.

  • Adjustable sensitivity for each channel: 0.25uA~15.75uA.

  • Adjustable baseline and touch threshold (both difference and absolute value) for each channel.

  • Support liquid tolerance: guard sensor.

  • Programmable channel scan mode.

  • Auto scan mode: hardware automatically scans every enabled channel in sequence.

  • Automatic environment sensor capacitance tracking and calibration (ETC).

  • Support interrupt control.

  • Low power consumption.

CapTouch Channel Pin Location

  • Channel 0: P0_0

  • Channel 1: P0_1

  • Channel 2: P0_2

  • Channel 3: P0_3

Sample Range

CapTouch sample range is related to channel sensitivity; the more sensitive the channel, the shorter the sample range. The sensitivity parameter is used to increase or decrease the strength of the sensor signal (difference count), which means different counts for the same capacitance change. A higher value of the sensitivity setting (bias current) leads to a stronger signal from the sensors (more difference count for the same capacitance change), and also causes the decrease of the sample range. The typical sample range of CapTouch is 5~45pF when channel sensitivity is 5uA.

Environment Tracking and Calibration (ETC)

Sensor capacitance changes all the time according to environmental variations, such as temperature, moisture, overlay changes, or other slight environmental noise. The ETC module is built for tracking and calibration with environmental variation. The ETC function operates all the time during low power mode. The ETC system tracks the sensor capacitance change by period and updates the baseline and touch threshold based on the ETC automatic update algorithm.

There is no need for an extra scan operation except an active mode scan operation. ETC auto-tunes all the parameters of the ETC module, it works by capturing and comparing the data of the scan operation, and making a decision to update the baseline and absolute threshold or not.

Manual tuning of ETC parameters is also supported to meet different noise environments or special applications.

Touch Judgement Mode (with ETC Function Enable)

After ADC finishes data processing, decision logic will finish the following operations:

  1. Data average operation.

  2. Make subtraction operations of the average sample data and baseline.

  3. Compare difference data with difference threshold.

  4. If the difference data is larger than the difference threshold, touch or proximity is detected.

Auto Scan Mode

Hardware will scan every enabled channel in sequence during one scan period. For example, if channel 2 is disabled, then hardware will scan channel 0->1->3 once each scan period. The auto scan mode flow as Auto Scan Mode Flow Chart shows.

Scan Period

CapTouch scan period consists of active time and sleep time. Both the active time and sleep time can be set individually for different applications. The scan period as Schematic Diagram of Scan Period shows.

Active Time

The active time of CapTouch is defined by ADC scan sample number. CapTouch averages the sample raw data of capture ADC for best accuracy and noise immunity.

Sleep Time

After all of these operations for each channel, the channel enters the sleep period, and another channel begins to scan and process data. After 4 channels of scanning and data processing are finished, capture ADC power is off, and the CapTouch system enters an ultra-low power state until the next cycle of sensor scanning. During the sleep period, all channels are still enabled, and MCU uses clock gating to save power. Each channel could be disabled while a sensor error is detected or in other situations.

Baseline Auto-Initialization

The baseline initial value is 0x0 when CapTouch function enables, CapTouch will initialize baseline value automatically with ETC function and baseline initial function both are enabled. Hardware will set the baseline with average of ADC raw code. After that, hardware will enter normal scan mode (ETC scan and judge operation).

Noise Threshold

The environmental negative noise threshold means the maximum capacitance change of raw data that is still considered an environmental change. CapTouch system supports 2 noise thresholds: positive noise threshold and negative noise threshold for optimal calibration. Both of the two noise thresholds are individually adjustable for each channel.

Environmental noise usually changes slightly and slowly. Most of the noise average data ranges from 0~50, less than 40% * touch threshold even when Bluetooth or other RF transmissions occur beside the CapTouch device. The recommended value of noise threshold is 40% * touch threshold.

Specific operations take place while a signal changes significantly, which is larger than the noise threshold. For example, when a finger touches the sensor surface, glass or plastic overlay causes the difference data (baseline - signal) to be larger than the negative noise threshold. Glass or plastic being removed from the sensor surface or a finger released after CapTouch initiation both cause the difference data (signal - baseline) to be larger than the positive noise threshold. All of these operations are not normal environment noise variations.

CapTouch sends P_ENT interrupt to the host while the difference (signal - baseline) is larger than the positive noise threshold. The host needs to initialize the baseline when P_ENT is detected. CapTouch instructs the ETC module to ignore the ETC update operation automatically when the difference data (baseline - signal) is larger than the negative noise threshold.

Both noise thresholds need tuning for different applications and noise environments.

Fast Mode

To improve response time, the scan period can become smaller after detecting ADC raw data lower than the threshold. The smaller interval makes for a faster response time and higher power consumption.

Channel False Alarm and Release Active Counter

  • Fs Match Counter

    In idle mode, count how many scans meet the threshold condition. When fs_match_cnt meets the setting, the scan interval changes from slow mode to fast mode. When setting fs_match_cnt = 0, it will always be in slow mode.

  • False Alarm Counter

    Counting for false alarms. When fs_match_cnt meets and debounce_cnt doesn’t meet, the false alarm counter will count the scans in fast mode. After the false alarm counter meets, it returns to the idle state (slow interval).

  • Release Active Counter

    Counting for release active (triggered by the release active event). After the release active event, counting scans in fast mode. After the release active counter meets, it returns to the idle state (slow mode).

Channel Press Counter

  • False Touch Counter

    Counter for false touch. It starts after the debounce counter meets the setting. After the false touch counter triggers, it is forced to return to the idle state to prevent extra power consumption.

  • Fast Touch Counter

    Counting how many scans meet threshold conditions in fast mode. Calculate the press time according to this counter.

CapTouch Operation Flow

CapTouch initialization flow is shown in the following figure.

The codes below demonstrate the CapTouch initialization flow.

/* Enable CapTouch function */
CapTouch_SystemEnable(true);

/* Reset CapTouch system and clear all settings */
CapTouch_SysReset();

IO_PRINT_INFO2("cap_touch_demo: Start, max_channel %d, cap_touch_enable %d",
                   CapTouch_GetMaxChannel(), CapTouch_IsSystemEnable());

/* Register new interrupt handler to vector table */
RamVectorTableUpdate(TOUCH_VECTORn, (IRQ_Fun)CapTouch_Handler);

/* Enable specified channel */
CapTouch_ChCmd(CTC_CH0, ENABLE);
CapTouch_ChCmd(CTC_CH1, ENABLE);
CapTouch_ChCmd(CTC_CH2, ENABLE);
CapTouch_ChCmd(CTC_CH3, ENABLE);

/* Enable the specified CapTouch interrupts of specified channel */
CapTouch_ChINTConfig(CTC_CH0, (CTC_CH_INT_TYPE)(CTC_TOUCH_PRESS_INT | CTC_TOUCH_RELEASE_INT |
                                                    CTC_FALSE_TOUCH_INT), ENABLE);
CapTouch_ChINTConfig(CTC_CH1, (CTC_CH_INT_TYPE)(CTC_TOUCH_PRESS_INT | CTC_TOUCH_RELEASE_INT |
                                                    CTC_FALSE_TOUCH_INT), ENABLE);
CapTouch_ChINTConfig(CTC_CH2, (CTC_CH_INT_TYPE)(CTC_TOUCH_PRESS_INT | CTC_TOUCH_RELEASE_INT |
                                                    CTC_FALSE_TOUCH_INT), ENABLE);
CapTouch_ChINTConfig(CTC_CH3, (CTC_CH_INT_TYPE)(CTC_TOUCH_PRESS_INT | CTC_TOUCH_RELEASE_INT |
                                                    CTC_FALSE_TOUCH_INT), ENABLE);

/* Enable the specified CapTouch noise interrupts */
CapTouch_NoiseINTConfig(CTC_OVER_P_NOISE_INT, ENABLE);

/* Set scan interval */
if (!CapTouch_SetScanInterval(0x3B, CTC_SLOW_MODE))
{
    IO_PRINT_WARN0("cap_touch_demo: Slow mode scan interval overrange");
}
if (!CapTouch_SetScanInterval(0x1D, CTC_FAST_MODE))
{
    IO_PRINT_WARN0("cap_touch_demo: Fast mode scan interval overrange");
}

/* Enable touch wakeup from DLPS, PowerDown */
CapTouch_ChWakeupCmd(CTC_CH0, (FunctionalState)ENABLE);
CapTouch_ChWakeupCmd(CTC_CH1, (FunctionalState)ENABLE);
CapTouch_ChWakeupCmd(CTC_CH2, (FunctionalState)ENABLE);
CapTouch_ChWakeupCmd(CTC_CH3, (FunctionalState)ENABLE);

/*Should keep 32k clk if enable wakeup from power down mode*/
pmu_set_clk_32k_power_in_powerdown(true);

/* CapTouch start after 3s later */
CapTouch_Cmd(ENABLE, ENABLE);

CapTouch interrupt handle flow is shown in the following figure.

The codes below demonstrate the CapTouch interrupt handle flow.

void captouch_handler(void)
{
    uint32_t int_status = 0;
    int_status = CapTouch_GetINTStatus();
    IO_PRINT_INFO1("captouch_handler: int_status 0x%x", int_status);
    /* Channel 0 interrupts */
    if (CapTouch_IsChINTTriggered(int_status, CTC_CH0, CTC_TOUCH_PRESS_INT))
    {
        /* do something */
        CapTouch_ChINTClearPendingBit(CTC_CH0, CTC_TOUCH_PRESS_INT);
    }
    if (CapTouch_IsChINTTriggered(int_status, CTC_CH0, CTC_TOUCH_RELEASE_INT))
    {
        /* do something */
        CapTouch_ChINTClearPendingBit(CTC_CH0, CTC_TOUCH_RELEASE_INT);
    }
    if (CapTouch_IsChINTTriggered(int_status, CTC_CH0, CTC_FALSE_TOUCH_INT))
    {
        /* do something */
        CapTouch_ChINTClearPendingBit(CTC_CH0, CTC_FALSE_TOUCH_INT);
    }
    /* Channel 1 interrupts */
    if (CapTouch_IsChINTTriggered(int_status, CTC_CH1, CTC_TOUCH_PRESS_INT))
    {
        /* do something */
        CapTouch_ChINTClearPendingBit(CTC_CH1, CTC_TOUCH_PRESS_INT);
    }
    if (CapTouch_IsChINTTriggered(int_status, CTC_CH1, CTC_TOUCH_RELEASE_INT))
    {
        /* do something */
        CapTouch_ChINTClearPendingBit(CTC_CH1, CTC_TOUCH_RELEASE_INT);
    }
    if (CapTouch_IsChINTTriggered(int_status, CTC_CH1, CTC_FALSE_TOUCH_INT))
    {
        /* do something */
        CapTouch_ChINTClearPendingBit(CTC_CH1, CTC_FALSE_TOUCH_INT);
    }
    /* Channel 2 interrupts */
    if (CapTouch_IsChINTTriggered(int_status, CTC_CH2, CTC_TOUCH_PRESS_INT))
    {
        /* do something */
        CapTouch_ChINTClearPendingBit(CTC_CH2, CTC_TOUCH_PRESS_INT);
    }
    if (CapTouch_IsChINTTriggered(int_status, CTC_CH2, CTC_TOUCH_RELEASE_INT))
    {
        /* do something */
        CapTouch_ChINTClearPendingBit(CTC_CH2, CTC_TOUCH_RELEASE_INT);
    }
    if (CapTouch_IsChINTTriggered(int_status, CTC_CH2, CTC_FALSE_TOUCH_INT))
    {
        /* do something */
        CapTouch_ChINTClearPendingBit(CTC_CH2, CTC_FALSE_TOUCH_INT);
    }
    /* Channel 3 interrupts */
    if (CapTouch_IsChINTTriggered(int_status, CTC_CH3, CTC_TOUCH_PRESS_INT))
    {
        /* do something */
        CapTouch_ChINTClearPendingBit(CTC_CH3, CTC_TOUCH_PRESS_INT);
    }
    if (CapTouch_IsChINTTriggered(int_status, CTC_CH3, CTC_TOUCH_RELEASE_INT))
    {
        /* do something */
        CapTouch_ChINTClearPendingBit(CTC_CH3, CTC_TOUCH_RELEASE_INT);
    }
    if (CapTouch_IsChINTTriggered(int_status, CTC_CH3, CTC_FALSE_TOUCH_INT))
    {
        /* do something */
        CapTouch_ChINTClearPendingBit(CTC_CH3, CTC_FALSE_TOUCH_INT);
    }
    /* Noise Interrupt */
    if (CapTouch_IsNoiseINTTriggered(int_status, CTC_OVER_N_NOISE_INT))
    {
        /* do something */
        CapTouch_NoiseINTClearPendingBit(CTC_OVER_N_NOISE_INT);
    }
    if (CapTouch_IsNoiseINTTriggered(int_status, CTC_OVER_P_NOISE_INT))
    {
        IO_PRINT_ERROR0("captouch_handler: OVER_P_NOISE_INT baseline error, need to reset Cap-touch system");
        CapTouch_NoiseINTClearPendingBit(CTC_OVER_P_NOISE_INT);
    }
}

ADC

ADC Demo Code Support List

Demo 1

adc_demo.c

Sample Purpose

Demonstrates how ADC samples data by interrupt mode in one shot mode.

Brief Introduction

Uses one shot mode of ADC peripheral to measure voltage on P0_0, P0_1, VBAT, and VADP by interrupt. Prints voltage values in Debug Analyzer.

File Path

sdk\src\sample\io_demo\adc\one-shot\adc_demo.c

Function Entry

adc_demo()

Pre-Condition

Turn off ‘Charger auto enable’ and ‘Battery detection support’ on the MCUConfig Tool.

Channel

ADC0
ADC1
VBAT
VADPIN

External Channel Input Mode

ADC0 is divide mode and ADC1 is bypass mode.

Hardware Connection

As shown in ADC Demo Hardware Connection Diagram.
1. Connect M0_0 and M0_1 of EVB to external DC voltage source. Input voltage of M0_0 must range from 0 to 3.3V, and input voltage of M0_1 must range from 0 to 0.9V.
2. Connect VBAT to BAT+ and connect Lithium-ion battery to battery socket.
3. Connect VADP to U_5V_FT.

Expected Result

Prints voltage on P0_0, P0_1, VBAT and VADP in Debug Analyzer every 1000ms.

Demo 2

adc_polling_demo.c

Sample Purpose

Demonstrates how ADC samples data by polling mode in one shot mode.

Brief Introduction

Uses one shot mode of ADC peripheral to measure voltage on P0_1, VBAT, and VADP by polling. Prints voltage values in Debug Analyzer.

File Path

sdk\src\sample\io_demo\adc\one-shot\adc_polling_demo.c

Function Entry

adc_polling_demo()

Pre-Condition

Turn off ‘Charger auto enable’ and ‘Battery detection support’ on the MCUConfig Tool.

Channel

ADC1
VBAT
VADPIN

External Channel Input Mode

ADC1 is divide mode.

Hardware Connection

1. Connect M0_1 of EVB to external DC voltage source and input voltage of M0_1 must range from 0 to 3.3V.
2. Connect VBAT to BAT+ and connect Lithium-ion battery to battery socket.
3. Connect VADP to U_5V_FT.

Expected Result

Prints voltage on P0_1, VBAT, and VADP in Debug Analyzer.

Demo 3

adc_hw_average_demo.c

Sample Purpose

Demonstrates how ADC samples data with hardware average function.

Brief Introduction

Uses the hardware average function of the ADC peripheral to measure voltage on P0_1 and prints voltage values in Debug Analyzer.

File Path

sdk\src\sample\io_demo\adc\adc_hw_average\adc_hw_average_demo.c

Function Entry

adc_hw_average_demo()

Pre-Condition

Turn off ‘Charger auto enable’ and ‘Battery detection support’ on the MCUConfig Tool.

Channel

ADC1

External Channel Input Mode

ADC1 is divide mode.

Hardware Connection

Connect M0_1 of EVB to an external DC voltage source. Input voltage of M0_1 must range from 0 to 3.3V.

Expected Result

Print voltage on P0_1 in Debug Analyzer.

Demo 4

adc_manager_demo.c

Sample Purpose

Demonstrate how ADC samples data by ADC manager.

Brief Introduction

Uses one shot mode of the ADC peripheral to measure voltage on VBAT and VADP by ADC manager. Prints sample raw data in Debug Analyzer.

File Path

sdk\src\sample\io_demo\adc\adc_manger\adc_manager_demo.c

Function Entry

adc_manager_demo()

Channel

VBAT
VADPIN

Hardware Connection

1. Connect VBAT to BAT+ and connect Lithium-ion battery to battery socket.
2. Connect VADP to U_5V_FT.

Expected Result

Print sample raw data in Debug Analyzer.

Demo 5

adc_continuous_mode_demo.c

Sample Purpose

Demonstrates how ADC samples data in continuous mode with charger and discharger enabled.

Brief Introduction

Uses continuous mode of the ADC peripheral to measure voltage on P0_0 with charger and discharger enabled. Prints sample raw data and voltage in Debug Analyzer.

File Path

sdk\src\sample\io_demo\adc\adc_continuous_mode\adc_continuous_mode_demo.c

Function Entry

adc_continuous_mode_demo()

Pre-Condition

Turn on ‘Charger auto enable’ and ‘Battery detection support’ on the MCUConfig Tool.

Channel

ADC0

External Channel Input Mode

ADC0 is divide mode.

Hardware Connection

Connect M0_0 of EVB to an external DC voltage source. Input voltage of M0_0 must range from 0 to 3.3V.

Expected Result

When VADP and U_5V_FT are connected, ADC stops continuous sampling. When VADP and U_5V_FT are disconnected, ADC starts continuous sampling and prints sample raw data and voltage on P0_0 in Debug Analyzer.

Demo 6

adc_charger_demo.c

Sample Purpose

Demonstrates how ADC samples NTC and VBAT voltage.

Brief Introduction

Uses one shot mode of the ADC peripheral to measure voltage on VBAT and NTC by ADC manager. Prints voltage values in Debug Analyzer.

File Path

sdk\src\sample\io_demo\adc\adc_charger_demo\adc_charger_demo.c

Function Entry

adc_charger_demo()

Channel

ADC0
ADC1
VBAT

External Channel Input Mode

ADC0 and ADC1 are bypass mode.

Hardware Connection

1. Connect M0_0 and M0_1 of EVB to an external DC voltage source and input voltage must range from 0 to 0.9V.
2. Connect VBAT to BAT+ and connect Lithium-ion battery to battery socket.

Expected Result

Prints voltage on VBAT and NTC in Debug Analyzer every 500ms.

Feature List

  • VBAT and VADPIN internal channels.

  • Two external channel input modes: bypass mode and divide mode.

  • Support single-ended mode.

  • Two work modes: one shot mode and continuous mode.

  • 16 index schedule table.

  • TIMER 7 triggers ADC one shot mode sampling.

  • 32 depth FIFO for continuous mode.

  • Support hardware average function.

Note

RTL87x3D supports 8 external channels. RTL87x3E and RTL87x3EP support 4 external channels. RTL87x3EP doesn’t support continuous mode.

ADC Pin

  • RTL87x3D supports 8 external channels: external channel 0, 1, 2, 3, 4, 5, 6, and 7 correspond to pin P0_0, P0_1, P0_2, P0_3, P0_4, P0_5, P0_6, and P0_7.

  • RTL87x3E and RTL87x3EP support 4 external channels: external channel 0, 1, 2, and 3 correspond to pin P0_0, P0_1, P0_2, and P0_3.

Channel Mode

  • Single-Ended Mode

    Single-Ended mode occupies one channel and uses only one pin for sampling.

  • Internal VBAT and Internal VADPIN Modes

    Internal VBAT mode is used to measure VBAT voltage. Internal VADPIN mode is used to measure VADP voltage.

External Channel Input Mode

  • Bypass Mode

    The input range of ADC bypass mode is 0 to 0.9V.

  • Divide Mode

    The input range of ADC divide mode is 0 to 3.3V.

Work Mode

  • One Shot Mode

    • After ADC is enabled, only one sampling is performed. To sample again, the user needs to manually restart sampling.

    • It can cooperate with TIMER 7 peripheral to realize timing continuous sampling.

  • Continuous Mode

    • After ADC is enabled, sampling continues until ADC is disabled.

    • It can cooperate with GDMA continuous sampling.

ADC Schedule Table Index

  1. ADC has 16 schedule tables. Write the parameters in the table below into schIndex[0] ~ schIndex[15] to set channel mode and channel number.

  2. Then set bitmap, schIndex[0] ~ schIndex[15] corresponding to bit 0 ~ bit 15 of bitmap. If the specific bit of bitmap is set to 1, it means that the schedule table corresponding to this bit is enabled. For example, if config schIndex[0] and schIndex[1], then bitmap is 0000 0000 0011 (that is, 0x0003), if config schIndex[0] and schIndex[2], then bitmap is 0000 0000 0101 (that is, 0x0005).

  3. After ADC is enabled, ADC will sample successively according to the mode configured in the enabled schedule table.

schIndex

Description

EXT_SINGLE_ENDED(0)

Single-Ended mode, the input is external channel 0.

EXT_SINGLE_ENDED(1)

Single-Ended mode, the input is external channel 1.

EXT_SINGLE_ENDED(2)

Single-Ended mode, the input is external channel 2.

EXT_SINGLE_ENDED(3)

Single-Ended mode, the input is external channel 3.

EXT_SINGLE_ENDED(4)

Single-Ended mode, the input is external channel 4.

EXT_SINGLE_ENDED(5)

Single-Ended mode, the input is external channel 5.

EXT_SINGLE_ENDED(6)

Single-Ended mode, the input is external channel 6.

EXT_SINGLE_ENDED(7)

Single-Ended mode, the input is external channel 7.

INTERNAL_VBAT_MODE

Internal battery voltage detection channel.

INTERNAL_VADPIN_MODE

Internal adapter voltage detection channel.

ADC One Shot Mode Operation Flow

Polling Mode

The flow of ADC sampling in one shot mode by polling is shown in the following figure.

The codes below demonstrate the flow of ADC sampling in one shot mode by polling. For details, please refer to src\sample\io_demo\adc\one-shot\adc_polling_demo.c.

Note

To use the method below, please turn off ‘Charger auto enable’ and ‘Battery detection support’ on the MCUConfig Tool. As shown in Turn Off Charger on the MCUConfig Tool.

/* Enable ADC clock */
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE);

ADC_InitTypeDef adc_init_struct;
/* Fill each ADC_InitStruct member variable with its default value */
ADC_StructInit(&adc_init_struct);

/* Write the parameters into schedule table to set channel mode and channel number. */
adc_init_struct.schIndex[0] = EXT_SINGLE_ENDED(1);
adc_init_struct.schIndex[1] = INTERNAL_VBAT_MODE;
adc_init_struct.schIndex[2] = INTERNAL_VADPIN_MODE;
/* Set bitmap, schIndex[0] ~ schIndex[15] corresponding to bit0 ~ bit15 of bitmap.
   If the specific bit of bitmap is set to 1, it means that the schedule table corresponding to this bit is enabled.
   For example, if config schIndex[0] and schIndex[1], then bitmap is 0000 0000 0011 (that is, 0x0003),
   if config schIndex[0] and schIndex[2], then bitmap is 0000 0000 0101 (that is, 0x0005).
   After ADC is enabled, ADC will sample successively according to the mode configured in the enabled schedule table.
   */
adc_init_struct.bitmap = 0x07;
/* Initialize ADC */
ADC_Init(ADC, &adc_init_struct);

/* Enable ADC one shot mode done interrupt */
ADC_INTConfig(ADC, ADC_INT_ONE_SHOT_DONE, ENABLE);

/* Disable NVIC of ADC */
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = ADC_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
NVIC_InitStruct.NVIC_IRQChannelCmd = DISABLE;
NVIC_Init(&NVIC_InitStruct);

/* Enable ADC one shot sampling.
   When ADC is enabled, sampling will be done quickly.
   After initialization, ADC can be enabled when sampling is needed. */
ADC_Cmd(ADC, ADC_One_Shot_Mode, ENABLE);

/* Check ADC_INT_ONE_SHOT_DONE interrupt status flag */
while (ADC_GetIntFlagStatus(ADC, ADC_INT_ONE_SHOT_DONE) == RESET);

/* Clear ADC_INT_ONE_SHOT_DONE interrupt */
ADC_ClearINTPendingBit(ADC, ADC_INT_ONE_SHOT_DONE);

/* ADC one shot sampling mode, read data from schedule table.
   The schedule table index which config in ADC init function.
   The value is 0 ~ 15 */
data[0] = ADC_Read(ADC, 0);
data[1] = ADC_Read(ADC, 1);
data[2] = ADC_Read(ADC, 2);

/* Get conversion results based on data. The unit of the result is mV. */
res[0] = ADC_GetRes(data[0], EXT_SINGLE_ENDED(1));
res[1] = ADC_GetRes(data[1], INTERNAL_VBAT_MODE);
res[2] = ADC_GetRes(data[2], INTERNAL_VADPIN_MODE);

Interrupt Mode

The flow of ADC sampling in one shot mode by interrupt is shown in the following figure.

The codes below demonstrate the flow of ADC sampling in one shot mode by interrupt. For details, please refer to src\sample\io_demo\adc\one-shot\adc_demo.c.

Note

To use the method below, please turn off ‘Charger auto enable’ and ‘Battery detection support’ on the MCUConfig Tool.

/* Bypass mode config, please notice that the input voltage of
   ADC channel using bypass mode should not be over 0.9V */
ADC_HighBypassCmd(1, ENABLE);

/* Enable ADC clock */
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE);

ADC_InitTypeDef adcInitStruct;
/* Fill each ADC_InitStruct member variable with its default value */
ADC_StructInit(&adcInitStruct);

/* Write the parameters into schedule table to set channel mode and channel number. */
adcInitStruct.schIndex[0] = EXT_SINGLE_ENDED(0);
adcInitStruct.schIndex[1] = EXT_SINGLE_ENDED(1);
adcInitStruct.schIndex[2] = INTERNAL_VBAT_MODE;
adcInitStruct.schIndex[3] = INTERNAL_VADPIN_MODE;
/* Set bitmap, schIndex[0] ~ schIndex[15] corresponding to bit0 ~ bit15 of bitmap.
   If the specific bit of bitmap is set to 1, it means that the schedule table corresponding to this bit is enabled.
   For example, if config schIndex[0] and schIndex[1], then bitmap is 0000 0000 0011 (that is, 0x0003).
   If config schIndex[0] and schIndex[2], then bitmap is 0000 0000 0101 (that is, 0x0005).
   After ADC is enabled, ADC will sample successively according to the mode configured in the enabled schedule table.
   */
adcInitStruct.bitmap = 0x0f;
/* Initialize ADC */
ADC_Init(ADC, &adcInitStruct);

/* Enable ADC one shot mode done interrupt */
ADC_INTConfig(ADC, ADC_INT_ONE_SHOT_DONE, ENABLE);

/* Enable NVIC of ADC */
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = ADC_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 2;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);

/* Enable ADC one shot sampling.
   When ADC is enabled, sampling will be done quickly and interruption will occur.
   After initialization, ADC can be enabled when sampling is needed. */
ADC_Cmd(ADC, ADC_One_Shot_Mode, ENABLE);

ADC interrupt handle flow is shown in the following figure.

The codes below demonstrate the ADC interrupt handle flow.

void adc_handler(void)
{
    int32_t data[4];
    int32_t res[4];

    /* Check ADC_INT_ONE_SHOT_DONE interrupt status flag */
    if (ADC_GetIntFlagStatus(ADC, ADC_INT_ONE_SHOT_DONE) == SET)
    {
        /* Clear ADC_INT_ONE_SHOT_DONE interrupt */
        ADC_ClearINTPendingBit(ADC, ADC_INT_ONE_SHOT_DONE);
        /* ADC one shot sampling mode, read data from schedule table.
           The schedule table index which config in ADC_Init function.
           The value is 0 ~ 15 */
        data[0] = ADC_Read(ADC, 0);
        data[1] = ADC_Read(ADC, 1);
        data[2] = ADC_Read(ADC, 2);
        data[3] = ADC_Read(ADC, 3);
        /* Get conversion results based on data. The unit of the result is mV. */
        res[0] = ADC_GetRes(data[0], EXT_SINGLE_ENDED(0));
        res[1] = ADC_GetHighBypassRes(data[1], EXT_SINGLE_ENDED(1));
        res[2] = ADC_GetRes(data[2], INTERNAL_VBAT_MODE);
        res[3] = ADC_GetRes(data[3], INTERNAL_VADPIN_MODE);
    }
}

Hardware Average Mode

ADC hardware average function can only be used in one shot mode and only schedule table 0 can be used. For RTL87x3E and RTL87x3EP, it is recommended to use the hardware average function. The flow of ADC sampling in one shot mode by hardware average is shown in the following figure.

The codes below demonstrate the flow of ADC sampling in one shot mode by hardware average. For details, please refer to src\sample\io_demo\adc\adc_hw_average\adc_hw_average_demo.c.

Note

To use the method below, please turn off ‘Charger auto enable’ and ‘Battery detection support’ on the MCUConfig Tool.

/* Enable ADC clock */
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE);

ADC_InitTypeDef adc_init_struct;
/* Fill each ADC_InitStruct member variable with its default value */
ADC_StructInit(&adc_init_struct);

/* When hardware average function is enabled, ADC can only use schedule table 0 */
adc_init_struct.schIndex[0] = EXT_SINGLE_ENDED(1);
adc_init_struct.bitmap = 0x01;
/* Initialize ADC */
ADC_Init(ADC, &adc_init_struct);

/* Enable ADC hardware average function */
ADC_HwEvgEn(ADC, ENABLE);
/* Set the hardware average number of times */
ADC_HwEvgSel(ADC, ADC_DTAT_AVG_SEL_BY32);

/* Enable ADC one shot mode done interrupt */
ADC_INTConfig(ADC, ADC_INT_ONE_SHOT_DONE, ENABLE);

/* Enable NVIC of ADC */
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = ADC_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);

/* Enable ADC one shot sampling.
   When ADC is enabled, sampling will be done quickly and interruption will occur.
   After initialization, ADC can be enabled when sampling is needed. */
ADC_Cmd(ADC, ADC_One_Shot_Mode, ENABLE);

ADC interrupt handle flow is shown in the following figure.

The codes below demonstrate the ADC interrupt handle flow.

void adc_handler(void)
{
    int32_t data;
    int32_t result;

    /* Check ADC_INT_ONE_SHOT_DONE interrupt status flag */
    if (ADC_GetIntFlagStatus(ADC, ADC_INT_ONE_SHOT_DONE) == SET)
    {
        /* Clear ADC_INT_ONE_SHOT_DONE interrupt */
        ADC_ClearINTPendingBit(ADC, ADC_INT_ONE_SHOT_DONE);
        /* Read ADC data */
        data = ADC_HwEvgRead(ADC);
        /* Get conversion results based on data. The unit of the result is mV. */
        result = ADC_GetRes(data, EXT_SINGLE_ENDED(1));
    }
}

ADC Manager Mode

When the internal charger is enabled, it is necessary to use adc manager mode for ADC sampling. The flow of ADC sampling in one shot mode by ADC manager is shown in the following figure.

The codes below demonstrate the flow of ADC sampling in one shot mode by ADC manager. For details, please refer to src\sample\io_demo\adc\adc_charger_demo\adc_charger_demo.c and src\sample\io_demo\adc\adc_manger\adc_manager_demo.c.

Note

To use the method below, please turn on ‘Charger auto enable’ and ‘Battery detection support’ on the MCUConfig Tool.

/* Bypass mode config, please notice that the input voltage of
   ADC channel using bypass mode should not be over 0.9V */
ADC_HighBypassCmd(0, ENABLE);
ADC_HighBypassCmd(1, ENABLE);

ADC_InitTypeDef ADC_InitStruct;
/* Fill each ADC_InitStruct member variable with its default value */
ADC_StructInit(&ADC_InitStruct);

/* Set bitmap, schIndex[0] ~ schIndex[15] corresponding to bit0 ~ bit15 of bitmap. 
   If the specific bit of bitmap is set to 1, it means that the schedule table corresponding to this bit is enabled.
   For example, if config schIndex[0] and schIndex[1], then bitmap is 0000 0000 0011 (that is, 0x0003),
   if config schIndex[0] and schIndex[2], then bitmap is 0000 0000 0101 (that is, 0x0005).
   After ADC is enabled, ADC will sample successively according to the mode configured in the enabled schedule table.
   */
ADC_InitStruct.bitmap = 0x0007;
/* Write the parameters into schedule table to set channel mode and channel number. */
ADC_InitStruct.schIndex[0] = EXT_SINGLE_ENDED(0);
ADC_InitStruct.schIndex[1] = EXT_SINGLE_ENDED(1);
ADC_InitStruct.schIndex[2] = INTERNAL_VBAT_MODE;

/* Request for a channel in ADC manager */
if (!adc_mgr_register_req(&ADC_InitStruct,
                              (adc_callback_function_t)app_adc_vbat_ntc_voltage_read_callback,
                              &adc_channel_vbat_ntc_voltage))
{
    IO_PRINT_ERROR0("app_adc_vbat_ntc_voltage_init: adc_mgr_register_req failed");
}

/* Enable the specific ADC manager channel for sampling */
adc_mgr_enable_req(adc_channel_vbat_ntc_voltage);

ADC manager callback handle flow is shown in the following figure.

The codes below demonstrate the ADC manager callback handle flow.

static void app_adc_vbat_ntc_voltage_read_callback(void *pvPara, uint32_t int_status)
{
    uint16_t adc_data[3];
    uint16_t sched_bit_map = 0x0007;

    /* Read ADC sampling data of the specific ADC manager channel */
    adc_mgr_read_data_req(adc_channel_vbat_ntc_voltage, adc_data, sched_bit_map);

    /* Get conversion results based on data. The unit of the result is mV. */
    adc_charger_data_mgr.temperature_battery_1 = ADC_GetHighBypassRes(adc_data[0], EXT_SINGLE_ENDED(0));
    adc_charger_data_mgr.temperature_battery_2 = ADC_GetHighBypassRes(adc_data[1], EXT_SINGLE_ENDED(1));
    adc_charger_data_mgr.voltage_battery = ADC_GetRes(adc_data[2], INTERNAL_VBAT_MODE);
}

ADC Continuous Mode Operation Flow

GDMA Mode

The flow of ADC sampling in continuous mode by GDMA is shown in the following figure.

The codes below demonstrate the flow of ADC sampling in continuous mode by GDMA. For details, please refer to src\sample\io_demo\gdma\adc_dma\adc_gdma_demo.c.

Note

  1. To use the method below, please turn off ‘Charger auto enable’ and ‘Battery detection support’ on the MCUConfig Tool.

  2. Please refer to src\sample\io_demo\adc\adc_continuous_mode\adc_continuous_mode_demo.c for use of the internal charger and ADC continuous sampling mode at the same time.

/* Enable ADC clock */
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE);

ADC_InitTypeDef adc_init_struct;
/* Fill each ADC_InitStruct member variable with its default value */
ADC_StructInit(&adc_init_struct);

/* Write the parameters into schedule table to set channel mode and channel number. */
adc_init_struct.schIndex[0] = EXT_SINGLE_ENDED(0);
/* Set bitmap, schIndex[0] ~ schIndex[15] corresponding to bit0 ~ bit15 of bitmap.
   If the specific bit of bitmap is set to 1, it means that the schedule table corresponding to this bit is enabled.
   For example, if config schIndex[0] and schIndex[1], then bitmap is 0000 0000 0011 (that is, 0x0003),
   if config schIndex[0] and schIndex[2], then bitmap is 0000 0000 0101 (that is, 0x0005).
   After ADC is enabled, ADC will sample successively according to the mode configured in the enabled schedule table.
    */
adc_init_struct.bitmap = 0x01;
/* Set burst size to trigger GDMA request */
adc_init_struct.adcBurstSize = 8;
/* Initialize ADC */
ADC_Init(ADC, &adc_init_struct);

SLEEP LED

SLEEP LED Demo Code Support List

Demo 1

sleep_led_demo.c

Sample Purpose

Demonstrate SLEEP LED breathe mode.

File Path

sdk\src\sample\io_demo\led\sleep_led_demo.c

Function Entry

sleep_led_breathe_demo()

Phase0 Parameters

Duty update time: 10ms
Phase0 output time: 500ms
Initial high level time: 0
Duty step time: 0.03125ms
Change direction: increase

Phase1 Parameters

Duty update time: 10ms
Phase1 output time: 500ms
Initial high level time: 3.125ms
Duty step time: 0.0625ms
Change direction: increase

Phase2 Parameters

Duty update time: 10ms
Phase2 output time: 500ms
Initial high level time: 6.25ms
Duty step time: 0.09375ms
Change direction: increase

Phase3 Parameters

Duty update time: 10ms
Phase3 output time: 500ms
Initial high level time: 9.375ms
Duty step time: 0.125ms
Change direction: increase

Phase4 Parameters

Duty update time: 10ms
Phase4 output time: 500ms
Initial high level time: 9.375ms
Duty step time: 0.03125ms
Change direction: decrease

Phase5 Parameters

Duty update time: 10ms
Phase5 output time: 500ms
Initial high level time: 6.25ms
Duty step time: 0.0625ms
Change direction: decrease

Phase6 Parameters

Duty update time: 10ms
Phase6 output time: 500ms
Initial high level time: 3.125ms
Duty step time: 0.09375ms
Change direction: decrease

Phase7 Parameters

Duty update time: 10ms
Phase7 output time: 500ms
Initial high level time: 0
Duty step time: 0
Change direction: decrease

Hardware Connection

As shown in SLEEP LED Demo Hardware Connection Diagram. On EVB, connect M0_1 to LED1 and connect M2_1 to LED2 and connect M2_2 to LED3.

Pin Definition

#define LED_OUT_0     ADC_1
#define LED_OUT_1     P2_1
define LED_OUT_2     P2_2

Expected Result

LEDs turn from dark to bright and then from bright to dark in breathe mode.

Demo 2

sleep_led_demo.c

Sample Purpose

Demonstrate SLEEP LED blink mode.

File Path

sdk\src\sample\io_demo\led\sleep_led_demo.c

Function Entry

sleep_led_blink_demo()

Period Parameters

Channel0: period0, period1, and period2 high level time is 200ms, period0, period1, and period2 low level time is 100ms.
Channel1: period0 and period1 high level time is 200ms, period0 and period1 low level time is 100ms, period2 high level and low level time are 0.
Channel2: period0 high level time is 200ms, period0 low level time is 100ms, period1 and period2 high level and low level time are 0.

Hardware Connection

As shown in SLEEP LED Demo Hardware Connection Diagram. On EVB, connect M0_1 to LED1 and connect M2_1 to LED2 and connect M2_2 to LED3.

Pin Definition

#define LED_OUT_0     ADC_1
#define LED_OUT_1     P2_1
#define LED_OUT_2     P2_2

Expected Result

LEDs blink with 200ms on and 100ms off.

Function Description

SLEEP LED is used to control LED to make the effect of blinking light or breathing light.

Note

RTL87x3D and RTL87x3E support SLEEP LED. RTL87x3EP doesn’t support SLEEP LED.

Feature List

  • Support three channels.

  • Support blink mode and breathe mode.

  • 32KHz clock source.

  • 3 periods per channel in blink mode.

  • 8 phases per channel in breathe mode.

  • Support output level setting in idle state.

  • Support reverse output function.

  • Support period bypass in blink mode and phase bypass in breathe mode.

Note

If a default pull-up pin (P1_0/P1_1/P2_0/P3_0/P3_1) is set as a high active LED, or any other pull-down pin is set as a low active LED, it will blink when CPU reboots.

Breathe Mode

In breathe mode, one channel is divided into eight phases. As shown in the following figure, it is executed sequentially from phase0, and after the end of phase7, it goes to phase0 to continue the loop execution.

Note

  1. phase_timetick = prescale / 32000

  2. phase_uptate_rate[x]: duty update time = (phase_uptate_rate[x] + 1) * phase_timetick (x = 0, 1, 2, …, 7)

  3. phase_phase_tick[x]: The duration of the whole phase. phasex output time = phase_phase_tick[x] * phase_timetick (x = 0, 1, 2, …, 7)

  4. phase_initial_duty[x]: initial high level time = phase_initial_duty[x] / 32000 (x = 0, 1, 2, …, 7)

  5. phase_increase_duty[x]: The direction of each change of duty. 1: increase duty. 0: decrease duty. (x = 0, 1, 2, …, 7)

  6. phase_duty_step[x]: duty step time = phase_duty_step[x] / 32000 (x = 0, 1, 2, …, 7)

  7. After high level time increases to phase_timetick, it remains at phase_timetick.

  8. After high level time decreases to 0, it remains at 0.

  9. Low level time = phase_timetick - high level time

  10. If phase_phase_tick[x] is 0, this and subsequent phases are bypassed. For example, if phase_phase_tick[6] is 0, phase6 and phase7 are bypassed, it is executed sequentially from phase0, and after the end of phase5, it goes to phase0 to continue the loop execution.

Idle State

Call the SleepLed_SetIdleMode() API to set whether the channel outputs a high level or low level after the SLEEP LED is disabled.

Reverse Output Function

Each channel of SLEEP LED supports the reverse function. After the reverse function is enabled, the original waveform is reversed and output, the actual waveform is opposite to the set value.

Breathe Mode Operation Flow

The operation flow of SLEEP LED breathe mode is shown in the following figure.

The codes below demonstrate the SLEEP LED breathe mode operation flow.

/* Clear all the Sleep LED registers to their default reset values */
SleepLed_Reset();

SLEEP_LED_InitTypeDef Led_Initsturcture;
/* Fill each SLEEP_LED_InitTypeDef member variable with its default value */
SleepLed_StructInit(&Led_Initsturcture);

/* Set clock division factor */
Led_Initsturcture.prescale                    = 320;
/* Set SLEEP LED mode */
Led_Initsturcture.mode                        = LED_BREATHE_MODE;
/* Set reverse output function */
Led_Initsturcture.polarity                    = LED_OUTPUT_NORMAL;
/* Set duty update time */
Led_Initsturcture.phase_uptate_rate[0]              = 0;
/* Set the duration of the whole phase */
Led_Initsturcture.phase_phase_tick[0]               = 50;
/* Set initial high level time */
Led_Initsturcture.phase_initial_duty[0]             = 0;
/* Set the direction of each change of duty */
Led_Initsturcture.phase_increase_duty[0]            = 1;
/* Set duty step when duty is updated */
Led_Initsturcture.phase_duty_step[0]                = 1;

/* Set phase1 parameters */
Led_Initsturcture.phase_uptate_rate[1]              = 0;
Led_Initsturcture.phase_phase_tick[1]               = 50;
Led_Initsturcture.phase_initial_duty[1]             = 100;
Led_Initsturcture.phase_increase_duty[1]            = 1;
Led_Initsturcture.phase_duty_step[1]                = 2;

/* Set phase2 parameters */
Led_Initsturcture.phase_uptate_rate[2]              = 0;
Led_Initsturcture.phase_phase_tick[2]               = 50;
Led_Initsturcture.phase_initial_duty[2]             = 200;
Led_Initsturcture.phase_increase_duty[2]            = 1;
Led_Initsturcture.phase_duty_step[2]                = 3;

/* Set phase3 parameters */
Led_Initsturcture.phase_uptate_rate[3]              = 0;
Led_Initsturcture.phase_phase_tick[3]               = 50;
Led_Initsturcture.phase_initial_duty[3]             = 300;
Led_Initsturcture.phase_increase_duty[3]            = 1;
Led_Initsturcture.phase_duty_step[3]                = 4;

/* Set phase4 parameters */
Led_Initsturcture.phase_uptate_rate[4]              = 0;
Led_Initsturcture.phase_phase_tick[4]               = 50;
Led_Initsturcture.phase_initial_duty[4]             = 300;
Led_Initsturcture.phase_increase_duty[4]            = 0;
Led_Initsturcture.phase_duty_step[4]                = 1;

/* Set phase5 parameters */
Led_Initsturcture.phase_uptate_rate[5]              = 0;
Led_Initsturcture.phase_phase_tick[5]               = 50;
Led_Initsturcture.phase_initial_duty[5]             = 200;
Led_Initsturcture.phase_increase_duty[5]            = 0;
Led_Initsturcture.phase_duty_step[5]                = 2;

/* Set phase6 parameters */
Led_Initsturcture.phase_uptate_rate[6]              = 0;
Led_Initsturcture.phase_phase_tick[6]               = 50;
Led_Initsturcture.phase_initial_duty[6]             = 100;
Led_Initsturcture.phase_increase_duty[6]            = 0;
Led_Initsturcture.phase_duty_step[6]                = 3;

/* Set phase7 parameters */
Led_Initsturcture.phase_uptate_rate[7]              = 0;
Led_Initsturcture.phase_phase_tick[7]               = 50;
Led_Initsturcture.phase_initial_duty[7]             = 0;
Led_Initsturcture.phase_increase_duty[7]            = 0;
Led_Initsturcture.phase_duty_step[7]                = 0;
/* Initialize channel 0 */
SleepLed_Init(LED_CHANNEL_0, &Led_Initsturcture);
/* Initialize channel 1 */
SleepLed_Init(LED_CHANNEL_1, &Led_Initsturcture);
/* Initialize channel 2 */
SleepLed_Init(LED_CHANNEL_2, &Led_Initsturcture);
/* Enable Sleep led */
SleepLed_Cmd(LED_CHANNEL_1 | LED_CHANNEL_0 | LED_CHANNEL_2, ENABLE);

QDEC

QDEC Demo Code Support List

Demo 1

qdec_demo.c

Sample Purpose

Demonstrate how QDEC works.

Brief Introduction

This sample code demonstrates how QDEC works. The chip will detect the direction and count of wheel turns.

File Path

sdk\src\sample\io_demo\qdec\qdec_demo.c

Function Entry

qdec_demo()

Hardware Connection

As shown in QDEC Demo Hardware Connection Diagram. On EVB, connect P1_0 to the PHA of the wheel, connect P1_1 to the PHB of the wheel.

QDEC PHA Pin Definition

#define QDEC_Y_PHA_PIN P1_0

QDEC PHB Pin Definition

#define QDEC_Y_PHB_PIN P1_1

QDEC Axial

Y

Scan Clock

50KHz

Debounce Clock

5KHz

Debounce

Enable

Debounce Time

5ms

Expected Result

1. Press the reset button on the EVB.
2. When the wheel is turned, the direction is recorded in the variable dir, and the count is recorded in the variable y_axis.

Function Description

As shown in the following figure, QDEC is used to detect the motion state of the rotation-sensing device. When the rotating device moves, it will output two quadrature signals PHA and PHB. QDEC judges the direction of rotation by detecting the phase change of PHA and PHB.

Feature List

  • Support 3 axes.

  • Support hardware debounce: debounce time for each axis can be set independently.

  • Support initial phase setting.

  • Support illegal phase change detection.

  • 16-bit phase change counter.

Note

RTL87x3E cannot disable the hardware debounce function. RTL87x3D can disable the hardware debounce function.

Direction Judgment and Counting Method

  1. PHA and PHB are combined into a 2-bit number. PHA is the high bit, and PHB is the low bit.

  2. The phases are divided into four types: 00, 01, 11, and 10.

  3. As shown in the following figure, changes in the order of 00, 01, 11, and 10 are defined as positive. When the counter scale is set to 0, the counter will increase by one when the phase changes once. When the counter scale is set to 1, the counter will increase by one when the phase changes twice.

  4. Changes in the order of 00, 10, 11, and 01 are defined as negative. When the counter scale is set to 0, the counter will decrease by one when the phase changes once. When the counter scale is set to 1, the counter will decrease by one when the phase changes twice.

  5. PHA and PHB should only have one signal change at a time. If both signals change at the same time, the state is considered wrong. When this error state occurs, the counter does not count. Illegal interrupts can be turned on to detect this error condition.

QDEC Operation Flow

QDEC operation flow is shown in the following figure.

The codes below demonstrate the QDEC operation flow.

RCC_PeriphClockCmd(APBPeriph_QDEC, APBPeriph_QDEC_CLOCK, ENABLE);

QDEC_InitTypeDef qdecInitStruct;
QDEC_StructInit(&qdecInitStruct);
qdecInitStruct.ScanClockKHZ         = 50; /*!< 50KHz */
qdecInitStruct.DebonceClockKHZ     = 5; /*!< 5KHz */
qdecInitStruct.axisConfigY       = ENABLE;
qdecInitStruct.debounceEnableY   = Debounce_Enable;
qdecInitStruct.debounceTimeY     = 5 * 5; /*!< 5ms */

QDEC_Init(QDEC, &qdecInitStruct);

RamVectorTableUpdate(Qdecode_VECTORn, (IRQ_Fun)qdec_handler);
QDEC_INTConfig(QDEC, QDEC_Y_INT_NEW_DATA, ENABLE);

NVIC_InitTypeDef nvic_init_struct;
nvic_init_struct.NVIC_IRQChannel         = QDEC_IRQn;
nvic_init_struct.NVIC_IRQChannelCmd      = (FunctionalState)ENABLE;
nvic_init_struct.NVIC_IRQChannelPriority = 3;
NVIC_Init(&nvic_init_struct);

QDEC_Cmd(QDEC, QDEC_AXIS_Y, ENABLE);

QDEC interrupt handle flow is shown in the following figure.

The codes below demonstrate the QDEC interrupt handle flow.

void qdec_handler(void)
{
    /* Check Y-axis counter interrupt status flag */
    if (QDEC_GetFlagState(QDEC, QDEC_FLAG_NEW_CT_STATUS_Y) == SET)
    {
        /* Mask Y-axis counter interrupt */
        QDEC_INTMask(QDEC, QDEC_Y_CT_INT_MASK, ENABLE);

        /* Read direction */
        dir = QDEC_GetAxisDirection(QDEC, QDEC_AXIS_Y);
        /* Read counter count value */
        y_axis = QDEC_GetAxisCount(QDEC, QDEC_AXIS_Y);
        IO_PRINT_INFO2("qdec_handler: dir %d, y_axis %d", dir, y_axis);
        /* clear Y-axis counter interrupt status flag */
        QDEC_ClearFlags(QDEC, QDEC_CLR_NEW_CT_Y);
        /* Unmask Y-axis counter interrupt */
        QDEC_INTMask(QDEC, QDEC_Y_CT_INT_MASK, DISABLE);
    }
}

KeyScan

KeyScan Demo Code Support List

Demo 1

keyscan_demo.c

Sample Purpose

Demonstrates that KeyScan works in active mode.

File Path

sdk\src\sample\io_demo\keyscan\active\keyscan_demo.c

Function Entry

keyscan_demo()

Hardware Connection

As shown in KeyScan Hardware Connection Diagram. EVB is connected to matrix keyboard module: connect M0_2 to ROW0, M0_3 to ROW1, M0_0 to COLUMN0, and M0_1 to COLUMN1.

Pin Definition

#define COLUMN0     ADC_0
#define COLUMN1     ADC_1
#define ROW0     ADC_2
#define ROW1     ADC_3

Expected Result

1. When a key is pressed, key information is printed on Debug Analyzer.
2. When all keys are released, the string ‘io_demo_task: All key release’ is printed on Debug Analyzer.

Demo 2

keyscan_demo_dlps.c

Sample Purpose

Demonstrates that KeyScan works in DLPS mode.

File Path

sdk\src\sample\io_demo\keyscan\dlps\keyscan_demo_dlps.c

Function Entry

keyscan_demo_dlps()

Hardware Connection

As shown in KeyScan Hardware Connection Diagram. EVB is connected to matrix keyboard module: connect M0_2 to ROW0, M0_3 to ROW1, M0_0 to COLUMN0, and M0_1 to COLUMN1.

Pin Definition

#define COLUMN0     ADC_0
#define COLUMN1     ADC_1
#define ROW0     ADC_2
#define ROW1     ADC_3

Expected Result

1. Press the reset button on the EVB, the string ‘io_dlps_enter’ will be printed on Debug Analyzer and the system will enter DLPS mode.
2. When a key is pressed, the system will be woken up and key information is printed on Debug Analyzer.
3. When all keys are released, the string ‘keyscan_release_handle: All key release’ is printed on Debug Analyzer and the system will enter DLPS mode.

Function Description

KeyScan needs to be used with an external key matrix. In the idle state, row[x] is input, pull high is required, column[y] is output low, and output mode must be open-drain. When any key is pressed, the level of the corresponding row changes from high to low, triggering KeyScan hardware scan action.

After the debounce is completed, the first scan starts. When scanning, the column[y] being scanned is output low, and the other columns output high. If row[x] is low at this time, it is considered that row[x] column[y] key is pressed.

Scan order is first column[0] fixed, scan from row[0] to row[x], then column[1] fixed, scan from row[0] to row[x], until column[y].

Note

RTL87x3D and RTL87x3E support KeyScan, RTL87x3EP doesn’t support KeyScan.

Feature List

  • Support 12 (row) * 20 (column) matrix scan.

  • Configurable number of rows (1-12), columns (1-20).

  • Support hardware debounce, configurable debounce time.

  • Configurable scan clock.

  • Support multi-key detection, up to 26 keys can be pressed at the same time.

  • Support periodic scan, configurable scan period.

  • 26 bytes FIFO depth.

  • Support auto scan and manual scan.

  • Support all key release hardware detection.

Clock Divider

IO Clock will be divided into 2 channels.

The KeyScan scan clock is generated by the frequency division of keyscan_clk_div (11 bits), which can be freely configured in the range of 10KHz ~ 100KHz.

The low-level delay clock is generated by the frequency division of keyscan_delay_div (6 bits) for use by the relevant timer.

Auto Scan Mode

The workflow of automatic scanning is shown in the figure below.

Interrupt

  1. KEYSCAN_INT_OVER_READ

    When there is no data in the FIFO, reading the FIFO will trigger this interrupt to prevent over-reading.

  2. KEYSCAN_INT_SCAN_END

    Whether the key value is scanned or not, the interrupt will be triggered as long as the scanning action is completed.

  3. KEYSCAN_INT_FIFO_NOT_EMPTY

    If there is data in the FIFO, the interrupt will be triggered.

  4. KEYSCAN_INT_THRESHOLD

    This interrupt is triggered when data in the FIFO reaches the threshold level.

  5. KEYSCAN_INT_ALL_RELEASE

    When the release time count reaches the set value, if no key is pressed, the interrupt is triggered.

KeyScan Operation Flow

KeyScan initialization flow is shown in the following figure.

The codes below demonstrate the KeyScan initialization flow.

For details, please refer to src\sample\io_demo\keyscan\active\keyscan_demo.c.

RCC_PeriphClockCmd(APBPeriph_KEYSCAN, APBPeriph_KEYSCAN_CLOCK, ENABLE);
KEYSCAN_InitTypeDef  KeyScan_InitStruct;
KeyScan_StructInit(&KeyScan_InitStruct);
KeyScan_InitStruct.colSize         = KEYPAD_COLUMN_SIZE;
KeyScan_InitStruct.rowSize         = KEYPAD_ROW_SIZE;
KeyScan_InitStruct.scanInterval    = 0x80;
KeyScan_Init(KEYSCAN, &KeyScan_InitStruct);
KeyScan_INTConfig(KEYSCAN, KEYSCAN_INT_SCAN_END | KEYSCAN_INT_ALL_RELEASE, ENABLE);

NVIC_InitTypeDef nvic_init_struct;
nvic_init_struct.NVIC_IRQChannel         = KeyScan_IRQn;
nvic_init_struct.NVIC_IRQChannelCmd      = (FunctionalState)ENABLE;
nvic_init_struct.NVIC_IRQChannelPriority = 3;
NVIC_Init(&nvic_init_struct);

KeyScan_Cmd(KEYSCAN, ENABLE);

I2S

Function Description

I2S interface can support audio protocols such as I2S, Left-Justified, PCM, and TDM. Through the I2S interface, RTL87x3E and RTL87x3D can bridge to an external DSP core (or audio codec/audio amplifier). I2S can be operated in GDMA mode or FIFO mode. Set the buffer size according to the amount of transferred data in GDMA mode, or access I2S FIFO directly to transmit and receive data in FIFO mode. It is recommended to transfer the audio data via GDMA automatically since it can reduce the number of interrupts and improve efficiency.

Feature List

  • Configurable BCLK and LRCK clock rate.

  • Support I2S, Left-Justified, PCM format.

  • Support 16/ 20/ 24/ 32 bits data resolution (data width).

  • Support 16/ 20/ 24/ 32 bits word length (channel width).

  • Support non-TDM (2-ch), TDM4 (4-ch), TDM6 (6-ch), and TDM8 (8-ch).

  • Support master and slave mode.

  • Support GDMA handshake operation.

Note

  1. RTL87x3D has 4 ports, RTL87x3E has 2 ports.

  2. RTL87x3D supports up to TDM8, RTL87x3E supports up to TDM4.

I2S Initialization Flow

I2S function initialization flow is shown in the following figure.

The codes below demonstrate the I2S function initialization flow.

Note

As mentioned in PINMUX and PAD function descriptions, I2S PAD should be configured as software mode and pulled down when I2S is disabled to prevent PAD from floating during low power mode.

void board_i2s_init(void)
{
    /* set PAD_SW_MODE & PAD_PULL_DOWN when I2S is disabled to prevent PAD floating in low power mode */
    Pad_Config(I2S_BCLK_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_LOW);
    Pad_Config(I2S_LRCK_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_LOW);
    Pad_Config(I2S_SDO_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_LOW);
    Pad_Config(I2S_SDI_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_LOW);

    Pinmux_Config(I2S_BCLK_PIN, I2S_BCLK_PINMUX);
    Pinmux_Config(I2S_LRCK_PIN, I2S_LRCK_PINMUX);
    Pinmux_Config(I2S_SDO_PIN, I2S_SDO_PINMUX);
    Pinmux_Config(I2S_SDI_PIN, I2S_SDI_PINMUX);
}

void driver_i2s_init(void)
{
    I2S_InitTypeDef I2S_InitStruct;

    I2S_StructInit(&I2S_InitStruct);
    I2S_InitStruct.I2S_ClockSource      = I2S_CLK_XTAL;
    /* BCLK = 40MHz * (I2S_BClockNi / I2S_BClockMi), LRCK = BCLK / (I2S_BClockDiv + 1) */
    I2S_InitStruct.I2S_BClockMi         = 0x271;    /* LRCK = 48KHz */
    I2S_InitStruct.I2S_BClockNi         = 0x30;     /* BCLK = 3.072MHz */
    I2S_InitStruct.I2S_BClockDiv        = 0x3F;
    I2S_InitStruct.I2S_DeviceMode       = I2S_DeviceMode_Master;
    I2S_InitStruct.I2S_TxChannelType    = I2S_Channel_Stereo;
    I2S_InitStruct.I2S_TxDataWidth      = I2S_Width_24Bits;
    I2S_InitStruct.I2S_RxDataWidth      = I2S_Width_24Bits;
    I2S_InitStruct.I2S_TxChannelWidth   = I2S_Width_32Bits;
    I2S_InitStruct.I2S_RxChannelWidth   = I2S_Width_32Bits;
    I2S_InitStruct.I2S_TxDataFormat     = I2S_Mode;
    I2S_InitStruct.I2S_RxDataFormat     = I2S_Mode;
    I2S_InitStruct.I2S_DMACmd           = I2S_DMA_DISABLE;
    I2S_Init(I2S_NUM, &I2S_InitStruct);

    I2S_Cmd(I2S_NUM, I2S_MODE_TRX, ENABLE);
}

Clock Divider

  1. BCLK fractional divider according to the following equation: BCLK = XTAL 40MHz * (I2S_BClockNi / I2S_BClockMi).

    1. Example: For XTAL 40MHz clock source to generate 12.288MHz BCLK case. It’s recommended to use the settings of I2S_BClockNi = 192 and I2S_BClockMi = 625.

    2. Note that because the clock source comes from XTAL 40MHz, BCLK would be a jittered clock composed of 10MHz and 13.33MHz in practice.

  2. Set even-bit integer divider for LRCK according to the following equation: LRCK = BCLK / (I2S_BClockDiv + 1).

    1. Where I2S_BClockDiv could be calculated by: I2S_BClockDiv = (channel width * channel number) - 1.

    2. The channel number is determined by the TDM (Time Division Multiplexing) mode, 2-channels for without-TDM mode, 4-channels for TDM4 mode, and so on.

    3. The recommended clock divider setting for 2-channels & 32-bit channel width is shown below.

BCLK Frequency

Clock Source

I2S_BClockNi

I2S_BClockMi

I2S_BClockDiv

Sampling Rate

0.512 MHz

XTAL 40MHz

8

625

63

8 KHz

0.768 MHz

XTAL 40MHz

12

625

63

12 KHz

1.024 MHz

XTAL 40MHz

16

625

63

16 KHz

1.536 MHz

XTAL 40MHz

24

625

63

24 KHz

2.048 MHz

XTAL 40MHz

32

625

63

32 KHz

3.072 MHz

XTAL 40MHz

48

625

63

48 KHz

6.144 MHz

XTAL 40MHz

96

625

63

96 KHz

12.288 MHz

XTAL 40MHz

192

625

63

192 KHz

2.8224 MHz

XTAL 40MHz

441

6250

63

44.1 KHz

5.6448 MHz

XTAL 40MHz

441

3125

63

88.2 KHz

0.7056 MHz

XTAL 40MHz

441

25000

63

11.025 KHz

1.4112 MHz

XTAL 40MHz

441

12500

63

22.05 KHz

  1. As mentioned above, I2S BCLK is a jittered clock composed of two frequencies that are generated from XTAL 40MHz. The clock jitter percentage generated from XTAL 40MHz is shown in below.

BCLK (MHz) Clock Jitter Percentage (%)
Sampling Rate 48KHz Group 1.024 1.132
2.048 1.032
3.072 1.772
6.144 1.297
12.288 1.627
Sampling Rate 44.1KHz Group 2.8224 1.241
5.6448 1.261
11.2896 1.24

LRCK (KHz)

Clock Jitter Percentage (%)

16

0

48

0.08

96

0.179

44.1

0.107

88.2

0.114

192

0.168

  1. Clock jitter could be calculated by the following equation.

    Clock Jitter Percentage = max ( |(Tmin period - Tideal) / Tideal| , |(Tmax period - Tideal) / Tideal| ) * 100%

I2S Operation Flow

I2S TX GDMA Handshake Operation

  1. Turn on the peripheral clock source of the GDMA.

  2. I2S TX and GDMA initialization: Set GDMA handshake with I2S TX.

  3. Enable the GDMA_INT_Transfer interrupt and enable GDMA.

  4. Invoke I2S_Cmd to generate LRCK and start retrieving data from TX FIFO.

  5. Initiate GDMA request if TX FIFO water level is lower than TX GDMA burst size.

  6. Trigger GDMA transfer interrupt and wait for GDMA transfer to complete.

  7. Clear GDMA_INT_Transfer interrupt.

The flow chart of I2S TX GDMA handshake operation is shown in the following figure.

I2S RX GDMA Handshake Operation

  1. Turn on the peripheral clock source of the GDMA.

  2. I2S RX and GDMA initialization: Set GDMA handshake with I2S RX.

  3. Enable the GDMA_INT_Transfer interrupt and enable GDMA.

  4. Invoke I2S_Cmd to generate LRCK and start sending data to RX FIFO.

  5. Wait for RX FIFO data to exceed RX GDMA burst size and initiate GDMA request.

  6. Trigger GDMA transfer interrupt and wait for GDMA transfer to complete.

  7. Clear GDMA_INT_Transfer interrupt.

The flow chart of I2S RX GDMA handshake operation is shown in the following figure.

The codes below demonstrate the I2S GDMA handshake initialization flow.

void driver_gdma_init(T_I2S_CONFIG_DIR dir)
{
    GDMA_InitTypeDef gdma_init;
    NVIC_InitTypeDef nvic_init;

    RCC_PeriphClockCmd(APBPeriph_GDMA, APBPeriph_GDMA_CLOCK, ENABLE);

    GDMA_StructInit(&gdma_init);
    gdma_init.GDMA_BufferSize           = I2S_DMA_BUF_LEN;
    gdma_init.GDMA_SourceDataSize       = GDMA_DataSize_Word;
    gdma_init.GDMA_DestinationDataSize  = GDMA_DataSize_Word;
    gdma_init.GDMA_SourceMsize          = GDMA_Msize_4;
    gdma_init.GDMA_DestinationMsize     = GDMA_Msize_4;

    if (dir == I2S_CONFIG_TX)
    {
        gdma_init.GDMA_ChannelNum           = I2S_TX_DMA_CHANNEL_NUM;
        gdma_init.GDMA_DIR                  = GDMA_DIR_MemoryToPeripheral;
        gdma_init.GDMA_SourceAddr           = (uint32_t)(i2s_send_buff);
        gdma_init.GDMA_DestinationAddr      = (uint32_t)I2S_TX_ADDR;
        gdma_init.GDMA_SourceInc            = DMA_SourceInc_Inc;
        gdma_init.GDMA_DestinationInc       = DMA_DestinationInc_Fix;
        gdma_init.GDMA_DestHandshake        = I2S_TX_DMA_HANDSHAKE;
        GDMA_Init(I2S_TX_DMA_CHANNEL, &gdma_init);

        RamVectorTableUpdate(I2S_TX_DMA_VECTOR, i2s_tx_dma_handler);

        nvic_init.NVIC_IRQChannel           = I2S_TX_DMA_IRQ;
    }
    else if (dir == I2S_CONFIG_RX)
    {
        gdma_init.GDMA_ChannelNum           = I2S_RX_DMA_CHANNEL_NUM;
        gdma_init.GDMA_DIR                  = GDMA_DIR_PeripheralToMemory;
        gdma_init.GDMA_SourceAddr           = (uint32_t)I2S_RX_ADDR;
        gdma_init.GDMA_DestinationAddr      = (uint32_t)(i2s_recv_buff);
        gdma_init.GDMA_SourceInc            = DMA_SourceInc_Fix;
        gdma_init.GDMA_DestinationInc       = DMA_DestinationInc_Inc;
        gdma_init.GDMA_SourceHandshake      = I2S_RX_DMA_HANDSHAKE;
        GDMA_Init(I2S_RX_DMA_CHANNEL, &gdma_init);

        RamVectorTableUpdate(I2S_RX_DMA_VECTOR, i2s_rx_dma_handler);

        nvic_init.NVIC_IRQChannel           = I2S_RX_DMA_IRQ;
    }

    nvic_init.NVIC_IRQChannelCmd        = (FunctionalState)ENABLE;
    nvic_init.NVIC_IRQChannelPriority   = 3;
    NVIC_Init(&nvic_init);
}

SDIO

SDIO Demo Code Support List

Demo 1

sdio_demo.c

Sample Purpose

Demonstrates how PC communicates with SD card.

Brief Introduction

This sample code demonstrates SD card read and write function. Read the data at the specified address of the SD card, and write the specified data to the SD card.

File Path

sdk\src\sample\io_demo\sdio\sdcard\sdio_demo.c

Function Entry

sdio_demo()

Supply Voltage

3.3V, check rcfg of Voltage Setting.

Group Pins

The specific group pins are shown in SDIO Group Pins in RTL87x3D and SDIO Group Pins in RTL87x3E.

Hardware Connection

Take RTL87x3D Group0 as an example, shown in SDIO Hardware Connection Diagram. The 6 pins of the SD card are respectively connected with Group0 on EVB, and the VDD and GND pins of the SD card are connected with the VCC and GND pins on EVB.

Expected Result

Press the reset button on the EVB, the string ‘sd_print_binary_data: buf:’ will be printed in Debug Analyzer. The last printed data buf is 0~FF+0~FF (512 bytes).

Demo 2

sdio_fs_demo.c

Sample Purpose

Demonstrates how PC communicates with SD card by filesystem.

Brief Introduction

This sample code demonstrates SD card read and write function by filesystem. FatFS_DirectoyDemo can write the data under the specified directory file of the SD card; FatFS_Demo can write and read data directly to the SD card file.

File Path

sdk\src\sample\io_demo\sdio\demo\sdio_fs_demo.c

Function Entry

SD_DemoCode()

Supply Voltage

3.3V, check rcfg of Voltage Setting.

Group Pins

The specific group pins are shown in SDIO Group Pins in RTL87x3D and SDIO Group Pins in RTL87x3E.

Hardware Connection

Take RTL87x3D Group0 as an example, shown in SDIO Hardware Connection Diagram. The 6 pins of the SD card are respectively connected with Group0 on EVB, and the VDD and GND pins of the SD card are connected with the VCC and GND pins on EVB.

File Prepare

1. FatFS_DirectoyDemo: The BBpro directory and written files need to be created in the root directory.
2. FatFS_Demo: The ‘Data.txt’ file needs to be created in the root directory.

Expected Result

1. Press the reset button on the EVB.
2. FatFS_DirectoyDemo: String ‘FatFS_DirectoyDemo: write OK!’ will be printed in Debug Analyzer. And check that the files in the BBpro directory of the SD card are written data.
3. FatFS_Demo: The string ‘FatFS_Demo: f_read: 0x31, 0x32, 0x33, read_len 1024!’ will be printed in Debug Analyzer. And check that ‘Test.txt’ in the SD card is the written data.

Demo 3

sdio_card_detect_demo.c

Sample Purpose

Demonstrates SD card detection by GPIO.

Brief Introduction

This sample code demonstrates the SD card detection function. Simulate SD card insertion and removal through GPIO.

File Path

sdk\src\sample\io_demo\sdio\sdcard\sdio_card_detect_demo.c

Function Entry

sdio_card_detect_demo()

Supply Voltage

3.3V, check rcfg of Voltage Setting.

Selected CD Pin Definition

#define SD_CARD_DETECT_PIN  P0_3

Group Pins

The specific group pins are shown in SDIO Group Pins in RTL87x3D and SDIO Group Pins in RTL87x3E.

Hardware Connection

Take RTL87x3D Group0 as an example, shown in SDIO Hardware Connection Diagram. The 6 pins of the SD card are respectively connected with Group0 on EVB, and the VDD and GND pins of the SD card are connected with the VCC and GND pins on EVB.

Expected Result

Connect P0_3 with GND on EVB, the string ‘gpio_isr_cb: card insert!’ will be printed in Debug Analyzer. Remove P0_3 from GND, the string ‘gpio_isr_cb: card remove!’ will be printed in Debug Analyzer.

RTL87x3D

CLK

CMD

DAT0

DAT1

DAT2

DAT3

Group0 pins

P1_2

P1_3

P1_4

P1_5

P1_6

P1_7

Group1 pins

P4_2

P4_3

P4_4

P4_5

P4_6

P4_7

RTL87x3E

CLK

CMD

DAT0

DAT1

DAT2

DAT3

Group0 pins

P5_0

P5_1

P5_2

P5_3

P5_4

P5_5

Group1 pins

P6_0

P6_1

P6_2

P6_3

P6_4

P6_5

Function Description

  1. SDIO

    Secure Digital Input and Output, defines a peripheral interface. SDIO card is an IO device that uses the SD bus and SD commands. The shape and interface of the SDIO card are compatible with the SD card, but it not only realizes the storage function, but also realizes other functions, such as Bluetooth, Wireless Fidelity, etc.

  2. SDHC

    SD host controller, the connection of SDHC and SD card is shown in SDHC and SD Card Connection Diagram. The host controls the internal operation of the SD card by reading/writing SDHC internal registers.

  3. SDIO transmission mode

    SPI mode, 1-bit mode (single-wire), 4-bit SD mode (four-wire). The pin definitions in different modes are shown in SDIO Pin Definitions in Different Modes.

  4. SDIO interface definition (4-bit SD mode)

    1. CLK

      Host to card clock signal.

    2. CMD

      Bi-directional command/response signal.

    3. DAT0-DAT3

      4 Bi-directional data signals.

Note

RTL87x3D, RTL87x3E, and RTL87x3EP support SDIO.

Pins

4-Bit Mode

1-Bit Mode

SPI mode

1

VCC

VCC

VCC

2

VSS1

VSS1

VSS1

3

VSS2

VSS2

VSS2

4

CLK

CLK

CLK

5

CMD

CMD

CS

6

DAT0

DAT0

DAT0

7

DAT1

RSV

DAT1

8

DAT2

RSV

RSV

9

DAT3/CD

CD

RSV

Feature List

  • Support SD Spec V2.0.

  • Support only 2 Group Pins on EVB to communicate with SD card. For specific pins, please refer to SDIO Group Pins in RTL87x3D or SDIO Group Pins in RTL87x3E.

  • Support 1-bit and 4-bit SD bus width.

  • Support optional bus clock, 40MHz and 80MHz can only support in RTL87x3D.

  • Support multiple block and single block transfer, SDHC max block size is 512 Bytes.

  • High Voltage SD card: operation Voltage 3.3V.

  • Support DMA transfer.

  • Support interrupt control.

SD Bus Protocol

  • The control on the SD bus is realized through CMD: The host initiates a request, and then the SD card responds to the request.

  • Data transfer format: Start bit 0, first MSB, then LSB, CRC check, end bit 1.

  • Data is transferred in the form of data blocks. SD Bus block read and write operation, as shown in SD BUS (Multiple) Block Read Operation and SD BUS (Multiple) Block Write Operation.

Take the SD Bus multi-block read operation as an example:

  1. The host sends a multi-block read command.

  2. The SD card sends a response.

  3. The card starts sending data.

  4. After each block is sent, return a CRC status.

  5. The card transmits the next block data.

  6. Until the host sends a stop command, the card responds.

SDIO Operation Flow

The codes below demonstrate the SD card initialization flow.

const T_SD_CONFIG    sd_card_cfg =
{
    .sd_if_type = SD_IF_SD_CARD,
    .sdh_group = GROUP_0,
    .sdh_bus_width = SD_BUS_WIDTH_4B,
    .sd_bus_clk_sel = SD_BUS_CLK_20M
};

/* SD config init */
sd_config_init((T_SD_CONFIG *)&sd_card_cfg);
/* Group pins PINMUX & PAD Config */
sd_board_init();
/* Initialize SD card peripheral */
sd_card_init();

The codes below demonstrate the SD card communication flow. For details, please refer to src\sample\io_demo\sdio\sdcard\sdio_demo.c.

static uint8_t *test_buf = NULL;
uint32_t sd_status = 0;

void sd_test(void)
{
    memset(test_buf, 0, sizeof(test_buf));
    /* Read the data at the specified address of the SD card */
    sd_status = sd_read(OPER_SD_CARD_ADDR, (uint32_t)test_buf, SINGLE_BLOCK_SIZE, BLOCK_NUM);

    if (sd_status != 0)
    {
        return ;
    }
    /*SD card print the binary data of test_buf */
    sd_print_binary_data(test_buf, SINGLE_BLOCK_SIZE * BLOCK_NUM);

    for (uint32_t i = 0; i < SINGLE_BLOCK_SIZE * BLOCK_NUM; i++)
    {
        test_buf[i] = i & 0xff;
    }
    sd_print_binary_data(test_buf, SINGLE_BLOCK_SIZE * BLOCK_NUM);
    /* Write the specified test_buf data to the SD card */
    sd_status = sd_write(OPER_SD_CARD_ADDR, (uint32_t)test_buf, SINGLE_BLOCK_SIZE, BLOCK_NUM);
}

The codes below demonstrate the SD card communication flow by filesystem.

For details, please refer to src\sample\io_demo\sdio\sdcard\demo\sdio_fs_demo.c.

void FatFS_Demo(void)
{
    uint32_t a = 1;
    uint32_t res = 0;
    const char driver_num = 0;

    /* Create workspace */
    res = f_mount(&fs, &driver_num, 1);

    /* Open file */
    res = f_open(&fdst, "Test.txt", FA_CREATE_ALWAYS | FA_WRITE);
    if (res != FR_OK)
    {
        //Open file failure, add error handle code here
        f_close(&fdst);
        return ;
    }

    res = f_open(&fsrc, "Data.txt", FA_OPEN_EXISTING | FA_READ);
    if (res != FR_OK)
    {
        //Open file failure, add error handle code here
        f_close(&fsrc);
        return ;
    }

    /* File operation */
    for (uint32_t i = 0; i < 1024; i++)
    {
        buffer[i] = i % 0x09 + 0x30;
    }
    buffer[1021] = 69;
    buffer[1022] = 69;
    buffer[1023] = 69;
    f_write(&fdst, buffer, 1024, &a);

    memset(buffer, 0, 1024);
    f_read(&fsrc, buffer, 1024, &a);

    /* Close file */
    f_close(&fsrc);
    f_close(&fdst);
}