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.
main.cpp@2:c9b24787d5e1, 2017-08-25 (annotated)
- 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?
User | Revision | Line number | New 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 | } |