##// END OF EJS Templates

File last commit:

r220:221
r220:221
Show More
adcport.c
266 lines | 7.6 KiB | text/x-c | CLexer
r220 /*
* 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
}