Date:2011-02-22 04:24:07 (8 years 7 months ago)
Author:Werner Almesberger
Commit:78cfc8ffeb03a6fd6a1e63295c9d807eda84017d
Message:moved atusb/fw3/ to atusb/fw/

Files: atusb/fw/Makefile (1 diff)
atusb/fw/README (1 diff)
atusb/fw/an/README (1 diff)
atusb/fw/an/dec.py (1 diff)
atusb/fw/an/get.py (1 diff)
atusb/fw/an/plot (1 diff)
atusb/fw/atusb.c (1 diff)
atusb/fw/board.c (1 diff)
atusb/fw/board.h (1 diff)
atusb/fw/descr.c (1 diff)
atusb/fw/ep0.c (1 diff)
atusb/fw/spi.c (1 diff)
atusb/fw/spi.h (1 diff)
atusb/fw/usb/atu2.c (1 diff)
atusb/fw/usb/usb.c (1 diff)
atusb/fw/usb/usb.h (1 diff)
atusb/fw/version.h (1 diff)
atusb/fw3/Makefile (1 diff)
atusb/fw3/README (1 diff)
atusb/fw3/an/README (1 diff)
atusb/fw3/an/dec.py (1 diff)
atusb/fw3/an/get.py (1 diff)
atusb/fw3/an/plot (1 diff)
atusb/fw3/atusb.c (1 diff)
atusb/fw3/board.c (1 diff)
atusb/fw3/board.h (1 diff)
atusb/fw3/descr.c (1 diff)
atusb/fw3/ep0.c (1 diff)
atusb/fw3/spi.c (1 diff)
atusb/fw3/spi.h (1 diff)
atusb/fw3/usb/atu2.c (1 diff)
atusb/fw3/usb/usb.c (1 diff)
atusb/fw3/usb/usb.h (1 diff)
atusb/fw3/version.h (1 diff)

Change Details

atusb/fw/Makefile
1#
2# Makefile - Makefile of the ATUSB firmware
3#
4# Written 2010-2011 by Werner Almesberger
5# Copyright 2010-2011 by Werner Almesberger
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12
13SHELL = /bin/bash
14
15NAME = atusb
16
17CFLAGS = -g -Wall -Wextra -Wshadow -Werror -Wno-unused-parameter \
18     -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes
19
20CHIP=atmega32u2
21
22AVR_PREFIX = $(BIN_PATH) avr-
23CC = $(AVR_PREFIX)gcc
24OBJCOPY = $(AVR_PREFIX)objcopy
25#OBJDUMP = $(AVR_PREFIX)objdump
26
27USB_OBJS = usb.o atu2.o
28OBJS = atusb.o board.o spi.o descr.o ep0.o $(USB_OBJS)
29
30vpath %.c usb/
31
32CFLAGS += -I../fw/include -Iusb
33
34# ----- Verbosity control -----------------------------------------------------
35
36CC_normal := $(CC)
37BUILD_normal :=
38DEPEND_normal := $(CPP) $(CFLAGS) -MM -MG
39
40CC_quiet = @echo " CC " $@ && $(CC_normal)
41BUILD_quiet = @echo " BUILD " $@ && $(BUILD_normal)
42DEPEND_quiet = @$(DEPEND_normal)
43
44ifeq ($(V),1)
45    CC = $(CC_normal)
46    BUILD = $(BUILD_normal)
47    DEPEND = $(DEPEND_normal)
48else
49    CC = $(CC_quiet)
50    BUILD = $(BUILD_quiet)
51    DEPEND = $(DEPEND_quiet)
52endif
53
54# ----- Rules -----------------------------------------------------------------
55
56.PHONY: all clean upload prog version.c
57
58all: $(NAME).bin
59
60$(NAME).elf: $(OBJS)
61        $(MAKE) version.o
62        $(CC) $(CFLAGS) -mmcu=$(CHIP) -o $@ $(OBJS) version.o
63
64%.bin: %.elf
65        $(BUILD) $(OBJCOPY) -j .text -j .data -O binary $< $@
66        @echo "build #`cat .version`, `ls -l $@`"
67
68# ----- Cleanup ---------------------------------------------------------------
69
70clean:
71        rm -f $(NAME).bin $(NAME).elf $(OBJS) $(OBJS:.o=.d)
72        rm -f version.c version.d version.o
73
74# ----- Build version ---------------------------------------------------------
75
76version.c:
77        @if [ -f .version ]; then \
78            v=`cat .version`; \
79            expr $$v + 1 >.version; \
80        else \
81            echo 0 >.version; \
82        fi
83        @[ -s .version ] || echo 0 >.version
84        @echo '/* MACHINE-GENERATED. DO NOT EDIT ! */' >version.c
85        @echo '#include "version.h"' >>version.c
86        @echo "const char *build_date = \"`date`\";" >>version.c
87        @echo "const uint16_t build_number = `cat .version`;" \
88          >>version.c
89
90# ----- Dependencies ----------------------------------------------------------
91
92%.o: %.c
93        $(CC) $(CFLAGS) -mmcu=$(CHIP) -Os -c $<
94        $(DEPEND) $< | \
95          sed -e \
96            '/^\(.*:\)\? */{p;s///;s/ *\\\?$$/ /;s/ */:\n/g;H;}' \
97            -e '$${g;p;}' -e d >$*.d; \
98          [ "$${PIPESTATUS[*]}" = "0 0" ] || { rm -f $*.d; exit 1; }
99
100-include $(OBJS:.o=.d)
101
102# ----- Programming and device control ----------------------------------------
103
104upload: $(NAME).bin
105        scp $(NAME).bin jlime:
106
107prog:
108        ssh jlime avrdude -F -p $(CHIP) -c nanonote_atusb -e \
109          -U flash:w:$(NAME).bin:r \
110          -U lfuse:w:0x60:m # external clock, slow start-up
111
112on:
113        ssh jlime poke 0x10010318 4
114
115off:
116        ssh jlime poke 0x10010314 4
117
118reset:
119        ssh jlime poke 0x10010318 2048
120        ssh jlime poke 0x10010314 2048
atusb/fw/README
1Requires very recent toolchain, because ATmega32U2 is relatively new.
2
3Building:
4
5make
6make upload prog
7
8--------------------------
9
10Making the toolchain:
11
12# patches according to
13# http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=789527
14
15# some gcc prerequisites
16
17apt-get remove avr-libc gcc-avr binutils-avr
18apt-get install libmpfr-dev libmpc-dev
19
20# binutils
21
22wget http://ftp.gnu.org/gnu/binutils/binutils-2.21.tar.bz2
23tar xfj binutils-2.21.tar.bz2
24cd binutils-2.21
25./configure --target=avr --disable-nls
26make
27make install
28
29# gcc
30
31wget http://ftpmirror.gnu.org/gcc/gcc-4.5.2/gcc-4.5.2.tar.bz2
32wget -O gcc_452_avr.patch http://gcc.gnu.org/bugzilla/attachment.cgi?id=23050
33tar xfj gcc-4.5.2.tar.bz2
34cd gcc-4.5.2
35patch -p1 -s <../gcc_452_avr.patch
36mkdir obj-avr
37cd obj-avr
38../configure --target=avr --enable-languages=c \
39    --disable-nls --disable-libssp --with-dwarf2
40make
41make install
42
43wget http://download.savannah.gnu.org/releases/avr-libc/avr-libc-1.7.0.tar.bz2
44wget -O avr_libc_170.patch \
45  https://savannah.nongnu.org/support/download.php?file_id=21669
46tar xfj avr-libc-1.7.0.tar.bz2
47cd avr-libc-1.7.0
48patch -p0 -s <../avr_libc_170.patch
49./bootstrap # the automake at the end takes a while
50./configure --build=`./config.guess` --host=avr
51make
52make install
atusb/fw/an/README
1workflow:
2
3- connect zprobe (note: it currently inverts because it didn't have any
4  other chips around. this may change later.)
5
6- capture the USB signals at an interesting moment with a sample rate of
7  50 MSa/s
8
9- zoom into the frame(s) of interest
10
11- download the data with
12  ./get.py
13
14- decode with
15  ./dec.py
16
17  For manual decoding, set the coders to D+ and D- (we need D- for SE0
18  and SE1 detection), then click on a rising clock edge left of the
19  packet and move the cursor to the right.
20
21- if there are problems with the clock, the analog signal and digital
22  signals derived from it can be examined after running dec.py with
23  ./plot
24
25  (Note that the digital zprobe hides any analog anomalies.)
atusb/fw/an/dec.py
1#!/usr/bin/python
2
3from tmc.wave import *
4from tmc.dxplore import dxplore
5from tmc.decode import d_usb_stream
6
7
8#
9# Clock recovery: we assume that each change in the wave is triggered by a
10# clock edge. We know the clock's nominal period and resynchronize on each
11# edge. Additionally, we can obtain a list of times when a timing violation
12# has occurred.
13#
14# Note that the timing violations logic doesn't make much sense in its present
15# form, since it mainly measures noise (particularly if we're digitizing slow
16# edges) and not clock drift.
17#
18# A more useful metric would be accumulated error from some point of reference
19# or at least the timing of same edges, to eliminate (generally harmless) time
20# offsets introduced by digitizing.
21#
22# So it would probably make more sense for "recover" not to check for timing
23# violations at all, and leave this to more specialized functions.
24#
25def recover(self, period, min = None, max = None, t0 = None):
26    if t0 is None:
27    t0 = self.data[0]
28    v = not self.initial
29    res = []
30    violations = []
31    for t in self.data:
32    v = not v
33    if t <= t0:
34        continue
35    n = 0
36    while t0 < t-period/2:
37        res.append(t0)
38        t0 += period
39        n += 1
40    if min is not None:
41        if t0-t > n*min:
42        violations.append(t)
43    if max is not None:
44        if t-t0 > n*max:
45        violations.append(t)
46    t0 = t
47    return res, violations
48
49
50#
51# Load the analog waves saved by get.py
52#
53wv = waves()
54wv.load("_wv")
55
56#
57# Digitize the waves and save the result.
58#
59dp = wv[0].digitize(1.5, 1.8)
60dm = wv[1].digitize(1.5, 1.8)
61wv = waves(dp, dm, dp-dm)
62wv.save("_dig")
63
64#
65# Also record the differential signal.
66#
67wd = wv[1]-wv[0]
68dd = wd.digitize(-0.5, 0.5)
69wd.save("_diff")
70
71#
72# Run clock recovery on D+/D-. We only need one, but check both to be sure.
73#
74#p = 1/1.5e6
75p = 1/12e6
76dp_t, viol = recover(dp, p, p*0.9, p*1.1)
77print viol
78dm_t, viol = recover(dm, p, p*.9, p*1.1, t0 = dp.data[0])
79print viol
80
81#
82# Shift the clock by half a period, add a few periods to get steady state and
83# SE0s (if any), and then sample the data lines.
84#
85clk = map(lambda t: t+p/2, dp_t)
86clk.extend((clk[-1]+p, clk[-1]+2*p, clk[-1]+3*p))
87dp_bv = dp.get(clk)
88dm_bv = dm.get(clk)
89
90#
91# Save a wave with the recovered clock to make it easier to find the bits in
92# analog graphs.
93#
94dd.data = dp_t;
95dd.save("_clk")
96
97#
98# For decoding, we need a fake bit clock. We generate it by doubling each data
99# bit and generating a L->H transition during this bit.
100#
101dpd = []
102dmd = []
103dck = []
104
105# err, silly, seems that we've mixed up D+ and D- all over the place :-)
106print d_usb_stream(dm_bv[:], dp_bv[:])
107
108for v in dp_bv:
109    dpd.append(v)
110    dpd.append(v)
111    dck.append(0)
112    dck.append(1)
113
114for v in dm_bv:
115    dmd.append(v)
116    dmd.append(v)
117
118#
119# Display the reconstructed digital signal. Note that the absolute time is only
120# correct at the beginning and that relative time is only accurate over
121# intervals in which no significant clock resynchronization has occurred.
122#
123# In fact, dxplore should probably have an option to either turn off time
124# entirely or to display a user-provided time axis. The latter may be a bit
125# tricky to implement.
126#
127dxplore((dmd, dpd, dck), 0, p/2, labels = ("D+", "D-", "CLK"))
atusb/fw/an/get.py
1#!/usr/bin/python
2
3from tmc.scope import rigol_ds1000c
4
5#-800, +1600
6s = rigol_ds1000c()
7#s.debug = False
8
9pos = s.hor.pos
10scale = s.hor.scale
11t0 = pos-scale*s.div_hor/2
12t1 = pos+scale*s.div_hor/2
13print t0, t1
14
15#zoom = 10
16#step = scale/s.samples_per_div/zoom
17#print step
18step = 4e-9
19step = 2e-9
20
21w = s.wave((s.ch[0], s.ch[1]), start = t0, end = t1, step = step)
22w[0] = 3.3-w[0]
23w[1] = 3.3-w[1]
24
25s.hor.pos = pos
26s.hor.scale = scale
27
28w[0].label = "D+";
29w[1].label = "D-";
30
31w.save("_wv")
atusb/fw/an/plot
1#!/bin/sh
2#
3# Plot output of "dec"
4#
5gnuplot -persist <<EOF
6set style data lines
7plot "_wv" using 1:(\$2-4), \
8  "_dig" using 1:(\$2*3.3-4) lw 2, \
9  "_wv" using 1:3, \
10  "_dig" using 1:(\$3*3.3) lw 2, \
11  "_clk" using 1:(\$2+1) lt 7
12EOF
atusb/fw/atusb.c
1/*
2 * fw/atusb.c - ATUSB initialization and main loop
3 *
4 * Written 2008-2011 by Werner Almesberger
5 * Copyright 2008-2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdint.h>
15
16#include <avr/io.h>
17
18#define F_CPU 8000000UL
19#include <util/delay.h>
20
21#include "usb.h"
22
23#include "board.h"
24#include "spi.h"
25#include "atusb/ep0.h"
26
27
28int main(void)
29{
30    board_init();
31    spi_init();
32    reset_rf();
33
34    /* now we should be at 8 MHz */
35
36#if 0
37    led(1);
38    _delay_ms(100);
39    led(0);
40#endif
41
42    usb_init();
43    ep0_init();
44
45    while (1)
46        usb_poll();
47}
atusb/fw/board.c
1/*
2 * fw/board.c - Board-specific functions
3 *
4 * Written 2011 by Werner Almesberger
5 * Copyright 2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdint.h>
15
16#include <avr/io.h>
17#include <avr/interrupt.h>
18
19#define F_CPU 8000000UL
20#include <util/delay.h>
21
22#include "at86rf230.h"
23#include "board.h"
24#include "spi.h"
25
26
27static void set_clkm(void)
28{
29    /* switch CLKM to 8 MHz */
30
31    /*
32     * @@@ Note: Atmel advise against changing the external clock in
33     * mid-flight. We should therefore switch to the RC clock first, then
34     * crank up the external clock, and finally switch back to the external
35     * clock. The clock switching procedure is described in the ATmega32U2
36     * data sheet in secton 8.2.2.
37     */
38
39    spi_begin();
40    spi_send(AT86RF230_REG_WRITE | REG_TRX_CTRL_0);
41    spi_send(CLKM_CTRL_8MHz);
42    spi_end();
43}
44
45
46void reset_rf(void)
47{
48    /* AT86RF231 data sheet, 12.4.13, reset pulse width: 625 ns (min) */
49
50    CLR(nRST_RF);
51    _delay_us(1);
52    SET(nRST_RF);
53
54    /* 12.4.14: SPI access latency after reset: 625 ns (min) */
55
56    _delay_us(1);
57
58    /* we must restore TRX_CTRL_0 after each reset (9.6.4) */
59
60    set_clkm();
61}
62
63
64uint8_t read_irq(void)
65{
66    return PIN(IRQ_RF);
67}
68
69
70void led(int on)
71{
72    if (on)
73        SET(LED);
74    else
75        CLR(LED);
76}
77
78
79void panic(void)
80{
81    cli();
82    while (1) {
83        SET(LED);
84        _delay_ms(100);
85        CLR(LED);
86        _delay_ms(100);
87    }
88}
89
90
91void board_init(void)
92{
93    /* We start with a 1 MHz/8 clock. Disable the prescaler. */
94
95    CLKPR = 1 << CLKPCE;
96    CLKPR = 0;
97
98    /* set up all the outputs; default port value is 0 */
99
100    OUT(LED);
101    OUT(nRST_RF); /* resets the transceiver */
102    OUT(SLP_TR);
103}
atusb/fw/board.h
1/*
2 * fw/board.h - Board-specific functions and definitions
3 *
4 * Written 2008-2010 by Werner Almesberger
5 * Copyright 2008-2010 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#ifndef BOARD_H
14#define BOARD_H
15
16#include <stdint.h>
17
18
19#define LED_PORT B
20#define LED_BIT 6
21#define nRST_RF_PORT C
22#define nRST_RF_BIT 7
23#define SLP_TR_PORT B
24#define SLP_TR_BIT 4
25
26#define SCLK_PORT D
27#define SCLK_BIT 5
28#define MOSI_PORT D
29#define MOSI_BIT 3
30
31#define MISO_PORT D
32#define MISO_BIT 2
33#define nSS_PORT D
34#define nSS_BIT 1
35#define IRQ_RF_PORT D
36#define IRQ_RF_BIT 0
37
38
39#define SET_2(p, b) PORT##p |= 1 << (b)
40#define CLR_2(p, b) PORT##p &= ~(1 << (b))
41#define IN_2(p, b) DDR##p &= ~(1 << (b))
42#define OUT_2(p, b) DDR##p |= 1 << (b)
43#define PIN_2(p, b) ((PIN##p >> (b)) & 1)
44
45#define SET_1(p, b) SET_2(p, b)
46#define CLR_1(p, b) CLR_2(p, b)
47#define IN_1(p, b) IN_2(p, b)
48#define OUT_1(p, b) OUT_2(p, b)
49#define PIN_1(p, b) PIN_2(p, b)
50
51#define SET(n) SET_1(n##_PORT, n##_BIT)
52#define CLR(n) CLR_1(n##_PORT, n##_BIT)
53#define IN(n) IN_1(n##_PORT, n##_BIT)
54#define OUT(n) OUT_1(n##_PORT, n##_BIT)
55#define PIN(n) PIN_1(n##_PORT, n##_BIT)
56
57
58void reset_rf(void);
59uint8_t read_irq(void);
60void led(int on);
61void panic(void);
62void board_init(void);
63
64#endif /* !BOARD_H */
atusb/fw/descr.c
1/*
2 * fw/descr.c - USB descriptors
3 *
4 * Written 2008-2011 by Werner Almesberger
5 * Copyright 2008-2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include "usb.h"
15
16
17#define USB_VENDOR 0x20b7 /* Qi Hardware */
18#define USB_PRODUCT 0x1540 /* ben-wpan atusb */
19
20#define LE(x) ((uint16_t) (x) & 0xff), ((uint16_t) (x) >> 8)
21
22/*
23 * Device descriptor
24 */
25
26const uint8_t device_descriptor[18] = {
27    18, /* bLength */
28    USB_DT_DEVICE, /* bDescriptorType */
29    LE(0x200), /* bcdUSB */
30    USB_CLASS_VENDOR_SPEC, /* bDeviceClass */
31    0x00, /* bDeviceSubClass */
32    0x00, /* bDeviceProtocol */
33    EP0_SIZE, /* bMaxPacketSize */
34    LE(USB_VENDOR), /* idVendor */
35    LE(USB_PRODUCT), /* idProduct */
36    LE(0x0001), /* bcdDevice */
37    0, /* iManufacturer */
38    0, /* iProduct */
39    0, /* iSerialNumber */
40    1 /* bNumConfigurations */
41};
42
43
44/*
45 * Our configuration
46 *
47 * We're always bus-powered.
48 */
49
50const uint8_t config_descriptor[] = {
51    9, /* bLength */
52    USB_DT_CONFIG, /* bDescriptorType */
53#if 0
54    LE(9+9+7+7), /* wTotalLength */
55#else
56    LE(9+9), /* wTotalLength */
57#endif
58    1, /* bNumInterfaces */
59    1, /* bConfigurationValue (> 0 !) */
60    0, /* iConfiguration */
61    USB_ATTR_BUS_POWERED, /* bmAttributes */
62    50/2, /* bMaxPower (50 mA) */
63
64    /* Interface #0 */
65
66    9, /* bLength */
67    USB_DT_INTERFACE, /* bDescriptorType */
68    0, /* bInterfaceNumber */
69    0, /* bAlternateSetting */
70#if 0
71    2, /* bNumEndpoints */
72#else
73    0,
74#endif
75    USB_CLASS_VENDOR_SPEC, /* bInterfaceClass */
76    0, /* bInterfaceSubClass */
77    0, /* bInterfaceProtocol */
78    0, /* iInterface */
79
80#if 0
81    /* EP OUT */
82
83    7, /* bLength */
84    USB_DT_ENDPOINT, /* bDescriptorType */
85    0x01, /* bEndPointAddress */
86    0x02, /* bmAttributes (bulk) */
87    LE(EP1_SIZE), /* wMaxPacketSize */
88    0, /* bInterval */
89
90    /* EP IN */
91
92    7, /* bLength */
93    USB_DT_ENDPOINT, /* bDescriptorType */
94    0x81, /* bEndPointAddress */
95    0x02, /* bmAttributes (bulk) */
96    LE(EP1_SIZE), /* wMaxPacketSize */
97    0, /* bInterval */
98#endif
99};
atusb/fw/ep0.c
1/*
2 * fw/ep0.c - EP0 extension protocol
3 *
4 * Written 2008-2011 by Werner Almesberger
5 * Copyright 2008-2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdint.h>
15
16#include <avr/io.h>
17
18#ifndef NULL
19#define NULL 0
20#endif
21
22#include "usb.h"
23
24#include "at86rf230.h"
25#include "atusb/ep0.h"
26#include "version.h"
27#include "board.h"
28#include "spi.h"
29
30
31#define HW_TYPE HW_TYPE_110131
32
33#define debug(...)
34#define error(...)
35
36
37static const uint8_t id[] = { EP0ATUSB_MAJOR, EP0ATUSB_MINOR, HW_TYPE };
38static uint8_t buf[MAX_PSDU+3]; /* command, PHDR, and LQI */
39static uint8_t size;
40
41
42static void do_buf_write(void *user)
43{
44    uint8_t i;
45
46    spi_begin();
47    for (i = 0; i != size; i++)
48        spi_send(buf[i]);
49    spi_end();
50}
51
52
53#define BUILD_OFFSET 7 /* '#' plus "65535" plus ' ' */
54
55
56static int my_setup(const struct setup_request *setup)
57{
58    unsigned tmp;
59    uint8_t i;
60
61    switch (setup->bmRequestType | setup->bRequest << 8) {
62    case ATUSB_FROM_DEV(ATUSB_ID):
63        debug("ATUSB_ID\n");
64        if (setup->wLength > 3)
65            return 0;
66        usb_send(&eps[0], id, setup->wLength, NULL, NULL);
67        return 1;
68    case ATUSB_FROM_DEV(ATUSB_BUILD):
69        debug("ATUSB_BUILD\n");
70        tmp = build_number;
71        for (i = BUILD_OFFSET-2; tmp; i--) {
72            buf[i] = (tmp % 10)+'0';
73            tmp /= 10;
74        }
75        buf[i] = '#';
76        buf[BUILD_OFFSET-1] = ' ';
77        for (size = 0; build_date[size]; size++)
78            buf[BUILD_OFFSET+size] = build_date[size];
79        size += BUILD_OFFSET-i;
80        if (size > setup->wLength)
81            return 0;
82        usb_send(&eps[0], buf+i, size, NULL, NULL);
83        return 1;
84
85#ifdef NOTYET
86    case ATUSB_TO_DEV(ATUSB_RESET):
87        debug("ATUSB_RESET\n");
88        RSTSRC = SWRSF;
89        while (1);
90#endif
91
92    case ATUSB_TO_DEV(ATUSB_RF_RESET):
93        debug("ATUSB_RF_RESET\n");
94        reset_rf();
95        //ep_send_zlp(EP_CTRL);
96        return 1;
97
98    case ATUSB_FROM_DEV(ATUSB_POLL_INT):
99        debug("ATUSB_POLL_INT\n");
100        if (setup->wLength < 1)
101            return 0;
102        *buf = read_irq();
103        usb_send(&eps[0], buf, 1, NULL, NULL);
104        return 1;
105
106    case ATUSB_TO_DEV(ATUSB_REG_WRITE):
107        debug("ATUSB_REG_WRITE\n");
108        spi_begin();
109        spi_send(AT86RF230_REG_WRITE | setup->wIndex);
110        spi_send(setup->wValue);
111        spi_end();
112        //ep_send_zlp(EP_CTRL);
113        return 1;
114    case ATUSB_FROM_DEV(ATUSB_REG_READ):
115        debug("ATUSB_REG_READ\n");
116        spi_begin();
117        spi_send(AT86RF230_REG_READ | setup->wIndex);
118        *buf = spi_recv();
119        spi_end();
120        usb_send(&eps[0], buf, 1, NULL, NULL);
121        return 1;
122
123    case ATUSB_TO_DEV(ATUSB_BUF_WRITE):
124        debug("ATUSB_BUF_WRITE\n");
125        if (setup->wLength < 1)
126            return 0;
127        if (setup->wLength > MAX_PSDU)
128            return 0;
129        buf[0] = AT86RF230_BUF_WRITE;
130        buf[1] = setup->wLength;
131        size = setup->wLength+2;
132        usb_recv(&eps[0], buf+2, setup->wLength, do_buf_write, NULL);
133        return 1;
134    case ATUSB_FROM_DEV(ATUSB_BUF_READ):
135        debug("ATUSB_BUF_READ\n");
136        if (setup->wLength < 2) /* PHR+LQI */
137            return 0;
138        if (setup->wLength > MAX_PSDU+2) /* PHR+PSDU+LQI */
139            return 0;
140        spi_begin();
141        spi_send(AT86RF230_BUF_READ);
142        size = spi_recv();
143        if (size >= setup->wLength)
144            size = setup->wLength-1;
145        for (i = 0; i != size+1; i++)
146            buf[i] = spi_recv();
147        spi_end();
148        usb_send(&eps[0], buf, size+1, NULL, NULL);
149        return 1;
150
151    case ATUSB_TO_DEV(ATUSB_SRAM_WRITE):
152        debug("ATUSB_SRAM_WRITE\n");
153        if (setup->wIndex > SRAM_SIZE)
154            return 0;
155        if (setup->wIndex+setup->wLength > SRAM_SIZE)
156            return 0;
157        buf[0] = AT86RF230_SRAM_WRITE;
158        buf[1] = setup->wIndex;
159        size = setup->wLength+2;
160        usb_recv(&eps[0], buf+2, setup->wLength, do_buf_write, NULL);
161        return 1;
162    case ATUSB_TO_DEV(ATUSB_SRAM_READ):
163        debug("ATUSB_SRAM_READ\n");
164        if (setup->wIndex > SRAM_SIZE)
165            return 0;
166        if (setup->wIndex+setup->wLength > SRAM_SIZE)
167            return 0;
168        spi_begin();
169        spi_send(AT86RF230_SRAM_READ);
170        spi_send(setup->wIndex);
171        for (i = 0; i != size; i++)
172            buf[i] = spi_recv();
173        spi_end();
174        usb_send(&eps[0], buf, size, NULL, NULL);
175        return 1;
176
177    default:
178        error("Unrecognized SETUP: 0x%02x 0x%02x ...\n",
179            setup->bmRequestType, setup->bRequest);
180        return 0;
181    }
182}
183
184
185void ep0_init(void)
186{
187    user_setup = my_setup;
188}
atusb/fw/spi.c
1/*
2 * fw/spi.c - ATmega8 family SPI I/O
3 *
4 * Written 2011 by Werner Almesberger
5 * Copyright 2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdint.h>
15
16#include <avr/io.h>
17
18#include "board.h"
19#include "spi.h"
20
21
22void spi_begin(void)
23{
24    CLR(nSS);
25}
26
27
28uint8_t spi_io(uint8_t v)
29{
30// while (!(UCSR1A & 1 << UDRE1));
31        UDR1 = v;
32        while (!(UCSR1A & 1 << RXC1));
33        return UDR1;
34}
35
36
37void spi_end(void)
38{
39// while (!(UCSR1A & 1 << TXC1));
40    SET(nSS);
41}
42
43
44void spi_init(void)
45{
46    SET(nSS);
47    OUT(SCLK);
48    OUT(MOSI);
49    OUT(nSS);
50    IN(MISO);
51
52    UBRR1 = 0; /* set bit rate to zero to begin */
53    UCSR1C = 1 << UMSEL11 | 1 << UMSEL10;
54            /* set MSPI, MSB first, SPI data mode 0 */
55    UCSR1B = 1 << RXEN1 | 1 << TXEN1;
56            /* enable receiver and transmitter */
57    UBRR1 = 0; /* reconfirm the bit rate */
58}
atusb/fw/spi.h
1/*
2 * fw/spi.h - ATmega8 family SPI I/O
3 *
4 * Written 2011 by Werner Almesberger
5 * Copyright 2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#ifndef SPI_H
14#define SPI_H
15
16#include <stdint.h>
17
18
19void spi_begin(void);
20uint8_t spi_io(uint8_t v);
21void spi_end(void);
22void spi_init(void);
23
24#define spi_send(v) (void) spi_io(v)
25#define spi_recv(v) spi_io(0)
26
27#endif /* !SPI_H */
atusb/fw/usb/atu2.c
1/*
2 * fw/usb/atu2.c - Chip-specific driver for Atmel ATxxxU2 USB chips
3 *
4 * Written 2008-2011 by Werner Almesberger
5 * Copyright 2008-2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13/*
14 * Known issues:
15 * - no suspend/resume
16 * - we don't call back after failed transmissions,
17 * - we don't reset the EP buffer after failed receptions
18 * - enumeration often encounters an error -71 (from which it recovers)
19 */
20
21#include <stdint.h>
22
23#define F_CPU 8000000UL
24#include <util/delay.h>
25
26#include <avr/io.h>
27#include "usb.h"
28#include "../board.h"
29
30
31#ifndef NULL
32#define NULL 0
33#endif
34
35#if 1
36#define BUG_ON(cond) do { if (cond) panic(); } while (0)
37#else
38#define BUG_ON(cond)
39#endif
40
41
42#define NUM_EPS 1
43
44
45struct ep_descr eps[NUM_EPS];
46
47
48static uint16_t usb_read_word(void)
49{
50    uint8_t low;
51
52    low = UEDATX;
53    return low | UEDATX << 8;
54}
55
56
57static void enable_addr(void *user)
58{
59    while (!(UEINTX & (1 << TXINI)));
60    UDADDR |= 1 << ADDEN;
61}
62
63
64int set_addr(uint8_t addr)
65{
66    UDADDR = addr;
67    usb_send(&eps[0], NULL, 0, enable_addr, NULL);
68    return 1;
69}
70
71
72static int ep_setup(void)
73{
74    struct setup_request setup;
75
76    BUG_ON(UEBCLX < 8);
77
78    setup.bmRequestType = UEDATX;
79    setup.bRequest = UEDATX;
80    setup.wValue = usb_read_word();
81    setup.wIndex = usb_read_word();
82    setup.wLength = usb_read_word();
83
84    if (!handle_setup(&setup))
85        return 0;
86    if (!(setup.bmRequestType & 0x80) && eps[0].state == EP_IDLE)
87        usb_send(&eps[0], NULL, 0, NULL, NULL);
88    return 1;
89}
90
91
92static int ep_rx(struct ep_descr *ep)
93{
94    uint8_t size;
95
96    size = UEBCLX;
97    if (size > ep->end-ep->buf)
98        return 0;
99    while (size--)
100        *ep->buf++ = UEDATX;
101    if (ep->buf == ep->end) {
102        ep->state = EP_IDLE;
103        if (ep->callback)
104            ep->callback(ep->user);
105        if (ep == &eps[0])
106            usb_send(ep, NULL, 0, NULL, NULL);
107    }
108    return 1;
109}
110
111
112static void ep_tx(struct ep_descr *ep)
113{
114    uint8_t size = ep->end-ep->buf;
115    uint8_t left;
116
117    if (size > ep->size)
118        size = ep->size;
119    for (left = size; left; left--)
120        UEDATX = *ep->buf++;
121    if (size == ep->size)
122        return;
123    ep->state = EP_IDLE;
124}
125
126
127static void handle_ep(int n)
128{
129    struct ep_descr *ep = eps+n;
130
131    UENUM = n;
132    if (UEINTX & (1 << RXSTPI)) {
133        /* @@@ EP_RX. EP_TX: cancel */
134        if (!ep_setup())
135            goto stall;
136        UEINTX &= ~(1 << RXSTPI);
137    }
138    if (UEINTX & (1 << RXOUTI)) {
139        /* @@ EP_TX: cancel */
140        if (ep->state != EP_RX)
141            goto stall;
142        if (!ep_rx(ep))
143            goto stall;
144// UEINTX &= ~(1 << RXOUTI);
145        UEINTX &= ~(1 << RXOUTI | 1 << FIFOCON);
146    }
147    if (UEINTX & (1 << STALLEDI)) {
148        ep->state = EP_IDLE;
149        UEINTX &= ~(1 << STALLEDI);
150    }
151    if (UEINTX & (1 << TXINI)) {
152        /* @@ EP_RX: cancel */
153        if (ep->state == EP_TX) {
154            ep_tx(ep);
155            UEINTX &= ~(1 << TXINI);
156            if (ep->state == EP_IDLE && ep->callback)
157                ep->callback(ep->user);
158        }
159    }
160    return;
161
162stall:
163    UEINTX &= ~(1 << RXSTPI | 1 << RXOUTI | 1 << STALLEDI);
164    ep->state = EP_IDLE;
165    UECONX |= 1 << STALLRQ;
166}
167
168
169void usb_poll(void)
170{
171    uint8_t flags, i;
172
173    flags = UEINT;
174    for (i = 0; i != NUM_EPS; i++)
175        if (1 || flags & (1 << i))
176            handle_ep(i);
177    /* @@@ USB bus reset */
178}
179
180
181static void ep_init(void)
182{
183    UENUM = 0;
184    UECONX = (1 << RSTDT) | (1 << EPEN); /* enable */
185    UECFG0X = 0; /* control, direction is ignored */
186    UECFG1X = 3 << EPSIZE0; /* 64 bytes */
187    UECFG1X |= 1 << ALLOC;
188
189    while (!(UESTA0X & (1 << CFGOK)));
190
191    eps[0].state = EP_IDLE;
192    eps[0].size = 64;
193}
194
195
196void usb_init(void)
197{
198    USBCON |= 1 << FRZCLK; /* freeze the clock */
199
200    /* enable the PLL and wait for it to lock */
201    PLLCSR &= ~(1 << PLLP2 | 1 << PLLP1 | 1 << PLLP0);
202    PLLCSR |= 1 << PLLE;
203    while (!(PLLCSR & (1 << PLOCK)));
204
205    USBCON &= ~(1 << USBE); /* reset the controller */
206    USBCON |= 1 << USBE;
207
208    USBCON &= ~(1 << FRZCLK); /* thaw the clock */
209
210    UDCON &= ~(1 << DETACH); /* attach the pull-up */
211    UDCON |= 1 << RSTCPU; /* reset CPU on bus reset */
212
213    ep_init();
214}
atusb/fw/usb/usb.c
1/*
2 * fw/usb/usb.c - USB hardware setup and standard device requests
3 *
4 * Written 2008-2011 by Werner Almesberger
5 * Copyright 2008-2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13/*
14 * Known issues:
15 * - no suspend/resume
16 * - should support EP clearing and stalling
17 */
18
19#include <stdint.h>
20
21#include "usb.h"
22#include "../board.h"
23
24
25#ifndef NULL
26#define NULL 0
27#endif
28
29#define NUM_EPS 1
30
31#if 1
32extern void panic(void);
33#define BUG_ON(cond) do { if (cond) panic(); } while (0)
34#else
35#define BUG_ON(cond)
36#endif
37
38int (*user_setup)(const struct setup_request *setup);
39int (*user_get_descriptor)(uint8_t type, uint8_t index,
40    const uint8_t * const *reply, uint8_t *size);
41void (*user_reset)(void);
42
43
44void usb_io(struct ep_descr *ep, enum ep_state state, uint8_t *buf,
45    uint8_t size, void (*callback)(void *user), void *user)
46{
47    BUG_ON(ep->state);
48    ep->state = state;
49    ep->buf = buf;
50    ep->end = buf+size;
51    ep->callback = callback;
52    ep->user = user;
53}
54
55
56static int get_descriptor(uint8_t type, uint8_t index, uint16_t length)
57{
58    const uint8_t *reply;
59    uint8_t size;
60
61    switch (type) {
62    case USB_DT_DEVICE:
63        reply = device_descriptor;
64        size = reply[0];
65        break;
66    case USB_DT_CONFIG:
67        if (index)
68            return 0;
69        reply = config_descriptor;
70        size = reply[2];
71        break;
72    default:
73        if (!user_get_descriptor)
74            return 0;
75        if (!user_get_descriptor(type, index, &reply, &size))
76            return 0;
77    }
78    if (length < size)
79        size = length;
80    usb_send(&eps[0], reply, size, NULL, NULL);
81    return 1;
82}
83
84
85int handle_setup(const struct setup_request *setup)
86{
87    switch (setup->bmRequestType | setup->bRequest << 8) {
88
89    /*
90     * Device request
91     *
92     * See http://www.beyondlogic.org/usbnutshell/usb6.htm
93     */
94
95    case FROM_DEVICE(GET_STATUS):
96        if (setup->wLength != 2)
97            return 0;
98        usb_send(&eps[0], "\000", 2, NULL, NULL);
99        break;
100    case TO_DEVICE(CLEAR_FEATURE):
101        break;
102    case TO_DEVICE(SET_FEATURE):
103        return 0;
104    case TO_DEVICE(SET_ADDRESS):
105        set_addr(setup->wValue);
106        break;
107    case FROM_DEVICE(GET_DESCRIPTOR):
108        if (!get_descriptor(setup->wValue >> 8, setup->wValue,
109            setup->wLength))
110            return 0;
111        break;
112    case TO_DEVICE(SET_DESCRIPTOR):
113        return 0;
114    case FROM_DEVICE(GET_CONFIGURATION):
115        usb_send(&eps[0], "", 1, NULL, NULL);
116        break;
117    case TO_DEVICE(SET_CONFIGURATION):
118        if (setup->wValue != config_descriptor[5])
119            return 0;
120        break;
121
122    /*
123     * Interface request
124     */
125
126    case FROM_INTERFACE(GET_STATUS):
127        return 0;
128    case TO_INTERFACE(CLEAR_FEATURE):
129        return 0;
130    case TO_INTERFACE(SET_FEATURE):
131        return 0;
132    case FROM_INTERFACE(GET_INTERFACE):
133        return 0;
134    case TO_INTERFACE(SET_INTERFACE):
135        {
136            const uint8_t *interface_descriptor =
137                config_descriptor+9;
138
139            if (setup->wIndex != interface_descriptor[2] ||
140                setup->wValue != interface_descriptor[3])
141                return 0;
142        }
143        break;
144
145    /*
146     * Endpoint request
147     */
148
149    case FROM_ENDPOINT(GET_STATUS):
150        return 0;
151    case TO_ENDPOINT(CLEAR_FEATURE):
152        return 0;
153    case TO_ENDPOINT(SET_FEATURE):
154        return 0;
155    case FROM_ENDPOINT(SYNCH_FRAME):
156        return 0;
157
158    default:
159        if (!user_setup)
160            return 0;
161        return user_setup(setup);
162    }
163
164    return 1;
165}
atusb/fw/usb/usb.h
1/*
2 * fw/usb//usb.h - USB hardware setup and standard device requests
3 *
4 * Written 2008, 2009 by Werner Almesberger
5 * Copyright 2008, 2009 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#ifndef USB_H
15#define USB_H
16
17
18#include <stdint.h>
19
20
21/*
22 * Descriptor types
23 *
24 * Reuse libusb naming scheme (/usr/include/usb.h)
25 */
26
27#define USB_DT_DEVICE 1
28#define USB_DT_CONFIG 2
29#define USB_DT_STRING 3
30#define USB_DT_INTERFACE 4
31#define USB_DT_ENDPOINT 5
32
33/*
34 * Device classes
35 *
36 * Reuse libusb naming scheme (/usr/include/usb.h)
37 */
38
39#define USB_CLASS_PER_INTERFACE 0xfe
40#define USB_CLASS_VENDOR_SPEC 0xff
41
42/*
43 * Configuration attributes
44 */
45
46#define USB_ATTR_BUS_POWERED 0x80
47#define USB_ATTR_SELF_POWERED 0x40
48#define USB_ATTR_REMOTE_WAKEUP 0x20
49
50/*
51 * Setup request types
52 */
53
54#define TO_DEVICE(req) (0x00 | (req) << 8)
55#define FROM_DEVICE(req) (0x80 | (req) << 8)
56#define TO_INTERFACE(req) (0x01 | (req) << 8)
57#define FROM_INTERFACE(req) (0x81 | (req) << 8)
58#define TO_ENDPOINT(req) (0x02 | (req) << 8)
59#define FROM_ENDPOINT(req) (0x82 | (req) << 8)
60
61/*
62 * Setup requests
63 */
64
65#define GET_STATUS 0x00
66#define CLEAR_FEATURE 0x01
67#define SET_FEATURE 0x03
68#define SET_ADDRESS 0x05
69#define GET_DESCRIPTOR 0x06
70#define SET_DESCRIPTOR 0x07
71#define GET_CONFIGURATION 0x08
72#define SET_CONFIGURATION 0x09
73#define GET_INTERFACE 0x0a
74#define SET_INTERFACE 0x0b
75#define SYNCH_FRAME 0x0c
76
77
78/*
79 * Odd. sdcc seems to think "x" assumes the size of the destination, i.e.,
80 * uint8_t. Hence the cast.
81 */
82
83#define LE(x) ((uint16_t) (x) & 0xff), ((uint16_t) (x) >> 8)
84
85#define LO(x) (((uint8_t *) &(x))[0])
86#define HI(x) (((uint8_t *) &(x))[1])
87
88
89#ifdef LOW_SPEED
90#define EP0_SIZE 8
91#else
92#define EP0_SIZE 64
93#endif
94
95#define EP1_SIZE 64 /* simplify */
96
97
98enum ep_state {
99    EP_IDLE,
100    EP_RX,
101    EP_TX,
102    EP_STALL,
103};
104
105struct ep_descr {
106    enum ep_state state;
107    uint8_t *buf;
108    uint8_t *end;
109    uint8_t size;
110    void (*callback)(void *user);
111    void *user;
112};
113
114struct setup_request {
115    uint8_t bmRequestType;
116    uint8_t bRequest;
117    uint16_t wValue;
118    uint16_t wIndex;
119    uint16_t wLength;
120};
121
122
123extern const uint8_t device_descriptor[];
124extern const uint8_t config_descriptor[];
125extern struct ep_descr eps[];
126
127extern int (*user_setup)(const struct setup_request *setup);
128extern int (*user_get_descriptor)(uint8_t type, uint8_t index,
129    const uint8_t * const *reply, uint8_t *size);
130extern void (*user_reset)(void);
131
132
133#define usb_left(ep) ((ep)->end-(ep)->buf)
134#define usb_send(ep, buf, size, callback, user) \
135    usb_io(ep, EP_TX, (void *) buf, size, callback, user)
136#define usb_recv(ep, buf, size, callback, user) \
137    usb_io(ep, EP_RX, buf, size, callback, user)
138
139void usb_io(struct ep_descr *ep, enum ep_state state, uint8_t *buf,
140    uint8_t size, void (*callback)(void *user), void *user);
141
142int handle_setup(const struct setup_request *setup);
143int set_addr(uint8_t addr);
144void usb_init(void);
145void usb_poll(void);
146
147#endif /* !USB_H */
atusb/fw/version.h
1/*
2 * fw/version.h - Automatically generated version string
3 *
4 * Written 2008, 2011 by Werner Almesberger
5 * Copyright 2008, 2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#ifndef VERSION_H
15#define VERSION_H
16
17#include <stdint.h>
18
19
20extern const char *build_date;
21extern const uint16_t build_number;
22
23#endif /* !VERSION_H */
atusb/fw3/Makefile
1#
2# Makefile - Makefile of the ATUSB firmware
3#
4# Written 2010-2011 by Werner Almesberger
5# Copyright 2010-2011 by Werner Almesberger
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12
13SHELL = /bin/bash
14
15NAME = atusb
16
17CFLAGS = -g -Wall -Wextra -Wshadow -Werror -Wno-unused-parameter \
18     -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes
19
20CHIP=atmega32u2
21
22AVR_PREFIX = $(BIN_PATH) avr-
23CC = $(AVR_PREFIX)gcc
24OBJCOPY = $(AVR_PREFIX)objcopy
25#OBJDUMP = $(AVR_PREFIX)objdump
26
27USB_OBJS = usb.o atu2.o
28OBJS = atusb.o board.o spi.o descr.o ep0.o $(USB_OBJS)
29
30vpath %.c usb/
31
32CFLAGS += -I../fw/include -Iusb
33
34# ----- Verbosity control -----------------------------------------------------
35
36CC_normal := $(CC)
37BUILD_normal :=
38DEPEND_normal := $(CPP) $(CFLAGS) -MM -MG
39
40CC_quiet = @echo " CC " $@ && $(CC_normal)
41BUILD_quiet = @echo " BUILD " $@ && $(BUILD_normal)
42DEPEND_quiet = @$(DEPEND_normal)
43
44ifeq ($(V),1)
45    CC = $(CC_normal)
46    BUILD = $(BUILD_normal)
47    DEPEND = $(DEPEND_normal)
48else
49    CC = $(CC_quiet)
50    BUILD = $(BUILD_quiet)
51    DEPEND = $(DEPEND_quiet)
52endif
53
54# ----- Rules -----------------------------------------------------------------
55
56.PHONY: all clean upload prog version.c
57
58all: $(NAME).bin
59
60$(NAME).elf: $(OBJS)
61        $(MAKE) version.o
62        $(CC) $(CFLAGS) -mmcu=$(CHIP) -o $@ $(OBJS) version.o
63
64%.bin: %.elf
65        $(BUILD) $(OBJCOPY) -j .text -j .data -O binary $< $@
66        @echo "build #`cat .version`, `ls -l $@`"
67
68# ----- Cleanup ---------------------------------------------------------------
69
70clean:
71        rm -f $(NAME).bin $(NAME).elf $(OBJS) $(OBJS:.o=.d)
72        rm -f version.c version.d version.o
73
74# ----- Build version ---------------------------------------------------------
75
76version.c:
77        @if [ -f .version ]; then \
78            v=`cat .version`; \
79            expr $$v + 1 >.version; \
80        else \
81            echo 0 >.version; \
82        fi
83        @[ -s .version ] || echo 0 >.version
84        @echo '/* MACHINE-GENERATED. DO NOT EDIT ! */' >version.c
85        @echo '#include "version.h"' >>version.c
86        @echo "const char *build_date = \"`date`\";" >>version.c
87        @echo "const uint16_t build_number = `cat .version`;" \
88          >>version.c
89
90# ----- Dependencies ----------------------------------------------------------
91
92%.o: %.c
93        $(CC) $(CFLAGS) -mmcu=$(CHIP) -Os -c $<
94        $(DEPEND) $< | \
95          sed -e \
96            '/^\(.*:\)\? */{p;s///;s/ *\\\?$$/ /;s/ */:\n/g;H;}' \
97            -e '$${g;p;}' -e d >$*.d; \
98          [ "$${PIPESTATUS[*]}" = "0 0" ] || { rm -f $*.d; exit 1; }
99
100-include $(OBJS:.o=.d)
101
102# ----- Programming and device control ----------------------------------------
103
104upload: $(NAME).bin
105        scp $(NAME).bin jlime:
106
107prog:
108        ssh jlime avrdude -F -p $(CHIP) -c nanonote_atusb -e \
109          -U flash:w:$(NAME).bin:r \
110          -U lfuse:w:0x60:m # external clock, slow start-up
111
112on:
113        ssh jlime poke 0x10010318 4
114
115off:
116        ssh jlime poke 0x10010314 4
117
118reset:
119        ssh jlime poke 0x10010318 2048
120        ssh jlime poke 0x10010314 2048
atusb/fw3/README
1Requires very recent toolchain, because ATmega32U2 is relatively new.
2
3Building:
4
5make
6make upload prog
7
8
9Making the toolchain:
10
11# patches according to
12# http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=789527
13
14# some gcc prerequisites
15
16apt-get remove avr-libc gcc-avr binutils-avr
17apt-get install libmpfr-dev libmpc-dev
18
19# binutils
20
21wget http://ftp.gnu.org/gnu/binutils/binutils-2.21.tar.bz2
22tar xfj binutils-2.21.tar.bz2
23cd binutils-2.21
24./configure --target=avr --disable-nls
25make
26make install
27
28# gcc
29
30wget http://ftpmirror.gnu.org/gcc/gcc-4.5.2/gcc-4.5.2.tar.bz2
31wget -O gcc_452_avr.patch http://gcc.gnu.org/bugzilla/attachment.cgi?id=23050
32tar xfj gcc-4.5.2.tar.bz2
33cd gcc-4.5.2
34patch -p1 -s <../gcc_452_avr.patch
35mkdir obj-avr
36cd obj-avr
37../configure --target=avr --enable-languages=c \
38    --disable-nls --disable-libssp --with-dwarf2
39make
40make install
41
42wget http://download.savannah.gnu.org/releases/avr-libc/avr-libc-1.7.0.tar.bz2
43wget -O avr_libc_170.patch \
44  https://savannah.nongnu.org/support/download.php?file_id=21669
45tar xfj avr-libc-1.7.0.tar.bz2
46cd avr-libc-1.7.0
47patch -p0 -s <../avr_libc_170.patch
48./bootstrap # the automake at the end takes a while
49./configure --build=`./config.guess` --host=avr
50make
51make install
atusb/fw3/an/README
1workflow:
2
3- connect zprobe (note: it currently inverts because it didn't have any
4  other chips around. this may change later.)
5
6- capture the USB signals at an interesting moment with a sample rate of
7  50 MSa/s
8
9- zoom into the frame(s) of interest
10
11- download the data with
12  ./get.py
13
14- decode with
15  ./dec.py
16
17  For manual decoding, set the coders to D+ and D- (we need D- for SE0
18  and SE1 detection), then click on a rising clock edge left of the
19  packet and move the cursor to the right.
20
21- if there are problems with the clock, the analog signal and digital
22  signals derived from it can be examined after running dec.py with
23  ./plot
24
25  (Note that the digital zprobe hides any analog anomalies.)
atusb/fw3/an/dec.py
1#!/usr/bin/python
2
3from tmc.wave import *
4from tmc.dxplore import dxplore
5from tmc.decode import d_usb_stream
6
7
8#
9# Clock recovery: we assume that each change in the wave is triggered by a
10# clock edge. We know the clock's nominal period and resynchronize on each
11# edge. Additionally, we can obtain a list of times when a timing violation
12# has occurred.
13#
14# Note that the timing violations logic doesn't make much sense in its present
15# form, since it mainly measures noise (particularly if we're digitizing slow
16# edges) and not clock drift.
17#
18# A more useful metric would be accumulated error from some point of reference
19# or at least the timing of same edges, to eliminate (generally harmless) time
20# offsets introduced by digitizing.
21#
22# So it would probably make more sense for "recover" not to check for timing
23# violations at all, and leave this to more specialized functions.
24#
25def recover(self, period, min = None, max = None, t0 = None):
26    if t0 is None:
27    t0 = self.data[0]
28    v = not self.initial
29    res = []
30    violations = []
31    for t in self.data:
32    v = not v
33    if t <= t0:
34        continue
35    n = 0
36    while t0 < t-period/2:
37        res.append(t0)
38        t0 += period
39        n += 1
40    if min is not None:
41        if t0-t > n*min:
42        violations.append(t)
43    if max is not None:
44        if t-t0 > n*max:
45        violations.append(t)
46    t0 = t
47    return res, violations
48
49
50#
51# Load the analog waves saved by get.py
52#
53wv = waves()
54wv.load("_wv")
55
56#
57# Digitize the waves and save the result.
58#
59dp = wv[0].digitize(1.5, 1.8)
60dm = wv[1].digitize(1.5, 1.8)
61wv = waves(dp, dm, dp-dm)
62wv.save("_dig")
63
64#
65# Also record the differential signal.
66#
67wd = wv[1]-wv[0]
68dd = wd.digitize(-0.5, 0.5)
69wd.save("_diff")
70
71#
72# Run clock recovery on D+/D-. We only need one, but check both to be sure.
73#
74#p = 1/1.5e6
75p = 1/12e6
76dp_t, viol = recover(dp, p, p*0.9, p*1.1)
77print viol
78dm_t, viol = recover(dm, p, p*.9, p*1.1, t0 = dp.data[0])
79print viol
80
81#
82# Shift the clock by half a period, add a few periods to get steady state and
83# SE0s (if any), and then sample the data lines.
84#
85clk = map(lambda t: t+p/2, dp_t)
86clk.extend((clk[-1]+p, clk[-1]+2*p, clk[-1]+3*p))
87dp_bv = dp.get(clk)
88dm_bv = dm.get(clk)
89
90#
91# Save a wave with the recovered clock to make it easier to find the bits in
92# analog graphs.
93#
94dd.data = dp_t;
95dd.save("_clk")
96
97#
98# For decoding, we need a fake bit clock. We generate it by doubling each data
99# bit and generating a L->H transition during this bit.
100#
101dpd = []
102dmd = []
103dck = []
104
105# err, silly, seems that we've mixed up D+ and D- all over the place :-)
106print d_usb_stream(dm_bv[:], dp_bv[:])
107
108for v in dp_bv:
109    dpd.append(v)
110    dpd.append(v)
111    dck.append(0)
112    dck.append(1)
113
114for v in dm_bv:
115    dmd.append(v)
116    dmd.append(v)
117
118#
119# Display the reconstructed digital signal. Note that the absolute time is only
120# correct at the beginning and that relative time is only accurate over
121# intervals in which no significant clock resynchronization has occurred.
122#
123# In fact, dxplore should probably have an option to either turn off time
124# entirely or to display a user-provided time axis. The latter may be a bit
125# tricky to implement.
126#
127dxplore((dmd, dpd, dck), 0, p/2, labels = ("D+", "D-", "CLK"))
atusb/fw3/an/get.py
1#!/usr/bin/python
2
3from tmc.scope import rigol_ds1000c
4
5#-800, +1600
6s = rigol_ds1000c()
7#s.debug = False
8
9pos = s.hor.pos
10scale = s.hor.scale
11t0 = pos-scale*s.div_hor/2
12t1 = pos+scale*s.div_hor/2
13print t0, t1
14
15#zoom = 10
16#step = scale/s.samples_per_div/zoom
17#print step
18step = 4e-9
19step = 2e-9
20
21w = s.wave((s.ch[0], s.ch[1]), start = t0, end = t1, step = step)
22w[0] = 3.3-w[0]
23w[1] = 3.3-w[1]
24
25s.hor.pos = pos
26s.hor.scale = scale
27
28w[0].label = "D+";
29w[1].label = "D-";
30
31w.save("_wv")
atusb/fw3/an/plot
1#!/bin/sh
2#
3# Plot output of "dec"
4#
5gnuplot -persist <<EOF
6set style data lines
7plot "_wv" using 1:(\$2-4), \
8  "_dig" using 1:(\$2*3.3-4) lw 2, \
9  "_wv" using 1:3, \
10  "_dig" using 1:(\$3*3.3) lw 2, \
11  "_clk" using 1:(\$2+1) lt 7
12EOF
atusb/fw3/atusb.c
1/*
2 * fw/atusb.c - ATUSB initialization and main loop
3 *
4 * Written 2008-2011 by Werner Almesberger
5 * Copyright 2008-2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdint.h>
15
16#include <avr/io.h>
17
18#define F_CPU 8000000UL
19#include <util/delay.h>
20
21#include "usb.h"
22
23#include "board.h"
24#include "spi.h"
25#include "atusb/ep0.h"
26
27
28int main(void)
29{
30    board_init();
31    spi_init();
32    reset_rf();
33
34    /* now we should be at 8 MHz */
35
36#if 0
37    led(1);
38    _delay_ms(100);
39    led(0);
40#endif
41
42    usb_init();
43    ep0_init();
44
45    while (1)
46        usb_poll();
47}
atusb/fw3/board.c
1/*
2 * fw/board.c - Board-specific functions
3 *
4 * Written 2011 by Werner Almesberger
5 * Copyright 2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdint.h>
15
16#include <avr/io.h>
17#include <avr/interrupt.h>
18
19#define F_CPU 8000000UL
20#include <util/delay.h>
21
22#include "at86rf230.h"
23#include "board.h"
24#include "spi.h"
25
26
27static void set_clkm(void)
28{
29    /* switch CLKM to 8 MHz */
30
31    /*
32     * @@@ Note: Atmel advise against changing the external clock in
33     * mid-flight. We should therefore switch to the RC clock first, then
34     * crank up the external clock, and finally switch back to the external
35     * clock. The clock switching procedure is described in the ATmega32U2
36     * data sheet in secton 8.2.2.
37     */
38
39    spi_begin();
40    spi_send(AT86RF230_REG_WRITE | REG_TRX_CTRL_0);
41    spi_send(CLKM_CTRL_8MHz);
42    spi_end();
43}
44
45
46void reset_rf(void)
47{
48    /* AT86RF231 data sheet, 12.4.13, reset pulse width: 625 ns (min) */
49
50    CLR(nRST_RF);
51    _delay_us(1);
52    SET(nRST_RF);
53
54    /* 12.4.14: SPI access latency after reset: 625 ns (min) */
55
56    _delay_us(1);
57
58    /* we must restore TRX_CTRL_0 after each reset (9.6.4) */
59
60    set_clkm();
61}
62
63
64uint8_t read_irq(void)
65{
66    return PIN(IRQ_RF);
67}
68
69
70void led(int on)
71{
72    if (on)
73        SET(LED);
74    else
75        CLR(LED);
76}
77
78
79void panic(void)
80{
81    cli();
82    while (1) {
83        SET(LED);
84        _delay_ms(100);
85        CLR(LED);
86        _delay_ms(100);
87    }
88}
89
90
91void board_init(void)
92{
93    /* We start with a 1 MHz/8 clock. Disable the prescaler. */
94
95    CLKPR = 1 << CLKPCE;
96    CLKPR = 0;
97
98    /* set up all the outputs; default port value is 0 */
99
100    OUT(LED);
101    OUT(nRST_RF); /* resets the transceiver */
102    OUT(SLP_TR);
103}
atusb/fw3/board.h
1/*
2 * fw/board.h - Board-specific functions and definitions
3 *
4 * Written 2008-2010 by Werner Almesberger
5 * Copyright 2008-2010 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#ifndef BOARD_H
14#define BOARD_H
15
16#include <stdint.h>
17
18
19#define LED_PORT B
20#define LED_BIT 6
21#define nRST_RF_PORT C
22#define nRST_RF_BIT 7
23#define SLP_TR_PORT B
24#define SLP_TR_BIT 4
25
26#define SCLK_PORT D
27#define SCLK_BIT 5
28#define MOSI_PORT D
29#define MOSI_BIT 3
30
31#define MISO_PORT D
32#define MISO_BIT 2
33#define nSS_PORT D
34#define nSS_BIT 1
35#define IRQ_RF_PORT D
36#define IRQ_RF_BIT 0
37
38
39#define SET_2(p, b) PORT##p |= 1 << (b)
40#define CLR_2(p, b) PORT##p &= ~(1 << (b))
41#define IN_2(p, b) DDR##p &= ~(1 << (b))
42#define OUT_2(p, b) DDR##p |= 1 << (b)
43#define PIN_2(p, b) ((PIN##p >> (b)) & 1)
44
45#define SET_1(p, b) SET_2(p, b)
46#define CLR_1(p, b) CLR_2(p, b)
47#define IN_1(p, b) IN_2(p, b)
48#define OUT_1(p, b) OUT_2(p, b)
49#define PIN_1(p, b) PIN_2(p, b)
50
51#define SET(n) SET_1(n##_PORT, n##_BIT)
52#define CLR(n) CLR_1(n##_PORT, n##_BIT)
53#define IN(n) IN_1(n##_PORT, n##_BIT)
54#define OUT(n) OUT_1(n##_PORT, n##_BIT)
55#define PIN(n) PIN_1(n##_PORT, n##_BIT)
56
57
58void reset_rf(void);
59uint8_t read_irq(void);
60void led(int on);
61void panic(void);
62void board_init(void);
63
64#endif /* !BOARD_H */
atusb/fw3/descr.c
1/*
2 * fw/descr.c - USB descriptors
3 *
4 * Written 2008-2011 by Werner Almesberger
5 * Copyright 2008-2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include "usb.h"
15
16
17#define USB_VENDOR 0x20b7 /* Qi Hardware */
18#define USB_PRODUCT 0x1540 /* ben-wpan atusb */
19
20#define LE(x) ((uint16_t) (x) & 0xff), ((uint16_t) (x) >> 8)
21
22/*
23 * Device descriptor
24 */
25
26const uint8_t device_descriptor[18] = {
27    18, /* bLength */
28    USB_DT_DEVICE, /* bDescriptorType */
29    LE(0x200), /* bcdUSB */
30    USB_CLASS_VENDOR_SPEC, /* bDeviceClass */
31    0x00, /* bDeviceSubClass */
32    0x00, /* bDeviceProtocol */
33    EP0_SIZE, /* bMaxPacketSize */
34    LE(USB_VENDOR), /* idVendor */
35    LE(USB_PRODUCT), /* idProduct */
36    LE(0x0001), /* bcdDevice */
37    0, /* iManufacturer */
38    0, /* iProduct */
39    0, /* iSerialNumber */
40    1 /* bNumConfigurations */
41};
42
43
44/*
45 * Our configuration
46 *
47 * We're always bus-powered.
48 */
49
50const uint8_t config_descriptor[] = {
51    9, /* bLength */
52    USB_DT_CONFIG, /* bDescriptorType */
53#if 0
54    LE(9+9+7+7), /* wTotalLength */
55#else
56    LE(9+9), /* wTotalLength */
57#endif
58    1, /* bNumInterfaces */
59    1, /* bConfigurationValue (> 0 !) */
60    0, /* iConfiguration */
61    USB_ATTR_BUS_POWERED, /* bmAttributes */
62    50/2, /* bMaxPower (50 mA) */
63
64    /* Interface #0 */
65
66    9, /* bLength */
67    USB_DT_INTERFACE, /* bDescriptorType */
68    0, /* bInterfaceNumber */
69    0, /* bAlternateSetting */
70#if 0
71    2, /* bNumEndpoints */
72#else
73    0,
74#endif
75    USB_CLASS_VENDOR_SPEC, /* bInterfaceClass */
76    0, /* bInterfaceSubClass */
77    0, /* bInterfaceProtocol */
78    0, /* iInterface */
79
80#if 0
81    /* EP OUT */
82
83    7, /* bLength */
84    USB_DT_ENDPOINT, /* bDescriptorType */
85    0x01, /* bEndPointAddress */
86    0x02, /* bmAttributes (bulk) */
87    LE(EP1_SIZE), /* wMaxPacketSize */
88    0, /* bInterval */
89
90    /* EP IN */
91
92    7, /* bLength */
93    USB_DT_ENDPOINT, /* bDescriptorType */
94    0x81, /* bEndPointAddress */
95    0x02, /* bmAttributes (bulk) */
96    LE(EP1_SIZE), /* wMaxPacketSize */
97    0, /* bInterval */
98#endif
99};
atusb/fw3/ep0.c
1/*
2 * fw/ep0.c - EP0 extension protocol
3 *
4 * Written 2008-2011 by Werner Almesberger
5 * Copyright 2008-2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdint.h>
15
16#include <avr/io.h>
17
18#ifndef NULL
19#define NULL 0
20#endif
21
22#include "usb.h"
23
24#include "at86rf230.h"
25#include "atusb/ep0.h"
26#include "version.h"
27#include "board.h"
28#include "spi.h"
29
30
31#define HW_TYPE HW_TYPE_110131
32
33#define debug(...)
34#define error(...)
35
36
37static const uint8_t id[] = { EP0ATUSB_MAJOR, EP0ATUSB_MINOR, HW_TYPE };
38static uint8_t buf[MAX_PSDU+3]; /* command, PHDR, and LQI */
39static uint8_t size;
40
41
42static void do_buf_write(void *user)
43{
44    uint8_t i;
45
46    spi_begin();
47    for (i = 0; i != size; i++)
48        spi_send(buf[i]);
49    spi_end();
50}
51
52
53#define BUILD_OFFSET 7 /* '#' plus "65535" plus ' ' */
54
55
56static int my_setup(const struct setup_request *setup)
57{
58    unsigned tmp;
59    uint8_t i;
60
61    switch (setup->bmRequestType | setup->bRequest << 8) {
62    case ATUSB_FROM_DEV(ATUSB_ID):
63        debug("ATUSB_ID\n");
64        if (setup->wLength > 3)
65            return 0;
66        usb_send(&eps[0], id, setup->wLength, NULL, NULL);
67        return 1;
68    case ATUSB_FROM_DEV(ATUSB_BUILD):
69        debug("ATUSB_BUILD\n");
70        tmp = build_number;
71        for (i = BUILD_OFFSET-2; tmp; i--) {
72            buf[i] = (tmp % 10)+'0';
73            tmp /= 10;
74        }
75        buf[i] = '#';
76        buf[BUILD_OFFSET-1] = ' ';
77        for (size = 0; build_date[size]; size++)
78            buf[BUILD_OFFSET+size] = build_date[size];
79        size += BUILD_OFFSET-i;
80        if (size > setup->wLength)
81            return 0;
82        usb_send(&eps[0], buf+i, size, NULL, NULL);
83        return 1;
84
85#ifdef NOTYET
86    case ATUSB_TO_DEV(ATUSB_RESET):
87        debug("ATUSB_RESET\n");
88        RSTSRC = SWRSF;
89        while (1);
90#endif
91
92    case ATUSB_TO_DEV(ATUSB_RF_RESET):
93        debug("ATUSB_RF_RESET\n");
94        reset_rf();
95        //ep_send_zlp(EP_CTRL);
96        return 1;
97
98    case ATUSB_FROM_DEV(ATUSB_POLL_INT):
99        debug("ATUSB_POLL_INT\n");
100        if (setup->wLength < 1)
101            return 0;
102        *buf = read_irq();
103        usb_send(&eps[0], buf, 1, NULL, NULL);
104        return 1;
105
106    case ATUSB_TO_DEV(ATUSB_REG_WRITE):
107        debug("ATUSB_REG_WRITE\n");
108        spi_begin();
109        spi_send(AT86RF230_REG_WRITE | setup->wIndex);
110        spi_send(setup->wValue);
111        spi_end();
112        //ep_send_zlp(EP_CTRL);
113        return 1;
114    case ATUSB_FROM_DEV(ATUSB_REG_READ):
115        debug("ATUSB_REG_READ\n");
116        spi_begin();
117        spi_send(AT86RF230_REG_READ | setup->wIndex);
118        *buf = spi_recv();
119        spi_end();
120        usb_send(&eps[0], buf, 1, NULL, NULL);
121        return 1;
122
123    case ATUSB_TO_DEV(ATUSB_BUF_WRITE):
124        debug("ATUSB_BUF_WRITE\n");
125        if (setup->wLength < 1)
126            return 0;
127        if (setup->wLength > MAX_PSDU)
128            return 0;
129        buf[0] = AT86RF230_BUF_WRITE;
130        buf[1] = setup->wLength;
131        size = setup->wLength+2;
132        usb_recv(&eps[0], buf+2, setup->wLength, do_buf_write, NULL);
133        return 1;
134    case ATUSB_FROM_DEV(ATUSB_BUF_READ):
135        debug("ATUSB_BUF_READ\n");
136        if (setup->wLength < 2) /* PHR+LQI */
137            return 0;
138        if (setup->wLength > MAX_PSDU+2) /* PHR+PSDU+LQI */
139            return 0;
140        spi_begin();
141        spi_send(AT86RF230_BUF_READ);
142        size = spi_recv();
143        if (size >= setup->wLength)
144            size = setup->wLength-1;
145        for (i = 0; i != size+1; i++)
146            buf[i] = spi_recv();
147        spi_end();
148        usb_send(&eps[0], buf, size+1, NULL, NULL);
149        return 1;
150
151    case ATUSB_TO_DEV(ATUSB_SRAM_WRITE):
152        debug("ATUSB_SRAM_WRITE\n");
153        if (setup->wIndex > SRAM_SIZE)
154            return 0;
155        if (setup->wIndex+setup->wLength > SRAM_SIZE)
156            return 0;
157        buf[0] = AT86RF230_SRAM_WRITE;
158        buf[1] = setup->wIndex;
159        size = setup->wLength+2;
160        usb_recv(&eps[0], buf+2, setup->wLength, do_buf_write, NULL);
161        return 1;
162    case ATUSB_TO_DEV(ATUSB_SRAM_READ):
163        debug("ATUSB_SRAM_READ\n");
164        if (setup->wIndex > SRAM_SIZE)
165            return 0;
166        if (setup->wIndex+setup->wLength > SRAM_SIZE)
167            return 0;
168        spi_begin();
169        spi_send(AT86RF230_SRAM_READ);
170        spi_send(setup->wIndex);
171        for (i = 0; i != size; i++)
172            buf[i] = spi_recv();
173        spi_end();
174        usb_send(&eps[0], buf, size, NULL, NULL);
175        return 1;
176
177    default:
178        error("Unrecognized SETUP: 0x%02x 0x%02x ...\n",
179            setup->bmRequestType, setup->bRequest);
180        return 0;
181    }
182}
183
184
185void ep0_init(void)
186{
187    user_setup = my_setup;
188}
atusb/fw3/spi.c
1/*
2 * fw/spi.c - ATmega8 family SPI I/O
3 *
4 * Written 2011 by Werner Almesberger
5 * Copyright 2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdint.h>
15
16#include <avr/io.h>
17
18#include "board.h"
19#include "spi.h"
20
21
22void spi_begin(void)
23{
24    CLR(nSS);
25}
26
27
28uint8_t spi_io(uint8_t v)
29{
30// while (!(UCSR1A & 1 << UDRE1));
31        UDR1 = v;
32        while (!(UCSR1A & 1 << RXC1));
33        return UDR1;
34}
35
36
37void spi_end(void)
38{
39// while (!(UCSR1A & 1 << TXC1));
40    SET(nSS);
41}
42
43
44void spi_init(void)
45{
46    SET(nSS);
47    OUT(SCLK);
48    OUT(MOSI);
49    OUT(nSS);
50    IN(MISO);
51
52    UBRR1 = 0; /* set bit rate to zero to begin */
53    UCSR1C = 1 << UMSEL11 | 1 << UMSEL10;
54            /* set MSPI, MSB first, SPI data mode 0 */
55    UCSR1B = 1 << RXEN1 | 1 << TXEN1;
56            /* enable receiver and transmitter */
57    UBRR1 = 0; /* reconfirm the bit rate */
58}
atusb/fw3/spi.h
1/*
2 * fw/spi.h - ATmega8 family SPI I/O
3 *
4 * Written 2011 by Werner Almesberger
5 * Copyright 2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#ifndef SPI_H
14#define SPI_H
15
16#include <stdint.h>
17
18
19void spi_begin(void);
20uint8_t spi_io(uint8_t v);
21void spi_end(void);
22void spi_init(void);
23
24#define spi_send(v) (void) spi_io(v)
25#define spi_recv(v) spi_io(0)
26
27#endif /* !SPI_H */
atusb/fw3/usb/atu2.c
1/*
2 * fw/usb/atu2.c - Chip-specific driver for Atmel ATxxxU2 USB chips
3 *
4 * Written 2008-2011 by Werner Almesberger
5 * Copyright 2008-2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13/*
14 * Known issues:
15 * - no suspend/resume
16 * - we don't call back after failed transmissions,
17 * - we don't reset the EP buffer after failed receptions
18 * - enumeration often encounters an error -71 (from which it recovers)
19 */
20
21#include <stdint.h>
22
23#define F_CPU 8000000UL
24#include <util/delay.h>
25
26#include <avr/io.h>
27#include "usb.h"
28#include "../board.h"
29
30
31#ifndef NULL
32#define NULL 0
33#endif
34
35#if 1
36#define BUG_ON(cond) do { if (cond) panic(); } while (0)
37#else
38#define BUG_ON(cond)
39#endif
40
41
42#define NUM_EPS 1
43
44
45struct ep_descr eps[NUM_EPS];
46
47
48static uint16_t usb_read_word(void)
49{
50    uint8_t low;
51
52    low = UEDATX;
53    return low | UEDATX << 8;
54}
55
56
57static void enable_addr(void *user)
58{
59    while (!(UEINTX & (1 << TXINI)));
60    UDADDR |= 1 << ADDEN;
61}
62
63
64int set_addr(uint8_t addr)
65{
66    UDADDR = addr;
67    usb_send(&eps[0], NULL, 0, enable_addr, NULL);
68    return 1;
69}
70
71
72static int ep_setup(void)
73{
74    struct setup_request setup;
75
76    BUG_ON(UEBCLX < 8);
77
78    setup.bmRequestType = UEDATX;
79    setup.bRequest = UEDATX;
80    setup.wValue = usb_read_word();
81    setup.wIndex = usb_read_word();
82    setup.wLength = usb_read_word();
83
84    if (!handle_setup(&setup))
85        return 0;
86    if (!(setup.bmRequestType & 0x80) && eps[0].state == EP_IDLE)
87        usb_send(&eps[0], NULL, 0, NULL, NULL);
88    return 1;
89}
90
91
92static int ep_rx(struct ep_descr *ep)
93{
94    uint8_t size;
95
96    size = UEBCLX;
97    if (size > ep->end-ep->buf)
98        return 0;
99    while (size--)
100        *ep->buf++ = UEDATX;
101    if (ep->buf == ep->end) {
102        ep->state = EP_IDLE;
103        if (ep->callback)
104            ep->callback(ep->user);
105        if (ep == &eps[0])
106            usb_send(ep, NULL, 0, NULL, NULL);
107    }
108    return 1;
109}
110
111
112static void ep_tx(struct ep_descr *ep)
113{
114    uint8_t size = ep->end-ep->buf;
115    uint8_t left;
116
117    if (size > ep->size)
118        size = ep->size;
119    for (left = size; left; left--)
120        UEDATX = *ep->buf++;
121    if (size == ep->size)
122        return;
123    ep->state = EP_IDLE;
124}
125
126
127static void handle_ep(int n)
128{
129    struct ep_descr *ep = eps+n;
130
131    UENUM = n;
132    if (UEINTX & (1 << RXSTPI)) {
133        /* @@@ EP_RX. EP_TX: cancel */
134        if (!ep_setup())
135            goto stall;
136        UEINTX &= ~(1 << RXSTPI);
137    }
138    if (UEINTX & (1 << RXOUTI)) {
139        /* @@ EP_TX: cancel */
140        if (ep->state != EP_RX)
141            goto stall;
142        if (!ep_rx(ep))
143            goto stall;
144// UEINTX &= ~(1 << RXOUTI);
145        UEINTX &= ~(1 << RXOUTI | 1 << FIFOCON);
146    }
147    if (UEINTX & (1 << STALLEDI)) {
148        ep->state = EP_IDLE;
149        UEINTX &= ~(1 << STALLEDI);
150    }
151    if (UEINTX & (1 << TXINI)) {
152        /* @@ EP_RX: cancel */
153        if (ep->state == EP_TX) {
154            ep_tx(ep);
155            UEINTX &= ~(1 << TXINI);
156            if (ep->state == EP_IDLE && ep->callback)
157                ep->callback(ep->user);
158        }
159    }
160    return;
161
162stall:
163    UEINTX &= ~(1 << RXSTPI | 1 << RXOUTI | 1 << STALLEDI);
164    ep->state = EP_IDLE;
165    UECONX |= 1 << STALLRQ;
166}
167
168
169void usb_poll(void)
170{
171    uint8_t flags, i;
172
173    flags = UEINT;
174    for (i = 0; i != NUM_EPS; i++)
175        if (1 || flags & (1 << i))
176            handle_ep(i);
177    /* @@@ USB bus reset */
178}
179
180
181static void ep_init(void)
182{
183    UENUM = 0;
184    UECONX = (1 << RSTDT) | (1 << EPEN); /* enable */
185    UECFG0X = 0; /* control, direction is ignored */
186    UECFG1X = 3 << EPSIZE0; /* 64 bytes */
187    UECFG1X |= 1 << ALLOC;
188
189    while (!(UESTA0X & (1 << CFGOK)));
190
191    eps[0].state = EP_IDLE;
192    eps[0].size = 64;
193}
194
195
196void usb_init(void)
197{
198    USBCON |= 1 << FRZCLK; /* freeze the clock */
199
200    /* enable the PLL and wait for it to lock */
201    PLLCSR &= ~(1 << PLLP2 | 1 << PLLP1 | 1 << PLLP0);
202    PLLCSR |= 1 << PLLE;
203    while (!(PLLCSR & (1 << PLOCK)));
204
205    USBCON &= ~(1 << USBE); /* reset the controller */
206    USBCON |= 1 << USBE;
207
208    USBCON &= ~(1 << FRZCLK); /* thaw the clock */
209
210    UDCON &= ~(1 << DETACH); /* attach the pull-up */
211    UDCON |= 1 << RSTCPU; /* reset CPU on bus reset */
212
213    ep_init();
214}
atusb/fw3/usb/usb.c
1/*
2 * fw/usb/usb.c - USB hardware setup and standard device requests
3 *
4 * Written 2008-2011 by Werner Almesberger
5 * Copyright 2008-2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13/*
14 * Known issues:
15 * - no suspend/resume
16 * - should support EP clearing and stalling
17 */
18
19#include <stdint.h>
20
21#include "usb.h"
22#include "../board.h"
23
24
25#ifndef NULL
26#define NULL 0
27#endif
28
29#define NUM_EPS 1
30
31#if 1
32extern void panic(void);
33#define BUG_ON(cond) do { if (cond) panic(); } while (0)
34#else
35#define BUG_ON(cond)
36#endif
37
38int (*user_setup)(const struct setup_request *setup);
39int (*user_get_descriptor)(uint8_t type, uint8_t index,
40    const uint8_t * const *reply, uint8_t *size);
41void (*user_reset)(void);
42
43
44void usb_io(struct ep_descr *ep, enum ep_state state, uint8_t *buf,
45    uint8_t size, void (*callback)(void *user), void *user)
46{
47    BUG_ON(ep->state);
48    ep->state = state;
49    ep->buf = buf;
50    ep->end = buf+size;
51    ep->callback = callback;
52    ep->user = user;
53}
54
55
56static int get_descriptor(uint8_t type, uint8_t index, uint16_t length)
57{
58    const uint8_t *reply;
59    uint8_t size;
60
61    switch (type) {
62    case USB_DT_DEVICE:
63        reply = device_descriptor;
64        size = reply[0];
65        break;
66    case USB_DT_CONFIG:
67        if (index)
68            return 0;
69        reply = config_descriptor;
70        size = reply[2];
71        break;
72    default:
73        if (!user_get_descriptor)
74            return 0;
75        if (!user_get_descriptor(type, index, &reply, &size))
76            return 0;
77    }
78    if (length < size)
79        size = length;
80    usb_send(&eps[0], reply, size, NULL, NULL);
81    return 1;
82}
83
84
85int handle_setup(const struct setup_request *setup)
86{
87    switch (setup->bmRequestType | setup->bRequest << 8) {
88
89    /*
90     * Device request
91     *
92     * See http://www.beyondlogic.org/usbnutshell/usb6.htm
93     */
94
95    case FROM_DEVICE(GET_STATUS):
96        if (setup->wLength != 2)
97            return 0;
98        usb_send(&eps[0], "\000", 2, NULL, NULL);
99        break;
100    case TO_DEVICE(CLEAR_FEATURE):
101        break;
102    case TO_DEVICE(SET_FEATURE):
103        return 0;
104    case TO_DEVICE(SET_ADDRESS):
105        set_addr(setup->wValue);
106        break;
107    case FROM_DEVICE(GET_DESCRIPTOR):
108        if (!get_descriptor(setup->wValue >> 8, setup->wValue,
109            setup->wLength))
110            return 0;
111        break;
112    case TO_DEVICE(SET_DESCRIPTOR):
113        return 0;
114    case FROM_DEVICE(GET_CONFIGURATION):
115        usb_send(&eps[0], "", 1, NULL, NULL);
116        break;
117    case TO_DEVICE(SET_CONFIGURATION):
118        if (setup->wValue != config_descriptor[5])
119            return 0;
120        break;
121
122    /*
123     * Interface request
124     */
125
126    case FROM_INTERFACE(GET_STATUS):
127        return 0;
128    case TO_INTERFACE(CLEAR_FEATURE):
129        return 0;
130    case TO_INTERFACE(SET_FEATURE):
131        return 0;
132    case FROM_INTERFACE(GET_INTERFACE):
133        return 0;
134    case TO_INTERFACE(SET_INTERFACE):
135        {
136            const uint8_t *interface_descriptor =
137                config_descriptor+9;
138
139            if (setup->wIndex != interface_descriptor[2] ||
140                setup->wValue != interface_descriptor[3])
141                return 0;
142        }
143        break;
144
145    /*
146     * Endpoint request
147     */
148
149    case FROM_ENDPOINT(GET_STATUS):
150        return 0;
151    case TO_ENDPOINT(CLEAR_FEATURE):
152        return 0;
153    case TO_ENDPOINT(SET_FEATURE):
154        return 0;
155    case FROM_ENDPOINT(SYNCH_FRAME):
156        return 0;
157
158    default:
159        if (!user_setup)
160            return 0;
161        return user_setup(setup);
162    }
163
164    return 1;
165}
atusb/fw3/usb/usb.h
1/*
2 * fw/usb//usb.h - USB hardware setup and standard device requests
3 *
4 * Written 2008, 2009 by Werner Almesberger
5 * Copyright 2008, 2009 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#ifndef USB_H
15#define USB_H
16
17
18#include <stdint.h>
19
20
21/*
22 * Descriptor types
23 *
24 * Reuse libusb naming scheme (/usr/include/usb.h)
25 */
26
27#define USB_DT_DEVICE 1
28#define USB_DT_CONFIG 2
29#define USB_DT_STRING 3
30#define USB_DT_INTERFACE 4
31#define USB_DT_ENDPOINT 5
32
33/*
34 * Device classes
35 *
36 * Reuse libusb naming scheme (/usr/include/usb.h)
37 */
38
39#define USB_CLASS_PER_INTERFACE 0xfe
40#define USB_CLASS_VENDOR_SPEC 0xff
41
42/*
43 * Configuration attributes
44 */
45
46#define USB_ATTR_BUS_POWERED 0x80
47#define USB_ATTR_SELF_POWERED 0x40
48#define USB_ATTR_REMOTE_WAKEUP 0x20
49
50/*
51 * Setup request types
52 */
53
54#define TO_DEVICE(req) (0x00 | (req) << 8)
55#define FROM_DEVICE(req) (0x80 | (req) << 8)
56#define TO_INTERFACE(req) (0x01 | (req) << 8)
57#define FROM_INTERFACE(req) (0x81 | (req) << 8)
58#define TO_ENDPOINT(req) (0x02 | (req) << 8)
59#define FROM_ENDPOINT(req) (0x82 | (req) << 8)
60
61/*
62 * Setup requests
63 */
64
65#define GET_STATUS 0x00
66#define CLEAR_FEATURE 0x01
67#define SET_FEATURE 0x03
68#define SET_ADDRESS 0x05
69#define GET_DESCRIPTOR 0x06
70#define SET_DESCRIPTOR 0x07
71#define GET_CONFIGURATION 0x08
72#define SET_CONFIGURATION 0x09
73#define GET_INTERFACE 0x0a
74#define SET_INTERFACE 0x0b
75#define SYNCH_FRAME 0x0c
76
77
78/*
79 * Odd. sdcc seems to think "x" assumes the size of the destination, i.e.,
80 * uint8_t. Hence the cast.
81 */
82
83#define LE(x) ((uint16_t) (x) & 0xff), ((uint16_t) (x) >> 8)
84
85#define LO(x) (((uint8_t *) &(x))[0])
86#define HI(x) (((uint8_t *) &(x))[1])
87
88
89#ifdef LOW_SPEED
90#define EP0_SIZE 8
91#else
92#define EP0_SIZE 64
93#endif
94
95#define EP1_SIZE 64 /* simplify */
96
97
98enum ep_state {
99    EP_IDLE,
100    EP_RX,
101    EP_TX,
102    EP_STALL,
103};
104
105struct ep_descr {
106    enum ep_state state;
107    uint8_t *buf;
108    uint8_t *end;
109    uint8_t size;
110    void (*callback)(void *user);
111    void *user;
112};
113
114struct setup_request {
115    uint8_t bmRequestType;
116    uint8_t bRequest;
117    uint16_t wValue;
118    uint16_t wIndex;
119    uint16_t wLength;
120};
121
122
123extern const uint8_t device_descriptor[];
124extern const uint8_t config_descriptor[];
125extern struct ep_descr eps[];
126
127extern int (*user_setup)(const struct setup_request *setup);
128extern int (*user_get_descriptor)(uint8_t type, uint8_t index,
129    const uint8_t * const *reply, uint8_t *size);
130extern void (*user_reset)(void);
131
132
133#define usb_left(ep) ((ep)->end-(ep)->buf)
134#define usb_send(ep, buf, size, callback, user) \
135    usb_io(ep, EP_TX, (void *) buf, size, callback, user)
136#define usb_recv(ep, buf, size, callback, user) \
137    usb_io(ep, EP_RX, buf, size, callback, user)
138
139void usb_io(struct ep_descr *ep, enum ep_state state, uint8_t *buf,
140    uint8_t size, void (*callback)(void *user), void *user);
141
142int handle_setup(const struct setup_request *setup);
143int set_addr(uint8_t addr);
144void usb_init(void);
145void usb_poll(void);
146
147#endif /* !USB_H */
atusb/fw3/version.h
1/*
2 * fw/version.h - Automatically generated version string
3 *
4 * Written 2008, 2011 by Werner Almesberger
5 * Copyright 2008, 2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#ifndef VERSION_H
15#define VERSION_H
16
17#include <stdint.h>
18
19
20extern const char *build_date;
21extern const uint16_t build_number;
22
23#endif /* !VERSION_H */

Archive Download the corresponding diff file



interactive