From 0a8259147088450425bfc4b5ebf36b74cf10ad44 Mon Sep 17 00:00:00 2001 From: petroborys Date: Wed, 6 Mar 2019 09:32:44 +0200 Subject: [PATCH 1/3] Add can_api.c for efm32 --- .../TARGET_EFM32/PeripheralNames.h | 7 + .../TARGET_EFM32GG11/can_device.h | 32 ++ .../TARGET_EFM32/can_api.c | 310 +++++++++++++++ .../TARGET_EFM32/emlib/inc/em_can.h | 165 ++++---- .../TARGET_EFM32/emlib/src/em_can.c | 363 +++++++++--------- targets/targets.json | 1 + 6 files changed, 623 insertions(+), 255 deletions(-) create mode 100644 targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG11/can_device.h create mode 100644 targets/TARGET_Silicon_Labs/TARGET_EFM32/can_api.c diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/PeripheralNames.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/PeripheralNames.h index f8690f98081..4e9622cfa13 100644 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/PeripheralNames.h +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/PeripheralNames.h @@ -136,6 +136,13 @@ typedef enum { } UARTName; #endif +#if DEVICE_CAN +typedef enum { + CAN_0 = (int)CAN0_BASE, + CAN_1 = (int)CAN1_BASE +} CANName; +#endif + #if DEVICE_QSPI typedef enum { #ifdef QSPI0_BASE diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG11/can_device.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG11/can_device.h new file mode 100644 index 00000000000..ddd82d6776d --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG11/can_device.h @@ -0,0 +1,32 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_CAN_DEVICE_H +#define MBED_CAN_DEVICE_H + +#include "cmsis.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if DEVICE_CAN + +#define CAN_COUNT 2 // Number of CAN peripherals + + +#endif // DEVICE_CAN + +#endif diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/can_api.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/can_api.c new file mode 100644 index 00000000000..79ee7cf4327 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/can_api.c @@ -0,0 +1,310 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "can_api.h" +#include "clocking.h" + + +#if DEVICE_CAN + +#include "cmsis.h" +#include "pinmap.h" +#include "pinmap_function.h" +#include "PeripheralPins.h" +#include "mbed_assert.h" +#include "can_device.h" +#include "em_cmu.h" +#include "em_can.h" + +static uint32_t can_irq_ids[CAN_COUNT] = {0}; +static can_irq_handler irq_handler; + +// CAN bus interfaces +#define CAN_TX_IF 0 +#define CAN_RX_IF 1 + +void can_init(can_t *obj, PinName rd, PinName td) +{ + can_init_freq(obj, rd, td, 100000); +} + +void can_init_freq(can_t *obj, PinName rd, PinName td, int hz) +{ + CANName can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RX); + CANName can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TX); + obj->instance = (CAN_TypeDef *)pinmap_merge(can_rd, can_td); + + CMU_Clock_TypeDef cmuClock_number; + switch ((CANName)obj->instance) { + case CAN_0: + cmuClock_number = cmuClock_CAN0; + break; + case CAN_1: + cmuClock_number = cmuClock_CAN1; + break; + } + + MBED_ASSERT((unsigned int)rd != NC); + MBED_ASSERT((unsigned int)td != NC); + + + // Configure CAN pins + pinmap_pinout(rd, PinMap_CAN_RX); + pinmap_pinout(td, PinMap_CAN_TX); + + + CMU_ClockEnable(cmuClock_number, true); + + CAN_Init_TypeDef CanInit = CAN_INIT_DEFAULT; + CanInit.bitrate=hz; + CAN_Init(obj->instance, &CanInit); + CAN_SetMode(obj->instance, canModeNormal); + + uint32_t loc_rd = pin_location(rd, PinMap_CAN_RX); + uint32_t loc_td = pin_location(td, PinMap_CAN_TX); + + CAN_SetRoute(obj->instance, true, loc_rd, loc_td); + + + // Add pull-ups + if (rd != NC) { + pin_mode(rd, gpioModeInput); + } + if (td != NC) { + pin_mode(td, gpioModePushPull); + } + + CAN_ConfigureMessageObject(obj->instance, CAN_TX_IF, 1, true, true, false, true, true); + + CAN_ConfigureMessageObject(obj->instance, CAN_RX_IF, 2, true, false, false, true, true); + + CAN_MessageObject_TypeDef receiver; + + receiver.msgNum = 2; + receiver.id = 0; + receiver.mask = 0; + receiver.extended = false; + receiver.extendedMask = false; + + CAN_SetIdAndFilter(obj->instance, CAN_RX_IF, true, &receiver, true); +} + +void can_irq_init(can_t *obj, can_irq_handler handler, uint32_t id) +{ + int index = 0; + + switch ((CANName)obj->instance) { + case CAN_0: + index = 0; + break; + case CAN_1: + index = 1; + break; + } + + irq_handler = handler; + can_irq_ids[index] = id; +} + +void can_irq_free(can_t *obj) +{ + CAN_MessageIntDisable(obj->instance, _CAN_IF0IEN_MESSAGE_MASK); + CAN_MessageIntClear(obj->instance, 0xFFFFFFFF); + + switch ((CANName)obj->instance) { + case CAN_0: + NVIC_DisableIRQ(CAN0_IRQn); + break; + case CAN_1: + NVIC_DisableIRQ(CAN1_IRQn); + break; + } +} + +void can_free(can_t *obj) +{ + CAN_Enable(obj->instance, false); +} + +int can_frequency(can_t *obj, int f) +{ + CAN_Init_TypeDef CanInit = CAN_INIT_DEFAULT; + CanInit.bitrate=f; + + CAN_SetBitTiming(obj->instance, + CanInit.bitrate, + CanInit.propagationTimeSegment, + CanInit.phaseBufferSegment1, + CanInit.phaseBufferSegment2, + CanInit.synchronisationJumpWidth); +} + +int can_write(can_t *obj, CAN_Message msg, int cc) +{ + CAN_MessageObject_TypeDef message; + + message.id = msg.id; + message.msgNum = 1; + + if (msg.format == 0) message.extended = false; + else message.extended = true; + + message.dlc = msg.len; + + for (int i = 0; i < message.dlc; ++i) { + message.data[i] = (uint32_t)msg.data[i]; + } + + CAN_SendMessage(obj->instance, CAN_TX_IF, &message, true); + + return 1; +} + +int can_read(can_t *obj, CAN_Message *msg, int handle) +{ + CAN_MessageObject_TypeDef receiver; + + if (CAN_HasNewdata(obj->instance)) { + + receiver.msgNum = 2; + + CAN_ReadMessage(obj->instance, CAN_RX_IF, &receiver); + + msg->id = receiver.id; + msg->len = receiver.dlc; + + for (int i = 0; i < receiver.dlc; ++i) { + msg->data[i] = (unsigned char)receiver.data[i]; + } + + return 1; + } + + return 0; +} + +void can_reset(can_t *obj) +{ + CAN_Reset(obj->instance); +} + +unsigned char can_rderror(can_t *obj) +{ + return ((obj->instance->ERRCNT>>_CAN_ERRCNT_REC_SHIFT)&0xFF); +} + +unsigned char can_tderror(can_t *obj) +{ + return ((obj->instance->ERRCNT)&0xFF); +} + +void can_monitor(can_t *obj, int silent) +{ + CanMode mode = MODE_NORMAL; + + if (silent) { + mode = MODE_SILENT; + } + + CAN_SetMode(obj->instance, mode); +} + +int can_mode(can_t *obj, CanMode mode) +{ + CAN_SetMode(obj->instance, mode); + return 1; +} + +int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle) +{ + CAN_MessageObject_TypeDef message; + + message.msgNum = 2; + message.id = id; + message.mask = mask; + + if (format == CANStandard) { + message.extended = false; + message.extendedMask = false; + } else { + message.extended = true; + message.extendedMask = true; + } + + CAN_SetIdAndFilter(obj->instance, CAN_RX_IF, true, &message, true); + + return handle; +} + +void can_irq_set(can_t *obj, CanIrqType type, uint32_t enable) +{ + uint32_t ier = _CAN_IF0IEN_MESSAGE_MASK; + + if (enable) { + CAN_MessageIntEnable(obj->instance, ier); + } else { + CAN_MessageIntDisable(obj->instance, ier); + } + + switch ((CANName)obj->instance) { + case CAN_0: + NVIC_SetVector(CAN0_IRQn, CAN0_IRQHandler); + NVIC_EnableIRQ(CAN0_IRQn); + break; + case CAN_1: + NVIC_SetVector(CAN1_IRQn, CAN1_IRQHandler); + NVIC_EnableIRQ(CAN1_IRQn); + break; + } +} + +static void can_irq(CANName name, int id) +{ + CAN_TypeDef *can; + can = (CAN_TypeDef *)name; + + if (can->STATUS & CAN_STATUS_RXOK) { + irq_handler(can_irq_ids[id], IRQ_RX); + CAN_MessageIntClear(can, 0xFFFFFFFF); + } + + if (can->STATUS & CAN_STATUS_TXOK) { + irq_handler(can_irq_ids[id], IRQ_TX); + CAN_MessageIntClear(can, 0xFFFFFFFF); + } +} + +void CAN0_IRQHandler(void) +{ + can_irq(CAN_0, 0); +} + +void CAN1_IRQHandler(void) +{ + can_irq(CAN_1, 1); +} + + +const PinMap *can_rd_pinmap() +{ + return PinMap_CAN_TX; +} + +const PinMap *can_td_pinmap() +{ + return PinMap_CAN_RX; +} + +#endif // DEVICE_CAN diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/emlib/inc/em_can.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/emlib/inc/em_can.h index ead480eab7e..4d61f6f2c1d 100644 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/emlib/inc/em_can.h +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/emlib/inc/em_can.h @@ -1,33 +1,32 @@ /***************************************************************************//** - * @file em_can.h + * @file * @brief Controller Area Network API - * @version 5.3.3 + * @version 5.7.2 ******************************************************************************* * # License - * Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com + * Copyright 2018 Silicon Laboratories Inc. www.silabs.com ******************************************************************************* * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no - * obligation to support this Software. Silicon Labs is providing the - * Software "AS IS", with no express or implied warranties of any kind, - * including, but not limited to, any implied warranties of merchantability - * or fitness for any particular purpose or warranties against infringement - * of any proprietary rights of a third party. - * - * Silicon Labs will not be liable for any consequential, incidental, or - * special damages, or any other relief, or for any claim by any third party, - * arising from your use of this Software. - * ******************************************************************************/ #ifndef EM_CAN_H @@ -61,9 +60,9 @@ extern "C" { ******************************** ENUMS ************************************ ******************************************************************************/ -/** CAN Status codes */ +/** CAN Status codes. */ typedef enum { - /** No error occurred during last CAN bus event. */ + /** No error occurred during the last CAN bus event. */ canErrorNoError = CAN_STATUS_LEC_NONE, /** @@ -78,36 +77,36 @@ typedef enum { /** The message this CAN Core transmitted was not acknowledged by another node. */ canErrorAck = CAN_STATUS_LEC_ACK, - /** Wrong monitored bus value : dominant when the module wanted to send a recessive. */ + /** A wrong monitored bus value : dominant when the module wants to send a recessive. */ canErrorBit1 = CAN_STATUS_LEC_BIT1, - /** Wrong monitored bus value : recessive when the module intended to send a dominant. */ + /** A wrong monitored bus value : recessive when the module intends to send a dominant. */ canErrorBit0 = CAN_STATUS_LEC_BIT0, /** CRC check sum incorrect. */ canErrorCrc = CAN_STATUS_LEC_CRC, - /** Unused. No new error since the cpu wrote this value */ + /** Unused. No new error since the CPU wrote this value. */ canErrorUnused = CAN_STATUS_LEC_UNUSED } CAN_ErrorCode_TypeDef; -/** CAN peripheral mode */ +/** CAN peripheral mode. */ typedef enum { - /** CAN peripheral in Normal mode : ready to send and receive messages */ + /** CAN peripheral in Normal mode : ready to send and receive messages. */ canModeNormal, - /** CAN peripheral in Basic mode : no use of the RAM */ + /** CAN peripheral in Basic mode : no use of the RAM. */ canModeBasic, /** * CAN peripheral in Loopback mode : input from the CAN bus is disregarded - * and comes from TX instead + * and comes from TX instead. */ canModeLoopBack, /** * CAN peripheral in SilentLoopback mode : input from the CAN bus is - * disregarded and comes from TX instead ; no output on the CAN bus + * disregarded and comes from TX instead ; no output on the CAN bus. */ canModeSilentLoopBack, @@ -122,57 +121,57 @@ typedef enum { ******************************* STRUCTS *********************************** ******************************************************************************/ -/** CAN Message Object TypeDef structure. LSBs is used */ +/** CAN Message Object TypeDef structure. LSBs is used. */ typedef struct { - /** Message number of this Message Object, [1 - 32] */ + /** A message number of this Message Object, [1 - 32]. */ uint8_t msgNum; - /** Id extended if true, standard if false */ + /** ID extended if true, standard if false. */ bool extended; /** - * Id of the message, with 11 bits (standard) or 28 bits (extended). - * LSBs are used for both of them + * ID of the message with 11 bits (standard) or 28 bits (extended). + * LSBs are used for both. */ uint32_t id; - /** Data Length Code [0 - 8] */ + /** Data Length Code [0 - 8]. */ uint8_t dlc; - /** Pointer to the data, [0 - 8] bytes */ + /** A pointer to data, [0 - 8] bytes. */ uint8_t data[8]; - /** Mask for id filtering */ + /** A mask for ID filtering. */ uint32_t mask; - /** Enable the use of 'extended' value for filtering */ + /** Enable the use of 'extended' value for filtering. */ bool extendedMask; - /** Enable the use of 'direction' value for filtering */ + /** Enable the use of 'direction' value for filtering. */ bool directionMask; } CAN_MessageObject_TypeDef; /** CAN initialization structure. */ typedef struct { - /** true to set the CAN Device in normal mode after init */ + /** True to set the CAN Device in normal mode after initialization. */ bool enable; - /** True to reset messages during initialization */ + /** True to reset messages during initialization. */ bool resetMessages; - /** Default bitrate */ + /** Default bitrate. */ uint32_t bitrate; - /** Default Propagation Time Segment */ + /** Default Propagation Time Segment. */ uint8_t propagationTimeSegment; - /** Default Phase Buffer Segment 1 */ + /** Default Phase Buffer Segment 1. */ uint8_t phaseBufferSegment1; - /** Default Phase Buffer Segment 2 */ + /** Default Phase Buffer Segment 2. */ uint8_t phaseBufferSegment2; - /** Default Synchronisation Jump Width */ + /** Default Synchronisation Jump Width. */ uint8_t synchronisationJumpWidth; } CAN_Init_TypeDef; @@ -180,17 +179,17 @@ typedef struct { * Default initialization of CAN_Init_TypeDef. The total duration of a bit with * these default parameters is 10 tq (time quantum : tq = brp/fsys, brp being * the baudrate prescaler and being set according to the wanted bitrate, fsys - * beeing the CAN Device frequency). + * beeing the CAN device frequency). */ -#define CAN_INIT_DEFAULT \ - { \ - true, /** Set the CAN Device in normal mode after init */ \ - true, /** Reset messages during initialization */ \ - 100000, /** Set bitrate to 100 000 */ \ - 1, /** Set the Propagation Time Segment to 1 */ \ - 4, /** Set the Phase Buffer Segment 1 to 4 */ \ - 4, /** Set the Phase Buffer Segment 2 to 4 */ \ - 1 /** Set the Synchronization Jump Width to 1 */ \ +#define CAN_INIT_DEFAULT \ + { \ + true, /** Set the CAN Device in normal mode after initialization. */ \ + true, /** Reset messages during initialization. */ \ + 100000, /** Set bitrate to 100 000 */ \ + 1, /** Set the Propagation Time Segment to 1. */ \ + 4, /** Set the Phase Buffer Segment 1 to 4. */ \ + 4, /** Set the Phase Buffer Segment 2 to 4. */ \ + 1 /** Set the Synchronization Jump Width to 1. */ \ } /******************************************************************************* @@ -264,11 +263,11 @@ void CAN_SendRequest(CAN_TypeDef *can, * Enable the Host Controller to send messages. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] enable - * true to enable CAN device, false to disable it. If the CAN device is - * enabled, it goes in normal mode (the default working mode). + * True to enable CAN device, false to disable it. If the CAN device is + * enabled, it goes to normal mode (the default working mode). ******************************************************************************/ __STATIC_INLINE void CAN_Enable(CAN_TypeDef *can, bool enable) { @@ -277,13 +276,13 @@ __STATIC_INLINE void CAN_Enable(CAN_TypeDef *can, bool enable) /***************************************************************************//** * @brief - * Gives the communication capabilities state. + * Give the communication capabilities state. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @return - * true if the Host Controller can send messages, false otherwise. + * True if the Host Controller can send messages, false otherwise. ******************************************************************************/ __STATIC_INLINE bool CAN_IsEnabled(CAN_TypeDef *can) { @@ -295,7 +294,7 @@ __STATIC_INLINE bool CAN_IsEnabled(CAN_TypeDef *can) * Waiting function. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] interface * Indicate which Message Interface Register to use. @@ -328,13 +327,13 @@ __STATIC_INLINE CAN_ErrorCode_TypeDef CAN_GetLastErrorCode(CAN_TypeDef *can) /***************************************************************************//** * @brief - * Indicates which messages objects have received new data. + * Indicates which message objects have received new data. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @return - * State of MESSAGEDATA register indicating which messages objects have received + * State of MESSAGEDATA register indicating which message objects have received * new data. ******************************************************************************/ __STATIC_INLINE uint32_t CAN_HasNewdata(CAN_TypeDef *can) @@ -347,7 +346,7 @@ __STATIC_INLINE uint32_t CAN_HasNewdata(CAN_TypeDef *can) * Clear one or more pending CAN status interrupts. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] flags * Pending CAN status interrupt source(s) to clear. @@ -362,7 +361,7 @@ __STATIC_INLINE void CAN_StatusIntClear(CAN_TypeDef *can, uint32_t flags) * Disable CAN status interrupts. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] flags * CAN status interrupt source(s) to disable. @@ -377,7 +376,7 @@ __STATIC_INLINE void CAN_StatusIntDisable(CAN_TypeDef *can, uint32_t flags) * Enable CAN status interrupts. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] flags * CAN status interrupt source(s) to enable. @@ -392,10 +391,10 @@ __STATIC_INLINE void CAN_StatusIntEnable(CAN_TypeDef *can, uint32_t flags) * Get pending CAN status interrupt flags. * * @note - * The event bits are not cleared by the use of this function. + * This function does not clear event bits. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @return * CAN interrupt source(s) pending. @@ -410,10 +409,10 @@ __STATIC_INLINE uint32_t CAN_StatusIntGet(CAN_TypeDef *can) * Get pending and enabled CAN status interrupt flags. * * @note - * The event bits are not cleared by the use of this function. + * This function does not clear event bits. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @return * CAN interrupt source(s) pending and enabled. @@ -431,7 +430,7 @@ __STATIC_INLINE uint32_t CAN_StatusIntGetEnabled(CAN_TypeDef *can) * Set one or more CAN status interrupts. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] flags * CAN status interrupt source(s) to set to pending. @@ -446,10 +445,10 @@ __STATIC_INLINE void CAN_StatusIntSet(CAN_TypeDef *can, uint32_t flags) * Get CAN status. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @return - * Value of CAN register STATUS. + * A value of CAN register STATUS. ******************************************************************************/ __STATIC_INLINE uint32_t CAN_StatusGet(CAN_TypeDef *can) { @@ -461,7 +460,7 @@ __STATIC_INLINE uint32_t CAN_StatusGet(CAN_TypeDef *can) * Clear CAN status. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] flags * CAN status bits to clear. @@ -476,7 +475,7 @@ __STATIC_INLINE void CAN_StatusClear(CAN_TypeDef *can, uint32_t flags) * Get the error count. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @return * Error count. @@ -491,7 +490,7 @@ __STATIC_INLINE uint32_t CAN_GetErrorCount(CAN_TypeDef *can) * Clear one or more pending CAN message interrupts. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] flags * Pending CAN message interrupt source(s) to clear. @@ -506,7 +505,7 @@ __STATIC_INLINE void CAN_MessageIntClear(CAN_TypeDef *can, uint32_t flags) * Disable CAN message interrupts. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] flags * CAN message interrupt source(s) to disable. @@ -521,7 +520,7 @@ __STATIC_INLINE void CAN_MessageIntDisable(CAN_TypeDef *can, uint32_t flags) * Enable CAN message interrupts. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] flags * CAN message interrupt source(s) to enable. @@ -536,10 +535,10 @@ __STATIC_INLINE void CAN_MessageIntEnable(CAN_TypeDef *can, uint32_t flags) * Get pending CAN message interrupt flags. * * @note - * The event bits are not cleared by the use of this function. + * This function does not clear event bits. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @return * CAN message interrupt source(s) pending. @@ -554,10 +553,10 @@ __STATIC_INLINE uint32_t CAN_MessageIntGet(CAN_TypeDef *can) * Get CAN message interrupt flags that are pending and enabled. * * @note - * The event bits are not cleared by the use of this function. + * This function does not clear event bits. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @return * CAN message interrupt source(s) pending and enabled. @@ -575,10 +574,10 @@ __STATIC_INLINE uint32_t CAN_MessageIntGetEnabled(CAN_TypeDef *can) * Set one or more CAN message interrupts. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] flags - * CAN message interrupt source(s) to set to pending. + * CAN message interrupt source(s) to set as pending. ******************************************************************************/ __STATIC_INLINE void CAN_MessageIntSet(CAN_TypeDef *can, uint32_t flags) { diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_can.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_can.c index 643cfd23906..061473423b5 100644 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_can.c +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_can.c @@ -1,33 +1,32 @@ /***************************************************************************//** - * @file em_can.c + * @file * @brief Controller Area Network API - * @version 5.3.3 + * @version 5.7.2 ******************************************************************************* * # License - * Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com + * Copyright 2018 Silicon Laboratories Inc. www.silabs.com ******************************************************************************* * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * - * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no - * obligation to support this Software. Silicon Labs is providing the - * Software "AS IS", with no express or implied warranties of any kind, - * including, but not limited to, any implied warranties of merchantability - * or fitness for any particular purpose or warranties against infringement - * of any proprietary rights of a third party. - * - * Silicon Labs will not be liable for any consequential, incidental, or - * special damages, or any other relief, or for any claim by any third party, - * arising from your use of this Software. - * ******************************************************************************/ #include "em_can.h" @@ -40,9 +39,9 @@ /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ -/* Macros to use the ID field in the CANn_MIRx_ARB register as a 11 bit - * standard id. The register field can be used for both an 11 bit standard - * id and a 29 bit extended id. */ +/* Macros to use for the ID field in the CANn_MIRx_ARB register as an 11 bit + * standard ID. The register field can be used for both an 11 bit standard + * ID and a 29 bit extended ID. */ #define _CAN_MIR_ARB_STD_ID_SHIFT 18 #define _CAN_MIR_MASK_STD_SHIFT 18 #define _CAN_MIR_ARB_STD_ID_MASK 0x1FFC0000UL @@ -71,8 +70,8 @@ * multi-master serial bus for connecting microcontrollers and devices, also * known as nodes, to communicate with each other in applications without a host * computer. CAN is a message-based protocol, designed originally for automotive - * applications, but meanwhile used also in many other surroundings. - * The complexity of the node can range from a simple I/O device up to an + * applications, but also used in many other scenarios. + * The complexity of a node can range from a simple I/O device up to an * embedded computer with a CAN interface and sophisticated software. The node * may also be a gateway allowing a standard computer to communicate over a USB * or Ethernet port to the devices on a CAN network. Devices are connected to @@ -92,10 +91,10 @@ * Initialize CAN. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] init - * Pointer to CAN initialization structure. + * A pointer to the CAN initialization structure. ******************************************************************************/ void CAN_Init(CAN_TypeDef *can, const CAN_Init_TypeDef *init) { @@ -122,13 +121,13 @@ void CAN_Init(CAN_TypeDef *can, const CAN_Init_TypeDef *init) * Get the CAN module frequency. * * @details - * There is an internal prescaler of 2 inside the CAN module. + * An internal prescaler of 2 is inside the CAN module. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @return - * Clock value + * A clock value. ******************************************************************************/ uint32_t CAN_GetClockFrequency(CAN_TypeDef *can) { @@ -153,33 +152,33 @@ uint32_t CAN_GetClockFrequency(CAN_TypeDef *can) * 'Message Lost' flag. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] interface * Indicate which Message Interface Register to use. * * @param[in] msgNum - * Message number of the Message Object, [1 - 32]. + * A message number of the Message Object, [1 - 32]. * * @return - * true if a message was lost, false otherwise. + * True if a message was lost, false otherwise. ******************************************************************************/ bool CAN_MessageLost(CAN_TypeDef *can, uint8_t interface, uint8_t msgNum) { CAN_MIR_TypeDef * mir = &can->MIR[interface]; bool messageLost; - /* Make sure msgNum is in the correct range */ + /* Make sure msgNum is in the correct range. */ EFM_ASSERT((msgNum > 0) && (msgNum <= 32)); CAN_ReadyWait(can, interface); - /* Set which registers to read from the RAM */ + /* Set which registers to read from RAM. */ mir->CMDMASK = CAN_MIR_CMDMASK_WRRD_READ | CAN_MIR_CMDMASK_CONTROL | CAN_MIR_CMDMASK_CLRINTPND; - /* Send reading request and wait (3 to 6 cpu cycle) */ + /* Send reading request and wait (3 to 6 cpu cycle). */ CAN_SendRequest(can, interface, msgNum, true); messageLost = mir->CTRL & _CAN_MIR_CTRL_MESSAGEOF_MASK; @@ -187,14 +186,14 @@ bool CAN_MessageLost(CAN_TypeDef *can, uint8_t interface, uint8_t msgNum) if (messageLost) { mir->CMDMASK = CAN_MIR_CMDMASK_WRRD | CAN_MIR_CMDMASK_CONTROL; - /* Reset the 'MessageLost' bit */ + /* Reset the 'MessageLost' bit. */ mir->CTRL &= ~_CAN_MIR_CTRL_MESSAGEOF_MASK; - /* Send reading request and wait (3 to 6 cpu cycle) */ + /* Send reading request and wait (3 to 6 cpu cycle). */ CAN_SendRequest(can, interface, msgNum, true); } - /* Return the state of the MESSAGEOF bit */ + /* Return the state of the MESSAGEOF bit. */ return messageLost; } @@ -203,16 +202,16 @@ bool CAN_MessageLost(CAN_TypeDef *can, uint8_t interface, uint8_t msgNum) * Set the ROUTE registers. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] active - * Boolean to activate or not the ROUTE registers. + * A boolean indicating whether or not to activate the ROUTE registers. * * @param[in] pinRxLoc - * Location of the rx pin. + * A location of the RX pin. * * @param[in] pinTxLoc - * Location of the tx pin. + * A location of the TX pin. ******************************************************************************/ void CAN_SetRoute(CAN_TypeDef *can, bool active, @@ -232,34 +231,34 @@ void CAN_SetRoute(CAN_TypeDef *can, /***************************************************************************//** * @brief - * Set the bitrate and its parameters + * Set the bitrate and its parameters. * * @details - * There are multiple parameters which need to be properly configured. - * Please refer to the reference manual for a detailed description. + * Multiple parameters need to be properly configured. + * See the reference manual for a detailed description. * Careful : the BRP (Baud Rate Prescaler) is calculated by: * 'brp = freq / (period * bitrate);'. freq is the frequency of the CAN - * device, period the time of transmission of a bit. The result is an uint32_t - * hence it's truncated, causing an approximation error. This error is non - * negligeable when period is high, bitrate is high and freq is low. + * device, period the time of transmission of a bit. The result is an uint32_t. + * Hence it's truncated, causing an approximation error. This error is non + * negligible when the period is high, the bitrate is high, and frequency is low. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] bitrate - * Wanted bitrate on the CAN bus. + * A wanted bitrate on the CAN bus. * * @param[in] propagationTimeSegment - * Value for the Propagation Time Segment. + * A value for the Propagation Time Segment. * * @param[in] phaseBufferSegment1 - * Value for the Phase Buffer Segment 1. + * A value for the Phase Buffer Segment 1. * * @param[in] phaseBufferSegment2 - * Value for the Phase Buffer Segment 2. + * A value for the Phase Buffer Segment 2. * * @param[in] synchronisationJumpWidth - * Value for the Synchronisation Jump Width. + * A value for the Synchronization Jump Width. ******************************************************************************/ void CAN_SetBitTiming(CAN_TypeDef *can, uint32_t bitrate, @@ -270,7 +269,7 @@ void CAN_SetBitTiming(CAN_TypeDef *can, { uint32_t sum, brp, period, freq, brpHigh, brpLow; - /* Verification that the parameters are within range */ + /* Verification that the parameters are in range. */ EFM_ASSERT((propagationTimeSegment <= 8) && (propagationTimeSegment > 0)); EFM_ASSERT((phaseBufferSegment1 <= 8) && (phaseBufferSegment1 > 0)); EFM_ASSERT((phaseBufferSegment2 <= 8) && (phaseBufferSegment2 > 0)); @@ -280,29 +279,29 @@ void CAN_SetBitTiming(CAN_TypeDef *can, && (synchronisationJumpWidth > 0)); /* propagationTimeSegment is counted as part of phaseBufferSegment1 in the - BITTIMING register */ + BITTIMING register. */ sum = phaseBufferSegment1 + propagationTimeSegment; - /* period is the total length of one CAN bit. 1 is the Sync_seg */ + /* Period is the total length of one CAN bit. 1 is the Sync_seg. */ period = 1 + sum + phaseBufferSegment2; freq = CAN_GetClockFrequency(can); brp = freq / (period * bitrate); EFM_ASSERT(brp != 0); - /* -1 because the hardware reads 'written value + 1' */ + /* -1 because the hardware reads 'written value + 1'. */ brp = brp - 1; - /* brp is divided between two registers */ + /* brp is divided between two registers. */ brpHigh = brp / 64; brpLow = brp % 64; - /* Checking register limit */ + /* Checking register limit. */ EFM_ASSERT(brpHigh <= 15); bool enabled = CAN_IsEnabled(can); - /* Enable access to the bittiming registers */ + /* Enable access to the bittiming registers. */ can->CTRL |= CAN_CTRL_CCE | CAN_CTRL_INIT; can->BITTIMING = (brpLow << _CAN_BITTIMING_BRP_SHIFT) @@ -323,12 +322,12 @@ void CAN_SetBitTiming(CAN_TypeDef *can, * Set the CAN operation mode. * * @details - * In Init mode, the CAN module is deactivated. Reset of the Messages in all - * the other modes to be sure that there are no leftover data and that they - * need to be configured before being of use. + * In initialization mode, the CAN module is deactivated. Reset the messages in all + * other modes to be sure that there is no leftover data that + * needs to be configured before use. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] mode * Mode of operation : Init, Normal, Loopback, SilentLoopback, Silent, Basic. @@ -385,22 +384,22 @@ void CAN_SetMode(CAN_TypeDef *can, CAN_Mode_TypeDef mode) /***************************************************************************//** * @brief - * Set the Id and the filter for a specific Message Object. + * Set the ID and the filter for a specific Message Object. * * @details - * The Init bit have to be 0 to use this function. + * The initialization bit has to be 0 to use this function. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] interface * Indicate which Message Interface Register to use. * * @param[in] useMask - * Boolean to choose whether or not to use the masks. + * A boolean to choose whether or not to use the masks. * * @param[in] message - * Message Object + * A Message Object. * * @param[in] wait * If true, wait for the end of the transfer between the MIRx registers and @@ -413,89 +412,90 @@ void CAN_SetIdAndFilter(CAN_TypeDef *can, const CAN_MessageObject_TypeDef *message, bool wait) { - /* Make sure msgNum is in the correct range */ + /* Make sure msgNum is in the correct range. */ EFM_ASSERT((message->msgNum > 0) && (message->msgNum <= 32)); CAN_MIR_TypeDef * mir = &can->MIR[interface]; CAN_ReadyWait(can, interface); - /* Set which registers to read from the RAM */ + /* Set which registers to read from RAM. */ mir->CMDMASK = CAN_MIR_CMDMASK_WRRD_READ | CAN_MIR_CMDMASK_ARBACC | CAN_MIR_CMDMASK_CONTROL; - /* Send reading request and wait (3 to 6 cpu cycle) */ + /* Send reading request and wait (3 to 6 CPU cycle). */ CAN_SendRequest(can, interface, message->msgNum, true); - /* Reset MSGVAL */ - mir->CMDMASK |= CAN_MIR_CMDMASK_WRRD; - mir->ARB &= ~(0x1 << _CAN_MIR_ARB_MSGVAL_SHIFT); + /* Reset MSGVAL. */ + mir->CMDMASK |= CAN_MIR_CMDMASK_WRRD_WRITE; + mir->ARB &= ~(0x1U << _CAN_MIR_ARB_MSGVAL_SHIFT); CAN_SendRequest(can, interface, message->msgNum, true); - /* Set which registers to write to the RAM */ + /* Set which registers to write to RAM. */ mir->CMDMASK |= CAN_MIR_CMDMASK_MASKACC; - /* Set UMASK bit */ + /* Set UMASK bit. */ BUS_RegBitWrite(&mir->CTRL, _CAN_MIR_CTRL_UMASK_SHIFT, useMask); - /* Configure the id */ + /* Configure the ID. */ if (message->extended) { EFM_ASSERT(message->id <= _CAN_MIR_ARB_ID_MASK); mir->ARB = (mir->ARB & ~_CAN_MIR_ARB_ID_MASK) | (message->id << _CAN_MIR_ARB_ID_SHIFT) - | (uint32_t)(0x1 << _CAN_MIR_ARB_MSGVAL_SHIFT) + | (0x1UL << _CAN_MIR_ARB_MSGVAL_SHIFT) | CAN_MIR_ARB_XTD_EXT; } else { EFM_ASSERT(message->id <= _CAN_MIR_ARB_STD_ID_MAX); mir->ARB = (mir->ARB & ~(_CAN_MIR_ARB_ID_MASK | CAN_MIR_ARB_XTD_STD)) - | (message->id << _CAN_MIR_ARB_STD_ID_SHIFT) - | (uint32_t)(0x1 << _CAN_MIR_ARB_MSGVAL_SHIFT); + | (_CAN_MIR_ARB_STD_ID_SHIFT) + | (0x1UL << _CAN_MIR_ARB_MSGVAL_SHIFT); } if (message->extendedMask) { - mir->MASK = (message->mask << _CAN_MIR_MASK_MASK_SHIFT); + mir->MASK = (message->mask << _CAN_MIR_MASK_MASK_SHIFT) + & _CAN_MIR_MASK_MASK_MASK; } else { mir->MASK = (message->mask << _CAN_MIR_MASK_STD_SHIFT) & _CAN_MIR_ARB_STD_ID_MASK; } - /* Configure the masks */ + /* Configure the masks. */ mir->MASK |= (message->extendedMask << _CAN_MIR_MASK_MXTD_SHIFT) | (message->directionMask << _CAN_MIR_MASK_MDIR_SHIFT); - /* Send writing request */ + /* Send a writing request. */ CAN_SendRequest(can, interface, message->msgNum, wait); } /***************************************************************************//** * @brief - * Configure valid, tx/rx, remoteTransfer for a specific Message Object. + * Configure valid, TX/RX, remoteTransfer for a specific Message Object. * * @details - * The Init bit have to be 0 to use this function. + * The initialization bit has to be 0 to use this function. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] interface * Indicate which Message Interface Register to use. * * @param[in] msgNum - * Message number of this Message Object, [1 - 32]. + * A message number of this Message Object, [1 - 32]. * * @param[in] valid - * true if Message Object is valid, false otherwise. + * True if the Message Object is valid, false otherwise. * * @param[in] tx - * true if Message Object is used for transmission, false if used for + * True if the Message Object is used for transmission, false if used for * reception. * * @param[in] remoteTransfer - * true if Message Object is used for remote transmission, false otherwise. + * True if the Message Object is used for remote transmission, false otherwise. * * @param[in] endOfBuffer - * true if it is for a single Message Object or the end of a fifo buffer, - * false if the Message Object is part of a fifo buffer and not the last. + * True if it is for a single Message Object or the end of a FIFO buffer, + * false if the Message Object is part of a FIFO buffer and not the last. * * @param[in] wait * If true, wait for the end of the transfer between the MIRx registers and @@ -513,64 +513,64 @@ void CAN_ConfigureMessageObject(CAN_TypeDef *can, { CAN_MIR_TypeDef * mir = &can->MIR[interface]; - /* Make sure msgNum is in the correct range */ + /* Make sure msgNum is in correct range. */ EFM_ASSERT((msgNum > 0) && (msgNum <= 32)); CAN_ReadyWait(can, interface); - /* Set which registers to read from the RAM */ + /* Set which registers to read from RAM. */ mir->CMDMASK = CAN_MIR_CMDMASK_WRRD_READ | CAN_MIR_CMDMASK_ARBACC | CAN_MIR_CMDMASK_CONTROL; - /* Send reading request and wait (3 to 6 cpu cycle) */ + /* Send reading request and wait (3 to 6 CPU cycle). */ CAN_SendRequest(can, interface, msgNum, true); - /* Set which registers to write to the RAM */ - mir->CMDMASK |= CAN_MIR_CMDMASK_WRRD; + /* Set which registers to write to RAM. */ + mir->CMDMASK |= CAN_MIR_CMDMASK_WRRD_WRITE; - /* Configure valid message and direction */ + /* Configure a valid message and direction. */ mir->ARB = (mir->ARB & ~(_CAN_MIR_ARB_DIR_MASK | _CAN_MIR_ARB_MSGVAL_MASK)) | (valid << _CAN_MIR_ARB_MSGVAL_SHIFT) | (tx << _CAN_MIR_ARB_DIR_SHIFT); - /* Set eob bit, rx and tx interrupts */ + /* Set EOB bit, RX, and TX interrupts. */ mir->CTRL = (endOfBuffer << _CAN_MIR_CTRL_EOB_SHIFT) | _CAN_MIR_CTRL_TXIE_MASK | _CAN_MIR_CTRL_RXIE_MASK | (remoteTransfer << _CAN_MIR_CTRL_RMTEN_SHIFT); - /* Send writing request */ + /* Send a writing request. */ CAN_SendRequest(can, interface, msgNum, wait); } /***************************************************************************//** * @brief - * Send the data from the Message Object message. + * Send data from the Message Object message. * * @details - * If message is configured as tx and remoteTransfer = 0, calling this function + * If the message is configured as TX and remoteTransfer = 0, calling this function * will send the data of this Message Object if its parameters are correct. - * If message is tx and remoteTransfer = 1, this function will set the data of - * message to the RAM and exit, the data will be automatically sent after + * If the message is TX and remoteTransfer = 1, this function will set the data of + * message to RAM and exit. Data will be automatically sent after * reception of a remote frame. - * If message is rx and remoteTransfer = 1, this function will send a remote - * frame to the corresponding id. - * If message is rx and remoteTransfer = 0, the user shouldn't call this + * If the message is RX and remoteTransfer = 1, this function will send a remote + * frame to the corresponding ID. + * If the message is RX and remoteTransfer = 0, the user shouldn't call this * function. It will also send a remote frame. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] interface * Indicate which Message Interface Register to use. * * @param[in] message - * Message Object + * A Message Object. * * @param[in] wait * If true, wait for the end of the transfer between the MIRx registers and - * the RAM to exit. If false, exit immediately, the transfer can still be + * RAM to exit. If false, exit immediately. The transfer can still be * in progress. ******************************************************************************/ void CAN_SendMessage(CAN_TypeDef *can, @@ -580,85 +580,85 @@ void CAN_SendMessage(CAN_TypeDef *can, { CAN_MIR_TypeDef * mir = &can->MIR[interface]; - /* Make sure msgNum is in the correct range */ + /* Make sure msgNum is in correct range. */ EFM_ASSERT((message->msgNum > 0) && (message->msgNum <= 32)); - /* Make sure dlc is in the correct range */ + /* Make sure dlc is in correct range. */ EFM_ASSERT(message->dlc <= _CAN_MIR_CTRL_DLC_MASK); CAN_ReadyWait(can, interface); - /* Set LEC to unused value to be sure it is reset to 0 after sending */ + /* Set LEC to an unused value to be sure it is reset to 0 after sending. */ BUS_RegMaskedWrite(&can->STATUS, _CAN_STATUS_LEC_MASK, 0x7); - /* Set which registers to read from the RAM */ + /* Set which registers to read from RAM. */ mir->CMDMASK = CAN_MIR_CMDMASK_WRRD_READ | CAN_MIR_CMDMASK_ARBACC | CAN_MIR_CMDMASK_CONTROL; - /* Send reading request and wait (3 to 6 cpu cycle) */ + /* Send a reading request and wait (3 to 6 CPU cycle). */ CAN_SendRequest(can, interface, message->msgNum, true); - /* Reset MSGVAL */ - mir->CMDMASK |= CAN_MIR_CMDMASK_WRRD; - mir->ARB &= ~(0x1 << _CAN_MIR_ARB_MSGVAL_SHIFT); + /* Reset MSGVAL. */ + mir->CMDMASK |= CAN_MIR_CMDMASK_WRRD_WRITE; + mir->ARB &= ~(0x1UL << _CAN_MIR_ARB_MSGVAL_SHIFT); CAN_SendRequest(can, interface, message->msgNum, true); - /* Set which registers to write to the RAM */ + /* Set which registers to write to RAM. */ mir->CMDMASK |= CAN_MIR_CMDMASK_DATAA | CAN_MIR_CMDMASK_DATAB; - /* If tx = 1 and remoteTransfer = 1, nothing is sent */ + /* If TX = 1 and remoteTransfer = 1, nothing is sent. */ if ( ((mir->CTRL & _CAN_MIR_CTRL_RMTEN_MASK) == 0) || ((mir->ARB & _CAN_MIR_ARB_DIR_MASK) == _CAN_MIR_ARB_DIR_RX)) { mir->CTRL |= CAN_MIR_CTRL_TXRQST; - /* DATAVALID is set only if it is not sending a remote message */ + /* DATAVALID is set only if it is not sending a remote message. */ if ((mir->CTRL & _CAN_MIR_CTRL_RMTEN_MASK) == 0) { mir->CTRL |= CAN_MIR_CTRL_DATAVALID; } } - /* Set the Data length Code */ + /* Set the data length code. */ mir->CTRL = (mir->CTRL & ~_CAN_MIR_CTRL_DLC_MASK) | message->dlc; - /* Configure the id */ + /* Configure the ID. */ if (message->extended) { EFM_ASSERT(message->id <= _CAN_MIR_ARB_ID_MASK); mir->ARB = (mir->ARB & ~_CAN_MIR_ARB_ID_MASK) | (message->id << _CAN_MIR_ARB_ID_SHIFT) - | (uint32_t)(0x1 << _CAN_MIR_ARB_MSGVAL_SHIFT) + | (0x1UL << _CAN_MIR_ARB_MSGVAL_SHIFT) | CAN_MIR_ARB_XTD_EXT; } else { EFM_ASSERT(message->id <= _CAN_MIR_ARB_STD_ID_MAX); mir->ARB = (mir->ARB & ~(_CAN_MIR_ARB_ID_MASK | _CAN_MIR_ARB_XTD_MASK)) - | (uint32_t)(0x1 << _CAN_MIR_ARB_MSGVAL_SHIFT) + | (0x1UL << _CAN_MIR_ARB_MSGVAL_SHIFT) | (message->id << _CAN_MIR_ARB_STD_ID_SHIFT) | CAN_MIR_ARB_XTD_STD; } - /* Set the data */ + /* Set data. */ CAN_WriteData(can, interface, message); - /* Send writing request */ + /* Send a writing request. */ CAN_SendRequest(can, interface, message->msgNum, wait); } /***************************************************************************//** * @brief - * Read the data from a Message Object in the RAM and store it in message. + * Read data from a Message Object in RAM and store it in a message. * * @details - * Read all the information from the RAM on this Message Object : the data but + * Read the information from RAM on this Message Object : data but * also the configuration of the other registers. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] interface * Indicate which Message Interface Register to use. * * @param[in] message - * Message Object + * A Message Object. ******************************************************************************/ void CAN_ReadMessage(CAN_TypeDef *can, uint8_t interface, @@ -668,12 +668,12 @@ void CAN_ReadMessage(CAN_TypeDef *can, uint32_t buffer; uint32_t i; - /* Make sure msgNum is in the correct range */ + /* Make sure msgNum is in correct range. */ EFM_ASSERT((message->msgNum > 0) && (message->msgNum <= 32)); CAN_ReadyWait(can, interface); - /* Set which registers to read from the RAM */ + /* Set which registers to read from RAM. */ mir->CMDMASK = CAN_MIR_CMDMASK_WRRD_READ | CAN_MIR_CMDMASK_MASKACC | CAN_MIR_CMDMASK_ARBACC @@ -683,16 +683,23 @@ void CAN_ReadMessage(CAN_TypeDef *can, | CAN_MIR_CMDMASK_DATAA | CAN_MIR_CMDMASK_DATAB; - /* Send reading request and wait (3 to 6 cpu cycle) */ + /* Send a reading request and wait (3 to 6 cpu cycle). */ CAN_SendRequest(can, interface, message->msgNum, true); - /* Get dlc from the control register */ + /* Get dlc from the control register. */ message->dlc = ((mir->CTRL & _CAN_MIR_CTRL_DLC_MASK) >> _CAN_MIR_CTRL_DLC_SHIFT); - /* Make sure dlc is in the correct range */ + /* Make sure dlc is in correct range. */ EFM_ASSERT(message->dlc <= 8); - /* Copy the data from the MIR registers to the Message Object message */ + /* Get id from the control register */ + if (message->extended) { + message->id = (mir->ARB & _CAN_MIR_ARB_ID_MASK); + } else { + message->id = ((mir->ARB & _CAN_MIR_ARB_STD_ID_MASK) >> _CAN_MIR_ARB_STD_ID_SHIFT); + } + + /* Copy data from the MIR registers to the Message Object message. */ buffer = mir->DATAL; for (i = 0; i < SL_MIN(message->dlc, 4U); ++i) { message->data[i] = buffer & 0xFF; @@ -709,25 +716,25 @@ void CAN_ReadMessage(CAN_TypeDef *can, /***************************************************************************//** * @brief - * Abort the sending of a message + * Abort sending a message. * * @details - * Set the TXRQST of the CTRL register to 0. Doesn't touch the data ot the - * others parameters. The user can reuse CAN_SendMessage() to send the object + * Set the TXRQST of the CTRL register to 0. Doesn't touch data or the + * other parameters. The user can call CAN_SendMessage() to send the object * after using CAN_AbortSendMessage(). * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] interface * Indicate which Message Interface Register to use. * * @param[in] msgNum - * Message number of this Message Object, [1 - 32]. + * A message number of this Message Object, [1 - 32]. * * @param[in] wait * If true, wait for the end of the transfer between the MIRx registers and - * the RAM to exit. If false, exit immediately, the transfer can still be + * the RAM to exit. If false, exit immediately. The transfer can still be * in progress. ******************************************************************************/ void CAN_AbortSendMessage(CAN_TypeDef *can, @@ -735,29 +742,36 @@ void CAN_AbortSendMessage(CAN_TypeDef *can, uint8_t msgNum, bool wait) { - /* Make sure msgNum is in the correct range */ + /* Make sure msgNum is in correct range. */ EFM_ASSERT((msgNum > 0) && (msgNum <= 32)); CAN_MIR_TypeDef * mir = &can->MIR[interface]; CAN_ReadyWait(can, interface); - /* Set which registers to write to the RAM */ + /* Set which registers to read from RAM. */ + mir->CMDMASK = CAN_MIR_CMDMASK_WRRD_READ + | CAN_MIR_CMDMASK_CONTROL; + + /* Send a reading request and wait (3 to 6 cpu cycle). */ + CAN_SendRequest(can, interface, msgNum, true); + + /* Set which registers to write to RAM. */ mir->CMDMASK = CAN_MIR_CMDMASK_WRRD - | CAN_MIR_CMDMASK_ARBACC; + | CAN_MIR_CMDMASK_CONTROL; - /* Set TXRQST bit to 0 */ - mir->ARB &= ~_CAN_MIR_CTRL_TXRQST_MASK; + /* Set TXRQST bit to 0. */ + mir->CTRL &= ~_CAN_MIR_CTRL_TXRQST_MASK; - /* Send writing request */ + /* Send a writing request. */ CAN_SendRequest(can, interface, msgNum, wait); } /***************************************************************************//** * @brief - * Reset all the Message Objects and set their data to 0. + * Reset all Message Objects and set their data to 0. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] interface * Indicate which Message Interface Register to use. @@ -767,7 +781,7 @@ void CAN_ResetMessages(CAN_TypeDef *can, uint8_t interface) CAN_MIR_TypeDef * mir = &can->MIR[interface]; CAN_ReadyWait(can, interface); - /* Set which registers to read from the RAM */ + /* Set which registers to read from RAM. */ mir->CMDMASK = CAN_MIR_CMDMASK_WRRD | CAN_MIR_CMDMASK_MASKACC | CAN_MIR_CMDMASK_ARBACC @@ -781,7 +795,7 @@ void CAN_ResetMessages(CAN_TypeDef *can, uint8_t interface) mir->DATAL = 0x00000000; mir->DATAH = 0x00000000; - /* Write each reset Message Object to the RAM */ + /* Write each reset Message Object to RAM. */ for (int i = 1; i <= 32; ++i) { CAN_SendRequest(can, interface, i, true); } @@ -789,10 +803,10 @@ void CAN_ResetMessages(CAN_TypeDef *can, uint8_t interface) /***************************************************************************//** * @brief - * Set all the CAN registers to RESETVALUE. Leave the CAN Device disabled. + * Set all CAN registers to RESETVALUE. Leave the CAN device disabled. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. ******************************************************************************/ void CAN_Reset(CAN_TypeDef *can) { @@ -833,56 +847,61 @@ void CAN_Reset(CAN_TypeDef *can) /***************************************************************************//** * @brief - * Write the data from message to the MIRx registers + * Write data from a message to the MIRx registers. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] interface * Indicate which Message Interface Register to use. * * @param[in] message - * Message Object + * A Message Object. ******************************************************************************/ void CAN_WriteData(CAN_TypeDef *can, uint8_t interface, const CAN_MessageObject_TypeDef *message) { - CAN_MIR_TypeDef * mir = &can->MIR[interface]; + uint32_t tmp; uint8_t data[8] = { 0 }; size_t length = SL_MIN(8, message->dlc); + CAN_MIR_TypeDef * mir = &can->MIR[interface]; for (size_t i = 0; i < length; i++) { data[i] = message->data[i]; } CAN_ReadyWait(can, interface); - mir->DATAL = (data[3] << 24) - | (data[2] << 16) - | (data[1] << 8) - | (data[0] << 0); - mir->DATAH = (data[7] << 24) - | (data[6] << 16) - | (data[5] << 8) - | (data[4] << 0); + + tmp = data[0]; + tmp |= data[1] << 8; + tmp |= data[2] << 16; + tmp |= data[3] << 24; + mir->DATAL = tmp; + + tmp = data[4]; + tmp |= data[5] << 8; + tmp |= data[6] << 16; + tmp |= data[7] << 24; + mir->DATAH = tmp; } /***************************************************************************//** * @brief - * Send request for writing or reading the RAM of Message Object msgNum. + * Send a request for writing or reading RAM of the Message Object msgNum. * * @param[in] can - * Pointer to CAN peripheral register block. + * A pointer to the CAN peripheral register block. * * @param[in] interface * Indicate which Message Interface Register to use. * * @param[in] msgNum - * Message number of the Message Object, [1 - 32]. + * A message number of the Message Object, [1 - 32]. * * @param[in] wait * If true, wait for the end of the transfer between the MIRx registers and - * the RAM to exit. If false, exit immediately, the transfer can still be + * the RAM to exit. If false, exit immediately. The transfer can still be * in progress. ******************************************************************************/ void CAN_SendRequest(CAN_TypeDef *can, @@ -892,13 +911,13 @@ void CAN_SendRequest(CAN_TypeDef *can, { CAN_MIR_TypeDef * mir = &can->MIR[interface]; - /* Make sure msgNum is in the correct range */ + /* Make sure msgNum is in correct range. */ EFM_ASSERT((msgNum > 0) && (msgNum <= 32)); - /* Make sure the MIRx registers aren't busy */ + /* Make sure the MIRx registers aren't busy. */ CAN_ReadyWait(can, interface); - /* Write msgNum to the CMDREQ register */ + /* Write msgNum to the CMDREQ register. */ mir->CMDREQ = msgNum << _CAN_MIR_CMDREQ_MSGNUM_SHIFT; if (wait) { diff --git a/targets/targets.json b/targets/targets.json index 278cd63b03f..baac3eaf55b 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -6237,6 +6237,7 @@ "device_name": "EFM32GG11B820F2048GL192", "device_has": [ "ANALOGIN", + "CAN", "CRC", "EMAC", "I2C", From f29dffa7d7b6e3b52a9ac0db1641433ed0995ba5 Mon Sep 17 00:00:00 2001 From: petroborys Date: Fri, 26 Apr 2019 07:17:02 +0000 Subject: [PATCH 2/3] Add can_api.c for efm32: wrap in presence of the base peripheral --- .../TARGET_EFM32/PeripheralNames.h | 6 +++- .../TARGET_EFM32GG11/can_device.h | 32 ------------------- .../TARGET_EFM32/can_api.c | 29 ++++++++++++++--- 3 files changed, 30 insertions(+), 37 deletions(-) delete mode 100644 targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG11/can_device.h diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/PeripheralNames.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/PeripheralNames.h index 4e9622cfa13..c055253c0df 100644 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/PeripheralNames.h +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/PeripheralNames.h @@ -138,8 +138,12 @@ typedef enum { #if DEVICE_CAN typedef enum { +#ifdef CAN0_BASE CAN_0 = (int)CAN0_BASE, - CAN_1 = (int)CAN1_BASE +#endif +#ifdef CAN1_BASE + CAN_1 = (int)CAN1_BASE, +#endif } CANName; #endif diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG11/can_device.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG11/can_device.h deleted file mode 100644 index ddd82d6776d..00000000000 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG11/can_device.h +++ /dev/null @@ -1,32 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2017 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef MBED_CAN_DEVICE_H -#define MBED_CAN_DEVICE_H - -#include "cmsis.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if DEVICE_CAN - -#define CAN_COUNT 2 // Number of CAN peripherals - - -#endif // DEVICE_CAN - -#endif diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/can_api.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/can_api.c index 79ee7cf4327..55be7ed71dc 100644 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/can_api.c +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/can_api.c @@ -1,5 +1,5 @@ /* mbed Microcontroller Library - * Copyright (c) 2006-2017 ARM Limited + * Copyright (c) 2019 ToolSense * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,6 @@ #include "pinmap_function.h" #include "PeripheralPins.h" #include "mbed_assert.h" -#include "can_device.h" #include "em_cmu.h" #include "em_can.h" @@ -48,12 +47,16 @@ void can_init_freq(can_t *obj, PinName rd, PinName td, int hz) CMU_Clock_TypeDef cmuClock_number; switch ((CANName)obj->instance) { +#ifdef CAN0 case CAN_0: cmuClock_number = cmuClock_CAN0; break; +#endif +#ifdef CAN1 case CAN_1: cmuClock_number = cmuClock_CAN1; break; +#endif } MBED_ASSERT((unsigned int)rd != NC); @@ -106,12 +109,16 @@ void can_irq_init(can_t *obj, can_irq_handler handler, uint32_t id) int index = 0; switch ((CANName)obj->instance) { +#ifdef CAN0 case CAN_0: index = 0; break; +#endif +#ifdef CAN1 case CAN_1: index = 1; break; +#endif } irq_handler = handler; @@ -124,12 +131,16 @@ void can_irq_free(can_t *obj) CAN_MessageIntClear(obj->instance, 0xFFFFFFFF); switch ((CANName)obj->instance) { +#ifdef CAN0 case CAN_0: NVIC_DisableIRQ(CAN0_IRQn); break; +#endif +#ifdef CAN1 case CAN_1: NVIC_DisableIRQ(CAN1_IRQn); break; +#endif } } @@ -149,6 +160,7 @@ int can_frequency(can_t *obj, int f) CanInit.phaseBufferSegment1, CanInit.phaseBufferSegment2, CanInit.synchronisationJumpWidth); + return 0; } int can_write(can_t *obj, CAN_Message msg, int cc) @@ -179,6 +191,8 @@ int can_read(can_t *obj, CAN_Message *msg, int handle) if (CAN_HasNewdata(obj->instance)) { receiver.msgNum = 2; + receiver.extended = false; + receiver.extendedMask = false; CAN_ReadMessage(obj->instance, CAN_RX_IF, &receiver); @@ -259,14 +273,18 @@ void can_irq_set(can_t *obj, CanIrqType type, uint32_t enable) } switch ((CANName)obj->instance) { +#ifdef CAN0 case CAN_0: NVIC_SetVector(CAN0_IRQn, CAN0_IRQHandler); NVIC_EnableIRQ(CAN0_IRQn); break; +#endif +#ifdef CAN1 case CAN_1: NVIC_SetVector(CAN1_IRQn, CAN1_IRQHandler); NVIC_EnableIRQ(CAN1_IRQn); break; +#endif } } @@ -286,16 +304,19 @@ static void can_irq(CANName name, int id) } } +#ifdef CAN0 void CAN0_IRQHandler(void) { can_irq(CAN_0, 0); } +#endif +#ifdef CAN1 void CAN1_IRQHandler(void) { can_irq(CAN_1, 1); } - +#endif const PinMap *can_rd_pinmap() { @@ -307,4 +328,4 @@ const PinMap *can_td_pinmap() return PinMap_CAN_RX; } -#endif // DEVICE_CAN +#endif //DEVICE_CAN From b635c024a40c54bb2ae978eecde02b8d9364a0d0 Mon Sep 17 00:00:00 2001 From: petroborys Date: Tue, 30 Apr 2019 10:33:08 +0000 Subject: [PATCH 3/3] Add can_api.c for efm32:review build-IAR --- targets/TARGET_Silicon_Labs/TARGET_EFM32/can_api.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/can_api.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/can_api.c index 55be7ed71dc..0e847400de9 100644 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/can_api.c +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/can_api.c @@ -275,13 +275,13 @@ void can_irq_set(can_t *obj, CanIrqType type, uint32_t enable) switch ((CANName)obj->instance) { #ifdef CAN0 case CAN_0: - NVIC_SetVector(CAN0_IRQn, CAN0_IRQHandler); + NVIC_SetVector(CAN0_IRQn, (uint32_t)CAN0_IRQHandler); NVIC_EnableIRQ(CAN0_IRQn); break; #endif #ifdef CAN1 case CAN_1: - NVIC_SetVector(CAN1_IRQn, CAN1_IRQHandler); + NVIC_SetVector(CAN1_IRQn, (uint32_t)CAN1_IRQHandler); NVIC_EnableIRQ(CAN1_IRQn); break; #endif