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 CCS Technical Support

MCP3208 driver vs SPI Library functions
Goto page Previous  1, 2
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Mon Mar 29, 2021 3:11 am     Reply with quote

Nuclear__. I'm guessing that perhaps you are on a PIC24/30/33?. Only
thing that would explain your being able to print values above 255, without
using the l format.
If so, this could be the issue, since on these chips the default 'int' is signed
and 16bit. This could very easily be giving issues with how the code
places bits and combines them....
Now as an 'exercise' this morning, I decided to generate a driver that should
be compatible with all the PIC families, using #use spi, and supporting
the MCP 3204 & 8, both in single ended and differential mode.
Now, 'no guarantees', I've just written it from the data sheet.

main3208.c showing it setup, loaded and used
Code:

//Basic setup. Change to suit your PIC
#include <18F4520.h>
#device ADC=10

#FUSES NOWDT                    //No Watch Dog Timer

#use delay(crystal=20000000)

#use rs232(UART1, baud=9600,parity=N,stream=SERIAL, ERRORS)
//Simple UART for demo code

#use SPI(SPI1, baud=1000000, mode=0, BITS=8, stream=MCP32xx)
//setup the SPI. Can be a software or the hardware port as shown
//can go up to 2MHz at 5v, but 1MHz max for whole supply range
//can be mode0, or 3. Stream name must match for driver.

#define SINGLE_ENDED 1
#define DIFFERENTIAL 0
#define CH1NEG
//If in differential mode this will make CH1 the -ve input. REM out this
//definition to make CH1 the +ve input
#define MCP3208 //change to 3204 if this is the chip involved
#define MCP32xx_CS PIN_C0 //define the pin to use for CS - change for your hardware
#define MCP_IP SINGLE_ENDED //run inputs in single ended mode

#include "mcp32xx.h" //load the driver

void main()
{
   signed int16 data[CHANS]; //set up an array for the supported number of channels
   signed int16 single; //and a single value
   int counter;
   
   setup_adc_ports(NO_ANALOGS, VSS_VDD);
   MCP32xx_init(); //INIT the SPI

   while(TRUE)
   {
      //First demonstrate reading a single channel
      single=MCPread_chan(0); //returns chan 0
     
      fprintf(SERIAL,"Chan 0 is %ld\n", single);
     
      //now read all the channels
      MCPread_all(data);
     
      for (counter=0;counter<CHANS;counter++)
         fprintf(SERIAL,"Chan %d is %ld\n", counter, data[counter]);
      delay_ms(1000); //just delay to slow things down
   }
}


Then the mcp32xx.h driver code
Code:

//Driver for MCP3204/3208 using standard SPI functions

//work out how many channels are supported
#ifdef MCP3204
   #if MCP_IP==SINGLE_ENDED
     #define CHANS 4
   #else
     #define CHANS 2
   #endif
#else
   #if MCP_IP==SINGLE_ENDED
      #define CHANS 8
   #else
      #define CHANS 4
   #endif
#endif

void mcp32xx_init(void)
{
   //just ensure CS line is high
   output_high(MCP32XX_CS);
}

signed int16 MCPread_chan(int16 chan)
{
   //routine to read a single channel. Now on this chip, to give the correct
   //12 bit alignment, we have to send the top bit of the channel number
   //together with the SE/DIFF selection and a start as the bottom 3 bits of
   //the
   //first byte sent, then clock out the remaining two bits of the channel
   //two 'dummy' bits, then clock back the 12bit value (phew)...
   struct {
      unsigned int8 bytes[2];
      signed int16 word;
   } combiner, reply;
   if (MCP_IP==SINGLE_ENDED)
      combiner.word=chan*64; //Move the channel to the right location
      //compiler will optimise this to a rotation
   else
   {
      //Now if we are in differential mode, the channel number needs
      //to be doubled and combined with the bit for direction CH1NEG
      combiner.word=chan*128;
      #ifndef CH1NEG
        //if channel one is not negative need to set D0
        bit_set(combiner.byte[0], 6); //D0 bit set
      #endif
   }   
   if (MCP_IP==SINGLE_ENDED)
      bit_set(combiner.bytes[1],1); //set the SGL/DIFF bit
   bit_set(combiner.bytes[1],2); //set the start bit
   output_low(MCP32xx_CS); //start transaction
   //now need to clock the bytes out to the SPI port and read the reply
   //total of three bytes to send, and two reply bytes
   spi_xfer(MCP32xx, combiner.bytes[1], 8);
   reply.bytes[1]=spi_xfer(MCP32xx, combiner.bytes[0], 8);
   reply.bytes[0]=spi_xfer(MCP32xx, 0, 8); //dummy output byte for the reply
   output_high(MCP32xx_CS); //end transaction   
   reply.word &= 0xFFF; //mask just 12 bits
   #if MCP_IP==SINGLE_ENDED
     return reply.word;
   #else 
     //in differential mode, we need to sign extend if the reply is -ve
     if (bit_test(reply.bytes[1],3)
        reply.byte[1] |= 0xF0; //set top 4 bits if so
     return reply.word;
   #endif
}

void MCPread_all(signed int16 * chan_data)
{
   //read all the channels into chan_data array
   int ctr;
   for (ctr=0;ctr<CHANS;ctr++)
      chan_data[ctr]=MCPread_chan(ctr);
}
nuclear__



Joined: 24 Jan 2015
Posts: 63

View user's profile Send private message

PostPosted: Mon Mar 29, 2021 6:12 am     Reply with quote

wow ! nice morning task.
Before i check it i should mention that

I was misunderstood. I use pic18f47j53. I do use lu to print int16 . I mention that the first 3 variables that i printed, was not int16 but only the last one (for which i used lu).

Secondly mcp3208.c didn't work at all. I get 0 on all channel.

About vreference and circuit staff can't be the problem. My voltages are very solid, checked on oscilloscope. I have no load variation on 3.7 V line and the difference i see in adc reading can't be excused in any way unless my Vdd would drop from 3.7V to 2.5V . The pcb for the mcp3208 is really awful, made on pre-holed board, but again it can't be noise problem since i get the very same reading in each adc function calling. This pcb is separate from the main pic pcb which is printed and well designed.

I will come back with testing results!
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Mon Mar 29, 2021 6:44 am     Reply with quote

Are you using the hardware SPI pins?. B4,B5 & C7.
Seriously, there will be ripple on the supply. Not enough to explain this
problem, but when you think a 12bit ADC measures down to 0.9mV, you
will get some error from this. You need to switch the scope to AC
coupling, and set it's range up to perhaps 5mV/div, to actually see the
sort of noise that will affect the signal....

Separate PCB's. You have remembered to connect the grounds together.

If you look, you never actually post any code showing %l being used.
nuclear__



Joined: 24 Jan 2015
Posts: 63

View user's profile Send private message

PostPosted: Mon Mar 29, 2021 7:55 am     Reply with quote

Yes i use hardware spi
Code:
#use SPI (MASTER, DO = PIN_c7, DI = PIN_b5, CLK = PIN_B4, BITS = 8, Mode = 0)


Here is my v supply on main board and then on mcp board. They are ground coupled.

The same waveform i get when i use a loop that i get readings from spi (mcp) all the time.





For 9mv readings is not good but i actually need less than 8 bit resolution, so i will divide my reading with 16.

I will firstly try your code and if i get the same results i will go into pcb correction.

temtronic, the actual conversion is shown on the return value of file adc_io.c shown in Charlie U's post above. I hope i won't need an external reference, if so i will use a zener diode after the rest fail.
temtronic



Joined: 01 Jul 2010
Posts: 9225
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Mar 29, 2021 10:32 am     Reply with quote

That's a LOT of noise on VDD !!!
It should be perfectly 'flat' and NOT have those 'spikes'. You need to find out what's causing them( looks like some kind of clock ?) and ELIMINATE it.
nuclear__



Joined: 24 Jan 2015
Posts: 63

View user's profile Send private message

PostPosted: Mon Mar 29, 2021 12:03 pm     Reply with quote

temtronic wrote:
That's a LOT of noise on VDD !!!
It should be perfectly 'flat' and NOT have those 'spikes'. You need to find out what's causing them( looks like some kind of clock ?) and ELIMINATE it.


That's probably my step down converter . 5v->3.7v
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Mon Mar 29, 2021 12:09 pm     Reply with quote

Has it got the specified decoupling capacitor on it's output?.
They usually require a low ESR capacitor.
With the right capacitor there should only be a few uV of ripple.
nuclear__



Joined: 24 Jan 2015
Posts: 63

View user's profile Send private message

PostPosted: Tue Mar 30, 2021 5:25 am     Reply with quote

Yes it has, i added one more just in case. The more the better. However i noticed that probes were responsible for the noise too. Adding a small ceramic on the probe itself while measuring, things went better.

I tried your code without success. It must be my configurations problem , since mcp3208.h wasn't working either. i get 0 on both

Please don't bother if its not something eye catching for you.
I will probably use your code for testing in a new clean program.


Here are the most crucial parts of the code:

main.h
Code:
#include "18F47J53.h"
#device ADC=8
#BIT VBGEN=getenv("BIT:VBGEN")
#FUSES intrc_pll_io
#fuses HSPLL
#FUSES pll2
#FUSES pllen
//#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT2048                  //Watch Dog Timer uses 1:2048 Postscale
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES PROTECT                  //Code protected from reads
#FUSES SOSC_DIG                 //Digital mode, I/O port functionality of RC0 and RC1
#FUSES CLOCKOUT                 //Output clock on OSC2
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES IESO                     //Internal External Switch Over mode enabled
#FUSES DSWDTOSC_INT             //DSWDT uses INTRC as reference clock
#FUSES RTCOSC_INT               //RTCC uses Internal 31KHz Oscillator as reference source
#FUSES DSBOR                    //BOR enabled in Deep Sleep
#FUSES DSWDT                    //Deep Sleep Watchdog Timer enabled
//#FUSES DSWDT2147483648          //DSWDT uses 1:2147483648 Postscale
#FUSES NOIOL1WAY                //Allows multiple reconfigurations of peripheral pins
//#FUSES ADC10                    //ADC is 10-bits
#FUSES MSSPMSK7                 //MSSP uses 7 bit Masking mode
#FUSES WPFP                     //Write/Erase Protect Page Start/End Location, set to last page or use WPFP=x to set page
#FUSES WPCFG                    //Configuration Words page is erase/write-protected
#FUSES WPDIS                    //All Flash memory may be erased or written
#FUSES WPEND                    //Flash pages WPFP to Configuration Words page are write/erase protected
#use delay(internal=8MHz, clock=48MHz, restart_wdt, USB_FULL, act=USB)
//#use standard_io(D)
//#device CONST=ROM
#PIN_SELECT int1 = pin_b1
#pin_select U2TX = PIN_D4
#pin_select U2RX = PIN_D5
#define USB_CONFIG_BUS_POWER 500
#define dbg_printf(...) if(debug_on){printf(usb_cdc_putc,__VA_ARGS__);}
#define Status_led   PIN_c0
#define pwm_dim   PIN_a3
#define dis_4v1 pin_d6
#define USB_CABLE_IS_ATTACHED() input(PIN_D3)
#define but1 input(PIN_D2)
#define but2 input(PIN_C2)
#define but3 input(PIN_C1)
#define input_int_h input(PIN_B1)
#define PIN_DS18B20_DATA PIN_E2
#define DS1820_DATAPIN PIN_E2
#define DQ PIN_E2
#define ONE_WIRE_PIN PIN_E2
//---------spi
#define SINGLE_ENDED 1
#define DIFFERENTIAL 0
#define CH1NEG
//If in differential mode this will make CH1 the -ve input. REM out this
//definition to make CH1 the +ve input
#define MCP3208 //change to 3204 if this is the chip involved
#define MCP32xx_CS PIN_B7 //define the pin to use for CS - change for your hardware
#define MCP_IP SINGLE_ENDED //run inputs in single ended mode
//-------------
//#define SDA pin_d1
//#define SCL pin_d0
#define USE_TX_ISR
#use i2c(master,SDA =pin_d1,SCL =pin_d0,FAST=400)
//#use i2c(master, sda=EEPROM_SDA, scl=EEPROM_SCL, FAST=400)
#use SPI (MASTER, DO = PIN_c7, DI = PIN_b5, CLK = PIN_B4, BITS = 8, Mode = 0,stream=MCP32xx)
#use rs232(UART2,baud=38400,RECEIVE_BUFFER=250, TRANSMIT_BUFFER=256,parity=N,bits=8,xmit=PIN_D4,rcv=PIN_D5,stream=GSM,TXISR,restart_wdt,ERRORS) //xmit=PIN_D4,rcv=PIN_D5,
//#use SPI (FORCE_HW,SPI1, MASTER, BITS = 8, Mode = 0,stream=MCP32xx)


Commented out parts, have been tested alternatively without success.

main
Code:

void main()
{
   
   //delay_ms(5);
   setup_adc_ports(sAN6|sAN5|sAN4|sAN2);
   setup_adc(ADC_CLOCK_INTERNAL|ADC_TAD_MUL_0);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);  // 0.5 sec
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);      //262 ms overflow
   setup_timer_2(T2_DIV_BY_16,61,5);      //1,0 ms overflow, 5 ms interrupt
   //setup_timer_3(T3_INTERNAL | T3_DIV_BY_8);
   setup_rtc(RTC_ENABLE,127);
   //port_d_pullups(FALSE);
   delay_ms(1000);
   usb_init_cs();
   debug_on=0;
   lcd_init();
   delay_ms(1000);
   usb_task();
   clear_usb_buffer();
   enable_interrupts(int_timer0);
   disable_interrupts(int_timer1);
   enable_interrupts(int_timer2);
   disable_interrupts(int_timer3);
   enable_interrupts(INT_EXT1);
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);
   init_ext_eeprom();
   AM2320_init();
   VBGEN = TRUE;     
   output_low(dis_4v1);
   clear_usb_buffer();
   clear_ser_buffer();
   lcd_clear();
   init_vars();
   MCP32xx_init();

   //output_float(pin_d0);
   //output_float(pin_d1);
   
   while(TRUE)
   {
......


And here are the functions that i call with 2 buttons, one for adc_io and one for your mcp32xx:
Code:

void get_adcs()

   int8 ch;
   dbg_printf("\r\n");
   for(ch=0;ch<=7;ch++)
   {
      adc_ch16[ch] = read_ext_adc(ch);//read_analog(ch);
      dbg_printf("adc%u:%lu ",ch,adc_ch16[ch]);
   }
}

/*void get_adcs2() //uses mcp3208.h

   int8 ch;
   //adc_init();
   dbg_printf("\r\n");
   for(ch=0;ch<=7;++ch)
   {
      adc_ch16[ch] = read_analog( ch);//read_analog(ch);
      delay_us(100);
      dbg_printf("adc%u:%lu ",ch,adc_ch16[ch]);
   }
}*/

void get_adcs3()

   int8 ch;
   dbg_printf("\r\n");
   MCPread_all(data);
   for (ch=0;ch<8;ch++)
         //fprintf(SERIAL,"Chan %d is %ld\n", counter, data[counter]);
   dbg_printf("adc%d:%ld ",ch,data[ch]);
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Tue Mar 30, 2021 6:56 am     Reply with quote

No, these are not a case of the more the better. Most switch mode circuits
like these will oscillate if you have too much capacitance. The critical thing is
the layout of the board, and the ESR of the capacitor. In some cases there
are both upper and lower limits on this.
However it sounds as if this may be an RF pickup problem on the probes.

I would move the #use delay above the fuses and get rid of the PLL
fuse settings. The compiler does these automatically.
I would specify the clock rate in the #use spi. Your chip could clock the
SPI much too fast for the MCP chip to support....
nuclear__



Joined: 24 Jan 2015
Posts: 63

View user's profile Send private message

PostPosted: Tue Mar 30, 2021 12:34 pm     Reply with quote

Smile
I did your suggestions.
BAUD = 100000 Did the work !

adc_io works now. Still have problem with mcp32xx but feel more confident that the problem is on settings so i can focus on that.
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Tue Mar 30, 2021 11:38 pm     Reply with quote

A step forwards. Very Happy

You have done the settings as I show. MCP_IP set to single ended?.
Technically if this is set, the mcp code has to generate exactly the same
bit pattern for channel 0, that the adc_io code does. If you think about it
if this is set it sets bits 9, and 10 in the output (2, & 3 of the high byte),
and this gives a 16bit value 0f 0x0600, exactly the same as the adc_io
version. So it should work.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2
Page 2 of 2

 
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