編集履歴一覧に戻る
jonajiroのアイコン画像

jonajiro が 2022年08月29日00時29分21秒 に編集

初版

タイトルの変更

+

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

タグの変更

+

spresense

+

Arduino_IDE

メイン画像の変更

メイン画像が設定されました

記事種類の変更

+

セットアップや使用方法

ライセンスの変更

+

(MIT) The MIT License

本文の変更

+

# はじめに SpresenseのPWM分解能について調査したので報告。 公式のSpresense Arduino IDEの開発ガイドではPWM分解能が256の例しか示されていない。 一方で下記URLではSpresense SDKのAPIをArduinoで叩けばいけるよ的なこと書いていたが具体的なプログラムが示されていなかったのでトライした。 [arduino-ideでpwm出力を15bitで扱う方法](https://ja.stackoverflow.com/questions/65475/arduino-ide%E3%81%A7pwm%E5%87%BA%E5%8A%9B%E3%82%9215bit%E3%81%A7%E6%89%B1%E3%81%86%E6%96%B9%E6%B3%95) また、Spresense SDKの下記URLのexampleを参考にした。 [https://github.com/jodersky/nuttx/blob/master/apps/examples/pwm/pwm_main.c](https://github.com/jodersky/nuttx/blob/master/apps/examples/pwm/pwm_main.c) 上記ソースコードはSpresense SDK をダウンロードすれば examples の中にマージされるのでそっち確認してもいいかも。 以下にPWMを動かした様子を示す。 @[twitter](https://twitter.com/k218675554/status/1563903011730395136) # プログラム ■ void pwm_init(int freq, float duty) PWMの初期化。※なくても動くけどSDKのexampleに記載があった。 1. freq:初期周波数指定。 最大は2kHzまでしか確認してないが6、スペック上6.5MHzは出るらしい。 1. 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 1. freq:周波数指定。 最大は2kHzまでしか確認してないが6、スペック上6.5MHzは出るらしい。 1. duty:デュティ比指定 0~1をfloatで入力。0%なら0、50%なら0.5、100%なら1みたいな感じ。 ```arduino:pwm_test.ino #include <nuttx/config.h> #include <sys/types.h> #include <sys/ioctl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <debug.h> #include <string.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; pwm_init(freq, duty); 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); } ```