diff --git a/cpu/mc1322x/Makefile b/cpu/mc1322x/Makefile index 431b3b75bb..6edc8dc43e 100644 --- a/cpu/mc1322x/Makefile +++ b/cpu/mc1322x/Makefile @@ -1,6 +1,9 @@ MODULE =cpu DIRS = +ifneq (,$(findstring mc1322x_adc,$(USEMODULE))) + DIRS += adc +endif all: $(BINDIR)$(MODULE).a @for i in $(DIRS) ; do $(MAKE) -C $$i ; done ; diff --git a/cpu/mc1322x/adc/Makefile b/cpu/mc1322x/adc/Makefile new file mode 100644 index 0000000000..7cdb51ecb5 --- /dev/null +++ b/cpu/mc1322x/adc/Makefile @@ -0,0 +1,5 @@ +INCLUDES = -I$(RIOTBASE)/cpu/mc1322x/adc/include + +MODULE =mc1322x_adc + +include $(MAKEBASE)/Makefile.base diff --git a/cpu/mc1322x/adc/adc.c b/cpu/mc1322x/adc/adc.c new file mode 100644 index 0000000000..5f22b96f94 --- /dev/null +++ b/cpu/mc1322x/adc/adc.c @@ -0,0 +1,192 @@ +/* + * adc.c - implementation of the Analog to Digital Converter module of the mc1322x MCU + * Copyright (C) 2013 Thomas Eichinger + * + * This source code is licensed under the GNU Lesser General Public License, + * Version 2. See the file LICENSE for more details. + * + * This file is part of RIOT. + */ + +#include "adc.h" +#include "gpio.h" + +#define ADC_CLOCK_DIVIDER_300kHz 0x50 + +#ifndef REF_OSC +#define REF_OSC 24000000UL /* reference osc. frequency */ +#endif + +#define ADC_PRESCALE_CLK 1000000 /* targeted prescale clk */ +#define ADC_PRESCALE_VALUE ((REF_OSC / ADC_PRESCALE_CLK)-1) + +#define ADC_CONVERT_TIME 23 /* function of prescale clk. has to be >= 20us */ + +#define ADC_NUM_CHANS 8 + +/** + * Initializes the ADC module. + * + * Analog Clk set to 300kHz + * Prescale Clk set to 1MHz + * Convert Time set to 23us + * Not using timers or IRQs + */ +void adc_init(void) +{ + /* configure frequencies */ + ADC->CLOCK_DIVIDER = ADC_CLOCK_DIVIDER_300kHz; + ADC->PRESCALE = ADC_PRESCALE_VALUE; + + /* power on */ + ADC->CONTROLbits.ON = 0x1; + + /* ON-TIME must be >= 10us */ + ADC->ON_TIME = 0xa; + + /* should be >= 20us (6 ADC clks) */ + ADC->CONVERT_TIME = ADC_CONVERT_TIME; + + /* automated mode */ + ADC->MODE = 0x0; + + /* don't use IRQs */ + ADC->FIFO_CONTROL = 0x0; + + /* disable all input channels */ + ADC->SEQ_1 = 0x0; + /* sequence using convert time */ + ADC->SEQ_1bits.SEQ_MODE = 0x0; + /* enable battery reference voltage channel */ + ADC->SEQ_1bits.BATT = 0x1; + + /* disable all input channels */ + ADC->SEQ_2 = 0x0; + /* sequence using convert time */ + ADC->SEQ_2bits.SEQ_MODE = 0x0; +} + +/** + * Set up a given channel 0...7 for ADC usage. + * + * \param channel The channel to set up + */ +void adc_setup_channel(uint8_t channel) +{ + switch (channel) { + case 0: + ADC->SEQ_1bits.CH0 = 0x1; + GPIO->FUNC_SEL.ADC0 = 0x1; + GPIO->PAD_DIR.ADC0 = 0x0; + GPIO->PAD_KEEP.ADC0 = 0x0; + GPIO->PAD_PU_EN.ADC0 = 0; + break; + + case 1: + ADC->SEQ_1bits.CH1 = 0x1; + GPIO->FUNC_SEL.ADC1 = 0x1; + GPIO->PAD_DIR.ADC1 = 0x0; + GPIO->PAD_KEEP.ADC1 = 0x0; + GPIO->PAD_PU_EN.ADC1 = 0; + break; + + case 2: + ADC->SEQ_1bits.CH2 = 0x1; + GPIO->FUNC_SEL.ADC2 = 0x1; + GPIO->PAD_DIR.ADC2 = 0x0; + GPIO->PAD_KEEP.ADC2 = 0x0; + GPIO->PAD_PU_EN.ADC2 = 0; + break; + + case 3: + ADC->SEQ_1bits.CH3 = 0x1; + GPIO->FUNC_SEL.ADC3 = 0x1; + GPIO->PAD_DIR.ADC3 = 0x0; + GPIO->PAD_KEEP.ADC3 = 0x0; + GPIO->PAD_PU_EN.ADC3 = 0; + break; + + case 4: + ADC->SEQ_1bits.CH4 = 0x1; + GPIO->FUNC_SEL.ADC4 = 0x1; + GPIO->PAD_DIR.ADC4 = 0x0; + GPIO->PAD_KEEP.ADC4 = 0x0; + GPIO->PAD_PU_EN.ADC4 = 0; + break; + + case 5: + ADC->SEQ_1bits.CH5 = 0x1; + GPIO->FUNC_SEL.ADC5 = 0x1; + GPIO->PAD_DIR.ADC5 = 0x0; + GPIO->PAD_KEEP.ADC5 = 0x0; + GPIO->PAD_PU_EN.ADC5 = 0; + break; + + case 6: + ADC->SEQ_1bits.CH6 = 0x1; + GPIO->FUNC_SEL.ADC6 = 0x1; + GPIO->PAD_DIR.ADC6 = 0x0; + GPIO->PAD_KEEP.ADC6 = 0x0; + GPIO->PAD_PU_EN.ADC6 = 0; + break; + + case 7: + ADC->SEQ_1bits.CH7 = 0x1; + GPIO->FUNC_SEL.ADC7 = 0x1; + GPIO->PAD_DIR.ADC7 = 0x0; + GPIO->PAD_KEEP.ADC7 = 0x0; + GPIO->PAD_PU_EN.ADC7 = 0; + break; + } +} + +/** + * Read from the ADC FIFO + * Reads a 16 bit value from the ADC FIFO. + * Bits 15:12 contain the channel the value origin. + * Bits 11:0 contain the actual measured value. + * + * \return 16 Bits containing the channel and the measurement. + */ +uint16_t adc_read(void) +{ + /* wait for ADC result */ + while (ADC->FIFO_STATUSbits.EMPTY) { + continue; + } + + /* upper 4 bits contain channel number */ + return ADC->FIFO_READ; +} + +/** + * Flushes any measured values from the ADC FIFO until FIFO is empty. + */ +void adc_flush(void) +{ + while (!ADC->FIFO_STATUSbits.EMPTY) { + ADC->FIFO_READ; + } +} + +/** + * When using several channels simultaniously this function can read + * values from the ADC FIFO and store them in an array sorted by the + * channel number. + * + * \param channels_read An array of 8 uint16_t the measured values get + * stored into. The user could use ADC_NUM_CHANS + * to asure compliancy. + */ +void adc_service(uint16_t *channels_read) +{ + uint16_t tmp; + + while (!ADC->FIFO_STATUSbits.EMPTY) { + tmp = ADC->FIFO_READ; + + if ((tmp >> 12) < ADC_NUM_CHANS) { + channels_read[tmp >> 12] = tmp & 0x0fff; + } + } +} diff --git a/cpu/mc1322x/adc/include/adc.h b/cpu/mc1322x/adc/include/adc.h new file mode 100644 index 0000000000..e3732a4d13 --- /dev/null +++ b/cpu/mc1322x/adc/include/adc.h @@ -0,0 +1,132 @@ +/* + * adc.h - Structure definition for registers of the + * Analog to Digital Converter module of the mc1322x MCU + * Copyright (C) 2013 Thomas Eichinger + * + * This source code is licensed under the GNU Lesser General Public License, + * Version 2. See the file LICENSE for more details. + * + * This file is part of RIOT. + */ + +#ifndef ADC_H +#define ADC_H + +#include + +#define ADC_BASE (0x8000D000) + +/* Structure-based register definitions */ +/* ADC registers are all 16-bit wide with 16-bit access only */ +struct ADC_struct { + union { + uint16_t COMP[8]; + struct { + uint16_t COMP_0; + uint16_t COMP_1; + uint16_t COMP_2; + uint16_t COMP_3; + uint16_t COMP_4; + uint16_t COMP_5; + uint16_t COMP_6; + uint16_t COMP_7; + }; + }; + uint16_t BAT_COMP_OVER; + uint16_t BAT_COMP_UNDER; + union { + uint16_t SEQ_1; + struct ADC_SEQ_1 { + uint16_t CH0: 1; + uint16_t CH1: 1; + uint16_t CH2: 1; + uint16_t CH3: 1; + uint16_t CH4: 1; + uint16_t CH5: 1; + uint16_t CH6: 1; + uint16_t CH7: 1; + uint16_t BATT: 1; + uint16_t : 6; + uint16_t SEQ_MODE: 1; + } SEQ_1bits; + }; + union { + uint16_t SEQ_2; + struct ADC_SEQ_2 { + uint16_t CH0: 1; + uint16_t CH1: 1; + uint16_t CH2: 1; + uint16_t CH3: 1; + uint16_t CH4: 1; + uint16_t CH5: 1; + uint16_t CH6: 1; + uint16_t CH7: 1; + uint16_t : 7; + uint16_t SEQ_MODE: 1; + } SEQ_2bits; + }; + union { + uint16_t CONTROL; + struct ADC_CONTROL { + uint16_t ON: 1; + uint16_t TIMER1_ON: 1; + uint16_t TIMER2_ON: 1; + uint16_t SOFT_RESET: 1; + uint16_t AD1_VREFHL_EN: 1; + uint16_t AD2_VREFHL_EN: 1; + uint16_t : 6; + uint16_t COMPARE_IRQ_MASK: 1; + uint16_t SEQ1_IRQ_MASK: 1; + uint16_t SEQ2_IRQ_MASK: 1; + uint16_t FIFO_IRQ_MASK: 1; + } CONTROLbits; + }; + uint16_t TRIGGERS; + uint16_t PRESCALE; + uint16_t reserved1; + uint16_t FIFO_READ; + uint16_t FIFO_CONTROL; + union { + uint16_t FIFO_STATUS; + struct ADC_FIFO_STATUS { + uint16_t LEVEL: 4; + uint16_t FULL: 1; + uint16_t EMPTY: 1; + uint16_t : 10; + } FIFO_STATUSbits; + }; + uint16_t reserved2[5]; + uint16_t SR_1_HIGH; + uint16_t SR_1_LOW; + uint16_t SR_2_HIGH; + uint16_t SR_2_LOW; + uint16_t ON_TIME; + uint16_t CONVERT_TIME; + uint16_t CLOCK_DIVIDER; + uint16_t reserved3; + union { + uint16_t OVERRIDE; + struct ADC_OVERRIDE { + uint16_t MUX1: 4; + uint16_t MUX2: 4; + uint16_t AD1_ON: 1; + uint16_t AD2_ON: 1; + uint16_t : 6; + } OVERRIDEbits; + }; + uint16_t IRQ; + uint16_t MODE; + uint16_t RESULT_1; + uint16_t RESULT_2; +}; + +static volatile struct ADC_struct *const ADC = (void *)(ADC_BASE); + +/* function prototypes */ +void adc_init(void); +void adc_setup_channel(uint8_t channel); +uint16_t adc_read(void); +void adc_flush(void); +void adc_service(uint16_t *channels_read); + +#endif /* ADC_H */ diff --git a/cpu/mc1322x/gpio.c b/cpu/mc1322x/gpio.c new file mode 100644 index 0000000000..f238d052da --- /dev/null +++ b/cpu/mc1322x/gpio.c @@ -0,0 +1,75 @@ +/* + * gpio.c - GPIO driver for redbee + * Copyright (C) 2013 Thomas Eichinger + * + * This source code is licensed under the GNU General Public License, + * Version 3. See the file LICENSE for more details. + * + * This file is part of RIOT. + */ + +#include "gpio.h" + +inline void gpio_pad_dir(volatile uint64_t data) +{ + GPIO->PAD_DIR0 = (data & 0xffffffff); + GPIO->PAD_DIR1 = (data >> 32); +} + +inline void gpio_data(volatile uint64_t data) +{ + GPIO->DATA0 = (data & 0xffffffff); + GPIO->DATA1 = (data >> 32); +} + +inline uint64_t gpio_data_get(volatile uint64_t bits) { + uint64_t rdata = 0; + + rdata = GPIO->DATA0 & (bits & 0xffffffff); + rdata |= (GPIO->DATA1 & (bits >> 32)) << 32; + + return rdata; +} + +inline void gpio_pad_pu_en(volatile uint64_t data) +{ + GPIO->PAD_PU_EN0 = (data & 0xffffffff); + GPIO->PAD_PU_EN1 = (data >> 32); +} + +inline void gpio_data_sel(volatile uint64_t data) +{ + GPIO->DATA_SEL0 = (data & 0xffffffff); + GPIO->DATA_SEL1 = (data >> 32); +} + +inline void gpio_pad_pu_sel(volatile uint64_t data) +{ + GPIO->PAD_PU_SEL0 = (data & 0xffffffff); + GPIO->PAD_PU_SEL1 = (data >> 32); +} + +inline void gpio_data_set(volatile uint64_t data) +{ + GPIO->DATA_SET0 = (data & 0xffffffff); + GPIO->DATA_SET1 = (data >> 32); +} + +inline void gpio_data_reset(volatile uint64_t data) +{ + GPIO->DATA_RESET0 = (data & 0xffffffff); + GPIO->DATA_RESET1 = (data >> 32); +} + +inline void gpio_pad_dir_set(volatile uint64_t data) +{ + GPIO->PAD_DIR_SET0 = (data & 0xffffffff); + GPIO->PAD_DIR_SET1 = (data >> 32); +} + +inline void gpio_pad_dir_reset(volatile uint64_t data) +{ + GPIO->PAD_DIR_RESET0 = (data & 0xffffffff); + GPIO->PAD_DIR_RESET1 = (data >> 32); +} + diff --git a/cpu/mc1322x/include/gpio.h b/cpu/mc1322x/include/gpio.h new file mode 100644 index 0000000000..78cef03508 --- /dev/null +++ b/cpu/mc1322x/include/gpio.h @@ -0,0 +1,160 @@ +/* + * gpio.h - GPIO driver for redbee + * Copyright (C) 2013 Thomas Eichinger + * + * This source code is licensed under the GNU General Public License, + * Version 3. See the file LICENSE for more details. + * + * This file is part of RIOT. + */ + +#ifndef GPIO_H +#define GPIO_H + +// TODO: why do we need to include this for macro expansion? +#include "stdint.h" + +/* Structure-based GPIO access + Example usage: + + GPIO->FUNC_SEL0 |= 0x00008000; // set a whole register + + GPIO->FUNC_SEL_08 = 2; // set just one pin + + #define MY_PIN GPIO_08 + GPIO->FUNC_SEL.MY_PIN = 2; // same, to allow #define for pin names + GPIO->DATA.MY_PIN = 1; + + gpio_set(GPIO_08); // efficiently set or clear a single output bit + gpio_reset(GPIO_08); +*/ + +// GPIO to Function Alias macros: + +#define ADC0 GPIO_30 +#define ADC1 GPIO_31 +#define ADC2 GPIO_32 +#define ADC3 GPIO_33 +#define ADC4 GPIO_34 +#define ADC5 GPIO_35 +#define ADC6 GPIO_36 +#define ADC7 GPIO_37 +#define TDO GPIO_49 +#define TDI GPIO_48 +#define TCK GPIO_47 +#define TMS GPIO_46 +#define U2RTS GPIO_21 +#define U2CTS GPIO_20 +#define U2RX GPIO_19 +#define U2TX GPIO_18 +#define U1RTS GPIO_17 +#define U1CTS GPIO_16 +#define U1RX GPIO_15 +#define U1TX GPIO_14 +#define SDA GPIO_13 +#define SCL GPIO_12 +#define TMR3 GPIO_11 +#define TMR2 GPIO_10 +#define TMR1 GPIO_09 +#define TMR0 GPIO_08 +#define SCK GPIO_07 +#define MOSI GPIO_06 +#define MISO GPIO_05 +#define SS GPIO_04 +#define BTCK GPIO_03 +#define FSYN GPIO_02 +#define SSIRX GPIO_01 +#define SSITX GPIO_00 +#define KBI7 GPIO_29 +#define KBI6 GPIO_28 +#define KBI5 GPIO_27 +#define KBI4 GPIO_26 +#define KBI3 GPIO_25 +#define KBI2 GPIO_24 +#define KBI1 GPIO_23 +#define KBI0 GPIO_22 +#define TXON GPIO_44 +#define RXON GPIO_45 +#define ANT1 GPIO_42 +#define ANT2 GPIO_43 +#define VREF2H GPIO_38 +#define VREF2L GPIO_39 +#define VREF1H GPIO_40 +#define VREF1L GPIO_41 +#define MDO0 GPIO_51 +#define MDO1 GPIO_52 +#define MDO2 GPIO_53 +#define MDO3 GPIO_54 +#define MDO4 GPIO_55 +#define MDO5 GPIO_56 +#define MDO6 GPIO_57 +#define MDO7 GPIO_58 +#define MSEO0 GPIO_59 +#define MSEO1 GPIO_60 +#define RDY GPIO_61 +#define EVTO GPIO_62 +#define MCKO GPIO_50 +#define EVTI GPIO_63 + + +#define _V(x,n,i) uint32_t x##_##i : n; +#define _REP(x,n) \ + _V(x,n,00) _V(x,n,01) _V(x,n,02) _V(x,n,03) _V(x,n,04) _V(x,n,05) _V(x,n,06) _V(x,n,07) \ + _V(x,n,08) _V(x,n,09) _V(x,n,10) _V(x,n,11) _V(x,n,12) _V(x,n,13) _V(x,n,14) _V(x,n,15) \ + _V(x,n,16) _V(x,n,17) _V(x,n,18) _V(x,n,19) _V(x,n,20) _V(x,n,21) _V(x,n,22) _V(x,n,23) \ + _V(x,n,24) _V(x,n,25) _V(x,n,26) _V(x,n,27) _V(x,n,28) _V(x,n,29) _V(x,n,30) _V(x,n,31) \ + _V(x,n,32) _V(x,n,33) _V(x,n,34) _V(x,n,35) _V(x,n,36) _V(x,n,37) _V(x,n,38) _V(x,n,39) \ + _V(x,n,40) _V(x,n,41) _V(x,n,42) _V(x,n,43) _V(x,n,44) _V(x,n,45) _V(x,n,46) _V(x,n,47) \ + _V(x,n,48) _V(x,n,49) _V(x,n,50) _V(x,n,51) _V(x,n,52) _V(x,n,53) _V(x,n,54) _V(x,n,55) \ + _V(x,n,56) _V(x,n,57) _V(x,n,58) _V(x,n,59) _V(x,n,60) _V(x,n,61) _V(x,n,62) _V(x,n,63) + +struct GPIO_struct { +#define _IO(x) \ + union { struct { uint32_t x##0; uint32_t x##1; }; \ + struct { _REP(x, 1) }; \ + struct GPIO_##x { _REP(GPIO, 1) } x; }; +#define _IO_2bit(x) \ + union { struct { uint32_t x##0; uint32_t x##1; uint32_t x##2; uint32_t x##3; }; \ + struct { _REP(x, 2) }; \ + struct GPIO_##x { _REP(GPIO, 2) } x; }; + + _IO(PAD_DIR); + _IO(DATA); + _IO(PAD_PU_EN); + _IO_2bit(FUNC_SEL); + _IO(DATA_SEL); + _IO(PAD_PU_SEL); + _IO(PAD_HYST_EN); + _IO(PAD_KEEP); + _IO(DATA_SET); + _IO(DATA_RESET); + _IO(PAD_DIR_SET); + _IO(PAD_DIR_RESET); +}; +#undef _IO +#undef _IO_2bit + +/* Build an enum lookup to map GPIO_08 -> 8 */ +#undef _V +#define _V(x,n,i) __NUM_GPIO_GPIO_##i, +enum { _REP(0,0) }; + +/* Macros to set or reset a data pin in the fastest possible way */ +#define gpio_set(gpio_xx) __gpio_set(gpio_xx) +#define __gpio_set(gpio_xx) \ + ((__NUM_GPIO_##gpio_xx < 32) \ + ? (GPIO->DATA_SET0 = (1 << (__NUM_GPIO_##gpio_xx - 0))) \ + : (GPIO->DATA_SET1 = (1 << (__NUM_GPIO_##gpio_xx - 32)))) +#define gpio_reset(gpio_xx) __gpio_reset(gpio_xx) +#define __gpio_reset(gpio_xx) \ + ((__NUM_GPIO_##gpio_xx < 32) \ + ? (GPIO->DATA_RESET0 = (1 << (__NUM_GPIO_##gpio_xx - 0))) \ + : (GPIO->DATA_RESET1 = (1 << (__NUM_GPIO_##gpio_xx - 32)))) + +#undef _REP +#undef _V + +static volatile struct GPIO_struct * const GPIO = (void *) (0x80000000); + +#endif +