My application
I designed a 32 regulated power supply, computer controlled. The PC interface is written in Java and provides all control needed. The system has 32 removable voltage regulators boards. Each voltage regulators have two voltage references (in the main board) to set the voltage output and the current limit. For each channel the output voltage and output current can be measured.
The system uses an Arduino Uno R3 to interface to the PC via USB and to the adc’s and dac’s in the system via SPI. The address decoding uses four devices HC154 (decoder 4 to 1-of 16) and an inverter. This part works.
The voltage references are issued by dac7562, one per each channel, operating in SPI mode 1. All dac channels operate and provide output voltage of 0-5V to the 1mV precision.
The output voltage and output current is measured using in each channel adc122s021cimm operating in SPI mode 3. There are 32 dac7562 and 32 adc122s021 on the same SPI bus.
Problem description
-
The regulator output voltage is measured at the adc122s021 pin 5 which is named IN1 in the data sheet. To address this pin I had to use the configuration for IN2 (see tables 2, 3, 4 in page 17 in the data sheet). I solved this problem in the Arduino software but it seems there is a typo in the data sheet. Please check.
-
The dacs work without problems. The problem is that some of the adcs work and some others not. I suspected there is an ESD issue and replaced some of the failing devices, only to get the same fail results. So I think something is working near some limit and for this I need your help. Following is some data:
Tfall(CS) to Tfall (CLK) = 1.55uS start of conversion
Trise = Tfall = 25nS CLK
Trise(CLK) to Trise(CS) = 5.9uS end of conversion
Fclock = 2MHz. Tests were performed also at 1MHz with the same results
Since SPI work in bytes I have to issue a reading twice to get all the 16bits. This produces a small interval between the requests = 5.9uS. During this time the clock remains at logic 1.
The following scope pics were issued with 1000mV dac output. The dac outputs were connected directly to the adc inputs to avoid problems related to the regulators. For this the code needed (5V reference) is 819dec = 333 hex. The adcs should output about the same value when reading the voltage. Following is a scope pic of a good channel.
Code = Vout/Vref * 4096 = 1V/5V * 4096 ≈ 819
The yellow trace is CS (chip select)
The green trace is the clock.
The blue trace is Data In (MOSI)
The red trace is Data Out (MISO)
Note the “1” in Data In as I presented in issue 1, above. The output code is 334hex = 820dec
Now is a bad channel
This channel shows an output code of 576dec = 240hex.
To read the data I look at the rising edges of the clock, also shown in the scope pics.
Some of the channels provide 0 value around 1.25V (Vref/4) and then from 1.3 - 1..5V the value is constant 1024dec = 400hex.
One of the devices has a similar behavior around 2.5V (Vref/2).
Following are the relevant schematics
The connection from the output of the dac to the input of the adc is in connector J1 (at the right) by shorting pins A4 (adc in) – A7 (dac out). The diodes and the resistors form a primitive ESD protection for the adc since the adc input (also the regulator output) is exposed to the external world.
To the right top is the address decoder, based on the HC154. One pair cover the dacs addressing and the other pair cover the adcs addressing. Two enable lines adcselb and dacselb enable the address decoder (and the corresponding device) after the address is set. The scheme was tested and works without any problem.
The inverters at the bottom was modified and is relevant to the dacs. They provided control to the CLR signal in the dac7562. The circuit was modified so there is no longer control and the dacs get a fixed “high” signal.
Following is the relevant code in the Arduino
This is the function that reads the adcs.
//--------------------------------------------------------------
int adcConvert(byte adChannel, byte address){ // 8 bit version
byte adDin;
if(adChannel == 1) //select adc channel
adDin = 0x08; //convert command channel 1
else
if(adChannel == 2)
adDin = 0x00; //convert command channel 2
selectAddress(address); //select adc address
SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE3));
digitalWrite(adcselb, LOW); //adc enable
int adDataHigh = SPI.transfer(adDin); // high byte data transfer
int adDataLow = SPI.transfer(0); // low byte data transfer
digitalWrite(adcselb, HIGH); //adc disable
SPI.endTransaction();
int adData = (adDataHigh << 8) + adDataLow;
return adData;
}
//-------------------------------------------------------------------------
At the starting of the function there is the addressing for IN1 or IN2 as reported above.
The function is called in a nested <for> loop which also prepares the data array to be send to the PC. The <for> loop is called once per second using the internal timer in the Arduino. This fills up the array adDataOut[192]. The data transmission also works.
// -----------------------------------------------
byte index =0;
for(address = 0; address < 32; address++){ // get data from all adc's for(adChannel = 1; adChannel <= 2; adChannel++){ // data into three consecutive bytes
adData = adcConvert(adChannel, address); // adc call
// adc chA = 1 - vout
// adc chB = 2 - currentmon
adDataOut[index] = (byte)(adData & 0x00FF); // adc low data 0x00 - 0xFF
index += 1;
adDataOut[index] = (byte)((adData & 0x0F00) >> 8); // adc high data 0x00 - 0x0F
index += 1;
adDataOut[index] = (byte)(address + (adChannel << 6));
// composite address 0bcc0aaaaa
index += 1;
}
}
// -----------------------------------------------------------------------------------------------------
Below is the window in the PC
Please look at channel 1. The voltage is set to 1 Volt (output settings). The reading in output readings is code, not voltage for debugging purposes. The value is 576 which is not good.
For channel 23 I get 820 which is a good value.
I hope you can help me. Thanks.
Mario Zajac



