The '0' and '1' commands

The '0' and '1' commands turn all of the unallocated outputs OFF or ON. By "unallocated", it always means PORT B, PINS 0, 1, and 2. If the nRF24L01+ (i.e., if the WORD at EEPROM address 0x45:0x44 does not point to a valid EEPROM address), then it also means PORTB, PIN 7 and PORT D, PINS 4, 5, and 6.

The PORT B, PINS 0, 1, and 2 are in the lower portion of the 2x5 "EISP" connector on the SSG Dual Relay Board and are the pins labeled "8", "9", and "10" on the Arduino Pro Mini board.

If the command is "0" alone, all unallocated outputs are turned OFF.

If the command is "1" alone, all unallocated outputs are turned ON.

If either command has ANY character following the "0" or "1" (which could even be a space), then a WS2812 command is also sent to set the first 8 LEDs attached to every configured PORT C pin which is configured as an output are either (when "0_") set to 0, which is OFF, or (when "1_") set to 255, which is full bright white. This feature is to be able to use the standard PORT C outputs to debug using the WS2812 GRB pixels as individual byte (i.e., 8-bit) data values.

Consider this Assembly language subroutine:
; Pass:  R26 BYTE = bValue to be displayed in the GRB LEDs
;        R27 BYTE = bBitMask to use for PORTC outputs (B000001 to B111111)

.INCLUDE "BinDefs.Def"       ; Definitions of B00010000, etc.
.INCLUDE "IOM328P.Def"       ; Definitions for SREG, PORTC, et.al
.INCLUDE "Indices.Def"       ; All 128 indirectly-accessed system jump indices
; Change "Filename" in the line below with this file's name (less the .ASM)
.INCLUDE "Filename.Ptr"      ; Address constants for targets in the code below

.ORG  0x2600

WS2812_GRBDebug:
   LDI     R30, I_PushAll            ; Allow any Register to be used within this subroutine
   RCALL   ASoftVector_WSDDT
   MOVW    R16, R26                  ; Save R26 and R27, passed by the caller
   LDI     R30, I_StackAlloc50       ; Note: StackAlloc50() alters R27:R26
   RCALL   ASoftVector_WSDDT         ; Returns the pointer to the stack-based
   MOVW    R10, R30                  ;  buffer in 'Z'; save it in R11:R10

   LDI     R23, 0                    ; Use R23 instead of relying on R1 to be 0
   LDI     R20, 8                    ; Initialize the loop count (8 bits)
   LDI     R21, 25                   ; Set the Green component's value
   LDI     R24, 35                   ; Set the Red component's value

WS2812_ShowByteLoop:                 ; R16 (passed as R26) is the data value
   ROR     R16                       ; Output in Little-Endian order
;----- (or)
;  ADD     R16, R16                  ; Output in Big-Endian order
;-----
   IN      R7, SREG                  ; Copy the FLAGS to R7 then, if CARRY was
   SBRS    R7, SREG_C                ;  set, skip the next single instruction
   ST      Z+, R23                   ; Set Green = 0
   SBRC    R7, SREG_C                ; If CARRY was set, change it to nonzero
   ST      Z+, R21                   ; Set Green = constant (25) set above
   SBRS    R7, SREG_C
   ST      Z+, R23                   ; Set Red   = 0
   SBRC    R7, SREG_C
   ST      Z+, R24                   ; Set Red   = constant (35) set above
   ST      Z+, R23                   ; Set Blue  = 0  (always)

   DEC     R20                       ; DEC preserves CARRY; loop back until the
   BRNE    AWS2812_ShowByteLoop      ;  8-bit count in R20 has been satisfied

   MOVW    R24, R10                  ; Transfer the starting address to R25:R24
;- LDI     R23, 0                    ; R23:R22 number of BYTES to be output
   LDI     R22, 8 * 3                ;  (Note that R23 is already 0)
   LDI     R20, PORTC                ; R20: ATMega PORT to use to toggle a bit
   MOV     R18, R17                  ; R18: the bit(s) to toggle on that PORT
   LDI     R30, I_WS2812_Command
   RCALL   ASoftVector_WSDDT         ; Call "WS2812_Command" to perform the actual output

   LDI     R30, I_StackFree50        ; Prepare to deallocate the temporary buffer
   RCALL   ASoftVector_WSDDT         ; Release the temporary stack-based buffer
   LDI     R30, I_PopAll             ; PopAll() MUST use a JUMP, not a CALL!

SoftVector_WSDDT:
   JMP     ASoftVector               ; Only a single FAR JUMP is needed

;------------------------------------
;  iHex image of the above subroutine:
:10260000E0E01ED08D01E2E01BD05F0170E048E009
:1026100059E183E207957FB670FE719370FC519388
:1026200070FE719370FC819371934A9599F7C5017F
:1026300068E148E0212FE7E703D0E3E001D0E1E0E3
:042640000C940000F6
:00000001FF

The subroutine above displays a single BYTE's value to a group of eight (8) WS2812 LEDs. In order to assist in debugging without using the serial port (i.e., printed) output, this routine could be used. The data value that will be displayed is passed in R26, rather than the usual R24 in order to preserve R24.

Consider then, this routine to invoke it:
   .ORG 0x2670

   LDI     R27, B00001000            ; Select PORT C, PIN 3 as the output pin
   LDS     R26, 0x230                ; Read the Parsing Buffer's byte count
   JMP     0x2600                    ; Jump to the WS2812_GRBDebug routine by address

;------------------------------------
;  iHex image of this subroutine:
:0A267000B8E0A09130020C940013B2
:00000001FF
This second 4-line routine (above) obtains the number of bytes in the MITROS Parsing Buffer (at SRAM address 0x230) and displays that as a binary value in LEDs with low-intensity yellow indicating '0' bits and OFF LEDs indicating '1' bits. To enter them into the device's FLASH memory, first enter a '$' as the first character to enter Manager mode (as indicated by a "m>" prompt) then copy and paste the following into the command buffer:
DF+ 0x2600 0x80
:10260000E0E01ED08D01E2E01BD05F0170E048E009
:1026100059E183E207957FB670FE719370FC519388
:1026200070FE719370FC819371934A9599F7C5017F
:1026300068E148E0212FE7E703D0E3E001D0E1E0E3
:042640000C940000F6
:0A267000B8E0A09130020C940013B2
:00000001FF
DF+ 0x2600 128
The resulting interaction should look like this:
m>DF+ 0x2600 0x80
FLASH (program memory) contents:
2600:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
2610:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
2620:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
2630:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
2640:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
2650:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
2660:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
2670:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
m>:10260000E0E01ED08D01E2E01BD05F0170E048E009
m>:1026100059E183E207957FB670FE719370FC519388
m>:1026200070FE719370FC819371934A9599F7C5017F
m>:1026300068E148E0212FE7E703D0E3E001D0E1E0E3
m>:042640000C940000F6
m>:0A267000B8E0A09130020C940013B2
m>:00000001FF
m>DF+ 0x2600 128
FLASH (program memory) contents:
2600:  E0 E0 1E D0 8D 01 E2 E0-1B D0 5F 01 70 E0 48 E0  .........._.p.H.
2610:  59 E1 83 E2 07 95 7F B6-70 FE 71 93 70 FC 51 93  Y.......p.q.p.Q.
2620:  70 FE 71 93 70 FC 81 93-71 93 4A 95 99 F7 C5 01  p.q.p...q.J.....
2630:  68 E1 48 E0 21 2F E7 E7-03 D0 E3 E0 01 D0 E1 E0  h.H.!/..........
2640:  0C 94 00 00 FF FF FF FF-FF FF FF FF FF FF FF FF  ................
2650:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
2660:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
2670:  B8 E0 A0 91 30 02 0C 94-00 13 FF FF FF FF FF FF  ....0...........
m>                                                                              

Notice that there was no need to reboot or stop other aspects of MITROS from continuing to run and operate. Those were FLASH program changes, stored and ready to run, made "on the fly"!

If a string of at least 8 WS2812 LEDs is connected to PORT C, PIN 3 (which is the 4th of the 6 Discrete Output pins on the SSG Dual Relay board or the pin marked "A3" on an Arduino Pro or Pro Mini), and "@ 0x2670" is entered on the keyboard (while still at the "m>" prompt), a single LED should come on, indicating 8 BYTEs (B00001000) in the Parsing Buffer. Try " @ 0x2670" and "@ 0x02670" (or even several intervening or padding spaces) and note the difference in the lights displayed. The LEDs show the binary value of the number of text bytes in the Parsing Buffer input line.

Enter "11" (two ones) and notice that the LEDs all illuminate (and very brightly at that.) Again, any character after the first "1" will cause this same output. Enter "00" (two zeros) and verify that all 8 LEDs extinguish.

Although we really are beyond the scope of the "0" and "1" commands at this point, let's continue by entering these five (5) commands. You can copy the entire lines or just the portions before the ';'. Everything after the ';' is treated as a comment and discarded.
E 1 ~= 0x80             ; Disable multitasking
ESW 0x28C = 0x2670      ; Pointer to the subroutine to call in FLASH
ESW 0x288 = 75 M        ; Time between calls is 75 mSec
E 45 = 8                ; First (only) task structure at uVars.B[ 8 ]
E 1 |= 0x80             ; Enable multitasking

If a standard LED is also attached, it should cause it to blink rapidly (each 75 mSec), as it continuously emits the 24 bits of GRB data to the 8 GRB LEDs. Typing any other command will display the number of BYTEs that have been entered into the Parsing Buffer up to that point, and until Enter is input or backspace is pressed a sufficient number of times to remove all previously input characters from the Parsing Buffer. Two nice aspects is that it is very fast and doesn't interfere with the input or output (i.e., doesn't clutter up the screen.) Consider using this debugging method for displaying single BYTE values in real time.

Just for fun, input "11" then "Enter". Strobe light!

Notice there are a lot of unused BYTEs from 0x2644 to 0x266F (44, actually.) Could the block just entered be moved to 0x2646? There are several ways to do that. Since that code contains no relative jumps, the easiest is to simply change the address on the iHex line which writes the ten (10) BYTEs at 0x2670 so they begin at 0x2646 instead. Without even disabling the multitasking code, check this out:
m>:0A264600B8E0A09130020C940013B2

Checksum error; received: 0xB2; calculated: 0xDC
m>; So, change the two (2) checksum text BYTEs and output again:
m>:0A264600B8E0A09130020C940013DC
m>:00000001FF
m>DF+ 0x2DF+ 600 128
FLASH (program memory) contents:
2600:  E0 E0 1E D0 8D 01 E2 E0-1B D0 5F 01 70 E0 48 E0  .........._.p.H.
2610:  59 E1 83 E2 07 95 7F B6-70 FE 71 93 70 FC 51 93  Y.......p.q.p.Q.
2620:  70 FE 71 93 70 FC 81 93-71 93 4A 95 99 F7 C5 01  p.q.p...q.J.....
2630:  68 E1 48 E0 21 2F E7 E7-03 D0 E3 E0 01 D0 E1 E0  h.H.!/..........
2640:  0C 94 00 00 FF FF B8 E0-A0 91 30 02 0C 94 00 13  ..........0.....
2650:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
2660:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
2670:  B8 E0 A0 91 30 02 0C 94-00 13 FF FF FF FF FF FF  ....0...........
  (was)
m>dfh+- 0x2660 10
:0A266000FFFFFFFFFFFFFFFFFFFF7A
:00000001FF
m>:0A267000FFFFFFFFFFFFFFFFFFFF7A

Checksum error; received: 0x7A; calculated: 0x6A
m>:0A267000FFFFFFFFFFFFFFFFFFFF6A
m>:00000001FF
m>DF+ 0x2600 128
FLASH (program memory) contents:
2600:  E0 E0 1E D0 8D 01 E2 E0-1B D0 5F 01 70 E0 48 E0  .........._.p.H.
2610:  59 E1 83 E2 07 95 7F B6-70 FE 71 93 70 FC 51 93  Y.......p.q.p.Q.
2620:  70 FE 71 93 70 FC 81 93-71 93 4A 95 99 F7 C5 01  p.q.p...q.J.....
2630:  68 E1 48 E0 21 2F E7 E7-03 D0 E3 E0 01 D0 E1 E0  h.H.!/..........
2640:  0C 94 00 00 FF FF B8 E0-A0 91 30 02 0C 94 00 13  ..........0.....
2650:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
2660:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
2670:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
m>                                                                              

But wait! The mulitasking logic is still active. It didn't crash!?

No, MIRTOS stopped calling it since the target (at 0x2670) became 0xFFFF. Note that a binary value is still shown in the LEDs, but that it remained "frozen" with the value B00001011 as new commands were entered.

Check this out:
m>ds+ 0x280 32
SRAM contents:
0280:  00 00 00 00 00 00 00 00-4B 00 2F DC 70 26 00 00  ........K./.p&..
0290:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
m>ESW 0x28C = 0x2646   ; Change the Task 1 subroutine address to call
m>DS+ 0x280 32
SRAM contents:
0280:  00 00 00 00 00 00 00 00-4B 00 F7 E4 46 26 00 00  ........K...F&..
0290:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
m>                                                                              
And the GRB LEDs work again, displaying the number of characters in the Parsing Buffer, executing from the new FLASH address! There was no stopping, reloading, or rebooting; all of the changes were made to the live system. The next step would be to save the buffered BYTE count and only output it it changed from the last time. We'll leave that example for another time.

Of course, there are some caveats in the doing this, one of which was to use the absolute form of the JUMP instruction ("JMP 0x2600") instead of the relative (RJMP) version for this example. This example was just an illustration of what can be done with careful and thoughtful programming in order to make live changes to a running program.