Add example which uses the in-built 'DMA sniff' capability to check a CRC32

This commit is contained in:
andygpz11
2023-02-10 17:11:00 +00:00
committed by GitHub
parent 42ffd518c9
commit 827cb43b3a
4 changed files with 113 additions and 0 deletions

View File

@@ -44,6 +44,7 @@ App|Description
[hello_dma](dma/hello_dma)| Use the DMA to copy data in memory.
[control_blocks](dma/control_blocks)| Build a control block list, to program a longer sequence of DMA transfers to the UART.
[channel_irq](dma/channel_irq)| Use an IRQ handler to reconfigure a DMA channel, in order to continuously drive data through a PIO state machine.
[sniff_crc](dma/sniff_crc)| Use the DMA engine's 'sniff' capability to calculate a CRC32 on a data buffer.
### Flash

View File

@@ -2,4 +2,5 @@ if (NOT PICO_NO_HARDWARE)
add_subdirectory(channel_irq)
add_subdirectory(control_blocks)
add_subdirectory(hello_dma)
add_subdirectory(sniff_crc)
endif ()

View File

@@ -0,0 +1,11 @@
add_executable(sniff_crc
sniff_crc.c
)
target_link_libraries(sniff_crc pico_stdlib hardware_dma)
# create map/bin/hex file etc.
pico_add_extra_outputs(sniff_crc)
# add url via pico_set_program_url
example_auto_set_url(sniff_crc)

100
dma/sniff_crc/sniff_crc.c Normal file
View File

@@ -0,0 +1,100 @@
/**
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// Use the DMA engine's 'sniff' capability to calculate a CRC32 on data in a buffer.
// Note: This does NOT do an actual data copy, it 'transfers' all the data to a single
// dummy destination byte so as to be able to crawl over the input data using a 'DMA'.
// If a data copy *with* a CRC32 sniff is required, the start address of the suitably sized
// destination buffer must be supplied and the 'write_increment' set to true (see below).
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/dma.h"
#define CRC32_INIT ((uint32_t)-1l)
#define DATA_TO_CHECK_LEN 9
#define CRC32_LEN 4
#define TOTAL_LEN (DATA_TO_CHECK_LEN + CRC32_LEN)
// commonly used crc test data and also space for the crc value
static uint8_t src[TOTAL_LEN] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00 };
static uint8_t dummy_dst[1];
// This uses a standard polynomial with the alternate 'reversed' shift direction.
// It is possible to use a non-reversed algorithm here but the DMA sniff set-up
// below would need to be modified to remain consistent and allow the check to pass.
static uint32_t soft_crc32_block(uint32_t crc, uint8_t *bytp, uint32_t length) {
while(length--) {
uint32_t byte32 = (uint32_t)*bytp++;
for (uint8_t bit = 8; bit; bit--, byte32 >>= 1) {
crc = (crc >> 1) ^ (((crc ^ byte32) & 1ul) ? 0xEDB88320ul : 0ul);
}
}
return crc;
}
int main() {
uint32_t crc_res;
stdio_init_all();
// calculate and append the crc
crc_res = soft_crc32_block(CRC32_INIT, src, DATA_TO_CHECK_LEN);
*((uint32_t *)&src[DATA_TO_CHECK_LEN]) = crc_res;
printf("Buffer to DMA: ");
for (int i = 0; i < TOTAL_LEN; i++) {
printf("0x%02x ", src[i]);
}
printf("\n");
// UNcomment the next line to deliberately corrupt the buffer
//src[0]++; // modify any byte, in any way, to break the CRC32 check
// Get a free channel, panic() if there are none
int chan = dma_claim_unused_channel(true);
// 8 bit transfers. The read address increments after each transfer but
// the write address remains unchanged pointing to the dummy destination.
// No DREQ is selected, so the DMA transfers as fast as it can.
dma_channel_config c = dma_channel_get_default_config(chan);
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
channel_config_set_read_increment(&c, true);
channel_config_set_write_increment(&c, false);
// (bit-reverse) CRC32 specific sniff set-up
channel_config_set_sniff_enable(&c, true);
dma_sniffer_set_data_accumulator(CRC32_INIT);
dma_sniffer_set_output_reverse_enabled(true);
dma_sniffer_enable(chan, DMA_SNIFF_CTRL_CALC_VALUE_CRC32R, true);
dma_channel_configure(
chan, // Channel to be configured
&c, // The configuration we just created
dummy_dst, // The (unchanging) write address
src, // The initial read address
TOTAL_LEN, // Total number of transfers inc. appended crc; each is 1 byte
true // Start immediately.
);
// We could choose to go and do something else whilst the DMA is doing its
// thing. In this case the processor has nothing else to do, so we just
// wait for the DMA to finish.
dma_channel_wait_for_finish_blocking(chan);
uint32_t sniffed_crc = dma_sniffer_get_data_accumulator();
printf("Completed DMA sniff of %d byte buffer, DMA sniff accumulator value: 0x%lx\n", TOTAL_LEN, sniffed_crc);
if (0ul == sniffed_crc) {
printf("CRC32 check is good\n");
}
else {
printf("ERROR - CRC32 check FAILED!\n");
}
}