Author Topic: CAN on ATSAMC21J18A  (Read 4745 times)

0 Members and 1 Guest are viewing this topic.

Offline ziehao

  • Contributor
  • Posts: 8
  • Country: sg
CAN on ATSAMC21J18A
« on: June 18, 2019, 08:45:38 am »
I am learning how to program a ATSAMC21J18A MCU, and so far, I have managed to properly write an I2C initialization and Read/Write Transmission code on the register level, things like below...

SERCOM5->I2CM.ADDR.reg = 0x16;

SERCOM5->I2CM.DATA.reg = 0x44;

 

I am now trying to do a CAN Extended ID transmit and receive by writing the code on a register level as well, things like below...

CAN0->CCCR.reg |= CAN_CCCR_INIT;

CAN0->XIDFC.bit.LSE = 0x00;

 

So now, I have roughly wrote the CAN initialization code, but the datasheet does not say clearly which registers should I put the Extended Address for Receiving messages, or also where should I put the data for Transmitting.

I am lost on the Tx/Rx FIFO and Message RAM as well, where to put the Address and Data etc.

Could someone guide me on the steps involved or a certain link for a tutorial on this topic?

 

Thanks in advance...
 

Offline JPortici

  • Super Contributor
  • ***
  • Posts: 2857
  • Country: it
Re: CAN on ATSAMC21J18A
« Reply #1 on: June 18, 2019, 09:38:25 am »
When i was evaluating the C21 i had some trouble at first. I opened an ASF example project using CAN and i single stepped every function of interest until i found what i needed (i HATE ATSAM datasheets. They are the equivalent of autogenerated doxygen crap)

It was just a test though, i quickly went back to PIC32MX, but it didn't require much work :)
 

Offline KIKi

  • Contributor
  • Posts: 8
  • Country: hr
Re: CAN on ATSAMC21J18A
« Reply #2 on: June 18, 2019, 09:57:57 am »
Hi,

You should use Atmel Start Framework https://start.atmel.com/. There is a bug in CAN driver of ASF. ASF driver is not setting proper ACK bit when CAN message is received. You should change _can_async_read function (hpl_can.c) as it is shown below (marked with comment Fix). Everything else should work as configured in Atmel Start. Be careful with clocks and sampling segments, that is most important thing in CAN!

Code: [Select]
int32_t _can_async_read(struct _can_async_device *const dev, struct can_message *msg)
{
struct _can_rx_fifo_entry *f = NULL;

uint32_t pTemp = 0; // Fix.

if (!hri_can_read_RXF0S_F0FL_bf(dev->hw)) {
return ERR_NOT_FOUND;
}

#ifdef CONF_CAN0_ENABLED
if (dev->hw == CAN0) {
f = (struct _can_rx_fifo_entry *)(can0_rx_fifo + hri_can_read_RXF0S_F0GI_bf(dev->hw) * CONF_CAN0_F0DS);
}
#endif
#ifdef CONF_CAN1_ENABLED
if (dev->hw == CAN1) {
f = (struct _can_rx_fifo_entry *)(can1_rx_fifo + hri_can_read_RXF0S_F0GI_bf(dev->hw) * CONF_CAN1_F0DS);
}
#endif

if (f == NULL) {
return ERR_NO_RESOURCE;
}

if (f->R0.bit.XTD == 1) {
msg->fmt = CAN_FMT_EXTID;
msg->id  = f->R0.bit.ID;
} else {
msg->fmt = CAN_FMT_STDID;
/* A standard identifier is stored into ID[28:18] */
msg->id = f->R0.bit.ID >> 18;
}

if (f->R0.bit.RTR == 1) {
msg->type = CAN_TYPE_REMOTE;
}

const uint8_t dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64};
msg->len                = dlc2len[f->R1.bit.DLC];

memcpy(msg->data, f->data, msg->len);

// Get FIFI0 index.
pTemp = hri_can_read_RXF0S_F0GI_bf(dev->hw); // Fix.

// Ack.
hri_can_write_RXF0A_reg(dev->hw, pTemp); // Fix.

return ERR_NONE;
}

 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 8364
  • Country: us
    • Personal site
Re: CAN on ATSAMC21J18A
« Reply #3 on: June 18, 2019, 04:58:51 pm »
Here is a simple bare-metal CAN bootloader that shows basic use of that peripheral.

The CAN IP in this device is made by Bosch, so you can look up the Bosch datasheet (it is public), it may have a bit more information.
Alex
 
The following users thanked this post: ivernot, ziehao

Offline ziehao

  • Contributor
  • Posts: 8
  • Country: sg
Re: CAN on ATSAMC21J18A
« Reply #4 on: June 19, 2019, 01:18:20 am »
Hi JPortici,
I know right... SAM datasheets are so hard to understand sometimes... AVR datasheets are good though.

Hi KIKi,
Thanks for the reply, but I wish to do the CAN programming the Register Way (as some would call it) instead of using the ASF. Mainly because the ASF is hard to understand and/or customise.
I have written some I2C codes using the Register Way, and it had problems merging with the CAN ASF version, that is also one of the reason I do not wish to use the ASF...

Hi ataradov,
Thanks for the file. You have no idea how long I have been looking for something like this.... (Maybe my googling skills are not there yet)
I will look through it and update here again.
 

Offline ziehao

  • Contributor
  • Posts: 8
  • Country: sg
Re: CAN on ATSAMC21J18A
« Reply #5 on: June 20, 2019, 10:00:56 am »
I am trying to take out pieces of the Bosch codes to do a simple Tx and Rx.
Looking at the Bosch codes, I am confused about the below section

Code: [Select]
static alignas(4) CanMramSidfe can_rx_standard_filter;
static alignas(4) CanMramXifde can_rx_Xstandard_filter;
static alignas(4) CanMramRxbe  can_rx_buffer;
static alignas(4) CanMramTxbe  can_tx_buffer;
static alignas(4) CanMramTxefe can_tx_event_fifo;

What is the use of aligns(4), do I need to copy the .h files to my main program?
If I do not need to use it, what alternative way should I write it?
« Last Edit: June 20, 2019, 12:50:52 pm by ziehao »
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 8364
  • Country: us
    • Personal site
Re: CAN on ATSAMC21J18A
« Reply #6 on: June 20, 2019, 05:05:55 pm »
Just to be clear, the code is not from Bosch, it is from Microchip. The code was written by me.

alignas() is a standard C directive to ensure that variables are aligned in the memory in a certain way. In this case hardware expects those things to be aligned at a 32-bit boundary (4 bytes).

I don't really understand the rest of the question. The code presented here is essentially minimal working code. You need to have everything related to CAN for CAN to work.

It is hard to say how you should integrate this into your application without knowing the details of that application.
Alex
 

Offline L1L1

  • Contributor
  • Posts: 47
  • Country: gr
Re: CAN on ATSAMC21J18A
« Reply #7 on: June 21, 2019, 01:43:49 pm »
Just to be clear, the code is not from Bosch, it is from Microchip. The code was written by me.

Thanks for this code, I was just looking into the SAMC21 CAN peripheral a few weeks ago myself.
I often look at your code on Github (https://github.com/ataradov/mcu-starter-projects) for ideas. It's been helpful.
You should tell Microchip that they need to improve their documentation. The section on CAN bus in the SAMC21 datasheet is terrible.
 

Offline JPortici

  • Super Contributor
  • ***
  • Posts: 2857
  • Country: it
Re: CAN on ATSAMC21J18A
« Reply #8 on: June 21, 2019, 03:20:18 pm »
Any section in the ATSAM datasheet is terrible. And unfortunately since microhip acquired atmel the 8bit team has started doing documentation Atmel style..
The old datasheet would fill in 300 pages, the new ones require 450+ pages.
tables that did fit in one page now need two.

The same exact shit in the erratas. One of the few erratas styles that were concise, to the point, full of examples are being replaced by the wall of text that is on atmel errata.

but hey, more color, more fonts, more fun!
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 8364
  • Country: us
    • Personal site
Re: CAN on ATSAMC21J18A
« Reply #9 on: June 21, 2019, 03:49:32 pm »
Complain to support about this.  There is nothing I personally can do about the documentation. All I can do is to struggle through it and create software that helps people understand how hardware works. And that's what I do.
Alex
 
The following users thanked this post: chayma

Offline ziehao

  • Contributor
  • Posts: 8
  • Country: sg
Re: CAN on ATSAMC21J18A
« Reply #10 on: June 28, 2019, 06:49:59 am »
Hi,

So I tried using the Atmel Start to generate some CAN code for me to test. The initialization was fine, now I can Transmit and Receive message.
The CAN0_Handler in the hpl_can.c as shown below
Code: [Select]
void CAN0_Handler(void)
{
struct _can_async_device *dev = _can0_dev;
uint32_t                  ir;
ir = hri_can_read_IR_reg(dev->hw);

if (ir & CAN_IR_RF0N) { // Rx New Message
dev->cb.rx_done(dev);
                PORT->Group[0].OUTTGL.reg |= PORT_PA15; // Toggle LED
}

if (ir & CAN_IR_TC) { // Timestamp Completed
dev->cb.tx_done(dev);
}

if (ir & CAN_IR_BO) { // Bus Off
dev->cb.irq_handler(dev, CAN_IRQ_BO);
}

if (ir & CAN_IR_EW) { // Error Warning
dev->cb.irq_handler(dev, CAN_IRQ_EW);
}

if (ir & CAN_IR_EP) { // Error Passive
dev->cb.irq_handler(dev, hri_can_get_PSR_EP_bit(dev->hw) ? CAN_IRQ_EP : CAN_IRQ_EA);
}

if (ir & CAN_IR_RF0L) { // Rx Message Lost
dev->cb.irq_handler(dev, CAN_IRQ_DO);
}
hri_can_write_IR_reg(dev->hw, ir); // Clear Interrupt
}

Q1. I placed a toggle LED code so that I will know whenever it successfully receive a message, but I do not understand the line dev->cb.rx_done(dev); in the Rx New Message
Can someone summarize what is it about and what does it do?

Q2. I am trying to save the Received message into a buffer for the Main code to use,
AND
if the Received message has been saved into a buffer, how do I use it in the Main code.
« Last Edit: June 28, 2019, 06:51:46 am by ziehao »
 
The following users thanked this post: chayma

Online ataradov

  • Super Contributor
  • ***
  • Posts: 8364
  • Country: us
    • Personal site
Re: CAN on ATSAMC21J18A
« Reply #11 on: June 28, 2019, 04:14:11 pm »
If you want to work with ASF, then you should use ASF APIs. In the example code you will see how to set callbacks using functions like can_async_register_callback(). The IRQ handler will call the callback you have provided.

After that you can read the data using can_async_read() function. All of that will happen in the main code. How to structure all of this is a matter of taste.

But there is no need for interrupts if your main code just checks for a flag. It might as well just check for a flag in the CAN register and do what mu code does.

Alex
 

Offline ziehao

  • Contributor
  • Posts: 8
  • Country: sg
Re: CAN on ATSAMC21J18A
« Reply #12 on: July 11, 2019, 06:57:30 am »
So, just a solution for future ppl who are using CAN for ATSAMC21J, below are sections of the code that im using for CAN tx and rx with the help of Atmel Start


Code: [Select]
void CAN_tx(uint32_t tx_address, uint8_t tx_message[8])    {
    struct can_message msg;
    struct can_filter  filter;
    //insert code to copy received message into tx_message_2
    if (rtr == 1)
    {
        /*Send extended message with ID: rtr_id and 8 byte data 0 to 7*/
        msg.id   = rtr_id;
        msg.type = CAN_TYPE_DATA;
        //msg.data = rx_data;
        msg.data = tx_message;
        msg.len  = 8;
        msg.fmt  = CAN_FMT_EXTID;
        can_async_register_callback(&CAN_0, CAN_ASYNC_TX_CB, (FUNC_PTR)CAN_0_tx_callback);
        can_async_enable(&CAN_0);
        can_async_write(&CAN_0, &msg);
        button_pressed = 0;
        rtr = 0;
    }
    else
    {
        /*Send extended message with ID: 0x155555A5 and 8 byte data rx_data*/
        msg.id   = tx_address;
        msg.type = CAN_TYPE_DATA;
        msg.data = rx_data;
        //msg.data = tx_message_2;
        msg.len  = 8;
        msg.fmt  = CAN_FMT_EXTID;
        can_async_register_callback(&CAN_0, CAN_ASYNC_TX_CB, (FUNC_PTR)CAN_0_tx_callback);
        can_async_enable(&CAN_0);
        can_async_write(&CAN_0, &msg);
        button_pressed = 0;
    }
}

void CAN0_Handler(void)
{
    volatile uint32_t status, interrupt;
    status = CAN0->IR.reg;
    interrupt = CAN0->IR.reg;
   
    if (interrupt & CAN_IR_RF0N) {                        // Rx New Message
        received_msg = 1;
        PORT->Group[0].OUTTGL.reg |= PORT_PA15;        // Toggle LED
        CAN0->IR.bit.RF0N = 1;                    // Reset Interrupt
    }
}

main

Code: [Select]
while (1)
{
if (received_msg == 1)
{
int buffer_index = CAN0->RXF0S.bit.F0GI;
CAN_0_rx_callback(&CAN_0); // save data into rx_data
CAN0->RXF0A.bit.F0AI = buffer_index;
received_msg = 0;
button_pressed = 1;
//PORT->Group[0].OUTTGL.reg |= PORT_PA15; // Toggle LED
}

if (button_pressed == 1) // or when message received
{
                        CAN_tx(0x155555A5, tx_message_2);
                        button_pressed = 0;
                }
    }
 
The following users thanked this post: chayma

Offline jars121

  • Contributor
  • Posts: 28
  • Country: au
Re: CAN on ATSAMC21J18A
« Reply #13 on: October 21, 2020, 02:32:37 am »
Sorry for bumping this thread, but there's some pertinent content here regarding CAN, SAM devices and ASF.

Ataradov, thank you for providing the code example and the support, it's greatly appreciated. Are you aware of a similar code example for CAN on the SAME70? Failing that, I've not used the SAMC21, so I'm not sure how closely aligned it is to the SAME70, but I might try and port it across. I've tried my best to get a simple CAN RX example working on the SAME70 using the ASF SAMV71 example project but haven't had any luck.
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 8364
  • Country: us
    • Personal site
Re: CAN on ATSAMC21J18A
« Reply #14 on: October 21, 2020, 02:35:14 am »
SAM E70 uses exactly the same Bosch CAN controller IP. The same code will run as is, with possible minor renaming of registers and obviously different clock configurations.

The only thing to watch out for is that Bosch controller only has access to the 64 K of RAM, so all the pointers to the buffers you give to the IP must be located in the first 64 K of RAM.
Alex
 

Offline jars121

  • Contributor
  • Posts: 28
  • Country: au
Re: CAN on ATSAMC21J18A
« Reply #15 on: October 21, 2020, 11:02:32 pm »
Thanks for clarifying Alex, much appreciated.

I've put considerable time into MCAN on the SAME70 using ASF and am really not getting anywhere. I'll start a new thread so as not to pollute this one any further.
 

Offline chayma

  • Newbie
  • Posts: 2
  • Country: tn
Re: CAN on ATSAMC21J18A
« Reply #16 on: February 26, 2021, 08:47:06 am »
Hello,
I appreciate your help for us who struggle with CAN in asf4
But your example didn't work in my code.
Could you tell me your clock configuration.

best regards,
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 8364
  • Country: us
    • Personal site
Re: CAN on ATSAMC21J18A
« Reply #17 on: February 26, 2021, 06:24:23 pm »
The code for the bootloader I provided is complete and functional, it has all the clocks configurations. I have no idea about ASF4.
Alex
 

Offline matti.salo

  • Contributor
  • Posts: 11
  • Country: fi
Re: CAN on ATSAMC21J18A
« Reply #18 on: October 07, 2021, 12:59:14 pm »
Hi,

I'm quite new with samc21. I have an custom board with samc21g18. I'm trying to get both CAN's to work with mcp2551. I have so far got the uart work with ASF4 and "testled" blinking. But for some reason i CAN's just won't work. First of all. ASF code seems to hang if i'm trying to use 48MHz main clock. Code does not hang if i divide it to 24MHz.
Second, what ever divider / timequota settings i try the can signal is just a mess. It seems that CAN0 goes in to endless loop of crap if i try to send somethin with it.

I have tried to unattach tranciever from CAN1 but still i dont get any sense to this.

As far as i understand there should not be any problems in schematics sinse there is only cantx and canrx lines going into transiever.

Can0 Scope: [attach=1]

CAN1 Scope: [attach=2]

Serial : [attach=3]

Any working example that i could try on my hardware? just something that would sent test message/messages to CAN busses?

I wasn't able to get that bootloader code to open and test in microchip studio 7.
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 8364
  • Country: us
    • Personal site
Re: CAN on ATSAMC21J18A
« Reply #19 on: October 07, 2021, 06:11:41 pm »
Most likely reason for the hanging is incorrect setting for the flash wait states. ASF4 example CAN project is known to work out of the box.

And as far the bootloader, it should also open in Atmel/Microchip studio. So error description may be helpful.

You should probably post your schematics and full setup description. CAN can't have just one node, it will not work. You need to have at least two devices on the bus.
Alex
 

Offline matti.salo

  • Contributor
  • Posts: 11
  • Country: fi
Re: CAN on ATSAMC21J18A
« Reply #20 on: October 14, 2021, 07:57:41 am »
I didn't find "basic CAN" example only FD, bnut that doesn't help me since i do not have a another FD device.

I have now again gathered example with ASF4 configurator:
Clocks:
[attach=1]
CAN0:
[attach=2]


The main code is only:
Code: [Select]
#include <atmel_start.h>

int main(void)
{
/* Initializes MCU, drivers and middleware */
atmel_start_init();

delay_ms(1000);
/* Replace with your application code */
while (1) {

CAN_0_example();
USART_0_example();
delay_ms(200);
gpio_toggle_pin_level(LEDI);
}
}


The CAN part of my board:[attach=3]

In CAN bus i'm now using PCAN interface as a second device and Picoscope as debug device.
With these settings i get: [attach=4]

If i set just a random time quanta settinks like:
25+25+25:
[attach=5]

What am i'm missing.

 

Offline matti.salo

  • Contributor
  • Posts: 11
  • Country: fi
Re: CAN on ATSAMC21J18A
« Reply #21 on: October 14, 2021, 12:53:22 pm »
Just after last message i got this to work.

First: 48Mhz clock started to work after adding NVM waits from 0 to 1. thanks to this post:
https://www.avrfreaks.net/forum/samc21-not-running-48mhz-and-96mhz
[attach=1]

Second i added 120ohm resistor to can.
Working setting on ASF are now:
[attach=3]
[attach=2]
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 8364
  • Country: us
    • Personal site
Re: CAN on ATSAMC21J18A
« Reply #22 on: October 14, 2021, 01:10:31 pm »
I mentioned flash wait states in my original reply.

Example in ASF3 is much better and has both FD and classical example in the same application controllable though serial port menus. Although it looks like that CAN FD demo from ASF4 is the same exact demo.
« Last Edit: October 14, 2021, 01:18:22 pm by ataradov »
Alex
 
The following users thanked this post: matti.salo

Offline matti.salo

  • Contributor
  • Posts: 11
  • Country: fi
Re: CAN on ATSAMC21J18A
« Reply #23 on: October 15, 2021, 08:19:25 am »
Yes, you did mention it, but i did not understand it :) so that was my bad. Configuring clocks is new to me.

I thank you ataradov, without your help i would not got this to work.
 

Offline Rudolph Riedel

  • Contributor
  • Posts: 34
  • Country: de
Re: CAN on ATSAMC21J18A
« Reply #24 on: October 23, 2021, 02:55:53 pm »
First: 48Mhz clock started to work after adding NVM waits from 0 to 1. thanks to this post:
https://www.avrfreaks.net/forum/samc21-not-running-48mhz-and-96mhz

It might work but as the datasheet and the quote in the linked thread says, for 48MHz the SAMC21 needs 2 wait-states, not 1.

Unfortunately Atmel never fully qualified what the ATSAMC2x or ATSAMx5x are capable of and Microchip does not seem to care,
so a lot of these numbers are still based on simulation rather than qualified measurements and so a lot of these Maximum frequency numbers for the various peripheral units look way too conservative.
But if the datasheet states that 48MHz require 2WS I rather configure the controller to 2WS than risking the software to fail in some random way that is impossible to reproduce.

And in this context I wonder why the same CAN-FD module supposedly can only do 48MHz in the ATSAMC21, 100MHz in the ATSAME51 and whatever the limit is for ATSAMx7x as it looks like this information is not given in the datasheet.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf