at89atbits
Member level 1
- Joined
- Sep 20, 2014
- Messages
- 35
- Helped
- 0
- Reputation
- 0
- Reaction score
- 0
- Trophy points
- 6
- Activity points
- 353
The data has to be written bytewise to SSPBUF, checking SSPSTAT bit for completion of transmission.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
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); }
In principle, yes.
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; }
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; }
SPI_Write("CONFIG3", 0xC0);
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
/*
* 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;
}
SPI_Write("CONFIG3", 0xC0);
...
I wonder if you read replies to your thread? That's just B.S.
Code:SPI_Write("CONFIG3", 0xC0); ...
I wonder if you read replies to your thread? That's just B.S.
Code:SPI_Write("CONFIG3", 0xC0); ...
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?