Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[PIC] SPI commands for PIC18F4550 with ADS1298 slave.

Status
Not open for further replies.

at89atbits

Member level 1
Joined
Sep 20, 2014
Messages
35
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
353
Hi,
I am trying to use PIC18F4550 to control the functions of ADS1298 ECG AFE.
I read the datasheet of ADS1298 and saw the various registers used for different operations.
However I am not able to figure out how the command is to be written in SPI.
I searched google for different SPI tutorials as well as sample ADS1298 codes but couldn't find anything helpful.
I can't figure out a format in which the instructions are to be written.
I understand question seems very much naive since I am a beginner at this.
Any help is sincerely appreciated :)
 

Step 1 is to make sure that the PIC SPI peripheral is working OK. Remember that the SPI is an exchange of values and that (even in 'master' more on that device) you should remember to read back the received values form the SSPBUF after each exchange (even if you do nothing with the value - it can prevent other problems later on).
The ADS1298 data sheet will give you the maximum SCK frequency that you can generate - you can go up to 20MHz BUT that will probably stretch the capabilities of the PIC. Not knowing your design requirements, typically a 2MHz SCK works well.
Also, remember to lower the \CS\ line (which you will need to connect to a port pin on the PIC) before you send the instruction byte and after you finish exchanging any data bytes that may be needed.
I wold recommend that you write a short function (or 2) that handles that part for you based on some parameters.
As for the format there are two possible answers. At the hardware level, the PIC can only send MSB first but that is what the chip is expecting anyway. Also, the data sheet tells you about the relationship between the SCK and data reading/availability with the CPOL and CPHA values. Unfortunately these are not terms that the PIC uses and so a little 'translation' is required. Looking at the ADS1298 data sheet it would appear that the data is sampled on the falling clock pulse and so setting the CKP, CPE and SMP bits to 0 in the MSSP should do the trick.
At the higher level (i.e. the values begin exchanged) you will need to read the data sheet and work out what it is you are trying to do. By the look of it, most of the 'instructions' to the chip are single values to do with the very basic operation of the device. There are only 2 instructions that have additional values and they are to read and write to one or more registers. As I've said above, that part should not be hard as long as you make sure that you complete the exchange of each value before starting the next and also keep the \CS\ line low for all values in the same command.
I really can't help you much with what you need to write to or read from the registers - for that you will just have to study thew data sheet and work out what your design has to achieve.
Susan
 
Thanks for the information
It really helped clear some concepts.

But what I was looking for was a sample code for SPI communication to register addresses or something of that sort.

I found one on this website: http://www.ermicro.com/blog/?p=1846

My doubt is here in the SPI_Write function, at the beginning of every data transfer even the slave ID is being specified.
Is this slave ID same as the device ID mentioned in ADS1298 datasheet or this is something else?
 

There's no device ID involved in SPI communication. The "slave ID" is a a specific MCP23S17 thing and actually designating a single bit in the first command byte. The term has been invented by the code author.
 
So when writing a code for ADS1298,
I should first send the register address in SSPBUF followed by the data to be written to the particular register right?
 

I am writing the code in C.
So how should the instruction be?
Like WREG = 0x4000;
or how?

Isn't SSPBUF to be used when writing the code here at all?
 

Remember that the ADS1298 is in a completely different chip to the PIC and the only way you have of communicating with it is via the SPI link. This is why I started off by suggesting that you make sure that the SPI peripheral in the PIC was set up correctly and you set up whatever functions you needed within the PIC s that you could exchange 1 or more bytes with the ADS1298.
Lets say that you want to read the ID register within the ADS1298. (I know you talked about writing but the principles are the same but a bit easier to test that you are getting a valid SPI exchange going.)
The data sheet (page 23) shows that the ID register has an address of 0x00 and is 8 bits long.
Looking further down (page 38) there is a list of all of the commands you can issue to the ADS1298 and near the bottom of the table is the RREG command which is ore fully explained on page 41. It tells you that the RREG command needs 2 bytes and how those bytes are formatted.
The first byte has the top 3 bits set to 0x20 and the bottom 5 bits set the address of the first register you want to access - in this case the ID register and so the bottom 5 bits are 0x00. OR those two values together (0x20 for the command and 0x00 for the starting register address = 0x20 in this case).
The next byte contains the number of registers you want to read "- 1". I this case you want to read a single register and so the 2nd byte will be 0x00.
Now, you need to send those command bytes to the ADS1298 and then also receive the reply. As you have requested the value of 1 register, you will need to exchange 3 values - the first 2 being the command the the 3rd being the register value.
Up above I suggested that you write a function to perform an single value exchange and also another function that would handle the \CS\ line (which tells the slave ship that you are talking to it). Now you can see why.
The complete set of actions you need to do to send the RREG and get back the vale are along the lines of:
- lower the \CS\ line to activate the ADS1298
- exchange the first command value and (in this case) you can ignore the returned value
- when the above exchange is complete, exchange the 2nd command value and also ignore the returned value
- now you need to send a dummy value (I'd use 0x00) so that the DS1298 will send back the value of the ID register which you can save somewhere
- raise the \CS\ line to tell the DS1298 that the command sequence has been completed.
- examine the ID value you have received
By making a function that is passed 2 buffers (of equal length) that are the values you want to send and those that you receive back, along with a value to say how many values are to be exchanged, you can do all of the above steps for any command sequence.
Susan
 
So how should the instruction be?
Like WREG = 0x4000;
or how?

Isn't SSPBUF to be used when writing the code here at all?
The data has to be written bytewise to SSPBUF, checking SSPSTAT bit for completion of transmission.
 

Remember that the ADS1298 is in a completely different chip to the PIC and the only way you have of communicating with it is via the SPI link. This is why I started off by suggesting that you make sure that the SPI peripheral in the PIC was set up correctly and you set up whatever functions you needed within the PIC s that you could exchange 1 or more bytes with the ADS1298.
Lets say that you want to read the ID register within the ADS1298. (I know you talked about writing but the principles are the same but a bit easier to test that you are getting a valid SPI exchange going.)
The data sheet (page 23) shows that the ID register has an address of 0x00 and is 8 bits long.
Looking further down (page 38) there is a list of all of the commands you can issue to the ADS1298 and near the bottom of the table is the RREG command which is ore fully explained on page 41. It tells you that the RREG command needs 2 bytes and how those bytes are formatted.
The first byte has the top 3 bits set to 0x20 and the bottom 5 bits set the address of the first register you want to access - in this case the ID register and so the bottom 5 bits are 0x00. OR those two values together (0x20 for the command and 0x00 for the starting register address = 0x20 in this case).
The next byte contains the number of registers you want to read "- 1". I this case you want to read a single register and so the 2nd byte will be 0x00.
Now, you need to send those command bytes to the ADS1298 and then also receive the reply. As you have requested the value of 1 register, you will need to exchange 3 values - the first 2 being the command the the 3rd being the register value.
Up above I suggested that you write a function to perform an single value exchange and also another function that would handle the \CS\ line (which tells the slave ship that you are talking to it). Now you can see why.
The complete set of actions you need to do to send the RREG and get back the vale are along the lines of:
- lower the \CS\ line to activate the ADS1298
- exchange the first command value and (in this case) you can ignore the returned value
- when the above exchange is complete, exchange the 2nd command value and also ignore the returned value
- now you need to send a dummy value (I'd use 0x00) so that the DS1298 will send back the value of the ID register which you can save somewhere
- raise the \CS\ line to tell the DS1298 that the command sequence has been completed.
- examine the ID value you have received
By making a function that is passed 2 buffers (of equal length) that are the values you want to send and those that you receive back, along with a value to say how many values are to be exchanged, you can do all of the above steps for any command sequence.
Susan


So you mean to say something of this sort right?
Is this code fine for accessing the registers of ADS1298



Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
void SPI_Write(unsigned char addr,unsigned char data)
{
  // Activate the SS SPI Select pin
  PORTAbits.RA5 = 0;
  // Send the address of the register to be accessed
  SSPBUF = (0x40|addr);
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
 
  // One register at a time
  SSPBUF = 0x00;
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
 
  // Write data
  SSPBUF = data;
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
 
  // CS pin is not active
  PORTAbits.RA5 = 1;
}
 
unsigned char SPI_Read(unsigned char addr)
{
  // Activate the SS SPI Select pin
  PORTAbits.RA5 = 0;
  // Send address of the register to be accessed
  SSPBUF = (0x20|addr);
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
 
  // One register at a time
  SSPBUF = 0x00;
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
 
  // Send dummy variable
  SSPBUF = 0x00;
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
 
 
  // CS pin is not active
  PORTAbits.RA5 = 1;
  return(SSPBUF);
 
}

 
Last edited by a moderator:


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void SPI_Write(unsigned char addr,unsigned char data)
{
  // Activate the SS SPI Select pin
  PORTAbits.RA5 = 0;
  // Send the address of the register to be accessed
  SSPBUF = (0x40|addr);
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
 
  // One register at a time
  SSPBUF = 0x00;
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
 
  // Write data
  SSPBUF = data;
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
 
  // CS pin is not active
  PORTAbits.RA5 = 1;
}

In principle, yes.
One thing: the general rule for any device that has both PORT and LAT registers is to "read from the PORT and write to the LAT" as this gets around a very nasty thing called the "read-modify-write" problem. Even though the hardware treats a write to the PORT and the LAT as the same thing (see figure 10-1 in the data sheet), the 'read' part still comes from different sources and is the root-cause of the problem.
I am not totally convinced that "SPI_Write" is a good name for your function as that name is often used by others as the low-level function I was talking about to perform a single SPI exchange. While you can call any function anything you like, in terms of readability and (later) re-working the code, perhaps something like 'Write_Single_ADS_Register" would be more descriptive.
Of course the bottom line is: if it works correctly in all circumstances then that is the final arbiter".
Susan
 
I am attaching my code alongwith
The problem I am encountering now is I am getting a warning: (358) illegal conversion of pointer to integer
for all the addresses that I have defined
And if I change that variable in the function to unsigned char* addr, then I get an error on the line
SSPBUF = (0x20|addr); since I am doing a binary OR for the address and 0x20.
How do I fix this?
Or should I ignore the warning?



Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/* 
 * File:   ecgcode1.c
 * Author: SONY
 *
 * Created on 4 January, 2015, 12:02 PM
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <sw_spi.h>
 
 
 
// CONFIGURATION BITS ON pg294 of PIC18F4550 datasheet
#pragma config USBDIV = 0; // USB clock source comes directly from the primary oscillator block with no postscale
#pragma config CPUDIV = 00; // Primary oscillator used directly for system clock (no postscaler)
#pragma config PLLDIV = 000;
#pragma config IESO = 0; // Oscillator Switchover mode disabled
#pragma config FCMEN = 0; // Fail-Safe Clock Monitor disabled
#pragma config FOSC = 0b1010; // 1010 = Internal oscillator, XT used by USB (INTXT)
#pragma config VREGEN = 1; // USB voltage regulator enabled
#pragma config BOR = 0; // Brown-out Reset disabled in hardware and software
#pragma config PWRT = 0; // PWRT disabled
#pragma config WDT = 0; // WDT disabled (control is placed on the SWDTEN bit)
#pragma config MCLRE = 1; // MCLR pin enabled, RE3 input pin disabled
#pragma config PBADEN = 0; // PORTB<4:0> pins are configured as digital I/O on Reset
// #pragma config PBADEN = 1; PORTB<4:0> pins are configured as analog input channels on Reset
#pragma config CCP2MX = 1; // 1 = CCP2 input/output is multiplexed with RC1; 0 = CCP2 input/output is multiplexed with RB3
#pragma config CONFIG4L = 0b11000000; // background debugger disabled, Dedicated ICPORT enabled, LVP disabled, stack overflow will not cause RESET,
#pragma config CONFIG5L = 0b00001111; // No code protection
#pragma config CONFIG5H = 0b11000000; // No code protection
#pragma config CONFIG6L = 0b00001111; // No write protection
#pragma config CONFIG6H = 0b11100000; // No write protection
#pragma config CONFIG7L = 0b00001111; // Not protected from table reads executed in other blocks
#pragma config CONFIG7H = 0b01000000; // Not protected from table reads executed in other blocks
 
 
 
#define _XTAL_FREQ 20000000
 
// Device Setting Read Only
 
// Global Setting across channels
#define CONFIG1 0x01h
#define CONFIG2 0x02h
#define CONFIG3 0x03h
#define LOFF 0x04h
 
// Channel specific settings
#define CH1SET 0x05h
#define CH2SET 0x06h
#define CH3SET 0x07h
#define CH4SET 0x08h
#define CH5SET 0x09h
#define CH6SET 0x0Ah
#define CH7SET 0x0Bh
#define CH8SET 0x0Ch
#define RLD_SENSP 0x0Dh
#define RLD_SENSN 0x0Eh
#define LOFF_SENSP 0x0Fh
#define LOFF_SENSN 0x10h
#define LOFF_FLIP 0x11h
 
//Lead Off Status Registers (Read Only)
#define LOFF_STATP 0x12h
#define LOFF_STATN 0x13h
 
//GPIO and other registers
#define GPIO 0x14h
#define PACE 0x15h
#define RESP 0x16h
#define CONFIG4 0x17h
#define WCT1 0x18h
#define WCT2 0x19h
 
#define DevID 0b10010010
 
// opcode commands
#define WAKEUP 0x02h
#define STANDBY 0x04h
#define RESETr 0x06h
#define START 0x08h
#define STOP 0x0Ah
#define RDATAC 0x10h
#define SDATAC 0x11h
#define RDATA 0x12h
 
void delay_millisec(unsigned int X);
void SPI_Write(unsigned char addr,unsigned char data);
unsigned char SPI_Read(unsigned char addr);
void OPCODE_Write(unsigned char code);
 
int main(void) {
 
    TRISD = 0x00; // port D configured as output
    LATD = 0x00; // all outputs set to 0;
 
    unsigned char ID = 0;
    SMP = 0b1; // Input data sampled at end of data output time
    CKE = 0b1; // Transmit occurs on transition from active to Idle clock state
 
    SSPEN = 0b1; // Enables serial port and configures SCK, SDO, SDI and SS as serial port pins
    CKP = 0b0; // Idle state for clock is a low level
    SSPM3 = 0b0; // SPI Master mode, clock = FOSC/4 USE FOSC = 8MHz
    SSPM2 = 0b0;
    SSPM1 = 0b0;
    SSPM0 = 0b0;
 
    delay_millisec(820);
    OPCODE_Write("RESETr");
    __delay_us(9);
 
    OPCODE_Write("SDATAC");
    __delay_us(2);
 
    SPI_Write("CONFIG3", 0xC0);
    SPI_Write("CONFIG1", 0x86);
    SPI_Write("CONFIG2", 0x00);
    SPI_Write("CH1SET", 0x01);
    SPI_Write("CH2SET", 0x01);
    SPI_Write("CH3SET", 0x01);
    SPI_Write("CH4SET", 0x01);
    SPI_Write("CH5SET", 0x01);
    SPI_Write("CH6SET", 0x01);
    SPI_Write("CH7SET", 0x01);
    SPI_Write("CH8SET", 0x01);
 
 
    ID = SPI_Read(0x00);
    //LATD = ID;
 
 
    while (1)
    {
 
    //ID = SPI_Read(0x00);
    LATD = ID;
    }
    return (EXIT_SUCCESS);
}
 
 
void delay_millisec(unsigned int X)
{
 
    do
    {
        X--;
        __delay_ms(1);
    }
    while(X  > 0);
 
}
 
void SPI_Write(unsigned char addr,unsigned char data)
{
  // Activate the SS SPI Select pin
  PORTAbits.RA5 = 0;
  // Send the address of the register to be accessed
  SSPBUF = (0x40|addr);
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
  // Delay of 4 tCLKs after every transfer. Refer pg40 of ads1298 datasheet
  __delay_us(2);
 
  // One register at a time
  SSPBUF = 0x00;
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
  // Delay of 4 tCLKs after every transfer. Refer pg40 of ads1298 datasheet
  __delay_us(2);
 
  // Write data
  SSPBUF = data;
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
  // Delay of 4 tCLKs after every transfer. Refer pg40 of ads1298 datasheet
  __delay_us(2);
 
  // CS pin is not active
  PORTAbits.RA5 = 1;
}
 
unsigned char SPI_Read(unsigned char addr)
{
  // Activate the SS SPI Select pin
  PORTAbits.RA5 = 0;
  //NOP;
  // Send address of the register to be accessed
  SSPBUF = (0x20|addr);
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
  // Delay of 4 tCLKs after every transfer. Refer pg40 of ads1298 datasheet
  __delay_us(2);
 
  // One register at a time
  SSPBUF = 0x00;
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
  // Delay of 4 tCLKs after every transfer. Refer pg40 of ads1298 datasheet
  __delay_us(2);
 
  // Send dummy variable
  SSPBUF = 0x00;
  // Delay of 8 tCLKs after every transfer
  __delay_us(4);
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
  // Delay of 4 tCLKs after every transfer. Refer pg40 of ads1298 datasheet
  __delay_us(2);
 
  // Delay of 4 tCLKs before CS goes high. Refer pg15 of ads1298 datasheet
  __delay_us(2);
 
 
  // CS pin is not active
  PORTAbits.RA5 = 1;
  //NOP;
  return(SSPBUF);
 
}
 
void OPCODE_Write(unsigned char code)
{
  // Activate the SS SPI Select pin
  PORTAbits.RA5 = 0;
  //NOP;
  // Send the OPCODE
  SSPBUF = code;
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
  // Delay of 4 tCLKs after every transfer. Refer pg40 of ads1298 datasheet
  __delay_us(2);
 
  // Delay of 4 tCLKs before CS goes high. Refer pg15 of ads1298 datasheet
  __delay_us(2);
 
  // CS pin is not active
  PORTAbits.RA5 = 1;
  //NOP;
}

 
Last edited by a moderator:

You should not ignore the warnings, because you are supplying a string instead of a char literal for addr.

Code:
SPI_Write("CONFIG3", 0xC0);
must be changed to
Code:
SPI_Write(CONFIG3, 0xC0);
 

You are STILL writing to the port - to avoid all sorts of hard-to-track-down problems (perhaps not now but anytime you use any other port A line) you should ALWAYS write to the LAT.
As a matter of interest, you have you written your own "delay_millisec" which is fair enough but why then not just pass the parameter to the "__delay_ms" function (or better yet just user the __delay_ms function directly)?
Finally, please get out of the habit of including the "stdio", "stdlib" and similar headers for embedded applications. While these might be 'standard' for PC and other larger systems, they are rarely useful for embedded systems except in some unusual situations. Also the "xc.h" should be the first include as it sets up everything that some of the other headers are expecting.
Susan
 

You are STILL writing to the port - to avoid all sorts of hard-to-track-down problems (perhaps not now but anytime you use any other port A line) you should ALWAYS write to the LAT.
As a matter of interest, you have you written your own "delay_millisec" which is fair enough but why then not just pass the parameter to the "__delay_ms" function (or better yet just user the __delay_ms function directly)?
Finally, please get out of the habit of including the "stdio", "stdlib" and similar headers for embedded applications. While these might be 'standard' for PC and other larger systems, they are rarely useful for embedded systems except in some unusual situations. Also the "xc.h" should be the first include as it sets up everything that some of the other headers are expecting.
Susan


Yes, thanks for pointing out the PORT -> LAT. I made those changes in the code.

I also removed the stdlib and stdio headers.

I am not using the __delay_ms() because if I give any delay above 40ms I get a "160: error: inline delay argument too large"

I tried testing the given code with ads1298.
But I am not getting the desired output.
All that the code is doing is trying to read the device ID and display it on portD pins of the PIC.
So I tried testing the portD pins of the PIC for the device ID which ideally should be 0b10010010 for a PAG package ADS1298 but no output is coming on any of the pins.

Where might the error be?
Is it in the SPI instructions due to illegal conversion of integer to pointer?

How do I fix this?

I am attaching my latest code for reference

Code:
/* 
 * File:   ecgcode1.c
 * Author: SONY
 *
 * Created on 4 January, 2015, 12:02 PM
 */

//#include <stdio.h>
//#include <stdlib.h>
#include <xc.h>
#include <sw_spi.h>



// CONFIGURATION BITS ON pg294 of PIC18F4550 datasheet
#pragma config USBDIV = 0; // USB clock source comes directly from the primary oscillator block with no postscale
#pragma config CPUDIV = 00; // Primary oscillator used directly for system clock (no postscaler)
#pragma config PLLDIV = 000;
#pragma config IESO = 0; // Oscillator Switchover mode disabled
#pragma config FCMEN = 0; // Fail-Safe Clock Monitor disabled
#pragma config FOSC = 0b1001; // Internal oscillator, CLKO function on RA6, EC used by USB (INTCKO)
#pragma config VREGEN = 1; // USB voltage regulator enabled
#pragma config BOR = 0; // Brown-out Reset disabled in hardware and software
#pragma config PWRT = 0; // PWRT disabled
#pragma config WDT = 0; // WDT disabled (control is placed on the SWDTEN bit)
#pragma config MCLRE = 1; // MCLR pin enabled, RE3 input pin disabled
#pragma config PBADEN = 0; // PORTB<4:0> pins are configured as digital I/O on Reset
// #pragma config PBADEN = 1; PORTB<4:0> pins are configured as analog input channels on Reset
#pragma config CCP2MX = 1; // 1 = CCP2 input/output is multiplexed with RC1; 0 = CCP2 input/output is multiplexed with RB3
#pragma config CONFIG4L = 0b11000000; // background debugger disabled, Dedicated ICPORT enabled, LVP disabled, stack overflow will not cause RESET,
#pragma config CONFIG5L = 0b00001111; // No code protection
#pragma config CONFIG5H = 0b11000000; // No code protection
#pragma config CONFIG6L = 0b00001111; // No write protection
#pragma config CONFIG6H = 0b11100000; // No write protection
#pragma config CONFIG7L = 0b00001111; // Not protected from table reads executed in other blocks
#pragma config CONFIG7H = 0b01000000; // Not protected from table reads executed in other blocks
//#pragma config OSCCON = 0b01111111; // 8MHz Internal Clock

/*
#pragma config FOSC = INTOSCIO_EC
#pragma config FCMEN = OFF                                 // OR this way
#pragma config BORV = 3
#pragma config WDT = OFF
#pragma config CPB = OFF
#pragma config CPD = OFF //- See more at: http://www.rakeshmondal.info/pic18f4550-tutorial-blinking-led#sthash.x41V8uJZ.dpuf
*/

#define _XTAL_FREQ 20000000

// Device Setting Read Only

// Global Setting across channels
#define CONFIG1 0x01h
#define CONFIG2 0x02h
#define CONFIG3 0x03h
#define LOFF 0x04h

// Channel specific settings
#define CH1SET 0x05h
#define CH2SET 0x06h
#define CH3SET 0x07h
#define CH4SET 0x08h
#define CH5SET 0x09h
#define CH6SET 0x0Ah
#define CH7SET 0x0Bh
#define CH8SET 0x0Ch
#define RLD_SENSP 0x0Dh
#define RLD_SENSN 0x0Eh
#define LOFF_SENSP 0x0Fh
#define LOFF_SENSN 0x10h
#define LOFF_FLIP 0x11h

//Lead Off Status Registers (Read Only)
#define LOFF_STATP 0x12h
#define LOFF_STATN 0x13h

//GPIO and other registers
#define GPIO 0x14h
#define PACE 0x15h
#define RESP 0x16h
#define CONFIG4 0x17h
#define WCT1 0x18h
#define WCT2 0x19h

#define DevID 0b10010010

// opcode commands
#define WAKEUP 0x02h
#define STANDBY 0x04h
#define RESETr 0x06h
#define START 0x08h
#define STOP 0x0Ah
#define RDATAC 0x10h
#define SDATAC 0x11h
#define RDATA 0x12h

void delay_millisec(unsigned int X);
void SPI_Write(unsigned char addr,unsigned char data);
unsigned char SPI_Read(unsigned char addr);
void OPCODE_Write(unsigned char* code);

int main(void) {

    OSCCON = 0b01111111;

    TRISD = 0x00; // port D configured as output
    LATD = 0x00; // all outputs set to 0;

    unsigned char ID = 0;
    SMP = 0b1; // Input data sampled at end of data output time
    CKE = 0b1; // Transmit occurs on transition from active to Idle clock state

    SSPEN = 0b1; // Enables serial port and configures SCK, SDO, SDI and SS as serial port pins
    CKP = 0b0; // Idle state for clock is a low level
    SSPM3 = 0b0; // SPI Master mode, clock = FOSC/4 USE FOSC = 8MHz
    SSPM2 = 0b0;
    SSPM1 = 0b0;
    SSPM0 = 0b0;

    delay_millisec(820);
    OPCODE_Write("RESETr");
    __delay_us(9);

    OPCODE_Write("SDATAC");
    __delay_us(2);

    SPI_Write("CONFIG3", 0xC0);
    SPI_Write("CONFIG1", 0x86);
    SPI_Write("CONFIG2", 0x00);
    SPI_Write("CH1SET", 0x01);
    SPI_Write("CH2SET", 0x01);
    SPI_Write("CH3SET", 0x01);
    SPI_Write("CH4SET", 0x01);
    SPI_Write("CH5SET", 0x01);
    SPI_Write("CH6SET", 0x01);
    SPI_Write("CH7SET", 0x01);
    SPI_Write("CH8SET", 0x01);


    ID = SPI_Read(0x00);
    //LATD = ID;


    while (1)
    {

    //ID = SPI_Read(0x00);
    LATD = ID;
    }
   // return (EXIT_SUCCESS);
}


void delay_millisec(unsigned int X)
{

    do
    {
        X--;
        __delay_ms(1);
    }
    while(X  > 0);

}

void SPI_Write(unsigned char addr,unsigned char data)
{
  // Activate the SS SPI Select pin
  LATAbits.LATA5 = 0;
  // Send the address of the register to be accessed
  SSPBUF = (0x40|addr);
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
  // Delay of 4 tCLKs after every transfer. Refer pg40 of ads1298 datasheet
  __delay_us(2);

  // One register at a time
  SSPBUF = 0x00;
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
  // Delay of 4 tCLKs after every transfer. Refer pg40 of ads1298 datasheet
  __delay_us(2);

  // Write data
  SSPBUF = data;
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
  // Delay of 4 tCLKs after every transfer. Refer pg40 of ads1298 datasheet
  __delay_us(2);

  // CS pin is not active
  LATAbits.LATA5 = 1;
}

unsigned char SPI_Read(unsigned char addr)
{
  // Activate the SS SPI Select pin
  LATAbits.LATA5 = 0;
  //NOP;
  // Send address of the register to be accessed
  SSPBUF = (0x20|addr);
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
  // Delay of 4 tCLKs after every transfer. Refer pg40 of ads1298 datasheet
  __delay_us(2);

  // One register at a time
  SSPBUF = 0x00;
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
  // Delay of 4 tCLKs after every transfer. Refer pg40 of ads1298 datasheet
  __delay_us(2);

  // Send dummy variable
  SSPBUF = 0x00;
  // Delay of 8 tCLKs after every transfer
  __delay_us(4);
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
  // Delay of 4 tCLKs after every transfer. Refer pg40 of ads1298 datasheet
  __delay_us(2);

  // Delay of 4 tCLKs before CS goes high. Refer pg15 of ads1298 datasheet
  __delay_us(2);


  // CS pin is not active
  LATAbits.LATA5 = 1;
  //NOP;
  return(SSPBUF);

}

void OPCODE_Write(unsigned char* code)
{
  // Activate the SS SPI Select pin
  LATAbits.LATA5 = 0;
  //NOP;
  // Send the OPCODE
  SSPBUF = code;
  // Wait for Data Transmit/Receipt complete
  while(!SSPSTATbits.BF);
  // Delay of 4 tCLKs after every transfer. Refer pg40 of ads1298 datasheet
  __delay_us(2);

  // Delay of 4 tCLKs before CS goes high. Refer pg15 of ads1298 datasheet
  __delay_us(2);

  // CS pin is not active
  LATAbits.LATA5 = 1;
  //NOP;
}

I am getting the following warning on all the SPI read/write instructions.

illegal conversion of pointer to integer.png

- - - Updated - - -

I am getting a message on all the line : while (!SSPSTATbits.BF); saying "unable to resolve identifier BF". Are there any specific headers to be included for SPI?
Also I am getting a message on the line LATAbits.LATA5 = 0 which says "unable to resolve identifier LATA5".

Am I missing something in the code?
 
Last edited:

I wonder if you read replies to your thread? That's just B.S.
Code:
SPI_Write("CONFIG3", 0xC0);
...
 

Disable ADC and Comparator on PORTA and also ADC on other PORTS used for SPI communication with ADS1298. All the pins used for SPI communications should be digital IOs.
 

Yes I tried changing "CONFIG3" to CONFIG3.
But it gave the following errors:
ecgcode1.c:127: error: (195) expression syntax
ecgcode1.c:127: error: (187) too few function arguments
ecgcode1.c:127: error: (194) ")" expected
ecgcode1.c:127: error: (195) expression syntax

- - - Updated - - -

I wonder if you read replies to your thread? That's just B.S.
Code:
SPI_Write("CONFIG3", 0xC0);
...


Yes I tried changing "CONFIG3" to CONFIG3.
But it gave the following errors:
ecgcode1.c:127: error: (195) expression syntax
ecgcode1.c:127: error: (187) too few function arguments
ecgcode1.c:127: error: (194) ")" expected
ecgcode1.c:127: error: (195) expression syntax

- - - Updated - - -

I wonder if you read replies to your thread? That's just B.S.
Code:
SPI_Write("CONFIG3", 0xC0);
...


Yes I tried changing "CONFIG3" to CONFIG3.
But it gave the following errors:
ecgcode1.c:127: error: (195) expression syntax
ecgcode1.c:127: error: (187) too few function arguments
ecgcode1.c:127: error: (194) ")" expected
ecgcode1.c:127: error: (195) expression syntax
 

Zip and post your complete MPLAB X project files.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top