Compare commits

..

4 Commits

Author SHA1 Message Date
13cd30069d Make more like atmega32u2 branch 2012-10-12 14:15:42 -04:00
1a780ac319 Fix makefile baudrate for 8u2 2012-10-12 14:13:47 -04:00
71d0b686d0 Fix makefile indentation 2012-10-12 14:11:36 -04:00
15806b6571 Makefile for atmega8u2, programmed by bus pirate
Conflicts:
	Makefile
2012-10-08 16:23:16 -04:00
5 changed files with 500 additions and 524 deletions

View File

@ -1,9 +1,9 @@
MCU = at90usb1287
MCU = atmega8u2
ARCH = AVR8
BOARD = USER
F_CPU = 8000000
F_USB = 8000000
OPTIMIZATION = 3
F_CPU = 16000000
F_USB = 16000000
OPTIMIZATION = s
TARGET = main
LUFA_PATH = lufa/LUFA
CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -Iconfig/ -Wall
@ -25,9 +25,13 @@ DEVICE = /dev/serial/by-id/usb-LUFA_FT232_*
# Open terminal on USB port
term:
terminal.py $(DEVICE)
python terminal.py $(DEVICE)
.PHONY: term
AVRDUDE_PROGRAMMER := buspirate
AVRDUDE_PORT := /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AH00S82Y-if00-port0
AVRDUDE_FLAGS := -V
# Include LUFA build script makefiles
include $(LUFA_PATH)/Build/lufa_sources.mk
include $(LUFA_PATH)/Build/lufa_build.mk
@ -41,3 +45,6 @@ $(LUFA_PATH)/Build/lufa_core.mk:
# Remove some stuff from BASE_CC_FLAGS that the LUFA core put in there.
BASE_CC_FLAGS := $(filter-out -fno-inline-small-functions,$(BASE_CC_FLAGS))
prog: main.hex
avrdude -p atmega8u2 -P /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AH00S82Y-if00-port0 -c buspirate -V -U flash:w:main.hex

267
ftdi.c
View File

@ -8,8 +8,8 @@
#include "queue.h"
/* TX and RX queues */
volatile static uint8_t ftdi_txqueue_buf[FTDI_TX_QUEUE_LEN];
volatile static uint8_t ftdi_rxqueue_buf[FTDI_RX_QUEUE_LEN];
static uint8_t ftdi_txqueue_buf[FTDI_TX_QUEUE_LEN];
static uint8_t ftdi_rxqueue_buf[FTDI_RX_QUEUE_LEN];
struct queue ftdi_txqueue =
QUEUE_INITIALIZER(ftdi_txqueue_buf, sizeof(ftdi_txqueue_buf));
struct queue ftdi_rxqueue =
@ -35,7 +35,7 @@ static const uint8_t ftdi_eeprom[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0xa5
};
volatile static struct ftdi_status {
static struct ftdi_status {
/* modem status */
unsigned reserved_1:1;
unsigned reserved_0:3;
@ -55,28 +55,13 @@ volatile static struct ftdi_status {
unsigned fifoerr:1;
} ftdi_status = { 0 };
volatile static struct ctrl_status {
static struct ctrl_status {
unsigned dtr:1;
unsigned rts:1;
} ctrl_status = { 0 };
static bool ftdi_onlcr = false; /* Translate \n to \r\n, like stty "onlcr" */
static bool ftdi_blocking_in = false;
static bool ftdi_blocking_out = false;
static bool ftdi_delay_init_tx = false;
volatile bool got_setbaudrate;
volatile bool got_first_rx;
#define WAIT_FRAMES 250
volatile uint8_t frames_since_setbaudrate;
volatile uint8_t latency_timer = 16;
volatile uint8_t latency_count = 0;
/* Fdev compatible wrappers */
static int ftdi_fdev_write(char c, FILE *stream) {
if (ftdi_onlcr && c == '\n')
ftdi_putchar('\r');
ftdi_putchar(c);
return 0;
}
@ -87,38 +72,22 @@ static FILE _ftdi_stream =
FDEV_SETUP_STREAM(ftdi_fdev_write, ftdi_fdev_read, _FDEV_SETUP_RW);
FILE *ftdi_stream = &_ftdi_stream;
static void reset_internal_state(void)
/* Init */
static bool ftdi_blocking_in = false;
static bool ftdi_blocking_out = false;
void ftdi_init(int flags)
{
/* Disable endpoint interrupts */
UEIENX &= ~(1 << RXOUTE);
UEIENX &= ~(1 << TXINE);
/* Reset flags for ftdi_init_track_tx */
got_setbaudrate = false;
got_first_rx = false;
frames_since_setbaudrate = 0;
/* Latency timer */
latency_timer = 16;
latency_count = 0;
/* Reset line state */
ftdi_status = (struct ftdi_status) { 0 };
memset(&ftdi_status, 0, sizeof(struct ftdi_status));
ftdi_status.reserved_1 = 1;
ftdi_status.cts = 1;
ftdi_status.dsr = 1;
ftdi_status.ri = 0;
ftdi_status.cd = 1;
ctrl_status = (struct ctrl_status) { 0 };
memset(&ctrl_status, 0, sizeof(struct ctrl_status));
ctrl_status.dtr = 0;
ctrl_status.rts = 0;
}
/* Init */
void ftdi_init(int flags)
{
reset_internal_state();
if (flags & FTDI_STDIO) {
stdout = ftdi_stream;
@ -129,17 +98,11 @@ void ftdi_init(int flags)
ftdi_blocking_in = true;
if (flags & FTDI_BLOCKING_OUT)
ftdi_blocking_out = true;
if (flags & FTDI_ONLCR)
ftdi_onlcr = true;
if (flags & FTDI_DELAY_INIT_TX)
ftdi_delay_init_tx = true;
USB_Device_EnableSOFEvents();
}
static inline void ftdi_control_request(void)
{
uint16_t val;
uint16_t x;
if (!Endpoint_IsSETUPReceived())
return;
@ -151,68 +114,50 @@ static inline void ftdi_control_request(void)
switch (USB_ControlRequest.bRequest) {
case SIO_RESET_REQUEST:
/* Reset */
switch (USB_ControlRequest.wValue) {
case SIO_RESET_SIO:
ctrl_status.dtr = 0;
ctrl_status.rts = 0;
ftdi_init(0);
break;
case SIO_RESET_PURGE_RX:
while (_queue_can_get(&ftdi_rxqueue))
(void)_queue_get(&ftdi_rxqueue);
break;
case SIO_RESET_PURGE_TX:
while (_queue_can_get(&ftdi_txqueue))
(void)_queue_get(&ftdi_txqueue);
ftdi_status.temt = 1;
break;
}
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
return;
case SIO_READ_EEPROM_REQUEST:
/* Return fake EEPROM data */
val = (USB_ControlRequest.wIndex & 0xff) * 2;
if (val + USB_ControlRequest.wLength > sizeof(ftdi_eeprom))
x = (USB_ControlRequest.wIndex & 0xff) * 2;
if (x + USB_ControlRequest.wLength > sizeof(ftdi_eeprom))
return;
Endpoint_ClearSETUP();
Endpoint_Write_Control_Stream_LE((uint8_t *)&ftdi_eeprom[val],
Endpoint_Write_Control_Stream_LE((uint8_t *)&ftdi_eeprom[x],
USB_ControlRequest.wLength);
Endpoint_ClearStatusStage();
return;
case SIO_SET_BAUDRATE_REQUEST:
got_setbaudrate = true;
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
return;
case SIO_WRITE_EEPROM_REQUEST:
case SIO_ERASE_EEPROM_REQUEST:
case SIO_SET_BAUDRATE_REQUEST:
case SIO_SET_DATA_REQUEST:
case SIO_SET_FLOW_CTRL_REQUEST:
case SIO_SET_EVENT_CHAR_REQUEST:
case SIO_SET_ERROR_CHAR_REQUEST:
case SIO_SET_LATENCY_TIMER_REQUEST:
case SIO_SET_BITMODE_REQUEST:
/* Ignore these */
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
return;
case SIO_SET_LATENCY_TIMER_REQUEST:
val = USB_ControlRequest.wValue;
if (val >= 1 && val <= 255) {
latency_timer = val;
latency_count = 0;
}
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
return;
case SIO_SET_MODEM_CTRL_REQUEST:
if (USB_ControlRequest.wValue & SIO_SET_DTR_HIGH)
ctrl_status.dtr = 1;
@ -227,11 +172,12 @@ static inline void ftdi_control_request(void)
return;
case SIO_GET_LATENCY_TIMER_REQUEST:
/* Return dummy value */
if (USB_ControlRequest.wLength != 1)
return;
Endpoint_ClearSETUP();
val = latency_timer;
Endpoint_Write_Control_Stream_LE((uint8_t *)&val, 1);
x = 100;
Endpoint_Write_Control_Stream_LE((uint8_t *)&x, 1);
Endpoint_ClearStatusStage();
return;
@ -240,8 +186,8 @@ static inline void ftdi_control_request(void)
if (USB_ControlRequest.wLength != 1)
return;
Endpoint_ClearSETUP();
val = 0;
Endpoint_Write_Control_Stream_LE((uint8_t *)&val, 1);
x = 0;
Endpoint_Write_Control_Stream_LE((uint8_t *)&x, 1);
Endpoint_ClearStatusStage();
return;
@ -264,7 +210,7 @@ static const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
.Type = DTYPE_Device
},
.USBSpecification = VERSION_BCD(2,0,0),
.USBSpecification = VERSION_BCD(02.00),
.Class = 0x00,
.SubClass = 0x00,
.Protocol = 0x00,
@ -359,7 +305,7 @@ static const USB_Descriptor_String_t *strings[] = {
};
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
const uint16_t wIndex,
const uint8_t wIndex,
const void** const DescriptorAddress)
{
const uint8_t DescriptorType = (wValue >> 8);
@ -403,13 +349,6 @@ void EVENT_USB_Device_Reset(void)
{
Endpoint_SelectEndpoint(ENDPOINT_CONTROLEP);
USB_INT_Enable(USB_INT_RXSTPI);
reset_internal_state();
}
void EVENT_USB_Device_Disconnect(void)
{
reset_internal_state();
}
/* Configure endpoint with the best available number of banks. */
@ -422,86 +361,26 @@ static inline bool ftdi_config_ep(uint8_t address, uint8_t type, uint16_t size)
return Endpoint_ConfigureEndpoint(address, type, size, 1);
}
static void maybe_enable_tx(void)
{
/* Not configured? */
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
/* Transmitter empty, and latency timer hasn't timed out? */
if (ftdi_status.temt && latency_count < latency_timer)
return;
/* Delay the initial TX? */
if (ftdi_delay_init_tx)
{
if (!got_first_rx)
{
if (!got_setbaudrate)
return;
if (frames_since_setbaudrate < WAIT_FRAMES)
return;
}
}
/* Enable it */
Endpoint_SelectEndpoint(FTDI_TX_EPADDR);
UEIENX |= (1 << TXINE);
}
void EVENT_USB_Device_StartOfFrame(void)
{
if (latency_count < latency_timer)
{
latency_count++;
if (latency_count == latency_timer)
maybe_enable_tx();
}
if (!ftdi_delay_init_tx)
return;
if (!got_setbaudrate)
return;
if (frames_since_setbaudrate < WAIT_FRAMES)
{
frames_since_setbaudrate++;
if (frames_since_setbaudrate == WAIT_FRAMES)
maybe_enable_tx();
}
}
void EVENT_USB_Device_ConfigurationChanged(void)
{
uint8_t PrevSelectedEndpoint = Endpoint_GetCurrentEndpoint();
/* Configure endpoints */
/* IN */
ftdi_config_ep(FTDI_TX_EPADDR, EP_TYPE_BULK, FTDI_TXRX_EPSIZE);
Endpoint_SelectEndpoint(FTDI_TX_EPADDR);
UEIENX = (1 << TXINE);
/* OUT */
ftdi_config_ep(FTDI_RX_EPADDR, EP_TYPE_BULK, FTDI_TXRX_EPSIZE);
/* Start interrupt on RX endpoint */
Endpoint_SelectEndpoint(FTDI_RX_EPADDR);
UEIENX |= (1 << RXOUTE);
/* If we have data to send, start interrupt on TX endpoint */
maybe_enable_tx();
UEIENX = (1 << RXOUTE);
/* Done */
Endpoint_SelectEndpoint(PrevSelectedEndpoint);
}
static const char *fmt_ch(uint8_t ch) __attribute__((unused));
static const char *fmt_ch(uint8_t ch)
{
static char s[10];
if (ch > 32 && ch <= 127)
sprintf(s, "%c", ch);
else
sprintf(s, "<%d>", ch);
return s;
}
static inline void ftdi_bulk_in(void)
{
int len, i;
@ -509,38 +388,27 @@ static inline void ftdi_bulk_in(void)
/* Data format: ftdi_status structure (2 bytes) followed by the
serial data. */
len = _queue_get_len(&ftdi_txqueue);
if (len > FTDI_TXRX_EPSIZE - 2) {
/* There will be more data after this packet */
if (len >= FTDI_TXRX_EPSIZE - 2) {
/* more to send */
ftdi_status.thre = 0;
ftdi_status.temt = 0;
len = FTDI_TXRX_EPSIZE - 2;
} else {
/* No more data after this */
ftdi_status.temt = 1;
/* transmitter empty */
ftdi_status.thre = 0;
ftdi_status.temt = 0;
}
/* If we have data or the latency timer expired, send status
bytes and the data. Otherwise, this will just be a ZLP. */
if (len > 0 || latency_count == latency_timer)
{
Endpoint_Write_8(((uint8_t *)&ftdi_status)[0]);
Endpoint_Write_8(((uint8_t *)&ftdi_status)[1]);
for (i = 0; i < len; i++)
{
uint8_t ch = _queue_get(&ftdi_txqueue);
Endpoint_Write_8(ch);
}
Endpoint_Write_8(_queue_get(&ftdi_txqueue));
/* Latency timer can be reset, since we're sending
useful data to the host. */
latency_count = 0;
}
if (ftdi_status.temt)
{
/* If we have no more data, and we wrote a packet that was
smaller than the full endpoint size, then this transfer is
done and we can disable the IN interrupt. We'll reenable
it when we have more data to send. */
if (len != FTDI_TXRX_EPSIZE - 2)
/* If that packet was empty, disable the IN interrupt. We'll
reenable it when we have more data to send. */
if (len == 0) {
UEIENX &= ~(1 << TXINE);
}
@ -552,28 +420,20 @@ static inline void ftdi_bulk_out(void)
{
int i;
int len;
bool overflow = false;
len = Endpoint_BytesInEndpoint();
if (_queue_get_free(&ftdi_rxqueue) < len) {
/* We can't deal with this right now. Disable OUT
interrupt; we'll reenable after reading some bytes */
UEIENX &= ~(1 << RXOUTE);
return;
}
for (i = 0; i < len; i++) {
/* This will discard incoming bytes if queue is full */
uint8_t ch = Endpoint_Read_8();
got_first_rx = true;
/* Put into RX queue */
if (_queue_put(&ftdi_rxqueue, ch) < 0)
overflow = true;
_queue_put(&ftdi_rxqueue, Endpoint_Read_8());
}
if (overflow)
{
/* We lost data because our RX queue was full.
Disable OUT interrupt; we'll reenable after emptying
some bytes from the RX queue. */
UEIENX &= ~(1 << RXOUTE);
}
Endpoint_ClearOUT();
}
@ -618,15 +478,10 @@ void ftdi_putchar(uint8_t c)
if (ftdi_blocking_out == false)
return;
/* Protect against race conditions by double checking
that we still have data to send, while interrupts are
disabled. */
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
if (_queue_get_len(&ftdi_txqueue) > 0)
{
ftdi_status.temt = 0;
maybe_enable_tx();
}
/* Enable the IN endpoint interrupt, since we have data to send. */
if (USB_DeviceState == DEVICE_STATE_Configured) {
Endpoint_SelectEndpoint(FTDI_TX_EPADDR);
UEIENX |= (1 << TXINE);
}
}
@ -639,17 +494,11 @@ int ftdi_getchar(void)
if (ftdi_blocking_in == false)
return -1;
/* Protect against race conditions by double checking
that we still have space for new data, while interrupts
are disabled. */
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
/* Reenable the OUT endpoint interrupt, since we read
some data */
/* Reenable the OUT endpoint interrupt, since we read some data */
if (USB_DeviceState == DEVICE_STATE_Configured) {
Endpoint_SelectEndpoint(FTDI_RX_EPADDR);
UEIENX |= (1 << RXOUTE);
}
}
return ret;
}

18
ftdi.h
View File

@ -9,11 +9,11 @@
/* FTDI device-to-host data IN endpoint */
#define FTDI_TX_EPADDR (ENDPOINT_DIR_IN | 1)
#define FTDI_TX_QUEUE_LEN 256
#define FTDI_TX_QUEUE_LEN 32
/* Endpoint address of FTDI host-to-device data OUT endpoint */
#define FTDI_RX_EPADDR (ENDPOINT_DIR_OUT | 2)
#define FTDI_RX_QUEUE_LEN 256 /* Must be at least FTDI_TXRX_EPSIZE + 1 */
#define FTDI_RX_QUEUE_LEN 32 /* Must be at least FTDI_TXRX_EPSIZE + 1 */
/* Endpoint size */
#define FTDI_TXRX_EPSIZE 16 /* e.g. 16 or 64 */
@ -63,18 +63,6 @@
#define FTDI_BLOCKING_OUT (1 << 2)
#define FTDI_BLOCKING (FTDI_BLOCKING_IN | FTDI_BLOCKING_OUT)
/* Whether to translate \n to \r\n on output, like stty's onlcr flag */
#define FTDI_ONLCR (1 << 3)
/* Whether to delay the initial TX after USB configuration.
If set, wait for either:
- 250ms to pass after a SET_BAUDRATE command
- input to be received
before sending any data. This is to work around issues where
some hsots will discard (or even echo) input while the port
is still being opened. */
#define FTDI_DELAY_INIT_TX (1 << 4)
/* Initialize FTDI routines, with flags above */
void ftdi_init(int flags);
@ -92,7 +80,7 @@ void EVENT_USB_Device_ControlRequest(void);
void EVENT_USB_Device_Reset(void);
void EVENT_USB_Device_ConfigurationChanged(void);
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
const uint16_t wIndex,
const uint8_t wIndex,
const void** const DescriptorAddress)
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);

2
lufa

@ -1 +1 @@
Subproject commit 737382aeda146ca793be452ac5790e12d1ca16ea
Subproject commit f59a34370cec33272412d9aee6e68871d7e8b5e0

132
terminal.py Executable file
View File

@ -0,0 +1,132 @@
#!/usr/bin/python
# Based on miniterm sample in pyserial
import sys, os, serial, threading, traceback, time
if os.name == 'nt':
import msvcrt
class Console:
def __init__(self):
pass
def cleanup(self):
pass
def getkey(self):
while 1:
z = msvcrt.getch()
if z == '\0' or z == '\xe0': # function keys
msvcrt.getch()
else:
if z == '\r':
return '\n'
return z
elif os.name == 'posix':
import termios, sys, os
class Console:
def __init__(self):
self.fd = sys.stdin.fileno()
try:
self.old = termios.tcgetattr(self.fd)
new = termios.tcgetattr(self.fd)
new[3] = new[3] & ~termios.ICANON & ~termios.ECHO & ~termios.ISIG
new[6][termios.VMIN] = 1
new[6][termios.VTIME] = 0
termios.tcsetattr(self.fd, termios.TCSANOW, new)
except termios.error:
# ignore errors, so we can pipe stuff to this script
pass
def cleanup(self):
try:
termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old)
except:
# ignore errors, so we can pipe stuff to this script
pass
def getkey(self):
c = os.read(self.fd, 1)
return c
else:
raise ("Sorry, no terminal implementation for your platform (%s) "
"available." % sys.platform)
class Miniterm:
def __init__(self, serial):
self.serial = serial
def start(self):
self.alive = True
#start serial->console thread
self.receiver_thread = threading.Thread(target=self.reader)
self.receiver_thread.daemon = True
self.receiver_thread.start()
#enter console->serial loop
self.console = Console()
self.transmitter_thread = threading.Thread(target=self.writer)
self.transmitter_thread.daemon = True
self.transmitter_thread.start()
def stop(self):
self.alive = False
def join(self, transmit_only=False):
self.receiver_thread.join()
self.transmitter_thread.join()
def reader(self):
"""loop and copy serial->console"""
try:
while self.alive:
data = self.serial.read(1)
sys.stdout.write(data)
sys.stdout.flush()
except Exception as e:
traceback.print_exc()
self.console.cleanup()
os._exit(1)
def writer(self):
"""loop and copy console->serial until ^C"""
try:
while self.alive:
try:
c = self.console.getkey()
except KeyboardInterrupt:
c = '\x03'
if c == '\x03':
self.stop()
return
elif c == '':
# EOF on input. Wait a tiny bit so we can
# flush the remaining input, then stop.
time.sleep(0.25)
self.stop()
return
else:
self.serial.write(c) # send character
except Exception as e:
traceback.print_exc()
self.console.cleanup()
os._exit(1)
def run(self):
self.serial.timeout = 0.1
self.start()
self.join()
print ""
self.console.cleanup()
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Simple serial terminal")
parser.add_argument('device', metavar='DEVICE',
help='serial device')
parser.add_argument('baudrate', metavar='BAUDRATE', type=int, nargs='?',
help='baud rate', default=115200)
args = parser.parse_args()
try:
dev = serial.Serial(args.device, args.baudrate)
except serial.serialutil.SerialException:
sys.stderr.write("error opening %s\n" % args.device)
raise SystemExit(1)
term = Miniterm(dev)
term.run()