|
|
View previous topic :: View next topic |
Author |
Message |
ac34856
Joined: 14 Dec 2009 Posts: 33 Location: Wales
|
Help needed with SPI on MAX186 ADC |
Posted: Fri Dec 18, 2009 10:35 am |
|
|
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
|
|
Posted: Fri Dec 18, 2009 10:51 am |
|
|
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
|
|
Posted: Fri Dec 18, 2009 11:00 am |
|
|
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
|
|
Posted: Fri Dec 18, 2009 11:08 am |
|
|
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
|
|
Posted: Fri Dec 18, 2009 11:31 am |
|
|
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
|
|
Posted: Fri Dec 18, 2009 2:13 pm |
|
|
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);
}
} |
|
|
|
|
|
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
|