1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112 | ------------------------------------------------------------------------------
-- --
-- Copyright (C) 2019-2020, AdaCore --
-- --
-- Redistribution and use in source and binary forms, with or without --
-- modification, are permitted provided that the following conditions are --
-- met: --
-- 1. Redistributions of source code must retain the above copyright --
-- notice, this list of conditions and the following disclaimer. --
-- 2. Redistributions in binary form must reproduce the above copyright --
-- notice, this list of conditions and the following disclaimer in --
-- the documentation and/or other materials provided with the --
-- distribution. --
-- 3. Neither the name of the copyright holder nor the names of its --
-- contributors may be used to endorse or promote products derived --
-- from this software without specific prior written permission. --
-- --
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS --
-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT --
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR --
-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT --
-- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --
-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT --
-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, --
-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY --
-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT --
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE --
-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --
-- --
------------------------------------------------------------------------------
-- Bit-bang a sequence of color LED values to a one-pin LED strip (WS2812B
-- or similar).
with System.Machine_Code; use System, System.Machine_Code;
with NRF_SVD.GPIO; use NRF_SVD.GPIO;
with MicroBit.Time;
package body MicroBit.IOs.NeoPixel is
-----------
-- Write --
-----------
procedure Write (Pin : Pin_Id; Values : UInt8_Array) is
Point : constant GPIO_Point := Points (Pin);
Mask : constant UInt32 := 2 ** Point.Pin;
EOL : constant String := ASCII.LF & ASCII.HT;
begin
-- Set pin to digital out mode and reset strip
Set (Pin, False);
MicroBit.Time.Delay_Ms (1);
-- The following loop is very time-sensitive. The bit frame is 1.25 µs,
-- i.e. 20 cycles of the 16 MHz clock. So, we run it with IRQs disabled,
-- and carefully account for every cycle.
-- Code taken from:
-- https://github.com/Microsoft/pxt-ws2812b/blob/master/sendBuffer.asm
Asm (" cpsid i @ disable irq" & EOL &
" b .start" & EOL &
".nextbit: @ c0" & EOL &
" str %2, [%1, #0] @ pin := hi c2" & EOL &
" tst r6, r0 @ c3" & EOL &
" bne .islate @ c4" & EOL &
" str %2, [%0, #0] @ pin := lo c6" & EOL &
".islate:" & EOL &
" lsr r6, r6, #1 @ r6 >>= 1 c7" & EOL &
" bne .justbit @ c8" & EOL &
"@ not just a bit - need new byte" & EOL &
" add %3, #1 @ buf++ c9" & EOL &
" sub %4, #1 @ len-- c10" & EOL &
" bcc .stop @ if (len<0) goto .stop c11" & EOL &
".start:" & EOL &
" movs r6, #0x80 @ reset mask c12" & EOL &
" nop @ c13" & EOL &
".common: @ c13" & EOL &
" str %2, [%0, #0] @ pin := lo c15" & EOL &
" @ always re-load byte - it just fits with the" & EOL &
" @ cycles better this way." & EOL &
" ldrb r0, [%3, #0] @ r0 := *buf c17" & EOL &
" b .nextbit @ c20" & EOL &
".justbit: @ c10" & EOL &
" @ no nops, branch taken is already 3 cycles" & EOL &
" b .common @ c13" & EOL &
".stop:" & EOL &
" str %2, [%0, #0] @ pin := lo" & EOL &
" cpsie i @ enable irq",
Inputs => (Address'Asm_Input ("l", GPIO_Periph.OUTCLR'Address), -- %0
Address'Asm_Input ("l", GPIO_Periph.OUTSET'Address), -- %1
UInt32'Asm_Input ("l", Mask), -- %2
Address'Asm_Input ("l", Values'Address), -- %3
Natural'Asm_Input ("l", Values'Length)), -- %4
Volatile => True,
Clobber => "r0,r6");
end Write;
end MicroBit.IOs.NeoPixel;
|