Converting Bresenham's line plotting algorithm

hippy

Technical Support
Staff member
Strange for px=x1 to x2 step-1 works but for px=x2 to x1 doesn't.
Not that strange; the two are not equivalent. As 'x1' is larger than 'x2', the first will decrement from the highest to lowest, the second will increment from lowest to highest -

Code:
Symbol x1 = b0
Symbol x2 = b1
Symbol px = b3

x1 = 99
x2 = 90

For px = x1 To x2 step -1
  SerTxd( #px, " " )
Next
SerTxd( CR, LF )

For px = x2 To x1 
  SerTxd( #px, " " )
Next
SerTxd( CR, LF )
 

AllyCat

Senior Member
Hi,

Improvement to be measured with real Picaxe...
I did back in #32. It's around 250us @ 4MHz; about the same as changing from a DO loop to FOR..NEXT (if it worked with negative steps).

I think the code could be speeded further by combining the "exit" condition into the DO loop. I believe that could save around 800 us per pass, but the lines of code need to be rearranged somewhat.

I haven't tested it but "STEP $FFFF" will probably decrease the index variable by one, be the equivalent of "STEP -1".
No I don't think it does (because the compiler is actually looking for a "-"), but it's complicated because the real (20M2) chip and the simulator behave differently (and the latter inconsistently). I tested this code:

Code:
#no_data
for w1 = 8 to 5 step $ffff
sertxd(" ",#w1)
pause 500
next
sertxd(" end")
The real chip produced "8 end" and the simulator 8 8 8 8 .... . :eek:
Changing the $ffff to -1 and both then worked as expected. (8 7 6 5 end) .
BUT changing back to $ffff and then the simulator (still) produced 8 7 6 5 end . :confused:

Restarting the PE (nice and quick as I'm still using PE5) and the simulator again produced the 8 8 8 8 8.... :p

EDIT: OK, it was time for a coffee so I fired up PE6 while the ketttle was boiling. The PE6 simulator appears to work like a "real" chip (i.e. step $ffff terminates after a single pass if start > end).

Cheers, Alan.
 
Last edited:

hippy

Technical Support
Staff member
Restarting the PE (nice and quick as I'm still using PE5) and the simulator again produced the 8 8 8 8 8.... :p
That might well be a bug of PE5. PE6 does as expected, replicates the chip's behaviour and only produces a single "8".

So, no "Step $FFFF" is not the same as "Step -1".
 

stan74

Senior Member
Here is all the code BESQUEUT, Too large for copying for forum. Quite an interesting display.SAM_1285.JPG
#picaxe 28x2
setfreq m16
symbol maxpos = $7fff
symbol x1=b0
symbol x2=b1
symbol y1=b2
symbol y2=b3
symbol px=b4
symbol py=b5
symbol nt=b6
symbol yrow=b7
symbol bitpos=b8
symbol screenbit=b9
symbol temp1=b10
symbol temp2=b11
symbol sx=b12
symbol sy=b13
symbol dx=w8
symbol dy=w9
symbol er=w10
symbol tempvar1=w11
symbol tempvar2=w12
symbol e2=w13

;
SYMBOL DispNum = W12
SYMBOL row = b25
SYMBOL col = b26
SYMBOL temp = b27
SYMBOL aByte = b28
SYMBOL index = b29


SYMBOL TWI_BUFFER_LENGTH = 32
SYMBOL SSD1306_LCDWIDTH = 128
SYMBOL SSD1306_LCDHEIGHT = 64
SYMBOL SSD1306_SETCONTRAST =0x81
SYMBOL SSD1306_DISPLAYALLON_RESUME =0xA4
SYMBOL SSD1306_DISPLAYALLON =0xA5
SYMBOL SSD1306_NORMALDISPLAY =0xA6
SYMBOL SSD1306_INVERTDISPLAY =0xA7
SYMBOL SSD1306_DISPLAYOFF =0xAE
SYMBOL SSD1306_DISPLAYON =0xAF
SYMBOL SSD1306_SETDISPLAYOFFSET =0xD3
SYMBOL SSD1306_SETCOMPINS =0xDA
SYMBOL SSD1306_SETVCOMDETECT =0xDB
SYMBOL SSD1306_SETDISPLAYCLOCKDIV =0xD5
SYMBOL SSD1306_SETPRECHARGE =0xD9
SYMBOL SSD1306_SETMULTIPLEX =0xA8
SYMBOL SSD1306_SETLOWCOLUMN =0x00
SYMBOL SSD1306_SETHIGHCOLUMN =0x10
SYMBOL SSD1306_SETSTARTLINE =0x40
SYMBOL SSD1306_MEMORYMODE =0x20
SYMBOL SSD1306_COLUMNADDR =0x21
SYMBOL SSD1306_PAGEADDR =0x22 ; Page 0-7 represents line 0 - 7
SYMBOL SSD1306_COMSCANINC =0xC0
SYMBOL SSD1306_COMSCANDEC =0xC8
SYMBOL SSD1306_SEGREMAP =0xA0 | 1
SYMBOL SSD1306_CHARGEPUMP =0x8D
SYMBOL SSD1306_EXTERNALVCC =0x1
SYMBOL SSD1306_SWITCHCAPVCC =0x2
;Scrolling SYMBOLs
SYMBOL ACTIVATE_SCROLL =0x2F
SYMBOL DEACTIVATE_SCROLL =0x2E
SYMBOL SET_VERTICAL_SCROLL_AREA =0xA3
SYMBOL RIGHT_HORIZONTAL_SCROLL =0x26
SYMBOL LEFT_HORIZONTAL_SCROLL =0x27
SYMBOL VERT_AND_RIGHT_HORIZONTAL =0x29
SYMBOL VERT_AND_LEFT_HORIZONTAL =0x2A
;**************************************************************
SYMBOL SSD1306_ADDR = $3C << 1 ; this is the I2C address ($78)

main:
gosub InitialiseLcd

let x1=0:let y1=0:let y2=63
for x2=0 to 127 step 16
let y1=0
let x1=0
gosub line
next x2

let x1=127:let y1=0:let y2=63
for x2=0 to 127 step 16
let y1=0
let x1=127
gosub line
next x2

let x1=127:let y1=63:let y2=0
for x2=0 to 127 step 16
let y1=63
let x1=127
gosub line
next x2

let x1=0:let y1=63:let y2=0
for x2=0 to 127 step 16
let y1=63
let x1=0
gosub line
next x2

gosub sendbuffer

do:loop
;----------------------------------------------------------------
sendbuffer:
for ptr=0 to 1023
hi2cout (0x40,@ptr)
next ptr
return
plot:
let yrow = py / 8 ; find row
let bitpos = yrow * 8
let screenbit = py - bitpos ; pixel position
let ptr = yrow * 128 + px ; screen byte
let bitpos=0
setbit bitpos,screenbit ;pixel mask
@ptr = @ptr or bitpos ; OR onto screen byte
return
line:
if x1 < x2 then :let sx = 1 :let dx = x2 - x1:else let sx = -1 :let dx = x1 - x2 : endif
if y1 < y2 then :let sy = 1 :let dy = y2 - y1:else let sy = -1 :let dy = y1 - y2 : endif
if dx > dy then :let er = dx:else let er = dy : endif ; Don't divide "er" by 2
let dx =dx+dx :let dy =dy+dy

if dx > dy then
let py=y1
if x1<x2 then
for px=x1 to x2
gosub plot
let er = er - dy
if er > maxpos then ; It's Negative
let er = er + dx:let py = py + sy
endif
next px
else
for px=x1 to x2 step-1
gosub plot
let er = er - dy
if er > maxpos then ; It's Negative
let er = er + dx:let py = py + sy
endif
next px
endif
else
let px=x1
if y1<y2 then
for py=y1 to y2
gosub plot
let er = er - dx
if er > maxpos then
let er = er + dy:let px = px + sx
endif
next py
else
for py=y1 to y2 step-1
gosub plot
let er = er - dx
if er > maxpos then
let er = er + dy:let px = px + sx
endif
next py
endif
endif
return


InitialiseLcd:
PAUSE 500
i2cslave SSD1306_ADDR, i2cfast, i2cbyte

for index = 0 TO 23
read index,aByte
gosub DirectSendCmd
next

eeprom 0, (SSD1306_DISPLAYOFF); ; 0xAE
eeprom 1, (SSD1306_SETDISPLAYCLOCKDIV); ; 0xD5
eeprom 2, (0x80); ; the suggested ratio 0x80
eeprom 3, (SSD1306_SETMULTIPLEX); ; 0xA8
eeprom 4, (0x3F);
eeprom 5, (SSD1306_SETDISPLAYOFFSET); ; 0xD3
eeprom 6, (0x0); ; no offset
eeprom 7, (SSD1306_SETSTARTLINE); ; line #0
eeprom 8, (SSD1306_CHARGEPUMP); ; 0x8D
eeprom 9, (0x14); ; INTERNAL VCC
eeprom 10, (SSD1306_MEMORYMODE); ; 0x20
eeprom 11, (0x00); ; Horiz mode. 0x0 act like ks0108
eeprom 12, (SSD1306_SEGREMAP);
eeprom 13, (SSD1306_COMSCANDEC);
eeprom 14, (SSD1306_SETCOMPINS); ; 0xDA
eeprom 15, (0x12);
eeprom 16, (SSD1306_SETCONTRAST); ; 0x81
eeprom 17, (0xCF) ; INTERNAL VCC
eeprom 18, (SSD1306_SETPRECHARGE); ; 0xd9
eeprom 19, (0xF1) ; INTERNAL VCC
eeprom 20, (SSD1306_SETVCOMDETECT); ; 0xDB
eeprom 21, (0x40);
eeprom 22, (SSD1306_DISPLAYALLON_RESUME); ; 0xA4
eeprom 23, (SSD1306_DISPLAYON); ; 0xA4
'eeprom 24, (SSD1306_DISPLAYALLON); ; 0xA5
return
DirectSendCmd:
' Commands are preceeded by a 0 filled byte
writei2c (0,abyte)
return
 

stan74

Senior Member
"If you wrap the code in
Code:
 ...
tags the original formatting and spacing of the code will be preserved when viewed."
"Here is all the code BESQUEUT, Too large for copying for forum."
PE said:- "Too many characters...I bloated your code so it's too big to post-Ha! Ha! "...or something similar :)
I'll post it in 2 halves if anyone asks. Thanks guys for helping me. I'll make it complete with text positioning-line/column,rectangles,xor plotting etc if you think it would be of use to anyone,there not being much picaxe info. I think these displays will become more popular being relatively inexpensive. Your not going to get much of a frame rate on a picaxe thpugh.
 

AllyCat

Senior Member
Hi,

PE said:- "Too many characters...I bloated your code so it's too big to post-Ha! Ha! ".
Yup, one of the hazards of "multi-coloured" PE6. Paste it into PE5, Select All and "copy for forum" and it will probably fit easily. ;)

Cheers, Alan.
 

stan74

Senior Member
Code:
#picaxe 28x2
setfreq em64
symbol maxpos = $7fff
symbol x1=b0
symbol x2=b1
symbol y1=b2
symbol y2=b3
symbol px=b4
symbol py=b5
symbol nt=b6
symbol yrow=b7
symbol bitpos=b8
symbol screenbit=b9
symbol temp1=b10
symbol temp2=b11
symbol sx=b12
symbol sy=b13
symbol dx=w8
symbol dy=w9
symbol er=w10
symbol e2=w11

;
SYMBOL  DispNum  = W12
SYMBOL  row = b25
SYMBOL  col = b26
SYMBOL  temp  = b27
SYMBOL  aByte = b28
SYMBOL  index = b29


SYMBOL TWI_BUFFER_LENGTH 		= 32	
SYMBOL SSD1306_LCDWIDTH   		= 128
SYMBOL SSD1306_LCDHEIGHT            = 64
SYMBOL SSD1306_SETCONTRAST 		=0x81
SYMBOL SSD1306_DISPLAYALLON_RESUME 	=0xA4
SYMBOL SSD1306_DISPLAYALLON 		=0xA5
SYMBOL SSD1306_NORMALDISPLAY 		=0xA6
SYMBOL SSD1306_INVERTDISPLAY 		=0xA7
SYMBOL SSD1306_DISPLAYOFF 		=0xAE
SYMBOL SSD1306_DISPLAYON 		=0xAF	
SYMBOL SSD1306_SETDISPLAYOFFSET 	=0xD3
SYMBOL SSD1306_SETCOMPINS 		=0xDA	
SYMBOL SSD1306_SETVCOMDETECT 		=0xDB	
SYMBOL SSD1306_SETDISPLAYCLOCKDIV 	=0xD5
SYMBOL SSD1306_SETPRECHARGE 		=0xD9
SYMBOL SSD1306_SETMULTIPLEX 		=0xA8	
SYMBOL SSD1306_SETLOWCOLUMN 		=0x00
SYMBOL SSD1306_SETHIGHCOLUMN 		=0x10
SYMBOL SSD1306_SETSTARTLINE 		=0x40
SYMBOL SSD1306_MEMORYMODE 		=0x20
SYMBOL SSD1306_COLUMNADDR 		=0x21
SYMBOL SSD1306_PAGEADDR   		=0x22		; Page 0-7 represents line 0 - 7
SYMBOL SSD1306_COMSCANINC 		=0xC0
SYMBOL SSD1306_COMSCANDEC 		=0xC8
SYMBOL SSD1306_SEGREMAP 		=0xA0 | 1
SYMBOL SSD1306_CHARGEPUMP 		=0x8D
SYMBOL SSD1306_EXTERNALVCC 		=0x1
SYMBOL SSD1306_SWITCHCAPVCC 		=0x2
;Scrolling SYMBOLs
SYMBOL ACTIVATE_SCROLL 				=0x2F
SYMBOL DEACTIVATE_SCROLL 			=0x2E
SYMBOL SET_VERTICAL_SCROLL_AREA 		=0xA3
SYMBOL RIGHT_HORIZONTAL_SCROLL 		=0x26
SYMBOL LEFT_HORIZONTAL_SCROLL 		=0x27
SYMBOL VERT_AND_RIGHT_HORIZONTAL 		=0x29
SYMBOL VERT_AND_LEFT_HORIZONTAL 		=0x2A   
;   
SYMBOL  SSD1306_ADDR  = $3C << 1    ; this is the I2C address ($78)
;------------------------------------------------------------
main:
gosub InitialiseLcd

let x1=20:let y1=20:let y2=43
for x2=0 to 127 step 16
	let y1=20
	let x1=0
	gosub line
next x2

let x1=127:let y1=0:let y2=63
for x2=0 to 127 step 16
	let y1=0
	let x1=127
	gosub line
next x2

let x1=127:let y1=63:let y2=0
for x2=0 to 127 step 16
	let y1=63
	let x1=127
	gosub line
next x2

let x1=0:let y1=63:let y2=0
for x2=0 to 127 step 16
	let y1=63
	let x1=0
	gosub line
next x2

gosub sendbuffer

do:loop
;---------------------------------------------
sendbuffer:
for ptr=0 to 1023
	hi2cout (0x40,@ptr) ;this must be sorted
next ptr
return
;---------------------------------------------
plot:
let yrow = py / 8 ; find row
let bitpos = yrow * 8
let screenbit = py - bitpos ; pixel position
let ptr = yrow * 128  + px ; screen byte
let bitpos=0
setbit bitpos,screenbit ;pixel mask
@ptr = @ptr or bitpos ; OR onto screen byte
return
;---------------------------------------------
line:
if x1 < x2 then :let sx = 1 :let dx = x2 - x1:else let sx = -1 :let dx = x1 - x2 : endif
if y1 < y2 then :let sy = 1 :let dy = y2 - y1:else let sy = -1 :let dy = y1 - y2 : endif
if dx > dy then :let er = dx:else let er = dy : endif ; Don't divide "er" by 2
let dx =dx+dx :let dy =dy+dy

if dx > dy then
      let py=y1
	if x1<x2 then
      for px=x1 to x2
;-----------
		let yrow = py / 8 ; find row
		let bitpos = yrow * 8
		let screenbit = py - bitpos ; pixel position
		let ptr = yrow * 128  + px ; screen byte
		let bitpos=0
		setbit bitpos,screenbit ;pixel mask
		@ptr = @ptr or bitpos ; OR onto screen byte
;-----------			
            let er = er - dy
            if er > maxpos then ; It's Negative
		let er = er + dx:let py = py + sy 
            endif 
	next px
	else
      for px=x1 to x2 step-1
;-----------
		let yrow = py / 8 ; find row
		let bitpos = yrow * 8
		let screenbit = py - bitpos ; pixel position
		let ptr = yrow * 128  + px ; screen byte
		let bitpos=0
		setbit bitpos,screenbit ;pixel mask
		@ptr = @ptr or bitpos ; OR onto screen byte
;-----------
            let er = er - dy
            if er > maxpos then ; It's Negative
		let er = er + dx:let py = py + sy
		endif
	next px
	endif
else
      let px=x1
	if y1<y2 then
		for py=y1 to y2
;-----------
			let yrow = py / 8 ; find row
			let bitpos = yrow * 8
			let screenbit = py - bitpos ; pixel position
			let ptr = yrow * 128  + px ; screen byte
			let bitpos=0
			setbit bitpos,screenbit ;pixel mask
			@ptr = @ptr or bitpos ; OR onto screen byte
;-----------
			let er = er - dx
			if er > maxpos then
				let er = er + dy:let px = px + sx
			endif
		next py
	else		
		for py=y1 to y2 step-1
;-----------
			let yrow = py / 8 ; find row
			let bitpos = yrow * 8
			let screenbit = py - bitpos ; pixel position
			let ptr = yrow * 128  + px ; screen byte
			let bitpos=0
			setbit bitpos,screenbit ;pixel mask
			@ptr = @ptr or bitpos ; OR onto screen byte
;-----------
         		let er = er - dx 
			if er > maxpos then
				let er = er + dy:let px = px + sx
           		endif
     		next py
	endif
endif
return
;----------------------------------------------------------------------

InitialiseLcd:	
	PAUSE 500
	i2cslave SSD1306_ADDR, i2cfast, i2cbyte
	
	for index = 0 TO 23
		read index,aByte
		gosub DirectSendCmd
	next
		
	eeprom 0, (SSD1306_DISPLAYOFF);                   ; 0xAE
	eeprom 1, (SSD1306_SETDISPLAYCLOCKDIV);           ; 0xD5
	eeprom 2, (0x80);                                 ; the suggested ratio 0x80
	eeprom 3, (SSD1306_SETMULTIPLEX);                 ; 0xA8
	eeprom 4, (0x3F);
	eeprom 5, (SSD1306_SETDISPLAYOFFSET);             ; 0xD3
	eeprom 6, (0x0);                                  ; no offset
	eeprom 7, (SSD1306_SETSTARTLINE);            	  ; line #0
	eeprom 8, (SSD1306_CHARGEPUMP);                   ; 0x8D
	eeprom 9, (0x14);						  ; INTERNAL VCC
	eeprom 10, (SSD1306_MEMORYMODE);                  ; 0x20
	eeprom 11, (0x00);                                ; Horiz mode. 0x0 act like ks0108
	eeprom 12, (SSD1306_SEGREMAP);
	eeprom 13, (SSD1306_COMSCANDEC);
	eeprom 14, (SSD1306_SETCOMPINS);                  ; 0xDA
	eeprom 15, (0x12);
	eeprom 16, (SSD1306_SETCONTRAST);                 ; 0x81
	eeprom 17, (0xCF)						  ; INTERNAL VCC
	eeprom 18, (SSD1306_SETPRECHARGE);                ; 0xd9
	eeprom 19, (0xF1)						  ; INTERNAL VCC
	eeprom 20, (SSD1306_SETVCOMDETECT);               ; 0xDB
	eeprom 21, (0x40);
	eeprom 22, (SSD1306_DISPLAYALLON_RESUME);         ; 0xA4
	eeprom 23, (SSD1306_DISPLAYON);                	  ; 0xA4	
	'eeprom 24, (SSD1306_DISPLAYALLON);               ; 0xA5          
return
;-----------------------------------------------------------------
DirectSendCmd:
' Commands are preceeded by a 0 filled byte    
writei2c (0,abyte)   
return
 

BESQUEUT

Senior Member
Yup, one of the hazards of "multi-coloured" PE6. Paste it into PE5, Select All and "copy for forum" and it will probably fit easily.
No need for PE5 : use PE6/copy then "Go advanced" and # button... :cool: :cool: :cool:

Or use a macro to reduce source code size :
Code:
[color=Navy]#macro [/color][color=Black]DrawLines[/color][color=Blue]([/color][color=Black]xx1,yy1,yy2[/color][color=Blue])
      [/color][color=Black]yy2[/color][color=DarkCyan]=[/color][color=Purple]y2
      [/color][color=Blue]for [/color][color=Purple]x2[/color][color=DarkCyan]=[/color][color=Navy]0 [/color][color=Blue]to [/color][color=Navy]127 [/color][color=Blue]step [/color][color=Navy]16
            [/color][color=Blue]let [/color][color=Purple]y1[/color][color=DarkCyan]=[/color][color=Black]yy1
            [/color][color=Blue]let [/color][color=Purple]x1[/color][color=DarkCyan]=[/color][color=Black]xx1
            [/color][color=Blue]gosub [/color][color=Black]line
      [/color][color=Blue]next [/color][color=Purple]x2[/color]
[color=Navy]#endmacro[/color]

[color=Black]main:[/color]
[color=Blue]gosub [/color][color=Black]InitialiseLcd
DrawLines[/color][color=Blue]([/color][color=Navy]0[/color][color=Black],[/color][color=Navy]20[/color][color=Black],[/color][color=Navy]43[/color][color=Blue])[/color]
[color=Black]DrawlLines[/color][color=Blue]([/color][color=Navy]127[/color][color=Black],[/color][color=Navy]0[/color][color=Black],[/color][color=Navy]63[/color][color=Blue])[/color]
[color=Black]DrawLines[/color][color=Blue]([/color][color=Navy]127[/color][color=Black],[/color][color=Navy]63[/color][color=Black],[/color][color=Navy]0[/color][color=Blue])[/color]
[color=Black]DrawLines[/color][color=Blue]([/color][color=Navy]0[/color][color=Black],[/color][color=Navy]63[/color][color=Black],[/color][color=Navy]0[/color][color=Blue])

gosub [/color][color=Black]sendbuffer[/color]

[color=Blue]do[/color][color=Black]:[/color][color=Blue]loop[/color]
[color=Green];---------------------------------------------[/color]
[color=Black]sendbuffer:[/color]
[color=Blue]for [/color][color=Purple]ptr[/color][color=DarkCyan]=[/color][color=Navy]0 [/color][color=Blue]to [/color][color=Navy]1023
      [/color][color=Blue]hi2cout ([/color][color=Navy]0x40[/color][color=Black],[/color][color=Purple]@ptr[/color][color=Blue]) [/color][color=Green];this must be sorted[/color]
[color=Blue]next [/color][color=Purple]ptr[/color]
[color=Blue]return[/color]
[color=Green];---------------------------------------------[/color]
[color=Navy]#macro [/color][color=Black]Plot[/color][color=Blue]([/color][color=Black]PP,XX,XXX[/color][color=Blue])
for [/color][color=Black]PP[/color][color=DarkCyan]=[/color][color=Black]XX [/color][color=Blue]to [/color][color=Black]XXX
      [/color][color=Purple]yrow [/color][color=DarkCyan]= [/color][color=Purple]py [/color][color=DarkCyan]/ [/color][color=Navy]8     [/color][color=Green]; find row
      [/color][color=Purple]bitpos [/color][color=DarkCyan]= [/color][color=Purple]yrow [/color][color=DarkCyan]* [/color][color=Navy]8
      [/color][color=Purple]screenbit [/color][color=DarkCyan]= [/color][color=Purple]py [/color][color=DarkCyan]- [/color][color=Purple]bitpos [/color][color=Green]; pixel position
      [/color][color=Purple]ptr [/color][color=DarkCyan]= [/color][color=Purple]yrow [/color][color=DarkCyan]* [/color][color=Navy]128  [/color][color=DarkCyan]+ [/color][color=Purple]px  [/color][color=Green]; screen byte
      [/color][color=Purple]bitpos[/color][color=DarkCyan]=[/color][color=Navy]0
      [/color][color=Blue]setbit [/color][color=Purple]bitpos[/color][color=Black],[/color][color=Purple]screenbit             [/color][color=Green];pixel mask
      [/color][color=Purple]@ptr [/color][color=DarkCyan]= [/color][color=Purple]@ptr [/color][color=DarkCyan]or [/color][color=Purple]bitpos   [/color][color=Green]; OR onto screen byte
      
      [/color][color=Blue]let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]- [/color][color=Purple]dy
      [/color][color=Blue]if [/color][color=Purple]er [/color][color=DarkCyan]> [/color][color=Blue]maxpos then [/color][color=Green]; It's Negative
            [/color][color=Blue]let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]+ [/color][color=Purple]dx[/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]py [/color][color=DarkCyan]= [/color][color=Purple]py [/color][color=DarkCyan]+ [/color][color=Purple]sy 
      [/color][color=Blue]endif 
next [/color][color=Black]PP[/color]
[color=Navy]#endmacro[/color]

[color=Green];---------------------------------------------[/color]
[color=Black]line:[/color]
[color=Blue]if [/color][color=Purple]x1 [/color][color=DarkCyan]< [/color][color=Purple]x2 [/color][color=Blue]then :let [/color][color=Purple]sx [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]dx [/color][color=DarkCyan]= [/color][color=Purple]x2 [/color][color=DarkCyan]- [/color][color=Purple]x1[/color][color=Black]:[/color][color=Blue]else let [/color][color=Purple]sx [/color][color=DarkCyan]= -[/color][color=Navy]1 [/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]dx [/color][color=DarkCyan]= [/color][color=Purple]x1 [/color][color=DarkCyan]- [/color][color=Purple]x2 [/color][color=Black]: [/color][color=Blue]endif
if [/color][color=Purple]y1 [/color][color=DarkCyan]< [/color][color=Purple]y2 [/color][color=Blue]then :let [/color][color=Purple]sy [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]dy [/color][color=DarkCyan]= [/color][color=Purple]y2 [/color][color=DarkCyan]- [/color][color=Purple]y1[/color][color=Black]:[/color][color=Blue]else let [/color][color=Purple]sy [/color][color=DarkCyan]= -[/color][color=Navy]1 [/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]dy [/color][color=DarkCyan]= [/color][color=Purple]y1 [/color][color=DarkCyan]- [/color][color=Purple]y2 [/color][color=Black]: [/color][color=Blue]endif
if [/color][color=Purple]dx [/color][color=DarkCyan]> [/color][color=Purple]dy [/color][color=Blue]then :let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]dx[/color][color=Black]:[/color][color=Blue]else let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]dy [/color][color=Black]: [/color][color=Blue]endif [/color][color=Green]; Don't divide "er" by 2[/color]
[color=Blue]let [/color][color=Purple]dx [/color][color=DarkCyan]=[/color][color=Purple]dx[/color][color=DarkCyan]+[/color][color=Purple]dx [/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]dy [/color][color=DarkCyan]=[/color][color=Purple]dy[/color][color=DarkCyan]+[/color][color=Purple]dy[/color]

[color=Blue]if [/color][color=Purple]dx [/color][color=DarkCyan]> [/color][color=Purple]dy [/color][color=Blue]then
      let [/color][color=Purple]py[/color][color=DarkCyan]=[/color][color=Purple]y1
      [/color][color=Blue]if [/color][color=Purple]x1[/color][color=DarkCyan]<[/color][color=Purple]x2 [/color][color=Blue]then
            [/color][color=Black]Plot[/color][color=Blue]([/color][color=Purple]px[/color][color=Black],[/color][color=Purple]x1[/color][color=Black],[/color][color=Purple]x2[/color][color=Blue])
      else
            [/color][color=Black]Plot[/color][color=Blue]([/color][color=Purple]px[/color][color=Black],[/color][color=Purple]x1[/color][color=Black],[/color][color=Purple]x2 [/color][color=Blue]step[/color][color=DarkCyan]-[/color][color=Navy]1[/color][color=Blue])
      endif
else
      let [/color][color=Purple]px[/color][color=DarkCyan]=[/color][color=Purple]x1
      [/color][color=Blue]if [/color][color=Purple]y1[/color][color=DarkCyan]<[/color][color=Purple]y2 [/color][color=Blue]then
            [/color][color=Black]Plot[/color][color=Blue]([/color][color=Purple]py[/color][color=Black],[/color][color=Purple]y1[/color][color=Black],[/color][color=Purple]y2[/color][color=Blue])
      else  
            [/color][color=Black]Plot[/color][color=Blue]([/color][color=Purple]py[/color][color=Black],[/color][color=Purple]y1[/color][color=Black],[/color][color=Purple]y2 [/color][color=Blue]step [/color][color=DarkCyan]-[/color][color=Navy]1[/color][color=Blue])
      endif
endif
return[/color]
:p
 
Last edited:

hippy

Technical Support
Staff member
Code:
;-----------
		let yrow = py / 8 ; find row
		let bitpos = yrow * 8
		let screenbit = py - bitpos ; pixel position
		let ptr = yrow * 128  + px ; screen byte
		let bitpos=0
		setbit bitpos,screenbit ;pixel mask
		@ptr = @ptr or bitpos ; OR onto screen byte
;-----------
That can almost certainly be optimised for speed and get you considerable performance improvement, especially with X2 shift operators which will avoid multiplications and divisions.

This is also where #MACRO becomes extremely useful. You only have to change the code in the #MACRO definition and everywhere it is used will get the same change.

Code:
sendbuffer:
for ptr=0 to 1023
	hi2cout (0x40,@ptr) ;this must be sorted
next ptr
return
Could also be improved with ... keep doubling up what's sent and the step value ... (untested) ...

Code:
sendbuffer:
ptr = 0
for er=0 to 1023 Step 2
	hi2cout (0x40,@ptrinc, 0x40,@ptrinc)
next
return
 

BESQUEUT

Senior Member
Code:
sendbuffer:
for ptr=0 to 1023
	hi2cout (0x40,@ptr) ;this must be sorted
next ptr
return
Could also be improved with ... keep doubling up what's sent and the step value ... (untested) ...

Code:
sendbuffer:
ptr = 0
for er=0 to 1023 Step 2
	hi2cout (0x40,@ptrinc, 0x40,@ptrinc)
next
return
No need for step, and can be double doubled ...
Code:
sendbuffer:
ptr = 0
for er=0 to 255
	hi2cout (0x40,@ptrinc, 0x40,@ptrinc,0x40,@ptrinc, 0x40,@ptrinc)
next
return
 

AllyCat

Senior Member
Hi,

Or even: ?

Code:
sendbuffer:
ptr = 0
do
	hi2cout (0x40,@ptrinc, 0x40,@ptrinc,0x40,@ptrinc, 0x40,@ptrinc)
loop until ptr = 0        ; (1024)
return
Cheers, Alan.
 

stan74

Senior Member
Hi all, just a few questions. I changed the code to use do while instead of for next step var...-1 is 255 issue.
It doesn't work..loop while px<>x2, px keeps increasing??
let val1=val2<<val2<<val2<<val2 ; val1=val2*8 gives 0, as per manual but should multiply by 8??
The loop to move 1K need a 64 byte first,means 1 data byte to follow but examples show one 64 wright before the loop but that doesn't work and the do loop until idea should work but I think it's TOO fast.Also read the oled can handle 255 bytes at a time but that's carp to.
Code:
[color=Black]sendbuffer:[/color]
[color=Blue]for [/color][color=Purple]ptr[/color][color=DarkCyan]=[/color][color=Navy]0 [/color][color=Blue]to [/color][color=Navy]1023
      [/color][color=Blue]hi2cout ([/color][color=Navy]64[/color][color=Black],[/color][color=Purple]@ptr[/color][color=Blue])[/color][color=Green];,64,@ptrinc,64,@ptrinc,64,@ptrinc,64,@ptrinc,64,@ptrinc,64,@ptrinc,64,@ptrinc)[/color]
[color=Blue]next [/color][color=Purple]ptr[/color]
[color=Blue]return[/color]
[color=Black]plot:[/color]
[color=Blue]let [/color][color=Purple]yrow[/color][color=DarkCyan]=[/color][color=Purple]py[/color][color=DarkCyan]/[/color][color=Navy]8 [/color][color=Green];let yrow=py>>py>>py>>py ; find row[/color]
[color=Blue]let [/color][color=Purple]bitpos [/color][color=DarkCyan]= [/color][color=Purple]yrow[/color][color=DarkCyan]*[/color][color=Navy]8[/color][color=Green];let bitpos=yrow<<yrow<<yrow<<yrow[/color]
[color=Blue]let [/color][color=Purple]screenbit [/color][color=DarkCyan]= [/color][color=Purple]py [/color][color=DarkCyan]- [/color][color=Purple]bitpos [/color][color=Green]; pixel position[/color]
[color=Blue]let [/color][color=Purple]ptr [/color][color=DarkCyan]= [/color][color=Purple]yrow[/color][color=DarkCyan]*[/color][color=Navy]128[/color][color=DarkCyan]+[/color][color=Purple]px[/color][color=Green];let ptr=yrow<<yrow<<yrow<<yrow<<yrow<<yrow<<yrow<<yrow + px ; screen byte[/color]
[color=Blue]let [/color][color=Purple]bitpos[/color][color=DarkCyan]=[/color][color=Navy]0[/color]
[color=Blue]setbit [/color][color=Purple]bitpos[/color][color=Black],[/color][color=Purple]screenbit [/color][color=Green];pixel mask[/color]
[color=Purple]@ptr [/color][color=DarkCyan]= [/color][color=Purple]@ptr [/color][color=DarkCyan]or [/color][color=Purple]bitpos [/color][color=Green]; OR onto screen byte [/color]
[color=Blue]return[/color]
[color=Black]line:[/color]
[color=Blue]push [/color][color=Purple]x1[/color][color=Black],[/color][color=Purple]y1[/color]
[color=Blue]if [/color][color=Purple]x1 [/color][color=DarkCyan]< [/color][color=Purple]x2 [/color][color=Blue]then :let [/color][color=Purple]sx [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]dx [/color][color=DarkCyan]= [/color][color=Purple]x2 [/color][color=DarkCyan]- [/color][color=Purple]x1[/color][color=Black]:[/color][color=Blue]else let [/color][color=Purple]sx [/color][color=DarkCyan]= -[/color][color=Navy]1 [/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]dx [/color][color=DarkCyan]= [/color][color=Purple]x1 [/color][color=DarkCyan]- [/color][color=Purple]x2 [/color][color=Black]: [/color][color=Blue]endif
if [/color][color=Purple]y1 [/color][color=DarkCyan]< [/color][color=Purple]y2 [/color][color=Blue]then :let [/color][color=Purple]sy [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]dy [/color][color=DarkCyan]= [/color][color=Purple]y2 [/color][color=DarkCyan]- [/color][color=Purple]y1[/color][color=Black]:[/color][color=Blue]else let [/color][color=Purple]sy [/color][color=DarkCyan]= -[/color][color=Navy]1 [/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]dy [/color][color=DarkCyan]= [/color][color=Purple]y1 [/color][color=DarkCyan]- [/color][color=Purple]y2 [/color][color=Black]: [/color][color=Blue]endif
if [/color][color=Purple]dx [/color][color=DarkCyan]> [/color][color=Purple]dy [/color][color=Blue]then :let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]dx[/color][color=Black]:[/color][color=Blue]else let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]dy [/color][color=Black]: [/color][color=Blue]endif [/color][color=Green]; Don't divide "er" by 2[/color]
[color=Blue]let [/color][color=Purple]dx [/color][color=DarkCyan]=[/color][color=Purple]dx[/color][color=DarkCyan]+[/color][color=Purple]dx [/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]dy [/color][color=DarkCyan]=[/color][color=Purple]dy[/color][color=DarkCyan]+[/color][color=Purple]dy[/color]

[color=Blue]if [/color][color=Purple]dx [/color][color=DarkCyan]> [/color][color=Purple]dy [/color][color=Blue]then
      let [/color][color=Purple]py[/color][color=DarkCyan]=[/color][color=Purple]y1
      [/color][color=Blue]if [/color][color=Purple]x1[/color][color=DarkCyan]<[/color][color=Purple]x2 [/color][color=Blue]then
            let [/color][color=Purple]temp1[/color][color=DarkCyan]=[/color][color=Navy]1
      [/color][color=Blue]else  let [/color][color=Purple]temp1[/color][color=DarkCyan]=-[/color][color=Navy]1
      [/color][color=Blue]endif
      do [/color][color=Green]; for px=x1 to x2 step temp1
            [/color][color=Blue]gosub [/color][color=Black]plot[/color]
[color=Blue]sertxd ([/color][color=Red]"px= "[/color][color=Black],#[/color][color=Purple]px[/color][color=Black],[/color][color=Blue]cr[/color][color=Black],[/color][color=Blue]lf)
            let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]- [/color][color=Purple]dy
            [/color][color=Blue]if [/color][color=Purple]er [/color][color=DarkCyan]> [/color][color=Blue]maxpos then [/color][color=Green]; It's Negative
                  [/color][color=Blue]let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]+ [/color][color=Purple]dx[/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]py [/color][color=DarkCyan]= [/color][color=Purple]py [/color][color=DarkCyan]+ [/color][color=Purple]sy 
            [/color][color=Blue]endif
            let [/color][color=Purple]px[/color][color=DarkCyan]=[/color][color=Purple]px[/color][color=DarkCyan]+[/color][color=Purple]temp1
      [/color][color=Blue]loop while [/color][color=Purple]px[/color][color=DarkCyan]<>[/color][color=Purple]x2 [/color][color=Green];next px[/color]
[color=Blue]else
      let [/color][color=Purple]px[/color][color=DarkCyan]=[/color][color=Purple]x1
      [/color][color=Blue]if [/color][color=Purple]y1[/color][color=DarkCyan]<[/color][color=Purple]y2 [/color][color=Blue]then
            let [/color][color=Purple]temp1[/color][color=DarkCyan]=[/color][color=Navy]1
      [/color][color=Blue]else let [/color][color=Purple]temp1[/color][color=DarkCyan]=-[/color][color=Navy]1
      [/color][color=Blue]endif
      do [/color][color=Green]; for py=y1 to y2 step temp1
            [/color][color=Blue]gosub [/color][color=Black]plot              [/color]
[color=Blue]sertxd ([/color][color=Red]"px= "[/color][color=Black],#[/color][color=Purple]px[/color][color=Black],[/color][color=Blue]cr[/color][color=Black],[/color][color=Blue]lf)
            let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]- [/color][color=Purple]dx
            [/color][color=Blue]if [/color][color=Purple]er [/color][color=DarkCyan]> [/color][color=Blue]maxpos then
                  let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]+ [/color][color=Purple]dy[/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]px [/color][color=DarkCyan]= [/color][color=Purple]px [/color][color=DarkCyan]+ [/color][color=Purple]sx
            [/color][color=Blue]endif
            let [/color][color=Purple]py[/color][color=DarkCyan]=[/color][color=Purple]py[/color][color=DarkCyan]+[/color][color=Purple]temp1
      [/color][color=Blue]loop while [/color][color=Purple]py[/color][color=DarkCyan]<>[/color][color=Purple]y2 [/color][color=Green]; next py[/color]
[color=Blue]endif
pop [/color][color=Purple]y1[/color][color=Black],[/color][color=Purple]x1[/color]
[color=Blue]return[/color]
 

BESQUEUT

Senior Member
Hi all, just a few questions. I changed the code to use do while instead of for next step var...-1 is 255 issue.
It doesn't work..loop while px<>x2, px keeps increasing??
How are defined temp1, px and py ?
Gosub can be used for testing. But for speed optimisation, it is a bad idea. (prefer using a macro...)
 

hippy

Technical Support
Staff member
let val1=val2<<val2<<val2<<val2 ; val1=val2*8 gives 0, as per manual but should multiply by 8??
No; that will shift val2 left by val2 bits, then shift that left by val2 bits etc. To multiply by 8 using shift -

let val1 = val2 << 3 ; 23 = 8

It seems to me that ...
Code:
let yrow = py / 8           ; find row
let bitpos = yrow * 8
let screenbit = py - bitpos ; pixel position
let ptr = yrow * 128  + px  ; screen byte
let bitpos = 0
setbit bitpos,screenbit     ; pixel mask
@ptr = @ptr or bitpos       ; OR onto screen byte
Can be replaced with ...
Code:
ptr = py And $F8 << 4 Or px
screenbit = py And $07
@ptr = 1 << screenbit Or @ptr
 

stan74

Senior Member
Fixed the do while error..moved px=x1:py=y1 to before main loop.
Code:
[color=Black]plot:[/color]
[color=Blue]let [/color][color=Purple]yrow[/color][color=DarkCyan]=[/color][color=Purple]py[/color][color=DarkCyan]/[/color][color=Navy]8 [/color][color=Green];let yrow=py>>py>>py>>py ; find row[/color]
[color=Blue]let [/color][color=Purple]bitpos [/color][color=DarkCyan]= [/color][color=Purple]yrow[/color][color=DarkCyan]*[/color][color=Navy]8[/color][color=Green];let bitpos=yrow<<yrow<<yrow<<yrow[/color]
[color=Blue]let [/color][color=Purple]screenbit [/color][color=DarkCyan]= [/color][color=Purple]py [/color][color=DarkCyan]- [/color][color=Purple]bitpos [/color][color=Green]; pixel position[/color]
[color=Blue]let [/color][color=Purple]ptr [/color][color=DarkCyan]= [/color][color=Purple]yrow[/color][color=DarkCyan]*[/color][color=Navy]128[/color][color=DarkCyan]+[/color][color=Purple]px[/color][color=Green];let ptr=yrow<<yrow<<yrow<<yrow<<yrow<<yrow<<yrow<<yrow + px ; screen byte[/color]
[color=Blue]let [/color][color=Purple]bitpos[/color][color=DarkCyan]=[/color][color=Navy]0[/color]
[color=Blue]setbit [/color][color=Purple]bitpos[/color][color=Black],[/color][color=Purple]screenbit [/color][color=Green];pixel mask[/color]
[color=Purple]@ptr [/color][color=DarkCyan]= [/color][color=Purple]@ptr [/color][color=DarkCyan]or [/color][color=Purple]bitpos [/color][color=Green]; OR onto screen byte [/color]
[color=Blue]return[/color]
[color=Green];28x2 line draw for 128x64 oled-x1 y1 line start..x2 y2 line end[/color]
[color=Black]line:[/color]
[color=Blue]push [/color][color=Purple]x1[/color][color=Black],[/color][color=Purple]y1[/color]
[color=Blue]if [/color][color=Purple]x1 [/color][color=DarkCyan]< [/color][color=Purple]x2 [/color][color=Blue]then :let [/color][color=Purple]sx [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]dx [/color][color=DarkCyan]= [/color][color=Purple]x2 [/color][color=DarkCyan]- [/color][color=Purple]x1[/color][color=Black]:[/color][color=Blue]else let [/color][color=Purple]sx [/color][color=DarkCyan]= -[/color][color=Navy]1 [/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]dx [/color][color=DarkCyan]= [/color][color=Purple]x1 [/color][color=DarkCyan]- [/color][color=Purple]x2 [/color][color=Black]: [/color][color=Blue]endif
if [/color][color=Purple]y1 [/color][color=DarkCyan]< [/color][color=Purple]y2 [/color][color=Blue]then :let [/color][color=Purple]sy [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]dy [/color][color=DarkCyan]= [/color][color=Purple]y2 [/color][color=DarkCyan]- [/color][color=Purple]y1[/color][color=Black]:[/color][color=Blue]else let [/color][color=Purple]sy [/color][color=DarkCyan]= -[/color][color=Navy]1 [/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]dy [/color][color=DarkCyan]= [/color][color=Purple]y1 [/color][color=DarkCyan]- [/color][color=Purple]y2 [/color][color=Black]: [/color][color=Blue]endif
if [/color][color=Purple]dx [/color][color=DarkCyan]> [/color][color=Purple]dy [/color][color=Blue]then :let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]dx[/color][color=Black]:[/color][color=Blue]else let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]dy [/color][color=Black]: [/color][color=Blue]endif
let [/color][color=Purple]dx [/color][color=DarkCyan]=[/color][color=Purple]dx[/color][color=DarkCyan]+[/color][color=Purple]dx [/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]dy [/color][color=DarkCyan]=[/color][color=Purple]dy[/color][color=DarkCyan]+[/color][color=Purple]dy[/color]
[color=Blue]let [/color][color=Purple]py[/color][color=DarkCyan]=[/color][color=Purple]y1[/color]
[color=Blue]let [/color][color=Purple]px[/color][color=DarkCyan]=[/color][color=Purple]x1[/color]
[color=Blue]if [/color][color=Purple]dx [/color][color=DarkCyan]> [/color][color=Purple]dy [/color][color=Blue]then
      if [/color][color=Purple]x1[/color][color=DarkCyan]<[/color][color=Purple]x2 [/color][color=Blue]then
            let [/color][color=Purple]temp1[/color][color=DarkCyan]=[/color][color=Navy]1
      [/color][color=Blue]else  let [/color][color=Purple]temp1[/color][color=DarkCyan]=-[/color][color=Navy]1
      [/color][color=Blue]endif
      do
            gosub [/color][color=Black]plot
            [/color][color=Blue]let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]- [/color][color=Purple]dy
            [/color][color=Blue]if [/color][color=Purple]er [/color][color=DarkCyan]> [/color][color=Blue]maxpos then [/color][color=Green]; It's Negative
                  [/color][color=Blue]let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]+ [/color][color=Purple]dx[/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]py [/color][color=DarkCyan]= [/color][color=Purple]py [/color][color=DarkCyan]+ [/color][color=Purple]sy 
            [/color][color=Blue]endif
            let [/color][color=Purple]px[/color][color=DarkCyan]=[/color][color=Purple]px[/color][color=DarkCyan]+[/color][color=Purple]temp1
      [/color][color=Blue]loop while [/color][color=Purple]px[/color][color=DarkCyan]<>[/color][color=Purple]x2 [/color][color=Green];next px[/color]
[color=Blue]else
      if [/color][color=Purple]y1[/color][color=DarkCyan]<[/color][color=Purple]y2 [/color][color=Blue]then
            let [/color][color=Purple]temp2[/color][color=DarkCyan]=[/color][color=Navy]1
      [/color][color=Blue]else let [/color][color=Purple]temp2[/color][color=DarkCyan]=-[/color][color=Navy]1
      [/color][color=Blue]endif
      do
            gosub [/color][color=Black]plot              
            [/color][color=Blue]let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]- [/color][color=Purple]dx
            [/color][color=Blue]if [/color][color=Purple]er [/color][color=DarkCyan]> [/color][color=Blue]maxpos then
                  let [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]+ [/color][color=Purple]dy[/color][color=Black]:[/color][color=Blue]let [/color][color=Purple]px [/color][color=DarkCyan]= [/color][color=Purple]px [/color][color=DarkCyan]+ [/color][color=Purple]sx
            [/color][color=Blue]endif
            let [/color][color=Purple]py[/color][color=DarkCyan]=[/color][color=Purple]py[/color][color=DarkCyan]+[/color][color=Purple]temp2         
      [/color][color=Blue]loop while [/color][color=Purple]py[/color][color=DarkCyan]<>[/color][color=Purple]y2[/color]
[color=Blue]endif
pop [/color][color=Purple]y1[/color][color=Black],[/color][color=Purple]x1[/color]
[color=Blue]return[/color]
 

stan74

Senior Member
It seems to me that ...
Code:
let yrow = py / 8 ; find row
let bitpos = yrow * 8
let screenbit = py - bitpos ; pixel position
let ptr = yrow * 128 + px ; screen byte
let bitpos = 0
setbit bitpos,screenbit ; pixel mask
@ptr = @ptr or bitpos ; OR onto screen byte
Can be replaced with ...
Code:
ptr = py And $F8 << 4 Or px
screenbit = py And $07
@ptr = 1 << screenbit Or @ptr
It didn't work hippy but looks worth a further look. I noticed that yrow was a byte var (yrow*128) and the plot only worked because bitpos was the next var and it's just reset on the next line anyway. Not a deliberate variable saver but handy.
Sorry hippy,it did work,thanks.
 
Last edited:

stan74

Senior Member
The values for a plot or line routine are usually preserved. I was drawing patterns like 35 years ago.
I was thinking that I could now use the picaxe adc to make a component tester..just to see if I could.
The component won't change so no need for speed.My mate wants one but is too tight to buy a mini 2 channel scope,pocket size, he said you can use a square wave. I thought...no way. https://www.youtube.com/watch?v=Gwo3pEH7hUE
 

stan74

Senior Member
Instead of drawing lines and when finished send the 1K buffer to screen ram I kept the buffer and each pixel that's written to the buffer is also written to screen ram. That's extra code for the plot routine but I prefer to see what's happening in real time.
This 28x2 is the same speed as running on a raspberry pi2 using python but using the oled library is 10 lines a second.

Code:
[color=Black]plot2screenram:[/color]
[color=Blue]let [/color][color=Purple]yrow[/color][color=DarkCyan]=[/color][color=Purple]py[/color][color=DarkCyan]>>[/color][color=Navy]3 [/color][color=Green];let yrow=py/8 find row[/color]
[color=Blue]let [/color][color=Purple]screenbufferbyte[/color][color=DarkCyan]=[/color][color=Purple]yrow[/color][color=DarkCyan]<<[/color][color=Navy]3 [/color][color=Green];let screenbufferbyte=yrow*8[/color]
[color=Blue]let [/color][color=Purple]screenbit [/color][color=DarkCyan]= [/color][color=Purple]py [/color][color=DarkCyan]And [/color][color=Navy]$07[/color][color=Green];let screenbit=py - screenbufferbyte ; pixel position[/color]
[color=Blue]let [/color][color=Purple]ptr [/color][color=DarkCyan]= [/color][color=Purple]py [/color][color=DarkCyan]And [/color][color=Navy]$F8 [/color][color=DarkCyan]<< [/color][color=Navy]4 [/color][color=DarkCyan]Or [/color][color=Purple]px[/color][color=Green];let ptr=yrow*128 + px ; screen byte[/color]
[color=Blue]let [/color][color=Purple]screenbufferbyte[/color][color=DarkCyan]=[/color][color=Navy]0[/color]
[color=Blue]setbit [/color][color=Purple]screenbufferbyte[/color][color=Black],[/color][color=Purple]screenbit [/color][color=Green];pixel mask[/color]
[color=Purple]@ptr [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=DarkCyan]<< [/color][color=Purple]screenbit [/color][color=DarkCyan]Or [/color][color=Purple]@ptr[/color][color=Green];@ptr=@ptr or screenbufferbyte ; OR onto screen byte [/color]

[color=Blue]let [/color][color=Purple]row[/color][color=DarkCyan]=[/color][color=Purple]py[/color][color=DarkCyan]>>[/color][color=Navy]3[/color]
[color=Blue]hi2cout ([/color][color=Navy]0[/color][color=Black],[/color][color=Blue]SSD1306_PAGEADDR)
hi2cout ([/color][color=Navy]0[/color][color=Black],[/color][color=Purple]row[/color][color=Blue])
hi2cout ([/color][color=Navy]0[/color][color=Black],[/color][color=Navy]7[/color][color=Blue])
hi2cout ([/color][color=Navy]0[/color][color=Black],[/color][color=Blue]SSD1306_COLUMNADDR)
hi2cout ([/color][color=Navy]0[/color][color=Black],[/color][color=Purple]px[/color][color=Blue])
hi2cout ([/color][color=Navy]0[/color][color=Black],[/color][color=Navy]127[/color][color=Blue])
hi2cout ([/color][color=Navy]64[/color][color=Black],[/color][color=Purple]@ptr[/color][color=Blue])[/color]
https://youtu.be/AL6Jrsc0AXI
PS, I've run out of variables and eeprom. Push them all,they're for oled or peek/poke for what mems left.
Is there a dynamic pointer to the end of the program and can that empty space be used? Probably been asked before.
I've found this very interesting, what a picaxe can-can't do. I've brushed my maths and learnt new basic code methods. This could be useful. Thanks again all.
 
Last edited:

hippy

Technical Support
Staff member
Code:
[color=Black]plot2screenram:[/color]
[color=Blue]let [/color][color=Purple]yrow[/color][color=DarkCyan]=[/color][color=Purple]py[/color][color=DarkCyan]>>[/color][color=Navy]3 [/color][color=Green];let yrow=py/8 find row[/color]
[color=Blue]let [/color][color=Purple]screenbufferbyte[/color][color=DarkCyan]=[/color][color=Purple]yrow[/color][color=DarkCyan]<<[/color][color=Navy]3 [/color][color=Green];let screenbufferbyte=yrow*8[/color]
[color=Blue]let [/color][color=Purple]screenbit [/color][color=DarkCyan]= [/color][color=Purple]py [/color][color=DarkCyan]And [/color][color=Navy]$07[/color][color=Green];let screenbit=py - screenbufferbyte ; pixel position[/color]
[color=Blue]let [/color][color=Purple]ptr [/color][color=DarkCyan]= [/color][color=Purple]py [/color][color=DarkCyan]And [/color][color=Navy]$F8 [/color][color=DarkCyan]<< [/color][color=Navy]4 [/color][color=DarkCyan]Or [/color][color=Purple]px[/color][color=Green];let ptr=yrow*128 + px ; screen byte[/color]
[color=Blue]let [/color][color=Purple]screenbufferbyte[/color][color=DarkCyan]=[/color][color=Navy]0[/color]
[color=Blue]setbit [/color][color=Purple]screenbufferbyte[/color][color=Black],[/color][color=Purple]screenbit [/color][color=Green];pixel mask[/color]
[color=Purple]@ptr [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=DarkCyan]<< [/color][color=Purple]screenbit [/color][color=DarkCyan]Or [/color][color=Purple]@ptr[/color][color=Green];@ptr=@ptr or screenbufferbyte ; OR onto screen byte [/color]

[color=Blue]let [/color][color=Purple]row[/color][color=DarkCyan]=[/color][color=Purple]py[/color][color=DarkCyan]>>[/color][color=Navy]3[/color]
[color=Blue]hi2cout ([/color][color=Navy]0[/color][color=Black],[/color][color=Blue]SSD1306_PAGEADDR)
hi2cout ([/color][color=Navy]0[/color][color=Black],[/color][color=Purple]row[/color][color=Blue])
hi2cout ([/color][color=Navy]0[/color][color=Black],[/color][color=Navy]7[/color][color=Blue])
hi2cout ([/color][color=Navy]0[/color][color=Black],[/color][color=Blue]SSD1306_COLUMNADDR)
hi2cout ([/color][color=Navy]0[/color][color=Black],[/color][color=Purple]px[/color][color=Blue])
hi2cout ([/color][color=Navy]0[/color][color=Black],[/color][color=Navy]127[/color][color=Blue])
hi2cout ([/color][color=Navy]64[/color][color=Black],[/color][color=Purple]@ptr[/color][color=Blue])[/color]
You can speed that up by removing the stuff you don't need or use in that code. And, as it's an X2 you can used "DCD var" in place of "1 << var" ...

Code:
let row = py >> 3

let screenbit = py And $07
let ptr = row << 7 Or px
@ptr = DCD screenbit Or @ptr

hi2cout (0,SSD1306_PAGEADDR)
hi2cout (0,row)
hi2cout (0,7)
hi2cout (0,SSD1306_COLUMNADDR)
hi2cout (0,px)
hi2cout (0,127)
hi2cout (64,@ptr)
And you should get another speed improvement by putting the consecutive HI2COUT commands all into one or two HI2COUT commands.
 

stan74

Senior Member
Nice one guys. To me a macro would replace x1=:x2=y1=:y2=:gosub line, with line (x1,y1,x2,y2) but doesn't that take time/code?
hippy, can you show my code modified with yours please as my maths is nostalgia.
Having loads of fun.Programming tron with 2 pixels leaving a trail, border around screen and random pixels for objects,each pixel will have direction -1 0 1 added to x,y co-ords and each pixel will check what's in front then go up/down/left/right depending where the other pixel is.Done it before...it's cool.
 

BESQUEUT

Senior Member
Nice one guys. To me a macro would replace x1=:x2=y1=:y2=:gosub line, with line (x1,y1,x2,y2) but doesn't that take time/code?
I was thinking about plot2screenram:

And you should get another speed improvement by putting the consecutive HI2COUT commands all into one or two HI2COUT commands.
Did you try that ?
Please publish whole code, not only extracts...
 

hippy

Technical Support
Staff member
Visually, it seems twice as fast. shock horror.
There are three main things to do to improve speed of execution for a PICAXE program -

1) Do as little as possible. Use the fewest steps and fewest operations you can and avoid multiplication and division.

2) Use as few lines of code as possible. Put as much as as you can into each command.

3) Remove GOSUB commands and loops. This may mean putting code in #MACRO or otherwise including it in-line which may increase code space.

Of course it is often not as simple as that. If some value, say a variable divided by 10 is used in multiple subsequent commands, it may be best to store that in a separate variable and use that in subsequent commands to avoid multiple divisions. Sometimes it needs gut feeling and other times it needs testing to see which option is fastest.

And note this only applies to speed critical code, such as plotting a line as here. There is little reason 'initialise' and similar cannot be subroutines with GOSUB and even inefficient in how they are written. If code is only run once or infrequently it may add a little time but noting excessive. It is those things which gets called many times a second where effort should be concentrated.

There was nothing wrong with your original code except it wasn't as elegant, efficient and as fast as it could be. Nothing wrong with that; get it working then optimise is the rule. What you had proved and showed exactly what you have to do and then it is just a case of optimisation as above.

Your original code was very useful for showing what the operations boiled down to, and then it is simply a matter of finding the best way to implement that -

Code:
        .-------------------.     .---------------------.
     px | 0 | x x x x x x x |  py | 0 0 | y y y | b b b |
        `-------------------'     `---------------------'
              | | | | | | |               | | |   | | |
      .-------|-|-|-|-|-|-|---------------' | |  .-----.
      | .-----|-|-|-|-|-|-|-----------------' |  | DCD |
      | | .---|-|-|-|-|-|-|-------------------'  `-----'
      | | |   | | | | | | |                         |
      | | |   | | | | | | |                    .----'
      | | |   | | | | | | |             _______|_______
    .-----------------------.         .-----------------.
ptr | y y y | x x x x x x x |     bit | m m m m m m m m |
    `-----------------------'         `-----------------'
 

stan74

Senior Member
I first started using picaxe in September and being new, took a while to discover the commands eg dcd which I hadn't seen.
My plot code was going to be
get py mod 8 some how
if 0 set bit 0 of mask
etc
if 7 set bit 7 of mask
I didn't want ifs in the plot routine ,it being continually repeated.
And calculating the screen byte, screenbyte=((py/8) * 128)+px, is faster with bit wise operators.
I changed the if x1=x1 and y1=y2
to if x1=x2 then if y1=y2...just 1 test.
Multi statements on 1 line are only faster because of the way picaxe basic works. If it compiled to assembler then that wouldn't make any difference and I can't see how a macro is faster, or after using one, any easier than a gosub. Like what's the difference between #macro line (x1,y1,x2,y2) line routine #endmacro
let x1=0:let y1=0:let x2=0:let y2=0
line (x1,y1,x2,y2)
and gosub line?
Why is PE code often posted without the let command which on pe6 gives error?
 

hippy

Technical Support
Staff member
Multi statements on 1 line are only faster because of the way picaxe basic works.
Multiple statements on one line will not usually be faster than statements on separate lines. It is doing things in a single command rather than in separate commands where speed will be gained.


I can't see how a macro is faster, or after using one, any easier than a gosub.
It is not necessarily easier, but it's not necessarily harder. They are simply alternatives, either of which may be most appropriate for the program being written.

The advantage of a macro over a subroutine is that execution is faster, simply because there is no GOSUB or RETURN required to execute the code of the macro. The cost is in using more memory as the code is expanded in-line for each additional use rather than being limited only to the overhead of an additional GOSUB command.

Consider the following examples which must be run on a physical M2 chip. The first uses GOSUB the second uses #MACRO, both increment w0 as many times as they can in 10 seconds -

Code:
#Picaxe 08M2
#Terminal 4800
#No_Data

time = 0
Do : Loop Until time = 2
SerTxd( "Started", CR, LF )
Do
  Gosub IncrementW0
Loop Until time >= 12
SerTxd( "Executed ", #w0, " times", CR, LF )
End

IncrementW0:
  w0 = w0 + 1
  Return

#IfDef SIMULATING
  #Error Must be run on physical PICAXE chip
#EndIf
Code:
#Picaxe 08M2
#Terminal 4800
#No_Data

#Macro IncrementW0
  w0 = w0 + 1
#EndMacro

time = 0
Do : Loop Until time = 2
SerTxd( "Started", CR, LF )
Do
  IncrementW0
Loop Until time >= 12
SerTxd( "Executed ", #w0, " times", CR, LF )
End

#IfDef SIMULATING
  #Error Must be run on physical PICAXE chip
#EndIf
In the first with GOSUB, w0 reaches 2052 in 10 seconds, with #MACRO that becomes 5775. GOSUB can manage around 205 loops per second, #MACRO can manage 577 per second; nearly three times faster.

Where speed of execution is of the essence, code size is secondary to memory used. The faster code can be the better, even if that is only saving the execution time of the GOSUB and the corresponding RETURN. Save enough of those times and it can mean a significant speed improvement.

Macros can also be used to better express coding structure, to save typing, and to make code more readable or understandable. It is not a case of macro or subroutines; each has their place and either can be used as appropriate.


Why is PE code often posted without the let command which on pe6 gives error?
Lack of "LET" should not generate an error in PE6 or other PICAXE software. The "LET" is entirely optional at the start of an assignment statement.

It may be the case however that the presence and absence of LET causes different behaviours in badly formed multi-line statements put on one line. For example -

Code:
If b0 = 0 Then b1 = 1 End If
Does produce an "Expected a label" syntax error where the following does not -

Code:
If b0 = 0 Then Let b1 = 1 End If
That is a result of the compiler doing its best to try and figure out what a badly formed statement should mean, failing in the first case, succeeding in the second. The solution is not to add LET to help the compiler out, but to structure the statement correctly.

A multi-line statement placed on one line should have colons used to separate what would have been the individual lines. When done correctly, as below, both versions will pass syntax checking without error -

Code:
If b0 = 0 Then : b1 = 1 : End If
If b0 = 0 Then : Let b1 = 1 : End If
In generally it is best to always use "LET" or never use "LET" rather than have a mix of both. It is also common for "LET" to be left off as it is entirely optional.
 

AllyCat

Senior Member
Hi,

if x1=x1 and y1=y2
to if x1=x2 then if y1=y2...just 1 test
The first uses 3 mathematical/logic operators (= AND =) and one IF .. THEN. The latter may use only two mathematical operations, but also two IF .. THENs. Generally the IF .. THENs will be slower than math operations because they involve a "jump" (GOTO) in the program flow. Even in PIC assembler, maths operations take one cycle and (conditional) jumps take two cycles.

Multi statements on 1 line are only faster because of the way picaxe basic works.
Are they? I believe the PE will treat them exactly the same. But multiple operators WITHIN a single statement (which I think is what hippy intended) probably WILL be faster.

what's the difference between #macro line (x1,y1,x2,y2) line routine #endmacro let x1=0:let y1=0:let x2=0:let y2=0
line (x1,y1,x2,y2) and gosub line?
The CALL (gosub) and RETURN take around 3,200 PIC (assembler) instruction cycles in addition to the (same) code being executed. That's a very significant time wastage for simpler routines (where duplicatng the code in-line is not a significant issue).

Why is PE code often posted without the let command which on pe6 gives error?
The LET command is optional and rarely (IMHO) used except in "educational" applications. I must admit that I normally use PE5 but would be surprised if PE6 flagged an "error" if the command syntax were otherwise completely correct. Do you have an example?

Cheers, Alan.
 

BESQUEUT

Senior Member
Multiple statements on one line will not usually be faster than statements on separate lines. It is doing things in a single command rather than in separate commands where speed will be gained.
For example :
Code:
hi2cout (0,SSD1306_PAGEADDR)
hi2cout (0,row)
hi2cout (0,7)
hi2cout (0,SSD1306_COLUMNADDR)
hi2cout (0,px)
hi2cout (0,127)
hi2cout (64,@ptr)
hi2cout (0,SSD1306_PAGEADDR,0,row,0,7,0,SSD1306_COLUMNADDR,0,px,0,127,64,@ptr)
 

stan74

Senior Member
f x1=x1 and y1=y2
to if x1=x2 then if y1=y2...just 1 test,,,,,, it skips then if y1=y2 if x1=x2 not true
Gosubs,true,a waste that mounts up and goto. Keep code inline for speed
if a=1 then let a=-1
else let a=1 ,,,,,,,,,,,let a=not a
end if
,
if a=1 then
blah
blah
is slower than
if a=1 then blah;blah:blah?
No let syntax happened.How many times have I typed let,including that let I just typed and the last one,let that be a lesson.
Just installed PE6 on a desktop pc,win 10.Much faster than my laptop.
 
Top