diff -r 7029db7ac3db -r 3b3af1ff2783 kstmApp/src/drvAdcPi.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kstmApp/src/drvAdcPi.c Tue Jan 19 10:54:27 2016 +0100 @@ -0,0 +1,297 @@ +/** @brief driver for Pi ADC card xxx + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "drvAdcPi.h" + +/* crc("adcPi") */ +#define MYMAGIC 1729550187U + + + + +#define MCP3424_NEW_CONV 0x80 +#define MCP3424_CHANNEL_1 0x00 +#define MCP3424_CHANNEL_2 0x20 +#define MCP3424_CHANNEL_3 0x40 +#define MCP3424_CHANNEL_4 0x60 +#define MCP3424_CONT_CONV 0x10 +#define MCP3424_ONE_SHOT_CONV 0x00 +#define MCP3424_12BIT_240SPS 0x00 +#define MCP3424_14BIT_60SPS 0x04 +#define MCP3424_16BIT_15SPS 0x08 +#define MCP3424_18BIT_3_75SPS 0x0c +#define MCP3424_GAIN_1 0x00 +#define MCP3424_GAIN_2 0x01 +#define MCP3424_GAIN_4 0x02 +#define MCP3424_GAIN_8 0x03 +#define MCP3424_CONT_MASK 0x6f + +// adcPi definitions, on i2c-bus +#define ADC_1 0x68 +#define ADC_2 0x69 +#define ADC_CHANNEL1 (MCP3424_NEW_CONV | MCP3424_CHANNEL_1 | MCP3424_CONT_CONV | MCP3424_14BIT_60SPS | MCP3424_GAIN_1 ) +#define ADC_CHANNEL2 (MCP3424_NEW_CONV | MCP3424_CHANNEL_2 | MCP3424_CONT_CONV | MCP3424_14BIT_60SPS | MCP3424_GAIN_1 ) +#define ADC_CHANNEL3 (MCP3424_NEW_CONV | MCP3424_CHANNEL_3 | MCP3424_CONT_CONV | MCP3424_14BIT_60SPS | MCP3424_GAIN_1 ) +#define ADC_CHANNEL4 (MCP3424_NEW_CONV | MCP3424_CHANNEL_4 | MCP3424_CONT_CONV | MCP3424_14BIT_60SPS | MCP3424_GAIN_1 ) + +/** @brief linked list of card structures + * + */ +struct adcPiCard { + epicsUInt32 magic; + adcPiCard *next; + int cardNumber; + unsigned int i2cAddress; + char* baseAddress; // not used with i2c + unsigned int fh; // file handle + +}; +static adcPiCard *firstCard = NULL; + +int adcPiDebug = 1; +epicsExportAddress (int, adcPiDebug); + +static long adcPiReport (int detail); + +typedef struct { + long number; + DRVSUPFUN report; + DRVSUPFUN init; +} drvAdcPi_drvet; +drvAdcPi_drvet adcPi = { + 2, + adcPiReport, + NULL +}; + +epicsExportAddress (drvet, adcPi); + +static epicsUInt16 getAdc(adcPiCard* card, int signal) +{ +static __u8 res[4]; +static unsigned int dummy; +static __u8 adc, adc_channel; +static int ret; +//static unsigned int threadPrio; +//epicsTimeStamp startTime, endTime; +//double elapsedTime; +//static int loopCounter; + + if (signal < 0 || signal > ADC_PI_MAX_CHANNEL) { + errMessage (-1, "Signal Number out of range"); + return 0; + } + //threadPrio = epicsThreadGetPrioritySelf(); + //epicsThreadSetPriority( epicsThreadGetIdSelf(),epicsThreadPriorityMin ); + + //printf(" card->fh : %d, signal : %d (prio: %d)\n", card->fh, signal, epicsThreadGetPrioritySelf()); + + switch (signal){ + case 0: { adc=ADC_1; adc_channel=ADC_CHANNEL1; }; break; + case 1: { adc=ADC_1; adc_channel=ADC_CHANNEL2; }; break; + case 2: { adc=ADC_1; adc_channel=ADC_CHANNEL3; }; break; + case 3: { adc=ADC_1; adc_channel=ADC_CHANNEL4; }; break; + case 4: { adc=ADC_2; adc_channel=ADC_CHANNEL1; }; break; + case 5: { adc=ADC_2; adc_channel=ADC_CHANNEL2; }; break; + case 6: { adc=ADC_2; adc_channel=ADC_CHANNEL3; }; break; + case 7: { adc=ADC_2; adc_channel=ADC_CHANNEL4; }; break; + default: { adc=ADC_1; adc_channel=ADC_CHANNEL1; }; break; + } + + + // choose device + if (ioctl(card->fh,I2C_SLAVE,adc) != 0) errMessage (0, "ioctl failed"); + //if (usleep (50000) < 0) errMessage (0, "usleep failed"); + //printf ("adc_channel = 0x%02X \n", adc_channel); + //epicsTimeGetCurrent(&startTime); + if (i2c_smbus_write_byte (card->fh, adc_channel) != 0) errMessage (0, "i2c_smbus_write_byte failed"); + // wait a little bit for end of conversion + if (usleep (50000) < 0) errMessage (0, "usleep failed"); + // 3 for != 18bit mode + //loopCounter = 0; + do { + ret = i2c_smbus_read_i2c_block_data(card->fh, adc_channel, 3, res); + // printf(" res[0] = 0x%02X, res[1] = 0x%02X, res[2] = 0x%02X\n", res[0], res[1], res[2]); + if (ret != 3) { + errMessage (0, "i2c_smbus_read_i2c_block_data"); + fprintf (stderr, "i2c_smbus_read_i2c_block_data returns %d bytes != 3\n", ret); + } + //if (res[2] & 0x80) { + // fprintf (stderr, "i2c_smbus_read_i2c_block_data, output register (0x%02X) not updated yet\n", res[2]); + //} + //loopCounter++; + } while (res[2] & 0x80); + + //epicsTimeGetCurrent(&endTime); + //elapsedTime = epicsTimeDiffInSeconds(&endTime, &startTime); + //printf("Elapsed time %f\n", elapsedTime); + //printf(" res[0] = 0x%02X, res[1] = 0x%02X, res[2] = 0x%02X, loopCounter = %d\n", res[0], res[1], res[2], loopCounter); + + + dummy = (res[0]<<8|res[1]); + if (dummy>=32768) dummy=65536-dummy; + //val = dummy * 0.000154; + // printf(" dummy = %d, val = %lf\n", dummy, val); + //return val; + //if (adcPiDebug) printf ("dummy = 0x%x\n", dummy); + // epicsThreadSetPriority( epicsThreadGetIdSelf(), threadPrio); + return dummy; +} + + +/** @brief configure function + * + * The configure function is called from the startup script + */ +int adcPiConfigure (int cardNumber, unsigned int i2cAddress) +{ + // long status; + // volatile void* baseAddress; + // char id[6]; + adcPiCard **pCard; + + /** @brief Check card number for sanity */ + if (cardNumber != 1) { + fprintf (stderr, "adcPiConfigure: cardNumber %d must be 1\n", cardNumber); + return S_dev_noDevice; + } + + /** @brief Find end of card list and check for duplicates */ + for (pCard = &firstCard; *pCard; pCard=&(*pCard)->next) { + if ((*pCard)->cardNumber == cardNumber) { + fprintf (stderr, "adcPiConfigure: cardnumber %d already in use\n", cardNumber); + return S_dev_identifyOverlap; + } + } // pCard points to the end of the list + + + /** @brief Check address for sanity + * + * We use /dev/i2c-1, should be fixed/solved, so a "1" should be used*/ + if (i2cAddress != 1) { + fprintf (stderr, "adcPiConfigure: i2cAddress %d must be 1\n", i2cAddress); + return S_dev_noDevice; + } + + // check VMEaddress for sanity + + // translate address to local address, check for overlap + + // check that correct hardware is installed, devReadProbe + // read i2c? + + /** @brief create new card structure + * + */ + *pCard = malloc (sizeof(adcPiCard)); + if (!*pCard) { + fprintf (stderr, "adcPiConfigure: out of memory\n"); + return S_dev_noMemory; + } + + (*pCard)->fh = open("/dev/i2c-1", O_RDWR); // "1" hardcoded! + if ((*pCard)->fh <= 0) { + fprintf (stderr, "adcPiConfigure: could not open /dev/i2c-1\n"); + return S_dev_noDevice; + } + + (*pCard)->magic = MYMAGIC; + (*pCard)->next = NULL; + (*pCard)->cardNumber = cardNumber; + (*pCard)->i2cAddress = i2cAddress; + + return 0; +} + +adcPiCard* adcPiOpen (int cardNumber) +{ + adcPiCard* card; + for (card = firstCard; card; card=card->next) + if (card->cardNumber == cardNumber) return card; + return NULL; +} + +int adcPiGet (adcPiCard* card, int signal, epicsUInt16* pValue) +{ + + if (adcPiDebug>1) + printf("adcPiGet card %d signal %d (adcPiDebug: %d)\n", + card->cardNumber, signal, adcPiDebug); + + if (!card) return S_dev_noDevice; + if (card->magic != MYMAGIC) return S_dev_wrongDevice; + + if (signal < 0 || signal > ADC_PI_MAX_CHANNEL) return S_dev_badSignalNumber; + + *pValue = getAdc(card, signal); + + if (adcPiDebug>1) + printf("adcPiGet card %d signal %d @%p = 0x%4X\n", + card->cardNumber, signal, (void *)&getAdc, (epicsUInt16)*pValue); + return 0; +} + +/** @brief report function + * + */ +static long adcPiReport (int detail) +{ + adcPiCard *card; + for (card = firstCard; card; card = card->next) { + printf (" card %d at address %p \n", card->cardNumber, card->baseAddress); + if (detail >= 1) { + int signal; + unsigned short value; + for (signal = 0; signal < ADC_PI_MAX_CHANNEL; signal++) { + value = getAdc(card, signal); + printf(" ADC %d = 0x%04x = %+8.4f V\n", signal, value, value * 0.000154); // tobedef + } + } + } + return 0; +} + + + + +static const iocshArg adcPiConfigureArg0 = { "cardNumber", iocshArgInt }; +static const iocshArg adcPiConfigureArg1 = { "i2cAddress", iocshArgInt }; + +static const iocshArg * const adcPiConfigureArgs[] = { + &adcPiConfigureArg0, + &adcPiConfigureArg1 +}; +static const iocshFuncDef adcPiConfigureDef = { "adcPiConfigure", 2, adcPiConfigureArgs }; +static void adcPiConfigureFunc (const iocshArgBuf *args) +{ + adcPiConfigure (args[0].ival, args[1].ival); +} + +static void adcPiRegister () +{ + iocshRegister (&adcPiConfigureDef, adcPiConfigureFunc); +} + +epicsExportRegistrar (adcPiRegister);