Skip to content

Add Hardware CRC HAL API specification #6708

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from May 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doxyfile_options
Original file line number Diff line number Diff line change
Expand Up @@ -2069,6 +2069,7 @@ PREDEFINED = DOXYGEN_ONLY \
DEVICE_ANALOGIN \
DEVICE_ANALOGOUT \
DEVICE_CAN \
DEVICE_CRC \
DEVICE_ETHERNET \
DEVICE_EMAC \
DEVICE_ETH \
Expand Down
2 changes: 1 addition & 1 deletion doxygen_options.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"SEARCH_INCLUDES": "YES",
"INCLUDE_PATH": "",
"INCLUDE_FILE_PATTERNS": "",
"PREDEFINED": "DOXYGEN_ONLY DEVICE_ANALOGIN DEVICE_ANALOGOUT DEVICE_CAN DEVICE_ETHERNET DEVICE_EMAC DEVICE_FLASH DEVICE_I2C DEVICE_I2CSLAVE DEVICE_I2C_ASYNCH DEVICE_INTERRUPTIN DEVICE_ITM DEVICE_LOWPOWERTIMER DEVICE_PORTIN DEVICE_PORTINOUT DEVICE_PORTOUT DEVICE_PWMOUT DEVICE_RTC DEVICE_TRNG DEVICE_SERIAL DEVICE_SERIAL_ASYNCH DEVICE_SERIAL_FC DEVICE_SLEEP DEVICE_SPI DEVICE_SPI_ASYNCH DEVICE_SPISLAVE DEVICE_STORAGE \"MBED_DEPRECATED_SINCE(f, g)=\" \"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=\" \"MBED_DEPRECATED(s)=\"",
"PREDEFINED": "DOXYGEN_ONLY DEVICE_ANALOGIN DEVICE_ANALOGOUT DEVICE_CAN DEVICE_CRC DEVICE_ETHERNET DEVICE_EMAC DEVICE_FLASH DEVICE_I2C DEVICE_I2CSLAVE DEVICE_I2C_ASYNCH DEVICE_INTERRUPTIN DEVICE_ITM DEVICE_LOWPOWERTIMER DEVICE_PORTIN DEVICE_PORTINOUT DEVICE_PORTOUT DEVICE_PWMOUT DEVICE_RTC DEVICE_TRNG DEVICE_SERIAL DEVICE_SERIAL_ASYNCH DEVICE_SERIAL_FC DEVICE_SLEEP DEVICE_SPI DEVICE_SPI_ASYNCH DEVICE_SPISLAVE DEVICE_STORAGE \"MBED_DEPRECATED_SINCE(f, g)=\" \"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=\" \"MBED_DEPRECATED(s)=\"",
"EXPAND_AS_DEFINED": "",
"SKIP_FUNCTION_MACROS": "NO",
"STRIP_CODE_COMMENTS": "NO",
Expand Down
82 changes: 61 additions & 21 deletions drivers/MbedCRC.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
#ifndef MBED_CRC_API_H
#define MBED_CRC_API_H

#include <stdint.h>
#include "drivers/TableCRC.h"
#include "hal/crc_api.h"
#include "platform/mbed_assert.h"

/* This is invalid warning from the compiler for below section of code
Expand All @@ -38,19 +38,6 @@ namespace mbed {
/** \addtogroup drivers */
/** @{*/

/** CRC Polynomial value
*
* Different polynomial values supported
*/
typedef enum crc_polynomial {
POLY_OTHER = 0,
POLY_8BIT_CCITT = 0x07, // x8+x2+x+1
POLY_7BIT_SD = 0x9, // x7+x3+1;
POLY_16BIT_CCITT = 0x1021, // x16+x12+x5+1
POLY_16BIT_IBM = 0x8005, // x16+x15+x2+1
POLY_32BIT_ANSI = 0x04C11DB7, // x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1
} crc_polynomial_t;

/** CRC object provides CRC generation through hardware/software
*
* ROM polynomial tables for supported polynomials (:: crc_polynomial_t) will be used for
Expand Down Expand Up @@ -106,6 +93,9 @@ typedef enum crc_polynomial {
template <uint32_t polynomial=POLY_32BIT_ANSI, uint8_t width=32>
class MbedCRC
{
public:
enum CrcMode { HARDWARE = 0, TABLE, BITWISE };

public:
typedef uint64_t crc_data_size_t;

Expand Down Expand Up @@ -178,13 +168,21 @@ class MbedCRC
*/
int32_t compute_partial(void *buffer, crc_data_size_t size, uint32_t *crc)
{
if (NULL == _crc_table) {
// Compute bitwise CRC
return bitwise_compute_partial(buffer, size, crc);
} else {
// Table CRC
return table_compute_partial(buffer, size, crc);
switch (_mode)
{
case HARDWARE:
#ifdef DEVICE_CRC
hal_crc_compute_partial((uint8_t *)buffer, size);
#endif // DEVICE_CRC
*crc = 0;
return 0;
case TABLE:
return table_compute_partial(buffer, size, crc);
case BITWISE:
return bitwise_compute_partial(buffer, size, crc);
}

return -1;
}

/** Compute partial start, indicate start of partial computation
Expand All @@ -200,6 +198,21 @@ class MbedCRC
int32_t compute_partial_start(uint32_t *crc)
{
MBED_ASSERT(crc != NULL);

#ifdef DEVICE_CRC
if (_mode == HARDWARE) {
crc_mbed_config_t config;
config.polynomial = polynomial;
config.width = width;
config.initial_xor = _initial_value;
config.final_xor = _final_xor;
config.reflect_in = _reflect_data;
config.reflect_out = _reflect_remainder;

hal_crc_compute_partial_start(&config);
}
#endif // DEVICE_CRC

*crc = _initial_value;
return 0;
}
Expand All @@ -215,6 +228,16 @@ class MbedCRC
int32_t compute_partial_stop(uint32_t *crc)
{
MBED_ASSERT(crc != NULL);

if (_mode == HARDWARE) {
#ifdef DEVICE_CRC
*crc = hal_crc_get_result();
return 0;
#else
return -1;
#endif
}

uint32_t p_crc = *crc;
if ((width < 8) && (NULL == _crc_table)) {
p_crc = (uint32_t)(p_crc << (8 - width));
Expand Down Expand Up @@ -247,6 +270,7 @@ class MbedCRC
bool _reflect_data;
bool _reflect_remainder;
uint32_t *_crc_table;
CrcMode _mode;

/** Get the current CRC data size
*
Expand Down Expand Up @@ -408,9 +432,25 @@ class MbedCRC
/** Constructor init called from all specialized cases of constructor
* Note: All construtor common code should be in this function.
*/
void mbed_crc_ctor(void) const
void mbed_crc_ctor(void)
{
MBED_STATIC_ASSERT(width <= 32, "Max 32-bit CRC supported");

_mode = (_crc_table != NULL) ? TABLE : BITWISE;

#ifdef DEVICE_CRC
crc_mbed_config_t config;
config.polynomial = polynomial;
config.width = width;
config.initial_xor = _initial_value;
config.final_xor = _final_xor;
config.reflect_in = _reflect_data;
config.reflect_out = _reflect_remainder;

if (hal_crc_is_supported(&config)) {
_mode = HARDWARE;
}
#endif
}
};

Expand Down
189 changes: 189 additions & 0 deletions hal/crc_api.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/** \addtogroup hal */
/** @{*/
/* mbed Microcontroller Library
* Copyright (c) 2018 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_CRC_HAL_API_H
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the header file needs to be updated to be consistent with other HAL headers.
Doxygen groups, requirements, undefined behavior, potential bugs sections should be added. Example can be found here:
https://github.com/ARMmbed/mbed-os/blob/feature-hal-spec-ticker/hal/us_ticker_api.h

I have also created some example update with the requirements for testing, which can be found here:
https://github.com/mprse/mbed-os/blob/scartmell-arm_crc_tests/hal/crc_api.h

The requirements were created based on provided function descriptions, so probably they need to be extended.
Please fill free to use this example in order to update the header file.

#define MBED_CRC_HAL_API_H

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with other HAL APIs we need some intro (have a look at ticker/rtc/sleep)

/** CRC Polynomial value
*
* Different polynomial values supported
*/
typedef enum crc_polynomial {
POLY_OTHER = 0,
POLY_8BIT_CCITT = 0x07, // x8+x2+x+1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why x8 has been added in the comment?
0x07 == 0000 0111b => x^2 + x^1 + x^0 = x^2 + x + 1

Next definitions also have this issue.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hrm, it's technically correct, but misleading. The top bit is excluded from the polynomial. It's defined with the x^8 here. https://en.wikipedia.org/wiki/Cyclic_redundancy_check#Polynomial_representations_of_cyclic_redundancy_checks

POLY_7BIT_SD = 0x9, // x7+x3+1;
POLY_16BIT_CCITT = 0x1021, // x16+x12+x5+1
POLY_16BIT_IBM = 0x8005, // x16+x15+x2+1
POLY_32BIT_ANSI = 0x04C11DB7, // x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1
} crc_polynomial_t;

typedef struct crc_mbed_config {
/** CRC Polynomial. Example polynomial: 0x21 = 0010_0011 = x^5+x+1 */
uint32_t polynomial;
/** CRC Bit Width */
uint32_t width;
/** Initial seed value for the computation. */
uint32_t initial_xor;
/** Final xor value for the computation. */
uint32_t final_xor;
/** Reflect bits on input. */
bool reflect_in;
/** Reflect bits in final result before returning. */
bool reflect_out;
} crc_mbed_config_t;

#ifdef DEVICE_CRC

#ifdef __cplusplus
extern "C" {
#endif

/**
* \defgroup hal_crc Hardware CRC
*
* The Hardware CRC HAL API provides a low-level interface to the Hardware CRC
* module of a target platform.
*
* @{
*/

/** Determine if the current platform supports hardware CRC for given polynomial
*
* The purpose of this function is to inform the CRC Platform API whether the
* current platform has a hardware CRC module and that it can support the
* requested polynomial.
*
* Supported polynomials are restricted to the named polynomials that can be
* constructed in the MbedCRC class, POLY_8BIT_CCITT, POLY_7BIT_SD,
* POLY_16BIT_CCITT, POLY_16BIT_IBM and POLY_32BIT_ANSI.
*
* The current platform must support the given polynomials default parameters
* in order to return a true response. These include: reflect in, reflect out,
* initial xor and final xor. For example, POLY_32BIT_ANSI requires an initial
* and final xor of 0xFFFFFFFF, and reflection of both input and output. If any
* of these settings cannot be configured, the polynomial is not supported.
*
* This function is thread safe; it safe to call from multiple contexts if
* required.
*
* \param config Contains CRC configuration parameters for initializing the
* hardware CRC module. For example, polynomial and initial seed
* values.
*
* \return True if running if the polynomial is supported, false if not.
*/
bool hal_crc_is_supported(const crc_mbed_config_t* config);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to inform here as well, that it is not thread safe.


/** Initialize the hardware CRC module with the given polynomial
*
* After calling this function, the CRC HAL module is ready to receive data
* using the hal_crc_compute_partial() function. The CRC module on the board
* is configured internally with the specified configuration and is ready
* to receive data.
*
* The platform configures itself based on the default configuration
* parameters of the input polynomial.
*
* This function must be called before calling hal_crc_compute_partial().
*
* This function must be called with a valid polynomial supported by the
* platform. The polynomial must be checked for support using the
* hal_crc_is_supported() function.
*
* Calling hal_crc_compute_partial_start() multiple times without finalizing the
* CRC calculation with hal_crc_get_result() overrides the current
* configuration and state, and the intermediate result of the computation is
* lost.
*
* This function is not thread safe. A CRC calculation must not be started from
* two different threads or contexts at the same time; calling this function
* from two different contexts may lead to configurations being overwritten and
* results being lost.
*
* \param config Contains CRC configuration parameters for initializing the
* hardware CRC module. For example, polynomial and initial seed
* values.
*/
void hal_crc_compute_partial_start(const crc_mbed_config_t* config);

/** Writes data to the current CRC module.
*
* Writes input data buffer bytes to the CRC data register. The CRC module
* must interpret the data as an array of bytes.
*
* The final transformations are not applied to the data; the CRC module must
* retain the intermediate result so that additional calls to this function
* can be made, appending the additional data to the calculation.
*
* To obtain the final result of the CRC calculation, hal_crc_get_result() is
* called to apply the final transformations to the data.
*
* If the function is passed an undefined pointer, or the size of the buffer is
* specified to be 0, this function does nothing and returns.
*
* This function can be called multiple times in succession. This can be used
* to calculate the CRC result of streamed data.
*
* This function is not thread safe. There is only one instance of the CRC
* module active at a time. Calling this function from multiple contexts
* appends different data to the same, single instance of the module, which causes an
* erroneous value to be calculated.
*
* \param data Input data stream to be written into the CRC calculation
* \param size Size of the data stream in bytes
*/
void hal_crc_compute_partial(const uint8_t *data, const size_t size);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not get any failures from hardware? I believe return of computation should be non-zero and error codes should be propagated


/* Reads the checksum result from the CRC module.
*
* Reads the final checksum result for the final checksum value. The returned
* value is cast as an unsigned 32-bit integer. The actual size of the returned
* result depends on the polynomial used to configure the CRC module.
*
* Additional transformations that are used in the default configuration of the
* input polynomial are applied to the result before it is returned from this
* function. These transformations include: the final xor being appended to the
* calculation, and the result being reflected if required.
*
* Calling this function multiple times is undefined. The first call to this
* function returns the final result of the CRC calculation. The return
* value on successive calls is undefined because the contents of the register after
* accessing them is platform-specific.
*
* This function is not thread safe. There is only one instance of the CRC
* module active at a time. Calling this function from multiple contexts may
* return incorrect data or affect the current state of the module.
*
* \return The final CRC checksum after the reflections and final calculations
* have been applied.
*/
uint32_t hal_crc_get_result(void);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of the CRC functions are thread safe, please indicate in this API as well


/**@}*/

#ifdef __cplusplus
};
#endif

#endif // DEVICE_CRC
#endif // MBED_CRC_HAL_API_H

/**@}*/
Loading