# HG changeset patch # User Heinz Junkes # Date 1453197267 -3600 # Node ID 3b3af1ff2783849aec2f065b9863bf99fc2c52b7 # Parent 7029db7ac3db4cc6ed2136d75fac02fc9e40fcd0 add driver abd device support for adcPi diff -r 7029db7ac3db -r 3b3af1ff2783 iocBoot/iockstm/st.cmd --- a/iocBoot/iockstm/st.cmd Wed Sep 09 18:06:59 2015 +0200 +++ b/iocBoot/iockstm/st.cmd Tue Jan 19 10:54:27 2016 +0100 @@ -38,6 +38,11 @@ drvAsynIPPortConfigure(${PGC2_MC_LINK}, ${PGC2_MC_INET}, 0, 0, 0) drvAsynIPPortConfigure(${PGC2_PC_LINK}, ${PGC2_PC_INET}, 0, 0, 0) +#drvAsynI2CConfigure( "I2C", "/dev/i2c-1" ) + +adcPiConfigure ("1", "1") +var adcPiDebug 0 + # Set asyn trace IO format #define ASYN_TRACEIO_NODATA 0x0000 #define ASYN_TRACEIO_ASCII 0x0001 @@ -67,9 +72,14 @@ dbLoadRecords("db/pgc2.db","PORT=PGC2_MC, P=FHI4KSTM, Q=PGC2_MC") dbLoadRecords("db/pgc2.db","PORT=PGC2_PC, P=FHI4KSTM, Q=PGC2_PC") +#dbLoadRecords("db/adcPi.db","P=FHI4KSTM:ADCPI:CH_0,C=0") #dbLoadRecords("db/adcPi.db","P=FHI4KSTM:ADCPI:CH_1,C=1") -#dbLoadRecords("db/adcPi.db","P=FHI4KSTM:ADCPI:CH_2,C=2") +dbLoadRecords("db/adcPi.db","P=FHI4KSTM:ADCPI:CH_2,C=2") dbLoadRecords("db/adcPi.db","P=FHI4KSTM:ADCPI:CH_3,C=3") +#dbLoadRecords("db/adcPi.db","P=FHI4KSTM:ADCPI:CH_4,C=4") +#dbLoadRecords("db/adcPi.db","P=FHI4KSTM:ADCPI:CH_5,C=5") +#dbLoadRecords("db/adcPi.db","P=FHI4KSTM:ADCPI:CH_6,C=6") +#dbLoadRecords("db/adcPi.db","P=FHI4KSTM:ADCPI:CH_7,C=7") iocInit() diff -r 7029db7ac3db -r 3b3af1ff2783 kstmApp/Db/adcPi.db --- a/kstmApp/Db/adcPi.db Wed Sep 09 18:06:59 2015 +0200 +++ b/kstmApp/Db/adcPi.db Tue Jan 19 10:54:27 2016 +0100 @@ -1,9 +1,10 @@ record(ai,"$(P)"){ - field(DTYP,"AdcPi") + field(DTYP,"adcPi") field(DESC,"ADC Pi") field(SCAN,"$(SCAN=1 second)") - field(INP,"$(C)") + field(INP,"#C1 S$(C) @dumm") field(LINR,"LINEAR") - field (ESLO, "0.000154") + field (EGUF, "1.024") + field (EGUL, "-1.024") field(EGU,"V") } diff -r 7029db7ac3db -r 3b3af1ff2783 kstmApp/src/Makefile --- a/kstmApp/src/Makefile Wed Sep 09 18:06:59 2015 +0200 +++ b/kstmApp/src/Makefile Tue Jan 19 10:54:27 2016 +0100 @@ -22,7 +22,7 @@ kstm_DBD += drvAsynIPPort.dbd kstm_DBD += stream.dbd kstm_DBD += adcPi.dbd - +#kstm_DBD += drvAsynI2C.dbd # Add all the support libraries needed by this IOC #kstm_LIBS += xxx @@ -38,7 +38,10 @@ kstm_SRCS += pi_2_dht_read.c kstm_SRCS += aSubReadDHT.c #kstm_SRCS += dbSubReadADC.c -kstm_SRCS += devadcpi.c +#kstm_SRCS += devadcpi.c +kstm_SRCS += drvAdcPi.c +kstm_SRCS += devAdcPi.c +#kstm_SRCS += drvAsynI2C.cpp # Build the main IOC entry point on workstation OSs. kstm_SRCS_DEFAULT += kstmMain.cpp diff -r 7029db7ac3db -r 3b3af1ff2783 kstmApp/src/adcPi.dbd --- a/kstmApp/src/adcPi.dbd Wed Sep 09 18:06:59 2015 +0200 +++ b/kstmApp/src/adcPi.dbd Tue Jan 19 10:54:27 2016 +0100 @@ -1,1 +1,4 @@ -device(ai,CONSTANT,devAiAdcPi,"AdcPi") +driver (adcPi) +variable (adcPiDebug, int) +registrar (adcPiRegister) +device (ai, VME_IO, adcPiAi, "adcPi") diff -r 7029db7ac3db -r 3b3af1ff2783 kstmApp/src/devAdcPi.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kstmApp/src/devAdcPi.c Tue Jan 19 10:54:27 2016 +0100 @@ -0,0 +1,124 @@ +/** @brief device support adcPi + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "drvAdcPi.h" + +typedef struct { + adcPiCard* card; + int signal; +} adcPiAiPrivate; + +long adcPiInitRecordAi (aiRecord *record); +long adcPiReadAi (aiRecord *record); +long adcPiSpecialLinconvAi (aiRecord *record, int after); + +struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_ai; + DEVSUPFUN special_linconv; +} adcPiAi = { + 6, + NULL, + NULL, + adcPiInitRecordAi, + NULL, + adcPiReadAi, + adcPiSpecialLinconvAi +}; +epicsExportAddress (dset, adcPiAi); + +/** @brief init record + * + */ +long adcPiInitRecordAi (aiRecord *record) +{ + adcPiAiPrivate *priv; + epicsUInt16 initval; + adcPiCard* card; + int signal; + + if (record->inp.type != VME_IO) { + errlogSevPrintf (errlogFatal, "adcPiInitRecordAi %s: illegal INP link type\n", record->name); + return -1; + } + + card = adcPiOpen (record->inp.value.vmeio.card); + if (!card) { + errlogSevPrintf (errlogFatal, "adcPiInitRecordAi %s: invalid card number %d\n", record->name, record->inp.value.vmeio.card); + return S_dev_noDevice; + } + + signal = record->inp.value.vmeio.signal; + if (signal < 0 || signal >= ADC_PI_MAX_CHANNEL) { + errlogSevPrintf (errlogFatal, "adcPiInitRecordAi %s: invalid signal number %d\n", record->name, signal); + return S_dev_badSignalNumber; + } + + priv = (adcPiAiPrivate*) malloc (sizeof (adcPiAiPrivate)); + if (!priv) { + errlogSevPrintf (errlogFatal, "adcPiInitRecordAi %s: out of memory\n", record->name); + return S_dev_noMemory; + } + + priv->card = card; + priv->signal = signal; + record->dpvt = priv; + + // printf(" priv at @%p [%d]\n", priv, sizeof (adcPiAiPrivate) ); + + adcPiSpecialLinconvAi (record, TRUE); + adcPiGet (card, signal, &initval); + + record->rval = initval; + return 0; +} + +long adcPiReadAi (aiRecord *record) +{ + adcPiAiPrivate *priv = (adcPiAiPrivate*) record->dpvt; + int status; + + // printf("ReadAi: priv at @%p [%d]\n", priv, sizeof (adcPiAiPrivate) ); + + if (!priv) { + recGblSetSevr (record, UDF_ALARM, INVALID_ALARM); + errlogSevPrintf (errlogFatal, "adcPiReadAi %s: record not initialized correctly\n", record->name); + return -1; + } + unsigned short value; + status = adcPiGet (priv->card, priv->signal, &value); + if (status) { + errlogSevPrintf (errlogFatal, "adcPiReadAi %s: adcPiGet failes: error code 0x%x\n", record->name, status); + recGblSetSevr (record, READ_ALARM, INVALID_ALARM); + } + record->rval = value; + return status; // 2 do not convert +} + +long adcPiSpecialLinconvAi (aiRecord *record, int after) +{ + if (after) { + // printf(" In convert ....\n"); + // Check/Check ... + // MAX_CODE_12BIT / 2048 Volt + //record->eoff = ( 8191 * record->egul - -8192 * record->eguf) / (8191 - 8192); + record->eoff = 0; + record->eslo = 0.000250; // 205 uV (record->eguf - record->egul)/ (8191 - 8192); + } + return 0; +} + + + 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); diff -r 7029db7ac3db -r 3b3af1ff2783 kstmApp/src/drvAdcPi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kstmApp/src/drvAdcPi.h Tue Jan 19 10:54:27 2016 +0100 @@ -0,0 +1,35 @@ +#ifndef drvAdcPi_h +#define drvAdcPi_h +#include +#include + + +#define ADC_PI_MAX_CHANNEL 8 + +#define MAX_CODE_12BIT 8191 + +/** @brief Initialize the card + * + * Initialize the card(called from startup script) + */ +int adcPiConfigure (int cardnumber, unsigned int i2cAddress); + +/** @brief card handle + * + * Define a type for the card handle + */ +typedef struct adcPiCard adcPiCard; + +/** @brief open card + * + * Get card handle for card number + */ +adcPiCard* adcPiOpen (int cardnumber); + +/** @brief get values + * + * Read values from channels + */ +int adcPiGet (adcPiCard* card, int signal, epicsUInt16* pvalue); + +#endif \ No newline at end of file