View previous topic :: View next topic |
Author |
Message |
khalis
Joined: 12 Feb 2009 Posts: 54
|
SPI problem (PIC18F252 + MAX6682) |
Posted: Thu Feb 12, 2009 9:38 pm |
|
|
Hi,
Recently I tried to interface the max6682 with pic(18F252) using spi mode. Unfortunately, what I can see on the desktop through the hyperterminal was just displayed ' 0 '. For information, I was trying to retrieve 10bit data from the max6682 and display it on PC.
The recent coding that I used as below:
Code: | #include <18F252.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, bits=8)
#byte PORTA = 5
#byte PORTB = 6
#byte PORTC = 7
void main()
{
byte incode;
setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_16);
while(1)
{
set_tris_c(0x90);
incode = spi_read(); // Read character from UART
printf( " Thermocouple Reading = %d ",incode); // Display it on
putc(13);
delay_ms(1000);
}
} |
|
|
|
Ttelmah Guest
|
|
Posted: Fri Feb 13, 2009 3:25 am |
|
|
Some comment:
First, though you are not using them, you have definitions for PORTA etc., that are _wrong_. The values you have are for a 16 chip, not a 18 chip. These need fixing.
Second, you are trying to operate the 6682, without using CS. You _need_ to connect the CS line. The 6682, actually outputs 11bit data, and then tri-states the output line. The way you read it with a chip (like the PIC), that only supports 8bit clocking for SPI, is to lower the CS line, perform two 8bit transfers, and then raise the CS line. If you put the result into a signed 16bit integer, and then divide it by 32, you get the ten bit result _and sign_ correctly presented.
The SPI bus for this chip, needs to have the clock idle low, and read the data on the rising edge of the clock pulse. In SPI 'mode numbers', this is Mode0_0. Pull the posted mode number conversions from here (I think it was Ckielstra who first posted these), and use them. You need:
SPI_L_TO_H | SPI_XMIT_L_TO_H
For this chip.
As currently written (without CS), you will only get one and a third bytes at the start, containing anything 'useful', after this, the bus will go idle, and the display will depend totally on whether the data line floats high or low.
Best Wishes |
|
|
khalis
Joined: 12 Feb 2009 Posts: 54
|
Need more explanations |
Posted: Fri Feb 13, 2009 7:15 pm |
|
|
Thank you for your advise but if you don't mind, could you give a simple coding for me to follow..i'm new in c programming..thanks.. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Feb 14, 2009 2:22 am |
|
|
Look at the code in this post. It has some of the things that Ttelmah
has mentioned. For example, it sets the Chip Select signal low while
the SPI read operations are in progress. It has an spi_write() line
which is not needed by the MAX6682 (and should be removed for your
code). It combines the two bytes with a make16() function. It does not
do the division by 32 which Ttelmah mentions. You need to add that.
You should read Ttelmah's post and look at the timing diagram on page 6 of the MAX6682 data sheet. Then try to write the code yourself.
It's better for you to learn by doing it that way.
http://www.ccsinfo.com/forum/viewtopic.php?t=27833&start=2 |
|
|
khalis
Joined: 12 Feb 2009 Posts: 54
|
|
Posted: Sat Feb 14, 2009 11:37 pm |
|
|
First of all...i would to thank for the reply..i finally understand to use write spi coding...this is my first trial using spi and i'm very excited today..the coding that i used as below...
Code: | #include <18F252.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, bits=8)
void main()
{
int8 lsb;
int8 msb;
int16 result1;
set_tris_c(0b10110110);
output_high(PIN_C0);
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);
while(1)
{
output_low(PIN_C0);
msb = spi_read(0x00);
lsb = spi_read(0x00);
output_high(PIN_C0);
result1 = make16(msb, lsb);
printf("Thermistor Value = %Lx\n\r", result1);
delay_ms(1000);
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 15, 2009 12:29 am |
|
|
Quote: | setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64); |
Ttelmah said that you need to use SPI mode 0 with the MAX6682.
You should add these #define statements above main():
Code: | // SPI modes
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H) |
Then do your setup_spi() statement like this:
Code: | setup_spi(SPI_MASTER | [b]SPI_MODE_0[/b] | SPI_CLK_DIV_4);
|
According to the MAX6682 data sheet, the maximum SCLK frequency
is 5 MHz. 20 MHz / 4 = 5 Mhz. You don't need to divide by 64. Dividing
the crystal frequency by 4 will work. If you want to be conservative,
you can divided it by 16, and use SPI_CLK_DIV_16.
Quote: | set_tris_c(0b10110110); |
You don't need to set the TRIS. The compiler will set it for you, if you use
the CCS library code and CCS pin i/o statements (which you are doing).
You can delete this line.
Quote: |
result1 = make16(msb, lsb);
printf("Thermistor Value = %Lx\n\r", result1);
|
Ttelmah said that you should put the result in a signed int16 variable, and
then divide it by 32. So your code really should be changed to this:
Quote: |
signed int16 result1;
.
.
.
result1 = make16(msb, lsb);
printf("Thermistor Value = %Lx\n\r", result1 / 32);
|
|
|
|
khalis
Joined: 12 Feb 2009 Posts: 54
|
|
Posted: Sun Feb 15, 2009 12:56 am |
|
|
[SPI_MODE_0]
what does it means by the letter of 'b' in this code SPI_MODE_0 [/quote] |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 15, 2009 1:05 am |
|
|
That was supposed to put in it "bold" print. But, I put the line in
a Code block by mistake. Features such as bold and italics don't
work in code block. This is what I intended it to be:
Quote: | setup_spi(SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_4); |
|
|
|
khalis
Joined: 12 Feb 2009 Posts: 54
|
|
Posted: Sun Feb 15, 2009 1:31 am |
|
|
O..i see...one more thing, we know that output comes out on display is in hex value..is there a way to convert the value into decimal |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 15, 2009 2:17 am |
|
|
Quote: | Is there a way to convert the value into decimal ? |
Use "%Ld" instead of "%Lx". |
|
|
khalis
Joined: 12 Feb 2009 Posts: 54
|
|
Posted: Sun Feb 15, 2009 4:34 am |
|
|
I have tried the %Ld to display the result into decimal..and when i tried to multiply the decimal data with 0.125..the result became 0.. |
|
|
khalis
Joined: 12 Feb 2009 Posts: 54
|
|
Posted: Sun Feb 15, 2009 5:37 am |
|
|
Below the update coding that i made to display decimal
Code: | #include <18F252.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, bits=8)
// SPI modes
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
void main()
{
int8 lsb;
int8 msb;
signed int16 result1;
signed int16 result2;
output_high(PIN_C0);
setup_spi(SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_4);
while(1)
{
output_low(PIN_C0);
msb = spi_read(0x00);
lsb = spi_read(0x00);
output_high(PIN_C0);
result1 = make16(msb, lsb);
result2 = (result1 / 32)*125;
delay_ms(500);
printf("Thermistor Value Actual = %Ld Final(x120) = %Ld\n\r",result1,result2);
delay_ms(1000);
}
} |
|
|
|
khalis
Joined: 12 Feb 2009 Posts: 54
|
|
Posted: Sun Feb 15, 2009 5:43 am |
|
|
Is it possible to calculate and display the final result ex : 27.125 , 26.125? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 15, 2009 10:08 am |
|
|
Change the declaration of result2 to 'float', instead of signed int16.
Then change the 32 to a floating point value as shown below:
Quote: | result2 = (result1 / 32.0) * 125; |
Then use "%7.3f" in printf to display result2. |
|
|
Ttelmah Guest
|
|
Posted: Sun Feb 15, 2009 10:21 am |
|
|
Or, probably faster, and smaller, consider doing:
Code: |
signed int32 result2; //Make this large enough to store value * 3200
result2 = ((int32)result1 * 12500)/ 32;
|
Then use "%7.2w" to display result2.
This handles result2 as an int32 value, holding the required number * 100. Arithmetic for int32, is faster than floating point, typically perhaps 50% (and a lot faster for the division by 32), and uses CCS's ability to display this as a scaled value to give the required result.
As with most things, there are actually dozens of possible 'solutions'.
Best Wishes |
|
|
|