Prop1 SPIN: Binary manipulation 101
WBA Consulting
Posts: 2,934
in Propeller 1
I am updating a test fixture that I had originally developed in 2014 from this old thread. While I have already updated the firmware for the new requirements this past weekend, I have an idea to make another change to the tester to make it more visually appealing since the pass/fail is determined by an operator viewing the 56 LEDs. The tester Prop1 chip is powered up after the DUT is inserted, so the program starts from scratch at each test and my program is designed that way.
Some background: The PCBA being tested has 4 Left/Right banks of VU Meter style LEDs, 4 green, 2 yellow, and 1 red that are driven by MAX7313 ICs. The two banks are referred to the Low bank (L) and High bank (H). See the original thread for more details, but what I would like to do is get a little more "proper" with my binary data that is being sent to the MAX7313s so that it is easier to show rolling/sequential patterns across the banks. I stripped down my code to explain what I am currently doing:
Main Program Code (this version would cycle the MAX7313 at address $20 from only red on to full off repeatedly, but always leaving the unused bit off)
MAX7313 Object (key portions only!)
So, with all that said, the pattern for each bank of LEDs is below. Remember, these are Left/Right banks of 7 LEDs each, with one output of each output bank not used (the "-" in the pattern definition):
Here is a pattern for just the two yellows on:
The Left (Low) and Right (High) bank positions of LEDs are inverted in relation to the MAX7313 outputs, so, 3 Greens on for Low and High would be %1000_0111 for the Low bank and %1111_0000 for the High bank. The first bit of "1" is for the unused output so it is always "1" in any pattern so that it remains off
The dilemma that is mocking my lack of binary manipulation knowledge is as follows:
Here is what I want to do: Rotate a single "on" LED through the bank, somewhat fast. So visually, an operator can see that each one lights individually. I know that to do that, I should be able to do some straightforward binary manipulation so I don't need a CON list of 8 patterns. What is blocking my train of thought is the challenge with dealing with the unused output between the channels.
Is there an easy way to flip the Low bank value, shift over by one and then make the first bit a 1 to get the High bank value of the same pattern?
I am thinking using a mask to OR with the original value to set the first "1" each time. Is that wrong?
I believe I can do a basic shift operation to move the single "0" through the pattern to light one at a time, but the issue of aligning it against that one unused inverted bit is confusing.
My dream pseudocode would be
Any and all help is appreciated.
Some background: The PCBA being tested has 4 Left/Right banks of VU Meter style LEDs, 4 green, 2 yellow, and 1 red that are driven by MAX7313 ICs. The two banks are referred to the Low bank (L) and High bank (H). See the original thread for more details, but what I would like to do is get a little more "proper" with my binary data that is being sent to the MAX7313s so that it is easier to show rolling/sequential patterns across the banks. I stripped down my code to explain what I am currently doing:
Main Program Code (this version would cycle the MAX7313 at address $20 from only red on to full off repeatedly, but always leaving the unused bit off)
MAX7313.init_A(i2cSDA, i2cSCL,false) MAX7313.Setup_A($20) repeat MAX7313.LED_BLANK_A($20) waitcnt(clkfreq/5 + cnt) MAX7313.LED_RED_A($20) waitcnt(clkfreq/5 + cnt)
MAX7313 Object (key portions only!)
CON BLANK_L = %1111_1111 BLANK_H = %1111_1111 RED_L = %1011_1111 RED_H = %1111_1110 PUB LED_BLANK_A(devaddress) | dev_addr dev_addr := devaddress << 1 | 0 i2cObject.i2cStart i2cObject.i2cWrite(dev_addr | 0,8) i2cObject.i2cWrite(PORTS7to0 | 0,8) '0x06 i2cObject.i2cWrite(BLANK_L | 0,8) ' Send Pattern i2cObject.i2cWrite(BLANK_H | 0,8) ' Send Pattern (auto increments to 0x07) i2cObject.i2cStop PUB LED_RED_A(devaddress) | dev_addr dev_addr := devaddress << 1 | 0 i2cObject.i2cStart i2cObject.i2cWrite(dev_addr | 0,8) i2cObject.i2cWrite(PORTS7to0 | 0,8) '0x06 i2cObject.i2cWrite(RED_L | 0,8) ' Send Pattern i2cObject.i2cWrite(RED_H | 0,8) ' Send Pattern (auto increments to 0x07) i2cObject.i2cStop
So, with all that said, the pattern for each bank of LEDs is below. Remember, these are Left/Right banks of 7 LEDs each, with one output of each output bank not used (the "-" in the pattern definition):
LEDs P7-0 "_L" %1000_0000 -RYY_GGGG LEDs P15-8 "_H" %1000_0000 -GGG_GYYR
Here is a pattern for just the two yellows on:
YELLOW_L = %1100_1111 ' -RYY_GGGG YELLOW_H = %1111_1001 ' -GGG_GYYR
The Left (Low) and Right (High) bank positions of LEDs are inverted in relation to the MAX7313 outputs, so, 3 Greens on for Low and High would be %1000_0111 for the Low bank and %1111_0000 for the High bank. The first bit of "1" is for the unused output so it is always "1" in any pattern so that it remains off
The dilemma that is mocking my lack of binary manipulation knowledge is as follows:
Here is what I want to do: Rotate a single "on" LED through the bank, somewhat fast. So visually, an operator can see that each one lights individually. I know that to do that, I should be able to do some straightforward binary manipulation so I don't need a CON list of 8 patterns. What is blocking my train of thought is the challenge with dealing with the unused output between the channels.
Is there an easy way to flip the Low bank value, shift over by one and then make the first bit a 1 to get the High bank value of the same pattern?
I am thinking using a mask to OR with the original value to set the first "1" each time. Is that wrong?
I believe I can do a basic shift operation to move the single "0" through the pattern to light one at a time, but the issue of aligning it against that one unused inverted bit is confusing.
My dream pseudocode would be
Init I2c Setup/7313 Call a routine that repeatedly sends the same variable as the pattern and that variable that gets manipulated each cycle to rotate the "0" through the pattern appropriately.
Any and all help is appreciated.
Comments
%1111_1011 XOR %0000_1100 = %1111_0111
-Phil
EDIT: Ah! ROL works with longs... Thx
dgately
If you have an 8 bit value 1, 000000001, you can shift that one bit left by multiplying it by 2, 00000010. The pattern continues until the values roll over to 0, so you will need to check every iteration if the value = 0 and if it does, add 1 instead of multiplying by 2.
Something similar to this will work (I forget the ROL function so I have just used SHL instead)
Just re-read your original post. So here is a routine using 16 bits of the pattern long where lower 8 bits for one LED group and next 8 bits for the next.
That seems inconsistent with the patterns for 2 yellows. Does a 0 bit signify on or off?
Phil, so it looks like I would just need to change the value of what I XOR with the pattern each time to keep pushing the 0 across the pattern. Sounds fairly straightforward and at least makes sense to me.
JRoark, JonnyMac stated that ROL only works with longs, so not sure how to change yours for that
Cluso, That makes some sense to me, but I need to learn why you are using $80 and $8000 so I fully understand. I haven't touched SPIN for nerly a yer, so a little rusty.
JonnyMac, I think I am following your code correctly, so I can see how that could be useful, IF I am able to understand it well enough
mpark, a 0 is on and 1 is off. The first bit is always 1 because that port isn't used, thus remains off all the time.
I won't be able to get the tester back in my hands until Thursday, but I am updating some code for testing variations.
(the rest deleted, I misread "-" for "_"!)
Perhaps I miss-read the requirement.
Cluso, the pattern I am after is simply a single LED starting at green and going to the red, then repeating. To my understanding, I can't send Low and High bits together as a single data segment, they have to be sent separately, but I could be wrong. I will play around with it as a Long, rather than two Words.
Thanks for the pattern example, I used that method to show what I have been trying to explain:
I realized that I can actually make use of the unused LED and just cycle the "ON" right through it rather than trying to figure out how to work around it. (that pin is not connected to anything on the PCBA)
So, my pattern can be:
Production finished the current batch of boards so I will run some new code through it over the weekend.
I tried several different options from the different suggestions and while doing so, I realized that the idea of a Knight Rider chasing LED pattern would actually meet my goals. I also realized that the reason I was having so much trouble was due to the inverted nature (1 is off and 0 is on) so I simply used a starting pattern that was opposite to make use of the shifting commands easily and then inverted it when I sent it to the MAX7313. With all that said, my Main code looks like this:
And my LED_BINARY method looks like this:
Everything looks good and it is now very easy to verify all LEDs in a few seconds.