The Missing Bit

CRC 32 on STM32l0

zig stm32 til

The goal is to do the same as zig's std.hash.crc.Crc32.hash(&buf) on STM32 hardware.

There is no real complication, but it took me a while to find the correct configuration. The zig std lib code is as follow:

const buf: [9]u8 = .{1, 2, 3, 4, 4, 5, 1, 23, 4};

const crc = std.hash.crc.Crc32.hash(&buf)

The produced CRC for the above code is 0xd85c2351.

To get the same CRC with STM32 hardware, here is the code:

pub fn crc(buf: []const u8) u32 {
    _ = buf;
    regs.CRC.INIT.modify(.{ .CRC_INIT = 0xffffffff });
        .Polynomialcoefficients = 0x4C11DB7,
        .RESET = 1,
        .REV_IN = 0b01,
        .REV_OUT = 1,

    const dr = @ptrCast(*volatile u8, regs.CRC.DR);

    for (buf) |b| dr.* = b;

    return @intCast(u32, regs.CRC.DR.*) ^ 0xffffffff;

There are multiple things to explain here.

First, the CRC_INIT is the default value, but I do specify it here.

The POL is the default value for polynomial coefficient is the same as zig, except that if you read zig code, you will find this value: 0xedb88320. It took me a bit to realize it was the same but with bits reversed.

The CR has three configurations:

Now the last gotcha is that the DR register must be accessed as 8 bit to iterate the slice. This is what the ptrCast is for.

Finally, the resulting CRC must be XOR'ed with 0xffffffff to produce the same result as the zig std lib. This also took me a bit to find out.

I hope this can help you if you need to generate a CRC on STM32 hardware and in software.

I tested this on STM32l0x1 hardware, but I think it should work on other MCU.

If you wish to comment or discuss this post, just mention me on Mastodon or Twitter.