copy LLD from KINETIS HAL (no changes yet)
This commit is contained in:
parent
b4b3579c86
commit
480534795c
|
@ -0,0 +1,9 @@
|
|||
ifeq ($(USE_SMART_BUILD),yes)
|
||||
ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),)
|
||||
PLATFORMSRC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/GPIOv1/hal_pal_lld.c
|
||||
endif
|
||||
else
|
||||
PLATFORMSRC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/GPIOv1/hal_pal_lld.c
|
||||
endif
|
||||
|
||||
PLATFORMINC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/GPIOv1
|
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
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 GPIOv1/hal_pal_lld.c
|
||||
* @brief 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. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @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 < PADS_PER_PORT, "pal_lld_setpadmode() #1, 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() #2, invalid port");
|
||||
|
||||
switch (mode) {
|
||||
case PAL_MODE_RESET:
|
||||
case PAL_MODE_INPUT:
|
||||
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 |
|
||||
PORTx_PCRn_PS;
|
||||
break;
|
||||
case PAL_MODE_INPUT_PULLDOWN:
|
||||
portcfg->PCR[pad] = PIN_MUX_ALTERNATIVE(1) |
|
||||
PORTx_PCRn_PE;
|
||||
break;
|
||||
case PAL_MODE_UNCONNECTED:
|
||||
case PAL_MODE_INPUT_ANALOG:
|
||||
portcfg->PCR[pad] = PIN_MUX_ALTERNATIVE(0);
|
||||
break;
|
||||
case PAL_MODE_ALTERNATIVE_1:
|
||||
portcfg->PCR[pad] = PIN_MUX_ALTERNATIVE(1);
|
||||
break;
|
||||
case PAL_MODE_ALTERNATIVE_2:
|
||||
portcfg->PCR[pad] = PIN_MUX_ALTERNATIVE(2);
|
||||
break;
|
||||
case PAL_MODE_ALTERNATIVE_3:
|
||||
portcfg->PCR[pad] = PIN_MUX_ALTERNATIVE(3);
|
||||
break;
|
||||
case PAL_MODE_ALTERNATIVE_4:
|
||||
portcfg->PCR[pad] = PIN_MUX_ALTERNATIVE(4);
|
||||
break;
|
||||
case PAL_MODE_ALTERNATIVE_5:
|
||||
portcfg->PCR[pad] = PIN_MUX_ALTERNATIVE(5);
|
||||
break;
|
||||
case PAL_MODE_ALTERNATIVE_6:
|
||||
portcfg->PCR[pad] = PIN_MUX_ALTERNATIVE(6);
|
||||
break;
|
||||
case PAL_MODE_ALTERNATIVE_7:
|
||||
portcfg->PCR[pad] = PIN_MUX_ALTERNATIVE(7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Kinetis I/O ports configuration.
|
||||
* @details Ports A-E clocks enabled.
|
||||
*
|
||||
* @param[in] config the Kinetis ports configuration
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _pal_lld_init(const PALConfig *config) {
|
||||
|
||||
int i, j;
|
||||
|
||||
/* Enable clocking on all Ports */
|
||||
SIM->SCGC5 |= SIM_SCGC5_PORTA |
|
||||
SIM_SCGC5_PORTB |
|
||||
SIM_SCGC5_PORTC |
|
||||
SIM_SCGC5_PORTD |
|
||||
SIM_SCGC5_PORTE;
|
||||
|
||||
/* Initial PORT and GPIO setup */
|
||||
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) {
|
||||
|
||||
int i;
|
||||
|
||||
(void)mask;
|
||||
|
||||
for (i = 0; i < PADS_PER_PORT; i++) {
|
||||
pal_lld_setpadmode(port, i, mode);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_PAL */
|
||||
|
||||
/** @} */
|
|
@ -0,0 +1,428 @@
|
|||
/*
|
||||
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 GPIOv1/hal_pal_lld.h
|
||||
* @brief PAL subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup PAL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_PAL_LLD_H_
|
||||
#define HAL_PAL_LLD_H_
|
||||
|
||||
#if HAL_USE_PAL || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Unsupported modes and specific modes */
|
||||
/*===========================================================================*/
|
||||
|
||||
#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)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* I/O Ports Types and constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#define TOTAL_PORTS 5
|
||||
#define PADS_PER_PORT 32
|
||||
|
||||
/**
|
||||
* @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)
|
||||
|
||||
/**
|
||||
* @brief Digital I/O port sized unsigned type.
|
||||
*/
|
||||
typedef uint32_t ioportmask_t;
|
||||
|
||||
/**
|
||||
* @brief Digital I/O modes.
|
||||
*/
|
||||
typedef uint32_t iomode_t;
|
||||
|
||||
/**
|
||||
* @brief Type of an I/O line.
|
||||
*/
|
||||
typedef uint32_t ioline_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;
|
||||
|
||||
/**
|
||||
* @brief Type of an pad identifier.
|
||||
*/
|
||||
typedef uint32_t iopadid_t;
|
||||
|
||||
/**
|
||||
* @brief Port Configuration.
|
||||
* @details This structure stores the configuration parameters of all pads
|
||||
* belonging to a port.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* I/O Ports Identifiers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief GPIO port A identifier.
|
||||
*/
|
||||
#define IOPORT1 GPIOA
|
||||
|
||||
/**
|
||||
* @brief GPIO port B identifier.
|
||||
*/
|
||||
#define IOPORT2 GPIOB
|
||||
|
||||
/**
|
||||
* @brief GPIO port C identifier.
|
||||
*/
|
||||
#define IOPORT3 GPIOC
|
||||
|
||||
/**
|
||||
* @brief GPIO port D identifier.
|
||||
*/
|
||||
#define IOPORT4 GPIOD
|
||||
|
||||
/**
|
||||
* @brief GPIO port E identifier.
|
||||
*/
|
||||
#define IOPORT5 GPIOE
|
||||
|
||||
/**
|
||||
* @name Line handling macros
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Forms a line identifier.
|
||||
* @details A port/pad pair are encoded into an @p ioline_t type. The encoding
|
||||
* of this type is platform-dependent.
|
||||
* @note In this driver the pad number is encoded in the byte of the GPIO
|
||||
* address that's zero on all Kinetis devices.
|
||||
*/
|
||||
#define PAL_LINE(port, pad) \
|
||||
((ioline_t)((uint32_t)(port) | ((uint32_t)(pad)<<20)))
|
||||
|
||||
/**
|
||||
* @brief Decodes a port identifier from a line identifier.
|
||||
*/
|
||||
#define PAL_PORT(line) \
|
||||
((GPIO_TypeDef *)(((uint32_t)(line)) & 0xF00FFFFFU))
|
||||
|
||||
/**
|
||||
* @brief Decodes a pad identifier from a line identifier.
|
||||
*/
|
||||
#define PAL_PAD(line) \
|
||||
((uint32_t)((uint32_t)(line) & 0x0FF00000U)>>20)
|
||||
|
||||
/**
|
||||
* @brief Value identifying an invalid line.
|
||||
*/
|
||||
#define PAL_NOLINE 0U
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* 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 toggled 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 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
|
||||
*/
|
||||
#define pal_lld_readpad(port, pad) _pal_lld_readpad(port, pad)
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
#define pal_lld_writepad(port, pad, bit) _pal_lld_writepad(port, pad, bit)
|
||||
|
||||
/**
|
||||
* @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);
|
||||
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
|
||||
|
||||
#endif /* HAL_USE_PAL */
|
||||
|
||||
#endif /* HAL_PAL_LLD_H_ */
|
||||
|
||||
/** @} */
|
|
@ -0,0 +1,9 @@
|
|||
ifeq ($(USE_SMART_BUILD),yes)
|
||||
ifneq ($(findstring HAL_USE_GPT TRUE,$(HALCONF)),)
|
||||
PLATFORMSRC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/PITv1/hal_gpt_lld.c
|
||||
endif
|
||||
else
|
||||
PLATFORMSRC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/PITv1/hal_gpt_lld.c
|
||||
endif
|
||||
|
||||
PLATFORMINC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/PITv1
|
|
@ -0,0 +1,391 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2014 Derek Mulcahy
|
||||
|
||||
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 PITv1/hal_gpt_lld.c
|
||||
* @brief KINETIS GPT subsystem low level driver source.
|
||||
*
|
||||
* @addtogroup GPT
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_GPT || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief GPTD1 driver identifier.
|
||||
* @note The driver GPTD1 allocates the complex timer PIT0 when enabled.
|
||||
*/
|
||||
#if KINETIS_GPT_USE_PIT0 || defined(__DOXYGEN__)
|
||||
GPTDriver GPTD1;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD2 driver identifier.
|
||||
* @note The driver GPTD2 allocates the timer PIT1 when enabled.
|
||||
*/
|
||||
#if KINETIS_GPT_USE_PIT1 || defined(__DOXYGEN__)
|
||||
GPTDriver GPTD2;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD3 driver identifier.
|
||||
* @note The driver GPTD3 allocates the timer PIT2 when enabled.
|
||||
*/
|
||||
#if KINETIS_GPT_USE_PIT2 || defined(__DOXYGEN__)
|
||||
GPTDriver GPTD3;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD4 driver identifier.
|
||||
* @note The driver GPTD4 allocates the timer PIT3 when enabled.
|
||||
*/
|
||||
#if KINETIS_GPT_USE_PIT3 || defined(__DOXYGEN__)
|
||||
GPTDriver GPTD4;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* 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. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Shared IRQ handler.
|
||||
*
|
||||
* @param[in] gptp pointer to a @p GPTDriver object
|
||||
*/
|
||||
static void gpt_lld_serve_interrupt(GPTDriver *gptp) {
|
||||
|
||||
/* Clear the interrupt */
|
||||
gptp->channel->TFLG |= PIT_TFLGn_TIF;
|
||||
|
||||
if (gptp->state == GPT_ONESHOT) {
|
||||
gptp->state = GPT_READY; /* Back in GPT_READY state. */
|
||||
gpt_lld_stop_timer(gptp); /* Timer automatically stopped. */
|
||||
}
|
||||
gptp->config->callback(gptp);
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !KINETIS_HAS_PIT_COMMON_IRQ
|
||||
|
||||
#if KINETIS_GPT_USE_PIT0
|
||||
/**
|
||||
* @brief PIT1 interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
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
|
||||
/**
|
||||
* @brief PIT1 interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
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
|
||||
/**
|
||||
* @brief PIT2 interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
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
|
||||
/**
|
||||
* @brief PIT3 interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
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. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level GPT driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void gpt_lld_init(void) {
|
||||
|
||||
#if KINETIS_GPT_USE_PIT0
|
||||
/* Driver initialization.*/
|
||||
GPTD1.channel = &PIT->CHANNEL[0];
|
||||
gptObjectInit(&GPTD1);
|
||||
#endif
|
||||
|
||||
#if KINETIS_GPT_USE_PIT1
|
||||
/* Driver initialization.*/
|
||||
GPTD2.channel = &PIT->CHANNEL[1];
|
||||
gptObjectInit(&GPTD2);
|
||||
#endif
|
||||
|
||||
#if KINETIS_GPT_USE_PIT2
|
||||
/* Driver initialization.*/
|
||||
GPTD3.channel = &PIT->CHANNEL[2];
|
||||
gptObjectInit(&GPTD3);
|
||||
#endif
|
||||
|
||||
#if KINETIS_GPT_USE_PIT3
|
||||
/* Driver initialization.*/
|
||||
GPTD4.channel = &PIT->CHANNEL[3];
|
||||
gptObjectInit(&GPTD4);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the GPT peripheral.
|
||||
*
|
||||
* @param[in] gptp pointer to the @p GPTDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void gpt_lld_start(GPTDriver *gptp) {
|
||||
uint16_t psc;
|
||||
|
||||
if (gptp->state == GPT_STOP) {
|
||||
/* Clock activation.*/
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
#if KINETIS_GPT_USE_PIT1
|
||||
if (&GPTD2 == gptp) {
|
||||
nvicEnableVector(PITChannel1_IRQn, KINETIS_GPT_PIT1_IRQ_PRIORITY);
|
||||
}
|
||||
#endif
|
||||
#if KINETIS_GPT_USE_PIT2
|
||||
if (&GPTD3 == gptp) {
|
||||
nvicEnableVector(PITChannel2_IRQn, KINETIS_GPT_PIT2_IRQ_PRIORITY);
|
||||
}
|
||||
#endif
|
||||
#if KINETIS_GPT_USE_PIT3
|
||||
if (&GPTD4 == gptp) {
|
||||
nvicEnableVector(PITChannel3_IRQn, KINETIS_GPT_PIT3_IRQ_PRIORITY);
|
||||
}
|
||||
#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.*/
|
||||
psc = (uint16_t)((gptp->clock / gptp->config->frequency) - 1);
|
||||
osalDbgAssert(((uint32_t)(psc + 1) * gptp->config->frequency) == gptp->clock,
|
||||
"invalid frequency");
|
||||
|
||||
/* Enable the PIT */
|
||||
PIT->MCR = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the GPT peripheral.
|
||||
*
|
||||
* @param[in] gptp pointer to the @p GPTDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void gpt_lld_stop(GPTDriver *gptp) {
|
||||
|
||||
if (gptp->state == GPT_READY) {
|
||||
SIM->SCGC6 &= ~SIM_SCGC6_PIT;
|
||||
|
||||
/* Disable the channel */
|
||||
gptp->channel->TCTRL = 0;
|
||||
|
||||
/* Clear pending interrupts */
|
||||
gptp->channel->TFLG |= PIT_TFLGn_TIF;
|
||||
|
||||
#if !KINETIS_HAS_PIT_COMMON_IRQ
|
||||
|
||||
#if KINETIS_GPT_USE_PIT0
|
||||
if (&GPTD1 == gptp) {
|
||||
nvicDisableVector(PITChannel0_IRQn);
|
||||
}
|
||||
#endif
|
||||
#if KINETIS_GPT_USE_PIT1
|
||||
if (&GPTD2 == gptp) {
|
||||
nvicDisableVector(PITChannel1_IRQn);
|
||||
}
|
||||
#endif
|
||||
#if KINETIS_GPT_USE_PIT2
|
||||
if (&GPTD3 == gptp) {
|
||||
nvicDisableVector(PITChannel2_IRQn);
|
||||
}
|
||||
#endif
|
||||
#if KINETIS_GPT_USE_PIT3
|
||||
if (&GPTD4 == gptp) {
|
||||
nvicDisableVector(PITChannel3_IRQn);
|
||||
}
|
||||
#endif
|
||||
|
||||
#else /* !KINETIS_HAS_PIT_COMMON_IRQ */
|
||||
if(--active_channels == 0)
|
||||
nvicDisableVector(PIT_IRQn);
|
||||
#endif /* !KINETIS_HAS_PIT_COMMON_IRQ */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the timer in continuous mode.
|
||||
*
|
||||
* @param[in] gptp pointer to the @p GPTDriver object
|
||||
* @param[in] interval period in ticks
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t interval) {
|
||||
|
||||
/* Clear pending interrupts */
|
||||
gptp->channel->TFLG |= PIT_TFLGn_TIF;
|
||||
|
||||
/* Set the interval */
|
||||
gpt_lld_change_interval(gptp, interval);
|
||||
|
||||
/* Start the timer */
|
||||
gptp->channel->TCTRL |= PIT_TCTRLn_TIE | PIT_TCTRLn_TEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the timer.
|
||||
*
|
||||
* @param[in] gptp pointer to the @p GPTDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void gpt_lld_stop_timer(GPTDriver *gptp) {
|
||||
|
||||
/* Stop the timer */
|
||||
gptp->channel->TCTRL = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the timer in one shot mode and waits for completion.
|
||||
* @details This function specifically polls the timer waiting for completion
|
||||
* in order to not have extra delays caused by interrupt servicing,
|
||||
* this function is only recommended for short delays.
|
||||
*
|
||||
* @param[in] gptp pointer to the @p GPTDriver object
|
||||
* @param[in] interval time interval in ticks
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval) {
|
||||
struct PIT_CHANNEL *channel = gptp->channel;
|
||||
|
||||
/* Disable timer and disable interrupts */
|
||||
channel->TCTRL = 0;
|
||||
|
||||
/* Clear the interrupt flag */
|
||||
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_TCTRLn_TEN;
|
||||
|
||||
/* Wait for the interrupt flag to be set */
|
||||
while (!(channel->TFLG & PIT_TFLGn_TIF))
|
||||
;
|
||||
|
||||
/* Disable timer and disable interrupts */
|
||||
channel->TCTRL = 0;
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_GPT */
|
||||
|
||||
/** @} */
|
|
@ -0,0 +1,333 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2014 Derek Mulcahy
|
||||
|
||||
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 PITv1/hal_gpt_lld.h
|
||||
* @brief KINETIS GPT subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup GPT
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_GPT_LLD_H_
|
||||
#define HAL_GPT_LLD_H_
|
||||
|
||||
#if HAL_USE_GPT || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief GPTD1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for GPTD1 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(KINETIS_GPT_USE_PIT0) || defined(__DOXYGEN__)
|
||||
#define KINETIS_GPT_USE_PIT0 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD2 driver enable switch.
|
||||
* @details If set to @p TRUE the support for GPTD2 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(KINETIS_GPT_USE_PIT1) || defined(__DOXYGEN__)
|
||||
#define KINETIS_GPT_USE_PIT1 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD3 driver enable switch.
|
||||
* @details If set to @p TRUE the support for GPTD3 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(KINETIS_GPT_USE_PIT2) || defined(__DOXYGEN__)
|
||||
#define KINETIS_GPT_USE_PIT2 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD4 driver enable switch.
|
||||
* @details If set to @p TRUE the support for GPTD4 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(KINETIS_GPT_USE_PIT3) || defined(__DOXYGEN__)
|
||||
#define KINETIS_GPT_USE_PIT3 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD1 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(KINETIS_GPT_PIT0_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define KINETIS_GPT_PIT0_IRQ_PRIORITY 7
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD2 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(KINETIS_GPT_PIT1_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define KINETIS_GPT_PIT1_IRQ_PRIORITY 7
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD3 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(KINETIS_GPT_PIT2_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define KINETIS_GPT_PIT2_IRQ_PRIORITY 7
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD4 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(KINETIS_GPT_PIT3_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#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. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if KINETIS_GPT_USE_PIT0 && !KINETIS_HAS_PIT0
|
||||
#error "PIT0 not present in the selected device"
|
||||
#endif
|
||||
|
||||
#if KINETIS_GPT_USE_PIT1 && !KINETIS_HAS_PIT1
|
||||
#error "PIT1 not present in the selected device"
|
||||
#endif
|
||||
|
||||
#if KINETIS_GPT_USE_PIT2 && !KINETIS_HAS_PIT2
|
||||
#error "PIT2 not present in the selected device"
|
||||
#endif
|
||||
|
||||
#if KINETIS_GPT_USE_PIT3 && !KINETIS_HAS_PIT3
|
||||
#error "PIT3 not present in the selected device"
|
||||
#endif
|
||||
|
||||
#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 && !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 && !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 && !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 && !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. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief GPT frequency type.
|
||||
*/
|
||||
typedef uint32_t gptfreq_t;
|
||||
|
||||
/**
|
||||
* @brief GPT counter type.
|
||||
*/
|
||||
typedef uint32_t gptcnt_t;
|
||||
|
||||
/**
|
||||
* @brief Driver configuration structure.
|
||||
* @note It could be empty on some architectures.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Timer clock in Hz.
|
||||
* @note The low level can use assertions in order to catch invalid
|
||||
* frequency specifications.
|
||||
*/
|
||||
gptfreq_t frequency;
|
||||
/**
|
||||
* @brief Timer callback pointer.
|
||||
* @note This callback is invoked on GPT counter events.
|
||||
* @note This callback can be set to @p NULL but in that case the
|
||||
* one-shot mode cannot be used.
|
||||
*/
|
||||
gptcallback_t callback;
|
||||
/* End of the mandatory fields.*/
|
||||
} GPTConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing a GPT driver.
|
||||
*/
|
||||
struct GPTDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
gptstate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const GPTConfig *config;
|
||||
#if defined(GPT_DRIVER_EXT_FIELDS)
|
||||
GPT_DRIVER_EXT_FIELDS
|
||||
#endif
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Timer base clock.
|
||||
*/
|
||||
uint32_t clock;
|
||||
/**
|
||||
* @brief Channel structure in PIT registers block.
|
||||
*/
|
||||
struct PIT_CHANNEL *channel;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Changes the interval of GPT peripheral.
|
||||
* @details This function changes the interval of a running GPT unit.
|
||||
* @pre The GPT unit must be running in continuous mode.
|
||||
* @post The GPT unit interval is changed to the new value.
|
||||
* @note The function has effect at the next cycle start.
|
||||
*
|
||||
* @param[in] gptp pointer to a @p GPTDriver object
|
||||
* @param[in] interval new cycle time in timer ticks
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define gpt_lld_change_interval(gptp, interval) \
|
||||
((gptp)->channel->LDVAL = (uint32_t)( \
|
||||
( (gptp)->clock / (gptp)->config->frequency ) * \
|
||||
( interval ) ))
|
||||
|
||||
/**
|
||||
* @brief Returns the interval of GPT peripheral.
|
||||
* @pre The GPT unit must be running in continuous mode.
|
||||
*
|
||||
* @param[in] gptp pointer to a @p GPTDriver object
|
||||
* @return The current interval.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#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.
|
||||
* @pre The GPT unit must be running in continuous mode.
|
||||
* @note The nature of the counter is not defined, it may count upward
|
||||
* or downward, it could be continuously running or not.
|
||||
*
|
||||
* @param[in] gptp pointer to a @p GPTDriver object
|
||||
* @return The current counter value.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define gpt_lld_get_counter(gptp) ((gptcnt_t)(gptp)->pit->CHANNEL[gptp->channel].CVAL)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if KINETIS_GPT_USE_PIT0 && !defined(__DOXYGEN__)
|
||||
extern GPTDriver GPTD1;
|
||||
#endif
|
||||
|
||||
#if KINETIS_GPT_USE_PIT1 && !defined(__DOXYGEN__)
|
||||
extern GPTDriver GPTD2;
|
||||
#endif
|
||||
|
||||
#if KINETIS_GPT_USE_PIT2 && !defined(__DOXYGEN__)
|
||||
extern GPTDriver GPTD3;
|
||||
#endif
|
||||
|
||||
#if KINETIS_GPT_USE_PIT3 && !defined(__DOXYGEN__)
|
||||
extern GPTDriver GPTD4;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void gpt_lld_init(void);
|
||||
void gpt_lld_start(GPTDriver *gptp);
|
||||
void gpt_lld_stop(GPTDriver *gptp);
|
||||
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t period);
|
||||
void gpt_lld_stop_timer(GPTDriver *gptp);
|
||||
void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_GPT */
|
||||
|
||||
#endif /* HAL_GPT_LLD_H_ */
|
||||
|
||||
/** @} */
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
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 PITv1/hal_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 */
|
||||
|
||||
/** @} */
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
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 PITv1/hal_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 HAL_ST_LLD_H_
|
||||
#define HAL_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 /* HAL_ST_LLD_H_ */
|
||||
|
||||
/** @} */
|
|
@ -0,0 +1,9 @@
|
|||
ifeq ($(USE_SMART_BUILD),yes)
|
||||
ifneq ($(findstring HAL_USE_SERIAL TRUE,$(HALCONF)),)
|
||||
PLATFORMSRC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/UARTv1/hal_serial_lld.c
|
||||
endif
|
||||
else
|
||||
PLATFORMSRC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/UARTv1/hal_serial_lld.c
|
||||
endif
|
||||
|
||||
PLATFORMINC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/UARTv1
|
|
@ -0,0 +1,693 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2013-2015 Fabio Utzig
|
||||
Copyright (C) 2017 Wim Lewis
|
||||
|
||||
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 UARTv1/hal_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
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART3 || defined(__DOXYGEN__)
|
||||
SerialDriver SD4;
|
||||
#endif
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART4 || defined(__DOXYGEN__)
|
||||
SerialDriver SD5;
|
||||
#endif
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART5 || defined(__DOXYGEN__)
|
||||
SerialDriver SD6;
|
||||
#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);
|
||||
|
||||
/* Clearing on K20x, K60x, and KL2x/UART>0 is done by reading S1 and
|
||||
* then reading D.*/
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(KL2x) && KINETIS_SERIAL_USE_UART0
|
||||
static void serve_error_interrupt_uart0(void) {
|
||||
SerialDriver *sdp = &SD1;
|
||||
UART_w_TypeDef *u = &(sdp->uart);
|
||||
uint8_t s1 = *(u->s1_p);
|
||||
|
||||
/* S1 bits are write-1-to-clear for UART0 on KL2x. */
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif /* KL2x && KINETIS_SERIAL_USE_UART0 */
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(KL2x) && KINETIS_SERIAL_USE_UART0
|
||||
if (sdp == &SD1) {
|
||||
serve_error_interrupt_uart0();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
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.
|
||||
*/
|
||||
static void notify(io_queue_t *qp)
|
||||
{
|
||||
preload(qp->q_link);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Common driver initialization, except LP.
|
||||
*/
|
||||
static void sd_lld_init_driver(SerialDriver *SDn, UART_TypeDef *UARTn) {
|
||||
/* Driver initialization.*/
|
||||
sdObjectInit(SDn, NULL, notify);
|
||||
SDn->uart.bdh_p = &(UARTn->BDH);
|
||||
SDn->uart.bdl_p = &(UARTn->BDL);
|
||||
SDn->uart.c1_p = &(UARTn->C1);
|
||||
SDn->uart.c2_p = &(UARTn->C2);
|
||||
SDn->uart.c3_p = &(UARTn->C3);
|
||||
SDn->uart.c4_p = &(UARTn->C4);
|
||||
SDn->uart.s1_p = (volatile uint8_t *)&(UARTn->S1);
|
||||
SDn->uart.s2_p = &(UARTn->S2);
|
||||
SDn->uart.d_p = &(UARTn->D);
|
||||
SDn->uart.uart_p = UARTn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) || defined(K60x) || defined(MK66F18) /* KL2x */
|
||||
|
||||
/* UARTs 0 and 1 are clocked from SYSCLK, others from BUSCLK on K20x and K60x. */
|
||||
#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) || defined(K60x)
|
||||
*(uart->c4_p) = UARTx_C4_BRFA(divisor) | (*(uart->c4_p) & ~UARTx_C4_BRFA_MASK);
|
||||
#endif /* K20x, K60x */
|
||||
|
||||
/* 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_SERIAL_USE_UART3 || defined(__DOXYGEN__)
|
||||
OSAL_IRQ_HANDLER(KINETIS_SERIAL3_IRQ_VECTOR) {
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
serve_interrupt(&SD4);
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART4 || defined(__DOXYGEN__)
|
||||
OSAL_IRQ_HANDLER(KINETIS_SERIAL4_IRQ_VECTOR) {
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
serve_interrupt(&SD5);
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART5 || defined(__DOXYGEN__)
|
||||
OSAL_IRQ_HANDLER(KINETIS_SERIAL5_IRQ_VECTOR) {
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
serve_interrupt(&SD6);
|
||||
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();
|
||||
#if defined(KL2x)
|
||||
serve_error_interrupt_uart0();
|
||||
#else
|
||||
serve_error_interrupt(&SD1);
|
||||
#endif
|
||||
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
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART3 || defined(__DOXYGEN__)
|
||||
OSAL_IRQ_HANDLER(KINETIS_SERIAL3_ERROR_IRQ_VECTOR) {
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
serve_error_interrupt(&SD4);
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART4 || defined(__DOXYGEN__)
|
||||
OSAL_IRQ_HANDLER(KINETIS_SERIAL4_ERROR_IRQ_VECTOR) {
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
serve_error_interrupt(&SD5);
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART5 || defined(__DOXYGEN__)
|
||||
OSAL_IRQ_HANDLER(KINETIS_SERIAL5_ERROR_IRQ_VECTOR) {
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
serve_error_interrupt(&SD6);
|
||||
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.*/
|
||||
#if ! KINETIS_SERIAL0_IS_LPUART
|
||||
sd_lld_init_driver(&SD1, (UART_TypeDef *)UART0);
|
||||
#else /* ! KINETIS_SERIAL0_IS_LPUART */
|
||||
/* little endian! */
|
||||
sdObjectInit(&SD1, NULL, notify);
|
||||
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.c4_p = &(UART0->C4); /* fix up misconfigured C4 register */
|
||||
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.*/
|
||||
#if ! KINETIS_SERIAL1_IS_LPUART
|
||||
sd_lld_init_driver(&SD2, UART1);
|
||||
#else /* ! KINETIS_SERIAL1_IS_LPUART */
|
||||
/* little endian! */
|
||||
sdObjectInit(&SD2, NULL, notify);
|
||||
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
|
||||
sd_lld_init_driver(&SD3, UART2);
|
||||
#endif /* KINETIS_SERIAL_USE_UART2 */
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART3
|
||||
sd_lld_init_driver(&SD4, UART3);
|
||||
#endif /* KINETIS_SERIAL_USE_UART3 */
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART4
|
||||
sd_lld_init_driver(&SD5, UART4);
|
||||
#endif /* KINETIS_SERIAL_USE_UART4 */
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART5
|
||||
sd_lld_init_driver(&SD6, UART5);
|
||||
#endif /* KINETIS_SERIAL_USE_UART5 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 */
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART3
|
||||
if (sdp == &SD4) {
|
||||
SIM->SCGC4 |= SIM_SCGC4_UART3;
|
||||
configure_uart(sdp, config);
|
||||
nvicEnableVector(UART3Status_IRQn, KINETIS_SERIAL_UART3_PRIORITY);
|
||||
nvicEnableVector(UART3Error_IRQn, KINETIS_SERIAL_UART3_PRIORITY);
|
||||
}
|
||||
#endif /* KINETIS_SERIAL_USE_UART3 */
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART4
|
||||
if (sdp == &SD5) {
|
||||
SIM->SCGC1 |= SIM_SCGC1_UART4;
|
||||
configure_uart(sdp, config);
|
||||
nvicEnableVector(UART4Status_IRQn, KINETIS_SERIAL_UART4_PRIORITY);
|
||||
nvicEnableVector(UART4Error_IRQn, KINETIS_SERIAL_UART4_PRIORITY);
|
||||
}
|
||||
#endif /* KINETIS_SERIAL_USE_UART4 */
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART5
|
||||
if (sdp == &SD6) {
|
||||
SIM->SCGC1 |= SIM_SCGC1_UART5;
|
||||
configure_uart(sdp, config);
|
||||
nvicEnableVector(UART5Status_IRQn, KINETIS_SERIAL_UART5_PRIORITY);
|
||||
nvicEnableVector(UART5Error_IRQn, KINETIS_SERIAL_UART5_PRIORITY);
|
||||
}
|
||||
#endif /* KINETIS_SERIAL_USE_UART5 */
|
||||
|
||||
}
|
||||
/* 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
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART3
|
||||
if (sdp == &SD4) {
|
||||
nvicDisableVector(UART3Status_IRQn);
|
||||
nvicDisableVector(UART3Error_IRQn);
|
||||
SIM->SCGC4 &= ~SIM_SCGC4_UART3;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART4
|
||||
if (sdp == &SD5) {
|
||||
nvicDisableVector(UART4Status_IRQn);
|
||||
nvicDisableVector(UART4Error_IRQn);
|
||||
SIM->SCGC1 &= ~SIM_SCGC1_UART4;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART5
|
||||
if (sdp == &SD6) {
|
||||
nvicDisableVector(UART5Status_IRQn);
|
||||
nvicDisableVector(UART5Error_IRQn);
|
||||
SIM->SCGC1 &= ~SIM_SCGC1_UART5;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_SERIAL */
|
||||
|
||||
/** @} */
|
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
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 UARTv1/hal_serial_lld.h
|
||||
* @brief Kinetis KL2x Serial Driver subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup SERIAL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_SERIAL_LLD_H_
|
||||
#define HAL_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 SD4 driver enable switch.
|
||||
* @details If set to @p TRUE the support for SD4 is included.
|
||||
*/
|
||||
#if !defined(KINETIS_SERIAL_USE_UART3) || defined(__DOXYGEN__)
|
||||
#define KINETIS_SERIAL_USE_UART3 FALSE
|
||||
#endif
|
||||
/**
|
||||
* @brief SD5 driver enable switch.
|
||||
* @details If set to @p TRUE the support for SD5 is included.
|
||||
*/
|
||||
#if !defined(KINETIS_SERIAL_USE_UART4) || defined(__DOXYGEN__)
|
||||
#define KINETIS_SERIAL_USE_UART4 FALSE
|
||||
#endif
|
||||
/**
|
||||
* @brief SD6 driver enable switch.
|
||||
* @details If set to @p TRUE the support for SD6 is included.
|
||||
*/
|
||||
#if !defined(KINETIS_SERIAL_USE_UART5) || defined(__DOXYGEN__)
|
||||
#define KINETIS_SERIAL_USE_UART5 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
|
||||
|
||||
/**
|
||||
* @brief UART3 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(KINETIS_SERIAL_UART3_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define KINETIS_SERIAL_UART3_PRIORITY 12
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART4 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(KINETIS_SERIAL_UART4_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define KINETIS_SERIAL_UART4_PRIORITY 12
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART5 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(KINETIS_SERIAL_UART5_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define KINETIS_SERIAL_UART5_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_UART3 && !KINETIS_HAS_SERIAL3
|
||||
#error "UART3 not present in the selected device"
|
||||
#endif
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART4 && !KINETIS_HAS_SERIAL4
|
||||
#error "UART4 not present in the selected device"
|
||||
#endif
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART5 && !KINETIS_HAS_SERIAL5
|
||||
#error "UART5 not present in the selected device"
|
||||
#endif
|
||||
|
||||
#if !(KINETIS_SERIAL_USE_UART0 || KINETIS_SERIAL_USE_UART1 || \
|
||||
KINETIS_SERIAL_USE_UART2 || KINETIS_SERIAL_USE_UART3 || \
|
||||
KINETIS_SERIAL_USE_UART4 || KINETIS_SERIAL_USE_UART5)
|
||||
#error "Serial driver activated but no UART peripheral assigned"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* 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 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.
|
||||
*/
|
||||
#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_w_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
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART3 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver SD4;
|
||||
#endif
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART4 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver SD5;
|
||||
#endif
|
||||
|
||||
#if KINETIS_SERIAL_USE_UART5 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver SD6;
|
||||
#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 /* HAL_SERIAL_LLD_H_ */
|
||||
|
||||
/** @} */
|
|
@ -0,0 +1,9 @@
|
|||
ifeq ($(USE_SMART_BUILD),yes)
|
||||
ifneq ($(findstring HAL_USE_USB TRUE,$(HALCONF)),)
|
||||
PLATFORMSRC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/USBHSv1/hal_usb_lld.c
|
||||
endif
|
||||
else
|
||||
PLATFORMSRC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/USBHSv1/hal_usb_lld.c
|
||||
endif
|
||||
|
||||
PLATFORMINC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/KINETIS/LLD/USBHSv1
|
|
@ -0,0 +1,873 @@
|
|||
/*
|
||||
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 USBHSv1/hal_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 receiving in the chibios state machine */
|
||||
(usbp)->receiving &= ~1;
|
||||
/* Call SETUP function (ChibiOS core), which prepares
|
||||
* for send or receive and releases the buffer
|
||||
*/
|
||||
_usb_isr_invoke_setup_cb(usbp, ep);
|
||||
/* When a setup packet is received, tx is suspended,
|
||||
* so it needs to be resumed here.
|
||||
*/
|
||||
USB0->CTL &= ~USBx_CTL_TXSUSPENDTOKENBUSY;
|
||||
} 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
|
||||
|
||||
/* Set USB clock source to MCGPLLCLK, MCGFLLCLK, USB1 PFD, or IRC48M */
|
||||
SIM->SOPT2 |= SIM_SOPT2_USBSRC;
|
||||
|
||||
#if defined(K20x5) || defined(K20x7) || defined(MK66F18)
|
||||
|
||||
#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
|
||||
|
||||
#if !defined(MK66F18)
|
||||
/* Note: We don't need this for MK66F18, we can use IRC48M clock for USB */
|
||||
#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:
|
||||
osalDbgAssert(i<2 && j <8,"USB Init error");
|
||||
#endif
|
||||
|
||||
#else /* KINETIS_MCG_MODE == KINETIS_MCG_MODE_PEE */
|
||||
#error USB clock setting not implemented for this KINETIS_MCG_MODE
|
||||
#endif /* KINETIS_MCG_MODE == ... */
|
||||
|
||||
#if defined(MK66F18)
|
||||
/* Switch from default MCGPLLCLK to IRC48M for USB */
|
||||
SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(0);
|
||||
SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_SET(3);
|
||||
#endif
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
#if defined(MK66F18)
|
||||
/* Disable the USB current limiter */
|
||||
SIM->USBPHYCTL |= SIM_USBPHYCTL_USBDISILIM;
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
* Release the current DATA0 buffer
|
||||
*/
|
||||
bd->desc = BDT_DESC(usbp->epc[ep]->out_maxsize,DATA0);
|
||||
/* If DATA1 was expected, then the states are out of sync.
|
||||
* So reset the other buffer too, and set it as DATA1.
|
||||
* This should not happen in normal cases, but is possible in
|
||||
* error situations. NOTE: it's possible that this is too late
|
||||
* and the next packet has already been received and dropped, but
|
||||
* there's nothing that we can do about that anymore at this point.
|
||||
*/
|
||||
if (os->data_bank == DATA1)
|
||||
{
|
||||
bd_t *bd_next = (bd_t*)&_bdt[BDT_INDEX(ep, RX, os->odd_even^ODD)];
|
||||
bd_next->desc = BDT_DESC(usbp->epc[ep]->out_maxsize,DATA1);
|
||||
}
|
||||
/* After a SETUP, both in and out are always DATA1 */
|
||||
usbp->epc[ep]->in_state->data_bank = 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) {
|
||||
if (ep == 0 && usbp->ep0state == USB_EP0_IN_SENDING_STS) {
|
||||
/* When a status packet is about to be sent on endpoint 0 the
|
||||
* next packet will be a setup packet, which means that the
|
||||
* buffer we expect after this should be DATA0, and the following
|
||||
* DATA1. Since no out packets should be in flight at this time
|
||||
* it's safe to initialize the buffers according to the expectations
|
||||
* here.
|
||||
*/
|
||||
const USBEndpointConfig* epc = usbp->epc[ep];
|
||||
bd_t * bd = (bd_t*)&_bdt[BDT_INDEX(ep, RX, epc->out_state->odd_even)];
|
||||
bd_t *bd_next = (bd_t*)&_bdt[BDT_INDEX(ep, RX, epc->out_state->odd_even^ODD)];
|
||||
|
||||
bd->desc = BDT_DESC(usbp->epc[ep]->out_maxsize,DATA1);
|
||||
bd_next->desc = BDT_DESC(usbp->epc[ep]->out_maxsize,DATA0);
|
||||
epc->out_state->data_bank = DATA0;
|
||||
}
|
||||
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 */
|
||||
|
||||
/** @} */
|
|
@ -0,0 +1,455 @@
|
|||
/*
|
||||
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 USBHSv1/hal_usb_lld.h
|
||||
* @brief KINETIS USB subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup USB
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_USB_LLD_H_
|
||||
#define HAL_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
|
||||
|
||||
/**
|
||||
* @brief Host wake-up procedure duration.
|
||||
*/
|
||||
#if !defined(USB_HOST_WAKEUP_DURATION) || defined(__DOXYGEN__)
|
||||
#define USB_HOST_WAKEUP_DURATION 2
|
||||
#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
|
||||
|
||||
#if (USB_HOST_WAKEUP_DURATION < 2) || (USB_HOST_WAKEUP_DURATION > 15)
|
||||
#error "invalid USB_HOST_WAKEUP_DURATION setting, it must be between 2 and 15"
|
||||
#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;
|
||||
/**
|
||||
* @brief State of the driver when a suspend happened.
|
||||
*/
|
||||
usbstate_t saved_state;
|
||||
#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
|
||||
|
||||
/**
|
||||
* @brief Start of host wake-up procedure.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define usb_lld_wakeup_host(usbp) \
|
||||
do{ \
|
||||
USB0->CTL |= USBx_CTL_RESUME; \
|
||||
osalThreadSleepMilliseconds(USB_HOST_WAKEUP_DURATION); \
|
||||
USB0->CTL &= ~USBx_CTL_RESUME; \
|
||||
} while (false)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* 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 /* HAL_USB_LLD_H_ */
|
||||
|
||||
/** @} */
|
Loading…
Reference in New Issue