Interfacing MCP41010 with 16F690 - Page 1
Forum section: electronics / general

author: TheTeacher
author_rank: Newbie
timestamp: November 06, 2014, 08:09:28 am
content: hi guysI'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 4000000unsigned 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=1SSPEN=0; // Disable port to allow configurationSSPM3 = 0; // F_OSC / 64SSPM2 = 0;SSPM1 = 1;SSPM0 = 0;CKP = 0;CKE = 0;SMP = 1;SSPEN=1; // EnableSPI_Write_Enable();SPI_CS = 0; // chip select=0WriteSPI(0x11); // writing the command byte to the potWriteSPI(0xFF); // writing the data byte to the pot.SPI_CS = 1; // chip select=1, to excute the commandSSPEN=0; // Disablewhile(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/OANSELH = 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;}

author: anachrocomputer
author_rank: Regular Contributor
timestamp: November 06, 2014, 09:34:48 am
content: 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).

author: TheTeacher
author_rank: Newbie
timestamp: November 06, 2014, 03:44:30 pm
content: 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.

author: dannyf
author_rank: Super Contributor
timestamp: November 06, 2014, 05:45:41 pm
content: 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

author: macboy
author_rank: Super Contributor
timestamp: November 07, 2014, 05:17:11 pm
content: Quote from: TheTeacher on November 06, 2014, 03:44:30 pmYour 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 16SPI clocktransitions. 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.

author: dannyf
author_rank: Super Contributor
timestamp: November 07, 2014, 05:56:08 pm
content: 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.

author: macboy
author_rank: Super Contributor
timestamp: November 07, 2014, 06:09:18 pm
content: Quote from: dannyf on November 07, 2014, 05:56:08 pmTheses lines:SSPM3 = 0; // F_OSC / 64SSPM2 = 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 causeat leastthe second byte to be clobbered by de-asserting CS too soon.

author: TheTeacher
author_rank: Newbie
timestamp: November 08, 2014, 12:40:53 pm
content: I followed the steps and it works! Thanks a lot guys

author: dannyf
author_rank: Super Contributor
timestamp: November 08, 2014, 12:48:10 pm
content: Here is your code, with minor cosmetic changes, looping around: