So-net無料ブログ作成
  • ブログをはじめる
  • ログイン
前の10件 | -

(続)ESP32のLEDCについて調べてみた。 [ESP32]

某SNSで、LEDCで16チャネル分のPWM出力した時、チャネル8以降でDutyを0に設定してもLOWにならない!と言う話。その後
https://www.facebook.com/groups/927623023964478/permalink/2015391691854267/

件のコードは以下。
#define  L1   27
#define  L15  2

void setup()
{
  Serial.begin(9600);
  pinMode(L1,OUTPUT);
  ledcSetup(0, 256, 8);
  ledcAttachPin(L1, 0);
  pinMode(L15,OUTPUT);
  ledcSetup(8, 256, 8);
  ledcAttachPin(L15,8);
  delay(10);
}

void loop()
{
  for(int vr = 0; vr <= 255; vr++)
  {
    ledcWrite(0,vr);
    ledcWrite(8,vr);
    Serial.println(vr);
    delay(10);
  }
  delay(2000);

  for(int vr = 255; vr >= 0; vr--)
  {
    ledcWrite(0,vr);
    ledcWrite(8,vr);
    Serial.println(vr);
    delay(10);
  }
  delay(5000); 
}

前回は秋月で3450円で売っている簡易オシロ( http://akizukidenshi.com/catalog/g/gM-12972/ )で確認した。このオシロではDuty=100%時になんかヒゲが出ている事は確認している。
今回はもう少しましなオシロ( http://akizukidenshi.com/catalog/g/gM-10135/ )で確認してみる。

チャネル8の出力で、Duty=100%と0%の両方で止めてみた波形が以下
Duty=100%
esp32_ledc_level1.png

Duty=0%
esp32_ledc_level0.png


ともにおよそ15μsのヒゲが出ている事が観測される。またDuty=100%ではLOWに落ち切らず、800mVくらいオフセットが出ている。
※15μsは、PWM周波数が256Hz、分解能が8bitからであろう。

※どうも8bit分解能ではDuty=100%にする為には256を設定しないとダメみたいだ。0~256???

※Duty=0%にしてもLOWに落ち切らない現象はチャネル8(以降?)で発生する。

※件の問題の原因がこれかどうかは判らない。

※しかしこれはライブラリのバグでしょう!

※esp32-hal-ledc.cのledcWriteを見てみると、
esp32_ledc_hal_ledcWrite.png


チャネル8が所属するグループ1側は値の変更に対して、チャネル0~7のグループ0はクロックの停止をしている?なぜグループで対応が異なるのかは判らない。

※githubでも報告されていますねん!
https://github.com/espressif/arduino-esp32/issues/1909
nice!(0)  コメント(0) 

ESP32のLEDCについて調べてみた。 [ESP32]

某SNSで、LEDCで16チャネル分のPWM出力した時、チャネル8以降でDutyを0に設定してもLOWにならない!と言う話があって、ちょっとLEDCについて調べてみた。
なので以下の様なコードを書いてお確かめ。

ESP32_LEDC_TEST.ino
#include  "led.h"

#define  LED_CH0_PIN  32
#define  LED_CH1_PIN  33
#define  LED_CH2_PIN  25
#define  LED_CH3_PIN  26
#define  LED_CH4_PIN  27
#define  LED_CH5_PIN  14
#define  LED_CH6_PIN  13
#define  LED_CH7_PIN  15
#define  LED_CH8_PIN  4
#define  LED_CH9_PIN  16
#define  LED_CH10_PIN  17
#define  LED_CH11_PIN  5
#define  LED_CH12_PIN  18
#define  LED_CH13_PIN  19
#define  LED_CH14_PIN  21
#define  LED_CH15_PIN  22

#define  LED_CH0_FRQ  1000.0  /* hz チャネル0とチャネル1は同一タイマーの為、後から設定した方の周波数になるはず */
#define  LED_CH1_FRQ  2000.0  /* hz チャネル0とチャネル1は同一タイマーの為、後から設定した方の周波数になるはず */
#define  LED_CH2_FRQ  3000.0  /* hz チャネル2とチャネル3は同一タイマーの為、後から設定した方の周波数になるはず */
#define  LED_CH3_FRQ  4000.0  /* hz チャネル2とチャネル3は同一タイマーの為、後から設定した方の周波数になるはず */
#define  LED_CH4_FRQ  5000.0  /* hz チャネル4とチャネル5は同一タイマーの為、後から設定した方の周波数になるはず */
#define  LED_CH5_FRQ  6000.0  /* hz チャネル4とチャネル5は同一タイマーの為、後から設定した方の周波数になるはず */
#define  LED_CH6_FRQ  7000.0  /* hz チャネル6とチャネル7は同一タイマーの為、後から設定した方の周波数になるはず */
#define  LED_CH7_FRQ  8000.0  /* hz チャネル6とチャネル7は同一タイマーの為、後から設定した方の周波数になるはず */
#define  LED_CH8_FRQ  9000.0  /* hz チャネル8とチャネル9は同一タイマーの為、後から設定した方の周波数になるはず */
#define  LED_CH9_FRQ  10000.0  /* hz チャネル8とチャネル9は同一タイマーの為、後から設定した方の周波数になるはず */
#define  LED_CH10_FRQ  20000.0  /* hz チャネル10とチャネル11は同一タイマーの為、後から設定した方の周波数になるはず */
#define  LED_CH11_FRQ  30000.0  /* hz チャネル10とチャネル11は同一タイマーの為、後から設定した方の周波数になるはず */
#define  LED_CH12_FRQ  40000.0  /* hz チャネル12とチャネル13は同一タイマーの為、後から設定した方の周波数になるはず */
#define  LED_CH13_FRQ  50000.0  /* hz チャネル12とチャネル13は同一タイマーの為、後から設定した方の周波数になるはず */
#define  LED_CH14_FRQ  60000.0  /* hz チャネル14とチャネル15は同一タイマーの為、後から設定した方の周波数になるはず */
#define  LED_CH15_FRQ  70000.0  /* hz チャネル14とチャネル15は同一タイマーの為、後から設定した方の周波数になるはず */

#define  LED_CH0_RES  (8)  /* resolution */
#define  LED_CH1_RES  (8)  /* resolution */
#define  LED_CH2_RES  (8)  /* resolution */
#define  LED_CH3_RES  (8)  /* resolution */
#define  LED_CH4_RES  (8)  /* resolution */
#define  LED_CH5_RES  (8)  /* resolution */
#define  LED_CH6_RES  (8)  /* resolution */
#define  LED_CH7_RES  (8)  /* resolution */
#define  LED_CH8_RES  (8)  /* resolution */
#define  LED_CH9_RES  (8)  /* resolution */
#define  LED_CH10_RES  (8)  /* resolution */
#define  LED_CH11_RES  (8)  /* resolution */
#define  LED_CH12_RES  (8)  /* resolution */
#define  LED_CH13_RES  (8)  /* resolution */
#define  LED_CH14_RES  (8)  /* resolution */
#define  LED_CH15_RES  (8)  /* resolution */

#define  DUTY( duty,res )  map( duty,0,100,0,(1 << res) - 1 )

led led_0( LED_CH0_PIN, 0 );
led led_1( LED_CH1_PIN, 1 );
led led_2( LED_CH2_PIN, 2 );
led led_3( LED_CH3_PIN, 3 );
led led_4( LED_CH4_PIN, 4 );
led led_5( LED_CH5_PIN, 5 );
led led_6( LED_CH6_PIN, 6 );
led led_7( LED_CH7_PIN, 7 );
led led_8( LED_CH8_PIN, 8 );
led led_9( LED_CH9_PIN, 9 );
led led_10( LED_CH10_PIN, 10 );
led led_11( LED_CH11_PIN, 11 );
led led_12( LED_CH12_PIN, 12 );
led led_13( LED_CH13_PIN, 13 );
led led_14( LED_CH14_PIN, 14 );
led led_15( LED_CH15_PIN, 15 );

void setup()
{
  /* led 0 */
  led_0.begin( LED_CH0_FRQ, LED_CH0_RES );
  led_0.write( DUTY( 50,LED_CH0_RES) );
  /* led 1 */
  led_1.begin( LED_CH1_FRQ, LED_CH1_RES );
  led_1.write( DUTY( 50,LED_CH1_RES) );
  /* led 2 */
  led_2.begin( LED_CH2_FRQ, LED_CH2_RES );
  led_2.write( DUTY( 50,LED_CH2_RES) );
  /* led 3 */
  led_3.begin( LED_CH3_FRQ, LED_CH3_RES );
  led_3.write( DUTY( 50,LED_CH3_RES) );
  /* led 4 */
  led_4.begin( LED_CH4_FRQ, LED_CH4_RES );
  led_4.write( DUTY( 50,LED_CH4_RES) );
  /* led 5 */
  led_5.begin( LED_CH5_FRQ, LED_CH5_RES );
  led_5.write( DUTY( 50,LED_CH5_RES) );
  /* led 6 */
  led_6.begin( LED_CH6_FRQ, LED_CH6_RES );
  led_6.write( DUTY( 50,LED_CH6_RES) );
  /* led 7 */
  led_7.begin( LED_CH7_FRQ, LED_CH7_RES );
  led_7.write( DUTY( 50,LED_CH7_RES) );
  /* led 8 */
  led_8.begin( LED_CH8_FRQ, LED_CH8_RES );
  led_8.write( DUTY( 50,LED_CH8_RES) );
//  led_8.write( 0 );
//  led_8.write( 255 );
  /* led 9 */
  led_9.begin( LED_CH9_FRQ, LED_CH9_RES );
  led_9.write( DUTY( 50,LED_CH9_RES) );
  /* led 10 */
  led_10.begin( LED_CH10_FRQ, LED_CH10_RES );
  led_10.write( DUTY( 50,LED_CH10_RES) );
  /* led 11 */
  led_11.begin( LED_CH11_FRQ, LED_CH11_RES );
  led_11.write( DUTY( 50,LED_CH11_RES) );
  /* led 12 */
  led_12.begin( LED_CH12_FRQ, LED_CH12_RES );
  led_12.write( DUTY( 50,LED_CH12_RES) );
  /* led 13 */
  led_13.begin( LED_CH13_FRQ, LED_CH13_RES );
  led_13.write( DUTY( 50,LED_CH13_RES) );
  /* led 14 */
  led_14.begin( LED_CH14_FRQ, LED_CH14_RES );
  led_14.write( DUTY( 50,LED_CH14_RES) );
  /* led 15 */
  led_15.begin( LED_CH15_FRQ, LED_CH15_RES );
  led_15.write( DUTY( 50,LED_CH15_RES) );
}

void loop()
{
}

led.h
/****************************************************************************/
/* led header                                                               */
/*                         Copyright (C) 2018 hamayan All Rights Reserved.  */
/****************************************************************************/
#ifndef LED_h
#define LED_h

#include  <Arduino.h>
#include  <esp32-hal-ledc.h>

extern "C" {
}

class led {
private :
  uint8_t ledPin;
  uint8_t ledChannel;

public :  
  led( uint8_t pin, uint8_t channel );
  ~led();
  double begin( double freq, uint8_t resolution_bits );

  void write( uint32_t duty );
  uint32_t read();
  double tone( double freq );
  double note( note_t note, uint8_t octave );
};

#endif /* LED_h */

/****************************************************************************/
/*                                  Copyright (C) 2018- by hamayan          */
/****************************************************************************/

led.c
/****************************************************************************/
/* led source                                                               */
/*                         Copyright (C) 2018 hamayan All Rights Reserved.  */
/****************************************************************************/
#include  "led.h"

/*************************************************************************/
/*  constructor,destructor                                               */
/*************************************************************************/
led::led( uint8_t pin, uint8_t channel )
{
  ledPin = pin;
  ledChannel = channel;
  ledcAttachPin( pin, channel );
}

led::~led()
{
  ledcDetachPin( ledPin );
}

/*************************************************************************/
/*  begin                                                                */
/*************************************************************************/
double led::begin( double freq, uint8_t resolution_bits )
{
  return ledcSetup( ledChannel, freq, resolution_bits );
}


/*************************************************************************/
/*  write (duty)                                                         */
/*************************************************************************/
void led::write( uint32_t duty )
{
  ledcWrite( ledChannel, duty );
}


/*************************************************************************/
/*  read (duty)                                                          */
/*************************************************************************/
uint32_t led::read()
{
  return ledcRead( ledChannel );
}


/*************************************************************************/
/*  tone                                                                 */
/*************************************************************************/
double led::tone( double freq )
{
  return ledcWriteTone( ledChannel, freq );
}


/*************************************************************************/
/*  note                                                                 */
/*************************************************************************/
double led::note( note_t note, uint8_t octave )
{
  return ledcWriteNote( ledChannel, note, octave );
}


/****************************************************************************/
/*                                  Copyright (C) 2018- by hamayan          */
/****************************************************************************/

チャネル0のみ1000HzでDuty=50%の波形を出力してみると以下の波形となった。
2018-11-16 10.35.13.jpg


次に全16チャネルを出力させてみた。その時のチャネル0の波形が以下である。
2018-11-16 10.43.19.jpg

お判り頂けたであろうか?PWM周波数が変わってしまっている。

以下はesp32_hal_ledc.cの一部抜粋である。
/*
 * LEDC Chan to Group/Channel/Timer Mapping
** ledc: 0  => Group: 0, Channel: 0, Timer: 0
** ledc: 1  => Group: 0, Channel: 1, Timer: 0
** ledc: 2  => Group: 0, Channel: 2, Timer: 1
** ledc: 3  => Group: 0, Channel: 3, Timer: 1
** ledc: 4  => Group: 0, Channel: 4, Timer: 2
** ledc: 5  => Group: 0, Channel: 5, Timer: 2
** ledc: 6  => Group: 0, Channel: 6, Timer: 3
** ledc: 7  => Group: 0, Channel: 7, Timer: 3
** ledc: 8  => Group: 1, Channel: 0, Timer: 0
** ledc: 9  => Group: 1, Channel: 1, Timer: 0
** ledc: 10 => Group: 1, Channel: 2, Timer: 1
** ledc: 11 => Group: 1, Channel: 3, Timer: 1
** ledc: 12 => Group: 1, Channel: 4, Timer: 2
** ledc: 13 => Group: 1, Channel: 5, Timer: 2
** ledc: 14 => Group: 1, Channel: 6, Timer: 3
** ledc: 15 => Group: 1, Channel: 7, Timer: 3
*/

チャネル0とチャネル1は同一タイマーとなっている、、、ようするにチャネル0とチャネル1間では、後から設定した方が有効となってしまう。そりゃそうだ、、、
またチャネル0からチャネル7までと、チャネル8からチャネル15までで異なるグループとなっている。これはグループ0が80MHzを原振とする高速側のタイマー、グループ1が1MHz?を原振とする低速側のタイマーとなっているようである。
つまりledcで沢山のチャネルを使用する時は、上記事柄に気を付けて使う必要がある。

※低速側タイマーの場合、最大のPWM周波数は312KHz(8bit解像度)くらい?
※高速側タイマーの場合、最大のPWM周波数は312KHz(8bit解像度)くらい?
※え!う~~~~ん、高速は判る、80MHzを256で割れば312KHzだしい。まるでウドンのキツネをつまんでいる様な、、、
※結局グループ0側も、グループ1側も、解像度を2bitにすると20MHzの波形を出力できるのう!なんだったのだろう???
※20MHzにすると、IO18とIO21が出力しない。

さて、件のLOWが出ない件であるが、Duty=0とした時の波形が以下である。
2018-11-16 11.11.15.jpg

LOWフラット、、、
試しにDuty=100とした時の波形は以下である。
2018-11-16 11.12.05.jpg

3.3Vフラットに見えるが、立下りのヒゲが出ている、、、

nice!(0)  コメント(0) 

STM32FをArduino iDEで開発的なメモメモメモ [STM32F]

以下はまったく未保証なので注意してね。何かあれば戻せるようにした上でどうぞ。

1.gccのバージョンを上げてみる。

流石にバージョンが4.8.何某はないんじゃないかと思って最新のバージョンにしてみる。
arm-none-eabi-gccはすでに2018バージョンがリリースされているので、それをまずPCにインストールする。
が!このままではArduinoから呼ばれない。STM32-Arduinoが呼んでいるarm-none-eabi-gccはArduino15フォルダー以下に存在する。Arduino IDEの環境設定からArduino15フォルダーを開くと便利。
C:\Users\hamayan\AppData\Local\Arduino15\packages\arduino\tools\arm-none-eabi-gcc
このフォルダーの下に、先ほどインストールしたarm-none-eabi-gccをまるっとコピー。

次にboards.txtを編集する。たぶん33行目辺りにarm-none-eabi-gccのツールチェインバージョンが書かれた行が有るので、それを編集する。
nucleo_f103rb.build.gcc_ver=gcc-arm-none-eabi-7 2018-q2-update
※nucleo_f103rbとなっているが、他のボードにも適用される模様。

一旦Arduino IDEを再起動してビルドすると上記の変更が反映される。

2.duplicate 'inline' errorが出るようになっちゃった!
もうARM関連は色々いじり過ぎて、何をやっているのかさっぱり。上記エラーがSTM32 Arduinoで出るようになってしまったので、対策を探す。
以下の内容がとても近い、AVR-GCCの話だけれど。
https://www.avrfreaks.net/forum/avrgnu-c-compiler-duplicate-inline-error

そこでエラーの出ているソースを編集してみる。
元は
static inline __always_inline void afio_exti_select(exti_num exti, exti_cfg port)
だったものを
__attribute__( ( always_inline ) ) static inline void afio_exti_select(exti_num exti, exti_cfg port)
とした、、、微妙だなぁ。



多分2週間もしたらきっと忘れるので、こうやってメモしておこう。

※arm-none-eabi-gccの2018バージョンは、STM32Fの開発でCoIDEでデバッガーを起動すると問題が起きるので、その一つ前の2017年バージョンに落とした。

nice!(0)  コメント(0) 

STM32FをArduino iDEで開発的なメモメモ [STM32F]

ボード毎にUSB DPのプルアップの制御が異なるので、これを一々ヘッダーファイルやCソースを書き換えていてはたいへんだから、boards.txtで対応できるようにした。

まづはboards.txtのvariantにオリジナルの基板の定義を追加
genericSTM32F103V.menu.device_variant.PIXIS1303=PIXIS1303
genericSTM32F103V.menu.device_variant.PIXIS1303.build.variant=generic_stm32f103v
genericSTM32F103V.menu.device_variant.PIXIS1303.build.cpu_flags=-DMCU_STM32F103VE -DUSB_ON_PORT=GPIOE -DUSB_ON_PIN=1 -DUSB_POWER_ON=1
genericSTM32F103V.menu.device_variant.PIXIS1303.upload.maximum_size=524288
genericSTM32F103V.menu.device_variant.PIXIS1303.upload.maximum_data_size=65536
genericSTM32F103V.menu.device_variant.PIXIS1303.build.ldscript=ld/stm32f103ve.ld

コンパイルのDEFINEオプションに
-DUSB_ON_PORT=GPIOE -DUSB_ON_PIN=1 -DUSB_POWER_ON=1
を追加し、ポート番号、ピン番号、プルアップ時の論理を渡す。

board.hは以下の様に変更
/* USB configuration.  BOARD_USB_DISC_DEV is the GPIO port containing
 * the USB_DISC pin, and BOARD_USB_DISC_BIT is that pin's bit. */
//#define BOARD_USB_DISC_DEV      GPIOC  /* original */
//#define BOARD_USB_DISC_BIT      12  /* original */
#define BOARD_USB_DISC_DEV      USB_ON_PORT
#define BOARD_USB_DISC_BIT      USB_ON_PIN


usb_cdcacm.cは以下の様に変更
void usb_cdcacm_enable(gpio_dev *disc_dev, uint8 disc_bit) {
    /* Present ourselves to the host. Writing 0 to "disc" pin must
     * pull USB_DP pin up while leaving USB_DM pulled down by the
     * transceiver. See USB 2.0 spec, section 7.1.7.3. */

    if (disc_dev!=NULL)
    {
      gpio_set_mode(disc_dev, disc_bit, GPIO_OUTPUT_PP);
//    gpio_write_bit(disc_dev, disc_bit, 0);  /* for original */
      gpio_write_bit(disc_dev, disc_bit, USB_POWER_ON );  /* for pixis 1303 */
    }

いやぁ、良かった良かった。
stm32fArduinoIde_002.png
nice!(0)  コメント(0) 

STM32FをArduino iDEで開発的なメモ [STM32F]

1.Arduino IDEを起動して、ツール→ボードマネージャーでボードマネージャを起動し、フィルターにSAMを入力してCortex-M3に関する環境を入手する。※フィルターにSTMを入れるとSTM32F4が見つかる。
stm32fArduinoIde_001.png

2.GitHubからSTM32F用のArduinoライブラリを入手する。
https://github.com/rogerclarkmelbourne/Arduino_STM32
展開後、展開したフォルダーごとhardwareフォルダー以下に移動。

3.適当なプロジェクトを作成する。書き込みはSTLinkを選択する。
※DFU(USB書き込み)とかシリアル書き込みはできるのだけど、都度BOOTのスイッチを切り替える必要が有るので、もうSTLinkでイイじゃん!って感じ。

4.以上!
※gccのツールチェインバージョンが4.8.3-2014q1と古いのが気になる、、、

5.ライブラリのドキュメントの参照先
http://docs.leaflabs.com/static.leaflabs.com/pub/leaflabs/maple-docs/0.0.12/language-index.html

こことかも
https://scrapbox.io/ArduinoSTM32/Arduino_STM32_リファレンス_日本語版

※STM32FのUSBを有効にするためには、USBのDPのプルアップを制御しているDISK(信号名)を基板に合わせる必要が有る。例えばMB-STM32F103ならPC13がそれになる(標準はPC12)。この基板で使用しているのはSTM32F103VETなので、以下のboard.hの111行目を編集して適応化させる。
\hardware\Arduino_STM32-master\STM32F1\variants\generic_stm32f103v\board\board.h
論理の変更は以下のファイルの390行目だと思われる。
\hardware\Arduino_STM32-master\STM32F1\cores\maple\libmaple\usb\stm32f1\usb_cdcacm.c

gpio_write_bit(disc_dev, disc_bit, 0); 最後の引数を0から1かなぁ、、、と言うのは元になっているmaple-r5と言う基板が以下の様になっているからである。
https://github.com/leaflabs/maple/blob/master/maple-r5/maple-r5-schematic.pdf
信号名DISCをLOWにするとDPにプルアップが行われる。

GitHubに置かれたプロジェクト
https://github.com/chobichan/stm32f3MultiTask_001


※PIN番号とGPIOの対応
上記のboard.hに以下の様に定義されている。
/* Pin aliases: these give the GPIO port/bit for each pin as an
 * enum. These are optional, but recommended. They make it easier to
 * write code using low-level GPIO functionality. */
enum {
PA0,PA1,PA2,PA3,PA4,PA5,PA6,PA7,PA8,PA9,PA10,PA11,PA12,PA13,PA14,PA15,
PB0,PB1,PB2,PB3,PB4,PB5,PB6,PB7,PB8,PB9,PB10,PB11,PB12,PB13,PB14,PB15,
PC0,PC1,PC2,PC3,PC4,PC5,PC6,PC7,PC8,PC9,PC10,PC11,PC12,PC13,PC14,PC15,
PD0,PD1,PD2,PD3,PD4,PD5,PD6,PD7,PD8,PD9,PD10,PD11,PD12,PD13,PD14,PD15,
PE0,PE1,PE2,PE3,PE4,PE5,PE6,PE7,PE8,PE9,PE10,PE11,PE12,PE13,PE14,PE15,
};


nice!(1)  コメント(0) 

Arduino AVRでマルチタスクしてみない [ATmarquino Arduino]

avrWaveGenerator_001.png


折角なのでPWMで2相出力してみる。
/**********************************************************/
/* AVR Atmega328P PWM generator                           */
/**********************************************************/
#include <avr/io.h>
#include <FlexiTimer2.h>

extern "C"
{
}

/**********************************************************/
/* prototypes                                             */
/**********************************************************/

/**********************************************************/
/* valiables                                              */
/**********************************************************/
#define  PWMA_PIN  9  // PB1:OC1A
#define  PWMB_PIN  10  // PB2:OC1B
#define  TIMER_COUNTER_CLOCK  (1000000)
#define  FREQUENCY            (50.0f)
#define  RESOLUTION           (32)
#define  PHASE_SHIFT          (-60.0f)

int scale = (256 / 2) - 1;  /**/
int offset = (256 / 2) - 0;  /* center position */
int waveTableCounter;
float channelPhase = (2 * M_PI * PHASE_SHIFT / 360.0f);
unsigned int waveTableA[ RESOLUTION ];
unsigned int waveTableB[ RESOLUTION ];

/**********************************************************/
/* setup                                                  */
/**********************************************************/
void setup()
{
  Serial.begin( 115200UL );
  Serial.println( "AVR Atmega328P PWM generator." );
  pinMode( PWMA_PIN, OUTPUT );
  pinMode( PWMB_PIN, OUTPUT );

  /* generate wave data */
  for( int i = 0; i < RESOLUTION; i++ )
  {
    int tempI = (int)(sin(2 * M_PI * i / RESOLUTION) * scale);
    waveTableA[ i ] = (unsigned int)tempI + offset;
    tempI = (int)(sin((2 * M_PI * i / RESOLUTION) + channelPhase) * scale);
    waveTableB[ i ] = (unsigned int)tempI + offset;
  }

  /* display wave data A */
  Serial.println( "WAVE DATA A" );
  for( int i = 0; i < RESOLUTION; i++ )
  {
    Serial.print( waveTableA[ i ], DEC );
    Serial.print( "," );
    if( (i % 10) == 9 ) Serial.println();
  }
  Serial.println();

  /* display wave data B */
  Serial.println( "WAVE DATA B" );
  for( int i = 0; i < RESOLUTION; i++ )
  {
    Serial.print( waveTableB[ i ], DEC );
    Serial.print( "," );
    if( (i % 10) == 9 ) Serial.println();
  }
  Serial.println();

  /* timer counter initialize. */
  TCCR1B = 0x00;  //  timer1 stop
  TCNT1 = 0x0000;  // 16bit counter clear
  TIMSK1 = 0x00;  // interrupt disable
  TCCR1A = 0b10100001;  //  0b10 10 00 01
    // OC1A : compare match goes OC1A to clear and top goes OC1A to set.
    // OC1B : compare match goes OC1B to clear and top goes OC1B to set.
    // fast 8bit PWM and top is 0x00FF. WGM = 0b0101
  TCCR1B = 0b00001010;  //  0b0 0 0 01 010
    // fast 8bit PWM and top is 0x00FF.
    // clkIO / 8 priscaller.
  OCR1A = waveTableA[ 0 ];
  OCR1B = waveTableB[ 0 ];
  TIMSK1 = 0x00;  // interrupt disable

  waveTableCounter = 1;

  FlexiTimer2::set( 1, 1.0f / (FREQUENCY * RESOLUTION), pwmUpdateHandler );
  FlexiTimer2::start();

  /* Infinite loop */
  while(1) {}
}

/**********************************************************/
/* loop ※使われない                                      */
/**********************************************************/
void loop()
{
}

/**********************************************************/
/* pwm update handler                                     */
/**********************************************************/
void pwmUpdateHandler()
{
  OCR1A = waveTableA[ waveTableCounter ];
  OCR1B = waveTableB[ waveTableCounter ];
  if( ++waveTableCounter >= RESOLUTION )
  {
    waveTableCounter = 0;
  }
}


nice!(0)  コメント(0) 

Arduino AVRでマルチタスクしてみる タスク2 [ATmarquino Arduino]

avrMultiTask_002.png


ファイル名を変えずに中身を書き換えちゃったのは、まずかったかなぁ、、、

マルチタスクのサンプルとして、PWMで50Hzのサイン波を出力するデモ。
別途用意したスイッチを押す度に別途用意したLPFを通してサイン波が出力される。ただし10秒間掛けて波形はフェードアウトする。

/**********************************************************/
/* マルチタスクやってみる                                 */
/* PWMで50hzのサイン波を出力する。10秒掛けてフェードアウト。 */
/**********************************************************/
#include <avr/io.h>
#include <FlexiTimer2.h>
#include "delivertive.h"

extern "C"
{
  #include "mul_tsk.h"
}

/**********************************************************/
/* prototypes                                             */
/**********************************************************/
void tsk_ini( void );
void stackMonitor( void );
void switchScanTask( void );
void pwmGenerateTask( void );

/**********************************************************/
/* valiables                                              */
/**********************************************************/
SYSTIM systim;  // 1msでインクリメントする変数
uint8_t tsk0_stk[ 128 * 1 ];
uint8_t tsk1_stk[ 128 * 1 ];
uint8_t tsk2_stk[ 128 * 1 ];

#define  PWM_PIN      10
#define  TRIGGER_PIN  2
#define  LED_PIN      13

#define  TIMER_COUNTER_CLOCK  (8 * 1000000UL)
#define  PWM_FREQUENCY        (10 * 1000)
#define  RESOLUTION           (40)  /* 50hz * 40 over sampling. */
#define  DELTA_SLOPE          (1.0f / 500)

int scale = TIMER_COUNTER_CLOCK / PWM_FREQUENCY / 2;  /* 1000000 is timer clock */
int offset = TIMER_COUNTER_CLOCK / PWM_FREQUENCY / 2;  /* center position */
int waveTableCounter;
float slope = 1.0f - DELTA_SLOPE;  /* 10s = 20ms * 500 */
int originalWaveTable[ RESOLUTION ];
unsigned int waveTable[ RESOLUTION ];
unsigned char switchScanUpdate;
unsigned long timer1CompbIsrCounter;
bool conversionStart = false;

/**********************************************************/
/* setup                                                  */
/**********************************************************/
void setup()
{
  Serial.begin( 115200UL );
  Serial.println( "AVR Multi Task Demo." );

  /* ststem and pwm update timer start. */
  FlexiTimer2::set( 5, 1.0f / 10000, pwmUpdateHandler );
  FlexiTimer2::start();

  tsk_ini();  //タスクの初期化
  sta_rdq( ID_monitor );  //ラウンドロビン開始。ここからタスクが開始される
}

/**********************************************************/
/* loop ※使われない                                      */
/**********************************************************/
void loop()
{
}

/**********************************************************/
/* タスク初期化                                           */
/**********************************************************/
void tsk_ini( void )
{
  reg_tsk( ID_monitor, (void *)stackMonitor, (void *)tsk0_stk, sizeof(tsk0_stk), 0,0,0,0 );
  reg_tsk( ID_switchScan, (void *)switchScanTask, (void *)tsk1_stk, sizeof(tsk1_stk), 0,0,0,0 );
  reg_tsk( ID_pwmGenerate, (void *)pwmGenerateTask, (void *)tsk2_stk, sizeof(tsk2_stk), 0,0,0,0 );

  sta_tsk( ID_monitor );
//  sta_tsk( ID_switchScan );
//  sta_tsk( ID_pwmGenerate );
}

/**********************************************************/
/* stack monitor task                                     */
/**********************************************************/
static unsigned int RemainStack( void *stk, unsigned int sz );
static void stackPrint( const char *msg, void *stk, unsigned int sz );

void stackMonitor( void )
{
  sta_tsk( ID_pwmGenerate );
  while( 1 )
  {
    dly_tsk( 10 * 1000UL );
    stackPrint( "task1 stack : ", tsk1_stk, sizeof(tsk1_stk) );
    stackPrint( "task2 stack : ", tsk2_stk, sizeof(tsk2_stk) );
    stackPrint( "monitor stack : ", tsk0_stk, sizeof(tsk0_stk) );
  }
}

static void stackPrint( const char *msg, void *stk, unsigned int sz )
{
  Serial.print( msg );
  Serial.print( RemainStack( stk, sz ), DEC );
  Serial.print( "/" );
  Serial.println( sz, DEC );
}

static unsigned int RemainStack( void *stk, unsigned int sz )
{
  unsigned int i;
  char *ptr = (char *)stk;

  for( i = 0; i < sz; i++ )
  {
    if( *ptr++ != 0 ) break;
  }

  return sz - i;
//  return i;
}

/**********************************************************/
/* switchScanTask                                         */
/**********************************************************/
void switchScanTask( void )
{
  pinMode( TRIGGER_PIN, INPUT_PULLUP );
  unsigned char sw = 0x00;
  while( 1 )
  {
    sw <<= 1;
    if( digitalRead( TRIGGER_PIN ) == LOW ) sw |= 1;
    if( (sw & 0x0f) == 0x07 )
    {
      switchScanUpdate++;
    }

    dly_tsk( 50UL );
  }
}

/**********************************************************/
/* PWM Generate Task                                      */
/**********************************************************/
void pwmGenerateTask( void )
{
  pinMode( PWM_PIN, OUTPUT );
  digitalWrite( LED_PIN, LOW );
  pinMode( LED_PIN, OUTPUT );

  /* wave table generate. */
  for( int i = 0; i < RESOLUTION; i++ )
  {
    int tempI = (int)(sin( 2 * M_PI * i / RESOLUTION) * scale);
    originalWaveTable[ i ] = tempI;
    waveTable[ i ] = (unsigned int)tempI + offset;
    Serial.print( waveTable[ i ], DEC );
    Serial.print( "," );
    if( (i % 10) == 9 ) Serial.println();
  }

  /* start switch scan task. */
  sta_tsk( ID_switchScan );

  while( 1 )
  {
    /* wait for switch pushed. */
    unsigned char switchScanUpdateBase = switchScanUpdate;
    while( switchScanUpdateBase == switchScanUpdate ) dly_tsk( 50UL );
    switchScanUpdateBase = switchScanUpdate;
    Serial.println( "pwmGenerateTask PWM start." );

    /* timer counter initialize. */
    TCCR1B = 0x00;  //  timer1 stop
    TCNT1 = 0x0000;  // 16bit counter clear
    TIMSK1 = 0x00;  // interrupt disable
    TCCR1A = 0b00100011;  //  0b00 10 00 11
      // OC1A : normal port and not connected OC1A.
      // OC1B : compare match goes OC1B to clear and top goes OC1B to set.
      // fast PWM and top is OCR1A.
    TCCR1B = 0b00011001;  //  0b0 0 0 11 001
      // fast PWM and top is OCR1A.
      // clkIO / 1 priscaller.
    OCR1A = (unsigned int)(TIMER_COUNTER_CLOCK / PWM_FREQUENCY);
    OCR1B = waveTable[ 0 ];
    TIMSK1 = 0x00;

    /* interrupt timer start. */
    slope = 1.0f - DELTA_SLOPE;
    waveTableCounter = 1;
    conversionStart = true;
    digitalWrite( LED_PIN, HIGH );

    /* wait 10s. */
    dly_tsk( 11 * 1000UL );
    conversionStart = false;
    for( int i = 0; i < RESOLUTION; i++ )
    {
      int tempI = originalWaveTable[ i ];
      waveTable[ i ] = (unsigned int)tempI + offset;
    }
    Serial.println( "pwmGenerateTask PWM stop." );
    digitalWrite( LED_PIN, LOW );
  }
}

/**********************************************************/
/* pwm update handler                                     */
/**********************************************************/
void pwmUpdateHandler()
{
  static int count = 0;

  /* system timer update */
  if( count & 1 ) systim += 1UL;
  count++;

  if( conversionStart == true && slope >= 0.0f )
  {
    OCR1B = waveTable[ waveTableCounter ];
    float tempF = (float)originalWaveTable[ waveTableCounter ] * slope;
    waveTable[ waveTableCounter ] = (unsigned int)tempF + offset;
    if( ++waveTableCounter >= RESOLUTION )
    {
      waveTableCounter = 0;
      slope -= DELTA_SLOPE;
    }
  }
}


nice!(0)  コメント(0) 

ESP32でアラームハンドラーが動いたり、動かなかったり、チップリビジョン? [ESP32]

経緯はここを見てね。
https://www.facebook.com/groups/927623023964478/permalink/1966158430110927/?comment_id=1973470699379700¬if_id=1539774777726286¬if_t=group_comment_follow

ESP32のチップリビジョンでアラームハンドラが動いたり動かなかったりする事は確認。

こまったねぇ、、、

nice!(1)  コメント(0) 

Arduino AVRでマルチタスクしてみる タスク1 [ATmarquino Arduino]

arduinoAvrMultiTask_001.png

gitHubで公開と言う慣れない事をやっているので、良かったら教えてね!

https://github.com/chobichan/avrMultiTask_001
※ちょっとだけ修正入れています。ダウンロード実績1件、わらった!

サンプルINOは3つのタスクが起動しています。
1.stackMonitor
2.task1
3.task2
ライブラリの非依存部のサービスコールは従来からこのblogで公開している物。
AVRに依存するライブラリを今回新たに作成している。

AVR依存部を作成するにあたって考慮するところ!
※AVR GCCの破壊レジスタ : r0,r18-r27(X register),r30-r31(Z register)

※;AVR GCCの非破壊レジスタ : r2-r17,r28-r29(Y register)

※関数から戻る時は必ずr1レジスタを0にする r1=0

※AVR GCCの最初の引数 : r25:r24、AVR GCCの2番目の引数 : r23:r22、AVR GCCの3番目の引数 : r21:r20、AVR GCCの4番目の引数 : r19:r18

※AVR GCCの戻り値 : r25:r24

コンテキストをスタックに積むところは以下の様にした。
スタックポインタからのオフセットレジスタ
0r29
1r28
2r17
3r16
4r15
5r14
6r13
7r12
8r11
9r10
10r9
11r8
12r7
13r6
14r5
15r4
16r3
17r2
18ステータスレジスタ
19空き
20プログラム・カウンタ 上位
21プログラム・カウンタ 下位


スタックにプログラム・カウンタを積むところで結構嵌った(笑)。

nice!(0)  コメント(0) 

ESP32のSerialライブラリ [ESP32]

ESP32は標準のSerialがあるけれど、それ以外にJPEGカメラとサーモセンサー(共にシリアルインタフェース)を接続する為に、2つのSerialを追加して使用している。
そうすると、わりと高い頻度で追加したSerialが止まってしまう困った現象を起こしていた。

でまぁ、困ったのでgithubを見るとSerial廻りとか割り込み廻りの更新が9月20日くらいに行われているので、そのバージョンを適用してみた。

結果、いまのところ順調である。

やれやれ、、、
nice!(0)  コメント(0) 
前の10件 | -