This is regarding a 9S12DJ128. I am trying to implement a design using the CAN module in order to control an instrument panel cluster for a simulator. I am writing the code directly in assembly language and not using an API. The memory map for my processor for CAN0 is from $0140 - $017F. Various configuration registers are defined from $0140 - $015F. The receive foreground register is 16 bytes: $0160 - $016F. The transmit foreground register is 16 bytes: $0170 - $017F. Then, CAN1 takes over from $0180 - $01BF.
Documentation states that there are 3 transmit buffers that are addressable by the CPU. However, memory mapping only shows one, from $0170 - $017F. Does anyone know how to address all of the transmit buffers? There are transmit buffer select bits in the CANTBSEL register: TX2 - TX0. It states: The lowest numbered bit places the respective transmit buffer in the CANTXFG ($0170 - $017F) register space.
My question is, how does the CPU know where the 3 transmit buffers are located? I.e., how can I load a message into either transmit buffer 1 or 2 or 3, when I don't even know where it is mapped in memory?
I appreciate the help of anyone with expertise in this area.
Joel
Solved! Go to Solution.
It is simply, there are three 3 tx buffers which shares one space in memory model. Access is driven by CANTBSEL register.
CANTBSEL register has special feature – when we write and read this register, it will find the lowest ordered bit set to “1”, all other bits will be read as “0”. This feature allows simple code for selecting proper buffer.
Datasheet says:
The application software wants to get the next available transmit buffer. It reads the CANTFLG register and writes this value back into the CANTBSEL register. In this example Tx buffers TX1 and TX2 are available. The value read from CANTFLG is therefore 0b0000_0110. When writing this value back to CANTBSEL the Tx buffer TX1 is selected in the CANTXFG because the lowest numbered bit set to “1” is at bit position 1. Reading back this value out of CANTBSEL results in 0b0000_0010, because only the lowest numbered bit position set to “1” is presented. This mechanism eases the application software the selection of the next available Tx buffer.
LDD CANTFLG; value read is 0b0000_0110
STD CANTBSEL; value written is 0b0000_0110
LDD CANTBSEL; value read is 0b0000_0010
So, you can use this code:
CAN0TBSEL = CAN0TFLG; /* Select lowest empty buffer */
txbuffer = CAN0TBSEL; /* Backup selected buffer */
//fill Tx buffer
CAN0TFLG = txbuffer; /* Start transmission */
In attachment you can find simple example code.
Note: example code was created for different S12 MCU, therefore some details doesn’t need to fit, however principle is the same.
It is simply, there are three 3 tx buffers which shares one space in memory model. Access is driven by CANTBSEL register.
CANTBSEL register has special feature – when we write and read this register, it will find the lowest ordered bit set to “1”, all other bits will be read as “0”. This feature allows simple code for selecting proper buffer.
Datasheet says:
The application software wants to get the next available transmit buffer. It reads the CANTFLG register and writes this value back into the CANTBSEL register. In this example Tx buffers TX1 and TX2 are available. The value read from CANTFLG is therefore 0b0000_0110. When writing this value back to CANTBSEL the Tx buffer TX1 is selected in the CANTXFG because the lowest numbered bit set to “1” is at bit position 1. Reading back this value out of CANTBSEL results in 0b0000_0010, because only the lowest numbered bit position set to “1” is presented. This mechanism eases the application software the selection of the next available Tx buffer.
LDD CANTFLG; value read is 0b0000_0110
STD CANTBSEL; value written is 0b0000_0110
LDD CANTBSEL; value read is 0b0000_0010
So, you can use this code:
CAN0TBSEL = CAN0TFLG; /* Select lowest empty buffer */
txbuffer = CAN0TBSEL; /* Backup selected buffer */
//fill Tx buffer
CAN0TFLG = txbuffer; /* Start transmission */
In attachment you can find simple example code.
Note: example code was created for different S12 MCU, therefore some details doesn’t need to fit, however principle is the same.
The 3 tx buffers are a "tripple buffer", one buffer used for the message currently sent, one for the message currently being loaded by software, and one middle buffer in between them, to make continuous CAN transmission possible, without the delays that a double buffer solution would have. Thus it only makes sense to load the message into "a free" tx buffer. This is done by copying the contents of CANTFLG into CANTBSEL. This will "expose" the selected buffer, making it appear at the address of CANTXFG. So you really don't need to concern yourself about there being 3 buffers, the hardware will keep track of them.
I'd strongly recommend to read the whole MSCAN manual in detail before writing any driver for it.