diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/crc_api.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/crc_api.c new file mode 100644 index 0000000000..4e7c71de0c --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/crc_api.c @@ -0,0 +1,147 @@ +/***************************************************************************//** + * @file crc_api.c + ******************************************************************************* + * @section License + * (C) Copyright 2018 Silicon Labs, http://www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 "device.h" +#include "clocking.h" +#include + +#if DEVICE_CRC +#include "mbed_assert.h" +#include "crc_api.h" +#include "em_cmu.h" + +#if defined(GPCRC_PRESENT) && (GPCRC_COUNT > 0) +#include "em_gpcrc.h" + +static bool revOutput = false; +static uint32_t final_xor; + +bool hal_crc_is_supported(const crc_mbed_config_t *config) +{ + //GPCRC supports any 16-bit poly, but only the CCITT 32-bit poly + if (config == NULL) { + return false; + } + + if (config->width == 16) { + return true; + } else if (config->width == 32) { + if (config->polynomial == POLY_32BIT_ANSI) { + return true; + } else { + return false; + } + } else { + return false; + } +} + +void hal_crc_compute_partial_start(const crc_mbed_config_t *config) +{ + if (!hal_crc_is_supported(config)) { + return; + } + + CMU_ClockEnable(cmuClock_GPCRC, true); + GPCRC_Reset(GPCRC); + + GPCRC_Init_TypeDef crc_init; + + crc_init.autoInit = false; + crc_init.enable = true; + crc_init.crcPoly = config->polynomial; + + // GPCRC operates on bit-reversed inputs and outputs vs the standard + // defined by the mbed API. Emlib does the reversal on the poly, but + // not on the initial value. + if (config->width == 16) { + crc_init.initValue = __RBIT(config->initial_xor) >> 16; + } else { + crc_init.initValue = __RBIT(config->initial_xor); + } + + // GPCRC operates on bit-reversed inputs and outputs vs the standard + // defined by the mbed API, so reflect_in/out needs to be negated. + if (config->reflect_in) { + crc_init.reverseByteOrder = false; + crc_init.reverseBits = false; + } else { + crc_init.reverseByteOrder = true; + crc_init.reverseBits = true; + } + + // Disable byte mode to be able to run a faster U32 input version + crc_init.enableByteMode = false; + + // GPCRC does not support hardware output bit-reversal, nor finalisation. + // Since the mbed API does not pass the config struct when fetching the + // CRC calculation result, we need to keep track of these locally. + revOutput = config->reflect_out; + final_xor = config->final_xor; + + GPCRC_Init(GPCRC, &crc_init); + GPCRC_Start(GPCRC); +} + +void hal_crc_compute_partial(const uint8_t *data, const size_t size) +{ + if (data == NULL || size <= 0) { + return; + } + + if (((uint32_t)data & 0x3) != 0 || size < 4) { + // Unaligned or very small input, run a bytewise CRC + for (size_t i = 0; i < size; i++) { + GPCRC_InputU8(GPCRC, data[i]); + } + } else { + // Aligned input, run 32-bit inputs as long as possible to make go faster. + size_t i = 0; + for (; i < (size & (~0x3)); i+=4) { + GPCRC_InputU32(GPCRC, *((uint32_t*)(&data[i]))); + } + for (; i < size; i++) { + GPCRC_InputU8(GPCRC, data[i]); + } + } +} + +uint32_t hal_crc_get_result(void) +{ + uint32_t result; + + // GPCRC operates on bit-reversed inputs and outputs vs the standard + // defined by the mbed API. + if (!revOutput) { + result = GPCRC_DataReadBitReversed(GPCRC); + } else { + result = GPCRC_DataRead(GPCRC); + } + + GPCRC_Enable(GPCRC, false); + + return result ^ final_xor; +} + +#endif //GPCRC_PRESENT +#endif //DEVICE_CRC diff --git a/targets/targets.json b/targets/targets.json index 8d2d6c9dcc..7a13918744 100755 --- a/targets/targets.json +++ b/targets/targets.json @@ -3255,7 +3255,7 @@ }, "EFM32PG_STK3401": { "inherits": ["EFM32PG1B100F256GM32"], - "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "FLASH"], + "device_has": ["ANALOGIN", "CRC", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "FLASH"], "forced_reset_timeout": 2, "config": { "hf_clock_src": { @@ -3318,7 +3318,7 @@ }, "EFR32MG1_BRD4150": { "inherits": ["EFR32MG1P132F256GM48"], - "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "FLASH"], + "device_has": ["ANALOGIN", "CRC", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "FLASH"], "forced_reset_timeout": 2, "config": { "hf_clock_src": { @@ -3361,7 +3361,7 @@ }, "TB_SENSE_1": { "inherits": ["EFR32MG1P233F256GM48"], - "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "FLASH"], + "device_has": ["ANALOGIN", "CRC", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "FLASH"], "forced_reset_timeout": 5, "config": { "hf_clock_src": { @@ -3409,7 +3409,7 @@ }, "EFM32PG12_STK3402": { "inherits": ["EFM32PG12B500F1024GL125"], - "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "TRNG", "FLASH"], + "device_has": ["ANALOGIN", "CRC", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "TRNG", "FLASH"], "forced_reset_timeout": 2, "config": { "hf_clock_src": { @@ -3463,7 +3463,7 @@ "TB_SENSE_12": { "inherits": ["EFR32MG12P332F1024GL125"], "device_name": "EFR32MG12P332F1024GL125", - "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "TRNG", "FLASH"], + "device_has": ["ANALOGIN", "CRC", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "TRNG", "FLASH"], "forced_reset_timeout": 5, "config": { "hf_clock_src": { @@ -3512,7 +3512,7 @@ "EFM32GG11_STK3701": { "inherits": ["EFM32GG11B820F2048GL192"], "device_name": "EFM32GG11B820F2048GL192", - "device_has": ["ANALOGIN", "EMAC", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "TRNG", "FLASH"], + "device_has": ["ANALOGIN", "CRC", "EMAC", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "TRNG", "FLASH"], "forced_reset_timeout": 5, "config": { "hf_clock_src": {