dac_r2r.c - Create a sine wave using a DACΒΆ
Performs a basic config of the ADC and samples two channels manually and sequentially with 12-bit results. Use this to control the amplitude of the sine wave. Conversion results are printed to screen as both HEX values and voltages.
#include "pic24_all.h"
#include "stdio.h"
#if defined(__PIC24E__) || defined(__dsPIC33E__)
# warning "This is a E family processor, which this example does not support."
int main(void) {
return 0;
}
#else
uncomment the next line to setup this project for a 12-bit ADC
#define USE_12BIT_ADC
#ifdef USE_12BIT_ADC
#define ADC_LEN 12
#define ADC_NSTEPS 4096
#define ADC_12BIT_FLAG 1
#else
#define ADC_LEN 10
#define ADC_NSTEPS 1024
#define ADC_12BIT_FLAG 0
#endif
prototypes provided for each DAC we support in this little example
void configDAC(void);
void writeDAC(uint16_t u16_x, uint16_t u16_y);
volatile uint8_t u8_per, u8_amp;
volatile uint16_t u16_per;
const uint8_t au8_sinetbl[] = {127,133,139,146,152,158,164,170,176,181, \
187,192,198,203,208,212,217,221,225,229,233,236,239,242,244,247,249,250, \
252,253,253,254,254,254,253,253,252,250,249,247,244,242,239,236,233,229, \
225,221,217,212,208,203,198,192,187,181,176,170,164,158,152,146,139,133, \
127,121,115,108,102,96,90,84,78,73,67,62,56,51,46,42,37,33,29,25,21,18, \
15,12,10,7,5,4,2,1,1,0,0,0,1,1,2,4,5,7,10,12,15,18,21,25,29,33,37,42,46, \
51,56,62,67,73,78,84,90,96,102,108,115,121
};
/**
*** Select the DAC you want to use by uncomment _ONLY_ONE_ line below!
**/
//#define __DAC_R2R
//#define __DAC_MAX548A
#define __DAC_MAX5353
//#define __DAC_MAX518
//#define __DAC_MAX518_DUAL
#ifdef __DAC_R2R
#warning "DAC_R2R.C built for explicit R-2R DAC connected to RB9(MSb)-RB2(LSb)."
void configDAC() {
CONFIG_RB2_AS_DIG_OUTPUT();
CONFIG_RB3_AS_DIG_OUTPUT();
CONFIG_RB4_AS_DIG_OUTPUT();
CONFIG_RB5_AS_DIG_OUTPUT();
CONFIG_RB6_AS_DIG_OUTPUT();
CONFIG_RB7_AS_DIG_OUTPUT();
CONFIG_RB8_AS_DIG_OUTPUT();
CONFIG_RB9_AS_DIG_OUTPUT();
}
void writeDAC(uint16_t u16_x, uint16_t u16_y) {
uint16_t u16_temp;
u16_temp = LATB & 0xFC03; // read PORTB removing our eight bits
u16_temp |= ((u16_x & 0xFF00) >> 6); // put our eight bits into PORTB value
LATB = u16_temp;
}
#endif
#ifdef __DAC_MAX548A
#warning "DAC_R2R.C built for SPI-based dual 8-bit MAX548A DAC connected to RB14(SDO) and RB13(SCLK)."
#define CONFIG_MAX548A_ENABLE() CONFIG_RA2_AS_DIG_OUTPUT()
#define MAX548A_ENABLE() _LATA2 = 0
#define MAX548A_DISABLE() _LATA2 = 1
void configDAC(void) {
//spi clock = 40MHz/1*4 = 40MHz/4 = 10MHz
SPI1CON1 = SEC_PRESCAL_1_1 | //1:1 secondary prescale
PRI_PRESCAL_4_1 | //4:1 primary prescale
CLK_POL_ACTIVE_HIGH | //clock active high (CKP = 0)
SPI_CKE_ON | //out changes inactive to active (CKE=0)
SPI_MODE8_ON | //8-bit mode
MASTER_ENABLE_ON; //master mode
//configure pins. Only need SDO, SCLK since MAX548 is output only
CONFIG_RB14_AS_DIG_OUTPUT();
CONFIG_SDO1_TO_RP(RB14_RP); //use RB14 for SDO
CONFIG_RB13_AS_DIG_OUTPUT();
CONFIG_SCK1OUT_TO_RP(RB13_RP); //use RB13 for SCLK
SPI1STATbits.SPIEN = 1; //enable SPI mode
CONFIG_MAX548A_ENABLE(); //chip select for MAX548
MAX548A_DISABLE(); //disable the chip select
}
void writeDAC(uint16_t u16_x, uint16_t u16_y) {
only update DAC A
//MAX548A_ENABLE(); //assert chipselect
//ioMasterSPI1(0x09); //command to immediately write DAC A
//ioMasterSPI1(u16_x>>8); //write DAC A data
//MAX548A_DISABLE(); //release CS and update DAC outputs
MAX548A_ENABLE(); //assert chipselect
ioMasterSPI1(0x02); //command to write DAC B input (do not change output)
ioMasterSPI1(u16_y>>8); //write DAC B data
MAX548A_DISABLE(); //release CS and update DAC input
MAX548A_ENABLE(); //assert chipselect
ioMasterSPI1(0x09); //command to write DAC A input and update both DAC outputs
ioMasterSPI1(u16_x>>8); //write DAC A data
MAX548A_DISABLE(); //release CS and update DAC outputs
}
#endif
#ifdef __DAC_MAX5353
#warning "DAC_R2R.C built for SPI-based 12-bit MAX5353 DAC connected to RB14(SDO) and RB13(SCLK)."
#define CONFIG_MAX5353_ENABLE() CONFIG_RA3_AS_DIG_OUTPUT()
#define MAX5353_CMD_ANDMASK 0x1FFE
#define MAX5353_ENABLE() _LATA3 = 0
#define MAX5353_DISABLE() _LATA3 = 1
void configDAC(void) {
//spi clock = 40MHz/1*4 = 40MHz/4 = 10MHz
SPI1CON1 = SEC_PRESCAL_1_1 | //1:1 secondary prescale
PRI_PRESCAL_4_1 | //4:1 primary prescale
CLK_POL_ACTIVE_HIGH | //clock active high (CKP = 0)
SPI_CKE_ON | //out changes inactive to active (CKE=0)
SPI_MODE16_ON | //16-bit mode
MASTER_ENABLE_ON; //master mode
//configure pins. Only need SDO, SCLK since MAX548 is output only
CONFIG_RB14_AS_DIG_OUTPUT();
CONFIG_SDO1_TO_RP(RB14_RP); //use RB14 for SDO
CONFIG_RB13_AS_DIG_OUTPUT();
CONFIG_SCK1OUT_TO_RP(RB13_RP); //use RB13 for SCLK
SPI1STATbits.SPIEN = 1; //enable SPI mode
CONFIG_MAX5353_ENABLE(); //chip select for MAX548
MAX5353_DISABLE(); //disable the chip select
}
void writeDAC(uint16_t u16_x, uint16_t u16_y) {
UNUSED(u16_y);
MAX5353_ENABLE(); //assert chipselect
//write DAC B data (with command bits and sub-bit cleared)
ioMasterSPI1((u16_x>>3) & MAX5353_CMD_ANDMASK);
MAX5353_DISABLE(); //release CS and update DAC input
}
#endif
#ifdef __DAC_MAX518
#warning "DAC_R2R.C built for I2C-based single output 8-bit MAX518 DAC connected to RB9(SDA) and RB8(SCL)."
#define MAX518_I2C_ADDR 0x58 // see MAX518 datasheet 19-0393 Figure 6
#define MAX518_WRITE_DACA 0x00 // see MAX518 datasheet 19-0393 Figure 7
#define MAX518_WRITE_DACB 0x01 // see MAX518 datasheet 19-0393 Figure 7
void configDAC(void) {
configI2C1(400); //configure I2C for 400 KHz
}
void writeDAC(uint16_t u16_x, uint16_t u16_y) {
write2I2C1(MAX518_I2C_ADDR, MAX518_WRITE_DACA, (uint8_t) (u16_x>>8) );
}
#endif
#ifdef __DAC_MAX518_DUAL
#warning "DAC_R2R.C built for I2C-based DUAL output 8-bit MAX518 DAC connected to RB9(SDA) and RB8(SCL)."
#warning "In this example, I2C SCL is beyond specification for the MAX518 DAC."
#define MAX518_I2C_ADDR 0x58 // see MAX518 datasheet 19-0393 Figure 6
#define MAX518_WRITE_DACA 0x00 // see MAX518 datasheet 19-0393 Figure 7
#define MAX518_WRITE_DACB 0x01 // see MAX518 datasheet 19-0393 Figure 7
void configDAC(void) {
configI2C1(700); //configure I2C for 400 KHz
}
void writeDAC(uint16_t u16_x, uint16_t u16_y) {
static uint8_t au8_buf[]= {MAX518_WRITE_DACA, 0, MAX518_WRITE_DACB, 0 };
au8_buf[1] = (uint8_t) (u16_x>>8);
au8_buf[3] = (uint8_t) (u16_y>>8);
writeNI2C1(MAX518_I2C_ADDR, &au8_buf[0], 4);
}
#endif
void _ISR _T3Interrupt (void) {
static uint8_t u8_idx;
static uint16_t u16_idx, u16_old;
static uint16_t u16_val;
writeDAC(u16_val, u16_idx); // write new DAC value
Compute DAC value for next time
u16_idx+=u16_per;
u8_idx = (uint8_t) (u16_idx>>9 );
u16_val = ((uint16_t)au8_sinetbl[u8_idx])<<8; // get sine fcn value
u16_val >>= u8_amp; // reduce sine amplitude based on input from pot
if ((u16_idx^u16_old)&0x8000) _LATB12 = !_LATB12;
u16_old = u16_idx;
_T3IF = 0; //clear T3 interrupt flag
}
void configTimer3(void) {
configure T3 as 32-bit timer to trigger every 1/64 second
T3CONbits.TON = 0;
T3CON = T3_PS_1_1 | T3_SOURCE_INT;
TMR3 = 0;
PR3 = usToU16Ticks(50, getTimerPrescale(T3CONbits)) - 1; // # of ticks for 50us (200KHz) seconds
_T3IP=7;
_T3IF=0;
_T3IE=1;
T3CONbits.TON = 1;
}
int main (void) {
uint8_t u8_uiCount;
configBasic(HELLO_MSG);
configure AN0 and AN1 to for analog input to PIC24 ADC
CONFIG_RA0_AS_ANALOG();
CONFIG_RA1_AS_ANALOG();
configDAC();
configTimer3();
CONFIG_RB12_AS_DIG_OUTPUT();
_LATB12 = 0;
u8_uiCount=5;
while (1) {
configADC1_ManualCH0(RA0_AN, 31, ADC_12BIT_FLAG);
DELAY_MS(100);
u16_per =convertADC1();
if (u16_per==0) u16_per++; // u16_per must be >= 1
configADC1_ManualCH0(RA1_AN, 31, ADC_12BIT_FLAG);
DELAY_MS(100);
u8_amp = convertADC1()>>9; // 0 <= u8_amp <= 7
if (!u8_uiCount) {
printf("timestep=0x%04X amplitude shift = 0x%02X\n", u16_per, u8_amp );
u8_uiCount=5;
} else
u8_uiCount--;
} //endof while()
} // endof main()
#endif