Announcement

Collapse
No announcement yet.

STM32 Smart Metal Detector Project

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • STM32 Smart Metal Detector Project

    Hi friends


    I recently started working on a new STM32 Smart Metal Detector that is based on STM32F103RE and on the BLE module nRF51822 which is used to communicate with the phone and to update the firmware my first code is based on this sketch http://github.com/dc42/arduino/blob/...alDetector.ino which I edited to work on STM32 with parts working well I want to ask you if anyone who could help me with a code that is pretty complicated and my STM32 programming skills are not up to so good i would like if someone advised me how to work ground balance and how to integrate it into my code. I also attach some photo of the first pcb that can be integrated into the original XP Deus coil.
    Attached Files

  • #2
    Good Luck on an ambitious project. I think the 8-bit ADC resolution will cause you problems eventually - commercial machines tend to use 12-bit converters if they have some compression circuitry in analogue circuitry, or 16 - 20 bit ADC if no hardware compression is used.
    As you're running the coil at a fixed frequency, you should be able to improve the IB null of the coil, using small bits of ferrite, placed close to the searchcoil. This should allow you to reduce the pre-amp output signal level. This would allow you to increase circuit gain, and achieve better results from your low ADC bit-count method.

    A quick look through the code source shows it takes the square-root of a number in order to compute the vector amplitude of the signal. It seems to me that this is unnecessary. If all you are doing is comparing to a threshold, the simpler "sum of the squares" value is enough.

    To be honest, adding 'ground balance' is not going to help the performance of this detector much.

    Comment


    • #3
      Thank you for your reply STM32F103RE has 12bit ADC so it should be a problem with resolution I will be grateful for all your advice and suggestions if you have any idea how to edit the code to work better you can add it here tomorrow I will add my code that works but not yet ground balance.

      Comment


      • #4
        I quote from the github code:
        "Induction balance metal detector.
        We run the CPU at 16MHz and the ADC clock at 1MHz. ADC resolution is reduced to 8 bits at this speed.
        "

        I'm not a code expert, so can offer little advice about this matter.

        Comment


        • #5
          The code on Github is written for ATmega328P and it works max on 20Mhz I think STM32 works in the range of 48-128Mhz code on Github was just an example I overwrite to work on STM32.

          Comment


          • #6
            Hello friends

            I have read this http://forum.cxem.net/applications/c....php?id=511334 document in which the procedure for manufacturing and programming the Metal Detector BI is great, but I'm still not sure about many things about cos and sin. I have just this part of the code where I generate a Tx signal 10kHz and Rx signal divided into 4 parts of 90 degrees I would like to consult how to convert these signals into one VDI signal using cos and sin and can do groun balance to debug the ground.

            Code:
            [COLOR=#006600][FONT=Monaco]#include <STM32ADC.h>[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]STM32ADC myADC(ADC1);[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]uint8 RxPin = PA6;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]const int TxPin = PA4;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]const int maxSamples = 1;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]uint16_t dataPoints[maxSamples];[/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]#define SerialMode Serial[/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]int frequency = 10000; // frequency (Hz)[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]int prescaler = 4;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]double freq;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  [/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]int Calibrate = 1;[/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]int16_t bins[4];                 // bins used to accumulate ADC readings, one for each of the 4 phases[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]uint16_t numSamples = 0;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]const uint16_t numSamplesToAverage = 64;[/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]volatile int16_t averages[4];         // when we've accumulated enough readings in the bins, the ISR copies them to here and starts again[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]volatile uint32_t ticks = 0;         // system tick counter for timekeeping[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]volatile bool sampleReady = false;  // indicates that the averages array has been updated[/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]int16_t calib[4];                // values (set during calibration) that we subtract from the averages[/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]int interruptCounter = 0;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]volatile uint8_t lastctr;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]volatile uint16_t misses = 0;    // this counts how many times the ISR has been executed too late. Should remain at zero if everything is working properly.[/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]void Tx_Rx_Isr(void) {[/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]  ++ticks;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  interruptCounter++;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  uint8_t ctr = interruptCounter;[/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]  if (ctr == 2) {[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]      digitalWrite(TxPin, 0);[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  }[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  if (ctr == 6) {[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]      digitalWrite(TxPin, 1);[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  }[/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]  if (ctr != ((lastctr + 1) & 8))[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  {[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  ++misses;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  }[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  lastctr = ctr;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  int16_t *p = &bins[ctr -1 & 3];[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  if (ctr < 5)[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  {[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  *p += dataPoints[0];[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  //if (*p > 16000) *p = 16000;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  }[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  else[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  {[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  *p -= dataPoints[0];[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  //if (*p < -16000) *p = -16000;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  } [/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]  if (ctr == 8)[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  {[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]    ++numSamples;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]    if (numSamples == numSamplesToAverage)[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]    {[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]      numSamples = 0;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]      if (!sampleReady)      // if previous sample has been consumed[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]      {[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]       memcpy((void*)averages, bins, sizeof(averages));[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]       sampleReady = true;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]      }[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]      memset(bins, 0, sizeof(bins));[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]    }[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]    interruptCounter = 0;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  }   [/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]} [/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]void setup()[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]{[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  SerialMode.begin(57600); [/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]  pinMode(TxPin, OUTPUT);     [/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]  myADC.calibrate();  [/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  myADC.setSampleRate(ADC_SMPR_1_5);//set the Sample Rate[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  myADC.setPins(&RxPin, 1);           //set how many and which pins to convert.[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  myADC.setContinuous();            //set the ADC in continuous mode.[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  myADC.setDMA(dataPoints, 1, (DMA_MINC_MODE | DMA_CIRC_MODE), NULL);  [/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  myADC.startConversion();     [/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  [/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  Timer1.setPrescaleFactor(prescaler);[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  freq = (72000000/2/prescaler)/frequency/4;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  Timer1.setOverflow(freq); [/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  Timer1.attachCompare1Interrupt(Tx_Rx_Isr);[/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]  while (!sampleReady) {}    // discard the first sample[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  misses = 0;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  sampleReady = false;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]}[/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]void loop() {[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   while (!sampleReady) {} [/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   uint32_t oldTicks = ticks;[/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]   if(1 == Calibrate){[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   calib[0] = averages[0];[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   calib[1] = averages[1];[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   calib[2] = averages[2];[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   calib[3] = averages[3];[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   [/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   sampleReady = false;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   Calibrate = 0;[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   }[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   else[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   {  [/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   averages[0] -= calib[0];[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   averages[1] -= calib[1];[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   averages[2] -= calib[2];[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   averages[3] -= calib[3];[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   sampleReady = false; [/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]   SerialMode.print("Average 1: ");[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   SerialMode.println(averages[0]);[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   SerialMode.print("Average 2: ");[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   SerialMode.println(averages[1]);[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   SerialMode.print("Average 3: ");[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   SerialMode.println(averages[2]);[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   SerialMode.print("Average 4: ");[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   SerialMode.println(averages[3]);[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   SerialMode.println();  [/FONT][/COLOR]
            
            [COLOR=#006600][FONT=Monaco]   }[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]   while (ticks - oldTicks < 8000)[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]  {[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]}[/FONT][/COLOR]
            [COLOR=#006600][FONT=Monaco]}[/FONT][/COLOR]

            Comment

            Working...
            X