中国 Puyaが製造している ARM マイコンです。 おもに Flash などを製造している会社のようです。
このなかでも PY32F002A は最低価格帯に所属する製品で、驚くことに安いと話題の CH32V003 よりも安い、「世界最安値フラッシュマイコン」「8セントマイコン」などと呼ばれています。 実際 LCSC では大量購入すると $0.08 という値段を見ることができます。
CH32V003 と違い、公式ドキュメントは中国語ばかりで、ほとんどネットで情報を見かけることはないというマイナーマイコンです。
今回は TTSOP20 版の PY32F002AF15P を Aliexpress で購入しました。 一つ辺り 20円くらいです。(円安つらたん)
さすがに最低価格帯なので、最低限の機能しかありません。 CH32V003 と比較すると次のようになっています。
PY32F002A | CH32V003 | |
---|---|---|
Core | Cortex M0+ | RV32EC |
MaxClock | 24MHz | 48MHz |
Flash | 20KB | 16KB |
SRAM | 3KB | 2KB |
Timer | 3 | 2 |
SPI | 1 | 1 |
I2C | 1 | 1 |
USART | 1 | 1 |
DMA | 0 | 7 |
ADC | 12bit 8ch | 10bit 8ch |
動作クロックが半分、メモリのサイズが少し大きい他はほぼ同じ構成に見えます。
公式には DMA が存在しないのが残念なところですが、まぁこれはのちにいろいろ変わるので…
CH32V003 は STM8F003 とピンコンパチですが、PY32F002A は完全オリジナル配列となっています。 姉妹品である PY32F003/030 ともピン配置に互換性はありません。
ARM で一般的な SWDIO がありますので、OpenOCD などで書き込みができます。 また USART からの書き込みもできますので、高価? な書き込み機は不要です。
腐っても ARM マイコンですので、公式には Keil MDK などを推奨しているようです。
STM32の HAL や LL API に相当する FirmwareLibrary をメーカが提供しているので、 無償の開発環境を用意することもできます。
無償の開発環境としては、以下の2 つがあるようです。
以下の 3 つの実装が github 上では見つかります。
なお、2つ目のWindows で使える開発環境では SEGGER/J-Link OB が必要と書かれています。 どこのご家庭にもある ST-LINK や LPC-LINK が使えるようですが。 (make で書き込み・デバックしなきゃ大丈夫なような気が…)
こちらも STM32 と同じような Arduino が使えるようです。 ただし、ドキュメントは中国語です。(英語に翻訳してくれる人募集中らしい…)
gcc toolchain を使うものは、差分は Makefile くらいしかなさそうなので、 今回は、https://github.com/IOsetting/py32f0-template/ をベースに環境構築したいと思います。
GCC toochain を使った開発環境には前提条件がいくつかありますので、先にインストールします。
ARM 公式サイトから gcc 一式をダウンロードします。
AArch32 bare-metal target (arm-none-eabi)
を選択してください。
Windows 環境ならインストーラ形式の exe ファイルをダウンロードすればよいでしょう。
Linux なら、distro の純正パッケージにあると思いますが、Windows には存在しないのでMake for Windowsを別途インストールします。 インストールしたディレクトリを PATH に通しておきます。
PS> $ENV:Path="C:\Program Files (x86)\GnuWin32\bin;"+$ENV:Path
Python3 環境をインストールのうえ、pip コマンドで PyOCD をインストールします。
pip install pyocd
準備ができたら、https://github.com/IOsetting/py32f0-template/ をダウンロードするか git clone
します。
テンプレートは PA0 を L チカするコードになっているので、まずはこのままビルドします。
テンプレートの Makefile は Linux 環境用になっているので、
https://github.com/TDLOGY/py32f0-template-project/ の Makefile
と rules.mk
を持ってきます。
gcc toolchain のバージョンやらライブラリのパスが違うのでMakefile
を修正する必要があります。(Appendix 参照)
make できれば、Build/app.hex
にバイナリができます。
書き込みます。 まずは SWDIO 書き込みということで、WCH-LinkE を ARM モードにしたものを使っています。
PS> make flash
pyocd erase -t py32f002ax5 --chip --config ./Misc/pyocd.yaml
0001324 I Erasing chip... [eraser]
0001519 I Chip erase complete [eraser]
pyocd load ./Build/app.hex -t py32f002ax5 --config ./Misc/pyocd.yaml
0001252 I Loading C:\Users\ \Documents\PUYA\blink\Build\app.hex [load_cmd]
[==================================================] 100%
0002854 I Erased 8192 bytes (2 sectors), programmed 7808 bytes (61 pages), skipped 0 bytes (0 pages) at 4.79 kB/s [loader]
USART を覗くと一秒ごとに echo
と出力されるのがわかります。
PY32F0xx LED Toggle Demo
System Clock: 8000000
echo
echo
echo
echo
echo
というわけで、開発環境構築から L チカまでお届けしました。
##### Project #####
ifeq ($(OS),Windows_NT) # is Windows_NT on XP, 2000, 7, Vista, 10...
detected_OS := WIN
else
detected_OS := $(shell uname) # same as "uname -s"
endif
PROJECT ?= app
# The path for generated files
BUILD_DIR = Build
##### Options #####
# Use LL library instead of HAL, y:yes, n:no
USE_LL_LIB ?= n
# Enable printf float %f support, y:yes, n:no
ENABLE_PRINTF_FLOAT ?= n
# Build with FreeRTOS, y:yes, n:no
USE_FREERTOS ?= n
# Build with CMSIS DSP functions, y:yes, n:no
USE_DSP ?= n
# Build with Waveshare e-paper lib, y:yes, n:no
USE_EPAPER ?= n
# Programmer, jlink or pyocd
FLASH_PROGRM ?= pyocd
##### Toolchains #######
ifeq ($(detected_OS),WIN) # is Windows_NT on XP, 2000, 7, Vista, 10...
ARM_TOOCHAIN ?= C:/Program Files (x86)/Arm GNU Toolchain arm-none-eabi/13.2 rel1/bin
JLINKEXE ?= C:/Program Files/SEGGER/JLink/JLink
else
ARM_TOOCHAIN ?= /opt/gcc-arm/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi/bin
JLINKEXE ?= /opt/SEGGER/JLink/JLinkExe
endif
# path to JLinkExe
# JLink device type, options:
# PY32F002AX5, PY32F002X5,
# PY32F003X4, PY32F003X6, PY32F003X8,
# PY32F030X4, PY32F030X6, PY32F030X7, PY32F030X8
JLINK_DEVICE ?= PY32F030X6
# path to PyOCD,
PYOCD_EXE ?= pyocd
# PyOCD device type, options:
# py32f002ax5, py32f002x5,
# py32f003x4, py32f003x6, py32f003x8,
# py32f030x3, py32f030x4, py32f030x6, py32f030x7, py32f030x8
# py32f072xb
PYOCD_DEVICE ?= py32f030x6
##### Paths ############
# Link descript file: py32f002x5.ld, py32f003x6.ld, py32f003x8.ld, py32f030x6.ld, py32f030x8.ld
# LDSCRIPT = Libraries/LDScripts/py32f030x8.ld
#LDSCRIPT = Libraries/LDScripts/py32f002ax5.ld
LDSCRIPT = Libraries/LDScripts/py32f030x6.ld
# Library build flags:
# PY32F002x5, PY32F002Ax5,
# PY32F003x4, PY32F003x6, PY32F003x8,
# PY32F030x3, PY32F030x4, PY32F030x6, PY32F030x7, PY32F030x8,
# PY32F072xB
LIB_FLAGS = PY32F030x6
# C source files (if there are any single ones)
CSOURCES :=
CFILES := Libraries/CMSIS/Device/PY32F0xx/Source/system_py32f0xx.c \
User/main.c \
User/py32f0xx_it.c
# ASM single files
#AFILES := Libraries/CMSIS/Device/PY32F0xx/Source/gcc/startup_py32f002a.s
AFILES := Libraries/CMSIS/Device/PY32F0xx/Source/gcc/startup_py32f030.s
# Include paths
INCLUDES := Libraries/CMSIS/Core/Include \
Libraries/CMSIS/Device/PY32F0xx/Include \
User
ifeq ($(USE_LL_LIB),y)
CFILES += Libraries/PY32F0xx_LL_BSP/Src/py32f0xx_bsp_clock.c \
Libraries/PY32F0xx_LL_BSP/Src/py32f0xx_bsp_led.c \
Libraries/PY32F0xx_LL_BSP/Src/py32f0xx_bsp_printf.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_adc.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_dma.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_gpio.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_lptim.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_rtc.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_usart.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_comp.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_exti.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_i2c.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_pwr.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_spi.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_utils.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_crc.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_flash.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_led.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_rcc.c \
Libraries/PY32F0xx_LL_Driver/Src/py32f0xx_ll_tim.c
INCLUDES += Libraries/PY32F0xx_LL_Driver/Inc \
Libraries/PY32F0xx_LL_BSP/Inc
LIB_FLAGS += USE_FULL_LL_DRIVER
else
CFILES += Libraries/PY32F0xx_HAL_BSP/Src/py32f0xx_bsp_clock.c\
Libraries/PY32F0xx_HAL_BSP/Src/py32f0xx_bsp_led.c\
Libraries/PY32F0xx_HAL_BSP/Src/py32f0xx_bsp_printf.c\
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_dma.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_iwdg.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_rtc.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_usart.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_adc.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_exti.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_led.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_rtc_ex.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_wwdg.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_adc_ex.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_flash.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_lptim.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_spi.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_comp.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_gpio.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_pwr.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_tim.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_cortex.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_i2c.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_rcc.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_tim_ex.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_crc.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_irda.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_rcc_ex.c \
Libraries/PY32F0xx_HAL_Driver/Src/py32f0xx_hal_uart.c \
User/py32f0xx_hal_msp.c
INCLUDES += Libraries/PY32F0xx_HAL_Driver/Inc \
Libraries/PY32F0xx_HAL_BSP/Inc
endif
ifeq ($(USE_FREERTOS),y)
CFILES += Libraries/FreeRTOS/croutine.c \
Libraries/FreeRTOS/list.c \
Libraries/FreeRTOS/queue.c \
Libraries/FreeRTOS/tasks.c \
Libraries/FreeRTOS/timers.c \
Libraries/FreeRTOS/stream_buffer.c \
Libraries/FreeRTOS/portable/GCC/ARM_CM0/port.c
CFILES += Libraries/FreeRTOS/portable/MemMang/heap_4.c
INCLUDES += Libraries/FreeRTOS/include \
Libraries/FreeRTOS/portable/GCC/ARM_CM0
endif
ifeq ($(USE_DSP),y)
CFILES += Libraries/CMSIS/DSP/Source/BasicMathFunctions/BasicMathFunctions.c \
Libraries/CMSIS/DSP/Source/BayesFunctions/BayesFunctions.c \
Libraries/CMSIS/DSP/Source/CommonTables/CommonTables.c \
Libraries/CMSIS/DSP/Source/ComplexMathFunctions/ComplexMathFunctions.c \
Libraries/CMSIS/DSP/Source/ControllerFunctions/ControllerFunctions.c \
Libraries/CMSIS/DSP/Source/DistanceFunctions/DistanceFunctions.c \
Libraries/CMSIS/DSP/Source/FastMathFunctions/FastMathFunctions.c \
Libraries/CMSIS/DSP/Source/FilteringFunctions/FilteringFunctions.c \
Libraries/CMSIS/DSP/Source/InterpolationFunctions/InterpolationFunctions.c \
Libraries/CMSIS/DSP/Source/MatrixFunctions/MatrixFunctions.c \
Libraries/CMSIS/DSP/Source/QuaternionMathFunctions/QuaternionMathFunctions.c \
Libraries/CMSIS/DSP/Source/StatisticsFunctions/StatisticsFunctions.c \
Libraries/CMSIS/DSP/Source/SupportFunctions/SupportFunctions.c \
Libraries/CMSIS/DSP/Source/SVMFunctions/SVMFunctions.c \
Libraries/CMSIS/DSP/Source/TransformFunctions/TransformFunctions.c
INCLUDES += Libraries/CMSIS/DSP/Include \
Libraries/CMSIS/DSP/PrivateInclude
endif
ifeq ($(USE_EPAPER),y)
CDIRS += Libraries/EPaper/Lib \
Libraries/EPaper/Examples \
Libraries/EPaper/Fonts \
Libraries/EPaper/GUI
INCLUDES += Libraries/EPaper/Lib \
Libraries/EPaper/Examples \
Libraries/EPaper/Fonts \
Libraries/EPaper/GUI
endif
include ./rules.mk