|
|
/*
|
|
|
* 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
|
|
|
|
|
|
}
|
|
|
|
|
|
|