Skip to content

Instantly share code, notes, and snippets.

@autoiue
Last active December 29, 2019 14:31
Show Gist options
  • Save autoiue/39e1f7a1ab9327098aab345e4391aa7a to your computer and use it in GitHub Desktop.
Save autoiue/39e1f7a1ab9327098aab345e4391aa7a to your computer and use it in GitHub Desktop.
Using pyserial with Arduino without hangs or freezes

Using pyserial with Arduino without hangs or freezes

By default pyserial doesn't play nice with Arduino. The Arduino may reset at the start of the communication or hangs after few minutes.
This application demonstrate 2MBits/sec serial communication with an Arduino UNO (ATMega328) to drive 56 APA102 LEDs. This code can achieve a refresh rate of ~100Hz and can run forever with no hangs or freezes.

Installing pyserial

pip install pyserial

#include <FastGPIO.h>
#define APA102_USE_FAST_GPIO
#include <APA102.h>
#define PIN_DATA 11
#define PIN_CLOCK 12
#define NUM_LEDS 56
#define NUM_BYTES NUM_LEDS * 3
const uint8_t PROGMEM gamma8[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
APA102<PIN_DATA, PIN_CLOCK> Strip;
char buffer[512];
rgb_color leds[NUM_LEDS];
void setup(){
Serial.begin(2000000);
leds[0] = rgb_color(0, 255, 30);
Strip.write(leds, NUM_LEDS);
}
void loop(){
if (Serial.available()) {
char read = Serial.readBytes(buffer, NUM_BYTES);
while(Serial.available() > 0) {
char t = Serial.read();
}
Serial.println(read);
for (int i = 0; i < NUM_LEDS; ++i){
leds[i] = rgb_color(
(uint8_t) pgm_read_byte(&gamma8[(uint8_t) buffer[3*i]]),
(uint8_t) pgm_read_byte(&gamma8[(uint8_t) buffer[3*i+1]]),
(uint8_t) pgm_read_byte(&gamma8[(uint8_t) buffer[3*i+2]]));
}
Strip.write(leds, NUM_LEDS);
}
}
from time import sleep
import serial
from threading import Thread
from queue import Queue
class Driver:
def __init__(self, port_name="/dev/ttyACM0", baudrate=2000000, led_count=56):
self.frame_q = Queue(maxsize=0)
self.port_name = port_name
self.led_count = led_count
self.baudrate = baudrate
self.running = True
Thread(target=self.handle_serial).start()
sleep(1)
def close(self):
self.running = False
def __len__(self):
return self.led_count
def handle_serial(self):
port = serial.Serial()
port.port = self.port_name
port.baudrate = self.baudrate
port.bytesize = serial.EIGHTBITS
port.parity = serial.PARITY_NONE
port.stopbits = serial.STOPBITS_ONE
port.xonxoff = False
port.rtscts = False
port.dtr = False
port.timeout = 1
port.write_timeout = 1
port.open()
while self.running:
if not self.frame_q.empty():
port.write(self.frame_q.get())
port.flush()
port.reset_input_buffer()
port.reset_output_buffer()
pass
port.close()
def to_bytes(self, leds):
ba = bytearray([])
for l in leds:
ba = ba + bytearray(l)
return ba
def set_leds(self, l):
self.frame_q.put(self.to_bytes(l))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment