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():
|
||||
port = ser2neo.open_port('/dev/ttyUSB0')
|
||||
port = ser2neo.open_port()
|
||||
neo = ser2neo.NeoPixels(port)
|
||||
|
||||
offset = 0
|
||||
|
|
|
@ -23,7 +23,7 @@ def angle2idx(neo, angle, limit):
|
|||
|
||||
|
||||
def main():
|
||||
port = ser2neo.open_port('/dev/ttyUSB0')
|
||||
port = ser2neo.open_port()
|
||||
neo = ser2neo.NeoPixels(port)
|
||||
|
||||
anim = ser2neo.Animator()
|
||||
|
|
|
@ -24,7 +24,7 @@ def angle2idx(neo, angle, limit):
|
|||
|
||||
|
||||
def main():
|
||||
port = ser2neo.open_port('/dev/ttyUSB0')
|
||||
port = ser2neo.open_port()
|
||||
neo = ser2neo.NeoPixels(port)
|
||||
|
||||
random.seed()
|
||||
|
|
|
@ -18,7 +18,7 @@ import time
|
|||
|
||||
|
||||
def main():
|
||||
port = ser2neo.open_port('/dev/ttyUSB0')
|
||||
port = ser2neo.open_port()
|
||||
neo = ser2neo.NeoPixels(port)
|
||||
|
||||
at = 0
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
from __future__ import division
|
||||
|
||||
import serial
|
||||
import serial.tools.list_ports
|
||||
import time
|
||||
import struct
|
||||
|
||||
|
@ -33,18 +34,15 @@ class RGB:
|
|||
|
||||
def __add__(self, other):
|
||||
"""Componentwise addition."""
|
||||
return RGB(*list(
|
||||
_clip(x + y) for x, y in zip(self.rgb, other.rgb)))
|
||||
return RGB(*list(_clip(x + y) for x, y in zip(self.rgb, other.rgb)))
|
||||
|
||||
def __mul__(self, level):
|
||||
"""Scalar multiplier."""
|
||||
return RGB(*(
|
||||
_clip(x * level) for x in self.rgb))
|
||||
return RGB(*(_clip(x * level) for x in self.rgb))
|
||||
|
||||
def __truediv__(self, level):
|
||||
"""Scalar division."""
|
||||
return RGB(*(
|
||||
_clip(x / level) for x in self.rgb))
|
||||
return RGB(*(_clip(x / level) for x in self.rgb))
|
||||
|
||||
__div__ = __truediv__
|
||||
|
||||
|
@ -64,17 +62,28 @@ class Colour:
|
|||
|
||||
def _escape(buf):
|
||||
EOL, ESC = ord('\r'), ord('+')
|
||||
special = set((EOL, ESC, ord('?')))
|
||||
|
||||
for ch in buf:
|
||||
if ch == EOL or ch == ESC:
|
||||
if ch in special:
|
||||
yield ESC
|
||||
yield ch ^ ESC
|
||||
else:
|
||||
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."""
|
||||
if name is None:
|
||||
name = first_serial()
|
||||
return serial.Serial(name, 57600, timeout=0.02)
|
||||
|
||||
|
||||
|
@ -108,8 +117,7 @@ class NeoPixels:
|
|||
buf = b'l'
|
||||
for rgb in self.leds:
|
||||
rgb = rgb * self.brightness
|
||||
buf += struct.pack('BBB',
|
||||
int(_clip(rgb.rgb[1] * 0xFF, 0xFF)),
|
||||
buf += struct.pack('BBB', int(_clip(rgb.rgb[1] * 0xFF, 0xFF)),
|
||||
int(_clip(rgb.rgb[0] * 0xFF, 0xFF)),
|
||||
int(_clip(rgb.rgb[2] * 0xFF, 0xFF)))
|
||||
if str == bytes:
|
||||
|
|
|
@ -17,7 +17,7 @@ import ser2neo
|
|||
|
||||
|
||||
def main():
|
||||
port = ser2neo.open_port('/dev/ttyUSB0')
|
||||
port = ser2neo.open_port()
|
||||
neo = ser2neo.NeoPixels(port)
|
||||
|
||||
p0 = 0
|
||||
|
|
100
neopixel.cc
100
neopixel.cc
|
@ -15,66 +15,82 @@
|
|||
// limitations under the License.
|
||||
//
|
||||
#include "neopixel.h"
|
||||
#include "serial.h"
|
||||
#include "chip.h"
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <string.h>
|
||||
#include <cstring>
|
||||
|
||||
#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.
|
||||
void NeoPixel::init() {
|
||||
DDRB |= _BV(1);
|
||||
TCCR0A = _BV(WGM01) | _BV(WGM00) | _BV(COM0B1) | _BV(COM0B0);
|
||||
TCCR0B = _BV(WGM02) | _BV(CS00);
|
||||
clear();
|
||||
|
||||
static_assert(Reload > 15, "Inter-bit time is probably too short.");
|
||||
OCR0A = Reload;
|
||||
OCR0B = Low;
|
||||
LPC_FMC->FLASHCFG = 0; // 1 wait state instead of 1
|
||||
|
||||
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.
|
||||
void NeoPixel::clear() {
|
||||
p_ = bits_;
|
||||
memset(bits_, Low, sizeof(bits_));
|
||||
p_ = bytes_;
|
||||
memset(bytes_, 0, sizeof(bytes_));
|
||||
}
|
||||
|
||||
/// Append a byte to the stream.
|
||||
void NeoPixel::append(uint8_t b) {
|
||||
if (p_ <= (bits_ + sizeof(bits_) - Tail - BitsPerColour)) {
|
||||
for (auto i = 0; i < BitsPerColour; i++) {
|
||||
*p_++ = (b & 0x80) ? High : Low;
|
||||
b <<= 1;
|
||||
}
|
||||
if (p_ <= (bytes_ + sizeof(bytes_))) {
|
||||
*p_++ = b;
|
||||
}
|
||||
}
|
||||
|
||||
void NeoPixel::send(uint16_t cmd) {
|
||||
while ((LPC_SPI0->STAT & SPI_STAT_TXRDY) == 0) {}
|
||||
LPC_SPI0->TXDAT = cmd;
|
||||
}
|
||||
|
||||
/// Write to the LEDs.
|
||||
void NeoPixel::write() {
|
||||
bits_[sizeof(bits_) - 1] = Stop;
|
||||
|
||||
uint8_t *p = bits_;
|
||||
uint8_t *pend = bits_ + sizeof(bits_);
|
||||
|
||||
cli();
|
||||
|
||||
OCR0B = Stop;
|
||||
TIFR |= _BV(OCF0A);
|
||||
while (!(TIFR & _BV(OCF0A))) {
|
||||
send(0);
|
||||
send(0);
|
||||
for (auto p = bytes_; p < bytes_ + sizeof(bytes_); p++) {
|
||||
auto ch = *p;
|
||||
send(bits_[ch >> 4]);
|
||||
send(bits_[ch & 0xF]);
|
||||
}
|
||||
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:
|
||||
static const int MaxLEDs = 16;
|
||||
|
||||
static const int BitsPerColour = 8;
|
||||
static const int ColoursPerLED = 3;
|
||||
static const int Tail = 2;
|
||||
|
||||
static const uint8_t Reload = F_CPU / 800000;
|
||||
static const uint8_t Low = Reload * 2 / 3;
|
||||
static const uint8_t High = Reload - Low;
|
||||
static const uint8_t Stop = 0xFF;
|
||||
void send(uint16_t ch);
|
||||
|
||||
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
|
||||
// limitations under the License.
|
||||
//
|
||||
#include <avr/interrupt.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "neopixel.h"
|
||||
|
@ -43,6 +42,22 @@ class Ser2Neo {
|
|||
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.
|
||||
void Ser2Neo::init() {
|
||||
leds.init();
|
||||
|
@ -96,8 +111,6 @@ void Ser2Neo::send_ok(const char* msg) {
|
|||
|
||||
/// Run the main loop. Process and run commands.
|
||||
void Ser2Neo::run() {
|
||||
sei();
|
||||
|
||||
serial.putstr("READY\n");
|
||||
|
||||
for (;;) {
|
||||
|
@ -123,11 +136,11 @@ void Ser2Neo::run() {
|
|||
}
|
||||
}
|
||||
|
||||
static Ser2Neo ser2led;
|
||||
static Ser2Neo ser2neo;
|
||||
|
||||
int main() {
|
||||
ser2led.init();
|
||||
ser2led.run();
|
||||
ser2neo.init();
|
||||
ser2neo.run();
|
||||
|
||||
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.
|
||||
//
|
||||
|
@ -16,107 +16,32 @@
|
|||
//
|
||||
#include "serial.h"
|
||||
|
||||
#include <avr/io.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)
|
||||
#include "board.h"
|
||||
|
||||
/// Initialise the hardware.
|
||||
void Serial::init() {
|
||||
state_ = Idle;
|
||||
rx_full_ = false;
|
||||
Chip_UART_Init(LPC_USART0);
|
||||
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.
|
||||
_set(DDRB, TxPin);
|
||||
_set(PORTB, TxPin);
|
||||
_clear(DDRB, RxPin);
|
||||
UART_CONFIG_T cfg = {
|
||||
.sys_clk_in_hz = CONFIG_SYS_FREQ / ClockDiv,
|
||||
.baudrate_in_hz = 115200,
|
||||
.config = 1,
|
||||
.sync_mod = 0,
|
||||
.error_en = NO_ERR_EN,
|
||||
};
|
||||
|
||||
// Set up the timer.
|
||||
static_assert(BitTime > 50, "BitTime is too short");
|
||||
static_assert(BitTime < 255*2/3, "BitTime may overflow");
|
||||
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);
|
||||
}
|
||||
auto frg = LPC_UARTD_API->uart_init(handle_, &cfg);
|
||||
Chip_SYSCTL_SetUSARTFRGDivider(0xFF);
|
||||
Chip_SYSCTL_SetUSARTFRGMultiplier(frg);
|
||||
}
|
||||
|
||||
/// Wait until the hardware is free then start the transmit.
|
||||
void Serial::putch(uint8_t ch) {
|
||||
while (state_ != Idle) {
|
||||
sleep_cpu();
|
||||
}
|
||||
state_ = Transmit;
|
||||
txing_ = (ch << 1) | 0xFE00;
|
||||
bits_ = 10;
|
||||
|
||||
TCNT1 = 0;
|
||||
_set(TIMSK, TOV1);
|
||||
LPC_UARTD_API->uart_put_char(handle_, ch);
|
||||
}
|
||||
|
||||
/// Send a string.
|
||||
|
@ -128,18 +53,5 @@ void Serial::putstr(const char* str) {
|
|||
|
||||
/// Wait until a character is received, then return it.
|
||||
uint8_t Serial::getch() {
|
||||
while (!rx_full_) {
|
||||
sleep_cpu();
|
||||
}
|
||||
uint8_t ch = rxed_;
|
||||
rx_full_ = false;
|
||||
return ch;
|
||||
return LPC_UARTD_API->uart_get_char(handle_);
|
||||
}
|
||||
|
||||
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(); }
|
||||
|
|
47
serial.h
47
serial.h
|
@ -1,4 +1,4 @@
|
|||
// Half-duplex interrupt based serial port.
|
||||
// Blocking serial port.
|
||||
//
|
||||
// Copyright 2015 Google Inc.
|
||||
//
|
||||
|
@ -18,9 +18,9 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
/// Half-duplex interrupt based serial port.
|
||||
///
|
||||
/// Loosely based on AVR304.
|
||||
#include "chip.h"
|
||||
|
||||
/// Blocking serial port.
|
||||
///
|
||||
class Serial {
|
||||
public:
|
||||
|
@ -32,41 +32,8 @@ class Serial {
|
|||
uint8_t getch();
|
||||
|
||||
private:
|
||||
enum State : uint8_t {
|
||||
Idle,
|
||||
Receive,
|
||||
Transmit,
|
||||
};
|
||||
static const int ClockDiv = 1;
|
||||
|
||||
// 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();
|
||||
uint32_t mem_[40 / sizeof(uint32_t)];
|
||||
UART_HANDLE_T* handle_;
|
||||
};
|
||||
|
|
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