-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAPA102lib.cpp
More file actions
171 lines (145 loc) · 4.3 KB
/
Copy pathAPA102lib.cpp
File metadata and controls
171 lines (145 loc) · 4.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include "SPI.h"
#include "APA102lib.h"
// Example to control APA102-based RGB LED Modules in a strand or strip
// Written by MatanLed
// Based on Adafruit - MIT license library to ws2801 RGB led
/*****************************************************************************/
// Constructor for use with hardware SPI (specific clock/data pins):
APA102::APA102(uint16_t n) {
alloc(n);
updatePins();
}
// Constructor for use with arbitrary clock/data pins:
APA102::APA102(uint16_t n, uint8_t dpin, uint8_t cpin) {
alloc(n);
updatePins(dpin, cpin);
}
// Allocate 3 bytes per pixel, init to RGB 'off' state:
void APA102::alloc(uint16_t n) {
begun = false;
numLEDs = n;
pixels = (uint8_t *)calloc(n, 3);
}
// Activate hard/soft SPI as appropriate:
void APA102::begin(void) {
if(hardwareSPI == true) {
startSPI();
} else {
pinMode(datapin, OUTPUT);
pinMode(clkpin , OUTPUT);
}
begun = true;
}
// Change pin assignments post-constructor, switching to hardware SPI:
void APA102::updatePins(void) {
hardwareSPI = true;
datapin = clkpin = 0;
// If begin() was previously invoked, init the SPI hardware now:
if(begun == true) startSPI();
// Otherwise, SPI is NOT initted until begin() is explicitly called.
// Note: any prior clock/data pin directions are left as-is and are
// NOT restored as inputs!
}
// Change pin assignments post-constructor, using arbitrary pins:
void APA102::updatePins(uint8_t dpin, uint8_t cpin) {
if(begun == true) { // If begin() was previously invoked...
// If previously using hardware SPI, turn that off:
if(hardwareSPI == true) SPI.end();
// Regardless, now enable output on 'soft' SPI pins:
pinMode(dpin, OUTPUT);
pinMode(cpin, OUTPUT);
} // Otherwise, pins are not set to outputs until begin() is called.
// Note: any prior clock/data pin directions are left as-is and are
// NOT restored as inputs!
hardwareSPI = false;
datapin = dpin;
clkpin = cpin;
clkport = portOutputRegister(digitalPinToPort(cpin));
clkpinmask = digitalPinToBitMask(cpin);
dataport = portOutputRegister(digitalPinToPort(dpin));
datapinmask = digitalPinToBitMask(dpin);
}
// Enable SPI hardware and set up protocol details:
void APA102::startSPI(void) {
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV16 );
// It's works for me just in 1Mhz and that what the data sheet I found
//recommended as max transfer speed
//I didn't need any resistors
}
uint16_t APA102::numPixels(void) {
return numLEDs;
}
void APA102::show(void) {
uint16_t i, nl3 = numLEDs;
uint8_t bit,t,c;
// Write 24 bits per pixel:
if(hardwareSPI)
{
for(t=0;t<4;t++) //first by sending 32 low bits
SPI.transfer(0x00);
for(i=0; i<nl3; i++)
{
SPI.transfer(0xFF);
SPI.transfer(pixels[3*i]); // blue
SPI.transfer(pixels[3*i+1]); // blue
SPI.transfer(pixels[3*i+2]); // blue
}
for(t=0;t<4;t++) //end by sending 32 high bits
SPI.transfer(0xFF);
}
else
{
*dataport &= ~datapinmask;
for(t=0;t<32;t++)
{
*clkport |= clkpinmask;
*clkport &= ~clkpinmask;
}
for(i=0; i<nl3; i++ )
{
*dataport |= datapinmask;
for(t=0;t<8;t++)
{
*clkport |= clkpinmask;
*clkport &= ~clkpinmask;
}
for(c=0;c<3;c++)
{
for(bit=0x80; bit; bit >>= 1)
{
if(pixels[i*3+c] & bit) *dataport |= datapinmask;
else *dataport &= ~datapinmask;
*clkport |= clkpinmask;
*clkport &= ~clkpinmask;
}
}
}
*dataport |= datapinmask;
for(t=0;t<32;t++)
{
*clkport |= clkpinmask;
*clkport &= ~clkpinmask;
}
}
}
// Set pixel color from separate 8-bit R, G, B components:
void APA102::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b) {
if(n < numLEDs) { // Arrays are 0-indexed, thus NOT '<='
uint8_t *p = &pixels[n * 3];
*p++ = b; //the order of sending data is Blue, Green, Red
*p++ = g;
*p++ = r;
}
}
// Set pixel color from 'packed' 32-bit RGB value:
void APA102::setPixelColor(uint16_t n, uint32_t c) {
if(n < numLEDs) { // Arrays are 0-indexed, thus NOT '<='
uint8_t *p = &pixels[n * 3];
*p++ = c >> 16; //the order of sending data is Blue, Green, Red.
*p++ = c >> 8; //That's mean it'll switch the red and blue in most common examples
*p++ = c;
}
}