Paris Electronic Week Synth Workshop

Making a simple FPGA video synth for PEW 2023 at Villette Makerz. It takes audio in and generates patterns based on the voltage threshold and the 9 keys being pressed.

The code is here : https://github.com/merlinmarrs/iCE40HX-verilog-video-patterns

This time the top interface side has only buttons and no electronics. I have a simplified VGA out and HDMI with the correct LVDS resistor setup this time. I am relying on raspberry pi or arduino for programming.

Trying a grid ground pour on the Stop layer :

Found a site called OpenCores (https://opencores.org) that has free FPGA IP like math libraries.

Here are some tests with cool looking patterns :

Because dividing, trig functions, etc. aren’t supported by default, the most promising is the bitwise boolean logic operating on the entire vector :

wire[11:0] bit_or;
assign bit_or = h_count[11:0] | v_count[11:0];

[...]

if (bit_or[5] == 1 | bit_or[3] == 0) begin
wire[11:0] bit_xor;
assign bit_xor = h_count[11:0]^v_count[11:0];

[...]

if (bit_xor[2] == 1 | bit_xor[4] == 1) begin
wire[11:0] bit_and;
assign bit_and = h_count[11:0]&v_count[11:0];

...

if (bit_and[6] == 1 | bit_xor[7] == 1) begin

I could imagine having the keys vary which logic operations are in play and having the music threshold change the color of the pixels for instance.

***

This site has a module for a quasi random number generator : https://simplefpga.blogspot.com/2013/02/random-number-generator-in-verilog-fpga.html

This site has some good Processing examples : http://www.generative-gestaltung.de/2/

***

If I do this workshop again I’d like to design it to be made on aluminum as, it is at least in principle, recyclable.

PCBWay’s diagram of a double layer board (https://www.pcbway.fr/pcb_prototype/General_introduction_of_Aluminum_PCB.html) :

Two-layer_single_side.png

***

Simplest imaginable keypad switch (and audio in post comparator) test works :

module top (
input hwclk,
output led1,
input keypad_c1
);

assign led1=keypad_c1;

endmodule
Modified and restructured the random code from this site : https://simplefpga.blogspot.com/2013/02/random-number-generator-in-verilog-fpga.html and it appears to work :
`default_nettype none

module LFSR (
input clock,
input reset,
output [12:0] rnd
);

wire feedback;
reg [12:0] random, random_done;
reg [3:0] count; //to keep track of the shifts

assign feedback = random[12] ^ random[3] ^ random[2] ^ random[0];
assign rnd = random_done;
always @ (posedge clock)
begin
if (reset)
begin
random <= 13'hF; //An LFSR cannot have an all 0 state, thus reset to FF
count <= 0;
end

else
begin
if (count == 13)
begin
count <= 0;
random_done <= random; //assign the random number to output after 13 shifts
end

else
begin
random <= {random[11:0], feedback}; //shift left the xor'd every posedge clock
count <= count + 1;
end
end
end
endmodule

 

I am using it in the top code like this :

wire [12:0] random_number;

[...]

LFSR random_s(
.clock(clk_in),
.reset(reset),
.rnd(random_number)
);

***

Sine gen :

  • https://miscircuitos.com/sinus-wave-generation-with-verilog-using-vivado-for-a-fpga/
  • https://zipcpu.com/dsp/2017/07/11/simplest-sinewave-generator.html
  • https://verilogcodes.blogspot.com/2015/11/verilog-code-for-simple-sine-wave.html

I added a time delay module I modified from the led_rotation example :

`default_nettype none
module tempo(
input wire clk,
output reg half_sec_pulse
);

reg[25:0] div_cntr1;
reg[25:0] div_cntr2;
always@(posedge clk)
begin
div_cntr1 <= div_cntr1 + 1;
if (div_cntr1 == 0)
if (div_cntr2 == 0)
begin
div_cntr2 <= 0;
half_sec_pulse <= ~half_sec_pulse;
end

else
div_cntr2 <= div_cntr2 + 1;
else
half_sec_pulse <= half_sec_pulse;
end

endmodule

 

I can’t figure out why this makes 1/2 second ish though. Google says it should last 130.312488 days…

From the led_rotation code I get 2^16 = 65536, this happens 91 times so 65536x91, then multiplied by the period of a 12MHz clock (83.3ns) gets me to around 0.49 seconds.

I’m guessing it is getting clipped because the register is too big ?

*****

Fabien showed me that on AliExpress you can buy things like this tracking ball for cents :

Blackberry Trackball

https://fr.aliexpress.com/item/1005004324983317.html?spm=a2g0o.detail.0.0.3f40hagUhagUgw&gps-id=pcDetailTopMoreOtherSeller&scm=1007.40000.327270.0&scm_id=1007.40000.327270.0&scm-url=1007.40000.327270.0&pvid=83e84367-84b9-424f-b42a-31b87563ff5e&_t=gps-id:pcDetailTopMoreOtherSeller,scm-url:1007.40000.327270.0,pvid:83e84367-84b9-424f-b42a-31b87563ff5e,tpp_buckets:668%232846%238114%231999&pdp_npi=4%40dis%21EUR%210.80%210.72%21%21%216.14%21%21%40211b801516946910696348428ea8cb%2112000030031307832%21rec%21FR%21%21ABS&search_p4p_id=202309140431096642081558243384177015_4

Each one requires four little hall effect sensors which output HI-LOW pulses. The one made by Sparkfun is the AN48841B : high sensitivity CMOS Hall IC Operates on Alternating Magnetic Field (low-speed rotation for lock detection). Trying to find an alternative for not too much on Mouser.

https://www.mouser.fr/ProductDetail/Infineon-Technologies/TLI49632MXTSA1?qs=0DP5yvOrqYlmAP5lA6MTRA%3D%3D

I am also thinking about an HDMI mini – not micro – (if I can get HDMI working, if not get a helper chip), an atmega2560 to handle the SD card communication. Possibly a USB charger and a battery too – so that there can really be a minimum of cables when the battery is charged up.

A dumb-proof programming connector with an automatically controlled bus to disconnect the programmer from the FPGA when reset not asserted so I don’t need to unplug and replug every time ?

*****

Maybe I don’t need to rebuild the FPGA etc each time, but should just make interfaces that plug into it ?

The only thing left to try in hardware is the SD card fetching video data and then putting it on screen, and perhaps test having way more bits for each color and using the 4K LUT version of the iCE40.

I could also try using the specialized HDMI chip ?

*****

Got a code that works :

`default_nettype none

module vga_sync_test(

input wire clk_in,
input wire reset,
input wire key[8:0],
input wire adc_in,
output reg led_red,
output reg led_green,

//VGA OUT

output reg [3:0] r_out,
output reg [3:0] b_out,
output reg [3:0] g_out,
output wire h_sync,
output wire v_sync

);

wire half_sec;
wire [12:0] random_number_0;
wire [12:0] random_number_1;
wire [12:0] random_number_2;
wire [12:0] random_number_3;
wire [12:0] random_number_4;
wire [12:0] random_number_5;
wire [12:0] random_number_6;
wire [12:0] random_number_7;
wire [12:0] random_number_8;
wire [12:0] random_number_9;
wire [7:0] sine_wave;
wire display_en;
wire [11:0] h_count;
wire [11:0] v_count;

localparam h_pixel_max = 1280;
localparam v_pixel_max = 960;
localparam h_pixel_half = 640;
localparam v_pixel_half = 480;
localparam h_pixel_25 = 320;
localparam v_pixel_25 = 240;
localparam h_pixel_75 = 960;
localparam v_pixel_75 = 700;

//VGA COLOR OUT

always @(posedge clk_in) begin

if (display_en) begin

if ( key[0] == 0 &&

h_count < h_pixel_25 + random_number_1[4:0] && v_count < v_pixel_25 + random_number_7[8:5] &&
h_count > h_pixel_25 - random_number_2[4:0] && v_count > v_pixel_25 - random_number_2[8:5]

) begin

r_out <= random_number_1[3:0];
g_out <= random_number_5[3:0];
b_out <= random_number_9[6:4];

led_green <= 1;

end

else if ( key[1] == 0 &&

h_count < h_pixel_half + random_number_7[5:0] && v_count < v_pixel_half + random_number_7[10:5] &&
h_count > h_pixel_25 - random_number_6[5:0] && v_count > v_pixel_25 - random_number_6[10:5]

) begin

r_out <= random_number_3[7:5];
g_out <= random_number_3[3:0];
b_out <= random_number_6[6:4];

led_green <= 1;

end

else if ( key[2] == 0 &&

h_count < h_pixel_25 + random_number_8[6:0] && v_count < v_pixel_25 + random_number_8[12:6] &&
h_count > h_pixel_half - random_number_9[6:0] && v_count > v_pixel_half - random_number_9[11:5]

) begin

r_out <= random_number_4[7:5];
g_out <= random_number_5[3:0];
b_out <= random_number_7[6:4];
led_green <= 1;

end

else if ( key[3] == 0 &&

h_count < h_pixel_half + random_number_0[7:0] && v_count < v_pixel_half + random_number_0[7:0] &&
h_count > h_pixel_half - random_number_3[7:0] && v_count > v_pixel_half - random_number_3[11:4]

) begin

r_out <= random_number_8[7:5];
g_out <= random_number_8[3:0];
b_out <= random_number_8[6:4];
led_green <= 1;

end

else if ( key[4] == 0 &&

h_count < h_pixel_75 + random_number_2[8:0] && v_count < v_pixel_half + random_number_2[11:3] &&
h_count > h_pixel_75 - random_number_4[8:0] && v_count > v_pixel_half - random_number_4[11:3]

) begin

r_out <= random_number_7[7:5];
g_out <= random_number_7[3:0];
b_out <= random_number_7[6:4];

led_green <= 1;

end

else if ( key[5] == 0 &&
h_count < h_pixel_half + random_number_3[9:0] && v_count < v_pixel_75 + random_number_3[11:2] &&
h_count > h_pixel_half - random_number_8[9:0] && v_count > v_pixel_75 - random_number_8[11:2]

) begin

r_out <= random_number_5[7:5];
g_out <= random_number_5[3:0];
b_out <= random_number_5[6:4];
led_green <= 1;

end

else if ( key[6] == 0 &&

h_count < h_pixel_75 + random_number_4[10:0] && v_count < v_pixel_75 + random_number_4[11:1] &&
h_count > h_pixel_75 - random_number_6[10:0] && v_count > v_pixel_75 - random_number_6[11:1]

) begin
r_out <= random_number_4[7:5];
g_out <= random_number_4[3:0];
b_out <= random_number_4[6:4];
led_green <= 1;
end
else begin
r_out <= random_number_2[3:0];
g_out <= random_number_3[6:4];
b_out <= random_number_4[3:0];
led_green <= 0;
end
end
else begin
r_out <= 4'b0000;
g_out <= 4'b0000;
b_out <= 4'b0000;
led_green <= 0;
end
end

vga_sync vga_s(

.clk_in(clk_in),
.reset(reset),
.h_sync(h_sync),
.v_sync(v_sync),
.h_count(h_count),
.v_count(v_count),

.display_en(display_en) // '1' => pixel region

);

LFSR random_s(

.clock(clk_in),
.reset(reset),
.half_sec_pulse(half_sec),
.rnd_0(random_number_0),
.rnd_1(random_number_1),
.rnd_2(random_number_2),
.rnd_3(random_number_3),
.rnd_4(random_number_4),
.rnd_5(random_number_5),
.rnd_6(random_number_6),
.rnd_7(random_number_7),
.rnd_8(random_number_8),
.rnd_9(random_number_9)
);

sine_wave_gen sine_wave_s(
.clk(clk_in),
.data_out(sine_wave)
);

tempo tempo_s(
.clk(clk_in),
.half_sec_pulse(half_sec)
);

endmodule

and here is the PCF file :

set_io v_sync 97
set_io h_sync 76
set_io clk_in 49
set_io reset 66

set_io r_out[0] 91
set_io r_out[1] 95
set_io r_out[2] 96

set_io g_out[0] 75
set_io g_out[1] 74
set_io g_out[2] 73

set_io b_out[0] 87
set_io b_out[1] 88
set_io b_out[2] 90

set_io key[0] 37
set_io key[1] 38
set_io key[2] 39
set_io key[3] 41
set_io key[4] 42
set_io key[5] 43
set_io key[6] 44
set_io key[7] 45
set_io key[8] 47
set_io led_red 23
set_io led_green 24
set_io adc_in 56

FPGA SRAM board

FPGA SRAM board

 

Shadertoy is the future of this project, so what am I doing ? This new board is a reprogrammable FPGA 2D pixel shader (aka fragment shader) which can control the color of pixels and know only of the coordinate of the pixel being drawn. Pixel shaders can also sample the values of nearby pixels. As a result, they can do 2D post-processing (https://en.wikipedia.org/wiki/Video_post-processing) or filtering for a video streams. Why do this on an FPGA rather than in-brower ? You are super low level, and you have constraints based on the number of LUTs, it has a live-playable interface. In any case, I think this is my last board for a while, unless I can make an AI board somehow.

On the other hand, I’m not sure how profound it is to make photoshop like filters. (You can test a 5×5 grid if you go under Filters>Custom in PS). They are all kind of superficial…

I am starting to realize that I spend loads of time debugging soldering errors (yes, I get the learning that comes with that but still). If I made boards and had them assembled elsewhere I would not have this issue. Should I also, in the same spirit, just jump ahead to what everyone else is doing, with the thinking that they are not wasting time on problems that have already been solved and are exploring an interesting space.

I also spend a lot of time designing and building boards, interfaces, and less time programming them: the SCARA robot arm that I didn’t even plug in, the covid temperature interface board, the drone, and the MIT version of the mini swarm robot. On the other side are the projects I’ve perhaps spent too must time making and incrementally remaking perhaps : 3105 power harvester + radio transciever, the Ben Eater style memory. A nice balance was perhaps the solar sunflower protytpes which were experiments with form and function.

*EDIT* I am now thinking that I must work on things that would be of interest to other people, like Machine Learning for instance. I must be humble, just because something is interesting to me doesn’t mean anyone else cares ! Turns our that FPGAs consume a lot less current than GPUs so they are not bad for implementing ML once the training is done. Here is a info about ML with FPGAs :

  • https://www.youtube.com/@marcowinzker3682
  • https://www.mdpi.com/2076-3417/12/1/89
  • https://github.com/verimake-team/MLonFPGA
  • https://qengineering.eu/deep-learning-with-fpga-aka-bnn.html
  • https://qengineering.eu/embedded-vision.html#FPGA_stitching

Great post about the marble machine project : https://www.reddit.com/r/MarbleMachineX/comments/pzh5kw/an_open_letter_to_martin_on_the_state_of_the/

  • The machine is not about reliability and precision, it is about imperfection and the journey
  • It’s an art project, it is a project for the project’s sake and the documentation.
  • The project shouldn’t run like a start-up, and we are not the sum of what we produce for capitalism
  • Not specializing in one thing is what makes this project cool.

ERRATA :

  • I think the 590 is not clock dividing as expected…Is it not 3.3V compatible ? I think so, even though unclear on Mouser website.
  • Currently only 2 bits of each raspberry pi color input are appearing despite having selected dpi24 in the rpi config file.
  • The fine pots are the wrong footprint for the pots I have.
  • I could have used DEN (display enable) from the raspi.
  • sometimes the rpi starts up and then restarts after playing only a few seconds of video…not sure why.

To change the PLL, there is a tool in IceCube2 under Tool>Configure>Configure PLL Module

Here is the user guide explaining how to use it : https://www.latticesemi.com/-/media/LatticeSemi/Documents/ApplicationNotes/IK2/FPGA-TN-02052-1-4-iCE40-sysCLOCK-PLL-Design-User-Guide.ashx?document_id=47778

I want the following options :

  • General Purpose I/O Pad or Core Logic
  • Using a feedback path internal to the PLL
  • Input Frequency (MHz) : 100
  • Output Frequency (MHz) : 25

Here is the new PCF file :

set_io v_sync 87
set_io h_sync 88
set_io clk_in 64
set_io reset 66
set_io r0 81
set_io r1 80
set_io r2 79
set_io g0 94
set_io g1 93
set_io g2 91
set_io b0 76
set_io b1 75
set_io b2 74
set_io led 45
set_io locked_led 37
Tested with a 12MHz external clock, it works to output VGA.
No luck so far with 100MHz clock and multiplying all the pixel drawing, syncing and front and back porches by 4. Thinking of just switching out for a 12MHz clock like on the first version.
*EDIT* Also working with 25MHz external clock and removing the PLL.
*EDIT* Very strange but working with 100MHz now, except the code should only work with 50MHz…Here are the two files being used to generate the signal :

module vga_sync_test(
input wire clk_in,
input wire reset,
output reg r0,
output reg r1,
output reg r2,
output reg b0,
output reg b1,
output reg b2,
output reg g0,
output reg g1,
output reg g2,
output wire h_sync,
output wire v_sync
);

wire display_en;
//reg [9:0] h_count;
wire [11:0] h_count;
//reg [9:0] v_count;
wire [11:0] v_count;

/*
//for 100MHZ
localparam h_pixel_max = 2560;
localparam v_pixel_max = 1920;
localparam h_pixel_half = 1280;
localparam v_pixel_half = 960;
*/


//for 50MHZ

localparam h_pixel_max = 1280;
localparam v_pixel_max = 960;
localparam h_pixel_half = 640;
localparam v_pixel_half = 480;

/*
//for 25MHZ

localparam h_pixel_max = 640;
localparam v_pixel_max = 480;
localparam h_pixel_half = 320;
localparam v_pixel_half = 240;
*/

//Check if we can create RGB colors
always @(posedge clk_in) begin
if (display_en) begin
if (h_count < h_pixel_half
&& v_count < v_pixel_half) begin
//Assign here your test color
r0 <= 1'b0;
r1 <= 1'b0;
r2 <= 1'b0;
g0 <= 1'b0;
g1 <= 1'b0;
g2 <= 1'b0;
b0 <= 1'b1;
b1 <= 1'b1;
b2 <= 1'b1;
end else if (h_count > h_pixel_half
&& v_count < v_pixel_half) begin
//Assign here your test color
r0 <= 1'b0;
r1 <= 1'b0;
r2 <= 1'b0;
g0 <= 1'b1;
g1 <= 1'b1;
g2 <= 1'b1;
b0 <= 1'b0;
b1 <= 1'b0;
b2 <= 1'b0;
end else if (h_count < h_pixel_half
&& v_count > v_pixel_half) begin
//Assign here your test color
r0 <= 1'b1;
r1 <= 1'b1;
r2 <= 1'b1;
g0 <= 1'b0;
g1 <= 1'b0;
g2 <= 1'b0;
b0 <= 1'b0;
b1 <= 1'b0;
b2 <= 1'b0;
end else begin
//Assign here your test color
r0 <= 1'b1;
r1 <= 1'b1;
r2 <= 1'b1;
g0 <= 1'b1;
g1 <= 1'b1;
g2 <= 1'b1;
b0 <= 1'b1;
b1 <= 1'b1;
b2 <= 1'b1;
end
end else begin
r0 <= 1'b0;
r1 <= 1'b0;
r2 <= 1'b0;
g0 <= 1'b0;
g1 <= 1'b0;
g2 <= 1'b0;
b0 <= 1'b0;
b1 <= 1'b0;
b2 <= 1'b0;
end
end

vga_sync vga_s(
.clk_in(clk_in), //100,50, OR 25MHz clock input
.reset(reset), // RST assigned to SW1
.h_sync(h_sync),
.v_sync(v_sync),
.h_count(h_count),
.v_count(v_count),
.display_en(display_en) // '1' => pixel region
);

endmodule
/*
640x480 VGA singal generator
============================

- Creates h_sync,v_sync signals
- Creates display enable signal and horizontal, vertical
pixel position in display (h,v)
*/

`default_nettype none


module vga_sync(
input wire clk_in,
input wire reset,
output reg h_sync,
output reg v_sync,
output wire clk_sys,
output reg [11:0] h_count,
output reg [11:0] v_count,
output reg display_en
);


// Pixel counters
reg [11:0] h_counter = 0;
reg [11:0] v_counter = 0;

/*

//FOR 100MHz

localparam h_pixel_total = 3200;
localparam h_pixel_display = 2560;
localparam h_pixel_front_porch_amount = 64;
localparam h_pixel_sync_amount = 384;
localparam h_pixel_back_porch_amount = 192;

localparam v_pixel_total = 2100;
localparam v_pixel_display = 1920;
localparam v_pixel_front_porch_amount = 40;
localparam v_pixel_sync_amount = 8;
localparam v_pixel_back_porch_amount = 132;

*/

// FOR 50MHz

localparam h_pixel_total = 1600;
localparam h_pixel_display = 1280;
localparam h_pixel_front_porch_amount = 32;
localparam h_pixel_sync_amount = 192;
localparam h_pixel_back_porch_amount = 96;

localparam v_pixel_total = 1050;
localparam v_pixel_display = 960;
localparam v_pixel_front_porch_amount = 20;
localparam v_pixel_sync_amount = 4;
localparam v_pixel_back_porch_amount = 66;


/*

//FOR 25MHz

localparam h_pixel_total = 800;
localparam h_pixel_display = 640;
localparam h_pixel_front_porch_amount = 16;
localparam h_pixel_sync_amount = 96;
localparam h_pixel_back_porch_amount = 48;

localparam v_pixel_total = 525;
localparam v_pixel_display = 480;
localparam v_pixel_front_porch_amount = 10;
localparam v_pixel_sync_amount = 2;
localparam v_pixel_back_porch_amount = 33;

*/

always @(posedge clk_in) begin

if (reset) begin
//Reset counter values
h_counter <= 0;
v_counter <= 0;
display_en <= 0;
end
else
begin
// Generate display enable signal
if (h_counter < h_pixel_display && v_counter < v_pixel_display)
display_en <= 1;
else
display_en <= 0;

//Check if horizontal has arrived to the end
if (h_counter >= h_pixel_total)
begin
h_counter <= 0;
v_counter <= v_counter + 1;
end
else
//horizontal increment pixel value
h_counter <= h_counter + 1;
// check if vertical has arrived to the end
if (v_counter >= v_pixel_total)
v_counter <= 0;
end
end

always @(posedge clk_in) begin
// Check if sync_pulse needs to be created
if (h_counter >= (h_pixel_display + h_pixel_front_porch_amount)
&& h_counter < (h_pixel_display + h_pixel_front_porch_amount + h_pixel_sync_amount) )
h_sync <= 0;
else
h_sync <= 1;
// Check if sync_pulse needs to be created
if (v_counter >= (v_pixel_display + v_pixel_front_porch_amount)
&& v_counter < (v_pixel_display + v_pixel_front_porch_amount + v_pixel_sync_amount) )
v_sync <= 0;
else
v_sync <= 1;
end

// Route h_/v_counter to out
always @ (posedge clk_in) begin
h_count <= h_counter;
v_count <= v_counter;
end

endmodule

***
Trying to reconfigure the raspberry pi now for DPI output based on this document : https://www.raspberrypi.com/documentation/computers/raspberry-pi.html
Here’s what I did :
dtparam=spi=off
dtparam=i2c_arm=off
#display_auto_detect=1 // comment this
#dtoverlay=vc4-kms-v3d // comment this
gpio=0-9=a2
gpio=12-17=a2
gpio=20-25=a2
gpio=26-27=a2
dtoverlay=dpi24
enable_dpi_lcd=1
display_default_lcd=1
extra_transpose_buffer=2
dpi_group=2
dpi_mode=87
dpi_output_format=0x7f216
dpi_timings=720 0 40 48 128 720 0 13 3 15 0 0 0 60 0 41000000 4
Will now try to get the raspberry pi going at 50000000. Doesn’t seem to help FPGA with FPGA H&V to record or play anything back.
Testing to see if I can very simply just let the raspberry pi signals pass through the FPGA :
module vga_sync(
input wire R7IN,
input wire R6IN,
input wire R5IN,
input wire R4IN,
input wire G7IN,
input wire G6IN,
input wire G5IN,
input wire G4IN,
input wire B7IN,
input wire B6IN,
input wire B5IN,
input wire B4IN,
output wire R7OUT,
output wire R6OUT,
output wire R5OUT,
output wire R4OUT,
output wire G7OUT,
output wire G6OUT,
output wire G5OUT,
output wire G4OUT,
output wire B7OUT,
output wire B6OUT,
output wire B5OUT,
output wire B4OUT
);

assign R7OUT = R7IN;
assign R6OUT = R6IN;
assign R5OUT = R5IN;
assign R4OUT = R4IN;
assign G7OUT = G7IN;
assign G6OUT = G6IN;
assign G5OUT = G5IN;
assign G4OUT = G4IN;
assign B7OUT = B7IN;
assign B6OUT = B6IN;
assign B5OUT = B5IN;
assign B4OUT = B4IN;

I made a pcf to go with this test code :

set_io R7IN 107
set_io R6IN 106
set_io R5IN 105
set_io R4IN 104
set_io G7IN 97
set_io G6IN 96
set_io G5IN 95
set_io G4IN 112
set_io B7IN 102
set_io B6IN 101
set_io B5IN 99
set_io B4IN 98
set_io R7OUT 81
set_io R6OUT 80
set_io R5OUT 79
set_io R4OUT 78
set_io G7OUT 94
set_io G6OUT 93
set_io G5OUT 91
set_io G4OUT 90
set_io B7OUT 76
set_io B6OUT 75
set_io B5OUT 74
set_io B4OUT 73

Memory soldering done, added to the pcf :

set_io v_sync 87
set_io h_sync 88
set_io clk_in 64
set_io reset 66
set_io r0 81
set_io r1 80
set_io r2 79
set_io g0 94
set_io g1 93
set_io g2 91
set_io b0 76
set_io b1 75
set_io b2 74

set_io io0 1
set_io io1 2
set_io io2 3
set_io io3 4
set_io io4 122
set_io io5 121
set_io io6 120
set_io io7 119

set_io a0 138
set_io a1 139
set_io a2 141
set_io a3 142
set_io a4 143
set_io a5 8
set_io a6 9
set_io a7 10
set_io a8 11
set_io a9 12
set_io a10 136
set_io a11 135
set_io a12 134
set_io a13 129
set_io a14 128
set_io a15 117
set_io a16 116
set_io a17 115
set_io a18 114
set_io a19 137
set_io a20 113

set_io cs1 71
set_io we0 7

*********************

Refreshing my verilog learning from HDLbits :

A note on wire vs. reg: The right-hand-side of an assign statement must be a net type (e.g., wire), while the left-hand-side of a procedural assignment (in an always block) must be a variable type (e.g., reg).

                                                                                                  *******

you can do assign w = a; outside of an always block

assign continuously drives a into w

assign out = a&b; makes out equal to a AND’ed with b

it’s a combinational (i.e., memory-less, with no hidden state) function

using assign is the same as using always @(*)

                                                                                            *****

if you don’t declare it, output [3:0] a; will be a vector of type wire

to declare a vector : type [upper:lower] vector_name;

                                                                                              *****

A bitwise operation between two N-bit vectors replicates the operation for each bit of the vector and produces a N-bit output, while a logical operation treats the entire vector as a boolean value (true = non-zero, false = zero) and produces a 1-bit output.

Eg.

output [2:0] out_or_bitwise,
output out_or_logical,

assign out_or_bitwise = a | b;
assign out_or_logical = a || b;

Beware the different symbols for bitwise or logical !
                                                                                                ****

module mod_a ( input in1, input in2, output out );
// Module body
endmodule

When instantiating mod_a inside top_module :

module top_module (
input a,
input b,
output out
);

// Create an instance of “mod_a” named “inst1”, and connect ports by name:
mod_a inst1 (
.in1(a), // Port”in1″connects to wire “a”
.in2(b), // Port “in2” connects to wire “b”
.out(out) // Port “out” connects to wire “out”
// (Note: mod_a’s port “out” is not related to top_module’s wire “out”.
// It is simply coincidence that they have the same name)
);

                                                                                                ***

ALWAYS BLOCKS :

Clocked: always @(posedge clk)

Procedural blocks have a richer set of statements (e.g., if-then, case), cannot contain continuous assignments,

Clocked always blocks create a blob of combinational logic just like combinational always blocks, but also creates a set of flip-flops (or “registers”) at the output of the blob of combinational logic. Instead of the outputs of the blob of logic being visible immediately, the outputs are visible only immediately after the next (posedge clk).

In a locked always block, only use procedural non-blocking assignment: (x <= y;)

                                                                                            ***

Combinational circuits must have a value assigned to all outputs under all conditions. This usually means you always need else clauses or a default value assigned to the outputs.

This can cause the Warning (10240): … inferring latch(es) error message

                                                                                            ***

Saw some inspiring machines in Munich :

Barrels would be cool to incorporate into my next prototype.

I wonder if I could make an analog feedback set up with linear actuators, a screen and camera…

I love the scientific instrument aspect. The monitor hovering on the side could be cool to incorporate.

 

*****

Check out this analog video feedback setup… could I do a miniature version ? :

 

****

One reaction to the museum visit it to think of what makes something look like a machine.

  • an agglomeration of mainly metal (especially machined aluminum and folded steel) and plastic modules
  • rotation and linear motion, symmetry about a central axis or a pile of modules facing the user

If I wanted to focus on the technical object itself, I could work on a custom cooling setup, with thin curving pipes, knobs that allow for various kinds of custom fine control, screens and cameras on various linear axes for feedback loop control.

A DIY water cooler :

Amazing! DIY Mini Liquid Cooling System - YouTube

Importance apprenti Gonfle diy cpu water block la toux mosaïque sans rapport

A custom keyboard from https://keyboards.tanebox.com/a/blog/939/ :

I like the exposed keyboard that extends into a circuit board with chips on the top. Could it be possible to make a kind of reprogrammable FPGA video synth computer ? Perhaps I could also learn things about video by taking a video file from a an SD card and then moving it into a dual port DRAM memory to be displayed.

This gets at something that feels important : I am always trying to get myself to some harder to get to place, with the help of DIY tech, before making artsy stuff. It’s almost like I feel I’m not competitive enough starting from the most accessible starting point (classical art like drawing, painting, sculpture). Sam suggested that I combine my interest in hardware with software. Can I make a kind of custom programmable computer that is my own and then program it in a low level language (like assembly or verilog)?

MechBoardsのPlaid // ThroughHole – コトコト

I love the windy wire plug found on the mechanical keyboard subreddit :

r/CustomKeyboards - I Can't Get No

r/CustomKeyboards - My totally customized split keyboard

From https://spectrum.ieee.org/yugoslavia-diy-microcomputer :

Keyboard buttons from Mouser : https://www.mouser.fr/ProductDetail/E-Switch/KS1100OA1AF060?qs=gt1LBUVyoHkJwqhwHM2wRw%3D%3D

***

Or, in the totally opposite direction (not going for gimmicks or flashiness), super inexpensive DRAM chips (1 euro for 16Mbit) :

https://www.mouser.fr/ProductDetail/ISSI/IS42S16100H-7TL?qs=yfIbTn1BQ2BEUPfKEYbGCA%3D%3D

****

Had a thought : I am basically trying to “play” the VGA format itself like an instrument.

****

So making a pin that is both input and output for an FPGA is not so simple ! This post helped : https://electronics.stackexchange.com/questions/33144/birectional-i-o-pin-in-verilog

My attempts to make diagrams :

 

I also cleaned up the code a bit, making vectors with indices and following naming conventions :

I can see evidence of something being recorded and played back out of sync (only when rpi input provides H&V and the FPGA used the rpi 41MHz pixel clock or the 100MHz clock) but it’s far from working completely.

I can send external clocks that are divisions of 41MHz clock (20.5MHz, 10.25MHz) when rpi is supplying the H&V and it just barely works.

The FPGA works with external 25MHz clock also, but I can’t see any recordings.

*EDIT* I can get pretty clear recordings with the RPI clock and H&V after fiddling. Still no luck with recording RPI color information and then showing it at FPGA H&V with either pixel clock. I have gotten rid of the test colors and now am showing full screen FPGA. Twiddled 4 versus 3 bits on the output.

`default_nettype none

module vga_sync_test(

input wire clk_in,
input wire reset,

input wire rec, // Direction of io, 1 = set output, 0 = read input

//RASPBERRY PI
input wire [3:0] r_in,
input wire [3:0] b_in,
input wire [3:0] g_in,

//VGA OUT
output reg [3:0] r_out,
output reg [3:0] b_out,
output reg [3:0] g_out,

output wire h_sync,
output wire v_sync,

//SRAM

output reg [20:0] addr,
inout wire [7:0] io, // inout must be type wire

output wire cs_1,
output reg we_0

);

wire [7:0] data_in;
wire [7:0] data_out;

reg [7:0] a, b;

assign io = rec ? a : 8'bzzzzzzzz;

assign data_out = b;

assign data_in[1:0] = r_in[3:2];
assign data_in[3:2] = b_in[3:2];
assign data_in[5:4] = g_in[3:2];
assign data_in[7:6] = 2'b00;

wire display_en;
wire [11:0] h_count;
wire [11:0] v_count;

assign cs_1 = 0; // low to select, high to deselect

localparam h_pixel_max = 1280;
localparam v_pixel_max = 960;
localparam h_pixel_half = 640;
localparam v_pixel_half = 480;


//SRAM address counter

always @(posedge clk_in) begin
    if (reset)
        addr <= 0;
    else
        addr <= addr+1;
    end


//REC control

always @(posedge clk_in) begin
      b <= io;
      a <= data_in;
     if (rec) begin
          we_0 <= addr[0]; //not sure why it isn't the inverse of addr[0] but that doesn't make the inverse on 'scope
     end
     else begin
          we_0 <= 1;
     end
end

//VGA COLOR OUT

always @(posedge clk_in) begin
if (display_en) begin
if (h_count < h_pixel_half
&& v_count < v_pixel_half) begin

r_out[1:0] <= data_out[1:0];
r_out[2] <= 1'b0;
g_out[1:0] <= data_out[3:2];
g_out[2] <= 1'b0;
b_out[1:0] <= data_out[5:4];
b_out[2] <= 1'b0;

end else if (h_count > h_pixel_half
&& v_count < v_pixel_half) begin


r_out <= 3'b000;
g_out <= 3'b111;
b_out <= 3'b000;

end else if (h_count < h_pixel_half
&& v_count > v_pixel_half) begin


r_out <= 3'b111;
g_out <= 3'b000;
b_out <= 3'b000;

end else begin


r_out <= 3'b111;
g_out <= 3'b111;
b_out <= 3'b111;

end
end else begin

r_out <= 3'b000;
g_out <= 3'b000;
b_out <= 3'b000;
end
end

vga_sync vga_s(
.clk_in(clk_in),
.reset(reset),
.h_sync(h_sync),
.v_sync(v_sync),
.h_count(h_count),
.v_count(v_count),
.display_en(display_en) // '1' => pixel region
);

endmodule

 

Here is the complete pcf :

set_io v_sync 87
set_io h_sync 88
set_io clk_in 64
set_io reset 66

set_io io[0] 1
set_io io[1] 2
set_io io[2] 3
set_io io[3] 4
set_io io[4] 122
set_io io[5] 121
set_io io[6] 120
set_io io[7] 119

set_io io[8] 45
set_io io[9] 47
set_io io[10] 48
set_io io[11] 49
set_io io[12] 28
set_io io[13] 26
set_io io[14] 25
set_io io[15] 24

set_io addr[0] 138
set_io addr[1] 139
set_io addr[2] 141
set_io addr[3] 142
set_io addr[4] 143
set_io addr[5] 8
set_io addr[6] 9
set_io addr[7] 10
set_io addr[8] 11
set_io addr[9] 12
set_io addr[10] 136
set_io addr[11] 135
set_io addr[12] 134
set_io addr[13] 129
set_io addr[14] 128
set_io addr[15] 117
set_io addr[16] 116
set_io addr[17] 115
set_io addr[18] 114
set_io addr[19] 137
set_io addr[20] 113

set_io addr[21] 38
set_io addr[22] 39
set_io addr[23] 41
set_io addr[24] 42
set_io addr[25] 43
set_io addr[26] 52
set_io addr[27] 56
set_io addr[28] 58
set_io addr[29] 60
set_io addr[30] 61
set_io addr[31] 34
set_io addr[32] 33
set_io addr[33] 32
set_io addr[34] 31
set_io addr[35] 29
set_io addr[36] 23
set_io addr[37] 22
set_io addr[38] 21
set_io addr[39] 20
set_io addr[40] 37
set_io addr[41] 19

set_io cs_0 144
set_io cs_1 71
set_io cs_2 44
set_io cs_3 63

set_io we_0 7
set_io we_1 50

set_io rec 62

set_io r_in[0] 107
set_io r_in[1] 106
set_io r_in[2] 105
set_io r_in[3] 104
set_io g_in[0] 97
set_io g_in[1] 96
set_io g_in[2] 95
set_io g_in[3] 112
set_io b_in[0] 102
set_io b_in[1] 101
set_io b_in[2] 99
set_io b_in[3] 98

set_io r_out[0] 81
set_io r_out[1] 80
set_io r_out[2] 79
set_io r_out[3] 78
set_io g_out[0] 94
set_io g_out[1] 93
set_io g_out[2] 91
set_io g_out[3] 90
set_io b_out[0] 76
set_io b_out[1] 75
set_io b_out[2] 74
set_io b_out[3] 73

****

Added the third SRAM and having issues, commented out one new pin at a time and it seems like address 18 (on pin 20) is problematic. When I remove this pin everything else functions well enough for a memory with a missing pin however.

`default_nettype none

module vga_sync_test(

input wire clk_in,
input wire reset,

input wire rec, // Direction of io, 1 = set output, 0 = read input

//RASPBERRY PI
input wire [3:0] r_in,
input wire [3:0] b_in,
input wire [3:0] g_in,

//VGA OUT
output reg [3:0] r_out,
output reg [3:0] b_out,
output reg [3:0] g_out,

output wire h_sync,
output wire v_sync,

//SRAM

output reg [20:0] addr,
inout wire [7:0] io, // inout must be type wire

output wire cs_1,
output wire cs_0,
output reg we_0

);

wire [7:0] data_in;
wire [7:0] data_out;

reg toggle;

reg [7:0] a, b;

assign io = rec ? a : 8'bzzzzzzzz;

assign data_out = b;

assign data_in[1:0] = r_in[3:2];
assign data_in[3:2] = b_in[3:2];
assign data_in[5:4] = g_in[3:2];
assign data_in[7:6] = 2'b00;

wire display_en;
wire [11:0] h_count;
wire [11:0] v_count;

localparam h_pixel_max = 1280;
localparam v_pixel_max = 960;
localparam h_pixel_half = 640;
localparam v_pixel_half = 480;

// CS: low to select, high to deselect

assign cs_0 = toggle ? 1 : 0;
assign cs_1 = toggle ? 0 : 1;

//SRAM address counter

always @(posedge clk_in) begin

if (addr == 0) begin
toggle <= toggle+1;
end

if (reset) begin
addr <= 0;
end else begin
addr <= addr+1;

end
end


//REC control

always @(posedge clk_in) begin

b <= io;
a <= data_in;

if (rec) begin
we_0 <= addr[0]; //not sure why it isn't the inverse of addr[0] but that doesn't make the inverse on 'scope
end
else begin
we_0 <= 1;
end
end

//VGA COLOR OUT

always @(posedge clk_in) begin
if (display_en) begin

r_out[3:2] <= data_out[1:0];
r_out[1:0] <= data_out[1:0];
g_out[3:2] <= data_out[3:2];
g_out[1:0] <= data_out[3:2];
b_out[3:2] <= data_out[5:4];
b_out[1:0] <= data_out[5:4];

end else begin

r_out <= 4'b0000;
g_out <= 4'b0000;
b_out <= 4'b0000;
end
end

vga_sync vga_s(
.clk_in(clk_in),
.reset(reset),
.h_sync(h_sync),
.v_sync(v_sync),
.h_count(h_count),
.v_count(v_count),
.display_en(display_en) // '1' => pixel region
);

endmodule

***

I made an animated video of the assembly of the board :

When I make the next board I’ll  record the eagle CAD and make another video.

Here are some images of what a new device could look like !

What about an FPGA chip holder ? And a snazzy pivotable SD card holder ? Using meanders this time? With its own fictional programming language like in that assembly video game ? With a mini PCI-E connector somewhere ?

To pre-digest the videos for the FPGA before putting them on a gigantic SD card, I could use ffmpeg to output a less compressed format like .avi or an .mkv and then erase the header and footer ?

Have a name (little Lebowski urban achiever is too long), and a format 100×80 (free Eagle max), and a rough layout (HDMI super close, USB next to FTDI and to flash memory, all the memory to the right equidistant to the chip). AND, some kind of transparent cover, a first for me, make it seem more like a legitimate product and would reduce the risk of short circuits from something conductive falling on the board. For the symbols on the keyboard, there is the Comodore 64 keyboard symbol set which is cool. Or some ancient symbols ??

I am now moving away from SDRAM, challenging and I’m not sure why I’m putting myself through it. The real interest is going to be decoding videos stored on the SD card and putting them on screen. I want to try to do it like the pros – drawing to the screen in the blanking period and using only one SRAM.

****

Still trying to resolve the A18 issue.

  • I tried soldering another IO pin to pin 20, but this led to total chaos, none of the address pins working. I could have tried severing the link between the pin 20 and the SRAM but I don’t want to damage the board before I identify the problem (it may be in the code?).
  • Trying to lower the size of the address counter to stop at 17 instead of going to 18.
  • I connected to the rpi’s DEN and changed the code to work with it instead of the FPGAs display en (it doesn’t work anyways). It is cool as it is more likely to capture the image on the rpi if I understand correctly.

****

I am now trying some of the code I was dreaming about – modifying the input and output video stream based on other parallel data.

Here is one strategy based on two bits of the same color having an impact on recording and playback.

if (b[3]==b[2]) begin
a <= data_in;
end
else begin
a <= 8'b00000000;
end

I have the two memories working (excepted A18 on the second SRAM), and also tried reading DEN from the rpi. It makes some pretty funky glitches by touching the RAM pins with my hands !

Also check out the bitmap to program the FPGA :

 

`default_nettype none

module vga_sync_test(

input wire clk_in,
input wire reset,

input wire rec, // Direction of io, 1 = set output, 0 = read input

//RASPBERRY PI
input wire [3:0] r_in,
input wire [3:0] b_in,
input wire [3:0] g_in,
input wire DEN,

//VGA OUT
output reg [3:0] r_out,
output reg [3:0] b_out,
output reg [3:0] g_out,

output wire h_sync,
output wire v_sync,

//SRAM

output reg [20:0] addr,
output reg [20:0] addr_copy,
inout wire [15:0] io, // inout must be type wire

output wire cs_3,
output wire cs_2,
output wire cs_1,
output wire cs_0,

output reg we_1,
output reg we_0

);

wire [15:0] data_in;
wire [15:0] data_out;

reg [1:0] toggle;

reg [15:0] a, b;

assign io = rec ? a : 16'bzzzzzzzzzzzzzzzz;

assign data_out = b;

assign data_in[1:0] = DEN ? r_in[3:2] : 0;
assign data_in[3:2] = DEN ? b_in[3:2] : 0;
assign data_in[5:4] = DEN ? g_in[3:2] : 0;
assign data_in[7:6] = 2'b00;

assign data_in[9:8] = DEN ? r_in[3:2] : 0;
assign data_in[11:10] = DEN ? b_in[3:2] : 0;
assign data_in[13:12] = DEN ? g_in[3:2] : 0;
assign data_in[15:14] = 2'b00;

wire display_en;
wire [11:0] h_count;
wire [11:0] v_count;

localparam h_pixel_max = 1280;
localparam v_pixel_max = 960;
localparam h_pixel_half = 640;
localparam v_pixel_half = 480;

// CS: low to select, high to deselect

assign cs_0 = toggle == 2'b00 ? 1 : 0;
assign cs_1 = toggle == 2'b01 ? 1 : 0;
assign cs_2 = toggle == 2'b10 ? 1 : 0;
assign cs_3 = toggle == 2'b11 ? 1 : 0;

//SRAM address counter

always @(posedge clk_in) begin

if (addr == 0) begin
   toggle <= toggle+1;
end

if (reset) begin
   addr <= 0;
end else begin
   addr <= addr+1;
   addr_copy <= addr_copy+1;

end
end

//REC control

always @(posedge clk_in) begin

   b <= io;
   a <= data_in;
if (rec) begin
   we_0 <= addr[0]; //not sure why it isn't the inverse of addr[0] but that doesn't make the inverse on 'scope
   we_1 <= addr[0];
end
else begin
   we_0 <= 1;
   we_1 <= 1;
end
end

//VGA COLOR OUT

always @(posedge clk_in) begin
if (DEN) begin
if (toggle==2'b00 || toggle==2'b01 ) begin
   r_out[3:2] <= data_out[1:0];
   r_out[1:0] <= data_out[1:0];
   g_out[3:2] <= data_out[3:2];
   g_out[1:0] <= data_out[3:2];
   b_out[3:2] <= data_out[5:4];
   b_out[1:0] <= data_out[5:4];

end else begin
   r_out[3:2]<= data_out[9:8];
   r_out[1:0]<= data_out[9:8];
   g_out[3:2]<= data_out[11:10];
   g_out[1:0]<= data_out[11:10];
   b_out[3:2]<= data_out[13:12];
   b_out[1:0]<= data_out[13:12];
end
end else begin
   r_out <= 4'b0000;
   g_out <= 4'b0000;
   b_out <= 4'b0000;
end
end

vga_sync vga_s(
.clk_in(clk_in),
.reset(reset),
.h_sync(h_sync),
.v_sync(v_sync),
.h_count(h_count),
.v_count(v_count),
.display_en(display_en) // '1' => pixel region
);

endmodule

From https://www.fpga4fun.com/VerilogTips.html:

  • I need to initialize verilog counters !!
  • Another way of selecting 4 bits in a vector : wire [3:0] thisis4also = myvalue[16+:4];
  • It might be smarter to use a PLL than to take the external clock directly.
  • I need to debounce all input buttons !

****

Check out shaders that take video as input :

https://www.shadertoy.com/view/ctsyzN

https://www.shadertoy.com/view/XtcSRs

****

Tried to make some vignettes of the new board to show the impedence matching :

I think I will order it in white with the meanders exposed like on the VGA spaghettini.

Color options (I’m leaning towards white or maybe green):

***************************

I am now thinking about how I will be able to share all that I am trying to learn about verilog and FPGAs in workshops. The bottleneck is programming the FPGA without special hardware.

OLIMEX has a link to a rasberry pi utility called flashrom that can program and read FLASH memory documented here : https://github.com/OLIMEX/iCE40HX1K-EVB/tree/master/programmer/olimexino-32u4%20firmware

These raspberry pi examples program the ice40 and looks simple :

  • https://j-marjanovic.io/lattice-ice40-configuration-using-raspberry-pi.html
  • https://github.com/plex1/raspice40

The steps have been automated here : https://notabug.org/sagaracharya/swarajya/src/master/hdl_to_hx8k/on_pi

Also for the rpi Pico : https://github.com/dan-rodrigues/pico-hx

I could knock off the 2232 FTDI and have made something like this: https://shop.trenz-electronic.de/en/TEM0009-02-FPGA-USB-programmer-JTAG-for-development-with-Microchip-FPGAs

Most interestingly, it seems like Arduino Uno could program an FPGA using a library like SPIMemory by Prajwal Bhattaram : https://github.com/Marzogh/SPIMemory/tree/v2.2.0

Finally, I could make a board like the gameduino that has an API for the Arduino to use to talk to the FPGA which handles fast screen drawing. This would mean everything could be done within the Arduino IDE.

EDIT* Come to think of it, even if the FTDI adds cost, it would make everything so much easier for a workshop – one piece of software and no extra hardware to program after for the participants. But when I plug it in it says USB device malfunctioned…(I also realized that I think I can forgo the RS232 connections between the FTDI and the FPGA and just connect it to the EEPROM and FLASH.)

EDIT* The OLIMEX code for Arduino is also not compiling and winIceProgDuino.exe (to program FPGA by sending serial commands to Arduino firmware I suppose) is not opening either.

EDIT*2 The Arduino sketch compiles but only for MEGA, Leonardo, and Micro so far (no UNO or NANO or MINI) but only after removing the iceprog.cpp file.

******************

Some thoughts on low-level versus high-level programming :

Something unsatisfying about making something from a pre-digested meta language (fast.ai for instance). Lost the feeling of ownership of the thing you’re making.

Obviously you can do much more when you stand atop of the shoulders of giants, but you are less connected with the surface of the ground because you are working with abstractions. If something goes wrong, you have no recourse because you are just a customer.
Low level languages make the architecture of the machine visible by laying it bear. There is agency. Then again, to do something very simple can be hard and require lots of code which provides many opportunities for silly mistakes.
Yet for workshops it seems good to avoid low level stuff. It’s not impressive, it’s discouraging, and it’s hard to debug.
*******************
I have soldered the new board, I love the keys !! But HDMI is still not working.

Lots of fun could be had rearranging the keys using the same row heights  :

I wonder if I should just transition to making interfaces directly – I am a designer after all !

The FPGA4fun.com code is not synthesizing, I think because it requires clock dividing modules that I don’t have.
I tried this code and it compiles but I don’t see anything on the ‘scope: https://gist.github.com/uXeBoy/0d46e2f1560f73dd573d83e78309bfa0
This code eventually produced signals on HDMI out, will have to wait to see if it is acceptable HDMI once I have the proper resistor LVDS setup.
`default_nettype none // disable implicit definitions by Verilog
//-----------------------------------------------------------------
// minimalDVID_encoder.vhd : A quick and dirty DVI-D implementation
//
// Author: Mike Field <hamster@snap.net.nz>
//
// DVI-D uses TMDS as the 'on the wire' protocol, where each 8-bit
// value is mapped to one or two 10-bit symbols, depending on how
// many 1s or 0s have been sent. This makes it a DC balanced protocol,
// as a correctly implemented stream will have (almost) an equal
// number of 1s and 0s.
//
// Because of this implementation quite complex. By restricting the
// symbols to a subset of eight symbols, all of which having have
// five ones (and therefore five zeros) this complexity drops away
// leaving a simple implementation. Combined with a DDR register to
// send the symbols the complexity is kept very low.
//-----------------------------------------------------------------

module top(
clk100, hdmi_p, hdmi_n
);

input clk100;
output [3:0] hdmi_p;
output [3:0] hdmi_n;

// For holding the outward bound TMDS symbols in the slow and fast domain
reg [9:0] c0_symbol; reg [9:0] c0_high_speed;
reg [9:0] c1_symbol; reg [9:0] c1_high_speed;
reg [9:0] c2_symbol; reg [9:0] c2_high_speed;
reg [9:0] clk_high_speed;

reg [1:0] c2_output_bits;
reg [1:0] c1_output_bits;
reg [1:0] c0_output_bits;
reg [1:0] clk_output_bits;

wire clk_x5;
reg [2:0] latch_high_speed = 3'b100; // Controlling the transfers into the high speed domain

wire vsync, hsync;
wire [1:0] syncs; // To glue the HSYNC and VSYNC into the control character
assign syncs = {vsync, hsync};

// video structure constants
parameter hpixels = 800; // horizontal pixels per line
parameter vlines = 525; // vertical lines per frame
parameter hpulse = 96; // hsync pulse length
parameter vpulse = 2; // vsync pulse length
parameter hbp = 144; // end of horizontal back porch (96 + 48)
parameter hfp = 784; // beginning of horizontal front porch (800 - 16)
parameter vbp = 35; // end of vertical back porch (2 + 33)
parameter vfp = 515; // beginning of vertical front porch (525 - 10)

// registers for storing the horizontal & vertical counters
reg [9:0] vc;
reg [9:0] hc;
// generate sync pulses (active high)
assign vsync = (vc < vpulse);
assign hsync = (hc < hpulse);

always @(posedge clk_x5) begin
//-------------------------------------------------------------
// Now take the 10-bit words and take it into the high-speed
// clock domain once every five cycles.
//
// Then send out two bits every clock cycle using DDR output
// registers.
//-------------------------------------------------------------
c0_output_bits <= c0_high_speed[1:0];
c1_output_bits <= c1_high_speed[1:0];
c2_output_bits <= c2_high_speed[1:0];
clk_output_bits <= clk_high_speed[1:0];
if (latch_high_speed[2]) begin // pixel clock 25MHz
c0_high_speed <= c0_symbol;
c1_high_speed <= c1_symbol;
c2_high_speed <= c2_symbol;
clk_high_speed <= 10'b0000011111;
latch_high_speed <= 3'b000;
if (hc < hpixels)
hc <= hc + 1;
else
begin
hc <= 0;
if (vc < vlines)
vc <= vc + 1;
else
vc <= 0;
end
end
else begin
c0_high_speed <= {2'b00, c0_high_speed[9:2]};
c1_high_speed <= {2'b00, c1_high_speed[9:2]};
c2_high_speed <= {2'b00, c2_high_speed[9:2]};
clk_high_speed <= {2'b00, clk_high_speed[9:2]};
latch_high_speed <= latch_high_speed + 1'b1;
end
end

always @(*) // display 100% saturation colourbars
begin
// first check if we're within vertical active video range
if (vc >= vbp && vc < vfp)
begin
// now display different colours every 80 pixels
// while we're within the active horizontal range
// -----------------
// display white bar
if (hc >= hbp && hc < (hbp+80))
begin
c2_symbol = 10'b1011110000; // red
c1_symbol = 10'b1011110000; // green
c0_symbol = 10'b1011110000; // blue
end
// display yellow bar
else if (hc >= (hbp+80) && hc < (hbp+160))
begin
c2_symbol = 10'b1011110000; // red
c1_symbol = 10'b1011110000; // green
c0_symbol = 10'b0111110000; // blue
end
// display cyan bar
else if (hc >= (hbp+160) && hc < (hbp+240))
begin
c2_symbol = 10'b0111110000; // red
c1_symbol = 10'b1011110000; // green
c0_symbol = 10'b1011110000; // blue
end
// display green bar
else if (hc >= (hbp+240) && hc < (hbp+320))
begin
c2_symbol = 10'b0111110000; // red
c1_symbol = 10'b1011110000; // green
c0_symbol = 10'b0111110000; // blue
end
// display magenta bar
else if (hc >= (hbp+320) && hc < (hbp+400))
begin
c2_symbol = 10'b1011110000; // red
c1_symbol = 10'b0111110000; // green
c0_symbol = 10'b1011110000; // blue
end
// display red bar
else if (hc >= (hbp+400) && hc < (hbp+480))
begin
c2_symbol = 10'b1011110000; // red
c1_symbol = 10'b0111110000; // green
c0_symbol = 10'b0111110000; // blue
end
// display blue bar
else if (hc >= (hbp+480) && hc < (hbp+560))
begin
c2_symbol = 10'b0111110000; // red
c1_symbol = 10'b0111110000; // green
c0_symbol = 10'b1011110000; // blue
end
// display black bar
else if (hc >= (hbp+560) && hc < hfp)
begin
c2_symbol = 10'b0111110000; // red
c1_symbol = 10'b0111110000; // green
c0_symbol = 10'b0111110000; // blue
end
// we're outside active horizontal range
else
begin
c2_symbol = 10'b1101010100; // red
c1_symbol = 10'b1101010100; // green
//---------------------------------------------
// Channel 0 carries the blue pixels, and also
// includes the HSYNC and VSYNCs during
// the CTL (blanking) periods.
//---------------------------------------------
case (syncs)
2'b00 : c0_symbol = 10'b1101010100;
2'b01 : c0_symbol = 10'b0010101011;
2'b10 : c0_symbol = 10'b0101010100;
default : c0_symbol = 10'b1010101011;
endcase
end
end
// we're outside active vertical range
else
begin
c2_symbol = 10'b1101010100; // red
c1_symbol = 10'b1101010100; // green
//---------------------------------------------
// Channel 0 carries the blue pixels, and also
// includes the HSYNC and VSYNCs during
// the CTL (blanking) periods.
//---------------------------------------------
case (syncs)
2'b00 : c0_symbol = 10'b1101010100;
2'b01 : c0_symbol = 10'b0010101011;
2'b10 : c0_symbol = 10'b0101010100;
default : c0_symbol = 10'b1010101011;
endcase
end
end

// red N
defparam hdmin2.PIN_TYPE = 6'b010000;
defparam hdmin2.IO_STANDARD = "SB_LVCMOS";
SB_IO hdmin2 (
.PACKAGE_PIN (hdmi_n[2]),
.CLOCK_ENABLE (1'b1),
.OUTPUT_CLK (clk_x5),
.OUTPUT_ENABLE (1'b1),
.D_OUT_0 (c2_output_bits[1]),
.D_OUT_1 (c2_output_bits[0])
);

// red P
defparam hdmip2.PIN_TYPE = 6'b010000;
defparam hdmip2.IO_STANDARD = "SB_LVCMOS";
SB_IO hdmip2 (
.PACKAGE_PIN (hdmi_p[2]),
.CLOCK_ENABLE (1'b1),
.OUTPUT_CLK (clk_x5),
.OUTPUT_ENABLE (1'b1),
.D_OUT_0 (c2_output_bits[1]),
.D_OUT_1 (c2_output_bits[0])
);

// green N
defparam hdmin1.PIN_TYPE = 6'b010000;
defparam hdmin1.IO_STANDARD = "SB_LVCMOS";
SB_IO hdmin1 (
.PACKAGE_PIN (hdmi_n[1]),
.CLOCK_ENABLE (1'b1),
.OUTPUT_CLK (clk_x5),
.OUTPUT_ENABLE (1'b1),
.D_OUT_0 (c1_output_bits[1]),
.D_OUT_1 (c1_output_bits[0])
);

// green P
defparam hdmip1.PIN_TYPE = 6'b010000;
defparam hdmip1.IO_STANDARD = "SB_LVCMOS";
SB_IO hdmip1 (
.PACKAGE_PIN (hdmi_p[1]),
.CLOCK_ENABLE (1'b1),
.OUTPUT_CLK (clk_x5),
.OUTPUT_ENABLE (1'b1),
.D_OUT_0 (c1_output_bits[1]),
.D_OUT_1 (c1_output_bits[0])
);


// blue N
defparam hdmin0.PIN_TYPE = 6'b010000;
defparam hdmin0.IO_STANDARD = "SB_LVCMOS";
SB_IO hdmin0 (
.PACKAGE_PIN (hdmi_n[0]),
.CLOCK_ENABLE (1'b1),
.OUTPUT_CLK (clk_x5),
.OUTPUT_ENABLE (1'b1),
.D_OUT_0 (c0_output_bits[1]),
.D_OUT_1 (c0_output_bits[0])
);

// blue P
defparam hdmip0.PIN_TYPE = 6'b010000;
defparam hdmip0.IO_STANDARD = "SB_LVCMOS";
SB_IO hdmip0 (
.PACKAGE_PIN (hdmi_p[0]),
.CLOCK_ENABLE (1'b1),
.OUTPUT_CLK (clk_x5),
.OUTPUT_ENABLE (1'b1),
.D_OUT_0 (c0_output_bits[1]),
.D_OUT_1 (c0_output_bits[0])
);

// clock N
defparam hdmin3.PIN_TYPE = 6'b010000;
defparam hdmin3.IO_STANDARD = "SB_LVCMOS";
SB_IO hdmin3 (
.PACKAGE_PIN (hdmi_n[3]),
.CLOCK_ENABLE (1'b1),
.OUTPUT_CLK (clk_x5),
.OUTPUT_ENABLE (1'b1),
.D_OUT_0 (clk_output_bits[1]),
.D_OUT_1 (clk_output_bits[0])
);


// clock P
defparam hdmip3.PIN_TYPE = 6'b010000;
defparam hdmip3.IO_STANDARD = "SB_LVCMOS";
SB_IO hdmip3 (
.PACKAGE_PIN (hdmi_p[3]),
.CLOCK_ENABLE (1'b1),
.OUTPUT_CLK (clk_x5),
.OUTPUT_ENABLE (1'b1),
.D_OUT_0 (clk_output_bits[1]),
.D_OUT_1 (clk_output_bits[0])
);
// D_OUT_0 and D_OUT_1 swapped?
// https://github.com/YosysHQ/yosys/issues/330


SB_PLL40_PAD #(
.FEEDBACK_PATH ("SIMPLE"),
.DIVR (4'b0000),
.DIVF (7'b0001001),
.DIVQ (3'b011),
.FILTER_RANGE (3'b101)
) uut (
.RESETB (1'b1),
.BYPASS (1'b0),
.PACKAGEPIN (clk100),
.PLLOUTGLOBAL (clk_x5) // DVI clock 125MHz
);

endmodule
I learned a bit about how HDMI is encoded to reduce strings of 1s or Os and how transitions are minimized. I currently suspect that the PLL is not working but I’m not sure why yet. I will turn on the PLL locked LED feature to check and then mess with other parameters (see https://zipcpu.com/blog/2017/09/14/even-i-get-stuck.html) if it isn’t working.
*EDIT 1 Apparently IceCube2 doesn’t want me to attach the CLK to any pin other than 49 (GBIN5) or 129 (GBIN0) ! This explains why nothing is happening, the clock wasn’t even entering the FPGA.
*EDIT 2 I connected the clock pin to 49, and made the original connection to pin 64 high Z, along with the accidental connection to pin 48 nextdoor, and now I see signals being output to the HDMI. (It’s too tight to try and solder in resistors to test the proper LVDS simulation as described in the Using Differential I/O (LVDS, Sub-LVDS) in iCE40 LP/HX Devices annex.) I used the pin constraints editor in IceCube and it added some info to the pcf which may have helped get things working ? :
set_io hdmi_p[0] 139 -io_std SB_LVCMOS
set_io hdmi_p[2] 144 -io_std SB_LVCMOS
set_io hdmi_p[1] 142 -io_std SB_LVCMOS
set_io hdmi_p[3] 137 -io_std SB_LVCMOS
set_io clk100 49
For the next version, I think I need to include resistors to simulate the LVDS signals and I should connect the clock at one of the dedicated input pins which seem to be optimized for this.
Just realizing now that all the code I have been looking at involves using a dedicated chip (the TFP410 @ 8 euros) to convert the FPGA signals into. From the blogs it also seems like this solution works for some TVs but not all, and is better for monitors. Perhaps I should include a VGA + HDMI in case this is just too finicky. Looking at the OLIMEX VGA PMOD board, it looks like I only need a few resistors to get VGA working : https://www.olimex.com/Products/FPGA/iCE40/iCE40-IO/open-source-hardware
I am looking for more ressources on DVI with Ice40 FPGAs and found these :
  • https://projectf.io/posts/fpga-graphics/
  • https://github.com/lawrie/hdmi_examples/tree/master
The fact that the code above (before my modifications at least) is being used on another ice40 makes me think it should work in the end.
**********
 

Technische Universität München Lecture

I have a month to work on a 45 minute lecture on my work at the Technische Universität München. I will also be doing a lecture at TU Darmstadt in November. I would like to use this opportunity to try to bring my video experiments into focus and incorporate it into my previous time-lapse projects.

This could take the form of a video series of me playing the prepared video buffer, possibly with explanations about what is causing what effect and demonstrative images / videos ? It could be contrasted with a “typical” workflow using the constraints of a software platform like photoshop? I could prepare this a similarly focused investigation of how the prepared piano altered sound, how Sonia Sheridan altered the photocopier, Paul Schafer made custom concrete music machines, etc.

EDIT* : I had a try !

  • It’s kind of long and I also need to get a better top view.
  • Adding text to describe what’s happening ?
  • I also see that when I’m turning knobs the device is kind of hidden. I haven’t really designed the interface to be playable and to look good and be legible while being played.
  • Looked into some other examples of video synth top down videos :

This is making me think more about the physical presence of my devices, and how I could incorporate more mechanical parts – instead of purely making electronics. I may have to play the game a bit more, make things that look like what they do and help people understand the associations I’m trying to make.

I could have micrometer heads for the potentiometers :

I could have fiber optic cables too :

Fiber Optic Cable Connectors & Assemblies | Clearfield

I think if I every try to make a product though I would need to team up with someone who has skills I don’t.

***

Why make hardware ?

  • it can be analog and digital
  • it’s faster at doing things with video than software
  • it can be custom
  • it has a live-playable interface

***

What effects am I creating ? (check out Premiere to see what kinds of effects exist).

  • Recording and playing things back at different speeds (video transposition), assigning to different color channels
  • desynchronizing recordings with the screen sync so that they jump around
  • recording videos side by side in memory so that they bleed over one another.
  • Video collage and montage composer (video sampling, video looping), video plastifier, étude II, micro-montage, noise research, play, do and see, polyvideo layering, defamiliarizing of the image + reflecting the mediascape we inhabit, video as “palpable”, “nontheoretical”, and “experiential” (quotes from musique concrete wiki).
  • The structure of the videos is based on the indexicality of the medium (the SRAM and how it stores). So the recording technique is also the synthesis technique.

    Struggling to represent the painterliness of the raster videos without showing them as a video. It is completely different from my experiments with lines and triangles, and is less intuitive for me. An attempt at a kind of chronogram of a video :

    It gives some idea of the range of images I guess?

    Here are some notes I took about a year ago after visiting a painting expo that relate to my painterly video experiments :

    • Layering
    • Contour
    • Surface
    • Saturation
    • Flow vs. Choppiness
    • Roughness, relief 
    • Edges versus centers
    • Movement vs stasis 
    • Enriching of detail
    • Abstracting, cosmic making
    • Fine lines versus coarse
    • Exposure 
    • Color fields
    • Texture
    • Deep friedness
    • Films of cows, ocean. Stills of still life? Flowers, birds, drapes folding, mold, fruit, bones
    • Color mixing vs melting vs meeting
    • Paint viscosity (runny vs clotted)
    • Direction of brush strokes 
    • Contour
    • Focus direction in canvas
    • Translucent flesh, shine vs glow from interior, waxiness 
    • Graininess 
    • Composition, color pairings and form
    • Foreground displaced to background vice versa 
    • Meeting pattern planes 
    • Lighting and shadow
    • Illusion of depth
    • Cloudiness 
    • Turbulence

    Check out this “glitch” video artist Jacques Perconte that Marc shared with me : https://www.youtube.com/watch?v=8_Xhu9Vx5XM

    He works, since the 1990s, with compression and achieves a painterly, impressionistic effects and exposes them on immense projection surfaces.

    Check out also Tauba Auerbach’s work :

    Tauba Auerbach

    Tauba Auerbach at the ICA | Inside LDN

    Jack Whitten :

    Jack Whitten: Artwork Survey: 1970s | Art21

    *************

    Some quotes from Art21 series :

    James Turrel – what you are perceiving is perception itself. We don’t receive the world around us we create it.

    Jeff Wall – Art gives you an experience that alters something, it doesn’t tell you or convince you.

    Jeff Wall – When I started photography there were potential energies in the medium that weren’t being realized.

    Roland Barthes – The punctum points to those features of a photograph that seem to produce or convey a meaning without invoking any recognizable symbolic system.

    Olafur Eliasson – Art provokes a negotiation : why I am seeing this the way that I am seeing it, what does looking mean? Instead of questioning the object you are questioning yourself. Art offers the opportunity for self-evaluation.

    Tauba Auerbach – I want to learn things all the time, I want to understand the patterns behind things. I experience science through craft. With craft I try to cultivate sensitivity in a practiced, purposeful way. If you work with marbling you know just as much about viscosity and flow than a scientist, through your fingertips in a different way.

    Tauba Auerbach – Ideally I want to make an image that has a tiny effect on all the future images that you see.

    Tauba Auerbach – The pursuit of the sweet spot, cultivate the place of boundaries, limits of fraying, not hard edges.

    Cindy Sherman – I don’t know what I’m looking for until I see it.

    Richard Serra – Artists invent strategies, tools, techniques, that allow themselves to see in a way they haven’t seen before to extend their vision beyond the standardized classic reflex actions. These help us to see inside what we’re doing so we don’t get into a lock step notion of how to do what you do.

    Louise Despont – If you’re always making work for someone, and not for yourself, maybe you don’t let yourself make the mistakes that are necessary.

    Louise Despont – Each drawing is a series of tiny discoveries, it reveals/unfolds the drawing from total control. I own at most 1/4 of the drawing. The rest is something else, this is what’s exciting.

    Louise Despont – It’s best explained in the drawings, words are clumsy to describe something like the concrete feeling of spirituality.

    Liz Magor – My Studio is a space to reconcile dissonance, no one knows I’m here. When I’m not in my studio I want to be in my studio working. My tools are rudimentary. I’m here for pleasure but it’s not fun. Everyone should have a studio for mental health. I can filter out the noise and see the ever present under the radar stuff.

    Liz Magor – I’m not an animist but objects have stuff in them that comes out. I try to resurrect these objects from the netherworld.

    Liz Magor – The slowness of the material process matches the slowness of my thinking process.

    Liz Magor – I’m creating an experience for looking.

    Liz Magor – I give myself my own program, I give myself my own assignments. And art is the choices I make.

    Liz Magor – Maintaining the conditions for this production, which is not very logical, uncalled for. No one is asking me to do this, I’m barely asking me to do this. To do this I have to overlook my making with the journey of the things into the world.

    Liz Magor – After the casting I unwrap it like a little gift, there are surprises.

    Elliott Hundley – This photoshoot is so elaborate but not because I want a certain effect, because I want to not control the effects, and have a layer of unexpected results. In relinquishing control, the piece gives me something back I didn’t expect.

    Jack Whitten – I’m not a narrative painter.

    Jack Whitten – I built a device to move large amounts of acrylic paint in one gesture.

    Katherina Gross – Painting is not linear. The synchronicity in painting is compelling for your thought process. I’m trying to grasp some of those fast thoughts that are moving through my brain.

    *************

    Reading about the history of video synthesis.

    From https://museumzero.blogspot.com/2013/12/its-all-baseball-nam-june-paik-starts.html)

    Nam June Paik sees Taoist energy in working with the flow of TV video :

    “To receive simultaneously the parallel flows of many independent movements is, as Paik pointed out at the time, a classical Taoist way of meditating: by becoming aware of everything going on in the present, you discover eternity right now.” 

    “I love Chinese history, surprise, nonlinearity.  You know what judo means?  A way to be soft.  You let other guy do all the work.  I think in some Oriental way.  In TV I try not to be boss, to stay as small as possible.  So that seems to work. “ 

    “So then when I started TV, the best decision I made in life is not really to go into TV, but to do work inside TV.”

    “Imagine everything that exists is flowing, like the tao, in a perpetual motion, with endless waves, like the ocean.  We come from it; we go back to it.  Whatever surges forward falls back, so Lao-tse, who wrote the Tao Te Ching (On the Nature of the Way), urges us not to try too hard.  Relax; be like a baby; follow whatever path presents itself.  That is the way. ”

    Not striving to fit yourself to some preconceived ideal, like a Buddhist or a Confucian; simply being, following breath wherever it blows.  In this sense, the television signal is like the tao; endlessly variable, continually reversing itself, dying, being reborn, it is never idle, yet it is so vast and perpetual that it often seems calm as the sea.

    Beginning with whatever live programs came along, distorting them, then recombining his distortions like waves on the ocean surface, Paik created an indeterminate and endless show for the Galerie Parnass, in Wuppertal, Germany, in 1963.  

    From Scanimate: The Origins of Computer Motion Graphics :

    • This is about the history of television, these were the first ways to put text and make graphics on screen (Media Archaeology!). Nowadays visuals are gratuitous. What did we lose in the transition to digital ? The imperfections, the proximity to the functioning.
    • Had a role in music videos, and news segments, so was part of culture.
    • “Blooming” is the term for the glowing edges in CRT Scanimate.
    • It’s real life artefacts. It’s like exploding scale models instead of GCI.
    • They made cookbooks with the recipes of different effects that created while working with clients.

    From https://wearethemutants.com/2018/01/09/a-sloppy-machine-like-me-the-history-of-video-synthesizers/

    Like its close temporal and conceptual counterpart, the audio synthesizer, the video synthesizer was created iteratively by academics, artists, and tinkerers, then eagerly snatched up by the world’s biggest media producers once prototypes had proved their power and versatility.

    • Started with experimental musicians like John Cage and la musique concrète.
    • Early pirate TV station in NYC.
    • Amiga supplants the Scanimate and analog synths.
    • The 1967 Portapak release and it’s importance for activism and experimental art.
    • Video comes from the root video of Latin video (“I see”).
    • There is a relationship between images and waves  :

    https://upload.wikimedia.org/wikipedia/commons/6/61/P-type-chirplets-for-image-processing.png

    CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=641492

    This is so hard for me to understand but this somehow relates to chirping also :

    Published in IEEE International Conference on Acoustics, Speech, and Signal Processing 1992

    Time-frequency perspectives: the ‘chirplet’ transform

    Steve MannS. Haykin

    From article about DCT for image compression :

    undefined

    By Drummyfish – Own work, CC0, https://commons.wikimedia.org/w/index.php?curid=77608151

    More cool matrix math image modifications here : https://en.wikipedia.org/wiki/Digital_image_processing

    Also this website which describes it all visually ! https://setosa.io/ev/image-kernels/

    From Video Art : An Anthology :

      • The synthesizer let’s you see things that exist only in the mind’s eye.
      • visual ingredients
      • video synthesizers churn out…images based on their own electronic structure.
      • We make the image with our eyes and brain. It’s psycho-visual
      • video as concretized imagination.
      • video is surreal, the images are ephemeral products of micro electronic pulses.
      • “electronic imagery”
      • video is a medium which works with time

    Au commencement était le bruit, la poésie électronique de Steina et Woody Vasulka | sonore visuel

    The Vasulkas

    *************

    Here is an attempt to describe what could be a model of a potential “practice” :

    *EDIT* This should include me blogging ! Maybe add a RESEARCH and/or DOCUMENTATION phase ?

    *******

    Check out this pyramid of types of work :

    Bloom's revised taxonomy organized as a pyramid of learning levels with explanations of each

    I feel like my project is about analysing (and curating), I’m not sure if I take a real position.

    *******

    Check out this amazing NIME article called The Concentric Sampler: A musical instrument from a repurposed floppy disk drive by Timothy Tate about “the redundancy and physicality of magnetic recording media” which utilizes “time-based granular synthesis” and lo-fi:

    https://nime.pubpub.org/pub/uh76shf0/release/1

    Some quotes :

    • Physical media offer an opportunity to “foreground the physical medium as a tool for musical expression.”
    • “The deterioration of old magnetic tape as it is looped, defining a … musical structure.” The “failure of the medium is in focus, rather than the mechanism.”
    • “as soon as something’s on tape, it becomes a substance which is malleable and mutable and cuttable and reversible in ways that discs aren’t.”
    • “This study emphasises working within a medium’s limitation, rather than prescribing a compositional framework or sonic agenda upon it”
    • Motivation to “foreground musical and technical possibilities…and generative sonic potentials…and novel, unique expressive and
    • compositional possibilities”…to be “discoveredexplored”
    • The device is a “performable instrument and a generative sonic tool”
    • “Rather than focusing on the authenticity of the sound reproduction, the Concentric Sampler draws focus to the byproducts and the resultant indexicality and generative sonic possibilities of the floppy disk as a medium.”
    • “the term ‘musical expression’ here places value on the ability to shape and define a musical grammar from the indexicality of themedium and mechanism.”
    • subverting traditional modes ofexpression
    • “Each section is accompanied by a demonstrative video” !!!
    • The live playable instrument can “achieve the dissociation of pitch and time
    • “imperfections in … reproduction”
    • “possibilities within a framework of … making”

    Now following up on some of the references from this article:

    • You can think of an instrument as a framework that has a predisposed range (affordances). Our tools provide a certain range of suggested usages. Some things are easier and some things harder to do with an instrument, this is the instrument’s spectrum. If you stay within those ranges, you accept the silent grain of the instrument. If you make an unusual tool then, do you risk finding yourself in an unusual affordance ? (J. Mooney) Could it be possible to make videos subtractively, instead of additively ?
    • From New Media Reader : The different between representation and simulation. P.18″Digital media process the physical properties of the input data, light and sound waves, are not converted into another object but into numbers; that is, into abstract symlbols rather than analogous objects and physical surfaces. Hence, media processes are brought into the symbolic realm of math rather than physics or chemistry. Once coded numerically, the input data in a digital media production can immediately be subjected to the math processes of addition, subtraction, multiplication and division…” AND compressed AND manipulated more easily than analogue forms because they are more mutable than objects. Also easy access and quick movement of the data of an enormous mass of data. This causes the materiality of the world around us to become unsteady…The televisual
    • Because everything else is also digitized, there is a “convergence of previously discreet media forms, now a new fluid area of media decentralized production and consumption. Remediation, Multilinearity.
    • Hand-made videos. Exploring the boundary between hand tools and large-scale machines which is a distinction Marx makes P.91.

    Check out these Bauhaus era artist’s work with the audio band in video :

    Paul Schaeffer (coiner of the “club d’essai“) designed specific tools like the morphophone and phonogène for modifying audio for musique concrete :

    *******

    Watching ENSCI diploma presentations I’ve thought about how nice the sequence is : first you write something that explores a topic and cites thinkers on the subject, and then you work on a design project that relates to this somehow. Also looking back at some videos, there is already a lot of content I have produced that I could try to learn from ! Like that Amsterdam-based artist told me, I could also focus on using my tools.

    I am also doing a synth workshop in late September at Villette Makerz but I’m not sure if I can connect to that or not here. *EDIT* an FPGA board that generates patterns based on audio input is a GO !*

    I also want to make a next FPGA board which will be a software reconfigurable device so that I can move to verilog for the summer instead of making a new board for every experiment. Not sure if this could also take the form of a simple video synth for Villette Makerz or at least a simplified version perhaps.

    *******

    Some quick looking in to GPUs :

    GPUs are all about direct memory access (DMA) not mediated through the CPU. A thought about the FPGA board – perhaps I should first have Arduino mess with the clock while playing back / recording something on the 16MB board (but I’m limited to the number of pins for address and I/O – it would essentially be a counter that could change in frequency on the fly)? Having memory connected to the screen (a screen buffer) and modifying it is the fundamental computer display setup. From 1951 a memory pattern on CRT :

    It would be cool to experiment with sprites and copying parts of memory from one bank to another too like a blitter https://en.wikipedia.org/wiki/Blitter .

    It looks like what makes shaders cool is that they are programmable and have their own code languages now. Before shaders there were hardware rendering pipelines called fixed-function. Different units would be responsible for specific functions. It seems like these units would take in vertex data then output pixel colors.

    I looked in to how to do matrix multiplication in hardware. It actually seems to be more natural as an analog circuit with resistor arrays. It can also be done by multiplying two 2-bit binary numbers using this kind of logic setup :

    **********

    I am becoming more and more curious about the difference from having a screen buffer that is written to during the blanking period and having a massive bank of memory that can be recorded to like in the 128Kbit. Check out these articles about how writing and reading to video memory is dealt with in different systems :

    https://en.wikipedia.org/wiki/Tiled_rendering

    https://en.wikipedia.org/wiki/Multiple_buffering

    https://en.wikipedia.org/wiki/Vertical_blank_interrupt ,quoted from : 

    During the vertical blanking interval, the driver orders the video card to either rapidly copy the off-screen graphics area into the active display area (double buffering), or treat both memory areas as displayable, and simply switch back and forth between them (page flipping). [The two buffers are called the front and the back buffer] Some graphics systems let the software perform its memory accesses so that they stay at the same time point relative to the display hardware’s refresh cycle, known as raster interrupt or racing the beam.” [i.e. you can also draw things during the horizontal blanking interval]

    **********

    The Real-Time Corrupter is fascinating https://redscientist.com/rtc . The kinds of memory modifications it allows for are fascinating and far more dynamic than static, text-based find-and-replace experiments I’ve done in workshops. Looking at this video I learned some cool stuff (https://www.youtube.com/watch?v=n9HS6zftuSk&list=PLItZ3jvJKD7rnoxmqJJ0B5E1B9_WW9L5E&index=2). For instance, copying values from one address (in video RAM, scrolling backdrops memory space a.k.a. “nametables”, NES RAM, ROM etc.) and then reapplying them to another address every frame (called piping) or just one time, the ability to isolate specific effects with the sanitize function. It can generate noise between certain values, or shift values up or down on (called tilting), listen to a value and then reapply it after a fixed number of frames, freezing the current value somewhere for future frames, replacing values intelligently with values in certain sets (for 3D glitching). It’s like performing brain surgery while the patient is fully conscious and telling a story. All of these memory transformations could be applied with the FPGA board !

    **********

    In a similar spirit, this game called Code War involves creating a program that competes with others to write to all of the memory space. There are competing strategies (quoted from https://corewar-docs.readthedocs.io/en/latest/corewar/strategies/) for warriors :

    Rock - a warrior which rapidly bombs the core with dat instructions
    Paper - a warrior which replicates, creating multiple, parallel copies
    Scissors - a warrior which scans the core looking for other warriors

    The battle is visualized in a memory grid (https://corewar-docs.readthedocs.io/en/latest/corewar/visualisation/)

    https://upload.wikimedia.org/wikipedia/commons/c/c2/Core_War_PMars_Screenshot.png

    You can simulate and battle warrior code here : https://crypto.stanford.edu/~blynn/play/redcode.html

    **********

    Visualizing memory access in time. From https://bling.kapsi.fi/blog/x86-memory-access-visualization.html:

    *********

    Some thoughts on HCI from people at work :

    it’s research if it follows scientific method and has possible applications.

    Find your peers, try to publish in their journals.

    The idea of publishing is to get feedback from your peers.

    If you make a pedagogical tool, then you could test how effective it is at helping people learn.

    Based on this conversation, I thought about how I don’t necessarily want to promote engineering education and that I always want to be on the design/art side of things. I also have learned that I find doing something I already know how to do less exciting, and so making simple kits or small series of artworks that are guaranteed to work for days on end, is not always super rewarding for me intellectually. This leads me to the current conclusion : I want to teach and then do a kind of artistic research on the side. I should then keep building my teaching career and try to get expos of my work. I am still trying to figure out how exactly my artistic research should be communicated (through articles in design magazines, through conferences with expos connected to them?).

    **********

    I am preparing a solar workshop at Villette Makerz based on the simple solar engine with optimized SMD components. The idea is an art bot that will draw, paint, in the sun. I am working on testing the various combinations of solar panels, capacitors and voltage supervisors.

    We are also making a version 2 of the video synth modules which are all Eurorack compatible in terms of dimensions, use 3.5mm audio jacks, the eurorack power supply. The idea is that the modules be both manual and automatable for the purpose of demos and to be didactic for students learning about analog electronics.

     

    Marc is doing a great job reimagining this project – he is good at compromising and imposing the vision of the final thing on each step of the construction. I am, in contrast, driven astray I think by my fascination by what “the machine itself wants to express”…

    ********

    Finally getting around to testing the Arduino-controllable analog switch to activate record or READ mode on the SRAM 16MB board. The idea is to test taking a recorded video and then doing some bit manipulations with it and saving it back to the memory. Predictably though, I’m having issues just writing anything to the thing…

    I/O pins on Arduino 0-7
    CLK on Arduino 12
    REC on Arduino 13 connected to analog switch connecting the WR pin on SRAM to either VCC or !CLK
    
    unsigned long memory; //total number of 8bit words on the 16Mb SRAM = 2048000
    
    const byte IO_0 = 7; 
    const byte IO_1 = 6; 
    const byte IO_2 = 5; 
    const byte IO_3 = 4; 
    const byte IO_4 = 3; 
    const byte IO_5 = 2; 
    const byte IO_6 = 1; 
    const byte IO_7 = 0; 
    
    void setup() {
    //Serial.begin(115200);
    pinMode(13, OUTPUT);
    pinMode(12, OUTPUT);
    
    pinMode(IO_0, OUTPUT);
    pinMode(IO_1, OUTPUT);
    pinMode(IO_2, OUTPUT);
    pinMode(IO_3, OUTPUT);
    pinMode(IO_4, OUTPUT);
    pinMode(IO_5, OUTPUT);
    pinMode(IO_6, OUTPUT);
    pinMode(IO_7, OUTPUT);
    
    //WRITE
    while(memory<= 2048000){
    memory++;
    
    // if (memory%10000==0){
    // Serial.println(memory);
    // }
    
    if (memory%5==0){
    PORTD = B11110000; // the IO pins. simple pattern test.
    
    }
    else{
    PORTD = B00001111;// the IO pins. simple pattern test.
    }
    //WRITE MODE
    PORTB = B11101111; // PIN 12 ARDUINO CLK goes LOW/HIGH
    PORTB = B11111111; // PIN 13 ARDUINO WR STAYS HIGH
    
    }
    // Serial.println("finished writing");
    }
    
    void loop() {
    pinMode(IO_0, INPUT);
    pinMode(IO_1, INPUT);
    pinMode(IO_2, INPUT);
    pinMode(IO_3, INPUT);
    pinMode(IO_4, INPUT);
    pinMode(IO_5, INPUT);
    pinMode(IO_6, INPUT);
    pinMode(IO_7, INPUT);
    
    digitalWrite(IO_0, LOW);
    digitalWrite(IO_1, LOW);
    digitalWrite(IO_2, LOW);
    digitalWrite(IO_3, LOW);
    digitalWrite(IO_4, LOW);
    digitalWrite(IO_5, LOW);
    digitalWrite(IO_6, LOW);
    digitalWrite(IO_7, LOW);
    
    //PIN 13 REC IN LOW READ MODE
    PORTB = B11011111; // PIN 12 ARDUINO CLK goes LOW/HIGH
    PORTB = B11001111; // PIN 12 ARDUINO CLK goes LOW/HIGH
    }
    

    Not working…

    unsigned long memory; //total number of 8bit words = 2048000
    byte cell; // store the word at this address
    
    void setup() {
    
    //PD0 - PD7 are IO
    pinMode(13, OUTPUT); // REC - PB5
    pinMode(12, OUTPUT);// CLK - PB4
    
     while(memory<= 2048000){
        memory++;
    //READ
            DDRD = B00000000; // all IOs in INPUT
            PORTD = B00000000; // no pull-ups
    
            PORTB = B11011111; // WR stays LOW + CLK HIGH
            delayMicroseconds(10);
            cell = PIND; // read the cell at this memory address and store it in the variable cell
            delayMicroseconds(10);
            PORTB = B11001111; // WR stays LOW + CLK LOW
            delayMicroseconds(10);
    
    //WRITE
           
            DDRD = B11111111; // all IOs in OUTPUT
    
            PORTD = ~cell; // write  a transformed cell back to memory
            PORTB = B11111111; // WR stays HIGH + CLK HIGH
            delayMicroseconds(10);
            PORTB = B11101111; // WR stays HIGH + CLK goes LOW
            delayMicroseconds(10);
      }
    }
    
    
    void loop() {
    //READ MODE TO SEE WHAT WE HAVE IN MEMORY
            PORTB = B11011111; // WR stays LOW + CLK HIGH
            delay(500);
            PORTB = B11001111; //  WR stays LOW +  CLK LOW
            delay(500);
    }
    Not working either...

     

    ****

    I reread the manual for the SRAM and found that in the writing mode where OE is held LOW, you need to not force the SRAM IO pins for a duration of 10ns after WE goes low or else the “previously read data will drive the IO buffer”. So I need to put the IO pins into HIZ for this period of time.

    I also found that the SRAM needs a startup time of 150ns after the voltage has settled. This needs to be added in the setup.

    Looking at the 74HC590 datasheet, I am realizing that there is a significant propogation delay for the CLK to convert into a new address on the ADD pins. I can’t figure out the exact delay but the highest delays I see for any step in the pipeline are in the 100s of ns. To be conservative, after the CLK goes HIGH and WR LOW, I’m adding a big delay so that the address lines can catch up.

    *EDIT* I forgot, the SRAM is 3.3V logic level so I need a level shifter or I’ll damage it !

    However, even with that, still no dice ! Very curious…

    *****

    I just tried some different op amps with the Serpentin 128KB board.

    Recorded some different speeds in the same recording which was cool.

    Here are the things I’ve played with :

    1. Recording versus playing
    2. Clock speeds
    3. Amplifying input / output and threshold
    4. Count resetting, memory chunk selection
    5. The memory size
    6. The bit width
    7. combining several recordings

    What I want to play with :

    1. editing tiny parts of memory, possibly based on the contents of the memory
    2. moving through the memory non-linearly, and at different speeds/accelerations
    3. copying parts of one memory to another  

      ********

    FPGA synth

    Heading towards a more reliable, deployable and software-leaning approach (but not so much about automated choreography as with previous atmega boards as augmented live playable machine for manual performances) to working with video now.

    I am also trying to be a bit more strategic and attempt to think ahead a little bit beyond the one board one experiment situation. It takes a long time to trouble shoot a single board and learn all the lessons from it, I have to give each board the time it deserves and I need to be perhaps less productive and more thorough.

    I am also coming to the awareness of what is my scope with this next board :

    • I won’t be doing challenging engineering things (like implementing different ways of programming the same FPGA, interfacing with differential pair protocols like HDMI) that have no impact on the images and take loads of time to do.
    • These are boards for experimenting and live playing, so they also need to have controls on the board.
    • I also need to think about safety, avoiding the possibility of easily making short circuits and damaging the board.
    • I’d also like to move back to color, and away from the intense limits of exclusively 1bit resolution.
    • I want to keep removing superfluous cables and adapters too, this one will have only a VGA out.

    I made a map of my prototypes so far for this project :

    It’s been around two years I’ve been working on this !

    After talking with Zach at work, his idea was to show not just the screen but also me turning knobs etc. Here’s what this could look like :

    Or,

    …or,

     

    It would be nice to have a computer interfaced oscilloscope to record the signals.

    *****

    The most plug and play option would appear to already exist : a tiny raspberry pi zero can already run Processing scripts and control small screens https://learn.adafruit.com/processing-on-the-raspberry-pi-and-pitft/processing !

    Here’s a good intro to making simple patterns with processing : https://processing.org/examples/

    We would be more in the zone of software video synth : https://learn.adafruit.com/feather-rp2040-dvi-video-synth

    Also seem to be companies making just this kind of thing : https://store.excamera.com/

    Arduino talks to the FPGA by SPI as if it were a RAM space. https://excamera.com/files/gameduino/synth/doc/gen/poster.pdf

    Design / Engineer friend Paolo Salvagione pointed me to Configurable mixed-signal ICs. It appears to be like an FPGA but for mixed analog and digital circuitry and is configured in design software.

    There is also the world of ASICs and the google open-source silicon project https://developers.google.com/silicon

    *************

    My project was originally about slowing down computer processes and representing them in space. Now I just seem to order things on Amazon and design increasing numbers of PCBs. It seems that I have so little time to do the art in the end because of how much investment the technical stuff requires. How could I get back to my original project here ?

    My project also had a collection of related techniques :

    • Try to free machines from their corseted, factory settings and reveal their full range of expression that would otherwise just exist in a parallel unseen dimension
    • Try to show our files from the perspective of / through the eyes of the machines that are processing them.
    • Curate series of abstract formal compositions which emerge from figurative, architecturally-themed or culturally iconic ones.
    • Try to describe the behaviour / idiosyncracies of algorithms and make them tangible
    • Isolate specific moments of machine-to-machine interface in a larger system
    • Get one’s hands inside the black box, and make prepared machines which expose their parameters
    • Try to rebuild electronic systems based on help from the DIY internet and then hope to stumble on something unintentional
    • All the while emphasize the materiality of technology
    • Trying to go super low-level and avoiding abstract computer “visualizations”
    • Exploring the link between visual chaos and harmony, that sweet spot of medium entropy.
    • Riffing off of the music synthesizer movement of knobs and playful electronics interfaces and its anti-theory vibe
    • Exploring the surreal, bizarre space of the computational unconscious
    • Do “artistic research” projects that are educational, at least for me
    • play with form versus content

    I wonder if the pixel based screen is not really appropriate for my methodology. It’s the opposite of over-looked and black boxed. It’s an obsession for an entire culture. It also does a pretty good job of “representing” what happens inside the computer already. It doesn’t really need my help !

    ********

    I also need to do a debrief on this leg of the video synth project. What have I learned ?

    Technical stuff :

        • How to make and debug PCBs
        • To work with video + SRAM with counters as well as some op amp circuits. The difference between digital and analog in the video context.
        • To work with the VGA protocols, about resolution and brightness of the image.
        • I learned about oscillation, the difference between KHz and MHz in the context of video and what sampling is.

    Stuff about media representation

        • some aspects of the nature of visual memory, how some of our sensory apparatus work at different speeds
        • the curious experience of “searching” for an image (like when messing with ADC knobs and CLK speeds).
        • what is required to identify / recognize and image or scene, how much resolution and shape
        • Deconstructing the illusion of television by interacting with its materiality and mutability
        • Repeating historical art explorations with television (see Sans Soleil – Chris Marker)
        • synchronizing the data with the frame of the image is a key part of the illusion of video. If you mess with this suddenly the video frame becomes a malleable object. If it is desynchronized, the image is out of frame and will jump around with the SRAM recording. If you change the speed of recording or of playback you can zoom.
        • Layering of different images in a palimpsest can create textures from them.
        • I’ve made some nice abstract pattern discoveries through knob twisting.
        • Exploring the gap between legible figurative image and abstract patterns, contours, fields,
        • the texture and grain of data at various scales
        • the connection between video and abstract field painting

    What does it mean to be trying to make super simple hardware video filter in the age of AI generated video and images ? How is this activity relevant ? I feel like I’m looking for low hanging fruit here but I’m not sure there is any left. Also, the time it takes to make a single experiment in hardware is astronomical compared to the software option…

    I think the project started off about the screen itself, how to send signals and display them. At some point it became clear that the screen just displays data stored in memory.

    In this spirit, I could try to represent memory access patterns : https://en.wikipedia.org/wiki/Memory_access_pattern Or the patterns that memory is refreshed in : https://en.wikipedia.org/wiki/Memory_refresh

    http://www.overbyte.com.au/misc/Lesson3/CacheFun.html

    I could also sample images and then modify them algorithmically? But it kind of ends up looking like simple Photoshop filters. It would have to be modified in some way based on the way the image is stored in the memory ?

    Check out this image stored in DDR ram decaying over time from J. Alex Halderman’s paper : https://jhalderm.com/pub/papers/coldboot-sec08.pdf

    Also it seems like different DDR has different decay rates (from A Trustworthy Key Generation Prototype Based on DDR3 PUF for Wireless Sensor Networks https://www.researchgate.net/figure/DRAM-cells-decay-feature-with-power-switch-interval-time-of-120-s-a-DDR3-device-1-b_fig3_263586301):

     

    For comparison, check out the same Mona Lisa image sent through the air and damaged by the earth’s atmosphere :

    undefined

    ********

    I’ve never thought of this before but I guess I could generate a simple arduino code, and then take the .hex file and glitch it with any of the glitching techniques I’ve been using and see what it puts on screen.

    I could also test overclocking / overheating the atmel and seeing how they collapse !!

    ********

    I should also finish the boards I’ve already designed and had made, they offer learning opportunities and possible discoveries ! The bucket brigade, the digitally-controlled pots (meh), and the band splitter (*EDIT* completed !) are the three that are left from that series. Also the Palimpsest.OS 2 board when controlled by microchip – especially if I can get the sync working ! Of course I have the new 128Kbit memory board (*EDIT* all done !) once I get the parts too and then a final (?) FPGA v2 board.

    ********

    I am still interested in exploring FPGAs and getting my hands in the tech to possibly stumble on cool stuff though so here is a second attempt at a video FPGA board based on the iCE40HX1K-TQ144 to output HDMI, DVI, VGA, and composite video.

    For generating verilog, there is migen for python 3 (https://github.com/m-labs/migen). I’m going to try a super simple thing in Verilog first to get a feeling for it. 

    I am learning verilog here : https://hdlbits.01xz.net/wiki/Main_Page

    It looks like generating HDMI is doable even though there is a difference between LVDS and TMDS (involving possibly 100nF series capacitors ?) :

    Here is the official guide : https://www.latticesemi.com/-/media/LatticeSemi/Documents/ApplicationNotes/UZ/FPGA-TN-02213-1-7-Using-Differential-IO-LVDS-Sub-LVDS-iCE40-LP-HX.ashx?document_id=47960

    https://www.fpga4fun.com/HDMI.html

    blackmesalabs.wordpress.com/2017/12/15/bml-hdmi-video-for-fpgas-over-pmod/

    https://github.com/hdl-util/hdmi/

    Different chips being used like the PTN3360D HDMI / DVI Level Shifter (IN STOCK!), a TFP410PAP TFP410 TI PanelBus™ Digital Transmitter (NO STOCK!),

    Question - Pluto IIX GCvideo help needed | BitBuilt - Giving Life to Old Consoles

    According to the datasheet, “The LVDS25E/subLVDSE differential output buffers are available on all banks but the LVDS/subLVDS input buffers are only available on Bank 3 ofiCE40 LP/HXdevices.” ***Those are INPUTS but there are no special OUTPUT pins.***

    I have replaced the LDO with was giving me trouble previously and am making this version USB programmable so it could be a useful for others as a cool video kit.

    *****

    Revisiting FPGA programming, here is where I got to last time :

    Here is my process for the FPGA programming so far :

    1. I signed up for an account at www.latticesemi.com.
    2. I got a licence for iCEcube2, put it somewhere easy to find and took note of the directory, and downloaded iCEcube2 and the Lattice Diamond software from here : https://www.latticesemi.com/en/Products/DesignSoftwareAndIP
    3. I plugged in the iCEstick and it blinked in a circular pattern. I also checked that it had a port under Device Manager (it had 2!). 
    4. I went into iCEcube2 then to Help > Tutorial to open a pdf called “Implementing the Design” and followed the following steps :
      1. Start new project (iCE40, HX1K, ?TQ144?)
      2. Add Design file iCElab.v and Constraint file iCElab.sdc and checked the Device Info.
      3. Run Synplify Pro Synthesis
      4. Select Implementation
      5. Add constraint file iCElab.pcf under Import P&R Input Files.
      6. Run Placer
      7. Check the Floorplan, package view, timing analysis, power estimation
      8. Generate the bitmap (.bit and .hex files) which is saved wherever the project was saved. (For instance C:\Users\Jonah\Desktop\FPGA LATTICE DEMO PROJECTS\quick_start\quick_start\quick_start_Implmnt\sbt\outputs\bitmap).
      9. Here is what everything should look like once finished :
    5. I then transitioned to Youtube for a detailed explaination of using Diamond Programmer with the iCEstick here : https://www.youtube.com/watch?v=Df9k1T0bHmA&ab_channel=Dom
      1. Launch Diamond Programmer and take the default options (or click scan and take those). Important to note that you must launch Lattice Diamond Programmer directly, not through Lattice Diamond, in order to find the iCE40HX1K chip.
      2. It will mistake the board for a JTAG interface and give the following errors : “Failed to scan board”, “Scan Failed – Creating Blank Programmer Project.”
      3. Now change the Device Family to iCE40, the device to iCE40HX1K, and under Program enter the following information :
        1. Change Access mode to SPI Flash Programming and now some other options appear. Select > Vendor: Micron, Device: N25Q032, Package:  8-pin VDFPN8
        2. Now load the bitmap (.bin) file and check that it has a non-zero datasize :
        3. Click OK and then click the green traffic light on the next to top row of icons. You should then see a completion message and have the program on your board :
        4. Presto !

    Just for info :

    For the actual pinout of the ice40 (which you can change in Pin Constraints Editor):

    ***

    And here is my attempt programming my own board with the Lattice Programmer.

    I followed the same steps as above but instead selected the HW-USBN-2B (FTDI) programmer. Important to note that you must launch Lattice Diamond Programmer directly, not through Lattice Diamond, in order to find the iCE40HX1K chip. Also note that you need Lattice iCEcube2™ Software, not just Diamond for some reason.

    Here are the color connections needed from the Lattice Programming Cables User Guide :

    The USB power and Board power lights should be on on the programmer and the Prog blue LED should flash a few times before the Done blue LED will flash and Lattice Programmer will display Operation: successful.

    I am taking the example LED rotation verilog .v code :

    module LED_Rotation(
    
        input  clk,
        output LED1,
        output LED2,
        output LED3,
        output LED4,
        output LED5
    
        );
    
                   reg[15:0] div_cntr1;
                   reg[6:0] div_cntr2;
                   reg[1:0] dec_cntr;
                   reg half_sec_pulse;                         
    
                   always@(posedge clk)
                                  begin
                                  div_cntr1 <= div_cntr1 + 1;
                                  if (div_cntr1 == 0)
                                                if (div_cntr2 == 91)
    
                                                               begin
                                                               div_cntr2 <= 0;
                                                               half_sec_pulse <= 1; 
                                                               end
                                                else
                                                               div_cntr2 <= div_cntr2 + 1;
                                  else
                                                half_sec_pulse <= 0;                            
    
                                  if (half_sec_pulse == 1) 
                                                dec_cntr <= dec_cntr + 1;                                          
                                  end                                                            
                   assign LED1 = (dec_cntr == 0) ;
                   assign LED2 = (dec_cntr == 1) ;
                   assign LED3 = (dec_cntr == 2) ;
                   assign LED4 = (dec_cntr == 3) ;
                   assign LED5 = 1'b1;
                                                         
    endmodule
    

    Under Tool > Pin Constraints Editor, we can change the pins activated in the code but mine is already set up connected to pin 99:

    I am soldering a second FPGA board. I noticed that the clock was not outputing anything, and also that the max temperature for the IC for reflow soldering is around 250°C. I am making sure to use the soldering iron “kissing” technique along with loads of flux applied.

    Reading through the datasheet :

    • Bank 3 additionally supports differential LVDS25 input buffers.
    • Each bank can have it’s own voltage level.
    • I may have to power the VCC, VCCIO_2, VCC_SPI, VCC_PLL, and VPP_2V5 (with a diode) even if I don’t plan on using them all just to get the device to turn on. (There is even a proper sequence to power them up in).
    • GNDPLL must NOT be connected to the board’s ground !
    • Bank 2 has two dedicated Input pins.

    ****

    FPGA BOARD ERRATA / DIARY :

    • 1.2V is connected to 5V throughout because of an EAGLE issue 🙁
    • I tried the voltage regulator 3 times and still no luck. *UPDATE* I tried a second 1.2V LDO that I ordered and it still reads 2.2V or so. No idea why this is happening when I can power the pin directly with 1.2V with my power supply no problem (therefore it can’t be a bad connection somewhere between 1.2V and another trace right?). Positive news is that the FPGA appears to have survived the over-voltage !!
    • Maybe I should give it a higher frequency oscillator, at least 25MHz, as I’m working with video?
    • I connected pin 9 of VGA to GND, it is connected to 5V on the signal side !
    • The GNDPLL should not be connected to GND.
    • The R2R ladder has a 270ohm going to ground instead of a 536 on each ladder.
    • Unclear which pins to plug where for programming – *EDIT* SOLVED
    • I had a hard time at first soldering the FPGA but then discovered a soldering “kiss” technique that was reliable and effective. For the clock, I melted the solder and then placed it gently on top.
    • I plugged it in with 2.2V instead of 1.2V and likely destroyed the chip the first time…
    • 0805 is doable and better for compact designs
    • I can’t find the name of the chip in the Target Device menu of Diamond Programmer. *EDIT* SOLVED : You need to open Diamond Programmer directly.
    • I need to get nicer boards if I am going to be working on FPGA boards, Aisler not inexpensively manufactured.
    • It seems like exploiting the parallelism of the FPGA could be interesting to explore. For this project it would probably be to logically mix several input videos together while transforming ?

    ***

    I’ve got it blinking at different frequencies !

    Now I want to generate some VGA signals as quickly as possible and start creating images by tweaking pre-made code like for VGAX.

    And here is demo code for the OLIMEX ice40 developement board which has RAM, DAC, ADC and VGA (but it needs a 100MHz clock) : https://github.com/OLIMEX/iCE40HX1K-EVB/tree/master/demo/ice40-io-video

    Also super simple (but uses a 25MHz clock) : https://www.fpga4fun.com/PongGame.html

    Here is the one I ended up using (takes a 12MHz clock and turns it into a 25MHz with the PLL) : https://github.com/imuguruza/alhambra_II_test/blob/master/vga/vga_test/

    Here is the key part of the code that actually draws on screen :

    module vga_sync_test(
        input wire clk_in,
        input wire reset,
        output reg r0,
        output reg r1,
        output reg r2,
        output reg b0,
        output reg b1,
        output reg b2,
        output reg g0,
        output reg g1,
        output reg g2,
        output wire h_sync,
        output wire v_sync,
        output wire led,
        output wire locked_led
      );
    
    wire clk_sys;
    wire display_en;
    //reg [9:0] h_count;
    wire [9:0] h_count;
    //reg [9:0] v_count;
    wire [9:0] v_count;
    assign  led = clk_sys;
    
    localparam  h_pixel_max = 640;
    localparam  v_pixel_max = 480;
    localparam  h_pixel_half = 320;
    localparam  v_pixel_half = 240;
    
    //Check if we can create RGB colors
    always @(posedge clk_sys) begin
      if (display_en) begin
        if (h_count < h_pixel_half
            && v_count < v_pixel_half) begin
          //Assign here your test color
          r0 <= 1'b0;
          r1 <= 1'b0;
          r2 <= 1'b0;
          g0 <= 1'b0;
          g1 <= 1'b0;
          g2 <= 1'b0;
          b0 <= 1'b1;
          b1 <= 1'b1;
          b2 <= 1'b1;
        end else if (h_count > h_pixel_half
                && v_count < v_pixel_half) begin
          //Assign here your test color
          r0 <= 1'b0;
          r1 <= 1'b0;
          r2 <= 1'b0;
          g0 <= 1'b1;
          g1 <= 1'b1;
          g2 <= 1'b1;
          b0 <= 1'b0;
          b1 <= 1'b0;
          b2 <= 1'b0;
         end else if (h_count < h_pixel_half
                && v_count > v_pixel_half) begin
          //Assign here your test color
          r0 <= 1'b1;
          r1 <= 1'b1;
          r2 <= 1'b1;
          g0 <= 1'b0;
          g1 <= 1'b0;
          g2 <= 1'b0;
          b0 <= 1'b0;
          b1 <= 1'b0;
          b2 <= 1'b0;
        end else begin
          //Assign here your test color
          r0 <= 1'b1;
          r1 <= 1'b1;
          r2 <= 1'b1;
          g0 <= 1'b1;
          g1 <= 1'b1;
          g2 <= 1'b1;
          b0 <= 1'b1;
          b1 <= 1'b1;
          b2 <= 1'b1;
          end
      end else begin
        r0 <= 1'b0;
        r1 <= 1'b0;
        r2 <= 1'b0;
        g0 <= 1'b0;
        g1 <= 1'b0;
        g2 <= 1'b0;
        b0 <= 1'b0;
        b1 <= 1'b0;
        b2 <= 1'b0;
      end
    end
    
    vga_sync vga_s(
          .clk_in(clk_in),         //12MHz clock input
          .reset(reset),           // RST assigned to SW1
          .h_sync(h_sync),
          .v_sync(v_sync),
          .clk_sys(clk_sys),       //25.125 MHz clock generated by PLL
          .h_count(h_count),
          .v_count(v_count),
          .display_en(display_en), // '1' => pixel region
          .locked(locked_led)      // PLL signal, '1' => OK
          );
    
    endmodule
    
     

    I would like to modify this code in the spirit of VGAX bytebeat-inspired video synthesis.

    I made sure to load the three dependent .v files and then changed the pin constraints in the .pcf as follows :

    set_io b0 76
    set_io clk_in 21
    set_io led 99
    set_io r0 81
    set_io b1 75
    set_io g2 91
    set_io r1 80
    set_io v_sync 87
    set_io b2 74
    set_io g1 95
    set_io locked_led 142
    set_io r2 79
    set_io reset 2
    set_io g0 96
    set_io h_sync 88
    
    

     

    It works !

    Just waiting for the LDOs to make it more practical to plug in. I will now test some actual patterns !

    ***

    Here is my first test bench with ModelSim ! Thanks to this tutorial from Nandland : https://nandland.com/tutorial-your-fpga-program-an-led-blinker-part-2/

    I am using ModelSim Lattice FPGA 2020.3 (which downloaded with either Icecube2 or Lattice Programmer?) and followed this PDF called
    Using Mentor ModelSim Simulator with Lattice iCEcube2
    (https://www.latticesemi.com/-/media/LatticeSemi/Documents/ApplicationNotes/MP2/Modelsim_AN006_Dec2020.ashx?document_id=50795)

    The steps to follow :

    1. Open a new project
    2. Click Add Existing Files (pick only the test bench verilog file) and then Close
    3. Now Compilation > Compile All
    4. Now Simulation > Start Simulation
    5. In the console type <<view wave>>…
    6. …then <<add wave * >>…
    7. …and a time period for example : <<run 100ms>>. (It takes us, ns, ms, and sec it appears)

    The signals are a little small and it is apparently possible to change this under Tools -> Edit Preferences, Wave Font and Footer Font…but when I try it crashes !

    Looks like printing to the console is going to be useful ! They work by using display like so…

    $display("0.5 seconds");

    …and then in the console area of ModelSim:

    run -all

    Here’s a simpler version of a tb for a 10 ps period of the following module :

    module dut ( input clk ); 
    `timescale 1ps / 1ps
    module top_module ( output reg clk );
    
          dut instance2 (.clk(clk));
    
               initial begin
               clk = 1'b0;
               forever #5 clk = ~clk;
         end
    endmodule

    ***

    Thinking about different ways of generating patterns on a screen :

    1. Screen coordinate based (plotting functions that take an input x and produce an output y)
    2. Time based + screen coordinate based (a counter t increases over time and modifies the function’s behaviour)

    Turns out FPGAs can’t do math like microprocessors ! To implement trig functions you need to build a CORDIC, which is like a computer to calculate functions.

    Then again there are some things FPGAs can do better than microcontrollers like cellular automata (one study I checked out said 36 times faster than a GPU and up to 2,800 times faster than software). HDL Bits has an exercise to build the rule 30, 90, rule 101, rule 184 cellular automata.

    (Similar to cellular automata, it’s possible to make a hardware psuedo random number generator using a linear feedback shift register : https://en.wikipedia.org/wiki/Linear-feedback_shift_register )

    Here was the solution to the rule 90 challenge that I had to look up in the end :

    module top_module(
    input clk,
    input load,
    input [511:0] data,
    output reg [511:0] q);
    
    always @(posedge clk) begin
           if (load)
               q <= data; // Load the DFFs with a value.
           else begin
              // At each clock, the DFF storing each bit position becomes the XOR of its left neighbour
              // and its right neighbour. Since the operation is the same for every
              // bit position, it can be written as a single operation on vectors.
              // The shifts are accomplished using part select and concatenation operators.
    
             // left                     right
             // neighbour              neighbour
               q <= q[511:1] ^ {q[510:0], 1'b0} ;
            end
        end
    endmodule

    Check out this processing sketch that is evocative of cellular automata :

    https://openprocessing.org/sketch/1879926 or sketch 1908904

    Could it be possible to do this live to recorded video with the FPGA and be able to vary the number of generations, speed, etc. ?

    Try changing the “rules” live (by clicking “random”) while this cellular automata scrolls : https://devinacker.github.io/celldemo/

    https://en.wikipedia.org/wiki/Cyclic_cellular_automaton

    Makes one think that you could make a video game entirely from these patterns being activated at different times and in different zones…Or a dedicated FPGA board that takes in audio and divides it into different bands, or other control signals directly, to control which rules are being used to generate the pattern + a bunch of knobs to change the speeds etc. It could be super minimal, just some knobs, an FPGA and an HDMI out.

    Hardware version of CA : tinkerings.org/2016/09/24/cellular-automata-explorer/

    Also check out rules that go beyond logic operations with neighboring cells and into modulo values : https://en.wikipedia.org/wiki/Cyclic_cellular_automaton

    I am now trying to use the test bench to better understand why this code isn’t putting any pixels on the screen currently.

    Here is my test bench. An important note is that variables that are not modified in an always or initial block should not be reg but wire instead.

    `include "rule90.v"
    `timescale 1ps / 1ps
    
    
    module rule90_tb();
    reg clk;
    reg load;
    reg [511:0] data;
    wire [511:0] q;
    
    rule90 DUT (
    .clk(clk),
    .load(load),
    .data(data),
    .q(q)
    );
    
    initial begin
    #10
    clk = 1'b1;
    #10;
    clk = 1'b0;
    #10;
    load = 1'b1;
    data = 1'b1;
    clk = 1'b1;
    #10;
    clk = 1'b0;
    #10;
    load = 1'b0;
    
    end
    
    always #10 clk = ~clk;
    endmodule

    This shows that the rule90 circuit is working. Every clock cycle it advances. If I could show one bit per pixel and refresh every clock cycle ?

    ***

     

    I’m getting some cool images :

    ***

    For the next FPGA board, I’m aiming for the following features :

    • It could have a handy mini screen (raspberry pi zero using DPI I/0 pins with video splitter to pass on the VGA to FPGA). I wonder if this isn’t a gimmick and not really in line with the “artistic research” aspect of my project.
    • FTDI chip for USB programming (this is too technical I have decided)
    • 100MHz oscillator with divider
    • 4x SRAM, possibly in two banks as I only have a total of 95 pins to work with
    • HDMI out, (possibly composite and DVI also ?). I wonder if this isn’t a gimmick and not really in line with the “artistic research” aspect of my project.
    • Some kind of basic interface ? (Knobs etc? But this would require an ADC unless I just use dip switches). One solution is to make hardware controls on the peripherals (clock divider, bit selections for incoming and outgoing signals, reset and CS sel on SRAM, etc.).
    • An atmega which can ask the FPGA to do things? Not sure this is necessary.
    • A fan and heat sink for the FPGA?? But this will hide it. Also a gimmick.
    • An FPGA with more Logic Modules – like 4K instead of 1K? But this doesn’t come in the easier to solder format…
    • A reset button ?
    • A fuse and reverse polarity protection !
    • microcontroller-accessed SPI FLASH so we can test moving between different types of memory. Except I haven’t had a lot of luck with SPI memory and video recording so far.

    Reading a bit more about what FPGAs can do well ;

    • they have tons more I/O pins than an Arduino? This means I can control multiple SRAM address and I/0 pins.
    • Architecture can be completely reconfigurable (unlike a microcontroller which keeps the same architecture).
    • low latency applications that take data as a stream in real time from sensors, cameras, etc. This means I can perform fast logic manipulations of saved data.
    • high throughput applications, pipelining
    • encryption and networking
    • digital signal processing (IIR, FIR, FFT, ADC, DAC) like video filtering
    • parallelism, like doing 128 small tasks at the same time, versus microcontrollers doing things in serial
    • algorithms that can be solved with LUTs, tasks with lots of small adding and subtracting or multiplication (?)
    • K-means clustering, Monte Carlo, neural nets, Mandelbrot fractals, cellular automata ?
    • Seems that there are more and more systems that include micrcontrollers + FPGA + DSP, and you can of course put a microchip inside an FPGA. Here the FPGA accelerates certain tasks for the CPU

    *****

    Here’s what I think I could do with an FPGA and two individually-accessible SRAM I/0 banks   banks :

    • Reverse, scramble, or move through memory addressing with different patterns
    • could change the sample rate of recorded or incoming images
    • could perform logic operations on incoming /recorded video
    • could place sprites on screen, or other parts of memory, through blitting I could selectively overwrite memory.
    • It could record 8 tracks in parallel at 1 bit resolution, or record super long 1 bit resolution videos like on previous boards.
    • It could do matrix transformations on memory like shear, rotation
    • Copying values from one address and then reapplying them to another address every frame (called piping) or just one time. I could generate noise between certain values, or shift values up or down on (called tilting), listen to a value and then reapply it after a fixed number of frames, freezing the current value somewhere for future frames, replacing values intelligently with values in certain sets. Could this be called in-memory processing (https://en.wikipedia.org/wiki/In-memory_processing)? I could copy all the kinds of ways memory is accessed : https://en.wikipedia.org/wiki/Memory_access_pattern !

    With this setup, the FPGA can increment the ADD of all memories while individually controlling which SRAM is reading or writing. Additionally, and simultaneously, it can send and receive different data between two connected SRAM banks. Bascially, it can’t simultaneously access two different parts of memory for reading or writing, if it wanted to do that it would need to remember some info in a buffer and then change the address in sequence like a normal microchip (this is all to give a greater color range to the board). So as far as I can tell the following memory reading and writing operations could be accomplished :

    1. while incrementing memory ADD, record incoming video on A, B, C, D in sequence (at various bit depths)
    2. while incrementing memory ADD, record incoming video on A, B, C, D in parallel (make 4 copies)
    3. while incrementing memory ADD, record incoming video on A, B, C, D and playback previously recorded video
    4. while incrementing memory ADD, play back video on A, B, C, D in sequence
    5. while incrementing memory ADD, playback video 4 copies of a video on A, B, C, D in sequence (i.e. loop)
    6. while decrementing memory ADD, playback a video in reverse
    7. access recorded video with different ADD patterns
    8. while incrementing memory ADD, take stored sprites from the top of one SRAM and insert them into over SRAMs at later addresses
    9. while incrementing memory ADD, perform logic operation on incoming video + an SRAM reading while writing it to a second SRAM
    10. while incrementing memory ADD, perform bit level transformation on an SRAM recording while writing it to a second SRAM

    I am starting to think that losing some color information is worth having more flexibility to work in parallel with SRAM and save me headaches later on when I’m doing verilog hardware descriptions. Here is a simpler proposal that would have a single input (possibly record/pb or “function” meaning do something to the incoming video and then show it on a loop) :

    • I lose LEDs, but I replace them with the most honest indicators possible, the signals themselves buffered.
    • Lost the ability to control individually each quarter memory with WE control.
    • No more DIP select buttons…How will I be able to play this thing live once it’s going through its code (apart from being able to mess with the clock, the RGB bias out, VGA pins coming in, and being able to reset SRAMs and the FPGA)? Should I be able to interrupt it’s functioning by directly controlling CS and WE pins ? (This is possibly dangerous as two memories both set to READ sharing the same I/O pins would be bad.) How about a single button, which activates some hardware function? I would need to load a new code if I wanted to test a new hardware function.

    I’m trying to justify doing this thing in hardware by having tons of indicator LEDs, knobs to change parameters etc. I have to acknowledge that there is a certain amount of manipulation in making art, I am pushing it further in the direction I want so that it is easier to explain to people.

    Reminder : Why am I not using an atMega 2580 which has 86 programmable IO lines and 16MHz frequency ? FPGA is parallel, and it is faster, several people in different contexts have suggested FPGAs for my project, and it’s a learning opportunity.

    In general, doing things in harder is (Fabien) Faster than software, (Vivien) emphasizing materiality, and (Marc) pushing against the genericness of software and hardware that we are increasingly using.

    ****

    Using BRAM seems pretty simple to implicity create :

    reg [15:0] memory [start_address : end_address];

    //memory[4] addresses word 4;

    Fabien at work suggested two things : Not using a resettable fuse as they take longer to stop high current destroying things. And possibly having an SD card with the videos which the FPGA can read directly and getting rid of the RPI. This is because, while writing to SD takes time, reading can be fast. This would be a kind of ROM where I could store videos.

    The best mode for an FPGA apparently is one bit SD mode, instead of SPI, as it only requires 3 pins: CMD, CLK and DAT0.

    https://www.fpga4fun.com/SD2.html

    It looks like inside the SD card is just NAND Flash memory, so maybe I could interface directly with this ?

    https://upload.wikimedia.org/wikipedia/commons/f/f0/Pretec_16GB_SDHC_without_cover_20090420.jpg

    Or I could have Arduino doing the interface with an SD card ? I’m not sure why but I feel like this is going in the engineering direction and not the artistic one. The Rasbpi solution works, why not just keep it and save the headache that won’t in any way change the artistic output of the board.

    *****

    ATmega2560 SRAM board with SD card and I2C Flash memory. Raspberry pi as video in.

    But not very interactive. More about messing with different kinds of memory, and as a parallel test as the FPGA but more familiar and constrained in C.

    ***

    Don’t know what this is yet but, some kind of typology of memory modifications ?

    Choreographable video synth (PART III)

    Making things easier, simpler, more plug and play.

    ****

    Workshop
    Organize parts 
    
    Palimpsest.OS
    Get all channels working 
    Get raspberry pi VGA out working 
    Test with raspberry pi VGA put 
    Fix VGA input/output (I know what the problem is at least :)!
    SPI SRAM 
    Get recording as fast as possible 
    Try with 4MB FRAM ?
    New board with several + raspberry pi + snake-like channel overwriting?
    
    FPGA
    Try simple VGA with LatticIce40
    Solder FPGA board 
    ****
    La Generale experience :

    So many cables and wires and machines….something more minimal / smaller and portable possible ?

    Would love to have an integrated thing with raspberry pi / FPGA generating video and the thing directly outputting it.
    Do not rely on computers to output VGA signals ! Try raspberry pi.
    Physical objects is what I should make, not projections, because my project is about materiality ! I could make circuits that go beyond just recording and have moving parts and tiny screens eventually ? Then again this is a dangerous dream as I’ve learned with VHS and Floppy Disk tests…
    Don’t make experimental stuff during residencies, test tools you’ve already built and deploy tested things.
    My project is all about trying to touch video, get my hands into the inside of the machine. It’s also all about making mistakes, and stumbling upon unexpected output as a result.
    Somewhere between a kit/workshop and an object. (It’s not a performance) 
    ****

    I’ve got a Raspberry Pi Zero outputting VGA nicely. On startup it launches VLC in fullscreen and plays a playlist of iconic film excerpts. I activated hotplugging so it keeps looping even if the adapter is unplugged for long periods of time.

    I used Win32DiskImager and downloaded the ISO Image Raspberry Pi OS with desktop (around 1GB) from the officiql website (https://www.raspberrypi.com/software/operating-systems/) and put it onto an 8GB SD Card.

    In terms of connectors I needed a SD Micro > SD card adapter, HDMI mini > HDMI, an HDMI > VGA, a USB A > USB Micro for power, and a USB Micro to USB A female in order to plug in a mouse / keyboard.

    I followed these three tutorials for setting up VLC autoplay and turning off annoying VLC text:

    https://forums.raspberrypi.com/viewtopic.php?t=17051

    Raspberry Pi: Run VLC on startup and play slideshow videos/pictures from folder

    https://www.shellhacks.com/raspberry-pi-force-hdmi-hotplug/

     

    Now adding a power off button (not good to pull the plug while running)

    https://howchoo.com/g/mwnlytk3zmm/how-to-add-a-power-button-to-your-raspberry-pi

    **EDIT The rasbpi turns off when I unplug HDMI or plug into the palimpsestOS. Is it because RGB are mixed with only 100ohm resistors ? Should I have 3 blocking caps and then mix after ?

    Here’s a write up on how to VGA :

    https://chipnetics.com/tutorials/understanding-75-ohm-video-signals/

    Looks like parallel 75ohm resistors going to GND from the input is good practice + a cap and 75 ohm resistor on output?

     

    VGA OUTPUT examples :

    MAX4032 5V, 6dB Video Buffer with Sync-Tip Clamp, Output Sag Correction, and 150nA Shutdown Current | Analog Devices

    If I understand this last one, three parallel 75ohm resistors makes a 25ohm resistor. 97ohms gets 80% of 3.3V gone before the 25ohm dissipates the rest so that there is 0.7V left for the 3 channels. For a 5V supply like mine, I’ll need to remove 86% of 5V to get it down to 0.7V.  A 160 ohm resistor then ?

    VGA INPUT examples :

     

     

    *EDIT Made the changes (RGB colors in to GND through 75ohm, one color through cap to bias + 160ohm and now there is no output…But maybe it was already broken at this point? Can test when new converters arrive.)

    Looked at some VGA in/out boards I had in my possession and saw the following :

    • H and V sync can go to a 74HC125 Line Driver / Buffer.
    • Color returns can be conected together and grounded along with chassis.
    • Examples of color pins going to grounded 75ohm resistors then on to blocking caps. Also colors to gates of transistors.
    • Colors also going to video signal switcher like this : QS4A210 – 2-Channel 4:1 Analog Mux/Demux
    • Definitely DO NOT ground pin 9 (which is 5V), as I have done in all previous boards…

    ****

    An older HDMI to VGA converter broke so I opened it up to see if I could reproduce it. It’s an ALGOLTEK AG6201 which appears to be not accessible anywhere but the manufacturer’s website.

    The alternative is using a video chip which can trasmit HDMI like this project : https://hackaday.com/2019/07/26/hdmi-from-your-arduino/ which uses a CH7035B HDMI encoder.

    Alternatively I use the HDMI to VGA adapter and solder a D Sub Standard Male connector (https://www.mouser.fr/ProductDetail/TE-Connectivity-AMP/2301843-1?qs=rrS6PyfT74crws9wAQVNoA%3D%3D&mgh=1&vip=1&gclid=Cj0KCQjw27mhBhC9ARIsAIFsETE7Rp9JFGXhYFAXh_Z2YbQUB2NfHqO8rM7yPueb-T3yFiKbUMvJkOEaAtjJEALw_wcB) to the board.

    ***

    I will be testing a pico projector and a VGA capture device soon…

    Video Coverter VGA Capture Card,VGA to USB2.0 Converter,Audio and Video Capture Device,Plug-and-Play,USB Drive-Free HD 108...Mini Projector, PVO Portable Projector for Cartoon, Kids Gift, Outdoor Movie Projector, LED Pico Video Projector for Home ...

    ***

    Trying again with SPI SRAM

    This code seems solid to me but I can’t go beyond 100Hz…

    #include <SPI.h>
    #include <SRAM_23LC.h>
    
    // SPI bus can be SPI, SPI1 (if present), etc.
    #define SPI_PERIPHERAL    SPI
    #define CHIP_SELECT_PIN   8
    
    /* Device can be:
     * 128KB: SRAM_23LCV1024, SRAM_23LC1024, SRAM_23A1024
     * 64KB: SRAM_23LCV512, SRAM_23LC512, SRAM_23A512
     * 32KB: SRAM_23A256, SRAM_23K256
     * 8KB: SRAM_23A640, SRAM_23K640
     */
    SRAM_23LC SRAM(&SPI_PERIPHERAL, CHIP_SELECT_PIN, SRAM_23LCV1024);
    
    // Additional SRAM chips
    // SRAM_23LC SRAM1(&SPI_PERIPHERAL1, CHIP_SELECT_PIN1, SRAM_23LC512);
    
    #define START_ADDRESS   0
    
    //uint8_t buffer[BUFFER_SIZE];
    //#define BUFFER_SIZE  320
    
    char buffer[1000];
    #define BUFFER_SIZE  (sizeof(buffer) / sizeof(uint8_t))
    
    void setup(void)
    {
      pinMode(2, OUTPUT);
      /* Without parameters, begin() uses the default speed for this
       * library (12MHz for samd, 14MHz for sam, and 4MHz for avr).
       * Note that SPI transaction support is required.
       */
      SRAM.begin();
     // SRAM.begin(8000000UL);      // or specify speed
      //Serial.begin(9600);
    }
    
    void loop(void)
    {
      //while (!Serial); // Wait for serial monitor to connect
    
    // Record a series of values
      for (size_t i=0; i < BUFFER_SIZE; i++) {
        //buffer[i] = byte(digitalRead(A2));
            if ( (PINC & (1 << PINC2)) == (1 << PINC2) ) { //PC2 is what we're reading
            buffer[i] = 0xFF;// pin is high
            }
            else {
            buffer[i] = 0x00;// pin is low
            }
      }
    /*
      // Print buffer to serial monitor
      Serial.print("Write Block: ");
      for (size_t i=0; i < BUFFER_SIZE; i++) {
        Serial.print(buffer[i], DEC);
      }
      Serial.println();
      */
    
      // Write block
      if (!SRAM.writeBlock(START_ADDRESS, BUFFER_SIZE, buffer)) {
        //Serial.println("Write Block Failure");
      }
    
      // Clear buffer
      //memset(&buffer[0], 0, BUFFER_SIZE);
    
      // Read block
      //Serial.print("Read Block:  ");
      if (!SRAM.readBlock(START_ADDRESS, BUFFER_SIZE, buffer)) {
        //Serial.println("Read Block Failure");
      }
    
      // Print buffer to serial monitor
      for (size_t i=0; i < BUFFER_SIZE; i++) {
        //Serial.print(buffer[i], DEC);
       if(buffer[i] == 0x00){
         //digitalWrite(2, LOW);
          PORTD &= ~(1 << PD2);    // set pin 2 of Port D low
       }  
       else{
        // digitalWrite(2, HIGH);
          PORTD |= (1 << PD2);     // set pin 2 of Port D high
       }
      }
      //Serial.println();
      //delay(1000);
    }

    I just can’t manage to get the same level of control with an SPI device as with parallel SRAM and counters.

    ****

    New board time 😀 ! Test new things but keep the plug and play idea from last board and make even more so. SPEND MORE TIME SANITY CHECKING THE DESIGN and double checking pull ups and downs.

    Goals :

    • How about using a 16Mbit SRAM to store 128MBits of data with only a few added components ?! The plan is a pair of shift registers to convert serial output from a comparator into 8 bits to be sent all at once to the SRAM and the inverse on the output side. I would need the shift register clocks to be 8 times faster than the SRAM I think?
    • Make it so power (5V – with an LDO on board to eliminate possibility for accidents) can be shared with a double power jack. Reverse polarity protection.
    • A fine and coarse threshold selection !
    • proper VGA input and output good practices that will never harm anything sending video signals in or recieving signals sent out (blocking caps, 75 ohm impedence matching, Vref for top side of variable comparator bias!!, buffers for H and V sync!!, two cables close together!! and shielding – guard rings? – on the PCB for these traces!! different grounds for different parts of the VGA cable, use BNC connectors for RGB??)
    • Raspberry pi as input VGA through converter which plugs into a male VGA on the board, add an OFF/ON switch to safely turn off
    • pass thru VGA signal switch !!
    • Have different clock cans to switch between?
    • Extended Display Identification Data chip as a test?
    • Have audio out option ?

    Here’s the preliminary circuit :

    From https://www.cs.unca.edu/~bruce/Fall11/255/Labs/Lab13AnalogInput.html

    comparator

    From https://electronics.stackexchange.com/questions/144530/circuit-for-a-coarse-and-fine-setting-potentiometer

    ****

    As for PCB inspiration, perhaps something that evokes the computer video graphics card :

    Rectangular, with metal bracket (these are called Computer brackets in the Circuit Board Hardware – PCB category of Mouser.fr. They come in low profile or high profile), fan, heatsink, memory bank in a row, name of the board somewhere, PCI connector

    Palit Daytona NVIDIA GeForce2 MX 400 AGP 32MB VGA Vintage Retro Graphics Card | eBay

    16 MB PCI VGA Video Adapter Card - Our video cards and sound cards enable you to add smooth video performance or high-end audio capability to your PC computer, through a motherboard

    143 8MB Graphics Card, VGA PCI 8MB 32Bit Desktop Computer Accessories Multi- Display for ATI Rage XL Supporting All Motherboards with PCI Plug : Amazon.co.uk: Computers & Accessories

    ****

    Here is my first attempt at simulating the logic :

    The only tricky part was activating parallel load of the output register only once per 8 clock cylces.

    This design includes a giant FPGA to control enables all broken out along the PCI-E connector (that could be played like a piano with an alligator going to GND) in time and also to match the aesthetic of the video card. It would feature a stunning 128 Mbits (16MBits SRAM x 8) of memory. Would be cool to have LEDs next to each memory which light up when that block is recording.

    ***

    Building on the idea of making physical artefacts, Vivien Roussel had the idea of moving towards displaying the chassis of the computer along with these boards. There are loads of cool test bench computer cases that could be an inspiration for this :

     

    ****

    Or a DDR SDRAM module as inspiration :

    Diferenças entre as memórias DDR2, DDR3 e DDR4 | Crucial BR

    Here’s what it’s looking like in Eagle so far :

    I still like the idea of a kind of piano controlling :

    • 3x SRAM CS sel bits
    • 3x COUNTER EN + individual RST

    And of course :

    • Threshold control (fine and coarse this time !)
    • Clock DIV
    • REC/PB

    Here’s the board as ordered :

    CIRCUIT DIARY :

    • The fine and coarse pots appear to work very well.
    • The clock divider works as expected. Though it might be interesting to be able to play with different frequencies too as it seems to be important to get the combination of sampling versus pixel frequencies.
    • I checked and the serial clock is indeed being divided by 8 and inverted (albeit super noisy!) :
    • The Overflow and CS signals appear to be working well (though I had a hard time soldering the resistor networks!)
    • The !WR signal is as expected
    • Possibly should have put pull-downs for the SRAM I/0 pins ?
    • I should have made a timing diagram not just the simulation..
    • The option to manually advance the OVERFLOW signals is cool because you can solder one SRAM and test only it without having to wait for its turn to come around !
    • I have reached a problem : the 596 is not shifting the serial into parallel. I can see it trying (little mini signals getting through), but it is as if the I/O pins are being pulled low, but by what ? The SRAM ? I’ve confirmed we’re in write mode so they should be high Z. The Serial to Parallel converter somehow? But the I/O pins are inputs for this IC…Hmmm. Is it something to do with the open drain outputs (or the Schmitt trigger inputs?) on the 596 ? **EDIT : Had a 595 with the same footprint and substituted it, seems to be working now.
    • So, the output is very stripey. I have removed the 75ohm resistor to ground and shorted the 100ohm to the output RGB pins. I’ve tried shorting the blocking cap and it makes things a tiny bit easier to see but overall it is barely legible as an image. I think it has something to do with the output parallel to serial conversion. Here is a sample of a capture :

    • For some reason it can also work much better :

    • I don’t understand how it is possible to see the screen while it is recording as there is no “pass-thru” option…. There is also sometimes quite a difference from what is somehow passing through while in record mode and what plays during PB mode. *EDIT*There is a noise issue, when the VGA input is plugged in there is static that is entering somewhere. Trying to locate it currently. *EDIT* it is coming from the VGA IN. Tried connecting a bunch of GNDs (digital GND, chassis GND, color return RED) but still getting nowhere trying to eliminate the noise.
    • I ordered the wrong type of bracket, this one is for a double row VGA…
    • I had an issue with SRAM D but then replaced it and all is good.
    • I forgot to have a pre-amp before the comparator, this is essential otherwise you don’t get any in screen peaks and basically don’t see anything unless you’re really lucky. I used the Palimpsest.OS preamp and bias setup and it works fine.
    • The tiny trimpots need to be replaced with actual knobs !!
    • I forgot to add loop LEDs ! It would have also been cool to know which SRAM is currently recording.
    • EVERYTHING IS WORKING I CAN’T BELIEVE IT. The solution was to just test everything with a simple ramp using the function generator and look at the play back. Then I checked the pins on the SRAM and saw funky signals for several address pins that looked like they were several signals being added together. Clearly when I soldered in a bunch more SRAM and there were tiny connections between five different address pins and an I/O that I did not notice. This was causing chaos. I found the connections and fixed them, now it’s recording just as expected and it’s so glorious. NOTES : I am using the op amp from Palimpsest.OS AND crucially, am connecting both Analog and Digital Grounds between the two boards and the VGA IN with VGA OUT.

    ***

    While waiting for this board to arrive :

    • Try different function generated patterns of hitting count 0 enable while recording on the 16Mbit version
    • Test the 8 layer board ! *DONE*
      • Remove pin 9 GND and fix other issues with VGA in and OUT with VGA beakout PCB
      • Test on raspberry pi / computer IN *DONE*
      • Test feedback ! *DONE*
    • Try mini projector *DONE*
    • Try VGA capture device *DONE*
    • Put restart button on rasbpi

    *******************

    *EDIT* It works with rasbpi when I connect only a color, GND, H and V syncs !! So much more convenient than previously.

    • It might be cool to be able vary the mixing of the different channels
    • The output image is quite faintweak, I think I should rexamine the resistors I put at the termination and maybe switch to B+W.
    • It’s a bit muddy with several channels, would be cool to be able to filter that
    • I need a path to feedback with a pot !
    • Switched the output resistors to a 150ohm going to R,G,B and it works nicely.
    • Dip switch hard to use without tool.
    • Hard to see which direction switches are pointing in darker light

    More technical ERRATA :

    • Pin 1 of the 40MHz clock should be pulled HIGH to be enabled, not LOW as it is on the board !
    • The THRESHOLD pot isn’t connected to GND on one side…
    • I should have tied the CCLR (pin 10, which resets when pulled LOW) of the 590 to VCC with a 10K instead of leaving it floating connected to VSYNC. This made it malfunction.
    • BIG PROBLEM : I ordered multiplexers (unidirectional) instead of analog switches (bidirectional) ! The ‘157 multiplexers mess with SRAM B’s I/Os when it is in READ mode (when the SRAM is outputing values on the I/O pins). I ordered a replacement that is pin compatible, the 74LVC1G3157 (DATASHEET : https://www.ti.com/lit/ds/symlink/sn74lvc1g3157.pdf?HQS=dis-mous-null-mousermode-dsf-pf-null-wwe&ts=1679316452048&ref_url=https%253A%252F%252Fwww.mouser.de%252F). EDIT* The new components work perfectly – everything is good !
    • The Sync Clock IC is 3.3V not 5V…
    • Image jumps around of course. When I try to record with the Burst AND IC which outputs !CLK, no writing can occur. I’m guessing this gate messes with the timing somehow? As a workaround I’m trying to connect the 4 AND’ed V SYNC counts to either the address counter IC Reset or to another reset somewhere. 
    • Lots of noise on V SYNC, I should maybe have made the input and output VGA jacks right next to one another…
    • Pin 9 of the VGA D-SUB 15 is VCC for the Display ID EEPROM chip – but I have it connected to GND !! In general I need to respect the rules around the different grounds and return pins in the VGA protocol and not just connect them all together. Hoping to fix this in the next version.

    ***

    Thinking about making a board with a small 5″ screen / or a mini projector incorperated in it

    Fabien suggests using an LCD driver from a normal sized computer screen for a smaller screen (but he says it will will in 16:9 format). The other option he suggests is to use an FPGA to control a screen directly with LVDS.

    Artist Andreas Gysin’s LCD 1 from http://lcd.ertdfgcvb.xyz/

    ***

    Just realized that I could have an raspberry pi using VGA directly from I/0 pins : https://fr.pinout.xyz/pinout/dpi#

     

    ****

    Currently thinking the next PCB should be raspberry pi sending video through I/O (not through HDMI) and FPGA controlling SRAM. This would allow messing with the sequence of the memory recording / playback. Could make a compact version of this project (a kind of black box, deployable version) without many external components but with sililar functionality. I could test making the FPGA USB programmable board too. Of course it would also be programmable.

    To get here :

    • make the automated palimpsest.OS board
    • make the simple FPGA VGA board

    ****

    I am revisiting the SPI SRAM code with renewed patience, I actually wrote it first on paper !

    Here is my simple buffer filling code first off :

    const int buffer_size = 2000;  // Only 2K bytes of SRAM on the 328P
    byte buffer[buffer_size];
    void setup() {
      DDRC = 0b00000000;  // set PC2 as input pin
      DDRD = 0b00000100;  // set PD2 as output pin
    }
    
    void loop() {
    
      //  fill the buffer
      for (int i = 0; i < buffer_size; i++) {  // iterate through buffer
        for (byte mask = 0b00000001; mask > 0; mask <<= 1) {  // iterate through a bitmask
          if ((PINC & 0b0000100) == 0b00000100) {  // if input pin high...
            buffer[i] = (buffer[i] | mask);  // set this bit
          }
          else {
            buffer[i] = (buffer[i] & ~(mask));  // clear this bit
          }
        }
      }
      // read buffer back
      for (int i = 0; i < buffer_size; i++) {  // iterate through buffer
        for (byte mask = 0b00000001; mask > 0; mask <<= 1) {  // iterate through mask
          if ((buffer[i] & mask) == mask) {  // if bit in buffer is high...
            PORTD |= 0b00000100;  // ...write output pin high
          }
          else {
            PORTD &= ~(0b00000100);  // else, write output pin low
          }
        }
      }
    }
    
    
    

    Tried to see what this produce on the screen. I’m using a comparator from the previous board to do ADC and then feeding the ouput through a 470ohm resistor to red. It just leaves little comets which don’t appear to relate to the image…

    On the scope it doesn’t look far away though :

    Hmm…

    ****************

    After skimming from Nand2Tetris and checking out the VTECH Video Painter, I realized I could make a really basic screen interface :

    • I could record an image and then have an algorithm go through it and make changes (like photoshop effects like blur or polarize).
    • I could have sprites stored and then copy them into the screen-memory mapped SRAM
    • I could even have a joystick move from pixel to pixel and let you draw, copy and paste and draw circles !
    • It could also be a non uniform mapping from memory to the screen !

    ****************

    The VGA Capture is working and it’s fantastic ! I’m using OBS, I just clicked ADD SOURCE and then Video Capture device. It needs to be plugged in to USB A, not C, for the LED to come on.

     

    I tried the mini projector but it didn’t like the signals I was sending it. I think I have to avoid intelligent interfaces that can decide to send or not along my signals. Wondering about the camcorder CRT viewfinder and if I should head back in that direction.

    Here is a popular 4″ screen :

    Il Mini Monitor CRT da 4 pollici in bianco e nero supporta l'ingresso Video 12V4W tubo per immagini elettronico da 4 pollici - AliExpress

    Choreographable video synth (PART II)

    Inspired by the history of mounting circuits on wood with screws and wire, evoking John Cage’s prepared pianos. 

    This iteration of the project is born of a few realizations :

    1. VGA is an analog signal, it’s not digital.
    2. The coolest effects are the simplest ones : XOR, HP and LP filters, comparators, etc. which can be easily made with discrete components.
    3. A simple low frequency oscillator could control these effects with an LED > LDR voltage controlled resistor set-up. 
    4. Two out of sync oscillators easily make a pattern that doesn’t repeat often and is difficult to predict.

    Pedagogically and aesthetically I like this idea : it goes back to the basics of electronics, the history of electronics, and will show the materiality of video signals. This in contrast to the overly complex use of digital components to do basic modifications…

    The three basic circuits :

      

    *TESTED* This works (powered at 5V, with pull down 10K on input and the rest 1K and two BD135s) at lower frequencies (<100KHz) around 5V.  I added a 5K variable resistor (or an LDR + resistor) to increase the resistance of R1 and it varies the threshold !

    *TESTED* Works using BD136 PNP, 10K for the pull down and 1K for the base protection. General purpose diodes. I replaced the pull down with a 5K variable resistor and got some messed up results in the MHz. Doesn’t need power – just takes it from the input signal ! (But VGA signal would need to be amplified in order to work. 

    *TESTED* With a 104 cap and 5K variable resistor I can vary the filtering of a 5V function generator signal. 

     

    ****

    OK we’re back to the original plan ! Here is the Palimsest.OS Rev.2 :

    WHY ?

    • This board is for the inauguration of the IFT at the DVIC. It has to demonstrate technical proficiency on behalf of the staff, and must run independently as an tech-art installation, modifying video independently day in day out. 
    • Rev.1 didn’t work for microchip automation, this one should work smoothly(?). If everything works I could write code that executes different video manipulations. I also added selection LEDs to show the microchip doing its thing.
    • This tests the 8 channel 1-bit WRITE/REWRITE memory idea (but not the more elegant SRAM + buffer idea of Fabien), with certain effects tied to certain channels
    • Incorporates a simple to control XOR, comparator and HP/LP/BP filter into one board
    • Has a stable clock setup with metal can oscilloscope, a gen lock IC, and V SYNC burst setup
    • Tests an (expensive) programmable filter IC
    • It is a test for a simpler, inexpensive 8 ch recorder board that could be a cool kit
    • Does away with the ADC and all its pesky issues and trades it for a simpler 1bit “ADC”. 
    • I’m also using 5V SRAM to avoid the headache of different logic levels (though this means I only have 4MB of SRAM versus 16MB).
    • For testing purposes it can be soldered as a logic-controlled board or as a physical switch controlled-board. 
    • Instead of having lots of jumpers for wires, I went for rotary switches to make things more plug and play. However this also means that there are fewer experminental tests that are facilitated (like disabling a single counter while recording etc.) that were possible on rev.1
    • Can layer different recorded portions easily in theory
    • Battery switch and edge potentiometers instead of knobs
    • Theoretically could do feedback and echo tests with this board as it can read and write from and into memory simoultaneously 
    • This board should be easier to work with than the previous stacked PCI-E motherboard design which made knob turning and mounting hard. 
    • Instead of using generic octal logic ICs I went for more specific purpose ones.
    • The board will be made at https://aisler.net/ instead of JLCPCB so I’m hoping for a really nice finish

    Here’s a possible minimal installation with it :

    ****

    PALIMPSEST.OS v2 ERRATA :

    • Pin 1 of the 40MHz clock should be pulled HIGH to be enabled, not LOW as it is on the board !
    • The THRESHOLD pot isn’t connected to GND on one side…
    • I should have tied the CCLR (pin 10, which resets when pulled LOW) of the 590 to VCC with a 10K instead of leaving it floating connected to VSYNC. This made it malfunction.
    • BIG PROBLEM : I ordered multiplexers (unidirectional) instead of analog switches (bidirectional) ! The ‘157 multiplexers mess with SRAM B’s I/Os when it is in READ mode (when the SRAM is outputing values on the I/O pins). I ordered a replacement that is pin compatible, the 74LVC1G3157 (DATASHEET : https://www.ti.com/lit/ds/symlink/sn74lvc1g3157.pdf?HQS=dis-mous-null-mousermode-dsf-pf-null-wwe&ts=1679316452048&ref_url=https%253A%252F%252Fwww.mouser.de%252F). EDIT* The new components work perfectly – everything is good !
    • The Sync Clock IC is 3.3V not 5V…
    • Image jumps around of course. When I try to record with the Burst AND IC which outputs !CLK, no writing can occur. I’m guessing this gate messes with the timing somehow? As a workaround I’m trying to connect the 4 AND’ed V SYNC counts to either the address counter IC Reset or to another reset somewhere. 
    • Lots of noise on V SYNC, I should maybe have made the input and output VGA jacks right next to one another…
    • Pin 9 of the VGA D-SUB 15 is VCC for the Display ID EEPROM chip – but I have it connected to GND !! In general I need to respect the rules around the different grounds and return pins in the VGA protocol and not just connect them all together. Hoping to fix this in the next version.

    More Meta errata :

    • It’s a bit muddy with several channels, would be cool to be able to filter that
    • I need a path to feedback with a pot !
    • Switched the output resistors to a 150ohm going to R,G,B and it works nicely.
    • Dip switch hard to use without tool.
    • Hard to see which direction switches are pointing in darker light

    Oy vey ! I realized that I could just use an I2C RAM IC and save about a billion components. Here are the more plug and play simple boards I made in the aftermath :

    Good news: The 328 works. 

    ERRATA : I fried the logic chips with 5V :(. Resoldered new ones and looks good.  I think I need to be feeding in a signal that has already been digitized (like by a comparator). Otherwise I need to mess around with knobs to get the signal right around the threshold of the logic gates with bias setup. 

    Good news: The 328 works. And I can see the effect of selecting different filters. I’m not sure why but it works best when the signal is coming in on A and I’m taking the output on B (or vice versa). I’ve also got a cap going from the output of the filter board before amplifying it again.

    ERRATA: I ordered the wrong length of bussed resistor network. 

    Good news: The 328 works. 

    errata ^ Wrong footprint (and value!) for the digital potentiometer here… Will have to wait for the correct part to test this.

    Good news: The 328 works and at least it produces an image !

    errata ^ H SYNC and V SYNC plugged in to wrong pins on Arduino (should be PD3 and PB1 respectively).

    Good news: The 328 works.

    ERRATA : the PD pin (which enables ADC IOs when low) is pulled HIGH ! I resoldered it and now it’s working great. 

    I chose a non PWM pin on the atmega to be the voltage control pin of the VCO… I soldered it to the nextdoor pin which can do PWM and all is good. 

     

    ERRATA: I tried two chips, they both come up as unidentified FRAM when I have them speak on the serial running the demo codes…I should probably pull Write Protect (WP) HIGH just in case. Still not working…I will try replacing with a 23LC1024 serial SPI SRAM as it has the same pinout. 

    ***EDIT: Just saw this on the Adafruit website : “For the 4Mbit version, you should change this to: fram.begin(3)”…Still doesn’t work though.

    I replaced with the 23LC1024 and am using the SRAMsimple libary which appears to work well. For some reason the digitalRead I’m doing in the setup is always returning 0 even if connected to 5V.

    #include <SRAMsimple.h>
    #defineCSPIN8       // Default Chip Select Line for Uno (change as needed)
    SRAMsimple sram;       //initialize an instance of this class
    /*******  Set up code to define variables and start the SCI and SPI serial interfaces  *****/
    voidsetup()
    {
    uint32_t address = 0;                       // create a 32 bit variable to hold the address (uint32_t=long)
    Serial.begin(9600);                         // set communication speed for the serial monitor
    SPI.begin();                                // start communicating with the memory chip
      // And now the fun begins:
    /**********Write a Single Byte *******************/
    bool data = digitalRead(A0);                        // initialize the data
    for(int i = 0; i <=5; i++){                 // Let's write 5 individual bytes to memory
        address = i;                              // use the loop counter as the address
    sram.WriteByte(address, byte(data));            // now write the data to that address
        data+=2;                                  // increment the data by 2
    }
    /********* Read a single Byte *********************/
    Serial.println("Reading each data byte individually: ");
      byte value;                                 // create variable to hold the data value read
    for(int i = 0; i <=5; i++){                 // start at memory location 0 and end at 5
        address = i;                              // use the loop counter as the memory address
        value = sram.ReadByte(address);           // reads a byte of data at that memory location
    Serial.println(value);                    // Let's see what we got
    }
    }

    Not sure why…

    *EDIT: Got the thing working with Fabien’s help !  

    
    #include <SPI.h>
    #include <SRAM_23LC.h>
    #define SPI_PERIPHERAL SPI
    #define CHIP_SELECT_PIN 8
    
    SRAM_23LC SRAM(&SPI_PERIPHERAL, CHIP_SELECT_PIN, SRAM_23LC1024);
    
    #define START_ADDRESS 0
    
    void setup(void)
    {
    pinMode(2, OUTPUT); // where we write the recorded data to.
    pinMode(A2, INPUT);
    SRAM.begin();
    }
    
    void loop(void)
    {
    for(unsigned long i=0; i<128000; i++)
    {
    byte val;
    if ( (PINC & (1 << PINC2)) == (1 << PINC2) ) {
    val = 255; // pin is high
    }
    else {
    val = 0; // pin is low
    }
    SRAM.writeByte(START_ADDRESS + i, val);
    }
    
    delayMicroseconds(1);
    
    for(unsigned long i=0; i<128000; i++)
    {
    byte ch = SRAM.readByte(START_ADDRESS + i);
    PORTD = ch;
    }
    
    delayMicroseconds(1);
    }

    However in this byte write/read mode the fastest I can get it going is 10KHz…The next step is to use this SPI tutorial (https://docs.arduino.cc/tutorials/generic/introduction-to-the-serial-peripheral-interface) and the SRAM datasheet ( https://ww1.microchip.com/downloads/aemDocuments/documents/MPD/ProductDocuments/DataSheets/23A1024-23LC1024-1-Mbit-SPI-Serial-SRAM-with-SDI-and-SQI-Interface-DS20005142.pdf) to operate in “sequential operation” mode where pages are ignored and its all just one big array. 

    I have tried to do this but haven’t yet succeeded. I can successfully write and read from the memory with the code below..:

    #define DATAOUT 11//MOSI
    #define DATAIN 12//MISO
    #define SPICLOCK 13//sck
    #define CHIPSELECT 8//ss
    
    //opcodes
    #define READ 0x03 // read data
    #define WRITE 0x02 // write data
    #define WRMR 0x01 // write to the Mode Register
    
    //modes
    #define SEQUENTIAL 0x20 // 0100000 in Binary
    
    byte clr;
    
    byte address0 = 0;
    byte address1 = 0;
    byte address2 = 0;
    
    byte data_to_write = 0;
    byte data_to_read = 0;
    
    char spi_transfer(volatile byte data)
    {
    SPDR = data; // Start the transmission
    while (!(SPSR & (1<<SPIF))) // Wait the end of the transmission
    {
    };
    return SPDR; // return the received byte
    }
    
    void setup(void)
    {
    
    pinMode(DATAOUT, OUTPUT);
    pinMode(DATAIN, INPUT);
    pinMode(SPICLOCK,OUTPUT);
    pinMode(CHIPSELECT,OUTPUT);
    digitalWrite(CHIPSELECT,HIGH); //disable device
    pinMode(2, OUTPUT); // where we write the recorded data to.
    //pinMode(10, OUTPUT); // LED
    pinMode(A2, INPUT); // where we read the data from
    // SPCR = 01010000
    //interrupt disabled,spi enabled,msb 1st,controller,clk low when idle,
    //sample on leading edge of clk,system clock/4 rate (fastest)
    SPCR = (1<<SPE)|(1<<MSTR);
    clr=SPSR;
    clr=SPDR;
    
    digitalWrite(CHIPSELECT,LOW);
    spi_transfer(WRMR); // access the Mode Register
    spi_transfer(SEQUENTIAL);//enter Sequential Mode
    digitalWrite(CHIPSELECT,HIGH); //disable device
    }
    void loop(void)
    {
    //WRITE
    digitalWrite(CHIPSELECT,LOW);
    spi_transfer(WRITE);
    spi_transfer(address0);
    spi_transfer(address1);
    spi_transfer(address2);
    
    for(unsigned long i=0; i<128000; i++) // address is automatically incremented internally in the SRAM in this mode
    {
    if ( (PINC & (1 << PINC2)) == (1 << PINC2) ) {
    data_to_write = 255; // pin is high
    } 
    else {
    data_to_write = 0; // pin is low
    }
    spi_transfer(data_to_write);
    }
    digitalWrite(CHIPSELECT,HIGH);
    
    //READ
    digitalWrite(CHIPSELECT,LOW);
    spi_transfer(READ); //transmit read opcode
    spi_transfer(address0);
    spi_transfer(address1);
    spi_transfer(address2); // 24 bit address in three parts (this could be a problem)
    
    for(unsigned long i=0; i<128000; i++)
    {
    data_to_read = spi_transfer(0xFF); //get data byte
    PORTD = data_to_read;
    }
    digitalWrite(CHIPSELECT,HIGH); //release chip, signal end transfer
    }

    …but when I do this in chunks with loops it doesn’t appear to work. I’m not sure if it’s because I’m reading the value of the pin during the writing and if I should perhaps do this before with a buffer array and then just read from it ?

    OVERALL ERRATA : I also need some kind of power board that distributes 5V and 3.3V 

    ***

    On the back of the boards I tried an experiment using the bmp import ULP in Eagle. Not sure what the results will look like :

       An

    **** 

    I also starting thinking that I should probably look at more existing DIY and pro analog video synth circuits…

    A collection of great video synthesizer schematics resources : https://scanlines.xyz/t/diy-resources-file-system/224

    Here are some of the ICs (that are still being manufactured) that I haven’t work with before that appear in several designs :

    • Resettable and retriggerable Monostable Multivibrators : https://assets.nexperia.com/documents/data-sheet/74HC4538.pdf
    • High speed diff comparators : https://www.ti.com/lit/ds/snosbj5c/snosbj5c.pdf?HQS=dis-mous-null-mousermode-dsf-pf-null-wwe&ts=1676232730602&ref_url=https%253A%252F%252Fwww.mouser.fr%252F
    • Video Fader IC: https://www.analog.com/media/en/technical-documentation/data-sheets/12516fa.pdf
    • Graphic EQ display filter : https://www.sparkfun.com/products/10468

    To divide a signal into 8 different bands (if you skip the MUX at the end) :

    Here’s a simple implementation with a 4051 analog mux at the end :

    This worked after I sorted out that the Atmega 328 reset was pulled LOW all the time – so it programmed fine but never did anything after that. I also removed the op amps which were supposed to follow the selected thresholds, I connected the top and bottom directly to the pots in the end. I tried slowly switching between bands at half a second and also faster at 50ms. Both as expected.

    And I’m revisiting all kinds of combined capacitor + switch circuits which move tiny charges around based on signals  :

    • sample and hold 
    • bucket brigade
    • comb filter 
    • switched capacitor circuit

     I have made this bucket brigade “delay” with 50 microchip tunable (variable) 100-200pF capacitors :

    I am now curious about some other capacitor switching circuits like this Comb Filter : https://en.wikipedia.org/wiki/Comb_filter which somehow “provides response” at different multiples of 1KHz depending on 3 bit code. All the caps are the same value.

    Here is another circuit design for the same function :

    Block diagram of comb filter including the CMOS multiplexers and the... | Download Scientific Diagram

    ****

    For the FPGA board, I’ve ordered an iCE40HX1K development board and am currently planning to test some basic VGA signal generation. The next steps could involve basing a design off of the OLIMEX dev board design (https://github.com/OLIMEX/iCE40HX1K-EVB/blob/master/ICE40-1KEVB_Rev_A.pdf) which already has SRAM and VGA OUT along with code on the internet (which I would follow closely for the first iteration). I would alter the board to be able to program directly via USB using the components from the Ice40 stick ( https://www.mouser.fr/new/lattice-semiconductor/lattice-icestick-kit/), like a fancy new FTDI chip, so I could stay within the Lattice software for my first steps. 

    Compared to the VGAX, the FPGA could generate signals much faster (being clocked with a 100MHz crystal versus the 16MHz of the Atmega), it would also be producing signals based on a a different coding paradigm (I have no idea what that would mean in terms of images), and because it has around 90 I/O it could also work with super deep colors using only a R2R ladder. The possibility of using an SDRAM is so cool but it seems hard to implement, with SRAM being much simpler to interface. The OLIMEX has only 512KB of SRAM, so I couldn’t really record a lot with it. 

    ****

    Here is my process for the FPGA programming so far :

    1. I signed up for an account at www.latticesemi.com.
    2. I got a licence for iCEcube2, put it somewhere easy to find and took note of the directory, and downloaded iCEcube2 and the Lattice Diamond software from here : https://www.latticesemi.com/en/Products/DesignSoftwareAndIP
    3. I plugged in the iCEstick and it blinked in a circular pattern. I also checked that it had a port under Device Manager (it had 2!). 
    4. I went into iCEcube2 then to Help > Tutorial to open a pdf called “Implementing the Design” and followed the following steps :
      1. Start new project (iCE40, HX1K, ?TQ144?)
      2. Add Design file iCElab.v and Constraint file iCElab.sdc and checked the Device Info.
      3. Run Synplify Pro Synthesis
      4. Select Implementation
      5. Add constraint file iCElab.pcf under Import P&R Input Files.
      6. Run Placer
      7. Check the Floorplan, package view, timing analysis, power estimation
      8. Generate the bitmap (.bit and .hex files) which is saved wherever the project was saved. (For instance C:\Users\Jonah\Desktop\FPGA LATTICE DEMO PROJECTS\quick_start\quick_start\quick_start_Implmnt\sbt\outputs\bitmap).
      9. Here is what everything should look like once finished :
    5. I then transitioned to Youtube for a detailed explaination of using Diamond Programmer with the iCEstick here : https://www.youtube.com/watch?v=Df9k1T0bHmA&ab_channel=Dom
      1. Launch Diamond Programmer and take the default options (or click scan and take those)
      2. It will mistake the board for a JTAG interface and give the following errors : “Failed to scan board”, “Scan Failed – Creating Blank Programmer Project.”
      3. Now change the Device Family to iCE40, the device to iCE40HX1K, and under Program enter the following information :
        1. Change Access mode to SPI Flash Programming and now some other options appear. Select > Vendor: Micron, Device: N25Q032, Package:  8-pin VDFPN8
        2. Now load the bitmap (.bin) file and check that it has a non-zero datasize :
        3. Click OK and then click the green traffic light on the next to top row of icons. You should then see a completion message and have the program on your board :
        4. Presto !

    Just for info :

    For the actual pinout of the ice40 (which you can change in Pin Constraints Editor):

    Generating your own .v file, you can open Notepad++ and paste :

    module AND( input A, input B, output Y ); assign Y = A&B; endmodule

    ***

     

    Here’s what ended up getting presented :

    Here is the text I made to go with it :

    La préparation d’un piano est l’action expérimentale d’ouvrir le couvercle du piano et de placer des objets (des vis, par exemple) entre les cordes. Ces « préparations » modifient la vibration des cordes et peuvent provoquer de nouveaux sons, parfois des sons de batterie plus du piano. Post-préparation, le pianiste peut composer une partition qui exploite les nouvelles modalités soniques découvertes, entrant en dialogue créatif avec l’instrument. L’acte d’intervenir et de détourner le fonctionnement du piano encourage le pianiste à comprendre le fonctionnement de leur instrument d’une manière concrète et recadre l’instrument en tant que site d’expérimentation créative, menant souvent à des découvertes inopinées, bien que fugaces, dans un processus artistique ouvert et indéterminé.
    Ce projet représente une tentative (ambitieuse) de fabriquer, et ensuite de « jouer » avec, un type d’écran préparé. Les signaux électroniques qui passent entre le laptop et l’écran ici sont comparables aux vibrations qui voyagent dans les cordes du ventre du piano. De la même manière qu’une vis peut modifier le son généré par l’activation d’une touche du piano, nous pouvons atténuer et amplifier sélectivement les voies de signaux électroniques pour produire de nouveaux stimuli (en forme d’images cette fois).
    Notre quête pour répertorier des préparations vidéo possibles, et pour documenter leur fonctionnement, nous a mené à la rencontre de filtres artisanaux montés sur bois, qui évoquent les radios fait maison des années 1950s, ainsi que les technologies moins abordables et plus sophistiquées comme les FPGA (des circuits intégrés de logiques programmables). Ces prototypes sont fixés dans l’arrière-plan et ont vocation de rappeler le caractère expérimental et ludique du projet de recherche.
    En clin d’œil au monde de la synthèse modulaire audio, qui prend souvent une esthétique punk, nous avons fixé un enchainement de modules de préparation vidéo au premier plan. En concaténant des modules, tel que les filtres à capacités commutées, des mémoires vives statiques, des convertisseurs analogique-numérique, des portes logiques combinatoires, et encore d’autres, nous pouvons délaminer les flux vidéo, créer de nouvelles voies électroniques, tordre, caresser et déformer des signaux, les synthétiser, et finalement les tresser ensemble, avec plus ou moins de finesse, et observer les résultats en temps-réel.
                                                                                                ***
    A prepared piano is the result of opening up a piano and placing objects (often bolts and screws) between the piano strings. “Preparations” modify the sound of a vibrating piano string to create new sounds, sometimes more resembling a drum than a traditional piano. After a piano has been prepared, a score is developed to explore the new qualities of the instrument. Instrument preparation invites a musician to engage with and understand the inner working of their instrument, literally getting their hands inside the body of the instrument. Preparation reframes the instrument itself as a site of creative experimentation, often leading to serendipitous discovery in an exhilarating, and at times painfully anxious making (!), open-ended design process.
    This work is an attempt at making a kind of prepared computer monitor. The electrical signals passing between the laptop and the monitor are analogous to the vibrations inside the strings within the belly of the piano. Just like a bolt can create a new type of sound in the prepared piano, we can similarly dampen and accentuate the video signal pathways of the prepared computer monitor to create new types of image transformations that play out in time for our eyes.
    Our journey to explore a range of possible preparations and document their effects has taken us to different eras of technology, from simple, artisanal high pass filters mounted on nails in wood, to more sophisticated technologies like the Field Programmable Gate Array (FPGA). These exploratory prototypes are visible on the backplane and emphasize the importance of the process in this artistic research project.
    In a nod to the world of modular audio synthesis, we are displaying one of many different possible concatenations, or “patches” as they are known, of our video preparation modules in the foreground. By linking together various microchip-controlled switched capacitor filters, static RAM delay modules, Analog to Digital converters, combinatorial logic boards, and other circuits, we can playfully delaminate a video signal, open up different signal pathways, bend and warp signals, synthesize new ones altogether, and finally braid these all together on screen and observe the results.
    ***

    My takeaways :

    Do something simple, and humble, but try to do it well. Trying to do too many things, or a “universal” thing, or a multi-functional reprogrammable thing is really ambitious. This has happened to me before :

    • At the Barilla Hackathon (the team that did the best made a simple lunch surface, it was simple but really well made and designed). 
    • With my solar robot project (the one that was supposed to run on solar energy and no battery, interact with other robots, and possibly build a structure)
    • With my original solar sunflower design that was supposed to look super intricate.

    Making a machine that works for a demo is the highest level of challenge. It requires you to master the functining of the machine to a high degree to be able to fix it and adapt in changing conditions. It you do something simple, you have a higher chance of being able to do this.

    It would have been important to realize that the place this was to be shown is a corporate environment, and that my interest in the bodge / bricolage would never have found its place here. The corporate mentality is shiny, new, pro-tech, and “impressive”. I should have understood this before taking the project. 

    The simple, distilled, purified, humble and clear idea from this project was the wooden-mounted electronic circuits. This would have been in line with my “design research” interests, my aesthetic.

    If I were to make a complex machine like the one I had in mind for this expo that would have worked, I think I would have to change the following things :

    • Generate my own VGA signals. For plug and play things, generating this in software seems so much easier because you are the one making it and you have control over what is being produced. 
    • Figure out, once and for all, the story around shared grounds and blocking caps, and bias pots, and voltage in and voltage out levels, for different modules. Also, 75ohm resistors and small caps before VGA out ? Should I just get a VGA driver chip that works? (EDIT: Here is an explaination of how to calculate the output impedence for VGA cables : https://hackaday.io/project/18682-pic-graphics-demo/log/49786-vga-interface)
    • I would need to figure out what makes the VGA monitor turn off (is it sending something it doesn’t consider a video, or a voltage level that is too high?)

    I think the alternative, which would be showing pre-recorded videos, is uninteresting for a performance. Another key ingredient I think is having designers / artists to help me review the project regularly (like in design school). It should also be really clear to me if it is my design project or a commission (in which case I’m an engineer I guess?). I should also get clear right from the begining next time what are the conditions of the final thing – where will it be, what are the goals of the person commissioning the work, etc.). I should probably only work with people who share my interests and aesthetic ! 

    I think I have to acknowledge that I have an extremely constrained working process that is highly method driven. I am not focused so much on the end product directly. My friend suggested I was over constraining myself. Basically there is a confusion between whether I’m using technology to stumble upon unexpected things, or whether I’m using it to make something that works. To work efficiently on things would work well would require time developing the things that must work well, and an organized, systematic working practice. I MUST ORGANIZE MY ELECTRONIC PARTS to make this process more efficient.

    Also : all the intense pressure and hardcore work streaks I put in DID NOT HELP THE FINAL PROJECT – I can’t even think straight or debug basic circuits right now :(. It would have been better to perhaps start working on the final thing starting on day 1, with the EASIEST, SIMPLEST, AND MOST LIKELY TO WORK PAINLESSLY solutions. 

    Another key question is what is the output, and who is my audience ? I need a way of mesuring my output and comparing it. 

    • Am I making art for people who consume art ? (then I have to move towards very simple projects and focus on their EXECUTION while photographing everything super well for my PORTFOLIO)
    • Am I making “design research” papers/talks for academics and people who consume this ? (then I need to WRITE about my research)
    • Am I making open-sourced electronics kits for hobbyists ? (Then I need to spend time ENGINEERING working kits that people would be interested in making)
    • Am I making workshops for designers ? (Then I need to come up with simple exercises for workshops?)

    And am I doing several of these things simoultaneously ? I think doing any one of them well first could take a lifetime already ! My friend suggested projecting five years in the future to where I would like to be and building backwards from there. I think I would most like to be a teacher who does art/design research in the form of expos, articles and classes (a bit like Andrew Witt at the GSD).

    ********

    Where I would like to go from here :

    1. Test my basic FPGA VGA board. What can it do with video ? Possibly make another pro version (USB programmale, nicely laid out, SRAM). FPGAs feel like the future because they are good a processing video in parallel, and because coding them is essentially like building 74 series logic circuits but without all the soldering. It could also lead to some cool machine learning experiments later on..
    2. Test my automatable SRAM 4MB board. What kind of automatic looping can it make?
    3. Try to get the SPI SRAM board functioning (it is so simple it would be perfect for a video sampling workshop). It would be cool to see what kinds of images it produces. It works at 20MHz, it would be perfect !
    4. Get Spaghettini working with aluminum board (just avoid going through-hole) – this is the simplest way to generate cool simple memory based video !
    5. Have another stab at presenting my work as an art installation at my show end of march at La Générale. 
    6. Try the bucket brigade and digitally controlled pot boards

    *******

      After my colleague Fabien told me about EDID EEPROMs, I am thinking it could be possible to mess with the memory of this EEPROM that communicates with the computer sending VGA signals and create some interesting glitches this way : https://en.wikipedia.org/wiki/Extended_Display_Identification_Data

      Also check out these types of RAM : 

      • https://en.wikipedia.org/wiki/Dual-ported_RAM
      • https://en.wikipedia.org/wiki/GDDR_SDRAM

      And this keeps coming up when looking into controlling screen rows and columns directly : https://en.wikipedia.org/wiki/Low-voltage_differential_signaling

      Check out no input mixing and electro-acoustic musique concrete, and machine exorcism. 

      Check out universal LCD driver IC RTD2556 on boards like this :

      ***

      It looks like I could build my own HMDI to VGA converter with two AD ICs : https://www.analog.com/en/analog-dialogue/articles/hdmi-made-easy.html

      I could combine this with a new board that uses a bunch of SPI SRAM memory chips controlled by arduino to approximate the 7 channel 4MB recording and mixing board I made. 

      I could also put a rasbpi zero with just power, an SD card containing videos and an HDMI mini out. For the Raspberry Pi I made the HDMI hot pluggable (hdmi_force_hotplug=1) and put a bunch of low res mp4 videos in the boot SD card which are accessible.

      Choreographable Video Synth

       This circuit is a next version from the video synth. 

      Some ideas from how this installation could look like :

      Messing around with my last synths, here are some circuits that I want to be able to reproduce with my new synth :

         

      Here are some ideas of how the circuit could take form :

      A Nintendo gameboy catridge teardown :

      Some sketches of possible configurations :

      *******

      I am currently splitting the project into two parts : 

      PART 1 : A series of independent transforming modules, VGA IN/OUT with screens, and oscillators with patch cables.

      PART 2: A board called palímpsêst.OS which is a rack (or archive) of several 16MB memory modules. 

      ***********

      Palimpsest.OS

      Each memory will share the same power (5V, 3.3V, GND), timing CLK signals, control signals (to enable/disable counters, buffers, RAM, ADC etc. and to RESET things). All this can be automatically controlled by an microchip which can turn on/off these memory banks individually in time. Despite this there will be basically all the components on the board to make it function independently and, most importantly, test and debug it’s functioning. 

      Just like for the previous memory board, the following parameters will be modifiable :

      • the duration of the recording and playback,
      • the sequencing of addressing this memory,
      • the amplification of the incoming and outgoing video data,
      • the sampling rate and sampling pattern of video recording and playback,
      • the bit resolution of the recording and playback,
      • the continuity of the above processes or the frequency of their interruption

      I have corrected the errata from the previous 16MB memory board, removed jumpers (as this board will be made by JLC PCB), added a ground plane, made it more compact (by removing the burst record functionality, level shifting, and having two layers). I also added a battery so that memory is persistent as long as the battery has juice. The main work however has been breaking out pins to a bus which can be controlled by a microcontroller. There is now the possibility to have 3 memory boards A,B and C, and to control their recording and playback, and all the parameters of these two things that can easily be controlled, in time. 

      With these boards it should be possible to take an input, record it, then play it back and mix it with the input through a feedback pot. Because this can be done by three memories, they can also record their respective outputs and layer without any mixing with the VGA . 

      *****

      01/12/2022 UPDATE :

      So far debugging: For some reason the ADC is not spitting out anything, regardless of what I feed it. I changed the input op amp and it had no effect. Previously to soldering the ADC everything seemed to be working…As far as I can tell the memory is working and all the bias pots too.

      ERRATA :

      -The direction pin of the 245 buffer connecting to the R2 ladder is wrong – it should be HIGH instead of LOW.  To temporarily correct this involves jumping the DIR pin to VCC – AND CRUCIALLY – to ALSO disconnect this pin from GND unless you will have a short.****

      -Why on earth did I connect all the pins without dip switches (ADC EN, 1/0 0-7, etc.) from the memory boards together ? This makes it impossible to record on one board and not on the others. I cut the non-DIP’d traces and it seems to work. 

      -the LED needs a current limiting resistor or it just explodes.

      -one switch for master record (WR EN and ADC EN)?

      -I should follow the ADC1175 instructions and isolate the DGND and AGND with caps. 

      -Should have an input pin and 5V pin for testing on board.

      -I should add the right footprint for a big capacitor at the input of the ADC (I forgot and put a 0.1uF which didn’t work).

      -It would be super cool to have a coarse and fine knob (and or a super precise pot) for the VCO for instance on the base board. 

      -I should take the classic gameboy battery footprint.

      -There isn’t an extra pin so I can send V SYNC both to be frequency divided and pass it on to the VGA out. 

      -The populated side of the memory PCB is facing “backwards” with regards to the base board…

      -The LDO pinout on the base board is wrong

      -I can’t plug in standard jumper headers to the PCIe breakout pins because they are a different diameter

      -I tried hard syncing the VGA’s H Sync with the 4046 ( see text in description of video here : https://www.youtube.com/watch?v=S694YY7sJMw&ab_channel=drumasaurusrex ). It only works with the V Sync but that’s too slow. I can’t get a stable signal out, it looks super wobly at high frequencies.  

      *****

      TESTING THE PALIMSEST.OS

      • Not sure why but it seems like I can’t record only on one board when multiple boards are connected. I have to disconnect all but the board I want to record on to get a recording onto it. *EDIT* Because I connected all the non-dipped pins from the boards together via the PCI-E bus…
      • It would be super cool to be able to send different clock signals to each board. I should maybe not have made the same CLK hardwired to each board. 
      • It’s not possible to turn the knobs when then three boards are plugged in at once because the pot shafts are too long. 
      • Not sure exactly how the battery is working, it seems like it can “remember” something for a few minutes at least. 
      • It’s hard to palimpsest various things together – You have to get one board all calibrated, then send it something from another calibrated board, record it, then rewrite to play it back. (I am hoping the new 8 channel 1 bit device makes things easier). 
      • I can’t automatically have things read or write currently, not sure why it’s not working…
      • I can’t echo with this board because I can’t simoultaneously read and write. That said I can mix a recording with live channel and then record that together into a memory and begin layering. 
      • I would like to have the image stay stable instead of always jumping everywhere. 
      • Dephasing the ADC and RAM clocks makesa large variety of nice patterns on the output !
      • It would be nice to be able to count up and down and do that to 4 bits in the middle of memory !
      • remember to connect GNDs if using memory board with analog f(x) for example
      • Trying to hard sync with h sync and cd4046 based on these links (https://www.renesas.com/us/en/document/oth/tb476regenerating-hsync-corrupted-sog-or-csync-during-vsync and https://www.youtube.com/watch?v=5VymS65eefo&ab_channel=drumasaurusrex)… I think the solution might be an oscillator in a can (with 4 not 2 leads), which I can then divide. (I can still have a free style VCO with knob to control the sampling of the ADC though !)
      • Works great with a four lead crystal oscillator can and the f divider – a very clean image that doesn’t warp ! You can still use the knob controlled high speed VCO to trigger the ADC and it’s a nice combo. 
      • *****WOW – feeding in a quartz can 10MHz into a frequency divider (and sending diff divisions to the SRAM clock), and hooking up V Sync directly to the reset, produces a really stable image that doesn’t slide left or right !!!****
      • ***ABOVE ALSO WORKS WITH H SYNC AT LOWER FREQUENCIES – SOOO COOOL : D !!
      • I’m not able to use MOSFETs or transistors to reliably automate the switch from REC to PB for some reason. I’ve even tried using an optocoupler to isolate the arduino and also tried using and AND gate as a buffer with the WR signal but neither work. I think should use mechanical relays to get around this problem or just avoid it all together by having Arduino send the CLK and WR signals in the next version. 
      • Tying differnt oscillator cans (10MHz, 12MHz, and 40MHz) 12 is nice because it doesn’t jump too much on my screen resolution (800×600). At 1280×720, 10MHz is nicest. 
      • I did a proof of concept for the 8 track recording and rerecodording idea, it seems to work though there may be a bit of interference from neighbouring channels on one another ? Not sure how I would try to isolate them from one another but some bleeding might actually be cool ?
      • I tried doing a feedback recording (recording a mix of a play back and a live feed) and had no success. Not sure why this isn’t working.

      ***********

      Realizing that this whole massive multi-module thing could be made with just one memory module having feedback !!! That or a simple echo IC like this one I ordered (BU9253 : https://www.mouser.fr/datasheet/2/348/rohm_semiconductor_rohms16891-1-1742621.pdf ) :

      That said the delay is only 8Kbits and it’s designed for audio.

      *****

      Analog Functions Board :

      Trying to remake the previous analog functions board but at JLC and as pro-style as I can. The general idea is to make a bunch of op-amp circuits that modify video in various ways and that can be combined with the logic modification board to make a completely full suite of electronics video transformations. Not sure yet how they could be automated.

      Fixes from previous esceptionally newbie laser engraved version :

      • +15/-15V supply for all the op-amps using the handy ICL7660 negative voltage generating IC will hopefully solve many issues.
      • Using normal general purpose op amps in addition to super fast video ones 
      • Having bias pots at the inputs and outputs to sort out any different in offsets. 
      • Doing more research to get better circuit designs, notably looking at the Analog Thing, The Hackaday Logic Noise Series, Rod Elliott’s active op-amp series.
      • Making things less noisy with : seperated AGND and DGND, caps near op amps, following suggested board layouts, 2 sided board with GND plane (!)
      • Tying to take into account impedence matching with 75ohm VGA camble at the input and output and testing a specialized video line driver IC
      • Making op amp board with the possibility of automating thier switching / pot levels ?
      • Adding over-amped fuz circuit, phase-shifter, and various filters (LP, HP, BP, Notch), and adding a reset to the integrator circuit. 

      I think the theme of this board, especially seeing as I have 25 of these TL074 op amps, is showing the diversity of flavours (and range of sometimes exotic circuits) of the history of op amp filters, arithmatic, etc. circuits. I plan on highlighting the names (and dates?) somehow.

      The idea has clarified now, it will be a grid of 24 different op amp circuits in a 6 by 4 grid with the name of each circuit and a letter/number identifier. At the top will be all the power, VGA in out and bias amps.

      I collected the circuits from various places (AoE among them) but especially from Rod Elliott’s write up on active filters (which you can access with Internet Archive) : http://sound.westhost.com/articles/active-filters.htm

      I am most excited about the combination of digital and analog – like in the switched cap filter, sample and hold, resettable integrator, and demux amp circuits. Being able to modify the functioning of am amp with digital signals (even with a tunable capacity and voltage controlled potentiometer) seems to offer really cool potential. This being combined with SRAM could be a really cool composite project.

      ERRATA :

      • VCCIO and GND directly overlapping on top layer  (near A2/A3) :/
      • the preamp in and out and misaligned 
      • Should have included blocking capacitors
      • VGA not being recognized by my computer with driver chip 
      • Should have included an inductor circuit
      • awful humming from the negative 12V generator
      • not enough room for 220uF caps for the video driver on board
      • some kind of “pass through” switch would be useful to show what the input looks like
      • the driver IC can only accept one color for some reason…I should not include it next time
      • the female – female jumpers are not reliable and lead to weak contacts…maybe going towards jumpers?
      • The thing is long to set up – it’s not plug and play and is finicky for demos
      • Learn about the safety of hot plugging
      • The Voltage Control works a litte, with a 1k8 resistor and picking the right voltage range. But it is not reliable, I should move to pot ICs for the next version. 

       

      • A0  with a 200uF cap after the final amp has some filtering output
      • A1  just tears the left side of the screen
      • A2  nothing happening
      • A3 varies nicely with different frequencies, though sometimes just looks like it’s “adding” frequency pattern to input
      • A4 I think the original comparator design (with 1K resistor going to VCC and pot with middle shorted to GND going to GND is correct and this one wrong)
      • A5 same note as above, but preamp in and upper seem to work. Perhaps the best way to get abstract forms from input super easily. 
      • B0 Not working…
      • B1 nice filtering !
      • B2 needs blocking cap on output or else produces nothing. Goes from filtering to almost comparator like behaviour.
      • B3 needs a cap on output and >20MHz to produce anything, no relation to input though ?
      • B4 creates a cool zebra repeating effect at one extreme
      • B5 great filter !! Both knobs do things and there is great range.
      • C0 nothing cool happening here…Seems just to pass on a modified version of the digital in signal ?
      • C1 top knob needs resoldering. Only does stuff when top knob fully to one side then behaves a bit like A3 but can go down to low frequencies on digital in.
      • C2 Cool zebra like filtering (like B4 but messier and less repetitive.
      • C3 nothing happening…
      • C4 faintest image at one extreme
      • C5 nice filter (like B5) ! Only top knob seems to do cool stuff though. (Other knob goes haywire at one extreme).
      • D0 barely the faintest image at low frequencies…
      • D1 the HP inverts the input !
      • D2 Does add when the knobs are set right. I put a cap on the function generator input.
      • D3 Does kind of subtract ! Can invert or not.
      • D4 makes a banding across the screen, not sure what effect the 3 binary inputs have…
      • D5 doesn’t really work but with the second multiplier input floating you can touch it and send the thing into an overdrive momentarily. 

      *********

      Notes from Museum visits :

      Composite (wood, porcelaine, gold) in flat, relief, and form of object.

      Could I have both feathery frilly fuzzy video mixed with crisp solid geometric form to create similar layering ?
      Some video noise looks like different types of stone
      Rococo / Baroque video ?
      Decorative video?
      High quality video / image capture ?
      Once I’ve finished with this round of tools, I have to compose more !!

      Can I mirror an image half way to make a Rorschach like ink splot ?

      Wicker chair silhouette series, pumpkins 
      Some format of showing the circuit and the output that can end up in a book
      Shoot my own video to mess with

      Layering

      Contour
      Surface
      Saturation
      Flow vs. Choppiness
      Look at Photoshop for 
      Roughness, relief 
      Edges versus centers 

      Movement vs stasis 

      Enriching of detail possible ?
      Abstracting, cosmic making
      Fine lines versus coarse
      Exposure 
      Color fields
      Texture
      Deep friedness
      Films of cows, ocean. Stills of still life? Flowers, birds, drapes folding, mold, fruit, bones
      Color mixing vs melting vs meeting
      Paint viscosity (runny vs clotted)
      Direction of brush strokes 
      Contour
      Focus direction in canvas
      Translucent flesh, shine vs glow from interior, waxiness 
      Graininess 
      Composition, color pairings and form
      Foreground displaced to background vice versa 
      Meeting pattern planes 
      Lighting and shadow
      Illusion of depth
      Cloudiness 
      *****
      IDEA : I could take a file, put it into the memory, and then “play” it different ways (because the width is completely arbitrary below). A file could thereby become a pattern, or a long abstract video, 

      Windows PE visualization

      Or I could put an image onto a floppy, then damage the floppy, and show how it would modify the image ?

      THINGS TO TRY:

       

      • Palimpsest.OS with arduino controlling WR and COUNTER CLK (and forgetting about CLK) to control the boards recording and playing back. 

       

      • Check out Video Effects list from Adobe Premiere : https://helpx.adobe.com/premiere-pro/using/effects.html
      • test outputting to a projector !! * EDIT * WOW this was a good idea :

      • take HDMI and mess with it digitally (but not analogically?)

      • design easier to understand / less complex board which is more plug and play ? *EDIT* Try 74*8154 16 bit counter + 32K x8 IS61C256A SRAM !
      • Take photos of boards in the light box !  

      This is what a loop sounds like :

      *****

      I’m currently working on a final set of four boards for the Choreographable Video Synth that will finish this project. 

      All the boards will have the following improvements :

      • Plug and play – very little setup time, no need for a function gen, and no fiddling to get an image on the screen for demos quickly.
      • Nice 2mm banana connectors and 30cm multi colored patch cables that make reliable connections and are more modular. (Not sure about edge connecting female plugs and edge actionnable pot knobs or vertical plugs).
      • Only the best bits of the previous boards (Analog f(x), Oc74, Palimpses.OS) in a smaller square format with playful designs.
      • The three f(x) boards will have an onboard audio amp + speaker to hear the signals you are making. A speaker hole will be present.
      • Finished product for inauguration of the IFT in early March, 75mmx75mm ans nice compositions. 
      • Make this version actually be entirely controlled by digital potentiometers and buffers and then also be able to manually control these digital devices on board with hardware switches and buttons. 

      SIGNALS IN/OUT board :

      • Takes VGA, HDMI, DVI-A in, and puts out VGA and HDMI. (Or just VGA in and out?)
      • Has a passthrough switch to see directly what’s on the screen. (Or skip this?)
      • Has a final mixing stage (especially a microcontrolled matrix mixer !!)
      • Acts as a power supply for the other boards (12V because the analog board needs this?)
      • Could take 2 VGA inputs ?
      • Has an atmega 328 to output low res H and V ?

      ANALOG F(X) board:

      • Only the four best of the 24 analog functions board. (Butterworth HP, LP, Analog MUX, ADC)

      OC74 DIGITAL F(X) board :

      • Only the best functions (comparator, DAC, S+H, XOR, Bin Counter)

      MEMORY board (OR MAYBE THIS IS A SEPERATE KIT AND I SHOULD JUST MAKE A 16MB MEMORY BOARD AGAIN?) :

      • 8 channels of 1 bit memory recording on a total of 1MBit of SRAM
      • Comparators acting as 1-bit ADCs (but maybe this belongs on another board ?)
      • A battery system that actually works (where battery and input voltage Diode-OR’d and with an ON-OFF switch to conserve batt)  !
      • Double SRAM so that I can begin messing with echo and delay, and rerecord over non-new signal channels
      • Series of 74AUP1G157GW MUX to prevent any damage to memories when recording fresh signals and to make this process automizable
      • A pulse generation setup which does not need an external function generator… (like by using an oscillator can).

      Some possible playful interface designs (I especially like the gravity effected ones) :

      ***

      Arduino controlled SRAM :

      Not yet working so going to test with two mechanical relays – this HAS to work or else I’m crazy.

      This code can get the SRAM writing :

      void setup() {
      pinMode(13, OUTPUT);
      pinMode(12, OUTPUT);
      }
      
      void loop() {
      //WRITE
      PORTB = B11101111; // CLK goes LOW/HIGH
      PORTB = B11011111; //WR goes HIGH/LOW
      }

      This code seems to work but it’s results are not predictable (I think because the code runs too slowly)… :

      unsigned long startMillis; //some global variables available anywhere in the program
      unsigned long currentMillis;
      const unsigned long period = 1000; //the value is a number of milliseconds
      int WRState = HIGH; // the current state of the WR pin
      
      void setup()
      {
      pinMode(13, OUTPUT); //WR PIN
      pinMode(12, OUTPUT); //CLK PIN
      pinMode(11, OUTPUT); //ADC EN PIN
      startMillis = millis(); //initial start time
      }
      
      void loop()
      {
      
      if(WRState == HIGH)
      {
      currentMillis = millis(); //get the current "time" (actually the number of milliseconds since the program started)
      
      //WRITE TO SRAM
      PORTB = B11101111; // CLK goes LOW/HIGH, ADC_EN HIGH
      PORTB = B11011111; //WR goes HIGH/LOW, ADC_EN HIGH
           if (currentMillis - startMillis >= period) //test whether the period has elapsed
           {
            WRState = !WRState;
            startMillis = currentMillis; //IMPORTANT to save the start time of the current LED state.
           }
      }
      
      if(WRState == LOW)
      {
      currentMillis = millis(); //get the current "time" (actually the number of milliseconds since the program started)
      
      // READ SRAM
      PORTB = B11100111; // CLK goes LOW/HIGH, ADC_EN LOW
      PORTB = B11110111; //WR stays high, ADC_EN LOW
      
           if (currentMillis - startMillis >= period) //test whether the period has elapsed
            {
             WRState = !WRState;
             startMillis = currentMillis; //IMPORTANT to save the start time of the current LED state.
            }
      }
      }
      

      Magnetic Media Video Synthesis

       

      I want to continue messing around with magnetic media (audio cassette players/recorders, floppy disk drives, video camcorders) and try to get them recording and playing back video.

      Here is some inspiration :

      From the timeless Hardware Hacking manual. The suggestion is to use a high gain amplifier to hear the results of the tape pickup. :

      A very cool project putting video onto a cassette :

      https://www.ubergizmo.com/2020/04/audio-cassette-tape-used-to-capture-video/

      From this reply : https://electronics.stackexchange.com/questions/108907/create-input-jack-from-tape-head

      “You can use the continuity tester to check for the ground lead. This should be connected to the metal shield of the head, you can leave it unconnected. You’ll want to connect the other two wires to your two inputs”

      From this site http://stevecoates.net/walkman/ :

      This https://makezine.com/projects/turn-old-walkman-scratchbox/ Make Magazine article connects simply :

      Four-terminal play head

      Some very cool experiments with a disconnected tape head :

      And a custom loop tape :

      **************************

      I began testing a bit, it looks like I can both see and hear the audio signals from the tape (yellow is R?, blue is L?):

      It’s most audible right near the end (the hum is the tape cassette motor spining) :

       

      *****************************************

      The method is just to power the cassette rotating motor with around 3.3V, then hook up the red(R?) or white(left?) to a probe or audio in for an amp, and then the black (GND) – which looks like it’s connected to two pins – to GND.

      The next step would be to try to amplify with a high gain op-amp circuit ? And then to begin trying to write ?

      UPDATE :

      Might be easier to work with the electronics already present on the board, learn how it works, desolder it and then put it on a breakout board to mess around with? Here is one of the simplest ICs I found on one of the dissassembled tape decks in an easy to solder SOP16 package:

      I could order a series of boards like this to make tests with them : SOIC-32, SOP-32 | SMD to DIP Adapter | SchmalzTech

      UPDATE:

      I plugged in the little audio amp into the Audio out jack of the device while I touched different pins on the IC. I found that the large slide switch on the back switched from REC to PLAY. I found that during REC mode the pins that caused the most amplification were the MIC IN and EQ IN. In PLAY mode I found the most important pin for producing output on the AUDIO OUT was LINE IN.

      I also tried connecting the little speaker amp to the REC OUT, LINE OUT while I touched various pins. 

      I was unable to amplify the tape head signals however with any of the various combinations I tried. I will try the other tape cassette circuit boards to see if I have any more luck, and also test the 2.5W power amp from Adafruit. Ideally I would be able to take an input, amplify it, send it to the tape head, then read it back by reversing the sequence after rewinding to the same section. This should also work with a strip of tape taped to a desk that I can manually run the magnet head over (right??). 

      Once I’m able to do this, I want to try the same thing (amplify an analog signal, write it to the disk through the heads directly, then read the analog signal back off it) with the Floppy Circuitry. 

      *************

      A great VCR technical reference : https://www.wikiwand.com/en/VHS

      I got my hands on a VCR, took it apart and broke out the cable coming from the helical read/write head.

       

       

      It looks like there is one little board with all the drivers for the various motors. Might be able to control it. (See this video : https://www.youtube.com/watch?v=4F7xJOb32GI&ab_channel=LifeOfDiy). I’ve got a BA6878EFV 3-phase motor driver for VTR capstan, datasheets available online. It looks like you need to plug in GND (3), 5V (2), and then connect EC(7) and HYS OUT (9) together.

      So far I haven’t been able to pick anything up on the oscilloscope from moving the tape across the print heads while listening in to various output pins.

      https://www.wikiwand.com/en/VHS#Media/File:Medion_MD8910_-_VHS_Helical_scan_tape_head-8601.jpg

      There appear to be two video heads (with two wires each – one wire for each electromagnet) and two audio heads (with one wire each) making a total of 6 wires with 1 dummy. It looks like the pinout is the following :

      1. Video Green 1
      2. Video Red 1
      3. Video Green 2
      4. Video Red 2
      5. No connection (shortened turn)
      6. Audio Red
      7. Audio Green

      It seems like others have two shortened turns to help isolate signals from one another.

      I measured the resistances between the output pins:

      1. grey 
      2. white
      3. blue(1)
      4. green
      5. yellow(1)
      6. orange
      7. red
      8. blue(2)
      9. yellow(2)

      The following are connected :

      Looking up the chip LA71750 ( Video and Audio Signal-Processing IC) – on the right in the image below – and the LA7264B (Audio Signal-Processing IC) – on the left – and checking out the datasheets and inspecting the PCB, looks like the following are the important connections :

      From the LA71750 datasheet :

       

      Would appear possible to make this pinout diagram :

      I have tried connecting pins to the oscilloscope while moving the tape head, but even at 10mV level at various time scales I can’t see anything. 

      UPDATE : Just seeing now that this chip takes control data in the form of I2C. It would be super hard for me to desolder the chip and make my own controller with it as a result.

      ******************

      I have tried amplifying and sending 20V signals at various frequencies. 

      Turning to more research for answers, check out these links :

      Article about audio sampler made from floppy :

      https://nime.pubpub.org/pub/uh76shf0/release/1

      Video made from floppy :

      Freespin is a demo made for the Commodore 1541 – no, not the computer, just the floppy drive

      For more tech info about floppy heads :

      http://forums.openmusiclabs.com/viewtopic.php?f=11&t=92&sid=9a4c3a6763f9bc02426c9d3910187e70

      ******************

      From this reading break I think the following things should be attempted :

      -with a >2W class D amp can I push some signal onto the tape that I can then read ? (Just afraid that it won’t be fast enough for video signals as it is made for audio signals ? Perhaps a high power high speed amp is even better?).

      -I could get the same preamp LA IC used in the concentric sampler paper.

      -Everyone seems to say, “try different combinations with the R/W heads” and “check continuitiy” and apply the signal to continuous wires. 

      -I could try adding the bias oscillator to the signal I’m trying to R/W?

      -I should get a super strong magnet for testing purposes

      ***********

      Looking at my floppy drive, I found the following CX20185 chip which is a Read/Write Amplifier for Floppy Disk Drive.

      It looks like the pinout is the following :

      It looks like I could read the Preamp Out pins to read from the floppy. I’m not sure how I could yet wright to the floppy without giving data to the logic on the driver.

      Here is me figuring out the pinout :

      I turned on the floppy LED I have by connecting the sixth pin next to the stepper head motor to the GND, and turned on the central motor by connecting the 8th pin to GND and plugging in 12V as well :

      When I listen in to READ DUMP A or B I can see voltage when I spin the disk manually (when I plug in the brushless motor it no longer responds to spinning):

      When I listen in to PRE OUT A or B I can see the normally high voltage go down and vary :

      Meh. 

      Some stuff about data degredation :

      https://fr.wikipedia.org/wiki/The_Disintegration_Loops

      Project Kryoflux – Part 3: Recovery in Practice

      ******

      Suggestion from research engineer at DVIC for the previous experiments:

      -For the floppy, look at the input from head (but oscilloscope will probably mess this up), preamp, and digital out (READ OUT – which should be connected directly to the chip I have the datasheet for) at same time. 

      -Basically you’re not going to see anything on the oscilloscope when looking at these electromagnets. It’s all in the very sensitive amp – so all the more reason to use the amp that comes with the device !

      -Is the preamp chip IC I am looking at even enabled ? Check POWER ON.

      -Try the floppy pinout here : https://old.pinouts.ru/HD/InternalDisk_pinout.shtml

      -For the VCR, get the thing plugged in and functioning as it was in the beginning. Observe it first, then try to intervene (you’ll never be able to reinvent the thing from nothing !)

      ****

      Listening to the DATA READ pin 33 while the disk is spinning :

      ****

      UPDATES:

      I learned from watching this (https://www.youtube.com/watch?v=DdMOGvKjrfk&ab_channel=JeffHxC2001) that the way to read is to sync the oscilloscope with the INDEX pulse. The Difference Out pin is the one being listened to in this video.

      I learned from looking more into the floppy interface that the Head Select (32) is HIGH for BOTTOM and LOW for TOP head. I also learned that Floppy Write Enable (24) is HIGH to READ and LOW to WRITE. Finally, the READY pin 34 may need to be tied to GND.

      From a Floppy Maintenance Manual showing the sequence : R/W head > Pre-Amp > Differentiator > Voltage Comparator > Time/Domain Filter > DATA OUT

      UPDATES:

      I think to make this project work, I would first need to *VERY CAREFULLY* observe the correct functioning of a working device without any changes made to it. I would need to be able to confirm completely the working of the machine, and see what signals are supposed to look like at each step. 

      Only after doing this could I start intervening in this process.

      I think Floppy is the best way to go – it’s part of the history of the computer (like all my other projects) which isn’t the case with the video recorder. The floppy is the best documented, easiest to source, and least expensive to work with. It already has a nice interface which is easy to use. It also is more standardized, unlike the many different kind of video recorders that exist. 

      What is the most standard Floppy Drive Read/Write Amplifier ? The Sony CXA series (1360, 1720, 3010, 3071, 20185, etc.) seem to have specs available online. ROHM also have BH6xxx and BA6xxx series. 

      Then again if I’m only going to be recording analog, I don’t need anything but the preamp (especially for reading) ? I could just take the tape preamps I have and put them on a breakout board ? I have BA3110, CX20023, and a CXA1262 to work with. I could try getting them to work amplifying the mic first, and also get the playback working. Then I could test putting analog signals on a floppy.

      Video synth workshop

      This workshop with La Diagonale at UP Saclay is a simple circuit to begin playing with code and screen patterns. 

      Here is the github: https://github.com/merlinmarrs/spaghettini-video-synth

      Arduino Coding and Video Synthesis Workshop

      Lean to code in C with Arduino, solder and assemble a custom printed-circuit board made in the Fablab, and make your own algorithmically-generated video art!

      This workshop is inspired by the improvisational music of Live coding (https://fr.wikipedia.org/wiki/Live_coding) and the burgeoning minimalist Bytebeats movement (https://nightmachines.tv/bytebeats-tutorial).

      Our video synthesis kit plugs in to the Arduino (https://www.arduino.cc/), a reprogrammable embedded micro-controller that can interact with the world through code, and uses the VGAX library (https://github.com/smaffer/vgax) to generate funky video.

      Meet other creative technologists and sharpen your expertise in computer sciences and electronics soldering!

      Here are some initial sketches :

      The functionality that is important is :

      -being able to select between different programs (with button and leds to indicate)

      -to be able to take audio in and have it modify the patterns on screen

      -to be able to change the colors on the go

      -I have since phased out the brightness changeability but I could add an LDR easily ?

      *******************************************************************************************

      Because our lasercutter is not operational, I am trying to make this circuit with the vinyl cutter using 5cm wide copper tape. 

       

      I am worried about the headers getting pulled out when plugging/unplugging. I will try adding some hot glue to fortify them. The other option is potting the circuit in resin but that would get messy and expensive. 

      Errata:

      -button too close to headers when glue is applied

      -remember space for audio in jack plug 

      -the two columns of headers for the Arduino should not be continuous, also unclear what is first and last pin. Also they should be SMD headers. 

      -don’t mess with RX and TX pins on the Arduino. 

      -make a version with VGA plug?

      -add text but have it cut onto plastic not made from metal

      -audio offset thing doesn’t work

      I also want to think about expandability, how could people take this project further by themselves afterwards ?

      -Having a knob  or two knobs / LDR connected to an analog in on the Arduino…

      -Be able to control the program based on voltage control levels at an input. This could mean it could even be attached to the polyphonic synth !

       

      ***************************************************************************

      Here is the next version called the Spaghettini:

      -It respects the height of the 50mm wide copper tape I have on hand.

      -It makes more sense for the audio in cable to plug in at the side and not interfere with the capacitive sensor. 

      -It uses curvy lines just for the capacitive sensing functionality and straight elsewhere which feels honest. 

      -It has the ability to modify the brightness of any of the three channels, one at a time. 

      -It has a potentiometer for analog in in adition the capacitive sensor. 

      -I’m experimenting with different patterns on the left portion.

      -The sensor works with the Arduino library CapacitiveSensor 

      And here’s what it looks like all plugged in ! (But I need to add hot glue to make it really usable)

       

      Memory Experiments (continued)

      I have two goals for this project:

      1. Finish the VGA video recorder board (with op amps, bias pots, bias for ADC) – DONE!
      2. Make a version of the vectorscope image modification series but with a raster system taking the following image as the input – DONE :

      1. Finishing the VGA Video Sampler board

      For the first goal, I need to correct that last board I made:

      Errata:

      -The gain pots for the op-amp don’t work.

      -I mixed up VCC (3.3V) and VCA (5V) in several places. (I just replaced the PFET with the LDO and manually rewired)

      -The “EN” text next to the ADC was in the wrong place. 

      -I forgot to tie down the reset of 74HC590 with a 10K resistor.

      -The 74HC04 is labelled backwards, I put inputs on the right and outputs on the left for some reason.

      Things appear to work with these changes:

      It takes some knob fiddling but I can get an input sine wave digitalized. One definitely needs an oscilloscope to see what’s happening though.

      2. Vectorscope image series

      I can either load the image into memory by playing it on a computer screen and capturing the pixels, OR, loading the image into memory with a microcontroller. I’m not sure how big I should make the image, and what dimensions, if I load the image. 

      Here is the p5.js code to take an image (called p.jpg) and print the red pixel value into a text document (called OUTPUT) with a comma and space seperator :

      let img;
      
      function preload() {
      img = loadImage('p.jpg');
      }
      
      function setup() {
      createCanvas(img.width, img.height);
      background(220);
      image(img, 0, 0);
      let writer = createWriter('OUTPUT.txt');
      
      for(var y = 0; y < height; y++) {
      for(var x = 0; x < width; x++){
      let pix = img.get(x, y);
      writer.write(pix[0] + ', '); // takes RED pixel info, adds a comma and a space
      if(!(y==1-height || x==1-width))
      {
      writer.write(pix[0]); // don't put a comma if it's the last element of the list
      }
      }
      }
      writer.close();
      }

      And here is the Arduino code to take this color information and load it into the memory space (90×90 max as PROGMEM has max 8,192 bytes max):

      byte myChar;
      
      #define IMG_WIDTH 90
      #define IMG_HEIGHT 90
      //data size=900 bytes
      const unsigned char img [IMG_HEIGHT*IMG_WIDTH] PROGMEM={
      17, 19, 19, 19, 19, 20, 20, 20, 20, 20, 21, 23, 23, 22, 21, 21, 22, 22, 21, 22, 21, 22, 21, 20, 21, 21, 23, 23, 23, 23, 23, 23, 24, 23, 25, 23, 24, 23, 25, 25, 25, 25, 25, 24, 25, 26, 24, 23, 25, 24, 23, 24, 25, 21, 20, 24, 24, 23, 20, 20, 21, 23, 22, 22, 22, 22, 22, 23, 23, 24, 23, 23, 23, 25, 23, 24, 24, 23, 24, 25, 23, 25, 25, 23, 25, 24, 24, 25, 28, 28, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 19, 35, 25, 32, 32, 26, 27, 17, 23, 27, 30, 33, 33, 35, 37, 35, 29, 30, 34, 37, 44, 26, 30, 65, 65, 57, 56, 55, 57, 59, 42, 38, 46, 38, 33, 40, 41, 43, 46, 35, 3, 0, 0, 0, 0, 1, 1, 0, 9, 49, 18, 0, 4, 0, 0, 0, 3, 2, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 3, 29, 231, 255, 245, 252, 250, 247, 248, 240, 245, 249, 255, 255, 255, 255, 255, 254, 254, 255, 255, 255, 255, 252, 252, 255, 254, 255, 254, 255, 255, 255, 254, 255, 255, 254, 253, 255, 255, 255, 255, 255, 71, 1, 1, 1, 1, 0, 15, 189, 244, 255, 223, 205, 216, 183, 191, 207, 210, 221, 234, 240, 233, 220, 215, 113, 138, 251, 225, 219, 223, 224, 169, 166, 201, 208, 217, 220, 196, 190, 181, 189, 181, 188, 193, 148, 149, 207, 171, 25, 0, 50, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 250, 245, 244, 253, 255, 255, 246, 240, 239, 231, 239, 234, 255, 255, 255, 249, 238, 234, 247, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255, 255, 90, 0, 1, 0, 1, 1, 43, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 241, 229, 249, 255, 255, 255, 254, 249, 249, 248, 255, 251, 254, 254, 255, 242, 235, 241, 253, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 77, 0, 31, 240, 254, 249, 189, 170, 192, 190, 179, 202, 131, 12, 4, 0, 107, 226, 192, 54, 0, 11, 8, 2, 2, 146, 225, 204, 71, 0, 0, 65, 200, 206, 192, 194, 197, 185, 200, 255, 255, 255, 211, 24, 0, 1, 0, 1, 0, 8, 178, 255, 255, 243, 204, 194, 197, 198, 189, 209, 181, 25, 0, 0, 106, 217, 213, 96, 0, 6, 5, 7, 0, 126, 236, 199, 38, 0, 0, 84, 220, 208, 203, 205, 198, 210, 200, 225, 255, 255, 68, 0, 19, 226, 254, 219, 10, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 190, 255, 255, 95, 0, 3, 0, 2, 0, 3, 0, 48, 253, 255, 151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 144, 255, 255, 80, 0, 62, 255, 255, 235, 24, 0, 0, 0, 0, 0, 3, 2, 0, 1, 2, 0, 1, 5, 3, 1, 1, 2, 4, 1, 0, 0, 1, 0, 3, 2, 0, 0, 0, 0, 0, 0, 0, 189, 255, 255, 105, 0, 1, 1, 1, 0, 3, 0, 65, 255, 255, 124, 0, 1, 0, 0, 0, 0, 0, 3, 6, 2, 1, 0, 0, 4, 3, 0, 3, 1, 1, 2, 1, 0, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 157, 255, 255, 85, 0, 45, 252, 255, 241, 31, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 2, 1, 0, 0, 187, 255, 255, 102, 0, 2, 1, 0, 0, 2, 0, 94, 255, 254, 143, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 2, 3, 1, 0, 0, 0, 134, 255, 255, 69, 0, 48, 253, 255, 227, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 1, 0, 0, 0, 0, 2, 0, 0, 178, 255, 255, 119, 0, 1, 0, 0, 1, 2, 0, 66, 255, 255, 138, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 145, 255, 255, 84, 0, 49, 254, 255, 229, 19, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 0, 0, 0, 1, 1, 2, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 196, 255, 255, 110, 0, 0, 0, 0, 0, 2, 1, 54, 255, 255, 138, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 130, 254, 255, 76, 0, 39, 245, 255, 225, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 2, 1, 23, 233, 255, 255, 82, 0, 2, 1, 0, 1, 1, 0, 61, 255, 255, 124, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 142, 255, 254, 74, 0, 55, 255, 254, 246, 31, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 6, 207, 255, 255, 116, 0, 2, 0, 0, 0, 1, 1, 99, 255, 255, 137, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 92, 255, 255, 83, 0, 32, 254, 255, 107, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 1, 0, 0, 2, 1, 0, 71, 231, 255, 79, 0, 3, 0, 0, 0, 5, 0, 68, 241, 193, 48, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 159, 255, 89, 0, 55, 255, 182, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 1, 1, 0, 4, 1, 0, 0, 5, 6, 0, 0, 0, 2, 3, 1, 1, 0, 1, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 3, 3, 0, 137, 255, 95, 0, 52, 255, 186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 3, 0, 0, 2, 1, 1, 1, 1, 14, 41, 8, 0, 1, 1, 0, 0, 2, 7, 4, 0, 1, 2, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 2, 0, 0, 173, 255, 80, 0, 40, 254, 238, 34, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 7, 5, 0, 0, 0, 1, 1, 0, 29, 124, 222, 255, 113, 0, 0, 0, 0, 0, 4, 0, 44, 174, 80, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 114, 255, 255, 75, 0, 44, 250, 255, 225, 17, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 3, 1, 5, 1, 2, 5, 6, 3, 1, 2, 4, 4, 4, 2, 0, 0, 0, 1, 0, 93, 255, 255, 254, 191, 1, 0, 0, 0, 0, 2, 0, 60, 255, 255, 101, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 1, 0, 0, 2, 0, 113, 255, 255, 87, 0, 47, 251, 255, 249, 36, 1, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 1, 2, 1, 1, 3, 3, 1, 1, 1, 3, 0, 1, 1, 0, 0, 0, 0, 1, 89, 255, 255, 255, 178, 0, 0, 0, 0, 1, 2, 0, 66, 241, 255, 139, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 67, 255, 255, 87, 0, 51, 245, 254, 235, 24, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 86, 255, 255, 254, 197, 0, 0, 0, 0, 0, 3, 0, 97, 163, 192, 142, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 1, 0, 1, 0, 1, 115, 255, 255, 77, 0, 68, 254, 255, 241, 29, 1, 2, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 95, 255, 255, 255, 192, 0, 1, 0, 1, 0, 3, 0, 78, 237, 254, 114, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 118, 255, 255, 84, 0, 72, 255, 255, 251, 41, 0, 2, 0, 0, 1, 3, 1, 1, 0, 0, 3, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 2, 1, 0, 1, 2, 0, 71, 255, 254, 255, 160, 0, 0, 0, 0, 1, 3, 0, 26, 233, 255, 132, 0, 0, 2, 0, 1, 1, 2, 2, 2, 2, 2, 0, 1, 0, 1, 2, 0, 1, 2, 3, 3, 2, 1, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 165, 255, 255, 83, 0, 77, 255, 254, 227, 17, 0, 0, 0, 0, 0, 1, 4, 2, 2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 51, 253, 255, 255, 158, 0, 0, 0, 0, 2, 0, 1, 54, 255, 255, 98, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 3, 3, 4, 2, 0, 0, 0, 0, 0, 0, 0, 139, 255, 255, 72, 0, 71, 255, 255, 229, 89, 66, 87, 83, 78, 90, 46, 0, 0, 0, 103, 142, 136, 145, 128, 162, 157, 122, 126, 127, 128, 127, 128, 130, 128, 128, 127, 127, 127, 126, 125, 106, 172, 255, 255, 255, 224, 30, 0, 0, 0, 0, 3, 0, 92, 255, 254, 135, 0, 46, 44, 8, 11, 39, 30, 25, 26, 34, 54, 45, 22, 39, 32, 28, 28, 26, 28, 27, 38, 14, 0, 4, 0, 5, 32, 37, 29, 27, 32, 25, 9, 169, 254, 255, 88, 0, 26, 227, 255, 255, 255, 255, 255, 255, 255, 255, 231, 36, 0, 61, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255, 254, 255, 255, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 116, 0, 0, 0, 1, 0, 20, 190, 255, 254, 250, 239, 255, 255, 181, 196, 255, 245, 240, 241, 248, 255, 247, 239, 253, 246, 245, 245, 242, 243, 243, 255, 173, 0, 0, 0, 100, 254, 255, 245, 243, 247, 246, 246, 250, 255, 255, 79, 0, 46, 245, 255, 255, 254, 255, 255, 255, 255, 255, 255, 190, 0, 163, 255, 255, 254, 255, 255, 255, 255, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 254, 255, 254, 255, 255, 255, 138, 0, 0, 0, 1, 0, 61, 255, 255, 255, 254, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 119, 0, 12, 222, 255, 255, 255, 255, 255, 254, 255, 255, 255, 249, 48, 0, 80, 255, 255, 237, 139, 113, 121, 128, 127, 123, 149, 83, 1, 92, 219, 207, 197, 173, 206, 190, 150, 183, 255, 255, 255, 221, 214, 199, 170, 170, 180, 189, 242, 255, 255, 255, 254, 255, 255, 255, 255, 131, 0, 0, 0, 1, 0, 58, 255, 254, 255, 255, 254, 255, 255, 172, 80, 103, 108, 175, 220, 199, 101, 141, 255, 255, 158, 74, 100, 96, 102, 107, 87, 109, 60, 0, 4, 104, 128, 109, 115, 114, 125, 108, 97, 209, 255, 255, 88, 0, 58, 255, 255, 157, 0, 0, 0, 0, 0, 1, 0, 0, 5, 1, 1, 0, 0, 1, 0, 1, 0, 10, 221, 255, 253, 48, 2, 1, 0, 3, 12, 83, 255, 255, 254, 255, 255, 255, 254, 249, 193, 35, 0, 1, 0, 1, 1, 0, 79, 162, 233, 255, 255, 255, 255, 129, 0, 1, 8, 14, 11, 6, 8, 85, 255, 255, 70, 0, 0, 1, 1, 0, 0, 1, 1, 7, 10, 2, 1, 0, 0, 0, 0, 1, 0, 115, 255, 255, 86, 0, 80, 254, 187, 0, 0, 0, 2, 1, 1, 1, 0, 2, 6, 1, 0, 0, 0, 1, 0, 0, 0, 23, 231, 255, 255, 60, 1, 0, 1, 98, 200, 251, 254, 255, 255, 255, 241, 154, 81, 9, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 6, 70, 183, 254, 255, 254, 189, 27, 16, 8, 0, 0, 5, 169, 255, 255, 86, 0, 1, 2, 3, 5, 4, 1, 1, 3, 5, 4, 4, 0, 1, 3, 1, 3, 0, 0, 169, 255, 90, 0, 88, 255, 179, 0, 0, 0, 0, 0, 1, 2, 4, 2, 1, 5, 5, 5, 1, 0, 2, 0, 1, 57, 255, 255, 255, 86, 0, 1, 137, 255, 255, 254, 255, 254, 209, 79, 11, 1, 0, 0, 1, 2, 0, 1, 0, 0, 1, 1, 2, 1, 1, 0, 0, 42, 168, 255, 255, 252, 152, 27, 1, 0, 14, 193, 255, 255, 88, 0, 2, 0, 2, 1, 1, 3, 6, 2, 0, 6, 4, 0, 1, 0, 0, 2, 4, 0, 150, 255, 89, 0, 64, 255, 255, 73, 0, 0, 0, 0, 2, 2, 8, 8, 0, 2, 4, 3, 1, 0, 1, 1, 0, 47, 250, 255, 255, 114, 0, 141, 255, 255, 255, 255, 247, 107, 0, 0, 1, 1, 2, 0, 1, 1, 0, 0, 1, 0, 0, 1, 2, 2, 0, 2, 1, 0, 0, 77, 244, 255, 255, 200, 22, 4, 12, 141, 255, 255, 87, 0, 2, 3, 1, 1, 0, 1, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 33, 221, 255, 79, 0, 72, 255, 255, 201, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 34, 242, 255, 255, 90, 50, 255, 255, 253, 255, 220, 37, 0, 1, 9, 3, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 2, 2, 1, 1, 1, 0, 4, 4, 0, 27, 208, 255, 255, 196, 24, 8, 62, 255, 254, 86, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 174, 255, 255, 92, 0, 99, 255, 255, 227, 16, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 64, 255, 255, 255, 87, 145, 255, 255, 255, 214, 23, 0, 2, 2, 5, 5, 0, 2, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 5, 0, 8, 192, 255, 185, 5, 2, 80, 255, 255, 91, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 172, 255, 255, 93, 0, 105, 255, 255, 226, 16, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 52, 253, 255, 243, 131, 217, 255, 255, 235, 33, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 2, 0, 0, 214, 207, 0, 0, 73, 254, 255, 89, 0, 3, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 173, 255, 255, 97, 0, 93, 255, 255, 221, 13, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 49, 252, 255, 253, 254, 255, 255, 255, 97, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 33, 239, 193, 81, 141, 255, 254, 93, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 168, 255, 255, 93, 0, 68, 255, 245, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 34, 242, 255, 255, 255, 254, 255, 139, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 113, 254, 255, 255, 254, 255, 94, 1, 3, 0, 0, 1, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 191, 255, 94, 0, 69, 255, 185, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 16, 228, 254, 255, 255, 255, 212, 15, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 5, 204, 255, 255, 255, 255, 88, 0, 2, 1, 1, 3, 2, 1, 5, 2, 2, 1, 1, 1, 1, 0, 0, 2, 1, 0, 153, 255, 95, 0, 92, 254, 179, 0, 1, 0, 0, 0, 0, 0, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74, 254, 255, 255, 255, 255, 111, 0, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 0, 101, 255, 255, 255, 255, 94, 1, 0, 3, 2, 3, 4, 5, 7, 3, 5, 7, 5, 2, 0, 1, 0, 0, 5, 1, 163, 255, 93, 0, 102, 255, 241, 50, 0, 0, 0, 0, 0, 1, 0, 5, 4, 2, 0, 0, 0, 0, 0, 0, 0, 81, 255, 254, 254, 255, 233, 25, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 3, 1, 10, 216, 254, 255, 254, 86, 0, 0, 1, 0, 0, 0, 1, 2, 6, 6, 4, 0, 0, 1, 0, 0, 0, 1, 21, 220, 255, 87, 0, 72, 255, 254, 235, 163, 162, 167, 164, 164, 182, 89, 0, 0, 15, 192, 233, 211, 212, 212, 210, 236, 223, 242, 255, 255, 255, 164, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 3, 2, 0, 0, 125, 255, 255, 255, 169, 87, 118, 97, 98, 106, 124, 72, 0, 5, 0, 39, 152, 148, 142, 143, 141, 146, 132, 216, 255, 255, 94, 0, 81, 255, 255, 255, 254, 255, 255, 255, 255, 255, 246, 63, 0, 115, 255, 255, 255, 255, 255, 255, 255, 254, 255, 254, 255, 255, 67, 0, 1, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 6, 0, 56, 255, 254, 255, 255, 255, 255, 255, 255, 254, 255, 255, 75, 0, 0, 165, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 98, 0, 87, 254, 255, 254, 255, 254, 255, 255, 255, 255, 255, 109, 0, 165, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 48, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 25, 232, 255, 237, 255, 244, 238, 255, 249, 248, 255, 254, 150, 0, 2, 212, 255, 255, 255, 255, 254, 254, 250, 252, 255, 255, 100, 0, 37, 224, 255, 173, 71, 81, 83, 70, 66, 70, 69, 20, 0, 81, 177, 148, 121, 117, 119, 116, 116, 119, 116, 118, 128, 82, 1, 1, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 1, 3, 2, 0, 25, 36, 15, 41, 23, 18, 46, 31, 26, 36, 30, 10, 0, 0, 34, 55, 37, 40, 41, 41, 40, 8, 91, 234, 222, 57, 0, 0, 11, 12, 3, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 3, 2, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4, 1, 0, 0, 0, 1, 1, 0, 0, 0, 2, 0, 3, 4, 3, 0, 0, 1, 4, 2, 2, 2, 1, 3, 2, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 3, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 3, 6, 1, 2, 1, 0, 0, 2, 5, 4, 0, 0, 2, 2, 0, 2, 10, 7, 0, 0, 2, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 4, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 5, 8, 1, 5, 7, 2, 1, 0, 0, 0, 1, 1, 0, 1, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 1, 0, 0, 0, 0, 0, 5, 1, 1, 0, 6, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 4, 1, 0, 0, 0, 0, 0, 7, 8, 0, 0, 1, 0, 0, 0, 0, 0, 3, 56, 60, 8, 0, 1, 161, 252, 137, 40, 65, 62, 45, 46, 68, 68, 16, 0, 18, 97, 111, 100, 100, 95, 100, 111, 113, 108, 129, 137, 42, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 0, 11, 183, 217, 202, 207, 213, 221, 195, 189, 202, 211, 234, 99, 0, 0, 104, 182, 142, 141, 153, 141, 145, 126, 189, 255, 253, 45, 0, 18, 225, 255, 255, 255, 255, 255, 255, 255, 255, 255, 83, 0, 73, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 177, 0, 0, 2, 1, 2, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 3, 0, 62, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 103, 0, 1, 164, 255, 255, 255, 255, 255, 254, 255, 254, 255, 251, 46, 0, 8, 210, 255, 255, 254, 252, 253, 255, 253, 255, 180, 2, 0, 0, 181, 255, 255, 254, 255, 255, 254, 254, 255, 255, 255, 233, 23, 0, 4, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 1, 1, 1, 97, 255, 255, 255, 255, 247, 244, 241, 241, 244, 255, 156, 0, 0, 0, 34, 192, 208, 191, 190, 186, 186, 166, 218, 254, 249, 43, 0, 10, 225, 255, 119, 8, 26, 29, 28, 26, 28, 10, 0, 10, 1, 12, 57, 55, 52, 49, 36, 40, 35, 199, 255, 254, 255, 84, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 3, 1, 0, 159, 255, 255, 255, 135, 1, 23, 22, 20, 22, 16, 3, 0, 7, 8, 0, 1, 0, 0, 1, 0, 0, 1, 74, 255, 255, 40, 0, 20, 248, 131, 1, 1, 0, 0, 0, 0, 1, 0, 3, 2, 4, 2, 0, 0, 0, 0, 0, 0, 0, 169, 254, 255, 255, 165, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 4, 1, 31, 240, 255, 255, 255, 117, 0, 1, 0, 0, 0, 0, 1, 3, 0, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 46, 0, 21, 246, 124, 0, 1, 0, 0, 0, 0, 2, 1, 1, 2, 1, 4, 0, 0, 0, 1, 2, 0, 1, 184, 255, 255, 254, 255, 55, 0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 1, 0, 148, 254, 255, 255, 255, 118, 0, 0, 0, 1, 2, 1, 0, 2, 1, 0, 3, 2, 1, 0, 0, 0, 2, 6, 1, 124, 255, 45, 0, 16, 250, 156, 0, 1, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 1, 0, 0, 0, 0, 1, 0, 194, 255, 254, 255, 255, 171, 0, 0, 2, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 6, 0, 40, 245, 255, 255, 255, 255, 121, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 6, 0, 137, 255, 42, 0, 22, 240, 255, 93, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 196, 255, 255, 255, 255, 255, 80, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 137, 255, 255, 255, 255, 254, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 255, 255, 49, 0, 13, 219, 255, 148, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 255, 255, 255, 176, 202, 247, 31, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 64, 253, 255, 254, 255, 255, 255, 122, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 255, 250, 46, 0, 13, 222, 255, 113, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 0, 1, 0, 190, 255, 254, 99, 0, 134, 255, 173, 0, 0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 4, 0, 24, 248, 192, 40, 29, 128, 255, 255, 113, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 255, 255, 46, 0, 22, 227, 255, 138, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 188, 254, 197, 0, 54, 255, 255, 254, 153, 0, 1, 2, 2, 0, 0, 0, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 2, 3, 0, 1, 2, 1, 4, 7, 0, 23, 217, 255, 200, 24, 0, 94, 254, 255, 126, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 142, 255, 245, 38, 0, 17, 233, 255, 103, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 191, 255, 212, 8, 24, 181, 255, 255, 255, 186, 20, 0, 0, 3, 4, 2, 1, 2, 2, 0, 0, 0, 0, 1, 0, 2, 2, 0, 3, 2, 1, 3, 1, 0, 48, 230, 255, 255, 254, 84, 11, 84, 255, 255, 132, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 98, 254, 254, 39, 0, 18, 248, 143, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 4, 209, 255, 255, 108, 5, 4, 123, 255, 255, 255, 235, 75, 0, 0, 3, 5, 0, 4, 4, 0, 0, 1, 1, 1, 2, 0, 4, 1, 2, 4, 2, 0, 0, 109, 255, 255, 255, 254, 111, 4, 11, 165, 255, 255, 116, 1, 1, 2, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3, 1, 0, 139, 255, 48, 0, 18, 245, 126, 0, 1, 0, 1, 2, 0, 0, 2, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 183, 255, 255, 89, 1, 1, 6, 94, 239, 255, 254, 255, 186, 52, 0, 0, 1, 0, 6, 7, 0, 0, 0, 0, 2, 7, 6, 2, 0, 0, 0, 80, 211, 255, 255, 255, 179, 33, 8, 0, 5, 162, 254, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 128, 255, 47, 0, 25, 255, 173, 0, 0, 0, 0, 0, 1, 0, 0, 4, 4, 2, 1, 0, 0, 0, 0, 0, 1, 0, 200, 255, 245, 48, 6, 0, 2, 11, 15, 140, 252, 255, 255, 255, 185, 74, 0, 0, 0, 4, 2, 0, 0, 2, 5, 2, 0, 1, 7, 90, 201, 255, 255, 255, 255, 113, 9, 12, 0, 0, 5, 134, 255, 255, 123, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 143, 255, 44, 0, 31, 241, 255, 140, 7, 29, 33, 29, 14, 28, 32, 10, 0, 0, 51, 65, 51, 54, 54, 55, 36, 55, 227, 255, 235, 69, 142, 200, 122, 55, 1, 1, 189, 255, 255, 255, 254, 255, 227, 194, 108, 3, 0, 0, 0, 1, 0, 12, 102, 165, 228, 255, 255, 255, 255, 255, 123, 0, 9, 92, 135, 130, 52, 149, 255, 255, 137, 0, 19, 23, 24, 11, 0, 21, 9, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 80, 255, 255, 64, 0, 10, 213, 255, 254, 251, 249, 251, 247, 231, 249, 255, 107, 0, 32, 243, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 243, 240, 254, 255, 255, 255, 255, 254, 255, 254, 255, 65, 0, 0, 1, 0, 0, 121, 255, 255, 255, 255, 255, 255, 255, 255, 220, 213, 241, 251, 255, 255, 253, 252, 255, 255, 250, 233, 237, 239, 241, 228, 216, 254, 185, 0, 0, 132, 189, 164, 167, 156, 163, 161, 155, 228, 254, 255, 61, 0, 17, 221, 255, 255, 255, 255, 255, 254, 255, 255, 228, 37, 0, 0, 171, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255, 66, 0, 1, 0, 0, 1, 124, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 167, 0, 1, 176, 255, 255, 255, 255, 255, 255, 255, 255, 255, 199, 1, 0, 21, 229, 255, 172, 79, 95, 102, 99, 95, 106, 46, 0, 2, 0, 36, 133, 138, 128, 127, 130, 132, 136, 140, 142, 141, 145, 145, 140, 142, 154, 159, 147, 157, 157, 143, 143, 146, 220, 255, 255, 153, 0, 0, 0, 0, 1, 0, 16, 200, 255, 255, 211, 148, 182, 180, 192, 203, 193, 188, 194, 196, 192, 187, 196, 189, 194, 196, 177, 187, 194, 201, 206, 220, 192, 29, 0, 0, 45, 175, 173, 158, 165, 164, 163, 137, 209, 255, 209, 12, 0, 26, 237, 255, 108, 1, 0, 0, 0, 0, 0, 0, 7, 5, 5, 3, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 152, 255, 254, 55, 1, 3, 0, 0, 0, 5, 0, 99, 255, 255, 122, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 3, 7, 5, 2, 1, 0, 0, 0, 0, 0, 0, 122, 255, 251, 43, 0, 30, 238, 255, 113, 0, 2, 0, 1, 0, 2, 2, 3, 3, 1, 2, 2, 2, 2, 2, 3, 5, 1, 1, 4, 3, 3, 3, 3, 4, 1, 1, 3, 1, 1, 1, 0, 1, 185, 255, 255, 87, 0, 1, 0, 1, 1, 0, 0, 141, 255, 255, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 3, 2, 1, 0, 1, 0, 0, 0, 0, 0, 0, 142, 255, 255, 57, 0, 19, 228, 255, 120, 1, 0, 1, 0, 1, 0, 2, 0, 0, 0, 1, 2, 1, 1, 1, 2, 2, 1, 4, 2, 0, 0, 2, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 163, 255, 255, 74, 1, 1, 0, 0, 2, 0, 0, 141, 254, 255, 114, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 2, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 147, 255, 255, 54, 0, 30, 238, 255, 121, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 142, 255, 255, 66, 0, 1, 1, 0, 0, 1, 0, 128, 255, 255, 105, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 152, 255, 247, 40, 0, 25, 232, 254, 119, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 174, 255, 255, 71, 0, 1, 0, 0, 2, 0, 0, 143, 255, 255, 106, 1, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 153, 255, 250, 45, 0, 28, 235, 254, 142, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 190, 255, 255, 76, 0, 1, 0, 0, 0, 0, 0, 148, 255, 255, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 152, 255, 248, 45, 0, 20, 244, 230, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 117, 255, 255, 75, 1, 0, 0, 0, 0, 0, 1, 145, 255, 255, 94, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 118, 255, 250, 38, 0, 40, 254, 117, 1, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 70, 146, 27, 0, 1, 0, 0, 0, 2, 0, 65, 197, 84, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 143, 255, 39, 0, 25, 253, 126, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 3, 2, 0, 0, 4, 4, 0, 0, 1, 0, 2, 4, 0, 0, 0, 4, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 121, 255, 43, 0, 27, 255, 137, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 1, 8, 25, 6, 1, 0, 0, 0, 0, 0, 4, 8, 11, 3, 2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 114, 255, 52, 0, 39, 254, 255, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 23, 201, 237, 27, 0, 0, 0, 1, 0, 1, 0, 39, 240, 141, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 26, 206, 255, 45, 0, 37, 244, 255, 131, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 98, 255, 236, 27, 0, 2, 1, 0, 0, 3, 0, 34, 255, 255, 52, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 138, 255, 245, 39, 0, 37, 245, 254, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 95, 255, 244, 32, 1, 0, 0, 0, 2, 1, 0, 55, 255, 255, 46, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 117, 255, 248, 39, 0, 33, 242, 255, 117, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 114, 255, 230, 21, 0, 1, 0, 0, 0, 4, 0, 51, 255, 255, 53, 0, 2, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 118, 255, 251, 43, 0, 29, 239, 255, 115, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 114, 255, 237, 35, 0, 1, 0, 0, 0, 5, 0, 45, 255, 254, 51, 0, 2, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 125, 254, 254, 48, 0, 34, 242, 255, 116, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 1, 3, 2, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 109, 255, 242, 36, 0, 1, 0, 0, 1, 2, 0, 51, 254, 255, 56, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 1, 0, 1, 124, 255, 246, 38, 0, 34, 245, 255, 111, 0, 1, 0, 0, 0, 0, 1, 0, 2, 2, 0, 0, 1, 4, 3, 7, 3, 2, 2, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 108, 255, 218, 7, 0, 0, 0, 1, 0, 3, 0, 44, 254, 255, 50, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 0, 0, 1, 3, 3, 1, 1, 3, 1, 1, 0, 1, 1, 4, 2, 2, 0, 0, 0, 0, 0, 0, 0, 128, 255, 243, 36, 0, 40, 246, 255, 157, 9, 23, 32, 30, 17, 29, 13, 0, 1, 0, 24, 61, 25, 0, 1, 0, 0, 1, 0, 0, 34, 32, 0, 1, 0, 1, 12, 6, 0, 2, 19, 22, 0, 128, 255, 240, 36, 0, 2, 1, 1, 0, 1, 1, 64, 255, 255, 64, 1, 10, 7, 10, 10, 16, 6, 0, 0, 0, 10, 35, 13, 1, 0, 0, 0, 0, 0, 0, 6, 8, 0, 0, 0, 0, 3, 8, 6, 7, 8, 2, 0, 150, 255, 248, 43, 0, 27, 229, 255, 255, 247, 242, 246, 243, 233, 254, 216, 46, 0, 43, 217, 255, 242, 61, 0, 23, 11, 18, 0, 94, 255, 255, 102, 2, 6, 121, 253, 228, 215, 220, 241, 250, 176, 197, 255, 255, 204, 6, 1, 0, 0, 2, 1, 8, 214, 255, 238, 243, 222, 230, 223, 225, 226, 255, 150, 0, 0, 49, 217, 255, 189, 22, 18, 37, 36, 41, 22, 75, 228, 250, 83, 0, 1, 44, 203, 245, 227, 226, 226, 224, 223, 249, 255, 251, 46, 0, 23, 231, 255, 254, 255, 255, 254, 255, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255, 252, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255, 254, 255, 255, 255, 255, 241, 33, 0, 1, 0, 1, 0, 14, 224, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 254, 255, 253, 254, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255, 244, 39, 0, 10, 122, 153, 147, 144, 138, 142, 134, 131, 131, 138, 145, 136, 124, 122, 125, 139, 148, 151, 158, 139, 129, 143, 40, 74, 144, 135, 128, 127, 106, 109, 116, 106, 102, 99, 110, 117, 114, 97, 129, 96, 0, 0, 0, 0, 0, 0, 0, 102, 138, 112, 123, 116, 117, 107, 114, 131, 132, 140, 135, 135, 130, 112, 137, 86, 86, 118, 105, 101, 100, 108, 94, 93, 101, 103, 119, 120, 105, 100, 103, 102, 101, 99, 97, 95, 89, 83, 63, 7, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
      // ARRAY OF PIXELS GOES HERE, COMMA + SPACE SEPERATED
      };
      
      void setup() {
      pinMode (0, OUTPUT);
      pinMode (1, OUTPUT);
      pinMode (2, OUTPUT);
      pinMode (3, OUTPUT);
      pinMode (4, OUTPUT);
      pinMode (5, OUTPUT);
      pinMode (6, OUTPUT);
      pinMode (7, OUTPUT); // PORT D
      
      pinMode (8, OUTPUT); // WR PIN (inverted)
      
      
      for (byte k = 0; k < strlen_P(img); k++) {
      
      digitalWrite(8, LOW); // inverted so this puts WR HIGH (to read)
      delay(10);
      
      myChar = pgm_read_byte_near(img + k);
      PORTD = myChar;
      
      digitalWrite(8, HIGH); // inverted so this puts WR LOW (to write)
      delay(10);
      
      }
      }
      void loop() {
      }
      
      

      Success finishing the board and recording Palladio distorted by the board :

       

       

       

      Here is the setup :

      I’m currently using two boards, but soon I’ll have the components to put everything on the board to the left. 

      The techniques I’m using is the one developed in the previous post :

      TO RECORD IN BURSTS: I can now save a short video : 695.45 kHz (This is the slowest I can go and still almost see an image) on the function gen AND’ed with the top 4 frequency divisions of the vertical sync. This makes for a burst of image recording every X number of frames.  I then amplify the output to make it visible on screen (and speed the clock up to 695.48 kHz). 
      TO STOP THE IMAGE JUMPING: If the reset is connected to the inverse of the freq subdivision of the vertical sync signal AND’ed with the address 20, it will play the image in a loop and always place it in the same part of the screen ! 
      EXPERIMENT : 1 bit recording 

      Recording a single bit of an image appears to produce almost the same image quality ! This means that in theory I could record 8 videos at the same time and output video to 8 screens simoultaneously !

       

      EXPERIMENT : Loading an image with Arduino
      Loading the tiny image once was a drop of water in the ocean so I recorded the image again and again until I ran out of space. This is taking a long time with a few 10ms delays in my code. 

       

      Here is the Arduino sending bits (captured after DAC) :

       

      but so far nothing that comes out looking like an image on the other side…

      I also can’t get my VGA to HDMI converter working…

      Here’s an attempt at a grid of raster variations :

      Here’s the final version of the board :

       

      Memory Experiments

       

      https://github.com/merlinmarrs/Video-Memory

      This project started with an ambitious board combining ADC, DAC and SRAM. 

       

      There were too many issues so I broke the board down into two parts: a memory board and a ADC/DAC board. This allowed me to isolate things and proceed in a step by step way.

      I discovered that the memory needed a WR signal inbetween clock address refreshing, and for the second board that my op amp choice was inappropriate and needed to work around it (by using the DAC only as an R2R ladder and skipping the op-amp for the ADC input). 

       

      During assembly I found that several 0 ohm jumpers were causing shorts. I also tore out the 8 pin header but applying too much force accidentally. Otherwise the switch system was very effective to test my understanding of the memory chip operation. It can essentially record a series of button manipulations for about 1.5 minutes.  

      Here is my first successful “recording” of a sine wave through the ADC and into SRAM and play back from SRAM through the DAC :

      BOARD ERRATA:

      -need last bit of address counter (cuts memory in half !)

      -more jumpers should be broken out for testing (like alternative op amp for input, clk for various chips, etc.)

      -leds burn out when activated and output plugged into 5V at the same time…

      -GND and 5V switched on the two boards 🙁

      -Wrong op amp spec’d. The ADC1175 suggests the LMH6702MF and a choke between power supplies. 

      -caps on all ICs

      -the LEDs I set up on the microchip are plugged into ADC…

      -Add enable header on microchip board

      -power LED on the ADC board

      -add a MSB and LSB next to LEDs on memory board **

      I calculated how much I could store in the 4K of the SRAM I am currently using, and it would be a single line of a 600×800 screen at 40Mhz pixel frequency…

      So what can I do with this ? I could record 4,000 pixels of a static image (i.e. lower the resolution of the image to 100×400 for instance) and then play it back. This would require me to control the sampling of the ADC with the CLK pin of the ADC1175 for every X pixels, somehow synchronized with the VGA in signal (use timing signals of an incoming VGA signal set), or to generate a custom VGA output signal with different timing using the VGAX library. 

      Some important references : 

      nootropicdesign.com/video-experimenter/build

      gieskes.nl/visual-equipment/?file=gvs1

      I am looking into what I could draw on screen with only 4K memory at a 20MHz clock.

      EEPROM and SD cards are also interesting before reaching the holy grail of magnetic recording media of course…

      I have the AT28C256F-15TU EEPROM chip which has 256K x 8 bits (enough to at least store an entire 600×800 static screen) and the ADV7125STZ50 8 bit triple HS video DAC. 

      https://www.mouser.fr/datasheet/2/268/doc0006-1108095.pdf

      https://www.mouser.fr/datasheet/2/609/ADV7125-1503638.pdf

      I’d like to have a standalone arduino VGAX based board (https://github.com/smaffer/vgax) which can output 120×60 pixels and reads from internal SRAM and can record and playback. With 256K I could record a static image on screen at a higher resolution or a low resolution short video.

      I have already made an SD card image saving board: 

      Just realized what I’m trying to do is called a frame grabber and it’s a massive PCB :

      https://en.wikipedia.org/wiki/Frame_grabber#:~:text=A%20frame%20grabber%20is%20an,or%20a%20digital%20video%20stream.&text=Historically%2C%20frame%20grabber%20expansion%20cards,to%20interface%20cameras%20to%20PCs.

       

      *********************************************************************************

      I have designed a similar memory board but using a 256K EEPROM chip in place of the  SRAM and with VGA connectors to begin testing images. (There do appear to be larger SRAMs, going up to 16MB. There are obviously large flash memories in SD format going into the GBs which may also be interesting to play with).

      -Added out VGA to work with VGAX library (not sure if need a second microchip to handle just the memory stuff?)

      -Added a 16MHz resonator

      -With two 8 bit counters to have the full 13 bits to control this time.

      -EEPROM will keep a recording after power down.

      -can control buffers with microchip

      Just learned that EEPROM is probably the slowest…

      Just a thought but I could save control signals for the 0c74 instead of saving actual pixel information…

      *************

      First test (WORKING):

      int switchState = 0;

      pinMode(6, OUTPUT); // CLK LED (*)
      pinMode(7, OUTPUT); // CLK

      pinMode(10, OUTPUT); // WR/RD SIGNAL TO SRAM
      pinMode(A3, INPUT); // WR/RD SWITCH (WR HIGH, READ LOW)

      pinMode(8, OUTPUT); // WR LED
      }

      // the loop function runs over and over again forever
      void loop() {

      switchState = digitalRead(A3);

      // check if the pushbutton is pressed.
      // if it is, the buttonState is HIGH:
      if (switchState == LOW) {
      // WR selected on switch so turn WR LED on and send a LOW to SRAM

      digitalWrite(8, HIGH);
      //
      digitalWrite(10, HIGH);
      digitalWrite(6, HIGH); // 
      digitalWrite(7, HIGH); // 
      delay(10);
      digitalWrite(10, LOW);
      digitalWrite(6, HIGH); // 
      digitalWrite(7, HIGH); // 
      delay(10); // 
      digitalWrite(10, LOW);
      digitalWrite(6, LOW); 
      digitalWrite(7, LOW); 
      delay(10); // 
      digitalWrite(10, HIGH);
      digitalWrite(6, LOW); // 
      digitalWrite(7, LOW); // 
      delay(10); // 

      }
      else {
      // READ selected on switch so turn WR LED OFF on and send a HIGH to SRAM
      digitalWrite(10, HIGH); // STAYS HIGH THE WHOLE TIME
      digitalWrite(8, LOW);
      //
      digitalWrite(6, HIGH); // 
      digitalWrite(7, HIGH); //
      delay(20); // 
      digitalWrite(6, LOW); // 
      digitalWrite(7, LOW); // 
      delay(20); //

      }

      }

      This is what it produces:

      Second test (WORKING): 

      int switchState = 0;

      // the setup function runs once when you press reset or power the board
      void setup() {
      // initialize digital pin 13 as an output.
      pinMode(6, OUTPUT); // CLK LED (*)
      pinMode(7, OUTPUT); // CLK

      pinMode(10, OUTPUT); // WR/RD SIGNAL TO SRAM
      pinMode(A3, INPUT); // WR/RD SWITCH (WR HIGH, READ LOW)

      pinMode(8, OUTPUT); // WR LED
      }

      // the loop function runs over and over again forever
      void loop() {

      switchState = digitalRead(A3);

      // check if the pushbutton is pressed.
      // if it is, the buttonState is HIGH:
      if (switchState == LOW) {
      // WR selected on switch so turn WR LED on and send a LOW to SRAM

      digitalWrite(8, HIGH);
      //
      digitalWrite(10, HIGH);
      digitalWrite(6, HIGH); // turn the LED on (HIGH is the voltage level)
      digitalWrite(7, HIGH); // turn the LED on (HIGH is the voltage level)
      delayMicroseconds(1);
      digitalWrite(10, LOW);
      digitalWrite(6, HIGH); // turn the LED on (HIGH is the voltage level)
      digitalWrite(7, HIGH); // turn the LED on (HIGH is the voltage level)
      delayMicroseconds(1); // wait for a second
      digitalWrite(10, LOW);
      digitalWrite(6, LOW); // turn the LED on (HIGH is the voltage level)
      digitalWrite(7, LOW); // turn the LED on (HIGH is the voltage level)
      delayMicroseconds(1); // wait for a second
      digitalWrite(10, HIGH);
      digitalWrite(6, LOW); // turn the LED on (HIGH is the voltage level)
      digitalWrite(7, LOW); // turn the LED on (HIGH is the voltage level)
      delayMicroseconds(1); // wait for a second
      // wait for a second
      }
      else {
      // READ selected on switch so turn WR LED OFF on and send a HIGH to SRAM
      digitalWrite(10, HIGH); // STAYS HIGH THE WHOLE TIME
      digitalWrite(8, LOW);
      //
      digitalWrite(6, HIGH); // turn the LED on (HIGH is the voltage level)
      digitalWrite(7, HIGH); // turn the LED on (HIGH is the voltage level)
      delayMicroseconds(1); // wait for a second
      digitalWrite(6, LOW); // turn the LED on (HIGH is the voltage level)
      digitalWrite(7, LOW); // turn the LED on (HIGH is the voltage level)
      delayMicroseconds(1); // wait for a second

      }

      }

      And here are some shots of what three different speeds (10ms, 10microseconds, 1 microseconds) as delay in the Arduino code :

       

      ***********************************************************************

      Third test (NOT WORKING):

      I recorded a sine wave at 100KHz (with WR activated on the microchip board) with the ADC being clocked at 10KHz. I made sure I had the ADC selected with the right buffers and then sent this 8 bit sequence to the memory where I recorded it with a new Arduino code:

      void setup()
      {
      DDRD = B11111111; // set PORTD (digital 7~0) to outputs
      DDRB = B11111111; // set PORTB (digital 7~0) to outputs
      }

      void loop()
      {
      if((PINC & 0b00001000)==0)
      {
      PORTD = B11111111; // set PORTD pins (digital 7~0) high
      PORTB = B00000000; // set PORTD pins (digital 7~0) low
      PORTD = B00000000; // set PORTD pins (digital 7~0) low
      PORTB = B11111111; // set PORTD pins (digital 7~0) high

      }
      else
      {
      PORTB = B00000100; // WR PULLED HIGH SO TURNED OFF
      PORTD = B11111111; // set PORTD pins (digital 7~0) high
      PORTD = B00000000; // set PORTD pins (digital 7~0) low
      }
      }

      /*
      CLOCK:
      _____ _____
      | ` | | |
      ___| |___| |____

      WR:
      _________ ____________
      ` | |
      |___|

      */

      I then switched to the DAC with the buffers and switched into READ mode on the microchip board.  Now the 8 bit sequence was being translated back into a sine wave. I took this sine wave and amplified it with an audio amp and sent it to the three color channels combined with an arduino running the VGAX pattern code without the colors plugged in and only H and V SYNC.

      I got this on the screen :

      Here is the tentacular and unoptimized setup :

      To make this actually easy to use, I need to:

      -have the microchip control the buffers and the ADC clocking based on the switch state.

      -have the memory and adc on a single board.

      -have a VGAX out setup integrated into the memory board.

      -have an op amp on the ADC board to amplify the output signal !!

      -have a dial change the speed of the playback / sampling of recording.

      *******************************************

      I added an external crystal and set the AVR dude Fuses to : Ext. Crystal Osc.8.0 – ___MHz 16K CK/14 CK + 65 ms. 

      I added F_CPU 16000000UL ABOVE the #include. 

      Forgot that if you don’t add 0b before a binary number nothing happens with the pins !

      Here is the code that still isn’t working :

      /*
      * eeprom board v.2.c
      *
      * Created: 06/02/2022 09:19:50
      * Author : Jonah
      */

      #include <avr/io.h>

      int main(void)
      {

      DDRC = 0b00000000; // PC3 is the switch for WR (0) or RD(1)

      DDRD = 0b11111111; //PD5 is CLK and PD4 is !OE

      DDRB = 0b11111111; //PB0 is the LED and PB2 is !WE

      while (1)
      {

      /*
      BYTE WRITE: A low pulse on the WE or CE input with CE or WE low (respectively) and OE high initiates a write
      cycle. The address is latched on the falling edge of CE or WE, whichever occurs last. The data is latched by the first
      rising edge of CE or WE. Once a byte write is started, it will automatically time itself to completion. Once a
      programming operation is initiated and for the duration of tWC, a read operation will effectively be a polling operation.
      */

      if((PINC & 0b00001000)==0) // WRITE MODE: (CE -> TIED LO); !WE -> TOGGLE ; !OE -> HI ; CLK -> TOGGLE
      {
      PORTD = 0b00010000; // !OE -> HI ; CLK -> LO
      PORTB = 0b00000000; // !WE -> LO
      PORTB = 0b00000001; // !WE -> LO (to make the pulse width at least 100ns)
      PORTB = 0b00000101; // !WE -> HI
      PORTD = 0b00110000; // !OE -> HI ; CLK -> HI (next address must come a max of 50 ns following !WE going HI?)

      }

      /*
      READ: The AT28C256 is accessed like a Static RAM. When CE and OE are low and WE is high, the data stored at
      the memory location determined by the address pins is asserted on the outputs.
      The outputs are put in the highimpedance state when either CE or OE is high. This dual-line control offers designers flexibility in preventing bus
      contention in their system.

      */

      else // READ MODE : (CE -> TIED LO); !WE -> HI ; !OE -> (TOGGLE ? OR JUST LO?) ; CLK -> TOGGLE
      {
      PORTB = 0b00000101; // !WE -> HI
      PORTD = 0b00100000; // !OE -> LO ; CLK -> HI
      PORTD = 0b00000000; // !OE -> LO ; CLK -> LO
      }
      }
      }

      **********************************************************************************

      One question I have is: does the EEPROM require OE to go on and off when reading unlike the SRAM I worked with in the previous board ?

      Another question is, how long does the EEPROM need to write a byte ? It talks about “access times of 150ns”…?

      Is it OK I have CE tied low the whole time ?

      As a next step I will try doing all of this but very slowly to see if that works. 

      *EDIT : tried slowing everything down and I’m still not able to load anything into the memory :(. I just get 5V and little pops of ground after writing ground into every cell of the memory. This is after changing !OE toggle and always ON also. 

      I did get the VGAX code running though so at least that works. 

      ERRATA:

      -the labeling of WR and RD are confusing, when the switch is to the RD side it is in WR mode etc. 

      -the VGA parts are COMPLETELY wrong. 

      -I need to order 16MHz of this format (I took one from a dead Arduino board). 

      -the text is too small and came off during cleaning.

       

      TROUBLESHOOTING AT28C256 EEPROM:

      -Need to wait a second before doing and writing or reading,

      -Need to either wait the maximum time for the EEPROM to write (Write Cycle Time Max AT28C256 = 10ms) or poll 1/0 7 to wait until it matches what you sent it before starting another write cycle.

      -The device may be locked (even though the devices should ship unlocked) :(. The unlock sequence is :

      LOAD DATA AA
      TO
      ADDRESS 5555

      LOAD DATA 55
      TO
      ADDRESS 2AAA

      LOAD DATA 80
      TO
      ADDRESS 5555

      LOAD DATA AA
      TO
      ADDRESS 5555

       

      LOAD DATA 55
      TO
      ADDRESS 2AAA

      LOAD DATA 20
      TO
      ADDRESS 5555

      LOAD DATA XX
      TO
      ANY ADDRESS(4)

      LOAD LAST BYTE
      TO
      LAST ADDRESS

       

      ************************

      Here are some thoughts I have on the SRAM device :

      Do I want addressed to loop or not ? (Add inverter if want to loop)

        >> Make it optional with a jumper, this expands the possibilities of experimenting.

      Max sample rate I can get from SRAM ? 
      >>Looks to be around 20MHz if the read time is 50ns ?
      What happens if I slow a recorded signal down with a knob, what visual effects produced ?
      >> I need a bunch of recorded stuff and a super fast clock or else I just output bands everyonce and a while.
      Bigger SRAM same brand? need more counters?

        >> Check out this super fast 1Mx8bit SRAM

      61-64WV10248EDBLL-276598.pdf (mouser.fr)

      Two memories ? Feedback from one memory possible ?
      Jumpers to either have vgax doing syncs or input vga.
      Record at slow speed play back at high speed ? Keeps theme of time and computation…
      How have vgax send clock and wr signal for memory circuit while doing vgax timing ? Or have separate clocks (high speed resonator) and sync somehow ? ( Or generate my own sync sign also in logic ?)
      How actually use and function with two vgas ?
      It would be cool to be able to record an image, or parts of a series of images, on an input vga signal and then play them back at different speeds and doubled with the original. This seems really challenging to do accurately but could be cool to stretch an image or sample every line from an animation.

      Also would be cool to be able to output blocky animations based on memory. Could vgax output memory values? Then could compose.

      Could the vgax do a kind of low fi screen capture ? This is a ripoff of gieske though…
      Could this thing be a composition machine, where you slowly switch 8 pin dip switches and take a “photo” of each finished byte ? Then play back at higher speeds?
      I started this board wanting to learn about memory. What have I learned ? Could have button to reset address counters, knob for clock speed, but what other Params?
      Could take memory and output it as pattern by vgax ?
      Do all first with Arduino analog read  ?? Why is this better than Arduino ? What advantage, what has it allowed me to learn ? Faster ? Physicalized memory space ?
      **********
      Retried this code modified slightly from this tutorial : https://scanlines.xyz/t/tutorials-for-generating-video-sync-signals-with-arduino/104

      #define LINE_CYCLES 508
      #define HSYNC_CYLCLES 60
      #define VSYNC_LINES 2
      #define FRAME_LINES 525
      #define PIXEL_FREQ 1

      volatile int linecount;

      void setup(){
      pinMode(7, OUTPUT); // VSync
      pinMode(9, OUTPUT); // HSync
      pinMode(6, OUTPUT); // Pixel frequency

      //inverted fast pwm mode on timer 1
      TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(WGM11);
      TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);

      ICR1 = LINE_CYCLES; // Overflow at Cycles per line
      OCR1A = HSYNC_CYLCLES; // Compare high after HSync cycles

      //timer 0 in CTC mode
      TCCR0A = _BV(COM0A0) | _BV(WGM01) ; // Toggle pin on each cycle, no CPU clock prescaling/
      TCCR0B = _BV(CS00); // no clock prescaling
      OCR0A = PIXEL_FREQ; // go super fast

      TIMSK1 = _BV(TOIE1); // Enable timer overflow interrupt
      }

      ISR(TIMER1_OVF_vect)
      {

      if (linecount == 0) PORTD = PORTD ^ 0x80; //Toggle the most significant bit of port D.;
      else if (linecount == 2) PORTD = PORTD ^ 0x80; //Toggle the most significant bit of port D.;
      else if (linecount == 3) PORTD = PORTD ^ 0x80; //Toggle the most significant bit of port D.;
      else if (linecount == FRAME_LINES) linecount = 0;
      linecount++;
      }

      void loop(){}

      *******************

      Works well. Also tried generating my own V and H sync with logic and a 4040 counter from this tutorial : https://hackaday.io/project/9782-nes-zapper-video-synth-theremin/log/32271-vga-sync-generation

      It didn’t work for me. The reset of the 4040 didn’t want to be connected to anything but GND, otherwise the whole thing was inoperational. 

      I also messed around again with floppy disk writing. I got the floppy disk motor turning, plugged the index into step, activated the drive select, and connected direction to either 5V or GND. I soldered a connector for the 5 wires froming from the recording magnets. I tried blasting them with a sine wave added to a 10KHz square wave but saw no sign of the signals when playing back the floppy. 

      I have a new plan: Triple SRAM device for copying and pasting a loop of very blocky “video” :

       

      *****************************************************************************************

      Here’s what I learned :

      version 1 :

      I need to make a smd breakout board for chips or order DIP versions so that I can do tests first. This would save a lot of time designing and redesigning boards. The idea for a minimal integrated board was good though. Break more pins out.

      version 2 :

      BOARD A : I need to make a more stable way to solder pin headers to the card so they don’t rip off easily. I should use buffers to protect the LEDs. There are also way too many jumpers between the the counter and SRAM. 

      BOARD B : The op amps don’t work. The DAC doesn’t work as I wired it. I forgot to connect the CLK of the DAC.  

      It’s a mess to connect the two boards, make the right connections. The two boards need to be integrated. 

      version 3 :

      The EEPROM doesn’t work, is it locked ? I also used the wrong VGA pins. 

      version 4 :

      It’s a beautiful board but the DAC was VERY challenging to solder by hand. I think the level of complexity and ambition of the board was a little bit too high for this production method. I think I should head back to a board that is easy to assemble, easy to test and understand. 

      version 5: 

      The idea : using buffers I can have LEDs display what is in the memory while also outputing analog output. There are fewer jumpers than in earlier versions. I am planning to use the inverter to control the SRAM WR which appears to be possible based on the datasheet. Simplified DAC with R2 ladder, I can control A12 with a switch and have an A11 LED now. I got rid of the VGA functionality – this makes things simpler. I chose switches over shunts to make connections.

      I want to make 3 of these boards, ABC, so that they can each record in two 4K memories, and then do cool logic transformations and save the results too. Connecting the ADC to the SRAM inputs requires 8 jumpers, and I’ve done away with 8 pin dip switches. To manually set data you connect the jumpers to the spare + and – headers. 

      I would like the decisions to be guided by how I could practically use this device to “record” 8 bits of data / an analog signal for a given period of time (based on the clock speed) and then play it back (while modifying the clock speed manually, and overwriting portions of the memory, possibly from another pair of memory boards) to display on a screen (with another board handling the VGA signals and optionally sharing its clock with this board to keep things in sync). I want to move to something that produces output ASAP, and away from endlessly redesigning these boards looking for something perfect. (If this works I want to make 3, then a specialized VGA board too).

      I’ve added reverse polarity protection, a STEP button, which is hardware debounced, to manually advance one address at a time. I kept the op-amp modular so that it could be used to amplify analog in or out. I switched out the edge accessible thumb pots for normal pots, so this thing is no longer really stackable.

      Not sure exactly how they stack (but many things accessible on the edges) though and not sure if I should have a battery included or not so that it remembers what it recorded…

      Version 5 UPDATE :

      Thoughts on possible  version 6 additions :

      Backup battery to record option ?

      8pin dip switch with header somewhere on board?
      Question I have to resolve with current version :
      What can I record (in analog and in digital) and for how long ?
      What does it look like on the screen with and without a generated pixel clock to do the sync?
      Going at pixel frequency speed I can draw different repeating textures on the screen when I record very slowly and then speed it up :

      Patterns are repeating, it’s like a texture. Sending a non-repeating signal, like the arbitrary function signal which leaves a non-repeating pattern on screen, seems like a cool thing to try. Another option is to have a single block of memory but to jump around in how you address it somehow ?
      How fast and how slow can it go ?
      With a 10K resistor and a 0.1uF for the CD4046 I have a max sampling speed of 1Khz that is barely enough to represent a 100 Hz sine wave.
      Apparently this max is called the Nyquist frequency :

      Nyquist Frequency=Fmax = SampleRate/2

      The SRAM module IS61C64AL can run up to 20MHz according to the datasheet (https://www.issi.com/WW/pdf/61C64AL.pdf)

      When I feed it the 3MHz pixel frequency from the modified VGAX it can record a 1.5MHz sine wave and play it back ! The problem when it is going slow is that it just outputs bands every now and then. It could act as a memory of a control signals which would change parameters in a circuit which generates more interesting output. (It could even control an analog computer like this https://the-analog-thing.org/ ).
      The other option would be to have a super fast clock that is connected to the V and H sync, one that I can divide and use to control recording of a large SRAM memory.
      Would second mem board be cool ?
      Not unless I get a bigger SRAM I think and daisy chain a series of 8 bit counters :
      https://www.mouser.fr/datasheet/2/198/62-65WV10248EALL-BLL-462620.pdf
      VERSION 5 UPDATE :

      Here are the issues :
      -I added a reset for the counters to go back to address 0. It takes a while to kick in though – I think because it resets the counter but not the 8 bit storage register ?
      -I added an LED to show when ADD21 is activated.
      -the 74F541 does not like 5V. I replaced it with an 74HCT254 and pulled the DIR pin HIGH.
      -the ADC1175 operates at 4.5-5.5V ! (I will test it’s max speed – supposedly 20MHz by powering it with 5V)
      -One pin connection missing on 8 pin dip switch
      -The phase shifter sucks and the amp doesn’t currently work.
      -CS should be held down and not toggled with WE.
      -RCO for cascading counters was not working at higher frequencies – I switched to sending the last Qout of each counter to the CLK in. 
      -I don’t have a way of taking 5V analog signals and stepping them down to 3.3V.
      -The memory should default to floating (instead of ground?) so that I can re-record over previous stuff. (Currently when I re-record, if a pin is not set it defaults to being black and just erasing everything).
      -need a 3.3V to 5V booster if you want to interface with another 5V memory. It would be nice to have an in-line 8 plug so I don’t need to plug in each wire one by one…
      -I can’t currently take VGA in at 400×800 from a computer (amplified) and saved it into the memory (it’s pixel clock is at 40MHz, I set the function generator to 4MHz). But I can record an image imperfectly from the VGAX color out at around 1.3038210 MHz.
      -I need to amplify at the input and the output (and ideally be able to offset them both and up and down – especially to hit the middly of the CMOS threshold between low and hi if I want to record in image in b&w with a single bit). The next version of the board would have two amps.
      -When I play back a recording, each time the memory restarts at zero, the frame of the video moves. (To solve this I need the freq divider, AND chip and inverter).
      -Pin 11 of the ADC should be connected to 3.3V while pin 13 should be connected to 5V.
      Possible improvements:
      -a 5V power in with 3.3V LDO so I can power things with both ?
      -if I want to upload something to memory, and then change to outputing, I have to disconnect all the wires that were connected to it previously. I should have a 74HCT254 Bus transciever that can change directions to disconnect a set of 8 wires from the memory. ALTERNATE OPTION : Just keep everything plugged in and turn off ADC?
      -Maybe an LED that tells me I’m recording (easy not to notice that it’s not in recording mode and then connect it to outputs that are pulling it up and down). 
      -Would be cool to be able to select which chunk of memory I’m replaying over with two knobs that control the start point and end point. (This could be two comparators connected to two pots ?)
      Developements:
      I can load values into the memory from Arduino’s PRGMEM like so:
      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      /* TO LOAD DATA INTO THE MEMORY */

      #include <avr/pgmspace.h>

      byte myByte;

      #define IMG_PIRATE_BWIDTH 30
      #define IMG_PIRATE_HEIGHT 60
      //data size=900 bytes
      const byte img_pirate_data[IMG_PIRATE_HEIGHT*IMG_PIRATE_BWIDTH] PROGMEM={
      0, 7,255,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 63,252, 6, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 0, 0, 0, 0, 0,
      2,255,112, 96,129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      15,222, 2, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,
      255,240, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
      252, 65,144, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0,
      248, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,144, 0, 0, 0, 0, 0, 0,
      65,132, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0,
      0, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
      36,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0,
      65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0,
      8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0,
      16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 0, 0, 0, 0, 0, 0, 0, 0,
      32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,130,168,160, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34,138, 42, 32, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      16, 0, 0, 0, 0, 0, 0, 0, 0, 34, 34, 34,136, 32,130, 0, 0, 32, 0, 0, 0, 1, 69, 64, 80, 0, 20, 5, 4, 0,
      32, 0, 0, 0, 0, 0, 0, 8,170,160, 0, 0,170,170, 40, 42,170,136, 0, 0, 0, 0, 64, 17, 4, 68, 64, 16, 68, 0,
      0, 0, 0, 0, 0, 0, 0,162, 10, 2,170,170,170,170,168, 32, 0, 34, 0, 0, 0, 0, 65, 65, 4, 16, 84, 16, 68, 0,
      64, 0, 0, 0, 0, 0, 10,130,171,239,255,238,170,170,160,162,170,162, 0, 0, 0, 0, 68, 1, 4, 16, 65, 16, 64, 0,
      36, 0, 0, 0, 0, 0, 8, 42,187,250,170,170,187,238,250, 0, 0, 34, 0, 0, 0, 0, 69, 80, 80, 68, 20, 5, 4, 0,
      0, 0, 0, 0, 0, 0, 34,170,255,234,170,170,171,187,178, 60, 0,170,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      152, 0, 0, 0, 0, 0, 0,171,254,170, 0, 2,186,255,248, 61, 3, 2, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      1,196, 0, 0, 0, 0, 10,187,254,168,112, 4,171,191,248, 54, 0, 40,136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 8,198, 96, 0, 0, 42,191,250,163,240, 14,174,255,254,136,170,138, 34,128, 1,128, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0,139,191,250,168, 53, 26,171,255,252,138, 34,186,162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 42,251,250,170,170,170,174,191,254, 34,187,174,232,128, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 2,170,174,255,186,170,170,187,255,255, 34,234,251,170,128, 0,128, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 1, 0, 0,138,187,187,171,170,238,187,191,255,138,175,255,238, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 10,239,255,186,186,170,238,239,255,224,235,255,250, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 46,175,255,255,238,186,190,255,255,248,171,255,250,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0,170,191,255,255,250,171,187,239,255,254, 42,255,238, 32, 0,144, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 42,238,255,255,251,170,174,187,255,254,174,190,234,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 1,128, 0, 0,174,187,255,255,254,235,171,255,255,254, 10,171,170,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 32, 0, 0, 0,138,174,255,255,255,186,163,255,255,255,162,186,186,128, 0, 4, 36, 0, 0, 0, 0, 0, 0, 0,
      0, 4, 0, 0, 0, 0, 43,187,239,255,254,170,234,170,174,234, 34, 42,168, 0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 10,174,186,255,251,171,168,128, 10,128, 2, 34,226, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0,
      0, 0, 64, 0, 0, 0, 2,171,239,187,254,234,170, 40, 0, 0, 0, 40, 32, 0, 0, 2,170,168, 0, 0, 0, 0, 0, 0,
      0, 0, 40, 0, 8, 0, 0, 42,190,239,190,186,128, 0, 0, 0, 0, 0,160, 0, 0, 64,170,170,160, 0, 0, 0, 0, 0,
      0, 2,160, 0, 60, 0, 0, 42,171,190,250,168, 0, 0, 10,170,168, 0, 0, 0, 0,128, 16, 10,168, 0, 0, 0, 0, 0,
      0, 42,128, 2,240, 0, 0,130,234,186,170,160, 0,170,170,170,174,128, 0, 0, 0, 6, 0,170,170,128, 0, 0, 0, 0,
      0,170,128, 47, 0, 0, 0, 10, 42,170,170,128, 42,170,175,255,250, 32, 0, 0, 1, 0, 42,170,170,168, 0, 0, 0, 0,
      10,170, 64, 40, 48, 0, 0, 0, 40,162,170, 0,171,255,255,255,234,136, 0, 0, 2, 0, 2,170,170,170, 0, 0, 0, 0,
      170,170, 0,160,176, 0, 0, 0, 0,130,168, 2,191,186,175,250,170, 32, 0, 0, 1, 56, 0,170,170,170, 0, 0, 0, 0,
      170,170,130,130, 64, 0, 0, 0, 2, 8,168, 10,239,255,234,170,170,136, 0, 0, 16, 60,128,170,170,170, 0, 0, 0, 0,
      170,170,128,138, 0, 60, 0, 0, 0, 8, 32, 2,255,255,255,234,186,128, 0, 0, 0, 7,232, 42,170,170,128, 0, 0, 0,
      170,170,160,168, 0,252, 0, 0, 0, 0, 0, 10,175,255,255,251,170,128, 0, 0, 0, 0, 26, 42,170,170,128, 0, 0, 0,
      170,170,168, 8, 0,240, 32, 0, 0, 0, 0, 8,190,187,235,238,168, 32, 0, 0, 0, 0, 4,170,170,170,160, 0, 0, 0,
      170,170,160,170, 0,240,192, 0, 0, 0, 0, 0,170,254,238,170,186, 0, 0, 0, 0, 0, 72, 42,170,170,168, 0, 0, 0,
      170,168, 0,170,128, 2, 64, 0, 0, 0, 0, 0, 2,171,170, 58,160, 0, 0, 0, 0, 0, 2, 10,170,170,170,128, 0, 0,
      170,170, 42,170,168, 3, 0, 0, 0, 0, 0, 0, 2, 10, 42, 8, 0, 0, 0, 0, 0, 0, 1, 42,170,170,170,168,128, 0,
      170,170,170,170,169, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 18, 42,170,170,170,170,168, 0,
      170,170,170,170,168, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54,128, 0, 42,170,170,170,170,170, 0,
      170,170,170,168, 36, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,188, 96, 15,170,170,170,170,170,170, 0,
      170,170,170,170, 0,130, 14, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 95, 0, 63,234,170,170,170,170,170,128,
      170,170,170,170,170,170,143,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0,249,240, 63,234,170,170,170,170,170,128,
      170,170,170,170,170,170,144, 63,240, 0, 0, 0, 0, 65, 0, 0, 0, 15,192, 0, 63,144, 63,170,170,170,170,170,170,160,
      170,170,170,170,170,170,175,239,240, 0, 1, 0, 0, 2, 24, 0, 0, 15,252, 0, 7,228, 15,218,170,170,170,170,170,168,
      170,170,170,170,170,170,168,255,240, 48, 64, 0, 13,129, 1, 0, 0, 3,255, 0, 0,114, 15,250,170,170,170,170,170,170,
      170,170,170,170,170,170,170, 62,192,188, 0, 0, 63,126,192, 36, 0, 2,127,208, 0,185,191,250,170,170,170,170,170,170,
      };

      void setup() {

      Serial.begin(9600);

      pinMode(7, OUTPUT); // I/O 8
      pinMode(6, OUTPUT);
      pinMode(5, OUTPUT);
      pinMode(4, OUTPUT);
      pinMode(3, OUTPUT);
      pinMode(2, OUTPUT);
      pinMode(1, OUTPUT);
      pinMode(0, OUTPUT); // I/O 0

      pinMode(8, OUTPUT); // CLK

      for (byte k = 0; k < 200; k++) {
      myByte = pgm_read_byte_near(img_pirate_data + k);
      Serial.print(myByte);
      digitalWrite(8, LOW); //CLK LOW
      delay(1);
      PORTD = myByte;
      digitalWrite(8, HIGH); //CLK HIGH
      delay(1);
      }
      for (byte k = 0; k < 200; k++) {
      myByte = pgm_read_byte_near(img_pirate_data + 200+ k);
      Serial.print(myByte);
      digitalWrite(8, LOW); //CLK LOW
      delay(1);
      PORTD = myByte;
      digitalWrite(8, HIGH); //CLK HIGH
      delay(1);
      }
      for (byte k = 0; k < 200; k++) {
      myByte = pgm_read_byte_near(img_pirate_data + 200+ k);
      Serial.print(myByte);
      digitalWrite(8, LOW); //CLK LOW
      delay(1);
      PORTD = myByte;
      digitalWrite(8, HIGH); //CLK HIGH
      delay(1);
      }
      for (byte k = 0; k < 200; k++) {
      myByte = pgm_read_byte_near(img_pirate_data + 200+ k);
      Serial.print(myByte);
      digitalWrite(8, LOW); //CLK LOW
      delay(1);
      PORTD = myByte;
      digitalWrite(8, HIGH); //CLK HIGH
      delay(1);
      }

      Serial.print(“FINISHED”);
      }

      void loop() {

      }

       

      ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

      I have a different Arduino to trigger the memory on each pixel and generate the sync signals :
      /* TO TRIGGER MEMORY CLOCK EACH PIXEL AND GEN VGA SYNCS */

      #define LINE_CYCLES 508
      #define HSYNC_CYLCLES 60
      #define VSYNC_LINES 2
      #define FRAME_LINES 525
      #define PIXEL_FREQ 1

      volatile int linecount;

      void setup(){
      pinMode(7, OUTPUT); // VSync
      pinMode(9, OUTPUT); // HSync
      pinMode(6, OUTPUT); // Pixel frequency

      //inverted fast pwm mode on timer 1
      TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(WGM11);
      TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);

      ICR1 = LINE_CYCLES; // Overflow at Cycles per line
      OCR1A = HSYNC_CYLCLES; // Compare high after HSync cycles

      //timer 0 in CTC mode
      TCCR0A = _BV(COM0A0) | _BV(WGM01) ; // Toggle pin on each cycle, no CPU clock prescaling/
      TCCR0B = _BV(CS00); // no clock prescaling
      OCR0A=PIXEL_FREQ;

      TIMSK1 = _BV(TOIE1); // Enable timer overflow interrupt
      }

      ISR(TIMER1_OVF_vect)
      {

      if (linecount == 0) PORTD = PORTD ^ 0x80; //Toggle the most significant bit of port D.;
      else if (linecount == 2) PORTD = PORTD ^ 0x80; //Toggle the most significant bit of port D.;
      else if (linecount == 3) PORTD = PORTD ^ 0x80; //Toggle the most significant bit of port D.;
      else if (linecount == FRAME_LINES) linecount = 0;
      linecount++;
      }

      void loop(){

      }

      ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      UPDATE:
      I finally have a screen I can use to subtract the memory contents with :

      #include <VGAX.h>

      VGAX vga;

      void setup()
      {
      vga.begin();
      vga.clear(11);
      }
      void loop(){for (int y=0; y!=VGAX_HEIGHT; y++) {
      for (int x=0; x!=VGAX_BWIDTH; x++) {
      vga.putpixel(x, y, 3);
      }}}

       

      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

      I now can use this with an AND chip and my own function gen frequency and output from the SRAM !

      And here are some of the images I’m getting (using an AND also for the clock coming from the signal gen) :

      And here I am trying to record VGA…
      …from VGAX (120×60):

       

      …and from a computer VGA at 800×600 passing along the sync signals:

      Here was what was onscreen :

      Test card - Wikipedia

      I can reproduce this reliably with :
      -op amp taking memory and amplifying it
      -a pixel clock at 1.007MHz (pixel clock for 640×480 of 25.175 MHz divided by 25)
      But it kinda turns on and off and also jumps around on the screen for some reason.
      I also found out I could use the vertical sync along with a counter (taking as input a 4MHz fucntion generated square wave) and a bunch of AND gates to essentially only record only every X frame and store it in memory. This meant I can save way more frames. Getting the right spacing for the frames will be key to be able to store a short video. 
      UPDATE 1:
      I can now save a short video : 695.45 kHz (This is the slowest I can go and still almost see an image) on the function gen AND’ed with the top 4 frequency divisions of the vertical sync. This makes for a burst of image recording every X number of frames.  I then amplify the output to make it visible on screen (and speed the clock up to 695.48 kHz). One problem is that it looks like everything is in fast forward and it’s barely possible to interpret the images. The other issue is once the video starts again from memory its frame moves with regards to the screen. 
      UPDATE 2:
      If the reset is connected to the inverse of the freq subdivision of the vertical sync signal AND’ed with the address 20, it will play the image in a loop and always place it in the same part of the screen ! 
      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      TESTING MAX ADC SPEED:
      I’m not sure what to make of this as the signal was super noisy but, I can “follow” a sine that is at 50Hz sampling it at 5MHz fine. I’m not sure what conclusions to draw from this…

      VGA controller board :

      -Attiny(?) 
      -several clock speeds to chose from
      -knob to select diff screen resolutions
      -PLL to sync to input VGA? Use an XOR to see delay with signal and then get closer to it ?
      -easy setup to pass input VGA syncs to an output VGA
      -filters to knock out certain frequencies to tune into what I want. 

       

      ANALOG BOARD:

      Based on the Analog Thing functionality (summing, multiplying, comparing, integrating, differentiating, etc.) along with counters to divide the screen by powers of two !

       

      UPDATE:

      Working now on a next version of the 16MB board. The idea is to fix the issues in the 16MB board, add more functionality, and also to move towards a finished board that is more plug-and-play with regards to recording VGA signals and less of a prepared instrument for testing. It’s a test to see if I could make something that behaves like a product.

      One question is if it requires an analog function generator or not, and to what degree the machine is mono-functional or not. (Though I think if it could record video reliably and display to a screen that would already be not bad.)

      Fixes :

      • A21 LED added
      • Top and bottom bias of ADC now controllable with pots
      • op amps on input and output both with variable gain and bias
      • fixed 5V and 3.3V power (ADC and op amps need 5V) with onboard LDO.
      • got rid of phase shifter and 8 pin dip switch
      • CS no longer tied to WR on SRAM.
      • various enables broken out so they can be turned on an off with external control 64KBSRAM
      • counters daisy chained with last address going to clock input of the following counter (no longer using RCO)
      • Replaced 74*541 with 74*245 (so it would have big footprint to let wires pass under but work with 3.3V)
      •  Added VGA in and out connectors and made pass thru mode for input.
      • Added f divider, AND, and NOT gates.

      This board should allow me to test the idea of having a control board chroreograph a sequence of memory operations, and allow me to begin testing the analog board with a stable (not breadborded) video recorder. 

       

      Sunflower Array

       

      The github for this project :

      https://github.com/merlinmarrs/tournesol

      I’ve made the PCB for with the 74AC240 based on this design from http://www.smfr.org/robots/robot_images/dualsolarhead_schematic.png :

      Hoping that it works better than the 540 version with the solar midpoint.

      IT DOES! It is far more responsive and efficient and works with the solar panel! It has a funny quirk where it will first turn the wrong way then correct itself in one direction though…Next i’ll make it on a super small extra compact board and try the other circuit option:

      It’s much more compact that the previous version. The photodiodes could be removed to make it even smaller. It took me around 25 minutes to assemble at a comfotable speed. By far the least efficient element of the assembly is the braided wire which is causing mini shorts :

      There is already some interesting interplay with the two machines side by side…

      3D model of fancy motor version:

      Here’s a version with a tiny gear motor. The motor appears to lock up at low currents however so it doesn’t work super well. It’s also very difficult to attach the motor axle to the bottom platform. 

      With the metal gearmotor it works much better:

      And this version with the panels lower down:

      Here is a tall version:

      Here’s a compact design with a “flipper” arm:

      The idea of pulling the solar panels from the board, exposing the electronics and creating the tilt naturally.

      The little metal cap is actually a nice part of the look of the machine:

      I have made the board thinner so that it fits perfectly over the gear motor:

      Here’s a shot of it looking pretty:

      Llama edition (it’s a heat sink). This photo makes me think I could have fun with shadows like in the 1970 Il Conformista film:

      I see a monocled mustachioed Monopoly man here somehow:

      This idea distributes the things to look at around the machine (one side has solar panels and the gear motor, the other has electronics and the underside gold lettering on the solar panels). When the machine is facing the sun we get to see the electronics. I guess the electronics is also sheltered from the heat of the sun a bit?:

      Here are some feet ideas for the resin printer using small set screws and (in the right model) Pogo pins:

      Here are two versions of the tripod design. One has the electronics as a backpack and hides it from the sun, the robot has two faces. The other has the “face” of the robot face the sun, in one photograph the whole robot is visible.

      Version 1:

      Version 2:

      ****

      Side to side comparisons:

       Another idea for pogo pin feet using the crowned tips:

      ***

      I made the barebones circuit in extra slim also:

      debugging the previous version, it appears that the solar panels are indeed producing the expected voltage and current (2 x 1.67V, 18.4 mA), the voltage trigger and mosfet are working, the capacitor is charging, and the voltage to the motors is spiking. However the motors aren’t so much turning as twitching. The motors appear to be identical to others that are working however. Changing the capacitor from .22F to .15F changed nothing. 

      EDIT:

      I had another stab at this:

      I noticed that the charging and triggering part of the circuit appeared to be working but that the motor was not firing. I assumed then that there was a soldering problem on the 74AC240 pins somewhere. I tested a copy of the same boards from the same batch to see if there were any problems with the etching itself, they all seemed good with no shorts and clean traces. I tested a blank 74AC240 as well and found that the only pins that were internally connected were 9 (Y1) and 10 (GND) – though I’m not sure why this is the case. I took a voltmeter to measure if there were any shorts between the pins on the IC and found that everything was mostly normal. Looking under the microscope it occured to me that the problem might be that the pins of the IC aren’t fully touching the pads below as they appeared to have been soldered quickly. In order to assume myself that everything was indeed well connected I reheated each of the pin connections and retested that I didn’t introduce any shorts. I then switched out the larger motor for a more efficient smaller DC motor. Testing with artificial light I now have normally functionality!

      The second malfunctioning solar head has a different issue: It charges up fine from having no power and spins the motor no problem. But after a few times it stops triggering at hovers around 3.6V…I resoldered the connections and had the same issue. The voltage trigger appears to be triggering despite the voltage staying high. In the end I switched the bigger metal gearmotor for a small vibe motor and it worked just fine. I think I can conclude from this that the circuit I used is not suitable for the metal gear motors but works fine with smaller ones.

      I am now looking into making this circuit even smaller using TSSOP-20 packages of the 74AC240 and maybe 0603 smd components too. I plan to make this double sided and to have the boards made at PCB way after testing a prototype circuit in the lab.

       

      The circuit works fine after I had to resolder some of the IC pins to the pads (they seem to hover just above sometimes despite the soldering) and fixing a short between the two sides of the MOSFET by lifting up the positive side of the SMD cap up.

       

      Testing with a single 3.4V panel and…it turns! I’m going to try to add the light detection now.

      And this is how it could be integrated into the 2DOF design: 

      This is a second option which would involve probably halving the above circuit and making it double sided. 

       

      Another idea is to see how far this minimalism and miniturization can go, for instance with a single solar panel capable of charging up the cap to 3.3V ish. It could be 1DOF or 2DOF. Testing with the power supply with 4,46V @ 5,9mA it works no problem with the small gear motor. We’ll see if that’s the case with the actual solar cell soon.

      Monocrystalline Solar Cell 24.5mW (4,46V Current – Short Circuit (Isc) 5,9mA)

      https://www.digikey.fr/product-detail/en/anysolar-ltd/KXOB25-01X8F-TR/KXOB25-01X8F-DKR-ND/10127250

      KXOB25-01X8F-TR ANYSOLAR Ltd | KXOB25-01X8F-DKR-ND DigiKey Electronics

      Monocrystalline Solar Cell 26.3mW 5.53V:

      https://www.digikey.fr/product-detail/en/anysolar-ltd/KXOB25-02X8F-TR/KXOB25-02X8FDKR-ND/9990483

      KXOB25-02X8F-TR ANYSOLAR Ltd | KXOB25-02X8FDKR-ND DigiKey Electronics

      Here is what it could look like 1DOF:

      …and 2DOF:

      If the solar panels are a bit offset from the boards then the light sensors could be directly on the board and not need to be offset themselves from the board. 

      ****

      I actually have one of these lying around to test the one panel idea (3,4V
      @ 4,4mA): 

      https://www.digikey.fr/product-detail/fr/ixys/KXOB22-01X8/KXOB22-01X8-ND/2754274

      Here it is working! (remember that the “GND” side of the photo bridge actually connects to the ENABLE of the 74HC240)

      some other panel configurations:

      I could have the light sensors on either end. 

      A little higher up…

      Satellite inspired:

      Here’s a quick 3D print:

      Not even sure if adding another DOF will have a big effect, over the course of a day how much will it actually tilt up or down?…

      Dual Solar Tracking Part III

      Another idea is to start with the actual solution (two small servos) and make it look better. It’s sturdy and already balanced. It just needs a hinge and a tilting arm:

      With a makeshift hinge and tilt arm:

      This would only require an Arduino mini pro and some super caps charged by a solar panel through a diode.

      Some other more simple options:

      For a miniature 2DOF.

      A mini 1 DOF.

        The 2 metal gear motor design I was working with early on.

      *****

      Here is a super simple two servo motor controller that recharges supercaps through a diode:

      This works with the code below as a test:

      #include <Servo.h>

      Servo myservo1; // create servo object to control a servo

      Servo myservo2; // create servo object to control a servo

      int pos = 0; // variable to store the servo position
      int threshold = 100;

      void setup()
      {
      myservo1.attach(5); // attaches the servo on pin 9 to the servo object
      myservo2.attach(6); // attaches the servo on pin 9 to the servo object
      }

      void loop()
      {

      if (analogRead(A2)-analogRead(A3)>threshold)
      {
      myservo1.write(90);
      delay(15);
      }

      if (analogRead(A3)-analogRead(A2)>threshold)
      {
      myservo1.write(-90);
      delay(15);
      }

      if (analogRead(A4)-analogRead(A5)>threshold)
      {
      myservo2.write(90);
      }

      if (analogRead(A5)-analogRead(A4)>threshold)
      {
      myservo2.write(-90);
      }
      }

      This is the monster in all its tentacularity:

      ****

      Testing the barebones circuit with the solarbotics white DC gearmotors and the SMD solar engine. It works with only two mini solar cells and the SMD cap as long as the sun is medium strong!

       

      This is exciting as a result (but I just needed the change the motor wire polarity):

      Here’s what the circuit looks like:

      This suddenly stopped working and I did the following things:

      Checked to see if the cap was charging, if the voltage monitor was triggering (and I manually triggered the MOSFET to see if the motor fired), the voltage at the midpoint between the two photodiodes, and if there were any shorts.

      In the end I replaced the zener with a normal SMD diode which I found, replaced the photodiodes with green LEDs because one lead was broken on the photodiode, and then discovered the motor was broken (or at least the blue wire was disconnected on the inside)! It gave me a chance to look inside the tiny gear boxes of the motors though: 

      Here is the, once again, working prototype:

       

      I would like to be able to tune the midpoint between the LEDs. I would also like smd light sensors. 

      Phototransistor Output Voltage Circuit connects the phototransistor and 2 k-ohm resistor in series

      Some options for solar panel and motor assemblies:

      Here’s with SMD LEDs soldered on:

      Not sure why but the thing is only turning clockwise…

      I tried the following things:

      1. A 10K trimpot (with each photodiode into each side of the resistor and the variable pin going to the logic chip). The trim pot at either extreme does indeed make the circuit turn in the opposite direction. However, in the middle it stops either side from firing.
      2. Replacing the photodiodes with Silicon PIN Photodiode BP34s, green LEDs 5mm, Green SMD LEDS, and LDRs.
      3. changing the ground of the photodiode pair to the ground of the capacitor instead of the ground connected to the floating connected to the MOSfet.

      Just found this image here (http://solarbotics.net/library/circuits/bot_popper_240.html) which seems to imply I could use phototransistors also:

      Looking at other Smart Head circuits, it looks like the + side of the photodiode pair is connected directly to the Vcc but that the negative side is connected to the “local” ground, not the negative of the capacitor. However, there are also counter examples…

      I tried just setting up the dual photodiode circuit on a breadboard. Two photodiodes , two LDRs etc. They each move from a midway value up or down depending on which device is in the dark. However, they don’t always have 1/2V as a midpoint, which appears to be the important threshold point for the oscillator. **EDIT** I think what they meant was half of VCC not 0.5V. I could try to find the exact threshold voltage that is the balance point with the power supply?

      2.25V for my desktop breadboard version of the circuit while supplying 4V for the solar panel. 2.85V was the threshold with solar panels at 5V. It also has a dead zone where neither motor will fire if it is perfectly in the middle. 

      For the soldered version the threshold is around 1.3-1.4V when being fed 4V as solar panel. 

      At 3.5V solar panel supply, I have a lower threshold bound of 1.25V and a higher bound of 1.4V. In the deadzone neither direction turns. 

      At 3V funny things happen. It will only turn one direction unless I suddenly make the input 0V. This might explain why my circuit is behaving strangely! I am using a 2.92V voltage supervisor so I don’t think my current circuit is ever going to work. 

      I should replace it with a higher voltage threshold like this one perhaps: https://www.mouser.fr/ProductDetail/968-ISL88001IH46ZT7A 

      In the meantime I can use a voltage divider like I did for the 1381. 

      Here’s the scope output attached to one lead of the motor. The fat, fuzzy part is when the motor is not turning and the threshold is reached. Either side it sends between 1.5-2V to the motor turning one way or the other.

      Setting up my own little trim pot between the LDRs I was able to tune them to the correct voltage threshold and everything works well on a breadboard at least.

      Here is the 74AC240 datasheet: 

      Checked out the 74AC240 datasheet, for 3.5V the threshold should be between 0.9V-2.1V.

      ****

      Version 2 of the board has trimpots for the voltage trigger and the light sensors (which are now SMD and on either side of the board):

      Here are the parts laid out with the new board:

      Post-soldering. The size of the board versus two small solar cells:

      I had to put electric tape under the trim pots because contacts were exposed underneath…  The full assembly:

      ****

      Found this online here (http://www.smfr.org/robots/robot_images/dualsolarhead_schematic.png): 

      It uses the solar panels as the light sensors! It also lays things out in an easy to understand way (the midpoint is the boundary between what the inverter sees as HIGH or LOW. Once the solar engine has enough power this decision of HIGH vs. LOW then powers the motor through six remaining gates – presumably to increase the current as each pin seems to be limited to 75mA according to the datasheet above?).

      ***

      Testing V.2:

      I can get 3.5+ volts (4V outside in full sunlight even) with the current setup of two solar cells + little cap!

      BUT…When I short the voltage supervisor 5K trim pot the motor fires, but even in its least resistance position the supervisor is not triggering…It is also only doing mini movements, not full shots. I removed the trim pot and now it behaves normally. I don’t understand why the trim pot doesn’t work when it was flawless with the benchtop power supply…

      With a 1M trimpot the variable voltage trigger does work just as expected, however! I moved it up to 3.5V ish.

      The 5K trim pot for fine tuning the light sensors also does not appear to work. Also doesn’t work with a 1M and two green LEDs…

      I tried using the two solar panels as sensors as suggested in the found circuit and it appears to work, there remains the same problem of how to tune the voltage level however if my trim pot solution doesn’t work. 

      ***

      I think I need to order 74AC240s (I think the 74LS540s I am using might be slightly different in terms of their HIGH/LOW thresholds) or voltage triggers for 3.5V+. This is a nicely tuned circuit that seems hard to mess with.

      Just a reminder of how much the complexity has been reduced in this project!:

      ***

      I have realized I need to understand the circuit I am working with better in order to tinker with it. 

      First thing, the 74LS540 that I am using has a minimum voltage of 4.5V! It also can only supply 45mA max as an ouput if I understand correctly. However, I also have a 74F244D octal buffer which works as low as 2V. However it is Bipolar and not CMOS technology like the 74AC240 AND more importantly, it has non-inverting outputs. Clearly getting the right logic chip and family is an important element and not a detail for this circuit…

      So, the LDR “photo bridge”. After testing 10 we had lying around I arrived at these average values:

       

      Here’s some R Thevenin calculations (Thanks to Learning the Art of Electronics!) to figure out what size pot I can afford to pull up or push down the midpoint from the LDR divider:

       

      And here’s the current logic circuit in a more understandable format:

      ****

      Did some tests, looks like I need to bring the midpoint DOWN in my circuit:

      Yellow is the cap voltage (3.42V) and green in the midpoint (2V) with equal light on both phototransistors. 

      This scope image shows first both photodiodes in light, then the left (connected to GND) in darkness, and finally the right (connected to VCC) in darkness:

      Without even needing to take any measurements it’s evident that the midpoint is too high. This causes the motors to always turn the same direction when the light intensity is equal between the two phototransistors. I flipped the photo transistors and observed the same effect so I think it’s the circuit not the difference between the phototransistors.  

      This scope image shows me adjusting the phototransistor trim pot. (Fully attenuating on the left, halfway in the middle and then fully open on the right). 

      And here’s testing with the middle threshold covering and uncovering each phototransistor:

      This shows that the 10K trimpot effectively drops the entire midpoint! I can effectively dail in the midpoint to exactly half of VCC now (3.42 Vcap, 1.71V threshold)!:

      Now the machine is not turning in only one direction! But it also might need some resistors for when the two photodiodes are both seeing bring light. I also need to replace the LS540 with an AC240 because I am currently operating outside the maximum minimum voltage of the IC. It would also be nice to use the solar panel as a sensor and thereby reduce the part count (I could still tune the midpoint in the same way once I determine which way the imbalance is – it would also solve the shorting problem in high light). 

      I varied the pot and everything is working as expected. I also added heat shrink to the phototransistors. Here is a video:

      I tried some 2DOF designs but I think this needs to stay MINIMAL and the force of the project, if it comes, will come from the array more than individual complexity. Plus they already seem imbalanced and more likely to malfunction…

      Some tests with the solar panel voltage divider:

      Here’s what it looks like when I change the solar panel midpoint with the 10K trimpot:

      Here is the solar panel midpoint trim pot all the way to one side:

      Here is the solar panel midpoint trim pot all the way to the other side (not sure why it goes all the way to the ground here only):

      Here is me putting one panel in the shade, then the other. The difference is not massive.

      The problem is that now I fall into a large deadzone where no movement happens in the middle. I’m trying to find the right combination of voltage trigger trim level and solar midpoint level but it’s not easy without sunshine…

      ****

      Here’s the cost per unit of this design:

      74AC240: 0,462 €

      0.2F cap: 1,21 €

      solar cell: 3.56 € (1.78 € x 2)

      micro gear motor: 4.25€

      voltage trigger: 0,356 €

      diode + 0.47uF cap: 0,1€

      PCB: ?

      Total: 9.938€ + PCB cost

      ****

      I have now a 1M trimpot on the solar midpoint and have added a 1M between the midpoint and VCC to try to balance things out.

      I think 3×3 is better than 4×4 ? 5×5 would be out of control.

      ****

      Working towards simplifying the dual servo sun seeker. Here is a post for controlling servos without a microcontroller:

      https://www.pololu.com/blog/18/simple-hardware-approach-to-controlling-a-servo

      Could use LDR pair to replace pots inside the servos, based on ideas from Hackaday post shared with me by Paolo Salvagione:

      Light Tracking Robot Relies on LDRs

       

      ***

      Went back to the super simple business card sun shaker and added some feet. I also tested the new 0.2F caps and they work with outdoor light but might be too tough to charge with indoor light (unless it’s actually bright then they work fine). After Paolo Salvagione’s comment about using a smaller motor to rotate the device, it occured to me that I could use the vibe motors in two directions to create movement that follows the sun:

       

      ****

      Ordered this motor: 

      Here is a new design with (human) adjustable tilt. It has more of a “pro” vibe. The motor adds 5 euros to the total cost of the machine bringing it up to 15 euros:

      ****

      Looks like the trick with the light sensing is just to put the photodiodes behind the board so that the shadow cast by the sun creates a clear preference for one side or the other. They can be bent around a little bit to be perfectly tuned but it also adds a bit of idiosyncracy to the ‘bot. So it doesn’t appear that I need a trim pot for this option. I’m not sure how to create the same contrast with the solar panels as putting either in the shade is obviously not a good idea. Pointing them in different directions creates some difference but not a great deal.

      ****

      I’ve redone the circuit for the 74AC240 and make it more compact:

      Here is my next design with the smaller DC gear motor. I’m imagining a soldering a pin to the PBC in order to attach the pivoting arm to it. Otherwise the issue is how to make this attachment without creating a whole frame and bumping into components etc. It has a small M2 bolt to fix the print to the motor and to adjust the angle:

      I’ve made a cleaner video of the first prototype:

      Dual Solar Tracking Part II

      Continuing the project of making a small solar tracking device.

      ****

      Idea to simplify the circuit drastically and make the 3D model a bit more robust and less fragile so it is far easier to assemble and won’t topple over (while hopefully maintaining some elegance…) 

      -Battery-powered (and possibly solar recharging through very simple circuit):

       

      plus Attiny with two steppers only powered directly from output pins (max 40mA and danger of kick back which might be solved with diodes) and no light sensing – just the almanac algorithm for sun following. *

      *(Remember you can test the stepper resistances to know which are pairs!)

      Tried powering a stepper directly with an Atmega using the Stepper library in Arduino with a bunch of different step and speed values – if it turns at all it’s extremely weak…So this doesn’t appear to be an option.

      Tried powering an atmega328 directly to cap and solar panel through diode, in medium sun there is no action. With bright sunlight it manages to power up despite blinking a blue LED every secon. I could try with the sleep timer I recently acquired (https://www.adafruit.com/product/3573). Or maybe a simple sleep code will be enough. This seems like a viable option which would simplify the circuit considerably.

      Another cheap and simple option is the ULN2003, but this requires 5V to function unlike the low power DRV8833 I have. 

      ***

      Tried driving the stepper gearmotor chain drive and it moves very smoothly and almost imperceptably. 

      I dug up some DC DVD raft drives, they are nice mechanisms:

      The black rack was attached to the raft. 

      I tried powering these with Wilf’s SPSH circuit and the bearbones solar head and they were too big a motor to be powered unfortunately. I could still try to increase the 1381 trigger level with a resistor though…

      I’ve redesigned the microchip version of the board to make the wiring to the stepper much easier this time. I’ve also added two caps to smooth out the motor supply. 

      And here is a more robust version of the previous two stepper, this one has two parallel bars, a more robust hinge, and the lower bearing is encased completely for more stability hopefully. I am also getting rid of the lead screw plastic piece and trying to replace that part with a thin metal rod. In general it’s simplified and a bit thicker all around :

      I am using a dremel to clear out the holes before inserting things and this is reducing shattering of the more fragile white resin. 

      The bottom bearing:

      Part of the solar panel hinge:

      Only one of the two stepper drivers worked on this board but I haven’t found the issue yet…I wonder if back reverse polarity I destroyed it by accident or over heated it during soldering. I’m going to replace it with a fresh one and see if that changes anything.

       

      Here’s the assembled machine:

      Here is a look at some of the technical details:

       

      A different panel orientation option: 

      Comparing the two versions (the newer is far more compact and stable but less playful and off-beat/asymmetrical):

      Check out the angle range, it’s better than I expected!

      ERRATA:

      1. The idea of putting a pin accross to act as the lead screw is not working with only one side screwed in. AND the lead screw platform is impossible to insert into position (I had to break it in half and glue it back together once in position). I should definitely not try to go under the lead screw, with the nut that holds the pin, it actually makes contact with other nuts holding the whole linear rail assembly. I think I should go back to integrating the existing plastic lead screw – aesthetically it adds more flavour and asymmetry.
      2. The part that attaches to the panel should be one connected part because this gives more surface to attach to and more rigidity. (X)
      3. There is a volume which enters into the bearing socket that I needed to remove with the dremel. (X)
      4. The three bottom holes for screws are not evenly spread out around the circle. (X)

      POSSIBLE CHANGES:

      1. Tensioner for bottom chain or larger bottom gear?
      2. The top hinge is too symmetrical for my liking but otherwise it’s super stable.
      3. Transparent resin is definitely nicer.
      4. The bottom nut needs a tiny bit more room, but it just works.
      5. The bolts are hitting the bottom stepper gearmotor.

      Here is a new version which solves the errata, but it looks hideous:

      I am considering returning to a one bar setup. I am also considering how I can make one version of this device that will work for the different linear actuating steppers and the different rotational motors (the micro steppers and DC gear motors have the same face plate thankfully). The top and bottom of device are also not connected (so varying heights of linear drives can be accomodated). Should one single design be able to work with belt drive or chain? I think I should now focus on producing a bunch of these.

      Here is how the little plastic parts that act as lead screws work:

       

      There are all kinds of shapes but in the end they all appear to have one main screw location and a bunch of other nibs and slots to help with alignement. I can include a sliding slot for the main screw in the 3D print but I may use a dremel to adapt it to different nib locations. 

      I’ve revisited the version 1 and have made the following changes:

      1. I’ve kept the more robust base from version 2.
      2. I’ve revised the lead screw plastic part holder and made the print compatible with the highest number of these peices and allowed for longer stroke.
      3. I’ve kept the magical setup that allowed for a great variation in the panel angle.
      4. I’ve kept the circular base which is more stable and made a larger base gear so it looks more stable. (The pitch of chain I am using is 0.1227″ https://www.mcmaster.com/miniature-roller-chain-sprockets/pitch~0-1227/)
      5. I adjusted the motor so the bolts are no loner hitting the bottom stepper gearmotor.

       

      ****

      Wire management:

      I like the ribon wires from the CD drives and the mini locking sockets and plan to use them:

      The top option seems sensible.

      Here the bottom motor ribbon is going to be super stretched when the panel is at full extension in angle…

      I like the asymmetry of the second option, it implies that the lead screw and hinge action is taking place on one side and the electrical connections on the other side.

      (I’m just realizing that some of the ribbon cables that come with the stepper linear drive are not very long + the brown/orange doesn’t go super well with the white. Should I replace those cables with white ones so that everything is the right length and homogenous?)

       

      There is also the possibility of folding the ribbon cable…

      I’m trying to find this product (it seems to be called “flexible flat ribbon cable”) but not having luck on Farnell or Mouser (*correction: https://www.mouser.fr/ProductDetail/Wurth-Elektronik/687606050002?qs=qR1qlUC5%2FYSp8nXHAtNchQ%3D%3D) …Here it is on Ebay and Amazon:

      The other option is to harvest wire from the old CD drives I have, the wire lenghts seem to vary from 8-11cm.

      Some solar panel options:

       

      ****

      Next version sucesses:

      orienting parts so that the supports don’t touch faces that will be seen is a good idea, it saved the bottom platform from pockmarks.

      Errata:

      1. The main issue is the lead nuts. They are massive and therefore reduce the stroke considerably. Most have a setup where they push against the leadscrew and twist the sliding cam which is now only fixed to one rod.  I should try to design the nut myself, if the solar panel is in the middle it is hidden in any case. The other option is to find another one in a million lead nut that works like the one in version one where it doesn’t push against the cam / use two bars. (X)
      2. Somehow the ratio of arm lengths is producing a totally different range of angles, mostly in the negative direction! (X)
      3. the layer on top and below of the bearing is too thin and comes out wavy. (X* I did the top visible part but not the bottom).
      4. missing a subtraction around the collar of the bottom stepper motor shaft. (X)

      Possible changes:

      1. all black hardware would be nice. Or perhaps all white?

      ******

      Modeling the lead screw:

      The threads themselves:

      I want it to be possible to adjust this thing so I am planning to use a stack of washers to accomplish this. I am also adding a notch in the purple volume to prevent the green volume from rotating. It should also mean that the green volume can be made to accomodate different threads and the purple volume will still work regardless (i.e. it’s modular).

      The backside leaves space for a nut to fix the green piece in place at the right height.

      I’ve also adjusted the angles to match the version 2 as exactly as possible this time:

      Here is the finished version 3:

      Some quick ideas about how this project could be displayed in an expo:

      1. I can make a bunch of solar critters that react to the sun in different ways (sweeping in circles, following the sun but staying in place, making sound by tapping the ground or playing a song, etc.). This is the kind of ludic, “diversity of nature” bio-inspired option. The robots are indifferent to one another but occupy the same space. I’m not sure how to chose the materials but maintain difference/cohension of the group but presumably I could pick a kind of 3D printing and use the same motors.

       

      2. Make one such critter (like the sun follower) and create an array of them in a given space and watch the group effect of their behaviour. This is kind of obvious but at least it’s abstract and sober, hopefully fitting in my portfolio with my other more abstract/representational work. It would also be easier to mass produce one design than to make a bunch of one-off designs I think.

      And here is the BOM so far:

      And here is the newest build:

      ERRATA:

      1. The lead screw does not work. It is not perfectly aligned with the threaded rod and the system for holding it tightly in place is not working. I think I need to put the lead screw on the bottom side of the threaded rod and have a tensioning mechanism on the front (accessible) side.
      2. The angles are still wrong. If I make the top arm (that is glued to the solar panel) shorter I think it will improve.

      I’ve put the lead screw on the back of the threaded rod and inserted alignment rods and increased the borders to hold the top piece in place:

      ****

      The solar panel angles are fixed! With two of the threaded nut sides making a sandwich it does actually work as a lead screw nut (even though it really doesn’t look nice) !

      ***

      Thoughts from artist Paolo Salvagione:

      1. Make a power budget (what does everything i.e. steppers, microchips, drivers use when not on, when on)
      2. Run motors 24/7 for weeks before to test that nothing falls apart.
      3. Replace bolt hinges with flanges or miniature bearings from McMaster Carr. (The smallest available at a reasonable price is 5mm OD no flange).
      4. Try pulling up everything to the top beneath the board and alternatively pushing everything else to the ground to create a sunflower.
      5. Think about the center of balance of the machine and how you can place it directly over the pivot point (or move it there with weights).
      6. What kind of choreography would I like to see here.
      7. Alibaba has super inexpensive solar panels that look great.
      8. Could the array relate to different light sources which exist in a kind of solar system around the plinth.
      9. How can visitors experience this piece at different distances (“layers” of experience)?
      10. Medium-runs of a finished design are easier than making a ton of one offs or mass producing.
      11. It’s possible to order flexible PCBs from PCB Way.

      ****

      Some thoughts on the layers possible:

      I have found a few 10mm OD bearings and will redesign the arm portion with these:

      I’m not totally satisfied with the bearings in the design (McMaster has perfect 5mm bearings that are reasonably priced but they don’t ship out of the U.S.).

      ****

      Calculating the balance point with help of this site: https://www.school-for-champions.com/science/gravity_center.htm#.X2B-cFUzaUk

      Calculating CG of weights 

      CG = (aM + bN + cP)/(M + N + P)

      Seems like I should try to keep the solar panel light in general (under 12 grams?), but that I have the option of adding some weight above the stepper in the rear. In the other axis I can shift the solar panel a bit to the side to compensate for the weight of the bearings in the arms. 

       

      ****

      New version with arm bearings:

      It was hard to attach the solar panel to that arm model so I switched it for one with mini bolts:

         

      I don’t like the look of the three wide and narrow bearings so I am trying to hide one under the panel and switch up the second by putting the black bolt through it. One of these only would look great but three is too much.

       

      A new design with McMaster 5mm bearings (I can in fact order them it would appear). In one I keep a single large bearing and in the other all the bearing are small:

      Making a third prototype to test the following things:

      1. Durable resin for everything but especially for the lead screw.
      2. Adding flanges to hold the current bearings in place.
      3. Slight tweak to the currently improvised lead screw design.
      4. Fix angles again with shorter arm.
      5. Hiding the other bearings a bit under the panel.
      6. Making a third so that I can begin testing the “swarm” effect of the robots actually moving.

      ****

      I began two stress tests based on Paolo’s advice:

      Some things to note:

      1. These are so much fun, people visiting see what you’re doing as Paolo suggested!
      2. It fights anxiety – you know if it will work or not.
      3. Working for 1 minute is not the same as working for two weeks 😉

      Unfortunately there is a serious issue: The linear drive is drawing 600mA at 5V to move up and down…I should try to mess with the steps and speeds to see if I can get this down. The rotating motor is drawing less than 150mA. 

      Looking on Alibaba, the most popular size of smaller panel is 156mmx156mm.  But also found some 47×47:

      and some 55mmx14mm

      37x21.8mm 6V 2mA outdoor used Thin Film Amorphous Silicon Solar Cells for Outdoor Products

      37×21.8×1.1mm 

      Here are the best links I’ve found so far:

      https://www.alibaba.com/product-detail/55x14mm-3-0V-7uA-dim-light_60585863880.html?spm=a2700.galleryofferlist.0.0.43be4630X6CXwJ

      https://www.alibaba.com/product-detail/Dim-Light-Amorphous-Silicon-Thin-Film_208238751.html?spm=a2700.details.deiletai6.5.561929devzX1BP

      https://www.alibaba.com/product-detail/3V-10uA-Dim-Light-Amorphous-Thin_62187655652.html?spm=a2700.details.deiletai6.1.561929devzX1BP

      https://www.alibaba.com/product-detail/37×21-8mm-6V-2mA-outdoor-used_60506651563.html?spm=a2700.galleryofferlist.0.0.2430367cO11E7R&s=p

       

      I sent my first email: 

      Hello,

      I’m a research engineer at the Universite of Paris Sud in France and an M.I.T. graduate.

      I’m working on a low-power solar follower product and reqiure small cells like yours to create a series of panels (with each an array of 5×2) to combine with an energy harvesting IC.

      I am interested in your product and would like to request a sample if possible to test with my setup.

      Thank you ,
      Jonah Marrs

      *********

      Easy stepper motor driver can drive both steppers at around 150mA at 5V with no load. 

      The DRV8833 with correct step and speed settings can drive the linear with the plastic lead screw found in the CD drive at around 360mA but has a super high idle current of 600mA. It gets super hot as a result. The DRV8833 cannot drive my lead screw setup however… Basically there is too much friction in my lead screw design currently. So, the conclusion is that it’s possible to drive this thing if I put the driver to sleep and I use the existing lead screw.

      I am leaning towards using the found CD drive mechanisms (because they are perfectly made to minimize friction etc. already and look super cool) and add a second bar parallel to the first to improve stability and compensate for the rotating that the plastic lead screw wants to do.

      I’m also adding another bolt to the bottom angle bearing, and looking for some 3mm bushings to add to the sliding portion. Here seem to be the two primary options:

      The side by side bars on the left are less flexible with different found lead screws as the bolt location can’t move much to either side. It also makes the front part flatter and longer, whereas the bar behind makes the design feel more three dimensional and compact. 

      I prefer the bar behind. 

      Bending joints options:

      I like the asymmetry of not having the top and bottom joints unaligned in elevation and in plan views, it feels more dynamic and optimized. I like the bottom bearing being centered with the cam. 

      Hopefully this version will allow me to do some stress testing with the tilt mechanism.

       

      Here are the parts laid out:

      The assembly turned out well:

       

      ERRATA:

      1. The lead screw is a tiny bit too high above the threaded rod, I had to carve out some material with the dremel…
      2. The elbow joint connected to the cam can’t work with a captive nut the way I originally concieved but it can work with the cap of the screw in the place of the nut.
      3. The set screw for the sprocket needs to be almost flush with the sprocket surface to not hit the bearing squeezing screw. The bearing squeezing screw between the parallel bars needs to come from the top not the bottom or else it interferes with the chain. 
      4. I think I need to shift the two bolts that hold in place the bottom motor 90 degrees. And I may need to add a little circular band to keep this motor straight.  A tiny drop of hot glue solves this…
      5. The solar panel surface is not flat but tilts inwards.

      I got the test set up working again with two Easy Stepper Motor Drivers (with Enables and 5V+ connected also) this time. Now the bottom motor is driving 100mA and the linear is pulling 200mA. Both are cool to the touch. However, there is a little bit of power lacking for the linear lifting motor and it is skipping some steps. Switching to 1/4 instead of 1/8 microstepping, and making sure all the bearings are set up smoothly, appears to mostly fix this though.

      Some experiments taking nicer photos:

      A with and without solar panel gif:

      *****

      I’m doing a next design based on the observation that the motor is struggling to pull up the solar panel and that the weight could be repositioned closer to the center of gravity and rotation axis. It’s more sunflower like, and the lead screw is now exposed as in version one. Nicer balance in terms of the bending joints which now aren’t all on the same side. One of the three bearings is hidden so the emphasis is more on the two side ones now. Far more sturdy rotation mechanism for the solar panel so no more warping and bending hopefully. The arm will have to travel far less distance to change the angle of the solar panel also.

      This experiment is interesting to me because it’s an attempt to move towards a more robust design while trying to keep it visually interesting and maintaining the attention to form.

       

      I adapted it for a mirrored version of the linear drive and new lead screws (it wasn’t too hard to do). Now I have right and left handed machines:

      This is interesting as it shows how easy or not it is to adapt to the repurposed CD drive mechanisms with the current design and how much variation can be created organically. 

      ***

       

      It looks like I should go with white Rigid resin and that I should use bushings for the sliding portions so no part of the print has friction.

      These appear to be the key characteristics of the lead screw/nut setup.

      ****

      Adding some grease to the rails:

      *****

      Here’s the tall version:

      It has great tilt range.

      It feels much taller and more slender. It also looks far more like a sunflower. It’s also lost its animate / cuteness quality that comes from being compact and now feels more like a machine. It does make more sense in terms of weight distribution, however.

      It proves that the idea of adjusting for found CD drives works in principle. 

      V.4 ERRATA:

      1. The Durable resin is too flexible to make rigid longer parts. The whole assembly is flopping all over the place.
      2. I need to modify the central solar panel hinge – it’s not possible with the hardware I have to make it function properly. Because the tilt arm pulls from the side, it has a tendancy to tweak the central hinge. I could use the large bottom bearing up top?

      ****

      The new version features a pole that pushes up to tilt the solar panel, and lets the panel rotate down when it descends. This means fewer bearings and maybe less strain on the linear actuator stepper motor:

      I’ve redesigned the control board. It now has a nicer spacing between the motor driver out pins and doesn’t have any other wires nearby to get in the way of these pins. It also has the motor driver sleep pins connected to the microchip, and can drive two steppers instead of one stepper and one DC motor as with the previous version. It also has more noise attenuating caps:

      I am also considering using an Arduino Nano with DRV8834s and a mini lithium ion just to get this prototype running!

      This works but it’s very heavy with the battery packs. I may need to glue the bearings in place or work with a more robust design for this phase.

       

      I’m using the StepperDriver Arduino library and this is what my loop looks like:

      if (analogRead(A0)-analogRead(A1)>threshold)
      {
      stepperTop.move(-MOTOR_STEPS*MICROSTEPS);
      }

      if (analogRead(A1)-analogRead(A0)>threshold)
      {
      stepperTop.move(MOTOR_STEPS*MICROSTEPS);
      }

      if (analogRead(A2)-analogRead(A3)>threshold)
      {
      stepperBottom.move(-MOTOR_STEPS*MICROSTEPS);
      }

      if (analogRead(A3)-analogRead(A2)>threshold)
      {
      stepperBottom.move(MOTOR_STEPS*MICROSTEPS);
      }

       

      And here’s the new print:

      ****

      Just discovered why I may have been having issues with the DRV8833s…Their max soldering temperature is 260C, I have been using 300C!

      ****

      I tried to get a full prototype running with the Arduino breakoutboard version but it’s surprisingly heavy and both attempts were unsuccessful. The second:

      Without the weight of the circuit board everything is fine however:

       

      I think I may have to admit that this thing is too janky to work beyond as a quick video. 

       

      *****

      Meanwhile I’m working on a DC prototype of the more complex 2DOF design:

       

      The idea here is to have 2 1DOF solar engine circuits + a dark activated pummer circuit. The machine would then spend its days searching for the sun and charging up a bigger capacitor to then blink at night like a lighthouse. I’m not sure if I should make the blinking synchronise with other nearby blinkers using this circuit:

      https://www.instructables.com/Synchronizing-Fireflies/

      One DC motor (controlling the tilt) is so slow it’s barely noticable at all while the other one swings the machine round dramatically. The design has less magic than the servo version but is far easier to control and has no issues with the weight of the solar panels. 

       

      Robot Arm

      Here is the final product:

       

       

      1 Common robot arm configurations | Download Scientific Diagram

      After the relative success of the foam cutting machine, I would like to build a medium-sized robot arm which can actually be a useful tool in the lab and not just a toy.

      The main questions appear to be: how to increase the torque of the stepper motors? Should we make a classic robot arm or a Selective Compliance Assembly Robot Arm SCARA?  Should the parts be 3D printed or CNC milled (or a combo)? and, Do I already have the parts necessary or do I need to order them in which case how much should I order?

      **********

      Stepper torque options:

      1. Use our super beefy stepper motors. Unfortunately, none of the other hardware (like belt sprockets) fit the diameters of the shafts.

      NEMA 34 Stepper Motor (6A , 12 Nm , 151mm) | DIYElectronics

      2. 3D print a planetary gear or buy one:

      (but these make the front of the stepper bulky and a bit ungainly)

      3. Get a large timing belt pully with a short belt drive: (unfortunately we don’t have anything like this lying around the lab).

      4.  3D print a large gear to turn directly with the stepper:

      A different concept that involves a motors not all at the base:

      **********

      SCARA vs. Conventional robot arm.

       

      Building SCARA Robot Arm pick and place using vision system - YouTube

      YK400XE

      #SCARAs fold up easily and are faster for certain tasks than conventional robot arms.

       

      pyBot: OPEN SOURCE and 3D printed Robotic Arm controlled with Python

      Custom SCARA printer finally taking shape. : 3Dprinting

      Scara arm solution

      A Desktop SCARA Robot using Stepper Motors

      298 Best CNC images in 2020 | Cnc, Diy cnc, Cnc machine

      But there are some neat conventional robot arm designs out there too:

      *******

      CNC milling vs. 3D printing:

      CNC milling some parts (like the large gears) seems possible:

      Nylon and ZMorph CNC PRO Milling Toolhead

      But I also need either to buy a large bearing or to make my own bearing…Unless I make a geared slew bearing:

      Single Row External Gear Slewing Bearing China Manufacturer

      Here’s a cool guide on designing gears: https://lcamtuf.coredump.cx/gcnc/ch6/

      Some DIY slew bearings:

      Project | Mammoth ARM | Hackaday.io

      A 2.5D Slew Ring | Hackaday.io

      ***********

      Robot background information: http://www.societyofrobots.com/robot_arm_tutorial.shtml

      Cool tutorial includes info about DOF, calculating torque for each joint (fewest joints possible with shortest lever arms the better): http://www.societyofrobots.com/robot_arm_calculator.shtml

      Some simple arm linkage ideas:

      Homemade Scara Robot Arm DIY Robotic Frame Projects Laser 3D Printer Chassis Draw Arduino Control d - YouTube

      3D Printer Technology and Innovation | Desktop cnc, Robotic arm diy, Diy robot

      **********

      And these Five-bar linkage machines (aka Parallel SCARA robots), they appear to be known for being super fast:

      https://en.wikipedia.org/wiki/Five-bar_linkage

      Homemade Scara Robot Arm DIY Robotic Laser 3D Printer Chassis Draw Arduino Control Frame Projects 2 - FutureTribe.Me

      SCARyllA: Dual (parallel) arm SCARA laser engraver build

      ÉTS : Laboratoire de commande et de robotique

      Related image

      Lightning-Fast SCARA Robot Prototype by Proto G - Hackster.io

      **********

      For the end effector I think either air pressure or electromagnet:

      Vacuum End Effectors VEE

      Robotics Industry Insights - Latest Trends in Intellig...

      ************

      Some early models:

      With only two rails (I’m not sure if this is sufficiently stable or not as many designs have 3 or even 4 rail):

      Similar but with a larger motor at the bottom and less ugly mounting plate. 

      A completely different SCARA design, I like the silhouette but it would involve tons of cut planar material that would need to slide into together and we might not have everything on hand to make this either: 

      Quick attempts at 3D printing planetary gears:

      https://www.thingiverse.com/thing:2114390

      https://www.thingiverse.com/thing:3231908

      (interesting belt option here: https://www.thingiverse.com/thing:2911407)

      Using the 0.8 nozzle was not ideal and none of the pieces fit properly. I would love to try this as a cnc cut project but I think it would be highly technical and difficult and at the end would end up in a tiny box. (I’m going for medium scale machines at the moment not tiny intricate things).

      We have 12mm HDPE in white and blue in the lab, I’m going to first 3D print then mill it. 

      I’ve come to a compromise with the design. It will give me the opportunity to design with a Nema 23 a complex peice (geared slew bearing), to work for the first time with a 5 linkage parallel robot design, to CNC mill HDPE for a more robust machine, but also builds on the syringe pump linear actuator and the foam cutter designs. Most importantly, I have all the components I need to build the full prototype already in the lab. 

      I added hardware to this model to make sure everything makes sense:

      *********

      Developement of the geared slew bearing:

      Outlined this drawing in Rhino and then applied it to a circle:

      To make everything fit (increments of 2mm) I changed the size slightly of the gear:

       

      Here is the first prototype:

      Here is a section showing the bearings cut through and how two layers of 6mm HDPE should come together to make the bearing. After assembling we’ll see if .1mm was too much spacing between the bearing and the walls, and also if there need to be two rows of 4mm bearings.

       

      *******

      Here are the 5 bar parallel robot 3D printed parts (view from underneath):

      A combination of nuts, washers, 16mm bearings and socket shoulder bolts:

      There is an offset in order to make everything work on the stepper motor shafts:

       

      *****

      With the final additions here is the final machine:

      Here’s the 3D print file with all the parts: 

      Here is the kit of parts (minus the parallel arm rods):

      The geared slew bearing assembly is tricky because the bearings want to fall within the inner moat.

      Adding the top bit:

      Finishing it off:

      Here is the drive mechanism with an idler I added:

      Assembling the parallel robot arm components:

      Hammering in the bearings caused splitting in the print…

      I sawed the metal bar and deburred before assembly. 

      The top threaded rod motor assembly (I broke one side hammering the nut in a little too vigorously)  

      Despite checking and rechecking I somehow forgot to put holes in the middle of the rod bearings (!)

      Here’s the linear actuator assembly:

       

      With the parallel arms attached, just waiting for the base to finish printing:

      With the base:

       

      Errata with the bottom part of the robot:

      -impossible to tighten hex nut to fasten gear to bottom motor axel. (Added slot for this purpose)

      -not nut subtractions to help hold bolts which fix geared slew bearing to base plate. (Added captive nut subtractions to bottom of base plate)

      -I subtrated a cylinder from the base for the motor gear but this makes no sense as it rotates around and does not stay fixed. (I filled this in)

      -With current arrangement the belt between the drive shaft and geared slew bearing was loose. (Either I add a spot for an adjustable bearing or I change the location of the motor to pull it further away…I chose the latter).

      ****

      CNC milling:

      The top motor and rail mount:

      I replaced one part of the 3D printed robot parts at a time:

      The middle component:

      Everything fits together nicely!

      And here is the final result:

      The CNC mill using HDPE is extremely fun to use. The only part that is not easy to make is the bearing assembly. This I will print in durable white resin on the Formlabs.

          

      Medium-sized CNC Foam Cutter (with Léon Reboul)

      Here is the finished product:

       

      And here is a quick video cutting foam:

       

      Another video showing the stage testing:

       

       

      Here are the files on Thingiverse: https://www.thingiverse.com/thing:4428184

      We’ll be harvesting parts from an old Ultimaker 2.

      The stuff we plan to use:

      Based on what we found, we plan on making two threaded rod actuators and two belt-driven actuators.

      Here is the prototype of the linear threaded rod actuator:

      Here is the prototype of the linear belt-driven actuator:

      Here is the prototype of the entire foam cutter assembly: