-
Home
-
doc
-
support
-
driver
-
qei
qei_pic24e_dspic33e.c
View on Github
/**
* @file qei_pic24e_dspic33e.c
* @author Sebastien CAUX (sebcaux)
* @copyright Robotips 2016-2017
* @copyright UniSwarm 2018-2023
*
* @date April 18, 2016, 22:33 PM
*
* @brief Quadrature Encoder Interface support driver for dsPIC33EP,
* dsPIC33EV, PIC24EP, dsPIC33CH and dsPIC33CK
*
* Implementation based on Microchip document DS70601B :
* http://ww1.microchip.com/downloads/en/DeviceDoc/S15.pdf
*/
#include "qei.h"
#include <archi.h>
#if !defined(QEI_COUNT) || QEI_COUNT == 0
# warning "No qei on the current device or unknow device"
#endif
#ifdef UDEVKIT_HAVE_CONFIG
# include "udevkit_config.h"
#endif
enum
{
QEI_FLAG_UNUSED = 0x00
};
typedef struct
{
union
{
struct
{
unsigned used : 1;
unsigned enabled : 1;
unsigned : 6;
};
uint8_t val;
};
} qei_status;
struct qei_dev
{
qei_status flags;
};
static struct qei_dev _qeis[] = {
#if QEI_COUNT >= 1
{.flags = {{.val = QEI_FLAG_UNUSED}}},
#endif
};
/**
* @brief Gives a free QEI device number and open it
* @return QEI device number
*/
rt_dev_t qei_getFreeDevice(void)
{
#if QEI_COUNT >= 1
uint8_t qei_id;
for (qei_id = 0; qei_id < QEI_COUNT; qei_id++)
{
if (_qeis[qei_id].flags.used == 0)
{
break;
}
}
if (qei_id == QEI_COUNT)
{
return NULLDEV;
}
rt_dev_t device = MKDEV(DEV_CLASS_QEI, qei_id);
qei_open(device);
return device;
#else
return NULLDEV;
#endif
}
/**
* @brief Open a QEI
* @param device QEI device number
* @return 0 if ok, -1 in case of error
*/
int qei_open(rt_dev_t device)
{
#if QEI_COUNT >= 1
uint8_t qei = MINOR(device);
if (qei >= QEI_COUNT)
{
return -1;
}
if (_qeis[qei].flags.used == 1)
{
return -1;
}
_qeis[qei].flags.used = 1;
return 0;
#else
return -1;
#endif
}
/**
* @brief Close a QEI
* @param device QEI device number
* @return 0 if ok, -1 in case of error
*/
int qei_close(rt_dev_t device)
{
#if QEI_COUNT >= 1
uint8_t qei = MINOR(device);
if (qei >= QEI_COUNT)
{
return -1;
}
qei_disable(device);
_qeis[qei].flags.used = 0;
return 0;
#else
return -1;
#endif
}
/**
* @brief QEI sdk state
* @param device qei device number
* @return true if qei was openned by qei_open function
*/
bool qei_isOpened(rt_dev_t device)
{
uint8_t qei = MINOR(device);
if (qei >= QEI_COUNT)
{
return false;
}
return (_qeis[qei].flags.used == 1);
}
/**
* @brief Enable the specified QEI device
* @param device QEI device number
* @return 0 if ok, -1 in case of error
*/
int qei_enable(rt_dev_t device)
{
#if QEI_COUNT >= 1
uint8_t qei = MINOR(device);
if (qei > QEI_COUNT)
{
return -1;
}
_qeis[qei].flags.enabled = 1;
switch (qei)
{
# if (QEI_COUNT >= 1) && !defined(QEI1_DISABLE)
case QEI1_ID:
QEI1CONbits.QEIEN = 1;
break;
# endif
# if (QEI_COUNT >= 2) && !defined(QEI2_DISABLE)
case QEI2_ID:
QEI2CONbits.QEIEN = 1;
break;
# endif
# if (QEI_COUNT >= 3) && !defined(QEI3_DISABLE)
case QEI3_ID:
QEI3CONbits.QEIEN = 1;
break;
# endif
}
return 0;
#else
return -1;
#endif
}
/**
* @brief Disable the specified QEI device
* @param device QEI device number
* @return 0 if ok, -1 in case of error
*/
int qei_disable(rt_dev_t device)
{
#if QEI_COUNT >= 1
uint8_t qei = MINOR(device);
if (qei > QEI_COUNT)
{
return -1;
}
_qeis[qei].flags.enabled = 0;
switch (qei)
{
# if (QEI_COUNT >= 1) && !defined(QEI1_DISABLE)
case QEI1_ID:
QEI1CONbits.QEIEN = 0;
break;
# endif
# if (QEI_COUNT >= 2) && !defined(QEI2_DISABLE)
case QEI2_ID:
QEI2CONbits.QEIEN = 0;
break;
# endif
# if (QEI_COUNT >= 3) && !defined(QEI3_DISABLE)
case QEI3_ID:
QEI3CONbits.QEIEN = 0;
break;
# endif
}
return 0;
#else
return -1;
#endif
}
/**
* @brief QEI sdk enabled state
* @param device qei device number
* @return true if qei was enabled by qei_enable function
*/
bool qei_isEnabled(rt_dev_t device)
{
uint8_t qei = MINOR(device);
if (qei >= QEI_COUNT)
{
return false;
}
return (_qeis[qei].flags.enabled == 1);
}
/**
* Configures the specified QEI device with bits in config
* @param device QEI device number
* @param config config bit
* @return 0 if ok, -1 in case of error
*/
int qei_setConfig(rt_dev_t device, uint16_t config)
{
#if QEI_COUNT >= 1
uint8_t qei = MINOR(device);
if (qei > QEI_COUNT)
{
return -1;
}
switch (qei)
{
# if (QEI_COUNT >= 1) && !defined(QEI1_DISABLE)
case QEI1_ID:
INDX1CNTH = 0xFFFF;
INDX1CNTL = 0xFFFF;
QEI1GECH = 0xFFFF;
QEI1GECL = 0xFFFF;
POS1CNTL = 0;
POS1CNTH = 0;
QEI1IOCbits.QEAPOL = config & QEI_AB_INV;
QEI1IOCbits.QEBPOL = config & QEI_AB_INV;
QEI1IOCbits.IDXPOL = config & QEI_I_INV;
break;
# endif
# if (QEI_COUNT >= 2) && !defined(QEI2_DISABLE)
case QEI2_ID:
INDX2CNTH = 0xFFFF;
INDX2CNTL = 0xFFFF;
QEI2GECH = 0xFFFF;
QEI2GECL = 0xFFFF;
POS2CNTL = 0;
POS2CNTH = 0;
QEI2IOCbits.QEAPOL = config & QEI_AB_INV;
QEI2IOCbits.QEBPOL = config & QEI_AB_INV;
QEI2IOCbits.IDXPOL = config & QEI_I_INV;
break;
# endif
# if (QEI_COUNT >= 3) && !defined(QEI3_DISABLE)
case QEI3_ID:
INDX3CNTH = 0xFFFF;
INDX3CNTL = 0xFFFF;
QEI3GECH = 0xFFFF;
QEI3GECL = 0xFFFF;
POS3CNTL = 0;
POS3CNTH = 0;
QEI3IOCbits.QEAPOL = config & QEI_AB_INV;
QEI3IOCbits.QEBPOL = config & QEI_AB_INV;
QEI3IOCbits.IDXPOL = config & QEI_I_INV;
break;
# endif
}
return 0;
#else
return -1;
#endif
}
/**
* Configure the hardware input filter on QEIx A, B and I
* @param device QEI device number
* @param divider Clock divider
* @return 0 if ok, -1 in case of error
*/
int qei_setInputFilterConfig(rt_dev_t device, uint16_t divider)
{
#if QEI_COUNT >= 1
uint8_t qei = MINOR(device);
if (qei > QEI_COUNT)
{
return -1;
}
uint8_t fltren;
if (divider == 0)
{
fltren = 0;
}
else
{
fltren = 1;
uint8_t shift = 0;
// find the position number of the first bit, rounded up
// ex : input 64 -> output 6
// ex : input 65 -> output 7
while ((shift < 16) && !((divider - 1) & 0x8000))
{
divider <<= 1;
shift++;
}
divider = 16 - shift;
}
switch (qei)
{
# if (QEI_COUNT >= 1) && !defined(QEI1_DISABLE)
case QEI1_ID:
QEI1IOCbits.FLTREN = fltren;
QEI1IOCbits.QFDIV = divider;
break;
# endif
# if (QEI_COUNT >= 2) && !defined(QEI2_DISABLE)
case QEI2_ID:
QEI2IOCbits.FLTREN = fltren;
QEI2IOCbits.QFDIV = divider;
break;
# endif
# if (QEI_COUNT >= 3) && !defined(QEI3_DISABLE)
case QEI3_ID:
QEI3IOCbits.FLTREN = fltren;
QEI3IOCbits.QFDIV = divider;
break;
# endif
}
return 0;
#else
return -1;
#endif
}
/**
* Set QEI position counter to work in modulo mode
* @param device QEI device number
* @param minimum The position counter minimum value. will loop to the maximum value
* @param maximum The position counter maximum value. will loop to the minimum value
* @return 0 if ok, -1 in case of error
*/
int qei_setModuloCountMode(rt_dev_t device, int32_t minimum, int32_t maximum)
{
#if QEI_COUNT >= 1
uint8_t qei = MINOR(device);
if (qei > QEI_COUNT)
{
return -1;
}
switch (qei)
{
# if (QEI_COUNT >= 1) && !defined(QEI1_DISABLE)
case QEI1_ID:
QEI1CONbits.PIMOD = 6; // modulo count mode for position counter
QEI1LECL = minimum & 0xFFFF;
QEI1LECH = (minimum >> 16) & 0xFFFF;
QEI1GECL = maximum & 0xFFFF;
QEI1GECH = (maximum >> 16) & 0xFFFF;
break;
# endif
# if (QEI_COUNT >= 2) && !defined(QEI2_DISABLE)
case QEI2_ID:
QEI2CONbits.PIMOD = 6; // modulo count mode for position counter
QEI2LECL = minimum & 0xFFFF;
QEI2LECH = (minimum >> 16) & 0xFFFF;
QEI2GECL = maximum & 0xFFFF;
QEI2GECH = (maximum >> 16) & 0xFFFF;
break;
# endif
# if (QEI_COUNT >= 3) && !defined(QEI3_DISABLE)
case QEI3_ID:
QEI3CONbits.PIMOD = 6; // modulo count mode for position counter
QEI3LECL = minimum & 0xFFFF;
QEI3LECH = (minimum >> 16) & 0xFFFF;
QEI3GECL = maximum & 0xFFFF;
QEI3GECH = (maximum >> 16) & 0xFFFF;
break;
# endif
}
return 0;
#else
return -1;
#endif
}
/**
* Returns the actual position of the specified QEI
* @param device QEI device number
* @return position
*/
qei_type qei_value(rt_dev_t device)
{
qei_type tmp32 = 0;
#if QEI_COUNT >= 1
uint8_t qei = MINOR(device);
if (qei > QEI_COUNT)
{
return 0;
}
switch (qei)
{
# if (QEI_COUNT >= 1) && !defined(QEI1_DISABLE)
case QEI1_ID:
tmp32 = (uint32_t)POS1CNTL;
tmp32 += (uint32_t)POS1HLD << 16;
break;
# endif
# if (QEI_COUNT >= 2) && !defined(QEI2_DISABLE)
case QEI2_ID:
tmp32 = (uint32_t)POS2CNTL;
tmp32 += (uint32_t)POS2HLD << 16;
break;
# endif
# if (QEI_COUNT >= 3) && !defined(QEI3_DISABLE)
case QEI3_ID:
tmp32 = (uint32_t)POS3CNTL;
tmp32 += (uint32_t)POS3HLD << 16;
# endif
}
#endif
return tmp32;
}
int qei_setValue(rt_dev_t device, qei_type value)
{
#if QEI_COUNT >= 1
uint8_t qei = MINOR(device);
if (qei > QEI_COUNT)
{
return -1;
}
switch (qei)
{
# if (QEI_COUNT >= 1) && !defined(QEI1_DISABLE)
case QEI1_ID:
POS1CNTL = value & 0x0000FFFF;
POS1HLD = value >> 16;
break;
# endif
# if (QEI_COUNT >= 2) && !defined(QEI2_DISABLE)
case QEI2_ID:
POS2CNTL = value & 0x0000FFFF;
POS2HLD = value >> 16;
break;
# endif
# if (QEI_COUNT >= 3) && !defined(QEI3_DISABLE)
case QEI3_ID:
POS3CNTL = value & 0x0000FFFF;
POS3HLD = value >> 16;
# endif
}
#endif
return 0;
}
int qei_setHomeValue(rt_dev_t device, qei_type home)
{
UDK_UNUSED(device);
UDK_UNUSED(home);
// TODO implement me
return 0;
}