Skip to content

Commit

Permalink
Merge branch 'feature/swuart'
Browse files Browse the repository at this point in the history
  • Loading branch information
blastur committed Sep 3, 2011
2 parents c08b103 + e89f498 commit ae77297
Show file tree
Hide file tree
Showing 8 changed files with 284 additions and 50 deletions.
45 changes: 29 additions & 16 deletions Makefile
Expand Up @@ -24,34 +24,47 @@ PROGTYPE=stk500v2
PROGPORT=/dev/avrusb0
AVRDUDE=avrdude -p $(MCU) -c $(PROGTYPE) -P $(PROGPORT)

PROG=magboot
IHEX=magboot.ihex
SRCS=magboot.c
OBJS=$(SRCS:%.c=%.o)
HWUART=magboot_hw
SWUART=magboot_sw
HWUART_IHEX=magboot_hw.ihex
SWUART_IHEX=magboot_sw.ihex

COMMON_OBJS=magboot.o
HWUART_OBJS=hwuart.o
SWUART_OBJS=swuart.o

#OPTIMIZE = -Os -fno-inline-small-functions -fno-split-wide-types -mshort-calls
OPTIMIZE = -Os
CFLAGS += -g -Wall $(OPTIMIZE) -mmcu=$(MCU) -DF_CPU=$(CPU_FREQ)
CFLAGS += -g -Wall $(OPTIMIZE) -mmcu=$(MCU) -include config.h -DBAUD_RATE=19200
LDFLAGS += -Wl,--section-start=.text=$(BOOTADDR)

CFLAGS += -DBAUD_RATE=115200
CFLAGS += -DJUMP_ADDR=0x00

# Target specifics: ATmega328p @ external 16 MHz
# Target definition
MCU=atmega328p
CPU_FREQ=16000000L
HFUSE=0xdc
BOOTADDR=0x7c00

$(PROG): $(OBJS)
.PHONY: all
all: $(HWUART_IHEX) $(SWUART_IHEX)

$(HWUART): $(COMMON_OBJS) $(HWUART_OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^

$(IHEX): $(PROG)
$(SWUART): $(COMMON_OBJS) $(SWUART_OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^

$(HWUART_IHEX): $(HWUART)
$(OBJCOPY) -j .text -j .data -S -O ihex $^ $@

$(SWUART_IHEX): $(SWUART)
$(OBJCOPY) -j .text -j .data -S -O ihex $^ $@

.PHONY: flash
flash: $(IHEX)
$(AVRDUDE) -e -U flash:w:$(IHEX)
.PHONY: flash_sw
flash_sw: $(SWUART_IHEX)
$(AVRDUDE) -e -U flash:w:$^

.PHONY: flash_hw
flash_hw: $(HWUART_IHEX)
$(AVRDUDE) -e -U flash:w:$^

.PHONY: fusedump
fusedump:
Expand All @@ -67,4 +80,4 @@ flashdump:

.PHONY: clean
clean:
rm -f $(OBJS) $(PROG) $(IHEX)
rm -f $(COMMON_OBJS) $(HWUART) $(HWUART_IHEX) $(HWUART_OBJS) $(SWUART) $(SWUART_IHEX) $(SWUART_OBJS)
51 changes: 42 additions & 9 deletions README
Expand Up @@ -12,34 +12,41 @@ Features
* Basic device identification to prevent flashing unknown or unsupported devices
* Fits in a 1 kb boot section (binary size is approx. 650 bytes)
* Supports loading raw binaries only (ihex is NOT supported at the moment)
* Supports native AVR serialport or software serialport on two arbitrary pins

Installation
================================================================================
To install magboot you need an ISP programmer.

1) Edit Makefile and the "Target specifics"-section:
1) Edit Makefile and the "Target definition"-section:

MCU Set to either atmega328p or atmega168p depending on target.
MCU Set to either 'atmega328p' or 'atmega168p' depending on target.

CPU_FREQ Match your clock settings (LFUSE and oscillator etc)

HFUSE Should be OK on both targets. If you have special requirements,
HFUSE Sets AVR Hi-Fuse. Normally you will not have to change this
value for either 328p or 168p. If you have special requirements,
http://www.engbedded.com/fusecalc is a good AVR fuse calculator.

BOOTADDR This is flash size minus boot section size, expressed in bytes.
For example, 32 kb - 1 kb = 31 kb = 31 * 1024 = 0x7c00
Set to 0x7c00 for Atmega328p and 0x3c00 for Atmega168p.

2) Program the device:
2) Edit the target configuration in config.h:

FCPU Target clock frequency

Unless you plan to use the software serialport implementation (SWUART), you do
not have to change any of the CONFIG_SWUART_* directives.

3) Build and program the device:

make fuseprog
make flash
make magboot_hw
make flash_hw

The Makefile assumes your ISP programmer is of type stk500v2 and located at file
/dev/avrusb0. If this is not true, append the PROGTYPE and PROGPORT parameters
with appropriate values. Example:

make PROGPORT=/dev/ttyUSB0 PROGTYPE=jtagmkII flash
make PROGPORT=/dev/ttyUSB0 PROGTYPE=jtagmkII flash_hw

For a list of valid PROGTYPE values, please refer to the Avrdude manual:

Expand Down Expand Up @@ -99,3 +106,29 @@ was successfull!

Optionally, the device may be reset using -r. This will cause the device to
reboot and bypass the bootloader.

Software serial port support (ADVANCED)
================================================================================
Magboot normally operates over the built-in serialport of the AVR using the
predefined TX and RX pins. This covers most needs and is the recommended mode of
operation unless your serial port is connected to another pair of pins.

In this case, you may use the software serialport mode of operation. It allows
you to configure two arbitrary pins to use for TX and RX. This is useful if the
native serialport is unavailable, perhaps because of other peripheral serial
devices.

The serialport mode is a compile-time option. You may build the SoftWare UART
(SWUART) version of Magboot by issuing Make-target "magboot_sw":

make magboot_sw

Prior to building the SWUART version, pin-configuration must be setup in
config.h. Please note that all the configuration steps listed in the
Installation section above also applies for the SWUART build (F_CPU etc.).

Finally, flash Magboot SWUART onto target:

make [PROGPORT=/dev/ttyUSB0 PROGTYPE=myprogrammer] flash_sw

For usage information, please refer to the Usage section above.
14 changes: 14 additions & 0 deletions config.h
@@ -0,0 +1,14 @@
/* Target configuration */
#define F_CPU (16000000L)
#define JUMP_ADDR (0x00)

/* SWUART pin-configuration */
#define CONFIG_SWUART_RX_BIT (PB3)
#define CONFIG_SWUART_RX_PORT (PORTB)
#define CONFIG_SWUART_RX_PIN (PINB)
#define CONFIG_SWUART_RX_DIR (DDRB)

#define CONFIG_SWUART_TX_BIT (PB4)
#define CONFIG_SWUART_TX_PORT (PORTB)
#define CONFIG_SWUART_TX_DIR (DDRB)

43 changes: 43 additions & 0 deletions hwuart.c
@@ -0,0 +1,43 @@
/* Copyright (C) 2010-2011 Magnus Olsson
*
* This file is part of magboot
* Windnode is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Windnode is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with magboot. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <avr/io.h>

void uart_putc(uint8_t ch)
{
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = ch;
}

uint8_t uart_getc(void)
{
uint8_t ch;

loop_until_bit_is_set(UCSR0A, RXC0);
ch = UDR0;

return ch;
}

void uart_init()
{
UCSR0A = _BV(U2X0);
UCSR0B = _BV(RXEN0) | _BV(TXEN0);
UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
UBRR0L = (uint8_t)((F_CPU + BAUD_RATE * 4L)/(BAUD_RATE * 8L) - 1);
}

26 changes: 2 additions & 24 deletions magboot.c
Expand Up @@ -25,6 +25,8 @@
#include <avr/interrupt.h>
#include <avr/sfr_defs.h>

#include "uart.h"

#define LED_DIR DDRB
#define LED_PORT PORTB
#define LED_BIT PB5
Expand All @@ -34,30 +36,6 @@

typedef void (*jump_t)(void);

static void uart_putc(char ch)
{
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = ch;
}

static uint8_t uart_getc(void)
{
uint8_t ch;

loop_until_bit_is_set(UCSR0A, RXC0);
ch = UDR0;

return ch;
}

static void uart_init()
{
UCSR0A = _BV(U2X0);
UCSR0B = _BV(RXEN0) | _BV(TXEN0);
UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
UBRR0L = (uint8_t)((F_CPU + BAUD_RATE * 4L)/(BAUD_RATE * 8L) - 1);
}

static bool cmd_load_addr(uint16_t *addr)
{
/* 16-bit addr, little-endian */
Expand Down
2 changes: 1 addition & 1 deletion magboot.py
Expand Up @@ -143,7 +143,7 @@ def cmd_wait():
print "Unsupported device '" + sys.argv[2] + "'"
sys.exit(3)

ser = serial.Serial(port=sys.argv[1], baudrate=115200, timeout=1)
ser = serial.Serial(port=sys.argv[1], baudrate=19200, timeout=1)

try:
opts, args = getopt.getopt(sys.argv[3:], 'a:w:ijrz')
Expand Down
127 changes: 127 additions & 0 deletions swuart.c
@@ -0,0 +1,127 @@
/* Copyright (C) 2010-2011 Magnus Olsson
*
* This file is part of magboot
* Windnode is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Windnode is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with magboot. If not, see <http://www.gnu.org/licenses/>.
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>

#include "uart.h"

#define STARTBIT (0)
#define STOPBIT (1)

/* Calculate baudtime using timer pre-scaler 64 */
#define BAUDTIME ((F_CPU)/(BAUD_RATE*64l))

#if (BAUDTIME > 255)
#error Baudrate is too low!
#endif

#if (BAUDTIME < 1)
#error Baudrate is too high!
#endif

static void __bit_delay(void)
{
TCCR0B |= _BV(CS01) | _BV(CS00); /* Timer pre-scaler 64 */
while (TCNT0 < BAUDTIME) { /* NOP */ }
TCCR0B &= ~(_BV(CS01) | _BV(CS00));
}

static void bit_delay(void)
{
TCNT0 = 0;
__bit_delay();
}

static void half_bit_delay(void)
{
TCNT0 = BAUDTIME/2;
__bit_delay();
}

static uint8_t rx_pin(void)
{
return (CONFIG_SWUART_RX_PIN & _BV(CONFIG_SWUART_RX_BIT)) != 0;
}

static void tx_pin(uint8_t hi)
{
if (hi)
CONFIG_SWUART_TX_PORT |= _BV(CONFIG_SWUART_TX_BIT);
else
CONFIG_SWUART_TX_PORT &= ~(_BV(CONFIG_SWUART_TX_BIT));
}

/* uart_putc() -- blocking 8N1 transmit */
void uart_putc(uint8_t ch)
{
uint8_t bit;

tx_pin(STARTBIT);
bit_delay();
for (bit = 0; bit < 8; bit++) {
tx_pin(ch & 0x1);
ch = ch >> 1;
bit_delay();
}
tx_pin(STOPBIT);
bit_delay();
}

static int __getc(void)
{
uint8_t bit;
uint8_t ch;

half_bit_delay();
if (rx_pin() != STARTBIT)
return -1; /* Glitch */
bit_delay();
for (bit = 0; bit < 8; bit++) {
ch = ch >> 1;
if (rx_pin())
ch |= 1 << 7;
bit_delay();
}

if (rx_pin() != STOPBIT)
return -2; /* Frame error */

return (int) ch;
}

/* uart_getc() -- blocking 8N1 receive */
uint8_t uart_getc(void)
{
while (1) {
int ch;
while (rx_pin() != STARTBIT) { /* NOP */ }

ch = __getc();
if (ch >= 0)
return (uint8_t) ch;
}
}

void uart_init()
{
CONFIG_SWUART_RX_DIR &= ~(_BV(CONFIG_SWUART_RX_BIT));
CONFIG_SWUART_RX_PORT |= _BV(CONFIG_SWUART_RX_BIT);
CONFIG_SWUART_TX_DIR |= _BV(CONFIG_SWUART_TX_BIT);
tx_pin(STOPBIT);
}

0 comments on commit ae77297

Please sign in to comment.