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