Merge remote branch 'libmc1322x/master'

This commit is contained in:
Mariano Alvira 2011-03-11 16:28:14 -05:00
commit 59d7fad746
13 changed files with 1127 additions and 4 deletions

138
cpu/mc1322x/lib/adc.c Normal file
View file

@ -0,0 +1,138 @@
/*
* Copyright (c) 2010, Mariano Alvira <mar@devl.org> 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 <stdint.h>
#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);
}
}
}

View file

@ -0,0 +1,63 @@
#include <mc1322x.h>
#include <board.h>
#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;
}

View file

@ -0,0 +1,164 @@
/*
* Copyright (c) 2010, Mariano Alvira <mar@devl.org> 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 <stdint.h>
#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

View file

@ -0,0 +1,28 @@
#ifndef GPIO_UTIL_H
#define GPIO_UTIL_H
#include <stdbool.h>
#include <stdint.h>
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

View file

@ -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

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2010, Mariano Alvira <mar@devl.org> 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

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2010, Mariano Alvira <mar@devl.org> 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

View file

@ -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);

254
cpu/mc1322x/lib/pwm.c Normal file
View file

@ -0,0 +1,254 @@
/*
* Copyright (c) 2010, Mariano Alvira <mar@devl.org> 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 <mc1322x.h>
#include <stdlib.h>
#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;
}

202
cpu/mc1322x/lib/rtc.c Normal file
View file

@ -0,0 +1,202 @@
/*
* Copyright (c) 2010, Mariano Alvira <mar@devl.org> 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 <mc1322x.h>
#include <stdlib.h>
#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;
}

View file

@ -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

63
cpu/mc1322x/tests/adc.c Normal file
View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2010, Mariano Alvira <mar@devl.org> 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 <mc1322x.h>
#include <board.h>
#include <stdio.h>
#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<NUM_ADC_CHAN; c++) {
adc_service();
printf("%u %04u\r\n", c, adc_reading[c]);
}
}
}

85
cpu/mc1322x/tests/pwm.c Normal file
View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 2010, Mariano Alvira <mar@devl.org> 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 <mc1322x.h>
#include <board.h>
#include <stdio.h>
#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);
}
}