11 Replies Latest reply on May 3, 2020 5:47 PM by AjSh_4344506

    Psoc 5LP issues with SAR ADC at <1 volts measurements

    AjSh_4344506

      Hello Everyone,

       

      These are some of my early days working with the Psoc 5LP CY8KIT -059 and I come from a mechanical engineering background so please bear with me.

       

      I am using the SAR ADC to measure 0-5V from the terminal of the DC motor and reading this display on the LCD

      image 1.JPG

      image 2.JPG

      I chose the single ended input range i.e from Vssa (GND) to Vdda (5.0V)

      This arrangement only gives me a reliable reading from >1V - 5V. Any reading below <1V is displayed erroneously

      I also tried switching input range from 0 to Vref*2 ( 0 to 2.048)  but this also did not help.

       

      I am having trouble root causing this and would appreciate any input to help me through !

       

      Thanks in advance.

        • 1. Re: Psoc 5LP issues with SAR ADC at <1 volts measurements
          LePo_1062026

          AjSh,

           

          I have experience with designing MCUs to control BDC motors so I might be of assistance.

           

          You're not very explicit as to what type of problem you are having.

          I'm assuming the issue you have is reading the voltage at Pin0_4 when the FET is ON.  Again, I'm assuming the major issue you're having is that the readings are low voltage (<1V) but are "jumping" around.

           

          If this is a correct assumption, this a normal effect of driving a BDC motor.  There are many things that cause an apparent erratic reading with the motor being driven.  (I apologize in advance if you are already aware of all the effects I'm mentioning.  Since this is a post in a forum, this might assist someone else looking to do what you are trying to do.)

          • Startup torque. The resistance of the motor is almost the DC resistance of the motor when it is first started. The way to determine that is the voltage across the motor divided by the stall current.
            The circuit resistance the sum of the Rmotordc@stall + Rds[of the FET] + Rcurrentsense.  Let's throw some numbers in Rmotordc@stall = Vdd/Istall = 3V/5A = 0.6 ohms.   Rds[@ full on] = 0.01 ohms  Rcurrentsense = 0.62.   You'll notice that the Rmotordc@stall almost equals the Rds and Rcurrentsense combined.  Therefore at startup V@Pin0_4 ~= Vdd/2 ~= 2.5V!
            Once the motor starts moving the backemf generated by the motor will reduce the effective resistance in the motor.  This will cause the voltage at Pin0_4 to go lower.
          • Motor Loading. The resistance of the motor changes with the mechanical loading.  The lower the load, the higher backemf generated the higher the effective resistance.  The higher the load, the less backemf and the lower the effective ressitance value.  In the case you stall the motor, you're back to the resistance listed in the first point.
          • Cogging torque.  Since applying current to a coil on the armature causes a magnetic field to be generated, it's position to the static magnetic field (due to the permanent magnets) will roughly determine the backemf. As the armature rotates, the position to the magnets change causing the effective resistance to vary with position.  Hence once a motor is rotating event with a little load, you're going to see a lot of current fluctuations.
          • Commutation switching. The motor's coils are on the moving armature.  To transfer current to the moving coils, a pair of graphite brushes are in contact with pairs of multiple copper plates on the armature.  Along with variations in brush resistance as they contact the plate, when the brushes bridge over to the next plate pair, there is actually two sets of coils being powered.  When the second set of coils are engaged they have current in them.  This causes a almost immediate surge in motor current which to your circuit looks like a significant drop in the resistance of the motor.
            When the brushes fully leave a plate pair, the current in that pair is almost immediate disconnected.
          • There are other effects I haven't mentioned here but are somewhat less significant.

           

          From ALL the effects above you can see that you will not get a 'clean' motor reading.  I've often used a more immediate reading to determine if the motor is stalled and a highly averaged reading to determine the average loading effects.

           

          Another set of thoughts:

          When using an ADC, I prefer to use the system available Vref for the ADC reference.  Hence the 0 to Vref*2 ( 0 to 2.048) is a better choice.

          This is especially true when driving a high loaded circuit element such as a motor from the same Voltage source as the CPU.  This is because if you use Vssa to Vdda, Vdda is derived from Vdd.  If Vdd drops due to a highly loaded motor (or due to startup stall currents), then your ratiometric result to the ADC is effected.  For example, using Vssa to Vdda where Vssa = 0 and Vdda = 5V,  then your ADC resolution is ratiometric to (Vdda-Vssa)/(1<<ADC_resolution) = (5V-0V)/(1<<10bits) = 4.88mV per ADC count.

          If Vdd drops due to heavy loading, Vdda will drop proportionally.  If Vdda drops to 3.5V then (Vdda-Vssa)/(1<<ADC_resolution) = (3.5V-0V)/(1<<10bits) = 3.42mV per ADC count.

           

          Using the system available Vref will be generally immune to Vdda drops.  Your readings will be more 'consistent' against Vdd variances.

           

          I hope you're not using the Vdd derived from the KitProg part of the Cy8CKIT-059.  The Vdd is limited to 0.48A as per USB specifications and the Vdd voltage averages 4.75V lightly loaded.  When you place more load, (driving LEDs or a motor for example), Vdd drops.

           

          I know I've been a bit 'wordy' but I hope with some completeness to my answer,it might explain what you are seeing or what to expect to see in future working with motor circuits.

           

          Len

          • 2. Re: Psoc 5LP issues with SAR ADC at <1 volts measurements
            AjSh_4344506

            Hi Len,

             

            I tested the same using a potentiometer instead of the motor to eliminate the possible motor load/noises that could affect measurements at low voltage but it wasn't the case.

            The Vdd i use is not from the Kitprog but from the USB port.

            I may need to redo the steps by a separate battery source. Is there a reason for not using them as a power source but only as a logic driver?

             

            I really appreciate your support and thank you for sharing your experience with motor controllers.

            • 3. Re: Psoc 5LP issues with SAR ADC at <1 volts measurements
              MoTa_728816

              Hi,

               

              I found the attached project from my HDD.

              And the Tera Term Log of that day shows

              000-TeraTerm-log.JPG

              So this may be usable for you.

               

              moto

              2 of 2 people found this helpful
              • 4. Re: Psoc 5LP issues with SAR ADC at <1 volts measurements
                LePo_1062026

                AjSh,

                 

                You're welcome.

                 

                I'm glad to hear you've substituted a load resistor that can be measured in current to try to prove out the ADC conversion. It's a very good and solid idea.  It allows you to minimize outside influences while you debug the circuit.

                 

                In the motor drive controller products I've done for the automotive market, I use calibrated reference power resistors to calibrate the ADC circuit as well as functionally test the FET drivers in End-of-line testing.

                 

                The Vdd off the USB is basically the same specs as off the KitProg board.  <0.5A @ ~4.75V

                 

                There's another test you can perform if you have an adjustable DC voltage source.

                • Make sure the kit is powered but not driving the FET.
                • Place the "+" terminal of the power supply on Pin0_4
                • Place the "-" of the power supply on GND (VSS).
                • Adjust the voltage source from 0V to 4.0V slowly in increments.
                • At each stage of incrementing, note the output voltage (preferably using a calibrated meter) and determine the ADC results.
                • Create a table of the results and share it with us.  It might lend some clues as to what is going on.

                 

                Check out moto's project.  Maybe he's got some clues as to how to improve your design.

                 

                Len

                 

                PS:  Bravo to you!  I found it always best to perform cross-disciplinary engineering.

                2 of 2 people found this helpful
                • 5. Re: Psoc 5LP issues with SAR ADC at <1 volts measurements
                  AjSh_4344506

                  Thanks for sharing this moto!

                  • 6. Re: Psoc 5LP issues with SAR ADC at <1 volts measurements
                    AjSh_4344506

                    Hi Len,

                     

                    I will perform these steps and see how it turns out. I will also use a dedicated DC power source to remove any uncertainties coming from the MCU Vdd.

                    • 7. Re: Psoc 5LP issues with SAR ADC at <1 volts measurements
                      AjSh_4344506

                      Hello,

                       

                      I was kind of able to figure out the problem with  <1V measurement from the SAR_ADC. I think the problem was not with ADC but simply the conversion and display on the LCD. I saw Motoo's code and accordingly applied it in mine and was able to go as low as 0.1 V with the Vdd supply from PSoc

                      if (loop_counter>5000)

                          {

                             loop_counter=0;

                              LCD_Position(0,0);

                              LCD_PrintString("Voltage is:");

                              LCD_Position(1,0);

                              LCD_PrintNumber(Vir/1000);

                              LCD_PrintString(".");

                              LCD_PrintNumber(Vir%1000);

                       

                      I have a new problem now, (portion of code below). I am trying to divide a type float static value(Rsense) into a digital (ADC) signal. Basically, the signal is voltage and I want to divide it by the Resistance (Rsense) to obtain current. The output clearly didn't work. Is there a way to achieve this?

                      Again, coming from a mechanical engineering background i may be missing some basic digital signal concept understanding and would really appreciate some guidance!

                       

                          ADC_SAR_2_StartConvert();

                          ADC_SAR_2_IsEndConversion(ADC_SAR_1_WAIT_FOR_RESULT); // does not complete conversion until

                          vir = ADC_SAR_2_GetResult16();  //get basic data from ADC

                          Vir = ADC_SAR_2_CountsTo_mVolts(vir); // Convert this to mVolts

                        Vsense = Vir                   -------( Vsense is of type float)

                          Isense= Vir/Rsense;            ---------(Isense is of type float)

                          Vr_motor= Isense*Rmotor;

                      • 8. Re: Psoc 5LP issues with SAR ADC at <1 volts measurements
                        MoTa_728816

                        Hi

                         

                        > The output clearly didn't work. Is there a way to achieve this?

                        "clearly didn't work" does mean almost nothing.

                        Explaining what you are seeing will help us to help you.

                         

                        Having said that I modified my sample as below.

                        ================

                        int main(void)

                        {

                            static float Rsense = 123.456 ;

                            uint16_t adc_count ;

                            int16_t mV ;

                            float isense ;

                          

                            init_hardware() ;

                          

                            splash() ;

                         

                            for(;;) {      

                                ADC_StartConvert() ;

                                ADC_IsEndConversion(ADC_WAIT_FOR_RESULT) ;

                                adc_count = ADC_GetResult16(0) ;

                                mV = ADC_CountsTo_mVolts(adc_count) ;

                              

                                if (mV < 0) {

                                    mV = -mV ;

                                    print("-") ;

                                }

                                snprintf(str, STR_LEN,  "%d.%03d V (0x%04X) : ", mV/1000, mV%1000, adc_count) ;

                                print(str) ;

                              

                                isense = (float)mV / Rsense ;

                              

                                snprintf(str, STR_LEN, "%.2f mA\n\r", isense) ;

                                print(str) ;

                              

                                CyDelay(1000) ;

                            }

                        }

                        ================

                         

                        And the Tera Term log was

                        000-TeraTerm-log.JPG

                        So I hope that we can get current value.

                         

                        BUT, there is/are some catch here.

                        Please refer to my old memo about printf with float

                        printf and float rhapsody (aka, yet another printf and floating topic)

                         

                        To make above project work, I had to modify a couple of Project Settings.

                        (1) Enable float format in the library

                        From Project > Bulid Settings...

                        Select ARM GCC xxx > Linker > General

                        In the General pane, set "Use newlib-nano Float Formatting" to True

                        001-Build-settings.JPG

                        (2) Enlarge the heap size

                        From Workspace Explorer > <the project> > Design Wide Resources > System

                        The default Heap Size (bytes) is set to 0x80,

                        you need to set it larger, for my example I set it to 0x400

                        002-DWR-System-heap.JPG

                         

                        But if your application needs speed, maybe using float is not a good idea,

                        using integer for 1000 x current value may serve your purpose without the cost of float (speed, and memory usage).

                         

                        And last but not least, if our replies are useful, please make it "Like" or "Helpful".

                         

                        moto

                        1 of 1 people found this helpful
                        • 9. Re: Psoc 5LP issues with SAR ADC at <1 volts measurements
                          AjSh_4344506

                          Hi Motoo,

                           

                          Again many thanks for your support.

                          I don't have much knowledge of UART and basically had this project to run on an LCD display so I couldn't log values to show.

                          This project was to measure the back emf from a DC motor and using that to display the motor speed on an LCD.

                           

                          I think the major struggle throughout this project for me was using basic conversions for display on the LCD. The highlighted pieces of code is what I corrected after taking your inputs to get my results.

                           

                           

                              AMux_Select(0); //Channel 1 select for measuring Vir = I*Rsense

                              ADC_SAR_1_StartConvert();

                              ADC_SAR_1_IsEndConversion(ADC_SAR_1_WAIT_FOR_RESULT); // does not complete conversion until

                              vir = ADC_SAR_1_GetResult16();  //get basic data from ADC

                              Vir = ADC_SAR_1_CountsTo_mVolts(vir); // Convert this to mVolts

                             Isense=(float) Vir*1.3;

                            Vr_motor= (int16)Isense*Rmotor;

                           

                             Vb= Vs-Vr-Vr_motor; // Vb = V - (V-IR-Kb*w) - IR = Kb*w

                              rpm = Vb*2885; // Using Kb=000331 from datasheet and converting to rpm 60/2*3.14

                          if (loop_counter>4000)

                              {

                                 loop_counter=0;

                                  LCD_Position(0,0);

                               

                                  if (Vb<=0)          // This condition is to prevent showing negative values on LCD which spoils display later

                                  {

                                  LCD_PrintString("Voltage is:");

                                  LCD_Position(1,0);

                                  LCD_PrintString("000000");

                                  LCD_Position(1,8);

                                  LCD_PrintString("rpm");

                                  }

                                  else

                                  {

                                  LCD_ClearDisplay();

                                  LCD_PrintString("Voltage is:");

                                  LCD_Position(1,0);

                                  LCD_PrintU32Number(rpm/1000);

                                  LCD_PrintString(".");

                                  LCD_PrintU32Number(rpm%10);

                                  LCD_Position(1,8);

                                  LCD_PrintString("rpm");

                                  }

                          }

                              }

                          }

                           

                          I'm trying to figure out how to attach files here btw.

                           

                          Thank for you support.

                          • 10. Re: Psoc 5LP issues with SAR ADC at <1 volts measurements
                            MoTa_728816

                            Hi,

                             

                            Just reading your code, I have a couple of points which I'd like to ask you to confirm,

                             

                            (1) Can you put a break point at the line

                                        LCD_PrintU32Number(rpm/1000);

                            and read the value of rpm?

                            Is the value of rpm what you expected?

                             

                            (2) To me following lines seem to be strange

                                    LCD_PrintU32Number(rpm/1000);

                                    LCD_PrintString(".");

                                    LCD_PrintU32Number(rpm%10);

                            Is rpm an integer or float?

                            If rpm is a float number, you need to write

                                    LCD_PrintU32Number((int)(rpm/1000)) ;

                             

                            Meantime, let's assume rpm = 123456

                            rpm/1000 = 123

                            rpm%10 = 6

                            So you will get "123.6"

                             

                            If you want to see the first place under decimal point

                            you need to do

                            (rpm/100)%10 = (123456/100)%10 = 1234 % 10 = 4

                             

                            So to be safe (in case rpm is a float), I hope that doing the following will show you "123.4"

                                    LCD_PrintU32Number((int)(rpm/1000));

                                    LCD_PrintString(".");

                                    LCD_PrintU32Number(((int)(rpm/100))%10);

                             

                            moto

                            • 11. Re: Psoc 5LP issues with SAR ADC at <1 volts measurements
                              AjSh_4344506

                              Hi Motoo,

                               

                              Yes, the rpm is what I expected. The variable type for 'rpm' is int32. I was careful enough there to not have a float variable printed in the LCD.

                               

                              "(2) To me following lines seem to be strange

                                      LCD_PrintU32Number(rpm/1000);

                                      LCD_PrintString(".");

                                      LCD_PrintU32Number(rpm%10);

                              Is rpm an integer or float?

                              If rpm is a float number, you need to write

                                      LCD_PrintU32Number((int)(rpm/1000)) ;

                               

                              Meantime, let's assume rpm = 123456

                              rpm/1000 = 123

                              rpm%10 = 6

                              So you will get "123.6"  "

                               

                              Yes, this is exactly what i got with int32