2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Raspberry PiAdvent Calendar 2017

Day 5

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

Last updated at Posted at 2017-12-05

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
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?