Author Topic: Interfacing MCP41010 with 16F690  (Read 3842 times)

0 Members and 1 Guest are viewing this topic.

Offline TheTeacher

  • Newbie
  • Posts: 3
Interfacing MCP41010 with 16F690
« on: November 06, 2014, 08:09:28 am »
hi guys

I'm a newbie. I'm having trouble programming the MCP41010 on Hi Tech C. The wiper is just always in the default halfway position. I'm trying to use the digipot in Rheostat Mode. I'm using MPLAB v8.43. The code is posted below.

Thanks in advance


#include <stdio.h>
#include <htc.h>

    __CONFIG(INTIO & WDTDIS & PWRTEN & BORDIS);

#define SPI_CS RC2                      // Setting RC2 (pin#17)of the PIC to be
#define SPI_SDO RC7
#define SPI_SCK RB6

#define _XTAL_FREQ 4000000

unsigned char dummy;
int x;

void WriteSPI(unsigned char data);
void SPI_Write_Enable(void);
void IO_Init(void);

void main()
{
   IO_Init();   
   SPI_CS = 1;                      // chip select=1


   SSPEN=0;                              // Disable port to allow configuration
   SSPM3 = 0;                        // F_OSC / 64
   SSPM2 = 0;
   SSPM1 = 1;
   SSPM0 = 0;

   CKP = 0;
   CKE = 0;
   SMP = 1;
   
   SSPEN=1;                               // Enable
   
   SPI_Write_Enable();

   SPI_CS = 0;                      // chip select=0

   WriteSPI(0x11);                   // writing the command byte to the pot
   WriteSPI(0xFF);                   // writing the data byte to the pot.
   
   SPI_CS = 1;                      // chip select=1, to excute the command

   SSPEN=0;                               // Disable

   while(1);
   {
   }

}

void SPI_Write_Enable(void)
{
   SPI_CS   =   0;
   SSPBUF = 0x06;
   while(BF==1)
   dummy=SSPBUF;
   SPI_CS = 1;
}

void WriteSPI(unsigned char data)
{   
   SSPBUF   =   data;          // write data to SPI Buffer (1 clock cycle)
   for(x=7; x>0; x--)         // delay 7 clock cycles
   {
   }
}

void IO_Init(void)
{
   ANSEL = 0x00;             // Set PORTC as Digital I/O
   ANSELH = 0x00;
   TRISC7 = 0;             // Set PORTC as Output(RC7 as output)
   TRISB6 = 0;             // Set RB4 as input and RB6 as output( SDI and SCK)
   TRISC2 = 0;                 //  Set RA2 as output (SS)   
   PORTB = 0x00;
   PORTC = 0x00;
}
 

Offline anachrocomputer

  • Regular Contributor
  • *
  • Posts: 64
  • Country: gb
Re: Interfacing MCP41010 with 16F690
« Reply #1 on: November 06, 2014, 09:34:48 am »
In your WriteSPI() function, your comments imply a 7-cycle delay by means of an empty for-loop. Now, this may work as intended, or it may get optimised away by the compiler. It's better to use a while-loop that tests the SPI ready (or done) bit. You'll need to find that bit in the microcontroller's registers.

Also, as  matter of style, the variable 'x' in that loop is a global. It's better to use local variables for loop counters like that, otherwise you can get into a muddle if you call functions within for-loops (as you develop more complex programs).
 

Offline TheTeacher

  • Newbie
  • Posts: 3
Re: Interfacing MCP41010 with 16F690
« Reply #2 on: November 06, 2014, 03:44:30 pm »
Thank you for your response:

According to the datasheet of the MCP41010, the write operation for both bytes must last 16 clock cycles. Forcing each WriteSPI() to last 8 cyles is an attempt at making the whole write operation last 16 clock cycles. Here is the relevant extract from the datasheet:

"Executing any command is accomplished by setting CS low and then clocking-in a command byte followed by a data byte into the 16-bit shift register. The command is executed when CS is raised. Data is clocked in on the rising edge of clock and out the SO pin on the falling edge of the clock (see Figure 5-1). The device will track the number of clocks (rising edges) while CS is low and will abort all commands if the number of clocks is not a multiple of 16."

Also, it seems only one flag is available to use as you suggested; it is the Buffer Full flag (BF). The problem is it can't be used in the first WriteSPI() since the SSPBUF won't be full yet.



 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Interfacing MCP41010 with 16F690
« Reply #3 on: November 06, 2014, 05:45:41 pm »
You should break it into two parts:

a, is the pic sending the right data? And b, is the mcp responding to the right data?

while the code isn't well steuctured, it does the job. The issue is outside of the pic
================================
https://dannyelectronics.wordpress.com/
 

Offline macboy

  • Super Contributor
  • ***
  • Posts: 2016
  • Country: ca
Re: Interfacing MCP41010 with 16F690
« Reply #4 on: November 07, 2014, 05:17:11 pm »
Thank you for your response:

According to the datasheet of the MCP41010, the write operation for both bytes must last 16 clock cycles. Forcing each WriteSPI() to last 8 cyles is an attempt at making the whole write operation last 16 clock cycles. Here is the relevant extract from the datasheet:

"Executing any command is accomplished by setting CS low and then clocking-in a command byte followed by a data byte into the 16-bit shift register. The command is executed when CS is raised. Data is clocked in on the rising edge of clock and out the SO pin on the falling edge of the clock (see Figure 5-1). The device will track the number of clocks (rising edges) while CS is low and will abort all commands if the number of clocks is not a multiple of 16."

Also, it seems only one flag is available to use as you suggested; it is the Buffer Full flag (BF). The problem is it can't be used in the first WriteSPI() since the SSPBUF won't be full yet.

Your code does not work because you call WriteSPI() a second time, without checking if the first transaction has completed beforehand. The second transaction clobbers the first. You also de-assert CS (set to 1) immediately upon returning from WriteSPI(), long before the byte has finished transferring.

You are also confused about what kind of "clock cycles" that are referred to in the data sheet. It means that each SPI transaction must contains 16 SPI clock transitions. This has nothing to do with the CPU clock per se. A fixed CPU clock delay is not useful.

What you need to do is:
1. assert CS,
2: send one byte (8 bits) over SPI,
3: wait for it to finish,
4: send the second byte (8 bits) over SPI,
5: WAIT for it to finish!!,
6: de-assert CS. Done.

Sending two bytes means 16 SPI clocks, and that fills the datasheet requirement you are looking at. It doesn't matter how much time elapses, as long as there are exactly 16 SPI clock transitions.


« Last Edit: November 07, 2014, 05:19:43 pm by macboy »
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Interfacing MCP41010 with 16F690
« Reply #5 on: November 07, 2014, 05:56:08 pm »
The code generally works - the transmission is buffered and if the speed is sufficiently fast, the looping at the end does the job.

A better approach is to test the buffer before loading the sspbuf register.
================================
https://dannyelectronics.wordpress.com/
 

Offline macboy

  • Super Contributor
  • ***
  • Posts: 2016
  • Country: ca
Re: Interfacing MCP41010 with 16F690
« Reply #6 on: November 07, 2014, 06:09:18 pm »
The code generally works - the transmission is buffered and if the speed is sufficiently fast, the looping at the end does the job.

A better approach is to test the buffer before loading the sspbuf register.
Theses lines:
   SSPM3 = 0;                        // F_OSC / 64
   SSPM2 = 0;
   SSPM1 = 1;
   SSPM0 = 0;

Set the SPI clock to 1/64 of Fosc. That is 1/16 of the CPU clock (CPU is 1/4 Fosc). Then a byte takes 128 CPU clock cycles to send. The 0-7 loop delay (assuming it isn't completely optimised out) is very likely not long enough, which will cause at least the second byte to be clobbered by de-asserting CS too soon.

« Last Edit: November 07, 2014, 07:08:41 pm by macboy »
 

Offline TheTeacher

  • Newbie
  • Posts: 3
Re: Interfacing MCP41010 with 16F690
« Reply #7 on: November 08, 2014, 12:40:53 pm »
I followed the steps and it works! Thanks a lot guys  :)
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Interfacing MCP41010 with 16F690
« Reply #8 on: November 08, 2014, 12:48:10 pm »
Here is your code, with minor cosmetic changes, looping around:

================================
https://dannyelectronics.wordpress.com/
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf