Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Shift Register Timing Issue

Status
Not open for further replies.

tom_pay

Member
Hi

I have built a simple LCD driver circuit using a 6 bit shift register (6x D Flip-Flops). However the timing of the clock pulses is acting very odd!!

If I put the data onto the serial in pin and clock it within 3 µs the screen displays jibberish, if I wait for a total of ~18 µs it works perfectly.

Why is this so?

All of the pulse widths are above minimum values as stated in the data-sheet. So it is not being over-run.

I apologize if I am being a bit vague, but I just have no idea where to start.

Thanks

Tom
 
The clock signal is just the MCU pulsing the clock pin high, for 1 instruction cycle (2 uS), then back to low.

When I checked a signal created in the same way, just in astable mode, and it was nice and clean.

Tom
 
Hi

This Here works

Code:
for(i = 0; i < 6; i++)
{
if (0 != ((1 << 5) & dataout))
{
Data = 1;
}
else
{
Data = 0;
}
dataout = dataout << 1;

CLK = 1;
CLK = 0;
}

And this here doesn't :-(

Code:
for(i = 0; i < 6; i++)
{
if (0 != ((1 << 5) & dataout))
{
Data = 1;
}
else
{
Data = 0;
}
CLK = 1;
CLK = 0;

[B]dataout = dataout << 1;[/B]
}

Tom
 
Last edited:
Big difference there.

In the top loop, you're shifting your "register" (dataout) before strobing the clock; in the second loop, you're reversing the order.

Don't you think this might have something to do with the way your circuit responds?
 
Big difference there.
The only difference is in the timing before applying the clock (data setup time).

So you are using an HD44780 based LCD?

How is the enable pin driven? If you're just connecting all flipflop lines directly to the LCD I can imagine there'll be some issues as you shift the data (& rs) through past the enable pin. Can you post a schematic?
 
Hi

The LCD data-sheet says that it is driven by a HD44780 compatible chip.

The enable pin is driven with a AND gate (diode and resistor), it gets one high from the shift register and one from the data pin once it has finished inputting the data.

I tried this code last night and it also worked....

Code:
for(i = 0; i < 6; i++)
{
if (0 != ((1 << 5) & dataout))
{
Data = 1;
}
else
{
Data = 0;
}

[B]15 µs Timer[/B]

CLK = 1;
CLK = 0;

dataout = dataout << 1;
}

I will go and scan the schematic now.

Tom
 
Hi

Here is the rest of the LCD code....

Code:
Data = 0;

for (i = 0; i < 6; i++)
{
CLK = 1;
CLK = 0;
}

dataout = dataout | (1 << 5) | ( (RS & 1) << 4);

for(i = 0; i < 6; i++)
{
if (0 != ((1 << 5) & dataout))
{
Data = 1;
}
else
{
Data = 0;
}
dataout = dataout << 1;

CLK = 1;
CLK = 0;
}

Data = 1;
Data = 0;

and the schematic is attached, sorry for the dodgy quality.

Tom
 

Attachments

  • SCAN0009.jpg
    SCAN0009.jpg
    248.3 KB · Views: 145
Um.. sorry to say that it all looks ok to me...

The only LCD timing parameter that is close to the magnitude of your instruction cycle period (what, 1us?) is the minimum enable period (which is 1000ns = 1us). The shift register should have no issues with any clock rate the pic can give it.

From the working & nonworking code snippets you posted, it looks like data takes a little while to settle or something. Anyway, sorry again, I can't provide any insight whatsoever.
 
You don't say what processor you are using.

Can you possibly post the assembly code that the C compiler produces?

I suspect that

Code:
Data = 0;
}
CLK = 1;

compiles to

Code:
    BCF    PORTN,  A
some_random_label
    BSF    PORTN, B

so if that cycle is outputting a low, those two lines are executed one after the other and you have a read-modify-write problem.

Even a single line delay is enough to prevent the problem, and the

Code:
dataout = dataout << 1;

is providing that delay.

https://www.cornerstonerobotics.org/curriculum/lessons_year2/erii_rmw_problem.pdf
 
Last edited:
Ahhhhhhhhhhh, You might be onto something.

I'm using a PIC 16F684.

Here is some ASM code, I think!!!!! I have no idea what ASM is about sorry.

Code:
; *************** function _LCDWriteSUB *****************
; Defined at:
;		line 22 in file "C:\Documents and Settings\Administrator\My Documents\Electronics\PIC Evil Genius\Experiments\2 Bit LCD\Basic.c"
; Parameters:    Size  Location     Type
;  dataout         2    0[BANK0 ] int 
;  RS              2    2[BANK0 ] int 
; Auto vars:     Size  Location     Type
;		None
; Return value:  Size  Location     Type
;                  2    0[BANK0 ] int 
; Registers used:
;		wreg
; Tracked objects:
;		On entry : 0/0
;		On exit  : 0/0
;		Unchanged: 0/0
; Data sizes:     COMMON   BANK0   BANK1
;      Locals:         5       4       0
;      Temp:     5
;      Total:    9
; This function calls:
;		Nothing
; This function is called by:
;		_LCDWrite
; This function uses a non-reentrant model
; 
psect	text30
	file	"C:\Documents and Settings\Administrator\My Documents\Electronics\PIC Evil Genius\Experiments\2 Bit LCD\Basic.c"
	line	22
	global	__size_of_LCDWriteSUB
	__size_of_LCDWriteSUB	equ	__end_of_LCDWriteSUB-_LCDWriteSUB
;Basic.c: 21: LCDWriteSUB(int dataout, int RS)
;Basic.c: 22: {
	
_LCDWriteSUB:	
	opt stack 5
; Regs used in _LCDWriteSUB: [wreg]
	line	23
	
l30000388:	
;Basic.c: 23: RA4 = 0;
	bcf	status, 5	;RP0=0, select bank0
	bcf	(44/8),(44)&7
	
l30000389:	
	line	25
;Basic.c: 25: for (i = 0; i < 6; i++)
	movlw	low(0)
	movwf	(_i)
	movlw	high(0)
	movwf	((_i))+1
	
l11:	
	line	27
;Basic.c: 26: {
;Basic.c: 27: RA5 = 1;
	bcf	status, 5	;RP0=0, select bank0
	bsf	(45/8),(45)&7
	line	28
;Basic.c: 28: RA5 = 0;
	bcf	(45/8),(45)&7
	
l30000391:	
	line	25
	movlw	low(01h)
	addwf	(_i),f
	skipnc
	incf	(_i+1),f
	movlw	high(01h)
	addwf	(_i+1),f
	movf	(_i+1),w
	xorlw	80h
	movwf	(??_LCDWriteSUB+0+0)
	movlw	(high(06h))^80h
	subwf	(??_LCDWriteSUB+0+0),w
	skipz
	goto	u155
	movlw	low(06h)
	subwf	(_i),w
u155:

	skipc
	goto	u151
	goto	u150
u151:
	goto	l11
u150:
	
l30000392:	
	line	31
;Basic.c: 29: }
;Basic.c: 31: dataout = dataout | (1 << 5) | ( (RS & 1) << 4);
	movlw	low(01h)
	bcf	status, 5	;RP0=0, select bank0
	andwf	(LCDWriteSUB@RS),w
	movwf	(??_LCDWriteSUB+0+0)
	movlw	high(01h)
	andwf	(LCDWriteSUB@RS+1),w
	movwf	1+(??_LCDWriteSUB+0+0)
	movlw	04h
	movwf	(??_LCDWriteSUB+2+0)
u165:
	clrc
	rlf	(??_LCDWriteSUB+0+0),f
	rlf	(??_LCDWriteSUB+0+1),f
	decfsz	(??_LCDWriteSUB+2+0),f
	goto	u165
	movf	(LCDWriteSUB@dataout),w
	iorwf	0+(??_LCDWriteSUB+0+0),w
	movwf	(??_LCDWriteSUB+3+0)
	movf	(LCDWriteSUB@dataout+1),w
	iorwf	1+(??_LCDWriteSUB+0+0),w
	movwf	1+(??_LCDWriteSUB+3+0)
	movlw	020h
	iorwf	0+(??_LCDWriteSUB+3+0),w
	movwf	(LCDWriteSUB@dataout)
	movf	1+(??_LCDWriteSUB+3+0),w
	movwf	1+(LCDWriteSUB@dataout)
	line	33
;Basic.c: 33: for(i = 0; i < 6; i++)
	movlw	low(0)
	movwf	(_i)
	movlw	high(0)
	movwf	((_i))+1
	
l14:	
	line	35
;Basic.c: 34: {
;Basic.c: 35: if (0 != ((1 << 5) & dataout))
	bcf	status, 5	;RP0=0, select bank0
	btfss	(LCDWriteSUB@dataout),(5)&7
	goto	u171
	goto	u170
u171:
	goto	l17
u170:
	
l30000394:	
	line	37
;Basic.c: 36: {
;Basic.c: 37: RA4 = 1;
	bsf	(44/8),(44)&7
	goto	l30000395
	
l17:	
	line	41
;Basic.c: 39: else
;Basic.c: 40: {
;Basic.c: 41: RA4 = 0;
	bcf	(44/8),(44)&7
	
l30000395:	
	line	43
;Basic.c: 42: }
;Basic.c: 43: dataout = dataout << 1;
	movf	(LCDWriteSUB@dataout+1),w
	movwf	(??_LCDWriteSUB+0+0+1)
	movf	(LCDWriteSUB@dataout),w
	movwf	(??_LCDWriteSUB+0+0)
	movlw	01h
	movwf	(??_LCDWriteSUB+2+0)
u185:
	clrc
	rlf	(??_LCDWriteSUB+0+0),f
	rlf	(??_LCDWriteSUB+0+1),f
	decfsz	(??_LCDWriteSUB+2+0),f
	goto	u185
	movf	0+(??_LCDWriteSUB+0+0),w
	movwf	(LCDWriteSUB@dataout)
	movf	1+(??_LCDWriteSUB+0+0),w
	movwf	(LCDWriteSUB@dataout+1)
	
l30000396:	
	line	45
;Basic.c: 45: RA5 = 1;
	bsf	(45/8),(45)&7
	
l30000397:	
	line	46
;Basic.c: 46: RA5 = 0;
	bcf	(45/8),(45)&7
	line	33
	movlw	low(01h)
	addwf	(_i),f
	skipnc
	incf	(_i+1),f
	movlw	high(01h)
	addwf	(_i+1),f
	movf	(_i+1),w
	xorlw	80h
	movwf	(??_LCDWriteSUB+0+0)
	movlw	(high(06h))^80h
	subwf	(??_LCDWriteSUB+0+0),w
	skipz
	goto	u195
	movlw	low(06h)
	subwf	(_i),w
u195:

	skipc
	goto	u191
	goto	u190
u191:
	goto	l14
u190:
	
l15:	
	line	49
# 49 "C:\Documents and Settings\Administrator\My Documents\Electronics\PIC Evil Genius\Experiments\2 Bit LCD\Basic.c"
nop ;#
psect	text30
	line	50
;Basic.c: 50: RA4 = 1;
	bcf	status, 5	;RP0=0, select bank0
	bsf	(44/8),(44)&7
	line	51
# 51 "C:\Documents and Settings\Administrator\My Documents\Electronics\PIC Evil Genius\Experiments\2 Bit LCD\Basic.c"
nop ;#
psect	text30
	line	52
;Basic.c: 52: RA4 = 0;
	bcf	(44/8),(44)&7
	
l10:	
	return
	opt stack 0
GLOBAL	__end_of_LCDWriteSUB
	__end_of_LCDWriteSUB:
; =============== function _LCDWriteSUB ends ============

Thanks so much for your help everyone.

Tom
 
I think that you just sent me the working version.

If I remove the dataout = dataout << 1 line and its code, one part reads

Code:
	line	41
;Basic.c: 39: else
;Basic.c: 40: {
;Basic.c: 41: RA4 = 0;
	bcf	(44/8),(44)&7   ; This clears bit 4 in port 5
	

l30000396:	
	line	45
;Basic.c: 45: RA5 = 1;
	bsf	(45/8),(45)&7 ; This sets bit 5 in port 5

Now they are not always run like that, because there is often a jump to l30000396

However if they are run one after the other like that, then bit 4 is set at the end of the first instruction.
Right at the start of the second instruction, only 1 cycle of the processor clock later, the whole of port 5 is read. The voltage on that pin will still be low so the reading will have bit 4 low.

Then bit 5 is set in the Arithmetic Logic Unit. All other bits are unaffected, but bit 4 is low.

Then the value is transferred to the port, taking bit 5 high, and taking bit 4 low again.

I am disappointed that your compiler lets that happen. It took 15 lines to do dataout = dataout << 1 which would be 1 line if written in assembler, so space is not an issue and it should never put two bit operations adjacent on the same port, where the bit numbers are different.
 
Ok,

I get the general idea of what you are saying, but this code just seems so complicated!!

If I had written this in assembler rather than C, would this problem not have occurred? If so is assembler hard to learn from C?

Thank-you for your help, you are a really good teacher.

Tom
 
The problem could easily have occoured in assembler, but it would be easier to see where it was happening, and easier to arrange that the lines were not adjacent.

In assembler, you can easily write

nop

to put in a line that does nothing but takes one cycle to execute.

I was surprised that the C compiler let it happen.

I think that an understanding of assembler, which is what the C complier produces, along with an idea of the actual hardware, is useful when writing in C.

The assembler produced by a complier is much more difficult to read than assembler written by a person, because a person will use friendly names for registers and labels. There may even be comments to help understand it.

For instance, the compiler has written:-
bsf (45/8),(45)&7

where in assembler I might have written:-
bsf Clock_port, clock ;raise clock line.

(having defined Clock_port, and clock earlier in the code)

Both of those assemble to the same instruction.
 
First I must admit I have not read the entire thread. Just the last bit.

You could have run the program in MPLAB simulator and used the Logic Analyzer to see that the LCD's timing parameters were violated.

A real LA is a nice tool to have too.
 
I think I might have to look into this assembler language.

I had simulated the program many many times before and after programming.

Thanks for your help,

Tom
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top