スポンサーサイト

.-- -- スポンサー広告 comment(-) trackback(-)
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

AVR-USB(4)

.16 2010 AVR-USB comment(0) trackback(0)
DATA0/1をどうするかというのが前から結構気になってたんですが、良く考えたらホストがPID送ってくるのでそれでDATA0/1は分かるんですね。

というわけで今日は上の階層。USB_INITあたりを見てみます。Ref: Ch9

と思ったのですが、Ch9を見るとこの階層は電源投入時に送るdescriptorやUSB通信の設定の話で、パケットがきちんと送受されるようになってから見ればよさそうです。

# というかそろそろ英語だらけのデータシート見るの飽きてきた。そろそろ実際に何か動かして感触をつかまないと禁断症状が…

なので先に下層をアセンブリで実装することを考えます。

まずはアセンブリでどのくらいの機能までを実装するか考えます。

#include <avr/io.h>

int
main()
{
	uint8_t		i;
	
	boardInit();
	usbInit();
	for (;;) {
		if (receivedLen) {
			setLED();
		}
		for (i = 0; i < KEY_NUM; i++) {
			if (keyChanged(i)) {
				usbSendBuf[usbSenbLen++] = i;
			}
		}
		usbPoll();
	}
}
TopModuleをこんな感じに書けるようにusbInit, usbPollを実装します。 usbInit、usbPollともにもう少しCで細部まで書いて本当に細かい処理はアセンブリでやります。

アセンブリ関数としてどの辺まで用意するのか…

かなり悩みましたがとりあえずは最初のパケット(SOF)を受け取ってそれをLEDに表示するところまでやってみます。

PIN立ち上がり割り込み→SYNC→PID(=SOF)→FrameNumber, CRC-5(計16bit)→SE0状態
と送ってくるはずで、今回はSYNC field以外の3byteをbufferに放り込んでそのうちのPIDだけをLEDに表示します。

というわけで前に配線したボードを引っ張り出してきたのですが回路図が見つからない…
のでしかたなく配線を確認してboardInit関数を実装。
note:今回のテストボードの配線
PORDBLED(7:0)
PD1, 4, 5, 6sw(touch sensor)
PD0D-
PD2(=INT0)D+

CLK:12MHz(ヒューズビット書き換え)
#include <avr/io.h>

#define LED_PORT	PORTB
#define LED_DDR		(*(&LED_PORT - 1))

#define SW_PIN		PIND
#define SW_DDR		(*(&SW_PIN + 1))

#define USB_PIN		PIND
#define USB_DDR		(*(&USB_PIN + 1))
#define USB_PORT	(*(&USB_PIN + 2))

#define DMINUS		0
#define DPLUS		2

volatile uint8_t	buf[11];
volatile uint8_t	*receiveBuf;

void
boardInit()
{
	LED_DDR		= 0xff;
	LED_PORT	= 0;
	USB_DDR		= 0xff & ~((1 << DMINUS) | (1 << DPLUS));
	return;
}

void
usbInit()
{
	/* 
	 * TODO: INT0のrising edge intrを有効にする
	 * 詳細はattiny2313のデータシート「外部割込み」の章
	 */
	MCUCR = 0b00000011;
	GIMSK = 0b01000000;
	sei();
	return;
}

int
main()
{
	boardInit();
	usbInit();
	usbWait();
	cli();
	LED_PORT = receiveBuf[0];	// ここにPIDが入るはず
	for(;;);
}

アセンブリの方はとりあえずこんな感じでよさそうかな?
#include <avr/io.h>

#define __zero_reg__	r1
#define USB_PIN		_SFR_IO_ADDR(PIND)

	; 2clkかかるnopを用意(nopを2回書くよりプログラムメモリの消費が少なくてすむ)
#define nop2		rjmp	.+0


	.section .data
fin_intr:	.dc.b	0x00
	
	
	.section .text

	.global SIG_INTERRUPT0
    .type   SIG_INTERRUPT0, @function
SIG_INTERRUPT0:

	; 正直SYNCではやることない(8 * 8clk待ったらSYNCは終わるはず)
	; 8 * 8 + 4clk待てば位相が180度ずれて受信成功率が上がると思われるが、
	; 割り込みベクタに飛ぶまでに4clkかかっているので64clk待てばよい。(20日追記)
	; 本当はちゃんとホストがSYNC送ってるか確認するべき
	; 68clkで退避するものはすべて退避(C呼び出しではなく割り込みなので使うものすべて退避)
	
	push	r27
	push	r26
	push	r25
	push	r24
	push	r23
	push	r22
							; 退避完了:12clk
	
	ldi		r25, 12
	ldi		r27, HIGH(buf)
	ldi		r26, LOW(buf)	; Xreg <- bufのアドレス
	ldi		r23, 0
	ldi		r22, 0			; ここまでで+5clk
recv_sync:
	nop
	dec		r25
	brne	recv_sync	; ここを抜けるとき12 + 5 + 4 * (12 - 1) + 3 = 64clk
	
recv_loop:				; 以降のデータはすべてbit-stuffing付きNRZI変換をしてbufに放り込む
	; 1bitあたり8clkまでしか使えないから難しい…ここは後回し
	
ret_proc:
	ldi		r25, 1
	sts		fin_intr, r25
	pop		r22
	pop		r23
	pop		r24
	pop		r25
	pop		r26
	pop		r27
	reti
	.endfunc

	.global usbWait
	.func	usbWait
usbWait:
	sts		fin_intr, __zero_reg__
usbWaitLoop:
	lds		r25, fin_intr
	breq	usbWaitLoop
	ret
	.endfunc

ここまでは(これといってまともな処理してないので)多分大丈夫。

recv_loopが超難しいのでここはまた次回。そろそろ諦めて先人の知恵をお借りします…
関連記事

  • comment
  • secret
  • 管理者にだけ表示を許可する

trackbackURL:http://yuranos.blog11.fc2.com/tb.php/32-896ea20d
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。