ChibiOS 2.6.8, until I can figure out where to get it from git.

This commit is contained in:
Jared Boone
2015-07-08 08:40:23 -07:00
parent dc6fee8370
commit e1eea8e08a
1929 changed files with 575326 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,832 @@
/*
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
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 SPC5xx/edma.h
* @brief EDMA helper driver header.
*
* @addtogroup SPC5xx_EDMA
* @{
*/
#ifndef _SPC5_EDMA_H_
#define _SPC5_EDMA_H_
#if SPC5_HAS_EDMA
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief EDMA channel allocation error.
*/
#define EDMA_ERROR -1
/**
* @name EDMA mode constants
* @{
*/
#define EDMA_TCD_MODE_START (1U << 0)
#define EDMA_TCD_MODE_INT_END (1U << 1)
#define EDMA_TCD_MODE_INT_HALF (1U << 2)
#define EDMA_TCD_MODE_DREQ (1U << 3)
#define EDMA_TCD_MODE_ACTIVE (1U << 6)
#define EDMA_TCD_MODE_DONE (1U << 7)
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief Default EDMA CR register initialization.
*/
#if !defined(SPC5_EDMA_ERROR_HANDLER) || defined(__DOXYGEN__)
#define SPC5_EDMA_CR_SETTING 0x0000C400
#endif
/**
* @brief EDMA critical error handler, must not return.
*/
#if !defined(SPC5_EDMA_ERROR_HANDLER) || defined(__DOXYGEN__)
#define SPC5_EDMA_ERROR_HANDLER() chSysHalt()
#endif
/**
* @brief EDMA error handler IRQ priority.
*/
#if !defined(SPC5_EDMA_ERROR_IRQ_PRIO) || defined(__DOXYGEN__)
#define SPC5_EDMA_ERROR_IRQ_PRIO 12
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of and eDMA channel number.
*/
typedef int32_t edma_channel_t;
/**
* @brief Type of an eDMA TCD.
*/
typedef struct {
union {
uint32_t word[8];
};
} edma_tcd_t;
/**
* @brief Type of an eDMA peripheral.
*/
typedef struct {
union {
vuint32_t R;
struct {
vuint32_t :14;
vuint32_t CX :1;
vuint32_t ECX :1;
vuint32_t GRP3PRI :2;
vuint32_t GRP2PRI :2;
vuint32_t GRP1PRI :2;
vuint32_t GRP0PRI :2;
vuint32_t EMLM :1;
vuint32_t CLM :1;
vuint32_t HALT :1;
vuint32_t HOE :1;
vuint32_t ERGA :1;
vuint32_t ERCA :1;
vuint32_t EDBG :1;
vuint32_t :1;
} B;
} CR; /* DMA Control Register @baseaddress + 0x0 */
union {
vuint32_t R;
struct {
vuint32_t VLD :1;
vuint32_t :14;
vuint32_t ECX :1;
vuint32_t GPE :1;
vuint32_t CPE :1;
vuint32_t ERRCHN :6;
vuint32_t SAE :1;
vuint32_t SOE :1;
vuint32_t DAE :1;
vuint32_t DOE :1;
vuint32_t NCE :1;
vuint32_t SGE :1;
vuint32_t SBE :1;
vuint32_t DBE :1;
} B;
} ESR; /* Error Status Register @baseaddress + 0x4 */
union {
vuint32_t R;
struct {
vuint32_t ERQ63 :1;
vuint32_t ERQ62 :1;
vuint32_t ERQ61 :1;
vuint32_t ERQ60 :1;
vuint32_t ERQ59 :1;
vuint32_t ERQ58 :1;
vuint32_t ERQ57 :1;
vuint32_t ERQ56 :1;
vuint32_t ERQ55 :1;
vuint32_t ERQ54 :1;
vuint32_t ERQ53 :1;
vuint32_t ERQ52 :1;
vuint32_t ERQ51 :1;
vuint32_t ERQ50 :1;
vuint32_t ERQ49 :1;
vuint32_t ERQ48 :1;
vuint32_t ERQ47 :1;
vuint32_t ERQ46 :1;
vuint32_t ERQ45 :1;
vuint32_t ERQ44 :1;
vuint32_t ERQ43 :1;
vuint32_t ERQ42 :1;
vuint32_t ERQ41 :1;
vuint32_t ERQ40 :1;
vuint32_t ERQ39 :1;
vuint32_t ERQ38 :1;
vuint32_t ERQ37 :1;
vuint32_t ERQ36 :1;
vuint32_t ERQ35 :1;
vuint32_t ERQ34 :1;
vuint32_t ERQ33 :1;
vuint32_t ERQ32 :1;
} B;
} ERQRH; /* DMA Enable Request Register High @baseaddress + 0x8*/
union {
vuint32_t R;
struct {
vuint32_t ERQ31 :1;
vuint32_t ERQ30 :1;
vuint32_t ERQ29 :1;
vuint32_t ERQ28 :1;
vuint32_t ERQ27 :1;
vuint32_t ERQ26 :1;
vuint32_t ERQ25 :1;
vuint32_t ERQ24 :1;
vuint32_t ERQ23 :1;
vuint32_t ERQ22 :1;
vuint32_t ERQ21 :1;
vuint32_t ERQ20 :1;
vuint32_t ERQ19 :1;
vuint32_t ERQ18 :1;
vuint32_t ERQ17 :1;
vuint32_t ERQ16 :1;
vuint32_t ERQ15 :1;
vuint32_t ERQ14 :1;
vuint32_t ERQ13 :1;
vuint32_t ERQ12 :1;
vuint32_t ERQ11 :1;
vuint32_t ERQ10 :1;
vuint32_t ERQ09 :1;
vuint32_t ERQ08 :1;
vuint32_t ERQ07 :1;
vuint32_t ERQ06 :1;
vuint32_t ERQ05 :1;
vuint32_t ERQ04 :1;
vuint32_t ERQ03 :1;
vuint32_t ERQ02 :1;
vuint32_t ERQ01 :1;
vuint32_t ERQ00 :1;
} B;
} ERQRL; /* DMA Enable Request Register Low @baseaddress + 0xC*/
union {
vuint32_t R;
struct {
vuint32_t EEI63 :1;
vuint32_t EEI62 :1;
vuint32_t EEI61 :1;
vuint32_t EEI60 :1;
vuint32_t EEI59 :1;
vuint32_t EEI58 :1;
vuint32_t EEI57 :1;
vuint32_t EEI56 :1;
vuint32_t EEI55 :1;
vuint32_t EEI54 :1;
vuint32_t EEI53 :1;
vuint32_t EEI52 :1;
vuint32_t EEI51 :1;
vuint32_t EEI50 :1;
vuint32_t EEI49 :1;
vuint32_t EEI48 :1;
vuint32_t EEI47 :1;
vuint32_t EEI46 :1;
vuint32_t EEI45 :1;
vuint32_t EEI44 :1;
vuint32_t EEI43 :1;
vuint32_t EEI42 :1;
vuint32_t EEI41 :1;
vuint32_t EEI40 :1;
vuint32_t EEI39 :1;
vuint32_t EEI38 :1;
vuint32_t EEI37 :1;
vuint32_t EEI36 :1;
vuint32_t EEI35 :1;
vuint32_t EEI34 :1;
vuint32_t EEI33 :1;
vuint32_t EEI32 :1;
} B;
} EEIRH; /* DMA Enable Error Interrupt Register High @baseaddress + 0x10*/
union {
vuint32_t R;
struct {
vuint32_t EEI31 :1;
vuint32_t EEI30 :1;
vuint32_t EEI29 :1;
vuint32_t EEI28 :1;
vuint32_t EEI27 :1;
vuint32_t EEI26 :1;
vuint32_t EEI25 :1;
vuint32_t EEI24 :1;
vuint32_t EEI23 :1;
vuint32_t EEI22 :1;
vuint32_t EEI21 :1;
vuint32_t EEI20 :1;
vuint32_t EEI19 :1;
vuint32_t EEI18 :1;
vuint32_t EEI17 :1;
vuint32_t EEI16 :1;
vuint32_t EEI15 :1;
vuint32_t EEI14 :1;
vuint32_t EEI13 :1;
vuint32_t EEI12 :1;
vuint32_t EEI11 :1;
vuint32_t EEI10 :1;
vuint32_t EEI09 :1;
vuint32_t EEI08 :1;
vuint32_t EEI07 :1;
vuint32_t EEI06 :1;
vuint32_t EEI05 :1;
vuint32_t EEI04 :1;
vuint32_t EEI03 :1;
vuint32_t EEI02 :1;
vuint32_t EEI01 :1;
vuint32_t EEI00 :1;
} B;
} EEIRL; /* DMA Enable Error Interrupt Register Low @baseaddress + 0x14*/
union {
vuint8_t R;
struct {
vuint8_t NOP :1;
vuint8_t SERQ :7;
} B;
} SERQR; /* DMA Set Enable Request Register @baseaddress + 0x18*/
union {
vuint8_t R;
struct {
vuint8_t NOP :1;
vuint8_t CERQ :7;
} B;
} CERQR; /* DMA Clear Enable Request Register @baseaddress + 0x19*/
union {
vuint8_t R;
struct {
vuint8_t NOP :1;
vuint8_t SEEI :7;
} B;
} SEEIR; /* DMA Set Enable Error Interrupt Register @baseaddress + 0x1A*/
union {
vuint8_t R;
struct {
vuint8_t NOP :1;
vuint8_t CEEI :7;
} B;
} CEEIR; /* DMA Clear Enable Error Interrupt Register @baseaddress + 0x1B*/
union {
vuint8_t R;
struct {
vuint8_t NOP :1;
vuint8_t CINT :7;
} B;
} CIRQR; /* DMA Clear Interrupt Request Register @baseaddress + 0x1C */
union {
vuint8_t R;
struct {
vuint8_t NOP :1;
vuint8_t CERR :7;
} B;
} CER; /* DMA Clear error Register @baseaddress + 0x1D */
union {
vuint8_t R;
struct {
vuint8_t NOP :1;
vuint8_t SSB :7;
} B;
} SSBR; /* Set Start Bit Register @baseaddress + 0x1E */
union {
vuint8_t R;
struct {
vuint8_t NOP :1;
vuint8_t CDSB :7;
} B;
} CDSBR; /* Clear Done Status Bit Register @baseaddress + 0x1F */
union {
vuint32_t R;
struct {
vuint32_t INT63 :1;
vuint32_t INT62 :1;
vuint32_t INT61 :1;
vuint32_t INT60 :1;
vuint32_t INT59 :1;
vuint32_t INT58 :1;
vuint32_t INT57 :1;
vuint32_t INT56 :1;
vuint32_t INT55 :1;
vuint32_t INT54 :1;
vuint32_t INT53 :1;
vuint32_t INT52 :1;
vuint32_t INT51 :1;
vuint32_t INT50 :1;
vuint32_t INT49 :1;
vuint32_t INT48 :1;
vuint32_t INT47 :1;
vuint32_t INT46 :1;
vuint32_t INT45 :1;
vuint32_t INT44 :1;
vuint32_t INT43 :1;
vuint32_t INT42 :1;
vuint32_t INT41 :1;
vuint32_t INT40 :1;
vuint32_t INT39 :1;
vuint32_t INT38 :1;
vuint32_t INT37 :1;
vuint32_t INT36 :1;
vuint32_t INT35 :1;
vuint32_t INT34 :1;
vuint32_t INT33 :1;
vuint32_t INT32 :1;
} B;
} IRQRH; /* DMA Interrupt Request High @baseaddress + 0x20 */
union {
vuint32_t R;
struct {
vuint32_t INT31 :1;
vuint32_t INT30 :1;
vuint32_t INT29 :1;
vuint32_t INT28 :1;
vuint32_t INT27 :1;
vuint32_t INT26 :1;
vuint32_t INT25 :1;
vuint32_t INT24 :1;
vuint32_t INT23 :1;
vuint32_t INT22 :1;
vuint32_t INT21 :1;
vuint32_t INT20 :1;
vuint32_t INT19 :1;
vuint32_t INT18 :1;
vuint32_t INT17 :1;
vuint32_t INT16 :1;
vuint32_t INT15 :1;
vuint32_t INT14 :1;
vuint32_t INT13 :1;
vuint32_t INT12 :1;
vuint32_t INT11 :1;
vuint32_t INT10 :1;
vuint32_t INT09 :1;
vuint32_t INT08 :1;
vuint32_t INT07 :1;
vuint32_t INT06 :1;
vuint32_t INT05 :1;
vuint32_t INT04 :1;
vuint32_t INT03 :1;
vuint32_t INT02 :1;
vuint32_t INT01 :1;
vuint32_t INT00 :1;
} B;
} IRQRL; /* DMA Interrupt Request Low @baseaddress + 0x24 */
union {
vuint32_t R;
struct {
vuint32_t ERR63 :1;
vuint32_t ERR62 :1;
vuint32_t ERR61 :1;
vuint32_t ERR60 :1;
vuint32_t ERR59 :1;
vuint32_t ERR58 :1;
vuint32_t ERR57 :1;
vuint32_t ERR56 :1;
vuint32_t ERR55 :1;
vuint32_t ERR54 :1;
vuint32_t ERR53 :1;
vuint32_t ERR52 :1;
vuint32_t ERR51 :1;
vuint32_t ERR50 :1;
vuint32_t ERR49 :1;
vuint32_t ERR48 :1;
vuint32_t ERR47 :1;
vuint32_t ERR46 :1;
vuint32_t ERR45 :1;
vuint32_t ERR44 :1;
vuint32_t ERR43 :1;
vuint32_t ERR42 :1;
vuint32_t ERR41 :1;
vuint32_t ERR40 :1;
vuint32_t ERR39 :1;
vuint32_t ERR38 :1;
vuint32_t ERR37 :1;
vuint32_t ERR36 :1;
vuint32_t ERR35 :1;
vuint32_t ERR34 :1;
vuint32_t ERR33 :1;
vuint32_t ERR32 :1;
} B;
} ERH; /* DMA Error High @baseaddress + 0x28 */
union {
vuint32_t R;
struct {
vuint32_t ERR31 :1;
vuint32_t ERR30 :1;
vuint32_t ERR29 :1;
vuint32_t ERR28 :1;
vuint32_t ERR27 :1;
vuint32_t ERR26 :1;
vuint32_t ERR25 :1;
vuint32_t ERR24 :1;
vuint32_t ERR23 :1;
vuint32_t ERR22 :1;
vuint32_t ERR21 :1;
vuint32_t ERR20 :1;
vuint32_t ERR19 :1;
vuint32_t ERR18 :1;
vuint32_t ERR17 :1;
vuint32_t ERR16 :1;
vuint32_t ERR15 :1;
vuint32_t ERR14 :1;
vuint32_t ERR13 :1;
vuint32_t ERR12 :1;
vuint32_t ERR11 :1;
vuint32_t ERR10 :1;
vuint32_t ERR09 :1;
vuint32_t ERR08 :1;
vuint32_t ERR07 :1;
vuint32_t ERR06 :1;
vuint32_t ERR05 :1;
vuint32_t ERR04 :1;
vuint32_t ERR03 :1;
vuint32_t ERR02 :1;
vuint32_t ERR01 :1;
vuint32_t ERR00 :1;
} B;
} ERL; /* DMA Error Low @baseaddress + 0x2C */
union {
vuint32_t R;
struct {
vuint32_t HRS63 :1;
vuint32_t HRS62 :1;
vuint32_t HRS61 :1;
vuint32_t HRS60 :1;
vuint32_t HRS59 :1;
vuint32_t HRS58 :1;
vuint32_t HRS57 :1;
vuint32_t HRS56 :1;
vuint32_t HRS55 :1;
vuint32_t HRS54 :1;
vuint32_t HRS53 :1;
vuint32_t HRS52 :1;
vuint32_t HRS51 :1;
vuint32_t HRS50 :1;
vuint32_t HRS49 :1;
vuint32_t HRS48 :1;
vuint32_t HRS47 :1;
vuint32_t HRS46 :1;
vuint32_t HRS45 :1;
vuint32_t HRS44 :1;
vuint32_t HRS43 :1;
vuint32_t HRS42 :1;
vuint32_t HRS41 :1;
vuint32_t HRS40 :1;
vuint32_t HRS39 :1;
vuint32_t HRS38 :1;
vuint32_t HRS37 :1;
vuint32_t HRS36 :1;
vuint32_t HRS35 :1;
vuint32_t HRS34 :1;
vuint32_t HRS33 :1;
vuint32_t HRS32 :1;
} B;
} HRSH; /* hardware request status high @baseaddress + 0x30 */
union {
vuint32_t R;
struct {
vuint32_t HRS31 :1;
vuint32_t HRS30 :1;
vuint32_t HRS29 :1;
vuint32_t HRS28 :1;
vuint32_t HRS27 :1;
vuint32_t HRS26 :1;
vuint32_t HRS25 :1;
vuint32_t HRS24 :1;
vuint32_t HRS23 :1;
vuint32_t HRS22 :1;
vuint32_t HRS21 :1;
vuint32_t HRS20 :1;
vuint32_t HRS19 :1;
vuint32_t HRS18 :1;
vuint32_t HRS17 :1;
vuint32_t HRS16 :1;
vuint32_t HRS15 :1;
vuint32_t HRS14 :1;
vuint32_t HRS13 :1;
vuint32_t HRS12 :1;
vuint32_t HRS11 :1;
vuint32_t HRS10 :1;
vuint32_t HRS09 :1;
vuint32_t HRS08 :1;
vuint32_t HRS07 :1;
vuint32_t HRS06 :1;
vuint32_t HRS05 :1;
vuint32_t HRS04 :1;
vuint32_t HRS03 :1;
vuint32_t HRS02 :1;
vuint32_t HRS01 :1;
vuint32_t HRS00 :1;
} B;
} HRSL; /* hardware request status low @baseaddress + 0x34 */
uint32_t eDMA_reserved0038[50]; /* 0x0038-0x00FF */
union {
vuint8_t R;
struct {
vuint8_t ECP :1;
vuint8_t DPA :1;
vuint8_t GRPPRI :2;
vuint8_t CHPRI :4;
} B;
} CPR[64]; /* Channel n Priority @baseaddress + 0x100 */
uint32_t eDMA_reserved0140[944]; /* 0x0140-0x0FFF */
edma_tcd_t TCD[64];
} edma_t;
/**
* @brief DMA callback type.
*
* @param[in] channel the channel number
* @param[in] p parameter for the registered function
*/
typedef void (*edma_callback_t)(edma_channel_t channel, void *p);
/**
* @brief DMA error callback type.
*
* @param[in] channel the channel number
* @param[in] p parameter for the registered function
* @param[in] esr content of the ESR register
*/
typedef void (*edma_error_callback_t)(edma_channel_t channel,
void *p,
uint32_t esr);
/**
* @brief Type of an EDMA channel configuration structure.
*/
typedef struct {
uint8_t dma_periph; /**< @brief Peripheral to be
associated to the channel. */
uint8_t dma_prio; /**< @brief Priority register value
for this channel. */
uint8_t dma_irq_prio; /**< @brief IRQ priority level for
this channel. */
edma_callback_t dma_func; /**< @brief Channel callback,
can be NULL if not required. */
edma_error_callback_t dma_error_func; /**< @brief Channel error callback,
can be NULL if not required. */
void *dma_param; /**< @brief Channel callback param. */
} edma_channel_config_t;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name eDMA units references
* @{
*/
#if SPC5_HAS_EDMA || defined(__DOXYGEN__)
#define SPC5_EDMA (*(edma_t *)0xFFF44000U)
#endif
/** @} */
/**
* @brief Returns the TCD address associated to a channel.
*
* @param[in] channel the channel number
* @return A pointer to an @p edma_tcd_t structure.
*
* @api
*/
#define edmaGetTCD(channel) ((edma_tcd_t *)&SPC5_EDMA.TCD[channel])
/**
* @brief Sets the word 0 fields into a TCD.
*
* @param[in] tcdp pointer to an @p edma_tcd_t structure
* @param[in] src the source address
*
* @api
*/
#define edmaTCDSetWord0(tcdp, src) \
((tcdp)->word[0] = (uint32_t)(src))
/**
* @brief Sets the word 1 fields into a TCD.
*
* @param[in] tcdp pointer to an @p edma_tcd_t structure
* @param[in] ssize the source width
* @param[in] dst the destination width
* @param[in] soff the source increment value
*
* @api
*/
#define edmaTCDSetWord1(tcdp, ssize, dsize, soff) \
((tcdp)->word[1] = (((uint32_t)(ssize) << 24) | \
((uint32_t)(dsize) << 16) | \
((uint32_t)(soff) << 0)))
/**
* @brief Sets the word 2 fields into a TCD.
*
* @param[in] tcdp pointer to an @p edma_tcd_t structure
* @param[in] nbytes the inner counter value
*
* @api
*/
#define edmaTCDSetWord2(tcdp, nbytes) \
((tcdp)->word[2] = (uint32_t)(nbytes))
/**
* @brief Sets the word 3 fields into a TCD.
*
* @param[in] tcdp pointer to an @p edma_tcd_t structure
* @param[in] slast the adjustment value
*
* @api
*/
#define edmaTCDSetWord3(tcdp, slast) \
((tcdp)->word[3] = (uint32_t)(slast))
/**
* @brief Sets the word 4 fields into a TCD.
*
* @param[in] tcdp pointer to an @p edma_tcd_t structure
* @param[in] dst the destination address
*
* @api
*/
#define edmaTCDSetWord4(tcdp, dst) \
((tcdp)->word[4] = (uint32_t)(dst))
/**
* @brief Sets the word 5 fields into a TCD.
*
* @param[in] tcdp pointer to an @p edma_tcd_t structure
* @param[in] citer the current outer counter value
* @param[in] doff the destination increment value
*
* @api
*/
#define edmaTCDSetWord5(tcdp, citer, doff) \
((tcdp)->word[5] = (((uint32_t)(citer) << 16) | \
((uint32_t)(doff) << 0)))
/**
* @brief Sets the word 6 fields into a TCD.
*
* @param[in] tcdp pointer to an @p edma_tcd_t structure
* @param[in] dlast the adjustment value
*
* @api
*/
#define edmaTCDSetWord6(tcdp, dlast) \
((tcdp)->word[6] = (uint32_t)(dlast))
/**
* @brief Sets the word 7 fields into a TCD.
*
* @param[in] tcdp pointer to an @p edma_tcd_t structure
* @param[in] biter the base outer counter value
* @param[in] mode the mode value
*
* @api
*/
#define edmaTCDSetWord7(tcdp, biter, mode) \
((tcdp)->word[7] = (((uint32_t)(biter) << 16) | \
((uint32_t)(mode) << 0)))
/**
* @brief Starts or restarts an EDMA channel.
*
* @param[in] channel the channel number
*
* @api
*/
#define edmaChannelStart(channel) (SPC5_EDMA.SERQR.R = (channel))
/**
* @brief Stops an EDMA channel.
*
* @param[in] channel the channel number
*
* @api
*/
#define edmaChannelStop(channel) { \
SPC5_EDMA.CERQR.R = (channel); \
SPC5_EDMA.CDSBR.R = (channel); \
}
/**
* @brief EDMA channel setup.
*
* @param[in] channel eDMA channel number
* @param[in] src source address
* @param[in] dst destination address
* @param[in] soff source address offset
* @param[in] doff destination address offset
* @param[in] ssize source transfer size
* @param[in] dsize destination transfer size
* @param[in] nbytes minor loop count
* @param[in] iter major loop count
* @param[in] dlast last destination address adjustment
* @param[in] slast last source address adjustment
* @param[in] mode LSW of TCD register 7
*
* @api
*/
#define edmaChannelSetup(channel, src, dst, soff, doff, ssize, dsize, \
nbytes, iter, slast, dlast, mode) { \
edma_tcd_t *tcdp = edmaGetTCD(channel); \
edmaTCDSetWord0(tcdp, src); \
edmaTCDSetWord1(tcdp, ssize, dsize, soff); \
edmaTCDSetWord2(tcdp, nbytes); \
edmaTCDSetWord3(tcdp, slast); \
edmaTCDSetWord4(tcdp, dst); \
edmaTCDSetWord5(tcdp, iter, doff); \
edmaTCDSetWord6(tcdp, dlast); \
edmaTCDSetWord7(tcdp, iter, mode); \
}
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void edmaInit(void);
edma_channel_t edmaChannelAllocate(const edma_channel_config_t *ccfg);
void edmaChannelRelease(edma_channel_t channel);
#ifdef __cplusplus
}
#endif
#endif /* SPC5_HAS_EDMA */
#endif /* _SPC5_EDMA_H_ */
/** @} */
+744
View File
@@ -0,0 +1,744 @@
/*
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
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 SPC5xx/EQADC_v1/adc_lld.c
* @brief SPC5xx low level ADC driver code.
*
* @addtogroup ADC
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_ADC || defined(__DOXYGEN__)
/* Some forward declarations.*/
static void adc_serve_rfifo_irq(edma_channel_t channel, void *p);
static void adc_serve_dma_error_irq(edma_channel_t channel,
void *p,
uint32_t esr);
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/**
* @brief Calibration constant.
* @details Ideal conversion result for 75%(VRH - VRL) minus 2.
*/
#define ADC_IDEAL_RES75_2 12286
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief ADCD1 driver identifier.
*/
#if SPC5_ADC_USE_ADC0_Q0 || defined(__DOXYGEN__)
ADCDriver ADCD1;
#endif
/**
* @brief ADCD2 driver identifier.
*/
#if SPC5_ADC_USE_ADC0_Q1 || defined(__DOXYGEN__)
ADCDriver ADCD2;
#endif
/**
* @brief ADCD3 driver identifier.
*/
#if SPC5_ADC_USE_ADC0_Q2 || defined(__DOXYGEN__)
ADCDriver ADCD3;
#endif
/**
* @brief ADCD4 driver identifier.
*/
#if SPC5_ADC_USE_ADC1_Q3 || defined(__DOXYGEN__)
ADCDriver ADCD4;
#endif
/**
* @brief ADCD5 driver identifier.
*/
#if SPC5_ADC_USE_ADC1_Q4 || defined(__DOXYGEN__)
ADCDriver ADCD5;
#endif
/**
* @brief ADCD6 driver identifier.
*/
#if SPC5_ADC_USE_ADC1_Q5 || defined(__DOXYGEN__)
ADCDriver ADCD6;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/**
* @brief Number of active ADC FIFOs.
*/
static uint32_t adc_active_fifos;
/**
* @brief Static setup for input resistors.
*/
static const uint16_t pudcrs[8] = SPC5_ADC_PUDCR;
#if SPC5_ADC_USE_ADC0_Q0 || defined(__DOXYGEN__)
/**
* @brief DMA configuration for EQADC CFIFO0.
*/
static const edma_channel_config_t adc_cfifo0_dma_config = {
0, SPC5_ADC_FIFO0_DMA_PRIO, SPC5_ADC_FIFO0_DMA_IRQ_PRIO,
NULL, adc_serve_dma_error_irq, &ADCD1
};
/**
* @brief DMA configuration for EQADC RFIFO0.
*/
static const edma_channel_config_t adc_rfifo0_dma_config = {
1, SPC5_ADC_FIFO0_DMA_PRIO, SPC5_ADC_FIFO0_DMA_IRQ_PRIO,
adc_serve_rfifo_irq, adc_serve_dma_error_irq, &ADCD1
};
#endif /* SPC5_ADC_USE_ADC0_Q0 */
#if SPC5_ADC_USE_ADC0_Q1 || defined(__DOXYGEN__)
/**
* @brief DMA configuration for EQADC CFIFO1.
*/
static const edma_channel_config_t adc_cfifo1_dma_config = {
2, SPC5_ADC_FIFO1_DMA_PRIO, SPC5_ADC_FIFO1_DMA_IRQ_PRIO,
NULL, adc_serve_dma_error_irq, &ADCD2
};
/**
* @brief DMA configuration for EQADC RFIFO1.
*/
static const edma_channel_config_t adc_rfifo1_dma_config = {
3, SPC5_ADC_FIFO1_DMA_PRIO, SPC5_ADC_FIFO1_DMA_IRQ_PRIO,
adc_serve_rfifo_irq, adc_serve_dma_error_irq, &ADCD2
};
#endif /* SPC5_ADC_USE_ADC0_Q1 */
#if SPC5_ADC_USE_ADC0_Q2 || defined(__DOXYGEN__)
/**
* @brief DMA configuration for EQADC CFIFO2.
*/
static const edma_channel_config_t adc_cfifo2_dma_config = {
4, SPC5_ADC_FIFO2_DMA_PRIO, SPC5_ADC_FIFO2_DMA_IRQ_PRIO,
NULL, adc_serve_dma_error_irq, &ADCD3
};
/**
* @brief DMA configuration for EQADC RFIFO2.
*/
static const edma_channel_config_t adc_rfifo2_dma_config = {
5, SPC5_ADC_FIFO2_DMA_PRIO, SPC5_ADC_FIFO2_DMA_IRQ_PRIO,
adc_serve_rfifo_irq, adc_serve_dma_error_irq, &ADCD3
};
#endif /* SPC5_ADC_USE_ADC0_Q2 */
#if SPC5_ADC_USE_ADC1_Q3 || defined(__DOXYGEN__)
/**
* @brief DMA configuration for EQADC CFIFO3.
*/
static const edma_channel_config_t adc_cfifo3_dma_config = {
6, SPC5_ADC_FIFO3_DMA_PRIO, SPC5_ADC_FIFO3_DMA_IRQ_PRIO,
NULL, adc_serve_dma_error_irq, &ADCD4
};
/**
* @brief DMA configuration for EQADC RFIFO3.
*/
static const edma_channel_config_t adc_rfifo3_dma_config = {
7, SPC5_ADC_FIFO3_DMA_PRIO, SPC5_ADC_FIFO3_DMA_IRQ_PRIO,
adc_serve_rfifo_irq, adc_serve_dma_error_irq, &ADCD4
};
#endif /* SPC5_ADC_USE_ADC1_Q3 */
#if SPC5_ADC_USE_ADC1_Q4 || defined(__DOXYGEN__)
/**
* @brief DMA configuration for EQADC CFIFO4.
*/
static const edma_channel_config_t adc_cfifo4_dma_config = {
8, SPC5_ADC_FIFO4_DMA_PRIO, SPC5_ADC_FIFO4_DMA_IRQ_PRIO,
NULL, adc_serve_dma_error_irq, &ADCD5
};
/**
* @brief DMA configuration for EQADC RFIFO4.
*/
static const edma_channel_config_t adc_rfifo4_dma_config = {
9, SPC5_ADC_FIFO4_DMA_PRIO, SPC5_ADC_FIFO4_DMA_IRQ_PRIO,
adc_serve_rfifo_irq, adc_serve_dma_error_irq, &ADCD5
};
#endif /* SPC5_ADC_USE_ADC1_Q4 */
#if SPC5_ADC_USE_ADC1_Q5 || defined(__DOXYGEN__)
/**
* @brief DMA configuration for EQADC CFIFO5.
*/
static const edma_channel_config_t adc_cfifo5_dma_config = {
10, SPC5_ADC_FIFO5_DMA_PRIO, SPC5_ADC_FIFO5_DMA_IRQ_PRIO,
NULL, adc_serve_dma_error_irq, &ADCD6
};
/**
* @brief DMA configuration for EQADC RFIFO5.
*/
static const edma_channel_config_t adc_rfifo5_dma_config = {
11, SPC5_ADC_FIFO5_DMA_PRIO, SPC5_ADC_FIFO5_DMA_IRQ_PRIO,
adc_serve_rfifo_irq, adc_serve_dma_error_irq, &ADCD6
};
#endif /* SPC5_ADC_USE_ADC1_Q5 */
/*===========================================================================*/
/* Driver local functions and macros. */
/*===========================================================================*/
/**
* @brief Unsigned two's complement.
*
* @param[in] n the value to be complemented
*
* @notapi
*/
#define CPL2(n) ((~(uint32_t)(n)) + 1)
/**
* @brief Address of a CFIFO push register.
*
* @param[in] fifo the FIFO identifier
*
* @notapi
*/
#define CFIFO_PUSH_ADDR(fifo) ((uint32_t *)(&EQADC.CFPR[fifo].R))
/**
* @brief Address of a RFIFO pop register.
*
* @param[in] fifo the FIFO identifier
*
* @notapi
*/
#define RFIFO_POP_ADDR(fifo) (((uint16_t *)&EQADC.RFPR[fifo].R) + 1)
/**
* @brief Enables a CFIFO.
*
* @param[in] fifo the FIFO identifier
* @param[in] cfcr CFCR register value
* @param[in] idcr IDCR register value
*
* @notapi
*/
static void cfifo_enable(adcfifo_t fifo, uint16_t cfcr, uint16_t idcr) {
EQADC.CFCR[fifo].R = cfcr;
EQADC.IDCR[fifo].R = idcr;
}
/**
* @brief Disables a CFIFO and the associated resources.
*
* @param[in] fifo the FIFO identifier
*
* @notapi
*/
static void cfifo_disable(adcfifo_t fifo) {
/* Disables the CFIFO.*/
EQADC.CFCR[fifo].R = EQADC_CFCR_MODE_DISABLED;
/* Disables Interrupts and DMAs of the CFIFO.*/
EQADC.IDCR[fifo].R = 0;
/* Waits for the CFIFO to become idle.*/
while ((EQADC.CFSR.R & (0xC0000000 >> (fifo * 2))) != 0)
;
/* Invalidates the CFIFO.*/
EQADC.CFCR[fifo].R = EQADC_CFCR_CFINV | EQADC_CFCR_MODE_DISABLED;
/* Clears all Interrupts and eDMA flags for the CFIFO.*/
EQADC.FISR[fifo].R = EQADC_FISR_CLEAR_MASK;
/* Clears the Tx Count Registers for the CFIFO.*/
EQADC.CFTCR[fifo].R = 0;
}
/**
* @brief Pushes a command into the CFIFO0.
*
* @param[in] cmd the command
*
* @notapi
*/
static void cfifo0_push_command(adccommand_t cmd) {
while (EQADC.FISR[0].B.CFCTR >= 4)
;
EQADC.CFPR[0].R = cmd;
}
/**
* @brief Waits until the RFIFO0 contains the specified number of entries.
*
* @param[in] n number of entries
*
* @notapi
*/
static void cfifo0_wait_rfifo(uint32_t n) {
while (EQADC.FISR[0].B.RFCTR < n)
;
EQADC.FISR[0].R = EQADC_FISR_CLEAR_MASK;
}
/**
* @brief Reads a sample from the RFIFO0.
*
* @notapi
*/
#define rfifo0_get_value() (EQADC.RFPR[0].R)
/**
* @brief Writes an internal ADC register.
*
* @param[in] adc the ADC unit
* @param[in] reg the register index
* @param[in] value value to be written into the register
*
* @notapi
*/
#define adc_write_register(adc, reg, value) \
cfifo0_push_command(EQADC_RW_WRITE | (adc) | EQADC_RW_REG_ADDR(reg) | \
EQADC_RW_VALUE(value))
/**
* @brief Enables both ADCs.
*
* @notapi
*/
static void adc_enable(void) {
/* Both ADCs must be enabled because this sentence in the reference manual:
"Both ADC0 and ADC1 of an eQADC module pair must be enabled before
calibrating or using either ADC0 or ADC1 of the pair. Failure to
enable both ADC0 and ADC1 of the pair can result in inaccurate
conversions.".*/
adc_write_register(EQADC_RW_BN_ADC0, ADC_REG_CR,
SPC5_ADC_CR_CLK_PS | ADC_CR_EN);
adc_write_register(EQADC_RW_BN_ADC1, ADC_REG_CR,
SPC5_ADC_CR_CLK_PS | ADC_CR_EN);
}
/**
* @brief Disables both ADCs.
*
* @notapi
*/
static void adc_disable(void) {
adc_write_register(EQADC_RW_BN_ADC0, ADC_REG_CR,
SPC5_ADC_CR_CLK_PS);
adc_write_register(EQADC_RW_BN_ADC1, ADC_REG_CR,
SPC5_ADC_CR_CLK_PS);
}
/**
* @brief Calibrates an ADC unit.
*
* @param[in] adc the ADC unit
*
* @notapi
*/
static void adc_calibrate(uint32_t adc) {
uint16_t res25, res75;
uint32_t gcc, occ;
/* Starts the calibration, write command messages to sample 25% and
75% VREF.*/
cfifo0_push_command(0x00002C00 | adc); /* Vref 25%.*/
cfifo0_push_command(0x00002B00 | adc); /* Vref 75%.*/
cfifo0_wait_rfifo(2);
/* Reads the results and compute calibration register values.*/
res25 = rfifo0_get_value();
res75 = rfifo0_get_value();
gcc = 0x08000000UL / ((uint32_t)res75 - (uint32_t)res25);
occ = (uint32_t)ADC_IDEAL_RES75_2 - ((gcc * (uint32_t)res75) >> 14);
/* Loads the gain and offset values (default configuration, 12 bits).*/
adc_write_register(adc, ADC_REG_GCCR, gcc);
adc_write_register(adc, ADC_REG_OCCR, occ & 0xFFFF);
/* Loads gain and offset values (alternate configuration 1, 10 bits).*/
adc_write_register(adc, ADC_REG_AC1GCCR, gcc);
adc_write_register(adc, ADC_REG_AC1OCCR, occ & 0xFFFF);
/* Loads gain and offset values (alternate configuration 1, 8 bits).*/
adc_write_register(adc, ADC_REG_AC2GCCR, gcc);
adc_write_register(adc, ADC_REG_AC2OCCR, occ & 0xFFFF);
}
/**
* @brief Calibrates an ADC unit.
*
* @param[in] adc the ADC unit
*
* @notapi
*/
static void adc_setup_resistors(uint32_t adc) {
unsigned i;
for (i = 0; i < 8; i++)
adc_write_register(adc, ADC_REG_PUDCR(i), pudcrs[i]);
}
/**
* @brief Shared ISR for RFIFO DMA events.
*
* @param[in] channel the channel number
* @param[in] p parameter for the registered function
*
* @notapi
*/
static void adc_serve_rfifo_irq(edma_channel_t channel, void *p) {
ADCDriver *adcp = (ADCDriver *)p;
edma_tcd_t *tcdp = edmaGetTCD(channel);
if (adcp->grpp != NULL) {
if ((tcdp->word[5] >> 16) != (tcdp->word[7] >> 16)) {
/* Half transfer processing.*/
_adc_isr_half_code(adcp);
}
else {
/* Re-starting DMA channels if in circular mode.*/
if (adcp->grpp->circular) {
edmaChannelStart(adcp->rfifo_channel);
edmaChannelStart(adcp->cfifo_channel);
}
/* Transfer complete processing.*/
_adc_isr_full_code(adcp);
}
}
}
/**
* @brief Shared ISR for CFIFO/RFIFO DMA error events.
*
* @param[in] channel the channel number
* @param[in] p parameter for the registered function
* @param[in] esr content of the ESR register
*
* @notapi
*/
static void adc_serve_dma_error_irq(edma_channel_t channel,
void *p,
uint32_t esr) {
ADCDriver *adcp = (ADCDriver *)p;
(void)channel;
(void)esr;
_adc_isr_error_code(adcp, ADC_ERR_DMAFAILURE);
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level ADC driver initialization.
*
* @notapi
*/
void adc_lld_init(void) {
/* FIFOs initially all not in use.*/
adc_active_fifos = 0;
#if SPC5_ADC_USE_ADC0_Q0
/* Driver initialization.*/
adcObjectInit(&ADCD1);
ADCD1.cfifo_channel = EDMA_ERROR;
ADCD1.rfifo_channel = EDMA_ERROR;
ADCD1.fifo = ADC_FIFO_0;
#endif /* SPC5_ADC_USE_EQADC_Q0 */
#if SPC5_ADC_USE_ADC0_Q1
/* Driver initialization.*/
adcObjectInit(&ADCD2);
ADCD2.cfifo_channel = EDMA_ERROR;
ADCD2.rfifo_channel = EDMA_ERROR;
ADCD2.fifo = ADC_FIFO_1;
#endif /* SPC5_ADC_USE_EQADC_Q1 */
#if SPC5_ADC_USE_ADC0_Q2
/* Driver initialization.*/
adcObjectInit(&ADCD3);
ADCD3.cfifo_channel = EDMA_ERROR;
ADCD3.rfifo_channel = EDMA_ERROR;
ADCD3.fifo = ADC_FIFO_2;
#endif /* SPC5_ADC_USE_EQADC_Q2 */
#if SPC5_ADC_USE_ADC1_Q3
/* Driver initialization.*/
adcObjectInit(&ADCD4);
ADCD4.cfifo_channel = EDMA_ERROR;
ADCD4.rfifo_channel = EDMA_ERROR;
ADCD4.fifo = ADC_FIFO_3;
#endif /* SPC5_ADC_USE_ADC1_Q3 */
#if SPC5_ADC_USE_ADC1_Q4
/* Driver initialization.*/
adcObjectInit(&ADCD5);
ADCD5.cfifo_channel = EDMA_ERROR;
ADCD5.rfifo_channel = EDMA_ERROR;
ADCD5.fifo = ADC_FIFO_4;
#endif /* SPC5_ADC_USE_ADC1_Q4 */
#if SPC5_ADC_USE_ADC1_Q5
/* Driver initialization.*/
adcObjectInit(&ADCD6);
ADCD6.cfifo_channel = EDMA_ERROR;
ADCD6.rfifo_channel = EDMA_ERROR;
ADCD6.fifo = ADC_FIFO_5;
#endif /* SPC5_ADC_USE_ADC1_Q5 */
/* Temporarily enables CFIFO0 for calibration and initialization.*/
cfifo_enable(ADC_FIFO_0, EQADC_CFCR_SSE | EQADC_CFCR_MODE_SWCS, 0);
adc_enable();
/* Calibration of both ADC units, programming alternate configs
one and two for 10 and 8 bits operations, setting up pull up/down
resistors.*/
#if SPC5_ADC_USE_ADC0
adc_calibrate(EQADC_RW_BN_ADC0);
adc_write_register(EQADC_RW_BN_ADC0, ADC_REG_AC1CR, ADC_ACR_RESSEL_10BITS);
adc_write_register(EQADC_RW_BN_ADC0, ADC_REG_AC2CR, ADC_ACR_RESSEL_8BITS);
adc_setup_resistors(EQADC_RW_BN_ADC0);
#endif
#if SPC5_ADC_USE_ADC1
adc_calibrate(EQADC_RW_BN_ADC1);
adc_write_register(EQADC_RW_BN_ADC1, ADC_REG_AC1CR, ADC_ACR_RESSEL_10BITS);
adc_write_register(EQADC_RW_BN_ADC1, ADC_REG_AC2CR, ADC_ACR_RESSEL_8BITS);
adc_setup_resistors(EQADC_RW_BN_ADC1);
#endif
/* ADCs disabled until the driver is started by the application.*/
adc_disable();
cfifo_disable(ADC_FIFO_0);
}
/**
* @brief Configures and activates the ADC peripheral.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_start(ADCDriver *adcp) {
chDbgAssert(adc_active_fifos < 6, "adc_lld_start(), #1", "too many FIFOs");
if (adcp->state == ADC_STOP) {
/* Enables the peripheral.*/
#if SPC5_ADC_USE_ADC0_Q0
if (&ADCD1 == adcp) {
adcp->cfifo_channel = edmaChannelAllocate(&adc_cfifo0_dma_config);
adcp->rfifo_channel = edmaChannelAllocate(&adc_rfifo0_dma_config);
adc_active_fifos++;
}
#endif /* SPC5_ADC_USE_ADC0_Q0 */
#if SPC5_ADC_USE_ADC0_Q1
if (&ADCD2 == adcp) {
adcp->cfifo_channel = edmaChannelAllocate(&adc_cfifo1_dma_config);
adcp->rfifo_channel = edmaChannelAllocate(&adc_rfifo1_dma_config);
adc_active_fifos++;
}
#endif /* SPC5_ADC_USE_ADC0_Q1 */
#if SPC5_ADC_USE_ADC0_Q2
if (&ADCD3 == adcp) {
adcp->cfifo_channel = edmaChannelAllocate(&adc_cfifo2_dma_config);
adcp->rfifo_channel = edmaChannelAllocate(&adc_rfifo2_dma_config);
adc_active_fifos++;
}
#endif /* SPC5_ADC_USE_ADC0_Q2 */
#if SPC5_ADC_USE_ADC1_Q3
if (&ADCD4 == adcp) {
adcp->cfifo_channel = edmaChannelAllocate(&adc_cfifo3_dma_config);
adcp->rfifo_channel = edmaChannelAllocate(&adc_rfifo3_dma_config);
adc_active_fifos++;
}
#endif /* SPC5_ADC_USE_ADC1_Q3 */
#if SPC5_ADC_USE_ADC1_Q4
if (&ADCD5 == adcp) {
adcp->cfifo_channel = edmaChannelAllocate(&adc_cfifo4_dma_config);
adcp->rfifo_channel = edmaChannelAllocate(&adc_rfifo4_dma_config);
adc_active_fifos++;
}
#endif /* SPC5_ADC_USE_ADC1_Q4 */
#if SPC5_ADC_USE_ADC1_Q5
if (&ADCD6 == adcp) {
adcp->cfifo_channel = edmaChannelAllocate(&adc_cfifo5_dma_config);
adcp->rfifo_channel = edmaChannelAllocate(&adc_rfifo5_dma_config);
adc_active_fifos++;
}
#endif /* SPC5_ADC_USE_ADC1_Q5 */
/* If this is the first FIFO activated then the ADC is enabled.*/
if (adc_active_fifos == 1)
adc_enable();
}
chDbgAssert((adcp->cfifo_channel != EDMA_ERROR) &&
(adcp->rfifo_channel != EDMA_ERROR),
"adc_lld_start(), #2", "channel cannot be allocated");
}
/**
* @brief Deactivates the ADC peripheral.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_stop(ADCDriver *adcp) {
chDbgAssert(adc_active_fifos < 6, "adc_lld_stop(), #1", "too many FIFOs");
if (adcp->state == ADC_READY) {
/* Resets the peripheral.*/
/* Releases the allocated EDMA channels.*/
edmaChannelRelease(adcp->cfifo_channel);
edmaChannelRelease(adcp->rfifo_channel);
/* If it is the last active FIFO then the ADC is disable too.*/
if (--adc_active_fifos == 0)
adc_disable();
}
}
/**
* @brief Starts an ADC conversion.
* @note Because an HW constraint the number of rows in the samples
* array must not be greater than the preconfigured value in
* the conversion group.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_start_conversion(ADCDriver *adcp) {
uint32_t bitoff;
chDbgAssert(adcp->grpp->num_iterations >= adcp->depth,
"adc_lld_start_conversion(), #1", "too many elements");
/* Setting up CFIFO TCD parameters.*/
edmaChannelSetup(adcp->cfifo_channel, /* channel. */
adcp->grpp->commands, /* src. */
CFIFO_PUSH_ADDR(adcp->fifo), /* dst. */
4, /* soff, advance by 4. */
0, /* doff, do not advance. */
2, /* ssize, 32 bits transfers.*/
2, /* dsize, 32 bits transfers.*/
4, /* nbytes, always four. */
(uint32_t)adcp->grpp->num_channels *
(uint32_t)adcp->depth, /* iter. */
CPL2((uint32_t)adcp->grpp->num_channels *
(uint32_t)adcp->depth *
sizeof(adccommand_t)), /* slast. */
0, /* dlast, no dest.adjust. */
EDMA_TCD_MODE_DREQ); /* mode. */
/* Setting up RFIFO TCD parameters.*/
edmaChannelSetup(adcp->rfifo_channel, /* channel. */
RFIFO_POP_ADDR(adcp->fifo), /* src. */
adcp->samples, /* dst. */
0, /* soff, do not advance. */
2, /* doff, advance by two. */
1, /* ssize, 16 bits transfers.*/
1, /* dsize, 16 bits transfers.*/
2, /* nbytes, always two. */
(uint32_t)adcp->grpp->num_channels *
(uint32_t)adcp->depth, /* iter. */
0, /* slast, no source adjust. */
CPL2((uint32_t)adcp->grpp->num_channels *
(uint32_t)adcp->depth *
sizeof(adcsample_t)), /* dlast. */
EDMA_TCD_MODE_DREQ | EDMA_TCD_MODE_INT_END |
((adcp->depth > 1) ? EDMA_TCD_MODE_INT_HALF: 0));/* mode.*/
/* HW triggers setup.*/
bitoff = 20 + ((uint32_t)adcp->fifo * 2);
SIU.ETISR.R = (SIU.ETISR.R & ~(3U << bitoff)) |
(adcp->grpp->tsel << bitoff);
bitoff = (uint32_t)adcp->fifo * 5;
SIU.ISEL3.R = (SIU.ISEL3.R & ~(31U << bitoff)) |
(adcp->grpp->etsel << bitoff);
/* Starting DMA channels.*/
edmaChannelStart(adcp->rfifo_channel);
edmaChannelStart(adcp->cfifo_channel);
/* Enabling CFIFO, conversion starts.*/
cfifo_enable(adcp->fifo, adcp->grpp->cfcr,
EQADC_IDCR_CFFE | EQADC_IDCR_CFFS |
EQADC_IDCR_RFDE | EQADC_IDCR_RFDS);
}
/**
* @brief Stops an ongoing conversion.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_stop_conversion(ADCDriver *adcp) {
/* Stopping DMA channels.*/
edmaChannelStop(adcp->cfifo_channel);
edmaChannelStop(adcp->rfifo_channel);
/* Disabling CFIFO.*/
cfifo_disable(adcp->fifo);
}
#endif /* HAL_USE_ADC */
/** @} */
+705
View File
@@ -0,0 +1,705 @@
/*
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
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 SPC5xx/EQADC_v1/adc_lld.c
* @brief SPC5xx low level ADC driver header.
*
* @addtogroup ADC
* @{
*/
#ifndef _ADC_LLD_H_
#define _ADC_LLD_H_
#if HAL_USE_ADC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name Analog channel identifiers
* @{
*/
#define ADC_CHN_AN0 0U
#define ADC_CHN_AN1 1U
#define ADC_CHN_AN2 2U
#define ADC_CHN_AN3 3U
#define ADC_CHN_AN4 4U
#define ADC_CHN_AN5 5U
#define ADC_CHN_AN6 6U
#define ADC_CHN_AN7 7U
#define ADC_CHN_AN8 8U
#define ADC_CHN_AN9 9U
#define ADC_CHN_AN10 10U
#define ADC_CHN_AN11 11U
#define ADC_CHN_AN12 12U
#define ADC_CHN_AN13 13U
#define ADC_CHN_AN14 14U
#define ADC_CHN_AN15 15U
#define ADC_CHN_AN16 16U
#define ADC_CHN_AN17 17U
#define ADC_CHN_AN18 18U
#define ADC_CHN_AN19 19U
#define ADC_CHN_AN20 20U
#define ADC_CHN_AN21 21U
#define ADC_CHN_AN22 22U
#define ADC_CHN_AN23 23U
#define ADC_CHN_AN24 24U
#define ADC_CHN_AN25 25U
#define ADC_CHN_AN26 26U
#define ADC_CHN_AN27 27U
#define ADC_CHN_AN28 28U
#define ADC_CHN_AN29 29U
#define ADC_CHN_AN30 30U
#define ADC_CHN_AN31 31U
#define ADC_CHN_AN32 32U
#define ADC_CHN_AN33 33U
#define ADC_CHN_AN34 34U
#define ADC_CHN_AN35 35U
#define ADC_CHN_AN36 36U
#define ADC_CHN_AN37 37U
#define ADC_CHN_AN38 38U
#define ADC_CHN_AN39 39U
#define ADC_CHN_VRH 40U
#define ADC_CHN_VRL 41U
#define ADC_CHN_VREF50 42U
#define ADC_CHN_VREF75 43U
#define ADC_CHN_VREF25 44U
#define ADC_CHN_BANDGAP 45U
#define ADC_CHN_DAN0 96U
#define ADC_CHN_DAN1 97U
#define ADC_CHN_DAN2 98U
#define ADC_CHN_DAN3 99U
#define ADC_CHN_TEMP_SENSOR 128U
#define ADC_CHN_SPARE 129U
/** @} */
/**
* @name Internal registers indexes
* @{
*/
#define ADC_REG_CR 0x1
#define ADC_REG_TSCR 0x2
#define ADC_REG_TBCR 0x3
#define ADC_REG_GCCR 0x4
#define ADC_REG_OCCR 0x5
#define ADC_REG_AC1GCCR 0x31
#define ADC_REG_AC1OCCR 0x32
#define ADC_REG_AC2GCCR 0x35
#define ADC_REG_AC2OCCR 0x36
#define ADC_REG_AC1CR 0x30
#define ADC_REG_AC2CR 0x34
#define ADC_REG_AC3CR 0x38
#define ADC_REG_AC4CR 0x3C
#define ADC_REG_AC5CR 0x40
#define ADC_REG_AC6CR 0x44
#define ADC_REG_AC7CR 0x48
#define ADC_REG_AC8CR 0x4C
#define ADC_REG_PUDCR(n) (0x70 + (n))
#define ADC_REG_PUDCR0 0x70UL
#define ADC_REG_PUDCR1 0x71UL
#define ADC_REG_PUDCR2 0x72UL
#define ADC_REG_PUDCR3 0x73UL
#define ADC_REG_PUDCR4 0x74UL
#define ADC_REG_PUDCR5 0x75UL
#define ADC_REG_PUDCR6 0x76UL
#define ADC_REG_PUDCR7 0x77UL
/** @} */
/**
* @name EQADC IDCR registers definitions
* @{
*/
#define EQADC_IDCR_NCIE (1U << 15)
#define EQADC_IDCR_TORIE (1U << 14)
#define EQADC_IDCR_PIE (1U << 13)
#define EQADC_IDCR_EOQIE (1U << 12)
#define EQADC_IDCR_CFUIE (1U << 11)
#define EQADC_IDCR_CFFE (1U << 9)
#define EQADC_IDCR_CFFS (1U << 8)
#define EQADC_IDCR_RFOIE (1U << 3)
#define EQADC_IDCR_RFDE (1U << 1)
#define EQADC_IDCR_RFDS (1U << 0)
/** @} */
/**
* @name EQADC CFCR registers definitions
* @{
*/
#define EQADC_CFCR_CFEEE0 (1U << 12)
#define EQADC_CFCR_STRME0 (1U << 11)
#define EQADC_CFCR_SSE (1U << 10)
#define EQADC_CFCR_CFINV (1U << 9)
#define EQADC_CFCR_MODE_MASK (15U << 4)
#define EQADC_CFCR_MODE(n) ((n) << 4)
#define EQADC_CFCR_MODE_DISABLED EQADC_CFCR_MODE(0)
#define EQADC_CFCR_MODE_SWSS EQADC_CFCR_MODE(1)
#define EQADC_CFCR_MODE_HWSS_LL EQADC_CFCR_MODE(2)
#define EQADC_CFCR_MODE_HWSS_HL EQADC_CFCR_MODE(3)
#define EQADC_CFCR_MODE_HWSS_FE EQADC_CFCR_MODE(4)
#define EQADC_CFCR_MODE_HWSS_RE EQADC_CFCR_MODE(5)
#define EQADC_CFCR_MODE_HWSS_BE EQADC_CFCR_MODE(6)
#define EQADC_CFCR_MODE_SWCS EQADC_CFCR_MODE(9)
#define EQADC_CFCR_MODE_HWCS_LL EQADC_CFCR_MODE(10)
#define EQADC_CFCR_MODE_HWCS_HL EQADC_CFCR_MODE(11)
#define EQADC_CFCR_MODE_HWCS_FE EQADC_CFCR_MODE(12)
#define EQADC_CFCR_MODE_HWCS_RE EQADC_CFCR_MODE(13)
#define EQADC_CFCR_MODE_HWCS_BE EQADC_CFCR_MODE(14)
#define EQADC_CFCR_AMODE0_MASK (15U << 0)
#define EQADC_CFCR_AMODE0(n) ((n) << 0)
/** @} */
/**
* @name EQADC FISR registers definitions
* @{
*/
#define EQADC_FISR_POPNXTPTR_MASK (15U << 0)
#define EQADC_FISR_RFCTR_MASK (15U << 4)
#define EQADC_FISR_TNXTPTR_MASK (15U << 8)
#define EQADC_FISR_CFCTR_MASK (15U << 12)
#define EQADC_FISR_RFDF (1U << 17)
#define EQADC_FISR_RFOF (1U << 19)
#define EQADC_FISR_CFFF (1U << 25)
#define EQADC_FISR_SSS (1U << 26)
#define EQADC_FISR_CFUF (1U << 27)
#define EQADC_FISR_EOQF (1U << 28)
#define EQADC_FISR_PF (1U << 29)
#define EQADC_FISR_TORF (1U << 30)
#define EQADC_FISR_NCF (1U << 31)
#define EQADC_FISR_CLEAR_MASK (EQADC_FISR_NCF | EQADC_FISR_TORF | \
EQADC_FISR_PF | EQADC_FISR_EOQF | \
EQADC_FISR_CFUF | EQADC_FISR_RFOF | \
EQADC_FISR_RFDF)
/** @} */
/**
* @name EQADC conversion/configuration commands
* @{
*/
#define EQADC_CONV_CONFIG_STD (0U << 0) /**< @brief Alt.config.1. */
#define EQADC_CONV_CONFIG_SEL1 (8U << 0) /**< @brief Alt.config.1. */
#define EQADC_CONV_CONFIG_SEL2 (9U << 0) /**< @brief Alt.config.2. */
#define EQADC_CONV_CONFIG_SEL3 (10U << 0) /**< @brief Alt.config.3. */
#define EQADC_CONV_CONFIG_SEL4 (11U << 0) /**< @brief Alt.config.4. */
#define EQADC_CONV_CONFIG_SEL5 (12U << 0) /**< @brief Alt.config.5. */
#define EQADC_CONV_CONFIG_SEL6 (13U << 0) /**< @brief Alt.config.6. */
#define EQADC_CONV_CONFIG_SEL7 (14U << 0) /**< @brief Alt.config.7. */
#define EQADC_CONV_CONFIG_SEL8 (15U << 0) /**< @brief Alt.config.8. */
#define EQADC_CONV_CHANNEL_MASK (255U << 8) /**< @brief Channel number mask.*/
#define EQADC_CONV_CHANNEL(n) ((n) << 8) /**< @brief Channel number. */
#define EQADC_CONV_FMT_RJU (0U << 16) /**< @brief Unsigned samples. */
#define EQADC_CONV_FMT_RJS (1U << 16) /**< @brief Signed samples. */
#define EQADC_CONV_TSR (1U << 17) /**< @brief Time stamp request. */
#define EQADC_CONV_LST_MASK (3U << 18) /**< @brief Sample time. */
#define EQADC_CONV_LST_2 (0U << 18) /**< @brief 2 clock cycles. */
#define EQADC_CONV_LST_8 (1U << 18) /**< @brief 8 clock cycles. */
#define EQADC_CONV_LST_64 (2U << 18) /**< @brief 64 clock cycles. */
#define EQADC_CONV_LST_128 (3U << 18) /**< @brief 128 clock cycles. */
#define EQADC_CONV_MSG_MASK (15U << 20) /**< @brief Message mask. */
#define EQADC_CONV_MSG_RFIFO(n) ((n) << 20) /**< @brief Result in RFIFO0..5.*/
#define EQADC_CONV_MSG_NULL (6U << 20) /**< @brief Null message. */
#define EQADC_CONV_CAL (1U << 24) /**< @brief Calibrated result. */
#define EQADC_CONV_BN_MASK (1U << 25) /**< @brief Buffer number mask. */
#define EQADC_CONV_BN_ADC0 (0U << 25) /**< @brief ADC0 selection. */
#define EQADC_CONV_BN_ADC1 (1U << 25) /**< @brief ADC1 selection. */
#define EQADC_CONV_REP (1U << 29) /**< @brief Repeat loop flag. */
#define EQADC_CONV_PAUSE (1U << 30) /**< @brief Pause flag. */
#define EQADC_CONV_EOQ (1U << 31) /**< @brief End of queue flag. */
/** @} */
/**
* @name EQADC read/write commands
* @{
*/
#define EQADC_RW_REG_ADDR_MASK (255U << 0)
#define EQADC_RW_REG_ADDR(n) ((n) << 0)
#define EQADC_RW_VALUE_MASK (0xFFFF << 8)
#define EQADC_RW_VALUE(n) ((n) << 8)
#define EQADC_RW_WRITE (0U << 24)
#define EQADC_RW_READ (1U << 24)
#define EQADC_RW_BN_ADC0 (0U << 25)
#define EQADC_RW_BN_ADC1 (1U << 25)
#define EQADC_RW_REP (1U << 29)
#define EQADC_RW_PAUSE (1U << 30)
#define EQADC_RW_EOQ (1U << 31)
/** @} */
/**
* @name ADC CR register definitions
* @{
*/
#define ADC_CR_CLK_PS_MASK (31U << 0)
#define ADC_CR_CLK_PS(n) ((((n) >> 1) - 1) | ((n) & 1 ? ADC_CR_ODD_PS\
: 0))
#define ADC_CR_CLK_SEL (1U << 5)
#define ADC_CR_CLK_DTY (1U << 6)
#define ADC_CR_ODD_PS (1U << 7)
#define ADC_CR_TBSEL_MASK (3U << 8)
#define ADC_CR_TBSEL(n) ((n) << 8)
#define ADC_CR_EMUX (1U << 11)
#define ADC_CR_EN (1U << 15)
/** @} */
/**
* @name ADC AxCR registers definitions
* @{
*/
#define ADC_ACR_PRE_GAIN_MASK (3U << 0)
#define ADC_ACR_PRE_GAIN_X1 (0U << 0)
#define ADC_ACR_PRE_GAIN_X2 (1U << 0)
#define ADC_ACR_PRE_GAIN_X4 (2U << 0)
#define ADC_ACR_RESSEL_MASK (3U << 6)
#define ADC_ACR_RESSEL_12BITS (0U << 6)
#define ADC_ACR_RESSEL_10BITS (1U << 6)
#define ADC_ACR_RESSEL_8BITS (2U << 6)
/** @} */
/**
* @name ADC PUDCRx registers definitions
* @{
*/
#define ADC_PUDCR_NONE 0x0000
#define ADC_PUDCR_UP_200K 0x1100
#define ADC_PUDCR_UP_100K 0x1200
#define ADC_PUDCR_UP_5K 0x1300
#define ADC_PUDCR_DOWN_200K 0x2100
#define ADC_PUDCR_DOWN_100K 0x2200
#define ADC_PUDCR_DOWN_5K 0x2300
#define ADC_PUDCR_UP_DOWN_200K 0x3100
#define ADC_PUDCR_UP_DOWN_100K 0x3200
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief ADCD1 driver enable switch.
* @details If set to @p TRUE the support for ADC0 queue 0 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ADC_USE_ADC0_Q0) || defined(__DOXYGEN__)
#define SPC5_ADC_USE_ADC0_Q0 FALSE
#endif
/**
* @brief ADCD2 driver enable switch.
* @details If set to @p TRUE the support for ADC0 queue 1 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ADC_USE_ADC0_Q1) || defined(__DOXYGEN__)
#define SPC5_ADC_USE_ADC0_Q1 FALSE
#endif
/**
* @brief ADCD3 driver enable switch.
* @details If set to @p TRUE the support for ADC0 queue 2 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ADC_USE_ADC0_Q2) || defined(__DOXYGEN__)
#define SPC5_ADC_USE_ADC0_Q2 FALSE
#endif
/**
* @brief ADCD4 driver enable switch.
* @details If set to @p TRUE the support for ADC1 queue 3 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ADC_USE_ADC1_Q3) || defined(__DOXYGEN__)
#define SPC5_ADC_USE_ADC1_Q3 FALSE
#endif
/**
* @brief ADCD5 driver enable switch.
* @details If set to @p TRUE the support for ADC1 queue 4 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ADC_USE_ADC1_Q4) || defined(__DOXYGEN__)
#define SPC5_ADC_USE_ADC1_Q4 FALSE
#endif
/**
* @brief ADCD6 driver enable switch.
* @details If set to @p TRUE the support for ADC1 queue 5 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ADC_USE_ADC1_Q5) || defined(__DOXYGEN__)
#define SPC5_ADC_USE_ADC1_Q5 FALSE
#endif
/**
* @brief EQADC CFIFO0 and RFIFO0 DMA priority.
*/
#if !defined(SPC5_ADC_FIFO0_DMA_PRIO) || defined(__DOXYGEN__)
#define SPC5_ADC_FIFO0_DMA_PRIO 12
#endif
/**
* @brief EQADC CFIFO1 and RFIFO1 DMA priority.
*/
#if !defined(SPC5_ADC_FIFO1_DMA_PRIO) || defined(__DOXYGEN__)
#define SPC5_ADC_FIFO1_DMA_PRIO 12
#endif
/**
* @brief EQADC CFIFO2 and RFIFO2 DMA priority.
*/
#if !defined(SPC5_ADC_FIFO2_DMA_PRIO) || defined(__DOXYGEN__)
#define SPC5_ADC_FIFO2_DMA_PRIO 12
#endif
/**
* @brief EQADC CFIFO3 and RFIFO3 DMA priority.
*/
#if !defined(SPC5_ADC_FIFO3_DMA_PRIO) || defined(__DOXYGEN__)
#define SPC5_ADC_FIFO3_DMA_PRIO 12
#endif
/**
* @brief EQADC CFIFO4 and RFIFO4 DMA priority.
*/
#if !defined(SPC5_ADC_FIFO4_DMA_PRIO) || defined(__DOXYGEN__)
#define SPC5_ADC_FIFO4_DMA_PRIO 12
#endif
/**
* @brief EQADC CFIFO5 and RFIFO5 DMA priority.
*/
#if !defined(SPC5_ADC_FIFO5_DMA_PRIO) || defined(__DOXYGEN__)
#define SPC5_ADC_FIFO5_DMA_PRIO 12
#endif
/**
* @brief EQADC CFIFO0 and RFIFO0 DMA IRQ priority.
*/
#if !defined(SPC5_ADC0_FIFO0_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
#define SPC5_ADC_FIFO0_DMA_IRQ_PRIO 12
#endif
/**
* @brief EQADC CFIFO1 and RFIFO1 DMA IRQ priority.
*/
#if !defined(SPC5_ADC0_FIFO1_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
#define SPC5_ADC_FIFO1_DMA_IRQ_PRIO 12
#endif
/**
* @brief EQADC CFIFO2 and RFIFO2 DMA IRQ priority.
*/
#if !defined(SPC5_ADC0_FIFO2_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
#define SPC5_ADC_FIFO2_DMA_IRQ_PRIO 12
#endif
/**
* @brief EQADC CFIFO3 and RFIFO3 DMA IRQ priority.
*/
#if !defined(SPC5_ADC0_FIFO3_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
#define SPC5_ADC_FIFO3_DMA_IRQ_PRIO 12
#endif
/**
* @brief EQADC CFIFO4 and RFIFO4 DMA IRQ priority.
*/
#if !defined(SPC5_ADC0_FIFO4_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
#define SPC5_ADC_FIFO4_DMA_IRQ_PRIO 12
#endif
/**
* @brief EQADC CFIFO5 and RFIFO5 DMA IRQ priority.
*/
#if !defined(SPC5_ADC0_FIFO5_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
#define SPC5_ADC_FIFO5_DMA_IRQ_PRIO 12
#endif
/**
* @brief EQADC clock prescaler value.
*/
#if !defined(SPC5_ADC_CR_CLK_PS) || defined(__DOXYGEN__)
#define SPC5_ADC_CR_CLK_PS ADC_CR_CLK_PS(5)
#endif
/**
* @brief Initialization value for PUDCRx registers.
*/
#if !defined(SPC5_ADC_PUDCR) || defined(__DOXYGEN__)
#define SPC5_ADC_PUDCR {ADC_PUDCR_NONE, \
ADC_PUDCR_NONE, \
ADC_PUDCR_NONE, \
ADC_PUDCR_NONE, \
ADC_PUDCR_NONE, \
ADC_PUDCR_NONE, \
ADC_PUDCR_NONE, \
ADC_PUDCR_NONE}
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !SPC5_HAS_EQADC
#error "EQADC not present in the selected device"
#endif
#define SPC5_ADC_USE_ADC0 (SPC5_ADC_USE_ADC0_Q0 || \
SPC5_ADC_USE_ADC0_Q1 || \
SPC5_ADC_USE_ADC0_Q2)
#define SPC5_ADC_USE_ADC1 (SPC5_ADC_USE_ADC1_Q3 || \
SPC5_ADC_USE_ADC1_Q4 || \
SPC5_ADC_USE_ADC1_Q5)
#if !SPC5_ADC_USE_ADC0 && !SPC5_ADC_USE_ADC1
#error "ADC driver activated but no ADC peripheral assigned"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/*!
* @brief FIFO unit numeric IDs.
*/
typedef enum {
ADC_FIFO_0 = 0,
ADC_FIFO_1 = 1,
ADC_FIFO_2 = 2,
ADC_FIFO_3 = 3,
ADC_FIFO_4 = 4,
ADC_FIFO_5 = 5
} adcfifo_t;
/**
* @brief ADC command data type.
*/
typedef uint32_t adccommand_t;
/**
* @brief ADC sample data type.
*/
typedef uint16_t adcsample_t;
/**
* @brief Channels number in a conversion group.
*/
typedef uint16_t adc_channels_num_t;
/**
* @brief Possible ADC failure causes.
* @note Error codes are architecture dependent and should not relied
* upon.
*/
typedef enum {
ADC_ERR_DMAFAILURE = 0 /**< DMA operations failure. */
} adcerror_t;
/**
* @brief Type of a structure representing an ADC driver.
*/
typedef struct ADCDriver ADCDriver;
/**
* @brief ADC notification callback type.
*
* @param[in] adcp pointer to the @p ADCDriver object triggering the
* callback
* @param[in] buffer pointer to the most recent samples data
* @param[in] n number of buffer rows available starting from @p buffer
*/
typedef void (*adccallback_t)(ADCDriver *adcp, adcsample_t *buffer, size_t n);
/**
* @brief ADC error callback type.
*
* @param[in] adcp pointer to the @p ADCDriver object triggering the
* callback
* @param[in] err ADC error code
*/
typedef void (*adcerrorcallback_t)(ADCDriver *adcp, adcerror_t err);
/**
* @brief Conversion group configuration structure.
* @details This implementation-dependent structure describes a conversion
* operation.
* @note Implementations may extend this structure to contain more,
* architecture dependent, fields.
*/
typedef struct {
/**
* @brief Enables the circular buffer mode for the group.
*/
bool_t circular;
/**
* @brief Number of the analog channels belonging to the conversion group.
*/
adc_channels_num_t num_channels;
/**
* @brief Callback function associated to the group or @p NULL.
*/
adccallback_t end_cb;
/**
* @brief Error callback or @p NULL.
*/
adcerrorcallback_t error_cb;
/* End of the mandatory fields.*/
/**
* @brief Initialization value for CFCR register.
*/
uint16_t cfcr;
/**
* @brief SIU ETISR.TSEL value for this queue;
*/
uint8_t tsel;
/**
* @brief SIU ISEL3.ETSEL value for this queue;
*/
uint8_t etsel;
/**
* @brief Number of command iterations stored in @p commands.
* @note The total number of array elements must be @p num_channels *
* @p num_iterations.
* @note This fields is the upper limit of the parameter @p n that can
* be passed to the functions @p adcConvert() and
* @p adcStartConversion().
*/
uint32_t num_iterations;
/**
* @brief Pointer to an array of low level EQADC commands to be pushed
* into the CFIFO during a conversion.
*/
const adccommand_t *commands;
} ADCConversionGroup;
/**
* @brief Driver configuration structure.
* @note Empty in this implementation can be ignored.
*/
typedef struct {
uint32_t dummy;
} ADCConfig;
/**
* @brief Structure representing an ADC driver.
*/
struct ADCDriver {
/**
* @brief Driver state.
*/
adcstate_t state;
/**
* @brief Current configuration data.
*/
const ADCConfig *config;
/**
* @brief Current samples buffer pointer or @p NULL.
*/
adcsample_t *samples;
/**
* @brief Current samples buffer depth or @p 0.
*/
size_t depth;
/**
* @brief Current conversion group pointer or @p NULL.
*/
const ADCConversionGroup *grpp;
#if ADC_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
Thread *thread;
#endif
#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the peripheral.
*/
Mutex mutex;
#elif CH_USE_SEMAPHORES
Semaphore semaphore;
#endif
#endif /* ADC_USE_MUTUAL_EXCLUSION */
#if defined(ADC_DRIVER_EXT_FIELDS)
ADC_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief CFIFO/RFIFO used by this instance.
*/
adcfifo_t fifo;
/**
* @brief EDMA channel used for the CFIFO.
*/
edma_channel_t cfifo_channel;
/**
* @brief EDMA channel used for the RFIFO.
*/
edma_channel_t rfifo_channel;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if SPC5_ADC_USE_ADC0_Q0 && !defined(__DOXYGEN__)
extern ADCDriver ADCD1;
#endif
#if SPC5_ADC_USE_ADC0_Q1 && !defined(__DOXYGEN__)
extern ADCDriver ADCD2;
#endif
#if SPC5_ADC_USE_ADC0_Q2 && !defined(__DOXYGEN__)
extern ADCDriver ADCD3;
#endif
#if SPC5_ADC_USE_ADC1_Q3 && !defined(__DOXYGEN__)
extern ADCDriver ADCD4;
#endif
#if SPC5_ADC_USE_ADC1_Q4 && !defined(__DOXYGEN__)
extern ADCDriver ADCD5;
#endif
#if SPC5_ADC_USE_ADC1_Q5 && !defined(__DOXYGEN__)
extern ADCDriver ADCD6;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void adc_lld_init(void);
void adc_lld_start(ADCDriver *adcp);
void adc_lld_stop(ADCDriver *adcp);
void adc_lld_start_conversion(ADCDriver *adcp);
void adc_lld_stop_conversion(ADCDriver *adcp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_ADC */
#endif /* _ADC_LLD_H_ */
/** @} */
@@ -0,0 +1,296 @@
/*
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
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 SPC5xx/ESCI_v1/serial_lld.c
* @brief SPC5xx low level serial driver code.
*
* @addtogroup SERIAL
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief eSCI-A serial driver identifier.
*/
#if SPC5_USE_ESCIA || defined(__DOXYGEN__)
SerialDriver SD1;
#endif
/**
* @brief eSCI-B serial driver identifier.
*/
#if SPC5_USE_ESCIB || defined(__DOXYGEN__)
SerialDriver SD2;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/**
* @brief Driver default configuration.
*/
static const SerialConfig default_config = {
SERIAL_DEFAULT_BITRATE,
SD_MODE_NORMAL | SD_MODE_PARITY_NONE
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief eSCI initialization.
* @details This function must be invoked with interrupts disabled.
*
* @param[in] sdp pointer to a @p SerialDriver object
* @param[in] config the architecture-dependent serial driver configuration
*/
static void esci_init(SerialDriver *sdp, const SerialConfig *config) {
volatile struct ESCI_tag *escip = sdp->escip;
uint8_t mode = config->sc_mode;
escip->CR2.R = 0; /* MDIS off. */
escip->CR1.R = 0;
escip->LCR.R = 0;
escip->CR1.B.SBR = SPC5_SYSCLK / (16 * config->sc_speed);
if (mode & SD_MODE_LOOPBACK)
escip->CR1.B.LOOPS = 1;
switch (mode & SD_MODE_PARITY_MASK) {
case SD_MODE_PARITY_ODD:
escip->CR1.B.PT = 1;
case SD_MODE_PARITY_EVEN:
escip->CR1.B.PE = 1;
escip->CR1.B.M = 1; /* Makes it 8 bits data + 1 bit parity. */
default:
;
}
escip->LPR.R = 0;
escip->CR1.R |= 0x0000002C; /* RIE, TE, RE to 1. */
escip->CR2.R = 0x000F; /* ORIE, NFIE, FEIE, PFIE to 1. */
}
/**
* @brief eSCI de-initialization.
* @details This function must be invoked with interrupts disabled.
*
* @param[in] escip pointer to an eSCI I/O block
*/
static void esci_deinit(volatile struct ESCI_tag *escip) {
escip->LPR.R = 0;
escip->SR.R = 0xFFFFFFFF;
escip->CR1.R = 0;
escip->CR2.R = 0x8000; /* MDIS on. */
}
/**
* @brief Error handling routine.
*
* @param[in] sdp pointer to a @p SerialDriver object
* @param[in] sr eSCI SR register value
*/
static void set_error(SerialDriver *sdp, uint32_t sr) {
flagsmask_t sts = 0;
if (sr & 0x08000000)
sts |= SD_OVERRUN_ERROR;
if (sr & 0x04000000)
sts |= SD_NOISE_ERROR;
if (sr & 0x02000000)
sts |= SD_FRAMING_ERROR;
if (sr & 0x01000000)
sts |= SD_PARITY_ERROR;
/* if (sr & 0x00000000)
sts |= SD_BREAK_DETECTED;*/
chSysLockFromIsr();
chnAddFlagsI(sdp, sts);
chSysUnlockFromIsr();
}
/**
* @brief Common IRQ handler.
*
* @param[in] sdp pointer to a @p SerialDriver object
*/
static void serve_interrupt(SerialDriver *sdp) {
volatile struct ESCI_tag *escip = sdp->escip;
uint32_t sr = escip->SR.R;
escip->SR.R = 0x3FFFFFFF; /* Does not clear TDRE | TC.*/
if (sr & 0x0F000000) /* OR | NF | FE | PF. */
set_error(sdp, sr);
if (sr & 0x20000000) { /* RDRF. */
chSysLockFromIsr();
sdIncomingDataI(sdp, escip->DR.B.D);
chSysUnlockFromIsr();
}
if (escip->CR1.B.TIE && (sr & 0x80000000)) { /* TDRE. */
msg_t b;
chSysLockFromIsr();
b = chOQGetI(&sdp->oqueue);
if (b < Q_OK) {
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
escip->CR1.B.TIE = 0;
}
else {
ESCI_A.SR.B.TDRE = 1;
escip->DR.R = (uint16_t)b;
}
chSysUnlockFromIsr();
}
}
#if SPC5_USE_ESCIA || defined(__DOXYGEN__)
static void notify1(GenericQueue *qp) {
(void)qp;
if (ESCI_A.SR.B.TDRE) {
msg_t b = sdRequestDataI(&SD1);
if (b != Q_EMPTY) {
ESCI_A.SR.B.TDRE = 1;
ESCI_A.CR1.B.TIE = 1;
ESCI_A.DR.R = (uint16_t)b;
}
}
}
#endif
#if SPC5_USE_ESCIB || defined(__DOXYGEN__)
static void notify2(GenericQueue *qp) {
(void)qp;
if (ESCI_B.SR.B.TDRE) {
msg_t b = sdRequestDataI(&SD2);
if (b != Q_EMPTY) {
ESCI_B.SR.B.TDRE = 1;
ESCI_B.CR1.B.TIE = 1;
ESCI_B.DR.R = (uint16_t)b;
}
}
}
#endif
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if SPC5_USE_ESCIA || defined(__DOXYGEN__)
#if !defined(SPC5_ESCIA_HANDLER)
#error "SPC5_ESCIA_HANDLER not defined"
#endif
/**
* @brief eSCI-A interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(SPC5_ESCIA_HANDLER) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD1);
CH_IRQ_EPILOGUE();
}
#endif
#if SPC5_USE_ESCIB || defined(__DOXYGEN__)
#if !defined(SPC5_ESCIB_HANDLER)
#error "SPC5_ESCIB_HANDLER not defined"
#endif
/**
* @brief eSCI-B interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(SPC5_ESCIB_HANDLER) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD2);
CH_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level serial driver initialization.
*
* @notapi
*/
void sd_lld_init(void) {
#if SPC5_USE_ESCIA
sdObjectInit(&SD1, NULL, notify1);
SD1.escip = &ESCI_A;
ESCI_A.CR2.R = 0x8000; /* MDIS ON. */
INTC.PSR[SPC5_ESCIA_NUMBER].R = SPC5_ESCIA_PRIORITY;
#endif
#if SPC5_USE_ESCIB
sdObjectInit(&SD2, NULL, notify2);
SD2.escip = &ESCI_B;
ESCI_B.CR2.R = 0x8000; /* MDIS ON. */
INTC.PSR[SPC5_ESCIB_NUMBER].R = SPC5_ESCIB_PRIORITY;
#endif
}
/**
* @brief Low level serial driver configuration and (re)start.
*
* @param[in] sdp pointer to a @p SerialDriver object
* @param[in] config the architecture-dependent serial driver configuration.
* If this parameter is set to @p NULL then a default
* configuration is used.
*
* @notapi
*/
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
if (config == NULL)
config = &default_config;
esci_init(sdp, config);
}
/**
* @brief Low level serial driver stop.
*
* @param[in] sdp pointer to a @p SerialDriver object
*
* @notapi
*/
void sd_lld_stop(SerialDriver *sdp) {
if (sdp->state == SD_READY)
esci_deinit(sdp->escip);
}
#endif /* HAL_USE_SERIAL */
/** @} */
@@ -0,0 +1,170 @@
/*
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
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 SPC5xx/ESCI_v1/serial_lld.c
* @brief SPC5xx low level serial driver header.
*
* @addtogroup SERIAL
* @{
*/
#ifndef _SERIAL_LLD_H_
#define _SERIAL_LLD_H_
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name Serial port modes
* @{
*/
#define SD_MODE_PARITY_MASK 0x03 /**< @brief Parity field mask. */
#define SD_MODE_PARITY_NONE 0x00 /**< @brief No parity. */
#define SD_MODE_PARITY_EVEN 0x01 /**< @brief Even parity. */
#define SD_MODE_PARITY_ODD 0x02 /**< @brief Odd parity. */
#define SD_MODE_NORMAL 0x00 /**< @brief Normal operations. */
#define SD_MODE_LOOPBACK 0x80 /**< @brief Internal loopback. */
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief eSCI-A driver enable switch.
* @details If set to @p TRUE the support for eSCI-A is included.
* @note The default is @p TRUE.
*/
#if !defined(SPC5_USE_ESCIA) || defined(__DOXYGEN__)
#define SPC5_USE_ESCIA TRUE
#endif
/**
* @brief eSCI-B driver enable switch.
* @details If set to @p TRUE the support for eSCI-B is included.
* @note The default is @p TRUE.
*/
#if !defined(SPC5_USE_ESCIB) || defined(__DOXYGEN__)
#define SPC5_USE_ESCIB TRUE
#endif
/**
* @brief eSCI-A interrupt priority level setting.
*/
#if !defined(SPC_ESCIA_PRIORITY) || defined(__DOXYGEN__)
#define SPC5_ESCIA_PRIORITY 8
#endif
/**
* @brief eSCI-B interrupt priority level setting.
*/
#if !defined(SPC_ESCIB_PRIORITY) || defined(__DOXYGEN__)
#define SPC5_ESCIB_PRIORITY 8
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if SPC5_USE_ESCIA && !SPC5_HAS_ESCIA
#error "eSCI-A not present in the selected device"
#endif
#if SPC5_USE_ESCIB && !SPC5_HAS_ESCIB
#error "eSCI-B not present in the selected device"
#endif
#if !SPC5_USE_ESCIA && !SPC5_USE_ESCIB
#error "SERIAL driver activated but no eSCI 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 This structure content is architecture dependent, each driver
* implementation defines its own version and the custom static
* initializers.
*/
typedef struct {
/**
* @brief Bit rate.
*/
uint32_t sc_speed;
/**
* @brief Mode flags.
*/
uint8_t sc_mode;
} SerialConfig;
/**
* @brief @p SerialDriver specific data.
*/
#define _serial_driver_data \
_base_asynchronous_channel_data \
/* Driver state.*/ \
sdstate_t state; \
/* Input queue.*/ \
InputQueue iqueue; \
/* Output queue.*/ \
OutputQueue 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 volatile eSCI registers block.*/ \
volatile struct ESCI_tag *escip;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if SPC5_USE_ESCIA && !defined(__DOXYGEN__)
extern SerialDriver SD1;
#endif
#if SPC5_USE_ESCIB && !defined(__DOXYGEN__)
extern SerialDriver SD2;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void sd_lld_init(void);
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config);
void sd_lld_stop(SerialDriver *sdp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SERIAL */
#endif /* _SERIAL_LLD_H_ */
/** @} */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,475 @@
/*
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
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 FlexPWM_v1/pwm_lld.h
* @brief SPC5xx low level PWM driver header.
*
* @addtogroup PWM
* @{
*/
#ifndef _PWM_LLD_H_
#define _PWM_LLD_H_
#if HAL_USE_PWM || defined(__DOXYGEN__)
#include "spc5_flexpwm.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name STS register bits definitions
* @{
*/
#define SPC5_FLEXPWM_STS_CMPF0 (1U << 0)
#define SPC5_FLEXPWM_STS_CMPF1 (1U << 1)
#define SPC5_FLEXPWM_STS_CMPF2 (1U << 2)
#define SPC5_FLEXPWM_STS_CMPF3 (1U << 3)
#define SPC5_FLEXPWM_STS_CMPF4 (1U << 4)
#define SPC5_FLEXPWM_STS_CMPF5 (1U << 5)
#define SPC5_FLEXPWM_STS_CFX0 (1U << 6)
#define SPC5_FLEXPWM_STS_CFX1 (1U << 7)
#define SPC5_FLEXPWM_STS_RF (1U << 12)
#define SPC5_FLEXPWM_STS_REF (1U << 13)
#define SPC5_FLEXPWM_STS_RUF (1U << 14)
/** @} */
/**
* @name PSC values definition
* @{
*/
#define SPC5_FLEXPWM_PSC_1 0U
#define SPC5_FLEXPWM_PSC_2 1U
#define SPC5_FLEXPWM_PSC_4 2U
#define SPC5_FLEXPWM_PSC_8 3U
#define SPC5_FLEXPWM_PSC_16 4U
#define SPC5_FLEXPWM_PSC_32 5U
#define SPC5_FLEXPWM_PSC_64 6U
#define SPC5_FLEXPWM_PSC_128 7U
/** @} */
/**
* @brief Number of PWM channels per PWM driver.
*/
#define PWM_CHANNELS 2
/**
* @brief Complementary output modes mask.
* @note This is an SPC5-specific setting.
*/
#define PWM_COMPLEMENTARY_OUTPUT_MASK 0xF0
/**
* @brief Complementary output not driven.
* @note This is an SPC5-specific setting.
*/
#define PWM_COMPLEMENTARY_OUTPUT_DISABLED 0x00
/**
* @brief Complementary output, active is logic level one.
* @note This is an SPC5-specific setting.
*/
#define PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH 0x10
/**
* @brief Complementary output, active is logic level zero.
* @note This is an SPC5-specific setting.
*/
#define PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW 0x20
/**
* @brief Alignment mode mask.
* @note This is an SPC5-specific setting.
*/
#define PWM_ALIGN_MASK 0x01
/**
* @brief Edge-Aligned PWM functional mode.
* @note This is an SPC5-specific setting.
*/
#define PWM_ALIGN_EDGE 0x00
/**
* @brief Center-Aligned PWM functional mode.
* @note This is an SPC5-specific setting.
*/
#define PWM_ALIGN_CENTER 0x01
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief PWMD1 driver enable switch.
* @details If set to @p TRUE the support for PWMD1 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_PWM_USE_SMOD0) || defined(__DOXYGEN__)
#define SPC5_PWM_USE_SMOD0 FALSE
#endif
/**
* @brief PWMD2 driver enable switch.
* @details If set to @p TRUE the support for PWMD2 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_PWM_USE_SMOD1) || defined(__DOXYGEN__)
#define SPC5_PWM_USE_SMOD1 FALSE
#endif
/**
* @brief PWMD3 driver enable switch.
* @details If set to @p TRUE the support for PWMD3 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_PWM_USE_SMOD2) || defined(__DOXYGEN__)
#define SPC5_PWM_USE_SMOD2 FALSE
#endif
/**
* @brief PWMD4 driver enable switch.
* @details If set to @p TRUE the support for PWMD4 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_PWM_USE_SMOD3) || defined(__DOXYGEN__)
#define SPC5_PWM_USE_SMOD3 FALSE
#endif
/**
* @brief PWMD1 interrupt priority level setting.
*/
#if !defined(SPC5_PWM_SMOD0_PRIORITY) || defined(__DOXYGEN__)
#define SPC5_PWM_SMOD0_PRIORITY 7
#endif
/**
* @brief PWMD2 interrupt priority level setting.
*/
#if !defined(SPC5_PWM_SMOD1_PRIORITY) || defined(__DOXYGEN__)
#define SPC5_PWM_SMOD1_PRIORITY 7
#endif
/**
* @brief PWMD3 interrupt priority level setting.
*/
#if !defined(SPC5_PWM_SMOD2_PRIORITY) || defined(__DOXYGEN__)
#define SPC5_PWM_SMOD2_PRIORITY 7
#endif
/**
* @brief PWMD4 interrupt priority level setting.
*/
#if !defined(SPC5_PWM_SMOD3_PRIORITY) || defined(__DOXYGEN__)
#define SPC5_PWM_SMOD3_PRIORITY 7
#endif
/**
* @brief FlexPWM-0 peripheral configuration when started.
* @note The default configuration is 1 (always run) in run mode and
* 2 (only halt) in low power mode. The defaults of the run modes
* are defined in @p hal_lld.h.
*/
#if !defined(SPC5_PWM_FLEXPWM0_START_PCTL) || defined(__DOXYGEN__)
#define SPC5_PWM_FLEXPWM0_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
SPC5_ME_PCTL_LP(2))
#endif
/**
* @brief FlexPWM-0 peripheral configuration when stopped.
* @note The default configuration is 0 (never run) in run mode and
* 0 (never run) in low power mode. The defaults of the run modes
* are defined in @p hal_lld.h.
*/
#if !defined(SPC5_PWM_FLEXPWM0_STOP_PCTL) || defined(__DOXYGEN__)
#define SPC5_PWM_FLEXPWM0_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
SPC5_ME_PCTL_LP(0))
#endif
/**
* @brief PWMD5 driver enable switch.
* @details If set to @p TRUE the support for PWMD5 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_PWM_USE_SMOD4) || defined(__DOXYGEN__)
#define SPC5_PWM_USE_SMOD4 FALSE
#endif
/**
* @brief PWMD6 driver enable switch.
* @details If set to @p TRUE the support for PWMD6 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_PWM_USE_SMOD5) || defined(__DOXYGEN__)
#define SPC5_PWM_USE_SMOD5 FALSE
#endif
/**
* @brief PWMD7 driver enable switch.
* @details If set to @p TRUE the support for PWMD7 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_PWM_USE_SMOD6) || defined(__DOXYGEN__)
#define SPC5_PWM_USE_SMOD6 FALSE
#endif
/**
* @brief PWMD8 driver enable switch.
* @details If set to @p TRUE the support for PWMD8 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_PWM_USE_SMOD7) || defined(__DOXYGEN__)
#define SPC5_PWM_USE_SMOD7 FALSE
#endif
/**
* @brief PWMD5 interrupt priority level setting.
*/
#if !defined(SPC5_PWM_SMOD4_PRIORITY) || defined(__DOXYGEN__)
#define SPC5_PWM_SMOD4_PRIORITY 7
#endif
/**
* @brief PWMD6 interrupt priority level setting.
*/
#if !defined(SPC5_PWM_SMOD5_PRIORITY) || defined(__DOXYGEN__)
#define SPC5_PWM_SMOD5_PRIORITY 7
#endif
/**
* @brief PWMD7 interrupt priority level setting.
*/
#if !defined(SPC5_PWM_SMOD6_PRIORITY) || defined(__DOXYGEN__)
#define SPC5_PWM_SMOD6_PRIORITY 7
#endif
/**
* @brief PWMD8 interrupt priority level setting.
*/
#if !defined(SPC5_PWM_SMOD7_PRIORITY) || defined(__DOXYGEN__)
#define SPC5_PWM_SMOD7_PRIORITY 7
#endif
/**
* @brief FlexPWM-1 peripheral configuration when started.
* @note The default configuration is 1 (always run) in run mode and
* 2 (only halt) in low power mode. The defaults of the run modes
* are defined in @p hal_lld.h.
*/
#if !defined(SPC5_PWM_FLEXPWM1_START_PCTL) || defined(__DOXYGEN__)
#define SPC5_PWM_FLEXPWM1_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
SPC5_ME_PCTL_LP(2))
#endif
/**
* @brief FlexPWM-1 peripheral configuration when stopped.
* @note The default configuration is 0 (never run) in run mode and
* 0 (never run) in low power mode. The defaults of the run modes
* are defined in @p hal_lld.h.
*/
#if !defined(SPC5_PWM_FLEXPWM1_STOP_PCTL) || defined(__DOXYGEN__)
#define SPC5_PWM_FLEXPWM1_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
SPC5_ME_PCTL_LP(0))
#endif
/*===========================================================================*/
/* Configuration checks. */
/*===========================================================================*/
#define SPC5_PWM_USE_FLEXPWM0 (SPC5_PWM_USE_SMOD0 || \
SPC5_PWM_USE_SMOD1 || \
SPC5_PWM_USE_SMOD2 || \
SPC5_PWM_USE_SMOD3)
#define SPC5_PWM_USE_FLEXPWM1 (SPC5_PWM_USE_SMOD4 || \
SPC5_PWM_USE_SMOD5 || \
SPC5_PWM_USE_SMOD6 || \
SPC5_PWM_USE_SMOD7)
#if !SPC5_HAS_FLEXPWM0 && SPC5_PWM_USE_FLEXPWM0
#error "FlexPWM0 not present in the selected device"
#endif
#if !SPC5_HAS_FLEXPWM1 && SPC5_PWM_USE_FLEXPWM1
#error "FlexPWM1 not present in the selected device"
#endif
#if !SPC5_PWM_USE_FLEXPWM0 && !SPC5_PWM_USE_FLEXPWM1
#error "PWM driver activated but no PWM peripheral assigned"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief PWM mode type.
*/
typedef uint32_t pwmmode_t;
/**
* @brief PWM channel type.
*/
typedef uint8_t pwmchannel_t;
/**
* @brief PWM counter type.
*/
typedef uint16_t pwmcnt_t;
/**
* @brief PWM driver channel configuration structure.
*/
typedef struct {
/**
* @brief Channel active logic level.
*/
pwmmode_t mode;
/**
* @brief Channel callback pointer.
* @note This callback is invoked on the channel compare event. If set to
* @p NULL then the callback is disabled.
*/
pwmcallback_t callback;
/* End of the mandatory fields.*/
} PWMChannelConfig;
/**
* @brief PWM driver configuration structure.
*/
typedef struct {
/**
* @brief Timer clock in Hz.
* @note The low level can use assertions in order to catch invalid
* frequency specifications.
*/
uint32_t frequency;
/**
* @brief PWM period in ticks.
* @note The low level can use assertions in order to catch invalid
* period specifications.
*/
pwmcnt_t period;
/**
* @brief Periodic callback pointer.
* @note This callback is invoked on PWM counter reset. If set to
* @p NULL then the callback is disabled.
*/
pwmcallback_t callback;
/**
* @brief Channels configurations.
*/
PWMChannelConfig channels[PWM_CHANNELS];
/* End of the mandatory fields.*/
/**
* @brief PWM functional mode.
*/
pwmmode_t mode;
} PWMConfig;
/**
* @brief Structure representing a PWM driver.
*/
struct PWMDriver {
/**
* @brief Driver state.
*/
pwmstate_t state;
/**
* @brief Current driver configuration data.
*/
const PWMConfig *config;
/**
* @brief Current PWM period in ticks.
*/
pwmcnt_t period;
#if defined(PWM_DRIVER_EXT_FIELDS)
PWM_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @Pointer to the volatile FlexPWM registers block.
*/
volatile struct spc5_flexpwm *flexpwmp;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if SPC5_PWM_USE_SMOD0 && !defined(__DOXYGEN__)
extern PWMDriver PWMD1;
#endif
#if SPC5_PWM_USE_SMOD1 && !defined(__DOXYGEN__)
extern PWMDriver PWMD2;
#endif
#if SPC5_PWM_USE_SMOD2 && !defined(__DOXYGEN__)
extern PWMDriver PWMD3;
#endif
#if SPC5_PWM_USE_SMOD3 && !defined(__DOXYGEN__)
extern PWMDriver PWMD4;
#endif
#if SPC5_PWM_USE_SMOD4 && !defined(__DOXYGEN__)
extern PWMDriver PWMD5;
#endif
#if SPC5_PWM_USE_SMOD5 && !defined(__DOXYGEN__)
extern PWMDriver PWMD6;
#endif
#if SPC5_PWM_USE_SMOD6 && !defined(__DOXYGEN__)
extern PWMDriver PWMD7;
#endif
#if SPC5_PWM_USE_SMOD7 && !defined(__DOXYGEN__)
extern PWMDriver PWMD8;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void pwm_lld_init(void);
void pwm_lld_start(PWMDriver *pwmp);
void pwm_lld_stop(PWMDriver *pwmp);
void pwm_lld_enable_channel(PWMDriver *pwmp,
pwmchannel_t channel,
pwmcnt_t width);
void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel);
void pwm_lld_change_period(PWMDriver *pwmp, pwmcnt_t period);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_PWM */
#endif /* _PWM_LLD_H_ */
/** @} */
@@ -0,0 +1,491 @@
/*
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
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 FlexPWM_v1/spc5_flexpwm.h
* @brief SPC5xx FlexPWM header file.
*
* @addtogroup PWM
* @{
*/
#ifndef _SPC5_FLEXPWM_H_
#define _SPC5_FLEXPWM_H_
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief SPC5 FlexPWM registers block.
* @note Redefined from the SPC5 headers because the non uniform
* declaration of the SubModules registers among the various
* sub-families.
*/
struct spc5_flexpwm_submodule {
union {
vuint16_t R;
} CNT; /* Counter Register */
union {
vuint16_t R;
} INIT; /* Initial Count Register */
union {
vuint16_t R;
struct {
vuint16_t DBGEN :1;
vuint16_t WAITEN :1;
vuint16_t INDEP :1;
vuint16_t PWMA_INIT :1;
vuint16_t PWMB_INIT :1;
vuint16_t PWMX_INIT :1;
vuint16_t INIT_SEL :2;
vuint16_t FRCEN :1;
vuint16_t FORCE :1;
vuint16_t FORCE_SEL :3;
vuint16_t RELOAD_SEL :1;
vuint16_t CLK_SEL :2;
} B;
} CTRL2; /* Control 2 Register */
union {
vuint16_t R;
struct {
vuint16_t LDFQ :4;
vuint16_t HALF :1;
vuint16_t FULL :1;
vuint16_t DT :2;
vuint16_t :1;
vuint16_t PRSC :3;
vuint16_t :3;
vuint16_t DBLEN :1;
} B;
} CTRL; /* Control Register */
union {
vuint16_t R;
} VAL[6]; /* Value Register 0->5 */
union {
vuint16_t R;
struct {
vuint16_t FRACAEN :1;
vuint16_t :10;
vuint16_t FRACADLY :5;
} B;
} FRACA; /* Fractional Delay Register A */
union {
vuint16_t R;
struct {
vuint16_t FRACBEN :1;
vuint16_t :10;
vuint16_t FRACBDLY :5;
} B;
} FRACB; /* Fractional Delay Register B */
union {
vuint16_t R;
struct {
vuint16_t PWMA_IN :1;
vuint16_t PWMB_IN :1;
vuint16_t PWMX_IN :1;
vuint16_t :2;
vuint16_t POLA :1;
vuint16_t POLB :1;
vuint16_t POLX :1;
vuint16_t :2;
vuint16_t PWMAFS :2;
vuint16_t PWMBFS :2;
vuint16_t PWMXFS :2;
} B;
} OCTRL; /* Output Control Register */
union {
vuint16_t R;
struct {
vuint16_t :1;
vuint16_t RUF :1;
vuint16_t REF :1;
vuint16_t RF :1;
vuint16_t CFA1 :1;
vuint16_t CFA0 :1;
vuint16_t CFB1 :1;
vuint16_t CFB0 :1;
vuint16_t CFX1 :1;
vuint16_t CFX0 :1;
vuint16_t CMPF :6;
} B;
} STS; /* Status Register */
union {
vuint16_t R;
struct {
vuint16_t :2;
vuint16_t REIE :1;
vuint16_t RIE :1;
vuint16_t :4;
vuint16_t CX1IE :1;
vuint16_t CX0IE :1;
vuint16_t CMPIE :6;
} B;
} INTEN; /* Interrupt Enable Register */
union {
vuint16_t R;
struct {
vuint16_t :6;
vuint16_t VALDE :1;
vuint16_t FAND :1;
vuint16_t CAPTDE :2;
vuint16_t CA1DE :1;
vuint16_t CA0DE :1;
vuint16_t CB1DE :1;
vuint16_t CB0DE :1;
vuint16_t CX1DE :1;
vuint16_t CX0DE :1;
} B;
} DMAEN; /* DMA Enable Register */
union {
vuint16_t R;
struct {
vuint16_t :10;
vuint16_t OUT_TRIG_EN :6;
} B;
} TCTRL; /* Output Trigger Control Register */
union {
vuint16_t R;
struct {
vuint16_t :4;
vuint16_t DISX :4;
vuint16_t DISB :4;
vuint16_t DISA :4;
} B;
} DISMAP; /* Fault Disable Mapping Register */
union {
vuint16_t R;
struct {
vuint16_t :5;
vuint16_t DTCNT0 :11;
} B;
} DTCNT0; /* Deadtime Count Register 0 */
union {
vuint16_t R;
struct {
vuint16_t :5;
vuint16_t DTCNT1 :11;
} B;
} DTCNT1; /* Deadtime Count Register 1 */
union {
vuint16_t R;
struct {
vuint16_t CA1CNT :3;
vuint16_t CA0CNT :3;
vuint16_t CFAWM :2;
vuint16_t EDGCNTAEN :1;
vuint16_t INPSELA :1;
vuint16_t EDGA1 :2;
vuint16_t EDGA0 :2;
vuint16_t ONESHOTA :1;
vuint16_t ARMA :1;
} B;
} CAPTCTRLA; /* Capture Control Register A */
union {
vuint16_t R;
struct {
vuint16_t EDGCNTA :8;
vuint16_t EDGCMPA :8;
} B;
} CAPTCOMPA; /* Capture Compare Register A */
union {
vuint16_t R;
struct {
vuint16_t CB1CNT :3;
vuint16_t CB0CNT :3;
vuint16_t CFBWM :2;
vuint16_t EDGCNTBEN :1;
vuint16_t INPSELB :1;
vuint16_t EDGB1 :2;
vuint16_t EDGB0 :2;
vuint16_t ONESHOTB :1;
vuint16_t ARMB :1;
} B;
} CAPTCTRLB; /* Capture Control Register B */
union {
vuint16_t R;
struct {
vuint16_t EDGCNTB :8;
vuint16_t EDGCMPB :8;
} B;
} CAPTCOMPB; /* Capture Compare Register B */
union {
vuint16_t R;
struct {
vuint16_t CX1CNT :3;
vuint16_t CX0CNT :3;
vuint16_t CFXWM :2;
vuint16_t EDGCNTX_EN :1;
vuint16_t INP_SELX :1;
vuint16_t EDGX1 :2;
vuint16_t EDGX0 :2;
vuint16_t ONESHOTX :1;
vuint16_t ARMX :1;
} B;
} CAPTCTRLX; /* Capture Control Register B */
union {
vuint16_t R;
struct {
vuint16_t EDGCNTX :8;
vuint16_t EDGCMPX :8;
} B;
} CAPTCOMPX; /* Capture Compare Register X */
union {
vuint16_t R;
struct {
vuint16_t CAPTVAL0 :16;
} B;
} CVAL0; /* Capture Value 0 Register */
union {
vuint16_t R;
struct {
vuint16_t :12;
vuint16_t CVAL0CYC :4;
} B;
} CVAL0C; /* Capture Value 0 Cycle Register */
union {
vuint16_t R;
struct {
vuint16_t CAPTVAL1 :16;
} B;
} CVAL1; /* Capture Value 1 Register */
union {
vuint16_t R;
struct {
vuint16_t :12;
vuint16_t CVAL1CYC :4;
} B;
} CVAL1C; /* Capture Value 1 Cycle Register */
union {
vuint16_t R;
struct {
vuint16_t CAPTVAL2 :16;
} B;
} CVAL2; /* Capture Value 2 Register */
union {
vuint16_t R;
struct {
vuint16_t :12;
vuint16_t CVAL2CYC :4;
} B;
} CVAL2C; /* Capture Value 2 Cycle Register */
union {
vuint16_t R;
struct {
vuint16_t CAPTVAL3 :16;
} B;
} CVAL3; /* Capture Value 3 Register */
union {
vuint16_t R;
struct {
vuint16_t :12;
vuint16_t CVAL3CYC :4;
} B;
} CVAL3C; /* Capture Value 3 Cycle Register */
union {
vuint16_t R;
struct {
vuint16_t CAPTVAL4 :16;
} B;
} CVAL4; /* Capture Value 4 Register */
union {
vuint16_t R;
struct {
vuint16_t :12;
vuint16_t CVAL4CYC :4;
} B;
} CVAL4C; /* Capture Value 4 Cycle Register */
union {
vuint16_t R;
struct {
vuint16_t CAPTVAL5 :16;
} B;
} CVAL5; /* Capture Value 5 Register */
union {
vuint16_t R;
struct {
vuint16_t :12;
vuint16_t CVAL5CYC :4;
} B;
} CVAL5C; /* Capture Value 5 Cycle Register */
uint32_t FLEXPWM_SUB_reserved0; /* (0x04A - 0x050)/4 = 0x01 */
};
/* end of FLEXPWM_SUB_tag */
struct spc5_flexpwm {
struct spc5_flexpwm_submodule SUB[4];
union {
vuint16_t R;
struct {
vuint16_t :4;
vuint16_t PWMA_EN :4;
vuint16_t PWMB_EN :4;
vuint16_t PWMX_EN :4;
} B;
} OUTEN; /* Output Enable Register */
union {
vuint16_t R;
struct {
vuint16_t :4;
vuint16_t MASKA :4;
vuint16_t MASKB :4;
vuint16_t MASKX :4;
} B;
} MASK; /* Output Mask Register */
union {
vuint16_t R;
struct {
vuint16_t :8;
vuint16_t OUTA_3 :1;
vuint16_t OUTB_3 :1;
vuint16_t OUTA_2 :1;
vuint16_t OUTB_2 :1;
vuint16_t OUTA_1 :1;
vuint16_t OUTB_1 :1;
vuint16_t OUTA_0 :1;
vuint16_t OUTB_0 :1;
} B;
} SWCOUT; /* Software Controlled Output Register */
union {
vuint16_t R;
struct {
vuint16_t SELA_3 :2;
vuint16_t SELB_3 :2;
vuint16_t SELA_2 :2;
vuint16_t SELB_2 :2;
vuint16_t SELA_1 :2;
vuint16_t SELB_1 :2;
vuint16_t SELA_0 :2;
vuint16_t SELB_0 :2;
} B;
} DTSRCSEL; /* Deadtime Source Select Register */
union {
vuint16_t R;
struct {
vuint16_t IPOL :4;
vuint16_t RUN :4;
vuint16_t CLDOK :4;
vuint16_t LDOK :4;
} B;
} MCTRL; /* Master Control Register */
int16_t FLEXPWM_reserved1;
union {
vuint16_t R;
struct {
vuint16_t FLVL :4;
vuint16_t FAUTO :4;
vuint16_t FSAFE :4;
vuint16_t FIE :4;
} B;
} FCTRL; /* Fault Control Register */
union {
vuint16_t R;
struct {
vuint16_t :3;
vuint16_t FTEST :1;
vuint16_t FFPIN :4;
vuint16_t :4;
vuint16_t FFLAG :4;
} B;
} FSTS; /* Fault Status Register */
union {
vuint16_t R;
struct {
vuint16_t :5;
vuint16_t FILT_CNT :3;
vuint16_t FILT_PER :8;
} B;
} FFILT; /* Fault FilterRegister */
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name FlexPWM units references
* @{
*/
#if SPC5_HAS_FLEXPWM0 || defined(__DOXYGEN__)
#define SPC5_FLEXPWM_0 (*(volatile struct spc5_flexpwm *)0xFFE24000UL)
#endif
#if SPC5_HAS_FLEXPWM1 || defined(__DOXYGEN__)
#define SPC5_FLEXPWM_1 (*(volatile struct spc5_flexpwm *)0xFFE28000UL)
#endif
/** @} */
#endif /* _SPC5_FLEXPWM_H_ */
/** @} */
@@ -0,0 +1,426 @@
/*
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
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 SPC5xx/LINFlex_v1/serial_lld.c
* @brief SPC5xx low level serial driver code.
*
* @addtogroup SERIAL
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief LIINFlex-0 serial driver identifier.
*/
#if SPC5_SERIAL_USE_LINFLEX0 || defined(__DOXYGEN__)
SerialDriver SD1;
#endif
/**
* @brief LIINFlex-1 serial driver identifier.
*/
#if SPC5_SERIAL_USE_LINFLEX1 || defined(__DOXYGEN__)
SerialDriver SD2;
#endif
/**
* @brief LIINFlex-2 serial driver identifier.
*/
#if SPC5_SERIAL_USE_LINFLEX2 || defined(__DOXYGEN__)
SerialDriver SD3;
#endif
/**
* @brief LIINFlex-3 serial driver identifier.
*/
#if SPC5_SERIAL_USE_LINFLEX3 || defined(__DOXYGEN__)
SerialDriver SD4;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/**
* @brief Driver default configuration.
*/
static const SerialConfig default_config = {
SERIAL_DEFAULT_BITRATE,
SD_MODE_8BITS_PARITY_NONE
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief LINFlex initialization.
* @details This function must be invoked with interrupts disabled.
*
* @param[in] sdp pointer to a @p SerialDriver object
* @param[in] config the architecture-dependent serial driver configuration
*/
static void spc5_linflex_init(SerialDriver *sdp, const SerialConfig *config) {
uint32_t div;
volatile struct LINFLEX_tag *linflexp = sdp->linflexp;
/* Enters the configuration mode.*/
linflexp->LINCR1.R = 1; /* INIT bit. */
/* Configures the LINFlex in UART mode with all the required
parameters.*/
linflexp->UARTCR.R = SPC5_UARTCR_UART; /* UART mode FIRST. */
linflexp->UARTCR.R = SPC5_UARTCR_UART | SPC5_UARTCR_RXEN | config->mode;
div = SPC5_LINFLEX0_CLK / config->speed;
linflexp->LINFBRR.R = (uint16_t)(div & 15); /* Fractional divider. */
linflexp->LINIBRR.R = (uint16_t)(div >> 4); /* Integer divider. */
linflexp->UARTSR.R = 0xFFFF; /* Clearing UARTSR register.*/
linflexp->LINIER.R = SPC5_LINIER_DTIE | SPC5_LINIER_DRIE |
SPC5_LINIER_BOIE | SPC5_LINIER_FEIE |
SPC5_LINIER_SZIE; /* Interrupts enabled. */
/* Leaves the configuration mode.*/
linflexp->LINCR1.R = 0;
}
/**
* @brief LINFlex de-initialization.
* @details This function must be invoked with interrupts disabled.
*
* @param[in] linflexp pointer to a LINFlex I/O block
*/
static void spc5_linflex_deinit(volatile struct LINFLEX_tag *linflexp) {
/* Enters the configuration mode.*/
linflexp->LINCR1.R = 1; /* INIT bit. */
/* Resets the LINFlex registers.*/
linflexp->LINFBRR.R = 0; /* Fractional divider. */
linflexp->LINIBRR.R = 0; /* Integer divider. */
linflexp->UARTSR.R = 0xFFFF; /* Clearing UARTSR register.*/
linflexp->UARTCR.R = SPC5_UARTCR_UART;
linflexp->LINIER.R = 0; /* Interrupts disabled. */
/* Leaves the configuration mode.*/
linflexp->LINCR1.R = 0;
}
/**
* @brief Common RXI IRQ handler.
*
* @param[in] sdp pointer to a @p SerialDriver object
*/
static void spc5xx_serve_rxi_interrupt(SerialDriver *sdp) {
flagsmask_t sts = 0;
uint16_t sr = sdp->linflexp->UARTSR.R;
sdp->linflexp->UARTSR.R = SPC5_UARTSR_NF | SPC5_UARTSR_DRF |
SPC5_UARTSR_PE0;
if (sr & SPC5_UARTSR_NF)
sts |= SD_NOISE_ERROR;
if (sr & SPC5_UARTSR_PE0)
sts |= SD_PARITY_ERROR;
chSysLockFromIsr();
if (sts)
chnAddFlagsI(sdp, sts);
if (sr & SPC5_UARTSR_DRF) {
sdIncomingDataI(sdp, sdp->linflexp->BDRM.B.DATA4);
sdp->linflexp->UARTSR.R = SPC5_UARTSR_RMB;
}
chSysUnlockFromIsr();
}
/**
* @brief Common TXI IRQ handler.
*
* @param[in] sdp pointer to a @p SerialDriver object
*/
static void spc5xx_serve_txi_interrupt(SerialDriver *sdp) {
msg_t b;
sdp->linflexp->UARTSR.R = SPC5_UARTSR_DTF;
chSysLockFromIsr();
b = chOQGetI(&sdp->oqueue);
if (b < Q_OK) {
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
sdp->linflexp->UARTCR.B.TXEN = 0;
}
else
sdp->linflexp->BDRL.B.DATA0 = b;
chSysUnlockFromIsr();
}
/**
* @brief Common ERR IRQ handler.
*
* @param[in] sdp pointer to a @p SerialDriver object
*/
static void spc5xx_serve_err_interrupt(SerialDriver *sdp) {
flagsmask_t sts = 0;
uint16_t sr = sdp->linflexp->UARTSR.R;
sdp->linflexp->UARTSR.R = SPC5_UARTSR_BOF | SPC5_UARTSR_FEF |
SPC5_UARTSR_SZF;
if (sr & SPC5_UARTSR_BOF)
sts |= SD_OVERRUN_ERROR;
if (sr & SPC5_UARTSR_FEF)
sts |= SD_FRAMING_ERROR;
if (sr & SPC5_UARTSR_SZF)
sts |= SD_BREAK_DETECTED;
chSysLockFromIsr();
chnAddFlagsI(sdp, sts);
chSysUnlockFromIsr();
}
#if SPC5_SERIAL_USE_LINFLEX0 || defined(__DOXYGEN__)
static void notify1(GenericQueue *qp) {
(void)qp;
if (!SD1.linflexp->UARTCR.B.TXEN) {
msg_t b = sdRequestDataI(&SD1);
if (b != Q_EMPTY) {
SD1.linflexp->UARTCR.B.TXEN = 1;
SD1.linflexp->BDRL.B.DATA0 = b;
}
}
}
#endif
#if SPC5_SERIAL_USE_LINFLEX1 || defined(__DOXYGEN__)
static void notify2(GenericQueue *qp) {
(void)qp;
if (!SD2.linflexp->UARTCR.B.TXEN) {
msg_t b = sdRequestDataI(&SD2);
if (b != Q_EMPTY) {
SD2.linflexp->UARTCR.B.TXEN = 1;
SD2.linflexp->BDRL.B.DATA0 = b;
}
}
}
#endif
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if SPC5_SERIAL_USE_LINFLEX0 || defined(__DOXYGEN__)
#if !defined(SPC5_LINFLEX0_RXI_HANDLER)
#error "SPC5_LINFLEX0_RXI_HANDLER not defined"
#endif
/**
* @brief LINFlex-0 RXI interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(SPC5_LINFLEX0_RXI_HANDLER) {
CH_IRQ_PROLOGUE();
spc5xx_serve_rxi_interrupt(&SD1);
CH_IRQ_EPILOGUE();
}
#if !defined(SPC5_LINFLEX0_TXI_HANDLER)
#error "SPC5_LINFLEX0_TXI_HANDLER not defined"
#endif
/**
* @brief LINFlex-0 TXI interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(SPC5_LINFLEX0_TXI_HANDLER) {
CH_IRQ_PROLOGUE();
spc5xx_serve_txi_interrupt(&SD1);
CH_IRQ_EPILOGUE();
}
#if !defined(SPC5_LINFLEX0_ERR_HANDLER)
#error "SPC5_LINFLEX0_ERR_HANDLER not defined"
#endif
/**
* @brief LINFlex-0 ERR interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(SPC5_LINFLEX0_ERR_HANDLER) {
CH_IRQ_PROLOGUE();
spc5xx_serve_err_interrupt(&SD1);
CH_IRQ_EPILOGUE();
}
#endif
#if SPC5_SERIAL_USE_LINFLEX1 || defined(__DOXYGEN__)
#if !defined(SPC5_LINFLEX1_RXI_HANDLER)
#error "SPC5_LINFLEX1_RXI_HANDLER not defined"
#endif
/**
* @brief LINFlex-1 RXI interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(SPC5_LINFLEX1_RXI_HANDLER) {
CH_IRQ_PROLOGUE();
spc5xx_serve_rxi_interrupt(&SD2);
CH_IRQ_EPILOGUE();
}
#if !defined(SPC5_LINFLEX1_TXI_HANDLER)
#error "SPC5_LINFLEX1_TXI_HANDLER not defined"
#endif
/**
* @brief LINFlex-1 TXI interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(SPC5_LINFLEX1_TXI_HANDLER) {
CH_IRQ_PROLOGUE();
spc5xx_serve_txi_interrupt(&SD2);
CH_IRQ_EPILOGUE();
}
#if !defined(SPC5_LINFLEX1_ERR_HANDLER)
#error "SPC5_LINFLEX1_ERR_HANDLER not defined"
#endif
/**
* @brief LINFlex-1 ERR interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(SPC5_LINFLEX1_ERR_HANDLER) {
CH_IRQ_PROLOGUE();
spc5xx_serve_err_interrupt(&SD2);
CH_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level serial driver initialization.
*
* @notapi
*/
void sd_lld_init(void) {
#if SPC5_SERIAL_USE_LINFLEX0
sdObjectInit(&SD1, NULL, notify1);
SD1.linflexp = &LINFLEX_0;
INTC.PSR[SPC5_LINFLEX0_RXI_NUMBER].R = SPC5_SERIAL_LINFLEX0_PRIORITY;
INTC.PSR[SPC5_LINFLEX0_TXI_NUMBER].R = SPC5_SERIAL_LINFLEX0_PRIORITY;
INTC.PSR[SPC5_LINFLEX0_ERR_NUMBER].R = SPC5_SERIAL_LINFLEX0_PRIORITY;
#endif
#if SPC5_SERIAL_USE_LINFLEX1
sdObjectInit(&SD2, NULL, notify2);
SD2.linflexp = &LINFLEX_1;
INTC.PSR[SPC5_LINFLEX1_RXI_NUMBER].R = SPC5_SERIAL_LINFLEX1_PRIORITY;
INTC.PSR[SPC5_LINFLEX1_TXI_NUMBER].R = SPC5_SERIAL_LINFLEX1_PRIORITY;
INTC.PSR[SPC5_LINFLEX1_ERR_NUMBER].R = SPC5_SERIAL_LINFLEX1_PRIORITY;
#endif
}
/**
* @brief Low level serial driver configuration and (re)start.
*
* @param[in] sdp pointer to a @p SerialDriver object
* @param[in] config the architecture-dependent serial driver configuration.
* If this parameter is set to @p NULL then a default
* configuration is used.
*
* @notapi
*/
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
if (config == NULL)
config = &default_config;
if (sdp->state == SD_STOP) {
#if SPC5_SERIAL_USE_LINFLEX0
if (&SD1 == sdp) {
halSPCSetPeripheralClockMode(SPC5_LINFLEX0_PCTL,
SPC5_SERIAL_LINFLEX0_START_PCTL);
}
#endif
#if SPC5_SERIAL_USE_LINFLEX1
if (&SD2 == sdp) {
halSPCSetPeripheralClockMode(SPC5_LINFLEX1_PCTL,
SPC5_SERIAL_LINFLEX1_START_PCTL);
}
#endif
}
spc5_linflex_init(sdp, config);
}
/**
* @brief Low level serial driver stop.
*
* @param[in] sdp pointer to a @p SerialDriver object
*
* @notapi
*/
void sd_lld_stop(SerialDriver *sdp) {
if (sdp->state == SD_READY) {
spc5_linflex_deinit(sdp->linflexp);
#if SPC5_SERIAL_USE_LINFLEX0
if (&SD1 == sdp) {
halSPCSetPeripheralClockMode(SPC5_LINFLEX0_PCTL,
SPC5_SERIAL_LINFLEX0_STOP_PCTL);
return;
}
#endif
#if SPC5_SERIAL_USE_LINFLEX1
if (&SD2 == sdp) {
halSPCSetPeripheralClockMode(SPC5_LINFLEX1_PCTL,
SPC5_SERIAL_LINFLEX1_STOP_PCTL);
return;
}
#endif
}
}
#endif /* HAL_USE_SERIAL */
/** @} */
@@ -0,0 +1,278 @@
/*
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
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 SPC5xx/LINFlex_v1/serial_lld.h
* @brief SPC5xx low level serial driver header.
*
* @addtogroup SERIAL
* @{
*/
#ifndef _SERIAL_LLD_H_
#define _SERIAL_LLD_H_
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name LINIER register bits definitions
* @{
*/
#define SPC5_LINIER_HRIE (1U << 0)
#define SPC5_LINIER_DTIE (1U << 1)
#define SPC5_LINIER_DRIE (1U << 2)
#define SPC5_LINIER_DBEIE (1U << 3)
#define SPC5_LINIER_DBFIE (1U << 4)
#define SPC5_LINIER_WUIE (1U << 5)
#define SPC5_LINIER_LSIE (1U << 6)
#define SPC5_LINIER_BOIE (1U << 7)
#define SPC5_LINIER_FEIE (1U << 8)
#define SPC5_LINIER_HEIE (1U << 11)
#define SPC5_LINIER_CEIE (1U << 12)
#define SPC5_LINIER_BEIE (1U << 13)
#define SPC5_LINIER_OCIE (1U << 14)
#define SPC5_LINIER_SZIE (1U << 15)
/** @} */
/**
* @name UARTSR register bits definitions
* @{
*/
#define SPC5_UARTSR_NF (1U << 0)
#define SPC5_UARTSR_DTF (1U << 1)
#define SPC5_UARTSR_DRF (1U << 2)
#define SPC5_UARTSR_WUF (1U << 5)
#define SPC5_UARTSR_RPS (1U << 6)
#define SPC5_UARTSR_BOF (1U << 7)
#define SPC5_UARTSR_FEF (1U << 8)
#define SPC5_UARTSR_RMB (1U << 9)
#define SPC5_UARTSR_PE0 (1U << 10)
#define SPC5_UARTSR_PE1 (1U << 11)
#define SPC5_UARTSR_PE2 (1U << 12)
#define SPC5_UARTSR_PE3 (1U << 13)
#define SPC5_UARTSR_OCF (1U << 14)
#define SPC5_UARTSR_SZF (1U << 15)
/** @} */
/**
* @name UARTCR register bits definitions
* @{
*/
#define SPC5_UARTCR_UART (1U << 0)
#define SPC5_UARTCR_WL (1U << 1)
#define SPC5_UARTCR_PCE (1U << 2)
#define SPC5_UARTCR_OP (1U << 3)
#define SPC5_UARTCR_TXEN (1U << 4)
#define SPC5_UARTCR_RXEN (1U << 5)
/** @} */
/**
* @name Serial driver allowable modes
* @{
*/
#define SD_MODE_8BITS_PARITY_NONE (SPC5_UARTCR_WL)
#define SD_MODE_8BITS_PARITY_EVEN (SPC5_UARTCR_WL | \
SPC5_UARTCR_PCE)
#define SD_MODE_8BITS_PARITY_ODD (SPC5_UARTCR_WL | \
SPC5_UARTCR_PCE | \
SPC5_UARTCR_OP)
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief LINFlex-0 driver enable switch.
* @details If set to @p TRUE the support for LINFlex-0 is included.
*/
#if !defined(SPC5_SERIAL_USE_LINFLEX0) || defined(__DOXYGEN__)
#define SPC5_SERIAL_USE_LINFLEX0 TRUE
#endif
/**
* @brief LINFlex-1 driver enable switch.
* @details If set to @p TRUE the support for LINFlex-1 is included.
*/
#if !defined(SPC5_SERIAL_USE_LINFLEX1) || defined(__DOXYGEN__)
#define SPC5_SERIAL_USE_LINFLEX1 TRUE
#endif
/**
* @brief LINFlex-0 interrupt priority level setting.
*/
#if !defined(SPC5_SERIAL_LINFLEX0_PRIORITY) || defined(__DOXYGEN__)
#define SPC5_SERIAL_LINFLEX0_PRIORITY 8
#endif
/**
* @brief LINFlex-1 interrupt priority level setting.
*/
#if !defined(SPC5_SERIAL_LINFLEX1_PRIORITY) || defined(__DOXYGEN__)
#define SPC5_SERIAL_LINFLEX1_PRIORITY 8
#endif
/**
* @brief LINFlex-0 peripheral configuration when started.
* @note The default configuration is 1 (always run) in run mode and
* 2 (only halt) in low power mode. The defaults of the run modes
* are defined in @p hal_lld.h.
*/
#if !defined(SPC5_SERIAL_LINFLEX0_START_PCTL) || defined(__DOXYGEN__)
#define SPC5_SERIAL_LINFLEX0_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
SPC5_ME_PCTL_LP(2))
#endif
/**
* @brief LINFlex-0 peripheral configuration when stopped.
* @note The default configuration is 0 (never run) in run mode and
* 0 (never run) in low power mode. The defaults of the run modes
* are defined in @p hal_lld.h.
*/
#if !defined(SPC5_SERIAL_LINFLEX0_STOP_PCTL) || defined(__DOXYGEN__)
#define SPC5_SERIAL_LINFLEX0_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
SPC5_ME_PCTL_LP(0))
#endif
/**
* @brief LINFlex-1 peripheral configuration when started.
* @note The default configuration is 1 (always run) in run mode and
* 2 (only halt) in low power mode. The defaults of the run modes
* are defined in @p hal_lld.h.
*/
#if !defined(SPC5_SERIAL_LINFLEX1_START_PCTL) || defined(__DOXYGEN__)
#define SPC5_SERIAL_LINFLEX1_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
SPC5_ME_PCTL_LP(2))
#endif
/**
* @brief LINFlex-1 peripheral configuration when stopped.
* @note The default configuration is 0 (never run) in run mode and
* 0 (never run) in low power mode. The defaults of the run modes
* are defined in @p hal_lld.h.
*/
#if !defined(SPC5_SERIAL_LINFLEX1_STOP_PCTL) || defined(__DOXYGEN__)
#define SPC5_SERIAL_LINFLEX1_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
SPC5_ME_PCTL_LP(0))
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if SPC5_SERIAL_USE_LINFLEX0 && !SPC5_HAS_LINFLEX0
#error "LINFlex-0 not present in the selected device"
#endif
#if SPC5_SERIAL_USE_LINFLEX1 && !SPC5_HAS_LINFLEX1
#error "LINFlex-1 not present in the selected device"
#endif
#if SPC5_SERIAL_USE_LINFLEX2 && !SPC5_HAS_LINFLEX2
#error "LINFlex-2 not present in the selected device"
#endif
#if SPC5_SERIAL_USE_LINFLEX3 && !SPC5_HAS_LINFLEX3
#error "LINFlex-3 not present in the selected device"
#endif
#if !SPC5_SERIAL_USE_LINFLEX0 && !SPC5_SERIAL_USE_LINFLEX1 && \
!SPC5_SERIAL_USE_LINFLEX2 && !SPC5_SERIAL_USE_LINFLEX3
#error "SERIAL driver activated but no LINFlex 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 This structure content is architecture dependent, each driver
* implementation defines its own version and the custom static
* initializers.
*/
typedef struct {
/**
* @brief Bit rate.
*/
uint32_t speed;
/**
* @brief Mode flags.
*/
uint8_t mode;
} SerialConfig;
/**
* @brief @p SerialDriver specific data.
*/
#define _serial_driver_data \
_base_asynchronous_channel_data \
/* Driver state.*/ \
sdstate_t state; \
/* Input queue.*/ \
InputQueue iqueue; \
/* Output queue.*/ \
OutputQueue 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 volatile LINFlex registers block.*/ \
volatile struct LINFLEX_tag *linflexp;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if SPC5_SERIAL_USE_LINFLEX0 && !defined(__DOXYGEN__)
extern SerialDriver SD1;
#endif
#if SPC5_SERIAL_USE_LINFLEX1 && !defined(__DOXYGEN__)
extern SerialDriver SD2;
#endif
#if SPC5_SERIAL_USE_LINFLEX2 && !defined(__DOXYGEN__)
extern SerialDriver SD3;
#endif
#if SPC5_SERIAL_USE_LINFLEX3 && !defined(__DOXYGEN__)
extern SerialDriver SD4;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void sd_lld_init(void);
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config);
void sd_lld_stop(SerialDriver *sdp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SERIAL */
#endif /* _SERIAL_LLD_H_ */
/** @} */
+173
View File
@@ -0,0 +1,173 @@
/*
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
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 SPC5xx/SIUL_v1/pal_lld.c
* @brief SPC5xx SIUL low level driver code.
*
* @addtogroup PAL
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
#if defined(SPC5_SIUL_SYSTEM_PINS)
static const unsigned system_pins[] = {SPC5_SIUL_SYSTEM_PINS};
#endif
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief SPC5xx I/O ports configuration.
*
* @param[in] config the STM32 ports configuration
*
* @notapi
*/
void _pal_lld_init(const PALConfig *config) {
unsigned i;
#if defined(SPC5_SIUL_PCTL)
/* SIUL clock gating if present.*/
halSPCSetPeripheralClockMode(SPC5_SIUL_PCTL,
SPC5_ME_PCTL_RUN(2) | SPC5_ME_PCTL_LP(2));
#endif
/* Initialize PCR registers for undefined pads.*/
for (i = 0; i < SPC5_SIUL_NUM_PCRS; i++) {
#if defined(SPC5_SIUL_SYSTEM_PINS)
/* Handling the case where some SIU pins are not meant to be reprogrammed,
for example JTAG pins.*/
unsigned j;
for (j = 0; j < sizeof system_pins; j++) {
if (i == system_pins[j])
goto skip;
}
SIU.PCR[i].R = config->default_mode;
skip:
;
#else
SIU.PCR[i].R = config->default_mode;
#endif
}
/* Initialize PADSEL registers.*/
for (i = 0; i < SPC5_SIUL_NUM_PADSELS; i++)
SIU.PSMI[i].R = config->padsels[i];
/* Initialize PCR registers for defined pads.*/
i = 0;
while (config->inits[i].pcr_value != 0) {
SIU.GPDO[config->inits[i].pcr_index].R = config->inits[i].gpdo_value;
SIU.PCR[config->inits[i].pcr_index].R = config->inits[i].pcr_value;
i++;
}
}
/**
* @brief Reads a group of bits.
*
* @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
*/
ioportmask_t _pal_lld_readgroup(ioportid_t port,
ioportmask_t mask,
uint_fast8_t offset) {
(void)port;
(void)mask;
(void)offset;
return 0;
}
/**
* @brief Writes a group of bits.
*
* @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
*/
void _pal_lld_writegroup(ioportid_t port,
ioportmask_t mask,
uint_fast8_t offset,
ioportmask_t bits) {
(void)port;
(void)mask;
(void)offset;
(void)bits;
}
/**
* @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) {
unsigned pcr_index = (unsigned)(port * PAL_IOPORTS_WIDTH);
ioportmask_t m1 = 0x8000;
while (m1) {
if (mask & m1)
SIU.PCR[pcr_index].R = mode;
m1 >>= 1;
++pcr_index;
}
}
#endif /* HAL_USE_PAL */
/** @} */
+423
View File
@@ -0,0 +1,423 @@
/*
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
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 SPC5xx/SIUL_v1/pal_lld.h
* @brief SPC5xx SIUL low level driver header.
*
* @addtogroup PAL
* @{
*/
#ifndef _PAL_LLD_H_
#define _PAL_LLD_H_
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Unsupported modes and specific modes */
/*===========================================================================*/
#undef PAL_MODE_RESET
#undef PAL_MODE_UNCONNECTED
#undef PAL_MODE_INPUT
#undef PAL_MODE_INPUT_PULLUP
#undef PAL_MODE_INPUT_PULLDOWN
#undef PAL_MODE_INPUT_ANALOG
#undef PAL_MODE_OUTPUT_PUSHPULL
#undef PAL_MODE_OUTPUT_OPENDRAIN
/**
* @name SIUL-specific PAL modes
* @{
*/
#define PAL_SPC5_SMC (1U << 14)
#define PAL_SPC5_APC (1U << 13)
#define PAL_SPC5_PA_MASK (3U << 10)
#define PAL_SPC5_PA(n) ((n) << 10)
#define PAL_SPC5_OBE (1U << 9)
#define PAL_SPC5_IBE (1U << 8)
#define PAL_SPC5_ODE (1U << 5)
#define PAL_SPC5_SRC (1U << 2)
#define PAL_SPC5_WPE (1U << 1)
#define PAL_SPC5_WPS (1U << 0)
/** @} */
/**
* @name Pads mode constants
* @{
*/
/**
* @brief After reset state.
*/
#define PAL_MODE_RESET 0
/**
* @brief Safe state for <b>unconnected</b> pads.
*/
#define PAL_MODE_UNCONNECTED (PAL_SPC5_WPE | PAL_SPC5_WPS)
/**
* @brief Regular input high-Z pad.
*/
#define PAL_MODE_INPUT (PAL_SPC5_IBE)
/**
* @brief Input pad with weak pull up resistor.
*/
#define PAL_MODE_INPUT_PULLUP (PAL_SPC5_IBE |PAL_SPC5_WPE | \
PAL_SPC5_WPS)
/**
* @brief Input pad with weak pull down resistor.
*/
#define PAL_MODE_INPUT_PULLDOWN (PAL_SPC5_IBE |PAL_SPC5_WPE)
/**
* @brief Analog input mode.
*/
#define PAL_MODE_INPUT_ANALOG PAL_SPC5_APC
/**
* @brief Push-pull output pad.
*/
#define PAL_MODE_OUTPUT_PUSHPULL (PAL_SPC5_IBE | PAL_SPC5_OBE)
/**
* @brief Open-drain output pad.
*/
#define PAL_MODE_OUTPUT_OPENDRAIN (PAL_SPC5_IBE | PAL_SPC5_OBE | \
PAL_SPC5_ODE)
/**
* @brief Alternate "n" output pad.
*/
#define PAL_MODE_OUTPUT_ALTERNATE(n) (PAL_SPC5_IBE | PAL_SPC5_PA(n))
/** @} */
/*===========================================================================*/
/* I/O Ports Types and constants. */
/*===========================================================================*/
/**
* @brief Width, in bits, of an I/O port.
*/
#define PAL_IOPORTS_WIDTH 16
/**
* @brief Whole port mask.
* @brief This macro specifies all the valid bits into a port.
*/
#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFF)
/**
* @brief Digital I/O port sized unsigned type.
*/
typedef uint16_t ioportmask_t;
/**
* @brief Digital I/O modes.
*/
typedef uint16_t iomode_t;
/**
* @brief Port Identifier.
* @details This type can be a scalar or some kind of pointer, do not make
* any assumption about it, use the provided macros when populating
* variables of this type.
*/
typedef uint32_t ioportid_t;
/**
* @brief SIUL register initializer type.
*/
typedef struct {
uint8_t pcr_index;
uint8_t gpdo_value;
iomode_t pcr_value;
} spc_siu_init_t;
/**
* @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 {
iomode_t default_mode;
const spc_siu_init_t *inits;
const uint8_t *padsels;
} PALConfig;
/*===========================================================================*/
/* I/O Ports Identifiers. */
/*===========================================================================*/
/**
* @brief I/O port A identifier.
*/
#define PORT_A 0
/**
* @brief I/O port B identifier.
*/
#define PORT_B 1
/**
* @brief I/O port C identifier.
*/
#define PORT_C 2
/**
* @brief I/O port D identifier.
*/
#define PORT_D 3
/**
* @brief I/O port E identifier.
*/
#define PORT_E 4
/**
* @brief I/O port F identifier.
*/
#define PORT_F 5
/**
* @brief I/O port G identifier.
*/
#define PORT_G 6
/**
* @brief I/O port H identifier.
*/
#define PORT_H 7
/*===========================================================================*/
/* Implementation, some of the following macros could be implemented as */
/* functions, if so please put them in pal_lld.c. */
/*===========================================================================*/
/**
* @brief Port bit helper macro.
* @note Overrides the one in @p pal.h.
*
* @param[in] n bit position within the port
*
* @return The bit mask.
*/
#define PAL_PORT_BIT(n) ((ioportmask_t)(0x8000U >> (n)))
/**
* @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) (((volatile uint16_t *)SIU.PGPDI)[port])
/**
* @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) (((volatile uint16_t *)SIU.PGPDO)[port])
/**
* @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) \
(((volatile uint16_t *)SIU.PGPDO)[port] = (bits))
/**
* @brief Reads a group of bits.
*
* @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) \
_pal_lld_readgroup(port, mask, offset)
/**
* @brief Writes a group of bits.
*
* @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) \
_pal_lld_writegroup(port, mask, offset, 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) \
(SIU.GPDI[((port) * 16) + (pad)].R)
/**
* @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) \
(SIU.GPDO[((port) * 16) + (pad)].R = (bit))
/**
* @brief Sets a pad logical state to @p PAL_HIGH.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_setpad(port, pad) \
(SIU.GPDO[((port) * 16) + (pad)].R = 1)
/**
* @brief Clears a pad logical state to @p PAL_LOW.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_clearpad(port, pad) \
(SIU.GPDO[((port) * 16) + (pad)].R = 0)
/**
* @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) \
(SIU.GPDO[((port) * 16) + (pad)].R = ~SIU.GPDO[((port) * 16) + (pad)].R)
/**
* @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)
extern const PALConfig pal_default_config;
#ifdef __cplusplus
extern "C" {
#endif
void _pal_lld_init(const PALConfig *config);
ioportmask_t _pal_lld_readgroup(ioportid_t port,
ioportmask_t mask,
uint_fast8_t offset);
void _pal_lld_writegroup(ioportid_t port,
ioportmask_t mask,
uint_fast8_t offset,
ioportmask_t bits);
void _pal_lld_setgroupmode(ioportid_t port,
ioportmask_t mask,
iomode_t mode);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_PAL */
#endif /* _PAL_LLD_H_ */
/** @} */
+145
View File
@@ -0,0 +1,145 @@
/*
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
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 SPC5xx/SIU_v1/pal_lld.c
* @brief SPC5xx SIU low level driver code.
*
* @addtogroup PAL
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
#if defined(SPC5_SIU_SYSTEM_PINS)
static const unsigned system_pins[] = {SPC5_SIU_SYSTEM_PINS};
#endif
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief SPC5xx I/O ports configuration.
*
* @param[in] config the STM32 ports configuration
*
* @notapi
*/
void _pal_lld_init(const PALConfig *config) {
unsigned i;
/* Initialize PCR registers for defined pads.*/
i = 0;
while (config->inits[i].pcr_value != 0) {
SIU.GPDO[config->inits[i].pcr_index].R = config->inits[i].gpdo_value;
SIU.PCR[config->inits[i].pcr_index].R = config->inits[i].pcr_value;
i++;
}
}
/**
* @brief Reads a group of bits.
*
* @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
*/
ioportmask_t _pal_lld_readgroup(ioportid_t port,
ioportmask_t mask,
uint_fast8_t offset) {
(void)port;
(void)mask;
(void)offset;
return 0;
}
/**
* @brief Writes a group of bits.
*
* @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
*/
void _pal_lld_writegroup(ioportid_t port,
ioportmask_t mask,
uint_fast8_t offset,
ioportmask_t bits) {
(void)port;
(void)mask;
(void)offset;
(void)bits;
}
/**
* @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) {
unsigned pcr_index = (unsigned)(port * PAL_IOPORTS_WIDTH);
ioportmask_t m1 = 0x8000;
while (m1) {
if (mask & m1)
SIU.PCR[pcr_index].R = mode;
m1 >>= 1;
++pcr_index;
}
}
#endif /* HAL_USE_PAL */
/** @} */
+419
View File
@@ -0,0 +1,419 @@
/*
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
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 SPC5xx/SIU_v1/pal_lld.h
* @brief SPC5xx SIU low level driver header.
*
* @addtogroup PAL
* @{
*/
#ifndef _PAL_LLD_H_
#define _PAL_LLD_H_
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Unsupported modes and specific modes */
/*===========================================================================*/
#undef PAL_MODE_RESET
#undef PAL_MODE_UNCONNECTED
#undef PAL_MODE_INPUT
#undef PAL_MODE_INPUT_PULLUP
#undef PAL_MODE_INPUT_PULLDOWN
#undef PAL_MODE_INPUT_ANALOG
#undef PAL_MODE_OUTPUT_PUSHPULL
#undef PAL_MODE_OUTPUT_OPENDRAIN
/**
* @name SIU-specific PAL modes
* @{
*/
#define PAL_SPC5_PA_MASK (15U << 10)
#define PAL_SPC5_PA(n) ((n) << 10)
#define PAL_SPC5_OBE (1U << 9)
#define PAL_SPC5_IBE (1U << 8)
#define PAL_SPC5_DSC_10PF (0U << 6)
#define PAL_SPC5_DSC_20PF (1U << 6)
#define PAL_SPC5_DSC_30PF (2U << 6)
#define PAL_SPC5_DSC_50PF (3U << 6)
#define PAL_SPC5_ODE (1U << 5)
#define PAL_SPC5_HYS (1U << 4)
#define PAL_SPC5_WPE (1U << 1)
#define PAL_SPC5_WPS (1U << 0)
/** @} */
/**
* @name Pads mode constants
* @{
*/
/**
* @brief After reset state.
*/
#define PAL_MODE_RESET 0
/**
* @brief Safe state for <b>unconnected</b> pads.
*/
#define PAL_MODE_UNCONNECTED (PAL_SPC5_WPE | PAL_SPC5_WPS)
/**
* @brief Regular input high-Z pad.
*/
#define PAL_MODE_INPUT (PAL_SPC5_IBE)
/**
* @brief Input pad with weak pull up resistor.
*/
#define PAL_MODE_INPUT_PULLUP (PAL_SPC5_IBE |PAL_SPC5_WPE | \
PAL_SPC5_WPS)
/**
* @brief Input pad with weak pull down resistor.
*/
#define PAL_MODE_INPUT_PULLDOWN (PAL_SPC5_IBE |PAL_SPC5_WPE)
/**
* @brief Push-pull output pad.
*/
#define PAL_MODE_OUTPUT_PUSHPULL (PAL_SPC5_IBE | PAL_SPC5_OBE)
/**
* @brief Open-drain output pad.
*/
#define PAL_MODE_OUTPUT_OPENDRAIN (PAL_SPC5_IBE | PAL_SPC5_OBE | \
PAL_SPC5_ODE)
/**
* @brief Alternate "n" output pad.
*/
#define PAL_MODE_OUTPUT_ALTERNATE(n) (PAL_SPC5_IBE | PAL_SPC5_PA(n))
/** @} */
/*===========================================================================*/
/* I/O Ports Types and constants. */
/*===========================================================================*/
/**
* @brief Width, in bits, of an I/O port.
*/
#define PAL_IOPORTS_WIDTH 16
/**
* @brief Whole port mask.
* @brief This macro specifies all the valid bits into a port.
*/
#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFF)
/**
* @brief Digital I/O port sized unsigned type.
*/
typedef uint16_t ioportmask_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 uint32_t ioportid_t;
/**
* @brief Digital I/O modes.
*/
typedef uint16_t iomode_t;
/**
* @brief SIU/SIUL register initializer type.
*/
typedef struct {
uint8_t pcr_index;
uint8_t gpdo_value;
iomode_t pcr_value;
} spc_siu_init_t;
/**
* @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 {
const spc_siu_init_t *inits;
} PALConfig;
/*===========================================================================*/
/* I/O Ports Identifiers. */
/*===========================================================================*/
/**
* @name Port identifiers
* @{
*/
#define PORT0 0
#define PORT1 1
#define PORT2 2
#define PORT3 3
#define PORT4 4
#define PORT5 5
#define PORT6 6
#define PORT7 7
#define PORT8 8
#define PORT9 9
#define PORT10 10
#define PORT11 11
#define PORT12 12
#define PORT13 13
#define PORT14 14
#define PORT15 15
#define PORT16 16
#define PORT17 17
#define PORT18 18
#define PORT19 19
#define PORT20 20
#define PORT21 21
#define PORT22 22
#define PORT23 23
#define PORT24 24
#define PORT25 25
#define PORT26 26
#define PORT27 27
#define PORT28 28
#define PORT29 29
#define PORT30 30
#define PORT31 31
/** @} */
/*===========================================================================*/
/* Implementation, some of the following macros could be implemented as */
/* functions, if so please put them in pal_lld.c. */
/*===========================================================================*/
/**
* @brief Port bit helper macro.
* @note Overrides the one in @p pal.h.
*
* @param[in] n bit position within the port
*
* @return The bit mask.
*/
#define PAL_PORT_BIT(n) ((ioportmask_t)(0x8000U >> (n)))
/**
* @brief Low level PAL subsystem initialization.
*
* @param[in] config architecture-dependent ports configuration
*
* @notapi
*/
#define pal_lld_init(config) _pal_lld_init(config)
#if SPC5_SIU_SUPPORTS_PORTS || defined(__DOXYGEN__)
/**
* @brief Reads the physical I/O port states.
*
* @param[in] port port identifier
* @return The port bits.
*
* @notapi
*/
#define pal_lld_readport(port) (((volatile uint16_t *)SIU.PGPDI)[port])
/**
* @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) (((volatile uint16_t *)SIU.PGPDO)[port])
/**
* @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) \
(((volatile uint16_t *)SIU.PGPDO)[port] = (bits))
/**
* @brief Reads a group of bits.
*
* @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) \
_pal_lld_readgroup(port, mask, offset)
/**
* @brief Writes a group of bits.
*
* @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) \
_pal_lld_writegroup(port, mask, offset, bits)
#endif /* SPC5_SIU_SUPPORTS_PORTS */
/**
* @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) \
(SIU.GPDI[((port) * 16) + (pad)].R)
/**
* @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) \
(SIU.GPDO[((port) * 16) + (pad)].R = (bit))
/**
* @brief Sets a pad logical state to @p PAL_HIGH.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_setpad(port, pad) \
(SIU.GPDO[((port) * 16) + (pad)].R = 1)
/**
* @brief Clears a pad logical state to @p PAL_LOW.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_clearpad(port, pad) \
(SIU.GPDO[((port) * 16) + (pad)].R = 0)
/**
* @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) \
(SIU.GPDO[((port) * 16) + (pad)].R = ~SIU.GPDO[((port) * 16) + (pad)].R)
/**
* @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)
extern const PALConfig pal_default_config;
#ifdef __cplusplus
extern "C" {
#endif
void _pal_lld_init(const PALConfig *config);
ioportmask_t _pal_lld_readgroup(ioportid_t port,
ioportmask_t mask,
uint_fast8_t offset);
void _pal_lld_writegroup(ioportid_t port,
ioportmask_t mask,
uint_fast8_t offset,
ioportmask_t bits);
void _pal_lld_setgroupmode(ioportid_t port,
ioportmask_t mask,
iomode_t mode);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_PAL */
#endif /* _PAL_LLD_H_ */
/** @} */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,612 @@
/*
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
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 eTimer_v1/icu_lld.h
* @brief SPC5xx low level ICU driver header.
*
* @addtogroup ICU
* @{
*/
#ifndef _ICU_LLD_H_
#define _ICU_LLD_H_
#if HAL_USE_ICU || defined(__DOXYGEN__)
#include "spc5_etimer.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name Mode options
* @{
*/
/**
* @brief Skip first capture cycle.
* @details If set to @p TRUE the first capture cycle is skipped.
* @note The default is @p FALSE.
*/
#if !defined(ICU_JUMP_FIRST_CAPTURE) || defined(__DOXYGEN__)
#define ICU_SKIP_FIRST_CAPTURE FALSE
#endif
#define SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_1 0x18
#define SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_2 0x19
#define SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_4 0x1A
#define SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_8 0x1B
#define SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_16 0x1C
#define SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_32 0x1D
#define SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_64 0x1E
#define SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_128 0x1F
#define SPC5_ETIMER_COUNTER_0_INPUT_PIN 0U
#define SPC5_ETIMER_COUNTER_1_INPUT_PIN 1U
#define SPC5_ETIMER_COUNTER_2_INPUT_PIN 2U
#define SPC5_ETIMER_COUNTER_3_INPUT_PIN 3U
#define SPC5_ETIMER_COUNTER_4_INPUT_PIN 4U
#define SPC5_ETIMER_COUNTER_5_INPUT_PIN 5U
#define SPC5_ETIMER_CNTMODE_NO_OPERATION 0U
#define SPC5_ETIMER_CNTMODE_RE 1U
#define SPC5_ETIMER_CNTMODE_RFE 2U
#define SPC5_ETIMER_CNTMODE_RFE_SIHA 3U
#define SPC5_ETIMER_CNTMODE_QUADRATURE 4U
#define SPC5_ETIMER_CNTMODE_RE_SSSD 5U
#define SPC5_ETIMER_CNTMODE_ESS_TRIGGER 6U
#define SPC5_ETIMER_CNTMODE_CASCADE 7U
#define SPC5_ETIMER_CPT1MODE_DISABLED 0U
#define SPC5_ETIMER_CPT1MODE_FALLING_EDGE 1U
#define SPC5_ETIMER_CPT1MODE_RISING_EDGE 2U
#define SPC5_ETIMER_CPT1MODE_ANY_EDGE 3U
#define SPC5_ETIMER_CPT2MODE_DISABLED 0U
#define SPC5_ETIMER_CPT2MODE_FALLING_EDGE 1U
#define SPC5_ETIMER_CPT2MODE_RISING_EDGE 2U
#define SPC5_ETIMER_CPT2MODE_ANY_EDGE 3U
#define SPC5_ETIMER_ROC_DO_NOT_RELOAD 0U
#define SPC5_ETIMER_ROC_REL_ON_CAP1 1U
#define SPC5_ETIMER_ROC_REL_ON_CAP2 2U
#define SPC5_ETIMER_ROC_REL_ON_CAP1_CAP2 3U
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief ICUD1 driver enable switch.
* @details If set to @p TRUE the support for ICUD1 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD0) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD0 FALSE
#endif
/**
* @brief ICUD2 driver enable switch.
* @details If set to @p TRUE the support for ICUD2 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD1) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD1 FALSE
#endif
/**
* @brief ICUD3 driver enable switch.
* @details If set to @p TRUE the support for ICUD3 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD2) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD2 FALSE
#endif
/**
* @brief ICUD4 driver enable switch.
* @details If set to @p TRUE the support for ICUD4 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD3) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD3 FALSE
#endif
/**
* @brief ICUD5 driver enable switch.
* @details If set to @p TRUE the support for ICUD5 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD4) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD4 FALSE
#endif
/**
* @brief ICUD6 driver enable switch.
* @details If set to @p TRUE the support for ICUD6 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD5) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD5 FALSE
#endif
/**
* @brief eTimer0 interrupt priority level setting.
*/
#if !defined(SPC5_ICU_ETIMER0_PRIORITY) || defined(__DOXYGEN__)
#define SPC5_ICU_ETIMER0_PRIORITY 7
#endif
/**
* @brief eTIMER0 peripheral configuration when started.
* @note The default configuration is 1 (always run) in run mode and
* 2 (only halt) in low power mode. The defaults of the run modes
* are defined in @p hal_lld.h.
*/
#if !defined(SPC5_ICU_ETIMER0_START_PCTL) || defined(__DOXYGEN__)
#define SPC5_ICU_ETIMER0_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
SPC5_ME_PCTL_LP(2))
#endif
/**
* @brief eTIMER0 peripheral configuration when stopped.
* @note The default configuration is 0 (never run) in run mode and
* 0 (never run) in low power mode. The defaults of the run modes
* are defined in @p hal_lld.h.
*/
#if !defined(SPC5_ICU_ETIMER0_STOP_PCTL) || defined(__DOXYGEN__)
#define SPC5_ICU_ETIMER0_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
SPC5_ME_PCTL_LP(0))
#endif
/**
* @brief ICUD6 driver enable switch.
* @details If set to @p TRUE the support for ICUD6 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD6) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD6 FALSE
#endif
/**
* @brief ICUD7 driver enable switch.
* @details If set to @p TRUE the support for ICUD7 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD7) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD7 FALSE
#endif
/**
* @brief ICUD8 driver enable switch.
* @details If set to @p TRUE the support for ICUD8 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD8) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD8 FALSE
#endif
/**
* @brief ICUD9 driver enable switch.
* @details If set to @p TRUE the support for ICUD9 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD9) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD9 FALSE
#endif
/**
* @brief ICUD10 driver enable switch.
* @details If set to @p TRUE the support for ICUD10 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD10) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD10 FALSE
#endif
/**
* @brief ICUD11 driver enable switch.
* @details If set to @p TRUE the support for ICUD11 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD11) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD11 FALSE
#endif
/**
* @brief eTimer1 interrupt priority level setting.
*/
#if !defined(SPC5_ICU_ETIMER1_PRIORITY) || defined(__DOXYGEN__)
#define SPC5_ICU_ETIMER1_PRIORITY 7
#endif
/**
* @brief eTIMER1 peripheral configuration when started.
* @note The default configuration is 1 (always run) in run mode and
* 2 (only halt) in low power mode. The defaults of the run modes
* are defined in @p hal_lld.h.
*/
#if !defined(SPC5_ICU_ETIMER1_START_PCTL) || defined(__DOXYGEN__)
#define SPC5_ICU_ETIMER1_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
SPC5_ME_PCTL_LP(2))
#endif
/**
* @brief eTIMER1 peripheral configuration when stopped.
* @note The default configuration is 0 (never run) in run mode and
* 0 (never run) in low power mode. The defaults of the run modes
* are defined in @p hal_lld.h.
*/
#if !defined(SPC5_ICU_ETIMER1_STOP_PCTL) || defined(__DOXYGEN__)
#define SPC5_ICU_ETIMER1_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
SPC5_ME_PCTL_LP(0))
#endif
/**
* @brief ICUD13 driver enable switch.
* @details If set to @p TRUE the support for ICUD13 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD12) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD12 FALSE
#endif
/**
* @brief ICUD14 driver enable switch.
* @details If set to @p TRUE the support for ICUD14 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD13) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD13 FALSE
#endif
/**
* @brief ICUD15 driver enable switch.
* @details If set to @p TRUE the support for ICUD15 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD14) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD14 FALSE
#endif
/**
* @brief ICUD16 driver enable switch.
* @details If set to @p TRUE the support for ICUD16 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD15) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD15 FALSE
#endif
/**
* @brief ICUD17 driver enable switch.
* @details If set to @p TRUE the support for ICUD17 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD16) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD16 FALSE
#endif
/**
* @brief ICUD18 driver enable switch.
* @details If set to @p TRUE the support for ICUD18 is included.
* @note The default is @p FALSE.
*/
#if !defined(SPC5_ICU_USE_SMOD17) || defined(__DOXYGEN__)
#define SPC5_ICU_USE_SMOD17 FALSE
#endif
/**
* @brief eTimer2 interrupt priority level setting.
*/
#if !defined(SPC5_ICU_ETIMER2_PRIORITY) || defined(__DOXYGEN__)
#define SPC5_ICU_ETIMER2_PRIORITY 7
#endif
/**
* @brief eTIMER2 peripheral configuration when started.
* @note The default configuration is 1 (always run) in run mode and
* 2 (only halt) in low power mode. The defaults of the run modes
* are defined in @p hal_lld.h.
*/
#if !defined(SPC5_ICU_ETIMER2_START_PCTL) || defined(__DOXYGEN__)
#define SPC5_ICU_ETIMER2_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
SPC5_ME_PCTL_LP(2))
#endif
/**
* @brief eTIMER2 peripheral configuration when stopped.
* @note The default configuration is 0 (never run) in run mode and
* 0 (never run) in low power mode. The defaults of the run modes
* are defined in @p hal_lld.h.
*/
#if !defined(SPC5_ICU_ETIMER2_STOP_PCTL) || defined(__DOXYGEN__)
#define SPC5_ICU_ETIMER2_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
SPC5_ME_PCTL_LP(0))
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#define SPC5_ICU_USE_ETIMER0 (SPC5_ICU_USE_SMOD0 || \
SPC5_ICU_USE_SMOD1 || \
SPC5_ICU_USE_SMOD2 || \
SPC5_ICU_USE_SMOD3 || \
SPC5_ICU_USE_SMOD4 || \
SPC5_ICU_USE_SMOD5)
#define SPC5_ICU_USE_ETIMER1 (SPC5_ICU_USE_SMOD6 || \
SPC5_ICU_USE_SMOD7 || \
SPC5_ICU_USE_SMOD8 || \
SPC5_ICU_USE_SMOD9 || \
SPC5_ICU_USE_SMOD10 || \
SPC5_ICU_USE_SMOD11)
#define SPC5_ICU_USE_ETIMER2 (SPC5_ICU_USE_SMOD12 || \
SPC5_ICU_USE_SMOD13 || \
SPC5_ICU_USE_SMOD14 || \
SPC5_ICU_USE_SMOD15 || \
SPC5_ICU_USE_SMOD16 || \
SPC5_ICU_USE_SMOD17)
#if !SPC5_HAS_ETIMER0 && SPC5_ICU_USE_ETIMER0
#error "ETIMER0 not present in the selected device"
#endif
#if !SPC5_HAS_ETIMER1 && SPC5_ICU_USE_ETIMER1
#error "ETIMER1 not present in the selected device"
#endif
#if !SPC5_HAS_ETIMER2 && SPC5_ICU_USE_ETIMER2
#error "ETIMER2 not present in the selected device"
#endif
#if !SPC5_ICU_USE_ETIMER0 && !SPC5_ICU_USE_ETIMER1 && !SPC5_ICU_USE_ETIMER2
#error "ICU driver activated but no SMOD peripheral assigned"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief ICU driver mode.
*/
typedef enum {
ICU_INPUT_ACTIVE_HIGH = 0, /**< Trigger on rising edge. */
ICU_INPUT_ACTIVE_LOW = 1, /**< Trigger on falling edge. */
} icumode_t;
/**
* @brief ICU frequency type.
*/
typedef uint32_t icufreq_t;
/**
* @brief ICU channel.
*/
typedef enum {
ICU_CHANNEL_1 = 0, /**< Use SMODxCH1. */
ICU_CHANNEL_2 = 1, /**< Use SMODxCH2. */
ICU_CHANNEL_3 = 2, /**< Use SMODxCH3. */
ICU_CHANNEL_4 = 3, /**< Use SMODxCH4. */
ICU_CHANNEL_5 = 4, /**< Use SMODxCH5. */
ICU_CHANNEL_6 = 5, /**< Use SMODxCH6. */
} icuchannel_t;
/**
* @brief ICU counter type.
*/
typedef uint16_t icucnt_t;
/**
* @brief Driver configuration structure.
* @note It could be empty on some architectures.
*/
typedef struct {
/**
* @brief Driver mode.
*/
icumode_t mode;
/**
* @brief Timer clock in Hz.
* @note The low level can use assertions in order to catch invalid
* frequency specifications.
*/
icufreq_t frequency;
/**
* @brief Callback for pulse width measurement.
*/
icucallback_t width_cb;
/**
* @brief Callback for cycle period measurement.
*/
icucallback_t period_cb;
/**
* @brief Callback for timer overflow.
*/
icucallback_t overflow_cb;
/* End of the mandatory fields.*/
} ICUConfig;
/**
* @brief Structure representing an ICU driver.
*/
struct ICUDriver {
/**
* @brief Driver state.
*/
icustate_t state;
/**
* @brief Current configuration data.
*/
const ICUConfig *config;
#if defined(ICU_DRIVER_EXT_FIELDS)
ICU_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Clock value for this unit.
*/
uint32_t clock;
/**
* @brief eTimer submodule number.
*/
uint32_t smod_number;
/**
* @brief Pointer to the eTimerx registers block.
*/
volatile struct spc5_etimer *etimerp;
/**
* @brief CCR register used for width capture.
*/
volatile vuint16_t *wccrp;
/**
* @brief CCR register used for period capture.
*/
volatile vuint16_t *pccrp;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Returns the width of the latest pulse.
* @details The pulse width is defined as number of ticks between the start
* edge and the stop edge.
*
* @param[in] icup pointer to the @p ICUDriver object
* @return The number of ticks.
*
* @notapi
*/
#define icu_lld_get_width(icup) (*((icup)->wccrp) + 1)
/**
* @brief Returns the width of the latest cycle.
* @details The cycle width is defined as number of ticks between a start
* edge and the next start edge.
*
* @param[in] icup pointer to the @p ICUDriver object
* @return The number of ticks.
*
* @notapi
*/
#define icu_lld_get_period(icup) (*((icup)->pccrp) + 1)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if SPC5_ICU_USE_SMOD0 && !defined(__DOXYGEN__)
extern ICUDriver ICUD1;
#endif
#if SPC5_ICU_USE_SMOD1 && !defined(__DOXYGEN__)
extern ICUDriver ICUD2;
#endif
#if SPC5_ICU_USE_SMOD2 && !defined(__DOXYGEN__)
extern ICUDriver ICUD3;
#endif
#if SPC5_ICU_USE_SMOD3 && !defined(__DOXYGEN__)
extern ICUDriver ICUD4;
#endif
#if SPC5_ICU_USE_SMOD4 && !defined(__DOXYGEN__)
extern ICUDriver ICUD5;
#endif
#if SPC5_ICU_USE_SMOD5 && !defined(__DOXYGEN__)
extern ICUDriver ICUD6;
#endif
#if SPC5_ICU_USE_SMOD6 && !defined(__DOXYGEN__)
extern ICUDriver ICUD7;
#endif
#if SPC5_ICU_USE_SMOD7 && !defined(__DOXYGEN__)
extern ICUDriver ICUD8;
#endif
#if SPC5_ICU_USE_SMOD8 && !defined(__DOXYGEN__)
extern ICUDriver ICUD9;
#endif
#if SPC5_ICU_USE_SMOD9 && !defined(__DOXYGEN__)
extern ICUDriver ICUD10;
#endif
#if SPC5_ICU_USE_SMOD10 && !defined(__DOXYGEN__)
extern ICUDriver ICUD11;
#endif
#if SPC5_ICU_USE_SMOD11 && !defined(__DOXYGEN__)
extern ICUDriver ICUD12;
#endif
#if SPC5_ICU_USE_SMOD12 && !defined(__DOXYGEN__)
extern ICUDriver ICUD13;
#endif
#if SPC5_ICU_USE_SMOD13 && !defined(__DOXYGEN__)
extern ICUDriver ICUD14;
#endif
#if SPC5_ICU_USE_SMOD14 && !defined(__DOXYGEN__)
extern ICUDriver ICUD15;
#endif
#if SPC5_ICU_USE_SMOD15 && !defined(__DOXYGEN__)
extern ICUDriver ICUD16;
#endif
#if SPC5_ICU_USE_SMOD16 && !defined(__DOXYGEN__)
extern ICUDriver ICUD17;
#endif
#if SPC5_ICU_USE_SMOD17 && !defined(__DOXYGEN__)
extern ICUDriver ICUD18;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void icu_lld_init(void);
void icu_lld_start(ICUDriver *icup);
void icu_lld_stop(ICUDriver *icup);
void icu_lld_enable(ICUDriver *icup);
void icu_lld_disable(ICUDriver *icup);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_ICU */
#endif /* _ICU_LLD_H_ */
/** @} */
@@ -0,0 +1,316 @@
/*
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
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 eTimer_v1/etimer.h
* @brief SPC5xx eTimer header file.
*
* @addtogroup ICU
* @{
*/
#ifndef _ETIMER_H_
#define _ETIMER_H_
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief SPC5 FlexPWM registers block.
* @note Redefined from the SPC5 headers because the non uniform
* declaration of the SubModules registers among the various
* sub-families.
*/
struct spc5_etimer_submodule {
union {
vuint16_t R;
struct {
vuint16_t COMP1 :16;
} B;
} COMP1; /* Compare Register 1 */
union {
vuint16_t R;
struct {
vuint16_t COMP2 :16;
} B;
} COMP2; /* Compare Register 2 */
union {
vuint16_t R;
struct {
vuint16_t CAPT1 :16;
} B;
} CAPT1; /* Capture Register 1 */
union {
vuint16_t R;
struct {
vuint16_t CAPT2 :16;
} B;
} CAPT2; /* Capture Register 2 */
union {
vuint16_t R;
struct {
vuint16_t LOAD :16;
} B;
} LOAD; /* Load Register */
union {
vuint16_t R;
struct {
vuint16_t HOLD :16;
} B;
} HOLD; /* Hold Register */
union {
vuint16_t R;
struct {
vuint16_t CNTR :16;
} B;
} CNTR; /* Counter Register */
union {
vuint16_t R;
struct {
vuint16_t CNTMODE :3;
vuint16_t PRISRC :5;
vuint16_t ONCE :1;
vuint16_t LENGTH :1;
vuint16_t DIR :1;
vuint16_t SECSRC :5;
} B;
} CTRL; /* Control Register */
union {
vuint16_t R;
struct {
vuint16_t OEN :1;
vuint16_t RDNT :1;
vuint16_t INPUT :1;
vuint16_t VAL :1;
vuint16_t FORCE :1;
vuint16_t COFRC :1;
vuint16_t COINIT :2;
vuint16_t SIPS :1;
vuint16_t PIPS :1;
vuint16_t OPS :1;
vuint16_t MSTR :1;
vuint16_t OUTMODE :4;
} B;
} CTRL2; /* Control Register 2 */
union {
vuint16_t R;
struct {
vuint16_t STPEN :1;
vuint16_t ROC :2;
vuint16_t FMODE :1;
vuint16_t FDIS :4;
vuint16_t C2FCNT :3;
vuint16_t C1FCNT :3;
vuint16_t DBGEN :2;
} B;
} CTRL3; /* Control Register 3 */
union {
vuint16_t R;
struct {
vuint16_t :6;
vuint16_t WDF :1;
vuint16_t RCF :1;
vuint16_t ICF2 :1;
vuint16_t ICF1 :1;
vuint16_t IEHF :1;
vuint16_t IELF :1;
vuint16_t TOF :1;
vuint16_t TCF2 :1;
vuint16_t TCF1 :1;
vuint16_t TCF :1;
} B;
} STS; /* Status Register */
union {
vuint16_t R;
struct {
vuint16_t ICF2DE :1;
vuint16_t ICF1DE :1;
vuint16_t CMPLD2DE :1;
vuint16_t CMPLD1DE :1;
vuint16_t :2;
vuint16_t WDFIE :1;
vuint16_t RCFIE :1;
vuint16_t ICF2IE :1;
vuint16_t ICF1IE :1;
vuint16_t IEHFIE :1;
vuint16_t IELFIE :1;
vuint16_t TOFIE :1;
vuint16_t TCF2IE :1;
vuint16_t TCF1IE :1;
vuint16_t TCFIE :1;
} B;
} INTDMA; /* Interrupt and DMA Register */
union {
vuint16_t R;
struct {
vuint16_t CMPLD1 :16;
} B;
} CMPLD1; /* Compare Load Register 1 */
union {
vuint16_t R;
struct {
vuint16_t CMPLD2 :16;
} B;
} CMPLD2; /* Compare Load Register 2 */
union {
vuint16_t R;
struct {
vuint16_t CLC2 :3;
vuint16_t CLC1 :3;
vuint16_t CMPMODE :2;
vuint16_t CPT2MODE :2;
vuint16_t CPT1MODE :2;
vuint16_t CFWM :2;
vuint16_t ONESHOT :1;
vuint16_t ARM :1;
} B;
} CCCTRL; /* Compare and Capture Control Register */
union {
vuint16_t R;
struct {
vuint16_t :5;
vuint16_t FILTCNT :3;
vuint16_t FILTPER :8;
} B;
} FILT; /* Input Filter Register */
};
/* end of ETIMER_CHANNEL_tag */
struct spc5_etimer {
struct spc5_etimer_submodule CHANNEL[8];
union {
vuint16_t R;
struct {
vuint16_t WDTOL :16;
} B;
} WDTOL; /* Watchdog Time-out Low Register */
union {
vuint16_t R;
struct {
vuint16_t WDTOH :16;
} B;
} WDTOH; /* Watchdog Time-out High Register */
union {
vuint16_t R;
struct {
vuint16_t :3;
vuint16_t FTEST :1;
vuint16_t FIE :4;
vuint16_t :4;
vuint16_t FLVL :4;
} B;
} FCTRL; /* Fault Control Register */
union {
vuint16_t R;
struct {
vuint16_t :4;
vuint16_t FFPIN :4;
vuint16_t :4;
vuint16_t FFLAG :4;
} B;
} FSTS; /* Fault Status Register */
union {
vuint16_t R;
struct {
vuint16_t :5;
vuint16_t FFILTCNT :3;
vuint16_t FFILTPER :8;
} B;
} FFILT; /* Fault Filter Register */
int16_t ETIMER_reserved1;
union {
vuint16_t R;
struct {
vuint16_t :8;
vuint16_t ENBL :8;
} B;
} ENBL; /* Channel Enable Register */
int16_t ETIMER_reserved2;
union {
vuint16_t R;
struct {
vuint16_t :11;
vuint16_t DREQ :5;
} B;
} DREQ[4]; /* DMA Request 0->3 Select Register */
};
/* end of ETIMER_tag */
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name FlexPWM units references
* @{
*/
#if SPC5_HAS_ETIMER0
#define SPC5_ETIMER_0 (*(volatile struct spc5_etimer *)0xFFE18000UL)
#endif
#if SPC5_HAS_ETIMER1
#define SPC5_ETIMER_1 (*(volatile struct spc5_etimer *)0xFFE1C000UL)
#endif
#if SPC5_HAS_ETIMER2
#define SPC5_ETIMER_2 (*(volatile struct spc5_etimer *)0xFFE20000UL)
#endif
/** @} */
#endif /* _FLEXPWM_H_ */
/** @} */