Electron Spin Resonance – SW Part

Abstract: In the previous posts (Electron Spin Resonance , Electron Spin Resonance – HW Part) we have described the general principles and the hardware part of our ESR DIY apparatus. In this post we complete the description of the device focusing on the management firmware part and on the data recording software part.

Firmware

The management of the electronic spin resonance apparatus is done with a Cypress PSoC 5lp series microcontroller. It is a so-called “system on chip”. In addition to the classic functionality of a microcontroller, this component integrates advanced features that include precision ADCs and DACs, programmable op amps and FPGA-like logic, all configurable via an easy-to-use graphical and programmable C interface.

The ADC converter is a delta-sigma converter with 18 bit, with range 0 – 6V and the conversion takes place in multiplexer mode. The acquired channels are the trimmer on the board, the Hall sensor signal for the magnetic field and the ESR signal detected and amplified by the lock-in detector. The following image shows the schematic of the ADC part of the PSoC.

The reading of the signal produced by the Hall sensor must be converted into the corresponding value of the magnetic field measured in mT. The following code shows the conversion function.

/*******************************************************************************
* Function Name: CalcBfield
********************************************************************************
* Summary:
* 
********************************************************************************/
double CalcBfield(double HallSensorReading){
  int offsetHallSensor = 2585; // 2585mv means 0mT
  int HallSensorRatio = 100; // 100mV/mT
  double Bfield = (HallSensorReading-offsetHallSensor)/HallSensorRatio; // mag. field in mT 
  return Bfield;
}

We also need the PSoC to measure the frequency of the signal generated by the Robinson oscillator. As described in the previous post on the HW part, the signal is divided by a factor of 128 by a prescaler circuit. The frequency is measured by the counter component as described in the following diagram.

The following code shows the instruction for calculating the frequency.

/* Counter pulse reading - frequency calculation*/
osc_freq = ((Counter_ReadCounter()*(1000.0/readingPeriod))/1000000)*128; //128 presc. factor

Our PSoC also generates the Helmholtz coil driving signal and the 1KHz modulating signal. For this operation the DAC components of the PSoC are used, including the WaveDAC which allows the generation of preset waveforms, as shown in the following diagram.

The driving signal of the Helmholtz coils is an increasing ramp that starts from an initial value of 200mV and ends at the maximum value determined by the reading of the trimmer; the increment steps are 16mV and occur at a rate determined by the stepPeriod variable; the following code shows the ramp implementation.

/* DAC Variables */
static int sweepValue = 0;       // sweep value (mV)
static int sweepInitValue = 200; // init value 200mV
static int sweepEndValue;        // from trimmer
static int stepValue = 16;       // step value 16mV
static int stepPeriod = 250;     // step period 250ms

/*******************************************************************************
* Function Name: SweepingTimerInt_ISR
*******************************************************************************
* Summary:
* Sweeping Timer Interrupt (every period).
*******************************************************************************/
CY_ISR(SweepingTimerInt_ISR){
  /* Calculation of the sweep value */
  sweepValue = sweepInitValue + stepValue*stepCount;
  /* Assign DAC value */
  DACvalue = (uint8)((sweepValue*256)/4096);
  CoilDriver_SetValue(DACvalue);
  /* increment number of steps */
  stepCount++;
  /* check final value reached */
  if(sweepValue >= sweepEndValue){
    /* Reset */
    stepCount = 0;
  }
  /* Reset timer */
  Sweeping_Timer_ReadStatusRegister();
}

Software Python

The data acquired with the PSoC are sent via USB/serial interface to a linux PC running a python program that reads the magnetic field and ESR signal data and plots them in a graph (like the one shown in the cover image). The data is also recorded on csv files for further analysis.
The code below shows an example of the python data acquisition and plotting program.

################################
# serial reading /dev/ttyACM0
# and plotting data
################################

import time
import serial
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

# file definition
filenameESR = "ESRData.csv"
outFile = open(filenameESR,"a+")
outFile.write("**************\n")
outFile.write("** ESR Data **\n")
outFile.write("**************\n")

# parameters
x_len = 500 # time interval 0.1s
y1_range=[0,5] # B field intensity mT
y2_range=[1000,3500] # ESR signal mv

# create figure for plotting
fig = plt.figure()
ax1 = fig.add_subplot(2,1,1)
ax2 = fig.add_subplot(2,1,2)
xs = list(range(0,x_len))
y1s = [0]*x_len
y2s = [0]*x_len
ax1.set_ylim(y1_range)
ax2.set_ylim(y2_range)

# create figure for plotting
ax1.set_title('Magnetic Field')
ax1.set_xlabel('time [0.1s]')
ax1.set_ylabel('B [mT]')
ax2.set_title('ESR Signal')
ax2.set_xlabel('time [0.1s]')
ax2.set_ylabel('Signal [mV]')
plt.subplots_adjust(hspace=0.5)

# init serial
ser=serial.Serial('/dev/ttyACM0')
ser.flushInput()
time.sleep(2) # give time to flush

# create blank line
linea1 = ax1.plot(xs,y1s)[0]
linea2 = ax2.plot(xs,y2s)[0]

# funcion called periodically from FuncAnimation
def animate(i,y1s,y2s,outFile):
  try:
    line=ser.readline().strip()
    BFieldTxt,ESRSignalTxt=line.decode('ascii').split(";",1)
    BField=round(np.float32(BFieldTxt),2)
    ESRSignal=np.int(ESRSignalTxt)
    #print('BField',BField)
    #print('ESRSignal',ESRSignal)
    outFile.write(BFieldTxt+","+ESRSignalTxt+"\n")
  except ValueError:
    print('failed to read serial')

# add data to lists
y1s.append(BField)
y1s=y1s[-x_len:]

y2s.append(ESRSignal)
y2s=y2s[-x_len:]

# update lines
linea1.set_ydata(y1s)
linea2.set_ydata(y2s)

return linea1,linea2

# animation
ani = animation.FuncAnimation(fig,animate,fargs=(y1s,y2s,outFile),interval=100,blit=True)
plt.show()

Conclusions

With this post we conclude the description of our DIY apparatus for electronic spin resonance. In the next post we will describe some experimental measurements carried out with our apparatus.

If you liked this post you can share it on the “social” Facebook, Twitter or LinkedIn with the buttons below. This way you can help us! Thank you !

Donation

If you like this site and if you want to contribute to the development of the activities you can make a donation, thank you !

Check Also

CALL for Donations

The PhysicsOpenLab adventure has lasted for several years now. They were beautiful years in which …