CRC hardware on pyboard

The official pyboard running MicroPython.
This is the reference design and main target board for MicroPython.
You can buy one at the store.
Target audience: Users with a pyboard.
Post Reply
manitou
Posts: 73
Joined: Wed Feb 25, 2015 12:15 am

CRC hardware on pyboard

Post by manitou » Fri Apr 17, 2015 6:53 pm

I'm trying to test the CRC hardware on the pyboard (ref manual chapter 4) using stm. If I enable the CRC peripheral, values do change in the CRC data register, but they don't match any test vectors for CRC32.
Here is a session, where i enable the CRC peripheral, reset it, set data register to 0, and print data register.

Code: Select all

>>> import stm
>>> print(hex(stm.mem32[stm.RCC + stm.RCC_AHB1ENR]))
0x10000f
>>> stm.mem32[stm.RCC + stm.RCC_AHB1ENR] = 0x10100f
>>> stm.mem32[stm.CRC+stm.CRC_CR] = 1
>>> print(hex(stm.mem32[stm.CRC+stm.CRC_DR]))
-0x1
>>> stm.mem32[stm.CRC+stm.CRC_DR] = 0
>>> print(hex(stm.mem32[stm.CRC+stm.CRC_DR]))
-0x38fb2285
CRC32 of 4 bytes of 0 should be 0x2144df1c

Is there really CRC hardware on STM32F405RG?
Any hints?
If one can get it working, one could add python access to the firmware. There seems to be HAL support ...

test vectors http://www.febooti.com/products/filetwe ... t-vectors/

crc calculator http://www.lammertbies.nl/comm/info/crc ... ation.html

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: CRC hardware on pyboard

Post by dhylands » Sat Apr 18, 2015 12:01 am

It seems that the 405 HW uses the reversed polynomial 0x4C11DB7 where you used what I would consider the traditional polynomial of 0xedb88320

So if you take your result -0x38fb2285 and make it positive, you'll get: 0xC704DD7B

Now convert that to binary: 1100 0111 0000 0100 1101 1101 0111 1011 and now bit reverse that bit sequence (i.e. read that bit sequence from right to left) and you'll get:

1101 1110 1011 1011 0010 0000 1110 0011

FInally bit negate that (since that's what the crc32 algo does with the intermediary result at the very end and you get:

0010 0001 0100 0100 1101 1111 0001 1100 which is 0x2144df1c

An issue you'll run into with stm and reading the registers is that you'll run ito issues trying to read values with bit 31 isn't equal to bit 30, since micropython can only represent 31-bit small ints. So I think you'd need a helper routine to do a 32-bit register read and return a proper mulit-precision int or return it as 2 16-bit small ints. The datasheet says that the register needs be accessed by 32-bit words, so the CRC_DR register needs to be read as a single 32-bit entity.

cloudformdesign
Posts: 35
Joined: Wed Mar 11, 2015 7:48 pm

Re: CRC hardware on pyboard

Post by cloudformdesign » Tue May 05, 2015 1:15 am

That's a really unfortunate result of the 31bit magic. I think it's worth it to create an issue for the stm module to return the actual in value - - if that has to be multiple precision then so be it.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: CRC hardware on pyboard

Post by pythoncoder » Tue May 05, 2015 8:42 pm

This could be addressed using the inline assembler. The following code puts the 32 bit result into a single element Python array (bypassing the MicroPython limitation). The getcrc() function then coerces the return value into a Python integer of arbitrary precision. I'm no expert on CRC so you'll need to check the correctness of the output of the following (please report back). But it does produce values with differing bits in b31 and b30.

Code: Select all

from array import array
import stm

def enable_crc():
    stm.mem32[stm.RCC + stm.RCC_AHB1ENR] = stm.mem32[stm.RCC + stm.RCC_AHB1ENR] | 0x1000

def reset_crc():
    stm.mem32[stm.CRC+stm.CRC_CR] = 1

@micropython.asm_thumb
def getval(r0, r1):
    movwt(r3, stm.CRC + stm.CRC_DR)
    str(r1, [r3, 0])
    ldr(r2, [r3, 0])
    str(r2, [r0, 0])

def getcrc(value):
    a = array('i', [0])
    getval(a, value)
    return a[0] & 0xffffffff # coerce to arbitrary precision

enable_crc()
reset_crc()
for x in range(20):
    print(hex(getcrc(0)))
Peter Hinch
Index to my micropython libraries.

manitou
Posts: 73
Joined: Wed Feb 25, 2015 12:15 am

Re: CRC hardware on pyboard

Post by manitou » Sat Apr 23, 2016 12:40 am

Update. Working in C++ on mbed F446RE ( STM32F446xx cortex-m4 @180mhz, hardware float) with the same simple minded CRC hardware as pyboard, I figured out how to do CRC on 32-bit words so that test vector results were good. You have to reverse the bits of the input words, and the final output CRC has to be bit reversed and the bits flipped.

Code: Select all

        
        CRC->CR = 1;   //reset
        while(CRC->DR != ~0);  // wait for reset
        CRC->DR = __RBIT(0x41414141);   // AAAA ;
        result = ~__RBIT(CRC->DR);
The CRC unit only works on 32-bit words, so you'll need additional software if your data stream is not a multiple of 4 bytes.

User avatar
tsjoiner
Posts: 22
Joined: Tue Sep 05, 2017 3:09 pm
Location: Alberta Beach, Alberta, Canada

Re: CRC hardware on pyboard

Post by tsjoiner » Wed May 16, 2018 12:53 am

I'm experimenting with hardware crc on the pyboard testing pythoncoder's example above. Don't think I understand. How can I generate a crc for a string "The quick brown fox jumped over the lazy dog" ? Also, how might I generate a matching crc value using standard Python?

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: CRC hardware on pyboard

Post by dhylands » Wed May 16, 2018 3:34 am

I have some C code which will return a CRC32 for an arbitrary file here:
https://github.com/dhylands/projects/tr ... /src/crc32

This produces the same CRC32 that zip uses. So another way to get a CRC32 value is to put the text you want in a zip file and then print detailed info about the zip archive (under zip you can use zip -l -v foo.zip)

MicroPython has some CRC32 code in the ubunascii module. I was able to do:

Code: Select all

>>> import ubinascii
>>> ubinascii.crc32('Test\n')
4202175170
>>> hex(ubinascii.crc32('Test\n'))
'0xfa781ac2'
Using the other utilities mentioned above:

Code: Select all

$ echo Test > test.txt
$ crc32 test.txt 
0xfa781ac2 test.txt
$ unzip -l -v test.zip 
Archive:  test.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
       5  Stored        5   0% 2018-05-15 20:27 fa781ac2  test.txt
--------          -------  ---                            -------
       5                5   0%                            1 file
$ hd test.txt
00000000  54 65 73 74 0a                                    |Test.|
00000005

User avatar
tsjoiner
Posts: 22
Joined: Tue Sep 05, 2017 3:09 pm
Location: Alberta Beach, Alberta, Canada

Re: CRC hardware on pyboard

Post by tsjoiner » Wed May 16, 2018 4:32 am

Just ran:
>>> import ubinascii
>>> ubinascii.crc32('Test\n')

on Pyboard 1.1:
MicroPython v1.9.3-558-ga60efa82 on 2018-04-23; PYBv1.1 with STM32F405RG

got:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'crc32'

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: CRC hardware on pyboard

Post by pythoncoder » Wed May 16, 2018 6:17 am

It only works on the Unix build here.

My assembler code simply provides access to the CRC hardware which operates on 32 bit words. You could get a CRC value by putting each character into a 32 bit word and using my code, but I don't think the result would conform to any standard.

Code: Select all

import stm
from array import array
s = 'the quick brown fox jumps over the lazy dog'
a = array('i', ord(p) for p in s)

def enable_crc():
    stm.mem32[stm.RCC + stm.RCC_AHB1ENR] = stm.mem32[stm.RCC + stm.RCC_AHB1ENR] | 0x1000

def reset_crc():
    stm.mem32[stm.CRC+stm.CRC_CR] = 1

@micropython.asm_thumb
def getval(r0, r1):
    movwt(r3, stm.CRC + stm.CRC_DR)
    str(r1, [r3, 0])
    ldr(r2, [r3, 0])
    str(r2, [r0, 0])

def getcrc(value):
    a = array('i', [0])
    getval(a, value)
    return a[0] & 0xffffffff # coerce to arbitrary precision

enable_crc()
reset_crc()
for i in a:
    crc = getcrc(i)
print(hex(crc))
Peter Hinch
Index to my micropython libraries.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: CRC hardware on pyboard

Post by dhylands » Wed May 16, 2018 6:16 pm

It looks like you can enable it for the pyboard by setting: MICROPY_PY_UBINASCII_CRC32 in ports/stm32/mpconfigport.h

Specifically, I would try adding:

Code: Select all

#define MICROPY_PY_UBINASCII_CRC32 (1)
after the definition of MICROPY_PY_UBINASCII here: https://github.com/micropython/micropyt ... ort.h#L125

Post Reply