Reflex Example 5: Low-frequency PWMIndex

The Problem

Suppose a BrainStem must output a 100Hz PWM signal on one of its digital IO pins.  The signal must have a 0% to 100% duty cycle.

The Solution

Here is some logic to implement this function:

P is the period of the PWM signal.  T/P is the duty ratio.  The time when the digital pin is high will be called the "PWM high pulse".  The time when the digital pin is low will be called the "PWM low pulse".

The Details

We need to describe this logic in terms that can be directly translated into BrainStem commands.  This requires two timers that control the duration of the PWM high pulse and PWM low pulse.  Timer 23 controls the duration of the high pulse.  Timer 24 controls the duration of the low pulse.  Digital output 4 has the PWM output.

For a period of 100Hz, P is 10ms.  T ranges from 0ms to 10ms.  Controlling the duty cycle requires setting Timer 23 to T and Timer 24 to P-T.  The timers use increments of 0.1ms which gives 100 steps in the range 0% to 100%.  This logic requires some means for passing a variable input parameter for controlling the duty cycle.  The cmdPAD_INPUT command provides this functionality.  It takes a value from the scratchpad and issues a raw input with that value as its parameter.  In this example, scratch pad byte 31 (pad[31]) controls the duty cycle.  Once the reflex is started, an application can control the duty cycle by writing to pad[31].

In actual operation the duty cycle parameter, pad[31], can only range between 1 and 99.  Otherwise, the reflex will try to set a timer to 0 and that will cause an error.  Getting a true 0% or 100% duty cycle requires some extra control bytes.  The scratchpad saves the default state for the PWM high pulse in pad[30] and the default state for the PWM low pulse in pad[29].  Setting both those bytes to 0 gives a 0% duty cycle.  Setting both those bytes to 1 gives a 100% duty cycle.  Pad[30] must be set to 1 and pad[29] must be set to 0 to get a duty cycle between 0% and 100%.

Reflex 43 Issue raw input 125 with its parameter set to pad[30].
  Reflex 125 Take the raw input parameter and apply it to digital pin 4.
  Issue raw input 124 with its parameter set to pad[31].
  Reflex 124 Take the raw input parameter and use it to set Timer 23 to T.
  Reflex 42 Issue raw input 123 with its parameter set to pad[29].
  Reflex 123 Take the raw input parameter and apply it to digital pin 4.
  Issue raw input 122 with its parameter set to pad[31].
  Reflex 122 Take the raw input parameter and use it to set Timer 24 to P-T.

Reflex 43 is reflex that is activated when Timer 24 expires.  Reflex 42 is reflex that is activated when Timer 23 expires.  Start at Reflex 43 above and trace the flow of the routine.  Once started, the reflex continually loops through the reflexes in the order that they are listed.  This maintains the 100Hz PWM signal at digital output 4.

The Commands

In the reflexive routine described above, there are really only seven unique commands.  These commands, complete with address byte and size byte, are listed below.  They are numbered from 0 to 6.  Note the values in parentheses in several of the commands.  They represent bytes that will be modifiable parameters in the final reflexive routine.

0 Issue raw input 125 with its parameter set to pad[30]. 2 3 52 125 30
1 Set digital IO pin 4. 2 3 27 4 (0)
2 Issue raw input 124 with its parameter set to pad[31]. 2 3 52 124 31
3 Set Timer 23. 2 4 39 23 0 (0)
4 Issue raw input 123 with its parameter set to pad[29]. 2 3 52 123 29
5 Issue raw input 122 with its parameter set to pad[31]. 2 3 52 122 31
6 Set Timer 24. 2 4 39 24 0 (100)

These commands go in reflex command slots 0-6.  The series of cmdMSG_WR commands listed below will save the command data into the appropriate locations in the EEPROM.  Note that Reflex Commands 3 and 6 must be saved with two cmdMSG_WR commands because they are too long to be saved with a single command.

Reflex CMD 0 2 12 128 0 2 3 52 125 30
Reflex CMD 1 2 12 128 1 2 3 27 4 0
Reflex CMD 2 2 12 128 2 2 3 52 124 31
Reflex CMD 3 2 12 0 2 4 39 23 0 0
2 12 134 3
Reflex CMD 4 2 12 128 4 2 3 52 123 29
Reflex CMD 5 2 12 128 5 2 3 52 122 31
Reflex CMD 6 2 12 0 2 4 39 24 0 100
2 12 134 6

The Vectors

Now that the reflex commands are in the EEPROM, we need to define the reflex vector data for reflexes 43, 125, 124, 42, 123, and 122.  The vectors in this example have either one or two records per vector.  The binary contents of each vector along with a description of what the contents mean is listed below:

Reflex Vector 43 Cmd 0, (last in vector)
[ 1 | 0000000 ] [ 1 | 000 | 0000 ]
128 128
Reflex Vector 125 Cmd 1, byte[4] = byte[4] + input
Cmd 2, (last in vector)
[ 0 | 0000001 ] [ 1 | 001 | 0100 ]
[ 1 | 0000010 ] [ 1 | 000 | 0000 ]
1 148
130 128
Reflex Vector 124 Cmd 3, (last in vector), byte[5] = byte[5] + input
[ 1 | 0000011 ] [ 1 | 001 | 0101 ]
131 149
Reflex Vector 42 Cmd 4, (last in vector)
[ 1 | 0000100 ] [ 1 | 000 | 0000 ]
132 128
Reflex Vector 123 Cmd 1, byte[4] = byte[4] + input
Cmd 5, (last in vector)
[ 0 | 0000001 ] [ 1 | 001 | 0100 ]
[ 1 | 0000101 ] [ 1 | 000 | 0000 ]
1 148
133 128
Reflex Vector 122 Cmd 6, (last in vector), byte[5] = byte[5] - input
[ 1 | 0000110 ] [ 1 | 010 | 0101 ]
134 165

This vector data goes into reflex vector slots 43, 125, 124, 42, 123, and 122.  The series of cmdVEC_WR commands listed below will save the vector data into the appropriate locations in the EEPROM.

Vector 43 2 11 128 43 128 128
Vector 125 2 11 128 125 1 148 130 128
Vector 124 2 11 128 124 131 149
Vector 42 2 11 128 42 132 128
Vector 123 2 11 128 123 1 148 133 128
Vector 122 2 11 128 122 134 165

The Results

The PWM routine is now completely defined.  A text batch file can store all the commands for downloading the reflex data.  Copy and paste the following lines of numbers to a file called "pwm.txt" in your "aUser" directory.  The Console can download the file to the BrainStem.  Just enter batch "pwm.txt" at the prompt.

To test the routine, connect a series resistor and LED to digital output 4.  The PWM signal can control the brightness of an LED.  Enter the following command to configure digital pin 4 as an output:

Initialize the scratchpad control bytes with the following commands:

That sets a 50% duty cycle and sets the default states for the high pulse and low pulse.  Enter the next command and the reflex will start:

The LED should be glowing dimly.  Try the following commands and notice how the brightness of the LED changes.  The first selects a 1% duty cycle and the second selects a 99% duty cycle:

The following commands set the default states for both the high pulse and low pulse to off for a 0% duty cycle:

The following commands set the default states for both the high pulse and low pulse to on for a 100% duty cycle:

This example demonstrates a useful PWM reflex and shows how reflexes can be controlled by scratchpad variables.  A host machine can send commands to alter the scratchpad variables to change the PWM output.  A TEA program can write to the scratchpad using IO ports and change the PWM output.

Here is a LEAF source file for the reflex routine in this example:

ex5_pwm.leaf

Download "ex5_pwm.leaf" here
/* file: ex5_pwm.leaf */

#include <aCmd.tea>
#include <aGPReflexes.tea>

/* assume the BrainStem has address 2 */
#define MODULE 2

/* IO stuff */
#define PWMPIN 4

/* message ids */
#define mINPUT1 0
#define mPWMOUT 1
#define mINPUT2 2
#define mTMR23 3
#define mINPUT3 4
#define mINPUT4 5
#define mTMR24 6

/* user-defined vectors */
#define vSTEP1 125
#define vSTEP2 124
#define vSTEP3 123
#define vSTEP4 122

module[MODULE] {

  /************* REFLEX COMMANDS *************/

  message[mINPUT1] {
    MODULE, cmdPAD_INPUT, vSTEP1, 30
  }

  message[mPWMOUT] {
    MODULE, cmdDIG_IO, PWMPIN, 0
  }

  message[mINPUT2] {
    MODULE, cmdPAD_INPUT, vSTEP2, 31
  }

  message[mTMR23] {
    MODULE, cmdTMR_SET, 23, 0, 0
  }

  message[mINPUT3] {
    MODULE, cmdPAD_INPUT, vSTEP3, 29
  }

  message[mINPUT4] {
    MODULE, cmdPAD_INPUT, vSTEP4, 31
  }

  message[mTMR24] {
    MODULE, cmdTMR_SET, 24, 0, 100
  }

  /************* REFLEX VECTORS *************/

  vector[aGP_RFX_TIMER_24] {
    mINPUT1
  }

  vector[vSTEP1] {
    char + mPWMOUT[4],
    mINPUT2
  }

  vector[vSTEP2] {
    char + mTMR23[5]
  }

  vector[aGP_RFX_TIMER_23] {
    mINPUT3
  }

  vector[vSTEP3] {
    char + mPWMOUT[4],
    mINPUT4
  }

  vector[vSTEP4] {
    mTMR24[5] - char
  }
}

Here is the BAG output from the LEAF compiler:

ex5_pwm.bag

Download "ex5_pwm.bag" here

// module 2 (7 messages, 6 vectors)

// message 0
2 12 128 0 2 3 52 125 30
// message 1
2 12 128 1 2 3 27 4 0
// message 2
2 12 128 2 2 3 52 124 31
// message 3
2 12 0 2 4 39 23 0 0
2 12 134 3
// message 4
2 12 128 4 2 3 52 123 29
// message 5
2 12 128 5 2 3 52 122 31
// message 6
2 12 0 2 4 39 24 0 100
2 12 134 6
// vector 42
2 11 128 42 132 128
// vector 43
2 11 128 43 128 128
// vector 122
2 11 128 122 134 165
// vector 123
2 11 128 123 1 148 133 128
// vector 124
2 11 128 124 131 149
// vector 125
2 11 128 125 1 148 130 128

This batch file contains the same commands for downloading the reflex that were listed for the "pwm.txt" file, but in a different order.


version: 1.0, build n.a.
© Copyright 1994-2012 Acroname, Inc., Boulder, Colorado.  All rights reserved.