please dont rip this site

Massmind news letter, January 2003

In this months issue of the Massmind newsletter:

These items will appear on the site in a month or so, but you get them first with a subscription to the newsletter!

Welcome to the first edition of the massmind SXList newsletter!

Sacrificing a bit to save a nibble.

While laying out the registers for an application, I needed a counter for shifting out bits (count from 8 to zero) and so I allocated a byte in the global register space and dismissed the missgiving I had about wasting the top 5 bit of the byte. I really needed a lot of speed for the routine that was shifting out the bits so I didn't want to mask off the top x bits to test for zero.

As it turned out, I didn't run out of registers, I ran out of code space.

Reviewing the code, I realized that I was spending a lot of code bank switching between buffer head and tail pointers that I hadn't quite been able to squeeze into global space and the bank where the buffer was actually stored. Finding some more global memory would help reduce the code size.

I had one byte of global space allocated to flags, and only 5 bits used. I re-checked the bits and found that I could move one to a bank without any additional code so that left 4 bits to find a home for. I though of that short counter, but reviewing the VP code convinced me that I just could not afford to check for zero with any extra instructions. The original analysis of the job was based on how fast we could shift out those bits and I specified an SX at 75MHz and had written the bit shifting code in my head at the time.

I started thinking about how to tell if a part of a byte has reached zero and eventually realized that when the lower 3 bits were decremented from 0, the 4th bit would be cleared and that could be used to test for zero!

xxxx1111 dec
xxxx1110 dec
... and so on until
xxxx1000 dec
xxxx0111

And I realized that I could reload the counter simply by setting the 4th bit! No need to load a literal value. I moved the remaining 4 flag bits into the top of the "Half counter" byte and rewrote the bit code (which now had less of a delay between bytes for a small increase in the overall bitrate).

Since then, I've seen a number of cases where this trick has been of great value. I've used it to dispatch VP's when one needed to be executed once for every 4 interrupts (for example) by checking the second bit. Well, on that one you do have to check the bottom bit as well... Another use was when I needed to check for the occurance of 2 different things, but I didn't care what order they came in. I decremented once when I found one type, twice when I found another. I could do a single bit check to see which had arrived (so as to not accept two of the same thing) but still just do a single bit test to check for the arrival of both signals.

One of these days, I'll write a macro to automatically compile the best code for any FOR start TO end type loop.

Better jump tables through bit testing

When you need a jump table (not a lookup table; iread is better for that) for 4 or fewer routines, bit testing is actually more efficient than adding an offset to the PC and then jumping from there.

Since I am (as Peter said) a "macro freak" I wrote the following macros for SASM to automatically compile bit tests and jumps for up to 8 addreses (based on the value of the bottom 3 bits of a register). It is almost as good as a jump table at that size, and better below that. The macros start with binjmp2 which only accepts two different labels and one bit. For example:

binjmp2 status.c, carry, nocarry

and will generate:

 jnb flag, first
 jmp second

It assumes that an equate called pageaddr is set to the current page and if one of the destinations is outside this page, it generates "long" jumps with the @ before the label instead.

binjmp2 MACRO index, one, two
;assumes that pageaddr is set to current value of page bits on entry.
 noexpand
 pageaddr = $>>9
 ifdef one
  if (pageaddr == one >> 9)
   expand
 jnb index.0,one
   noexpand
  else
   pageaddr = $ >> 9
   expand
 jnb index.0,@one
   noexpand
   endif
 else
   pageaddr = $ >> 9
  expand
 jnb index.0,@one
  noexpand
  endif
 ifdef two
  if (pageaddr == two >> 9)
   expand
 jmp two
   noexpand
  else
   pageaddr = $ >> 9
   expand
 jmp @two
   noexpand
   endif
 else
  pageaddr = $ >> 9
  expand
 jmp @two
  noexpand
  endif
 endm

With this routine under our belt, we can build binjmp4 which calls it twice for 4 addresses or once for 3 or 1 and takes care of the other address itself. There is some tricky page bit testing here based on the routine knowing that the next set of bit tests can't be more than a certain distance away. It works, trust me (he says)

binjmp4 MACRO index, one, two, three, four
	local :1set
;assumes that pageaddr is set to current value of page bits on entry.
 if (pageaddr == ($+9)>>9) ;:1set can't be more than 9 words away.
  expand
 jb index.1, :1set
  noexpand
 else
  expand
 sb index.1 
 page :1set
 jmp :1set
  noexpand
  endif
 binjmp2 index, one, two
 expand
:1set
 noexpand
 pageaddr = $ >> 9	;can't get here except by jump and so must be paged
 binjmp2 index, three, four
 endm

Now! we can get crazy and build one that handles any number of jumps by calling binjmp4 or binjmp2 and takeing care of the odd lable itself. This also sets the page and the pageaddr value so we don't have to think about anything! To use it, just enter
BinJump <reg>, <Address> [, <Address>]
where <reg> is the first parameter of the register to tbe tested and the following parameters are a list of addresses to jump to based on the value of the register.

binjump MACRO
 local :2Set, :1Set, parms, index
parms = \0 - 1
index = \1
;Call with the first parameter of the register to tbe tested and
;the following parameters a list of addresses to jump to based on
;the value of the register.
;More effecient than a long jump table for 4 or fewer addresses
 expand
 page $
 noexpand
 pageaddr = $ >> 9
 if parms > 4
  if parms == 5
   expand
 jb \1.2, @\6	;=4
   noexpand
   binjmp4 \1,\2,\3,\4,\5
  else ;6 or more
   if (pageaddr == ($+19)>>9)
    expand
 jb \1.2, :2Set ;>4 ;@$+16
    noexpand
   else
    expand
 sb \1.2 
 page :2set
 jmp :2set ;>4 ;@$+16
    noexpand
    endif
   binjmp4 \1,\2,\3,\4,\5
   expand
:2Set
   noexpand
   pageaddr = $ >> 9	;can't get here except by jump and so must be paged
   if parms > 6
    if parms > 7
     binjmp4 \1,\6,\7,\8,\9
    else ;7
     expand
 jb \1.2, @\8 ;=2 or 6
     noexpand
     binjmp4 \1,\2,\3,\6,\7
     endif
   else ;6
    binjmp2 \1,\6,\7
    endif
   endif
 else ;4 or less
  if parms > 2
   if parms == 3
    expand
 jb \1.1, @\4 ;=2 or 6
    noexpand
    binjmp2 \1,\2,\3
   else ;4
    binjmp4 \1,\2,\3,\4,\5
    endif
 else ;2
  binjmp2 \1, \2, \3
  endif
 endif
 endm

There is also a GotoW macro at

http://www.sxlist.com/techref/ubicom/sasmcond.src that compiles either a binjmp or a regular jump table based on the number of addresses and does some tricky testing for pageing.

Nokia LCD interface code

sxlist.com member BCI-hotmail-K96 added some code for the PIC16F84a to interface to the graphic LCD module LPH 7366-1 used in the Nokia 5110 cell Phone. These are very nice little LCD modules available for about $25 on ebay and all over the web.. This is a High-resolution, illuminated, graphical display; Up to 5 lines for text, numbers, graphics; Dynamic display for large/small font. It uses a PCD8544 48 x 84 pixels matrix LCD controller/driver. Beats the hell of of the other "serial LCD units" available. All the info is at http://sandiding.tripod.com/lcd.html including the wireing, power supply, etc...

Running the  through the Code converter from MPASM to SASM at:
http://www.sxlist.com/cgi-bin/mpasm2sasm2.exe gives us the following which should be ready to go with only a few tweaks. If anyone tries it, please let me know.

;=======LCD_Nokia nse1,nse3,nsm1 / Version 10====================$21/$12/$02==
;	cod LPH7366-$1 / driver PCD8544
;	rb6,rb7     sclock,sdata
;	ra0,ra1,ra2,ra3	d/C,Reset,Vccmd,SCE
;     internal clock
;     standard crystal 4000 MHz XT - 1us pe instructiune/pe aproape
;	Program realizat de Ing. Bergthaller Iulian-Alexandru
;------------------------------------------------------------
	list	p=$16f84A;f=inhx8m
_CP_OFF	equ	$3FFF	;code protect off
_PWRTE_ON	equ	$3FFF	;Power on timer on
_WDT_OFF	equ	$3FFB	;watch dog timer off
_XT_OSC	equ	$3FFD	;crystal oscillator
	__CONFIG       _CP_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC
;------------------------------------------------------------
;      cpu init
porta	equ	$05
portb	equ	$06
count1	equ	$0C
count2	equ	$0D
count3	equ	$0E
afisaj	equ	$0F

;LPH7366 pinout:
;      pin1     V+
;      pin2     Sclk
;      pin3     Sda
;      pin4     DorC
;      pin5     Cs
;      pin6     Osc (32768Hz external clock)
;      pin7     Gnd
;      pin8     Vout(DC/DC voltage converter)
;      pin9     Reset

#DEFINE sclk	portb,$6
#DEFINE sdta	portb,$7
#DEFINE dorc	porta,$0
#DEFINE rset	porta,$1
#DEFINE tens	porta,$2
#DEFINE enab	porta,$3
;------------------------------------------------------------
;      bit init
w	equ	$0
;------------------------------------------------------------
	org	$0
;
;------------------------------------------------------------
init
	mov	W, #$0
;*** WARNING: TRIS expanded in two instructions. Check if previous instruction is a skip instruction.
;	tris    portb ; set portb as output
	; set portb as output
	mov	Rb, W	; all ouput low
	mov	W, #$0
;*** WARNING: TRIS expanded in two instructions. Check if previous instruction is a skip instruction.
;	tris    porta ; set portb as output
	; set portb as output
	mov	Ra, W	; all ouput low
start	call	pause
	setb	dorc
	setb	enab
	setb	tens	;activare tensiune
	call	lcres	;resetare cca. 250ms
	mov	W, #21H	;set extins
	mov	afisaj, W
	call	lccmd
	mov	W, #197	;Vop
	mov	afisaj, W
	call	lccmd
	mov	W, #13H	;bias
	mov	afisaj, W
	call	lccmd
	mov	W, #20H	;afisare orizontala
	mov	afisaj, W
	call	lccmd
	mov	W, #09H	;mod control all on
	mov	afisaj, W
	call	cbild	;resetare DDRAM
	call	lccmd
	call	pause
	mov	W, #08H	;mod control blank
	mov	afisaj, W
	call	lccmd
	call	pause
	mov	W, #0CH	;mod control normal
	mov	afisaj, W
	call	lccmd
	mov	W, #40H	;x ini
	mov	afisaj, W
	call	lccmd
	mov	W, #80H	;y ini
	mov	afisaj, W
	call	lccmd
adata	mov	W, #1FH	;date
	mov	afisaj, W
	call	lcdta
	mov	W, #05H	;date
	mov	afisaj, W
	call	lcdta
	mov	W, #07H	;date
	mov	afisaj, W
	call	lcdta
	jmp	adata
lcdta	setb	dorc
	clrb	enab	;activare chip si start date
	call	varsa
	setb	enab
	retw	$00
lccmd	clrb	dorc
	clrb	enab	;activare chip si start date
	call	varsa
	setb	enab
	retw	$00
lcres	clrb	rset	;resetare
	call	pause
	setb	rset	;dezactivare reset
	retw	$00
varsa	clrb	sclk
	snb	afisaj.$7	;bit0(MSB)
	setb	sdta
	sb	afisaj.$7
	clrb	sdta
	call	halta
	setb	sclk
	call	halta
	clrb	sclk
	snb	afisaj.$6	;bit1
	setb	sdta
	sb	afisaj.$6
	clrb	sdta
	call	halta
	setb	sclk
	call	halta
	clrb	sclk
	snb	afisaj.$5	;bit2
	setb	sdta
	sb	afisaj.$5
	clrb	sdta
	call	halta
	setb	sclk
	call	halta
	clrb	sclk
	snb	afisaj.$4	;bit3
	setb	sdta
	sb	afisaj.$4
	clrb	sdta
	call	halta
	setb	sclk
	call	halta
	clrb	sclk
	snb	afisaj.$3	;bit4
	setb	sdta
	sb	afisaj.$3
	clrb	sdta
	call	halta
	setb	sclk
	call	halta
	clrb	sclk
	snb	afisaj.$2	;bit5
	setb	sdta
	sb	afisaj.$2
	clrb	sdta
	call	halta
	setb	sclk
	call	halta
	clrb	sclk
	snb	afisaj.$1	;bit6
	setb	sdta
	sb	afisaj.$1
	clrb	sdta
	call	halta
	setb	sclk
	call	halta
	clrb	sclk
	snb	afisaj.$0	;bit7(LSB)
	setb	sdta
	sb	afisaj.$0
	clrb	sdta
	call	halta
	setb	sclk
	call	halta
	clrb	sclk
	retw	$00
cbild	clrb	sdta
	mov	W, #6
	mov	count3, W
c3	mov	W, #84
	mov	count1, W
c1	mov	W, #8
	mov	count2, W
	setb	dorc
	clrb	enab
c2	clrb	sclk
	nop
	nop
	setb	sclk
	decsz	count2
	jmp	c2
	setb	enab
	decsz	count1
	jmp	c1
	decsz	count3
	jmp	c3
	retw	$00
pause	mov	W, #7
	mov	count3, W
d3	mov	W, #50
	mov	count1, W
d1	mov	W, #250
	mov	count2, W
d2	decsz	count2
	jmp	d2
	decsz	count1
	jmp	d1
	decsz	count3
	jmp	d3
	retw	$00
halta	mov	W, #20H
	mov	count1, W
g1	mov	W, #40H
	mov	count2, W
g2	decsz	count2
	jmp	g2
	decsz	count1
	jmp	g1
	retw	$00
;------------------------------------------------------------
	end
;============================================================

By the way did you know how Nokia got that name? Its the sound made by the siamese twin elephants (joined at the trunk) whenever they tried to trumpet.

Code Challange

Can you find a faster way to convert a bit number into a mask for that bit? Hint: it can be done faster with tables. I like this routine because it doesn't need a table and so avoids pageing issues.

	;build mask from fsr.1-3 (8 words, 8 cycles)
	mov	w,#1	;mask = (fsr && 2) ? 4 : 1
	sb	fsr.1
	 mov	w,#4
	mov	mask,w
	sb	fsr.2	;if (fsr && 4) mask = mask << 4
	 swap	mask
	sb	fsr.0	;if (fsr && 1) mask = mask << 1
	 rl	mask

Question of the month

Why is each higher baud rate twice as fast until 14.4K which is only 1.5 times faster than 9600?

115,200
 57,600
 28,800
 14,400
    ?
  9,600
  4,800
  2,400
  1,200
    600
    300
	

Feedback:

Please do comment on any errors, improvments, confusions or ideas that are found in this letter.

Thanks!

---
James Newton, Host of SXList.com
james@sxlist.com 1-619-652-0593 fax:1-208-279-8767
SX FAQ / Code / Tutorials / Documentation: 
http://www.sxlist.com Pick faster!


file: /Techref/new/letter/news0201.htm, 15KB, , updated: 2008/1/22 09:35, local time: 2024/12/26 09:49,
TOP NEW HELP FIND: 
3.144.95.167:LOG IN

 ©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE!

<A HREF="http://linistepper.com/Techref/new/letter/news0201.htm"> Massmind news letter, January 2003</A>

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type a nice message (short messages are blocked as spam) in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.


Link? Put it here: 
if you want a response, please enter your email address: 
Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
Did you find what you needed?