jonajiroのアイコン画像
jonajiro 2022年08月29日作成 (2022年08月31日更新) © MIT
セットアップや使用方法 セットアップや使用方法 閲覧数 1904
jonajiro 2022年08月29日作成 (2022年08月31日更新) © MIT セットアップや使用方法 セットアップや使用方法 閲覧数 1904

Spresense Arduino IDEで15bit分解能PWMを使用する

Spresense Arduino IDEで15bit分解能PWMを使用する

はじめに

SpresenseのPWM分解能について調査したので報告。
公式のSpresense Arduino IDEの開発ガイドではPWM分解能が256の例しか示されていない。
一方で下記URLではnuttx のドライバをArduinoで叩けばいけるよ的なこと書いていたが具体的なプログラムが示されていなかったのでトライした。
arduino-ideでpwm出力を15bitで扱う方法
また、Spresense SDKの下記URLのexampleを参考にした。
https://github.com/jodersky/nuttx/blob/master/apps/examples/pwm/pwm_main.c
上記ソースコードはSpresense SDK をダウンロードすれば examples の中にマージされるのでそっち確認してもいいかも。
以下にPWMを動かした様子を示す。

プログラム

■ void pwm_init(int freq, float duty)
PWMの初期化。※なくても動くけどSDKのexampleに記載があった。

  1. freq:初期周波数指定。
    最大は2kHzまでしか確認してないがスペック上6.5MHzは出るらしい。
  2. duty:初期デュティ比指定
    0~1をfloatで入力。0%なら0、50%なら0.5、100%なら1みたいな感じ。

■ void pwm_output(int pin_num, int freq, float duty)
PWMのポート、周波数、デュティ比の指示

  1. pin_num:出力ポート指定
    pin_numには0~3を入力する。拡張ボードのピン番号との対応は下記の通りだった。
    pin_num 0:D6
    pin_num 1:D5
    pin_num 2:D3
    pin_num 3:D9
  2. freq:周波数指定。
    最大は2kHzまでしか確認してないがスペック上6.5MHzは出るらしい。
  3. duty:デュティ比指定
    0~1をfloatで入力。0%なら0、50%なら0.5、100%なら1みたいな感じ。

pwm_test.ino

#include <sys/ioctl.h> #include <fcntl.h> #include <nuttx/timers/pwm.h> struct pwm_state_s { bool initialized; FAR char *devpath; uint8_t duty; uint32_t freq; }; static struct pwm_state_s g_pwmstate; void setup() { // put your setup code here, to run once: Serial.begin(115200); pwm_init(2000, 0.1); } float duty_c = 0.0; void loop() { // put your main code here, to run repeatedly: duty_c = duty_c + 0.01; if (duty_c > 1.0) { duty_c = 0.0; } pwm_output(0 , 2000, duty_c); pwm_output(1 , 2000, duty_c); pwm_output(2 , 2000, duty_c); pwm_output(3 , 2000, duty_c); delay(10); } void pwm_init(int freq, float duty) { if (!g_pwmstate.initialized) { g_pwmstate.duty = (uint32_t)(duty * 65535); g_pwmstate.freq = freq; g_pwmstate.initialized = true; } } void pwm_output(int pin_num, int freq, float duty) { int fd; int ret; struct pwm_info_s info; char* devpath; if (pin_num == 0) { devpath = "/dev/pwm0\0"; } else if (pin_num == 1) { devpath = "/dev/pwm1\0"; } else if (pin_num == 2) { devpath = "/dev/pwm2\0"; } else if (pin_num == 3) { devpath = "/dev/pwm3\0"; } else { devpath = "/dev/pwm0\0"; } if (g_pwmstate.devpath) { free(g_pwmstate.devpath); } g_pwmstate.devpath = strdup(devpath); fd = open(g_pwmstate.devpath, O_RDONLY); if (fd < 0) { close(fd); return; } info.frequency = freq; info.duty = (uint32_t)(duty * 65535); ret = ioctl(fd, PWMIOC_SETCHARACTERISTICS, (unsigned long)((uintptr_t)&info)); if (ret < 0) { close(fd); return; } ret = ioctl(fd, PWMIOC_START, 0); if (ret < 0) { close(fd); return; } close(fd); }