Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 827cb43

Browse files
authoredFeb 10, 2023
Add example which uses the in-built 'DMA sniff' capability to check a CRC32
1 parent 42ffd51 commit 827cb43

File tree

4 files changed

+113
-0
lines changed

4 files changed

+113
-0
lines changed
 

‎README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ App|Description
4444
[hello_dma](dma/hello_dma)| Use the DMA to copy data in memory.
4545
[control_blocks](dma/control_blocks)| Build a control block list, to program a longer sequence of DMA transfers to the UART.
4646
[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.
47+
[sniff_crc](dma/sniff_crc)| Use the DMA engine's 'sniff' capability to calculate a CRC32 on a data buffer.
4748

4849
### Flash
4950

‎dma/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ if (NOT PICO_NO_HARDWARE)
22
add_subdirectory(channel_irq)
33
add_subdirectory(control_blocks)
44
add_subdirectory(hello_dma)
5+
add_subdirectory(sniff_crc)
56
endif ()

‎dma/sniff_crc/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
add_executable(sniff_crc
2+
sniff_crc.c
3+
)
4+
5+
target_link_libraries(sniff_crc pico_stdlib hardware_dma)
6+
7+
# create map/bin/hex file etc.
8+
pico_add_extra_outputs(sniff_crc)
9+
10+
# add url via pico_set_program_url
11+
example_auto_set_url(sniff_crc)

‎dma/sniff_crc/sniff_crc.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/**
2+
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
3+
*
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
// Use the DMA engine's 'sniff' capability to calculate a CRC32 on data in a buffer.
8+
// Note: This does NOT do an actual data copy, it 'transfers' all the data to a single
9+
// dummy destination byte so as to be able to crawl over the input data using a 'DMA'.
10+
// If a data copy *with* a CRC32 sniff is required, the start address of the suitably sized
11+
// destination buffer must be supplied and the 'write_increment' set to true (see below).
12+
13+
#include <stdio.h>
14+
#include <string.h>
15+
#include "pico/stdlib.h"
16+
#include "hardware/dma.h"
17+
18+
#define CRC32_INIT ((uint32_t)-1l)
19+
20+
#define DATA_TO_CHECK_LEN 9
21+
#define CRC32_LEN 4
22+
#define TOTAL_LEN (DATA_TO_CHECK_LEN + CRC32_LEN)
23+
24+
// commonly used crc test data and also space for the crc value
25+
static uint8_t src[TOTAL_LEN] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00 };
26+
static uint8_t dummy_dst[1];
27+
28+
// This uses a standard polynomial with the alternate 'reversed' shift direction.
29+
// It is possible to use a non-reversed algorithm here but the DMA sniff set-up
30+
// below would need to be modified to remain consistent and allow the check to pass.
31+
static uint32_t soft_crc32_block(uint32_t crc, uint8_t *bytp, uint32_t length) {
32+
while(length--) {
33+
uint32_t byte32 = (uint32_t)*bytp++;
34+
35+
for (uint8_t bit = 8; bit; bit--, byte32 >>= 1) {
36+
crc = (crc >> 1) ^ (((crc ^ byte32) & 1ul) ? 0xEDB88320ul : 0ul);
37+
}
38+
}
39+
return crc;
40+
}
41+
42+
int main() {
43+
uint32_t crc_res;
44+
45+
stdio_init_all();
46+
47+
// calculate and append the crc
48+
crc_res = soft_crc32_block(CRC32_INIT, src, DATA_TO_CHECK_LEN);
49+
*((uint32_t *)&src[DATA_TO_CHECK_LEN]) = crc_res;
50+
51+
printf("Buffer to DMA: ");
52+
for (int i = 0; i < TOTAL_LEN; i++) {
53+
printf("0x%02x ", src[i]);
54+
}
55+
printf("\n");
56+
57+
// UNcomment the next line to deliberately corrupt the buffer
58+
//src[0]++; // modify any byte, in any way, to break the CRC32 check
59+
60+
// Get a free channel, panic() if there are none
61+
int chan = dma_claim_unused_channel(true);
62+
63+
// 8 bit transfers. The read address increments after each transfer but
64+
// the write address remains unchanged pointing to the dummy destination.
65+
// No DREQ is selected, so the DMA transfers as fast as it can.
66+
dma_channel_config c = dma_channel_get_default_config(chan);
67+
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
68+
channel_config_set_read_increment(&c, true);
69+
channel_config_set_write_increment(&c, false);
70+
71+
// (bit-reverse) CRC32 specific sniff set-up
72+
channel_config_set_sniff_enable(&c, true);
73+
dma_sniffer_set_data_accumulator(CRC32_INIT);
74+
dma_sniffer_set_output_reverse_enabled(true);
75+
dma_sniffer_enable(chan, DMA_SNIFF_CTRL_CALC_VALUE_CRC32R, true);
76+
77+
dma_channel_configure(
78+
chan, // Channel to be configured
79+
&c, // The configuration we just created
80+
dummy_dst, // The (unchanging) write address
81+
src, // The initial read address
82+
TOTAL_LEN, // Total number of transfers inc. appended crc; each is 1 byte
83+
true // Start immediately.
84+
);
85+
86+
// We could choose to go and do something else whilst the DMA is doing its
87+
// thing. In this case the processor has nothing else to do, so we just
88+
// wait for the DMA to finish.
89+
dma_channel_wait_for_finish_blocking(chan);
90+
91+
uint32_t sniffed_crc = dma_sniffer_get_data_accumulator();
92+
printf("Completed DMA sniff of %d byte buffer, DMA sniff accumulator value: 0x%lx\n", TOTAL_LEN, sniffed_crc);
93+
94+
if (0ul == sniffed_crc) {
95+
printf("CRC32 check is good\n");
96+
}
97+
else {
98+
printf("ERROR - CRC32 check FAILED!\n");
99+
}
100+
}

0 commit comments

Comments
 (0)
Please sign in to comment.