blob: e5f3024b10715a1aaac565d07c7c5894bf818bb2 [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
27#include <stdio.h>
28#include "c_types.h"
29#include "eagle_soc.h"
30#include "user_interface.h"
31#include "espapa102.h"
32
33#define NOP asm volatile(" nop \n\t")
34
35static inline void _esp_apa102_send_byte(uint32_t clockPinMask, uint32_t dataPinMask, uint8_t byte) {
36 for (uint32_t i = 0; i < 8; i++) {
37 if (byte & 0x80) {
38 // set data pin high
39 GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, dataPinMask);
40 } else {
41 // set data pin low
42 GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, dataPinMask);
43 }
44
45 // set clock pin high
46 GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, clockPinMask);
47 byte <<= 1;
48 NOP;
49 NOP;
50
51 // set clock pin low
52 GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, clockPinMask);
53 NOP;
54 NOP;
55 }
56}
57
58static inline void _esp_apa102_send_colors(uint32_t clockPinMask, uint32_t dataPinMask, uint8_t *pixels, uint32_t numBytes) {
59 for (uint32_t i = 0; i < numBytes / 4; i++) {
60 _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4 + 3] | 0xE0);
61 _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4 + 2]);
62 _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4 + 1]);
63 _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4]);
64 }
65}
66
67static inline void _esp_apa102_start_frame(uint32_t clockPinMask, uint32_t dataPinMask) {
68 for (uint32_t i = 0; i < 4; i++) {
69 _esp_apa102_send_byte(clockPinMask, dataPinMask, 0x00);
70 }
71}
72
73static inline void _esp_apa102_append_additionial_cycles(uint32_t clockPinMask, uint32_t dataPinMask, uint32_t numBytes) {
74 GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, dataPinMask);
75
76 // we need to write some more clock cycles, because each led
77 // delays the data by one edge after inverting the clock
78 for (uint32_t i = 0; i < numBytes / 8 + ((numBytes / 4) % 2); i++) {
79 GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, clockPinMask);
80 NOP;
81 NOP;
82
83 GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, clockPinMask);
84 NOP;
85 NOP;
86 }
87}
88
89static inline void _esp_apa102_end_frame(uint32_t clockPinMask, uint32_t dataPinMask) {
90 for (uint32_t i = 0; i < 4; i++) {
91 _esp_apa102_send_byte(clockPinMask, dataPinMask, 0xFF);
92 }
93}
94
95void esp_apa102_write(uint8_t clockPin, uint8_t dataPin, uint8_t *pixels, uint32_t numBytes) {
96 uint32_t clockPinMask, dataPinMask;
97
98 clockPinMask = 1 << clockPin;
99 dataPinMask = 1 << dataPin;
100
101 // start the frame
102 _esp_apa102_start_frame(clockPinMask, dataPinMask);
103
104 // write pixels
105 _esp_apa102_send_colors(clockPinMask, dataPinMask, pixels, numBytes);
106
107 // end the frame
108 _esp_apa102_append_additionial_cycles(clockPinMask, dataPinMask, numBytes);
109 _esp_apa102_end_frame(clockPinMask, dataPinMask);
110}