Merge branch 'master'
[fw/altos] / src / samd21 / ao_apa102.c
1 /*
2  * Copyright © 2019 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include <ao.h>
20 #include <ao_snek.h>
21
22 #define bit(v)  do {                            \
23                 port_c->outtgl = (1 << pin_c);  \
24                 ao_arch_nop(); \
25                 ao_gpio_set(port_d, pin_d, v);  \
26                 ao_arch_nop(); \
27                 port_c->outtgl = (1 << pin_c);  \
28                 ao_arch_nop(); \
29         } while (0)
30
31 #define byte(v) do {                            \
32                 uint8_t _bit_ = 0x80;           \
33                 while (_bit_) {                 \
34                         bit(!!((v) & _bit_));   \
35                         _bit_ >>= 1;            \
36                 }                               \
37         } while(0)
38
39 #define repeat(v,c) do {                        \
40                 uint8_t _i_;                    \
41                 for (_i_ = 0; _i_ < (c); _i_++) \
42                         bit(v);                 \
43         } while (0)
44
45 void
46 ao_snek_apa102_write(void *gpio_d, uint8_t pin_d,
47                      void *gpio_c, uint8_t pin_c,
48                      int npixel,
49                      struct snek_neopixel *pixels)
50 {
51         struct samd21_port *port_d = gpio_d;
52         struct samd21_port *port_c = gpio_c;
53
54         ao_gpio_set(port_c, pin_c, 1);
55         int i;
56         for (i = 0; i < 32; i++)
57                 ao_arch_nop();
58         repeat(0, 32);
59         while (npixel--) {
60                 byte(0xff);
61                 byte(pixels->b);
62                 byte(pixels->g);
63                 byte(pixels->r);
64         }
65         repeat(1, 32);
66 }