Gpio 测试

您好, 我现在用gpio模拟pwm ,这个频率周期最大支持到多少,现在在内核中使用高精度定时器测试,当频率设置为2微秒时,电平失真,并且达不到需要的2微秒

当使用20微秒周期的时候。信号如下图:

hello 550399056,

may I know what’s your approach to simulate PWM?
or… could you please share the code snippets for reference?

 34 static enum hrtimer_restart pwm_timer_callback(struct hrtimer *timer) {
 35     timer_cnt++;
 36     if(timer_cnt == high_cnt){
 37          gpio_set_value(ir_pwm.gpioNum, 0);
 38     }
 39     if(timer_cnt == period_cnt){
 40          gpio_set_value(ir_pwm.gpioNum, 1);
 41          timer_cnt = 0;
 42     }
 43     hrtimer_forward(timer, timer->base->get_time(), pwm_period);
 44 //    state = !state;
 45 //    gpio_set_value(ir_pwm.gpioNum, state);
 46 //    hrtimer_forward_now(timer,pwm_period);
 47 
 48     return HRTIMER_RESTART;
 49 }

hello 550399056,

please give it a try by using sleep instead of variable counts to set high/low period.

sleep 能到精准到微妙级吗

there’re msleep, usleep_range…etc, please give it a try.

我使用了 usleep_range

 36 static int thread_func(void *data) {
 37 
 38         int i, count;
 39         int step = 2;
 40         int period_us = 1000000 / frequency;              // 计算周期(微秒)                          
 41         int duty_cycle = 30;
 42         int high_time_us = period_us * duty_cycle / 100;  // 高电平时间
 43         int low_time_us = period_us - high_time_us;       // 低电平时间
 44 
 45         while (1){
 46                 usleep_range(high_time_us,high_time_us+step);
 47                 gpio_set_value(ir_pwm.gpioNum, 1);
 48                 usleep_range(low_time_us,low_time_us+step);
 49                 gpio_set_value(ir_pwm.gpioNum, 0);
 50         }
 51         return 0;
 52 }

偶尔会出现上面周期不同步的情况。

hello 550399056,

since you’re using an application to toggle GPIO state change, is it related to system process scheduling?
please give it a try by using commands to adjust the process priority (i.e. renice) for specific process,
you may further to assign CPUs individually (i.e. taskset) for the test application.

for instance,

  • To modify the priority
    • please note its ranges from -20 (highest priority) to 19 (lowest priority value), and the default is 0.
    • $ sudo renice -20 -p <pid>
  • To specify CPUs
    • here’s example to assign CPU-2 and CPU-3 for executing application.
    • $ taskset -c -p 2,3 <pid>

这是个内核线程,怎么指定优先级呢?

我使用下面方法,效果还是一样:

        thread_body = kthread_create(thread_func, NULL, "thread_pwm");
        if((thread_body))
        {   

            thread_body->prio = 1;
            bind_thread_to_cpu(thread_body,1);
            wake_up_process(thread_body);
        }

hello 550399056,

may I know the test results by using constant variable, i.e. usleep_range(10, 20);
and… since it’s a range (i.e. 10~20us) for scheduler to pause the code, would you please also check whether high/low is around 10~20us as well?

上面我设置的是:

 45         while (1){
 46                 usleep_range(high_time_us,high_time_us+step);
 47                 gpio_set_value(ir_pwm.gpioNum, 1);
 48                 usleep_range(low_time_us,low_time_us+step);
 49                 gpio_set_value(ir_pwm.gpioNum, 0);
 50         }

具体数值如下:

 45         while (1){
 46                 usleep_range(30,32);
 47                 gpio_set_value(ir_pwm.gpioNum, 1);
 48                 usleep_range(70,72);
 49                 gpio_set_value(ir_pwm.gpioNum, 0);
 50         }

最终效果如示波器上显示的方波一样。不稳定

hello 550399056,

may I know which L4T release version you’re working with, did you test on Orin Nano developer kit?

我们使用的是orin nx,版本:

JetPack 5.1.4
Linux 35.6.0
Linux Kernel 5.10
Ubuntu 20.04 root file system

hello 550399056,

just curious, why you don’t use PWM directly. i.e. $ ls -la /sys/class/pwm/pwmchip*
here’s an example to enable pwm0

cd /sys/class/pwm/pwmchip3
echo 0 > export
cd pwm0
echo 100000000 > period    # i.e. 10Hz
echo 5000 > duty_cycle 
echo 1 > enable