Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Honored Contributor I
3,123 Views

Avalon- Wishbone Wrapper OpenCores CAN Protocoll Controller

Hi, I know that this has been discussed in some old threats but I could not get some real help from those. I want to use the CAN Protocoll Controller in my NIOSII system designed with QSYS. 

 

I took a look at the two bus specifications and came up with this wrapper:  

 

library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; entity OC_Can is port ( avs_s0_address : in std_logic_vector(7 downto 0) := (others => '0'); -- s0.address avs_s0_read : in std_logic := '0'; -- .read avs_s0_readdata : out std_logic_vector(31 downto 0); -- .readdata avs_s0_write : in std_logic := '0'; -- .write avs_s0_writedata : in std_logic_vector(31 downto 0) := (others => '0'); -- .writedata avs_s0_readdatavalid : out std_logic; -- .readdatavalid avs_s0_waitrequest : out std_logic := '0'; clk : in std_logic := '0'; -- clock.clk reset : in std_logic := '0'; -- reset.reset avs_irq_n : out std_logic; -- irq0.irq clk_i : IN STD_LOGIC; rx_i : IN STD_LOGIC; tx_o : OUT STD_LOGIC; bus_off_on : OUT STD_LOGIC; irq_on : OUT STD_LOGIC; clkout_o : OUT STD_LOGIC ); end entity OC_Can; architecture rtl of OC_Can is COMPONENT can_top GENERIC ( Tp : INTEGER := 1 ); PORT ( wb_clk_i : IN STD_LOGIC; wb_rst_i : IN STD_LOGIC; wb_dat_i : IN STD_LOGIC_VECTOR(7 DOWNTO 0); wb_dat_o : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); wb_cyc_i : IN STD_LOGIC; wb_stb_i : IN STD_LOGIC; wb_we_i : IN STD_LOGIC; wb_adr_i : IN STD_LOGIC_VECTOR(7 DOWNTO 0); wb_ack_o : OUT STD_LOGIC; clk_i : IN STD_LOGIC; rx_i : IN STD_LOGIC; tx_o : OUT STD_LOGIC; bus_off_on : OUT STD_LOGIC; irq_on : OUT STD_LOGIC; clkout_o : OUT STD_LOGIC ); END COMPONENT; signal wb_readdata : STD_LOGIC_VECTOR(7 downto 0); signal wb_writedata : STD_LOGIC_VECTOR(7 downto 0); signal wb_stb : STD_LOGIC; signal wb_ack : STD_LOGIC; signal wb_cyc : STD_LOGIC; signal avs_irq : STD_LOGIC; signal av_readdatavalid : STD_LOGIC; begin can_inst : can_top PORT MAP ( wb_clk_i => clk, wb_rst_i => reset, wb_dat_i => wb_writedata, --write data wb_dat_o => wb_readdata, --read data wb_cyc_i => wb_cyc, --when asserted indicates that valid bus cycle is in progress wb_stb_i => wb_stb, --when asserted indicates that the slave is selected, slave should not respond till stb_i is asserted wb_we_i => avs_s0_write, --deasserted during read cycles, asserted during write cycles wb_adr_i => avs_s0_address, wb_ack_o => wb_ack, --when asserted indicates termination of normal bus cycle clk_i => clk_i, rx_i => rx_i, tx_o => tx_o, bus_off_on => bus_off_on, irq_on => avs_irq, clkout_o => clkout_o ); wb_stb <= avs_s0_read OR avs_s0_write; wb_cyc <= avs_s0_read OR avs_s0_write; avs_s0_waitrequest <= not wb_ack; avs_s0_readdatavalid <= wb_ack; --extend 8bits coming from can core to full 32 bits for avalon avs_s0_readdata <= "000000000000000000000000" & wb_readdata; --map lowest 8bits coming from avalon to writedata of can core wb_writedata <= avs_s0_writedata(7 downto 0); --avs_s0_readdatavalid <= '0'; avs_irq_n <= not avs_irq;; end architecture rtl; -- of OC_Can  

 

As I can not simulate it for mixed signal reasons, I tried to access the CAN Core with the following very basic programm from the NIOS: 

 

# include <stdio.h># include <io.h># include "system.h"# include "sys/alt_stdio.h" int main() { unsigned int temp; printf("Hello from Nios II!\n"); temp = IORD_32DIRECT(OC_CAN_0_BASE,4); printf("%u",temp); while(1); return 0; }  

 

What I'm experiencing is that the CPU is getting stuck at the IORD_32DIRECT access. 

 

Can anyone see where the problem might be hidden? As dev board I'm using a de0-nano. Did anyone get this CAN Controller running on a cyclone IV device? 

 

Thanks in advance!
Tags (1)
0 Kudos
10 Replies
Highlighted
Honored Contributor I
60 Views

I used the OC CAN controller on CIII and this is my wrapper (Verilog). 

As you can see, I don't use readdatavalid signal. 

 

module CAN_av_wrapper( //Avalon common input av_clk, input av_reset, //Avalon control port input av_address, input av_chipselect, input av_write, input av_read, input av_writedata, output av_readdata, input av_byteenable, output av_waitrequest_n, // CAN interface input CAN_clk, input CAN_reset, input CAN_rx, output CAN_tx, output CAN_bus_off, output CAN_irq, output CAN_clkout ); wire wb_ack_o; assign av_waitrequest_n = wb_ack_o; wire wb_cs_i; assign wb_cs_i = (av_byteenable == 4'b0001); assign av_readdata = 24'hz; can_top wishbone_can_inst ( .wb_clk_i(av_clk), .wb_rst_i(av_reset | CAN_reset), .wb_dat_i(av_writedata), .wb_dat_o(av_readdata), .wb_cyc_i(av_write | av_read), .wb_stb_i(av_chipselect & (av_write | av_read)), .wb_we_i(av_write & ~av_read), .wb_adr_i({2'b0, av_address}), .wb_ack_o(wb_ack_o), .clk_i(CAN_clk), .rx_i(CAN_rx), .tx_o(CAN_tx), .bus_off_on(CAN_bus_off), .irq_on(CAN_irq), .clkout_o(CAN_clkout) ); endmodule
0 Kudos
Highlighted
Honored Contributor I
60 Views

Thanks a lot for the help! There's some communication going on now! You pointed out some major flaws in my wrapper. The chipselect could actually just be skipped, as it suggested in the avalon specification? But I don't understand the addressing .wb_adr_i({2'b0, av_address}) 

My thoughts where: avalon fabric is addressing the slave on a 32bit wide words basis, while the CAN Controller has a set of byte registers where each address maps to one register. As the data is expanded to 32bits I would have expected a one to one mapping of the addresses. Probabaly you could give me a jumpstart here. 

 

The read/write accesses are not blocking the system anymore but I'm not sure if the result does make sense. If I use the following code to read/write registers  

printf("Goint to reset mode \n"); IOWR_32DIRECT(OC_CAN_VERILOG_WRAP_0_BASE,0,1); for(i = 4; i < 120; i += 4) { temp = IORD_32DIRECT(OC_CAN_VERILOG_WRAP_0_BASE,i); printf("%u: R %u ",i/4,temp); IOWR_32DIRECT(OC_CAN_VERILOG_WRAP_0_BASE,i,255); temp = IORD_32DIRECT(OC_CAN_VERILOG_WRAP_0_BASE,i); printf("W+R255 %u ", temp); printf("\n"); } it outputs the following: 

 

 

--- Quote Start ---  

 

Goint to reset mode  

0: R 1 W+R255 0  

1: R 0 W+R255 0  

2: R 0 W+R255 0  

3: R 0 W+R255 0  

4: R 0 W+R255 0  

5: R 0 W+R255 0  

6: R 0 W+R255 0  

7: R 0 W+R255 0  

8: R 4 W+R255 4  

9: R 4 W+R255 4  

10: R 4 W+R255 4  

11: R 4 W+R255 4  

12: R 0 W+R255 0  

13: R 0 W+R255 0  

14: R 0 W+R255 0  

15: R 0 W+R255 0  

16: R 255 W+R255 0  

17: R 0 W+R255 0  

18: R 0 W+R255 0  

19: R 0 W+R255 0  

20: R 0 W+R255 0  

21: R 0 W+R255 0  

22: R 0 W+R255 0  

23: R 0 W+R255 0  

24: R 255 W+R255 255  

25: R 255 W+R255 255  

26: R 255 W+R255 255  

27: R 255 W+R255 255  

28: R 255 W+R255 255  

29: R 255 W+R255 255  

 

--- Quote End ---  

 

 

The avalon clock is of course connected to the nios clock (100MHz), the external clock to a 10MHz clock, reset to the global reset and the other exports to pins of the IO header of the de0-nano - no CAN Transceiver yet. But the reading/writing of the registers should work. Something is going wrong somewhere... 

What were your experiences with the controller in general. Is it working reliably and thus usable? 

 

Thanks again!
0 Kudos
Highlighted
Honored Contributor I
60 Views

It has been quite a long time since I worked with this CAN controller, so I don't remember everything exactly. 

Anyway, I try to recollect here some information. 

 

.wb_adr_i({2'b0, av_address[7:2]}) 

As you correctly pointed out, this is because Avalon is 32bit wide but it uses byte addressing. In a perfect world I've used the CAN controller with byte accesses (i.e. IORD_8DIRECT,IOWR_8DIRECT). Unfortunately Avalon fabric generates 4 8bit reads even with IORD_8DIRECT, because it requires a 32bit complete access to be performed: this is generally invisible to the application, since only the requested byte is returned by IORD_8DIRECT, but it makes a mess with devices involving fifo register which automatically pop data at every read access, and this CAN controller is one of them. 

That's why I remapped CAN register in order to access them as if they were 32bit wide. 

Please note that you must feed register addresses with multiple of 4, and discard higher 24 bits: 

data = IORD(OC_CAN_VERILOG_WRAP_0_BASE, reg*4) & 0xFF;  

IOWR(OC_CAN_VERILOG_WRAP_0_BASE, reg*4, data); 

 

The CAN controller works. I had some problems with FIFOs because of what I said above, but then it worked fine. 

I suggest you use 24 or 40MHz for CAN clock; IIRC with 10MHz you can't achieve all standard CAN baudrates
0 Kudos
Highlighted
Honored Contributor I
60 Views

I'm new with the use of IP cores and this forum has been helpful to use the CAN controller from OpenCores. At the moment I've added the component to avalon bus, following the Wrapper, in a project with the DE0-nano development board, but I'm still working with the software interface. 

 

The documentation of the opencores project indicates that CAN controller description is compatible with the SJA1000 controller, but want to know if the registers address are identical to those of SJA1000 controller?, there is a problem when accessing registers? or just the need of addresses multipled by 4? 

 

 

thanks and I hope early reply.
0 Kudos
Highlighted
Honored Contributor I
60 Views

Hi, 

 

for you and the people of the future here the wrapper I used: 

 

module OC_Can_av_wrapper( //Avalon common input av_clk, input av_reset, //Avalon control port input av_address, input av_chipselect, input av_write, input av_read, input av_writedata, output av_readdata, input av_byteenable, output av_waitrequest_n, // CAN interface input CAN_clk, input CAN_reset, input CAN_rx, output CAN_tx, output CAN_bus_off, output CAN_irq, output CAN_clkout ); wire wb_ack_o; assign av_waitrequest_n = wb_ack_o; assign av_readdata = 24'hz; can_top wishbone_can_inst ( .wb_clk_i(av_clk), .wb_rst_i(av_reset | CAN_reset), .wb_dat_i(av_writedata), .wb_dat_o(av_readdata), .wb_cyc_i(av_write | av_read), .wb_stb_i(av_chipselect & (av_write | av_read)), .wb_we_i(av_write & ~av_read), .wb_adr_i({av_address}), .wb_ack_o(wb_ack_o), .clk_i(CAN_clk), .rx_i(CAN_rx), .tx_o(CAN_tx), .bus_off_on(CAN_bus_off), .irq_on(CAN_irq), .clkout_o(CAN_clkout) ); endmodule 

 

Using this wrapper, the addresses should be according to the data sheet. 

 

Here a little snippet I used to verify the correct behaviour: 

 

#include <stdio.h> # include <io.h> # include "system.h" # include "sys/alt_stdio.h" int main() { unsigned int temp; int i = 0; printf("Control Register \n"); temp = IORD(OC_CAN_VERILOG_WRAP_0_BASE,0x0000); printf("%u : R %u \n",i,temp); printf("Goint to OP mode \n"); IOWR_32DIRECT(OC_CAN_VERILOG_WRAP_0_BASE,0,32); temp = IORD_32DIRECT(OC_CAN_VERILOG_WRAP_0_BASE,0x0000); printf("%u : R %u \n",i,temp); /*printf("Goint to reset mode \n"); IOWR_32DIRECT(OC_CAN_VERILOG_WRAP_0_BASE,0,32); temp = IORD_32DIRECT(OC_CAN_VERILOG_WRAP_0_BASE,0x0000); printf("%u : R %u \n",i,temp); */ printf("Double check \n"); temp = IORD(OC_CAN_VERILOG_WRAP_0_BASE,0x0000); printf("%u : R %u \n",i,temp); printf("Read Clock Divider Reg \n"); i=31; temp = IORD(OC_CAN_VERILOG_WRAP_0_BASE,31); printf("%u : R %u \n",i,temp); printf("Set it to extended mode \n"); IOWR(OC_CAN_VERILOG_WRAP_0_BASE,31,128); temp = IORD(OC_CAN_VERILOG_WRAP_0_BASE,31); printf("%u : R %u \n",i,temp); printf("And back \n"); IOWR(OC_CAN_VERILOG_WRAP_0_BASE,31,0); temp = IORD(OC_CAN_VERILOG_WRAP_0_BASE,31); printf("%u : R %u \n",i,temp); for(i = 1; i < 32; i++) { IOWR_32DIRECT(OC_CAN_VERILOG_WRAP_0_BASE,i*4,0); temp = IORD_32DIRECT(OC_CAN_VERILOG_WRAP_0_BASE,i*4); printf("%u: R %u \n",i,temp); } printf("Goint to reset mode \n"); IOWR_32DIRECT(OC_CAN_VERILOG_WRAP_0_BASE,0,33); temp = IORD_32DIRECT(OC_CAN_VERILOG_WRAP_0_BASE,0x0000); printf("%u : R %u \n",i,temp); printf("Double check \n"); temp = IORD(OC_CAN_VERILOG_WRAP_0_BASE,0x0000); for(i = 1; i < 32; i++) { IOWR_32DIRECT(OC_CAN_VERILOG_WRAP_0_BASE,i*4,0); temp = IORD_32DIRECT(OC_CAN_VERILOG_WRAP_0_BASE,i*4); printf("%u: R %u \n",i,temp); } printf("\nDONE"); return 0; } 

 

I mixed a bit the use of IO** and IO**_32DIRECT. This shouldn't be a problem as long as you are aware of the difference (see this thread (http://www.alteraforum.com/forum/showthread.php?t=32282)). 

The activation of the reset mode is commented to test if the core can just be set to extended mode if in reset mode (see data sheet (http://www.nxp.com/documents/data_sheet/sja1000.pdf) at page 56). 

 

I hope this helps!
0 Kudos
Highlighted
Honored Contributor I
60 Views

Thanks a lot for the help! I will test on DE0-nano.

0 Kudos
Highlighted
Honored Contributor I
60 Views

Hi, I need help, I'm testing the CAN controller with a DE0-nano board and I used the wrapper and it works fine, I have made the software test and it responds, but when I try to send a message, the can controller generates errors (reflected in the status reg). I'm using a 25Mhz can clock and I don't know what else should I test, can you help me, I send the code used in software to test and send a message. 

 

main program code: 

printf("Start CAN operation:\n"); unsigned int temp; i=0; read_status(); reset_mode(); read_status(); op_mode(); read_status(); can_init(Basic_can , 0x00FF, 0x00FF, Fosc_14); read_status(); can_tx= 0x0F; can_tx= 0x0E; can_tx= 0x0D; can_tx= 0x0C; can_tx= 0x0B; can_tx= 0x0A; can_tx= 0xF1; can_tx= 0xF7; reset_mode(); read_regs_can(); op_mode(); read_regs_can(); send_msg(can_tx, 0x0001, 0x08, 0); read_regs_can(); read_status(); while(1) {}  

 

in a header file (M_can.h) I define:# define Basic_can 0x00# define Peli_can 0x80# define Fosc_14 0x06# define Bus_Tx_libre 0x0C 

 

in a source file (M_can.c) I define the functions: 

 

# include"M_can.h" # include <stdio.h># include <string.h> void reset_mode() { unsigned char temp; printf("Reset mode\n"); temp = IORD_32DIRECT(CAN_CONTROLLER_0_BASE,0x0000); printf("%u : Reg %X h \n",0,temp); printf("%u : Reg %u decimal \n",0,temp); IOWR_32DIRECT(CAN_CONTROLLER_0_BASE,0, (temp | 0x01)); temp = IORD_32DIRECT(CAN_CONTROLLER_0_BASE,0x0000); printf("%u : Reg %X h \n",0,temp); printf("%u : Reg %u decimal \n",0,temp); } void op_mode() { unsigned char temp; printf("OP mode:\n"); temp = IORD_32DIRECT(CAN_CONTROLLER_0_BASE,0x0000); printf("%u : Reg %X h \n",0,temp); printf("%u : Reg %u decimal \n",0,temp); IOWR_32DIRECT(CAN_CONTROLLER_0_BASE,0, (0xFE & temp)); temp = IORD_32DIRECT(CAN_CONTROLLER_0_BASE,0x0000); printf("%u : Reg %X h \n",0,temp); printf("%u : Reg %u decimal \n",0,temp); } unsigned char read_status() { unsigned char status; printf("reading status \n"); status = IORD(CAN_CONTROLLER_0_BASE,2); printf("Now %u : Reg %X h \n",2,status); printf("%u : Reg %u decimal \n",2,status); return(status); } void read_regs_can(void) { int i; unsigned char temp; for(i = 0; i < 32; i++) { temp = IORD_32DIRECT(CAN_CONTROLLER_0_BASE,i*4); printf("Reg %u : %X h ",i,temp); printf("Reg %u: %u decimal \n",i,temp); } } void send_msg(unsigned char *vector, unsigned int id, unsigned char long_bytes_msg, unsigned char rtr) { unsigned char filtro_h, filtro_l, status; int i; printf("sending msg"); status=0x00; filtro_h = (id >> 3); filtro_l = (id << 5); if (rtr ==1) filtro_l = filtro_l | 0x10; if(long_bytes_msg > 0x08) long_bytes_msg = 0x08; filtro_l = filtro_l | long_bytes_msg; IOWR(CAN_CONTROLLER_0_BASE,10,filtro_h); IOWR(CAN_CONTROLLER_0_BASE,11,filtro_l); for(i=0 ; i<long_bytes_msg ; i++) { IOWR(CAN_CONTROLLER_0_BASE,(12+i),*vector); vector = vector+1; } // sending request IOWR(CAN_CONTROLLER_0_BASE,1,0x01); while(status != Bus_Tx_free) { status = read_status(); status = status & Bus_Tx_libre; } printf("Msg Sended \n"); } void can_init(unsigned char mode, unsigned int masc, unsigned int filtro, unsigned char fout) { printf("init can \n"); unsigned char temp; reset_mode(); temp = modo | fout; temp = temp | 0x60; IOWR(CAN_CONTROLLER_0_BASE,31,temp); IOWR(CAN_CONTROLLER_0_BASE,4,filtro); config_timing_reg(1000000, SJW_1, SAM_1); config_output(normal_mode, push_pull); op_mode(); printf("end init \n"); } void config_timing_reg(float frec_CAN, unsigned char SJW, unsigned char muest) { float BRP; unsigned int BRP_int; unsigned char temp, temp2; BRP = (( (F_crystal * T_crystal) / (2.0) ) - 1.0); BRP_int = BRP; // casting a int. temp = BRP_int; // casting a char. temp = SJW | temp; IOWR(CAN_CONTROLLER_0_BASE,6,temp); temp2 = muest | seg1 | seg2; IOWR(CAN_CONTROLLER_0_BASE,7,temp2); } void config_output(unsigned char mode, unsigned char output_pol) { unsigned char temp; temp= mode | output_pol; IOWR(CAN_CONTROLLER_0_BASE,8,temp); }  

 

 

when I test the main program, the CAN controller send bits in the Tx pin, but then the Bus_off pin changes and in the status reg I see the 0xD4h errors, I don't know if maybe the process of sending the message is right. 

 

thanks.
0 Kudos
Highlighted
Honored Contributor I
60 Views

I don't have the time to carefully analyze your code now. 

Just a few question which could help to identify your problem: 

- do you connect to a CAN device on the other side or do you test the core without bus connection?  

- are timing registers correctly configured for the bus baudrate? IIRC 25MHz clock frequency is generally not used for CAN since you can't achieve all standard baudrates; if you can have it, use 24MHZ or 48MHz. 

- Do you see any waveform on bus lines when you call the send_msg the first time?
0 Kudos
Highlighted
Honored Contributor I
60 Views

Hi, acording to questions, fistly, I was testing the can core without an external can device, and when I read the status reg, after a transmission request, I find a 0xD4 wich means bus_off, error, Tx in progress and Tx buffer released. Then I use a MCP2551 can transceiver and a external can device, another MCP2551 and a PIC30F4013 to test it. with the external hardware, I send again a message and find in the status reg again a 0xD4, so I don't know what is happend. I have tested the status reg in every step of initialization but when I send the comand for transmition request the status changes from 0x0C (Tx complete and Tx buffer released) to 0xD4, in this process to changes I see that the can controller send a package in the Tx pin, but with an osciloscope it seem to be the error frame.

0 Kudos
Highlighted
Honored Contributor I
60 Views

 

--- Quote Start ---  

in this process to changes I see that the can controller send a package in the Tx pin, but with an osciloscope it seem to be the error frame. 

--- Quote End ---  

 

What do you mean with error frame? On tx pin you must see the frame you write in the tx buffer, namely can_tx[] values coded according to CAN protocol.  

An error frame would be possibly transmitted back from the can slave. 

 

A few stupid questions: 

Did you check with the oscilloscope if the baudrate you see on tx pin is correct? 

Is PIC30F4013 CAN interface set to the same baudrate? 

Did you try the rx as well? I mean transmit from the PIC30F and check if you receive anything on the DE2-nano
0 Kudos