]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/drivers/peripherals/mcan.c
Add SAMA5D2 Xplained IAR demo.
[freertos] / FreeRTOS / Demo / CORTEX_A5_SAMA5D2x_Xplained_IAR / AtmelFiles / drivers / peripherals / mcan.c
diff --git a/FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/drivers/peripherals/mcan.c b/FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/drivers/peripherals/mcan.c
new file mode 100644 (file)
index 0000000..b957ed4
--- /dev/null
@@ -0,0 +1,749 @@
+/* ----------------------------------------------------------------------------\r
+ *         SAM Software Package License\r
+ * ----------------------------------------------------------------------------\r
+ * Copyright (c) 2015, Atmel Corporation\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above copyright notice,\r
+ * this list of conditions and the disclaimer below.\r
+ *\r
+ * Atmel's name may not be used to endorse or promote products derived from\r
+ * this software without specific prior written permission.\r
+ *\r
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ * ----------------------------------------------------------------------------\r
+ */\r
+\r
+/** \file\r
+ *  Implements functions for Controller Area Network with Flexible Data-rate,\r
+ *  relying on the MCAN peripheral.\r
+ */\r
+/** \addtogroup can_module\r
+ *@{*/\r
+\r
+/*----------------------------------------------------------------------------\r
+ *        Headers\r
+ *----------------------------------------------------------------------------*/\r
+\r
+#include "board.h"\r
+#include "chip.h"\r
+#include "mcan.h"\r
+#include "pmc.h"\r
+\r
+#include <assert.h>\r
+#include <string.h>\r
+\r
+/*---------------------------------------------------------------------------\r
+ *      Local definitions\r
+ *---------------------------------------------------------------------------*/\r
+\r
+enum mcan_dlc\r
+{\r
+       CAN_DLC_0 = 0,\r
+       CAN_DLC_1 = 1,\r
+       CAN_DLC_2 = 2,\r
+       CAN_DLC_3 = 3,\r
+       CAN_DLC_4 = 4,\r
+       CAN_DLC_5 = 5,\r
+       CAN_DLC_6 = 6,\r
+       CAN_DLC_7 = 7,\r
+       CAN_DLC_8 = 8,\r
+       CAN_DLC_12 = 9,\r
+       CAN_DLC_16 = 10,\r
+       CAN_DLC_20 = 11,\r
+       CAN_DLC_24 = 12,\r
+       CAN_DLC_32 = 13,\r
+       CAN_DLC_48 = 14,\r
+       CAN_DLC_64 = 15\r
+};\r
+\r
+/*---------------------------------------------------------------------------\r
+ *        Local functions\r
+ *---------------------------------------------------------------------------*/\r
+\r
+/**\r
+ * \brief Convert data length to Data Length Code.\r
+ * \param len  length, in bytes\r
+ * \param dlc  address where the matching Data Length Code will be written\r
+ * \return true if a code matched the provided length, false if this exact\r
+ * length is not supported.\r
+ */\r
+static bool get_length_code(uint8_t len, enum mcan_dlc *dlc)\r
+{\r
+       assert(dlc);\r
+\r
+       if (len <= 8) {\r
+               *dlc = (enum mcan_dlc)len;\r
+               return true;\r
+       }\r
+       if (len % 4)\r
+               return false;\r
+       len /= 4;\r
+       if (len <= 6) {\r
+               *dlc = (enum mcan_dlc)(len + 6);\r
+               return true;\r
+       }\r
+       if (len % 4)\r
+               return false;\r
+       len /= 4;\r
+       if (len > 4)\r
+               return false;\r
+       *dlc = (enum mcan_dlc)(len + 11);\r
+       return true;\r
+}\r
+\r
+/**\r
+ * \brief Convert Data Length Code to actual data length.\r
+ * \param dlc  CAN_DLC_xx enum value\r
+ * \return Data length, expressed in bytes.\r
+ */\r
+static uint8_t get_data_length(enum mcan_dlc dlc)\r
+{\r
+       assert((dlc == CAN_DLC_0 || dlc > CAN_DLC_0) && dlc <= CAN_DLC_64);\r
+\r
+       if (dlc <= CAN_DLC_8)\r
+               return (uint8_t)dlc;\r
+       if (dlc <= CAN_DLC_24)\r
+               return ((uint8_t)dlc - 6) * 4;\r
+       return ((uint8_t)dlc - 11) * 16;\r
+}\r
+\r
+/**\r
+ * \brief Compute the size of the Message RAM, depending on the application.\r
+ * \param set  Pointer to a MCAN instance that will be setup accordingly.\r
+ * \param cfg  MCAN configuration to be considered. Only integer size parameters\r
+ * need to be configured. The other parameters can be left blank at this stage.\r
+ * \param size  address where the required size of the Message RAM will be\r
+ * written, expressed in (32-bit) words.\r
+ * \return true if successful, false if a parameter is set to an unsupported\r
+ * value.\r
+ */\r
+static bool configure_ram(struct mcan_set *set,\r
+                          const struct mcan_config *cfg, uint32_t *size)\r
+{\r
+       if (cfg->array_size_filt_std > 128 || cfg->array_size_filt_ext > 64\r
+           || cfg->fifo_size_rx0 > 64 || cfg->fifo_size_rx1 > 64\r
+           || cfg->array_size_rx > 64 || cfg->fifo_size_tx_evt > 32\r
+           || cfg->array_size_tx > 32 || cfg->fifo_size_tx > 32\r
+           || cfg->array_size_tx + cfg->fifo_size_tx > 32\r
+           || cfg->buf_size_rx_fifo0 > 64 || cfg->buf_size_rx_fifo1 > 64\r
+           || cfg->buf_size_rx > 64 || cfg->buf_size_tx > 64)\r
+               return false;\r
+\r
+       set->ram_filt_std = cfg->msg_ram;\r
+       *size = (uint32_t)cfg->array_size_filt_std * MCAN_RAM_FILT_STD_SIZE;\r
+       set->ram_filt_ext = cfg->msg_ram + *size;\r
+       *size += (uint32_t)cfg->array_size_filt_ext * MCAN_RAM_FILT_EXT_SIZE;\r
+       set->ram_fifo_rx0 = cfg->msg_ram + *size;\r
+       *size += (uint32_t)cfg->fifo_size_rx0 * (MCAN_RAM_BUF_HDR_SIZE\r
+           + cfg->buf_size_rx_fifo0 / 4);\r
+       set->ram_fifo_rx1 = cfg->msg_ram + *size;\r
+       *size += (uint32_t)cfg->fifo_size_rx1 * (MCAN_RAM_BUF_HDR_SIZE\r
+           + cfg->buf_size_rx_fifo1 / 4);\r
+       set->ram_array_rx = cfg->msg_ram + *size;\r
+       *size += (uint32_t)cfg->array_size_rx * (MCAN_RAM_BUF_HDR_SIZE\r
+           + cfg->buf_size_rx / 4);\r
+       set->ram_fifo_tx_evt = cfg->msg_ram + *size;\r
+       *size += (uint32_t)cfg->fifo_size_tx_evt * MCAN_RAM_TX_EVT_SIZE;\r
+       set->ram_array_tx = cfg->msg_ram + *size;\r
+       *size += (uint32_t)cfg->array_size_tx * (MCAN_RAM_BUF_HDR_SIZE\r
+           + cfg->buf_size_tx / 4);\r
+       *size += (uint32_t)cfg->fifo_size_tx * (MCAN_RAM_BUF_HDR_SIZE\r
+           + cfg->buf_size_tx / 4);\r
+       return true;\r
+}\r
+\r
+/*---------------------------------------------------------------------------\r
+ *      Exported Functions\r
+ *---------------------------------------------------------------------------*/\r
+\r
+bool mcan_configure_msg_ram(const struct mcan_config *cfg, uint32_t *size)\r
+{\r
+       assert(cfg);\r
+       assert(size);\r
+\r
+       struct mcan_set tmp_set = { .cfg = { 0 } };\r
+\r
+       return configure_ram(&tmp_set, cfg, size);\r
+}\r
+\r
+bool mcan_initialize(struct mcan_set *set, const struct mcan_config *cfg)\r
+{\r
+       assert(set);\r
+       assert(cfg);\r
+       assert(cfg->regs);\r
+       assert(cfg->msg_ram);\r
+\r
+       Mcan *mcan = cfg->regs;\r
+       uint32_t *element = NULL, *elem_end = NULL;\r
+       uint32_t freq, regVal32;\r
+       enum mcan_dlc dlc;\r
+\r
+       memset(set, 0, sizeof(*set));\r
+       if (!configure_ram(set, cfg, &regVal32))\r
+               return false;\r
+       set->cfg = *cfg;\r
+\r
+       /* Configure the MSB of the Message RAM Base Address */\r
+       regVal32 = (uint32_t)cfg->msg_ram >> 16;\r
+       if (cfg->id == ID_CAN0_INT0 || cfg->id == ID_CAN0_INT1)\r
+               regVal32 = (SFR->SFR_CAN & ~SFR_CAN_EXT_MEM_CAN0_ADDR_Msk)\r
+                   | SFR_CAN_EXT_MEM_CAN0_ADDR(regVal32);\r
+       else\r
+               regVal32 = (SFR->SFR_CAN & ~SFR_CAN_EXT_MEM_CAN1_ADDR_Msk)\r
+                   | SFR_CAN_EXT_MEM_CAN1_ADDR(regVal32);\r
+       SFR->SFR_CAN = regVal32;\r
+\r
+       /* Reset the CC Control Register */\r
+       mcan->MCAN_CCCR = 0 | MCAN_CCCR_INIT_ENABLED;\r
+\r
+       mcan_disable(set);\r
+       mcan_reconfigure(set);\r
+\r
+       /* Global Filter Configuration: Reject remote frames, reject non-matching frames */\r
+       mcan->MCAN_GFC = MCAN_GFC_RRFE_REJECT | MCAN_GFC_RRFS_REJECT\r
+           | MCAN_GFC_ANFE(2) | MCAN_GFC_ANFS(2);\r
+\r
+       /* Extended ID Filter AND mask */\r
+       mcan->MCAN_XIDAM = 0x1FFFFFFF;\r
+\r
+       /* Interrupt configuration - leave initialization with all interrupts off\r
+        * Disable all interrupts */\r
+       mcan->MCAN_IE = 0;\r
+       mcan->MCAN_TXBTIE = 0x00000000;\r
+       /* All interrupts directed to Line 0 */\r
+       mcan->MCAN_ILS = 0x00000000;\r
+       /* Disable both interrupt LINE 0 & LINE 1 */\r
+       mcan->MCAN_ILE = 0x00;\r
+       /* Clear all interrupt flags */\r
+       mcan->MCAN_IR = 0xFFCFFFFF;\r
+\r
+       /* Configure CAN bit timing */\r
+       if (cfg->bit_rate == 0\r
+           || cfg->quanta_before_sp < 3 || cfg->quanta_before_sp > 257\r
+           || cfg->quanta_after_sp < 1 || cfg->quanta_after_sp > 128\r
+           || cfg->quanta_sync_jump < 1 || cfg->quanta_sync_jump > 128)\r
+               return false;\r
+       /* Retrieve the frequency of the CAN core clock i.e. the Generated Clock */\r
+       freq = pmc_get_gck_clock(cfg->id);\r
+       /* Compute the Nominal Baud Rate Prescaler */\r
+       regVal32 = ROUND_INT_DIV(freq, cfg->bit_rate\r
+           * (cfg->quanta_before_sp + cfg->quanta_after_sp));\r
+       if (regVal32 < 1 || regVal32 > 512)\r
+               return false;\r
+       /* Apply bit timing configuration */\r
+       mcan->MCAN_NBTP = MCAN_NBTP_NBRP(regVal32 - 1)\r
+           | MCAN_NBTP_NTSEG1(cfg->quanta_before_sp - 1 - 1)\r
+           | MCAN_NBTP_NTSEG2(cfg->quanta_after_sp - 1)\r
+           | MCAN_NBTP_NSJW(cfg->quanta_sync_jump - 1);\r
+\r
+       /* Configure fast CAN FD bit timing */\r
+       if (cfg->bit_rate_fd < cfg->bit_rate\r
+           || cfg->quanta_before_sp_fd < 3 || cfg->quanta_before_sp_fd > 33\r
+           || cfg->quanta_after_sp_fd < 1 || cfg->quanta_after_sp_fd > 16\r
+           || cfg->quanta_sync_jump_fd < 1 || cfg->quanta_sync_jump_fd > 8)\r
+               return false;\r
+       /* Compute the Fast Baud Rate Prescaler */\r
+       regVal32 = ROUND_INT_DIV(freq, cfg->bit_rate_fd\r
+           * (cfg->quanta_before_sp_fd + cfg->quanta_after_sp_fd));\r
+       if (regVal32 < 1 || regVal32 > 32)\r
+               return false;\r
+       /* Apply bit timing configuration */\r
+       mcan->MCAN_DBTP = MCAN_DBTP_FBRP(regVal32 - 1)\r
+           | MCAN_DBTP_DTSEG1(cfg->quanta_before_sp_fd - 1 - 1)\r
+           | MCAN_DBTP_DTSEG2(cfg->quanta_after_sp_fd - 1)\r
+           | MCAN_DBTP_DSJW(cfg->quanta_sync_jump_fd - 1);\r
+\r
+       /* Configure Message RAM starting addresses and element count */\r
+       /* 11-bit Message ID Rx Filters */\r
+       mcan->MCAN_SIDFC =\r
+           MCAN_SIDFC_FLSSA((uint32_t)set->ram_filt_std >> 2)\r
+           | MCAN_SIDFC_LSS(cfg->array_size_filt_std);\r
+       /* 29-bit Message ID Rx Filters */\r
+       mcan->MCAN_XIDFC =\r
+           MCAN_XIDFC_FLESA((uint32_t)set->ram_filt_ext >> 2)\r
+           | MCAN_XIDFC_LSE(cfg->array_size_filt_ext);\r
+       /* Rx FIFO 0 */\r
+       mcan->MCAN_RXF0C =\r
+           MCAN_RXF0C_F0SA((uint32_t)set->ram_fifo_rx0 >> 2)\r
+           | MCAN_RXF0C_F0S(cfg->fifo_size_rx0)\r
+           | MCAN_RXF0C_F0WM(0)\r
+           | 0;   /* clear MCAN_RXF0C_F0OM */\r
+       /* Rx FIFO 1 */\r
+       mcan->MCAN_RXF1C =\r
+           MCAN_RXF1C_F1SA((uint32_t)set->ram_fifo_rx1 >> 2)\r
+           | MCAN_RXF1C_F1S(cfg->fifo_size_rx1)\r
+           | MCAN_RXF1C_F1WM(0)\r
+           | 0;   /* clear MCAN_RXF1C_F1OM */\r
+       /* Dedicated Rx Buffers\r
+        * Note: the HW does not know (and does not care about) how many\r
+        * dedicated Rx Buffers are used by the application. */\r
+       mcan->MCAN_RXBC =\r
+           MCAN_RXBC_RBSA((uint32_t)set->ram_array_rx >> 2);\r
+       /* Tx Event FIFO */\r
+       mcan->MCAN_TXEFC =\r
+           MCAN_TXEFC_EFSA((uint32_t)set->ram_fifo_tx_evt >> 2)\r
+           | MCAN_TXEFC_EFS(cfg->fifo_size_tx_evt)\r
+           | MCAN_TXEFC_EFWM(0);\r
+       /* Tx Buffers */\r
+       mcan->MCAN_TXBC =\r
+           MCAN_TXBC_TBSA((uint32_t)set->ram_array_tx >> 2)\r
+           | MCAN_TXBC_NDTB(cfg->array_size_tx)\r
+           | MCAN_TXBC_TFQS(cfg->fifo_size_tx)\r
+           | 0;   /* clear MCAN_TXBC_TFQM */\r
+\r
+       /* Configure the size of data fields in Rx and Tx Buffer Elements */\r
+       if (!get_length_code(cfg->buf_size_rx_fifo0, &dlc))\r
+               return false;\r
+       regVal32 = MCAN_RXESC_F0DS(dlc < CAN_DLC_8 ? 0 : dlc - CAN_DLC_8);\r
+       if (!get_length_code(cfg->buf_size_rx_fifo1, &dlc))\r
+               return false;\r
+       regVal32 |= MCAN_RXESC_F1DS(dlc < CAN_DLC_8 ? 0 : dlc - CAN_DLC_8);\r
+       if (!get_length_code(cfg->buf_size_rx, &dlc))\r
+               return false;\r
+       regVal32 |= MCAN_RXESC_RBDS(dlc < CAN_DLC_8 ? 0 : dlc - CAN_DLC_8);\r
+       mcan->MCAN_RXESC = regVal32;\r
+       if (!get_length_code(cfg->buf_size_tx, &dlc))\r
+               return false;\r
+       mcan->MCAN_TXESC =\r
+           MCAN_TXESC_TBDS(dlc < CAN_DLC_8 ? 0 : dlc - CAN_DLC_8);\r
+\r
+       /* Configure Message ID Filters\r
+        * ...Disable all standard filters */\r
+       for (element = set->ram_filt_std, elem_end = set->ram_filt_std\r
+           + (uint32_t)cfg->array_size_filt_std * MCAN_RAM_FILT_STD_SIZE;\r
+           element < elem_end;\r
+           element += MCAN_RAM_FILT_STD_SIZE)\r
+               element[0] = MCAN_RAM_FILT_SFEC_DIS;\r
+       /* ...Disable all extended filters */\r
+       for (element = set->ram_filt_ext, elem_end = set->ram_filt_ext\r
+           + (uint32_t)cfg->array_size_filt_ext * MCAN_RAM_FILT_EXT_SIZE;\r
+           element < elem_end;\r
+           element += MCAN_RAM_FILT_EXT_SIZE)\r
+               element[0] = MCAN_RAM_FILT_EFEC_DIS;\r
+\r
+       mcan->MCAN_NDAT1 = 0xFFFFFFFF;   /* clear new (rx) data flags */\r
+       mcan->MCAN_NDAT2 = 0xFFFFFFFF;   /* clear new (rx) data flags */\r
+\r
+       regVal32 = mcan->MCAN_CCCR & ~(MCAN_CCCR_BRSE | MCAN_CCCR_FDOE);\r
+       mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_PXHD | MCAN_CCCR_BRSE_DISABLED\r
+           | MCAN_CCCR_FDOE_DISABLED;\r
+\r
+       DSB();\r
+       ISB();\r
+       return true;\r
+}\r
+\r
+void mcan_reconfigure(struct mcan_set *set)\r
+{\r
+       Mcan *mcan = set->cfg.regs;\r
+       uint32_t regVal32;\r
+\r
+       regVal32 = mcan->MCAN_CCCR & ~MCAN_CCCR_CCE;\r
+       assert((regVal32 & MCAN_CCCR_INIT) == MCAN_CCCR_INIT_ENABLED);\r
+       /* Enable writing to configuration registers */\r
+       mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_CCE_CONFIGURABLE;\r
+}\r
+\r
+void mcan_set_mode(struct mcan_set *set, enum mcan_can_mode mode)\r
+{\r
+       Mcan *mcan = set->cfg.regs;\r
+       uint32_t regVal32;\r
+\r
+       regVal32 = mcan->MCAN_CCCR & ~(MCAN_CCCR_BRSE | MCAN_CCCR_FDOE);\r
+       switch (mode) {\r
+       case MCAN_MODE_CAN:\r
+               regVal32 |= MCAN_CCCR_BRSE_DISABLED | MCAN_CCCR_FDOE_DISABLED;\r
+               break;\r
+       case MCAN_MODE_EXT_LEN_CONST_RATE:\r
+               regVal32 |= MCAN_CCCR_BRSE_DISABLED | MCAN_CCCR_FDOE_ENABLED;\r
+               break;\r
+       case MCAN_MODE_EXT_LEN_DUAL_RATE:\r
+               regVal32 |= MCAN_CCCR_BRSE_ENABLED | MCAN_CCCR_FDOE_ENABLED;\r
+               break;\r
+       default:\r
+               return;\r
+       }\r
+       mcan->MCAN_CCCR = regVal32;\r
+}\r
+\r
+enum mcan_can_mode mcan_get_mode(const struct mcan_set *set)\r
+{\r
+       const uint32_t cccr = set->cfg.regs->MCAN_CCCR;\r
+\r
+       if ((cccr & MCAN_CCCR_FDOE) == MCAN_CCCR_FDOE_DISABLED)\r
+               return MCAN_MODE_CAN;\r
+       if ((cccr & MCAN_CCCR_BRSE) == MCAN_CCCR_BRSE_DISABLED)\r
+               return MCAN_MODE_EXT_LEN_CONST_RATE;\r
+       return MCAN_MODE_EXT_LEN_DUAL_RATE;\r
+}\r
+\r
+void mcan_init_loopback(struct mcan_set *set)\r
+{\r
+       Mcan *mcan = set->cfg.regs;\r
+\r
+       mcan->MCAN_CCCR |= MCAN_CCCR_TEST_ENABLED;\r
+#if 0\r
+       mcan->MCAN_CCCR |= MCAN_CCCR_MON_ENABLED;   /* for internal loop back */\r
+#endif\r
+       mcan->MCAN_TEST |= MCAN_TEST_LBCK_ENABLED;\r
+}\r
+\r
+void mcan_set_tx_queue_mode(struct mcan_set *set)\r
+{\r
+       Mcan *mcan = set->cfg.regs;\r
+       mcan->MCAN_TXBC |= MCAN_TXBC_TFQM;\r
+}\r
+\r
+void mcan_enable(struct mcan_set *set)\r
+{\r
+       uint32_t index, val;\r
+\r
+       /* Depending on bus condition, the HW may switch back to the\r
+        * Initialization state, by itself. Therefore, upon timeout, return.\r
+        * [Using an arbitrary timeout criterion.] */\r
+       for (index = 0; index < 1024; index++) {\r
+               val = set->cfg.regs->MCAN_CCCR;\r
+               if ((val & MCAN_CCCR_INIT) == MCAN_CCCR_INIT_DISABLED)\r
+                       break;\r
+               if (index == 0)\r
+                       set->cfg.regs->MCAN_CCCR = (val & ~MCAN_CCCR_INIT)\r
+                           | MCAN_CCCR_INIT_DISABLED;\r
+       }\r
+}\r
+\r
+void mcan_disable(struct mcan_set *set)\r
+{\r
+       uint32_t val;\r
+       bool initial;\r
+\r
+       for (initial = true; true; initial = false) {\r
+               val = set->cfg.regs->MCAN_CCCR;\r
+               if ((val & MCAN_CCCR_INIT) == MCAN_CCCR_INIT_ENABLED)\r
+                       break;\r
+               if (initial)\r
+                       set->cfg.regs->MCAN_CCCR = (val & ~MCAN_CCCR_INIT)\r
+                           | MCAN_CCCR_INIT_ENABLED;\r
+       }\r
+}\r
+\r
+void mcan_loopback_on(struct mcan_set *set)\r
+{\r
+       Mcan *mcan = set->cfg.regs;\r
+       mcan->MCAN_TEST |= MCAN_TEST_LBCK_ENABLED;\r
+}\r
+\r
+void mcan_loopback_off(struct mcan_set *set)\r
+{\r
+       Mcan *mcan = set->cfg.regs;\r
+       mcan->MCAN_TEST &= ~MCAN_TEST_LBCK_ENABLED;\r
+}\r
+\r
+void mcan_enable_rx_array_flag(struct mcan_set *set, uint8_t line)\r
+{\r
+       assert(line == 0 || line == 1);\r
+\r
+       Mcan *mcan = set->cfg.regs;\r
+       if (line) {\r
+               mcan->MCAN_ILS |= MCAN_ILS_DRXL;\r
+               mcan->MCAN_ILE |= MCAN_ILE_EINT1;\r
+       } else {\r
+               mcan->MCAN_ILS &= ~MCAN_ILS_DRXL;\r
+               mcan->MCAN_ILE |= MCAN_ILE_EINT0;\r
+       }\r
+       mcan->MCAN_IR = MCAN_IR_DRX;   /* clear previous flag */\r
+       mcan->MCAN_IE |= MCAN_IE_DRXE;   /* enable it */\r
+}\r
+\r
+uint8_t * mcan_prepare_tx_buffer(struct mcan_set *set, uint8_t buf_idx,\r
+                                uint32_t id, uint8_t len)\r
+{\r
+       assert(buf_idx < set->cfg.array_size_tx);\r
+       assert(len <= set->cfg.buf_size_tx);\r
+\r
+       Mcan *mcan = set->cfg.regs;\r
+       uint32_t *pThisTxBuf = 0;\r
+       uint32_t val;\r
+       const enum mcan_can_mode mode = mcan_get_mode(set);\r
+       enum mcan_dlc dlc;\r
+\r
+       if (buf_idx >= set->cfg.array_size_tx)\r
+               return NULL;\r
+       if (!get_length_code(len, &dlc))\r
+               dlc = CAN_DLC_0;\r
+       pThisTxBuf = set->ram_array_tx + buf_idx\r
+           * (MCAN_RAM_BUF_HDR_SIZE + set->cfg.buf_size_tx / 4);\r
+       if (mcan_is_extended_id(id))\r
+               *pThisTxBuf++ = MCAN_RAM_BUF_XTD | MCAN_RAM_BUF_ID_XTD(id);\r
+       else\r
+               *pThisTxBuf++ = MCAN_RAM_BUF_ID_STD(id);\r
+       val = MCAN_RAM_BUF_MM(0) | MCAN_RAM_BUF_DLC((uint32_t)dlc);\r
+       if (mode == MCAN_MODE_EXT_LEN_CONST_RATE)\r
+               val |= MCAN_RAM_BUF_FDF;\r
+       else if (mode == MCAN_MODE_EXT_LEN_DUAL_RATE)\r
+               val |= MCAN_RAM_BUF_FDF | MCAN_RAM_BUF_BRS;\r
+       *pThisTxBuf++ = val;\r
+       /* enable transmit from buffer to set TC interrupt bit in IR,\r
+        * but interrupt will not happen unless TC interrupt is enabled */\r
+       mcan->MCAN_TXBTIE = (1 << buf_idx);\r
+       return (uint8_t *)pThisTxBuf;   /* now it points to the data field */\r
+}\r
+\r
+void mcan_send_tx_buffer(struct mcan_set *set, uint8_t buf_idx)\r
+{\r
+       Mcan *mcan = set->cfg.regs;\r
+\r
+       if (buf_idx < set->cfg.array_size_tx)\r
+               mcan->MCAN_TXBAR = (1 << buf_idx);\r
+}\r
+\r
+uint8_t mcan_enqueue_outgoing_msg(struct mcan_set *set, uint32_t id,\r
+                                 uint8_t len, const uint8_t *data)\r
+{\r
+       assert(len <= set->cfg.buf_size_tx);\r
+\r
+       Mcan *mcan = set->cfg.regs;\r
+       uint32_t val;\r
+       uint32_t *pThisTxBuf = 0;\r
+       const enum mcan_can_mode mode = mcan_get_mode(set);\r
+       enum mcan_dlc dlc;\r
+       uint8_t putIdx = 255;\r
+\r
+       if (!get_length_code(len, &dlc))\r
+               dlc = CAN_DLC_0;\r
+       /* Configured for FifoQ and FifoQ not full? */\r
+       if (set->cfg.fifo_size_tx == 0 || (mcan->MCAN_TXFQS & MCAN_TXFQS_TFQF))\r
+               return putIdx;\r
+       putIdx = (uint8_t)((mcan->MCAN_TXFQS & MCAN_TXFQS_TFQPI_Msk)\r
+           >> MCAN_TXFQS_TFQPI_Pos);\r
+       pThisTxBuf = set->ram_array_tx + (uint32_t)\r
+           putIdx * (MCAN_RAM_BUF_HDR_SIZE + set->cfg.buf_size_tx / 4);\r
+       if (mcan_is_extended_id(id))\r
+               *pThisTxBuf++ = MCAN_RAM_BUF_XTD | MCAN_RAM_BUF_ID_XTD(id);\r
+       else\r
+               *pThisTxBuf++ = MCAN_RAM_BUF_ID_STD(id);\r
+       val = MCAN_RAM_BUF_MM(0) | MCAN_RAM_BUF_DLC((uint32_t)dlc);\r
+       if (mode == MCAN_MODE_EXT_LEN_CONST_RATE)\r
+               val |= MCAN_RAM_BUF_FDF;\r
+       else if (mode == MCAN_MODE_EXT_LEN_DUAL_RATE)\r
+               val |= MCAN_RAM_BUF_FDF | MCAN_RAM_BUF_BRS;\r
+       *pThisTxBuf++ = val;\r
+       memcpy(pThisTxBuf, data, len);\r
+       /* enable transmit from buffer to set TC interrupt bit in IR,\r
+        * but interrupt will not happen unless TC interrupt is enabled\r
+        */\r
+       mcan->MCAN_TXBTIE = (1 << putIdx);\r
+       /* request to send */\r
+       mcan->MCAN_TXBAR = (1 << putIdx);\r
+       return putIdx;\r
+}\r
+\r
+bool mcan_is_buffer_sent(const struct mcan_set *set, uint8_t buf_idx)\r
+{\r
+       Mcan *mcan = set->cfg.regs;\r
+       return mcan->MCAN_TXBTO & (1 << buf_idx) ? true : false;\r
+}\r
+\r
+void mcan_filter_single_id(struct mcan_set *set,\r
+                              uint8_t buf_idx, uint8_t filter, uint32_t id)\r
+{\r
+       assert(buf_idx < set->cfg.array_size_rx);\r
+       assert(id & CAN_EXT_MSG_ID ? filter < set->cfg.array_size_filt_ext\r
+           : filter < set->cfg.array_size_filt_std);\r
+       assert(id & CAN_EXT_MSG_ID ? (id & ~CAN_EXT_MSG_ID) <= 0x1fffffff :\r
+           id <= 0x7ff);\r
+\r
+       uint32_t *pThisRxFilt = 0;\r
+\r
+       if (buf_idx >= set->cfg.array_size_rx)\r
+               return;\r
+       if (mcan_is_extended_id(id)) {\r
+               pThisRxFilt = set->ram_filt_ext + filter\r
+                   * MCAN_RAM_FILT_EXT_SIZE;\r
+               *pThisRxFilt++ = MCAN_RAM_FILT_EFEC_BUF\r
+                   | MCAN_RAM_FILT_EFID1(id);\r
+               *pThisRxFilt = MCAN_RAM_FILT_EFID2_BUF\r
+                   | MCAN_RAM_FILT_EFID2_BUF_IDX(buf_idx);\r
+       } else {\r
+               pThisRxFilt = set->ram_filt_std + filter\r
+                   * MCAN_RAM_FILT_STD_SIZE;\r
+               *pThisRxFilt = MCAN_RAM_FILT_SFEC_BUF\r
+                   | MCAN_RAM_FILT_SFID1(id)\r
+                   | MCAN_RAM_FILT_SFID2_BUF\r
+                   | MCAN_RAM_FILT_SFID2_BUF_IDX(buf_idx);\r
+       }\r
+}\r
+\r
+void mcan_filter_id_mask(struct mcan_set *set, uint8_t fifo, uint8_t filter,\r
+                         uint32_t id, uint32_t mask)\r
+{\r
+       assert(fifo == 0 || fifo == 1);\r
+       assert(id & CAN_EXT_MSG_ID ? filter < set->cfg.array_size_filt_ext\r
+           : filter < set->cfg.array_size_filt_std);\r
+       assert(id & CAN_EXT_MSG_ID ? (id & ~CAN_EXT_MSG_ID) <= 0x1fffffff :\r
+           id <= 0x7ff);\r
+       assert(id & CAN_EXT_MSG_ID ? mask <= 0x1fffffff : mask <= 0x7ff);\r
+\r
+       uint32_t *pThisRxFilt = 0;\r
+       uint32_t val;\r
+\r
+       if (mcan_is_extended_id(id)) {\r
+               pThisRxFilt = set->ram_filt_ext + filter\r
+                   * MCAN_RAM_FILT_EXT_SIZE;\r
+               *pThisRxFilt++ = (fifo ? MCAN_RAM_FILT_EFEC_FIFO1\r
+                   : MCAN_RAM_FILT_EFEC_FIFO0) | MCAN_RAM_FILT_EFID1(id);\r
+               *pThisRxFilt = MCAN_RAM_FILT_EFT_CLASSIC\r
+                   | MCAN_RAM_FILT_EFID2(mask);\r
+       } else {\r
+               pThisRxFilt = set->ram_filt_std + filter\r
+                   * MCAN_RAM_FILT_STD_SIZE;\r
+               val = MCAN_RAM_FILT_SFT_CLASSIC\r
+                   | MCAN_RAM_FILT_SFID1(id)\r
+                   | MCAN_RAM_FILT_SFID2(mask);\r
+               *pThisRxFilt = (fifo ? MCAN_RAM_FILT_SFEC_FIFO1\r
+                   : MCAN_RAM_FILT_SFEC_FIFO0) | val;\r
+       }\r
+}\r
+\r
+bool mcan_rx_buffer_data(const struct mcan_set *set, uint8_t buf_idx)\r
+{\r
+       Mcan *mcan = set->cfg.regs;\r
+\r
+       if (buf_idx < 32)\r
+               return mcan->MCAN_NDAT1 & (1 << buf_idx) ? true : false;\r
+       else if (buf_idx < 64)\r
+               return mcan->MCAN_NDAT2 & (1 << (buf_idx - 32)) ? true : false;\r
+       else\r
+               return false;\r
+}\r
+\r
+void mcan_read_rx_buffer(struct mcan_set *set, uint8_t buf_idx,\r
+                         struct mcan_msg_info *msg)\r
+{\r
+       assert(buf_idx < set->cfg.array_size_rx);\r
+\r
+       Mcan *mcan = set->cfg.regs;\r
+       const uint32_t *pThisRxBuf = 0;\r
+       uint32_t tempRy;   /* temp copy of RX buffer word */\r
+       uint8_t len;\r
+\r
+       if (buf_idx >= set->cfg.array_size_rx) {\r
+               msg->id = 0;\r
+               msg->timestamp = 0;\r
+               msg->full_len = 0;\r
+               msg->data_len = 0;\r
+               return;\r
+       }\r
+       pThisRxBuf = set->ram_array_rx + (buf_idx\r
+           * (MCAN_RAM_BUF_HDR_SIZE + set->cfg.buf_size_rx / 4));\r
+       tempRy = *pThisRxBuf++;   /* word R0 contains ID */\r
+       if (tempRy & MCAN_RAM_BUF_XTD)\r
+               msg->id = CAN_EXT_MSG_ID | (tempRy & MCAN_RAM_BUF_ID_XTD_Msk)\r
+                   >> MCAN_RAM_BUF_ID_XTD_Pos;\r
+       else\r
+               msg->id = (tempRy & MCAN_RAM_BUF_ID_STD_Msk)\r
+                   >> MCAN_RAM_BUF_ID_STD_Pos;\r
+       tempRy = *pThisRxBuf++;   /* word R1 contains DLC & time stamp */\r
+       msg->full_len = len = get_data_length((enum mcan_dlc)\r
+           ((tempRy & MCAN_RAM_BUF_DLC_Msk) >> MCAN_RAM_BUF_DLC_Pos));\r
+       msg->timestamp = (tempRy & MCAN_RAM_BUF_RXTS_Msk)\r
+           >> MCAN_RAM_BUF_RXTS_Pos;\r
+       if (msg->data) {\r
+               /* copy the data from the Rx Buffer Element to the\r
+                * application-owned buffer */\r
+               if (len > set->cfg.buf_size_rx)\r
+                       len = set->cfg.buf_size_rx;\r
+               if (len > msg->data_len)\r
+                       len = msg->data_len;\r
+               memcpy(msg->data, pThisRxBuf, len);\r
+               msg->data_len = len;\r
+       }\r
+       else\r
+               msg->data_len = 0;\r
+       /* clear the new data flag for the buffer */\r
+       if (buf_idx < 32)\r
+               mcan->MCAN_NDAT1 = (1 << buf_idx);\r
+       else\r
+               mcan->MCAN_NDAT2 = (1 << (buf_idx - 32));\r
+}\r
+\r
+uint8_t mcan_dequeue_received_msg(struct mcan_set *set, uint8_t fifo,\r
+                                 struct mcan_msg_info *msg)\r
+{\r
+       assert(fifo == 0 || fifo == 1);\r
+\r
+       Mcan *mcan = set->cfg.regs;\r
+       uint32_t *pThisRxBuf = 0;\r
+       uint32_t tempRy;   /* temp copy of RX buffer word */\r
+       uint8_t buf_elem_data_size, len;\r
+       uint32_t *fifo_ack_reg;\r
+       uint32_t get_index;\r
+       uint8_t fill_level = 0;   /* default: fifo empty */\r
+\r
+       if (fifo) {\r
+               get_index = (mcan->MCAN_RXF1S & MCAN_RXF1S_F1GI_Msk) >>\r
+                   MCAN_RXF1S_F1GI_Pos;\r
+               fill_level = (uint8_t)((mcan->MCAN_RXF1S & MCAN_RXF1S_F1FL_Msk)\r
+                   >> MCAN_RXF1S_F1FL_Pos);\r
+               pThisRxBuf = set->ram_fifo_rx1;\r
+               buf_elem_data_size = set->cfg.buf_size_rx_fifo1;\r
+               fifo_ack_reg = (uint32_t *) & mcan->MCAN_RXF1A;\r
+       } else {\r
+               get_index = (mcan->MCAN_RXF0S & MCAN_RXF0S_F0GI_Msk)\r
+                   >> MCAN_RXF0S_F0GI_Pos;\r
+               fill_level = (uint8_t)((mcan->MCAN_RXF0S & MCAN_RXF0S_F0FL_Msk)\r
+                   >> MCAN_RXF0S_F0FL_Pos);\r
+               pThisRxBuf = set->ram_fifo_rx0;\r
+               buf_elem_data_size = set->cfg.buf_size_rx_fifo0;\r
+               fifo_ack_reg = (uint32_t *) & mcan->MCAN_RXF0A;\r
+       }\r
+\r
+       if (fill_level == 0)\r
+               return 0;\r
+\r
+       pThisRxBuf += get_index * (MCAN_RAM_BUF_HDR_SIZE + buf_elem_data_size\r
+           / 4);\r
+       tempRy = *pThisRxBuf++;   /* word R0 contains ID */\r
+       if (tempRy & MCAN_RAM_BUF_XTD)\r
+               msg->id = CAN_EXT_MSG_ID | (tempRy & MCAN_RAM_BUF_ID_XTD_Msk)\r
+                   >> MCAN_RAM_BUF_ID_XTD_Pos;\r
+       else\r
+               msg->id = (tempRy & MCAN_RAM_BUF_ID_STD_Msk)\r
+                   >> MCAN_RAM_BUF_ID_STD_Pos;\r
+       tempRy = *pThisRxBuf++;   /* word R1 contains DLC & timestamps */\r
+       msg->full_len = len = get_data_length((enum mcan_dlc)\r
+           ((tempRy & MCAN_RAM_BUF_DLC_Msk) >> MCAN_RAM_BUF_DLC_Pos));\r
+       msg->timestamp = (tempRy & MCAN_RAM_BUF_RXTS_Msk)\r
+           >> MCAN_RAM_BUF_RXTS_Pos;\r
+       if (msg->data) {\r
+               /* copy the data from the Rx Buffer Element to the\r
+                * application-owned buffer */\r
+               if (len > buf_elem_data_size)\r
+                       len = buf_elem_data_size;\r
+               if (len > msg->data_len)\r
+                       len = msg->data_len;\r
+               memcpy(msg->data, pThisRxBuf, len);\r
+               msg->data_len = len;\r
+       }\r
+       else\r
+               msg->data_len = 0;\r
+       /* acknowledge reading the fifo entry */\r
+       *fifo_ack_reg = get_index;\r
+       /* return entries remaining in FIFO */\r
+       return (fill_level);\r
+}\r
+\r
+/**@}*/\r