Skip to content

Commit

Permalink
Merge branch 'feature/ws2811-usb' into raspi
Browse files Browse the repository at this point in the history
  • Loading branch information
kcuzner committed Dec 16, 2018
2 parents beb347b + 0070db1 commit af87ff3
Show file tree
Hide file tree
Showing 27 changed files with 9,391 additions and 0 deletions.
5 changes: 5 additions & 0 deletions kl2-ws2811/.gitignore
@@ -0,0 +1,5 @@
bin
obj

.gdb_history

164 changes: 164 additions & 0 deletions kl2-ws2811/Makefile
@@ -0,0 +1,164 @@
# Makefile for the KL26-based WS2811 USB dongle
#
# Kevin Cuzner
#

PROJECT = kl2-ws2811

# Project target
CPU = cortex-m0plus

# Source
SRCDIRS = src
GENSRCDIRS = src
BINDIR = bin
OBJDIR = obj
GENDIR = obj/gen
INCDIRS = include
LDINCDIRS =
CSRCDIRS = $(SRCDIRS)
SSRCDIRS = $(SRCDIRS)
SRC = $(foreach DIR,$(CSRCDIRS),$(wildcard $(DIR)/*.c))
GENSRC = $(foreach DIR,$(GENSRCDIRS),$(wildcard $(DIR)/*.c))
STORAGESRC = $(foreach DIR,$(CSRCDIRS),$(wildcard $(DIR)/*.storage.xml))
ASM = $(foreach DIR,$(SSRCDIRS),$(wildcard $(DIR)/*.s))


# Include directories
INCLUDE = $(foreach DIR,$(INCDIRS),-I$(DIR)) -I$(GENDIR) -I.
LDINCLUDE = $(foreach DIR,$(LDINCDIRS),-L$(DIR))

# Linker
LSCRIPT = kl2-dev.ld

# C Flags
GCFLAGS = -std=gnu99 -Wall -fno-common -mthumb -mcpu=$(CPU) -DSTM32F103xB --specs=nosys.specs -g -Wa,-ahlms=$(addprefix $(OBJDIR)/,$(notdir $(<:.c=.lst))) -O3
GCFLAGS += $(INCLUDE) -DUSB_DEBUG
CFLAGS += $(GCFLAGS)
LDFLAGS += -T$(LSCRIPT) -mthumb -mcpu=$(CPU) -Wl,-Map,$(BINDIR)/$(PROJECT).map -nostartfiles
LDFLAGS += $(LDINCLUDE)
ASFLAGS += -mcpu=$(CPU)

# Flashing
OCDFLAGS = -f openocd/openocd.cfg

# Tools
CC = arm-none-eabi-gcc
AS = arm-none-eabi-as
AR = arm-none-eabi-ar
LD = arm-none-eabi-ld
OBJCOPY = arm-none-eabi-objcopy
SIZE = arm-none-eabi-size --format=SysV
OBJDUMP = arm-none-eabi-objdump
OCD = openocd
GDB = arm-none-eabi-gdb

RM = rm -rf

# Code Generation
PYTHON = python3
SCRIPTDIR = ./scripts
DESCRIPTORGEN = $(PYTHON) $(SCRIPTDIR)/descriptorgen.py

GENERATE =


#
# Build Targets
#

all:: $(BINDIR)/$(PROJECT).bin $(BINDIR)/$(PROJECT).hex

install: $(BINDIR)/$(PROJECT).bin $(BINDIR)/openocd.pid
cat openocd/flash.cfg | nc localhost 4444

macros:
$(CC) $(GCFLAGS) -dM -E - < /dev/null

cleanBuild: clean

clean: stop
$(RM) $(BINDIR)
$(RM) $(OBJDIR)

size:
$(SIZE) $(BINDIR)/$(PROJECT).elf

#
# Debug
#

start: $(BINDIR)/openocd.pid

stop:
-echo shutdown | nc localhost 4444

$(BINDIR)/openocd.pid:
openocd/run-openocd-server.sh $(OCD) $@

gdb:
$(GDB) -ex "target remote alarmpi:3333" $(BINDIR)/$(PROJECT).elf

## Build process

GENERATE_USB_DESCRIPTOR=USB_DESCRIPTOR
GENERATE_USB_DESCRIPTOR_SRC=_gen_usb_desc.c
GENERATE_USB_DESCRIPTOR_HDR=_gen_usb_desc.h

OBJ := $(addprefix $(OBJDIR)/,$(notdir $(SRC:.c=.o)))
OBJ += $(addprefix $(OBJDIR)/,$(notdir $(ASM:.s=.o)))
ifneq ($(filter $(GENERATE), $(GENERATE_USB_DESCRIPTOR)),)
GEN_OBJ += $(GENDIR)/$(GENERATE_USB_DESCRIPTOR_SRC:.c=.o)
GEN_TARGETS += $(GENERATE_USB_DESCRIPTOR)
endif
ALL_OBJ := $(OBJ) $(GEN_OBJ)
DEP := $(addprefix $(OBJDIR)/,$(notdir $(SRC:.c=.d)))

#
# Code generation
#
$(GENERATE_USB_DESCRIPTOR):
@mkdir -p $(GENDIR)
$(DESCRIPTORGEN) -os $(GENDIR)/$(GENERATE_USB_DESCRIPTOR_SRC) \
-oh $(GENDIR)/$(GENERATE_USB_DESCRIPTOR_HDR) \
$(GENSRC)


$(BINDIR)/$(PROJECT).hex: $(BINDIR)/$(PROJECT).elf
$(OBJCOPY) -R .stack -O ihex $(BINDIR)/$(PROJECT).elf $(BINDIR)/$(PROJECT).hex

$(BINDIR)/$(PROJECT).bin: $(BINDIR)/$(PROJECT).elf
$(OBJCOPY) -R .stack -O binary $(BINDIR)/$(PROJECT).elf $(BINDIR)/$(PROJECT).bin

$(BINDIR)/$(PROJECT).elf: $(ALL_OBJ)
@mkdir -p $(dir $@)
$(CC) $(ALL_OBJ) $(LDFLAGS) -o $(BINDIR)/$(PROJECT).elf
$(OBJDUMP) -D $(BINDIR)/$(PROJECT).elf > $(BINDIR)/$(PROJECT).lst
$(SIZE) $(BINDIR)/$(PROJECT).elf


# Generates compilation rules for the directory in $1
#
# Note to self: The double-dollar sign escapes the $ so that it doesn't get
# evaluated when this function is generated, but instead gets evaluated when
# Make is actually making.
define build_gcc_rules
$$(OBJDIR)/%.o: $1/%.c Makefile
@mkdir -p $$(dir $$@)
$$(CC) $$(GCFLAGS) -MMD -c $$< -o $$@
endef
define build_asm_rules
$$(OBJDIR)/%.o: $1/%.s Makefile
@mkdir -p $$(dir $$@)
$$(AS) $$(ASFLAGS) -o $$@ $$<
endef

# Generate rules for each source directory
$(foreach DIR,$(CSRCDIRS),$(eval $(call build_gcc_rules,$(DIR))))
$(foreach DIR,$(SSRCDIRS),$(eval $(call build_asm_rules,$(DIR))))

-include $(DEP)

# Ensure generated objects get run first
$(OBJ): | $(GEN_TARGETS)

118 changes: 118 additions & 0 deletions kl2-ws2811/README.md
@@ -0,0 +1,118 @@
# WS2811 USB Dongle

This is USB dongle firmware specifically built for the christmas tree project. I
originally was going to make a nice general dongle, but both my motivation and
time ran out. Instead, I am going to use my
[kl2-dev](https://github.com/kcuzner/kl2-dev) board with this firmware. The
raspberry pi will be used to flash it, although I cannot actually compile the
program on the raspberry pi with archlinuxarm, since the package is missing and
I don't feel like waiting hours and hours to compile arm-none-eabi-gcc.

## Hardware Specifics

The kl2-dev dongle has the following hardware:

- MKL26Z32VRM4 Kinetis KL26 microcontroller
- A USB port (micro usb)
- Every I/O broken out into a pin

## Feature List

- USB Driver ported from my STM32 adventures.
- USB Descriptor Generation ported from the midi-fader project (WIP)
- Custom protocol (for use with libusb) (WIP)

## Building

### Environment

This project should live on the raspberry pi. The raspberry pi needs to have NFS
or some other file sharing set up to a standard x86 desktop.

### Prerequisites - Raspberry Pi

- `make`
- `openocd`

### Prerequisites - Desktop PC

- `arm-none-eabi-gcc`
- `arm-none-eabi-binutils`
- `python3`

### Build

On the desktop PC, execute the following to build the firmware:

```
$ make
```

### Installation

On the raspberry pi, execute the following to install the firmware

```
$ make install
```

This will start an openocd server which will persist. To shut down this server,
run:

```
$ make stop
```

### Debug

After installation, an openocd server will be running. The makefile should be
configured with the hostname of the raspberry pi. The following command should
be executed on the desktop PC. Unlike my other projects, it will not
automatically start the openocd server.

```
$ make gdb
```

## Theory of Operation

This is meant to be a very simple device. It essentially provides a buffer that
will be dumped into the WS2811 chain as bytes are received. The device has no
knowledge of the topology of the LEDs and will blindly dump data into the chain.

Data is received over USB and dumped into the chain as soon as it is received.
Once a transfer ends or if there is a data underflow, the device will cease
dumping data into the buffer until the next transfer begins.

The performance goal of this project is that I can dump enough data for 50 LEDs
into the device every 16ms or so.

## Protocol

The protocol is very simple. There are no additional setup requests beyond the
standard USB ones and there are no additional descriptors.

In order to change the color of the LEDs (including turning them off), the host
PC should initiate a bulk write to Endpoint 1. The data shall have the following
format:

```
Byte 0: Red value for the first LED in the chain
Byte 1: Green value for the first LED in the chain
Byte 2: Blue value for the first LED in the chain
Byte 3: Red value for the second LED in the chain
Byte 4: Blue value for the second LED in the chain
Byte 5: Green value for the second LED in the chain
Byte 6: Red for ...
...
```

Each byte triple is for one LED, starting with the LED nearest to the
microcontroller. The number of bytes written must be a multiple of three. If the
bulk transfer has a length which is not a multiple of three, a STALL condition
results although the data up to the last byte triple will be pushed out to the
LEDs.

In the interest of keeping things simple, there is no reporting of whether or
not there is a data underflow.

0 comments on commit af87ff3

Please sign in to comment.