AVRマイコン

2025年9月26日 (金)

ATtinyのデータシートに「1/1023」が出現

ArduinoのA/D変換値(10bitなら0~1023)から
入力電圧を求めるときは「1/1024」でっせを
何度も言ってきました。
   トラ技にも書いたし。
ところが・・・
8ピンのAVRマイコン「ATtiny402」のデータシート
を見ていたら「1/1023」になっていたのです。

まずこれがArduino UNO R3のマイコンATmega328Pの
データシートでの記述。
正しく「1/1024」です。
T13_20250926090601

それがATtiny402(202~406まとめての)のデータシート
では「1/1023」と示されているのです。
T11_20250926090601

追跡しきってはいませんが、「アトメル」時代からあるチップは
正しく「1/1024」と。
「マイクロチップ」になってからできたチップが「1/1023」と
なっているような感じかと。

※追記 3・1/2桁電圧計IC(モトローラのMC14433)の資料から
大昔のデータシートを引っ張ってきました。
モトローラの3・1/2桁電圧計IC、BCDでの表示出力が±1999。
  ※関連
   ・1/2桁とは
   ・1/2桁とは 「セグメント説」
基準電圧が2.000Vだと±1.999Vがフルスケール。
0.2000Vだと±フルスケールは1999mVになります。
このあたりの関係、データシートではこのように
表現されています。

14433a
ごくあたりまえですが、このVref=2.000Vで
1.000Vが入力されたら
表示出力は1.000Vになります。
(1.000V ÷ 1.999) × Vref = 1.00050V
ではありません。
  出力桁外になる0.00050VがこのICで
  どういう挙動になるかは別問題。
(1.000V ÷ 2.000) × Vref = 1.000V
がまっとうな計算。
  Vrefがジャスト2.000Vじゃないとき、
  入力電圧に対して何Vが表示されるか
  の検証計算。

| | コメント (2)

2025年9月 9日 (火)

ATtiny402サンプル:"Wire.h"を使わずI2Cで液晶表示 AQM1602だと

ATtiny402サンプル:I2Cで液晶表示 SCL周波数を設定できるようにしたら
で使った液晶AC0802は、コントラストを外付け
ボリュームで調整します。

AQM1602Y-NLW(FLW、FLB)やAQM1602XA-RNは
内部レジスタの操作でコントラストが変わります。

電源電圧3.3Vなら内部ブースター回路をオンに
して、液晶の駆動電圧を上げるので、5Vで使う
時とで微妙にコントラストが変わりますが
両方とも「35」あたりでOKのようです。

バックライト付のAQM1602Y-FLW-FBWを試したのが
このページ。 ※ずいぶん前だぁ
 ・秋月電子16文字x2行のI2Cインターフェース液晶AQM1602Y

今回はATtiny402でバックライト無しの
AQM1602Y-RN-GBWを試してみました。
  電源電圧は3.3Vでこんな回路。
Sch21
VRを回すとコントラストが変わります。
Cc01_20250909165301

※制御スケッチ
  ・ダウンロード - lcd_test2a.zip
    ※BCD変換ルーチンを別ファイルにしてあります。

これで、
  スケッチが1537バイト(37%)
  グローバル変数が37バイト(14%)
というメモリー使用量。

"Wire.h”をやめたおかげでRAMへの圧迫が
取り除かれています。

初期化のところで、文字数と行数、SCL周波数、
電源電圧を設定します。

  LCD.begin(16, 2, 100, LCD_V3R3);
   // I2C液晶 ★wire.hは使わない
   // 液晶初期化 16文字x2行,100kHz,3.3V
   // (5V:LCD_V5R0,3.3VならLCD_V3R3に)

3.3Vならブースター回路をオン。
5Vならオフに。

tiny402の動作周波数はArduino IDEの画面で設定
します。
3.3V動作なら10MHzが最大。
Ide02

電源電圧5Vでは必ず電圧ブースターをオフにという
のが注意点です。
  LCD.begin()での電圧設定をLCD_V5R0
  にしたらオフになります。

Arduinoでのアナログ入力といえば「analogRead() 」ですが、
tiny402には連続変換モード(自由走行という表現)というのが
あって、変換を始めたらいつでも最新値を読み出せるのです。
  入力チャンネルを切り替えるとなると
  タイミングがちょっとややこしいけど。
累積加算の機能と合わせて、割り込みで処理しなくて
良いのでなかなか便利。

もうひとつ。
内蔵クロック32.768kHzベースのRTCタイマに付随する
PIT(Periodic Interrupt Timer)が、メインクロック周波数が
変わっても一定時間を数えてくれるので、これも便利。
  通常はF_CPUで動作クロックが分かるのですが、
  例えばこのサンプルでは0.25秒(1/4秒)サイクル
  でPITフラグが立つようにしています。
  メイン周波数が変わっても、一定タイミングが
  得られます。
    delay()を使わなくてもエエんです。

| | コメント (0)

ATtiny402サンプル:I2Cで液晶表示 SCL周波数を設定できるようにしたら

ATtiny402マイコン サンプル:I2Cで液晶表示(Wire.hを使わないで)
これの続き。

I2C液晶、スペックを見ると電源5VならSCL周波数は
400kHzに対応しています。
そこで・・・液晶の文字数・行数をセットするときに
SCL周波数をセットできるようにしてみました。

//  I2C液晶
LCD.begin(8, 2, 400); // 液晶初期化 8文字x2行,SCL=400kHz

設定処理はこんな具合。
  WIFビットのタイムアウトチェックは無くしました。

/*****  TWI 初期化      *****/
// _scl_frq(kHz)からTWI周波数を設定
// MBAUD = F_CPU/2/fSCL - 5
void i2c_lcd_acm0802_tn::twiInit()
{
int16_t d;
// TWI0.MBAUD = 50; // TWI SCL周波数設定
// CPUクロックから計算してみる
d = F_CPU / 1000; // CPU クロック周波数(kHz)
d = (d / 2 / _scl_frq) - 5; // F_CPU/2/fSCL-5
if(d < 0) d = 1; // 1~255
if(d > 255) d = 255;
TWI0.MBAUD = d; // TWI SCL周波数設定
TWI0.MCTRLA = 0b00000001;
// || ||||+----- ENABLE 主装置許可
// || |||+------ SMEN 簡便動作しない
// || |++------- TIMEOUT 使わない
// || +--------- QCEN 迅速指令 しない
// |+----------- WIEN 書き込み割り込み なし
// +------------ RIEN 読み込み割り込み なし
TWI0.MSTATUS = 0b00000001;
// ||||||++----- BUSSTATE アイドル状態に
// |||||+------- BUSERR
// ||||+-------- ARBLOST
// |||+--------- RXACK
// ||+---------- CLKHOLD
// |+----------- WIF
// +------------ RIF
}
/***** TWI 書込み送出開始 *****/
void i2c_lcd_acm0802_tn::twiStartW(uint8_t adrs)
{
TWI0.MADDR = adrs << 1; // アドレス 書き込みで(0)
while(!(TWI0.MSTATUS & TWI_WIF_bm)); // WIF=1を待つ
}
/***** TWI データ書き込み *****/
void i2c_lcd_acm0802_tn::twiWrite(uint8_t data)
{
TWI0.MDATA = data; // データ書き込み
while(!(TWI0.MSTATUS & TWI_WIF_bm)); // WIF=1を待つ
}
/***** TWI 送出終了 *****/
void i2c_lcd_acm0802_tn::twiStop()
{
TWI0.MCTRLB = TWI_MCMD_STOP_gc; // Stop Condition
}

メイン側の記述でSCL周波数が設定できてエエかな
っと思ったのですが、「割り算」が入るので、単純に
「TWI0.MBAUD」に値を書くだけの元のに比べると
「90バイト」ほど肥大してしまいました。

ここらは目をつぶってSCL周波数を設定できるほうが
便利になるかと。
  100kHz→400kHzにしたら液晶表示のための
  処理速度が1データの書き込み単位で4倍に。

※スケッチ全体の様子
  ・ダウンロード - lcd_test1a.zip
    上で示したのとはちょっと変えてます

※表示画面
At41
回路図はこの記事の
 ・ATtiny402マイコン サンプル:I2Cで液晶表示

| | コメント (0)

2025年9月 8日 (月)

ATtiny402マイコン サンプル:I2Cで液晶表示(Wire.hを使わないで)

ATtiny402マイコン サンプル:I2Cで液晶表示 この続き。

ATtiny402での液晶表示、ちょっとでも「軽く」する
(メモリ使用量を減らす)ため、"Wire.h"を使わない
液晶表示ルーチンを仕立ててみました。

■LCD_TEST0 : "Wire.h"を使った場合

// "Wire.h"を使ってのACM0802液晶テスト
// ATtiny402 20MHz Arduino IDE環境
// PA0 6pin UPDI
// PA1 4pin - SDA I2C液晶
// PA2 5pin - SCL I2C液晶
// PA3 7pin out
// PA6 2pin out
// PA7 3pin out
// ボードマネージャー:
// http://drazzy.com/package_drazzy.com_index.json
#include "Wire.h" // I2C ACM0802液晶
#include "i2c_lcd_acm0802.h" // LCD制御ヘッダーファイル
i2c_lcd_acm0802 LCD(0x3C); // LCD I2Cアドレスを設定
/***** SETUP *****/
void setup() {
cli(); // 割込禁止
PORTA.DIR = 0b11001000; //ポート出力指定
// || |||+---- PA0 6pin UPDI
// || ||+----- PA1 4pin in SDA
// || |+------ PA2 5pin in SCL
// || +------- PA3 7pin out
// |+---------- PA6 2pin out
// +----------- PA7 3pin out
// PIT 1秒タイミング
RTC.CLKSEL = 0b00000001;
// ++---- INT1K 1024Hz
RTC.CTRLA = 0b00000001;
// ||||| +---- RTCEN RTC周辺機能許可
// |++++------- CLK_RTC DIV1 1/1
// +----------- RUNSTBY
RTC.PITCTRLA = 0b01001001;
// |||| +-- PITEN
// ++++----- PERIOD 1/1024 →1秒
// I2C液晶
Wire.begin(); // I2C開始
LCD.begin(8, 2); // 液晶初期化 8文字x2行
}
/***** LOOP ******/
void loop() {
byte c = '0';
LCD.setCursor(0, 0); // LCD上段
LCD.strdisp("Test LCD"); // タイトル
while(1){
if(RTC_PITINTFLAGS & 0x01){ // 1秒経過
RTC_PITINTFLAGS = 1; // PIフラグクリア
LCD.setCursor(7, 1); // LCD右下段
LCD.write(c); // 0~9
c++;
if(c > '9') c = '0';
}
}
}

結果。
  スケッチが1523バイト(37%)
  グローバル変数が100バイト(39%)

~~~~~~~~~~~~~~~~~~~~~~~~~~
■LCD_TEST1 : "Wire.h"を使わない場合

// "Wire.h"を使わないACM0802液晶テスト
#include "i2c_lcd_acm0802_tn.h" // LCD制御ヘッダーファイル
// ★wire.hは使わない
i2c_lcd_acm0802_tn LCD(0x3C); // LCD I2Cアドレスを設定
/***** SETUP *****/
void setup() {
cli(); // 割込禁止
PORTA.DIR = 0b11001000; //ポート出力指定
// || |||+---- PA0 6pin UPDI
// || ||+----- PA1 4pin in SDA
// || |+------ PA2 5pin in SCL
// || +------- PA3 7pin out
// |+---------- PA6 2pin out
// +----------- PA7 3pin out
// PIT 1秒タイミング
RTC.CLKSEL = 0b00000001;
// ++---- INT1K 1024Hz
RTC.CTRLA = 0b00000001;
// ||||| +---- RTCEN RTC周辺機能許可
// |++++------- CLK_RTC DIV1 1/1
// +----------- RUNSTBY
RTC.PITCTRLA = 0b01001001;
// |||| +-- PITEN
// ++++----- PERIOD 1/1024 →1秒
// I2C液晶
// Wire.begin(); // I2C開始 ★wire.hは使わない
LCD.begin(8, 2); // 液晶初期化 8文字x2行
}
/***** LOOP ******/
void loop() {
byte c = 'A';
LCD.setCursor(0, 0); // LCD上段
LCD.strdisp("Test LCD"); // タイトル
while(1){
if(RTC_PITINTFLAGS & 0x01){ // PIT 1秒経過
RTC_PITINTFLAGS = 1; // PIフラグクリア
LCD.setCursor(7, 1); // LCD右下段
LCD.write(c); // A~Z
c++;
if(c > 'Z') c = 'A';
}
}
}

結果。
  スケッチが773バイト(18%)
  グローバル変数が14バイト(5%)

8文字×2行の液晶、1行目にタイトルを表示して
右下に1文字の数字(TEST0)あるいは大文字英字
(TEST1)を1秒サイクルでインクリメント。

例題の違いはWire.hを使うか使わないか。
TEST0の下請けルーチン、i2c_lcd_acm0802は
これまでどおりにWire.hとtwi.hで制御。

TEST1のi2c_lcd_acm0802_tnはtiny402の
TWIレジスタを直接操作。
手抜きで、I2Cの制御にエラーが生じても(ACKが来ない
ゾ)そこでストップさせずにそのまま最後まで進んじゃ
います。

その結果、Wire.h仕様のTEST0だと、
  スケッチが1523バイト(37%)
  グローバル変数が100バイト(39%)

それがTEST1だと
  スケッチが773バイト(18%)
  グローバル変数が14バイト(5%)
と、大幅に使用メモリが少なくなりました。
RAMの使用量を減らせたのが大きいかと。

スケッチと下請けルーチンはダウンロードで。(zip圧縮)

 ・ダウンロード - lcd_test0.zip Wire.h使用

 ・ダウンロード - lcd_test1.zip TWIレジスタ直書きで


TEST1(i2c_lcd_acm0802_tn)で使ったTWIレジスタ
のアクセス方法。

/********************************/
/* TWIモジュールのアクセス */
/********************************/
// ATtiny402のTWIハードウェアを制御
// 割り込みを使わなない
// タイムアウトチェックカウンタを設けて異常でも抜けるように
// 正しくACKが帰ってこない場合も処理を続行
/***** TWI 初期化 *****/
// TWI周波数を設定 100kHz
void twiInit(void )
{
TWI0.MBAUD = 100; // 20MHz/2/fSCL
// 100kHz→100
// 400kHz→25
TWI0.MCTRLA = 0b00000001;
// || ||||+----- ENABLE 主装置許可
// || |||+------ SMEN 簡便動作しない
// || |++------- TIMEOUT 使わない
// || +--------- QCEN 迅速指令 しない
// |+----------- WIEN 書き込み割り込み なし
// +------------ RIEN 読み込み割り込み なし
TWI0.MSTATUS = 0b00000001;
// ||||||++----- BUSSTATE アイドル状態に
// |||||+------- BUSERR
// ||||+-------- ARBLOST
// |||+--------- RXACK
// ||+---------- CLKHOLD
// |+----------- WIF
// +------------ RIF
}
/***** TWI 書込み送出開始 *****/
void twiStartW(uint8_t adrs)
{
uint16_t tt; // time out check counter
TWI0.MADDR = adrs << 1; // アドレス 書き込みで(0)
tt = 2000; // 2000 loop
while(tt){ // time out?
if(TWI0.MSTATUS & TWI_WIF_bm) break; // WIF=1を待つ
tt--;
}
}
/***** TWI データ書き込み *****/
void twiWrite(uint8_t data)
{
uint16_t tt; // time out check counter
TWI0.MDATA = data; // データ書き込み
tt = 2000; // 2000 loop
while(tt){ // time out?
if(TWI0.MSTATUS & TWI_WIF_bm) break; // WIF=1を待つ
tt--;
}
}
/***** TWI 送出終了 *****/
void twiStop(void)
{
TWI0.MCTRLB = TWI_MCMD_STOP_gc; // Stop Condition
}

 

| | コメント (1)

2025年9月 5日 (金)

ATtiny402マイコン サンプル:I2Cで液晶表示

ATtiny402マイコン サンプル:割り込みでシリアル出力
ATtiny402マイコン サンプル:RCサーボモータテスター
に続いて、あらたなATtiny402マイコンのサンプルです。
これらに、I2C液晶を追加してみました。

Sch01

※参:Arduino IDEの環境
Ide01

・シリアル出力を割り込みで。
  出力完了を待たなくても、次の仕事が
  できる。

・A/D変換データ取得を割り込みで。
  変換完了を待たなくても最近値を
  いつでも読める。

・1ms割り込みでタイマー。
  この中でA/D変換開始を指令。


液晶表示の様子
Tn11

ざっと、タイミングを見てもらいましょう。
上から
  PWM出力 50Hz(20ms)でサーボ用パルスを出力
  シリアル出力データ(9600BPS)
  I2C SCL 液晶表示
  I2C SDA  〃

01m

4文字+6文字の液晶表示を行った後、シリアルデータを出力。
2msの時間待ちをしてから2文字を表示。
シリアル出力が割り込みで処理されるので、
2ms待ちと2文字表示が、シリアル出力完了を待たなくても
処理が進んでいます。

さて、なんとかしたいのが液晶表示のためのI2Cアクセス。
「Wire」「twi」ライブラリを使うので複雑になっています。
液晶表示だけなら書くだけ。
余計な処理はいらないので、もっと短くシンプルに
できるはず。

※参考
I2C液晶のアクセス、割り込み処理で遅れる原因らしきもの
I2C液晶のアクセス、割り込みで処理しないようにすると

Arduino UNO R3のI2C制御とATtiny402の制御が
異なるので、ATmega328用のプログラムは動きません。
もうちょい勉強です。

~~~~~~~~~~~~~~~~
  超低速2相パルス発生回路・ケース入れ で、
  I2C液晶表示をwireライブラリを使わない
  ようにしたら(wireの中からtwiを呼んでいる)、
  プログラムのサイズが1.8kバイトほど減少。
  RAMエリアも200バイトほど減りました。
~~~~~~~~~~~~~~~~
てな具合なので、なんとかしたいです。

※バックアップ代わりに今回のスケッチ
  液晶表示処理は別ファイルになってます
   ・ダウンロード - lcd_pwm_txint0.zip


※注意:I2Cのプルアップ抵抗
 ・秋月の液晶表示器 ACM0802C-NLW-BBW-IIC、I2Cのプルアップ抵抗
モジュールに2.2kΩのプルアップ抵抗が内蔵されています。

※続き
 ・ATtiny402マイコン サンプル:I2Cで液晶表示(Wire.hを使わないで)
   プログラムエリアとRAMエリアを縮小できます。

 ・ATtiny402サンプル:I2Cで液晶表示 SCL周波数を設定できるようにしたら


| | コメント (0)

2025年7月29日 (火)

ATtiny402マイコン サンプル:割り込みでシリアル出力

Arduino 環境でのATtiny402。
UNO R3と同じようにSerial.beginとSerial.print
を使えばシリアル入出力が可能です。

しかし・・・なにせROMが4kバイトしかありません。
できるだけメモリーを節約したい・・・
ということで、
 ・シリアル出力だけで受信はいらない。
 ・でも出力待ちはイヤ。
  出力したらすぐ戻ってくるように割り込み
  で処理したい。
こんなときのサンプルです。

/********************************/
/* 割り込みでシリアル送信を */
/********************************/
// 9600BPSでシリアル出力 受信はなし
// 1秒ごとに2chのA/D値をシリアル出力
/***** タイマデータ *****/
volatile byte tm_10ms; // 10msダウンカウントタイマ
/***** タイマーTCB0周期割り込み *****/
// 1ms割り込み
ISR(TCB0_INT_vect)
{
static byte c1; // 10msカウンタ
TCB0.INTFLAGS = 1; // 割込要求クリア
ADC0_COMMAND = 1; // A/D変換開始指令
VPORTA.OUT |= (1 << 3); // PA3 H (!!!) 7pin
c1++; // 10msチェック
if (c1 >= 10) {
c1 = 0;
if (tm_10ms) tm_10ms--; // 10msダウンカウント
}
}
/**** A/D データ *****/
// A/D変換チャンネル
const byte ad_mpx[] = {
0b00000001, // AIN1:PA1 4pin
0b00000010, // AIN2:PA2 5pin
};
// A/Dデータ(2ch)
volatile word ad_15b[2]; // A/D変換データ 0~32736(32回加算)
// 割込で書き込み
/***** A/D割り込み処理 *****/
ISR(ADC0_RESRDY_vect)
{
static byte ch; // A/D変換チャンネル(ch0,1)
ad_15b[ch] = ADC0_RES; // A/D (0~1023*32) 15bitデータ
ch++; // 次変換チャンネル
if (ch >= 2) ch = 0; // 0に戻す
ADC0.MUXPOS = ad_mpx[ch]; // A/D入力MPX切り替え
VPORTA.OUT &= ~(1 << 3); // PA3 L (!!!) 7pin
}

/***** シリアル出力バッファ *****/
char str_bff[16]; // 文字出力バッファ
/***** 送信割り込みデータ ******/
volatile char tx_bff[32]; // 送信割り込み文字バッファ
volatile byte tx_rdp; // 送信 読み出しポインタ
volatile byte tx_wrp; // 送信 書き込みポインタ
volatile byte tx_cnt; // 送信 データ数
/***** シリアル送信割り込み *****/
// 送信完了で起動
ISR(USART0_TXC_vect)
{
USART0.STATUS = USART_TXCIF_bm; // 送信完了解除
if(tx_cnt == 0){ // バッファに残データ無し
USART0.CTRLA &= ~USART_TXCIE_bm; // 送信完了割り込みオフに
}
else{ // バッファにデータあり
USART0.TXDATAL = tx_bff[tx_rdp]; // 1文字送信
tx_rdp++; // ポインタ+1
if(tx_rdp >= sizeof(tx_bff)){ // 最終?
tx_rdp = 0; // 先頭に
}
tx_cnt--; // データ数-1
}
}
/***** シリアル送信可チェック *****/
// 1:送信可 0:送信できない(バッファいっぱい)
byte txx(void)
{
byte cnt;
cli(); // 割込禁止に
cnt = tx_cnt; // 送信バッファ内データ数
sei();
if(cnt >= sizeof(tx_bff)) return 0; // 送信不可
else return 1; // 送信OK
}
/***** シリアル出力 *****/
void tx(char c)
{
while(!txx()); // 送信OK待ち
// 初めてならいきなり出力
// 2回目以降はバッファに書き込む
cli(); // 割込禁止に
if(!(USART0.CTRLA & USART_TXCIE_bm)){ // 初めての送信
USART0.CTRLA |= USART_TXCIE_bm; // 送信割り込みon
USART0.TXDATAL = c; // 1文字直接送信
}
else{ // 送信継続中
tx_bff[tx_wrp] = c; // 1文字書き込み
tx_wrp++; // 書き込みポインタ+1
if(tx_wrp >= sizeof(tx_bff)){ // 最終?
tx_wrp = 0; // 先頭に
}
tx_cnt++; // データ数+1
}
sei(); // 割込有効に
}
/***** 文字列出力 *****/
void txstr(const char *s)
{
while (*s != '\0') { // Nullまで
tx(*s); // 1文字出力
s++; // 次文字
}
}

/***** SETUP *****/
// 20MHzクロック
void setup()
{
cli(); // 割り込み禁止に
PORTA.OUT = 0b01000000; //ポート出力
PORTA.DIR = 0b11001000;
// || |||+---- PA0 6pin UPDI
// || ||+----- PA1 4pin in AIN1
// || |+------ PA2 5pin out AIN2
// || +------- PA3 7pin out
// |+---------- PA6 2pin out TXD
// +----------- PA7 3pin out
// タイマーA0, 分割モードで初期化されるので16bitモードに
TCA0.SPLIT.CTRLA = 0; // タイマー停止
TCA0.SPLIT.INTCTRL = 0; // 割り込みなしに
PORTMUX.CTRLC = 0; // TCAポート多重切り替えなしに
// タイマーB0 1msタイマー
TCB0.CCMP = 20000 - 1; // 20MHz/20000=1kHz
TCB0.CTRLB = 0b00000000;
// ||| +++---- CNTMODE 周期割り込み
// ||+-------- CCMPEN
// |+--------- CMPINT
// +---------- ASYNC
TCB0.CTRLA = 0b00000001;
// | | ||+---- ENABALE 有効
// | | ++----- CLKSEL 1/1 20MHz
// | +-------- SYNCUPD 同期
// +---------- RUNSTDBY
TCB0.INTCTRL = 1; // 割込許可
// A/D AIN1:PA1 4pin, AIN2:PA2 5pin
ADC0.CTRLA = 0b00000001;
// | ||+--- ENABLE 許可
// | |+---- FREERUN しない
// | +----- RESEL 10bit
// +---------- RUNSTDBY
ADC0.CTRLB = 0b00000101; // サンプル回数
// +++--- 32回 約680usの変換時間
ADC0.CTRLC = 0b01010011;
// ||| +++--- PRESC 20MHz/16=1.25MHz
// |++------- REFSEL VDD
// +--------- SMAPCAP 5PF
ADC0.CTRLD = 0; // 遅延なしに
ADC0.MUXPOS = 0b00000001; // MPX
// +++++--- AIN1 PA1
PORTA.PIN1CTRL = 0b00000100; // AIN1:PA1 4pin
PORTA.PIN2CTRL = 0b00000100; // AIN2:PA2 5pin
// | |+++---- ディジタル入力禁止
// | +------- pullupなし
// +----------- 反転I/Oなし
ADC0.INTCTRL = 0b00000001; // 割り込み
// |+---- RESRDY 変換完了割込許可
// +----- WCMP
// シリアル
USART0.CTRLA = 0; // 送信完了割り込みのセットはtx()で
USART0.CTRLB = 0b01000000;
// || ||||+-- MPCE
// || ||++--- RXMODE
// || |+----- ODME
// || +------ SFDEN
// |+-------- TXEN 送信有効
// +--------- RXEN 受信はしない
USART0.CTRLC = 0b00000011;
// |||||+++-- CHSIZE 8BIT
// ||||+----- SBMODE 1stop
// ||++------ PMODE Parity無し
// ++-------- CMODE 非同期USART
USART0.BAUD = 8333; // 4*20MHz/9600
sei(); // 割り込みイネーブル
}

/***** LOOP ******/
// 1秒ごとに2つのAD値をシリアル出力
void loop() {
byte i;
int d;
while (1) {
VPORTA.IN |= (1 << 7); // PA7 トグル (!!!) 3pin
if(tm_10ms == 0){ // タイムアップ?
tm_10ms = 100; // 1秒セット
for (i = 0; i < 2; i++) { // 2ch loop
cli(); // いったん割込禁止にして
d = ad_15b[i]; // A/D 15bit 32回累積加算値読み出し
sei();
d = d / 32; // 15bitを10bitに(0~1023)
// sprintf(str_bff, "%5d", d); // 5桁文字に
strcpy(str_bff, " ABC"); // ★
txstr(str_bff); // 文字列出力
}
txstr("\r\n"); // CR+LF
}
}
}

 

sprintfを使わなければROMが782バイト、RAMが58バイト
sprintf利用でROM 2559バイト
Serial.begin、Serial.printだとROM 1823バイトなので
ずいぶん軽量化しているかと。

もちろんArduino環境ではなく、Microchip Studioでの
プログラムでも使えます。 
  (setupやloopじゃなく)

10進数値出力だけで良いのなら
ATtiny402マイコン サンプル:RCサーボモータテスター
で示したstrbcd()が役に立つかと。

ATtiny402の内蔵ハードウェア直叩きの例、
あとは液晶表示ルーチンあたりでしょか。

※注目点
・割り込みで処理されるデータ、可能なら1バイトに
 してしまい、cli()、sei()で囲まなくてよいように。
・でも、2バイトのA/D値やらシリアル出力関連
 レジスタを操作する時は割り込み禁止処理が必須。

| | コメント (0)

2025年7月25日 (金)

ATtiny402マイコン サンプル:RCサーボモータテスター

Arduino IDE下でのATtiny402、そのサンプルです。
 ・2つのボリュームをA/Dコンバータで入力。
 ・その値を元にRCサーボ用のPWMパルスを2ch出力。
 ・1秒ごとに2chの回転角をシリアル出力。
こんな回路です。
Servo_test
ソフト的には、
 ・PWM出力はTCAタイマーで。
   20MHzクロックを1/8して0.4usクロックで
   カウント。
 ・TCBタイマーで1msタイマー割り込み。
 ・A/D変換は割り込み処理で。
   32回累積させて15bit値で読み出し。
    analogReadは使わない。
 ・シリアル出力は独自ルーチンで。
    ArduinoのSerial.printは使わない。
    ただし、割り込み処理していないので
    文字出力中は出力ルーチンから抜け
    出せない。

Arduino環境ですが、ATtiny402を裸にして使っています。

/*********************************************/
/* 小型サーボモータテスト用パルス発生回路 */
/*********************************************/
// ATtiny402 20MHz Arduino IDE環境
// ボードマネージャー:
// http://drazzy.com/package_drazzy.com_index.json
// TCA0 20MHz/8=2.5MHz=0.4us
// サーボの周波数50Hz=20ms 20000/0.4=50000clk
// -90° 0.50ms 1250clk
// 0° 1.45ms 3625clk
// -90° 2.40ms 6000clk
#define SVP_PR 50000 // サーボ周波数clk数
#define SVP_M90 1250 // サーボ-90°位置clk
#define SVP_00 3625 // サーボ 0°位置clk
#define SVP_P90 6000 // サーボ+90°位置clk
/***** タイマーTCB0周期割り込み *****/
// 1ms割り込み
ISR(TCB0_INT_vect) {
TCB0.INTFLAGS = 1; // 割込要求クリア
ADC0_COMMAND = 1; // A/D変換開始指令
}
/**** A/D データ *****/
// A/D変換チャンネル
const byte ad_mpx[] ={
0b00000001, // AIN1:PA1 4pin
0b00000111, // AIN7:PA7 3pin
};
// A/Dデータ(2ch)
volatile word ad_15b[2]; // A/D変換データ 0~32736(32回加算)
// 割込で書き込み
word ad_10b[2]; // 10bit A/D値 0~1023
// mainで読み出し
// TCAデータ サーボの角度パルスを発生
volatile word *const TCA0CMP[]={
&TCA0.SINGLE.CMP0BUF, // WO0出力 PA3 0.4usクロック
&TCA0.SINGLE.CMP2BUF, // WO2出力 PA2
};
word tca_pwm[2]; // TCAに対するPWM設定値
// -90°~0°~+90°のデューティを設定
/***** A/D割り込み処理 *****/
ISR(ADC0_RESRDY_vect)
{
static byte ch; // A/D変換チャンネル
ad_15b[ch] = ADC0_RES; // A/D (0~1023*32) 15bitデータ
// 次変換チャンネル
ch++; // ch0,1だけ
if(ch >= 2) ch = 0; // 0に戻す
ADC0.MUXPOS = ad_mpx[ch]; // A/D入力MPX切り替え
}

/***** BCD文字出力処理 *****/
// BCD出力用文字バッファ
char bcd_bff[16]; // 16文字 終端のnull含めて
// longは10桁
/***** 桁指定BCD文字出力 *****/
// d:変換データ long値
// n:整数部文字数(-を含めて)
// p:小数部文字数(.は含まない)
// 数値は整数を入力 浮動小数点ではない
// 小数部は整数の基数が0.01などの時に用いる
// 12345が123.56を意味する時 (d,3,2)と指定
// -1234を-123.4と表示するときは(d,4,1)と-を含めた文字数に
// bcd_bffに入った文字の先頭アドレスを持ってリターン
char *strbcd(int32_t d, byte n, byte p)
{
byte i;
byte sgn = 0; // 符号フラグ
byte zr = 0; // ゼロデータ処理済みフラグ
char *s; // 0~9書込みバッファのアドレス
if(d < 0){ // マイナス?
d = -d; // +の値にして
sgn = 1; // -フラグをオン
}
i = n + p; // 文字数
if(p) i++; // 小数点あれば+1
s = bcd_bff + i; // バッファの最後尾
*s = '\0'; // 最後にnullをセット
// 小数部 '.'まで
if(p){ // 小数部あり
for(i = 0; i < p; i++){ // loop
if(d){ // 0でないときは計算
*--s = (byte)(d % 10) + '0'; // 下位桁から0~9に
d = d / 10; // 1/10して上位桁の処理
}
else{ // 0なら'0'を
*--s = '0';
}
}
*--s = '.'; // 小数点
}
// 整数部 上位ゼロサプレス
for(i = 0; i < n; i++){ // loop
if((i == 0) || // 1桁目あるいは
(d != 0)){ // ゼロ以外
*--s = (byte)(d % 10) + '0'; // 下位桁から0~9に
d = d / 10; // 1/10して上位桁の処理
}
else if((sgn != 0) && // ゼロでマイナス
(zr == 0)){ // -符号処理まだ
*--s = '-'; // マイナスを付加
zr = 1; // 始めてのゼロを処理した
}
else{ // 2桁目以降でゼロ
*--s = ' '; // ゼロサプレス
}
}
return s; // 文字列の先頭アドレスを持ってリターン
}

/***** シリアル出力 *****/
void tx(char c)
{
while(!(USART0.STATUS & USART_DREIF_bm)); // 送信できるまで待つ
USART0.TXDATAL = c; // 1文字出力
}
/***** 文字列出力 *****/
void txstr(const char *s)
{
while(*s != '\0'){ // Nullまで
tx(*s); // 1文字出力
s++; // 次文字
}
}

/***** SETUP *****/
void setup() {
cli();
PORTA.OUT = 0b01000000; //ポート出力
PORTA.DIR = 0b01001100;
// || |||+---- PA0 6pin UPDI
// || ||+----- PA1 4pin in AIN1
// || |+------ PA2 5pin out PWM WO2
// || +------- PA3 7pin out PWM WO0
// |+---------- PA6 2pin out TXD
// +----------- PA7 3pin in AIN7
// タイマーA0, 分割モードで初期化されるので16bitモードに
TCA0.SPLIT.CTRLA = 0; // タイマー停止
TCA0.SPLIT.INTCTRL = 0; // 割り込みなしに
PORTMUX.CTRLC = 0; // TCAポート多重切り替えなしに
TCA0.SINGLE.CTRLD = 0; // TCA0を16bitモードに
TCA0.SINGLE.PER = SVP_PR - 1; // 周期 20MHz/8/50000 = 50Hz(20ms)
TCA0.SINGLE.CMP0BUF = SVP_00; // WO0出力 PA3 0°位置 1.45ms
TCA0.SINGLE.CMP2BUF = SVP_00; // WO2出力 PA2
TCA0.SINGLE.CTRLB = 0b01010011;
// ||||+++----- WGM 1傾斜PWMモード
// |||+-------- ALUPD
// ||+--------- CMP0EN PA3 7pin 出力
// |+---------- CMP1EN PA1 4pin (AIN1)
// +----------- CMP2EN PA2 5pin 出力
TCA0.SINGLE.CTRLA = 0b00000111;
// |||+----- ENABLE 動作開始
// +++------ CLKSEL プリスケーラ1/8
// タイマーB 1msタイマー
TCB0.CCMP = 20000-1; // 20MHz/20000=1kHz
TCB0.CTRLB = 0b00000000;
// ||| +++---- CNTMODE 周期割り込み
// ||+-------- CCMPEN
// |+--------- CMPINT
// +---------- ASYNC
TCB0.CTRLA = 0b00000001;
// | | ||+---- ENABALE 有効
// | | ++----- CLKSEL 1/1 20MHz
// | +-------- SYNCUPD 同期
// +---------- RUNSTDBY
TCB0.INTCTRL = 1; // 割込許可
// A/D AIN1:PA1 4pin, AIN7:PA7 3pin
ADC0.CTRLA = 0b00000001;
// | ||+--- ENABLE 許可
// | |+---- FREERUN しない
// | +----- RESEL 10bit
// +---------- RUNSTDBY
ADC0.CTRLB = 0b00000101; // サンプル回数
// +++--- 32回 変換時間約0.6ms
ADC0.CTRLC = 0b01010011;
// ||| +++--- PRESC 20MHz/16=1.25MHz
// |++------- REFSEL VDD
// +--------- SMAPCAP 5PF
ADC0.MUXPOS = 0b00000001; // MPX
// +++++--- AIN1 PA1
PORTA.PIN1CTRL = 0b00000100; // AIN1:PA1 4pin
PORTA.PIN7CTRL = 0b00000100; // AIN7:PA7 3pin
// | |+++---- ディジタル入力禁止
// | +------- pullupなし
// +----------- 反転I/Oなし
ADC0.INTCTRL = 0b00000001; // 割り込み
// |+---- RESRDY 変換完了割込許可
// +----- WCMP
// シリアル
USART0.CTRLB = 0b01000000;
// || ||||+-- MPCE
// || ||++--- RXMODE
// || |+----- ODME
// || +------ SFDEN
// |+-------- TXEN 送信有効
// +--------- RXEN 受信はしない
USART0.CTRLC = 0b00000011;
// |||||+++-- CHSIZE 8BIT
// ||||+----- SBMODE 1stop
// ||++------ PMODE Parity無し
// ++-------- CMODE 非同期USART
USART0.BAUD = 8333; // (64*20MHz)/(9600/16)
sei();
}

/***** LOOP ******/
// 20ms周期でA/D値を読んでPWM値を設定
// 1秒ごとに2つの角度をシリアル出力
void loop() {
byte i;
int d;
byte cnt = 0; // 処理カウンタ 1秒をチェック
while(1){
if(TCA0.SINGLE.INTFLAGS & TCA_SINGLE_OVF_bm){ // TCA 1サイクル? (20ms)
TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm; // フラグクリア
for(i=0; i < 2; i++){ // 2ch
cli(); // 割込禁止にして
d = ad_15b[i]; // A/D 15bit 32回累積加算値読み出し
sei();
ad_10b[i] = d / 32; // 15bit値を10bitに
tca_pwm[i] = map(ad_10b[i], // 0~1023を
0, 1023, SVP_M90, SVP_P90); // -90°~+90°のPWM値に
*TCA0CMP[i] = tca_pwm[i]; // PWM設定
}
cnt++; // 20msごとに+1
}
if(cnt >= 50){ // 1秒経過
cnt = 0;
for(i=0; i < 2; i++){ // 2ch
d = map(ad_10b[i], // A/D値 0~1023を
0, 1023, -900, 900); // -90.0°~+90.0°
strbcd(d, 4, 1); // xxxx.x 6文字に
txstr(bcd_bff); // 文字列出力
}
txstr("\r\n"); // CR+LF
}
}
}

メモリーの使用量、こんな具合です。
  最大4096バイトのフラッシュメモリのうち、スケッチが
   1135バイト(27%)を使っています。
  最大256バイトのRAMのうち、グローバル変数が35バイト
   (13%)を使っていて、ローカル変数で221バイト使うことができます。

例えば、シリアル出力するためにSerial.begin()、Serial.print()を
使うと、
  フラッシュメモリ 1823バイト(44%)
  RAM 59バイト(23%)
となってしまいます。
さらに、sprintf(); で書式指定すると
  フラッシュメモリ 3014バイト(73%)
となり、処理プログラムのエリアを圧迫しはじめます。

「4kバイト:0x0000~0x0FFF」というプログラム領域、
昔なら「2732」(24ピンの紫外線消去ROM)です。

Arduinoの内部タイマとしてTCAが8bitの分割モードで
使われています。
これを16bitで使うには、という手順の参考になるかと。

A/Dコンバータの累積加算機能はありがたいかと。

※サンプルプログラムといえば「Lチカ」して
「動いたよ」というパターンが多いかと思います。
しかし・・・マイコンが持つ能力を引き出したいとき
(内蔵のハードウェアを堪能したい)は、出来合いの
ライブラリには頼れません。
ハードウェアの直叩きが必要です。

※関連
ATtiny402 備忘録
その後のMPLAB@Snap:Arduino IDEで使えるぞ
Arduinoから「タイマー0」を取り上げる(ユーザーが使う)
割り込みで処理させるwordデータの扱い
数値をBCD出力(表示)するルーチン #3



| | コメント (0)

2025年7月23日 (水)

ATtiny402 備忘録

ATtiny402、まだ本格的には使っていませんが、
ちょいとメモを残しておきます。
  8pinのだけじゃなくtinyAVR0系 AVR1系 AVR2系
  についてもあれこれと。

・Arduino IDEでAttiny402が使える。
  その後のMPLAB@Snap:Arduino IDEで使えるぞ
    ただし、そのままではArduinoの環境で
    動くようになるので、I/Oまわりを触ろうと
    すると注意が必要。

・書き込み方法がUPDIに。
  電源+GND+UPDIの3線だけでライタと接続。
    ATmega328Pだと6線が必要。
  しかし、UPDI線にスイッチをつないでもリセットはできない。
    30kΩくらいでプルアップされている。
  UPDI:PA0を出力にしても出力制御(H/L出力)はできない。
  しかし、入力はできる(ようだ)。
    この入力にパルスを与えた後はUPDI書き込みに
    失敗するのでいったん電源を再投入。

・I/Oレジスタのアクセス方法が変わった。
  Atmega328Pでは、ポートの入出力と初期H/L出力レベル、
  それとプルアップの有無をまとめて指定できた。
  ATtiny402では、VPORTに対して同様の操作はできるが、
  プルアップ抵抗をオンするには別の命令で指定しなけれ
  ばならない。

これまでは入出力とプルアップを同時に指定できた。
PORTB = 0b00110000; // out data, pull up
DDRB = 0b00001111; // portI/O
// |||||+---- PB0 out
// ||||+----- PB1 out
// |||+------ PB2 out
// ||+------- PB3 out
// |+-------- PB4 in (pull up)
// +--------- PB5 in (pull up)

ATtiny402だとプルアップは別命令で。
VPORTA.OUT = 0b11000000; // 出力データ
VPORTA.DIR = 0b01001100; // ポート入出力
// || |||+---- PA0 6pin in UPDI
// || ||+----- PA1 4pin in
// || |+------ PA2 5pin out
// || +------- PA3 7pin out
// |+---------- PA6 2pin out H出力
// +----------- PA7 3pin in 【pull upされない
PORTA.PIN7CTRL = PORT_PULLUPEN_bm; // PA7 pull upは別命令で

  出力にした入力ポートに1を書くと出力のH/Lが反転
  する操作はこれまでと同じよう可能。
  これはオシロで見るためのテスト的パルスを出すのに便利。

・さらばPROGMEM。 (PSTRやPGM_P、Fマクロ)
  Atmega328PではROMに置いてあるデータを読み出すのに、
  「LPM命令」しか使えなかった。
  このため、PROGMEM、PSTR、PGM_P、Fマクロを駆使して
  ROMエリアに固定データ(文字列を含む)を配置していた。
  ATtiny402では、「LD命令」でRAMのデータだけでなくROMの
  データも読めるようになり、LPMを使わなくてすむようになった。
  これでPROGMEMから開放されるのだ!

・AD変換で変換データの累積ができる。
  1回だけの10bit変換だけでなく、2、4、8、16、32、64回の
  自動的累積加算が設定できるようになった。
  64回にセットすると、10bitのAD値が64回加算され、最大値
  で65472のデータが得られる。
  ソフト的に加算平均しなくても、勝手に加算してくれる。

・どうしてもリセットしたいとき。
  ウオッチドッグを使ってのリセット操作だろう。
  プルアップ付きの入力ポート(これにPA0:UPDI線が使えれば
  エエんだが、どうだか)にスイッチを付け、押されたらloop
  を回してWDR命令の実行(このloop外のメインループでのWDR)
  を阻止してリセット。

・RSTCTRL.SWPRでもリセットできる。
  データシートのRSTCTRLを見ると、ソフトウェアリセット
  の機能を持っている。
    // Reset immdiately using software reset.
    inline void ResetViaSoftware() {
      _PROTECTED_WRITE(RSTCTRL.SWRR, 1);
    }
  これでリセット。

・PWM出力のデューティ、0でLを、maxでHを出力できる。
  Atmega328Pの偽AnalogWriteとおさらば。

・delayやmillisのためにタイマーTCAを8bit分割モードで使っ
 ている。(Arduino環境のとき)
 このためTCAを16bitで使いたいときは、とうぜん、delay、
 milllisは使えなくなる。

・RTC、PIT設定時の注意 《データシート 22.13~》
 RTC.CTRLA、RTC.CNT、RTC.PER、RTC.CMP、RTC.PITCTRLA
 これらのレジスタを操作する時は
 RTC.STATUSおよびRTC.PITSTATUSレジスタにある
 それぞれのbusyビットをチェック(0の確認)をすること。
 さもないと、うまいこと動かない。
   下記記事のように、RTCとPIT関連レジスタを触る
   ときはビジー待ちをチェックのこと。
 ・RTC機能付ATtiny RTCとPITの初期化注意点
 ・ATtiny1614に時計用水晶発振子をつなぐ

・ATtiny402はタイマAとBの2種類だけだが、
 ATtiny1614ではタイマDが増える。
 周波数カウンタではタイマBとタイマDが
 使えるのだが、両方ともキャプチャ信号が
 計数する入力クロックで刻まれている。
 このため、クロック信号が無い状態では
 キャプチャできない。
 周波数ゼロの状態を計られない。

・ATtinyを含め、AVRマイコンのデータシートなどの
 情報はここ。
  ・AVR日本語情報サイト

・14pinのtiny1604,1614,1624を比較。
  AVR0系:ATtiny1604のピン配列
1604
  AVR1系:ATtiny1614のピン配列
1614
  AVR2系:ATtiny1624のピン配列
1624

・14pinのtiny1604,1614,1624,3224の価格(デジキー調べ)
  ATtiny1604   SOP:@124
  ATtiny1614   SOP:@145
  ATtiny1624   SOP:@162
  ATtiny1624  SSOP:@148
  ATtiny3224   SOP:@159
  ATtiny3224  SSOP:@169
    ROM,RAMの大きな(32k/3k)ATtiny3224を買って
    おくほうが幸せになれる。
    UARTが2つ乗っているし。

・SSOP(0.65mm)はATtiny1624,3224だけ。
  SSOPを使うと、秋月の
   AE-TSSOP14 0.65mmピッチ表面実装用14ピン DIP変換基板
  が使えて、狭ピッチ(14pin DIP幅)で配線できる。

・tinyAVR2系は、12bitのタイマTCDが無いかわりに、
 2つのTCBを連結して、32bitタイマを構成できる。
   これは楽しみ!
 TCBのクロック入力はイベントで得ることができ、
 tinyAVR1のようにタイマTCAからもらうことを
 しなくてすむようになっている。 とデータシートから。


| | コメント (0)

2025年7月21日 (月)

その後のMPLAB@Snap:Arduino IDEで使えるぞ

あれこれネットをさまよっていたら、
 JH7UBCブログ
ATtiny402 ArduinoでLチカまで(2023-07-18)
USBシリアル変換器でATtiny402への書き込み(2023-07-23)
Arduinon IDEでATtiny402を手懐ける方法が出てきました。

その中で「書き込み装置の選択」にMPLAB SNAP(UPDI mode)
出ています。
うまく行くのかどうか分かりませんでしたが、
試してみると・・・書けました。

設定、確認するとことろ。
Ss12_20250721101601

  a.書き込み装置 MPLAB SNAP(UPDI mode)
  b.チップの種別 ATtiny402
  c.使用するクロック周波数
  d.milliesやdelayを使いたいならd.
  e.タイマー割り込みは要らないぜというのならe.

タイマーはタイマーAを8bit分割で使い、ベクタ番号9
のオーバーフロー割り込みで計時しています。

「e.」だと、この処理が無くなって、使用RAMバイト数
はゼロになって、ほぼ裸のTiny402が使えます。


たとえば、こんなテストスケッチ。

//  ATtiny402 : 20MHz, millis() micros()タイマーイネーブル
void setup() {
VPORTA.DIR = 0b11001110;
// || |||+---- PA0 6pin UPDI
// || ||+----- PA1 4pin
// || |+------ PA2 5pin
// || +------- PA3 7pin 20ms経過でトグル
// |+---------- PA6 2pin millis変化でトグル
// +----------- PA7 3pin loopでトグル
}

void loop() {
uint32_t ms, ms20, tnow;
tnow = millis(); // 現ms値
ms = ms20 = tnow;
while(1){
VPORTA.IN |= (1 << 7); // PA7 3pin トグル
tnow = millis(); // 現ms値
if(ms != tnow){ // ms値変化?
VPORTA.IN |= (1 << 6); // PA6 2pin トグル
ms = tnow;
}
if((tnow - ms20) >= 20){ // 20ms経過
VPORTA.IN |= (1 << 3); // PA3 7pin トグル
ms20 = tnow;
}
}
}

・loopでPA7をトグル
・millis()で1ms変化を調べてPA6をトグル。
・20ms経過を調べてPA3をトグル。

すると、こんな波形が出てきます。
Ms11a
もうちょい拡大すると・・・
Ms12a
「millis()値変化でトグル」が1msきっちりにならない
のに注意が必要です。
  Arduino UNO R3でもきっちり1msじゃ
  ありません。

| | コメント (0)

2025年7月16日 (水)

その後のMPLAB@Snap

UPDI」で書き込む新しいタイプのAVRマイコン、
  ・Microchip StudioでMPLAB@Snapが動かない
ということで、MPLAB@SnapはMicrochip Studioで
使うのはあきらめて、「MPLAB IPE」を使って
書いていました。

フラッシュメモリの書き込みはちゃんとできていたんですが、
困ったぞが「ヒューズビット」の書き込み。
MPLAB IPEでは、うまいこといかないのです。
 ・起動時のクロックを20MHz→16MHzにしたい
 ・BOD電圧を触りたい 1.8V→2.6V
など。

そこで・・・あれこれ検索すると
ATTINY202/402のFUSEビットをAVRDUDESSを使って書く方法
[Part2] ATTINY202への書き込みとプログラムをやっています!

AVRDUDESSが使えそうということで、試してみました。

起動するとMPLAB@Snapをそのまま認識してくれました。
Sn1

コンパイル結果のHEXファイルを読み込むようにして、
右下の追加コマンド。
 ・-x mode=avr    AVRモードにせよ
             これは必須!

 ・-U fuse2:w:0x01:m ヒューズ02の値を01に
          変更したいときだけ

とりあえずこれでMPLAB@Snapを使っています。

・書き込み装置選択画面
Sn2

| | コメント (0)

より以前の記事一覧