/* * _010_BCD_Arduini_SigGen.c * * Created: 5/14/2017 1:15:16 PM * Author: Ajoy * Based on 009_BCD.c * Which implemented a Timing Based BCD Switch Decoder * and 007_DDS.c * Which implements a Direct Digital Synthesis (DDR) Audio Signal Generator * The DDS Audio frequency to be set based on the decoded BCD Switches * This software also accepts commands from the earlier Arduino Aj_Sig_Gen * VB program used with 007.DDS.C */ /* This program while implementing a DDS Audio signal generator is a good example of use of interrupts. The manual captures the BCD switch values based on INT0. For this INT0 calls INT1, INT20,INT21 and INT23 in sequence. Communication to the PC uses the USART_RX interrupt. As before a fast DDS while loop is used to generate the waveforms through a 6-BIT D/A formed on PORTD. THe while loop is broken either on the INT0 or USART_RX interrupts to setup an updated waveform */ //-------------Remarks------------------ /* Step 1 : Timer ONE setup to provide a square wave on OC0A at 244 Hz : PWM duty cycle 224/255 : Cap Network 0.2/0.1/0.05/0.0250 uF : Interrupts used INT1, INT20, INT21, INT23 : The 4 Switch Values Switch4 PCINT23 Thousands Switch3 PCINT21 Hundreds Switch2 PCINT21 Tens Switch1 INT1 Units : Period count / switch value sent on USART *Note : ISR (PCINT0_vect) pin change interrupt for D8 to D13 ISR (PCINT1_vect) pin change interrupt for A0 to A5 ISR (PCINT2_vect) pin change interrupt for D0 to D7 Step 2 : The four interrupts were being enabled in sequence and TCNT0 corresponding to each switch captured and processed. : INT0 is added and the value of the switches would only be read based on when this interrupt occurs. : Works but disconnecting and reconnecting serial monitor sets back switch values to 0 ? as seen on serial output. Keep this bug in mind! Step 3 : Added the DDS signal generator to work with these switch values Program computes the value of phase_step required based on switch values converted to freq and then phase_step. The DDS loop uses a while loop with minimum instructions so as achieve the fastest FClock. The while loop can be broken using a break statement based on INT0. Based on INT0 mode=0X42 is used break the DDS while loop to update the frequency Step 4 : SetUp PC0, and PC1 as inputs with pull up PC0 High for freq X10 PC1 High for TRI and low for SIN Added default 1kHz SIN on StartUp Manual mode Done - Need to add PC Mode Step 5 : For PC Controlled Mode mode= 0x41 dummy used by BCD controlled mode Default 1kHz Sin removed On first startup / processor reset System goes into the while loop waiting for PC serial commands Visual Basic GUI software can be connected at this time PC commands setup frequency/wave-shape through the GUI On INT0 interrupt the system goes into manual mode PC command is restored by Rx interrupt through the GUI However, sometimes more than one RUN command is required some RUN commands show timeout but trying again works. /* ------------Commands Hex values --------------------- Break Command 42 42 42 42 B in ASCII Identify 49 49 49 49 I in ASSCII 5kHz Sin 53 03 70 DC S in ASCII Followed by Frequency Setting in Hex corresponds to a phase step of 225,500 25kHz Triangle 54 11 34 4D T in ASCII Followed by Frequency Setting in Hex corresponds to a phase step of 1,127,501 5kHz RampUp 55 03 70 DC U in ASCII Followed by Frequency Setting in Hex 5kHz RampDn 44 03 70 DC D in ASCII Followed by Frequency Setting in Hex Load Arbitrary Data 4C 4C 4C 4C L in ASCII This is to be followed by 128 Hex Data 6-Bit maximum 1F Hex / 63 Dec 5kHz Arbitrary 41 03 70 DC A in ASCII Followed by Frequency Setting in Hex */ //-------------Includes----------------- #include #include "util/delay.h" #include //-------------Defines------------------- #define F_CPU 16000000UL //CPU Clock Speed #define USART_BAUDRATE 38400 // Define baud rate #define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) //Function prototypes BCD Switch----------------------------------------------------- void pwm_init(); //Initialize Timer0 for PWM 144 Hz 224/256 duty cycle void USART_Init(void); void USART_SendByte(uint8_t u8Data); uint8_t USART_ReceiveByte(); void INT0_init(); void INT1_init(); void PCINT20_init(); void PCINT21_init(); void PCINT23_init(); void get_BCD(); void get_value_INT1(); void get_value_INT20(); void get_value_INT21(); void get_value_INT23(); get_switch(uint8_t duty); //Function prototypes DDS------------------------------------------------- void DDS_OUT(); void Calculate_freq(); void Calculate_phase_step(); uint8_t create_out_map( uint8_t MAP[128]); void Default_DDS_OUT();//1 kHz Sin Wave //Waveform tables------------------------------------------------------------------- uint8_t SIN_MAP[128]={//8Bit>>2 0x1F,0x21,0x22,0x24,0x25,0x27,0x28,0x2A,0x2B,0x2D,0x2E,0x30,0x31,0x32,0x33,0x35, 0x36,0x37,0x38,0x39,0x3A,0x3A,0x3B,0x3C,0x3D,0x3D,0x3E,0x3E,0x3E,0x3F,0x3F,0x3F, 0x3F,0x3F,0x3F,0x3F,0x3E,0x3E,0x3E,0x3D,0x3D,0x3C,0x3B,0x3A,0x3A,0x39,0x38,0x37, 0x36,0x35,0x33,0x32,0x31,0x30,0x2E,0x2D,0x2B,0x2A,0x28,0x27,0x25,0x24,0x22,0x21, 0x1F,0x1E,0x1C,0x1B,0x19,0x18,0x16,0x15,0x13,0x12,0x10,0x0F,0x0E,0x0C,0x0B,0x0A, 0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08, 0x09,0x0A,0x0B,0x0C,0x0E,0x0F,0x10,0x12,0x13,0x15,0x16,0x18,0x19,0x1B,0x1C,0x1E }; uint8_t TRI_MAP[128]={ 0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E, 0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E, 0x3F,0x3E,0x3D,0x3C,0x3B,0x3A,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, 0x2F,0x2E,0x2D,0x2C,0x2B,0x2A,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, 0x1F,0x1E,0x1D,0x1C,0x1B,0x1A,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, 0x0F,0x0E,0x0D,0x0C,0x0B,0x0A,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, 0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E, 0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E }; uint8_t RAMPUP_MAP[128]={ 0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07, 0x07,0x08,0x08,0x09,0x09,0x0A,0x0A,0x0B,0x0B,0x0C,0x0C,0x0D,0x0D,0x0E,0x0E,0x0F, 0x0F,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17, 0x17,0x18,0x18,0x19,0x19,0x1A,0x1A,0x1B,0x1B,0x1C,0x1C,0x1D,0x1D,0x1E,0x1E,0x1F, 0x1F,0x20,0x20,0x21,0x21,0x22,0x22,0x23,0x23,0x24,0x24,0x25,0x25,0x26,0x26,0x27, 0x27,0x28,0x28,0x29,0x29,0x2A,0x2A,0x2B,0x2B,0x2C,0x2C,0x2D,0x2D,0x2E,0x2E,0x2F, 0x2F,0x30,0x30,0x31,0x31,0x32,0x32,0x33,0x33,0x34,0x34,0x35,0x35,0x36,0x36,0x37, 0x37,0x38,0x38,0x39,0x39,0x3A,0x3A,0x3B,0x3B,0x3C,0x3C,0x3D,0x3D,0x3E,0x3E,0x3F }; uint8_t RAMPDN_MAP[128]={ 0x3F,0x3E,0x3E,0x3D,0x3D,0x3C,0x3C,0x3B,0x3B,0x3A,0x3A,0x39,0x39,0x38,0x38,0x37, 0x37,0x36,0x36,0x35,0x35,0x34,0x34,0x33,0x33,0x32,0x32,0x31,0x31,0x30,0x30,0x2F, 0x2F,0x2E,0x2E,0x2D,0x2D,0x2C,0x2C,0x2B,0x2B,0x2A,0x2A,0x29,0x29,0x28,0x28,0x27, 0x27,0x26,0x26,0x25,0x25,0x24,0x24,0x23,0x23,0x22,0x22,0x21,0x21,0x20,0x20,0x1F, 0x1F,0x1E,0x1E,0x1D,0x1D,0x1C,0x1C,0x1B,0x1B,0x1A,0x1A,0x19,0x19,0x18,0x18,0x17, 0x17,0x16,0x16,0x15,0x15,0x14,0x14,0x13,0x13,0x12,0x12,0x11,0x11,0x10,0x10,0x0F, 0x0F,0x0E,0x0E,0x0D,0x0D,0x0C,0x0C,0x0B,0x0B,0x0A,0x0A,0x09,0x09,0x08,0x08,0x07, 0x07,0x06,0x06,0x05,0x05,0x04,0x04,0x03,0x03,0x02,0x02,0x01,0x01,0x00,0x00,0x00 }; //------------------Globals BCD Switch------------------------------------- volatile uint8_t duty, switch_value=0,Hi_or_Lo,INT20_21_23=0; volatile uint8_t sw4,sw3,sw2,sw1; volatile static uint8_t next_write=0; // the pointers to the receive buffer //------------------Globals DDS------------------------------------- uint8_t table_index; //128 step tables volatile uint8_t DataMode; uint32_t phase_accumulator, phase_step, freq; //volatile static uint8_t next_write=0; // the pointers to the receive buffer volatile uint8_t buffer[4]; // circular buffer for receiver volatile uint8_t mode,phase_step_b2, phase_step_b1,phase_step_b0; volatile uint8_t freq_thousands, freq_hundreds, freq_tens, freq_units; volatile uint8_t cmd_recd, pc0, pc1, freq_mult_10; uint8_t DDS_OUT_MAP[128]; volatile uint8_t DDS_ARB_BUF[128]; //-----------------INT0 ISR---------------------------------- // Interrupt Service Routine attached to INT0 vector PortD2 ISR(INT0_vect){ EIMSK &= ~ (1 << INT0); // Disable external interrupt INT0 //Very important to avoid contact bounce //Get switch values get_BCD(); //Get out of any running DDS while loop mode=0x42; _delay_ms(500); EIMSK |= (1 << INT0); // Enable external interrupt INT0 //Check PC0, PC1 and PC2 //PC0 High for freq X10 //PC1 High for TRI and low for SIN pc0=(PINC & (1 << PINC0)); pc1=(PINC & (1 << PINC1))>>1; if (pc0==0) {freq_mult_10=1;} else{freq_mult_10=10;} phase_accumulator=0; Calculate_freq(); if (pc1==0) {create_out_map(SIN_MAP);} else{create_out_map(TRI_MAP);} mode=0x41;//dummy mode DDS_OUT(); //EIMSK |= (1 << INT0); // Enable external interrupt INT0 } // Interrupt Service Routine attached to INT1 vector PortD3 ISR(INT1_vect){ EIMSK &= ~ (1 << INT1); // Disable external interrupt INT0 //Very important to avoid contact bounce //Read TCNT0 sw1=TCNT0; freq_units= get_switch(sw1); } // Interrupt Service Routine attached to PCINT2 vector ISR (PCINT2_vect){ PCICR &= ~ (1 << PCIE2); // Disable pin change interrupt PCINT2 //ISR Portion for INT20 PortD4 if(INT20_21_23==0){ Hi_or_Lo=(PIND & (1 << PIND4))>>4; if (Hi_or_Lo==1){//Low to High PCICR |= (1 << PCIE2); // Enable pin change interrupt PCINT2 } if (Hi_or_Lo==0){//High to Low PCICR &= ~ (1 << PCIE2); // Disable pin change interrupt PCINT2 sw2=TCNT0; freq_tens= get_switch(sw2); } } //ISR Portion for INT21 PortD5 if(INT20_21_23==1){ Hi_or_Lo=(PIND & (1 << PIND5))>>5; if (Hi_or_Lo==1){//Low to High PCICR |= (1 << PCIE2); // Enable pin change interrupt PCINT2 } if (Hi_or_Lo==0){//High to Low PCICR &= ~ (1 << PCIE2); // Disable pin change interrupt PCINT2 sw3=TCNT0; freq_hundreds= get_switch(sw3); } } //ISR Portion for INT23 PortD7 if(INT20_21_23==2){ Hi_or_Lo=(PIND & (1 << PIND7))>>7; if (Hi_or_Lo==1){//Low to High PCICR |= (1 << PCIE2); // Enable pin change interrupt PCINT2 } if (Hi_or_Lo==0){//High to Low PCICR &= ~ (1 << PCIE2); // Disable pin change interrupt PCINT2 sw4=TCNT0; freq_thousands= get_switch(sw4); USART_SendByte(freq_thousands); } } } //-----------------USART RX ISR---------------------------------- ISR(USART_RX_vect){ // the interrupt signal when a byte is received by the USART // store the data into the buffer if (DataMode==1){//4 Byte Data Mode buffer[next_write++] = UDR0; if (next_write == 4){ next_write = 0; mode=buffer[0]; phase_step_b2=buffer[1]; phase_step_b1=buffer[2]; phase_step_b0=buffer[3];//lsb if (mode==0x4C){ DataMode=0; } } } else if (DataMode==0){//256 Data Mode DDS_ARB_BUF[next_write++] = UDR0; if (next_write == 128){ next_write = 0; DataMode=1; } } } //---------------- Main -------------------------------------- int main(void){ //SetUp DAC pins as output DDRB =0xFF; //PORTB all outputs //SetUp PC0 and PC1 as inputs with pull up //PC0 High for freq X10 //PC1 High for internal and Low for PC Control DDRC &= ~(1 << DDD0); // Clear the PC0 pin Set as Input PORTC |= (1 << PORTC0); // Turn On the Pull-up DDRC &= ~(1 << DDD1); // Clear the PC1 pin Set as Input PORTC |= (1 << PORTC1); // Turn On the Pull-up //SetUp USART USART_Init(); // Initialize USART //SetUp Interrupt INT0 cli(); // Disable global interrupts INT0_init(); sei(); // Enable global interrupts // initialize timer in PWM mode pwm_init(); mode= 0x42; DataMode=1; //Default_DDS_OUT(); while(1){ // Repeat indefinitely on reset/startup // Called again only on Rx interrupt commands _delay_ms(100); if (mode== 0x53){//Set Sin phase_accumulator=0; Calculate_phase_step(); USART_SendByte(0x44); USART_SendByte(0x44); USART_SendByte(0x53); USART_SendByte(0x5F); USART_SendByte(0x53); USART_SendByte(0x69); USART_SendByte(0x6E); USART_SendByte(0x5F); USART_SendByte(0x53); USART_SendByte(0x65); USART_SendByte(0x74); USART_SendByte(0x0D); USART_SendByte(0x0A); create_out_map( SIN_MAP); DDS_OUT(); } else if (mode==0x54){//Set Triangle phase_accumulator=0; Calculate_phase_step(); USART_SendByte(0x44); USART_SendByte(0x44); USART_SendByte(0x53); USART_SendByte(0x5F); USART_SendByte(0x54); USART_SendByte(0x72); USART_SendByte(0x69); USART_SendByte(0x5F); USART_SendByte(0x53); USART_SendByte(0x65); USART_SendByte(0x74); USART_SendByte(0x0D); USART_SendByte(0x0A); create_out_map( TRI_MAP); DDS_OUT(); } else if (mode== 0x55){//Set Ramp UP phase_accumulator=0; Calculate_phase_step(); USART_SendByte(0x44); USART_SendByte(0x44); USART_SendByte(0x53); USART_SendByte(0x5F); USART_SendByte(0x52); USART_SendByte(0x61); USART_SendByte(0x6D); USART_SendByte(0x70); USART_SendByte(0x55); USART_SendByte(0x70);USART_SendByte(0x5F); USART_SendByte(0x53); USART_SendByte(0x65); USART_SendByte(0x74); USART_SendByte(0x0D); USART_SendByte(0x0A); create_out_map( RAMPUP_MAP); DDS_OUT(); } else if (mode==0x44){//Set Ramp DN phase_accumulator=0; Calculate_phase_step(); USART_SendByte(0x44); USART_SendByte(0x44); USART_SendByte(0x53); USART_SendByte(0x5F); USART_SendByte(0x52); USART_SendByte(0x61); USART_SendByte(0x6D); USART_SendByte(0x70); USART_SendByte(0x44); USART_SendByte(0x6E);USART_SendByte(0x5F); USART_SendByte(0x53); USART_SendByte(0x65); USART_SendByte(0x74); USART_SendByte(0x0D); USART_SendByte(0x0A); create_out_map( RAMPDN_MAP); DDS_OUT(); } else if (mode==0x41) {//Run Arbitrary Data phase_accumulator=0; Calculate_phase_step(); USART_SendByte(0x44); USART_SendByte(0x44); USART_SendByte(0x53); USART_SendByte(0x5F); USART_SendByte(0x41); USART_SendByte(0x72);USART_SendByte(0x62);USART_SendByte(0x5F); USART_SendByte(0x53); USART_SendByte(0x65); USART_SendByte(0x74); USART_SendByte(0x0D); USART_SendByte(0x0A); /*uint8_t j; for (j=0;j<128;j++){ USART_SendByte(DDS_ARB_BUF[j]); } */ create_out_map( DDS_ARB_BUF); DDS_OUT(); } else if (mode==0x49){//Identify USART_SendByte(0x41); USART_SendByte(0x6A); USART_SendByte(0x5F); USART_SendByte(0x53); USART_SendByte(0x69); USART_SendByte(0x67); USART_SendByte(0x47); USART_SendByte(0x65); USART_SendByte(0x6E);USART_SendByte(0x0D);USART_SendByte(0x0A);//Aj_SigGen mode=42; //break } } }//end of main //Functions BCD Switch--------------------------------------------------------- void pwm_init() { // initialize TCCR0A // Clock select pre-scaler CS02 CS01 CS00 //011=64, 100 =256, 101 =1024 976 Hz / 244Hz / 61 Hz // Frequency would be 16*10^6 /64/256 = TCCR0B |= (1<> 8); /* Load upper 8-bits into the high byte of the UBRR register Default frame format is 8 data bits, no parity, 1 stop bit to change use UCSRC, see AVR data-sheet*/ // Enable receiver and transmitter and receive complete interrupt UCSR0B = ((1< 7 && duty <=21 ){switch_value=1;} else{if (duty> 21 && duty <=35 ){switch_value=2;} else{if (duty>35 && duty <=48){switch_value=3;} else{if (duty> 48 && duty <=60){switch_value=4;} else{if (duty> 60 && duty <=74){switch_value=5;} else{if (duty> 74 && duty <=87){switch_value=6;} else{if (duty> 87 && duty <=100){switch_value=7;} else{if (duty> 100 && duty <=114){switch_value=8;} else{if (duty> 114){switch_value=9;} }}}}}}}}} return (switch_value); } //Functions DDS ------------------------------------------------------------------ void Calculate_phase_step(){ phase_step = phase_step_b0; phase_step = phase_step + ((phase_step_b1*0x100) & 0x0000ffff); phase_step = phase_step+ ((phase_step_b2*0x10000)& 0x00ffffff); } void Calculate_freq(){ //phase_step = freq * 2^24/372kHz //phase_step = freq * 16777216/372093 //phase_step = freq * 45.08 freq = freq_units; //USART_SendByte(freq_units); freq = freq + (freq_tens*10); //USART_SendByte(freq_tens); freq = freq + (freq_hundreds*100); //USART_SendByte(freq_hundreds); freq = freq + (freq_thousands*1000); //USART_SendByte(freq_thousands); freq = freq * freq_mult_10; //Limit to 50kHz if (freq>50000) {freq = 50000;} //calculate phase_step phase_step = freq * 4511;//4508 adjusted to 4512 by practical measurement phase_step = phase_step/100; } //DDS_OUT void DDS_OUT(){ while(1){ // While loop 43 Cycles runs at 372kHz phase_accumulator=phase_accumulator + phase_step; table_index=(phase_accumulator)>>16; //shifting by 8,16 require less cycles table_index=table_index>>1; PORTB=DDS_OUT_MAP[table_index]; if(mode==0x42) break; } } //Function Create DDS_OUT MAP uint8_t create_out_map( uint8_t MAP[128]){ uint8_t i; for (i=0;i<128;i++){ DDS_OUT_MAP[i]= (MAP[i]); //return b; } } void Default_DDS_OUT(){ while(1){ // While loop 43 Cycles runs at 372kHz phase_accumulator=phase_accumulator + 36712;//45080;//this loop is faster table_index=(phase_accumulator)>>16; //shifting by 8,16 require less cycles table_index=table_index>>1; PORTB=SIN_MAP[table_index]; if(mode==0x42) break; } }