STM32C0を使ってみる4 -8PinのSTM32C0を使いこなせ!-

今回は秋月電子さんから販売された8ピンのSTM32C011J4M7を使いこなします。
STM32G0の時と違ってGPIOの設定が厳密になっているのでそこら辺も掘り込んで
詳しく紹介します。

●ねむいさん的STM32C011やっけつ回路

今回紹介する8ピンSTM32C011の回路図はG0の頃と同じ感じです。
8ピンSTM32G0をそのまま差し替えて使用できるようにしてみました。
もちろん1-Wireも使えます!

ちなみに最低限のやっけつ回路なので真似される方は電源ラインは
適宜強化願います。


●GPIOのリマップとマルチプレクス

さて、8ピンのSTM32C011はひとつのピンに多重にGPIOや周辺機能が
割り当てられています。


ねむいさんは8ピンのSTM32G0と同じ回路でI2Cを動作させたかったの
ですが、STM32C011のI2Cは1つしか存在しないためSTM32G0では可能
だったI2C2が使用できずI2C1のみとなっております。
その結果PA11,PA12をそのまま使用することができないので"リマップ"
を行う必要があります。



SYSCFGのCFGR1レジスタをいじってGPIOのリマップを行うことによりI2C1
(PA9,PA10)がようやく使用可能となります。


実際はHALライブラリのRemap関数が提供されているのでそれを使用しております。


また、STM32G0ではガバガバだったGPIOの設定もC0では厳密になっており、
例えば8Pin版STM32C0でPC14を選択して使用したい場合はSYSCFGのCFGR3
レジスタのPINMUXビットをいじる必要があります(ついでにPA9とPA10も)。


また、20Pin版STM32C011F4P6では他のI/Oポートと重複がなくPINMUXをいじる
必要がないため、上で提示したコードのようにパッケージレジスタを参照し、
PINMUXをいじるか否かを判定しております。


てわけで改めてSTM32C011J4M7を使ってI2Cデバイス(秋月OLEDSHT40)を
使った温湿度計を稼働させてみました!楽勝ですね☆

秋月から8pinSTM32G0がなくなった今、8ピンのSTM32C011J4M7がSTM32への
入門の定番となっていくでしょう!

今回紹介したプロジェクトはSTM32C0-NUCELOのプロジェクトと合体させて
公開しております!どしどしご活用ください!



●STM32C011J4M7のフラッシュ容量は実際32kByteもある?
STM32C011J4M7のフラッシュ容量は公称では16kByteとなっております。
しかし実際には32kByteもあるようです…マジかよ…
実際に以下の方々が32kByteあることを確認をしております。
しっぽいいんちょ様
amanoya3様


ねむいさんもSTM32C0-NucleoからSWDを引き出してSTM32C011に接続し、
STM32CubeProgrammerで確認してみました!


…ッッマジだ…32kByteってなってる…


わざと16kByteを超える30kByte超えのバイナリを作って書き込んで
みました…書き込める…ちゃんとベリファイも通る…!!!


もちろんちゃんと動いてるし…!


てわけで秋月で売っているSTM32C011J4M7は16kByteではなく実際は
32kByteもあることがわかりましたがこのおまけ容量に頼った設計を
しないように!ちゃんと16kByteの範疇で遊びましょう!





なお、OpenOCDでは16kByte以上を書き込むことができず、16kByte
以降の領域は書き込まれていないためベリファイが通りません。


なんでかというとOpenOCDのSTM32C0のフラッシュ書き込みドライバは
STM32C0に仕込んであるフラッシュ容量レジスタを参照して厳密に書き込める
容量を決定しているためです。

逆に言うとSTM32CubeProgrammerのほうがガバッガバなドンブリ設計…
STマイクロ公式がそれでいいのか!?


ちなみに超セコい技ですがCubeProgrammerで予め16kByte以降の領域を
書き込んでおくとOpenOCDでもベリファイが通りプログラムも正常に
動作します。全然意味ないですがー!

このおまけ容量の使い方としてはどうしてもプログラムサイズが
増えがちなデバッグ時に一時的な使い方として用いるのがよいです。
まぁロットが変わっておまけの16kByte分が無くなったら出来ない
技なので当たり引けたらラッキー的な感じで遊んでいきましょ〜

STM32C0を使ってみる3 -STM32C011秋月発売記念-


少し前の話ですがSTM32C0シリーズが秋月電子よりついに販売されました!!


8pinのSTM32C011J4M7


20pinのSTM32C011F4P6です!!


ROM容量はROM16kbyte,RAMが6kbyteとSTM32シリーズの中では
非常に小ぶりな品種となります。


●ピン配置について注意


まず注意点として20Pinの品種は同じく秋月で販売されているSTM32L010F4P6
ピン互換性がないのでご注意ください。



また、8pinのSTM32C011J4M7はかつて秋月で販売されていたSTM32G031J6M6
ほぼピン互換となっております…

が!


ねむいさんの使い方ではI/Oのリマップを行わないと一部の機能…I2Cが
使用できないのでご注意ください。こちらについては次回にみっちりと解説
させていただきます!



●実際に使ってみた

そんなわけで秋月OLED秋月販売のSHT408pinSTM32C011でサクッと温湿度
表示してみました…!

長らくの間ねむいさんのドットマトリクスOLEDドライバが秋月OLEDに対応して
なかったの気づいてませんでしたが誰も気づいてなかったから多分大丈夫です…

すみません次回からまじめにやります…!!


今回はさわりだけ紹介しましたが、次回はI/Oのリマップ機能とかも使いこなす
方法も解説していこうと思います!

20240206追:
既存のSTM32C031-NUCLEO向けプロジェクトにSTM32C011J4M7向けの
やつを合体させたの先行公開します!!!!!

20240206追:

秋月発売記念!AVR64DD28を使ってみる!

あけましておめでとうございます。

今年は最初から災難続きでございますが、できることを精一杯頑張って
まいりましょう!!


今回は昨年末に秋月電子通商から販売されたAVR-DDシリーズの
最大容量品であるAVR64DD28
の紹介をしていこうと思います。


AVR-DDシリーズはAVR-DBシリーズの小規模化したデバイスとなります。
DxCoreの品種比較表がわかりやすいです。またDBシリーズで存在した
エラッタがいくつか修正されているのも特徴です。

基本的な機能はAVR-DBを引き継いでいますのでAVR64DD28は現時点で
非常に使い勝手がよいAVRとなり、将来的にはATMega328Pを置き換えて
いくことでしょう。

●AVR64DD28のプログラムメモリ構成とrodataの取り扱いについて
AVR-Dxシリーズはデータ領域にプログラム領域の一部がマッピング
されており、LPM命令を使用しないでも通常のLD命令が使用可能な
領域が存在しております。


AVR64DD28においては64kByteあるプログラムメモリの後半32kByte分が
データ領域にデフォルトでマッピングされております。残念ながら
64KByte品では全領域とはならず半分の32kByte分となります。
32kByte以下の容量品では全領域がマッピングされております。


ちなみにNVMモジュールのCTRLBレジスタはデフォルトで後半32kByte分
のマッピング設定になっているため通常使いの場合は特に設定は
不要で後半32kByte分はデータ領域としてアクセスできるわけです。


が!




AVR128DA48とかAVR128DB28を使ったときにも同じ解説をしておりますが、
AVR64DD28というかAVR-Dxシリーズの64kByte以上のフラッシュ容量の
品種では何も考えないでビルドするとavr-gcc内にビルドインされた
デフォルトのリンカスクリプト(AVR64DD28ではavrxmega2.xn)を選択して
しまうため、上記のようなデータ領域のマッピングを意識しないメモリの
取り扱いをしてしまいます。
これでは旧AVR製品のように面倒なPROGMEMが必要となってしまいます。


ねむいさんは64KByte中後半32kByteをrodataとするような特別なリンカ
スクリプトを作成してPROGMEM使わなくてもSTM32みたいに普通にconstを
取り扱えるようにしてみました。
まぁAVRとしてはプログラム領域32kByteとrodata領域32kByteは十分すぎる
広さとなるでしょう〜
プロジェクト中にもありますが一応私が作ったリンカスクリプト貼っておきます。

/* Script for -n */
/* Copyright (C) 2014-2023 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
OUTPUT_ARCH(avr:102)
__TEXT_REGION_ORIGIN__ = DEFINED(__TEXT_REGION_ORIGIN__) ? __TEXT_REGION_ORIGIN__ : 0;
__DATA_REGION_ORIGIN__ = DEFINED(__DATA_REGION_ORIGIN__) ? __DATA_REGION_ORIGIN__ : 0x802000;
__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 1024K;
__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 0xffa0;
__EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 64K;
__FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K;
__LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 1K;
__SIGNATURE_REGION_LENGTH__ = DEFINED(__SIGNATURE_REGION_LENGTH__) ? __SIGNATURE_REGION_LENGTH__ : 1K;
__USER_SIGNATURE_REGION_LENGTH__ = DEFINED(__USER_SIGNATURE_REGION_LENGTH__) ? __USER_SIGNATURE_REGION_LENGTH__ : 1K;
__RODATA_PM_OFFSET__ = DEFINED(__RODATA_PM_OFFSET__) ? __RODATA_PM_OFFSET__ : 0x8000;
MEMORY
{
text (rx) : ORIGIN = __TEXT_REGION_ORIGIN__, LENGTH = __TEXT_REGION_LENGTH__-32K
rodata (rx) : ORIGIN = __TEXT_REGION_LENGTH__-32K, LENGTH = 32K
data (rw!x) : ORIGIN = __DATA_REGION_ORIGIN__, LENGTH = __DATA_REGION_LENGTH__
eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
fuse (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
lock (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__
signature (rw!x) : ORIGIN = 0x840000, LENGTH = __SIGNATURE_REGION_LENGTH__
user_signatures (rw!x) : ORIGIN = 0x850000, LENGTH = __USER_SIGNATURE_REGION_LENGTH__
}
SECTIONS
{
/* Read-only sections, merged into text segment: */
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.text :
{
*(.rel.text)
*(.rel.text.*)
*(.rel.gnu.linkonce.t*)
}
.rela.text :
{
*(.rela.text)
*(.rela.text.*)
*(.rela.gnu.linkonce.t*)
}
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.rodata :
{
*(.rel.rodata)
*(.rel.rodata.*)
*(.rel.gnu.linkonce.r*)
}
.rela.rodata :
{
*(.rela.rodata)
*(.rela.rodata.*)
*(.rela.gnu.linkonce.r*)
}
.rel.data :
{
*(.rel.data)
*(.rel.data.*)
*(.rel.gnu.linkonce.d*)
}
.rela.data :
{
*(.rela.data)
*(.rela.data.*)
*(.rela.gnu.linkonce.d*)
}
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.bss : { *(.rel.bss) }
.rela.bss : { *(.rela.bss) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
/* Internal text space or external memory. */
.text :
{
*(.vectors)
KEEP(*(.vectors))
/* For data that needs to reside in the lower 64k of progmem. */
*(.progmem.gcc*)
/* PR 13812: Placing the trampolines here gives a better chance
that they will be in range of the code that uses them. */
. = ALIGN(2);
__trampolines_start = . ;
/* The jump trampolines for the 16-bit limited relocs will reside here. */
*(.trampolines)
*(.trampolines*)
__trampolines_end = . ;
/* avr-libc expects these data to reside in lower 64K. */
*libprintf_flt.a:*(.progmem.data)
*libc.a:*(.progmem.data)
*(.progmem.*)
. = ALIGN(2);
/* For code that needs to reside in the lower 128k progmem. */
*(.lowtext)
*(.lowtext*)
__ctors_start = . ;
*(.ctors)
__ctors_end = . ;
__dtors_start = . ;
*(.dtors)
__dtors_end = . ;
KEEP(SORT(*)(.ctors))
KEEP(SORT(*)(.dtors))
/* From this point on, we do not bother about whether the insns are
below or above the 16 bits boundary. */
*(.init0) /* Start here after reset. */
KEEP (*(.init0))
*(.init1)
KEEP (*(.init1))
*(.init2) /* Clear __zero_reg__, set up stack pointer. */
KEEP (*(.init2))
*(.init3)
KEEP (*(.init3))
*(.init4) /* Initialize data and BSS. */
KEEP (*(.init4))
*(.init5)
KEEP (*(.init5))
*(.init6) /* C++ constructors. */
KEEP (*(.init6))
*(.init7)
KEEP (*(.init7))
*(.init8)
KEEP (*(.init8))
*(.init9) /* Call main(). */
KEEP (*(.init9))
*(.text)
. = ALIGN(2);
*(.text.*)
. = ALIGN(2);
*(.fini9) /* _exit() starts here. */
KEEP (*(.fini9))
*(.fini8)
KEEP (*(.fini8))
*(.fini7)
KEEP (*(.fini7))
*(.fini6) /* C++ destructors. */
KEEP (*(.fini6))
*(.fini5)
KEEP (*(.fini5))
*(.fini4)
KEEP (*(.fini4))
*(.fini3)
KEEP (*(.fini3))
*(.fini2)
KEEP (*(.fini2))
*(.fini1)
KEEP (*(.fini1))
*(.fini0) /* Infinite loop after program termination. */
KEEP (*(.fini0))
/* For code that needs not to reside in the lower progmem. */
*(.hightext)
*(.hightext*)
*(.progmemx.*)
. = ALIGN(2);
/* For tablejump instruction arrays. We do not relax
JMP / CALL instructions within these sections. */
*(.jumptables)
*(.jumptables*)
_etext = . ;
} > text
.data :
{
PROVIDE (__data_start = .) ;
*(.data)
*(.data*)
*(.gnu.linkonce.d*)
. = ALIGN(2);
_edata = . ;
PROVIDE (__data_end = .) ;
} > data AT> text
.bss ADDR(.data) + SIZEOF (.data) : AT (ADDR (.bss))
{
PROVIDE (__bss_start = .) ;
*(.bss)
*(.bss*)
*(COMMON)
PROVIDE (__bss_end = .) ;
} > data
__data_load_start = LOADADDR(.data);
__data_load_end = __data_load_start + SIZEOF(.data);
/* Global data not cleared after reset. */
.noinit ADDR(.bss) + SIZEOF (.bss) : AT (ADDR (.noinit))
{
PROVIDE (__noinit_start = .) ;
*(.noinit .noinit.* .gnu.linkonce.n.*)
PROVIDE (__noinit_end = .) ;
_end = . ;
PROVIDE (__heap_start = .) ;
} > data
.rodata :
{
*(.rodata)
*(.rodata*)
*(.gnu.linkonce.r*)
} > rodata
.eeprom :
{
/* See .data above... */
KEEP(*(.eeprom*))
__eeprom_end = . ;
} > eeprom
.fuse :
{
KEEP(*(.fuse))
KEEP(*(.lfuse))
KEEP(*(.hfuse))
KEEP(*(.efuse))
} > fuse
.lock :
{
KEEP(*(.lock*))
} > lock
.signature :
{
KEEP(*(.signature*))
} > signature
.user_signatures :
{
KEEP(*(.user_signatures*))
} > user_signatures
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1. */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions. */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2. */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2. */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions. */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3. */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF 5. */
.debug_addr 0 : { *(.debug_addr) }
.debug_line_str 0 : { *(.debug_line_str) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_macro 0 : { *(.debug_macro) }
.debug_names 0 : { *(.debug_names) }
.debug_rnglists 0 : { *(.debug_rnglists) }
.debug_str_offsets 0 : { *(.debug_str_offsets) }
.debug_sup 0 : { *(.debug_sup) }
}

これをLDFLAGSに食わせてやればこちらが優先されて上記のようにメモリが
配置される仕組みになっています。詳細は私のプロジェクト内makefileの
274行目あたりを参照してください。

ねむいさん式リンカスクリプト
dataセクションの使用領域が減りました。さらにrodata領域に
読み取り専用のデータが割り当てられています。
Memory region         Used Size  Region Size  %age Used
text: 2796 B 32 KB 8.53%
rodata: 144 B 32 KB 0.44%
data: 144 B 8 KB 1.76%
eeprom: 0 GB 256 B 0.00%
fuse: 0 GB 16 B 0.00%
lock: 0 GB 1 KB 0.00%
signature: 0 GB 1 KB 0.00%
user_signatures: 0 GB 1 KB 0.00%
一方デフォルトリンカスクリプトのメモリ使用領域は…
dataセクションに取られてしまい無駄にメモリ領域を圧迫してます。
Memory region         Used Size  Region Size  %age Used
text: 2940 B 64 KB 4.49%
data: 288 B 8 KB 3.52%
eeprom: 0 GB 256 B 0.00%
fuse: 0 GB 16 B 0.00%
lock: 0 GB 1 KB 0.00%
signature: 0 GB 1 KB 0.00%
user_signatures: 0 GB 1 KB 0.00%




20240123追:
GCC14ではコンパイル時のスイッチでリマップに対応するようです!!!
こうご期待!!!

20240123追:



●AVR64DD28向けのバイナリをAVR-GCCでビルドする方法
数年前からお伝えしている通り、avr-gccでAVR64DD28とかの最新の品種を
ビルドするためには自分でオブジェクトとかデバイス定義ファイルを
追加してやる必要があります。今回はavr-gccの導入から改めて解説して
いこうと思います。64bit版Windows10環境下を想定しております。


1.Windows向けavr-gccを取得する
Zak's Electronics Blogの"AVR-GCC 13.2.0 for Windows"をダウンロード
します。GCCが最新の13.2.0となっておりますが特筆すべきはビルドイン
されたリンカスクリプトに"__DATA_REGION_ORIGIN__"が追加されるように
なったのですがこれめっちゃ重要な修正なので必ず13.2.0のバイナリを
使用するようにしてください!!


ねむいさんの環境ではARM開発環境に倣って下記ディレクトリに展開します。
C:¥Devz¥AVR¥avr-gcc



avr-gccディレクトリ内はこうなります。
またmakeの呼び出し方はARMとまったく共通なのでARMマイコンのビルド
環境構築法
のCoreutilsの設定を参考にしてください。


2.MicrochipのサイトからDeviceFamilyPacks(DFP)を取得する
こっからがだいぶ面倒です。"Microchip Packs Repository"から
"Microchip AVR-Dx Series Device Support"をダウンロードします。
拡張子がatpackとなっていますが実態はzip圧縮ファイルです。
以下7zの使用を想定して進めていきます。

3.DFPからヘッダファイルとかデバイス定義ファイル抽出して追加
a.ヘッダファイルの追加
圧縮ファイル内の"¥include"に進みます。

"C:¥Devz¥AVR¥avr-gcc¥avr¥include"内にavrフォルダをコピーします。

b.device-specsの追加
圧縮ファイル内の"¥gcc¥dev¥avr64dd28"と進みます。

"C:¥Devz¥AVR¥avr-gcc¥lib¥gcc¥avr¥13.2.0"内にdevice-specsフォルダを
コピーします。

c.スタートアップファイルの追加

"C:¥Devz¥AVR¥avr-gcc¥avr¥lib"内にavrxmega2フォルダをコピーします。

あああめんどくさい…
とにかくこれで前準備が終わりました…

ほかの品種でもこの操作を行うことによって最新のAVRがビルドできます。





それでは改めてねむいさんのプロジェクトの上記の部分をavr64dd28にして
ビルドします。

ちゃんと設定ができていたらビルドが始まり…

すぐ終わった…


書き込みはavrdudeを使用します
書き込み方法はこちらのserialUPDIの記事を参考に…



プログラムはAVR128DA/DBと共通でデバイスの固有シリアル番号を表示
した後1秒ごとにチップ温度をUARTで送出するものです。
ADCとUART(ノンブロッキング)を使用しております。
チップ単体でできる基本的なことを網羅しております。





今回もぐだぐだとした内容になってしまいましたが、ねむいさんの
ぶろぐを見てる人はねむいさんより技術力が高い方ばっかりなので
多分理解してくれて大丈夫だと思います…


そんなわけでこんな感じで精いっぱいがむばっていこうと思います…!

いろいろ試す61(と今年の反省会)

あっという間に年末になってしまいましたね…
残り時間は少ないですが最後まで頑張りましょう〜




●ATMELSTARTが新機種のAVR非対応に

ねむいさんはだいぶ前からAVR-DDシリーズも手に入れておりました。
しかし買ってそのまま放置してたのでとりあえず使ってみようと思い、
まずはATMELSTARTで初期コードの生成をやってみようと思ったのですが
AVR-DDシリーズにはもはや対応しておりませんでしたorz

そしてMicorochip社の提供するMPLABなる総合開発環境でコードを
生成する必要があります…

ねむいさんAVRはArduinoすら使わずavr-gccのコマンドラインビルド環境で
プログラム書き込みはavrdude派なのでこんな小規模のマイコンにこんな
糞重い環境使いたくないんですけぉ!!!

う〜む微妙だ…


と思案に暮れていたところにMicrochipのgithubを見てみたらちゃんと周辺
機器別のExampleが大量にありましたとさorz
これ参考にAVR-DDのコードをAVR-GCCに当てはめて動作せしめられました。
今回はほんのさわりだけですがAVR-DDシリーズについては来年詳しく紹介
しますのでよろしく!

秋月電子でもAVR64DD28が販売開始でこれは熱くなるかも!?


●Picoscope7のソフトがようやく安定…か?
6から7になって超不安定になってしまったPicoscopeのソフトですが10月に
7.1.13にアップデートしておりました。"Other stability improvements "の
文字列を信じてインストールしてみました!!!


お?


以前のverでは速攻固まって使い物にならなかったI2Cのデコード表示も
ちゃんとできてる!!


と思ったらいろいろいじってたら固まったorz
ううむあと一歩…

全く使えないレベルからだましだまし使えるレベルになってきましたがまだ
安心して移行できる状態ではないですね…
当分の間は6を使っていこうと思います…ていうか私以外にPicoscopeを
使ってる人ほとんどいないのでは…ちょっと波形が見たいけど据え置き型を
出すまでもない状況ではかなり使えるんですけどね〜


●いつものの小変更
私のSTM32へのFatFs移植例"いつもの"について、長らくCMSISv5を
使ってまいりましたが今年後半からCMSISv6に移行しております。
で、このCMSISv6ですがNVIC周りで最近結構でかい更新がかかりました
さらに、CMSIS_v6のその他の変更はこちらにまとめられております

具体的にはIPというレジスタがIPRに変更になっています。
STM32においては古いペリフェラルライブラリを使用しているSTM32F1と
STM32F4の作例が直撃です(新しいHALライブラリは大丈夫です)。

仕方ないのでこんな感じに修正してお茶を濁しておきました…。
んでもってついでに以下の作例を2024年1月版に更新しております。
STM32F1
STM32F4
STM32F7
STM32H7
STM32L5
STM32H5

STM32L5に関しては今回の更新で完全終了で今後はH5に注力していきます。
H5は精力的に更新していきますので今後ともよろしく!!


●中華液晶追加など
地味ですがねむいさんのいつものの作例中にある液晶ドライバに
2種追加しております。年末なのでついでに紹介しようと思います。

まずはNT39106をコントローラに持つ170x220のQCIFなやつです。


お次はNT39116Bをコントローラに持つ240x320のQVGAなやつです。

これらの液晶モジュールは中華サイトを調べまくったりすでに動作
確認できた品種に似た型番の物から初期化コードを推測して無理くそ
動かしちゃってます。
ここまで来たらもう意地ですがAliexpress見てると次から次に新しい
刺客がやってくるので飽きさせてくれませんね…
こちらも地味に追加を重ねていこうと思います。


●"ペット・サウンズ"で使われてたフォント
電子工作と全然関係ないですがねむいさんはBeachBoysの大ファンで、
PetSoundsは好きなアルバムの一つです。
このアルバムジャケットで使用されていたフォントが今まで何か分からなかった
のですが調べまくって判明いたしました。
それがCooper Blackです!!!
型番シール作成する時はこのフォント好んで使っております。
まぁ完全に個人の趣味ですけどね〜



●そして反省会と来年の展望

今年もやろうと思ってできなかったことだらけですが長年後しでやっと
かたづいたやつが1件…
・DropBoxの画像表示問題の解消
 これにつきます。
 5年越しでやっとこ終わりました…長かった…
 このペースでいくと今度は容量問題に立ち当たることになりますが
 その時はその時で対処していきたいなと思います

そして今後やるべき事柄ですがこれは2件…
・ARM開発環境の整備
 特にかつてデバッグで使用していたInsightはWin10以降で使用不能に
 なってしまいましたので現在CodeLiteによるデバッグ方法を確立して
 いる最中となっております。
 2024年中にはわかりやすくなおかつ安定してデバッグできるような
 手順書の作成を進めてまいります。

・AVR関連の記事の増強
 これ最近になっていろいろ問い合わせいただくようになってきました。
 UPDIを使用する新しいタイプのAVRの使用記や書き込みソフト"avrdude"
 についての記事の需要が非常に高まっていると感じます。
 ちょうどAVR-EA/EBも出てさらにAVR-DUシリーズも登場の予感が出て
 来ましたのでちょっとAVRにもがむばってみようと思います。
 せっかくなのでついでにXMEGAの作例も2024年版に更新してみました
 かつて一度は捨てたはずのマイコンですが再びこうやって相まみえる
 とは運命を感じますね…


てわけで上記2件を来年の目標に記事の充実と整備を続けていこうと
思います!今後ともよろしくお願いします。

中部北陸自然歩道を往く -再走!小松から金沢まで-

今年6月早々に敦賀〜金沢まで走破達成した…つもりでしたがあとから
調べたら小松〜金沢間で"整備中・廃道"となっているルートが存在している
ことが判明し、この年末にその失われたルートに赴いて真の走破達成を
目指しました!!!はてさてどうなることやら…



●2023.12.28 中部北陸自然歩道(小松〜金沢)


なぜ私は再走を…
再び小松の地に立つ私…
新幹線ムードがいやがおうにも高まる小松駅からスタートです…!


小松は歌舞伎推しですね


菟橋神社で47匱紊離丱肇襪良勝祈願をしました!


安宅橋近くに来ました。
6月に訪れた安宅灯台も見えますね。


"自然歩道"のルートと合流します。安宅バス停付近です。
石川県内のルートは現在正式には3ルートしか存在しませんが
実は"自然百景の道"なる大量の中部北陸自然歩道構想が存在して
おりました。こんなにあったのになぜ今3ルートしかないかというと
予算とかの都合で整備放棄->廃道となったり永遠の未整備となって
いるようです。


そひてこれが整備放棄され廃道化した"弁慶・義経なみだのみち"です…
今回はこの自然歩道たちに忠実に進んで金沢へ向かいます!!!



ちょっとグラウンドを周回した後すぐに日本海に出ます…がいきなりの
冬季通行止め看板が!
今回のルートは小松加賀自転車道と道をほとんど同じくしておりますが…
まぁこの天気だと問題なく全部通れそうですけどね〜(死亡フラグ


ちゃんと側道もあるのでこちらを通りました。



と思ったらすぐに住宅街方面に押し出される…
翠が丘運動公園から北陸自動車道を超えていきます。


住宅街ルート中にも神社仏閣がちらほら見られ、
飽きさせません。


源平合戦で有名らしい根上松です。


高坂公園です。


ほんと神社仏閣が多いですね…


サンダーバードが北陸の大地を駆け抜けるのもあと少し…


能美根上駅で小休止しました。



能美根上駅から再び日本海に向かいます。


と思ったらまた住宅街に戻される…


JR小舞子駅です。
ここで弁慶・義経なみだのみちはおしまいです。
次は加賀海岸しおかぜのみちらしいですが…



国道に沿って取手川を越えていきます。


さぁ今度こそ日本海を走る!



と思ったらまたまた戻されていく…
取手公園平賀園地に沿って進みます。


今度こそほんとのホントに日本海沿いをひたすら走るルートに!!!


あ、こんなところに
いつもお世話になっております(意味深




豪快な日本海とどこまでも続く自転車道、そして…
12月とは思えないくらい日差しが強い太陽…!
天候的には抜群のコンディションですね…




日本海の荒波に常にされされているせいかここかしこに補修を続けて
いる場面が見られます…こういうのもあって自然歩道から外れちゃったの
でしょうねぇ…




徳光PAに到着です…!
売店でマス寿司を買って大休憩で後半戦に備えます。


???



さぁ後半もお気楽自転車どu…う”!?
道が砂で埋まってる!?


砂に足を取られて先に進めない…靴の中にもどんどん砂が
たまってくる…天候はベストなのが唯一の救いです…


と思ったら今度は川かYO!
これ自転車道ですよね…?



体力をごりっと削られてやっと砂地獄から解放された…
ていうか冬季に限らず自転車で通れるわけないでしょ!!!


県民海浜公園で砂落としがてら休憩です。
ここから先は川沿いのサイクリングロードを走ります。


ねこ。



犀川サイクリングロードに沿って駆け抜けていきます…
あと少し…あと少し…


北陸新幹線の延伸ももうすぐですね…



金沢市街に突入しました。
最後の神社にお参りして香林坊に向かいます。


自然歩道の終点(と思われる場所)、芭蕉の辻に到着です。
香林坊まであとほんのちょっと!!!




ッッ到着…!!
北陸道の交差路香林坊に到着です!!!!



そして昨年10月から足掛け1年2か月…敦賀から金沢まで自然歩道を
たどってこんどこそ真の走破を達成しました!!


金沢駅に来たらゴーゴーカレーも忘れない!!
いただきます!!!


さておなかを満たした後は…(道に迷ってる)



やっと見つけた!
サウナもある瓢箪湯で足の疲れをいやしました…♨



お土産もたくさん買い込んで京都に帰還です…
次に金沢に来るときは北陸新幹線になるのかな〜
…と思いながら帰路につきました。


ていうわけで年末ぎりぎりに突っ込んでみましたが後半の砂地獄以外は
懸念していた雪もなく天候に恵まれ楽しく?走り抜けることができました!


●2023.12.28 中部北陸自然歩道(小松〜金沢)GPSログ


さぁ次は今度こそ富山県境にアタックDA!

STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-

クリスマス直前ですがわずかな時間を見つけて少しでもSTM32H5を使った
記事を書き残していきます…その先に何があるのかわからなくとも…!
すでにFatFsのSTM32H5への移植例はアップロードしておりますので今回も
これをもとに解説を進めていきますよぅ!


今回は基本中の基本、GPIOのほかにCortex-M33というかSTM32H5を使う人の
所見殺しポイントの回避とかを紹介してまいります。


●GPIOのレジスタがちょっと合理化

これはSTM32L5からなのですがGPIO出力のビットセット/リセットのレジスタ
(BSRR/BRR)が別々のアドレスに設定されております。

これは何気に良い改良だと思います。STM32F1とかの古い品種では上位16bit
がBRRで下位16bitがBSRRでひとまとまりになっており、HALに振り回されて
非常に使いづらくオーバーヘッドも多いので実行速度・コードサイズ的に
とても不利な代物でした。

で、ねむいさんは例えばSTM32F4のHALライブラリを使った作例とかではこんな
感じの構造体を作ってキャストしなおしてアクセスする手法でGPIOのビット
セット&リセットを簡潔にやってきましたが、たまにソースコードちゃんと
読まない方々からBRRなんてないからこのプログラムは動かないのでは?とか
質問もらうのですがほんとにBRRが定義されてないのならそもそもビルド通らん
やろうがぁああああ!!ちゃんとstm32f4xx_hal_conf.hの一番下のところ読めや
あああぁぁあぁあ!!!11!1

はぁはぁ…失礼…話を戻しますがSTM32H5・STM32L5以降ではそういう
小手先の手間も省けてBRR/BSRRられるようになりましたので安心です♥


●ビルド途中でGCCがセグメンテーションフォルトして死ぬ

なんでやねん
どうしたらよいのだ私は…
具体的に言うとGCC12でstm32h5xx_hal_dma_ex.cを最適化レベル-O2以降で
コンパイルしたらセグフォ死します…何やっても先に進めません

ねむいさんより先にSTM32H5触れた方も所見殺しの罠にかかっておられ
ました…
やはり初物はエラッタからライブラリに至るまで罠が満載…


ねむいさんは苦しみ紛れに屁をこいたような対策でセグフォ死の罠を
回避を行うことで対策しております。ちなみに現在リリースされている
GCC13では対策されて-O2にしても落ちなくなったので安心です☆

ねむいさんはSTM32H5のDMA対応ですっっごく時間食われましたがその半分
くらいはセグフォ問題で捕まりました…F**K!


●DACを使用したりUniqueIDを読みだそうとしたらHardFaultって死ぬ
だからなんでやねん
L5だと全く問題なかったのに…!


その理由はUIDレジスタのアドレスの変更に理由があります。
STM32L5ではこれらのレジスタは0x0BFA0590だったのですがSTM32H5では
0x08FFF800以降に変更されており、このアドレス領域はフラッシュメモリが
存在するアドレス(0x08000000)と同じであり命令実行を前提としている
そうなので普通の使い方ではIキャッシュを有効にすると思いますが有効に
してUIDレジスタがある0x08FFF800にアクセスした瞬間に命令領域にデータ
アクセスしようとしたと判断されてHardFaultして死にます!


もっと凶悪なのがHALライブラリのDACライブラリ中でパッケージデータを
判別して使用するチャネルを設定するコードがあり、そのパッケージを判別
するレジスタも0x08FFF800以降に存在するので何も対策してないと上記の例と
同じようにHardFaultして容赦なく死にます!!

STM32のフォーラムでは罠にかかった犠牲者がすでにちらほら出ております…


で、対策なのですがMPUを使用して0x08FFF800あたりのアドレスを読み出し
オンリー&命令実行禁止設定にしてあげればよいです。具体的には下記の
コードになります。

static void MPU_Config(void)
{
MPU_Region_InitTypeDef MPU_InitStruct;
MPU_Attributes_InitTypeDef MPU_AttributesInit;

/* Configure region for UID,PACKAGE,FLASHSIZE Register */
/* Disable MPU */
HAL_MPU_Disable();

/* Define readonly access via MPU */
MPU_AttributesInit.Number = MPU_ATTRIBUTES_NUMBER0;
MPU_AttributesInit.Attributes = MPU_NOT_CACHEABLE;
HAL_MPU_ConfigMemoryAttributes(&MPU_AttributesInit);

MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x08FFF800UL; /* UID ADDRESS and others */
MPU_InitStruct.LimitAddress = 0x08FFF800UL + 32 - 1;
MPU_InitStruct.AccessPermission = MPU_REGION_ALL_RO;
MPU_InitStruct.AttributesIndex = MPU_ATTRIBUTES_NUMBER0;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);

/* Enable MPU (any access not covered by any enabled region will cause a fault) */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}



なお、マニュアルにもあらかじめMPU使っておけよと匂わせておりますが
こんなん初見で絶対わかりませんよぅ!!!
人にソースコードよく見ろと言っておきながら自分のことは棚に上げて
言うのもアレですがマニュアル相当読み込まないとマジで気づきません。

STM32L5から特に何も考えずスライド移植したら罠にかかって爆死する
パタンがH5では多いので気を付けましょう(経験者バイアス)
それとこうならないようにマニュアルはちゃんと読みましょうorz

20240205追:
STM32H5の地雷踏まないようなMPU設定の仕方が公式で
ようやく公開されています…最初から公表しろ〜〜〜〜!!!!!!

20240205追:




そんなわけでいくつもの罠が待ち受けているSTM32H5ですがこれからも
未知の罠が待ち受けているでしょう。しかしアーリーアダプタな戦士たちは
それに臆せず果敢に進んでいくのです…!!


そして先にも紹介しましたがFatFsのSTM32H5への移植例はおきぱですでに
公開しております
。ちょっと気が早いですが先行して2024年版に更新
しておりますのでヨロシク!!

Go to top of page