Setting a 40-296 Potentiometer Channel

The schematic for a 40-296 (or 50-296) potentiometer resistor chain is shown below (extracted from the product manual).

Diagram of module 40-296

Setting a 16x2 potentiometer

Each resistor chain comprises resistor chains for the lower and upper arms of the potentiometer with a Wiper tap at the junction of the two arms.

The potentiometer is set by controlling the resistors such that the sum of both arms is constant. In the simpler case of a potentiometer using the entire resistor chain, the upper resistor must be the binary complement of the lower chain.

Note however that the bit order of the resistors are reversed, so the pattern for the upper arm must be the reverse bit order of the complement of the lower arm.

A function that performs the required actions for a 16 bit resistor chain (16 lower and 16 upper) is listed below:

(NOTE: in the interest of clarity no error checking is performed in any of the code examples below)

unsigned int calculate_296_pattern(unsigned int x)
{
    unsigned int maskl = 1<<15;
    unsigned int maskh = 1 << 16;
    unsigned int result = x |= 0xffff0000;
 
    do
    {
        if ((x & maskl) == maskl) result &= ~maskh;
        maskl >>= 1;
        maskh <<= 1;
    } while (maskl > 0);
 
    return ~result;
}

The requested resistance value of he lower arm is passed to the function, the upper 16 bits of the 32-bit contained are set to logic 1.

One-by-one each bit of the lower 16-bits of that value is checked and where a logic 1 is present the corresponding bit of the upper 16 is set to logic 0.

Finally the entire 32-bit pattern in inverted and returned to the caller, This pattern will set both lower and upper resistor chains to the correct values.

This will create a potentiometer with an overall value of 65535 Ohms where the wiper may be set to any 1 Ohm step across the entire potentiometer range.

Other sizes

The 16x2 version is the simplest case to consider, but Pickering also provide cards with 8, 12 and 24 bit chains. These need to be treated slightly differently.

The 8x2 bit and 12x2 bit versions are fairly simply implemented by modification of the masks in the above example.

// 8-bit
unsigned int maskl = 1 << 7;
unsigned int maskh = 1 << 8;
unsigned int result = x |= 0xffffff00;
 
// 12-bit
unsigned int maskl = 1 << 11;
unsigned int maskh = 1 << 12;
unsigned int result = x |= 0xffffff00;

Cards with 24-bit chains require a little more work since the final pattern occupies 48 bits and must be passed to the card as an array of two 32-bit words.

void calculate_pattern(unsigned int x, unsigned int *q)
{
    int64_t r = x;
    uint64_t maskl = (uint64_t)1 << 31;
    uint64_t maskh = (uint64_t)1 << 32;
    uint64_t result = r |= 0xffffffff00000000;
 
    do
    {
        if ((r & maskl) == maskl) result &= ~maskh;
        maskl >>= 1;
        maskh <<= 1;
    } while (maskl > 0);
 
    q[0] = ~(result & 0x00000000ffffffff);
    result >>= 32;
    q[1] = ~((unsigned int)result);
    return;
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    unsigned int  output[2];
 
    reverse(r, output);
 

In this case a 2 element array of 32-bit values is declared and passed to the function which performs the calculation using 64-bit variables and then converts the result and places it into the array.

Other values

It may be that the user wished to emulate a potentiometer with a different overall value, say for example a 50 kOhm potentiometer on the above 16x2 bit chain.

In these cases the upper resistor is not set to the binary complement of the lower value, but rather to a value such that the sum of the two resistors remains constant at the required overall value. For example if the lower resistor is 1 kOhm and the overall value is 50 kOhm then the upper resistor must be set to 49 kOhm.

void calculateBothResistors(unsigned int lower,
                            unsigned int total,
                            int resistor_size,
                            unsigned int *result)
{
    unsigned int upper = total - lower;  // calculate upper resistor value
 
        // initialize masks
    unsigned int mask = 1 << (resistor_size-1);
    uint64_t masku = 1 << resistor_size;
 
    uint64_t pattern = 0;
    do
    {
        if ((upper & mask) == mask)
        {
            pattern |= masku;
        }
        mask >>= 1;
        masku <<= 1;
    } while (masku > 0);
 
    pattern |= (uint64_t)lower;
 
        // split 64 bit value into a pair of 32 bit values
    result[0] = ~(pattern & 0x00000000ffffffff);
    pattern >>= 32;
    result[1] = ~((unsigned int)pattern);
    return;
}

Here, resistor_size is the size of a single resistor, so 8, 12, 16 or 24.

total is the overall potentiometer value required and lower is the value of the lower arm of that potentiometer

This function fills in the values of a 2 element array ready to be sent as a pattern to the potentiometer sub_unit.

How did we do?
0 out of 0 people found this helpful.