diff --git a/Lib/Makefile b/Lib/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c629db44e8cd309da8541648adfd4b40ac1bc5cd --- /dev/null +++ b/Lib/Makefile @@ -0,0 +1,146 @@ + +CC=gcc -fPIC -g +CFLAGS= -c -Wall +LDFLAGS= + +#defined global variables and programs to build +include ../conf/Makefile + +#Globals Directories + +# necessary to access Paolo includes to build interface to its library (contains includes and libs) +# +# used if no rpm +# PCIE40_INC_DIR=$(pcie40DaqDir) +# PCIE40_DYN_LIB=$(pcie40DaqDir)/pcie40_ecs/libpcie40_ecs.so +# PCIE40_STAT_LIB=$(pcie40DaqDir)/pcie40_ecs/libpcie40_ecs.a +# used if rpm (normally useless because default +# but need to be defined later or build crashes because include in -I are missing +PCIE40_INC_DIR=/usr/include/ +PCIE40_DYN_LIB=/usr/lib64 +PCIE40_STAT_LIB=/usr/lib64 + +OBJ_DIR=obj/ +SRC_DIR=src/ +INC_DIR=inc/ +LIB_DIR=lib/ + +#SubDirectories +ECS_DIR=ecs/ +MINIPODS_DIR=minipods/ +USER_DIR=user/ +SYSTEM_DIR=system/ +LTC2990_DIR=ltc2990/ + +#Files ------------------------------------------------------------------------ + +#ECS +ECS_SRC= $(wildcard $(SRC_DIR)$(ECS_DIR)*.c) +ECS_OBJ=$(ECS_SRC:$(SRC_DIR)$(ECS_DIR)%.c=$(OBJ_DIR)%.o) + +#Minipods +MINIPODS_SRC= $(wildcard $(SRC_DIR)$(MINIPODS_DIR)*.c) +MINIPODS_OBJ=$(MINIPODS_SRC:$(SRC_DIR)$(MINIPODS_DIR)%.c=$(OBJ_DIR)%.o) + +#User +USER_SRC= $(wildcard $(SRC_DIR)$(USER_DIR)*.c) +USER_OBJ=$(USER_SRC:$(SRC_DIR)$(USER_DIR)%.c=$(OBJ_DIR)%.o) + +#LTC2990 +LTC2990_SRC= $(wildcard $(SRC_DIR)$(LTC2990_DIR)*.c) +LTC2990_OBJ=$(LTC2990_SRC:$(SRC_DIR)$(LTC2990_DIR)%.c=$(OBJ_DIR)%.o) + +# static libraries +ECS_LIB= libecs.a +MINIPODS_LIB= libminipods.a +USER_LIB= libuser.a +LTC2990_LIB= libltc2990.a +# dynamic libraries +USER_DYNLIB= libuser-dyn.so +LLI_DYNLIB= lli-dyn.so + + +all: $(ECS_OBJ) $(ECS_LIB) $(MINIPODS_OBJ) $(MINIPODS_LIB) $(LTC2990_OBJ) $(LTC2990_LIB) $(LLI_DYNLIB) $(USER_LIB) $(USER_DYNLIB) + +$(ECS_OBJ): $(OBJ_DIR)%.o : $(SRC_DIR)$(ECS_DIR)%.c + @echo "Construction of ecs objects $@ from $<" + $(CC) $(CFLAGS) -I $(INC_DIR)$(ECS_DIR) -I $(INC_DIR)$(SYSTEM_DIR) -I $(PCIE40_INC_DIR) $< -o $@ + +$(ECS_LIB) : $(ECS_OBJ) + @echo "Construction of ECS Library" + ar -q $(LIB_DIR)$(ECS_LIB) $(ECS_OBJ) + @echo "" + +$(MINIPODS_OBJ): $(OBJ_DIR)%.o : $(SRC_DIR)$(MINIPODS_DIR)%.c + @echo "Construction of $@ from $<" + $(CC) $(CFLAGS) -I $(INC_DIR)$(MINIPODS_DIR) -I $(INC_DIR)$(SYSTEM_DIR) -I $(INC_DIR)$(ECS_DIR) -I $(PCIE40_INC_DIR) $< -o $@ + @echo "" + +$(MINIPODS_LIB) : $(MINIPODS_OBJ) + @echo "Construction of MINIPODS Library" + ar -q $(LIB_DIR)$(MINIPODS_LIB) $(MINIPODS_OBJ) + @echo "" + +$(LTC2990_OBJ): $(OBJ_DIR)%.o : $(SRC_DIR)$(LTC2990_DIR)%.c + @echo "Construction of $@ from $<" + $(CC) $(CFLAGS) -I $(INC_DIR)$(PLL_DIR) -I $(INC_DIR)$(LTC2990_DIR) -I $(INC_DIR)$(SYSTEM_DIR) -I $(INC_DIR)$(MINIPODS_DIR) -I $(INC_DIR)$(LTC2990_DIR) -I $(PCIE40_INC_DIR) $< -o $@ + @echo "" + +$(LTC2990_LIB) : $(LTC2990_OBJ) + @echo "Construction of LTC2990 Library" + ar -q $(LIB_DIR)$(LTC2990_LIB) $(LTC2990_OBJ) + @echo "" + +$(USER_OBJ): $(OBJ_DIR)%.o : $(SRC_DIR)$(USER_DIR)%.c + @echo "Construction of $@ from $<" + $(CC) $(CFLAGS) -I $(INC_DIR)$(USER_DIR) -I $(INC_DIR)$(SYSTEM_DIR) -I $(INC_DIR)$(ECS_DIR) -I $(PCIE40_INC_DIR) $< -o $@ + @echo "" + +$(USER_LIB) : $(USER_OBJ) + @echo "Construction of USER Library" + ar -q $(LIB_DIR)$(USER_LIB) $(USER_OBJ) $(ECS_OBJ) + @echo "" + +$(USER_DYNLIB) : $(USER_OBJ) + @echo "Construction of dynamic USER Library" + $(CC) -o $(LIB_DIR)$(USER_DYNLIB) -shared $(USER_OBJ) $(ECS_OBJ) + @echo + +$(LLI_DYNLIB) : $(ECS_OBJ) $(MINIPODS_OBJ) + @echo "Construction of dynamic LLI technical Library for V2" +# with locally built ecs library +# $(CC) -o $(LIB_DIR)$(LLI_DYNLIB) -shared $(ECS_OBJ) $(PLL_OBJ) $(MINIPODS_OBJ) $(PCIE40_DYN_LIB) +# with rpm installed ecs library + $(CC) -o $(LIB_DIR)$(LLI_DYNLIB) -shared $(ECS_OBJ) $(MINIPODS_OBJ) -lpcie40_ecs + @echo + +clean: mrproper + @echo "removing lli objects" + -rm $(OBJ_DIR)*.o + @echo "" + + @echo "removing $(ECS_LIB)" + -rm $(LIB_DIR)$(ECS_LIB) + @echo "" + + @echo "removing $(MINIPODS_LIB)" + -rm $(LIB_DIR)$(MINIPODS_LIB) + @echo "" + + @echo "removing $(LTC2990_LIB)" + -rm $(LIB_DIR)$(LTC2990_LIB) + @echo "" + + @echo "removing $(USER_LIB)" + -rm $(LIB_DIR)$(USER_LIB) + -rm $(LIB_DIR)$(USER_DYNLIB) + -rm $(LIB_DIR)$(LLI_DYNLIB) + + @echo "" + + +mrproper: + @echo "Removing all *~ files" + -find . -name "*~" -exec rm {} \; + @echo "" + diff --git a/Lib/i2c_ltc2990_lib.c b/Lib/i2c_ltc2990_lib.c new file mode 100644 index 0000000000000000000000000000000000000000..090488922db5f5ffc555b151aaf56c6e1ae8a46c --- /dev/null +++ b/Lib/i2c_ltc2990_lib.c @@ -0,0 +1,294 @@ +/****************************************************************************************//** +* \file i2c_ltc2990_lib.c +* +* \brief This file contains the user driver to control the 3 ltc2990 ADC components. +* +* \author MJ/PYD +* \version 0.1 +* \date : 15/03/2016 +* \copyright (c) Copyright CERN for the benefit of the LHCb Collaboration. +* Distributed under the terms of the GNU General Public Licence V3. +* ana.py script is free and open source software. +* +* CHANGELOG +* PYD : 15/03/2016 initial version +* PYD : 16/09/2016 use multiple boards +*//********************************************************************************************/ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> + +#include <systemConfig.h> +#include <i2cDriver.h> +#include <ltc2990.h> + +// Temporisation Fernand Raynaud pour basculer entre 2 modes +//TEMPO_FERNAND 0.3 +#define BUS_DELAY 300000 + +// usefull for configuration functions +# define trigger 0x7F + +/***********************************************************************//** + * \fn int setConfig(int dev, int bus, unsigned add, unsigned config) + * \brief Function to configure the component + * + * 1) Apply the configuration + * 2) Déclenchement du trigger : on met nimporte quelle valeur dans + * TRIGGER_REGISTER, par exemple 0x7F + * je dis 0x7F car apparement le bit 7 du TRIGGER_REGISTER reste + * toujours à 0, donc la relecture est erronee... + * + * 3) 13/01/2015 : on met une tempo car lorsque l'on change de mode, + * car on a observé que l'on doit attendre un certain temps + * (au sens etymologique de fernand raynaud...) pour basculer + * + * \param bus : the i2c bus number + * \param add : the component add on the i2c bus + * \param config : the value of the config word + * \return 1 success, 0 error + *//***********************************************************************/ +static int setConfig(int dev, int bus, unsigned add, unsigned config){ + unsigned val = trigger; +// int i2c_writeMem(int bus, unsigned slaveAdd, unsigned regIndex, unsigned *val) + if ( (i2c_writeMem(dev, bus, add, CONTROL_REGISTER_ADDRESS, &config) == -1) + ||(i2c_writeMem(dev, bus, add, TRIGGER_REGISTER_ADDRESS, &val ) == -1) ){ + printf("Configuration is not OK!!!\n"); + return(0); + } + else { + usleep(BUS_DELAY); +// time.sleep(TEMPO_FERNAND) +// printf("Configuration is OK\n"); + return(1); + } +} +/***********************************************************************//** + * \fn int setConfig2TR(int dev, int bus, int add) + * \brief Function to configure the component for 2 differential temperature, + * \brief probes, mode repeat, temperature en Celsius + * + * CONTROL_REGISTER= 0x1D (0001 1101), c'est à dire: + * Mode[2:0] = 101 = TR1,TR2 + * Mode[4:3] = 11 = All Measurements per Mode[2:0], lectures de registres + * fixees sur TR1,TR2 + * Temperature Format = 0 (Temperature reported in Celsius) + * Repeat/Single = 0 (Repeat Acquisition) + * + * \param bus : the i2c bus number + * \param add : the component add on the i2c bus + * \return 1 success, 0 error + *//***********************************************************************/ +int Config2TR(int dev, int bus, int add){ + printf("ltc2990: onfiguration for 2 TR sensor temperature is running....\n"); + return setConfig(dev, bus, add, 0x1D); +} +/***********************************************************************//** + * \fn int setConfig2TR(int bus, int add) + * \brief Function to configure the component for 2 differential tension reading, + * \brief mode repeat, temperature en Celsius + * + * CONTROL_REGISTER= 0x1E (0001 1110), c'est à dire: + * Mode[2:0] = 101 = lecture de V1-V2, V3-V4 + * Mode[4:3] = 11 = All Measurements per Mode[2:0],lectures de registres + * fixees sur V1-V2, V3-V4 + * Temperature Format = 0 = Temperature reported in Celsius + * Repeat/Single = 0 = Repeat Acquisition + * + * \param bus : the i2c bus number + * \param add : the component add on the i2c bus + * \return 1 success, 0 error + *//***********************************************************************/ +int Config2VoltDif(int dev, int bus, int add){ + printf("ltc2990: ltc2990 configuration for 2 differential voltage is running....\n"); + return setConfig(dev, bus, add, 0x1E); +} +/***********************************************************************//** + * \fn int Config4VoltSingleEnded(int bus, int add) + * \brief Function to configure the component to read 4 tensions single ended, + * \brief mode repeat, temperature en Celsius + * + * CONTROL_REGISTER= 0x1F = 0001 1111, c'est à dire: + * Mode[2:0] = 111 = lecture de V1,V2,V3,V4 + * Mode[4:3] = 11 = All Measurements per Mode[2:0],lectures de registres + * fixées sur V1,V2, V3,V4 + * Temperature Format = 0 = Temperature reported in Celsius + * Repeat/Single = 0 = Repeat Acquisition + * + * Note : it is important to select Celsius temp because even in this config + * we read the circuit internal temperature + * + * \param bus : the i2c bus number + * \param add : the component add on the i2c bus + * \return 1 success, 0 error + *//***********************************************************************/ +int Config4VoltSingleEnded(int dev, int bus, int add){ + printf("ltc2990: configuration for 4 single ended voltage is running..\n"); + return setConfig(dev, bus, add, 0x1F); +} + + +/****************************************************************************//** + * \fn int two_comp13(int nb13bits) + * \brief Function to present the right way a complemented to two in 13 bits value, + * + * All temperatures -internal or TR1 or TR2) are in 13bits complemented to 2. + * So we need this conversion function + * + * \return : the converted value + *//*****************************************************************************/ +//static int two_comp13(int nb13bits){ +static unsigned two_comp13(unsigned nb13bits){ + if (nb13bits > 8191){ + printf("ltc2990: ERROR number is greater than 8191!!!\n"); + nb13bits = 8191; + } + if (nb13bits <= 4095) + return(nb13bits); + else + return(nb13bits-8192); +} +/****************************************************************************//** + * \fn int two_comp15(int nb15bits) + * \brief Function to present the right way a complemented to two in 15 bits value, + * + * All single-ended (V1,V2,V3,V4) or differential (V1-V2, V3-V4) tensions + * are in 15bits complemented to 2. + * So we need this conversion function + * + * \return : the converted value + *//*****************************************************************************/ +static int two_comp15(int nb15bits){ + if (nb15bits > 32767){ + printf("ltc2990: ERROR number is greater than 32767!!!\n"); + nb15bits = 32767; + } + if (nb15bits <= 16383) + return(nb15bits); + else + return(nb15bits-32768); +} +/*************************************************************************************************//** + * \fn float ReadTempOrTension(int bus, int add, int msbReg, int lsbReg, int measureType, int inversion) + * \brief Function to read the temperature or tension in the component + * + * We loop reading the MSB register untill bit 7 switch to 1. + * We apply the mask: + * - when temperature reading to extract D8-D12 bits + * - when tension reading D8-D13 and D14 (sign) + * We read the LSB register to concatenate the two words to get the full value + * We then complement the value to 2 and multiply by a constant factor + * - factor = 0.0625 for temp + * - factor = 0.00030518 for tensions + * + * \param bus : the i2c bus number on the board + * \param add : the component i2c address + * \param msbReg : the msb register index + * \param lsbReg : the lsb register index + * \param measureType : type of measure TEMP or VOLT + * \param inversion : for some components the tension is inverted (1 or 0) + * + * \return read value or 0 if failed + *//*************************************************************************************************/ +static float ReadTempOrTension(int dev, int bus, unsigned add, unsigned msbReg, unsigned lsbReg, enum type_measure measureType, int inversion){ + unsigned mask; + int cpt_timeout = 0; + int DataValidBit = 0; + float factor, RSHUNT, LSB_DIFFERENTIAL; + unsigned LocalTempMSB, dataMSB, dataLSB, dataInteger16; + + if (measureType == TEMP){ + mask = 0b11111; + factor = 0.0625; + } + else { + mask = 0b1111111; + factor = 0.00030518; + } +// On divise ensuite par la valeur de la resistance de shunt ( +// supposee egale a 0.003 ohm) pour avoir la valeur du courant IPEX09V + if (inversion == 1){ + RSHUNT = 0.003; + LSB_DIFFERENTIAL = 0.00001942; + factor = LSB_DIFFERENTIAL/RSHUNT; + } + while (!(DataValidBit)){ +// int i2c_readMem(int bus, unsigned slaveAdd, unsigned regIndex, unsigned *val) + if (i2c_readMem(dev, bus, add, msbReg, &LocalTempMSB) != 0){ + printf("ReadTempOrTension : error readihg i2c register\n"); + return(0); + } +// LocalTempMSB = i2c.read(bus, add, msbReg)[1] + DataValidBit = (0b10000000) & LocalTempMSB; + cpt_timeout = cpt_timeout + 1; + if (cpt_timeout > 1000){ + printf("ReadTempOrTension : Error Timeout to read\n"); + break; + } + } + dataMSB = LocalTempMSB & mask; + +// dataLSB = i2c.read(bus, add, lsbReg)[1] + if (i2c_readMem(dev, bus, add, lsbReg, &dataLSB) != 0){ + printf("ReadTempOrTension : error readihg i2c register\n"); + return(0); + } + dataInteger16 = dataMSB*256 + dataLSB; + if (measureType == TEMP){ + return(two_comp13(dataInteger16)*factor); + } + else { + if (inversion == 1) + return (-two_comp15(dataInteger16)*factor); + else + return (two_comp15(dataInteger16)*factor); + } +} + +float ReadLocalTemperature(int dev, int bus, unsigned add){ + enum type_measure temp = TEMP; + return(ReadTempOrTension(dev, bus, add, TINTMSB_REGISTER_ADDRESS, TINTLSB_REGISTER_ADDRESS, temp, 0)); +} + +float ReadTR1(int dev, int bus,unsigned add){ + enum type_measure temp = TEMP; + return(ReadTempOrTension(dev, bus, add, V1MSB_REGISTER_ADDRESS, V1LSB_REGISTER_ADDRESS, temp, 0)); +} + +float ReadTR2(int dev, int bus,unsigned add){ + enum type_measure temp = TEMP; + return (ReadTempOrTension(dev, bus, add, V3MSB_REGISTER_ADDRESS, V3LSB_REGISTER_ADDRESS, temp, 0)); +} + +float ReadV1(int dev, int bus,unsigned add){ + enum type_measure tens = VOLT; + return(ReadTempOrTension(dev, bus, add, V1MSB_REGISTER_ADDRESS, V1LSB_REGISTER_ADDRESS, tens, 0)); +} + +float ReadV2(int dev, int bus,unsigned add){ + enum type_measure tens = VOLT; + return(ReadTempOrTension(dev, bus, add, V2MSB_REGISTER_ADDRESS, V2LSB_REGISTER_ADDRESS, tens, 0)); +} + +float ReadV3(int dev, int bus,unsigned add){ + enum type_measure tens = VOLT; + return(ReadTempOrTension(dev, bus, add, V3MSB_REGISTER_ADDRESS, V3LSB_REGISTER_ADDRESS, tens, 0)); +} + +float ReadV4(int dev, int bus,unsigned add){ + enum type_measure tens = VOLT; + return(ReadTempOrTension(dev, bus, add, V4MSB_REGISTER_ADDRESS, V4LSB_REGISTER_ADDRESS, tens, 0)); +} + +float ReadIPEX09V(int dev, int bus,unsigned add){ +// Entering this function we have to be in read differential tension mode. + enum type_measure tens = VOLT; + return(ReadTempOrTension(dev, bus, add, V1minV2MSB_REGISTER_ADDRESS, V1minV2LSB_REGISTER_ADDRESS, tens, 1)); +} + +float ReadIPEX09VDDA(int dev, int bus,unsigned add){ +// Entering this function we have to be in read differential tension mode. + enum type_measure tens = VOLT; + return (ReadTempOrTension(dev, bus, add, V3minV4MSB_REGISTER_ADDRESS, V3minV4LSB_REGISTER_ADDRESS, tens, 1)); +} +