Reputation: 71
I am trying to configure a PIC24FJ512GA610 to use SPI to interface with an ADC module. As such, I am configuring it in two-wire mode (only SCK and SDI, CS controlled by ports). Below is the relevant code I am using to configure the SPI. A header file contains most definitions:
// SPI3 is used to read from 22-bit ADC tied to RTDs
// SPI3CON1L
#define SPI3EN 0<<15 // SPI Enable Pin
// unimplemented
#define SPI3SIDL 0<<13 // Stop when CPU is in idle mode
#define SPI3DSSDO 1<<12 // Disable SDO (no data sent to ADC module)
#define SPI3MODE1 0<<11 // Data mode: (0,0) transmits 8-bits
#define SPI3MODE0 0<<10 //
#define SPI3SMP 1<<9 // Sampling phase: samples at the end of output data time
#define SPI3CKE 0<<8 // Transmits on transition from idle to active
#define SPI3SSEN 0<<7 // only used in slave mode
#define SPI3CKP 0<<6 // clock idle state is low, active state is high
#define SPI3MSTEN 1<<5 // Master mode enabled
#define SPI3DISSDI 0<<4 // Disable SDI (no data received the board))
#define SPI3DISSCK 0<<3
#define SPI3MCLKEN 1<<2
#define SPI3SPIFE 0<<1
#define SPI3ENHBUF 0<<0
#define SPI3CON1L_MASK (SPI3EN | SPI3SIDL | SPI3DSSDO | SPI3MODE1 | SPI3MODE0 | SPI3SMP |\
SPI3CKE | SPI3SSEN | SPI3CKP | SPI3MSTEN | SPI3DISSDI | SPI3DISSCK | SPI3MCLKEN |\
SPI3SPIFE | SPI3ENHBUF )
// SPI3CON1H
#define AUDEN3 0<<15 // Audio codec enable
#define SPI3SGNEXT 0<<14 // Sign Extend Enable
#define IGNROV3 0<<13 // Ignore Receive Overflow
#define IGNTUR3 0<<12 // Ignore Transmit Underrun
#define AUDMONO3 0<<11 // Audio data format
#define URDTEN3 0<<10 // Transmit underrun data enable
#define AUDMOD31 0<<9 // Audio protocol mode select
#define AUDMOD30 0<<8 //
#define FRMEN3 1<<7 // Framed SPI support
#define FRMSYNC3 0<<6 // Frame sync pulse direction control
#define FRMPOL3 0<<5 // Frame sync/slave select polarity bit
#define MSSEN3 0<<4 // Master mode slave select enable
#define FRMSYPW3 0<<3 // Frame sync pulse width bit
#define FRMCNT32 0<<2 // Frame sync pulse counter bits
#define FRMCNT31 0<<1 //
#define FRMCNT30 0<<0 //
#define SPI3CON1H_MASK (AUDEN3 | SPI3SGNEXT | IGNROV3 | IGNTUR3 | AUDMONO3 | URDTEN3 | AUDMOD31 |\
AUDMOD30 | FRMEN3 | FRMSYNC3 | FRMPOL3 | MSSEN3 | FRMSYPW3 | FRMCNT32 |\
FRMCNT31 | FRMCNT30 )
The function that configures the SPI is found elsewhere:
void SPI3Init(void)
// SPI 3 is the thermocouple interface chip or
// the external adc interface for the cryostat
// **************************************
{
#if PROCESSOR == __PIC24FJ512GA610__
// Used for SPI communication to read RTDs through ADC
IEC3bits.SPI3RXIE = 0; // disable all SPI3 interrupts
IEC5bits.SPI3TXIE = 0;
IEC5bits.SPI3IE = 0;
SPI3BUFL = 0; // clear buffer
SPI3BUFH = 0;
OSCCONbits.IOLOCK = 0;
RPINR28bits.SDI3R = 30; // assign SPI3 SDI to pin 52 (RP30)
// RPINR28bits.SCK3R = 15; // assign SPI3 SCK to pin 53 (RP15)
RPOR7bits.RP15R = 24; // Set SCK pin to SPI3 SCK OUT (function 24)
RPOR8bits.RP16R = 23; // Map SDO to N/C pin 51 (function 23)
OSCCONbits.IOLOCK = 1;
SPI3CON1Lbits.SPIEN = 0; // disable the port
SPI3IMSKH = 0; // disable all interrupts
SPI3CON1L = 0; // disable SPI
SPI3CON1H = 0; // turn off AUDEN & FRMEN
SPI3BRGL = 832; // 3=16mhz / (2* (3+1)) = 2mhz, 7=16/2(7+1) = 1mhz, 832 -> 9600 )
SPI3CON1L = SPI3CON1L_MASK; // Write config masks
SPI3CON1H = SPI3CON1H_MASK;
SPI3CON2L = 7; // 8 bit data
SPI3STATLbits.SPIROV = 0; // clear any overflow status
SPI3CON1Lbits.SPIEN = 1; // enable the port
SPI3BUFL = 0;
ADC_CS_HIGH;
ADC_CS_LOW;
ADC_CS_HIGH;
#endif
return;
}
Actually reading the ADC calls this function three times (one for each 8 bits of resolution)
unsigned char Read_SPI3()
{
unsigned char ioByte = 0;
if(SPI3STATLbits.SPIROV)
SPI3STATLbits.SPIROV = 0; // clear overflow
SPI3BUFL = ioByte; // CLK out data on falling edge
while(!SPI3STATLbits.SPIRBF)
;
ioByte = SPI3BUFL; // CLK in data on rising edge
return ioByte;
}
I have been going through my code for the last day or two and, after combing the internet, cannot figure out what I am doing wrong. Putting a scope on the SCK line indicates that the serial clock is not running. I have confirmed that the config bits are being successfully written. Can anybody tell me what might be wrong?
Upvotes: 0
Views: 1242
Reputation: 4288
With this:
RPOR7bits.RP15R = 24;
you are mapping your SCLK pin to RF8. But you had to switch this pin to an output with.
TRISFbits.TRISF8 = 0;
And you had to switch this pin to digital with
ANSELFbits.ANSELF8 = 0;
Same thing for the SDO pin.
And as @Dan already mentiones, you need a unlock/lock sequence for the PPS. Have aloo at page 163 in the datasheet
Upvotes: 1
Reputation: 1225
The statement you use to unlock the pin selector:
OSCCONbits.IOLOCK = 0;
Is not what Microchip requires.
Because all of the writable bits in the OSCCON register are "protected" a built in compiler extension command must be used to change them.
The command to unlock the PPS looks like this:
__builtin_write_OSCCONL(OSCCON & _OSCCON_IOLOCK_MASK);
The command to lock the PPS looks like this:
__builtin_write_OSCCONL(OSCCON | _OSCCON_IOLOCK_MASK);
Depending on how you have set the configuration words the PPS may be configured so it cannot be unlocked, and once locked it takes a power-on-reset for the PPS to become unlocked.
Upvotes: 0
Reputation: 755
A few thoughts:
Upvotes: 1