##// END OF EJS Templates
Versión inicial de los bloques de comunicación para el módulo de procesamiento.
Versión inicial de los bloques de comunicación para el módulo de procesamiento.

File last commit:

r216:217
r219:220
Show More
adcport.c
266 lines | 7.6 KiB | text/x-c | CLexer
aaguilar
Actualizacion
r216 /*
* adcport.c
*
* Created on: Mar 25, 2015
* Author: shinobi
*/
#include "adcport.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#define SPI_SS_bm PIN4_bm /*!< \brief Bit mask para el pin SS. */
#define SPI_MOSI_bm PIN5_bm /*!< \brief Bit mask para el pin MOSI. */
#define SPI_MISO_bm PIN6_bm /*!< \brief Bit mask para el pin MISO. */
#define SPI_SCK_bm PIN7_bm /*!< \brief Bit mask para el pin SCK. */
#define SS_OFF PORTC.OUTSET=PIN4_bm;/*!< \brief Deselecciona el ADC (puerto SPI) */
#define SS_ON PORTC.OUTCLR=PIN4_bm;/*!< \brief Selecciona el ADC (puerto SPI) */
/*
* Al iniciar la adquisicion se debe activar la interrupcion del pin RDY a
* traves del PINC6 del XMEGA.
* Luego al leer los datos digitalizados, se debe desactivar. Al terminar
* se reactiva para esperar la siguiente interrupcion.
* Esto se debe a que el DOUT y el RDY del ADC comparten el pin. Si se dejara
* activa la interrupcion al leer, se generarian interrupciones e los flancos
* de bajada generados por la transferencia de las muestras
*/
#define WAIT_DATA PORTC.INT0MASK=PIN6_bm/*!< \brief Activa interrupcion que indica dato nuevo */
#define GET_DATA PORTC.INT0MASK=0/*!< \brief Desactiva iterrupcion que indica dato nuevo */
volatile uint8_t buff_idx;
uint32_t * pfull_buff;
uint32_t * pread_buff;
volatile uint8_t buff_full_flg = 0;
/*!
* \fn adcport_ready_interrupt_config
* \brief configura el pin de MISO (conectado a DOUT del ADC), para que dispare
* una interrupcion por flanco de bajada.
* una vez disparada la interrupcion, se puede leer el pin; sin embargo, debe
* desactivarse antes de leer la interrupcion por flanco (con GET_DATA). De lo
* contrario se disparara la interrupcion varias veces al leer los datos, ya
* que ese el pin RDY y DOUT es el mismo en el ADC.
*/
inline void adcport_ready_interrupt_config(){
// pin6: MISO(xmega) --> DOUT/RDY(ADC) => pin6 entrada
PORTC.DIRCLR=PIN6_bm;
// El ADC llevara a "low" RDY cuando la conversion de un dato haya concluido
// Se debe leer el dato generado luego. Se espera una interrupcion de flanco
// de bajada para manejar esto
PORTC.PIN6CTRL=PORT_ISC_FALLING_gc;
// Se mapea la interrupcion externa INT0 de PORTC a PINC6
PORTC.INT0MASK=PIN6_bm;
// Debido a que esta interrupcion va a manejar la adquisicion de datos, se
// le da maxima prioridad (nivel alto)
PORTC.INTCTRL=PORT_INT0LVL_HI_gc;
// Se habilita la atencion de interrupciones de nivel alto
PMIC.CTRL|= PMIC_HILVLEN_bm;
}
/*!
* \fn adcport_spi_config
* \brief configura el puerto SPI para que coincida con el requerimiento del ADC
* AD7178-2
*/
inline void adcport_spi_config(){
PORTC.DIRSET = SPI_MOSI_bm | SPI_SCK_bm | SPI_SS_bm;
// Preescaler: clkper/2 (con clk2x). Maestro. CPOL=1,CPHA=1
// MSB primero
SPIC.CTRL = SPI_CLK2X_bm|SPI_ENABLE_bm|SPI_MASTER_bm|
SPI_MODE1_bm|SPI_MODE0_bm;
}
/*!
* \fn adcport_config
* \brief Configura el microcontrolador para darle servicio a la interrupcion
* del pin "RDY" del ADC, que reacciona con un flanco de bajada cuando se ha
* terminado de digitalar una muestra nueva.
* Tambien configura el puerto SPI que servira para comunicarse con el ADC.
* \see adcport_ready_interrupt_config
* \see adcport_spi_config
*/
inline void adcport_config(){
adcport_ready_interrupt_config();
adcport_spi_config();
// TODO configurar ADC: datarate, ganancia, desactivar CRC, formato numerico
// de muestras debe ser "bipolar offset binary"(canales diferenciales).
}
/*!
* \fn adcport_open
* \brief Inicializa el buffer de entrada (para datos de 24bits del ADC) y
* activa la comunicacion a traves del pin "SS" del puerto SPI.
* \see adcport_close
*/
inline void adcport_open(){
buff_idx=0;
// TODO configurar interrupcion externa PPS (pin 6)
// TODO configurar interrupcion externa LOCK (pin 21)
pfull_buff = malloc(sizeof(uint32_t)*BUFF_SIZE);
pread_buff = malloc(sizeof(uint32_t)*BUFF_SIZE);
adcport_config();
SS_ON;
}
/*!
* \fn adcport_close
* \brief Desactiva la comunicacion con el ADC a traves del pin "SS" del puerto
* SPI.
* \see adcport_open
*/
inline void adcport_close(){
SS_OFF;
free(pfull_buff);
free(pread_buff);
}
/*!
* \fn adcport_start
* \brief Inicia la digitalizacion de muestras del sensor.
* SPI.
* \see adcport_stop
* \see adcport_open
* \see adcport_close
*/
inline void adcport_start(){
// necesario para darle servicio con interrupciones al flanco de bajada
// del pin "RDY"
WAIT_DATA;
// TODO enviar comandos al ADC para que inicie la adquisicion.
}
/*!
* \fn adcport_stop
* \brief Pausa la digitalizacion de muestras del sensor.
* SPI.
* \see adcport_start
* \see adcport_open
* \see adcport_close
*/
inline void adcport_stop(){
// TODO enviar comandos al ADC para que deje de adquirir.
// necesario para cortar el servicio interrupcion del pin "RDY"
GET_DATA;
}
/*!
* \fn adcport_tranceiv
* \brief Realiza la transmision y recepcion simultanea de datos entre el ADC y
* el microcontrolador.
* Incluso en para leer un dato del ADC se debe transmitir, ya que solo la
* transmision genera clock en el pin "sclk"
* \param El dato a transmitir
* \return El dato leido del ADC
*/
inline uint8_t adcport_tranceiv(uint8_t data){
//
SPIC.DATA = data;
//Wait until transmission complete
while(!(SPIC.STATUS)&SPI_IF_bm);
// Return received data
return SPIC.DATA;
}
/*!
* \fn adcport_start
* \brief Inicia la digitalizacion de muestras del sensor.
* SPI.
* \see adcport_open
*/
void adcport_read_sample(){
uint32_t aux;
GET_DATA; // desactiva interrupciones de flaco de bajada
// Se le indica al adc que se va a leer el registro de data.
adcport_tranceiv(0x44);
// El byte mas significativo de la variable de 32bits es cero
// La codificacion de los numeros es "bipolar offset binary" y
// la transmision es MSB first
aux = adcport_tranceiv(0);
aux = (aux<<8)|adcport_tranceiv(0);
aux = (aux<<8)|adcport_tranceiv(0);
aux = (aux<<8)|adcport_tranceiv(0);
pread_buff[buff_idx]=aux;
WAIT_DATA; // reactiva interrupciones de flanco de bajada
}
/*!
* \fn adcport_getbuff
* \brief Devuelve la direccion del buffer lleno
* \return Direccion del buffer lleno. 0 si no esta lleno aun
*/
inline uint32_t* adcport_getbuff(){
if(buff_full_flg==1){
buff_full_flg=0;
return pfull_buff;
}
return 0;
}
uint8_t adcport_get_param(uint8_t data){
adcport_tranceiv(data);
return adcport_tranceiv(0);
}
/*!
* \brief interrupcion externa debe dispararse en flanco de bajada en PC6 (RDY del ADC).
* Cuando el ADC lleva este pin a "low", se debe leer el dato nuevo
*/
ISR(PORTC_INT0_vect){
adcport_read_sample();
buff_idx++;
if(buff_idx>=100){
uint32_t* paux = pread_buff;
pread_buff = pfull_buff;
pfull_buff = paux;
buff_full_flg=1;
// TODO dar aviso al programa principal que el buffer esta lleno.
// Puede ser a traves de una interrupcion "externa" en un pin que no se
// use, para lo cual debe estar configurado como salida y para recibir
// interrupciones de IO.
// para hacer que funcione como una interrupcion software, solo escribir
// en ese pin un valor segun se configure la interrupcion
}
}
/* TODO
* interrupcion del LOCK del GNSS (pin numero 21 del xmega)
* servira para indicar que el GNSS esta sincronizado con satelites y la hora y
* PPS son correctos, a partir de ese momento se pueden contar los PPS y
* identificarlos en el header.
*/
ISR(PORTx_INTx_vect){ // FIXME
}
/* TODO
* interrupcion del PPS del GNSS (pin numero 6 del xmega)
* servira para sincronizar la hora. Debe agregar un numero de serie entre 0 y 255
* a la cabecera del buffer que indentifique al PPS; y el numero de muestra que se adquirio
* en el momento de la llegada de esta interrupcion.
*/
ISR(PORTx_INTx_vect){ // FIXME
}