Skip to content

CRC driver stm32u5xx#63

Open
mihailinux wants to merge 8 commits into
masterfrom
stm32u5xx_crc
Open

CRC driver stm32u5xx#63
mihailinux wants to merge 8 commits into
masterfrom
stm32u5xx_crc

Conversation

@mihailinux

@mihailinux mihailinux commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Pull Request Overview

This pull request adds the initial draft for the CRC Driver for the STM32U5xx. AI was only used for researching the CRC32 Ethernet algorithm parameters. As an initial draft, it is subject to changes.

Testing Strategy

This pull request was tested by Clippy.

TODO or Help Wanted

This pull request still needs thorough testing.

Documentation Updated

  • Updated the relevant files in /docs, or no updates are required.

Formatting

  • Ran make prepush.

AI Use

  • The PR description details my use of AI in the production of the
    code in this PR, if any, and I have manually checked and
    personally certify the entire contents of this PR.

@github-actions github-actions Bot added the stm32 label Jul 8, 2026
@genan2003

Copy link
Copy Markdown

When this will be finished, please test it with an userspace application.

@genan2003

Copy link
Copy Markdown

Any updates on this?

@mihailinux

mihailinux commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator Author

I've just added the new commits, forgot to push them :( , implementing the CRC and linking it via the lib.rs and in the main.rs of the board.

I'll also append the userspace application down below, used for testing. It is built on top of the existing example found in the libtock-c applications for the CRC, but I have reworked it in order to not use the board's RNG, as it was previously not uploaded.

All test cases found in the test_cases.h run and compile, no worries on that part.

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <libtock-sync/peripherals/crc.h>
#include <libtock-sync/services/alarm.h>

struct test_case {
  libtock_crc_alg_t alg;
  uint32_t output;
  char* input;
};

#define CASE(alg, output, input) char input_##alg##_##output [] = input;
#include "test_cases.h"
#undef CASE

static struct test_case test_cases[] = {
#define CASE(alg, output, input) \
        { alg, output, input_##alg##_##output },
#include "test_cases.h"
#undef CASE
};

int n_test_cases = sizeof(test_cases) / sizeof(struct test_case);

int main(void) {
  int r;

  printf("[CRC Test] This app tests the CRC syscall interface\n");

  if (!libtocksync_crc_exists()) {
    printf("CRC driver does not exist\n");
    exit(1);
  }

  while (1) {
    for (int test_index = 0; test_index < n_test_cases; test_index++) {
      struct test_case* t = &test_cases[test_index];
      uint32_t result;
      if ((r = libtocksync_crc_compute((uint8_t*) t->input, strlen(t->input), t->alg, &result)) != RETURNCODE_SUCCESS) {
        printf("CRC compute failed: %s\n", tock_strrcode(r));
        exit(1);
      }

      printf("[Test] Case %2d: ", test_index);
      if (r == RETURNCODE_SUCCESS) {
        printf("result=%08" PRIx32 " ", result);
        if (result == t->output) {
          printf("(OK)");
        } else {
          printf("(Expected %08" PRIx32 ")", t->output);
        }
      } else {
        printf("failed with status %d\n", r);
      }
      printf("\n");
    }

    printf("\n");
    libtocksync_alarm_delay_ms(1000);
  }
}

There is however an issue I would like assistance with, the data register DR is 32 bit wide. In order to input data into it, I must abide by that size. The reference manual does however mention that the input may vary in length, but I am unsure of how to implement that in code.

At the moment, i just insert the data parsed byte by byte, as u32, into the DR. However, this ruins the CRC computation, as I just insert padded bytes instead of the entire message. How can I solve this, taking into consideration a varying length for the input?

The code for this resides in the input function of the CRC driver, which I will also insert down below.

fn input(
        &self,
        data: SubSliceMut<'static, u8>,
    ) -> Result<(), (ErrorCode, SubSliceMut<'static, u8>)> {
        debug!("CRC: input() called with {} bytes", data.len());

        if self.alg_state.get() == AlgSet::Uninitialised {
            return Err((ErrorCode::RESERVE, data));
        }

        if self.state.get() == State::Processing {
            return Err((ErrorCode::BUSY, data));
        }

        self.state.set(State::Processing);

        // wrote them as mut_slice and iter_mut first, realised that I only read them
        // so would not need it
        for &byte in data.as_slice().iter() {
            // should use set? or write
            self.registers.dr.set(byte as u32);
        }
        //reinterpret cast array de u32 uri

        debug!("CRC: Finished writing to DR, triggering deferred call");

        // pots and pans technology
        let mut consumed_data = data;
        let len = consumed_data.len();
        consumed_data.slice(len..len);

        self.buffer.set(consumed_data);
        self.request.set(Request::Input);
        self.deferred_call.set();

        Ok(())
    }

The for loop is what has been bugging me.

@mihailinux mihailinux changed the title CRC driver draft CRC driver STM32U5xx Jul 15, 2026
@mihailinux mihailinux changed the title CRC driver STM32U5xx CRC driver stm32u5xx Jul 15, 2026
@mihailinux

mihailinux commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator Author

The issue regarding the input has been solved, by creating a new memory reference to the base address, this time as an u8 ReadWrite, then setting the bytes to that address.

/// Address needed for writing inputs as u8, as the DR supports both read/write.
/// Reading is easily done, but the writing proved difficult, as
/// inserting data that is not a multiple of 32 bits should also be supported.
/// This solves this by defining a pointer that allows us to solve this.
const CRC_DR_BYTE: StaticRef<ReadWrite<u8>> =
    unsafe { StaticRef::new(0x50023000 as *const ReadWrite<u8>) };
// The DR registers requires 8-bit writes when inputting data.
// Writing the whole 32 bits causes incorrect results, so we cannot use the regular register.
// We need to read it as 32 bits at the end, to retrieve the CRC result.
        for &byte in data.as_slice().iter() {
            CRC_DR_BYTE.set(byte);
        }

This solves the problem of varying input lengths, as we do not pad the bytes as before, when we used byte as u32.

The inspiration for this was taken from the CRC implementation found in the C version of the STM's HAL, linked here. The function I am referencing is CRC_HANDLE_8.

mihailinux and others added 8 commits July 20, 2026 12:01
Signed-off-by: mihailinux <mihaigabrielbusiness@gmail.com>
Signed-off-by: mihailinux <mihaigabrielbusiness@gmail.com>
Signed-off-by: mihailinux <mihaigabrielbusiness@gmail.com>
Signed-off-by: mihailinux <mihaigabrielbusiness@gmail.com>
Signed-off-by: mihailinux <mihaigabrielbusiness@gmail.com>
Signed-off-by: mihailinux <mihaigabrielbusiness@gmail.com>
Signed-off-by: mihailinux <mihaigabrielbusiness@gmail.com>
Signed-off-by: mihailinux <mihaigabrielbusiness@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants