初めてのRaspberry Pi Pico ㉗ C言語 PWM その3


 PWMの周波数設定がわかりにくかったので、整理します。


// Output PWM signals on pins 2 and 3

#include "pico/stdlib.h"
#include "hardware/pwm.h"
#include <stdio.h>
#include "hardware/clocks.h"
#include <math.h>

int main() {
    stdio_init_all();  // need when UART 

    printf("\nstart GPIO 2,3\n");

    gpio_set_function(2, GPIO_FUNC_PWM);
    gpio_set_function(3, GPIO_FUNC_PWM);

    // Find out which PWM slice is connected to GPIO 2 (it's slice 0)
    uint slice_num = pwm_gpio_to_slice_num(2);

    // Set period
    pwm_set_wrap(slice_num, 99);

    // Set channel A output high for one cycle before dropping
    pwm_set_chan_level(slice_num, PWM_CHAN_A, 10);
    // Set initial B output high for three cycles before dropping
    pwm_set_chan_level(slice_num, PWM_CHAN_B, 50);
    // Set the PWM running
    pwm_set_enabled(slice_num, true);
}

 wrapを100回繰り返すと125MHz ÷ 100 = 1.25MHzになります。では1.0MHzはどうやって作るのでしょうか。
 分周ユニットは8.4の固定小数点で表現されます。整数が8ビット、小数点が4ビットです。

    pwm_set_wrap(slice_num, 99);

の後ろに、

    uint8_t div = 1;
    uint8_t fract = 4;
    pwm_set_clkdiv_int_frac(slice_num, div, fract);

 整数1は、倍率1です。
 小数点部分は1/2^nの重み付けになります。4は2進数では
0100 = 0 * 1/2^1 + 1 * 1/2^2 + 0 * 1/2^3 + 0 * 1/2^4
= 0.25
合成すると1.25なので、1.25MHz/1.25=1MHzになります。

もう一例。

    uint8_t div = 2;
    uint8_t fract = 8;
    pwm_set_clkdiv_int_frac(slice_num, div, fract);

 整数2は、倍率2です。
 小数点部分は1/2^nの重み付けになります。8は2進数では
1000 = 1 * 1/2^1 + 0 * 1/2^2 + 0 * 1/2^3 + 0 * 1/2^4
= 0.5
合成すると2.5なので、1.25MHz/2.5=500kHzになります。

最後に、980Hzが欲しいなら、

1.25MHz/980=1275.5102
整数部は2^8=256を超えているので設定できません。pwm_set_wrap(slice_num, 999);に設定し、基準となるクロックを125kHzまで落とします。
125kHz/980=127.551
 したがって、整数部を127に、小数点部分を8にしました。980.39Hzとほぼ近い周波数になりました。warpは16ビットなので、もっと基準となる周波数を下げれば、目的に周波数に近づけると思います。

// Output PWM signals on pins 2 and 3

#include "pico/stdlib.h"
#include "hardware/pwm.h"
#include <stdio.h>
#include "hardware/clocks.h"
#include <math.h>

int main() {
    stdio_init_all();  // need when UART 

    printf("\nstart GPIO 2,3\n");

    gpio_set_function(2, GPIO_FUNC_PWM);
    gpio_set_function(3, GPIO_FUNC_PWM);

    // Find out which PWM slice is connected to GPIO 2 (it's slice 0)
    uint slice_num = pwm_gpio_to_slice_num(2);

    uint16_t divCounter = 1000; // max 2^16 = 65536
    pwm_set_wrap(slice_num, divCounter-1);

    uint8_t div = 127;
    uint8_t fract = 9;
    pwm_set_clkdiv_int_frac(slice_num, div, fract);


    // duty 10%
    pwm_set_chan_level(slice_num, PWM_CHAN_A, (int)divCounter*0.1);
    //  duty 50%
    pwm_set_chan_level(slice_num, PWM_CHAN_B, (int)divCounter*0.5);
    // Set the PWM running
    pwm_set_enabled(slice_num, true);
}