-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 6143785
Showing
11 changed files
with
475 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2018 NeoCat | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
#include "P3RGB64x32MatrixPanel.h" | ||
|
||
volatile SemaphoreHandle_t P3RGB64x32MatrixPanel::timerSemaphore; | ||
P3RGB64x32MatrixPanel* P3RGB64x32MatrixPanel ::singleton; | ||
|
||
void IRAM_ATTR P3RGB64x32MatrixPanel::onTimer() { | ||
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; | ||
portENTER_CRITICAL_ISR(&timerMux); | ||
|
||
singleton->draw(); | ||
|
||
portEXIT_CRITICAL_ISR(&timerMux); | ||
xSemaphoreGiveFromISR(timerSemaphore, NULL); | ||
} | ||
|
||
void P3RGB64x32MatrixPanel::begin() { | ||
singleton = this; | ||
|
||
pinMode(pinR1, OUTPUT); | ||
pinMode(pinG1, OUTPUT); | ||
pinMode(pinB1, OUTPUT); | ||
pinMode(pinR2, OUTPUT); | ||
pinMode(pinG2, OUTPUT); | ||
pinMode(pinB2, OUTPUT); | ||
|
||
pinMode(pinLAT, OUTPUT); | ||
pinMode(pinCLK, OUTPUT); | ||
pinMode(pinOE, OUTPUT); | ||
|
||
pinMode(pinA, OUTPUT); | ||
pinMode(pinB, OUTPUT); | ||
pinMode(pinC, OUTPUT); | ||
pinMode(pinD, OUTPUT); | ||
|
||
digitalWrite(pinLAT, LOW); | ||
digitalWrite(pinCLK, LOW); | ||
digitalWrite(pinOE, HIGH); | ||
|
||
timerSemaphore = xSemaphoreCreateBinary(); | ||
hw_timer_t* timer = timerBegin(0, 80, true); | ||
timerAttachInterrupt(timer, &onTimer, true); | ||
timerAlarmWrite(timer, 30, true); | ||
timerAlarmEnable(timer); | ||
} | ||
|
||
uint16_t P3RGB64x32MatrixPanel::colorHSV(long hue, uint8_t sat, uint8_t val) { | ||
uint8_t r, g, b, lo; | ||
uint16_t s1, v1; | ||
|
||
// Hue ( 0 - 1535 ) | ||
hue %= 1536; | ||
if (hue < 0) hue += 1536; | ||
lo = hue & 255; // Low byte = primary/secondary color mix | ||
switch (hue >> 8) { // High byte = sextant of colorwheel | ||
case 0 : r = 255 ; g = lo ; b = 0 ; break; // R to Y | ||
case 1 : r = 255 - lo; g = 255 ; b = 0 ; break; // Y to G | ||
case 2 : r = 0 ; g = 255 ; b = lo ; break; // G to C | ||
case 3 : r = 0 ; g = 255 - lo; b = 255 ; break; // C to B | ||
case 4 : r = lo ; g = 0 ; b = 255 ; break; // B to M | ||
default: r = 255 ; g = 0 ; b = 255 - lo; break; // M to R | ||
} | ||
|
||
s1 = sat + 1; | ||
r = 255 - (((255 - r) * s1) >> 8); | ||
g = 255 - (((255 - g) * s1) >> 8); | ||
b = 255 - (((255 - b) * s1) >> 8); | ||
|
||
v1 = val + 1; | ||
r = (r * v1) >> 11; | ||
g = (g * v1) >> 11; | ||
b = (b * v1) >> 11; | ||
|
||
return color555(r, g, b); | ||
} | ||
|
||
void P3RGB64x32MatrixPanel::drawPixel(int16_t x, int16_t y, uint16_t color) { | ||
int16_t idx = x + y * 64; | ||
if (idx >= 32 * 64) return; | ||
matrixbuff[idx] = color; | ||
} | ||
|
||
void P3RGB64x32MatrixPanel::draw() { | ||
static byte cnt = 31; | ||
static byte y = 15; | ||
static uint32_t out = 0; | ||
y = (y + 1) % 16; | ||
|
||
if (y == 0) | ||
cnt = (cnt + 1) % 32; | ||
|
||
byte cmp = (cnt >> 4) | ((cnt >> 2) & 0x2) | (cnt & 0x4) | ((cnt << 2) & 0x8) | ((cnt << 4) & 0x10); | ||
|
||
for (int x = 0; x < 64; x++) { | ||
bool r1, b1, g1, r2, g2, b2; | ||
uint16_t c = matrixbuff[x + y * 64]; | ||
r1 = (c & 0x1f) > cmp; | ||
g1 = ((c >> 5) & 0x1f) > cmp; | ||
b1 = ((c >> 10) & 0x1f) > cmp; | ||
c = matrixbuff[x + (y + 16) * 64]; | ||
r2 = (c & 0x1f) > cmp; | ||
g2 = ((c >> 5) & 0x1f) > cmp; | ||
b2 = ((c >> 10) & 0x1f) > cmp; | ||
|
||
REG_WRITE(GPIO_OUT_REG, out | | ||
((uint32_t)r1 << pinR1) | | ||
((uint32_t)g1 << pinG1) | | ||
((uint32_t)b1 << pinB1) | | ||
((uint32_t)r2 << pinR2) | | ||
((uint32_t)g2 << pinG2) | | ||
((uint32_t)b2 << pinB2)); | ||
|
||
REG_WRITE(GPIO_OUT_W1TS_REG, (1 << pinCLK)); | ||
} | ||
//REG_WRITE(GPIO_OUT_W1TC_REG, (1 << pinCLK)); | ||
|
||
REG_WRITE(GPIO_OUT1_W1TS_REG, (1 << pinOE - 32) | (1 << pinLAT - 32)); | ||
|
||
out = ((y & 1) << pinA) | ((y & 2) << (pinB - 1)) | | ||
((y & 4) << (pinC - 2)) | ((y & 8) << (pinD - 3)); | ||
REG_WRITE(GPIO_OUT_REG, out); | ||
|
||
for (int x = 0; x < 8; x++) NOP(); // to wait latch and row switch | ||
|
||
REG_WRITE(GPIO_OUT1_W1TC_REG, (1 << pinOE - 32) | (1 << pinLAT - 32)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#include "Adafruit_GFX.h" | ||
|
||
class P3RGB64x32MatrixPanel : public Adafruit_GFX { | ||
public: | ||
P3RGB64x32MatrixPanel() : Adafruit_GFX(64, 32), matrixbuff({}) {} | ||
void begin(void); | ||
virtual void drawPixel(int16_t x, int16_t y, uint16_t color); | ||
|
||
uint16_t color444(uint8_t r, uint8_t g, uint8_t b) { return ((r & 0xf) << 1) | ((uint16_t)(g & 0xf) << 6) | ((uint16_t)(b & 0xf) << 11); } | ||
uint16_t color555(uint8_t r, uint8_t g, uint8_t b) { return (r&0x1f) | ((uint16_t)(g & 0x1f) << 5) | ((uint16_t)(b & 0x1f) << 10); } | ||
uint16_t colorHSV(long hue, uint8_t sat, uint8_t val); | ||
|
||
uint16_t matrixbuff[64*32]; | ||
|
||
private: | ||
|
||
static void IRAM_ATTR onTimer(void); | ||
void draw(); | ||
|
||
const int pinR1 = 25; | ||
const int pinG1 = 26; | ||
const int pinB1 = 27; | ||
const int pinR2 = 21; | ||
const int pinG2 = 22; | ||
const int pinB2 = 23; | ||
|
||
const int pinCLK = 15; | ||
const int pinLAT = 32; | ||
const int pinOE = 33; | ||
|
||
const int pinA = 12; | ||
const int pinB = 16; | ||
const int pinC = 17; | ||
const int pinD = 18; | ||
|
||
static volatile SemaphoreHandle_t timerSemaphore; | ||
static P3RGB64x32MatrixPanel *singleton; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# P3RGB64x32MatrixPanel library for ESP32 | ||
|
||
ESP32 Arduino library for P3 64x32 RGB LED Matrix Panel (available at https://amzn.to/2jlqX1q ). | ||
|
||
This software is released under the MIT License, see LICENSE.txt. | ||
|
||
# Installation | ||
|
||
To download, click the "Download ZIP" button, and specify the zip file | ||
from the "Sketch > Include Library > Add .ZIP Library" menu in the Arduino IDE. | ||
|
||
You also need to install "Adafruit_GFX_Library" from the "Library > Manage Libraries" menu. | ||
|
||
## Patching GPIO to avoid eratta of ESP32 | ||
|
||
You should patch the `tools/sdk/ld/esp32.peripherals.ld` to avoid random pixel noise on the display as following: | ||
|
||
``` | ||
/* PROVIDE ( GPIO = 0x3ff44000 ); */ | ||
PROVIDE ( GPIO = 0x60004000 ); | ||
``` | ||
|
||
Please refer section 3.3. in https://www.espressif.com/sites/default/files/documentation/eco_and_workarounds_for_bugs_in_esp32_en.pdf for more details. | ||
|
||
# Connection to ESP32 and the LED Matrix Panel | ||
|
||
The panel has HUB75 compatible pins. | ||
|
||
``` | ||
+---------+ Panel - ESP32 pins | ||
| R1 G1 | R1 - IO25 G1 - IO26 | ||
| B1 GND | B1 - IO27 | ||
| R2 G2 | R2 - IO21 R2 - IO22 | ||
| B2 GND | B2 - IO23 | ||
| A B | A - IO12 B - IO16 | ||
| C D | C - IO17 D - IO18 | ||
| CLK LAT | CLK - IO15 LAT - IO32 | ||
| OE GND | OE - IO33 | ||
+---------+ | ||
``` | ||
|
||
The panel must be powered by 5V AC adapter with enough current capacity. | ||
(Current varies due to how many LED are turned on at the same time. | ||
To drive all the LED, you need 5V4A adapter.) | ||
|
||
# Usage | ||
|
||
Please check the examples directory for sample programs. | ||
|
||
Note that this library heavily use the timer interrupt to drive LED matrix to enable software based 5bit PWM for each line. | ||
This may conflict with WiFi setup, so you should start WiFi before `matrix.begin()` which sets up timer interrupts. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#include <WiFi.h> | ||
|
||
#include <Adafruit_GFX.h> | ||
#include <Fonts/Picopixel.h> | ||
#include <P3RGB64x32MatrixPanel.h> | ||
|
||
P3RGB64x32MatrixPanel matrix; | ||
|
||
char ssid[] = "****SSID****"; | ||
char pass[] = "**PASSWORD**"; | ||
WiFiServer server(20032); | ||
|
||
void setup() { | ||
Serial.begin(115200); | ||
|
||
Serial.print("Attempting to connect to Network named: "); | ||
Serial.println(ssid); // print the network name (SSID); | ||
|
||
WiFi.begin(ssid, pass); | ||
while (WiFi.status() != WL_CONNECTED) { | ||
Serial.print("."); | ||
delay(1000); | ||
} | ||
Serial.println(""); | ||
IPAddress ip = WiFi.localIP(); | ||
Serial.print("IP Address: "); | ||
Serial.println(ip); | ||
|
||
server.begin(); // start the server | ||
|
||
matrix.begin(); // setup the LED matrix | ||
|
||
matrix.setTextColor(matrix.color444(0, 0, 8)); // print IP address | ||
matrix.println("IP address"); | ||
matrix.setTextColor(matrix.color444(12, 12, 12)); | ||
matrix.setFont(&Picopixel); | ||
matrix.println(ip); | ||
} | ||
|
||
void loop() | ||
{ | ||
WiFiClient client = server.available(); // listen for incoming clients | ||
|
||
if (client) { | ||
Serial.println("new client"); | ||
unsigned int idx = 0; | ||
while (client.connected()) { | ||
if (client.available()) { | ||
int len = client.read((byte*)matrix.matrixbuff + idx , 64*32*2 - idx); | ||
idx = (idx + len) & (64 * 32 * 2 - 1); | ||
} | ||
} | ||
// close the connection: | ||
client.stop(); | ||
Serial.println("client disonnected"); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
source 'https://rubygems.org' | ||
gem 'mini_magick' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
GEM | ||
remote: https://rubygems.org/ | ||
specs: | ||
mini_magick (4.8.0) | ||
|
||
PLATFORMS | ||
ruby | ||
|
||
DEPENDENCIES | ||
mini_magick | ||
|
||
BUNDLED WITH | ||
1.16.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Setup | ||
|
||
``` | ||
bundle install | ||
``` | ||
|
||
Start up ESP32 with "ImageFromWiFi" | ||
|
||
# Usage | ||
|
||
``` | ||
bundle exec ./send.rb 192.168.x.x image.png | ||
bundle exec ./send.rb 192.168.x.x image.jpg | ||
``` | ||
|
||
The image height must be larger than its width * 2. | ||
|
||
The image will be resized to 64 pixels width and scrolled vertically. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#!/usr/bin/env ruby | ||
require 'mini_magick' | ||
require 'socket' | ||
|
||
if ARGV.size != 2 | ||
STDERR.puts "usage: #{$PROGRAM_NAME} ip_address_of_ESP32 image_file_path" | ||
exit 1 | ||
end | ||
|
||
image = MiniMagick::Image.open ARGV[1] | ||
new_height = image.height * 64 / image.width | ||
image.resize "64x#{new_height}!" | ||
puts "#{image.width}x#{image.height}" | ||
image.contrast | ||
image.gamma 0.3 | ||
pixels = image.get_pixels | ||
|
||
sock = TCPSocket.open(ARGV[0], 20032) | ||
|
||
(new_height - 31).times do |y0| | ||
pix = [] | ||
32.times do |y| | ||
64.times do |x| | ||
r, g, b = pixels[y + y0][x].map { |v| v >> 3 } | ||
c = r | (g << 5) | (b << 10) | ||
pix << c | ||
end | ||
end | ||
data = pix.pack('v*') | ||
sock.write data | ||
sleep 0.1 | ||
sleep 0.5 if y0 == 0 | ||
end |
Oops, something went wrong.