Skip to content

Instantly share code, notes, and snippets.

@dhildreth

dhildreth/Makefile

Last active Apr 9, 2019
Embed
What would you like to do?
TS-7680 4-20mA Current Loop Example Code
This gist provides example code for working with a 4-20mA current loop
sensor, specifically temperature, on a TS-7680. It can be applied to
other 4-20mA sensors as well. Here are some steps to run before using
the code in this gist on a TS-7680:
# Setup networking
dhclient eth0
# Install packages
sed -i 's/httpredir/archive/g' /etc/apt/sources.list
apt-get update
apt-get install build-essential bc
# Compile and install getadc
make
# Run getadc
getadc 0
# Run rtdTemp.sh
chmod +x rtdTemp.sh
./rtdTemp.sh
/*******************************************************************************
* getadc.c
*
* Based on mx28adcctl.c example code from Technologic Systems, getadc.c will
* read current loop values (mV and uA) from a given ADC channel and flash the
* "Activity" LED. Refer to the TS-7680 manual for more informtation.
*
* Example usage: ./getadc 0
*
* To compile, simply run `sudo make`. The included Makefile will compile,
* install to /usr/local/bin/, and setup executable permissions so it can be run
* as a normal user without the need for sudo. Run `make clean` to uninstall.
*
*******************************************************************************/
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
void gpioExport(int gpio)
{
int fd;
char buf[255];
fd = open("/sys/class/gpio/export", O_WRONLY|O_SYNC);
sprintf(buf, "%d", gpio);
write(fd, buf, strlen(buf));
close(fd);
}
void gpioDirection(int gpio, int direction) // 1 for output, 0 for input
{
int fd;
char buf[255];
sprintf(buf, "/sys/class/gpio/gpio%d/direction", gpio);
fd = open(buf, O_WRONLY|O_SYNC);
if (direction)
{
if( write(fd, "out", 3) != 3 ) {
perror("write failed");
}
}
else
{
if( write(fd, "in", 2) != 2 ) {
perror("write failed");
}
}
close(fd);
}
void gpioSet(int gpio, int value)
{
int fd;
char buf[255];
sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio);
fd = open(buf, O_WRONLY|O_SYNC);
sprintf(buf, "%d", value);
if( write(fd, buf, 1) != 1 ) {
perror("write failed");
}
close(fd);
}
int main(int argc, char **argv) {
volatile unsigned int *mxlradcregs;
volatile unsigned int *mxhsadcregs;
volatile unsigned int *mxclkctrlregs;
unsigned int i, x;
unsigned long long chan[8] = {0,0,0,0,0,0,0,0};
int devmem;
int activityLed = 58;
int adcPair1 = 231;
int adcPair2 = 232;
// Setup Activity LED
gpioExport(activityLed);
gpioDirection(activityLed, 1);
// Setup all ADCs for 4-20mA Current Loop
gpioExport(adcPair1);
gpioDirection(adcPair1, 1);
gpioSet(adcPair1, 1);
gpioExport(adcPair2);
gpioDirection(adcPair2, 1);
gpioSet(adcPair2, 1);
// EN_CL_0_1 is an FPGA IO, which is somewhat slow.
// Give it time to catch up.
usleep(5000);
// Turn on the activity LED
gpioSet(activityLed, 0); // 1 = off, 0 = on
devmem = open("/dev/mem", O_RDWR|O_SYNC);
assert(devmem != -1);
// LRADC
mxlradcregs = (unsigned int *) mmap(0, getpagesize(),
PROT_READ | PROT_WRITE, MAP_SHARED, devmem, 0x80050000);
mxlradcregs[0x148/4] = 0xfffffff; //Clear LRADC6:0 assignments
mxlradcregs[0x144/4] = 0x6543210; //Set LRDAC6:0 to channel 6:0
mxlradcregs[0x28/4] = 0xff000000; //Set 1.8v range
for(x = 0; x < 7; x++)
mxlradcregs[(0x50+(x * 0x10))/4] = 0x0; //Clear LRADCx reg
for(x = 0; x < 10; x++) {
mxlradcregs[0x18/4] = 0x7f; //Clear interrupt ready
mxlradcregs[0x4/4] = 0x7f; //Schedule conversaion of chan 6:0
while(!((mxlradcregs[0x10/4] & 0x7f) == 0x7f)); //Wait
for(i = 0; i < 7; i++)
chan[i] += (mxlradcregs[(0x50+(i * 0x10))/4] & 0xffff);
}
mxhsadcregs = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED,
devmem, 0x80002000);
mxclkctrlregs = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED,
devmem, 0x80040000);
// HDADC
//Lets see if we need to bring the HSADC out of reset
if(mxhsadcregs[0x0/4] & 0xC0000000) {
mxclkctrlregs[0x154/4] = 0x70000000;
mxclkctrlregs[0x1c8/4] = 0x8000;
//ENGR116296 errata workaround
mxhsadcregs[0x8/4] = 0x80000000;
mxhsadcregs[0x0/4] = ((mxhsadcregs[0x0/4] | 0x80000000) & (~0x40000000));
mxhsadcregs[0x4/4] = 0x40000000;
mxhsadcregs[0x8/4] = 0x40000000;
mxhsadcregs[0x4/4] = 0x40000000;
usleep(10);
mxhsadcregs[0x8/4] = 0xc0000000;
}
mxhsadcregs[0x28/4] = 0x2000; //Clear powerdown
mxhsadcregs[0x24/4] = 0x31; //Set precharge and SH bypass
mxhsadcregs[0x30/4] = 0xa; //Set sample num
mxhsadcregs[0x40/4] = 0x1; //Set seq num
mxhsadcregs[0x4/4] = 0x40000; //12bit mode
while(!(mxhsadcregs[0x10/4] & 0x20)) {
mxhsadcregs[0x50/4]; //Empty FIFO
}
mxhsadcregs[0x50/4]; //An extra read is necessary
mxhsadcregs[0x14/4] = 0xfc000000; //Clr interrupts
mxhsadcregs[0x4/4] = 0x1; //Set HS_RUN
usleep(10);
mxhsadcregs[0x4/4] = 0x08000000; //Start conversion
while(!(mxhsadcregs[0x10/4] & 0x1)) ; //Wait for interrupt
for(i = 0; i < 5; i++) {
x = mxhsadcregs[0x50/4];
chan[7] += ((x & 0xfff) + ((x >> 16) & 0xfff));
}
if (argc < 2) {
printf("%s returns the analog input voltage in mV\n", argv[0]);
printf(" Usage: %s <ADC_PIN_NUMBER>\n", argv[0]);
// Turn off activity LED
gpioSet(activityLed, 1);
// Set ADCs back to normal
gpioSet(adcPair1, 0);
gpioSet(adcPair2, 0);
return 1;
}
int adcPin = atoi(argv[1]);
unsigned int meas_mV, uA;
meas_mV = ((((chan[adcPin]/10)*45177)*6235)/100000000);
uA = (((meas_mV)*1000)/240);
printf("mV: %d\n", meas_mV);
printf("uA: %d\n", uA);
// Turn off activity LED
gpioSet(activityLed, 1);
// Set ADCs back to normal
gpioSet(adcPair1, 0);
gpioSet(adcPair2, 0);
return 0;
}
NAME=getadc
SRCS=getadc.c
CFLAGS=-fno-tree-cselim -Wall -O0 -mcpu=arm9 -o $(NAME)
CC=gcc
INSTALL=/usr/local/bin/
all: main install
main: $(SRCS)
$(CC) $(CFLAGS) $(SRCS)
chown root:root $(NAME)
chmod 4755 $(NAME)
install:
cp $(NAME) $(INSTALL)$(NAME)
clean:
/bin/rm -f $(NAME)
/bin/rm -f $(INSTALL)$(NAME)
#!/bin/bash
####
# Assumes output from getadc to be:
# mV: 2732
# uA: 11383
####
uA=$(getadc 0 | awk 'FNR == 2 {print $2}')
mA=$(echo "scale=3; $uA / 1000" | bc)
####
# For RTD PT100 4-20mA, -50C to 100C transmittor,
# the formula is (where x is temp in C and y is mA):
#
# y = .107x + 9.333
#
# Solving for x:
#
# x = (y - 9.333) / .107
####
tempC=$(echo "scale=1; ($mA - 9.333) / .107" | bc)
tempF=$(echo "scale=1; ($tempC * 9/5) + 32" | bc)
echo "Temp (C): $tempC"
echo "Temp (F): $tempF"
#Output:
#Temp (C): 19.4
#Temp (F): 66.9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment