Hi again.

I sent a day old file last time and it had debugging stuff and ws2811.off 
hadn't counter and zero made some problems.

Here is right version. Hopefully no more big bugs. Feel free to comment. I've 
tested with small stripe and 20MHz F_CPU.
The communication timing is
zero bit: 250/1000 ns 
one bit: 1000/250 ns
reset: 50+us

Best regards,
Hannu Vuolasaho

; Hannu Vuolasaho 2014

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 2 of the License, or
;    (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.
;
;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

; Device driver for WS2811 LED drivers.

; v. 20141113
; FIXED: 
;    ws2811.off ( n -- ) now has counter
;    wait_cycles doesn't print debug data
;    Zero check

; Rather stupid delay system.

eight_cycle_delay:
    ret

.macro wait_cycles
  .set busy_wait =  ((@0 * @1) / F_CPU)
  .if (busy_wait & 16)
    call eight_cycle_delay
    call eight_cycle_delay
  .endif
  .if   (busy_wait & 8)
    call eight_cycle_delay
  .endif
  .if   (busy_wait & 4)
    rjmp  pc+1
    rjmp  pc+1
  .endif
  .if   (busy_wait & 2)
    rjmp  pc+1
  .endif
  .if   (busy_wait & 1)
    nop
  .endif
.endmacro

.if (F_CPU < 8000000)
    .error "WS2811 800 kHz driver can't work. F_CPU too slow"
.endif
.macro ns250_fill_delay
  wait_cycles 3, 20000000
.endmacro
.macro ns1000_fill_delay
  wait_cycles 9, 20000000
.endmacro

.set WS2811_DDR=(WS2811_PORT-1)

;****f* WS2811.WRITE
; NAME
;   WS2811.WRITE
; SYNOPSIS
;   WS2811.WRITE ( addr len -- ) Write array of 8-bit RGB values to LED chain.
; DESCRIPTION
;   Write RGB values to WS2811 device chain.
;******
; ( addr len -- )
; Hardware
; Write to WS2811 devices

VE_WS2811_WRITE:
    .dw $ff0c
    .db "ws2811.write"
    .dw VE_HEAD
    .set VE_HEAD = VE_WS2811_WRITE
XT_WS2811_WRITE:
    .dw PFA_WS2811_WRITE
PFA_WS2811_WRITE:
    movw temp0, tosl ; len
    loadtos
    mov temp2, temp0
    or temp2, temp1
    brne PFA_WS2811_WRITE_CONTINUE ; jump end if zero given.
    loadtos ; dump the temp value from tos
    jmp_ DO_NEXT
PFA_WS2811_WRITE_CONTINUE:
    ; Reset WS2811
    sbi WS2811_DDR, WS2811_BIT; Set as output
    ;Write zero
    cbi WS2811_PORT, WS2811_BIT; Write zero
    delay 50 ; Wait 50 usec
    ; Prepare to write
    movw Z, tosl ; addr
    in temp2, WS2811_PORT ; zero value
    cbr temp2, (1 << WS2811_BIT)
    mov temp3, temp2 ; one value
    sbr temp3, (1 << WS2811_BIT)
    ; Save status register and disable interrupts. This is critical.
    in temp4, SREG
    cli
PFA_WS2811_WRITE_START:
    ldi temp6, 7             ; Bit counter to 7
     ld temp5, Z+              ; Load from Z to 
PFA_WS2811_WRITE_CLK_6:
    nop 
PFA_WS2811_WRITE_CLK_7:
    nop
     ns1000_fill_delay
    out WS2811_PORT, temp2   ; Pin DOWN 
PFA_WS2811_WRITE_CLK_9: 
    lsl temp5                 ; MSB to carry
    ns250_fill_delay
PFA_WS2811_WRITE_CLK_0: 
    out WS2811_PORT, temp3   ; Pin UP
      ns250_fill_delay
    brcs PFA_WS2811_WRITE_CLK_3; If carry set jump CLK_3
    out WS2811_PORT, temp2   ; Carry not set, pin DOWN
PFA_WS2811_WRITE_CLK_3: 
    dec temp6                ; Bit counter -1 
    brne PFA_WS2811_WRITE_CLK_6 ; Jump CLK_6 if bits  left to send from byte.
    lsl temp5                 ; MSB to carry
     brcc PFA_WS2811_WRITE_LOAD_CLOCK_8 ; If carry clear jump
     ldi temp6, 7             ; Bit counter to 7
    ns1000_fill_delay
     out WS2811_PORT, temp2   ; Pin DOWN
    nop
    ns250_fill_delay
     out WS2811_PORT, temp3   ; Pin UP
    ns250_fill_delay
    subi temp0, 1            ; Byte counter -1
    sbci temp1, 0            ; sbiw equivalent
     ;sbiw temp0, 1            ; Byte counter -1
     ld temp5, Z+              ; Next byte
     brne PFA_WS2811_WRITE_CLK_7 ; Jump CLK_7 if byte counter 0
    ns1000_fill_delay
     rjmp PFA_WS2811_WRITE_EXIT_CLK_8 ; jump to end
PFA_WS2811_WRITE_LOAD_CLOCK_8:
    ns1000_fill_delay 
    out WS2811_PORT, temp2   ; Pin DOWN 
     ldi temp6, 7
    ns250_fill_delay
     out WS2811_PORT, temp3   ; Pin UP
     nop
    
    ns250_fill_delay
     out WS2811_PORT, temp2   ; Pin DOWN
    ns1000_fill_delay 
    subi temp0, 1            ; Byte counter -1
    sbci temp1, 0            ; sbiw equivalent;
     ;sbiw temp0, 1            ; Byte counter -1
     ld temp5, Z+              ; Next byte
     brne PFA_WS2811_WRITE_CLK_9 ; Jump CLK_9 if byte count != 0
PFA_WS2811_WRITE_EXIT_CLK_8:
    out WS2811_PORT, temp2   ; Pin DOWN
    nop 
    ns250_fill_delay
    out WS2811_PORT, temp3   ; Pin UP
    out SREG, temp4
    loadtos ; dump the temp value from tos
    jmp_ DO_NEXT

    
;****f* WS2811.OFF
; NAME
;   WS2811.OFF
; SYNOPSIS
;   WS2811.OFF ( n -- ) shut off n ws2811 leds.
; DESCRIPTION
;   Simple loop which write zero to chain n * 3 times.
;******
; ( n -- )
; Hardware
; Write to WS2811 devices

VE_WS2811_OFF:
    .dw $ff0a
    .db "ws2811.off"
    .dw VE_HEAD
    .set VE_HEAD = VE_WS2811_OFF
XT_WS2811_OFF:
    .dw PFA_WS2811_OFF
PFA_WS2811_OFF:
    mov temp0, tosl
    or temp0, tosh
;    cpi temp0, 0
    breq PFA_WS2811_OFF_END ; jump end if zero given.
     ; Reset WS2811
    sbi WS2811_DDR, WS2811_BIT; Set as output
    ;Write zero
    cbi WS2811_PORT, WS2811_BIT; Write zero
    delay 50 ; Wait 50 usec
    ldi temp3,24
    in temp1, WS2811_PORT ; zero value
    cbr temp1, (1 << WS2811_BIT)
    mov temp2, temp1 ; one value
    sbr temp2, (1 << WS2811_BIT)
    in temp0, SREG
    cli
PFA_WS2811_RESET_LOOP_CLK_5:
    rjmp pc+1
    rjmp pc+1
    ns250_fill_delay
PFA_WS2811_RESET_LOOP_CLK_0:
    out WS2811_PORT, temp2; Write one
    nop
    ns250_fill_delay
    out WS2811_PORT, temp1; Write zero
    ns1000_fill_delay 
    dec temp3 ; bec bit counter
    brne PFA_WS2811_RESET_LOOP_CLK_5
    ldi temp3,24 ; All bits sent reset counter
    sbiw tosl, 1 ; decrement LED count
    brne PFA_WS2811_RESET_LOOP_CLK_0
    out SREG, temp0 ; All LEDs shut off, enable interrupts
    ns250_fill_delay
    out WS2811_PORT, temp2 ; write one
PFA_WS2811_OFF_END:
    loadtos ; dump the temp value from tos
    jmp_ DO_NEXT

                                          
------------------------------------------------------------------------------
Comprehensive Server Monitoring with Site24x7.
Monitor 10 servers for $9/Month.
Get alerted through email, SMS, voice calls or mobile push notifications.
Take corrective actions from your mobile device.
http://pubads.g.doubleclick.net/gampad/clk?id=154624111&iu=/4140/ostg.clktrk
_______________________________________________
Amforth-devel mailing list for http://amforth.sf.net/
Amforth-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/amforth-devel

Reply via email to