From f715e9b7879dc91762502582f31f4f14c7c35d36 Mon Sep 17 00:00:00 2001 From: v01d Date: Tue, 9 Aug 2016 14:01:27 -0300 Subject: [PATCH] RTC working, I2C in progress --- arch/arm/src/kinetis/Make.defs | 4 + arch/arm/src/kinetis/chip/kinetis_rtc.h | 8 +- arch/arm/src/kinetis/kinetis_alarm.h | 78 ++++++ arch/arm/src/kinetis/kinetis_i2c.c | 38 ++- arch/arm/src/kinetis/kinetis_rtc.c | 323 ++++++++++++++++++++++++ configs/teensy-3.x/include/board.h | 8 +- configs/teensy-3.x/src/k20_boot.c | 10 + configs/teensy-3.x/src/k20_i2c.c | 36 ++- configs/teensy-3.x/src/teensy-3x.h | 2 +- 9 files changed, 482 insertions(+), 25 deletions(-) create mode 100644 arch/arm/src/kinetis/kinetis_alarm.h create mode 100644 arch/arm/src/kinetis/kinetis_rtc.c diff --git a/arch/arm/src/kinetis/Make.defs b/arch/arm/src/kinetis/Make.defs index 4bbc493d90b..29eec9505af 100644 --- a/arch/arm/src/kinetis/Make.defs +++ b/arch/arm/src/kinetis/Make.defs @@ -135,6 +135,10 @@ ifeq ($(CONFIG_I2C),y) CHIP_CSRCS += kinetis_i2c.c endif +ifeq ($(CONFIG_RTC),y) +CHIP_CSRCS += kinetis_rtc.c +endif + ifeq ($(CONFIG_NET),y) ifeq ($(CONFIG_KINETIS_ENET),y) CHIP_CSRCS += kinetis_enet.c diff --git a/arch/arm/src/kinetis/chip/kinetis_rtc.h b/arch/arm/src/kinetis/chip/kinetis_rtc.h index d00c02a6974..948c6ce8771 100644 --- a/arch/arm/src/kinetis/chip/kinetis_rtc.h +++ b/arch/arm/src/kinetis/chip/kinetis_rtc.h @@ -59,7 +59,7 @@ #define KINETIS_RTC_CR_OFFSET 0x0010 /* RTC Control Register */ #define KINETIS_RTC_SR_OFFSET 0x0014 /* RTC Status Register */ #define KINETIS_RTC_LR_OFFSET 0x0018 /* RTC Lock Register */ -#if defined(KINETIS_K40) || defined(KINETIS_K64) +#if defined(KINETIS_K20) || defined(KINETIS_K40) || defined(KINETIS_K64) # define KINETIS_RTC_IER_OFFSET 0x001c /* RTC Interrupt Enable Register (K40) */ #endif #ifdef KINETIS_K60 @@ -77,7 +77,7 @@ #define KINETIS_RTC_CR (KINETIS_RTC_BASE+KINETIS_RTC_CR_OFFSET) #define KINETIS_RTC_SR (KINETIS_RTC_BASE+KINETIS_RTC_SR_OFFSET) #define KINETIS_RTC_LR (KINETIS_RTC_BASE+KINETIS_RTC_LR_OFFSET) -#if defined(KINETIS_K40) || defined(KINETIS_K64) +#if defined(KINETIS_K20) || defined(KINETIS_K40) || defined(KINETIS_K64) # define KINETIS_RTC_IER (KINETIS_RTC_BASE+KINETIS_RTC_IER_OFFSET) #endif #ifdef KINETIS_K60 @@ -135,13 +135,13 @@ #define RTC_LR_TCL (1 << 3) /* Bit 3: Time Compensation Lock */ #define RTC_LR_CRL (1 << 4) /* Bit 4: Control Register Lock */ #define RTC_LR_SRL (1 << 5) /* Bit 5: Status Register Lock */ -#ifdef KINETIS_K40 +#if defined(KINETIS_K20) || defined(KINETIS_K40) # define RTC_LR_LRL (1 << 6) /* Bit 6: Lock Register Lock (K40) */ #endif /* Bits 7-31: Reserved */ /* RTC Interrupt Enable Register (32-bits, K40) */ -#if defined(KINETIS_K40) || defined(KINETIS_K64) +#if defined(KINETIS_K20) || defined(KINETIS_K40) || defined(KINETIS_K64) # define RTC_IER_TIIE (1 << 0) /* Bit 0: Time Invalid Interrupt Enable */ # define RTC_IER_TOIE (1 << 1) /* Bit 1: Time Overflow Interrupt Enable */ # define RTC_IER_TAIE (1 << 2) /* Bit 2: Time Alarm Interrupt Enable */ diff --git a/arch/arm/src/kinetis/kinetis_alarm.h b/arch/arm/src/kinetis/kinetis_alarm.h new file mode 100644 index 00000000000..ee135a5eb2f --- /dev/null +++ b/arch/arm/src/kinetis/kinetis_alarm.h @@ -0,0 +1,78 @@ +#ifndef __ARCH_ARM_SRC_KINETIS_ALARM_H +#define __ARCH_ARM_SRC_KINETIS_ALARM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +#ifdef CONFIG_RTC_ALARM + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/* The form of an alarm callback */ + +typedef CODE void (*alarmcb_t)(void); + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: kinetis_rtc_setalarm + * + * Description: + * Set up an alarm. + * + * Input Parameters: + * tp - the time to set the alarm + * callback - the function to call when the alarm expires. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +struct timespec; +int kinetis_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback); + +/**************************************************************************** + * Name: kinetis_rtc_cancelalarm + * + * Description: + * Cancel a pending alarm alarm + * + * Input Parameters: + * none + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int kinetis_rtc_cancelalarm(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_RTC_ALARM */ +#endif /* __ARCH_ARM_SRC_KINETIS_ALARM_H */ diff --git a/arch/arm/src/kinetis/kinetis_i2c.c b/arch/arm/src/kinetis/kinetis_i2c.c index 750cee6dd2f..8bfc75b928a 100644 --- a/arch/arm/src/kinetis/kinetis_i2c.c +++ b/arch/arm/src/kinetis/kinetis_i2c.c @@ -42,8 +42,10 @@ #define I2C_DEFAULT_FREQUENCY 400000 -#define STATE_OK 0 -#define STATE_ABORTED 1 +#define STATE_OK 0 +#define STATE_ARBITRATION_ERROR 1 +#define STATE_TIMEOUT 2 +#define STATE_NAK 3 /* * TODO: @@ -289,14 +291,23 @@ static void kinetis_i2c_setfrequency(struct kinetis_i2cdev_s *priv, static int kinetis_i2c_start(struct kinetis_i2cdev_s *priv) { struct i2c_msg_s *msg; + irqstate_t flags; msg = priv->msgs; + i2cinfo("start"); + + flags = enter_critical_section(); + /* now take control of the bus */ if (getreg8(KINETIS_I2C0_C1) & I2C_C1_MST) { /* we are already the bus master, so send a repeated start */ - putreg8(I2C_C1_IICEN | I2C_C1_MST | I2C_C1_RSTA | I2C_C1_TX, KINETIS_I2C0_C1); + putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_RSTA | I2C_C1_TX, KINETIS_I2C0_C1); +#if 0 + putreg8(I2C_C1_IICEN | I2C_C1_IICIE, KINETIS_I2C0_C1); /* DEBUG: stop + start */ + putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX, KINETIS_I2C0_C1); +#endif } else { @@ -304,7 +315,7 @@ static int kinetis_i2c_start(struct kinetis_i2cdev_s *priv) while (getreg8(KINETIS_I2C0_S) & I2C_S_BUSY); /* become the bus master in transmit mode (send start) */ - putreg8(I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX, KINETIS_I2C0_C1); + putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX, KINETIS_I2C0_C1); } /* wait until start condition establishes control of the bus */ @@ -317,7 +328,9 @@ static int kinetis_i2c_start(struct kinetis_i2cdev_s *priv) I2C_READADDR8(msg->addr) : I2C_WRITEADDR8(msg->addr), KINETIS_I2C0_D); - return 0; + leave_critical_section(flags); + + return OK; } /**************************************************************************** @@ -347,7 +360,7 @@ static void kinetis_i2c_timeout(int argc, uint32_t arg, ...) struct kinetis_i2cdev_s *priv = (struct kinetis_i2cdev_s *)arg; irqstate_t flags = enter_critical_section(); - priv->state = STATE_ABORTED; + priv->state = STATE_TIMEOUT; sem_post(&priv->wait); leave_critical_section(flags); } @@ -393,22 +406,22 @@ static int kinetis_i2c_interrupt(int irq, FAR void *context) if (irq == KINETIS_IRQ_I2C0) { - priv = &g_i2c_dev; + priv = &g_i2c_dev; } else { - PANIC(); + PANIC(); } /* get current state */ state = getreg8(KINETIS_I2C0_S); - msg = priv->msgs; + msg = priv->msgs; /* arbitration lost */ if (state & I2C_S_ARBL) { putreg8(I2C_S_IICIF | I2C_S_ARBL, KINETIS_I2C0_S); - priv->state = STATE_ABORTED; + priv->state = STATE_ARBITRATION_ERROR; kinetis_i2c_stop(priv); } else @@ -424,7 +437,7 @@ static int kinetis_i2c_interrupt(int irq, FAR void *context) /* last write was not acknowledged */ if (state & I2C_S_RXAK) { - priv->state = STATE_ABORTED; /* set error flag */ + priv->state = STATE_NAK; /* set error flag */ kinetis_i2c_stop(priv); /* send STOP */ } else @@ -541,7 +554,8 @@ static int kinetis_i2c_transfer(FAR struct i2c_master_s *dev, wd_cancel(priv->timeout); /* Process next message */ - kinetis_i2c_nextmsg(priv); + if (priv->state == STATE_OK) + kinetis_i2c_nextmsg(priv); } /* release access to I2C bus */ diff --git a/arch/arm/src/kinetis/kinetis_rtc.c b/arch/arm/src/kinetis/kinetis_rtc.c new file mode 100644 index 00000000000..3d0af29c60d --- /dev/null +++ b/arch/arm/src/kinetis/kinetis_rtc.c @@ -0,0 +1,323 @@ +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "up_arch.h" + +#include "kinetis_config.h" +#include "chip.h" +#include "chip/kinetis_rtc.h" +#include "chip/kinetis_sim.h" +#include "kinetis.h" +#include "kinetis_alarm.h" + +#if defined(CONFIG_RTC) + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +/************************************************************************************ + * Private Data + ************************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static alarmcb_t g_alarmcb; +#endif + +/************************************************************************************ + * Private Declarations + ************************************************************************************/ + +static int kinetis_rtc_interrupt(int irq, void *context); + +/************************************************************************************ + * Public Data + ************************************************************************************/ + +volatile bool g_rtc_enabled = false; + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: up_rtc_initialize + * + * Description: + * Initialize the hardware RTC per the selected configuration. This function is + * called once during the OS initialization sequence + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +int up_rtc_initialize(void) +{ + int regval; + + /* enable RTC module */ + regval = getreg32(KINETIS_SIM_SCGC6); + regval |= SIM_SCGC6_RTC; + putreg32(regval, KINETIS_SIM_SCGC6); + + /* disable counters (just in case) */ + putreg32(0, KINETIS_RTC_SR); + + /* enable oscilator */ + putreg32(RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE, KINETIS_RTC_CR); /* capacitance values from teensyduino */ + /* TODO: delay some time (1024 cycles? would be 30ms) */ + + /* disable interrupts */ + putreg32(0, KINETIS_RTC_IER); + + /* reset flags requires writing the seconds register, the following line avoids altering any stored time value */ + putreg32(getreg32(KINETIS_RTC_TSR), KINETIS_RTC_TSR); + +#if defined(CONFIG_RTC_ALARM) + /* enable alarm interrupts */ + irq_attach(KINETIS_IRQ_RTC, kinetis_rtc_interrupt); + up_enable_irq(KINETIS_IRQ_RTC); +#endif + + /* enable counters */ + putreg32(RTC_SR_TCE, KINETIS_RTC_SR); + + /* mark RTC enabled */ + g_rtc_enabled = true; + + return OK; +} + +/************************************************************************************ + * Name: up_rtc_time + * + * Description: + * Get the current time in seconds. This is similar to the standard time() + * function. This interface is only required if the low-resolution RTC/counter + * hardware implementation selected. It is only used by the RTOS during + * initialization to set up the system time when CONFIG_RTC is set but neither + * CONFIG_RTC_HIRES nor CONFIG_RTC_DATETIME are set. + * + * Input Parameters: + * None + * + * Returned Value: + * The current time in seconds + * + ************************************************************************************/ + +#ifndef CONFIG_RTC_HIRES +time_t up_rtc_time(void) +{ + return getreg32(KINETIS_RTC_TSR); +} +#endif + +/************************************************************************************ + * Name: up_rtc_gettime + * + * Description: + * Get the current time from the high resolution RTC clock/counter. This interface + * is only supported by the high-resolution RTC/counter hardware implementation. + * It is used to replace the system timer. + * + * Input Parameters: + * tp - The location to return the high resolution time value. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +#ifdef CONFIG_RTC_HIRES +int up_rtc_gettime(FAR struct timespec *tp) +{ + irqstate_t flags; + uint32_t seconds, prescaler, prescaler2; + + /* + * get prescaler and seconds register. this is in a loop which + * ensures that registers will be re-read if during the reads the + * prescaler has wrapped-around + */ + + flags = enter_critical_section(); + do + { + prescaler = getreg32(KINETIS_RTC_TPR); + seconds = getreg32(KINETIS_RTC_TSR); + prescaler2 = getreg32(KINETIS_RTC_TPR); + } + while (prescaler > prescaler2); + leave_critical_section(flags); + + /* build seconds + nanoseconds from seconds and prescaler register */ + tp->tv_sec = seconds; + tp->tv_nsec = prescaler * (1000000000 / CONFIG_RTC_FREQUENCY); + return OK; +} +#endif + +/************************************************************************************ + * Name: up_rtc_settime + * + * Description: + * Set the RTC to the provided time. All RTC implementations must be able to + * set their time based on a standard timespec. + * + * Input Parameters: + * tp - the time to use + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +int up_rtc_settime(FAR const struct timespec *tp) +{ + irqstate_t flags; + uint32_t seconds, prescaler; + + seconds = tp->tv_sec; + prescaler = tp->tv_nsec * (CONFIG_RTC_FREQUENCY / 1000000000); + + flags = enter_critical_section(); + + putreg32(0, KINETIS_RTC_SR); /* disable counter */ + + putreg32(prescaler, KINETIS_RTC_TPR); /* always write prescaler first */ + putreg32(seconds, KINETIS_RTC_TSR); + + putreg32(RTC_SR_TCE, KINETIS_RTC_SR); /* re-enable counter */ + + leave_critical_section(flags); + + return OK; +} + +/************************************************************************************ + * Private Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: kinetis_rtc_setalarm + * + * Description: + * Set up an alarm. + * + * Input Parameters: + * tp - the time to set the alarm + * callback - the function to call when the alarm expires. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +int kinetis_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback) +{ + /* Is there already something waiting on the ALARM? */ + if (g_alarmcb == NULL) + { + /* No.. Save the callback function pointer */ + + g_alarmcb = callback; + + /* Enable and set RTC alarm */ + + putreg32(tp->tv_sec, KINETIS_RTC_TAR); /* set alarm (also resets flags) */ + putreg32(RTC_IER_TAIE, KINETIS_RTC_IER); /* enable alarm interrupt */ + + return OK; + } + else + return -EBUSY; +} +#endif + +/************************************************************************************ + * Name: kinetis_rtc_cancelalarm + * + * Description: + * Cancel a pending alarm alarm + * + * Input Parameters: + * none + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +int kinetis_rtc_cancelalarm(void) +{ + if (g_alarmcb != NULL) + { + /* Cancel the global callback function */ + + g_alarmcb = NULL; + + /* Unset the alarm */ + + putreg32(0, KINETIS_RTC_IER); /* disable alarm interrupt */ + + return OK; + } + else + return -ENODATA; +} +#endif + +/************************************************************************************ + * Name: kinetis_rtc_interrupt + * + * Description: + * RTC interrupt service routine + * + * Input Parameters: + * irq - The IRQ number that generated the interrupt + * context - Architecture specific register save information. + * + * Returned Value: + * Zero (OK) on success; A negated errno value on failure. + * + ************************************************************************************/ + +#if defined(CONFIG_RTC_ALARM) +static int kinetis_rtc_interrupt(int irq, void *context) +{ + if (g_alarmcb != NULL) + { + /* Alarm callback */ + g_alarmcb(); + g_alarmcb = NULL; + } + + /* Clear pending flags, disable alarm */ + putreg32(0, KINETIS_RTC_TAR); /* unset alarm (resets flags) */ + putreg32(0, KINETIS_RTC_IER); /* disable alarm interrupt */ + + return 0; +} +#endif + +#endif // KINETIS_RTC diff --git a/configs/teensy-3.x/include/board.h b/configs/teensy-3.x/include/board.h index 869bbe255fa..d0c5c0002ba 100644 --- a/configs/teensy-3.x/include/board.h +++ b/configs/teensy-3.x/include/board.h @@ -190,7 +190,7 @@ #define LED_STACKCREATED 1 /* STATUS LED=ON */ #define LED_INIRQ 2 /* STATUS LED=no change */ #define LED_SIGNAL 2 /* STATUS LED=no change */ -#define LED_ASSERTION 2 /* STATUS LED=no change */ +#define LED_ASSERTION 3 /* STATUS LED=no change */ #define LED_PANIC 3 /* STATUS LED=flashing */ /* Button definitions ***************************************************************/ @@ -233,12 +233,12 @@ #endif #ifdef CONFIG_KINETIS_I2C0 -#ifndef CONFIG_TEENSY_3X_I2C_ALT_PINS +#ifdef CONFIG_TEENSY_3X_I2C_ALT_PINS # define PIN_I2C0_SCL (PIN_I2C0_SCL_1 | PIN_ALT2_OPENDRAIN | PIN_ALT2_SLOW | PIN_ALT2_HIGHDRIVE) # define PIN_I2C0_SDA (PIN_I2C0_SDA_1 | PIN_ALT2_OPENDRAIN | PIN_ALT2_SLOW | PIN_ALT2_HIGHDRIVE) #else -# define PIN_I2C0_SCL (PIN_I2C0_SCL_2 | PIN_ALT2_OPENDRAIN | PIN_ALT2_SLOW | PIN_ALT2_HIGHDRIVE) -# define PIN_I2C0_SDA (PIN_I2C0_SDA_2 | PIN_ALT2_OPENDRAIN | PIN_ALT2_SLOW | PIN_ALT2_HIGHDRIVE) +# define PIN_I2C0_SCL (PIN_I2C0_SCL_2 | PIN_ALT2_OPENDRAIN | PIN_ALT2_SLOW /*| PIN_ALT2_HIGHDRIVE*/) +# define PIN_I2C0_SDA (PIN_I2C0_SDA_2 | PIN_ALT2_OPENDRAIN | PIN_ALT2_SLOW /*| PIN_ALT2_HIGHDRIVE*/) #endif #endif diff --git a/configs/teensy-3.x/src/k20_boot.c b/configs/teensy-3.x/src/k20_boot.c index 6bd0282ddf4..cfb62f9b260 100644 --- a/configs/teensy-3.x/src/k20_boot.c +++ b/configs/teensy-3.x/src/k20_boot.c @@ -88,3 +88,13 @@ void kinetis_boardinitialize(void) board_autoled_initialize(); #endif } + +#if defined(CONFIG_BOARD_INITIALIZE) +void board_initialize(void) +{ +#if defined(CONFIG_KINETIS_I2C0) || defined(CONFIG_KINETIS_I2C1) + //if (kinetis_i2cdev_initialize) + kinetis_i2cdev_initialize(); +#endif +} +#endif diff --git a/configs/teensy-3.x/src/k20_i2c.c b/configs/teensy-3.x/src/k20_i2c.c index 3f4e4ffa7cf..be546056fc0 100644 --- a/configs/teensy-3.x/src/k20_i2c.c +++ b/configs/teensy-3.x/src/k20_i2c.c @@ -2,6 +2,24 @@ * Included Files ************************************************************************************/ +#if 0 +#include + +#include +#include +#include + +#include +#include +#include + +#include "up_arch.h" +#include "chip.h" +#include "kinetis.h" +#include "teensy-3x.h" +#include "kinetis_i2c.h" +#endif + #include #include @@ -14,8 +32,9 @@ #include "up_arch.h" #include "chip.h" #include "kinetis.h" -#include "teensy-3x.h" #include "kinetis_i2c.h" +#include "teensy-3x.h" + #if defined(CONFIG_KINETIS_I2C0) || defined(CONFIG_KINETIS_I2C1) @@ -31,14 +50,23 @@ * ************************************************************************************/ -void weak_function kinetis_i2cdev_initialize(void) +void kinetis_i2cdev_initialize(void) { + FAR struct i2c_master_s *i2c; + #if defined(CONFIG_KINETIS_I2C0) - kinetis_i2cbus_initialize(0); + i2c = kinetis_i2cbus_initialize(0); +#if defined(CONFIG_I2C_DRIVER) + i2c_register(i2c, 0); +#endif #endif + #if defined(CONFIG_KINETIS_I2C1) - kinetis_i2cbus_initialize(1); + i2c = kinetis_i2cbus_initialize(1); +#if defined(CONFIG_I2C_DRIVER) + i2c_register(i2c, 1); +#endif #endif } diff --git a/configs/teensy-3.x/src/teensy-3x.h b/configs/teensy-3.x/src/teensy-3x.h index 5124a29f754..a50f5b0606e 100644 --- a/configs/teensy-3.x/src/teensy-3x.h +++ b/configs/teensy-3.x/src/teensy-3x.h @@ -100,7 +100,7 @@ extern void weak_function kinetis_spidev_initialize(void); * ************************************************************************************/ -extern void weak_function kinetis_i2cdev_initialize(void); +void kinetis_i2cdev_initialize(void); /************************************************************************************ * Name: kinetis_usbinitialize