Introduction

 

All art movements used to have manifestos, at least the more radical ones at the start of the

twentieth century did, so I thought I'd do one for electronic art where the manifesto was, itself, an

artwork. The main art influence for the text of this was a piece written by the American artist Claus

Oldenburg in 1961 called "I'm for an art...", but of course his was much better.

 

The Work

 

Here are a couple of pictures of it on the wall of my workroom.

 

 

The following video shows it working.

 

 

Here's one display running for a while so you can get a flavour of the manifesto

 

 

It would be interesting, in a gallery setting, to see just how long viewers stood in front of it

reading the text before they got bored and wandered off.

 

The Technical Stuff

 

I had to decide how I was going to present the text of the manifesto. My first thought was an LED

moving-message style display, but decided that would be too much work to construct in a week and would

blow my whole budget (with seven pieces still to do), so, slightly reluctantly, I settled on a LCD

character display. But a single display didn't seem quite right, so I decided to have three displays

all runnning in parallel to add some complexity to the work (after the last slice of pi, I'm bored of

minimalism already). Why three? I've often thought that good 'rules of thumb' for art are to avoid

hard symmetry, unless you're really, really good, and given a choice between an odd number and an even

one, pick the odd one (or even better a prime).

 

To keep the wiring down and to make the code easier, I chose some Winstar 16x2 displays (WH1602B3-

SLL-JWV) which have an I2C interface. I'm hoping I can address them on one bus. The datasheet, in

time-honoured tradition for LCD panels, is all a bit vague and ambiguous suggesting that there is a

choice of four addresses that can be selected but leaving off from the pin-out any indication of where

to find the pins to do it.

 

Here are my starting materials. A Pi 3 B+, three LCDs, and a canvas.

 

 

Before I worry about the art stuff, I need to get the Pi talking to the displays on the bench and get

the code sorted out.

 

What seemed like it would be the easiest part turned out to be the hardest. You'd think that something

sold as having an I2C interface would be simple to connect to, but this quickly turned into being a

'hack your own display' type exercise. Not just for how to do the physical interface connections

without blowing up the panel in the process, but also how on earth to send the right commands to make

it present some text on the panel. The problem is that this is a variant of a board that can also be

configured (by them, with 0-ohm links) to be a parallel interface or an SPI one and they've left bits

and pieces of all of them in the datasheet, including a recommended circuit that would apply to SPI

and not I2C. They've hacked their own datasheet and I've got the fun job of deciphering it.

It looks like there's an on-board generator for a negative supply for the LCD voltage and the voltage

comes out on pin 15. Sometimes that pin is used for the anodes of the backlight LEDs, so I'm going to

have to be cautious - the voltage inverter won't be too happy if I short its output to something else.

 

Here's the panel with a 5.1V supply connected to pins 1 (GND) and 2 (+5V) and you can see from the

meter that the panel generates -5.1V on pin 15.

 

 

That's being done by the small 8-pin package that you can see on the back of the board and the two

tants. That -5V will have go to one end of a trimmer pot, with +5V at the other end, and the slider

going to the Vo supply input in order to bias the panel and adjust the contrast. The LCD part of the

panel works relative to the +5V supply, so the trimmer slider will be slightly negative to give the

recommended voltage for the LCD supply.

 

Although the pinout doesn't show the I2C address lines, they are mentioned later in the text which

also identifies the clock and data pins which are the other way round to those on the datasheet pinout

(which are for SPI). So next I'm going to connect the panel as I think the interface should go and see

if the Pi can talk to it and get acknowledges back. I'm going to leave the backlight for now and come

back to it at the end.

 

To work out where to connect it to on the Pi expansion header, I'm using this drawing. It's part of

the reduced schematic for the Pi from the Raspberry Pi website. That shows the power pins and the I2C

connections, which is all I need this time round. Although the Pi IO operates on 3.3V and the LCD on

5V, with the SDA and SCL lines I should be ok just connecting them together as the pull-ups are on the

Pi side of things.

 

You'd think the software side of driving I2C on a Pi would be very easy, but all the information about

it is very confusing so this just represents the point I've reached with it and shouldn't be taken as

a how-to tutorial.

 

It seems that the actual low-level code to drive the I2C is built into the kernal as it gets used to

control devices in the system under the guise of SMBus. To reach it from Python we need something to

include in the code that allows us to talk to those routines. Many examples on the web use python-

smbus, which is a separate C module. That needs to be installed - Python couldn't find it when I tried

including it.

 

After a bit of searching, I came across these bindings as an alternative

 

https://github.com/kplindegaard/smbus2

 

unlike the smbus module, where the bindings are done with separate C code, this is done with pure

Python. That makes it easier for me to install on my headless Pi because I can just copy the file that

does the work across the network from a laptop to my home directory on the Pi.

 

After a bit of fiddling about, I got these waveforms on the SDA and SCL lines. That shows the Pi

sending a command (3 bytes in total) to the LCD. I don't have a visible display yet, however you can

see that the panel is responding by the ack at the end of each byte being sent (the ack is slightly

raised up in the air because the MOSFET on the panel is a bit weedy - it's fine for an ack, though: if

the Pi didn't like it, it would stop at that point and not do the rest).

 

 

It also means I'm ok with the Pi's 3.3V pull-ups on the I2C driving the +5V panel.

 

I was very unsure about the backlighting. The usual anode connection is missing as it's been replaced

by the LCD bias voltage. Measuring with a meter, it turned out that the anodes had the +5V supply on

them, so the intention is obviously to put the current limiting resistor in series with the cathode

connnection to pin 16, rather than take it straight to ground. That works ok and, after adjusting the

contrast pot, I can now see a single character that I've written to the display.

 

Here it is. The displayed digit is a bit dim because I was being very cautious and the LED current is

limited to about 9mA. I've now got it counting from 0 to 9 at one second intervals, so the panel is

working reliably.

 

 

This is how I've wired it to the Pi 3 B+.

 

 

Notes:
1) this applies only to the B3 variant (I2C-only interface);
2) Vee is a -5V output from the panel that's generated from the Vdd supply. Don't connect it to

anything other than the contrast trimmer pot;
3) SA0 and SA1 set the LSBs of the I2C address. The circuit above gives a slave address of 0x3C;
4) The backlight resistor is for 60mA;
5) The panel is write-only. The only thing that comes back is the ack. That means there's no 'busy

bit' to test and the sending end has to ensure that there's time for the panel to complete a command

before sending the next.

 

Next job is to leave the software for a moment and wire up the other two panels. Then I can check that

the addressing works. At that point I'll have enough to work with to do the final code for the

artwork.

 

I've now wired up the three displays and the Pi. At this stage, I changed my mind about the canvas and

decided I would arrange it on an old off-cut of plywood. Not quite sure why. Might have had something

to do with looking at pictures of some early Robert Rauschenberg 'combine' pictures in a book at the

library.

 

That all seems fine. Here it is with the LCDs showing text. The addressing works and they can all be

written to individually - the individual digit on the bottom row is the display address.

 

 

I've put the manifesto text in a text file, so that it can be changed easily. That gets read at the

start into a list of strings. The software has an index for each display to keep track of which string

is being displayed, an index for the next string, and an index for position along the line. It reads

16 characters and uses the ord() function to turn them into ASCII for sending to the panel. Trickiest

part was running over the join between the current string and the next string. I was very confused

about the string handling at first, but once I realised that strings and lists can be treated as

though they were arrays and indexed I was fine with it.

 

Here's the code as it stands at the moment. It's not good code, there is no exception processing,

testing of bounds, or any of the defensive coding you'd do for something that has to be robust and

work every time, but it will do for what is essentially me hacking art together.

 

import time
import random
from smbus2 import SMBus
# start off with some sensible values in the various variables
currentString = [1,2,3]
nextString = [4,5,6]
currentPos = [0,0,0]
# fetch the whole manifesto from a text file
with open("manifesto.txt","r") as fileHandle: #open the file
  manifestoStrings = fileHandle.readlines() #read all the lines as strings
# initialise the LCD panels
# and write the static first line
bus = SMBus(1)
firstLineString = "---MANIFESTO----"
displayBuffer = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
for i in range (0, 16):
  displayBuffer[i] = ord(firstLineString[i])
for display in range(0, 3):
  bus.write_i2c_block_data(0x3C + display, 0x00, [0x3C])
  time.sleep(0.015)
  bus.write_i2c_block_data(0x3C + display, 0x00, [0x0C])
  time.sleep(0.001)
  bus.write_i2c_block_data(0x3C + display, 0x00, [0x01])
  time.sleep(0.001)
  bus.write_i2c_block_data(0x3C + display, 0x00, [0x06])
  time.sleep(0.01)
  bus.write_i2c_block_data(0x3C + display, 0x00, [0x80])
  bus.write_i2c_block_data(0x3C + display, 0x40, displayBuffer)
# this loop processes part of the current string into a temporary display buffer
# and sends the result to the LCD panel
# repeats for each of the three panels
# updates current position and, if off end, deals with getting a new next string
while True:
  #wait for half a second
  time.sleep(0.3)
  #now for each LCD display get string data and send to panel
  for display in range(0, 3):
    if currentPos[display] <= (len(manifestoStrings[currentString[display]]) - 18):
      for i in range (0, 16):
        displayBuffer[i] = ord(manifestoStrings[currentString[display]][currentPos[display] + i])
    else:
      j = (len(manifestoStrings[currentString[display]]) - 2) - currentPos[display]
      for i in range (0, j):
        displayBuffer[i] = ord(manifestoStrings[currentString[display]][currentPos[display] + i])
      for i in range (0, 16-j):
        displayBuffer[i + j] = ord(manifestoStrings[nextString[display]][i])
    bus.write_i2c_block_data(0x3C + display, 0x00, [0xC0])
    bus.write_i2c_block_data(0x3C + display, 0x40, displayBuffer)
    # update current position
    currentPos[display] = currentPos[display] + 1
    # and if off end of string, move next to current and randomly choose another next
    if currentPos[display] >= (len(manifestoStrings[currentString[display]]) - 2):
      currentPos[display] = 0
      currentString[display] = nextString[display]
      while nextString[display] == currentString[display]:
        nextString[display] = random.randint(0, len(manifestoStrings)-2)

 

I'm not particularly satisfied with the way it turned out - the character displays aren't ideal for

the application and the lettering on the board needs to be more prominent - but I don't have time for any more work

on it for now, so this is it as far as PiCasso is concerned.

 

Now I'm even further behind the one-a-week schedule. Oh well, ever onwards! Slice 3 next.

 

Note for the judges: I'm following along with this Design Challenge as an independent participant, not as a challenger. I'm

not entering the competition for the prizes.