Electronics > Microcontrollers


(1/6) > >>

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->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...

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 :)


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: ---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)) {

if (dev->hw == CAN0) {
f = (struct _can_rx_fifo_entry *)(can0_rx_fifo + hri_can_read_RXF0S_F0GI_bf(dev->hw) * CONF_CAN0_F0DS);
if (dev->hw == CAN1) {
f = (struct _can_rx_fifo_entry *)(can1_rx_fifo + hri_can_read_RXF0S_F0GI_bf(dev->hw) * CONF_CAN1_F0DS);

if (f == NULL) {

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;

--- End code ---

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.

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.


[0] Message Index

[#] Next page

There was an error while thanking
Go to full version