configuración de registros ADC mediante comunicación spi

5

Soy nuevo en los microcontroladores: estoy tratando de leer los valores ADC externos de un AD7798 ADC utilizando la comunicación SPI.

Inicialmente tengo que configurar algunos registros ADC, algunos registros no están configurados. Para configurar los registros, tengo que usar el registro de comunicación para seleccionar qué registro quiero configurar.

Por ejemplo, quiero establecer el registro de configuración AD7798 (16 bits). Tengo un código como este:       #incluir     #define PORTB.3 ADC_CS     #define WG_CS PORTB.4     #define MOSI PORTB.5     #define MISO_PU PORTB.6     #define MISO_PIN PINB.6     # define SCK PORTB.7

//global functions.
unsigned int adcConfig;
unsigned int adcMode;
unsigned int adcId;

void init_io(void) 
{ 
DDRB = 0xBF;        // make SCK, MOSI, CS1, CS2 outputs 
ADC_CS = 1;              //disable ADC 
WG_CS = 1;               //disable WaveGenerator 
MISO_PU = 1;             //enable pull-up on MISO so we can test !RDY 
} 

unsigned char spi(unsigned char data) 
{ 
//Start transmision 
SPDR = data; 
//Wait for transmision complete 
while (!(SPSR & (1<<SPIF))); 
return SPDR; 
} 

//Sets the waveform generator output to given phase 
void SetWGPhase(unsigned int phase) 
{ 
SPCR = 0x5A; // mode #2 F_CPU/64 
WG_CS = 0;                      // enable 
spi(0x20); 
spi(0x00); 
spi((phase >> 8) | 0xC0);       //Load into phase register 0 
spi(phase & 0x00FF); 
WG_CS = 1; 
} 

void setupAd(){ 
    SPCR = 0x5D; 
    ADC_CS = 0; 
   // while(spi(0x10) != 0x10); 
    spi(0x10);                  //set up communication register for configuration reg. 
    spi(0x07);        
    spi(0x10); 

    spi(0x08);                  //set up communication register for mode reg. 
    spi(0x00);        
    spi(0x0A); 
    ADC_CS = 1; 
    } 


 unsigned int ReadAd(void) 
 { 
unsigned int data; 
SPCR = 0x5D; // mode #3 F_CPU/16 
CheckStatus();
ADC_CS = 0;                     // enable 
while (MISO_PIN != 0) ;         // wait for  DOUT/!RDY line to go low 
//Read data 
spi(0x58);                      //Place readinstruction in communication register 
data = spi(0xFF);               // read hi-byte 
data = (data << 8) | spi(0xFF); // and lo-byte. 
ADC_CS = 1;                     // disable 
return data; 
} 

 unsigned char CheckStatus(void)
{
char adcStatus; 
            SPCR = 0x5D;
            ADC_CS = 0;                     // enable  
            while(ADC_CS_PIN);
            adcStatus = 0xFF; 
while(!(adcStatus & 0x80)){                                     

             spi(0x40);
             adcStatus = spi(0xFF); 
          }          
ADC_CS = 1;                      

return adcStatus;
}

unsigned int ReadAdConfReg(void) 
{              
  unsigned int retvalconfig;
SPCR = 0x5D;  
ADC_CS = 0;      
while (MISO_PIN != 0) ; 
spi(0x50); 
adcConfig = spi(0xFF);    
adcConfig = (adcConfig << 8) | spi(0xFF); 
retvalconfig= adcConfig;
ADC_CS = 1; 
return retvalconfig;
} 

unsigned int ReadAdModeReg(void) 
{              
  unsigned retvalmode;
SPCR = 0x5D;  
ADC_CS = 0;        
while (MISO_PIN != 0) ; 
spi(0x48); 
adcMode = spi(0xFF);  
adcMode = (adcMode << 8) | spi(0xFF); 
retvalmode =adcMode;   
ADC_CS = 1;
return retvalmode;
} 
unsigned int ReadAdIdReg(void) 
{              

SPCR = 0x5D;  
ADC_CS = 0;          
while (MISO_PIN != 0) ; 
spi(0x60); 
adcId = spi(0xFF);    
ADC_CS = 1;
 return adcId; 
} 

cuando imprimo el registro de configuración está dando valor "16383". pero cuando apago / enciendo el objetivo obtengo "1808 (que es equivalente a 0x0710)" después de eso, está dando el mismo valor que "16383". También he probado con diferentes configuraciones pero no está cambiando, siempre imprimiendo "16383" excepto el apagado / encendido. Creo que el valor predeterminado.

Incluso con el registro de modo siempre se está imprimiendo "10 (que es equivalente a 0x000A)" pero ese es el valor que obtengo siempre, incluso si cambio la configuración a "0x0022".

Incluso he intentado leer el registro de identificación, pero está dando "0x48". pero en la hoja de datos mencionó "0xX8" para AD7798. Gracias de antemano.

Alguien que me ayude, por favor, no tengo idea de qué error estoy cometiendo aquí.

    
pregunta verendra

4 respuestas

5

Si bien esta hoja de datos hace que mis ojos sangren por la complejidad de hacer una conversión / lectura simple, necesita hacer algunos cambios simples.

No estoy seguro de por qué la gente está haciendo esto más difícil de lo que realmente es. Tire de la línea de selección de chip hacia abajo, y el IC objetivo simplemente debería leer lo que le dé hasta que lo saque de nuevo. Solo porque su método toma un valor de 8 bits no significa que no puede llamarlo dos veces para pasar un valor de 16 bits a su IC. No hay necesidad de morder nada. Eso es una tontería.

Llame a su método SPI para decirle al ADC que desea escribir en el registro de configuración:

spi(0x10);

Según entiendo de la hoja de datos, puede escribir inmediatamente su valor de 16 bits en el registro de configuración después de eso, por lo que haría:

spi(0x07);
spi(0x10);

Olvidé de qué manera terminará siendo ensamblado en el lado del IC objetivo, así que simplemente podrías revertirlos si las cosas no funcionan bien. No hay necesidad de cambiar de bit ningún valor en absoluto. En el peor de los casos, es necesario volver a colocar la línea CS en alto antes de volver a bajar para enviar los datos para escribir en el registro de configuración.

De lo contrario, esto es super simple. Recuerde, si el dispositivo SPI de destino espera más de un byte, es decir, un valor de 16 bits, es probable que el envío de los bytes en el orden en que aparecerían normalmente (por lo tanto, si desea enviar 0x1234, tendrá 0x12). y 0x34) funcionará bien y no necesitarás cambiar nada.

    
respondido por el Toby Lawrence
3

La línea de selección de chips en AD7798 es activo bajo. Parece que tienes la polaridad hacia atrás en tu código.

Debe establecer CS en bajo (0) al comienzo de la transferencia, y alto después de la transferencia. Así que prueba esto:

void setupADC()
{
    ChipSelectAd(0); // was 1
    spi(0x10);
    spi(0x07);
    spi(0x10);
    ChipSelectAd(1); // was 0  
}

También verifique que esté usando el modo SPI correcto (llamado CPOL y CPHA en muchos microcontroladores, para "polaridad de reloj" y "fase de reloj"). Esto determina qué borde del reloj activa las transiciones de datos, y qué nivel tiene el reloj entre las transacciones (en reposo).

El AD7798 requiere CPOL = 1 y CPHA = 1 (modo SPI 3).

    
respondido por el Ben Voigt
1

Como dice RocketMagnet

spi(0x07)<<8;   

no tiene sentido. Aunque la función spi() está definida como char , la estás desplazando a la izquierda y luego la descartas.

spi(0x07 << 8);   

desplaza el argumento 8 bits a la izquierda, por lo que será 0x0700 . Pero eso no hace lo que quieres. No anula la selección de SS (Selección de esclavo) entre las llamadas de la función spi() , por lo que será automático. Lo cambiaría para tener un argumento opcional hold_ss , de modo que pueda cambiar en el primer byte, luego en el segundo, y solo luego anular la verificación de SS.

De esa manera, podrá transferir 16 bits de datos al ADC, sin tener que cambiar los datos antes de la llamada spi() . Alternativamente, puede escribir una función spi16() :

unsigned int spi16(unsigned int data16)
{ 
    assert_SS(IOpin);          
    spi8(data >> 8); /* assuming LSB is shifted first */
    spi8(data);
    deassert_SS(IOpin);
}

(Estoy ignorando los datos entrantes por el momento).

La hoja de datos indica que el Registro de configuración realmente necesita 16 bits, pero aunque no da detalles, espero que los necesite como una sola transferencia. Verifique la función spi() del compilador de su microcontrolador y la hoja de datos del microcontrolador para ver si las transferencias de 16 bits son realmente posibles en primer lugar. Si el controlador puede realizar transferencias de 16 bits, debería poder hacer esto:

spi(0x0710);

Si solo es posible realizar transferencias de 8 bits, creo que tendrás que recurrir a un SPI de bajo impacto (que no es tan difícil).

editar
Rocketmagnet me señala la definición de la función spi() :

char spi(char data) 

Eso lo dice todo: el argumento es de tipo char , por lo que solo es de 8 bits.

( Gracias por el puntero (sin juego de palabras), Rocketmagnet )

    
respondido por el stevenvh
0

¿Qué micro estás usando? No proporcionó información sobre lo que spi() está haciendo allí. Podría estar enviando 8bits. En cuyo caso su cambio de 8 bits da como resultado tonterías. Ahora, usted indicó que desea enviar "0x0710". Piense por un segundo lo que puede estar pasando en su código.

Parece que estás confundido acerca de cómo se realiza esta transferencia de SPI.

Primero, estás enviando 0x10. Luego, suponiendo que su función spi() envía 16 bits, está enviando 0x0700. Acabas de transferir 0x100700.

Estoy bastante seguro de que su función spi() no envía sus 16 bits. Así que básicamente estás enviando dos bytes: 0x10 y 0x00. Bien hecho.

Debe revertir el orden de los bytes al enviar múltiples bytes a través de SPI. Primero, envíe 0x07, y solo luego envíe 0x10.

    
respondido por el Jonny B Good

Lea otras preguntas en las etiquetas