PDA

View Full Version : Datasheet and register question



Christopher4187
- 10th July 2012, 22:10
This is probably a basic question for most of you but I can't quite figure it out. I have a register that needs to be set, lets say INEEDSLEEP. The addresses are 80h, 90h, 100h. My questions are:

1. If the data sheet says it's bits <3:0>, why are there only three addresses when it covers four bits?

2. Do you put the exact same values into all of the addresses?

When I've used more basic registers, I just use something like INEEDSLEEP = %00010100. Maybe I just never noticed it but I don't remember ever having to put values into three different addresses for one value.

I'll start with this and see if someone can get it through my thick skull.

HenrikOlsson
- 11th July 2012, 06:34
Hi Christopher,
It would be nice if you linked to the datasheet you're looking at but due to your other currently 'active' threads I suspect it's the MCP2515 we're talking about? If not then this answer may not apply.

1) There are three INEEDSLEEP registers, one at adress $80, one at $90 and one at $100. Judging by the other register names in the MCP2515 the description of the register in the datasheet would likely be something like INEEDSLEEPn where n is the number of the register. 0,1,2 or perhaps 1,2,3. There are 8bits en each register but you're interested in the lower 4bits <3:0> of each register.

2) It depends on what INEEDSLEEP does and what YOU want to do really. Since I don't know CAN or the MCP2515 (if that's what we're really talking about here) I'm going to try a stupid example. If the chip wasn't a CAN driver but a say PWM chip with three output channels. Then you'd have three dutycycle registers in the chip. The functionality and operation of the registers would be exactly equal so instead of describing it three times in the datasheet the might show it DUTYn (at adresses $10, $20, $30 or whatever) where n is either 0,1 or 2 for the three different channels.

Now, if you wanted to set the dutycycle of all three channels to 0 would you write 0 to all three registers? YES of course. If you then wanted to set the dutycycle of channel 1 to 50 would you write 50 to all three registers? NO of course not, you'd write 50 to DUTY1, which is at address $20 in the external chip. If it was in the PIC then the actual address would be of less interest because the compiler would include a file (think of it like sort of a phonebook) with register names and their addresses, so you could access it directly by its name (DUTY1).

As I said, a stupid example but it's the best I can do without reference to the actual part and actual register. I hope it makes some sense though.

/Henrik.

Christopher4187
- 11th July 2012, 10:47
Min forre flickvan (mycket vakra) var Svensk och jag prata lite Svenska! It's been years but I still remember a little, although there may be spelling mistakes;)

Anyhow, I started this thread for the datasheet question because it was more of a generic question but yes, I am asking about the MCP2515. Here are the two things I can't understand:

1. Page 21. For TXBnDm it gives a number of address values and they are looking for eight different numbers. I've found that the .asm files and the C files provided help out a little bit but do I need to put each of the TXBnDm numbers (0-7) in a different address or do I just assign a value to them in the code like TXB1Dm = $FF or is it written TXBnDm7 = $FF?

2. I'm learning about the bit modify instruction but it isn't completely clear. I don't understand how to code the higher and lower order address bits. As an example, on page 61 I am having trouble understanding how to program TXBnSIDL and TXBnSIDH.

Thanks,

Chris

HenrikOlsson
- 11th July 2012, 14:31
Hej Christopher,
Din svenska är helt OK!

1) The MCP2515 has three transmit buffers (ie it's to these buffers you write the data to be sent out on the CAN bus). Each of these transmit buffers consists of 8 bytes. The first transmit buffer starts at $36 and ends at $3D. So the first byte of the first buffer is at address $36 and would be called TXB0D0 (Transmit Buffer 0 DataByte 0). The first byte of the second buffer would be at address $46 and would be called TXB1D0 (Transmit Buffer 1 DataByte 0) and so on.

You can't simply do TXB0D0 = $FF because, once again, the register is not in the PIC, you'll have to write to that register using either SHIFTOUT or the MSSP module like we discussed in one of the other threads. Ie, to load TXB0D0 with $FF you'd do

SHIFTOUT DataPin, ClkPin, MSBFirst, [2, $36, $FF] ' 2=Write Instruction, $36=adress of TXB0D0 regsiter, $FF=Data to be written to that register
Now, you can obviously create CONstants to the various registers and commands, like

WriteCmd CON 2
TXB0D0 CON $36
SHIFTOUT DataPin, ClkPin, MSBFirst, [WriteCmd, TXB0D0, $FF]


2) The register map on page 61 shows the address of all the registers in the device. TXBnSIDL and TXBnSIDH are Transmit Buffer Standard Identifier (whatever that is) register and since there are three Transmit buffers there are three TXNnSIDL and TXBnSIDH registers (again, n would be 0,1 or 2 for the three individual registers "coupled" to each transmit buffer.

So, looking at the table on page 61, you can see that the four high order bits of the address are in the columns and the four low order bits are in the rows. For TXB0SIDL you'll get 0011 for the high order bits and 0010 for the low order bits. Combing these give you %00110010 which is the same as $32 - which, if you look at the description for the TXBnSIDL register (page 20) matches what they say IS the address of TXB0SIDL.

So, to write the value $12 to TXB0SIDL you'd do

SHIFTOUT DataPin, ClkPin, MSBFirst, [2, $32, $12] '2=WriteInstruction, $32= Adress of register, $12=Data to write.

In the register map all register which are allowed to be manipulated by the BitModify instruction are shaded. The TXBnSIDL registers are not shaded and can not be modified using the BitModify instruction.

/Henrik.

Christopher4187
- 15th July 2012, 19:06
Thanks for the help Henrik. I still don't understand it. I've been trying for the past four days and I can't get my variables set up correctly. I've been looking at code on here and other places on the internet and I'm more confused than I was before - most of them are in C. The datasheet seems really confusing to me. I think I've wasted more than 100 hours so far.

Christopher4187
- 15th July 2012, 22:12
I have a hammer in one hand and the 18F4550, along with the MCP2515 are on my table. It would really provide a lot of stress relief.

I'm going to scrap this and just go with an 18F with CAN built in.

comwarrior
- 16th July 2012, 01:38
The 4550 is quite commonly supported... not only that but the datasheets seem (to me) to be written properly...

I've not played with CAN, however i (along with a lot of other people on here) know the 4550 very well...

HenrikOlsson
- 16th July 2012, 09:24
Hi Christopher,
This may be moot if you've already decided to switch devices but it still seems to me like if you're missing one crucial point. You said that you can't get your variable set up correctly which variables are you talking about here and how do you set them? I don't mean to which values you set them but how do you actually assign your values - whatever value it might be - TO the variable?

The reason I ask is because I still think you may be missing the point that in order for the MCP2515 to work you need to set IT up - ie assign values to the regsiters that are IN the MCP2515. The MCP2515 is an intelligent device, it's not like a MAX232 which has nothing to set up. When you say variables it sounds as if you're still trying to assign values to variables that you create in the PIC and that won't work.

Are you using SHIFTOUT to write the values or do you use the MSSP module?

If it was me I start by making a routine which write values to the MCP2515. Then I'd make a routine which reads values from the MCP2515 to verify that the write routine is working properly.

Can you post some code of your current attempts?

/Henrik.

Christopher4187
- 16th July 2012, 14:07
The 4550 is quite commonly supported... not only that but the datasheets seem (to me) to be written properly...

I've not played with CAN, however i (along with a lot of other people on here) know the 4550 very well...Thank you for your substantive post. It has helped me greatly.


Are you using SHIFTOUT to write the values or do you use the MSSP module?

If it was me I start by making a routine which write values to the MCP2515. Then I'd make a routine which reads values from the MCP2515 to verify that the write routine is working properly.

Can you post some code of your current attempts?I'm using the MSSP. I think my commands are getting to the MCP but I'm guessing my problem lies in one of these places:

CNF1, CNF2, CNF3, SSPCON, SSPSTAT OR BAUDCON. It could be anywhere else too. Basically, the entire program is suspect. Thanks for the help Henrik. Maybe you can spot some issues with what I wrote:


INCLUDE "modedefs.bas"
'
DEFINE OSC 20


'================================================= =============================
' SETTINGS
' ================================================== ============================
'76543210 '76543210
TRISA = %11111111: PORTA = %00000000
TRISB = %00010001: PORTB = %00010000
TRISC = %00000000: PORTC = %00000001
TRISD = %11111111: PORTD = %00000000
TRISE = %00010000: PORTE = %00010111
ADCON0 = %00000000
ADCON1 = %00000000
ADRESH = %00000000
ADRESL = %00000000
CMCON = %00000000
SSPSTAT = %11000100
SSPCON1 = %10110001
BAUDCON = %00001111


'================================================= ==============================
' Register Mapping
'================================================= ===============================

CANSTAT CON $0E
CANCTRL CON $0F
BFPCTRL CON $0C
TEC CON $1C
REC CON $1D
CNF3 CON $28
CNF2 CON $29
CNF1 CON $2A
CANINTE CON $2B
CANINTF CON $2C
EFLG CON $2D
TXRTSCTRL CON $0D

'' Recieve Filters ''
RXF0SIDH CON $00
RXF0SIDL CON $01
RXF0EID8 CON $02
RXF0EID0 CON $03
RXF1SIDH CON $04
RXF1SIDL CON $05
RXF1EID8 CON $06
RXF1EID0 CON $07
RXF2SIDH CON $08
RXF2SIDL CON $09
RXF2EID8 CON $0A
RXF2EID0 CON $0B
RXF3SIDH CON $10
RXF3SIDL CON $11
RXF3EID8 CON $12
RXF3EID0 CON $13
RXF4SIDH CON $14
RXF4SIDL CON $15
RXF4EID8 CON $16
RXF4EID0 CON $17
RXF5SIDH CON $18
RXF5SIDL CON $19
RXF5EID8 CON $1A
RXF5EID0 CON $1B

'' Receive Masks ''
RXM0SIDH CON $20
RXM0SIDL CON $21
RXM0EID8 CON $22
RXM0EID0 CON $23
RXM1SIDH CON $24
RXM1SIDL CON $25
RXM1EID8 CON $26
RXM1EID0 CON $27

'' Tx Buffer 0 ''
TXB0CTRL CON $30
TXB0SIDH CON $31
TXB0SIDL CON $32
TXB0EID8 CON $33
TXB0EID0 CON $34
TXB0DLC CON $35
TXB0D0 CON $36
TXB0D1 CON $37
TXB0D2 CON $38
TXB0D3 CON $39
TXB0D4 CON $3A
TXB0D5 CON $3B
TXB0D6 CON $3C
TXB0D7 CON $3D

'' Tx Buffer 1 ''
TXB1CTRL CON $40
TXB1SIDH CON $41
TXB1SIDL CON $42
TXB1EID8 CON $43
TXB1EID0 CON $44
TXB1DLC CON $45
TXB1D0 CON $46
TXB1D1 CON $47
TXB1D2 CON $48
TXB1D3 CON $49
TXB1D4 CON $4A
TXB1D5 CON $4B
TXB1D6 CON $4C
TXB1D7 CON $4D

'' Tx Buffer 2 ''
TXB2CTRL CON $50
TXB2SIDH CON $51
TXB2SIDL CON $52
TXB2EID8 CON $53
TXB2EID0 CON $54
TXB2DLC CON $55
TXB2D0 CON $56
TXB2D1 CON $57
TXB2D2 CON $58
TXB2D3 CON $59
TXB2D4 CON $5A
TXB2D5 CON $5B
TXB2D6 CON $5C
TXB2D7 CON $5D

'' Rx Buffer 0 ''
RXB0CTRL CON $60
RXB0SIDH CON $61
RXB0SIDL CON $62
RXB0EID8 CON $63
RXB0EID0 CON $64
RXB0DLC CON $65
RXB0D0 CON $66
RXB0D1 CON $67
RXB0D2 CON $68
RXB0D3 CON $69
RXB0D4 CON $6A
RXB0D5 CON $6B
RXB0D6 CON $6C
RXB0D7 CON $6D

'' Rx Buffer 1 ''
RXB1CTRL CON $70
RXB1SIDH CON $71
RXB1SIDL CON $72
RXB1EID8 CON $73
RXB1EID0 CON $74
RXB1DLC CON $75
RXB1D0 CON $76
RXB1D1 CON $77
RXB1D2 CON $78
RXB1D3 CON $79
RXB1D4 CON $7A
RXB1D5 CON $7B
RXB1D6 CON $7C
RXB1D7 CON $7D


'================================================= ==============================
' Register Bit Masks
'================================================= ==============================

DLC_0 CON $00
DLC_1 CON $01
DLC_2 CON $02
DLC_3 CON $03
DLC_4 CON $04
DLC_5 CON $05
DLC_6 CON $06
DLC_7 CON $07
DLC_8 CON $08



'================================================= ==============================
' ' CAN SPI commands
'================================================= ==============================
'
' CAN_RESET $C0
' CAN_READ $03
MCPWRT CON $02
' CAN_RTS $80
' CAN_RTS_TXB0 $81
' CAN_RTS_TXB1 $82
' CAN_RTS_TXB2 $84
' CAN_RD_STATUS $A0
' CAN_BIT_MODIFY $05
' CAN_RX_STATUS $B0
' CAN_RD_RX_BUFF $90
' CAN_LOAD_TX $40

'================================================= ==============================
' ALIAS & MODIFIERS
'================================================= =============================
CS VAR PORTB.4 ' CS LINE
SCLK VAR PORTB.1 ' CLOCK LINE
SDI VAR PORTB.0 ' DATA INPUT LINE
SDO VAR PORTC.7 ' DATA OUTPUT LINE
SENDLED VAR PORTA.5 ' LED TO INDICATE THE PROGRAM IS IN THE SENDING ROUTINE
MAINLED VAR PORTE.2 ' LED TO INDICATE THE PROGRAM IS IN THE MAIN ROUTINE
INT VAR PORTB.5 ' INTERRUPT OUTPUT FROM 18F4550
MCPRST VAR PORTC.0 ' RESET LINE FOR MCP2515
SW_LOAD VAR PORTA.4 ' BUTTON CONNECTED TO 18F4550 TO START SENDING DATA (WHEN IMPLEMENTED)

'================================================= ==============================
' SOFTWARE VARIABLES
'================================================= ==============================

DATAOUT VAR BYTE 'FIRST BYTE OF DATA TO BE SENT
MCPREG VAR BYTE 'ADDRESS OF FIRST BYTE OF DATA TO BE SENT

'================================================= =============================
' RESET MCP2515
'================================================= =============================

LOW MCPRST ' COMMAND TO RESET THE MCP2515 (SOFTWARE)
PAUSE 1
HIGH MCPRST
PAUSE 20

'================================================= =============================
' INITIALIZE MCP2515
'================================================= =============================


LOW CS
SSPBUF = MCPWRT ' COMMAND TO WRITE TO THE MCP2515
PIR1.3 = 0
WHILE PIR1.3=0 :WEND

MCPREG = CANCTRL ' PUT THE MCP2515 INTO CONFIGURATION MODE
DATAOUT = %10001010
GOSUB SENDCANDATA

MCPREG = CNF3 'CNF3 - CONFIGURATION REGISTER 3
DATAOUT = $07
GOSUB SENDCANDATA

MCPREG = CNF2 'CNF2 - CONFIGURATION REGISTER 2
DATAOUT = $BA
GOSUB SENDCANDATA

MCPREG = CNF1 'CNF1 - CONFIGURATION REGISTER 1
DATAOUT = $03
GOSUB SENDCANDATA

MCPREG = TXB0SIDL 'TRANSMIT BUFFER 0 FOR SIDL
DATAOUT = %10000000
GOSUB SENDCANDATA

MCPREG = TXB0SIDH 'TRANSMIT BUFFER 0 FOR SIDH
DATAOUT = %00000001
GOSUB SENDCANDATA

MCPREG = CANCTRL 'PUT THE MCP2515 BACK INTO NORMAL MODE
DATAOUT = %00001010
GOSUB SENDCANDATA
HIGH CS



'================================================= =============================
' MAIN PROGRAM FOR MCP2515
'================================================= =============================

PROGRAMSTART:
HIGH SENDLED
PAUSE 50

LOW CS

SSPBUF = $02 ' COMMAND TO WRITE TO THE MCP2515
PIR1.3 = 0
WHILE PIR1.3=0 :WEND

MCPREG = CANINTE ' DISABLE ALL INTERRUPTS
DATAOUT = %00000000
GOSUB SENDCANDATA

MCPREG = TXB0CTRL ' FLAG THE TRANSMIT BUFFER - - 11=HIGH, 10=MEDIUM, 01=LOW, 00=LOWEST
DATAOUT = %00001011
GOSUB SENDCANDATA

MCPREG = TXB0SIDL ' TRANSMIT BUFFER 0 FOR SIDH
DATAOUT = %00110010
GOSUB SENDCANDATA

MCPREG = TXB0SIDH ' TRANSMIT BUFFER 0 FOR SIDH
DATAOUT = %00110001
GOSUB SENDCANDATA

MCPREG = TXB0DLC ' NUMBER OF BYTES TO BE TRANSMITTED IN CAN FRAME
DATAOUT = %00000010
GOSUB SENDCANDATA

MCPREG = TXB0D0 ' DATA PACKET FOR BYTE 1
DATAOUT = %00000001
GOSUB SENDCANDATA

MCPREG = TXB0D1 'DATA PACKET FOR BYTE 2
DATAOUT = %00000100
GOSUB SENDCANDATA


HIGH CS

LOW sendled
pause 50



goto PROGRAMSTART
'================================================= ==============================
' SEND CAN DATA SECTION
'================================================= ==============================
SENDCANDATA:

SSPBUF = MCPREG ' ADDRESS TO LOAD THE DATA TO THE MCP2515
PIR1.3 = 0
WHILE PIR1.3=0 : WEND
SSPBUF = DATAOUT 'DATA BEING LOADED TO THE MCP2515 ON MCPREG
PIR1.3 = 0
WHILE PIR1.3=0 : WEND

RETURN

HenrikOlsson
- 16th July 2012, 15:15
Hi Christopher,
OK, you're making progress, don't give up!

You have ADCON1 = 0 which will have all 13 analog pins set as analog, you probably want to turn the analog stuff OFF by setting ADCON1 = 15. For example RB0 and RB1 are AN12 and AN10 respectively but they are also the SDI and SCK pins for the MSSP module - that may or may not be part of the problem.

You have CMOCON = 0 which will leave both analog comparators ON, to turn them OFF on the 4550 you need to do CMCON = 7 - may or may not be part of the problem depending on exactly which pins they are on and what you're using, or trying to use, them for - I haven't looked into it.

The MCP2515 SPI timing diagrams show the SPI clock idling LOW. You have SSPCON1.4 set to 1 which will make the clock idle HIGH, ie wrong polarity.

Well, that's three things I see that may have something to do with it. Try adressing those, then try capturing the signals with your scope and see if they look anything like the timing diagrams in the MCP2515 datasheet.

/Henrik.

Christopher4187
- 20th July 2012, 06:23
Jag är trött.....snälla hjälp mig!

It's 1am here so hopefully this post is clear enough and someone can help me! I've been adjusting settings and trying new things and it still doesn't work. Here is what it boils down to. This is a picture of the working code from Microchip (if I knew C I'd be done already).

Channel 1 (Yellow) SDO from 18F4550
Channel 2 (Blue) CS from 18F4550
Channel 3 (Purple) TXCAN from MCP2515
Channel 4 (Green) CLK from 18F4550?

6601
This is what I'm looking to achieve.

This is what my code looks like:
6600
At least it's not that much different and I'm in the ballpark. What I can see is the signals are similar but way more compressed. It seems like a timing issue but I really don't know.

I adjusted the oscilloscope to the same seconds/division as the Microchip example and it's very compressed. It looks like this:6602

I tried adjusting the HSPLL to HS and that seemed to make things a little better but didn't do much as far as a working program. The clock still looks strange when I compare it with the Microchip code.
6603

The other things I see wrong:

1. The code I'm using is sending one data packet, along with SIDH and SIDL. I setup Microchip's program to do the same thing. I can't figure out why but my code is sending a lot more than a few bytes of data. In fact, it overloads the demo program that Microchip supplies and shuts it down.

2. Microchip's code sends the CAN data after the CS line goes high. For some reason, my program sends it halfway through the data transfer and my SDO line and the CAN output line are sending data at the same time. I did it once (send data after the CS line went high) but I can't remember what I did.

3. I'm confused with the CKE/CKP bits and not sure what I need to set them as. I see this "mode 0,0" advertised in the MCP2515 datasheet but it literally means nothing to me and I'm sure it's pretty important.

4. Did I properly set my BAUDCON?

HenrikOlsson
- 20th July 2012, 07:19
Hi Christopher,
Being tired and trying to solve problems usually don't go hand in hand....

1) I don't know why your code is sending more data than the Microchip example because A) I don't know which Microchip example your talking about and B) I don't see your code so it's impossible to say. Besides I'm not very good at reading C either.

2) Your program probably transfers the CAN data to the MCP2515. It then starts to send it down the CAN-bus WHILE your program continues to transfer some other data to the MCP2515. The MCP example, since it apparently transfers LESS data the MCP2515 than your code, de-asserts the CS line right after transfering the actual data to be sent. (All guesses of course.)

3) CKP is Clock Polarity. 0 means clock idles low, 1 means clock idles high. CKE is the "phase" of the data being output by the PIC on the SDO-pin. Here's a quote form the MCP2515 datasheet

Commands and data are sent to the device via the SI pin, with data being clocked in on the rising edge of SCK. Data is driven out by the MCP2515 (on the SO line) on the falling edge of SCK.
This means that the PIC must have the state of SDO pin valid by the time the rising edge of the clock occurs. The datasheet for the 18F4550 explains: When CKE bit is set, the SDO data is valid before there is a clock edge on SCK. So, my vote is for CKP=0, CKE=1 which should have the data output covered.

The SMP bit in the PIC controls when the SDI-input is sampled relative to the clock. Since the MCP2515 outputs data on the falling edge of CLK-input we need to sample at, or after, that event. Looking at figure 19-3 and following the CKP0=0,CKE=0 trace down in the diagram we can see that in order to sample at the falling edge of the clock we need to have SMP=1.

It is a bit confusing and I can honestly say that I'm not 100% confident I've got this right but that's my interpretation of the two the datasheets and it is what I'd try as starting point.

4) BAUDCON in the 18F4550 is used to control the baudrate of the EUSART and has nothing to do with the MSSP module. The SPI clock rate of the MSSP module is a function of the device clock (Fosc) and the divide ratio set by the lower two bits in the SSPCON1 register.

/Henrik.

Christopher4187
- 20th July 2012, 10:16
I made my last post at 1:23am, it's now 5:11am and I've been up for 20 minutes getting ready for work. My math tells me that's about 3.5 hours or so.....

Yes, I see I forgot to attach my code. I knew I forgot something! I also attached the Microchip C code as well.




================================================== ============================
' DEFINES & INCLUDES
'================================================= ==============================
INCLUDE "modedefs.bas"
'
DEFINE OSC 20

' ================================================== ============================
' CONFIGS
'================================================= ==============================

@ __CONFIG _CONFIG1L, _PLLDIV_5_1L & _CPUDIV_OSC1_PLL2_1L & _USBDIV_2_1L
@ __CONFIG _CONFIG1H, _FOSC_HSPLL_HS_1H & _FCMEN_OFF_1H & _IESO_OFF_1H
@ __CONFIG _CONFIG2L, _PWRT_OFF_2L & _BOR_OFF_2L & _BORV_3_2L & _VREGEN_ON_2L
@ __CONFIG _CONFIG2H, _WDT_OFF_2H & _WDTPS_32768_2H
@ __CONFIG _CONFIG3H, _CCP2MX_ON_3H & _PBADEN_OFF_3H & _LPT1OSC_OFF_3H & _MCLRE_ON_3H
@ __CONFIG _CONFIG4L, _STVREN_ON_4L & _LVP_OFF_4L & _ICPRT_ON_4L & _XINST_OFF_4L

'================================================= =============================
' SETTINGS
' ================================================== ============================
'76543210 '76543210
TRISA = %00010110: PORTA = %00000000
TRISB = %00010001: PORTB = %00010000
TRISC = %00000000: PORTC = %00000001
TRISD = %00011100: PORTD = %00000000
TRISE = %00010000: PORTE = %00010111
ADCON0 = %00111100
ADCON1 = 15
ADRESH = %00000000
ADRESL = %00000000
CMCON = 7
SSPSTAT = %01100100
SSPCON1 = %00100001
BAUDCON = %00001111


'================================================= ==============================
' Register Mapping
'================================================= ===============================

CANSTAT CON $0E
CANCTRL CON $0F
BFPCTRL CON $0C
TEC CON $1C
REC CON $1D
CNF3 CON $28
CNF2 CON $29
CNF1 CON $2A
CANINTE CON $2B
CANINTF CON $2C
EFLG CON $2D
TXRTSCTRL CON $0D

'' Recieve Filters ''
RXF0SIDH CON $00
RXF0SIDL CON $01
RXF0EID8 CON $02
RXF0EID0 CON $03
RXF1SIDH CON $04
RXF1SIDL CON $05
RXF1EID8 CON $06
RXF1EID0 CON $07
RXF2SIDH CON $08
RXF2SIDL CON $09
RXF2EID8 CON $0A
RXF2EID0 CON $0B
RXF3SIDH CON $10
RXF3SIDL CON $11
RXF3EID8 CON $12
RXF3EID0 CON $13
RXF4SIDH CON $14
RXF4SIDL CON $15
RXF4EID8 CON $16
RXF4EID0 CON $17
RXF5SIDH CON $18
RXF5SIDL CON $19
RXF5EID8 CON $1A
RXF5EID0 CON $1B

'' Receive Masks ''
RXM0SIDH CON $20
RXM0SIDL CON $21
RXM0EID8 CON $22
RXM0EID0 CON $23
RXM1SIDH CON $24
RXM1SIDL CON $25
RXM1EID8 CON $26
RXM1EID0 CON $27

'' Tx Buffer 0 ''
TXB0CTRL CON $30
TXB0SIDH CON $31
TXB0SIDL CON $32
TXB0EID8 CON $33
TXB0EID0 CON $34
TXB0DLC CON $35
TXB0D0 CON $36
TXB0D1 CON $37
TXB0D2 CON $38
TXB0D3 CON $39
TXB0D4 CON $3A
TXB0D5 CON $3B
TXB0D6 CON $3C
TXB0D7 CON $3D

'' Tx Buffer 1 ''
TXB1CTRL CON $40
TXB1SIDH CON $41
TXB1SIDL CON $42
TXB1EID8 CON $43
TXB1EID0 CON $44
TXB1DLC CON $45
TXB1D0 CON $46
TXB1D1 CON $47
TXB1D2 CON $48
TXB1D3 CON $49
TXB1D4 CON $4A
TXB1D5 CON $4B
TXB1D6 CON $4C
TXB1D7 CON $4D

'' Tx Buffer 2 ''
TXB2CTRL CON $50
TXB2SIDH CON $51
TXB2SIDL CON $52
TXB2EID8 CON $53
TXB2EID0 CON $54
TXB2DLC CON $55
TXB2D0 CON $56
TXB2D1 CON $57
TXB2D2 CON $58
TXB2D3 CON $59
TXB2D4 CON $5A
TXB2D5 CON $5B
TXB2D6 CON $5C
TXB2D7 CON $5D

'' Rx Buffer 0 ''
RXB0CTRL CON $60
RXB0SIDH CON $61
RXB0SIDL CON $62
RXB0EID8 CON $63
RXB0EID0 CON $64
RXB0DLC CON $65
RXB0D0 CON $66
RXB0D1 CON $67
RXB0D2 CON $68
RXB0D3 CON $69
RXB0D4 CON $6A
RXB0D5 CON $6B
RXB0D6 CON $6C
RXB0D7 CON $6D

'' Rx Buffer 1 ''
RXB1CTRL CON $70
RXB1SIDH CON $71
RXB1SIDL CON $72
RXB1EID8 CON $73
RXB1EID0 CON $74
RXB1DLC CON $75
RXB1D0 CON $76
RXB1D1 CON $77
RXB1D2 CON $78
RXB1D3 CON $79
RXB1D4 CON $7A
RXB1D5 CON $7B
RXB1D6 CON $7C
RXB1D7 CON $7D


'================================================= ==============================
' Register Bit Masks
'================================================= ==============================

DLC_0 CON $00
DLC_1 CON $01
DLC_2 CON $02
DLC_3 CON $03
DLC_4 CON $04
DLC_5 CON $05
DLC_6 CON $06
DLC_7 CON $07
DLC_8 CON $08



'================================================= ==============================
' ' CAN SPI commands
'================================================= ==============================
'
CAN_RST CON $C0
' CAN_READ $03
MCPWRT CON $02
' CAN_RTS $80
' CAN_RTS_TXB0 $81
' CAN_RTS_TXB1 $82
' CAN_RTS_TXB2 $84
' CAN_RD_STATUS $A0
' CAN_BIT_MODIFY $05
' CAN_RX_STATUS $B0
' CAN_RD_RX_BUFF $90
' CAN_LOAD_TX $40

'================================================= ==============================
' ALIAS & MODIFIERS
'================================================= =============================
CS VAR PORTB.4 ' CS LINE
SCLK VAR PORTB.1 ' CLOCK LINE
SDI VAR PORTB.0 ' DATA INPUT LINE
SDO VAR PORTC.7 ' DATA OUTPUT LINE
SENDLED VAR PORTA.5 ' LED TO INDICATE THE PROGRAM IS IN THE SENDING ROUTINE
MAINLED VAR PORTE.2 ' LED TO INDICATE THE PROGRAM IS IN THE MAIN ROUTINE
INT VAR PORTB.5 ' INTERRUPT OUTPUT FROM 18F4550
MCPRST VAR PORTC.0 ' RESET LINE FOR MCP2515
SW_LOAD VAR PORTA.4 ' BUTTON CONNECTED TO 18F4550 TO START SENDING DATA (WHEN IMPLEMENTED)
RX_LED VAR PORTD.1 ' USB RECEIVE LED
TX_LED VAR PORTD.0 ' USB TRANSMIT LED

'================================================= ==============================
' SOFTWARE VARIABLES
'================================================= ==============================

DATAOUT VAR BYTE 'FIRST BYTE OF DATA TO BE SENT
MCPREG VAR BYTE 'ADDRESS OF FIRST BYTE OF DATA TO BE SENT


TX_LED=1
RX_LED=1
'================================================= =============================
' RESET CAN
'================================================= =============================




'================================================= =============================
' RESET CAN
'================================================= =============================

'================================================= =============================
' INITIALIZE MCP2515
'================================================= =============================


LOW CS
SSPBUF = MCPRST ' COMMAND TO RESET THE MCP2515
PIR1.3 = 0
WHILE PIR1.3=0 :WEND
HIGH CS

PAUSE 1000
LOW CS

SSPBUF = mcpwrt ' COMMAND TO WRITE TO THE MCP2515
PIR1.3 = 0
WHILE PIR1.3=0 :WEND

MCPREG = CANCTRL 'PUT THE MCP2515 INTO CONFIGURATON MODE
DATAOUT = $08
GOSUB SEND_CAN_DATA

SSPBUF = cnf3 ' CNF3 REGISTER
PIR1.3 = 0
WHILE PIR1.3=0 :WEND

SSPBUF = $07 ' PART OF BAUD RATE
PIR1.3 = 0
WHILE PIR1.3=0 :WEND

SSPBUF = $BA ' PART OF BAUD RATE
PIR1.3 = 0
WHILE PIR1.3=0 :WEND

SSPBUF = $03 ' PART OF BAUDRATE
PIR1.3 = 0
WHILE PIR1.3=0 :WEND

MCPREG = CANCTRL 'PUT THE MCP2515 BACK INTO NORMAL MODE
DATAOUT = $0
GOSUB SEND_CAN_DATA

high cs







'================================================= =============================
' MAIN PROGRAM FOR MCP2515
'================================================= =============================

START:
HIGH SENDLED
PAUSE 4000

LOW CS

SSPBUF = mcpwrt ' COMMAND TO WRITE TO THE MCP2515
PIR1.3 = 0
WHILE PIR1.3=0 :WEND

MCPREG = CANINTE ' DISABLE ALL INTERRUPTS
DATAOUT = %00000000
GOSUB SEND_CAN_DATA

high cs ' ON THE MICROCHIP EXAMPLE, THEY PULLED THE CS LINE LOW, SENT
' SOME DATA, THEN HIGH AND LOW AGAIN TO RESEND MORE DATA. I
' I STILL CAN'T FIGURE OUT WHY. IT'S PROBABLY SOMETHING
' SIMPLE I AM MISSING BUT I TRIED TO DUPLICATE IT.
LOW CS

SSPBUF = mcpwrt ' COMMAND TO WRITE TO THE MCP2515
PIR1.3 = 0
WHILE PIR1.3=0 :WEND


MCPREG = TXB0CTRL ' FLAG THE TRANSMIT BUFFER - - 11=HIGH, 10=MEDIUM, 01=LOW, 00=LOWEST
DATAOUT = %00001011
GOSUB SEND_CAN_DATA

MCPREG = TXB0SIDL ' TRANSMIT BUFFER 0 FOR SIDH
DATAOUT = %0000000
GOSUB SEND_CAN_DATA

MCPREG = TXB0SIDH ' TRANSMIT BUFFER 0 FOR SIDH
DATAOUT = %00001000
GOSUB SEND_CAN_DATA

MCPREG = TXB0DLC ' NUMBER OF BYTES TO BE TRANSMITTED IN CAN FRAME
DATAOUT = %00000001
GOSUB SEND_CAN_DATA

MCPREG = TXB0D0 ' DATA PACKET FOR BYTE 1
DATAOUT = %00000111
GOSUB SEND_CAN_DATA

'MCPREG = TXB0D1 'DATA PACKET FOR BYTE 2
'DATAOUT = %00001111
'GOSUB SEND_CAN_DATA

HIGH CS


LOW sendled
pause 4000

goto START


'================================================= ==============================
' SEND CAN DATA SECTION
'================================================= ==============================
SEND_CAN_DATA:




SSPBUF = MCPREG ' ADDRESS TO LOAD THE DATA TO THE MCP2515
PIR1.3 = 0
WHILE PIR1.3=0 : WEND

SSPBUF = DATAOUT 'DATA BEING LOADED TO THE MCP2515 ON MCPREG
PIR1.3 = 0
WHILE PIR1.3=0 : WEND


RETURN








/************************************************** *******************
*
* Microchip USB C18 Firmware Version 1.0
*
************************************************** *******************
* FileName: main.c
* Dependencies: See INCLUDES section below
* Processor: PIC18
* Compiler: C18 2.30.01+
* Company: Microchip Technology, Inc.
*
* Software License Agreement
*
* The software supplied herewith by Microchip Technology Incorporated
* (the “Company”) for its PICmicro® Microcontroller is intended and
* supplied to you, the Company’s customer, for use solely and
* exclusively on Microchip PICmicro Microcontroller products. The
* software is owned by the Company and/or its supplier, and is
* protected under applicable copyright laws. All rights are reserved.
* Any use in violation of the foregoing restrictions may subject the
* user to criminal sanctions under applicable laws, as well as to
* civil liability for the breach of the terms and conditions of this
* license.
*
* THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
* TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
* IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
* Author Date Comment
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
* Rawin Rojvanit 11/19/04 Original.
************************************************** ******************/

#pragma config PLLDIV = 5 // (20 MHz crystal on PICDEM FS USB board)
#pragma config CPUDIV = OSC1_PLL2
#pragma config USBDIV = 2 // Clock source from 96MHz PLL/2
#pragma config FOSC = HSPLL_HS
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRT = OFF
#pragma config BOR = OFF
#pragma config BORV = 3
#pragma config VREGEN = ON //USB Voltage Regulator
#pragma config WDT = OFF
#pragma config WDTPS = 32768
#pragma config MCLRE = ON
#pragma config LPT1OSC = OFF
#pragma config PBADEN = OFF
#pragma config CCP2MX = ON
#pragma config STVREN = ON
#pragma config LVP = OFF
#pragma config ICPRT = ON // Dedicated In-Circuit Debug/Programming
#pragma config XINST = OFF // Extended Instruction Set
#pragma config CP0 = OFF
#pragma config CP1 = OFF
#pragma config CP2 = OFF
#pragma config CP3 = OFF
#pragma config CPB = OFF
#pragma config CPD = OFF
#pragma config WRT0 = OFF
#pragma config WRT1 = OFF
#pragma config WRT2 = OFF
#pragma config WRT3 = OFF
#pragma config WRTB = OFF // Boot Block Write Protection
#pragma config WRTC = OFF
#pragma config WRTD = OFF
#pragma config EBTR0 = OFF
#pragma config EBTR1 = OFF
#pragma config EBTR2 = OFF
#pragma config EBTR3 = OFF
#pragma config EBTRB = OFF



/** I N C L U D E S ************************************************** ********/
#include <p18cxxx.h>
#include "system\typedefs.h" // Required
#include "system\usb\usb.h" // Required
#include "io_cfg.h" // Required

#include "system\usb\usb_compile_time_validation.h" // Optional
#include "user\BusMon.h" // Modifiable


/** V A R I A B L E S ************************************************** ******/
#pragma udata

/** P R I V A T E P R O T O T Y P E S ***************************************/
static void InitializeSystem(void);
void USBTasks(void);

/** V E C T O R R E M A P P I N G *******************************************/

/*
extern void _startup (void); // See c018i.c in your C18 compiler dir
#pragma code _RESET_INTERRUPT_VECTOR = 0x002000
void _reset (void)
{
_asm goto _startup _endasm
}
*/

//#pragma code _HIGH_INTERRUPT_VECTOR = 0x002008
//void _high_ISR (void)
//{
// ;
//}
//
//#pragma code LOW_INTERRUPT_VECTOR = 0x002018
//void _low_ISR (void)
//{
// _asm
// goto InterruptHandler
// _endasm
//}

#pragma code

/************************************************** ****************************
* Function: void main(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Main program entry point.
*
* Note: None
************************************************** ***************************/
void main(void)
{
InitializeSystem();
UserInit(); // See BusMon.c & .h
while(1)
{
if(usb_power_check) //Only do USB USB if not powered by CAN connector
USBTasks(); // USB Tasks
// INTCONbits.GIE = 1;
ProcessIO(); // See user\BusMon.c & .h
}
}//end main

/************************************************** ****************************
* Function: static void InitializeSystem(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: InitializeSystem is a centralize initialization routine.
* All required USB initialization routines are called from
* here.
*
* User application initialization routine should also be
* called from here.
*
* Note: None
************************************************** ***************************/
static void InitializeSystem(void)
{
ADCON1 |= 0x0F; // Default all pins to digital

#if defined(USE_USB_BUS_SENSE_IO)
tris_usb_bus_sense = INPUT_PIN; // See io_cfg.h
#endif

#if defined(USE_SELF_POWER_SENSE_IO)
tris_self_power = INPUT_PIN;
#endif

if(usb_power_check) //Only initialize USB if not powered by CAN connector
mInitializeUSBDriver(); // See usbdrv.h

}//end InitializeSystem

/************************************************** ****************************
* Function: void USBTasks(void)
*
* PreCondition: InitializeSystem has been called.
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Service loop for USB tasks.
*
* Note: None
************************************************** ***************************/
void USBTasks(void)
{
/*
* Servicing Hardware
*/
USBCheckBusStatus(); // Must use polling method
if(UCFGbits.UTEYE!=1)
USBDriverService(); // Interrupt or polling method

}// end USBTasks


////************************************************** ***************************
//// High priority interrupt vector
//#pragma code InterruptVectorHigh = 0x08
//void InterruptVectorHigh(void)
//{
//_asm
//bra InterruptHandler // jump to interrupt routine
//_endasm
//}
//#pragma code InterruptVectorHigh = 0x08
//void InterruptVectorLow(void)
//{
//_asm
//bra InterruptHandler // jump to interrupt routine
//_endasm
//}
//
//
//#pragma code
//#pragma interrupt InterruptHandler
//void InterruptHandler(void)
//{
//}

/** EOF main.c ************************************************** *************/

HenrikOlsson
- 20th July 2012, 11:50
Hi Christopher,
That Microchip code doesn't make any sense at all in this context. I see a lot of USB references but nothing about the MSSP module or the MCP2515.

But I took another look at your code.... At the very beginning, in the INITIALIZE MCP2515 section you have this piece of code:

LOW CS
SSPBUF = MCPRST ' COMMAND TO RESET THE MCP2515
PIR1.3 = 0
WHILE PIR1.3=0 :WEND
HIGH CS
I then went to see exactly what MCPRST was and the only thing I found in your code was an alias to PortC.0 so what's happening in that piece of code is that the PIC reads PortC.0 and then the result of that read operation (1 or 0) to SSPBUF. To reset the device you either pull the hardware reset line LOW or send $C0 over SPI.

Properly resetting the device automatically puts in the configuration mode so therotically you shouldn't need to put it in that mode directly after a (proper) reset. Then your comments says that you're writing to "part of baudrate" or something but $07 is the EXTENDED IDENTIFIER LOW register receiver 1, $03 is EXTENDED IDENTIFIER LOW register for receiver 0 and I can't even find what $BA is.

OK, moving to MAIN then....
You send the command to write then you send the value 0 to CANINTE at adress $02, that all seems OK to me if disabling interrupts is what you want to do.

Next you set the TXB0CTRL register for a high priority message and request it to send. Then you write the TRANSMIT BUFFER STANDARD IDENTIFIER register. I have no idea what these does so I'm going to asume it's correct. Then, you tell it you want to send a single byte by writing the value 1 to TXB0DLC and then you write the actual data.

Personally I would've thought you should first load the data to be sent THEN tell the device to send it. Ie write TXB0CTRL after you've loaded the data but the way you have it might be correct.

OK, that's it for now. It feels like your pretty close.

/Henrik.

Christopher4187
- 20th July 2012, 12:47
Yeah, I can see where my post was confusing. Let me clarify a few things.


That Microchip code doesn't make any sense at all in this context. I see a lot of USB references but nothing about the MSSP module or the MCP2515.I attached the main code but I meant to attach another sheet.

/** D E C L A R A T I O N S **************************************************/

#define Mode00 0
#define Mode11 1

#define ON 1
#define OFF 0

#define HIGH 1
#define LOW 0


//#pragma code
//-----------------------------------------------------------------------------
// SPIReset()
//-----------------------------------------------------------------------------
void SPIReset(void)
{
CS_2515_LOW();
WriteSPI(CAN_RESET);
CS_2515_HIGH();
for(dummy=0; dummy<255; dummy++);


}

//-------------------------------------------------------------------------
// SPIByteWrite()
//-------------------------------------------------------------------------
void SPIByteWrite(unsigned char addr, unsigned char value )
{
CS_2515_LOW();
while(WriteSPI(CAN_WRITE));
while(WriteSPI(addr));
while(WriteSPI(value));
CS_2515_HIGH();
}

//-------------------------------------------------------------------------
// Function Name: SPISegWrite
// Return Value: None
// Parameters: Starting address, numbytes, and pointer
// to an array.
// Description: This routine performs a sequential write.
//-------------------------------------------------------------------------
void SPISeqWrite(unsigned char startaddr, unsigned char numbytes, char *data)
{
unsigned char n;

CS_2515_LOW();
while( WriteSPI(CAN_WRITE) );
while( WriteSPI(startaddr) );
for(n=0; n<numbytes; n++)
while( WriteSPI(data[n]) );
CS_2515_HIGH();
}


//-----------------------------------------------------------------------------
// SPIByteRead()
//-----------------------------------------------------------------------------
unsigned char SPIByteRead(unsigned char addr)
{
unsigned char tempdata;
CS_2515_LOW();
WriteSPI(CAN_READ);
WriteSPI(addr);
tempdata = ReadSPI();
CS_2515_HIGH();
return tempdata;
}

//-----------------------------------------------------------------------------
// SPISeqRead(unsigned char startaddr, unsigned char numbytes, *data)
// Return Value: None (puts read data in string)
// Parameters: Starting address, numbytes, and pointer
// to an array.
// Description: Sequential read from the MCP2515
//-----------------------------------------------------------------------------
void SPISeqRead(unsigned char startaddr, unsigned char numbytes, char *data)
{
unsigned char n;
CS_2515_LOW();
while( WriteSPI(CAN_READ) );
while( WriteSPI(startaddr) );
for(n=0; n<numbytes; n++)
{
data[n] = ReadSPI();
}
data[n] = ReadSPI(); //Last byte
CS_2515_HIGH();
}

//-----------------------------------------------------------------------------
// SPIReadRX(unsigned char opcode, unsigned char numbytes, unsigned char *data)
// opcode = SPI opcode and pointer to RXBn register location// (see datasheet)
// numbytes = number of bytes to read
// *data = pointer to a string of data
//
//-----------------------------------------------------------------------------
void SPIReadRX(unsigned char opcode, unsigned char numbytes, char *data)
{
unsigned char n;
CS_2515_LOW();
while( WriteSPI(opcode));
for(n=0; n<numbytes; n++)
{
data[n] = ReadSPI();
}
data[n] = ReadSPI(); //Last byte
CS_2515_HIGH();
}

//-----------------------------------------------------------------------------
// SPILoadTX(unsigned char opcode, unsigned char numbytes, unsigned char *data)
// opcode = SPI opcode and pointer to TXBn register location// (see datasheet)
// numbytes = number of bytes to write
// *data = pointer to a string of data
//
//-----------------------------------------------------------------------------
char SPILoadTX(unsigned char opcode, unsigned char numbytes, char *data)
{
unsigned char n, buff;

//Check if this function is suppossed to choose the TX buffer to load
if(opcode == CAN_LOAD_TX)//This function chooses the buffer
{
n = SPIReadStatus();
//Check for free buffer
if(!(n & 0x04)) //TXB0 is available
opcode = CAN_LD_TXB0_ID; //Point to TXB0SIDH
else if(!(n & 0x10)) //TXB1 is available
opcode = CAN_LD_TXB1_ID; //Point to TXB1SIDH
else if(!(n & 0x40)) //TXB2 is available
opcode = CAN_LD_TXB2_ID; //Point to TXB2SIDH
else if(n & 0x54) //No buffers available
{
SPIByteWrite(TXB0CTRL, 0x00); //Clear TXREQ (and whole register)
for(dummy=0; dummy<255; dummy++);
opcode = CAN_LD_TXB0_ID; //Point to TXB0SIDH
}
}

CS_2515_LOW();
while( WriteSPI(opcode) );
for(n=0; n<numbytes; n++)
while( WriteSPI(data[n]) );
CS_2515_HIGH();

return(opcode); //So calling function knows which buffer was loaded
}

//-----------------------------------------------------------------------------
// RTS(buffer)
// buffer = CAN_RTS_TXBn; where 'n' = 0, 1, 2
// OR
// buffer = CAN_RTS; followed by | 0 - 7 (e.g., "CAN_RTS | 7" sends TX0 and TX1)
// OR
// buffer = CAN_RTS_TXBn | CAN_RTS_TXBn | CAN_RTS_TXBn; where 'n' = 0, 1, 2
//-----------------------------------------------------------------------------
void SPI_RTS(unsigned char buffer)
{
unsigned char tempdata;
tempdata = SPIReadStatus();

if(buffer & 0x01) //Buffer 0
if(tempdata & 0x04) //Check TXREQ first
{
Delay_ms(1);
SPIByteWrite(TXB0CTRL, 0); //Clear TXREQ (and everything else... not clean)
while(SPIReadStatus() & 0x04); //Wait for TXREQ to clear
}
if(buffer & 0x02) //Buffer 1
if(tempdata & 0x10) //Check TXREQ first
{
Delay_ms(1);
SPIByteWrite(TXB1CTRL, 0); //Clear TXREQ (and everything else... not clean)
while(SPIReadStatus() & 0x10); //Wait for TXREQ to clear
}
if(buffer & 0x04) //Buffer 2
if(tempdata & 0x40) //Check TXREQ first
{
Delay_ms(1);
SPIByteWrite(TXB2CTRL, 0); //Clear TXREQ (and everything else... not clean)
while(SPIReadStatus() & 0x40); //Wait for TXREQ to clear
}

CS_2515_LOW();
WriteSPI(buffer);
CS_2515_HIGH();
}

//-----------------------------------------------------------------------------
// char SPIReadStatus//(void)
// Performs Read Status command and returns result
//-----------------------------------------------------------------------------
char SPIReadStatus(void)
{
unsigned char tempdata;
CS_2515_LOW();
WriteSPI(CAN_RD_STATUS);
tempdata = ReadSPI();
CS_2515_HIGH();
return tempdata;
}

//-----------------------------------------------------------------------------
// Delay_ms()
// Tcy = 1 us
// Tcy X 1000 = 1 ms
// FFFFh - 3E8h (1000d) = FC17h
// For(){} loop is in 1 ms increments
//-----------------------------------------------------------------------------
void Delay_ms(unsigned char num_ms)
{
unsigned char n;

TMR1H = 0xFC;
TMR1L = 0x17;

T1CONbits.TMR1ON = 1; //Start timer

for(n = 0; n < num_ms; n++)
{
while(!PIR1bits.TMR1IF); //Wait for timer flag
PIR1bits.TMR1IF = 0; //Clear flag
TMR1H = 0xFC;
TMR1L = 0x17;
}

T1CONbits.TMR1ON = 0; //Stop timer
}





/** P R I V A T E P R O T O T Y P E S ***************************************/
void CheckLoadButton(void);
unsigned char ReadSPI( void );
void SetBitTiming(char data_rate);
void CANLoadTX(void);

/** D E C L A R A T I O N S **************************************************/
#define CAN_1000kbps 0 //BRP setting in CNF1
#define CAN_500kbps 1 //
#define CAN_250kbps 3 //
#define CAN_125kbps 7 //

/** S T R U C T S ************************************************** ******/
struct {
unsigned char INTF:1; //bit 0
unsigned char MCP_RXBn:2;
unsigned char SOF:1;
unsigned char USBsend:1;
unsigned char USBQueue:1;
unsigned char CANLoading:1;
unsigned char Flag8:1;
} UserFlag;


struct {
unsigned char BusLoad:2; //bit 0
unsigned char TX_buff:2; //OUT message to instruct TX buff to send
unsigned char CAN_USB_PTR:2;
unsigned char nu2:1;
unsigned char nu3:1;
} usbcan_STATUS;


/** V A R I A B L E S ************************************************** ******/
#pragma udata
//byte old_sw2,old_sw3;

BOOL emulate_mode;
rom signed char dir_table[]={-4,-4,-4, 0, 4, 4, 4, 0};
byte movement_length;
byte vector = 0;

byte AquireData = 1; //0 = STOP; 1 = Aquire (Not Used)
char buffer[3];
char inbuffer[BUF_SIZE]; // 64 byte input to USB device buffer
char outbuffer[BUF_SIZE]; // 64 byte output to USB device buffer

byte TimerCounter = 0xF0;
static unsigned char gTimeout = 0;

unsigned int CANLoadTimer = 0x00;
unsigned int LoadPrescaler = 0x8000;

static byte LOAD_FLAG = PERCENT_0;

static char USB_ptr = 0xFF; //Points to the USB location of the start of the
//four possible CAN messages
static char old_CANCTRL; //Used to track CANCTRL changes from host


char DataArray[32];
char ReadArray[32];

#pragma code

/************************************************** ****************************
* Function: void ProcessIO
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This function is a place holder for other user routines.
* It is a mixture of both USB and non-USB tasks.
*
* Note: None
************************************************** ***************************/
void ProcessIO(void)
{
unsigned char n, b, c, y;
int a;
// User Application USB tasks

if(!(usb_power_check)) //Only generate traffic if NOT connected to USB
{
CheckLoadButton();
CANLoadTX();
}

if((usb_device_state < CONFIGURED_STATE)||(UCONbits.SUSPND==1)) return;

//----- Read USB buffer if it has data from the host -----
if (HIDRxReport(inbuffer, 64)) // USB receive buffer has data
{
LED_RX_ON(); //Turn LED on
T0CONbits.TMR0ON = 1; //Start timer for TX LED on time
gTimeout = 0; //Reset timout

//---- CANmsgs: Check if host has requested CAN messages to be transmited
switch(inbuffer[u_CANmsgs]) // interpret command
{
case 0x00: // No messages are available
break;

case 0x01: // Message 1 is available
GetUSBData(m1_SIDH, 13, DataArray);
n = SPILoadTX(CAN_LOAD_TX, 13, DataArray);

if(n == CAN_LD_TXB0_ID) //if TX0 is loaded
{
RTS0_2515_LOW();
RTS0_2515_HIGH();
}
else if(n == CAN_LD_TXB1_ID) //if TX1 is loaded
{
RTS1_2515_LOW();
RTS1_2515_HIGH();
}
else if(n == CAN_LD_TXB2_ID) //if TX2 is loaded
{
RTS2_2515_LOW();
RTS2_2515_HIGH();
}
break;

case 0x02: // Message 1 and 2 are available
//Message 1
GetUSBData(m1_SIDH, m1_DLC + 5, DataArray);
n = SPILoadTX(CAN_LOAD_TX, m1_DLC + 5, DataArray);

if(n == CAN_LD_TXB0_ID) //if TX0 is loaded
{
RTS0_2515_LOW();
RTS0_2515_HIGH();
}
else if(n == CAN_LD_TXB1_ID) //if TX1 is loaded
{
RTS1_2515_LOW();
RTS1_2515_HIGH();
}
else if(n == CAN_LD_TXB2_ID) //if TX2 is loaded
{
RTS2_2515_LOW();
RTS2_2515_HIGH();
}

//Message 2
GetUSBData(m2_SIDH, m2_DLC + 5, DataArray);
n = SPILoadTX(CAN_LOAD_TX, m2_DLC + 5, DataArray);

if(n == CAN_LD_TXB0_ID) //if TX0 is loaded
{
RTS0_2515_LOW();
RTS0_2515_HIGH();
}
else if(n == CAN_LD_TXB1_ID) //if TX1 is loaded
{
RTS1_2515_LOW();
RTS1_2515_HIGH();
}
else if(n == CAN_LD_TXB2_ID) //if TX2 is loaded
{
RTS2_2515_LOW();
RTS2_2515_HIGH();
}
break;

case 0x03: // Message 1, 2, and 3 are available
//Message 1
GetUSBData(m1_SIDH, m1_DLC + 5, DataArray);
n = SPILoadTX(CAN_LOAD_TX, m1_DLC + 5, DataArray);

if(n == CAN_LD_TXB0_ID) //if TX0 is loaded
{
RTS0_2515_LOW();
RTS0_2515_HIGH();
}
else if(n == CAN_LD_TXB1_ID) //if TX1 is loaded
{
RTS1_2515_LOW();
RTS1_2515_HIGH();
}
else if(n == CAN_LD_TXB2_ID) //if TX2 is loaded
{
RTS2_2515_LOW();
RTS2_2515_HIGH();
}

//Message 2
GetUSBData(m2_SIDH, m2_DLC + 5, DataArray);
n = SPILoadTX(CAN_LOAD_TX, m2_DLC + 5, DataArray);

if(n == CAN_LD_TXB0_ID) //if TX0 is loaded
{
RTS0_2515_LOW();
RTS0_2515_HIGH();
}
else if(n == CAN_LD_TXB1_ID) //if TX1 is loaded
{
RTS1_2515_LOW();
RTS1_2515_HIGH();
}
else if(n == CAN_LD_TXB2_ID) //if TX2 is loaded
{
RTS2_2515_LOW();
RTS2_2515_HIGH();
}

//Message 3
GetUSBData(m3_SIDH, m3_DLC + 5, DataArray);
n = SPILoadTX(CAN_LOAD_TX, m3_DLC + 5, DataArray);

if(n == CAN_LD_TXB0_ID) //if TX0 is loaded
{
RTS0_2515_LOW();
RTS0_2515_HIGH();
}
else if(n == CAN_LD_TXB1_ID) //if TX1 is loaded
{
RTS1_2515_LOW();
RTS1_2515_HIGH();
}
else if(n == CAN_LD_TXB2_ID) //if TX2 is loaded
{
RTS2_2515_LOW();
RTS2_2515_HIGH();
}
break;

case 0x04: //--FUTURE-- Message 1, 2, 3, and 4 are available
break;

default: // unrecognized or null command
;
}// END switch: inbuffer[u_CANmsgs]

//---- CANCTRL: Write to the CANCTRL register if changed
if(inbuffer[u_CANCTRL] != old_CANCTRL) //If host sent new CANCTRL value
{
SPIByteWrite(CANCTRL,inbuffer[u_CANCTRL]); //Write to CANCTRL
EEPROMBYTEWrite(CANCTRL,inbuffer[u_CANCTRL]);
EEPROMCRCWrite(0,128);
old_CANCTRL = inbuffer[u_CANCTRL]; //
outbuffer[u_CANSTAT] = SPIByteRead(CANSTAT);
while((outbuffer[u_CANSTAT] & 0xE0) != (inbuffer[u_CANCTRL] & 0xE0))//if didn't change modes yet
{
outbuffer[u_CANSTAT] = SPIByteRead(CANSTAT);
}
UserFlag.USBsend = 1; //Set flag so will send USB message
}

//---- SPI: SPI command from host
if(inbuffer[u_SPI]) //If host sent SPI command (non-zero)
{
switch(inbuffer[u_SPI])
{
case CAN_RESET: //
SPIReset();
break;

case CAN_READ: //
if(!UserFlag.USBQueue) // If previous message is queued
{
outbuffer[u_SPI] = CAN_READ; //Send back to host
outbuffer[u_REG] = inbuffer[u_REG]; //Send back to host
outbuffer[u_DATA] = SPIByteRead(inbuffer[u_REG]); //Send back to host
}
UserFlag.USBsend = 1; //Set flag so will send USB message
UserFlag.USBQueue = 1; //Indicates msg is queued, but not sent
break;

case CAN_WRITE: //
//outbuffer[u_SPI] = 0; //Send back to host //JM
SPIByteWrite(inbuffer[u_REG],inbuffer[u_DATA]);
EEPROMBYTEWrite(inbuffer[u_REG],inbuffer[u_DATA]);
EEPROMCRCWrite(0,128);
break;

case CAN_RTS: //
SPI_RTS(inbuffer[u_DATA]);
break;

case CAN_RD_STATUS: //
outbuffer[u_DATA] = SPIReadStatus();
UserFlag.USBsend = 1; //Set flag so will send USB message
break;

default: // unrecognized or null command
;
}// END switch: inbuffer[u_SPI]
}
}//END if (HIDRxReport(inbuffer, 1)

//---- Check RXnBF pins and service messages as needed ---
switch(CheckCANRX()) // Check if CAN message received
{
case 0x01: // Message in RXB0 (Msgs in this buffer are Standard)
SPIReadRX(CAN_RD_START_RXB0SIDH, 13, ReadArray);
LoadUSBString(ReadArray);
break;

case 0x02: // Message in RXB1 (Msgs in this buffer are Extended)
SPIReadRX(CAN_RD_START_RXB1SIDH, 13, ReadArray);
LoadUSBString(ReadArray);
break;

case 0x03: // Message in RXB0 and RXB1
SPIReadRX(CAN_RD_START_RXB0SIDH, 13, ReadArray);
LoadUSBString(ReadArray);
SPIReadRX(CAN_RD_START_RXB1SIDH, 13, ReadArray);
LoadUSBString(ReadArray);
break;

default: // unrecognized or null command
;
}// END switch: CheckCANRX()

//---- The following turns off the TX and RX USB indicator LEDs after some time
//Inst. cycle = 200 ns; TMR0IF sets every 51 us
if(INTCONbits.TMR0IF)
{
TimerCounter++;
if (!TimerCounter) //if rolled over, set flag. User code will handle the rest.
{
LED_TX_OFF(); //Turn LED off
LED_RX_OFF(); //Turn LED off
T0CONbits.TMR0ON = 0; //Start timer for TX LED on time
TimerCounter = 0xFE;
gTimeout = 1; //Reset timout
}
INTCONbits.TMR0IF = 0;
}

//------ Load USB Data to be transmitted to the host --------
if(UserFlag.MCP_RXBn | UserFlag.USBsend)
{
if(!mHIDTxIsBusy())
{
HIDTxReport(outbuffer, 64);

outbuffer[0] = 0x00; //PKR$$$ Need this??

UserFlag.MCP_RXBn = 0; //clear flag
UserFlag.USBsend = 0; //clear flag
UserFlag.USBQueue = 0; //Clear message queue

LED_TX_ON(); //Turn LED on
T0CONbits.TMR0ON = 1; //Start timer for TX LED on time
gTimeout = 0; //Reset timout

outbuffer[u_SPI] = 0x00; //clear back to 00h so host doesn't detect "SPI response"
USB_ptr = 0xFF; //Point to location 0xFF
outbuffer[u_CANmsgs] = 0x00; //Clear message status
}
}
}//end ProcessIO


/************************************************** ****************************
* Function: char CheckCANRX(void)
*
* PreCondition: None
*
* Input: None
*
* Output: Which RX buffer have message
* 0 = None; 1 = RXB0; 2 = RXB1; 3 = Both buffers
*
* Side Effects: None
*
* Overview:
*
* Note:
************************************************** ***************************/
char CheckCANRX(void)
{
//First, set the correct flag. ORs with flag because this might not be the
//1st time through
UserFlag.MCP_RXBn = 0;

if(!RXB0_2515) UserFlag.MCP_RXBn = UserFlag.MCP_RXBn | 0x01; //RXB0 is active low
if(!RXB1_2515) UserFlag.MCP_RXBn = UserFlag.MCP_RXBn | 0x02; //RXB1 is active low

return UserFlag.MCP_RXBn;
}

/************************************************** ****************************
* Function: void LoadUSBString//(char *data)
*
* PreCondition: Set the pointer to the USB array "USB_ptr"
*
* Input: Pointer to array that contains the data to write to USB
*
* Output: None
*
* Side Effects: None
*
* Overview: Loads data read from the MCP2515 RX buffer. Note, the
* function already knows the *data is 13 bytes
*
* Note:
************************************************** ***************************/
void LoadUSBString(char *data)
{
unsigned char n, rtr, ide, dlc, num_bytes, CAN_ptr;

CAN_ptr = 0;

if(USB_ptr == 0xFF) //If 0xFF, then this is the 1st time through
USB_ptr = 0;

//-----Calculate how big the CAN msg is... how many USB bytes to use---
if(data[mx_SIDL] & 0x08){ //If extended ID
ide = 0x20; //Maps to 'INFO' byte in USB
num_bytes = 0x04; ` //All four ID registers (extended ID)
}
else{
ide = 0x00; //Maps to 'INFO' byte in USB
num_bytes = 0x02; //Just the standard ID registers
}

if(ide) //If extended ID, then RTR is in DLC; else in SIDL
{
if(data[mx_DLC] & 0x40){ //RTR bit in DLC
rtr = 0x10; //Maps to 'INFO' byte in USB
}
else{
rtr = 0x00; //Maps to 'INFO' byte in USB
}
}
else
{
if(data[mx_SIDL] & 0x10){ //RTR bit in SIDL
rtr = 0x10; //Maps to 'INFO' byte in USB
}
else{
rtr = 0x00; //Maps to 'INFO' byte in USB
}
}
dlc = data[mx_DLC] & 0x0F; //Determine the data length code
//END--Calculate how big the CAN msg is... how many USB bytes to use---END

//Calculate if there is enough room to add the CAN message to USB:
//52 is the location of the 1st control message. Subract the pointer location
//If this is larger than the current CAN message (includes the "INFO" byte)
//then can load 'outbuffer[]'. Otherwise, will need to switch interfaces
//(assuming currently on the 1st interface).

//If enough room, add the bytes
if(52 - USB_ptr > num_bytes)
{
//Now load the 'INFO' byte
outbuffer[USB_ptr] = 0x80 + ide + rtr + dlc;
USB_ptr++;

//Load the identifier registers
for(n=0; n<num_bytes; n++)
{
outbuffer[USB_ptr] = data[CAN_ptr];
USB_ptr++;
CAN_ptr++;
}

if(!ide) CAN_ptr = CAN_ptr + 2; //skip over EXIDE regs
CAN_ptr++; //skip over the DLC register

if(!rtr) //if a data frame
{
//Load the data registers
for(n=0; n<dlc; n++) //
{
outbuffer[USB_ptr] = data[CAN_ptr];
USB_ptr++;
CAN_ptr++;
}
}

//Now clear next byte (STATUS). Cleared to 0 in case this is the last time through.
//PC looks at MSb and, if clear, no message follows
outbuffer[USB_ptr] = 0x00;

//Next, need to load the other status bytes from byte 53 - 59
//[CANINTF, EFLG, TEC, REC, CANSTAT, CANCTRL]

//Need to read TEC, REC, and CANSTAT to report to host
SPISeqRead(TEC, 3, ReadArray);
outbuffer[u_TEC] = ReadArray[0];
outbuffer[u_REC] = ReadArray[1];
outbuffer[u_CANSTAT] = ReadArray[2];
}
}

/************************************************** ****************************
* Function: void GetUSBData//(char start_ptr, char num_bytes, char *data)
*
* PreCondition: None
*
* Input: Pointer to location in USB string
* Number of bytes to get
* Pointer to array that contains the data to write to USB
*
* Output: None
*
* Side Effects: None
*
* Overview: Gets data from the USB string.
*
* Note:
************************************************** ***************************/
void GetUSBData(char start_ptr, char num_bytes, char *data)
{
unsigned char n;

for(n=start_ptr; n<start_ptr+num_bytes; n++)
data[n - start_ptr] = inbuffer[n];
}

/************************************************** ****************************
* Function: void UserInit
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This function initializes the PIC.
*
*
* Note: None
************************************************** ***************************/

void UserInit(void)
{
byte i;

CS_2515_HIGH(); //Drive high
tris_CS = 0; //Output
OpenSPI(SPI_FOSC_16, MODE_00, SMPMID);

TRISBbits.TRISB0 = 1; //SDI
TRISBbits.TRISB1 = 0; //SCK

//-------------------------
// initialize variables
//-------------------------
for (i=0; i<BUF_SIZE; i++) // initialize input and output buffer to 0
{
inbuffer[i]=0;
outbuffer[i]=0;
}

//Timer 0
TMR0H = 0; //clear timer
TMR0L = 0; //clear timer
T0CONbits.PSA = 0; //Assign prescaler to Timer 0
T0CONbits.T0PS2 = 1; //Setup prescaler
T0CONbits.T0PS1 = 1; //Will time out every 51 us based on
T0CONbits.T0PS0 = 1; //20 MHz Fosc
T0CONbits.T0CS = 0; //Increment on instuction cycle

INTCON2 = 0xFF; //INT2 on rising edge
INTCON3bits.INT2IP = 0; //Low priority
INTCON3bits.INT2IF = 0; //Clear flag
INTCON3bits.INT2IE = 1; //Enable INT2 interrupt

//Outputs for the LEDs
ADCON1 = 0x0F; //Digital pins
CMCON = 0x07; //Digital pins

LED_25PCT_OFF();
LED_50PCT_OFF();
LED_75PCT_OFF();
LED_100PCT_OFF();

tris_LED_25PCT = OUTPUT_PIN;
tris_LED_50PCT = OUTPUT_PIN;
tris_LED_75PCT = OUTPUT_PIN;
tris_LED_100PCT = OUTPUT_PIN;

UserFlag.CANLoading = OFF;

LED_RX_OFF();
LED_TX_OFF();

tris_LED_TX = OUTPUT_PIN;
tris_LED_RX = OUTPUT_PIN;

tris_SW_LOAD = INPUT_PIN;

//RTS Pin Outputs
RTS0_2515_HIGH();
tris_RTS0_pin = OUTPUT_PIN;

RTS1_2515_HIGH();
tris_RTS1_pin = OUTPUT_PIN;

RTS2_2515_HIGH();
tris_RTS2_pin = OUTPUT_PIN;

tris_CAN_RES = OUTPUT_PIN;
CAN_RES_ON(); //JM
// CAN_RES_OFF(); //Disconnect the termination resistor by default

UserFlag.MCP_RXBn = 0; //clear flag
UserFlag.USBsend = 0; //clear flag
UserFlag.USBQueue = 0; //Clear message queue

//Need to set up MCP2515 before enabling interrupts
CANInit(); // See BusMon.c & .h

RCONbits.IPEN = 1;
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;
}//end UserInit

/************************************************** ****************************
* Function: void CANInit//(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This function initializes the MCP2515.
*
*
* Note: None
************************************************** ***************************/
void CANInit()
{
unsigned char n,EEPROM_ver;
SPIReset(); //Wait state is in SPIReset() function
EEPROM_ver=EEPROMCRCCheck(0,128);
EEPROM_ver=0;
for(n=0; n<250; n++); //Wait anyway

//Set Config Mode and verify
//CANCTRL Register
/*
if(EEPROM_ver)
{
CANCTRL_byte=EEPROMBYTERead(CANCTRL);
}
else
{
EEPROMBYTEWrite(CANCTRL,CANCTRL_byte);
}
*/
SET_CONFIG; //Set Configuration mode
CLEAR_OSM; //Not One-Shot-Mode
CLEAR_ABORT; //Clear ABAT bit
CLKOUT_ENABLED; //Enabled CLKOUT pin (will configure as SOF pin in CNF3)
//EEPROMBYTEWrite(CANCTRL,CANCTRL_byte);

SPIByteWrite(CANCTRL,CANCTRL_byte); //Write to CANCTRL
//Verify Mode change
if ((SPIByteRead(CANSTAT)& 0xE0) != OPMODE_CONFIG)
SPIByteWrite(CANCTRL,CANCTRL_byte); //Try again

if(usb_power_check) //Only if connected to USB. Traffic gen board doesn't process RX msgs
{
//Configure INTERRUPTS
/*
if(EEPROM_ver)
{
CANINTE_byte=EEPROMBYTERead(CANINTE);
}
else
{
EEPROMBYTEWrite(CANINTE,CANINTE_byte);
}
*/
G_RXB_INT_ENABLED;
G_TXB_INT_ENABLED;
//EEPROMBYTEWrite(CANINTE,CANINTE_byte);

SPIByteWrite(CANINTE, CANINTE_byte);
}

//Use RXnBF pins as interrupts on RX //(BFPCTRL register)
RXB0BF_PIN_INT;
RXB1BF_PIN_INT;
SPIByteWrite(BFPCTRL, BFPCTRL_byte);

//Configure TXnRTS pins as RTS pins
TXRTSCTRL_byte = 0x07;
SPIByteWrite(TXRTSCTRL, TXRTSCTRL_byte);

//Configure MASKS
DataArray[0] = 0x00;
DataArray[1] = 0x00;
DataArray[2] = 0x00;
DataArray[3] = 0x00;
/*
if(EEPROM_ver)
{
DataArray[0]=EEPROMBYTERead(RXM0SIDH);
DataArray[1]=EEPROMBYTERead(RXM0SIDL);
DataArray[2]=EEPROMBYTERead(RXM0EID8);
DataArray[3]=EEPROMBYTERead(RXM0EID0);
}
else
{
EEPROMDataWrite(RXM0SIDH,&DataArray[0],4);
}
*/
SPISeqWrite(RXM0SIDH, 4, DataArray); //RX Mask 0

DataArray[0] = 0x00;
DataArray[1] = 0x00;
DataArray[2] = 0x00;
DataArray[3] = 0x00;
/*
if(EEPROM_ver)
{
DataArray[0]=EEPROMBYTERead(RXM1SIDH);
DataArray[1]=EEPROMBYTERead(RXM1SIDL);
DataArray[2]=EEPROMBYTERead(RXM1EID8);
DataArray[3]=EEPROMBYTERead(RXM1EID0);
}
else
{
EEPROMDataWrite(RXM1SIDH,&DataArray[0],4);
}
*/
SPISeqWrite(RXM1SIDH, 4, DataArray); //RX Mask 1
//SPISeqWrite(RXB0CTRL, 1, 0); //RXB0 Control JM
//SPISeqWrite(RXB1CTRL, 1, 0); //RXB1 Control JM

//Configure FILTERS
//Will RX standard messages into RXB0 and extended into RXB1


DataArray[0] = 0x00;
DataArray[1] = 0x00;
DataArray[2] = 0x00;
DataArray[3] = 0x00;
/*
if(EEPROM_ver)
{
DataArray[0]=EEPROMBYTERead(RXF0SIDH);
DataArray[1]=EEPROMBYTERead(RXF0SIDL);
DataArray[2]=EEPROMBYTERead(RXF0EID8);
DataArray[3]=EEPROMBYTERead(RXF0EID0);
}
else
{
EEPROMDataWrite(RXF0SIDH,&DataArray[0],4);
}
*/
SPISeqWrite(RXF0SIDH, 4, DataArray);
//SPIByteWrite(RXF0SIDL, 0x00); //Clearing EXIDE... the rest is "don't care"

DataArray[0] = 0x00;
DataArray[1] = 0x00;
DataArray[2] = 0x00;
DataArray[3] = 0x00;
/*
if(EEPROM_ver)
{
DataArray[0]=EEPROMBYTERead(RXF1SIDH);
DataArray[1]=EEPROMBYTERead(RXF1SIDL);
DataArray[2]=EEPROMBYTERead(RXF1EID8);
DataArray[3]=EEPROMBYTERead(RXF1EID0);
}
else
{
EEPROMDataWrite(RXF1SIDH,&DataArray[0],4);
}
*/
SPISeqWrite(RXF1SIDH, 4, DataArray);

//SPIByteWrite(RXF1SIDL, 0x00); //Clearing EXIDE... the rest is "don't care" //JM

DataArray[0] = 0x00;
DataArray[1] = 0x08;
DataArray[2] = 0x00;
DataArray[3] = 0x00;
/*
if(EEPROM_ver)
{
DataArray[0]=EEPROMBYTERead(RXF2SIDH);
DataArray[1]=EEPROMBYTERead(RXF2SIDL);
DataArray[2]=EEPROMBYTERead(RXF2EID8);
DataArray[3]=EEPROMBYTERead(RXF2EID0);
}
else
{
EEPROMDataWrite(RXF2SIDH,&DataArray[0],4);
}
*/
SPISeqWrite(RXF2SIDH, 4, DataArray);

//SPIByteWrite(RXF2SIDL, 0x08); //Setting EXIDE... the rest is "don't care"

DataArray[0] = 0x00;
DataArray[1] = 0x08;
DataArray[2] = 0x00;
DataArray[3] = 0x00;
/*
if(EEPROM_ver)
{
DataArray[0]=EEPROMBYTERead(RXF3SIDH);
DataArray[1]=EEPROMBYTERead(RXF3SIDL);
DataArray[2]=EEPROMBYTERead(RXF3EID8);
DataArray[3]=EEPROMBYTERead(RXF3EID0);
}
else
{
EEPROMDataWrite(RXF3SIDH,&DataArray[0],4);
}
*/
SPISeqWrite(RXF3SIDH, 4, DataArray);


//SPIByteWrite(RXF3SIDL, 0x08); //Setting EXIDE... the rest is "don't care" //JM

DataArray[0] = 0x00;
DataArray[1] = 0x08;
DataArray[2] = 0x00;
DataArray[3] = 0x00;
/*
if(EEPROM_ver)
{
DataArray[0]=EEPROMBYTERead(RXF4SIDH);
DataArray[1]=EEPROMBYTERead(RXF4SIDL);
DataArray[2]=EEPROMBYTERead(RXF4EID8);
DataArray[3]=EEPROMBYTERead(RXF4EID0);
}
else
{
EEPROMDataWrite(RXF4SIDH,&DataArray[0],4);
}
*/
SPISeqWrite(RXF4SIDH, 4, DataArray);

//SPIByteWrite(RXF4SIDL, 0x08); //Setting EXIDE... the rest is "don't care" //JM

DataArray[0] = 0x00;
DataArray[1] = 0x08;
DataArray[2] = 0x00;
DataArray[3] = 0x00;
/*
if(EEPROM_ver)
{
DataArray[0]=EEPROMBYTERead(RXF5SIDH);
DataArray[1]=EEPROMBYTERead(RXF5SIDL);
DataArray[2]=EEPROMBYTERead(RXF5EID8);
DataArray[3]=EEPROMBYTERead(RXF5EID0);
}
else
{
EEPROMDataWrite(RXF5SIDH,&DataArray[0],4);
}
*/
SPISeqWrite(RXF5SIDH, 4, DataArray);

//SPIByteWrite(RXF5SIDL, 0x08); //Setting EXIDE... the rest is "don't care" //JM

//Configure TX BUFFER 0
DataArray[0] = 0xA3;
DataArray[1] = 0x09;
DataArray[2] = 0x12;
DataArray[3] = 0x34;
DataArray[4] = 0x04;
DataArray[5] = 0x00;
DataArray[6] = 0x01;
DataArray[7] = 0x02;
DataArray[8] = 0x03;
DataArray[9] = 0x04;
DataArray[10] = 0x05;
DataArray[11] = 0x06;
DataArray[12] = 0x07;

/*
if(EEPROM_ver)
{
DataArray[0]=EEPROMBYTERead(TXB0SIDH);
DataArray[1]=EEPROMBYTERead(TXB0SIDL);
DataArray[2]=EEPROMBYTERead(TXB0EID8);
DataArray[3]=EEPROMBYTERead(TXB0EID0);
DataArray[4]=EEPROMBYTERead(TXB0DLC);
DataArray[5]=EEPROMBYTERead(TXB0D0);
DataArray[6]=EEPROMBYTERead(TXB0D1);
DataArray[7]=EEPROMBYTERead(TXB0D2);
DataArray[8]=EEPROMBYTERead(TXB0D3);
DataArray[9]=EEPROMBYTERead(TXB0D4);
DataArray[10]=EEPROMBYTERead(TXB0D5);
DataArray[11]=EEPROMBYTERead(TXB0D6);
DataArray[12]=EEPROMBYTERead(TXB0D7);

}
else
{
EEPROMDataWrite(TXB0SIDH,&DataArray,13);
}
*/
SPILoadTX(CAN_LD_TXB0_ID, 13, DataArray);

//Configure TX BUFFER 1
DataArray[0] = 0x22;
DataArray[1] = 0x00;
DataArray[2] = 0x64;
DataArray[3] = 0x68;
DataArray[4] = 0x02;
DataArray[5] = 0x00;
DataArray[6] = 0x11;
DataArray[7] = 0x22;
DataArray[8] = 0x33;
DataArray[9] = 0x44;
DataArray[10] = 0x55;
DataArray[11] = 0x66;
DataArray[12] = 0x77;
/*
if(EEPROM_ver)
{
DataArray[0]=EEPROMBYTERead(TXB1SIDH);
DataArray[1]=EEPROMBYTERead(TXB1SIDL);
DataArray[2]=EEPROMBYTERead(TXB1EID8);
DataArray[3]=EEPROMBYTERead(TXB1EID0);
DataArray[4]=EEPROMBYTERead(TXB1DLC);
DataArray[5]=EEPROMBYTERead(TXB1D0);
DataArray[6]=EEPROMBYTERead(TXB1D1);
DataArray[7]=EEPROMBYTERead(TXB1D2);
DataArray[8]=EEPROMBYTERead(TXB1D3);
DataArray[9]=EEPROMBYTERead(TXB1D4);
DataArray[10]=EEPROMBYTERead(TXB1D5);
DataArray[11]=EEPROMBYTERead(TXB1D6);
DataArray[12]=EEPROMBYTERead(TXB1D7);

}
else
{
EEPROMDataWrite(TXB1SIDH,&DataArray,13);
}
*/
SPILoadTX(CAN_LD_TXB1_ID, 13, DataArray);

//Configure TX BUFFER 2
DataArray[0] = 0xAA;
DataArray[1] = 0x03;
DataArray[2] = 0x33;
DataArray[3] = 0x33;
DataArray[4] = 0x08;
DataArray[5] = 0xAA;
DataArray[6] = 0xBB;
DataArray[7] = 0xCC;
DataArray[8] = 0xDD;
DataArray[9] = 0xEE;
DataArray[10] = 0xFF;
DataArray[11] = 0x0A;
DataArray[12] = 0x0B;
SPILoadTX(CAN_LD_TXB2_ID, 13, DataArray);
/*
if(EEPROM_ver)
{
DataArray[0]=EEPROMBYTERead(TXB2SIDH);
DataArray[1]=EEPROMBYTERead(TXB2SIDL);
DataArray[2]=EEPROMBYTERead(TXB2EID8);
DataArray[3]=EEPROMBYTERead(TXB2EID0);
DataArray[4]=EEPROMBYTERead(TXB2DLC);
DataArray[5]=EEPROMBYTERead(TXB2D0);
DataArray[6]=EEPROMBYTERead(TXB2D1);
DataArray[7]=EEPROMBYTERead(TXB2D2);
DataArray[8]=EEPROMBYTERead(TXB2D3);
DataArray[9]=EEPROMBYTERead(TXB2D4);
DataArray[10]=EEPROMBYTERead(TXB2D5);
DataArray[11]=EEPROMBYTERead(TXB2D6);
DataArray[12]=EEPROMBYTERead(TXB2D7);

}
else
{
EEPROMDataWrite(TXB2SIDH,&DataArray,13);
}
*/

SPISeqRead(TXB1SIDH, 13, ReadArray);

//Configure BIT TIMING
SOF_ENABLED; //Start-of-Frame signal enabled. Will set when "SetBitTiming()" is called
/*
if(EEPROM_ver)
{
DataArray[0] = EEPROMBYTERead(CNF3); //Load array
DataArray[1] = EEPROMBYTERead(CNF2); //
DataArray[2] = EEPROMBYTERead(CNF1); //
SPISeqWrite(CNF3, 3, DataArray); //Write registers

}
else
*/
{
SetBitTiming(CAN_125kbps); //Note, this function puts device in Normal Mode

}

//Set Normal Mode and verify
SET_NORMAL;
SPIByteWrite(CANCTRL,CANCTRL_byte); //Write to CANCTRL
old_CANCTRL = 0x00;
//EEPROMCRCWrite(0,128);

//Verify Mode change
if ((SPIByteRead(CANSTAT)& 0xE0) != OPMODE_NORMAL)
SPIByteWrite(CANCTRL,CANCTRL_byte); //Try again
}

/************************************************** ****************************
* Function: void SetBitTiming//(char data_rate)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This function sets the bit timing.
*
*
* Note: None
************************************************** ***************************/
void SetBitTiming(char data_rate)
{
unsigned char a,b,c,dummy;
//Set Config Mode and verify
SET_CONFIG; //Set Configuration mode
SPIByteWrite(CANCTRL,CANCTRL_byte); //Write to CANCTRL
//Verify Mode change
if ((SPIByteRead(CANSTAT)& 0xE0) != OPMODE_CONFIG)
SPIByteWrite(CANCTRL,CANCTRL_byte); //Try again

//Need 10TQ based on 20 MHz osc
//Will only need to modify BRP to acheive the 4 bit rates
//First clear CNFn registers
CNF1_byte = 0;
CNF2_byte = 0;
CNF3_byte = 0;
//Now set individual bits
SJW_1TQ; //Sync Jump Width
PRSEG_3TQ; //Prop Segment
PHSEG1_3TQ; //Phase Seg 1
PHSEG2_3TQ; //Phase Seg 2
BTLMODE_CNF3; //Use CNF3 to set Phase Seg 2

SOF_ENABLED; //Start-of-Frame signal enabled. Will set when "SetBitTiming()" is called

//Configure Baud Rate Prescaler
switch(data_rate) // interpret command
{
case CAN_125kbps: // Set to 125 kbps
BRP7; //
break;

case CAN_250kbps: // Set to 250 kbps
BRP3; //
break;

case CAN_500kbps: // Set to 500 kbps
BRP1; //
break;

case CAN_1000kbps: // Set to 1000 kbps
BRP0; //
break;

default: // unrecognized or null command
;
}// END switch: data_rate

//Now write the CNFn registers
DataArray[0] = CNF3_byte; //Load array
DataArray[1] = CNF2_byte; //
DataArray[2] = CNF1_byte; //
SPISeqWrite(CNF3, 3, DataArray); //Write registers

//Set Normal Mode and verify
SET_NORMAL;
SPIByteWrite(CANCTRL,CANCTRL_byte); //Write to CANCTRL
//Verify Mode change
if ((SPIByteRead(CANSTAT)& 0xE0) != OPMODE_CONFIG)
SPIByteWrite(CANCTRL,CANCTRL_byte); //Try again
EEPROMDataWrite(CNF3,&DataArray,3);
}


/************************************************** ****************************
* Function: void CANLoadTX(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This function transmits messages on the CAN bus depending
* on the Load Button setting
*
* Note:
************************************************** ***************************/
void CANLoadTX(void)
{
static char buffer_q;

if(UserFlag.CANLoading) //if bus loading is turned on
{

CANLoadTimer++; //Increment the counter
if (!CANLoadTimer) //if rolled over, set flag. User code will handle the rest.
{
CANLoadTimer = LoadPrescaler;
switch(buffer_q) // interpret command
{
case 0: // Send buffer 0
RTS0_2515_LOW();
RTS0_2515_HIGH();
buffer_q = 1; //For next time around
break;
case 1: // Send buffer 1
RTS1_2515_LOW();
RTS1_2515_HIGH();
buffer_q = 2; //For next time around
break;
case 2: // Send buffer 2
RTS2_2515_LOW();
RTS2_2515_HIGH();
buffer_q = 0; //For next time around
break;
default: // unrecognized or null command
buffer_q = 0;
}// END switch:
}//END: if (!CANLoadTimer)
}//END: if(UserFlag.CANLoading)
}

/************************************************** ****************************
* Function: void EEPROMBYTEWrite(char addr,char data)
*
* PreCondition: None
*
* Input: data and address
*
* Output: None
*
* Side Effects: None
*
* Overview: This function writes a byte to EEPROM in addr
*
* Note:
************************************************** ***************************/
void EEPROMBYTEWrite(char addr,char data)
{
char buf_con=INTCON;
return;
EEADR=addr;
EEDATA=data;
EECON1bits.EEPGD=0;
EECON1bits.CFGS=0;
EECON1bits.WREN=1;
INTCONbits.GIE=0;
EECON2=0x55;
EECON2=0xaa;
EECON1bits.WR=1;
while(EECON1bits.WR==1);
EECON1bits.WREN=0;
//INTCONbits.GIE=1;
INTCON=buf_con;


}
/************************************************** ****************************
* Function: void EEPROMDataWrite(char addr,char* data,char len)
*
* PreCondition: void EEPROMBYTEWrite(char addr,char data)
*
* Input: begin address,data address,data length
*
* Output: None
*
* Side Effects: None
*
* Overview: This function writes a byte to EEPROM in addr
*
* Note:
************************************************** ***************************/
void EEPROMDataWrite(char addr,char* data,char len)
{
unsigned char i;
for(i=0;i<len;i++)
{
EEPROMBYTEWrite(addr+i,data[i]);
}
}

/************************************************** ****************************
* Function: void EEPROMBYTERead(char addr,char data)
*
* PreCondition: None
*
* Input: address
*
* Output: data
*
* Side Effects: None
*
* Overview: This function writes a byte to EEPROM in addr
*
* Note:
************************************************** ***************************/

char EEPROMBYTERead(char addr)
{
EEADR=addr;
EECON1bits.EEPGD=0;
EECON1bits.CFGS=0;
EECON1bits.RD=1;
return EEDATA;

}

/************************************************** ****************************
* Function: void EEPROMDataRead(char addr,char data)
*
* PreCondition: None
*
* Input: address in EEPROM,buffer address,data length
*
* Output: data
*
* Side Effects: None
*
* Overview: This function writes a byte to EEPROM in addr
*
* Note:
************************************************** ***************************/
void EEPROMDataRead(char addr,char* data,char len)
{
unsigned char i;
for(i=0;i<len;i++)
{
data[i]=EEPROMBYTERead(addr+i);
}
}


/************************************************** ****************************
* Function: void EEPROMCRCWrite(char addr,char len)
*
* PreCondition: None
*
* Input: address in EEPROM,data length
*
* Output: data
*
* Side Effects: None
*
* Overview: This function writes a byte to EEPROM in addr
*
* Note:
************************************************** ***************************/

void EEPROMCRCWrite(char addr,char len)
{
unsigned char buf,i;
buf=0;
for(i=0;i<len;i++)
{
buf+=EEPROMBYTERead(i+addr);
}
EEPROMBYTEWrite(128,buf);

}
/************************************************** ****************************
* Function: bool EEPROMCRCCheck(char addr,char len)
*
* PreCondition: None
*
* Input: address in EEPROM,data length
*
* Output: true for checksum equal
*
* Side Effects: None
*
* Overview: This function writes a byte to EEPROM in addr
*
* Note:
************************************************** ***************************/

BOOL EEPROMCRCCheck(char addr,char len)
{
unsigned char buf,i;
buf=0;
for(i=0;i<len;i++)
{
buf+=EEPROMBYTERead(i+addr);
}

if(buf==EEPROMBYTERead(128))
{
return TRUE;
}
else
{
return FALSE;
}

}

/** EOF BusMon.c****************************************** **************/



But I took another look at your code.... At the very beginning, in the INITIALIZE MCP2515 section you have this piece of code:
Code:
LOW CS
SSPBUF = MCPRST ' COMMAND TO RESET THE MCP2515
PIR1.3 = 0
WHILE PIR1.3=0 :WEND
HIGH CS
I then went to see exactly what MCPRST was and the only thing I found in your code was an alias to PortC.0 so what's happening in that piece of code is that the PIC reads PortC.0 and then the result of that read operation (1 or 0) to SSPBUF. To reset the device you either pull the hardware reset line LOW or send $C0 over SPI.I tried $C0 and pulling the reset line low, both of which didn't seem to work. The problem is, I was trying multiple things at the same time and I ended up just putting the MCPRST command thinking it was $C0 when I meant to use CAN_RST, which is already in my code! Good catch! Maybe I should not work on this until 1am tonight!;)


Properly resetting the device automatically puts in the configuration mode so therotically you shouldn't need to put it in that mode directly after a (proper) reset. Then your comments says that you're writing to "part of baudrate" or something but $07 is the EXTENDED IDENTIFIER LOW register receiver 1, $03 is EXTENDED IDENTIFIER LOW register for receiver 0 and I can't even find what $BA is.I was confused about this too so I searched the internet for someone who has written this code properly AND it worked. I found this:


Public Sub mcp2515_CAN_Freq()
mcp_assert_cs() ' start comms to MCP2515
spi_transfer(SPI_WRITE) ' send write command
spi_transfer(CNF3) ' address
spi_transfer(config3) ' CNF3
spi_transfer(config2) ' CNF2
spi_transfer(config1) ' CNF1
mcp_deassert_cs() ' stop comms to MCP2515
End Sub

This portion of C code seems self explanatory but configuring CNF1, CNF2 AND CNF3 was confusing. They talk about propagation segment, bit time length, Fosc, BRP, etc. It's all new to me and confusing so I went with values I found on the internet, which were $07, $BA and $03. It has to do with timing the MCP frequency with the oscillator frequency and I *think* those numbers are correct.



OK, moving to MAIN then....
You send the command to write then you send the value 0 to CANINTE at adress $02, that all seems OK to me if disabling interrupts is what you want to do.For now I just want to send something so I'm disabling the interrupts.


Next you set the TXB0CTRL register for a high priority message and request it to send. Then you write the TRANSMIT BUFFER STANDARD IDENTIFIER register. I have no idea what these does so I'm going to asume it's correct. Then, you tell it you want to send a single byte by writing the value 1 to TXB0DLC and then you write the actual data.The SID, if I understand correctly, is the ID of the message. I've circled it in red and I think this is the SID:6604


Personally I would've thought you should first load the data to be sent THEN tell the device to send it. Ie write TXB0CTRL after you've loaded the data but the way you have it might be correct.I'll play around with it and see what works better.

I don't understand what Fosc command to use. I have 20 MhZ oscillator. Do I use:


SSPM3:SSPM0: Master Synchronous Serial Port Mode Select bits
0101 = SPI Slave mode, clock = SCK pin, SS pin control disabled, SS can be used as I/O pin(3)
0100 = SPI Slave mode, clock = SCK pin, SS pin control enabled(3)
0011 = SPI Master mode, clock = TMR2 output/2(3)
0010 = SPI Master mode, clock = FOSC/64(3)
0001 = SPI Master mode, clock = FOSC/16(3)
0000 = SPI Master mode, clock = FOSC/4(3)

Thanks for all of your help Henrik, I wouldn't have gotten this far without it.

HenrikOlsson
- 20th July 2012, 13:52
Hi Christopher,

OK, hang on a minute.... I may have spotted something here.
Lets take a look at the SPI section of the MCP2515 datasheet again, section 12.5

The Write instruction is started by lowering the CS pin. The Write instruction is then sent to the MCP2515 followed by the adress and then at least one byte of data.
Now let's take a look at your configuration section again, with my comments in it.

LOW CS ' The Write instruction is started by lowering the CS pin
SSPBUF = mcpwrt ' The Write instruction then sent to the MCP2515

PIR1.3 = 0 ' Wait for it to tranfer
WHILE PIR1.3=0 :WEND

MCPREG = CANCTRL ' followed by the adress
DATAOUT = $08 ' and at least one byte of data.

GOSUB SEND_CAN_DATA

So far so good, as far as I can see. Now lets continue where we left off in the datasheet:

It is possible to write sequential registers by continuing to clock in data bytes, as long as CS is held low.
Keyword here: sequential. Now back to your code again:

SSPBUF = cnf3 ' CNF3 REGISTER
PIR1.3 = 0
WHILE PIR1.3=0 :WEND

SSPBUF = $07 ' PART OF BAUD RATE
PIR1.3 = 0
WHILE PIR1.3=0 :WEND

SSPBUF = $BA ' PART OF BAUD RATE
PIR1.3 = 0
WHILE PIR1.3=0 :WEND

SSPBUF = $03 ' PART OF BAUDRATE
PIR1.3 = 0
WHILE PIR1.3=0 :WEND

MCPREG = CANCTRL 'PUT THE MCP2515 BACK INTO NORMAL MODE
DATAOUT = $0
GOSUB SEND_CAN_DATA

high cs
If I understand this correctly the intention of your code is to write the value $07 to register CNF3 (at adress $28) but since you haven't deasserted the CS line the next byte transfered to the MCP2515 will automatically get written to next adress (right after CANCTRL in this case). So what actually happens is that the value $28 (which is the adress of CNF3) gets written to the register after CANCTRL (CANCTRL is at $0F so $28 will end up at adress $10) and then value $07 gets written to the register after that ($11).

If you intend to write to registers which aren't sequential in the MCP2515 I think you need must deassert the CS line and start all over again: CS low, write instruction, adress, data.


I'd try with the slowest SPI clock possible to begin with. Ie SSPM3:SSPM0 = 0010

/Henrik.

Christopher4187
- 20th July 2012, 14:14
I've been over the sequential write portion of code more times than I can count and it may have something to do with the problem. I was just now able to succeed sending data over the CAN! While the information isn't correct, some of the numbers I'm putting in are coming up on the computer so that's a good thing.

I think the sequential write/bit modify stuff has something to do with it. Where I'm expecting data (i.e. - the data for byte one (D0) in the data field), I'm seeing the address. Perhaps it is expecting just to run through the data and not have to address each variable when I load the buffer. That may be why I was overloading the number of bytes and crashed the Microchip interface. Instead of seeing 8 bytes of data, it was seeing 16.

First I'm going to SAVE this code! Then I'll start to modify the code a little bit and work my way up to two-way communication with all of the little additions needed to have an error free CAN node. If it took me this long to get something going, I can't imagine how long it will take to write the full code:frown:

But, at least I'm past step one, which hopefully was the hardest. Again, thank you so much for your help. I'll be back sooner rather than later to ask a million more questions.

Chris

Christopher4187
- 20th July 2012, 14:26
Microchip does it like this:

SPILoadTX(CAN_LD_TXB0_ID, 13, DataArray);

//Configure TX BUFFER 1
DataArray[0] = 0x22;
DataArray[1] = 0x00;
DataArray[2] = 0x64;
DataArray[3] = 0x68;
DataArray[4] = 0x02;
DataArray[5] = 0x00;
DataArray[6] = 0x11;
DataArray[7] = 0x22;
DataArray[8] = 0x33;
DataArray[9] = 0x44;
DataArray[10] = 0x55;
DataArray[11] = 0x66;
DataArray[12] = 0x77;

HenrikOlsson
- 20th July 2012, 15:38
Hi,
For transfering the actual data to be sent and setting up the packet lenght etc I'd probably try something like this:

CAN_DATA VAR BYTE[8]
CAN_LENGTH VAR BYTE
CAN_ID_H VAR BYTE
CAN_ID_L VAR BYTE
i VAR BYTE

' Prepare a message
ArrayWrite CAN_DATA[$11, $22, $33, $44, $55, $66, $77, $88] ' Actual data, 8 bytes
CAN_LENGTH = 8 ' 8 because that's how many bytes we want to transfer
CAN_ID_H = 0
CAN_ID_L = 0

GOSUB Transfer_CAN_Data

END

'----Subrotuine to set the packet length, Standard identifiers, load the data to be sent from array and tell MCP2515 to send it when it can (CAN).
Tranfer_CAN_Data:

LOW CS ' Select device

SSPBUF = MCPWRT : PAUSE 1 ' Send write command
SSPBUF = TXB0SIDL : PAUSE 1 ' Select TXB0SIDL register.
SSPBUF = CAN_ID_L : PAUSE 1 ' Send low byte of standard identifier

' Next register is te TXB0SIDH so we can continue spitting out bytes.
SSPBUF = CAN_ID_H : PAUSE 1 ' Send high byte of standard identifier

HIGH CS ' Deselect device to end write operation
PAUSE 10
LOW CS ' Select device

' Now set the Transmit bufferdata length register
SSPBUF = MCPWRT : PAUSE 1 ' Send write command
SSPBUF = TXB0DLC : PAUSE 1 ' Point at register
SSPBUF = CAN_LENGTH : PAUSE 1 ' Send length of packet



' The first databyte register in the TX buffer is located right after the message
' length register so we can use the sequential write feature and just keep going
' with the actual data.

FOR i = 0 to CAN_LENGHT - 1 ' Iterate thru the array and transfer
SSPBUF = CAN_LENGTH[i] ' one byte at the time
PAUSE 1 ' Wait for it
NEXT

HIGH CS ' Deselect device to end write operation
PAUSE 10
LOW CS ' Select device

' Now the the message lenth is set and the data to be sent is transfered.

SSPBUF = MCPWRT : PAUSE 1 ' Send write command
SSPBUF = TXB0CTRL : PAUSE 1 ' Transmitt buffer control register
SSPBUF = %00001011 : PAUSE 1 ' Request message to be sent with highest priority

' According to the datasheet this does NOT inititare the actual transfer. It politely
' tells the MCP2515 that the databuffer is ready and can be sent whent the bus is available.

RETURN
Now, I don't know about the Standard Identifier, if they need to be set on a message per message basis or if they are like a node adress or something. In the code above they gets set each time which might be unneccessary. I'm also using PAUSE to wait for the MSSP module, looking at the interrupt flag or buffer free flag as you've been doing is obviously better but it cluttered up the overall structure so I used PAUSE for clarity.

Not saying it'll work but that's what I'd try.

/Henrik.

Christopher4187
- 20th July 2012, 16:10
I still have version 2.5. I think you need 2.6 for arraywrite, correct? I have a program that will only work with 2.5 so I haven't moved past that point yet but it looks like I may need to. Is there a similar command that will work?

HenrikOlsson
- 20th July 2012, 16:23
Just load the array manually

CAN_DATA[0] = $00
CAN_DATA[1] = $11
CAN_DATA[2] = $22
' and so on

Christopher4187
- 21st July 2012, 14:31
Something changed and I can't figure out what I did. My waveforms appear to match the Microchip program, except for one. The SDO from the 18F4550 is at 5V instead of 0V. I can't find any reference to change that. The only thing I've found is commands to change the clock signal but nothing for the SDO. Any ideas?

I'm very close now.:smile: