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

Help needed with SPI on MAX186 ADC

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



Joined: 14 Dec 2009
Posts: 33
Location: Wales

View user's profile Send private message

Help needed with SPI on MAX186 ADC
PostPosted: Fri Dec 18, 2009 10:35 am     Reply with quote

Hi, I'm trying to read a MAX186 ADC and so far the code talks to the
ADC (SDI, SDO, CLK present) but I only get zeros back when I read the ADC. I am using AI7 tied to 2.5V. I left the #INT_SPI declaration in for diagnostics but I dont think I need it.

Here is my code. Any comments appreciated.
Code:

//
//   Test routine for SPI clock
//
#include    <18F4620.h>

#define      SCL      PIN_C3
#define      SDI      PIN_C4
#define      SDO      PIN_C5
#define      CS0      PIN_D0
#define      CS1      PIN_D1
#define      CS2      PIN_D2

#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)

#fuses       HS, WDT, WDT128, NOPROTECT, NOLVP, BROWNOUT
#use       DELAY(CLOCK=20000000, RESTART_WDT)
#use       RS232(BAUD=115200, PARITY=N, XMIT=PIN_C0, BITS=8, RESTART_WDT, STREAM=DEBUG)
#use      SPI(MASTER, DI=SDI, DO=SDO, CLK=SCL, BAUD=2000000, BITS=8, STREAM=DEFAULT_SPI)
#use      FAST_IO(B)
#use      FAST_IO(D)

unsigned    width=0;
char        spi_lb;      //   8 bits data words on SPI
char       spi_hb;      //      
char      lb, hb;      //   8 bits data words on SPI
char       dummy;      //

#INT_SSP
void   ssp_handler()
{
disable_interrupts(GLOBAL);
clear_interrupt(INT_SSP);

fprintf(DEBUG, "\r\n Interrupt on SPI:   ");
delay_ms(200);
// spi_lbyte   =   SPI_XFER(DEFAULT_SPI, 0, 8);
// spi_hbyte   =   SPI_XFER(DEFAULT_SPI, 0, 8);
enable_interrupts(GLOBAL);
}

//*********************************************************
//   This section of comment details the required signals
//   for the MAX186
//   CS - This must go low before conversion and high after.
//   
//*********************************************************

void main ()
{
   unsigned    count=0;
   unsigned   adc_value;

   setup_adc_ports(NO_ANALOGS);
   setup_adc_ports(ADC_OFF);

   enable_interrupts(INT_SSP);
      enable_interrupts(GLOBAL);
   set_tris_d(0b00000000);            // Dont check the direction register - All outputs on PORT D!
   set_tris_a(0b00000000);            // Set for ALL outputs on PORT A

   output_high(CS0);               // This is the enable for the MAX186
   
   setup_spi(SPI_MASTER | SPI_MODE_3 ); //| SPI_CLK_DIV_16 );      //    | SPI_SS_DISABLED);
     
   fprintf(DEBUG, "\r\n+++++++++++++++++++++++++++++++++++++++++++++");
   fprintf(DEBUG, "\r\n+ MASTER SPI Open on PIC18F4620 - CPU Reset +");
   fprintf(DEBUG, "\r\n+++++++++++++++++++++++++++++++++++++++++++++");

   switch(restart_cause())
      {
      case WDT_TIMEOUT:
         {
         printf("\r\n*******************************************");
         printf("\r\n* Error: Watchdog timed out - CPU Reset ! *");
         printf("\r\n*******************************************");
         break;
         }
      case NORMAL_POWER_UP:
         {
         printf("\r\nPowering up for test on MAX186 with 18F4620.");
         break;
         }
      case WDT_FROM_SLEEP:
         {
         printf("\r\nAwoke from Sleep !");
         break;
         }
      }   setup_wdt(WDT_ON);   

//    This next line decides whether to call the routines for reading
//   back on SPI bus.

   while(TRUE)
      {
      fprintf(DEBUG, "\r\n +++ Requesting SPI data %u +++", count);
      output_low(CS0);            // Get ready for next conversion
      //   SPI_XFER(DEFAULT_SPI, 0xff);   //    Send control byte & trigger conversion on AI7
      fprintf(DEBUG, "\r\n Debug 1st SPI Write:");
      spi_write(0xff);   dummy = spi_read(0);
      delay_us(10);
      fprintf(DEBUG, "\r\n Debug 2nd SPI Write:");
      spi_write(0);      lb = spi_read(0);
      fprintf(DEBUG, "\r\n Debug 3rd SPI Write:");
      spi_write(0);      hb = spi_read(0);
      //   delay_us(20);
      output_high(CS0);            //  End of conversion here ...

      fprintf(DEBUG, "\r\n Data LB : %02x HB : %02x", lb, hb);

      //   SPI_XFER(DEFAULT_SPI, 0x00);   //   Send second byte   
      //   SPI_XFER(DEFAULT_SPI, 0x00);   //   Send third byte and wait for data
      //   lb      =   SPI_XFER(DEFAULT_SPI, 0);
      //   hb      =   SPI_XFER(DEFAULT_SPI, 0);
      delay_ms(20);               //  Leave on just long enought to see LED.
      //   output_high(CS0);
      delay_ms(100);
      restart_wdt();
      //
      // if (spi_data_us_in())
      //   fprintf(DEBUG, "\r\n SPI Data Found");   
      //   spi_xfer(DEFAULT_SPI, 0xf10f, 16);
      //   spi_xfer(DEFAULT_SPI, 0xff0f, 16);
      //
      fprintf(DEBUG, "\r\n Outputting SPI Clock ? : (%u retries) ", count++);
      //   count++;
      }
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Dec 18, 2009 10:51 am     Reply with quote

Quote:
#INT_SSP
void ssp_handler()
{
disable_interrupts(GLOBAL);
clear_interrupt(INT_SSP);

fprintf(DEBUG, "\r\n Interrupt on SPI: ");
delay_ms(200);
// spi_lbyte = SPI_XFER(DEFAULT_SPI, 0, 8);
// spi_hbyte = SPI_XFER(DEFAULT_SPI, 0, 8);
enable_interrupts(GLOBAL);
}

Did you read the reply to your previous thread ? Did you read the
warnings ? Here is your thread:
http://www.ccsinfo.com/forum/viewtopic.php?t=40998


The 2nd thing is that your code is incredibly complicated for a
simple driver test program for the MAX186. You have a lot
of "chaff" in your program, such as "commented out" statements
for spi_xfer(). These just clutter up your program and make it
hard to read.

You have lots of restart_cause() in there. You should not be
getting watchdog timeouts in a test program.
ac34856



Joined: 14 Dec 2009
Posts: 33
Location: Wales

View user's profile Send private message

PostPosted: Fri Dec 18, 2009 11:00 am     Reply with quote

Apology, I just saw the previous thread. Many thanks.

Thanks for the comments in particular, these things are
quite obvious when someone explains them, but take
a little practice.

Rob
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Dec 18, 2009 11:08 am     Reply with quote

Also there is no need for #int_ssp interrupts in a driver for the MAX186.
All of this code should be removed:
Quote:
#INT_SSP
void ssp_handler()
{
disable_interrupts(GLOBAL);
clear_interrupt(INT_SSP);

fprintf(DEBUG, "\r\n Interrupt on SPI: ");
delay_ms(200);
// spi_lbyte = SPI_XFER(DEFAULT_SPI, 0, 8);
// spi_hbyte = SPI_XFER(DEFAULT_SPI, 0, 8);
enable_interrupts(GLOBAL);
}


enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
Guest








PostPosted: Fri Dec 18, 2009 11:31 am     Reply with quote

Thanks again *all* for helping. Here is what I think should be the correct
code. I've run it in MODEs 0,1,2,3 and it also increments the control byte
to show if there is any effect. Still not working but any suggestions would
be welcome. Its a very simple IC (supposedly) but I can't see where its
going wrong.
Code:

// Skeleton program for reading SPI
//

#include <18F4620.h>
#fuses    HS,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use    DELAY(CLOCK=20000000)
#use   RS232(BAUD=115200, PARITY=N, XMIT=PIN_C0, BITS=8, RESTART_WDT, ERRORS)
#use    FAST_IO(D)

#define   CS0   PIN_D0

#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)

//===============================
main(void)
{
unsigned   counter=0;
char      dummy=0, control=0xff;
char      msb, lsb;

setup_spi(SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_16);
set_tris_d(0b00000000);

//   Comments:
//   If data length is 8 bits use spi_read(0) or spi_write(0xff);
//   If data length is different, define #use SPI and use instead
//   spi_xfer(stream, data, bits)

while(1)
     {
   output_low(CS0);      //   This is CS
   delay_ms(3);
      spi_write(control--);      //   This will give a duty cycle of 50%
   delay_us(10);         //    wait for EOC
   dummy   =   spi_read(0);
   // First read to get data MSB
   spi_write(0);      msb=spi_read(0);
   // Secnd read to get data LSB
   spi_write(0);      lsb=spi_read(0);
   printf("\r\n Count %u, Data read %02x %02x Control: %02x", counter++, lsb, msb, control);
   output_high(CS0);
   delay_ms(100);
     }
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Dec 18, 2009 2:13 pm     Reply with quote

Post a list of your external connections to the MAX186's pins.
It has 20 pins. Post what is connected to each pin. Especially
post the connections between the PIC pins and the MAX186 pins.

Just to save time, try using this sample program. I changed the
#use rs232() pins to use the Hardware UART on pins C6 and C7.
That's the standard way to do it. I also changed the baud rate
to 9600 just because that's normally what I use. Notice that
#fast io mode is not used. It's not necessary. I added comments
to explain what the code is doing. Notice how simple this code is.
Always try to write simple code. It's easier to understand.

Compare this code to Figure 9 (on page 13) of the Max186 data sheet.
You will see that the code follows the timing diagram in the data sheet.
http://datasheets.maxim-ic.com/en/ds/MAX186-MAX188.pdf

Code:

#include <18F4620.h>
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#define  MAX186_CS   PIN_D0

// Control Byte:  Ch.0, unipolar, single-ended, internal clock
#define MAX186_CTRL_BYTE  0x8E

#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)

// Always read channel 0.
int16 read_max186(void)
{
int8 lsb, msb;
int16 retval;

// Send control byte to start the conversion.
output_low(MAX186_CS);   
spi_write(MAX186_CTRL_BYTE);
output_high(MAX186_CS);   

// Allow time for the conversion to occur.
// Data sheet says 10us max, so wait 15us to be safe.
delay_us(15); 

// Now read two bytes of the A/D result.
output_low(MAX186_CS);   
msb=spi_read(0);
lsb=spi_read(0);
output_high(MAX186_CS);   
 
// Convert two bytes into a 16-bit word.
retval = make16(msb, lsb);

retval >>= 4;   // Right justify the 12-bit result

return(retval);
}

//===============================
main(void)
{
int16 result;

setup_spi(SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_16);

while(1)
  {
   result = read_max186();
   printf("%LX \n\r", result);
   delay_ms(500);   
  }

}
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