
15 changed files with 1493 additions and 0 deletions
@ -0,0 +1,5 @@
|
||||
# define the module that is build
|
||||
MODULE = cpu
|
||||
# add a list of subdirectories, that should also be build
|
||||
DIRS = periph $(ATMEGA_COMMON)
|
||||
include $(RIOTBASE)/Makefile.base |
@ -0,0 +1,28 @@
|
||||
|
||||
# this CPU implementation is using the new core/CPU interface
|
||||
export CFLAGS += -DCOREIF_NG=1
|
||||
|
||||
# tell the build system that the CPU depends on the atmega common files
|
||||
export USEMODULE += atmega_common
|
||||
|
||||
# define path to atmega common module, which is needed for this CPU
|
||||
export ATMEGA_COMMON = $(RIOTCPU)/atmega_common/
|
||||
|
||||
# define the linker script to use for this CPU
|
||||
#export LINKERSCRIPT = $(RIOTCPU)/$(CPU)/atmega2560_linkerscript.ld
|
||||
|
||||
# include CPU specific includes
|
||||
export INCLUDES += -I$(RIOTCPU)/$(CPU)/include
|
||||
|
||||
# explicitly tell the linker to link the syscalls and startup code.
|
||||
# Without this the interrupt vectors will not be linked correctly!
|
||||
export UNDEF += $(BINDIR)cpu/startup.o
|
||||
|
||||
# export the peripheral drivers to be linked into the final binary
|
||||
export USEMODULE += periph
|
||||
|
||||
# the uart implementation uses ringbuffer and therefore needs lib
|
||||
export USEMODULE += lib
|
||||
|
||||
# CPU depends on the atmega common module, so include it
|
||||
include $(ATMEGA_COMMON)Makefile.include |
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup cpu_atmega2560 |
||||
* @{ |
||||
* |
||||
* @file cpu.c |
||||
* @brief Implementation of the CPU initialization |
||||
* |
||||
* @author Hinnerk van Bruinehsen <h.v.bruinehsen@fu-berlin.de> |
||||
* @} |
||||
*/ |
||||
|
||||
#include "cpu.h" |
||||
|
||||
/**
|
||||
* @brief Initialize the CPU, set IRQ priorities |
||||
*/ |
||||
void cpu_init(void) |
||||
{ |
||||
/* Right now we need to do nothing here */ |
||||
; |
||||
} |
@ -0,0 +1,10 @@
|
||||
/** |
||||
* @defgroup cpu_atmega2560 Atmel ATmega2560 |
||||
* @ingroup cpu |
||||
* @brief Implementation of Atmel's ATmega2560 MCU |
||||
*/ |
||||
|
||||
/** |
||||
* @defgroup cpu_atmega2560_definitions Atmel ATmega2560 Definitions |
||||
* @ingroup cpu_atmega2560 |
||||
*/ |
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup cpu_atmega2560 |
||||
* @{ |
||||
* |
||||
* @file hwtimer_arch.c |
||||
* @brief Implementation of the kernels hwtimer interface |
||||
* |
||||
* The hardware timer implementation uses the ATmega2560 build-in system timer as back-end. |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
* @author Hinnerk van Bruinehsen <h.v.bruinehsen@fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include "arch/hwtimer_arch.h" |
||||
#include "board.h" |
||||
#include "periph/timer.h" |
||||
#include "thread.h" |
||||
|
||||
|
||||
void irq_handler(int channel); |
||||
void (*timeout_handler)(int); |
||||
|
||||
|
||||
void hwtimer_arch_init(void (*handler)(int), uint32_t fcpu) |
||||
{ |
||||
timeout_handler = handler; |
||||
timer_init(HW_TIMER, 1, &irq_handler); |
||||
} |
||||
|
||||
void hwtimer_arch_enable_interrupt(void) |
||||
{ |
||||
timer_irq_enable(HW_TIMER); |
||||
} |
||||
|
||||
void hwtimer_arch_disable_interrupt(void) |
||||
{ |
||||
timer_irq_disable(HW_TIMER); |
||||
} |
||||
|
||||
void hwtimer_arch_set(unsigned long offset, short timer) |
||||
{ |
||||
timer_set(HW_TIMER, timer, offset); |
||||
} |
||||
|
||||
void hwtimer_arch_set_absolute(unsigned long value, short timer) |
||||
{ |
||||
timer_set_absolute(HW_TIMER, timer, value); |
||||
} |
||||
|
||||
void hwtimer_arch_unset(short timer) |
||||
{ |
||||
timer_clear(HW_TIMER, timer); |
||||
} |
||||
|
||||
unsigned long hwtimer_arch_now(void) |
||||
{ |
||||
return timer_read(HW_TIMER); |
||||
} |
||||
|
||||
void irq_handler(int channel) |
||||
{ |
||||
timeout_handler((short)(channel)); |
||||
} |
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Implementation specific CPU configuration options |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
* @author Hinnerk van Bruinehsen <h.v.bruinehsen@fu-berlin.de> |
||||
*/ |
||||
|
||||
#ifndef __CPU_CONF_H |
||||
#define __CPU_CONF_H |
||||
|
||||
|
||||
|
||||
/**
|
||||
* @name Kernel configuration |
||||
* |
||||
* Since printf seems to get memory allocated by the linker/avr-libc the stack |
||||
* size tested sucessfully even with pretty small stacks.k |
||||
* @{ |
||||
*/ |
||||
#define KERNEL_CONF_STACKSIZE_PRINTF (128) |
||||
|
||||
#ifndef KERNEL_CONF_STACKSIZE_DEFAULT |
||||
#define KERNEL_CONF_STACKSIZE_DEFAULT (256) |
||||
#endif |
||||
|
||||
#define KERNEL_CONF_STACKSIZE_IDLE (128) |
||||
/** @} */ |
||||
|
||||
/**
|
||||
* @name UART0 buffer size definition for compatibility reasons |
||||
* |
||||
* TODO: remove once the remodeling of the uart0 driver is done |
||||
* @{ |
||||
*/ |
||||
#ifndef UART0_BUFSIZE |
||||
#define UART0_BUFSIZE (128) |
||||
#endif |
||||
/** @} */ |
||||
|
||||
#endif /* __CPU_CONF_H */ |
||||
/** @} */ |
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup cpu_atmega2560 |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief CPU specific hwtimer configuration options |
||||
* |
||||
* @author Hinnerk van Bruinehsen <h.v.bruinehsen@fu-berlin.de> |
||||
*/ |
||||
|
||||
#ifndef __HWTIMER_CPU_H |
||||
#define __HWTIMER_CPU_H |
||||
|
||||
/**
|
||||
* @name Hardware timer configuration |
||||
* @{ |
||||
*/ |
||||
#define HWTIMER_MAXTIMERS 3 /**< the CPU implementation supports 3 HW timers */ |
||||
#define HWTIMER_SPEED 1000000 /**< the HW timer runs with 1MHz */ |
||||
#define HWTIMER_MAXTICKS (0xFFFF) /**< 16-bit timer */ |
||||
/** @} */ |
||||
|
||||
#endif /* __HWTIMER_CPU_H */ |
||||
/** @} */ |
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup cpu_atmega2560 |
||||
* @{ |
||||
* |
||||
* @file io_arch.c |
||||
* @brief Implementation of the kernel's architecture dependent IO interface |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
* @author Hinnerk van Bruinehsen <h.v.bruinehsen@fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include "arch/io_arch.h" |
||||
|
||||
int io_arch_puts(char *data, int size) |
||||
{ |
||||
int i = 0; |
||||
|
||||
for (; i < size; i++) { |
||||
putchar(data[i]); |
||||
} |
||||
|
||||
return i; |
||||
} |
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup cpu_atmega2560 |
||||
* @{ |
||||
* |
||||
* @file lpm_arch.c |
||||
* @brief Implementation of the kernels power management interface |
||||
* |
||||
* @author Hinnerk van Bruinehsen <h.v.bruinehsen@fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include "arch/lpm_arch.h" |
||||
|
||||
void lpm_arch_init(void) |
||||
{ |
||||
/* TODO */ |
||||
} |
||||
|
||||
enum lpm_mode lpm_arch_set(enum lpm_mode target) |
||||
{ |
||||
/* TODO */ |
||||
return 0; |
||||
} |
||||
|
||||
enum lpm_mode lpm_arch_get(void) |
||||
{ |
||||
/* TODO */ |
||||
return 0; |
||||
} |
||||
|
||||
void lpm_arch_awake(void) |
||||
{ |
||||
/* TODO */ |
||||
} |
||||
|
||||
void lpm_arch_begin_awake(void) |
||||
{ |
||||
/* TODO */ |
||||
} |
||||
|
||||
void lpm_arch_end_awake(void) |
||||
{ |
||||
/* TODO */ |
||||
} |
@ -0,0 +1,2 @@
|
||||
MODULE = periph
|
||||
include $(RIOTBASE)/Makefile.base |
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup driver_periph |
||||
* @{ |
||||
* |
||||
* @file gpio.c |
||||
* @brief Low-level GPIO driver implementation |
||||
* |
||||
* @author Hauke Petersen <mail@haukepetersen.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
/*
|
||||
* TODO: Implement GPIO interface |
||||
*/ |
||||
|
||||
#include "cpu.h" |
||||
#include "periph/gpio.h" |
||||
#include "periph_conf.h" |
||||
|
||||
typedef struct { |
||||
void (*cb)(void); |
||||
} gpio_state_t; |
||||
|
||||
/*static gpio_state_t config[GPIO_NUMOF]; */ |
||||
|
||||
|
||||
|
||||
int gpio_init_out(gpio_t dev, gpio_pp_t pushpull) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
int gpio_init_in(gpio_t dev, gpio_pp_t pushpull) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
int gpio_init_int(gpio_t dev, gpio_pp_t pushpull, gpio_flank_t flank, gpio_cb_t cb, void *arg) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
int gpio_read(gpio_t dev) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
void gpio_set(gpio_t dev) |
||||
{ |
||||
} |
||||
|
||||
void gpio_clear(gpio_t dev) |
||||
{ |
||||
} |
||||
|
||||
void gpio_toggle(gpio_t dev) |
||||
{ |
||||
} |
||||
|
||||
void gpio_write(gpio_t dev, int value) |
||||
{ |
||||
} |
@ -0,0 +1,672 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup driver_periph |
||||
* @{ |
||||
* |
||||
* @file timer.c |
||||
* @brief Low-level timer driver implementation for the ATmega2560 CPU |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
* @author Hinnerk van Bruinehsen <h.v.bruinehsen@fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
|
||||
#include <avr/interrupt.h> |
||||
|
||||
#include "board.h" |
||||
#include "cpu.h" |
||||
|
||||
#include "periph/timer.h" |
||||
#include "periph_conf.h" |
||||
|
||||
static inline int __set_timer(tim_t dev, |
||||
int channel, |
||||
unsigned int timeout, |
||||
unsigned int interval |
||||
); |
||||
|
||||
#define IRQ_DISABLED 0x00 |
||||
|
||||
typedef struct { |
||||
void (*cb)(int); |
||||
volatile uint8_t ctr_a; |
||||
volatile uint8_t ctr_b; |
||||
volatile uint8_t ctr_c; |
||||
uint8_t limit; |
||||
uint16_t timeout_a; |
||||
uint16_t timeout_b; |
||||
uint16_t timeout_c; |
||||
} timer_conf_t; |
||||
|
||||
/**
|
||||
* @brief Timer state memory |
||||
*/ |
||||
timer_conf_t config[TIMER_NUMOF]; |
||||
|
||||
/**
|
||||
* @brief Setup the given timer |
||||
* |
||||
*/ |
||||
int timer_init(tim_t dev, unsigned int ticks_per_us, void (*callback)(int)) |
||||
{ |
||||
/* reject impossible ticks_per_us values */ |
||||
if ((ticks_per_us > 16) && (ticks_per_us == 0)) { |
||||
return -1; |
||||
} |
||||
|
||||
config[dev].limit = 16 / ticks_per_us; |
||||
config[dev].ctr_a = 0x00; |
||||
config[dev].ctr_b = 0x00; |
||||
config[dev].ctr_c = 0x00; |
||||
|
||||
/* select the timer and enable the timer specific peripheral clocks */ |
||||
switch (dev) { |
||||
#if TIMER_0_EN |
||||
|
||||
case TIMER_0: |
||||
TIMER0_COUNTER = 0; |
||||
TIMER0_CONTROL_B |= TIMER0_FREQ_16MHZ; |
||||
break; |
||||
#endif |
||||
#if TIMER_1_EN |
||||
|
||||
case TIMER_1: |
||||
TIMER1_COUNTER = 0; |
||||
TIMER1_CONTROL_B |= TIMER1_FREQ_16MHZ; |
||||
break; |
||||
#endif |
||||
#if TIMER_2_EN |
||||
|
||||
case TIMER_2: |
||||
TIMER2_COUNTER = 0; |
||||
TIMER2_CONTROL_B |= TIMER2_FREQ_16MHZ; |
||||
break; |
||||
#endif |
||||
|
||||
case TIMER_UNDEFINED: |
||||
default: |
||||
return -1; |
||||
} |
||||
|
||||
/* save callback */ |
||||
config[dev].cb = callback; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int timer_set(tim_t dev, int channel, unsigned int timeout) |
||||
{ |
||||
return __set_timer(dev, channel, timer_read(dev) + timeout, timeout); |
||||
} |
||||
|
||||
int timer_set_absolute(tim_t dev, int channel, unsigned int timeout) |
||||
{ |
||||
return __set_timer(dev, channel, timeout, timeout); |
||||
} |
||||
|
||||
int timer_clear(tim_t dev, int channel) |
||||
{ |
||||
|
||||
switch (dev) { |
||||
#if TIMER_0_DIS |
||||
|
||||
case TIMER_0: |
||||
switch (channel) { |
||||
case 0: |
||||
TIMER0_IRQ_FLAG_REG &= ~(1 << TIMER0_COMP_A_FLAG); |
||||
config[dev].timeout_a = IRQ_DISABLED; |
||||
break; |
||||
|
||||
case 1: |
||||
TIMER0_IRQ_FLAG_REG &= ~(1 << TIMER0_COMP_B_FLAG); |
||||
config[dev].timeout_b = IRQ_DISABLED; |
||||
break; |
||||
|
||||
case 2: |
||||
TIMER0_IRQ_FLAG_REG &= ~(1 << TIMER0_COMP_C_FLAG); |
||||
config[dev].timeout_c = IRQ_DISABLED; |
||||
break; |
||||
|
||||
default: |
||||
return -1; |
||||
} |
||||
|
||||
break; |
||||
#endif |
||||
#if TIMER_1_DIS |
||||
|
||||
case TIMER_1: |
||||
switch (channel) { |
||||
case 0: |
||||
TIMER1_IRQ_FLAG_REG &= ~(1 << TIMER1_COMP_A_FLAG); |
||||
config[dev].timeout_a = IRQ_DISABLED; |
||||
break; |
||||
|
||||
case 1: |
||||
TIMER1_IRQ_FLAG_REG &= ~(1 << TIMER1_COMP_B_FLAG); |
||||
config[dev].timeout_b = IRQ_DISABLED; |
||||
break; |
||||
|
||||
case 2: |
||||
TIMER1_IRQ_FLAG_REG &= ~(1 << TIMER1_COMP_C_FLAG); |
||||
config[dev].timeout_c = IRQ_DISABLED; |
||||
break; |
||||
|
||||
default: |
||||
return -1; |
||||
break; |
||||
} |
||||
|
||||
break; |
||||
#endif |
||||
#if TIMER_2_DIS |
||||
|
||||
case TIMER_2: |
||||
switch (channel) { |
||||
case 0: |
||||
TIMER2_IRQ_FLAG_REG &= ~(1 << TIMER2_COMP_A_FLAG); |
||||
config[dev].timeout_a = IRQ_DISABLED; |
||||
break; |
||||
|
||||
case 1: |
||||
TIMER2_IRQ_FLAG_REG &= ~(1 << TIMER2_COMP_B_FLAG); |
||||
config[dev].timeout_b = IRQ_DISABLED; |
||||
break; |
||||
|
||||
case 2: |
||||
TIMER2_IRQ_FLAG_REG &= ~(1 << TIMER2_COMP_C_FLAG); |
||||
config[dev].timeout_c = IRQ_DISABLED; |
||||
break; |
||||
|
||||
default: |
||||
return -1; |
||||
break; |
||||
} |
||||
|
||||
break; |
||||
#endif |
||||
|
||||
case TIMER_UNDEFINED: |
||||
default: |
||||
return -1; |
||||
} |
||||
|
||||
timer_irq_disable(dev); |
||||
return 1; |
||||
} |
||||
|
||||
unsigned int timer_read(tim_t dev) |
||||
{ |
||||
uint16_t value; |
||||
/*
|
||||
* Disabling interrupts globally because read from 16 Bit register can |
||||
* otherwise be messed up |
||||
*/ |
||||
disableIRQ(); |
||||
|
||||
switch (dev) { |
||||
#if TIMER_0_EN |
||||
|
||||
case TIMER_0: |
||||
value = TIMER0_COUNTER; |
||||
break; |
||||
#endif |
||||
#if TIMER_1_EN |
||||
|
||||
case TIMER_1: |
||||
value = TIMER1_COUNTER; |
||||
break; |
||||
#endif |
||||
#if TIMER_2_EN |
||||
|
||||
case TIMER_2: |
||||
value = TIMER2_COUNTER; |
||||
break; |
||||
#endif |
||||
|
||||
case TIMER_UNDEFINED: |
||||
default: |
||||
value = 0; |
||||
enableIRQ(); |
||||
} |
||||
|
||||
enableIRQ(); |
||||
return value; |
||||
} |
||||
|
||||
void timer_stop(tim_t dev) |
||||
{ |
||||
switch (dev) { |
||||
#if TIMER_0_EN |
||||
|
||||
case TIMER_0: |
||||
TIMER0_CONTROL_B = TIMER0_FREQ_DISABLE; |
||||
break; |
||||
#endif |
||||
#if TIMER_1_EN |
||||
|
||||
case TIMER_1: |
||||
TIMER1_CONTROL_B = TIMER1_FREQ_DISABLE; |
||||
break; |
||||
#endif |
||||
#if TIMER_2_EN |
||||
|
||||
case TIMER_2: |
||||
TIMER2_CONTROL_B = TIMER2_FREQ_DISABLE; |
||||
break; |
||||
#endif |
||||
|
||||
case TIMER_UNDEFINED: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void timer_start(tim_t dev) |
||||
{ |
||||
switch (dev) { |
||||
#if TIMER_0_EN |
||||
|
||||
case TIMER_0: |
||||
TIMER0_CONTROL_B |= TIMER0_FREQ_16MHZ; |
||||
break; |
||||
#endif |
||||
#if TIMER_1_EN |
||||
|
||||
case TIMER_1: |
||||
TIMER1_CONTROL_B |= TIMER1_FREQ_16MHZ; |
||||
break; |
||||
#endif |
||||
#if TIMER_2_EN |
||||
|
||||
case TIMER_2: |
||||
TIMER1_CONTROL_B |= TIMER1_FREQ_16MHZ; |
||||
break; |
||||
#endif |
||||
|
||||
case TIMER_UNDEFINED: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void timer_irq_enable(tim_t dev) |
||||
{ |
||||
switch (dev) { |
||||
#if TIMER_0_EN |
||||
|
||||
case TIMER_0: |
||||
if (config[dev].timeout_a != IRQ_DISABLED) { |
||||
TIMER0_IRQ_MASK_REG |= (1 << TIMER0_COMP_A_EN); |
||||
} |
||||
|
||||
if (config[dev].timeout_b != IRQ_DISABLED) { |
||||
TIMER0_IRQ_MASK_REG |= (1 << TIMER0_COMP_B_EN); |
||||
} |
||||
|
||||
if (config[dev].timeout_c != IRQ_DISABLED) { |
||||
TIMER0_IRQ_MASK_REG |= (1 << TIMER0_COMP_C_EN); |
||||
} |
||||
|
||||
break; |
||||
#endif |
||||
#if TIMER_1_EN |
||||
|
||||
case TIMER_1: |
||||
if (config[dev].timeout_a != IRQ_DISABLED) { |
||||
TIMER1_IRQ_MASK_REG |= (1 << TIMER1_COMP_A_EN); |
||||
} |
||||
|
||||
if (config[dev].timeout_b != IRQ_DISABLED) { |
||||
TIMER1_IRQ_MASK_REG |= (1 << TIMER1_COMP_B_EN); |
||||
} |
||||
|
||||
if (config[dev].timeout_c != IRQ_DISABLED) { |
||||
TIMER1_IRQ_MASK_REG |= (1 << TIMER1_COMP_C_EN); |
||||
} |
||||
|
||||
break; |
||||
#endif |
||||
#if TIMER_2_EN |
||||
|
||||
case TIMER_2: |
||||
if (config[dev].timeout_a != IRQ_DISABLED) { |
||||
TIMER2_IRQ_MASK_REG |= (1 << TIMER2_COMP_A_EN); |
||||
} |
||||
|
||||
if (config[dev].timeout_b != IRQ_DISABLED) { |
||||
TIMER2_IRQ_MASK_REG |= (1 << TIMER2_COMP_B_EN); |
||||
} |
||||
|
||||
if (config[dev].timeout_c != IRQ_DISABLED) { |
||||
TIMER2_IRQ_MASK_REG |= (1 << TIMER2_COMP_C_EN); |
||||
} |
||||
|
||||
break; |
||||
#endif |
||||
|
||||
case TIMER_UNDEFINED: |
||||
break; |
||||
} |
||||
|
||||
enableIRQ(); |
||||
} |
||||
|
||||
void timer_irq_disable(tim_t dev) |
||||
{ |
||||
switch (dev) { |
||||
#if TIMER_0_EN |
||||
|
||||
case TIMER_0: |
||||
if (config[dev].timeout_a == IRQ_DISABLED) { |
||||
TIMER0_IRQ_MASK_REG &= ~(1 << TIMER0_COMP_A_EN); |
||||
} |
||||
|
||||
if (config[dev].timeout_b == IRQ_DISABLED) { |
||||
TIMER0_IRQ_MASK_REG &= ~(1 << TIMER0_COMP_B_EN); |
||||
} |
||||
|
||||
if (config[dev].timeout_c == IRQ_DISABLED) { |
||||
TIMER0_IRQ_MASK_REG &= ~(1 << TIMER0_COMP_C_EN); |
||||
} |
||||
|
||||
break; |
||||
#endif |
||||
#if TIMER_1_EN |
||||
|
||||
case TIMER_1: |
||||
if (config[dev].timeout_a == IRQ_DISABLED) { |
||||
TIMER1_IRQ_MASK_REG &= ~(1 << TIMER1_COMP_A_EN); |
||||
} |
||||
|
||||
if (config[dev].timeout_b == IRQ_DISABLED) { |
||||
TIMER1_IRQ_MASK_REG &= ~(1 << TIMER1_COMP_B_EN); |
||||
} |
||||
|
||||
if (config[dev].timeout_c == IRQ_DISABLED) { |
||||
TIMER1_IRQ_MASK_REG &= ~(1 << TIMER1_COMP_C_EN); |
||||
} |
||||
|
||||
break; |
||||
#endif |
||||
#if TIMER_2_EN |
||||
|
||||
case TIMER_2: |
||||
if (config[dev].timeout_a == IRQ_DISABLED) { |
||||
TIMER2_IRQ_MASK_REG &= ~(1 << TIMER2_COMP_A_EN); |
||||
} |
||||
|
||||
if (config[dev].timeout_b == IRQ_DISABLED) { |
||||
TIMER2_IRQ_MASK_REG &= ~(1 << TIMER2_COMP_B_EN); |
||||
} |
||||
|
||||
if (config[dev].timeout_c == IRQ_DISABLED) { |
||||
TIMER2_IRQ_MASK_REG &= ~(1 << TIMER2_COMP_C_EN); |
||||
} |
||||
|
||||
break; |
||||
#endif |
||||
|
||||
case TIMER_UNDEFINED: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void timer_reset(tim_t dev) |
||||
{ |
||||
switch (dev) { |
||||
#if TIMER_0_EN |
||||
|
||||
case TIMER_0: |
||||
TIMER0_COUNTER = 0; |
||||
break; |
||||
#endif |
||||
#if TIMER_1_EN |
||||
|
||||
case TIMER_1: |
||||
TIMER1_COUNTER = 0; |
||||
break; |
||||
#endif |
||||
#if TIMER_2_EN |
||||
|
||||
case TIMER_2: |
||||
TIMER2_COUNTER = 0; |
||||
break; |
||||
#endif |
||||
|
||||
case TIMER_UNDEFINED: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
inline int __set_timer(tim_t dev, int channel, unsigned int timeout, unsigned int interval) |
||||
{ |
||||
/*
|
||||
* Disabling interrupts globally because write to 16 Bit register can |
||||
* otherwise be messed up |
||||
*/ |
||||
disableIRQ(); |
||||
|
||||
switch (dev) { |
||||
#if TIMER_0_EN |
||||
|
||||
case TIMER_0: |
||||
switch (channel) { |
||||
case 0: |
||||
TIMER0_COMP_A = (uint16_t) timeout * config[dev].limit; |
||||
config[dev].timeout_a = interval; |
||||
break; |
||||
|
||||
case 1: |
||||
TIMER0_COMP_B = (uint16_t) timeout * config[dev].limit; |
||||
config[dev].timeout_b = interval; |
||||
break; |
||||
|
||||
case 2: |
||||
TIMER0_COMP_C = (uint16_t) timeout * config[dev].limit; |
||||
config[dev].timeout_c = interval; |
||||
break; |
||||
|
||||
default: |
||||
enableIRQ(); |
||||
return -1; |
||||
} |
||||
|
||||
break; |
||||
#endif |
||||
#if TIMER_1_EN |
||||
|
||||
case TIMER_1: |
||||
switch (channel) { |
||||
case 0: |
||||
TIMER1_COMP_A = (uint16_t) timeout * config[dev].limit; |
||||
config[dev].timeout_a = interval; |
||||
break; |
||||
|
||||
case 1: |
||||
TIMER1_COMP_B = (uint16_t) timeout * config[dev].limit; |
||||
config[dev].timeout_b = interval; |
||||
break; |
||||
|
||||
case 2: |
||||
TIMER1_COMP_C = (uint16_t) timeout * config[dev].limit; |
||||
config[dev].timeout_c = interval; |
||||
break; |
||||
|
||||
default: |
||||
enableIRQ(); |
||||
return -1; |
||||
} |
||||
|
||||
break; |
||||
#endif |
||||
#if TIMER_2_EN |
||||
|
||||
case TIMER_2: |
||||
switch (channel) { |
||||
case 0: |
||||
TIMER2_COMP_A = (uint16_t) timeout * config[dev].limit; |
||||
config[dev].timeout_a = interval; |
||||
break; |
||||
|
||||
case 1: |
||||
TIMER2_COMP_B = (uint16_t) timeout * config[dev].limit; |
||||
config[dev].timeout_b = interval; |
||||
break; |
||||
|
||||
case 2: |
||||
TIMER2_COMP_C = (uint16_t) timeout * config[dev].limit; |
||||
config[dev].timeout_c = interval; |
||||
break; |
||||
|
||||
default: |
||||
enableIRQ(); |
||||
return -1; |
||||
} |
||||
|
||||
break; |
||||
#endif |
||||
|
||||
case TIMER_UNDEFINED: |
||||
default: |
||||
enableIRQ(); |
||||
return -1; |
||||
} |
||||
|
||||
/* enable interrupts for given timer */ |
||||
timer_irq_enable(dev); |
||||
enableIRQ(); |
||||
|
||||
return 1; |
||||
} |
||||
#if TIMER_0_EN |
||||
ISR(TIMER0_COMPA_ISR, ISR_BLOCK) |
||||
{ |
||||
config[TIMER_0].ctr_a++; |
||||
|
||||
if (config[TIMER_0].ctr_a >= config[TIMER_0].limit) { |
||||
config[TIMER_0].limit = 0; |
||||
config[TIMER_0].cb(0); |
||||
TIMER0_COMP_A = TIMER0_COMP_A + config[TIMER_0].timeout_a * config[TIMER_0].limit; |
||||
} |
||||
} |
||||
ISR(TIMER0_COMPB_ISR, ISR_BLOCK) |
||||
{ |
||||
config[TIMER_0].ctr_b++; |
||||
|
||||
if (config[TIMER_0].ctr_b >= config[TIMER_0].limit) { |
||||
config[TIMER_0].limit = 0; |
||||
config[TIMER_0].cb(1); |
||||
TIMER0_COMP_B = TIMER0_COMP_B + config[TIMER_0].timeout_b * config[TIMER_0].limit; |
||||
} |
||||
} |
||||
ISR(TIMER0_COMPC_ISR, ISR_BLOCK) |
||||
{ |
||||
config[TIMER_0].ctr_c++; |
||||
|
||||
if (config[TIMER_0].ctr_c >= config[TIMER_0].limit) { |
||||
config[TIMER_0].limit = 0; |
||||
config[TIMER_0].cb(2); |
||||
TIMER0_COMP_C = TIMER0_COMP_C + config[TIMER_0].timeout_c * config[TIMER_0].limit; |
||||
} |
||||
} |
||||
#endif /* TIMER_0_EN */ |
||||
|
||||
#if TIMER_1_EN |
||||
ISR(TIMER1_COMPA_ISR, ISR_BLOCK) |
||||
{ |
||||
config[TIMER_1].ctr_a++; |
||||
|
||||
if (config[TIMER_1].ctr_a >= config[TIMER_1].limit) { |
||||
config[TIMER_1].limit = 0; |
||||
config[TIMER_1].cb(0); |
||||
TIMER1_COMP_A = TIMER1_COMP_A + config[TIMER_1].timeout_a * config[TIMER_1].limit; |
||||
} |
||||
|
||||
if (sched_context_switch_request) { |
||||
thread_yield(); |
||||
} |
||||
} |
||||
ISR(TIMER1_COMPB_ISR, ISR_BLOCK) |
||||
{ |
||||
config[TIMER_1].ctr_b++; |
||||
|
||||
if (config[TIMER_1].ctr_b >= config[TIMER_1].limit) { |
||||
config[TIMER_1].limit = 0; |
||||
config[TIMER_1].cb(1); |
||||
TIMER1_COMP_B = TIMER1_COMP_B + config[TIMER_1].timeout_b * config[TIMER_1].limit; |
||||
} |
||||
|
||||
if (sched_context_switch_request) { |
||||
thread_yield(); |
||||
} |
||||
} |
||||
ISR(TIMER1_COMPC_ISR, ISR_BLOCK) |
||||
{ |
||||
config[TIMER_1].ctr_c++; |
||||
|
||||
if (config[TIMER_1].ctr_c >= config[TIMER_1].limit) { |
||||
config[TIMER_1].limit = 0; |
||||
config[TIMER_1].cb(2); |
||||
TIMER1_COMP_C = TIMER1_COMP_C + config[TIMER_1].timeout_c * config[TIMER_1].limit; |
||||
} |
||||
|
||||
if (sched_context_switch_request) { |
||||
thread_yield(); |
||||
} |
||||
} |
||||
#endif /* TIMER_1_EN */ |
||||
|
||||
#if TIMER_2_EN |
||||
ISR(TIMER2_COMPA_ISR, ISR_BLOCK) |
||||
{ |
||||
config[TIMER_2].ctr_a++; |
||||
|
||||
if (config[TIMER_2].ctr_a >= config[TIMER_2].limit) { |
||||
config[TIMER_2].limit = 0; |
||||
config[TIMER_2].cb(0); |
||||
TIMER2_COMP_A = TIMER2_COMP_A + config[TIMER_2].timeout_a * config[TIMER_2].limit; |
||||
} |
||||
|
||||
if (sched_context_switch_request) { |
||||
thread_yield(); |
||||
} |
||||
} |
||||
ISR(TIMER2_COMPB_ISR, ISR_BLOCK) |
||||
{ |
||||
config[TIMER_2].ctr_b++; |
||||
|
||||
if (config[TIMER_2].ctr_b >= config[TIMER_2].limit) { |
||||
config[TIMER_2].limit = 0; |
||||
config[TIMER_2].cb(1); |
||||
TIMER2_COMP_B = TIMER2_COMP_B + config[TIMER_2].timeout_b * config[TIMER_2].limit; |
||||
} |
||||
|
||||
if (sched_context_switch_request) { |
||||
thread_yield(); |
||||
} |
||||
} |
||||
ISR(TIMER2_COMPC_ISR, ISR_BLOCK) |
||||
{ |
||||
config[TIMER_2].ctr_c++; |
||||
|
||||
if (config[TIMER_2].ctr_c >= config[TIMER_2].limit) { |
||||
config[TIMER_2].limit = 0; |
||||
config[TIMER_2].cb(2); |
||||
TIMER2_COMP_C = TIMER2_COMP_C + config[TIMER_2].timeout_c * config[TIMER_2].limit; |
||||
} |
||||
|
||||
if (sched_context_switch_request) { |
||||
thread_yield(); |
||||
} |
||||
} |
||||
#endif /* TIMER_2_EN */ |
@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup driver_periph |
||||
* @{ |
||||
* |
||||
* @file uart.c |
||||
* @brief Low-level UART driver implementation |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
* @author Hinnerk van Bruinehsen <h.v.bruinehsen@fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include "board.h" |
||||
#include "cpu.h" |
||||
#include "thread.h" |
||||
#include "sched.h" |
||||
|
||||
#include "periph/uart.h" |
||||
#include "periph_conf.h" |
||||
|
||||
|
||||
/**
|
||||
* @brief Each UART device has to store two callbacks. |
||||
*/ |
||||
typedef struct { |
||||
uart_rx_cb_t rx_cb; |
||||
uart_tx_cb_t tx_cb; |
||||
void *arg; |
||||
} uart_conf_t; |
||||
|
||||
/**
|
||||
* @brief Allocate memory to store the callback functions. |
||||
*/ |
||||
static uart_conf_t config[UART_NUMOF]; |
||||
|
||||
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, uart_tx_cb_t tx_cb, void *arg) |
||||
{ |
||||
/* initialize basic functionality */ |
||||
int res = uart_init_blocking(uart, baudrate); |
||||
|
||||
if (res != 0) { |
||||
return res; |
||||
} |
||||
|
||||
/* register callbacks */ |
||||
config[uart].rx_cb = rx_cb; |
||||
config[uart].tx_cb = tx_cb; |
||||
config[uart].arg = arg; |
||||
|
||||
/* configure interrupts and enable RX interrupt */ |
||||
switch (uart) { |
||||
#if UART_0_EN |
||||
|
||||
case UART_0: |
||||
UART0_RX_IRQ_EN; |
||||
break; |
||||
#endif /* UART_0_EN */ |
||||
#if UART_1_EN |
||||
|
||||
case UART_1: |
||||
UART1_RX_IRQ_EN; |
||||
break; |
||||
#endif /* UART_1_EN */ |
||||
#if UART_2_EN |
||||
|
||||
case UART_2: |
||||
UART2_RX_IRQ_EN; |
||||
break; |
||||
#endif /* UART_2_EN */ |
||||
#if UART_3_EN |
||||
|
||||
case UART_3: |
||||
UART3_RX_IRQ_EN; |
||||
break; |
||||
#endif /* UART_3_EN */ |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int uart_init_blocking(uart_t uart, uint32_t baudrate) |
||||
{ |
||||
uint16_t clock_divider = F_CPU / (16 * baudrate); |
||||
|
||||
switch (uart) { |
||||
#if UART_0_EN |
||||
|
||||
case UART_0: |
||||
/* enable RX and TX */ |
||||
UART0_RX_TX_EN; |
||||
/* use 8 Bit characters */ |
||||
UART0_SET_8BIT_SIZE; |
||||
|
||||
/* set clock divider */ |
||||
UART0_BAUD_RATE_L = clock_divider; |
||||
UART0_BAUD_RATE_H = (clock_divider >> 8); |
||||
break; |
||||
#endif /* UART_0 */ |
||||
#if UART_1_EN |
||||
|
||||
case UART_1: |
||||
/* enable RX and TX */ |
||||
UART1_RX_TX_EN; |
||||
/* use 8 Bit characters */ |
||||
UART1_SET_8BIT_SIZE; |
||||
|
||||
/* set clock divider */ |
||||
UART1_BAUD_RATE_L = clock_divider; |
||||
UART1_BAUD_RATE_H = (clock_divider >> 8); |
||||
break; |
||||
#endif /* UART_1 */ |
||||
#if UART_2_EN |
||||
|
||||
case UART_2: |
||||
/* enable RX and TX */ |
||||
UART2_RX_TX_EN; |
||||
/* use 8 Bit characters */ |
||||
UART2_SET_8BIT_SIZE; |
||||
|
||||
/* set clock divider */ |
||||
UART2_BAUD_RATE_L = clock_divider; |
||||
UART2_BAUD_RATE_H = (clock_divider >> 8); |
||||
break; |
||||
#endif /* UART_2 */ |
||||
#if UART_3_EN |
||||
|
||||
case UART_3: |
||||
/* enable RX and TX */ |
||||
UART3_RX_TX_EN; |
||||
/* use 8 Bit characters */ |
||||
UART3_SET_8BIT_SIZE; |
||||
|
||||
/* set clock divider */ |
||||
UART3_BAUD_RATE_L = clock_divider; |
||||
UART3_BAUD_RATE_H = (clock_divider >> 8); |
||||
break; |
||||
#endif /* UART_3 */ |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void uart_tx_begin(uart_t uart) |
||||
{ |
||||
|
||||
} |
||||
|
||||
void uart_tx_end(uart_t uart) |
||||
{ |
||||
|
||||
} |
||||
|
||||
int uart_write(uart_t uart, char data) |
||||
{ |
||||
switch (uart) { |
||||
#if UART_0_EN |
||||
|
||||
case UART_0: |
||||
UART0_DATA_REGISTER = data; |
||||
break; |
||||
#endif /* UART_0_EN */ |
||||
#if UART_1_EN |
||||
|
||||
case UART_1: |
||||
UART1_DATA_REGISTER = data; |
||||
break; |
||||
#endif /* UART_1_EN */ |
||||
#if UART_2_EN |
||||
|
||||
case UART_2: |
||||
UART2_DATA_REGISTER = data; |
||||
break; |
||||
#endif /* UART_2_EN */ |
||||
#if UART_3_EN |
||||
|
||||
case UART_3: |
||||
UART3_DATA_REGISTER = data; |
||||
break; |
||||
#endif /* UART_3_EN */ |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
int uart_read_blocking(uart_t uart, char *data) |
||||
{ |
||||
switch (uart) { |
||||
#if UART_0_EN |
||||
|
||||
case UART_0: |
||||
while (!UART0_RECEIVED_DATA); |
||||
|
||||
*data = (char) UART0_DATA_REGISTER; |
||||
break; |
||||
#endif /* UART_0_EN */ |
||||
#if UART_1_EN |
||||
|
||||
case UART_1: |
||||
while (!UART1_RECEIVED_DATA); |
||||
|
||||
*data = (char) UART1_DATA_REGISTER; |
||||
break; |
||||
#endif /* UART_1_EN */ |
||||
#if UART_2_EN |
||||
|
||||
case UART_2: |
||||
while (!UART2_RECEIVED_DATA); |
||||
|
||||
*data = (char) UART2_DATA_REGISTER; |
||||
break; |
||||
#endif /* UART_2_EN */ |
||||
#if UART_3_EN |
||||
|
||||
case UART_3: |
||||
while (!UART3_RECEIVED_DATA); |
||||
|
||||
*data = (char) UART3_DATA_REGISTER; |
||||
break; |
||||
#endif /* UART_3_EN */ |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
int uart_write_blocking(uart_t uart, char data) |
||||
{ |
||||
switch (uart) { |
||||
#if UART_0_EN |
||||
|
||||
case UART_0: |
||||
while (!UART0_DTREG_EMPTY); |
||||
|
||||
UART0_DATA_REGISTER = data; |
||||
break; |
||||
#endif /* UART_0_EN */ |
||||
#if UART_1_EN |
||||
|
||||
case UART_1: |
||||
while (!UART1_DTREG_EMPTY); |
||||
|
||||
UART1_DATA_REGISTER = data; |
||||
break; |
||||
#endif /* UART_1_EN */ |
||||
#if UART_2_EN |
||||
|
||||
case UART_2: |
||||
while (!UART2_DTREG_EMPTY); |
||||
|
||||
UART2_DATA_REGISTER = data; |
||||
break; |
||||
#endif /* UART_2_EN */ |
||||
#if UART_3_EN |
||||
|
||||
case UART_3: |
||||
while (!UART3_DTREG_EMPTY); |
||||
|
||||
UART3_DATA_REGISTER = data; |
||||
break; |
||||
#endif /* UART_3_EN */ |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
|
||||
#if UART_0_EN |
||||
ISR(USART0_RX_vect, ISR_BLOCK) |
||||
{ |
||||
config[UART_0].rx_cb(config[UART_0].arg, UART0_DATA_REGISTER); |
||||
|
||||
if (sched_context_switch_request) { |
||||
thread_yield(); |
||||
} |
||||
} |
||||
#endif /* UART_0_EN */ |
||||
|
||||
#if UART_1_EN |
||||
ISR(USART1_RX_vect, ISR_BLOCK) |
||||
{ |
||||
config[UART_1].rx_cb(config[UART_1].arg, UART0_DATA_REGISTER); |
||||
|
||||
if (sched_context_switch_request) { |
||||
thread_yield(); |
||||
} |
||||
} |
||||
#endif /* UART_1_EN */ |
||||
|
||||
#if UART_1_EN |
||||
ISR(USART2_RX_vect, ISR_BLOCK) |
||||
{ |
||||
config[UART_2].rx_cb(config[UART_2].arg, UART0_DATA_REGISTER); |
||||
|
||||
if (sched_context_switch_request) { |
||||
thread_yield(); |
||||
} |
||||
} |
||||
#endif /* UART_2_EN */ |
||||
|
||||
#if UART_2_EN |
||||
ISR(USART2_RX_vect, ISR_BLOCK) |
||||
{ |
||||
config[UART_3].rx_cb(config[UART_3].arg, UART0_DATA_REGISTER); |
||||
|
||||
if (sched_context_switch_request) { |
||||
thread_yield(); |
||||
} |
||||
} |
||||
#endif /* UART_3_EN */ |
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup cpu_atmega2560 |
||||
* @{ |
||||
* |
||||
* @file reboot_arch.c |
||||
* @brief Implementation of the kernels reboot interface |
||||
* |
||||
* @author Hinnerk van Bruinehsen <h.v.bruinehsen@fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <avr/wdt.h> |
||||
|
||||
#include "arch/reboot_arch.h" |
||||
#include "cpu.h" |
||||
|
||||
|
||||
int reboot_arch(int mode) |
||||
{ |
||||
printf("Going into reboot, mode %i\n", mode); |
||||
|
||||
/*
|
||||
* Since the AVR doesn't support a real software reset, we set the Watchdog |
||||
* Timer on a 250ms timeout. Consider this a kludge. |
||||
*/ |
||||
wdt_enable(WDTO_250MS); |
||||
|
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup cpu_atmega2560 |
||||
* @{ |
||||
* |
||||
* @file startup.c |
||||
* @brief Startup code and interrupt vector definition |
||||
* |
||||
* @author Hinnerk van Bruinehsen <h.v.bruinehsen@fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <stdint.h> |
||||
#include <avr/interrupt.h> |
||||
#include <avr/io.h> |
||||
|
||||
/* For Catchall-Loop */ |
||||
#include "board.h" |
||||
#include <util/delay.h> |
||||
#include <stdio.h> |
||||
|
||||
|
||||
/**
|
||||
* @brief functions for initializing the board, std-lib and kernel |
||||
*/ |
||||
extern void board_init(void); |
||||
extern void kernel_init(void); |
||||
extern void __libc_init_array(void); |
||||
|
||||
/**
|
||||
* @brief This pair of functions hook circumvent the call to main |
||||
* |
||||
* avr-libc normally uses the .init9 section for a call to main. This call |
||||
* seems to be not replaceable without hacking inside the library. We |
||||
* circumvent the call to main by using section .init7 to call the function |
||||
* reset_handler which therefore is the real entry point and section .init8 |
||||
* which should never be reached but just in case jumps to exit. |
||||
* This way there should be no way to call main directly. |
||||
*/ |
||||
void init7_ovr(void) __attribute__((naked)) __attribute__((section(".init7"))); |
||||
void init8_ovr(void) __attribute__((naked)) __attribute__((section(".init8"))); |
||||
|
||||
|
||||
void init7_ovr(void) |
||||
{ |
||||
asm("call reset_handler"); |
||||
} |
||||
|
||||
void init8_ovr(void) |
||||
{ |
||||
asm("jmp exit"); |
||||
} |
||||
/**
|
||||
|