Hello,
I'm having trouble with getting the MSCAN to transmit a message on the MC9S08DZ60. I have, I think, properly initialized everything, and wrote a subroutine that gets called every 5ms from a timer interrupt. I know the subroutine gets called, because I toggle a pin, and I can set a breakpoint. Unfortunately, the CANTX pin never responds. Right now, the pin is floating. If I connect it to a CAN network through a transceiver, I get the same result. I've checked my initialization code and transmit code against some other examples, but I'm not seeing any problem. I considered that perhaps my code isn't initializing properly, since I'm not waiting for the INITAK bit to be set, but according to the data sheet this should already be set on startup. Additionally, I can view the initialized registers, and they seem to have the correct values.
Moreover, I understand that transmit buffer 0 might not be available when I enter the subroutine. However, when I step through the program, I can see that buffer 0 is empty every time I enter the subroutine. I'll reinstate the appropriate logic once I can get this operating, but I took it out lest it casue an issue.
I can see that the last step in the subroutine, where I'm supposed to be clearing the CANTFLG, isn't working. I can see the $01 loaded into register A, but when that gets stored in CANTFLG, CANTFLG remains at $07, and I don't see any life on the TXCAN line.
I included my initialization code and the transmit code inline in the post. If anyone wants the whole thing, I can provide that as well. I'm using CodeWarrior V10.1 and the PE Micro USB Multilink Interface standalone probe.
Thanks in advance,
Matt
This is my initialization code:
;Initialize CAN
LDA #$80 ;Enable the CAN peripheral
STA CANCTL1
LDA #$F0 ;Enable normal operation, set clock source to bus clock (8MHz)
STA CANCTL1
LDA #$67 ;Set 7xTq before sample, 8xTq after, for 500kHz bitrate
STA CANBTR1
LDA #$00 ;Clear INITRQ, to enter CAN operation
STA CANCTL0
...and this is the subroutine that, I think, should transmit a message:
;****CAN_TX***********************************************
CAN_TX:
LDA #$01 ;Select transmit buffer 0
STA CANTBSEL
LDA #$32 ;Set CAN ID to $191
STA CANTIDR1
LDA #$20
STA CANTIDR0
LDA #$01 ;Set CAN Message to $0123456789ABCDEF
STA CANTDSR0
LDA #$23
STA CANTDSR1
LDA #$45
STA CANTDSR2
LDA #$67
STA CANTDSR3
LDA #$89
STA CANTDSR4
LDA #$AB
STA CANTDSR5
LDA #$DC
STA CANTDSR6
LDA #$EF
STA CANTDSR7
LDA #$08 ;Eight transmit bytes
STA CANTDLR
LDA #$01 ;Clear transmit flag 0
STA CANTFLG
LDA PTFD
EOR #$08
STA PTFD
RTS
;****END CAN_TX***********************************************
Buy using mysterios constants, and avoiding decent comments in your code, yur are creating problems not only for yourself, but also for others.
Go decifier what $F0 really means below, write decent comment and you will find main reason why it is not working.
LDA #$F0 ;Enable normal operation, set clock source to bus clock (8MHz)
STA CANCTL1
I ignored the rest of code
I apologize. I forget sometimes that most people don't like translating hexadecimal until I leave my desk. I added more complete comments. Hopefully this will help:
;Initialize CAN
LDA #$80 ;%1000 0000 Enable the CAN peripheral by setting CANE bit
STA CANCTL1
LDA #$F0 ;%1111 0000 Enable normal operation by setting LOOPB and LISTEN, set clock source to bus clock (8MHz) by setting CLKSRC, and write CANE to 1 (although this should still have no effect at this point)
STA CANCTL1
LDA #$67 ;%0110 0111 Set 7xTq before sample by loading 7 into TSEG2, 8xTq after sample by loading 8 into TSEG1. This give a 500kHz bitrate
STA CANBTR1
LDA #$00 ;%0000 0000 Clear INITRQ, to enter CAN operation
STA CANCTL0
...and this is the subroutine that, I think, should transmit a message:
;****CAN_TX***********************************************
CAN_TX:
LDA #$01 ;%0000 0001 Select transmit buffer 0 by setting bit 0
STA CANTBSEL
LDA #$32 ;%0011 0010 Set CAN ID to $191 (combine with CANTIDR0)
STA CANTIDR1
LDA #$20 ;%0010 0000 bottom three bits for CAN ID, clear RTR for Data Frame, clear IDE for standard identifiers
STA CANTIDR0
LDA #$01 ;Set CAN Message to $0123456789ABCDEF (CANTDSR0-7)
STA CANTDSR0
LDA #$23
STA CANTDSR1
LDA #$45
STA CANTDSR2
LDA #$67
STA CANTDSR3
LDA #$89
STA CANTDSR4
LDA #$AB
STA CANTDSR5
LDA #$DC
STA CANTDSR6
LDA #$EF
STA CANTDSR7
LDA #$08 ;%0000 1000 Eight transmit bytes
STA CANTDLR
LDA #$01 ;%0000 0001 Clear transmit flag 0 by writing a 1 to TX0
STA CANTFLG
;Toggle a pin to synch with scope, also to verify that the subroutine is being called properly
LDA PTFD
EOR #$08
STA PTFD
RTS ;Return from subroutine
;****END CAN_TX***********************************************
Wrong conclusion. Hex<->bin, and even hex<->dec is fine for me. Not fine is looking into datasheet how is the meaning of bit 6 is some register. Do you remember them? Certainly you should comment what bits (by name) you are accessing, at least when you are showing your problematic code to someone else than you.
Comment still is wrong. Setting LOOPB and LISTEN can't be called normal operation. I had a hope that you will read what does LISTEN mean. You can't have anything transferred with this bit set. Reading Bosch CAN specs could help you a lot.
In TX routine, CANTIDR1 and CANTIDR0 seem being swapped.
I have the Bosch spec. It is, indeed, very helpful. I thought I had "remembered" reading a training document from Freescale that setting both LOOPB and LISTEN would enter normal operation. Apparently I misread it the first several times. Now I'm clearing them both (setting CANCTL1 to $C0), and I'm getting transmission.
You're right about IDR1 and IDR0 being swapped.
Thanks again for the help.
Matt