EmbeddedRelated.com
Forums

I2C question??

Started by elalex_76 May 12, 2006
Hello, i had been trying to work with MC9S12DP256B board and SRF08
sensor that makes use of the I2C bus, pins j6 and j7 ,SDA & SCL. I
haven't been able to communicate with the device. I have included the
.asm file, so if anyone can take a look at it and advice me on what
i'm doing wrong.
What i'm trying to do in this code, is to change the address of the
slave(SRF08). In order to change the address i need to write 0xA0,
0xAA, 0xA5 and the new address 0xE4 to the command register in the SRF08.
The reason that i'm trying to change the address is because it uses
the write command to the I2C bus. If i am able to change the address,
then i am able to comunicate.

Any help is good help!
Alex C

#include dp256reg.asm

org $4000
;IIC initialization
movb #$18,IBFD ;Set Freq div for IIC, 9 clock cycles= 1.123us @8MHz
movb #$e0,IBAD ;HC12 slave address
movb #$80,IBCR ;Set enable bit

jsr Delay
jsr Delay


;Transmission
;Generating Start Condition
brset IBSR,$20,* ;Wait for bus busy flag to clear IBB Flag
bset IBCR,$30 ;Set Transmit master mode
brclr IBSR,$20,* ;Wait for IBB flag to set
jsr Delay
movb $e0,IBDR ;Transmit Dev Select and write packet
brclr IBSR,$20,* ;

brclr IBSR,$02,* ;Wait for data to be transmitted
bclr IBSR,$02 ;Clear flag
jsr Delay
movb $00,IBDR ;Transmit 0x00(Data to write to address 0x00)

brclr IBSR,$02,* ;Wait for data to be transmitted
bclr IBSR,$02 ;Clear flag
jsr Delay
movb $a0,IBDR ;Transmit 0xa0(Data to write to address 0x00)
brclr IBSR,$02,* ;Wait for data to be transmitted
bclr IBSR,$02 ;Clear flag
jsr Delay
movb $aa,IBDR ;Transmit 0xaa (Data to write to address 0x00)
brclr IBSR,$02,* ;Wait for data to be transmitted
bclr IBSR,$02 ;Clear flag
jsr Delay
movb $a5,IBDR ;Transmit 0xa5 (Data to write to address 0x00)

brclr IBSR,$02,* ;Wait for data to be transmitted
bclr IBSR,$02 ;Clear flag
movb $e4,IBDR ;Transmit 0xe4 (Data to write to address 0x00)

;Generate a Stop condition
brclr IBSR,$02,* ;Wait for data to be transmitted
bclr IBCR,$20
jsr Delay

;***;Disable I2C module
bclr IBCR,$80
swi

Delay:
ldx #13000; delay of 65ms
again psha
pula
psha
pula
psha
pula
psha
pula
psha
pula
psha
pula
psha
pula
nop
nop
dbne x,again
rts







--- In 6..., "elalex_76" wrote:
>
> Hello, i had been trying to work with MC9S12DP256B board and SRF08
> sensor that makes use of the I2C bus, pins j6 and j7 ,SDA & SCL. I
> haven't been able to communicate with the device. I have included
the
> .asm file, so if anyone can take a look at it and advice me on what
> i'm doing wrong.

To clear the IBIF flag in the IIC Status Register, you have to WRITE
a 1 to it. You can't use BCLR.
Mike Elphick

> What i'm trying to do in this code, is to change the address of the
> slave(SRF08). In order to change the address i need to write 0xA0,
> 0xAA, 0xA5 and the new address 0xE4 to the command register in the
SRF08.
> The reason that i'm trying to change the address is because it uses
> the write command to the I2C bus. If i am able to change the
address,
> then i am able to comunicate.
>
> Any help is good help!
> Alex C
>
> #include dp256reg.asm
>
> org $4000
> ;IIC initialization
> movb #$18,IBFD ;Set Freq div for IIC, 9 clock cycles1.123us @8MHz
> movb #$e0,IBAD ;HC12 slave address
> movb #$80,IBCR ;Set enable bit
>
> jsr Delay
> jsr Delay
>
>
> ;Transmission
> ;Generating Start Condition
> brset IBSR,$20,* ;Wait for bus busy flag to clear IBB Flag
> bset IBCR,$30 ;Set Transmit master mode
> brclr IBSR,$20,* ;Wait for IBB flag to set
> jsr Delay
> movb $e0,IBDR ;Transmit Dev Select and write packet
> brclr IBSR,$20,* ;
>
> brclr IBSR,$02,* ;Wait for data to be transmitted
> bclr IBSR,$02 ;Clear flag
> jsr Delay
> movb $00,IBDR ;Transmit 0x00(Data to write to address 0x00)
>
> brclr IBSR,$02,* ;Wait for data to be transmitted
> bclr IBSR,$02 ;Clear flag
> jsr Delay
> movb $a0,IBDR ;Transmit 0xa0(Data to write to address 0x00)
> brclr IBSR,$02,* ;Wait for data to be transmitted
> bclr IBSR,$02 ;Clear flag
> jsr Delay
> movb $aa,IBDR ;Transmit 0xaa (Data to write to address 0x00)
> brclr IBSR,$02,* ;Wait for data to be transmitted
> bclr IBSR,$02 ;Clear flag
> jsr Delay
> movb $a5,IBDR ;Transmit 0xa5 (Data to write to address 0x00)
>
> brclr IBSR,$02,* ;Wait for data to be transmitted
> bclr IBSR,$02 ;Clear flag
> movb $e4,IBDR ;Transmit 0xe4 (Data to write to address 0x00)
>
> ;Generate a Stop condition
> brclr IBSR,$02,* ;Wait for data to be transmitted
> bclr IBCR,$20
> jsr Delay
>
> ;***;Disable I2C module
> bclr IBCR,$80
> swi
>
> Delay:
> ldx #13000; delay of 65ms
> again psha
> pula
> psha
> pula
> psha
> pula
> psha
> pula
> psha
> pula
> psha
> pula
> psha
> pula
> nop
> nop
> dbne x,again
> rts
>

"michael_c_elphick" wrote:

> --- In 6..., "elalex_76" wrote:
>>
>> Hello, i had been trying to work with MC9S12DP256B board and SRF08
>> sensor that makes use of the I2C bus, pins j6 and j7 ,SDA & SCL. I
>> haven't been able to communicate with the device. I have included
> the
>> .asm file, so if anyone can take a look at it and advice me on what
>> i'm doing wrong.
>
> To clear the IBIF flag in the IIC Status Register, you have to WRITE
> a 1 to it. You can't use BCLR.

BCLR indeed can be used, however not directly. BSET is what can't be used to
clear single write-one-resettable bit in registers having more than one
write-one resettable bit. But BCLR with inverted bitmask is OK:
IBIF is bit1 of IBSR register. So bitmask for that is 2. Suppose all
available IBSR bits are set at the time you are trying to clear
IBIF. So let's say IBSR reads as 0xF7 (bit3 is always zero).

It's not OK to :
BCLR IBSR,#2 ;; This doesn't work because CPU would write (0xF7 & ~2)=
0xF5 to IBSR. In other words CPU would write ones to all bits except
bit1(bitmask 2) and bit3. All "write1" resettable bits will be reset except
one which you specified by bitmask. You want to clear IBIF bit but CPU
clears IBAL.

It's OK to:
BCLR IBSR,#~2 ;; This works because CPU would write (0xF7 & ~(~2))=2 to
IBSR. BCLR statusregister,#invertedbitmask works well for all write-one
resettable bits, ECT, CAN, RTI flags ... In C it may be coded as IBSR &=
2;. It's OK to BCLR statusregister,#invertedbitmask in asm. It's also OK to
statusregister&=bitmask in C.

The only difference between MOVB and BCLR is that MOVB #2,IBSR always
writes one to IBIF. BCLR IBSR,#0xFD writes one to IBIF only if IBIF is set.
But if IBIF is already cleared then you can't clear it again so MOVB isn't
much better than BCLR.
And BSET is evil for write-one clearable bits. It may be used only for
registers having single write-one resettable bit.

BSET xx,#mask is xx = xx | mask. This writes ones to all set bits and
also ones to bits specified by mask. In result it clears all set bits...

BSET xx,#~mask is xx = xx | ~mask . This writes ones to all bits except
that if bit, specified by mask, was cleared, then BSET will not write 1 to
this bit. Funny.
> Mike Elphick

Edward





May 12, 2006 2:48 PM Edward Karpicz wrote: -

> BCLR indeed can be used, however not directly. BSET is what can't be
> used to clear single write-one-resettable bit in registers having more
> than one write-one resettable bit. But BCLR with inverted bitmask is OK

Edward is correct and has explained each method of clearing these
flags very well :-)

> It's OK to:
> BCLR IBSR,#~2 ;; This works because CPU would write (0xF7 & ~(~2))=2
> to IBSR. BCLR statusregister,#invertedbitmask works well for all
> write-one resettable bits, ECT, CAN, RTI flags ... In C it may be
> coded as IBSR &=2;. It's OK to BCLR statusregister,#invertedbitmask
> in asm. It's also OK to statusregister&=bitmask in C.

Indeed you *can* use BCLR in this way, but when reading the code
it does not look so intuitive and the use of BCLR like this takes
some time to explain, as you can see from the length of Edward's reply.
Although it is a neat, I personally don't do it this way (in case someone
comes along and changes it!). However, the way Alex C was using BCLR is
totally and completely wrong.

To clear the IBIF flag I normally go: -

LDAA IBSR
ORAA #IBIF
STAA IBSR

This is clearer, but does use a few more clock cycles.

Michael Elphick
--- In 6..., "Edward Karpicz" wrote:
> It's OK to:
> BCLR IBSR,#~2 ;; This works because CPU would write (0xF7 &
~(~2))=2 to
> IBSR. BCLR statusregister,#invertedbitmask works well for all
write-one
> resettable bits, ECT, CAN, RTI flags ... In C it may be coded as
IBSR &=
> 2;. It's OK to BCLR statusregister,#invertedbitmask in asm. It's
also OK to
> statusregister&=bitmask in C.

Thank you very much for the explanation, i will use it instead of the
way i was using it.
I will test it and post back..


> And BSET is evil for write-one clearable bits. It may be used only for
> registers having single write-one resettable bit.
>
> BSET xx,#mask is xx = xx | mask. This writes ones to all set
bits and
> also ones to bits specified by mask. In result it clears all set bits...
>
> BSET xx,#~mask is xx = xx | ~mask . This writes ones to all bits
except
> that if bit, specified by mask, was cleared, then BSET will not
write 1 to
> this bit. Funny.
>
> Edward
>
Edward, what should i use instead of bset?

Thank you very much for your input Edward and also to Michael.
I'm trying to understand the code, Michael tthanks for e-mail me the code.
Alex C.





Michael Elphick wrote:

> May 12, 2006 2:48 PM Edward Karpicz wrote: -
>
>> BCLR indeed can be used, however not directly. BSET is what can't be
>> used to clear single write-one-resettable bit in registers having more
>> than one write-one resettable bit. But BCLR with inverted bitmask is OK
>
> Edward is correct and has explained each method of clearing these
> flags very well :-)
>
>> It's OK to:
>> BCLR IBSR,#~2 ;; This works because CPU would write (0xF7 & ~(~2))=2
>> to IBSR. BCLR statusregister,#invertedbitmask works well for all
>> write-one resettable bits, ECT, CAN, RTI flags ... In C it may be
>> coded as IBSR &=2;. It's OK to BCLR statusregister,#invertedbitmask
>> in asm. It's also OK to statusregister&=bitmask in C.
>
> Indeed you *can* use BCLR in this way, but when reading the code
> it does not look so intuitive and the use of BCLR like this takes
> some time to explain, as you can see from the length of Edward's reply.
> Although it is a neat, I personally don't do it this way (in case someone
> comes along and changes it!). However, the way Alex C was using BCLR is
> totally and completely wrong.

I haven't come to IIC world yet so I'll better not comment what Alex wrote.
All my post is only about BCLR.

>
> To clear the IBIF flag I normally go: -
>
> LDAA IBSR
> ORAA #IBIF
> STAA IBSR

>
> This is clearer, but does use a few more clock cycles.

Mike, do you understand that this 3 instruction sequence behaves the same
like

BSET IBSR,#IBIF

If IBAL is set before CPU reads IBSR (before LDAA IBSR data read cycle),
then after ORAA #IBIF, accumulutar will have ones in both IBIF and IBAL bit
positions. IBAL will be cleared. I don't know how dramatic it will be for
your code and IIC handling but that's a bug. Hope it was just a typo in your
snippet.

Many people would write in C:

IBSR |= IBIF; // that's BSET or ldaa-oraa-staa and it's wrong.
IBSR &=IBIF; // that's BCLR IBSR,#~IBIF and is OK.

CW defines bitfields for everything. It's so temptating to just IBIF=1.
Guess what? IBIF=1 is either BSET or LDAA-ORAA-STAA and also will clear
IBAL.
>
> Michael Elphick
Edward

> --- In 6..., "Edward Karpicz" wrote:
>> It's OK to:
>> BCLR IBSR,#~2 ;; This works because CPU would write (0xF7 &
> ~(~2))=2 to
>> IBSR. BCLR statusregister,#invertedbitmask works well for all
> write-one
>> resettable bits, ECT, CAN, RTI flags ... In C it may be coded as
> IBSR &>> 2;. It's OK to BCLR statusregister,#invertedbitmask in asm. It's
> also OK to
>> statusregister&=bitmask in C.
>
> Thank you very much for the explanation, i will use it instead of the
> way i was using it.
> I will test it and post back..
>

Alex, please note that I don't know anything about S12 IIC module. I can
tell only about bits wich are cleared writing ones to them.

>
>> And BSET is evil for write-one clearable bits. It may be used only for
>> registers having single write-one resettable bit.
>>
>> BSET xx,#mask is xx = xx | mask. This writes ones to all set
> bits and
>> also ones to bits specified by mask. In result it clears all set bits...
>>
>> BSET xx,#~mask is xx = xx | ~mask . This writes ones to all bits
> except
>> that if bit, specified by mask, was cleared, then BSET will not
> write 1 to
>> this bit. Funny.
>>
>> Edward
>>
> Edward, what should i use instead of bset?

x|y - is bit or operation. For example 1|4=5;
~x - is a not operation. For example ~1=0xFF
x< flagsN - any register having bits clearable by writing 1 to them

Having above 3 defined lets say you want to clear Nth bit of flagsN. Bit
mask for Nth bit is (1< 1<<2=4. Bit mask of both bit0 and bit2 is (1<<0)|(1<<2)=5. Now having bits
and their masks defined, to clear bit2 you have 4 valid variants:
1) BCLR flagsN,#~(1<<2) ; ~(1<<2) expands to 0xFB

2) MOVB #(1<<2), flagsN

3) LDAB #(1<<2) ; or LDAA-STAA
STAB flagsN

4) LDAB flagsN ; or LDAA-ANDA-STAA
ANDB #(1<<2) ; expands to 4.
STAB flagsN

To clear for example bits 3,5,7 all at once:

BCLR flagsN,#~( (1<<3) | (1<<5) | (1<<7) )

Quite simple to use if you let compiler compute all those shifts and nots
for you.

>
> Thank you very much for your input Edward and also to Michael.
> I'm trying to understand the code, Michael tthanks for e-mail me the code.
> Alex C.
>
Edward

On May 12, 2006 5:14 PM, Edward Karpicz wrote: -

> Mike, do you understand that this 3 instruction sequence
> behaves the same like
>
> BSET IBSR,#IBIF
>
> If IBAL is set before CPU reads IBSR (before LDAA IBSR data
> read cycle), then after ORAA #IBIF, accumulutar will have ones
> in both IBIF and IBAL bit positions. IBAL will be cleared. I don't
> know how dramatic it will be for your code and IIC handling but
> that's a bug. Hope it was just a typo in your snippet.

Whoops! Dug myself into a hole with that one!

I copied it from my program. In this instance I'm not bothered with IBAL and if it's set it needs to be cleared. Not a good example!

If it's just the IBIF bit to clear (and I know it's set) then I would: -

LDAA #IBIF
STAA IBSR

or

MOVB #IBIF, IBSR

I hope I've got it right this time -- it's so easy to make silly mistakes when posting to a group like this!

Cheers,

Michael Elphick