SX/B 2.00.07 array issue ? - (4) 74HC595 use of SHIFTOUT with 32 LEDs - Sequenc
I have written a LED sequencer program with 32 LEDs and (4) 74HC595's. See attached schematic and code. The schematic reflects using 12v LEDs and ULN2803s so disreguard that for the moment (but I don't think it matters anyway for my issue).
In the code below (and attached), pay attention to the·array declaration·'pattern··VAR·Byte(LED_COUNT)' which was set to 32 by the CONstant LED_COUNT.·All was working well until I·worked·on expanding the number of DATA statements which seemed to be limited to 28 until·strange LED displays started happening afterwards. So I limited it to 28 and it worked out well for Chaser4 and Chaser5 - DATA statements anyway. But then I noticed that LED_COUNT was set to 32 and for use in the DATLONG routine it should have been set to 28 * 4 which is 112 (not the original 32). So I·set the·CONstant LED_COUNT_LONG·to 112. This is when I got a·VARIABLE EXCEED AVAILABLE RAM error. I can change LED_COUNT_LONG down to as low as 103 without gettting the error but that doesn't really answer the issue.
Here is the question.
Why was the DATLONG routine able to function correctly at all knowing that pattern(idx) was being addressed well above the LED_COUNT value of 32. Values between 0 and 111 was being inserted into pattern(idx)? The program runs well but just doesn't make sense since I beleive pattern(idx) would need to be set to 112 (LED_COUNT_LONG) not 32 (LED_COUNT) for it to work at all.
I am using the new Public Beta version of SX/B 2.00.07.
In the code below (and attached), pay attention to the·array declaration·'pattern··VAR·Byte(LED_COUNT)' which was set to 32 by the CONstant LED_COUNT.·All was working well until I·worked·on expanding the number of DATA statements which seemed to be limited to 28 until·strange LED displays started happening afterwards. So I limited it to 28 and it worked out well for Chaser4 and Chaser5 - DATA statements anyway. But then I noticed that LED_COUNT was set to 32 and for use in the DATLONG routine it should have been set to 28 * 4 which is 112 (not the original 32). So I·set the·CONstant LED_COUNT_LONG·to 112. This is when I got a·VARIABLE EXCEED AVAILABLE RAM error. I can change LED_COUNT_LONG down to as low as 103 without gettting the error but that doesn't really answer the issue.
Here is the question.
Why was the DATLONG routine able to function correctly at all knowing that pattern(idx) was being addressed well above the LED_COUNT value of 32. Values between 0 and 111 was being inserted into pattern(idx)? The program runs well but just doesn't make sense since I beleive pattern(idx) would need to be set to 112 (LED_COUNT_LONG) not 32 (LED_COUNT) for it to work at all.
I am using the new Public Beta version of SX/B 2.00.07.
' ========================================================================= ' ' File...... 74HC595_3_Test.SXB ' Purpose... Expanding the SX outputs with multiple 74HC595's ' Author.... Timothy Gilmore ' E-mail.... [url=mailto:Gilmoret@us.saic.com]Gilmoret@us.saic.com[/url] ' Started... 28 JAN 2009 ' Updated... 31 JAN 2009 ' ' ========================================================================= ' ------------------------------------------------------------------------- ' Program Description ' ------------------------------------------------------------------------- ' Cascade (4) 74HC595's together for use with 32 LEDs ' ------------------------------------------------------------------------- ' Device Settings ' ------------------------------------------------------------------------- DEVICE SX28, OSC4MHZ, TURBO, STACKX, OPTIONX FREQ 4_000_000 ' ------------------------------------------------------------------------- ' IO Pins ' ------------------------------------------------------------------------- Clock VAR RA.0 ' shift clock DataIn VAR RA.1 ' shift data in Strobe VAR RA.2 ' strobe outputs ' ------------------------------------------------------------------------- ' Constants ' ------------------------------------------------------------------------- DelayTime CON 500 DelayTimeHalf CON DelayTime / 2 DelayTimeQtr CON DelayTime / 4 DelayTimeFifth CON DelayTime / 5 DelayTimeTenth CON DelayTime / 10 LED_COUNT CON 32 'Total number of LEDs used LED_COUNT_MIN1 CON 31 'LEDs - 1 LED_COUNT_DIV8 CON 4 'LEDs / 8 [b]LED_COUNT_LONG CON 112 '28 sets of 4 DATA statements = 112 LED_COUNT_LONG_MIN1 CON 111 'LED sets - 1[/b] ' ------------------------------------------------------------------------- ' Variables ' ------------------------------------------------------------------------- pattern VAR Byte(LED_COUNT) ' pattern for LEDs - [b]This works - but why? 'pattern VAR Byte(LED_COUNT_LONG)[/b] ' ????? Causes [b]VARIABLE EXCEED AVAILABLE RAM[/b] error idx VAR Byte idx2 VAR Byte temp1 VAR Byte ' subroutine work vars tmpW1 VAR Word ' subroutine work vars ' ========================================================================= PROGRAM Start ' ========================================================================= ' ------------------------------------------------------------------------- ' Subroutine Declarations ' ------------------------------------------------------------------------- DATPAT SUB 2 DATLONG SUB 2 FORWARD_1 SUB 0 BACKWARD_1 SUB 0 OUT SUB 0 ' move value to A6821s CLEARALL SUB 0 ' ------------------------------------------------------------------------- ' Program Code ' ------------------------------------------------------------------------- Start: PLP_A = %0111 ' pull-up unused pins PLP_B = %00000000 PLP_C = %00000000 RA = %0000 TRIS_A = %1000 Main: FORWARD_1 BACKWARD_1 DATPAT Chaser2 DATPAT Chaser1 DATPAT Chaser3 DATPAT Chaser3 DATPAT Chaser3 [b]DATLONG Chaser4 DATLONG Chaser5[/b] DATLONG Chaser4 DATLONG Chaser5 GOTO Main END ' ------------------------------------------------------------------------- ' Subroutine Code ' ------------------------------------------------------------------------- SUB DATPAT tmpW1 = __WPARAM12 FOR idx = 0 TO LED_COUNT_MIN1 READINC tmpW1, pattern(idx) NEXT idx FOR idx = 0 TO LED_COUNT_MIN1 STEP LED_COUNT_DIV8 SHIFTOUT DataIn, Clock, MSBFIRST, pattern(idx) ' send the bits idx2 = idx + 1 SHIFTOUT DataIn, Clock, MSBFIRST, pattern(idx2)' send the bits idx2 = idx2 + 1 SHIFTOUT DataIn, Clock, MSBFIRST, pattern(idx2)' send the bits idx2 = idx2 + 1 SHIFTOUT DataIn, Clock, MSBFIRST, pattern(idx2)' send the bits PULSOUT Strobe, 1 IF tmpW1 <> Chaser3 THEN PAUSE DelayTimeFifth ELSE PAUSE DelayTime ENDIF NEXT idx CLEARALL 'Clear out all the patterns ENDSUB [b]SUB DATLONG tmpW1 = __WPARAM12 FOR idx = 0 TO LED_COUNT_LONG_MIN1 READINC tmpW1, pattern(idx) NEXT idx[/b] [b][/b] [b] FOR idx = 0 TO 111 STEP LED_COUNT_DIV8 SHIFTOUT DataIn, Clock, MSBFIRST, pattern(idx) ' send the bits idx2 = idx + 1 SHIFTOUT DataIn, Clock, MSBFIRST, pattern(idx2)' send the bits idx2 = idx2 + 1 SHIFTOUT DataIn, Clock, MSBFIRST, pattern(idx2)' send the bits idx2 = idx2 + 1 SHIFTOUT DataIn, Clock, MSBFIRST, pattern(idx2)' send the bits PULSOUT Strobe, 1 IF tmpW1 <> Chaser4 THEN PAUSE DelayTimeTenth ELSE PAUSE DelayTime ENDIF NEXT idx CLEARALL 'Clear out all the patterns ENDSUB[/b] SUB CLEARALL FOR idx = 0 TO LED_COUNT_MIN1 pattern(idx) = 0 NEXT idx ENDSUB SUB FORWARD_1 idx = 0 pattern(0) = %00000001 DO OUT ' move pattern to LEDs PAUSE DelayTimeHalf ' hold pattern(0) = pattern(0) << 1 ' shift pattern left INC idx LOOP UNTIL idx = 8 idx = 0 pattern(1) = %00000001 DO OUT ' move pattern to LEDs PAUSE DelayTimeHalf ' hold pattern(1) = pattern(1) << 1 ' shift pattern left INC idx LOOP UNTIL idx = 8 idx = 0 pattern(2) = %00000001 DO OUT ' move pattern to LEDs PAUSE DelayTimeHalf ' hold pattern(2) = pattern(2) << 1 ' shift pattern left INC idx LOOP UNTIL idx = 8 idx = 0 pattern(3) = %00000001 DO OUT ' move pattern to LEDs PAUSE DelayTimeHalf ' hold pattern(3) = pattern(3) << 1 ' shift pattern left INC idx LOOP UNTIL idx = 8 ENDSUB SUB BACKWARD_1 idx = 8 pattern(3) = %10000000 DO OUT ' move pattern to LEDs PAUSE DelayTimeQtr ' hold pattern(3) = pattern(3) >> 1 ' shift pattern left DEC idx LOOP UNTIL idx = 0 idx = 8 pattern(2) = %10000000 DO OUT ' move pattern to LEDs PAUSE DelayTimeQtr ' hold pattern(2) = pattern(2) >> 1 ' shift pattern left DEC idx LOOP UNTIL idx = 0 idx = 8 pattern(1) = %10000000 DO OUT ' move pattern to LEDs PAUSE DelayTimeQtr ' hold pattern(1) = pattern(1) >> 1 ' shift pattern left DEC idx LOOP UNTIL idx = 0 idx = 8 pattern(0) = %10000000 DO OUT ' move pattern to LEDs PAUSE DelayTimeQtr ' hold pattern(0) = pattern(0) >> 1 ' shift pattern left DEC idx LOOP UNTIL idx = 0 ENDSUB ' ------------------------------------------------------------------------- SUB OUT FOR temp1 = 3 to 0 step -1 SHIFTOUT DataIn, Clock, MSBFIRST, pattern(temp1)' send the bits NEXT temp1 PULSOUT Strobe, 1 ' transfer to outputs ENDSUB '74HC595 Last 3rd 2nd 1st Chaser1: DATA %00000001, %10000000, %11000000, %00000011 DATA %00000010, %01000000, %01100000, %00000110 DATA %00000100, %00100000, %00110000, %00001100 DATA %00001000, %00010000, %00011000, %00011000 DATA %00010000, %00001000, %00001100, %00110000 DATA %00100000, %00000100, %00000110, %01100000 DATA %01000000, %00000010, %00000011, %11000000 DATA %10000000, %00000001, %00000001, %10000000 Chaser2: DATA %00000000, %11001100, %00011000, %00000000 DATA %00000000, %00110011, %00111100, %00000000 DATA %00000000, %11001100, %01111110, %00000000 DATA %00000000, %00110011, %11111111, %00000000 DATA %00000000, %11110000, %11111111, %00000000 DATA %00000000, %00001111, %01111110, %00000000 DATA %00000000, %11110000, %00111100, %00000000 DATA %00000000, %00001111 ,%00011000, %00000000 Chaser3: DATA %00001111, %00001111, %00001111, %00001111 DATA %00111100, %00111100, %00111100, %00111100 DATA %11110000, %11110000, %11110000, %11110000 DATA %11000011, %11000011, %11000011, %11000011 DATA %00001111, %00001111, %00001111, %00001111 DATA %00111100, %00111100, %00111100, %00111100 DATA %11110000, %11110000, %11110000, %11110000 DATA %11000011, %11000011, %11000011, %11000011 [b]Chaser4: DATA %00000000, %00000000, %00000000, %00001111 DATA %00000000, %00000000, %00000000, %00011110 DATA %00000000, %00000000, %00000000, %00111100 DATA %00000000, %00000000, %00000000, %01111000 DATA %00000000, %00000000, %00000000, %11110000 DATA %00000000, %00000000, %00000001, %11100000 DATA %00000000, %00000000, %00000011, %11000000 DATA %00000000, %00000000, %00000111, %10000000 DATA %00000000, %00000000, %00001111, %00000000 DATA %00000000, %00000000, %00011110, %00000000 DATA %00000000, %00000000, %00111100, %00000000 DATA %00000000, %00000000, %01111000, %00000000 DATA %00000000, %00000000, %11110000, %00000000 DATA %00000000, %00000001, %11100000, %00000000 DATA %00000000, %00000011, %11000000, %00000000 DATA %00000000, %00000111, %10000000, %00000000 DATA %00000000, %00001111, %00000000, %00000000 DATA %00000000, %00011110, %00000000, %00000000 DATA %00000000, %00111100, %00000000, %00000000 DATA %00000000, %01111000, %00000000, %00000000 DATA %00000000, %11110000, %00000000, %00000000 DATA %00000001, %11100000, %00000000, %00000000 DATA %00000011, %11000000, %00000000, %00000000 DATA %00000111, %10000000, %00000000, %00000000 DATA %00001111, %00000000, %00000000, %00000000 DATA %00011110, %00000000, %00000000, %00000000 DATA %00111100, %00000000, %00000000, %00000000 DATA %01111000, %00000000, %00000000, %00000000 Chaser5: DATA %11110000, %00000000, %00000000, %00000000 DATA %01111000, %00000000, %00000000, %00000000 DATA %00111100, %00000000, %00000000, %00000000 DATA %00011110, %00000000, %00000000, %00000000 DATA %00001111, %00000000, %00000000, %00000000 DATA %00000111, %10000000, %00000000, %00000000 DATA %00000011, %11000000, %00000000, %00000000 DATA %00000001, %11100000, %00000000, %00000000 DATA %00000000, %11110000, %00000000, %00000000 DATA %00000000, %01111000, %00000000, %00000000 DATA %00000000, %00111100, %00000000, %00000000 DATA %00000000, %00011110, %00000000, %00000000 DATA %00000000, %00001111, %00000000, %00000000 DATA %00000000, %00000111, %10000000, %00000000 DATA %00000000, %00000011, %11000000, %00000000 DATA %00000000, %00000001, %11100000, %00000000 DATA %00000000, %00000000, %11110000, %00000000 DATA %00000000, %00000000, %01111000, %00000000 DATA %00000000, %00000000, %00111100, %00000000 DATA %00000000, %00000000, %00011110, %00000000 DATA %00000000, %00000000, %00001111, %00000000 DATA %00000000, %00000000, %00000111, %10000000 DATA %00000000, %00000000, %00000011, %11000000 DATA %00000000, %00000000, %00000001, %11100000 DATA %00000000, %00000000, %00000000, %11110000 DATA %00000000, %00000000, %00000000, %01111000 DATA %00000000, %00000000, %00000000, %00111100 DATA %00000000, %00000000, %00000000, %00011110[/b]
Comments
That is awesome. I never knew about that!
If I declare: pattern·VAR·Byte(103) it shows all of the RAM locations so you know how much space you have left for RAM variables / arrays. At 103 it brings it to the very end limit. So using an array of 112 would cause the error. Great to know!
With pattern··VAR·Byte(103) - See below:
With pattern··VAR·Byte(LED_COUNT) 'where LED_COUNT is 32
Thanks again for this very helpfull find!
·
The demo shows how to loop through the items in a table. A couple of your tables are simply doing shifts and rolls. I created routines that do this without having to read from the table more than once (the first element) -- and you can actually eliminate the table by using the PUT_DRAM routine. If you want to shift all the LEDs left, for example, call DSHIFT_LEFT then DRAM_2_LEDS. This is coded in assembly so that bits can move from one byte in the array to another -- basically, dRam is a 32-bit value. I also coded routines to "roll" the bits so that the LED on one end wraps around to the other side (is not lost in the bit bucket as with shifting). Both the shift and roll routines allow you to specify the number of bits to move and default to 1 if you don't pass a parameter.
See if you can build your show with these new routines.
[noparse][[/noparse]Edit] NoLatch constant fixed and order adjusted for $IFUSED.
Post Edited (JonnyMac) : 1/31/2009 10:58:49 PM GMT
Is there anything different in the hardware setup. I previously attached my schematic (disreguard the +12v and ULN2803A usage). Eventually, I want to control about 150 or more LEDs which means I may have to move to an SX48.
Fixes:
1) NoLatch constant was incorrect (you should have busted me on that one, Tim <grin>)
2) Order of SUBs adjusted to play nice with $IFUSED
3) (not a fix) changed DRAM_2_LEDS to DRAM_TO_LEDS, DATA_2_LEDS to DATA_TO_LEDS
One note: On my setup I shift through the LSB '595 -- it looks like your hardware does this, too.
Post Edited (JonnyMac) : 2/1/2009 12:00:49 AM GMT
Note that the PUT_DRAM at Chase_5 is only required if you want to call Chase_5 independent of Chase_4.
Your program is working great on my setup. Thank you for sharing! I need to follow closely your program to see what is happening. One thing that I don't immediately see is where to put the updated Chaser4 and 5 routines that you just posted? I don't see the Chaser 2 and 3 being used but I can probably figure that out after looking at your great program in more detail.
Once again Thank you so much for your program.
Great job putting this together and thinking outside the box. Assembly language is a good thing when you know it.
See attached updated SXB file.
I was trying to modify your code to use it with (16) 74HC595s for 128 LEDs. All I care about at the Moment is the Chaser4 sequence.
However, I don't think the·logic I used in·your Assembly Language routines will work. Especially look at PUT DRAM·to start. There are only 4 (or 5) __PARAM statements available Not 16. How can I get arround this?
See attached.
Thanks.
Don't be concerned about the Assembly stuff; those are working routines. You don't find it necessary to fix SEROUT, do you? Of course not. So as you trust that SEROUT works please trust that I spent time coding these routines and testing them for use in my own projects -- now you can use them in yours.
Thanks.
I got it working to allow for my 128 LED requirement using (16) 74HC595s. Although I beleive it is possible to modify it to have up to 800 LEDs without running out of memory on an SX28 and probably double that on an SX48.
I am currently only using your Chase4 and Chase5 routines that have been modified. All of the other routines are in place for future use - just commented.
It can probably be cleaned up a bit but I believe it is working well.
Thanks for sticking with me.
Since PUT_DRAM is gone I suggest you use LOAD_DRAM and an address of a table that holds the bits you want to load; this will probably make your listing cleaner, anyway. Run the attached demo in the Debugger to verify that the routines that load and manipulate the 16-byte dRam() array work as intended.
FWIW: I don't consider myself an Assembly programmer; that said, between Guenther's book and the output from the SX/B compiler I have learned how to add Assembly segments into my programs where that would be the most efficient strategy. I don't see SX/B as a BASIC language, but as a BASIC/Assembly framework for programming the SX chip.
[noparse][[/noparse]Edit] I updated the shift and roll routines using looping but your linear versions may in fact be faster. I did what I did for the exercise as I'm trying to get better at Assembly -- you've got two ways to go; both work.
[noparse][[/noparse]Edit] I updated my second demo with linear routines for loading, shifting and rolling as these are considerably faster (and easier to understand) than the loop versions.
Post Edited (JonnyMac) : 2/1/2009 7:31:57 PM GMT
So from your last posting, I believe you stated that either my program or your program should work. I just wanted to make sure I wasn't missing something as I am repeating the PUT_DRAM_x routine 4 times to cover the 16 registers - which you are not using. First attempt at running your·2 programs produces no movement of the LEDs but I will look at it closer. Although, as long as my last post·attachement file will work, I would just as well·use that and bring in your other routines·(you modified for 16·registers) for future use.
[noparse][[/noparse]Edit] I just reconnected a 74HC595 on my PDB and DRAM_TO_LEDS is working as expected. Remember, if you want to shift the LEDs you have to call a shift or roll routine and then update the outputs with DRAM_TO_LEDS. If you wan the display updated at the end of a shift or roll put DRAM_TO_LEDS right before the $ENDIF marker at the end of each of these routines.
Time for a Super Bowl party in Beverly Hills -- I'm outta here!
Post Edited (JonnyMac) : 2/1/2009 9:30:16 PM GMT