ATtiny10の環境構築とLチカまで
ATtiny10の環境の構築とサンプルプログラムの解説
ATtiny10の環境構築とLチカまで
この記事は TUT (powered by LinuxClub) Advent Calendar 2025 の13日目の記事です。
はじめに
あいさつ
12月13日となり、クリスマスまで2週間を切りましたね。今回は、すみさんのアドベントカレンダー第一弾として、クリスマスにちなんだ内容をやりたいと思いました。
そこで、「クリスマス→イルミネーション→LED→Lチカ」 ということで、前回のサークルで行ったLT会のスライドをベースに、ATtiny10の環境構築からLチカまでを解説することにしました。
以下は、LT会のスライドです。
ATtiny10とは
ATtiny10 とは、Microchip Technology社(旧Atmel社)が提供している「tinyAVR」シリーズに属するマイコンです。
スペックを簡単に見ると以下の通りです。
| 項目 | 仕様 | 備考 |
|---|---|---|
| コア | 8bit AVR (Reduced) | 汎用レジスタは16個 (r16〜r31) |
| ROM (Flash) | 1 kB | プログラム領域 1024Bまで |
| RAM (SRAM) | 32 Bytes | 変数領域 ちっちゃい |
| クロック | 8MHz (最大12MHz) | 内蔵オシレーター、デフォルト1MHz |
| 動作電圧 | 1.8V〜5.5V | 幅広い電源電圧に対応 |
| GPIO | 4本 | 電源ピンを除くと4本のみ |
| パッケージ | SOT23-6 | 2mm × 3mm程度 |

このように、ATtiny10はパッケージサイズ・RAM・ROMのすべてにおいて極めて小さいのが特徴です。
環境構築
Microchip Studioのインストール
ATtiny10の開発には、Microchip社が提供する統合開発環境(IDE)であるMicrochip Studio(旧Atmel Studio)を使用します。
- Microchip社の公式サイト からインストーラーをダウンロードする。
- インストーラーを起動し、指示に従ってインストールを進める。
- アーキテクチャの選択画面では、「AVR 8-bit MCUs」にチェックが入っていることを確認する。
書き込み装置 (TPI) の準備
ATtiny10へのプログラム書き込みには、TPI (Tiny Programming Interface) というプロトコルを使用します。 ATtiny10は足が6本しかなく書き込み方式が特殊なため、今回はArduino Unoを書き込み装置として利用する方法を採用します。
Arduinoを書き込み装置にする
Arduino UnoをTPIプログラマとして動作させるためのスケッチをArduinoIDEやPlatformIOで書き込みます。 今回は bdpdx/ATtiny10Programmer のコードを使用します。
- 上記リポジトリからZIPファイルをダウンロードするか、
git cloneしてコードを入手する。 ATtiny10Programmer.inoをArduino IDEやPlatformIOで開く。- ボード選択欄でArduino Unoを選択し、スケッチを書き込む。
配線(書き込み回路)
ArduinoとATtiny10を以下のように接続します。
注意: Arduino D11とATtiny10のTPIDATAの間には 2.2kΩの抵抗 が必要です。
| Arduino Pin | ATtiny10 Pin | 機能 | 備考 |
|---|---|---|---|
| D10 | 6 (PB3) | RESET | |
| D11 | 1 (PB0) | TPIDATA | 抵抗を経由して接続 |
| D12 | 1 (PB0) | TPIDATA | |
| D13 | 3 (PB1) | TPICLK | |
| 5V | 5 (VCC) | VCC | |
| GND | 2 (GND) | GND |
※ 安定動作のために、ATtiny10のVCC-GND間に0.1μF〜100μF程度のパスコンを入れることを推奨します。

書き込み手順
- Microchip Studioでビルドして生成された
.hexファイルの内容をすべてコピーする。(ファイルはプロジェクトフォルダ内のDebugまたはReleaseフォルダに出力されます。) - 書き込み装置化したArduinoをPCに接続し、シリアルモニタを開く。(ポーレートは115200bps)
- シリアルモニタに
Command [d,e,i,m,u,v,?] >といったメニューが表示されていることを確認する。 iを送信して接続確認を行う。ATtiny10 connectedと表示されれば配線成功。- 再度メニューが表示されたら
uを送信してアップロードモードに入る。Upload hex file content to serial monitorと表示される。 - 入力欄にコピーしたhexファイルの内容をそのまま貼り付けて送信する。
Writing flashに続いて各行がOKと表示され、すべて完了したら書き込み成功。

サンプルプログラム解説
環境構築と書き込みができたら、実際に動くコードを見てみましょう。 今回のサンプルでは、アセンブリを用いて単純なON/OFFではなく「正弦波テーブルに合わせてPWM制御をする」というところまで実装しています。
実際に動作させた様子が以下の動画で、LEDが正弦波に合わせてなめらかに明滅します。
以下でこのコードを解説していきます。サンプルコードは SmiSANN/attiny10-asm-templates-01 リポジトリで公開しています。
LED接続について: このサンプルでは PB0(1番ピン) と PB1(3番ピン) がPWM出力ピンになります。各ピンに適切な抵抗(330Ω〜1kΩ程度)を介してLEDを接続してください。
Lチカ(正弦波PWM)のコード
このプログラムは、Flashメモリ上に配置した正弦波データを順次読み出します。その値をPWMのデューティ比として出力することで、LEDの明るさを滑らかに変化させています。
1;2; AssemblerProject1_Optimized.asm3; Created: 2025/11/28 17:46:574; Author : smi5; Target: ATtiny106; Clock: 8MHz (Derived from code)7; Function: PWM Waveform Generator (Likely Sine wave on PB0/PB1)8 9.device ATtiny1010.cseg11.org 0x000012 13RESET:14 ; --- システムクロック設定 (8MHz) ---15 LDI r16, 0xD8 ; CCP書き込みキー16 OUT CCP, r1617 LDI r16, 0x00 ; 分周なし18 OUT CLKPSR, r1619 20 ; --- スタックポインタ設定 ---21 OUT SPH, r16 ; SPH = 022 LDI r16, low(RAMEND)23 OUT SPL, r1624 25 ; --- I/O設定 ---26 ; PB0=OC0A, PB1=OC0B (タイマー出力ピン)として出力設定27 LDI r16, 0x03 ; PB0, PB1を出力設定 (0b00000011)28 OUT DDRB, r1629 30 ; --- タイマー0設定 (Phase Correct PWM, 8-bit) ---31 ; COM0A1:0=10, COM0B1:0=10 (非反転), WGM01:0=0132 LDI r16, 0xA133 OUT TCCR0A, r1634 ; WGM03:2=00, CS02:0=001 (分周なし)35 LDI r16, 0x0136 OUT TCCR0B, r1637 38 ; --- ポインタ初期化 ---39 ; Flash先頭(0x4000) + データオフセット(0x0100) = 0x410040 LDI XH, 0x4141 LDI XL, 0x00 ; Phase 042 43 LDI YH, 0x4144 LDI YL, 0x55 ; Phase +85 (約120度位相差)45 46 ; --- メインループ ---47loop:48 ; データ読み出し (ロード & インクリメント)49 LD r16, X+50 LD r17, Y+51 52 ; PWM更新53 OUT OCR0AL, r16 ; PB054 OUT OCR0BL, r17 ; PB155 56 ; --- ディレイ処理 (明滅を視認可能にする) ---57 ; 8MHz動作時、約6ms程度のディレイ58 LDI r19, 64 ; 外側ループカウンタ59delay_outer:60 LDI r20, 255 ; 内側ループカウンタ61delay_inner:62 DEC r2063 BRNE delay_inner ; r20 != 0 ならループ64 DEC r1965 BRNE delay_outer ; r19 != 0 ならループ66 67 ; ポインタ補正 (256バイトループ)68 ; X+, Y+で下位バイトがオーバーフロー(FF->00)すると上位バイト(XH/YH)が69 ; インクリメント(41->42)されてしまうため、強制的に0x41に戻す70 LDI r18, 0x4171 MOV XH, r1872 MOV YH, r1873 74 RJMP loop75 76; --- 波形データ (256バイト) ---77.org 0x0080 ; Byte Address 0x010078SineTable:79 .db 0x7F, 0x82, 0x85, 0x88, 0x8B, 0x8F, 0x92, 0x9580 .db 0x98, 0x9B, 0x9E, 0xA1, 0xA4, 0xA7, 0xAA, 0xAD81 .db 0xB0, 0xB3, 0xB6, 0xB8, 0xBB, 0xBE, 0xC1, 0xC382 .db 0xC6, 0xC8, 0xCB, 0xCD, 0xD0, 0xD2, 0xD5, 0xD783 .db 0xD9, 0xDB, 0xDD, 0xE0, 0xE2, 0xE4, 0xE5, 0xE784 .db 0xE9, 0xEB, 0xEC, 0xEE, 0xEF, 0xF1, 0xF2, 0xF485 .db 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFB86 .db 0xFC, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE87 .db 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD88 .db 0xFC, 0xFB, 0xFB, 0xFA, 0xF9, 0xF8, 0xF7, 0xF689 .db 0xF5, 0xF4, 0xF2, 0xF1, 0xEF, 0xEE, 0xEC, 0xEB90 .db 0xE9, 0xE7, 0xE5, 0xE4, 0xE2, 0xE0, 0xDD, 0xDB91 .db 0xD9, 0xD7, 0xD5, 0xD2, 0xD0, 0xCD, 0xCB, 0xC892 .db 0xC6, 0xC3, 0xC1, 0xBE, 0xBB, 0xB8, 0xB6, 0xB393 .db 0xB0, 0xAD, 0xAA, 0xA7, 0xA4, 0xA1, 0x9E, 0x9B94 .db 0x98, 0x95, 0x92, 0x8F, 0x8B, 0x88, 0x85, 0x8295 .db 0x7F, 0x7C, 0x79, 0x76, 0x73, 0x6F, 0x6C, 0x6996 .db 0x66, 0x63, 0x60, 0x5D, 0x5A, 0x57, 0x54, 0x5197 .db 0x4E, 0x4B, 0x48, 0x46, 0x43, 0x40, 0x3D, 0x3B98 .db 0x38, 0x36, 0x33, 0x31, 0x2E, 0x2C, 0x29, 0x2799 .db 0x25, 0x23, 0x21, 0x1E, 0x1C, 0x1A, 0x19, 0x17100 .db 0x15, 0x13, 0x12, 0x10, 0x0F, 0x0D, 0x0C, 0x0A101 .db 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x03102 .db 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00103 .db 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02104 .db 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09105 .db 0x0A, 0x0C, 0x0D, 0x0F, 0x10, 0x12, 0x13, 0x15106 .db 0x17, 0x19, 0x1A, 0x1C, 0x1E, 0x21, 0x23, 0x25107 .db 0x27, 0x29, 0x2C, 0x2E, 0x31, 0x33, 0x36, 0x38108 .db 0x3B, 0x3D, 0x40, 0x43, 0x46, 0x48, 0x4B, 0x4E109 .db 0x51, 0x54, 0x57, 0x5A, 0x5D, 0x60, 0x63, 0x66110 .db 0x69, 0x6C, 0x6F, 0x73, 0x76, 0x79, 0x7C, 0x7F機能ごとの解説
Note: 以下の解説は ATtiny4/5/9/10 - Complete Datasheet に基づいています。
プログラムは大きく分けて以下の6つのブロックで構成されています。
- クロック設定:
ATtiny10はデフォルトで内蔵発振8MHzを8分周した1MHzで動作します。PWM周波数を可聴域より高くし、かつ滑らかにするために、保護レジスタ(
CCP)を解除して分周なしの8MHzで動作するように設定しています。 - スタックポインタ設定:
スタックはサブルーチン呼び出し時の戻りアドレスや、一時的なデータ退避に使用されるメモリ領域です。
SPHとSPLでスタックの先頭アドレス(RAMEND)を設定します。今回のプログラムではサブルーチンを使用していませんが、初期化として設定しておくのが一般的です。 - I/O設定:
DDRBレジスタを設定し、PB0とPB1ピンを出力モードにします。ATtiny10ではPB0がOC0A出力、PB1がOC0B出力に対応しています。PB2はDDRBのビット2が0のままであるため入力(ハイインピーダンス)となり、出力されません。 - PWM(タイマー)設定: タイマー機能でPWM波形を自動生成します。今回はPhase Correct PWMモードを使用しており、カウントアップとダウンを繰り返す(三角波)ため、周波数は半分になりますが位相が揃いやすい特徴があります。
- メインループ:
メモリ上の正弦波データを順番に読み込み、PWMの明るさ設定レジスタ(
OCR0AL/BL)に書き込みます。 - ディレイ処理: LEDの明滅を人間の目で視認できるように、ネストしたループで約6ms程度の待ち時間を作っています。これにより正弦波1周期が約1.5秒になります。
アセンブラディレクティブとメモリマップの解説
ATtiny10のアセンブラコードを理解する上で、最もつまずきやすい「アドレス」の概念について補足します。
| ディレクティブ | 意味 | 詳細解説 |
|---|---|---|
| .device | 対象マイコン指定 | ATtiny10のメモリマップ定義を読み込みます。 |
| .cseg | コードセグメント | Flashメモリ(プログラム領域)への配置を指示します。 |
| .org | 配置アドレス指定 | .org 0x0080 は「ワードアドレス」を指定しています。AVRの命令は16bit単位なので、バイトアドレスに換算すると 0x0100 になります。 |
| .db | データ定義 | 正弦波テーブル(256バイト)をFlashに埋め込みます。 |
なぜ LD 命令でFlashが読めるのか?
通常のAVRマイコン(ATmega328Pなど)では、Flashメモリを読むために専用のLPM命令が必要です。
しかし、ATtiny10はデータ空間にFlashメモリがマッピングされているという特殊な構造を持っています。
- データメモリ空間 0x4000番地 から先に、Flashメモリの中身がそのままコピー(マッピング)されています。
- そのため、SRAMを読むのと同じ
LD命令を使って、アドレスに 0x4000 を足すだけでFlashデータを読み出せます。
計算式:
Flash先頭オフセット (0x4000) + データ配置場所 (0x0100) = 0x4100
これが、コード中のポインタ初期化で 0x4100 を設定している理由です。
ラベルについて
RESET:やloop:、SineTable:はラベルと呼ばれ、その位置のアドレスに名前を付けるものです。RJMP loopのようにジャンプ先を分かりやすく指定でき、コードの可読性が向上します。
使った命令の解説
アセンブリ言語は命令の羅列です。このプログラムで使う主要な命令は7つだけ。これさえ分かればコードが読めます!
| 命令 | 正式名称 | 意味 | 意訳 |
|---|---|---|---|
| LDI | Load Immediate | Rd = K | 「箱(レジスタ)に数字を入れる」LDI r16, 0x03 は r16という箱に3を入れる命令。 |
| OUT | Out to I/O | I/O(A) = Rr | 「ハードウェアの設定を変更する」 レジスタの値を、設定用の場所(I/O)に書き込む。 |
| LD | Load Indirect | Rd = (X) | 「ポインタが指す場所のデータを読む」 Xポインタ(住所)にあるデータを取得。 X+と書くと「読んだ後に住所を1つ進める」動作になる。 |
| MOV | Copy Register | Rd = Rr | 「箱の中身をコピーする」 あるレジスタの値を別のレジスタにコピーする。 |
| DEC | Decrement | Rd = Rd - 1 | 「1つ減らす」 レジスタの値を1減算する。ディレイループのカウンタに使用。 |
| BRNE | Branch if Not Equal | if (Z=0) PC += k + 1 | 「0じゃないならジャンプ」 直前の計算結果が0でなければ指定ラベルへジャンプ。ループの継続判定に使用。 |
| RJMP | Relative Jump | PC = PC + k + 1 | 「ジャンプする」RJMP loop で、loopというラベルの場所へ戻る。無限ループを作成。 |
使った機能レジスタの解説
データシートに基づき、各ビット設定の意味を正確に解説します。
-
CCP (Configuration Change Protection): 誤動作防止用の保護解除レジスタ。書き込みキー
0xD8を書き込んだ直後の 4クロックサイクル以内 に限り、重要レジスタ(CLKPSRなど)の変更が許可されます。Bit 7 6 5 4 3 2 1 0 Name CCP7 CCP6 CCP5 CCP4 CCP3 CCP2 CCP1 CCP0 Set 1 1 0 1 1 0 0 0 -
CLKPSR (Clock Prescaler Register): システムクロックの分周比設定。
0x00を書き込むことで分周比1(8MHz直結)となります。Bit 7 6 5 4 3 2 1 0 Name - - - - CLKPS3 CLKPS2 CLKPS1 CLKPS0 Set 0 0 0 0 0 0 0 0 -
TCCR0A (Timer/Counter Control Register A): 設定値
0xA1(1010 0001) の内訳:Bit 7 6 5 4 3 2 1 0 Name COM0A1 COM0A0 COM0B1 COM0B0 - - WGM01 WGM00 Set 1 0 1 0 0 0 0 1 COM0A1:0 = 10: OC0A一致でLow、BOTTOMでHigh(非反転動作)。COM0B1:0 = 10: OC0B一致でLow、BOTTOMでHigh(非反転動作)。WGM01:0 = 01: PWM, Phase Correct, 8-bit の下位ビット設定。
-
TCCR0B (Timer/Counter Control Register B): 設定値
0x01(0000 0001) の内訳:Bit 7 6 5 4 3 2 1 0 Name ICNC0 ICES0 - WGM03 WGM02 CS02 CS01 CS00 Set 0 0 0 0 0 0 0 1 WGM03:2 = 00: モード設定の上位ビット。Aと合わせてモード1(Phase Correct)になります。CS02:0 = 001: クロック源を分周なしで使用。
-
OCR0AL / OCR0BL (Output Compare Register): 8bitのコンペアレジスタ。タイマーの値とこのレジスタの値が一致した瞬間に、対応するピン(OC0A=PB0 / OC0B=PB1)の出力が反転します。これがPWMのパルス幅になります。
-
DDRB (Data Direction Register B): ポートBの各ピンを入力(0)にするか出力(1)にするかを決めるレジスタ。
0x03(=0b00000011)を設定することで、PB0とPB1を出力に設定しています。Bit 7 6 5 4 3 2 1 0 Name - - - - DDB3 DDB2 DDB1 DDB0 Set 0 0 0 0 0 0 1 1
AVR特有の X, Y, Z ポインタの解説
ATtiny10はレジスタベースのアーキテクチャですが、メモリ間接アクセス(ポインタ)が強力です。
16bitポインタの構造
8bitマイコンで16bitのアドレス(0x4000〜)を扱うため、2つの8bitレジスタを連結して使用します。
注意: ATtiny10は「Reduced AVR Core」を採用しており、汎用レジスタは r16〜r31 の16個のみです(通常のAVRは r0〜r31 の32個)。そのため、ポインタレジスタもこの範囲から使用されます。
- X ポインタ: r27(XH) : r26(XL) — 汎用的なデータアクセスに使用。今回のコードでは正弦波テーブルの読み出しに使用しています。
- Y ポインタ: r29(YH) : r28(YL) — Xと同様に汎用的なデータアクセスに使用。複数のデータ列を同時に扱う場合に便利です。
- Z ポインタ: r31(ZH) : r30(ZL) —
LPM(Load Program Memory)命令でFlash読み出しに使える唯一のポインタ。ただしATtiny10ではLD命令でもFlashにアクセスできるため、今回は使用していません。
これらのポインタは、配列やテーブルを順番に読み書きする処理で特に威力を発揮します。
オートインクリメント機能
コード中の LD r16, X+ は「ポストインクリメント付きロード」と呼ばれる動作をします。1命令で以下の2つを同時に行います。
- ロード: Xポインタが指す番地(0x4100)のデータを r16 にコピー。
- インクリメント: Xポインタの値(0x4100)を +1 して 0x4101 に更新。
これにより、ループ内でポインタを自分で足し算する命令を書く必要がなくなり、コードサイズが削減され高速化します。
; XH(r27)に0x41, XL(r26)に0x00を入れる
LDI XH, 0x41
LDI XL, 0x00
; これで Xペア は「0x4100」という16bitのアドレスを指差している状態になる
おわりに
今回は、ATtiny10の環境構築手順と、前回のLTでは触れられなかったアセンブリコードの詳細について解説しました。
レジスタ操作やポインタなど、少しとっつきにくい部分もあったかと思いますが、「命令が上から順に実行され、ハードウェアが動く」というマイコンならではの挙動を実感していただけたなら嬉しいです。
これでPWM制御ができるようになり、イルミネーション完成へ一歩近づきました。ここからソフトウェアPWMも組み合わせた3色LED制御や、他のLED制御をしているマイコンとの通信などを組み合わせることにより高度なイルミネーションにすることができます。
私は「マイコン間通信」の実現に向けて、引き続き勉強を進めていこうと思います。
皆さんもぜひATtiny10を使った小さな電子工作に、挑戦してみてください!
TUT (powered by LinuxClub) Advent Calendar 2025の次回担当は、kash / Hytus(@KashEight)です。