[KINETIS] HAL cleanup/update.

New entries in kinetis_registry.h to support new MCUs.
Moved registers to ext/CMSIS, like it is done for STM32.
Move the same drivers to LLD.
Add USB driver.
This commit is contained in:
flabbergast 2016-03-22 17:51:46 +00:00
parent ca6f8bd296
commit d5a880807b
37 changed files with 3884 additions and 5619 deletions

View File

@ -39,7 +39,7 @@
#ifdef __CC_ARM
__attribute__ ((section(".ARM.__at_0x400")))
#else
__attribute__ ((used, section(".cfmconfig")))
__attribute__ ((used,section(".cfmconfig")))
#endif
const uint8_t _cfm[0x10] = {
0xFF, /* NV_BACKKEY3: KEY=0xFF */
@ -84,7 +84,7 @@ void hal_lld_init(void) {
}
/**
* @brief MK20D5 clock initialization.
* @brief K20x clock initialization.
* @note All the involved constants come from the file @p board.h.
* @note This function is meant to be invoked early during the system
* initialization, it is usually invoked from the file
@ -93,16 +93,9 @@ void hal_lld_init(void) {
*
* @special
*/
void mk20d50_clock_init(void) {
void k20x_clock_init(void) {
#if !KINETIS_NO_INIT
#if KINETIS_MCG_MODE == KINETIS_MCG_MODE_PEE
uint32_t ratio, frdiv;
uint32_t ratios[] = { 32, 64, 128, 256, 512, 1024, 1280, 1536 };
int ratio_quantity = sizeof(ratios) / sizeof(ratios[0]);
int i;
#endif /* KINETIS_MCG_MODE == KINETIS_MCG_MODE_PEE */
/* Disable the watchdog */
WDOG->UNLOCK = 0xC520;
WDOG->UNLOCK = 0xD928;
@ -115,14 +108,24 @@ void mk20d50_clock_init(void) {
SIM_SCGC5_PORTE;
#if KINETIS_MCG_MODE == KINETIS_MCG_MODE_FEI
/* This is the default mode at reset. */
/* Configure FEI mode */
MCG->C4 = MCG_C4_DRST_DRS(KINETIS_MCG_FLL_DRS) |
(KINETIS_MCG_FLL_DMX32 ? MCG_C4_DMX32 : 0);
#endif /* KINETIS_MCG_MODE == KINETIS_MCG_MODE_FEI */
/* Set clock dividers */
SIM->CLKDIV1 = SIM_CLKDIV1_OUTDIV1(KINETIS_CLKDIV1_OUTDIV1-1) |
SIM_CLKDIV1_OUTDIV2(KINETIS_CLKDIV1_OUTDIV2-1) |
SIM_CLKDIV1_OUTDIV4(KINETIS_CLKDIV1_OUTDIV4-1);
SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(0); /* not strictly necessary since usb_lld will set this */
#if KINETIS_MCG_MODE == KINETIS_MCG_MODE_PEE
#elif KINETIS_MCG_MODE == KINETIS_MCG_MODE_PEE
uint32_t ratio, frdiv;
uint32_t ratios[] = { 32, 64, 128, 256, 512, 1024, 1280, 1536 };
uint8_t ratio_quantity = sizeof(ratios) / sizeof(ratios[0]);
uint8_t i;
/* EXTAL0 and XTAL0 */
PORTA->PCR[18] = 0;
@ -132,8 +135,13 @@ void mk20d50_clock_init(void) {
* Start in FEI mode
*/
/* Disable capacitors for crystal */
OSC->CR = 0;
/* Internal capacitors for crystal */
#if defined(KINETIS_BOARD_OSCILLATOR_SETTING)
OSC0->CR = KINETIS_BOARD_OSCILLATOR_SETTING;
#else /* KINETIS_BOARD_OSCILLATOR_SETTING */
/* Disable the internal capacitors */
OSC0->CR = 0;
#endif /* KINETIS_BOARD_OSCILLATOR_SETTING */
/* TODO: need to add more flexible calculation, specially regarding
* divisors which may not be available depending on the XTAL
@ -141,13 +149,13 @@ void mk20d50_clock_init(void) {
*/
/* Enable OSC, low power mode */
MCG->C2 = MCG_C2_LOCRE0 | MCG_C2_EREFS0;
if (KINETIS_XTAL_FREQUENCY > 8000000)
if (KINETIS_XTAL_FREQUENCY > 8000000UL)
MCG->C2 |= MCG_C2_RANGE0(2);
else
MCG->C2 |= MCG_C2_RANGE0(1);
frdiv = 7;
ratio = KINETIS_XTAL_FREQUENCY / 31250;
ratio = KINETIS_XTAL_FREQUENCY / 31250UL;
for (i = 0; i < ratio_quantity; ++i) {
if (ratio == ratios[i]) {
frdiv = i;
@ -170,22 +178,42 @@ void mk20d50_clock_init(void) {
/*
* Now in FBE mode
*/
#define KINETIS_PLLIN_FREQUENCY 2000000UL
/*
* Config PLL input for 2 MHz
* TODO: Make sure KINETIS_XTAL_FREQUENCY >= 2Mhz && <= 50Mhz
*/
MCG->C5 = MCG_C5_PRDIV0((KINETIS_XTAL_FREQUENCY/KINETIS_PLLIN_FREQUENCY) - 1);
/* Config PLL input for 2 MHz */
MCG->C5 = MCG_C5_PRDIV0((KINETIS_XTAL_FREQUENCY / 2000000) - 1);
/*
* Config PLL output to match KINETIS_SYSCLK_FREQUENCY
* TODO: make sure KINETIS_SYSCLK_FREQUENCY is a match
*/
for(i = 24; i < 56; i++)
{
if(i == (KINETIS_PLLCLK_FREQUENCY/KINETIS_PLLIN_FREQUENCY))
{
/* Config PLL to match KINETIS_PLLCLK_FREQUENCY */
MCG->C6 = MCG_C6_PLLS | MCG_C6_VDIV0(i-24);
break;
}
}
/* Config PLL for 96 MHz output */
MCG->C6 = MCG_C6_PLLS | MCG_C6_VDIV0(0);
if(i>=56) /* Config PLL for 96 MHz output as default setting */
MCG->C6 = MCG_C6_PLLS | MCG_C6_VDIV0(0);
/* Wait for PLL to start using crystal as its input */
while (!(MCG->S & MCG_S_PLLST));
/* Wait for PLL to lock */
while (!(MCG->S & MCG_S_LOCK0));
/* Wait for PLL to start using crystal as its input, and to lock */
while ((MCG->S & (MCG_S_PLLST|MCG_S_LOCK0))!=(MCG_S_PLLST|MCG_S_LOCK0));
/*
* Now in PBE mode
*/
/* Set the PLL dividers for the different clocks */
SIM->CLKDIV1 = SIM_CLKDIV1_OUTDIV1(KINETIS_CLKDIV1_OUTDIV1-1) |
SIM_CLKDIV1_OUTDIV2(KINETIS_CLKDIV1_OUTDIV2-1) |
SIM_CLKDIV1_OUTDIV4(KINETIS_CLKDIV1_OUTDIV4-1);
SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(0);
SIM->SOPT2 = SIM_SOPT2_PLLFLLSEL;
/* Switch to PLL as clock source */
MCG->C1 = MCG_C1_CLKS(0);
@ -196,7 +224,9 @@ void mk20d50_clock_init(void) {
/*
* Now in PEE mode
*/
#endif /* KINETIS_MCG_MODE == KINETIS_MCG_MODE_PEE */
#else /* KINETIS_MCG_MODE == KINETIS_MCG_MODE_PEE */
#error Unimplemented KINETIS_MCG_MODE
#endif /* KINETIS_MCG_MODE == ... */
#endif /* !KINETIS_NO_INIT */
}

View File

@ -15,8 +15,8 @@
*/
/**
* @file KL2x/hal_lld.h
* @brief Kinetis KL2x HAL subsystem low level driver header.
* @file K20x/hal_lld.h
* @brief Kinetis K20x HAL subsystem low level driver header.
*
* @addtogroup HAL
* @{
@ -25,7 +25,6 @@
#ifndef _HAL_LLD_H_
#define _HAL_LLD_H_
#include "mk20d5.h"
#include "kinetis_registry.h"
/*===========================================================================*/
@ -44,16 +43,6 @@
#define PLATFORM_NAME "Kinetis"
/** @} */
/**
* @brief Maximum system and core clock (f_SYS) frequency.
*/
#define KINETIS_SYSCLK_MAX 48000000
/**
* @brief Maximum bus clock (f_BUS) frequency.
*/
#define KINETIS_BUSCLK_MAX 24000000
/**
* @name Internal clock sources
* @{
@ -94,24 +83,56 @@
#endif
/**
* @brief Clock divider for core/system and bus/flash clocks (OUTDIV1).
* @note The allowed range is 1...16.
* @note The default value is calculated for a 48 MHz system clock
* from a 96 MHz PLL output.
* @brief MCU PLL clock frequency.
*/
#if !defined(KINETIS_MCG_FLL_OUTDIV1) || defined(__DOXYGEN__)
#define KINETIS_MCG_FLL_OUTDIV1 2
#if !defined(KINETIS_PLLCLK_FREQUENCY) || defined(__DOXYGEN__)
#define KINETIS_PLLCLK_FREQUENCY 96000000UL
#endif
/**
* @brief Additional clock divider bus/flash clocks (OUTDIV4).
* @note The allowed range is 1...8.
* @note This divider is on top of the OUTDIV1 divider.
* @note The default value is calculated for 24 MHz bus/flash clocks
* from a 96 MHz PLL output and 48 MHz core/system clock.
* @brief Clock divider for core/system clocks (OUTDIV1).
* @note The allowed range is 1..16
* @note The default value is calculated for a 48 MHz system clock
* from a 96 MHz PLL output.
*/
#if !defined(KINETIS_MCG_FLL_OUTDIV4) || defined(__DOXYGEN__)
#define KINETIS_MCG_FLL_OUTDIV4 2
#if !defined(KINETIS_CLKDIV1_OUTDIV1) || defined(__DOXYGEN__)
#if defined(KINETIS_SYSCLK_FREQUENCY) && KINETIS_SYSCLK_FREQUENCY > 0
#define KINETIS_CLKDIV1_OUTDIV1 (KINETIS_PLLCLK_FREQUENCY/KINETIS_SYSCLK_FREQUENCY)
#else
#define KINETIS_CLKDIV1_OUTDIV1 2
#endif
#endif
/**
* @brief Clock divider for bus clock (OUTDIV2).
* @note The allowed range is 1..16
* @note The default value is calculated for a 48 MHz bus clock
* from a 96 MHz PLL output.
*/
#if !defined(KINETIS_CLKDIV1_OUTDIV2) || defined(__DOXYGEN__)
#if defined(KINETIS_BUSCLK_FREQUENCY) && KINETIS_BUSCLK_FREQUENCY > 0
#define KINETIS_CLKDIV1_OUTDIV2 (KINETIS_PLLCLK_FREQUENCY/KINETIS_BUSCLK_FREQUENCY)
#elif defined(KINETIS_SYSCLK_FREQUENCY) && KINETIS_SYSCLK_FREQUENCY > 0
#define KINETIS_CLKDIV1_OUTDIV2 KINETIS_CLKDIV1_OUTDIV1
#else
#define KINETIS_CLKDIV1_OUTDIV2 2
#endif
#endif
/**
* @brief Clock divider for flash clock (OUTDIV4).
* @note The allowed range is 1..16
* @note The default value is calculated for a 24 MHz flash clock
* from a 96 MHz PLL output
*/
#if !defined(KINETIS_CLKDIV1_OUTDIV4) || defined(__DOXYGEN__)
#if defined(KINETIS_FLASHCLK_FREQUENCY) && KINETIS_FLASHCLK_FREQUENCY > 0
#define KINETIS_CLKDIV1_OUTDIV4 (KINETIS_PLLCLK_FREQUENCY/KINETIS_FLASHCLK_FREQUENCY)
#elif defined(KINETIS_SYSCLK_FREQUENCY) && KINETIS_SYSCLK_FREQUENCY > 0
#define KINETIS_CLKDIV1_OUTDIV4 (KINETIS_CLKDIV1_OUTDIV1*2)
#else
#define KINETIS_CLKDIV1_OUTDIV4 4
#endif
#endif
/**
@ -140,32 +161,21 @@
* @brief MCU system/core clock frequency.
*/
#if !defined(KINETIS_SYSCLK_FREQUENCY) || defined(__DOXYGEN__)
#define KINETIS_SYSCLK_FREQUENCY 48000000UL
#define KINETIS_SYSCLK_FREQUENCY (KINETIS_PLLCLK_FREQUENCY / KINETIS_CLKDIV1_OUTDIV1)
#endif
/**
* @brief MCU bus/flash clock frequency.
* @brief MCU bus clock frequency.
*/
#if !defined(KINETIS_BUSCLK_FREQUENCY) || defined(__DOXYGEN__)
#define KINETIS_BUSCLK_FREQUENCY (KINETIS_SYSCLK_FREQUENCY / KINETIS_MCG_FLL_OUTDIV4)
#define KINETIS_BUSCLK_FREQUENCY (KINETIS_PLLCLK_FREQUENCY / KINETIS_CLKDIV1_OUTDIV2)
#endif
/**
* @brief UART0 clock frequency.
* @note The default value is based on 96 MHz PLL/2 source.
* If you use a different source, such as the FLL,
* you must set this properly.
* @brief MCU flash clock frequency.
*/
#if !defined(KINETIS_UART0_CLOCK_FREQ) || defined(__DOXYGEN__)
#define KINETIS_UART0_CLOCK_FREQ KINETIS_SYSCLK_FREQUENCY
#endif
/**
* @brief UART0 clock source.
* @note The default value is to use PLL/2 or FLL source.
*/
#if !defined(KINETIS_UART0_CLOCK_SRC) || defined(__DOXYGEN__)
#define KINETIS_UART0_CLOCK_SRC 1
#if !defined(KINETIS_FLASHCLK_FREQUENCY) || defined(__DOXYGEN__)
#define KINETIS_FLASHCLK_FREQUENCY (KINETIS_PLLCLK_FREQUENCY / KINETIS_CLKDIV1_OUTDIV4)
#endif
/** @} */
@ -175,29 +185,52 @@
/*===========================================================================*/
#if !defined(KINETIS_SYSCLK_FREQUENCY)
#error KINETIS_SYSCLK_FREQUENCY must be defined
#error KINETIS_SYSCLK_FREQUENCY must be defined
#endif
#if KINETIS_SYSCLK_FREQUENCY <= 0 || KINETIS_SYSCLK_FREQUENCY > KINETIS_SYSCLK_MAX
#error KINETIS_SYSCLK_FREQUENCY out of range
#error KINETIS_SYSCLK_FREQUENCY out of range
#endif
#if !defined(KINETIS_BUSCLK_FREQUENCY)
#error KINETIS_BUSCLK_FREQUENCY must be defined
#error KINETIS_BUSCLK_FREQUENCY must be defined
#endif
#if KINETIS_BUSCLK_FREQUENCY <= 0 || KINETIS_BUSCLK_FREQUENCY > KINETIS_BUSCLK_MAX
#error KINETIS_BUSCLK_FREQUENCY out of range
#error KINETIS_BUSCLK_FREQUENCY out of range
#endif
#if !(defined(KINETIS_MCG_FLL_OUTDIV1) && \
KINETIS_MCG_FLL_OUTDIV1 >= 1 && KINETIS_MCG_FLL_OUTDIV1 <= 16)
#error KINETIS_MCG_FLL_OUTDIV1 must be 1 through 16
#if KINETIS_BUSCLK_FREQUENCY > KINETIS_SYSCLK_FREQUENCY
#error KINETIS_BUSCLK_FREQUENCY must be an integer divide of\
KINETIS_SYSCLK_FREQUENCY
#endif
#if !(defined(KINETIS_MCG_FLL_OUTDIV4) && \
KINETIS_MCG_FLL_OUTDIV4 >= 1 && KINETIS_MCG_FLL_OUTDIV4 <= 8)
#error KINETIS_MCG_FLL_OUTDIV4 must be 1 through 8
#if !defined(KINETIS_FLASHCLK_FREQUENCY)
#error KINETIS_FLASHCLK_FREQUENCY must be defined
#endif
#if KINETIS_FLASHCLK_FREQUENCY <= 0 || KINETIS_FLASHCLK_FREQUENCY > KINETIS_FLASHCLK_MAX
#error KINETIS_FLASHCLK_FREQUENCY out of range
#endif
#if KINETIS_FLASHCLK_FREQUENCY > KINETIS_SYSCLK_FREQUENCY
#error KINETIS_FLASHCLK_FREQUENCY must be an integer divide of\
KINETIS_SYSCLK_FREQUENCY
#endif
#if !(defined(KINETIS_CLKDIV1_OUTDIV1) && \
KINETIS_CLKDIV1_OUTDIV1 >= 1 && KINETIS_CLKDIV1_OUTDIV1 <= 16)
#error KINETIS_CLKDIV1_OUTDIV1 must be 1 through 16
#endif
#if !(defined(KINETIS_CLKDIV1_OUTDIV2) && \
KINETIS_CLKDIV1_OUTDIV2 >= 1 && KINETIS_CLKDIV1_OUTDIV2 <= 16)
#error KINETIS_CLKDIV1_OUTDIV2 must be 1 through 16
#endif
#if !(defined(KINETIS_CLKDIV1_OUTDIV4) && \
KINETIS_CLKDIV1_OUTDIV4 >= 1 && KINETIS_CLKDIV1_OUTDIV4 <= 16)
#error KINETIS_CLKDIV1_OUTDIV4 must be 1 through 16
#endif
#if !(KINETIS_MCG_FLL_DMX32 == 0 || KINETIS_MCG_FLL_DMX32 == 1)
@ -259,7 +292,7 @@ typedef uint32_t halrtcnt_t;
extern "C" {
#endif
void hal_lld_init(void);
void mk20d50_clock_init(void);
void k20x_clock_init(void);
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,6 @@
/*
ChibiOS - Copyright (C) 2014 Derek Mulcahy
(C) 2016 flabbergast <s3+flabbergast@sdfeu.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -15,8 +16,8 @@
*/
/**
* @file KL2x/kinetis_registry.h
* @brief KL2x capabilities registry.
* @file K20x/kinetis_registry.h
* @brief K20x capabilities registry.
*
* @addtogroup HAL
* @{
@ -25,31 +26,230 @@
#ifndef _KINETIS_REGISTRY_H_
#define _KINETIS_REGISTRY_H_
#if !defined(K20x) || defined(__DOXYGEN__)
#define K20x
#endif
/*===========================================================================*/
/* Platform capabilities. */
/*===========================================================================*/
/**
* @name KL2x capabilities
* @name K20x capabilities
* @{
*/
/* EXT attributes.*/
/*===========================================================================*/
/* K20x5 */
/*===========================================================================*/
#if defined(K20x5) || defined(__DOXYGEN__)
/**
* @brief Maximum system and core clock (f_SYS) frequency.
*/
#define KINETIS_SYSCLK_MAX 50000000L
/**
* @brief Maximum bus clock (f_BUS) frequency.
*/
#define KINETIS_BUSCLK_MAX 50000000L
/**
* @brief Maximum flash clock (f_FLASH) frequency.
*/
#define KINETIS_FLASHCLK_MAX 25000000L
/* ADC attributes.*/
#define KINETIS_HAS_ADC0 TRUE
#define KINETIS_ADC0_IRQ_VECTOR Vector98
#define KINETIS_HAS_ADC1 FALSE
/* DAC attributes.*/
#define KINETIS_HAS_DAC0 FALSE
/* DMA attributes.*/
#define KINETIS_DMA0_IRQ_VECTOR Vector40
#define KINETIS_DMA1_IRQ_VECTOR Vector44
#define KINETIS_DMA2_IRQ_VECTOR Vector48
#define KINETIS_DMA3_IRQ_VECTOR Vector4C
#define KINETIS_HAS_DMA_ERROR_IRQ TRUE
#define KINETIS_DMA_ERROR_IRQ_VECTOR Vector50
/* EXT attributes.*/
#define KINETIS_PORTA_IRQ_VECTOR VectorE0
#define KINETIS_PORTB_IRQ_VECTOR VectorE4
#define KINETIS_PORTC_IRQ_VECTOR VectorE8
#define KINETIS_PORTD_IRQ_VECTOR VectorEC
#define KINETIS_PORTE_IRQ_VECTOR VectorF0
#define KINETIS_EXT_HAS_COMMON_CD_IRQ FALSE
#define KINETIS_EXT_HAS_COMMON_BCDE_IRQ FALSE
#define KINETIS_GPIO_HAS_OPENDRAIN TRUE
/* I2C attributes.*/
#define KINETIS_HAS_I2C0 TRUE
#define KINETIS_I2C0_IRQ_VECTOR Vector6C
#define KINETIS_HAS_I2C1 FALSE
/* Serial attributes.*/
#define KINETIS_HAS_SERIAL0 TRUE
#define KINETIS_SERIAL0_IRQ_VECTOR Vector80
#define KINETIS_HAS_SERIAL1 TRUE
#define KINETIS_SERIAL1_IRQ_VECTOR Vector88
#define KINETIS_HAS_SERIAL2 TRUE
#define KINETIS_SERIAL2_IRQ_VECTOR Vector90
#define KINETIS_HAS_SERIAL_ERROR_IRQ TRUE
#define KINETIS_SERIAL0_ERROR_IRQ_VECTOR Vector84
#define KINETIS_SERIAL1_ERROR_IRQ_VECTOR Vector8C
#define KINETIS_SERIAL2_ERROR_IRQ_VECTOR Vector94
#define KINETIS_SERIAL0_IS_LPUART FALSE
#define KINETIS_SERIAL0_IS_UARTLP FALSE
#define KINETIS_SERIAL1_IS_LPUART FALSE
/* SPI attributes.*/
#define KINETIS_HAS_SPI0 TRUE
#define KINETIS_SPI0_IRQ_VECTOR Vector70
#define KINETIS_HAS_SPI1 FALSE
/* FlexTimer attributes.*/
#define KINETIS_FTM0_CHANNELS 8
#define KINETIS_FTM1_CHANNELS 2
#define KINETIS_FTM0_IRQ_VECTOR VectorA4
#define KINETIS_FTM1_IRQ_VECTOR VectorA8
#define KINETIS_HAS_FTM2 FALSE
/* GPT attributes.*/
#define KINETIS_HAS_PIT0 TRUE
#define KINETIS_PIT0_IRQ_VECTOR VectorB8
#define KINETIS_HAS_PIT1 TRUE
#define KINETIS_PIT1_IRQ_VECTOR VectorBC
#define KINETIS_HAS_PIT2 TRUE
#define KINETIS_PIT2_IRQ_VECTOR VectorC0
#define KINETIS_HAS_PIT3 TRUE
#define KINETIS_PIT3_IRQ_VECTOR VectorC4
#define KINETIS_HAS_PIT_COMMON_IRQ FALSE
/* USB attributes.*/
#define KINETIS_HAS_USB TRUE
#define KINETIS_USB_IRQ_VECTOR VectorCC
#define KINETIS_USB0_IS_USBOTG TRUE
#define KINETIS_HAS_USB_CLOCK_RECOVERY FALSE
/* LPTMR attributes.*/
#define KINETIS_LPTMR0_IRQ_VECTOR VectorDC
/*===========================================================================*/
/* K20x7 */
/*===========================================================================*/
#elif defined(K20x7)
/**
* @brief Maximum system and core clock (f_SYS) frequency.
*/
#define KINETIS_SYSCLK_MAX 72000000L
/**
* @brief Maximum bus clock (f_BUS) frequency.
*/
#define KINETIS_BUSCLK_MAX 50000000L
/**
* @brief Maximum flash clock (f_FLASH) frequency.
*/
#define KINETIS_FLASHCLK_MAX 25000000L
/**
* @name K20x7 attributes
* @{
*/
/* ADC attributes.*/
#define KINETIS_HAS_ADC0 TRUE
#define KINETIS_ADC0_IRQ_VECTOR Vector98
#define KINETIS_ADC0_IRQ_VECTOR Vector124
#define KINETIS_HAS_ADC1 TRUE
#define KINETIS_ADC1_IRQ_VECTOR Vector128
/* DAC attributes.*/
#define KINETIS_HAS_DAC0 TRUE
#define KINTEIS_DAC0_IRQ_VECTOR Vector184
/* DMA attributes.*/
#define KINETIS_DMA0_IRQ_VECTOR Vector40
#define KINETIS_DMA1_IRQ_VECTOR Vector44
#define KINETIS_DMA2_IRQ_VECTOR Vector48
#define KINETIS_DMA3_IRQ_VECTOR Vector4C
#define KINETIS_HAS_DMA_ERROR_IRQ TRUE
#define KINETIS_DMA_ERROR_IRQ_VECTOR Vector50
/* EXT attributes.*/
#define KINETIS_PORTA_IRQ_VECTOR Vector19C
#define KINETIS_PORTB_IRQ_VECTOR Vector1A0
#define KINETIS_PORTC_IRQ_VECTOR Vector1A4
#define KINETIS_PORTD_IRQ_VECTOR Vector1A8
#define KINETIS_PORTE_IRQ_VECTOR Vector1AC
#define KINETIS_EXT_HAS_COMMON_CD_IRQ FALSE
#define KINETIS_EXT_HAS_COMMON_BCDE_IRQ FALSE
#define KINETIS_GPIO_HAS_OPENDRAIN TRUE
/* I2C attributes.*/
#define KINETIS_I2C0_IRQ_VECTOR Vector6C
#define KINETIS_HAS_I2C0 TRUE
#define KINETIS_I2C0_IRQ_VECTOR VectorA0
#define KINETIS_HAS_I2C1 TRUE
#define KINETIS_I2C1_IRQ_VECTOR VectorA4
/* USB attributes */
#define KINETIS_USB_IRQ_VECTOR VectorCC
/* Serial attributes.*/
#define KINETIS_HAS_SERIAL0 TRUE
#define KINETIS_SERIAL0_IRQ_VECTOR VectorF4
#define KINETIS_HAS_SERIAL1 TRUE
#define KINETIS_SERIAL1_IRQ_VECTOR VectorFC
#define KINETIS_HAS_SERIAL2 TRUE
#define KINETIS_SERIAL2_IRQ_VECTOR Vector104
#define KINETIS_HAS_SERIAL_ERROR_IRQ TRUE
#define KINETIS_SERIAL0_ERROR_IRQ_VECTOR VectorF8
#define KINETIS_SERIAL1_ERROR_IRQ_VECTOR Vector100
#define KINETIS_SERIAL2_ERROR_IRQ_VECTOR Vector108
#define KINETIS_SERIAL0_IS_LPUART FALSE
#define KINETIS_SERIAL0_IS_UARTLP FALSE
#define KINETIS_SERIAL1_IS_LPUART FALSE
/* SPI attributes.*/
#define KINETIS_HAS_SPI0 TRUE
#define KINETIS_SPI0_IRQ_VECTOR VectorA8
#define KINETIS_HAS_SPI1 TRUE
#define KINETIS_SPI1_IRQ_VECTOR VectorAC
/* FlexTimer attributes.*/
#define KINETIS_FTM0_CHANNELS 8
#define KINETIS_FTM1_CHANNELS 2
#define KINETIS_FTM2_CHANNELS 2
#define KINETIS_FTM0_IRQ_VECTOR Vector138
#define KINETIS_FTM1_IRQ_VECTOR Vector13C
#define KINETIS_HAS_FTM2 TRUE
#define KINETIS_FTM2_IRQ_VECTOR Vector140
/* GPT attributes.*/
#define KINETIS_HAS_PIT0 TRUE
#define KINETIS_PIT0_IRQ_VECTOR Vector150
#define KINETIS_HAS_PIT1 TRUE
#define KINETIS_PIT1_IRQ_VECTOR Vector154
#define KINETIS_HAS_PIT2 TRUE
#define KINETIS_PIT2_IRQ_VECTOR Vector158
#define KINETIS_HAS_PIT3 TRUE
#define KINETIS_PIT3_IRQ_VECTOR Vector15C
#define KINETIS_HAS_PIT FALSE
#define KINETIS_PIT_CHANNELS 4
#define KINETIS_HAS_PIT_COMMON_IRQ FALSE
/* USB attributes.*/
#define KINETIS_HAS_USB TRUE
#define KINETIS_USB_IRQ_VECTOR Vector164
#define KINETIS_USB0_IS_USBOTG TRUE
#define KINETIS_HAS_USB_CLOCK_RECOVERY FALSE
/* LPTMR attributes.*/
#define KINETIS_LPTMR0_IRQ_VECTOR Vector194
#endif /* K20xY */
/** @} */

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,16 @@
# List of all platform files.
PLATFORMSRC = ${CHIBIOS}/os/hal/ports/common/ARMCMx/nvic.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/K20x/hal_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/K20x/pal_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/K20x/serial_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/pal_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/serial_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/K20x/spi_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/i2c_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/ext_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/adc_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/K20x/gpt_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/K20x/st_lld.c
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/gpt_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/K20x/pwm_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/st_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/usb_lld.c
# Required include directories
PLATFORMINC = ${CHIBIOS}/os/hal/ports/common/ARMCMx \

View File

@ -0,0 +1,390 @@
/*
ChibiOS/HAL - Copyright (C) 2014 Adam J. Porter
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file K20x/pwm_lld.c
* @brief KINETIS PWM subsystem low level driver source.
*
* @addtogroup PWM
* @{
*/
#include "hal.h"
#if HAL_USE_PWM || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief PWMD1 driver identifier.
* @note The driver PWMD1 allocates the timer FTM0 when enabled.
*/
#if KINETIS_PWM_USE_FTM0 || defined(__DOXYGEN__)
PWMDriver PWMD1;
#endif
/**
* @brief PWMD2 driver identifier.
* @note The driver PWMD2 allocates the timer FTM1 when enabled.
*/
#if KINETIS_PWM_USE_FTM1 || defined(__DOXYGEN__)
PWMDriver PWMD2;
#endif
/**
* @brief PWMD3 driver identifier.
* @note The driver PWMD3 allocates the timer FTM2 when enabled.
*/
#if KINETIS_PWM_USE_FTM2 || defined(__DOXYGEN__)
PWMDriver PWMD3;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
static void pwm_lld_serve_interrupt(PWMDriver *pwmp) {
uint32_t sr;
sr = pwmp->ftm->SC;
pwmp->ftm->SC = sr&(~FTM_SC_TOF);
if (((sr & FTM_SC_TOF) != 0) && /* Timer Overflow */
((sr & FTM_SC_TOIE) != 0) &&
(pwmp->config->callback != NULL)) {
pwmp->config->callback(pwmp);
}
uint8_t n=0;
for(n=0;n<pwmp->channels;n++) {
sr = pwmp->ftm->CHANNEL[n].CnSC;
pwmp->ftm->CHANNEL[n].CnSC = sr&(~FTM_CnSC_CHF);
if (((sr & FTM_CnSC_CHF) != 0) &&
((sr & FTM_CnSC_CHIE) != 0) &&
(pwmp->config->channels[n].callback != NULL)) {
pwmp->config->channels[n].callback(pwmp);
}
}
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if KINETIS_PWM_USE_FTM0
/**
* @brief FTM0 interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(KINETIS_FTM0_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
pwm_lld_serve_interrupt(&PWMD1);
OSAL_IRQ_EPILOGUE();
}
#endif /* KINETIS_PWM_USE_FTM0 */
#if KINETIS_PWM_USE_FTM1
/**
* @brief FTM1 interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(KINETIS_FTM1_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
pwm_lld_serve_interrupt(&PWMD2);
OSAL_IRQ_EPILOGUE();
}
#endif /* KINETIS_PWM_USE_FTM1 */
#if KINETIS_PWM_USE_FTM2
/**
* @brief FTM2 interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(KINETIS_FTM2_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
pwm_lld_serve_interrupt(&PWMD3);
OSAL_IRQ_EPILOGUE();
}
#endif /* KINETIS_PWM_USE_FTM2 */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level PWM driver initialization.
*
* @notapi
*/
void pwm_lld_init(void) {
#if KINETIS_PWM_USE_FTM0
pwmObjectInit(&PWMD1);
PWMD1.channels = KINETIS_FTM0_CHANNELS;
PWMD1.ftm = FTM0;
#endif
#if KINETIS_PWM_USE_FTM1
pwmObjectInit(&PWMD2);
PWMD2.channels = KINETIS_FTM1_CHANNELS;
PWMD2.ftm = FTM1;
#endif
#if KINETIS_PWM_USE_FTM2
pwmObjectInit(&PWMD3);
PWMD3.channels = KINETIS_FTM2_CHANNELS;
PWMD3.ftm = FTM2;
#endif
}
/**
* @brief Configures and activates the PWM peripheral.
* @note Starting a driver that is already in the @p PWM_READY state
* disables all the active channels.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*
* @notapi
*/
void pwm_lld_start(PWMDriver *pwmp) {
uint16_t psc;
uint8_t i=0;
if (pwmp->state == PWM_STOP) {
/* Clock activation and timer reset.*/
#if KINETIS_PWM_USE_FTM0
if (&PWMD1 == pwmp) {
SIM->SCGC6 |= SIM_SCGC6_FTM0;
nvicEnableVector(FTM0_IRQn, KINETIS_PWM_FTM0_PRIORITY);
}
#endif
#if KINETIS_PWM_USE_FTM1
if (&PWMD2 == pwmp) {
SIM->SCGC6 |= SIM_SCGC6_FTM1;
nvicEnableVector(FTM1_IRQn, KINETIS_PWM_FTM1_PRIORITY);
}
#endif
#if KINETIS_PWM_USE_FTM2
if (&PWMD3 == pwmp) {
SIM->SCGC3 |= SIM_SCGC3_FTM2;
nvicEnableVector(FTM2_IRQn, KINETIS_PWM_FTM2_PRIORITY);
}
#endif
}
pwmp->ftm->MODE = FTM_MODE_FTMEN_MASK|FTM_MODE_PWMSYNC_MASK;
pwmp->ftm->SYNC = FTM_SYNC_CNTMIN_MASK|FTM_SYNC_CNTMAX_MASK
|FTM_SYNC_SWSYNC_MASK;
pwmp->ftm->COMBINE = FTM_COMBINE_SYNCEN3_MASK | FTM_COMBINE_SYNCEN2_MASK
| FTM_COMBINE_SYNCEN1_MASK | FTM_COMBINE_SYNCEN0_MASK;
pwmp->ftm->SYNCONF = FTM_SYNCONF_SYNCMODE_MASK;
pwmp->ftm->CNTIN = 0x0000;
//~ pwmp->ftm->SC = 0; /* Disable FTM counter.*/
pwmp->ftm->CNT = 0x0000; /* Clear count register.*/
/* Prescaler value calculation.*/
psc = (KINETIS_SYSCLK_FREQUENCY / pwmp->config->frequency);
//~ /* Prescaler must be power of two between 1 and 128.*/
osalDbgAssert(psc <= 128 && !(psc & (psc - 1)), "invalid frequency");
//~ /* Prescaler register value determination.
//~ Prescaler register value conveniently corresponds to bit position,
//~ i.e., register value for prescaler CLK/64 is 6 ((1 << 6) == 64).*/
for (i = 0; i < 8; i++) {
if (psc == (unsigned)(1 << i)) {
break;
}
}
/* Set prescaler and clock mode.
This also sets the following:
CPWMS up-counting mode
Timer overflow interrupt disabled
DMA disabled.*/
pwmp->ftm->SC = FTM_SC_CLKS(1) | FTM_SC_PS(i);
/* Configure period */
pwmp->ftm->MOD = pwmp->period-1;
pwmp->ftm->PWMLOAD = FTM_PWMLOAD_LDOK_MASK;
}
/**
* @brief Deactivates the PWM peripheral.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*
* @notapi
*/
void pwm_lld_stop(PWMDriver *pwmp) {
/* If in ready state then disables the PWM clock.*/
if (pwmp->state == PWM_READY) {
#if KINETIS_PWM_USE_FTM0
if (&PWMD1 == pwmp) {
SIM->SCGC6 &= ~SIM_SCGC6_FTM0;
nvicDisableVector(FTM0_IRQn);
}
#endif
#if KINETIS_PWM_USE_FTM1
if (&PWMD2 == pwmp) {
SIM->SCGC6 &= ~SIM_SCGC6_FTM1;
nvicDisableVector(FTM1_IRQn);
}
#endif
#if KINETIS_PWM_USE_FTM2
if (&PWMD3 == pwmp) {
SIM->SCGC3 &= ~SIM_SCGC3_FTM2;
nvicDisableVector(FTM2_IRQn);
}
#endif
/* Disable FTM counter.*/
pwmp->ftm->SC = 0;
pwmp->ftm->MOD = 0;
}
}
/**
* @brief Enables a PWM channel.
* @pre The PWM unit must have been activated using @p pwmStart().
* @post The channel is active using the specified configuration.
* @note The function has effect at the next cycle start.
* @note Channel notification is not enabled.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...channels-1)
* @param[in] width PWM pulse width as clock pulses number
*
* @notapi
*/
void pwm_lld_enable_channel(PWMDriver *pwmp,
pwmchannel_t channel,
pwmcnt_t width) {
uint32_t mode = FTM_CnSC_MSB; /* Edge-aligned PWM mode.*/
switch (pwmp->config->channels[channel].mode & PWM_OUTPUT_MASK) {
case PWM_OUTPUT_ACTIVE_HIGH:
mode |= FTM_CnSC_ELSB;
break;
case PWM_OUTPUT_ACTIVE_LOW:
mode |= FTM_CnSC_ELSA;
break;
}
if (pwmp->ftm->CHANNEL[channel].CnSC & FTM_CnSC_CHIE)
mode |= FTM_CnSC_CHIE;
pwmp->ftm->CHANNEL[channel].CnSC = mode;
pwmp->ftm->CHANNEL[channel].CnV = width;
pwmp->ftm->PWMLOAD = FTM_PWMLOAD_LDOK_MASK;
}
/**
* @brief Disables a PWM channel and its notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @post The channel is disabled and its output line returned to the
* idle state.
* @note The function has effect at the next cycle start.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...channels-1)
*
* @notapi
*/
void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) {
pwmp->ftm->CHANNEL[channel].CnSC = 0;
pwmp->ftm->CHANNEL[channel].CnV = 0;
}
/**
* @brief Enables the periodic activation edge notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @note If the notification is already enabled then the call has no effect.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*
* @notapi
*/
void pwm_lld_enable_periodic_notification(PWMDriver *pwmp) {
pwmp->ftm->SC |= FTM_SC_TOIE;
}
/**
* @brief Disables the periodic activation edge notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @note If the notification is already disabled then the call has no effect.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*
* @notapi
*/
void pwm_lld_disable_periodic_notification(PWMDriver *pwmp) {
pwmp->ftm->SC &= ~FTM_SC_TOIE;
}
/**
* @brief Enables a channel de-activation edge notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @pre The channel must have been activated using @p pwmEnableChannel().
* @note If the notification is already enabled then the call has no effect.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...channels-1)
*
* @notapi
*/
void pwm_lld_enable_channel_notification(PWMDriver *pwmp,
pwmchannel_t channel) {
pwmp->ftm->CHANNEL[channel].CnSC |= FTM_CnSC_CHIE;
}
/**
* @brief Disables a channel de-activation edge notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @pre The channel must have been activated using @p pwmEnableChannel().
* @note If the notification is already disabled then the call has no effect.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...channels-1)
*
* @notapi
*/
void pwm_lld_disable_channel_notification(PWMDriver *pwmp,
pwmchannel_t channel) {
pwmp->ftm->CHANNEL[channel].CnSC &= ~FTM_CnSC_CHIE;
}
#endif /* HAL_USE_PWM */
/** @} */

View File

@ -0,0 +1,270 @@
/*
ChibiOS/HAL - Copyright (C) 2014 Adam J. Porter
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file K20x7/pwm_lld.h
* @brief KINETIS PWM subsystem low level driver header.
*
* @addtogroup PWM
* @{
*/
#ifndef _PWM_LLD_H_
#define _PWM_LLD_H_
#if HAL_USE_PWM || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief Number of PWM channels per PWM driver.
*/
#define PWM_CHANNELS 8
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
#if !defined(KINETIS_PWM_USE_FTM0)
#define KINETIS_PWM_USE_FTM0 FALSE
#endif
#if !defined(KINETIS_PWM_USE_FTM1)
#define KINETIS_PWM_USE_FTM1 FALSE
#endif
#if !defined(KINETIS_PWM_USE_FTM2)
#define KINETIS_PWM_USE_FTM2 FALSE
#endif
/**
* @brief FTM0 interrupt priority level setting.
*/
#if !defined(KINETIS_PWM_FTM0_PRIORITY) || defined(__DOXYGEN__)
#define KINETIS_PWM_FTM0_PRIORITY 12
#endif
/**
* @brief FTM1 interrupt priority level setting.
*/
#if !defined(KINETIS_PWM_FTM1_PRIORITY) || defined(__DOXYGEN__)
#define KINETIS_PWM_FTM1_PRIORITY 12
#endif
/**
* @brief FTM2 interrupt priority level setting.
*/
#if !defined(KINETIS_PWM_FTM2_PRIORITY) || defined(__DOXYGEN__)
#define KINETIS_PWM_FTM2_PRIORITY 12
#endif
/** @} */
/**
* @name Configuration options
* @{
*/
/**
* @brief If advanced timer features switch.
* @details If set to @p TRUE the advanced features for TIM1 and TIM8 are
* enabled.
* @note The default is @p TRUE.
*/
#if !defined(KINETIS_PWM_USE_ADVANCED) || defined(__DOXYGEN__)
#define KINETIS_PWM_USE_ADVANCED FALSE
#endif
/** @} */
/*===========================================================================*/
/* Configuration checks. */
/*===========================================================================*/
#if !KINETIS_PWM_USE_FTM0 && !KINETIS_PWM_USE_FTM1 && !KINETIS_PWM_USE_FTM2
#error "PWM driver activated but no FTM peripheral assigned"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a PWM mode.
*/
typedef uint32_t pwmmode_t;
/**
* @brief Type of a PWM channel.
*/
typedef uint8_t pwmchannel_t;
/**
* @brief Type of a channels mask.
*/
typedef uint32_t pwmchnmsk_t;
/**
* @brief Type of a PWM counter.
*/
typedef uint16_t pwmcnt_t;
/**
* @brief Type of a PWM driver channel configuration structure.
*/
typedef struct {
/**
* @brief Channel active logic level.
*/
pwmmode_t mode;
/**
* @brief Channel callback pointer.
* @note This callback is invoked on the channel compare event. If set to
* @p NULL then the callback is disabled.
*/
pwmcallback_t callback;
/* End of the mandatory fields.*/
} PWMChannelConfig;
/**
* @brief Type of a PWM driver configuration structure.
*/
typedef struct {
/**
* @brief Timer clock in Hz.
* @note The low level can use assertions in order to catch invalid
* frequency specifications.
*/
uint32_t frequency;
/**
* @brief PWM period in ticks.
* @note The low level can use assertions in order to catch invalid
* period specifications.
*/
pwmcnt_t period;
/**
* @brief Periodic callback pointer.
* @note This callback is invoked on PWM counter reset. If set to
* @p NULL then the callback is disabled.
*/
pwmcallback_t callback;
/**
* @brief Channels configurations.
*/
PWMChannelConfig channels[PWM_CHANNELS];
/* End of the mandatory fields.*/
} PWMConfig;
/**
* @brief Structure representing a PWM driver.
*/
struct PWMDriver {
/**
* @brief Driver state.
*/
pwmstate_t state;
/**
* @brief Current driver configuration data.
*/
const PWMConfig *config;
/**
* @brief Current PWM period in ticks.
*/
pwmcnt_t period;
/**
* @brief Mask of the enabled channels.
*/
pwmchnmsk_t enabled;
/**
* @brief Number of channels in this instance.
*/
pwmchannel_t channels;
#if defined(PWM_DRIVER_EXT_FIELDS)
PWM_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Pointer to the FTM registers block.
*/
FTM_TypeDef *ftm;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Changes the period the PWM peripheral.
* @details This function changes the period of a PWM unit that has already
* been activated using @p pwmStart().
* @pre The PWM unit must have been activated using @p pwmStart().
* @post The PWM unit period is changed to the new value.
* @note The function has effect at the next cycle start.
* @note If a period is specified that is shorter than the pulse width
* programmed in one of the channels then the behavior is not
* guaranteed.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] period new cycle time in ticks
*
* @notapi
*/
#define pwm_lld_change_period(pwmp, period) \
do { \
(pwmp)->ftm->MOD = ((period) - 1); \
pwmp->ftm->PWMLOAD = FTM_PWMLOAD_LDOK_MASK;\
} while(0)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if KINETIS_PWM_USE_FTM0 || defined(__DOXYGEN__)
extern PWMDriver PWMD1;
#endif
#if KINETIS_PWM_USE_FTM1 || defined(__DOXYGEN__)
extern PWMDriver PWMD2;
#endif
#if KINETIS_PWM_USE_FTM2 || defined(__DOXYGEN__)
extern PWMDriver PWMD3;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void pwm_lld_init(void);
void pwm_lld_start(PWMDriver *pwmp);
void pwm_lld_stop(PWMDriver *pwmp);
void pwm_lld_enable_channel(PWMDriver *pwmp,
pwmchannel_t channel,
pwmcnt_t width);
void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel);
void pwm_lld_enable_periodic_notification(PWMDriver *pwmp);
void pwm_lld_disable_periodic_notification(PWMDriver *pwmp);
void pwm_lld_enable_channel_notification(PWMDriver *pwmp,
pwmchannel_t channel);
void pwm_lld_disable_channel_notification(PWMDriver *pwmp,
pwmchannel_t channel);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_PWM */
#endif /* _PWM_LLD_H_ */
/** @} */

View File

@ -1,327 +0,0 @@
/*
ChibiOS - Copyright (C) 2014-2015 Fabio Utzig
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file K20x/serial_lld.c
* @brief Kinetis K20x Serial Driver subsystem low level driver source.
*
* @addtogroup SERIAL
* @{
*/
#include "osal.h"
#include "hal.h"
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
#include "mk20d5.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief SD1 driver identifier.
*/
#if KINETIS_SERIAL_USE_UART0 || defined(__DOXYGEN__)
SerialDriver SD1;
#endif
#if KINETIS_SERIAL_USE_UART1 || defined(__DOXYGEN__)
SerialDriver SD2;
#endif
#if KINETIS_SERIAL_USE_UART2 || defined(__DOXYGEN__)
SerialDriver SD3;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/**
* @brief Driver default configuration.
*/
static const SerialConfig default_config = {
38400
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Common IRQ handler.
* @note Tries hard to clear all the pending interrupt sources, we don't
* want to go through the whole ISR and have another interrupt soon
* after.
*
* @param[in] u pointer to an UART I/O block
* @param[in] sdp communication channel associated to the UART
*/
static void serve_interrupt(SerialDriver *sdp) {
UART_TypeDef *u = sdp->uart;
uint8_t s1 = u->S1;
if (s1 & UARTx_S1_RDRF) {
osalSysLockFromISR();
if (iqIsEmptyI(&sdp->iqueue))
chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE);
if (iqPutI(&sdp->iqueue, u->D) < Q_OK)
chnAddFlagsI(sdp, SD_OVERRUN_ERROR);
osalSysUnlockFromISR();
}
if (s1 & UARTx_S1_TDRE) {
msg_t b;
osalSysLockFromISR();
b = oqGetI(&sdp->oqueue);
osalSysUnlockFromISR();
if (b < Q_OK) {
osalSysLockFromISR();
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
osalSysUnlockFromISR();
u->C2 &= ~UARTx_C2_TIE;
} else {
u->D = b;
}
}
}
/**
* @brief Attempts a TX preload
*/
static void preload(SerialDriver *sdp) {
UART_TypeDef *u = sdp->uart;
if (u->S1 & UARTx_S1_TDRE) {
msg_t b = oqGetI(&sdp->oqueue);
if (b < Q_OK) {
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
return;
}
u->D = b;
u->C2 |= UARTx_C2_TIE;
}
}
/**
* @brief Driver output notification.
*/
#if KINETIS_SERIAL_USE_UART0 || defined(__DOXYGEN__)
static void notify1(io_queue_t *qp)
{
(void)qp;
preload(&SD1);
}
#endif
#if KINETIS_SERIAL_USE_UART1 || defined(__DOXYGEN__)
static void notify2(io_queue_t *qp)
{
(void)qp;
preload(&SD2);
}
#endif
#if KINETIS_SERIAL_USE_UART2 || defined(__DOXYGEN__)
static void notify3(io_queue_t *qp)
{
(void)qp;
preload(&SD3);
}
#endif
/**
* @brief Common UART configuration.
*
*/
static void configure_uart(UART_TypeDef *uart, const SerialConfig *config)
{
uint32_t divisor = (KINETIS_SYSCLK_FREQUENCY * 2 + 1) / config->sc_speed;
/* Disable UART while configuring */
uart->C2 &= ~(UARTx_C2_RE | UARTx_C2_TE);
uart->C1 = 0;
uart->BDH = UARTx_BDH_SBR(divisor >> 13) | (uart->BDH & ~UARTx_BDH_SBR_MASK);
uart->BDL = divisor >> 5;
uart->C4 = UARTx_C4_BRFA(divisor) | (uart->C4 & ~UARTx_C4_BRFA_MASK);
uart->C2 |= UARTx_C2_RE | UARTx_C2_RIE | UARTx_C2_TE;
uart->C3 = UARTx_C3_ORIE | UARTx_C3_NEIE | UARTx_C3_FEIE | UARTx_C3_PEIE;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/* TODO:
* UART0_Error is Vector84
* UART1_Error is Vector8C
* UART2_Error is Vector94
*/
#if KINETIS_SERIAL_USE_UART0 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(Vector80) {
OSAL_IRQ_PROLOGUE();
serve_interrupt(&SD1);
OSAL_IRQ_EPILOGUE();
}
#endif
#if KINETIS_SERIAL_USE_UART1 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(Vector88) {
OSAL_IRQ_PROLOGUE();
serve_interrupt(&SD2);
OSAL_IRQ_EPILOGUE();
}
#endif
#if KINETIS_SERIAL_USE_UART2 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(Vector90) {
OSAL_IRQ_PROLOGUE();
serve_interrupt(&SD3);
OSAL_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level serial driver initialization.
*
* @notapi
*/
void sd_lld_init(void) {
#if KINETIS_SERIAL_USE_UART0
/* Driver initialization.*/
sdObjectInit(&SD1, NULL, notify1);
SD1.uart = UART0;
#endif
#if KINETIS_SERIAL_USE_UART1
/* Driver initialization.*/
sdObjectInit(&SD2, NULL, notify2);
SD2.uart = UART1;
#endif
#if KINETIS_SERIAL_USE_UART2
/* Driver initialization.*/
sdObjectInit(&SD3, NULL, notify3);
SD3.uart = UART2;
#endif
}
/**
* @brief Low level serial driver configuration and (re)start.
*
* @param[in] sdp pointer to a @p SerialDriver object
* @param[in] config the architecture-dependent serial driver configuration.
* If this parameter is set to @p NULL then a default
* configuration is used.
*
* @notapi
*/
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
if (config == NULL)
config = &default_config;
if (sdp->state == SD_STOP) {
/* Enables the peripheral.*/
#if KINETIS_SERIAL_USE_UART0
if (sdp == &SD1) {
SIM->SCGC4 |= SIM_SCGC4_UART0;
configure_uart(sdp->uart, config);
nvicEnableVector(UART0Status_IRQn, KINETIS_SERIAL_UART0_PRIORITY);
}
#endif /* KINETIS_SERIAL_USE_UART0 */
#if KINETIS_SERIAL_USE_UART1
if (sdp == &SD2) {
SIM->SCGC4 |= SIM_SCGC4_UART1;
configure_uart(sdp->uart, config);
nvicEnableVector(UART1Status_IRQn, KINETIS_SERIAL_UART1_PRIORITY);
}
#endif /* KINETIS_SERIAL_USE_UART1 */
#if KINETIS_SERIAL_USE_UART2
if (sdp == &SD3) {
SIM->SCGC4 |= SIM_SCGC4_UART2;
configure_uart(sdp->uart, config);
nvicEnableVector(UART2Status_IRQn, KINETIS_SERIAL_UART2_PRIORITY);
}
#endif /* KINETIS_SERIAL_USE_UART2 */
}
/* Configures the peripheral.*/
}
/**
* @brief Low level serial driver stop.
* @details De-initializes the USART, stops the associated clock, resets the
* interrupt vector.
*
* @param[in] sdp pointer to a @p SerialDriver object
*
* @notapi
*/
void sd_lld_stop(SerialDriver *sdp) {
if (sdp->state == SD_READY) {
/* TODO: Resets the peripheral.*/
#if KINETIS_SERIAL_USE_UART0
if (sdp == &SD1) {
nvicDisableVector(UART0Status_IRQn);
SIM->SCGC4 &= ~SIM_SCGC4_UART0;
}
#endif
#if KINETIS_SERIAL_USE_UART1
if (sdp == &SD2) {
nvicDisableVector(UART1Status_IRQn);
SIM->SCGC4 &= ~SIM_SCGC4_UART1;
}
#endif
#if KINETIS_SERIAL_USE_UART2
if (sdp == &SD3) {
nvicDisableVector(UART2Status_IRQn);
SIM->SCGC4 &= ~SIM_SCGC4_UART2;
}
#endif
}
}
#endif /* HAL_USE_SERIAL */
/** @} */

View File

@ -1,163 +0,0 @@
/*
ChibiOS - Copyright (C) 2014-2015 Fabio Utzig
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file K20x/serial_lld.h
* @brief Kinetis K20x Serial Driver subsystem low level driver header.
*
* @addtogroup SERIAL
* @{
*/
#ifndef _SERIAL_LLD_H_
#define _SERIAL_LLD_H_
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief SD1 driver enable switch.
* @details If set to @p TRUE the support for SD1 is included.
*/
#if !defined(KINETIS_SERIAL_USE_UART0) || defined(__DOXYGEN__)
#define KINETIS_SERIAL_USE_UART0 FALSE
#endif
/**
* @brief SD2 driver enable switch.
* @details If set to @p TRUE the support for SD2 is included.
*/
#if !defined(KINETIS_SERIAL_USE_UART1) || defined(__DOXYGEN__)
#define KINETIS_SERIAL_USE_UART1 FALSE
#endif
/**
* @brief SD3 driver enable switch.
* @details If set to @p TRUE the support for SD3 is included.
*/
#if !defined(KINETIS_SERIAL_USE_UART2) || defined(__DOXYGEN__)
#define KINETIS_SERIAL_USE_UART2 FALSE
#endif
/**
* @brief UART0 interrupt priority level setting.
*/
#if !defined(KINETIS_SERIAL_UART0_PRIORITY) || defined(__DOXYGEN__)
#define KINETIS_SERIAL_UART0_PRIORITY 12
#endif
/**
* @brief UART1 interrupt priority level setting.
*/
#if !defined(KINETIS_SERIAL_UART1_PRIORITY) || defined(__DOXYGEN__)
#define KINETIS_SERIAL_UART1_PRIORITY 12
#endif
/**
* @brief UART2 interrupt priority level setting.
*/
#if !defined(KINETIS_SERIAL_UART2_PRIORITY) || defined(__DOXYGEN__)
#define KINETIS_SERIAL_UART2_PRIORITY 12
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Generic Serial Driver configuration structure.
* @details An instance of this structure must be passed to @p sdStart()
* in order to configure and start a serial driver operations.
* @note Implementations may extend this structure to contain more,
* architecture dependent, fields.
*/
typedef struct {
/**
* @brief Bit rate.
*/
uint32_t sc_speed;
/* End of the mandatory fields.*/
} SerialConfig;
/**
* @brief @p SerialDriver specific data.
*/
#define _serial_driver_data \
_base_asynchronous_channel_data \
/* Driver state.*/ \
sdstate_t state; \
/* Input queue.*/ \
input_queue_t iqueue; \
/* Output queue.*/ \
output_queue_t oqueue; \
/* Input circular buffer.*/ \
uint8_t ib[SERIAL_BUFFERS_SIZE]; \
/* Output circular buffer.*/ \
uint8_t ob[SERIAL_BUFFERS_SIZE]; \
/* End of the mandatory fields.*/ \
/* Pointer to the UART registers block.*/ \
UART_TypeDef *uart;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if KINETIS_SERIAL_USE_UART0 && !defined(__DOXYGEN__)
extern SerialDriver SD1;
#endif
#if KINETIS_SERIAL_USE_UART1 && !defined(__DOXYGEN__)
extern SerialDriver SD2;
#endif
#if KINETIS_SERIAL_USE_UART2 && !defined(__DOXYGEN__)
extern SerialDriver SD3;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void sd_lld_init(void);
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config);
void sd_lld_stop(SerialDriver *sdp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SERIAL */
#endif /* _SERIAL_LLD_H_ */
/** @} */

View File

@ -30,10 +30,6 @@
/* Driver local definitions. */
/*===========================================================================*/
#if !defined(KINETIS_SPI_USE_SPI0)
#define KINETIS_SPI_USE_SPI0 TRUE
#endif
#if !defined(KINETIS_SPI0_RX_DMA_IRQ_PRIORITY)
#define KINETIS_SPI0_RX_DMA_IRQ_PRIORITY 8
#endif
@ -54,8 +50,35 @@
#define KINETIS_SPI0_TX_DMA_CHANNEL 1
#endif
#if !defined(KINETIS_SPI1_RX_DMA_IRQ_PRIORITY)
#define KINETIS_SPI1_RX_DMA_IRQ_PRIORITY 8
#endif
#if !defined(KINETIS_SPI1_RX_DMAMUX_CHANNEL)
#define KINETIS_SPI1_RX_DMAMUX_CHANNEL 0
#endif
#if !defined(KINETIS_SPI1_RX_DMA_CHANNEL)
#define KINETIS_SPI1_RX_DMA_CHANNEL 0
#endif
#if !defined(KINETIS_SPI1_TX_DMAMUX_CHANNEL)
#define KINETIS_SPI1_TX_DMAMUX_CHANNEL 1
#endif
#if !defined(KINETIS_SPI1_TX_DMA_CHANNEL)
#define KINETIS_SPI1_TX_DMA_CHANNEL 1
#endif
#if KINETIS_SPI_USE_SPI0
#define DMAMUX_SPI_RX_SOURCE 16
#define DMAMUX_SPI_TX_SOURCE 17
#endif
#if KINETIS_SPI_USE_SPI1
#define DMAMUX_SPI_RX_SOURCE 18
#define DMAMUX_SPI_TX_SOURCE 19
#endif
/*===========================================================================*/
/* Driver exported variables. */
@ -66,6 +89,11 @@
SPIDriver SPID1;
#endif
/** @brief SPI1 driver identifier.*/
#if KINETIS_SPI_USE_SPI1 || defined(__DOXYGEN__)
SPIDriver SPID2;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
@ -137,7 +165,9 @@ static void spi_stop_xfer(SPIDriver *spip)
/* Driver interrupt handlers. */
/*===========================================================================*/
OSAL_IRQ_HANDLER(Vector40) {
#if KINETIS_SPI_USE_SPI0 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(KINETIS_DMA0_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
/* Clear bit 0 in Interrupt Request Register (INT) by writing 0 to CINT */
@ -150,6 +180,25 @@ OSAL_IRQ_HANDLER(Vector40) {
OSAL_IRQ_EPILOGUE();
}
#endif
#if KINETIS_SPI_USE_SPI1 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(KINETIS_DMA0_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
/* Clear bit 0 in Interrupt Request Register (INT) by writing 0 to CINT */
DMA->CINT = KINETIS_SPI1_RX_DMA_CHANNEL;
spi_stop_xfer(&SPID2);
_spi_isr_code(&SPID2);
OSAL_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
@ -163,6 +212,9 @@ void spi_lld_init(void) {
#if KINETIS_SPI_USE_SPI0
spiObjectInit(&SPID1);
#endif
#if KINETIS_SPI_USE_SPI1
spiObjectInit(&SPID2);
#endif
}
/**
@ -193,6 +245,22 @@ void spi_lld_start(SPIDriver *spip) {
}
#endif
#if KINETIS_SPI_USE_SPI1
if (&SPID2 == spip) {
/* Enable the clock for SPI0 */
SIM->SCGC6 |= SIM_SCGC6_SPI1;
SPID2.spi = SPI1;
if (spip->config->tar0) {
spip->spi->CTAR[0] = spip->config->tar0;
} else {
spip->spi->CTAR[0] = KINETIS_SPI_TAR0_DEFAULT;
}
}
#endif
nvicEnableVector(DMA0_IRQn, KINETIS_SPI0_RX_DMA_IRQ_PRIORITY);
SIM->SCGC6 |= SIM_SCGC6_DMAMUX;
@ -201,6 +269,7 @@ void spi_lld_start(SPIDriver *spip) {
/* Clear DMA error flags */
DMA->ERR = 0x0F;
#if KINETIS_SPI_USE_SPI0
/* Rx, select SPI Rx FIFO */
DMAMUX->CHCFG[KINETIS_SPI0_RX_DMAMUX_CHANNEL] = DMAMUX_CHCFGn_ENBL |
DMAMUX_CHCFGn_SOURCE(DMAMUX_SPI_RX_SOURCE);
@ -239,6 +308,48 @@ void spi_lld_start(SPIDriver *spip) {
DMA_ATTR_DSIZE(dma_size);
DMA->TCD[KINETIS_SPI0_TX_DMA_CHANNEL].NBYTES_MLNO = spip->word_size;
DMA->TCD[KINETIS_SPI0_TX_DMA_CHANNEL].CSR = DMA_CSR_DREQ_MASK;
#endif
#if KINETIS_SPI_USE_SPI1
/* Rx, select SPI Rx FIFO */
DMAMUX->CHCFG[KINETIS_SPI1_RX_DMAMUX_CHANNEL] = DMAMUX_CHCFGn_ENBL |
DMAMUX_CHCFGn_SOURCE(DMAMUX_SPI_RX_SOURCE);
/* Tx, select SPI Tx FIFO */
DMAMUX->CHCFG[KINETIS_SPI1_TX_DMAMUX_CHANNEL] = DMAMUX_CHCFGn_ENBL |
DMAMUX_CHCFGn_SOURCE(DMAMUX_SPI_TX_SOURCE);
/* Extract the frame size from the TAR */
uint16_t frame_size = ((spip->spi->CTAR[0] >> SPIx_CTARn_FMSZ_SHIFT) &
SPIx_CTARn_FMSZ_MASK) + 1;
/* DMA transfer size is 16 bits for a frame size > 8 bits */
uint16_t dma_size = frame_size > 8 ? 1 : 0;
/* DMA word size is 2 for a 16 bit frame size */
spip->word_size = frame_size > 8 ? 2 : 1;
/* configure DMA RX fixed values */
DMA->TCD[KINETIS_SPI1_RX_DMA_CHANNEL].SADDR = (uint32_t)&SPI1->POPR;
DMA->TCD[KINETIS_SPI1_RX_DMA_CHANNEL].SOFF = 0;
DMA->TCD[KINETIS_SPI1_RX_DMA_CHANNEL].SLAST = 0;
DMA->TCD[KINETIS_SPI1_RX_DMA_CHANNEL].DLASTSGA = 0;
DMA->TCD[KINETIS_SPI1_RX_DMA_CHANNEL].ATTR = DMA_ATTR_SSIZE(dma_size) |
DMA_ATTR_DSIZE(dma_size);
DMA->TCD[KINETIS_SPI1_RX_DMA_CHANNEL].NBYTES_MLNO = spip->word_size;
DMA->TCD[KINETIS_SPI1_RX_DMA_CHANNEL].CSR = DMA_CSR_DREQ_MASK |
DMA_CSR_INTMAJOR_MASK;
/* configure DMA TX fixed values */
DMA->TCD[KINETIS_SPI1_TX_DMA_CHANNEL].SLAST = 0;
DMA->TCD[KINETIS_SPI1_TX_DMA_CHANNEL].DADDR = (uint32_t)&SPI1->PUSHR;
DMA->TCD[KINETIS_SPI1_TX_DMA_CHANNEL].DOFF = 0;
DMA->TCD[KINETIS_SPI1_TX_DMA_CHANNEL].DLASTSGA = 0;
DMA->TCD[KINETIS_SPI1_TX_DMA_CHANNEL].ATTR = DMA_ATTR_SSIZE(dma_size) |
DMA_ATTR_DSIZE(dma_size);
DMA->TCD[KINETIS_SPI1_TX_DMA_CHANNEL].NBYTES_MLNO = spip->word_size;
DMA->TCD[KINETIS_SPI1_TX_DMA_CHANNEL].CSR = DMA_CSR_DREQ_MASK;
#endif
}
}
@ -264,10 +375,20 @@ void spi_lld_stop(SPIDriver *spip) {
/* SPI halt.*/
spip->spi->MCR |= SPIx_MCR_HALT;
}
#endif
/* Disable the clock for SPI0 */
SIM->SCGC6 &= ~SIM_SCGC6_SPI0;
#endif
#if KINETIS_SPI_USE_SPI1
if (&SPID2 == spip) {
/* SPI halt.*/
spip->spi->MCR |= SPIx_MCR_HALT;
}
/* Disable the clock for SPI1 */
SIM->SCGC6 &= ~SIM_SCGC6_SPI1;
#endif
}
}

View File

@ -55,17 +55,39 @@
#define KINETIS_SPI_SPI0_IRQ_PRIORITY 10
#endif
/**
* @brief SPI1 driver enable switch.
* @details If set to @p TRUE the support for SPI0 is included.
* @note The default is @p FALSE.
*/
#if !defined(KINETIS_SPI_USE_SPI1) || defined(__DOXYGEN__)
#define KINETIS_SPI_USE_SPI1 FALSE
#endif
/**
* @brief SPI1 interrupt priority level setting.
*/
#if !defined(KINETIS_SPI_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define KINETIS_SPI_SPI1_IRQ_PRIORITY 10
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#define KINETIS_HAS_SPI0 TRUE
#if KINETIS_SPI_USE_SPI0 && !KINETIS_HAS_SPI0
#error "SPI0 not present in the selected device"
#endif
#if !KINETIS_SPI_USE_SPI0
#if KINETIS_SPI_USE_SPI1 && !KINETIS_HAS_SPI1
#error "SPI1 not present in the selected device"
#endif
#if KINETIS_SPI_USE_SPI0 && KINETIS_SPI_USE_SPI1
#error "Only one SPI peripheral can be enabled"
#endif
#if !(KINETIS_SPI_USE_SPI0 || KINETIS_SPI_USE_SPI1)
#error "SPI driver activated but no SPI peripheral assigned"
#endif
@ -74,6 +96,11 @@
#error "Invalid IRQ priority assigned to SPI0"
#endif
#if KINETIS_SPI_USE_SPI1 && \
!OSAL_IRQ_IS_VALID_PRIORITY(KINETIS_SPI_SPI1_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to SPI1"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
@ -205,6 +232,10 @@ struct SPIDriver {
extern SPIDriver SPID1;
#endif
#if KINETIS_SPI_USE_SPI1 && !defined(__DOXYGEN__)
extern SPIDriver SPID2;
#endif
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -1,98 +0,0 @@
/*
ChibiOS - Copyright (C) 2014-2015 Fabio Utzig
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file KINETIS/KL2x/st_lld.c
* @brief ST Driver subsystem low level driver code.
*
* @addtogroup ST
* @{
*/
#include "hal.h"
#if (OSAL_ST_MODE != OSAL_ST_MODE_NONE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if (OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC) || defined(__DOXYGEN__)
/**
* @brief System Timer vector.
* @details This interrupt is used for system tick in periodic mode.
*
* @isr
*/
OSAL_IRQ_HANDLER(SysTick_Handler) {
OSAL_IRQ_PROLOGUE();
osalSysLockFromISR();
osalOsTimerHandlerI();
osalSysUnlockFromISR();
OSAL_IRQ_EPILOGUE();
}
#endif /* OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level ST driver initialization.
*
* @notapi
*/
void st_lld_init(void) {
#if OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC
/* Periodic systick mode, the Cortex-Mx internal systick timer is used
in this mode.*/
SysTick->LOAD = (KINETIS_SYSCLK_FREQUENCY / OSAL_ST_FREQUENCY) - 1;
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_ENABLE_Msk |
SysTick_CTRL_TICKINT_Msk;
/* IRQ enabled.*/
nvicSetSystemHandlerPriority(HANDLER_SYSTICK, KINETIS_ST_IRQ_PRIORITY);
#endif /* OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC */
}
#endif /* OSAL_ST_MODE != OSAL_ST_MODE_NONE */
/** @} */

View File

@ -1,156 +0,0 @@
/*
ChibiOS - Copyright (C) 2014-2015 Fabio Utzig
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file KINETIS/st_lld.h
* @brief ST Driver subsystem low level driver header.
* @details This header is designed to be include-able without having to
* include other files from the HAL.
*
* @addtogroup ST
* @{
*/
#ifndef _ST_LLD_H_
#define _ST_LLD_H_
#include "mcuconf.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief SysTick timer IRQ priority.
*/
#if !defined(KINETIS_ST_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define KINETIS_ST_IRQ_PRIORITY 8
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void st_lld_init(void);
#ifdef __cplusplus
}
#endif
/*===========================================================================*/
/* Driver inline functions. */
/*===========================================================================*/
/**
* @brief Returns the time counter value.
*
* @return The counter value.
*
* @notapi
*/
static inline systime_t st_lld_get_counter(void) {
return (systime_t)0;
}
/**
* @brief Starts the alarm.
* @note Makes sure that no spurious alarms are triggered after
* this call.
*
* @param[in] time the time to be set for the first alarm
*
* @notapi
*/
static inline void st_lld_start_alarm(systime_t time) {
(void)time;
}
/**
* @brief Stops the alarm interrupt.
*
* @notapi
*/
static inline void st_lld_stop_alarm(void) {
}
/**
* @brief Sets the alarm time.
*
* @param[in] time the time to be set for the next alarm
*
* @notapi
*/
static inline void st_lld_set_alarm(systime_t time) {
(void)time;
}
/**
* @brief Returns the current alarm time.
*
* @return The currently set alarm time.
*
* @notapi
*/
static inline systime_t st_lld_get_alarm(void) {
return (systime_t)0;
}
/**
* @brief Determines if the alarm is active.
*
* @return The alarm status.
* @retval false if the alarm is not active.
* @retval true is the alarm is active
*
* @notapi
*/
static inline bool st_lld_is_alarm_active(void) {
return false;
}
#endif /* _ST_LLD_H_ */
/** @} */

View File

@ -40,7 +40,7 @@
#ifdef __CC_ARM
__attribute__ ((section(".ARM.__at_0x400")))
#else
__attribute__ ((used, section(".cfmconfig")))
__attribute__ ((used,section(".cfmconfig")))
#endif
const uint8_t _cfm[0x10] = {
0xFF, /* NV_BACKKEY3: KEY=0xFF */
@ -55,9 +55,20 @@ const uint8_t _cfm[0x10] = {
0xFF, /* NV_FPROT2: PROT=0xFF */
0xFF, /* NV_FPROT1: PROT=0xFF */
0xFF, /* NV_FPROT0: PROT=0xFF */
#if defined(KINETIS_NV_FSEC_BYTE)
#warning Please triple check your FSEC setting: KEYEN!=b10, MEEN==b10, SEC!=b10 leads to an unmodifiable chip.
KINETIS_NV_FSEC_BYTE,
#else /* KINETIS_NV_FSEC_BYTE */
0x7E, /* NV_FSEC: KEYEN=1,MEEN=3,FSLACC=3,SEC=2 */
#endif /* KINETIS_NV_FSEC_BYTE */
#if defined(KINETIS_NV_FOPT_BYTE)
KINETIS_NV_FOPT_BYTE,
#else /* KINETIS_NV_FOPT_BYTE */
0xFF, /* NV_FOPT: ??=1,??=1,FAST_INIT=1,LPBOOT1=1,RESET_PIN_CFG=1,
NMI_DIS=1,EZPORT_DIS=1,LPBOOT0=1 */
/* on KL27: bit7-6:BOOTSRC_SEL=0b11 (11=from ROM; 00=from FLASH)
bit1:BOOTPIN_OPT=1 (NMI pin not sampled at boot) */
#endif /* KINETIS_NV_FOPT_BYTE */
0xFF,
0xFF
};
@ -91,6 +102,7 @@ void hal_lld_init(void) {
*/
void kl2x_clock_init(void) {
#if !KINETIS_NO_INIT
/* Disable COP watchdog */
SIM->COPC = 0;
@ -107,16 +119,118 @@ void kl2x_clock_init(void) {
/* System oscillator drives 32 kHz clock (OSC32KSEL=0) */
SIM->SOPT1 &= ~SIM_SOPT1_OSC32KSEL_MASK;
#if KINETIS_HAS_MCG_LITE
/* MCU only has MCG_Lite */
#if KINETIS_MCGLITE_MODE == KINETIS_MCGLITE_MODE_LIRC8M
/* Out of reset, the MCU is in LIRC8M mode. */
/* Except when coming out of the ROM bootloader, then
* the MCU is in HIRC mode; so better set it explicitly here. */
/* Switching to LIRC8M mode, page 414 of the KL27Z manual. */
/* (1) Write 1b to MCG_C2[IRCS] to select LIRC 8M. */
MCG->C2 |= MCG_C2_IRCS;
/* (2) Write 1b to MCG_C1[IRCLKEN] to enable LIRC clock (optional). */
MCG->C1 |= MCG_C1_IRCLKEN;
/* (2) Write 01b to MCG_C1[CLKS] to select LIRC clock source. */
MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS_LIRC;
/* (3) Check MCG_S[CLKST] to confirm LIRC clock source is selected. */
while( (MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST_LIRC )
;
#elif KINETIS_MCGLITE_MODE == KINETIS_MCGLITE_MODE_HIRC
/* Switching to HIRC mode, page 413 of the KL27Z manual. */
/* (1) Write 1b to MCG_MC[HIRCEN] to enable HIRC (optional). */
MCG->MC |= MCG_MC_HIRCEN;
/* (2) Write 00b to MCG_C1[CLKS] to select HIRC clock source. */
MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS_HIRC;
/* (3) Check MCG_S[CLKST] to confirm HIRC clock source is selected. */
while( (MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST_HIRC )
;
#elif KINETIS_MCGLITE_MODE == KINETIS_MCGLITE_MODE_EXT
/* Assuming we have an external crystal, frequency
* specified with KINETIS_XTAL_FREQUENCY.
*
* Note: Except with 32768 kHz crystal (low-freq mode),
* external load capacitors and a feedback resistor
* are *required*. Additionally, a series resistor is
* required in the high-gain mode, and forbidden in
* the low-power mode.
* In this case, the internal caps can be configured
* via KINETIS_BOARD_OSCILLATOR_SETTING.
* (Page 420 of the KL27 manual.) */
/* EXTAL0 and XTAL0 */
PORTA->PCR[18] &= ~0x01000700; /* Set PA18 to analog (default) */
PORTA->PCR[19] &= ~0x01000700; /* Set PA19 to analog (default) */
/* Internal capacitors for crystal */
#if defined(KINETIS_BOARD_OSCILLATOR_SETTING)
OSC0->CR = KINETIS_BOARD_OSCILLATOR_SETTING;
#else /* KINETIS_BOARD_OSCILLATOR_SETTING */
/* Disable the internal capacitors */
OSC0->CR = 0;
#endif /* KINETIS_BOARD_OSCILLATOR_SETTING */
/* Switching to EXT mode, page 413 of the KL27 manual. */
/* (1) Configure MCG_C2[EREFS0] for external clock source selection. */
#if KINETIS_XTAL_FREQUENCY == 32768 /* low range */
MCG->C2 = (MCG->C2 & ~MCG_C2_RANGE0_MASK) | MCG_C2_RANGE0(0);
#elif (KINETIS_XTAL_FREQUENCY >= 1000000 && \
KINETIS_XTAL_FREQUENCY <= 8000000) /* high range */
MCG->C2 = (MCG->C2 & ~MCG_C2_RANGE0_MASK) | MCG_C2_RANGE0(1);
#elif (KINETIS_XTAL_FREQUENCY > 8000000 && \
KINETIS_XTAL_FREQUENCY <= 32000000) /* very high range */
MCG->C2 = (MCG->C2 & ~MCG_C2_RANGE0_MASK) | MCG_C2_RANGE0(2);
#else /* KINETIS_XTAL_FREQUENCY == */
#error KINETIS_XTAL_FREQUENCY not in allowed range
#endif /* KINETIS_XTAL_FREQUENCY == */
#if defined(KINETIS_XTAL_HIGH_GAIN) && KINETIS_XTAL_HIGH_GAIN
MCG->C2 |= MCG_C2_HGO0;
#endif /* KINETIS_XTAL_HIGH_GAIN */
/* Oscillator requested. */
MCG->C2 |= MCG_C2_EREFS0;
/* (2) Write 10b to MCG_C1[CLKS] to select external clock source. */
MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS_EXT;
/* (3) Check MCG_S[CLKST] to confirm external clock source is selected. */
while( (MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST_EXT )
;
#else /* KINETIS_MCGLITE_MODE */
#error Unimplemented KINETIS_MCGLITE_MODE
#endif /* KINETIS_MCGLITE_MODE */
#else /* KINETIS_HAS_MCG_LITE */
/* MCU has full blown MCG */
#if KINETIS_MCG_MODE == KINETIS_MCG_MODE_FEI
/* This is the default mode at reset. */
/* The MCGOUTCLK is divided by OUTDIV1 and OUTDIV4:
* OUTDIV1 (divider for core/system and bus/flash clock)
* OUTDIV4 (additional divider for bus/flash clock) */
SIM->CLKDIV1 =
SIM_CLKDIV1_OUTDIV1(1) | /* OUTDIV1 = divide-by-2 => 24 MHz */
SIM_CLKDIV1_OUTDIV4(0); /* OUTDIV4 = divide-by-1 => 24 MHz */
SIM_CLKDIV1_OUTDIV1(KINETIS_CLKDIV1_OUTDIV1-1) |
SIM_CLKDIV1_OUTDIV4(KINETIS_CLKDIV1_OUTDIV4-1);
/* Configure FEI mode */
MCG->C4 = MCG_C4_DRST_DRS(KINETIS_MCG_FLL_DRS) |
(KINETIS_MCG_FLL_DMX32 ? MCG_C4_DMX32 : 0);
#elif KINETIS_MCG_MODE == KINETIS_MCG_MODE_FEE
/* TODO: check this, for generality */
/*
* FLL Enabled External (FEE) MCG Mode
* 24 MHz core, 12 MHz bus - using 32.768 kHz crystal with FLL.
@ -138,14 +252,20 @@ void kl2x_clock_init(void) {
* OUTDIV1 (divider for core/system and bus/flash clock)
* OUTDIV4 (additional divider for bus/flash clock) */
SIM->CLKDIV1 =
SIM_CLKDIV1_OUTDIV1(KINETIS_MCG_FLL_OUTDIV1 - 1) |
SIM_CLKDIV1_OUTDIV4(KINETIS_MCG_FLL_OUTDIV4 - 1);
SIM_CLKDIV1_OUTDIV1(KINETIS_CLKDIV1_OUTDIV1 - 1) |
SIM_CLKDIV1_OUTDIV4(KINETIS_CLKDIV1_OUTDIV4 - 1);
/* EXTAL0 and XTAL0 */
PORTA->PCR[18] &= ~0x01000700; /* Set PA18 to analog (default) */
PORTA->PCR[19] &= ~0x01000700; /* Set PA19 to analog (default) */
/* Internal capacitors for crystal */
#if defined(KINETIS_BOARD_OSCILLATOR_SETTING)
OSC0->CR = KINETIS_BOARD_OSCILLATOR_SETTING;
#else /* KINETIS_BOARD_OSCILLATOR_SETTING */
/* Disable the internal capacitors */
OSC0->CR = 0;
#endif /* KINETIS_BOARD_OSCILLATOR_SETTING */
/* From KL25P80M48SF0RM section 24.5.1.1 "Initializing the MCG". */
/* To change from FEI mode to FEE mode: */
@ -183,35 +303,40 @@ void kl2x_clock_init(void) {
seems to omit it. */
#elif KINETIS_MCG_MODE == KINETIS_MCG_MODE_PEE
uint32_t ratio, frdiv;
uint32_t ratios[] = { 32, 64, 128, 256, 512, 1024, 1280, 1536 };
uint8_t ratio_quantity = sizeof(ratios) / sizeof(ratios[0]);
uint8_t i;
/*
* PLL Enabled External (PEE) MCG Mode
* 48 MHz core, 24 MHz bus - using 8 MHz crystal with PLL.
* Uses external crystal (KINETIS_XTAL_FREQUENCY) with PLL.
* f_MCGOUTCLK = (OSCCLK / PLL_R) * M
* = 8 MHz / 2 * 24 = 96 MHz
* OSCCLK = KINETIS_XTAL_FREQUENCY
* PLL_R is the reference divider selected by C5[PRDIV0]
* (OSCCLK/PLL_R must be between 2 and 4 MHz)
* M is the multiplier selected by C6[VDIV0]
*
* Running from PLL, so assuming PLLCLK = MCGOUTCLK.
*
* Then the core/system and bus/flash clocks are divided:
* f_SYS = f_MCGOUTCLK / OUTDIV1 = 96 MHz / 2 = 48 MHz
* f_BUS = f_MCGOUTCLK / OUTDIV1 / OUTDIV4 = 96 MHz / 4 = 24 MHz
*/
/* The MCGOUTCLK is divided by OUTDIV1 and OUTDIV4:
* OUTDIV1 (divider for core/system and bus/flash clock)
* OUTDIV4 (additional divider for bus/flash clock) */
SIM->CLKDIV1 =
SIM_CLKDIV1_OUTDIV1(1) | /* OUTDIV1 = divide-by-2 => 48 MHz */
SIM_CLKDIV1_OUTDIV4(1); /* OUTDIV4 = divide-by-2 => 24 MHz */
SIM->SOPT2 =
SIM_SOPT2_TPMSRC(1) | /* MCGFLLCLK clock or MCGPLLCLK/2 */
SIM_SOPT2_PLLFLLSEL; /* PLLFLLSEL=MCGPLLCLK/2 */
/* EXTAL0 and XTAL0 */
PORTA->PCR[18] &= ~0x01000700; /* Set PA18 to analog (default) */
PORTA->PCR[19] &= ~0x01000700; /* Set PA19 to analog (default) */
/* Start in FEI mode */
/* Internal capacitors for crystal */
#if defined(KINETIS_BOARD_OSCILLATOR_SETTING)
OSC0->CR = KINETIS_BOARD_OSCILLATOR_SETTING;
#else /* KINETIS_BOARD_OSCILLATOR_SETTING */
/* Disable the internal capacitors */
OSC0->CR = 0;
#endif /* KINETIS_BOARD_OSCILLATOR_SETTING */
/* From KL25P80M48SF0RM section 24.5.1.1 "Initializing the MCG". */
/* To change from FEI mode to FBE mode: */
@ -220,15 +345,27 @@ void kl2x_clock_init(void) {
resistor since FRDM-KL25Z has feedback resistor R25 unpopulated.
Use high-gain mode by setting C2[HGO0] instead if external
feedback resistor Rf is installed. */
MCG->C2 =
MCG_C2_RANGE0(2) | /* very high frequency range */
MCG_C2_EREFS0; /* external reference (using a crystal) */
MCG->C2 = MCG_C2_EREFS0; /* external reference (using a crystal) */
if (KINETIS_XTAL_FREQUENCY > 8000000UL)
MCG->C2 |= MCG_C2_RANGE0(2);
else
MCG->C2 |= MCG_C2_RANGE0(1);
/* (2) Write to C1 to select the clock mode. */
frdiv = 7;
ratio = KINETIS_XTAL_FREQUENCY / 31250UL;
for (i = 0; i < ratio_quantity; ++i) {
if (ratio == ratios[i]) {
frdiv = i;
break;
}
}
/* Switch to crystal as clock source, FLL input of 31.25 KHz */
MCG->C1 = /* Clear the IREFS bit to switch to the external reference. */
MCG_C1_CLKS_ERCLK | /* Use ERCLK for system clock, MCGCLKOUT. */
MCG_C1_FRDIV(3); /* Divide ERCLK / 256 for FLL reference. */
/* Note: FLL reference frequency must be 31.25 kHz to 39.0625 kHz.
8 MHz / 256 = 31.25 kHz. */
MCG_C1_CLKS_ERCLK | /* Use Ext Ref Clock for system clock, MCGCLKOUT. */
MCG_C1_FRDIV(frdiv); /* Divide ERCLK / 256 for FLL reference. */
/* Note: FLL reference frequency must be 31.25 kHz to 39.0625 kHz. */
MCG->C4 &= ~(MCG_C4_DMX32 | MCG_C4_DRST_DRS_MASK);
MCG->C6 = 0; /* PLLS=0: Select FLL as MCG source, not PLL */
@ -254,11 +391,25 @@ void kl2x_clock_init(void) {
/* (2) Then configure C5[PRDIV0] to generate the
correct PLL reference frequency. */
MCG->C5 = MCG_C5_PRDIV0(1); /* PLL External Reference Divide by 2 */
#define KINETIS_PLLIN_FREQUENCY 2000000UL
/* TODO: Make sure KINETIS_XTAL_FREQUENCY >= 2Mhz && <= 50Mhz */
/* PLL External Reference Divide by ... */
MCG->C5 = MCG_C5_PRDIV0((KINETIS_XTAL_FREQUENCY/KINETIS_PLLIN_FREQUENCY) - 1);
/* (3) Then from FBE transition to PBE mode. */
/* (3)(b) C6[PLLS]=1 to select PLL. */
/* (3)(b) C6[VDIV0]=5'b0000 (x24) 2 MHz * 24 = 48 MHz. */
MCG->C6 = MCG_C6_PLLS | MCG_C6_VDIV0(0);
/* (3)(b) C6[VDIV0]= PLLIN MHz * i = PLLCLK MHz. */
/* Config PLL output to match KINETIS_SYSCLK_FREQUENCY
* TODO: make sure KINETIS_SYSCLK_FREQUENCY is a match */
for(i = 24; i < 56; i++) {
if(i == (KINETIS_PLLCLK_FREQUENCY/KINETIS_PLLIN_FREQUENCY)) {
/* Config PLL to match KINETIS_PLLCLK_FREQUENCY */
MCG->C6 = MCG_C6_PLLS | MCG_C6_VDIV0(i-24);
break;
}
}
if(i>=56) /* Config PLL for 96 MHz output as default setting */
MCG->C6 = MCG_C6_PLLS | MCG_C6_VDIV0(0);
/* (3)(d) Loop until S[PLLST], indicating PLL
is the PLLS clock source. */
while ((MCG->S & MCG_S_PLLST) == 0)
@ -270,14 +421,26 @@ void kl2x_clock_init(void) {
/* --- MCG mode: PBE (PLL bypassed, external crystal) --- */
/* Set the PLL dividers for the different clocks */
/* The MCGOUTCLK is divided by OUTDIV1 and OUTDIV4:
* OUTDIV1 (divider for core/system and bus/flash clock)
* OUTDIV4 (additional divider for bus/flash clock)
* - these are computed in .h */
SIM->CLKDIV1 =
SIM_CLKDIV1_OUTDIV1(KINETIS_CLKDIV1_OUTDIV1-1) |
SIM_CLKDIV1_OUTDIV4(KINETIS_CLKDIV1_OUTDIV4-1);
SIM->SOPT2 =
SIM_SOPT2_TPMSRC(1) | /* MCGFLLCLK clock or MCGPLLCLK/2 */
SIM_SOPT2_PLLFLLSEL; /* PLLFLLSEL=MCGPLLCLK/2 */
/* (4) Transition from PBE mode to PEE mode. */
/* (4)(a) C1[CLKS] = 2'b00 to select PLL output as system clock source. */
// Switch to PEE mode
// Select PLL output (CLKS=0)
// FLL external reference divider (FRDIV=3)
// FLL external reference divider (FRDIV) already set
// External reference clock for FLL (IREFS=0)
MCG->C1 = MCG_C1_CLKS(0) |
MCG_C1_FRDIV(3);
MCG->C1 = MCG_C1_CLKS(0);
/* (4)(b) Loop until S[CLKST] are 2'b11, indicating the PLL output is selected for MCGOUTCLK. */
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST_PLL)
; /* wait until clock switched to PLL output */
@ -288,6 +451,8 @@ void kl2x_clock_init(void) {
#error Unimplemented KINETIS_MCG_MODE
#endif /* KINETIS_MCG_MODE != KINETIS_MCG_MODE_PEE */
#endif /* KINETIS_HAS_MCG_LITE */
#endif /* !KINETIS_NO_INIT */
}

View File

@ -25,7 +25,7 @@
#ifndef _HAL_LLD_H_
#define _HAL_LLD_H_
#include "kl25z.h"
#include "kl2xz.h"
#include "kinetis_registry.h"
/*===========================================================================*/
@ -44,15 +44,30 @@
#define PLATFORM_NAME "Kinetis"
/** @} */
/**
* @brief Maximum system and core clock (f_SYS) frequency.
*/
#define KINETIS_SYSCLK_MAX 48000000
#if KINETIS_HAS_MCG_LITE
/* MCU only has MCG_Lite */
/**
* @brief Maximum bus clock (f_BUS) frequency.
* @name Internal clock sources
* @{
*/
#define KINETIS_BUSCLK_MAX 24000000
#define KINETIS_HIRC 48000000 /**< High-frequency internal reference clock (USB recovery). */
#define KINETIS_LIRC_8 8000000 /**< Low-frequency internal reference clock (faster). */
#define KINETIS_LIRC_2 2000000 /**< Low-frequency internal reference clock (slower). */
/** @} */
/**
* @name MCG modes of operation
* @{
*/
#define KINETIS_MCGLITE_MODE_LIRC8M 1 /**< Low frequency internal reference mode (8MHz). */
#define KINETIS_MCGLITE_MODE_LIRC2M 2 /**< Low frequency internal reference mode (2MHz). */
#define KINETIS_MCGLITE_MODE_HIRC 3 /**< High frequency internal reference mode (with optional USB recovery). */
#define KINETIS_MCGLITE_MODE_EXT 4 /**< External reference mode. */
/** @} */
#else /* KINETIS_HAS_MCG_LITE */
/* MCU has full blown MCG */
/**
* @name Internal clock sources
@ -62,6 +77,10 @@
#define KINETIS_IRCLK_S 32768 /**< Slow internal reference clock, factory trimmed. */
/** @} */
/**
* @name MCG modes of operation
* @{
*/
#define KINETIS_MCG_MODE_FEI 1 /**< FLL Engaged Internal. */
#define KINETIS_MCG_MODE_FEE 2 /**< FLL Engaged External. */
#define KINETIS_MCG_MODE_FBI 3 /**< FLL Bypassed Internal. */
@ -70,6 +89,9 @@
#define KINETIS_MCG_MODE_PBE 6 /**< PLL Bypassed External. */
#define KINETIS_MCG_MODE_BLPI 7 /**< Bypassed Low Power Internal. */
#define KINETIS_MCG_MODE_BLPE 8 /**< Bypassed Low Power External. */
/** @} */
#endif /* KINETIS_HAS_MCG_LITE */
/*===========================================================================*/
/* Driver pre-compile time settings. */
@ -93,14 +115,29 @@
#define KINETIS_MCG_MODE KINETIS_MCG_MODE_PEE
#endif
#if !defined(KINETIS_MCGLITE_MODE) || defined(__DOXYGEN__)
#define KINETIS_MCGLITE_MODE KINETIS_MCGLITE_MODE_HIRC
#endif
/**
* @brief MCU PLL clock frequency.
*/
#if !defined(KINETIS_PLLCLK_FREQUENCY) || defined(__DOXYGEN__)
#define KINETIS_PLLCLK_FREQUENCY 96000000UL
#endif
/**
* @brief Clock divider for core/system and bus/flash clocks (OUTDIV1).
* @note The allowed range is 1...16.
* @note The default value is calculated for a 48 MHz system clock
* from a 96 MHz PLL output.
*/
#if !defined(KINETIS_MCG_FLL_OUTDIV1) || defined(__DOXYGEN__)
#define KINETIS_MCG_FLL_OUTDIV1 2
#if !defined(KINETIS_CLKDIV1_OUTDIV1) || defined(__DOXYGEN__)
#if defined(KINETIS_SYSCLK_FREQUENCY) && KINETIS_SYSCLK_FREQUENCY > 0
#define KINETIS_CLKDIV1_OUTDIV1 (KINETIS_PLLCLK_FREQUENCY/KINETIS_SYSCLK_FREQUENCY)
#else
#define KINETIS_CLKDIV1_OUTDIV1 2
#endif
#endif
/**
@ -110,8 +147,12 @@
* @note The default value is calculated for 24 MHz bus/flash clocks
* from a 96 MHz PLL output and 48 MHz core/system clock.
*/
#if !defined(KINETIS_MCG_FLL_OUTDIV4) || defined(__DOXYGEN__)
#define KINETIS_MCG_FLL_OUTDIV4 2
#if !defined(KINETIS_CLKDIV1_OUTDIV4) || defined(__DOXYGEN__)
#if defined(KINETIS_BUSCLK_FREQUENCY) && KINETIS_BUSCLK_FREQUENCY > 0
#define KINETIS_CLKDIV1_OUTDIV4 ((KINETIS_PLLCLK_FREQUENCY/KINETIS_CLKDIV1_OUTDIV1)/KINETIS_BUSCLK_FREQUENCY)
#else
#define KINETIS_CLKDIV1_OUTDIV4 2
#endif
#endif
/**
@ -140,14 +181,14 @@
* @brief MCU system/core clock frequency.
*/
#if !defined(KINETIS_SYSCLK_FREQUENCY) || defined(__DOXYGEN__)
#define KINETIS_SYSCLK_FREQUENCY 48000000UL
#define KINETIS_SYSCLK_FREQUENCY (KINETIS_PLLCLK_FREQUENCY / KINETIS_CLKDIV1_OUTDIV1)
#endif
/**
* @brief MCU bus/flash clock frequency.
*/
#if !defined(KINETIS_BUSCLK_FREQUENCY) || defined(__DOXYGEN__)
#define KINETIS_BUSCLK_FREQUENCY (KINETIS_SYSCLK_FREQUENCY / KINETIS_MCG_FLL_OUTDIV4)
#define KINETIS_BUSCLK_FREQUENCY (KINETIS_SYSCLK_FREQUENCY / KINETIS_CLKDIV1_OUTDIV4)
#endif
/**
@ -190,14 +231,20 @@
#error KINETIS_BUSCLK_FREQUENCY out of range
#endif
#if !(defined(KINETIS_MCG_FLL_OUTDIV1) && \
KINETIS_MCG_FLL_OUTDIV1 >= 1 && KINETIS_MCG_FLL_OUTDIV1 <= 16)
#error KINETIS_MCG_FLL_OUTDIV1 must be 1 through 16
#if KINETIS_BUSCLK_FREQUENCY > KINETIS_SYSCLK_FREQUENCY
#error KINETIS_BUSCLK_FREQUENCY must be an integer divide of\
KINETIS_SYSCLK_FREQUENCY
#endif
#if !(defined(KINETIS_MCG_FLL_OUTDIV4) && \
KINETIS_MCG_FLL_OUTDIV4 >= 1 && KINETIS_MCG_FLL_OUTDIV4 <= 8)
#error KINETIS_MCG_FLL_OUTDIV4 must be 1 through 8
#if !(defined(KINETIS_CLKDIV1_OUTDIV1) && \
KINETIS_CLKDIV1_OUTDIV1 >= 1 && KINETIS_CLKDIV1_OUTDIV1 <= 16)
#error KINETIS_CLKDIV1_OUTDIV1 must be 1 through 16
#endif
#if !(defined(KINETIS_CLKDIV1_OUTDIV4) && \
KINETIS_CLKDIV1_OUTDIV4 >= 1 && KINETIS_CLKDIV1_OUTDIV4 <= 16)
#error KINETIS_CLKDIV1_OUTDIV4 must be 1 through 16
#endif
#if !(KINETIS_MCG_FLL_DMX32 == 0 || KINETIS_MCG_FLL_DMX32 == 1)

View File

@ -1,5 +1,6 @@
/*
ChibiOS - Copyright (C) 2014 Derek Mulcahy
(C) 2016 flabbergast <s3+flabbergast@sdfeu.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -25,6 +26,10 @@
#ifndef _KINETIS_REGISTRY_H_
#define _KINETIS_REGISTRY_H_
#if !defined(KL2x) || defined(__DOXYGEN__)
#define KL2x
#endif
/*===========================================================================*/
/* Platform capabilities. */
/*===========================================================================*/
@ -34,16 +39,217 @@
* @{
*/
/* EXT attributes.*/
#define KINETIS_PORTA_IRQ_VECTOR VectorB8
#define KINETIS_PORTD_IRQ_VECTOR VectorBC
/*===========================================================================*/
/* Common features */
/*===========================================================================*/
/**
* @brief Maximum system and core clock (f_SYS) frequency.
*/
#define KINETIS_SYSCLK_MAX 48000000
/**
* @brief Maximum bus clock (f_BUS) frequency.
*/
#define KINETIS_BUSCLK_MAX 24000000
/* ADC attributes.*/
#define KINETIS_HAS_ADC0 TRUE
#define KINETIS_ADC0_IRQ_VECTOR Vector7C
#define KINETIS_HAS_ADC1 FALSE
/* DMA attributes.*/
#define KINETIS_DMA0_IRQ_VECTOR Vector40
#define KINETIS_DMA1_IRQ_VECTOR Vector44
#define KINETIS_DMA2_IRQ_VECTOR Vector48
#define KINETIS_DMA3_IRQ_VECTOR Vector4C
#define KINETIS_HAS_DMA_ERROR_IRQ FALSE
/* GPT attributes.*/
#define KINETIS_PIT_IRQ_VECTOR Vector98
#define KINETIS_HAS_PIT_COMMON_IRQ TRUE
#define KINETIS_HAS_PIT0 TRUE
#define KINETIS_HAS_PIT1 TRUE
#define KINETIS_HAS_PIT2 FALSE
#define KINETIS_HAS_PIT3 FALSE
/* I2C attributes.*/
#define KINETIS_HAS_I2C0 TRUE
#define KINETIS_I2C0_IRQ_VECTOR Vector60
#define KINETIS_HAS_I2C1 TRUE
#define KINETIS_I2C1_IRQ_VECTOR Vector64
/* Serial attributes */
#define KINETIS_HAS_SERIAL0 TRUE
#define KINETIS_SERIAL0_IRQ_VECTOR Vector70
#define KINETIS_HAS_SERIAL1 TRUE
#define KINETIS_SERIAL1_IRQ_VECTOR Vector74
#define KINETIS_HAS_SERIAL2 TRUE
#define KINETIS_SERIAL2_IRQ_VECTOR Vector78
#define KINETIS_HAS_SERIAL_ERROR_IRQ FALSE
/* SPI attributes.*/
#define KINETIS_HAS_SPI0 TRUE
#define KINETIS_SPI0_IRQ_VECTOR Vector68
#define KINETIS_HAS_SPI1 TRUE
#define KINETIS_SPI1_IRQ_VECTOR Vector6C
/* TPM attributes.*/
#define KINETIS_HAS_TPM0 TRUE
#define KINETIS_TPM0_CHANNELS 6
#define KINETIS_TPM0_IRQ_VECTOR Vector84
#define KINETIS_HAS_TPM1 TRUE
#define KINETIS_TPM1_CHANNELS 2
#define KINETIS_TPM1_IRQ_VECTOR Vector88
#define KINETIS_HAS_TPM2 TRUE
#define KINETIS_TPM2_CHANNELS 2
#define KINETIS_TPM2_IRQ_VECTOR Vector8C
/* USB attributes.*/
#define KINETIS_HAS_USB TRUE
#define KINETIS_USB_IRQ_VECTOR VectorA0
/* FTFA attributes.*/
#define KINETIS_FTFA_IRQ_VECTOR Vector54
/* LPTMR attributes */
#define KINETIS_LPTMR0_IRQ_VECTOR VectorB0
/*===========================================================================*/
/* KL25 */
/*===========================================================================*/
#if defined(KL25) || defined(__DOXYGEN__)
/* DAC attributes.*/
#define KINETIS_HAS_DAC0 TRUE
#define KINTEIS_DAC0_IRQ_VECTOR VectorA4
/* EXT attributes.*/
#define KINETIS_PORTA_IRQ_VECTOR VectorB8
#define KINETIS_PORTD_IRQ_VECTOR VectorBC
#define KINETIS_EXT_HAS_COMMON_CD_IRQ FALSE
#define KINETIS_EXT_HAS_COMMON_BCDE_IRQ FALSE
#define KINETIS_GPIO_HAS_OPENDRAIN FALSE
/* I2S attributes.*/
#define KINETIS_HAS_I2S0 FALSE
/* MCG attributes.*/
#define KINETIS_HAS_MCG_LITE FALSE
/* Serial attributes */
#define KINETIS_SERIAL0_IS_UARTLP TRUE
#define KINETIS_SERIAL0_IS_LPUART FALSE
#define KINETIS_SERIAL1_IS_LPUART FALSE
/* USB attributes.*/
#define KINETIS_USB0_IS_USBOTG TRUE
#define KINETIS_HAS_USB_CLOCK_RECOVERY FALSE
/*===========================================================================*/
/* KL26 */
/*===========================================================================*/
#elif defined(KL26) /* defined(KL25) */
/* DAC attributes.*/
#define KINETIS_HAS_DAC0 TRUE
#define KINTEIS_DAC0_IRQ_VECTOR VectorA4
/* EXT attributes.*/
#define KINETIS_PORTA_IRQ_VECTOR VectorB8
/* Common IRQ vector for PORTC and PORTD */
#define KINETIS_PORTD_IRQ_VECTOR VectorBC
#define KINETIS_EXT_HAS_COMMON_CD_IRQ TRUE
#define KINETIS_EXT_HAS_COMMON_BCDE_IRQ FALSE
#define KINETIS_GPIO_HAS_OPENDRAIN FALSE
/* I2S attributes.*/
#define KINETIS_HAS_I2S0 TRUE
#define KINETIS_I2S0_IRQ_VECTOR Vector9C
/* MCG attributes.*/
#define KINETIS_HAS_MCG_LITE FALSE
/* Serial attributes */
#define KINETIS_SERIAL0_IS_UARTLP TRUE
#define KINETIS_SERIAL0_IS_LPUART FALSE
#define KINETIS_SERIAL1_IS_LPUART FALSE
/* USB attributes.*/
#define KINETIS_USB0_IS_USBOTG TRUE
#define KINETIS_HAS_USB_CLOCK_RECOVERY FALSE
/*===========================================================================*/
/* KL27 */
/*===========================================================================*/
#elif defined(KL27Zxxx) || defined(KL27Zxx) /* defined(KL26) */
#if !defined(KL27)
#define KL27
#endif
/* MCG attributes.*/
#define KINETIS_HAS_MCG_LITE TRUE
/* Note: on this device, SERIAL2 IRQ is alternatively FlexIO IRQ. */
/* Serial attributes */
#define KINETIS_SERIAL0_IS_UARTLP FALSE
#define KINETIS_SERIAL0_IS_LPUART TRUE
#define KINETIS_SERIAL1_IS_LPUART TRUE
/* USB attributes.*/
#define KINETIS_USB0_IS_USBOTG FALSE
#define KINETIS_HAS_USB_CLOCK_RECOVERY TRUE
/*===========================================================================*/
/* KL27Zxxx (MKL27Z128* and MKL27Z256*) specific */
/*===========================================================================*/
#if defined(KL27Zxxx)
/* DAC attributes.*/
#define KINETIS_HAS_DAC0 TRUE
#define KINTEIS_DAC0_IRQ_VECTOR VectorA4
/* EXT attributes.*/
#define KINETIS_PORTA_IRQ_VECTOR VectorB8
/* Common IRQ vector for PORTC and PORTD */
#define KINETIS_PORTD_IRQ_VECTOR VectorBC
#define KINETIS_EXT_HAS_COMMON_CD_IRQ TRUE
#define KINETIS_EXT_HAS_COMMON_BCDE_IRQ FALSE
#define KINETIS_GPIO_HAS_OPENDRAIN FALSE
/* I2S attributes.*/
#define KINETIS_HAS_I2S0 TRUE
#define KINETIS_I2S0_IRQ_VECTOR Vector9C
/*===========================================================================*/
/* KL27Zxx (MKL27Z32* and MKL27Z264*) specific */
/*===========================================================================*/
#elif defined(KL27Zxx) /* defined(KL27Zxxx) */
/* Has CRC module */
/* Does not have USB voltage regulator */
/* Does have KEEP_ALIVE USB feature */
/* DAC attributes.*/
#define KINETIS_HAS_DAC0 FALSE
/* EXT attributes.*/
#define KINETIS_PORTA_IRQ_VECTOR VectorB8
/* Common IRQ vector for PORTB to PORTE */
#define KINETIS_PORTD_IRQ_VECTOR VectorBC
#define KINETIS_EXT_HAS_COMMON_CD_IRQ FALSE
#define KINETIS_EXT_HAS_COMMON_BCDE_IRQ TRUE
#define KINETIS_GPIO_HAS_OPENDRAIN FALSE
/* I2S attributes.*/
#define KINETIS_HAS_I2S0 FALSE
#endif /* defined(KL27Zxx) */
#else /* ! (KL25 || KL26 || KL27) */
#error MCU type not described in kinetis_registry
#endif /* KL2Y */
/** @} */

View File

@ -1,120 +0,0 @@
/*
ChibiOS - Copyright (C) 2014 Adam J. Porter
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file KL2x/kinetis_tpm.h
* @brief Kinetis TPM registers layout header.
*
* @addtogroup HAL
* @{
*/
#ifndef _KINETIS_TPM_H_
#define _KINETIS_TPM_H_
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name TPM_SC register
* @{
*/
#define TPM_SC_CMOD_DISABLE (0 << 3)
#define TPM_SC_CMOD_LPTPM_CLK (1 << 3)
#define TPM_SC_CMOD_LPTPM_EXTCLK (2 << 3)
#define TPM_SC_CPWMS (1 << 5)
#define TPM_SC_TOIE (1 << 6)
#define TPM_SC_TOF (1 << 7)
#define TPM_SC_DMA (1 << 8)
/** @} */
/**
* @name TPM_MOD register
* @{
*/
#define TPM_MOD_MASK (0xFFFF)
/** @} */
/**
* @name TPM_CnSC register
* @{
*/
#define TPM_CnSC_DMA (1 << 0)
#define TPM_CnSC_ELSA (1 << 2)
#define TPM_CnSC_ELSB (1 << 3)
#define TPM_CnSC_MSA (1 << 4)
#define TPM_CnSC_MSB (1 << 5)
#define TPM_CnSC_CHIE (1 << 6)
#define TPM_CnSC_CHF (1 << 7)
/** @} */
/**
* @name TPM_CnV register
* @{
*/
#define TPM_CnV_VAL_MASK (0xFFFF)
/** @} */
/**
* @name TPM_STATUS register
* @{
*/
#define TPM_STATUS_CH0F (1 << 0)
#define TPM_STATUS_CH1F (1 << 1)
#define TPM_STATUS_CH2F (1 << 2)
#define TPM_STATUS_CH3F (1 << 3)
#define TPM_STATUS_CH4F (1 << 4)
#define TPM_STATUS_CH5F (1 << 5)
#define TPM_STATUS_TOF (1 << 8)
/** @} */
/**
* @name TPM_CONF register
* @{
*/
#define TPM_CONF_DOZEEN (1 << 5)
#define TPM_CONF_DBGMODE_CONT (3 << 6)
#define TPM_CONF_DBGMODE_PAUSE (0 << 6)
#define TPM_CONF_GTBEEN (1 << 9)
#define TPM_CONF_CSOT (1 << 16)
#define TPM_CONF_CSOO (1 << 17)
#define TPM_CONF_CROT (1 << 18)
#define TPM_CONF_TRGSEL(n) ((n) << 24)
/** @{ */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#endif /* _KINETIS_TPM_H_ */
/** @} */

File diff suppressed because it is too large Load Diff

View File

@ -1,225 +0,0 @@
/*
ChibiOS - Copyright (C) 2013..2015 Fabio Utzig
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file KL2x/pal_lld.c
* @brief Kinetis KL2x PAL subsystem low level driver.
*
* @addtogroup PAL
* @{
*/
#include "osal.h"
#include "hal.h"
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief STM32 I/O ports configuration.
* @details Ports A-D(E, F, G, H) clocks enabled.
*
* @param[in] config the STM32 ports configuration
*
* @notapi
*/
void _pal_lld_init(const PALConfig *config) {
int i, j;
/* Enable clocking of all Ports */
SIM->SCGC5 |= SIM_SCGC5_PORTA |
SIM_SCGC5_PORTB |
SIM_SCGC5_PORTC |
SIM_SCGC5_PORTD |
SIM_SCGC5_PORTE;
for (i = 0; i < TOTAL_PORTS; i++) {
for (j = 0; j < PADS_PER_PORT; j++) {
pal_lld_setpadmode(config->ports[i].port,
j,
config->ports[i].pads[j]);
}
}
}
/**
* @brief Pads mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
*
* @param[in] port the port identifier
* @param[in] mask the group mask
* @param[in] mode the mode
*
* @notapi
*/
void _pal_lld_setgroupmode(ioportid_t port,
ioportmask_t mask,
iomode_t mode) {
(void)port;
(void)mask;
(void)mode;
}
/**
* @brief Reads a logical state from an I/O pad.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
* @return The logical state.
* @retval PAL_LOW low logical state.
* @retval PAL_HIGH high logical state.
*
* @notapi
*/
uint8_t pal_lld_readpad(ioportid_t port, uint8_t pad)
{
return (port->PDIR & ((uint32_t) 1 << pad)) ? PAL_HIGH : PAL_LOW;
}
/**
* @brief Writes a logical state on an output pad.
* @note This function is not meant to be invoked directly by the
* application code.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
* @param[in] bit logical value, the value must be @p PAL_LOW or
* @p PAL_HIGH
*
* @notapi
*/
void pal_lld_writepad(ioportid_t port, uint8_t pad, uint8_t bit)
{
if (bit == PAL_HIGH)
port->PDOR |= ((uint32_t) 1 << pad);
else
port->PDOR &= ~((uint32_t) 1 << pad);
}
/**
* @brief Pad mode setup.
* @details This function programs a pad with the specified mode.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
* @note Programming an unknown or unsupported mode is silently ignored.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
* @param[in] mode pad mode
*
* @notapi
*/
void _pal_lld_setpadmode(ioportid_t port, uint8_t pad, iomode_t mode)
{
PORT_TypeDef *portcfg = NULL;
osalDbgAssert(pad <= 31, "pal_lld_setpadmode() - invalid pad");
if (mode == PAL_MODE_OUTPUT_PUSHPULL)
port->PDDR |= ((uint32_t) 1 << pad);
else
port->PDDR &= ~((uint32_t) 1 << pad);
if (port == IOPORT1)
portcfg = PORTA;
else if (port == IOPORT2)
portcfg = PORTB;
else if (port == IOPORT3)
portcfg = PORTC;
else if (port == IOPORT4)
portcfg = PORTD;
else if (port == IOPORT5)
portcfg = PORTE;
osalDbgAssert(portcfg != NULL, "pal_lld_setpadmode() - invalid port");
switch (mode) {
case PAL_MODE_RESET:
case PAL_MODE_INPUT:
case PAL_MODE_OUTPUT_PUSHPULL:
portcfg->PCR[pad] = PORTx_PCRn_MUX(1);
break;
case PAL_MODE_INPUT_PULLUP:
portcfg->PCR[pad] = PORTx_PCRn_MUX(1) | PORTx_PCRn_PE | PORTx_PCRn_PS;
break;
case PAL_MODE_INPUT_PULLDOWN:
portcfg->PCR[pad] = PORTx_PCRn_MUX(1) | PORTx_PCRn_PE;
break;
case PAL_MODE_UNCONNECTED:
case PAL_MODE_INPUT_ANALOG:
portcfg->PCR[pad] = PORTx_PCRn_MUX(0);
break;
case PAL_MODE_ALTERNATIVE_1:
portcfg->PCR[pad] = PORTx_PCRn_MUX(1);
break;
case PAL_MODE_ALTERNATIVE_2:
portcfg->PCR[pad] = PORTx_PCRn_MUX(2);
break;
case PAL_MODE_ALTERNATIVE_3:
portcfg->PCR[pad] = PORTx_PCRn_MUX(3);
break;
case PAL_MODE_ALTERNATIVE_4:
portcfg->PCR[pad] = PORTx_PCRn_MUX(4);
break;
case PAL_MODE_ALTERNATIVE_5:
portcfg->PCR[pad] = PORTx_PCRn_MUX(5);
break;
case PAL_MODE_ALTERNATIVE_6:
portcfg->PCR[pad] = PORTx_PCRn_MUX(6);
break;
case PAL_MODE_ALTERNATIVE_7:
portcfg->PCR[pad] = PORTx_PCRn_MUX(7);
break;
}
}
#endif /* HAL_USE_PAL */
/** @} */

View File

@ -1,331 +0,0 @@
/*
ChibiOS - Copyright (C) 2013-2015 Fabio Utzig
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file KL2x/pal_lld.h
* @brief Kinetis KL2x PAL subsystem low level driver header.
*
* @addtogroup PAL
* @{
*/
#ifndef _PAL_LLD_H_
#define _PAL_LLD_H_
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Unsupported modes and specific modes */
/*===========================================================================*/
#undef PAL_MODE_OUTPUT_OPENDRAIN
#define PAL_MODE_ALTERNATIVE_1 0x10
#define PAL_MODE_ALTERNATIVE_2 0x11
#define PAL_MODE_ALTERNATIVE_3 0x12
#define PAL_MODE_ALTERNATIVE_4 0x13
#define PAL_MODE_ALTERNATIVE_5 0x14
#define PAL_MODE_ALTERNATIVE_6 0x15
#define PAL_MODE_ALTERNATIVE_7 0x16
/*===========================================================================*/
/* I/O Ports Types and constants. */
/*===========================================================================*/
#define TOTAL_PORTS 5
#define PADS_PER_PORT 32
/**
* @brief Digital I/O port sized unsigned type.
*/
typedef uint32_t ioportmask_t;
/**
* @brief Digital I/O modes.
*/
typedef uint8_t iomode_t;
/**
* @brief Port Identifier.
* @details This type can be a scalar or some kind of pointer, do not make
* any assumption about it, use the provided macros when populating
* variables of this type.
*/
typedef GPIO_TypeDef * ioportid_t;
typedef struct {
ioportid_t port;
iomode_t pads[PADS_PER_PORT];
} PortConfig;
/**
* @brief Generic I/O ports static initializer.
* @details An instance of this structure must be passed to @p palInit() at
* system startup time in order to initialized the digital I/O
* subsystem. This represents only the initial setup, specific pads
* or whole ports can be reprogrammed at later time.
* @note Implementations may extend this structure to contain more,
* architecture dependent, fields.
*/
typedef struct
{
PortConfig ports[TOTAL_PORTS];
} PALConfig;
/**
* @brief Width, in bits, of an I/O port.
*/
#define PAL_IOPORTS_WIDTH 32
/**
* @brief Whole port mask.
* @brief This macro specifies all the valid bits into a port.
*/
#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFFFFFF)
/*===========================================================================*/
/* I/O Ports Identifiers. */
/*===========================================================================*/
/**
* @brief First I/O port identifier.
* @details Low level drivers can define multiple ports, it is suggested to
* use this naming convention.
*/
#define IOPORT1 GPIOA
#define IOPORT2 GPIOB
#define IOPORT3 GPIOC
#define IOPORT4 GPIOD
#define IOPORT5 GPIOE
/*===========================================================================*/
/* Implementation, some of the following macros could be implemented as */
/* functions, if so please put them in pal_lld.c. */
/*===========================================================================*/
/**
* @brief Low level PAL subsystem initialization.
*
* @param[in] config architecture-dependent ports configuration
*
* @notapi
*/
#define pal_lld_init(config) _pal_lld_init(config)
/**
* @brief Reads the physical I/O port states.
*
* @param[in] port port identifier
* @return The port bits.
*
* @notapi
*/
#define pal_lld_readport(port) \
(port)->PDIR
/**
* @brief Reads the output latch.
* @details The purpose of this function is to read back the latched output
* value.
*
* @param[in] port port identifier
* @return The latched logical states.
*
* @notapi
*/
#define pal_lld_readlatch(port) \
(port)->PDOR
/**
* @brief Writes a bits mask on a I/O port.
*
* @param[in] port port identifier
* @param[in] bits bits to be written on the specified port
*
* @notapi
*/
#define pal_lld_writeport(port, bits) \
(port)->PDOR = (bits)
/**
* @brief Sets a bits mask on a I/O port.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] bits bits to be ORed on the specified port
*
* @notapi
*/
#define pal_lld_setport(port, bits) \
(port)->PSOR = (bits)
/**
* @brief Clears a bits mask on a I/O port.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] bits bits to be cleared on the specified port
*
* @notapi
*/
#define pal_lld_clearport(port, bits) \
(port)->PCOR = (bits)
/**
* @brief Toggles a bits mask on a I/O port.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] bits bits to be XORed on the specified port
*
* @notapi
*/
#define pal_lld_toggleport(port, bits) \
(port)->PTOR = (bits)
/**
* @brief Reads a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @return The group logical states.
*
* @notapi
*/
#define pal_lld_readgroup(port, mask, offset) 0
/**
* @brief Writes a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @param[in] bits bits to be written. Values exceeding the group width
* are masked.
*
* @notapi
*/
#define pal_lld_writegroup(port, mask, offset, bits) (void)bits
/**
* @brief Pads group mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
* @note Programming an unknown or unsupported mode is silently ignored.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @param[in] mode group mode
*
* @notapi
*/
#define pal_lld_setgroupmode(port, mask, offset, mode) \
_pal_lld_setgroupmode(port, mask << offset, mode)
/**
* @brief Sets a pad logical state to @p PAL_HIGH.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_setpad(port, pad) (port)->PSOR = ((uint32_t) 1 << (pad))
/**
* @brief Clears a pad logical state to @p PAL_LOW.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_clearpad(port, pad) (port)->PCOR = ((uint32_t) 1 << (pad))
/**
* @brief Toggles a pad logical state.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_togglepad(port, pad) (port)->PTOR = ((uint32_t) 1 << (pad))
/**
* @brief Pad mode setup.
* @details This function programs a pad with the specified mode.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
* @note Programming an unknown or unsupported mode is silently ignored.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
* @param[in] mode pad mode
*
* @notapi
*/
#define pal_lld_setpadmode(port, pad, mode) \
_pal_lld_setpadmode(port, pad, mode)
#if !defined(__DOXYGEN__)
extern const PALConfig pal_default_config;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void _pal_lld_init(const PALConfig *config);
void _pal_lld_setgroupmode(ioportid_t port,
ioportmask_t mask,
iomode_t mode);
void pal_lld_setpadmode(ioportid_t port,
uint8_t pad,
iomode_t mode);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_PAL */
#endif /* _PAL_LLD_H_ */
/** @} */

View File

@ -1,13 +1,15 @@
# List of all platform files.
PLATFORMSRC = ${CHIBIOS}/os/hal/ports/common/ARMCMx/nvic.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/KL2x/hal_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/KL2x/pal_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/KL2x/serial_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/pal_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/serial_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/i2c_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/ext_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/adc_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/gpt_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/KL2x/pwm_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/KL2x/st_lld.c
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/st_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/usb_lld.c
# Required include directories
PLATFORMINC = ${CHIBIOS}/os/hal/ports/common/ARMCMx \

View File

@ -26,18 +26,6 @@
#if HAL_USE_PWM || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
#define KINETIS_TPM0_CHANNELS 6
#define KINETIS_TPM1_CHANNELS 2
#define KINETIS_TPM2_CHANNELS 2
#define KINETIS_TPM0_HANDLER Vector84
#define KINETIS_TPM1_HANDLER Vector88
#define KINETIS_TPM2_HANDLER Vector8C
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
@ -80,25 +68,25 @@ static void pwm_lld_serve_interrupt(PWMDriver *pwmp) {
sr = pwmp->tpm->STATUS;
pwmp->tpm->STATUS = 0xFFFFFFFF;
if (((sr & TPM_SC_TOF) != 0) &&
if (((sr & TPMx_STATUS_TOF) != 0) &&
(pwmp->config->callback != NULL))
pwmp->config->callback(pwmp);
if (((sr & TPM_STATUS_CH0F) != 0) &&
if (((sr & TPMx_STATUS_CH0F) != 0) &&
(pwmp->config->channels[0].callback != NULL))
pwmp->config->channels[0].callback(pwmp);
if (((sr & TPM_STATUS_CH1F) != 0) &&
if (((sr & TPMx_STATUS_CH1F) != 0) &&
(pwmp->config->channels[1].callback != NULL))
pwmp->config->channels[1].callback(pwmp);
if (((sr & TPM_STATUS_CH2F) != 0) &&
if (((sr & TPMx_STATUS_CH2F) != 0) &&
(pwmp->config->channels[2].callback != NULL))
pwmp->config->channels[2].callback(pwmp);
if (((sr & TPM_STATUS_CH3F) != 0) &&
if (((sr & TPMx_STATUS_CH3F) != 0) &&
(pwmp->config->channels[3].callback != NULL))
pwmp->config->channels[3].callback(pwmp);
if (((sr & TPM_STATUS_CH4F) != 0) &&
if (((sr & TPMx_STATUS_CH4F) != 0) &&
(pwmp->config->channels[4].callback != NULL))
pwmp->config->channels[4].callback(pwmp);
if (((sr & TPM_STATUS_CH5F) != 0) &&
if (((sr & TPMx_STATUS_CH5F) != 0) &&
(pwmp->config->channels[5].callback != NULL))
pwmp->config->channels[5].callback(pwmp);
}
@ -113,7 +101,7 @@ static void pwm_lld_serve_interrupt(PWMDriver *pwmp) {
*
* @isr
*/
OSAL_IRQ_HANDLER(KINETIS_TPM0_HANDLER) {
OSAL_IRQ_HANDLER(KINETIS_TPM0_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
pwm_lld_serve_interrupt(&PWMD1);
@ -127,7 +115,7 @@ OSAL_IRQ_HANDLER(KINETIS_TPM0_HANDLER) {
*
* @isr
*/
OSAL_IRQ_HANDLER(KINETIS_TPM1_HANDLER) {
OSAL_IRQ_HANDLER(KINETIS_TPM1_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
pwm_lld_serve_interrupt(&PWMD2);
@ -141,7 +129,7 @@ OSAL_IRQ_HANDLER(KINETIS_TPM1_HANDLER) {
*
* @isr
*/
OSAL_IRQ_HANDLER(KINETIS_TPM2_HANDLER) {
OSAL_IRQ_HANDLER(KINETIS_TPM2_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
pwm_lld_serve_interrupt(&PWMD3);
@ -238,7 +226,7 @@ void pwm_lld_start(PWMDriver *pwmp) {
CPWM up-counting mode
Timer overflow interrupt disabled
DMA disabled.*/
pwmp->tpm->SC = TPM_SC_CMOD_LPTPM_CLK | i;
pwmp->tpm->SC = TPMx_SC_CMOD_LPTPM_CLK | i;
/* Configure period.*/
pwmp->tpm->MOD = pwmp->period - 1;
}
@ -297,19 +285,19 @@ void pwm_lld_stop(PWMDriver *pwmp) {
void pwm_lld_enable_channel(PWMDriver *pwmp,
pwmchannel_t channel,
pwmcnt_t width) {
uint32_t mode = TPM_CnSC_MSB; /* Edge-aligned PWM mode.*/
uint32_t mode = TPMx_CnSC_MSB; /* Edge-aligned PWM mode.*/
switch (pwmp->config->channels[channel].mode & PWM_OUTPUT_MASK) {
case PWM_OUTPUT_ACTIVE_HIGH:
mode |= TPM_CnSC_ELSB;
mode |= TPMx_CnSC_ELSB;
break;
case PWM_OUTPUT_ACTIVE_LOW:
mode |= TPM_CnSC_ELSA;
mode |= TPMx_CnSC_ELSA;
break;
}
if (pwmp->tpm->C[channel].SC & TPM_CnSC_CHIE)
mode |= TPM_CnSC_CHIE;
if (pwmp->tpm->C[channel].SC & TPMx_CnSC_CHIE)
mode |= TPMx_CnSC_CHIE;
pwmp->tpm->C[channel].SC = mode;
pwmp->tpm->C[channel].V = width;
@ -344,7 +332,7 @@ void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) {
*/
void pwm_lld_enable_periodic_notification(PWMDriver *pwmp) {
pwmp->tpm->SC |= TPM_SC_TOIE;
pwmp->tpm->SC |= TPMx_SC_TOIE;
}
/**
@ -358,7 +346,7 @@ void pwm_lld_enable_periodic_notification(PWMDriver *pwmp) {
*/
void pwm_lld_disable_periodic_notification(PWMDriver *pwmp) {
pwmp->tpm->SC &= ~TPM_SC_TOIE;
pwmp->tpm->SC &= ~TPMx_SC_TOIE;
}
/**
@ -375,7 +363,7 @@ void pwm_lld_disable_periodic_notification(PWMDriver *pwmp) {
void pwm_lld_enable_channel_notification(PWMDriver *pwmp,
pwmchannel_t channel) {
pwmp->tpm->C[channel].SC |= TPM_CnSC_CHIE;
pwmp->tpm->C[channel].SC |= TPMx_CnSC_CHIE;
}
/**
@ -392,7 +380,7 @@ void pwm_lld_enable_channel_notification(PWMDriver *pwmp,
void pwm_lld_disable_channel_notification(PWMDriver *pwmp,
pwmchannel_t channel) {
pwmp->tpm->C[channel].SC &= ~TPM_CnSC_CHIE;
pwmp->tpm->C[channel].SC &= ~TPMx_CnSC_CHIE;
}
#endif /* HAL_USE_PWM */

View File

@ -25,8 +25,6 @@
#ifndef _PWM_LLD_H_
#define _PWM_LLD_H_
#include "kinetis_tpm.h"
#if HAL_USE_PWM || defined(__DOXYGEN__)
/*===========================================================================*/
@ -65,16 +63,80 @@
#if !defined(KINETIS_PWM_USE_ADVANCED) || defined(__DOXYGEN__)
#define KINETIS_PWM_USE_ADVANCED FALSE
#endif
/**
* @brief TPM0 interrupt priority level setting.
* @note The default is 2.
*/
#if !defined(KINETIS_PWM_TPM0_IRQ_PRIORITY)|| defined(__DOXYGEN__)
#define KINETIS_PWM_TPM0_IRQ_PRIORITY 2
#endif
/**
* @brief TPM1 interrupt priority level setting.
* @note The default is 2.
*/
#if !defined(KINETIS_PWM_TPM1_IRQ_PRIORITY)|| defined(__DOXYGEN__)
#define KINETIS_PWM_TPM1_IRQ_PRIORITY 2
#endif
/**
* @brief TPM2 interrupt priority level setting.
* @note The default is 2.
*/
#if !defined(KINETIS_PWM_TPM2_IRQ_PRIORITY)|| defined(__DOXYGEN__)
#define KINETIS_PWM_TPM2_IRQ_PRIORITY 2
#endif
/** @} */
/*===========================================================================*/
/* Configuration checks. */
/*===========================================================================*/
#if KINETIS_PWM_USE_TPM0 && !KINETIS_HAS_TPM0
#error "TPM0 not present in the selected device"
#endif
#if KINETIS_PWM_USE_TPM1 && !KINETIS_HAS_TPM1
#error "TPM1 not present in the selected device"
#endif
#if KINETIS_PWM_USE_TPM2 && !KINETIS_HAS_TPM2
#error "TPM2 not present in the selected device"
#endif
#if !KINETIS_PWM_USE_TPM0 && !KINETIS_PWM_USE_TPM1 && !KINETIS_PWM_USE_TPM2
#error "PWM driver activated but no TPM peripheral assigned"
#endif
#if KINETIS_PWM_USE_TPM0 && \
!OSAL_IRQ_IS_VALID_PRIORITY(KINETIS_PWM_TPM0_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to KINETIS_PWM_TPM0_IRQ_PRIORITY"
#endif
#if KINETIS_PWM_USE_TPM1 && \
!OSAL_IRQ_IS_VALID_PRIORITY(KINETIS_PWM_TPM1_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to KINETIS_PWM_TPM1_IRQ_PRIORITY"
#endif
#if KINETIS_PWM_USE_TPM2 && \
!OSAL_IRQ_IS_VALID_PRIORITY(KINETIS_PWM_TPM2_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to KINETIS_PWM_TPM2_IRQ_PRIORITY"
#endif
#if !defined(KINETIS_TPM0_IRQ_VECTOR)
#error "KINETIS_TPM0_IRQ_VECTOR not defined"
#endif
#if !defined(KINETIS_TPM1_IRQ_VECTOR)
#error "KINETIS_TPM1_IRQ_VECTOR not defined"
#endif
#if !defined(KINETIS_TPM2_IRQ_VECTOR)
#error "KINETIS_TPM2_IRQ_VECTOR not defined"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/

View File

@ -1,353 +0,0 @@
/*
ChibiOS - Copyright (C) 2013-2015 Fabio Utzig
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file KL2x/serial_lld.c
* @brief Kinetis KL2x Serial Driver subsystem low level driver source.
*
* @addtogroup SERIAL
* @{
*/
#include "osal.h"
#include "hal.h"
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
#include "kl25z.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief SD1 driver identifier.
*/
#if KINETIS_SERIAL_USE_UART0 || defined(__DOXYGEN__)
SerialDriver SD1;
#endif
#if KINETIS_SERIAL_USE_UART1 || defined(__DOXYGEN__)
SerialDriver SD2;
#endif
#if KINETIS_SERIAL_USE_UART2 || defined(__DOXYGEN__)
SerialDriver SD3;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/**
* @brief Driver default configuration.
*/
static const SerialConfig default_config = {
38400
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Common IRQ handler.
* @note Tries hard to clear all the pending interrupt sources, we don't
* want to go through the whole ISR and have another interrupt soon
* after.
*
* @param[in] u pointer to an UART I/O block
* @param[in] sdp communication channel associated to the UART
*/
static void serve_interrupt(SerialDriver *sdp) {
UARTLP_TypeDef *u = sdp->uart;
if (u->S1 & UARTx_S1_RDRF) {
osalSysLockFromISR();
if (iqIsEmptyI(&sdp->iqueue))
chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE);
if (iqPutI(&sdp->iqueue, u->D) < Q_OK)
chnAddFlagsI(sdp, SD_OVERRUN_ERROR);
osalSysUnlockFromISR();
}
if (u->S1 & UARTx_S1_TDRE) {
msg_t b;
osalSysLockFromISR();
b = oqGetI(&sdp->oqueue);
osalSysUnlockFromISR();
if (b < Q_OK) {
osalSysLockFromISR();
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
osalSysUnlockFromISR();
u->C2 &= ~UARTx_C2_TIE;
} else {
u->D = b;
}
}
if (u->S1 & UARTx_S1_IDLE)
u->S1 = UARTx_S1_IDLE; // Clear IDLE (S1 bits are write-1-to-clear).
if (u->S1 & (UARTx_S1_OR | UARTx_S1_NF | UARTx_S1_FE | UARTx_S1_PF)) {
// FIXME: need to add set_error()
// Clear flags (S1 bits are write-1-to-clear).
u->S1 = UARTx_S1_OR | UARTx_S1_NF | UARTx_S1_FE | UARTx_S1_PF;
}
}
/**
* @brief Attempts a TX preload
*/
static void preload(SerialDriver *sdp) {
UARTLP_TypeDef *u = sdp->uart;
if (u->S1 & UARTx_S1_TDRE) {
msg_t b = oqGetI(&sdp->oqueue);
if (b < Q_OK) {
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
return;
}
u->D = b;
u->C2 |= UARTx_C2_TIE;
}
}
/**
* @brief Driver output notification.
*/
#if KINETIS_SERIAL_USE_UART0 || defined(__DOXYGEN__)
static void notify1(io_queue_t *qp)
{
(void)qp;
preload(&SD1);
}
#endif
#if KINETIS_SERIAL_USE_UART1 || defined(__DOXYGEN__)
static void notify2(io_queue_t *qp)
{
(void)qp;
preload(&SD2);
}
#endif
#if KINETIS_SERIAL_USE_UART2 || defined(__DOXYGEN__)
static void notify3(io_queue_t *qp)
{
(void)qp;
preload(&SD3);
}
#endif
/**
* @brief Common UART configuration.
*
*/
static void configure_uart(UARTLP_TypeDef *uart, const SerialConfig *config)
{
uint32_t uart_clock;
uart->C1 = 0;
uart->C3 = UARTx_C3_ORIE | UARTx_C3_NEIE | UARTx_C3_FEIE | UARTx_C3_PEIE;
uart->S1 = UARTx_S1_IDLE | UARTx_S1_OR | UARTx_S1_NF | UARTx_S1_FE | UARTx_S1_PF;
while (uart->S1 & UARTx_S1_RDRF) {
(void)uart->D;
}
#if KINETIS_SERIAL_USE_UART0
if (uart == UART0) {
/* UART0 can be clocked from several sources. */
uart_clock = KINETIS_UART0_CLOCK_FREQ;
}
#endif
#if KINETIS_SERIAL_USE_UART1
if (uart == UART1) {
uart_clock = KINETIS_BUSCLK_FREQUENCY;
}
#endif
#if KINETIS_SERIAL_USE_UART2
if (uart == UART2) {
uart_clock = KINETIS_BUSCLK_FREQUENCY;
}
#endif
/* FIXME: change fixed OSR = 16 to dynamic value based on baud */
uint16_t divisor = (uart_clock / 16) / config->sc_speed;
uart->C4 = UARTx_C4_OSR & (16 - 1);
uart->BDH = (divisor >> 8) & UARTx_BDH_SBR;
uart->BDL = (divisor & UARTx_BDL_SBR);
uart->C2 = UARTx_C2_RE | UARTx_C2_RIE | UARTx_C2_TE;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if KINETIS_SERIAL_USE_UART0 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(Vector70) {
OSAL_IRQ_PROLOGUE();
serve_interrupt(&SD1);
OSAL_IRQ_EPILOGUE();
}
#endif
#if KINETIS_SERIAL_USE_UART1 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(Vector74) {
OSAL_IRQ_PROLOGUE();
serve_interrupt(&SD2);
OSAL_IRQ_EPILOGUE();
}
#endif
#if KINETIS_SERIAL_USE_UART2 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(Vector78) {
OSAL_IRQ_PROLOGUE();
serve_interrupt(&SD3);
OSAL_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level serial driver initialization.
*
* @notapi
*/
void sd_lld_init(void) {
#if KINETIS_SERIAL_USE_UART0
/* Driver initialization.*/
sdObjectInit(&SD1, NULL, notify1);
SD1.uart = UART0;
#endif
#if KINETIS_SERIAL_USE_UART1
/* Driver initialization.*/
sdObjectInit(&SD2, NULL, notify2);
SD2.uart = UART1;
#endif
#if KINETIS_SERIAL_USE_UART2
/* Driver initialization.*/
sdObjectInit(&SD3, NULL, notify3);
SD3.uart = UART2;
#endif
}
/**
* @brief Low level serial driver configuration and (re)start.
*
* @param[in] sdp pointer to a @p SerialDriver object
* @param[in] config the architecture-dependent serial driver configuration.
* If this parameter is set to @p NULL then a default
* configuration is used.
*
* @notapi
*/
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
if (config == NULL)
config = &default_config;
if (sdp->state == SD_STOP) {
/* Enables the peripheral.*/
#if KINETIS_SERIAL_USE_UART0
if (sdp == &SD1) {
SIM->SCGC4 |= SIM_SCGC4_UART0;
SIM->SOPT2 =
(SIM->SOPT2 & ~SIM_SOPT2_UART0SRC_MASK) |
SIM_SOPT2_UART0SRC(KINETIS_UART0_CLOCK_SRC);
configure_uart(sdp->uart, config);
nvicEnableVector(UART0_IRQn, KINETIS_SERIAL_UART0_PRIORITY);
}
#endif /* KINETIS_SERIAL_USE_UART0 */
#if KINETIS_SERIAL_USE_UART1
if (sdp == &SD2) {
SIM->SCGC4 |= SIM_SCGC4_UART1;
configure_uart(sdp->uart, config);
nvicEnableVector(UART1_IRQn, KINETIS_SERIAL_UART1_PRIORITY);
}
#endif /* KINETIS_SERIAL_USE_UART1 */
#if KINETIS_SERIAL_USE_UART2
if (sdp == &SD3) {
SIM->SCGC4 |= SIM_SCGC4_UART2;
configure_uart(sdp->uart, config);
nvicEnableVector(UART2_IRQn, KINETIS_SERIAL_UART2_PRIORITY);
}
#endif /* KINETIS_SERIAL_USE_UART2 */
}
/* Configures the peripheral.*/
}
/**
* @brief Low level serial driver stop.
* @details De-initializes the USART, stops the associated clock, resets the
* interrupt vector.
*
* @param[in] sdp pointer to a @p SerialDriver object
*
* @notapi
*/
void sd_lld_stop(SerialDriver *sdp) {
if (sdp->state == SD_READY) {
/* TODO: Resets the peripheral.*/
#if KINETIS_SERIAL_USE_UART0
if (sdp == &SD1) {
nvicDisableVector(UART0_IRQn);
SIM->SCGC4 &= ~SIM_SCGC4_UART0;
}
#endif
#if KINETIS_SERIAL_USE_UART1
if (sdp == &SD2) {
nvicDisableVector(UART1_IRQn);
SIM->SCGC4 &= ~SIM_SCGC4_UART1;
}
#endif
#if KINETIS_SERIAL_USE_UART2
if (sdp == &SD3) {
nvicDisableVector(UART2_IRQn);
SIM->SCGC4 &= ~SIM_SCGC4_UART2;
}
#endif
}
}
#endif /* HAL_USE_SERIAL */
/** @} */

View File

@ -89,6 +89,19 @@ static void ext_lld_exti_irq_enable(void) {
#if KINETIS_EXT_PORTA_WIDTH > 0
nvicEnableVector(PINA_IRQn, KINETIS_EXT_PORTA_IRQ_PRIORITY);
#endif
#if KINETIS_EXT_HAS_COMMON_BCDE_IRQ
#if (KINETIS_EXT_PORTB_WIDTH > 0) || (KINETIS_EXT_PORTC_WIDTH > 0) \
|| (KINETIS_EXT_PORTD_WIDTH > 0) || (KINETIS_EXT_PORTE_WIDTH > 0)
nvicEnableVector(PINBCDE_IRQn, KINETIS_EXT_PORTD_IRQ_PRIORITY);
#endif
#elif KINETIS_EXT_HAS_COMMON_CD_IRQ /* KINETIS_EXT_HAS_COMMON_BCDE_IRQ */
#if (KINETIS_EXT_PORTC_WIDTH > 0) || (KINETIS_EXT_PORTD_WIDTH > 0)
nvicEnableVector(PINCD_IRQn, KINETIS_EXT_PORTD_IRQ_PRIORITY);
#endif
#else /* KINETIS_EXT_HAS_COMMON_CD_IRQ */
#if KINETIS_EXT_PORTB_WIDTH > 0
nvicEnableVector(PINB_IRQn, KINETIS_EXT_PORTB_IRQ_PRIORITY);
#endif
@ -101,6 +114,7 @@ static void ext_lld_exti_irq_enable(void) {
#if KINETIS_EXT_PORTE_WIDTH > 0
nvicEnableVector(PINE_IRQn, KINETIS_EXT_PORTE_IRQ_PRIORITY);
#endif
#endif /* !KINETIS_EXT_HAS_COMMON_CD_IRQ */
}
/**
@ -113,6 +127,19 @@ static void ext_lld_exti_irq_disable(void) {
#if KINETIS_EXT_PORTA_WIDTH > 0
nvicDisableVector(PINA_IRQn);
#endif
#if KINETIS_EXT_HAS_COMMON_BCDE_IRQ
#if (KINETIS_EXT_PORTB_WIDTH > 0) || (KINETIS_EXT_PORTC_WIDTH > 0) \
|| (KINETIS_EXT_PORTD_WIDTH > 0) || (KINETIS_EXT_PORTE_WIDTH > 0)
nvicDisableVector(PINBCDE_IRQn);
#endif
#elif KINETIS_EXT_HAS_COMMON_CD_IRQ /* KINETIS_EXT_HAS_COMMON_BCDE_IRQ */
#if (KINETIS_EXT_PORTC_WIDTH > 0) || (KINETIS_EXT_PORTD_WIDTH > 0)
nvicDisableVector(PINCD_IRQn);
#endif
#else /* KINETIS_EXT_HAS_COMMON_CD_IRQ */
#if KINETIS_EXT_PORTB_WIDTH > 0
nvicDisableVector(PINB_IRQn);
#endif
@ -125,6 +152,7 @@ static void ext_lld_exti_irq_disable(void) {
#if KINETIS_EXT_PORTE_WIDTH > 0
nvicDisableVector(PINE_IRQn);
#endif
#endif /* !KINETIS_EXT_HAS_COMMON_CD_IRQ */
}
/*===========================================================================*/
@ -164,6 +192,49 @@ OSAL_IRQ_HANDLER(KINETIS_PORTA_IRQ_VECTOR) {
}
#endif /* KINETIS_EXT_PORTA_WIDTH > 0 */
#if KINETIS_EXT_HAS_COMMON_BCDE_IRQ
#if defined(KINETIS_PORTD_IRQ_VECTOR)
OSAL_IRQ_HANDLER(KINETIS_PORTD_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
#if (KINETIS_EXT_PORTB_WIDTH > 0)
irq_handler(PORTB, KINETIS_EXT_PORTB_WIDTH, portb_channel_map);
#endif
#if (KINETIS_EXT_PORTC_WIDTH > 0)
irq_handler(PORTC, KINETIS_EXT_PORTC_WIDTH, portc_channel_map);
#endif
#if (KINETIS_EXT_PORTD_WIDTH > 0)
irq_handler(PORTD, KINETIS_EXT_PORTD_WIDTH, portd_channel_map);
#endif
#if (KINETIS_EXT_PORTE_WIDTH > 0)
irq_handler(PORTE, KINETIS_EXT_PORTE_WIDTH, porte_channel_map);
#endif
OSAL_IRQ_EPILOGUE();
}
#endif /* defined(KINETIS_PORTD_IRQ_VECTOR) */
#elif KINETIS_EXT_HAS_COMMON_CD_IRQ /* KINETIS_EXT_HAS_COMMON_BCDE_IRQ */
#if defined(KINETIS_PORTD_IRQ_VECTOR)
OSAL_IRQ_HANDLER(KINETIS_PORTD_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
#if (KINETIS_EXT_PORTC_WIDTH > 0)
irq_handler(PORTC, KINETIS_EXT_PORTC_WIDTH, portc_channel_map);
#endif
#if (KINETIS_EXT_PORTD_WIDTH > 0)
irq_handler(PORTD, KINETIS_EXT_PORTD_WIDTH, portd_channel_map);
#endif
OSAL_IRQ_EPILOGUE();
}
#endif /* defined(KINETIS_PORTD_IRQ_VECTOR) */
#else /* KINETIS_EXT_HAS_COMMON_CD_IRQ */
/**
* @brief PORTB interrupt handler.
*
@ -224,6 +295,8 @@ OSAL_IRQ_HANDLER(KINETIS_PORTE_IRQ_VECTOR) {
}
#endif /* KINETIS_EXT_PORTE_WIDTH > 0 */
#endif /* !KINETIS_EXT_HAS_COMMON_CD_IRQ */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/

View File

@ -30,11 +30,6 @@
/* Driver local definitions. */
/*===========================================================================*/
#define KINETIS_PIT0_HANDLER VectorB8
#define KINETIS_PIT1_HANDLER VectorBC
#define KINETIS_PIT2_HANDLER VectorC0
#define KINETIS_PIT3_HANDLER VectorC4
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
@ -75,6 +70,10 @@ GPTDriver GPTD4;
/* Driver local variables and types. */
/*===========================================================================*/
#if KINETIS_HAS_PIT_COMMON_IRQ
static uint8_t active_channels = 0;
#endif /* KINETIS_HAS_PIT_COMMON_IRQ */
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
@ -87,7 +86,7 @@ GPTDriver GPTD4;
static void gpt_lld_serve_interrupt(GPTDriver *gptp) {
/* Clear the interrupt */
gptp->channel->TFLG |= PIT_TCTRL_TIE;
gptp->channel->TFLG |= PIT_TFLGn_TIF;
if (gptp->state == GPT_ONESHOT) {
gptp->state = GPT_READY; /* Back in GPT_READY state. */
@ -100,82 +99,89 @@ static void gpt_lld_serve_interrupt(GPTDriver *gptp) {
/* Driver interrupt handlers. */
/*===========================================================================*/
#if !KINETIS_HAS_PIT_COMMON_IRQ
#if KINETIS_GPT_USE_PIT0
#if !defined(KINETIS_PIT0_HANDLER)
#error "KINETIS_PIT0_HANDLER not defined"
#endif
/**
* @brief PIT1 interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(KINETIS_PIT0_HANDLER) {
OSAL_IRQ_HANDLER(KINETIS_PIT0_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD1);
OSAL_IRQ_EPILOGUE();
}
#endif /* KINETIS_GPT_USE_PIT0 */
#if KINETIS_GPT_USE_PIT1
#if !defined(KINETIS_PIT1_HANDLER)
#error "KINETIS_PIT1_HANDLER not defined"
#endif
/**
* @brief PIT1 interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(KINETIS_PIT1_HANDLER) {
OSAL_IRQ_HANDLER(KINETIS_PIT1_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD2);
OSAL_IRQ_EPILOGUE();
}
#endif /* KINETIS_GPT_USE_PIT1 */
#if KINETIS_GPT_USE_PIT2
#if !defined(KINETIS_PIT2_HANDLER)
#error "KINETIS_PIT2_HANDLER not defined"
#endif
/**
* @brief PIT2 interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(KINETIS_PIT2_HANDLER) {
OSAL_IRQ_HANDLER(KINETIS_PIT2_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD3);
OSAL_IRQ_EPILOGUE();
}
#endif /* KINETIS_GPT_USE_PIT2 */
#if KINETIS_GPT_USE_PIT3
#if !defined(KINETIS_PIT3_HANDLER)
#error "KINETIS_PIT3_HANDLER not defined"
#endif
/**
* @brief PIT3 interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(KINETIS_PIT3_HANDLER) {
OSAL_IRQ_HANDLER(KINETIS_PIT3_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD4);
OSAL_IRQ_EPILOGUE();
}
#endif /* KINETIS_GPT_USE_PIT3 */
#else /* !KINETIS_HAS_PIT_COMMON_IRQ */
/**
* @brief Common PIT interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(KINETIS_PIT_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
#if KINETIS_GPT_USE_PIT0
if(GPTD1.channel->TFLG & PIT_TFLGn_TIF)
gpt_lld_serve_interrupt(&GPTD1);
#endif /* KINETIS_GPT_USE_PIT0 */
#if KINETIS_GPT_USE_PIT1
if(GPTD2.channel->TFLG & PIT_TFLGn_TIF)
gpt_lld_serve_interrupt(&GPTD2);
#endif /* KINETIS_GPT_USE_PIT1 */
#if KINETIS_GPT_USE_PIT2
if(GPTD3.channel->TFLG & PIT_TFLGn_TIF)
gpt_lld_serve_interrupt(&GPTD3);
#endif /* KINETIS_GPT_USE_PIT2 */
#if KINETIS_GPT_USE_PIT3
if(GPTD4.channel->TFLG & PIT_TFLGn_TIF)
gpt_lld_serve_interrupt(&GPTD4);
#endif /* KINETIS_GPT_USE_PIT3 */
OSAL_IRQ_EPILOGUE();
}
#endif /* !KINETIS_HAS_PIT_COMMON_IRQ */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
@ -227,6 +233,8 @@ void gpt_lld_start(GPTDriver *gptp) {
SIM->SCGC6 |= SIM_SCGC6_PIT;
gptp->clock = KINETIS_SYSCLK_FREQUENCY;
#if !KINETIS_HAS_PIT_COMMON_IRQ
#if KINETIS_GPT_USE_PIT0
if (&GPTD1 == gptp) {
nvicEnableVector(PITChannel0_IRQn, KINETIS_GPT_PIT0_IRQ_PRIORITY);
@ -248,6 +256,10 @@ void gpt_lld_start(GPTDriver *gptp) {
}
#endif
#else /* !KINETIS_HAS_PIT_COMMON_IRQ */
nvicEnableVector(PIT_IRQn, KINETIS_GPT_PIT_IRQ_PRIORITY);
active_channels++;
#endif /* !KINETIS_HAS_PIT_COMMON_IRQ */
}
/* Prescaler value calculation.*/
@ -275,7 +287,9 @@ void gpt_lld_stop(GPTDriver *gptp) {
gptp->channel->TCTRL = 0;
/* Clear pending interrupts */
gptp->channel->TFLG |= PIT_TFLG_TIF;
gptp->channel->TFLG |= PIT_TFLGn_TIF;
#if !KINETIS_HAS_PIT_COMMON_IRQ
#if KINETIS_GPT_USE_PIT0
if (&GPTD1 == gptp) {
@ -297,6 +311,11 @@ void gpt_lld_stop(GPTDriver *gptp) {
nvicDisableVector(PITChannel3_IRQn);
}
#endif
#else /* !KINETIS_HAS_PIT_COMMON_IRQ */
if(--active_channels == 0)
nvicDisableVector(PIT_IRQn);
#endif /* !KINETIS_HAS_PIT_COMMON_IRQ */
}
}
@ -311,13 +330,13 @@ void gpt_lld_stop(GPTDriver *gptp) {
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t interval) {
/* Clear pending interrupts */
gptp->channel->TFLG |= PIT_TFLG_TIF;
gptp->channel->TFLG |= PIT_TFLGn_TIF;
/* Set the interval */
gptp->channel->LDVAL = (gptp->clock / gptp->config->frequency) * interval;
gpt_lld_change_interval(gptp, interval);
/* Start the timer */
gptp->channel->TCTRL |= PIT_TCTRL_TIE | PIT_TCTRL_TEN;
gptp->channel->TCTRL |= PIT_TCTRLn_TIE | PIT_TCTRLn_TEN;
}
/**
@ -351,16 +370,16 @@ void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval) {
channel->TCTRL = 0;
/* Clear the interrupt flag */
channel->TFLG |= PIT_TFLG_TIF;
channel->TFLG |= PIT_TFLGn_TIF;
/* Set the interval */
channel->LDVAL = (gptp->clock / gptp->config->frequency) * interval;
/* Enable Timer but keep interrupts disabled */
channel->TCTRL = PIT_TCTRL_TEN;
channel->TCTRL = PIT_TCTRLn_TEN;
/* Wait for the interrupt flag to be set */
while (!(channel->TFLG & PIT_TFLG_TIF))
while (!(channel->TFLG & PIT_TFLGn_TIF))
;
/* Disable timer and disable interrupts */

View File

@ -103,6 +103,14 @@
#define KINETIS_GPT_PIT3_IRQ_PRIORITY 7
#endif
/**
* @brief GPTD* common interrupt priority level setting.
*/
#if (KINETIS_HAS_PIT_COMMON_IRQ && !defined(KINETIS_GPT_PIT_IRQ_PRIORITY)) \
|| defined(__DOXYGEN__)
#define KINETIS_GPT_PIT_IRQ_PRIORITY 2
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
@ -123,31 +131,60 @@
#error "PIT3 not present in the selected device"
#endif
#if !KINETIS_GPT_USE_PIT0 && !KINETIS_GPT_USE_PIT1 && \
#if !KINETIS_GPT_USE_PIT0 && !KINETIS_GPT_USE_PIT1 && \
!KINETIS_GPT_USE_PIT2 && !KINETIS_GPT_USE_PIT3
#error "GPT driver activated but no PIT peripheral assigned"
#endif
#if KINETIS_GPT_USE_PIT0 && \
#if KINETIS_GPT_USE_PIT0 && !KINETIS_HAS_PIT_COMMON_IRQ && \
!OSAL_IRQ_IS_VALID_PRIORITY(KINETIS_GPT_PIT0_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to PIT0"
#endif
#if KINETIS_GPT_USE_PIT1 && \
#if KINETIS_GPT_USE_PIT1 && !KINETIS_HAS_PIT_COMMON_IRQ && \
!OSAL_IRQ_IS_VALID_PRIORITY(KINETIS_GPT_PIT1_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to PIT1"
#endif
#if KINETIS_GPT_USE_PIT2 && \
#if KINETIS_GPT_USE_PIT2 && !KINETIS_HAS_PIT_COMMON_IRQ && \
!OSAL_IRQ_IS_VALID_PRIORITY(KINETIS_GPT_PIT2_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to PIT2"
#endif
#if KINETIS_GPT_USE_PIT3 && \
#if KINETIS_GPT_USE_PIT3 && !KINETIS_HAS_PIT_COMMON_IRQ && \
!OSAL_IRQ_IS_VALID_PRIORITY(KINETIS_GPT_PIT3_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to PIT3"
#endif
#if KINETIS_HAS_PIT_COMMON_IRQ && \
!OSAL_IRQ_IS_VALID_PRIORITY(KINETIS_GPT_PIT_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to PIT"
#endif
#if KINETIS_GPT_USE_PIT0 && !defined(KINETIS_PIT0_IRQ_VECTOR) && \
!KINETIS_HAS_PIT_COMMON_IRQ
#error "KINETIS_PIT0_IRQ_VECTOR not defined"
#endif
#if KINETIS_GPT_USE_PIT1 && !defined(KINETIS_PIT1_IRQ_VECTOR) && \
!KINETIS_HAS_PIT_COMMON_IRQ
#error "KINETIS_PIT1_IRQ_VECTOR not defined"
#endif
#if KINETIS_GPT_USE_PIT2 && !defined(KINETIS_PIT2_IRQ_VECTOR) && \
!KINETIS_HAS_PIT_COMMON_IRQ
#error "KINETIS_PIT2_IRQ_VECTOR not defined"
#endif
#if KINETIS_GPT_USE_PIT3 && !defined(KINETIS_PIT3_IRQ_VECTOR) && \
!KINETIS_HAS_PIT_COMMON_IRQ
#error "KINETIS_PIT3_IRQ_VECTOR not defined"
#endif
#if KINETIS_HAS_PIT_COMMON_IRQ && !defined(KINETIS_PIT_IRQ_VECTOR)
#error "KINETIS_PIT_IRQ_VECTOR not defined"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
@ -226,7 +263,9 @@ struct GPTDriver {
* @notapi
*/
#define gpt_lld_change_interval(gptp, interval) \
((gptp)->channel->LDVAL = (uint32_t)((interval)))
((gptp)->channel->LDVAL = (uint32_t)( \
( (gptp)->clock / (gptp)->config->frequency ) * \
( interval ) ))
/**
* @brief Returns the interval of GPT peripheral.
@ -237,7 +276,9 @@ struct GPTDriver {
*
* @notapi
*/
#define gpt_lld_get_interval(gptp) ((gptcnt_t)(gptp)->pit->CHANNEL[gptp->channel].LDVAL)
#define gpt_lld_get_interval(gptp) \
((uint32_t)( ( (uint64_t)(gptp)->channel->LDVAL * (gptp)->config->frequency ) / \
( (uint32_t)(gptp)->clock ) ))
/**
* @brief Returns the counter value of GPT peripheral.

View File

@ -15,7 +15,7 @@
*/
/**
* @file KINETIS/i2c_lld.c
* @file KINETIS/LLD/i2c_lld.c
* @brief KINETIS I2C subsystem low level driver source.
*
* @addtogroup I2C
@ -191,8 +191,7 @@ OSAL_IRQ_HANDLER(KINETIS_I2C0_IRQ_VECTOR) {
#if KINETIS_I2C_USE_I2C1 || defined(__DOXYGEN__)
/* FIXME: KL2x has I2C1 on Vector64; K2x don't have I2C1! */
OSAL_IRQ_HANDLER(Vector64) {
OSAL_IRQ_HANDLER(KINETIS_I2C1_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
serve_interrupt(&I2CD2);

View File

@ -15,7 +15,7 @@
*/
/**
* @file KINETIS/i2c_lld.h
* @file KINETIS/LLD/i2c_lld.h
* @brief KINETIS I2C subsystem low level driver header.
*
* @addtogroup I2C
@ -63,10 +63,38 @@
#endif
/** @} */
/**
* @brief I2C0 interrupt priority level setting.
*/
#if !defined(KINETIS_I2C_I2C0_PRIORITY) || defined(__DOXYGEN__)
#define KINETIS_I2C_I2C0_PRIORITY 12
#endif
/**
* @brief I2C1 interrupt priority level setting.
*/
#if !defined(KINETIS_I2C_I2C1_PRIORITY) || defined(__DOXYGEN__)
#define KINETIS_I2C_I2C1_PRIORITY 12
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/** @brief error checks */
#if KINETIS_I2C_USE_I2C0 && !KINETIS_HAS_I2C0
#error "I2C0 not present in the selected device"
#endif
#if KINETIS_I2C_USE_I2C1 && !KINETIS_HAS_I2C1
#error "I2C1 not present in the selected device"
#endif
#if !(KINETIS_I2C_USE_I2C0 || KINETIS_I2C_USE_I2C1)
#error "I2C driver activated but no I2C peripheral assigned"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/

View File

@ -15,7 +15,7 @@
*/
/**
* @file MK20D5/pal_lld.c
* @file KINETIS/LLD/pal_lld.c
* @brief PAL subsystem low level driver.
*
* @addtogroup PAL
@ -108,7 +108,7 @@ void _pal_lld_setpadmode(ioportid_t port,
PORT_TypeDef *portcfg = NULL;
chDbgAssert(pad <= 31, "pal_lld_setpadmode() #1, invalid pad");
chDbgAssert(pad < PADS_PER_PORT, "pal_lld_setpadmode() #1, invalid pad");
if (mode == PAL_MODE_OUTPUT_PUSHPULL)
port->PDDR |= ((uint32_t) 1 << pad);
@ -134,10 +134,14 @@ void _pal_lld_setpadmode(ioportid_t port,
case PAL_MODE_OUTPUT_PUSHPULL:
portcfg->PCR[pad] = PIN_MUX_ALTERNATIVE(1);
break;
#if KINETIS_GPIO_HAS_OPENDRAIN
case PAL_MODE_OUTPUT_OPENDRAIN:
portcfg->PCR[pad] = PIN_MUX_ALTERNATIVE(1) |
PORTx_PCRn_ODE;
break;
#else
#undef PAL_MODE_OUTPUT_OPENDRAIN
#endif
case PAL_MODE_INPUT_PULLUP:
portcfg->PCR[pad] = PIN_MUX_ALTERNATIVE(1) |
PORTx_PCRn_PE |

View File

@ -15,7 +15,7 @@
*/
/**
* @file MK20D5/pal_lld.h
* @file KINETIS/LLD/pal_lld.h
* @brief PAL subsystem low level driver header.
*
* @addtogroup PAL
@ -31,13 +31,13 @@
/* Unsupported modes and specific modes */
/*===========================================================================*/
#define PAL_MODE_ALTERNATIVE_1 10
#define PAL_MODE_ALTERNATIVE_2 11
#define PAL_MODE_ALTERNATIVE_3 12
#define PAL_MODE_ALTERNATIVE_4 13
#define PAL_MODE_ALTERNATIVE_5 14
#define PAL_MODE_ALTERNATIVE_6 15
#define PAL_MODE_ALTERNATIVE_7 16
#define PAL_MODE_ALTERNATIVE_1 0x10
#define PAL_MODE_ALTERNATIVE_2 0x11
#define PAL_MODE_ALTERNATIVE_3 0x12
#define PAL_MODE_ALTERNATIVE_4 0x13
#define PAL_MODE_ALTERNATIVE_5 0x14
#define PAL_MODE_ALTERNATIVE_6 0x15
#define PAL_MODE_ALTERNATIVE_7 0x16
#define PIN_MUX_ALTERNATIVE(x) PORTx_PCRn_MUX(x)
@ -151,7 +151,8 @@ typedef struct {
*
* @notapi
*/
#define pal_lld_readport(port) (port)->PDIR
#define pal_lld_readport(port) \
(port)->PDIR
/**
* @brief Reads the output latch.
@ -163,7 +164,8 @@ typedef struct {
*
* @notapi
*/
#define pal_lld_readlatch(port) (port)->PDOR
#define pal_lld_readlatch(port) \
(port)->PDOR
/**
* @brief Writes a bits mask on a I/O port.
@ -173,7 +175,8 @@ typedef struct {
*
* @notapi
*/
#define pal_lld_writeport(port, bits) (port)->PDOR = (bits)
#define pal_lld_writeport(port, bits) \
(port)->PDOR = (bits)
/**
* @brief Sets a bits mask on a I/O port.
@ -186,7 +189,8 @@ typedef struct {
*
* @notapi
*/
#define pal_lld_setport(port, bits) (port)->PSOR = (bits)
#define pal_lld_setport(port, bits) \
(port)->PSOR = (bits)
/**
* @brief Clears a bits mask on a I/O port.
@ -199,7 +203,8 @@ typedef struct {
*
* @notapi
*/
#define pal_lld_clearport(port, bits) (port)->PCOR = (bits)
#define pal_lld_clearport(port, bits) \
(port)->PCOR = (bits)
/**
* @brief Toggles a bits mask on a I/O port.
@ -212,7 +217,8 @@ typedef struct {
*
* @notapi
*/
#define pal_lld_toggleport(port, bits) (port)->PTOR = (bits)
#define pal_lld_toggleport(port, bits) \
(port)->PTOR = (bits)
/**
* @brief Reads a group of bits.
@ -364,6 +370,11 @@ extern "C" {
void _pal_lld_setpadmode(ioportid_t port,
uint8_t pad,
iomode_t mode);
uint8_t _pal_lld_readpad(ioportid_t port,
uint8_t pad);
void _pal_lld_writepad(ioportid_t port,
uint8_t pad,
uint8_t bit);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,583 @@
/*
ChibiOS - Copyright (C) 2013-2015 Fabio Utzig
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file KL2x/serial_lld.c
* @brief Kinetis KL2x Serial Driver subsystem low level driver source.
*
* @addtogroup SERIAL
* @{
*/
#include "osal.h"
#include "hal.h"
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief SD1 driver identifier.
*/
#if KINETIS_SERIAL_USE_UART0 || defined(__DOXYGEN__)
SerialDriver SD1;
#endif
#if KINETIS_SERIAL_USE_UART1 || defined(__DOXYGEN__)
SerialDriver SD2;
#endif
#if KINETIS_SERIAL_USE_UART2 || defined(__DOXYGEN__)
SerialDriver SD3;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/**
* @brief Driver default configuration.
*/
static const SerialConfig default_config = {
38400
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Error handling routine.
*
* @param[in] sdp pointer to a @p SerialDriver object
* @param[in] isr UART s1 register value
*/
static void set_error(SerialDriver *sdp, uint8_t s1) {
eventflags_t sts = 0;
if (s1 & UARTx_S1_OR)
sts |= SD_OVERRUN_ERROR;
if (s1 & UARTx_S1_PF)
sts |= SD_PARITY_ERROR;
if (s1 & UARTx_S1_FE)
sts |= SD_FRAMING_ERROR;
if (s1 & UARTx_S1_NF)
sts |= SD_NOISE_ERROR;
osalSysLockFromISR();
chnAddFlagsI(sdp, sts);
osalSysUnlockFromISR();
}
/**
* @brief Common error IRQ handler.
*
* @param[in] sdp communication channel associated to the UART
*/
static void serve_error_interrupt(SerialDriver *sdp) {
UART_w_TypeDef *u = &(sdp->uart);
uint8_t s1 = *(u->s1_p);
/* S1 bits are write-1-to-clear for UART0 on KL2x. */
/* Clearing on K20x and KL2x/UART>0 is done by reading S1 and
* then reading D.*/
#if defined(KL2x) && KINETIS_SERIAL_USE_UART0
if(sdp == &SD1) {
if(s1 & UARTx_S1_IDLE) {
*(u->s1_p) |= UARTx_S1_IDLE;
}
if(s1 & (UARTx_S1_OR | UARTx_S1_NF | UARTx_S1_FE | UARTx_S1_PF)) {
set_error(sdp, s1);
*(u->s1_p) |= UARTx_S1_OR | UARTx_S1_NF | UARTx_S1_FE | UARTx_S1_PF;
}
return;
}
#endif /* KL2x && KINETIS_SERIAL_USE_UART0 */
if(s1 & UARTx_S1_IDLE) {
(void)*(u->d_p);
}
if(s1 & (UARTx_S1_OR | UARTx_S1_NF | UARTx_S1_FE | UARTx_S1_PF)) {
set_error(sdp, s1);
(void)*(u->d_p);
}
}
/**
* @brief Common IRQ handler.
* @note Tries hard to clear all the pending interrupt sources, we don't
* want to go through the whole ISR and have another interrupt soon
* after.
*
* @param[in] sdp communication channel associated to the UART
*/
static void serve_interrupt(SerialDriver *sdp) {
UART_w_TypeDef *u = &(sdp->uart);
uint8_t s1 = *(u->s1_p);
if (s1 & UARTx_S1_RDRF) {
osalSysLockFromISR();
if (iqIsEmptyI(&sdp->iqueue))
chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE);
if (iqPutI(&sdp->iqueue, *(u->d_p)) < Q_OK)
chnAddFlagsI(sdp, SD_OVERRUN_ERROR);
osalSysUnlockFromISR();
}
if (s1 & UARTx_S1_TDRE) {
msg_t b;
osalSysLockFromISR();
b = oqGetI(&sdp->oqueue);
osalSysUnlockFromISR();
if (b < Q_OK) {
osalSysLockFromISR();
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
osalSysUnlockFromISR();
*(u->c2_p) &= ~UARTx_C2_TIE;
} else {
*(u->d_p) = b;
}
}
serve_error_interrupt(sdp);
}
/**
* @brief Attempts a TX preload
*/
static void preload(SerialDriver *sdp) {
UART_w_TypeDef *u = &(sdp->uart);
if (*(u->s1_p) & UARTx_S1_TDRE) {
msg_t b = oqGetI(&sdp->oqueue);
if (b < Q_OK) {
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
return;
}
*(u->d_p) = b;
*(u->c2_p) |= UARTx_C2_TIE;
}
}
/**
* @brief Driver output notification.
*/
#if KINETIS_SERIAL_USE_UART0 || defined(__DOXYGEN__)
static void notify1(io_queue_t *qp)
{
(void)qp;
preload(&SD1);
}
#endif
#if KINETIS_SERIAL_USE_UART1 || defined(__DOXYGEN__)
static void notify2(io_queue_t *qp)
{
(void)qp;
preload(&SD2);
}
#endif
#if KINETIS_SERIAL_USE_UART2 || defined(__DOXYGEN__)
static void notify3(io_queue_t *qp)
{
(void)qp;
preload(&SD3);
}
#endif
/**
* @brief Common UART configuration.
*
*/
static void configure_uart(SerialDriver *sdp, const SerialConfig *config) {
UART_w_TypeDef *uart = &(sdp->uart);
uint32_t divisor;
/* Discard any incoming data. */
while (*(uart->s1_p) & UARTx_S1_RDRF) {
(void)*(uart->d_p);
}
/* Disable UART while configuring */
*(uart->c2_p) &= ~(UARTx_C2_RE | UARTx_C2_TE);
/* The clock sources for various UARTs can be different. */
divisor=KINETIS_BUSCLK_FREQUENCY;
#if defined(KL2x)
#if KINETIS_SERIAL_USE_UART0
if (sdp == &SD1) {
/* UART0 can be clocked from several sources on KL2x. */
divisor = KINETIS_UART0_CLOCK_FREQ;
/* FIXME: change fixed OSR = 16 to dynamic value based on baud */
/* Note: OSR only works on KL2x/UART0; further UARTs have fixed 16. */
*(uart->c4_p) = UARTx_C4_OSR(16 - 1);
}
#endif /* KINETIS_SERIAL_USE_UART0 */
#elif defined(K20x) /* KL2x */
/* UARTs 0 and 1 are clocked from SYSCLK, others from BUSCLK on K20x. */
#if KINETIS_SERIAL_USE_UART0
if(sdp == &SD1)
divisor = KINETIS_SYSCLK_FREQUENCY;
#endif /* KINETIS_SERIAL_USE_UART0 */
#if KINETIS_SERIAL_USE_UART1
if(sdp == &SD2)
divisor = KINETIS_SYSCLK_FREQUENCY;
#endif /* KINETIS_SERIAL_USE_UART1 */
#else /* K20x */
#error Baud rate selection not implemented for this MCU type
#endif /* K20x */
divisor = (divisor * 2 + 1) / config->sc_speed;
*(uart->bdh_p) = UARTx_BDH_SBR(divisor >> 13) | (*(uart->bdh_p) & ~UARTx_BDH_SBR_MASK);
*(uart->bdl_p) = UARTx_BDL_SBR(divisor >> 5);
#if defined(K20x)
*(uart->c4_p) = UARTx_C4_BRFA(divisor) | (*(uart->c4_p) & ~UARTx_C4_BRFA_MASK);
#endif /* K20x */
/* Line settings. */
*(uart->c1_p) = 0;
/* Enable error event interrupts (overrun, noise, framing, parity) */
*(uart->c3_p) = UARTx_C3_ORIE | UARTx_C3_NEIE | UARTx_C3_FEIE | UARTx_C3_PEIE;
/* Enable the peripheral; including receive interrupts. */
*(uart->c2_p) |= UARTx_C2_RE | UARTx_C2_RIE | UARTx_C2_TE;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if KINETIS_SERIAL_USE_UART0 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(KINETIS_SERIAL0_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
serve_interrupt(&SD1);
OSAL_IRQ_EPILOGUE();
}
#endif
#if KINETIS_SERIAL_USE_UART1 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(KINETIS_SERIAL1_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
serve_interrupt(&SD2);
OSAL_IRQ_EPILOGUE();
}
#endif
#if KINETIS_SERIAL_USE_UART2 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(KINETIS_SERIAL2_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
serve_interrupt(&SD3);
OSAL_IRQ_EPILOGUE();
}
#endif
#if KINETIS_HAS_SERIAL_ERROR_IRQ
#if KINETIS_SERIAL_USE_UART0 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(KINETIS_SERIAL0_ERROR_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
serve_error_interrupt(&SD1);
OSAL_IRQ_EPILOGUE();
}
#endif
#if KINETIS_SERIAL_USE_UART1 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(KINETIS_SERIAL1_ERROR_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
serve_error_interrupt(&SD2);
OSAL_IRQ_EPILOGUE();
}
#endif
#if KINETIS_SERIAL_USE_UART2 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(KINETIS_SERIAL2_ERROR_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
serve_error_interrupt(&SD3);
OSAL_IRQ_EPILOGUE();
}
#endif
#endif /* KINETIS_HAS_SERIAL_ERROR_IRQ */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level serial driver initialization.
*
* @notapi
*/
void sd_lld_init(void) {
#if KINETIS_SERIAL_USE_UART0
/* Driver initialization.*/
sdObjectInit(&SD1, NULL, notify1);
#if ! KINETIS_SERIAL0_IS_LPUART
SD1.uart.bdh_p = &(UART0->BDH);
SD1.uart.bdl_p = &(UART0->BDL);
SD1.uart.c1_p = &(UART0->C1);
SD1.uart.c2_p = &(UART0->C2);
SD1.uart.c3_p = &(UART0->C3);
SD1.uart.c4_p = &(UART0->C4);
SD1.uart.s1_p = (volatile uint8_t *)&(UART0->S1);
SD1.uart.s2_p = &(UART0->S2);
SD1.uart.d_p = &(UART0->D);
#else /* ! KINETIS_SERIAL0_IS_LPUART */
/* little endian! */
SD1.uart.bdh_p = ((uint8_t *)&(LPUART0->BAUD)) + 1; /* BDH: BAUD, byte 3 */
SD1.uart.bdl_p = ((uint8_t *)&(LPUART0->BAUD)) + 0; /* BDL: BAUD, byte 4 */
SD1.uart.c1_p = ((uint8_t *)&(LPUART0->CTRL)) + 0; /* C1: CTRL, byte 4 */
SD1.uart.c2_p = ((uint8_t *)&(LPUART0->CTRL)) + 2; /* C2: CTRL, byte 2 */
SD1.uart.c3_p = ((uint8_t *)&(LPUART0->CTRL)) + 3; /* C3: CTRL, byte 1 */
SD1.uart.c4_p = ((uint8_t *)&(LPUART0->BAUD)) + 3; /* C4: BAUD, byte 1 */
SD1.uart.s1_p = ((uint8_t *)&(LPUART0->STAT)) + 2; /* S1: STAT, byte 2 */
SD1.uart.s2_p = ((uint8_t *)&(LPUART0->STAT)) + 3; /* S2: STAT, byte 1 */
SD1.uart.d_p = ((uint8_t *)&(LPUART0->DATA)) + 0; /* D: DATA, byte 4 */
#endif /* ! KINETIS_SERIAL0_IS_LPUART */
#if KINETIS_SERIAL0_IS_UARTLP
SD1.uart.uartlp_p = UART0;
SD1.uart.uart_p = NULL;
#elif KINETIS_SERIAL0_IS_LPUART
SD1.uart.lpuart_p = LPUART0;
SD1.uart.uart_p = NULL;
#else /* KINETIS_SERIAL0_IS_LPUART */
SD1.uart.uart_p = UART0;
#endif /* KINETIS_SERIAL0_IS_LPUART */
#endif /* KINETIS_SERIAL_USE_UART0 */
#if KINETIS_SERIAL_USE_UART1
/* Driver initialization.*/
sdObjectInit(&SD2, NULL, notify2);
#if ! KINETIS_SERIAL1_IS_LPUART
SD2.uart.bdh_p = &(UART1->BDH);
SD2.uart.bdl_p = &(UART1->BDL);
SD2.uart.c1_p = &(UART1->C1);
SD2.uart.c2_p = &(UART1->C2);
SD2.uart.c3_p = &(UART1->C3);
SD2.uart.c4_p = &(UART1->C4);
SD2.uart.s1_p = (volatile uint8_t *)&(UART1->S1);
SD2.uart.s2_p = &(UART1->S2);
SD2.uart.d_p = &(UART1->D);
SD2.uart.uart_p = UART1;
#else /* ! KINETIS_SERIAL1_IS_LPUART */
/* little endian! */
SD2.uart.bdh_p = ((uint8_t *)&(LPUART1->BAUD)) + 1; /* BDH: BAUD, byte 3 */
SD2.uart.bdl_p = ((uint8_t *)&(LPUART1->BAUD)) + 0; /* BDL: BAUD, byte 4 */
SD2.uart.c1_p = ((uint8_t *)&(LPUART1->CTRL)) + 0; /* C1: CTRL, byte 4 */
SD2.uart.c2_p = ((uint8_t *)&(LPUART1->CTRL)) + 2; /* C2: CTRL, byte 2 */
SD2.uart.c3_p = ((uint8_t *)&(LPUART1->CTRL)) + 3; /* C3: CTRL, byte 1 */
SD2.uart.c4_p = ((uint8_t *)&(LPUART1->BAUD)) + 3; /* C4: BAUD, byte 1 */
SD2.uart.s1_p = ((uint8_t *)&(LPUART1->STAT)) + 2; /* S1: STAT, byte 2 */
SD2.uart.s2_p = ((uint8_t *)&(LPUART1->STAT)) + 3; /* S2: STAT, byte 1 */
SD2.uart.d_p = ((uint8_t *)&(LPUART1->DATA)) + 0; /* D: DATA, byte 4 */
SD2.uart.lpuart_p = LPUART1;
SD2.uart.uart_p = NULL;
#endif /* ! KINETIS_SERIAL1_IS_LPUART */
#endif /* KINETIS_SERIAL_USE_UART1 */
#if KINETIS_SERIAL_USE_UART2
/* Driver initialization.*/
sdObjectInit(&SD3, NULL, notify3);
SD3.uart.bdh_p = &(UART2->BDH);
SD3.uart.bdl_p = &(UART2->BDL);
SD3.uart.c1_p = &(UART2->C1);
SD3.uart.c2_p = &(UART2->C2);
SD3.uart.c3_p = &(UART2->C3);
SD3.uart.c4_p = &(UART2->C4);
SD3.uart.s1_p = (volatile uint8_t *)&(UART2->S1);
SD3.uart.s2_p = &(UART2->S2);
SD3.uart.d_p = &(UART2->D);
SD3.uart.uart_p = UART2;
#endif /* KINETIS_SERIAL_USE_UART2 */
}
/**
* @brief Low level serial driver configuration and (re)start.
*
* @param[in] sdp pointer to a @p SerialDriver object
* @param[in] config the architecture-dependent serial driver configuration.
* If this parameter is set to @p NULL then a default
* configuration is used.
*
* @notapi
*/
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
if (config == NULL)
config = &default_config;
if (sdp->state == SD_STOP) {
/* Enables the peripheral.*/
#if KINETIS_SERIAL_USE_UART0
if (sdp == &SD1) {
#if KINETIS_SERIAL0_IS_LPUART
SIM->SCGC5 |= SIM_SCGC5_LPUART0;
SIM->SOPT2 =
(SIM->SOPT2 & ~SIM_SOPT2_LPUART0SRC_MASK) |
SIM_SOPT2_LPUART0SRC(KINETIS_UART0_CLOCK_SRC);
#else /* KINETIS_SERIAL0_IS_LPUART */
SIM->SCGC4 |= SIM_SCGC4_UART0;
#endif /* KINETIS_SERIAL0_IS_LPUART */
#if KINETIS_SERIAL0_IS_UARTLP
SIM->SOPT2 =
(SIM->SOPT2 & ~SIM_SOPT2_UART0SRC_MASK) |
SIM_SOPT2_UART0SRC(KINETIS_UART0_CLOCK_SRC);
#endif /* KINETIS_SERIAL0_IS_UARTLP */
configure_uart(sdp, config);
#if KINETIS_HAS_SERIAL_ERROR_IRQ
nvicEnableVector(UART0Status_IRQn, KINETIS_SERIAL_UART0_PRIORITY);
nvicEnableVector(UART0Error_IRQn, KINETIS_SERIAL_UART0_PRIORITY);
#else /* KINETIS_HAS_SERIAL_ERROR_IRQ */
#if KINETIS_SERIAL0_IS_LPUART
nvicEnableVector(LPUART0_IRQn, KINETIS_SERIAL_UART0_PRIORITY);
#else /* KINETIS_SERIAL0_IS_LPUART */
nvicEnableVector(UART0_IRQn, KINETIS_SERIAL_UART0_PRIORITY);
#endif /* KINETIS_SERIAL0_IS_LPUART */
#endif /* KINETIS_HAS_SERIAL_ERROR_IRQ */
}
#endif /* KINETIS_SERIAL_USE_UART0 */
#if KINETIS_SERIAL_USE_UART1
if (sdp == &SD2) {
#if KINETIS_SERIAL1_IS_LPUART
SIM->SCGC5 |= SIM_SCGC5_LPUART1;
SIM->SOPT2 =
(SIM->SOPT2 & ~SIM_SOPT2_LPUART1SRC_MASK) |
SIM_SOPT2_LPUART1SRC(KINETIS_UART1_CLOCK_SRC);
#else /* KINETIS_SERIAL1_IS_LPUART */
SIM->SCGC4 |= SIM_SCGC4_UART1;
#endif /* KINETIS_SERIAL1_IS_LPUART */
configure_uart(sdp, config);
#if KINETIS_HAS_SERIAL_ERROR_IRQ
nvicEnableVector(UART1Status_IRQn, KINETIS_SERIAL_UART1_PRIORITY);
nvicEnableVector(UART1Error_IRQn, KINETIS_SERIAL_UART0_PRIORITY);
#else /* KINETIS_HAS_SERIAL_ERROR_IRQ */
#if KINETIS_SERIAL1_IS_LPUART
nvicEnableVector(LPUART1_IRQn, KINETIS_SERIAL_UART1_PRIORITY);
#else /* KINETIS_SERIAL1_IS_LPUART */
nvicEnableVector(UART1_IRQn, KINETIS_SERIAL_UART1_PRIORITY);
#endif /* KINETIS_SERIAL1_IS_LPUART */
#endif /* KINETIS_HAS_SERIAL_ERROR_IRQ */
}
#endif /* KINETIS_SERIAL_USE_UART1 */
#if KINETIS_SERIAL_USE_UART2
if (sdp == &SD3) {
SIM->SCGC4 |= SIM_SCGC4_UART2;
configure_uart(sdp, config);
#if KINETIS_HAS_SERIAL_ERROR_IRQ
nvicEnableVector(UART2Status_IRQn, KINETIS_SERIAL_UART2_PRIORITY);
nvicEnableVector(UART2Error_IRQn, KINETIS_SERIAL_UART0_PRIORITY);
#else /* KINETIS_HAS_SERIAL_ERROR_IRQ */
nvicEnableVector(UART2_IRQn, KINETIS_SERIAL_UART2_PRIORITY);
#endif /* KINETIS_HAS_SERIAL_ERROR_IRQ */
}
#endif /* KINETIS_SERIAL_USE_UART2 */
}
/* Configures the peripheral.*/
}
/**
* @brief Low level serial driver stop.
* @details De-initializes the USART, stops the associated clock, resets the
* interrupt vector.
*
* @param[in] sdp pointer to a @p SerialDriver object
*
* @notapi
*/
void sd_lld_stop(SerialDriver *sdp) {
if (sdp->state == SD_READY) {
/* TODO: Resets the peripheral.*/
#if KINETIS_SERIAL_USE_UART0
if (sdp == &SD1) {
#if KINETIS_HAS_SERIAL_ERROR_IRQ
nvicDisableVector(UART0Status_IRQn);
nvicDisableVector(UART0Error_IRQn);
#else /* KINETIS_HAS_SERIAL_ERROR_IRQ */
#if KINETIS_SERIAL0_IS_LPUART
nvicDisableVector(LPUART0_IRQn);
#else /* KINETIS_SERIAL0_IS_LPUART */
nvicDisableVector(UART0_IRQn);
#endif /* KINETIS_SERIAL0_IS_LPUART */
#endif /* KINETIS_HAS_SERIAL_ERROR_IRQ */
#if KINETIS_SERIAL0_IS_LPUART
SIM->SCGC5 &= ~SIM_SCGC5_LPUART0;
#else /* KINETIS_SERIAL0_IS_LPUART */
SIM->SCGC4 &= ~SIM_SCGC4_UART0;
#endif /* KINETIS_SERIAL0_IS_LPUART */
}
#endif
#if KINETIS_SERIAL_USE_UART1
if (sdp == &SD2) {
#if KINETIS_HAS_SERIAL_ERROR_IRQ
nvicDisableVector(UART1Status_IRQn);
nvicDisableVector(UART1Error_IRQn);
#else /* KINETIS_HAS_SERIAL_ERROR_IRQ */
#if KINETIS_SERIAL1_IS_LPUART
nvicDisableVector(LPUART1_IRQn);
#else /* KINETIS_SERIAL1_IS_LPUART */
nvicDisableVector(UART1_IRQn);
#endif /* KINETIS_SERIAL1_IS_LPUART */
#endif /* KINETIS_HAS_SERIAL_ERROR_IRQ */
#if KINETIS_SERIAL1_IS_LPUART
SIM->SCGC5 &= ~SIM_SCGC5_LPUART1;
#else /* KINETIS_SERIAL1_IS_LPUART */
SIM->SCGC4 &= ~SIM_SCGC4_UART1;
#endif /* KINETIS_SERIAL1_IS_LPUART */
}
#endif
#if KINETIS_SERIAL_USE_UART2
if (sdp == &SD3) {
#if KINETIS_HAS_SERIAL_ERROR_IRQ
nvicDisableVector(UART2Status_IRQn);
nvicDisableVector(UART2Error_IRQn);
#else /* KINETIS_HAS_SERIAL_ERROR_IRQ */
nvicDisableVector(UART2_IRQn);
#endif /* KINETIS_HAS_SERIAL_ERROR_IRQ */
SIM->SCGC4 &= ~SIM_SCGC4_UART2;
}
#endif
}
}
#endif /* HAL_USE_SERIAL */
/** @} */

View File

@ -82,12 +82,44 @@
#define KINETIS_SERIAL_UART2_PRIORITY 12
#endif
/**
* @brief UART0 clock source.
*/
#if !defined(KINETIS_UART0_CLOCK_SRC) || defined(__DOXYGEN__)
#define KINETIS_UART0_CLOCK_SRC 1 /* MCGFLLCLK clock, or MCGPLLCLK/2; or IRC48M */
#endif
/**
* @brief UART1 clock source.
*/
#if !defined(KINETIS_UART1_CLOCK_SRC) || defined(__DOXYGEN__)
#define KINETIS_UART1_CLOCK_SRC 1 /* IRC48M */
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/** @brief error checks */
#if KINETIS_SERIAL_USE_UART0 && !KINETIS_HAS_SERIAL0
#error "UART0 not present in the selected device"
#endif
#if KINETIS_SERIAL_USE_UART1 && !KINETIS_HAS_SERIAL1
#error "UART1 not present in the selected device"
#endif
#if KINETIS_SERIAL_USE_UART2 && !KINETIS_HAS_SERIAL2
#error "UART2 not present in the selected device"
#endif
#if !(KINETIS_SERIAL_USE_UART0 || KINETIS_SERIAL_USE_UART1 || \
KINETIS_SERIAL_USE_UART2)
#error "Serial driver activated but no UART peripheral assigned"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
@ -107,6 +139,31 @@ typedef struct {
/* End of the mandatory fields.*/
} SerialConfig;
/**
* @brief Generic UART register structure.
* @note Individual UART register blocks (even within the same chip) can differ.
*/
typedef struct {
volatile uint8_t* bdh_p;
volatile uint8_t* bdl_p;
volatile uint8_t* c1_p;
volatile uint8_t* c2_p;
volatile uint8_t* c3_p;
volatile uint8_t* c4_p;
volatile uint8_t* s1_p;
volatile uint8_t* s2_p;
volatile uint8_t* d_p;
UART_TypeDef *uart_p;
#if KINETIS_SERIAL_USE_UART0 && KINETIS_SERIAL0_IS_UARTLP
UARTLP_TypeDef *uartlp_p;
#endif /* KINETIS_SERIAL_USE_UART0 && KINETIS_SERIAL0_IS_UARTLP */
#if (KINETIS_SERIAL_USE_UART0 && KINETIS_SERIAL0_IS_LPUART) \
|| (KINETIS_SERIAL_USE_UART1 && KINETIS_SERIAL1_IS_LPUART)
LPUART_TypeDef *lpuart_p;
#endif /* KINETIS_SERIAL_USE_UART0 && KINETIS_SERIAL0_IS_LPUART */
} UART_w_TypeDef;
/**
* @brief @p SerialDriver specific data.
*/
@ -124,7 +181,7 @@ typedef struct {
uint8_t ob[SERIAL_BUFFERS_SIZE]; \
/* End of the mandatory fields.*/ \
/* Pointer to the UART registers block.*/ \
UARTLP_TypeDef *uart;
UART_w_TypeDef uart;
/*===========================================================================*/
/* Driver macros. */

View File

@ -15,7 +15,7 @@
*/
/**
* @file KINETIS/KL2x/st_lld.c
* @file KINETIS/LLD/st_lld.c
* @brief ST Driver subsystem low level driver code.
*
* @addtogroup ST

View File

@ -15,7 +15,7 @@
*/
/**
* @file KINETIS/st_lld.h
* @file KINETIS/LLD/st_lld.h
* @brief ST Driver subsystem low level driver header.
* @details This header is designed to be include-able without having to
* include other files from the HAL.

View File

@ -0,0 +1,832 @@
/*
ChibiOS - Copyright (C) 2015 RedoX https://github.com/RedoXyde/
(C) 2015-2016 flabbergast <s3+flabbergast@sdfeu.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file KINETIS/LLD/usb_lld.c
* @brief KINETIS USB subsystem low level driver source.
*
* @addtogroup USB
* @{
*/
#include <string.h>
#include "hal.h"
#if HAL_USE_USB || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/** @brief USB0 driver identifier.*/
#if KINETIS_USB_USE_USB0 || defined(__DOXYGEN__)
USBDriver USBD1;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/**
* @brief IN EP0 state.
*/
USBInEndpointState ep0in;
/**
* @brief OUT EP0 state.
*/
USBOutEndpointState ep0out;
/**
* @brief Buffer for the EP0 setup packets.
*/
static uint8_t ep0setup_buffer[8];
/**
* @brief EP0 initialization structure.
*/
static const USBEndpointConfig ep0config = {
USB_EP_MODE_TYPE_CTRL,
_usb_ep0setup,
_usb_ep0in,
_usb_ep0out,
64,
64,
&ep0in,
&ep0out,
1,
ep0setup_buffer
};
/*
* Buffer Descriptor Table (BDT)
*/
/*
* Buffer Descriptor (BD)
* */
typedef struct {
uint32_t desc;
uint8_t* addr;
} bd_t;
/*
* Buffer Descriptor fields - p.889
*/
#define BDT_OWN 0x80
#define BDT_DATA 0x40
#define BDT_KEEP 0x20
#define BDT_NINC 0x10
#define BDT_DTS 0x08
#define BDT_STALL 0x04
#define BDT_DESC(bc, data) (BDT_OWN | BDT_DTS | ((data&0x1)<<6) | ((bc) << 16))
/*
* BDT PID - p.891
*/
#define BDT_PID_OUT 0x01
#define BDT_PID_IN 0x09
#define BDT_PID_SETUP 0x0D
#define BDT_TOK_PID(n) (((n)>>2)&0xF)
/*
* BDT index fields
*/
#define DATA0 0
#define DATA1 1
#define RX 0
#define TX 1
#define EVEN 0
#define ODD 1
#define BDT_INDEX(endpoint, tx, odd) (((endpoint)<<2) | ((tx)<<1) | (odd))
/*
* Get RX-ed/TX-ed bytes count from BDT entry
*/
#define BDT_BC(n) (((n)>>16)&0x3FF)
/* The USB-FS needs 2 BDT entry per endpoint direction
* that adds to: 2*2*16 BDT entries for 16 bi-directional EP
*/
static volatile bd_t _bdt[(KINETIS_USB_ENDPOINTS)*2*2] __attribute__((aligned(512)));
/* FIXME later with dyn alloc
* 16 EP
* 2 directions per EP
* 2 buffer per direction
* => 64 buffers
*/
static uint8_t _usbb[KINETIS_USB_ENDPOINTS*4][64] __attribute__((aligned(4)));
static volatile uint8_t _usbbn=0;
uint8_t* usb_alloc(uint8_t size)
{
(void)size;
if(_usbbn < (KINETIS_USB_ENDPOINTS)*4)
return _usbb[_usbbn++];
while(1); /* Should not happen, ever */
}
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/* Called from locked ISR. */
void usb_packet_transmit(USBDriver *usbp, usbep_t ep, size_t n)
{
const USBEndpointConfig *epc = usbp->epc[ep];
USBInEndpointState *isp = epc->in_state;
bd_t *bd = (bd_t *)&_bdt[BDT_INDEX(ep, TX, isp->odd_even)];
if (n > (size_t)epc->in_maxsize)
n = (size_t)epc->in_maxsize;
/* Copy from buf to _usbb[] */
size_t i=0;
for(i=0;i<n;i++)
bd->addr[i] = isp->txbuf[i];
/* Update the Buffer status */
bd->desc = BDT_DESC(n, isp->data_bank);
/* Toggle the odd and data bits for next TX */
isp->data_bank ^= DATA1;
isp->odd_even ^= ODD;
}
/* Called from locked ISR. */
void usb_packet_receive(USBDriver *usbp, usbep_t ep, size_t n)
{
const USBEndpointConfig *epc = usbp->epc[ep];
USBOutEndpointState *osp = epc->out_state;
bd_t *bd = (bd_t *)&_bdt[BDT_INDEX(ep, RX, osp->odd_even)];
if (n > (size_t)epc->out_maxsize)
n = (size_t)epc->out_maxsize;
/* Copy from _usbb[] to buf */
size_t i=0;
for(i=0;i<n;i++)
osp->rxbuf[i] = bd->addr[i];
/* Update the Buffer status
* Set current buffer to same DATA bank and then toggle.
* Since even/odd buffers are ping-pong and setup re-initialized them
* this should work correctly */
bd->desc = BDT_DESC(epc->out_maxsize, osp->data_bank);
osp->data_bank ^= DATA1;
usb_lld_start_out(usbp, ep);
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*============================================================================*/
#if KINETIS_USB_USE_USB0 || defined(__DOXYGEN__)
/**
* @brief USB interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(KINETIS_USB_IRQ_VECTOR) {
USBDriver *usbp = &USBD1;
uint8_t istat = USB0->ISTAT;
OSAL_IRQ_PROLOGUE();
/* 04 - Bit2 - Start Of Frame token received */
if(istat & USBx_ISTAT_SOFTOK) {
_usb_isr_invoke_sof_cb(usbp);
USB0->ISTAT = USBx_ISTAT_SOFTOK;
}
/* 08 - Bit3 - Token processing completed */
while(istat & USBx_ISTAT_TOKDNE) {
uint8_t stat = USB0->STAT;
uint8_t ep = stat >> 4;
if(ep > KINETIS_USB_ENDPOINTS) {
OSAL_IRQ_EPILOGUE();
return;
}
const USBEndpointConfig *epc = usbp->epc[ep];
/* Get the correct BDT entry */
uint8_t odd_even = (stat & USBx_STAT_ODD_MASK) >> USBx_STAT_ODD_SHIFT;
uint8_t tx_rx = (stat & USBx_STAT_TX_MASK) >> USBx_STAT_TX_SHIFT;
bd_t *bd = (bd_t*)&_bdt[BDT_INDEX(ep,tx_rx,odd_even)];
/* Update the ODD/EVEN state for RX */
if(tx_rx == RX && epc->out_state != NULL)
epc->out_state->odd_even = odd_even;
switch(BDT_TOK_PID(bd->desc))
{
case BDT_PID_SETUP: // SETUP
{
/* Clear any pending IN stuff */
_bdt[BDT_INDEX(ep, TX, EVEN)].desc = 0;
_bdt[BDT_INDEX(ep, TX, ODD)].desc = 0;
/* Also in the chibios state machine */
(usbp)->receiving &= ~1;
/* After a SETUP, IN is always DATA1 */
usbp->epc[ep]->in_state->data_bank = DATA1;
/* Call SETUP function (ChibiOS core), which sends back stuff */
_usb_isr_invoke_setup_cb(usbp, ep);
/* Buffer is released by the above callback. */
/* from Paul: "unfreeze the USB, now that we're ready" */
USB0->CTL = USBx_CTL_USBENSOFEN;
} break;
case BDT_PID_IN: // IN
{
if(epc->in_state == NULL)
break;
/* Special case for SetAddress for EP0 */
if(ep == 0 && (((uint16_t)usbp->setup[0]<<8)|usbp->setup[1]) == 0x0500)
{
usbp->address = usbp->setup[2];
usb_lld_set_address(usbp);
_usb_isr_invoke_event_cb(usbp, USB_EVENT_ADDRESS);
usbp->state = USB_SELECTED;
}
uint16_t txed = BDT_BC(bd->desc);
epc->in_state->txcnt += txed;
if(epc->in_state->txcnt < epc->in_state->txsize)
{
epc->in_state->txbuf += txed;
osalSysLockFromISR();
usb_packet_transmit(usbp,ep,epc->in_state->txsize - epc->in_state->txcnt);
osalSysUnlockFromISR();
}
else
{
if(epc->in_cb != NULL)
_usb_isr_invoke_in_cb(usbp,ep);
}
} break;
case BDT_PID_OUT: // OUT
{
if(epc->out_state == NULL)
break;
uint16_t rxed = BDT_BC(bd->desc);
osalSysLockFromISR();
usb_packet_receive(usbp,ep,rxed);
osalSysUnlockFromISR();
if(rxed)
{
epc->out_state->rxbuf += rxed;
/* Update transaction data */
epc->out_state->rxcnt += rxed;
epc->out_state->rxsize -= rxed;
epc->out_state->rxpkts -= 1;
/* The transaction is completed if the specified number of packets
has been received or the current packet is a short packet.*/
if ((rxed < epc->out_maxsize) || (epc->out_state->rxpkts == 0))
{
if(epc->out_cb != NULL)
_usb_isr_invoke_out_cb(usbp, ep);
}
}
} break;
default:
break;
}
USB0->ISTAT = USBx_ISTAT_TOKDNE;
istat = USB0->ISTAT;
}
/* 01 - Bit0 - Valid USB Reset received */
if(istat & USBx_ISTAT_USBRST) {
_usb_reset(usbp);
USB0->ISTAT = USBx_ISTAT_USBRST;
OSAL_IRQ_EPILOGUE();
return;
}
/* 80 - Bit7 - STALL handshake received */
if(istat & USBx_ISTAT_STALL) {
USB0->ISTAT = USBx_ISTAT_STALL;
}
/* 02 - Bit1 - ERRSTAT condition triggered */
if(istat & USBx_ISTAT_ERROR) {
uint8_t err = USB0->ERRSTAT;
USB0->ERRSTAT = err;
USB0->ISTAT = USBx_ISTAT_ERROR;
}
/* 10 - Bit4 - Constant IDLE on USB bus detected */
if(istat & USBx_ISTAT_SLEEP) {
/* This seems to fire a few times before the device is
* configured - need to ignore those occurences somehow. */
/* The other option would be to only activate INTEN_SLEEPEN
* on CONFIGURED event, but that would need to be done in
* user firmware. */
if(usbp->state == USB_ACTIVE) {
_usb_suspend(usbp);
/* Enable interrupt on resume */
USB0->INTEN |= USBx_INTEN_RESUMEEN;
}
// low-power version (check!):
// enable wakeup interrupt on resume USB signaling
// (check that it was a wakeup int with USBx_USBTRC0_USB_RESUME_INT)
//? USB0->USBTRC0 |= USBx_USBTRC0_USBRESMEN
// suspend the USB module
//? USB0->USBCTRL |= USBx_USBCTRL_SUSP;
USB0->ISTAT = USBx_ISTAT_SLEEP;
}
/* 20 - Bit5 - Resume - Only allowed in sleep=suspend mode */
if(istat & USBx_ISTAT_RESUME) {
/* Disable interrupt on resume (should be disabled
* during normal operation according to datasheet). */
USB0->INTEN &= ~USBx_INTEN_RESUMEEN;
// low power version (check!):
// desuspend the USB module
//? USB0->USBCTRL &= ~USBx_USBCTRL_SUSP;
// maybe also
//? USB0->CTL = USBx_CTL_USBENSOFEN;
_usb_wakeup(usbp);
USB0->ISTAT = USBx_ISTAT_RESUME;
}
/* 40 - Bit6 - ATTACH - used */
OSAL_IRQ_EPILOGUE();
}
#endif /* KINETIS_USB_USE_USB0 */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level USB driver initialization.
*
* @notapi
*/
void usb_lld_init(void) {
/* Driver initialization.*/
usbObjectInit(&USBD1);
#if KINETIS_USB_USE_USB0
SIM->SOPT2 |= SIM_SOPT2_USBSRC;
#if defined(K20x5) || defined(K20x7)
#if KINETIS_MCG_MODE == KINETIS_MCG_MODE_FEI
/* MCGOUTCLK is the SYSCLK frequency, so don't divide for USB clock */
SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(0);
#elif KINETIS_MCG_MODE == KINETIS_MCG_MODE_PEE
#define KINETIS_USBCLK_FREQUENCY 48000000UL
uint32_t i,j;
for(i=0; i < 2; i++) {
for(j=0; j < 8; j++) {
if((KINETIS_PLLCLK_FREQUENCY * (i+1)) == (KINETIS_USBCLK_FREQUENCY*(j+1))) {
SIM->CLKDIV2 = i | SIM_CLKDIV2_USBDIV(j);
goto usbfrac_match_found;
}
}
}
usbfrac_match_found:
chDbgAssert(i<2 && j <8,"USB Init error");
#else /* KINETIS_MCG_MODE == KINETIS_MCG_MODE_PEE */
#error USB clock setting not implemented for this KINETIS_MCG_MODE
#endif /* KINETIS_MCG_MODE == ... */
#elif defined(KL25) || defined (KL26) || defined(KL27)
/* No extra clock dividers for USB clock */
#else /* defined(KL25) || defined (KL26) || defined(KL27) */
#error USB driver not implemented for your MCU type
#endif
#endif /* KINETIS_USB_USE_USB0 */
}
/**
* @brief Configures and activates the USB peripheral.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @notapi
*/
void usb_lld_start(USBDriver *usbp) {
if (usbp->state == USB_STOP) {
#if KINETIS_USB_USE_USB0
if (&USBD1 == usbp) {
/* Clear BDT */
uint8_t i;
for(i=0;i<KINETIS_USB_ENDPOINTS;i++) {
_bdt[i].desc=0;
_bdt[i].addr=0;
}
/* Enable Clock */
#if KINETIS_USB0_IS_USBOTG
SIM->SCGC4 |= SIM_SCGC4_USBOTG;
#else /* KINETIS_USB0_IS_USBOTG */
SIM->SCGC4 |= SIM_SCGC4_USBFS;
#endif /* KINETIS_USB0_IS_USBOTG */
#if KINETIS_HAS_USB_CLOCK_RECOVERY
USB0->CLK_RECOVER_IRC_EN |= USBx_CLK_RECOVER_IRC_EN_IRC_EN;
USB0->CLK_RECOVER_CTRL |= USBx_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN;
#endif /* KINETIS_HAS_USB_CLOCK_RECOVERY */
/* Reset USB module, wait for completion */
USB0->USBTRC0 |= USBx_USBTRC0_USBRESET;
while ((USB0->USBTRC0 & USBx_USBTRC0_USBRESET));
/* Set BDT Address */
USB0->BDTPAGE1 = ((uint32_t)_bdt) >> 8;
USB0->BDTPAGE2 = ((uint32_t)_bdt) >> 16;
USB0->BDTPAGE3 = ((uint32_t)_bdt) >> 24;
/* Clear all ISR flags */
USB0->ISTAT = 0xFF;
USB0->ERRSTAT = 0xFF;
#if KINETIS_USB0_IS_USBOTG
USB0->OTGISTAT = 0xFF;
#endif /* KINETIS_USB0_IS_USBOTG */
USB0->USBTRC0 |= 0x40; //a hint was given that this is an undocumented interrupt bit
/* Enable USB */
USB0->CTL = USBx_CTL_ODDRST | USBx_CTL_USBENSOFEN;
USB0->USBCTRL = 0;
/* Enable reset interrupt */
USB0->INTEN |= USBx_INTEN_USBRSTEN;
/* Enable interrupt in NVIC */
#if KINETIS_USB0_IS_USBOTG
nvicEnableVector(USB_OTG_IRQn, KINETIS_USB_USB0_IRQ_PRIORITY);
#else /* KINETIS_USB0_IS_USBOTG */
nvicEnableVector(USB_IRQn, KINETIS_USB_USB0_IRQ_PRIORITY);
#endif /* KINETIS_USB0_IS_USBOTG */
}
#endif /* KINETIS_USB_USE_USB0 */
}
}
/**
* @brief Deactivates the USB peripheral.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @notapi
*/
void usb_lld_stop(USBDriver *usbp) {
/* TODO: If in ready state then disables the USB clock.*/
if (usbp->state == USB_STOP) {
#if KINETIS_USB_USE_USB0
if (&USBD1 == usbp) {
#if KINETIS_USB0_IS_USBOTG
nvicDisableVector(USB_OTG_IRQn);
#else /* KINETIS_USB0_IS_USBOTG */
nvicDisableVector(USB_IRQn);
#endif /* KINETIS_USB0_IS_USBOTG */
}
#endif /* KINETIS_USB_USE_USB0 */
}
}
/**
* @brief USB low level reset routine.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @notapi
*/
void usb_lld_reset(USBDriver *usbp) {
// FIXME, dyn alloc
_usbbn = 0;
#if KINETIS_USB_USE_USB0
/* Reset BDT ODD/EVEN bits */
USB0->CTL = USBx_CTL_ODDRST;
/* EP0 initialization.*/
usbp->epc[0] = &ep0config;
usb_lld_init_endpoint(usbp, 0);
/* Clear all pending interrupts */
USB0->ERRSTAT = 0xFF;
USB0->ISTAT = 0xFF;
/* Set the address to zero during enumeration */
usbp->address = 0;
USB0->ADDR = 0;
/* Enable other interrupts */
USB0->ERREN = 0xFF;
USB0->INTEN = USBx_INTEN_TOKDNEEN |
USBx_INTEN_SOFTOKEN |
USBx_INTEN_STALLEN |
USBx_INTEN_ERROREN |
USBx_INTEN_USBRSTEN |
USBx_INTEN_SLEEPEN;
/* "is this necessary?", Paul from PJRC */
USB0->CTL = USBx_CTL_USBENSOFEN;
#endif /* KINETIS_USB_USE_USB0 */
}
/**
* @brief Sets the USB address.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @notapi
*/
void usb_lld_set_address(USBDriver *usbp) {
#if KINETIS_USB_USE_USB0
USB0->ADDR = usbp->address&0x7F;
#endif /* KINETIS_USB_USE_USB0 */
}
/**
* @brief Enables an endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) {
if(ep > KINETIS_USB_ENDPOINTS)
return;
const USBEndpointConfig *epc = usbp->epc[ep];
uint8_t mask=0;
if(epc->out_state != NULL)
{
/* OUT Endpoint */
epc->out_state->odd_even = EVEN;
epc->out_state->data_bank = DATA0;
/* RXe */
_bdt[BDT_INDEX(ep, RX, EVEN)].desc = BDT_DESC(epc->out_maxsize, DATA0);
_bdt[BDT_INDEX(ep, RX, EVEN)].addr = usb_alloc(epc->out_maxsize);
/* RXo */
_bdt[BDT_INDEX(ep, RX, ODD)].desc = BDT_DESC(epc->out_maxsize, DATA1);
_bdt[BDT_INDEX(ep, RX, ODD)].addr = usb_alloc(epc->out_maxsize);
/* Enable OUT direction */
mask |= USBx_ENDPTn_EPRXEN;
}
if(epc->in_state != NULL)
{
/* IN Endpoint */
epc->in_state->odd_even = EVEN;
epc->in_state->data_bank = DATA0;
/* TXe, not used yet */
_bdt[BDT_INDEX(ep, TX, EVEN)].desc = 0;
_bdt[BDT_INDEX(ep, TX, EVEN)].addr = usb_alloc(epc->in_maxsize);
/* TXo, not used yet */
_bdt[BDT_INDEX(ep, TX, ODD)].desc = 0;
_bdt[BDT_INDEX(ep, TX, ODD)].addr = usb_alloc(epc->in_maxsize);
/* Enable IN direction */
mask |= USBx_ENDPTn_EPTXEN;
}
/* EPHSHK should be set for CTRL, BULK, INTR not for ISOC*/
if((epc->ep_mode & USB_EP_MODE_TYPE) != USB_EP_MODE_TYPE_ISOC)
mask |= USBx_ENDPTn_EPHSHK;
/* Endpoint is not a CTRL endpoint, disable SETUP transfers */
if((epc->ep_mode & USB_EP_MODE_TYPE) != USB_EP_MODE_TYPE_CTRL)
mask |= USBx_ENDPTn_EPCTLDIS;
#if KINETIS_USB_USE_USB0
USB0->ENDPT[ep].V = mask;
#endif /* KINETIS_USB_USE_USB0 */
}
/**
* @brief Disables all the active endpoints except the endpoint zero.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @notapi
*/
void usb_lld_disable_endpoints(USBDriver *usbp) {
(void)usbp;
uint8_t i;
#if KINETIS_USB_USE_USB0
for(i=1;i<KINETIS_USB_ENDPOINTS;i++)
USB0->ENDPT[i].V = 0;
#endif /* KINETIS_USB_USE_USB0 */
}
/**
* @brief Returns the status of an OUT endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @return The endpoint status.
* @retval EP_STATUS_DISABLED The endpoint is not active.
* @retval EP_STATUS_STALLED The endpoint is stalled.
* @retval EP_STATUS_ACTIVE The endpoint is active.
*
* @notapi
*/
usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep) {
(void)usbp;
#if KINETIS_USB_USE_USB0
if(ep > USB_MAX_ENDPOINTS)
return EP_STATUS_DISABLED;
if(!(USB0->ENDPT[ep].V & (USBx_ENDPTn_EPRXEN)))
return EP_STATUS_DISABLED;
else if(USB0->ENDPT[ep].V & USBx_ENDPTn_EPSTALL)
return EP_STATUS_STALLED;
return EP_STATUS_ACTIVE;
#endif /* KINETIS_USB_USE_USB0 */
}
/**
* @brief Returns the status of an IN endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @return The endpoint status.
* @retval EP_STATUS_DISABLED The endpoint is not active.
* @retval EP_STATUS_STALLED The endpoint is stalled.
* @retval EP_STATUS_ACTIVE The endpoint is active.
*
* @notapi
*/
usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep) {
(void)usbp;
if(ep > USB_MAX_ENDPOINTS)
return EP_STATUS_DISABLED;
#if KINETIS_USB_USE_USB0
if(!(USB0->ENDPT[ep].V & (USBx_ENDPTn_EPTXEN)))
return EP_STATUS_DISABLED;
else if(USB0->ENDPT[ep].V & USBx_ENDPTn_EPSTALL)
return EP_STATUS_STALLED;
return EP_STATUS_ACTIVE;
#endif /* KINETIS_USB_USE_USB0 */
}
/**
* @brief Reads a setup packet from the dedicated packet buffer.
* @details This function must be invoked in the context of the @p setup_cb
* callback in order to read the received setup packet.
* @pre In order to use this function the endpoint must have been
* initialized as a control endpoint.
* @post The endpoint is ready to accept another packet.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @param[out] buf buffer where to copy the packet data
*
* @notapi
*/
void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) {
/* Get the BDT entry */
USBOutEndpointState *os = usbp->epc[ep]->out_state;
bd_t *bd = (bd_t*)&_bdt[BDT_INDEX(ep, RX, os->odd_even)];
/* Copy the 8 bytes of data */
uint8_t n;
for (n = 0; n < 8; n++) {
buf[n] = bd->addr[n];
}
/* Release the buffer
* Setup packet is always DATA0
* Initialize buffers so current expects DATA0 & opposite DATA1 */
bd->desc = BDT_DESC(usbp->epc[ep]->out_maxsize,DATA0);
_bdt[BDT_INDEX(ep, RX, os->odd_even^ODD)].desc = BDT_DESC(usbp->epc[ep]->out_maxsize,DATA1);
os->data_bank = DATA1;
}
/**
* @brief Starts a receive operation on an OUT endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
void usb_lld_start_out(USBDriver *usbp, usbep_t ep) {
USBOutEndpointState *osp = usbp->epc[ep]->out_state;
/* Transfer initialization.*/
if (osp->rxsize == 0) /* Special case for zero sized packets.*/
osp->rxpkts = 1;
else
osp->rxpkts = (uint16_t)((osp->rxsize + usbp->epc[ep]->out_maxsize - 1) /
usbp->epc[ep]->out_maxsize);
}
/**
* @brief Starts a transmit operation on an IN endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @note Called from ISR and locked zone.
* @notapi
*/
void usb_lld_start_in(USBDriver *usbp, usbep_t ep) {
(void)usbp;
(void)ep;
usb_packet_transmit(usbp,ep,usbp->epc[ep]->in_state->txsize);
}
/**
* @brief Brings an OUT endpoint in the stalled state.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) {
(void)usbp;
#if KINETIS_USB_USE_USB0
USB0->ENDPT[ep].V |= USBx_ENDPTn_EPSTALL;
#endif /* KINETIS_USB_USE_USB0 */
}
/**
* @brief Brings an IN endpoint in the stalled state.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) {
(void)usbp;
#if KINETIS_USB_USE_USB0
USB0->ENDPT[ep].V |= USBx_ENDPTn_EPSTALL;
#endif /* KINETIS_USB_USE_USB0 */
}
/**
* @brief Brings an OUT endpoint in the active state.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
void usb_lld_clear_out(USBDriver *usbp, usbep_t ep) {
(void)usbp;
#if KINETIS_USB_USE_USB0
USB0->ENDPT[ep].V &= ~USBx_ENDPTn_EPSTALL;
#endif /* KINETIS_USB_USE_USB0 */
}
/**
* @brief Brings an IN endpoint in the active state.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
void usb_lld_clear_in(USBDriver *usbp, usbep_t ep) {
(void)usbp;
#if KINETIS_USB_USE_USB0
USB0->ENDPT[ep].V &= ~USBx_ENDPTn_EPSTALL;
#endif /* KINETIS_USB_USE_USB0 */
}
#endif /* HAL_USE_USB */
/** @} */

View File

@ -0,0 +1,428 @@
/*
ChibiOS - Copyright (C) 2015 RedoX https://github.com/RedoXyde/
(C) 2015-2016 flabbergast <s3+flabbergast@sdfeu.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file KINETIS/LLD/usb_lld.h
* @brief KINETIS USB subsystem low level driver header.
*
* @addtogroup USB
* @{
*/
#ifndef _USB_LLD_H_
#define _USB_LLD_H_
#if HAL_USE_USB || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief Maximum endpoint address.
*/
#define USB_MAX_ENDPOINTS 15
/**
* @brief Status stage handling method.
*/
#define USB_EP0_STATUS_STAGE USB_EP0_STATUS_STAGE_SW
/**
* @brief Address ack handling
*/
#define USB_SET_ADDRESS_ACK_HANDLING USB_SET_ADDRESS_ACK_SW
/**
* @brief This device requires the address change after the status packet.
*/
#define USB_SET_ADDRESS_MODE USB_LATE_SET_ADDRESS
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief USB1 driver enable switch.
* @details If set to @p TRUE the support for USB1 is included.
* @note The default is @p TRUE.
*/
#if !defined(KINETIS_USB_USE_USB0) || defined(__DOXYGEN__)
#define KINETIS_USB_USE_USB0 FALSE
#endif
/**
* @brief USB1 interrupt priority level setting.
*/
#if !defined(KINETIS_USB_USB0_IRQ_PRIORITY)|| defined(__DOXYGEN__)
#define KINETIS_USB_USB0_IRQ_PRIORITY 5
#endif
#if !defined(KINETIS_USB_ENDPOINTS) || defined(__DOXYGEN__)
#define KINETIS_USB_ENDPOINTS USB_MAX_ENDPOINTS+1
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if KINETIS_USB_USE_USB0 && !KINETIS_HAS_USB
#error "USB not present in the selected device"
#endif
#if !KINETIS_USB_USE_USB0
#error "USB driver activated but no USB peripheral assigned"
#endif
#if KINETIS_USB_USE_USB0 && \
!OSAL_IRQ_IS_VALID_PRIORITY(KINETIS_USB_USB0_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to KINETIS_USB_USB0_IRQ_PRIORITY"
#endif
#if !defined(KINETIS_USB_IRQ_VECTOR)
#error "KINETIS_USB_IRQ_VECTOR not defined"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of an IN endpoint state structure.
*/
typedef struct {
/**
* @brief Requested transmit transfer size.
*/
size_t txsize;
/**
* @brief Transmitted bytes so far.
*/
size_t txcnt;
/**
* @brief Pointer to the transmission linear buffer.
*/
const uint8_t *txbuf;
#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
thread_reference_t thread;
#endif
/* End of the mandatory fields.*/
/* */
bool odd_even; /* ODD / EVEN */
/* */
bool data_bank; /* DATA0 / DATA1 */
} USBInEndpointState;
/**
* @brief Type of an OUT endpoint state structure.
*/
typedef struct {
/**
* @brief Requested receive transfer size.
*/
size_t rxsize;
/**
* @brief Received bytes so far.
*/
size_t rxcnt;
/**
* @brief Pointer to the receive linear buffer.
*/
uint8_t *rxbuf;
#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
thread_reference_t thread;
#endif
/* End of the mandatory fields.*/
/**
* @brief Number of packets to receive.
*/
uint16_t rxpkts;
/* */
bool odd_even; /* ODD / EVEN */
/* */
bool data_bank; /* DATA0 / DATA1 */
} USBOutEndpointState;
/**
* @brief Type of an USB endpoint configuration structure.
* @note Platform specific restrictions may apply to endpoints.
*/
typedef struct {
/**
* @brief Type and mode of the endpoint.
*/
uint32_t ep_mode;
/**
* @brief Setup packet notification callback.
* @details This callback is invoked when a setup packet has been
* received.
* @post The application must immediately call @p usbReadPacket() in
* order to access the received packet.
* @note This field is only valid for @p USB_EP_MODE_TYPE_CTRL
* endpoints, it should be set to @p NULL for other endpoint
* types.
*/
usbepcallback_t setup_cb;
/**
* @brief IN endpoint notification callback.
* @details This field must be set to @p NULL if callback is not required.
*/
usbepcallback_t in_cb;
/**
* @brief OUT endpoint notification callback.
* @details This field must be set to @p NULL if callback is not required.
*/
usbepcallback_t out_cb;
/**
* @brief IN endpoint maximum packet size.
* @details This field must be set to zero if the IN endpoint is not used.
*/
uint16_t in_maxsize;
/**
* @brief OUT endpoint maximum packet size.
* @details This field must be set to zero if the OUT endpoint is not used.
*/
uint16_t out_maxsize;
/**
* @brief @p USBEndpointState associated to the IN endpoint.
* @details This field must be set to @p NULL if the IN endpoint is not
* used.
*/
USBInEndpointState *in_state;
/**
* @brief @p USBEndpointState associated to the OUT endpoint.
* @details This field must be set to @p NULL if the OUT endpoint is not
* used.
*/
USBOutEndpointState *out_state;
/* End of the mandatory fields.*/
/**
* @brief Reserved field, not currently used.
* @note Initialize this field to 1 in order to be forward compatible.
*/
uint16_t ep_buffers;
/**
* @brief Pointer to a buffer for setup packets.
* @details Setup packets require a dedicated 8-bytes buffer, set this
* field to @p NULL for non-control endpoints.
*/
uint8_t *setup_buf;
} USBEndpointConfig;
/**
* @brief Type of an USB driver configuration structure.
*/
typedef struct {
/**
* @brief USB events callback.
* @details This callback is invoked when an USB driver event is registered.
*/
usbeventcb_t event_cb;
/**
* @brief Device GET_DESCRIPTOR request callback.
* @note This callback is mandatory and cannot be set to @p NULL.
*/
usbgetdescriptor_t get_descriptor_cb;
/**
* @brief Requests hook callback.
* @details This hook allows to be notified of standard requests or to
* handle non standard requests.
*/
usbreqhandler_t requests_hook_cb;
/**
* @brief Start Of Frame callback.
*/
usbcallback_t sof_cb;
/* End of the mandatory fields.*/
} USBConfig;
/**
* @brief Structure representing an USB driver.
*/
struct USBDriver {
/**
* @brief Driver state.
*/
usbstate_t state;
/**
* @brief Current configuration data.
*/
const USBConfig *config;
/**
* @brief Bit map of the transmitting IN endpoints.
*/
uint16_t transmitting;
/**
* @brief Bit map of the receiving OUT endpoints.
*/
uint16_t receiving;
/**
* @brief Active endpoints configurations.
*/
const USBEndpointConfig *epc[USB_MAX_ENDPOINTS + 1];
/**
* @brief Fields available to user, it can be used to associate an
* application-defined handler to an IN endpoint.
* @note The base index is one, the endpoint zero does not have a
* reserved element in this array.
*/
void *in_params[USB_MAX_ENDPOINTS];
/**
* @brief Fields available to user, it can be used to associate an
* application-defined handler to an OUT endpoint.
* @note The base index is one, the endpoint zero does not have a
* reserved element in this array.
*/
void *out_params[USB_MAX_ENDPOINTS];
/**
* @brief Endpoint 0 state.
*/
usbep0state_t ep0state;
/**
* @brief Next position in the buffer to be transferred through endpoint 0.
*/
uint8_t *ep0next;
/**
* @brief Number of bytes yet to be transferred through endpoint 0.
*/
size_t ep0n;
/**
* @brief Endpoint 0 end transaction callback.
*/
usbcallback_t ep0endcb;
/**
* @brief Setup packet buffer.
*/
uint8_t setup[8];
/**
* @brief Current USB device status.
*/
uint16_t status;
/**
* @brief Assigned USB address.
*/
uint8_t address;
/**
* @brief Current USB device configuration.
*/
uint8_t configuration;
#if defined(USB_DRIVER_EXT_FIELDS)
USB_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Pointer to the next address in the packet memory.
*/
uint32_t pmnext;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Returns the current frame number.
*
* @param[in] usbp pointer to the @p USBDriver object
* @return The current frame number.
*
* @notapi
*/
#define usb_lld_get_frame_number(usbp) ((USB0->FRMNUMH<<8)|USB0->FRMNUML)
/**
* @brief Returns the exact size of a receive transaction.
* @details The received size can be different from the size specified in
* @p usbStartReceiveI() because the last packet could have a size
* different from the expected one.
* @pre The OUT endpoint must have been configured in transaction mode
* in order to use this function.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @return Received data size.
*
* @notapi
*/
#define usb_lld_get_transaction_size(usbp, ep) \
((usbp)->epc[ep]->out_state->rxcnt)
/**
* @brief Connects the USB device.
*
* @api
*/
#if !defined(usb_lld_connect_bus)
#define usb_lld_connect_bus(usbp) (USB0->CONTROL |= USBx_CONTROL_DPPULLUPNONOTG)
#endif
/**
* @brief Disconnect the USB device.
*
* @api
*/
#if !defined(usb_lld_disconnect_bus)
/* Writing to USB0->CONTROL causes an unhandled exception when USB module is not clocked. */
#if KINETIS_USB0_IS_USBOTG
#define usb_lld_disconnect_bus(usbp) if(SIM->SCGC4 & SIM_SCGC4_USBOTG) {USB0->CONTROL &= ~USBx_CONTROL_DPPULLUPNONOTG;} else {}
#else /* KINETIS_USB0_IS_USBOTG */
#define usb_lld_disconnect_bus(usbp) if(SIM->SCGC4 & SIM_SCGC4_USBFS) {USB0->CONTROL &= ~USBx_CONTROL_DPPULLUPNONOTG;} else {}
#endif /* KINETIS_USB0_IS_USBOTG */
#endif
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if KINETIS_USB_USE_USB0 && !defined(__DOXYGEN__)
extern USBDriver USBD1;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void usb_lld_init(void);
void usb_lld_start(USBDriver *usbp);
void usb_lld_stop(USBDriver *usbp);
void usb_lld_reset(USBDriver *usbp);
void usb_lld_set_address(USBDriver *usbp);
void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep);
void usb_lld_disable_endpoints(USBDriver *usbp);
usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep);
usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep);
void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf);
void usb_lld_start_out(USBDriver *usbp, usbep_t ep);
void usb_lld_start_in(USBDriver *usbp, usbep_t ep);
void usb_lld_stall_out(USBDriver *usbp, usbep_t ep);
void usb_lld_stall_in(USBDriver *usbp, usbep_t ep);
void usb_lld_clear_out(USBDriver *usbp, usbep_t ep);
void usb_lld_clear_in(USBDriver *usbp, usbep_t ep);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_USB */
#endif /* _USB_LLD_H_ */
/** @} */