/**
* 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%x\n", TOTAL_LEN, sniffed_crc);
if (0ul == sniffed_crc) {
printf("CRC32 check is good\n");
}
else {
printf("ERROR - CRC32 check FAILED!\n");
}
}
This firmware image was imported from the pico-examples repository.
Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Before flashing, please put your Raspberry Pi Pico™ chip in the bootloader mode by keeping the BOOTSEL button pressed while powering up. For more information, please take a look at your board's datasheet.
If you find yourself unable to perform any of the operations, please navigate to the troubleshooting, and the Q&A pages.
The "π Check installed version" button doesn't send your firmware to the Internet. Instead, its algorithm compares the firmware builds' UF2 block hashes safely in your web browser.
The installed firmware version is compared only with all the different versions (builds) of the same project.
Exercise caution while exploring projects of unknown origin. In principle, anyone can publish their firmware here. Projects endorsed by this website will always come with the "submitted by flashmypico" text written just below their title.
A part of your chip's unique RANDID number may be sent to the server if this project's author has enabled the installed version tracking feature. This number will only be logged if the project's author already has it, and has used it to enable this feature for this particular board.