1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-12 19:10:32 +03:00

Removing pico-sdk (replace with module)

This commit is contained in:
blckmn 2025-05-22 21:24:27 +10:00
parent aa8701ef87
commit 28f898679a
569 changed files with 0 additions and 434481 deletions

View file

@ -1,3 +0,0 @@
This directory code that is common to all builds regardless of `PICO_PLATFORM`. It is a mix
of common header files, or high level functionality built entirely using `hardware_` or `pico_` libraries provided
by the actual target `PICO_PLATFORM``

View file

@ -1,171 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _BOOT_PICOBIN_H
#define _BOOT_PICOBIN_H
#ifndef NO_PICO_PLATFORM
#include "pico/platform.h"
#else
#ifndef _u
#ifdef __ASSEMBLER__
#define _u(x) x
#else
#define _u(x) x ## u
#endif
#endif
#endif
/** \file picobin.h
* \defgroup boot_picobin_headers boot_picobin_headers
*
* \brief Constants for PICOBIN format
*/
// these are designed to not look like (likely) 16/32-bit ARM or RISC-V instructions or look like valid pointers
#define PICOBIN_BLOCK_MARKER_START _u(0xffffded3)
#define PICOBIN_BLOCK_MARKER_END _u(0xab123579)
#define PICOBIN_MAX_BLOCK_SIZE _u(0x280)
#define PICOBIN_MAX_IMAGE_DEF_BLOCK_SIZE _u(0x180)
#define PICOBIN_MAX_PARTITION_TABLE_BLOCK_SIZE _u(0x280)
// note bit 6 is used to make parity even
#define PICOBIN_BLOCK_ITEM_1BS_NEXT_BLOCK_OFFSET _u(0x41)
#define PICOBIN_BLOCK_ITEM_1BS_IMAGE_TYPE _u(0x42)
#define PICOBIN_BLOCK_ITEM_1BS_VECTOR_TABLE _u(0x03)
#define PICOBIN_BLOCK_ITEM_1BS_ENTRY_POINT _u(0x44)
#define PICOBIN_BLOCK_ITEM_1BS_ROLLING_WINDOW_DELTA _u(0x05)
#define PICOBIN_BLOCK_ITEM_LOAD_MAP _u(0x06)
#define PICOBIN_BLOCK_ITEM_1BS_HASH_DEF _u(0x47)
#define PICOBIN_BLOCK_ITEM_1BS_VERSION _u(0x48)
#define PICOBIN_BLOCK_ITEM_SIGNATURE _u(0x09)
#define PICOBIN_BLOCK_ITEM_PARTITION_TABLE _u(0x0a)
#define PICOBIN_BLOCK_ITEM_HASH_VALUE _u(0x4b)
#define PICOBIN_BLOCK_ITEM_SALT _u(0x0c)
#define PICOBIN_BLOCK_ITEM_2BS_IGNORED (_u(0x80) | _u(0x7e))
#define PICOBIN_BLOCK_ITEM_2BS_LAST (_u(0x80) | _u(0x7f))
// ----
#define PICOBIN_INDEX_TO_BITS(y, x) (y ## _ ## x << y ## _LSB)
#define PICOBIN_IMAGE_TYPE_IMAGE_TYPE_LSB _u(0)
#define PICOBIN_IMAGE_TYPE_IMAGE_TYPE_BITS _u(0x000f)
#define PICOBIN_IMAGE_TYPE_IMAGE_TYPE_INVALID _u(0x0)
#define PICOBIN_IMAGE_TYPE_IMAGE_TYPE_EXE _u(0x1)
#define PICOBIN_IMAGE_TYPE_IMAGE_TYPE_DATA _u(0x2)
#define PICOBIN_IMAGE_TYPE_IMAGE_TYPE_AS_BITS(x) PICOBIN_INDEX_TO_BITS(PICOBIN_IMAGE_TYPE_IMAGE_TYPE, x)
#define PICOBIN_IMAGE_TYPE_EXE_SECURITY_LSB _u(4)
#define PICOBIN_IMAGE_TYPE_EXE_SECURITY_BITS _u(0x0030)
#define PICOBIN_IMAGE_TYPE_EXE_SECURITY_UNSPECIFIED _u(0x0)
#define PICOBIN_IMAGE_TYPE_EXE_SECURITY_NS _u(0x1)
#define PICOBIN_IMAGE_TYPE_EXE_SECURITY_S _u(0x2)
#define PICOBIN_IMAGE_TYPE_EXE_SECURITY_AS_BITS(x) PICOBIN_INDEX_TO_BITS(PICOBIN_IMAGE_TYPE_EXE_SECURITY, x)
#define PICOBIN_IMAGE_TYPE_EXE_CPU_LSB _u(8)
#define PICOBIN_IMAGE_TYPE_EXE_CPU_BITS _u(0x0700)
#define PICOBIN_IMAGE_TYPE_EXE_CPU_ARM _u(0)
#define PICOBIN_IMAGE_TYPE_EXE_CPU_RISCV _u(1)
#define PICOBIN_IMAGE_TYPE_EXE_CPU_VARMULET _u(2)
#define PICOBIN_IMAGE_TYPE_EXE_CPU_AS_BITS(x) PICOBIN_INDEX_TO_BITS(PICOBIN_IMAGE_TYPE_EXE_CPU, x)
#define PICOBIN_IMAGE_TYPE_EXE_CHIP_LSB _u(12)
#define PICOBIN_IMAGE_TYPE_EXE_CHIP_BITS _u(0x7000)
#define PICOBIN_IMAGE_TYPE_EXE_CHIP_RP2040 _u(0)
#define PICOBIN_IMAGE_TYPE_EXE_CHIP_RP2350 _u(1)
#define PICOBIN_IMAGE_TYPE_EXE_CHIP_AS_BITS(x) PICOBIN_INDEX_TO_BITS(PICOBIN_IMAGE_TYPE_EXE_CHIP, x)
#define PICOBIN_IMAGE_TYPE_EXE_TBYB_BITS _u(0x8000)
// todo assert no overlap ^
#define PICOBIN_PARTITION_PERMISSIONS_LSB _u(26)
#define PICOBIN_PARTITION_PERMISSIONS_BITS _u(0xfc000000)
#define PICOBIN_PARTITION_PERMISSION_S_R_BITS _u(0x04000000)
#define PICOBIN_PARTITION_PERMISSION_S_W_BITS _u(0x08000000)
#define PICOBIN_PARTITION_PERMISSION_NS_R_BITS _u(0x10000000)
#define PICOBIN_PARTITION_PERMISSION_NS_W_BITS _u(0x20000000)
#define PICOBIN_PARTITION_PERMISSION_NSBOOT_R_BITS _u(0x40000000)
#define PICOBIN_PARTITION_PERMISSION_NSBOOT_W_BITS _u(0x80000000)
#define PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB _u(0)
#define PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS _u(0x00001fff)
#define PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB _u(13)
#define PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS _u(0x03ffe000)
#define PICOBIN_PARTITION_FLAGS_HAS_ID_BITS _u(0x00000001)
#define PICOBIN_PARTITION_FLAGS_LINK_TYPE_LSB _u(1)
#define PICOBIN_PARTITION_FLAGS_LINK_TYPE_BITS _u(0x00000006)
#define PICOBIN_PARTITION_FLAGS_LINK_VALUE_LSB _u(3)
#define PICOBIN_PARTITION_FLAGS_LINK_VALUE_BITS _u(0x00000078)
#define PICOBIN_PARTITION_MAX_EXTRA_FAMILIES _u(3)
#define PICOBIN_PARTITION_FLAGS_ACCEPTS_NUM_EXTRA_FAMILIES_LSB _u(7)
#define PICOBIN_PARTITION_FLAGS_ACCEPTS_NUM_EXTRA_FAMILIES_BITS _u(0x00000180)
// these are an optimization when booting in either ARM or RISC-V, to avoid looking at partitions
// which are known not to contain the right sort of binary, OR as a way to prevent
// auto-architecture-switch. NOTE: the first partition that can be booted, will be,
// so if you have a RISC-V binary in the first partition, and auto-arhcitecture-switch enabled, then
// even if booting under ARM, with an ARM binary in a later partition, the RISC-V binary
// will be booted by default; setting PICOBIN_PARTITION_FLAGS_IGNORED_DURING_ARM_BOOT_BITS
// on the partition, will have the RISC-V binary containing partition ignored under ARM
// boot
#define PICOBIN_PARTITION_FLAGS_IGNORED_DURING_ARM_BOOT_BITS _u(0x00000200)
#define PICOBIN_PARTITION_FLAGS_IGNORED_DURING_RISCV_BOOT_BITS _u(0x00000400)
#define PICOBIN_PARTITION_FLAGS_UF2_DOWNLOAD_AB_NON_BOOTABLE_OWNER_AFFINITY _u(0x00000800)
#define PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS _u(0x00001000)
#define PICOBIN_PARTITION_FLAGS_UF2_DOWNLOAD_NO_REBOOT_BITS _u(0x00002000)
// we have a bit for each well known family-id .. note we expect there to be more in the future with new chips,
// but we have plenty of space for now.
#define PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILIES_LSB _u(14)
#define PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2040_BITS _u(0x00004000)
#define PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_ABSOLUTE_BITS _u(0x00008000)
#define PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_DATA_BITS _u(0x00010000)
#define PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2350_ARM_S_BITS _u(0x00020000)
#define PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2350_RISCV_BITS _u(0x00040000)
#define PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2350_ARM_NS_BITS _u(0x00080000)
#define PICOBIN_PARTITION_FLAGS_LINK_TYPE_NONE _u(0)
#define PICOBIN_PARTITION_FLAGS_LINK_TYPE_A_PARTITION _u(1)
#define PICOBIN_PARTITION_FLAGS_LINK_TYPE_OWNER_PARTITION _u(2)
#define PICOBIN_PARTITION_FLAGS_LINK_TYPE_AS_BITS(x) PICOBIN_INDEX_TO_BITS(PICOBIN_PARTITION_FLAGS_LINK_TYPE, x)
#define PICOBIN_HASH_SHA256 _u(0x01)
#define PICOBIN_SIGNATURE_SECP256K1 _u(0x01)
#ifndef __ASSEMBLER__
#include <stdbool.h>
typedef struct {
// these must all be word aligned
uint32_t storage_address_rel;
uint32_t runtime_address;
uint32_t size;
} picobin_load_map_entry;
typedef struct {
uint32_t header;
picobin_load_map_entry entries[];
} picobin_load_map;
static inline unsigned int picobin_load_map_entry_count(const picobin_load_map *lm) {
return (lm->header << 1) >> 25;
}
static inline bool picobin_load_map_is_relative(const picobin_load_map *lm) {
return (int32_t)lm->header >= 0;
}
#endif
#endif

View file

@ -1,175 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _BOOT_PICOBOOT_H
#define _BOOT_PICOBOOT_H
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#ifndef NO_PICO_PLATFORM
#include "pico/platform.h"
#endif
/** \file picoboot.h
* \defgroup boot_picoboot_headers boot_picoboot_headers
*
* \brief Header file for the PICOBOOT USB interface exposed by an RP2xxx chip in BOOTSEL mode
*/
#include "picoboot_constants.h"
#define PICOBOOT_MAGIC 0x431fd10bu
// --------------------------------------------
// CONTROL REQUESTS FOR THE PICOBOOT INTERFACE
// --------------------------------------------
// size 0 OUT - un-stall EPs and reset
#define PICOBOOT_IF_RESET 0x41
// size 16 IN - return the status of the last command
#define PICOBOOT_IF_CMD_STATUS 0x42
// --------------------------------------------------
// COMMAND REQUESTS SENT TO THE PICOBOOT OUT ENDPOINT
// --------------------------------------------------
//
// picoboot_cmd structure of size 32 is sent to OUT endpoint
// transfer_length bytes are transferred via IN/OUT
// device responds on success with 0 length ACK packet set via OUT/IN
// device may stall the transferring endpoint in case of error
enum picoboot_cmd_id {
PC_EXCLUSIVE_ACCESS = 0x1,
PC_REBOOT = 0x2,
PC_FLASH_ERASE = 0x3,
PC_READ = 0x84, // either RAM or FLASH
PC_WRITE = 0x5, // either RAM or FLASH (does no erase)
PC_EXIT_XIP = 0x6,
PC_ENTER_CMD_XIP = 0x7,
PC_EXEC = 0x8,
PC_VECTORIZE_FLASH = 0x9,
// RP2350 only below here
PC_REBOOT2 = 0xa,
PC_GET_INFO = 0x8b,
PC_OTP_READ = 0x8c,
PC_OTP_WRITE = 0xd,
//PC_EXEC2 = 0xe, // currently unused
};
enum picoboot_status {
PICOBOOT_OK = 0,
PICOBOOT_UNKNOWN_CMD = 1,
PICOBOOT_INVALID_CMD_LENGTH = 2,
PICOBOOT_INVALID_TRANSFER_LENGTH = 3,
PICOBOOT_INVALID_ADDRESS = 4,
PICOBOOT_BAD_ALIGNMENT = 5,
PICOBOOT_INTERLEAVED_WRITE = 6,
PICOBOOT_REBOOTING = 7,
PICOBOOT_UNKNOWN_ERROR = 8,
PICOBOOT_INVALID_STATE = 9,
PICOBOOT_NOT_PERMITTED = 10,
PICOBOOT_INVALID_ARG = 11,
PICOBOOT_BUFFER_TOO_SMALL = 12,
PICOBOOT_PRECONDITION_NOT_MET = 13,
PICOBOOT_MODIFIED_DATA = 14,
PICOBOOT_INVALID_DATA = 15,
PICOBOOT_NOT_FOUND = 16,
PICOBOOT_UNSUPPORTED_MODIFICATION = 17,
};
struct __packed picoboot_reboot_cmd {
uint32_t dPC; // 0 means reset into regular boot path
uint32_t dSP;
uint32_t dDelayMS;
};
// note this (with pc_sp) union member has the same layout as picoboot_reboot_cmd except with extra dFlags
struct __packed picoboot_reboot2_cmd {
uint32_t dFlags;
uint32_t dDelayMS;
uint32_t dParam0;
uint32_t dParam1;
};
// used for EXEC, VECTORIZE_FLASH
struct __packed picoboot_address_only_cmd {
uint32_t dAddr;
};
// used for READ, WRITE, FLASH_ERASE
struct __packed picoboot_range_cmd {
uint32_t dAddr;
uint32_t dSize;
};
struct __packed picoboot_exec2_cmd {
uint32_t image_base;
uint32_t image_size;
uint32_t workarea_base;
uint32_t workarea_size;
};
enum picoboot_exclusive_type {
NOT_EXCLUSIVE = 0,
EXCLUSIVE,
EXCLUSIVE_AND_EJECT
};
struct __packed picoboot_exclusive_cmd {
uint8_t bExclusive;
};
struct __packed picoboot_otp_cmd {
uint16_t wRow; // OTP row
uint16_t wRowCount; // number of rows to transfer
uint8_t bEcc; // use error correction (16 bit per register vs 24 (stored as 32) bit raw)
};
struct __packed picoboot_get_info_cmd {
uint8_t bType;
uint8_t bParam;
uint16_t wParam;
uint32_t dParams[3];
};
// little endian
struct __packed __aligned(4) picoboot_cmd {
uint32_t dMagic;
uint32_t dToken; // an identifier for this token to correlate with a status response
uint8_t bCmdId; // top bit set for IN
uint8_t bCmdSize; // bytes of actual data in the arg part of this structure
uint16_t _unused;
uint32_t dTransferLength; // length of IN/OUT transfer (or 0) if none
union {
uint8_t args[16];
struct picoboot_reboot_cmd reboot_cmd;
struct picoboot_range_cmd range_cmd;
struct picoboot_address_only_cmd address_only_cmd;
struct picoboot_exclusive_cmd exclusive_cmd;
struct picoboot_reboot2_cmd reboot2_cmd;
struct picoboot_otp_cmd otp_cmd;
struct picoboot_get_info_cmd get_info_cmd;
struct picoboot_exec2_cmd exec2_cmd;
};
};
static_assert(32 == sizeof(struct picoboot_cmd), "picoboot_cmd must be 32 bytes big");
struct __packed __aligned(4) picoboot_cmd_status {
uint32_t dToken;
uint32_t dStatusCode;
uint8_t bCmdId;
uint8_t bInProgress;
uint8_t _pad[6];
};
static_assert(16 == sizeof(struct picoboot_cmd_status), "picoboot_cmd_status must be 16 bytes big");
#endif

View file

@ -1,42 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _BOOT_PICOBOOT_CONSTANTS_H
#define _BOOT_PICOBOOT_CONSTANTS_H
#define REBOOT2_TYPE_MASK 0x0f
// note these match REBOOT_TYPE in pico/bootrom_constants.h (also 0 is used for PC_SP for backwards compatibility with RP2040)
// values 0-7 are secure/non-secure
#define REBOOT2_FLAG_REBOOT_TYPE_NORMAL 0x0 // param0 = diagnostic partition
#define REBOOT2_FLAG_REBOOT_TYPE_BOOTSEL 0x2 // param0 = bootsel_flags, param1 = gpio_config
#define REBOOT2_FLAG_REBOOT_TYPE_RAM_IMAGE 0x3 // param0 = image_base, param1 = image_end
#define REBOOT2_FLAG_REBOOT_TYPE_FLASH_UPDATE 0x4 // param0 = update_base
// values 8-15 are secure only
#define REBOOT2_FLAG_REBOOT_TYPE_PC_SP 0xd
#define REBOOT2_FLAG_REBOOT_TO_ARM 0x10
#define REBOOT2_FLAG_REBOOT_TO_RISCV 0x20
#define REBOOT2_FLAG_NO_RETURN_ON_SUCCESS 0x100
#define BOOTSEL_FLAG_DISABLE_MSD_INTERFACE 0x01
#define BOOTSEL_FLAG_DISABLE_PICOBOOT_INTERFACE 0x02
#define BOOTSEL_FLAG_GPIO_PIN_ACTIVE_LOW 0x10
#define BOOTSEL_FLAG_GPIO_PIN_SPECIFIED 0x20
#define PICOBOOT_GET_INFO_SYS 1
#define PICOBOOT_GET_INFO_PARTTION_TABLE 2
#define PICOBOOT_GET_INFO_UF2_TARGET_PARTITION 3
#define PICOBOOT_GET_INFO_UF2_STATUS 4
#define UF2_STATUS_IGNORED_FAMILY 0x01
#define UF2_STATUS_ABORT_EXCLUSIVELY_LOCKED 0x10
#define UF2_STATUS_ABORT_BAD_ADDRESS 0x20
#define UF2_STATUS_ABORT_WRITE_ERROR 0x40
#define UF2_STATUS_ABORT_REBOOT_FAILED 0x80
#endif

View file

@ -1,53 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _BOOT_UF2_H
#define _BOOT_UF2_H
#include <stdint.h>
#include <assert.h>
/** \file uf2.h
* \defgroup boot_uf2_headers boot_uf2_headers
*
* \brief Header file for the UF2 format supported by a RP2xxx chip in BOOTSEL mode
*/
#define UF2_MAGIC_START0 0x0A324655u
#define UF2_MAGIC_START1 0x9E5D5157u
#define UF2_MAGIC_END 0x0AB16F30u
#define UF2_FLAG_NOT_MAIN_FLASH 0x00000001u
#define UF2_FLAG_FILE_CONTAINER 0x00001000u
#define UF2_FLAG_FAMILY_ID_PRESENT 0x00002000u
#define UF2_FLAG_MD5_PRESENT 0x00004000u
#define RP2040_FAMILY_ID 0xe48bff56u
#define ABSOLUTE_FAMILY_ID 0xe48bff57u
#define DATA_FAMILY_ID 0xe48bff58u
#define RP2350_ARM_S_FAMILY_ID 0xe48bff59u
#define RP2350_RISCV_FAMILY_ID 0xe48bff5au
#define RP2350_ARM_NS_FAMILY_ID 0xe48bff5bu
#define FAMILY_ID_MAX 0xe48bff5bu
struct uf2_block {
// 32 byte header
uint32_t magic_start0;
uint32_t magic_start1;
uint32_t flags;
uint32_t target_addr;
uint32_t payload_size;
uint32_t block_no;
uint32_t num_blocks;
uint32_t file_size; // or familyID;
uint8_t data[476];
uint32_t magic_end;
};
static_assert(sizeof(struct uf2_block) == 512, "uf2_block not sector sized");
#endif

View file

@ -1,56 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "hardware/claim.h"
uint32_t hw_claim_lock(void) {
return spin_lock_blocking(spin_lock_instance(PICO_SPINLOCK_ID_HARDWARE_CLAIM));
}
void hw_claim_unlock(uint32_t save) {
spin_unlock(spin_lock_instance(PICO_SPINLOCK_ID_HARDWARE_CLAIM), save);
}
inline bool hw_is_claimed(const uint8_t *bits, uint bit_index) {
return (bits[bit_index >> 3u] & (1u << (bit_index & 7u)));
}
void hw_claim_or_assert(uint8_t *bits, uint bit_index, const char *message) {
uint32_t save = hw_claim_lock();
if (hw_is_claimed(bits, bit_index)) {
panic(message, bit_index);
} else {
bits[bit_index >> 3u] |= (uint8_t)(1u << (bit_index & 7u));
}
hw_claim_unlock(save);
}
int hw_claim_unused_from_range(uint8_t *bits, bool required, uint bit_lsb, uint bit_msb, const char *message) {
// don't bother check lsb / msb order as if wrong, then it'll fail anyway
uint32_t save = hw_claim_lock();
int found_bit = -1;
for(uint bit=bit_lsb; bit <= bit_msb; bit++) {
if (!hw_is_claimed(bits, bit)) {
bits[bit >> 3u] |= (uint8_t)(1u << (bit & 7u));
found_bit = (int)bit;
break;
}
}
hw_claim_unlock(save);
if (found_bit < 0 && required) {
panic(message);
}
return found_bit;
}
void hw_claim_clear(uint8_t *bits, uint bit_index) {
uint32_t save = hw_claim_lock();
assert(hw_is_claimed(bits, bit_index));
bits[bit_index >> 3u] &= (uint8_t) ~(1u << (bit_index & 7u));
hw_claim_unlock(save);
}

View file

@ -1,108 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_CLAIM_H
#define _HARDWARE_CLAIM_H
#include "pico.h"
#include "hardware/sync.h"
/** \file claim.h
* \defgroup hardware_claim hardware_claim
* \brief Lightweight hardware resource management API
*
* `hardware_claim` provides a simple API for management of hardware resources at runtime.
*
* This API is usually called by other hardware specific _claiming_ APIs and provides simple
* multi-core safe methods to manipulate compact bit-sets representing hardware resources.
*
* This API allows any other library to cooperatively participate in a scheme by which
* both compile time and runtime allocation of resources can co-exist, and conflicts
* can be avoided or detected (depending on the use case) without the libraries having
* any other knowledge of each other.
*
* Facilities are providing for:
*
* 1. Claiming resources (and asserting if they are already claimed)
* 2. Freeing (unclaiming) resources
* 3. Finding unused resources
*/
#ifdef __cplusplus
extern "C" {
#endif
/*! \brief Atomically claim a resource, panicking if it is already in use
* \ingroup hardware_claim
*
* The resource ownership is indicated by the bit_index bit in an array of bits.
*
* \param bits pointer to an array of bits (8 bits per byte)
* \param bit_index resource to claim (bit index into array of bits)
* \param message string to display if the bit cannot be claimed; note this may have a single printf format "%d" for the bit
*/
void hw_claim_or_assert(uint8_t *bits, uint bit_index, const char *message);
/*! \brief Atomically claim one resource out of a range of resources, optionally asserting if none are free
* \ingroup hardware_claim
*
* \param bits pointer to an array of bits (8 bits per byte)
* \param required true if this method should panic if the resource is not free
* \param bit_lsb the lower bound (inclusive) of the resource range to claim from
* \param bit_msb the upper bound (inclusive) of the resource range to claim from
* \param message string to display if the bit cannot be claimed
* \return the bit index representing the claimed or -1 if none are available in the range, and required = false
*/
int hw_claim_unused_from_range(uint8_t *bits, bool required, uint bit_lsb, uint bit_msb, const char *message);
/*! \brief Determine if a resource is claimed at the time of the call
* \ingroup hardware_claim
*
* The resource ownership is indicated by the bit_index bit in an array of bits.
*
* \param bits pointer to an array of bits (8 bits per byte)
* \param bit_index resource to check (bit index into array of bits)
* \return true if the resource is claimed
*/
bool hw_is_claimed(const uint8_t *bits, uint bit_index);
/*! \brief Atomically unclaim a resource
* \ingroup hardware_claim
*
* The resource ownership is indicated by the bit_index bit in an array of bits.
*
* \param bits pointer to an array of bits (8 bits per byte)
* \param bit_index resource to unclaim (bit index into array of bits)
*/
void hw_claim_clear(uint8_t *bits, uint bit_index);
/*! \brief Acquire the runtime mutual exclusion lock provided by the `hardware_claim` library
* \ingroup hardware_claim
*
* This method is called automatically by the other `hw_claim_` methods, however it is provided as a convenience
* to code that might want to protect other hardware initialization code from concurrent use.
*
* \note hw_claim_lock() uses a spin lock internally, so disables interrupts on the calling core, and will deadlock
* if the calling core already owns the lock.
*
* \return a token to pass to hw_claim_unlock()
*/
uint32_t hw_claim_lock(void);
/*! \brief Release the runtime mutual exclusion lock provided by the `hardware_claim` library
* \ingroup hardware_claim
*
* \note This method MUST be called from the same core that call hw_claim_lock()
*
* \param token the token returned by the corresponding call to hw_claim_lock()
*/
void hw_claim_unlock(uint32_t token);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,33 +0,0 @@
# build the auto gen config headers
set(header_content "// AUTOGENERATED FROM PICO_CONFIG_HEADER_FILES and then PICO_<PLATFORM>_CONFIG_HEADER_FILES\n// DO NOT EDIT!\n")
string(TOUPPER ${PICO_PLATFORM} PICO_PLATFORM_UPPER)
string(REGEX REPLACE "-" "_" PICO_PLATFORM_UPPER "${PICO_PLATFORM_UPPER}")
macro(add_header_content_from_var VAR)
set(header_content "${header_content}\n\n// based on ${VAR}:\n")
foreach(var IN LISTS ${VAR})
set(header_content "${header_content}\n#include \"${var}\"")
endforeach()
endmacro()
# PICO_CMAKE_CONFIG: PICO_CONFIG_HEADER_FILES, List of extra header files to include from pico/config.h for all platforms, type=list, group=pico_base
add_header_content_from_var(PICO_CONFIG_HEADER_FILES)
# PICO_CMAKE_CONFIG: PICO_RP2040_CONFIG_HEADER_FILES, List of extra header files to include from pico/config.h for the rp2040 platform only, type=list, group=pico_base
# PICO_CMAKE_CONFIG: PICO_RP2350_ARM_S_CONFIG_HEADER_FILES, List of extra header files to include from pico/config.h for the rp2350-arm-s platform only, type=list, group=pico_base
# PICO_CMAKE_CONFIG: PICO_RP2350_RISCV_CONFIG_HEADER_FILES, List of extra header files to include from pico/config.h for the riscv platform only, type=list, group=pico_base
# PICO_CMAKE_CONFIG: PICO_HOST_CONFIG_HEADER_FILES, List of extra header files to include from pico/config.h for the host platform only, type=list, group=pico_base
add_header_content_from_var(PICO_${PICO_PLATFORM_UPPER}_CONFIG_HEADER_FILES)
pico_register_common_scope_var(PICO_${PICO_PLATFORM_UPPER}_CONFIG_HEADER_FILES)
file(GENERATE
OUTPUT ${CMAKE_BINARY_DIR}/generated/pico_base/pico/config_autogen.h
CONTENT "${header_content}"
)
configure_file( ${CMAKE_CURRENT_LIST_DIR}/include/pico/version.h.in ${CMAKE_BINARY_DIR}/generated/pico_base/pico/version.h)
foreach(DIR IN LISTS PICO_INCLUDE_DIRS)
target_include_directories(pico_base_headers SYSTEM INTERFACE ${DIR})
endforeach()

View file

@ -1,38 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_H
#define _PICO_H
/** \file pico.h
* \defgroup pico_base pico_base
*
* \brief Core types and macros for the Raspberry Pi Pico SDK.
*
* This header is intended to be included by all source code
* as it includes configuration headers and overrides in the correct order
*
* This header may be included by assembly code
*/
// We may be included by assembly which can't include <cdefs.h>
#define __PICO_STRING(x) #x
#define __PICO_XSTRING(x) __PICO_STRING(x)
#define __PICO_CONCAT1(x, y) x ## y
#include "pico/types.h"
#include "pico/version.h"
// PICO_CONFIG: PICO_CONFIG_HEADER, Unquoted path to header include in place of the default pico/config.h which may be desirable for build systems which can't easily generate the config_autogen header, group=pico_base
#ifdef PICO_CONFIG_HEADER
#include __PICO_XSTRING(PICO_CONFIG_HEADER)
#else
#include "pico/config.h"
#endif
#include "pico/platform.h"
#include "pico/error.h"
#endif

View file

@ -1,52 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_ASSERT_H
#define _PICO_ASSERT_H
#include <stdbool.h>
#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));})
#define invalid_params_if_and_return(x, test, rc) ({/*if (PARAM_ASSERTIONS_ENABLED(x)) assert(!(test)); */ if (test) return rc; })
#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

View file

@ -1,26 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_CONFIG_H
#define _PICO_CONFIG_H
// -----------------------------------------------------
// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLY CODE SO
// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
// OR USE #ifndef __ASSEMBLER__ guards
// -------------
// PICO_CONFIG_HEADER_FILES and then PICO_SDK_<PLATFORM>_CONFIG_INCLUDE_FILES
// entries are dumped in order at build time into this generated header
#include "pico/config_autogen.h"
// PICO_CONFIG: PICO_CONFIG_RTOS_ADAPTER_HEADER, Unquoted path to header include in the default pico/config.h for RTOS integration defines that must be included in all sources, group=pico_base
#ifdef PICO_CONFIG_RTOS_ADAPTER_HEADER
#include __PICO_XSTRING(PICO_CONFIG_RTOS_ADAPTER_HEADER)
#endif
#endif

View file

@ -1,50 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_ERROR_H
#define _PICO_ERROR_H
#ifndef __ASSEMBLER__
/*!
* \brief Common return codes from pico_sdk methods that return a status
*
* All `PICO_ERROR_` values are negative so they can be returned from functions that also
* want to return a zero or positive value on success.
*
* Note these error codes may be returned via bootrom functions too.
*
* \ingroup pico_base
*/
enum pico_error_codes {
PICO_OK = 0, ///< No error; the operation succeeded
PICO_ERROR_NONE = 0, ///< No error; the operation succeeded
PICO_ERROR_GENERIC = -1, ///< An unspecified error occurred
PICO_ERROR_TIMEOUT = -2, ///< The function failed due to timeout
PICO_ERROR_NO_DATA = -3, ///< Attempt for example to read from an empty buffer/FIFO
PICO_ERROR_NOT_PERMITTED = -4, ///< Permission violation e.g. write to read-only flash partition, or security violation
PICO_ERROR_INVALID_ARG = -5, ///< Argument is outside of range of supported values`
PICO_ERROR_IO = -6, ///< An I/O error occurred
PICO_ERROR_BADAUTH = -7, ///< The authorization failed due to bad credentials
PICO_ERROR_CONNECT_FAILED = -8, ///< The connection failed
PICO_ERROR_INSUFFICIENT_RESOURCES = -9, ///< Dynamic allocation of resources failed
PICO_ERROR_INVALID_ADDRESS = -10, ///< Address argument was out-of-bounds or was determined to be an address that the caller may not access
PICO_ERROR_BAD_ALIGNMENT = -11, ///< Address was mis-aligned (usually not on word boundary)
PICO_ERROR_INVALID_STATE = -12, ///< Something happened or failed to happen in the past, and consequently we (currently) can't service the request
PICO_ERROR_BUFFER_TOO_SMALL = -13, ///< A user-allocated buffer was too small to hold the result or working state of this function
PICO_ERROR_PRECONDITION_NOT_MET = -14, ///< The call failed because another function must be called first
PICO_ERROR_MODIFIED_DATA = -15, ///< Cached data was determined to be inconsistent with the actual version of the data
PICO_ERROR_INVALID_DATA = -16, ///< A data structure failed to validate
PICO_ERROR_NOT_FOUND = -17, ///< Attempted to access something that does not exist; or, a search failed
PICO_ERROR_UNSUPPORTED_MODIFICATION = -18, ///< Write is impossible based on previous writes; e.g. attempted to clear an OTP bit
PICO_ERROR_LOCK_REQUIRED = -19, ///< A required lock is not owned
PICO_ERROR_VERSION_MISMATCH = -20, ///< A version mismatch occurred (e.g. trying to run PIO version 1 code on RP2040)
PICO_ERROR_RESOURCE_IN_USE = -21 ///< The call could not proceed because requires resourcesw were unavailable
};
#endif // !__ASSEMBLER__
#endif

View file

@ -1,121 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_TYPES_H
#define _PICO_TYPES_H
#ifndef __ASSEMBLER__
#include "pico/assert.h"
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
typedef unsigned int uint;
// PICO_CONFIG: PICO_OPAQUE_ABSOLUTE_TIME_T, Enable opaque type for absolute_time_t to help catch inadvertent confusing uint64_t delays with absolute times, default=0, advanced=true, group=pico_base
#ifndef PICO_OPAQUE_ABSOLUTE_TIME_T
#define PICO_OPAQUE_ABSOLUTE_TIME_T 0
#endif
/*! \typedef absolute_time_t
\brief An opaque 64 bit timestamp in microseconds
The type is used instead of a raw uint64_t to prevent accidentally passing relative times or times in the wrong
time units where an absolute time is required.
note: As of SDK 2.0.0 this type defaults to being a uin64_t (i.e. no protection); it is enabled
by setting PICO_OPAQUE_ABSOLUTE_TIME_T to 1
\see to_us_since_boot()
\see update_us_since_boot()
\ingroup timestamp
*/
#if PICO_OPAQUE_ABSOLUTE_TIME_T
typedef struct {
uint64_t _private_us_since_boot;
} absolute_time_t;
#else
typedef uint64_t absolute_time_t;
#endif
/*! fn to_us_since_boot
* \brief convert an absolute_time_t into a number of microseconds since boot.
* \param t the absolute time to convert
* \return a number of microseconds since boot, equivalent to t
* \ingroup timestamp
*/
static inline uint64_t to_us_since_boot(absolute_time_t t) {
#ifdef PICO_DEBUG_ABSOLUTE_TIME_T
return t._private_us_since_boot;
#else
return t;
#endif
}
/*! fn update_us_since_boot
* \brief update an absolute_time_t value to represent a given number of microseconds since boot
* \param t the absolute time value to update
* \param us_since_boot the number of microseconds since boot to represent. Note this should be representable
* as a signed 64 bit integer
* \ingroup timestamp
*/
static inline void update_us_since_boot(absolute_time_t *t, uint64_t us_since_boot) {
#ifdef PICO_DEBUG_ABSOLUTE_TIME_T
assert(us_since_boot <= INT64_MAX);
t->_private_us_since_boot = us_since_boot;
#else
*t = us_since_boot;
#endif
}
/*! fn from_us_since_boot
* \brief convert a number of microseconds since boot to an absolute_time_t
* \param us_since_boot number of microseconds since boot
* \return an absolute time equivalent to us_since_boot
* \ingroup timestamp
*/
static inline absolute_time_t from_us_since_boot(uint64_t us_since_boot) {
absolute_time_t t;
update_us_since_boot(&t, us_since_boot);
return t;
}
#ifdef NDEBUG
#define ABSOLUTE_TIME_INITIALIZED_VAR(name, value) name = value
#else
#define ABSOLUTE_TIME_INITIALIZED_VAR(name, value) name = {value}
#endif
// PICO_CONFIG: PICO_INCLUDE_RTC_DATETIME, Whether to include the datetime_t type used with the RP2040 RTC hardware, default=1 on RP2040, group=util_datetime
#ifndef PICO_INCLUDE_RTC_DATETIME
#define PICO_INCLUDE_RTC_DATETIME PICO_RP2040
#endif
#if PICO_INCLUDE_RTC_DATETIME
/** \struct datetime_t
* \ingroup util_datetime
* \brief Structure containing date and time information
*
* When setting an RTC alarm, set a field to -1 tells
* the RTC to not match on this field
*/
typedef struct {
int16_t year; ///< 0..4095
int8_t month; ///< 1..12, 1 is January
int8_t day; ///< 1..28,29,30,31 depending on month
int8_t dotw; ///< 0..6, 0 is Sunday
int8_t hour; ///< 0..23
int8_t min; ///< 0..59
int8_t sec; ///< 0..59
} datetime_t;
#endif
#define bool_to_bit(x) ((uint)!!(x))
#endif
#endif

View file

@ -1,19 +0,0 @@
/*
* 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

View file

@ -1,31 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_BINARY_INFO_H
#define _PICO_BINARY_INFO_H
/** \file binary_info.h
* \defgroup pico_binary_info pico_binary_info
*
* \brief Binary info is intended for embedding machine readable information with the binary in FLASH
*
* Example uses include:
*
* - Program identification / information
* - Pin layouts
* - Included features
* - Identifying flash regions used as block devices/storage
*/
#include "pico/binary_info/defs.h"
#include "pico/binary_info/structure.h"
// PICO_CONFIG: PICO_NO_BINARY_INFO, Don't include "binary info" in the output binary, type=bool, default=0 except for `PICO_PLATFORM` `host`, group=pico_runtime_init
#if !PICO_ON_DEVICE && !defined(PICO_NO_BINARY_INFO)
#define PICO_NO_BINARY_INFO 1
#endif
#include "pico/binary_info/code.h"
#endif

View file

@ -1,269 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_BINARY_INFO_CODE_H
#define _PICO_BINARY_INFO_CODE_H
// pico.h is not available when PICO_NO_BINARY_INFO=1 is used for builds outside of the SDK (e.g. picotool)
// and only needed anyway (because of macro definitions) in PICO_NO_BINARY_INFO=0 builds
#if !PICO_NO_BINARY_INFO
#include "pico.h"
#endif
#include "pico/binary_info/structure.h"
#if !PICO_NO_BINARY_INFO
#define __bi_decl(name, bi, section_prefix, attr) static const attr __attribute__((section(section_prefix __STRING(name)))) struct _binary_info_core *const name = bi
#define __bi_lineno_var_name __CONCAT(__bi_, __LINE__)
#define __bi_ptr_lineno_var_name __CONCAT(__bi_ptr, __LINE__)
#define __bi_enclosure_check_lineno_var_name __CONCAT(_error_bi_is_missing_enclosing_decl_,__LINE__)
#define __bi_mark_enclosure static const __unused int __bi_enclosure_check_lineno_var_name=0;
#if __cplusplus || __GNUC__ >= 8
#define __bi_enclosure_check(x) (x + __bi_enclosure_check_lineno_var_name)
#else
// skip the version check on older GCC non C++, as it doesn't compile.. this is only here to catch the
// user accidentally forgetting to enclose the binary item with bi_decl
#define __bi_enclosure_check(x) (x)
#endif
/**
* \brief Declare some binary information that will be included if the contain source file/line is compiled into the binary
* \ingroup pico_binary_info
*/
#define bi_decl(_decl) __bi_mark_enclosure _decl; __bi_decl(__bi_ptr_lineno_var_name, &__bi_lineno_var_name.core, ".binary_info.keep.", __used);
/**
* \brief Declare some binary information that will be included if the function containing the decl is linked into the binary.
* The SDK uses --gc-sections, so functions that are never called will be removed by the linker, and any associated
* binary information declared this way will also be stripped
* \ingroup pico_binary_info
*/
#define bi_decl_if_func_used(_decl) ({__bi_mark_enclosure _decl; __bi_decl(__bi_ptr_lineno_var_name, &__bi_lineno_var_name.core, ".binary_info.", ); *(const volatile uint8_t *)&__bi_ptr_lineno_var_name;});
#define bi_decl_with_attr(_decl, _attr) __bi_mark_enclosure _attr _decl; __bi_decl(__bi_ptr_lineno_var_name, &__bi_lineno_var_name.core, ".binary_info.keep.", __used);
#define bi_decl_if_func_used_with_attr(_decl, _attr) ({__bi_mark_enclosure _attr _decl; __bi_decl(__bi_ptr_lineno_var_name, &__bi_lineno_var_name.core, ".binary_info.", ); *(const volatile uint8_t *)&__bi_ptr_lineno_var_name;});
#else
#define __bi_decl(bi, name, attr)
#define bi_decl_with_attr(_decl, _attr)
#define bi_decl(_decl)
#define bi_decl_if_func_used_with_attr(_decl, _attr) ((void)0);
#define bi_decl_if_func_used(_decl) ((void)0);
#endif
#define bi_int(_tag, _id, _value) \
static const struct _binary_info_id_and_int __bi_lineno_var_name = { \
.core = { \
.type = __bi_enclosure_check(BINARY_INFO_TYPE_ID_AND_INT), \
.tag = _tag, \
},\
.id = _id, \
.value = _value \
};
#define bi_string(_tag, _id, _value) \
static const struct _binary_info_id_and_string __bi_lineno_var_name = { \
.core = { \
.type = __bi_enclosure_check(BINARY_INFO_TYPE_ID_AND_STRING), \
.tag = _tag, \
},\
.id = _id, \
.value = _value, \
}
#define __bi_ptr_int32_with_name(_tag, _id, _label, _value) \
static const struct _binary_info_ptr_int32_with_name __bi_lineno_var_name = { \
.core = { \
.type = __bi_enclosure_check(BINARY_INFO_TYPE_PTR_INT32_WITH_NAME), \
.tag = _tag, \
},\
.id = _id, \
.value = &_value, \
.label = _label, \
}
#define bi_ptr_int32(_tag, _id, _var, _default) __attribute__((section(".data"))) static int _var = _default; __bi_ptr_int32_with_name(_tag, _id, __STRING(_var), _var)
#define __bi_ptr_string_with_name(_tag, _id, _label, _value, _len) \
static const struct _binary_info_ptr_string_with_name __bi_lineno_var_name = { \
.core = { \
.type = __bi_enclosure_check(BINARY_INFO_TYPE_PTR_STRING_WITH_NAME), \
.tag = _tag, \
},\
.id = _id, \
.value = _value, \
.label = _label, \
.len = _len, \
}
#define bi_ptr_string(_tag, _id, _var, _default, _max_len) static char _var[_max_len] = _default; __bi_ptr_string_with_name(_tag, _id, __STRING(_var), _var, _max_len)
#define bi_block_device(_tag, _name, _address, _size, _extra, _flags) \
static const struct _binary_info_block_device __bi_lineno_var_name = { \
.core = { \
.type = __bi_enclosure_check(BINARY_INFO_TYPE_BLOCK_DEVICE), \
.tag = _tag, \
},\
.name = _name, \
.address = _address, \
.size = _size, \
.extra = _extra, \
.flags = _flags, \
}
#define __bi_encoded_pins_with_func(_encoding) \
static const struct _binary_info_pins_with_func __bi_lineno_var_name = { \
.core = { \
.type = __bi_enclosure_check(BINARY_INFO_TYPE_PINS_WITH_FUNC), \
.tag = BINARY_INFO_TAG_RASPBERRY_PI, \
},\
.pin_encoding = _encoding \
}
#define __bi_encoded_pins_64_with_func(_encoding) \
static const struct _binary_info_pins64_with_func __bi_lineno_var_name = { \
.core = { \
.type = __bi_enclosure_check(BINARY_INFO_TYPE_PINS64_WITH_FUNC), \
.tag = BINARY_INFO_TAG_RASPBERRY_PI, \
},\
.pin_encoding = _encoding \
}
#define __bi_pins_with_name(_mask, _label) \
static const struct _binary_info_pins_with_name __bi_lineno_var_name = { \
.core = { \
.type = __bi_enclosure_check(BINARY_INFO_TYPE_PINS_WITH_NAME), \
.tag = BINARY_INFO_TAG_RASPBERRY_PI, \
},\
.pin_mask = _mask, \
.label = _label \
}
#define __bi_pins_64_with_name(_mask, _label) \
static const struct _binary_info_pins64_with_name __bi_lineno_var_name = { \
.core = { \
.type = __bi_enclosure_check(BINARY_INFO_TYPE_PINS64_WITH_NAME), \
.tag = BINARY_INFO_TAG_RASPBERRY_PI, \
},\
.pin_mask = _mask, \
.label = _label \
}
#define __bi_named_group(_parent_tag, _parent_id, _group_tag, _group_id, _label, _flags) \
static const struct _binary_info_named_group __bi_lineno_var_name = { \
.core = { \
.type = __bi_enclosure_check(BINARY_INFO_TYPE_NAMED_GROUP), \
.tag = _parent_tag, \
},\
.parent_id = _parent_id, \
.group_tag = _group_tag, \
.flags = _flags, \
.group_id = _group_id, \
.label = _label \
}
#define bi_binary_end(end) bi_int(BINARY_INFO_TAG_RASPBERRY_PI, BINARY_INFO_ID_RP_BINARY_END, end)
#define bi_program_name(name) bi_string(BINARY_INFO_TAG_RASPBERRY_PI, BINARY_INFO_ID_RP_PROGRAM_NAME, name)
#define bi_program_description(description) bi_string(BINARY_INFO_TAG_RASPBERRY_PI, BINARY_INFO_ID_RP_PROGRAM_DESCRIPTION, description)
#define bi_program_version_string(version_string) bi_string(BINARY_INFO_TAG_RASPBERRY_PI, BINARY_INFO_ID_RP_PROGRAM_VERSION_STRING, version_string)
#define bi_program_build_date_string(date_string) bi_string(BINARY_INFO_TAG_RASPBERRY_PI, BINARY_INFO_ID_RP_PROGRAM_BUILD_DATE_STRING, date_string)
#define bi_program_url(url) bi_string(BINARY_INFO_TAG_RASPBERRY_PI, BINARY_INFO_ID_RP_PROGRAM_URL, url)
// multiple of these may be added
#define bi_program_feature(feature) bi_string(BINARY_INFO_TAG_RASPBERRY_PI, BINARY_INFO_ID_RP_PROGRAM_FEATURE, feature)
#define bi_program_build_attribute(attr) bi_string(BINARY_INFO_TAG_RASPBERRY_PI, BINARY_INFO_ID_RP_PROGRAM_BUILD_ATTRIBUTE, attr)
#define bi_program_feature_group(tag, id, name) __bi_named_group(BINARY_INFO_TAG_RASPBERRY_PI, BINARY_INFO_ID_RP_PROGRAM_FEATURE, tag, id, name, 0)
#define bi_program_feature_group_with_flags(tag, id, name, flags) __bi_named_group(BINARY_INFO_TAG_RASPBERRY_PI, BINARY_INFO_ID_RP_PROGRAM_FEATURE, tag, id, name, flags)
#ifndef PICO_BINARY_INFO_USE_PINS_64
#define PICO_BINARY_INFO_USE_PINS_64 (NUM_BANK0_GPIOS > 32)
#endif
#if !PICO_BINARY_INFO_USE_PINS_64
#define bi_1pin_with_func(p0, func) __bi_encoded_pins_with_func(BI_PINS_ENCODING_MULTI | ((func << 3)) | ((p0) << 7) | ((p0) << 12))
#define bi_2pins_with_func(p0, p1, func) __bi_encoded_pins_with_func(BI_PINS_ENCODING_MULTI | ((func << 3)) | ((p0) << 7) | ((p1) << 12) | ((p1) << 17))
#define bi_3pins_with_func(p0, p1, p2, func) __bi_encoded_pins_with_func(BI_PINS_ENCODING_MULTI | ((func << 3)) | ((p0) << 7) | ((p1) << 12) | ((p2) << 17) | ((p2) << 22))
#define bi_4pins_with_func(p0, p1, p2, p3, func) __bi_encoded_pins_with_func(BI_PINS_ENCODING_MULTI | ((func << 3)) | ((p0) << 7) | ((p1) << 12) | ((p2) << 17) | ((p3) << 22) | ((p3) << 27))
#define bi_5pins_with_func(p0, p1, p2, p3, p4, func) __bi_encoded_pins_with_func(BI_PINS_ENCODING_MULTI | ((func << 3)) | ((p0) << 7) | ((p1) << 12) | ((p2) << 17) | ((p3) << 22) | ((p4) << 27))
#define bi_pin_range_with_func(plo, phi, func) __bi_encoded_pins_with_func(BI_PINS_ENCODING_RANGE | ((func << 3)) | ((plo) << 7) | ((phi) << 12))
#define bi_pin_mask_with_name(pmask, label) __bi_pins_with_name((pmask), (label))
// names are separated by | ... i.e. "name1|name2|name3"
#define bi_pin_mask_with_names(pmask, label) __bi_pins_with_name((pmask), (label))
#else
#define bi_1pin_with_func(p0, func) __bi_encoded_pins_64_with_func(BI_PINS_ENCODING_MULTI | ((func << 3)) | ((p0) << 8) | ((p0) << 16))
#define bi_2pins_with_func(p0, p1, func) __bi_encoded_pins_64_with_func(BI_PINS_ENCODING_MULTI | ((func << 3)) | ((p0) << 8) | ((p1) << 16) | ((p1) << 24))
#define bi_3pins_with_func(p0, p1, p2, func) __bi_encoded_pins_64_with_func(BI_PINS_ENCODING_MULTI | ((func << 3)) | ((p0) << 8) | ((p1) << 16) | ((p2) << 24) | ((uint64_t)(p2) << 32))
#define bi_4pins_with_func(p0, p1, p2, p3, func) __bi_encoded_pins_64_with_func(BI_PINS_ENCODING_MULTI | ((func << 3)) | ((p0) << 8) | ((p1) << 16) | ((p2) << 24) | ((uint64_t)(p3) << 32) | ((uint64_t)(p3) << 40))
#define bi_5pins_with_func(p0, p1, p2, p3, p4, func) __bi_encoded_pins_64_with_func(BI_PINS_ENCODING_MULTI | ((func << 3)) | ((p0) << 8) | ((p1) << 16) | ((p2) << 24) | ((uint64_t)(p3) << 32) | ((uint64_t)(p4) << 40) | ((uint64_t)(p4) << 48))
#define bi_pin_range_with_func(plo, phi, func) __bi_encoded_pins_64_with_func(BI_PINS_ENCODING_RANGE | ((func << 3)) | ((plo) << 8) | ((phi) << 16))
#define bi_pin_mask_with_name(pmask, label) __bi_pins_64_with_name((uint64_t)(pmask), (label))
// names are separated by | ... i.e. "name1|name2|name3"
#define bi_pin_mask_with_names(pmask, label) __bi_pins_64_with_name((uint64_t)(pmask), (label))
#endif
// 6 and 7 pins require pins_64
#define bi_6pins_with_func(p0, p1, p2, p3, p4, p5, func) __bi_encoded_pins_64_with_func(BI_PINS_ENCODING_MULTI | ((func << 3)) | ((p0) << 8) | ((p1) << 16) | ((p2) << 24) | ((uint64_t)(p3) << 32) | ((uint64_t)(p4) << 40) | ((uint64_t)(p5) << 48) | ((uint64_t)(p5) << 56))
#define bi_7pins_with_func(p0, p1, p2, p3, p4, p5, p6,func) __bi_encoded_pins_64_with_func(BI_PINS_ENCODING_MULTI | ((func << 3)) | ((p0) << 8) | ((p1) << 16) | ((p2) << 24) | ((uint64_t)(p3) << 32) | ((uint64_t)(p4) << 40) | ((uint64_t)(p5) << 48) | ((uint64_t)(p6) << 56))
#define bi_1pin_with_name(p0, name) bi_pin_mask_with_name(1ull << (p0), name)
#define bi_2pins_with_names(p0, name0, p1, name1) bi_pin_mask_with_names((1ull << (p0)) | (1ull << (p1)), p0 < p1 ? name0 "|" name1 : name1 "|" name0)
#define bi_3pins_with_names(p0, name0, p1, name1, p2, name2) bi_pin_mask_with_names((1ull << (p0)) | (1ull << (p1)) | (1ull << (p2)),\
p0 < p1 ?\
(p1 < p2 ?\
name0 "|" name1 "|" name2:\
(p0 < p2 ? name0 "|" name2 "|" name1 : name2 "|" name0 "|" name1)):\
(p1 < p2 ?\
(p0 < p2 ? name1 "|" name0 "|" name2 : name1 "|" name2 "|" name0) :\
name2 "|" name1 "|" name0))
#define bi_4pins_with_names(p0, name0, p1, name1, p2, name2, p3, name3) bi_pin_mask_with_names((1ull << (p0)) | (1ull << (p1)) | (1ull << (p2)) | (1ull << (p3)),\
p0 < p1 ?\
(p1 < p2 ?\
(p2 < p3 ?\
name0 "|" name1 "|" name2 "|" name3:\
(p0 < p3 ?\
(p1 < p3 ?\
name0 "|" name1 "|" name3 "|" name2:\
name0 "|" name3 "|" name1 "|" name2):\
name3 "|" name0 "|" name1 "|" name2)):\
(p2 < p3 ?\
(p0 < p2 ?\
(p1 < p3 ?\
name0 "|" name2 "|" name1 "|" name3:\
name0 "|" name2 "|" name3 "|" name1):\
(p0 < p3 ?\
(p1 < p3 ?\
name2 "|" name0 "|" name1 "|" name3:\
name2 "|" name0 "|" name3 "|" name1):\
name2 "|" name3 "|" name0 "|" name1)):\
(p0 < p2 ?\
(p0 < p3 ?\
name0 "|" name3 "|" name2 "|" name1:\
name3 "|" name0 "|" name2 "|" name1):\
name3 "|" name2 "|" name0 "|" name1))):\
(p1 < p2 ?\
(p2 < p3 ?\
(p0 < p2 ?\
name1 "|" name0 "|" name2 "|" name3:\
(p0 < p3 ?\
name1 "|" name2 "|" name0 "|" name3:\
name1 "|" name2 "|" name3 "|" name0)):\
(p0 < p2 ?\
(p0 < p3 ?\
name1 "|" name0 "|" name3 "|" name2:\
(p1 < p3 ?\
name1 "|" name3 "|" name0 "|" name2:\
name3 "|" name1 "|" name0 "|" name2)):\
(p1 < p3 ?\
name1 "|" name3 "|" name2 "|" name0:\
name3 "|" name1 "|" name2 "|" name0))):\
(p2 < p3 ?\
(p0 < p3 ?\
name2 "|" name1 "|" name0 "|" name3:\
(p1 < p3 ?\
name2 "|" name1 "|" name3 "|" name0:\
name2 "|" name3 "|" name1 "|" name0)):\
name3 "|" name2 "|" name1 "|" name0)))
#endif

View file

@ -1,43 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_BINARY_INFO_DEFS_H
#define _PICO_BINARY_INFO_DEFS_H
// this file is for pre-processor definitions only
// should be found within the first 256 bytes of the real binary (i.e. after the flash second stage if a flash binary)
//
// Note the layout is:
//
// addr : BINARY_INFO_MARKER_START
// addr+0x04 : __binary_info_start
// addr+0x08 : __binary_info_end
// addr+0x0c : __address_mapping_table
// addr+0x10 | BINARY_INFO_MARKER_END
//
// __binary_info_start to __binary_info_end are the start, end (non inclusive) of an array
// of pointers to binary_info_t structures
//
// __address_mapping_table is an array of the following items:
//
// uint32_t source_addr_start
// uint32_t dest_addr_start
// uint32_t dest_addr_end
//
// representing a mapping from the stored address in the binary/flash to addresses at runtime.
// The linker will store pointers within the binary using their runtime values, however because of
// "AT" mapping in the link script these addresses actually correspond to a different address in the binary
// image. This mapping (which in the case of crt0.S is simply the data copy table used at initialization
// to copy data into its runtime location) can be used by picotool or others to reverse the mapping to find data
// within the binary.
//
// Note the above array is terminated with a NULL source_addr_start
#define BINARY_INFO_MARKER_START 0x7188ebf2
#define BINARY_INFO_MARKER_END 0xe71aa390
#endif

View file

@ -1,181 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_BINARY_INFO_STRUCTURE_H
#define _PICO_BINARY_INFO_STRUCTURE_H
// NOTE: This file may be included by non SDK code, so does not use SDK includes
// NOTE: ALL CHANGES MUST BE BACKWARDS COMPATIBLE
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#ifndef __packed
#define __packed __attribute__((packed))
#endif
typedef struct _binary_info_core binary_info_t;
#define BINARY_INFO_TYPE_RAW_DATA 1
#define BINARY_INFO_TYPE_SIZED_DATA 2
#define BINARY_INFO_TYPE_BINARY_INFO_LIST_ZERO_TERMINATED 3
#define BINARY_INFO_TYPE_BSON 4
#define BINARY_INFO_TYPE_ID_AND_INT 5
#define BINARY_INFO_TYPE_ID_AND_STRING 6
// traditional block device
#define BINARY_INFO_TYPE_BLOCK_DEVICE 7
#define BINARY_INFO_TYPE_PINS_WITH_FUNC 8
#define BINARY_INFO_TYPE_PINS_WITH_NAME 9
#define BINARY_INFO_TYPE_NAMED_GROUP 10
#define BINARY_INFO_TYPE_PTR_INT32_WITH_NAME 11
#define BINARY_INFO_TYPE_PTR_STRING_WITH_NAME 12
#define BINARY_INFO_TYPE_PINS64_WITH_FUNC 13
#define BINARY_INFO_TYPE_PINS64_WITH_NAME 14
// note plan is to reserve c1 = 0->31 for "collision tags"; i.e.
// for which you should always use random IDs with the binary_info,
// giving you 4 + 8 + 32 = 44 bits to avoid collisions
#define BINARY_INFO_MAKE_TAG(c1, c2) ((((uint)c2&0xffu)<<8u)|((uint)c1&0xffu))
// Raspberry Pi defined. do not use
#define BINARY_INFO_TAG_RASPBERRY_PI BINARY_INFO_MAKE_TAG('R','P')
#define BINARY_INFO_ID_RP_PROGRAM_NAME 0x02031c86
#define BINARY_INFO_ID_RP_PROGRAM_VERSION_STRING 0x11a9bc3a
#define BINARY_INFO_ID_RP_PROGRAM_BUILD_DATE_STRING 0x9da22254
#define BINARY_INFO_ID_RP_BINARY_END 0x68f465de
#define BINARY_INFO_ID_RP_PROGRAM_URL 0x1856239a
#define BINARY_INFO_ID_RP_PROGRAM_DESCRIPTION 0xb6a07c19
#define BINARY_INFO_ID_RP_PROGRAM_FEATURE 0xa1f4b453
#define BINARY_INFO_ID_RP_PROGRAM_BUILD_ATTRIBUTE 0x4275f0d3
#define BINARY_INFO_ID_RP_SDK_VERSION 0x5360b3ab
#define BINARY_INFO_ID_RP_PICO_BOARD 0xb63cffbb
#define BINARY_INFO_ID_RP_BOOT2_NAME 0x7f8882e1
#if PICO_ON_DEVICE
#define bi_ptr_of(x) x *
#else
#define bi_ptr_of(x) uint32_t
#endif
typedef struct __packed _binary_info_core {
uint16_t type;
uint16_t tag;
} binary_info_core_t;
typedef struct __packed _binary_info_raw_data {
struct _binary_info_core core;
uint8_t bytes[1];
} binary_info_raw_data_t;
typedef struct __packed _binary_info_sized_data {
struct _binary_info_core core;
uint32_t length;
uint8_t bytes[1];
} binary_info_sized_data_t;
typedef struct __packed _binary_info_list_zero_terminated {
struct _binary_info_core core;
bi_ptr_of(binary_info_t) list;
} binary_info_list_zero_terminated_t;
typedef struct __packed _binary_info_id_and_int {
struct _binary_info_core core;
uint32_t id;
int32_t value;
} binary_info_id_and_int_t;
typedef struct __packed _binary_info_id_and_string {
struct _binary_info_core core;
uint32_t id;
bi_ptr_of(const char) value;
} binary_info_id_and_string_t;
typedef struct __packed _binary_info_ptr_int32_with_name {
struct _binary_info_core core;
int32_t id;
bi_ptr_of(const int) value;
bi_ptr_of(const char) label;
} binary_info_ptr_int32_with_name_t;
typedef struct __packed _binary_info_ptr_string_with_name {
struct _binary_info_core core;
int32_t id;
bi_ptr_of(const char) value;
bi_ptr_of(const char) label;
uint32_t len;
} binary_info_ptr_string_with_name_t;
typedef struct __packed _binary_info_block_device {
struct _binary_info_core core;
bi_ptr_of(const char) name; // optional static name (independent of what is formatted)
uint32_t address;
uint32_t size;
bi_ptr_of(binary_info_t) extra; // additional info
uint16_t flags;
} binary_info_block_device_t;
#define BI_PINS_ENCODING_RANGE 1
#define BI_PINS_ENCODING_MULTI 2
typedef struct __packed _binary_info_pins_with_func {
struct _binary_info_core core;
// p4_5 : p3_5 : p2_5 : p1_5 : p0_5 : func_4 : 010_3 //individual pins p0,p1,p2,p3,p4 ... if fewer than 5 then duplicate p
// phi_5 : plo_5 : func_4 : 001_3 // pin range plo-phi inclusive
uint32_t pin_encoding;
} binary_info_pins_with_func_t;
typedef struct __packed _binary_info_pins64_with_func {
struct _binary_info_core core;
// p6_8 : p5_8 : p4_8 : p3_8 : p2_8 : p1_8 : p0_8 : func_5 : 010_3 //individual pins p0,p1,p2 ... if fewer than 7 then duplicate p
// phi_8 : plo_8 : func_5 : 001_3 // pin range plo-phi inclusive
uint64_t pin_encoding;
} binary_info_pins64_with_func_t;
typedef struct __packed _binary_info_pins_with_name {
struct _binary_info_core core;
uint32_t pin_mask;
bi_ptr_of(const char) label;
} binary_info_pins_with_name_t;
typedef struct __packed _binary_info_pins64_with_name {
struct _binary_info_core core;
uint64_t pin_mask;
bi_ptr_of(const char) label;
} binary_info_pins64_with_name_t;
#define BI_NAMED_GROUP_SHOW_IF_EMPTY 0x0001 // default is to hide
#define BI_NAMED_GROUP_SEPARATE_COMMAS 0x0002 // default is newlines
#define BI_NAMED_GROUP_SORT_ALPHA 0x0004 // default is no sort
#define BI_NAMED_GROUP_ADVANCED 0x0008 // if set, then only shown in say info -a
typedef struct __packed _binary_info_named_group {
struct _binary_info_core core;
uint32_t parent_id;
uint16_t flags;
uint16_t group_tag;
uint32_t group_id;
bi_ptr_of(const char) label;
} binary_info_named_group_t;
enum {
BINARY_INFO_BLOCK_DEV_FLAG_READ = 1 << 0, // if not readable, then it is basically hidden, but tools may choose to avoid overwriting it
BINARY_INFO_BLOCK_DEV_FLAG_WRITE = 1 << 1,
BINARY_INFO_BLOCK_DEV_FLAG_REFORMAT = 1 << 2, // may be reformatted..
BINARY_INFO_BLOCK_DEV_FLAG_PT_UNKNOWN = 0 << 4, // unknown free to look
BINARY_INFO_BLOCK_DEV_FLAG_PT_MBR = 1 << 4, // expect MBR
BINARY_INFO_BLOCK_DEV_FLAG_PT_GPT = 2 << 4, // expect GPT
BINARY_INFO_BLOCK_DEV_FLAG_PT_NONE = 3 << 4, // no partition table
};
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,45 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_BIT_OPS_H
#define _PICO_BIT_OPS_H
#include "pico.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \file bit_ops.h
* \defgroup pico_bit_ops pico_bit_ops
*
* \brief Optimized bit manipulation functions
*
* Additionally provides replacement implementations of the compiler built-ins __builtin_popcount, __builtin_clz
* and __bulitin_ctz
*/
/*! \brief Reverse the bits in a 32 bit word
* \ingroup pico_bit_ops
*
* \param bits 32 bit input
* \return the 32 input bits reversed
*/
uint32_t __rev(uint32_t bits);
/*! \brief Reverse the bits in a 64 bit double word
* \ingroup pico_bit_ops
*
* \param bits 64 bit input
* \return the 64 input bits reversed
*/
uint64_t __revll(uint64_t bits);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,323 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_DIVIDER_H
#define _PICO_DIVIDER_H
#include "pico.h"
#include "hardware/divider.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* \defgroup pico_divider pico_divider
* \brief Optimized 32 and 64 bit division functions accelerated by the RP2040 hardware divider
*
* Additionally provides integration with the C `/` and `%` operators
*/
/** \file pico/divider.h
* \brief High level APIs including combined quotient and remainder functions for 32 and 64 bit accelerated by the hardware divider
* \ingroup pico_divider
*
* These functions all call __aeabi_idiv0 or __aebi_ldiv0 on division by zero
* passing the largest applicably signed value
*
* Functions with unsafe in their name do not save/restore divider state, so are unsafe to call from interrupts. Unsafe functions are slightly faster.
*/
/**
* \brief Integer divide of two signed 32-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return quotient
*/
int32_t div_s32s32(int32_t a, int32_t b);
/**
* \brief Integer divide of two signed 32-bit values, with remainder
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \param [out] rem The remainder of dividend/divisor
* \return Quotient result of dividend/divisor
*/
static inline int32_t divmod_s32s32_rem(int32_t a, int32_t b, int32_t *rem) {
divmod_result_t r = hw_divider_divmod_s32(a, b);
*rem = to_remainder_s32(r);
return to_quotient_s32(r);
}
/**
* \brief Integer divide of two signed 32-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return quotient in low word/r0, remainder in high word/r1
*/
divmod_result_t divmod_s32s32(int32_t a, int32_t b);
/**
* \brief Integer divide of two unsigned 32-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return Quotient
*/
uint32_t div_u32u32(uint32_t a, uint32_t b);
/**
* \brief Integer divide of two unsigned 32-bit values, with remainder
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \param [out] rem The remainder of dividend/divisor
* \return Quotient result of dividend/divisor
*/
static inline uint32_t divmod_u32u32_rem(uint32_t a, uint32_t b, uint32_t *rem) {
divmod_result_t r = hw_divider_divmod_u32(a, b);
*rem = to_remainder_u32(r);
return to_quotient_u32(r);
}
/**
* \brief Integer divide of two unsigned 32-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return quotient in low word/r0, remainder in high word/r1
*/
divmod_result_t divmod_u32u32(uint32_t a, uint32_t b);
/**
* \brief Integer divide of two signed 64-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return Quotient
*/
int64_t div_s64s64(int64_t a, int64_t b);
/**
* \brief Integer divide of two signed 64-bit values, with remainder
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \param [out] rem The remainder of dividend/divisor
* \return Quotient result of dividend/divisor
*/
int64_t divmod_s64s64_rem(int64_t a, int64_t b, int64_t *rem);
/**
* \brief Integer divide of two signed 64-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return quotient in result (r0,r1), remainder in regs (r2, r3)
*/
int64_t divmod_s64s64(int64_t a, int64_t b);
/**
* \brief Integer divide of two unsigned 64-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return Quotient
*/
uint64_t div_u64u64(uint64_t a, uint64_t b);
/**
* \brief Integer divide of two unsigned 64-bit values, with remainder
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \param [out] rem The remainder of dividend/divisor
* \return Quotient result of dividend/divisor
*/
uint64_t divmod_u64u64_rem(uint64_t a, uint64_t b, uint64_t *rem);
/**
* \brief Integer divide of two signed 64-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return quotient in result (r0,r1), remainder in regs (r2, r3)
*/
uint64_t divmod_u64u64(uint64_t a, uint64_t b);
// -----------------------------------------------------------------------
// these "unsafe" functions are slightly faster, but do not save the divider state,
// so are not generally safe to be called from interrupts
// -----------------------------------------------------------------------
/**
* \brief Unsafe integer divide of two signed 32-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return quotient
*
* Do not use in interrupts
*/
int32_t div_s32s32_unsafe(int32_t a, int32_t b);
/**
* \brief Unsafe integer divide of two signed 32-bit values, with remainder
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \param [out] rem The remainder of dividend/divisor
* \return Quotient result of dividend/divisor
*
* Do not use in interrupts
*/
int32_t divmod_s32s32_rem_unsafe(int32_t a, int32_t b, int32_t *rem);
/**
* \brief Unsafe integer divide of two unsigned 32-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return quotient in low word/r0, remainder in high word/r1
*
* Do not use in interrupts
*/
divmod_result_t divmod_s32s32_unsafe(int32_t a, int32_t b);
/**
* \brief Unsafe integer divide of two unsigned 32-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return Quotient
*
* Do not use in interrupts
*/
uint32_t div_u32u32_unsafe(uint32_t a, uint32_t b);
/**
* \brief Unsafe integer divide of two unsigned 32-bit values, with remainder
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \param [out] rem The remainder of dividend/divisor
* \return Quotient result of dividend/divisor
*
* Do not use in interrupts
*/
uint32_t divmod_u32u32_rem_unsafe(uint32_t a, uint32_t b, uint32_t *rem);
/**
* \brief Unsafe integer divide of two unsigned 32-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return quotient in low word/r0, remainder in high word/r1
*
* Do not use in interrupts
*/
divmod_result_t divmod_u32u32_unsafe(uint32_t a, uint32_t b);
/**
* \brief Unsafe integer divide of two signed 64-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return Quotient
*
* Do not use in interrupts
*/
int64_t div_s64s64_unsafe(int64_t a, int64_t b);
/**
* \brief Unsafe integer divide of two signed 64-bit values, with remainder
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \param [out] rem The remainder of dividend/divisor
* \return Quotient result of dividend/divisor
*
* Do not use in interrupts
*/
int64_t divmod_s64s64_rem_unsafe(int64_t a, int64_t b, int64_t *rem);
/**
* \brief Unsafe integer divide of two signed 64-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return quotient in result (r0,r1), remainder in regs (r2, r3)
*
* Do not use in interrupts
*/
int64_t divmod_s64s64_unsafe(int64_t a, int64_t b);
/**
* \brief Unsafe integer divide of two unsigned 64-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return Quotient
*
* Do not use in interrupts
*/
uint64_t div_u64u64_unsafe(uint64_t a, uint64_t b);
/**
* \brief Unsafe integer divide of two unsigned 64-bit values, with remainder
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \param [out] rem The remainder of dividend/divisor
* \return Quotient result of dividend/divisor
*
* Do not use in interrupts
*/
uint64_t divmod_u64u64_rem_unsafe(uint64_t a, uint64_t b, uint64_t *rem);
/**
* \brief Unsafe integer divide of two signed 64-bit values
* \ingroup pico_divider
*
* \param a Dividend
* \param b Divisor
* \return quotient in result (r0,r1), remainder in regs (r2, r3)
*
* Do not use in interrupts
*/
uint64_t divmod_u64u64_unsafe(uint64_t a, uint64_t b);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,90 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_STDLIB_H
#define _PICO_STDLIB_H
#include "pico.h"
#include "pico/stdio.h"
#include "pico/time.h"
#include "hardware/gpio.h"
#include "hardware/uart.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \file stdlib.h
* \defgroup pico_stdlib pico_stdlib
*
* \brief Aggregation of a core subset of Raspberry Pi Pico SDK libraries used by most executables along with some additional
* utility methods
*
* Including pico_stdlib gives you everything you need to get a basic program running
* which prints to stdout or flashes a LED
*
* This library aggregates:
* - @ref hardware_divider
* - @ref hardware_gpio
* - @ref hardware_uart
* - @ref pico_runtime
* - @ref pico_platform
* - @ref pico_stdio
* - @ref pico_time
* - @ref pico_util
*
* There are some basic default values used by these functions that will default to
* usable values, however, they can be customised in a board definition header via
* config.h or similar
*/
// Note PICO_STDIO_UART, PICO_STDIO_USB, PICO_STDIO_SEMIHOSTING are set by the
// respective INTERFACE libraries, so these defines are set if the library
// is included for the target executable
#if LIB_PICO_STDIO_UART
#include "pico/stdio_uart.h"
#endif
#if LIB_PICO_STDIO_USB
#include "pico/stdio_usb.h"
#endif
#if LIB_PICO_STDIO_SEMIHOSTING
#include "pico/stdio_semihosting.h"
#endif
// PICO_CONFIG: PICO_DEFAULT_LED_PIN, Optionally define a pin that drives a regular LED on the board, default=Usually provided via board header, group=pico_stdlib
// PICO_CONFIG: PICO_DEFAULT_LED_PIN_INVERTED, 1 if LED is inverted or 0 if not, type=int, default=0, group=pico_stdlib
#ifndef PICO_DEFAULT_LED_PIN_INVERTED
#define PICO_DEFAULT_LED_PIN_INVERTED 0
#endif
// PICO_CONFIG: PICO_DEFAULT_WS2812_PIN, Optionally define a pin that controls data to a WS2812 compatible LED on the board, group=pico_stdlib
// PICO_CONFIG: PICO_DEFAULT_WS2812_POWER_PIN, Optionally define a pin that controls power to a WS2812 compatible LED on the board, group=pico_stdlib
/*! \brief Set up the default UART and assign it to the default GPIOs
* \ingroup pico_stdlib
*
* By default this will use UART 0, with TX to pin GPIO 0,
* RX to pin GPIO 1, and the baudrate to 115200
*
* Calling this method also initializes stdin/stdout over UART if the
* @ref pico_stdio_uart library is linked.
*
* Defaults can be changed using configuration defines,
* PICO_DEFAULT_UART_INSTANCE,
* PICO_DEFAULT_UART_BAUD_RATE
* PICO_DEFAULT_UART_TX_PIN
* PICO_DEFAULT_UART_RX_PIN
*/
void setup_default_uart(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,25 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/critical_section.h"
#if PICO_32BIT
static_assert(sizeof(critical_section_t) == 8, "");
#endif
void critical_section_init(critical_section_t *crit_sec) {
critical_section_init_with_lock_num(crit_sec, (uint)spin_lock_claim_unused(true));
}
void critical_section_init_with_lock_num(critical_section_t *crit_sec, uint lock_num) {
crit_sec->spin_lock = spin_lock_instance(lock_num);
__mem_fence_release();
}
void critical_section_deinit(critical_section_t *crit_sec) {
spin_lock_unclaim(spin_lock_get_num(crit_sec->spin_lock));
crit_sec->spin_lock = NULL;
}

View file

@ -1,98 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_CRITICAL_SECTION_H
#define _PICO_CRITICAL_SECTION_H
#include "pico/lock_core.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \file critical_section.h
* \defgroup critical_section critical_section
* \ingroup pico_sync
* \brief Critical Section API for short-lived mutual exclusion safe for IRQ and multi-core
*
* A critical section is non-reentrant, and provides mutual exclusion using a spin-lock to prevent access
* from the other core, and from (higher priority) interrupts on the same core. It does the former
* using a spin lock and the latter by disabling interrupts on the calling core.
*
* Because interrupts are disabled when a critical_section is owned, uses of the critical_section
* should be as short as possible.
*/
typedef struct __packed_aligned critical_section {
spin_lock_t *spin_lock;
uint32_t save;
} critical_section_t;
/*! \brief Initialise a critical_section structure allowing the system to assign a spin lock number
* \ingroup critical_section
*
* The critical section is initialized ready for use, and will use a (possibly shared) spin lock
* number assigned by the system. Note that in general it is unlikely that you would be nesting
* critical sections, however if you do so you *must* use \ref critical_section_init_with_lock_num
* to ensure that the spin locks used are different.
*
* \param crit_sec Pointer to critical_section structure
*/
void critical_section_init(critical_section_t *crit_sec);
/*! \brief Initialise a critical_section structure assigning a specific spin lock number
* \ingroup critical_section
* \param crit_sec Pointer to critical_section structure
* \param lock_num the specific spin lock number to use
*/
void critical_section_init_with_lock_num(critical_section_t *crit_sec, uint lock_num);
/*! \brief Enter a critical_section
* \ingroup critical_section
*
* If the spin lock associated with this critical section is in use, then this
* method will block until it is released.
*
* \param crit_sec Pointer to critical_section structure
*/
static inline void critical_section_enter_blocking(critical_section_t *crit_sec) {
crit_sec->save = spin_lock_blocking(crit_sec->spin_lock);
}
/*! \brief Release a critical_section
* \ingroup critical_section
*
* \param crit_sec Pointer to critical_section structure
*/
static inline void critical_section_exit(critical_section_t *crit_sec) {
spin_unlock(crit_sec->spin_lock, crit_sec->save);
}
/*! \brief De-Initialise a critical_section created by the critical_section_init method
* \ingroup critical_section
*
* This method is only used to free the associated spin lock allocated via
* the critical_section_init method (it should not be used to de-initialize a spin lock
* created via critical_section_init_with_lock_num). After this call, the critical section is invalid
*
* \param crit_sec Pointer to critical_section structure
*/
void critical_section_deinit(critical_section_t *crit_sec);
/*! \brief Test whether a critical_section has been initialized
* \ingroup mutex
*
* \param crit_sec Pointer to critical_section structure
* \return true if the critical section is initialized, false otherwise
*/
static inline bool critical_section_is_initialized(critical_section_t *crit_sec) {
return crit_sec->spin_lock != 0;
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,199 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_LOCK_CORE_H
#define _PICO_LOCK_CORE_H
#include "pico.h"
#include "pico/time.h"
#include "hardware/sync.h"
/** \file lock_core.h
* \defgroup lock_core lock_core
* \ingroup pico_sync
* \brief base synchronization/lock primitive support.
*
* Most of the pico_sync locking primitives contain a lock_core_t structure member. This currently just holds a spin
* lock which is used only to protect the contents of the rest of the structure as part of implementing the synchronization
* primitive. As such, the spin_lock member of lock core is never still held on return from any function for the primitive.
*
* \ref critical_section is an exceptional case in that it does not have a lock_core_t and simply wraps a spin lock, providing
* methods to lock and unlock said spin lock.
*
* lock_core based structures work by locking the spin lock, checking state, and then deciding whether they additionally need to block
* or notify when the spin lock is released. In the blocking case, they will wake up again in the future, and try the process again.
*
* By default the SDK just uses the processors' events via SEV and WEV for notification and blocking as these are sufficient for
* cross core, and notification from interrupt handlers. However macros are defined in this file that abstract the wait
* and notify mechanisms to allow the SDK locking functions to effectively be used within an RTOS or other environment.
*
* When implementing an RTOS, it is desirable for the SDK synchronization primitives that wait, to block the calling task (and immediately yield),
* and those that notify, to wake a blocked task which isn't on processor. At least the wait macro implementation needs to be atomic with the protecting
* spin_lock unlock from the callers point of view; i.e. the task should unlock the spin lock when it starts its wait. Such implementation is
* up to the RTOS integration, however the macros are defined such that such operations are always combined into a single call
* (so they can be performed atomically) even though the default implementation does not need this, as a WFE which starts
* following the corresponding SEV is not missed.
*/
// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_LOCK_CORE, Enable/disable assertions in the lock core, type=bool, default=0, group=pico_sync
#ifndef PARAM_ASSERTIONS_ENABLED_LOCK_CORE
#define PARAM_ASSERTIONS_ENABLED_LOCK_CORE 0
#endif
/** \file lock_core.h
* \ingroup lock_core
*
* Base implementation for locking primitives protected by a spin lock. The spin lock is only used to protect
* access to the remaining lock state (in primitives using lock_core); it is never left locked outside
* of the function implementations
*/
struct lock_core {
// spin lock protecting this lock's state
spin_lock_t *spin_lock;
// note any lock members in containing structures need not be volatile;
// they are protected by memory/compiler barriers when gaining and release spin locks
};
typedef struct lock_core lock_core_t;
/*! \brief Initialise a lock structure
* \ingroup lock_core
*
* Inititalize a lock structure, providing the spin lock number to use for protecting internal state.
*
* \param core Pointer to the lock_core to initialize
* \param lock_num Spin lock number to use for the lock. As the spin lock is only used internally to the locking primitive
* method implementations, this does not need to be globally unique, however could suffer contention
*/
void lock_init(lock_core_t *core, uint lock_num);
#ifndef lock_owner_id_t
/*! \brief type to use to store the 'owner' of a lock.
* \ingroup lock_core
*
* By default this is int8_t as it only needs to store the core number or -1, however it may be
* overridden if a larger type is required (e.g. for an RTOS task id)
*/
#define lock_owner_id_t int8_t
#endif
#ifndef LOCK_INVALID_OWNER_ID
/*! \brief marker value to use for a lock_owner_id_t which does not refer to any valid owner
* \ingroup lock_core
*/
#define LOCK_INVALID_OWNER_ID ((lock_owner_id_t)-1)
#endif
#ifndef lock_get_caller_owner_id
/*! \brief return the owner id for the caller
* \ingroup lock_core
*
* By default this returns the calling core number, but may be overridden (e.g. to return an RTOS task id)
*/
#define lock_get_caller_owner_id() ((lock_owner_id_t)get_core_num())
#ifndef lock_is_owner_id_valid
#define lock_is_owner_id_valid(id) ((id)>=0)
#endif
#endif
#ifndef lock_is_owner_id_valid
#define lock_is_owner_id_valid(id) ((id) != LOCK_INVALID_OWNER_ID)
#endif
#ifndef lock_internal_spin_unlock_with_wait
/*! \brief Atomically unlock the lock's spin lock, and wait for a notification.
* \ingroup lock_core
*
* _Atomic_ here refers to the fact that it should not be possible for a concurrent lock_internal_spin_unlock_with_notify
* to insert itself between the spin unlock and this wait in a way that the wait does not see the notification (i.e. causing
* a missed notification). In other words this method should always wake up in response to a lock_internal_spin_unlock_with_notify
* for the same lock, which completes after this call starts.
*
* In an ideal implementation, this method would return exactly after the corresponding lock_internal_spin_unlock_with_notify
* has subsequently been called on the same lock instance, however this method is free to return at _any_ point before that;
* this macro is _always_ used in a loop which locks the spin lock, checks the internal locking primitive state and then
* waits again if the calling thread should not proceed.
*
* By default this macro simply unlocks the spin lock, and then performs a WFE, but may be overridden
* (e.g. to actually block the RTOS task).
*
* \param lock the lock_core for the primitive which needs to block
* \param save the uint32_t value that should be passed to spin_unlock when the spin lock is unlocked. (i.e. the `PRIMASK`
* state when the spin lock was acquire
*/
#define lock_internal_spin_unlock_with_wait(lock, save) spin_unlock((lock)->spin_lock, save), __wfe()
#endif
#ifndef lock_internal_spin_unlock_with_notify
/*! \brief Atomically unlock the lock's spin lock, and send a notification
* \ingroup lock_core
*
* _Atomic_ here refers to the fact that it should not be possible for this notification to happen during a
* lock_internal_spin_unlock_with_wait in a way that that wait does not see the notification (i.e. causing
* a missed notification). In other words this method should always wake up any lock_internal_spin_unlock_with_wait
* which started before this call completes.
*
* In an ideal implementation, this method would wake up only the corresponding lock_internal_spin_unlock_with_wait
* that has been called on the same lock instance, however it is free to wake up any of them, as they will check
* their condition and then re-wait if necessary/
*
* By default this macro simply unlocks the spin lock, and then performs a SEV, but may be overridden
* (e.g. to actually un-block RTOS task(s)).
*
* \param lock the lock_core for the primitive which needs to block
* \param save the uint32_t value that should be passed to spin_unlock when the spin lock is unlocked. (i.e. the PRIMASK
* state when the spin lock was acquire)
*/
#define lock_internal_spin_unlock_with_notify(lock, save) spin_unlock((lock)->spin_lock, save), __sev()
#endif
#ifndef lock_internal_spin_unlock_with_best_effort_wait_or_timeout
/*! \brief Atomically unlock the lock's spin lock, and wait for a notification or a timeout
* \ingroup lock_core
*
* _Atomic_ here refers to the fact that it should not be possible for a concurrent lock_internal_spin_unlock_with_notify
* to insert itself between the spin unlock and this wait in a way that the wait does not see the notification (i.e. causing
* a missed notification). In other words this method should always wake up in response to a lock_internal_spin_unlock_with_notify
* for the same lock, which completes after this call starts.
*
* In an ideal implementation, this method would return exactly after the corresponding lock_internal_spin_unlock_with_notify
* has subsequently been called on the same lock instance or the timeout has been reached, however this method is free to return
* at _any_ point before that; this macro is _always_ used in a loop which locks the spin lock, checks the internal locking
* primitive state and then waits again if the calling thread should not proceed.
*
* By default this simply unlocks the spin lock, and then calls \ref best_effort_wfe_or_timeout
* but may be overridden (e.g. to actually block the RTOS task with a timeout).
*
* \param lock the lock_core for the primitive which needs to block
* \param save the uint32_t value that should be passed to spin_unlock when the spin lock is unlocked. (i.e. the PRIMASK
* state when the spin lock was acquire)
* \param until the \ref absolute_time_t value
* \return true if the timeout has been reached
*/
#define lock_internal_spin_unlock_with_best_effort_wait_or_timeout(lock, save, until) ({ \
spin_unlock((lock)->spin_lock, save); \
best_effort_wfe_or_timeout(until); \
})
#endif
#ifndef sync_internal_yield_until_before
/*! \brief yield to other processing until some time before the requested time
* \ingroup lock_core
*
* This method is provided for cases where the caller has no useful work to do
* until the specified time.
*
* By default this method does nothing, however it can be overridden (for example by an
* RTOS which is able to block the current task until the scheduler tick before
* the given time)
*
* \param until the \ref absolute_time_t value
*/
#define sync_internal_yield_until_before(until) ((void)0)
#endif
#endif

View file

@ -1,313 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_MUTEX_H
#define _PICO_MUTEX_H
#include "pico/lock_core.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \file mutex.h
* \defgroup mutex mutex
* \ingroup pico_sync
* \brief Mutex API for non IRQ mutual exclusion between cores
*
* Mutexes are application level locks usually used protecting data structures that might be used by
* multiple threads of execution. Unlike critical sections, the mutex protected code is not necessarily
* required/expected to complete quickly, as no other system wide locks are held on account of an acquired mutex.
*
* When acquired, the mutex has an owner (see \ref lock_get_caller_owner_id) which with the plain SDK is just
* the acquiring core, but in an RTOS it could be a task, or an IRQ handler context.
*
* Two variants of mutex are provided; \ref mutex_t (and associated mutex_ functions) is a regular mutex that cannot
* be acquired recursively by the same owner (a deadlock will occur if you try). \ref recursive_mutex_t
* (and associated recursive_mutex_ functions) is a recursive mutex that can be recursively obtained by
* the same caller, at the expense of some more overhead when acquiring and releasing.
*
* It is generally a bad idea to call blocking mutex_ or recursive_mutex_ functions from within an IRQ handler.
* It is valid to call \ref mutex_try_enter or \ref recursive_mutex_try_enter from within an IRQ handler, if the operation
* that would be conducted under lock can be skipped if the mutex is locked (at least by the same owner).
*
* NOTE: For backwards compatibility with version 1.2.0 of the SDK, if the define
* PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY is set to 1, then the the regular mutex_ functions
* may also be used for recursive mutexes. This flag will be removed in a future version of the SDK.
*
* See \ref critical_section.h for protecting access between multiple cores AND IRQ handlers
*/
/*! \brief recursive mutex instance
* \ingroup mutex
*/
typedef struct {
lock_core_t core;
lock_owner_id_t owner; //! owner id LOCK_INVALID_OWNER_ID for unowned
uint8_t enter_count; //! ownership count
#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
bool recursive;
#endif
} recursive_mutex_t;
/*! \brief regular (non recursive) mutex instance
* \ingroup mutex
*/
#if !PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
typedef struct mutex {
lock_core_t core;
lock_owner_id_t owner; //! owner id LOCK_INVALID_OWNER_ID for unowned
} mutex_t;
#else
typedef recursive_mutex_t mutex_t; // they are one and the same when backwards compatible with SDK1.2.0
#endif
/*! \brief Initialise a mutex structure
* \ingroup mutex
*
* \param mtx Pointer to mutex structure
*/
void mutex_init(mutex_t *mtx);
/*! \brief Initialise a recursive mutex structure
* \ingroup mutex
*
* A recursive mutex may be entered in a nested fashion by the same owner
*
* \param mtx Pointer to recursive mutex structure
*/
void recursive_mutex_init(recursive_mutex_t *mtx);
/*! \brief Take ownership of a mutex
* \ingroup mutex
*
* This function will block until the caller can be granted ownership of the mutex.
* On return the caller owns the mutex
*
* \param mtx Pointer to mutex structure
*/
void mutex_enter_blocking(mutex_t *mtx);
/*! \brief Take ownership of a recursive mutex
* \ingroup mutex
*
* This function will block until the caller can be granted ownership of the mutex.
* On return the caller owns the mutex
*
* \param mtx Pointer to recursive mutex structure
*/
void recursive_mutex_enter_blocking(recursive_mutex_t *mtx);
/*! \brief Attempt to take ownership of a mutex
* \ingroup mutex
*
* If the mutex wasn't owned, this will claim the mutex for the caller and return true.
* Otherwise (if the mutex was already owned) this will return false and the
* caller will NOT own the mutex.
*
* \param mtx Pointer to mutex structure
* \param owner_out If mutex was already owned, and this pointer is non-zero, it will be filled in with the owner id of the current owner of the mutex
* \return true if mutex now owned, false otherwise
*/
bool mutex_try_enter(mutex_t *mtx, uint32_t *owner_out);
/*! \brief Attempt to take ownership of a mutex until the specified time
* \ingroup mutex
*
* If the mutex wasn't owned, this method will immediately claim the mutex for the caller and return true.
* If the mutex is owned by the caller, this method will immediately return false,
* If the mutex is owned by someone else, this method will try to claim it until the specified time, returning
* true if it succeeds, or false on timeout
*
* \param mtx Pointer to mutex structure
* \param until The time after which to return if the caller cannot be granted ownership of the mutex
* \return true if mutex now owned, false otherwise
*/
bool mutex_try_enter_block_until(mutex_t *mtx, absolute_time_t until);
/*! \brief Attempt to take ownership of a recursive mutex
* \ingroup mutex
*
* If the mutex wasn't owned or was owned by the caller, this will claim the mutex and return true.
* Otherwise (if the mutex was already owned by another owner) this will return false and the
* caller will NOT own the mutex.
*
* \param mtx Pointer to recursive mutex structure
* \param owner_out If mutex was already owned by another owner, and this pointer is non-zero,
* it will be filled in with the owner id of the current owner of the mutex
* \return true if the recursive mutex (now) owned, false otherwise
*/
bool recursive_mutex_try_enter(recursive_mutex_t *mtx, uint32_t *owner_out);
/*! \brief Wait for mutex with timeout
* \ingroup mutex
*
* Wait for up to the specific time to take ownership of the mutex. If the caller
* can be granted ownership of the mutex before the timeout expires, then true will be returned
* and the caller will own the mutex, otherwise false will be returned and the caller will NOT own the mutex.
*
* \param mtx Pointer to mutex structure
* \param timeout_ms The timeout in milliseconds.
* \return true if mutex now owned, false if timeout occurred before ownership could be granted
*/
bool mutex_enter_timeout_ms(mutex_t *mtx, uint32_t timeout_ms);
/*! \brief Wait for recursive mutex with timeout
* \ingroup mutex
*
* Wait for up to the specific time to take ownership of the recursive mutex. If the caller
* already has ownership of the mutex or can be granted ownership of the mutex before the timeout expires,
* then true will be returned and the caller will own the mutex, otherwise false will be returned and the caller
* will NOT own the mutex.
*
* \param mtx Pointer to recursive mutex structure
* \param timeout_ms The timeout in milliseconds.
* \return true if the recursive mutex (now) owned, false if timeout occurred before ownership could be granted
*/
bool recursive_mutex_enter_timeout_ms(recursive_mutex_t *mtx, uint32_t timeout_ms);
/*! \brief Wait for mutex with timeout
* \ingroup mutex
*
* Wait for up to the specific time to take ownership of the mutex. If the caller
* can be granted ownership of the mutex before the timeout expires, then true will be returned
* and the caller will own the mutex, otherwise false will be returned and the caller
* will NOT own the mutex.
*
* \param mtx Pointer to mutex structure
* \param timeout_us The timeout in microseconds.
* \return true if mutex now owned, false if timeout occurred before ownership could be granted
*/
bool mutex_enter_timeout_us(mutex_t *mtx, uint32_t timeout_us);
/*! \brief Wait for recursive mutex with timeout
* \ingroup mutex
*
* Wait for up to the specific time to take ownership of the recursive mutex. If the caller
* already has ownership of the mutex or can be granted ownership of the mutex before the timeout expires,
* then true will be returned and the caller will own the mutex, otherwise false will be returned and the caller
* will NOT own the mutex.
*
* \param mtx Pointer to mutex structure
* \param timeout_us The timeout in microseconds.
* \return true if the recursive mutex (now) owned, false if timeout occurred before ownership could be granted
*/
bool recursive_mutex_enter_timeout_us(recursive_mutex_t *mtx, uint32_t timeout_us);
/*! \brief Wait for mutex until a specific time
* \ingroup mutex
*
* Wait until the specific time to take ownership of the mutex. If the caller
* can be granted ownership of the mutex before the timeout expires, then true will be returned
* and the caller will own the mutex, otherwise false will be returned and the caller
* will NOT own the mutex.
*
* \param mtx Pointer to mutex structure
* \param until The time after which to return if the caller cannot be granted ownership of the mutex
* \return true if mutex now owned, false if timeout occurred before ownership could be granted
*/
bool mutex_enter_block_until(mutex_t *mtx, absolute_time_t until);
/*! \brief Wait for mutex until a specific time
* \ingroup mutex
*
* Wait until the specific time to take ownership of the mutex. If the caller
* already has ownership of the mutex or can be granted ownership of the mutex before the timeout expires,
* then true will be returned and the caller will own the mutex, otherwise false will be returned and the caller
* will NOT own the mutex.
*
* \param mtx Pointer to recursive mutex structure
* \param until The time after which to return if the caller cannot be granted ownership of the mutex
* \return true if the recursive mutex (now) owned, false if timeout occurred before ownership could be granted
*/
bool recursive_mutex_enter_block_until(recursive_mutex_t *mtx, absolute_time_t until);
/*! \brief Release ownership of a mutex
* \ingroup mutex
*
* \param mtx Pointer to mutex structure
*/
void mutex_exit(mutex_t *mtx);
/*! \brief Release ownership of a recursive mutex
* \ingroup mutex
*
* \param mtx Pointer to recursive mutex structure
*/
void recursive_mutex_exit(recursive_mutex_t *mtx);
/*! \brief Test for mutex initialized state
* \ingroup mutex
*
* \param mtx Pointer to mutex structure
* \return true if the mutex is initialized, false otherwise
*/
static inline bool mutex_is_initialized(mutex_t *mtx) {
return mtx->core.spin_lock != 0;
}
/*! \brief Test for recursive mutex initialized state
* \ingroup mutex
*
* \param mtx Pointer to recursive mutex structure
* \return true if the recursive mutex is initialized, false otherwise
*/
static inline bool recursive_mutex_is_initialized(recursive_mutex_t *mtx) {
return mtx->core.spin_lock != 0;
}
/*! \brief Helper macro for static definition of mutexes
* \ingroup mutex
*
* A mutex defined as follows:
*
* ```c
* auto_init_mutex(my_mutex);
* ```
*
* Is equivalent to doing
*
* ```c
* static mutex_t my_mutex;
*
* void my_init_function() {
* mutex_init(&my_mutex);
* }
* ```
*
* But the initialization of the mutex is performed automatically during runtime initialization
*/
#define auto_init_mutex(name) static __attribute__((section(".mutex_array"))) mutex_t name
/*! \brief Helper macro for static definition of recursive mutexes
* \ingroup mutex
*
* A recursive mutex defined as follows:
*
* ```c
* auto_init_recursive_mutex(my_recursive_mutex);
* ```
*
* Is equivalent to doing
*
* ```c
* static recursive_mutex_t my_recursive_mutex;
*
* void my_init_function() {
* recursive_mutex_init(&my_recursive_mutex);
* }
* ```
*
* But the initialization of the mutex is performed automatically during runtime initialization
*/
#define auto_init_recursive_mutex(name) static __attribute__((section(".mutex_array"))) recursive_mutex_t name = { .core = { .spin_lock = (spin_lock_t *)1 /* marker for runtime_init */ }, .owner = 0, .enter_count = 0 }
void runtime_init_mutex(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,139 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_SEM_H
#define _PICO_SEM_H
#include "pico/lock_core.h"
/** \file sem.h
* \defgroup sem sem
* \ingroup pico_sync
* \brief Semaphore API for restricting access to a resource
*
* A semaphore holds a number of available permits. `sem_acquire` methods will acquire a permit if available
* (reducing the available count by 1) or block if the number of available permits is 0.
* \ref sem_release() increases the number of available permits by one potentially unblocking a `sem_acquire` method.
*
* Note that \ref sem_release() may be called an arbitrary number of times, however the number of available
* permits is capped to the max_permit value specified during semaphore initialization.
*
* Although these semaphore related functions can be used from IRQ handlers, it is obviously preferable to only
* release semaphores from within an IRQ handler (i.e. avoid blocking)
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct semaphore {
struct lock_core core;
int16_t permits;
int16_t max_permits;
} semaphore_t;
/*! \brief Initialise a semaphore structure
* \ingroup sem
*
* \param sem Pointer to semaphore structure
* \param initial_permits How many permits are initially acquired
* \param max_permits Total number of permits allowed for this semaphore
*/
void sem_init(semaphore_t *sem, int16_t initial_permits, int16_t max_permits);
/*! \brief Return number of available permits on the semaphore
* \ingroup sem
*
* \param sem Pointer to semaphore structure
* \return The number of permits available on the semaphore.
*/
int sem_available(semaphore_t *sem);
/*! \brief Release a permit on a semaphore
* \ingroup sem
*
* Increases the number of permits by one (unless the number of permits is already at the maximum).
* A blocked `sem_acquire` will be released if the number of permits is increased.
*
* \param sem Pointer to semaphore structure
* \return true if the number of permits available was increased.
*/
bool sem_release(semaphore_t *sem);
/*! \brief Reset semaphore to a specific number of available permits
* \ingroup sem
*
* Reset value should be from 0 to the max_permits specified in the init function
*
* \param sem Pointer to semaphore structure
* \param permits the new number of available permits
*/
void sem_reset(semaphore_t *sem, int16_t permits);
/*! \brief Acquire a permit from the semaphore
* \ingroup sem
*
* This function will block and wait if no permits are available.
*
* \param sem Pointer to semaphore structure
*/
void sem_acquire_blocking(semaphore_t *sem);
/*! \brief Acquire a permit from a semaphore, with timeout
* \ingroup sem
*
* This function will block and wait if no permits are available, until the
* defined timeout has been reached. If the timeout is reached the function will
* return false, otherwise it will return true.
*
* \param sem Pointer to semaphore structure
* \param timeout_ms Time to wait to acquire the semaphore, in milliseconds.
* \return false if timeout reached, true if permit was acquired.
*/
bool sem_acquire_timeout_ms(semaphore_t *sem, uint32_t timeout_ms);
/*! \brief Acquire a permit from a semaphore, with timeout
* \ingroup sem
*
* This function will block and wait if no permits are available, until the
* defined timeout has been reached. If the timeout is reached the function will
* return false, otherwise it will return true.
*
* \param sem Pointer to semaphore structure
* \param timeout_us Time to wait to acquire the semaphore, in microseconds.
* \return false if timeout reached, true if permit was acquired.
*/
bool sem_acquire_timeout_us(semaphore_t *sem, uint32_t timeout_us);
/*! \brief Wait to acquire a permit from a semaphore until a specific time
* \ingroup sem
*
* This function will block and wait if no permits are available, until the
* specified timeout time. If the timeout is reached the function will
* return false, otherwise it will return true.
*
* \param sem Pointer to semaphore structure
* \param until The time after which to return if the sem is not available.
* \return true if permit was acquired, false if the until time was reached before
* acquiring.
*/
bool sem_acquire_block_until(semaphore_t *sem, absolute_time_t until);
/*! \brief Attempt to acquire a permit from a semaphore without blocking
* \ingroup sem
*
* This function will return false without blocking if no permits are
* available, otherwise it will acquire a permit and return true.
*
* \param sem Pointer to semaphore structure
* \return true if permit was acquired.
*/
bool sem_try_acquire(semaphore_t *sem);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,19 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_SYNC_H
#define _PICO_SYNC_H
/** \file pico/sync.h
* \defgroup pico_sync pico_sync
* \brief Synchronization primitives and mutual exclusion
*/
#include "pico/sem.h"
#include "pico/mutex.h"
#include "pico/critical_section.h"
#endif

View file

@ -1,13 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/lock_core.h"
void lock_init(lock_core_t *core, uint lock_num) {
valid_params_if(LOCK_CORE, lock_num < NUM_SPIN_LOCKS);
core->spin_lock = spin_lock_instance(lock_num);
}

View file

@ -1,228 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/mutex.h"
#include "pico/time.h"
#include "pico/runtime_init.h"
#if !PICO_RUNTIME_NO_INIT_MUTEX
void __weak runtime_init_mutex(void) {
// this is an array of either mutex_t or recursive_mutex_t (i.e. not necessarily the same size)
// however each starts with a lock_core_t, and the spin_lock is initialized to address 1 for a recursive
// spinlock and 0 for a regular one.
static_assert(!(sizeof(mutex_t)&3), "");
static_assert(!(sizeof(recursive_mutex_t)&3), "");
static_assert(!offsetof(mutex_t, core), "");
static_assert(!offsetof(recursive_mutex_t, core), "");
extern lock_core_t __mutex_array_start;
extern lock_core_t __mutex_array_end;
for (lock_core_t *l = &__mutex_array_start; l < &__mutex_array_end; ) {
if (l->spin_lock) {
assert(1 == (uintptr_t)l->spin_lock); // indicator for a recursive mutex
recursive_mutex_t *rm = (recursive_mutex_t *)l;
recursive_mutex_init(rm);
l = &rm[1].core; // next
} else {
mutex_t *m = (mutex_t *)l;
mutex_init(m);
l = &m[1].core; // next
}
}
}
#endif
#if defined(PICO_RUNTIME_INIT_MUTEX) && !PICO_RUNTIME_SKIP_INIT_MUTEX
PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_mutex, PICO_RUNTIME_INIT_MUTEX);
#endif
void mutex_init(mutex_t *mtx) {
lock_init(&mtx->core, next_striped_spin_lock_num());
mtx->owner = LOCK_INVALID_OWNER_ID;
#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
mtx->recursive = false;
#endif
__mem_fence_release();
}
void recursive_mutex_init(recursive_mutex_t *mtx) {
lock_init(&mtx->core, next_striped_spin_lock_num());
mtx->owner = LOCK_INVALID_OWNER_ID;
mtx->enter_count = 0;
#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
mtx->recursive = true;
#endif
__mem_fence_release();
}
void __time_critical_func(mutex_enter_blocking)(mutex_t *mtx) {
#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
if (mtx->recursive) {
recursive_mutex_enter_blocking(mtx);
return;
}
#endif
lock_owner_id_t caller = lock_get_caller_owner_id();
do {
uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
if (!lock_is_owner_id_valid(mtx->owner)) {
mtx->owner = caller;
spin_unlock(mtx->core.spin_lock, save);
break;
}
lock_internal_spin_unlock_with_wait(&mtx->core, save);
} while (true);
}
void __time_critical_func(recursive_mutex_enter_blocking)(recursive_mutex_t *mtx) {
lock_owner_id_t caller = lock_get_caller_owner_id();
do {
uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
if (mtx->owner == caller || !lock_is_owner_id_valid(mtx->owner)) {
mtx->owner = caller;
uint __unused total = ++mtx->enter_count;
spin_unlock(mtx->core.spin_lock, save);
assert(total); // check for overflow
return;
} else {
lock_internal_spin_unlock_with_wait(&mtx->core, save);
}
} while (true);
}
bool __time_critical_func(mutex_try_enter)(mutex_t *mtx, uint32_t *owner_out) {
#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
if (mtx->recursive) {
return recursive_mutex_try_enter(mtx, owner_out);
}
#endif
bool entered;
uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
if (!lock_is_owner_id_valid(mtx->owner)) {
mtx->owner = lock_get_caller_owner_id();
entered = true;
} else {
if (owner_out) *owner_out = (uint32_t) mtx->owner;
entered = false;
}
spin_unlock(mtx->core.spin_lock, save);
return entered;
}
bool __time_critical_func(mutex_try_enter_block_until)(mutex_t *mtx, absolute_time_t until) {
// not using lock_owner_id_t to avoid backwards incompatibility change to mutex_try_enter API
static_assert(sizeof(lock_owner_id_t) <= 4, "");
uint32_t owner;
if (!mutex_try_enter(mtx, &owner)) {
if ((lock_owner_id_t)owner == lock_get_caller_owner_id()) return false; // deadlock, so we can never own it
return mutex_enter_block_until(mtx, until);
}
return true;
}
bool __time_critical_func(recursive_mutex_try_enter)(recursive_mutex_t *mtx, uint32_t *owner_out) {
bool entered;
lock_owner_id_t caller = lock_get_caller_owner_id();
uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
if (!lock_is_owner_id_valid(mtx->owner) || mtx->owner == caller) {
mtx->owner = caller;
uint __unused total = ++mtx->enter_count;
assert(total); // check for overflow
entered = true;
} else {
if (owner_out) *owner_out = (uint32_t) mtx->owner;
entered = false;
}
spin_unlock(mtx->core.spin_lock, save);
return entered;
}
bool __time_critical_func(mutex_enter_timeout_ms)(mutex_t *mtx, uint32_t timeout_ms) {
return mutex_enter_block_until(mtx, make_timeout_time_ms(timeout_ms));
}
bool __time_critical_func(recursive_mutex_enter_timeout_ms)(recursive_mutex_t *mtx, uint32_t timeout_ms) {
return recursive_mutex_enter_block_until(mtx, make_timeout_time_ms(timeout_ms));
}
bool __time_critical_func(mutex_enter_timeout_us)(mutex_t *mtx, uint32_t timeout_us) {
return mutex_enter_block_until(mtx, make_timeout_time_us(timeout_us));
}
bool __time_critical_func(recursive_mutex_enter_timeout_us)(recursive_mutex_t *mtx, uint32_t timeout_us) {
return recursive_mutex_enter_block_until(mtx, make_timeout_time_us(timeout_us));
}
bool __time_critical_func(mutex_enter_block_until)(mutex_t *mtx, absolute_time_t until) {
#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
if (mtx->recursive) {
return recursive_mutex_enter_block_until(mtx, until);
}
#endif
assert(mtx->core.spin_lock);
lock_owner_id_t caller = lock_get_caller_owner_id();
do {
uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
if (!lock_is_owner_id_valid(mtx->owner)) {
mtx->owner = caller;
spin_unlock(mtx->core.spin_lock, save);
return true;
} else {
if (lock_internal_spin_unlock_with_best_effort_wait_or_timeout(&mtx->core, save, until)) {
// timed out
return false;
}
// not timed out; spin lock already unlocked, so loop again
}
} while (true);
}
bool __time_critical_func(recursive_mutex_enter_block_until)(recursive_mutex_t *mtx, absolute_time_t until) {
assert(mtx->core.spin_lock);
lock_owner_id_t caller = lock_get_caller_owner_id();
do {
uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
if (!lock_is_owner_id_valid(mtx->owner) || mtx->owner == caller) {
mtx->owner = caller;
uint __unused total = ++mtx->enter_count;
spin_unlock(mtx->core.spin_lock, save);
assert(total); // check for overflow
return true;
} else {
if (lock_internal_spin_unlock_with_best_effort_wait_or_timeout(&mtx->core, save, until)) {
// timed out
return false;
}
// not timed out; spin lock already unlocked, so loop again
}
} while (true);
}
void __time_critical_func(mutex_exit)(mutex_t *mtx) {
#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
if (mtx->recursive) {
recursive_mutex_exit(mtx);
return;
}
#endif
uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
assert(lock_is_owner_id_valid(mtx->owner));
mtx->owner = LOCK_INVALID_OWNER_ID;
lock_internal_spin_unlock_with_notify(&mtx->core, save);
}
void __time_critical_func(recursive_mutex_exit)(recursive_mutex_t *mtx) {
uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
assert(lock_is_owner_id_valid(mtx->owner));
assert(mtx->enter_count);
if (!--mtx->enter_count) {
mtx->owner = LOCK_INVALID_OWNER_ID;
lock_internal_spin_unlock_with_notify(&mtx->core, save);
} else {
spin_unlock(mtx->core.spin_lock, save);
}
}

View file

@ -1,95 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/sem.h"
#include "pico/time.h"
void sem_init(semaphore_t *sem, int16_t initial_permits, int16_t max_permits) {
lock_init(&sem->core, next_striped_spin_lock_num());
sem->permits = initial_permits;
sem->max_permits = max_permits;
__mem_fence_release();
}
int __time_critical_func(sem_available)(semaphore_t *sem) {
#ifdef __GNUC__
return *(volatile typeof(sem->permits) *) &sem->permits;
#else
static_assert(sizeof(sem->permits) == 2, "");
return *(volatile int16_t *) &sem->permits;
#endif
}
void __time_critical_func(sem_acquire_blocking)(semaphore_t *sem) {
do {
uint32_t save = spin_lock_blocking(sem->core.spin_lock);
if (sem->permits > 0) {
sem->permits--;
spin_unlock(sem->core.spin_lock, save);
break;
}
lock_internal_spin_unlock_with_wait(&sem->core, save);
} while (true);
}
bool __time_critical_func(sem_acquire_timeout_ms)(semaphore_t *sem, uint32_t timeout_ms) {
return sem_acquire_block_until(sem, make_timeout_time_ms(timeout_ms));
}
bool __time_critical_func(sem_acquire_timeout_us)(semaphore_t *sem, uint32_t timeout_us) {
return sem_acquire_block_until(sem, make_timeout_time_us(timeout_us));
}
bool __time_critical_func(sem_acquire_block_until)(semaphore_t *sem, absolute_time_t until) {
do {
uint32_t save = spin_lock_blocking(sem->core.spin_lock);
if (sem->permits > 0) {
sem->permits--;
spin_unlock(sem->core.spin_lock, save);
return true;
}
if (lock_internal_spin_unlock_with_best_effort_wait_or_timeout(&sem->core, save, until)) {
return false;
}
} while (true);
}
bool __time_critical_func(sem_try_acquire)(semaphore_t *sem) {
uint32_t save = spin_lock_blocking(sem->core.spin_lock);
if (sem->permits > 0) {
sem->permits--;
spin_unlock(sem->core.spin_lock, save);
return true;
}
spin_unlock(sem->core.spin_lock, save);
return false;
}
// todo this should really have a blocking variant for when permits are maxed out
bool __time_critical_func(sem_release)(semaphore_t *sem) {
uint32_t save = spin_lock_blocking(sem->core.spin_lock);
int32_t count = sem->permits;
if (count < sem->max_permits) {
sem->permits = (int16_t)(count + 1);
lock_internal_spin_unlock_with_notify(&sem->core, save);
return true;
} else {
spin_unlock(sem->core.spin_lock, save);
return false;
}
}
void __time_critical_func(sem_reset)(semaphore_t *sem, int16_t permits) {
assert(permits >= 0 && permits <= sem->max_permits);
uint32_t save = spin_lock_blocking(sem->core.spin_lock);
if (permits > sem->permits) {
sem->permits = permits;
lock_internal_spin_unlock_with_notify(&sem->core, save);
} else {
sem->permits = permits;
spin_unlock(sem->core.spin_lock, save);
}
}

View file

@ -1,844 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_TIME_H
#define _PICO_TIME_H
#include "pico.h"
#include "hardware/timer.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \file time.h
* \defgroup pico_time pico_time
*
* \brief API for accurate timestamps, sleeping, and time based callbacks
*
* \note The functions defined here provide a much more powerful and user friendly wrapping around the
* low level hardware timer functionality. For these functions (and any other SDK functionality
* e.g. timeouts, that relies on them) to work correctly, the hardware timer should not be modified. i.e. it is expected
* to be monotonically increasing once per microsecond. Fortunately there is no need to modify the hardware
* timer as any functionality you can think of that isn't already covered here can easily be modelled
* by adding or subtracting a constant value from the unmodified hardware timer.
*
* \sa \ref hardware_timer
*/
// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_PICO_TIME, Enable/disable assertions in the pico_time module, type=bool, default=0, group=pico_time
#ifndef PARAM_ASSERTIONS_ENABLED_PICO_TIME
#ifdef PARAM_ASSERTIONS_ENABLED_PICO_TIME // backwards compatibility with SDK < 2.0.0
#define PARAM_ASSERTIONS_ENABLED_PICO_TIME PARAM_ASSERTIONS_ENABLED_TIME
#else
#define PARAM_ASSERTIONS_ENABLED_PICO_TIME 0
#endif
#endif
// PICO_CONFIG: PICO_TIME_SLEEP_OVERHEAD_ADJUST_US, How many microseconds to wake up early (and then busy_wait) to account for timer overhead when sleeping in low power mode, type=int, default=6, group=pico_time
#ifndef PICO_TIME_SLEEP_OVERHEAD_ADJUST_US
#define PICO_TIME_SLEEP_OVERHEAD_ADJUST_US 6
#endif
/*!
* \defgroup timestamp timestamp
* \ingroup pico_time
* \brief Timestamp functions relating to points in time (including the current time).
*
* These are functions for dealing with timestamps (i.e. instants in time) represented by the type absolute_time_t. This opaque
* type is provided to help prevent accidental mixing of timestamps and relative time values.
*/
/*! \brief Return a representation of the current time.
* \ingroup timestamp
*
* Returns an opaque high fidelity representation of the current time sampled during the call.
*
* \return the absolute time (now) of the hardware timer
*
* \sa absolute_time_t
* \sa sleep_until()
* \sa time_us_64()
*/
static inline absolute_time_t get_absolute_time(void) {
absolute_time_t t;
update_us_since_boot(&t, time_us_64());
return t;
}
static inline uint32_t us_to_ms(uint64_t us) {
if (us >> 32u) {
return (uint32_t)(us / 1000u);
} else {
return ((uint32_t)us) / 1000u;
}
}
/*! fn to_ms_since_boot
* \ingroup timestamp
* \brief Convert a timestamp into a number of milliseconds since boot.
* \param t an absolute_time_t value to convert
* \return the number of milliseconds since boot represented by t
* \sa to_us_since_boot()
*/
static inline uint32_t to_ms_since_boot(absolute_time_t t) {
uint64_t us = to_us_since_boot(t);
return us_to_ms(us);
}
/*! \brief Return a timestamp value obtained by adding a number of microseconds to another timestamp
* \ingroup timestamp
*
* \param t the base timestamp
* \param us the number of microseconds to add
* \return the timestamp representing the resulting time
*/
static inline absolute_time_t delayed_by_us(const absolute_time_t t, uint64_t us) {
absolute_time_t t2;
uint64_t base = to_us_since_boot(t);
uint64_t delayed = base + us;
if ((int64_t)delayed < 0) {
// absolute_time_t (to allow for signed time deltas) is never greater than INT64_MAX which == at_the_end_of_time
delayed = INT64_MAX;
}
update_us_since_boot(&t2, delayed);
return t2;
}
/*! \brief Return a timestamp value obtained by adding a number of milliseconds to another timestamp
* \ingroup timestamp
*
* \param t the base timestamp
* \param ms the number of milliseconds to add
* \return the timestamp representing the resulting time
*/
static inline absolute_time_t delayed_by_ms(const absolute_time_t t, uint32_t ms) {
absolute_time_t t2;
uint64_t base = to_us_since_boot(t);
uint64_t delayed = base + ms * 1000ull;
if ((int64_t)delayed < 0) {
// absolute_time_t (to allow for signed time deltas) is never greater than INT64_MAX which == at_the_end_of_time
delayed = INT64_MAX;
}
update_us_since_boot(&t2, delayed);
return t2;
}
/*! \brief Convenience method to get the timestamp a number of microseconds from the current time
* \ingroup timestamp
*
* \param us the number of microseconds to add to the current timestamp
* \return the future timestamp
*/
static inline absolute_time_t make_timeout_time_us(uint64_t us) {
return delayed_by_us(get_absolute_time(), us);
}
/*! \brief Convenience method to get the timestamp a number of milliseconds from the current time
* \ingroup timestamp
*
* \param ms the number of milliseconds to add to the current timestamp
* \return the future timestamp
*/
static inline absolute_time_t make_timeout_time_ms(uint32_t ms) {
return delayed_by_ms(get_absolute_time(), ms);
}
/*! \brief Return the difference in microseconds between two timestamps
* \ingroup timestamp
*
* \note be careful when diffing against large timestamps (e.g. \ref at_the_end_of_time)
* as the signed integer may overflow.
*
* \param from the first timestamp
* \param to the second timestamp
* \return the number of microseconds between the two timestamps (positive if `to` is after `from` except
* in case of overflow)
*/
static inline int64_t absolute_time_diff_us(absolute_time_t from, absolute_time_t to) {
return (int64_t)(to_us_since_boot(to) - to_us_since_boot(from));
}
/*! \brief Return the earlier of two timestamps
* \ingroup timestamp
*
* \param a the first timestamp
* \param b the second timestamp
* \return the earlier of the two timestamps
*/
static inline absolute_time_t absolute_time_min(absolute_time_t a, absolute_time_t b) {
return to_us_since_boot(a) < to_us_since_boot(b) ? a : b;
}
/*! \brief The timestamp representing the end of time; this is actually not the maximum possible
* timestamp, but is set to 0x7fffffff_ffffffff microseconds to avoid sign overflows with time
* arithmetic. This is almost 300,000 years, so should be sufficient.
* \ingroup timestamp
*/
extern const absolute_time_t at_the_end_of_time;
/*! \brief Determine if the given timestamp is "at_the_end_of_time"
* \ingroup timestamp
* \param t the timestamp
* \return true if the timestamp is at_the_end_of_time
* \sa at_the_end_of_time
*/
static inline bool is_at_the_end_of_time(absolute_time_t t) {
return to_us_since_boot(t) == to_us_since_boot(at_the_end_of_time);
}
/*! \brief The timestamp representing a null timestamp
* \ingroup timestamp
*/
extern const absolute_time_t nil_time;
/*! \brief Determine if the given timestamp is nil
* \ingroup timestamp
* \param t the timestamp
* \return true if the timestamp is nil
* \sa nil_time
*/
static inline bool is_nil_time(absolute_time_t t) {
return !to_us_since_boot(t);
}
/*!
* \defgroup sleep sleep
* \ingroup pico_time
* \brief Sleep functions for delaying execution in a lower power state.
*
* These functions allow the calling core to sleep. This is a lower powered sleep; waking and re-checking time on every processor
* event (WFE)
*
* \note These functions should not be called from an IRQ handler.
*
* \note Lower powered sleep requires use of the \link alarm_pool_get_default default alarm pool\endlink which may
* be disabled by the PICO_TIME_DEFAULT_ALARM_POOL_DISABLED #define or currently full in which case these functions
* become busy waits instead.
*
* \note Whilst \a sleep_ functions are preferable to \a busy_wait functions from a power perspective, the \a busy_wait equivalent function
* may return slightly sooner after the target is reached.
*
* \sa busy_wait_until() \sa busy_wait_us() \sa busy_wait_us_32()
*/
/*! \brief Wait until after the given timestamp to return
* \ingroup sleep
*
* \note This method attempts to perform a lower power (WFE) sleep
*
* \param target the time after which to return
* \sa sleep_us()
* \sa busy_wait_until()
* */
void sleep_until(absolute_time_t target);
/*! \brief Wait for the given number of microseconds before returning
* \ingroup sleep
*
* \note This method attempts to perform a lower power (WFE) sleep
*
* \param us the number of microseconds to sleep
* \sa busy_wait_us()
*/
void sleep_us(uint64_t us);
/*! \brief Wait for the given number of milliseconds before returning
* \ingroup sleep
*
* \note This method attempts to perform a lower power sleep (using WFE) as much as possible.
*
* \param ms the number of milliseconds to sleep
*/
void sleep_ms(uint32_t ms);
/*! \brief Helper method for blocking on a timeout
* \ingroup sleep
*
* This method will return in response to an event (as per __wfe) or
* when the target time is reached, or at any point before.
*
* This method can be used to implement a lower power polling loop waiting on
* some condition signalled by an event (__sev()).
*
* This is called \a best_effort because under certain circumstances (notably the default timer pool
* being disabled or full) the best effort is simply to return immediately without a __wfe, thus turning the calling
* code into a busy wait.
*
* Example usage:
* ```c
* bool my_function_with_timeout_us(uint64_t timeout_us) {
* absolute_time_t timeout_time = make_timeout_time_us(timeout_us);
* do {
* // each time round the loop, we check to see if the condition
* // we are waiting on has happened
* if (my_check_done()) {
* // do something
* return true;
* }
* // will try to sleep until timeout or the next processor event
* } while (!best_effort_wfe_or_timeout(timeout_time));
* return false; // timed out
* }
* ```
* NOTE: This method should always be used in a loop associated with checking another "event" variable, since
* processor events are a shared resource and can happen for a large number of reasons.
*
* @param timeout_timestamp the timeout time
* @return true if the target time is reached, false otherwise
*/
bool best_effort_wfe_or_timeout(absolute_time_t timeout_timestamp);
/*!
* \defgroup alarm alarm
* \ingroup pico_time
* \brief Alarm functions for scheduling future execution
*
* Alarms are added to alarm pools, which may hold a certain fixed number of active alarms. Each alarm pool
* utilizes one of four underlying timer_alarms, thus you may have up to four alarm pools. An alarm pool
* calls (except when the callback would happen before or during being set) the callback on the core from which
* the alarm pool was created. Callbacks are called from the timer_alarm IRQ handler, so care must
* be taken in their implementation.
*
* A default pool is created the core specified by PICO_TIME_DEFAULT_ALARM_POOL_HARDWARE_ALARM_NUM
* on core 0, and may be used by the method variants that take no alarm pool parameter.
*
* \sa struct alarm_pool
* \sa hardware_timer
*/
// PICO_CONFIG: PICO_TIME_DEFAULT_ALARM_POOL_DISABLED, Disable the default alarm pool, type=bool, default=0, advanced=true, group=pico_time
#ifndef PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
/*!
* \brief If 1 then the default alarm pool is disabled (so no timer_alarm is claimed for the pool)
*
* \note Setting to 1 may cause some code not to compile as default timer pool related methods are removed
*
* \note When the default alarm pool is disabled, \a sleep_ methods and timeouts are no longer lower powered
* (they become \a busy_wait_)
*
* \ingroup alarm
* \sa #PICO_TIME_DEFAULT_ALARM_POOL_HARDWARE_ALARM_NUM
* \sa alarm_pool_get_default()
*/
#define PICO_TIME_DEFAULT_ALARM_POOL_DISABLED 0
#endif
// PICO_CONFIG: PICO_TIME_DEFAULT_ALARM_POOL_HARDWARE_ALARM_NUM, Select which HW alarm is used for the default alarm pool, min=0, max=3, default=3, advanced=true, group=pico_time
#ifndef PICO_TIME_DEFAULT_ALARM_POOL_HARDWARE_ALARM_NUM
/*!
* \brief Selects which timer_alarm is used for the default alarm pool
* \ingroup alarm
* \sa alarm_pool_get_default()
*/
#define PICO_TIME_DEFAULT_ALARM_POOL_HARDWARE_ALARM_NUM 3
#endif
// PICO_CONFIG: PICO_TIME_DEFAULT_ALARM_POOL_MAX_TIMERS, Selects the maximum number of concurrent timers in the default alarm pool, min=0, max=255, default=16, advanced=true, group=pico_time
#ifndef PICO_TIME_DEFAULT_ALARM_POOL_MAX_TIMERS
/*!
* \brief Selects the maximum number of concurrent timers in the default alarm pool
* \ingroup alarm
*
* \note For implementation reasons this is limited to PICO_PHEAP_MAX_ENTRIES which defaults to 255
* \sa #PICO_TIME_DEFAULT_ALARM_POOL_HARDWARE_ALARM_NUM
* \sa alarm_pool_get_default()
*/
#define PICO_TIME_DEFAULT_ALARM_POOL_MAX_TIMERS 16
#endif
/**
* \brief The identifier for an alarm
*
* \note this identifier is signed because <0 is used as an error condition when creating alarms
*
* \note alarm ids may be reused, however for convenience the implementation makes an attempt to defer
* reusing as long as possible. You should certainly expect it to be hundreds of ids before one is
* reused, although in most cases it is more. Nonetheless care must still be taken when cancelling
* alarms or other functionality based on alarms when the alarm may have expired, as eventually
* the alarm id may be reused for another alarm.
*
* \see pico_error_codes
* \ingroup alarm
*/
typedef int32_t alarm_id_t; // note this is signed because we use <0 as a meaningful error value
/**
* \brief User alarm callback
* \ingroup alarm
* \param id the alarm_id as returned when the alarm was added
* \param user_data the user data passed when the alarm was added
* \return <0 to reschedule the same alarm this many us from the time the alarm was previously scheduled to fire
* \return >0 to reschedule the same alarm this many us from the time this method returns
* \return 0 to not reschedule the alarm
*/
typedef int64_t (*alarm_callback_t)(alarm_id_t id, void *user_data);
typedef struct alarm_pool alarm_pool_t;
typedef void alarm_pool_timer_t;
/**
* \brief Create the default alarm pool (if not already created or disabled)
* \ingroup alarm
*/
void alarm_pool_init_default(void);
void runtime_init_default_alarm_pool(void);
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
/*!
* \brief The default alarm pool used when alarms are added without specifying an alarm pool,
* and also used by the SDK to support lower power sleeps and timeouts.
*
* \ingroup alarm
* \sa #PICO_TIME_DEFAULT_ALARM_POOL_HARDWARE_ALARM_NUM
*/
alarm_pool_t *alarm_pool_get_default(void);
#endif
alarm_pool_t *alarm_pool_create_on_timer(alarm_pool_timer_t *timer, uint timer_alarm_num, uint max_timers);
alarm_pool_timer_t *alarm_pool_timer_for_timer_num(uint timer_num);
alarm_pool_timer_t *alarm_pool_get_default_timer(void);
/**
* \brief Create an alarm pool
*
* The alarm pool will call callbacks from an alarm IRQ Handler on the core of this function is called from.
*
* In many situations there is never any need for anything other than the default alarm pool, however you
* might want to create another if you want alarm callbacks on core 1 or require alarm pools of
* different priority (IRQ priority based preemption of callbacks)
*
* \note This method will hard assert if the timer_alarm is already claimed.
*
* \ingroup alarm
* \param timer_alarm_num the timer_alarm to use to back this pool
* \param max_timers the maximum number of timers
* \note For implementation reasons this is limited to PICO_PHEAP_MAX_ENTRIES which defaults to 255
* \sa alarm_pool_get_default()
* \sa hardware_claiming
*/
static inline alarm_pool_t *alarm_pool_create(uint timer_alarm_num, uint max_timers) {
return alarm_pool_create_on_timer(alarm_pool_get_default_timer(), timer_alarm_num, max_timers);
}
alarm_pool_t *alarm_pool_create_on_timer_with_unused_hardware_alarm(alarm_pool_timer_t *timer, uint max_timers);
/**
* \brief Create an alarm pool, claiming an used timer_alarm to back it.
*
* The alarm pool will call callbacks from an alarm IRQ Handler on the core of this function is called from.
*
* In many situations there is never any need for anything other than the default alarm pool, however you
* might want to create another if you want alarm callbacks on core 1 or require alarm pools of
* different priority (IRQ priority based preemption of callbacks)
*
* \note This method will hard assert if the there is no free hardware to claim.
*
* \ingroup alarm
* \param max_timers the maximum number of timers
* \note For implementation reasons this is limited to PICO_PHEAP_MAX_ENTRIES which defaults to 255
* \sa alarm_pool_get_default()
* \sa hardware_claiming
*/
static inline alarm_pool_t *alarm_pool_create_with_unused_hardware_alarm(uint max_timers) {
return alarm_pool_create_on_timer_with_unused_hardware_alarm(alarm_pool_get_default_timer(), max_timers);
}
/**
* \brief Return the timer alarm used by an alarm pool
* \ingroup alarm
* \param pool the pool
* \return the timer_alarm used by the pool
*/
uint alarm_pool_timer_alarm_num(alarm_pool_t *pool);
// backwards compatibility
static inline uint alarm_pool_hardware_alarm_num(alarm_pool_t *pool) {
return alarm_pool_timer_alarm_num(pool);
}
/**
* \brief Return the core number the alarm pool was initialized on (and hence callbacks are called on)
* \ingroup alarm
* \param pool the pool
* \return the core used by the pool
*/
uint alarm_pool_core_num(alarm_pool_t *pool);
/**
* \brief Destroy the alarm pool, cancelling all alarms and freeing up the underlying timer_alarm
* \ingroup alarm
* \param pool the pool
*/
void alarm_pool_destroy(alarm_pool_t *pool);
/*!
* \brief Add an alarm callback to be called at a specific time
* \ingroup alarm
*
* Generally the callback is called as soon as possible after the time specified from an IRQ handler
* on the core the alarm pool was created on. If the callback is in the past or happens before
* the alarm setup could be completed, then this method will optionally call the callback itself
* and then return a return code to indicate that the target time has passed.
*
* \note It is safe to call this method from an IRQ handler (including alarm callbacks), and from either core.
*
* @param pool the alarm pool to use for scheduling the callback (this determines which timer_alarm is used, and which core calls the callback)
* @param time the timestamp when (after which) the callback should fire
* @param callback the callback function
* @param user_data user data to pass to the callback function
* @param fire_if_past if true, and the alarm time falls before or during this call before the alarm can be set,
* then the callback should be called during (by) this function instead
* @return >0 the alarm id for an active (at the time of return) alarm
* @return 0 if the alarm time passed before or during the call and fire_if_past was false
* @return <0 if there were no alarm slots available, or other error occurred
*/
alarm_id_t alarm_pool_add_alarm_at(alarm_pool_t *pool, absolute_time_t time, alarm_callback_t callback, void *user_data, bool fire_if_past);
/*!
* \brief Add an alarm callback to be called at or after a specific time
* \ingroup alarm
*
* The callback is called as soon as possible after the time specified from an IRQ handler
* on the core the alarm pool was created on. Unlike \ref alarm_pool_add_alarm_at, this method
* guarantees to call the callback from that core even if the time is during this method call or in the past.
*
* \note It is safe to call this method from an IRQ handler (including alarm callbacks), and from either core.
*
* @param pool the alarm pool to use for scheduling the callback (this determines which timer_alarm is used, and which core calls the callback)
* @param time the timestamp when (after which) the callback should fire
* @param callback the callback function
* @param user_data user data to pass to the callback function
* @return >0 the alarm id for an active (at the time of return) alarm
* @return <0 if there were no alarm slots available, or other error occurred
*/
alarm_id_t alarm_pool_add_alarm_at_force_in_context(alarm_pool_t *pool, absolute_time_t time, alarm_callback_t callback,
void *user_data);
/*!
* \brief Add an alarm callback to be called after a delay specified in microseconds
* \ingroup alarm
*
* Generally the callback is called as soon as possible after the time specified from an IRQ handler
* on the core the alarm pool was created on. If the callback is in the past or happens before
* the alarm setup could be completed, then this method will optionally call the callback itself
* and then return a return code to indicate that the target time has passed.
*
* \note It is safe to call this method from an IRQ handler (including alarm callbacks), and from either core.
*
* @param pool the alarm pool to use for scheduling the callback (this determines which timer_alarm is used, and which core calls the callback)
* @param us the delay (from now) in microseconds when (after which) the callback should fire
* @param callback the callback function
* @param user_data user data to pass to the callback function
* @param fire_if_past if true, and the alarm time falls during this call before the alarm can be set,
* then the callback should be called during (by) this function instead
* @return >0 the alarm id
* @return 0 if the alarm time passed before or during the call and fire_if_past was false
* @return <0 if there were no alarm slots available, or other error occurred
*/
static inline alarm_id_t alarm_pool_add_alarm_in_us(alarm_pool_t *pool, uint64_t us, alarm_callback_t callback, void *user_data, bool fire_if_past) {
return alarm_pool_add_alarm_at(pool, delayed_by_us(get_absolute_time(), us), callback, user_data, fire_if_past);
}
/*!
* \brief Add an alarm callback to be called after a delay specified in milliseconds
* \ingroup alarm
*
* Generally the callback is called as soon as possible after the time specified from an IRQ handler
* on the core the alarm pool was created on. If the callback is in the past or happens before
* the alarm setup could be completed, then this method will optionally call the callback itself
* and then return a return code to indicate that the target time has passed.
*
* \note It is safe to call this method from an IRQ handler (including alarm callbacks), and from either core.
*
* @param pool the alarm pool to use for scheduling the callback (this determines which timer_alarm is used, and which core calls the callback)
* @param ms the delay (from now) in milliseconds when (after which) the callback should fire
* @param callback the callback function
* @param user_data user data to pass to the callback function
* @param fire_if_past if true, and the alarm time falls before or during this call before the alarm can be set,
* then the callback should be called during (by) this function instead
* @return >0 the alarm id
* @return 0 if the alarm time passed before or during the call and fire_if_past was false
* @return <0 if there were no alarm slots available, or other error occurred
*/
static inline alarm_id_t alarm_pool_add_alarm_in_ms(alarm_pool_t *pool, uint32_t ms, alarm_callback_t callback, void *user_data, bool fire_if_past) {
return alarm_pool_add_alarm_at(pool, delayed_by_ms(get_absolute_time(), ms), callback, user_data, fire_if_past);
}
/*!
* \brief Return the time remaining before the next trigger of an alarm
* \ingroup alarm
*
* @param pool the alarm_pool containing the alarm
* @param alarm_id the alarm
*
* @return >=0 the number of microseconds before the next trigger
* @return <0 if either the given alarm is not in progress or it has passed
*/
int64_t alarm_pool_remaining_alarm_time_us(alarm_pool_t *pool, alarm_id_t alarm_id);
/*!
* \brief Return the time remaining before the next trigger of an alarm
* \ingroup alarm
*
* @param pool the alarm_pool containing the alarm
* @param alarm_id the alarm
*
* @return >=0 the number of milliseconds before the next trigger (INT32_MAX if the number of ms is higher than can be represented0
* @return <0 if either the given alarm is not in progress or it has passed
*/
int32_t alarm_pool_remaining_alarm_time_ms(alarm_pool_t *pool, alarm_id_t alarm_id);
/*!
* \brief Cancel an alarm
* \ingroup alarm
* \param pool the alarm_pool containing the alarm
* \param alarm_id the alarm
* \return true if the alarm was cancelled, false if it didn't exist
* \sa alarm_id_t for a note on reuse of IDs
*/
bool alarm_pool_cancel_alarm(alarm_pool_t *pool, alarm_id_t alarm_id);
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
/*!
* \brief Add an alarm callback to be called at a specific time
* \ingroup alarm
*
* Generally the callback is called as soon as possible after the time specified from an IRQ handler
* on the core of the default alarm pool (generally core 0). If the callback is in the past or happens before
* the alarm setup could be completed, then this method will optionally call the callback itself
* and then return a return code to indicate that the target time has passed.
*
* \note It is safe to call this method from an IRQ handler (including alarm callbacks), and from either core.
*
* @param time the timestamp when (after which) the callback should fire
* @param callback the callback function
* @param user_data user data to pass to the callback function
* @param fire_if_past if true, and the alarm time falls before or during this call before the alarm can be set,
* then the callback should be called during (by) this function instead
* @return >0 the alarm id
* @return 0 if the alarm time passed before or during the call and fire_if_past was false
* @return <0 if there were no alarm slots available, or other error occurred
*/
static inline alarm_id_t add_alarm_at(absolute_time_t time, alarm_callback_t callback, void *user_data, bool fire_if_past) {
return alarm_pool_add_alarm_at(alarm_pool_get_default(), time, callback, user_data, fire_if_past);
}
/*!
* \brief Add an alarm callback to be called after a delay specified in microseconds
* \ingroup alarm
*
* Generally the callback is called as soon as possible after the time specified from an IRQ handler
* on the core of the default alarm pool (generally core 0). If the callback is in the past or happens before
* the alarm setup could be completed, then this method will optionally call the callback itself
* and then return a return code to indicate that the target time has passed.
*
* \note It is safe to call this method from an IRQ handler (including alarm callbacks), and from either core.
*
* @param us the delay (from now) in microseconds when (after which) the callback should fire
* @param callback the callback function
* @param user_data user data to pass to the callback function
* @param fire_if_past if true, and the alarm time falls during this call before the alarm can be set,
* then the callback should be called during (by) this function instead
* @return >0 the alarm id
* @return 0 if the alarm time passed before or during the call and fire_if_past was false
* @return <0 if there were no alarm slots available, or other error occurred
*/
static inline alarm_id_t add_alarm_in_us(uint64_t us, alarm_callback_t callback, void *user_data, bool fire_if_past) {
return alarm_pool_add_alarm_in_us(alarm_pool_get_default(), us, callback, user_data, fire_if_past);
}
/*!
* \brief Add an alarm callback to be called after a delay specified in milliseconds
* \ingroup alarm
*
* Generally the callback is called as soon as possible after the time specified from an IRQ handler
* on the core of the default alarm pool (generally core 0). If the callback is in the past or happens before
* the alarm setup could be completed, then this method will optionally call the callback itself
* and then return a return code to indicate that the target time has passed.
*
* \note It is safe to call this method from an IRQ handler (including alarm callbacks), and from either core.
*
* @param ms the delay (from now) in milliseconds when (after which) the callback should fire
* @param callback the callback function
* @param user_data user data to pass to the callback function
* @param fire_if_past if true, and the alarm time falls during this call before the alarm can be set,
* then the callback should be called during (by) this function instead
* @return >0 the alarm id
* @return 0 if the alarm time passed before or during the call and fire_if_past was false
* @return <0 if there were no alarm slots available, or other error occurred
*/
static inline alarm_id_t add_alarm_in_ms(uint32_t ms, alarm_callback_t callback, void *user_data, bool fire_if_past) {
return alarm_pool_add_alarm_in_ms(alarm_pool_get_default(), ms, callback, user_data, fire_if_past);
}
/*!
* \brief Cancel an alarm from the default alarm pool
* \ingroup alarm
* \param alarm_id the alarm
* \return true if the alarm was cancelled, false if it didn't exist
* \sa alarm_id_t for a note on reuse of IDs
*/
static inline bool cancel_alarm(alarm_id_t alarm_id) {
return alarm_pool_cancel_alarm(alarm_pool_get_default(), alarm_id);
}
/*!
* \brief Return the time remaining before the next trigger of an alarm
* \ingroup alarm
*
* @param pool the alarm_pool containing the alarm
* @param alarm_id the alarm
*
* @return >=0 the number of microseconds before the next trigger
* @return <0 if either the given alarm is not in progress or it has passed
*/
int64_t remaining_alarm_time_us(alarm_id_t alarm_id);
/*!
* \brief Return the time remaining before the next trigger of an alarm
* \ingroup alarm
*
* @param alarm_id the alarm
*
* @return >=0 the number of milliseconds before the next trigger (INT32_MAX if the number of ms is higher than can be represented0
* @return <0 if either the given alarm is not in progress or it has passed
*/
int32_t remaining_alarm_time_ms(alarm_id_t alarm_id);
#endif
/*!
* \defgroup repeating_timer repeating_timer
* \ingroup pico_time
* \brief Repeating Timer functions for simple scheduling of repeated execution
*
* \note The regular \a alarm_ functionality can be used to make repeating alarms (by return non zero from the callback),
* however these methods abstract that further (at the cost of a user structure to store the repeat delay in (which
* the alarm framework does not have space for).
*/
typedef struct repeating_timer repeating_timer_t;
/**
* \brief Callback for a repeating timer
* \ingroup repeating_timer
* \param rt repeating time structure containing information about the repeating time. user_data is of primary important to the user
* \return true to continue repeating, false to stop.
*/
typedef bool (*repeating_timer_callback_t)(repeating_timer_t *rt);
/**
* \brief Information about a repeating timer
* \ingroup repeating_timer
* \return
*/
struct repeating_timer {
int64_t delay_us;
alarm_pool_t *pool;
alarm_id_t alarm_id;
repeating_timer_callback_t callback;
void *user_data;
};
/*!
* \brief Add a repeating timer that is called repeatedly at the specified interval in microseconds
* \ingroup repeating_timer
*
* Generally the callback is called as soon as possible after the time specified from an IRQ handler
* on the core the alarm pool was created on. If the callback is in the past or happens before
* the alarm setup could be completed, then this method will optionally call the callback itself
* and then return a return code to indicate that the target time has passed.
*
* \note It is safe to call this method from an IRQ handler (including alarm callbacks), and from either core.
*
* @param pool the alarm pool to use for scheduling the repeating timer (this determines which timer_alarm is used, and which core calls the callback)
* @param delay_us the repeat delay in microseconds; if >0 then this is the delay between one callback ending and the next starting; if <0 then this is the negative of the time between the starts of the callbacks. The value of 0 is treated as 1
* @param callback the repeating timer callback function
* @param user_data user data to pass to store in the repeating_timer structure for use by the callback.
* @param out the pointer to the user owned structure to store the repeating timer info in. BEWARE this storage location must outlive the repeating timer, so be careful of using stack space
* @return false if there were no alarm slots available to create the timer, true otherwise.
*/
bool alarm_pool_add_repeating_timer_us(alarm_pool_t *pool, int64_t delay_us, repeating_timer_callback_t callback, void *user_data, repeating_timer_t *out);
/*!
* \brief Add a repeating timer that is called repeatedly at the specified interval in milliseconds
* \ingroup repeating_timer
*
* Generally the callback is called as soon as possible after the time specified from an IRQ handler
* on the core the alarm pool was created on. If the callback is in the past or happens before
* the alarm setup could be completed, then this method will optionally call the callback itself
* and then return a return code to indicate that the target time has passed.
*
* \note It is safe to call this method from an IRQ handler (including alarm callbacks), and from either core.
*
* @param pool the alarm pool to use for scheduling the repeating timer (this determines which timer_alarm is used, and which core calls the callback)
* @param delay_ms the repeat delay in milliseconds; if >0 then this is the delay between one callback ending and the next starting; if <0 then this is the negative of the time between the starts of the callbacks. The value of 0 is treated as 1 microsecond
* @param callback the repeating timer callback function
* @param user_data user data to pass to store in the repeating_timer structure for use by the callback.
* @param out the pointer to the user owned structure to store the repeating timer info in. BEWARE this storage location must outlive the repeating timer, so be careful of using stack space
* @return false if there were no alarm slots available to create the timer, true otherwise.
*/
static inline bool alarm_pool_add_repeating_timer_ms(alarm_pool_t *pool, int32_t delay_ms, repeating_timer_callback_t callback, void *user_data, repeating_timer_t *out) {
return alarm_pool_add_repeating_timer_us(pool, delay_ms * (int64_t)1000, callback, user_data, out);
}
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
/*!
* \brief Add a repeating timer that is called repeatedly at the specified interval in microseconds
* \ingroup repeating_timer
*
* Generally the callback is called as soon as possible after the time specified from an IRQ handler
* on the core of the default alarm pool (generally core 0). If the callback is in the past or happens before
* the alarm setup could be completed, then this method will optionally call the callback itself
* and then return a return code to indicate that the target time has passed.
*
* \note It is safe to call this method from an IRQ handler (including alarm callbacks), and from either core.
*
* @param delay_us the repeat delay in microseconds; if >0 then this is the delay between one callback ending and the next starting; if <0 then this is the negative of the time between the starts of the callbacks. The value of 0 is treated as 1
* @param callback the repeating timer callback function
* @param user_data user data to pass to store in the repeating_timer structure for use by the callback.
* @param out the pointer to the user owned structure to store the repeating timer info in. BEWARE this storage location must outlive the repeating timer, so be careful of using stack space
* @return false if there were no alarm slots available to create the timer, true otherwise.
*/
static inline bool add_repeating_timer_us(int64_t delay_us, repeating_timer_callback_t callback, void *user_data, repeating_timer_t *out) {
return alarm_pool_add_repeating_timer_us(alarm_pool_get_default(), delay_us, callback, user_data, out);
}
/*!
* \brief Add a repeating timer that is called repeatedly at the specified interval in milliseconds
* \ingroup repeating_timer
*
* Generally the callback is called as soon as possible after the time specified from an IRQ handler
* on the core of the default alarm pool (generally core 0). If the callback is in the past or happens before
* the alarm setup could be completed, then this method will optionally call the callback itself
* and then return a return code to indicate that the target time has passed.
*
* \note It is safe to call this method from an IRQ handler (including alarm callbacks), and from either core.
*
* @param delay_ms the repeat delay in milliseconds; if >0 then this is the delay between one callback ending and the next starting; if <0 then this is the negative of the time between the starts of the callbacks. The value of 0 is treated as 1 microsecond
* @param callback the repeating timer callback function
* @param user_data user data to pass to store in the repeating_timer structure for use by the callback.
* @param out the pointer to the user owned structure to store the repeating timer info in. BEWARE this storage location must outlive the repeating timer, so be careful of using stack space
* @return false if there were no alarm slots available to create the timer, true otherwise.
*/
static inline bool add_repeating_timer_ms(int32_t delay_ms, repeating_timer_callback_t callback, void *user_data, repeating_timer_t *out) {
return alarm_pool_add_repeating_timer_us(alarm_pool_get_default(), delay_ms * (int64_t)1000, callback, user_data, out);
}
#endif
/**
* \brief Cancel a repeating timer
* \ingroup repeating_timer
* \param timer the repeating timer to cancel
* \return true if the repeating timer was cancelled, false if it didn't exist
* \sa alarm_id_t for a note on reuse of IDs
*/
bool cancel_repeating_timer(repeating_timer_t *timer);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,30 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_TIMEOUT_HELPER_H
#define _PICO_TIMEOUT_HELPER_H
#include "pico/time.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct timeout_state {
absolute_time_t next_timeout;
uint64_t param;
} timeout_state_t;
typedef bool (*check_timeout_fn)(timeout_state_t *ts, bool reset);
check_timeout_fn init_single_timeout_until(timeout_state_t *ts, absolute_time_t target);
check_timeout_fn init_per_iteration_timeout_us(timeout_state_t *ts, uint64_t per_iteration_timeout_us);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,570 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdlib.h>
#include "pico.h"
#include "pico/time.h"
#include "pico/sync.h"
#include "pico/runtime_init.h"
const absolute_time_t ABSOLUTE_TIME_INITIALIZED_VAR(nil_time, 0);
const absolute_time_t ABSOLUTE_TIME_INITIALIZED_VAR(at_the_end_of_time, INT64_MAX);
typedef struct alarm_pool_entry {
// next entry link or -1
int16_t next;
// low 15 bits are a sequence number used in the low word of the alarm_id so that
// the alarm_id for this entry only repeats every 32767 adds (note this value is never zero)
// the top bit is a cancellation flag.
volatile uint16_t sequence;
int64_t target;
alarm_callback_t callback;
void *user_data;
} alarm_pool_entry_t;
struct alarm_pool {
uint8_t timer_alarm_num;
uint8_t core_num;
// this is protected by the lock (threads allocate from it, and the IRQ handler adds back to it)
int16_t free_head;
// this is protected by the lock (threads add to it, the IRQ handler removes from it)
volatile int16_t new_head;
volatile bool has_pending_cancellations;
// this is owned by the IRQ handler so doesn't need additional locking
int16_t ordered_head;
uint16_t num_entries;
alarm_pool_timer_t *timer;
spin_lock_t *lock;
alarm_pool_entry_t *entries;
};
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
// To avoid bringing in calloc, we statically allocate the arrays and the heap
static alarm_pool_entry_t default_alarm_pool_entries[PICO_TIME_DEFAULT_ALARM_POOL_MAX_TIMERS];
static alarm_pool_t default_alarm_pool = {
.entries = default_alarm_pool_entries,
};
static inline bool default_alarm_pool_initialized(void) {
return default_alarm_pool.lock != NULL;
}
static lock_core_t sleep_notifier;
#endif
#include "pico/time_adapter.h"
static alarm_pool_t *pools[TA_NUM_TIMERS][TA_NUM_TIMER_ALARMS];
static void alarm_pool_post_alloc_init(alarm_pool_t *pool, alarm_pool_timer_t *timer, uint hardware_alarm_num, uint max_timers);
static inline int16_t alarm_index(alarm_id_t id) {
return (int16_t)(id >> 16);
}
static inline uint16_t alarm_sequence(alarm_id_t id) {
return (uint16_t)id;
}
static alarm_id_t make_alarm_id(int index, uint16_t counter) {
return index << 16 | counter;
}
#if !PICO_RUNTIME_NO_INIT_DEFAULT_ALARM_POOL
void __weak runtime_init_default_alarm_pool(void) {
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
// allow multiple calls for ease of use from host tests
if (!default_alarm_pool_initialized()) {
alarm_pool_timer_t *timer = alarm_pool_get_default_timer();
ta_hardware_alarm_claim(timer, PICO_TIME_DEFAULT_ALARM_POOL_HARDWARE_ALARM_NUM);
alarm_pool_post_alloc_init(&default_alarm_pool,
timer,
PICO_TIME_DEFAULT_ALARM_POOL_HARDWARE_ALARM_NUM,
PICO_TIME_DEFAULT_ALARM_POOL_MAX_TIMERS);
}
lock_init(&sleep_notifier, PICO_SPINLOCK_ID_TIMER);
#endif
}
#endif
void alarm_pool_init_default(void) {
runtime_init_default_alarm_pool();
}
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
alarm_pool_t *alarm_pool_get_default(void) {
assert(default_alarm_pool_initialized());
return &default_alarm_pool;
}
#if defined(PICO_RUNTIME_INIT_DEFAULT_ALARM_POOL) && !PICO_RUNTIME_SKIP_INIT_DEFAULT_ALARM_POOL
PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_default_alarm_pool, PICO_RUNTIME_INIT_DEFAULT_ALARM_POOL);
#endif
#endif
// note the timer is created with IRQs on this core
alarm_pool_t *alarm_pool_create_on_timer(alarm_pool_timer_t *timer, uint hardware_alarm_num, uint max_timers) {
alarm_pool_t *pool = (alarm_pool_t *) malloc(sizeof(alarm_pool_t));
if (pool) {
pool->entries = (alarm_pool_entry_t *) calloc(max_timers, sizeof(alarm_pool_entry_t));
ta_hardware_alarm_claim(timer, hardware_alarm_num);
alarm_pool_post_alloc_init(pool, timer, hardware_alarm_num, max_timers);
}
return pool;
}
alarm_pool_t *alarm_pool_create_on_timer_with_unused_hardware_alarm(alarm_pool_timer_t *timer, uint max_timers) {
alarm_pool_t *pool = (alarm_pool_t *) malloc(sizeof(alarm_pool_t));
if (pool) {
pool->entries = (alarm_pool_entry_t *) calloc(max_timers, sizeof(alarm_pool_entry_t));
alarm_pool_post_alloc_init(pool, timer, (uint) ta_hardware_alarm_claim_unused(timer, true), max_timers);
}
return pool;
}
static void alarm_pool_irq_handler(void);
// marker which we can use in place of handler function to indicate we are a repeating timer
#define repeating_timer_marker ((alarm_callback_t)alarm_pool_irq_handler)
#include "hardware/gpio.h"
static void alarm_pool_irq_handler(void) {
// This IRQ handler does the main work, as it always (assuming the IRQ hasn't been enabled on both cores
// which is unsupported) run on the alarm pool's core, and can't be preempted by itself, meaning
// that it doesn't need locks except to protect against linked list, or other state access.
// This simplifies the code considerably, and makes it much faster in general, even though we are forced to take
// two IRQs per alarm.
uint timer_alarm_num;
alarm_pool_timer_t *timer = ta_from_current_irq(&timer_alarm_num);
uint timer_num = ta_timer_num(timer);
alarm_pool_t *pool = pools[timer_num][timer_alarm_num];
assert(pool->timer_alarm_num == timer_alarm_num);
int64_t earliest_target;
// 1. clear force bits if we were forced (do this outside the loop, as forcing is hopefully rare)
ta_clear_force_irq(timer, timer_alarm_num);
do {
// 2. clear the IRQ if it was fired
ta_clear_irq(timer, timer_alarm_num);
// 3. we look at the earliest existing alarm first; the reasoning here is that we
// don't want to delay an existing callback because a later one is added, and
// if both are due now, then we have a race anyway (but we prefer to fire existing
// timers before new ones anyway.
int16_t earliest_index = pool->ordered_head;
// by default, we loop if there was any event pending (we will mark it false
// later if there is no work to do)
if (earliest_index >= 0) {
alarm_pool_entry_t *earliest_entry = &pool->entries[earliest_index];
earliest_target = earliest_entry->target;
if (((int64_t)ta_time_us_64(timer) - earliest_target) >= 0) {
// time to call the callback now (or in the past)
// note that an entry->target of < 0 means the entry has been canceled (not this is set
// by this function, in response to the entry having been queued by the cancel_alarm API
// meaning that we don't need to worry about tearing of the 64 bit value)
int64_t delta;
if (earliest_target >= 0) {
// special case repeating timer without making another function call which adds overhead
if (earliest_entry->callback == repeating_timer_marker) {
repeating_timer_t *rpt = (repeating_timer_t *)earliest_entry->user_data;
delta = rpt->callback(rpt) ? rpt->delay_us : 0;
} else {
alarm_id_t id = make_alarm_id(pool->ordered_head, earliest_entry->sequence);
delta = earliest_entry->callback(id, earliest_entry->user_data);
}
} else {
// negative target means cancel alarm
delta = 0;
}
if (delta) {
int64_t next_time;
if (delta < 0) {
// delta is (positive) delta from last fire time
next_time = earliest_target - delta;
} else {
// delta is relative to now
next_time = (int64_t) ta_time_us_64(timer) + delta;
}
earliest_entry->target = next_time;
// need to re-add, unless we are the only entry or already at the front
if (earliest_entry->next >= 0 && next_time - pool->entries[earliest_entry->next].target >= 0) {
// unlink this item
pool->ordered_head = earliest_entry->next;
int16_t *prev = &pool->ordered_head;
// find insertion point; note >= as if we add a new item for the same time as another, then it follows
while (*prev >= 0 && (next_time - pool->entries[*prev].target) >= 0) {
prev = &pool->entries[*prev].next;
}
earliest_entry->next = *prev;
*prev = earliest_index;
}
} else {
// need to remove the item
pool->ordered_head = earliest_entry->next;
// and add it back to the free list (under lock)
uint32_t save = spin_lock_blocking(pool->lock);
earliest_entry->next = pool->free_head;
pool->free_head = earliest_index;
spin_unlock(pool->lock, save);
}
}
}
// if we have any new alarms, add them to the ordered list
if (pool->new_head >= 0) {
uint32_t save = spin_lock_blocking(pool->lock);
// must re-read new head under lock
int16_t new_index = pool->new_head;
// clear the list
pool->new_head = -1;
spin_unlock(pool->lock, save);
// insert each of the new items
while (new_index >= 0) {
alarm_pool_entry_t *new_entry = &pool->entries[new_index];
int64_t new_entry_time = new_entry->target;
int16_t *prev = &pool->ordered_head;
// find insertion point; note >= as if we add a new item for the same time as another, then it follows
while (*prev >= 0 && (new_entry_time - pool->entries[*prev].target) >= 0) {
prev = &pool->entries[*prev].next;
}
int16_t next = *prev;
*prev = new_index;
new_index = new_entry->next;
new_entry->next = next;
}
}
// if we have any canceled alarms, then mark them for removal by setting their due time to -1 (which will
// cause them to be handled the next time round and removed)
if (pool->has_pending_cancellations) {
pool->has_pending_cancellations = false;
__compiler_memory_barrier();
int16_t *prev = &pool->ordered_head;
// set target for canceled items to -1, and move to front of the list
for(int16_t index = pool->ordered_head; index != -1; ) {
alarm_pool_entry_t *entry = &pool->entries[index];
int16_t next = entry->next;
if ((int16_t)entry->sequence < 0) {
// mark for deletion
entry->target = -1;
if (index != pool->ordered_head) {
// move to start of queue
*prev = entry->next;
entry->next = pool->ordered_head;
pool->ordered_head = index;
}
} else {
prev = &entry->next;
}
index = next;
}
}
earliest_index = pool->ordered_head;
if (earliest_index < 0) break;
// need to wait
alarm_pool_entry_t *earliest_entry = &pool->entries[earliest_index];
earliest_target = earliest_entry->target;
// we are leaving a timeout every 2^32 microseconds anyway if there is no valid target, so we can choose any value.
// best_effort_wfe_or_timeout now relies on it being the last value set, and arguably this is the
// best value anyway, as it is the furthest away from the last fire.
if (earliest_target != -1) { // cancelled alarm has target of -1
ta_set_timeout(timer, timer_alarm_num, earliest_target);
}
// check we haven't now passed the target time; if not we don't want to loop again
} while ((earliest_target - (int64_t)ta_time_us_64(timer)) <= 0);
// We always want the timer IRQ to wake a WFE so that best_effort_wfe_or_timeout() will wake up. It will wake
// a WFE on its own core by nature of having taken an IRQ, but we do an explicit SEV so it wakes the other core
__sev();
}
void alarm_pool_post_alloc_init(alarm_pool_t *pool, alarm_pool_timer_t *timer, uint hardware_alarm_num, uint max_timers) {
pool->timer = timer;
pool->lock = spin_lock_instance(next_striped_spin_lock_num());
pool->timer_alarm_num = (uint8_t) hardware_alarm_num;
invalid_params_if(PICO_TIME, max_timers > 65536);
pool->num_entries = (uint16_t)max_timers;
pool->core_num = (uint8_t) get_core_num();
pool->new_head = pool->ordered_head = -1;
pool->free_head = (int16_t)(max_timers - 1);
for(uint i=0;i<max_timers;i++) {
pool->entries[i].next = (int16_t)(i-1);
}
pools[ta_timer_num(timer)][hardware_alarm_num] = pool;
ta_enable_irq_handler(timer, hardware_alarm_num, alarm_pool_irq_handler);
}
void alarm_pool_destroy(alarm_pool_t *pool) {
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
if (pool == &default_alarm_pool) {
assert(false); // attempt to delete default alarm pool
return;
}
#endif
ta_disable_irq_handler(pool->timer, pool->timer_alarm_num, alarm_pool_irq_handler);
assert(pools[ta_timer_num(pool->timer)][pool->timer_alarm_num] == pool);
pools[ta_timer_num(pool->timer)][pool->timer_alarm_num] = NULL;
free(pool->entries);
free(pool);
}
alarm_id_t alarm_pool_add_alarm_at(alarm_pool_t *pool, absolute_time_t time, alarm_callback_t callback,
void *user_data, bool fire_if_past) {
if (!fire_if_past) {
absolute_time_t t = get_absolute_time();
if (absolute_time_diff_us(t, time) < 0) return 0;
}
return alarm_pool_add_alarm_at_force_in_context(pool, time, callback, user_data);
}
alarm_id_t alarm_pool_add_alarm_at_force_in_context(alarm_pool_t *pool, absolute_time_t time, alarm_callback_t callback,
void *user_data) {
// ---- take a free pool entry
uint32_t save = spin_lock_blocking(pool->lock);
int16_t index = pool->free_head;
alarm_pool_entry_t *entry = &pool->entries[index];
if (index >= 0) {
// remove from free list
pool->free_head = entry->next;
}
spin_unlock(pool->lock, save);
if (index < 0) return PICO_ERROR_GENERIC; // PICO_ERROR_INSUFFICIENT_RESOURCES - not using to preserve previous -1 return code
// ---- initialize the pool entry
entry->callback = callback;
entry->user_data = user_data;
entry->target = (int64_t)to_us_since_boot(time);
uint16_t next_sequence = (entry->sequence + 1) & 0x7fff;
if (!next_sequence) next_sequence = 1; // zero is not allowed
entry->sequence = next_sequence;
alarm_id_t id = make_alarm_id(index, next_sequence);
// ---- and add it to the new list
save = spin_lock_blocking(pool->lock);
entry->next = pool->new_head;
pool->new_head = index;
spin_unlock(pool->lock, save);
// force the IRQ
ta_force_irq(pool->timer, pool->timer_alarm_num);
return id;
}
bool alarm_pool_cancel_alarm(alarm_pool_t *pool, alarm_id_t alarm_id) {
int16_t index = alarm_index(alarm_id);
if (index >= pool->num_entries) return false;
uint16_t sequence = alarm_sequence(alarm_id);
bool canceled = false;
alarm_pool_entry_t *entry = &pool->entries[index];
uint32_t save = spin_lock_blocking(pool->lock);
// note this will not be true if the entry is already canceled (as the entry->sequence
// will have the top bit set)
uint current_sequence = entry->sequence;
if (sequence == current_sequence) {
entry->sequence = (uint16_t)(current_sequence | 0x8000);
__compiler_memory_barrier();
pool->has_pending_cancellations = true;
canceled = true;
}
spin_unlock(pool->lock, save);
// force the IRQ if we need to clean up an alarm id
if (canceled) ta_force_irq(pool->timer, pool->timer_alarm_num);
return canceled;
}
uint alarm_pool_timer_alarm_num(alarm_pool_t *pool) {
return pool->timer_alarm_num;
}
uint alarm_pool_core_num(alarm_pool_t *pool) {
return pool->core_num;
}
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
static int64_t sleep_until_callback(__unused alarm_id_t id, __unused void *user_data) {
uint32_t save = spin_lock_blocking(sleep_notifier.spin_lock);
lock_internal_spin_unlock_with_notify(&sleep_notifier, save);
return 0;
}
#endif
void sleep_until(absolute_time_t t) {
#if PICO_ON_DEVICE && !defined(NDEBUG)
if (__get_current_exception()) {
panic("Attempted to sleep inside of an exception handler; use busy_wait if you must");
}
#endif
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
uint64_t t_us = to_us_since_boot(t);
uint64_t t_before_us = t_us - PICO_TIME_SLEEP_OVERHEAD_ADJUST_US;
// needs to work in the first PICO_TIME_SLEEP_OVERHEAD_ADJUST_US of boot
if (t_before_us > t_us) t_before_us = 0;
absolute_time_t t_before;
update_us_since_boot(&t_before, t_before_us);
if (absolute_time_diff_us(get_absolute_time(), t_before) > 0) {
if (add_alarm_at(t_before, sleep_until_callback, NULL, false) >= 0) {
// able to add alarm for just before the time
while (!time_reached(t_before)) {
uint32_t save = spin_lock_blocking(sleep_notifier.spin_lock);
lock_internal_spin_unlock_with_wait(&sleep_notifier, save);
}
}
}
#else
// hook in case we're in RTOS; note we assume using the alarm pool is better always if available.
sync_internal_yield_until_before(t);
#endif
// now wait until the exact time
busy_wait_until(t);
}
void sleep_us(uint64_t us) {
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
sleep_until(make_timeout_time_us(us));
#else
if (us < PICO_TIME_SLEEP_OVERHEAD_ADJUST_US) {
busy_wait_us(us);
} else {
// hook in case we're in RTOS; note we assume using the alarm pool is better always if available.
absolute_time_t t = make_timeout_time_us(us - PICO_TIME_SLEEP_OVERHEAD_ADJUST_US);
sync_internal_yield_until_before(t);
// then wait the rest of the way
busy_wait_until(t);
}
#endif
}
void sleep_ms(uint32_t ms) {
sleep_us(ms * 1000ull);
}
bool best_effort_wfe_or_timeout(absolute_time_t timeout_timestamp) {
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
if (__get_current_exception()) {
tight_loop_contents();
return time_reached(timeout_timestamp);
} else {
alarm_id_t id;
// note that as of SDK 2.0.0 calling add_alarm_at always causes a SEV. What we really
// want to do is cause an IRQ at the specified time in the future if there is not
// an IRQ already happening before then. The problem is that the IRQ may be happening on the
// other core, so taking an IRQ is the only way to get the state protection.
//
// Therefore, we make a compromise; we will set the alarm, if we won't wake up before the right time
// already. This means that repeated calls to this function with the same timeout will work correctly
// after the first one! This is fine, because we ask callers to use a polling loop on another
// event variable when using this function.
//
// For this to work, we require that once we have set an alarm, an SEV happens no later than that, even
// if we cancel the alarm as we do below. Therefore, the IRQ handler (which is always enabled) will
// never set its wakeup time to a later value, but instead wake up once and then wake up again.
//
// This overhead when canceling alarms is a small price to pay for the much simpler/faster/cleaner
// implementation that relies on the IRQ handler (on a single core) being the only state accessor.
//
// Note also, that the use of software spin locks on RP2350 to access state would always cause a SEV
// due to use of LDREX etc., so actually using spin locks to protect the state would be worse.
if (ta_wakes_up_on_or_before(alarm_pool_get_default()->timer, alarm_pool_get_default()->timer_alarm_num,
(int64_t)to_us_since_boot(timeout_timestamp))) {
// we already are waking up at or before when we want to (possibly due to us having been called
// before in a loop), so we can do an actual WFE. Note we rely on the fact that the alarm pool IRQ
// handler always does an explicit SEV, since it may be on the other core.
__wfe();
return time_reached(timeout_timestamp);
} else {
id = add_alarm_at(timeout_timestamp, sleep_until_callback, NULL, false);
if (id <= 0) {
tight_loop_contents();
return time_reached(timeout_timestamp);
} else {
if (!time_reached(timeout_timestamp)) {
// ^ at the point above the timer hadn't fired, so it is safe
// to wait; the event will happen due to IRQ at some point between
// then and the correct wakeup time
__wfe();
}
// we need to clean up if it wasn't us that caused the wfe; if it was this will be a noop.
cancel_alarm(id);
return time_reached(timeout_timestamp);
}
}
}
#else
tight_loop_contents();
return time_reached(timeout_timestamp);
#endif
}
bool alarm_pool_add_repeating_timer_us(alarm_pool_t *pool, int64_t delay_us, repeating_timer_callback_t callback, void *user_data, repeating_timer_t *out) {
if (!delay_us) delay_us = 1;
out->pool = pool;
out->callback = callback;
out->delay_us = delay_us;
out->user_data = user_data;
out->alarm_id = alarm_pool_add_alarm_at(pool, make_timeout_time_us((uint64_t)(delay_us >= 0 ? delay_us : -delay_us)),
repeating_timer_marker, out, true);
return out->alarm_id > 0;
}
bool cancel_repeating_timer(repeating_timer_t *timer) {
bool rc = false;
if (timer->alarm_id) {
rc = alarm_pool_cancel_alarm(timer->pool, timer->alarm_id);
timer->alarm_id = 0;
}
return rc;
}
alarm_pool_timer_t *alarm_pool_timer_for_timer_num(uint timer_num) {
return ta_timer_instance(timer_num);
}
alarm_pool_timer_t *alarm_pool_get_default_timer(void) {
return ta_default_timer_instance();
}
int64_t alarm_pool_remaining_alarm_time_us(alarm_pool_t *pool, alarm_id_t alarm_id) {
// note there is no point distinguishing between invalid alarm_id and timer passed,
// since an alarm_id that has fired without being re-enabled becomes logically invalid after
// that point anyway
int64_t rc = -1;
int16_t index = alarm_index(alarm_id);
if ((uint16_t)index < pool->num_entries) {
uint16_t sequence = alarm_sequence(alarm_id);
alarm_pool_entry_t *entry = &pool->entries[index];
if (entry->sequence == sequence) {
uint32_t save = spin_lock_blocking(pool->lock);
int16_t search_index = pool->ordered_head;
while (search_index >= 0) {
entry = &pool->entries[search_index];
if (index == search_index) {
if (entry->sequence == sequence) {
rc = entry->target - (int64_t) ta_time_us_64(pool->timer);
}
break;
}
search_index = entry->next;
}
spin_unlock(pool->lock, save);
}
}
return rc;
}
int32_t alarm_pool_remaining_alarm_time_ms(alarm_pool_t *pool, alarm_id_t alarm_id) {
int64_t rc = alarm_pool_remaining_alarm_time_us(pool, alarm_id);
if (rc >= 0) rc /= 1000;
return rc >= INT32_MAX ? INT32_MAX : (int32_t) rc;
}
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
int64_t remaining_alarm_time_us(alarm_id_t alarm_id) {
return alarm_pool_remaining_alarm_time_us(alarm_pool_get_default(), alarm_id);
}
int32_t remaining_alarm_time_ms(alarm_id_t alarm_id) {
return alarm_pool_remaining_alarm_time_ms(alarm_pool_get_default(), alarm_id);
}
#endif

View file

@ -1,32 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/timeout_helper.h"
static bool check_single_timeout_us(timeout_state_t *ts, __unused bool reset) {
return time_reached(ts->next_timeout);
}
check_timeout_fn init_single_timeout_until(timeout_state_t *ts, absolute_time_t target) {
ts->next_timeout = target;
return check_single_timeout_us;
}
static bool check_per_iteration_timeout_us(timeout_state_t *ts, bool reset) {
if (reset) {
ts->next_timeout = make_timeout_time_us(ts->param);
}
if (time_reached(ts->next_timeout)) {
return true;
}
return false;
}
check_timeout_fn init_per_iteration_timeout_us(timeout_state_t *ts, uint64_t per_iteration_timeout_us) {
ts->next_timeout = make_timeout_time_us(per_iteration_timeout_us);
ts->param = per_iteration_timeout_us;
return check_per_iteration_timeout_us;
}

View file

@ -1,28 +0,0 @@
/*
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_USB_RESET_INTERFACE_H
#define _PICO_USB_RESET_INTERFACE_H
/** \file usb_reset_interface.h
* \defgroup pico_usb_reset_interface_headers pico_usb_reset_interface_headers
*
* \brief Definition for the reset interface that may be exposed by the pico_stdio_usb library
*/
// VENDOR sub-class for the reset interface
#define RESET_INTERFACE_SUBCLASS 0x00
// VENDOR protocol for the reset interface
#define RESET_INTERFACE_PROTOCOL 0x01
// CONTROL requests:
// reset to BOOTSEL
#define RESET_REQUEST_BOOTSEL 0x01
// regular flash boot
#define RESET_REQUEST_FLASH 0x02
#endif

View file

@ -1,95 +0,0 @@
#include "pico/util/datetime.h"
#include <stdio.h>
#if PICO_INCLUDE_RTC_DATETIME
static const char *DATETIME_MONTHS[12] = {
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
};
static const char *DATETIME_DOWS[7] = {
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
};
void datetime_to_str(char *buf, uint buf_size, const datetime_t *t) {
snprintf(buf,
buf_size,
"%s %d %s %d:%02d:%02d %d",
DATETIME_DOWS[t->dotw],
t->day,
DATETIME_MONTHS[t->month - 1],
t->hour,
t->min,
t->sec,
t->year);
};
bool time_to_datetime(time_t time, datetime_t *dt) {
struct tm local;
if (localtime_r(&time, &local)) {
dt->year = (int16_t) (local.tm_year + 1900); // 0..4095
dt->month = (int8_t) (local.tm_mon + 1); // 1..12, 1 is January
dt->day = (int8_t) local.tm_mday; // 1..28,29,30,31 depending on month
dt->dotw = (int8_t) local.tm_wday; // 0..6, 0 is Sunday
dt->hour = (int8_t) local.tm_hour; // 0..23
dt->min = (int8_t) local.tm_min; // 0..59
dt->sec = (int8_t) local.tm_sec; // 0..59
return true;
}
return false;
}
bool datetime_to_time(const datetime_t *dt, time_t *time) {
struct tm local;
local.tm_year = dt->year - 1900;
local.tm_mon = dt->month - 1;
local.tm_mday = dt->day;
local.tm_hour = dt->hour;
local.tm_min = dt->min;
local.tm_sec = dt->sec;
*time = mktime(&local);
return *time >= 0;
}
#endif
uint64_t timespec_to_ms(const struct timespec *ts) {
int64_t rc = ts->tv_sec * 1000;
rc += ts->tv_nsec / 1000000;
return (uint64_t) rc;
}
void ms_to_timespec(uint64_t ms, struct timespec *ts) {
ts->tv_sec = (time_t)((int64_t)ms / 1000);
ts->tv_nsec = ((long)((int64_t)ms % 1000)) * 1000000;
}
uint64_t timespec_to_us(const struct timespec *ts) {
int64_t rc = ts->tv_sec * 1000000;
rc += ts->tv_nsec / 1000;
return (uint64_t) rc;
}
void us_to_timespec(uint64_t ms, struct timespec *ts) {
ts->tv_sec = (time_t)((int64_t)ms / 1000000);
ts->tv_nsec = ((long)((int64_t)ms % 1000000)) * 1000;
}

View file

@ -1,4 +0,0 @@
/**
* \defgroup pico_util pico_util
* \brief Useful data structures and utility functions
*/

View file

@ -1,47 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_UTIL_DATETIME_H
#define _PICO_UTIL_DATETIME_H
#include "pico.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \file datetime.h
* \defgroup util_datetime datetime
* \brief Date/Time formatting
* \ingroup pico_util
*/
#if PICO_INCLUDE_RTC_DATETIME
#include <time.h>
/*! \brief Convert a datetime_t structure to a string
* \ingroup util_datetime
*
* \param buf character buffer to accept generated string
* \param buf_size The size of the passed in buffer
* \param t The datetime to be converted.
*/
void datetime_to_str(char *buf, uint buf_size, const datetime_t *t);
bool time_to_datetime(time_t time, datetime_t *dt);
bool datetime_to_time(const datetime_t *dt, time_t *time);
#endif
#include <sys/time.h>
uint64_t timespec_to_ms(const struct timespec *ts);
uint64_t timespec_to_us(const struct timespec *ts);
void ms_to_timespec(uint64_t ms, struct timespec *ts);
void us_to_timespec(uint64_t ms, struct timespec *ts);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,309 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_UTIL_PHEAP_H
#define _PICO_UTIL_PHEAP_H
#include "pico.h"
#ifdef __cplusplus
extern "C" {
#endif
// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_PHEAP, Enable/disable assertions in the pheap module, type=bool, default=0, group=pico_util
#ifndef PARAM_ASSERTIONS_ENABLED_PHEAP
#define PARAM_ASSERTIONS_ENABLED_PHEAP 0
#endif
/**
* \file pheap.h
* \defgroup util_pheap pheap
* \brief Pairing Heap Implementation
* \ingroup pico_util
*
* pheap defines a simple pairing heap. The implementation simply tracks array indexes, it is up to
* the user to provide storage for heap entries and a comparison function.
*
* NOTE: This class is not safe for concurrent usage. It should be externally protected. Furthermore
* if used concurrently, the caller needs to protect around their use of the returned id.
* For example, ph_remove_and_free_head returns the id of an element that is no longer in the heap.
* The user can still use this to look at the data in their companion array, however obviously further operations
* on the heap may cause them to overwrite that data as the id may be reused on subsequent operations
*
*/
// PICO_CONFIG: PICO_PHEAP_MAX_ENTRIES, Maximum number of entries in the pheap, min=1, max=65534, default=255, group=pico_util
#ifndef PICO_PHEAP_MAX_ENTRIES
#define PICO_PHEAP_MAX_ENTRIES 255
#endif
// public heap_node ids are numbered from 1 (0 means none)
#if PICO_PHEAP_MAX_ENTRIES < 256
typedef uint8_t pheap_node_id_t;
#elif PICO_PHEAP_MAX_ENTRIES < 65535
typedef uint16_t pheap_node_id_t;
#else
#error invalid PICO_PHEAP_MAX_ENTRIES
#endif
typedef struct pheap_node {
pheap_node_id_t child, sibling, parent;
} pheap_node_t;
/**
* \brief A user comparator function for nodes in a pairing heap.
* \ingroup util_pheap
*
* \return true if a < b in natural order. Note this relative ordering must be stable from call to call.
*/
typedef bool (*pheap_comparator)(void *user_data, pheap_node_id_t a, pheap_node_id_t b);
typedef struct pheap {
pheap_node_t *nodes;
pheap_comparator comparator;
void *user_data;
pheap_node_id_t max_nodes;
pheap_node_id_t root_id;
// we remove from head and add to tail to stop reusing the same ids
pheap_node_id_t free_head_id;
pheap_node_id_t free_tail_id;
} pheap_t;
/**
* \brief Create a pairing heap, which effectively maintains an efficient sorted ordering
* of nodes. The heap itself stores no user per-node state, it is expected
* that the user maintains a companion array. A comparator function must
* be provided so that the heap implementation can determine the relative ordering of nodes
* \ingroup util_pheap
*
* \param max_nodes the maximum number of nodes that may be in the heap (this is bounded by
* PICO_PHEAP_MAX_ENTRIES which defaults to 255 to be able to store indexes
* in a single byte).
* \param comparator the node comparison function
* \param user_data a user data pointer associated with the heap that is provided in callbacks
* \return a newly allocated and initialized heap
*/
pheap_t *ph_create(uint max_nodes, pheap_comparator comparator, void *user_data);
/**
* \brief Removes all nodes from the pairing heap
* \ingroup util_pheap
* \param heap the heap
*/
void ph_clear(pheap_t *heap);
/**
* \brief De-allocates a pairing heap
* \ingroup util_pheap
*
* Note this method must *ONLY* be called on heaps created by ph_create()
* \param heap the heap
*/
void ph_destroy(pheap_t *heap);
// internal method
static inline pheap_node_t *ph_get_node(pheap_t *heap, pheap_node_id_t id) {
assert(id && id <= heap->max_nodes);
return heap->nodes + id - 1;
}
// internal method
static void ph_add_child_node(pheap_t *heap, pheap_node_id_t parent_id, pheap_node_id_t child_id) {
pheap_node_t *n = ph_get_node(heap, parent_id);
assert(parent_id);
assert(child_id);
assert(parent_id != child_id);
pheap_node_t *c = ph_get_node(heap, child_id);
c->parent = parent_id;
if (!n->child) {
n->child = child_id;
} else {
c->sibling = n->child;
n->child = child_id;
}
}
// internal method
static pheap_node_id_t ph_merge_nodes(pheap_t *heap, pheap_node_id_t a, pheap_node_id_t b) {
if (!a) return b;
if (!b) return a;
if (heap->comparator(heap->user_data, a, b)) {
ph_add_child_node(heap, a, b);
return a;
} else {
ph_add_child_node(heap, b, a);
return b;
}
}
/**
* \brief Allocate a new node from the unused space in the heap
* \ingroup util_pheap
*
* \param heap the heap
* \return an identifier for the node, or 0 if the heap is full
*/
static inline pheap_node_id_t ph_new_node(pheap_t *heap) {
if (!heap->free_head_id) return 0;
pheap_node_id_t id = heap->free_head_id;
pheap_node_t *hn = ph_get_node(heap, id);
heap->free_head_id = hn->sibling;
if (!heap->free_head_id) heap->free_tail_id = 0;
hn->child = hn->sibling = hn->parent = 0;
return id;
}
/**
* \brief Inserts a node into the heap.
* \ingroup util_pheap
*
* This method inserts a node (previously allocated by ph_new_node())
* into the heap, determining the correct order by calling
* the heap's comparator
*
* \param heap the heap
* \param id the id of the node to insert
* \return the id of the new head of the pairing heap (i.e. node that compares first)
*/
static inline pheap_node_id_t ph_insert_node(pheap_t *heap, pheap_node_id_t id) {
assert(id);
pheap_node_t *hn = ph_get_node(heap, id);
hn->child = hn->sibling = hn->parent = 0;
heap->root_id = ph_merge_nodes(heap, heap->root_id, id);
return heap->root_id;
}
/**
* \brief Returns the head node in the heap, i.e. the node
* which compares first, but without removing it from the heap.
* \ingroup util_pheap
*
* \param heap the heap
* \return the current head node id
*/
static inline pheap_node_id_t ph_peek_head(pheap_t *heap) {
return heap->root_id;
}
/**
* \brief Remove the head node from the pairing heap. This head node is
* the node which compares first in the logical ordering provided
* by the comparator.
* \ingroup util_pheap
*
* Note that in the case of free == true, the returned id is no longer
* allocated and may be re-used by future node allocations, so the caller
* should retrieve any per node state from the companion array before modifying
* the heap further.
*
* @param heap the heap
* @param free true if the id is also to be freed; false if not - useful if the caller
* may wish to re-insert an item with the same id)
* @return the old head node id.
*/
pheap_node_id_t ph_remove_head(pheap_t *heap, bool free);
/**
* \brief Remove the head node from the pairing heap. This head node is
* the node which compares first in the logical ordering provided
* by the comparator.
* \ingroup util_pheap
*
* Note that the returned id will be freed, and thus may be re-used by future node allocations,
* so the caller should retrieve any per node state from the companion array before modifying
* the heap further.
*
* @param heap the heap
* @return the old head node id.
*/
static inline pheap_node_id_t ph_remove_and_free_head(pheap_t *heap) {
return ph_remove_head(heap, true);
}
/**
* \brief Remove and free an arbitrary node from the pairing heap. This is a more
* costly operation than removing the head via ph_remove_and_free_head()
* \ingroup util_pheap
*
* @param heap the heap
* @param id the id of the node to free
* @return true if the the node was in the heap, false otherwise
*/
bool ph_remove_and_free_node(pheap_t *heap, pheap_node_id_t id);
/**
* \brief Determine if the heap contains a given node. Note containment refers
* to whether the node is inserted (ph_insert_node()) vs allocated (ph_new_node())
* \ingroup util_pheap
*
* @param heap the heap
* @param id the id of the node
* @return true if the heap contains a node with the given id, false otherwise.
*/
static inline bool ph_contains_node(pheap_t *heap, pheap_node_id_t id) {
return id == heap->root_id || ph_get_node(heap, id)->parent;
}
/**
* \brief Free a node that is not currently in the heap, but has been allocated
* \ingroup util_pheap
*
* @param heap the heap
* @param id the id of the node
*/
static inline void ph_free_node(pheap_t *heap, pheap_node_id_t id) {
assert(id && !ph_contains_node(heap, id));
if (heap->free_tail_id) {
ph_get_node(heap, heap->free_tail_id)->sibling = id;
}
if (!heap->free_head_id) {
assert(!heap->free_tail_id);
heap->free_head_id = id;
}
heap->free_tail_id = id;
}
/**
* \brief Print a representation of the heap for debugging
* \ingroup util_pheap
*
* @param heap the heap
* @param dump_key a method to print a node value
* @param user_data the user data to pass to the dump_key method
*/
void ph_dump(pheap_t *heap, void (*dump_key)(pheap_node_id_t id, void *user_data), void *user_data);
/**
* \brief Initialize a statically allocated heap (ph_create() using the C heap).
* The heap member `nodes` must be allocated of size max_nodes.
* \ingroup util_pheap
*
* @param heap the heap
* @param max_nodes the max number of nodes in the heap (matching the size of the heap's nodes array)
* @param comparator the comparator for the heap
* @param user_data the user data for the heap.
*/
void ph_post_alloc_init(pheap_t *heap, uint max_nodes, pheap_comparator comparator, void *user_data);
/**
* \brief Define a statically allocated pairing heap. This must be initialized
* by ph_post_alloc_init
* \ingroup util_pheap
*/
#define PHEAP_DEFINE_STATIC(name, _max_nodes) \
static_assert(_max_nodes && _max_nodes < (1u << (8 * sizeof(pheap_node_id_t))), ""); \
static pheap_node_t name ## _nodes[_max_nodes]; \
static pheap_t name = { \
.nodes = name ## _nodes, \
.max_nodes = _max_nodes \
};
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,227 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_UTIL_QUEUE_H
#define _PICO_UTIL_QUEUE_H
#include "pico.h"
#include "hardware/sync.h"
// PICO_CONFIG: PICO_QUEUE_MAX_LEVEL, Maintain a field for the highest level that has been reached by a queue, type=bool, default=0, advanced=true, group=queue
#ifndef PICO_QUEUE_MAX_LEVEL
#define PICO_QUEUE_MAX_LEVEL 0
#endif
/** \file queue.h
* \defgroup queue queue
* \brief Multi-core and IRQ safe queue implementation
*
* Note that this queue stores values of a specified size, and pushed values are copied into the queue
* \ingroup pico_util
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "pico/lock_core.h"
typedef struct {
lock_core_t core;
uint8_t *data;
uint16_t wptr;
uint16_t rptr;
uint16_t element_size;
uint16_t element_count;
#if PICO_QUEUE_MAX_LEVEL
uint16_t max_level;
#endif
} queue_t;
/*! \brief Initialise a queue with a specific spinlock for concurrency protection
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param element_size Size of each value in the queue
* \param element_count Maximum number of entries in the queue
* \param spinlock_num The spin ID used to protect the queue
*/
void queue_init_with_spinlock(queue_t *q, uint element_size, uint element_count, uint spinlock_num);
/*! \brief Initialise a queue, allocating a (possibly shared) spinlock
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param element_size Size of each value in the queue
* \param element_count Maximum number of entries in the queue
*/
static inline void queue_init(queue_t *q, uint element_size, uint element_count) {
queue_init_with_spinlock(q, element_size, element_count, next_striped_spin_lock_num());
}
/*! \brief Destroy the specified queue.
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
*
* Does not deallocate the queue_t structure itself.
*/
void queue_free(queue_t *q);
/*! \brief Unsafe check of level of the specified queue.
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \return Number of entries in the queue
*
* This does not use the spinlock, so may return incorrect results if the
* spin lock is not externally locked
*/
static inline uint queue_get_level_unsafe(queue_t *q) {
int32_t rc = (int32_t)q->wptr - (int32_t)q->rptr;
if (rc < 0) {
rc += q->element_count + 1;
}
return (uint)rc;
}
/*! \brief Check of level of the specified queue.
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \return Number of entries in the queue
*/
static inline uint queue_get_level(queue_t *q) {
uint32_t save = spin_lock_blocking(q->core.spin_lock);
uint level = queue_get_level_unsafe(q);
spin_unlock(q->core.spin_lock, save);
return level;
}
#if PICO_QUEUE_MAX_LEVEL
/*! \brief Returns the highest level reached by the specified queue since it was created
* or since the max level was reset
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \return Maximum level of the queue
*/
static inline uint queue_get_max_level(queue_t *q) {
return q->max_level;
}
#endif
#if PICO_QUEUE_MAX_LEVEL
/*! \brief Reset the highest level reached of the specified queue.
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
*/
static inline void queue_reset_max_level(queue_t *q) {
uint32_t save = spin_lock_blocking(q->core.spin_lock);
q->max_level = queue_get_level_unsafe(q);
spin_unlock(q->core.spin_lock, save);
}
#endif
/*! \brief Check if queue is empty
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \return true if queue is empty, false otherwise
*
* This function is interrupt and multicore safe.
*/
static inline bool queue_is_empty(queue_t *q) {
return queue_get_level(q) == 0;
}
/*! \brief Check if queue is full
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \return true if queue is full, false otherwise
*
* This function is interrupt and multicore safe.
*/
static inline bool queue_is_full(queue_t *q) {
return queue_get_level(q) == q->element_count;
}
// nonblocking queue access functions:
/*! \brief Non-blocking add value queue if not full
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param data Pointer to value to be copied into the queue
* \return true if the value was added
*
* If the queue is full this function will return immediately with false, otherwise
* the data is copied into a new value added to the queue, and this function will return true.
*/
bool queue_try_add(queue_t *q, const void *data);
/*! \brief Non-blocking removal of entry from the queue if non empty
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param data Pointer to the location to receive the removed value, or NULL if the data isn't required
* \return true if a value was removed
*
* If the queue is not empty function will copy the removed value into the location provided and return
* immediately with true, otherwise the function will return immediately with false.
*/
bool queue_try_remove(queue_t *q, void *data);
/*! \brief Non-blocking peek at the next item to be removed from the queue
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param data Pointer to the location to receive the peeked value, or NULL if the data isn't required
* \return true if there was a value to peek
*
* If the queue is not empty this function will return immediately with true with the peeked entry
* copied into the location specified by the data parameter, otherwise the function will return false.
*/
bool queue_try_peek(queue_t *q, void *data);
// blocking queue access functions:
/*! \brief Blocking add of value to queue
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param data Pointer to value to be copied into the queue
*
* If the queue is full this function will block, until a removal happens on the queue
*/
void queue_add_blocking(queue_t *q, const void *data);
/*! \brief Blocking remove entry from queue
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param data Pointer to the location to receive the removed value, or NULL if the data isn't required
*
* If the queue is empty this function will block until a value is added.
*/
void queue_remove_blocking(queue_t *q, void *data);
/*! \brief Blocking peek at next value to be removed from queue
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param data Pointer to the location to receive the peeked value, or NULL if the data isn't required
*
* If the queue is empty function will block until a value is added
*/
void queue_peek_blocking(queue_t *q, void *data);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,138 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <stdlib.h>
#include "pico/util/pheap.h"
pheap_t *ph_create(uint max_nodes, pheap_comparator comparator, void *user_data) {
invalid_params_if(PHEAP, !max_nodes || max_nodes >= (1u << (8 * sizeof(pheap_node_id_t))));
pheap_t *heap = calloc(1, sizeof(pheap_t));
heap->nodes = calloc(max_nodes, sizeof(pheap_node_t));
ph_post_alloc_init(heap, max_nodes, comparator, user_data);
return heap;
}
void ph_post_alloc_init(pheap_t *heap, uint max_nodes, pheap_comparator comparator, void *user_data) {
invalid_params_if(PHEAP, !max_nodes || max_nodes >= (1u << (8 * sizeof(pheap_node_id_t))));
heap->max_nodes = (pheap_node_id_t) max_nodes;
heap->comparator = comparator;
heap->user_data = user_data;
ph_clear(heap);
}
void ph_clear(pheap_t *heap) {
heap->root_id = 0;
heap->free_head_id = 1;
heap->free_tail_id = heap->max_nodes;
for(pheap_node_id_t i = 1; i < heap->max_nodes; i++) {
ph_get_node(heap, i)->sibling = (pheap_node_id_t)(i + 1);
}
ph_get_node(heap, heap->max_nodes)->sibling = 0;
}
void ph_destroy(pheap_t *heap) {
free(heap->nodes);
free(heap);
}
pheap_node_id_t ph_merge_two_pass(pheap_t *heap, pheap_node_id_t id) {
if (!id || !ph_get_node(heap, id)->sibling) {
return id;
} else {
pheap_node_id_t a, b, new_node;
a = id;
b = ph_get_node(heap, id)->sibling;
new_node = ph_get_node(heap, b)->sibling;
ph_get_node(heap, a)->sibling = ph_get_node(heap, b)->sibling = 0;
return ph_merge_nodes(heap, ph_merge_nodes(heap, a, b), ph_merge_two_pass(heap, new_node));
}
}
static pheap_node_id_t ph_remove_any_head(pheap_t *heap, pheap_node_id_t root_id, bool free) {
assert(root_id);
// printf("Removing head %d (parent %d sibling %d)\n", root_id, ph_get_node(heap, root_id)->parent, ph_get_node(heap, root_id)->sibling);
assert(!ph_get_node(heap, root_id)->sibling);
assert(!ph_get_node(heap, root_id)->parent);
pheap_node_id_t new_root_id = ph_merge_two_pass(heap, ph_get_node(heap, root_id)->child);
if (free) {
if (heap->free_tail_id) {
ph_get_node(heap, heap->free_tail_id)->sibling = root_id;
}
if (!heap->free_head_id) {
assert(!heap->free_tail_id);
heap->free_head_id = root_id;
}
heap->free_tail_id = root_id;
}
if (new_root_id) ph_get_node(heap, new_root_id)->parent = 0;
ph_get_node(heap, root_id)->sibling = 0;
return new_root_id;
}
pheap_node_id_t ph_remove_head(pheap_t *heap, bool free) {
pheap_node_id_t old_root_id = ph_peek_head(heap);
heap->root_id = ph_remove_any_head(heap, old_root_id, free);
return old_root_id;
}
bool ph_remove_and_free_node(pheap_t *heap, pheap_node_id_t id) {
// 1) trivial cases
if (!id) return false;
if (id == heap->root_id) {
ph_remove_and_free_head(heap);
return true;
}
// 2) unlink the node from the tree
pheap_node_t *node = ph_get_node(heap, id);
if (!node->parent) return false; // not in tree
pheap_node_t *parent = ph_get_node(heap, node->parent);
if (parent->child == id) {
parent->child = node->sibling;
} else {
pheap_node_id_t prev_sibling_id = parent->child;
bool __unused found = false;
do {
pheap_node_t *prev_sibling = ph_get_node(heap, prev_sibling_id);
if (prev_sibling->sibling == id) {
prev_sibling->sibling = node->sibling;
found = true;
break;
}
prev_sibling_id = prev_sibling->sibling;
} while (prev_sibling_id);
assert(found);
}
node->sibling = node->parent = 0;
// ph_dump(heap, NULL, NULL);
// 3) remove it from the head of its own subtree
pheap_node_id_t new_sub_tree = ph_remove_any_head(heap, id, true);
assert(new_sub_tree != heap->root_id);
heap->root_id = ph_merge_nodes(heap, heap->root_id, new_sub_tree);
return true;
}
static uint ph_dump_node(pheap_t *heap, pheap_node_id_t id, void (*dump_key)(pheap_node_id_t, void *), void *user_data, uint indent) {
uint count = 0;
if (id) {
count++;
for (uint i = 0; i < indent * 2; i++) {
putchar(' ');
}
pheap_node_t *node = ph_get_node(heap, id);
printf("%d (c=%d s=%d p=%d) ", id, node->child, node->sibling, node->parent);
if (dump_key) dump_key(id, user_data);
printf("\n");
count += ph_dump_node(heap, node->child, dump_key, user_data, indent + 1);
count += ph_dump_node(heap, node->sibling, dump_key, user_data, indent);
}
return count;
}
void ph_dump(pheap_t *heap, void (*dump_key)(pheap_node_id_t, void *), void *user_data) {
uint count = ph_dump_node(heap, heap->root_id, dump_key, user_data, 0);
printf("node_count %d\n", count);
}

View file

@ -1,123 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdlib.h>
#include <string.h>
#include "pico/util/queue.h"
void queue_init_with_spinlock(queue_t *q, uint element_size, uint element_count, uint spinlock_num) {
lock_init(&q->core, spinlock_num);
q->data = (uint8_t *)calloc(element_count + 1, element_size);
q->element_count = (uint16_t)element_count;
q->element_size = (uint16_t)element_size;
q->wptr = 0;
q->rptr = 0;
}
void queue_free(queue_t *q) {
free(q->data);
}
static inline void *element_ptr(queue_t *q, uint index) {
assert(index <= q->element_count);
return q->data + index * q->element_size;
}
static inline uint16_t inc_index(queue_t *q, uint16_t index) {
if (++index > q->element_count) { // > because we have element_count + 1 elements
index = 0;
}
#if PICO_QUEUE_MAX_LEVEL
uint16_t level = queue_get_level_unsafe(q);
if (level > q->max_level) {
q->max_level = level;
}
#endif
return index;
}
static bool queue_add_internal(queue_t *q, const void *data, bool block) {
do {
uint32_t save = spin_lock_blocking(q->core.spin_lock);
if (queue_get_level_unsafe(q) != q->element_count) {
memcpy(element_ptr(q, q->wptr), data, q->element_size);
q->wptr = inc_index(q, q->wptr);
lock_internal_spin_unlock_with_notify(&q->core, save);
return true;
}
if (block) {
lock_internal_spin_unlock_with_wait(&q->core, save);
} else {
spin_unlock(q->core.spin_lock, save);
return false;
}
} while (true);
}
static bool queue_remove_internal(queue_t *q, void *data, bool block) {
do {
uint32_t save = spin_lock_blocking(q->core.spin_lock);
if (queue_get_level_unsafe(q) != 0) {
if (data) {
memcpy(data, element_ptr(q, q->rptr), q->element_size);
}
q->rptr = inc_index(q, q->rptr);
lock_internal_spin_unlock_with_notify(&q->core, save);
return true;
}
if (block) {
lock_internal_spin_unlock_with_wait(&q->core, save);
} else {
spin_unlock(q->core.spin_lock, save);
return false;
}
} while (true);
}
static bool queue_peek_internal(queue_t *q, void *data, bool block) {
do {
uint32_t save = spin_lock_blocking(q->core.spin_lock);
if (queue_get_level_unsafe(q) != 0) {
if (data) {
memcpy(data, element_ptr(q, q->rptr), q->element_size);
}
lock_internal_spin_unlock_with_notify(&q->core, save);
return true;
}
if (block) {
lock_internal_spin_unlock_with_wait(&q->core, save);
} else {
spin_unlock(q->core.spin_lock, save);
return false;
}
} while (true);
}
bool queue_try_add(queue_t *q, const void *data) {
return queue_add_internal(q, data, false);
}
bool queue_try_remove(queue_t *q, void *data) {
return queue_remove_internal(q, data, false);
}
bool queue_try_peek(queue_t *q, void *data) {
return queue_peek_internal(q, data, false);
}
void queue_add_blocking(queue_t *q, const void *data) {
queue_add_internal(q, data, true);
}
void queue_remove_blocking(queue_t *q, void *data) {
queue_remove_internal(q, data, true);
}
void queue_peek_blocking(queue_t *q, void *data) {
queue_peek_internal(q, data, true);
}

View file

@ -1,14 +0,0 @@
This is a basic set of replacement library implementations sufficient to get simple applications
running on your computer (Raspberry Pi OS, Linux, macOS or Windows using Cygwin or Windows Subsystem for Linux).
It is selected by `PICO_PLATFORM=host` in your CMake build
This can be extremely useful for testing and debugging higher level application code, or porting code which is not yet small enough
to run on the RP2040 or RP2350 device itself.
This base level host library provides a minimal environment to compile programs, but is likely sufficient for programs
that don't access hardware directly.
It is possible however to inject additional SDK library implementations/simulations to provide
more complete functionality. For an example of this see the [pico-host-sdl](https://github.com/raspberrypi/pico-host-sdl)
which uses the SDL2 library to add additional library support for pico_multicore, timers/alarms in pico-time and
pico-audio/pico-scanvideo from [pico-extras](https://github.com/raspberrypi/pico-extras)

View file

@ -1,3 +0,0 @@
int main() {
}

View file

@ -1,9 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "hardware/divider.h"
__thread uint64_t hw_divider_result_threadlocal;

View file

@ -1,331 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_DIVIDER_H
#define _HARDWARE_DIVIDER_H
#include "pico.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef uint64_t divmod_result_t;
static inline int __sign_of(int32_t v) {
return v > 0 ? 1 : (v < 0 ? -1 : 0);
}
/*! \brief Do an unsigned HW divide and wait for result
* \ingroup hardware_divider
*
* Divide \p a by \p b, wait for calculation to complete, return result as a fixed point 32p32 value.
*
* \param a The dividend
* \param b The divisor
* \return Results of divide as a 32p32 fixed point value.
*/
static inline divmod_result_t hw_divider_divmod_u32(uint32_t a, uint32_t b) {
if (!b) return (((uint64_t)a)<<32u) | (uint32_t)(-1); // todo check this
return (((uint64_t)(a%b))<<32u) | (a/b);
}
/*! \brief Do a signed HW divide and wait for result
* \ingroup hardware_divider
*
* Divide \p a by \p b, wait for calculation to complete, return result as a fixed point 32p32 value.
*
* \param a The dividend
* \param b The divisor
* \return Results of divide as a 32p32 fixed point value.
*/
static inline divmod_result_t hw_divider_divmod_s32(int32_t a, int32_t b) {
if (!b) return (((uint64_t)a)<<32u) | (uint32_t)(-__sign_of(a));
return (((uint64_t)(a%b))<<32u) | (uint32_t)(a/b);
}
extern __thread divmod_result_t hw_divider_result_threadlocal;
/*! \brief Start a signed asynchronous divide
* \ingroup hardware_divider
*
* Start a divide of the specified signed parameters. You should wait for 8 cycles (__div_pause()) or wait for the ready bit to be set
* (hw_divider_wait_ready()) prior to reading the results.
*
* \param a The dividend
* \param b The divisor
*/
static inline void hw_divider_divmod_s32_start(int32_t a, int32_t b) {
hw_divider_result_threadlocal = hw_divider_divmod_s32(a, b);
}
/*! \brief Start an unsigned asynchronous divide
* \ingroup hardware_divider
*
* Start a divide of the specified unsigned parameters. You should wait for 8 cycles (__div_pause()) or wait for the ready bit to be set
* (hw_divider_wait_ready()) prior to reading the results.
*
* \param a The dividend
* \param b The divisor
*/
static inline void hw_divider_divmod_u32_start(uint32_t a, uint32_t b) {
hw_divider_result_threadlocal = hw_divider_divmod_u32(a, b);
}
/*! \brief Return result of last asynchronous HW divide
* \ingroup hardware_divider
*
* This function waits for the result to be ready by calling hw_divider_wait_ready().
*
* \return Current result. Most significant 32 bits are the remainder, lower 32 bits are the quotient.
*/
static inline divmod_result_t hw_divider_result_wait(void) {
return hw_divider_result_threadlocal;
}
/*! \brief Return result of HW divide, nowait
* \ingroup hardware_divider
*
* \note This is UNSAFE in that the calculation may not have been completed.
*
* \return Current result. Most significant 32 bits are the remainder, lower 32 bits are the quotient.
*/
static inline divmod_result_t hw_divider_result_nowait(void) {
return hw_divider_result_threadlocal;
}
/*! \brief Wait for a divide to complete
* \ingroup hardware_divider
*
* Wait for a divide to complete
*/
static inline void hw_divider_wait_ready(void) {}
/*! \brief Efficient extraction of unsigned quotient from 32p32 fixed point
* \ingroup hardware_divider
*
* \param r 32p32 fixed point value.
* \return Unsigned quotient
*/
inline static uint32_t to_quotient_u32(divmod_result_t r) {
return (uint32_t) r;
}
/*! \brief Efficient extraction of signed quotient from 32p32 fixed point
* \ingroup hardware_divider
*
* \param r 32p32 fixed point value.
* \return Unsigned quotient
*/
inline static int32_t to_quotient_s32(divmod_result_t r) {
return (int32_t)(uint32_t)r;
}
/*! \brief Efficient extraction of unsigned remainder from 32p32 fixed point
* \ingroup hardware_divider
*
* \param r 32p32 fixed point value.
* \return Unsigned remainder
*
* \note On Arm this is just a 32 bit register move or a nop
*/
inline static uint32_t to_remainder_u32(divmod_result_t r) {
return (uint32_t)(r >> 32u);
}
/*! \brief Efficient extraction of signed remainder from 32p32 fixed point
* \ingroup hardware_divider
*
* \param r 32p32 fixed point value.
* \return Signed remainder
*
* \note On arm this is just a 32 bit register move or a nop
*/
inline static int32_t to_remainder_s32(divmod_result_t r) {
return (int32_t)(r >> 32u);
}
static inline void hw_divider_pause(void) {}
/*! \brief Do an unsigned HW divide, wait for result, return quotient
* \ingroup hardware_divider
*
* Divide \p a by \p b, wait for calculation to complete, return quotient.
*
* \param a The dividend
* \param b The divisor
* \return Quotient results of the divide
*/
static inline uint32_t hw_divider_u32_quotient(uint32_t a, uint32_t b) {
return b ? (a / b) : (uint32_t)(-1);
}
/*! \brief Do an unsigned HW divide, wait for result, return remainder
* \ingroup hardware_divider
*
* Divide \p a by \p b, wait for calculation to complete, return remainder.
*
* \param a The dividend
* \param b The divisor
* \return Remainder results of the divide
*/
static inline uint32_t hw_divider_u32_remainder(uint32_t a, uint32_t b) {
return b ? (a % b) : a;
}
/*! \brief Do a signed HW divide, wait for result, return quotient
* \ingroup hardware_divider
*
* Divide \p a by \p b, wait for calculation to complete, return quotient.
*
* \param a The dividend
* \param b The divisor
* \return Quotient results of the divide
*/
static inline int32_t hw_divider_quotient_s32(int32_t a, int32_t b) {
return to_quotient_s32(hw_divider_divmod_s32(a, b));
}
/*! \brief Do a signed HW divide, wait for result, return remainder
* \ingroup hardware_divider
*
* Divide \p a by \p b, wait for calculation to complete, return remainder.
*
* \param a The dividend
* \param b The divisor
* \return Remainder results of the divide
*/
static inline int32_t hw_divider_remainder_s32(int32_t a, int32_t b) {
return b ? (a % b) : a;
}
/*! \brief Return result of last asynchronous HW divide, unsigned quotient only
* \ingroup hardware_divider
*
* This function waits for the result to be ready by calling hw_divider_wait_ready().
*
* \return Current unsigned quotient result.
*/
static inline uint32_t hw_divider_u32_quotient_wait(void) {
return to_quotient_u32(hw_divider_result_wait());
}
/*! \brief Return result of last asynchronous HW divide, signed quotient only
* \ingroup hardware_divider
*
* This function waits for the result to be ready by calling hw_divider_wait_ready().
*
* \return Current signed quotient result.
*/
static inline int32_t hw_divider_s32_quotient_wait(void) {
return to_remainder_u32(hw_divider_result_wait());
}
/*! \brief Return result of last asynchronous HW divide, unsigned remainder only
* \ingroup hardware_divider
*
* This function waits for the result to be ready by calling hw_divider_wait_ready().
*
* \return Current unsigned remainder result.
*/
static inline uint32_t hw_divider_u32_remainder_wait(void) {
return to_quotient_s32(hw_divider_result_wait());
}
/*! \brief Return result of last asynchronous HW divide, signed remainder only
* \ingroup hardware_divider
*
* This function waits for the result to be ready by calling hw_divider_wait_ready().
*
* \return Current remainder results.
*/
static inline int32_t hw_divider_s32_remainder_wait(void) {
return to_remainder_s32(hw_divider_result_wait());
}
/*! \brief Do a hardware unsigned HW divide, wait for result, return quotient
* \ingroup hardware_divider
*
* Divide \p a by \p b, wait for calculation to complete, return quotient.
*
* \param a The dividend
* \param b The divisor
* \return Quotient result of the divide
*/
static inline uint32_t hw_divider_u32_quotient_inlined(uint32_t a, uint32_t b) {
return hw_divider_u32_quotient(a,b);
}
/*! \brief Do a hardware unsigned HW divide, wait for result, return remainder
* \ingroup hardware_divider
*
* Divide \p a by \p b, wait for calculation to complete, return remainder.
*
* \param a The dividend
* \param b The divisor
* \return Remainder result of the divide
*/
static inline uint32_t hw_divider_u32_remainder_inlined(uint32_t a, uint32_t b) {
return hw_divider_u32_remainder(a,b);
}
/*! \brief Do a hardware signed HW divide, wait for result, return quotient
* \ingroup hardware_divider
*
* Divide \p a by \p b, wait for calculation to complete, return quotient.
*
* \param a The dividend
* \param b The divisor
* \return Quotient result of the divide
*/
static inline int32_t hw_divider_s32_quotient_inlined(int32_t a, int32_t b) {
return hw_divider_quotient_s32(a,b);
}
/*! \brief Do a hardware signed HW divide, wait for result, return remainder
* \ingroup hardware_divider
*
* Divide \p a by \p b, wait for calculation to complete, return remainder.
*
* \param a The dividend
* \param b The divisor
* \return Remainder result of the divide
*/
static inline int32_t hw_divider_s32_remainder_inlined(int32_t a, int32_t b) {
return hw_divider_remainder_s32(a,b);
}
typedef uint64_t hw_divider_state_t;
/*! \brief Save the calling cores hardware divider state
* \ingroup hardware_divider
*
* Copy the current core's hardware divider state into the provided structure. This method
* waits for the divider results to be stable, then copies them to memory.
* They can be restored via hw_divider_restore_state()
*
* \param dest the location to store the divider state
*/
static inline void hw_divider_save_state(hw_divider_state_t *dest) {
*dest = hw_divider_result_threadlocal;
}
/*! \brief Load a saved hardware divider state into the current core's hardware divider
* \ingroup hardware_divider
*
* Copy the passed hardware divider state into the hardware divider.
*
* \param src the location to load the divider state from
*/
static inline void hw_divider_restore_state(hw_divider_state_t *src) {
hw_divider_result_threadlocal = *src;
}
#ifdef __cplusplus
}
#endif
#endif // _HARDWARE_DIVIDER_H

View file

@ -1,147 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "hardware/gpio.h"
// todo weak or replace? probably weak
void gpio_set_function(uint gpio, enum gpio_function fn) {
}
void gpio_pull_up(uint gpio) {
}
void gpio_pull_down(uint gpio) {
}
void gpio_disable_pulls(uint gpio) {
}
void gpio_set_pulls(uint gpio, bool up, bool down) {
}
void gpio_set_irqover(uint gpio, uint value) {
}
void gpio_set_outover(uint gpio, uint value) {
}
void gpio_set_inover(uint gpio, uint value) {
}
void gpio_set_oeover(uint gpio, uint value) {
}
void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled){
}
bool gpio_is_input_hysteresis_enabled(uint gpio){
return true;
}
void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew){
}
enum gpio_slew_rate gpio_get_slew_rate(uint gpio){
return GPIO_SLEW_RATE_FAST;
}
void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive){
}
enum gpio_drive_strength gpio_get_drive_strength(uint gpio){
return GPIO_DRIVE_STRENGTH_4MA;
}
void gpio_set_irq_enabled(uint gpio, uint32_t events, bool enable) {
}
void gpio_acknowledge_irq(uint gpio, uint32_t events) {
}
void gpio_init(uint gpio) {
}
PICO_WEAK_FUNCTION_DEF(gpio_get)
bool PICO_WEAK_FUNCTION_IMPL_NAME(gpio_get)(uint gpio) {
return 0;
}
uint32_t gpio_get_all() {
return 0;
}
void gpio_set_mask(uint32_t mask) {
}
void gpio_clr_mask(uint32_t mask) {
}
void gpio_xor_mask(uint32_t mask) {
}
void gpio_put_masked(uint32_t mask, uint32_t value) {
}
void gpio_put_all(uint32_t value) {
}
void gpio_put(uint gpio, int value) {
}
void gpio_set_dir_out_masked(uint32_t mask) {
}
void gpio_set_dir_in_masked(uint32_t mask) {
}
void gpio_set_dir_masked(uint32_t mask, uint32_t value) {
}
void gpio_set_dir_all_bits(uint32_t value) {
}
void gpio_set_dir(uint gpio, bool out) {
}
void gpio_debug_pins_init() {
}
void gpio_set_input_enabled(uint gpio, bool enable) {
}
void gpio_init_mask(uint gpio_mask) {
}

View file

@ -1,172 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_GPIO_H
#define _HARDWARE_GPIO_H
#ifdef __cplusplus
extern "C" {
#endif
#include "pico.h"
enum gpio_function {
GPIO_FUNC_XIP = 0,
GPIO_FUNC_SPI = 1,
GPIO_FUNC_UART = 2,
GPIO_FUNC_I2C = 3,
GPIO_FUNC_PWM = 4,
GPIO_FUNC_SIO = 5,
GPIO_FUNC_PIO0 = 6,
GPIO_FUNC_PIO1 = 7,
GPIO_FUNC_GPCK = 8,
GPIO_FUNC_USB = 9,
GPIO_FUNC_NULL = 0xf,
};
enum gpio_slew_rate {
GPIO_SLEW_RATE_SLOW = 0, ///< Slew rate limiting enabled
GPIO_SLEW_RATE_FAST = 1 ///< Slew rate limiting disabled
};
enum gpio_drive_strength {
GPIO_DRIVE_STRENGTH_2MA = 0, ///< 2 mA nominal drive strength
GPIO_DRIVE_STRENGTH_4MA = 1, ///< 4 mA nominal drive strength
GPIO_DRIVE_STRENGTH_8MA = 2, ///< 8 mA nominal drive strength
GPIO_DRIVE_STRENGTH_12MA = 3 ///< 12 mA nominal drive strength
};
#define GPIO_OUT 1
#define GPIO_IN 0
// ----------------------------------------------------------------------------
// Pad Controls + IO Muxing
// ----------------------------------------------------------------------------
// Declarations for gpio.c
void gpio_set_function(uint gpio, enum gpio_function fn);
enum gpio_function gpio_get_function(uint gpio);
void gpio_pull_up(uint gpio);
void gpio_pull_down(uint gpio);
void gpio_disable_pulls(uint gpio);
void gpio_set_pulls(uint gpio, bool up, bool down);
void gpio_set_irqover(uint gpio, uint value);
void gpio_set_outover(uint gpio, uint value);
void gpio_set_inover(uint gpio, uint value);
void gpio_set_oeover(uint gpio, uint value);
void gpio_set_input_enabled(uint gpio, bool enable);
void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled);
bool gpio_is_input_hysteresis_enabled(uint gpio);
void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew);
enum gpio_slew_rate gpio_get_slew_rate(uint gpio);
void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive);
enum gpio_drive_strength gpio_get_drive_strength(uint gpio);
// Configure a GPIO for direct input/output from software
void gpio_init(uint gpio);
void gpio_init_mask(uint gpio_mask);
// ----------------------------------------------------------------------------
// Input
// ----------------------------------------------------------------------------
// Get the value of a single GPIO
bool gpio_get(uint gpio);
// Get raw value of all
uint32_t gpio_get_all();
// ----------------------------------------------------------------------------
// Output
// ----------------------------------------------------------------------------
// Drive high every GPIO appearing in mask
void gpio_set_mask(uint32_t mask);
void gpio_clr_mask(uint32_t mask);
// Toggle every GPIO appearing in mask
void gpio_xor_mask(uint32_t mask);
// For each 1 bit in "mask", drive that pin to the value given by
// corresponding bit in "value", leaving other pins unchanged.
// Since this uses the TOGL alias, it is concurrency-safe with e.g. an IRQ
// bashing different pins from the same core.
void gpio_put_masked(uint32_t mask, uint32_t value);
// Drive all pins simultaneously
void gpio_put_all(uint32_t value);
// Drive a single GPIO high/low
void gpio_put(uint gpio, int value);
// ----------------------------------------------------------------------------
// Direction
// ----------------------------------------------------------------------------
// Switch all GPIOs in "mask" to output
void gpio_set_dir_out_masked(uint32_t mask);
// Switch all GPIOs in "mask" to input
void gpio_set_dir_in_masked(uint32_t mask);
// For each 1 bit in "mask", switch that pin to the direction given by
// corresponding bit in "value", leaving other pins unchanged.
// E.g. gpio_set_dir_masked(0x3, 0x2); -> set pin 0 to input, pin 1 to output,
// simultaneously.
void gpio_set_dir_masked(uint32_t mask, uint32_t value);
// Set direction of all pins simultaneously.
// For each bit in value,
// 1 = out
// 0 = in
void gpio_set_dir_all_bits(uint32_t value);
// Set a single GPIO to input/output.
// true = out
// 0 = in
void gpio_set_dir(uint gpio, bool out);
// debugging
#ifndef PICO_DEBUG_PIN_BASE
#define PICO_DEBUG_PIN_BASE 19u
#endif
// note these two macros may only be used once per compilation unit
#define CU_REGISTER_DEBUG_PINS(p, ...)
#define CU_SELECT_DEBUG_PINS(x)
#define DEBUG_PINS_ENABLED(p) false
#define DEBUG_PINS_SET(p, v) ((void)0)
#define DEBUG_PINS_CLR(p, v) ((void)0)
#define DEBUG_PINS_XOR(p, v) ((void)0)
void gpio_debug_pins_init();
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,381 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_IRQ_H
#define _HARDWARE_IRQ_H
// These two config items are also used by assembler, so keeping separate
// PICO_CONFIG: PICO_MAX_SHARED_IRQ_HANDLERS, Maximum number of shared IRQ handlers, default=4, advanced=true, group=hardware_irq
#ifndef PICO_MAX_SHARED_IRQ_HANDLERS
#define PICO_MAX_SHARED_IRQ_HANDLERS 4
#endif
// PICO_CONFIG: PICO_DISABLE_SHARED_IRQ_HANDLERS, Disable shared IRQ handlers, type=bool, default=0, group=hardware_irq
#ifndef PICO_DISABLE_SHARED_IRQ_HANDLERS
#define PICO_DISABLE_SHARED_IRQ_HANDLERS 0
#endif
// PICO_CONFIG: PICO_VTABLE_PER_CORE, User is using separate vector tables per core, type=bool, default=0, group=hardware_irq
#ifndef PICO_VTABLE_PER_CORE
#define PICO_VTABLE_PER_CORE 0
#endif
#include "pico.h"
#include "hardware/regs/intctrl.h"
/** \file irq.h
* \defgroup hardware_irq hardware_irq
*
* \brief Hardware interrupt handling
*
* The RP2040 uses the standard ARM nested vectored interrupt controller (NVIC).
*
* Interrupts are identified by a number from 0 to 31.
*
* On the RP2040, only the lower 26 IRQ signals are connected on the NVIC; IRQs 26 to 31 are tied to zero (never firing).
*
* There is one NVIC per core, and each core's NVIC has the same hardware interrupt lines routed to it, with the exception of the IO interrupts
* where there is one IO interrupt per bank, per core. These are completely independent, so, for example, processor 0 can be
* interrupted by GPIO 0 in bank 0, and processor 1 by GPIO 1 in the same bank.
*
* \note That all IRQ APIs affect the executing core only (i.e. the core calling the function).
*
* \note You should not enable the same (shared) IRQ number on both cores, as this will lead to race conditions
* or starvation of one of the cores. Additionally, don't forget that disabling interrupts on one core does not disable interrupts
* on the other core.
*
* There are three different ways to set handlers for an IRQ:
* - Calling irq_add_shared_handler() at runtime to add a handler for a multiplexed interrupt (e.g. GPIO bank) on the current core. Each handler, should check and clear the relevant hardware interrupt source
* - Calling irq_set_exclusive_handler() at runtime to install a single handler for the interrupt on the current core
* - Defining the interrupt handler explicitly in your application (e.g. by defining void `isr_dma_0` will make that function the handler for the DMA_IRQ_0 on core 0, and
* you will not be able to change it using the above APIs at runtime). Using this method can cause link conflicts at runtime, and offers no runtime performance benefit (i.e, it should not generally be used).
*
* \note If an IRQ is enabled and fires with no handler installed, a breakpoint will be hit and the IRQ number will
* be in register r0.
*
* \section interrupt_nums Interrupt Numbers
*
* Interrupts are numbered as follows, a set of defines is available (intctrl.h) with these names to avoid using the numbers directly.
*
* IRQ | Interrupt Source
* ----|-----------------
* 0 | TIMER_IRQ_0
* 1 | TIMER_IRQ_1
* 2 | TIMER_IRQ_2
* 3 | TIMER_IRQ_3
* 4 | PWM_IRQ_WRAP
* 5 | USBCTRL_IRQ
* 6 | XIP_IRQ
* 7 | PIO0_IRQ_0
* 8 | PIO0_IRQ_1
* 9 | PIO1_IRQ_0
* 10 | PIO1_IRQ_1
* 11 | DMA_IRQ_0
* 12 | DMA_IRQ_1
* 13 | IO_IRQ_BANK0
* 14 | IO_IRQ_QSPI
* 15 | SIO_IRQ_PROC0
* 16 | SIO_IRQ_PROC1
* 17 | CLOCKS_IRQ
* 18 | SPI0_IRQ
* 19 | SPI1_IRQ
* 20 | UART0_IRQ
* 21 | UART1_IRQ
* 22 | ADC0_IRQ_FIFO
* 23 | I2C0_IRQ
* 24 | I2C1_IRQ
* 25 | RTC_IRQ
*
*/
// PICO_CONFIG: PICO_DEFAULT_IRQ_PRIORITY, Define the default IRQ priority, default=0x80, group=hardware_irq
#ifndef PICO_DEFAULT_IRQ_PRIORITY
#define PICO_DEFAULT_IRQ_PRIORITY 0x80
#endif
#define PICO_LOWEST_IRQ_PRIORITY 0xff
#define PICO_HIGHEST_IRQ_PRIORITY 0x00
// PICO_CONFIG: PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY, Set default shared IRQ order priority, default=0x80, group=hardware_irq
#ifndef PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY
#define PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY 0x80
#endif
#define PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY 0xff
#define PICO_SHARED_IRQ_HANDLER_LOWEST_ORDER_PRIORITY 0x00
// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_IRQ, Enable/disable assertions in the hardware_irq module, type=bool, default=0, group=hardware_irq
#ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_IRQ
#ifdef PARAM_ASSERTIONS_ENABLED_IRQ // backwards compatibility with SDK < 2.0.0
#define PARAM_ASSERTIONS_ENABLED_HARDWARE_IRQ PARAM_ASSERTIONS_ENABLED_IRQ
#else
#define PARAM_ASSERTIONS_ENABLED_HARDWARE_IRQ 0
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*! \brief Interrupt handler function type
* \ingroup hardware_irq
*
* All interrupts handlers should be of this type, and follow normal ARM EABI register saving conventions
*/
typedef void (*irq_handler_t)(void);
static inline void check_irq_param(__unused uint num) {
invalid_params_if(HARDWARE_IRQ, num >= NUM_IRQS);
}
/*! \brief Set specified interrupt's priority
* \ingroup hardware_irq
*
* \param num Interrupt number \ref interrupt_nums
* \param hardware_priority Priority to set.
* Numerically-lower values indicate a higher priority. Hardware priorities
* range from 0 (highest priority) to 255 (lowest priority) though only the
* top 2 bits are significant on ARM Cortex-M0+. To make it easier to specify
* higher or lower priorities than the default, all IRQ priorities are
* initialized to PICO_DEFAULT_IRQ_PRIORITY by the SDK runtime at startup.
* PICO_DEFAULT_IRQ_PRIORITY defaults to 0x80
*/
void irq_set_priority(uint num, uint8_t hardware_priority);
/*! \brief Get specified interrupt's priority
* \ingroup hardware_irq
*
* Numerically-lower values indicate a higher priority. Hardware priorities
* range from 0 (highest priority) to 255 (lowest priority) though only the
* top 2 bits are significant on ARM Cortex-M0+. To make it easier to specify
* higher or lower priorities than the default, all IRQ priorities are
* initialized to PICO_DEFAULT_IRQ_PRIORITY by the SDK runtime at startup.
* PICO_DEFAULT_IRQ_PRIORITY defaults to 0x80
*
* \param num Interrupt number \ref interrupt_nums
* \return the IRQ priority
*/
uint irq_get_priority(uint num);
/*! \brief Enable or disable a specific interrupt on the executing core
* \ingroup hardware_irq
*
* \param num Interrupt number \ref interrupt_nums
* \param enabled true to enable the interrupt, false to disable
*/
void irq_set_enabled(uint num, bool enabled);
/*! \brief Determine if a specific interrupt is enabled on the executing core
* \ingroup hardware_irq
*
* \param num Interrupt number \ref interrupt_nums
* \return true if the interrupt is enabled
*/
bool irq_is_enabled(uint num);
/*! \brief Enable/disable multiple interrupts on the executing core
* \ingroup hardware_irq
*
* \param mask 32-bit mask with one bits set for the interrupts to enable/disable \ref interrupt_nums
* \param enabled true to enable the interrupts, false to disable them.
*/
void irq_set_mask_enabled(uint32_t mask, bool enabled);
/*! \brief Enable/disable multiple interrupts on the executing core
* \ingroup hardware_irq
*
* \param n the index of the mask to update. n == 0 means 0->31, n == 1 mean 32->63 etc.
* \param mask 32-bit mask with one bits set for the interrupts to enable/disable \ref interrupt_nums
* \param enabled true to enable the interrupts, false to disable them.
*/
void irq_set_mask_n_enabled(uint n, uint32_t mask, bool enabled);
/*! \brief Set an exclusive interrupt handler for an interrupt on the executing core.
* \ingroup hardware_irq
*
* Use this method to set a handler for single IRQ source interrupts, or when
* your code, use case or performance requirements dictate that there should
* no other handlers for the interrupt.
*
* This method will assert if there is already any sort of interrupt handler installed
* for the specified irq number.
*
* \param num Interrupt number \ref interrupt_nums
* \param handler The handler to set. See \ref irq_handler_t
* \see irq_add_shared_handler()
*/
void irq_set_exclusive_handler(uint num, irq_handler_t handler);
/*! \brief Get the exclusive interrupt handler for an interrupt on the executing core.
* \ingroup hardware_irq
*
* This method will return an exclusive IRQ handler set on this core
* by irq_set_exclusive_handler if there is one.
*
* \param num Interrupt number \ref interrupt_nums
* \see irq_set_exclusive_handler()
* \return handler The handler if an exclusive handler is set for the IRQ,
* NULL if no handler is set or shared/shareable handlers are installed
*/
irq_handler_t irq_get_exclusive_handler(uint num);
/*! \brief Add a shared interrupt handler for an interrupt on the executing core
* \ingroup hardware_irq
*
* Use this method to add a handler on an irq number shared between multiple distinct hardware sources (e.g. GPIO, DMA or PIO IRQs).
* Handlers added by this method will all be called in sequence from highest order_priority to lowest. The
* irq_set_exclusive_handler() method should be used instead if you know there will or should only ever be one handler for the interrupt.
*
* This method will assert if there is an exclusive interrupt handler set for this irq number on this core, or if
* the (total across all IRQs on both cores) maximum (configurable via PICO_MAX_SHARED_IRQ_HANDLERS) number of shared handlers
* would be exceeded.
*
* \param num Interrupt number \ref interrupt_nums
* \param handler The handler to set. See \ref irq_handler_t
* \param order_priority The order priority controls the order that handlers for the same IRQ number on the core are called.
* The shared irq handlers for an interrupt are all called when an IRQ fires, however the order of the calls is based
* on the order_priority (higher priorities are called first, identical priorities are called in undefined order). A good
* rule of thumb is to use PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY if you don't much care, as it is in the middle of
* the priority range by default.
*
* \note The order_priority uses \em higher values for higher priorities which is the \em opposite of the CPU interrupt priorities passed
* to irq_set_priority() which use lower values for higher priorities.
*
* \see irq_set_exclusive_handler()
*/
void irq_add_shared_handler(uint num, irq_handler_t handler, uint8_t order_priority);
/*! \brief Remove a specific interrupt handler for the given irq number on the executing core
* \ingroup hardware_irq
*
* This method may be used to remove an irq set via either irq_set_exclusive_handler() or
* irq_add_shared_handler(), and will assert if the handler is not currently installed for the given
* IRQ number
*
* \note This method may *only* be called from user (non IRQ code) or from within the handler
* itself (i.e. an IRQ handler may remove itself as part of handling the IRQ). Attempts to call
* from another IRQ will cause an assertion.
*
* \param num Interrupt number \ref interrupt_nums
* \param handler The handler to removed.
* \see irq_set_exclusive_handler()
* \see irq_add_shared_handler()
*/
void irq_remove_handler(uint num, irq_handler_t handler);
/*! \brief Determine if the current handler for the given number is shared
* \ingroup hardware_irq
*
* \param num Interrupt number \ref interrupt_nums
* \return true if the specified IRQ has a shared handler
*/
bool irq_has_shared_handler(uint num);
/*! \brief Get the current IRQ handler for the specified IRQ from the currently installed hardware vector table (VTOR)
* of the execution core
* \ingroup hardware_irq
*
* \param num Interrupt number \ref interrupt_nums
* \return the address stored in the VTABLE for the given irq number
*/
irq_handler_t irq_get_vtable_handler(uint num);
/*! \brief Clear a specific interrupt on the executing core
* \ingroup hardware_irq
*
* This method is only useful for "software" IRQs that are not connected to hardware (i.e. IRQs 26-31)
* as the the NVIC always reflects the current state of the IRQ state of the hardware for hardware IRQs, and clearing
* of the IRQ state of the hardware is performed via the hardware's registers instead.
*
* \param int_num Interrupt number \ref interrupt_nums
*/
void irq_clear(uint int_num);
/*! \brief Force an interrupt to be pending on the executing core
* \ingroup hardware_irq
*
* This should generally not be used for IRQs connected to hardware.
*
* \param num Interrupt number \ref interrupt_nums
*/
void irq_set_pending(uint num);
/*! \brief Perform IRQ priority initialization for the current core
*
* \note This is an internal method and user should generally not call it.
*/
void irq_init_priorities(void);
/*! \brief Claim ownership of a user IRQ on the calling core
* \ingroup hardware_irq
*
* User IRQs are numbered 26-31 and are not connected to any hardware, but can be triggered by \ref irq_set_pending.
*
* \note User IRQs are a core local feature; they cannot be used to communicate between cores. Therefore all functions
* dealing with Uer IRQs affect only the calling core
*
* This method explicitly claims ownership of a user IRQ, so other code can know it is being used.
*
* \param irq_num the user IRQ to claim
*/
void user_irq_claim(uint irq_num);
/*! \brief Mark a user IRQ as no longer used on the calling core
* \ingroup hardware_irq
*
* User IRQs are numbered 26-31 and are not connected to any hardware, but can be triggered by \ref irq_set_pending.
*
* \note User IRQs are a core local feature; they cannot be used to communicate between cores. Therefore all functions
* dealing with Uer IRQs affect only the calling core
*
* This method explicitly releases ownership of a user IRQ, so other code can know it is free to use.
*
* \note it is customary to have disabled the irq and removed the handler prior to calling this method.
*
* \param irq_num the irq irq_num to unclaim
*/
void user_irq_unclaim(uint irq_num);
/*! \brief Claim ownership of a free user IRQ on the calling core
* \ingroup hardware_irq
*
* User IRQs are numbered 26-31 and are not connected to any hardware, but can be triggered by \ref irq_set_pending.
*
* \note User IRQs are a core local feature; they cannot be used to communicate between cores. Therefore all functions
* dealing with Uer IRQs affect only the calling core
*
* This method explicitly claims ownership of an unused user IRQ if there is one, so other code can know it is being used.
*
* \param required if true the function will panic if none are available
* \return the user IRQ number or -1 if required was false, and none were free
*/
int user_irq_claim_unused(bool required);
/*
*! \brief Check if a user IRQ is in use on the calling core
* \ingroup hardware_irq
*
* User IRQs are numbered 26-31 and are not connected to any hardware, but can be triggered by \ref irq_set_pending.
*
* \note User IRQs are a core local feature; they cannot be used to communicate between cores. Therefore all functions
* dealing with Uer IRQs affect only the calling core
*
* \param irq_num the irq irq_num
* \return true if the irq_num is claimed, false otherwise
* \sa user_irq_claim
* \sa user_irq_unclaim
* \sa user_irq_claim_unused
*/
bool user_irq_is_claimed(uint irq_num);
void __unhandled_user_irq(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,125 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "hardware/irq.h"
#include "hardware/claim.h"
// totally non-functional IRQ
#if PICO_VTABLE_PER_CORE
static uint8_t user_irq_claimed[NUM_CORES];
static inline uint8_t *user_irq_claimed_ptr(void) {
return &user_irq_claimed[get_core_num()];
}
#else
static uint8_t user_irq_claimed;
static inline uint8_t *user_irq_claimed_ptr(void) {
return &user_irq_claimed;
}
#endif
PICO_WEAK_FUNCTION_DEF(irq_set_enabled)
void PICO_WEAK_FUNCTION_IMPL_NAME(irq_set_enabled)(uint num, bool enabled) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(irq_is_enabled)
bool PICO_WEAK_FUNCTION_IMPL_NAME(irq_is_enabled)(uint num) {
return false;
}
PICO_WEAK_FUNCTION_DEF(irq_set_mask_enabled)
void PICO_WEAK_FUNCTION_IMPL_NAME(irq_set_mask_enabled)(uint32_t mask, bool enabled) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(irq_set_mask_n_enabled)
void PICO_WEAK_FUNCTION_IMPL_NAME(irq_set_mask_n_enabled)(uint n, uint32_t mask, bool enabled) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(irq_set_pending)
void PICO_WEAK_FUNCTION_IMPL_NAME(irq_set_pending)(uint num) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(irq_has_shared_handler)
bool PICO_WEAK_FUNCTION_IMPL_NAME(irq_has_shared_handler)(uint irq_num) {
return false;
}
PICO_WEAK_FUNCTION_DEF(irq_get_vtable_handler)
irq_handler_t PICO_WEAK_FUNCTION_IMPL_NAME(irq_get_vtable_handler)(uint num) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(irq_set_exclusive_handler)
void PICO_WEAK_FUNCTION_IMPL_NAME(irq_set_exclusive_handler)(uint num, irq_handler_t handler) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(irq_get_exclusive_handler)
irq_handler_t PICO_WEAK_FUNCTION_IMPL_NAME(irq_get_exclusive_handler)(uint num) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(irq_add_shared_handler)
void PICO_WEAK_FUNCTION_IMPL_NAME(irq_add_shared_handler)(uint num, irq_handler_t handler, uint8_t order_priority) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(irq_remove_handler)
void PICO_WEAK_FUNCTION_IMPL_NAME(irq_remove_handler)(uint num, irq_handler_t handler) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(irq_set_priority)
void PICO_WEAK_FUNCTION_IMPL_NAME(irq_set_priority)(uint num, uint8_t hardware_priority) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(irq_get_priority)
uint PICO_WEAK_FUNCTION_IMPL_NAME(irq_get_priority)(uint num) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(irq_clear)
void PICO_WEAK_FUNCTION_IMPL_NAME(irq_clear)(uint int_num) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(irq_init_priorities)
void PICO_WEAK_FUNCTION_IMPL_NAME(irq_init_priorities)() {
}
static uint get_user_irq_claim_index(uint irq_num) {
invalid_params_if(HARDWARE_IRQ, irq_num < FIRST_USER_IRQ || irq_num >= NUM_IRQS);
// we count backwards from the last, to match the existing hard coded uses of user IRQs in the SDK which were previously using 31
static_assert(NUM_IRQS - FIRST_USER_IRQ <= 8, ""); // we only use a single byte's worth of claim bits today.
return NUM_IRQS - irq_num - 1u;
}
PICO_WEAK_FUNCTION_DEF(user_irq_claim)
void PICO_WEAK_FUNCTION_IMPL_NAME(user_irq_claim)(uint irq_num) {
hw_claim_or_assert(user_irq_claimed_ptr(), get_user_irq_claim_index(irq_num), "User IRQ is already claimed");
}
PICO_WEAK_FUNCTION_DEF(user_irq_unclaim)
void PICO_WEAK_FUNCTION_IMPL_NAME(user_irq_unclaim)(uint irq_num) {
hw_claim_clear(user_irq_claimed_ptr(), get_user_irq_claim_index(irq_num));
}
PICO_WEAK_FUNCTION_DEF(user_irq_claim_unused)
int PICO_WEAK_FUNCTION_IMPL_NAME(user_irq_claim_unused)(bool required) {
int bit = hw_claim_unused_from_range(user_irq_claimed_ptr(), required, 0, NUM_USER_IRQS - 1, "No user IRQs are available");
if (bit >= 0) bit = (int)NUM_IRQS - bit - 1;
return bit;
}
PICO_WEAK_FUNCTION_DEF(user_irq_is_claimed)
bool PICO_WEAK_FUNCTION_IMPL_NAME(user_irq_is_claimed)(uint irq_num) {
return hw_is_claimed(user_irq_claimed_ptr(), get_user_irq_claim_index(irq_num));
}

View file

@ -1,154 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_SYNC_H
#define _HARDWARE_SYNC_H
#include "pico.h"
#ifndef __cplusplus
#if (__STDC_VERSION__ >= 201112L)
#include <stdatomic.h>
#else
enum {
memory_order_acquire, memory_order_release
};
static inline void atomic_thread_fence(uint x) {}
#endif
#else
#include <atomic>
#endif
// PICO_CONFIG: PICO_SPINLOCK_ID_ATOMIC, Spinlock ID for atomics, min=0, max=31, default=8, group=hardware_sync
#ifndef PICO_SPINLOCK_ID_ATOMIC
#define PICO_SPINLOCK_ID_ATOMIC 8
#endif
// PICO_CONFIG: PICO_SPINLOCK_ID_IRQ, Spinlock ID for IRQ protection, min=0, max=31, default=9, group=hardware_sync
#ifndef PICO_SPINLOCK_ID_IRQ
#define PICO_SPINLOCK_ID_IRQ 9
#endif
// PICO_CONFIG: PICO_SPINLOCK_ID_TIMER, Spinlock ID for Timer protection, min=0, max=31, default=10, group=hardware_sync
#ifndef PICO_SPINLOCK_ID_TIMER
#define PICO_SPINLOCK_ID_TIMER 10
#endif
// PICO_CONFIG: PICO_SPINLOCK_ID_HARDWARE_CLAIM, Spinlock ID for Hardware claim protection, min=0, max=31, default=11, group=hardware_sync
#ifndef PICO_SPINLOCK_ID_HARDWARE_CLAIM
#define PICO_SPINLOCK_ID_HARDWARE_CLAIM 11
#endif
// PICO_CONFIG: PICO_SPINLOCK_ID_RAND, Spinlock ID for Random Number Generator, min=0, max=31, default=12, group=hardware_sync
#ifndef PICO_SPINLOCK_ID_RAND
#define PICO_SPINLOCK_ID_RAND 12
#endif
// PICO_CONFIG: PICO_SPINLOCK_ID_OS1, First Spinlock ID reserved for use by low level OS style software, min=0, max=31, default=14, group=hardware_sync
#ifndef PICO_SPINLOCK_ID_OS1
#define PICO_SPINLOCK_ID_OS1 14
#endif
// PICO_CONFIG: PICO_SPINLOCK_ID_OS2, Second Spinlock ID reserved for use by low level OS style software, min=0, max=31, default=15, group=hardware_sync
#ifndef PICO_SPINLOCK_ID_OS2
#define PICO_SPINLOCK_ID_OS2 15
#endif
// PICO_CONFIG: PICO_SPINLOCK_ID_STRIPED_FIRST, Lowest Spinlock ID in the 'striped' range, min=0, max=31, default=16, group=hardware_sync
#ifndef PICO_SPINLOCK_ID_STRIPED_FIRST
#define PICO_SPINLOCK_ID_STRIPED_FIRST 16
#endif
// PICO_CONFIG: PICO_SPINLOCK_ID_STRIPED_LAST, Highest Spinlock ID in the 'striped' range, min=0, max=31, default=23, group=hardware_sync
#ifndef PICO_SPINLOCK_ID_STRIPED_LAST
#define PICO_SPINLOCK_ID_STRIPED_LAST 23
#endif
// PICO_CONFIG: PICO_SPINLOCK_ID_CLAIM_FREE_FIRST, Lowest Spinlock ID in the 'claim free' range, min=0, max=31, default=24, group=hardware_sync
#ifndef PICO_SPINLOCK_ID_CLAIM_FREE_FIRST
#define PICO_SPINLOCK_ID_CLAIM_FREE_FIRST 24
#endif
#ifdef PICO_SPINLOCK_ID_CLAIM_FREE_END
#warning PICO_SPINLOCK_ID_CLAIM_FREE_END has been renamed to PICO_SPINLOCK_ID_CLAIM_FREE_LAST
#endif
// PICO_CONFIG: PICO_SPINLOCK_ID_CLAIM_FREE_LAST, Highest Spinlock ID in the 'claim free' range, min=0, max=31, default=31, group=hardware_sync
#ifndef PICO_SPINLOCK_ID_CLAIM_FREE_LAST
#define PICO_SPINLOCK_ID_CLAIM_FREE_LAST 31
#endif
typedef struct _spin_lock_t spin_lock_t;
inline static void __mem_fence_acquire() {
#ifndef __cplusplus
atomic_thread_fence(memory_order_acquire);
#else
std::atomic_thread_fence(std::memory_order_acquire);
#endif
}
inline static void __mem_fence_release() {
#ifndef __cplusplus
atomic_thread_fence(memory_order_release);
#else
std::atomic_thread_fence(std::memory_order_release);
#endif
}
#ifdef __cplusplus
extern "C" {
#endif
void __sev();
void __wev();
void __wfi();
void __wfe();
uint32_t save_and_disable_interrupts();
void restore_interrupts(uint32_t status);
void restore_interrupts_from_disabled(uint32_t status);
uint spin_lock_get_num(spin_lock_t *lock);
spin_lock_t *spin_lock_instance(uint lock_num);
void spin_lock_unsafe_blocking(spin_lock_t *lock);
void spin_unlock_unsafe(spin_lock_t *lock);
uint32_t spin_lock_blocking(spin_lock_t *lock);
bool is_spin_locked(const spin_lock_t *lock);
void spin_unlock(spin_lock_t *lock, uint32_t saved_irq);
spin_lock_t *spin_lock_init(uint lock_num);
void clear_spin_locks(void);
#define spin_locks_reset() clear_spin_locks()
uint next_striped_spin_lock_num();
void spin_lock_claim(uint lock_num);
void spin_lock_claim_mask(uint32_t lock_num_mask);
void spin_lock_unclaim(uint lock_num);
int spin_lock_claim_unused(bool required);
uint spin_lock_num(spin_lock_t *lock);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,140 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "hardware/sync.h"
#include "hardware/platform_defs.h"
// This is a dummy implementation that is single threaded
static struct _spin_lock_t {
bool locked;
} _spinlocks[NUM_SPIN_LOCKS];
PICO_WEAK_FUNCTION_DEF(save_and_disable_interrupts)
//static uint8_t striped_spin_lock_num;
uint32_t PICO_WEAK_FUNCTION_IMPL_NAME(save_and_disable_interrupts)() {
return 0;
}
PICO_WEAK_FUNCTION_DEF(restore_interrupts)
void PICO_WEAK_FUNCTION_IMPL_NAME(restore_interrupts)(uint32_t status) {
}
PICO_WEAK_FUNCTION_DEF(restore_interrupts_from_disabled)
void PICO_WEAK_FUNCTION_IMPL_NAME(restore_interrupts_from_disabled)(uint32_t status) {
}
PICO_WEAK_FUNCTION_DEF(spin_lock_instance)
spin_lock_t *PICO_WEAK_FUNCTION_IMPL_NAME(spin_lock_instance)(uint lock_num) {
assert(lock_num < NUM_SPIN_LOCKS);
return &_spinlocks[lock_num];
}
PICO_WEAK_FUNCTION_DEF(spin_lock_get_num)
uint PICO_WEAK_FUNCTION_IMPL_NAME(spin_lock_get_num)(spin_lock_t *lock) {
return lock - _spinlocks;
}
PICO_WEAK_FUNCTION_DEF(spin_lock_init)
spin_lock_t *PICO_WEAK_FUNCTION_IMPL_NAME(spin_lock_init)(uint lock_num) {
spin_lock_t *lock = spin_lock_instance(lock_num);
spin_unlock_unsafe(lock);
return lock;
}
PICO_WEAK_FUNCTION_DEF(spin_lock_unsafe_blocking)
void PICO_WEAK_FUNCTION_IMPL_NAME(spin_lock_unsafe_blocking)(spin_lock_t *lock) {
lock->locked = true;
}
PICO_WEAK_FUNCTION_DEF(spin_lock_blocking)
uint32_t PICO_WEAK_FUNCTION_IMPL_NAME(spin_lock_blocking)(spin_lock_t *lock) {
spin_lock_unsafe_blocking(lock);
return 1; // todo wrong value
}
PICO_WEAK_FUNCTION_DEF(is_spin_locked)
bool PICO_WEAK_FUNCTION_IMPL_NAME(is_spin_locked)(const spin_lock_t *lock) {
return lock->locked;
}
PICO_WEAK_FUNCTION_DEF(spin_unlock_unsafe)
void PICO_WEAK_FUNCTION_IMPL_NAME(spin_unlock_unsafe)(spin_lock_t *lock) {
lock->locked = false;
}
PICO_WEAK_FUNCTION_DEF(spin_unlock)
void PICO_WEAK_FUNCTION_IMPL_NAME(spin_unlock)(spin_lock_t *lock, uint32_t saved_irq) {
spin_unlock_unsafe(lock);
}
PICO_WEAK_FUNCTION_DEF(__sev)
volatile bool event_fired;
void PICO_WEAK_FUNCTION_IMPL_NAME(__sev)() {
event_fired = true;
}
PICO_WEAK_FUNCTION_DEF(__wfi)
void PICO_WEAK_FUNCTION_IMPL_NAME(__wfi)() {
panic("Can't wait on irq for host core0 only implementation");
}
PICO_WEAK_FUNCTION_DEF(__wfe)
void PICO_WEAK_FUNCTION_IMPL_NAME(__wfe)() {
while (!event_fired) tight_loop_contents();
}
PICO_WEAK_FUNCTION_DEF(clear_spin_locks)
void PICO_WEAK_FUNCTION_IMPL_NAME(clear_spin_locks)(void) {
for (uint i = 0; i < NUM_SPIN_LOCKS; i++) {
spin_unlock_unsafe(spin_lock_instance(i));
}
}
PICO_WEAK_FUNCTION_DEF(next_striped_spin_lock_num)
uint PICO_WEAK_FUNCTION_IMPL_NAME(next_striped_spin_lock_num)() {
return 0;
}
PICO_WEAK_FUNCTION_DEF(spin_lock_claim)
void PICO_WEAK_FUNCTION_IMPL_NAME(spin_lock_claim)(uint lock_num) {
}
PICO_WEAK_FUNCTION_DEF(spin_lock_claim_mask)
void PICO_WEAK_FUNCTION_IMPL_NAME(spin_lock_claim_mask)(uint32_t mask) {
}
PICO_WEAK_FUNCTION_DEF(spin_lock_unclaim)
void PICO_WEAK_FUNCTION_IMPL_NAME(spin_lock_unclaim)(uint lock_num) {
}
PICO_WEAK_FUNCTION_DEF(spin_lock_claim_unused)
int PICO_WEAK_FUNCTION_IMPL_NAME(spin_lock_claim_unused)(bool required) {
return 0;
}
PICO_WEAK_FUNCTION_DEF(spin_lock_num)
uint PICO_WEAK_FUNCTION_IMPL_NAME(spin_lock_num)(spin_lock_t *lock) {
return 0;
}

View file

@ -1,48 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_TIMER_H
#define _HARDWARE_TIMER_H
#include "pico.h"
#ifdef __cplusplus
extern "C" {
#endif
// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_TIMER, Enable/disable assertions in the hardware_timer module, type=bool, default=0, group=hardware_timer
#ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_TIMER
#ifdef PARAM_ASSERTIONS_ENABLED_TIMER // backwards compatibility with SDK < 2.0.0
#define PARAM_ASSERTIONS_ENABLED_HARDWARE_TIMER PARAM_ASSERTIONS_ENABLED_TIMER
#else
#define PARAM_ASSERTIONS_ENABLED_HARDWARE_TIMER 0
#endif
#endif
static inline void check_hardware_alarm_num_param(uint alarm_num) {
invalid_params_if(HARDWARE_TIMER, alarm_num >= NUM_ALARMS);
}
uint32_t time_us_32();
uint64_t time_us_64();
void busy_wait_us_32(uint32_t delay_us);
void busy_wait_us(uint64_t delay_us);
void busy_wait_ms(uint32_t delay_m);
void busy_wait_until(absolute_time_t t);
bool time_reached(absolute_time_t t);
typedef void (*hardware_alarm_callback_t)(uint alarm_num);
void hardware_alarm_claim(uint alarm_num);
void hardware_alarm_unclaim(uint alarm_num);
int hardware_alarm_claim_unused(bool required);
void hardware_alarm_set_callback(uint alarm_num, hardware_alarm_callback_t callback);
bool hardware_alarm_set_target(uint alarm_num, absolute_time_t t);
void hardware_alarm_cancel(uint alarm_num);
void hardware_alarm_force_irq(uint alarm_num);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,125 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "hardware/timer.h"
#if defined(__unix__) || defined(__APPLE__)
#include <unistd.h>
#include <sys/time.h>
#include <time.h>
#endif
// in our case not a busy wait
PICO_WEAK_FUNCTION_DEF(busy_wait_us_32)
void PICO_WEAK_FUNCTION_IMPL_NAME(busy_wait_us_32)(uint32_t delay_us) {
#if defined(__unix__) || defined(__APPLE__)
usleep(delay_us);
#else
assert(false);
#endif
}
PICO_WEAK_FUNCTION_DEF(busy_wait_us)
void PICO_WEAK_FUNCTION_IMPL_NAME(busy_wait_us)(uint64_t delay_us) {
absolute_time_t t;
update_us_since_boot(&t, time_us_64() + delay_us);
busy_wait_until(t);
}
PICO_WEAK_FUNCTION_DEF(busy_wait_ms)
void PICO_WEAK_FUNCTION_IMPL_NAME(busy_wait_ms)(uint32_t delay_ms) {
#if defined(__unix__) || defined(__APPLE__)
usleep(delay_ms * 1000);
#else
assert(false);
#endif
}
// this may or may not wrap
PICO_WEAK_FUNCTION_DEF(time_us_64)
uint64_t PICO_WEAK_FUNCTION_IMPL_NAME(time_us_64)() {
#if defined(__unix__) || defined(__APPLE__)
// struct timeval tv;
// gettimeofday(&tv, NULL);
// return tv.tv_sec * (uint64_t) 1000000 + tv.tv_usec;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * (uint64_t) 1000000 + ts.tv_nsec / 1000;
#else
panic_unsupported();
#endif
}
PICO_WEAK_FUNCTION_DEF(timer_us_32)
uint32_t PICO_WEAK_FUNCTION_IMPL_NAME(timer_us_32)() {
return (uint32_t) time_us_64();
}
PICO_WEAK_FUNCTION_DEF(time_reached)
bool PICO_WEAK_FUNCTION_IMPL_NAME(time_reached)(absolute_time_t t) {
uint64_t target = to_us_since_boot(t);
return time_us_64() >= target;
}
PICO_WEAK_FUNCTION_DEF(busy_wait_until)
void PICO_WEAK_FUNCTION_IMPL_NAME(busy_wait_until)(absolute_time_t target) {
#if defined(__unix__)
struct timespec tspec;
tspec.tv_sec = to_us_since_boot(target) / 1000000;
tspec.tv_nsec = (to_us_since_boot(target) % 1000000) * 1000;
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tspec, NULL);
#else
const int chunk = 1u<<30u;
uint64_t target_us = to_us_since_boot(target);
uint64_t time_us = time_us_64();
while ((int64_t)(target_us - time_us) >= chunk) {
busy_wait_us_32(chunk);
time_us = time_us_64();
}
if (target_us > time_us) {
busy_wait_us_32(target_us - time_us);
}
#endif
}
static uint8_t claimed_alarms;
void hardware_alarm_claim(uint alarm_num) {
assert(!(claimed_alarms & (1u << alarm_num)));
claimed_alarms |= 1u <<alarm_num;
}
void hardware_alarm_unclaim(uint alarm_num) {
assert(claimed_alarms & (1u << alarm_num));
claimed_alarms &= ~(1u <<alarm_num);
}
int hardware_alarm_claim_unused(bool required) {
int alarm_id = claimed_alarms ? __builtin_clz(~claimed_alarms) : 1;
if (alarm_id >= NUM_ALARMS) return -1;
claimed_alarms |= 1u << alarm_id;
return alarm_id;
}
PICO_WEAK_FUNCTION_DEF(hardware_alarm_set_callback)
void PICO_WEAK_FUNCTION_IMPL_NAME(hardware_alarm_set_callback)(uint alarm_num, hardware_alarm_callback_t callback) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(hardware_alarm_set_target)
bool PICO_WEAK_FUNCTION_IMPL_NAME(hardware_alarm_set_target)(uint alarm_num, absolute_time_t target) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(hardware_alarm_cancel)
void PICO_WEAK_FUNCTION_IMPL_NAME(hardware_alarm_cancel)(uint alarm_num) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(hardware_alarm_force_irq)
void PICO_WEAK_FUNCTION_IMPL_NAME(hardware_alarm_force_irq)(uint alarm_num) {
panic_unsupported();
}

View file

@ -1,100 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_UART_H
#define _HARDWARE_UART_H
#include "pico.h"
// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_UART, Enable/disable assertions in the hardware_uart module, type=bool, default=0, group=hardware_uart
#ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_UART
#ifdef PARAM_ASSERTIONS_ENABLED_UART // backwards compatibility with SDK < 2.0.0
#define PARAM_ASSERTIONS_ENABLED_HARDWARE_UART PARAM_ASSERTIONS_ENABLED_UART
#else
#define PARAM_ASSERTIONS_ENABLED_HARDWARE_UART 0
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct uart_inst uart_inst_t;
extern uart_inst_t * const uart0;
extern uart_inst_t * const uart1;
#define uart_default uart0
typedef enum {
UART_PARITY_NONE,
UART_PARITY_EVEN,
UART_PARITY_ODD
} uart_parity_t;
// ----------------------------------------------------------------------------
// Setup
// Put the UART into a known state, and enable it. Must be called before other
// functions.
uint uart_init(uart_inst_t *uart, uint baudrate);
// Disable the UART if it is no longer used. Must be reinitialised before
// being used again.
void uart_deinit(uart_inst_t *uart);
// Set baud rate as close as possible to requested, and return actual rate.
uint uart_set_baudrate(uart_inst_t *uart, uint baudrate);
// cts: enable flow control of TX by clear-to-send input
// rts: enable assertion of request-to-send output by RX flow control
void uart_set_hw_flow(uart_inst_t *uart, bool cts, bool rts);
// Configure how the UART serialises and deserialises data on the wire
void uart_set_format(uart_inst_t *uart, uint data_bits, uint stop_bits, uart_parity_t parity);
// Enable the UART's interrupt output. Need to install an interrupt handler first.
void uart_set_irqs_enabled(uart_inst_t *uart, bool rx_has_data, bool tx_needs_data);
// ----------------------------------------------------------------------------
// Generic input/output
// If returns 0, no space is available in the UART to write more data.
// If returns nonzero, at least that many bytes can be written without blocking.
bool uart_is_writable(uart_inst_t *uart);
// If returns 0, no data is available to be read from UART.
// If returns nonzero, at least that many bytes can be written without blocking.
bool uart_is_readable(uart_inst_t *uart);
// Write len bytes directly from src to the UART
void uart_write_blocking(uart_inst_t *uart, const uint8_t *src, size_t len);
// Read len bytes directly from the UART to dst
void uart_read_blocking(uart_inst_t *uart, uint8_t *dst, size_t len);
// ----------------------------------------------------------------------------
// UART-specific operations and aliases
void uart_putc(uart_inst_t *uart, char c);
void uart_putc_raw(uart_inst_t *uart, char c);
void uart_puts(uart_inst_t *uart, const char *s);
char uart_getc(uart_inst_t *uart);
// en: assert break condition (TX held low) if true. Clear break condition if false.
void uart_set_break(uart_inst_t *uart, bool en);
void uart_default_tx_wait_blocking();
#define UART_FUNCSEL_NUM(uart, gpio) 0
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,130 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "hardware/uart.h"
#if defined(__unix) || defined(__APPLE__)
#define _XOPEN_SOURCE 600 /* for ONLCR */
#define __BSD_VISIBLE 1 /* for ONLCR in *BSD */
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <stdlib.h>
#ifndef FNONBLOCK
#define FNONBLOCK O_NONBLOCK
#endif
struct termios _tty;
static tcflag_t _res_oflg = 0;
static tcflag_t _res_lflg = 0;
void _resettty(void) {
if (!isatty(STDIN_FILENO))
return;
/* reset tty: */
_tty.c_oflag = _res_oflg;
_tty.c_lflag = _res_lflg;
tcsetattr(STDIN_FILENO, TCSADRAIN, &_tty);
}
void _inittty(void) {
if (!isatty(STDIN_FILENO))
return;
/* save tty: */
tcgetattr(STDIN_FILENO, &_tty);
_res_oflg = _tty.c_oflag;
_res_lflg = _tty.c_lflag;
/* set raw: */
_tty.c_lflag &= ~(ICANON | ICRNL);// | ISIG);
//_tty.c_oflag &= ~ONLCR;
tcsetattr(STDIN_FILENO, TCSANOW, &_tty);
fcntl(STDIN_FILENO, F_SETFL, FNONBLOCK);
atexit(_resettty);
}
#else
void _inittty() {}
#endif
typedef struct {
bool dummy;
} uart_hw_t;
uart_inst_t *const uart0;
uart_inst_t *const uart1;
static int _nextchar = EOF;
static bool _peekchar() {
if (_nextchar == EOF) {
_nextchar = getchar();
}
return _nextchar != EOF;
}
uint uart_init(uart_inst_t *uart, uint baud_rate) {
_inittty();
return baud_rate;
}
bool uart_is_writable(uart_inst_t *uart) {
return 1;
}
// If returns 0, no data is available to be read from UART.
// If returns nonzero, at least that many bytes can be written without blocking.
bool uart_is_readable(uart_inst_t *uart) {
return _peekchar() ? 1 : 0;
}
// Write len bytes directly from src to the UART
void uart_write_blocking(uart_inst_t *uart, const uint8_t *src, size_t len) {
for (size_t i = 0; i < len; i++) {
uart_putc(uart, src[i]);
}
}
// Read len bytes directly from the UART to dst
void uart_read_blocking(uart_inst_t *uart, uint8_t *dst, size_t len) {
for (size_t i = 0; i < len; i++) {
dst[i] = uart_getc(uart);
}
}
// ----------------------------------------------------------------------------
// UART-specific operations and aliases
void uart_putc(uart_inst_t *uart, char c) {
putchar(c);
}
void uart_putc_raw(uart_inst_t *uart, char c) {
putchar(c);
}
void uart_puts(uart_inst_t *uart, const char *s) {
puts(s);
}
char uart_getc(uart_inst_t *uart) {
while (!_peekchar()) {
tight_loop_contents();
}
char rc = (char) _nextchar;
_nextchar = EOF;
return rc;
}
void uart_default_tx_wait_blocking() {
}

View file

@ -1,22 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/bit_ops.h"
uint32_t __rev(uint32_t v) {
v = ((v & 0x55555555u) << 1u) | ((v >> 1u) & 0x55555555u);
v = ((v & 0x33333333u) << 2u) | ((v >> 2u) & 0x33333333u);
v = ((v & 0x0f0f0f0fu) << 4u) | ((v >> 4u) & 0x0f0f0f0fu);
return (v << 24u) | ((v & 0xff00u) << 8u) | ((v >> 8u) & 0xff00u) | (v >> 24u);
}
uint64_t __revll(uint64_t v) {
v = ((v & 0x5555555555555555u) << 1u) | ((v >> 1u) & 0x5555555555555555u);
v = ((v & 0x3333333333333333u) << 2u) | ((v >> 2u) & 0x3333333333333333u);
v = ((v & 0x0f0f0f0f0f0f0f0fu) << 4u) | ((v >> 4u) & 0x0f0f0f0f0f0f0f0fu);
v = ((v & 0x00ff00ff00ff00ffu) << 8u) | ((v >> 8u) & 0x00ff00ff00ff00ffu);
return (v << 48u) | ((v & 0xffff0000u) << 16u) | ((v >> 16u) & 0xffff0000u) | (v >> 48u);
}

View file

@ -1,114 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/divider.h"
// These functions save/restore divider state, so are safe to call from interrupts
int32_t div_s32s32(int32_t a, int32_t b) {
return hw_divider_quotient_s32(a, b);
}
divmod_result_t divmod_s32s32(int32_t a, int32_t b) {
return hw_divider_divmod_s32(a, b);
}
uint32_t div_u32u32(uint32_t a, uint32_t b) {
return hw_divider_u32_quotient(a, b);
}
divmod_result_t divmod_u32u32(uint32_t a, uint32_t b) {
return hw_divider_divmod_u32(a, b);
}
static inline int __sign_of_64(int32_t v) {
return v > 0 ? 1 : (v < 0 ? -1 : 0);
}
typedef struct {
uint64_t quotient;
uint64_t remainder;
} qr_u64;
typedef struct {
int64_t quotient;
int64_t remainder;
} qr_s64;
// divides unsigned values a by b... (a/b) returned in low 32 bits, (a%b) in high 32 bits... results undefined for b==0
static inline qr_u64 udiv64(uint64_t a, uint64_t b) {
qr_u64 rc;
if (!b) {
rc.quotient = (uint64_t)-1; // todo check this
rc.remainder = a;
} else {
rc.quotient = a/b;
rc.remainder = a%b;
}
return rc;
}
// divides signed values a by b... (a/b) returned in low 32 bits, (a%b) in high 32 bits... results undefined for b==0
static inline qr_s64 div64(int64_t a, int64_t b) {
qr_s64 rc;
if (!b) {
rc.quotient = (uint64_t)(-__sign_of_64(a));
rc.remainder = a;
} else {
rc.quotient = a/b;
rc.remainder = a%b;
}
return rc;
}
int64_t div_s64s64(int64_t a, int64_t b) {
qr_s64 qr = div64(a, b);
return qr.quotient;
}
int64_t divmod_s64s64_rem(int64_t a, int64_t b, int64_t *rem) {
qr_s64 qr = div64(a, b);
*rem = qr.remainder;
return qr.quotient;
}
int64_t divmod_s64s64(int64_t a, int64_t b) {
qr_s64 qr = div64(a, b);
return qr.quotient;
}
uint64_t div_u64u64(uint64_t a, uint64_t b) {
qr_u64 qr = udiv64(a, b);
return qr.quotient;
}
uint64_t divmod_u64u64_rem(uint64_t a, uint64_t b, uint64_t *rem) {
qr_u64 qr = udiv64(a, b);
*rem = qr.remainder;
return qr.quotient;
}
uint64_t divmod_u64u64(uint64_t a, uint64_t b) {
qr_u64 qr = udiv64(a, b);
return qr.quotient;
}
// these functions are slightly faster, but unsafe the divider state, so are not generally safe to be called from interrupts
int32_t div_s32s32_unsafe(int32_t a, int32_t b) { return div_s32s32(a,b); }
int32_t divmod_s32s32_rem_unsafe(int32_t a, int32_t b, int32_t *rem) { return divmod_s32s32_rem(a, b, rem); }
divmod_result_t divmod_s32s32_unsafe(int32_t a, int32_t b) { return divmod_s32s32(a, b); }
uint32_t div_u32u32_unsafe(uint32_t a, uint32_t b) { return div_u32u32(a, b); }
uint32_t divmod_u32u32_rem_unsafe(uint32_t a, uint32_t b, uint32_t *rem) { return divmod_u32u32_rem(a, b, rem); }
uint64_t divmod_u32u32_unsafe(uint32_t a, uint32_t b) { return divmod_u32u32(a, b); }
int64_t div_s64s64_unsafe(int64_t a, int64_t b) { return div_s64s64(a, b); }
int64_t divmod_s64s64_rem_unsafe(int64_t a, int64_t b, int64_t *rem) { return divmod_s64s64_rem(a, b, rem); }
int64_t divmod_s64s64_unsafe(int64_t a, int64_t b) { return divmod_s64s64(a, b); }
uint64_t div_u64u64_unsafe(uint64_t a, uint64_t b) { return div_u64u64(a, b); }
uint64_t divmod_u64u64_rem_unsafe(uint64_t a, uint64_t b, uint64_t *rem) { return divmod_u64u64_rem(a, b, rem); }
uint64_t divmod_u64u64_unsafe(uint64_t a, uint64_t b) { return divmod_u64u64(a, b); }

View file

@ -1,45 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_MULTICORE_H
#define _PICO_MULTICORE_H
#include "pico/types.h"
#ifdef __cplusplus
extern "C" {
#endif
void multicore_reset_core1(void);
void multicore_launch_core1(void (*entry)(void));
void multicore_launch_core1_with_stack(void (*entry)(void), uint32_t *stack_bottom, size_t stack_size_bytes);
void multicore_launch_core1_raw(void (*entry)(void), uint32_t *sp, uint32_t vector_table);
bool multicore_fifo_rvalid(void);
bool multicore_fifo_wready(void);
void multicore_fifo_push_blocking(uint32_t data);
bool multicore_fifo_push_timeout_us(uint32_t data, uint64_t timeout_us);
uint32_t multicore_fifo_pop_blocking();
bool multicore_fifo_pop_timeout_us(uint64_t timeout_us, uint32_t *out);
void multicore_fifo_drain(void);
void multicore_fifo_clear_irq(void);
uint32_t multicore_fifo_get_status(void);
// call this from the lockout victim thread
void multicore_lockout_victim_init(void);
// start locking out the other core (it will be
bool multicore_lockout_start_timeout_us(uint64_t timeout_us);
void multicore_lockout_start_blocking(void);
bool multicore_lockout_end_timeout_us(uint64_t timeout_us);
void multicore_lockout_end_blocking(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,31 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_PLATFORM_DEFS_H
#define _HARDWARE_PLATFORM_DEFS_H
#define NUM_CORES 2u
#define NUM_DMA_CHANNELS 12u
#define NUM_GENERIC_TIMERS 1u
#define NUM_ALARMS 4u
#define NUM_IRQS 32u
#define NUM_SPIN_LOCKS 32u
#define XOSC_HZ 12000000u
#define NUM_SPIN_LOCKS 32u
#define NUM_BANK0_GPIOS 30
#ifndef _u
#define _u(x) x ## u
#endif
#endif

View file

@ -1,159 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_PLATFORM_H
#define _PICO_PLATFORM_H
#include "hardware/platform_defs.h"
#include <stdint.h>
#include <stddef.h>
#ifdef __unix__
#include <sys/cdefs.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define __not_in_flash(group)
#define __not_in_flash_func(func) func
#define __no_inline_not_in_flash_func(func) func
#define __in_flash(group)
#define __scratch_x(group)
#define __scratch_y(group)
#ifndef _MSC_VER
#define __packed __attribute__((packed))
#define __packed_aligned __packed __attribute((aligned))
#else
// MSVC requires #pragma pack which isn't compatible with a single attribute style define
#define __packed
#define __packed_aligned
#endif
#define __time_critical_func(x) x
#define __after_data(group)
//int running_on_fpga() { return false; }
extern void tight_loop_contents();
#ifndef __STRING
#define __STRING(x) #x
#endif
#if !defined(_MSC_VER) || defined(__clang__)
#ifndef __noreturn
#define __noreturn __attribute((noreturn))
#endif
#ifndef __unused
#define __unused __attribute__((unused))
#endif
#ifndef __noinline
#define __noinline __attribute__((noinline))
#endif
#ifndef __aligned
#define __aligned(x) __attribute__((aligned(x)))
#endif
#define PICO_WEAK_FUNCTION_DEF(x) _Pragma(__STRING(weak x))
#define PICO_WEAK_FUNCTION_IMPL_NAME(x) x
#ifndef __weak
#define __weak __attribute__((weak))
#endif
#else
#ifndef __noreturn
#define __noreturn __declspec(noreturn)
#endif
#ifndef __unused
#define __unused
#endif
#ifndef __noinline
#define __noinline __declspec(noinline)
#endif
#ifndef __aligned
#define __aligned(x) __declspec(align(x))
#endif
#ifndef __CONCAT
#define __CONCAT(x,y) x ## y
#endif
#define __thread __declspec( thread )
#define PICO_WEAK_FUNCTION_DEF(x) __pragma(comment(linker, __STRING(/alternatename:_##x=_##x##__weak)));
#define PICO_WEAK_FUNCTION_IMPL_NAME(x) x ## __weak
static __noreturn void __builtin_unreachable() {
}
#include <intrin.h>
#define __builtin_clz __lzcnt
#endif
#ifndef count_of
#define count_of(a) (sizeof(a)/sizeof((a)[0]))
#endif
#ifndef MAX
#define MAX(a, b) ((a)>(b)?(a):(b))
#endif
#ifndef MIN
#define MIN(a, b) ((b)>(a)?(a):(b))
#endif
// abort in our case
void __noreturn __breakpoint();
void __noreturn panic_unsupported();
void __noreturn panic(const char *fmt, ...);
// arggggghhhh there is a weak function called sem_init used by SDL
#define sem_init sem_init_alternative
extern uint32_t host_safe_hw_ptr_impl(uintptr_t x);
// return a 32 bit handle for a raw ptr; DMA chaining for example embeds pointers in 32 bit values
// which of course does not work if we're running the code natively on a 64 bit platforms. Therefore
// we provide this macro which allows that code to provide a 64->32 bit mapping in host mode
#define host_safe_hw_ptr(x) host_safe_hw_ptr_impl((uintptr_t)(x))
void *decode_host_safe_hw_ptr(uint32_t ptr);
#define __fast_mul(a,b) ((a)*(b))
typedef unsigned int uint;
static inline int32_t __mul_instruction(int32_t a,int32_t b)
{
return a*b;
}
static inline void __compiler_memory_barrier(void) {
}
uint get_core_num();
static inline uint __get_current_exception(void) {
return 0;
}
void busy_wait_at_least_cycles(uint32_t minimum_cycles);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,54 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdarg.h>
#include <stdio.h>
#include "pico.h"
#include "hardware/timer.h"
PICO_WEAK_FUNCTION_DEF(tight_loop_contents)
void PICO_WEAK_FUNCTION_IMPL_NAME(tight_loop_contents)() {
}
PICO_WEAK_FUNCTION_DEF(get_core_num)
uint PICO_WEAK_FUNCTION_IMPL_NAME(get_core_num)() {
return 0;
}
void __noreturn panic_unsupported() {
panic("not supported");
}
void panic(const char *fmt, ...) {
va_list args;
puts("*** PANIC ***\n");
if (fmt) {
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
puts("\n");
__breakpoint();
}
void __breakpoint() {
#ifdef _MSC_VER
__debugbreak();
#else
__builtin_trap();
#endif
}
PICO_WEAK_FUNCTION_DEF(busy_wait_at_least_cycles)
void PICO_WEAK_FUNCTION_IMPL_NAME(busy_wait_at_least_cycles)(uint32_t cycles) {
// fairly arbitrary; we'll use 125Mhz as a reference
busy_wait_us((cycles + 124)/125);
}

View file

@ -1,36 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_RUNTIME_H
#define _PICO_RUNTIME_H
#include "pico.h"
/** \file runtime.h
* \defgroup pico_runtime pico_runtime
* \brief Basic runtime support for running pre-main initializers provided by other libraries
*/
#ifdef __cplusplus
extern "C" {
#endif
#define PICO_RUNTIME_INIT_TYPE_HW 0
#define PICO_RUNTIME_INIT_TYPE_RUNTIME 1
#define PICO_RUNTIME_INIT_TYPE_PER_CORE 2
#ifndef PICO_RUNTIME_INIT_FUNC_FLAGS
#define PICO_RUNTIME_INIT_FUNC_FLAGS(func, flags, priority_string1, priority_string2)
#endif
#define PICO_RUNTIME_INIT_FUNC_HW(func, priority_string1, priority_string2) PICO_RUNTIME_INIT_FUNC_FLAGS(func, PICO_RUNTIME_INIT_TYPE_HW, priority_string1, priority_string2)
#define PICO_RUNTIME_INIT_FUNC_RUNTIME(func, priority_string1, priority_string2) PICO_RUNTIME_INIT_FUNC_FLAGS(func, PICO_RUNTIME_INIT_TYPE_RUNTIME, priority_string1, priority_string2)
#define PICO_RUNTIME_INIT_FUNC_PER_CORE(func, priority_string1, priority_string2) PICO_RUNTIME_INIT_FUNC_FLAGS(func, PICO_RUNTIME_INIT_TYPE_PER_CORE, priority_string1, priority_string2)
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,61 +0,0 @@
/*
* Copyright (c) 2024 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_RUNTIME_INIT_H
#define _PICO_RUNTIME_INIT_H
#include "pico.h"
#include "pico/runtime.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* The runtime initialization is registration based.
*
* For each step of the initialization there is a 5 digit ordinal which indicates
* the ordering (alphabetic increasing sort of the 5 digits) of the steps.
*
* e.g. for the step "bootrom_reset", there is:
*
* \code
* #ifndef PICO_RUNTIME_INIT_BOOTROM_RESET
* #define PICO_RUNTIME_INIT_BOOTROM_RESET "00050"
* #endif
* \endcode
*
* The user can override the order if they wish, by redefining PICO_RUNTIME_INIT_BOOTROM_RESET
*
* For each step, the automatic initialization may be skipped by defining (in this case)
* PICO_RUNTIME_SKIP_INIT_BOOTROM_RESET = 1. The user can then choose to either omit the step
* completely or register their own replacement initialization.
*
* The default method used to perform the initialization is provided, in case the user
* wishes to call it manually; in this case:
*
* \code
* void runtime_init_bootrom_reset(void);
* \endcode
*
* If PICO_RUNTIME_NO_INIT_BOOTOROM_RESET define is set (NO vs SKIP above), then the function
* is not defined, allowing the user to provide a replacement (and also avoiding
* cases where the default implementation won't compile due to missing dependencies)
*/
// must have no dependency on any other initialization code
#define PICO_RUNTIME_INIT_EARLIEST "00001"
#define PICO_RUNTIME_INIT_LATEST "99999"
// not supported on host at, (needs custom section)
#define PICO_RUNTIME_NO_INIT_MUTEX 1
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,11 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/runtime.h"
void __weak hard_assertion_failure(void) {
panic("Hard assert");
}

View file

@ -1,24 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_STDIO_H
#define _PICO_STDIO_H
typedef struct stdio_driver stdio_driver_t;
#define STDIO_ERROR -1
#define STDIO_NO_INPUT -2
static inline void stdio_usb_init() {}
void stdio_uart_init();
static inline void stdio_init_all() { stdio_uart_init(); }
static inline void stdio_filter_driver(stdio_driver_t *driver) {}
static inline void stdio_set_translate_crlf(stdio_driver_t *driver, bool enabled) {}
static inline bool stdio_usb_connected(void) { return true; }
int getchar_timeout_us(uint32_t timeout_us);
#define puts_raw puts
#define putchar_raw putchar
#endif

View file

@ -1,23 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/stdlib.h"
#include "hardware/uart.h"
int getchar_timeout_us(uint32_t timeout_us) {
absolute_time_t t = make_timeout_time_us(timeout_us);
while (!uart_is_readable(uart_default)) {
if (absolute_time_diff_us(t, get_absolute_time()) > 0) {
return STDIO_NO_INPUT;
}
sleep_ms(1);
}
return uart_getc(uart_default);
}
void stdio_uart_init() {
uart_init(uart_default, 0);
}

View file

@ -1,27 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/stdlib.h"
void setup_default_uart() {
}
void set_sys_clock_48mhz() {
}
bool check_sys_clock_khz(uint32_t freq_khz, uint *vco_out, uint *postdiv1_out, uint *postdiv2_out) {
*vco_out = 1000000;
*postdiv1_out = 0;
*postdiv2_out = 0;
return true;
}
void set_sys_clock_pll(__unused uint32_t vco_freq, __unused uint post_div1, __unused uint post_div2) {
}

View file

@ -1,35 +0,0 @@
/*
* Copyright (c) 2024 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_TIME_ADAPTER_H
#define _PICO_TIME_ADAPTER_H
#ifndef TA_NUM_TIMERS
#define TA_NUM_TIMERS 1
#endif
#ifndef TA_NUM_TIMER_ALARMS
#define TA_NUM_TIMER_ALARMS 4
#endif
void ta_clear_force_irq(alarm_pool_timer_t *timer, uint hardware_alarm_num);
void ta_clear_irq(alarm_pool_timer_t *timer, uint hardware_alarm_num);
void ta_force_irq(alarm_pool_timer_t *timer, uint hardware_alarm_num);
void ta_set_timeout(alarm_pool_timer_t *timer, uint hardware_alarm_num, int64_t target);
void ta_wakes_up_on_or_before(alarm_pool_timer_t *timer, uint alarm_num, int64_t target);
void ta_enable_irq_handler(alarm_pool_timer_t *timer, uint hardware_alarm_num, void (*irq_handler)(void));
void ta_disable_irq_handler(alarm_pool_timer_t *timer, uint hardware_alarm_num, void (*irq_handler)(void));
void ta_hardware_alarm_claim(alarm_pool_timer_t *timer, uint hardware_alarm_num);
int ta_hardware_alarm_claim_unused(alarm_pool_timer_t *timer, bool required);
alarm_pool_timer_t *ta_from_current_irq(uint *alarm_num);
uint ta_timer_num(alarm_pool_timer_t *timer);
static inline uint64_t ta_time_us_64(__unused alarm_pool_timer_t *timer) {
return time_us_64();
}
alarm_pool_timer_t *ta_timer_instance(uint instance_num);
alarm_pool_timer_t *ta_default_timer_instance(void);
#endif

View file

@ -1,71 +0,0 @@
/*
* Copyright (c) 2024 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/time.h"
#include "pico/time_adapter.h"
PICO_WEAK_FUNCTION_DEF(ta_clear_force_irq)
void PICO_WEAK_FUNCTION_IMPL_NAME(ta_clear_force_irq)(alarm_pool_timer_t *timer, uint hardware_alarm_num) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(ta_clear_irq)
void PICO_WEAK_FUNCTION_IMPL_NAME(ta_clear_irq)(alarm_pool_timer_t *timer, uint hardware_alarm_num) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(ta_force_irq)
void PICO_WEAK_FUNCTION_IMPL_NAME(ta_force_irq)(alarm_pool_timer_t *timer, uint hardware_alarm_num) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(ta_get_handler_hardware_alarm_num)
int PICO_WEAK_FUNCTION_IMPL_NAME(ta_get_handler_hardware_alarm_num)() {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(ta_set_timeout)
void PICO_WEAK_FUNCTION_IMPL_NAME(ta_set_timeout)(alarm_pool_timer_t *timer, uint hardware_alarm_num, int64_t target) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(ta_wakes_up_on_or_before)
void PICO_WEAK_FUNCTION_IMPL_NAME(ta_wakes_up_on_or_before)(alarm_pool_timer_t *timer, uint hardware_alarm_num, int64_t target) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(ta_enable_irq_handler)
void PICO_WEAK_FUNCTION_IMPL_NAME(ta_enable_irq_handler)(alarm_pool_timer_t *timer, uint hardware_alarm_num, void (*irq_handler)(void)) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(ta_disable_irq_handler)
void PICO_WEAK_FUNCTION_IMPL_NAME(ta_disable_irq_handler)(alarm_pool_timer_t *timer, uint hardware_alarm_num, void (*irq_handler)(void)) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(ta_hardware_alarm_claim)
void PICO_WEAK_FUNCTION_IMPL_NAME(ta_hardware_alarm_claim)(alarm_pool_timer_t *timer, uint hardware_alaram_num) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(ta_hardware_alarm_claim_unused)
int PICO_WEAK_FUNCTION_IMPL_NAME(ta_hardware_alarm_claim_unused)(alarm_pool_timer_t *timer, bool required) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(ta_from_current_irq);
alarm_pool_timer_t *PICO_WEAK_FUNCTION_IMPL_NAME(ta_from_current_irq)(uint *alarm_num) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(ta_timer_num);
uint ta_timer_num(alarm_pool_timer_t *timer) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(ta_timer_instance);
alarm_pool_timer_t *ta_timer_instance(uint instance_num) {
panic_unsupported();
}
PICO_WEAK_FUNCTION_DEF(ta_default_timer_instance);
alarm_pool_timer_t *ta_default_timer_instance(void) {
panic_unsupported();
}

View file

@ -1,6 +0,0 @@
This directory contains files specific to the RP2040 hardware. It is only used when building for the RP2040 platforms i.e. `PICO_PLATFORM=rp2040`
`hardware_regs` contains low level hardware register #defines autogenerated from the RP2040 chip definition itself.
`hardware_structs` contains C structures for accessing memory mapped registers

View file

@ -1,28 +0,0 @@
/*
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _BOOT2_HELPER_EXIT_FROM_BOOT2
#define _BOOT2_HELPER_EXIT_FROM_BOOT2
#include "hardware/regs/m0plus.h"
// If entered from the bootrom, lr (which we earlier pushed) will be 0,
// and we vector through the table at the start of the main flash image.
// Any regular function call will have a nonzero value for lr.
check_return:
pop {r0}
cmp r0, #0
beq vector_into_flash
bx r0
vector_into_flash:
ldr r0, =(XIP_BASE + 0x100)
ldr r1, =(PPB_BASE + M0PLUS_VTOR_OFFSET)
str r0, [r1]
ldmia r0, {r0, r1}
msr msp, r0
bx r1
#endif

View file

@ -1,30 +0,0 @@
/*
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _BOOT2_HELPER_READ_FLASH_SREG
#define _BOOT2_HELPER_READ_FLASH_SREG
#include "boot2_helpers/wait_ssi_ready.S"
// Pass status read cmd into r0.
// Returns status value in r0.
.global read_flash_sreg
.type read_flash_sreg,%function
.thumb_func
read_flash_sreg:
push {r1, lr}
str r0, [r3, #SSI_DR0_OFFSET]
// Dummy byte:
str r0, [r3, #SSI_DR0_OFFSET]
bl wait_ssi_ready
// Discard first byte and combine the next two
ldr r0, [r3, #SSI_DR0_OFFSET]
ldr r0, [r3, #SSI_DR0_OFFSET]
pop {r1, pc}
#endif

View file

@ -1,26 +0,0 @@
/*
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _BOOT2_HELPER_WAIT_SSI_READY
#define _BOOT2_HELPER_WAIT_SSI_READY
wait_ssi_ready:
push {r0, r1, lr}
// Command is complete when there is nothing left to send
// (TX FIFO empty) and SSI is no longer busy (CSn deasserted)
1:
ldr r1, [r3, #SSI_SR_OFFSET]
movs r0, #SSI_SR_TFE_BITS
tst r1, r0
beq 1b
movs r0, #SSI_SR_BUSY_BITS
tst r1, r0
bne 1b
pop {r0, r1, pc}
#endif

View file

@ -1,282 +0,0 @@
// ----------------------------------------------------------------------------
// Second stage boot code
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
// SPDX-License-Identifier: BSD-3-Clause
//
// Device: Adesto AT25SF128A
// Based on W25Q080 code: main difference is the QE bit is being set
// via command 0x31
//
// Description: Configures AT25SF128A to run in Quad I/O continuous read XIP mode
//
// Details: * Check status register 2 to determine if QSPI mode is enabled,
// and perform an SR2 programming cycle if necessary.
// * Use SSI to perform a dummy 0xEB read command, with the mode
// continuation bits set, so that the flash will not require
// 0xEB instruction prefix on subsequent reads.
// * Configure SSI to write address, mode bits, but no instruction.
// SSI + flash are now jointly in a state where continuous reads
// can take place.
// * Jump to exit pointer passed in via lr. Bootrom passes null,
// in which case this code uses a default 256 byte flash offset
//
// Building: * This code must be position-independent, and use stack only
// * The code will be padded to a size of 256 bytes, including a
// 4-byte checksum. Therefore code size cannot exceed 252 bytes.
// ----------------------------------------------------------------------------
#include "pico/asm_helper.S"
#include "hardware/regs/addressmap.h"
#include "hardware/regs/ssi.h"
#include "hardware/regs/pads_qspi.h"
// ----------------------------------------------------------------------------
// Config section
// ----------------------------------------------------------------------------
// It should be possible to support most flash devices by modifying this section
// The serial flash interface will run at clk_sys/PICO_FLASH_SPI_CLKDIV.
// This must be a positive, even integer.
// The bootrom is very conservative with SPI frequency, but here we should be
// as aggressive as possible.
#ifndef PICO_FLASH_SPI_CLKDIV
#define PICO_FLASH_SPI_CLKDIV 4
#endif
#if PICO_FLASH_SPI_CLKDIV & 1
#error PICO_FLASH_SPI_CLKDIV must be even
#endif
// Define interface width: single/dual/quad IO
#define FRAME_FORMAT SSI_CTRLR0_SPI_FRF_VALUE_QUAD
// For W25Q080 this is the "Read data fast quad IO" instruction:
#define CMD_READ 0xeb
// "Mode bits" are 8 special bits sent immediately after
// the address bits in a "Read Data Fast Quad I/O" command sequence.
// On W25Q080, the four LSBs are don't care, and if MSBs == 0xa, the
// next read does not require the 0xeb instruction prefix.
#define MODE_CONTINUOUS_READ 0x20
// The number of address + mode bits, divided by 4 (always 4, not function of
// interface width).
#define ADDR_L 8
// How many clocks of Hi-Z following the mode bits. For W25Q080, 4 dummy cycles
// are required.
#define WAIT_CYCLES 4
// If defined, we will read status reg, compare to SREG_DATA, and overwrite
// with our value if the SR doesn't match.
// We do a two-byte write to SR1 (01h cmd) rather than a one-byte write to
// SR2 (31h cmd) as the latter command isn't supported by WX25Q080.
// This isn't great because it will remove block protections.
// A better solution is to use a volatile SR write if your device supports it.
#define PROGRAM_STATUS_REG
#define CMD_WRITE_ENABLE 0x06
#define CMD_READ_STATUS 0x05
#define CMD_READ_STATUS2 0x35
#define CMD_WRITE_STATUS 0x01
#define CMD_WRITE_STATUS2 0x31
#define SREG_DATA 0x02 // Enable quad-SPI mode
// ----------------------------------------------------------------------------
// Start of 2nd Stage Boot Code
// ----------------------------------------------------------------------------
pico_default_asm_setup
.section .text
// lr will be zero on entry if entered from the bootrom, and the boot_stage2 is expected
// to continue into the binary via the vector table at 0x10000100.
//
// lr will be non-zero on entry if this code has been copied into RAM by user code and called
// from there, and the boot_stage2 should just return normally.
//
// r3 holds SSI base, r0...2 used as temporaries. Other GPRs not used.
regular_func _stage2_boot
push {lr}
// Set pad configuration:
// - SCLK 8mA drive, no slew limiting
// - SDx disable input Schmitt to reduce delay
ldr r3, =PADS_QSPI_BASE
movs r0, #(2 << PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_LSB | PADS_QSPI_GPIO_QSPI_SCLK_SLEWFAST_BITS)
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SCLK_OFFSET]
ldr r0, [r3, #PADS_QSPI_GPIO_QSPI_SD0_OFFSET]
movs r1, #PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_BITS
bics r0, r1
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD0_OFFSET]
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD1_OFFSET]
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD2_OFFSET]
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD3_OFFSET]
ldr r3, =XIP_SSI_BASE
// Disable SSI to allow further config
movs r1, #0
str r1, [r3, #SSI_SSIENR_OFFSET]
// Set baud rate
movs r1, #PICO_FLASH_SPI_CLKDIV
str r1, [r3, #SSI_BAUDR_OFFSET]
// Set 1-cycle sample delay. If PICO_FLASH_SPI_CLKDIV == 2 then this means,
// if the flash launches data on SCLK posedge, we capture it at the time that
// the next SCLK posedge is launched. This is shortly before that posedge
// arrives at the flash, so data hold time should be ok. For
// PICO_FLASH_SPI_CLKDIV > 2 this pretty much has no effect.
movs r1, #1
movs r2, #SSI_RX_SAMPLE_DLY_OFFSET // == 0xf0 so need 8 bits of offset significance
str r1, [r3, r2]
// On QSPI parts we usually need a 01h SR-write command to enable QSPI mode
// (i.e. turn WPn and HOLDn into IO2/IO3)
#ifdef PROGRAM_STATUS_REG
program_sregs:
#define CTRL0_SPI_TXRX \
(7 << SSI_CTRLR0_DFS_32_LSB) | /* 8 bits per data frame */ \
(SSI_CTRLR0_TMOD_VALUE_TX_AND_RX << SSI_CTRLR0_TMOD_LSB)
ldr r1, =(CTRL0_SPI_TXRX)
str r1, [r3, #SSI_CTRLR0_OFFSET]
// Enable SSI and select slave 0
movs r1, #1
str r1, [r3, #SSI_SSIENR_OFFSET]
// Check whether SR needs updating
movs r0, #CMD_READ_STATUS2
bl read_flash_sreg
movs r2, #SREG_DATA
cmp r0, r2
beq skip_sreg_programming
// Send write enable command
movs r1, #CMD_WRITE_ENABLE
str r1, [r3, #SSI_DR0_OFFSET]
// Poll for completion and discard RX
bl wait_ssi_ready
ldr r1, [r3, #SSI_DR0_OFFSET]
// Send status write command followed by data bytes
movs r1, #CMD_WRITE_STATUS2
str r1, [r3, #SSI_DR0_OFFSET]
str r2, [r3, #SSI_DR0_OFFSET]
bl wait_ssi_ready
ldr r1, [r3, #SSI_DR0_OFFSET]
ldr r1, [r3, #SSI_DR0_OFFSET]
ldr r1, [r3, #SSI_DR0_OFFSET]
// Poll status register for write completion
1:
movs r0, #CMD_READ_STATUS
bl read_flash_sreg
movs r1, #1
tst r0, r1
bne 1b
skip_sreg_programming:
// Disable SSI again so that it can be reconfigured
movs r1, #0
str r1, [r3, #SSI_SSIENR_OFFSET]
#endif
// Currently the flash expects an 8 bit serial command prefix on every
// transfer, which is a waste of cycles. Perform a dummy Fast Read Quad I/O
// command, with mode bits set such that the flash will not expect a serial
// command prefix on *subsequent* transfers. We don't care about the results
// of the read, the important part is the mode bits.
dummy_read:
#define CTRLR0_ENTER_XIP \
(FRAME_FORMAT /* Quad I/O mode */ \
<< SSI_CTRLR0_SPI_FRF_LSB) | \
(31 << SSI_CTRLR0_DFS_32_LSB) | /* 32 data bits */ \
(SSI_CTRLR0_TMOD_VALUE_EEPROM_READ /* Send INST/ADDR, Receive Data */ \
<< SSI_CTRLR0_TMOD_LSB)
ldr r1, =(CTRLR0_ENTER_XIP)
str r1, [r3, #SSI_CTRLR0_OFFSET]
movs r1, #0x0 // NDF=0 (single 32b read)
str r1, [r3, #SSI_CTRLR1_OFFSET]
#define SPI_CTRLR0_ENTER_XIP \
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Address + mode bits */ \
(WAIT_CYCLES << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z dummy clocks following address + mode */ \
(SSI_SPI_CTRLR0_INST_L_VALUE_8B \
<< SSI_SPI_CTRLR0_INST_L_LSB) | /* 8-bit instruction */ \
(SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_1C2A /* Send Command in serial mode then address in Quad I/O mode */ \
<< SSI_SPI_CTRLR0_TRANS_TYPE_LSB)
ldr r1, =(SPI_CTRLR0_ENTER_XIP)
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET) // SPI_CTRL0 Register
str r1, [r0]
movs r1, #1 // Re-enable SSI
str r1, [r3, #SSI_SSIENR_OFFSET]
movs r1, #CMD_READ
str r1, [r3, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO
movs r1, #MODE_CONTINUOUS_READ // 32-bit: 24 address bits (we don't care, so 0) and M[7:4]=1010
str r1, [r3, #SSI_DR0_OFFSET] // Push Address into TX FIFO - this will trigger the transaction
// Poll for completion
bl wait_ssi_ready
// The flash is in a state where we can blast addresses in parallel, and get
// parallel data back. Now configure the SSI to translate XIP bus accesses
// into QSPI transfers of this form.
movs r1, #0
str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config
// Note that the INST_L field is used to select what XIP data gets pushed into
// the TX FIFO:
// INST_L_0_BITS {ADDR[23:0],XIP_CMD[7:0]} Load "mode bits" into XIP_CMD
// Anything else {XIP_CMD[7:0],ADDR[23:0]} Load SPI command into XIP_CMD
configure_ssi:
#define SPI_CTRLR0_XIP \
(MODE_CONTINUOUS_READ /* Mode bits to keep flash in continuous read mode */ \
<< SSI_SPI_CTRLR0_XIP_CMD_LSB) | \
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Total number of address + mode bits */ \
(WAIT_CYCLES << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z dummy clocks following address + mode */ \
(SSI_SPI_CTRLR0_INST_L_VALUE_NONE /* Do not send a command, instead send XIP_CMD as mode bits after address */ \
<< SSI_SPI_CTRLR0_INST_L_LSB) | \
(SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_2C2A /* Send Address in Quad I/O mode (and Command but that is zero bits long) */ \
<< SSI_SPI_CTRLR0_TRANS_TYPE_LSB)
ldr r1, =(SPI_CTRLR0_XIP)
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET)
str r1, [r0]
movs r1, #1
str r1, [r3, #SSI_SSIENR_OFFSET] // Re-enable SSI
// Bus accesses to the XIP window will now be transparently serviced by the
// external flash on cache miss. We are ready to run code from flash.
// Pull in standard exit routine
#include "boot2_helpers/exit_from_boot2.S"
// Common functions
#include "boot2_helpers/wait_ssi_ready.S"
#ifdef PROGRAM_STATUS_REG
#include "boot2_helpers/read_flash_sreg.S"
#endif
.global literals
literals:
.ltorg
.end

View file

@ -1,106 +0,0 @@
// ----------------------------------------------------------------------------
// Second stage boot code
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
// SPDX-License-Identifier: BSD-3-Clause
//
// Device: Anything which responds to 03h serial read command
//
// Details: * Configure SSI to translate each APB read into a 03h command
// * 8 command clocks, 24 address clocks and 32 data clocks
// * This enables you to boot from almost anything: you can pretty
// much solder a potato to your PCB, or a piece of cheese
// * The tradeoff is performance around 3x worse than QSPI XIP
//
// Building: * This code must be position-independent, and use stack only
// * The code will be padded to a size of 256 bytes, including a
// 4-byte checksum. Therefore code size cannot exceed 252 bytes.
// ----------------------------------------------------------------------------
#include "pico/asm_helper.S"
#include "hardware/regs/addressmap.h"
#include "hardware/regs/ssi.h"
pico_default_asm_setup
// ----------------------------------------------------------------------------
// Config section
// ----------------------------------------------------------------------------
// It should be possible to support most flash devices by modifying this section
// The serial flash interface will run at clk_sys/PICO_FLASH_SPI_CLKDIV.
// This must be a positive, even integer.
// The bootrom is very conservative with SPI frequency, but here we should be
// as aggressive as possible.
#ifndef PICO_FLASH_SPI_CLKDIV
#define PICO_FLASH_SPI_CLKDIV 4
#endif
#define CMD_READ 0x03
// Value is number of address bits divided by 4
#define ADDR_L 6
#define CTRLR0_XIP \
(SSI_CTRLR0_SPI_FRF_VALUE_STD << SSI_CTRLR0_SPI_FRF_LSB) | /* Standard 1-bit SPI serial frames */ \
(31 << SSI_CTRLR0_DFS_32_LSB) | /* 32 clocks per data frame */ \
(SSI_CTRLR0_TMOD_VALUE_EEPROM_READ << SSI_CTRLR0_TMOD_LSB) /* Send instr + addr, receive data */
#define SPI_CTRLR0_XIP \
(CMD_READ << SSI_SPI_CTRLR0_XIP_CMD_LSB) | /* Value of instruction prefix */ \
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Total number of address + mode bits */ \
(2 << SSI_SPI_CTRLR0_INST_L_LSB) | /* 8 bit command prefix (field value is bits divided by 4) */ \
(SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_1C1A << SSI_SPI_CTRLR0_TRANS_TYPE_LSB) /* command and address both in serial format */
// ----------------------------------------------------------------------------
// Start of 2nd Stage Boot Code
// ----------------------------------------------------------------------------
.section .text
// lr will be zero on entry if entered from the bootrom, and the boot_stage2 is expected
// to continue into the binary via the vector table at 0x10000100.
//
// lr will be non-zero on entry if this code has been copied into RAM by user code and called
// from there, and the boot_stage2 should just return normally.
//
// r3 holds SSI base, r0...2 used as temporaries. Other GPRs not used.
regular_func _stage2_boot
push {lr}
ldr r3, =XIP_SSI_BASE // Use as base address where possible
// Disable SSI to allow further config
movs r1, #0
str r1, [r3, #SSI_SSIENR_OFFSET]
// Set baud rate
movs r1, #PICO_FLASH_SPI_CLKDIV
str r1, [r3, #SSI_BAUDR_OFFSET]
ldr r1, =(CTRLR0_XIP)
str r1, [r3, #SSI_CTRLR0_OFFSET]
ldr r1, =(SPI_CTRLR0_XIP)
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET)
str r1, [r0]
// NDF=0 (single 32b read)
movs r1, #0x0
str r1, [r3, #SSI_CTRLR1_OFFSET]
// Re-enable SSI
movs r1, #1
str r1, [r3, #SSI_SSIENR_OFFSET]
// We are now in XIP mode. Any bus accesses to the XIP address window will be
// translated by the SSI into 03h read commands to the external flash (if cache is missed),
// and the data will be returned to the bus.
// Pull in standard exit routine
#include "boot2_helpers/exit_from_boot2.S"
.global literals
literals:
.ltorg
.end

View file

@ -1,264 +0,0 @@
// ----------------------------------------------------------------------------
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
// SPDX-License-Identifier: BSD-3-Clause
//
// Device: ISSI IS25LP080D
// Based on W25Q080 code: main difference is the QE bit being in
// SR1 instead of SR2.
//
// Description: Configures IS25LP080D to run in Quad I/O continuous read XIP mode
//
// Details: * Check status register to determine if QSPI mode is enabled,
// and perform an SR programming cycle if necessary.
// * Use SSI to perform a dummy 0xEB read command, with the mode
// continuation bits set, so that the flash will not require
// 0xEB instruction prefix on subsequent reads.
// * Configure SSI to write address, mode bits, but no instruction.
// SSI + flash are now jointly in a state where continuous reads
// can take place.
// * Set VTOR = 0x10000100 (user vector table immediately after
// this boot2 image).
// * Read stack pointer (MSP) and reset vector from the flash
// vector table; set SP and jump, as though the processor had
// booted directly from flash.
//
// Building: * This code must be linked to run at 0x20027f00
// * The code will be padded to a size of 256 bytes, including a
// 4-byte checksum. Therefore code size cannot exceed 252 bytes.
// ----------------------------------------------------------------------------
#include "pico/asm_helper.S"
#include "hardware/regs/addressmap.h"
#include "hardware/regs/ssi.h"
// ----------------------------------------------------------------------------
// Config section
// ----------------------------------------------------------------------------
// It should be possible to support most flash devices by modifying this section
// The serial flash interface will run at clk_sys/PICO_FLASH_SPI_CLKDIV.
// This must be a positive, even integer.
// The bootrom is very conservative with SPI frequency, but here we should be
// as aggressive as possible.
#ifndef PICO_FLASH_SPI_CLKDIV
#define PICO_FLASH_SPI_CLKDIV 4
#endif
// Define interface width: single/dual/quad IO
#define FRAME_FORMAT SSI_CTRLR0_SPI_FRF_VALUE_QUAD
// For W25Q080 this is the "Read data fast quad IO" instruction:
#define CMD_READ 0xeb
// "Mode bits" are 8 special bits sent immediately after
// the address bits in a "Read Data Fast Quad I/O" command sequence.
// On W25Q080, the four LSBs are don't care, and if MSBs == 0xa, the
// next read does not require the 0xeb instruction prefix.
#define MODE_CONTINUOUS_READ 0xa0
// The number of address + mode bits, divided by 4 (always 4, not function of
// interface width).
#define ADDR_L 8
// How many clocks of Hi-Z following the mode bits. For W25Q080, 4 dummy cycles
// are required.
#define WAIT_CYCLES 4
// If defined, we will read status reg, compare to SREG_DATA, and overwrite
// with our value if the SR doesn't match.
// This isn't great because it will remove block protections.
// A better solution is to use a volatile SR write if your device supports it.
#define PROGRAM_STATUS_REG
#define CMD_WRITE_ENABLE 0x06
#define CMD_READ_STATUS 0x05
#define CMD_WRITE_STATUS 0x01
#define SREG_DATA 0x40 // Enable quad-SPI mode
// ----------------------------------------------------------------------------
// Start of 2nd Stage Boot Code
// ----------------------------------------------------------------------------
pico_default_asm_setup
.section .text
// lr will be zero on entry if entered from the bootrom, and the boot_stage2 is expected
// to continue into the binary via the vector table at 0x10000100.
//
// lr will be non-zero on entry if this code has been copied into RAM by user code and called
// from there, and the boot_stage2 should just return normally.
//
// r3 holds SSI base, r0...2 used as temporaries. Other GPRs not used.
regular_func _stage2_boot
push {lr}
ldr r3, =XIP_SSI_BASE // Use as base address where possible
// Disable SSI to allow further config
movs r1, #0
str r1, [r3, #SSI_SSIENR_OFFSET]
// Set baud rate
movs r1, #PICO_FLASH_SPI_CLKDIV
str r1, [r3, #SSI_BAUDR_OFFSET]
// On QSPI parts we usually need a 01h SR-write command to enable QSPI mode
// (i.e. turn WPn and HOLDn into IO2/IO3)
#ifdef PROGRAM_STATUS_REG
program_sregs:
#define CTRL0_SPI_TXRX \
(7 << SSI_CTRLR0_DFS_32_LSB) | /* 8 bits per data frame */ \
(SSI_CTRLR0_TMOD_VALUE_TX_AND_RX << SSI_CTRLR0_TMOD_LSB)
ldr r1, =(CTRL0_SPI_TXRX)
str r1, [r3, #SSI_CTRLR0_OFFSET]
// Enable SSI and select slave 0
movs r1, #1
str r1, [r3, #SSI_SSIENR_OFFSET]
// Check whether SR needs updating
ldr r0, =CMD_READ_STATUS
bl read_flash_sreg
ldr r2, =SREG_DATA
cmp r0, r2
beq skip_sreg_programming
// Send write enable command
movs r1, #CMD_WRITE_ENABLE
str r1, [r3, #SSI_DR0_OFFSET]
// Poll for completion and discard RX
bl wait_ssi_ready
ldr r1, [r3, #SSI_DR0_OFFSET]
// Send status write command followed by data bytes
movs r1, #CMD_WRITE_STATUS
str r1, [r3, #SSI_DR0_OFFSET]
movs r0, #0
str r2, [r3, #SSI_DR0_OFFSET]
bl wait_ssi_ready
ldr r1, [r3, #SSI_DR0_OFFSET]
ldr r1, [r3, #SSI_DR0_OFFSET]
// Poll status register for write completion
1:
ldr r0, =CMD_READ_STATUS
bl read_flash_sreg
movs r1, #1
tst r0, r1
bne 1b
skip_sreg_programming:
// Send a 0xA3 high-performance-mode instruction
// ldr r1, =0xa3
// str r1, [r3, #SSI_DR0_OFFSET]
// bl wait_ssi_ready
// Disable SSI again so that it can be reconfigured
movs r1, #0
str r1, [r3, #SSI_SSIENR_OFFSET]
#endif
// First we need to send the initial command to get us in to Fast Read Quad I/O
// mode. As this transaction requires a command, we can't send it in XIP mode.
// To enter Continuous Read mode as well we need to append 4'b0010 to the address
// bits and then add a further 4 don't care bits. We will construct this by
// specifying a 28-bit address, with the least significant bits being 4'b0010.
// This is just a dummy transaction so we'll perform a read from address zero
// and then discard what comes back. All we really care about is that at the
// end of the transaction, the flash device is in Continuous Read mode
// and from then on will only expect to receive addresses.
dummy_read:
#define CTRLR0_ENTER_XIP \
(FRAME_FORMAT /* Quad I/O mode */ \
<< SSI_CTRLR0_SPI_FRF_LSB) | \
(31 << SSI_CTRLR0_DFS_32_LSB) | /* 32 data bits */ \
(SSI_CTRLR0_TMOD_VALUE_EEPROM_READ /* Send INST/ADDR, Receive Data */ \
<< SSI_CTRLR0_TMOD_LSB)
ldr r1, =(CTRLR0_ENTER_XIP)
str r1, [r3, #SSI_CTRLR0_OFFSET]
movs r1, #0x0 // NDF=0 (single 32b read)
str r1, [r3, #SSI_CTRLR1_OFFSET]
#define SPI_CTRLR0_ENTER_XIP \
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Address + mode bits */ \
(WAIT_CYCLES << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z dummy clocks following address + mode */ \
(SSI_SPI_CTRLR0_INST_L_VALUE_8B \
<< SSI_SPI_CTRLR0_INST_L_LSB) | /* 8-bit instruction */ \
(SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_1C2A /* Send Command in serial mode then address in Quad I/O mode */ \
<< SSI_SPI_CTRLR0_TRANS_TYPE_LSB)
ldr r1, =(SPI_CTRLR0_ENTER_XIP)
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET) // SPI_CTRL0 Register
str r1, [r0]
movs r1, #1 // Re-enable SSI
str r1, [r3, #SSI_SSIENR_OFFSET]
movs r1, #CMD_READ
str r1, [r3, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO
movs r1, #MODE_CONTINUOUS_READ // 32-bit: 24 address bits (we don't care, so 0) and M[7:4]=1010
str r1, [r3, #SSI_DR0_OFFSET] // Push Address into TX FIFO - this will trigger the transaction
// Poll for completion
bl wait_ssi_ready
// At this point CN# will be deasserted and the SPI clock will not be running.
// The Winbond WX25X10CL device will be in continuous read, dual I/O mode and
// only expecting address bits after the next CN# assertion. So long as we
// send 4'b0010 (and 4 more dummy HiZ bits) after every subsequent 24b address
// then the Winbond device will remain in continuous read mode. This is the
// ideal mode for Execute-In-Place.
// (If we want to exit continuous read mode then we will need to switch back
// to APM mode and generate a 28-bit address phase with the extra nibble set
// to 4'b0000).
movs r1, #0
str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config
// Note that the INST_L field is used to select what XIP data gets pushed into
// the TX FIFO:
// INST_L_0_BITS {ADDR[23:0],XIP_CMD[7:0]} Load "mode bits" into XIP_CMD
// Anything else {XIP_CMD[7:0],ADDR[23:0]} Load SPI command into XIP_CMD
configure_ssi:
#define SPI_CTRLR0_XIP \
(MODE_CONTINUOUS_READ /* Mode bits to keep flash in continuous read mode */ \
<< SSI_SPI_CTRLR0_XIP_CMD_LSB) | \
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Total number of address + mode bits */ \
(WAIT_CYCLES << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z dummy clocks following address + mode */ \
(SSI_SPI_CTRLR0_INST_L_VALUE_NONE /* Do not send a command, instead send XIP_CMD as mode bits after address */ \
<< SSI_SPI_CTRLR0_INST_L_LSB) | \
(SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_2C2A /* Send Address in Quad I/O mode (and Command but that is zero bits long) */ \
<< SSI_SPI_CTRLR0_TRANS_TYPE_LSB)
ldr r1, =(SPI_CTRLR0_XIP)
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET)
str r1, [r0]
movs r1, #1
str r1, [r3, #SSI_SSIENR_OFFSET] // Re-enable SSI
// We are now in XIP mode, with all transactions using Dual I/O and only
// needing to send 24-bit addresses (plus mode bits) for each read transaction.
// Pull in standard exit routine
#include "boot2_helpers/exit_from_boot2.S"
// Common functions
#include "boot2_helpers/wait_ssi_ready.S"
#ifdef PROGRAM_STATUS_REG
#include "boot2_helpers/read_flash_sreg.S"
#endif
.global literals
literals:
.ltorg
.end

View file

@ -1,50 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/asm_helper.S"
// Stub second stage which calls into USB bootcode, with parameters.
// USB boot takes two parameters:
// - A GPIO mask for activity LED -- if mask is 0, don't touch GPIOs at all
// - A mask of interfaces to disable. Bit 0 disables MSC, bit 1 disables PICOBoot
// The bootrom passes 0 for both of these parameters, but user code (or this
// second stage) can pass anything.
#define USB_BOOT_MSD_AND_PICOBOOT 0x0
#define USB_BOOT_MSD_ONLY 0x2
#define USB_BOOT_PICOBOOT_ONLY 0x1
// Config
#define ACTIVITY_LED 0
#define BOOT_MODE USB_BOOT_MSD_AND_PICOBOOT
pico_default_asm_setup
.section .text
regular_func _stage2_boot
movs r7, #0x14 // Pointer to _well_known pointer table in ROM
ldrh r0, [r7, #0] // Offset 0 is 16 bit pointer to function table
ldrh r7, [r7, #4] // Offset 4 is 16 bit pointer to table lookup routine
ldr r1, =('U' | ('B' << 8)) // Symbol for USB Boot
blx r7
cmp r0, #0
beq dead
mov r7, r0
ldr r0, =(1u << ACTIVITY_LED) // Mask of which GPIO (or GPIOs) to use
movs r1, #BOOT_MODE
blx r7
dead:
wfi
b dead
.global literals
literals:
.ltorg
.end

View file

@ -1,284 +0,0 @@
// ----------------------------------------------------------------------------
// Second stage boot code
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
// SPDX-License-Identifier: BSD-3-Clause
//
// Device: Winbond W25Q080
// Also supports W25Q16JV (which has some different SR instructions)
// Also supports AT25SF081
// Also supports S25FL132K0
//
// Description: Configures W25Q080 to run in Quad I/O continuous read XIP mode
//
// Details: * Check status register 2 to determine if QSPI mode is enabled,
// and perform an SR2 programming cycle if necessary.
// * Use SSI to perform a dummy 0xEB read command, with the mode
// continuation bits set, so that the flash will not require
// 0xEB instruction prefix on subsequent reads.
// * Configure SSI to write address, mode bits, but no instruction.
// SSI + flash are now jointly in a state where continuous reads
// can take place.
// * Jump to exit pointer passed in via lr. Bootrom passes null,
// in which case this code uses a default 256 byte flash offset
//
// Building: * This code must be position-independent, and use stack only
// * The code will be padded to a size of 256 bytes, including a
// 4-byte checksum. Therefore code size cannot exceed 252 bytes.
// ----------------------------------------------------------------------------
#include "pico/asm_helper.S"
#include "hardware/regs/addressmap.h"
#include "hardware/regs/ssi.h"
#include "hardware/regs/pads_qspi.h"
// ----------------------------------------------------------------------------
// Config section
// ----------------------------------------------------------------------------
// It should be possible to support most flash devices by modifying this section
// The serial flash interface will run at clk_sys/PICO_FLASH_SPI_CLKDIV.
// This must be a positive, even integer.
// The bootrom is very conservative with SPI frequency, but here we should be
// as aggressive as possible.
#ifndef PICO_FLASH_SPI_CLKDIV
#define PICO_FLASH_SPI_CLKDIV 4
#endif
#if PICO_FLASH_SPI_CLKDIV & 1
#error PICO_FLASH_SPI_CLKDIV must be even
#endif
// Define interface width: single/dual/quad IO
#define FRAME_FORMAT SSI_CTRLR0_SPI_FRF_VALUE_QUAD
// For W25Q080 this is the "Read data fast quad IO" instruction:
#define CMD_READ 0xeb
// "Mode bits" are 8 special bits sent immediately after
// the address bits in a "Read Data Fast Quad I/O" command sequence.
// On W25Q080, the four LSBs are don't care, and if MSBs == 0xa, the
// next read does not require the 0xeb instruction prefix.
#define MODE_CONTINUOUS_READ 0xa0
// The number of address + mode bits, divided by 4 (always 4, not function of
// interface width).
#define ADDR_L 8
// How many clocks of Hi-Z following the mode bits. For W25Q080, 4 dummy cycles
// are required.
#define WAIT_CYCLES 4
// If defined, we will read status reg, compare to SREG_DATA, and overwrite
// with our value if the SR doesn't match.
// We do a two-byte write to SR1 (01h cmd) rather than a one-byte write to
// SR2 (31h cmd) as the latter command isn't supported by WX25Q080.
// This isn't great because it will remove block protections.
// A better solution is to use a volatile SR write if your device supports it.
#define PROGRAM_STATUS_REG
#define CMD_WRITE_ENABLE 0x06
#define CMD_READ_STATUS 0x05
#define CMD_READ_STATUS2 0x35
#define CMD_WRITE_STATUS 0x01
#define SREG_DATA 0x02 // Enable quad-SPI mode
// ----------------------------------------------------------------------------
// Start of 2nd Stage Boot Code
// ----------------------------------------------------------------------------
pico_default_asm_setup
.section .text
// lr will be zero on entry if entered from the bootrom, and the boot_stage2 is expected
// to continue into the binary via the vector table at 0x10000100.
//
// lr will be non-zero on entry if this code has been copied into RAM by user code and called
// from there, and the boot_stage2 should just return normally.
//
// r3 holds SSI base, r0...2 used as temporaries. Other GPRs not used.
regular_func _stage2_boot
push {lr}
// Set pad configuration:
// - SCLK 8mA drive, no slew limiting
// - SDx disable input Schmitt to reduce delay
ldr r3, =PADS_QSPI_BASE
movs r0, #(2 << PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_LSB | PADS_QSPI_GPIO_QSPI_SCLK_SLEWFAST_BITS)
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SCLK_OFFSET]
ldr r0, [r3, #PADS_QSPI_GPIO_QSPI_SD0_OFFSET]
movs r1, #PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_BITS
bics r0, r1
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD0_OFFSET]
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD1_OFFSET]
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD2_OFFSET]
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD3_OFFSET]
ldr r3, =XIP_SSI_BASE
// Disable SSI to allow further config
movs r1, #0
str r1, [r3, #SSI_SSIENR_OFFSET]
// Set baud rate
movs r1, #PICO_FLASH_SPI_CLKDIV
str r1, [r3, #SSI_BAUDR_OFFSET]
// Set 1-cycle sample delay. If PICO_FLASH_SPI_CLKDIV == 2 then this means,
// if the flash launches data on SCLK posedge, we capture it at the time that
// the next SCLK posedge is launched. This is shortly before that posedge
// arrives at the flash, so data hold time should be ok. For
// PICO_FLASH_SPI_CLKDIV > 2 this pretty much has no effect.
movs r1, #1
movs r2, #SSI_RX_SAMPLE_DLY_OFFSET // == 0xf0 so need 8 bits of offset significance
str r1, [r3, r2]
// On QSPI parts we usually need a 01h SR-write command to enable QSPI mode
// (i.e. turn WPn and HOLDn into IO2/IO3)
#ifdef PROGRAM_STATUS_REG
program_sregs:
#define CTRL0_SPI_TXRX \
(7 << SSI_CTRLR0_DFS_32_LSB) | /* 8 bits per data frame */ \
(SSI_CTRLR0_TMOD_VALUE_TX_AND_RX << SSI_CTRLR0_TMOD_LSB)
ldr r1, =(CTRL0_SPI_TXRX)
str r1, [r3, #SSI_CTRLR0_OFFSET]
// Enable SSI and select slave 0
movs r1, #1
str r1, [r3, #SSI_SSIENR_OFFSET]
// Check whether SR needs updating
movs r0, #CMD_READ_STATUS2
bl read_flash_sreg
movs r2, #SREG_DATA
cmp r0, r2
beq skip_sreg_programming
// Send write enable command
movs r1, #CMD_WRITE_ENABLE
str r1, [r3, #SSI_DR0_OFFSET]
// Poll for completion and discard RX
bl wait_ssi_ready
ldr r1, [r3, #SSI_DR0_OFFSET]
// Send status write command followed by data bytes
movs r1, #CMD_WRITE_STATUS
str r1, [r3, #SSI_DR0_OFFSET]
movs r0, #0
str r0, [r3, #SSI_DR0_OFFSET]
str r2, [r3, #SSI_DR0_OFFSET]
bl wait_ssi_ready
ldr r1, [r3, #SSI_DR0_OFFSET]
ldr r1, [r3, #SSI_DR0_OFFSET]
ldr r1, [r3, #SSI_DR0_OFFSET]
// Poll status register for write completion
1:
movs r0, #CMD_READ_STATUS
bl read_flash_sreg
movs r1, #1
tst r0, r1
bne 1b
skip_sreg_programming:
// Disable SSI again so that it can be reconfigured
movs r1, #0
str r1, [r3, #SSI_SSIENR_OFFSET]
#endif
// Currently the flash expects an 8 bit serial command prefix on every
// transfer, which is a waste of cycles. Perform a dummy Fast Read Quad I/O
// command, with mode bits set such that the flash will not expect a serial
// command prefix on *subsequent* transfers. We don't care about the results
// of the read, the important part is the mode bits.
dummy_read:
#define CTRLR0_ENTER_XIP \
(FRAME_FORMAT /* Quad I/O mode */ \
<< SSI_CTRLR0_SPI_FRF_LSB) | \
(31 << SSI_CTRLR0_DFS_32_LSB) | /* 32 data bits */ \
(SSI_CTRLR0_TMOD_VALUE_EEPROM_READ /* Send INST/ADDR, Receive Data */ \
<< SSI_CTRLR0_TMOD_LSB)
ldr r1, =(CTRLR0_ENTER_XIP)
str r1, [r3, #SSI_CTRLR0_OFFSET]
movs r1, #0x0 // NDF=0 (single 32b read)
str r1, [r3, #SSI_CTRLR1_OFFSET]
#define SPI_CTRLR0_ENTER_XIP \
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Address + mode bits */ \
(WAIT_CYCLES << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z dummy clocks following address + mode */ \
(SSI_SPI_CTRLR0_INST_L_VALUE_8B \
<< SSI_SPI_CTRLR0_INST_L_LSB) | /* 8-bit instruction */ \
(SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_1C2A /* Send Command in serial mode then address in Quad I/O mode */ \
<< SSI_SPI_CTRLR0_TRANS_TYPE_LSB)
ldr r1, =(SPI_CTRLR0_ENTER_XIP)
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET) // SPI_CTRL0 Register
str r1, [r0]
movs r1, #1 // Re-enable SSI
str r1, [r3, #SSI_SSIENR_OFFSET]
movs r1, #CMD_READ
str r1, [r3, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO
movs r1, #MODE_CONTINUOUS_READ // 32-bit: 24 address bits (we don't care, so 0) and M[7:4]=1010
str r1, [r3, #SSI_DR0_OFFSET] // Push Address into TX FIFO - this will trigger the transaction
// Poll for completion
bl wait_ssi_ready
// The flash is in a state where we can blast addresses in parallel, and get
// parallel data back. Now configure the SSI to translate XIP bus accesses
// into QSPI transfers of this form.
movs r1, #0
str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config
// Note that the INST_L field is used to select what XIP data gets pushed into
// the TX FIFO:
// INST_L_0_BITS {ADDR[23:0],XIP_CMD[7:0]} Load "mode bits" into XIP_CMD
// Anything else {XIP_CMD[7:0],ADDR[23:0]} Load SPI command into XIP_CMD
configure_ssi:
#define SPI_CTRLR0_XIP \
(MODE_CONTINUOUS_READ /* Mode bits to keep flash in continuous read mode */ \
<< SSI_SPI_CTRLR0_XIP_CMD_LSB) | \
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Total number of address + mode bits */ \
(WAIT_CYCLES << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z dummy clocks following address + mode */ \
(SSI_SPI_CTRLR0_INST_L_VALUE_NONE /* Do not send a command, instead send XIP_CMD as mode bits after address */ \
<< SSI_SPI_CTRLR0_INST_L_LSB) | \
(SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_2C2A /* Send Address in Quad I/O mode (and Command but that is zero bits long) */ \
<< SSI_SPI_CTRLR0_TRANS_TYPE_LSB)
ldr r1, =(SPI_CTRLR0_XIP)
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET)
str r1, [r0]
movs r1, #1
str r1, [r3, #SSI_SSIENR_OFFSET] // Re-enable SSI
// Bus accesses to the XIP window will now be transparently serviced by the
// external flash on cache miss. We are ready to run code from flash.
// Pull in standard exit routine
#include "boot2_helpers/exit_from_boot2.S"
// Common functions
#include "boot2_helpers/wait_ssi_ready.S"
#ifdef PROGRAM_STATUS_REG
#include "boot2_helpers/read_flash_sreg.S"
#endif
.global literals
literals:
.ltorg
.end

View file

@ -1,197 +0,0 @@
// ----------------------------------------------------------------------------
// Second stage boot code
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
// SPDX-License-Identifier: BSD-3-Clause
//
// Device: Winbond W25X10CL
//
// Description: Configures W25X10CL to run in Dual I/O continuous read XIP mode
//
// Details: * Disable SSI
// * Configure SSI to generate 8b command + 28b address + 2 wait,
// with address and data using dual SPI mode
// * Enable SSI
// * Generate dummy read with command = 0xBB, top 24b of address
// of 0x000000 followed by M[7:0]=0010zzzz (with the HiZ being
// generated by 2 wait cycles). This leaves the W25X10CL in
// continuous read mode
// * Disable SSI
// * Configure SSI to generate 0b command + 28b address + 2 wait,
// with the extra 4 bits of address LSB being 0x2 to keep the
// W25X10CL in continuous read mode forever
// * Enable SSI
// * Set VTOR = 0x10000100
// * Read MSP reset vector from 0x10000100 and write to MSP (this
// will also enable XIP mode in the SSI wrapper)
// * Read PC reset vector from 0x10000104 and jump to it
//
// Building: * This code must be linked to run at 0x20000000
// * The code will be padded to a size of 256 bytes, including a
// 4-byte checksum. Therefore code size cannot exceed 252 bytes.
// ----------------------------------------------------------------------------
#include "pico/asm_helper.S"
#include "hardware/regs/addressmap.h"
#include "hardware/regs/ssi.h"
// The serial flash interface will run at clk_sys/PICO_FLASH_SPI_CLKDIV.
// This must be an even number.
#ifndef PICO_FLASH_SPI_CLKDIV
#define PICO_FLASH_SPI_CLKDIV 4
#endif
pico_default_asm_setup
// ----------------------------------------------------------------------------
// The "System Control Block" is a set of internal Cortex-M0+ control registers
// that are memory mapped and accessed like any other H/W register. They have
// fixed addresses in the address map of every Cortex-M0+ system.
// ----------------------------------------------------------------------------
.equ SCB_VTOR, 0xE000ED08 // RW Vector Table Offset Register
// ----------------------------------------------------------------------------
// Winbond W25X10CL Supported Commands
// Taken from "w25x10cl_reg_021714.pdf"
// ----------------------------------------------------------------------------
.equ W25X10CL_CMD_READ_DATA_FAST_DUAL_IO, 0xbb
// ----------------------------------------------------------------------------
// Winbond W25X10CL "Mode bits" are 8 special bits sent immediately after
// the address bits in a "Read Data Fast Dual I/O" command sequence.
// Of M[7:4], they say M[7:6] are reserved (set to zero), and bits M[3:0]
// are don't care (we HiZ). Only M[5:4] are used, and they must be set
// to M[5:4] = 2'b10 to enable continuous read mode.
// ----------------------------------------------------------------------------
.equ W25X10CL_MODE_CONTINUOUS_READ, 0x20
// ----------------------------------------------------------------------------
// Start of 2nd Stage Boot Code
// ----------------------------------------------------------------------------
.org 0
.section .text
// lr will be zero on entry if entered from the bootrom, and the boot_stage2 is expected
// to continue into the binary via the vector table at 0x10000100.
//
// lr will be non-zero on entry if this code has been copied into RAM by user code and called
// from there, and the boot_stage2 should just return normally.
//
// r3 holds SSI base, r0...2 used as temporaries. Other GPRs not used.
regular_func _stage2_boot
push {lr}
ldr r3, =XIP_SSI_BASE // Use as base address where possible
// We are primarily interested in setting up Flash for DSPI XIP w/ continuous read
movs r1, #0
str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI to allow further config
// The Boot ROM sets a very conservative SPI clock frequency to be sure it can
// read the initial 256 bytes from any device. Here we can be more aggressive.
movs r1, #PICO_FLASH_SPI_CLKDIV
str r1, [r3, #SSI_BAUDR_OFFSET] // Set SSI Clock
// First we need to send the initial command to get us in to Fast Read Dual I/O
// mode. As this transaction requires a command, we can't send it in XIP mode.
// To enter Continuous Read mode as well we need to append 4'b0010 to the address
// bits and then add a further 4 don't care bits. We will construct this by
// specifying a 28-bit address, with the least significant bits being 4'b0010.
// This is just a dummy transaction so we'll perform a read from address zero
// and then discard what comes back. All we really care about is that at the
// end of the transaction, the Winbond W25X10CL device is in Continuous Read mode
// and from then on will only expect to receive addresses.
#define CTRLR0_ENTER_XIP \
(SSI_CTRLR0_SPI_FRF_VALUE_DUAL /* Dual I/O mode */ \
<< SSI_CTRLR0_SPI_FRF_LSB) | \
(31 << SSI_CTRLR0_DFS_32_LSB) | /* 32 data bits */ \
(SSI_CTRLR0_TMOD_VALUE_EEPROM_READ /* Send INST/ADDR, Receive Data */ \
<< SSI_CTRLR0_TMOD_LSB)
ldr r1, =(CTRLR0_ENTER_XIP)
str r1, [r3, #SSI_CTRLR0_OFFSET]
movs r1, #0x0 // NDF=0 (single 32b read)
str r1, [r3, #SSI_CTRLR1_OFFSET]
#define SPI_CTRLR0_ENTER_XIP \
(7 << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Send 28 bits (24 address + 4 mode) */ \
(2 << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z the other 4 mode bits (2 cycles @ dual I/O = 4 bits) */ \
(SSI_SPI_CTRLR0_INST_L_VALUE_8B \
<< SSI_SPI_CTRLR0_INST_L_LSB) | /* 8-bit instruction */ \
(SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_1C2A /* Send Command in serial mode then address in Dual I/O mode */ \
<< SSI_SPI_CTRLR0_TRANS_TYPE_LSB)
ldr r1, =(SPI_CTRLR0_ENTER_XIP)
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET) // SPI_CTRL0 Register
str r1, [r0]
movs r1, #1 // Re-enable SSI
str r1, [r3, #SSI_SSIENR_OFFSET]
movs r1, #W25X10CL_CMD_READ_DATA_FAST_DUAL_IO // 8b command = 0xBB
str r1, [r3, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO
movs r1, #0x0000002 // 28-bit Address for dummy read = 0x000000 + 0x2 Mode bits to set M[5:4]=10
str r1, [r3, #SSI_DR0_OFFSET] // Push Address into TX FIFO - this will trigger the transaction
// Now we wait for the read transaction to complete by monitoring the SSI
// status register and checking for the "RX FIFO Not Empty" flag to assert.
movs r1, #SSI_SR_RFNE_BITS
00:
ldr r0, [r3, #SSI_SR_OFFSET] // Read status register
tst r0, r1 // RFNE status flag set?
beq 00b // If not then wait
// At this point CN# will be deasserted and the SPI clock will not be running.
// The Winbond WX25X10CL device will be in continuous read, dual I/O mode and
// only expecting address bits after the next CN# assertion. So long as we
// send 4'b0010 (and 4 more dummy HiZ bits) after every subsequent 24b address
// then the Winbond device will remain in continuous read mode. This is the
// ideal mode for Execute-In-Place.
// (If we want to exit continuous read mode then we will need to switch back
// to APM mode and generate a 28-bit address phase with the extra nibble set
// to 4'b0000).
movs r1, #0
str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config
// Note that the INST_L field is used to select what XIP data gets pushed into
// the TX FIFO:
// INST_L_0_BITS {ADDR[23:0],XIP_CMD[7:0]} Load "mode bits" into XIP_CMD
// Anything else {XIP_CMD[7:0],ADDR[23:0]} Load SPI command into XIP_CMD
#define SPI_CTRLR0_XIP \
(W25X10CL_MODE_CONTINUOUS_READ /* Mode bits to keep Winbond in continuous read mode */ \
<< SSI_SPI_CTRLR0_XIP_CMD_LSB) | \
(7 << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Send 28 bits (24 address + 4 mode) */ \
(2 << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z the other 4 mode bits (2 cycles @ dual I/O = 4 bits) */ \
(SSI_SPI_CTRLR0_INST_L_VALUE_NONE /* Do not send a command, instead send XIP_CMD as mode bits after address */ \
<< SSI_SPI_CTRLR0_INST_L_LSB) | \
(SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_2C2A /* Send Address in Dual I/O mode (and Command but that is zero bits long) */ \
<< SSI_SPI_CTRLR0_TRANS_TYPE_LSB)
ldr r1, =(SPI_CTRLR0_XIP)
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET)
str r1, [r0]
movs r1, #1
str r1, [r3, #SSI_SSIENR_OFFSET] // Re-enable SSI
// We are now in XIP mode, with all transactions using Dual I/O and only
// needing to send 24-bit addresses (plus mode bits) for each read transaction.
// Pull in standard exit routine
#include "boot2_helpers/exit_from_boot2.S"
.global literals
literals:
.ltorg
.end

View file

@ -1,13 +0,0 @@
MEMORY {
/* We are loaded to the top 256 bytes of SRAM, which is above the bootrom
stack. Note 4 bytes occupied by checksum. */
SRAM(rx) : ORIGIN = 0x20041f00, LENGTH = 252
}
SECTIONS {
. = ORIGIN(SRAM);
.text : {
*(.entry)
*(.text)
} >SRAM
}

View file

@ -1,19 +0,0 @@
// ----------------------------------------------------------------------------
// Second stage boot code
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
// SPDX-License-Identifier: BSD-3-Clause
// ----------------------------------------------------------------------------
//
// This implementation uses the PICO_BOOT_STAGE2_CHOOSE_ preprocessor defines to pick
// amongst a menu of known boot stage 2 implementations, allowing the board
// configuration header to be able to specify the boot stage 2
#include "boot_stage2/config.h"
#ifdef PICO_BUILD_BOOT_STAGE2_NAME
// boot stage 2 is configured by cmake, so use the name specified there
#error PICO_BUILD_BOOT_STAGE2_NAME should not be defined for compile_time_choice builds
#else
// boot stage 2 is selected by board config header, and PICO_BOOT_STAGE2_ASM is set in boot_stage2/config.h
#include PICO_BOOT_STAGE2_ASM
#endif

View file

@ -1,4 +0,0 @@
/**
* \defgroup boot_stage2 boot_stage2
* \brief Second stage boot loaders responsible for setting up external flash
*/

View file

@ -1,91 +0,0 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _BOOT_STAGE2_CONFIG_H
#define _BOOT_STAGE2_CONFIG_H
// NOTE THIS HEADER IS INCLUDED FROM ASSEMBLY
#include "pico.h"
// PICO_CONFIG: PICO_BUILD_BOOT_STAGE2_NAME, Name of the boot stage 2 if selected in the build system, group=boot_stage2
#ifdef PICO_BUILD_BOOT_STAGE2_NAME
#define _BOOT_STAGE2_SELECTED
#else
// check that multiple boot stage 2 options haven't been set...
// PICO_CONFIG: PICO_BOOT_STAGE2_CHOOSE_IS25LP080, Select boot2_is25lp080 as the boot stage 2 when no boot stage 2 selection is made by the CMake build, type=bool, default=0, group=boot_stage2
#ifndef PICO_BOOT_STAGE2_CHOOSE_IS25LP080
#define PICO_BOOT_STAGE2_CHOOSE_IS25LP080 0
#elif PICO_BOOT_STAGE2_CHOOSE_IS25LP080
#ifdef _BOOT_STAGE2_SELECTED
#error multiple boot stage 2 options chosen
#endif
#define _BOOT_STAGE2_SELECTED
#endif
// PICO_CONFIG: PICO_BOOT_STAGE2_CHOOSE_W25Q080, Select boot2_w25q080 as the boot stage 2 when no boot stage 2 selection is made by the CMake build, type=bool, default=0, group=boot_stage2
#ifndef PICO_BOOT_STAGE2_CHOOSE_W25Q080
#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 0
#elif PICO_BOOT_STAGE2_CHOOSE_W25Q080
#ifdef _BOOT_STAGE2_SELECTED
#error multiple boot stage 2 options chosen
#endif
#define _BOOT_STAGE2_SELECTED
#endif
// PICO_CONFIG: PICO_BOOT_STAGE2_CHOOSE_W25X10CL, Select boot2_w25x10cl as the boot stage 2 when no boot stage 2 selection is made by the CMake build, type=bool, default=0, group=boot_stage2
#ifndef PICO_BOOT_STAGE2_CHOOSE_W25X10CL
#define PICO_BOOT_STAGE2_CHOOSE_W25X10CL 0
#elif PICO_BOOT_STAGE2_CHOOSE_W25X10CL
#ifdef _BOOT_STAGE2_SELECTED
#error multiple boot stage 2 options chosen
#endif
#define _BOOT_STAGE2_SELECTED
#endif
// PICO_CONFIG: PICO_BOOT_STAGE2_CHOOSE_AT25SF128A, Select boot2_at25sf128a as the boot stage 2 when no boot stage 2 selection is made by the CMake build, type=bool, default=0, group=boot_stage2
#ifndef PICO_BOOT_STAGE2_CHOOSE_AT25SF128A
#define PICO_BOOT_STAGE2_CHOOSE_AT25SF128A 0
#elif PICO_BOOT_STAGE2_CHOOSE_AT25SF128A
#ifdef _BOOT_STAGE2_SELECTED
#error multiple boot stage 2 options chosen
#endif
#define _BOOT_STAGE2_SELECTED
#endif
// PICO_CONFIG: PICO_BOOT_STAGE2_CHOOSE_GENERIC_03H, Select boot2_generic_03h as the boot stage 2 when no boot stage 2 selection is made by the CMake build, type=bool, default=1, group=boot_stage2
#if defined(PICO_BOOT_STAGE2_CHOOSE_GENERIC_03H) && PICO_BOOT_STAGE2_CHOOSE_GENERIC_03H
#ifdef _BOOT_STAGE2_SELECTED
#error multiple boot stage 2 options chosen
#endif
#define _BOOT_STAGE2_SELECTED
#endif
#endif // PICO_BUILD_BOOT_STAGE2_NAME
#ifdef PICO_BUILD_BOOT_STAGE2_NAME
// boot stage 2 is configured by cmake, so use the name specified there
#define PICO_BOOT_STAGE2_NAME PICO_BUILD_BOOT_STAGE2_NAME
#else
// boot stage 2 is selected by board config header, so we have to do some work
#if PICO_BOOT_STAGE2_CHOOSE_IS25LP080
#define _BOOT_STAGE2 boot2_is25lp080
#elif PICO_BOOT_STAGE2_CHOOSE_W25Q080
#define _BOOT_STAGE2 boot2_w25q080
#elif PICO_BOOT_STAGE2_CHOOSE_W25X10CL
#define _BOOT_STAGE2 boot2_w25x10cl
#elif PICO_BOOT_STAGE2_CHOOSE_AT25SF128A
#define _BOOT_STAGE2 boot2_at25sf128a
#elif !defined(PICO_BOOT_STAGE2_CHOOSE_GENERIC_03H) || PICO_BOOT_STAGE2_CHOOSE_GENERIC_03H
#undef PICO_BOOT_STAGE2_CHOOSE_GENERIC_03H
#define PICO_BOOT_STAGE2_CHOOSE_GENERIC_03H 1
#define _BOOT_STAGE2 boot2_generic_03h
#else
#error no boot stage 2 is defined by PICO_BOOT_STAGE2_CHOOSE_ macro
#endif
// we can't include cdefs in assembly, so define our own, but avoid conflict with real ones for c inclusion
#define PICO_BOOT_STAGE2_NAME __PICO_XSTRING(_BOOT_STAGE2)
#define PICO_BOOT_STAGE2_ASM __PICO_XSTRING(__PICO_CONCAT1(_BOOT_STAGE2,.S))
#endif
#endif

View file

@ -1,55 +0,0 @@
#!/usr/bin/env python3
import argparse
import binascii
import struct
import sys
def any_int(x):
try:
return int(x, 0)
except:
raise argparse.ArgumentTypeError("expected an integer, not '{!r}'".format(x))
def bitrev(x, width):
return int("{:0{w}b}".format(x, w=width)[::-1], 2)
parser = argparse.ArgumentParser()
parser.add_argument("ifile", help="Input file (binary)")
parser.add_argument("ofile", help="Output file (assembly)")
parser.add_argument("-p", "--pad", help="Padded size (bytes), including 4-byte checksum, default 256",
type=any_int, default=256)
parser.add_argument("-s", "--seed", help="Checksum seed value, default 0",
type=any_int, default=0)
args = parser.parse_args()
try:
idata = open(args.ifile, "rb").read()
except:
sys.exit("Could not open input file '{}'".format(args.ifile))
if len(idata) > args.pad - 4:
sys.exit("Input file size ({} bytes) too large for final size ({} bytes)".format(len(idata), args.pad))
idata_padded = idata + bytes(args.pad - 4 - len(idata))
# Our bootrom CRC32 is slightly bass-ackward but it's best to work around for now (FIXME)
# 100% worth it to save two Thumb instructions
checksum = bitrev(
(binascii.crc32(bytes(bitrev(b, 8) for b in idata_padded), args.seed ^ 0xffffffff) ^ 0xffffffff) & 0xffffffff, 32)
odata = idata_padded + struct.pack("<L", checksum)
try:
with open(args.ofile, "w") as ofile:
ofile.write("// Padded and checksummed version of: {}\n\n".format(args.ifile))
ofile.write(".cpu cortex-m0plus\n")
ofile.write(".thumb\n\n")
ofile.write(".section .boot2, \"ax\"\n\n")
for offs in range(0, len(odata), 16):
chunk = odata[offs:min(offs + 16, len(odata))]
ofile.write(".byte {}\n".format(", ".join("0x{:02x}".format(b) for b in chunk)))
except:
sys.exit("Could not open output file '{}'".format(args.ofile))

File diff suppressed because it is too large Load diff

View file

@ -1,119 +0,0 @@
/*
* Copyright (c) 2024 Raspberry Pi Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_PLATFORM_DEFS_H
#define _HARDWARE_PLATFORM_DEFS_H
// This header is included from C and assembler - intended mostly for #defines; guard other stuff with #ifdef __ASSEMBLER__
#ifndef _u
#ifdef __ASSEMBLER__
#define _u(x) x
#else
#define _u(x) x ## u
#endif
#endif
#define NUM_CORES _u(2)
#define NUM_DMA_CHANNELS _u(12)
#define NUM_DMA_TIMERS _u(4)
#define NUM_DMA_IRQS _u(2)
#define NUM_IRQS _u(32)
#define NUM_USER_IRQS _u(6)
#define NUM_PIOS _u(2)
#define NUM_PIO_STATE_MACHINES _u(4)
#define NUM_PIO_IRQS _u(2)
#define NUM_PWM_SLICES _u(8)
#define NUM_PWM_IRQS _u(1)
#define NUM_SPIN_LOCKS _u(32)
#define NUM_UARTS _u(2)
#define NUM_I2CS _u(2)
#define NUM_SPIS _u(2)
#define NUM_GENERIC_TIMERS _u(1)
#define NUM_ALARMS _u(4)
#define ADC_BASE_PIN _u(26)
#define NUM_ADC_CHANNELS _u(5)
#define NUM_RESETS _u(24)
#define NUM_BANK0_GPIOS _u(30)
#define NUM_QSPI_GPIOS _u(6)
#define PIO_INSTRUCTION_COUNT _u(32)
#define USBCTRL_DPRAM_SIZE _u(4096)
#define HAS_SIO_DIVIDER 1
#define HAS_RP2040_RTC 1
// PICO_CONFIG: XOSC_HZ, Crystal oscillator frequency in Hz, type=int, default=12000000, advanced=true, group=hardware_base
// NOTE: The system and USB clocks are generated from the frequency using two PLLs.
// If you override this define, or SYS_CLK_HZ/USB_CLK_HZ below, you will *also* need to add your own adjusted PLL set-up defines to
// override the defaults which live in src/rp2_common/hardware_clocks/include/hardware/clocks.h
// Please see the comments there about calculating the new PLL setting values.
#ifndef XOSC_HZ
#ifdef XOSC_KHZ
#define XOSC_HZ ((XOSC_KHZ) * _u(1000))
#elif defined(XOSC_MHZ)
#define XOSC_HZ ((XOSC_MHZ) * _u(1000000))
#else
#define XOSC_HZ _u(12000000)
#endif
#endif
// PICO_CONFIG: SYS_CLK_HZ, System operating frequency in Hz, type=int, default=125000000, advanced=true, group=hardware_base
#ifndef SYS_CLK_HZ
#ifdef SYS_CLK_KHZ
#define SYS_CLK_HZ ((SYS_CLK_KHZ) * _u(1000))
#elif defined(SYS_CLK_MHZ)
#define SYS_CLK_HZ ((SYS_CLK_MHZ) * _u(1000000))
#else
#define SYS_CLK_HZ _u(125000000)
#endif
#endif
// PICO_CONFIG: USB_CLK_HZ, USB clock frequency. Must be 48MHz for the USB interface to operate correctly, type=int, default=48000000, advanced=true, group=hardware_base
#ifndef USB_CLK_HZ
#ifdef USB_CLK_KHZ
#define USB_CLK_HZ ((USB_CLK_KHZ) * _u(1000))
#elif defined(USB_CLK_MHZ)
#define USB_CLK_HZ ((USB_CLK_MHZ) * _u(1000000))
#else
#define USB_CLK_HZ _u(48000000)
#endif
#endif
// For backwards compatibility define XOSC_KHZ if the frequency is indeed an integer number of Khz.
#if defined(XOSC_HZ) && !defined(XOSC_KHZ) && (XOSC_HZ % 1000 == 0)
#define XOSC_KHZ (XOSC_HZ / 1000)
#endif
// For backwards compatibility define XOSC_MHZ if the frequency is indeed an integer number of Mhz.
#if defined(XOSC_KHZ) && !defined(XOSC_MHZ) && (XOSC_KHZ % 1000 == 0)
#define XOSC_MHZ (XOSC_KHZ / 1000)
#endif
// For backwards compatibility define SYS_CLK_KHZ if the frequency is indeed an integer number of Khz.
#if defined(SYS_CLK_HZ) && !defined(SYS_CLK_KHZ) && (SYS_CLK_HZ % 1000 == 0)
#define SYS_CLK_KHZ (SYS_CLK_HZ / 1000)
#endif
// For backwards compatibility define SYS_CLK_MHZ if the frequency is indeed an integer number of Mhz.
#if defined(SYS_CLK_KHZ) && !defined(SYS_CLK_MHZ) && (SYS_CLK_KHZ % 1000 == 0)
#define SYS_CLK_MHZ (SYS_CLK_KHZ / 1000)
#endif
// For backwards compatibility define USB_CLK_KHZ if the frequency is indeed an integer number of Khz.
#if defined(USB_CLK_HZ) && !defined(USB_CLK_KHZ) && (USB_CLK_HZ % 1000 == 0)
#define USB_CLK_KHZ (USB_CLK_HZ / 1000)
#endif
// For backwards compatibility define USB_CLK_MHZ if the frequency is indeed an integer number of Mhz.
#if defined(USB_CLK_KHZ) && !defined(USB_CLK_MHZ) && (USB_CLK_KHZ % 1000 == 0)
#define USB_CLK_MHZ (USB_CLK_KHZ / 1000)
#endif
#define FIRST_USER_IRQ (NUM_IRQS - NUM_USER_IRQS)
#define VTABLE_FIRST_IRQ 16
#endif

View file

@ -1,314 +0,0 @@
// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
/**
* Copyright (c) 2024 Raspberry Pi Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// =============================================================================
// Register block : ADC
// Version : 2
// Bus type : apb
// Description : Control and data interface to SAR ADC
// =============================================================================
#ifndef _HARDWARE_REGS_ADC_H
#define _HARDWARE_REGS_ADC_H
// =============================================================================
// Register : ADC_CS
// Description : ADC Control and Status
#define ADC_CS_OFFSET _u(0x00000000)
#define ADC_CS_BITS _u(0x001f770f)
#define ADC_CS_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : ADC_CS_RROBIN
// Description : Round-robin sampling. 1 bit per channel. Set all bits to 0 to
// disable.
// Otherwise, the ADC will cycle through each enabled channel in a
// round-robin fashion.
// The first channel to be sampled will be the one currently
// indicated by AINSEL.
// AINSEL will be updated after each conversion with the newly-
// selected channel.
#define ADC_CS_RROBIN_RESET _u(0x00)
#define ADC_CS_RROBIN_BITS _u(0x001f0000)
#define ADC_CS_RROBIN_MSB _u(20)
#define ADC_CS_RROBIN_LSB _u(16)
#define ADC_CS_RROBIN_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : ADC_CS_AINSEL
// Description : Select analog mux input. Updated automatically in round-robin
// mode.
#define ADC_CS_AINSEL_RESET _u(0x0)
#define ADC_CS_AINSEL_BITS _u(0x00007000)
#define ADC_CS_AINSEL_MSB _u(14)
#define ADC_CS_AINSEL_LSB _u(12)
#define ADC_CS_AINSEL_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : ADC_CS_ERR_STICKY
// Description : Some past ADC conversion encountered an error. Write 1 to
// clear.
#define ADC_CS_ERR_STICKY_RESET _u(0x0)
#define ADC_CS_ERR_STICKY_BITS _u(0x00000400)
#define ADC_CS_ERR_STICKY_MSB _u(10)
#define ADC_CS_ERR_STICKY_LSB _u(10)
#define ADC_CS_ERR_STICKY_ACCESS "WC"
// -----------------------------------------------------------------------------
// Field : ADC_CS_ERR
// Description : The most recent ADC conversion encountered an error; result is
// undefined or noisy.
#define ADC_CS_ERR_RESET _u(0x0)
#define ADC_CS_ERR_BITS _u(0x00000200)
#define ADC_CS_ERR_MSB _u(9)
#define ADC_CS_ERR_LSB _u(9)
#define ADC_CS_ERR_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : ADC_CS_READY
// Description : 1 if the ADC is ready to start a new conversion. Implies any
// previous conversion has completed.
// 0 whilst conversion in progress.
#define ADC_CS_READY_RESET _u(0x0)
#define ADC_CS_READY_BITS _u(0x00000100)
#define ADC_CS_READY_MSB _u(8)
#define ADC_CS_READY_LSB _u(8)
#define ADC_CS_READY_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : ADC_CS_START_MANY
// Description : Continuously perform conversions whilst this bit is 1. A new
// conversion will start immediately after the previous finishes.
#define ADC_CS_START_MANY_RESET _u(0x0)
#define ADC_CS_START_MANY_BITS _u(0x00000008)
#define ADC_CS_START_MANY_MSB _u(3)
#define ADC_CS_START_MANY_LSB _u(3)
#define ADC_CS_START_MANY_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : ADC_CS_START_ONCE
// Description : Start a single conversion. Self-clearing. Ignored if start_many
// is asserted.
#define ADC_CS_START_ONCE_RESET _u(0x0)
#define ADC_CS_START_ONCE_BITS _u(0x00000004)
#define ADC_CS_START_ONCE_MSB _u(2)
#define ADC_CS_START_ONCE_LSB _u(2)
#define ADC_CS_START_ONCE_ACCESS "SC"
// -----------------------------------------------------------------------------
// Field : ADC_CS_TS_EN
// Description : Power on temperature sensor. 1 - enabled. 0 - disabled.
#define ADC_CS_TS_EN_RESET _u(0x0)
#define ADC_CS_TS_EN_BITS _u(0x00000002)
#define ADC_CS_TS_EN_MSB _u(1)
#define ADC_CS_TS_EN_LSB _u(1)
#define ADC_CS_TS_EN_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : ADC_CS_EN
// Description : Power on ADC and enable its clock.
// 1 - enabled. 0 - disabled.
#define ADC_CS_EN_RESET _u(0x0)
#define ADC_CS_EN_BITS _u(0x00000001)
#define ADC_CS_EN_MSB _u(0)
#define ADC_CS_EN_LSB _u(0)
#define ADC_CS_EN_ACCESS "RW"
// =============================================================================
// Register : ADC_RESULT
// Description : Result of most recent ADC conversion
#define ADC_RESULT_OFFSET _u(0x00000004)
#define ADC_RESULT_BITS _u(0x00000fff)
#define ADC_RESULT_RESET _u(0x00000000)
#define ADC_RESULT_MSB _u(11)
#define ADC_RESULT_LSB _u(0)
#define ADC_RESULT_ACCESS "RO"
// =============================================================================
// Register : ADC_FCS
// Description : FIFO control and status
#define ADC_FCS_OFFSET _u(0x00000008)
#define ADC_FCS_BITS _u(0x0f0f0f0f)
#define ADC_FCS_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : ADC_FCS_THRESH
// Description : DREQ/IRQ asserted when level >= threshold
#define ADC_FCS_THRESH_RESET _u(0x0)
#define ADC_FCS_THRESH_BITS _u(0x0f000000)
#define ADC_FCS_THRESH_MSB _u(27)
#define ADC_FCS_THRESH_LSB _u(24)
#define ADC_FCS_THRESH_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : ADC_FCS_LEVEL
// Description : The number of conversion results currently waiting in the FIFO
#define ADC_FCS_LEVEL_RESET _u(0x0)
#define ADC_FCS_LEVEL_BITS _u(0x000f0000)
#define ADC_FCS_LEVEL_MSB _u(19)
#define ADC_FCS_LEVEL_LSB _u(16)
#define ADC_FCS_LEVEL_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : ADC_FCS_OVER
// Description : 1 if the FIFO has been overflowed. Write 1 to clear.
#define ADC_FCS_OVER_RESET _u(0x0)
#define ADC_FCS_OVER_BITS _u(0x00000800)
#define ADC_FCS_OVER_MSB _u(11)
#define ADC_FCS_OVER_LSB _u(11)
#define ADC_FCS_OVER_ACCESS "WC"
// -----------------------------------------------------------------------------
// Field : ADC_FCS_UNDER
// Description : 1 if the FIFO has been underflowed. Write 1 to clear.
#define ADC_FCS_UNDER_RESET _u(0x0)
#define ADC_FCS_UNDER_BITS _u(0x00000400)
#define ADC_FCS_UNDER_MSB _u(10)
#define ADC_FCS_UNDER_LSB _u(10)
#define ADC_FCS_UNDER_ACCESS "WC"
// -----------------------------------------------------------------------------
// Field : ADC_FCS_FULL
#define ADC_FCS_FULL_RESET _u(0x0)
#define ADC_FCS_FULL_BITS _u(0x00000200)
#define ADC_FCS_FULL_MSB _u(9)
#define ADC_FCS_FULL_LSB _u(9)
#define ADC_FCS_FULL_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : ADC_FCS_EMPTY
#define ADC_FCS_EMPTY_RESET _u(0x0)
#define ADC_FCS_EMPTY_BITS _u(0x00000100)
#define ADC_FCS_EMPTY_MSB _u(8)
#define ADC_FCS_EMPTY_LSB _u(8)
#define ADC_FCS_EMPTY_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : ADC_FCS_DREQ_EN
// Description : If 1: assert DMA requests when FIFO contains data
#define ADC_FCS_DREQ_EN_RESET _u(0x0)
#define ADC_FCS_DREQ_EN_BITS _u(0x00000008)
#define ADC_FCS_DREQ_EN_MSB _u(3)
#define ADC_FCS_DREQ_EN_LSB _u(3)
#define ADC_FCS_DREQ_EN_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : ADC_FCS_ERR
// Description : If 1: conversion error bit appears in the FIFO alongside the
// result
#define ADC_FCS_ERR_RESET _u(0x0)
#define ADC_FCS_ERR_BITS _u(0x00000004)
#define ADC_FCS_ERR_MSB _u(2)
#define ADC_FCS_ERR_LSB _u(2)
#define ADC_FCS_ERR_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : ADC_FCS_SHIFT
// Description : If 1: FIFO results are right-shifted to be one byte in size.
// Enables DMA to byte buffers.
#define ADC_FCS_SHIFT_RESET _u(0x0)
#define ADC_FCS_SHIFT_BITS _u(0x00000002)
#define ADC_FCS_SHIFT_MSB _u(1)
#define ADC_FCS_SHIFT_LSB _u(1)
#define ADC_FCS_SHIFT_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : ADC_FCS_EN
// Description : If 1: write result to the FIFO after each conversion.
#define ADC_FCS_EN_RESET _u(0x0)
#define ADC_FCS_EN_BITS _u(0x00000001)
#define ADC_FCS_EN_MSB _u(0)
#define ADC_FCS_EN_LSB _u(0)
#define ADC_FCS_EN_ACCESS "RW"
// =============================================================================
// Register : ADC_FIFO
// Description : Conversion result FIFO
#define ADC_FIFO_OFFSET _u(0x0000000c)
#define ADC_FIFO_BITS _u(0x00008fff)
#define ADC_FIFO_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : ADC_FIFO_ERR
// Description : 1 if this particular sample experienced a conversion error.
// Remains in the same location if the sample is shifted.
#define ADC_FIFO_ERR_RESET "-"
#define ADC_FIFO_ERR_BITS _u(0x00008000)
#define ADC_FIFO_ERR_MSB _u(15)
#define ADC_FIFO_ERR_LSB _u(15)
#define ADC_FIFO_ERR_ACCESS "RF"
// -----------------------------------------------------------------------------
// Field : ADC_FIFO_VAL
#define ADC_FIFO_VAL_RESET "-"
#define ADC_FIFO_VAL_BITS _u(0x00000fff)
#define ADC_FIFO_VAL_MSB _u(11)
#define ADC_FIFO_VAL_LSB _u(0)
#define ADC_FIFO_VAL_ACCESS "RF"
// =============================================================================
// Register : ADC_DIV
// Description : Clock divider. If non-zero, CS_START_MANY will start
// conversions
// at regular intervals rather than back-to-back.
// The divider is reset when either of these fields are written.
// Total period is 1 + INT + FRAC / 256
#define ADC_DIV_OFFSET _u(0x00000010)
#define ADC_DIV_BITS _u(0x00ffffff)
#define ADC_DIV_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : ADC_DIV_INT
// Description : Integer part of clock divisor.
#define ADC_DIV_INT_RESET _u(0x0000)
#define ADC_DIV_INT_BITS _u(0x00ffff00)
#define ADC_DIV_INT_MSB _u(23)
#define ADC_DIV_INT_LSB _u(8)
#define ADC_DIV_INT_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : ADC_DIV_FRAC
// Description : Fractional part of clock divisor. First-order delta-sigma.
#define ADC_DIV_FRAC_RESET _u(0x00)
#define ADC_DIV_FRAC_BITS _u(0x000000ff)
#define ADC_DIV_FRAC_MSB _u(7)
#define ADC_DIV_FRAC_LSB _u(0)
#define ADC_DIV_FRAC_ACCESS "RW"
// =============================================================================
// Register : ADC_INTR
// Description : Raw Interrupts
#define ADC_INTR_OFFSET _u(0x00000014)
#define ADC_INTR_BITS _u(0x00000001)
#define ADC_INTR_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : ADC_INTR_FIFO
// Description : Triggered when the sample FIFO reaches a certain level.
// This level can be programmed via the FCS_THRESH field.
#define ADC_INTR_FIFO_RESET _u(0x0)
#define ADC_INTR_FIFO_BITS _u(0x00000001)
#define ADC_INTR_FIFO_MSB _u(0)
#define ADC_INTR_FIFO_LSB _u(0)
#define ADC_INTR_FIFO_ACCESS "RO"
// =============================================================================
// Register : ADC_INTE
// Description : Interrupt Enable
#define ADC_INTE_OFFSET _u(0x00000018)
#define ADC_INTE_BITS _u(0x00000001)
#define ADC_INTE_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : ADC_INTE_FIFO
// Description : Triggered when the sample FIFO reaches a certain level.
// This level can be programmed via the FCS_THRESH field.
#define ADC_INTE_FIFO_RESET _u(0x0)
#define ADC_INTE_FIFO_BITS _u(0x00000001)
#define ADC_INTE_FIFO_MSB _u(0)
#define ADC_INTE_FIFO_LSB _u(0)
#define ADC_INTE_FIFO_ACCESS "RW"
// =============================================================================
// Register : ADC_INTF
// Description : Interrupt Force
#define ADC_INTF_OFFSET _u(0x0000001c)
#define ADC_INTF_BITS _u(0x00000001)
#define ADC_INTF_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : ADC_INTF_FIFO
// Description : Triggered when the sample FIFO reaches a certain level.
// This level can be programmed via the FCS_THRESH field.
#define ADC_INTF_FIFO_RESET _u(0x0)
#define ADC_INTF_FIFO_BITS _u(0x00000001)
#define ADC_INTF_FIFO_MSB _u(0)
#define ADC_INTF_FIFO_LSB _u(0)
#define ADC_INTF_FIFO_ACCESS "RW"
// =============================================================================
// Register : ADC_INTS
// Description : Interrupt status after masking & forcing
#define ADC_INTS_OFFSET _u(0x00000020)
#define ADC_INTS_BITS _u(0x00000001)
#define ADC_INTS_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : ADC_INTS_FIFO
// Description : Triggered when the sample FIFO reaches a certain level.
// This level can be programmed via the FCS_THRESH field.
#define ADC_INTS_FIFO_RESET _u(0x0)
#define ADC_INTS_FIFO_BITS _u(0x00000001)
#define ADC_INTS_FIFO_MSB _u(0)
#define ADC_INTS_FIFO_LSB _u(0)
#define ADC_INTS_FIFO_ACCESS "RO"
// =============================================================================
#endif // _HARDWARE_REGS_ADC_H

View file

@ -1,81 +0,0 @@
// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
/**
* Copyright (c) 2024 Raspberry Pi Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _ADDRESSMAP_H
#define _ADDRESSMAP_H
/**
* \file rp2040/addressmap.h
*/
#include "hardware/platform_defs.h"
// Register address offsets for atomic RMW aliases
#define REG_ALIAS_RW_BITS (_u(0x0) << _u(12))
#define REG_ALIAS_XOR_BITS (_u(0x1) << _u(12))
#define REG_ALIAS_SET_BITS (_u(0x2) << _u(12))
#define REG_ALIAS_CLR_BITS (_u(0x3) << _u(12))
#define ROM_BASE _u(0x00000000)
#define XIP_BASE _u(0x10000000)
#define XIP_MAIN_BASE _u(0x10000000)
#define XIP_NOALLOC_BASE _u(0x11000000)
#define XIP_NOCACHE_BASE _u(0x12000000)
#define XIP_NOCACHE_NOALLOC_BASE _u(0x13000000)
#define XIP_CTRL_BASE _u(0x14000000)
#define XIP_SRAM_BASE _u(0x15000000)
#define XIP_SRAM_END _u(0x15004000)
#define XIP_SSI_BASE _u(0x18000000)
#define SRAM_BASE _u(0x20000000)
#define SRAM_STRIPED_BASE _u(0x20000000)
#define SRAM_STRIPED_END _u(0x20040000)
#define SRAM4_BASE _u(0x20040000)
#define SRAM5_BASE _u(0x20041000)
#define SRAM_END _u(0x20042000)
#define SRAM0_BASE _u(0x21000000)
#define SRAM1_BASE _u(0x21010000)
#define SRAM2_BASE _u(0x21020000)
#define SRAM3_BASE _u(0x21030000)
#define SYSINFO_BASE _u(0x40000000)
#define SYSCFG_BASE _u(0x40004000)
#define CLOCKS_BASE _u(0x40008000)
#define RESETS_BASE _u(0x4000c000)
#define PSM_BASE _u(0x40010000)
#define IO_BANK0_BASE _u(0x40014000)
#define IO_QSPI_BASE _u(0x40018000)
#define PADS_BANK0_BASE _u(0x4001c000)
#define PADS_QSPI_BASE _u(0x40020000)
#define XOSC_BASE _u(0x40024000)
#define PLL_SYS_BASE _u(0x40028000)
#define PLL_USB_BASE _u(0x4002c000)
#define BUSCTRL_BASE _u(0x40030000)
#define UART0_BASE _u(0x40034000)
#define UART1_BASE _u(0x40038000)
#define SPI0_BASE _u(0x4003c000)
#define SPI1_BASE _u(0x40040000)
#define I2C0_BASE _u(0x40044000)
#define I2C1_BASE _u(0x40048000)
#define ADC_BASE _u(0x4004c000)
#define PWM_BASE _u(0x40050000)
#define TIMER_BASE _u(0x40054000)
#define WATCHDOG_BASE _u(0x40058000)
#define RTC_BASE _u(0x4005c000)
#define ROSC_BASE _u(0x40060000)
#define VREG_AND_CHIP_RESET_BASE _u(0x40064000)
#define TBMAN_BASE _u(0x4006c000)
#define DMA_BASE _u(0x50000000)
#define USBCTRL_DPRAM_BASE _u(0x50100000)
#define USBCTRL_BASE _u(0x50100000)
#define USBCTRL_REGS_BASE _u(0x50110000)
#define PIO0_BASE _u(0x50200000)
#define PIO1_BASE _u(0x50300000)
#define XIP_AUX_BASE _u(0x50400000)
#define SIO_BASE _u(0xd0000000)
#define PPB_BASE _u(0xe0000000)
#endif // _ADDRESSMAP_H

View file

@ -1,327 +0,0 @@
// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
/**
* Copyright (c) 2024 Raspberry Pi Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// =============================================================================
// Register block : BUSCTRL
// Version : 1
// Bus type : apb
// Description : Register block for busfabric control signals and performance
// counters
// =============================================================================
#ifndef _HARDWARE_REGS_BUSCTRL_H
#define _HARDWARE_REGS_BUSCTRL_H
// =============================================================================
// Register : BUSCTRL_BUS_PRIORITY
// Description : Set the priority of each master for bus arbitration.
#define BUSCTRL_BUS_PRIORITY_OFFSET _u(0x00000000)
#define BUSCTRL_BUS_PRIORITY_BITS _u(0x00001111)
#define BUSCTRL_BUS_PRIORITY_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : BUSCTRL_BUS_PRIORITY_DMA_W
// Description : 0 - low priority, 1 - high priority
#define BUSCTRL_BUS_PRIORITY_DMA_W_RESET _u(0x0)
#define BUSCTRL_BUS_PRIORITY_DMA_W_BITS _u(0x00001000)
#define BUSCTRL_BUS_PRIORITY_DMA_W_MSB _u(12)
#define BUSCTRL_BUS_PRIORITY_DMA_W_LSB _u(12)
#define BUSCTRL_BUS_PRIORITY_DMA_W_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : BUSCTRL_BUS_PRIORITY_DMA_R
// Description : 0 - low priority, 1 - high priority
#define BUSCTRL_BUS_PRIORITY_DMA_R_RESET _u(0x0)
#define BUSCTRL_BUS_PRIORITY_DMA_R_BITS _u(0x00000100)
#define BUSCTRL_BUS_PRIORITY_DMA_R_MSB _u(8)
#define BUSCTRL_BUS_PRIORITY_DMA_R_LSB _u(8)
#define BUSCTRL_BUS_PRIORITY_DMA_R_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : BUSCTRL_BUS_PRIORITY_PROC1
// Description : 0 - low priority, 1 - high priority
#define BUSCTRL_BUS_PRIORITY_PROC1_RESET _u(0x0)
#define BUSCTRL_BUS_PRIORITY_PROC1_BITS _u(0x00000010)
#define BUSCTRL_BUS_PRIORITY_PROC1_MSB _u(4)
#define BUSCTRL_BUS_PRIORITY_PROC1_LSB _u(4)
#define BUSCTRL_BUS_PRIORITY_PROC1_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : BUSCTRL_BUS_PRIORITY_PROC0
// Description : 0 - low priority, 1 - high priority
#define BUSCTRL_BUS_PRIORITY_PROC0_RESET _u(0x0)
#define BUSCTRL_BUS_PRIORITY_PROC0_BITS _u(0x00000001)
#define BUSCTRL_BUS_PRIORITY_PROC0_MSB _u(0)
#define BUSCTRL_BUS_PRIORITY_PROC0_LSB _u(0)
#define BUSCTRL_BUS_PRIORITY_PROC0_ACCESS "RW"
// =============================================================================
// Register : BUSCTRL_BUS_PRIORITY_ACK
// Description : Bus priority acknowledge
// Goes to 1 once all arbiters have registered the new global
// priority levels.
// Arbiters update their local priority when servicing a new
// nonsequential access.
// In normal circumstances this will happen almost immediately.
#define BUSCTRL_BUS_PRIORITY_ACK_OFFSET _u(0x00000004)
#define BUSCTRL_BUS_PRIORITY_ACK_BITS _u(0x00000001)
#define BUSCTRL_BUS_PRIORITY_ACK_RESET _u(0x00000000)
#define BUSCTRL_BUS_PRIORITY_ACK_MSB _u(0)
#define BUSCTRL_BUS_PRIORITY_ACK_LSB _u(0)
#define BUSCTRL_BUS_PRIORITY_ACK_ACCESS "RO"
// =============================================================================
// Register : BUSCTRL_PERFCTR0
// Description : Bus fabric performance counter 0
// Busfabric saturating performance counter 0
// Count some event signal from the busfabric arbiters.
// Write any value to clear. Select an event to count using
// PERFSEL0
#define BUSCTRL_PERFCTR0_OFFSET _u(0x00000008)
#define BUSCTRL_PERFCTR0_BITS _u(0x00ffffff)
#define BUSCTRL_PERFCTR0_RESET _u(0x00000000)
#define BUSCTRL_PERFCTR0_MSB _u(23)
#define BUSCTRL_PERFCTR0_LSB _u(0)
#define BUSCTRL_PERFCTR0_ACCESS "WC"
// =============================================================================
// Register : BUSCTRL_PERFSEL0
// Description : Bus fabric performance event select for PERFCTR0
// Select an event for PERFCTR0. Count either contested accesses,
// or all accesses, on a downstream port of the main crossbar.
// 0x00 -> apb_contested
// 0x01 -> apb
// 0x02 -> fastperi_contested
// 0x03 -> fastperi
// 0x04 -> sram5_contested
// 0x05 -> sram5
// 0x06 -> sram4_contested
// 0x07 -> sram4
// 0x08 -> sram3_contested
// 0x09 -> sram3
// 0x0a -> sram2_contested
// 0x0b -> sram2
// 0x0c -> sram1_contested
// 0x0d -> sram1
// 0x0e -> sram0_contested
// 0x0f -> sram0
// 0x10 -> xip_main_contested
// 0x11 -> xip_main
// 0x12 -> rom_contested
// 0x13 -> rom
#define BUSCTRL_PERFSEL0_OFFSET _u(0x0000000c)
#define BUSCTRL_PERFSEL0_BITS _u(0x0000001f)
#define BUSCTRL_PERFSEL0_RESET _u(0x0000001f)
#define BUSCTRL_PERFSEL0_MSB _u(4)
#define BUSCTRL_PERFSEL0_LSB _u(0)
#define BUSCTRL_PERFSEL0_ACCESS "RW"
#define BUSCTRL_PERFSEL0_VALUE_APB_CONTESTED _u(0x00)
#define BUSCTRL_PERFSEL0_VALUE_APB _u(0x01)
#define BUSCTRL_PERFSEL0_VALUE_FASTPERI_CONTESTED _u(0x02)
#define BUSCTRL_PERFSEL0_VALUE_FASTPERI _u(0x03)
#define BUSCTRL_PERFSEL0_VALUE_SRAM5_CONTESTED _u(0x04)
#define BUSCTRL_PERFSEL0_VALUE_SRAM5 _u(0x05)
#define BUSCTRL_PERFSEL0_VALUE_SRAM4_CONTESTED _u(0x06)
#define BUSCTRL_PERFSEL0_VALUE_SRAM4 _u(0x07)
#define BUSCTRL_PERFSEL0_VALUE_SRAM3_CONTESTED _u(0x08)
#define BUSCTRL_PERFSEL0_VALUE_SRAM3 _u(0x09)
#define BUSCTRL_PERFSEL0_VALUE_SRAM2_CONTESTED _u(0x0a)
#define BUSCTRL_PERFSEL0_VALUE_SRAM2 _u(0x0b)
#define BUSCTRL_PERFSEL0_VALUE_SRAM1_CONTESTED _u(0x0c)
#define BUSCTRL_PERFSEL0_VALUE_SRAM1 _u(0x0d)
#define BUSCTRL_PERFSEL0_VALUE_SRAM0_CONTESTED _u(0x0e)
#define BUSCTRL_PERFSEL0_VALUE_SRAM0 _u(0x0f)
#define BUSCTRL_PERFSEL0_VALUE_XIP_MAIN_CONTESTED _u(0x10)
#define BUSCTRL_PERFSEL0_VALUE_XIP_MAIN _u(0x11)
#define BUSCTRL_PERFSEL0_VALUE_ROM_CONTESTED _u(0x12)
#define BUSCTRL_PERFSEL0_VALUE_ROM _u(0x13)
// =============================================================================
// Register : BUSCTRL_PERFCTR1
// Description : Bus fabric performance counter 1
// Busfabric saturating performance counter 1
// Count some event signal from the busfabric arbiters.
// Write any value to clear. Select an event to count using
// PERFSEL1
#define BUSCTRL_PERFCTR1_OFFSET _u(0x00000010)
#define BUSCTRL_PERFCTR1_BITS _u(0x00ffffff)
#define BUSCTRL_PERFCTR1_RESET _u(0x00000000)
#define BUSCTRL_PERFCTR1_MSB _u(23)
#define BUSCTRL_PERFCTR1_LSB _u(0)
#define BUSCTRL_PERFCTR1_ACCESS "WC"
// =============================================================================
// Register : BUSCTRL_PERFSEL1
// Description : Bus fabric performance event select for PERFCTR1
// Select an event for PERFCTR1. Count either contested accesses,
// or all accesses, on a downstream port of the main crossbar.
// 0x00 -> apb_contested
// 0x01 -> apb
// 0x02 -> fastperi_contested
// 0x03 -> fastperi
// 0x04 -> sram5_contested
// 0x05 -> sram5
// 0x06 -> sram4_contested
// 0x07 -> sram4
// 0x08 -> sram3_contested
// 0x09 -> sram3
// 0x0a -> sram2_contested
// 0x0b -> sram2
// 0x0c -> sram1_contested
// 0x0d -> sram1
// 0x0e -> sram0_contested
// 0x0f -> sram0
// 0x10 -> xip_main_contested
// 0x11 -> xip_main
// 0x12 -> rom_contested
// 0x13 -> rom
#define BUSCTRL_PERFSEL1_OFFSET _u(0x00000014)
#define BUSCTRL_PERFSEL1_BITS _u(0x0000001f)
#define BUSCTRL_PERFSEL1_RESET _u(0x0000001f)
#define BUSCTRL_PERFSEL1_MSB _u(4)
#define BUSCTRL_PERFSEL1_LSB _u(0)
#define BUSCTRL_PERFSEL1_ACCESS "RW"
#define BUSCTRL_PERFSEL1_VALUE_APB_CONTESTED _u(0x00)
#define BUSCTRL_PERFSEL1_VALUE_APB _u(0x01)
#define BUSCTRL_PERFSEL1_VALUE_FASTPERI_CONTESTED _u(0x02)
#define BUSCTRL_PERFSEL1_VALUE_FASTPERI _u(0x03)
#define BUSCTRL_PERFSEL1_VALUE_SRAM5_CONTESTED _u(0x04)
#define BUSCTRL_PERFSEL1_VALUE_SRAM5 _u(0x05)
#define BUSCTRL_PERFSEL1_VALUE_SRAM4_CONTESTED _u(0x06)
#define BUSCTRL_PERFSEL1_VALUE_SRAM4 _u(0x07)
#define BUSCTRL_PERFSEL1_VALUE_SRAM3_CONTESTED _u(0x08)
#define BUSCTRL_PERFSEL1_VALUE_SRAM3 _u(0x09)
#define BUSCTRL_PERFSEL1_VALUE_SRAM2_CONTESTED _u(0x0a)
#define BUSCTRL_PERFSEL1_VALUE_SRAM2 _u(0x0b)
#define BUSCTRL_PERFSEL1_VALUE_SRAM1_CONTESTED _u(0x0c)
#define BUSCTRL_PERFSEL1_VALUE_SRAM1 _u(0x0d)
#define BUSCTRL_PERFSEL1_VALUE_SRAM0_CONTESTED _u(0x0e)
#define BUSCTRL_PERFSEL1_VALUE_SRAM0 _u(0x0f)
#define BUSCTRL_PERFSEL1_VALUE_XIP_MAIN_CONTESTED _u(0x10)
#define BUSCTRL_PERFSEL1_VALUE_XIP_MAIN _u(0x11)
#define BUSCTRL_PERFSEL1_VALUE_ROM_CONTESTED _u(0x12)
#define BUSCTRL_PERFSEL1_VALUE_ROM _u(0x13)
// =============================================================================
// Register : BUSCTRL_PERFCTR2
// Description : Bus fabric performance counter 2
// Busfabric saturating performance counter 2
// Count some event signal from the busfabric arbiters.
// Write any value to clear. Select an event to count using
// PERFSEL2
#define BUSCTRL_PERFCTR2_OFFSET _u(0x00000018)
#define BUSCTRL_PERFCTR2_BITS _u(0x00ffffff)
#define BUSCTRL_PERFCTR2_RESET _u(0x00000000)
#define BUSCTRL_PERFCTR2_MSB _u(23)
#define BUSCTRL_PERFCTR2_LSB _u(0)
#define BUSCTRL_PERFCTR2_ACCESS "WC"
// =============================================================================
// Register : BUSCTRL_PERFSEL2
// Description : Bus fabric performance event select for PERFCTR2
// Select an event for PERFCTR2. Count either contested accesses,
// or all accesses, on a downstream port of the main crossbar.
// 0x00 -> apb_contested
// 0x01 -> apb
// 0x02 -> fastperi_contested
// 0x03 -> fastperi
// 0x04 -> sram5_contested
// 0x05 -> sram5
// 0x06 -> sram4_contested
// 0x07 -> sram4
// 0x08 -> sram3_contested
// 0x09 -> sram3
// 0x0a -> sram2_contested
// 0x0b -> sram2
// 0x0c -> sram1_contested
// 0x0d -> sram1
// 0x0e -> sram0_contested
// 0x0f -> sram0
// 0x10 -> xip_main_contested
// 0x11 -> xip_main
// 0x12 -> rom_contested
// 0x13 -> rom
#define BUSCTRL_PERFSEL2_OFFSET _u(0x0000001c)
#define BUSCTRL_PERFSEL2_BITS _u(0x0000001f)
#define BUSCTRL_PERFSEL2_RESET _u(0x0000001f)
#define BUSCTRL_PERFSEL2_MSB _u(4)
#define BUSCTRL_PERFSEL2_LSB _u(0)
#define BUSCTRL_PERFSEL2_ACCESS "RW"
#define BUSCTRL_PERFSEL2_VALUE_APB_CONTESTED _u(0x00)
#define BUSCTRL_PERFSEL2_VALUE_APB _u(0x01)
#define BUSCTRL_PERFSEL2_VALUE_FASTPERI_CONTESTED _u(0x02)
#define BUSCTRL_PERFSEL2_VALUE_FASTPERI _u(0x03)
#define BUSCTRL_PERFSEL2_VALUE_SRAM5_CONTESTED _u(0x04)
#define BUSCTRL_PERFSEL2_VALUE_SRAM5 _u(0x05)
#define BUSCTRL_PERFSEL2_VALUE_SRAM4_CONTESTED _u(0x06)
#define BUSCTRL_PERFSEL2_VALUE_SRAM4 _u(0x07)
#define BUSCTRL_PERFSEL2_VALUE_SRAM3_CONTESTED _u(0x08)
#define BUSCTRL_PERFSEL2_VALUE_SRAM3 _u(0x09)
#define BUSCTRL_PERFSEL2_VALUE_SRAM2_CONTESTED _u(0x0a)
#define BUSCTRL_PERFSEL2_VALUE_SRAM2 _u(0x0b)
#define BUSCTRL_PERFSEL2_VALUE_SRAM1_CONTESTED _u(0x0c)
#define BUSCTRL_PERFSEL2_VALUE_SRAM1 _u(0x0d)
#define BUSCTRL_PERFSEL2_VALUE_SRAM0_CONTESTED _u(0x0e)
#define BUSCTRL_PERFSEL2_VALUE_SRAM0 _u(0x0f)
#define BUSCTRL_PERFSEL2_VALUE_XIP_MAIN_CONTESTED _u(0x10)
#define BUSCTRL_PERFSEL2_VALUE_XIP_MAIN _u(0x11)
#define BUSCTRL_PERFSEL2_VALUE_ROM_CONTESTED _u(0x12)
#define BUSCTRL_PERFSEL2_VALUE_ROM _u(0x13)
// =============================================================================
// Register : BUSCTRL_PERFCTR3
// Description : Bus fabric performance counter 3
// Busfabric saturating performance counter 3
// Count some event signal from the busfabric arbiters.
// Write any value to clear. Select an event to count using
// PERFSEL3
#define BUSCTRL_PERFCTR3_OFFSET _u(0x00000020)
#define BUSCTRL_PERFCTR3_BITS _u(0x00ffffff)
#define BUSCTRL_PERFCTR3_RESET _u(0x00000000)
#define BUSCTRL_PERFCTR3_MSB _u(23)
#define BUSCTRL_PERFCTR3_LSB _u(0)
#define BUSCTRL_PERFCTR3_ACCESS "WC"
// =============================================================================
// Register : BUSCTRL_PERFSEL3
// Description : Bus fabric performance event select for PERFCTR3
// Select an event for PERFCTR3. Count either contested accesses,
// or all accesses, on a downstream port of the main crossbar.
// 0x00 -> apb_contested
// 0x01 -> apb
// 0x02 -> fastperi_contested
// 0x03 -> fastperi
// 0x04 -> sram5_contested
// 0x05 -> sram5
// 0x06 -> sram4_contested
// 0x07 -> sram4
// 0x08 -> sram3_contested
// 0x09 -> sram3
// 0x0a -> sram2_contested
// 0x0b -> sram2
// 0x0c -> sram1_contested
// 0x0d -> sram1
// 0x0e -> sram0_contested
// 0x0f -> sram0
// 0x10 -> xip_main_contested
// 0x11 -> xip_main
// 0x12 -> rom_contested
// 0x13 -> rom
#define BUSCTRL_PERFSEL3_OFFSET _u(0x00000024)
#define BUSCTRL_PERFSEL3_BITS _u(0x0000001f)
#define BUSCTRL_PERFSEL3_RESET _u(0x0000001f)
#define BUSCTRL_PERFSEL3_MSB _u(4)
#define BUSCTRL_PERFSEL3_LSB _u(0)
#define BUSCTRL_PERFSEL3_ACCESS "RW"
#define BUSCTRL_PERFSEL3_VALUE_APB_CONTESTED _u(0x00)
#define BUSCTRL_PERFSEL3_VALUE_APB _u(0x01)
#define BUSCTRL_PERFSEL3_VALUE_FASTPERI_CONTESTED _u(0x02)
#define BUSCTRL_PERFSEL3_VALUE_FASTPERI _u(0x03)
#define BUSCTRL_PERFSEL3_VALUE_SRAM5_CONTESTED _u(0x04)
#define BUSCTRL_PERFSEL3_VALUE_SRAM5 _u(0x05)
#define BUSCTRL_PERFSEL3_VALUE_SRAM4_CONTESTED _u(0x06)
#define BUSCTRL_PERFSEL3_VALUE_SRAM4 _u(0x07)
#define BUSCTRL_PERFSEL3_VALUE_SRAM3_CONTESTED _u(0x08)
#define BUSCTRL_PERFSEL3_VALUE_SRAM3 _u(0x09)
#define BUSCTRL_PERFSEL3_VALUE_SRAM2_CONTESTED _u(0x0a)
#define BUSCTRL_PERFSEL3_VALUE_SRAM2 _u(0x0b)
#define BUSCTRL_PERFSEL3_VALUE_SRAM1_CONTESTED _u(0x0c)
#define BUSCTRL_PERFSEL3_VALUE_SRAM1 _u(0x0d)
#define BUSCTRL_PERFSEL3_VALUE_SRAM0_CONTESTED _u(0x0e)
#define BUSCTRL_PERFSEL3_VALUE_SRAM0 _u(0x0f)
#define BUSCTRL_PERFSEL3_VALUE_XIP_MAIN_CONTESTED _u(0x10)
#define BUSCTRL_PERFSEL3_VALUE_XIP_MAIN _u(0x11)
#define BUSCTRL_PERFSEL3_VALUE_ROM_CONTESTED _u(0x12)
#define BUSCTRL_PERFSEL3_VALUE_ROM _u(0x13)
// =============================================================================
#endif // _HARDWARE_REGS_BUSCTRL_H

View file

@ -1,117 +0,0 @@
// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
/**
* Copyright (c) 2024 Raspberry Pi Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _DREQ_H
#define _DREQ_H
/**
* \file rp2040/dreq.h
*/
#ifdef __ASSEMBLER__
#define DREQ_PIO0_TX0 0
#define DREQ_PIO0_TX1 1
#define DREQ_PIO0_TX2 2
#define DREQ_PIO0_TX3 3
#define DREQ_PIO0_RX0 4
#define DREQ_PIO0_RX1 5
#define DREQ_PIO0_RX2 6
#define DREQ_PIO0_RX3 7
#define DREQ_PIO1_TX0 8
#define DREQ_PIO1_TX1 9
#define DREQ_PIO1_TX2 10
#define DREQ_PIO1_TX3 11
#define DREQ_PIO1_RX0 12
#define DREQ_PIO1_RX1 13
#define DREQ_PIO1_RX2 14
#define DREQ_PIO1_RX3 15
#define DREQ_SPI0_TX 16
#define DREQ_SPI0_RX 17
#define DREQ_SPI1_TX 18
#define DREQ_SPI1_RX 19
#define DREQ_UART0_TX 20
#define DREQ_UART0_RX 21
#define DREQ_UART1_TX 22
#define DREQ_UART1_RX 23
#define DREQ_PWM_WRAP0 24
#define DREQ_PWM_WRAP1 25
#define DREQ_PWM_WRAP2 26
#define DREQ_PWM_WRAP3 27
#define DREQ_PWM_WRAP4 28
#define DREQ_PWM_WRAP5 29
#define DREQ_PWM_WRAP6 30
#define DREQ_PWM_WRAP7 31
#define DREQ_I2C0_TX 32
#define DREQ_I2C0_RX 33
#define DREQ_I2C1_TX 34
#define DREQ_I2C1_RX 35
#define DREQ_ADC 36
#define DREQ_XIP_STREAM 37
#define DREQ_XIP_SSITX 38
#define DREQ_XIP_SSIRX 39
#define DREQ_DMA_TIMER0 59
#define DREQ_DMA_TIMER1 60
#define DREQ_DMA_TIMER2 61
#define DREQ_DMA_TIMER3 62
#define DREQ_FORCE 63
#else
/**
* \brief DREQ numbers for DMA pacing on RP2040 (used as typedef \ref dreq_num_t)
* \ingroup hardware_dma
*/
typedef enum dreq_num_rp2040 {
DREQ_PIO0_TX0 = 0, ///< Select PIO0's TX FIFO 0 as DREQ
DREQ_PIO0_TX1 = 1, ///< Select PIO0's TX FIFO 1 as DREQ
DREQ_PIO0_TX2 = 2, ///< Select PIO0's TX FIFO 2 as DREQ
DREQ_PIO0_TX3 = 3, ///< Select PIO0's TX FIFO 3 as DREQ
DREQ_PIO0_RX0 = 4, ///< Select PIO0's RX FIFO 0 as DREQ
DREQ_PIO0_RX1 = 5, ///< Select PIO0's RX FIFO 1 as DREQ
DREQ_PIO0_RX2 = 6, ///< Select PIO0's RX FIFO 2 as DREQ
DREQ_PIO0_RX3 = 7, ///< Select PIO0's RX FIFO 3 as DREQ
DREQ_PIO1_TX0 = 8, ///< Select PIO1's TX FIFO 0 as DREQ
DREQ_PIO1_TX1 = 9, ///< Select PIO1's TX FIFO 1 as DREQ
DREQ_PIO1_TX2 = 10, ///< Select PIO1's TX FIFO 2 as DREQ
DREQ_PIO1_TX3 = 11, ///< Select PIO1's TX FIFO 3 as DREQ
DREQ_PIO1_RX0 = 12, ///< Select PIO1's RX FIFO 0 as DREQ
DREQ_PIO1_RX1 = 13, ///< Select PIO1's RX FIFO 1 as DREQ
DREQ_PIO1_RX2 = 14, ///< Select PIO1's RX FIFO 2 as DREQ
DREQ_PIO1_RX3 = 15, ///< Select PIO1's RX FIFO 3 as DREQ
DREQ_SPI0_TX = 16, ///< Select SPI0's TX FIFO as DREQ
DREQ_SPI0_RX = 17, ///< Select SPI0's RX FIFO as DREQ
DREQ_SPI1_TX = 18, ///< Select SPI1's TX FIFO as DREQ
DREQ_SPI1_RX = 19, ///< Select SPI1's RX FIFO as DREQ
DREQ_UART0_TX = 20, ///< Select UART0's TX FIFO as DREQ
DREQ_UART0_RX = 21, ///< Select UART0's RX FIFO as DREQ
DREQ_UART1_TX = 22, ///< Select UART1's TX FIFO as DREQ
DREQ_UART1_RX = 23, ///< Select UART1's RX FIFO as DREQ
DREQ_PWM_WRAP0 = 24, ///< Select PWM Counter 0's Wrap Value as DREQ
DREQ_PWM_WRAP1 = 25, ///< Select PWM Counter 1's Wrap Value as DREQ
DREQ_PWM_WRAP2 = 26, ///< Select PWM Counter 2's Wrap Value as DREQ
DREQ_PWM_WRAP3 = 27, ///< Select PWM Counter 3's Wrap Value as DREQ
DREQ_PWM_WRAP4 = 28, ///< Select PWM Counter 4's Wrap Value as DREQ
DREQ_PWM_WRAP5 = 29, ///< Select PWM Counter 5's Wrap Value as DREQ
DREQ_PWM_WRAP6 = 30, ///< Select PWM Counter 6's Wrap Value as DREQ
DREQ_PWM_WRAP7 = 31, ///< Select PWM Counter 7's Wrap Value as DREQ
DREQ_I2C0_TX = 32, ///< Select I2C0's TX FIFO as DREQ
DREQ_I2C0_RX = 33, ///< Select I2C0's RX FIFO as DREQ
DREQ_I2C1_TX = 34, ///< Select I2C1's TX FIFO as DREQ
DREQ_I2C1_RX = 35, ///< Select I2C1's RX FIFO as DREQ
DREQ_ADC = 36, ///< Select the ADC as DREQ
DREQ_XIP_STREAM = 37, ///< Select the XIP Streaming FIFO as DREQ
DREQ_XIP_SSITX = 38, ///< Select the XIP SSI TX FIFO as DREQ
DREQ_XIP_SSIRX = 39, ///< Select the XIP SSI RX FIFO as DREQ
DREQ_DMA_TIMER0 = 59, ///< Select DMA_TIMER0 as DREQ
DREQ_DMA_TIMER1 = 60, ///< Select DMA_TIMER0 as DREQ
DREQ_DMA_TIMER2 = 61, ///< Select DMA_TIMER1 as DREQ
DREQ_DMA_TIMER3 = 62, ///< Select DMA_TIMER3 as DREQ
DREQ_FORCE = 63, ///< Select FORCE as DREQ
DREQ_COUNT
} dreq_num_t;
#endif
#endif // _DREQ_H

View file

@ -1,106 +0,0 @@
// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
/**
* Copyright (c) 2024 Raspberry Pi Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _INTCTRL_H
#define _INTCTRL_H
/**
* \file rp2040/intctrl.h
*/
#ifdef __ASSEMBLER__
#define TIMER_IRQ_0 0
#define TIMER_IRQ_1 1
#define TIMER_IRQ_2 2
#define TIMER_IRQ_3 3
#define PWM_IRQ_WRAP 4
#define USBCTRL_IRQ 5
#define XIP_IRQ 6
#define PIO0_IRQ_0 7
#define PIO0_IRQ_1 8
#define PIO1_IRQ_0 9
#define PIO1_IRQ_1 10
#define DMA_IRQ_0 11
#define DMA_IRQ_1 12
#define IO_IRQ_BANK0 13
#define IO_IRQ_QSPI 14
#define SIO_IRQ_PROC0 15
#define SIO_IRQ_PROC1 16
#define CLOCKS_IRQ 17
#define SPI0_IRQ 18
#define SPI1_IRQ 19
#define UART0_IRQ 20
#define UART1_IRQ 21
#define ADC_IRQ_FIFO 22
#define I2C0_IRQ 23
#define I2C1_IRQ 24
#define RTC_IRQ 25
#else
/**
* \brief Interrupt numbers on RP2040 (used as typedef \ref irq_num_t)
* \ingroup hardware_irq
*/
typedef enum irq_num_rp2040 {
TIMER_IRQ_0 = 0, ///< Select TIMER's IRQ 0 output
TIMER_IRQ_1 = 1, ///< Select TIMER's IRQ 1 output
TIMER_IRQ_2 = 2, ///< Select TIMER's IRQ 2 output
TIMER_IRQ_3 = 3, ///< Select TIMER's IRQ 3 output
PWM_IRQ_WRAP = 4, ///< Select PWM's IRQ_WRAP output
USBCTRL_IRQ = 5, ///< Select USBCTRL's IRQ output
XIP_IRQ = 6, ///< Select XIP's IRQ output
PIO0_IRQ_0 = 7, ///< Select PIO0's IRQ 0 output
PIO0_IRQ_1 = 8, ///< Select PIO0's IRQ 1 output
PIO1_IRQ_0 = 9, ///< Select PIO1's IRQ 0 output
PIO1_IRQ_1 = 10, ///< Select PIO1's IRQ 1 output
DMA_IRQ_0 = 11, ///< Select DMA's IRQ 0 output
DMA_IRQ_1 = 12, ///< Select DMA's IRQ 1 output
IO_IRQ_BANK0 = 13, ///< Select IO_BANK0's IRQ output
IO_IRQ_QSPI = 14, ///< Select IO_QSPI's IRQ output
SIO_IRQ_PROC0 = 15, ///< Select SIO_PROC0's IRQ output
SIO_IRQ_PROC1 = 16, ///< Select SIO_PROC1's IRQ output
CLOCKS_IRQ = 17, ///< Select CLOCKS's IRQ output
SPI0_IRQ = 18, ///< Select SPI0's IRQ output
SPI1_IRQ = 19, ///< Select SPI1's IRQ output
UART0_IRQ = 20, ///< Select UART0's IRQ output
UART1_IRQ = 21, ///< Select UART1's IRQ output
ADC_IRQ_FIFO = 22, ///< Select ADC's IRQ_FIFO output
I2C0_IRQ = 23, ///< Select I2C0's IRQ output
I2C1_IRQ = 24, ///< Select I2C1's IRQ output
RTC_IRQ = 25, ///< Select RTC's IRQ output
IRQ_COUNT
} irq_num_t;
#endif
#define isr_timer_0 isr_irq0
#define isr_timer_1 isr_irq1
#define isr_timer_2 isr_irq2
#define isr_timer_3 isr_irq3
#define isr_pwm_wrap isr_irq4
#define isr_usbctrl isr_irq5
#define isr_xip isr_irq6
#define isr_pio0_0 isr_irq7
#define isr_pio0_1 isr_irq8
#define isr_pio1_0 isr_irq9
#define isr_pio1_1 isr_irq10
#define isr_dma_0 isr_irq11
#define isr_dma_1 isr_irq12
#define isr_io_bank0 isr_irq13
#define isr_io_qspi isr_irq14
#define isr_sio_proc0 isr_irq15
#define isr_sio_proc1 isr_irq16
#define isr_clocks isr_irq17
#define isr_spi0 isr_irq18
#define isr_spi1 isr_irq19
#define isr_uart0 isr_irq20
#define isr_uart1 isr_irq21
#define isr_adc_fifo isr_irq22
#define isr_i2c0 isr_irq23
#define isr_i2c1 isr_irq24
#define isr_rtc isr_irq25
#endif // _INTCTRL_H

View file

@ -1,456 +0,0 @@
// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
/**
* Copyright (c) 2024 Raspberry Pi Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// =============================================================================
// Register block : PADS_QSPI
// Version : 1
// Bus type : apb
// =============================================================================
#ifndef _HARDWARE_REGS_PADS_QSPI_H
#define _HARDWARE_REGS_PADS_QSPI_H
// =============================================================================
// Register : PADS_QSPI_VOLTAGE_SELECT
// Description : Voltage select. Per bank control
// 0x0 -> Set voltage to 3.3V (DVDD >= 2V5)
// 0x1 -> Set voltage to 1.8V (DVDD <= 1V8)
#define PADS_QSPI_VOLTAGE_SELECT_OFFSET _u(0x00000000)
#define PADS_QSPI_VOLTAGE_SELECT_BITS _u(0x00000001)
#define PADS_QSPI_VOLTAGE_SELECT_RESET _u(0x00000000)
#define PADS_QSPI_VOLTAGE_SELECT_MSB _u(0)
#define PADS_QSPI_VOLTAGE_SELECT_LSB _u(0)
#define PADS_QSPI_VOLTAGE_SELECT_ACCESS "RW"
#define PADS_QSPI_VOLTAGE_SELECT_VALUE_3V3 _u(0x0)
#define PADS_QSPI_VOLTAGE_SELECT_VALUE_1V8 _u(0x1)
// =============================================================================
// Register : PADS_QSPI_GPIO_QSPI_SCLK
// Description : Pad control register
#define PADS_QSPI_GPIO_QSPI_SCLK_OFFSET _u(0x00000004)
#define PADS_QSPI_GPIO_QSPI_SCLK_BITS _u(0x000000ff)
#define PADS_QSPI_GPIO_QSPI_SCLK_RESET _u(0x00000056)
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SCLK_OD
// Description : Output disable. Has priority over output enable from
// peripherals
#define PADS_QSPI_GPIO_QSPI_SCLK_OD_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SCLK_OD_BITS _u(0x00000080)
#define PADS_QSPI_GPIO_QSPI_SCLK_OD_MSB _u(7)
#define PADS_QSPI_GPIO_QSPI_SCLK_OD_LSB _u(7)
#define PADS_QSPI_GPIO_QSPI_SCLK_OD_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SCLK_IE
// Description : Input enable
#define PADS_QSPI_GPIO_QSPI_SCLK_IE_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SCLK_IE_BITS _u(0x00000040)
#define PADS_QSPI_GPIO_QSPI_SCLK_IE_MSB _u(6)
#define PADS_QSPI_GPIO_QSPI_SCLK_IE_LSB _u(6)
#define PADS_QSPI_GPIO_QSPI_SCLK_IE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SCLK_DRIVE
// Description : Drive strength.
// 0x0 -> 2mA
// 0x1 -> 4mA
// 0x2 -> 8mA
// 0x3 -> 12mA
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_BITS _u(0x00000030)
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_MSB _u(5)
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_LSB _u(4)
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_ACCESS "RW"
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_VALUE_2MA _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_VALUE_4MA _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_VALUE_8MA _u(0x2)
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_VALUE_12MA _u(0x3)
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SCLK_PUE
// Description : Pull up enable
#define PADS_QSPI_GPIO_QSPI_SCLK_PUE_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SCLK_PUE_BITS _u(0x00000008)
#define PADS_QSPI_GPIO_QSPI_SCLK_PUE_MSB _u(3)
#define PADS_QSPI_GPIO_QSPI_SCLK_PUE_LSB _u(3)
#define PADS_QSPI_GPIO_QSPI_SCLK_PUE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SCLK_PDE
// Description : Pull down enable
#define PADS_QSPI_GPIO_QSPI_SCLK_PDE_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SCLK_PDE_BITS _u(0x00000004)
#define PADS_QSPI_GPIO_QSPI_SCLK_PDE_MSB _u(2)
#define PADS_QSPI_GPIO_QSPI_SCLK_PDE_LSB _u(2)
#define PADS_QSPI_GPIO_QSPI_SCLK_PDE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SCLK_SCHMITT
// Description : Enable schmitt trigger
#define PADS_QSPI_GPIO_QSPI_SCLK_SCHMITT_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SCLK_SCHMITT_BITS _u(0x00000002)
#define PADS_QSPI_GPIO_QSPI_SCLK_SCHMITT_MSB _u(1)
#define PADS_QSPI_GPIO_QSPI_SCLK_SCHMITT_LSB _u(1)
#define PADS_QSPI_GPIO_QSPI_SCLK_SCHMITT_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SCLK_SLEWFAST
// Description : Slew rate control. 1 = Fast, 0 = Slow
#define PADS_QSPI_GPIO_QSPI_SCLK_SLEWFAST_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SCLK_SLEWFAST_BITS _u(0x00000001)
#define PADS_QSPI_GPIO_QSPI_SCLK_SLEWFAST_MSB _u(0)
#define PADS_QSPI_GPIO_QSPI_SCLK_SLEWFAST_LSB _u(0)
#define PADS_QSPI_GPIO_QSPI_SCLK_SLEWFAST_ACCESS "RW"
// =============================================================================
// Register : PADS_QSPI_GPIO_QSPI_SD0
// Description : Pad control register
#define PADS_QSPI_GPIO_QSPI_SD0_OFFSET _u(0x00000008)
#define PADS_QSPI_GPIO_QSPI_SD0_BITS _u(0x000000ff)
#define PADS_QSPI_GPIO_QSPI_SD0_RESET _u(0x00000052)
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD0_OD
// Description : Output disable. Has priority over output enable from
// peripherals
#define PADS_QSPI_GPIO_QSPI_SD0_OD_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD0_OD_BITS _u(0x00000080)
#define PADS_QSPI_GPIO_QSPI_SD0_OD_MSB _u(7)
#define PADS_QSPI_GPIO_QSPI_SD0_OD_LSB _u(7)
#define PADS_QSPI_GPIO_QSPI_SD0_OD_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD0_IE
// Description : Input enable
#define PADS_QSPI_GPIO_QSPI_SD0_IE_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD0_IE_BITS _u(0x00000040)
#define PADS_QSPI_GPIO_QSPI_SD0_IE_MSB _u(6)
#define PADS_QSPI_GPIO_QSPI_SD0_IE_LSB _u(6)
#define PADS_QSPI_GPIO_QSPI_SD0_IE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD0_DRIVE
// Description : Drive strength.
// 0x0 -> 2mA
// 0x1 -> 4mA
// 0x2 -> 8mA
// 0x3 -> 12mA
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_BITS _u(0x00000030)
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_MSB _u(5)
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_LSB _u(4)
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_ACCESS "RW"
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_VALUE_2MA _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_VALUE_4MA _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_VALUE_8MA _u(0x2)
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_VALUE_12MA _u(0x3)
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD0_PUE
// Description : Pull up enable
#define PADS_QSPI_GPIO_QSPI_SD0_PUE_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD0_PUE_BITS _u(0x00000008)
#define PADS_QSPI_GPIO_QSPI_SD0_PUE_MSB _u(3)
#define PADS_QSPI_GPIO_QSPI_SD0_PUE_LSB _u(3)
#define PADS_QSPI_GPIO_QSPI_SD0_PUE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD0_PDE
// Description : Pull down enable
#define PADS_QSPI_GPIO_QSPI_SD0_PDE_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD0_PDE_BITS _u(0x00000004)
#define PADS_QSPI_GPIO_QSPI_SD0_PDE_MSB _u(2)
#define PADS_QSPI_GPIO_QSPI_SD0_PDE_LSB _u(2)
#define PADS_QSPI_GPIO_QSPI_SD0_PDE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD0_SCHMITT
// Description : Enable schmitt trigger
#define PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_BITS _u(0x00000002)
#define PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_MSB _u(1)
#define PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_LSB _u(1)
#define PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD0_SLEWFAST
// Description : Slew rate control. 1 = Fast, 0 = Slow
#define PADS_QSPI_GPIO_QSPI_SD0_SLEWFAST_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD0_SLEWFAST_BITS _u(0x00000001)
#define PADS_QSPI_GPIO_QSPI_SD0_SLEWFAST_MSB _u(0)
#define PADS_QSPI_GPIO_QSPI_SD0_SLEWFAST_LSB _u(0)
#define PADS_QSPI_GPIO_QSPI_SD0_SLEWFAST_ACCESS "RW"
// =============================================================================
// Register : PADS_QSPI_GPIO_QSPI_SD1
// Description : Pad control register
#define PADS_QSPI_GPIO_QSPI_SD1_OFFSET _u(0x0000000c)
#define PADS_QSPI_GPIO_QSPI_SD1_BITS _u(0x000000ff)
#define PADS_QSPI_GPIO_QSPI_SD1_RESET _u(0x00000052)
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD1_OD
// Description : Output disable. Has priority over output enable from
// peripherals
#define PADS_QSPI_GPIO_QSPI_SD1_OD_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD1_OD_BITS _u(0x00000080)
#define PADS_QSPI_GPIO_QSPI_SD1_OD_MSB _u(7)
#define PADS_QSPI_GPIO_QSPI_SD1_OD_LSB _u(7)
#define PADS_QSPI_GPIO_QSPI_SD1_OD_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD1_IE
// Description : Input enable
#define PADS_QSPI_GPIO_QSPI_SD1_IE_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD1_IE_BITS _u(0x00000040)
#define PADS_QSPI_GPIO_QSPI_SD1_IE_MSB _u(6)
#define PADS_QSPI_GPIO_QSPI_SD1_IE_LSB _u(6)
#define PADS_QSPI_GPIO_QSPI_SD1_IE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD1_DRIVE
// Description : Drive strength.
// 0x0 -> 2mA
// 0x1 -> 4mA
// 0x2 -> 8mA
// 0x3 -> 12mA
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_BITS _u(0x00000030)
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_MSB _u(5)
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_LSB _u(4)
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_ACCESS "RW"
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_VALUE_2MA _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_VALUE_4MA _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_VALUE_8MA _u(0x2)
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_VALUE_12MA _u(0x3)
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD1_PUE
// Description : Pull up enable
#define PADS_QSPI_GPIO_QSPI_SD1_PUE_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD1_PUE_BITS _u(0x00000008)
#define PADS_QSPI_GPIO_QSPI_SD1_PUE_MSB _u(3)
#define PADS_QSPI_GPIO_QSPI_SD1_PUE_LSB _u(3)
#define PADS_QSPI_GPIO_QSPI_SD1_PUE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD1_PDE
// Description : Pull down enable
#define PADS_QSPI_GPIO_QSPI_SD1_PDE_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD1_PDE_BITS _u(0x00000004)
#define PADS_QSPI_GPIO_QSPI_SD1_PDE_MSB _u(2)
#define PADS_QSPI_GPIO_QSPI_SD1_PDE_LSB _u(2)
#define PADS_QSPI_GPIO_QSPI_SD1_PDE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD1_SCHMITT
// Description : Enable schmitt trigger
#define PADS_QSPI_GPIO_QSPI_SD1_SCHMITT_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD1_SCHMITT_BITS _u(0x00000002)
#define PADS_QSPI_GPIO_QSPI_SD1_SCHMITT_MSB _u(1)
#define PADS_QSPI_GPIO_QSPI_SD1_SCHMITT_LSB _u(1)
#define PADS_QSPI_GPIO_QSPI_SD1_SCHMITT_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD1_SLEWFAST
// Description : Slew rate control. 1 = Fast, 0 = Slow
#define PADS_QSPI_GPIO_QSPI_SD1_SLEWFAST_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD1_SLEWFAST_BITS _u(0x00000001)
#define PADS_QSPI_GPIO_QSPI_SD1_SLEWFAST_MSB _u(0)
#define PADS_QSPI_GPIO_QSPI_SD1_SLEWFAST_LSB _u(0)
#define PADS_QSPI_GPIO_QSPI_SD1_SLEWFAST_ACCESS "RW"
// =============================================================================
// Register : PADS_QSPI_GPIO_QSPI_SD2
// Description : Pad control register
#define PADS_QSPI_GPIO_QSPI_SD2_OFFSET _u(0x00000010)
#define PADS_QSPI_GPIO_QSPI_SD2_BITS _u(0x000000ff)
#define PADS_QSPI_GPIO_QSPI_SD2_RESET _u(0x00000052)
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD2_OD
// Description : Output disable. Has priority over output enable from
// peripherals
#define PADS_QSPI_GPIO_QSPI_SD2_OD_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD2_OD_BITS _u(0x00000080)
#define PADS_QSPI_GPIO_QSPI_SD2_OD_MSB _u(7)
#define PADS_QSPI_GPIO_QSPI_SD2_OD_LSB _u(7)
#define PADS_QSPI_GPIO_QSPI_SD2_OD_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD2_IE
// Description : Input enable
#define PADS_QSPI_GPIO_QSPI_SD2_IE_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD2_IE_BITS _u(0x00000040)
#define PADS_QSPI_GPIO_QSPI_SD2_IE_MSB _u(6)
#define PADS_QSPI_GPIO_QSPI_SD2_IE_LSB _u(6)
#define PADS_QSPI_GPIO_QSPI_SD2_IE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD2_DRIVE
// Description : Drive strength.
// 0x0 -> 2mA
// 0x1 -> 4mA
// 0x2 -> 8mA
// 0x3 -> 12mA
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_BITS _u(0x00000030)
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_MSB _u(5)
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_LSB _u(4)
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_ACCESS "RW"
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_VALUE_2MA _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_VALUE_4MA _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_VALUE_8MA _u(0x2)
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_VALUE_12MA _u(0x3)
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD2_PUE
// Description : Pull up enable
#define PADS_QSPI_GPIO_QSPI_SD2_PUE_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD2_PUE_BITS _u(0x00000008)
#define PADS_QSPI_GPIO_QSPI_SD2_PUE_MSB _u(3)
#define PADS_QSPI_GPIO_QSPI_SD2_PUE_LSB _u(3)
#define PADS_QSPI_GPIO_QSPI_SD2_PUE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD2_PDE
// Description : Pull down enable
#define PADS_QSPI_GPIO_QSPI_SD2_PDE_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD2_PDE_BITS _u(0x00000004)
#define PADS_QSPI_GPIO_QSPI_SD2_PDE_MSB _u(2)
#define PADS_QSPI_GPIO_QSPI_SD2_PDE_LSB _u(2)
#define PADS_QSPI_GPIO_QSPI_SD2_PDE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD2_SCHMITT
// Description : Enable schmitt trigger
#define PADS_QSPI_GPIO_QSPI_SD2_SCHMITT_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD2_SCHMITT_BITS _u(0x00000002)
#define PADS_QSPI_GPIO_QSPI_SD2_SCHMITT_MSB _u(1)
#define PADS_QSPI_GPIO_QSPI_SD2_SCHMITT_LSB _u(1)
#define PADS_QSPI_GPIO_QSPI_SD2_SCHMITT_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD2_SLEWFAST
// Description : Slew rate control. 1 = Fast, 0 = Slow
#define PADS_QSPI_GPIO_QSPI_SD2_SLEWFAST_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD2_SLEWFAST_BITS _u(0x00000001)
#define PADS_QSPI_GPIO_QSPI_SD2_SLEWFAST_MSB _u(0)
#define PADS_QSPI_GPIO_QSPI_SD2_SLEWFAST_LSB _u(0)
#define PADS_QSPI_GPIO_QSPI_SD2_SLEWFAST_ACCESS "RW"
// =============================================================================
// Register : PADS_QSPI_GPIO_QSPI_SD3
// Description : Pad control register
#define PADS_QSPI_GPIO_QSPI_SD3_OFFSET _u(0x00000014)
#define PADS_QSPI_GPIO_QSPI_SD3_BITS _u(0x000000ff)
#define PADS_QSPI_GPIO_QSPI_SD3_RESET _u(0x00000052)
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD3_OD
// Description : Output disable. Has priority over output enable from
// peripherals
#define PADS_QSPI_GPIO_QSPI_SD3_OD_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD3_OD_BITS _u(0x00000080)
#define PADS_QSPI_GPIO_QSPI_SD3_OD_MSB _u(7)
#define PADS_QSPI_GPIO_QSPI_SD3_OD_LSB _u(7)
#define PADS_QSPI_GPIO_QSPI_SD3_OD_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD3_IE
// Description : Input enable
#define PADS_QSPI_GPIO_QSPI_SD3_IE_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD3_IE_BITS _u(0x00000040)
#define PADS_QSPI_GPIO_QSPI_SD3_IE_MSB _u(6)
#define PADS_QSPI_GPIO_QSPI_SD3_IE_LSB _u(6)
#define PADS_QSPI_GPIO_QSPI_SD3_IE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD3_DRIVE
// Description : Drive strength.
// 0x0 -> 2mA
// 0x1 -> 4mA
// 0x2 -> 8mA
// 0x3 -> 12mA
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_BITS _u(0x00000030)
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_MSB _u(5)
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_LSB _u(4)
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_ACCESS "RW"
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_VALUE_2MA _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_VALUE_4MA _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_VALUE_8MA _u(0x2)
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_VALUE_12MA _u(0x3)
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD3_PUE
// Description : Pull up enable
#define PADS_QSPI_GPIO_QSPI_SD3_PUE_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD3_PUE_BITS _u(0x00000008)
#define PADS_QSPI_GPIO_QSPI_SD3_PUE_MSB _u(3)
#define PADS_QSPI_GPIO_QSPI_SD3_PUE_LSB _u(3)
#define PADS_QSPI_GPIO_QSPI_SD3_PUE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD3_PDE
// Description : Pull down enable
#define PADS_QSPI_GPIO_QSPI_SD3_PDE_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD3_PDE_BITS _u(0x00000004)
#define PADS_QSPI_GPIO_QSPI_SD3_PDE_MSB _u(2)
#define PADS_QSPI_GPIO_QSPI_SD3_PDE_LSB _u(2)
#define PADS_QSPI_GPIO_QSPI_SD3_PDE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD3_SCHMITT
// Description : Enable schmitt trigger
#define PADS_QSPI_GPIO_QSPI_SD3_SCHMITT_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SD3_SCHMITT_BITS _u(0x00000002)
#define PADS_QSPI_GPIO_QSPI_SD3_SCHMITT_MSB _u(1)
#define PADS_QSPI_GPIO_QSPI_SD3_SCHMITT_LSB _u(1)
#define PADS_QSPI_GPIO_QSPI_SD3_SCHMITT_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SD3_SLEWFAST
// Description : Slew rate control. 1 = Fast, 0 = Slow
#define PADS_QSPI_GPIO_QSPI_SD3_SLEWFAST_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SD3_SLEWFAST_BITS _u(0x00000001)
#define PADS_QSPI_GPIO_QSPI_SD3_SLEWFAST_MSB _u(0)
#define PADS_QSPI_GPIO_QSPI_SD3_SLEWFAST_LSB _u(0)
#define PADS_QSPI_GPIO_QSPI_SD3_SLEWFAST_ACCESS "RW"
// =============================================================================
// Register : PADS_QSPI_GPIO_QSPI_SS
// Description : Pad control register
#define PADS_QSPI_GPIO_QSPI_SS_OFFSET _u(0x00000018)
#define PADS_QSPI_GPIO_QSPI_SS_BITS _u(0x000000ff)
#define PADS_QSPI_GPIO_QSPI_SS_RESET _u(0x0000005a)
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SS_OD
// Description : Output disable. Has priority over output enable from
// peripherals
#define PADS_QSPI_GPIO_QSPI_SS_OD_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SS_OD_BITS _u(0x00000080)
#define PADS_QSPI_GPIO_QSPI_SS_OD_MSB _u(7)
#define PADS_QSPI_GPIO_QSPI_SS_OD_LSB _u(7)
#define PADS_QSPI_GPIO_QSPI_SS_OD_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SS_IE
// Description : Input enable
#define PADS_QSPI_GPIO_QSPI_SS_IE_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SS_IE_BITS _u(0x00000040)
#define PADS_QSPI_GPIO_QSPI_SS_IE_MSB _u(6)
#define PADS_QSPI_GPIO_QSPI_SS_IE_LSB _u(6)
#define PADS_QSPI_GPIO_QSPI_SS_IE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SS_DRIVE
// Description : Drive strength.
// 0x0 -> 2mA
// 0x1 -> 4mA
// 0x2 -> 8mA
// 0x3 -> 12mA
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_BITS _u(0x00000030)
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_MSB _u(5)
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_LSB _u(4)
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_ACCESS "RW"
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_VALUE_2MA _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_VALUE_4MA _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_VALUE_8MA _u(0x2)
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_VALUE_12MA _u(0x3)
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SS_PUE
// Description : Pull up enable
#define PADS_QSPI_GPIO_QSPI_SS_PUE_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SS_PUE_BITS _u(0x00000008)
#define PADS_QSPI_GPIO_QSPI_SS_PUE_MSB _u(3)
#define PADS_QSPI_GPIO_QSPI_SS_PUE_LSB _u(3)
#define PADS_QSPI_GPIO_QSPI_SS_PUE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SS_PDE
// Description : Pull down enable
#define PADS_QSPI_GPIO_QSPI_SS_PDE_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SS_PDE_BITS _u(0x00000004)
#define PADS_QSPI_GPIO_QSPI_SS_PDE_MSB _u(2)
#define PADS_QSPI_GPIO_QSPI_SS_PDE_LSB _u(2)
#define PADS_QSPI_GPIO_QSPI_SS_PDE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SS_SCHMITT
// Description : Enable schmitt trigger
#define PADS_QSPI_GPIO_QSPI_SS_SCHMITT_RESET _u(0x1)
#define PADS_QSPI_GPIO_QSPI_SS_SCHMITT_BITS _u(0x00000002)
#define PADS_QSPI_GPIO_QSPI_SS_SCHMITT_MSB _u(1)
#define PADS_QSPI_GPIO_QSPI_SS_SCHMITT_LSB _u(1)
#define PADS_QSPI_GPIO_QSPI_SS_SCHMITT_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : PADS_QSPI_GPIO_QSPI_SS_SLEWFAST
// Description : Slew rate control. 1 = Fast, 0 = Slow
#define PADS_QSPI_GPIO_QSPI_SS_SLEWFAST_RESET _u(0x0)
#define PADS_QSPI_GPIO_QSPI_SS_SLEWFAST_BITS _u(0x00000001)
#define PADS_QSPI_GPIO_QSPI_SS_SLEWFAST_MSB _u(0)
#define PADS_QSPI_GPIO_QSPI_SS_SLEWFAST_LSB _u(0)
#define PADS_QSPI_GPIO_QSPI_SS_SLEWFAST_ACCESS "RW"
// =============================================================================
#endif // _HARDWARE_REGS_PADS_QSPI_H

Some files were not shown because too many files have changed in this diff Show more