2020年5月3日日曜日

atmega328pbに追加されたピンを使ってみた


背景

atmega328pbとは、Arduino Unoなどに利用されるatmega328pというマイコンの後継機です。
atmega328pよりも低価格で低消費電力ながら使えるピンの数が増えています。

atmega328pbで増えたピンをどう呼び出せば使えるか気になったので、調べて使ってみました。
備忘録を兼ねて取り組んだ内容を記事として共有します。

今回検証するピン: PORTE0〜PORTE3

atmega328pのデータシートのピン配列はこちらです。


それに対してatmega328pbのデータシートのピン配列はこちらです。


赤字で示した部分、新しく追加されたPORTEのピンを利用してみます。

atmega328p -> atmega328p
GND -> PE0
VCC -> PE1
ADC6 -> PE2
ADC7 -> PE3

使ったもの

  • PlatformIOをインストールしたPC
    atmega328pb向けのプログラムをビルドしてライターに送信します。
  • AVRライター
    PCから送られてくるファームウェアをatmega328pbに書き込むための装置です。
    今回はProMicroにArduino as ISP書き込んだものを利用します。
  • atmega328pbを実装した基板
    今回は自作したものを使っています。
    atmega328pbが載った商品としては、発振子付きのボードがスイッチサイエンスで売られています。
  • ブレッドボード、はんだごて、はんだ、信号線、LED、抵抗、ホットメルト
    信号線を引き出して動作確認するのに使いました。

把握しているatmega328pb取扱時の注意点

atmega328pとは異なりフルスイングオシレーターが載っていないので、外部の振動子を利用する場合は水晶振動子ではなく発振子が必要

atmega328pbはプログラムは後位互換を保っていますが回路的にはこの変更があるため、外部の水晶振動子を利用する用途での置き換えは外部発振子を利用する回路に変更するなどの対応が必要です。
(ネットに水晶振動子で動いたという記事があったりしますが、自分が以前試した水晶振動子では駆動できませんでした。)

fuseのhighとexternalはatmega328pと異なる

atmega328pbのデータシートatmega328pのデータシートを比べると、external fuseの3bitでクロックの失敗検知機能の有無を設定できるようになり、high fuseの0-2bitは設定項目が「BOOTSZ」から「BODLEVEL」に変わっています。(BODLEVELはexternal fuseにもあるのにhigh fuseにも追加された意図を自分はまだ読み取れていません。)

今回内部発振子の周波数設定に扱うlow fuseは同じなので、highとexternalのfuseは工場出荷時の設定で利用します。
なお、外部に発振子を付けてない状態でヒューズを外部発振子利用モードに書き換えるとマイコンが動かなくなるので、書き込み時に設定できるヒューズの設定には注意が必要です。

プログラムの書き込み環境

回路

Arduino as ISPとして動かしているProMicroからプログラムの書き込み信号と給電を行い、ブレッドボード上のLEDで動作確認を行う回路です。


この回路では、ISPの信号線に繋がっているバネ付きピンを基板のISPパッドに押し付けることでプログラムを書き込みます。
(量産時の書き込みを楽にするための工夫です。)


各ピンを引き出しているパッドに線をはんだ付けして信号を引き出します。


はんだ付けしていても細い線は容易に剥がれるので、ホットメルトなどで取れないように補強することをお勧めします。


信号線はブレッドボードに引き出し、電位が高くなったらLEDが光るようにLEDと抵抗を接続しておきます。
また、GNDとVCCも引き出し、ProMicroからの給電を受けます。


PlatformIOの設定

PlatformIOでatmega328pb向けの環境を検索すると、「ATmega328PB」と「elektor_uno_r4」の2つのボード設定が見つかりました。

$ pio boards | grep 328PB
ATmega328PB                  ATMEGA328PB    16MHz        31.50KB   2KB     ATmega328PB
elektor_uno_r4               ATMEGA328PB    16MHz        31.50KB   2KB     Elektor Uno R4

前者はMiniCoreというボード情報を、後者はElektorLabsのボード情報を利用しています。
前者は15日前に更新があり開発が進んでいるようですが、後者は3年前(2017年)のコミットを最後に開発が止まっていて、後者のWireライブラリを試そうとするとコンパイルエラーが出たり不安定な印象なので、この記事では前者のMiniCoreが提供するAtmega328PBを利用します。

Arduino as ISPでatmega328pbにプログラムを書き込むために、platormino.iniを下記の設定にしました。
(platformio.iniでは、行の「;」以後はコメントです。)

platformio.ini
[env:ATmega328PB]
platform = atmelavr
board = ATmega328PB
framework = arduino
board_build.f_cpu = 8000000L
upload_protocol = stk500v1
upload_port = /dev/ttyACM0
upload_speed = 19200
upload_flags =
  -b$UPLOAD_SPEED
  -P$UPLOAD_PORT
  ; use internal 8MHz and not divide it by 8
  -Ulfuse:w:0xE2:m

Arduino as ISPを書き込んだArduinoが認識されるポートはPCによって異なると思うので、環境に合わせて変更してください。
upload_port = /dev/ttyACM0

 ATmega328PBもelektor_uno_r4も16MHz駆動が標準なので、board_build.f_cpuで駆動周波数を8MHzに変更しています。
board_build.f_cpu = 8000000L

low huseを内部クロックを利用して8MHzで動く設定にします。
  ; use internal 8MHz and not divide it by 8
  -Ulfuse:w:0xE2:m

上記の設定でプロジェクトのフォルダに移動し、Arduino as ISPの書き込みピンをatmega328pbに接続した状態で下記のコマンドを入力すると、プログラムを書き込めます。
pio run -t program

ポートレジスタで操作

「ATMega328PB」にはPORTEの定義が追加されているため、ポートレジスタを操作する下記のプログラムで、PORTE0-3の電位を変化せられました。

src/main.cpp
#include <Arduino.h>

void setup() {
  DDRE = 0b1111;
}

void loop() {
  PORTE = 0b0000;
  delay(1000);
  PORTE = 0b0001;
  delay(1000);
  PORTE = 0b0010;
  delay(1000);
  PORTE = 0b0100;
  delay(1000);
  PORTE = 0b1000;
  delay(1000);
}

LEDを順番に点灯できました。


digitalWriteで制御

MinCoreのピン設定を見てみると、PORTE0〜3が23〜26で定義されていました。


ということで、23〜26番ピンを制御するプログラムを作成して書き込みました。

src/main.cpp
#include <Arduino.h>

void setup() {
  pinMode(23, OUTPUT);
  pinMode(24, OUTPUT);
  pinMode(25, OUTPUT); // A6
  pinMode(26, OUTPUT); // A7
}

void loop() {
  digitalWrite(23, LOW);
  digitalWrite(24, LOW);
  digitalWrite(25, LOW);
  digitalWrite(26, LOW);
  delay(1000);
  digitalWrite(23, HIGH);
  delay(1000);
  digitalWrite(23, LOW);
  digitalWrite(24, HIGH);
  delay(1000);
  digitalWrite(24, LOW);
  digitalWrite(25, HIGH);
  delay(1000);
  digitalWrite(25, LOW);
  digitalWrite(26, HIGH);
  delay(1000);
}

digitalWriteを利用してもLEDを順番に点灯できました。
(表示しているgifは先ほどのものと一緒です。)


ちなみに、23〜26はPWM出力に対応していないようなので、analogWriteによるPWMの出力は試していません。

まとめ

PlatformIOでATMega328PBをボードとして利用することで、atmega328pbに追加されたPORTEを利用してLEDを点滅できました。
atmega328pに比べて制御可能なピンが4ピン増えたので、atmega328pではギリギリピンの数が足りなくて諦めたものがatmega328pbなら作れるかもしれません。

この後、PORTE0とPORTE1で使える2つ目のI2Cポートを使ってみました。
良ければこちらもご覧ください。

atmega328pbのI2Cポート2つを使ってみた

変更履歴

2020.05.10 atmega328pbのI2Cポートを利用した記事のリンクをまとめに追加しました。
2020.05.30 A6とA7の定義に関するMiniCoreの不具合は、miniCoreが更新されたことにより解消されたので、それに関する注意の記述を削除しました。

0 件のコメント :