Generating a clock signal

thos_thom

New Member
I'm new to the picaxe scene (new to electronics in general) and I'm working on getting a little LCD to work with an 08m. I seem to have most of the code working (save for that I've completely run out of space to do anything useful with it) but I have one last problem.

The LCD requires a 50khz clock signal continuously to refresh the screen. My code ignores this and bit bangs the data to initialize and put something on the screen, then i "setfreq m8" and switch into a loop of
"pulsout" as fast as i can.

This refreshes the screen enough for me to be able to see my graphics to know the code works but it looks really bad.

Is there another way I could generate a faster clock?

Thanks,
Thom.
 

Technical

Technical Support
Staff member
Look up the pwmout command. On the 08M you can set this to provide background pulses whilst the PICAXE does other things.

pwmout 2,19,40

will give you 50kHz. Note you must use output 2, as this is the hardware pin with the pwmout function.
 

thos_thom

New Member
I have tried the pwmout command but I couldn't get it to work.
I'm not sure if I was doing it wrong or if my hardware was at fault.

Could it have something to do with the fact that pin2 would also have been connected to pint 1, the pin I was using as the clock for bit banging the data?
 

D n T

Senior Member
With regard to a clock signal

I want to get my 28X1 to read a sensor every 2 seconds can i use a PWM command to trigger an input and after x amount of triggers the sensor is read, or is there an easier way?
I need a regular sensing time so I can figure out the average amp consumption over a given period of time.
Help?
 

BeanieBots

Moderator
The 28X1 has an internal timer which can trigger interrupts.
However, if you want to measure average current over time without the worry about missing peaks, aliasing effects and all other manner of issues. Then have a look at how my "Battery Capacity Meter" works in the Misc Projects section. It uses a good old fashioned analog integrator which can be reset by the PICAXE.
 

hippy

Technical Support
Staff member
I have tried the pwmout command but I couldn't get it to work.
I'm not sure if I was doing it wrong or if my hardware was at fault.

Could it have something to do with the fact that pin2 would also have been connected to pint 1, the pin I was using as the clock for bit banging the data?
Quite probably. Pin 1 should now drive only the LCD data pin, and Pin 2 (PWM) should now drive only the LCD clock pin. There should be no physical connection between Pin 1 and Pin 2 of the PICAXE.
 

thos_thom

New Member
Quite probably. Pin 1 should now drive only the LCD data pin, and Pin 2 (PWM) should now drive only the LCD clock pin. There should be no physical connection between Pin 1 and Pin 2 of the PICAXE.
I'm sorry, perhaps I was not clear, for this LCD, the screen refresh clock signal is also used to synchronize the data transfer.

Is there a way of using the pwm to synchronize the data output? If not then I think I need both.

That is to say I need to use pin1 as a clock for the bit banging and once the data transfer is done, switch to use pin2 as the clock to refresh the screen at the correct speed for viewing.

How would I disconnect the bit-bang clock to ensure the pwm clock was received?
 

hippy

Technical Support
Staff member
You can turn PWM on and off under program control, so when outputting your data you would do what you were doing with Pin 1 but now on Pin 2 with PWM turned off. When you come to display you would turn on PWM which effectively does your PULSOUT loop of its own accord. When you need to update the display, turn PWM off, and then put the data out using Pin2 under your own control. When done, turn PWM on again.

Synchronising to a 50kHz signal ( 20uS period ) would be near impossible for a PICAXE, so I cannot see any other way to do it.

Do you have a link to a datasheet for this LCD so we can get a better understanding of how it works and what needs to be done ? There may be other techniques you could use.
 

thos_thom

New Member
You can turn PWM on and off under program control, so when outputting your data you would do what you were doing with Pin 1 but now on Pin 2 with PWM turned off. When you come to display you would turn on PWM which effectively does your PULSOUT loop of its own accord. When you need to update the display, turn PWM off, and then put the data out using Pin2 under your own control. When done, turn PWM on again.
Gah, use pin 2 as an output for both clocks :eek: why did I not think of that. That will probably be the solution I am looking for. I will give that a try tonight.

The data sheet for the device I'm using is here.

It is a screen/key combo with RGB LED back lighting.

I have code already for initializing the screen, sending commands to turn the back light on to various colours and sending bitmap data to display. I would be happy to share the code if anyone is interested.
 

inglewoodpete

Senior Member
An interesting device. I've googled it, hoping to get an idea of the unit price but no luck. Can I ask what you paid for the ScreenKey?
 

thos_thom

New Member
Using pin2 as both clocks works like a charm, the screen is displaying all crisp and beautiful. Thanks for all your help everyone! :D

I've added some code to write characters to the screen but its not quite right and I've run out of space on the 08m with just one character's worth of data. The code alone is 250ish bytes. I'm going to upgrade to that 18x I have and get some graphics on this thing.

An interesting device. I've googled it, hoping to get an idea of the unit price but no luck. Can I ask what you paid for the ScreenKey?
I got mine (RGB) for 20 euro a piece, which is a little steep but they do RG versions for 15, I think. I just sent them an email.

Just remember that this device only does bitmap graphics with four and a half bytes per line (writing whole bytes at a time) so it is a little tricky to work with. Also at 8mhz it takes a couple of seconds to bit bang a screens worth of data and the setup commands and while this happens because of the low clock speeds involved the screen looks really crazy. It is possible to address smaller contiguous sections of the screen but it isn't really possible to change the image fast enough for anyone not to notice.

This is not a criticism of the device, its just that it was not really intended for these low speeds.
 

hippy

Technical Support
Staff member
Possibly worth considering the 28X1, as that has twice the program memory capacity of the 18X and can run faster as well.
 

inglewoodpete

Senior Member
If you'd like to post your code (use the code tags), forum members may be able to give you some pointers in making it more compact.

I'm not promising anything but we may be able to help (you may be a better PICAXE programmer than many of us!) The longer term solution may be a bigger processor, but we love a challenge.
 

thos_thom

New Member
If you'd like to post your code (use the code tags), forum members may be able to give you some pointers in making it more compact.

I'm not promising anything but we may be able to help (you may be a better PICAXE programmer than many of us!) The longer term solution may be a bigger processor, but we love a challenge.
Sounds good, I haven't used basic since I was a child :eek: I'm sure it is a little more verbose that it should be and I'm never one to turn down programming tips ;)

Will get the code posted up this weekend.
 

thos_thom

New Member
Here it is, finally. Thank you all for your input. This is the first thing I have written asside from a flashing led so please be kind.

Code:
'start and end byte codes
symbol start   = 0x00
symbol finish  = 0xAA

'index of each command and its data
symbol start_red = 0
symbol end_red = 1
symbol start_freq = 2
symbol end_freq = 4
symbol start_mux = 5
symbol end_mux = 7
symbol char_start = 8
symbol colour = 0x23 'pink! or try 1 as blue or 2 as red!

'data: see above for index into this array
data 0,(0xed,colour,0xEF, 0x07, 0x00,0xEE, 0x00)

' character data, can only fit one character (0) would be more,
data char_start,(%01100110,%01111110,%01111110,%01111110,%01111110,%01100110,%01000010,%00000000)

'custom symbols for getting parity and
'stop bits for data, also memory addresses
'for parameters
symbol set_parity = b4
symbol parity = b5
symbol var_proc = w5
symbol block_loop = b6

' i use these locations to store
' params for the routines as some of them
' are nested and need variables
symbol from_range = $50
symbol to_range = $51
symbol line_number = $54
symbol line_lower_byte = $55
symbol line_uppet_byte = $56
symbol bytes_per_line = 27

'symbols for shift out
symbol sclk = 2 ‘ clock (output pin)
symbol sdata = 0 ‘ data (output pin for shiftout)
symbol counter = b7 ‘ variable used during loop
symbol mask = w4 ‘ bit masking variable
symbol var_out = w6 ‘ data variable used during shiftout
symbol bits = 12 ‘ number of bits - two stop bits, one parity bit, and eight data bits, one start bit
symbol MSBvalue = 128 ‘ MSBvalue


' **main!**
' main method, will set up internal variables and set
' the background colour to whatever colour is set to up above

main:	
	pause 3000
	setfreq m8
	
'set up freqency variables
	poke from_range,	start_freq
	poke to_range,	end_freq
	gosub sub_block
	
'set up mux variable
	poke from_range,	start_mux
	poke to_range,	end_mux
	gosub sub_block

'set colour to red
	poke from_range,	start_red
	poke to_range,	end_red
	gosub sub_block

'print out some characters
	
	poke line_number, 0
	poke line_lower_byte, 0
	gosub draw_line
	
	poke line_number, 1
	poke line_lower_byte, 1
	gosub draw_line
	
	poke line_number, 2
	poke line_lower_byte, 0
	gosub draw_line

' this draws the fourth line on the screen
' had to take this out to get the one character (0)
' in memory
'
'	poke line_number, 3
'	poke line_lower_byte, 1
'	gosub draw_line
	
	
	
'make screen refresh as fast as possible

	pwmout 2 , 39, 80

	clock:
	'pulsout sclk,1 ‘ pulse clock for 5us (m8 mode)
	goto clock


' **sub_block**
' writes out start and end bytes and will write out
' bytes from the eeprom based upon values
' from_range and to_range
'
' say 'from' is set to 10 and 'to' is set to 12
' it will write out bytes 10 11 12 from eeprom
' wrapped in start and end bytes with correct parity

sub_block:

	gosub sub_start'start byte
	peek from_range, b0'get params
	peek to_range, b1
	set_parity = 1'set parity
	for block_loop = b0 to b1
	   read block_loop, var_out
	   gosub out
	next block_loop
	gosub sub_finish'end byte
	
	return



' **draw_line**
' draws a character onto the screen
' based upon a word in storage - THIS IS BROKEN
' i ran out of space to make it work

draw_line:

	gosub sub_start
	peek line_number, b0
	b1 = bytes_per_line * b0
	var_out = 0x80 + b1
	set_parity = 1
	gosub out
	for b0 = 1 to 27
	   peek line_lower_byte, b2
	   b2 = b2 * 8
	   b1 = b0 % 5
	   b2 = b2 + b1
	   b2 = b2  + char_start
	   read b2, var_out
	   gosub out
	next b0
	gosub sub_finish
	
	return



' **sub_start**
' **sub_finish**
' will send start/end byte with correct parrity
' small optimisation here, shared code, bit messy
sub_start:
	var_out = start
	goto _sub_out
sub_finish:
	var_out = finish
_sub_out:
	set_parity = 0
	gosub out
	return

'**out**
'shift out lsb first
out:
' will turn a byte into a 12 bit word with 2 stop bits and parity
' parity will be based on set_parity
	parity = 0
	var_proc = var_out
	for counter = 1 to 8
	   mask = var_proc & 1 ‘ mask LSB
	   parity = parity ^ mask
	   var_proc = var_proc / 2 ‘ shift variable right for LSB
	next counter
	parity = parity ^ set_parity
	var_proc = parity * 512
	var_out = var_out*2
	var_out = 0x0C00 | var_out
	var_out = var_out | var_proc	
'actually do the shifting out
	for counter = 1 to bits ‘ number of bits
	   mask = var_out & 1 ‘ mask LSB
	   low sdata ‘ data low
	   if mask = 0 then skipLSB
	   high sdata ‘ data high
	   skipLSB: pulsout sclk,1 ‘ pulse clock for 10us
	   var_out = var_out / 2 ‘ shift variable right for LSB
	next counter
	
	return
I am going to 'port' this to an 18x so I can use the display to show the time
from an i2c real time clock.
 

hippy

Technical Support
Staff member
The code doesn't seem that bad. There are some optimisations which can be had but not that many without studying your code in more detail. The following changes reduce the code from 247 bytes to 226, saving 21 bytes, 8.5%. Not a great saving but sometimes it's just enough.

My rule of thumb is that it's unusual to recover more than a 10% without going for a code redesign from the ground up.

Note the changes haven't been tested. Keep a backup of original. Add a change at a time, check it works.

================================================

Maths compression ...

- peek line_lower_byte, b2
- b2 = b2 * 8
- b1 = b0 % 5
- b2 = b2 + b1
- b2 = b2 + char_start

+ peek line_lower_byte, b2
+ b1 = b0 % 5
+ b2 = b2 * 8 + b1 + char_start

================================================

Redundant Gosub/Return Removal ...

- gosub sub_finish
- return

+ goto sub_finish

================================================

Code re-ordering and redundant Gosub Removal; fall through one routine into
the next ...

- next b0
- gosub sub_finish
- return
-
- sub_start:
- var_out = start
- goto _sub_out
- sub_finish:
- var_out = finish
- sub_out:
- set_parity = 0
- gosub out
- return
-
- out:

+ next b0
+
+ sub_finish:
+ var_out = finish
+ goto _sub_out
+ sub_start:
+ var_out = start
+ sub_out:
+ set_parity = 0
+
+ out:

================================================

Keep numbers as small as possible ...

- for counter = 1 to 8

+ for counter = 0 to 7

================================================

Maths compression ...

- var_proc = parity * 512
- var_out = var_out*2
- var_out = 0x0C00 | var_out
- var_out = var_out | var_proc

+ var_proc = parity * 512
+ var_out = var_out * 2 | 0x0C00 | var_proc
 

thos_thom

New Member
The code doesn't seem that bad. There are some optimisations which can be had but not that many without studying your code in more detail. The following changes reduce the code from 247 bytes to 226, saving 21 bytes, 8.5%. Not a great saving but sometimes it's just enough.
Thanks for taking a look. I was not aware that I could do compound operations such as:

Code:
 b2 = b2 * 8 + b1 + char_start
Which is why I was doing things a line at a time. I'm sure I tried and got syntax errors. Are there operators that can't be used in compound operations?

I will have a go with these ideas and see if i can get characters out on this screen from an 08m before moving to an 18x.
 

hippy

Technical Support
Staff member
All maths operators can be used in compound assignments, but remember the operations are strictly left to right and there are no parentheseis for setting precedence ...

- b0 = 1 + 2 * 3

Will give 6, "(1+2)*3" not 7, "1+(2*3)"

- b0 = 1 * 100 + 2 * 10 + 3

Will give 1023, "(((1*100)+2)*10)+3", not 123, "(1*100)+(2*10)+3"
 

thos_thom

New Member
All maths operators can be used in compound assignments, but remember the operations are strictly left to right and there are no parentheseis for setting precedence ...

- b0 = 1 + 2 * 3

Will give 6, "(1+2)*3" not 7, "1+(2*3)"

- b0 = 1 * 100 + 2 * 10 + 3

Will give 1023, "(((1*100)+2)*10)+3", not 123, "(1*100)+(2*10)+3"
This will be why I got errors then. I will have been using parenthesis. Thanks for the info I will use this wisely.
 
Top