9 Replies Latest reply on May 20, 2017 4:51 PM by 2833902

    Inconsistent behaviour when setting pulse period

    2833902

      I am experimenting with the PWM package and have come across some odd behaviour. Below is the Midlet I have defined:

       

      import java.io.IOException;

      import java.util.logging.Level;

      import java.util.logging.Logger;

      import javax.microedition.midlet.MIDlet;

      import javax.microedition.midlet.MIDletStateChangeException;

      import jdk.dio.DeviceManager;

      import jdk.dio.gpio.GPIOPinConfig;

      import jdk.dio.pwm.PWMChannel;

      import jdk.dio.pwm.PWMChannelConfig;

       

       

      public class PwmWave extends MIDlet {

       

          private static final int PWM_PIN = 3;

          private static final int PULSE_PERIOD = 1_000_000;

          private static final int PULSE_WIDTH = 500_000;

          private static final int TOTAL_PULSES = 100;

          private static final float SCALE_FACTOR = 1.0f;

       

          private PWMChannel channel;

       

          @Override

          protected void startApp() throws MIDletStateChangeException {

       

              try {

                  PWMChannelConfig.Builder pwmConfigBuilder = new PWMChannelConfig.Builder();

                  pwmConfigBuilder.setControllerNumber(1);

                  pwmConfigBuilder.setChannelNumber(1);

       

                  // Out pin configuration

                  GPIOPinConfig.Builder pinConfigBuilder = new GPIOPinConfig.Builder();

                  pinConfigBuilder.setPinNumber(PWM_PIN);

                  pinConfigBuilder.setDirection(GPIOPinConfig.DIR_OUTPUT_ONLY);

                  pinConfigBuilder.setDriveMode(GPIOPinConfig.MODE_OUTPUT_PUSH_PULL);

       

                  pwmConfigBuilder.setOutputConfig(pinConfigBuilder.build());

                  pwmConfigBuilder.setScaleFactor(SCALE_FACTOR);

                  pwmConfigBuilder.setPulsePeriod(PULSE_PERIOD);

                  pwmConfigBuilder.setIdleState(PWMChannelConfig.IDLE_STATE_HIGH);

                  pwmConfigBuilder.setPulseAlignment(PWMChannelConfig.ALIGN_CENTER);

                  pwmConfigBuilder.setOutputBufferSize(0);

       

                  channel = DeviceManager.open(PWMChannel.class, pwmConfigBuilder.build());

                  //channel.setPulsePeriod(PULSE_PERIOD);

       

                  apply();

       

              } catch (IOException ex) {

                  Logger.getLogger(PwmWave.class.getName()).log(Level.SEVERE, null, ex);

                  throw new RuntimeException(ex);

              }

          }

       

          private void apply() throws IOException {

              channel.generate(PULSE_WIDTH, TOTAL_PULSES);

          }

       

          @Override

          protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {

              closeIgnoringExceptions(channel);

          }

       

          private void closeIgnoringExceptions(AutoCloseable ac) {

              try {

                  if (ac != null) {

                      ac.close();

                  }

              } catch (Exception e) {

                  // Ignore

              }

          }

      }

       

      The pulse period is set through the configuration object (don't mind the commented-out line of the direct setting on the channel object for now..). When I run this targeting EmbeddedDevice1 I get the following exception:

       

      java.lang.IllegalArgumentException: width or count is illegal

      - .unknown...unknown.(), bci=43

      - com/cos/jme/pwm/PwmWave.apply(PwmWave.java:58)

      - com/cos/jme/pwm/PwmWave.startApp(PwmWave.java:48)

      - .unknown...unknown.(), bci=1

      - .unknown...unknown.(), bci=5

      - .unknown...unknown.(), bci=220

      - .unknown...unknown.(), bci=38

      - .unknown...unknown.(), bci=5

      - .unknown...unknown.(), bci=130

      - com/sun/midp/main/AppIsolateMIDletSuiteLoader.main(), bci=23

       

      Which doesn't make since the width is less than the period and count is greater than zero. If I uncomment that line which sets the pulse period directly on the channel, everything works and the Midlet is deployed.

       

      Any ideas?

        • 1. Re: Inconsistent behaviour when setting pulse period
          Boris Kvartskhava-Oracle

          Could you please, inside apply(), just prior to generate() call,

           

          System.out.println("current channel's pulse period" + channel.getPulsePeriod());

           

          I suppose that the period you're setting with PWMChannelConfig is not supported and it was adjusted by the implementation.

          • 2. Re: Inconsistent behaviour when setting pulse period
            2833902

            Hi Boris,

             

            Adding that line prints the following:

             

            current channel's pulse period: 20

             

            which as you say, looks like an adjusted value. If I set the period on the channel though, the following is printed:

             

            current channel's pulse period: 1000000

             

            which is the value that has been set..On the pwm tab in the emulator however (for EmbeddedDevice1) it says that the min pulse period is 20 and the max is 1000000. So, based on that at least, a period of 1000000 should probably be allowed to be set?

             

            It looks as if setting the period through the configuration doesn't have any effect or is entirely ignored?

             

            Many thanks

            • 3. Re: Inconsistent behaviour when setting pulse period
              Boris Kvartskhava-Oracle

              - It looks as if setting the period through the configuration doesn't have any effect or is entirely ignored?

               

              I believe that behavior is described in PWMChannel.setPulsePeriod(int):

              PWMChannel

              "

              If the underlying platform or driver does not support the requested pulse period value then period will be aligned to the closest lower supported discrete period value. The resulting, actual pulse period can be retrieved by a call to getPulsePeriod. If the current scale factor as returned by getScaleFactor is scale and the current scaled pulse period value - after alignment - is sPeriod then the effective pulse period is calculated as follows:

               ePeriod = (sPeriod / scale)

              "

               

              It may happen  that only two values for pulse period are actually supported on emulator:  20 and 10e6.
              The easiest way to investigate which pulse period in the range [20;10e6] are supported on particular implementation,
              you can consequently use
                channel.setPulsePeriod(20+step);
                actualPP = channel.getPulsePeriod();
              and see actualPP values.


              -- If I set the period on the channel though, the following is printed:

               

              Do you mean you set 500000 and got 1000000?

              • 4. Re: Inconsistent behaviour when setting pulse period
                2833902

                Yup, the documentation is very clear on the expected behaviour. What I am seeing, however, is that when the channel setter is used the requested pulse period is honoured whereas when the configuration object is, it isn't. So, if in the example above the following line runs:

                 

                channel.setPulsePeriod(PULSE_PERIOD);

                 

                with PULSE_PERIOD being 1_000_000, then the following line:

                 

                System.out.println("current channel's pulse period: " + channel.getPulsePeriod());

                 

                prints:

                 

                current channel's pulse period: 1000000

                 

                Which is the requested value. If I try to set the period to something higher than the max value the device supports say: channel.setPulsePeriod(PULSE_PERIOD + 1);

                 

                (the max pulse period for EmbeddedDevice1 is, I believe, 1_000_000):

                 

                then I get the following exception:

                 

                jdk.dio.pwm.InvalidPulseRateException: Period 1000001 is out of the supported range

                - .unknown...unknown.(), bci=78

                - com/cos/jme/pwm/PwmWave.startApp(PwmWave.java:46)

                - .unknown...unknown.(), bci=1

                - .unknown...unknown.(), bci=5

                - .unknown...unknown.(), bci=220

                - .unknown...unknown.(), bci=38

                - .unknown...unknown.(), bci=5

                - .unknown...unknown.(), bci=130

                 

                If I try to set the pulse period to something lower than the min value supported by the device, say 19 (20 is the min value in EmbeddedDevice1) then the following line:

                 

                System.out.println("current channel's pulse period: " + channel.getPulsePeriod());

                 

                prints:

                 

                current channel's pulse period: 20

                 

                (the width was also reduced to 10)

                 

                 

                which is the correct behaviour as per the documentation, and in addition as we can see, the auto-alignment if you will, happens only for the min value (which I suppose, makes sense).

                 

                What I am observing, thought, is that setting the pulse period through the config object has not effect at all as it appears to be ignoring the requested value and instead retaining the min value for this device (20 in this case).

                • 5. Re: Inconsistent behaviour when setting pulse period
                  Boris Kvartskhava-Oracle

                  "...

                  prints:

                   

                  current channel's pulse period: 1000000

                  ..."


                  yes, because 1e6 is supported.


                  "

                  "...

                  If I try to set the period to something higher than the max value the device supports say: channel.setPulsePeriod(PULSE_PERIOD + 1);

                   

                  (the max pulse period for EmbeddedDevice1 is, I believe, 1_000_000)

                   

                   

                   

                  then I get the following exception:

                   

                  jdk.dio.pwm.InvalidPulseRateException: Period 1000001 is out of the supported range
                  ...

                  "

                  Expected, according to the spec: an attempt to set the period greater than maximum pulse period will result
                  in IAE.

                   

                  "

                  If I try to set the pulse period to something lower than the min value supported by the device, say 19 (20 is the min value in EmbeddedDevice1) then the following line:

                   

                  System.out.println("current channel's pulse period: " + channel.getPulsePeriod());

                   

                  prints:

                   

                  current channel's pulse period: 20

                  "


                  Please print
                      - current scale factor (channel.getScaleFactor())
                       - channel.getMinPulsePeriod()

                   

                  PRIOR and AFTER a call to setPulsePeriod(19).

                   

                   

                   

                   

                   

                   

                   

                   

                   

                   

                   

                   

                   

                   

                   

                   

                   





                   

                  • 6. Re: Inconsistent behaviour when setting pulse period
                    2833902

                    My bad...I had set the pulse period constant to 19 but forgot to remove the "+1" bit from channel.setPulsePeriod(PULSE_PERIOD + 1);

                     

                    So, effectively, I was setting the period to 20 again... :-)

                     

                    If I now try to actually set it to 19 I get the following exception:

                     

                    jdk.dio.pwm.InvalidPulseRateException: Period 19 is out of the supported range

                    - .unknown...unknown.(), bci=78

                    - com/cos/jme/pwm/PwmWave.startApp(PwmWave.java:46)

                    - .unknown...unknown.(), bci=1

                    - .unknown...unknown.(), bci=5

                    - .unknown...unknown.(), bci=220

                    - .unknown...unknown.(), bci=38

                    - .unknown...unknown.(), bci=5

                    - .unknown...unknown.(), bci=130

                     

                    Which is the correct behaviour as per the documentation. It does however, beg the question of under what circumstances does the auto-alignment  take place? So, in this case one would expect the value of 19 to be bumped-up to 20 which is the minimum supported value by the device?

                     

                    If I set the period to 20 again and print the details you mention, before and after setting the period, I get:

                     

                    Current scale factor: 1.0

                    Channel min period: 20

                    • 7. Re: Inconsistent behaviour when setting pulse period
                      Boris Kvartskhava-Oracle

                      Ok, this behavior is expected as the spec states:

                       

                      " PWMChanneg.setPulsePeriod:
                      ...
                      Throws:

                      InvalidPulseRateException - if period is greater than the maximum pulse period (see getMaxPulsePeriod) or lower than the minimum pulse period (see getMinPulsePeriod).

                      "

                      In your case, an attempt to set (given that scale factor is 1.0f) PP:


                      any value > 1000000 results in IAE
                      1000000 is set
                      any value in [20;1000000)  turns into 20
                      any value less than 20 results in IAE
                      =======


                      It means that only two values, 20 and 1000000, are supported.

                       

                      Given that the emulator is just proof of concept, it is not expected to support
                      more values. On real boards you will observe more than just two supported periods
                      (and min and max will be different, depending on h/w capabilities)

                      • 8. Re: Inconsistent behaviour when setting pulse period
                        Boris Kvartskhava-Oracle

                        "So, in this case one would expect the value of 19 to be bumped-up to 20 which is the minimum supported value by the device?"

                         

                        That expectation would contradict with the spec that says:

                         

                        Applies to all values in [20; 999999]

                        "...
                        If the underlying platform or driver does not support the requested pulse period value then period will be aligned to the closest lower supported discrete period value.

                        ...

                        ""

                         

                        Applies to the rest of values:

                        InvalidPulseRateException - if period is greater than the maximum pulse period (see getMaxPulsePeriod) or lower than the minimum pulse period (see getMinPulsePeriod).
                        • 9. Re: Inconsistent behaviour when setting pulse period
                          2833902

                          It means that only two values, 20 and 1000000, are supported.

                           

                          It seems that all values in the [20, 1_000_000] range inclusive are supported, actually.

                           

                          I added the following method which is called right before the channel invocation:

                           

                          private void printStateReport() {

                                  try {

                                      System.out.println("Max pulse period: " + channel.getMaxPulsePeriod());

                                      System.out.println("Min pulse period: " + channel.getMinPulsePeriod());

                                      System.out.println("Pulse period: " + channel.getPulsePeriod());

                                      System.out.println("Scale factor: " + channel.getScaleFactor());

                                  } catch (IOException ex) {

                                      Logger.getLogger(PwmWave.class.getName()).log(Level.SEVERE, null, ex);

                                  }

                          }

                           

                          When I run the Midlet with the following params:

                          PULSE_PERIOD = 30

                          SCALE_FACTOR = 1.0f

                           

                          I get the following output:

                           

                          Max pulse period: 1000000

                          Min pulse period: 20

                          Pulse period: 30

                          Scale factor: 1.0

                           

                          And the Midlet is installed fine.

                           

                          If, however, I double the scale factor so that the following params are used:

                          PULSE_PERIOD = 30

                          SCALE_FACTOR = 2.0f

                           

                          I get an IPRE:

                           

                          jdk.dio.pwm.InvalidPulseRateException: Period 30 is out of the supported range

                          - .unknown...unknown.(), bci=78

                          - com/cos/jme/pwm/PwmWave.startApp(PwmWave.java:46)

                          - .unknown...unknown.(), bci=1

                          - .unknown...unknown.(), bci=5

                          - .unknown...unknown.(), bci=220

                          - .unknown...unknown.(), bci=38

                          - .unknown...unknown.(), bci=5

                          - .unknown...unknown.(), bci=130

                           

                          Which makes sense since the effective period is now 15.

                           

                          So, my take on the following bit of the documentation :

                          If the underlying platform or driver does not support the requested pulse period value then period will be aligned to the closest lower supported discrete period value. The resulting, actual pulse period can be retrieved by a call to getPulsePeriod.

                          If the current scale factor as returned by getScaleFactor is scale and the current scaled pulse period value - after alignment - is sPeriod then the effective pulse period is calculated as follows:

                           

                           

                           

                          ePeriod = (sPeriod / scale)

                          is that when setting the pulse period, two things take place: 1) the requested period is set on the channel if it falls within the range supported by the device or possibly aligned to the lowest supported value (depending on the device). Auto-alignment is only applied on the lower value and any attempts to set the period to a value greater than the max value always result in an IPRE. 2) The actual (or effective) period is then calculated based on the formula above which takes into account the scale factor. If that calculation results in a value outside the [min, max] range, an IPRE is thrown.

                           

                          So, it seems that the approach taken in the Emulator is to to allow all values in the [min, max] range ( [20, 1_000_000] ) and do no auto-alignment. Naturally, if a scale factor pushes the period outside the permitted range an exception is thrown.

                           

                          Like you say, the Emulator is a poc and an auxiliary tool so that's not a problem. I actually think it's a great tool which in addition to emulation can be used to to experiment with features that may not be supported on a target device (like PWM on RasPi :-) )