SSブログ

STM32FをArduino IDEで開発的なメモの8乗くらい [STM32F]

色々あって、STM32FでやるArduinoは、以下にしています。
https://github.com/stm32duino

STM32Duinoでは端子の指定方法が2種類あって、これがややこしいのだが、
一つはPinNumber、もう一つはPinNameとなる。

PinNumberはvariantsフォルダーから辿っていき、それぞれのマイコンタイプ毎に分かれて、例えばSTM32F103VETでは以下のフォルダーの
https://github.com/stm32duino/Arduino_Core_STM32/tree/master/variants/STM32F1xx/F103V(C-D-E)(H-T)
variant_generic.hで定義されている、いわゆる通し番号となっている。

PinNameはこれとはまったく違うフォルダーの中に存在する。
https://github.com/stm32duino/Arduino_Core_STM32/blob/master/cores/arduino/stm32/PinNames.h

PinNameで参照しているPortAとかPortBとかは以下で定義されている。
https://github.com/stm32duino/Arduino_Core_STM32/blob/master/cores/arduino/stm32/PortNames.h

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

STM32FをArduino IDEで開発的なメモの7乗くらい [STM32F]

色々あって、STM32FでやるArduinoは、以下にしています。
https://github.com/stm32duino

アマゾンでHALライブラリの参考書を買ってみた。
と言うか、STM32CubeMXの使い方が書かれている。FreeRTOSやAIの導入まで書かれている。

HALライブラリとかSTM32CubeMXとか、なかなか判らんもんね~~~、助かる。


STM32HAL&SW4入門

STM32HAL&SW4入門

  • 作者: K.Watanabe
  • 出版社/メーカー:
  • 発売日: 2017/06/24
  • メディア: Kindle版



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

STM32FをArduino IDEで開発的なメモの6乗くらい [STM32F]

色々あって、STM32FでやるArduinoは、以下にしています。
https://github.com/stm32duino

STM32DuinoでBlynkをやった話。SPIの設定でちょっと躓いたのでメモ。
使ったのはSTM32F401RCTとW5500を搭載した基板となる。

ライブラリが整備されているので、Blynkのサーバーにアクセスする事はWiznetのW5100か、W5200か、W5500を使っている限り比較的容易にできる。
W5300に関してはまだライブラリが存在していないみたいで、これは自分でドライバーを書くしか無さそう。

以下を参照してみてください。

https://github.com/hamayanShowa-ele/ArduinoShare/tree/main/F4_2102_Blynk_Blink

W5500のインタフェースはSPIですが、W5500のCSを標準のNSSとかに設定していない場合、以下の行を初期化時に付け足しておく必要が有る。

Ethernet.init( W5500_CS );

以上。

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

STM32FをArduino IDEで開発的なメモの5乗くらい [STM32F]

色々あって、STM32FでやるArduinoは、以下にしています。

https://github.com/stm32duino
stm32f103_wave_001.png

STM32duinoでは様々な周辺機能のクラスが有ってプロトタイピングは楽なのですが、機能がサポートされていない物も有る。今回はTimerのPWM出力を使って任意のアナログ波形を生成したいと言うお題。もちろんPWM出力はLPF(Low Pass Filter)で均している。

STM32duinoはHardwareTimerクラスを持っている。折角有るのでこのHardwareTimerクラスを使ってお題をこなしたい。

https://github.com/stm32duino/Arduino_Core_STM32/blob/master/cores/arduino/HardwareTimer.h

を見るとPWM出力のメンバー関数も当然のように用意されているので、こちらを使えば、、、
しかしやりたいのは任意の”波形”であり、一定周期でPWMのDutyを変化させないと、任意の直流電圧波形になってしまう。

一定周期でPWMのDutyを変化させる方法は?
1.コンペアマッチのステータスをずっとモニターして、更新タイミングで新しいコンペアマッチの値をレジスタに代入する?
2.コンペアマッチのステータスの変化を割込みで捉えて、割込みのタイミングで新しいコンペアマッチの値をレジスタに代入する?

1のソフトウエアだけでやるのは如何にもスマートではないのでパス。2の割込みを使うのは現実的だが、まだソフトウエアの負荷が大きく、多数のチャネルでそれを行うのはちょっと忍びない。

3.更新タイミングに、DMAで新しい値を転送してしまおう!やはりこれしか無いかな?

STM32duinoはHALライブラリを使用している。HALライブラリでタイマー関連のライブラリは以下になる。

https://github.com/stm32duino/Arduino_Core_STM32/blob/master/system/Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_tim.h

/* Non-Blocking mode: DMA */
HAL_StatusTypeDef HAL_TIM_PWM_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length);
HAL_StatusTypeDef HAL_TIM_PWM_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel);

上記の様にDMA連動の関数が存在する。
確かにHAL_TIM_PWM_Start_DMAを使えば、PWMの更新値はDMA転送で行われている様子だ。
しかしもう少し進めて、DMAの転送完了割込みを起動したい。

HardwareTimerクラスはメンバー関数にattachInterruptを持つ。しかしこのメンバー関数はBASE Timerの更新とか、コンペアマッチの一致時に使うもので、DMA転送の完了と言う訳ではない。

stm32f1xx_hal_tim.hのHALライブラリで使用されているTIM_HandleTypeDef構造体には

DMA_HandleTypeDef *hdma[7];

が存在し、DMAと連動する7種類の条件が有る。
/** @defgroup DMA_Handle_index TIM DMA Handle Index
  * @{
  */
#define TIM_DMA_ID_UPDATE                ((uint16_t) 0x0000)       /*!< Index of the DMA handle used for Update DMA requests */
#define TIM_DMA_ID_CC1                   ((uint16_t) 0x0001)       /*!< Index of the DMA handle used for Capture/Compare 1 DMA requests */
#define TIM_DMA_ID_CC2                   ((uint16_t) 0x0002)       /*!< Index of the DMA handle used for Capture/Compare 2 DMA requests */
#define TIM_DMA_ID_CC3                   ((uint16_t) 0x0003)       /*!< Index of the DMA handle used for Capture/Compare 3 DMA requests */
#define TIM_DMA_ID_CC4                   ((uint16_t) 0x0004)       /*!< Index of the DMA handle used for Capture/Compare 4 DMA requests */
#define TIM_DMA_ID_COMMUTATION           ((uint16_t) 0x0005)       /*!< Index of the DMA handle used for Commutation DMA requests */
#define TIM_DMA_ID_TRIGGER               ((uint16_t) 0x0006)       /*!< Index of the DMA handle used for Trigger DMA requests */


とまぁ、PWMの更新にDMAを使い、データブロックの転送完了後に何かしらの割込みを発生させることが出来そうな雰囲気は有るのだが、どうすれば良いのか判らなくて嵌まった。

なのでSTM32の初心に帰って自分で割込みをなんとかする事とする。

そもそもDMA転送完了割込みの割込みハンドラ自体が、検索しても割込みベクターが書いてあるファイル(STM32F103VETであれば startup_stm32f103xe.s )の中に、例えばTimer3 channel1のDMA要求の接続先であるDMA1_Channel6の割込みハンドラは、

.weak DMA1_Channel6_IRQHandler
.thumb_set DMA1_Channel6_IRQHandler,Default_Handler

と記述されているが、このままではDefault_Handlerに行ってしまう。

つまり、DMA割込みを使いたかったら自前でDMA1_Channel6_IRQHandlerを用意し、NVICの設定を行い、DMAに割込みを許可すれば良い事になる、、、ホンマ?
以下、参照してみてください。

https://github.com/hamayanShowa-ele/ArduinoShare/tree/main/F1_PWM_WAVE_Output_01
https://github.com/hamayanShowa-ele/ArduinoShare/tree/main/libraries

上記例ではTC(Transmit Complete)とエラーのみ、割込みを有効化していますが、もちろんHT(Half Transmit)を有効化することは有用です。
例えばADCのデータを連続的に取り込む場合にDMAはよく使います。DMAを循環モードで動かしている場合、取り込み先のメモリーはリングバッファとして扱われますので常時どこかのアドレスに対して書込みが行われています。
プログラム側はどの位置まで書込みが完了したのか把握したい場合、リングバッファの前半と後半に分けてそれぞれ書込み完了のタイミングが判れば、前半終了のHT割込みのタイミングでリングバッファの前半の内容を安全に演算や転送などの処理をできますし、後半の終了のTC割込みのタイミングでリングバッファの後半の内容を安全に演算や転送などの処理をできます。

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

STM32FをArduino IDEで開発的なメモの4乗くらい [STM32F]

色々あって、STM32FでやるArduinoは、以下にしています。

https://github.com/stm32duino

STM32duinoでは、STM32F_CPU_IDENTITYクラスを利用する事で、CPUの情報を色々取得する事ができます。
例えば、
#include <STM32F_CPU_Identity.h>
STM32F_CPU_IDENTITY cpu_id;としておいて、
cpu_id.sysload()でsystick timerの値、
cpu_id.hclk()でhclkの値、
cpu_id.pclk1()とcpu_id.pclk2()でpclk1とpclk2の値、
cpu_id.sysclk()でシステムクロックの値が取得できますん。
また、
uint32_t uid[3];
cpu_id.uID( uid );

で、3つのCPU IDが取得できますん。

そんなわけでCPUのクロック等の情報を取得できたのですが、では実際にArduino環境でSTM32Fの開発を行った場合、システムクロックはどうなっているんでしょうか?
と言うのが今回のお題。

STM32Fの開発に使用した基板はNUCLEOとかではなくオリジナルの基板であることから、Arduino IDEのボードの選択は”STM32F1 series”とし、Board parts numberは"Generic F103VETx"としています。つまりSTM32F103VETを搭載したマイコンボードです。

上記マイコンボードは、HSE用に8MHzのクリスタルを接続してあります。STM32F103VETは最大72MHzで動かすことができます。
しかしSTM32F_CPU_IDENTITYクラスで取得したシステムクロックは64MHzとなりました、、、う~~~ん。

結局ボードにGenericタイプを選んだ時にシステムクロックがどうなるのかと言うと、STM32duinoのツールチェインのvariantsにそれが有りました。例えば、以下の様なPATHにgeneric_clock.cが有りますん。

C:\Users\ユーザー名\AppData\Local\Arduino15\packages\STMicroelectronics\hardware\stm32\2.0.0\variants\STM32F1xx\F103V(C-D-E)(H-T)

generic_clock.cのSystemClock_Config関数でシステムクロックの設定が行われており、標準ではHSIを使用し、HSIが8MHzですから8MHz÷2×16で64MHzの出来上がりです。

ですがSystemClock_Config関数はWEAK修飾子が付いています。
なのでユーザーが独自にSystemClock_Config関数を用意すれば、そちらが優先される事となります。

ユーザーがSystemClock_Config関数を生成するもっとも簡単な方法はSTM32CubeMXを使う事です。グラフィカルな画面でマウスでポチポチしていけばSystemClock_Config関数を生成してくれるので、それを取って来てスケッチに貼り付けるだけでOKです。以下参照してみてください。

https://github.com/hamayanShowa-ele/ArduinoShare/tree/main/F1F4_GET_CPU_ID
https://github.com/hamayanShowa-ele/ArduinoShare/tree/main/libraries

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

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

ハードディスクが飛ぶ寸前だったのを機にSSDに交換してクリーンインストールしたので、ついでにArduino IDEでstm32duinoのArduino Core STM32に手を出している。

https://github.com/stm32duino

環境設定から追加のボードマネージャーのURLを追加し、
https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json

ボードマネージャーでArduino Core STM32を追加したが、まぁいろいろうまく行かなかった。
ボードマネージャーで追加されたツールチェインでは正常にコンパイルが行われなかったので、gnu-armの最新版、いわくつきの2018年版をダウンロードしてplatform.txtでツールチェインのパスを変更

20行目辺り
#compiler.path={runtime.tools.arm-none-eabi-gcc-6-2017-q2-update.path}/bin/
compiler.path={runtime.tools.arm-none-eabi-gcc-8 2018-q4-major.path}/bin/
2019-05-08.png


が、今度はobjcopyでよくわからんエラーで先に進まない。

どうやらobjcopyのバグらしくこんな報告が上がっている、、、
https://bugs.launchpad.net/gcc-arm-embedded/+bug/1810274

はぁ、、、(*´Д`)

対策は、2018年版のツールチェインをやめて2017年版にするか、2017年版のobjcopyだけを上書きコピーすること。
※結局他でもトラブル起こすので、2017年 Q4 メジャー版に戻しましたよ、、、はぁ

お役立ちリンク
https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=2ahUKEwiAgI2ywoviAhULxbwKHbnFD3oQFjAAegQIARAB&url=https%3A%2F%2Fscrapbox.io%2FArduinoSTM32%2FArduino_STM32_%25E3%2583%25AA%25E3%2583%2595%25E3%2582%25A1%25E3%2583%25AC%25E3%2583%25B3%25E3%2582%25B9_%25E6%2597%25A5%25E6%259C%25AC%25E8%25AA%259E%25E7%2589%2588&usg=AOvVaw23b9dYNx5_EZ6Z6loRNkAL

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) 

STM32CubeMXに関する事 4 CoIDEで開発 7 [STM32F]

そして、書いたコードが消えた、、、orz
nice!(0)  コメント(0) 

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。