Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
QEI_hw/qeihw.cpp
- Committer:
- eembed
- Date:
- 2019-08-01
- Revision:
- 0:5459cdde6298
File content as of revision 0:5459cdde6298:
/* mbed Library - QEI driver for LP1768 hardware
* Copyright (c) 2010, hball
* released under MIT license http://mbed.org/licence/mit
*/
/***********************************************************************//**
* @file qeihw.cpp
* @brief Driver file for the QEI hardware. Requires connection to
* internal mbed circuit nodes. Adapted from the CMSIS
* driver, lpc17xx_qei.c, v 2.0
* @version 0.1
* @date 28 Dec 2010
* @author hb
**************************************************************************/
#include "mbed.h"
#include "qeihw.h"
QEIHW *QEIHW::instance;
/*********************************************************************//**
* @brief Create a QEI object and configure it.
* @param _dirinv Direction invert. When = 1, complements the QEICONF register DIR bit
* @param _sigmode Signal mode. When = 0, PhA and PhB are quadrature inputs. When = 1, PhA is direction and PhB is clock
* @param _capmode Capture mode. When = 0, count PhA edges only (2X mode). Whe = 1, count PhB edges also (4X mode).
* @param _invinx Invert index. When = 1, inverts the sense of the index signal
* @return None
**********************************************************************/
QEIHW::QEIHW(uint32_t _dirinv, uint32_t _sigmode, uint32_t _capmode, uint32_t _invinx)
{
/* Set up clock and power for QEI module */
LPC_SC->PCONP |= PCONP_QEI_ENABLE;
/* The clock for theQEI module is set to FCCLK */
LPC_SC->PCLKSEL1 = LPC_SC->PCLKSEL1 & ~(3UL<<0) | ((PCLKSEL_CCLK_DIV_1 & 3)<<0);
/* Assign the pins. They are hard-coded, not user-selected. The index
* pin is assigned, even though it is not easily accessed on the mbed.
* As it may be unconnected, it is given a pull-up resistor to minimize
* power drain.
*/
// MCI0 (PhA)
LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & PINSEL3_MCI0_MASK) | PINSEL3_MCI0 ;
LPC_PINCON->PINMODE3 = (LPC_PINCON->PINMODE3 & PINMODE3_MCI0_MASK) | PINMODE3_MCI0;
// MCI1 (PhB)
LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & PINSEL3_MCI1_MASK) | PINSEL3_MCI1 ;
LPC_PINCON->PINMODE3 = (LPC_PINCON->PINMODE3 & PINMODE3_MCI1_MASK) | PINMODE3_MCI1;
// MCI2 (Index)
LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & PINSEL3_MCI2_MASK) | PINSEL3_MCI2 ;
LPC_PINCON->PINMODE3 = (LPC_PINCON->PINMODE3 & PINMODE3_MCI2_MASK) | PINMODE3_MCI2;
// Initialize all remaining values in QEI peripheral
LPC_QEI->QEICON = QEI_CON_RESP | QEI_CON_RESV | QEI_CON_RESI;
LPC_QEI->QEIMAXPOS = 0xFFFFFFFF; // Default value
LPC_QEI->CMPOS0 = 0x00;
LPC_QEI->CMPOS1 = 0x00;
LPC_QEI->CMPOS2 = 0x00;
LPC_QEI->INXCMP = 0x00;
LPC_QEI->QEILOAD = 0x00;
LPC_QEI->VELCOMP = 0x00;
LPC_QEI->FILTER = 200000; // Default for mechanical switches.
// Set QEI configuration value corresponding to the call parameters
LPC_QEI->QEICONF = (
((_dirinv << 0) & 1) | \
((_sigmode << 1) & 2) | \
((_capmode << 2) & 4) | \
((_invinx <<3) & 8) );
// Mask all int sources
LPC_QEI->QEIIEC = QEI_IECLR_BITMASK; // Set the "clear" bits for all sources in the IE clear register
// Clear any pending ints
LPC_QEI->QEICLR = QEI_INTCLR_BITMASK; // Set the "clear" bits for for all sources in the Interrupt clear register
/* preemption = 1, sub-priority = 1 */
NVIC_SetPriority(QEI_IRQn, ((0x01<<3)|0x01));
//* Attach IRQ
instance = this;
NVIC_SetVector(QEI_IRQn, (uint32_t)&_Qeiisr);
/* Enable interrupt for QEI */
NVIC_EnableIRQ(QEI_IRQn);
}
/*********************************************************************//**
* @brief Resets value for each type of QEI value, such as velocity,
* counter, position, etc..
* @param[in] ulResetType QEI Reset Type, should be one of the following:
* - QEI_RESET_POS: Reset Position Counter
* - QEI_RESET_POSOnIDX: Reset Position Counter on Index signal
* - QEI_RESET_VEL: Reset Velocity
* - QEI_RESET_IDX: Reset Index Counter
* @return None
**********************************************************************/
void QEIHW::Reset(uint32_t ulResetType)
{
LPC_QEI->QEICON = ulResetType;
}
/*********************************************************************//**
* @brief De-initializes the QEI peripheral registers to their
* default reset values.
*
* @return None
**********************************************************************/
void QEIHW::DeInit()
{
/* Turn off clock and power for QEI module */
LPC_SC->PCONP &= PCONP_QEI_DISABLE;
/* Return pins to their default assignment (PINSEL = 0, PINMODE = PULLDOWN) */
// MCI0 (PhA) -> LED-2 (p1.20)
LPC_PINCON->PINSEL3 &= PINSEL3_MCI0_MASK;
LPC_PINCON->PINMODE3 = (LPC_PINCON->PINMODE3 & PINMODE3_MCI0_MASK) | PINMODE3_GPIO1p20;
// MCI1 (PhB) -> LED-4 (p1.23)
LPC_PINCON->PINSEL3 &= PINSEL3_MCI1_MASK;
LPC_PINCON->PINMODE3 = (LPC_PINCON->PINMODE3 & PINMODE3_MCI1_MASK) | PINMODE3_GPIO1p23;
// MCI2 (Index) -> p1.24
LPC_PINCON->PINSEL3 &= PINSEL3_MCI2_MASK;
LPC_PINCON->PINMODE3 = (LPC_PINCON->PINMODE3 & PINMODE3_MCI2_MASK) | PINMODE3_GPIO1p24;
}
/*********************************************************************//**
* @brief Report direction (QEISTAT bit DIR)
*
* @return State of the DIR bit (SET or RESET)
**********************************************************************/
FlagStatus QEIHW::Direction()
{
return ((LPC_QEI->QEISTAT & QEI_STATUS_DIR) ? SET : RESET);
}
/*********************************************************************//**
* @brief Get current position value in QEI peripheral
*
* @return Current position value of QEI peripheral
**********************************************************************/
uint32_t QEIHW::GetPosition()
{
return (LPC_QEI->QEIPOS);
}
/*********************************************************************//**
* @brief Set max position value for QEI peripheral
*
* @param[in] ulMaxPos Max position value to set
* @return None
**********************************************************************/
void QEIHW::SetMaxPosition(uint32_t ulMaxPos)
{
LPC_QEI->QEIMAXPOS = ulMaxPos;
}
/*********************************************************************//**
* @brief Set position compare value for QEI peripheral
* @param[in] QEIx QEI peripheral, should be LPC_QEI
* @param[in] bPosCompCh Compare Position channel, should be:
* - QEI_COMPPOS_CH_0: QEI compare position channel 0
* - QEI_COMPPOS_CH_1: QEI compare position channel 1
* - QEI_COMPPOS_CH_2: QEI compare position channel 2
* @param[in] ulPosComp Compare Position value to set
* @return None
**********************************************************************/
void QEIHW::SetPositionComp( uint8_t bPosCompCh, uint32_t ulPosComp)
{
uint32_t *tmp;
tmp = (uint32_t *) (&(LPC_QEI->CMPOS0) + bPosCompCh * 4);
*tmp = ulPosComp;
}
/*********************************************************************//**
* @brief Get current index counter of QEI peripheral
*
* @return Current value of QEI index counter
**********************************************************************/
uint32_t QEIHW::GetIndex()
{
return (LPC_QEI->INXCNT);
}
/*********************************************************************//**
* @brief Set value for index compare in QEI peripheral
* @param[in] ulIndexComp Compare Index Value to set
* @return None
**********************************************************************/
void QEIHW::SetIndexComp( uint32_t ulIndexComp)
{
LPC_QEI->INXCMP = ulIndexComp;
}
/*********************************************************************//**
* @brief Set Velocity timer reload value
*
* @param[in] ulReloadValue Velocity timer reload count
* @return None
**********************************************************************/
void QEIHW::SetVelocityTimerReload( uint32_t ulReloadValue)
{
LPC_QEI->QEILOAD = ulReloadValue;
}
/*********************************************************************//**
* @brief Set Velocity timer reload value in microseconds
*
* @param[in] ulReloadValue Velocity timer reload count
* @return None
**********************************************************************/
void QEIHW::SetVelocityTimerReload_us( uint32_t ulReloadValue)
{
int div;
//Work out CCLK
uint32_t m = (LPC_SC->PLL0CFG & 0xFFFF) + 1;
uint32_t n = (LPC_SC->PLL0CFG >> 16) + 1;
uint32_t cclkdiv = LPC_SC->CCLKCFG + 1;
uint32_t Fcco = (2 * m * XTAL_FREQ) / n;
uint32_t cclk = Fcco / cclkdiv;
// div = CLKPWR_GetPCLKSEL(ClkType);
div = LPC_SC->PCLKSEL1 & PCLKSEL1_PCLK_QEI_MASK;
switch (div)
{
case 0:
div = 4;
break;
case 1:
div = 1;
break;
case 2:
div = 2;
break;
case 3:
div = 8;
break;
}
cclk /=div;
cclk =((uint64_t)cclk / (1000000/ulReloadValue)) - 1;
LPC_QEI->QEILOAD = (uint32_t) cclk;
}
/*********************************************************************//**
* @brief Get current timer counter in QEI peripheral
*
* @return Current timer counter in QEI peripheral
**********************************************************************/
uint32_t QEIHW::GetTimer()
{
return (LPC_QEI->QEITIME);
}
/*********************************************************************//**
* @brief Get current velocity pulse counter in current time period
*
* @return Current velocity pulse counter value
**********************************************************************/
uint32_t QEIHW::GetVelocity()
{
return (LPC_QEI->QEIVEL);
}
/*********************************************************************//**
* @brief Get the most recently captured velocity of the QEI. When
* the Velocity timer in QEI is over-flow, the current velocity
* value will be loaded into Velocity Capture register.
*
* @return The most recently measured velocity value
**********************************************************************/
uint32_t QEIHW::GetVelocityCap()
{
return (LPC_QEI->QEICAP);
}
/*********************************************************************//**
* @brief Set Velocity Compare value for QEI peripheral
*
* @param[in] ulVelComp Compare Velocity value to set
* @return None
**********************************************************************/
void QEIHW::SetVelocityComp( uint32_t ulVelComp)
{
LPC_QEI->VELCOMP = ulVelComp;
}
/*********************************************************************//**
* @brief Set value of sampling count for the digital filter in
* QEI peripheral
*
* @param[in] ulSamplingPulse Value of sampling count to set
* @return None
**********************************************************************/
void QEIHW::SetDigiFilter( uint32_t ulSamplingPulse)
{
LPC_QEI->FILTER = ulSamplingPulse;
}
/*********************************************************************//**
* @brief Check whether if specified interrupt flag status in QEI
* peripheral is set or not
*
* @param[in] ulIntType Interrupt Flag Status type, should be:
- QEI_INTFLAG_INX_Int: index pulse was detected interrupt
- QEI_INTFLAG_TIM_Int: Velocity timer over flow interrupt
- QEI_INTFLAG_VELC_Int: Capture velocity is less than compare interrupt
- QEI_INTFLAG_DIR_Int: Change of direction interrupt
- QEI_INTFLAG_ERR_Int: An encoder phase error interrupt
- QEI_INTFLAG_ENCLK_Int: An encoder clock pulse was detected interrupt
- QEI_INTFLAG_POS0_Int: position 0 compare value is equal to the
current position interrupt
- QEI_INTFLAG_POS1_Int: position 1 compare value is equal to the
current position interrupt
- QEI_INTFLAG_POS2_Int: position 2 compare value is equal to the
current position interrupt
- QEI_INTFLAG_REV_Int: Index compare value is equal to the current
index count interrupt
- QEI_INTFLAG_POS0REV_Int: Combined position 0 and revolution count interrupt
- QEI_INTFLAG_POS1REV_Int: Combined position 1 and revolution count interrupt
- QEI_INTFLAG_POS2REV_Int: Combined position 2 and revolution count interrupt
* @return New State of specified interrupt flag status (SET or RESET)
**********************************************************************/
FlagStatus QEIHW::GetIntStatus( uint32_t ulIntType)
{
return((LPC_QEI->QEIINTSTAT & ulIntType) ? SET : RESET);
}
/*********************************************************************//**
* @brief Enable/Disable specified interrupt in QEI peripheral
*
* @param[in] ulIntType Interrupt Flag Status type, should be:
* - QEI_INTFLAG_INX_Int: index pulse was detected interrupt
* - QEI_INTFLAG_TIM_Int: Velocity timer over flow interrupt
* - QEI_INTFLAG_VELC_Int: Capture velocity is less than compare interrupt
* - QEI_INTFLAG_DIR_Int: Change of direction interrupt
* - QEI_INTFLAG_ERR_Int: An encoder phase error interrupt
* - QEI_INTFLAG_ENCLK_Int: An encoder clock pulse was detected interrupt
* - QEI_INTFLAG_POS0_Int: position 0 compare value is equal to the
* current position interrupt
* - QEI_INTFLAG_POS1_Int: position 1 compare value is equal to the
* current position interrupt
* - QEI_INTFLAG_POS2_Int: position 2 compare value is equal to the
* current position interrupt
* - QEI_INTFLAG_REV_Int: Index compare value is equal to the current
* index count interrupt
* - QEI_INTFLAG_POS0REV_Int: Combined position 0 and revolution count interrupt
* - QEI_INTFLAG_POS1REV_Int: Combined position 1 and revolution count interrupt
* - QEI_INTFLAG_POS2REV_Int: Combined position 2 and revolution count interrupt
* @param[in] NewState New function state, should be:
* - DISABLE
* - ENABLE
* @return None
**********************************************************************/
void QEIHW::IntCmd( uint32_t ulIntType, FunctionalState NewState)
{
if (NewState == ENABLE) {
LPC_QEI->QEIIES = ulIntType;
} else {
LPC_QEI->QEIIEC = ulIntType;
}
}
/*********************************************************************//**
* @brief Assert specified interrupt in QEI peripheral
*
* @param[in] ulIntType Interrupt Flag Status type, should be:
- QEI_INTFLAG_INX_Int: index pulse was detected interrupt
- QEI_INTFLAG_TIM_Int: Velocity timer over flow interrupt
- QEI_INTFLAG_VELC_Int: Capture velocity is less than compare interrupt
- QEI_INTFLAG_DIR_Int: Change of direction interrupt
- QEI_INTFLAG_ERR_Int: An encoder phase error interrupt
- QEI_INTFLAG_ENCLK_Int: An encoder clock pulse was detected interrupt
- QEI_INTFLAG_POS0_Int: position 0 compare value is equal to the
current position interrupt
- QEI_INTFLAG_POS1_Int: position 1 compare value is equal to the
current position interrupt
- QEI_INTFLAG_POS2_Int: position 2 compare value is equal to the
current position interrupt
- QEI_INTFLAG_REV_Int: Index compare value is equal to the current
index count interrupt
- QEI_INTFLAG_POS0REV_Int: Combined position 0 and revolution count interrupt
- QEI_INTFLAG_POS1REV_Int: Combined position 1 and revolution count interrupt
- QEI_INTFLAG_POS2REV_Int: Combined position 2 and revolution count interrupt
* @return None
**********************************************************************/
void QEIHW::IntSet( uint32_t ulIntType)
{
LPC_QEI->QEISET = ulIntType;
}
/*********************************************************************//**
* @brief De-assert specified interrupt (pending) in QEI peripheral
*
* @param[in] ulIntType Interrupt Flag Status type, should be:
- QEI_INTFLAG_INX_Int: index pulse was detected interrupt
- QEI_INTFLAG_TIM_Int: Velocity timer over flow interrupt
- QEI_INTFLAG_VELC_Int: Capture velocity is less than compare interrupt
- QEI_INTFLAG_DIR_Int: Change of direction interrupt
- QEI_INTFLAG_ERR_Int: An encoder phase error interrupt
- QEI_INTFLAG_ENCLK_Int: An encoder clock pulse was detected interrupt
- QEI_INTFLAG_POS0_Int: position 0 compare value is equal to the
current position interrupt
- QEI_INTFLAG_POS1_Int: position 1 compare value is equal to the
current position interrupt
- QEI_INTFLAG_POS2_Int: position 2 compare value is equal to the
current position interrupt
- QEI_INTFLAG_REV_Int: Index compare value is equal to the current
index count interrupt
- QEI_INTFLAG_POS0REV_Int: Combined position 0 and revolution count interrupt
- QEI_INTFLAG_POS1REV_Int: Combined position 1 and revolution count interrupt
- QEI_INTFLAG_POS2REV_Int: Combined position 2 and revolution count interrupt
* @return None
**********************************************************************/
void QEIHW::IntClear( uint32_t ulIntType)
{
LPC_QEI->QEICLR = ulIntType;
}
/*********************************************************************//**
* @brief Calculates the actual velocity in RPM passed via velocity
* capture value and Pulse Per Revolution (of the encoder) value
* parameter input.
*
* @param[in] ulVelCapValue Velocity capture input value that can
* be got from QEI_GetVelocityCap() function
* @param[in] ulPPR Pulse per round of encoder
* @return The actual value of velocity in RPM (Revolutions per minute)
**********************************************************************/
uint32_t QEIHW::CalculateRPM( uint32_t ulVelCapValue, uint32_t ulPPR)
{
uint64_t rpm, Load, edges;
int div;
// Get current Clock rate for timer input
//Work out CCLK
uint32_t m = (LPC_SC->PLL0CFG & 0xFFFF) + 1;
uint32_t n = (LPC_SC->PLL0CFG >> 16) + 1;
uint32_t cclkdiv = LPC_SC->CCLKCFG + 1;
uint32_t Fcco = (2 * m * XTAL_FREQ) / n;
uint32_t cclk = Fcco / cclkdiv;
// div = CLKPWR_GetPCLKSEL(ClkType);
div = LPC_SC->PCLKSEL1 & PCLKSEL1_PCLK_QEI_MASK;
switch (div)
{
case 0:
div = 4;
break;
case 1:
div = 1;
break;
case 2:
div = 2;
break;
case 3:
div = 8;
break;
}
cclk /= div;
// Get Timer load value (velocity capture period)
Load = (uint64_t)(LPC_QEI->QEILOAD + 1);
// Get Edge
edges = (uint64_t)((LPC_QEI->QEICONF & QEI_CONF_CAPMODE) ? 4 : 2);
// Calculate RPM
rpm = ((( uint64_t)cclk * ulVelCapValue * 60) / (Load * ulPPR * edges));
return (uint32_t)(rpm);
}
/*********************************************************************//**
* @brief Append interrupt handler for specific QEI interrupt source
*
* @param[in] ulISRType Interrupt Flag Status type, should be:
* - QEI_INTFLAG_INX_Int: index pulse was detected interrupt
* - QEI_INTFLAG_TIM_Int: Velocity timer over flow interrupt
* - QEI_INTFLAG_VELC_Int: Capture velocity is less than compare interrupt
* - QEI_INTFLAG_DIR_Int: Change of direction interrupt
* - QEI_INTFLAG_ERR_Int: An encoder phase error interrupt
* - QEI_INTFLAG_ENCLK_Int: An encoder clock pulse was detected interrupt
* - QEI_INTFLAG_POS0_Int: position 0 compare value is equal to the
* current position interrupt
* - QEI_INTFLAG_POS1_Int: position 1 compare value is equal to the
* current position interrupt
* - QEI_INTFLAG_POS2_Int: position 2 compare value is equal to the
* current position interrupt
* - QEI_INTFLAG_REV_Int: Index compare value is equal to the current
* index count interrupt
* - QEI_INTFLAG_POS0REV_Int: Combined position 0 and revolution count interrupt
* - QEI_INTFLAG_POS1REV_Int: Combined position 1 and revolution count interrupt
* - QEI_INTFLAG_POS2REV_Int: Combined position 2 and revolution count interrupt
*
* @return none
**********************************************************************/
void QEIHW::AppendISR(uint32_t ulISRType, void(*fptr)(void)) {
int i;
for(i = 0; i < 13; i++) {
if( ulISRType == (1UL << i) ) {
_qei_isr[i] = fptr;
break;
}
}
return;
}
/*********************************************************************//**
* @brief Unappend interrupt handler for specific QEI interrupt source
*
* @param[in] ulISRType Interrupt Flag Status type, should be:
* - QEI_INTFLAG_INX_Int: index pulse was detected interrupt
* - QEI_INTFLAG_TIM_Int: Velocity timer over flow interrupt
* - QEI_INTFLAG_VELC_Int: Capture velocity is less than compare interrupt
* - QEI_INTFLAG_DIR_Int: Change of direction interrupt
* - QEI_INTFLAG_ERR_Int: An encoder phase error interrupt
* - QEI_INTFLAG_ENCLK_Int: An encoder clock pulse was detected interrupt
* - QEI_INTFLAG_POS0_Int: position 0 compare value is equal to the
* current position interrupt
* - QEI_INTFLAG_POS1_Int: position 1 compare value is equal to the
* current position interrupt
* - QEI_INTFLAG_POS2_Int: position 2 compare value is equal to the
* current position interrupt
* - QEI_INTFLAG_REV_Int: Index compare value is equal to the current
* index count interrupt
* - QEI_INTFLAG_POS0REV_Int: Combined position 0 and revolution count interrupt
* - QEI_INTFLAG_POS1REV_Int: Combined position 1 and revolution count interrupt
* - QEI_INTFLAG_POS2REV_Int: Combined position 2 and revolution count interrupt
*
* @return none
**********************************************************************/
void QEIHW::UnAppendISR(uint32_t ulISRType) {
int i;
for(i = 0; i < 13; i++) {
if( ulISRType == (1UL << i) ) {
_qei_isr[i] = NULL;
break;
}
}
return;
}
void QEIHW::_Qeiisr(void)
{
instance->Qeiisr();
}
/*********************************************************************//**
* @brief QEI interrupt service dispatcher.
*
* @param[in] none
*
* @return none
**********************************************************************/
void QEIHW::Qeiisr(void)
{
int32_t i;
//User defined interrupt handlers. Check all possible sources, dispatch to corresponding non-null service routines.
for(i = 0; i < 13; i++) {
if(LPC_QEI->QEIINTSTAT & ((uint32_t)(1<<i)) ) {
if (_qei_isr[i] != NULL) {
_qei_isr[i]();
}
}
}
return;
}