Cómo obtener datos de 10 bits de ADC usando el protocolo SPI

Estoy haciendo una implementación de esclavo múltiple maestro único.
Maestro - PIC18F4550
Esclavo - PIC18F4520

Un potenciómetro está conectado al Esclavo. El esclavo convertirá el valor del potenciómetro a digital y se comunicará con el maestro mediante el protocolo SPI.

Recibo datos de 8 bits (ADRESH - Justificado a la izquierda) correctamente del esclavo. Pero tengo que obtener datos de 10 bits (ADRESH - 8 bits, ADRESL - 2 bits).

¿Cómo puedo obtener datos de 10 bits?

Codigo maestro

OpenSPI(SPI_FOSC_64, MODE_01, SMPMID);   //SPI configuration

SSPCON1bits.WCOL = 0;    //Clearing SSPBUF
LATDbits.LATD0 = 0;  //Slave select
WriteSPI(0xFF);  //writing 0xFF to slave    
for(mdelay = 0; mdelay < 10; mdelay++); 
var1 = SSPBUF;
LATDbits.LATD0 = 1;
highbyte = var1;
highbyte = highbyte << 8;    //deselecting SS   
for(mdelay = 0; mdelay < 100; mdelay++);

SSPCON1bits.WCOL = 0;
LATDbits.LATD0 = 0;  //2nd time slave selct 
WriteSPI(0xAA);
for(mdelay = 0; mdelay < 10; mdelay++); 
var2 = SSPBUF;
LATDbits.LATD0 = 1;
lowbyte = var2;
for(mdelay = 0; mdelay < 100; mdelay++);

highbyte = highbyte | lowbyte;
result = highbyte;

Esclavo

int Count;
unsigned char ch1,ch2,data; 

ADCON0 = 0x01;   // AD Control Register 1: Enable (turn on ADC)
ADCON2 = 0x3C;   // AD Control Register 2: 20 TAD (accuracy), FOSC 4 (freq/4)
ADCON2bits.ADFM = 0;     // ADC result left justified (D10 - D2 --> ADRESH, D1 - D0 --> ADRESL) 

TRISCbits.TRISC3 = 1;    //SPI pins(PIC18F4520)
TRISCbits.TRISC4 = 1;   
TRISCbits.TRISC5 = 0;
TRISAbits.TRISA5 = 1;

TRISDbits.TRISD0 = 0;    //Configuring PORTD as output
TRISDbits.TRISD1 = 0;
TRISDbits.TRISD2 = 0;
TRISDbits.TRISD3 = 0;
TRISDbits.TRISD4 = 0;
TRISDbits.TRISD5 = 0;
TRISDbits.TRISD6 = 0;
TRISDbits.TRISD7 = 0;   

SSPSTATbits.SMP = 0;     //Configuration of SPI register
SSPSTATbits.CKE = 0;
SSPCON1bits.CKP = 0;
SSPCON1bits.SSPM3 = 0;
SSPCON1bits.SSPM2 = 1;
SSPCON1bits.SSPM1 = 0;
SSPCON1bits.SSPM0 = 0;  
SSPCON1bits.SSPEN = 1;

while(1)
{   

ADCON0bits.CHS0 = 1;     //Selecting AN0 as analog input
ADCON0bits.CHS1 = 0;
ADCON0bits.CHS2 = 0;
ADCON0bits.CHS3 = 0;
ADCON0bits.GO = 1;   //Start analog to digital conversion   
while (ADCON0bits.NOT_DONE);    
ch1 = ADRESL;   
ch2 = ADRESH;


data = SSPBUF;   //loading the SSPBUF value to some dummy varible(Previous data in SSPBUF)

//First time slave select
SSPCON1bits.WCOL = 0;    //Clearing SSPBUF register
while(PORTAbits.RA5 == 1);  //wait for slave select
SSPBUF = ch1;    //Loading ADRESH value to SSPBUF
while(SSPSTATbits.BF == 0); //wait untill the buffer is full

for(Count=0;Count<10;Count++);  //delay

//Second time slave selct
SSPCON1bits.WCOL = 0;    //Clearing SSPBUF register
while(PORTAbits.RA5 == 1);  //wait for slave select
SSPBUF = ch2;    //Loading ADRESL value to SSPBUF
while(SSPSTATbits.BF == 0); //wait untill the buffer is full

for(Count=0;Count<10;Count++);  //delay
}

Respuestas (1)

Hay algunas cosas que me parecen sospechosas. En el lado del maestro, introduciría un pequeño retraso entre la configuración de la señal de selección del esclavo y el envío de los datos ficticios (para iniciar la transferencia), aunque esto puede no ser un problema. Las otras cosas que son sospechosas es que en tu código esclavo primero tienes...

ch1 = ADRESL;   
ch2 = ADRESH;

pero entonces

SSPBUF = ch1;    //Loading ADRESH value to SSPBUF
...
SSPBUF = ch2;    //Loading ADRESL value to SSPBUF

Entonces, de acuerdo con sus comentarios y con el código que espera el maestro, espera obtener primero el byte alto, luego el byte bajo, pero el esclavo en realidad envía ADRESL primero, luego ADRESH.

Por último, después de la transferencia del primer byte, introduce un retraso más largo (mdelay<100) antes de anular la selección de SS en el maestro. En el lado del esclavo, solo hay un breve retraso, luego espera a que se configure nuevamente el SS, que probablemente todavía esté configurado en función del largo retraso del maestro. Luego establece el segundo byte de datos y espera a que se establezca el bit BF. No estoy familiarizado con el PIC18F4550, por lo que no sé si esto es un problema, pero dado que nunca borra explícitamente el bit BF, aún podría configurarse desde la primera ronda, lo que haría que su esclavo reinicie el bucle principal (después de otro breve retraso).