microbit_bsp_0.2.0_74e9a20a/src/microbit-ios-neopixel.adb

  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;