Shop OBEX P1 Docs P2 Docs Learn Events
My first multicore design with problems — Parallax Forums

My first multicore design with problems

#include "simpletools.h"                      
#include "adcDCpropab.h"

void measure_imax();

volatile float i;
volatile float imax;

int main()                                    // Main function
{
  
  cog_run(measure_imax,128);
  
  adc_init(21, 20, 19, 18);
  
  set_directions(15, 0, 0b1111111111111111);  // pins 15 through 0 are outputs
  
  int d[] = {0b1110111, 0b1000100, 0b1101011, 0b1101110, 0b1011100,       //digits 0 through 9
             0b0111110, 0b0011111, 0b1100100, 0b1111111, 0b1111100};
        
      

 
  while(1)
  {    
       int a = (int) imax;            // intger part
       float b = (10 * (imax - a));                
       int c = (int)b;            // frac part
       
       //print("%f, %d, %d\n", imax, a, c);
       
       set_outputs(15, 9, d[c]);  // c is the decimal value
       set_output(1,1);           // pin 1 is the decimal digit driver
       pause(8);
       set_output(1,0);
       set_outputs(15, 9, d[a]);  // a is the integer value
       set_output(2,1);           // pin 2 is the integer digit driver
       pause(8);
       set_output(2,0);             
  }  
}




    
void measure_imax()
{    
  while(1)
  {  
    for (int sample = 0; sample <= 100; sample++)
       {   
          i =  adc_volts(2);
        
          if (i > 0)
          {
        
             float j = adc_volts(2);
        
             if (j > i)
               {
                 i = j;
               }        
          }
       }
       float imax = i;
  }       
}

This program is supposed to use a second cog to take samples of a 60hz voltage and store the max value in imax. The code in cog 0 takes imax and breaks it down into integer and fractional parts, to be displayed on 2) 7 segment leds.
I originally wrote this code in cog 0 and it ran, and gave output, but the sampling was slowed too much by the display routine. I worked through the simple library to write this multi-cog version, but for some reason the output is 0.0. Does
#include "adcDCpropab.h" need to be with the measure_imax function? Is there a mistake I made where the 2 functions don't communicate through the global variables? Please help I am using the WX activity board.

Comments

  • I actually figured it out, the problem was with the float imax = i;, float makes a new local variable I guess that is different than the global one. I changed it to imax = I which works. I am almost happy with the output. I get a reliable AC voltage reading but the display pulses back and forth beween 0 and the reading.
  • Cluso99Cluso99 Posts: 18,069
    I am not a C programmer.
    Looks like the second cog tests for an ADC value of zero and if so calculates j. But the last line which I think posts to the global is outside the zero test. So it will pass the zero value to the first cog for display.


  • If you haven't already, you might want to have a look at the example in the Learn links.
    http://learn.parallax.com/tutorials/language/propeller-c/multicore-approaches/cores-sharing-data
    Cluso99 wrote: »
    I am not a C programmer.
    Looks like the second cog tests for an ADC value of zero and if so calculates j. But the last line which I think posts to the global is outside the zero test. So it will pass the zero value to the first cog for display.

    I think it is fine. The code is checking first if 'i' is greater than 0, and if it is read in a new value into variable 'j'. Then 'j' and 'i' are compared to see if 'j' is larger than 'i' in which case 'i' is set to the value of 'j'. At the end of the for loop, imax is set to 'i' which should be the largest value of the loop. However, I am not sure if it is necessary to call 'adc_volts' twice like that. I think only once is needed. And, since there is already an 'imax' global, 'i' seems a bit redundant. I would have declared a local temp value in 'measure_imax". Also, I am not a fan of declaring a variable in a loop since it may get declared over and over or the compiler might just set it to be declared outside of the loop. I would have just declared 'j' before the 'while' loop. But that is just me.
  • Do you think that if I optimized measure_imax by getting away from the convenience of the simple libraries,
    that the function could be fast enough where the device could actually act like a AC voltmeter instrument?
    There needs to be a faster stream of imax values or a way to dampen the display.
  • MikeDYurMikeDYur Posts: 2,176
    edited 2017-07-31 13:45
    JonM, cleaned the link from above, looked like you accidently pasted it twice.


    http://learn.parallax.com/tutorials/language/propeller-c/multicore-approaches/cores-sharing-data
  • twm47099twm47099 Posts: 867
    edited 2017-07-31 14:24
    If I am reading the code correctly, the second cog reads 100 samples, picks the maximum value and then puts the max voltage into the global imax which is output by the first cog.

    I think that the "if" loop in "measure_imax" is cycling too fast. If i is zero, the loop takes almost no time so it does 100 repeats and gets the same value. Try putting a pause(x) into the loop. Experiment with the value of x, maybe different delays if i is zero and if i is greater than zero.

    The other thing in "measure_imax", each time through the loop you are resetting i to adcvolts(2). If in the previous time through the loop j was > i, you set i = j. But the next time through the loop that value of i is thrown away as i is reset to adcvolts(2).

    Tom

  • Beavis3215Beavis3215 Posts: 229
    edited 2017-07-31 14:52
    When connecting an AC signal to the ADC, the ADC only understands the positive half of the wave. The negative half is measured as zero. The if loop makes the imax sorting procedure ignore trying to sort all of the zero values, which makes the imax procedure faster. if (i > 0) is a virtual half wave rectifier.
  • If a few more parts are ok, add a precision rectifier to the ADC input then no worries about the a zero value on the negative half of the wave. Also, you could use a zero crossing detector to allow you to sample starting from near zero point of the AC wave.
  • Beavis3215Beavis3215 Posts: 229
    edited 2017-07-31 22:45
    I have the precision rectifier and peak voltage detector all ready hooked up as an option, and works fine for a generic AC signal, but the AC current sensor I am using (Littlebird clip on current sensor) requires a 2.5 VDC offset. Its output is an AC voltage signal riding on DC. This would be more than just adding a precision rectifier, as ground of the WX board would need to be connected to 2.5VDC to use the precision rectifier technique to rectify just the sine wave. I don't think that this would be good for my WX board. I'm sure there is a hardware method to get through it, but it does not seem simple to me. The manufacturer of the sensor recommends a data logging technique to read its output. The scheme I am trying to do now is a wildcard peak voltage detector. It can measure the maximum (and/or minimum if you want) of any fluctuating signal, but is just slower than I want in its present form. Also, the invention I'm working on will require 4 channels. If I could make the microcontroller do all the work, it would save 4 channels of precision rectifiers and a +- power supply fot the op amps. In reality my project will only require instantaneous voltage instead of peak voltage anyway, but I am trying to make it behave like an instrument just for me learning, and to calibrate other parts of the project as I work through it.
  • I mucked with your code a bit and added some items from other Multicore Learn examples and added a pause in your cog1 loop as well as increased the pause for cog0. With the pauses in their original state, you can see that cog0 will cycle multiple times before cog1 fires causing the same value to be cycled through in your cog0 loop. You only get a new value when cog1 fires which is many cycles later:

    //added a inCog1 variable to determine if in cog1 or not.
    In cog1
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    2.652588, 2, 6
    In cog1
    2.657471, 2, 6
    2.657471, 2, 6
    2.657471, 2, 6
    2.657471, 2, 6
    2.657471, 2, 6
    2.657471, 2, 6
    2.657471, 2, 6

    By increasing the pause in the cog0 loop and adding one in the cog1 loop, the two cogs are more inline. With more adjustment and both could be synced.

    // After increase pauses:
    2.667236, 2, 6
    In cog1
    2.678223, 2, 6
    2.678223, 2, 6
    In cog1
    2.668457, 2, 6
    In cog1
    2.664795, 2, 6
    In cog1
    2.655029, 2, 6
    2.655029, 2, 6
    In cog1
    2.655029, 2, 6
    In cog1
    2.648926, 2, 6

    // My hacking of your code, but leaving most in place.
    #include "simpletools.h"                      
    #include "adcDCpropab.h"
    
    void measure_imax();
    
    static volatile float i;
    static volatile float imax;
    static volatile int t, n; 
    int *otherCog;
    int inCog1 = 0;
    
    // Global vars for cogs to share
    unsigned int stack[44 + 128]; 
    
    // Forward declaration
    void measure_imax(void *par);
    
    
    int main()                                    // Main function
    {
      t = 5;                                     // Set values of t & n
      otherCog = cogstart(measure_imax, NULL, stack, sizeof(stack));
      
      adc_init(21, 20, 19, 18);
      
      set_directions(15, 0, 0b1111111111111111);  // pins 15 through 0 are outputs
      
      int d[] = {0b1110111, 0b1000100, 0b1101011, 0b1101110, 0b1011100,       //digits 0 through 9
                 0b0111110, 0b0011111, 0b1100100, 0b1111111, 0b1111100};
      int a = (int) imax;            // intger part
      float b = (10 * (imax - a));                
      int c = (int)b;       
          
    
     
      while(1)
      {    
           a = (int) imax;            // intger part
           b = (10 * (imax - a));                
           c = (int)b;            // frac part
           print("%f, %d, %d\n", imax, a, c); 
           set_outputs(15, 9, d[c]);  // c is the decimal value
           set_output(1,1);           // pin 1 is the decimal digit driver
           pause(200);
           set_output(1,0);
           set_outputs(15, 9, d[a]);  // a is the integer value
           set_output(2,1);           // pin 2 is the integer digit driver
           pause(200);
           set_output(2,0); 
           if (inCog1) {
              print("In cog1\n");
           }         
           inCog1 = 0;            
      }  
    }
    
    
        
    void measure_imax(void *par)
    {  
      while(1)
      {  
    
        for (int sample = 0; sample <= 100; sample++)
           {   
              i =  adc_volts(2);
            
              if (i > 0)
              {
            
                 float j = adc_volts(2);
            
                 if (j > i)
                   {
                     i = j;
                   }        
              }
           }
           imax = i;
           pause(t);
           inCog1 = 1;
      }       
       
    }
    
  • Beavis3215Beavis3215 Posts: 229
    edited 2017-08-01 11:40
    I like your idea, and I could see how it will help. I have had similar success by changing the number of samples. 35 seems to work best. It can still grab imax accuratly and seems to act the fastest. Kind of the same thing. I think that the real syncing required is with the signal itself. Sometimes the sampling will start on the zeros and sometimes on the voltage. That is why the output in my case seems to cycle between imax and zero about once per second.
  • Beavis3215Beavis3215 Posts: 229
    edited 2017-08-03 00:05
    I think that a possible solution is to fire up another cog with similar code as measure imax that is offset in time from the first. It can be offset by adjusting the number of samples, or by a small delay. This will increase the number of imax passes to the main program.
Sign In or Register to comment.