# To Dream of Magick

## Programming a Neopixel Pride Flag

Savanni D'Gerinel 8 Jul, 2018

Some weeks ago, I had an instance in which I was planning to do in person volunteer recruitment for Freedom for All Massachusetts. Now, this is very different from canvassing, as I found out about when I was at Pride. There is no “hide your politics for a bit because we need accurate information”, this is “assume everyone you talk to is on our side because we’re trying to recruit them to help us”.

So, what better way for me to show my pride, and be a techie, than to have a batch of LEDs rotating between the pride flags that I care most about?

Enter neopixels and an ATTiny86, in the form of an Adafruit Trinket. This is my first significant hardware project that involves both wiring and programming.

I started out with a neopixel RGBW jewel, but I was never able to get the signalling to work. Lacking any better ideas, I dropped back to a bunch of 8mm through-hole RGB neopixels and programmed for that. More on the problem later, but I think the programming library I was using does not actually signal RGBW neopixels correctly.

While it took a great many hours, mostly in setting up my environment and then getting the hang of very low level C programming, I did eventually succeed. But on a breadboard with long jumper wires. Still, proof of concept, and I’ll get a neopixel RGB jewel later to finish out the project.

All of the code for this project is in the pride-trinket github project.

# AVR Builds

First, I need a build environment. I am not using Adafruit’s development environment because I expect to pretty quickly go beyond the idea of a single tiny microcontroller, a microcontroller that Adafruit packaged and shipped. I’m already planning to go beyond Adafruit’s offerings, though their products are very nice.

For every AVR project, you need three things:

• AVR binutils
• Libc built for AVR
• A GCC that targets AVR

I discovered bugs in the libc and GCC builds in my Nix repository, so I patched against those bugs and then repackaged all three packages for safety.

avrbinutils has warnings that cause the build to error, so I replaced the build line.

  src = fetchurl {
url = "mirror://gnu/binutils/binutils-${version}.tar.bz2"; sha256 = "028cklfqaab24glva1ks2aqa1zxa6w6xmc8q34zs1sb7h22dxspg"; }; configureFlags = "--target=avr --enable-languages=c,c++ --disable-werror"; meta = with stdenv.lib; {  GCC needed a change to be able to find avrbinutils. I glue it all together with a rather pedantic shell.nix.  avrbinutils = import nixpkgs/avr/binutils { stdenv = pkgs.stdenv; fetchurl = pkgs.fetchurl; }; avrgcc = import nixpkgs/avr/gcc { stdenv = pkgs.stdenv; fetchurl = pkgs.fetchurl; gmp = pkgs.gmp; mpfr = pkgs.mpfr; libmpc = pkgs.libmpc; zlib = pkgs.zlib; avrbinutils = avrbinutils; texinfo = pkgs.texinfo; }; libc = import nixpkgs/avr/libc { stdenv = pkgs.stdenv; fetchurl = pkgs.fetchurl; avrgcc = avrgcc; avrbinutils = avrbinutils; automake = pkgs.automake; autoconf = pkgs.autoconf; }; ... buildInputs = [ avrbinutils avrgcc libc pkgs.avrdude ws2812.ws2812_avr ];  To get this working, I spent many hours trying to figure out why the libc libraries weren’t showing up in my path. I no longer remember searches that I used to find what I needed, but I eventually added a setup-hook.sh to my libc build. That script adds include paths and library paths to NIX_CFLAGS_COMPILE and NIX_LDFLAGS for each library directory under <libc>/avr/lib/. I do not have a GCC wrapper working in my environment, so I had to modify my project Makefile to explicitely include these environment variables. ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)$(NIX_CFLAGS_COMPILE) \$(NIX_LDFLAGS)


I copied my base Makefile from the neopixel_i2c project, which I have used in previous experiments that involved an embedded Linux system.

One final element, the crtattiny85.o file, is missing. That file is found in in avrlibc hierarchy at <libc>/avr/lib/avr25/crtattiny85.o. I have no idea how the compiler knows that it wants that file in paricular, so I have not determined what environment variables I could use to tell the compiler where to find it. Instead, and somewhat out of laziness, I just copied the file into my working directory.

This gives me a working compiler!

If you want to use the environment, try pulling the shell.nix file and the avr directory. If you are not doing a neopixel project, you can leave out the ws2812 derivation, as that is a packaging of the library that handles neopixel signalling.

# WS2812

WS2812 refers to the onboard controller that neopixels use. Neopixels may look like LEDs, but they are actually clusters of LEDs with their own processor and power distribution. The control protocol works by sending precisely timed signals down the wire, one trio of signals per pixel, followed by a long time at logical 0. Each pixel captures the first three signals it receives and sends all remaining signals down the wire until the long logical 0 indicates that the entire message is done.

The neopixel ws2812 library includes clever assembly code that implements the timing based on an 800kHz clock.

I first worked with the library as I was learning to work with the neopixel_i2c library. However, I did not want to use git submodules. Instead, I decided to package this as a Nix derivation, including any patches that I wanted to include.

In this case, I had to build the derivation from scratch as I had no template to start with. Fortunately, I have the hang of building libraries, but I still provide a setup-hook file to set a convenient WS2812_PATH environment variable and a patch to the Makefile to depend on NIX_CFLAGS_COMPILE and NIX_LDFLAGS.

My derivation file provides both light-ws2812-source and the ws2812_avr library as separate derivations. The library actually provides code for multiple environments, but ws2812_avr is the only one I currently build.

While this is a “library”, it is unusual in the same way as libc in that my only target is a .o file, not a .so or .a. Like with the crtattiny85.o file, I manually copy the light_ws2812.o file into my project.

# Some Hardware

This is where the fun happens. For this project, I have:

I have standardized my wire colors on this project as RED for 5V power, BLUE for ground, and YELLOW for data. Since Neopixels are 5V driven, I made sure to use a 5V Trinket. Watch out for that, as I don’t know what would happen if you tried to use a 3.3V trinket with the pixels.

The Trinket accepts main power on the USB wire. The underside of the Trinket has pads to which one could attach incoming power, also. Importantly, the 5V pin and the GND pin on he sides of Trinket are for the Trinket to provide power to any attached hardware, not for the Trinket to receive power. Fortunately, I did not destroy anything before I understood this.

I use Pin #3 on the Trinket as the data line. This pin number is hard-coded in the ws2812 library. You can change it by patching ws2812_pin in ws2812_config.h. If you wanted to do this, I recommend a patch that you provide in the patches phase of your derivation.

On this project I have only the single yellow wire because I carefully ensured that the data pins chain to one another. These particular pixels made that convenient by putting the data in and data out pins on the edge of the pixels with the power pins in the center.

The wiring is important. When you power the Trinket on for the first time, keep a finger near it and pull power as fast as you can if you feel heat. I made a mistake in my wire colors at first and accidentally shorted the Trinket’s power to ground. Fortunately, I noticed and pulled power before anything exploded.

When you apply power, all of the pixels will go to a random state while the Trinket boots up. While I don’t know the details of how to fix that, I suspect a pull-down resistor on the data line would help.

After a few seconds, though, the Trinket will start running the program. In my case, the program just runs forever, transitioning from one pride flag to the next in a loop. I get visible flicker in the pixels, which I suspect I could alleviate with capacitors on the inputs. Some folks have recommended 1uF capacitors, but said that 10uF, while overkill, would do the job.

# Programming

Brush up your C, as this is low-level programming. Nevertheless, it is an odd combination of fun and frustrating. Remember, you have no debugging tools on the Trinket.

ws2812 provides a cRGB convenience data structure and a function, ws2812_setleds function which accepts a struct cRGB *ledarray. I had not done any C programming in quite a long time, so I completely missed that struct cRGB *ledarray is a standard C way of describing struct cRGB ledarray[x], where x is unknown. This means a single contiguous block of data, one cRGB after another.

Until I figured that out, I wrote all kinds of wrong code that mostly amounted to creating arrays of pointers to cRGB structures. Now, I create my pride flags as normal cRGB arrays, and happily pass them around as struct cRGB *.

const struct cRGB genderqueer_flag[LED_COUNT * 3] = {
{ .r = 128, .g = 0,     .b = 128 },
{ .r = 128, .g = 0,     .b = 128 },
{ .r = 128, .g = 128,   .b = 128 },
{ .r = 0,   .g = 128,   .b = 0 },
{ .r = 0,   .g = 128,   .b = 0 }
};


I wrote so many bugs that trial and error was insufficient, so I wrote in some conditional compilation logic that lets me run my application directly on my host machine. For the neopixel project, I needed in particular to provide my own _delay_ms function, declarations for uint8_t and uint16_t, and wrapper for ws2812_setleds. At the top of my program I have a conditional compilation block for initial declarations:

#if __HOST__
/* headers for the host machine */

typedef unsigned char uint8_t;
struct cRGB { uint8_t g; uint8_t r; uint8_t b; };

void _delay_ms(double ms) {
int ms_int = round(ms);
struct timeval delay = { .tv_sec = ms_int / 1000, .tv_usec = (ms_int % 1000) * 1000000 };
select(0, NULL, NULL, NULL, &delay);
}

#define uint8_t unsigned char
#define uint16_t unsigned short
#else
/* headers for the AVR */
#endif


In the body of my code, I provide write_leds as a wrapper around ws2812_setleds, though I realize now that I could have simply redeclared ws2812_setleds in the __HOST__ block at the start of the application.

void write_leds(const struct cRGB *leds, uint16_t count) {
#if __HOST__
for (int i = 0; i < count; i++) {
printf("\t{ %d, %d, %d }\n", leds[i].r, leds[i].g, leds[i].b);
}
#else
ws2812_setleds((struct cRGB *)leds, count);
#endif
}


The main body of my code is a simple state machine that I modeled as a machine that is either RESTING on a particular pattern or TRANSITIONING to another pattern. When transitioning I do a simple interpolation between my starting pattern and my ending pattern, so I am able to base the “current” pattern solely on the start, end, current frame number, and total number of frames.

struct state_s {
uint8_t current;
uint8_t frame_count;

const struct cRGB *start;
const struct cRGB *end;
};

uint8_t interpolate_color (uint8_t start, uint8_t end, uint8_t frame_count) {
uint8_t res = start + ((end - start) / TRANSITION_FRAMES * (frame_count + 1));
return res;
}


Finally, my state machine block is rather straightforward:

        switch (state.current) {
case RESTING:
_delay_ms(REST_TIME_MS);
state.current = TRANSITIONING;
break;
case TRANSITIONING:
if (state.frame_count < TRANSITION_FRAMES) {
/* code to calculate write the current pattern */
state.frame_count = state.frame_count + 1;
_delay_ms(TRANSITION_TIME_MS / TRANSITION_FRAMES);
} else {
state.current = RESTING;
}
break;
}


Glue it all together and I get a program that displays a pattern for five seconds, then fades to the next one over the course of five seconds.

The final step to actually try out all of the work is to flash the program onto the chip. My Makefile provides a main.hex file, which is the AVR image to be sent to the controller. I use avrdude to do the programming. I include in my repository a Trinket-friendly, macOS version of avrdude.conf.

Every time I try programming, I have to do it twice in a row. The first time always fails with a checksum error, and the second time succeeds. I have no idea why this happens, but I made a script that does it for me:

avrdude -c usbtiny -p attiny85 -U flash:w:main.hex
sleep 5
avrdude -c usbtiny -p attiny85 -D -U flash:w:main.hex


Note that the two avrdude commands differ. Just issuing the command with -D gives me one checksum error. Issuing the command with the -D gives a different checksum error. Issuing the two commands in this order… just works? Let me know if you know why and especially if you can tell me the correct way of running the command.

Making sure to use a data cable, plug the Trinket into a USB port. The Trinket seems to automatically go into programming mode if it detects a data cable, so just run the script above. When the programming is done, the Trinket should immediately start running the application!

# More things!

I still have more that I want to do. I want to get an RGB pixel jewel and wrap it into a wearable form. I want to add a bisexual pride flag. And I want to show it off!

And then I want to start on my Halloween costume. I have a Lapis Lazuli costume that I have wanted to make for years, and now I can add lights into the design. When I do this costume, instead of using a Trinket I want to drop down to a bare AtTiny85 so I can make the electronics as compact as possible.

But more than this, I want to do more work based on a Beagle Bone or other embedded Linux platform so I can use the i2c bus to link together sensors and lights with some logic. I have already done experiments with this and I am looking forward to figuring out how to mount sensors and lights on a piece of clothing.

# More references

## Mental Health Care and Transgender Populations

Savanni D'Gerinel 21 May, 2018
**Content Warning: open discussion of mental health care, suicide, and religion**

## Here’s why psychiatric hospitals are so bad at helping transgender patients

Amelia Perry was family to me. Four months later I get by only by forgetting that she’s gone.

Every day, on social media, I see people telling me and others like me that being transgender is a mental illness or that we need to “get help”. Fascinatingly, many of us get a lot of help if we can afford it. Many more would get help if they had the money to afford it, but transgender people outside of tech tend to be close to destitute, so I have no idea where they are expected to “get help”.

But let us for a moment say that money is no object and that we all can get help. We still cannot get care because care for mental health has been slashed so far that we have less space for psychiatric patients than we did before the Civil War. And, worse, practitioners are not being trained to deal with us, though our needs very modest and easy to honor, at least for human beings capable of listening and respecting other human beings. Further, medical practitioners are not only able to get away with refusing to treat us for ordinary medical problems, the Republican Party under Trump is pushing to ensure that it is legal everywhere to deny us service.

The people who tell me to “get help”, don’t actually want me to get help.

They want me to shut up and die.

## The Catholic Church is Morally Bankrupt

The Catholic church controls so many hopsitals that 1/6th of patients end up in a Catholic hospital.

The Church has rejected us.

The Catholic Church has invaded or blessed the invasions of native populations on every populated continent in the world. They have conducted wholesale torture over the course of a millenia. They have hidden the ways in which priests abuse and rape parishioners. They accuse us of “ideological colonization”, but we have never murdered anyone, much less entire populations, to push our ideology. We have simply tried to protect our people from harm and live normal lives in a society in which we face violent hatred.

Here are some examples of medical malpractice against transgender people, and these are simply a small number that made it into the news:

I also know at least one transgender woman who went into the hospital with broken bones after a car crash and reports that the staff stopped treaoting her as soon as they found out she was trans. They discharged her with pain medications, and she now lives with permanent pain.

If your “right” to practice your faith ends the life of human beings you are honor-bound to serve, you have committed murder, no matter the tools you used or the legality of the situation.

You who want me to shut up and die can fuck right off.

FUCK OFF.

Remember Amelia.

• Please email me if you know the original creator of the resistance fist logo and the transgender variant. I would like to provide proper credit.

## Family, Queerness, and Polyamory

Savanni D'Gerinel 14 Feb, 2018

This day, the feast of St. Valentine (or whatever), is a day for lovers to get together for nice dinner, romantic dates, and possibly some great sex. I generally find it to be a rather gross mix of cisgender, heteronormative performance and unspoken expectation, in which mind reading is a required skill.

So, what happens in queer communities in which most people involved have multiple partners and lovers?

In poly circles, this usually leads to very extensive use of calendars and negotiations. or a lot of group dates. On a normal year, I would probably spend V-day itself with Daria, and then designate another day that I would spend with Cait and Leah. In that sense, this year is no different than others, except in that Daria and I are mourning, not celebrating.

Like I told most people a few months before I moved, I moved to Boston to be with Cait and Leah.

I also moved to be with Daria, Aria, and as it turns out, Julia, Jess, Amelia, Ezri, Georgia, and others. Some of these folks I knew in advance, others I met shortly after coming here. The Cambridge/Somerville area has a magical grouping in which a huge number of queer polyamorous folks who exist in a constant state of organic community, meeting and parting in ways that create a deep set of connections between us that cannot be tracked or easily described, but which form a large extended family.

For so many in the Camberville queer community (and, I, presume, the queer communities of other large cities), emphasis on consent and negotiation has created a group that has become incredibly affectionate in both sexual and non-sexual ways. We foster extremely safe spaces, and in that safety affection has been able to grow. Those who cannot deal with touch know that they will not be touched. Asexuals will not be pursued. Sexual relationships will be expected to be conducted with respect and consent. And mistakes… well, we even have room for those and informal means of alleviating harm.

When I moved, I knew that moving to be with my girlfriends would not suffice. I needed community, and I got a large extended family.

For the record, Cait, Leah, Daria, and I will be going to dinner somewhere that does not take reservations, so a litle finger-crossing is in order.

## Remembering Amelia

Savanni D'Gerinel 7 Feb, 2018

Tonight, I want to tell you about a dear friend. Someone very important to myself and to my partner, Daria.

Hir name was Amelia. Ze took hir own life late in the night last Tuesday. I found out as soon as I woke up Wednesday morning. A week ago today.

Amelia was gorgeous. Ze was brilliant. Ze sparkled, flirted, brightened spaces, tied innuendo into unexpected sentences, and could talk about advanced mathematics that I cannot begin to understand.

But, honestly, we never talked about advanced math or technology. Amelia was passionate about social justice. Ze came into our community during a chance run-in at a march in solidarity for immigrant’s rights. Late in hir life, ze started campaigning for patient’s rights in mental health. This hyper focus came about from continuous failures in her stays in various psych wards here in Boston. Some of these failures caused significant harm.

Make no mistake. While Amelia may have died at hir own hand, ze was driven to it. Multiple assaults from random men on the street who continue to feel liberty in how they treat women, followed by hospitalizations that dehumanized hir, ignored hir, and in some cases, did significantly more harm.

I miss my friend.

I miss a friendship lost.

I regret the tensions between us, the things we did not have time to heal.

The day we all found out, the morning after Amelia died, seventeen people gathered for an impromptu wake.

Let that sink in. Seventeen people dropped everything to gather, weep, and reminisce, with no advance notice. Queer community is not large, but it is tightly connected and our members are loved. To quote my friend Aria:

Queer culture is grieving as a family no outsider would recognize, a haphazard landslide of lovers & friends. The ones who bring the tequila & gin, the ones who bring the casseroles, the ones who bring the cookies and apologize about the butter, the ones who make a big thai curry

While we can never change what outsiders would see, I want very much to change the definition of “outsider”. While I always live visibly, I have not in the past put much effort into broadcasting that image, and it thus became possible for people ostensibly in my life to completely ignore that which they did not see. But that means that, should I die, there are many people who would have to learn about the full me only through pictures and stories. If they learn at all. Perhaps they would actively ignore.

For now, however, I want to actively try to show what a happy, healthy life outside of the norm of cisgender, heterosexual, monogamy looks like.

## Memoru Amelia

Savanni D'Gerinel 7 Feb, 2018

Memoru Amelia

Dreamer, Shaper, Seeker, Maker