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
- 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
- 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.
- 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;
}
|