The project is a fast lock in amplifier (LIA) which can update its output at rate of 1000 measurements/s. It performs digital dual mixing and filtering to obtain a DC value proportional to the AC input signal.

Dependencies:   N5110 mbed

Committer:
Nikollao
Date:
Fri Aug 25 10:22:51 2017 +0000
Revision:
2:c9b24787d5e1
Parent:
1:bf693859586c
Child:
3:dd4eb355f8d9
setting up the settings menu to adjust output gain and speed

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Nikollao 0:4e20939af8bb 1 #include "main.h"
Nikollao 0:4e20939af8bb 2
Nikollao 0:4e20939af8bb 3 int main()
Nikollao 0:4e20939af8bb 4 {
Nikollao 0:4e20939af8bb 5 pc.baud(115200);
Nikollao 2:c9b24787d5e1 6 lcd_intro();
Nikollao 2:c9b24787d5e1 7 calibrateJoystick(); ///calibrate joystick
Nikollao 2:c9b24787d5e1 8 settings_menu();
Nikollao 0:4e20939af8bb 9 dref.rise(&voltageRise); /// set interrupt to calculate reference frequency
Nikollao 0:4e20939af8bb 10 setupK64Fclocks();
Nikollao 2:c9b24787d5e1 11 //settings_menu();
Nikollao 0:4e20939af8bb 12 /// initialise DAC output dac0_out
Nikollao 0:4e20939af8bb 13 while (ref_freq < 1e2) {
Nikollao 0:4e20939af8bb 14 sleep();
Nikollao 0:4e20939af8bb 15 }
Nikollao 0:4e20939af8bb 16 /// make sure frequency is read before we go to the program
Nikollao 0:4e20939af8bb 17 /// cancel event-triggered rise interrupt, not to interfere with program
Nikollao 0:4e20939af8bb 18 dref.rise(NULL);
Nikollao 0:4e20939af8bb 19 pc.printf("Ref_Freq is:%.2f kHz\n\r",ref_freq*0.001);
Nikollao 1:bf693859586c 20 /// constant 6 for correct sampling time
Nikollao 1:bf693859586c 21 /// compensates for delay caused by computations
Nikollao 0:4e20939af8bb 22 sample_freq = 6*samples16*ref_freq;
Nikollao 0:4e20939af8bb 23 sample_time = 1/sample_freq;
Nikollao 0:4e20939af8bb 24
Nikollao 0:4e20939af8bb 25 initDAC();
Nikollao 0:4e20939af8bb 26 delay_freq = ref_freq*amp_points;
Nikollao 0:4e20939af8bb 27 amplitude_delay = 1/delay_freq;
Nikollao 1:bf693859586c 28 /// find the offset of the signal
Nikollao 0:4e20939af8bb 29 offset_ticker.attach(&offset_isr,0.001);
Nikollao 0:4e20939af8bb 30
Nikollao 0:4e20939af8bb 31 while (offset == 0) {
Nikollao 0:4e20939af8bb 32 if (g_offset_flag == 1) {
Nikollao 0:4e20939af8bb 33 g_offset_flag = 0;
Nikollao 0:4e20939af8bb 34 offset = mavg_filter(filter_points);
Nikollao 0:4e20939af8bb 35 }
Nikollao 0:4e20939af8bb 36 sleep();
Nikollao 0:4e20939af8bb 37 }
Nikollao 0:4e20939af8bb 38 offset_ticker.detach();
Nikollao 1:bf693859586c 39 /// once the offset is calculated detach the offset ticker
Nikollao 1:bf693859586c 40 /// attach the output ticker to update every 1 ms
Nikollao 0:4e20939af8bb 41 output_ticker.attach(&output_isr,0.00099);
Nikollao 0:4e20939af8bb 42
Nikollao 0:4e20939af8bb 43 while (true) {
Nikollao 0:4e20939af8bb 44 // gpo = !gpo;
Nikollao 1:bf693859586c 45 digitalMix(offset); /// perform digital mixing
Nikollao 1:bf693859586c 46 while (g_output_flag == 0) {sleep();} /// sleep until flag is set
Nikollao 1:bf693859586c 47 /// update output
Nikollao 0:4e20939af8bb 48 if (g_output_flag == 1) {
Nikollao 0:4e20939af8bb 49 g_output_flag = 0;
Nikollao 0:4e20939af8bb 50 //aout = max(samples16);
Nikollao 1:bf693859586c 51 aout = 2*max(samples16);
Nikollao 1:bf693859586c 52 /// DC output by taking the maximum value of the mixed signal (R)
Nikollao 0:4e20939af8bb 53 }
Nikollao 0:4e20939af8bb 54 }
Nikollao 0:4e20939af8bb 55 }
Nikollao 0:4e20939af8bb 56
Nikollao 0:4e20939af8bb 57 double max(int points)
Nikollao 0:4e20939af8bb 58 {
Nikollao 0:4e20939af8bb 59 double amp = 0;
Nikollao 0:4e20939af8bb 60
Nikollao 0:4e20939af8bb 61 for (int i = 0; i < points; i++) {
Nikollao 0:4e20939af8bb 62 if (amp < R[i])
Nikollao 1:bf693859586c 63 amp = R[i]; /// find max of R
Nikollao 0:4e20939af8bb 64 //wait(amplitude_delay);
Nikollao 0:4e20939af8bb 65 }
Nikollao 0:4e20939af8bb 66 return amp;
Nikollao 0:4e20939af8bb 67 }
Nikollao 0:4e20939af8bb 68
Nikollao 0:4e20939af8bb 69 double mavg_filter(int filt_points)
Nikollao 0:4e20939af8bb 70 {
Nikollao 0:4e20939af8bb 71 double avg = 0, signal = 0;
Nikollao 2:c9b24787d5e1 72 //double delay = 0.9/(1*ref_freq*filter_points);
Nikollao 0:4e20939af8bb 73 for (int i = 0; i < filter_points; i++) {
Nikollao 0:4e20939af8bb 74 signal = ain.read();
Nikollao 0:4e20939af8bb 75 avg = avg + signal;
Nikollao 0:4e20939af8bb 76 wait((float)(5e-5));
Nikollao 0:4e20939af8bb 77 }
Nikollao 1:bf693859586c 78 avg = avg/filter_points; /// find offset of input signal
Nikollao 0:4e20939af8bb 79 return avg;
Nikollao 0:4e20939af8bb 80 }
Nikollao 0:4e20939af8bb 81
Nikollao 0:4e20939af8bb 82 void digitalMix(double remove_offset) {
Nikollao 0:4e20939af8bb 83 /// perform mixing of input and reference signals
Nikollao 0:4e20939af8bb 84 double input = 0;
Nikollao 0:4e20939af8bb 85 for (int i = 0; i < samples16;i++) {
Nikollao 0:4e20939af8bb 86 /// remove the offset before doing the multiplication of signals
Nikollao 0:4e20939af8bb 87 input = ain.read()-remove_offset;
Nikollao 0:4e20939af8bb 88 /// find the X component by multiplying with sine 17 values array
Nikollao 0:4e20939af8bb 89 double refX = input*sin_array16[i];
Nikollao 0:4e20939af8bb 90 /// find the Y component by multiplying with cosine 17 values array
Nikollao 0:4e20939af8bb 91 double refY = input*cos_array16[i];
Nikollao 0:4e20939af8bb 92 //double XY = exp(2*log(refX))+exp(2*log(refY));
Nikollao 0:4e20939af8bb 93 double XY = (refX*refX)+(refY*refY); /// R square
Nikollao 0:4e20939af8bb 94 //double R = exp(0.5*log(XY))/4;
Nikollao 0:4e20939af8bb 95 R[i] = pow(XY,0.5); /// R
Nikollao 0:4e20939af8bb 96 //aout = (1+sin_array16[i])/4;
Nikollao 0:4e20939af8bb 97 //aout = R[i]/2;
Nikollao 0:4e20939af8bb 98 wait(sample_time); /// sample time
Nikollao 0:4e20939af8bb 99 }
Nikollao 0:4e20939af8bb 100 }
Nikollao 0:4e20939af8bb 101
Nikollao 0:4e20939af8bb 102 void voltageRise() {
Nikollao 0:4e20939af8bb 103 if (g_counter == 1) {
Nikollao 0:4e20939af8bb 104 /// first time function is called is the first rise
Nikollao 0:4e20939af8bb 105 /// start timer
Nikollao 0:4e20939af8bb 106 period_timer.start();
Nikollao 0:4e20939af8bb 107 /// increase counter so next time function is called we calculate freq.
Nikollao 0:4e20939af8bb 108 g_counter++;
Nikollao 0:4e20939af8bb 109 }
Nikollao 0:4e20939af8bb 110 else if (g_counter == 2) {
Nikollao 0:4e20939af8bb 111 /// second time function is called is the second rise
Nikollao 0:4e20939af8bb 112 /// stop timer
Nikollao 0:4e20939af8bb 113 period_timer.stop();
Nikollao 0:4e20939af8bb 114 /// calculate the time taken between the two rises to find period
Nikollao 0:4e20939af8bb 115 ref_period = period_timer.read();
Nikollao 0:4e20939af8bb 116 /// frequency is the inverse of the signal period
Nikollao 0:4e20939af8bb 117 ref_freq = 1/ref_period;
Nikollao 0:4e20939af8bb 118 /// reset timer
Nikollao 0:4e20939af8bb 119 period_timer.reset();
Nikollao 0:4e20939af8bb 120 /// increase counter because we only want to calculate once per cycle
Nikollao 0:4e20939af8bb 121 /// if we want to actively track the ref_freq we should decrease counter
Nikollao 0:4e20939af8bb 122 g_counter++;
Nikollao 0:4e20939af8bb 123 }
Nikollao 0:4e20939af8bb 124 }
Nikollao 0:4e20939af8bb 125
Nikollao 0:4e20939af8bb 126 void setupK64Fclocks() {
Nikollao 0:4e20939af8bb 127 if(1) {
Nikollao 0:4e20939af8bb 128 uint32_t div1=0,div2=0,busClk=0,adcClk=0;
Nikollao 0:4e20939af8bb 129 SystemCoreClockUpdate();
Nikollao 0:4e20939af8bb 130 pc.printf("SystemCoreClock= %u \r\n",SystemCoreClock);
Nikollao 0:4e20939af8bb 131 /// System Core Clock: 120 MHz
Nikollao 0:4e20939af8bb 132 div1=( (SIM->CLKDIV1) & SIM_CLKDIV1_OUTDIV1_MASK)>>SIM_CLKDIV1_OUTDIV1_SHIFT;
Nikollao 0:4e20939af8bb 133 div1=1+div1;
Nikollao 0:4e20939af8bb 134 div2=1+( (SIM->CLKDIV1) & SIM_CLKDIV1_OUTDIV2_MASK)>>SIM_CLKDIV1_OUTDIV2_SHIFT;
Nikollao 0:4e20939af8bb 135 busClk=SystemCoreClock*div1/div2;
Nikollao 0:4e20939af8bb 136 pc.printf("Divider1== %u div2=%u \r\n",div1,div2);
Nikollao 0:4e20939af8bb 137 pc.printf("MCGOUTCLK= %u, busClk = %u \r\n",SystemCoreClock*div1,busClk);
Nikollao 0:4e20939af8bb 138 /// MCGOUTCLK 120 MHz, Bus Clock = 120 MHz
Nikollao 1:bf693859586c 139 ADC1->SC3 &= ~ADC_SC3_AVGE_MASK;//disable averages
Nikollao 1:bf693859586c 140 ADC1->CFG1 &= ~ADC_CFG1_ADLPC_MASK;//high-power mode
Nikollao 1:bf693859586c 141 ADC1->CFG1 &= ~0x0063 ; //clears ADICLK and ADIV
Nikollao 1:bf693859586c 142 ADC1->CFG1 |= ADC_CFG1_ADIV(2); //divide clock 0=/1, 1=/2, 2=/4, 3=/8
Nikollao 0:4e20939af8bb 143 //ADC0->SC3 |= 0x0007;//enable 32 averages
Nikollao 0:4e20939af8bb 144
Nikollao 1:bf693859586c 145 if (((ADC1->CFG1)& 0x03) == 0) adcClk = busClk/(0x01<<(((ADC1->CFG1)&0x60)>>5));
Nikollao 1:bf693859586c 146 if (((ADC1->SC3)& 0x04) != 0) adcClk = adcClk/(0x01<<(((ADC1->SC3)&0x03)+2));
Nikollao 0:4e20939af8bb 147 pc.printf("adcCLK= %u \r\n",adcClk);
Nikollao 0:4e20939af8bb 148 /// ADC Clock: 60 MHz
Nikollao 0:4e20939af8bb 149 }
Nikollao 0:4e20939af8bb 150 }
Nikollao 0:4e20939af8bb 151
Nikollao 0:4e20939af8bb 152 void offset_isr() {
Nikollao 0:4e20939af8bb 153 g_offset_flag = 1;
Nikollao 0:4e20939af8bb 154 }
Nikollao 0:4e20939af8bb 155
Nikollao 0:4e20939af8bb 156 void output_isr() {
Nikollao 0:4e20939af8bb 157 g_output_flag = 1;
Nikollao 0:4e20939af8bb 158 }
Nikollao 0:4e20939af8bb 159
Nikollao 0:4e20939af8bb 160 void initDAC() {
Nikollao 0:4e20939af8bb 161 DAC0->C0 = 0;
Nikollao 0:4e20939af8bb 162 DAC0->C1 = 0; //reset DAC state
Nikollao 0:4e20939af8bb 163 DAC0->C0 = DAC_C0_DACEN_MASK | DAC_C0_DACSWTRG_MASK| DAC_C0_DACRFS_MASK;
Nikollao 0:4e20939af8bb 164 }
Nikollao 2:c9b24787d5e1 165 void lcd_intro()
Nikollao 2:c9b24787d5e1 166 {
Nikollao 2:c9b24787d5e1 167 lcd.init();
Nikollao 2:c9b24787d5e1 168 lcd.setBrightness(0.7); // put LED backlight on 50%
Nikollao 2:c9b24787d5e1 169 lcd.printString("THE CIRCUIT IS",1,1);
Nikollao 2:c9b24787d5e1 170 lcd.printString("A FAST LIA!",7,3);
Nikollao 2:c9b24787d5e1 171 lcd.refresh();
Nikollao 2:c9b24787d5e1 172 Timeout timeout;
Nikollao 2:c9b24787d5e1 173 timeout.attach(&timeout_isr,3);
Nikollao 2:c9b24787d5e1 174 sleep();
Nikollao 2:c9b24787d5e1 175 lcd.clear();
Nikollao 2:c9b24787d5e1 176 }
Nikollao 2:c9b24787d5e1 177
Nikollao 2:c9b24787d5e1 178 void settings_menu()
Nikollao 2:c9b24787d5e1 179 {
Nikollao 2:c9b24787d5e1 180 lcd.setBrightness(0.7); // put LED backlight on 50%
Nikollao 2:c9b24787d5e1 181 menu_ticker.attach(&menu_isr,0.2);
Nikollao 2:c9b24787d5e1 182
Nikollao 2:c9b24787d5e1 183 while (exit_menu == 0) {
Nikollao 2:c9b24787d5e1 184 if (g_menu_flag == 1) {
Nikollao 2:c9b24787d5e1 185 g_menu_flag = 0;
Nikollao 2:c9b24787d5e1 186
Nikollao 2:c9b24787d5e1 187 updateJoystick();
Nikollao 2:c9b24787d5e1 188 lcd.clear();
Nikollao 2:c9b24787d5e1 189
Nikollao 2:c9b24787d5e1 190 lcd.printString("Settings:",0,0);
Nikollao 2:c9b24787d5e1 191
Nikollao 2:c9b24787d5e1 192 char gain_char[20]; ///create an array of chars
Nikollao 2:c9b24787d5e1 193 sprintf(gain_char,"Gain:%.2f",var_gain); ///create string
Nikollao 2:c9b24787d5e1 194
Nikollao 2:c9b24787d5e1 195 char speed_char[20]; ///create an array of chars
Nikollao 2:c9b24787d5e1 196 sprintf(speed_char,"Speed:%.2f",var_speed); ///create string
Nikollao 2:c9b24787d5e1 197
Nikollao 2:c9b24787d5e1 198 lcd.printString(gain_char,0,2);
Nikollao 2:c9b24787d5e1 199 lcd.printString(speed_char,0,3);
Nikollao 2:c9b24787d5e1 200 lcd.refresh();
Nikollao 2:c9b24787d5e1 201 }
Nikollao 2:c9b24787d5e1 202 sleep();
Nikollao 2:c9b24787d5e1 203 }
Nikollao 2:c9b24787d5e1 204 }
Nikollao 2:c9b24787d5e1 205
Nikollao 2:c9b24787d5e1 206 void menu_isr() {
Nikollao 2:c9b24787d5e1 207 g_menu_flag = 1;
Nikollao 2:c9b24787d5e1 208 }
Nikollao 2:c9b24787d5e1 209
Nikollao 2:c9b24787d5e1 210 void timeout_isr() {}
Nikollao 2:c9b24787d5e1 211
Nikollao 2:c9b24787d5e1 212 void calibrateJoystick()
Nikollao 2:c9b24787d5e1 213 {
Nikollao 2:c9b24787d5e1 214 // must not move during calibration
Nikollao 2:c9b24787d5e1 215 joystick.x0 = xPot; // initial positions in the range 0.0 to 1.0 (0.5 if centred exactly)
Nikollao 2:c9b24787d5e1 216 joystick.y0 = yPot;
Nikollao 2:c9b24787d5e1 217 }
Nikollao 2:c9b24787d5e1 218
Nikollao 2:c9b24787d5e1 219 void updateJoystick()
Nikollao 2:c9b24787d5e1 220 {
Nikollao 2:c9b24787d5e1 221 // read current joystick values relative to calibrated values (in range -0.5 to 0.5, 0.0 is centred)
Nikollao 2:c9b24787d5e1 222 joystick.x = xPot - joystick.x0;
Nikollao 2:c9b24787d5e1 223 joystick.y = yPot - joystick.y0;
Nikollao 2:c9b24787d5e1 224 // read button state
Nikollao 2:c9b24787d5e1 225 joystick.button = joy_button;
Nikollao 2:c9b24787d5e1 226
Nikollao 2:c9b24787d5e1 227 // calculate direction depending on x,y values
Nikollao 2:c9b24787d5e1 228 // tolerance allows a little lee-way in case joystick not exactly in the stated direction
Nikollao 2:c9b24787d5e1 229 if ( fabs(joystick.y) < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
Nikollao 2:c9b24787d5e1 230 joystick.direction = CENTRE;
Nikollao 2:c9b24787d5e1 231 } else if ( joystick.y > DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
Nikollao 2:c9b24787d5e1 232 joystick.direction = UP;
Nikollao 2:c9b24787d5e1 233 } else if ( joystick.y < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
Nikollao 2:c9b24787d5e1 234 joystick.direction = DOWN;
Nikollao 2:c9b24787d5e1 235 } else if ( joystick.x > DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
Nikollao 2:c9b24787d5e1 236 joystick.direction = RIGHT;
Nikollao 2:c9b24787d5e1 237 } else if ( joystick.x < DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
Nikollao 2:c9b24787d5e1 238 joystick.direction = LEFT;
Nikollao 2:c9b24787d5e1 239 } /*else if (joystick.y > DIRECTION_TOLERANCE && joystick.x < DIRECTION_TOLERANCE) {
Nikollao 2:c9b24787d5e1 240 joystick.direction = UP_LEFT;
Nikollao 2:c9b24787d5e1 241 } else if (joystick.y > DIRECTION_TOLERANCE && joystick.x > DIRECTION_TOLERANCE) {
Nikollao 2:c9b24787d5e1 242 joystick.direction = UP_RIGHT;
Nikollao 2:c9b24787d5e1 243 } else if (joystick.y < DIRECTION_TOLERANCE && joystick.x < DIRECTION_TOLERANCE) {
Nikollao 2:c9b24787d5e1 244 joystick.direction = DOWN_LEFT;
Nikollao 2:c9b24787d5e1 245 } else if (joystick.y < DIRECTION_TOLERANCE && joystick.x > DIRECTION_TOLERANCE) {
Nikollao 2:c9b24787d5e1 246 joystick.direction = DOWN_RIGHT;
Nikollao 2:c9b24787d5e1 247 }*/
Nikollao 2:c9b24787d5e1 248 }