|
|
View previous topic :: View next topic |
Author |
Message |
Foppie
Joined: 16 Sep 2005 Posts: 138 Location: The Netherlands
|
code-error DAC MCP4922 |
Posted: Mon Nov 14, 2005 1:55 am |
|
|
Hello,
In my project I need to control a DAC MCP4922 with a PIC16F877A. I wrote the code to do it but found the following problem: when I sent data to the DAC, the output is always on DAC1. Even if I want it to be on DAC0. The output has the right voltage.
I have narrowed it down to the following function, but I cannot see what is the problem. Code: | #define DAC0 0 // VoutA
#define DAC1 1 // VoutB
void DAC_convert_long(short outputSelect, long data)
{
int upper, lower;
if (outputSelect == DAC0)
{
upper = 0b01100000;
}
else
{
upper = 0b11100000;
}
upper = upper | ((int)(data >> 6));
lower = (int)(data << 2);
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
output_low(CS_DAC);
delay_ms(1);
spi_write(upper);
spi_write(lower);
output_high(CS_DAC);
delay_ms(1);
output_low(DAC_LDAC);
delay_ms(1);
output_high(DAC_LDAC);
} | when I call this function, I do it like DAC_convert_long(DAC0, 700); or DAC_convert_long(DAC1, 350);
Any advice is appreciated. |
|
|
Ttelmah Guest
|
|
Posted: Mon Nov 14, 2005 6:04 am |
|
|
Try with SPI_H_TO_L.
If you look at the timing diagrams for a PIC SPI, the form where the data is sent while the clock is 'low', on the assumption that the chip at the other end reads it on the rising edge (which is what is illustrated for the MCP4922), has CKP=0, and CKE=1. The bit pattern to generate this on the SPI setup, is SPI_H_TO_L.
I suspect what is happening, is that the data is being output one clock late, so the chip always sees the '1', which is the second bit in the configuration data, as the first bit. It then select DOC1, and gets the gain set to '0', and loses the last bit of the data.
Best Wishes |
|
|
Foppie
Joined: 16 Sep 2005 Posts: 138 Location: The Netherlands
|
|
Posted: Mon Nov 14, 2005 6:45 am |
|
|
I tried with SPI_H_TO_L but no succes. The DAC doesn't work at all if I use it, not even DAC1. |
|
|
Foppie
Joined: 16 Sep 2005 Posts: 138 Location: The Netherlands
|
|
Posted: Tue Nov 15, 2005 1:58 am |
|
|
I also wrote a code for the AD5312 chip in the same manner, and that is working perfectly. So now I completely don't understand it anymore...
here's the code for a AD5312: Code: | #define DAC0 0 // VoutA
#define DAC1 1 // VoutB
void DAC_convert_long(short outputSelect, long data)
{
int upper, lower;
if (outputSelect == DAC0)
{
upper = 0b01000000;
}
else
{
upper = 0b11000000;
}
upper = upper | ((int)(data >> 6));
lower = (int)(data << 2);
setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_16);
delay_us(20);
output_low(CS_DAC); //SYNC input signal
delay_us(20);
//write upper nibble
spi_write(upper);
//write lower nibble
spi_write(lower);
output_low(DAC_LDAC);
output_high(CS_DAC);
//put value on line out
delay_us(20);
output_high(DAC_LDAC);
} |
|
|
|
Ttelmah Guest
|
|
Posted: Tue Nov 15, 2005 3:33 am |
|
|
Yes. The code looked fine (I had checked that the .lst generated put the right values in). I'd check what value is actually being put into the SSP config registers, and go and look at the two data sheets involved and see if there is something 'screwy'. Also perhaps check with a scope which way the data line idles (it should be idling low). It is some sort of 'silly' signalling fault I'm afraid....
Best Wishes |
|
|
Foppie
Joined: 16 Sep 2005 Posts: 138 Location: The Netherlands
|
|
Posted: Wed Nov 16, 2005 5:01 am |
|
|
I changed Code: | setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16); | into Code: | setup_spi(SPI_MASTER | SPI_CLK_DIV_16 | SPI_L_TO_H | SPI_SAMPLE_AT_END); | and now it works.
I didn't think it would be in my setup_spi because the DAC1 port was working correctly.
Many thanks Ttelmah |
|
|
Ttelmah Guest
|
|
Posted: Wed Nov 16, 2005 6:17 am |
|
|
Now I'll have to go an look at what effect 'sample at end', might have on data output!. I must admit, I wish that CCS, did their own nice table, showing which edge data would be sent on, sampled on etc., for their options. It should be obvious from the CCS data sheet, and the values, but it is hard work sometimes, to track through which bit a particular CCS function changes, and what the effect then is.
Now it gets odd. Sample at end, should only set bit 7 of the SSPSTAT register, which should not have any effect on data transmitted...
Aaargh!....
Checked the errata sheets for all versions of the 16F877A, and there is nothing here. I _hate_ this type of fault!...
Glad it now works anyway, I just wish I could see 'why'.
Best Wishes |
|
|
Foppie
Joined: 16 Sep 2005 Posts: 138 Location: The Netherlands
|
|
Posted: Wed Nov 16, 2005 7:00 am |
|
|
and now I feel really stupid
It seemed to work, but it only works once. The first value sent to the DAC is being put on the VoutA port, the rest of the values is on port VoutB. (I need to reset the PIC in order to get another value in VoutA)
The code that is sending looks as follows:
Code: | while(1)
{
DAC_convert_long(DAC0, ADC_read_long(ADC0));
delay_ms(100);
} |
I know for sure the right value is on the ADC0 input pin. That is something that does work!
I cannot seem to write any other value to VoutA after the first value is sent... Please help. |
|
|
Ttelmah Guest
|
|
Posted: Wed Nov 16, 2005 10:03 am |
|
|
Lets try something really 'radical'.
First, remove the SPI configuration from the subroutine. Configure it once when the chip wakes up.
Then, assuming the fault remains, try:
Code: |
#byte SSPBUF = 0x13
#byte SSPCON = 0x14
#byte I2CBUF = 0x93
#byte SSPSTAT = 0x94
#DEFINE READ_SSP() (SSPBUF)
#DEFINE WAIT_FOR_SSP() while((SSPSTAT & 1)==0)
#DEFINE WRITE_SSP(chr) SSPBUF=(chr)
#DEFINE CLEAR_WCOL() SSPCON=SSPCON & 0x3F
#define DAC0 0 // VoutA
#define DAC1 1 // VoutB
void DAC_convert_long(short outputSelect, long data) {
int upper, lower;
if (outputSelect == DAC0)
{
upper = 0b01100000;
}
else
{
upper = 0b11100000;
}
upper = upper | ((int)(data >> 6));
lower = (int)(data << 2);
output_low(CS_DAC);
//Note 1mSec, is a _long_ time - the chip needs 40nSec...
delay_cycles(1);
WRITE_SSP(upper);
WAIT_FOR_SSP();
WRITE_SSP(lower);
WAIT_FOR_SSP();
output_high(CS_DAC);
//Same comment applies
delay_cycles(1);
output_low(DAC_LDAC);
//Requires 400nSec for this signal only
delay_us(1);
output_high(DAC_LDAC);
}
|
Before using this, make sure you clear TRISC, 5 and 3 in the main.
If it still fails, then get rid of the setup_spi function, and instead write the setup values directly to the configuration registers.
At some point, hopefully it'll start working, and only one tiny fix will be needed...
Best Wishes |
|
|
Foppie
Joined: 16 Sep 2005 Posts: 138 Location: The Netherlands
|
|
Posted: Thu Nov 17, 2005 3:44 am |
|
|
Ttelmah wrote: | First, remove the SPI configuration from the subroutine. Configure it once when the chip wakes up. | I can't do this because I have another chip on the SPI connected, which requires another setup_spi. It's a max3100, not connected to a max232 chip, that can connect to a PC. But it is not connected. I'm pretty sure that is not a problem, because the only thing I do with the chip (on the moment) is configuring it, way before I do anything with the DAC.
That is why setup_spi is not on PIC wake up.
Ttelmah wrote: | Lets try something really 'radical'. | I'm starting with it now. I'll post as soon as I now more from testing. Thanks for your help so far! |
|
|
Ttelmah Guest
|
|
Posted: Thu Nov 17, 2005 5:14 am |
|
|
There is a potential problem present here. If you check the data sheets,the SPI clock line, needs to be low for a certain number of mSec, before the CS operates. If the other chip does not use the same default clock polarity, then it'd cause a problem selecting the DAC. Fortunately, the MAX31xx, does use the same polarity, so this should not be a problem.
You will have 'fun' with the Maxim chip though. The data sheets for this are wrong (the example C code given, does not actually work for data transmission, unless some incoming data arrives - I have a fixed set of code for the 31xx, which works).
Interestingly, I had almost exactly the same problems getting the code for the Maxim to work, as you are seeing. It was the register configuration, that 'fixed' it.
Code: |
#byte SSPCON = 0xFC6
#byte SSPSTAT = 0xFC7
#define SSPC_INIT 0x00
#bit SSPEN = SSPCON.5
#define SSPS_INIT 0x40
//setup_spi(SPI_MASTER|SPI_XMIT_L_TO_H|SPI_CLK_DIV_4);
SSPCON=SSPC_INIT;
SSPSTAT=SSPS_INIT;
SSPEN=1;
|
I switched from using the 'setup_spi' line given, to using the direct I/O shown above (also setting TRIS, not shown). The key difference, seems to be to not turn the SPI on, till after the setup values are written. The values sould function the same, but for me, the direct code worked, while the sandard setup didn't....
I'd suggest still getting rid of the setup_spi lines, and just toggling any bits that need to change to access the other chip.
Best Wishes |
|
|
Foppie
Joined: 16 Sep 2005 Posts: 138 Location: The Netherlands
|
|
Posted: Thu Nov 17, 2005 7:13 am |
|
|
Till now, your code gives the same result as mine, but I still have to replace the setup_spi() function...
Strange to hear that. i had totally no problem to program the MAX3100...
The code I use looks as follows:
Code: | void RS232_transmit(int data)
{
//define configuration byte
#define txUpper 0b10000010
//setup SPI
setup_spi(SPI_MASTER | SPI_CLK_DIV_16 | SPI_L_TO_H | SPI_SAMPLE_AT_END | SPI_XMIT_L_TO_H);
//send configuration byte and data
output_low(CS_RS232);
spi_write(txUpper);
spi_write(data);
output_high(CS_RS232);
//delay before sending next character
delay_us(981);
}
char RS232_receive()
{
//variable declaration
char data;
//setup SPI
setup_spi(SPI_MASTER | SPI_CLK_DIV_16 | SPI_L_TO_H | SPI_SAMPLE_AT_END | SPI_XMIT_L_TO_H);
//send 0x0000 and receive data
output_low(CS_RS232);
spi_write(0x00);
data = spi_read(0x00);
output_high(CS_RS232);
//return result
return data;
}
void RS232_config()
{
//define configuration bytes
#define configUpper 0b11000100
#define configLower 0b00001011
//setup SPI
setup_spi(SPI_MASTER | SPI_CLK_DIV_16 | SPI_L_TO_H | SPI_SAMPLE_AT_END | SPI_XMIT_L_TO_H);
//send configuration
output_low(CS_RS232);
spi_write(configUpper);
spi_write(configLower);
output_high(CS_RS232);
} |
I tested it extinsively, and it works good at 9600 baud. |
|
|
Ttelmah Guest
|
|
Posted: Thu Nov 17, 2005 7:47 am |
|
|
You seem to be polling the chip. I was using it interrupt driven, and what happens, is that when you send a character, it does not generate an interrupt, when the transmit buffer empties in certain circumstances. Their own 'example' code for it in interrupt driven mode, only works reliably, if some receive characters arrive, which then trigger an interrupt, and the waiting transmit characters get sent. Provided you have got incoming data, it will work, but if you want to send characters, with nothing arriving, you have to force an interrupt event to occur...
Best Wishes |
|
|
Prakash
Joined: 17 Sep 2010 Posts: 2 Location: Bangalore
|
|
Posted: Fri Sep 17, 2010 4:36 am |
|
|
Foppie wrote: | I also wrote a code for the AD5312 chip in the same manner, and that is working perfectly. So now I completely don't understand it anymore...
here's the code for a AD5312: Code: | #define DAC0 0 // VoutA
#define DAC1 1 // VoutB
void DAC_convert_long(short outputSelect, long data)
{
int upper, lower;
if (outputSelect == DAC0)
{
upper = 0b01000000;
}
else
{
upper = 0b11000000;
}
upper = upper | ((int)(data >> 6));
lower = (int)(data << 2);
setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_16);
delay_us(20);
output_low(CS_DAC); //SYNC input signal
delay_us(20);
//write upper nibble
spi_write(upper);
//write lower nibble
spi_write(lower);
output_low(DAC_LDAC);
output_high(CS_DAC);
//put value on line out
delay_us(20);
output_high(DAC_LDAC);
} |
|
I have ported this code with LPC2148 and its working fine from 0 to 3.3v:)
But I am using Vref as 5V.
For data 100, Vout I am getting is 0.3V and for 1023 Vout is 3.2V. But actually Vout should be 5V for 1023 data.
Kindly let me know what could be the possible issue. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Sep 17, 2010 7:05 am |
|
|
Quote: | But I am using Vref as 5V. | What is your Vdd voltage for the MCP4922? |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|