kopia lustrzana https://github.com/micropython/micropython-lib
112 wiersze
3.2 KiB
Python
112 wiersze
3.2 KiB
Python
import micropython
|
|
from uctypes import addressof
|
|
|
|
# ruff: noqa: F821 - @asm_thumb and @viper decorator adds names to function scope
|
|
|
|
# https://electronics.stackexchange.com/questions/321304/how-to-use-the-data-crc-of-sd-cards-in-spi-mode
|
|
# for sd bit mode
|
|
import array
|
|
|
|
_sd_crc16_table = array.array("H", (0 for _ in range(256)))
|
|
# /* Generate CRC16 table */
|
|
# for (byt = 0U; byt < 256U; byt ++){
|
|
# crc = byt << 8;
|
|
# for (bit = 0U; bit < 8U; bit ++){
|
|
# crc <<= 1;
|
|
# if ((crc & 0x10000U) != 0U){ crc ^= 0x1021U; }
|
|
# }
|
|
# sd_crc16_table[byt] = (crc & 0xFFFFU);
|
|
# }
|
|
for byt in range(256):
|
|
crc = byt << 8
|
|
for bit in range(8):
|
|
crc = crc << 1
|
|
if (crc & 0x10000) != 0:
|
|
crc ^= 0x1021
|
|
_sd_crc16_table[byt] = crc & 0xFFFF
|
|
|
|
|
|
# /* Running CRC16 calculation for a byte. */
|
|
# static unsigned int sd_crc16_byte(unsigned int crcval, unsigned int byte)
|
|
# {
|
|
# return (sd_crc16_table[(byte ^ (crcval >> 8)) & 0xFFU] ^ (crcval << 8)) & 0xFFFFU;
|
|
# }
|
|
|
|
|
|
@micropython.viper
|
|
def crc16_viper(crc: int, data) -> int:
|
|
dp = ptr8(addressof(data))
|
|
tp = ptr16(addressof(_sd_crc16_table))
|
|
nn = int(len(data))
|
|
idx = 0
|
|
while idx < nn:
|
|
crc = ((crc << 8) & 0xFFFF) ^ tp[((crc >> 8) ^ dp[idx]) & 0xFF]
|
|
idx += 1
|
|
return crc
|
|
|
|
|
|
try: # if we have asm_thumb, this goes faster
|
|
|
|
@micropython.asm_thumb
|
|
def _crc_loop_16(r0, r1, r2, r3) -> int:
|
|
# r0 is data address
|
|
# r1 is table address
|
|
# r2 is CRC
|
|
# r3 is count
|
|
mov(r4, 0)
|
|
mvn(r4, r4) # all ones now
|
|
mov(r7, 16)
|
|
lsr(r4, r7) # R4 = half-word of ones
|
|
mov(r5, 0xFF) # used for byte masking
|
|
label(loop)
|
|
mov(r6, r2) # copy current CRC
|
|
mov(r7, 8)
|
|
lsr(r6, r7) # crc >> 8
|
|
ldrb(r7, [r0, 0]) # fetch new byte dp[idx]
|
|
add(r0, 1) # push to next byte address
|
|
eor(r6, r7) # r6 = (crc>>8) ^ dp[idx]
|
|
and_(r6, r5) # mask byte ( (crc>>8) ^ dp[idx]) & 0xff
|
|
add(r6, r6, r6) # double for table offset
|
|
add(r6, r6, r1) # table data address
|
|
ldrh(r6, [r6, 0]) # fetch table syndrome
|
|
mov(r7, 8)
|
|
lsl(r2, r7) # CRC << 8
|
|
and_(r2, r4) # (crc << 8) & 0xffff)
|
|
eor(r2, r6) # new CRC
|
|
sub(r3, 1)
|
|
bne(loop)
|
|
mov(r0, r2)
|
|
|
|
@micropython.viper
|
|
def crc16(crc: int, data) -> int:
|
|
return int(
|
|
_crc_loop_16(
|
|
int(addressof(data)),
|
|
int(addressof(_sd_crc16_table)),
|
|
crc,
|
|
int(len(data)),
|
|
)
|
|
)
|
|
|
|
except:
|
|
# wrapper to allow the pure-python implementation to be accessed by the right name if asm_thumb doesn't work
|
|
@micropython.viper
|
|
def crc16(crc: int, data) -> int:
|
|
return int(crc16_viper(crc, data))
|
|
|
|
|
|
# def test_speed():
|
|
# data = b"\xaa"*1024
|
|
# import time
|
|
# crc = 0
|
|
# start = time.ticks_us()
|
|
# for i in range(1024):
|
|
# crc = crc16(crc, data)
|
|
# print("asm crc speed = ", f"{crc:08x}", 2**20 / (time.ticks_diff(time.ticks_us(), start) / 1e6), "bytes/s")
|
|
#
|
|
# crc = 0
|
|
# start = time.ticks_us()
|
|
# for i in range(1024):
|
|
# crc = crc16_viper(crc, data)
|
|
# print("py crc speed = ", f"{crc:08x}", 2**20 / (time.ticks_diff(time.ticks_us(), start) / 1e6), "bytes/s")
|