Unneeded code
This commit is contained in:
1
setup.py
1
setup.py
@@ -19,7 +19,6 @@ setup(
|
||||
packages=[
|
||||
'bbctrl',
|
||||
'inevent',
|
||||
'lcd',
|
||||
'camotics',
|
||||
'iw_parse'
|
||||
],
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "lcd.h"
|
||||
#include "rtc.h"
|
||||
#include "hardware.h"
|
||||
#include "command.h"
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
void lcd_init(uint8_t addr) {
|
||||
// Enable I2C master
|
||||
TWIC.MASTER.BAUD = F_CPU / 2 / 100000 - 5; // 100 KHz
|
||||
TWIC.MASTER.CTRLA = TWI_MASTER_ENABLE_bm;
|
||||
TWIC.MASTER.CTRLB = TWI_MASTER_TIMEOUT_DISABLED_gc;
|
||||
TWIC.MASTER.STATUS = TWI_MASTER_BUSSTATE_IDLE_gc;
|
||||
|
||||
_delay_ms(50);
|
||||
lcd_nibble(addr, 3 << 4); // Home
|
||||
_delay_ms(50);
|
||||
lcd_nibble(addr, 3 << 4); // Home
|
||||
_delay_ms(50);
|
||||
lcd_nibble(addr, 3 << 4); // Home
|
||||
lcd_nibble(addr, 2 << 4); // 4-bit
|
||||
|
||||
lcd_write(addr,
|
||||
LCD_FUNCTION_SET | LCD_2_LINE | LCD_5x8_DOTS | LCD_4_BIT_MODE, 0);
|
||||
lcd_write(addr, LCD_DISPLAY_CONTROL | LCD_DISPLAY_ON, 0);
|
||||
lcd_write(addr, LCD_ENTRY_MODE_SET | LCD_ENTRY_SHIFT_INC, 0);
|
||||
|
||||
lcd_write(addr, LCD_CLEAR_DISPLAY, 0);
|
||||
lcd_write(addr, LCD_RETURN_HOME, 0);
|
||||
}
|
||||
|
||||
|
||||
static void _master_wait() {
|
||||
#ifdef __AVR__
|
||||
while (!(TWIC.MASTER.STATUS & TWI_MASTER_WIF_bm)) continue;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void _write_i2c(uint8_t addr, uint8_t data) {
|
||||
data |= BACKLIGHT_BIT;
|
||||
|
||||
TWIC.MASTER.ADDR = addr << 1;
|
||||
_master_wait();
|
||||
|
||||
TWIC.MASTER.DATA = data;
|
||||
_master_wait();
|
||||
|
||||
TWIC.MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc;
|
||||
|
||||
_delay_us(100);
|
||||
}
|
||||
|
||||
|
||||
void lcd_nibble(uint8_t addr, uint8_t data) {
|
||||
_write_i2c(addr, data);
|
||||
_write_i2c(addr, data | ENABLE_BIT);
|
||||
_delay_us(500);
|
||||
_write_i2c(addr, data & ~ENABLE_BIT);
|
||||
_delay_us(100);
|
||||
}
|
||||
|
||||
|
||||
void lcd_write(uint8_t addr, uint8_t cmd, uint8_t flags) {
|
||||
lcd_nibble(addr, flags | (cmd & 0xf0));
|
||||
lcd_nibble(addr, flags | ((cmd << 4) & 0xf0));
|
||||
}
|
||||
|
||||
|
||||
void lcd_goto(uint8_t addr, uint8_t x, uint8_t y) {
|
||||
static uint8_t row[] = {0, 64, 20, 84};
|
||||
lcd_write(addr, LCD_SET_DDRAM_ADDR | (row[y] + x), 0);
|
||||
}
|
||||
|
||||
|
||||
void lcd_putchar(uint8_t addr, uint8_t c) {
|
||||
lcd_write(addr, c, REG_SELECT_BIT);
|
||||
}
|
||||
|
||||
|
||||
void lcd_pgmstr(uint8_t addr, const char *s) {
|
||||
while (true) {
|
||||
char c = pgm_read_byte(s++);
|
||||
if (!c) break;
|
||||
lcd_putchar(addr, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _splash(uint8_t addr) {
|
||||
lcd_init(addr);
|
||||
lcd_goto(addr, 1, 1);
|
||||
lcd_pgmstr(addr, PSTR("Controller booting"));
|
||||
lcd_goto(addr, 3, 2);
|
||||
lcd_pgmstr(addr, PSTR("Please wait..."));
|
||||
}
|
||||
|
||||
|
||||
void lcd_splash() {
|
||||
wdt_disable();
|
||||
_splash(0x27);
|
||||
_splash(0x3f);
|
||||
wdt_enable(WDTO_250MS);
|
||||
}
|
||||
|
||||
|
||||
void lcd_rtc_callback() {
|
||||
// Display the splash if we haven't gotten any commands in 1sec since boot
|
||||
if (!command_is_active() && rtc_get_time() == 1000)
|
||||
lcd_splash();
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pgmspace.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// Control flags
|
||||
enum {
|
||||
REG_SELECT_BIT = 1 << 0,
|
||||
READ_BIT = 1 << 1,
|
||||
ENABLE_BIT = 1 << 2,
|
||||
BACKLIGHT_BIT = 1 << 3,
|
||||
};
|
||||
|
||||
|
||||
// Commands
|
||||
enum {
|
||||
LCD_CLEAR_DISPLAY = 1 << 0,
|
||||
LCD_RETURN_HOME = 1 << 1,
|
||||
LCD_ENTRY_MODE_SET = 1 << 2,
|
||||
LCD_DISPLAY_CONTROL = 1 << 3,
|
||||
LCD_CURSOR_SHIFT = 1 << 4,
|
||||
LCD_FUNCTION_SET = 1 << 5,
|
||||
LCD_SET_CGRAM_ADDR = 1 << 6,
|
||||
LCD_SET_DDRAM_ADDR = 1 << 7,
|
||||
};
|
||||
|
||||
|
||||
// Entry Mode Set flags
|
||||
#define LCD_ENTRY_SHIFT_DISPLAY (1 << 0)
|
||||
#define LCD_ENTRY_SHIFT_INC (1 << 1)
|
||||
#define LCD_ENTRY_SHIFT_DEC (0 << 1)
|
||||
|
||||
|
||||
// Display Control flags
|
||||
#define LCD_BLINK_ON (1 << 0)
|
||||
#define LCD_BLINK_OFF (0 << 0)
|
||||
#define LCD_CURSOR_ON (1 << 1)
|
||||
#define LCD_CURSOR_OFF (0 << 1)
|
||||
#define LCD_DISPLAY_ON (1 << 2)
|
||||
#define LCD_DISPLAY_OFF (0 << 2)
|
||||
|
||||
|
||||
// Cursor Shift flags
|
||||
#define LCD_SHIFT_RIGHT (1 << 2)
|
||||
#define LCD_SHIFT_LEFT (0 << 2)
|
||||
#define LCD_SHIFT_DISPLAY (1 << 3)
|
||||
#define LCD_SHIFT_CURSOR (0 << 3)
|
||||
|
||||
|
||||
// Function Set flags
|
||||
#define LCD_5x11_DOTS (1 << 2)
|
||||
#define LCD_5x8_DOTS (0 << 2)
|
||||
#define LCD_2_LINE (1 << 3)
|
||||
#define LCD_1_LINE (0 << 3)
|
||||
#define LCD_8_BIT_MODE (1 << 4)
|
||||
#define LCD_4_BIT_MODE (0 << 4)
|
||||
|
||||
|
||||
// Text justification flags
|
||||
enum {
|
||||
JUSTIFY_LEFT = 0,
|
||||
JUSTIFY_RIGHT = 1,
|
||||
JUSTIFY_CENTER = 2,
|
||||
};
|
||||
|
||||
|
||||
void lcd_init(uint8_t addr);
|
||||
void lcd_nibble(uint8_t addr, uint8_t data);
|
||||
void lcd_write(uint8_t addr, uint8_t cmd, uint8_t flags);
|
||||
void lcd_goto(uint8_t addr, uint8_t x, uint8_t y);
|
||||
void lcd_putchar(uint8_t addr, uint8_t c);
|
||||
void lcd_pgmstr(uint8_t addr, const char *s);
|
||||
void lcd_splash();
|
||||
void lcd_rtc_callback();
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "switch.h"
|
||||
#include "analog.h"
|
||||
#include "motor.h"
|
||||
#include "lcd.h"
|
||||
#include "vfd_spindle.h"
|
||||
|
||||
#include <avr/io.h>
|
||||
@@ -46,7 +45,6 @@ static uint32_t ticks;
|
||||
ISR(RTC_OVF_vect) {
|
||||
ticks++;
|
||||
|
||||
lcd_rtc_callback();
|
||||
switch_rtc_callback();
|
||||
analog_rtc_callback();
|
||||
vfd_spindle_rtc_callback();
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# Makefile for Bulidbotics step-test
|
||||
PROJECT = step-test
|
||||
MCU = atxmega192a3u
|
||||
CLOCK = 32000000
|
||||
|
||||
# SRC
|
||||
SRC = usart.c lcd.c pins.c hardware.c
|
||||
SRC := $(wildcard *.c) $(patsubst %,../src/%,$(SRC))
|
||||
|
||||
include ../Makefile.common
|
||||
|
||||
CFLAGS += -I../src -I.
|
||||
|
||||
# Build
|
||||
all: $(PROJECT).hex size
|
||||
|
||||
$(PROJECT).elf: $(SRC)
|
||||
$(CC) $(SRC) $(CFLAGS) $(LDFLAGS) $(LIBS) -o $@
|
||||
|
||||
.PHONY: all
|
||||
@@ -1,187 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of the Buildbotics firmware. #
|
||||
# #
|
||||
# Copyright (c) 2015 - 2018, Buildbotics LLC #
|
||||
# All rights reserved. #
|
||||
# #
|
||||
# This file ("the software") is free software: you can redistribute it #
|
||||
# and/or modify it under the terms of the GNU General Public License, #
|
||||
# version 2 as published by the Free Software Foundation. You should #
|
||||
# have received a copy of the GNU General Public License, version 2 #
|
||||
# along with the software. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# The software is distributed in the hope that it will be useful, but #
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #
|
||||
# Lesser General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU Lesser General Public #
|
||||
# License along with the software. If not, see #
|
||||
# <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# For information regarding this software email: #
|
||||
# "Joseph Coffland" <joseph@buildbotics.com> #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
import sys, serial, argparse
|
||||
import numpy as np
|
||||
import math
|
||||
import json
|
||||
from time import sleep
|
||||
from collections import deque
|
||||
from datetime import datetime
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.animation as animation
|
||||
|
||||
|
||||
MM_PER_STEP = 5 * 1.8 / 360 / 32
|
||||
SAMPLES_PER_MIN = 6000
|
||||
|
||||
|
||||
class Plot:
|
||||
def __init__(self, port, baud, max_len):
|
||||
# Open serial port
|
||||
self.sp = serial.Serial(port, baud)
|
||||
|
||||
# Create data series
|
||||
self.series = []
|
||||
for i in range(5):
|
||||
self.series.append(deque([0.0] * max_len))
|
||||
|
||||
# Init vars
|
||||
self.max_len = max_len
|
||||
self.incoming = ''
|
||||
self.last = [None] * 4
|
||||
|
||||
# Open velocity log
|
||||
ts = datetime.now().strftime('%Y-%m-%d-%H:%M:%S')
|
||||
self.log = open('velocity-%s.log' % ts, 'w')
|
||||
|
||||
|
||||
# Add new series data
|
||||
def add(self, i, value):
|
||||
self.series[i].pop()
|
||||
self.series[i].appendleft(value)
|
||||
|
||||
|
||||
def update_text(self, text, vel, data):
|
||||
text[4].set_text('V {0:8,.2f}'.format(vel))
|
||||
|
||||
for i in range(4):
|
||||
text[i].set_text('{} {:11,}'.format('XYZA'[i], int(data[i])))
|
||||
|
||||
|
||||
def update(self, frame, axes, text):
|
||||
# Read new data
|
||||
try:
|
||||
data = self.sp.read(self.sp.in_waiting)
|
||||
self.incoming += data.decode('utf-8')
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return
|
||||
|
||||
while True:
|
||||
# Parse lines
|
||||
i = self.incoming.find('\n')
|
||||
if i == -1: break
|
||||
line = self.incoming[0:i]
|
||||
self.incoming = self.incoming[i + 1:]
|
||||
|
||||
# Handle reset
|
||||
if line.find('RESET') != -1:
|
||||
self.update_text(text, 0, [0] * 4)
|
||||
self.log.write(line + '\n')
|
||||
self.last = [None] * 4
|
||||
continue
|
||||
|
||||
# Parse data
|
||||
try:
|
||||
data = [float(value) for value in line.split(',')]
|
||||
except ValueError: continue
|
||||
|
||||
if len(data) != 4: continue
|
||||
|
||||
# Compute axis velocities
|
||||
v = [] # Axis velocity
|
||||
totalV = 0 # Tool velocity
|
||||
|
||||
for i in range(4):
|
||||
if self.last[i] is not None:
|
||||
delta = self.last[i] - data[i]
|
||||
v.append(delta * MM_PER_STEP * SAMPLES_PER_MIN) # mm/min
|
||||
totalV += math.pow(v[i], 2)
|
||||
|
||||
self.last[i] = data[i]
|
||||
|
||||
# Compute tool velocity
|
||||
totalV = math.sqrt(totalV)
|
||||
|
||||
# Update position and velocity text
|
||||
self.update_text(text, totalV, data)
|
||||
|
||||
# Don't update plots when not moving
|
||||
if totalV == 0: continue
|
||||
|
||||
# Add new data
|
||||
for i in range(4): self.add(i, v[i])
|
||||
self.add(4, totalV)
|
||||
|
||||
# Update plots
|
||||
for i in range(5):
|
||||
axes[i].set_data(range(self.max_len), self.series[i])
|
||||
|
||||
self.log.write(line + '\n')
|
||||
|
||||
|
||||
def close(self):
|
||||
self.sp.flush()
|
||||
self.sp.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Parse command line arguments
|
||||
description = "Plot velocity data in real-time"
|
||||
parser = argparse.ArgumentParser(description = description)
|
||||
parser.add_argument('-p', '--port', default = '/dev/ttyUSB0')
|
||||
parser.add_argument('-b', '--baud', default = 115200, type = int)
|
||||
parser.add_argument('-m', '--max-width', default = 2000, type = int)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Create plot
|
||||
plot = Plot(args.port, args.baud, args.max_width)
|
||||
fig = plt.figure()
|
||||
ax = plt.axes(xlim = (0, args.max_width), ylim = (-10000, 10000))
|
||||
axes = []
|
||||
axes_text = []
|
||||
|
||||
# Setup position and velocity text fields
|
||||
font = dict(fontsize = 14, family = 'monospace')
|
||||
|
||||
axes_text.append(plt.text(0, 11700, '', **font))
|
||||
axes_text.append(plt.text(800, 11700, '', **font))
|
||||
axes_text.append(plt.text(0, 10500, '', **font))
|
||||
axes_text.append(plt.text(800, 10500, '', **font))
|
||||
axes_text.append(plt.text(1500, 11700, '', **font))
|
||||
|
||||
# Create axes
|
||||
for i in range(5):
|
||||
axes.append(ax.plot([], [])[0])
|
||||
# Set text color to match axis color
|
||||
axes_text[i].set_color(axes[i].get_color())
|
||||
|
||||
# Initial text views
|
||||
plot.update_text(axes_text, 0, [0] * 4)
|
||||
|
||||
# Set up animation
|
||||
anim = animation.FuncAnimation(fig, plot.update, fargs = [axes, axes_text],
|
||||
interval = 100)
|
||||
|
||||
# Run
|
||||
plt.show()
|
||||
plot.close()
|
||||
@@ -1,230 +0,0 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include "hardware.h"
|
||||
#include "usart.h"
|
||||
#include "lcd.h"
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#define RESET_PIN SPI_MOSI_PIN
|
||||
|
||||
|
||||
void rtc_init() {}
|
||||
|
||||
|
||||
static struct {
|
||||
uint8_t step_pin;
|
||||
uint8_t dir_pin;
|
||||
TC0_t *timer;
|
||||
volatile int16_t high;
|
||||
volatile bool reading;
|
||||
|
||||
} channel[4] = {
|
||||
{STEP_X_PIN, DIR_X_PIN, &TCC0, 0},
|
||||
{STEP_Y_PIN, DIR_Y_PIN, &TCD0, 0},
|
||||
{STEP_Z_PIN, DIR_Z_PIN, &TCE0, 0},
|
||||
{STEP_A_PIN, DIR_A_PIN, &TCF0, 0},
|
||||
};
|
||||
|
||||
|
||||
static int reset = 0;
|
||||
|
||||
|
||||
void channel_reset(int i) {channel[i].timer->CNT = channel[i].high = 0;}
|
||||
|
||||
|
||||
#define EVSYS_CHMUX(CH) (&EVSYS_CH0MUX)[CH]
|
||||
#define EVSYS_CHCTRL(CH) (&EVSYS_CH0CTRL)[CH]
|
||||
|
||||
|
||||
void channel_overflow(int i) {
|
||||
if (IN_PIN(channel[i].dir_pin)) channel[i].high--;
|
||||
else channel[i].high++;
|
||||
channel[i].reading = false;
|
||||
}
|
||||
|
||||
|
||||
ISR(TCC0_OVF_vect) {channel_overflow(0);}
|
||||
ISR(TCD0_OVF_vect) {channel_overflow(1);}
|
||||
ISR(TCE0_OVF_vect) {channel_overflow(2);}
|
||||
ISR(TCF0_OVF_vect) {channel_overflow(3);}
|
||||
|
||||
|
||||
void channel_update_dir(int i) {
|
||||
if (IN_PIN(channel[i].dir_pin)) channel[i].timer->CTRLFSET = TC0_DIR_bm;
|
||||
else channel[i].timer->CTRLFCLR = TC0_DIR_bm;
|
||||
}
|
||||
|
||||
|
||||
ISR(PORTE_INT0_vect) {for (int i = 0; i < 4; i++) channel_update_dir(i);}
|
||||
|
||||
|
||||
int32_t __attribute__ ((noinline)) _channel_read(int i) {
|
||||
return (int32_t)channel[i].high << 16 | channel[i].timer->CNT;
|
||||
}
|
||||
|
||||
|
||||
int32_t channel_read(int i) {
|
||||
while (true) {
|
||||
channel[i].reading = true;
|
||||
|
||||
int32_t x = _channel_read(i);
|
||||
int32_t y = _channel_read(i);
|
||||
|
||||
if (x != y || !channel[i].reading) continue;
|
||||
|
||||
channel[i].reading = false;
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void channel_update_enable(int i) {
|
||||
if (IN_PIN(MOTOR_ENABLE_PIN))
|
||||
channel[i].timer->CTRLA = TC_CLKSEL_EVCH0_gc + i;
|
||||
else channel[i].timer->CTRLA = 0;
|
||||
}
|
||||
|
||||
|
||||
ISR(PORTF_INT0_vect) {
|
||||
for (int i = 0; i < 4; i++) channel_update_enable(i);
|
||||
if (!IN_PIN(MOTOR_ENABLE_PIN)) reset = 2;
|
||||
}
|
||||
|
||||
|
||||
ISR(PORTC_INT0_vect) {reset = 32;}
|
||||
|
||||
|
||||
ISR(TCC1_OVF_vect) {
|
||||
if (reset) reset--;
|
||||
|
||||
// Report measured steps
|
||||
static int32_t counts[4] = {0, 0, 0, 0};
|
||||
bool moving = false;
|
||||
bool zero = true;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int32_t count = channel_read(i);
|
||||
if (count != counts[i]) moving = true;
|
||||
if (count) zero = false;
|
||||
counts[i] = count;
|
||||
}
|
||||
|
||||
if (reset && !zero) {
|
||||
for (int i = 0; i < 4; i++) channel_reset(i);
|
||||
printf("RESET\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (moving)
|
||||
printf("%ld,%ld,%ld,%ld\n", counts[0], counts[1], counts[2], counts[3]);
|
||||
}
|
||||
|
||||
|
||||
static void _splash(uint8_t addr) {
|
||||
lcd_init(addr);
|
||||
lcd_goto(addr, 5, 1);
|
||||
lcd_pgmstr(addr, PSTR("Step Test"));
|
||||
}
|
||||
|
||||
|
||||
void channel_init(int i) {
|
||||
uint8_t step_pin = channel[i].step_pin;
|
||||
uint8_t dir_pin = channel[i].dir_pin;
|
||||
|
||||
// Configure I/O
|
||||
DIRCLR_PIN(step_pin);
|
||||
DIRCLR_PIN(dir_pin);
|
||||
PINCTRL_PIN(step_pin) = PORT_SRLEN_bm | PORT_ISC_RISING_gc;
|
||||
PINCTRL_PIN(dir_pin) = PORT_SRLEN_bm | PORT_ISC_BOTHEDGES_gc;
|
||||
|
||||
// Dir change interrupt
|
||||
PIN_PORT(dir_pin)->INTCTRL |= PORT_INT0LVL_HI_gc;
|
||||
PIN_PORT(dir_pin)->INT0MASK |= PIN_BM(dir_pin);
|
||||
|
||||
// Events
|
||||
EVSYS_CHMUX(i) = PIN_EVSYS_CHMUX(step_pin);
|
||||
EVSYS_CHCTRL(i) = EVSYS_DIGFILT_8SAMPLES_gc;
|
||||
|
||||
// Clock
|
||||
channel_update_enable(i);
|
||||
channel[i].timer->INTCTRLA = TC_OVFINTLVL_HI_gc;
|
||||
|
||||
// Set initial clock direction
|
||||
channel_update_dir(i);
|
||||
}
|
||||
|
||||
|
||||
static void init() {
|
||||
cli();
|
||||
|
||||
hw_init();
|
||||
usart_init();
|
||||
|
||||
// Motor channels
|
||||
for (int i = 0; i < 4; i++) channel_init(i);
|
||||
|
||||
// Motor enable
|
||||
DIRCLR_PIN(MOTOR_ENABLE_PIN);
|
||||
PINCTRL_PIN(MOTOR_ENABLE_PIN) =
|
||||
PORT_SRLEN_bm | PORT_ISC_BOTHEDGES_gc | PORT_OPC_PULLUP_gc;
|
||||
PIN_PORT(MOTOR_ENABLE_PIN)->INTCTRL |= PORT_INT0LVL_HI_gc;
|
||||
PIN_PORT(MOTOR_ENABLE_PIN)->INT0MASK |= PIN_BM(MOTOR_ENABLE_PIN);
|
||||
|
||||
// Configure report clock
|
||||
TCC1.INTCTRLA = TC_OVFINTLVL_LO_gc;
|
||||
TCC1.PER = F_CPU / 256 * 0.01; // 10ms
|
||||
TCC1.CTRLA = TC_CLKSEL_DIV256_gc;
|
||||
|
||||
// Reset switch
|
||||
DIRCLR_PIN(RESET_PIN);
|
||||
PINCTRL_PIN(RESET_PIN) =
|
||||
PORT_SRLEN_bm | PORT_ISC_RISING_gc | PORT_OPC_PULLUP_gc;
|
||||
PIN_PORT(RESET_PIN)->INTCTRL |= PORT_INT0LVL_LO_gc;
|
||||
PIN_PORT(RESET_PIN)->INT0MASK |= PIN_BM(RESET_PIN);
|
||||
|
||||
printf("RESET\n");
|
||||
|
||||
sei();
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
init();
|
||||
|
||||
_splash(0x27);
|
||||
_splash(0x3f);
|
||||
|
||||
while (true) continue;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -31,7 +31,6 @@ class Ctrl(object):
|
||||
self.avr = bbctrl.AVR(self)
|
||||
|
||||
self.i2c = bbctrl.I2C(args.i2c_port, args.demo)
|
||||
self.lcd = bbctrl.LCD(self)
|
||||
self.mach = bbctrl.Mach(self, self.avr)
|
||||
self.preplanner = bbctrl.Preplanner(self)
|
||||
if not args.demo:
|
||||
@@ -40,9 +39,6 @@ class Ctrl(object):
|
||||
|
||||
self.mach.connect()
|
||||
|
||||
self.lcd.add_new_page(bbctrl.MainLCDPage(self))
|
||||
self.lcd.add_new_page(bbctrl.IPLCDPage(self.lcd))
|
||||
|
||||
os.environ['GCODE_SCRIPT_PATH'] = self.get_upload()
|
||||
|
||||
except Exception:
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of the Buildbotics firmware. #
|
||||
# #
|
||||
# Copyright (c) 2015 - 2018, Buildbotics LLC #
|
||||
# All rights reserved. #
|
||||
# #
|
||||
# This file ("the software") is free software: you can redistribute it #
|
||||
# and/or modify it under the terms of the GNU General Public License, #
|
||||
# version 2 as published by the Free Software Foundation. You should #
|
||||
# have received a copy of the GNU General Public License, version 2 #
|
||||
# along with the software. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# The software is distributed in the hope that it will be useful, but #
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #
|
||||
# Lesser General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU Lesser General Public #
|
||||
# License along with the software. If not, see #
|
||||
# <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# For information regarding this software email: #
|
||||
# "Joseph Coffland" <joseph@buildbotics.com> #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
import subprocess
|
||||
|
||||
import bbctrl
|
||||
|
||||
|
||||
class IPLCDPage(bbctrl.LCDPage):
|
||||
# From bbctrl.LCDPage
|
||||
def activate(self):
|
||||
p = subprocess.Popen(['hostname', '-I'], stdout = subprocess.PIPE)
|
||||
ips = p.communicate()[0].decode('utf-8').split()
|
||||
|
||||
p = subprocess.Popen(['hostname'], stdout = subprocess.PIPE)
|
||||
hostname = p.communicate()[0].decode('utf-8').strip()
|
||||
|
||||
self.clear()
|
||||
|
||||
self.text('Host: %s' % hostname[0:14], 0, 0)
|
||||
|
||||
for i in range(min(3, len(ips))):
|
||||
if len(ips[i]) <= 16:
|
||||
self.text('IP: %s' % ips[i], 0, i + 1)
|
||||
@@ -64,12 +64,6 @@ class Jog(inevent.JogHandler):
|
||||
self.processor = inevent.InEvent(ctrl.ioloop, self, types = ['js'])
|
||||
|
||||
|
||||
def up(self): self.ctrl.lcd.page_up()
|
||||
def down(self): self.ctrl.lcd.page_down()
|
||||
def left(self): self.ctrl.lcd.page_left()
|
||||
def right(self): self.ctrl.lcd.page_right()
|
||||
|
||||
|
||||
def callback(self):
|
||||
if self.v != self.lastV:
|
||||
self.lastV = self.v
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of the Buildbotics firmware. #
|
||||
# #
|
||||
# Copyright (c) 2015 - 2018, Buildbotics LLC #
|
||||
# All rights reserved. #
|
||||
# #
|
||||
# This file ("the software") is free software: you can redistribute it #
|
||||
# and/or modify it under the terms of the GNU General Public License, #
|
||||
# version 2 as published by the Free Software Foundation. You should #
|
||||
# have received a copy of the GNU General Public License, version 2 #
|
||||
# along with the software. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# The software is distributed in the hope that it will be useful, but #
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #
|
||||
# Lesser General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU Lesser General Public #
|
||||
# License along with the software. If not, see #
|
||||
# <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# For information regarding this software email: #
|
||||
# "Joseph Coffland" <joseph@buildbotics.com> #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
import lcd
|
||||
import atexit
|
||||
|
||||
|
||||
class LCDPage:
|
||||
def __init__(self, lcd, text = None):
|
||||
self.lcd = lcd
|
||||
self.data = lcd.new_screen()
|
||||
|
||||
if text is not None:
|
||||
self.text(text, (lcd.width - len(text)) // 2, 1)
|
||||
|
||||
|
||||
def activate(self): pass
|
||||
def deactivate(self): pass
|
||||
|
||||
|
||||
def put(self, c, x, y):
|
||||
y += x // self.lcd.width
|
||||
x %= self.lcd.width
|
||||
y %= self.lcd.height
|
||||
|
||||
if self.data[x][y] != c:
|
||||
self.data[x][y] = c
|
||||
if self == self.lcd.page: self.lcd.update()
|
||||
|
||||
|
||||
def text(self, s, x, y):
|
||||
for c in s:
|
||||
self.put(c, x, y)
|
||||
x += 1
|
||||
|
||||
|
||||
def clear(self):
|
||||
self.data = self.lcd.new_screen()
|
||||
self.lcd.redraw = True
|
||||
|
||||
|
||||
def shift_left(self): pass
|
||||
def shift_right(self): pass
|
||||
def shift_up(self): pass
|
||||
def shift_down(self): pass
|
||||
|
||||
|
||||
class LCD:
|
||||
def __init__(self, ctrl):
|
||||
self.ctrl = ctrl
|
||||
self.log = ctrl.log.get('LCD')
|
||||
|
||||
self.addrs = self.ctrl.args.lcd_addr
|
||||
self.addr = self.addrs[0]
|
||||
self.addr_num = 0
|
||||
|
||||
self.width = 20
|
||||
self.height = 4
|
||||
self.lcd = None
|
||||
self.timeout = None
|
||||
self.reset = False
|
||||
self.page = None
|
||||
self.pages = []
|
||||
self.current_page = 0
|
||||
self.screen = self.new_screen()
|
||||
self.set_message('Loading...')
|
||||
|
||||
self._redraw(False)
|
||||
if not ctrl.args.demo: atexit.register(self.goodbye)
|
||||
|
||||
|
||||
def set_message(self, msg):
|
||||
try:
|
||||
self.load_page(LCDPage(self, msg))
|
||||
self._update()
|
||||
except IOError as e:
|
||||
self.log.warning('LCD communication failed: %s' % e)
|
||||
|
||||
|
||||
def new_screen(self):
|
||||
return [[' ' for y in range(self.height)] for x in range(self.width)]
|
||||
|
||||
|
||||
def new_page(self): return LCDPage(self)
|
||||
def add_page(self, page): self.pages.append(page)
|
||||
|
||||
|
||||
def add_new_page(self, page = None):
|
||||
if page is None: page = self.new_page()
|
||||
page.id = len(self.pages)
|
||||
self.add_page(page)
|
||||
return page
|
||||
|
||||
|
||||
def load_page(self, page):
|
||||
if self.page != page:
|
||||
if self.page is not None: self.page.deactivate()
|
||||
page.activate()
|
||||
self.page = page
|
||||
self.redraw = True
|
||||
self.update()
|
||||
|
||||
|
||||
def set_current_page(self, current_page):
|
||||
self.current_page = current_page % len(self.pages)
|
||||
self.load_page(self.pages[self.current_page])
|
||||
|
||||
|
||||
def page_up(self): pass
|
||||
def page_down(self): pass
|
||||
def page_right(self): self.set_current_page(self.current_page + 1)
|
||||
def page_left(self): self.set_current_page(self.current_page - 1)
|
||||
|
||||
|
||||
def update(self):
|
||||
if self.timeout is None:
|
||||
self.timeout = self.ctrl.ioloop.call_later(0.25, self._update)
|
||||
|
||||
|
||||
def _redraw(self, now = True):
|
||||
if now:
|
||||
self.redraw = True
|
||||
self.update()
|
||||
self.redraw_timer = self.ctrl.ioloop.call_later(5, self._redraw)
|
||||
|
||||
|
||||
def _update(self):
|
||||
self.timeout = None
|
||||
|
||||
try:
|
||||
if self.lcd is None:
|
||||
self.lcd = lcd.LCD(self.ctrl.i2c, self.addr, self.height,
|
||||
self.width)
|
||||
|
||||
if self.reset:
|
||||
self.lcd.reset()
|
||||
self.redraw = True
|
||||
self.reset = False
|
||||
|
||||
cursorX, cursorY = -1, -1
|
||||
|
||||
for y in range(self.height):
|
||||
for x in range(self.width):
|
||||
c = self.page.data[x][y]
|
||||
|
||||
if self.redraw or self.screen[x][y] != c:
|
||||
if cursorX != x or cursorY != y:
|
||||
self.lcd.goto(x, y)
|
||||
cursorX, cursorY = x, y
|
||||
|
||||
self.lcd.put_char(c)
|
||||
cursorX += 1
|
||||
self.screen[x][y] = c
|
||||
|
||||
self.redraw = False
|
||||
|
||||
except IOError as e:
|
||||
# Try next address
|
||||
#self.addr_num += 1
|
||||
#if len(self.addrs) <= self.addr_num: self.addr_num = 0
|
||||
#self.addr = self.addrs[self.addr_num]
|
||||
#self.lcd = None
|
||||
|
||||
#self.log.warning('LCD communication failed, ' +
|
||||
# 'retrying on address 0x%02x: %s' % (self.addr, e))
|
||||
|
||||
#self.log.warning('LCD not present.')
|
||||
|
||||
#self.reset = True
|
||||
self.reset = False
|
||||
#self.timeout = self.ctrl.ioloop.call_later(1, self._update)
|
||||
|
||||
|
||||
def goodbye(self, message = ''):
|
||||
if self.timeout:
|
||||
self.ctrl.ioloop.remove_timeout(self.timeout)
|
||||
self.timeout = None
|
||||
|
||||
if self.redraw_timer:
|
||||
self.ctrl.ioloop.remove_timeout(self.redraw_timer)
|
||||
self.redraw_timer = None
|
||||
|
||||
if self.lcd is not None: self.set_message(message)
|
||||
@@ -1,76 +0,0 @@
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of the Buildbotics firmware. #
|
||||
# #
|
||||
# Copyright (c) 2015 - 2018, Buildbotics LLC #
|
||||
# All rights reserved. #
|
||||
# #
|
||||
# This file ("the software") is free software: you can redistribute it #
|
||||
# and/or modify it under the terms of the GNU General Public License, #
|
||||
# version 2 as published by the Free Software Foundation. You should #
|
||||
# have received a copy of the GNU General Public License, version 2 #
|
||||
# along with the software. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# The software is distributed in the hope that it will be useful, but #
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #
|
||||
# Lesser General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU Lesser General Public #
|
||||
# License along with the software. If not, see #
|
||||
# <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# For information regarding this software email: #
|
||||
# "Joseph Coffland" <joseph@buildbotics.com> #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
import bbctrl
|
||||
|
||||
|
||||
class MainLCDPage(bbctrl.LCDPage):
|
||||
def __init__(self, ctrl):
|
||||
bbctrl.LCDPage.__init__(self, ctrl.lcd)
|
||||
|
||||
self.ctrl = ctrl
|
||||
self.install = True
|
||||
|
||||
ctrl.state.add_listener(self.update)
|
||||
|
||||
|
||||
def update(self, update):
|
||||
state = self.ctrl.state
|
||||
|
||||
# Must be after machine vars have loaded
|
||||
if self.install and hasattr(self, 'id'):
|
||||
self.install = False
|
||||
self.ctrl.lcd.set_current_page(self.id)
|
||||
|
||||
self.text('%-9s' % state.get('xx', ''), 0, 0)
|
||||
|
||||
metric = not state.get('imperial', False)
|
||||
scale = 1 if metric else 25.4
|
||||
|
||||
# Show enabled axes
|
||||
row = 0
|
||||
for axis in 'xyzabc':
|
||||
if state.is_axis_faulted(axis):
|
||||
self.text(' FAULT %s' % axis.upper(), 9, row)
|
||||
row += 1
|
||||
|
||||
elif state.is_axis_enabled(axis):
|
||||
position = state.get(axis + 'p', 0)
|
||||
position += state.get('offset_' + axis, 0)
|
||||
position /= scale
|
||||
self.text('% 10.3f%s' % (position, axis.upper()), 9, row)
|
||||
row += 1
|
||||
|
||||
while row < 4:
|
||||
self.text(' ' * 11, 9, row)
|
||||
row += 1
|
||||
|
||||
# Show tool, units, feed and speed
|
||||
self.text('%2uT' % state.get('tool', 0), 6, 1)
|
||||
self.text('%-6s' % 'MM' if metric else 'INCH', 0, 1)
|
||||
self.text('%8uF' % (state.get('feed', 0) / scale), 0, 2)
|
||||
self.text('%8dS' % state.get('speed', 0), 0, 3)
|
||||
@@ -68,7 +68,6 @@ class Pwr():
|
||||
|
||||
self.i2c_addr = ctrl.args.pwr_addr
|
||||
self.regs = [-1] * 9
|
||||
self.lcd_page = ctrl.lcd.add_new_page()
|
||||
self.failures = 0
|
||||
|
||||
self._update_cb(False)
|
||||
@@ -179,16 +178,6 @@ class Pwr():
|
||||
self.failures = 0
|
||||
return
|
||||
|
||||
self.lcd_page.text('%3dC Tmp' % self.regs[TEMP_REG], 0, 0)
|
||||
self.lcd_page.text('%5.1fV In' % self.regs[VIN_REG], 0, 1)
|
||||
self.lcd_page.text('%5.1fV Out' % self.regs[VOUT_REG], 0, 2)
|
||||
self.lcd_page.text(' %04x Flg' % self.regs[FLAGS_REG], 0, 3)
|
||||
|
||||
self.lcd_page.text('%5.1fA Mot' % self.regs[MOTOR_REG], 10, 0)
|
||||
self.lcd_page.text('%5.1fA Ld1' % self.regs[LOAD1_REG], 10, 1)
|
||||
self.lcd_page.text('%5.1fA Ld2' % self.regs[LOAD2_REG], 10, 2)
|
||||
self.lcd_page.text('%5.1fA Vdd' % self.regs[VDD_REG], 10, 3)
|
||||
|
||||
if len(update): self.ctrl.state.update(update)
|
||||
|
||||
self.failures = 0
|
||||
|
||||
@@ -22,7 +22,6 @@ def call_get_output(cmd):
|
||||
|
||||
class RebootHandler(bbctrl.APIHandler):
|
||||
def put_ok(self):
|
||||
self.get_ctrl().lcd.goodbye('Rebooting...')
|
||||
subprocess.Popen('reboot')
|
||||
|
||||
|
||||
@@ -193,13 +192,11 @@ class FirmwareUpdateHandler(bbctrl.APIHandler):
|
||||
with open('firmware/update.tar.bz2', 'wb') as f:
|
||||
f.write(firmware['body'])
|
||||
|
||||
self.get_ctrl().lcd.goodbye('Upgrading firmware')
|
||||
subprocess.Popen(['/usr/local/bin/update-bbctrl'])
|
||||
|
||||
|
||||
class UpgradeHandler(bbctrl.APIHandler):
|
||||
def put_ok(self):
|
||||
self.get_ctrl().lcd.goodbye('Upgrading firmware')
|
||||
subprocess.Popen(['/usr/local/bin/upgrade-bbctrl'])
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ from bbctrl.RequestHandler import RequestHandler
|
||||
from bbctrl.APIHandler import APIHandler
|
||||
from bbctrl.FileHandler import FileHandler
|
||||
from bbctrl.Config import Config
|
||||
from bbctrl.LCD import LCD, LCDPage
|
||||
from bbctrl.Mach import Mach
|
||||
from bbctrl.Web import Web
|
||||
from bbctrl.Jog import Jog
|
||||
@@ -52,8 +51,6 @@ from bbctrl.Preplanner import Preplanner
|
||||
from bbctrl.State import State
|
||||
from bbctrl.Comm import Comm
|
||||
from bbctrl.CommandQueue import CommandQueue
|
||||
from bbctrl.MainLCDPage import MainLCDPage
|
||||
from bbctrl.IPLCDPage import IPLCDPage
|
||||
from bbctrl.Camera import Camera, VideoHandler
|
||||
from bbctrl.AVR import AVR
|
||||
from bbctrl.AVREmu import AVREmu
|
||||
@@ -132,8 +129,6 @@ def parse_args():
|
||||
help = 'Serial baud rate')
|
||||
parser.add_argument('--i2c-port', default = 1, type = int,
|
||||
help = 'I2C port')
|
||||
parser.add_argument('--lcd-addr', default = [0x27, 0x3f], type = int,
|
||||
help = 'LCD I2C address')
|
||||
parser.add_argument('--avr-addr', default = 0x2b, type = int,
|
||||
help = 'AVR I2C address')
|
||||
parser.add_argument('--pwr-addr', default = 0x60, type = int,
|
||||
|
||||
@@ -72,12 +72,6 @@ class JogHandler:
|
||||
log.info(axes_to_string(self.axes) + ' x {:d}'.format(self.speed))
|
||||
|
||||
|
||||
def up(self): log.debug('up')
|
||||
def down(self): log.debug('down')
|
||||
def left(self): log.debug('left')
|
||||
def right(self): log.debug('right')
|
||||
|
||||
|
||||
def reset(self):
|
||||
self.axes = [0.0, 0.0, 0.0, 0.0]
|
||||
self.speed = 3
|
||||
@@ -105,17 +99,6 @@ class JogHandler:
|
||||
if event.type == EV_ABS and event.code in config['axes']:
|
||||
pass
|
||||
|
||||
elif event.type == EV_ABS and event.code in config['arrows']:
|
||||
axis = config['arrows'].index(event.code)
|
||||
|
||||
if event.value < 0:
|
||||
if axis == 1: self.up()
|
||||
else: self.left()
|
||||
|
||||
elif 0 < event.value:
|
||||
if axis == 1: self.down()
|
||||
else: self.right()
|
||||
|
||||
elif event.type == EV_KEY and event.code in config['speed']:
|
||||
old_speed = self.speed
|
||||
self.speed = config['speed'].index(event.code) + 1
|
||||
|
||||
@@ -1,236 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of the Buildbotics firmware. #
|
||||
# #
|
||||
# Copyright (c) 2015 - 2018, Buildbotics LLC #
|
||||
# All rights reserved. #
|
||||
# #
|
||||
# This file ("the software") is free software: you can redistribute it #
|
||||
# and/or modify it under the terms of the GNU General Public License, #
|
||||
# version 2 as published by the Free Software Foundation. You should #
|
||||
# have received a copy of the GNU General Public License, version 2 #
|
||||
# along with the software. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# The software is distributed in the hope that it will be useful, but #
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #
|
||||
# Lesser General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU Lesser General Public #
|
||||
# License along with the software. If not, see #
|
||||
# <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# For information regarding this software email: #
|
||||
# "Joseph Coffland" <joseph@buildbotics.com> #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
import time
|
||||
import logging
|
||||
|
||||
|
||||
log = logging.getLogger('LCD')
|
||||
|
||||
|
||||
# Control flags
|
||||
REG_SELECT_BIT = 1 << 0
|
||||
READ_BIT = 1 << 1
|
||||
ENABLE_BIT = 1 << 2
|
||||
BACKLIGHT_BIT = 1 << 3
|
||||
|
||||
# Commands
|
||||
LCD_CLEAR_DISPLAY = 1 << 0
|
||||
LCD_RETURN_HOME = 1 << 1
|
||||
LCD_ENTRY_MODE_SET = 1 << 2
|
||||
LCD_DISPLAY_CONTROL = 1 << 3
|
||||
LCD_CURSOR_SHIFT = 1 << 4
|
||||
LCD_FUNCTION_SET = 1 << 5
|
||||
LCD_SET_CGRAM_ADDR = 1 << 6
|
||||
LCD_SET_DDRAM_ADDR = 1 << 7
|
||||
|
||||
# Entry Mode Set flags
|
||||
LCD_ENTRY_SHIFT_DISPLAY = 1 << 0
|
||||
LCD_ENTRY_SHIFT_INC = 1 << 1
|
||||
LCD_ENTRY_SHIFT_DEC = 0 << 1
|
||||
|
||||
# Display Control flags
|
||||
LCD_BLINK_ON = 1 << 0
|
||||
LCD_BLINK_OFF = 0 << 0
|
||||
LCD_CURSOR_ON = 1 << 1
|
||||
LCD_CURSOR_OFF = 0 << 1
|
||||
LCD_DISPLAY_ON = 1 << 2
|
||||
LCD_DISPLAY_OFF = 0 << 2
|
||||
|
||||
# Cursor Shift flags
|
||||
LCD_SHIFT_RIGHT = 1 << 2
|
||||
LCD_SHIFT_LEFT = 0 << 2
|
||||
LCD_SHIFT_DISPLAY = 1 << 3
|
||||
LCD_SHIFT_CURSOR = 0 << 3
|
||||
|
||||
# Function Set flags
|
||||
LCD_5x11_DOTS = 1 << 2
|
||||
LCD_5x8_DOTS = 0 << 2
|
||||
LCD_2_LINE = 1 << 3
|
||||
LCD_1_LINE = 0 << 3
|
||||
LCD_8_BIT_MODE = 1 << 4
|
||||
LCD_4_BIT_MODE = 0 << 4
|
||||
|
||||
# Text justification flags
|
||||
JUSTIFY_LEFT = 0
|
||||
JUSTIFY_RIGHT = 1
|
||||
JUSTIFY_CENTER = 2
|
||||
|
||||
|
||||
|
||||
class LCD:
|
||||
def __init__(self, i2c, addr, height = 4, width = 20):
|
||||
self.addr = addr
|
||||
self.height = height
|
||||
self.width = width
|
||||
self.i2c = i2c
|
||||
self.backlight = True
|
||||
|
||||
self.reset()
|
||||
|
||||
|
||||
def reset(self):
|
||||
self.clear()
|
||||
time.sleep(0.050)
|
||||
self.write_nibble(3 << 4) # Home
|
||||
time.sleep(0.050)
|
||||
self.write_nibble(3 << 4) # Home
|
||||
time.sleep(0.050)
|
||||
self.write_nibble(3 << 4) # Home
|
||||
self.write_nibble(2 << 4) # 4-bit
|
||||
|
||||
self.write(LCD_FUNCTION_SET | LCD_2_LINE | LCD_5x8_DOTS |
|
||||
LCD_4_BIT_MODE)
|
||||
self.write(LCD_DISPLAY_CONTROL | LCD_DISPLAY_ON)
|
||||
self.write(LCD_ENTRY_MODE_SET | LCD_ENTRY_SHIFT_INC)
|
||||
|
||||
|
||||
def write_i2c(self, data):
|
||||
if self.backlight: data |= BACKLIGHT_BIT
|
||||
|
||||
self.i2c.write(self.addr, data)
|
||||
time.sleep(0.0001)
|
||||
|
||||
|
||||
# Write half of a command to LCD
|
||||
def write_nibble(self, data):
|
||||
self.write_i2c(data)
|
||||
|
||||
# Strobe
|
||||
self.write_i2c(data | ENABLE_BIT)
|
||||
time.sleep(0.0005)
|
||||
|
||||
self.write_i2c(data & ~ENABLE_BIT)
|
||||
time.sleep(0.0001)
|
||||
|
||||
|
||||
# Write an 8-bit command to LCD
|
||||
def write(self, cmd, flags = 0):
|
||||
self.write_nibble(flags | (cmd & 0xf0))
|
||||
self.write_nibble(flags | ((cmd << 4) & 0xf0))
|
||||
|
||||
|
||||
def set_cursor(self, on, blink):
|
||||
data = LCD_DISPLAY_CONTROL
|
||||
|
||||
if on: data |= LCD_CURSOR_ON
|
||||
if blink: data |= LCD_BLINK_ON
|
||||
|
||||
self.write(data)
|
||||
|
||||
|
||||
def set_backlight(self, enable):
|
||||
self.backlight = enable
|
||||
self.write_i2c(0)
|
||||
|
||||
|
||||
def program_char(self, addr, data):
|
||||
if addr < 0 or 8 <= addr: return
|
||||
|
||||
self.write(LCD_SET_CGRAM_ADDR | (addr << 3))
|
||||
for x in data:
|
||||
self.write(x, REG_SELECT_BIT)
|
||||
|
||||
|
||||
def goto(self, x, y):
|
||||
if x < 0 or self.width <= x or y < 0 or self.height <= y: return
|
||||
self.write(LCD_SET_DDRAM_ADDR | (0, 64, 20, 84)[y] + int(x))
|
||||
|
||||
|
||||
def put_char(self, c):
|
||||
self.write(ord(c), REG_SELECT_BIT)
|
||||
|
||||
|
||||
def text(self, msg, x = None, y = None):
|
||||
if x is not None and y is not None: self.goto(x, y)
|
||||
|
||||
for c in msg: self.put_char(c)
|
||||
|
||||
|
||||
def display(self, line, msg, justify = JUSTIFY_LEFT):
|
||||
if justify == JUSTIFY_RIGHT: x = self.width - len(msg)
|
||||
elif justify == JUSTIFY_CENTER: x = (self.width - len(msg)) / 2
|
||||
else: x = 0
|
||||
|
||||
if x < 0: x = 0
|
||||
|
||||
self.text(msg, x, line)
|
||||
|
||||
|
||||
def shift(self, count = 1, right = True, display = True):
|
||||
cmd = LCD_CURSOR_SHIFT
|
||||
if right: cmd |= LCD_SHIFT_RIGHT
|
||||
if display: cmd |= LCD_SHIFT_DISPLAY
|
||||
|
||||
for i in range(count): self.write(cmd)
|
||||
|
||||
|
||||
# Clear LCD and move cursor home
|
||||
def clear(self):
|
||||
self.write(LCD_CLEAR_DISPLAY)
|
||||
self.write(LCD_RETURN_HOME)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
lcd = LCD(1, 0x27)
|
||||
|
||||
lcd.clear()
|
||||
|
||||
lcd.program_char(0, (0b11011,
|
||||
0b11011,
|
||||
0b00000,
|
||||
0b01100,
|
||||
0b01100,
|
||||
0b00000,
|
||||
0b11011,
|
||||
0b11011))
|
||||
|
||||
lcd.program_char(1, (0b11000,
|
||||
0b01100,
|
||||
0b00110,
|
||||
0b00011,
|
||||
0b00011,
|
||||
0b00110,
|
||||
0b01100,
|
||||
0b11000))
|
||||
|
||||
lcd.program_char(2, (0b00011,
|
||||
0b00110,
|
||||
0b01100,
|
||||
0b11000,
|
||||
0b11000,
|
||||
0b01100,
|
||||
0b00110,
|
||||
0b00011))
|
||||
|
||||
lcd.display(0, '\0' * lcd.width)
|
||||
lcd.display(1, 'Hello world!', JUSTIFY_CENTER)
|
||||
lcd.display(2, '\1\2' * (lcd.width / 2))
|
||||
lcd.display(3, '12345678901234567890')
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of the Buildbotics firmware. #
|
||||
# #
|
||||
# Copyright (c) 2015 - 2018, Buildbotics LLC #
|
||||
# All rights reserved. #
|
||||
# #
|
||||
# This file ("the software") is free software: you can redistribute it #
|
||||
# and/or modify it under the terms of the GNU General Public License, #
|
||||
# version 2 as published by the Free Software Foundation. You should #
|
||||
# have received a copy of the GNU General Public License, version 2 #
|
||||
# along with the software. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# The software is distributed in the hope that it will be useful, but #
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #
|
||||
# Lesser General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU Lesser General Public #
|
||||
# License along with the software. If not, see #
|
||||
# <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# For information regarding this software email: #
|
||||
# "Joseph Coffland" <joseph@buildbotics.com> #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
import lcd
|
||||
|
||||
if __name__ == "__main__":
|
||||
screen = lcd.LCD(1, 0x27)
|
||||
|
||||
screen.clear()
|
||||
screen.display(0, 'Buildbotics', lcd.JUSTIFY_CENTER)
|
||||
screen.display(1, 'Controller', lcd.JUSTIFY_CENTER)
|
||||
screen.display(3, 'Booting...', lcd.JUSTIFY_CENTER)
|
||||
Reference in New Issue
Block a user