xref: /nrf52832-nimble/packages/NimBLE-latest/apps/blemesh_light/src/ws2812.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include <assert.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include "sysinit/sysinit.h"
24 #include "os/os.h"
25 #include "bsp/bsp.h"
26 #include "pwm/pwm.h"
27 #include "nrfx.h"
28 #include "nrfx_pwm.h"
29 #include "ws2812.h"
30 
31 #define BITS_PER_SEQ    (24)
32 #define BIT0            (0x8000 | 6)
33 #define BIT1            (0x8000 | 11)
34 
35 static const nrfx_pwm_t pwm = NRFX_PWM_INSTANCE(WS2812_PWM);
36 
37 static const nrfx_pwm_config_t pwm_config = {
38     .output_pins = { WS2812_GPIO, NRFX_PWM_PIN_NOT_USED, NRFX_PWM_PIN_NOT_USED, NRFX_PWM_PIN_NOT_USED },
39     .irq_priority = 3,
40     .base_clock = NRF_PWM_CLK_16MHz,
41     .count_mode = NRF_PWM_MODE_UP,
42     .top_value = 20,
43     .load_mode = NRF_PWM_LOAD_COMMON,
44     .step_mode = NRF_PWM_STEP_AUTO,
45 };
46 
47 static uint16_t pwm_seq_values[2][BITS_PER_SEQ];
48 
49 static const nrf_pwm_sequence_t pwm_seq[2] = {
50         {
51             .values.p_raw = pwm_seq_values[0],
52             .length = BITS_PER_SEQ,
53             .repeats = 0,
54             .end_delay = 0,
55         }, {
56             .values.p_raw = pwm_seq_values[1],
57             .length = BITS_PER_SEQ,
58             .repeats = 0,
59             .end_delay = 0,
60         },
61 };
62 
63 static uint32_t led_color[WS2812_NUM_LED];
64 static int led_idx;
65 
66 static void
load_pixel(void)67 load_pixel(void)
68 {
69     uint16_t *seq_values;
70     uint32_t grb;
71     int i;
72 
73     seq_values = pwm_seq_values[led_idx & 1];
74     grb = led_color[led_idx];
75 
76     for (i = 0; i < BITS_PER_SEQ; i++) {
77         *seq_values = grb & 0x800000 ? BIT1 : BIT0;
78         grb <<= 1;
79         seq_values++;
80     }
81 
82     led_idx++;
83 }
84 
85 static void
pwm_handler_func(nrfx_pwm_evt_type_t event_type)86 pwm_handler_func(nrfx_pwm_evt_type_t event_type)
87 {
88     switch (event_type) {
89     case NRFX_PWM_EVT_END_SEQ0:
90     case NRFX_PWM_EVT_END_SEQ1:
91         load_pixel();
92         break;
93     default:
94         break;
95     }
96 }
97 
98 int
ws2812_init(void)99 ws2812_init(void)
100 {
101     nrfx_err_t err;
102 
103     err = nrfx_pwm_init(&pwm, &pwm_config, pwm_handler_func);
104 
105     return err != NRFX_SUCCESS;
106 }
107 
108 int
ws2812_write(const uint32_t * rgb)109 ws2812_write(const uint32_t *rgb)
110 {
111     uint32_t grb;
112     int i;
113 
114     for (i = 0; i < WS2812_NUM_LED; i++) {
115         grb = 0;
116         grb |= (rgb[i] & 0x00FF00) << 8;
117         grb |= (rgb[i] & 0xFF0000) >> 8;
118         grb |= (rgb[i] & 0x0000FF);
119 
120         led_color[i] = grb;
121     }
122 
123     led_idx = 0;
124 
125     load_pixel();
126     load_pixel();
127     nrfx_pwm_complex_playback(&pwm, &pwm_seq[0], &pwm_seq[1], WS2812_NUM_LED,
128                               NRFX_PWM_FLAG_SIGNAL_END_SEQ0 |
129                               NRFX_PWM_FLAG_SIGNAL_END_SEQ1 |
130                               NRFX_PWM_FLAG_STOP);
131 
132     return 0;
133 }
134