SPI to control Analog tot Digital convertor

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
japus
Member
Posts: 14
Joined: Tue Oct 26, 2010 12:18 pm

SPI to control Analog tot Digital convertor

Post by japus »

Hello

I've got an Analog to Digital convertor so I can use my Sharp IR-sensor.
When I use an Arduino, the sensor works perfectly but the Analog to Digital convertor is giving me some problems.

I use the SPI library XMOS provides (https://www.xmos.com/applications/module/spi?ver=all).

First I enable the ADC by setting the CS pin high (as SPI requires) followed by the command to select Channel 0 on the ADC (it has 4). Then I read a short number that is shifted 4 bits to the right. (The ADC first sends 12 bits with the MSB first and then those 12 bits again with the LSB first. The 4 last bits are thus obsolete)

This is the information about the ADC, pages 19-20. http://ww1.microchip.com/downloads/en/D ... 21298e.pdf
It also gives some hints on how to use it when the microcontroller only allows blocks of 8 bit. I saw in the code that the port has an 8 bit buffer so I tried that method. It is specified on page 21.

The data always is 3112, 3128, 3140 or 3156. This doesn't seem right to me. Bringing an object in front of the sensor also has no inluence on the output. There is no pattern in the appearance of the 4 values, they are in random order.

This is my code:

Code: Select all

out port CS = XS1_PORT_1A; // 1 0 sturen voor activeren en 1 voor deactiveren

spi_master_interface spi_if = {
		XS1_CLKBLK_1,
		XS1_CLKBLK_2,
		XS1_PORT_1C,
		XS1_PORT_1D,
		XS1_PORT_1B};

int main() {
	spi_init(spi_if, 8);
	CS <: 1;

	while(1){
		CS <: 0;
		spi_out_byte(spi_if, 0b00000110);
		spi_out_byte(spi_if, 0b00000000);

		printintln(spi_in_short(spi_if));

		CS <: 1;
	}

	return 0;
}

I tried to follow the example that is included with the SPI library.

I have completely no idea what is wrong. I guess something with activating the right channel.

These things are quite popular, especially the IR-sensor so I hope someone can help me...

Thanks!

EDIT:
I've made a screenshot of the waveform analyzer in the simulator. It doesn't show the part I need, the data that is sent from the ADC but the signals I send look correct to me. They correspond to the drawings in the datasheet.
You do not have the required permissions to view the files attached to this post.


User avatar
boeserbaer
Active Member
Posts: 51
Joined: Fri Jan 29, 2010 4:36 pm

Post by boeserbaer »

Try the following pseudo code:

Code: Select all

// assumes singleEnded is true for "single ended"
// assumes chan is the channel 0 to 7;
unsigned char cmd = 0;
unsigned short val;

//start bit
cmd  |= (1 << 4);
// single ended/differential
if (singleEnded)
{
  cmd |= (1 << 3);
}
else
{
  cmd &= ~(1<<3);  // not strictly required as the s/d bit is inherently zero here
}
// set the channel bits
cmd &= (~0x07);  // again not strictly required
cmd |= (chan & 0x07);

CS <: 1;  // it is always a good idea to disable CS before any spi activity.  Initialization can sometimes toggle sclk.
spi_init(spi_if, 8);
CS <: 0;
spi_out_byte(spi_if, cmd);
val = (spi_in_short(spi_if) & 0x3f);
If val only runs 0 - 1/2 full scale, then try:
val = (spi_in_short(spi_if) >> 1) & 0x3f;

Regards Mike
User avatar
japus
Member
Posts: 14
Joined: Tue Oct 26, 2010 12:18 pm

Post by japus »

Thank you for the suggestion. Unfortunately it doesn't work.
Now I get values from 0 to 60 when they don't make any sense because of the fact below.

I've also dropped the sensor and replaced it with the 3.3V supply from the XMOS. That way I should always get the same value. When I attach the 5V supply, the result is more or less stable around 50-60.
When I attach it to the ground I get value 0, as it should be.
That's why I start to think there's something wrong with the convertor and not with the code.

I've also attached the updated waveform. It's the same as before, only the command is sent a few clock ticks faster.

Somehow I need to check the values that the ADC sends to the XMOS but I don't know how.

For completeness, this is what I made of your code:

Code: Select all

out port CS = XS1_PORT_1A;

spi_master_interface spi_if = {
		XS1_CLKBLK_1,
		XS1_CLKBLK_2,
		XS1_PORT_1C,
		XS1_PORT_1D,
		XS1_PORT_1B};

// assumes singleEnded is true for "single ended"
// assumes chan is the channel 0 to 7;
unsigned char cmd = 0;
unsigned short val;
unsigned char singleEnded = 1;

int main() {

	//start bit
	cmd |= (1 << 4);
	// single ended/differential
	if (singleEnded)
	{
		cmd |= (1 << 3);
	}
	else
	{
		cmd &= ~(1<<3); // not strictly required as the s/d bit is inherently zero here
	}
	// set the channel bits
	cmd &= (~0x07); // again not strictly required
	cmd |= (0 & 0x07); // chan = 0


	CS <: 1; // it is always a good idea to disable CS before any spi activity.  Initialization can sometimes toggle sclk.
	spi_init(spi_if, 8);
	while(1){
	CS <: 0;

	spi_out_byte(spi_if, cmd);
	val = (spi_in_short(spi_if) >> 1) & 0x3f;

	CS <: 1;
	
	printintln(val);
}

	return 0;
}

Oh and

Code: Select all

val = (spi_in_short(spi_if) & 0x3f);
and

Code: Select all

val = (spi_in_short(spi_if) >> 1) & 0x3f;
also give the same results

Thanks,

Jasper
You do not have the required permissions to view the files attached to this post.
User avatar
japus
Member
Posts: 14
Joined: Tue Oct 26, 2010 12:18 pm

Post by japus »

And then suddenly it works.

I searched the web for some examples and got some inspiration.
I changed

Code: Select all

val = (spi_in_short(spi_if) >> 1) & 0x3f;
to

Code: Select all

val = ((spi_in_short(spi_if)) >> 1) * 122 / 100;
On the web I found that the result that comes out of the ADC must be multiplied by 1.22 to get the supplied voltage in millivolts.

Now I get values that vary when I move an object closer and further from the sensor.
The only thing left is converting the voltage to a distance but that can't be too difficult as I've done that before.

Thanks for the help!

Jasper
User avatar
boeserbaer
Active Member
Posts: 51
Joined: Fri Jan 29, 2010 4:36 pm

Post by boeserbaer »

I think the removal of the 0x3f bit mask is more significant than the scaling. Try it without the scaling, and you will find you get nearly the same result (just without the scaling factor). Look at the SPI data sheet and try to figure out where the data is aligned. Is it left shifted? How much ?

Also be careful with the interface voltage levels. If you are messing about with different supplies, then I suggest input protection on all signals coming into the XMOS. An example is attached. The diodes should be schottkys such as BAT54, or if you don't have any around then use 1n4148 or similar small signal diodes.
clamp.JPG
Regards, Mike
You do not have the required permissions to view the files attached to this post.
User avatar
bsmithyman
Experienced Member
Posts: 126
Joined: Fri Feb 12, 2010 10:31 pm

Post by bsmithyman »

Hi japus,

Sorry I'm late to the party; we've moved apartments and Internet still isn't hooked up...
I actually already wrote a working library for the MCP3204/3208 ADC about a year and a half ago (I moved it over from xmoslinkers in September). It's in the projects list under MicroChip MCP3204/3208 ADC. I haven't had a chance to go through all your code yet, but if it helps feel free to use mine; I know it works. I never implemented differential sampling though, so if that's an issue you'd have to add the functionality.

Cheers,
Brendan
User avatar
japus
Member
Posts: 14
Joined: Tue Oct 26, 2010 12:18 pm

Post by japus »

Thank you bsmithyman for your code bit I got it working now. I will certainly try it out. I don't need the differential sampling. Your library actually looks a lot shorter and more straightforward than the one XMOS provides.
User avatar
bsmithyman
Experienced Member
Posts: 126
Joined: Fri Feb 12, 2010 10:31 pm

Post by bsmithyman »

japus wrote:Thank you bsmithyman for your code bit I got it working now. I will certainly try it out. I don't need the differential sampling. Your library actually looks a lot shorter and more straightforward than the one XMOS provides.
No worries, I hope it's useful :)

Just as a note: reading through some of the earlier posts, I noticed you're having some instabilities. These chips (the MCP3208 at any rate) seem to have some quirks if the power conditioning isn't really stable. Make sure you decouple the power supply well, very close to the chip. I think it's more of an issue when running the chip off of 5V0 and using the XMOS 3V3 I/O. This is especially true if you're running it off of one of the dev boards with cables of any length (I suspect it would be less of an issue on a custom PCB with a good ground plane). I was trying to embed it close to some sensors that draw a fair bit of current in a burst (ultrasound rangefinders), and it was really unstable until I gave them a better power supply.
User avatar
japus
Member
Posts: 14
Joined: Tue Oct 26, 2010 12:18 pm

Post by japus »

I've just finished my new implementation for the ADC and it works like a charm! I actually like it more than the XMOS implementation.
It has a few elements of both solutions. I took the technique to compse the command from boeserbaer and the sending from bsmithyman.
Thank you both for all the help!
When my project is finished I will put everything online. I guess that will be in about a month and a half.

Jasper