summaryrefslogtreecommitdiff
path: root/digital/avr/modules/utils/utils.avr.h
diff options
context:
space:
mode:
Diffstat (limited to 'digital/avr/modules/utils/utils.avr.h')
-rw-r--r--digital/avr/modules/utils/utils.avr.h105
1 files changed, 105 insertions, 0 deletions
diff --git a/digital/avr/modules/utils/utils.avr.h b/digital/avr/modules/utils/utils.avr.h
new file mode 100644
index 00000000..bdba7f6f
--- /dev/null
+++ b/digital/avr/modules/utils/utils.avr.h
@@ -0,0 +1,105 @@
+#ifndef utils_avr_h
+#define utils_avr_h
+/* utils.avr.h */
+/* avr.utils - Utilities AVR module. {{{
+ *
+ * Copyright (C) 2005 Nicolas Schodet
+ *
+ * Robot APB Team/Efrei 2006.
+ * Web: http://assos.efrei.fr/robot/
+ * Email: robot AT efrei DOT fr
+ *
+ * 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.
+ *
+ * }}} */
+
+#include <avr/wdt.h>
+
+/** Helper macro to build register value. Call it like this :
+ *
+ * TCCR0 = regv (FOC0, WGM00, COM01, COM0, WGM01, CS02, CS01, CS00,
+ * 0, 0, 0, 0, 0, 1, 1, 1);
+ *
+ * The macro check that the bits are given in the right order and compute the
+ * register value. If the bits are false, the compiler will generate an
+ * warning about a constant being to large.
+ */
+#define regv(b7, b6, b5, b4, b3, b2, b1, b0, v7, v6, v5, v4, v3, v2, v1, v0) \
+ ((b7) == 7 && (b6) == 6 && (b5) == 5 && (b4) == 4 \
+ && (b3) == 3 && (b2) == 2 && (b1) == 1 && (b0) == 0 \
+ ? (v7) << 7 | (v6) << 6 | (v5) << 5 | (v4) << 4 \
+ | (v3) << 3 | (v2) << 2 | (v1) << 1 | (v0) << 0 \
+ : -1024 * 1024)
+
+/** Delay in seconds. Do not call this function with a variable parameter.
+ * If you want a variable delay, prefer looping over a fixed delay.
+ * Maximum is about 4 seconds at 20MHz. */
+extern inline void
+utils_delay (double s) __attribute__ ((always_inline));
+
+extern inline void
+utils_delay (double s)
+{
+ double cycles = (double) AC_FREQ * s;
+ if (cycles <= 1.0)
+ {
+ /* Delay shorter than 1 instruction. */
+ asm volatile ("nop" : :);
+ }
+ else if (cycles <= 2.0)
+ {
+ /* Delay shorter than 2 instruction. */
+ asm volatile ("nop\n\tnop" : :);
+ }
+ else if (cycles <= 3.0)
+ {
+ /* Delay shorter than 3 instruction. */
+ asm volatile ("nop\n\tnop\n\tnop" : :);
+ }
+ else if (cycles <= 255 * 3)
+ {
+ uint8_t i = cycles / 3;
+ asm volatile ("1: dec %0\n\tbrne 1b" : "=r" (i) : "0" (i));
+ }
+ else if (cycles <= 65535 * 4)
+ {
+ uint16_t i = cycles / 4;
+ asm volatile ("1: sbiw %0,1\n\tbrne 1b" : "=w" (i) : "0" (i));
+ }
+ else
+ {
+ uint8_t j = (cycles + (65535 * 4 - 1)) / (65535 * 4);
+ uint16_t iv = cycles / (j * 4);
+ while (j--)
+ {
+ uint16_t i = iv;
+ asm volatile ("1: sbiw %0,1\n\tbrne 1b" : "=w" (i) : "0" (i));
+ }
+ }
+}
+
+extern inline void
+utils_reset (void) __attribute__ ((noreturn));
+
+/** Reset the avr using the watchdog. */
+extern inline void
+utils_reset (void)
+{
+ wdt_enable (WDTO_15MS);
+ while (1)
+ ;
+}
+
+#endif /* utils_avr_h */