Compare commits
11 commits
Author | SHA1 | Date | |
---|---|---|---|
c32c022d95 | |||
44f7a7ae2b | |||
8d5d6b3024 | |||
c26f3a3d19 | |||
4ecf66daa5 | |||
ab1e6ceb2c | |||
10733b27a7 | |||
612a1c082b | |||
|
3ae845f68d | ||
|
db92dbc3fb | ||
|
f5f5af221a |
20 changed files with 254 additions and 299 deletions
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[submodule "third_party/mbed"]
|
||||||
|
path = third_party/mbed
|
||||||
|
url = https://github.com/mbedmicro/mbed.git
|
||||||
|
[submodule "third_party/lpcopen"]
|
||||||
|
path = third_party/lpcopen
|
||||||
|
url = juju:~/p/git/lpcopen2
|
74
CMakeLists.txt
Normal file
74
CMakeLists.txt
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
# Copyright 2015 Google Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
cmake_minimum_required(VERSION 3.2)
|
||||||
|
project(ser2neo C CXX ASM)
|
||||||
|
|
||||||
|
set(LPCOPEN third_party/lpcopen)
|
||||||
|
|
||||||
|
add_library(
|
||||||
|
lpcopen
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/acmp_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/chip_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/clock_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/crc_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/gpio_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/i2c_common_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/i2cm_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/i2cs_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/iap.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/iocon_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/irc_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/pinint_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/pmu_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/ring_buffer.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/sct_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/sct_pwm_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/spi_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/spim_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/spis_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/stopwatch_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/swm_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/syscon_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/sysinit_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/uart_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/wkt_8xx.c
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/src/wwdt_8xx.c
|
||||||
|
)
|
||||||
|
|
||||||
|
set(MBED_LPC81X third_party/mbed/libraries/mbed/targets/cmsis/TARGET_NXP/TARGET_LPC81X)
|
||||||
|
|
||||||
|
set(STARTUP ${MBED_LPC81X}/TOOLCHAIN_GCC_ARM/startup_LPC81X.S)
|
||||||
|
set(LDSCRIPT ${MBED_LPC81X}/TARGET_LPC810/TOOLCHAIN_GCC_ARM/LPC810.ld)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${LPCOPEN}
|
||||||
|
${LPCOPEN}/lpc_chip_8xx/inc
|
||||||
|
.
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(
|
||||||
|
ser2neo
|
||||||
|
ser2neo.cc
|
||||||
|
serial.cc
|
||||||
|
neopixel.cc
|
||||||
|
retarget.cc
|
||||||
|
${STARTUP}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(ser2neo lpcopen)
|
||||||
|
|
||||||
|
set(EXTRA_FLAGS "-Wall -Os -flto --specs=nano.specs --specs=nosys.specs -DCORE_M0PLUS -Wl,-T${CMAKE_SOURCE_DIR}/${LDSCRIPT},-gc-sections -fno-builtin-printf -fno-builtin-putchar -fno-builtin-puts -Wl,-Map,ser2neo.map,--cref")
|
||||||
|
set(CMAKE_C_FLAGS "${COMMON_FLAGS} ${RUNTIME_FLAGS} ${EXTRA_FLAGS} -Wno-incompatible-pointer-types")
|
||||||
|
set(CMAKE_CXX_FLAGS "${COMMON_FLAGS} ${RUNTIME_FLAGS} ${EXTRA_FLAGS} -fno-exceptions -fno-rtti -std=gnu++14 -save-temps=obj")
|
16
Makefile
16
Makefile
|
@ -1,16 +0,0 @@
|
||||||
# Copyright 2015 Google Inc.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
include attiny85.mk
|
|
||||||
include avr.mk
|
|
16
attiny85.mk
16
attiny85.mk
|
@ -1,16 +0,0 @@
|
||||||
# Copyright 2015 Google Inc.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
DEVICE = attiny85
|
|
||||||
CLOCK = 16500000
|
|
47
avr.mk
47
avr.mk
|
@ -1,47 +0,0 @@
|
||||||
# Copyright 2015 Google Inc.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
APP ?= $(notdir $(PWD))
|
|
||||||
VERSION ?= $(shell date +%Y%m%d)+git$(shell git describe --always)
|
|
||||||
|
|
||||||
SRC = $(wildcard *.cc)
|
|
||||||
OBJ = $(SRC:%.cc=%.o)
|
|
||||||
|
|
||||||
CROSS_COMPILE = avr-
|
|
||||||
CC = $(CROSS_COMPILE)gcc
|
|
||||||
CXX = $(CROSS_COMPILE)g++
|
|
||||||
CFLAGS = -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -Wall
|
|
||||||
CXXFLAGS = $(CFLAGS) -std=gnu++1y
|
|
||||||
|
|
||||||
all: $(APP).hex
|
|
||||||
|
|
||||||
usb-flash: $(APP).hex
|
|
||||||
sudo $(HOME)/bin/micronucleus --run $<
|
|
||||||
|
|
||||||
%.elf: $(OBJ)
|
|
||||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ)
|
|
||||||
$(CROSS_COMPILE)size -d $@
|
|
||||||
|
|
||||||
%.hex: %.elf
|
|
||||||
avr-objcopy -j .text -j .data -O ihex $< $@
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(APP).hex $(APP).elf $(OBJ) *~ *.ii
|
|
||||||
|
|
||||||
dist:
|
|
||||||
rm -rf tmp
|
|
||||||
mkdir tmp
|
|
||||||
git archive --prefix=$(APP)-$(VERSION)/ HEAD | gzip > tmp/$(APP)-$(VERSION).tar.gz
|
|
||||||
cd tmp && git clone $$(readlink -f ..) $(APP)
|
|
||||||
$(MAKE) -C tmp/$(APP)
|
|
19
board.h
Normal file
19
board.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright 2015 Google Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define CONFIG_MAIN_FREQ 12'000'000
|
||||||
|
#define CONFIG_SYS_FREQ 12'000'000
|
|
@ -20,7 +20,7 @@ import colorsys
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
port = ser2neo.open_port('/dev/ttyUSB0')
|
port = ser2neo.open_port()
|
||||||
neo = ser2neo.NeoPixels(port)
|
neo = ser2neo.NeoPixels(port)
|
||||||
|
|
||||||
offset = 0
|
offset = 0
|
||||||
|
|
|
@ -23,7 +23,7 @@ def angle2idx(neo, angle, limit):
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
port = ser2neo.open_port('/dev/ttyUSB0')
|
port = ser2neo.open_port()
|
||||||
neo = ser2neo.NeoPixels(port)
|
neo = ser2neo.NeoPixels(port)
|
||||||
|
|
||||||
anim = ser2neo.Animator()
|
anim = ser2neo.Animator()
|
||||||
|
|
|
@ -24,7 +24,7 @@ def angle2idx(neo, angle, limit):
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
port = ser2neo.open_port('/dev/ttyUSB0')
|
port = ser2neo.open_port()
|
||||||
neo = ser2neo.NeoPixels(port)
|
neo = ser2neo.NeoPixels(port)
|
||||||
|
|
||||||
random.seed()
|
random.seed()
|
||||||
|
|
|
@ -18,7 +18,7 @@ import time
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
port = ser2neo.open_port('/dev/ttyUSB0')
|
port = ser2neo.open_port()
|
||||||
neo = ser2neo.NeoPixels(port)
|
neo = ser2neo.NeoPixels(port)
|
||||||
|
|
||||||
at = 0
|
at = 0
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
|
|
||||||
import serial
|
import serial
|
||||||
|
import serial.tools.list_ports
|
||||||
import time
|
import time
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
|
@ -33,18 +34,15 @@ class RGB:
|
||||||
|
|
||||||
def __add__(self, other):
|
def __add__(self, other):
|
||||||
"""Componentwise addition."""
|
"""Componentwise addition."""
|
||||||
return RGB(*list(
|
return RGB(*list(_clip(x + y) for x, y in zip(self.rgb, other.rgb)))
|
||||||
_clip(x + y) for x, y in zip(self.rgb, other.rgb)))
|
|
||||||
|
|
||||||
def __mul__(self, level):
|
def __mul__(self, level):
|
||||||
"""Scalar multiplier."""
|
"""Scalar multiplier."""
|
||||||
return RGB(*(
|
return RGB(*(_clip(x * level) for x in self.rgb))
|
||||||
_clip(x * level) for x in self.rgb))
|
|
||||||
|
|
||||||
def __truediv__(self, level):
|
def __truediv__(self, level):
|
||||||
"""Scalar division."""
|
"""Scalar division."""
|
||||||
return RGB(*(
|
return RGB(*(_clip(x / level) for x in self.rgb))
|
||||||
_clip(x / level) for x in self.rgb))
|
|
||||||
|
|
||||||
__div__ = __truediv__
|
__div__ = __truediv__
|
||||||
|
|
||||||
|
@ -64,17 +62,28 @@ class Colour:
|
||||||
|
|
||||||
def _escape(buf):
|
def _escape(buf):
|
||||||
EOL, ESC = ord('\r'), ord('+')
|
EOL, ESC = ord('\r'), ord('+')
|
||||||
|
special = set((EOL, ESC, ord('?')))
|
||||||
|
|
||||||
for ch in buf:
|
for ch in buf:
|
||||||
if ch == EOL or ch == ESC:
|
if ch in special:
|
||||||
yield ESC
|
yield ESC
|
||||||
yield ch ^ ESC
|
yield ch ^ ESC
|
||||||
else:
|
else:
|
||||||
yield ch
|
yield ch
|
||||||
|
|
||||||
|
|
||||||
def open_port(name):
|
def first_serial():
|
||||||
|
for info in serial.tools.list_ports.comports():
|
||||||
|
device = info[0]
|
||||||
|
if 'USB' in device or 'ACM' in device:
|
||||||
|
return device
|
||||||
|
return '/dev/ttyUSB0'
|
||||||
|
|
||||||
|
|
||||||
|
def open_port(name=None):
|
||||||
"""Open the serial connection to the adaptor."""
|
"""Open the serial connection to the adaptor."""
|
||||||
|
if name is None:
|
||||||
|
name = first_serial()
|
||||||
return serial.Serial(name, 57600, timeout=0.02)
|
return serial.Serial(name, 57600, timeout=0.02)
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,8 +117,7 @@ class NeoPixels:
|
||||||
buf = b'l'
|
buf = b'l'
|
||||||
for rgb in self.leds:
|
for rgb in self.leds:
|
||||||
rgb = rgb * self.brightness
|
rgb = rgb * self.brightness
|
||||||
buf += struct.pack('BBB',
|
buf += struct.pack('BBB', int(_clip(rgb.rgb[1] * 0xFF, 0xFF)),
|
||||||
int(_clip(rgb.rgb[1] * 0xFF, 0xFF)),
|
|
||||||
int(_clip(rgb.rgb[0] * 0xFF, 0xFF)),
|
int(_clip(rgb.rgb[0] * 0xFF, 0xFF)),
|
||||||
int(_clip(rgb.rgb[2] * 0xFF, 0xFF)))
|
int(_clip(rgb.rgb[2] * 0xFF, 0xFF)))
|
||||||
if str == bytes:
|
if str == bytes:
|
||||||
|
|
|
@ -17,7 +17,7 @@ import ser2neo
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
port = ser2neo.open_port('/dev/ttyUSB0')
|
port = ser2neo.open_port()
|
||||||
neo = ser2neo.NeoPixels(port)
|
neo = ser2neo.NeoPixels(port)
|
||||||
|
|
||||||
p0 = 0
|
p0 = 0
|
||||||
|
|
98
neopixel.cc
98
neopixel.cc
|
@ -15,66 +15,82 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
#include "neopixel.h"
|
#include "neopixel.h"
|
||||||
#include "serial.h"
|
#include "chip.h"
|
||||||
|
|
||||||
#include <avr/io.h>
|
#include <cstring>
|
||||||
#include <avr/interrupt.h>
|
|
||||||
#include <string.h>
|
#define CFG_ENABLE (1<<0)
|
||||||
|
#define CFG_MASTER (1<<2)
|
||||||
|
|
||||||
|
const uint16_t NeoPixel::bits_[] = {
|
||||||
|
0b100100100100,
|
||||||
|
0b100100100110,
|
||||||
|
0b100100110100,
|
||||||
|
0b100100110110,
|
||||||
|
0b100110100100,
|
||||||
|
0b100110100110,
|
||||||
|
0b100110110100,
|
||||||
|
0b100110110110,
|
||||||
|
0b110100100100,
|
||||||
|
0b110100100110,
|
||||||
|
0b110100110100,
|
||||||
|
0b110100110110,
|
||||||
|
0b110110100100,
|
||||||
|
0b110110100110,
|
||||||
|
0b110110110100,
|
||||||
|
0b110110110110,
|
||||||
|
};
|
||||||
|
|
||||||
extern Serial serial;
|
|
||||||
|
|
||||||
/// Initialise the hardware.
|
/// Initialise the hardware.
|
||||||
void NeoPixel::init() {
|
void NeoPixel::init() {
|
||||||
DDRB |= _BV(1);
|
clear();
|
||||||
TCCR0A = _BV(WGM01) | _BV(WGM00) | _BV(COM0B1) | _BV(COM0B0);
|
|
||||||
TCCR0B = _BV(WGM02) | _BV(CS00);
|
|
||||||
|
|
||||||
static_assert(Reload > 15, "Inter-bit time is probably too short.");
|
LPC_FMC->FLASHCFG = 0; // 1 wait state instead of 1
|
||||||
OCR0A = Reload;
|
|
||||||
OCR0B = Low;
|
LPC_SWM->PINENABLE0 |= 1<<2; // disable SWCLK
|
||||||
|
LPC_SWM->PINASSIGN[4] = 0xFFFFFF03UL; // SPI0_MOSI 3
|
||||||
|
|
||||||
|
/* Enable SPI0 clock */
|
||||||
|
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<11);
|
||||||
|
LPC_SYSCON->PRESETCTRL &= ~(1<<0);
|
||||||
|
LPC_SYSCON->PRESETCTRL |= (1<<0);
|
||||||
|
|
||||||
|
// 2.4 MHz, i.e. 12 MHz / 5
|
||||||
|
LPC_SPI0->DIV = 4;
|
||||||
|
LPC_SPI0->DLY = 0;
|
||||||
|
|
||||||
|
LPC_SPI0->TXCTRL = SPI_TXDATCTL_FLEN(12-1) | SPI_TXDATCTL_RXIGNORE;
|
||||||
|
|
||||||
|
LPC_SPI0->CFG = CFG_MASTER;
|
||||||
|
LPC_SPI0->CFG |= CFG_ENABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set all the LEDs to off and restart at the first LED.
|
/// Set all the LEDs to off and restart at the first LED.
|
||||||
void NeoPixel::clear() {
|
void NeoPixel::clear() {
|
||||||
p_ = bits_;
|
p_ = bytes_;
|
||||||
memset(bits_, Low, sizeof(bits_));
|
memset(bytes_, 0, sizeof(bytes_));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Append a byte to the stream.
|
/// Append a byte to the stream.
|
||||||
void NeoPixel::append(uint8_t b) {
|
void NeoPixel::append(uint8_t b) {
|
||||||
if (p_ <= (bits_ + sizeof(bits_) - Tail - BitsPerColour)) {
|
if (p_ <= (bytes_ + sizeof(bytes_))) {
|
||||||
for (auto i = 0; i < BitsPerColour; i++) {
|
*p_++ = b;
|
||||||
*p_++ = (b & 0x80) ? High : Low;
|
|
||||||
b <<= 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NeoPixel::send(uint16_t cmd) {
|
||||||
|
while ((LPC_SPI0->STAT & SPI_STAT_TXRDY) == 0) {}
|
||||||
|
LPC_SPI0->TXDAT = cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write to the LEDs.
|
/// Write to the LEDs.
|
||||||
void NeoPixel::write() {
|
void NeoPixel::write() {
|
||||||
bits_[sizeof(bits_) - 1] = Stop;
|
send(0);
|
||||||
|
send(0);
|
||||||
uint8_t *p = bits_;
|
for (auto p = bytes_; p < bytes_ + sizeof(bytes_); p++) {
|
||||||
uint8_t *pend = bits_ + sizeof(bits_);
|
auto ch = *p;
|
||||||
|
send(bits_[ch >> 4]);
|
||||||
cli();
|
send(bits_[ch & 0xF]);
|
||||||
|
|
||||||
OCR0B = Stop;
|
|
||||||
TIFR |= _BV(OCF0A);
|
|
||||||
while (!(TIFR & _BV(OCF0A))) {
|
|
||||||
}
|
}
|
||||||
TIFR |= _BV(OCF0A);
|
|
||||||
while (!(TIFR & _BV(OCF0A))) {
|
|
||||||
}
|
|
||||||
OCR0B = *p++;
|
|
||||||
|
|
||||||
for (; p != pend; p++) {
|
|
||||||
while (!(TIFR & _BV(OCF0A))) {
|
|
||||||
}
|
|
||||||
OCR0B = *p;
|
|
||||||
TIFR |= _BV(OCF0A);
|
|
||||||
}
|
|
||||||
OCR0B = Stop;
|
|
||||||
|
|
||||||
sei();
|
|
||||||
}
|
}
|
||||||
|
|
10
neopixel.h
10
neopixel.h
|
@ -35,15 +35,11 @@ class NeoPixel {
|
||||||
private:
|
private:
|
||||||
static const int MaxLEDs = 16;
|
static const int MaxLEDs = 16;
|
||||||
|
|
||||||
static const int BitsPerColour = 8;
|
|
||||||
static const int ColoursPerLED = 3;
|
static const int ColoursPerLED = 3;
|
||||||
static const int Tail = 2;
|
|
||||||
|
|
||||||
static const uint8_t Reload = F_CPU / 800000;
|
void send(uint16_t ch);
|
||||||
static const uint8_t Low = Reload * 2 / 3;
|
|
||||||
static const uint8_t High = Reload - Low;
|
|
||||||
static const uint8_t Stop = 0xFF;
|
|
||||||
|
|
||||||
uint8_t* p_;
|
uint8_t* p_;
|
||||||
uint8_t bits_[MaxLEDs * ColoursPerLED * BitsPerColour + Tail];
|
uint8_t bytes_[MaxLEDs * ColoursPerLED];
|
||||||
|
static const uint16_t bits_[];
|
||||||
};
|
};
|
||||||
|
|
21
retarget.cc
Normal file
21
retarget.cc
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2015 Google Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
#include "chip.h"
|
||||||
|
|
||||||
|
extern "C" void _exit(int code) {
|
||||||
|
for (;;) {
|
||||||
|
__WFI();
|
||||||
|
}
|
||||||
|
}
|
25
ser2neo.cc
25
ser2neo.cc
|
@ -14,7 +14,6 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
#include <avr/interrupt.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "neopixel.h"
|
#include "neopixel.h"
|
||||||
|
@ -43,6 +42,22 @@ class Ser2Neo {
|
||||||
Serial serial;
|
Serial serial;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern "C" void SystemInit() {
|
||||||
|
Chip_SYSCTL_PowerUp(SYSCTL_SLPWAKE_IRC_PD);
|
||||||
|
Chip_Clock_SetSystemPLLSource(SYSCTL_PLLCLKSRC_IRC);
|
||||||
|
Chip_Clock_SetMainClockSource(SYSCTL_MAINCLKSRC_IRC);
|
||||||
|
Chip_FMC_SetFLASHAccess(FLASHTIM_20MHZ_CPU);
|
||||||
|
|
||||||
|
Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_IOCON);
|
||||||
|
Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SWM);
|
||||||
|
|
||||||
|
Chip_SWM_DisableFixedPin(SWM_FIXED_SWCLK);
|
||||||
|
Chip_SWM_DisableFixedPin(SWM_FIXED_SWDIO);
|
||||||
|
|
||||||
|
Chip_SWM_MovablePinAssign(SWM_U0_TXD_O, 4);
|
||||||
|
Chip_SWM_MovablePinAssign(SWM_U0_RXD_I, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/// Initialise the hardware.
|
/// Initialise the hardware.
|
||||||
void Ser2Neo::init() {
|
void Ser2Neo::init() {
|
||||||
leds.init();
|
leds.init();
|
||||||
|
@ -96,8 +111,6 @@ void Ser2Neo::send_ok(const char* msg) {
|
||||||
|
|
||||||
/// Run the main loop. Process and run commands.
|
/// Run the main loop. Process and run commands.
|
||||||
void Ser2Neo::run() {
|
void Ser2Neo::run() {
|
||||||
sei();
|
|
||||||
|
|
||||||
serial.putstr("READY\n");
|
serial.putstr("READY\n");
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -123,11 +136,11 @@ void Ser2Neo::run() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Ser2Neo ser2led;
|
static Ser2Neo ser2neo;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
ser2led.init();
|
ser2neo.init();
|
||||||
ser2led.run();
|
ser2neo.run();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
124
serial.cc
124
serial.cc
|
@ -1,4 +1,4 @@
|
||||||
// Half-duplex interrupt based serial port.
|
// Blocking serial port.
|
||||||
//
|
//
|
||||||
// Copyright 2015 Google Inc.
|
// Copyright 2015 Google Inc.
|
||||||
//
|
//
|
||||||
|
@ -16,107 +16,32 @@
|
||||||
//
|
//
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
|
|
||||||
#include <avr/io.h>
|
#include "board.h"
|
||||||
#include <avr/interrupt.h>
|
|
||||||
#include <avr/sleep.h>
|
|
||||||
|
|
||||||
Serial* Serial::instance_;
|
|
||||||
|
|
||||||
#define _clear(port, pin) port &= ~_BV(pin)
|
|
||||||
#define _set(port, pin) port |= _BV(pin)
|
|
||||||
|
|
||||||
/// Initialise the hardware.
|
/// Initialise the hardware.
|
||||||
void Serial::init() {
|
void Serial::init() {
|
||||||
state_ = Idle;
|
Chip_UART_Init(LPC_USART0);
|
||||||
rx_full_ = false;
|
Chip_Clock_SetUARTClockDiv(ClockDiv);
|
||||||
|
|
||||||
instance_ = this;
|
handle_ = LPC_UARTD_API->uart_setup(
|
||||||
|
LPC_USART0_BASE, static_cast<uint8_t*>(static_cast<void*>(mem_)));
|
||||||
|
|
||||||
// Set up the GPIOs.
|
UART_CONFIG_T cfg = {
|
||||||
_set(DDRB, TxPin);
|
.sys_clk_in_hz = CONFIG_SYS_FREQ / ClockDiv,
|
||||||
_set(PORTB, TxPin);
|
.baudrate_in_hz = 115200,
|
||||||
_clear(DDRB, RxPin);
|
.config = 1,
|
||||||
|
.sync_mod = 0,
|
||||||
|
.error_en = NO_ERR_EN,
|
||||||
|
};
|
||||||
|
|
||||||
// Set up the timer.
|
auto frg = LPC_UARTD_API->uart_init(handle_, &cfg);
|
||||||
static_assert(BitTime > 50, "BitTime is too short");
|
Chip_SYSCTL_SetUSARTFRGDivider(0xFF);
|
||||||
static_assert(BitTime < 255*2/3, "BitTime may overflow");
|
Chip_SYSCTL_SetUSARTFRGMultiplier(frg);
|
||||||
OCR1C = BitTime;
|
|
||||||
TCCR1 = _BV(CTC1) | _BV(PWM1A);
|
|
||||||
|
|
||||||
static_assert(Prescale == 2, "Mismatched prescaler");
|
|
||||||
TCCR1 |= _BV(CS11);
|
|
||||||
|
|
||||||
// Set up the pin change interrupt.
|
|
||||||
PCMSK = _BV(RxPin);
|
|
||||||
_set(GIMSK, PCIE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Handle the pin change interrupt by starting receive.
|
|
||||||
void Serial::pcint0() {
|
|
||||||
_clear(PCMSK, RxPin);
|
|
||||||
_clear(TIMSK, TOV1); // PENDING
|
|
||||||
|
|
||||||
OCR1C = (BitTime / 2 * 3) - (PCIntDelay / Prescale);
|
|
||||||
TCNT1 = 0;
|
|
||||||
_set(TIFR, TOV1);
|
|
||||||
|
|
||||||
state_ = Receive;
|
|
||||||
bits_ = 8;
|
|
||||||
|
|
||||||
_set(TIMSK, TOV1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Handle the timer overflow interrupt by doing the next bit.
|
|
||||||
inline void Serial::timer1ovf() {
|
|
||||||
switch (state_) {
|
|
||||||
case Receive: {
|
|
||||||
auto got = PINB;
|
|
||||||
OCR1C = BitTime;
|
|
||||||
if (bits_ > 0) {
|
|
||||||
rxing_ >>= 1;
|
|
||||||
if (got & _BV(RxPin)) {
|
|
||||||
rxing_ |= 0x80;
|
|
||||||
}
|
|
||||||
bits_--;
|
|
||||||
} else {
|
|
||||||
state_ = Idle;
|
|
||||||
rxed_ = rxing_;
|
|
||||||
rx_full_ = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Transmit:
|
|
||||||
if (txing_ & 1) {
|
|
||||||
_set(PORTB, TxPin);
|
|
||||||
} else {
|
|
||||||
_clear(PORTB, TxPin);
|
|
||||||
}
|
|
||||||
txing_ >>= 1;
|
|
||||||
if (--bits_ == 0) {
|
|
||||||
state_ = Idle;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state_ == Idle) {
|
|
||||||
_clear(TIMSK, TOV1);
|
|
||||||
_set(PCMSK, RxPin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wait until the hardware is free then start the transmit.
|
/// Wait until the hardware is free then start the transmit.
|
||||||
void Serial::putch(uint8_t ch) {
|
void Serial::putch(uint8_t ch) {
|
||||||
while (state_ != Idle) {
|
LPC_UARTD_API->uart_put_char(handle_, ch);
|
||||||
sleep_cpu();
|
|
||||||
}
|
|
||||||
state_ = Transmit;
|
|
||||||
txing_ = (ch << 1) | 0xFE00;
|
|
||||||
bits_ = 10;
|
|
||||||
|
|
||||||
TCNT1 = 0;
|
|
||||||
_set(TIMSK, TOV1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a string.
|
/// Send a string.
|
||||||
|
@ -128,18 +53,5 @@ void Serial::putstr(const char* str) {
|
||||||
|
|
||||||
/// Wait until a character is received, then return it.
|
/// Wait until a character is received, then return it.
|
||||||
uint8_t Serial::getch() {
|
uint8_t Serial::getch() {
|
||||||
while (!rx_full_) {
|
return LPC_UARTD_API->uart_get_char(handle_);
|
||||||
sleep_cpu();
|
|
||||||
}
|
}
|
||||||
uint8_t ch = rxed_;
|
|
||||||
rx_full_ = false;
|
|
||||||
return ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Serial::pcint0_bounce() { instance_->pcint0(); }
|
|
||||||
|
|
||||||
inline void Serial::timer1ovf_bounce() { instance_->timer1ovf(); }
|
|
||||||
|
|
||||||
ISR(TIMER1_OVF_vect) { Serial::timer1ovf_bounce(); }
|
|
||||||
|
|
||||||
ISR(PCINT0_vect) { Serial::pcint0_bounce(); }
|
|
||||||
|
|
49
serial.h
49
serial.h
|
@ -1,4 +1,4 @@
|
||||||
// Half-duplex interrupt based serial port.
|
// Blocking serial port.
|
||||||
//
|
//
|
||||||
// Copyright 2015 Google Inc.
|
// Copyright 2015 Google Inc.
|
||||||
//
|
//
|
||||||
|
@ -18,9 +18,9 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/// Half-duplex interrupt based serial port.
|
#include "chip.h"
|
||||||
///
|
|
||||||
/// Loosely based on AVR304.
|
/// Blocking serial port.
|
||||||
///
|
///
|
||||||
class Serial {
|
class Serial {
|
||||||
public:
|
public:
|
||||||
|
@ -32,41 +32,8 @@ class Serial {
|
||||||
uint8_t getch();
|
uint8_t getch();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum State : uint8_t {
|
static const int ClockDiv = 1;
|
||||||
Idle,
|
|
||||||
Receive,
|
uint32_t mem_[40 / sizeof(uint32_t)];
|
||||||
Transmit,
|
UART_HANDLE_T* handle_;
|
||||||
};
|
|
||||||
|
|
||||||
// Note that these are all specific to an ATTINY85 USB board.
|
|
||||||
static const int RxPin = 0;
|
|
||||||
static const int TxPin = 2;
|
|
||||||
|
|
||||||
static const auto Prescale = 2;
|
|
||||||
static const auto Baud = 57600;
|
|
||||||
static const auto BitTime = F_CPU / Prescale / Baud - 1;
|
|
||||||
// Total number of clocks taken to service the pin change
|
|
||||||
// interrupt and start the receive. Use this to reduce the first
|
|
||||||
// bit-and-a-half time so sampling occurs half way through the
|
|
||||||
// first bit.
|
|
||||||
static const uint8_t PCIntDelay = 140;
|
|
||||||
|
|
||||||
void pcint0();
|
|
||||||
void timer1ovf();
|
|
||||||
|
|
||||||
volatile State state_;
|
|
||||||
uint8_t rxing_;
|
|
||||||
// Remaining number of bits to send or receive.
|
|
||||||
uint8_t bits_;
|
|
||||||
volatile uint8_t rxed_;
|
|
||||||
volatile bool rx_full_;
|
|
||||||
|
|
||||||
volatile uint16_t txing_;
|
|
||||||
|
|
||||||
static Serial* instance_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Interrupt handler entry points.
|
|
||||||
static void pcint0_bounce();
|
|
||||||
static void timer1ovf_bounce();
|
|
||||||
};
|
};
|
||||||
|
|
1
third_party/lpcopen
vendored
Submodule
1
third_party/lpcopen
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 478fc8fe6087ec8c9eebff491f0324c8dd38db87
|
1
third_party/mbed
vendored
Submodule
1
third_party/mbed
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 216fca1081a128e31a6a0b6683f6fe6f511ba647
|
Loading…
Reference in a new issue