Pico-sdk studies

From Wiki at Neela Nurseries
Revision as of 19:24, 23 August 2022 by Ted (talk | contribs) (^ Reference: - name correction "Buckley" not "Bucklay".)
Jump to: navigation, search

Device_tree_from_scratch   ::   Spi_device_tree_source_code   ::   Pico-sdk_studies


2022-08-15 Pico SDK Studies


^ DMA driver details

2022-08-18

This section holds notes on RPi Pico SDK driver code for the RP2040 direct memory access unit. Goal here is to understand how Pico SDK structures its Application Programmers' Interface or API. We need to understand this in order to connect a Zephyr based application to code running on RP2040 and using its DMA. Likely we will need DMA when we enable and implement one or more SPI based peripherals, as SPI transmit and receive lines are often associated with a DMA controller to support high data transmission rates.

Search for . . .

ted@localhost:~/projects/zephyr-based/workspace-rpi-pico-work/pico-sdk$ grep -nr NUM_DMA_CHANNELS ./*
./src/host/pico_platform/include/hardware/platform_defs.h:12:#define NUM_DMA_CHANNELS 12u
. . .
./src/rp2040/hardware_structs/include/hardware/structs/dma.h:106:    dma_channel_hw_t ch[NUM_DMA_CHANNELS]; // 12
./src/rp2040/hardware_structs/include/hardware/structs/dma.h:194:    } ch[NUM_DMA_CHANNELS];


So we have looked up a symbol which reflects that RP2040 DMA controller has twelve independent channels for memory to memory transfers. The Synopsys device bindings file however specifies that we must assign to node property "dma-cells" a fixed value of 1. Another good starting point to understand Pico SPI driver is in the "hello_dma" sample app. Before configuring any DMA attributes source file main.c first calls routine . . .



Another instructive Pico sample app is the DMA control block sample which uses two DMA channels to transfer a series of data blocks.



^ Pico assert.h definitions

RPi Pico SDK assert() definition is included in a section of this nn wiki page, as this Pico header file is included by both RPi Pico DMA driver and RPi Pico SPI driver. It is likely included by other Pico drivers and modules. We also include mention of this definition as recent studies of Zephyr third party drivers reveal that various projects each provide their own definitions of the C assert() construct.

$ find . -name assert.h
./common/pico_base/include/pico/assert.h

The contents of Pico SDK assert.h file are:


#ifdef __cplusplus

#include <cassert>

extern "C" {
#else
#include <assert.h>
#endif

// PICO_CONFIG: PARAM_ASSERTIONS_ENABLE_ALL, Global assert enable, type=bool, default=0, group=pico_base
// PICO_CONFIG: PARAM_ASSERTIONS_DISABLE_ALL, Global assert disable, type=bool, default=0, group=pico_base

#ifndef PARAM_ASSERTIONS_ENABLE_ALL
#define PARAM_ASSERTIONS_ENABLE_ALL 0
#endif

#ifndef PARAM_ASSERTIONS_DISABLE_ALL
#define PARAM_ASSERTIONS_DISABLE_ALL 0
#endif

#define PARAM_ASSERTIONS_ENABLED(x) ((PARAM_ASSERTIONS_ENABLED_ ## x || PARAM_ASSERTIONS_ENABLE_ALL) && !PARAM_ASSERTIONS_DISABLE_ALL)

#define invalid_params_if(x, test) ({if (PARAM_ASSERTIONS_ENABLED(x)) assert(!(test));})
#define valid_params_if(x, test) ({if (PARAM_ASSERTIONS_ENABLED(x)) assert(test);})
#define hard_assert_if(x, test) ({if (PARAM_ASSERTIONS_ENABLED(x)) hard_assert(!(test));})

#ifdef NDEBUG
extern void hard_assertion_failure(void);
static inline void hard_assert(bool condition, ...) {
    if (!condition)
        hard_assertion_failure();
}
#else
#define hard_assert assert
#endif

#ifdef __cplusplus
}
#endif
#endif


z z z



/*
 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

// ---------------------------------------
// THIS FILE IS AUTOGENERATED; DO NOT EDIT
// ---------------------------------------

#ifndef _PICO_VERSION_H
#define _PICO_VERSION_H

#define PICO_SDK_VERSION_MAJOR    ${PICO_SDK_VERSION_MAJOR}
#define PICO_SDK_VERSION_MINOR    ${PICO_SDK_VERSION_MINOR}
#define PICO_SDK_VERSION_REVISION ${PICO_SDK_VERSION_REVISION}
#define PICO_SDK_VERSION_STRING   "${PICO_SDK_VERSION_STRING}"

#endif


^ Study of DMA routine check_dma_channel_param()

The routine `check_dma_channel_param()` appears in file dma.c at line 24. In file dma.c references to this routine appear three three times and there is a conditionally compiled definition for it at line 97. There is a second place in Pico SDK where this routine is defined, in header file dma.h. The two definitions read as follows:

Excerpts 1 - check_dma_channel_param() definitions

rp2_common/hardware_dma/dma.c

rp2_common/hardware_dma/include/hardware/dma.h

 96 #if PARAM_ASSERTIONS_ENABLED(DMA)
 97 void check_dma_channel_param_impl(uint __unused channel) {
 98     valid_params_if(DMA, channel < NUM_DMA_CHANNELS);
 99 }
100 #endif
 49 static inline void check_dma_channel_param(__unused uint channel) {
 50 #if PARAM_ASSERTIONS_ENABLED(DMA)
 51     // this method is used a lot by inline functions so avoid code bloat by deferring to function
 52     extern void check_dma_channel_param_impl(uint channel);
 53     check_dma_channel_param_impl(channel);
 54 #endif
 55 }

The routine is defined in dma.c. An interesting feature of this definition is the use of an extern statement within the scope of the routine body. Perhaps the C compiler does not care whether an extern qualified expression is locally scoped or file scoped, in a sense that the compiler only needs to know that given routine is defined somewhere and will be known to the linker at link time.

The following routine-like macro plays a role in the definition of the above routine:


    ./src/common/pico_base/include/pico/assert.h:35:#define valid_params_if(x, test) ({if (PARAM_ASSERTIONS_ENABLED(x)) assert(test);})

and PARAM_ASSERTIONS_ENABLED(x) is defined,

    ./src/common/pico_base/include/pico/assert.h:32:#define PARAM_ASSERTIONS_ENABLED(x) ((PARAM_ASSERTIONS_ENABLED_ ## x || PARAM_ASSERTIONS_ENABLE_ALL) && !PARAM_ASSERTIONS_DISABLE_ALL)


Perhaps another DMA routine's implementation will be easier to track down:


200 /*! \brief Set the size of each DMA bus transfer in a channel configuration object
201  *  \ingroup channel_config
202  *
203  * Set the size of each bus transfer (byte/halfword/word). The read and write addresses
204  * advance by the specific amount (1/2/4 bytes) with each transfer.
205  *
206  * \param c Pointer to channel configuration object
207  * \param size See enum for possible values.
208  */
209 static inline void channel_config_set_transfer_data_size(dma_channel_config *c, enum dma_channel_transfer_size size) {
210     assert(size == DMA_SIZE_8 || size == DMA_SIZE_16 || size == DMA_SIZE_32);
211     c->ctrl = (c->ctrl & ~DMA_CH0_CTRL_TRIG_DATA_SIZE_BITS) | (((uint)size) << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB);
212 }


^ *

^ Pico SDK start up APIs

In studying hello_dma sample app, first Pico SDK call is to API stdio_init_all(). This appears to be defined in two places of the SDK . . .

Place 1:

Code excerpt, start up code from file [pico-sdk]/src/rp2_common/pico_stdio/stdio.c:

269 
270 void stdio_init_all(void) {
271     // todo add explicit custom, or registered although you can call stdio_enable_driver explicitly anyway
272     // These are well known ones
273 #if LIB_PICO_STDIO_UART
274     stdio_uart_init();
275 #endif
276 
277 #if LIB_PICO_STDIO_SEMIHOSTING
278     stdio_semihosting_init();
279 #endif
280 
281 #if LIB_PICO_STDIO_USB
282     stdio_usb_init();
283 #endif
284 }
285


Place 2:

[pico-sdk]/src/host/pico_stdio/include/pico/stdio.h"

  1 /*
  2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
  3  *
  4  * SPDX-License-Identifier: BSD-3-Clause
  5  */
  6 #ifndef _PICO_STDIO_H
  7 #define _PICO_STDIO_H
  8 
  9 typedef struct stdio_driver stdio_driver_t;
 10 
 11 #define STDIO_ERROR -1
 12 #define STDIO_NO_INPUT -2
 13 
 14 static inline void stdio_usb_init() {}
 15 void stdio_uart_init();
 16 static inline void stdio_init_all() { stdio_uart_init(); }
 17 static inline void stdio_filter_driver(stdio_driver_t *driver) {}
 18 static inline void stdio_set_translate_crlf(stdio_driver_t *driver, bool enabled) {}
 19 static inline bool stdio_usb_connected(void) { return true; }
 20 int getchar_timeout_us(uint32_t timeout_us);
 21 #define puts_raw puts
 22 #define putchar_raw putchar
 23 
 24 #endif

Ok, turns out there are supposed to be two definitions for this important API routine, as Pico SDK supports code development on hosts, processors other than the RP2040. The readme file [pico_sdk]/src/host/README.md explains this. Now we need to find another file which talks about a Pico SDK project setting to select RP2040 as the target MCU. This is the defaul, and it may help us resolve the compile time error we're getting as we start to include various headers of the Pico SDK in a Zephyr based exploratory app . . .

2022-08-20 excerpt - build errors during Pico SDK inclusion in Zephyr app:

. . .
 -fno-asynchronous-unwind-tables -fno-pie -fno-pic -fno-reorder-functions -fno-defer-pop -fmacro-prefix-map=/home/ted/projects/zephyr-based/workspace-rpi-pico-work/rpi-pico-zephyr-exploration=CMAKE_SOURCE_DIR -fmacro-prefix-map=/home/ted/projects/zephyr-based/workspace-rpi-pico-work/zephyr=ZEPHYR_BASE -fmacro-prefix-map=/home/ted/projects/zephyr-based/workspace-rpi-pico-work=WEST_TOPDIR -ffunction-sections -fdata-sections -std=c99 -nostdinc -MD -MT CMakeFiles/app.dir/home/ted/projects/zephyr-based/workspace-rpi-pico-work/pico-sdk/src/rp2_common/pico_stdio/stdio.c.obj -MF CMakeFiles/app.dir/home/ted/projects/zephyr-based/workspace-rpi-pico-work/pico-sdk/src/rp2_common/pico_stdio/stdio.c.obj.d -o CMakeFiles/app.dir/home/ted/projects/zephyr-based/workspace-rpi-pico-work/pico-sdk/src/rp2_common/pico_stdio/stdio.c.obj -c /home/ted/projects/zephyr-based/workspace-rpi-pico-work/pico-sdk/src/rp2_common/pico_stdio/stdio.c
/home/ted/projects/zephyr-based/workspace-rpi-pico-work/pico-sdk/src/rp2_common/pico_stdio/stdio.c:261:18: error: expected declaration specifiers or '...' before numeric constant
  261 | int __printflike(1, 0) WRAPPER_FUNC(printf)(const char* format, ...)
      |                  ^
/home/ted/projects/zephyr-based/workspace-rpi-pico-work/pico-sdk/src/rp2_common/pico_stdio/stdio.c:261:21: error: expected declaration specifiers or '...' before numeric constant
  261 | int __printflike(1, 0) WRAPPER_FUNC(printf)(const char* format, ...)
      |                     ^
/home/ted/projects/zephyr-based/workspace-rpi-pico-work/pico-sdk/src/rp2_common/pico_stdio/stdio.c:227:13: warning: 'stdio_buffered_printer' defined but not used [-Wunused-function]
  227 | static void stdio_buffered_printer(char c, void *arg) {
      |             ^~~~~~~~~~~~~~~~~~~~~~
[23/151] Building C object zephyr/CMakeFiles/zephyr.dir/subsys/logging/log_list.c.obj
ninja: build stopped: subcommand failed.
FATAL ERROR: command exited with status 1: /usr/bin/cmake --build /home/ted/projects/zephyr-based/workspace-rpi-pico-work/rpi-pico-zephyr-exploration/build
ted@localhost:~/projects/zephyr-based/workspace-rpi-pico-work/rpi-pico-zephyr-exploration$


. . . Ah easy, that readme file which describes pico-sdk's default MCU or "platform" is the primary pico-sdk README.md file. The pico-sdk project setting to note is 'PICO_PLATFORM=rp2040'.


^ Pico rp2_common headers versus host headers

Pico SDK "host" header files are designed to support running RPi Pico projects on non-rpi hardware. This would be useful if an app is too large to fit in an RPi Pico, or if for some reason an RPi Pico board is not available during all development times.


^ *

^ RPi Pico exploration project paths -06-txt

zztop
/home/ted/projects/zephyr-based/workspace-rpi-pico-work/rpi-pico-zephyr-exploration
/home/ted/projects/zephyr-based/workspace-rpi-pico-work/rpi-pico-zephyr-exploration/src
/home/ted/projects/zephyr-based/workspace-rpi-pico-work/rpi-pico-zephyr-exploration/boards
/
/
/
/
/
/
/
/home/ted/projects/zephyr-based/workspace-rpi-pico-work/pico-sdk
/home/ted/projects/zephyr-based/workspace-rpi-pico-work/pico-sdk/src/rp2_common
/home/ted/projects/zephyr-based/workspace-rpi-pico-work/pico-sdk/src/rp2_common/pico_stdio
/home/ted/reference/rpi-pico-sdk/src/host/pico_stdio/include/pico
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/


^ RPi Pico SDK code in Zephyr modules

Zephyr modules directory contains hal_rpi_pico references, see file [workspace]/modules/hal/rpi_pico/zephyr/module.yaml. What do stanzas cmake-ext and kconfig-ext mean? How possible that we do not find actual source files on the github Zephyr RTOS Project repository for RPi Pico SDK sources, but that these sources appear to be downloaded into the local Zephyr modules dir?

  1 name: hal_rpi_pico
  2 build:
  3   cmake-ext: True
  4   kconfig-ext: True

Ok, finding that in 2021 December Yonatan Schachter made a pull request to Zephyr RTOS Project to have RPi Pico SDK sources brought into Hardware Abstraction Layer (hal) module of Zephyr. Pull request and developer comments at:

   *  https://github.com/zephyrproject-rtos/zephyr/issues/40817



^ Reference

Hmm, would be nice to have mark up which supports HTML style ordered lists, with non-indented comments interleaved between list items - TMH  

  1. pico-sdk/src/rp2_common/README.md . . . document explains convention of Pico library routines which names of form hardware_ and pico_.
  2. pico_pre_load_platform.cmake . . . `cmake` file demonstrates cmake's ability to select variable from among `cmake` internal variables and environment variables.
  3. https://iosoft.blog/2021/10/26/pico-adc-dma/
  4. https://forums.raspberrypi.com/viewtopic.php?t=315944 . . . REVIEW this and next link, may solve __printflike() build errors - TMH
  5. https://forums.raspberrypi.com/viewtopic.php?t=315944#p1890253
  6. -
  7. https://forums.raspberrypi.com/viewtopic.php?t=302082 . . . with pico-examples must run a build at top level of pico-sdk project
  8. https://forums.raspberrypi.com/viewtopic.php?t=316408 . . . how to set PICO_SDK_PATH in Linux environment
  9. https://www.electromaker.io/blog/article/getting-started-with-the-raspberry-pi-pico-w-cc-sdk . . . Ian Buckley of Electromaker tutorial "Getting Started with Rpi Pico"