mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
c0628a3058
add peripheral drivers for Freescale Kinetis MCUs: adc driver cpuid driver gpio driver hwtimer_arch driver (hwtimer used Low Power Timer) i2c driver (master mode only) mcg driver pwm driver random_rnga driver random_rngb driver rtc driver spi driver timer driver (timer used Periodic Interrupt Timer) uart driver add doc.txt (configuration examples) random_rnga: Update RNGA driver in preparation for RNGB driver. random_rngb: Add RNGB driver. spi: refactor SPI to work for multiple CTARS, add spi_acquire, spi_release gpio: Add gpio_irq_enable, gpio_irq_disable. Refactor GPIO. gpio: Add gpio_irq_enable, gpio_irq_disable. gpio: Refactor ISR functions to work with all GPIOs (0-31) and all ports (PORTA-PORTH) adc: Refactor ADC, add calibration and scaling. Added integer scaling of results in adc_map. Handle precision setting in adc_init. Set ADC clock divider depending on module clock. Add ADC_1 as a possible device. Add ADC calibration procedure according to K60 ref manual. Handle ADC pins which are not part of the pin function mux. Signed-off-by: Joakim Gebart <joakim.gebart@eistec.se>
369 lines
7.5 KiB
C
369 lines
7.5 KiB
C
/*
|
|
* Copyright (C) 2014 Freie Universität Berlin
|
|
* Copyright (C) 2014 PHYTEC Messtechnik GmbH
|
|
*
|
|
* 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_kinetis_common_timer
|
|
*
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Low-level timer driver implementation
|
|
*
|
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
|
* @author Johann Fischer <j.fischer@phytec.de>
|
|
*
|
|
* @}
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "cpu.h"
|
|
#include "board.h"
|
|
#include "sched.h"
|
|
#include "thread.h"
|
|
#include "periph_conf.h"
|
|
#include "periph/timer.h"
|
|
|
|
#define ENABLE_DEBUG (0)
|
|
#include "debug.h"
|
|
|
|
#if TIMER_NUMOF
|
|
|
|
/** Type for timer state */
|
|
typedef struct {
|
|
void (*cb)(int);
|
|
} timer_conf_t;
|
|
|
|
/** Type for virtual count up timer */
|
|
typedef struct {
|
|
uint32_t counter32b;
|
|
uint32_t diff;
|
|
} count_up_timer_t;
|
|
|
|
static count_up_timer_t cu_timer[TIMER_NUMOF];
|
|
|
|
/** Timer state memory */
|
|
static timer_conf_t config[TIMER_NUMOF];
|
|
|
|
inline static void pit_timer_start(uint8_t ch)
|
|
{
|
|
TIMER_DEV->CHANNEL[ch].TCTRL |= (PIT_TCTRL_TEN_MASK);
|
|
}
|
|
|
|
inline static void pit_timer_stop(uint8_t ch)
|
|
{
|
|
TIMER_DEV->CHANNEL[ch].TCTRL &= ~(PIT_TCTRL_TEN_MASK);
|
|
}
|
|
|
|
/** use channel n-1 as prescaler */
|
|
inline static void timer_set_prescaler(uint8_t ch, unsigned int ticks_per_us)
|
|
{
|
|
TIMER_DEV->CHANNEL[ch].TCTRL = 0x0;
|
|
TIMER_DEV->CHANNEL[ch].LDVAL = (TIMER_CLOCK / 1e6) / ticks_per_us;
|
|
TIMER_DEV->CHANNEL[ch].TCTRL = (PIT_TCTRL_TEN_MASK);
|
|
}
|
|
|
|
inline static void timer_set_counter(uint8_t ch)
|
|
{
|
|
TIMER_DEV->CHANNEL[ch].TCTRL = 0x0;
|
|
TIMER_DEV->CHANNEL[ch].LDVAL = TIMER_MAX_VALUE;
|
|
TIMER_DEV->CHANNEL[ch].TCTRL = (PIT_TCTRL_TIE_MASK | PIT_TCTRL_CHN_MASK);
|
|
}
|
|
|
|
inline static uint32_t pit_timer_read(tim_t dev, uint8_t ch)
|
|
{
|
|
return cu_timer[dev].counter32b + (TIMER_DEV->CHANNEL[ch].LDVAL
|
|
- TIMER_DEV->CHANNEL[ch].CVAL);
|
|
}
|
|
|
|
inline static void pit_timer_set_max(uint8_t ch)
|
|
{
|
|
pit_timer_stop(ch);
|
|
TIMER_DEV->CHANNEL[ch].LDVAL = TIMER_MAX_VALUE;
|
|
pit_timer_start(ch);
|
|
}
|
|
|
|
int timer_init(tim_t dev, unsigned int ticks_per_us, void (*callback)(int))
|
|
{
|
|
PIT_Type *timer = TIMER_DEV;
|
|
|
|
/* enable timer peripheral clock */
|
|
TIMER_CLKEN();
|
|
|
|
timer->MCR = PIT_MCR_FRZ_MASK;
|
|
|
|
switch (dev) {
|
|
#if TIMER_0_EN
|
|
|
|
case TIMER_0:
|
|
NVIC_SetPriority(TIMER_0_IRQ_CHAN, TIMER_IRQ_PRIO);
|
|
timer_set_prescaler(TIMER_0_PRESCALER_CH, ticks_per_us);
|
|
timer_set_counter(TIMER_0_COUNTER_CH);
|
|
break;
|
|
#endif
|
|
#if TIMER_1_EN
|
|
|
|
case TIMER_1:
|
|
NVIC_SetPriority(TIMER_1_IRQ_CHAN, TIMER_IRQ_PRIO);
|
|
timer_set_prescaler(TIMER_1_PRESCALER_CH, ticks_per_us);
|
|
timer_set_counter(TIMER_1_COUNTER_CH);
|
|
break;
|
|
#endif
|
|
|
|
case TIMER_UNDEFINED:
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
/* set callback function */
|
|
config[dev].cb = callback;
|
|
cu_timer[dev].counter32b = 0;
|
|
cu_timer[dev].diff = 0;
|
|
|
|
/* enable the timer's interrupt */
|
|
timer_irq_enable(dev);
|
|
|
|
/* start the timer */
|
|
timer_start(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int timer_set(tim_t dev, int channel, unsigned int timeout)
|
|
{
|
|
unsigned int now = timer_read(dev);
|
|
|
|
return timer_set_absolute(dev, channel, now + timeout);
|
|
}
|
|
|
|
int timer_set_absolute(tim_t dev, int channel, unsigned int value)
|
|
{
|
|
switch (dev) {
|
|
#if TIMER_0_EN
|
|
|
|
case TIMER_0:
|
|
pit_timer_stop(TIMER_0_COUNTER_CH);
|
|
cu_timer[dev].counter32b = pit_timer_read(dev, TIMER_0_COUNTER_CH);
|
|
cu_timer[dev].diff = value - cu_timer[dev].counter32b;
|
|
TIMER_DEV->CHANNEL[TIMER_0_COUNTER_CH].LDVAL = cu_timer[dev].diff;
|
|
pit_timer_start(TIMER_0_COUNTER_CH);
|
|
break;
|
|
#endif
|
|
#if TIMER_1_EN
|
|
|
|
case TIMER_1:
|
|
pit_timer_stop(TIMER_1_COUNTER_CH);
|
|
cu_timer[dev].counter32b = pit_timer_read(dev, TIMER_1_COUNTER_CH);
|
|
cu_timer[dev].diff = value - cu_timer[dev].counter32b;
|
|
TIMER_DEV->CHANNEL[TIMER_1_COUNTER_CH].LDVAL = cu_timer[dev].diff;
|
|
pit_timer_start(TIMER_1_COUNTER_CH);
|
|
break;
|
|
#endif
|
|
|
|
case TIMER_UNDEFINED:
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
DEBUG("cntr: %lu, value: %u, diff: %lu\n",
|
|
cu_timer[dev].counter32b, value, cu_timer[dev].diff);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int timer_clear(tim_t dev, int channel)
|
|
{
|
|
switch (dev) {
|
|
#if TIMER_0_EN
|
|
|
|
case TIMER_0:
|
|
cu_timer[dev].counter32b = timer_read(dev);
|
|
cu_timer[dev].diff = 0;
|
|
pit_timer_set_max(TIMER_0_COUNTER_CH);
|
|
break;
|
|
#endif
|
|
#if TIMER_1_EN
|
|
|
|
case TIMER_1:
|
|
cu_timer[dev].counter32b = timer_read(dev);
|
|
cu_timer[dev].diff = 0;
|
|
pit_timer_set_max(TIMER_1_COUNTER_CH);
|
|
break;
|
|
#endif
|
|
|
|
case TIMER_UNDEFINED:
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
DEBUG("clear\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
unsigned int timer_read(tim_t dev)
|
|
{
|
|
switch (dev) {
|
|
#if TIMER_0_EN
|
|
|
|
case TIMER_0:
|
|
return pit_timer_read(dev, TIMER_0_COUNTER_CH);
|
|
break;
|
|
#endif
|
|
#if TIMER_1_EN
|
|
|
|
case TIMER_1:
|
|
return pit_timer_read(dev, TIMER_1_COUNTER_CH);
|
|
break;
|
|
#endif
|
|
|
|
case TIMER_UNDEFINED:
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void timer_start(tim_t dev)
|
|
{
|
|
switch (dev) {
|
|
#if TIMER_0_EN
|
|
|
|
case TIMER_0:
|
|
pit_timer_start(TIMER_0_COUNTER_CH);
|
|
break;
|
|
#endif
|
|
#if TIMER_1_EN
|
|
|
|
case TIMER_1:
|
|
pit_timer_start(TIMER_1_COUNTER_CH);
|
|
break;
|
|
#endif
|
|
|
|
case TIMER_UNDEFINED:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void timer_stop(tim_t dev)
|
|
{
|
|
switch (dev) {
|
|
#if TIMER_0_EN
|
|
|
|
case TIMER_0:
|
|
pit_timer_stop(TIMER_0_COUNTER_CH);
|
|
break;
|
|
#endif
|
|
#if TIMER_1_EN
|
|
|
|
case TIMER_1:
|
|
pit_timer_stop(TIMER_1_COUNTER_CH);
|
|
break;
|
|
#endif
|
|
|
|
case TIMER_UNDEFINED:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void timer_irq_enable(tim_t dev)
|
|
{
|
|
switch (dev) {
|
|
#if TIMER_0_EN
|
|
|
|
case TIMER_0:
|
|
NVIC_EnableIRQ(TIMER_0_IRQ_CHAN);
|
|
break;
|
|
#endif
|
|
#if TIMER_1_EN
|
|
|
|
case TIMER_1:
|
|
NVIC_EnableIRQ(TIMER_1_IRQ_CHAN);
|
|
break;
|
|
#endif
|
|
|
|
case TIMER_UNDEFINED:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void timer_irq_disable(tim_t dev)
|
|
{
|
|
switch (dev) {
|
|
#if TIMER_0_EN
|
|
|
|
case TIMER_0:
|
|
NVIC_DisableIRQ(TIMER_0_IRQ_CHAN);
|
|
break;
|
|
#endif
|
|
#if TIMER_1_EN
|
|
|
|
case TIMER_1:
|
|
NVIC_DisableIRQ(TIMER_1_IRQ_CHAN);
|
|
break;
|
|
#endif
|
|
|
|
case TIMER_UNDEFINED:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void timer_reset(tim_t dev)
|
|
{
|
|
switch (dev) {
|
|
#if TIMER_0_EN
|
|
|
|
case TIMER_0:
|
|
pit_timer_set_max(TIMER_0_COUNTER_CH);
|
|
break;
|
|
#endif
|
|
#if TIMER_1_EN
|
|
|
|
case TIMER_1:
|
|
pit_timer_set_max(TIMER_1_COUNTER_CH);
|
|
break;
|
|
#endif
|
|
|
|
case TIMER_UNDEFINED:
|
|
break;
|
|
}
|
|
}
|
|
|
|
inline static void pit_timer_irq_handler(tim_t dev, uint8_t ch)
|
|
{
|
|
cu_timer[dev].counter32b += TIMER_DEV->CHANNEL[ch].LDVAL;
|
|
|
|
TIMER_DEV->CHANNEL[ch].TFLG = PIT_TFLG_TIF_MASK;
|
|
|
|
if (cu_timer[dev].diff) {
|
|
if (config[dev].cb != NULL) {
|
|
config[dev].cb(0);
|
|
}
|
|
}
|
|
|
|
if (sched_context_switch_request) {
|
|
thread_yield();
|
|
}
|
|
}
|
|
|
|
#if TIMER_0_EN
|
|
void TIMER_0_ISR(void)
|
|
{
|
|
pit_timer_irq_handler(TIMER_0, TIMER_0_COUNTER_CH);
|
|
}
|
|
#endif
|
|
|
|
#if TIMER_1_EN
|
|
void TIMER_1_ISR(void)
|
|
{
|
|
pit_timer_irq_handler(TIMER_1, TIMER_1_COUNTER_CH);
|
|
}
|
|
#endif
|
|
|
|
#endif
|