diff --git a/cpu/mc1322x/lib/adc.c b/cpu/mc1322x/lib/adc.c new file mode 100644 index 000000000..841855107 --- /dev/null +++ b/cpu/mc1322x/lib/adc.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2010, Mariano Alvira and other contributors + * to the MC1322x project (http://mc1322x.devl.org) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of libmc1322x: see http://mc1322x.devl.org + * for details. + * + * + */ + +#include +#include "crm.h" +#include "adc.h" +#include "gpio-util.h" + +//#define ADC_CHANS_ENABLED 0x3F // channels 0-5 enabled +//#define ADC_CHANS_ENABLED 0x7E // channels 1-6 enabled +//#define ADC_CHANS_ENABLED (1 << 6) // only channel 6 enabled +#define ADC_CHANS_ENABLED 0x1FF // all channels, including battery reference voltage + +//#define ADC_PRESCALE_VALUE 24 // divide by 24 for 1MHz. + +#define ADC_SAMPLE_FREQ 400 // Hz (minimum of ~366.21 Hz) +#define ADC_PRESCALE_VALUE (REF_OSC / ADC_SAMPLE_FREQ) + +#define ADC_USE_TIMER 0 +#define ADC_USE_INTERRUPTS 0 // incomplete support + +uint16_t adc_reading[NUM_ADC_CHAN]; + +void ADC_flush(void) { + while(ADC->FIFO_STATUSbits.EMPTY == 0) ADC->FIFO_READ; +} + +uint16_t ADC_READ(void) { + while(ADC->FIFO_STATUSbits.EMPTY); // loop while empty + return ADC->FIFO_READ; // upper 4 bits are channel number +} + + +void adc_service(void) { + uint16_t value; + uint8_t channel; + while (ADC->FIFO_STATUSbits.EMPTY == 0) { + value = ADC->FIFO_READ; + channel = value >> 12; + if (channel < NUM_ADC_CHAN) adc_reading[channel] = value & 0xFFF; + } +} + +void adc_init(void) { + uint8_t n; + + ADC->CLOCK_DIVIDER = 80; // 300 KHz + ADC->PRESCALE = ADC_PRESCALE_VALUE - 1; // divide by 24 for 1MHz. + + ADC->CONTROL = 1; + + // The ON-TIME must always be 10µs or greater - typical On-Time value = 0x000A (10dec) + ADC->ON_TIME = 10; + + /* + NOTE + The ADC analog block requires 6 ADC_Clocks per conversion, and the + ADC_Clock must 300kHz or less. With 6 clocks/conversion and a 33.33µs + clock period: + * The ADC convert time must always be 20µs or greater + * If the ADC_Clock is a frequency lower than 300kHz, the convert time + must always be 6 ADC_Clock periods or greater + * For override mode, extend convert time to 40µs minimum or greater + For the convert time: + * This delay is a function of the Prescale Clock (typically 1 MHz) + * The register must be initialized for proper operation + * For a 20µs convert time with 1MHz, value = 0x0014 (20dec) + * If convert time is insufficient, inaccurate sample data will result + */ + ADC->CONVERT_TIME = 1000000 / (115200 / 8) - 1; + + ADC->MODE = 0; // Automatic + +#if ADC_USE_INTERRUPTS + ADC->FIFO_CONTROL = 7; +#else + ADC->FIFO_CONTROL = 0; +#endif + +#if ADC_USE_TIMER + ADC->SR_1_HIGH = 0x0000; + ADC->SR_1_LOW = (REF_OSC / ADC_PRESCALE_VALUE) / (115200 / 8) + 1; +#endif + + ADC->SEQ_1 = 0 +#if ADC_USE_TIMER + | (1 << 15) // sequence based on Timer 1. +#else + | (0 << 15) // sequence based on convert time. +#endif + | ADC_CHANS_ENABLED; + + ADC->CONTROL = 0xF001 +//#if ADC_USE_TIMER + | (1 << 1) // Timer 1 enable +//#endif + ; + ADC->OVERRIDE = (1 << 8); + + for (n=0; n<=8; n++) { + if ((ADC_CHANS_ENABLED >> n) & 1) { + gpio_select_function(30 + n, 1); // Function 1 = ADC + gpio_set_pad_dir(30 + n, PAD_DIR_INPUT); + } + } +} diff --git a/cpu/mc1322x/lib/gpio-util.c b/cpu/mc1322x/lib/gpio-util.c new file mode 100644 index 000000000..e1f55d426 --- /dev/null +++ b/cpu/mc1322x/lib/gpio-util.c @@ -0,0 +1,63 @@ + +#include +#include + +#include "gpio-util.h" + +void gpio_select_function(uint8_t gpio, uint8_t func) { + uint32_t mask = 3; + uint8_t major, minor, shift; + volatile uint32_t *base = GPIO_FUNC_SEL0; + uint32_t value; + major = gpio >> 4; + minor = gpio & 0xF; + shift = 2 * minor; + + value = base[major]; + value &= ~(mask << shift); + value |= (func << shift); + base[major] = value; +} + +void gpio_reg_set(volatile uint32_t* reg, uint8_t bit) { + uint8_t major, minor; + major = bit / 32; + minor = bit % 32; + *(reg + major) |= (1UL << minor); +} + +void gpio_reg_clear(volatile uint32_t* reg, uint8_t bit) { + uint8_t major, minor; + major = bit / 32; + minor = bit % 32; + *(reg + major) &= ~(1UL << minor); +} + +void gpio_set_pad_dir(uint8_t gpio, uint8_t dir) { + uint8_t major, minor; + major = gpio / 32; + minor = gpio % 32; + if (dir) gpio_reg_set(GPIO_PAD_DIR0 + major, minor); + else gpio_reg_clear(GPIO_PAD_DIR0 + major, minor); +} + +void gpio_set(uint8_t gpio) { + uint8_t major, minor; + major = gpio / 32; + minor = gpio % 32; + *(GPIO_DATA_SET0 + major) = (1UL << minor); +} + +void gpio_reset(uint8_t gpio) { + uint8_t major, minor; + major = gpio / 32; + minor = gpio % 32; + *(GPIO_DATA_RESET0 + major) = (1UL << minor); +} + +bool gpio_read(uint8_t gpio) { + uint8_t major, minor; + major = gpio / 32; + minor = gpio % 32; + return (*(GPIO_DATA0 + major) >> minor) & 1; +} diff --git a/cpu/mc1322x/lib/include/adc.h b/cpu/mc1322x/lib/include/adc.h new file mode 100644 index 000000000..580e3545e --- /dev/null +++ b/cpu/mc1322x/lib/include/adc.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2010, Mariano Alvira and other contributors + * to the MC1322x project (http://mc1322x.devl.org) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of libmc1322x: see http://mc1322x.devl.org + * for details. + * + * + */ + +#ifndef ADC_H +#define ADC_H + +#include +#include "utils.h" + +/* ADC registers are all 16-bit wide with 16-bit access only */ +#define ADC_BASE (0x8000D000) + +/* Structure-based register definitions */ + +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_FREFHL_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); + +#define NUM_ADC_CHAN 9 + +#define adc_enable() (ADC->CONTROLbits.ON = 1) +#define adc_disable() (ADC->CONTROLbits.ON = 0) +#define adc_select_channels(chans) (ADC->SEQ_1 = (ADC->SEQ_1 & 0xFE00) | chans) + +extern uint16_t adc_reading[NUM_ADC_CHAN]; +void ADC_flush(void); +uint16_t ADC_READ(void); +void read_scanners(void); +void adc_init(void); +void adc_service(void); + +#endif diff --git a/cpu/mc1322x/lib/include/gpio-util.h b/cpu/mc1322x/lib/include/gpio-util.h new file mode 100644 index 000000000..258ecf097 --- /dev/null +++ b/cpu/mc1322x/lib/include/gpio-util.h @@ -0,0 +1,28 @@ + +#ifndef GPIO_UTIL_H +#define GPIO_UTIL_H + +#include +#include + +void gpio_select_function(uint8_t gpio, uint8_t func); +void gpio_reg_set(volatile uint32_t* reg, uint8_t bit); +void gpio_reg_clear(volatile uint32_t* reg, uint8_t bit); + +#define PAD_DIR_INPUT 0 +#define PAD_DIR_OUTPUT 1 +void gpio_set_pad_dir(uint8_t gpio, uint8_t dir); + +#undef gpio_set +#undef gpio_reset +#undef gpio_read + +//#define gpio_set gpio_set_ian +//#define gpio_reset gpio_reset_ian +//#define gpio_read gpio_read_ian + +void gpio_set(uint8_t gpio); +void gpio_reset(uint8_t gpio); +bool gpio_read(uint8_t gpio); + +#endif diff --git a/cpu/mc1322x/lib/include/maca.h b/cpu/mc1322x/lib/include/maca.h index 2f567a9ac..d9bb283b8 100644 --- a/cpu/mc1322x/lib/include/maca.h +++ b/cpu/mc1322x/lib/include/maca.h @@ -121,8 +121,8 @@ enum { #define LFSR 6 /* 1 use polynomial for Turbolink */ #define TM 5 -#define MODE 3 -#define MODE_MASK bit_mask(2,MODE) +#define MACA_MODE 3 +#define MODE_MASK bit_mask(2,MACA_MODE) #define NO_CCA 0 #define NO_SLOT_CCA 1 #define SLOT_CCA 2 diff --git a/cpu/mc1322x/lib/include/pwm.h b/cpu/mc1322x/lib/include/pwm.h new file mode 100644 index 000000000..65cfe1616 --- /dev/null +++ b/cpu/mc1322x/lib/include/pwm.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2010, Mariano Alvira and other contributors + * to the MC1322x project (http://mc1322x.devl.org) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of libmc1322x: see http://mc1322x.devl.org + * for details. + * + * + */ + +#ifndef PWM_H +#define PWM_H + +/* Initialize PWM output. + timer_num = 0, 1, 2, 3 + rate = desired rate in Hz, + duty = desired duty cycle. 0=always off, 65536=always on. + enable_timer = whether to actually run the timer, versus just configuring it + Returns actual PWM rate. */ +uint32_t pwm_init_ex(int timer_num, uint32_t rate, uint32_t duty, int enable_timer); + +/* Initialize PWM output, helper macros + timer = TMR0, TMR1, TMR2, TMR2 + rate = desired rate in Hz, + duty = desired duty cycle. 0=always off, 65536=always on. + Returns actual PWM rate. */ +#define pwm_init(timer,rate,duty) pwm_init_ex(TMR_NUM(timer), rate, duty, 1) +#define pwm_init_stopped(timer,rate,duty) pwm_init_ex(TMR_NUM(timer), rate, duty, 0) + +/* Change duty cycle. Safe to call at any time. + timer_num = 0, 1, 2, 3 + duty = desired duty cycle. 0=always off, 65536=always on. +*/ +void pwm_duty_ex(int timer_num, uint32_t duty); + +/* Change duty cycle. Safe to call at any time. + timer = TMR0, TMR1, TMR2, TMR2 + duty = desired duty cycle. 0=always off, 65536=always on. +*/ +#define pwm_duty(timer,duty) pwm_duty_ex(TMR_NUM(timer), duty) + +#endif diff --git a/cpu/mc1322x/lib/include/rtc.h b/cpu/mc1322x/lib/include/rtc.h new file mode 100644 index 000000000..cda1d60cb --- /dev/null +++ b/cpu/mc1322x/lib/include/rtc.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010, Mariano Alvira and other contributors + * to the MC1322x project (http://mc1322x.devl.org) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of libmc1322x: see http://mc1322x.devl.org + * for details. + * + * + */ + +#ifndef RTC_H +#define RTC_H + +/* Init RTC (and calibrate, if using ring oscillator) */ +void rtc_init_osc(int use_32khz); + +#ifdef USE_32KHZ +#define rtc_init() rtc_init_osc(USE_32KHZ) +#else +#define rtc_init() rtc_init_osc(0) +#endif + +/* Calibrate the ring oscillator */ +void rtc_calibrate(void); + +/* Delay for the specified number of milliseconds by polling RTC */ +void rtc_delay_ms(uint32_t msec); + +/* Calibrated frequency of the RTC, in Hz */ +extern int rtc_freq; + +#endif diff --git a/cpu/mc1322x/lib/maca.c b/cpu/mc1322x/lib/maca.c index 06f74a6aa..d68b5a394 100644 --- a/cpu/mc1322x/lib/maca.c +++ b/cpu/mc1322x/lib/maca.c @@ -184,7 +184,7 @@ void maca_init(void) { /* nop, promiscuous, no cca */ *MACA_CONTROL = (prm_mode << PRM) | - (NO_CCA << MODE); + (NO_CCA << MACA_MODE); enable_irq(MACA); *INTFRC = (1 << INT_NUM_MACA); diff --git a/cpu/mc1322x/lib/pwm.c b/cpu/mc1322x/lib/pwm.c new file mode 100644 index 000000000..8ee8f2eb1 --- /dev/null +++ b/cpu/mc1322x/lib/pwm.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2010, Mariano Alvira and other contributors + * to the MC1322x project (http://mc1322x.devl.org) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of libmc1322x: see http://mc1322x.devl.org + * for details. + * + * + */ + +#include +#include +#include "pwm.h" + +static struct { + uint32_t period; + uint32_t guard; + uint32_t pad_forced; +} pwm_info[4]; + +static inline void pad_set_output(int timer_num) { // set to output (when in GPIO mode) + switch (timer_num) { + case 0: GPIO->DATA_SEL.TMR0_PIN = 1; GPIO->PAD_DIR.TMR0_PIN = 1; break; + case 1: GPIO->DATA_SEL.TMR1_PIN = 1; GPIO->PAD_DIR.TMR1_PIN = 1; break; + case 2: GPIO->DATA_SEL.TMR2_PIN = 1; GPIO->PAD_DIR.TMR2_PIN = 1; break; + case 3: GPIO->DATA_SEL.TMR3_PIN = 1; GPIO->PAD_DIR.TMR3_PIN = 1; break; + default: break; + } +} + +static inline void pad_set_zero(int timer_num) { // set to zero in GPIO mode + switch (timer_num) { + case 0: GPIO->DATA_RESET.TMR0_PIN = 1; GPIO->FUNC_SEL.TMR0_PIN = 0; break; + case 1: GPIO->DATA_RESET.TMR1_PIN = 1; GPIO->FUNC_SEL.TMR1_PIN = 0; break; + case 2: GPIO->DATA_RESET.TMR2_PIN = 1; GPIO->FUNC_SEL.TMR2_PIN = 0; break; + case 3: GPIO->DATA_RESET.TMR3_PIN = 1; GPIO->FUNC_SEL.TMR3_PIN = 0; break; + default: break; + } +} + +static inline void pad_set_one(int timer_num) { // set to one in GPIO mode + switch (timer_num) { + case 0: GPIO->DATA_SET.TMR0_PIN = 1; GPIO->FUNC_SEL.TMR0_PIN = 0; break; + case 1: GPIO->DATA_SET.TMR1_PIN = 1; GPIO->FUNC_SEL.TMR1_PIN = 0; break; + case 2: GPIO->DATA_SET.TMR2_PIN = 1; GPIO->FUNC_SEL.TMR2_PIN = 0; break; + case 3: GPIO->DATA_SET.TMR3_PIN = 1; GPIO->FUNC_SEL.TMR3_PIN = 0; break; + default: break; + } +} + +static inline void pad_set_normal(int timer_num) { // set to TMR OFLAG output + switch (timer_num) { + case 0: GPIO->FUNC_SEL.TMR0_PIN = 1; break; + case 1: GPIO->FUNC_SEL.TMR1_PIN = 1; break; + case 2: GPIO->FUNC_SEL.TMR2_PIN = 1; break; + case 3: GPIO->FUNC_SEL.TMR3_PIN = 1; break; + default: break; + } +} + +/* Initialize PWM output. + timer_num = 0, 1, 2, 3 + rate = desired rate in Hz, + duty = desired duty cycle. 0=always off, 65536=always on. + enable_timer = whether to actually run the timer, versus just configuring it + Returns actual PWM rate. */ +uint32_t pwm_init_ex(int timer_num, uint32_t rate, uint32_t duty, int enable_timer) +{ + uint32_t actual_rate; + volatile struct TMR_struct *timer = TMR_ADDR(timer_num); + int log_divisor = 0; + uint32_t period, guard; + + /* Turn timer off */ + TMR0->ENBL &= ~(1 << timer_num); + + /* Calculate optimal rate */ + for (log_divisor = 0; log_divisor < 8; log_divisor++) + { + int denom = (rate * (1 << log_divisor)); + period = (REF_OSC + denom/2) / denom; + if (period <= 65535) + break; + } + if (log_divisor >= 8) + { + period = 65535; + log_divisor = 7; + } + + /* Guard value (for safely changing duty cycle) should be + about 32 CPU clocks. Calculate how many timer counts that + is, based on prescaler */ + guard = 32 >> log_divisor; + if (guard < 2) guard = 2; + + /* Period should be about 50% longer than guard */ + if (period < ((guard * 3) / 2)) + period = guard + 4; + + /* Store period, guard, actual rate */ + pwm_info[timer_num].period = period; + pwm_info[timer_num].guard = guard; + actual_rate = REF_OSC / (period * (1 << log_divisor)); + + /* Set up timer */ + pwm_duty_ex(timer_num, duty); // sets CMPLD1, LOAD + timer->SCTRLbits = (struct TMR_SCTRL) { + .OEN = 1, // drive OFLAG + }; + timer->CSCTRLbits = (struct TMR_CSCTRL) { + .CL1 = 0x01, // Reload COMP1 when COMP1 matches + }; + timer->COMP1 = timer->CMPLD1; + timer->CNTR = timer->LOAD; + timer->CTRLbits = (struct TMR_CTRL) { + .COUNT_MODE = 1, // Count rising edge of primary source + .PRIMARY_CNT_SOURCE = 8 + log_divisor, // Peripheral clock divided by (divisor) + .LENGTH = 1, // At compare, reset to LOAD + .OUTPUT_MODE = 6, // Set on COMP1, clear on rollover + }; + + pad_set_output(timer_num); + pad_set_normal(timer_num); + + if (enable_timer) { + TMR0->ENBL |= (1 << timer_num); + } + +// printf("pwm timer %d, addr %p, requested rate %d, actual rate: %d, period %d, guard %d, divisor %d\r\n", +// timer_num, timer, rate, actual_rate, period, guard, 1 << log_divisor); + + return actual_rate; +} + +/* Change duty cycle. Safe to call at any time. + timer_num = 0, 1, 2, 3 + duty = desired duty cycle. 0=always off, 65536=always on. +*/ +void pwm_duty_ex(int timer_num, uint32_t duty) +{ + uint16_t comp1, load; + volatile struct TMR_struct *timer = TMR_ADDR(timer_num); + uint32_t period = pwm_info[timer_num].period; + + duty = (duty * period + 32767) / 65536; + + /* We don't use the "variable PWM" mode described in the datasheet because + there's no way to reliably change the duty cycle without potentially + changing the period for one cycle, which will cause phase drifts. + + Instead, we use the "Set on compare, clear on rollover" output mode: + + waveform: |_________| |----------| + counter: 0 COMP1 LOAD 65535 + + The low portion of the wave is COMP1 cycles long. The + compare changes the counter to LOAD, and so the high + portion is (65536 - LOAD) cycles long. + + Now, we just have to make sure we're not about to hit COMP1 + before we change LOAD and COMPLD1. If (COMP1 - CNTR) is less + than GUARD cycles, we wait for it to reload before changing. + */ + + if (duty == 0) { + pad_set_zero(timer_num); + pwm_info[timer_num].pad_forced = 1; + return; + } + + if (duty >= period) { + pad_set_one(timer_num); + pwm_info[timer_num].pad_forced = 1; + return; + } + + if (pwm_info[timer_num].pad_forced) { + pad_set_normal(timer_num); + pwm_info[timer_num].pad_forced = 0; + } + + comp1 = (period - duty) - 1; + load = (65536 - duty); + + /* Disable interrupts */ + uint32_t old_INTCNTL = ITC->INTCNTL; + ITC->INTCNTL = 0; + + if (TMR0->ENBL & (1 << timer_num)) + { + /* Timer is enabled, so use the careful approach. + Implemented in ASM so we can be sure of the cycle + count */ + uint32_t tmp1, tmp2; + asm volatile (//".arm \n\t" + "1: \n\t" + "ldrh %[tmp1], %[comp] \n\t" // load COMP1 + "ldrh %[tmp2], %[count] \n\t" // load CNTR + "sub %[tmp1], %[tmp1], %[tmp2] \n\t" // subtract + "lsl %[tmp1], %[tmp1], #16 \n\t" // clear high bits + "lsr %[tmp1], %[tmp1], #16 \n\t" + "cmp %[tmp1], %[guard] \n\t" // compare to GUARD + "bls 1b \n\t" // if less, goto 1 + + "strh %[ld1], %[cmpld] \n\t" // store CMPLD1 + "strh %[ld2], %[load] \n\t" // store LOAD + : /* out */ + [tmp1] "=&l" (tmp1), + [tmp2] "=&l" (tmp2), + [cmpld] "=m" (timer->CMPLD1), + [load] "=m" (timer->LOAD) + : /* in */ + [comp] "m" (timer->COMP1), + [count] "m" (timer->CNTR), + [ld1] "l" (comp1), + [ld2] "l" (load), + [guard] "l" (pwm_info[timer_num].guard) + : "memory" + ); + } else { + /* Just set it directly, timer isn't running */ + timer->CMPLD1 = comp1; + timer->LOAD = load; + } + + /* Re-enable interrupts */ + ITC->INTCNTL = old_INTCNTL; +} diff --git a/cpu/mc1322x/lib/rtc.c b/cpu/mc1322x/lib/rtc.c new file mode 100644 index 000000000..383384c38 --- /dev/null +++ b/cpu/mc1322x/lib/rtc.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2010, Mariano Alvira and other contributors + * to the MC1322x project (http://mc1322x.devl.org) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of libmc1322x: see http://mc1322x.devl.org + * for details. + * + * + */ + +#include +#include +#include "rtc.h" + +/* Define USE_32KHZ in board.h to start and use the 32 KHz + oscillator, otherwise the 2 KHz ring oscillator is used. */ + +int rtc_freq = 0; +static int __use_32khz = 0; + +/* Init RTC */ +void rtc_init_osc(int use_32khz) +{ + __use_32khz = use_32khz; + + if (use_32khz) + { + uint32_t old; + + /* You have to hold its hand with this one */ + /* once you start the 32KHz crystal it can only be + * stopped with a reset (hard or soft). */ + + /* first, disable the ring osc */ + CRM->RINGOSC_CNTLbits.ROSC_EN = 0; + + /* enable the 32kHZ crystal */ + CRM->XTAL32_CNTLbits.XTAL32_EN = 1; + + /* set the XTAL32_EXISTS bit */ + /* the datasheet says to do this after you check that RTC_COUNT + is changing, but it is not correct; it needs to be set first */ + CRM->SYS_CNTLbits.XTAL32_EXISTS = 1; + + old = CRM->RTC_COUNT; + while (CRM->RTC_COUNT == old) + continue; + + /* RTC has started up */ + rtc_freq = 32000; + } + else + { + /* Enable ring osc */ + CRM->RINGOSC_CNTLbits.ROSC_EN = 1; + CRM->XTAL32_CNTLbits.XTAL32_EN = 0; + + /* Set default tune values from datasheet */ + CRM->RINGOSC_CNTLbits.ROSC_CTUNE = 0x6; + CRM->RINGOSC_CNTLbits.ROSC_FTUNE = 0x17; + + /* Trigger calibration */ + rtc_calibrate(); + } +} + +uint32_t __rtc_try(int loading, int timeout) +{ + /* Total loading is + ctune * 1000 fF + ftune * 160 fF + ctune = 0-15 + ftune = 0-31 + max = 19960 fF + */ + +#define RTC_LOADING_MIN 0 +#define RTC_LOADING_MAX 19960 + + /* The fine tune covers a range larger than a single coarse + step. Check all coarse steps within the fine tune range to + find the optimal CTUNE, FTUNE pairs. */ +#define CTUNE_MAX 15 +#define FTUNE_MAX 31 +#define CSTEP 1000 +#define FSTEP 160 +#define MAX_F (FSTEP*FTUNE_MAX) /* actually lcm(CSTEP,FSTEP) would be better, + but in this case it's basically the same */ + int ctune; + int ftune; + int ctune_start = (loading - MAX_F) / CSTEP; + int ctune_end = loading / CSTEP; + int best_err = loading, best_ctune = 0, best_ftune = 0; + + uint32_t count; + + if (ctune_start < 0) ctune_start = 0; + if (ctune_end > CTUNE_MAX) ctune_end = CTUNE_MAX; + + for (ctune = ctune_start; ctune <= ctune_end; ctune++) + { + int this_loading, this_err; + + ftune = ((loading - (ctune * CSTEP)) + (FSTEP / 2)) / FSTEP; + if (ftune < 0) ftune = 0; + if (ftune > FTUNE_MAX) ftune = FTUNE_MAX; + + this_loading = ctune * CSTEP + ftune * FSTEP; + this_err = abs(this_loading - loading); + if (this_err < best_err) { + best_err = this_err; + best_ctune = ctune; + best_ftune = ftune; + } + } + +// printf("requested loading %d, actual loading %d\r\n", loading, +// best_ctune * CSTEP + best_ftune * FSTEP); + + /* Run the calibration */ + CRM->RINGOSC_CNTLbits.ROSC_CTUNE = best_ctune; + CRM->RINGOSC_CNTLbits.ROSC_FTUNE = best_ftune; + CRM->CAL_CNTLbits.CAL_TIMEOUT = timeout; + CRM->STATUSbits.CAL_DONE = 1; + CRM->CAL_CNTLbits.CAL_EN = 1; + while (CRM->STATUSbits.CAL_DONE == 0) + continue; + + /* Result should ideally be close to (REF_OSC * (timeout / 2000)) */ + count = CRM->CAL_COUNT; + if (count == 0) count = 1; /* avoid divide by zero problems */ + return count; +} + +/* Calibrate the ring oscillator */ +void rtc_calibrate(void) +{ + /* Just bisect a few times. Our best tuning accuracy is about + 1/500 of the full scale, so doing this 8-9 times is about + as accurate as we can get */ + int i; + int low = RTC_LOADING_MIN, high = RTC_LOADING_MAX; + int mid; + uint32_t count; + + if (__use_32khz) { + rtc_freq = 32000; + return; + } + +#define TIMEOUT 100 /* 50 msec per attempt */ + + for (i = 0; i < 9; i++) + { + mid = (low + high) / 2; + count = __rtc_try(mid, TIMEOUT); + // careful about overflow + rtc_freq = REF_OSC / ((count + TIMEOUT/2) / TIMEOUT); + + if (rtc_freq > 2000) + low = mid; // increase loading + else + high = mid; // decrease loading + } + +// printf("RTC calibrated to %d Hz\r\n", rtc_freq); +} + + +/* Delay for the specified number of milliseconds by polling RTC */ +void rtc_delay_ms(uint32_t msec) +{ + uint32_t start; + + start = CRM->RTC_COUNT; + while ((CRM->RTC_COUNT - start) < ((msec * rtc_freq) / 1000)) + continue; +} diff --git a/cpu/mc1322x/tests/Makefile b/cpu/mc1322x/tests/Makefile index 88c66dae2..0380d4f8b 100644 --- a/cpu/mc1322x/tests/Makefile +++ b/cpu/mc1322x/tests/Makefile @@ -11,7 +11,9 @@ TARGETS := blink-red blink-green blink-blue blink-white blink-allio \ tmr tmr-ints \ sleep \ printf \ - asm + asm \ + adc \ + pwm # these targets are built with space reserved for variables needed by ROM services # this space is initialized with a rom call to rom_data_init diff --git a/cpu/mc1322x/tests/adc.c b/cpu/mc1322x/tests/adc.c new file mode 100644 index 000000000..28a98ce75 --- /dev/null +++ b/cpu/mc1322x/tests/adc.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010, Mariano Alvira and other contributors + * to the MC1322x project (http://mc1322x.devl.org) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of libmc1322x: see http://mc1322x.devl.org + * for details. + * + * + */ + +#include +#include +#include + +#include "config.h" +#include "adc.h" + +int main(void) +{ + uint8_t c; + + trim_xtal(); + uart1_init(INC,MOD,SAMP); + adc_init(); + + printf("adc test\r\n"); + + printf("\x1B[2J"); // clear screen + + for(;;) { + printf("\x1B[H"); // cursor home + printf("# Value\r\n"); + for (c=0; c and other contributors + * to the MC1322x project (http://mc1322x.devl.org) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of libmc1322x: see http://mc1322x.devl.org + * for details. + * + * + */ + +#include +#include +#include + +#include "config.h" +#include "pwm.h" +#include "rtc.h" + +int main(void) +{ + int x = 32768; + + trim_xtal(); + uart1_init(INC,MOD,SAMP); + rtc_init(); + + printf("pwm test\r\n"); + pwm_init_stopped(TMR0, 12000000, x); + pwm_init_stopped(TMR1, 12000000, x); + TMR0->ENBL |= TMR_ENABLE_BIT(TMR0) | TMR_ENABLE_BIT(TMR1); + + for(;;) { + printf("duty %d = %d%%\r\n", x, ((x * 100 + 32768) / 65536)); + switch(uart1_getc()) { + case '[': x -= 1; break; + case ']': x += 1; break; + case '-': x -= 32; break; + case '=': x += 32; break; + case '_': x -= 512; break; + case '+': x += 512; break; + + case '`': x = 65535 * 0/10; break; + case '1': x = 65535 * 1/10; break; + case '2': x = 65535 * 2/10; break; + case '3': x = 65535 * 3/10; break; + case '4': x = 65535 * 4/10; break; + case '5': x = 65535 * 5/10; break; + case '6': x = 65535 * 6/10; break; + case '7': x = 65535 * 7/10; break; + case '8': x = 65535 * 8/10; break; + case '9': x = 65535 * 9/10; break; + case '0': x = 65535 * 10/10; break; + + } + x &= 65535; + pwm_duty(TMR0, x); + } +} + +