blob: 2bea26609af068badce2d3302653e74b287cecde [file] [log] [blame]
misterdanba0a08b42016-03-28 01:58:14 +02001/*
2 * This file is part of the MicroPython project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2016 Robert Foss, Daniel Busch
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
Paul Sokolovsky0e4cae52016-08-01 00:03:55 +030027#include "py/mpconfig.h"
28#if MICROPY_ESP8266_APA102
29
misterdanba0a08b42016-03-28 01:58:14 +020030#include <stdio.h>
31#include "c_types.h"
32#include "eagle_soc.h"
33#include "user_interface.h"
34#include "espapa102.h"
35
Damien George69661f32020-02-27 15:36:53 +110036#define NOP asm volatile (" nop \n\t")
misterdanba0a08b42016-03-28 01:58:14 +020037
38static inline void _esp_apa102_send_byte(uint32_t clockPinMask, uint32_t dataPinMask, uint8_t byte) {
39 for (uint32_t i = 0; i < 8; i++) {
40 if (byte & 0x80) {
41 // set data pin high
42 GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, dataPinMask);
43 } else {
44 // set data pin low
45 GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, dataPinMask);
46 }
47
48 // set clock pin high
49 GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, clockPinMask);
50 byte <<= 1;
51 NOP;
52 NOP;
53
54 // set clock pin low
55 GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, clockPinMask);
56 NOP;
57 NOP;
58 }
59}
60
61static inline void _esp_apa102_send_colors(uint32_t clockPinMask, uint32_t dataPinMask, uint8_t *pixels, uint32_t numBytes) {
62 for (uint32_t i = 0; i < numBytes / 4; i++) {
63 _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4 + 3] | 0xE0);
64 _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4 + 2]);
65 _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4 + 1]);
66 _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4]);
67 }
68}
69
70static inline void _esp_apa102_start_frame(uint32_t clockPinMask, uint32_t dataPinMask) {
71 for (uint32_t i = 0; i < 4; i++) {
72 _esp_apa102_send_byte(clockPinMask, dataPinMask, 0x00);
73 }
74}
75
76static inline void _esp_apa102_append_additionial_cycles(uint32_t clockPinMask, uint32_t dataPinMask, uint32_t numBytes) {
77 GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, dataPinMask);
78
79 // we need to write some more clock cycles, because each led
80 // delays the data by one edge after inverting the clock
81 for (uint32_t i = 0; i < numBytes / 8 + ((numBytes / 4) % 2); i++) {
82 GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, clockPinMask);
83 NOP;
84 NOP;
85
86 GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, clockPinMask);
87 NOP;
88 NOP;
89 }
90}
91
92static inline void _esp_apa102_end_frame(uint32_t clockPinMask, uint32_t dataPinMask) {
93 for (uint32_t i = 0; i < 4; i++) {
94 _esp_apa102_send_byte(clockPinMask, dataPinMask, 0xFF);
95 }
96}
97
98void esp_apa102_write(uint8_t clockPin, uint8_t dataPin, uint8_t *pixels, uint32_t numBytes) {
99 uint32_t clockPinMask, dataPinMask;
100
101 clockPinMask = 1 << clockPin;
102 dataPinMask = 1 << dataPin;
103
104 // start the frame
105 _esp_apa102_start_frame(clockPinMask, dataPinMask);
106
107 // write pixels
108 _esp_apa102_send_colors(clockPinMask, dataPinMask, pixels, numBytes);
109
110 // end the frame
111 _esp_apa102_append_additionial_cycles(clockPinMask, dataPinMask, numBytes);
112 _esp_apa102_end_frame(clockPinMask, dataPinMask);
113}
Paul Sokolovsky0e4cae52016-08-01 00:03:55 +0300114
115#endif