summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Schodet2010-06-14 00:20:08 +0200
committerNicolas Schodet2010-06-14 00:27:43 +0200
commit410eaf6017cd7c6abba3d751eb55f3ad4ffafec6 (patch)
tree5e829d342f56f222af99859d487686f8a8364e9a
parent3166dc06c80945e4458d91fb1cf3c88d583e238d (diff)
add bootloader
-rw-r--r--src/bwbootloader/Makefile12
-rw-r--r--src/bwbootloader/avrconfig.h59
-rw-r--r--src/bwbootloader/bwbootloader.c128
-rw-r--r--src/bwbootloader/bwbootloader.h44
-rw-r--r--src/bwbootloader/prog.c85
-rw-r--r--src/bwbootloader/prog.h51
-rw-r--r--src/bwbootloader/spacer.avr.S29
7 files changed, 408 insertions, 0 deletions
diff --git a/src/bwbootloader/Makefile b/src/bwbootloader/Makefile
new file mode 100644
index 0000000..2f477bb
--- /dev/null
+++ b/src/bwbootloader/Makefile
@@ -0,0 +1,12 @@
+BASE = $b/digital/avr
+AVR_PROGS = bwbootloader
+bwbootloader_SOURCES = bwbootloader.c prog.c spacer.avr.S
+MODULES = twi utils
+CONFIGFILE = avrconfig.h
+# atmega8, atmega8535, atmega128...
+AVR_MCU = attiny85
+# -O2 : speed
+# -Os : size
+OPTIMIZE = -Os
+
+include $(BASE)/make/Makefile.gen
diff --git a/src/bwbootloader/avrconfig.h b/src/bwbootloader/avrconfig.h
new file mode 100644
index 0000000..9c378b9
--- /dev/null
+++ b/src/bwbootloader/avrconfig.h
@@ -0,0 +1,59 @@
+#ifndef avrconfig_h
+#define avrconfig_h
+/* avrconfig.h */
+/* binwatch - Tiny binary wristwatch. {{{
+ *
+ * Copyright (C) 2010 Nicolas Schodet
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contact :
+ * Web: http://ni.fr.eu.org/
+ * Email: <nico at ni.fr.eu.org>
+ * }}} */
+
+/* utils */
+/** AVR Frequency : 1000000, 1843200, 2000000, 3686400, 4000000, 7372800,
+ * 8000000, 11059200, 14745600, 16000000, 18432000, 20000000. */
+#define AC_FREQ 1000000
+
+/* twi - TWI module. */
+/** Driver to implement TWI: HARD, SOFT, or USI. */
+#define AC_TWI_DRIVER USI
+/** Do not use interrupts. */
+#define AC_TWI_NO_INTERRUPT 1
+/** TWI frequency, should really be 100 kHz. */
+#define AC_TWI_FREQ 100000
+/** Enable slave part. */
+#define AC_TWI_SLAVE_ENABLE 1
+/** Enable master part. */
+#define AC_TWI_MASTER_ENABLE 0
+/** Use polled slave mode: received data is stored in a buffer which can be
+ * polled using twi_slave_poll. */
+#define AC_TWI_SLAVE_POLLED 0
+/** Slave reception callback to be defined by the user when not in polled
+ * mode. */
+#define AC_TWI_SLAVE_RECV bwbootloader_recv
+/** Master transfer completion callback, optionally defined by the user, called
+ * at end of master transfer. */
+#undef AC_TWI_MASTER_DONE
+/** Use internal pull up. */
+#define AC_TWI_PULL_UP 0
+/** Slave reception buffer size. */
+#define AC_TWI_SLAVE_RECV_BUFFER_SIZE (64 + 4)
+/** Slave transmission buffer size. */
+#define AC_TWI_SLAVE_SEND_BUFFER_SIZE (64 + 4)
+
+#endif /* avrconfig_h */
diff --git a/src/bwbootloader/bwbootloader.c b/src/bwbootloader/bwbootloader.c
new file mode 100644
index 0000000..b7cc283
--- /dev/null
+++ b/src/bwbootloader/bwbootloader.c
@@ -0,0 +1,128 @@
+/* bwbootloader.c */
+/* binwatch - Tiny binary wristwatch. {{{
+ *
+ * Copyright (C) 2010 Nicolas Schodet
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contact :
+ * Web: http://ni.fr.eu.org/
+ * Email: <nico at ni.fr.eu.org>
+ * }}} */
+#include "common.h"
+#include "modules/twi/twi.h"
+#include "modules/utils/utils.h"
+#include "modules/utils/byte.h"
+
+#include "bwbootloader.h"
+#include "prog.h"
+
+#include <string.h>
+
+/** Start application when 1. */
+volatile uint8_t start;
+
+int
+main (void)
+{
+ twi_init (0xb8);
+ while (!start)
+ twi_update ();
+ /* Small delay for acknowledge. */
+ utils_delay_ms (500);
+ twi_uninit ();
+ prog_start ();
+ return 0;
+}
+
+void
+bwbootloader_recv (const uint8_t *buffer, uint8_t size)
+{
+ /* Command is the first byte, it will be repeated as acknowledgement.
+ * Words are little endian. */
+ static uint8_t rbuffer[AC_TWI_SLAVE_SEND_BUFFER_SIZE];
+ if (size != 0)
+ {
+ switch (buffer[0])
+ {
+ case BWBOOTLOADER_INFO:
+ /* Return informations.
+ * =>
+ * - 12b: 'bwbootloader'.
+ * - b: page size.
+ * - w: flash size (minus bootloader size). */
+ if (size != 1)
+ break;
+ rbuffer[0] = buffer[0];
+ memcpy (&rbuffer[1], "bwbootloader", 12);
+ rbuffer[13] = PROG_PAGE_SIZE;
+ rbuffer[14] = (PROG_FLASH_SIZE - BWBOOTLOADER_SIZE) & 0xff;
+ rbuffer[15] = (PROG_FLASH_SIZE - BWBOOTLOADER_SIZE) >> 8;
+ twi_slave_update (rbuffer, 16);
+ return;
+ case BWBOOTLOADER_START:
+ /* Start application. */
+ if (size != 1)
+ break;
+ start = 1;
+ twi_slave_update (buffer, 1);
+ return;
+ case BWBOOTLOADER_READ:
+ /* Read from flash.
+ * - w: address.
+ * - b: size.
+ * =>
+ * - w: address.
+ * - size x b: flash content. */
+ if (size != 4 || buffer[3] > AC_TWI_SLAVE_SEND_BUFFER_SIZE - 3)
+ break;
+ rbuffer[0] = buffer[0];
+ rbuffer[1] = buffer[1];
+ rbuffer[2] = buffer[2];
+ prog_read (v8_to_v16 (buffer[2], buffer[1]), &rbuffer[3],
+ buffer[3]);
+ twi_slave_update (rbuffer, buffer[3] + 3);
+ return;
+ case BWBOOTLOADER_PAGE_WRITE:
+ /* Write flash page.
+ * - w: address.
+ * - b: size (must be PROG_PAGE_SIZE).
+ * - size x b: page content.
+ * =>
+ * - w: address. */
+ if (size != PROG_PAGE_SIZE + 4 || buffer[3] != PROG_PAGE_SIZE)
+ break;
+ if (!prog_page_write (v8_to_v16 (buffer[2], buffer[1]), &buffer[4]))
+ break;
+ twi_slave_update (buffer, 3);
+ return;
+ case BWBOOTLOADER_READ_FUSES:
+ /* Read fuse bytes.
+ * =>
+ * - b: low fuses.
+ * - b: high fuses.
+ * - b: extended fuses. */
+ if (size != 1)
+ break;
+ rbuffer[0] = buffer[0];
+ prog_read_fuses (&rbuffer[1]);
+ twi_slave_update (rbuffer, 4);
+ return;
+ }
+ }
+ /* Error. */
+ twi_slave_update (NULL, 0);
+}
+
diff --git a/src/bwbootloader/bwbootloader.h b/src/bwbootloader/bwbootloader.h
new file mode 100644
index 0000000..81f7796
--- /dev/null
+++ b/src/bwbootloader/bwbootloader.h
@@ -0,0 +1,44 @@
+#ifndef bwbootloader_h
+#define bwbootloader_h
+/* bwbootloader.h */
+/* binwatch - Tiny binary wristwatch. {{{
+ *
+ * Copyright (C) 2010 Nicolas Schodet
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contact :
+ * Web: http://ni.fr.eu.org/
+ * Email: <nico at ni.fr.eu.org>
+ * }}} */
+
+/** Reserved size for bootloader. */
+#define BWBOOTLOADER_SIZE 1024
+
+#ifndef __ASSEMBLER__
+
+/** Bootloader commands. */
+enum
+{
+ BWBOOTLOADER_INFO,
+ BWBOOTLOADER_START,
+ BWBOOTLOADER_READ,
+ BWBOOTLOADER_PAGE_WRITE,
+ BWBOOTLOADER_READ_FUSES,
+};
+
+#endif
+
+#endif /* bwbootloader_h */
diff --git a/src/bwbootloader/prog.c b/src/bwbootloader/prog.c
new file mode 100644
index 0000000..7b7d2c1
--- /dev/null
+++ b/src/bwbootloader/prog.c
@@ -0,0 +1,85 @@
+/* prog.c */
+/* binwatch - Tiny binary wristwatch. {{{
+ *
+ * Copyright (C) 2010 Nicolas Schodet
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contact :
+ * Web: http://ni.fr.eu.org/
+ * Email: <nico at ni.fr.eu.org>
+ * }}} */
+#include "common.h"
+
+#include "bwbootloader.h"
+#include "prog.h"
+
+#include <avr/boot.h>
+#include <avr/pgmspace.h>
+
+void
+prog_read (uint16_t address, uint8_t *buffer, uint8_t length)
+{
+ while (length--)
+ *buffer++ = pgm_read_byte (address++);
+}
+
+uint8_t
+prog_page_write (uint16_t address, const uint8_t *buffer)
+{
+ /* Bootloader area is protected. */
+ if (address >= PROG_FLASH_SIZE - BWBOOTLOADER_SIZE)
+ return 0;
+ /* Aligned write only. */
+ if (address % PROG_PAGE_SIZE != 0)
+ return 0;
+ /* No EEPROM or interrupt protection, there is none in this bootloader. */
+ /* Load page buffer. */
+ uint16_t w;
+ uint8_t i;
+ for (i = 0; i < PROG_PAGE_SIZE; i += 2)
+ {
+ /* Protect reset vector. */
+ if (address == 0 && i == 0)
+ w = pgm_read_word (0);
+ else
+ w = *(const uint16_t *) (buffer + i);
+ boot_page_fill (address + i, w);
+ }
+ /* Erase page. */
+ boot_page_erase (address);
+ boot_spm_busy_wait ();
+ /* Program page. */
+ boot_page_write (address);
+ boot_spm_busy_wait ();
+ /* All done. */
+ return 1;
+}
+
+void
+prog_read_fuses (uint8_t *buffer)
+{
+ buffer[0] = boot_lock_fuse_bits_get (GET_LOW_FUSE_BITS);
+ buffer[1] = boot_lock_fuse_bits_get (GET_HIGH_FUSE_BITS);
+ buffer[2] = boot_lock_fuse_bits_get (GET_EXTENDED_FUSE_BITS);
+}
+
+void
+prog_start (void)
+{
+ /* Jump after vectors. */
+ ((void (*) (void)) _VECTORS_SIZE) ();
+}
+
diff --git a/src/bwbootloader/prog.h b/src/bwbootloader/prog.h
new file mode 100644
index 0000000..caf0e75
--- /dev/null
+++ b/src/bwbootloader/prog.h
@@ -0,0 +1,51 @@
+#ifndef prog_h
+#define prog_h
+/* prog.h */
+/* binwatch - Tiny binary wristwatch. {{{
+ *
+ * Copyright (C) 2010 Nicolas Schodet
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contact :
+ * Web: http://ni.fr.eu.org/
+ * Email: <nico at ni.fr.eu.org>
+ * }}} */
+#include "io.h"
+
+/** Size of the hole flash. */
+#define PROG_FLASH_SIZE (FLASHEND + 1)
+/** Size of a single flash page. */
+#define PROG_PAGE_SIZE SPM_PAGESIZE
+/** Number of fuse bytes. */
+#define PROG_FUSE_NB 3
+
+/** Read from flash. */
+void
+prog_read (uint16_t address, uint8_t *buffer, uint8_t length);
+
+/** Write a full page to flash. */
+uint8_t
+prog_page_write (uint16_t address, const uint8_t *buffer);
+
+/** Read lfuse, hfuse and efuse. */
+void
+prog_read_fuses (uint8_t *buffer);
+
+/** Start application, never returns. */
+void
+prog_start (void);
+
+#endif /* prog_h */
diff --git a/src/bwbootloader/spacer.avr.S b/src/bwbootloader/spacer.avr.S
new file mode 100644
index 0000000..5ff2cb7
--- /dev/null
+++ b/src/bwbootloader/spacer.avr.S
@@ -0,0 +1,29 @@
+; spacer.avr.S
+; binwatch - Tiny binary wristwatch. {{{
+;
+; Copyright (C) 2010 Nicolas Schodet
+;
+; This program 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 2 of the License, or
+; (at your option) any later version.
+;
+; This program 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 this program; if not, write to the Free Software
+; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+;
+; }}}
+
+; This file sole purpose is to fill memory with 0xff after the vectors so that
+; the bootloader is placed in the last kilobyte.
+
+#include <avr/io.h>
+#include "bwbootloader.h"
+
+ .section .progmem
+ .skip FLASHEND + 1 - BWBOOTLOADER_SIZE - _VECTORS_SIZE, 0xff