MCF51JM128 MSCAN TX interrupt:Code loading overlap detected in range 0x00000184..0x00000187

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MCF51JM128 MSCAN TX interrupt:Code loading overlap detected in range 0x00000184..0x00000187

1,045 Views
carlhua
Contributor II

Based on AN3690, I am trying to add a CAN transmit interrupt. However when I tried to add the function

 

interrupt VectorNumber_Vcantx  void can_tx_isr(void)

 

 

the debugger gives me the warning:

Code loading overlap detected in range 0x00000184..0x00000187

 

 

There is little information i can find, can anyone enlighten me on how to resolve this?

Labels (1)
Tags (2)
0 Kudos
6 Replies

636 Views
carlhua
Contributor II

I resolved this by commenting out another place that defined the interrupt. However now my program is being flooded by this interrupt although I have transmitted nothing.

Anyone has any ideas?

636 Views
TomE
Specialist II

> I resolved this by commenting out another place that defined the interrupt.

Maybe the original programmer intended all the interrupts to be defined in the one place (in that place), and in that case you should probably try to write your code with the same "philosophy" as is already there. If the "other place" is meant to list only "all the unused interrupts", then what you've done may be what is intended.

> my program is being flooded by this interrupt although I have transmitted nothing.

That's the point. A Receive interrupt means you have to receive a message/data to clear the interrupt, and to clear a Transmit interrupt you have to send something.

For the purpose of this explanation, as far as interrupts, a CAN controller is just like a complicated UART.

There are two sorts or UARTS in the world. There are are ones designed to fit in a clean, regular and properly designed system architecture (PDP-11, 68000, ColdFire), and ones designed to fit into hardware that "just happened at random" like those derived from PC architecture, with no overall system design and where things just don't fit together neatly.

UARTs can either generate a transmit interrupt when they ARE empty (level trigger), or when they BECOME empty (edge trigger). The "clean" ones use Levels, and that's what the ColdFire one is.

You should read this part of the Reference Manual:

Table 11-11. CANTFLG Register Field Descriptions

TXE[2:0]:  This flag indicates that the associated transmit message buffer is empty, and thus

not scheduled for transmission. ... If not masked, a transmit interrupt is pending while this flag is set.

That means you have to MASK the transmit interrupt when you've got nothing to send.

The advantage of the "level" approach is that it makes transmitting simpler. Assume you have a "transmit buffer" or "transmit message ring". When your code goes to transmit something, all it has to do is to put the data into the ring or buffer, and then unmask the interrupt. The interrupt routine will then automatically send the first message. When the interrupt routine finds the buffer is empty it masks the transmit interrupt. The "edge" case is more complicated and more likely to go wrong as you have to separately "send" the first message to get the first interrupt when that one is sent.

Tom

636 Views
carlhua
Contributor II

Thank you Tom, your answer helped. So does this mean I will need to have logic in my code to check whether there is message to be sent. If not, then i will mask the interrupt?

My original vision is to perform the following:

1 task will be putting data into a circular buffer.

another task will send the first data, when the interrupt happens I will push out the next message.

but based on what you have mentioned plus table 11-11 of the reference manual, it seems that I now need to:

1 task will handle message buffering,

another task can send out the data, and when the interrupt happens, i will send out the next message, but if there is no more message, i need to mask the interrupt so that no additional interrupt will happen.

This seems rather complicated, maybe polling would be the way to go.

Thanks

0 Kudos

636 Views
TomE
Specialist II

> This seems rather complicated,


This stuff is trivially simple. You don't have a "task" to send, that's the job of the interrupt service routine.


The buffer has an "in pointer" and an "out pointer". Make sure they're both marked as "volatile". They can be real pointers or indexes.

Your sending task puts a new message in the buffer list (as long as it will fit) and then increments the "in pointer". For simplicity it should leave an empty slot in the ring, otherwise the pointers will match on "full" and "empty". You can handle this by having a count of "number of messages in ring" or an explicit "ring full" or "ring empty" flag, but then there's three variables that can get out of sync and need to be protected against interrupts. Having less variables is simpler and safer.

If the pointers were the same BEFORE the increment then it needs to unmask the interrupt (this operation needs to have the CPU interrupts disabled around it). It can usually mask it in iether the interrupt controller or the device - sometimes one is easier than the other depending on the hardware.

It may be simpler to disable CPU interrupts, put the message in the list, increment the "in pointer" and then unconditionally unmask the transmit interrupt, then re-enable the CPU interrupts. It depends on how long you want the CPU interrupts to be disabled for, and whether your "transmit" function allows multiple messages to be sent in the one call.

The interrupt service routine compares the in and out pointers. If they're different it sends the "out" message and then increments the pointer. Then it compares the pointers again, and if they're the same (no more data to send) it masks the transmit interrupt.

That's about as simple as it gets.


Of course with CAN you've got multiple transmit buffers. You should start with one, get it working and then decide if you need to get more complicated later.

(Edit to simplify the description a few days later).

Tom

0 Kudos

636 Views
carlhua
Contributor II

Thanks Tom,

I ended up implementing a buffer that holds certain amount of messages while the 3 transmit buffers are full. I have logic in a loop that checks whether another message can be sent... I kept it simple and disabled the interrupt..

0 Kudos

636 Views
TomE
Specialist II

I've read the FlexCAN manual again, and there's an important bit I missed.

This is partly due to Freescale often using "write one to clear" interrupt status bits,, and in many of their manuals this is marked on the Register Diagram by marking the bits "W1C".

The "TXEn" bits in "11.3.7 MSCAN Transmitter Flag Register (CANTFLG)" are "W1C" bits, but this manual doesn't mark them like that. It doesn't even say that in the Register Bit Description Table. Instead it says between the Diagram and Description that "write of 1 clears flag, write of 0 is ignored".

So the proper approach is detailed in "11.5.7.6 Interrupt Acknowledge", which is:

The flags in CANRFLG and CANTFLG must be reset within the interrupt handler to handshake the interrupt. The flags are reset by

writing a 1 to the corresponding bit position. A flag cannot be cleared if the respective condition prevails.

So in the interrupt routine you write a "1" to clear the bit to make the interrupt go away, right? Wrong. The last sentence above is a clue that you can't do that. It also says you ONLY clear this apparent STATUS bit as a COMMAND to start the next transmission of that message.

I'd suggest looking at someone else's code for ideas and as a sanity check:

http://lxr.free-electrons.com/source/drivers/net/can/mscan/

That shows the code setting and clearing the enable bits in the CANTIER register to manage the interrupts.

There's another problem; the ORDER of the sent messages. If you're sending messages where the order doesn't matter, then you're fine. If you're trying to send messages in a particular order (like a download or debug protocol), then it is difficult with MSCAN. The easiest approach is to only use one transmit buffer. If you want to use all three, then you can start the first message with the priority register "TBPR" set to "0". The next message "1" and so on all the way up to "255". Then what? You can't use "0" again or that one will jump the queue. You have to wait for all messages to finish transmitting and then you can start with "0" again. Or you can send three at a time and wait for them to drain.

Tom

0 Kudos