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@1:bf693859586c, 2017-08-21 (annotated)
- Committer:
- Nikollao
- Date:
- Mon Aug 21 11:43:03 2017 +0000
- Revision:
- 1:bf693859586c
- Parent:
- 0:4e20939af8bb
- Child:
- 2:c9b24787d5e1
Fast LIA done with PIN A5 working!
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 | 0:4e20939af8bb | 6 | dref.rise(&voltageRise); /// set interrupt to calculate reference frequency |
Nikollao | 0:4e20939af8bb | 7 | setupK64Fclocks(); |
Nikollao | 0:4e20939af8bb | 8 | /// initialise DAC output dac0_out |
Nikollao | 0:4e20939af8bb | 9 | while (ref_freq < 1e2) { |
Nikollao | 0:4e20939af8bb | 10 | sleep(); |
Nikollao | 0:4e20939af8bb | 11 | } |
Nikollao | 0:4e20939af8bb | 12 | /// make sure frequency is read before we go to the program |
Nikollao | 0:4e20939af8bb | 13 | /// cancel event-triggered rise interrupt, not to interfere with program |
Nikollao | 0:4e20939af8bb | 14 | dref.rise(NULL); |
Nikollao | 0:4e20939af8bb | 15 | pc.printf("Ref_Freq is:%.2f kHz\n\r",ref_freq*0.001); |
Nikollao | 1:bf693859586c | 16 | /// constant 6 for correct sampling time |
Nikollao | 1:bf693859586c | 17 | /// compensates for delay caused by computations |
Nikollao | 0:4e20939af8bb | 18 | sample_freq = 6*samples16*ref_freq; |
Nikollao | 0:4e20939af8bb | 19 | sample_time = 1/sample_freq; |
Nikollao | 0:4e20939af8bb | 20 | |
Nikollao | 0:4e20939af8bb | 21 | initDAC(); |
Nikollao | 0:4e20939af8bb | 22 | delay_freq = ref_freq*amp_points; |
Nikollao | 0:4e20939af8bb | 23 | amplitude_delay = 1/delay_freq; |
Nikollao | 1:bf693859586c | 24 | /// find the offset of the signal |
Nikollao | 0:4e20939af8bb | 25 | offset_ticker.attach(&offset_isr,0.001); |
Nikollao | 0:4e20939af8bb | 26 | |
Nikollao | 0:4e20939af8bb | 27 | while (offset == 0) { |
Nikollao | 0:4e20939af8bb | 28 | if (g_offset_flag == 1) { |
Nikollao | 0:4e20939af8bb | 29 | g_offset_flag = 0; |
Nikollao | 0:4e20939af8bb | 30 | offset = mavg_filter(filter_points); |
Nikollao | 0:4e20939af8bb | 31 | } |
Nikollao | 0:4e20939af8bb | 32 | sleep(); |
Nikollao | 0:4e20939af8bb | 33 | } |
Nikollao | 0:4e20939af8bb | 34 | offset_ticker.detach(); |
Nikollao | 1:bf693859586c | 35 | /// once the offset is calculated detach the offset ticker |
Nikollao | 1:bf693859586c | 36 | /// attach the output ticker to update every 1 ms |
Nikollao | 0:4e20939af8bb | 37 | output_ticker.attach(&output_isr,0.00099); |
Nikollao | 0:4e20939af8bb | 38 | |
Nikollao | 0:4e20939af8bb | 39 | while (true) { |
Nikollao | 0:4e20939af8bb | 40 | // gpo = !gpo; |
Nikollao | 1:bf693859586c | 41 | digitalMix(offset); /// perform digital mixing |
Nikollao | 1:bf693859586c | 42 | while (g_output_flag == 0) {sleep();} /// sleep until flag is set |
Nikollao | 1:bf693859586c | 43 | /// update output |
Nikollao | 0:4e20939af8bb | 44 | if (g_output_flag == 1) { |
Nikollao | 0:4e20939af8bb | 45 | g_output_flag = 0; |
Nikollao | 0:4e20939af8bb | 46 | //aout = max(samples16); |
Nikollao | 1:bf693859586c | 47 | aout = 2*max(samples16); |
Nikollao | 1:bf693859586c | 48 | /// DC output by taking the maximum value of the mixed signal (R) |
Nikollao | 0:4e20939af8bb | 49 | } |
Nikollao | 0:4e20939af8bb | 50 | } |
Nikollao | 0:4e20939af8bb | 51 | } |
Nikollao | 0:4e20939af8bb | 52 | |
Nikollao | 0:4e20939af8bb | 53 | double max(int points) |
Nikollao | 0:4e20939af8bb | 54 | { |
Nikollao | 0:4e20939af8bb | 55 | double amp = 0; |
Nikollao | 0:4e20939af8bb | 56 | |
Nikollao | 0:4e20939af8bb | 57 | for (int i = 0; i < points; i++) { |
Nikollao | 0:4e20939af8bb | 58 | if (amp < R[i]) |
Nikollao | 1:bf693859586c | 59 | amp = R[i]; /// find max of R |
Nikollao | 0:4e20939af8bb | 60 | //wait(amplitude_delay); |
Nikollao | 0:4e20939af8bb | 61 | } |
Nikollao | 0:4e20939af8bb | 62 | return amp; |
Nikollao | 0:4e20939af8bb | 63 | } |
Nikollao | 0:4e20939af8bb | 64 | |
Nikollao | 0:4e20939af8bb | 65 | double mavg_filter(int filt_points) |
Nikollao | 0:4e20939af8bb | 66 | { |
Nikollao | 0:4e20939af8bb | 67 | double avg = 0, signal = 0; |
Nikollao | 0:4e20939af8bb | 68 | double delay = 0.9/(1*ref_freq*filter_points); |
Nikollao | 0:4e20939af8bb | 69 | for (int i = 0; i < filter_points; i++) { |
Nikollao | 0:4e20939af8bb | 70 | signal = ain.read(); |
Nikollao | 0:4e20939af8bb | 71 | avg = avg + signal; |
Nikollao | 0:4e20939af8bb | 72 | wait((float)(5e-5)); |
Nikollao | 0:4e20939af8bb | 73 | } |
Nikollao | 1:bf693859586c | 74 | avg = avg/filter_points; /// find offset of input signal |
Nikollao | 0:4e20939af8bb | 75 | return avg; |
Nikollao | 0:4e20939af8bb | 76 | } |
Nikollao | 0:4e20939af8bb | 77 | |
Nikollao | 0:4e20939af8bb | 78 | void digitalMix(double remove_offset) { |
Nikollao | 0:4e20939af8bb | 79 | /// perform mixing of input and reference signals |
Nikollao | 0:4e20939af8bb | 80 | double input = 0; |
Nikollao | 0:4e20939af8bb | 81 | for (int i = 0; i < samples16;i++) { |
Nikollao | 0:4e20939af8bb | 82 | /// remove the offset before doing the multiplication of signals |
Nikollao | 0:4e20939af8bb | 83 | input = ain.read()-remove_offset; |
Nikollao | 0:4e20939af8bb | 84 | /// find the X component by multiplying with sine 17 values array |
Nikollao | 0:4e20939af8bb | 85 | double refX = input*sin_array16[i]; |
Nikollao | 0:4e20939af8bb | 86 | /// find the Y component by multiplying with cosine 17 values array |
Nikollao | 0:4e20939af8bb | 87 | double refY = input*cos_array16[i]; |
Nikollao | 0:4e20939af8bb | 88 | //double XY = exp(2*log(refX))+exp(2*log(refY)); |
Nikollao | 0:4e20939af8bb | 89 | double XY = (refX*refX)+(refY*refY); /// R square |
Nikollao | 0:4e20939af8bb | 90 | //double R = exp(0.5*log(XY))/4; |
Nikollao | 0:4e20939af8bb | 91 | R[i] = pow(XY,0.5); /// R |
Nikollao | 0:4e20939af8bb | 92 | //aout = (1+sin_array16[i])/4; |
Nikollao | 0:4e20939af8bb | 93 | //aout = R[i]/2; |
Nikollao | 0:4e20939af8bb | 94 | wait(sample_time); /// sample time |
Nikollao | 0:4e20939af8bb | 95 | } |
Nikollao | 0:4e20939af8bb | 96 | } |
Nikollao | 0:4e20939af8bb | 97 | |
Nikollao | 0:4e20939af8bb | 98 | void voltageRise() { |
Nikollao | 0:4e20939af8bb | 99 | if (g_counter == 1) { |
Nikollao | 0:4e20939af8bb | 100 | /// first time function is called is the first rise |
Nikollao | 0:4e20939af8bb | 101 | /// start timer |
Nikollao | 0:4e20939af8bb | 102 | period_timer.start(); |
Nikollao | 0:4e20939af8bb | 103 | /// increase counter so next time function is called we calculate freq. |
Nikollao | 0:4e20939af8bb | 104 | g_counter++; |
Nikollao | 0:4e20939af8bb | 105 | } |
Nikollao | 0:4e20939af8bb | 106 | else if (g_counter == 2) { |
Nikollao | 0:4e20939af8bb | 107 | /// second time function is called is the second rise |
Nikollao | 0:4e20939af8bb | 108 | /// stop timer |
Nikollao | 0:4e20939af8bb | 109 | period_timer.stop(); |
Nikollao | 0:4e20939af8bb | 110 | /// calculate the time taken between the two rises to find period |
Nikollao | 0:4e20939af8bb | 111 | ref_period = period_timer.read(); |
Nikollao | 0:4e20939af8bb | 112 | /// frequency is the inverse of the signal period |
Nikollao | 0:4e20939af8bb | 113 | ref_freq = 1/ref_period; |
Nikollao | 0:4e20939af8bb | 114 | /// reset timer |
Nikollao | 0:4e20939af8bb | 115 | period_timer.reset(); |
Nikollao | 0:4e20939af8bb | 116 | /// increase counter because we only want to calculate once per cycle |
Nikollao | 0:4e20939af8bb | 117 | /// if we want to actively track the ref_freq we should decrease counter |
Nikollao | 0:4e20939af8bb | 118 | g_counter++; |
Nikollao | 0:4e20939af8bb | 119 | } |
Nikollao | 0:4e20939af8bb | 120 | } |
Nikollao | 0:4e20939af8bb | 121 | |
Nikollao | 0:4e20939af8bb | 122 | void setupK64Fclocks() { |
Nikollao | 0:4e20939af8bb | 123 | if(1) { |
Nikollao | 0:4e20939af8bb | 124 | uint32_t div1=0,div2=0,busClk=0,adcClk=0; |
Nikollao | 0:4e20939af8bb | 125 | SystemCoreClockUpdate(); |
Nikollao | 0:4e20939af8bb | 126 | pc.printf("SystemCoreClock= %u \r\n",SystemCoreClock); |
Nikollao | 0:4e20939af8bb | 127 | /// System Core Clock: 120 MHz |
Nikollao | 0:4e20939af8bb | 128 | div1=( (SIM->CLKDIV1) & SIM_CLKDIV1_OUTDIV1_MASK)>>SIM_CLKDIV1_OUTDIV1_SHIFT; |
Nikollao | 0:4e20939af8bb | 129 | div1=1+div1; |
Nikollao | 0:4e20939af8bb | 130 | div2=1+( (SIM->CLKDIV1) & SIM_CLKDIV1_OUTDIV2_MASK)>>SIM_CLKDIV1_OUTDIV2_SHIFT; |
Nikollao | 0:4e20939af8bb | 131 | busClk=SystemCoreClock*div1/div2; |
Nikollao | 0:4e20939af8bb | 132 | pc.printf("Divider1== %u div2=%u \r\n",div1,div2); |
Nikollao | 0:4e20939af8bb | 133 | pc.printf("MCGOUTCLK= %u, busClk = %u \r\n",SystemCoreClock*div1,busClk); |
Nikollao | 0:4e20939af8bb | 134 | /// MCGOUTCLK 120 MHz, Bus Clock = 120 MHz |
Nikollao | 1:bf693859586c | 135 | ADC1->SC3 &= ~ADC_SC3_AVGE_MASK;//disable averages |
Nikollao | 1:bf693859586c | 136 | ADC1->CFG1 &= ~ADC_CFG1_ADLPC_MASK;//high-power mode |
Nikollao | 1:bf693859586c | 137 | ADC1->CFG1 &= ~0x0063 ; //clears ADICLK and ADIV |
Nikollao | 1:bf693859586c | 138 | ADC1->CFG1 |= ADC_CFG1_ADIV(2); //divide clock 0=/1, 1=/2, 2=/4, 3=/8 |
Nikollao | 0:4e20939af8bb | 139 | //ADC0->SC3 |= 0x0007;//enable 32 averages |
Nikollao | 0:4e20939af8bb | 140 | |
Nikollao | 1:bf693859586c | 141 | if (((ADC1->CFG1)& 0x03) == 0) adcClk = busClk/(0x01<<(((ADC1->CFG1)&0x60)>>5)); |
Nikollao | 1:bf693859586c | 142 | if (((ADC1->SC3)& 0x04) != 0) adcClk = adcClk/(0x01<<(((ADC1->SC3)&0x03)+2)); |
Nikollao | 0:4e20939af8bb | 143 | pc.printf("adcCLK= %u \r\n",adcClk); |
Nikollao | 0:4e20939af8bb | 144 | /// ADC Clock: 60 MHz |
Nikollao | 0:4e20939af8bb | 145 | } |
Nikollao | 0:4e20939af8bb | 146 | } |
Nikollao | 0:4e20939af8bb | 147 | |
Nikollao | 0:4e20939af8bb | 148 | void offset_isr() { |
Nikollao | 0:4e20939af8bb | 149 | g_offset_flag = 1; |
Nikollao | 0:4e20939af8bb | 150 | } |
Nikollao | 0:4e20939af8bb | 151 | |
Nikollao | 0:4e20939af8bb | 152 | void output_isr() { |
Nikollao | 0:4e20939af8bb | 153 | g_output_flag = 1; |
Nikollao | 0:4e20939af8bb | 154 | } |
Nikollao | 0:4e20939af8bb | 155 | |
Nikollao | 0:4e20939af8bb | 156 | void initDAC() { |
Nikollao | 0:4e20939af8bb | 157 | DAC0->C0 = 0; |
Nikollao | 0:4e20939af8bb | 158 | DAC0->C1 = 0; //reset DAC state |
Nikollao | 0:4e20939af8bb | 159 | DAC0->C0 = DAC_C0_DACEN_MASK | DAC_C0_DACSWTRG_MASK| DAC_C0_DACRFS_MASK; |
Nikollao | 0:4e20939af8bb | 160 | } |