Help us understand the problem. What is going on with this article?

Raspberry Pi でAVRマイコンのシグネチャーバイトを読み出す

More than 1 year has passed since last update.

C言語でGPIOを制御して、AVRマイコンをシリアルプログラミングモードにします。シグネチャーバイト(チップの種類固有の値)を読み取ってみましょう。

Raspberry Pi で、AVR書き込みプログラムを作成しようと思っている方が最初につまずくのが、AVRマイコンから何の反応も返ってこなくて、通信できているかわからないケースでしょう。最初のシグネチャーバイトの読み取りさえ成功すれば、あとは、データシートのコマンド表を見ながら、チップの消去や、書き込み、読み取りを実装することができます。

配線

Raspberry Pi とAVRマイコンをつなぎます。

board.png

(2019-07-14) この図には間違いがります。図中でMOSIとMISOが逆になっています。ソースコードでは、「#define ISP_MISO 2」「#define ISP_MOSI 3」と定義されており、こちらが正解です。GPIO2はMISO、GPIO3はMOSIにつなぐ必要がありますので、図中の青と緑の線は逆に接続してください。

wiring.jpg

作業ディレクトリ

名前は何でも良いですが、とりあえず、avrsigということにします。

$ mkdir avrsig
$ cd avrsig

GPIO制御ライブラリ

下記サイトで公開されているBCM2835ライブラリを用いて、GPIOを制御します。
http://www.airspayce.com/mikem/bcm2835/

$ wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.52.tar.gz
$ tar zxvf bcm2835-1.52.tar.gz

中に含まれている src ディレクトリを確認します。

pi@raspberrypi:~ $ ls bcm2835-1.52/src/
bcm2835.c  bcm2835.h  Makefile.am  Makefile.in  test.c

このうち bcm2835 で始まるファイルを、作業ディレクトリにコピーします。

$ cp bcm2835-1.52/src/bcm2835.* avrsig

メインプログラム

次のようなファイルを作成します。

main.c
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include "bcm2835.h"

#define ISP_MISO   2
#define ISP_MOSI   3
#define ISP_SCK    4
#define ISP_RESET 14

struct Signature {
    uint8_t a, b, c;
};

struct Fuse {
    uint8_t l, h;
};

void usleep(unsigned int us)
{
    struct timespec ts;
    ts.tv_sec  = (time_t)(us / 1000000);
    ts.tv_nsec = (long)(us % 1000000) * 1000;
    nanosleep(&ts, NULL);
}

void msleep(unsigned int ms)
{
    struct timespec ts;
    ts.tv_sec  = (time_t)(ms / 1000);
    ts.tv_nsec = (long)(ms % 1000) * 1000000;
    nanosleep(&ts, NULL);
}

int digitalRead(int pin)
{
    return bcm2835_gpio_lev(pin);
}

void digialWrite(int pin, int val)
{
    bcm2835_gpio_write(pin, val);
}

uint8_t spi_transfer(uint8_t c)
{
    int i;
    for (i = 0; i < 8; i++) {
        digialWrite(ISP_MOSI, c & 0x80);
        digialWrite(ISP_SCK, HIGH);
        usleep(100);
        c <<= 1;
        if (digitalRead(ISP_MISO) != LOW) {
            c |= 1;
        }
        digialWrite(ISP_SCK, LOW);
        usleep(100);
    }
    return c;
}

uint8_t transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
{
    spi_transfer(a);
    spi_transfer(b);
    spi_transfer(c);
    return spi_transfer(d);
}

void waitProgramming()
{
    while (transaction(0xf0, 0, 0, 0) & 1) {
        msleep(1);
    }
}

void reset()
{
    bcm2835_gpio_fsel(ISP_MISO, BCM2835_GPIO_FSEL_INPT);
    bcm2835_gpio_fsel(ISP_MOSI, BCM2835_GPIO_FSEL_INPT);
    bcm2835_gpio_fsel(ISP_SCK, BCM2835_GPIO_FSEL_INPT);
    bcm2835_gpio_fsel(ISP_RESET, BCM2835_GPIO_FSEL_OUTP);

    digialWrite(ISP_RESET, LOW);
    msleep(10);
    digialWrite(ISP_RESET, HIGH);

    bcm2835_gpio_fsel(ISP_RESET, BCM2835_GPIO_FSEL_INPT);
}

void enterProgrammingMode()
{
    bcm2835_gpio_fsel(ISP_MISO, BCM2835_GPIO_FSEL_INPT);
    bcm2835_gpio_fsel(ISP_MOSI, BCM2835_GPIO_FSEL_OUTP);
    bcm2835_gpio_fsel(ISP_SCK, BCM2835_GPIO_FSEL_OUTP);
    bcm2835_gpio_fsel(ISP_RESET, BCM2835_GPIO_FSEL_OUTP);

    digialWrite(ISP_RESET, LOW);
    digialWrite(ISP_SCK, LOW);
    msleep(20);
    digialWrite(ISP_RESET, HIGH);
    usleep(100);
    digialWrite(ISP_RESET, LOW);
    msleep(50);

    transaction(0xac, 0x53, 0x00, 0x00);
}

struct Signature readSignature()
{
    struct Signature sig;
    sig.a = transaction(0x30, 0x00, 0x00, 0x00);
    sig.b = transaction(0x30, 0x00, 0x01, 0x00);
    sig.c = transaction(0x30, 0x00, 0x02, 0x00);
    return sig;
}


struct Fuse readFuse()
{
    struct Fuse f;
    f.l = transaction(0x50, 0x00, 0x00, 0x00);
    f.h = transaction(0x50, 0x08, 0x00, 0x00);
    return f;
}

uint8_t readProgramL(int i)
{
    return transaction(0x20, 0x00, i, 0x00);
}

uint8_t readProgramH(int i)
{
    return transaction(0x28, 0x00, i, 0x00);
}

int main()
{
    bcm2835_init();

    enterProgrammingMode();

    struct Signature sig = readSignature();
    printf("Signature: %02x %02x %02x\n", sig.a, sig.b, sig.c);

    struct Fuse f = readFuse();
    printf("     Fuse: %02x %02x\n", f.h, f.l);

    reset();

    bcm2835_close();

    return 0;
}

コンパイル

Makefileを作成します。

all: avrsig

avrsig: main.o bcm2835.o
    cc $^ -o $@

メイクします。

$ make

実行

pi@raspberrypi:~/avrsig $ ./avrsig 
Signature: 1e 95 0f
     Fuse: ff e2

AVRマイコンのチップ型番ごとに異なるシグネチャーバイトが取得できます。どんな値かは、AVRマイコンのデータシートに記載されています。

AVR開発環境

raspbian の標準パッケージにコンパイラとライブラリが用意されていますので、Raspberry Pi だけでAVRマイコンの開発環境を構築できます。

$ sudo apt-get install gcc-avr avr-libc
soramimi_jp
C++とQtが好き。電子工作もやる。第一種情報処理技術者と第二種電気工事士を持ってる。ワンチップマイコンのファームウェアからPCのデスクトップアプリまで。PCより大規模なシステムは守備範囲外。うちの子かわいい(ドール)。40代独身おっさん(´・ω・`)
http://www.soramimi.jp/
AI-medical-service
近未来の内視鏡医療を実現する医療ベンチャー
https://www.ai-ms.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした