Ruth Hendrix

newbie [help] interfacing HC08 with CD4021BCN

Discussion created by Ruth Hendrix Employee on Jan 24, 2006
This message contains an entire topic ported from a separate forum. The original message and all replies are in this single message. We have seeded this new forum with selected information that we expect will be of value to you as you search for answers to your questions.
 
Posted: Sun Sep 25, 2005 1:56 am    
 
Hi, I'm using a HC08ab32 connected to a 8-Stage Static Shift Register
CD4021BCN serially. The Shift register is connected to a DIP switch. I
wanted to get the parallel-in data from the DIP switch. Do i need to
do it using the i2c method or other method? are there any example out
there for me to refer to? Thank you.
 
Posted: Sun Sep 25, 2005 1:30 pm
 
To interface with the 4021 shift register device, you will need to use the Serial Peripheral Interface (SPI) facility within the 908. The 908 will be the master, and the shift register the slave.

The Q8 output at pin 3 will connect to MISO, and the clock input at pin 10 will connect to SPSCK. You will also need to allocate an output from general purpose I/O to connect to pin 9 of the shift register, to provide a serial select signal. Connect the serial input at pin 11 to ground. You will need to decide whether the DIP switches should pull their inputs high or low when active, and provide either pull-down or pull-up resistors.

Note that the MOSI pin on the 908 will not be used for this application, and the /SS pin would be configured for general I/O. For the 4021 device operating at 5 volts, the SPI clock rate may not exceed 2.5 MHz.

During the initialisation routine for the 908 you will need to set the SPCR and SPSCR registers to suitable values. I assume that you would use a polling process (rather than interrupt) to access the DIP switch data, so I believe appropriate values would be:

MOV #$32,SPCR
MOV #$01,SPSCR

Look in the data sheet to see what each bit in these registers controls. To read the DIP switch data you will need to:

1. Set serial select output low using a BCLR instruction.
2. Write a dummy value to the SPDR register.
3. Wait for bit-7 of SPSCR to become set, to indicate new data in the receive buffer.
4. Read the SPDR register for the current DIP switch data.
5. Set serial select output high using BSET instruction.

BCLR SSEL,PTx
STA SPDR
BRCLR 7,SPSCR,$ ; Wait while bit is low
LDA SPDR ; DIP switch data in ACC
BSET SSEL,PTx

I hope this helps.

Regards,
Posted: Mon Sep 26, 2005 5:29 am    
 
Hi .. thanks for the reply, but I'm facing another problem that my SPI port is already used up. I only have i/o ports connected to the 4021. Can i still do it by using the i/o ports to manipulate it? thanks.
 
Posted: Mon Sep 26, 2005 10:14 am    
 
Hi.. I've come out with a solution. It seems to work. Efficiency I'm not very sure. Due to lack of SPI port.. I used i/o port for this. Here is my code.

Code:

chkaddr        bclr  I2CSDA,DDRH
               bset  PARSERSEL,PORTC
               jsr   i2del
               mov   #$08,BITCNT
               
chkaddr1       bset  I2CSCL,PORTC
               jsr   i2del
               lda   PORTH
               and   #$01
               ora   CARDADDR
               sta   CARDADDR
               lda   BITCNT
               cmp   #$01
               beq   chkaddr2
               asl   CARDADDR
chkaddr2       bclr  I2CSCL,PORTC
               jsr   i2del
               bclr  PARSERSEL,PORTC
               
               dec   BITCNT
               bne   chkaddr1
               
               rts

Are there any room to improve it? thanks.
 
Posted: Mon Sep 26, 2005 1:39 pm    
 
Be aware that the SPI port can usually be shared with multiple serial peripherals, so to say it is "used up" may not necessarily be true.

There are two possible aproaches to expanding the use of the SPI. Of course there is also the "bit banging" approach that will also work, but will consume more of the spare I/O, and will occupy many more bus cycles.

1. You may daisy-chain the shift register with other serial output shift registers, to increase the length of the chain. This requires that the other device has a serial input for expansion purposes.

2. You may connect a parallel shift register chain. In this case, each slave chain would have a separate slave select (SS) input that would cause its output to MISO to be high impedance when inactive. In your case, a different device would be necessary, such as the 74HC589 shift register.

To comment on your suggested "bit-banging" code - I will assume the following usage:
PARSERSEL,PORTC connects to pin 9 of the S/R,
I2CSDA is at 0,PORTH and is used as data input from the S/R,
I2CSCL,PORTC is your clock output,
Sub-routine 'i2del' provides a few cycles delay (and preserves the state of X and ACC).

a) According to my data book, the 4021 is in serial mode when PARSERSEL is low - but you set it high prior to the serial transaction, and set it low afterwards. This would seem to prevent the S/R from shifting the data out.

b) To test the state of a single bit within a register, be aware that the BRSET and BRCLR instructions set the carry flag in accordance with the current state of the bit. This can result in a significant simplification of the code.

c) You will need to test the bit state prior to the first shift clock, otherwise you will lose the first (most significant) bit from the S/R.

d) There are other minor variations that improve speed or code efficiency, e.g. use X register for your bit count, use ACC for your data byte, and utilise the DBNZ instruction for the loop.

The modified routine might look like the following:
Code:

CHKADDR: BCLR  I2CSDA,DDRH     ; This should really be part of POR initialisation
         BCLR  I2CSCL,PORTC    ; Initialise clock state
         BCLR  PARSERSEL,PORTC ; Serial mode for S/R
         LDX   #8              ; Bit count value
               
CHK1:    BRSET I2CSDA,PORTH,$+3 ; Set/clear carry
         ROLA                  ; store bit state
         BSET  I2CSCL,PORTC    ; Generate clock pulse
         JSR   i2del           ; small delay
         BCLR  I2CSCL,PORTC
         DBNZX CHK1            ; Loop for next bit

         STA   CARDADDR
         BSET  PARSERSEL,PORTC ; Return S/R to parallel mode
         RTS


I hope this is of assistance to you.

Regards,
Posted: Tue Sep 27, 2005 2:37 am    
 
Quote:
a) According to my data book, the 4021 is in serial mode when PARSERSEL is low - but you set it high prior to the serial transaction, and set it low afterwards. This would seem to prevent the S/R from shifting the data out.


Ininitally I set it to get the parallel data from the DIP switch. The wierd this is if is do it as below
Code:
               bset  PARSERSEL,PORTC
                        jsr   i2del
                        bclr   PARSERSEL,PORTC

I will miss the 1st data. I've to remain the PARSERSEL set till the entire process completed then clr it. In this case then I will only be able to get the entire set of data from the DIP switch.


another thing i don't understand is
Code:

BRSET I2CSDA,PORTH,$+3 ; Set/clear carry


As i'm using codewarrior compiler It couldn't recognise the $+3. I'm not sure about its operation. Could you please explain to me?

basically I found that the example code you gave me is far more efficient than mine. lol... thanks for the help man!
 
Posted: Tue Sep 27, 2005 3:16 pm    
 
Quote:

Ininitally I set it to get the parallel data from the DIP switch. The wierd this is if is do it as below
Code:
 
     bset  PARSERSEL,PORTC
     jsr   i2del
     bclr  PARSERSEL,PORTC

I will miss the 1st data. I've to remain the PARSERSEL set till the entire process completed then clr it. In this case then I will only be able to get the entire set of data from the DIP switch.

In the code example I gave previously, I was assuming that PARSERSEL would be set high during initialisation, and set low only during the serial data transfer. However, pulsing PARSERSEL high just prior to the serial operation should be equally valid, provided it remains low during during the serial transfer.

Are you saying that this did not work? When you refer to "miss the 1st data", do you mean the first data bit? If so, it is probably because your initial subroutine sent a clock pulse prior to reading the state of Q8. My sample routine reads the bit state before generating the first clock pulse.

Keep in mind that, if the ON state of each switch grounds its input (you are using pull-up resistors), the data byte will be negated. Maybe this is causing some confusion.

Holding PARSERSEL high during the serial transfer would cause the state of the switch at the P8 position to fill the whole byte.

Quote:

another thing i don't understand is
Code:
 
BRSET I2CSDA,PORTH,$+3 ; Set/clear carry

As i'm using codewarrior compiler It couldn't recognise the $+3. I'm not sure about its operation. Could you please explain to me?

Sorry about that. I am using the P&E assembler, and it interprets the dollar sign here as "the current program counter value" (at the start of the instruction). Since the BRSET instruction is three bytes long, "$+3" represents the start of the next (ROLA) instruction.

You will need to place a label preceeding the next instruction, and branch to that label. Since the BRSET instruction is only being used to set or clear the carry flag, we need to end up at the next instruction whether or not the branch is taken.

I hope this clarifies the situation.

Regards,
Posted: Wed Sep 28, 2005 3:18 pm    
 
Now i understand the whole picture. Thanks a lot man... appreciate you help along the way... Very Happy

Outcomes