Skip to content

GPIO analog Infrared instructions*

Since GX8002 has no infrared module, GPIO is needed to simulate infrared function.Then we need to raise the corresponding module frequency when using GPIO to simulate infrared output, and then restore the corresponding module frequency to normal after using it upThe advantage of this is that it can power saving.

Two interfaces are needed:

  • Configuring CPU frequency: LvpDynamiciallyAdjustCpuFrequency
  • Configure the GPIO module frequency: LvpDynamiciallyAdjustGpioFrequency
lvp/common/lvp_system_init.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
int LvpDynamiciallyAdjustGpioFrequency(GPIO_FREQUENCE_LEVEL gpio_frequence_level)
{
    unsigned int state = gx_lock_irq_save();

    if (gpio_frequence_level == GPIO_FREQUENCE_HIGH_SPEED) {
        gx_clock_set_module_source(CLOCK_MODULE_PMU         , MODULE_SOURCE_24M_PLL);
        gx_clock_set_module_source(CLOCK_MODULE_GPIO        , MODULE_SOURCE_24M_PLL);
        gx_clock_set_div(CLOCK_MODULE_PMU         ,  0);
    } else if (gpio_frequence_level == GPIO_FREQUENCE_STANDARD_SPEED) {
        gx_clock_set_module_source(CLOCK_MODULE_PMU         , MODULE_SOURCE_1M_12M);
        gx_clock_set_module_source(CLOCK_MODULE_GPIO        , MODULE_SOURCE_1M_12M);
        gx_clock_set_div(CLOCK_MODULE_PMU         ,  3);
    }

    gx_unlock_irq_restore(state);
    return 0;
}

int LvpDynamiciallyAdjustCpuFrequency(CPU_FREQUENCE_LEVEL cpu_frequence_level)
{
    unsigned int state = gx_lock_irq_save();
#ifdef CONFIG_ENABLE_PLL_FREQUENCY_50M
    int pll_multiple = 2;
#else
    int pll_multiple = 1;
#endif
    if (cpu_frequence_level == CPU_FREQUENCE_4M) {
        gx_clock_set_div(CLOCK_MODULE_SCPU, 6 * pll_multiple);
    } else if (cpu_frequence_level == CPU_FREQUENCE_6M) {
        gx_clock_set_div(CLOCK_MODULE_SCPU, 4 * pll_multiple);
    } else if (cpu_frequence_level == CPU_FREQUENCE_8M) {
        gx_clock_set_div(CLOCK_MODULE_SCPU, 3 * pll_multiple);
    } else if (cpu_frequence_level == CPU_FREQUENCE_12M) {
        gx_clock_set_div(CLOCK_MODULE_SCPU, 2 * pll_multiple);
    } else if (cpu_frequence_level == CPU_FREQUENCE_24M) {
        gx_clock_set_div(CLOCK_MODULE_SCPU, 1 * pll_multiple);
    } else if (cpu_frequence_level == CPU_FREQUENCE_50M) {
        if (pll_multiple == 2) {
            gx_clock_set_div(CLOCK_MODULE_SCPU, 0);
        } else {
            gx_unlock_irq_restore(state);
            return -1;
        }
    } else if (cpu_frequence_level == CPU_FREQUENCE_DEFAULT) {
        gx_clock_set_div(CLOCK_MODULE_SCPU, CUSTOMIZE_FREQUENCY_MCU_DIV_PARAM);
    } else {
        gx_unlock_irq_restore(state);
        return -1;
    }
# ifdef CONFIG_SYSTICK_COUNTER
    gx_timer_init();
# endif
    gx_unlock_irq_restore(state);
    return 0;
}

2. GPIO simulation infrared use steps*

notice

Strictly follow the steps below to invoke the responding API interface.

  • Step 1: Call on demand before simulates infrared app LvpDynamiciallyAdjustCpuFrequency and LvpDynamiciallyAdjustGpioFrequency
    LvpDynamiciallyAdjustCpuFrequency(CPU_FREQUENCE_24M);       // Set the cpu frequency to higher. If the default cpu frequency is 24 MB or greater, you do not need to adjust the CPU frequency
    LvpDynamiciallyAdjustGpioFrequency(GPIO_FREQUENCE_HIGH_SPEED);  // Turn up the gpio frequency, this step is necessary, otherwise the delay of level flipping will be large
    
    Please refer to related parameters:
    CPU frequency
    (LvpDynamiciallyAdjustCpuFrequency)
    GPIO module frequency
    (LvpDynamiciallyAdjustGpioFrequency)
    The time required to set the GPIO level(us)gx_gpio_set_level The time required to set the GPIO level(us)gpio_level_flip_write
    CPU_FREQUENCE_50M GPIO_FREQUENCE_HIGH_SPEED 1.3 0.6
    CPU_FREQUENCE_24M GPIO_FREQUENCE_HIGH_SPEED 2.3 0.9
    CPU_FREQUENCE_16M GPIO_FREQUENCE_HIGH_SPEED 3.2 1.1
    CPU_FREQUENCE_12M GPIO_FREQUENCE_HIGH_SPEED 4.3 1.3
    gpio level flip is recommended gpio_level_flip_write, shorter delay;

tip

  1. The delay error is related to the CPU frequency. The higher the CPU frequency, the smaller the delay error and the less gpio level turnover time.

notice

  1. The higher the cpu frequency, the lower the delay and the lower the error, but the higher the power consumption. The cpu frequency switch is set based on the requirements.
  2. The frequency of gpio must be increased, otherwise there will be a large delay.
  • Step 2: Obtain the delay factor

    int coeff = gx_udelay_fine_config(gx_clock_get_module_frequence(CLOCK_MODULE_SCPU));    // The delay factor is obtained by the cpu frequency
    

  • Step 3: Read the gpio register

    gpio_level_flip_read(gpio_port);                // Read the gpio register and transfer the gpio port that needs to be operated
    

  • Step 4: Close the interrupt

  • When using this interface, disable the interrupt; otherwise, the delay may be inaccurate Please resume interrupt after using

    unsigned int irq = gx_lock_irq_save();          // Save interrupts and close interrupts. Interrupts affect latency
    

  • Step 5: Delay and flip level

    gpio_level_flip_write(gpio_dout_l);         // The level is set to low
    gx_udelay_fine(half_cycle, coeff);          // Delay, incoming delay time and delay factor
    gpio_level_flip_write(gpio_dout_h);         // The level is set to high
    gx_udelay_fine(half_cycle, coeff);          // Delay, incoming delay time and delay factor
    

  • Step 6: Restore the interrupt

    gx_unlock_irq_restore(irq);                     // Open the interrupt when the operation is complete
    

  • Step 7: The default frequency should be restored after simulates infrared app :

    LvpDynamiciallyAdjustCpuFrequency(CPU_FREQUENCE_DEFAULT); // Fill in as needed
    LvpDynamiciallyAdjustGpioFrequency(GPIO_FREQUENCE_STANDARD_SPEED); // Must pass in GPIO_FREQUENCE_STANDARD_SPEED
    

3. GPIO analog infrared example*

  • For a complete example, please refer to lvp_sdk on gitlab. Only part of the code is shown below.
  • There are two ways to operate the control level inversion:
    // Large latency, including read and write operations
    gx_gpio_set_level(int port, int level); // Common interfaces, read and write operations, the delay is long
    
    // The following two interfaces are used in combination to achieve low latency; Read operations are performed during initialization, and write operations are only required for subsequent rollover, with relatively short latency
    gpio_level_flip_read(int port);      // Read interface
    gpio_level_flip_write(int level);    // Write interface
    
app/gpio_pwm_demo/lvp_app_gpio_pwm_demo.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#define GPIO_DOUT       (( GX_REG_BASE_GPIO0 ) + 0x04) // Output data


float half_cycle_f;
unsigned int gpio_dout_l, gpio_dout_h;
unsigned int gpio_port = 1;


int gpio_level_flip_read(int port)      // Read the register value of gpio
{
    gx_gpio_set_direction(port, GX_GPIO_DIRECTION_OUTPUT);
    gpio_dout_l = readl(GPIO_DOUT) & (~ (1 << (port%32)));
    gpio_dout_h = readl(GPIO_DOUT) | (1 << (port%32));
    return 0;
}
int gpio_level_flip_write(int level)    // Write register reverses gpio level
{
    writel(level, GPIO_DOUT);
    return 0;
}

int gpio_pwm_init(int opt)              // pwm initialization
{

    half_cycle_f = 1000000.f / CONFIG_LVP_APP_GPIO_PWM_FREQ / 2;    // To calculate the pwm half-cycle duration us, CONFIG_LVP_APP_GPIO_PWM_FREQ is the required pwm frequency set in the build configuration

    int cpu_fre = gx_clock_get_module_frequence(CLOCK_MODULE_SCPU); // Gets the cpu frequency
    // The fixed delay required to subtract the flip level
#if opt     // If gx_gpio_set_level is used, it is set to 1, using the following parameters
    if (cpu_fre >= 12287990 && cpu_fre <= 12288010)
        half_cycle_f -= 4.2;
    else if (cpu_fre >= 16383990 && cpu_fre <= 16384010)
        half_cycle_f -= 3.2;
    else if (cpu_fre >= 24575990 && cpu_fre <= 24576010)
        half_cycle_f -= 2.3;
    else if (cpu_fre >= 49151990 && cpu_fre <= 49152010)
        half_cycle_f -= 1.3;
#else       // If you are using the gpio_level_flip_write interface, set this to 0 and use the following parameters
    if (cpu_fre >= 12287990 && cpu_fre <= 12288010)
        half_cycle_f -= 1.3;
    else if (cpu_fre >= 16383990 && cpu_fre <= 16384010)
        half_cycle_f -= 1.1;
    else if (cpu_fre >= 24575990 && cpu_fre <= 24576010)
        half_cycle_f -= 0.9;
    else if (cpu_fre >= 49151990 && cpu_fre <= 49152010)
        half_cycle_f -= 0.6;
#endif
    return 0;
}

// The above interfaces do not need to be modified
// =========================================================================================================================
// The following code is modified as required

static int GpioPwmAppInit(void)
{
    printf(LOG_TAG" ---- %s ----\n", __func__);

    LvpDynamiciallyAdjustCpuFrequency(CPU_FREQUENCE_24M);       // Set the cpu frequency to higher. If the default cpu frequency is 24 MB or greater, you do not need to adjust the CPU frequency
    LvpDynamiciallyAdjustGpioFrequency(GPIO_FREQUENCE_HIGH_SPEED);  // Turn up the gpio frequency, this step is necessary, otherwise the delay of level flipping will be large
    int coeff = gx_udelay_fine_config(gx_clock_get_module_frequence(CLOCK_MODULE_SCPU));    // The delay factor is obtained by the cpu frequency
    if (coeff == -1)
    {
        return -1;
    }
    printf("coeff = %d mcu:%d\n", coeff, gx_clock_get_module_frequence(CLOCK_MODULE_SCPU));


    // gx_gpio_set_level Fixed delay: https://nationalchip.gitlab.io/ai_audio_docs/software/lvp/SDK%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/SDK%E5%BC%80%E5%8F%91_FAQ/GPIO%E6%A8%A1%E6%8B%9F%E7%BA%A2%E5%A4%96%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9/#2

    gpio_pwm_init(0);                               // pwm initialization, if using gx_gpio_set_level flip level, pass the non-0 parameter, if using gpio_level_flip_write interface, pass the 0 parameter
    int half_cycle = (int)half_cycle_f;
    printf("half_cycle %d\n", half_cycle);

    gpio_level_flip_read(gpio_port);                // Read the gpio register and transfer the gpio port that needs to be operated

    unsigned int irq = gx_lock_irq_save();          // Save interrupts and close interrupts. Interrupts affect latency
    while(1) {
        gpio_level_flip_write(gpio_dout_l);         // The level is set to low
        gx_udelay_fine(half_cycle, coeff);          // Delay, incoming delay time and delay factor
        gpio_level_flip_write(gpio_dout_h);         // The level is set to high
        gx_udelay_fine(half_cycle, coeff);          // Delay, incoming delay time and delay factor
    }
    gx_unlock_irq_restore(irq);                     // Open the interrupt when the operation is complete
    LvpDynamiciallyAdjustGpioFrequency(GPIO_FREQUENCE_STANDARD_SPEED);  // The default frequency needs to be restored after the operation is complete
    LvpDynamiciallyAdjustCpuFrequency(CPU_FREQUENCE_DEFAULT);   // Restore the default cpu frequency and use it together with the previous adjustment

    return 0;
}