CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

USB demo board (PIC18F4550) with MAX6675

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
peer9802



Joined: 26 May 2007
Posts: 14

View user's profile Send private message

USB demo board (PIC18F4550) with MAX6675
PostPosted: Tue Mar 06, 2012 10:16 pm     Reply with quote

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: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Wed Mar 07, 2012 1:19 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Mar 07, 2012 7:09 am     Reply with quote

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: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Wed Mar 07, 2012 9:32 am     Reply with quote

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: 19215

View user's profile Send private message

PostPosted: Wed Mar 07, 2012 9:33 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Mar 07, 2012 2:25 pm     Reply with quote

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: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Wed Mar 07, 2012 2:58 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Mar 07, 2012 3:01 pm     Reply with quote

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: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Wed Mar 07, 2012 3:06 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Mar 07, 2012 5:44 pm     Reply with quote

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: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Thu Mar 08, 2012 12:07 am     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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