-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Conversation
Do we need feature branch for this? it is against master at the moment |
I don't think it needs a feature branch. The software implementation is already in master, not many boards support Hardware CRC so the reference implementations cover most of them. And, it's not mandatory so if it's not implemented it will fall back on the software implementation anyway. |
@bulislaw Please confirm |
drivers/MbedCRC.h
Outdated
@@ -247,6 +262,7 @@ class MbedCRC | |||
bool _reflect_data; | |||
bool _reflect_remainder; | |||
uint32_t *_crc_table; | |||
crc_mode mode_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mode_
-> _mode
#include <stdbool.h> | ||
#include <stddef.h> | ||
#include <stdint.h> | ||
|
There was a problem hiding this comment.
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)
hal/crc_api.h
Outdated
* from two different contexts may lead to configurations being overwrite and | ||
* results being lost. | ||
* | ||
* \param polynomial CRC Polynomial. Example polynomial: 0x1021 = x^12+x^5+1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Link the enum.
@@ -0,0 +1,117 @@ | |||
#ifndef MBED_CRC_HAL_API_H |
There was a problem hiding this comment.
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.
} | ||
case POLY_8BIT_CCITT: | ||
{ | ||
width = kCrcBits16; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why width
is set to 16-bits if 8-bit CRC is requested?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are only two options, 16 and 32 bit, they correspond to the hardware returning the data from the HI-LO data registers for 32 bit, or LO data register for 16 bit. Any CRC's less than 16 bits will be returned in the LO register only as a 16 bit value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If hardware can handle only 16 or 32 bits CRC, then POLY_8BIT_CCITT
, POLY_7BIT_SD
polynomials should be not supported by this platform.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are supported. The result of the CRC calculation is stored in two 16 bit data registers in the CRC module. For CRCs less than 16-bits, only one 16-bit register is used, the other register may contain junk. Setting the width to 16-bit will return only the 16-bit register, which will contain the 7/8 bit result of the calculation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I'm missing something, but according to K64F reference manual:
The cyclic redundancy check (CRC) module generates 16/32-bit CRC code for error
detection.
It looks like currently POLY_8BIT_CCITT
and POLY_7BIT_SD
generates 16 bit CRC. We expect to have 8/7 bit CRC. config.crcBits
is set in both cases to kCrcBits16
(and on K64F platform we don't have definitions for 7/8 bits CRC). Only different polynomials are used in each case.
Please look at the following test:
uint32_t crc = 0;
const uint8_t test_data[] = "123456789";
hal_crc_compute_partial_start(POLY_8BIT_CCITT);
hal_crc_compute_partial((uint8_t*) test_data, strlen((const char*)test_data));
crc = hal_crc_get_result();
printf("Result: 0x%X \n", crc);
printf("Expected: 0x%X \n", 0xF4);
output:
Result: 0xEF6F <--- 16 bit result
Expected: 0xF4
I took expected result (0xF4) from `tests-mbed_drivers-crc`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, you're correct, I'm wrong, I thought there was another option for the polynomial width. I'll remove them from the code.
* \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); |
There was a problem hiding this comment.
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
case POLY_16BIT_CCITT: | ||
case POLY_16BIT_IBM: | ||
case POLY_32BIT_ANSI: | ||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
K64F supports only specified polynomials or any polynomial with width 16/32?
If we have hal API to set configs, user can select any polynomial and not just above three.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It supports any 16-bit or 32-bit polynomial, but to keep the API as simple as possible across all platforms it was decided to only support the polynomials named in the enum.
break; | ||
} | ||
default: | ||
MBED_ASSERT("Configuring Mbed CRC with unsupported polynomial"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Provide an option to set these configs and not ASSERT, it should be user configurable to have 16BIT_CCIIT but seed as Zero. I am sure it will work perfectly fine with HW.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above, it was decided to only support the named subset of polynomials in the enum which define the reflection/seed settings to keep the configuration as simple as possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can overload functions to set those parameters. I don;t think sticking to only specified polynomials make sense for HW. In case of software we need to add multiple tables for each polynomial which is not the case in HW.
Also with the same polynomial even SW CRC gives option to have different seed / reflection settings. How are you planning to support this constructor https://github.com/ARMmbed/mbed-os/blob/master/drivers/MbedCRC.h#L127
Also I have strong use case for this requirement, SD driver uses standard CCITT 16-bit but with seed value of 0. https://github.com/ARMmbed/sd-driver/blob/master/SDBlockDevice.cpp#L251
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don;t think sticking to only specified polynomials make sense for HW. - Unless HW supports only those few
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don;t think sticking to only specified polynomials make sense for HW
I don't either. But then, the only platforms you can reasonably set a polynomial on is K64F and STM(3 series).
How are you planning to support this constructor
By disabling the hardware mode when not using the default constructor.
If there's a use case for additional configuration, then it should be considered. @bulislaw
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CRC support in HW is rather modest. I don't really like the idea of complicating the API for K64F only for CRC polynomials that are not a very standard ones. Where the HW support actually matters is when we need to calculate the checksum repeatedly and fast eg network packets, bootloader maybe, but that should be using standard polynomials.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bulislaw - Polynomials supported in software CRC are not the only standard ones. Please see the list on Uncyclo "https://en.wikipedia.org/wiki/Cyclic_redundancy_check" for list.
|
||
void hal_crc_compute_partial(const uint8_t *data, const size_t size) | ||
{ | ||
CRC_WriteData(CRC0, data, size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to add robust checks against null pointer and 0 size and add the following information in the requirements section:
Function hal_crc_compute_partial() does nothing if pointer to buffer is undefined (NULL) or data length is equal to 0
.
On different platforms data size equal to 0 might have different consequences, so we can handle such case and simply return without any action.
@scartmell-arm Please do not edit the structure of the PR body! I have put it back to how it should be. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You defined a subset of what the standard supports: you don't include seed as a parameter, yet you also do not even use the same seed as managed boot loader mode for CRCITT32: 0.
Support the seed parameter.
Also I do not see hardware initialization functions called in K64F implementation. mbed-os/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/drivers/fsl_crc.c Line 195 in 920db8e
How are we planning to support init/deinit? |
|
hal/crc_api.h
Outdated
@@ -35,6 +35,19 @@ typedef enum crc_polynomial { | |||
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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that conception has changed. This change has massive impact on my test, so please provide requirements for testing.
I have also few questions, so I can start re-factoring my test.
Do we assume now that CRC platforms must support all of the listed options?
Why CRC width is not specified in crc_mbed_config
(we can have different CRC width for the same polynomial)?
Does conception with predefined typical polynomials is eventually abandoned?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we assume now that CRC platforms must support all of the listed options?
I think yes? Some of them can be handled manually like final_xor by writing it to the module before returning the value, but I believe reflect_in/out/initial_seed should be supported as options.
Why CRC width is not specified in crc_mbed_config (we can have different CRC width for the same polynomial)?
As far as I can tell the width of the CRC polynomial can be derived from the polynomial that's passed into the module, the largest polynomial that is set defines the width, at least for all the ones I've seen. I suppose an additional check needs to be added to the K64F implementation to ensure that either bit-31 is set indicating 32-bit polynomial, or that bit-15 is the highest bit set indicating a 16-bit one.
Does conception with predefined typical polynomials is eventually abandoned?
Yeah, it seemed to be more of an indicator for which polynomials have table support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the answers. I have two more questions:
- Do we still limit the number of supported polynomials to ones provided in
crc_polynomial_t
enum with additional config options (initial_xor, final_xor, reflect_in, reflect_out). - Why initial value config option is not available?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still limit the number of supported polynomials to ones provided in crc_polynomial_t enum with additional config options (initial_xor, final_xor, reflect_in, reflect_out).
No, any polynomial is now supported if the hardware allows it.
Why initial value config option is not available?
This is the same as an initial_xor? Most platforms that defines that option just uses it as an initial value in the hardware.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the same as an initial_xor?
Looks like it is :-) Thanks.
Where are the greentea HAL tests to verify correct integration with hw platform? If this feature is going to master, it's assumed will be complete, therefore tests have to be there. |
if (config == NULL) | ||
return false; | ||
|
||
if ((config->polynomial & 0x80008000) == 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It look like this check is to return false in case when CRC size is different than CRC16 or CRC32 - only these sizes can be handled by K64F hardware.
Please check the predefined polynomial values:
POLY_16BIT_CCITT = 0x1021
POLY_32BIT_ANSI = 0x04C11DB7
In both cases hal_crc_is_supported
function will return false
. I still suggest to add CRC size field into crc_mbed_config
structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I somehow overlooked those, I suppose there isn't a reasonable way to handle this other than specifying the width so I'll add the config.
platform_config.seed = config->initial_xor; | ||
platform_config.reflectIn = config->reflect_in; | ||
platform_config.reflectOut = config->reflect_out; | ||
platform_config.complementChecksum = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If given final_xor
config value is equal to all ones
(e.q. 0xFFFF_FFFF for 32-bit CRC), then platform_config.complementChecksum
should be set to true
.
If given final_xor
config value is 0, then platform_config.complementChecksum
should be set to false
.
If given final_xor
config value is different than both mentioned values, then platform_config.complementChecksum
should be set to false
, software xor
operation should be performed on the hardware result and the result of the operation should be returned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah okay, I assumed it wasn't supported in the hardware but that will have the same effect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Complement checksum is different name for final XOR. Its same parameter but different hardware modules accept either true or full value. It should not be separate argument from HAL.
*/ | ||
typedef enum crc_polynomial { | ||
POLY_OTHER = 0, | ||
POLY_8BIT_CCITT = 0x07, // x8+x2+x+1 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
hal/crc_api.h
Outdated
} crc_polynomial_t; | ||
|
||
typedef struct crc_mbed_config { | ||
/// CRC Polynomial. Example polynomial: 0x21 = 0010_0011 = x^5+x+1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to have docs, but these should be done as /**< text > */
as some others in hal folder
@@ -0,0 +1,65 @@ | |||
#include "crc_api.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing license header on top
bool hal_crc_is_supported(const crc_mbed_config_t* config) | ||
{ | ||
if (config == NULL) | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please review coding style (hoewever targets/ are not checked), there are others that shall be fixed
if (config == NULL) | ||
return; | ||
|
||
width = ((config->polynomial & 0xFFFF0000U) != 0) ? kCrcBits32 : kCrcBits16; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this extra intelligence here? User passes the width, and it is available as part of config->width. We can simply use that.
hal/crc_api.h
Outdated
* | ||
* \param polynomial CRC Polynomial. Example polynomial: 0x1021 = x^12+x^5+1 | ||
*/ | ||
void hal_crc_compute_partial_start(const crc_mbed_config_t* polynomial); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HAL API has first parameter this pointer (*obj), not needed for this API? This is hardware related functionality, thus will be needed to have access to their SDK or internal registers (K64F below has CRC0).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand. The K64F implementation uses CRC0 as the base pointer for the CRC module because all the CRC functions use offsets from that pointer for accessing specific CRC registers, but not all platforms require anything like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point was that all HAL API have defined as first parameter "this" pointer. My question is - why these new functions do not have it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need it, there is no platforms with multiple CRC engines (no real need for that) and there's no state/context that we need to be maintained.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some HW CRC modules do store intermediate CRC state, which might be an issue when using CRC HW from different threads.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we want to support multiple hardware CRC calculations being run concurrently, a different thread shouldn't initialize/use the module until the final value has been read from it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Driver is providing the locking, HAL specification explicitly mentions that it's up to the user to ensure access safety. HAL is designed for simplicity, the drivers add the level of complexity necessary for safe usage for the user.
@scartmell-arm let's try to merge it ASAP and add extra platforms after that. @theotherjimmy @0xc0170 @deepikabhavnani we are getting close to code freeze can you guys rereview the code and accept it if your comments were resolved. |
Copy edit file, mostly for American spelling and consistent tense across files.
/morph build |
Build : SUCCESSBuild number : 2141 Triggering tests/morph test |
Test : SUCCESSBuild number : 1935 |
Exporter Build : FAILUREBuild number : 1767 |
CI nodes want to leave for the weekend a bit too soon... |
Exporter Build : SUCCESSBuild number : 1770 |
This is now almost ready, but HAL #7009 should land first . Preceding PR label set |
Swapping this PR's priority with #7009. 7009 will need updates before it becomes ready to merge, whereas this is already ready to go. |
Description
Define the HAL API header for the Hardware CRC module. This set of functions
allows hardware acceleration of a subset of CRC algorithms for supported
platforms by providing access to the hardware CRC module of certain platforms.
Status
NOT READY
Tasks
[X] Integrate the HAL API into the Platform API
[ ] Add Reference Implementation for STM32X
[X] Add Reference Implementation for K64F
[ ] Add Reference Implementation for Maxim 32600
Pull request type
[ ] Fix
[ ] Refactor
[ ] New target
[X] Feature
[ ] Breaking change
@bulislaw @deepikabhavnani