ST7920 128 x 64 Graphics and text display using SPI and Cypress PSoC custom component.

Image

So it’s been a bit of a long time since I blogged on WordPress, but I am back again. Please bear with this specific blog as it is a work in progress.

Also apologies for layout glitches as I am getting used to the new blocks editor on WordPress before they retire the old WYSIWYG editor.

I had an old WG12864a display in my components box and I wanted to get it working with one of my PSoC development boards.

Sadly the magic grey smoke has escaped from both the display and the development board when an errant flying wire contacted with something it should have stayed away from.

Never fear this handy trader on E-Bay had a similar Text and Graphic Display using the ST7920 display driver.

There are lots of Arduino sketches for these types of display, but not much for Cypress PSoC 4 & 5 devices. As you will all know by now Crusty of “Crusty Hacks” likes the programmable hardware PSoC chips use. Using programmable hardware to handle what would b a “bit bashing” fest on a micro makes an awful lot of sense to me and being able to do things in parallel without intervention of the embedded micro just seems right.

So there are a number of options when using this display 4 bit, 8 bit and SPI modes of communication

  • 4 bit mode will use 8 pins on the controller,.
  • 8 bit uses 12 pins.
  • SPI uses 4 pins.

There are I2C breakout boards that provide a I2C serial to parallel mode for these displays, which will use only 3 pins from the controller. SPI uses 3 but I have opted to add one extra pin to allow for a hardware rest line.

The SPI data that is sent to the display is write only and is made up of 24 bits of data, only 9 bits of data will change in any 24 bit data frame, RW bit (Read/Write) will always be write as there is no read capability in SPI mode. Only the RS bit (Command or Data) and the 4 Higher and 4 Lower bits of data are going to change in any data frame.

Diagram from Sitronix data sheet.

Untitled.png
page26image26865280
This got me to thinking that all I need is a shift register that I can load with 8 bits of data and one RS bit (Command Zero or Data one), all the other bits are constantly assigned to the relevant bits of a 24 bit serial shift register. Easy or Hard?
 
Cypress PSoC Creator has a 24 bit shift register already prebuilt. Just drag and drop it into a schematic job done, well not quite.The shift register has to be loaded each time with all 24 bits of data and I just want to be a tech and load 9 bits of data for each frame.
I am also thinking of using the display on a Xilinx FPGA board and the early chips do not come with a processor built in.

It’s time to build a custom component for my Cypress PSoC 5 development board.

I am going to learn enough Verilog HDL (High Level Description language) to get Cypress Creator Warp Verilog to synthesise the component for me. 

The component is going to need  CLOCKS 

  • An input clock
  • A data clock to drive the data out one bit at at time from the SID output
  • A SCLK output that is 90 degrees out of phase with the data stream so the display knows when to read the data.

The component is going to need  inputs.

  • 8 data inputs.

The component is also going to need outputs.

  • outputI SCLK output
  • 1 CS output

The component is also going to need control inputs and outputs

  • 1 Load control line.
  • 1 Run control line.
  • 1 Frame sent or ready to load control line.

Now this is looking like a lot of inputs and outputs, but the component being designing is in the PSoC chip and only has the SID, SCLK and CS outputs coming out of the physical pins of the PSoC 5 chip. 

Screen Shot of the component thats needed

Component.PNGNext thing to do is think about what we want to happen.

  • Take an input clock make two clocks in step with each other but 90 degrees out of phase, Not as difficult as you might think only 2 d flip flops and some inverters. Diagram from

  • The parallel load serial shifter element is needed but it’s going to be 24 bit long and not 8 bit as per the diagram taken fromTexas Instruments Data sheet.

Screenshot 2020-06-30 at 15.14.11There is a slight flaw in my decision to use Warp Verilog to make my component

Warp Verilog needs you to be conversant with writing Verilog already, you input the Verilog just as you might write a C file. The error messages when Warp copies are not very helpful Warp has no RTL diagrams or Schematic diagrams and no testbed feature.

I have hit this before and have found a way to use the old but excellent Xilinx FPGA’s ISE design suite to write Verilog instructions that can be cut and pasted in to the Creators Warp Verilog file. The reason I use ISE is that it has an embedded help which has snippets of code for just about every element that you will use in your Verilog code, which you can copy and paste. It also has a schematic capture option which is not quite as useful for what we are going to do.

ISE is a big programme and you need a fairly fast PC, however you are not working in the cloud. While learning you can keep recompiling as often as you need to get rid of all the syntax errors and logic errors you may have. Now half the learning cycle of Verilog or even (VHDL) is understanding the error messages during synthesis. Whats “SYNTHESIS” in my simple terms getting your text description of the circuits components and their timing interaction transferred into logic packages the the FPGA vendor can assemble in the undedicated logic on their chip. This is where the fun starts take the simple logic function that we will use in our component.

This will synthesise into the following schematics

Registerter-transfer level RTL schematic.

Technology schematic   

So this is what Xilinx would fabricate the circuit as.

Interestingly the Xilinx Technology design has got rid of the simple flip-flops and used a flip-flop with a clear and reset. Similarly when we use the Verilog description in the Creator WARP file then we are told that WARP will parse the Verilog description and utilise predefined components in WARP to generate our design.

Which is why I put a logic analyser on the outputs and inputs of a custom component so that I can see that the design performs as expected.

The Module used in a Creator Schematic design

Component diagram

The Verilog HDL that sits inside the component above

include “cypress.v”
//`#end` — edit above this line, do not edit this line
// Generated on 06/23/2020 at 12:10
// Component: component01

module component01 (
output reg C_S,
output  Ser_out,
output reg Slave_clock,
output reg T_i,
input   Clk_in,
input  [7:0] Data,
input  wire Load,
input   R_S,
input  wire Run
);
//`#start body` — edit after this line, do not edit this line

//        Your code goes here
reg [23:0] shifter;
assign Ser_out = shifter[23];// set this as the output buffer
reg running;
reg [4:0] count; //set up the incrimenting counter for counting bits shifted
//**************take clock in signal divide by 2 and generate two clocks shifted by 90 degrees************
reg a;
reg b;
     wire Clk_0; 
     assign Clk_0 = a;
     wire Clk_90;
     assign Clk_90 = b;

always @ (posedge Clk_in)
begin
a <=~a;
end

always @ (negedge Clk_in)
begin
         if(running == 1’b1)
         begin
    b <= ~b;
            Slave_clock <= Clk_90;
         end else
         begin
            Slave_clock <= 1’b0;
         end
end

//***************************************************** 

always @ (posedge Clk_0)
begin
if(Load == 1 )
begin
shifter[23:19]<=5’b11111;//low value to start in bit 24 followed by 5 framing ones
shifter[18]<=1’b0;
shifter[17]<=R_S;
shifter[16]<=1’b0;
shifter[15:12]<= Data[7:4];
shifter[11:8]<=4’b0000;
shifter[7:4]<= Data[3:0];
shifter[3:0]<=4’b0000;
T_i <=1’b0;
C_S <=1’b0;
count <=5’b00000;
running <=1’b0;//set slave clock off
end
else
if(Run == 1 )
begin
           if(count == 0)
           begin
                C_S <= 1’b1;// set Chip select high
                running <= 1’b1;//set up the reg to start Slave_clock //output(always(negedge Clk_in)statement
                T_i <= 1’b0;
                count <= count + 1;//increment count so this only act s once
           end
  if(count >= 1 & count <=23)
begin
shifter <= shifter <<1;// move bits to the right and out to  output with shifter[24} as Ser_out pin
count <= count +1;//keep a count of how many times shift happens
end
else if(count > 23)//sent all the serial bits
begin
C_S <=1’b0;//Chip select goes low
T_i <=1’b1;
running <= 1’b0;//set up the reg to stop Slave_clock output(always(posedge Clk_in)statement)
end
end

end
//`#end` — edit above this line, do not edit this line
endmodule
//`#start footer` — edit after this line, do not edit this line
//`#end` — edit above this line, do not edit this line

Had a bit of trouble adding a testbed so below is the screenshot for the the initialising  sequence for the display.CaptureAnd here is the screen shot of one 24 bit serial frame sent to the display.Capture 2

Now the H file of what will become the API for the module


#include <project.h>
#ifndef __ST7920_H__
#define __ST7920_H__

#include <stdbool.h>
#include <string.h>
#define ACTIVE 1
#define INACTIVE 0
#define COMMAND 0
#define DATA 1
#define RESET_ACTIVE 0
#define RESET_INACTIVE 1



void ST7920_hard_reset();
void ST7920_basic_instruction();
void ST7920_disply_clear();
void ST7920_command_data( uint8 command_data, uint8 c_d_byte);
void ST7920_write_character(uint8 line, uint8 position ,char character);
void ST7920_write_string(uint8 line, uint8 position ,char *string_out);

#endif

/* [] END OF FILE */

The C File that will become the API of the Module

#include <ST7920.h>

int modifyBit(int x, unsigned char position, bool newState)
{
int mask;
int state;

mask = 1 << position;
if (newState == 1) state = 1; else state = 0;// relies on true = 1 and false = 0
return (x & ~mask) | (-state & mask);
}

void ST7920_command_data( uint8 command_data, uint8 c_d_byte)
{

// bits 0load, 1run, 2R_S
//should cope with what ever clock is set for the serial component
uint16 command_delay = 1600;//longest delay used
// while(Shift_done_status_Read() == 0)
{
//do nothing a previous shift is in process
};
Disp_control_reg_Write(0b00000000);//shifting has stopped now, control reg value should hold component stopped
Data_reg_Write(c_d_byte);//set up the c-d_byte to send out
if (command_data == COMMAND)
{
Disp_control_reg_Write(0b00000001);//load with register select bit 2 as command 0
while(Shift_done_status_Read() != 0){}; // wait for the load to complete slow clock shown by Ti output on comonent going high
Disp_control_reg_Write(0b00000010);//run, register select dont care in run mode as loaded
if(c_d_byte == 0b00000010)
{
command_delay = 1600;//clear screen takes a long time
}
else
{
command_delay = 200;//most other commands
}
};
if (command_data == DATA)
{
Disp_control_reg_Write(0b00000101);//load with register select bit 2 as data 1
while(Shift_done_status_Read() != 0){}; // wait for the load to complete slow clock Ti of component going low
Disp_control_reg_Write(0b00000110);//run, register select dont care in run mode as loaded
command_delay = 50;//delay for data to be stored.
};
while(Shift_done_status_Read() == 0){};//do nothing until shift complets
CyDelayUs(command_delay);//delay for display processor to complete action

};
/*
void ST7920_data(uint8 data_byte)
{
// bits 0load, 1run, 2R_S
Disp_control_reg_Write(0b00000000);//should hold stopped
Data_reg_Write(data_byte);//set up the command byte to send out
Disp_control_reg_Write(0b00000101);//load with register select bit 2 as data 1
Disp_control_reg_Write(0b00000110);//run,RS x dont care register select in run mode as loaded
while (Shift_done_status_Read() == 0)//check to see when all serial data sent
{
};
CyDelayUs(2000);//delay for data to be stored.
};
*/
void ST7920_basic_instruction()
{
ST7920_command_data(COMMAND,0b00000110);//cursor moveto the right DDRAM address counter (AC) plus 1
ST7920_command_data(COMMAND,0b00001110);//Display on,cursor on,blink off
ST7920_command_data(COMMAND,0b00010100);//cursor mover right by 1 position
ST7920_command_data(COMMAND,0b00100000);//4bit bus (should be dont care basic instruction set
};

uint8 ST7920_set_DDRAM_address(uint8 line, uint8 position)
{
uint8 DDRAM_add =0;
switch(line)
{
case 0 : DDRAM_add = 0x80; break;
case 1 : DDRAM_add = 0x90; break;
case 2 : DDRAM_add = 0x88; break;//yes correct data sheet wrong
case 3 : DDRAM_add = 0x98; break;//yes correct data sheet wrong
};
DDRAM_add = DDRAM_add + (position / 2);
ST7920_command_data(COMMAND,DDRAM_add);
return(DDRAM_add);
};

void ST7920_write_character(uint8 line, uint8 position ,char character)
{
ST7920_set_DDRAM_address(line,position);
ST7920_command_data(DATA,character);

};

void ST7920_write_string(uint8 line, uint8 position ,char *string_out)
{
uint8 count = 0;
ST7920_set_DDRAM_address(line,position);
for(count = 0; count <= strlen(string_out); count ++)
{
ST7920_command_data(DATA,string_out[count]);
};
};

void ST7920_hard_reset()
{
RST_Write(0);
CyDelay(100);//wait
RST_Write(1);
CyDelay(200);//wait
ST7920_command_data(DATA,0b00000000);//reset the serial component to quiescent state dummy data send
ST7920_disply_clear();
};

void ST7920_disply_clear()
{
ST7920_command_data(COMMAND,0b00000001);//display clear
};


/* [] END OF FILE */

I have just started on the basic C functions to support the graphic display and this will have a 5*7 ascii font.So given the Covid19 keeps me indoors there should be some more code added to this blog along with basic lines squares and circles, which actually means adapting previous code for a SSD1331 display. So I will try not to keep you waiting too long.

Getting text to format in the correct position on a line

Text should be easy to send except that the display has really been set up to display Chinese characters which are 16 x 16 character fonts, but will display two 16 * 8 ascii characters which means there are only 8 write locations in a 16 character line.

I took the easy way out to handle formatting a line of text, especially as you can not read memory from the display in serial mode. I am using four arrays of 16 char elements to represent line0 ,1 ,2 ,3 of the text display. On each edit of a line I edit the Array, to position the characters being sent and then just send the whole line array to the display. This way I can edit numbers theatre scaling up and down without affecting the text in the line. Oh there was a “got yer ” in the data sheets memory map for text line start address which I have itemised in the software driver for outputting text. Which is why I have been so slow in putting a video of the text in the blog.

ST7920 Graphics addressing is wierd.

THE GAMES AFOOT.

AS for graphics yet again this has driven me to distraction, as the data sheet is not that clear how the blocks of 16pixels are stored to the screen.

It turns out that the display only has a Vertical Y address of 32 lines and the Horizontal X address is 8 blocks of 16 bits for the upper half of the display. For the lower half you need the Vertical Y (0-63 lines) as modulo of 32 and then add 8 to the Horizontal X address blocks of 16bits.

along the way the MSB needs to be the LSB in the 16 bits of a block. I will include the hack of my code for the graphics and text tomorrow with a video of it in action.

I very nearly have enough of this working now to go onto my next part of the project which is the next blog


CYPRESS PSoC 4 controlling an HD44780 LCD display via I2C Port extender

https://plus.google.com/u/0/100845918259366165719/posts/eebbwZDWRiM?pid=6135734277326915362&oid=100845918259366165719

Ok so this is the code that I use to run an I2C AD8574 8 bit expansion port with an HD44780 LCD 4 line by 20 character display. all this is driven by a standard Cypress PSoC 4 development board link to video of this working on an earlier version of code

The following C code is free to all to use but I take no responsibility for how it works on your equipment.

I will however talk about what I have done to the point of boredom.

Have fun the C code below is compiled from a huge amount of information on the web most reasons for the displays not working is not providing a long enough wait state between commands and the strange way the display memory is addressed.

 

/* ========================================
*
* Copyright Crusty Consultants, 12/11/2015
* All Rights Reserved
* PUBLISHED, Free to use and abuse SOFTWARE.
*
* If it does not work then it’s not my fault
* I will explain what I have done if any one interested.
* This is part of a bigger works in progress to make solid state disk drives for older computers
* hence the comment about BBC B disc drive
* ========================================
*/
#include <project.h>
#include <stdbool.h>
#include <stdio.h>
uint8 const SlaveAdd8574   = 0x20;
uint8 const SlaveAdd8574A  = 0x70;//probably wrong
uint8 const HD44780I2C = 0x27;
uint8 const DisplayWidth = 20;
uint8 SlaveAdd;

bool Instruction = false; //low instruction input
bool Data = true; // Hi Data input
bool Write = false;// R/W low Write
bool Read = true;// R/W  hi Read
bool E_Inactive = false;// Enable low not enabled
bool E_Active = true;// Enable  hi Enabled
bool BL_On = true;
bool BL_Off = false;
bool Track_Changed = false;
uint8 const R_S = 0;
uint8 const R_W = 1;
uint8 const E   = 2;
uint8 const BL  = 3;
uint8 const StepDir = 1;//bit 1
uint8 const StepPulse = 0;//bit 0
uint8 const Line0 = 0x00;
uint8 const Line1 = 0x40;
uint8 const Line2 = 0x14;
uint8 const Line3 = 0x54;
uint8 BackLight;
uint8 Track_Count;

uint8 SetBitState8(uint8 SourceVal, uint8 BitPos,bool BitStateReq );
void Write_Port(uint8 OutVal);
void Write_LCD(uint8 Register,uint8 SendNibble);
void Enable_4bit();
void WriteMessage(char Message[]);
void SetLCDLine(uint8 LineNo, uint8 CursorPosition, bool ClearLine);
CY_ISR(Seek_Step_Int);
int main()
{
/* Place your initialization/startup code here (e.g. MyInst_Start()) */
BackLight = BL_On;
SlaveAdd = HD44780I2C;
I2C_Port_Start();
Step_Counter_Start();
Index_Pulse_Start();
char msg[] = “BBC B Disk Emulator”;
Enable_4bit();
WriteMessage(msg);
CyGlobalIntEnable;  /* Uncomment this line to enable global interrupts. */
for(;;)
{
/* Place your application code here. */

};
};
void WriteMessage(char Message[])
{
uint8 HiNibble;
uint8 LoNibble;
uint8 count = 0;
while (Message[count] != 0)
{
HiNibble = Message[count] >> 4;
LoNibble = Message[count] & 0x0F;
Write_LCD(Data,HiNibble);
Write_LCD(Data,LoNibble);
count++;
};
};
void Write_Port(uint8 OutVal)
{
if (BackLight == BL_On)OutVal= SetBitState8(OutVal,BL,BL_On);
I2C_Port_I2CMasterSendStart(SlaveAdd,I2C_Port_I2C_WRITE_XFER_MODE);
I2C_Port_I2CMasterWriteByte(OutVal);
I2C_Port_I2CMasterSendStop();
};

void Write_LCD(uint8 Register,uint8 SendNibble)
{
uint8 ByteToSend = 0;

ByteToSend= SetBitState8(ByteToSend,R_S,Register);//set bit for instruction
ByteToSend= SetBitState8(ByteToSend,R_W,Write);//set bit for write
ByteToSend= ByteToSend | ( SendNibble << 4); // store the nibble to the higher 4 bits and send
Write_Port(ByteToSend);// send without enable to stabalise the port bits
CyDelayUs(10);// let tit stabalise
ByteToSend= SetBitState8(ByteToSend,E,E_Active);//set the enable bit
Write_Port(ByteToSend);;//send the enable
CyDelayUs(10);
ByteToSend= SetBitState8(ByteToSend,E,E_Inactive);//clear the enable bit
Write_Port(ByteToSend);// send the dissable
CyDelayUs(10);

};
void SetLCDLine(uint8 LineNo, uint8 CursorPosition, bool ClearLine)//sets line to 0 to 3 ie 1 to 4
{
uint8 loop;
uint8 HiNibble = 0;
uint8 LoNibble = 0;
uint8 DDRAM = 0x80;// command value for moving cursor in display ram
switch (LineNo)
{
case 0 : DDRAM = DDRAM | Line0;// or first byte of line 0
break;
case 1 : DDRAM = DDRAM | Line1;// or first byte of line 1
break;
case 2 : DDRAM = DDRAM | Line2;// or first byte of line 2
break;
case 3 : DDRAM = DDRAM | Line3;// or first byte of line 3
break;
};
DDRAM = DDRAM + CursorPosition;// add where the cursor should be on line 0- 19
HiNibble = DDRAM  >> 4;
LoNibble = DDRAM & 0x0F;
Write_LCD(Instruction,HiNibble);//
CyDelay(10);
Write_LCD(Instruction,LoNibble);
CyDelay(10);
if (ClearLine == true)
{
for (loop = CursorPosition; loop <=( DisplayWidth – CursorPosition-1) ; loop++)
{
WriteMessage(” “);
}
Write_LCD(Instruction,HiNibble);//Put the cursor back where we want it again
CyDelay(10);
Write_LCD(Instruction,LoNibble);
CyDelay(10);
};
};

uint8 SetBitState8(uint8 SourceVal, uint8 BitPos,bool BitStateReq )
{
if (BitStateReq == true)//want to set the bit at location
{
SourceVal |= 1 << BitPos;
return SourceVal;
};
//not setting so want to clear the bit at bit  location
SourceVal &= ~(1 << BitPos );// want to clear the bit
return SourceVal;

};

void Enable_4bit()
{
CyDelay(20);//first delay on reset or power on
Write_LCD(Instruction,0x03);
CyDelay(5);
Write_LCD(Instruction,0x03);
CyDelay(160);
Write_LCD(Instruction,0x03);
CyDelay(160);
Write_LCD(Instruction,0x02);//enable 4 bit mode
CyDelay(5);
/*function set*/
Write_LCD(Instruction,0x02);
CyDelay(10);
Write_LCD(Instruction,0x08);
CyDelay(10);
/*display off */
Write_LCD(Instruction,0x00);
CyDelay(10);
Write_LCD(Instruction,0x08);
CyDelay(10);
/*display on*/
Write_LCD(Instruction,0x00);
CyDelay(10);
Write_LCD(Instruction,0x0F);
CyDelay(10);
/*Entry Mode*/
Write_LCD(Instruction,0x00);
CyDelay(10);
Write_LCD(Instruction,0x06);
CyDelay(10);
/*clear screen*/
Write_LCD(Instruction,0x00);
CyDelay(10);
Write_LCD(Instruction,0x01);
CyDelay(100);
/*cursor home*/
Write_LCD(Instruction,0x00);
CyDelay(10);
Write_LCD(Instruction,0x02);
CyDelay(100);
};
CY_ISR(Seek_Step_Int)
{
Track_Count = Step_Counter_ReadCapture();
Track_Changed = true;
};

/* [] END OF FILE */

Water saving alarm, stop hose blow outs in hot weather.

Image

The Blogs Aim

Its 30 degrees Centigrade in the back yard and the pot grown beans and tomatoes and cucumbers get mighty thirsty.
Whilst we are not covered by the drought order in sunny Emsworth on the Hampshire coast, I do not like wasting water or carting the watering can around each night and morning.

So we have invested in a Hozelock drip irrigation system on a tap timer, we have used these systems at another house we lived in and they work well.
However they do suffer from a propensity of the feed hose from the tap becoming detached from the hose connection to the drip feed system.
This never happens with any warning sign and usually dumps great quantities of precious water in a place that does no good (floods of biblical proportions have occurred in the past).

Well it happened last week again and enough is enough.
Technology to the rescue but on the cheap.
Got a lovely second hand BRITA water flow meter on E-bay with a pulse output for every 10L flow through it.
This has been plumbed hard onto the garden tap thread, so I now have a pulse for every 10L flowing (pulse is a passive momentary contact).
Now comes the technology:- feed the pulse to a micro processor I/O input and write an algorithm to
1) Build up a profile for flow with the drip feed running or the hose in use.
2) Tune the algorithm to raise an alarm when the flow is to high for too long.

As I might be away when the next flood occurs I want to be able to turn off the water flow.
So the alarm has to be fed into a stop down valve.
Here is the rub motorised battery powered stop valves cost an arm and a leg and low voltage flow solenoids take to much current to be battery operated. (Unless some one knows different).
However I have a way around this tap timers now sold for garden irrigation (and the cause of my problem) have come down to sub £20 in value.
These are very nifty bits of mechanical and plumbing engineering working on a couple of 1.5 volt cells, they have a purpose built rotating ball valve controlling the flow and it only draws current when opening or closing.
I seem unable to find this valve assembly from an original equipment supply (first time China and India have let me down), however good old e-bay has sourced a cheap tap timer (probably made in Hong Kong under license).
This is going to be hacked when it arrives and connect to the water flowing alarm.

Will it all work?
Keep looking as I post the ups and downs of my mad idea.

“There’s a lot more goodies in the pipe line” to quote 10CC and now the electronics den is back together I hope to be posting and updating my blogs more regularly.

Proof of concept.

Been a bit slow with this update, which is mainly down to having to finish decorating the stairs to the bedrooms which allow access to my attic electronics workroom.

However much has been going wrong and right while the decorating took place.

Royal Mail has delivered my garden water timer purchased from E-Bay, nice unit seems a shame to start to dismantle it, but we must boldly go were others fear to tread.

Hose timer as sold on EBay

First remove the grey battery case, this reveals two case screws, which can be removed with a long thin Philips head screw driver. However the top of the case will not budge. The green plastic must be cut at the top to reveal the third and final Philips screw.

Three screws later and the water timer is partially deconstructed

Three screws removed shows the connections to the battery pack 2AA cells meaning the unit will run from 3 volts down to about 2. 5 Volts. The little motor and gear box flip the valve open and closed. The Green PCB hides a microprocessor and rotary position switches which control the motor through a discrete  six transistor H-Bridge motor control.

Close up of valve and motor actuator

Close up of the lower housing with motor (black lump).  The top white gear driven from the cog on the motor spindle turns through 180 degrees of rotation, before hitting a stop at the end of travell. It appears that the motor is pulsed for a small time sufficient to rotate the white main gear from one stop to the other but short enough that when the motor is stalled at the end of travell that the curent drawn in stall does not burn out anything.

Hacking the electronics for a proof of concept

This picture shows the other side of the PCB with the minute switch removed. Desoldering the switch is not a task for a beginner and the desoldering iron is heavily used to achieve this state. Well worth the effort as I am now able to connect in turn the on and off switch pads to the negative and positive power rails and activate the motor to open and close the valve at my command.

Now I have got this far the thought of trying to tack my Atmel ATtiny85 processor onto the existing PCB seems to be an ugly patch too far, especially as I have started to think that this valve unit can be adapted to a greenhouse misting system, by adding a humidity sensor and changing some code in the processor.

So what next build a new circuit.

Now I hate to design and build a PCB at concept stage and over the years I have found a simple set of programmes that allow me to breadboard a circuit on Vero Board (strip board). I started my commercial electronics carrer using Vero Board so I am happy working with it.  However a lot of time a heartache can be saved using veeCad this is like a PCB layout programme for stripboard and works well with TinyCad schematic drawing programme.

Things had gone well up to this point.

I have long ago gravitated to Mac OSX as it is very resilient and almost virus free, but still the majority of electronics type programmes are Windows based.

So I started up my Vaio widows laptop and found that everything had been updated since I  last used Windows, veeCad and TinyCad, so wait for the downloads and essential reboots.

Strange as it may seem I know about H-Bridges for controling a motor but have never used an H-Bridge chip or built a descrete transistor H-Bridge. After a couple of hours of browsing the net I have the descrete transistor bridge design I want (http//library.solarbotics.net/circuits/driver_tilden.html).

This is when the air turns blue.

Well not the air but me.

With my move from London to rural Hampshire (England) refurbishing our tired 1963 chalet bungalow has taken close on 18 months and left little time for electronics. As a result it has been close on two years since I used the two bits of software quoted above, honestly put I had forgotten that a three legged transistor can be assigned 1,2 or 3 for its legs so of course when I used the programme to draw the electronic schematic I forgot to check that the Veroboard layout might have assigned different numbers to the transistor legs. I nearly always lay up the links on the Veroboard first before inserting the components, so it was an hours work before I fitted the first two transistors and realised at this point they were not orientated the right way. So I had to dive into the two software packages and put their pin structures right. So start again with a new bit of board and a whole new set of links.

Having cut all the copper tracks in the right place and soldered in all the links and the components (except the microprocessor chip) it’s now time to connect the circuit up to the lab bench power supply. These are a boon as you can set the voltage required to run the circuit but with minimal current set. By doing this it is usually possible to slowly turn up the current supply to the circuit and check to see if an abnormal amount of current is flowing, which usually means a short or a bad positioning of a link. Alls well the current stabalises at almost nothing. Now we can connect the motor to the bridge outputs and to my great glee no current flowing. Next a very crude technique in the prototype test arsenal take a wire and touch it to one of the inputs of the H-Bridge and the positive supply very briefly. Oh what joy motor turns gear wheel with a resounding clonk as it hits the end stop. Using the wire on the other input to the H-Bridge causes the motor to turn with a very satisfying clonk in the other direction.

We are on our way.

Fabrication bench in attic workshop

The fabrication bench in a state that is tidy!!, like cooking the bench has to be cleaned down before testing begins ranged on the right are a digital and analogue oscilloscope and the bench power supply.

The multimeter in the tray is cheap and disposable. I can connect it up badly during testing and loss is minimal cost.

Prototype H-Bridge control with Atmel ATTiny85 chip in place

Test unit with plumbing connectors assembled

Test circuit may look a little ragged but I only need it to prove that the concept design will work. The grey connector on the right is for programming the chip in the center. White and mauve leads go to the motor on the valve and the red and black to the bench power supply set at 2.7 volts to test everything will work on 2 AA cells that are well discharged.

A look at the plumbing the brass female socket on the left was difficult to find as I kept looking for a coupler and not a socket, once the syntax was correct any number were available the middle connection is made with a male to male hydraulics coupler. all fittings are 3/4 inch BSP (British Standard Pipe).

On test last night and I had the motor cycling back and forth under the control of processor surprisingly the motor is only being activated for  50 microseconds to get it to travel to the end stop in each direction. Have not measured the instantaneous current but bench supply shows around 68 milliamps drawn, this is such a short duration the batteries should last a long time. Standby current is about 3 milliamps and I should be able to get this down to a few microamps by putting the microprocessor to sleep for most of the time.

Hydraulic testing will now have to wait while I have a few days doing some new jobs that have become critical in the bungalow.

However I can now start to work on the final pretty PCB that most people now associate with commercial electronics. I like the idea of the two rotary switches for setting up the water alarm cut off parameters. One will set the flow rate say 10 liters to some other higher figure of liters, the other will set the amount of time in minutes that the set flow can run for, 10 minutes to some higher minute figure. Both switches will have ten stages.

Would it be worth having a display? The next prototype will so I can get debugging information . As I am using a water meter as the flow meter this has the total water consumed, but if I integrate a black box electronic flow meter into the final design then total flow would not be known. Who would the users be? If this went to market in today’s water shortage and water price hikes I suspect most buyers would like total water usage information.

Comment so far are welcomed and if you have extra ideas I will try to combine them.

So long for now.