|
|
View previous topic :: View next topic |
Author |
Message |
peer9802
Joined: 26 May 2007 Posts: 14
|
USB demo board (PIC18F4550) with MAX6675 |
Posted: Tue Mar 06, 2012 10:16 pm |
|
|
Hello,
I'm having trouble getting a MAX6675 to work with my CCS USB demo board. I am continuously reading 0 from the chip. Is there anything obvious in my code? The LCD portion works fine. I can't use hardware SPI due to pin availablility.
The header file:
Code: | #include <18F4550.h>
#device ICD=TRUE
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES PLL5 //Divide By 5(20MHz oscillator input)
#FUSES CPUDIV1 //No System Clock Postscaler
#FUSES HSPLL //High Speed Crystal/Resonator with PLL enabled
#FUSES NOBROWNOUT //No brownout reset
//#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
//#FUSES DEBUG
#use delay(clock=48000000)
#USE SPI (MASTER, CLK=PIN_D3, DI=PIN_D0, ENABLE=PIN_D1, MODE=0, BITS=8, STREAM=SPI_1)
|
and the code file
Code: | #include <lcdTest.h>
//************************************************************************
//USB declarations here
#define USB_EP1_TX_ENABLE USB_ENABLE_INTERRUPT
#define USB_EP1_RX_ENABLE USB_ENABLE_INTERRUPT
#define USB_CONFIG_HID_TX_SIZE 8
#define USB_CONFIG_HID_RX_SIZE 8
#define USB_CONFIG_VID 0x0461
#define USB_CONFIG_PID 0x0F01
#include <pic18_usb.h> //Microchip PIC18Fxx5x hardware layer for usb.c
#include "usb_desc_hid_EP_FermTemp.h"
#include <usb.c> //handles usb setup tokens and get descriptor reports
//*************************************************************************
#define LCD_DB4 PIN_D4
#define LCD_DB5 PIN_D5
#define LCD_DB6 PIN_D6
#define LCD_DB7 PIN_D7
#define LCD_E PIN_D2
#define LCD_RS PIN_B0
//#define LCD_RW PIN_B0
#define MAX_CS PIN_D1
#define MAX_DO PIN_D0
#define MAX_CLK PIN_D3
#include "flex_lcd.c"
void init_temp()
{
output_low(MAX_CLK);
output_low(MAX_DO);
output_low(MAX_CS);
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
output_high(MAX_CS);
}
int16 read_temp()
{
BYTE datah, datal=0;
int16 data=0;
output_low(MAX_CS);
delay_cycles(1);
datah=SPI_READ(0);
datal=SPI_READ(0);
output_high(MAX_CS);
if( bit_test(datal,2))
{
bit_set(data,15);
return(data);
}
data = datah<<8;
data = data | datal;
return(data);
}
void main()
{
setup_timer_3(T3_DISABLED | T3_DIV_BY_1);
lcd_init();
float total = 0;
int i=0;
int16 value;
init_temp();
while(TRUE)
{
lcd_putc("\f");
lcd_gotoxy(1,1);
value = read_temp();
value = value>>3;
printf(lcd_putc, "%f\r\n",((float)value)*.25);
delay_ms(1000);
}
}
|
_________________ Eric |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Wed Mar 07, 2012 1:19 am |
|
|
One item that strikes immediately is you output_low(MAX_DO);
you want that pin to be input -- not an output.
delete that (PIC's power up as inputs typically) and then see if you read back *anything* ... then see if it's what you expect.
I've used the MAX6675 (which is being replaced with the MAX31855 by the way)... and it's pretty straightforward.
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
peer9802
Joined: 26 May 2007 Posts: 14
|
|
Posted: Wed Mar 07, 2012 7:09 am |
|
|
Thanks Ben,
I commented out the recommended line; however, I'm still not reading anything.
Yes, the MAX6675 should be straight-forward...
Updated code: Code: |
void init_temp()
{
output_low(MAX_CS);
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_XMIT_L_TO_H | SPI_CLK_DIV_16);
output_high(MAX_CS);
}
int16 read_temp()
{
BYTE datah, datal=0;
int16 data=0;
output_low(MAX_CS);
delay_cycles(1);
datah=SPI_READ(0);
datal=SPI_READ(0);
output_high(MAX_CS);
if( bit_test(datal,2))
{
bit_set(data,15);
return(data);
}
data = datah<<8;
data = data | datal;
return(data);
}
void main()
{
setup_timer_3(T3_DISABLED | T3_DIV_BY_1);
lcd_init();
init_temp();
float total = 0;
int i=0;
int16 value;
while(TRUE)
{
value = read_temp();
value = value>>3;
lcd_putc("\f");
lcd_gotoxy(1,1);
printf(lcd_putc, "Temp=%f\r\n",((float)value)*.25);
delay_ms(1000);
}
|
_________________ Eric |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Wed Mar 07, 2012 9:32 am |
|
|
peer9802 wrote: | Thanks Ben,
I commented out the recommended line; however, I'm still not reading anything.
|
At this point, the fastest path to finding what's going one would be to get a 2 channel scope (at least. 3 is better) and connect up to the CS, SCK and SDO lines.
p.s. there's that "output_low(CS)" before your SPI ini, you don't need that either.
Just set output_high for CS and output_low for SCK
Then do the SPI_Setup. _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D
Last edited by bkamen on Wed Mar 07, 2012 9:35 am; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Wed Mar 07, 2012 9:33 am |
|
|
Are you sure you want 'NOLVP' remmed out?. Unless you have a pull down resistor on RB5, this will stop the chip from running reliably....
Triple check the connections. The last person who had this behaviour had some form of wiring problem.
Best Wishes |
|
|
peer9802
Joined: 26 May 2007 Posts: 14
|
|
Posted: Wed Mar 07, 2012 2:25 pm |
|
|
Still nothing but I borrowed an o-scope from work. It looks like the CS line is dropping low as it should; however, I'm not getting anything on the CLK and DI lines. Could this be a SPI setup issue?
I've also disabled the LCD and am now printing all results to the Monitor window via my ICD. _________________ Eric |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Wed Mar 07, 2012 2:58 pm |
|
|
Ok, I compiled a "shorter" version of your code and then reviewed the datasheet -- which reminded me... and I'll show you:
Code: | CCS PCH C Compiler, Version 4.130, 61205 07-Mar-12 14:50
Filename: C:\DOCUME~1\bkamen\Desktop\test2\max6675.lst
ROM used: 196 bytes (1%)
Largest free fragment is 31740
RAM used: 7 (0%) at main() level
10 (0%) worst case
Stack: 1 locations
*
0000: GOTO MAIN
.................... #include <18F4550.h>
.................... //////// Standard Header file for the PIC18F4550 device ////////////////
.................... #device PIC18F4550
.................... #list
....................
.................... #device ICD=TRUE
.................... #device adc=16
....................
.................... #FUSES NOWDT //No Watch Dog Timer
.................... #FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
.................... #FUSES PLL5 //Divide By 5(20MHz oscillator input)
.................... #FUSES CPUDIV1 //No System Clock Postscaler
.................... #FUSES HSPLL //High Speed Crystal/Resonator with PLL enabled
.................... #FUSES NOBROWNOUT //No brownout reset
.................... //#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
.................... #FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
.................... //#FUSES DEBUG
....................
....................
.................... #use delay(clock=48000000)
*
005E: CLRF FSR0H
0060: MOVLW ??65535
0062: MOVWF FSR0L
0064: MOVF INDF0,W
0066: BZ 0084
0068: MOVLW 0F
006A: MOVWF @01
006C: CLRF @00
006E: DECFSZ @00,F
0070: BRA 006E
0072: DECFSZ @01,F
0074: BRA 006C
0076: MOVLW 8F
0078: MOVWF @00
007A: DECFSZ @00,F
007C: BRA 007A
007E: NOP
0080: DECFSZ INDF0,F
0082: BRA 0068
0084: GOTO 00BC (RETURN)
.................... #USE SPI (MASTER, CLK=PIN_D3, DI=PIN_D0, ENABLE=PIN_D1, MODE=0, BITS=8, STREAM=SPI_1)
.................... //#USE RS232 (UART1, BAUD=9600, BITS=8, ERRORS)
....................
.................... #define MAX_CS PIN_D1
.................... #define MAX_DO PIN_D0
.................... #define MAX_CLK PIN_D3
....................
.................... void init_temp() {
.................... output_low(MAX_CLK);
*
0004: BCF TRISD.TRISD3
0006: BCF LATD.LATD3
.................... output_high(MAX_CS);
0008: BCF TRISD.TRISD1
000A: BSF LATD.LATD1
.................... setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
000C: BCF SSPCON1.SSPEN
000E: BCF TRISC.RC7
0010: BSF TRISB.RB0
0012: BCF TRISB.RB1
0014: MOVLW 21
0016: MOVWF SSPCON1
0018: MOVLW 00
001A: MOVWF SSPSTAT
.................... }
001C: GOTO 00A8 (RETURN)
....................
.................... int16 read_temp() {
0020: CLRF datal
0022: CLRF data+1
0024: CLRF data
.................... BYTE datah, datal=0;
.................... int16 data=0;
....................
.................... output_low(MAX_CS);
0026: BCF TRISD.TRISD1
0028: BCF LATD.LATD1
.................... delay_cycles(1);
002A: NOP
.................... datah=SPI_READ(0);
002C: MOVF SSPBUF,W
002E: CLRF SSPBUF
0030: RRCF SSPSTAT,W
0032: BNC 0030
0034: MOVFF SSPBUF,datah
.................... datal=SPI_READ(0);
0038: MOVF SSPBUF,W
003A: CLRF SSPBUF
003C: RRCF SSPSTAT,W
003E: BNC 003C
0040: MOVFF SSPBUF,datal
.................... output_high(MAX_CS);
0044: BCF TRISD.TRISD1
0046: BSF LATD.LATD1
....................
.................... data = datah<<8;
0048: MOVFF datah,data+1
004C: CLRF data
.................... data = data | datal;
004E: MOVF datal,W
0050: IORWF data,F
....................
.................... return(data);
0052: MOVFF data,01
0056: MOVFF data+1,02
.................... }
005A: GOTO 00AA (RETURN)
....................
....................
.................... void main() {
*
0088: CLRF TBLPTRU
008A: BCF RCON.IPEN
008C: CLRF FSR0H
008E: CLRF FSR0L
0090: BSF TRISD.TRISD0
0092: BCF TRISD.TRISD3
0094: BCF LATD.LATD3
0096: BCF TRISD.TRISD1
0098: BCF LATD.LATD1
009A: MOVF ADCON1,W
009C: ANDLW C0
009E: IORLW 0F
00A0: MOVWF ADCON1
00A2: MOVLW 07
00A4: MOVWF CMCON
.................... int16 value;
.................... init_temp();
00A6: BRA 0004
....................
.................... while(TRUE) {
.................... value = read_temp();
00A8: BRA 0020
00AA: MOVFF 02,value+1
00AE: MOVFF 01,value
.................... // printf("0x%04X", value);
.................... delay_ms(1000);
00B2: MOVLW 04
00B4: MOVWF @@07
00B6: MOVLW FA
00B8: MOVWF ??65535
00BA: BRA 005E
00BC: DECFSZ @@07,F
00BE: BRA 00B6
.................... }
00C0: BRA 00A8
....................
.................... }
00C2: BRA 00C2
Configuration Fuses:
Word 1: 4E24 PLL5 CPUDIV1 USBDIV HSPLL FCMEN NOIESO
Word 2: 1A31 NOPUT NOBROWNOUT BORV27 VREGEN NOWDT WDT8192
Word 3: 8700 CCP2C1 PBADEN LPT1OSC MCLR
Word 4: 0000 NOSTVREN NOLVP ICSP1 NOXINST DEBUG
Word 5: C00F NOPROTECT NOCPB NOCPD
Word 6: E00F NOWRT NOWRTC NOWRTB NOWRTD
Word 7: 400F NOEBTR NOEBTRB
Some fuses have been forced to be compatible with the ICD debugger.
|
Look at the "setup_spi" line. Setup_spi only works with hardware SPI modules and you've designed your PIC so those pins are not available.
So if we take out "setup_spi" -- we also can't use "spi_write|read()"
We have to use spi_xfer. (#use spi and setup_spi() tend to be mutually exclusive (for simplistic purposes).
Try this code and let me know if it helps:
Code: | #include <18F4550.h>
#device ICD=TRUE
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES PLL5 //Divide By 5(20MHz oscillator input)
#FUSES CPUDIV1 //No System Clock Postscaler
#FUSES HSPLL //High Speed Crystal/Resonator with PLL enabled
#FUSES NOBROWNOUT //No brownout reset
//#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
//#FUSES DEBUG
#use delay(clock=48000000)
#USE SPI (MASTER, CLK=PIN_D3, DI=PIN_D0, ENABLE=PIN_D1, MODE=0, BITS=8) // don't need stream. Only one SPI stream in use.
//#USE RS232 (UART1, BAUD=9600, BITS=8, ERRORS)
#define MAX_CS PIN_D1
#define MAX_DO PIN_D0
#define MAX_CLK PIN_D3
int16 read_temp() {
BYTE datah, datal=0;
int16 data=0;
output_low(MAX_CS);
delay_cycles(1);
datah=SPI_xfer(0);
datal=SPI_xfer(0);
output_high(MAX_CS);
data = datah<<8;
data = data | datal;
return(data);
}
void main() {
int16 value;
while(TRUE) {
value = read_temp();
// printf("0x%04X", value);
delay_ms(1000);
}
} |
_________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 07, 2012 3:01 pm |
|
|
I noticed that bkamen just told you the truth while I was typing this all in.
I'll post mine anyway. I spent too much time typing it.
Quote: | I can't use hardware SPI due to pin availablility.
#USE SPI (MASTER, CLK=PIN_D3, DI=PIN_D0, ENABLE=PIN_D1, MODE=0, BITS=8, STREAM=SPI_1)
|
You have defined software SPI (Read only), using pins on Port D.
OK.
But then, in your routine below, you go ahead and setup the hardware
SPI pins. That's what setup_spi() does. It's a hardware only function.
And also, there's no reason to initially take MAX_CS low. It should be
initialized to the Inactive level.
Quote: |
void init_temp()
{
output_low(MAX_CLK);
output_low(MAX_DO);
output_low(MAX_CS);
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
output_high(MAX_CS);
} |
Then in your code, below and in various other places, you are using the
hardware spi_read() function ! You should be using spi_xfer().
That's the correct function to use with the #use spi() statement.
Quote: |
output_low(MAX_CS);
delay_cycles(1);
datah=SPI_READ(0);
datal=SPI_READ(0);
output_high(MAX_CS);
|
Also, delay_cycles() is not clock speed independent. An instruction cycle
is a lot less at 48 MHz (83 ns) than it is at 4 MHz (1 us). Ideally you
should use delay_us(1), or whatever delay amount is required.
Then furthermore, in your code above you are manually handling the CS
signal. But if you did write code to use the specified software SPI pins,
it will automatically handle the CS. That's because you specified it in the
#use spi() statement.
Another thing, in your #use spi() statement, you only set 'bits = 8'.
But the SPI transaction diagram in the MAX6675 data sheet shows 16 bits
per read operation, not 8. You should have specifed 'bits=16'. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Wed Mar 07, 2012 3:06 pm |
|
|
PCM programmer wrote: | Also, delay_cycles() is not clock speed independent. An instruction cycle
is a lot less at 48 MHz (83 ns) than it is at 4 MHz (1 us). Ideally you
should use delay_us(1), or whatever delay amount is required.
Then furthermore, in your code above you are manually handling the CS
signal. But if you did write code to use the specified software SPI pins,
it will automatically handle the CS. That's because you specified it in the
#use spi() statement.
|
Oopps. forgot to take those out because of this...
Quote: |
Another thing, in your #use spi() statement, you only set 'bits = 8'.
But the SPI transaction diagram in the MAX6675 data sheet shows 16 bits
per read operation, not 8. You should have specifed 'bits=16'. |
He could. Software SPI is nice that way.
I tend to leave it as 8-bits because it's important to note ALL SPI DEVICES can handle 8bit chunks, but it can sometimes be trouble setting the SPI master to a chunk size (we'll just call it that) that some single device can handle. 8bits is a nice "lowest common denominator".
But in this case, 16bits is fine too.
Thanks for the additional, PCM.
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
peer9802
Joined: 26 May 2007 Posts: 14
|
|
Posted: Wed Mar 07, 2012 5:44 pm |
|
|
Ha! Software vs. hardware setup was it! I guess this may be the downside of blindly copying max6675 code off a forum...
The numbers are a bit off but I'll chalk that up for calibration and being plugged into a breadboard. One oddity is I get slightly different results when I set BITS=8 and call SPI_xfer(0) twice versus setting BITS=16 and calling SPI_xfer(0) once. BITS=16 gives better results (more fidelity) for whatever reason--likely that is what's required based on the datasheet.
Thanks for your help!
Final code for reference
Code: |
#include <18F4550.h>
#device ICD=TRUE
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES PLL5 //Divide By 5(20MHz oscillator input)
#FUSES CPUDIV1 //No System Clock Postscaler
#FUSES HSPLL //High Speed Crystal/Resonator with PLL enabled
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES DEBUG
#use delay(clock=48000000)
#USE SPI (MASTER, CLK=PIN_D3, DI=PIN_D0, ENABLE=PIN_D1, MODE=0, BITS=16)
#use rs232(debugger)
#define LCD_DB4 PIN_D4
#define LCD_DB5 PIN_D5
#define LCD_DB6 PIN_D6
#define LCD_DB7 PIN_D7
#define LCD_E PIN_D2
#define LCD_RS PIN_B0
#define LCD_RW PIN_C1
#include "flex_lcd.c"
void main()
{
setup_timer_3(T3_DISABLED | T3_DIV_BY_1);
lcd_init();
int16 value;
while(TRUE)
{
value = SPI_xfer(0);
value = value>>3;
lcd_putc("\f");
lcd_gotoxy(1,1);
printf(lcd_putc, "Temp=%f\r\n",((float)value)*.25);
printf("Temp=%f\r\n",((float)value)*.25);
delay_ms(1000);
}
}
|
_________________ Eric |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Thu Mar 08, 2012 12:07 am |
|
|
peer9802 wrote: |
BITS=16 gives better results (more fidelity) for whatever reason--likely that is what's required based on the datasheet.
|
It shouldn't matter and you should find out why it does.
Good to hear you're working...
ALWAYS be suspect of code online.
Cheers,
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
|
|
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
|