diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index eb20569030..caee24bad3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,6 +20,7 @@ jobs: boards-arm: ${{ steps.set-matrix.outputs.boards-arm }} boards-riscv: ${{ steps.set-matrix.outputs.boards-riscv }} boards-espressif: ${{ steps.set-matrix.outputs.boards-espressif }} + boards-aarch: ${{ steps.set-matrix.outputs.boards-aarch }} steps: - name: Dump GitHub context env: @@ -28,19 +29,17 @@ jobs: - uses: actions/checkout@v2.2.0 with: submodules: false - fetch-depth: 0 - - name: Populate selected submodules - run: git submodule update --init extmod/ lib/ tools/ - - name: Fetch tags - run: git fetch --recurse-submodules=no https://github.com/adafruit/circuitpython refs/tags/*:refs/tags/* - - name: CircuitPython version - run: | - git describe --dirty --tags - echo >>$GITHUB_ENV CP_VERSION=$(git describe --dirty --tags) + fetch-depth: 1 - name: Set up Python 3.8 uses: actions/setup-python@v1 with: python-version: 3.8 + - name: Get CP deps + run: python tools/ci_fetch_deps.py test ${{ github.ref }} + - name: CircuitPython version + run: | + git describe --dirty --tags + echo >>$GITHUB_ENV CP_VERSION=$(git describe --dirty --tags) - name: Install dependencies run: | sudo apt-get update @@ -136,19 +135,17 @@ jobs: - uses: actions/checkout@v2.2.0 with: submodules: false - fetch-depth: 0 - - name: Populate selected submodules - run: git submodule update --init extmod/ lib/ tools/ - - name: Fetch tags - run: git fetch --recurse-submodules=no https://github.com/adafruit/circuitpython refs/tags/*:refs/tags/* - - name: CircuitPython version - run: | - git describe --dirty --tags - echo >>$GITHUB_ENV CP_VERSION=$(git describe --dirty --tags) + fetch-depth: 1 - name: Set up Python 3.8 uses: actions/setup-python@v1 with: python-version: 3.8 + - name: Get CP deps + run: python tools/ci_fetch_deps.py mpy-cross-mac ${{ github.ref }} + - name: CircuitPython version + run: | + git describe --dirty --tags + echo >>$GITHUB_ENV CP_VERSION=$(git describe --dirty --tags) - name: Install dependencies run: | brew install gettext @@ -198,11 +195,9 @@ jobs: - uses: actions/checkout@v2.2.0 with: submodules: false - fetch-depth: 0 - - name: Populate selected submodules - run: git submodule update --init extmod/ - - name: Fetch tags - run: git fetch --recurse-submodules=no https://github.com/adafruit/circuitpython refs/tags/*:refs/tags/* + fetch-depth: 1 + - name: Get CP deps + run: python tools/ci_fetch_deps.py docs ${{ github.ref }} - name: CircuitPython version run: | git describe --dirty --tags @@ -271,10 +266,10 @@ jobs: python-version: 3.8 - uses: actions/checkout@v2.2.0 with: - submodules: true - fetch-depth: 0 - - name: Fetch tags - run: git fetch --recurse-submodules=no https://github.com/adafruit/circuitpython refs/tags/*:refs/tags/* + submodules: false + fetch-depth: 1 + - name: Get CP deps + run: python tools/ci_fetch_deps.py ${{ matrix.board }} ${{ github.ref }} - name: Install dependencies run: | sudo apt-get install -y gettext @@ -323,10 +318,10 @@ jobs: python-version: 3.8 - uses: actions/checkout@v2.2.0 with: - submodules: true - fetch-depth: 0 - - name: Fetch tags - run: git fetch --recurse-submodules=no https://github.com/adafruit/circuitpython refs/tags/*:refs/tags/* + submodules: false + fetch-depth: 1 + - name: Get CP deps + run: python tools/ci_fetch_deps.py ${{ matrix.board }} ${{ github.ref }} - name: Install dependencies run: | sudo apt-get install -y gettext @@ -375,10 +370,10 @@ jobs: python-version: 3.8 - uses: actions/checkout@v2.2.0 with: - submodules: true - fetch-depth: 0 - - name: Fetch tags - run: git fetch --recurse-submodules=no https://github.com/adafruit/circuitpython refs/tags/*:refs/tags/* + submodules: false + fetch-depth: 1 + - name: Get CP deps + run: python tools/ci_fetch_deps.py ${{ matrix.board }} ${{ github.ref }} - name: CircuitPython version run: git describe --dirty --tags - uses: actions/cache@v2 @@ -446,3 +441,67 @@ jobs: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} if: (github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository_owner == 'adafruit') || (github.event_name == 'release' && (github.event.action == 'published' || github.event.action == 'rerequested')) + + build-aarch: + runs-on: ubuntu-20.04 + needs: test + strategy: + fail-fast: false + matrix: + board: ${{ fromJSON(needs.test.outputs.boards-aarch) }} + if: ${{ needs.test.outputs.boards-aarch != '[]' }} + steps: + - name: Set up Python 3.8 + uses: actions/setup-python@v1 + with: + python-version: 3.8 + - uses: actions/checkout@v2.2.0 + with: + submodules: false + fetch-depth: 1 + - name: Get CP deps + run: python tools/ci_fetch_deps.py ${{ matrix.board }} ${{ github.ref }} + - name: Install dependencies + run: | + sudo apt-get install -y gettext mtools + pip install -r requirements-ci.txt -r requirements-dev.txt + wget --no-verbose https://adafruit-circuit-python.s3.amazonaws.com/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz + sudo tar -C /usr --strip-components=1 -xaf gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz + wget --no-verbose https://adafruit-circuit-python.s3.amazonaws.com/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2 + sudo tar -C /usr --strip-components=1 -xaf gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2 + - name: Install mkfs.fat + run: | + wget https://github.com/dosfstools/dosfstools/releases/download/v4.2/dosfstools-4.2.tar.gz + tar -xaf dosfstools-4.2.tar.gz + cd dosfstools-4.2 + ./configure + make -j 2 + cd src + echo >>$GITHUB_PATH $(pwd) + - name: Versions + run: | + gcc --version + aarch64-none-elf-gcc --version + arm-none-eabi-gcc --version + python3 --version + mkfs.fat --version || true + - name: mpy-cross + run: make -C mpy-cross -j2 + - name: Setup build failure matcher + run: echo "::add-matcher::$GITHUB_WORKSPACE/.github/workflows/match-build-fail.json" + - name: build + run: python3 -u build_release_files.py + working-directory: tools + env: + BOARDS: ${{ matrix.board }} + - uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.board }} + path: bin/${{ matrix.board }} + - name: Upload to S3 + run: "[ -z \"$AWS_ACCESS_KEY_ID\" ] || aws s3 cp bin/ s3://adafruit-circuit-python/bin/ --recursive --no-progress --region us-east-1" + env: + AWS_PAGER: '' + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + if: (github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository_owner == 'adafruit') || (github.event_name == 'release' && (github.event.action == 'published' || github.event.action == 'rerequested')) diff --git a/.github/workflows/create_website_pr.yml b/.github/workflows/create_website_pr.yml index 97c543da0d..ad33cca136 100644 --- a/.github/workflows/create_website_pr.yml +++ b/.github/workflows/create_website_pr.yml @@ -18,12 +18,14 @@ jobs: run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2.2.0 with: - submodules: true - fetch-depth: 0 + submodules: false + fetch-depth: 1 - name: Set up Python 3.8 uses: actions/setup-python@v1 with: python-version: 3.8 + - name: Get CP deps + run: python tools/ci_fetch_deps.py website ${{ github.ref }} - name: Install deps run: | pip install -r requirements-dev.txt @@ -31,7 +33,6 @@ jobs: run: | gcc --version python3 --version - - run: git fetch --recurse-submodules=no https://github.com/adafruit/circuitpython refs/tags/*:refs/tags/* - name: CircuitPython version run: git describe --dirty --tags - name: Website diff --git a/.github/workflows/ports_windows.yml b/.github/workflows/ports_windows.yml index 4b86f320ed..8491c4026d 100644 --- a/.github/workflows/ports_windows.yml +++ b/.github/workflows/ports_windows.yml @@ -65,12 +65,12 @@ jobs: which python; python --version; python -c "import cascadetoml" which python3; python3 --version; python3 -c "import cascadetoml" - - uses: actions/checkout@v2 + - uses: actions/checkout@v2.2.0 with: - submodules: true - fetch-depth: 0 - - - run: git fetch --recurse-submodules=no https://github.com/adafruit/circuitpython refs/tags/*:refs/tags/* + submodules: false + fetch-depth: 1 + - name: Get CP deps + run: python tools/ci_fetch_deps.py windows ${{ github.ref }} - name: CircuitPython version run: | git describe --dirty --tags diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 7fa71f1e66..2a8811115e 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -12,7 +12,7 @@ jobs: pre-commit: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2.2.0 - uses: actions/setup-python@v1 - name: Install deps run: | diff --git a/.gitmodules b/.gitmodules index e26d3dd76b..98661eef49 100644 --- a/.gitmodules +++ b/.gitmodules @@ -190,3 +190,11 @@ [submodule "frozen/Adafruit_CircuitPython_APDS9960"] path = frozen/Adafruit_CircuitPython_APDS9960 url = https://github.com/adafruit/Adafruit_CircuitPython_APDS9960 +[submodule "ports/broadcom/peripherals"] + path = ports/broadcom/peripherals + url = https://github.com/adafruit/broadcom-peripherals.git + branch = main-build +[submodule "rpi-firmware"] + path = ports/broadcom/firmware + url = https://github.com/raspberrypi/rpi-firmware.git + branch = master diff --git a/conf.py b/conf.py index 80b031ce05..fd92a3cc93 100644 --- a/conf.py +++ b/conf.py @@ -186,6 +186,8 @@ exclude_patterns = ["**/build*", "ports/atmel-samd/peripherals", "ports/atmel-samd/QTouch", "ports/atmel-samd/tools", + "ports/broadcom/firmware", + "ports/broadcom/peripherals", "ports/cxd56/mkspk", "ports/cxd56/spresense-exported-sdk", "ports/espressif/certificates", diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index e7340621f9..839519dc33 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -938,8 +938,8 @@ uint16_t bleio_adapter_max_attribute_handle(bleio_adapter_obj_t *adapter) { void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter) { - gc_collect_root((void **)adapter, sizeof(bleio_adapter_obj_t) / sizeof(size_t)); - gc_collect_root((void **)bleio_connections, sizeof(bleio_connections) / sizeof(size_t)); + gc_collect_root((void **)adapter, sizeof(bleio_adapter_obj_t) / (sizeof(size_t))); + gc_collect_root((void **)bleio_connections, sizeof(bleio_connections) / (sizeof(size_t))); } void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { diff --git a/docs/shared_bindings_matrix.py b/docs/shared_bindings_matrix.py index 7954e96bfd..44554e1ad7 100644 --- a/docs/shared_bindings_matrix.py +++ b/docs/shared_bindings_matrix.py @@ -30,7 +30,7 @@ import sys from concurrent.futures import ThreadPoolExecutor -SUPPORTED_PORTS = ['atmel-samd', 'cxd56', 'espressif', 'litex', 'mimxrt10xx', 'nrf', 'raspberrypi', 'stm'] +SUPPORTED_PORTS = ['atmel-samd', 'broadcom', 'cxd56', 'espressif', 'litex', 'mimxrt10xx', 'nrf', 'raspberrypi', 'stm'] aliases_by_board = { "circuitplayground_express": [ diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 208cf101f9..ce71d74b88 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -440,7 +440,7 @@ STATIC const mp_obj_property_t fat_vfs_label_obj = { .base.type = &mp_type_property, .proxy = {(mp_obj_t)&fat_vfs_getlabel_obj, (mp_obj_t)&fat_vfs_setlabel_obj, - MP_ROM_NONE}, + (mp_obj_t)MP_ROM_NONE}, }; #endif diff --git a/lib/oofatfs/ff.c b/lib/oofatfs/ff.c index b9b347a7d1..6188aead2d 100644 --- a/lib/oofatfs/ff.c +++ b/lib/oofatfs/ff.c @@ -1985,7 +1985,7 @@ static void gen_numname ( if (c > '9') c += 7; ns[i--] = c; seq /= 16; - } while (seq); + } while (seq && i > 0); ns[i] = '~'; /* Append the number to the SFN body */ diff --git a/lib/sdmmc/CMakeLists.txt b/lib/sdmmc/CMakeLists.txt new file mode 100644 index 0000000000..f6e8fe2b1e --- /dev/null +++ b/lib/sdmmc/CMakeLists.txt @@ -0,0 +1,9 @@ +idf_component_register(SRCS "sdmmc_cmd.c" + "sdmmc_common.c" + "sdmmc_init.c" + "sdmmc_io.c" + "sdmmc_mmc.c" + "sdmmc_sd.c" + INCLUDE_DIRS include + REQUIRES driver + PRIV_REQUIRES soc) diff --git a/lib/sdmmc/component.mk b/lib/sdmmc/component.mk new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/sdmmc/include/sdmmc_cmd.h b/lib/sdmmc/include/sdmmc_cmd.h new file mode 100644 index 0000000000..7952adac7c --- /dev/null +++ b/lib/sdmmc/include/sdmmc_cmd.h @@ -0,0 +1,274 @@ +// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include "sdmmc_defs.h" +#include "sdmmc_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Probe and initialize SD/MMC card using given host + * + * @note Only SD cards (SDSC and SDHC/SDXC) are supported now. + * Support for MMC/eMMC cards will be added later. + * + * @param host pointer to structure defining host controller + * @param out_card pointer to structure which will receive information + * about the card when the function completes + * @return + * - SDMMC_OK on success + * - One of the error codes from SDMMC host controller + */ +sdmmc_err_t sdmmc_card_init(const sdmmc_host_t* host, + sdmmc_card_t* out_card); + +/** + * @brief Print information about the card to a stream + * @param stream stream obtained using fopen or fdopen + * @param card card information structure initialized using sdmmc_card_init + */ +void sdmmc_card_print_info(FILE* stream, const sdmmc_card_t* card); + +/** + * Write given number of sectors to SD/MMC card + * + * @param card pointer to card information structure previously initialized + * using sdmmc_card_init + * @param src pointer to data buffer to read data from; data size must be + * equal to sector_count * card->csd.sector_size + * @param start_sector sector where to start writing + * @param sector_count number of sectors to write + * @return + * - SDMMC_OK on success + * - One of the error codes from SDMMC host controller + */ +sdmmc_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src, + size_t start_sector, size_t sector_count); + +/** + * Read given number of sectors from the SD/MMC card + * + * @param card pointer to card information structure previously initialized + * using sdmmc_card_init + * @param dst pointer to data buffer to write into; buffer size must be + * at least sector_count * card->csd.sector_size + * @param start_sector sector where to start reading + * @param sector_count number of sectors to read + * @return + * - SDMMC_OK on success + * - One of the error codes from SDMMC host controller + */ +sdmmc_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst, + size_t start_sector, size_t sector_count); + +/** + * Read one byte from an SDIO card using IO_RW_DIRECT (CMD52) + * + * @param card pointer to card information structure previously initialized + * using sdmmc_card_init + * @param function IO function number + * @param reg byte address within IO function + * @param[out] out_byte output, receives the value read from the card + * @return + * - SDMMC_OK on success + * - One of the error codes from SDMMC host controller + */ +sdmmc_err_t sdmmc_io_read_byte(sdmmc_card_t* card, uint32_t function, + uint32_t reg, uint8_t *out_byte); + +/** + * Write one byte to an SDIO card using IO_RW_DIRECT (CMD52) + * + * @param card pointer to card information structure previously initialized + * using sdmmc_card_init + * @param function IO function number + * @param reg byte address within IO function + * @param in_byte value to be written + * @param[out] out_byte if not NULL, receives new byte value read + * from the card (read-after-write). + * @return + * - SDMMC_OK on success + * - One of the error codes from SDMMC host controller + */ +sdmmc_err_t sdmmc_io_write_byte(sdmmc_card_t* card, uint32_t function, + uint32_t reg, uint8_t in_byte, uint8_t* out_byte); + +/** + * Read multiple bytes from an SDIO card using IO_RW_EXTENDED (CMD53) + * + * This function performs read operation using CMD53 in byte mode. + * For block mode, see sdmmc_io_read_blocks. + * + * @param card pointer to card information structure previously initialized + * using sdmmc_card_init + * @param function IO function number + * @param addr byte address within IO function where reading starts + * @param dst buffer which receives the data read from card + * @param size number of bytes to read + * @return + * - SDMMC_OK on success + * - SDMMC_ERR_INVALID_SIZE if size exceeds 512 bytes + * - One of the error codes from SDMMC host controller + */ +sdmmc_err_t sdmmc_io_read_bytes(sdmmc_card_t* card, uint32_t function, + uint32_t addr, void* dst, size_t size); + +/** + * Write multiple bytes to an SDIO card using IO_RW_EXTENDED (CMD53) + * + * This function performs write operation using CMD53 in byte mode. + * For block mode, see sdmmc_io_write_blocks. + * + * @param card pointer to card information structure previously initialized + * using sdmmc_card_init + * @param function IO function number + * @param addr byte address within IO function where writing starts + * @param src data to be written + * @param size number of bytes to write + * @return + * - SDMMC_OK on success + * - SDMMC_ERR_INVALID_SIZE if size exceeds 512 bytes + * - One of the error codes from SDMMC host controller + */ +sdmmc_err_t sdmmc_io_write_bytes(sdmmc_card_t* card, uint32_t function, + uint32_t addr, const void* src, size_t size); + +/** + * Read blocks of data from an SDIO card using IO_RW_EXTENDED (CMD53) + * + * This function performs read operation using CMD53 in block mode. + * For byte mode, see sdmmc_io_read_bytes. + * + * @param card pointer to card information structure previously initialized + * using sdmmc_card_init + * @param function IO function number + * @param addr byte address within IO function where writing starts + * @param dst buffer which receives the data read from card + * @param size number of bytes to read, must be divisible by the card block + * size. + * @return + * - SDMMC_OK on success + * - SDMMC_ERR_INVALID_SIZE if size is not divisible by 512 bytes + * - One of the error codes from SDMMC host controller + */ +sdmmc_err_t sdmmc_io_read_blocks(sdmmc_card_t* card, uint32_t function, + uint32_t addr, void* dst, size_t size); + +/** + * Write blocks of data to an SDIO card using IO_RW_EXTENDED (CMD53) + * + * This function performs write operation using CMD53 in block mode. + * For byte mode, see sdmmc_io_write_bytes. + * + * @param card pointer to card information structure previously initialized + * using sdmmc_card_init + * @param function IO function number + * @param addr byte address within IO function where writing starts + * @param src data to be written + * @param size number of bytes to read, must be divisible by the card block + * size. + * @return + * - SDMMC_OK on success + * - SDMMC_ERR_INVALID_SIZE if size is not divisible by 512 bytes + * - One of the error codes from SDMMC host controller + */ +sdmmc_err_t sdmmc_io_write_blocks(sdmmc_card_t* card, uint32_t function, + uint32_t addr, const void* src, size_t size); + +/** + * Enable SDIO interrupt in the SDMMC host + * + * @param card pointer to card information structure previously initialized + * using sdmmc_card_init + * @return + * - SDMMC_OK on success + * - SDMMC_ERR_NOT_SUPPORTED if the host controller does not support + * IO interrupts + */ +sdmmc_err_t sdmmc_io_enable_int(sdmmc_card_t* card); + +/** + * Block until an SDIO interrupt is received + * + * Slave uses D1 line to signal interrupt condition to the host. + * This function can be used to wait for the interrupt. + * + * @param card pointer to card information structure previously initialized + * using sdmmc_card_init + * @param timeout_ticks time to wait for the interrupt, in RTOS ticks + * @return + * - SDMMC_OK if the interrupt is received + * - SDMMC_ERR_NOT_SUPPORTED if the host controller does not support + * IO interrupts + * - SDMMC_ERR_TIMEOUT if the interrupt does not happen in timeout_ticks + */ +sdmmc_err_t sdmmc_io_wait_int(sdmmc_card_t* card, int timeout_ms); + +/** + * Get the data of CIS region of a SDIO card. + * + * You may provide a buffer not sufficient to store all the CIS data. In this + * case, this functions store as much data into your buffer as possible. Also, + * this function will try to get and return the size required for you. + * + * @param card pointer to card information structure previously initialized + * using sdmmc_card_init + * @param out_buffer Output buffer of the CIS data + * @param buffer_size Size of the buffer. + * @param inout_cis_size Mandatory, pointer to a size, input and output. + * - input: Limitation of maximum searching range, should be 0 or larger than + * buffer_size. The function searches for CIS_CODE_END until this range. Set to + * 0 to search infinitely. + * - output: The size required to store all the CIS data, if CIS_CODE_END is found. + * + * @return + * - SDMMC_OK: on success + * - SDMMC_ERR_INVALID_RESPONSE: if the card does not (correctly) support CIS. + * - SDMMC_ERR_INVALID_SIZE: CIS_CODE_END found, but buffer_size is less than + * required size, which is stored in the inout_cis_size then. + * - SDMMC_ERR_NOT_FOUND: if the CIS_CODE_END not found. Increase input value of + * inout_cis_size or set it to 0, if you still want to search for the end; + * output value of inout_cis_size is invalid in this case. + * - and other error code return from sdmmc_io_read_bytes + */ +sdmmc_err_t sdmmc_io_get_cis_data(sdmmc_card_t* card, uint8_t* out_buffer, size_t buffer_size, size_t* inout_cis_size); + +/** + * Parse and print the CIS information of a SDIO card. + * + * @note Not all the CIS codes and all kinds of tuples are supported. If you + * see some unresolved code, you can add the parsing of these code in + * sdmmc_io.c and contribute to the IDF through the Github repository. + * + * using sdmmc_card_init + * @param buffer Buffer to parse + * @param buffer_size Size of the buffer. + * @param fp File pointer to print to, set to NULL to print to stdout. + * + * @return + * - SDMMC_OK: on success + * - SDMMC_ERR_NOT_SUPPORTED: if the value from the card is not supported to be parsed. + * - SDMMC_ERR_INVALID_SIZE: if the CIS size fields are not correct. + */ +sdmmc_err_t sdmmc_io_print_cis_info(uint8_t* buffer, size_t buffer_size, FILE* fp); + + +#ifdef __cplusplus +} +#endif diff --git a/lib/sdmmc/include/sdmmc_defs.h b/lib/sdmmc/include/sdmmc_defs.h new file mode 100644 index 0000000000..7ac6ae1198 --- /dev/null +++ b/lib/sdmmc/include/sdmmc_defs.h @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2006 Uwe Stuehler + * Adaptations to ESP-IDF Copyright (c) 2016 Espressif Systems (Shanghai) PTE LTD + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SDMMC_DEFS_H_ +#define _SDMMC_DEFS_H_ + +#include +#include + +/* MMC commands */ /* response type */ +#define MMC_GO_IDLE_STATE 0 /* R0 */ +#define MMC_SEND_OP_COND 1 /* R3 */ +#define MMC_ALL_SEND_CID 2 /* R2 */ +#define MMC_SET_RELATIVE_ADDR 3 /* R1 */ +#define MMC_SWITCH 6 /* R1B */ +#define MMC_SELECT_CARD 7 /* R1 */ +#define MMC_SEND_EXT_CSD 8 /* R1 */ +#define MMC_SEND_CSD 9 /* R2 */ +#define MMC_SEND_CID 10 /* R1 */ +#define MMC_READ_DAT_UNTIL_STOP 11 /* R1 */ +#define MMC_STOP_TRANSMISSION 12 /* R1B */ +#define MMC_SEND_STATUS 13 /* R1 */ +#define MMC_SET_BLOCKLEN 16 /* R1 */ +#define MMC_READ_BLOCK_SINGLE 17 /* R1 */ +#define MMC_READ_BLOCK_MULTIPLE 18 /* R1 */ +#define MMC_WRITE_DAT_UNTIL_STOP 20 /* R1 */ +#define MMC_SET_BLOCK_COUNT 23 /* R1 */ +#define MMC_WRITE_BLOCK_SINGLE 24 /* R1 */ +#define MMC_WRITE_BLOCK_MULTIPLE 25 /* R1 */ +#define MMC_APP_CMD 55 /* R1 */ + +/* SD commands */ /* response type */ +#define SD_SEND_RELATIVE_ADDR 3 /* R6 */ +#define SD_SEND_SWITCH_FUNC 6 /* R1 */ +#define SD_SEND_IF_COND 8 /* R7 */ +#define SD_READ_OCR 58 /* R3 */ +#define SD_CRC_ON_OFF 59 /* R1 */ + +/* SD application commands */ /* response type */ +#define SD_APP_SET_BUS_WIDTH 6 /* R1 */ +#define SD_APP_SD_STATUS 13 /* R2 */ +#define SD_APP_OP_COND 41 /* R3 */ +#define SD_APP_SEND_SCR 51 /* R1 */ + +/* SD IO commands */ +#define SD_IO_SEND_OP_COND 5 /* R4 */ +#define SD_IO_RW_DIRECT 52 /* R5 */ +#define SD_IO_RW_EXTENDED 53 /* R5 */ + + +/* OCR bits */ +#define MMC_OCR_MEM_READY (1<<31) /* memory power-up status bit */ +#define MMC_OCR_ACCESS_MODE_MASK 0x60000000 /* bits 30:29 */ +#define MMC_OCR_SECTOR_MODE (1<<30) +#define MMC_OCR_BYTE_MODE (1<<29) +#define MMC_OCR_3_5V_3_6V (1<<23) +#define MMC_OCR_3_4V_3_5V (1<<22) +#define MMC_OCR_3_3V_3_4V (1<<21) +#define MMC_OCR_3_2V_3_3V (1<<20) +#define MMC_OCR_3_1V_3_2V (1<<19) +#define MMC_OCR_3_0V_3_1V (1<<18) +#define MMC_OCR_2_9V_3_0V (1<<17) +#define MMC_OCR_2_8V_2_9V (1<<16) +#define MMC_OCR_2_7V_2_8V (1<<15) +#define MMC_OCR_2_6V_2_7V (1<<14) +#define MMC_OCR_2_5V_2_6V (1<<13) +#define MMC_OCR_2_4V_2_5V (1<<12) +#define MMC_OCR_2_3V_2_4V (1<<11) +#define MMC_OCR_2_2V_2_3V (1<<10) +#define MMC_OCR_2_1V_2_2V (1<<9) +#define MMC_OCR_2_0V_2_1V (1<<8) +#define MMC_OCR_1_65V_1_95V (1<<7) + +#define SD_OCR_SDHC_CAP (1<<30) +#define SD_OCR_VOL_MASK 0xFF8000 /* bits 23:15 */ + +/* SD mode R1 response type bits */ +#define MMC_R1_READY_FOR_DATA (1<<8) /* ready for next transfer */ +#define MMC_R1_APP_CMD (1<<5) /* app. commands supported */ +#define MMC_R1_SWITCH_ERROR (1<<7) /* switch command did not succeed */ + +/* SPI mode R1 response type bits */ +#define SD_SPI_R1_IDLE_STATE (1<<0) +#define SD_SPI_R1_ERASE_RST (1<<1) +#define SD_SPI_R1_ILLEGAL_CMD (1<<2) +#define SD_SPI_R1_CMD_CRC_ERR (1<<3) +#define SD_SPI_R1_ERASE_SEQ_ERR (1<<4) +#define SD_SPI_R1_ADDR_ERR (1<<5) +#define SD_SPI_R1_PARAM_ERR (1<<6) +#define SD_SPI_R1_NO_RESPONSE (1<<7) + +#define SDIO_R1_FUNC_NUM_ERR (1<<4) + +/* 48-bit response decoding (32 bits w/o CRC) */ +#define MMC_R1(resp) ((resp)[0]) +#define MMC_R3(resp) ((resp)[0]) +#define MMC_R4(resp) ((resp)[0]) +#define MMC_R5(resp) ((resp)[0]) +#define SD_R6(resp) ((resp)[0]) +#define MMC_R1_CURRENT_STATE(resp) (((resp)[0] >> 9) & 0xf) + +/* SPI mode response decoding */ +#define SD_SPI_R1(resp) ((resp)[0] & 0xff) +#define SD_SPI_R2(resp) ((resp)[0] & 0xffff) +#define SD_SPI_R3(resp) ((resp)[0]) +#define SD_SPI_R7(resp) ((resp)[0]) + +/* SPI mode data response decoding */ +#define SD_SPI_DATA_RSP_VALID(resp_byte) (((resp_byte)&0x11)==0x1) +#define SD_SPI_DATA_RSP(resp_byte) (((resp_byte)>>1)&0x7) +#define SD_SPI_DATA_ACCEPTED 0x2 +#define SD_SPI_DATA_CRC_ERROR 0x5 +#define SD_SPI_DATA_WR_ERROR 0x6 + +/* RCA argument and response */ +#define MMC_ARG_RCA(rca) ((rca) << 16) +#define SD_R6_RCA(resp) (SD_R6((resp)) >> 16) + +/* bus width argument */ +#define SD_ARG_BUS_WIDTH_1 0 +#define SD_ARG_BUS_WIDTH_4 2 + +/* EXT_CSD fields */ +#define EXT_CSD_BUS_WIDTH 183 /* WO */ +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_REV 192 /* RO */ +#define EXT_CSD_STRUCTURE 194 /* RO */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_SEC_COUNT 212 /* RO */ +#define EXT_CSD_PWR_CL_26_360 203 /* RO */ +#define EXT_CSD_PWR_CL_52_360 202 /* RO */ +#define EXT_CSD_PWR_CL_26_195 201 /* RO */ +#define EXT_CSD_PWR_CL_52_195 200 /* RO */ +#define EXT_CSD_POWER_CLASS 187 /* R/W */ +#define EXT_CSD_CMD_SET 191 /* R/W */ +#define EXT_CSD_S_CMD_SET 504 /* RO */ + +/* EXT_CSD field definitions */ +#define EXT_CSD_CMD_SET_NORMAL (1U << 0) +#define EXT_CSD_CMD_SET_SECURE (1U << 1) +#define EXT_CSD_CMD_SET_CPSECURE (1U << 2) + +/* EXT_CSD_HS_TIMING */ +#define EXT_CSD_HS_TIMING_BC 0 +#define EXT_CSD_HS_TIMING_HS 1 +#define EXT_CSD_HS_TIMING_HS200 2 +#define EXT_CSD_HS_TIMING_HS400 3 + +/* EXT_CSD_BUS_WIDTH */ +#define EXT_CSD_BUS_WIDTH_1 0 +#define EXT_CSD_BUS_WIDTH_4 1 +#define EXT_CSD_BUS_WIDTH_8 2 +#define EXT_CSD_BUS_WIDTH_4_DDR 5 +#define EXT_CSD_BUS_WIDTH_8_DDR 6 + +/* EXT_CSD_CARD_TYPE */ +/* The only currently valid values for this field are 0x01, 0x03, 0x07, + * 0x0B and 0x0F. */ +#define EXT_CSD_CARD_TYPE_F_26M (1 << 0) /* SDR at "rated voltages */ +#define EXT_CSD_CARD_TYPE_F_52M (1 << 1) /* SDR at "rated voltages */ +#define EXT_CSD_CARD_TYPE_F_52M_1_8V (1 << 2) /* DDR, 1.8V or 3.3V I/O */ +#define EXT_CSD_CARD_TYPE_F_52M_1_2V (1 << 3) /* DDR, 1.2V I/O */ +#define EXT_CSD_CARD_TYPE_26M 0x01 +#define EXT_CSD_CARD_TYPE_52M 0x03 +#define EXT_CSD_CARD_TYPE_52M_V18 0x07 +#define EXT_CSD_CARD_TYPE_52M_V12 0x0b +#define EXT_CSD_CARD_TYPE_52M_V12_18 0x0f + +/* EXT_CSD MMC */ +#define EXT_CSD_MMC_SIZE 512 + +/* MMC_SWITCH access mode */ +#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ +#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits in value */ +#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits in value */ +#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ + +/* MMC R2 response (CSD) */ +#define MMC_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2) +#define MMC_CSD_CSDVER_1_0 1 +#define MMC_CSD_CSDVER_2_0 2 +#define MMC_CSD_CSDVER_EXT_CSD 3 +#define MMC_CSD_MMCVER(resp) MMC_RSP_BITS((resp), 122, 4) +#define MMC_CSD_MMCVER_1_0 0 /* MMC 1.0 - 1.2 */ +#define MMC_CSD_MMCVER_1_4 1 /* MMC 1.4 */ +#define MMC_CSD_MMCVER_2_0 2 /* MMC 2.0 - 2.2 */ +#define MMC_CSD_MMCVER_3_1 3 /* MMC 3.1 - 3.3 */ +#define MMC_CSD_MMCVER_4_0 4 /* MMC 4 */ +#define MMC_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4) +#define MMC_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12) +#define MMC_CSD_CAPACITY(resp) ((MMC_CSD_C_SIZE((resp))+1) << \ + (MMC_CSD_C_SIZE_MULT((resp))+2)) +#define MMC_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3) + +/* MMC v1 R2 response (CID) */ +#define MMC_CID_MID_V1(resp) MMC_RSP_BITS((resp), 104, 24) +#define MMC_CID_PNM_V1_CPY(resp, pnm) \ + do { \ + (pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \ + (pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \ + (pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \ + (pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \ + (pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \ + (pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \ + (pnm)[6] = MMC_RSP_BITS((resp), 48, 8); \ + (pnm)[7] = '\0'; \ + } while (0) +#define MMC_CID_REV_V1(resp) MMC_RSP_BITS((resp), 40, 8) +#define MMC_CID_PSN_V1(resp) MMC_RSP_BITS((resp), 16, 24) +#define MMC_CID_MDT_V1(resp) MMC_RSP_BITS((resp), 8, 8) + +/* MMC v2 R2 response (CID) */ +#define MMC_CID_MID_V2(resp) MMC_RSP_BITS((resp), 120, 8) +#define MMC_CID_OID_V2(resp) MMC_RSP_BITS((resp), 104, 16) +#define MMC_CID_PNM_V2_CPY(resp, pnm) \ + do { \ + (pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \ + (pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \ + (pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \ + (pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \ + (pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \ + (pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \ + (pnm)[6] = '\0'; \ + } while (0) +#define MMC_CID_PSN_V2(resp) MMC_RSP_BITS((resp), 16, 32) + +/* SD R2 response (CSD) */ +#define SD_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2) +#define SD_CSD_CSDVER_1_0 0 +#define SD_CSD_CSDVER_2_0 1 +#define SD_CSD_TAAC(resp) MMC_RSP_BITS((resp), 112, 8) +#define SD_CSD_TAAC_1_5_MSEC 0x26 +#define SD_CSD_NSAC(resp) MMC_RSP_BITS((resp), 104, 8) +#define SD_CSD_SPEED(resp) MMC_RSP_BITS((resp), 96, 8) +#define SD_CSD_SPEED_25_MHZ 0x32 +#define SD_CSD_SPEED_50_MHZ 0x5a +#define SD_CSD_CCC(resp) MMC_RSP_BITS((resp), 84, 12) +#define SD_CSD_CCC_BASIC (1 << 0) /* basic */ +#define SD_CSD_CCC_BR (1 << 2) /* block read */ +#define SD_CSD_CCC_BW (1 << 4) /* block write */ +#define SD_CSD_CCC_ERASE (1 << 5) /* erase */ +#define SD_CSD_CCC_WP (1 << 6) /* write protection */ +#define SD_CSD_CCC_LC (1 << 7) /* lock card */ +#define SD_CSD_CCC_AS (1 << 8) /*application specific*/ +#define SD_CSD_CCC_IOM (1 << 9) /* I/O mode */ +#define SD_CSD_CCC_SWITCH (1 << 10) /* switch */ +#define SD_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4) +#define SD_CSD_READ_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 79, 1) +#define SD_CSD_WRITE_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 78, 1) +#define SD_CSD_READ_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 77, 1) +#define SD_CSD_DSR_IMP(resp) MMC_RSP_BITS((resp), 76, 1) +#define SD_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12) +#define SD_CSD_CAPACITY(resp) ((SD_CSD_C_SIZE((resp))+1) << \ + (SD_CSD_C_SIZE_MULT((resp))+2)) +#define SD_CSD_V2_C_SIZE(resp) MMC_RSP_BITS((resp), 48, 22) +#define SD_CSD_V2_CAPACITY(resp) ((SD_CSD_V2_C_SIZE((resp))+1) << 10) +#define SD_CSD_V2_BL_LEN 0x9 /* 512 */ +#define SD_CSD_VDD_R_CURR_MIN(resp) MMC_RSP_BITS((resp), 59, 3) +#define SD_CSD_VDD_R_CURR_MAX(resp) MMC_RSP_BITS((resp), 56, 3) +#define SD_CSD_VDD_W_CURR_MIN(resp) MMC_RSP_BITS((resp), 53, 3) +#define SD_CSD_VDD_W_CURR_MAX(resp) MMC_RSP_BITS((resp), 50, 3) +#define SD_CSD_VDD_RW_CURR_100mA 0x7 +#define SD_CSD_VDD_RW_CURR_80mA 0x6 +#define SD_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3) +#define SD_CSD_ERASE_BLK_EN(resp) MMC_RSP_BITS((resp), 46, 1) +#define SD_CSD_SECTOR_SIZE(resp) MMC_RSP_BITS((resp), 39, 7) /* +1 */ +#define SD_CSD_WP_GRP_SIZE(resp) MMC_RSP_BITS((resp), 32, 7) /* +1 */ +#define SD_CSD_WP_GRP_ENABLE(resp) MMC_RSP_BITS((resp), 31, 1) +#define SD_CSD_R2W_FACTOR(resp) MMC_RSP_BITS((resp), 26, 3) +#define SD_CSD_WRITE_BL_LEN(resp) MMC_RSP_BITS((resp), 22, 4) +#define SD_CSD_RW_BL_LEN_2G 0xa +#define SD_CSD_RW_BL_LEN_1G 0x9 +#define SD_CSD_WRITE_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 21, 1) +#define SD_CSD_FILE_FORMAT_GRP(resp) MMC_RSP_BITS((resp), 15, 1) +#define SD_CSD_COPY(resp) MMC_RSP_BITS((resp), 14, 1) +#define SD_CSD_PERM_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 13, 1) +#define SD_CSD_TMP_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 12, 1) +#define SD_CSD_FILE_FORMAT(resp) MMC_RSP_BITS((resp), 10, 2) + +/* SD R2 response (CID) */ +#define SD_CID_MID(resp) MMC_RSP_BITS((resp), 120, 8) +#define SD_CID_OID(resp) MMC_RSP_BITS((resp), 104, 16) +#define SD_CID_PNM_CPY(resp, pnm) \ + do { \ + (pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \ + (pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \ + (pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \ + (pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \ + (pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \ + (pnm)[5] = '\0'; \ + } while (0) +#define SD_CID_REV(resp) MMC_RSP_BITS((resp), 56, 8) +#define SD_CID_PSN(resp) MMC_RSP_BITS((resp), 24, 32) +#define SD_CID_MDT(resp) MMC_RSP_BITS((resp), 8, 12) + +/* SCR (SD Configuration Register) */ +#define SCR_STRUCTURE(scr) MMC_RSP_BITS((scr), 60, 4) +#define SCR_STRUCTURE_VER_1_0 0 /* Version 1.0 */ +#define SCR_SD_SPEC(scr) MMC_RSP_BITS((scr), 56, 4) +#define SCR_SD_SPEC_VER_1_0 0 /* Version 1.0 and 1.01 */ +#define SCR_SD_SPEC_VER_1_10 1 /* Version 1.10 */ +#define SCR_SD_SPEC_VER_2 2 /* Version 2.00 or Version 3.0X */ +#define SCR_DATA_STAT_AFTER_ERASE(scr) MMC_RSP_BITS((scr), 55, 1) +#define SCR_SD_SECURITY(scr) MMC_RSP_BITS((scr), 52, 3) +#define SCR_SD_SECURITY_NONE 0 /* no security */ +#define SCR_SD_SECURITY_1_0 1 /* security protocol 1.0 */ +#define SCR_SD_SECURITY_1_0_2 2 /* security protocol 1.0 */ +#define SCR_SD_BUS_WIDTHS(scr) MMC_RSP_BITS((scr), 48, 4) +#define SCR_SD_BUS_WIDTHS_1BIT (1 << 0) /* 1bit (DAT0) */ +#define SCR_SD_BUS_WIDTHS_4BIT (1 << 2) /* 4bit (DAT0-3) */ +#define SCR_SD_SPEC3(scr) MMC_RSP_BITS((scr), 47, 1) +#define SCR_EX_SECURITY(scr) MMC_RSP_BITS((scr), 43, 4) +#define SCR_SD_SPEC4(scr) MMC_RSP_BITS((scr), 42, 1) +#define SCR_RESERVED(scr) MMC_RSP_BITS((scr), 34, 8) +#define SCR_CMD_SUPPORT_CMD23(scr) MMC_RSP_BITS((scr), 33, 1) +#define SCR_CMD_SUPPORT_CMD20(scr) MMC_RSP_BITS((scr), 32, 1) +#define SCR_RESERVED2(scr) MMC_RSP_BITS((scr), 0, 32) + +/* Max supply current in SWITCH_FUNC response (in mA) */ +#define SD_SFUNC_I_MAX(status) (MMC_RSP_BITS((uint32_t *)(status), 496, 16)) + +/* Supported flags in SWITCH_FUNC response */ +#define SD_SFUNC_SUPPORTED(status, group) \ + (MMC_RSP_BITS((uint32_t *)(status), 400 + (group - 1) * 16, 16)) + +/* Selected function in SWITCH_FUNC response */ +#define SD_SFUNC_SELECTED(status, group) \ + (MMC_RSP_BITS((uint32_t *)(status), 376 + (group - 1) * 4, 4)) + +/* Busy flags in SWITCH_FUNC response */ +#define SD_SFUNC_BUSY(status, group) \ + (MMC_RSP_BITS((uint32_t *)(status), 272 + (group - 1) * 16, 16)) + +/* Version of SWITCH_FUNC response */ +#define SD_SFUNC_VER(status) (MMC_RSP_BITS((uint32_t *)(status), 368, 8)) + +#define SD_SFUNC_GROUP_MAX 6 +#define SD_SFUNC_FUNC_MAX 15 + +#define SD_ACCESS_MODE 1 /* Function group 1, Access Mode */ + +#define SD_ACCESS_MODE_SDR12 0 /* 25 MHz clock */ +#define SD_ACCESS_MODE_SDR25 1 /* 50 MHz clock */ +#define SD_ACCESS_MODE_SDR50 2 /* UHS-I, 100 MHz clock */ +#define SD_ACCESS_MODE_SDR104 3 /* UHS-I, 208 MHz clock */ +#define SD_ACCESS_MODE_DDR50 4 /* UHS-I, 50 MHz clock, DDR */ + +/** + * @brief Extract up to 32 sequential bits from an array of 32-bit words + * + * Bits within the word are numbered in the increasing order from LSB to MSB. + * + * As an example, consider 2 32-bit words: + * + * 0x01234567 0x89abcdef + * + * On a little-endian system, the bytes are stored in memory as follows: + * + * 67 45 23 01 ef cd ab 89 + * + * MMC_RSP_BITS will extact bits as follows: + * + * start=0 len=4 -> result=0x00000007 + * start=0 len=12 -> result=0x00000567 + * start=28 len=8 -> result=0x000000f0 + * start=59 len=5 -> result=0x00000011 + * + * @param src array of words to extract bits from + * @param start index of the first bit to extract + * @param len number of bits to extract, 1 to 32 + * @return 32-bit word where requested bits start from LSB + */ +static inline uint32_t MMC_RSP_BITS(uint32_t *src, int start, int len) +{ + uint32_t mask = (len % 32 == 0) ? UINT_MAX : UINT_MAX >> (32 - (len % 32)); + size_t word = start / 32; + size_t shift = start % 32; + uint32_t right = src[word] >> shift; + uint32_t left = (len + shift <= 32) ? 0 : src[word + 1] << ((32 - shift) % 32); + return (left | right) & mask; +} + +/* SD R4 response (IO OCR) */ +#define SD_IO_OCR_MEM_READY (1<<31) +#define SD_IO_OCR_NUM_FUNCTIONS(ocr) (((ocr) >> 28) & 0x7) +#define SD_IO_OCR_MEM_PRESENT (1<<27) +#define SD_IO_OCR_MASK 0x00fffff0 + +/* CMD52 arguments */ +#define SD_ARG_CMD52_READ (0<<31) +#define SD_ARG_CMD52_WRITE (1<<31) +#define SD_ARG_CMD52_FUNC_SHIFT 28 +#define SD_ARG_CMD52_FUNC_MASK 0x7 +#define SD_ARG_CMD52_EXCHANGE (1<<27) +#define SD_ARG_CMD52_REG_SHIFT 9 +#define SD_ARG_CMD52_REG_MASK 0x1ffff +#define SD_ARG_CMD52_DATA_SHIFT 0 +#define SD_ARG_CMD52_DATA_MASK 0xff +#define SD_R5_DATA(resp) ((resp)[0] & 0xff) + +/* CMD53 arguments */ +#define SD_ARG_CMD53_READ (0<<31) +#define SD_ARG_CMD53_WRITE (1<<31) +#define SD_ARG_CMD53_FUNC_SHIFT 28 +#define SD_ARG_CMD53_FUNC_MASK 0x7 +#define SD_ARG_CMD53_BLOCK_MODE (1<<27) +#define SD_ARG_CMD53_INCREMENT (1<<26) +#define SD_ARG_CMD53_REG_SHIFT 9 +#define SD_ARG_CMD53_REG_MASK 0x1ffff +#define SD_ARG_CMD53_LENGTH_SHIFT 0 +#define SD_ARG_CMD53_LENGTH_MASK 0x1ff +#define SD_ARG_CMD53_LENGTH_MAX 512 + +/* Card Common Control Registers (CCCR) */ +#define SD_IO_CCCR_START 0x00000 +#define SD_IO_CCCR_SIZE 0x100 +#define SD_IO_CCCR_FN_ENABLE 0x02 +#define SD_IO_CCCR_FN_READY 0x03 +#define SD_IO_CCCR_INT_ENABLE 0x04 +#define SD_IO_CCCR_INT_PENDING 0x05 +#define SD_IO_CCCR_CTL 0x06 +#define CCCR_CTL_RES (1<<3) +#define SD_IO_CCCR_BUS_WIDTH 0x07 +#define CCCR_BUS_WIDTH_1 (0<<0) +#define CCCR_BUS_WIDTH_4 (2<<0) +#define CCCR_BUS_WIDTH_8 (3<<0) +#define CCCR_BUS_WIDTH_ECSI (1<<5) +#define SD_IO_CCCR_CARD_CAP 0x08 +#define CCCR_CARD_CAP_LSC BIT(6) +#define CCCR_CARD_CAP_4BLS BIT(7) +#define SD_IO_CCCR_CISPTR 0x09 +#define SD_IO_CCCR_BLKSIZEL 0x10 +#define SD_IO_CCCR_BLKSIZEH 0x11 +#define SD_IO_CCCR_HIGHSPEED 0x13 +#define CCCR_HIGHSPEED_SUPPORT BIT(0) +#define CCCR_HIGHSPEED_ENABLE BIT(1) + +/* Function Basic Registers (FBR) */ +#define SD_IO_FBR_START 0x00100 +#define SD_IO_FBR_SIZE 0x00700 + +/* Card Information Structure (CIS) */ +#define SD_IO_CIS_START 0x01000 +#define SD_IO_CIS_SIZE 0x17000 + +/* CIS tuple codes (based on PC Card 16) */ +#define CISTPL_CODE_NULL 0x00 +#define CISTPL_CODE_DEVICE 0x01 +#define CISTPL_CODE_CHKSUM 0x10 +#define CISTPL_CODE_VERS1 0x15 +#define CISTPL_CODE_ALTSTR 0x16 +#define CISTPL_CODE_CONFIG 0x1A +#define CISTPL_CODE_CFTABLE_ENTRY 0x1B +#define CISTPL_CODE_MANFID 0x20 +#define CISTPL_CODE_FUNCID 0x21 +#define TPLFID_FUNCTION_SDIO 0x0c +#define CISTPL_CODE_FUNCE 0x22 +#define CISTPL_CODE_VENDER_BEGIN 0x80 +#define CISTPL_CODE_VENDER_END 0x8F +#define CISTPL_CODE_SDIO_STD 0x91 +#define CISTPL_CODE_SDIO_EXT 0x92 +#define CISTPL_CODE_END 0xFF + + +/* Timing */ +#define SDMMC_TIMING_LEGACY 0 +#define SDMMC_TIMING_HIGHSPEED 1 +#define SDMMC_TIMING_MMC_DDR52 2 + +#include "py/runtime.h" + +// Logging macros +// #define ESP_LOGD(tag, string, ...) mp_printf(&mp_plat_print, string "\n" __VA_OPT__(,) __VA_ARGS__) +// #define ESP_LOGV(tag, string, ...) mp_printf(&mp_plat_print, string "\n" __VA_OPT__(,) __VA_ARGS__) +// #define ESP_LOGW(tag, string, ...) mp_printf(&mp_plat_print, string "\n" __VA_OPT__(,) __VA_ARGS__) +// #define ESP_LOGE(tag, string, ...) mp_printf(&mp_plat_print, string "\n" __VA_OPT__(,) __VA_ARGS__) + +#define ESP_LOGD(tag, string, ...) +#define ESP_LOGV(tag, string, ...) +#define ESP_LOGW(tag, string, ...) +#define ESP_LOGE(tag, string, ...) +#define TSD_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) ) + +#endif //_SDMMC_DEFS_H_ diff --git a/lib/sdmmc/include/sdmmc_types.h b/lib/sdmmc/include/sdmmc_types.h new file mode 100644 index 0000000000..79a15e2290 --- /dev/null +++ b/lib/sdmmc/include/sdmmc_types.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2006 Uwe Stuehler + * Adaptations to ESP-IDF Copyright (c) 2016 Espressif Systems (Shanghai) PTE LTD + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SDMMC_TYPES_H_ +#define _SDMMC_TYPES_H_ + +#include +#include +#include + +/** + * Decoded values from SD card Card Specific Data register + */ +typedef struct { + int csd_ver; /*!< CSD structure format */ + int mmc_ver; /*!< MMC version (for CID format) */ + int capacity; /*!< total number of sectors */ + int sector_size; /*!< sector size in bytes */ + int read_block_len; /*!< block length for reads */ + int card_command_class; /*!< Card Command Class for SD */ + int tr_speed; /*!< Max transfer speed */ +} sdmmc_csd_t; + +/** + * Decoded values from SD card Card IDentification register + */ +typedef struct { + int mfg_id; /*!< manufacturer identification number */ + int oem_id; /*!< OEM/product identification number */ + char name[8]; /*!< product name (MMC v1 has the longest) */ + int revision; /*!< product revision */ + int serial; /*!< product serial number */ + int date; /*!< manufacturing date */ +} sdmmc_cid_t; + +/** + * Decoded values from SD Configuration Register + */ +typedef struct { + int sd_spec; /*!< SD Physical layer specification version, reported by card */ + int bus_width; /*!< bus widths supported by card: BIT(0) — 1-bit bus, BIT(2) — 4-bit bus */ +} sdmmc_scr_t; + +/** + * Decoded values of Extended Card Specific Data + */ +typedef struct { + uint8_t power_class; /*!< Power class used by the card */ +} sdmmc_ext_csd_t; + +/** + * SD/MMC command response buffer + */ +typedef uint32_t sdmmc_response_t[4]; + +/** + * SD SWITCH_FUNC response buffer + */ +typedef struct { + uint32_t data[512 / 8 / sizeof(uint32_t)]; /*!< response data */ +} sdmmc_switch_func_rsp_t; + +typedef enum { + SDMMC_OK = 0, + SDMMC_ERR_NOT_SUPPORTED = 1, + SDMMC_ERR_INVALID_RESPONSE = 2, + SDMMC_ERR_TIMEOUT = 3, + SDMMC_ERR_NO_MEM = 4, + SDMMC_ERR_INVALID_SIZE = 5, + SDMMC_ERR_NO_CARD = 6, + SDMMC_ERR_INVALID_ARG = 7, + SDMMC_ERR_BUSY = 8, +} sdmmc_err_t; + +/** + * SD/MMC command information + */ +typedef struct { + uint32_t opcode; /*!< SD or MMC command index */ + uint32_t arg; /*!< SD/MMC command argument */ + sdmmc_response_t response; /*!< response buffer */ + void* data; /*!< buffer to send or read into */ + size_t datalen; /*!< length of data buffer */ + size_t blklen; /*!< block length */ + int flags; /*!< see below */ +/** @cond */ +#define SCF_ITSDONE 0x0001 /*!< command is complete */ +#define SCF_CMD(flags) ((flags) & 0x00f0) +#define SCF_CMD_AC 0x0000 +#define SCF_CMD_ADTC 0x0010 +#define SCF_CMD_BC 0x0020 +#define SCF_CMD_BCR 0x0030 +#define SCF_CMD_READ 0x0040 /*!< read command (data expected) */ +#define SCF_RSP_BSY 0x0100 +#define SCF_RSP_136 0x0200 +#define SCF_RSP_CRC 0x0400 +#define SCF_RSP_IDX 0x0800 +#define SCF_RSP_PRESENT 0x1000 +/* response types */ +#define SCF_RSP_R0 0 /*!< none */ +#define SCF_RSP_R1 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) +#define SCF_RSP_R1B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY) +#define SCF_RSP_R2 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_136) +#define SCF_RSP_R3 (SCF_RSP_PRESENT) +#define SCF_RSP_R4 (SCF_RSP_PRESENT) +#define SCF_RSP_R5 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) +#define SCF_RSP_R5B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY) +#define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) +#define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) +/* special flags */ +#define SCF_WAIT_BUSY 0x2000 /*!< Wait for completion of card busy signal before returning */ +#define SCF_AUTO_STOP 0x4000 /*!< Auto stop with command 12 */ +/** @endcond */ + sdmmc_err_t error; /*!< error returned from transfer */ + int timeout_ms; /*!< response timeout, in milliseconds */ +} sdmmc_command_t; + +/** + * SD/MMC Host description + * + * This structure defines properties of SD/MMC host and functions + * of SD/MMC host which can be used by upper layers. + */ +#define BIT(x) (1 << x) + +typedef struct { + uint32_t flags; /*!< flags defining host properties */ +#define SDMMC_HOST_FLAG_1BIT BIT(0) /*!< host supports 1-line SD and MMC protocol */ +#define SDMMC_HOST_FLAG_4BIT BIT(1) /*!< host supports 4-line SD and MMC protocol */ +#define SDMMC_HOST_FLAG_8BIT BIT(2) /*!< host supports 8-line MMC protocol */ +#define SDMMC_HOST_FLAG_SPI BIT(3) /*!< host supports SPI protocol */ +#define SDMMC_HOST_FLAG_DDR BIT(4) /*!< host supports DDR mode for SD/MMC */ +#define SDMMC_HOST_FLAG_DEINIT_ARG BIT(5) /*!< host `deinit` function called with the slot argument */ + int slot; /*!< slot number, to be passed to host functions */ + int max_freq_khz; /*!< max frequency supported by the host */ +#define SDMMC_FREQ_DEFAULT 20000 /*!< SD/MMC Default speed (limited by clock divider) */ +#define SDMMC_FREQ_HIGHSPEED 40000 /*!< SD High speed (limited by clock divider) */ +#define SDMMC_FREQ_PROBING 400 /*!< SD/MMC probing speed */ +#define SDMMC_FREQ_52M 52000 /*!< MMC 52MHz speed */ +#define SDMMC_FREQ_26M 26000 /*!< MMC 26MHz speed */ + float io_voltage; /*!< I/O voltage used by the controller (voltage switching is not supported) */ + sdmmc_err_t (*init)(void); /*!< Host function to initialize the driver */ + sdmmc_err_t (*set_bus_width)(int slot, size_t width); /*!< host function to set bus width */ + size_t (*get_bus_width)(int slot); /*!< host function to get bus width */ + sdmmc_err_t (*set_bus_ddr_mode)(int slot, bool ddr_enable); /*!< host function to set DDR mode */ + sdmmc_err_t (*set_card_clk)(int slot, uint32_t freq_khz); /*!< host function to set card clock frequency */ + sdmmc_err_t (*do_transaction)(int slot, sdmmc_command_t* cmdinfo); /*!< host function to do a transaction */ + union { + sdmmc_err_t (*deinit)(void); /*!< host function to deinitialize the driver */ + sdmmc_err_t (*deinit_p)(int slot); /*!< host function to deinitialize the driver, called with the `slot` */ + }; + sdmmc_err_t (*io_int_enable)(int slot); /*!< Host function to enable SDIO interrupt line */ + sdmmc_err_t (*io_int_wait)(int slot, int timeout_ms); /*!< Host function to wait for SDIO interrupt line to be active */ + int command_timeout_ms; /*!< timeout, in milliseconds, of a single command. Set to 0 to use the default value. */ +} sdmmc_host_t; + +/** + * SD/MMC card information structure + */ +typedef struct { + sdmmc_host_t host; /*!< Host with which the card is associated */ + uint32_t ocr; /*!< OCR (Operation Conditions Register) value */ + union { + sdmmc_cid_t cid; /*!< decoded CID (Card IDentification) register value */ + sdmmc_response_t raw_cid; /*!< raw CID of MMC card to be decoded + after the CSD is fetched in the data transfer mode*/ + }; + sdmmc_csd_t csd; /*!< decoded CSD (Card-Specific Data) register value */ + sdmmc_scr_t scr; /*!< decoded SCR (SD card Configuration Register) value */ + sdmmc_ext_csd_t ext_csd; /*!< decoded EXT_CSD (Extended Card Specific Data) register value */ + uint16_t rca; /*!< RCA (Relative Card Address) */ + uint16_t max_freq_khz; /*!< Maximum frequency, in kHz, supported by the card */ + uint32_t is_mem : 1; /*!< Bit indicates if the card is a memory card */ + uint32_t is_sdio : 1; /*!< Bit indicates if the card is an IO card */ + uint32_t is_mmc : 1; /*!< Bit indicates if the card is MMC */ + uint32_t num_io_functions : 3; /*!< If is_sdio is 1, contains the number of IO functions on the card */ + uint32_t log_bus_width : 2; /*!< log2(bus width supported by card) */ + uint32_t is_ddr : 1; /*!< Card supports DDR mode */ + uint32_t reserved : 23; /*!< Reserved for future expansion */ +} sdmmc_card_t; + +// OS abstraction layer (copied from TinyUSB) +void osal_task_delay(uint32_t msec); + +#endif // _SDMMC_TYPES_H_ diff --git a/lib/sdmmc/sdmmc_cmd.c b/lib/sdmmc/sdmmc_cmd.c new file mode 100644 index 0000000000..e2d853d765 --- /dev/null +++ b/lib/sdmmc/sdmmc_cmd.c @@ -0,0 +1,501 @@ +/* + * Copyright (c) 2006 Uwe Stuehler + * Adaptations to ESP-IDF Copyright (c) 2016-2018 Espressif Systems (Shanghai) PTE LTD + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "sdmmc_common.h" + +sdmmc_err_t sdmmc_send_cmd(sdmmc_card_t* card, sdmmc_command_t* cmd) +{ + if (card->host.command_timeout_ms != 0) { + cmd->timeout_ms = card->host.command_timeout_ms; + } else if (cmd->timeout_ms == 0) { + cmd->timeout_ms = SDMMC_DEFAULT_CMD_TIMEOUT_MS; + } + + int slot = card->host.slot; + ESP_LOGV(TAG, "sending cmd slot=%d op=%d arg=%x flags=%x data=%p blklen=%d datalen=%d timeout=%d", + slot, cmd->opcode, cmd->arg, cmd->flags, cmd->data, cmd->blklen, cmd->datalen, cmd->timeout_ms); + sdmmc_err_t err = (*card->host.do_transaction)(slot, cmd); + if (err != 0) { + ESP_LOGD(TAG, "cmd=%d, sdmmc_req_run returned 0x%x", cmd->opcode, err); + return err; + } + ESP_LOGV(TAG, "cmd response %08x %08x %08x %08x err=0x%x state=%d", + cmd->response[0], + cmd->response[1], + cmd->response[2], + cmd->response[3], + cmd->error, + MMC_R1_CURRENT_STATE(cmd->response)); + return cmd->error; +} + +sdmmc_err_t sdmmc_send_app_cmd(sdmmc_card_t* card, sdmmc_command_t* cmd) +{ + sdmmc_command_t app_cmd = { + .opcode = MMC_APP_CMD, + .flags = SCF_CMD_AC | SCF_RSP_R1, + .arg = MMC_ARG_RCA(card->rca), + }; + sdmmc_err_t err = sdmmc_send_cmd(card, &app_cmd); + if (err != SDMMC_OK) { + return err; + } + // Check APP_CMD status bit (only in SD mode) + if (!host_is_spi(card) && !(MMC_R1(app_cmd.response) & MMC_R1_APP_CMD)) { + ESP_LOGW(TAG, "card doesn't support APP_CMD"); + return SDMMC_ERR_NOT_SUPPORTED; + } + return sdmmc_send_cmd(card, cmd); +} + + +sdmmc_err_t sdmmc_send_cmd_go_idle_state(sdmmc_card_t* card) +{ + sdmmc_command_t cmd = { + .opcode = MMC_GO_IDLE_STATE, + .flags = SCF_CMD_BC | SCF_RSP_R0, + }; + sdmmc_err_t err = sdmmc_send_cmd(card, &cmd); + if (host_is_spi(card)) { + /* To enter SPI mode, CMD0 needs to be sent twice (see figure 4-1 in + * SD Simplified spec v4.10). Some cards enter SD mode on first CMD0, + * so don't expect the above command to succeed. + * SCF_RSP_R1 flag below tells the lower layer to expect correct R1 + * response (in SPI mode). + */ + (void) err; + osal_task_delay(SDMMC_GO_IDLE_DELAY_MS); + + cmd.flags |= SCF_RSP_R1; + err = sdmmc_send_cmd(card, &cmd); + } + if (err == SDMMC_OK) { + osal_task_delay(SDMMC_GO_IDLE_DELAY_MS); + } + return err; +} + + +sdmmc_err_t sdmmc_send_cmd_send_if_cond(sdmmc_card_t* card, uint32_t ocr) +{ + const uint8_t pattern = 0xaa; /* any pattern will do here */ + sdmmc_command_t cmd = { + .opcode = SD_SEND_IF_COND, + .arg = (((ocr & SD_OCR_VOL_MASK) != 0) << 8) | pattern, + .flags = SCF_CMD_BCR | SCF_RSP_R7, + }; + sdmmc_err_t err = sdmmc_send_cmd(card, &cmd); + if (err != SDMMC_OK) { + return err; + } + uint8_t response = cmd.response[0] & 0xff; + if (response != pattern) { + ESP_LOGD(TAG, "%s: received=0x%x expected=0x%x", __func__, response, pattern); + return SDMMC_ERR_INVALID_RESPONSE; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_send_cmd_send_op_cond(sdmmc_card_t* card, uint32_t ocr, uint32_t *ocrp) +{ + sdmmc_err_t err; + + sdmmc_command_t cmd = { + .arg = ocr, + .flags = SCF_CMD_BCR | SCF_RSP_R3, + .opcode = SD_APP_OP_COND + }; + int nretries = SDMMC_SEND_OP_COND_MAX_RETRIES; + int err_cnt = SDMMC_SEND_OP_COND_MAX_ERRORS; + for (; nretries != 0; --nretries) { + bzero(&cmd, sizeof cmd); + cmd.arg = ocr; + cmd.flags = SCF_CMD_BCR | SCF_RSP_R3; + if (!card->is_mmc) { /* SD mode */ + cmd.opcode = SD_APP_OP_COND; + err = sdmmc_send_app_cmd(card, &cmd); + } else { /* MMC mode */ + cmd.arg &= ~MMC_OCR_ACCESS_MODE_MASK; + cmd.arg |= MMC_OCR_SECTOR_MODE; + cmd.opcode = MMC_SEND_OP_COND; + err = sdmmc_send_cmd(card, &cmd); + } + + if (err != SDMMC_OK) { + if (--err_cnt == 0) { + ESP_LOGD(TAG, "%s: sdmmc_send_app_cmd err=0x%x", __func__, err); + return err; + } else { + ESP_LOGV(TAG, "%s: ignoring err=0x%x", __func__, err); + continue; + } + } + // In SD protocol, card sets MEM_READY bit in OCR when it is ready. + // In SPI protocol, card clears IDLE_STATE bit in R1 response. + if (!host_is_spi(card)) { + if ((MMC_R3(cmd.response) & MMC_OCR_MEM_READY) || + ocr == 0) { + break; + } + } else { + if ((SD_SPI_R1(cmd.response) & SD_SPI_R1_IDLE_STATE) == 0) { + break; + } + } + osal_task_delay(10); + } + if (nretries == 0) { + return SDMMC_ERR_TIMEOUT; + } + if (ocrp) { + *ocrp = MMC_R3(cmd.response); + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_send_cmd_read_ocr(sdmmc_card_t *card, uint32_t *ocrp) +{ + assert(ocrp); + sdmmc_command_t cmd = { + .opcode = SD_READ_OCR, + .flags = SCF_CMD_BCR | SCF_RSP_R2 + }; + sdmmc_err_t err = sdmmc_send_cmd(card, &cmd); + if (err != SDMMC_OK) { + return err; + } + *ocrp = SD_SPI_R3(cmd.response); + return SDMMC_OK; +} + + +sdmmc_err_t sdmmc_send_cmd_all_send_cid(sdmmc_card_t* card, sdmmc_response_t* out_raw_cid) +{ + assert(out_raw_cid); + sdmmc_command_t cmd = { + .opcode = MMC_ALL_SEND_CID, + .flags = SCF_CMD_BCR | SCF_RSP_R2 + }; + sdmmc_err_t err = sdmmc_send_cmd(card, &cmd); + if (err != SDMMC_OK) { + return err; + } + memcpy(out_raw_cid, &cmd.response, sizeof(sdmmc_response_t)); + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_send_cmd_send_cid(sdmmc_card_t *card, sdmmc_cid_t *out_cid) +{ + assert(out_cid); + assert(host_is_spi(card) && "SEND_CID should only be used in SPI mode"); + assert(!card->is_mmc && "MMC cards are not supported in SPI mode"); + sdmmc_response_t buf; + sdmmc_command_t cmd = { + .opcode = MMC_SEND_CID, + .flags = SCF_CMD_READ | SCF_CMD_ADTC, + .arg = 0, + .data = &buf[0], + .datalen = sizeof(buf) + }; + sdmmc_err_t err = sdmmc_send_cmd(card, &cmd); + if (err != SDMMC_OK) { + return err; + } + sdmmc_flip_byte_order(buf, sizeof(buf)); + return sdmmc_decode_cid(buf, out_cid); +} + + +sdmmc_err_t sdmmc_send_cmd_set_relative_addr(sdmmc_card_t* card, uint16_t* out_rca) +{ + assert(out_rca); + sdmmc_command_t cmd = { + .opcode = SD_SEND_RELATIVE_ADDR, + .flags = SCF_CMD_BCR | SCF_RSP_R6 + }; + + /* MMC cards expect us to set the RCA. + * Set RCA to 1 since we don't support multiple cards on the same bus, for now. + */ + uint16_t mmc_rca = 1; + if (card->is_mmc) { + cmd.arg = MMC_ARG_RCA(mmc_rca); + } + + sdmmc_err_t err = sdmmc_send_cmd(card, &cmd); + if (err != SDMMC_OK) { + return err; + } + *out_rca = (card->is_mmc) ? mmc_rca : SD_R6_RCA(cmd.response); + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_send_cmd_set_blocklen(sdmmc_card_t* card, sdmmc_csd_t* csd) +{ + sdmmc_command_t cmd = { + .opcode = MMC_SET_BLOCKLEN, + .arg = csd->sector_size, + .flags = SCF_CMD_AC | SCF_RSP_R1 + }; + return sdmmc_send_cmd(card, &cmd); +} + +sdmmc_err_t sdmmc_send_cmd_send_csd(sdmmc_card_t* card, sdmmc_csd_t* out_csd) +{ + /* The trick with SEND_CSD is that in SPI mode, it acts as a data read + * command, while in SD mode it is an AC command with R2 response. + */ + sdmmc_response_t spi_buf; + const bool is_spi = host_is_spi(card); + sdmmc_command_t cmd = { + .opcode = MMC_SEND_CSD, + .arg = is_spi ? 0 : MMC_ARG_RCA(card->rca), + .flags = is_spi ? (SCF_CMD_READ | SCF_CMD_ADTC | SCF_RSP_R1) : + (SCF_CMD_AC | SCF_RSP_R2), + .data = is_spi ? &spi_buf[0] : 0, + .datalen = is_spi ? sizeof(spi_buf) : 0, + }; + sdmmc_err_t err = sdmmc_send_cmd(card, &cmd); + if (err != SDMMC_OK) { + return err; + } + uint32_t* ptr = cmd.response; + if (is_spi) { + sdmmc_flip_byte_order(spi_buf, sizeof(spi_buf)); + ptr = spi_buf; + } + if (card->is_mmc) { + err = sdmmc_mmc_decode_csd(cmd.response, out_csd); + } else { + err = sdmmc_decode_csd(ptr, out_csd); + } + return err; +} + +sdmmc_err_t sdmmc_send_cmd_select_card(sdmmc_card_t* card, uint32_t rca) +{ + /* Don't expect to see a response when de-selecting a card */ + uint32_t response = (rca == 0) ? 0 : SCF_RSP_R1; + sdmmc_command_t cmd = { + .opcode = MMC_SELECT_CARD, + .arg = MMC_ARG_RCA(rca), + .flags = SCF_CMD_AC | response + }; + return sdmmc_send_cmd(card, &cmd); +} + +sdmmc_err_t sdmmc_send_cmd_send_scr(sdmmc_card_t* card, sdmmc_scr_t *out_scr) +{ + size_t datalen = 8; + uint32_t buf[datalen]; + sdmmc_command_t cmd = { + .data = buf, + .datalen = datalen, + .blklen = datalen, + .flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1, + .opcode = SD_APP_SEND_SCR + }; + sdmmc_err_t err = sdmmc_send_app_cmd(card, &cmd); + if (err == SDMMC_OK) { + err = sdmmc_decode_scr(buf, out_scr); + } + return err; +} + +sdmmc_err_t sdmmc_send_cmd_set_bus_width(sdmmc_card_t* card, int width) +{ + sdmmc_command_t cmd = { + .opcode = SD_APP_SET_BUS_WIDTH, + .flags = SCF_RSP_R1 | SCF_CMD_AC, + .arg = (width == 4) ? SD_ARG_BUS_WIDTH_4 : SD_ARG_BUS_WIDTH_1, + }; + + return sdmmc_send_app_cmd(card, &cmd); +} + +sdmmc_err_t sdmmc_send_cmd_crc_on_off(sdmmc_card_t* card, bool crc_enable) +{ + assert(host_is_spi(card) && "CRC_ON_OFF can only be used in SPI mode"); + sdmmc_command_t cmd = { + .opcode = SD_CRC_ON_OFF, + .arg = crc_enable ? 1 : 0, + .flags = SCF_CMD_AC | SCF_RSP_R1 + }; + return sdmmc_send_cmd(card, &cmd); +} + +sdmmc_err_t sdmmc_send_cmd_send_status(sdmmc_card_t* card, uint32_t* out_status) +{ + sdmmc_command_t cmd = { + .opcode = MMC_SEND_STATUS, + .arg = MMC_ARG_RCA(card->rca), + .flags = SCF_CMD_AC | SCF_RSP_R1 + }; + sdmmc_err_t err = sdmmc_send_cmd(card, &cmd); + if (err != SDMMC_OK) { + return err; + } + if (out_status) { + *out_status = MMC_R1(cmd.response); + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src, + size_t start_block, size_t block_count) +{ + sdmmc_err_t err = SDMMC_OK; + size_t block_size = card->csd.sector_size; + if ((intptr_t)src % 4 == 0) { + err = sdmmc_write_sectors_dma(card, src, start_block, block_count); + } else { + // SDMMC peripheral needs DMA-capable buffers. Split the write into + // separate single block writes, if needed, and allocate a temporary + // DMA-capable buffer. + uint32_t tmp_buf[block_size / sizeof(uint32_t)]; + const uint8_t* cur_src = (const uint8_t*) src; + for (size_t i = 0; i < block_count; ++i) { + memcpy(tmp_buf, cur_src, block_size); + cur_src += block_size; + err = sdmmc_write_sectors_dma(card, tmp_buf, start_block + i, 1); + if (err != SDMMC_OK) { + ESP_LOGD(TAG, "%s: error 0x%x writing block %d+%d", + __func__, err, start_block, i); + break; + } + } + } + return err; +} + +sdmmc_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src, + size_t start_block, size_t block_count) +{ + if (start_block + block_count > (size_t) card->csd.capacity) { + return SDMMC_ERR_INVALID_SIZE; + } + size_t block_size = card->csd.sector_size; + sdmmc_command_t cmd = { + .flags = SCF_CMD_ADTC | SCF_RSP_R1, + .blklen = block_size, + .data = (void*) src, + .datalen = block_count * block_size, + .timeout_ms = SDMMC_WRITE_CMD_TIMEOUT_MS + }; + if (block_count == 1) { + cmd.opcode = MMC_WRITE_BLOCK_SINGLE; + } else { + cmd.opcode = MMC_WRITE_BLOCK_MULTIPLE; + cmd.flags |= SCF_AUTO_STOP; + } + if (card->ocr & SD_OCR_SDHC_CAP) { + cmd.arg = start_block; + } else { + cmd.arg = start_block * block_size; + } + sdmmc_err_t err = sdmmc_send_cmd(card, &cmd); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: sdmmc_send_cmd returned 0x%x", __func__, err); + return err; + } + uint32_t status = 0; + size_t count = 0; + while (!host_is_spi(card) && !(status & MMC_R1_READY_FOR_DATA)) { + // TODO: add some timeout here + err = sdmmc_send_cmd_send_status(card, &status); + if (err != SDMMC_OK) { + return err; + } + if (++count % 10 == 0) { + ESP_LOGV(TAG, "waiting for card to become ready (%d)", count); + } + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst, + size_t start_block, size_t block_count) +{ + sdmmc_err_t err = SDMMC_OK; + size_t block_size = card->csd.sector_size; + if ((intptr_t)dst % 4 == 0) { + err = sdmmc_read_sectors_dma(card, dst, start_block, block_count); + } else { + // SDMMC peripheral needs DMA-capable buffers. Split the read into + // separate single block reads, if needed, and allocate a temporary + // DMA-capable buffer. + uint32_t tmp_buf[block_size / sizeof(uint32_t)]; + uint8_t* cur_dst = (uint8_t*) dst; + for (size_t i = 0; i < block_count; ++i) { + err = sdmmc_read_sectors_dma(card, tmp_buf, start_block + i, 1); + if (err != SDMMC_OK) { + ESP_LOGD(TAG, "%s: error 0x%x writing block %d+%d", + __func__, err, start_block, i); + break; + } + memcpy(cur_dst, tmp_buf, block_size); + cur_dst += block_size; + } + } + return err; +} + +sdmmc_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst, + size_t start_block, size_t block_count) +{ + if (start_block + block_count > (size_t) card->csd.capacity) { + return SDMMC_ERR_INVALID_SIZE; + } + size_t block_size = card->csd.sector_size; + sdmmc_command_t cmd = { + .flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1, + .blklen = block_size, + .data = (void*) dst, + .datalen = block_count * block_size + }; + if (block_count == 1) { + cmd.opcode = MMC_READ_BLOCK_SINGLE; + } else { + cmd.opcode = MMC_READ_BLOCK_MULTIPLE; + cmd.flags |= SCF_AUTO_STOP; + } + if (card->ocr & SD_OCR_SDHC_CAP) { + cmd.arg = start_block; + } else { + cmd.arg = start_block * block_size; + } + sdmmc_err_t err = sdmmc_send_cmd(card, &cmd); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: sdmmc_send_cmd returned 0x%x", __func__, err); + return err; + } + uint32_t status = 0; + size_t count = 0; + while (!host_is_spi(card) && !(status & MMC_R1_READY_FOR_DATA)) { + // TODO: add some timeout here + err = sdmmc_send_cmd_send_status(card, &status); + if (err != SDMMC_OK) { + return err; + } + if (++count % 10 == 0) { + ESP_LOGV(TAG, "waiting for card to become ready (%d)", count); + } + } + return SDMMC_OK; +} diff --git a/lib/sdmmc/sdmmc_common.c b/lib/sdmmc/sdmmc_common.c new file mode 100644 index 0000000000..fea29ab2b2 --- /dev/null +++ b/lib/sdmmc/sdmmc_common.c @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2006 Uwe Stuehler + * Adaptations to ESP-IDF Copyright (c) 2016-2018 Espressif Systems (Shanghai) PTE LTD + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "sdmmc_common.h" + +sdmmc_err_t sdmmc_init_ocr(sdmmc_card_t* card) +{ + sdmmc_err_t err; + /* In SPI mode, READ_OCR (CMD58) command is used to figure out which voltage + * ranges the card can support. This step is skipped since 1.8V isn't + * supported on the ESP32. + */ + + uint32_t host_ocr = get_host_ocr(card->host.io_voltage); + if ((card->ocr & SD_OCR_SDHC_CAP) != 0) { + host_ocr |= SD_OCR_SDHC_CAP; + } + /* Send SEND_OP_COND (ACMD41) command to the card until it becomes ready. */ + err = sdmmc_send_cmd_send_op_cond(card, host_ocr, &card->ocr); + + /* If time-out, re-try send_op_cond as MMC */ + if (err == SDMMC_ERR_TIMEOUT && !host_is_spi(card)) { + ESP_LOGD(TAG, "send_op_cond timeout, trying MMC"); + card->is_mmc = 1; + err = sdmmc_send_cmd_send_op_cond(card, host_ocr, &card->ocr); + } + + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: send_op_cond (1) returned 0x%x", __func__, err); + return err; + } + if (host_is_spi(card)) { + err = sdmmc_send_cmd_read_ocr(card, &card->ocr); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: read_ocr returned 0x%x", __func__, err); + return err; + } + } + ESP_LOGD(TAG, "host_ocr=0x%x card_ocr=0x%x", host_ocr, card->ocr); + + /* Clear all voltage bits in host's OCR which the card doesn't support. + * Don't touch CCS bit because in SPI mode cards don't report CCS in ACMD41 + * response. + */ + host_ocr &= (card->ocr | (~SD_OCR_VOL_MASK)); + ESP_LOGD(TAG, "sdmmc_card_init: host_ocr=%08x, card_ocr=%08x", host_ocr, card->ocr); + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_init_cid(sdmmc_card_t* card) +{ + sdmmc_err_t err; + sdmmc_response_t raw_cid; + if (!host_is_spi(card)) { + err = sdmmc_send_cmd_all_send_cid(card, &raw_cid); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: all_send_cid returned 0x%x", __func__, err); + return err; + } + if (!card->is_mmc) { + err = sdmmc_decode_cid(raw_cid, &card->cid); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: decoding CID failed (0x%x)", __func__, err); + return err; + } + } else { + /* For MMC, need to know CSD to decode CID. But CSD can only be read + * in data transfer mode, and it is not possible to read CID in data + * transfer mode. We temporiliy store the raw cid and do the + * decoding after the RCA is set and the card is in data transfer + * mode. + */ + memcpy(card->raw_cid, raw_cid, sizeof(sdmmc_response_t)); + } + } else { + err = sdmmc_send_cmd_send_cid(card, &card->cid); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: send_cid returned 0x%x", __func__, err); + return err; + } + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_init_rca(sdmmc_card_t* card) +{ + sdmmc_err_t err; + err = sdmmc_send_cmd_set_relative_addr(card, &card->rca); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: set_relative_addr returned 0x%x", __func__, err); + return err; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_init_mmc_decode_cid(sdmmc_card_t* card) +{ + sdmmc_err_t err; + sdmmc_response_t raw_cid; + memcpy(raw_cid, card->raw_cid, sizeof(raw_cid)); + err = sdmmc_mmc_decode_cid(card->csd.mmc_ver, raw_cid, &card->cid); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: decoding CID failed (0x%x)", __func__, err); + return err; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_init_csd(sdmmc_card_t* card) +{ + assert(card->is_mem == 1); + /* Get and decode the contents of CSD register. Determine card capacity. */ + sdmmc_err_t err = sdmmc_send_cmd_send_csd(card, &card->csd); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: send_csd returned 0x%x", __func__, err); + return err; + } + const size_t max_sdsc_capacity = UINT32_MAX / card->csd.sector_size + 1; + if (!(card->ocr & SD_OCR_SDHC_CAP) && + (size_t) card->csd.capacity > max_sdsc_capacity) { + ESP_LOGW(TAG, "%s: SDSC card reports capacity=%u. Limiting to %u.", + __func__, card->csd.capacity, max_sdsc_capacity); + card->csd.capacity = max_sdsc_capacity; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_init_select_card(sdmmc_card_t* card) +{ + assert(!host_is_spi(card)); + sdmmc_err_t err = sdmmc_send_cmd_select_card(card, card->rca); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: select_card returned 0x%x", __func__, err); + return err; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_init_card_hs_mode(sdmmc_card_t* card) +{ + sdmmc_err_t err = SDMMC_ERR_NOT_SUPPORTED; + if (card->is_mem && !card->is_mmc) { + err = sdmmc_enable_hs_mode_and_check(card); + } else if (card->is_sdio) { + err = sdmmc_io_enable_hs_mode(card); + } else if (card->is_mmc){ + err = sdmmc_mmc_enable_hs_mode(card); + } + if (err == SDMMC_ERR_NOT_SUPPORTED) { + ESP_LOGD(TAG, "%s: host supports HS mode, but card doesn't", __func__); + card->max_freq_khz = SDMMC_FREQ_DEFAULT; + } else if (err != SDMMC_OK) { + return err; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_init_host_bus_width(sdmmc_card_t* card) +{ + int bus_width = 1; + + if ((card->host.flags & SDMMC_HOST_FLAG_4BIT) && + (card->log_bus_width == 2)) { + bus_width = 4; + } else if ((card->host.flags & SDMMC_HOST_FLAG_8BIT) && + (card->log_bus_width == 3)) { + bus_width = 8; + } + ESP_LOGD(TAG, "%s: using %d-bit bus", __func__, bus_width); + if (bus_width > 1) { + sdmmc_err_t err = (*card->host.set_bus_width)(card->host.slot, bus_width); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "host.set_bus_width failed (0x%x)", err); + return err; + } + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_init_host_frequency(sdmmc_card_t* card) +{ + assert(card->max_freq_khz <= card->host.max_freq_khz); + + /* Find highest frequency in the following list, + * which is below card->max_freq_khz. + */ + const uint32_t freq_values[] = { + SDMMC_FREQ_52M, + SDMMC_FREQ_HIGHSPEED, + SDMMC_FREQ_26M, + SDMMC_FREQ_DEFAULT + //NOTE: in sdspi mode, 20MHz may not work. in that case, add 10MHz here. + }; + const int n_freq_values = sizeof(freq_values) / sizeof(freq_values[0]); + + uint32_t selected_freq = SDMMC_FREQ_PROBING; + for (int i = 0; i < n_freq_values; ++i) { + uint32_t freq = freq_values[i]; + if (card->max_freq_khz >= freq) { + selected_freq = freq; + break; + } + } + + ESP_LOGD(TAG, "%s: using %d kHz bus frequency", __func__, selected_freq); + if (selected_freq > SDMMC_FREQ_PROBING) { + sdmmc_err_t err = (*card->host.set_card_clk)(card->host.slot, selected_freq); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "failed to switch bus frequency (0x%x)", err); + return err; + } + } + + if (card->is_ddr) { + if (card->host.set_bus_ddr_mode == NULL) { + ESP_LOGE(TAG, "host doesn't support DDR mode or voltage switching"); + return SDMMC_ERR_NOT_SUPPORTED; + } + sdmmc_err_t err = (*card->host.set_bus_ddr_mode)(card->host.slot, true); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "failed to switch bus to DDR mode (0x%x)", err); + return err; + } + } + return SDMMC_OK; +} + +void sdmmc_flip_byte_order(uint32_t* response, size_t size) +{ + assert(size % (2 * sizeof(uint32_t)) == 0); + const size_t n_words = size / sizeof(uint32_t); + for (size_t i = 0; i < n_words / 2; ++i) { + uint32_t left = __builtin_bswap32(response[i]); + uint32_t right = __builtin_bswap32(response[n_words - i - 1]); + response[i] = right; + response[n_words - i - 1] = left; + } +} + +void sdmmc_card_print_info(FILE* stream, const sdmmc_card_t* card) +{ + // bool print_scr = false; + // bool print_csd = false; + // const char* type; + // fprintf(stream, "Name: %s\n", card->cid.name); + // if (card->is_sdio) { + // type = "SDIO"; + // print_scr = true; + // print_csd = true; + // } else if (card->is_mmc) { + // type = "MMC"; + // print_csd = true; + // } else { + // type = (card->ocr & SD_OCR_SDHC_CAP) ? "SDHC/SDXC" : "SDSC"; + // } + // fprintf(stream, "Type: %s\n", type); + // if (card->max_freq_khz < 1000) { + // fprintf(stream, "Speed: %d kHz\n", card->max_freq_khz); + // } else { + // fprintf(stream, "Speed: %d MHz%s\n", card->max_freq_khz / 1000, + // card->is_ddr ? ", DDR" : ""); + // } + // fprintf(stream, "Size: %luMB\n", ((uint64_t) card->csd.capacity) * card->csd.sector_size / (1024 * 1024)); + + // if (print_csd) { + // fprintf(stream, "CSD: ver=%d, sector_size=%d, capacity=%d read_bl_len=%d\n", + // card->csd.csd_ver, + // card->csd.sector_size, card->csd.capacity, card->csd.read_block_len); + // } + // if (print_scr) { + // fprintf(stream, "SCR: sd_spec=%d, bus_width=%d\n", card->scr.sd_spec, card->scr.bus_width); + // } +} + +sdmmc_err_t sdmmc_fix_host_flags(sdmmc_card_t* card) +{ + const uint32_t width_1bit = SDMMC_HOST_FLAG_1BIT; + const uint32_t width_4bit = SDMMC_HOST_FLAG_4BIT; + const uint32_t width_8bit = SDMMC_HOST_FLAG_8BIT; + const uint32_t width_mask = width_1bit | width_4bit | width_8bit; + + int slot_bit_width = card->host.get_bus_width(card->host.slot); + if (slot_bit_width == 1 && + (card->host.flags & (width_4bit | width_8bit))) { + card->host.flags &= ~width_mask; + card->host.flags |= width_1bit; + } else if (slot_bit_width == 4 && (card->host.flags & width_8bit)) { + if ((card->host.flags & width_4bit) == 0) { + ESP_LOGW(TAG, "slot width set to 4, but host flags don't have 4 line mode enabled; using 1 line mode"); + card->host.flags &= ~width_mask; + card->host.flags |= width_1bit; + } else { + card->host.flags &= ~width_mask; + card->host.flags |= width_4bit; + } + } + return SDMMC_OK; +} diff --git a/lib/sdmmc/sdmmc_common.h b/lib/sdmmc/sdmmc_common.h new file mode 100644 index 0000000000..583bf9d8fe --- /dev/null +++ b/lib/sdmmc/sdmmc_common.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2006 Uwe Stuehler + * Adaptations to ESP-IDF Copyright (c) 2016-2018 Espressif Systems (Shanghai) PTE LTD + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#pragma once + +#include +#include "sdmmc_defs.h" +#include "sdmmc_types.h" +#include "sdmmc_cmd.h" + +#define SDMMC_GO_IDLE_DELAY_MS 20 +#define SDMMC_IO_SEND_OP_COND_DELAY_MS 10 + +/* These delay values are mostly useful for cases when CD pin is not used, and + * the card is removed. In this case, SDMMC peripheral may not always return + * CMD_DONE / DATA_DONE interrupts after signaling the error. These timeouts work + * as a safety net in such cases. + */ +#define SDMMC_DEFAULT_CMD_TIMEOUT_MS 1000 // Max timeout of ordinary commands +#define SDMMC_WRITE_CMD_TIMEOUT_MS 5000 // Max timeout of write commands + +/* Maximum retry/error count for SEND_OP_COND (CMD1). + * These are somewhat arbitrary, values originate from OpenBSD driver. + */ +#define SDMMC_SEND_OP_COND_MAX_RETRIES 100 +#define SDMMC_SEND_OP_COND_MAX_ERRORS 3 + +/* Functions to send individual commands */ +sdmmc_err_t sdmmc_send_cmd(sdmmc_card_t* card, sdmmc_command_t* cmd); +sdmmc_err_t sdmmc_send_app_cmd(sdmmc_card_t* card, sdmmc_command_t* cmd); +sdmmc_err_t sdmmc_send_cmd_go_idle_state(sdmmc_card_t* card); +sdmmc_err_t sdmmc_send_cmd_send_if_cond(sdmmc_card_t* card, uint32_t ocr); +sdmmc_err_t sdmmc_send_cmd_send_op_cond(sdmmc_card_t* card, uint32_t ocr, uint32_t *ocrp); +sdmmc_err_t sdmmc_send_cmd_read_ocr(sdmmc_card_t *card, uint32_t *ocrp); +sdmmc_err_t sdmmc_send_cmd_send_cid(sdmmc_card_t *card, sdmmc_cid_t *out_cid); +sdmmc_err_t sdmmc_send_cmd_all_send_cid(sdmmc_card_t* card, sdmmc_response_t* out_raw_cid); +sdmmc_err_t sdmmc_send_cmd_set_relative_addr(sdmmc_card_t* card, uint16_t* out_rca); +sdmmc_err_t sdmmc_send_cmd_set_blocklen(sdmmc_card_t* card, sdmmc_csd_t* csd); +sdmmc_err_t sdmmc_send_cmd_switch_func(sdmmc_card_t* card, + uint32_t mode, uint32_t group, uint32_t function, + sdmmc_switch_func_rsp_t* resp); +sdmmc_err_t sdmmc_send_cmd_send_csd(sdmmc_card_t* card, sdmmc_csd_t* out_csd); +sdmmc_err_t sdmmc_send_cmd_select_card(sdmmc_card_t* card, uint32_t rca); +sdmmc_err_t sdmmc_send_cmd_send_scr(sdmmc_card_t* card, sdmmc_scr_t *out_scr); +sdmmc_err_t sdmmc_send_cmd_set_bus_width(sdmmc_card_t* card, int width); +sdmmc_err_t sdmmc_send_cmd_send_status(sdmmc_card_t* card, uint32_t* out_status); +sdmmc_err_t sdmmc_send_cmd_crc_on_off(sdmmc_card_t* card, bool crc_enable); + +/* Higher level functions */ +sdmmc_err_t sdmmc_enable_hs_mode(sdmmc_card_t* card); +sdmmc_err_t sdmmc_enable_hs_mode_and_check(sdmmc_card_t* card); +sdmmc_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src, + size_t start_block, size_t block_count); +sdmmc_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst, + size_t start_block, size_t block_count); + +/* SD specific */ +sdmmc_err_t sdmmc_check_scr(sdmmc_card_t* card); +sdmmc_err_t sdmmc_decode_cid(sdmmc_response_t resp, sdmmc_cid_t* out_cid); +sdmmc_err_t sdmmc_decode_csd(sdmmc_response_t response, sdmmc_csd_t* out_csd); +sdmmc_err_t sdmmc_decode_scr(uint32_t *raw_scr, sdmmc_scr_t* out_scr); + +/* SDIO specific */ +sdmmc_err_t sdmmc_io_reset(sdmmc_card_t* card); +sdmmc_err_t sdmmc_io_enable_hs_mode(sdmmc_card_t* card); +sdmmc_err_t sdmmc_io_send_op_cond(sdmmc_card_t* card, uint32_t ocr, uint32_t *ocrp); +sdmmc_err_t sdmmc_io_rw_direct(sdmmc_card_t* card, int function, + uint32_t reg, uint32_t arg, uint8_t *byte); +sdmmc_err_t sdmmc_io_rw_extended(sdmmc_card_t* card, int function, + uint32_t reg, int arg, void *data, size_t size); + + +/* MMC specific */ +sdmmc_err_t sdmmc_mmc_send_ext_csd_data(sdmmc_card_t* card, void *out_data, size_t datalen); +sdmmc_err_t sdmmc_mmc_switch(sdmmc_card_t* card, uint8_t set, uint8_t index, uint8_t value); +sdmmc_err_t sdmmc_mmc_decode_cid(int mmc_ver, sdmmc_response_t resp, sdmmc_cid_t* out_cid); +sdmmc_err_t sdmmc_mmc_decode_csd(sdmmc_response_t response, sdmmc_csd_t* out_csd); +sdmmc_err_t sdmmc_mmc_enable_hs_mode(sdmmc_card_t* card); + +/* Parts of card initialization flow */ +sdmmc_err_t sdmmc_init_sd_if_cond(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_select_card(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_csd(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_cid(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_rca(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_mmc_decode_cid(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_ocr(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_spi_crc(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_io(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_sd_blocklen(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_sd_scr(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_sd_wait_data_ready(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_mmc_read_ext_csd(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_mmc_read_cid(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_host_bus_width(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_sd_bus_width(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_io_bus_width(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_mmc_bus_width(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_card_hs_mode(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_host_frequency(sdmmc_card_t* card); +sdmmc_err_t sdmmc_init_mmc_check_csd(sdmmc_card_t* card); + +/* Various helper functions */ +static inline bool host_is_spi(const sdmmc_card_t* card) +{ + return (card->host.flags & SDMMC_HOST_FLAG_SPI) != 0; +} + +static inline uint32_t get_host_ocr(float voltage) +{ + // TODO: report exact voltage to the card + // For now tell that the host has 2.8-3.6V voltage range + (void) voltage; + return SD_OCR_VOL_MASK; +} + +void sdmmc_flip_byte_order(uint32_t* response, size_t size); + +sdmmc_err_t sdmmc_fix_host_flags(sdmmc_card_t* card); diff --git a/lib/sdmmc/sdmmc_init.c b/lib/sdmmc/sdmmc_init.c new file mode 100644 index 0000000000..de5c739f82 --- /dev/null +++ b/lib/sdmmc/sdmmc_init.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2006 Uwe Stuehler + * Adaptations to ESP-IDF Copyright (c) 2016-2018 Espressif Systems (Shanghai) PTE LTD + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "sdmmc_common.h" + +#define SDMMC_INIT_STEP(condition, function) \ + do { \ + if ((condition)) { \ + sdmmc_err_t err = (function)(card); \ + if (err != SDMMC_OK) { \ + ESP_LOGD(TAG, "%s: %s returned 0x%x", __func__, #function, err); \ + return err; \ + } \ + } \ + } while(0); + + +sdmmc_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card) +{ + memset(card, 0, sizeof(*card)); + memcpy(&card->host, config, sizeof(*config)); + const bool is_spi = host_is_spi(card); + const bool always = true; + const bool io_supported = true; + + /* Check if host flags are compatible with slot configuration. */ + SDMMC_INIT_STEP(!is_spi, sdmmc_fix_host_flags); + + /* Reset SDIO (CMD52, RES) before re-initializing IO (CMD5). */ + SDMMC_INIT_STEP(io_supported, sdmmc_io_reset); + + /* GO_IDLE_STATE (CMD0) command resets the card */ + SDMMC_INIT_STEP(always, sdmmc_send_cmd_go_idle_state); + + /* SEND_IF_COND (CMD8) command is used to identify SDHC/SDXC cards. */ + SDMMC_INIT_STEP(always, sdmmc_init_sd_if_cond); + + /* IO_SEND_OP_COND(CMD5), Determine if the card is an IO card. */ + SDMMC_INIT_STEP(io_supported, sdmmc_init_io); + + const bool is_mem = card->is_mem; + const bool is_sdio = !is_mem; + + /* Enable CRC16 checks for data transfers in SPI mode */ + SDMMC_INIT_STEP(is_spi, sdmmc_init_spi_crc); + + /* Use SEND_OP_COND to set up card OCR */ + SDMMC_INIT_STEP(is_mem, sdmmc_init_ocr); + + const bool is_mmc = is_mem && card->is_mmc; + const bool is_sdmem = is_mem && !is_mmc; + + ESP_LOGD(TAG, "%s: card type is %s", __func__, + is_sdio ? "SDIO" : is_mmc ? "MMC" : "SD"); + + /* Read the contents of CID register*/ + SDMMC_INIT_STEP(is_mem, sdmmc_init_cid); + + /* Assign RCA */ + SDMMC_INIT_STEP(!is_spi, sdmmc_init_rca); + + /* Read and decode the contents of CSD register */ + SDMMC_INIT_STEP(is_mem, sdmmc_init_csd); + + /* Decode the contents of mmc CID register */ + SDMMC_INIT_STEP(is_mmc && !is_spi, sdmmc_init_mmc_decode_cid); + + /* Switch the card from stand-by mode to data transfer mode (not needed if + * SPI interface is used). This is needed to issue SET_BLOCKLEN and + * SEND_SCR commands. + */ + SDMMC_INIT_STEP(!is_spi, sdmmc_init_select_card); + + /* SD memory cards: + * Set block len for SDSC cards to 512 bytes (same as SDHC) + * Read SCR + * Wait to enter data transfer state + */ + SDMMC_INIT_STEP(is_sdmem, sdmmc_init_sd_blocklen); + SDMMC_INIT_STEP(is_sdmem, sdmmc_init_sd_scr); + SDMMC_INIT_STEP(is_sdmem, sdmmc_init_sd_wait_data_ready); + + /* MMC cards: read CXD */ + SDMMC_INIT_STEP(is_mmc, sdmmc_init_mmc_read_ext_csd); + + /* Try to switch card to HS mode if the card supports it. + * Set card->max_freq_khz value accordingly. + */ + SDMMC_INIT_STEP(always, sdmmc_init_card_hs_mode); + + /* Set bus width. One call for every kind of card, then one for the host */ + if (!is_spi) { + SDMMC_INIT_STEP(is_sdmem, sdmmc_init_sd_bus_width); + SDMMC_INIT_STEP(is_sdio, sdmmc_init_io_bus_width); + SDMMC_INIT_STEP(is_mmc, sdmmc_init_mmc_bus_width); + SDMMC_INIT_STEP(always, sdmmc_init_host_bus_width); + } + + /* Switch to the host to use card->max_freq_khz frequency. */ + SDMMC_INIT_STEP(always, sdmmc_init_host_frequency); + + /* Sanity check after switching the bus mode and frequency */ + SDMMC_INIT_STEP(is_sdmem, sdmmc_check_scr); + /* TODO: this is CMD line only, add data checks for eMMC */ + SDMMC_INIT_STEP(is_mmc, sdmmc_init_mmc_check_csd); + /* TODO: add similar checks for SDIO */ + + return SDMMC_OK; +} diff --git a/lib/sdmmc/sdmmc_io.c b/lib/sdmmc/sdmmc_io.c new file mode 100644 index 0000000000..369be8c233 --- /dev/null +++ b/lib/sdmmc/sdmmc_io.c @@ -0,0 +1,633 @@ +/* + * Copyright (c) 2006 Uwe Stuehler + * Adaptations to ESP-IDF Copyright (c) 2016-2018 Espressif Systems (Shanghai) PTE LTD + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "sdmmc_common.h" + + +#define CIS_TUPLE(NAME) (cis_tuple_t) {.code=CISTPL_CODE_##NAME, .name=#NAME, .func=&cis_tuple_func_default, } +#define CIS_TUPLE_WITH_FUNC(NAME, FUNC) (cis_tuple_t) {.code=CISTPL_CODE_##NAME, .name=#NAME, .func=&(FUNC), } + +#define CIS_CHECK_SIZE(SIZE, MINIMAL) do {int store_size = (SIZE); if((store_size) < (MINIMAL)) return SDMMC_ERR_INVALID_SIZE;} while(0) +#define CIS_CHECK_UNSUPPORTED(COND) do {if(!(COND)) return SDMMC_ERR_NOT_SUPPORTED;} while(0) +#define CIS_GET_MINIMAL_SIZE 32 + +typedef sdmmc_err_t (*cis_tuple_info_func_t)(const void* tuple_info, uint8_t* data, FILE* fp); + +typedef struct { + int code; + const char *name; + cis_tuple_info_func_t func; +} cis_tuple_t; + +static sdmmc_err_t cis_tuple_func_default(const void* p, uint8_t* data, FILE* fp); +static sdmmc_err_t cis_tuple_func_manfid(const void* p, uint8_t* data, FILE* fp); +static sdmmc_err_t cis_tuple_func_cftable_entry(const void* p, uint8_t* data, FILE* fp); +static sdmmc_err_t cis_tuple_func_end(const void* p, uint8_t* data, FILE* fp); + +static const cis_tuple_t cis_table[] = { + CIS_TUPLE(NULL), + CIS_TUPLE(DEVICE), + CIS_TUPLE(CHKSUM), + CIS_TUPLE(VERS1), + CIS_TUPLE(ALTSTR), + CIS_TUPLE(CONFIG), + CIS_TUPLE_WITH_FUNC(CFTABLE_ENTRY, cis_tuple_func_cftable_entry), + CIS_TUPLE_WITH_FUNC(MANFID, cis_tuple_func_manfid), + CIS_TUPLE(FUNCID), + CIS_TUPLE(FUNCE), + CIS_TUPLE(VENDER_BEGIN), + CIS_TUPLE(VENDER_END), + CIS_TUPLE(SDIO_STD), + CIS_TUPLE(SDIO_EXT), + CIS_TUPLE_WITH_FUNC(END, cis_tuple_func_end), +}; + + +sdmmc_err_t sdmmc_io_reset(sdmmc_card_t* card) +{ + uint8_t sdio_reset = CCCR_CTL_RES; + sdmmc_err_t err = sdmmc_io_rw_direct(card, 0, SD_IO_CCCR_CTL, SD_ARG_CMD52_WRITE, &sdio_reset); + if (err == SDMMC_ERR_TIMEOUT || (host_is_spi(card) && err == SDMMC_ERR_NOT_SUPPORTED)) { + /* Non-IO cards are allowed to time out (in SD mode) or + * return "invalid command" error (in SPI mode). + */ + } else if (err == SDMMC_ERR_NO_CARD) { + ESP_LOGD(TAG, "%s: card not present", __func__); + return err; + } else if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: unexpected return: 0x%x", __func__, err ); + return err; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_init_io(sdmmc_card_t* card) +{ + /* IO_SEND_OP_COND(CMD5), Determine if the card is an IO card. + * Non-IO cards will not respond to this command. + */ + sdmmc_err_t err = sdmmc_io_send_op_cond(card, 0, &card->ocr); + if (err != SDMMC_OK) { + ESP_LOGD(TAG, "%s: io_send_op_cond (1) returned 0x%x; not IO card", __func__, err); + card->is_sdio = 0; + card->is_mem = 1; + } else { + card->is_sdio = 1; + + if (card->ocr & SD_IO_OCR_MEM_PRESENT) { + ESP_LOGD(TAG, "%s: IO-only card", __func__); + card->is_mem = 0; + } + card->num_io_functions = SD_IO_OCR_NUM_FUNCTIONS(card->ocr); + ESP_LOGD(TAG, "%s: number of IO functions: %d", __func__, card->num_io_functions); + if (card->num_io_functions == 0) { + card->is_sdio = 0; + } + uint32_t host_ocr = get_host_ocr(card->host.io_voltage); + host_ocr &= card->ocr; + err = sdmmc_io_send_op_cond(card, host_ocr, &card->ocr); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: sdmmc_io_send_op_cond (1) returned 0x%x", __func__, err); + return err; + } + err = sdmmc_io_enable_int(card); + if (err != SDMMC_OK) { + ESP_LOGD(TAG, "%s: sdmmc_enable_int failed (0x%x)", __func__, err); + } + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_init_io_bus_width(sdmmc_card_t* card) +{ + sdmmc_err_t err; + card->log_bus_width = 0; + if (card->host.flags & SDMMC_HOST_FLAG_4BIT) { + uint8_t card_cap = 0; + err = sdmmc_io_rw_direct(card, 0, SD_IO_CCCR_CARD_CAP, + SD_ARG_CMD52_READ, &card_cap); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: sdmmc_io_rw_direct (read SD_IO_CCCR_CARD_CAP) returned 0x%0x", __func__, err); + return err; + } + ESP_LOGD(TAG, "IO card capabilities byte: %02x", card_cap); + if (!(card_cap & CCCR_CARD_CAP_LSC) || + (card_cap & CCCR_CARD_CAP_4BLS)) { + // This card supports 4-bit bus mode + uint8_t bus_width = CCCR_BUS_WIDTH_4; + err = sdmmc_io_rw_direct(card, 0, SD_IO_CCCR_BUS_WIDTH, + SD_ARG_CMD52_WRITE, &bus_width); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: sdmmc_io_rw_direct (write SD_IO_CCCR_BUS_WIDTH) returned 0x%0x", __func__, err); + return err; + } + card->log_bus_width = 2; + } + } + return SDMMC_OK; +} + + +sdmmc_err_t sdmmc_io_enable_hs_mode(sdmmc_card_t* card) +{ + /* If the host is configured to use low frequency, don't attempt to switch */ + if (card->host.max_freq_khz < SDMMC_FREQ_DEFAULT) { + card->max_freq_khz = card->host.max_freq_khz; + return SDMMC_OK; + } else if (card->host.max_freq_khz < SDMMC_FREQ_HIGHSPEED) { + card->max_freq_khz = SDMMC_FREQ_DEFAULT; + return SDMMC_OK; + } + + /* For IO cards, do write + read operation on "High Speed" register, + * setting EHS bit. If both EHS and SHS read back as set, then HS mode + * has been enabled. + */ + uint8_t val = CCCR_HIGHSPEED_ENABLE; + sdmmc_err_t err = sdmmc_io_rw_direct(card, 0, SD_IO_CCCR_HIGHSPEED, + SD_ARG_CMD52_WRITE | SD_ARG_CMD52_EXCHANGE, &val); + if (err != SDMMC_OK) { + ESP_LOGD(TAG, "%s: sdmmc_io_rw_direct returned 0x%x", __func__, err); + return err; + } + + ESP_LOGD(TAG, "%s: CCCR_HIGHSPEED=0x%02x", __func__, val); + const uint8_t hs_mask = CCCR_HIGHSPEED_ENABLE | CCCR_HIGHSPEED_SUPPORT; + if ((val & hs_mask) != hs_mask) { + return SDMMC_ERR_NOT_SUPPORTED; + } + card->max_freq_khz = SDMMC_FREQ_HIGHSPEED; + return SDMMC_OK; +} + + +sdmmc_err_t sdmmc_io_send_op_cond(sdmmc_card_t* card, uint32_t ocr, uint32_t *ocrp) +{ + sdmmc_err_t err = SDMMC_OK; + sdmmc_command_t cmd = { + .flags = SCF_CMD_BCR | SCF_RSP_R4, + .arg = ocr, + .opcode = SD_IO_SEND_OP_COND + }; + for (size_t i = 0; i < 100; i++) { + err = sdmmc_send_cmd(card, &cmd); + if (err != SDMMC_OK) { + break; + } + if ((MMC_R4(cmd.response) & SD_IO_OCR_MEM_READY) || + ocr == 0) { + break; + } + err = SDMMC_ERR_TIMEOUT; + osal_task_delay(SDMMC_IO_SEND_OP_COND_DELAY_MS); + } + if (err == SDMMC_OK && ocrp != NULL) + *ocrp = MMC_R4(cmd.response); + + return err; +} + +sdmmc_err_t sdmmc_io_rw_direct(sdmmc_card_t* card, int func, + uint32_t reg, uint32_t arg, uint8_t *data) +{ + sdmmc_err_t err; + sdmmc_command_t cmd = { + .flags = SCF_CMD_AC | SCF_RSP_R5, + .arg = 0, + .opcode = SD_IO_RW_DIRECT + }; + + arg |= (func & SD_ARG_CMD52_FUNC_MASK) << SD_ARG_CMD52_FUNC_SHIFT; + arg |= (reg & SD_ARG_CMD52_REG_MASK) << SD_ARG_CMD52_REG_SHIFT; + arg |= (*data & SD_ARG_CMD52_DATA_MASK) << SD_ARG_CMD52_DATA_SHIFT; + cmd.arg = arg; + + err = sdmmc_send_cmd(card, &cmd); + if (err != SDMMC_OK) { + ESP_LOGV(TAG, "%s: sdmmc_send_cmd returned 0x%x", __func__, err); + return err; + } + + *data = SD_R5_DATA(cmd.response); + + return SDMMC_OK; +} + + +sdmmc_err_t sdmmc_io_read_byte(sdmmc_card_t* card, uint32_t function, + uint32_t addr, uint8_t *out_byte) +{ + sdmmc_err_t ret = sdmmc_io_rw_direct(card, function, addr, SD_ARG_CMD52_READ, out_byte); + if (ret != SDMMC_OK) { + ESP_LOGE(TAG, "%s: sdmmc_io_rw_direct (read 0x%x) returned 0x%x", __func__, addr, ret); + } + return ret; +} + +sdmmc_err_t sdmmc_io_write_byte(sdmmc_card_t* card, uint32_t function, + uint32_t addr, uint8_t in_byte, uint8_t* out_byte) +{ + uint8_t tmp_byte = in_byte; + sdmmc_err_t ret = sdmmc_io_rw_direct(card, function, addr, + SD_ARG_CMD52_WRITE | SD_ARG_CMD52_EXCHANGE, &tmp_byte); + if (ret != SDMMC_OK) { + ESP_LOGE(TAG, "%s: sdmmc_io_rw_direct (write 0x%x) returned 0x%x", __func__, addr, ret); + return ret; + } + if (out_byte != NULL) { + *out_byte = tmp_byte; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_io_rw_extended(sdmmc_card_t* card, int func, + uint32_t reg, int arg, void *datap, size_t datalen) +{ + sdmmc_err_t err; + const size_t max_byte_transfer_size = 512; + sdmmc_command_t cmd = { + .flags = SCF_CMD_AC | SCF_RSP_R5, + .arg = 0, + .opcode = SD_IO_RW_EXTENDED, + .data = datap, + .datalen = datalen, + .blklen = max_byte_transfer_size /* TODO: read max block size from CIS */ + }; + + uint32_t count; /* number of bytes or blocks, depending on transfer mode */ + if (arg & SD_ARG_CMD53_BLOCK_MODE) { + if (cmd.datalen % cmd.blklen != 0) { + return SDMMC_ERR_INVALID_SIZE; + } + count = cmd.datalen / cmd.blklen; + } else { + if (datalen > max_byte_transfer_size) { + /* TODO: split into multiple operations? */ + return SDMMC_ERR_INVALID_SIZE; + } + if (datalen == max_byte_transfer_size) { + count = 0; // See 5.3.1 SDIO simplifed spec + } else { + count = datalen; + } + cmd.blklen = datalen; + } + + arg |= (func & SD_ARG_CMD53_FUNC_MASK) << SD_ARG_CMD53_FUNC_SHIFT; + arg |= (reg & SD_ARG_CMD53_REG_MASK) << SD_ARG_CMD53_REG_SHIFT; + arg |= (count & SD_ARG_CMD53_LENGTH_MASK) << SD_ARG_CMD53_LENGTH_SHIFT; + cmd.arg = arg; + + if ((arg & SD_ARG_CMD53_WRITE) == 0) { + cmd.flags |= SCF_CMD_READ; + } + + err = sdmmc_send_cmd(card, &cmd); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: sdmmc_send_cmd returned 0x%x", __func__, err); + return err; + } + + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_io_read_bytes(sdmmc_card_t* card, uint32_t function, + uint32_t addr, void* dst, size_t size) +{ + /* host quirk: SDIO transfer with length not divisible by 4 bytes + * has to be split into two transfers: one with aligned length, + * the other one for the remaining 1-3 bytes. + */ + uint8_t *pc_dst = dst; + while (size > 0) { + size_t size_aligned = size & (~3); + size_t will_transfer = size_aligned > 0 ? size_aligned : size; + + sdmmc_err_t err = sdmmc_io_rw_extended(card, function, addr, + SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT, + pc_dst, will_transfer); + if (err != SDMMC_OK) { + return err; + } + pc_dst += will_transfer; + size -= will_transfer; + addr += will_transfer; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_io_write_bytes(sdmmc_card_t* card, uint32_t function, + uint32_t addr, const void* src, size_t size) +{ + /* same host quirk as in sdmmc_io_read_bytes */ + const uint8_t *pc_src = (const uint8_t*) src; + + while (size > 0) { + size_t size_aligned = size & (~3); + size_t will_transfer = size_aligned > 0 ? size_aligned : size; + + sdmmc_err_t err = sdmmc_io_rw_extended(card, function, addr, + SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT, + (void*) pc_src, will_transfer); + if (err != SDMMC_OK) { + return err; + } + pc_src += will_transfer; + size -= will_transfer; + addr += will_transfer; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_io_read_blocks(sdmmc_card_t* card, uint32_t function, + uint32_t addr, void* dst, size_t size) +{ + if (size % 4 != 0) { + return SDMMC_ERR_INVALID_SIZE; + } + return sdmmc_io_rw_extended(card, function, addr, + SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT | SD_ARG_CMD53_BLOCK_MODE, + dst, size); +} + +sdmmc_err_t sdmmc_io_write_blocks(sdmmc_card_t* card, uint32_t function, + uint32_t addr, const void* src, size_t size) +{ + if (size % 4 != 0) { + return SDMMC_ERR_INVALID_SIZE; + } + return sdmmc_io_rw_extended(card, function, addr, + SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT | SD_ARG_CMD53_BLOCK_MODE, + (void*) src, size); +} + +sdmmc_err_t sdmmc_io_enable_int(sdmmc_card_t* card) +{ + if (card->host.io_int_enable == NULL) { + return SDMMC_ERR_NOT_SUPPORTED; + } + return (*card->host.io_int_enable)(card->host.slot); +} + +sdmmc_err_t sdmmc_io_wait_int(sdmmc_card_t* card, int timeout_ms) +{ + if (card->host.io_int_wait == NULL) { + return SDMMC_ERR_NOT_SUPPORTED; + } + return (*card->host.io_int_wait)(card->host.slot, timeout_ms); +} + + +/* + * Print the CIS information of a CIS card, currently only ESP slave supported. + */ + +static sdmmc_err_t cis_tuple_func_default(const void* p, uint8_t* data, FILE* fp) +{ + const cis_tuple_t* tuple = (const cis_tuple_t*)p; + uint8_t code = *(data++); + int size = *(data++); + if (tuple) { + fprintf(fp, "TUPLE: %s, size: %d: ", tuple->name, size); + } else { + fprintf(fp, "TUPLE: unknown(%02X), size: %d: ", code, size); + } + for (int i = 0; i < size; i++) fprintf(fp, "%02X ", *(data++)); + fprintf(fp, "\n"); + return SDMMC_OK; +} + +static sdmmc_err_t cis_tuple_func_manfid(const void* p, uint8_t* data, FILE* fp) +{ + const cis_tuple_t* tuple = (const cis_tuple_t*)p; + data++; + int size = *(data++); + fprintf(fp, "TUPLE: %s, size: %d\n", tuple->name, size); + CIS_CHECK_SIZE(size, 4); + fprintf(fp, " MANF: %04X, CARD: %04X\n", *(uint16_t*)(data), *(uint16_t*)(data+2)); + return SDMMC_OK; +} + +static sdmmc_err_t cis_tuple_func_end(const void* p, uint8_t* data, FILE* fp) +{ + const cis_tuple_t* tuple = (const cis_tuple_t*)p; + data++; + fprintf(fp, "TUPLE: %s\n", tuple->name); + return SDMMC_OK; +} + +static sdmmc_err_t cis_tuple_func_cftable_entry(const void* p, uint8_t* data, FILE* fp) +{ + const cis_tuple_t* tuple = (const cis_tuple_t*)p; + data++; + int size = *(data++); + fprintf(fp, "TUPLE: %s, size: %d\n", tuple->name, size); + CIS_CHECK_SIZE(size, 2); + + CIS_CHECK_SIZE(size--, 1); + bool interface = data[0] & BIT(7); + bool def = data[0] & BIT(6); + int conf_ent_num = data[0] & 0x3F; + fprintf(fp, " INDX: %02X, Intface: %d, Default: %d, Conf-Entry-Num: %d\n", *(data++), interface, def, conf_ent_num); + + if (interface) { + CIS_CHECK_SIZE(size--, 1); + fprintf(fp, " IF: %02X\n", *(data++)); + } + + CIS_CHECK_SIZE(size--, 1); + bool misc = data[0] & BIT(7); + int mem_space = (data[0] >> 5 )&(0x3); + bool irq = data[0] & BIT(4); + bool io_sp = data[0] & BIT(3); + bool timing = data[0] & BIT(2); + int power = data[0] & 3; + fprintf(fp, " FS: %02X, misc: %d, mem_space: %d, irq: %d, io_space: %d, timing: %d, power: %d\n", *(data++), misc, mem_space, irq, io_sp, timing, power); + + CIS_CHECK_UNSUPPORTED(power == 0); //power descriptor is not handled yet + CIS_CHECK_UNSUPPORTED(!timing); //timing descriptor is not handled yet + CIS_CHECK_UNSUPPORTED(!io_sp); //io space descriptor is not handled yet + + if (irq) { + CIS_CHECK_SIZE(size--, 1); + bool mask = data[0] & BIT(4); + fprintf(fp, " IR: %02X, mask: %d, ",*(data++), mask); + if (mask) { + CIS_CHECK_SIZE(size, 2); + size-=2; + fprintf(fp, " IRQ: %02X %02X\n", data[0], data[1]); + data+=2; + } + } + + if (mem_space) { + CIS_CHECK_SIZE(size, 2); + size-=2; + CIS_CHECK_UNSUPPORTED(mem_space==1); //other cases not handled yet + int len = *(uint16_t*)data; + fprintf(fp, " LEN: %04X\n", len); + data+=2; + } + + CIS_CHECK_UNSUPPORTED(misc==0); //misc descriptor is not handled yet + return SDMMC_OK; +} + +static const cis_tuple_t* get_tuple(uint8_t code) +{ + for (size_t i = 0; i < sizeof(cis_table)/sizeof(cis_tuple_t); i++) { + if (code == cis_table[i].code) return &cis_table[i]; + } + return NULL; +} + +sdmmc_err_t sdmmc_io_print_cis_info(uint8_t* buffer, size_t buffer_size, FILE* fp) +{ + if (!fp) fp = stdout; + + uint8_t* cis = buffer; + do { + const cis_tuple_t* tuple = get_tuple(cis[0]); + int size = cis[1]; + sdmmc_err_t ret = SDMMC_OK; + if (tuple) { + ret = tuple->func(tuple, cis, fp); + } else { + ret = cis_tuple_func_default(NULL, cis, fp); + } + if (ret != SDMMC_OK) return ret; + cis += 2 + size; + if (tuple && tuple->code == CISTPL_CODE_END) break; + } while (cis < buffer + buffer_size) ; + return SDMMC_OK; +} + +/** + * Check tuples in the buffer. + * + * @param buf Buffer to check + * @param buffer_size Size of the buffer + * @param inout_cis_offset + * - input: the last cis_offset, relative to the beginning of the buf. -1 if + * this buffer begin with the tuple length, otherwise should be no smaller than + * zero. + * - output: when the end tuple found, output offset of the CISTPL_CODE_END + * byte + 1 (relative to the beginning of the buffer; when not found, output + * the address of next tuple code. + * + * @return true if found, false if haven't. + */ +static bool check_tuples_in_buffer(uint8_t* buf, int buffer_size, int* inout_cis_offset) +{ + int cis_offset = *inout_cis_offset; + if (cis_offset == -1) { + //the CIS code is checked in the last buffer, skip to next tuple + cis_offset += buf[0] + 2; + } + assert(cis_offset >= 0); + while (1) { + if (cis_offset < buffer_size) { + //A CIS code in the buffer, check it + if (buf[cis_offset] == CISTPL_CODE_END) { + *inout_cis_offset = cis_offset + 1; + return true; + } + } + if (cis_offset + 1 < buffer_size) { + cis_offset += buf[cis_offset+1] + 2; + } else { + break; + } + } + *inout_cis_offset = cis_offset; + return false; +} + +sdmmc_err_t sdmmc_io_get_cis_data(sdmmc_card_t* card, uint8_t* out_buffer, size_t buffer_size, size_t* inout_cis_size) +{ + sdmmc_err_t ret = SDMMC_OK; + uint32_t buf[CIS_GET_MINIMAL_SIZE / sizeof(uint32_t)]; + + /* Pointer to size is a mandatory parameter */ + assert(inout_cis_size); + + /* + * CIS region exist in 0x1000~0x17FFF of FUNC 0, get the start address of it + * from CCCR register. + */ + uint32_t addr; + ret = sdmmc_io_read_bytes(card, 0, 9, &addr, 3); + if (ret != SDMMC_OK) return ret; + //the sdmmc_io driver reads 4 bytes, the most significant byte is not the address. + addr &= 0xffffff; + if (addr < 0x1000 || addr > 0x17FFF) { + return SDMMC_ERR_INVALID_RESPONSE; + } + + /* + * To avoid reading too long, take the input value as limitation if + * existing. + */ + size_t max_reading = UINT32_MAX; + if (*inout_cis_size != 0) { + max_reading = *inout_cis_size; + } + + /* + * Parse the length while reading. If find the end tuple, or reaches the + * limitation, read no more and return both the data and the size already + * read. + */ + size_t buffer_offset = 0; + size_t cur_cis_offset = 0; + bool end_tuple_found = false; + do { + ret = sdmmc_io_read_bytes(card, 0, addr + buffer_offset, &buf, CIS_GET_MINIMAL_SIZE); + if (ret != SDMMC_OK) return ret; + + //calculate relative to the beginning of the buffer + int offset = cur_cis_offset - buffer_offset; + bool finish = check_tuples_in_buffer((uint8_t*) buf, CIS_GET_MINIMAL_SIZE, &offset); + + int remain_size = buffer_size - buffer_offset; + int copy_len; + if (finish) { + copy_len = TSD_MIN(offset, remain_size); + end_tuple_found = true; + } else { + copy_len = TSD_MIN(CIS_GET_MINIMAL_SIZE, remain_size); + } + if (copy_len > 0) { + memcpy(out_buffer + buffer_offset, buf, copy_len); + } + cur_cis_offset = buffer_offset + offset; + buffer_offset += CIS_GET_MINIMAL_SIZE; + } while (!end_tuple_found && buffer_offset < max_reading); + + if (end_tuple_found) { + *inout_cis_size = cur_cis_offset; + if (cur_cis_offset > buffer_size) { + return SDMMC_ERR_INVALID_SIZE; + } else { + return SDMMC_OK; + } + } else { + return SDMMC_ERR_NO_CARD; + } +} diff --git a/lib/sdmmc/sdmmc_mmc.c b/lib/sdmmc/sdmmc_mmc.c new file mode 100644 index 0000000000..b77d7dd16e --- /dev/null +++ b/lib/sdmmc/sdmmc_mmc.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2006 Uwe Stuehler + * Adaptations to ESP-IDF Copyright (c) 2016-2018 Espressif Systems (Shanghai) PTE LTD + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include "sdmmc_common.h" + +sdmmc_err_t sdmmc_init_mmc_read_ext_csd(sdmmc_card_t* card) +{ + int card_type; + sdmmc_err_t err = SDMMC_OK; + + uint32_t ext_csd[EXT_CSD_MMC_SIZE / sizeof(uint32_t)]; + + uint32_t sectors = 0; + + ESP_LOGD(TAG, "MMC version: %d", card->csd.mmc_ver); + if (card->csd.mmc_ver < MMC_CSD_MMCVER_4_0) { + return SDMMC_ERR_NOT_SUPPORTED; + } + + /* read EXT_CSD */ + err = sdmmc_mmc_send_ext_csd_data(card, ext_csd, EXT_CSD_MMC_SIZE); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: send_ext_csd_data error 0x%x", __func__, err); + return err; + } + card_type = ext_csd[EXT_CSD_CARD_TYPE / sizeof(uint32_t)]; + + card->is_ddr = 0; + if (card_type & EXT_CSD_CARD_TYPE_F_52M_1_8V) { + card->max_freq_khz = SDMMC_FREQ_52M; + if ((card->host.flags & SDMMC_HOST_FLAG_DDR) && + card->host.max_freq_khz >= SDMMC_FREQ_26M && + card->host.get_bus_width(card->host.slot) == 4) { + ESP_LOGD(TAG, "card and host support DDR mode"); + card->is_ddr = 1; + } + } else if (card_type & EXT_CSD_CARD_TYPE_F_52M) { + card->max_freq_khz = SDMMC_FREQ_52M; + } else if (card_type & EXT_CSD_CARD_TYPE_F_26M) { + card->max_freq_khz = SDMMC_FREQ_26M; + } else { + ESP_LOGW(TAG, "%s: unknown CARD_TYPE 0x%x", __func__, card_type); + } + /* For MMC cards, use speed value from EXT_CSD */ + card->csd.tr_speed = card->max_freq_khz * 1000; + ESP_LOGD(TAG, "MMC card type %d, max_freq_khz=%d, is_ddr=%d", card_type, card->max_freq_khz, card->is_ddr); + card->max_freq_khz = TSD_MIN(card->max_freq_khz, card->host.max_freq_khz); + + if (card->host.flags & SDMMC_HOST_FLAG_8BIT) { + card->ext_csd.power_class = ext_csd[((card->max_freq_khz > SDMMC_FREQ_26M) ? + EXT_CSD_PWR_CL_52_360 : EXT_CSD_PWR_CL_26_360) / sizeof(uint32_t)] >> 4; + card->log_bus_width = 3; + } else if (card->host.flags & SDMMC_HOST_FLAG_4BIT) { + card->ext_csd.power_class = ext_csd[((card->max_freq_khz > SDMMC_FREQ_26M) ? + EXT_CSD_PWR_CL_52_360 : EXT_CSD_PWR_CL_26_360) / sizeof(uint32_t)] & 0x0f; + card->log_bus_width = 2; + } else { + card->ext_csd.power_class = 0; //card must be able to do full rate at powerclass 0 in 1-bit mode + card->log_bus_width = 0; + } + + sectors = ext_csd[EXT_CSD_SEC_COUNT / sizeof(uint32_t)]; + + if (sectors > (2u * 1024 * 1024 * 1024) / 512) { + card->csd.capacity = sectors; + } + + return err; +} + +sdmmc_err_t sdmmc_init_mmc_bus_width(sdmmc_card_t* card) +{ + sdmmc_err_t err; + if (card->ext_csd.power_class != 0) { + err = sdmmc_mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_POWER_CLASS, card->ext_csd.power_class); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: can't change power class (%d bit), 0x%x" + , __func__, card->ext_csd.power_class, err); + return err; + } + } + + if (card->log_bus_width > 0) { + int csd_bus_width_value = EXT_CSD_BUS_WIDTH_1; + int bus_width = 1; + if (card->log_bus_width == 2) { + if (card->is_ddr) { + csd_bus_width_value = EXT_CSD_BUS_WIDTH_4_DDR; + } else { + csd_bus_width_value = EXT_CSD_BUS_WIDTH_4; + } + bus_width = 4; + } else if (card->log_bus_width == 3) { + if (card->is_ddr) { + csd_bus_width_value = EXT_CSD_BUS_WIDTH_8_DDR; + } else { + csd_bus_width_value = EXT_CSD_BUS_WIDTH_8; + } + bus_width = 8; + } + err = sdmmc_mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_BUS_WIDTH, csd_bus_width_value); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: can't change bus width (%d bit), 0x%x", + __func__, bus_width, err); + (void) bus_width; + return err; + } + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_mmc_enable_hs_mode(sdmmc_card_t* card) +{ + sdmmc_err_t err; + if (card->max_freq_khz > SDMMC_FREQ_26M) { + /* switch to high speed timing */ + err = sdmmc_mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_HS_TIMING, EXT_CSD_HS_TIMING_HS); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: mmc_switch EXT_CSD_HS_TIMING_HS error 0x%x", + __func__, err); + return err; + } + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_mmc_decode_cid(int mmc_ver, sdmmc_response_t resp, sdmmc_cid_t* out_cid) +{ + if (mmc_ver == MMC_CSD_MMCVER_1_0 || + mmc_ver == MMC_CSD_MMCVER_1_4) { + out_cid->mfg_id = MMC_CID_MID_V1(resp); + out_cid->oem_id = 0; + MMC_CID_PNM_V1_CPY(resp, out_cid->name); + out_cid->revision = MMC_CID_REV_V1(resp); + out_cid->serial = MMC_CID_PSN_V1(resp); + out_cid->date = MMC_CID_MDT_V1(resp); + } else if (mmc_ver == MMC_CSD_MMCVER_2_0 || + mmc_ver == MMC_CSD_MMCVER_3_1 || + mmc_ver == MMC_CSD_MMCVER_4_0) { + out_cid->mfg_id = MMC_CID_MID_V2(resp); + out_cid->oem_id = MMC_CID_OID_V2(resp); + MMC_CID_PNM_V1_CPY(resp, out_cid->name); + out_cid->revision = 0; + out_cid->serial = MMC_CID_PSN_V1(resp); + out_cid->date = 0; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_mmc_decode_csd(sdmmc_response_t response, sdmmc_csd_t* out_csd) +{ + out_csd->csd_ver = MMC_CSD_CSDVER(response); + if (out_csd->csd_ver == MMC_CSD_CSDVER_1_0 || + out_csd->csd_ver == MMC_CSD_CSDVER_2_0 || + out_csd->csd_ver == MMC_CSD_CSDVER_EXT_CSD) { + out_csd->mmc_ver = MMC_CSD_MMCVER(response); + out_csd->capacity = MMC_CSD_CAPACITY(response); + out_csd->read_block_len = MMC_CSD_READ_BL_LEN(response); + } else { + ESP_LOGE(TAG, "unknown MMC CSD structure version 0x%x\n", out_csd->csd_ver); + return 1; + } + int read_bl_size = 1 << out_csd->read_block_len; + out_csd->sector_size = TSD_MIN(read_bl_size, 512); + if (out_csd->sector_size < read_bl_size) { + out_csd->capacity *= read_bl_size / out_csd->sector_size; + } + /* tr_speed will be determined when reading CXD */ + out_csd->tr_speed = 0; + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_mmc_send_ext_csd_data(sdmmc_card_t* card, void *out_data, size_t datalen) +{ + sdmmc_command_t cmd = { + .data = out_data, + .datalen = datalen, + .blklen = datalen, + .opcode = MMC_SEND_EXT_CSD, + .arg = 0, + .flags = SCF_CMD_ADTC | SCF_RSP_R1 | SCF_CMD_READ + }; + return sdmmc_send_cmd(card, &cmd); +} + +sdmmc_err_t sdmmc_mmc_switch(sdmmc_card_t* card, uint8_t set, uint8_t index, uint8_t value) +{ + sdmmc_command_t cmd = { + .opcode = MMC_SWITCH, + .arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (index << 16) | (value << 8) | set, + .flags = SCF_RSP_R1B | SCF_CMD_AC | SCF_WAIT_BUSY, + }; + sdmmc_err_t err = sdmmc_send_cmd(card, &cmd); + if (err == SDMMC_OK) { + //check response bit to see that switch was accepted + if (MMC_R1(cmd.response) & MMC_R1_SWITCH_ERROR) + err = SDMMC_ERR_INVALID_RESPONSE; + } + + return err; +} + +sdmmc_err_t sdmmc_init_mmc_check_csd(sdmmc_card_t* card) +{ + sdmmc_err_t err; + assert(card->is_mem == 1); + assert(card->rca != 0); + //The card will not respond to send_csd command in the transfer state. + //Deselect it first. + err = sdmmc_send_cmd_select_card(card, 0); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: select_card returned 0x%x", __func__, err); + return err; + } + + sdmmc_csd_t csd; + /* Get the contents of CSD register to verify the communication over CMD line + is OK. */ + err = sdmmc_send_cmd_send_csd(card, &csd); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: send_csd returned 0x%x", __func__, err); + return err; + } + + //Select the card again + err = sdmmc_send_cmd_select_card(card, card->rca); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: select_card returned 0x%x", __func__, err); + return err; + } + return SDMMC_OK; +} diff --git a/lib/sdmmc/sdmmc_sd.c b/lib/sdmmc/sdmmc_sd.c new file mode 100644 index 0000000000..b4391f2e7c --- /dev/null +++ b/lib/sdmmc/sdmmc_sd.c @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2006 Uwe Stuehler + * Adaptations to ESP-IDF Copyright (c) 2016-2018 Espressif Systems (Shanghai) PTE LTD + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "sdmmc_common.h" + +sdmmc_err_t sdmmc_init_sd_if_cond(sdmmc_card_t* card) +{ + /* SEND_IF_COND (CMD8) command is used to identify SDHC/SDXC cards. + * SD v1 and non-SD cards will not respond to this command. + */ + uint32_t host_ocr = get_host_ocr(card->host.io_voltage); + sdmmc_err_t err = sdmmc_send_cmd_send_if_cond(card, host_ocr); + if (err == SDMMC_OK) { + ESP_LOGD(TAG, "SDHC/SDXC card"); + host_ocr |= SD_OCR_SDHC_CAP; + } else if (err == SDMMC_ERR_TIMEOUT) { + ESP_LOGD(TAG, "CMD8 timeout; not an SD v2.00 card"); + } else if (host_is_spi(card) && err == SDMMC_ERR_NOT_SUPPORTED) { + ESP_LOGD(TAG, "CMD8 rejected; not an SD v2.00 card"); + } else { + ESP_LOGE(TAG, "%s: send_if_cond (1) returned 0x%x", __func__, err); + return err; + } + card->ocr = host_ocr; + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_init_sd_blocklen(sdmmc_card_t* card) +{ + /* SDSC cards support configurable data block lengths. + * We don't use this feature and set the block length to 512 bytes, + * same as the block length for SDHC cards. + */ + if ((card->ocr & SD_OCR_SDHC_CAP) == 0) { + sdmmc_err_t err = sdmmc_send_cmd_set_blocklen(card, &card->csd); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: set_blocklen returned 0x%x", __func__, err); + return err; + } + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_init_sd_scr(sdmmc_card_t* card) +{ + sdmmc_err_t err; + /* Get the contents of SCR register: bus width and the version of SD spec + * supported by the card. + * In SD mode, this is the first command which uses D0 line. Errors at + * this step usually indicate connection issue or lack of pull-up resistor. + */ + err = sdmmc_send_cmd_send_scr(card, &card->scr); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: send_scr (1) returned 0x%x", __func__, err); + return err; + } + + if ((card->scr.bus_width & SCR_SD_BUS_WIDTHS_4BIT) + && (card->host.flags & SDMMC_HOST_FLAG_4BIT)) { + card->log_bus_width = 2; + } else { + card->log_bus_width = 0; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_init_sd_bus_width(sdmmc_card_t* card) +{ + int width = 1; + if (card->log_bus_width == 2) { + width = 4; + } else if (card->log_bus_width == 3) { + width = 8; + } + sdmmc_err_t err = sdmmc_send_cmd_set_bus_width(card, width); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "set_bus_width failed (0x%x)", err); + return err; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_init_sd_wait_data_ready(sdmmc_card_t* card) +{ + /* Wait for the card to be ready for data transfers */ + uint32_t status = 0; + uint32_t count = 0; + while (!host_is_spi(card) && !(status & MMC_R1_READY_FOR_DATA)) { + // TODO: add some timeout here + sdmmc_err_t err = sdmmc_send_cmd_send_status(card, &status); + if (err != SDMMC_OK) { + return err; + } + if (++count % 16 == 0) { + ESP_LOGV(TAG, "waiting for card to become ready (%d)", count); + } + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_send_cmd_switch_func(sdmmc_card_t* card, + uint32_t mode, uint32_t group, uint32_t function, + sdmmc_switch_func_rsp_t* resp) +{ + if (card->scr.sd_spec < SCR_SD_SPEC_VER_1_10 || + ((card->csd.card_command_class & SD_CSD_CCC_SWITCH) == 0)) { + return SDMMC_ERR_NOT_SUPPORTED; + } + + if (group == 0 || + group > SD_SFUNC_GROUP_MAX || + function > SD_SFUNC_FUNC_MAX) { + return SDMMC_ERR_INVALID_ARG; + } + + if (mode > 1) { + return SDMMC_ERR_INVALID_ARG; + } + + uint32_t group_shift = (group - 1) << 2; + /* all functions which should not be affected are set to 0xf (no change) */ + uint32_t other_func_mask = (0x00ffffff & ~(0xf << group_shift)); + uint32_t func_val = (function << group_shift) | other_func_mask; + + sdmmc_command_t cmd = { + .opcode = MMC_SWITCH, + .flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1, + .blklen = sizeof(sdmmc_switch_func_rsp_t), + .data = resp->data, + .datalen = sizeof(sdmmc_switch_func_rsp_t), + .arg = (!!mode << 31) | func_val + }; + + sdmmc_err_t err = sdmmc_send_cmd(card, &cmd); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: sdmmc_send_cmd returned 0x%x", __func__, err); + return err; + } + sdmmc_flip_byte_order(resp->data, sizeof(sdmmc_switch_func_rsp_t)); + uint32_t resp_ver = SD_SFUNC_VER(resp->data); + if (resp_ver == 0) { + /* busy response is never sent */ + } else if (resp_ver == 1) { + if (SD_SFUNC_BUSY(resp->data, group) & (1 << function)) { + ESP_LOGD(TAG, "%s: response indicates function %d:%d is busy", + __func__, group, function); + return SDMMC_ERR_BUSY; + } + } else { + ESP_LOGD(TAG, "%s: got an invalid version of SWITCH_FUNC response: 0x%02x", + __func__, resp_ver); + return SDMMC_ERR_INVALID_RESPONSE; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_enable_hs_mode(sdmmc_card_t* card) +{ + /* This will determine if the card supports SWITCH_FUNC command, + * and high speed mode. If the cards supports both, this will enable + * high speed mode at the card side. + */ + if (card->scr.sd_spec < SCR_SD_SPEC_VER_1_10 || + ((card->csd.card_command_class & SD_CSD_CCC_SWITCH) == 0)) { + return SDMMC_ERR_NOT_SUPPORTED; + } + sdmmc_switch_func_rsp_t response; + + sdmmc_err_t err = sdmmc_send_cmd_switch_func(card, 0, SD_ACCESS_MODE, 0, &response); + if (err != SDMMC_OK) { + ESP_LOGD(TAG, "%s: sdmmc_send_cmd_switch_func (1) returned 0x%x", __func__, err); + return err; + } + uint32_t supported_mask = SD_SFUNC_SUPPORTED(response.data, 1); + if ((supported_mask & BIT(SD_ACCESS_MODE_SDR25)) == 0) { + return SDMMC_ERR_NOT_SUPPORTED; + } + err = sdmmc_send_cmd_switch_func(card, 1, SD_ACCESS_MODE, SD_ACCESS_MODE_SDR25, &response); + if (err != SDMMC_OK) { + ESP_LOGD(TAG, "%s: sdmmc_send_cmd_switch_func (2) returned 0x%x", __func__, err); + return err; + } + + return err; +} + +sdmmc_err_t sdmmc_enable_hs_mode_and_check(sdmmc_card_t* card) +{ + /* All cards should support at least default speed */ + card->max_freq_khz = SDMMC_FREQ_DEFAULT; + if (card->host.max_freq_khz <= card->max_freq_khz) { + /* Host is configured to use low frequency, don't attempt to switch */ + card->max_freq_khz = card->host.max_freq_khz; + return SDMMC_OK; + } + + /* Try to enabled HS mode */ + sdmmc_err_t err = sdmmc_enable_hs_mode(card); + if (err != SDMMC_OK) { + return err; + } + /* HS mode has been enabled on the card. + * Read CSD again, it should now indicate that the card supports + * 50MHz clock. + * Since SEND_CSD is allowed only in standby mode, and the card is currently in data transfer + * mode, deselect the card first, then get the CSD, then select the card again. This step is + * not required in SPI mode, since CMD7 (select_card) is not supported. + */ + const bool is_spi = host_is_spi(card); + if (!is_spi) { + err = sdmmc_send_cmd_select_card(card, 0); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: select_card (1) returned 0x%x", __func__, err); + return err; + } + } + err = sdmmc_send_cmd_send_csd(card, &card->csd); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: send_csd returned 0x%x", __func__, err); + return err; + } + if (!is_spi) { + err = sdmmc_send_cmd_select_card(card, card->rca); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: select_card (2) returned 0x%x", __func__, err); + return err; + } + } + + if (card->csd.tr_speed != 50000000) { + ESP_LOGW(TAG, "unexpected: after enabling HS mode, tr_speed=%d", card->csd.tr_speed); + return SDMMC_ERR_NOT_SUPPORTED; + } + + card->max_freq_khz = SDMMC_FREQ_HIGHSPEED; + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_check_scr(sdmmc_card_t* card) +{ + /* If frequency switch has been performed, read SCR register one more time + * and compare the result with the previous one. Use this simple check as + * an indicator of potential signal integrity issues. + */ + sdmmc_scr_t scr_tmp; + sdmmc_err_t err = sdmmc_send_cmd_send_scr(card, &scr_tmp); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: send_scr returned 0x%x", __func__, err); + return err; + } + if (memcmp(&card->scr, &scr_tmp, sizeof(scr_tmp)) != 0) { + ESP_LOGE(TAG, "got corrupted data after increasing clock frequency"); + return SDMMC_ERR_INVALID_RESPONSE; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_init_spi_crc(sdmmc_card_t* card) +{ + /* In SD mode, CRC checks of data transfers are mandatory and performed + * by the hardware. In SPI mode, CRC16 of data transfers is optional and + * needs to be enabled. + */ + assert(host_is_spi(card)); + sdmmc_err_t err = sdmmc_send_cmd_crc_on_off(card, true); + if (err != SDMMC_OK) { + ESP_LOGE(TAG, "%s: sdmmc_send_cmd_crc_on_off returned 0x%x", __func__, err); + return err; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_decode_cid(sdmmc_response_t resp, sdmmc_cid_t* out_cid) +{ + out_cid->mfg_id = SD_CID_MID(resp); + out_cid->oem_id = SD_CID_OID(resp); + SD_CID_PNM_CPY(resp, out_cid->name); + out_cid->revision = SD_CID_REV(resp); + out_cid->serial = SD_CID_PSN(resp); + out_cid->date = SD_CID_MDT(resp); + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_decode_csd(sdmmc_response_t response, sdmmc_csd_t* out_csd) +{ + out_csd->csd_ver = SD_CSD_CSDVER(response); + switch (out_csd->csd_ver) { + case SD_CSD_CSDVER_2_0: + out_csd->capacity = SD_CSD_V2_CAPACITY(response); + out_csd->read_block_len = SD_CSD_V2_BL_LEN; + break; + case SD_CSD_CSDVER_1_0: + out_csd->capacity = SD_CSD_CAPACITY(response); + out_csd->read_block_len = SD_CSD_READ_BL_LEN(response); + break; + default: + ESP_LOGE(TAG, "unknown SD CSD structure version 0x%x", out_csd->csd_ver); + return SDMMC_ERR_NOT_SUPPORTED; + } + out_csd->card_command_class = SD_CSD_CCC(response); + int read_bl_size = 1 << out_csd->read_block_len; + out_csd->sector_size = TSD_MIN(read_bl_size, 512); + if (out_csd->sector_size < read_bl_size) { + out_csd->capacity *= read_bl_size / out_csd->sector_size; + } + int speed = SD_CSD_SPEED(response); + if (speed == SD_CSD_SPEED_50_MHZ) { + out_csd->tr_speed = 50000000; + } else { + out_csd->tr_speed = 25000000; + } + return SDMMC_OK; +} + +sdmmc_err_t sdmmc_decode_scr(uint32_t *raw_scr, sdmmc_scr_t* out_scr) +{ + sdmmc_response_t resp = { 0 }; + resp[1] = __builtin_bswap32(raw_scr[0]); + resp[0] = __builtin_bswap32(raw_scr[1]); + int ver = SCR_STRUCTURE(resp); + if (ver != 0) { + return SDMMC_ERR_NOT_SUPPORTED; + } + out_scr->sd_spec = SCR_SD_SPEC(resp); + out_scr->bus_width = SCR_SD_BUS_WIDTHS(resp); + return SDMMC_OK; +} diff --git a/lib/sdmmc/test/CMakeLists.txt b/lib/sdmmc/test/CMakeLists.txt new file mode 100644 index 0000000000..d6d58598fb --- /dev/null +++ b/lib/sdmmc/test/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRC_DIRS "." + PRIV_INCLUDE_DIRS "." + PRIV_REQUIRES cmock sdmmc + ) diff --git a/lib/sdmmc/test/component.mk b/lib/sdmmc/test/component.mk new file mode 100644 index 0000000000..ce464a212a --- /dev/null +++ b/lib/sdmmc/test/component.mk @@ -0,0 +1 @@ +COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive diff --git a/lib/sdmmc/test/test_sd.c b/lib/sdmmc/test/test_sd.c new file mode 100644 index 0000000000..fd7051cbd2 --- /dev/null +++ b/lib/sdmmc/test/test_sd.c @@ -0,0 +1,584 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include "unity.h" +#include "driver/gpio.h" +#include "soc/soc_caps.h" +#if SOC_SDMMC_HOST_SUPPORTED +#include "driver/sdmmc_host.h" +#endif +#include "driver/sdspi_host.h" +#include "driver/sdmmc_defs.h" +#include "sdmmc_cmd.h" +#include "esp_log.h" +#include "esp_heap_caps.h" +#include "esp_rom_gpio.h" + +// Can't test eMMC (slot 0) and PSRAM together +#ifndef CONFIG_SPIRAM +#define WITH_EMMC_TEST +#endif + +/* power supply enable pin */ +#define SD_TEST_BOARD_VSEL_EN_GPIO 27 + +/* power supply voltage select pin */ +#define SD_TEST_BOARD_VSEL_GPIO 26 +#define SD_TEST_BOARD_VSEL_3V3 1 +#define SD_TEST_BOARD_VSEL_1V8 0 + +#define TEST_SDSPI_DMACHAN 1 + +/* time to wait for reset / power-on */ +#define SD_TEST_BOARD_PWR_RST_DELAY_MS 5 +#define SD_TEST_BOARD_PWR_ON_DELAY_MS 50 + +/* gpio which is not connected to actual CD pin, used to simulate CD behavior */ +#define CD_WP_TEST_GPIO 18 + + +__attribute__((unused)) static void sd_test_board_power_on(void) +{ + gpio_set_direction(SD_TEST_BOARD_VSEL_GPIO, GPIO_MODE_OUTPUT); + gpio_set_level(SD_TEST_BOARD_VSEL_GPIO, SD_TEST_BOARD_VSEL_3V3); + gpio_set_direction(SD_TEST_BOARD_VSEL_EN_GPIO, GPIO_MODE_OUTPUT); + gpio_set_level(SD_TEST_BOARD_VSEL_EN_GPIO, 0); + usleep(SD_TEST_BOARD_PWR_RST_DELAY_MS * 1000); + gpio_set_level(SD_TEST_BOARD_VSEL_EN_GPIO, 1); + usleep(SD_TEST_BOARD_PWR_ON_DELAY_MS * 1000); +} + +__attribute__((unused)) static void sd_test_board_power_off(void) +{ + gpio_set_level(SD_TEST_BOARD_VSEL_EN_GPIO, 0); + gpio_set_direction(SD_TEST_BOARD_VSEL_GPIO, GPIO_MODE_INPUT); + gpio_set_level(SD_TEST_BOARD_VSEL_GPIO, 0); + gpio_set_direction(SD_TEST_BOARD_VSEL_EN_GPIO, GPIO_MODE_INPUT); +} + +TEST_CASE("MMC_RSP_BITS", "[sd]") +{ + uint32_t data[2] = { 0x01234567, 0x89abcdef }; + TEST_ASSERT_EQUAL_HEX32(0x7, MMC_RSP_BITS(data, 0, 4)); + TEST_ASSERT_EQUAL_HEX32(0x567, MMC_RSP_BITS(data, 0, 12)); + TEST_ASSERT_EQUAL_HEX32(0xf0, MMC_RSP_BITS(data, 28, 8)); + TEST_ASSERT_EQUAL_HEX32(0x3, MMC_RSP_BITS(data, 1, 3)); + TEST_ASSERT_EQUAL_HEX32(0x11, MMC_RSP_BITS(data, 59, 5)); +} + +#if SOC_SDMMC_HOST_SUPPORTED + +static void probe_sd(int slot, int width, int freq_khz, int ddr) +{ + sd_test_board_power_on(); + sdmmc_host_t config = SDMMC_HOST_DEFAULT(); + config.slot = slot; + config.max_freq_khz = freq_khz; + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + if (width == 1) { + config.flags = SDMMC_HOST_FLAG_1BIT; + slot_config.width = 1; + } else if (width == 4) { + config.flags &= ~SDMMC_HOST_FLAG_8BIT; + slot_config.width = 4; + } else { + assert(!ddr && "host driver does not support 8-line DDR mode yet"); + } + if (!ddr) { + config.flags &= ~SDMMC_HOST_FLAG_DDR; + } + TEST_ESP_OK(sdmmc_host_init()); + TEST_ESP_OK(sdmmc_host_init_slot(slot, &slot_config)); + sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); + TEST_ASSERT_NOT_NULL(card); + TEST_ESP_OK(sdmmc_card_init(&config, card)); + sdmmc_card_print_info(stdout, card); + uint8_t* buffer = heap_caps_malloc(512, MALLOC_CAP_DMA); + TEST_ESP_OK(sdmmc_read_sectors(card, buffer, 0, 1)); + free(buffer); + TEST_ESP_OK(sdmmc_host_deinit()); + free(card); + sd_test_board_power_off(); +} + +TEST_CASE("probe SD, slot 1, 4-bit", "[sd][test_env=UT_T1_SDMODE]") +{ + probe_sd(SDMMC_HOST_SLOT_1, 4, SDMMC_FREQ_PROBING, 0); + probe_sd(SDMMC_HOST_SLOT_1, 4, SDMMC_FREQ_DEFAULT, 0); + probe_sd(SDMMC_HOST_SLOT_1, 4, SDMMC_FREQ_HIGHSPEED, 0); +} + +TEST_CASE("probe SD, slot 1, 1-bit", "[sd][test_env=UT_T1_SDMODE]") +{ + probe_sd(SDMMC_HOST_SLOT_1, 1, SDMMC_FREQ_PROBING, 0); + probe_sd(SDMMC_HOST_SLOT_1, 1, SDMMC_FREQ_DEFAULT, 0); + probe_sd(SDMMC_HOST_SLOT_1, 1, SDMMC_FREQ_HIGHSPEED, 0); +} + +#ifdef WITH_EMMC_TEST +TEST_CASE("probe eMMC, slot 0, 4-bit, DDR", "[sd][test_env=EMMC]") +{ + probe_sd(SDMMC_HOST_SLOT_0, 4, SDMMC_FREQ_HIGHSPEED, 1); +} + +TEST_CASE("probe eMMC, slot 0, 8-bit", "[sd][test_env=EMMC]") +{ + probe_sd(SDMMC_HOST_SLOT_0, 8, SDMMC_FREQ_PROBING, 0); + probe_sd(SDMMC_HOST_SLOT_0, 8, SDMMC_FREQ_DEFAULT, 0); + probe_sd(SDMMC_HOST_SLOT_0, 8, SDMMC_FREQ_HIGHSPEED, 0); +} +#endif // WITH_EMMC_TEST + +TEST_CASE("probe SD, slot 0, 4-bit", "[sd][test_env=UT_T1_SDCARD][ignore]") +{ + probe_sd(SDMMC_HOST_SLOT_0, 4, SDMMC_FREQ_PROBING, 0); + probe_sd(SDMMC_HOST_SLOT_0, 4, SDMMC_FREQ_DEFAULT, 0); + probe_sd(SDMMC_HOST_SLOT_0, 4, SDMMC_FREQ_HIGHSPEED, 0); +} + +TEST_CASE("probe SD, slot 0, 1-bit", "[sd][test_env=UT_T1_SDCARD][ignore]") +{ + probe_sd(SDMMC_HOST_SLOT_0, 1, SDMMC_FREQ_PROBING, 0); + probe_sd(SDMMC_HOST_SLOT_0, 1, SDMMC_FREQ_DEFAULT, 0); + probe_sd(SDMMC_HOST_SLOT_0, 1, SDMMC_FREQ_HIGHSPEED, 0); +} + +#endif + +#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32C3) +//No runners +static void test_sdspi_init_bus(spi_host_device_t host, int mosi_pin, int miso_pin, int clk_pin, int dma_chan) +{ + spi_bus_config_t bus_config = { + .mosi_io_num = mosi_pin, + .miso_io_num = miso_pin, + .sclk_io_num = clk_pin, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + }; + esp_err_t err = spi_bus_initialize(host, &bus_config, dma_chan); + TEST_ESP_OK(err); +} + +static void test_sdspi_deinit_bus(spi_host_device_t host) +{ + esp_err_t err = spi_bus_free(host); + TEST_ESP_OK(err); +} + +static void probe_core(int slot) +{ + sdmmc_host_t config = SDSPI_HOST_DEFAULT(); + config.slot = slot; + + sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); + TEST_ASSERT_NOT_NULL(card); + + TEST_ESP_OK(sdmmc_card_init(&config, card)); + sdmmc_card_print_info(stdout, card); + free(card); +} + +static void probe_spi(int freq_khz, int pin_miso, int pin_mosi, int pin_sck, int pin_cs) +{ + sd_test_board_power_on(); + + sdspi_dev_handle_t handle; + sdspi_device_config_t dev_config = SDSPI_DEVICE_CONFIG_DEFAULT(); + dev_config.gpio_cs = pin_cs; + test_sdspi_init_bus(dev_config.host_id, pin_mosi, pin_miso, pin_sck, TEST_SDSPI_DMACHAN); + TEST_ESP_OK(sdspi_host_init()); + TEST_ESP_OK(sdspi_host_init_device(&dev_config, &handle)); + + probe_core(handle); + + TEST_ESP_OK(sdspi_host_deinit()); + test_sdspi_deinit_bus(dev_config.host_id); + sd_test_board_power_off(); +} + +static void probe_spi_legacy(int freq_khz, int pin_miso, int pin_mosi, int pin_sck, int pin_cs) +{ + sd_test_board_power_on(); + sdmmc_host_t config = SDSPI_HOST_DEFAULT(); + sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT(); + slot_config.gpio_miso = pin_miso; + slot_config.gpio_mosi = pin_mosi; + slot_config.gpio_sck = pin_sck; + slot_config.gpio_cs = pin_cs; + + TEST_ESP_OK(sdspi_host_init()); + TEST_ESP_OK(sdspi_host_init_slot(config.slot, &slot_config)); + + probe_core(config.slot); + + TEST_ESP_OK(sdspi_host_deinit()); + sd_test_board_power_off(); +} + +TEST_CASE("probe SD in SPI mode, slot 1", "[sd][test_env=UT_T1_SPIMODE]") +{ + probe_spi(SDMMC_FREQ_DEFAULT, 2, 15, 14, 13); + probe_spi_legacy(SDMMC_FREQ_DEFAULT, 2, 15, 14, 13); +} + +TEST_CASE("probe SD in SPI mode, slot 0", "[sd][test_env=UT_T1_SDCARD][ignore]") +{ + probe_spi(SDMMC_FREQ_DEFAULT, 7, 11, 6, 10); + probe_spi_legacy(SDMMC_FREQ_DEFAULT, 7, 11, 6, 10); +} + +#endif //DISABLED(ESP32S2) + +// Fill buffer pointed to by 'dst' with 'count' 32-bit ints generated +// from 'rand' with the starting value of 'seed' +__attribute__((unused)) static void fill_buffer(uint32_t seed, uint8_t* dst, size_t count) { + srand(seed); + for (size_t i = 0; i < count; ++i) { + uint32_t val = rand(); + memcpy(dst + i * sizeof(uint32_t), &val, sizeof(val)); + } +} + +// Check if the buffer pointed to by 'dst' contains 'count' 32-bit +// ints generated from 'rand' with the starting value of 'seed' +__attribute__((unused)) static void check_buffer(uint32_t seed, const uint8_t* src, size_t count) { + srand(seed); + for (size_t i = 0; i < count; ++i) { + uint32_t val; + memcpy(&val, src + i * sizeof(uint32_t), sizeof(val)); + TEST_ASSERT_EQUAL_HEX32(rand(), val); + } +} + +__attribute__((unused)) static void do_single_write_read_test(sdmmc_card_t* card, + size_t start_block, size_t block_count, size_t alignment) +{ + size_t block_size = card->csd.sector_size; + size_t total_size = block_size * block_count; + printf(" %8d | %3d | %d | %4.1f ", start_block, block_count, alignment, total_size / 1024.0f); + + uint32_t* buffer = heap_caps_malloc(total_size + 4, MALLOC_CAP_DMA); + size_t offset = alignment % 4; + uint8_t* c_buffer = (uint8_t*) buffer + offset; + fill_buffer(start_block, c_buffer, total_size / sizeof(buffer[0])); + + struct timeval t_start_wr; + gettimeofday(&t_start_wr, NULL); + TEST_ESP_OK(sdmmc_write_sectors(card, c_buffer, start_block, block_count)); + struct timeval t_stop_wr; + gettimeofday(&t_stop_wr, NULL); + float time_wr = 1e3f * (t_stop_wr.tv_sec - t_start_wr.tv_sec) + 1e-3f * (t_stop_wr.tv_usec - t_start_wr.tv_usec); + + memset(buffer, 0xbb, total_size + 4); + + struct timeval t_start_rd; + gettimeofday(&t_start_rd, NULL); + TEST_ESP_OK(sdmmc_read_sectors(card, c_buffer, start_block, block_count)); + struct timeval t_stop_rd; + gettimeofday(&t_stop_rd, NULL); + float time_rd = 1e3f * (t_stop_rd.tv_sec - t_start_rd.tv_sec) + 1e-3f * (t_stop_rd.tv_usec - t_start_rd.tv_usec); + + printf(" | %6.2f | %5.2f | %6.2f | %5.2f\n", + time_wr, total_size / (time_wr / 1000) / (1024 * 1024), + time_rd, total_size / (time_rd / 1000) / (1024 * 1024)); + check_buffer(start_block, c_buffer, total_size / sizeof(buffer[0])); + free(buffer); +} + +__attribute__((unused)) static void read_write_test(sdmmc_card_t* card) +{ + sdmmc_card_print_info(stdout, card); + printf(" sector | count | align | size(kB) | wr_time(ms) | wr_speed(MB/s) | rd_time(ms) | rd_speed(MB/s)\n"); + do_single_write_read_test(card, 0, 1, 4); + do_single_write_read_test(card, 0, 4, 4); + do_single_write_read_test(card, 1, 16, 4); + do_single_write_read_test(card, 16, 32, 4); + do_single_write_read_test(card, 48, 64, 4); + do_single_write_read_test(card, 128, 128, 4); + do_single_write_read_test(card, card->csd.capacity - 64, 32, 4); + do_single_write_read_test(card, card->csd.capacity - 64, 64, 4); + do_single_write_read_test(card, card->csd.capacity - 8, 1, 4); + do_single_write_read_test(card, card->csd.capacity/2, 1, 4); + do_single_write_read_test(card, card->csd.capacity/2, 4, 4); + do_single_write_read_test(card, card->csd.capacity/2, 8, 4); + do_single_write_read_test(card, card->csd.capacity/2, 16, 4); + do_single_write_read_test(card, card->csd.capacity/2, 32, 4); + do_single_write_read_test(card, card->csd.capacity/2, 64, 4); + do_single_write_read_test(card, card->csd.capacity/2, 128, 4); + do_single_write_read_test(card, card->csd.capacity/2, 1, 1); + do_single_write_read_test(card, card->csd.capacity/2, 8, 1); + do_single_write_read_test(card, card->csd.capacity/2, 128, 1); +} + +#if SOC_SDMMC_HOST_SUPPORTED +void test_sd_rw_blocks(int slot, int width) +{ + sdmmc_host_t config = SDMMC_HOST_DEFAULT(); + config.max_freq_khz = SDMMC_FREQ_HIGHSPEED; + config.slot = slot; + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + if (width != 0) { + slot_config.width = width; + } + if (slot_config.width == 8) { + config.flags &= ~SDMMC_HOST_FLAG_DDR; + } + TEST_ESP_OK(sdmmc_host_init()); + TEST_ESP_OK(sdmmc_host_init_slot(slot, &slot_config)); + sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); + TEST_ASSERT_NOT_NULL(card); + TEST_ESP_OK(sdmmc_card_init(&config, card)); + read_write_test(card); + free(card); + TEST_ESP_OK(sdmmc_host_deinit()); +} + +TEST_CASE("SDMMC read/write test (SD slot 1)", "[sd][test_env=UT_T1_SDMODE]") +{ + sd_test_board_power_on(); + test_sd_rw_blocks(1, 4); + sd_test_board_power_off(); +} + +#ifdef WITH_EMMC_TEST +TEST_CASE("SDMMC read/write test (eMMC slot 0, 4 line DDR)", "[sd][test_env=EMMC]") +{ + sd_test_board_power_on(); + test_sd_rw_blocks(0, 4); + sd_test_board_power_off(); +} + +TEST_CASE("SDMMC read/write test (eMMC slot 0, 8 line)", "[sd][test_env=EMMC]") +{ + sd_test_board_power_on(); + test_sd_rw_blocks(0, 8); + sd_test_board_power_off(); +} +#endif // WITH_EMMC_TEST +#endif // SDMMC_HOST_SUPPORTED + +#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32C3) +//No runners +TEST_CASE("SDMMC read/write test (SD slot 1, in SPI mode)", "[sdspi][test_env=UT_T1_SPIMODE]") +{ + sd_test_board_power_on(); + + sdspi_dev_handle_t handle; + sdspi_device_config_t dev_config = SDSPI_DEVICE_CONFIG_DEFAULT(); + test_sdspi_init_bus(dev_config.host_id, GPIO_NUM_15, GPIO_NUM_2, GPIO_NUM_14, TEST_SDSPI_DMACHAN); + TEST_ESP_OK(sdspi_host_init()); + TEST_ESP_OK(sdspi_host_init_device(&dev_config, &handle)); + + sdmmc_host_t config = SDSPI_HOST_DEFAULT(); + config.slot = handle; + // This test can only run under 20MHz on ESP32, because the runner connects the card to + // non-IOMUX pins of HSPI. + + sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); + TEST_ASSERT_NOT_NULL(card); + TEST_ESP_OK(sdmmc_card_init(&config, card)); + read_write_test(card); + TEST_ESP_OK(sdspi_host_deinit()); + free(card); + test_sdspi_deinit_bus(dev_config.host_id); + sd_test_board_power_off(); +} +#endif //DISABLED_FOR_TARGETS(ESP32S2, ESP32C3) + +#if SOC_SDMMC_HOST_SUPPORTED +TEST_CASE("reads and writes with an unaligned buffer", "[sd][test_env=UT_T1_SDMODE]") +{ + sd_test_board_power_on(); + sdmmc_host_t config = SDMMC_HOST_DEFAULT(); + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + TEST_ESP_OK(sdmmc_host_init()); + + TEST_ESP_OK(sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config)); + sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); + TEST_ASSERT_NOT_NULL(card); + TEST_ESP_OK(sdmmc_card_init(&config, card)); + + const size_t buffer_size = 4096; + const size_t block_count = buffer_size / 512; + const size_t extra = 4; + uint8_t* buffer = heap_caps_malloc(buffer_size + extra, MALLOC_CAP_DMA); + + // Check read behavior: do aligned write, then unaligned read + const uint32_t seed = 0x89abcdef; + fill_buffer(seed, buffer, buffer_size / sizeof(uint32_t)); + TEST_ESP_OK(sdmmc_write_sectors(card, buffer, 0, block_count)); + memset(buffer, 0xcc, buffer_size + extra); + TEST_ESP_OK(sdmmc_read_sectors(card, buffer + 1, 0, block_count)); + check_buffer(seed, buffer + 1, buffer_size / sizeof(uint32_t)); + + // Check write behavior: do unaligned write, then aligned read + fill_buffer(seed, buffer + 1, buffer_size / sizeof(uint32_t)); + TEST_ESP_OK(sdmmc_write_sectors(card, buffer + 1, 8, block_count)); + memset(buffer, 0xcc, buffer_size + extra); + TEST_ESP_OK(sdmmc_read_sectors(card, buffer, 8, block_count)); + check_buffer(seed, buffer, buffer_size / sizeof(uint32_t)); + + free(buffer); + free(card); + TEST_ESP_OK(sdmmc_host_deinit()); + sd_test_board_power_off(); +} +#endif + +__attribute__((unused)) static void test_cd_input(int gpio_cd_num, const sdmmc_host_t* config) +{ + sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); + TEST_ASSERT_NOT_NULL(card); + + // SDMMC host should have configured CD as input. + // Enable output as well (not using the driver, to avoid touching input + // enable bits). + esp_rom_gpio_connect_out_signal(gpio_cd_num, SIG_GPIO_OUT_IDX, false, false); + REG_WRITE(GPIO_ENABLE_W1TS_REG, BIT(gpio_cd_num)); + + // Check that card initialization fails if CD is high + REG_WRITE(GPIO_OUT_W1TS_REG, BIT(gpio_cd_num)); + usleep(1000); + TEST_ESP_ERR(ESP_ERR_NOT_FOUND, sdmmc_card_init(config, card)); + + // Check that card initialization succeeds if CD is low + REG_WRITE(GPIO_OUT_W1TC_REG, BIT(gpio_cd_num)); + usleep(1000); + TEST_ESP_OK(sdmmc_card_init(config, card)); + + free(card); +} + +#if SOC_SDMMC_HOST_SUPPORTED +TEST_CASE("CD input works in SD mode", "[sd][test_env=UT_T1_SDMODE]") +{ + sd_test_board_power_on(); + sdmmc_host_t config = SDMMC_HOST_DEFAULT(); + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + slot_config.gpio_cd = CD_WP_TEST_GPIO; + TEST_ESP_OK(sdmmc_host_init()); + TEST_ESP_OK(sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config)); + + test_cd_input(CD_WP_TEST_GPIO, &config); + + TEST_ESP_OK(sdmmc_host_deinit()); + sd_test_board_power_off(); +} +#endif + +#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32C3) +//No runners +TEST_CASE("CD input works in SPI mode", "[sd][test_env=UT_T1_SPIMODE]") +{ + sd_test_board_power_on(); + + sdspi_dev_handle_t handle; + sdspi_device_config_t dev_config = SDSPI_DEVICE_CONFIG_DEFAULT(); + dev_config.gpio_cd = CD_WP_TEST_GPIO; + test_sdspi_init_bus(dev_config.host_id, GPIO_NUM_15, GPIO_NUM_2, GPIO_NUM_14, TEST_SDSPI_DMACHAN); + TEST_ESP_OK(sdspi_host_init()); + TEST_ESP_OK(sdspi_host_init_device(&dev_config, &handle)); + + sdmmc_host_t config = SDSPI_HOST_DEFAULT(); + config.slot = handle; + + test_cd_input(CD_WP_TEST_GPIO, &config); + + TEST_ESP_OK(sdspi_host_deinit()); + test_sdspi_deinit_bus(dev_config.host_id); + sd_test_board_power_off(); +} +#endif //DISABLED_FOR_TARGETS(ESP32S2) + +__attribute__((unused)) static void test_wp_input(int gpio_wp_num, const sdmmc_host_t* config) +{ + sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); + TEST_ASSERT_NOT_NULL(card); + + // SDMMC host should have configured WP as input. + // Enable output as well (not using the driver, to avoid touching input + // enable bits). + esp_rom_gpio_connect_out_signal(gpio_wp_num, SIG_GPIO_OUT_IDX, false, false); + REG_WRITE(GPIO_ENABLE_W1TS_REG, BIT(gpio_wp_num)); + + // Check that the card can be initialized with WP low + REG_WRITE(GPIO_OUT_W1TC_REG, BIT(gpio_wp_num)); + TEST_ESP_OK(sdmmc_card_init(config, card)); + + uint32_t* data = heap_caps_calloc(1, 512, MALLOC_CAP_DMA); + + // Check that card write succeeds if WP is high + REG_WRITE(GPIO_OUT_W1TS_REG, BIT(gpio_wp_num)); + usleep(1000); + TEST_ESP_OK(sdmmc_write_sectors(card, &data, 0, 1)); + + // Check that write fails if WP is low + REG_WRITE(GPIO_OUT_W1TC_REG, BIT(gpio_wp_num)); + usleep(1000); + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, sdmmc_write_sectors(card, &data, 0, 1)); + // ...but reads still work + TEST_ESP_OK(sdmmc_read_sectors(card, &data, 0, 1)); + + free(data); + free(card); +} + +#if SOC_SDMMC_HOST_SUPPORTED +TEST_CASE("WP input works in SD mode", "[sd][test_env=UT_T1_SDMODE]") +{ + sd_test_board_power_on(); + sdmmc_host_t config = SDMMC_HOST_DEFAULT(); + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + slot_config.gpio_wp = CD_WP_TEST_GPIO; + TEST_ESP_OK(sdmmc_host_init()); + TEST_ESP_OK(sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config)); + + test_wp_input(CD_WP_TEST_GPIO, &config); + + TEST_ESP_OK(sdmmc_host_deinit()); + sd_test_board_power_off(); +} +#endif + +#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32C3) +//No runners +TEST_CASE("WP input works in SPI mode", "[sd][test_env=UT_T1_SPIMODE]") +{ + sd_test_board_power_on(); + + sdspi_dev_handle_t handle; + sdspi_device_config_t dev_config = SDSPI_DEVICE_CONFIG_DEFAULT(); + dev_config.gpio_wp = CD_WP_TEST_GPIO; + test_sdspi_init_bus(dev_config.host_id, GPIO_NUM_15, GPIO_NUM_2, GPIO_NUM_14, TEST_SDSPI_DMACHAN); + + TEST_ESP_OK(sdspi_host_init()); + TEST_ESP_OK(sdspi_host_init_device(&dev_config, &handle)); + + sdmmc_host_t config = SDSPI_HOST_DEFAULT(); + config.slot = handle; + + test_wp_input(CD_WP_TEST_GPIO, &config); + + TEST_ESP_OK(sdspi_host_deinit()); + test_sdspi_deinit_bus(dev_config.host_id); + sd_test_board_power_off(); +} +#endif //DISABLED_FOR_TARGETS(ESP32S2) diff --git a/lib/sdmmc/test/test_sdio.c b/lib/sdmmc/test/test_sdio.c new file mode 100644 index 0000000000..ecafb1639c --- /dev/null +++ b/lib/sdmmc/test/test_sdio.c @@ -0,0 +1,388 @@ +// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "soc/soc_caps.h" +#if SOC_SDMMC_HOST_SUPPORTED + +#include +#include +#include +#include "esp_log.h" +#include "esp_heap_caps.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "driver/sdmmc_host.h" +#include "driver/sdmmc_defs.h" +#include "sdmmc_cmd.h" +#include "unity.h" + +/* Second ESP32 board attached as follows: + * Master Slave + * IO18 EN + * IO19 IO0 + * IO14 SD_CLK + * IO15 SD_CMD + * IO2 SD_D0 + * IO4 SD_D1 + * IO12 SD_D2 + * IO13 SD_D3 + */ + + +/* TODO: add SDIO slave header files, remove these definitions */ + +#define DR_REG_SLC_MASK 0xfffffc00 + +#define SLCCONF1 (DR_REG_SLC_BASE + 0x60) +#define SLC_SLC0_RX_STITCH_EN (BIT(6)) +#define SLC_SLC0_TX_STITCH_EN (BIT(5)) + +#define SLC0TX_LINK (DR_REG_SLC_BASE + 0x40) +#define SLC_SLC0_TXLINK_PARK (BIT(31)) +#define SLC_SLC0_TXLINK_RESTART (BIT(30)) +#define SLC_SLC0_TXLINK_START (BIT(29)) + +#define DR_REG_SLCHOST_MASK 0xfffffc00 +#define SLCHOST_STATE_W0 (DR_REG_SLCHOST_BASE + 0x64) +#define SLCHOST_CONF_W0 (DR_REG_SLCHOST_BASE + 0x6C) +#define SLCHOST_CONF_W5 (DR_REG_SLCHOST_BASE + 0x80) +#define SLCHOST_WIN_CMD (DR_REG_SLCHOST_BASE + 0x84) + +#define SLC_WIN_CMD_READ 0x80 +#define SLC_WIN_CMD_WRITE 0xC0 +#define SLC_WIN_CMD_S 8 + +#define SLC_THRESHOLD_ADDR 0x1f800 + +static const char* TAG = "sdio_test"; + +static esp_err_t slave_slchost_reg_read(sdmmc_card_t* card, uint32_t addr, uint32_t* out_val) +{ + if ((addr & DR_REG_SLCHOST_MASK) != DR_REG_SLCHOST_BASE) { + ESP_LOGW(TAG, "%s: invalid addr 0x%08x\n", __func__, addr); + return ESP_ERR_INVALID_ARG; + } + return sdmmc_io_read_bytes(card, 1, addr & (~DR_REG_SLCHOST_MASK), out_val, sizeof(*out_val)); +} + +static esp_err_t slave_slchost_reg_write(sdmmc_card_t* card, uint32_t addr, uint32_t val) +{ + if ((addr & DR_REG_SLCHOST_MASK) != DR_REG_SLCHOST_BASE) { + ESP_LOGW(TAG, "%s: invalid addr 0x%08x\n", __func__, addr); + return ESP_ERR_INVALID_ARG; + } + return sdmmc_io_write_bytes(card, 1, addr & (~DR_REG_SLCHOST_MASK), &val, sizeof(val)); +} + +static esp_err_t slave_slc_reg_read(sdmmc_card_t* card, uint32_t addr, uint32_t* val) +{ + if ((addr & DR_REG_SLC_MASK) != DR_REG_SLC_BASE) { + ESP_LOGW(TAG, "%s: invalid addr 0x%08x\n", __func__, addr); + return ESP_ERR_INVALID_ARG; + } + uint32_t word = (addr - DR_REG_SLC_BASE) / 4; + if (word > INT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + uint32_t window_command = word | (SLC_WIN_CMD_READ << SLC_WIN_CMD_S); + esp_err_t err = slave_slchost_reg_write(card, SLCHOST_WIN_CMD, window_command); + if (err != ESP_OK) { + return err; + } + + return slave_slchost_reg_read(card, SLCHOST_STATE_W0, val); +} + +static esp_err_t slave_slc_reg_write(sdmmc_card_t* card, uint32_t addr, uint32_t val) +{ + if ((addr & DR_REG_SLC_MASK) != DR_REG_SLC_BASE) { + ESP_LOGW(TAG, "%s: invalid addr 0x%08x\n", __func__, addr); + return ESP_ERR_INVALID_ARG; + } + uint32_t word = (addr - DR_REG_SLC_BASE) / 4; + if (word > INT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + esp_err_t err = slave_slchost_reg_write(card, SLCHOST_CONF_W5, val); + if (err != ESP_OK) { + return err; + } + + uint32_t window_command = word | (SLC_WIN_CMD_WRITE << SLC_WIN_CMD_S); + return slave_slchost_reg_write(card, SLCHOST_WIN_CMD, window_command); +} + +/** Reset and put slave into download mode */ +static void reset_slave(void) +{ + const int pin_en = 18; + const int pin_io0 = 19; + gpio_config_t gpio_cfg = { + .pin_bit_mask = BIT64(pin_en) | BIT64(pin_io0), + .mode = GPIO_MODE_OUTPUT_OD, + }; + TEST_ESP_OK(gpio_config(&gpio_cfg)); + gpio_set_level(pin_en, 0); + gpio_set_level(pin_io0, 0); + vTaskDelay(10 / portTICK_PERIOD_MS); + gpio_set_level(pin_en, 1); + vTaskDelay(10 / portTICK_PERIOD_MS); + gpio_set_level(pin_io0, 1); +} + +static void sdio_slave_common_init(sdmmc_card_t* card) +{ + uint8_t card_cap; + esp_err_t err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_CARD_CAP, &card_cap); + TEST_ESP_OK(err); + printf("CAP: 0x%02x\n", card_cap); + + uint8_t hs; + err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_HIGHSPEED, &hs); + TEST_ESP_OK(err); + printf("HS: 0x%02x\n", hs); + + +#define FUNC1_EN_MASK (BIT(1)) + + uint8_t ioe; + err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_ENABLE, &ioe); + TEST_ESP_OK(err); + printf("IOE: 0x%02x\n", ioe); + + uint8_t ior = 0; + err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_READY, &ior); + TEST_ESP_OK(err); + printf("IOR: 0x%02x\n", ior); + + // enable function 1 + ioe |= FUNC1_EN_MASK; + err = sdmmc_io_write_byte(card, 0, SD_IO_CCCR_FN_ENABLE, ioe, NULL); + TEST_ESP_OK(err); + + err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_ENABLE, &ioe); + TEST_ESP_OK(err); + printf("IOE: 0x%02x\n", ioe); + + // wait for the card to become ready + while ( (ior & FUNC1_EN_MASK) == 0 ) { + err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_READY, &ior); + TEST_ESP_OK(err); + printf("IOR: 0x%02x\n", ior); + } + + // get interrupt status + uint8_t ie; + err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_INT_ENABLE, &ie); + TEST_ESP_OK(err); + printf("IE: 0x%02x\n", ie); + + // enable interrupts for function 1&2 and master enable + ie |= BIT(0) | FUNC1_EN_MASK; + err = sdmmc_io_write_byte(card, 0, SD_IO_CCCR_INT_ENABLE, ie, NULL); + TEST_ESP_OK(err); + + err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_INT_ENABLE, &ie); + TEST_ESP_OK(err); + printf("IE: 0x%02x\n", ie); +} + +/** Common for all SDIO devices, set block size for specific function */ +static void sdio_slave_set_blocksize(sdmmc_card_t* card, int function, uint16_t bs) +{ + const uint8_t* bs_u8 = (const uint8_t*) &bs; + uint16_t bs_read = 0; + uint8_t* bs_read_u8 = (uint8_t*) &bs_read; + uint32_t offset = SD_IO_FBR_START * function; + TEST_ESP_OK( sdmmc_io_write_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEL, bs_u8[0], NULL)); + TEST_ESP_OK( sdmmc_io_write_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEH, bs_u8[1], NULL)); + TEST_ESP_OK( sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEL, &bs_read_u8[0])); + TEST_ESP_OK( sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEH, &bs_read_u8[1])); + TEST_ASSERT_EQUAL_HEX16(bs, bs_read); +} + +/** + * ESP32 ROM code does not set some SDIO slave registers to the defaults + * we need, this function clears/sets some bits. + */ +static void esp32_slave_init_extra(sdmmc_card_t* card) +{ + printf("Initialize some ESP32 SDIO slave registers\n"); + + uint32_t reg_val; + TEST_ESP_OK( slave_slc_reg_read(card, SLCCONF1, ®_val) ); + reg_val &= ~(SLC_SLC0_RX_STITCH_EN | SLC_SLC0_TX_STITCH_EN); + TEST_ESP_OK( slave_slc_reg_write(card, SLCCONF1, reg_val) ); + + TEST_ESP_OK( slave_slc_reg_read(card, SLC0TX_LINK, ®_val) ); + reg_val |= SLC_SLC0_TXLINK_START; + TEST_ESP_OK( slave_slc_reg_write(card, SLC0TX_LINK, reg_val) ); +} + +/** + * ESP32 bootloader implements "SIP" protocol which can be used to exchange + * some commands, events, and data packets between the host and the slave. + * This function sends a SIP command, testing CMD53 block writes along the way. + */ +static void esp32_send_sip_command(sdmmc_card_t* card) +{ + printf("Test block write using CMD53\n"); + const size_t block_size = 512; + uint8_t* data = heap_caps_calloc(1, block_size, MALLOC_CAP_DMA); + struct sip_cmd_bootup { + uint32_t boot_addr; + uint32_t discard_link; + }; + struct sip_cmd_write_reg { + uint32_t addr; + uint32_t val; + }; + struct sip_hdr { + uint8_t fc[2]; + uint16_t len; + uint32_t cmdid; + uint32_t seq; + }; + + struct sip_hdr* hdr = (struct sip_hdr*) data; + size_t len; + +#define SEND_WRITE_REG_CMD + +#ifdef SEND_WRITE_REG_CMD + struct sip_cmd_write_reg *write_reg = (struct sip_cmd_write_reg*) (data + sizeof(*hdr)); + len = sizeof(*hdr) + sizeof(*write_reg); + hdr->cmdid = 3; /* SIP_CMD_WRITE_REG */ + write_reg->addr = GPIO_ENABLE_W1TS_REG; + write_reg->val = BIT(0) | BIT(2) | BIT(4); /* Turn of RGB LEDs on WROVER-KIT */ +#else + struct sip_cmd_bootup *bootup = (struct sip_cmd_bootup*) (data + sizeof(*hdr)); + len = sizeof(*hdr) + sizeof(*bootup); + hdr->cmdid = 5; /* SIP_CMD_BOOTUP */ + bootup->boot_addr = 0x4005a980; /* start_tb_console function in ROM */ + bootup->discard_link = 1; +#endif + hdr->len = len; + + TEST_ESP_OK( sdmmc_io_write_blocks(card, 1, SLC_THRESHOLD_ADDR - len, data, block_size) ); + free(data); +} + +static void test_cmd52_read_write_single_byte(sdmmc_card_t* card) +{ + esp_err_t err; + printf("Write bytes to slave's W0_REG using CMD52\n"); + const size_t scratch_area_reg = SLCHOST_CONF_W0 - DR_REG_SLCHOST_BASE; + + const uint8_t test_byte_1 = 0xa5; + const uint8_t test_byte_2 = 0xb6; + // used to check Read-After-Write + uint8_t test_byte_1_raw; + uint8_t test_byte_2_raw; + uint8_t val = 0; + err = sdmmc_io_write_byte(card, 1, scratch_area_reg, test_byte_1, &test_byte_1_raw); + TEST_ESP_OK(err); + TEST_ASSERT_EQUAL_UINT8(test_byte_1, test_byte_1_raw); + err = sdmmc_io_write_byte(card, 1, scratch_area_reg + 1, test_byte_2, &test_byte_2_raw); + TEST_ESP_OK(err); + TEST_ASSERT_EQUAL_UINT8(test_byte_2, test_byte_2_raw); + + printf("Read back bytes using CMD52\n"); + TEST_ESP_OK(sdmmc_io_read_byte(card, 1, scratch_area_reg, &val)); + TEST_ASSERT_EQUAL_UINT8(test_byte_1, val); + + TEST_ESP_OK(sdmmc_io_read_byte(card, 1, scratch_area_reg + 1, &val)); + TEST_ASSERT_EQUAL_UINT8(test_byte_2, val); +} + +static void test_cmd53_read_write_multiple_bytes(sdmmc_card_t* card, size_t n_bytes) +{ + printf("Write multiple bytes using CMD53\n"); + const size_t scratch_area_reg = SLCHOST_CONF_W0 - DR_REG_SLCHOST_BASE; + + uint8_t* src = heap_caps_malloc(512, MALLOC_CAP_DMA); + uint32_t* src_32 = (uint32_t*) src; + + for (size_t i = 0; i < (n_bytes + 3) / 4; ++i) { + src_32[i] = rand(); + } + + TEST_ESP_OK(sdmmc_io_write_bytes(card, 1, scratch_area_reg, src, n_bytes)); + ESP_LOG_BUFFER_HEX(TAG, src, n_bytes); + + printf("Read back using CMD52\n"); + uint8_t* dst = heap_caps_malloc(512, MALLOC_CAP_DMA); + for (size_t i = 0; i < n_bytes; ++i) { + TEST_ESP_OK(sdmmc_io_read_byte(card, 1, scratch_area_reg + i, &dst[i])); + } + ESP_LOG_BUFFER_HEX(TAG, dst, n_bytes); + TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, n_bytes); + + printf("Read back using CMD53\n"); + TEST_ESP_OK(sdmmc_io_read_bytes(card, 1, scratch_area_reg, dst, n_bytes)); + ESP_LOG_BUFFER_HEX(TAG, dst, n_bytes); + TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, n_bytes); + + free(src); + free(dst); +} + + +TEST_CASE("can probe and talk to ESP32 SDIO slave", "[sdio][ignore]") +{ + reset_slave(); + + /* Probe */ + sdmmc_host_t config = SDMMC_HOST_DEFAULT(); + config.flags = SDMMC_HOST_FLAG_1BIT; + config.max_freq_khz = SDMMC_FREQ_PROBING; + + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + (sdmmc_host_init()); + (sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config)); + sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); + TEST_ASSERT_NOT_NULL(card); + TEST_ESP_OK(sdmmc_card_init(&config, card)); + sdmmc_card_print_info(stdout, card); + + /* Set up standard SDIO registers */ + sdio_slave_common_init(card); + + srand(0); + for (int repeat = 0; repeat < 4; ++repeat) { + test_cmd52_read_write_single_byte(card); + test_cmd53_read_write_multiple_bytes(card, 1); + test_cmd53_read_write_multiple_bytes(card, 2); + test_cmd53_read_write_multiple_bytes(card, 3); + test_cmd53_read_write_multiple_bytes(card, 4); + test_cmd53_read_write_multiple_bytes(card, 5); + test_cmd53_read_write_multiple_bytes(card, 23); + test_cmd53_read_write_multiple_bytes(card, 24); + } + + sdio_slave_set_blocksize(card, 0, 512); + sdio_slave_set_blocksize(card, 1, 512); + + esp32_slave_init_extra(card); + + esp32_send_sip_command(card); + + TEST_ESP_OK(sdmmc_host_deinit()); + free(card); +} + +#endif //SOC_SDMMC_HOST_SUPPORTED diff --git a/lib/tinyusb b/lib/tinyusb index 43aac7074b..ae73873b5c 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit 43aac7074be0d14e72cb04eaddcddf1a926c6a74 +Subproject commit ae73873b5cba0eb11c89165f4559964940430d44 diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index f7614caa2f..e2bbbd962a 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1221,6 +1221,10 @@ msgstr "" msgid "Insufficient encryption" msgstr "" +#: ports/espressif/common-hal/wifi/Radio.c +msgid "Interface must be started" +msgstr "" + #: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c msgid "Internal audio buffer too small" msgstr "" @@ -2142,10 +2146,6 @@ msgstr "" msgid "Stack size must be at least 256" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -msgid "Interface must be started" -msgstr "" - #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c msgid "Stereo left must be on PWM channel A" msgstr "" diff --git a/main.c b/main.c index a189add5e2..988253d0d3 100644 --- a/main.c +++ b/main.c @@ -158,7 +158,7 @@ STATIC void start_mp(supervisor_allocation *heap) { gc_init(heap->ptr, heap->ptr + get_allocation_length(heap) / 4); #endif mp_init(); - mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_init((mp_obj_list_t *)mp_sys_path, 0); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_)); // Frozen modules are in their own pseudo-dir, e.g., ".frozen". @@ -166,7 +166,7 @@ STATIC void start_mp(supervisor_allocation *heap) { mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_FROZEN_FAKE_DIR_QSTR)); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib)); - mp_obj_list_init(mp_sys_argv, 0); + mp_obj_list_init((mp_obj_list_t *)mp_sys_argv, 0); #if CIRCUITPY_ALARM // Record which alarm woke us up, if any. An object may be created so the heap must be functional. @@ -797,6 +797,9 @@ int __attribute__((used)) main(void) { supervisor_bluetooth_init(); #endif + // Start the debug serial + serial_early_init(); + // Create a new filesystem only if we're not in a safe mode. // A power brownout here could make it appear as if there's // no SPI flash filesystem, and we might erase the existing one. @@ -805,9 +808,6 @@ int __attribute__((used)) main(void) { // displays init after filesystem, since they could share the flash SPI board_init(); - // Start the debug serial - serial_early_init(); - // Reset everything and prep MicroPython to run boot.py. reset_port(); // Port-independent devices, like CIRCUITPY_BLEIO_HCI. @@ -905,7 +905,7 @@ void gc_collect(void) { // This naively collects all object references from an approximate stack // range. - gc_collect_root((void **)sp, ((uint32_t)port_stack_get_top() - sp) / sizeof(uint32_t)); + gc_collect_root((void **)sp, ((mp_uint_t)port_stack_get_top() - sp) / sizeof(mp_uint_t)); gc_collect_end(); } diff --git a/ports/atmel-samd/common-hal/canio/CAN.c b/ports/atmel-samd/common-hal/canio/CAN.c index 2ad292195d..cd5100ed52 100644 --- a/ports/atmel-samd/common-hal/canio/CAN.c +++ b/ports/atmel-samd/common-hal/canio/CAN.c @@ -47,7 +47,7 @@ STATIC canio_can_obj_t *can_objs[MP_ARRAY_SIZE(can_insts)]; // This must be placed in the first 64kB of RAM STATIC COMPILER_SECTION(".canram") canio_can_state_t can_state[MP_ARRAY_SIZE(can_insts)]; -void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *tx, mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent) { +void common_hal_canio_can_construct(canio_can_obj_t *self, const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent) { mcu_pin_function_t *tx_function = mcu_find_pin_function(can_tx, tx, -1, MP_QSTR_tx); int instance = tx_function->instance; diff --git a/ports/atmel-samd/common-hal/sdioio/SDCard.c b/ports/atmel-samd/common-hal/sdioio/SDCard.c index 9c8c1abf39..10ccb63a55 100644 --- a/ports/atmel-samd/common-hal/sdioio/SDCard.c +++ b/ports/atmel-samd/common-hal/sdioio/SDCard.c @@ -59,7 +59,7 @@ static Sdhc *sdhc_insts[] = SDHC_INSTS; void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *command, - uint8_t num_data, mcu_pin_obj_t **data, uint32_t frequency) { + uint8_t num_data, const mcu_pin_obj_t **data, uint32_t frequency) { /* SD breakout as assembled ("*" = minimum viable set) diff --git a/ports/broadcom/Makefile b/ports/broadcom/Makefile new file mode 100644 index 0000000000..a5a3f744b7 --- /dev/null +++ b/ports/broadcom/Makefile @@ -0,0 +1,179 @@ +# Select the board to build for. +BOARD=raspberrypi_pi4 + +ifeq ($(BOARD),) + $(error You must provide a BOARD parameter) +else + ifeq ($(wildcard boards/$(BOARD)/.),) + $(error Invalid BOARD specified) + endif +endif + +# If the build directory is not given, make it reflect the board name. +BUILD ?= build-$(BOARD) + +include ../../py/mkenv.mk +# Board-specific +include boards/$(BOARD)/mpconfigboard.mk +# Port-specific +include mpconfigport.mk +# CircuitPython-specific +include $(TOP)/py/circuitpy_mpconfig.mk + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h + +# include py core make definitions +include $(TOP)/py/py.mk + +include $(TOP)/supervisor/supervisor.mk + +# Include make rules and variables common across CircuitPython builds. +include $(TOP)/py/circuitpy_defns.mk + +HAL_DIR=hal/$(MCU_SERIES) + +INC += -I. \ + -I../.. \ + -I../../lib/mp-readline \ + -I../../lib/timeutils \ + -I../../lib/sdmmc/include \ + -Iboards/$(BOARD) \ + -Iboards/ \ + -Iperipherals/ \ + -I../../lib/tinyusb/src \ + -I../../supervisor/shared/usb \ + -I$(BUILD) + + +SRC_C += bindings/videocore/__init__.c \ + bindings/videocore/Framebuffer.c \ + boards/$(BOARD)/board.c \ + boards/$(BOARD)/pins.c \ + background.c \ + common-hal/videocore/Framebuffer.c \ + fatfs_port.c \ + mphalport.c \ + lib/sdmmc/sdmmc_cmd.c \ + lib/sdmmc/sdmmc_common.c \ + lib/sdmmc/sdmmc_init.c \ + lib/sdmmc/sdmmc_io.c \ + lib/sdmmc/sdmmc_mmc.c \ + lib/sdmmc/sdmmc_sd.c \ + lib/tinyusb/src/portable/synopsys/dwc2/dcd_dwc2.c \ + peripherals/broadcom/caches.c \ + peripherals/broadcom/gen/interrupt_handlers.c \ + peripherals/broadcom/gpio.c \ + peripherals/broadcom/interrupts.c \ + peripherals/broadcom/mmu.c \ + peripherals/broadcom/vcmailbox.c + + +SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ + $(addprefix shared-bindings/, $(SRC_BINDINGS_ENUMS)) \ + $(addprefix common-hal/, $(SRC_COMMON_HAL)) + +SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE)) \ + $(addprefix shared-module/, $(SRC_SHARED_MODULE)) \ + $(addprefix shared-module/, $(SRC_SHARED_MODULE_INTERNAL)) + +# There may be duplicates between SRC_COMMON_HAL_EXPANDED and SRC_SHARED_MODULE_EXPANDED, +# because a few modules have files both in common-hal/ and shared-modules/. +# Doing a $(sort ...) removes duplicates as part of sorting. +SRC_COMMON_HAL_SHARED_MODULE_EXPANDED = $(sort $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED)) +SRC_S = peripherals/broadcom/boot.s + +OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) + ifeq ($(INTERNAL_LIBM),1) +OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) +endif +OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) + +# BCM CLFAGS +CFLAGS += -ffreestanding -nostartfiles -DMICROPY_HW_MCU_NAME="\"$(CHIP_VARIANT)\"" + +ifeq ($(CHIP_VARIANT), "bcm2711") +CFLAGS += -mcpu=cortex-a72 -DBCM_VERSION=2711 +CROSS_COMPILE = aarch64-none-elf- +else +CFLAGS += -mcpu=cortex-a53 -DBCM_VERSION=2837 +CROSS_COMPILE = aarch64-none-elf- +# TODO add 32-bit support for Cortex-A7 and ARM1176 +endif + + +OPTIMIZATION_FLAGS ?= -O3 +CFLAGS += $(OPTIMIZATION_FLAGS) + +# TinyUSB defines +CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_BCM2711 -DCFG_TUD_MIDI_RX_BUFSIZE=512 \ + -DCFG_TUD_CDC_RX_BUFSIZE=512 -DCFG_TUD_MIDI_TX_BUFSIZE=512 \ + -DCFG_TUD_CDC_TX_BUFSIZE=512 -DCFG_TUD_MSC_BUFSIZE=1024 + +#Debugging/Optimization +ifeq ($(DEBUG), 1) + CFLAGS += -ggdb3 -Og + # No LTO because we may place some functions in RAM instead of flash. +else + CFLAGS += -DNDEBUG -ggdb3 + + # No LTO because we may place some functions in RAM instead of flash. + + ifdef CFLAGS_BOARD + CFLAGS += $(CFLAGS_BOARD) + endif +endif + + +CFLAGS += $(INC) -Wall -Werror -std=gnu11 $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) $(DISABLE_WARNINGS) + + +SRC_QSTR += $(SRC_C) $(SRC_SUPERVISOR) $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED) + +LDFLAGS += $(CFLAGS) -T peripherals/broadcom/link.ld -Wl,--gc-sections -Wl,-Map=$@.map # -Wl,--cref + +# Use toolchain libm if we're not using our own. +ifndef INTERNAL_LIBM +LIBS += -lm +endif + +all: $(BUILD)/firmware.kernel8.img $(BUILD)/firmware.disk.img.zip + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILD)/kernel8.elf: $(OBJ) + $(STEPECHO) "LINK $@" + $(Q)echo $(OBJ) > $(BUILD)/firmware.objs + $(Q)$(CC) -o $@ $(LDFLAGS) @$(BUILD)/firmware.objs -Wl,--start-group $(LIBS) -Wl,--end-group + +$(BUILD)/kernel8.img: $(BUILD)/kernel8.elf + $(STEPECHO) "Create $@" + $(OBJCOPY) -O binary $(BUILD)/kernel8.elf $@ + +$(BUILD)/firmware.kernel8.img: $(BUILD)/kernel8.img + $(STEPECHO) "Create $@" + $(CP) $^ $@ + +$(BUILD)/firmware.disk.img.zip: $(BUILD)/kernel8.img + $(STEPECHO) "Create $@" + $(Q)dd if=/dev/zero of=$(BUILD)/circuitpython-disk.img bs=1 count=0 seek=256M + $(Q)parted -s $(BUILD)/circuitpython-disk.img mktable msdos + $(Q)parted -s $(BUILD)/circuitpython-disk.img mkpart primary fat32 0% 100% + $(Q)mkfs.fat -F 32 -n BOOT --offset=2048 $(BUILD)/circuitpython-disk.img + + $(Q)mcopy -i $(BUILD)/circuitpython-disk.img@@1M config.txt firmware/bootcode.bin firmware/fixup* firmware/start* :: + $(Q)mcopy -i $(BUILD)/circuitpython-disk.img@@1M $(BUILD)/kernel8.img :: + $(Q)zip $@ $(BUILD)/circuitpython-disk.img + $(Q)rm $(BUILD)/circuitpython-disk.img + +include $(TOP)/py/mkrules.mk + + +# Print out the value of a make variable. +# https://stackoverflow.com/questions/16467718/how-to-print-out-a-variable-in-makefile +print-%: + @echo $* = $($*) diff --git a/ports/broadcom/background.c b/ports/broadcom/background.c new file mode 100644 index 0000000000..4b5190aa27 --- /dev/null +++ b/ports/broadcom/background.c @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "background.h" + +#include "py/runtime.h" +#include "supervisor/port.h" + +void port_start_background_task(void) { +} +void port_finish_background_task(void) { +} + +void port_background_task(void) { +} diff --git a/ports/broadcom/background.h b/ports/broadcom/background.h new file mode 100644 index 0000000000..ecbdd5d363 --- /dev/null +++ b/ports/broadcom/background.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_BROADCOM_BACKGROUND_H +#define MICROPY_INCLUDED_BROADCOM_BACKGROUND_H + +#include + +#endif // MICROPY_INCLUDED_BROADCOM_BACKGROUND_H diff --git a/ports/broadcom/bindings/videocore/Framebuffer.c b/ports/broadcom/bindings/videocore/Framebuffer.c new file mode 100644 index 0000000000..60c9ff4247 --- /dev/null +++ b/ports/broadcom/bindings/videocore/Framebuffer.c @@ -0,0 +1,197 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/objarray.h" + +#include "bindings/videocore/Framebuffer.h" +#include "shared-bindings/util.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/framebufferio/__init__.h" +#include "shared-module/framebufferio/FramebufferDisplay.h" + +//| class Framebuffer: +//| """A VideoCore managed frame buffer.""" +//| +//| def __init__(self, width: int, height: int) -> None: +//| """Create a Framebuffer object with the given dimensions. Memory is +//| allocated outside of the heap in GPU memory. +//| +//| The framebuffer is in "ARGB8888" format. +//| +//| A Framebuffer is often used in conjunction with a +//| `framebufferio.FramebufferDisplay`.""" +//| + +STATIC mp_obj_t videocore_framebuffer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_width, ARG_height, }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + videocore_framebuffer_obj_t *self = &allocate_display_bus_or_raise()->videocore; + self->base.type = &videocore_framebuffer_type; + + if (args[ARG_width].u_int <= 0) { + mp_raise_ValueError(translate("width must be greater than zero")); + } + + common_hal_videocore_framebuffer_construct(self, + args[ARG_width].u_int, + args[ARG_height].u_int); + + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Free the resources (pins, timers, etc.) associated with this +//| rgbmatrix instance. After deinitialization, no further operations +//| may be performed.""" +//| ... +//| +STATIC mp_obj_t videocore_framebuffer_deinit(mp_obj_t self_in) { + videocore_framebuffer_obj_t *self = (videocore_framebuffer_obj_t *)self_in; + common_hal_videocore_framebuffer_deinit(self); + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(videocore_framebuffer_deinit_obj, videocore_framebuffer_deinit); + +static void check_for_deinit(videocore_framebuffer_obj_t *self) { + if (common_hal_videocore_framebuffer_deinited(self)) { + raise_deinited_error(); + } +} + +//| width: int +//| """The width of the display, in pixels""" +//| +STATIC mp_obj_t videocore_framebuffer_get_width(mp_obj_t self_in) { + videocore_framebuffer_obj_t *self = (videocore_framebuffer_obj_t *)self_in; + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_videocore_framebuffer_get_width(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(videocore_framebuffer_get_width_obj, videocore_framebuffer_get_width); +const mp_obj_property_t videocore_framebuffer_width_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&videocore_framebuffer_get_width_obj, + MP_ROM_NONE, + MP_ROM_NONE}, +}; + +//| height: int +//| """The height of the display, in pixels""" +//| +STATIC mp_obj_t videocore_framebuffer_get_height(mp_obj_t self_in) { + videocore_framebuffer_obj_t *self = (videocore_framebuffer_obj_t *)self_in; + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_videocore_framebuffer_get_height(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(videocore_framebuffer_get_height_obj, videocore_framebuffer_get_height); + +const mp_obj_property_t videocore_framebuffer_height_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&videocore_framebuffer_get_height_obj, + MP_ROM_NONE, + MP_ROM_NONE}, +}; + +STATIC const mp_rom_map_elem_t videocore_framebuffer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&videocore_framebuffer_deinit_obj) }, + + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&videocore_framebuffer_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&videocore_framebuffer_height_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(videocore_framebuffer_locals_dict, videocore_framebuffer_locals_dict_table); + +STATIC void videocore_framebuffer_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufinfo) { + common_hal_videocore_framebuffer_get_buffer(self_in, bufinfo, 0); +} + +// These version exists so that the prototype matches the protocol, +// avoiding a type cast that can hide errors +STATIC void videocore_framebuffer_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) { + (void)dirty_row_bitmap; + common_hal_videocore_framebuffer_refresh(self_in); +} + +STATIC void videocore_framebuffer_deinit_proto(mp_obj_t self_in) { + common_hal_videocore_framebuffer_deinit(self_in); +} + +STATIC int videocore_framebuffer_get_width_proto(mp_obj_t self_in) { + return common_hal_videocore_framebuffer_get_width(self_in); +} + +STATIC int videocore_framebuffer_get_height_proto(mp_obj_t self_in) { + return common_hal_videocore_framebuffer_get_height(self_in); +} + +STATIC int videocore_framebuffer_get_color_depth_proto(mp_obj_t self_in) { + return 32; +} + +STATIC int videocore_framebuffer_get_bytes_per_cell_proto(mp_obj_t self_in) { + return 1; +} + +STATIC int videocore_framebuffer_get_native_frames_per_second_proto(mp_obj_t self_in) { + return 30; +} + +STATIC int videocore_framebuffer_get_row_stride_proto(mp_obj_t self_in) { + return common_hal_videocore_framebuffer_get_row_stride(self_in); +} + +STATIC const framebuffer_p_t videocore_framebuffer_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_framebuffer) + .get_bufinfo = videocore_framebuffer_get_bufinfo, + .get_width = videocore_framebuffer_get_width_proto, + .get_height = videocore_framebuffer_get_height_proto, + .get_color_depth = videocore_framebuffer_get_color_depth_proto, + .get_row_stride = videocore_framebuffer_get_row_stride_proto, + .get_bytes_per_cell = videocore_framebuffer_get_bytes_per_cell_proto, + .get_native_frames_per_second = videocore_framebuffer_get_native_frames_per_second_proto, + .swapbuffers = videocore_framebuffer_swapbuffers, + .deinit = videocore_framebuffer_deinit_proto, +}; + +const mp_obj_type_t videocore_framebuffer_type = { + { &mp_type_type }, + .flags = MP_TYPE_FLAG_EXTENDED, + .name = MP_QSTR_Framebuffer, + .locals_dict = (mp_obj_dict_t *)&videocore_framebuffer_locals_dict, + .make_new = videocore_framebuffer_make_new, + MP_TYPE_EXTENDED_FIELDS( + .buffer_p = { .get_buffer = common_hal_videocore_framebuffer_get_buffer, }, + .protocol = &videocore_framebuffer_proto, + ), +}; diff --git a/ports/broadcom/bindings/videocore/Framebuffer.h b/ports/broadcom/bindings/videocore/Framebuffer.h new file mode 100644 index 0000000000..305cad1568 --- /dev/null +++ b/ports/broadcom/bindings/videocore/Framebuffer.h @@ -0,0 +1,40 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "common-hal/videocore/Framebuffer.h" + +extern const mp_obj_type_t videocore_framebuffer_type; + +void common_hal_videocore_framebuffer_construct(videocore_framebuffer_obj_t *self, uint16_t width, uint16_t height); +void common_hal_videocore_framebuffer_deinit(videocore_framebuffer_obj_t *self); +bool common_hal_videocore_framebuffer_deinited(videocore_framebuffer_obj_t *self); +void common_hal_videocore_framebuffer_refresh(videocore_framebuffer_obj_t *self); +int common_hal_videocore_framebuffer_get_width(videocore_framebuffer_obj_t *self); +int common_hal_videocore_framebuffer_get_height(videocore_framebuffer_obj_t *self); +int common_hal_videocore_framebuffer_get_row_stride(videocore_framebuffer_obj_t *self); +mp_int_t common_hal_videocore_framebuffer_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags); diff --git a/ports/broadcom/bindings/videocore/__init__.c b/ports/broadcom/bindings/videocore/__init__.c new file mode 100644 index 0000000000..94a483adb5 --- /dev/null +++ b/ports/broadcom/bindings/videocore/__init__.c @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "bindings/videocore/Framebuffer.h" + +//| """Low-level routines for interacting with the Broadcom VideoCore GPU""" +//| + +STATIC const mp_rom_map_elem_t videocore_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_videocore) }, + { MP_ROM_QSTR(MP_QSTR_Framebuffer), MP_ROM_PTR(&videocore_framebuffer_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(videocore_module_globals, videocore_module_globals_table); + +const mp_obj_module_t videocore_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&videocore_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_videocore, videocore_module, CIRCUITPY_VIDEOCORE); diff --git a/ports/broadcom/boards/raspberrypi_cm4io/board.c b/ports/broadcom/boards/raspberrypi_cm4io/board.c new file mode 100644 index 0000000000..615a8e730e --- /dev/null +++ b/ports/broadcom/boards/raspberrypi_cm4io/board.c @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "supervisor/board.h" +#include "mpconfigboard.h" + +#include "bindings/videocore/Framebuffer.h" +#include "shared-module/displayio/__init__.h" +#include "shared-bindings/framebufferio/FramebufferDisplay.h" + +void board_init(void) { + videocore_framebuffer_obj_t *fb = &allocate_display_bus()->videocore; + fb->base.type = &videocore_framebuffer_type; + common_hal_videocore_framebuffer_construct(fb, 640, 480); + + framebufferio_framebufferdisplay_obj_t *display = &displays[0].framebuffer_display; + display->base.type = &framebufferio_framebufferdisplay_type; + common_hal_framebufferio_framebufferdisplay_construct( + display, + MP_OBJ_FROM_PTR(fb), + 0, + true); +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { +} diff --git a/ports/broadcom/boards/raspberrypi_cm4io/mpconfigboard.h b/ports/broadcom/boards/raspberrypi_cm4io/mpconfigboard.h new file mode 100644 index 0000000000..014d8a0713 --- /dev/null +++ b/ports/broadcom/boards/raspberrypi_cm4io/mpconfigboard.h @@ -0,0 +1 @@ +#define MICROPY_HW_BOARD_NAME "Raspberry Pi Compute Module 4 IO Board" diff --git a/ports/broadcom/boards/raspberrypi_cm4io/mpconfigboard.mk b/ports/broadcom/boards/raspberrypi_cm4io/mpconfigboard.mk new file mode 100644 index 0000000000..d430579260 --- /dev/null +++ b/ports/broadcom/boards/raspberrypi_cm4io/mpconfigboard.mk @@ -0,0 +1,6 @@ +USB_VID = 0x2E8A +USB_PID = 0xf000 +USB_PRODUCT = "Compute Module 4 IO Board" +USB_MANUFACTURER = "Raspberry Pi" + +CHIP_VARIANT = "bcm2711" diff --git a/ports/broadcom/boards/raspberrypi_cm4io/pins.c b/ports/broadcom/boards/raspberrypi_cm4io/pins.c new file mode 100644 index 0000000000..02682d7c4d --- /dev/null +++ b/ports/broadcom/boards/raspberrypi_cm4io/pins.c @@ -0,0 +1,62 @@ +#include "shared-bindings/board/__init__.h" + +#include "shared-module/displayio/__init__.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // These match the names used in Blinka + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, + + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_CE1), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_CE0), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_SCLK), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_TXD), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_RXD), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO15) }, + + { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_MISO_1), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_MOSI_1), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_D21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_SCLK_1), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_SCK_1), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_D22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_D24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_D26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_D27), MP_ROM_PTR(&pin_GPIO27) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)}, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/broadcom/boards/raspberrypi_pi4b/board.c b/ports/broadcom/boards/raspberrypi_pi4b/board.c new file mode 100644 index 0000000000..615a8e730e --- /dev/null +++ b/ports/broadcom/boards/raspberrypi_pi4b/board.c @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "supervisor/board.h" +#include "mpconfigboard.h" + +#include "bindings/videocore/Framebuffer.h" +#include "shared-module/displayio/__init__.h" +#include "shared-bindings/framebufferio/FramebufferDisplay.h" + +void board_init(void) { + videocore_framebuffer_obj_t *fb = &allocate_display_bus()->videocore; + fb->base.type = &videocore_framebuffer_type; + common_hal_videocore_framebuffer_construct(fb, 640, 480); + + framebufferio_framebufferdisplay_obj_t *display = &displays[0].framebuffer_display; + display->base.type = &framebufferio_framebufferdisplay_type; + common_hal_framebufferio_framebufferdisplay_construct( + display, + MP_OBJ_FROM_PTR(fb), + 0, + true); +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { +} diff --git a/ports/broadcom/boards/raspberrypi_pi4b/mpconfigboard.h b/ports/broadcom/boards/raspberrypi_pi4b/mpconfigboard.h new file mode 100644 index 0000000000..3b7627651c --- /dev/null +++ b/ports/broadcom/boards/raspberrypi_pi4b/mpconfigboard.h @@ -0,0 +1 @@ +#define MICROPY_HW_BOARD_NAME "Raspberry Pi 4B" diff --git a/ports/broadcom/boards/raspberrypi_pi4b/mpconfigboard.mk b/ports/broadcom/boards/raspberrypi_pi4b/mpconfigboard.mk new file mode 100644 index 0000000000..4567e9c15e --- /dev/null +++ b/ports/broadcom/boards/raspberrypi_pi4b/mpconfigboard.mk @@ -0,0 +1,6 @@ +USB_VID = 0x2E8A +USB_PID = 0xF001 +USB_PRODUCT = "Raspberry Pi 4B" +USB_MANUFACTURER = "Raspberry Pi" + +CHIP_VARIANT = bcm2711 diff --git a/ports/broadcom/boards/raspberrypi_pi4b/pins.c b/ports/broadcom/boards/raspberrypi_pi4b/pins.c new file mode 100644 index 0000000000..02682d7c4d --- /dev/null +++ b/ports/broadcom/boards/raspberrypi_pi4b/pins.c @@ -0,0 +1,62 @@ +#include "shared-bindings/board/__init__.h" + +#include "shared-module/displayio/__init__.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // These match the names used in Blinka + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, + + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_CE1), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_CE0), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_SCLK), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_TXD), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_RXD), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO15) }, + + { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_MISO_1), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_MOSI_1), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_D21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_SCLK_1), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_SCK_1), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_D22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_D24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_D26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_D27), MP_ROM_PTR(&pin_GPIO27) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)}, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/broadcom/boards/raspberrypi_zero2w/board.c b/ports/broadcom/boards/raspberrypi_zero2w/board.c new file mode 100644 index 0000000000..615a8e730e --- /dev/null +++ b/ports/broadcom/boards/raspberrypi_zero2w/board.c @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "supervisor/board.h" +#include "mpconfigboard.h" + +#include "bindings/videocore/Framebuffer.h" +#include "shared-module/displayio/__init__.h" +#include "shared-bindings/framebufferio/FramebufferDisplay.h" + +void board_init(void) { + videocore_framebuffer_obj_t *fb = &allocate_display_bus()->videocore; + fb->base.type = &videocore_framebuffer_type; + common_hal_videocore_framebuffer_construct(fb, 640, 480); + + framebufferio_framebufferdisplay_obj_t *display = &displays[0].framebuffer_display; + display->base.type = &framebufferio_framebufferdisplay_type; + common_hal_framebufferio_framebufferdisplay_construct( + display, + MP_OBJ_FROM_PTR(fb), + 0, + true); +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { +} diff --git a/ports/broadcom/boards/raspberrypi_zero2w/mpconfigboard.h b/ports/broadcom/boards/raspberrypi_zero2w/mpconfigboard.h new file mode 100644 index 0000000000..081089cb3e --- /dev/null +++ b/ports/broadcom/boards/raspberrypi_zero2w/mpconfigboard.h @@ -0,0 +1 @@ +#define MICROPY_HW_BOARD_NAME "Raspberry Pi Zero 2W" diff --git a/ports/broadcom/boards/raspberrypi_zero2w/mpconfigboard.mk b/ports/broadcom/boards/raspberrypi_zero2w/mpconfigboard.mk new file mode 100644 index 0000000000..8ba37dbba7 --- /dev/null +++ b/ports/broadcom/boards/raspberrypi_zero2w/mpconfigboard.mk @@ -0,0 +1,6 @@ +USB_VID = 0x2E8A +USB_PID = 0xF002 +USB_PRODUCT = "Raspberry Pi Zero 2W" +USB_MANUFACTURER = "Raspberry Pi" + +CHIP_VARIANT = rp3a0 diff --git a/ports/broadcom/boards/raspberrypi_zero2w/pins.c b/ports/broadcom/boards/raspberrypi_zero2w/pins.c new file mode 100644 index 0000000000..220668b328 --- /dev/null +++ b/ports/broadcom/boards/raspberrypi_zero2w/pins.c @@ -0,0 +1,11 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_GPIO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GPIO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_GPIO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GPIO21), MP_ROM_PTR(&pin_GPIO21) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/broadcom/common-hal/board/__init__.c b/ports/broadcom/common-hal/board/__init__.c new file mode 100644 index 0000000000..3c7f30df22 --- /dev/null +++ b/ports/broadcom/common-hal/board/__init__.c @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "common-hal/microcontroller/Pin.h" + +// Pins aren't actually defined here. They are in the board specific directory +// such as boards/arduino_zero/pins.c. diff --git a/ports/broadcom/common-hal/busio/I2C.c b/ports/broadcom/common-hal/busio/I2C.c new file mode 100644 index 0000000000..5feed7a162 --- /dev/null +++ b/ports/broadcom/common-hal/busio/I2C.c @@ -0,0 +1,108 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mperrno.h" +#include "py/mphal.h" +#include "shared-bindings/busio/I2C.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/__init__.h" + +#define NO_PIN 0xff + +// One second +#define BUS_TIMEOUT_US 1000000 + +STATIC bool never_reset_i2c[2]; +// STATIC i2c_inst_t *i2c[2] = {i2c0, i2c1}; + +void reset_i2c(void) { + for (size_t i = 0; i < 2; i++) { + if (never_reset_i2c[i]) { + continue; + } + + } +} + +void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, + const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) { +} + +bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { + return self->sda_pin == NO_PIN; +} + +void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { + if (common_hal_busio_i2c_deinited(self)) { + return; + } + // never_reset_i2c[i2c_hw_index(self->peripheral)] = false; + + reset_pin_number(self->sda_pin); + reset_pin_number(self->scl_pin); + self->sda_pin = NO_PIN; + self->scl_pin = NO_PIN; +} + +bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { + return common_hal_busio_i2c_write(self, addr, NULL, 0, true) == 0; +} + +bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) { + bool grabbed_lock = false; + if (!self->has_lock) { + grabbed_lock = true; + self->has_lock = true; + } + return grabbed_lock; +} + +bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self) { + return self->has_lock; +} + +void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { + self->has_lock = false; +} + +uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, + const uint8_t *data, size_t len, bool transmit_stop_bit) { + + return MP_ENODEV; +} + +uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, + uint8_t *data, size_t len) { + return MP_ENODEV; +} + +void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { + // never_reset_i2c[i2c_hw_index(self->peripheral)] = true; + + never_reset_pin_number(self->scl_pin); + never_reset_pin_number(self->sda_pin); +} diff --git a/ports/broadcom/common-hal/busio/I2C.h b/ports/broadcom/common-hal/busio/I2C.h new file mode 100644 index 0000000000..2acae2ef37 --- /dev/null +++ b/ports/broadcom/common-hal/busio/I2C.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_BROADCOM_COMMON_HAL_BUSIO_I2C_H +#define MICROPY_INCLUDED_BROADCOM_COMMON_HAL_BUSIO_I2C_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + bool has_lock; + uint baudrate; + uint8_t scl_pin; + uint8_t sda_pin; +} busio_i2c_obj_t; + +void reset_i2c(void); + +#endif // MICROPY_INCLUDED_BROADCOM_COMMON_HAL_BUSIO_I2C_H diff --git a/ports/broadcom/common-hal/busio/SPI.c b/ports/broadcom/common-hal/busio/SPI.c new file mode 100644 index 0000000000..230bd487e9 --- /dev/null +++ b/ports/broadcom/common-hal/busio/SPI.c @@ -0,0 +1,142 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/busio/SPI.h" + +#include "shared/runtime/interrupt_char.h" +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "supervisor/board.h" +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/microcontroller/Pin.h" + +#define NO_INSTANCE 0xff + +STATIC bool never_reset_spi[2]; + +void reset_spi(void) { + for (size_t i = 0; i < 2; i++) { + if (never_reset_spi[i]) { + continue; + } + + // TODO + } +} + +void common_hal_busio_spi_construct(busio_spi_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *miso) { + +} + +void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { + // never_reset_spi[spi_get_index(self->peripheral)] = true; + + common_hal_never_reset_pin(self->clock); + common_hal_never_reset_pin(self->MOSI); + common_hal_never_reset_pin(self->MISO); +} + +bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { + return self->clock == NULL; +} + +void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { + if (common_hal_busio_spi_deinited(self)) { + return; + } + // never_reset_spi[spi_get_index(self->peripheral)] = false; + + common_hal_reset_pin(self->clock); + common_hal_reset_pin(self->MOSI); + common_hal_reset_pin(self->MISO); + self->clock = NULL; +} + +bool common_hal_busio_spi_configure(busio_spi_obj_t *self, + uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { + if (baudrate == self->target_frequency && + polarity == self->polarity && + phase == self->phase && + bits == self->bits) { + return true; + } + + // TODO + + self->polarity = polarity; + self->phase = phase; + self->bits = bits; + self->target_frequency = baudrate; + self->real_frequency = baudrate; // TODO + + return true; +} + +bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { + bool grabbed_lock = false; + if (!self->has_lock) { + grabbed_lock = true; + self->has_lock = true; + } + return grabbed_lock; +} + +bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { + return self->has_lock; +} + +void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { + self->has_lock = false; +} + +bool common_hal_busio_spi_write(busio_spi_obj_t *self, + const uint8_t *data, size_t len) { + return false; +} + +bool common_hal_busio_spi_read(busio_spi_obj_t *self, + uint8_t *data, size_t len, uint8_t write_value) { + return false; +} + +bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len) { + return false; +} + +uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t *self) { + return self->real_frequency; +} + +uint8_t common_hal_busio_spi_get_phase(busio_spi_obj_t *self) { + return self->phase; +} + +uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t *self) { + return self->polarity; +} diff --git a/ports/broadcom/common-hal/busio/SPI.h b/ports/broadcom/common-hal/busio/SPI.h new file mode 100644 index 0000000000..0bdbf2d8e7 --- /dev/null +++ b/ports/broadcom/common-hal/busio/SPI.h @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_BROADCOM_COMMON_HAL_BUSIO_SPI_H +#define MICROPY_INCLUDED_BROADCOM_COMMON_HAL_BUSIO_SPI_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + bool has_lock; + const mcu_pin_obj_t *clock; + const mcu_pin_obj_t *MOSI; + const mcu_pin_obj_t *MISO; + uint32_t target_frequency; + int32_t real_frequency; + uint8_t polarity; + uint8_t phase; + uint8_t bits; +} busio_spi_obj_t; + +void reset_spi(void); + +#endif // MICROPY_INCLUDED_BROADCOM_COMMON_HAL_BUSIO_SPI_H diff --git a/ports/broadcom/common-hal/busio/UART.c b/ports/broadcom/common-hal/busio/UART.c new file mode 100644 index 0000000000..f6ee448e92 --- /dev/null +++ b/ports/broadcom/common-hal/busio/UART.c @@ -0,0 +1,308 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 microDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/busio/UART.h" + +#include "py/stream.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "supervisor/shared/tick.h" +#include "shared/runtime/interrupt_char.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "peripherals/broadcom/cpu.h" +#include "peripherals/broadcom/defines.h" +#include "peripherals/broadcom/gpio.h" +#include "peripherals/broadcom/interrupts.h" +#include "peripherals/broadcom/vcmailbox.h" + +#define NO_PIN 0xff + +#define UART_INST(uart) (((uart) ? uart1 : uart0)) + +typedef enum { + STATUS_FREE = 0, + STATUS_BUSY, + STATUS_NEVER_RESET +} uart_status_t; + +#define NUM_UARTS 2 + +static uart_status_t uart_status[NUM_UARTS]; + +void reset_uart(void) { + for (uint8_t num = 0; num < NUM_UARTS; num++) { + if (uart_status[num] == STATUS_BUSY) { + uart_status[num] = STATUS_FREE; + } + } +} + +static busio_uart_obj_t *active_uarts[NUM_UARTS]; + +void UART1_IRQHandler(void) { + while (UART1->STAT_b.DATA_READY && ringbuf_num_empty(&active_uarts[1]->ringbuf) > 0) { + ringbuf_put(&active_uarts[1]->ringbuf, (uint8_t)UART1->IO_b.DATA); + } + // We couldn't read all pending data (overrun) so clear the FIFO so that the interrupt + // can finish. + if (UART1->STAT_b.DATA_READY) { + UART1->IIR_b.DATA_READY = 1; + } +} + +void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) { + uart_status[self->uart_id] = STATUS_NEVER_RESET; +} + +void common_hal_busio_uart_construct(busio_uart_obj_t *self, + const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, + const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, + const mcu_pin_obj_t *rs485_dir, bool rs485_invert, + uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop, + mp_float_t timeout, uint16_t receiver_buffer_size, byte *receiver_buffer, + bool sigint_enabled) { + + if (bits > 8) { + mp_raise_ValueError(translate("Invalid word/bit length")); + } + + if (receiver_buffer_size == 0) { + mp_raise_ValueError(translate("Invalid buffer size")); + } + + if ((rs485_dir != NULL) || (rs485_invert)) { + mp_raise_NotImplementedError(translate("RS485 Not yet supported on this device")); + } + + if (tx == &pin_GPIO14) { + if (rx == &pin_GPIO15) { + self->uart_id = 1; + } + } + + self->rx_pin = rx; + self->tx_pin = tx; + + if (rx != NULL) { + if (receiver_buffer != NULL) { + self->ringbuf = (ringbuf_t) { receiver_buffer, receiver_buffer_size }; + } else { + // Initially allocate the UART's buffer in the long-lived part of the + // heap. UARTs are generally long-lived objects, but the "make long- + // lived" machinery is incapable of moving internal pointers like + // self->buffer, so do it manually. (However, as long as internal + // pointers like this are NOT moved, allocating the buffer + // in the long-lived pool is not strictly necessary) + // (This is a macro.) + if (!ringbuf_alloc(&self->ringbuf, receiver_buffer_size, true)) { + mp_raise_msg(&mp_type_MemoryError, translate("Failed to allocate RX buffer")); + } + } + } + + if (self->uart_id == 1) { + active_uarts[1] = self; + AUX->ENABLES_b.UART_1 = true; + + UART1->IER = 0; + UART1->CNTL = 0; + if (bits == 8) { + UART1->LCR_b.DATA_SIZE = UART1_LCR_DATA_SIZE_MODE_8BIT; + } else if (bits == 7) { + UART1->LCR_b.DATA_SIZE = UART1_LCR_DATA_SIZE_MODE_7BIT; + } + UART1->MCR = 0; + UART1->IER = 0; + + // Clear interrupts + UART1->IIR = 0xff; + uint32_t source_clock = vcmailbox_get_clock_rate_measured(VCMAILBOX_CLOCK_CORE); + UART1->BAUD = ((source_clock / (baudrate * 8)) - 1); + if (tx != NULL) { + UART1->CNTL |= UART1_CNTL_TX_ENABLE_Msk; + gpio_set_pull(14, BP_PULL_NONE); + gpio_set_function(14, GPIO_GPFSEL1_FSEL14_TXD1); + } + if (rx != NULL) { + UART1->CNTL |= UART1_CNTL_RX_ENABLE_Msk; + gpio_set_pull(15, BP_PULL_NONE); + gpio_set_function(15, GPIO_GPFSEL1_FSEL15_RXD1); + } + UART1->IER_b.DATA_READY = true; + // Never disable this in case the SPIs are used. They can each be + // disabled at the peripheral itself. + BP_EnableIRQ(AUX_IRQn); + } +} + +bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) { + return self->tx_pin == NULL && self->rx_pin == NULL; +} + +void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { + if (common_hal_busio_uart_deinited(self)) { + return; + } + if (self->uart_id == 1) { + UART1->IER_b.DATA_READY = false; + UART1->CNTL = 0; + AUX->ENABLES_b.UART_1 = false; + active_uarts[1] = NULL; + } + ringbuf_free(&self->ringbuf); + uart_status[self->uart_id] = STATUS_FREE; + common_hal_reset_pin(self->tx_pin); + common_hal_reset_pin(self->rx_pin); + common_hal_reset_pin(self->cts_pin); + common_hal_reset_pin(self->rts_pin); + self->tx_pin = NULL; + self->rx_pin = NULL; + self->cts_pin = NULL; + self->rts_pin = NULL; +} + +// Write characters. +size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data, size_t len, int *errcode) { + if (self->tx_pin == NULL) { + mp_raise_ValueError(translate("No TX pin")); + } + + if (self->uart_id == 1) { + COMPLETE_MEMORY_READS; + for (size_t i = 0; i < len; i++) { + // Wait for the FIFO to have space. + while (!UART1->STAT_b.TX_READY) { + RUN_BACKGROUND_TASKS; + } + UART1->IO = data[i]; + } + COMPLETE_MEMORY_READS; + return len; + } + + return 0; +} + +// Read characters. +size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t len, int *errcode) { + if (self->rx_pin == NULL) { + mp_raise_ValueError(translate("No RX pin")); + } + + if (len == 0) { + // Nothing to read. + return 0; + } + COMPLETE_MEMORY_READS; + + // Prevent conflict with uart irq. + if (self->uart_id == 1) { + UART1->IER_b.DATA_READY = false; + } + + // Copy as much received data as available, up to len bytes. + size_t total_read = ringbuf_get_n(&self->ringbuf, data, len); + + // Check if we still need to read more data. + if (len > total_read) { + len -= total_read; + uint64_t start_ticks = supervisor_ticks_ms64(); + // Busy-wait until timeout or until we've read enough chars. + while (len > 0 && (supervisor_ticks_ms64() - start_ticks < self->timeout_ms)) { + if (UART1->STAT_b.DATA_READY) { + // Read and advance. + data[total_read] = UART1->IO_b.DATA; + + // Adjust the counters. + len--; + total_read++; + + // Reset the timeout on every character read. + start_ticks = supervisor_ticks_ms64(); + } + RUN_BACKGROUND_TASKS; + // Allow user to break out of a timeout with a KeyboardInterrupt. + if (mp_hal_is_interrupted()) { + break; + } + } + } + + // Now that we've emptied the ringbuf some, fill it up with anything in the + // FIFO. This ensures that we'll empty the FIFO as much as possible and + // reset the interrupt when we catch up. + while (UART1->STAT_b.DATA_READY && ringbuf_num_empty(&self->ringbuf) > 0) { + ringbuf_put(&self->ringbuf, (uint8_t)UART1->IO_b.DATA); + } + + // Re-enable irq. + if (self->uart_id == 1) { + UART1->IER_b.DATA_READY = true; + } + + COMPLETE_MEMORY_READS; + if (total_read == 0) { + *errcode = EAGAIN; + return MP_STREAM_ERROR; + } + + return total_read; +} + +uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) { + return self->baudrate; +} + +void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate) { + self->baudrate = baudrate; +} + +mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self) { + return (mp_float_t)(self->timeout_ms / 1000.0L); +} + +void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout) { + self->timeout_ms = timeout * 1000; +} + +uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) { + return ringbuf_num_filled(&self->ringbuf); +} + +void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self) { + ringbuf_clear(&self->ringbuf); +} + +bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) { + if (self->tx_pin == NULL) { + return false; + } + if (self->uart_id == 1) { + return UART1->STAT_b.TX_READY; + } + return false; +} diff --git a/ports/broadcom/common-hal/busio/UART.h b/ports/broadcom/common-hal/busio/UART.h new file mode 100644 index 0000000000..8ef4073f8e --- /dev/null +++ b/ports/broadcom/common-hal/busio/UART.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 microDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_BROADCOM_COMMON_HAL_BUSIO_UART_H +#define MICROPY_INCLUDED_BROADCOM_COMMON_HAL_BUSIO_UART_H + +#include "py/obj.h" +#include "py/ringbuf.h" + +typedef struct { + mp_obj_base_t base; + const mcu_pin_obj_t *tx_pin; + const mcu_pin_obj_t *rx_pin; + const mcu_pin_obj_t *cts_pin; + const mcu_pin_obj_t *rts_pin; + uint8_t uart_id; + uint32_t baudrate; + uint32_t timeout_ms; + ringbuf_t ringbuf; +} busio_uart_obj_t; + +extern void reset_uart(void); + +#endif // MICROPY_INCLUDED_BROADCOM_COMMON_HAL_BUSIO_UART_H diff --git a/ports/broadcom/common-hal/busio/__init__.c b/ports/broadcom/common-hal/busio/__init__.c new file mode 100644 index 0000000000..41761b6743 --- /dev/null +++ b/ports/broadcom/common-hal/busio/__init__.c @@ -0,0 +1 @@ +// No busio module functions. diff --git a/ports/broadcom/common-hal/digitalio/DigitalInOut.c b/ports/broadcom/common-hal/digitalio/DigitalInOut.c new file mode 100644 index 0000000000..38a7cbb2b8 --- /dev/null +++ b/ports/broadcom/common-hal/digitalio/DigitalInOut.c @@ -0,0 +1,163 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/mphal.h" + +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "supervisor/shared/translate.h" + +#include "peripherals/broadcom/gpio.h" + +digitalinout_result_t common_hal_digitalio_digitalinout_construct( + digitalio_digitalinout_obj_t *self, const mcu_pin_obj_t *pin) { + claim_pin(pin); + self->pin = pin; + self->output = false; + self->open_drain = false; + + return DIGITALINOUT_OK; +} + +void common_hal_digitalio_digitalinout_never_reset( + digitalio_digitalinout_obj_t *self) { + never_reset_pin_number(self->pin->number); +} + +bool common_hal_digitalio_digitalinout_deinited(digitalio_digitalinout_obj_t *self) { + return self->pin == NULL; +} + +void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t *self) { + if (common_hal_digitalio_digitalinout_deinited(self)) { + return; + } + reset_pin_number(self->pin->number); + self->pin = NULL; +} + +void common_hal_digitalio_digitalinout_switch_to_input( + digitalio_digitalinout_obj_t *self, digitalio_pull_t pull) { + self->output = false; + // This also sets direction to input. + common_hal_digitalio_digitalinout_set_pull(self, pull); +} + +digitalinout_result_t common_hal_digitalio_digitalinout_switch_to_output( + digitalio_digitalinout_obj_t *self, bool value, + digitalio_drive_mode_t drive_mode) { + const uint8_t pin = self->pin->number; + gpio_set_pull(pin, PULL_NONE); + + self->output = true; + self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; + + // Pin direction is ultimately set in set_value. We don't need to do it here. + common_hal_digitalio_digitalinout_set_value(self, value); + return DIGITALINOUT_OK; +} + +digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( + digitalio_digitalinout_obj_t *self) { + return self->output ? DIRECTION_OUTPUT : DIRECTION_INPUT; +} + +void common_hal_digitalio_digitalinout_set_value( + digitalio_digitalinout_obj_t *self, bool value) { + const uint8_t pin = self->pin->number; + if (self->open_drain && value) { + // If true and open-drain, set the direction -before- setting + // the pin value, to to avoid a high glitch on the pin before + // switching from output to input for open-drain. + gpio_set_function(pin, GPIO_FUNCTION_INPUT); + gpio_set_value(pin, value); + } else { + // Otherwise set the direction -after- setting the pin value, + // to avoid a glitch which might occur if the old value was + // different and the pin was previously set to input. + gpio_set_value(pin, value); + gpio_set_function(pin, GPIO_FUNCTION_OUTPUT); + } +} + +bool common_hal_digitalio_digitalinout_get_value( + digitalio_digitalinout_obj_t *self) { + return gpio_get_value(self->pin->number); +} + +digitalinout_result_t common_hal_digitalio_digitalinout_set_drive_mode( + digitalio_digitalinout_obj_t *self, + digitalio_drive_mode_t drive_mode) { + bool value = common_hal_digitalio_digitalinout_get_value(self); + self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; + // True is implemented differently between modes so reset the value to make + // sure it's correct for the new mode. + if (value) { + common_hal_digitalio_digitalinout_set_value(self, value); + } + return DIGITALINOUT_OK; +} + +digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode( + digitalio_digitalinout_obj_t *self) { + if (self->open_drain) { + return DRIVE_MODE_OPEN_DRAIN; + } else { + return DRIVE_MODE_PUSH_PULL; + } +} + +void common_hal_digitalio_digitalinout_set_pull( + digitalio_digitalinout_obj_t *self, digitalio_pull_t pull) { + const uint8_t pin = self->pin->number; + BP_PULL_Enum bp_pull = BP_PULL_NONE; + if (pull == PULL_UP) { + bp_pull = BP_PULL_UP; + } else if (pull == PULL_DOWN) { + bp_pull = BP_PULL_DOWN; + } + gpio_set_pull(pin, bp_pull); +} + +digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( + digitalio_digitalinout_obj_t *self) { + uint32_t pin = self->pin->number; + if (self->output) { + mp_raise_AttributeError(translate("Cannot get pull while in output mode")); + return PULL_NONE; + } else { + if (gpio_get_pull(pin) == BP_PULL_UP) { + return PULL_UP; + } else if (gpio_get_pull(pin) == BP_PULL_DOWN) { + return PULL_DOWN; + } + } + return PULL_NONE; +} diff --git a/ports/broadcom/common-hal/digitalio/DigitalInOut.h b/ports/broadcom/common-hal/digitalio/DigitalInOut.h new file mode 100644 index 0000000000..8cb0236390 --- /dev/null +++ b/ports/broadcom/common-hal/digitalio/DigitalInOut.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_BROADCOM_COMMON_HAL_DIGITALIO_DIGITALINOUT_H +#define MICROPY_INCLUDED_BROADCOM_COMMON_HAL_DIGITALIO_DIGITALINOUT_H + +#include "common-hal/microcontroller/Pin.h" +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + const mcu_pin_obj_t *pin; + bool output; + bool open_drain; +} digitalio_digitalinout_obj_t; + +#endif // MICROPY_INCLUDED_BROADCOM_COMMON_HAL_DIGITALIO_DIGITALINOUT_H diff --git a/ports/broadcom/common-hal/digitalio/__init__.c b/ports/broadcom/common-hal/digitalio/__init__.c new file mode 100644 index 0000000000..20fad45959 --- /dev/null +++ b/ports/broadcom/common-hal/digitalio/__init__.c @@ -0,0 +1 @@ +// No digitalio module functions. diff --git a/ports/broadcom/common-hal/microcontroller/Pin.c b/ports/broadcom/common-hal/microcontroller/Pin.c new file mode 100644 index 0000000000..020a1eca14 --- /dev/null +++ b/ports/broadcom/common-hal/microcontroller/Pin.c @@ -0,0 +1,112 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/microcontroller/Pin.h" + +#include "peripherals/broadcom/gpio.h" + +void reset_all_pins(void) { +} + +void never_reset_pin_number(uint8_t pin_number) { +} + +void reset_pin_number(uint8_t pin_number) { + gpio_set_function(pin_number, 0); +} + +void common_hal_never_reset_pin(const mcu_pin_obj_t *pin) { + never_reset_pin_number(pin->number); +} + +void common_hal_reset_pin(const mcu_pin_obj_t *pin) { + reset_pin_number(pin->number); +} + +void claim_pin(const mcu_pin_obj_t *pin) { + // Nothing to do because all changes will set the GPIO settings. +} + +bool pin_number_is_free(uint8_t pin_number) { + return true; +} + +bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t *pin) { + return pin_number_is_free(pin->number); +} + +uint8_t common_hal_mcu_pin_number(const mcu_pin_obj_t *pin) { + return pin->number; +} + +void common_hal_mcu_pin_claim(const mcu_pin_obj_t *pin) { + return claim_pin(pin); +} + +void common_hal_mcu_pin_reset_number(uint8_t pin_no) { + reset_pin_number(pin_no); +} + +#define PIN(num) \ + const mcu_pin_obj_t pin_GPIO##num = { \ + { &mcu_pin_type }, \ + .number = num \ + }; + +PIN(0) +PIN(1) +PIN(2) +PIN(3) +PIN(4) +PIN(5) +PIN(6) +PIN(7) +PIN(8) +PIN(9) +PIN(10) +PIN(11) +PIN(12) +PIN(13) +PIN(14) +PIN(15) +PIN(16) +PIN(17) +PIN(18) +PIN(19) +PIN(20) +PIN(21) +PIN(22) +PIN(23) +PIN(24) +PIN(25) +PIN(26) +PIN(27) +PIN(48) +PIN(49) +PIN(50) +PIN(51) +PIN(52) +PIN(53) diff --git a/ports/broadcom/common-hal/microcontroller/Pin.h b/ports/broadcom/common-hal/microcontroller/Pin.h new file mode 100644 index 0000000000..bf7e6e592d --- /dev/null +++ b/ports/broadcom/common-hal/microcontroller/Pin.h @@ -0,0 +1,87 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_BROADCOM_COMMON_HAL_MICROCONTROLLER_PIN_H +#define MICROPY_INCLUDED_BROADCOM_COMMON_HAL_MICROCONTROLLER_PIN_H + +#include +#include + +#include + +typedef struct { + mp_obj_base_t base; + uint8_t number; +} mcu_pin_obj_t; + +extern const mcu_pin_obj_t pin_GPIO0; +extern const mcu_pin_obj_t pin_GPIO1; +extern const mcu_pin_obj_t pin_GPIO2; +extern const mcu_pin_obj_t pin_GPIO3; +extern const mcu_pin_obj_t pin_GPIO4; +extern const mcu_pin_obj_t pin_GPIO5; +extern const mcu_pin_obj_t pin_GPIO6; +extern const mcu_pin_obj_t pin_GPIO7; +extern const mcu_pin_obj_t pin_GPIO8; +extern const mcu_pin_obj_t pin_GPIO9; +extern const mcu_pin_obj_t pin_GPIO10; +extern const mcu_pin_obj_t pin_GPIO11; +extern const mcu_pin_obj_t pin_GPIO12; +extern const mcu_pin_obj_t pin_GPIO13; +extern const mcu_pin_obj_t pin_GPIO14; +extern const mcu_pin_obj_t pin_GPIO15; +extern const mcu_pin_obj_t pin_GPIO16; +extern const mcu_pin_obj_t pin_GPIO17; +extern const mcu_pin_obj_t pin_GPIO18; +extern const mcu_pin_obj_t pin_GPIO19; +extern const mcu_pin_obj_t pin_GPIO20; +extern const mcu_pin_obj_t pin_GPIO21; +extern const mcu_pin_obj_t pin_GPIO22; +extern const mcu_pin_obj_t pin_GPIO23; +extern const mcu_pin_obj_t pin_GPIO24; +extern const mcu_pin_obj_t pin_GPIO25; +extern const mcu_pin_obj_t pin_GPIO26; +extern const mcu_pin_obj_t pin_GPIO27; +extern const mcu_pin_obj_t pin_GPIO28; +extern const mcu_pin_obj_t pin_GPIO29; + +extern const mcu_pin_obj_t pin_GPIO48; +extern const mcu_pin_obj_t pin_GPIO49; +extern const mcu_pin_obj_t pin_GPIO50; +extern const mcu_pin_obj_t pin_GPIO51; +extern const mcu_pin_obj_t pin_GPIO52; +extern const mcu_pin_obj_t pin_GPIO53; + + +void reset_all_pins(void); +// reset_pin_number takes the pin number instead of the pointer so that objects don't +// need to store a full pointer. +void reset_pin_number(uint8_t pin_number); +void never_reset_pin_number(uint8_t pin_number); +void claim_pin(const mcu_pin_obj_t *pin); +bool pin_number_is_free(uint8_t pin_number); + +#endif // MICROPY_INCLUDED_BROADCOM_COMMON_HAL_MICROCONTROLLER_PIN_H diff --git a/ports/broadcom/common-hal/microcontroller/Processor.c b/ports/broadcom/common-hal/microcontroller/Processor.c new file mode 100644 index 0000000000..70984dd0e4 --- /dev/null +++ b/ports/broadcom/common-hal/microcontroller/Processor.c @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/microcontroller/Processor.h" + +#include "peripherals/broadcom/vcmailbox.h" + +float common_hal_mcu_processor_get_temperature(void) { + uint32_t temp = vcmailbox_get_temperature(); + return temp / 1000.0f; +} + +float common_hal_mcu_processor_get_voltage(void) { + return 1.2f; +} + +uint32_t common_hal_mcu_processor_get_frequency(void) { + return vcmailbox_get_clock_rate_measured(VCMAILBOX_CLOCK_ARM); +} + +void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { + uint64_t serial = vcmailbox_get_serial_number(); + for (size_t i = 0; i < sizeof(uint64_t); i++) { + raw_id[i] = (serial >> (64 - ((i + 1) * 8))) & 0xff; + } +} + +mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { + return RESET_REASON_UNKNOWN; +} diff --git a/ports/broadcom/common-hal/microcontroller/Processor.h b/ports/broadcom/common-hal/microcontroller/Processor.h new file mode 100644 index 0000000000..5abaf629d7 --- /dev/null +++ b/ports/broadcom/common-hal/microcontroller/Processor.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_BROADCOM_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H +#define MICROPY_INCLUDED_BROADCOM_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + // Stores no state currently. +} mcu_processor_obj_t; + +#define COMMON_HAL_MCU_PROCESSOR_UID_LENGTH 8 + +#endif // MICROPY_INCLUDED_BROADCOM_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H diff --git a/ports/broadcom/common-hal/microcontroller/__init__.c b/ports/broadcom/common-hal/microcontroller/__init__.c new file mode 100644 index 0000000000..dd9856f5a1 --- /dev/null +++ b/ports/broadcom/common-hal/microcontroller/__init__.c @@ -0,0 +1,132 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/microcontroller/__init__.h" + +#include "shared-bindings/microcontroller/Processor.h" +#include "common-hal/microcontroller/__init__.h" +#include "peripherals/broadcom/interrupts.h" + +#include "mphalport.h" + +void common_hal_mcu_delay_us(uint32_t delay) { + mp_hal_delay_us(delay); +} + +volatile uint32_t nesting_count = 0; +void common_hal_mcu_disable_interrupts(void) { + BP_DisableIRQs(); + nesting_count++; +} + +void common_hal_mcu_enable_interrupts(void) { + if (nesting_count == 0) { + // reset_into_safe_mode(LOCKING_ERROR); + } + nesting_count--; + if (nesting_count > 0) { + return; + } + BP_EnableIRQs(); +} + +void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { +} + +void common_hal_mcu_reset(void) { +} + +// The singleton microcontroller.Processor object, bound to microcontroller.cpu +// It currently only has properties, and no state. +#if CIRCUITPY_PROCESSOR_COUNT > 1 +static const mcu_processor_obj_t processor0 = { + .base = { + .type = &mcu_processor_type, + }, +}; + +static const mcu_processor_obj_t processor1 = { + .base = { + .type = &mcu_processor_type, + }, +}; + +static const mcu_processor_obj_t processor2 = { + .base = { + .type = &mcu_processor_type, + }, +}; + +static const mcu_processor_obj_t processor3 = { + .base = { + .type = &mcu_processor_type, + }, +}; + +const mp_rom_obj_tuple_t common_hal_multi_processor_obj = { + {&mp_type_tuple}, + CIRCUITPY_PROCESSOR_COUNT, + { + MP_ROM_PTR(&processor0), + MP_ROM_PTR(&processor1), + MP_ROM_PTR(&processor2), + MP_ROM_PTR(&processor3) + } +}; +#endif + +const mcu_processor_obj_t common_hal_mcu_processor_obj = { + .base = { + .type = &mcu_processor_type, + }, +}; + +#if CIRCUITPY_NVM && CIRCUITPY_INTERNAL_NVM_SIZE > 0 +// The singleton nvm.ByteArray object. +const nvm_bytearray_obj_t common_hal_mcu_nvm_obj = { + .base = { + .type = &nvm_bytearray_type, + }, + .len = CIRCUITPY_INTERNAL_NVM_SIZE, + .start_address = (uint8_t *)(CIRCUITPY_INTERNAL_NVM_START_ADDR) +}; +#endif + +#if CIRCUITPY_WATCHDOG +// The singleton watchdog.WatchDogTimer object. +watchdog_watchdogtimer_obj_t common_hal_mcu_watchdogtimer_obj = { + .base = { + .type = &watchdog_watchdogtimer_type, + }, + .timeout = 0.0f, + .mode = WATCHDOGMODE_NONE, +}; +#endif + +// This maps MCU pin names to pin objects. +const mp_rom_map_elem_t mcu_pin_global_dict_table[TOTAL_GPIO_COUNT] = { +}; +MP_DEFINE_CONST_DICT(mcu_pin_globals, mcu_pin_global_dict_table); diff --git a/ports/broadcom/common-hal/microcontroller/__init__.h b/ports/broadcom/common-hal/microcontroller/__init__.h new file mode 100644 index 0000000000..038be42427 --- /dev/null +++ b/ports/broadcom/common-hal/microcontroller/__init__.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_BROADCOM_COMMON_HAL_MICROCONTROLLER___INIT___H +#define MICROPY_INCLUDED_BROADCOM_COMMON_HAL_MICROCONTROLLER___INIT___H + +#define TOTAL_GPIO_COUNT 10 + +#endif // MICROPY_INCLUDED_BROADCOM_COMMON_HAL_MICROCONTROLLER___INIT___H diff --git a/ports/broadcom/common-hal/os/__init__.c b/ports/broadcom/common-hal/os/__init__.c new file mode 100644 index 0000000000..d5f2346885 --- /dev/null +++ b/ports/broadcom/common-hal/os/__init__.c @@ -0,0 +1,62 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "genhdr/mpversion.h" +#include "py/mpconfig.h" +#include "py/objstr.h" +#include "py/objtuple.h" +#include "py/qstr.h" + +STATIC const qstr os_uname_info_fields[] = { + MP_QSTR_sysname, MP_QSTR_nodename, + MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine +}; + +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, MICROPY_HW_MCU_NAME); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, MICROPY_HW_MCU_NAME); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, MICROPY_VERSION_STRING); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME); + + +STATIC MP_DEFINE_ATTRTUPLE( + os_uname_info_obj, + os_uname_info_fields, + 5, + (mp_obj_t)&os_uname_info_sysname_obj, + (mp_obj_t)&os_uname_info_nodename_obj, + (mp_obj_t)&os_uname_info_release_obj, + (mp_obj_t)&os_uname_info_version_obj, + (mp_obj_t)&os_uname_info_machine_obj + ); + +mp_obj_t common_hal_os_uname(void) { + return (mp_obj_t)&os_uname_info_obj; +} + +bool common_hal_os_urandom(uint8_t *buffer, uint32_t length) { + return false; +} diff --git a/ports/broadcom/common-hal/sdioio/SDCard.c b/ports/broadcom/common-hal/sdioio/SDCard.c new file mode 100644 index 0000000000..492d28d6d6 --- /dev/null +++ b/ports/broadcom/common-hal/sdioio/SDCard.c @@ -0,0 +1,367 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +#include "mphalport.h" + +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/sdioio/SDCard.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "supervisor/port.h" +#include "supervisor/shared/translate.h" + +#include "peripherals/broadcom/defines.h" +#include "peripherals/broadcom/gpio.h" + +#include "lib/sdmmc/include/sdmmc_cmd.h" + +void osal_task_delay(uint32_t msec) { + mp_hal_delay_ms(msec); +} + +/*!< Host function to initialize the driver */ +STATIC sdmmc_err_t _init(void) { + return SDMMC_OK; +} + +/*!< host function to set bus width */ +STATIC sdmmc_err_t _set_bus_width(int slot, size_t width) { + if (width == 4) { + EMMC->CONTROL0_b.HCTL_DWIDTH = true; + } else if (width == 8) { + EMMC->CONTROL0_b.HCTL_8BIT = true; + } + return SDMMC_OK; +} + +/*!< host function to get the maximum bus width of a particular slot */ +STATIC size_t _get_bus_width(int slot) { + return 4; +} + +/*!< host function to set card clock frequency */ +STATIC sdmmc_err_t _set_card_clk(int slot, uint32_t freq_khz) { + uint32_t base_clock = 125000000; + uint32_t frequency = freq_khz * 1000; + uint64_t start_ticks = port_get_raw_ticks(NULL); + while ((EMMC->STATUS_b.CMD_INHIBIT || EMMC->STATUS_b.DAT_INHIBIT) && (port_get_raw_ticks(NULL) - start_ticks) < 1024) { + } + if (EMMC->STATUS_b.CMD_INHIBIT || EMMC->STATUS_b.DAT_INHIBIT) { + return SDMMC_ERR_TIMEOUT; + } + + EMMC->CONTROL1_b.CLK_EN = false; + + uint32_t divisor = base_clock / frequency; + // + 1 to ensure we round the frequency down. + if (base_clock % frequency > 0) { + divisor += 1; + } + // Only even divisors are supported + uint32_t register_value = divisor / 2; + if (divisor % 2 == 1) { + register_value += 1; + } + + // The divisor is stored with bits swapped. + EMMC->CONTROL1_b.CLK_FREQ8 = divisor & 0xff; + EMMC->CONTROL1_b.CLK_FREQ_MS2 = (divisor >> 8) & 0x3; + + EMMC->CONTROL1_b.CLK_EN = true; + start_ticks = port_get_raw_ticks(NULL); + while (!EMMC->CONTROL1_b.CLK_STABLE && (port_get_raw_ticks(NULL) - start_ticks) < 1024) { + } + if (!EMMC->CONTROL1_b.CLK_STABLE) { + return SDMMC_ERR_TIMEOUT; + } + return SDMMC_OK; +} + +/*!< host function to do a transaction */ +STATIC sdmmc_err_t _do_transaction(int slot, sdmmc_command_t *cmdinfo) { + if (EMMC->STATUS_b.CMD_INHIBIT) { + return SDMMC_ERR_BUSY; + } + + // Clear interrupts and then send the command + EMMC->INTERRUPT = 0xffffffff; + EMMC->ARG1 = cmdinfo->arg; + + uint32_t cmd_flags = 0; + bool read = (cmdinfo->flags & SCF_CMD_READ) != 0; + if (SCF_CMD(cmdinfo->flags) == SCF_CMD_ADTC || + SCF_CMD(cmdinfo->flags) == (SCF_CMD_ADTC | SCF_CMD_READ)) { + if (EMMC->STATUS_b.DAT_INHIBIT) { + return SDMMC_ERR_BUSY; + } + cmd_flags = EMMC_CMDTM_TM_BLKCNT_EN_Msk | EMMC_CMDTM_CMD_ISDATA_Msk; + if (cmdinfo->datalen > cmdinfo->blklen) { + cmd_flags |= EMMC_CMDTM_TM_MULTI_BLOCK_Msk; + if ((cmdinfo->flags & SCF_AUTO_STOP) != 0) { + cmd_flags |= 1 << EMMC_CMDTM_TM_AUTO_CMD_EN_Pos; + } + } + if (read) { + cmd_flags |= EMMC_CMDTM_TM_DAT_DIR_Msk; + } + EMMC->BLKSIZECNT = (cmdinfo->datalen / cmdinfo->blklen) << EMMC_BLKSIZECNT_BLKCNT_Pos | + cmdinfo->blklen << EMMC_BLKSIZECNT_BLKSIZE_Pos; + } + + uint32_t response_type = EMMC_CMDTM_CMD_RSPNS_TYPE_RESPONSE_48BITS; + uint32_t crc = 0; + if ((cmdinfo->flags & SCF_RSP_CRC) != 0) { + crc |= EMMC_CMDTM_CMD_CRCCHK_EN_Msk; + } + if ((cmdinfo->flags & SCF_RSP_IDX) != 0) { + crc |= EMMC_CMDTM_CMD_IXCHK_EN_Msk; + } + if ((cmdinfo->flags & SCF_RSP_136) != 0) { + response_type = EMMC_CMDTM_CMD_RSPNS_TYPE_RESPONSE_136BITS; + } else if ((cmdinfo->flags & SCF_RSP_BSY) != 0) { + response_type = EMMC_CMDTM_CMD_RSPNS_TYPE_RESPONSE_48BITS_USING_BUSY; + } else if ((cmdinfo->flags & SCF_RSP_PRESENT) == 0) { + response_type = EMMC_CMDTM_CMD_RSPNS_TYPE_RESPONSE_NONE; + } + uint32_t full_cmd = cmd_flags | crc | + cmdinfo->opcode << EMMC_CMDTM_CMD_INDEX_Pos | + response_type << EMMC_CMDTM_CMD_RSPNS_TYPE_Pos; + EMMC->CMDTM = full_cmd; + + // Wait for an interrupt to indicate completion of the command. + uint64_t start_ticks = port_get_raw_ticks(NULL); + while (EMMC->INTERRUPT == 0 && (port_get_raw_ticks(NULL) - start_ticks) < (size_t)cmdinfo->timeout_ms) { + } + if (!EMMC->INTERRUPT_b.CMD_DONE) { + cmdinfo->response[0] = 0; + // Reset the command circuit + EMMC->CONTROL1_b.SRST_CMD = true; + // Wait for the bit to clear + start_ticks = port_get_raw_ticks(NULL); + while (EMMC->CONTROL1_b.SRST_CMD && (port_get_raw_ticks(NULL) - start_ticks) < (size_t)cmdinfo->timeout_ms) { + } + return SDMMC_ERR_TIMEOUT; + } else { + EMMC->INTERRUPT = EMMC_INTERRUPT_CMD_DONE_Msk; + } + + // Transfer the data. + // TODO: Use DMA + if (cmd_flags != 0) { + if (read) { + for (size_t i = 0; i < cmdinfo->datalen / sizeof(uint32_t); i++) { + start_ticks = port_get_raw_ticks(NULL); + while (!EMMC->INTERRUPT_b.READ_RDY && (port_get_raw_ticks(NULL) - start_ticks) < (size_t)cmdinfo->timeout_ms) { + } + if (!EMMC->INTERRUPT_b.READ_RDY) { + return SDMMC_ERR_TIMEOUT; + } + ((uint32_t *)cmdinfo->data)[i] = EMMC->DATA; + } + } else { + for (size_t i = 0; i < cmdinfo->datalen / sizeof(uint32_t); i++) { + start_ticks = port_get_raw_ticks(NULL); + while (!EMMC->INTERRUPT_b.WRITE_RDY && (port_get_raw_ticks(NULL) - start_ticks) < (size_t)cmdinfo->timeout_ms) { + } + if (!EMMC->INTERRUPT_b.WRITE_RDY) { + return SDMMC_ERR_TIMEOUT; + } + EMMC->DATA = ((uint32_t *)cmdinfo->data)[i]; + } + } + uint32_t data_done_mask = EMMC_INTERRUPT_ERR_Msk | EMMC_INTERRUPT_DATA_DONE_Msk; + start_ticks = port_get_raw_ticks(NULL); + while ((EMMC->INTERRUPT & data_done_mask) == 0 && (port_get_raw_ticks(NULL) - start_ticks) < (size_t)cmdinfo->timeout_ms) { + } + if (!EMMC->INTERRUPT_b.DATA_DONE) { + cmdinfo->response[0] = 0; + // Reset the command circuit + EMMC->CONTROL1_b.SRST_DATA = true; + // Wait for the bit to clear + start_ticks = port_get_raw_ticks(NULL); + while (EMMC->CONTROL1_b.SRST_DATA && (port_get_raw_ticks(NULL) - start_ticks) < (size_t)cmdinfo->timeout_ms) { + } + return SDMMC_ERR_TIMEOUT; + } + } + + cmdinfo->response[0] = EMMC->RESP0; + if (response_type == EMMC_CMDTM_CMD_RSPNS_TYPE_RESPONSE_136BITS) { + // Rotate one more byte for some reason. + cmdinfo->response[3] = EMMC->RESP3 << 8 | ((EMMC->RESP2 >> 24) & 0xff); + cmdinfo->response[2] = EMMC->RESP2 << 8 | ((EMMC->RESP1 >> 24) & 0xff); + cmdinfo->response[1] = EMMC->RESP1 << 8 | ((EMMC->RESP0 >> 24) & 0xff); + cmdinfo->response[0] <<= 8; + } + return SDMMC_OK; +} + +/*!< host function to deinitialize the driver, called with the `slot` */ +STATIC sdmmc_err_t _deinit(int slot) { + return SDMMC_OK; +} + +void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *command, + uint8_t num_data, const mcu_pin_obj_t **data, uint32_t frequency) { + + if (clock != NULL) { + gpio_set_function(clock->number, GPIO_GPFSEL4_FSEL48_SD1_CLK); + gpio_set_pull(clock->number, BP_PULL_NONE); + gpio_set_function(command->number, GPIO_GPFSEL4_FSEL49_SD1_CMD); + gpio_set_pull(command->number, BP_PULL_UP); + gpio_set_function(data[0]->number, GPIO_GPFSEL5_FSEL50_SD1_DAT0); + gpio_set_pull(data[0]->number, BP_PULL_UP); + gpio_set_function(data[1]->number, GPIO_GPFSEL5_FSEL51_SD1_DAT1); + gpio_set_pull(data[1]->number, BP_PULL_UP); + gpio_set_function(data[2]->number, GPIO_GPFSEL5_FSEL52_SD1_DAT2); + gpio_set_pull(data[2]->number, BP_PULL_UP); + gpio_set_function(data[3]->number, GPIO_GPFSEL5_FSEL53_SD1_DAT3); + gpio_set_pull(data[3]->number, BP_PULL_UP); + } else { + // Switch the sdcard to use the old arasan interface. + GPIO->EXTRA_MUX_b.SDIO = GPIO_EXTRA_MUX_SDIO_ARASAN; + } + + self->host_info = (sdmmc_host_t) { + .flags = SDMMC_HOST_FLAG_1BIT | SDMMC_HOST_FLAG_4BIT | SDMMC_HOST_FLAG_DEINIT_ARG, + .slot = 0, + .max_freq_khz = SDMMC_FREQ_HIGHSPEED, + .io_voltage = 3.3f, + .command_timeout_ms = 0, + .init = _init, + .set_bus_width = _set_bus_width, + .get_bus_width = _get_bus_width, + .set_bus_ddr_mode = NULL, + .set_card_clk = _set_card_clk, + .do_transaction = _do_transaction, + .deinit_p = _deinit, + }; + + // Reset the peripheral. + EMMC->CONTROL0 = 0; + EMMC->CONTROL1_b.SRST_HC = true; + // Wait for the bit to clear + while (EMMC->CONTROL1_b.SRST_HC) { + + } + // Set max timeout + EMMC->CONTROL1 |= EMMC_CONTROL1_CLK_INTLEN_Msk | (0xe << EMMC_CONTROL1_DATA_TOUNIT_Pos); + + EMMC->IRPT_MASK = 0xffffffff; + + // Start clocking the card. + _set_card_clk(0, 400); + + sdmmc_card_init(&self->host_info, &self->card_info); + + self->capacity = self->card_info.csd.capacity; +} + +uint32_t common_hal_sdioio_sdcard_get_count(sdioio_sdcard_obj_t *self) { + return self->capacity; +} + +uint32_t common_hal_sdioio_sdcard_get_frequency(sdioio_sdcard_obj_t *self) { + return self->frequency; +} + +uint8_t common_hal_sdioio_sdcard_get_width(sdioio_sdcard_obj_t *self) { + return self->num_data; +} + +STATIC void check_for_deinit(sdioio_sdcard_obj_t *self) { +} + +STATIC void check_whole_block(mp_buffer_info_t *bufinfo) { + if (bufinfo->len % 512) { + mp_raise_ValueError(translate("Buffer length must be a multiple of 512")); + } +} + +int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { + check_for_deinit(self); + check_whole_block(bufinfo); + self->state_programming = true; + + // mp_printf(&mp_plat_print, "write %d %d %d %d\n", start_block, bufinfo->len / 512, self->card_info.csd.capacity, self->card_info.csd.sector_size); + sdmmc_err_t error = sdmmc_write_sectors(&self->card_info, bufinfo->buf, + start_block, bufinfo->len / 512); + + + if (error != SDMMC_OK) { + mp_printf(&mp_plat_print, "write sectors result %d\n", error); + return -EIO; + } + + return 0; +} + +int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { + check_for_deinit(self); + check_whole_block(bufinfo); + sdmmc_err_t error = sdmmc_read_sectors(&self->card_info, bufinfo->buf, + start_block, bufinfo->len / 512); + + if (error != SDMMC_OK) { + mp_printf(&mp_plat_print, "read sectors result %d when reading block %d for %d\n", error, start_block, bufinfo->len / 512); + return -EIO; + } + + return 0; +} + +bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t frequency, uint8_t bits) { + check_for_deinit(self); + return true; +} + +bool common_hal_sdioio_sdcard_deinited(sdioio_sdcard_obj_t *self) { + return self->command_pin == COMMON_HAL_MCU_NO_PIN; +} + +void common_hal_sdioio_sdcard_deinit(sdioio_sdcard_obj_t *self) { + reset_pin_number(self->command_pin); + reset_pin_number(self->clock_pin); + reset_pin_number(self->data_pins[0]); + reset_pin_number(self->data_pins[1]); + reset_pin_number(self->data_pins[2]); + reset_pin_number(self->data_pins[3]); + + self->command_pin = COMMON_HAL_MCU_NO_PIN; + self->clock_pin = COMMON_HAL_MCU_NO_PIN; + self->data_pins[0] = COMMON_HAL_MCU_NO_PIN; + self->data_pins[1] = COMMON_HAL_MCU_NO_PIN; + self->data_pins[2] = COMMON_HAL_MCU_NO_PIN; + self->data_pins[3] = COMMON_HAL_MCU_NO_PIN; +} + +void common_hal_sdioio_sdcard_never_reset(sdioio_sdcard_obj_t *self) { +} diff --git a/ports/broadcom/common-hal/sdioio/SDCard.h b/ports/broadcom/common-hal/sdioio/SDCard.h new file mode 100644 index 0000000000..ebd8e13f34 --- /dev/null +++ b/ports/broadcom/common-hal/sdioio/SDCard.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "lib/sdmmc/include/sdmmc_types.h" + +typedef struct { + mp_obj_base_t base; + sdmmc_host_t host_info; + sdmmc_card_t card_info; + uint32_t frequency; + uint32_t capacity; + uint8_t num_data; + bool state_programming; + bool has_lock; + uint8_t command_pin; + uint8_t clock_pin; + uint8_t data_pins[4]; +} sdioio_sdcard_obj_t; diff --git a/ports/broadcom/common-hal/sdioio/__init__.c b/ports/broadcom/common-hal/sdioio/__init__.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ports/broadcom/common-hal/sdioio/__init__.h b/ports/broadcom/common-hal/sdioio/__init__.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ports/broadcom/common-hal/supervisor/Runtime.c b/ports/broadcom/common-hal/supervisor/Runtime.c new file mode 100644 index 0000000000..f827651781 --- /dev/null +++ b/ports/broadcom/common-hal/supervisor/Runtime.c @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Michael Schroeder + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "shared-bindings/supervisor/Runtime.h" +#include "supervisor/serial.h" + +bool common_hal_supervisor_runtime_get_serial_connected(void) { + return (bool)serial_connected(); +} + +bool common_hal_supervisor_runtime_get_serial_bytes_available(void) { + return (bool)serial_bytes_available(); +} diff --git a/ports/broadcom/common-hal/supervisor/Runtime.h b/ports/broadcom/common-hal/supervisor/Runtime.h new file mode 100644 index 0000000000..0622a83a24 --- /dev/null +++ b/ports/broadcom/common-hal/supervisor/Runtime.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Michael Schroeder + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_BROADCOM_COMMON_HAL_SUPERVISOR_RUNTIME_H +#define MICROPY_INCLUDED_BROADCOM_COMMON_HAL_SUPERVISOR_RUNTIME_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + // Stores no state currently. +} super_runtime_obj_t; + +#endif // MICROPY_INCLUDED_BROADCOM_COMMON_HAL_SUPERVISOR_RUNTIME_H diff --git a/ports/broadcom/common-hal/supervisor/__init__.c b/ports/broadcom/common-hal/supervisor/__init__.c new file mode 100644 index 0000000000..6dca35fb5a --- /dev/null +++ b/ports/broadcom/common-hal/supervisor/__init__.c @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Michael Schroeder + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include "py/obj.h" + +#include "shared-bindings/supervisor/__init__.h" +#include "shared-bindings/supervisor/Runtime.h" + + +// The singleton supervisor.Runtime object, bound to supervisor.runtime +// It currently only has properties, and no state. +const super_runtime_obj_t common_hal_supervisor_runtime_obj = { + .base = { + .type = &supervisor_runtime_type, + }, +}; diff --git a/ports/broadcom/common-hal/videocore/Framebuffer.c b/ports/broadcom/common-hal/videocore/Framebuffer.c new file mode 100644 index 0000000000..249bfd0850 --- /dev/null +++ b/ports/broadcom/common-hal/videocore/Framebuffer.c @@ -0,0 +1,68 @@ + +#include "bindings/videocore/Framebuffer.h" + +#include "py/gc.h" +#include "py/runtime.h" + +#include "peripherals/broadcom/caches.h" +#include "peripherals/broadcom/vcmailbox.h" + +void common_hal_videocore_framebuffer_construct(videocore_framebuffer_obj_t *self, + uint16_t width, uint16_t height) { + // These will be modified on success to indicate actual values. + uint32_t virtual_width = width; + uint32_t virtual_height = height; + uint32_t physical_width = width; + // TODO: Make the FB twice as tall if double buffering. + uint32_t physical_height = height; + uint32_t pitch = 0; + self->framebuffer = vcmailbox_get_framebuffer(&virtual_width, &virtual_height, &physical_width, &physical_height, &pitch); + if (self->framebuffer == NULL) { + if (gc_alloc_possible()) { + mp_raise_ValueError(translate("no fb")); + } else { + mp_printf(&mp_plat_print, "no fb\n"); + } + self->width = 0; + self->height = 0; + return; + } + mp_printf(&mp_plat_print, "%dx%d pitch %d\n", virtual_width, virtual_height, pitch); + self->width = virtual_width; + self->height = virtual_height; + self->pitch = pitch; +} + +void common_hal_videocore_framebuffer_deinit(videocore_framebuffer_obj_t *self) { + if (vcmailbox_release_framebuffer()) { + self->framebuffer = NULL; + } +} + +bool common_hal_videocore_framebuffer_deinited(videocore_framebuffer_obj_t *self) { + return self->framebuffer == NULL; +} + +void common_hal_videocore_framebuffer_refresh(videocore_framebuffer_obj_t *self) { + data_clean(self->framebuffer, sizeof(uint32_t) * self->width * self->height); +} + +int common_hal_videocore_framebuffer_get_width(videocore_framebuffer_obj_t *self) { + return self->width; +} + +int common_hal_videocore_framebuffer_get_height(videocore_framebuffer_obj_t *self) { + return self->height; +} + +mp_int_t common_hal_videocore_framebuffer_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + videocore_framebuffer_obj_t *self = (videocore_framebuffer_obj_t *)self_in; + bufinfo->buf = self->framebuffer; + bufinfo->typecode = 'L'; + bufinfo->len = self->pitch * self->height * sizeof(uint32_t); + return 0; +} + +int common_hal_videocore_framebuffer_get_row_stride(videocore_framebuffer_obj_t *self) { + return self->pitch; +} diff --git a/ports/broadcom/common-hal/videocore/Framebuffer.h b/ports/broadcom/common-hal/videocore/Framebuffer.h new file mode 100644 index 0000000000..85a582f874 --- /dev/null +++ b/ports/broadcom/common-hal/videocore/Framebuffer.h @@ -0,0 +1,38 @@ +#pragma once + +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + uint32_t *framebuffer; + uint16_t width; + uint16_t height; + uint16_t pitch; + bool doublebuffer; +} videocore_framebuffer_obj_t; diff --git a/ports/broadcom/config.txt b/ports/broadcom/config.txt new file mode 100644 index 0000000000..36fd6308cf --- /dev/null +++ b/ports/broadcom/config.txt @@ -0,0 +1,9 @@ + +# dtparam=audio=on +# dtoverlay=dwc2 +# core_freq_min=500 +gpio=22-27=np +enable_jtag_gpio=1 +# hdmi_group=1 +# hdmi_mode=16 +gpu_mem=16 diff --git a/ports/broadcom/fatfs_port.c b/ports/broadcom/fatfs_port.c new file mode 100644 index 0000000000..58a0ef0d72 --- /dev/null +++ b/ports/broadcom/fatfs_port.c @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mphal.h" +#include "py/runtime.h" +#include "lib/oofatfs/ff.h" /* FatFs lower layer API */ +#include "lib/oofatfs/diskio.h" /* FatFs lower layer API */ +#include "shared/timeutils/timeutils.h" + +#if CIRCUITPY_RTC +#include "shared-bindings/rtc/RTC.h" +#endif + +DWORD get_fattime(void) { + #if CIRCUITPY_RTC + timeutils_struct_time_t tm; + common_hal_rtc_get_time(&tm); + return ((tm.tm_year - 1980) << 25) | (tm.tm_mon << 21) | (tm.tm_mday << 16) | + (tm.tm_hour << 11) | (tm.tm_min << 5) | (tm.tm_sec >> 1); + #else + return ((2016 - 1980) << 25) | ((9) << 21) | ((1) << 16) | ((16) << 11) | ((43) << 5) | (35 / 2); + #endif + + +} diff --git a/ports/broadcom/firmware b/ports/broadcom/firmware new file mode 160000 index 0000000000..6a5207946e --- /dev/null +++ b/ports/broadcom/firmware @@ -0,0 +1 @@ +Subproject commit 6a5207946edcd45813d1dd1572ca8bd8101b68b6 diff --git a/ports/broadcom/mpconfigport.h b/ports/broadcom/mpconfigport.h new file mode 100644 index 0000000000..79227b3863 --- /dev/null +++ b/ports/broadcom/mpconfigport.h @@ -0,0 +1,62 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __INCLUDED_MPCONFIGPORT_H +#define __INCLUDED_MPCONFIGPORT_H + +// Definitions that control circuitpy_mpconfig.h: + +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +#define CIRCUITPY_MCU_FAMILY broadcom +#define MICROPY_PY_SYS_PLATFORM "BROADCOM" +#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) +#define MICROPY_PY_FUNCTION_ATTRS (1) +#define MICROPY_OBJ_REPR (0) +#define CIRCUITPY_DEFAULT_STACK_SIZE (0x10000) +#define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (1920) +#define CIRCUITPY_PROCESSOR_COUNT (4) + +#define MICROPY_FF_MKFS_FAT32 (1) +#define MICROPY_FATFS_EXFAT (1) + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// This also includes mpconfigboard.h. +#include "py/circuitpy_mpconfig.h" + +// Definitions that can be overridden by mpconfigboard.h: + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#define MICROPY_PORT_ROOT_POINTERS \ + CIRCUITPY_COMMON_ROOT_POINTERS + +#define DEBUG_UART_TX (&pin_GPIO14) +#define DEBUG_UART_RX (&pin_GPIO15) + +#endif // __INCLUDED_MPCONFIGPORT_H diff --git a/ports/broadcom/mpconfigport.mk b/ports/broadcom/mpconfigport.mk new file mode 100644 index 0000000000..b17eb12f63 --- /dev/null +++ b/ports/broadcom/mpconfigport.mk @@ -0,0 +1,58 @@ +# Typically the first module to create +CIRCUITPY_MICROCONTROLLER = 1 +# Typically the second module to create +CIRCUITPY_DIGITALIO = 1 +# Other modules: +CIRCUITPY_ANALOGIO = 0 +CIRCUITPY_BUSIO = 1 +CIRCUITPY_ONEWIREIO = 0 +CIRCUITPY_PWMIO = 0 +CIRCUITPY_COUNTIO = 0 +CIRCUITPY_NEOPIXEL_WRITE = 0 +CIRCUITPY_PULSEIO = 0 +CIRCUITPY_OS = 1 +CIRCUITPY_NVM = 0 +CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOIO = 0 +CIRCUITPY_ROTARYIO = 0 +CIRCUITPY_RTC = 0 +CIRCUITPY_SDCARDIO = 0 +CIRCUITPY_SDIOIO = 1 +CIRCUITPY_FRAMEBUFFERIO = 1 +CIRCUITPY_FREQUENCYIO = 0 +CIRCUITPY_I2CPERIPHERAL = 0 +# Requires SPI, PulseIO (stub ok): +CIRCUITPY_DISPLAYIO = 1 + +# These modules are implemented in shared-module/ - they can be included in +# any port once their prerequisites in common-hal are complete. +# Requires DigitalIO: +CIRCUITPY_BITBANGIO = 1 +# Requires DigitalIO +CIRCUITPY_GAMEPAD = 0 +# Requires neopixel_write or SPI (dotstar) +CIRCUITPY_PIXELBUF = 0 +# Requires OS +CIRCUITPY_RANDOM = 1 +# Requires OS, filesystem +CIRCUITPY_STORAGE = 1 +# Requires Microcontroller +CIRCUITPY_TOUCHIO = 0 +# Requires USB +CIRCUITPY_USB = 1 +CIRCUITPY_USB_MSC = 1 +CIRCUITPY_USB_HID = 1 +CIRCUITPY_USB_MIDI = 1 +USB_NUM_ENDPOINT_PAIRS = 8 +# Does nothing without I2C +CIRCUITPY_REQUIRE_I2C_PULLUPS = 0 +# No requirements, but takes extra flash +CIRCUITPY_ULAB = 0 + +CIRCUITPY_VIDEOCORE = 1 + +CIRCUITPY_ERRNO = 0 + +CIRCUITPY_FULL_BUILD = 0 + +INTERNAL_FLASH_FILESYSTEM = 1 diff --git a/ports/broadcom/mphalport.c b/ports/broadcom/mphalport.c new file mode 100644 index 0000000000..f4bfd8653b --- /dev/null +++ b/ports/broadcom/mphalport.c @@ -0,0 +1,34 @@ +#include + +#include +#include "py/mpconfig.h" +#include "py/obj.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "mphalport.h" + +void mp_hal_delay_us(mp_uint_t delay) { +} + +void mp_hal_disable_all_interrupts(void) { + common_hal_mcu_disable_interrupts(); +} + +void mp_hal_enable_all_interrupts(void) { + common_hal_mcu_enable_interrupts(); +} + +mp_uint_t cpu_get_regs_and_sp(mp_uint_t *regs) { + size_t sp = 0; + __asm__ ("mov %[out], sp" : [out] "=r" (sp)); + __asm__ ("mov %[out], x19" : [out] "=r" (regs[0])); + __asm__ ("mov %[out], x20" : [out] "=r" (regs[1])); + __asm__ ("mov %[out], x21" : [out] "=r" (regs[2])); + __asm__ ("mov %[out], x22" : [out] "=r" (regs[3])); + __asm__ ("mov %[out], x23" : [out] "=r" (regs[4])); + __asm__ ("mov %[out], x24" : [out] "=r" (regs[5])); + __asm__ ("mov %[out], x25" : [out] "=r" (regs[6])); + __asm__ ("mov %[out], x26" : [out] "=r" (regs[7])); + __asm__ ("mov %[out], x27" : [out] "=r" (regs[8])); + __asm__ ("mov %[out], x28" : [out] "=r" (regs[9])); + return sp; +} diff --git a/ports/broadcom/mphalport.h b/ports/broadcom/mphalport.h new file mode 100644 index 0000000000..1efd931974 --- /dev/null +++ b/ports/broadcom/mphalport.h @@ -0,0 +1,26 @@ +#include +#include "py/obj.h" + +void mp_hal_delay_ms(mp_uint_t ms); +void mp_hal_delay_us(mp_uint_t us); +mp_uint_t mp_hal_ticks_cpu(void); +mp_uint_t mp_hal_ticks_us(void); +mp_uint_t mp_hal_ticks_ms(void); + +void mp_hal_set_interrupt_char(int c); +int mp_hal_stdin_rx_chr(void); +void mp_hal_stdout_tx_strn(const char *str, size_t len); + +typedef enum std_io_t { + MINI_UART = 0, + UART, + UART_QEMU +} std_io_t; + +void uart_init(std_io_t interface); + +#ifdef MICROPY_HW_USBHOST +#include "usbkbd.h" + +void usbkbd_setup(); +#endif diff --git a/ports/broadcom/peripherals b/ports/broadcom/peripherals new file mode 160000 index 0000000000..764ea35db1 --- /dev/null +++ b/ports/broadcom/peripherals @@ -0,0 +1 @@ +Subproject commit 764ea35db106d2d4a2fe2f827a65485eded42e00 diff --git a/ports/broadcom/qstrdefsport.h b/ports/broadcom/qstrdefsport.h new file mode 100644 index 0000000000..ca01f8037c --- /dev/null +++ b/ports/broadcom/qstrdefsport.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// qstrs specific to this port, only needed if they aren't auto-generated + +// Entries for sys.path +Q(/sd) +Q(/sd/lib) diff --git a/ports/broadcom/supervisor/internal_flash.c b/ports/broadcom/supervisor/internal_flash.c new file mode 100644 index 0000000000..08c10848a8 --- /dev/null +++ b/ports/broadcom/supervisor/internal_flash.c @@ -0,0 +1,179 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "supervisor/flash.h" +#include "supervisor/internal_flash.h" + +#include + +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/sdioio/SDCard.h" + +STATIC sdioio_sdcard_obj_t sd; + +STATIC uint32_t first_lba = 0; +STATIC uint32_t sector_count = 0; + +STATIC bool inited = false; + +void supervisor_flash_init(void) { + if (inited) { + return; + } + inited = true; + + #if BCM_VERSION != 2711 + const mcu_pin_obj_t *data_pins[4] = { + &pin_GPIO50, + &pin_GPIO51, + &pin_GPIO52, + &pin_GPIO53, + }; + common_hal_sdioio_sdcard_construct(&sd, + &pin_GPIO48, &pin_GPIO49, + 4, data_pins, 8000000); + #else + common_hal_sdioio_sdcard_construct(&sd, + NULL, NULL, + 0, NULL, 8000000); + #endif + + uint32_t buffer[512 / sizeof(uint32_t)]; + mp_buffer_info_t bufinfo; + bufinfo.len = 512; + bufinfo.buf = buffer; + common_hal_sdioio_sdcard_readblocks(&sd, 0, &bufinfo); + size_t partition_count = 0; + size_t first_free_sector = 0; + for (size_t i = 0; i < 4; i++) { + uint32_t part_first_lba = 0; + uint32_t part_sector_count = 0; + for (size_t j = 0; j < 16; j++) { + size_t offset = 446 + i * 16 + j; + uint8_t value = ((uint8_t *)buffer)[offset]; + // Little endian + if (j >= 8 && j < 12) { + part_first_lba |= value << (8 * (j - 8)); + } else if (j >= 12) { + part_sector_count |= value << (8 * (j - 12)); + } + } + if (part_sector_count > 0) { + partition_count += 1; + first_free_sector = part_first_lba + part_sector_count; + } + // If the second partition exists, then use it (possibly after reformatting it.) + if (i == 1 && part_sector_count > 0 && part_first_lba > 0) { + sector_count = part_sector_count; + first_lba = part_first_lba; + } else if (i > 1 && part_sector_count > 0) { + sector_count = 0; + } + } + + // Special case where most of the card is unused and the first and only + // partition is likely the CP boot partition. (It is 255MB starting at 1MB) + size_t sectors_per_mb = 2048; + if (partition_count == 1 && first_free_sector == 256 * sectors_per_mb) { + size_t total_sectors = common_hal_sdioio_sdcard_get_count(&sd); + // Align to a MB + total_sectors = total_sectors - (total_sectors % sectors_per_mb); + // Don't use the last MB because the imager erases it. GPT tables put a + // backup there sometimes. + total_sectors -= sectors_per_mb; + size_t new_sector_count = total_sectors - first_free_sector; + + // Modify the MBR + size_t offset = 446 + 1 * 16; + uint8_t *part = ((uint8_t *)buffer) + offset; + part[0] = 0; // not boot + part[1] = 0xff; // Old unused CHS sizing + part[2] = 0xff; + part[3] = 0xff; + uint8_t type = 0x0C; // FAT32 with LBA + if (new_sector_count >= 0x4000000) { + type = 0x07; // Exfat when 32GB+ + } + part[4] = type; + part[5] = 0xff; // Old unused CHS sizing + part[6] = 0xff; + part[7] = 0xff; + part[8] = first_free_sector & 0xff; + part[9] = (first_free_sector >> 8) & 0xff; + part[10] = (first_free_sector >> 16) & 0xff; + part[11] = (first_free_sector >> 24) & 0xff; + part[12] = new_sector_count & 0xff; + part[13] = (new_sector_count >> 8) & 0xff; + part[14] = (new_sector_count >> 16) & 0xff; + part[15] = (new_sector_count >> 24) & 0xff; + + // Write back the modified MBR with the new partition. CircuitPython can + // detect a previously formatted FAT filesystem later if only the MBR and + // BOOT partition was updated. + if (common_hal_sdioio_sdcard_writeblocks(&sd, 0, &bufinfo) == 0) { + sector_count = new_sector_count; + first_lba = first_free_sector; + } + } +} + +uint32_t supervisor_flash_get_block_size(void) { + return 512; +} + +uint32_t supervisor_flash_get_block_count(void) { + return sector_count; +} + +void port_internal_flash_flush(void) { +} + +mp_uint_t supervisor_flash_read_blocks(uint8_t *dest, uint32_t block, uint32_t num_blocks) { + mp_buffer_info_t bufinfo; + bufinfo.len = 512; + for (size_t i = 0; i < num_blocks; i++) { + bufinfo.buf = dest + 512 * i; + if (common_hal_sdioio_sdcard_readblocks(&sd, first_lba + block + i, &bufinfo) != 0) { + return 1; // error + } + } + return 0; // success +} + +mp_uint_t supervisor_flash_write_blocks(const uint8_t *src, uint32_t block, uint32_t num_blocks) { + mp_buffer_info_t bufinfo; + bufinfo.len = 512; + for (size_t i = 0; i < num_blocks; i++) { + bufinfo.buf = (uint8_t *)src + 512 * i; + if (common_hal_sdioio_sdcard_writeblocks(&sd, first_lba + block + i, &bufinfo) != 0) { + return 1; // error + } + } + return 0; // success +} + +void supervisor_flash_release_cache(void) { +} diff --git a/ports/broadcom/supervisor/internal_flash.h b/ports/broadcom/supervisor/internal_flash.h new file mode 100644 index 0000000000..f27e161dd1 --- /dev/null +++ b/ports/broadcom/supervisor/internal_flash.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_BROADCOM_INTERNAL_FLASH_H +#define MICROPY_INCLUDED_BROADCOM_INTERNAL_FLASH_H + +#include + +#include "mpconfigport.h" + +#endif // MICROPY_INCLUDED_BROADCOM_INTERNAL_FLASH_H diff --git a/ports/broadcom/supervisor/internal_flash_root_pointers.h b/ports/broadcom/supervisor/internal_flash_root_pointers.h new file mode 100644 index 0000000000..5efe3ac813 --- /dev/null +++ b/ports/broadcom/supervisor/internal_flash_root_pointers.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_BROADCOM_INTERNAL_FLASH_ROOT_POINTERS_H +#define MICROPY_INCLUDED_BROADCOM_INTERNAL_FLASH_ROOT_POINTERS_H + +#define FLASH_ROOT_POINTERS + +#endif // MICROPY_INCLUDED_BROADCOM_INTERNAL_FLASH_ROOT_POINTERS_H diff --git a/ports/broadcom/supervisor/port.c b/ports/broadcom/supervisor/port.c new file mode 100644 index 0000000000..ddd24fe540 --- /dev/null +++ b/ports/broadcom/supervisor/port.c @@ -0,0 +1,199 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "supervisor/board.h" +#include "supervisor/port.h" + +#include "genhdr/mpversion.h" + +// #include "common-hal/rtc/RTC.h" +#include "common-hal/busio/I2C.h" +#include "common-hal/busio/SPI.h" +#include "common-hal/busio/UART.h" + +#include "peripherals/broadcom/caches.h" +#include "peripherals/broadcom/cpu.h" +#include "peripherals/broadcom/defines.h" +#include "peripherals/broadcom/interrupts.h" +#include "peripherals/broadcom/mmu.h" + +#include "shared-bindings/microcontroller/__init__.h" + +#include "supervisor/shared/safe_mode.h" +#include "supervisor/shared/stack.h" +#include "supervisor/shared/tick.h" + +#include "peripherals/broadcom/vcmailbox.h" + +// #include "tusb.h" + +extern volatile bool mp_msc_enabled; + +STATIC uint32_t board_revision; + +safe_mode_t port_init(void) { + board_revision = vcmailbox_get_board_revision(); + setup_mmu_flat_map(); + + init_caches(); + + // Set brown out. + + // Reset everything into a known state before board_init. + reset_port(); + + // Initialize RTC + // common_hal_rtc_init(); + + // For the tick. + // hardware_alarm_claim(0); + // hardware_alarm_set_callback(0, _tick_callback); + + // Check brownout. + + if (board_requests_safe_mode()) { + return USER_SAFE_MODE; + } + + return NO_SAFE_MODE; +} + +void reset_port(void) { + #if CIRCUITPY_BUSIO + reset_i2c(); + reset_spi(); + reset_uart(); + #endif + + #if CIRCUITPY_PWMIO + pwmout_reset(); + #endif + + #if CIRCUITPY_RTC + rtc_reset(); + #endif + + #if CIRCUITPY_AUDIOPWMIO + audiopwmout_reset(); + #endif + #if CIRCUITPY_AUDIOCORE + audio_dma_reset(); + #endif + + // reset_all_pins(); +} + +void reset_to_bootloader(void) { + // reset_usb_boot(0, 0); + while (true) { + } +} + +void reset_cpu(void) { + + while (true) { + } +} + +bool port_has_fixed_stack(void) { + return true; +} + +uint32_t *port_stack_get_limit(void) { + return (uint32_t *)0x4; +} + +uint32_t *port_stack_get_top(void) { + return (uint32_t *)0x80000; +} + +// From the linker script +extern uint32_t __bss_end; +uint32_t *port_heap_get_bottom(void) { + return &__bss_end; +} + +uint32_t *port_heap_get_top(void) { + // 32M heap + return (uint32_t *)(((uint64_t)&__bss_end) + 32 * 1024 * 1024); +} + +void port_set_saved_word(uint32_t value) { + // NOTE: This doesn't survive pressing the reset button (aka toggling RUN). + // watchdog_hw->scratch[0] = value; +} + +uint32_t port_get_saved_word(void) { + // return watchdog_hw->scratch[0]; + return 0; +} + +uint64_t port_get_raw_ticks(uint8_t *subticks) { + COMPLETE_MEMORY_READS; + uint64_t hi = SYSTMR->CHI; + uint64_t lo = SYSTMR->CLO; + if (hi != SYSTMR->CHI) { + hi = SYSTMR->CHI; + lo = SYSTMR->CLO; + } + COMPLETE_MEMORY_READS; + uint64_t microseconds = hi << 32 | lo; + return 1024 * (microseconds / 1000000) + (microseconds % 1000000) / 977; +} + +void TIMER_1_IRQHandler(void) { + SYSTMR->C1 += 977; + SYSTMR->CS_b.M1 = 1; + supervisor_tick(); +} + +// Enable 1/1024 second tick. +void port_enable_tick(void) { + COMPLETE_MEMORY_READS; + SYSTMR->CS_b.M1 = 1; + SYSTMR->C1 = SYSTMR->CLO + 977; + BP_EnableIRQ(TIMER_1_IRQn); +} + +// Disable 1/1024 second tick. +void port_disable_tick(void) { + BP_DisableIRQ(TIMER_1_IRQn); +} + +void port_interrupt_after_ticks(uint32_t ticks) { +} + +void port_idle_until_interrupt(void) { + common_hal_mcu_disable_interrupts(); +// if (!tud_task_event_ready()) { +// // asm volatile ("dsb 0xF":::"memory"); +// // __wfi(); +// } + common_hal_mcu_enable_interrupts(); +} diff --git a/ports/broadcom/supervisor/usb.c b/ports/broadcom/supervisor/usb.c new file mode 100644 index 0000000000..5430b6f943 --- /dev/null +++ b/ports/broadcom/supervisor/usb.c @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017, 2018 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "lib/tinyusb/src/device/usbd.h" +#include "py/runtime.h" +#include "supervisor/background_callback.h" +#include "supervisor/usb.h" + +#include "peripherals/broadcom/interrupts.h" +#include "peripherals/broadcom/vcmailbox.h" + +uint32_t SystemCoreClock = 700 * 1000 * 1000; + +void USB_IRQHandler(void) { + usb_irq_handler(); +} + +void init_usb_hardware(void) { + vcmailbox_set_power_state(VCMAILBOX_DEVICE_USB_HCD, true); + + BP_SetPriority(USB_IRQn, 0x00); + BP_ClearPendingIRQ(USB_IRQn); + BP_EnableIRQ(USB_IRQn); + BP_EnableIRQs(); +} diff --git a/ports/cxd56/common-hal/sdioio/SDCard.c b/ports/cxd56/common-hal/sdioio/SDCard.c index 58d786517b..56fe5f7057 100644 --- a/ports/cxd56/common-hal/sdioio/SDCard.c +++ b/ports/cxd56/common-hal/sdioio/SDCard.c @@ -38,7 +38,7 @@ void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *command, - uint8_t num_data, mcu_pin_obj_t **data, uint32_t frequency) { + uint8_t num_data, const mcu_pin_obj_t **data, uint32_t frequency) { struct geometry geo; if (clock->number != PIN_SDIO_CLK || command->number != PIN_SDIO_CMD) { diff --git a/ports/espressif/common-hal/canio/CAN.c b/ports/espressif/common-hal/canio/CAN.c index eebf064f44..fb2e35f1b1 100644 --- a/ports/espressif/common-hal/canio/CAN.c +++ b/ports/espressif/common-hal/canio/CAN.c @@ -105,7 +105,7 @@ STATIC twai_timing_config_t get_t_config(int baudrate) { } } -void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *tx, mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent) { +void common_hal_canio_can_construct(canio_can_obj_t *self, const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent) { #define DIV_ROUND(a, b) (((a) + (b) / 2) / (b)) #define DIV_ROUND_UP(a, b) (((a) + (b) - 1) / (b)) if (reserved_can) { diff --git a/ports/espressif/common-hal/paralleldisplay/ParallelBus.c b/ports/espressif/common-hal/paralleldisplay/ParallelBus.c index 05dcfcca54..b9ee1f055d 100644 --- a/ports/espressif/common-hal/paralleldisplay/ParallelBus.c +++ b/ports/espressif/common-hal/paralleldisplay/ParallelBus.c @@ -44,7 +44,7 @@ */ void common_hal_paralleldisplay_parallelbus_construct_nonsequential(paralleldisplay_parallelbus_obj_t *self, - uint8_t n_pins, mcu_pin_obj_t **data_pins, + uint8_t n_pins, const mcu_pin_obj_t **data_pins, const mcu_pin_obj_t *command, const mcu_pin_obj_t *chip_select, const mcu_pin_obj_t *write, const mcu_pin_obj_t *read, const mcu_pin_obj_t *reset, uint32_t frequency) { @@ -118,7 +118,7 @@ void common_hal_paralleldisplay_parallelbus_construct(paralleldisplay_parallelbu const mcu_pin_obj_t *data0, const mcu_pin_obj_t *command, const mcu_pin_obj_t *chip_select, const mcu_pin_obj_t *write, const mcu_pin_obj_t *read, const mcu_pin_obj_t *reset, uint32_t frequency) { char buf[7]; - mcu_pin_obj_t *data_pins[8]; + const mcu_pin_obj_t *data_pins[8]; for (int i = 0; i < 8; i++) { snprintf(buf, sizeof(buf), "GPIO%d", data0->number + i); data_pins[i] = validate_obj_is_free_pin(mp_obj_dict_get(MP_OBJ_FROM_PTR(&mcu_pin_globals), mp_obj_new_str(buf, strlen(buf)))); diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.c b/ports/raspberrypi/bindings/rp2pio/StateMachine.c index 61e526b226..0815112c3d 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.c +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.c @@ -201,22 +201,22 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n mp_get_buffer(args[ARG_init].u_obj, &init_bufinfo, MP_BUFFER_READ); // We don't validate pin in use here because we may be ok sharing them within a PIO. - mcu_pin_obj_t *first_out_pin = validate_obj_is_pin_or_none(args[ARG_first_out_pin].u_obj); + const mcu_pin_obj_t *first_out_pin = validate_obj_is_pin_or_none(args[ARG_first_out_pin].u_obj); if (args[ARG_out_pin_count].u_int < 1) { mp_raise_ValueError(translate("Pin count must be at least 1")); } - mcu_pin_obj_t *first_in_pin = validate_obj_is_pin_or_none(args[ARG_first_in_pin].u_obj); + const mcu_pin_obj_t *first_in_pin = validate_obj_is_pin_or_none(args[ARG_first_in_pin].u_obj); if (args[ARG_in_pin_count].u_int < 1) { mp_raise_ValueError(translate("Pin count must be at least 1")); } - mcu_pin_obj_t *first_set_pin = validate_obj_is_pin_or_none(args[ARG_first_set_pin].u_obj); + const mcu_pin_obj_t *first_set_pin = validate_obj_is_pin_or_none(args[ARG_first_set_pin].u_obj); if (args[ARG_set_pin_count].u_int < 1) { mp_raise_ValueError(translate("Pin count must be at least 1")); } if (args[ARG_set_pin_count].u_int > 5) { mp_raise_ValueError(translate("Set pin count must be between 1 and 5")); } - mcu_pin_obj_t *first_sideset_pin = validate_obj_is_pin_or_none(args[ARG_first_sideset_pin].u_obj); + const mcu_pin_obj_t *first_sideset_pin = validate_obj_is_pin_or_none(args[ARG_first_sideset_pin].u_obj); if (args[ARG_sideset_pin_count].u_int < 1) { mp_raise_ValueError(translate("Pin count must be at least 1")); } diff --git a/ports/raspberrypi/common-hal/rp2pio/__init__.c b/ports/raspberrypi/common-hal/rp2pio/__init__.c index ae4cb93d18..8b8101fbe5 100644 --- a/ports/raspberrypi/common-hal/rp2pio/__init__.c +++ b/ports/raspberrypi/common-hal/rp2pio/__init__.c @@ -32,9 +32,9 @@ bool common_hal_rp2pio_pins_are_sequential(size_t len, mp_obj_t *items) { if (len == 0) { return true; } - mcu_pin_obj_t *last_pin = validate_obj_is_pin(items[0]); + const mcu_pin_obj_t *last_pin = validate_obj_is_pin(items[0]); for (int i = 1; i < len; i++) { - mcu_pin_obj_t *pin = validate_obj_is_pin(items[i]); + const mcu_pin_obj_t *pin = validate_obj_is_pin(items[i]); if (pin->number != last_pin->number + 1) { return false; } diff --git a/ports/stm/common-hal/canio/CAN.c b/ports/stm/common-hal/canio/CAN.c index 091421fd1e..74ff7f964b 100644 --- a/ports/stm/common-hal/canio/CAN.c +++ b/ports/stm/common-hal/canio/CAN.c @@ -50,7 +50,7 @@ STATIC const mcu_periph_obj_t *find_pin_function(const mcu_periph_obj_t *table, } -void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *tx, mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent) { +void common_hal_canio_can_construct(canio_can_obj_t *self, const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent) { #define DIV_ROUND(a, b) (((a) + (b) / 2) / (b)) #define DIV_ROUND_UP(a, b) (((a) + (b) - 1) / (b)) diff --git a/ports/stm/common-hal/sdioio/SDCard.c b/ports/stm/common-hal/sdioio/SDCard.c index e09e2e1b3b..c7472a459f 100644 --- a/ports/stm/common-hal/sdioio/SDCard.c +++ b/ports/stm/common-hal/sdioio/SDCard.c @@ -51,7 +51,7 @@ STATIC const mcu_periph_obj_t *find_pin_function(const mcu_periph_obj_t *table, // match pins to SDIO objects STATIC int check_pins(sdioio_sdcard_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *command, - uint8_t num_data, mcu_pin_obj_t **data) { + uint8_t num_data, const mcu_pin_obj_t **data) { bool sdio_taken = false; const uint8_t sdio_clock_len = MP_ARRAY_SIZE(mcu_sdio_clock_list); @@ -122,7 +122,7 @@ STATIC int check_pins(sdioio_sdcard_obj_t *self, void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *command, - uint8_t num_data, mcu_pin_obj_t **data, uint32_t frequency) { + uint8_t num_data, const mcu_pin_obj_t **data, uint32_t frequency) { int periph_index = check_pins(self, clock, command, num_data, data); SDIO_TypeDef *SDIOx = mcu_sdio_banks[periph_index - 1]; diff --git a/py/builtinimport.c b/py/builtinimport.c index 5baef16d86..ca4b848407 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -483,7 +483,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { // afterwards. gc_collect(); } - if (outer_module_obj != MP_OBJ_NULL && VERIFY_PTR(outer_module_obj)) { + if (outer_module_obj != MP_OBJ_NULL && VERIFY_PTR(MP_OBJ_TO_PTR(outer_module_obj))) { qstr s = qstr_from_strn(mod_str + last, i - last); mp_store_attr(outer_module_obj, s, module_obj); // The above store can cause a dictionary rehash and new allocation. So, diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 68b529a05f..244abe9cba 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -206,6 +206,9 @@ endif ifeq ($(CIRCUITPY_I2CPERIPHERAL),1) SRC_PATTERNS += i2cperipheral/% endif +ifeq ($(CIRCUITPY_IMAGECAPTURE),1) +SRC_PATTERNS += imagecapture/% +endif ifeq ($(CIRCUITPY_IPADDRESS),1) SRC_PATTERNS += ipaddress/% endif @@ -332,6 +335,9 @@ endif ifeq ($(CIRCUITPY_USTACK),1) SRC_PATTERNS += ustack/% endif +ifeq ($(CIRCUITPY_VIDEOCORE),1) +SRC_PATTERNS += videocore/% +endif ifeq ($(CIRCUITPY_WATCHDOG),1) SRC_PATTERNS += watchdog/% endif @@ -341,9 +347,6 @@ endif ifeq ($(CIRCUITPY_PEW),1) SRC_PATTERNS += _pew/% endif -ifeq ($(CIRCUITPY_IMAGECAPTURE),1) -SRC_PATTERNS += imagecapture/% -endif ifeq ($(CIRCUITPY_MSGPACK),1) SRC_PATTERNS += msgpack/% endif diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 5105be4d95..6efc341fce 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -38,7 +38,9 @@ #define CIRCUITPY 1 // REPR_C encodes qstrs, 31-bit ints, and 30-bit floats in a single 32-bit word. +#ifndef MICROPY_OBJ_REPR #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C) +#endif // options to control how MicroPython is built // TODO(tannewt): Reduce this number if we want the REPL to function under 512 @@ -168,14 +170,17 @@ extern void common_hal_mcu_enable_interrupts(void); // Track stack usage. Expose results via ustack module. #define MICROPY_MAX_STACK_USAGE (0) -// This port is intended to be 32-bit, but unfortunately, int32_t for -// different targets may be defined in different ways - either as int -// or as long. This requires different printf formatting specifiers -// to print such value. So, we avoid int32_t and use int directly. #define UINT_FMT "%u" #define INT_FMT "%d" +#ifdef __LP64__ +typedef long mp_int_t; // must be pointer size +typedef unsigned long mp_uint_t; // must be pointer size +#else +// These are definitions for machines where sizeof(int) == sizeof(void*), +// regardless of actual size. typedef int mp_int_t; // must be pointer size -typedef unsigned mp_uint_t; // must be pointer size +typedef unsigned int mp_uint_t; // must be pointer size +#endif #if __GNUC__ >= 10 // on recent gcc versions we can check that this is so _Static_assert(sizeof(mp_int_t) == sizeof(void *)); _Static_assert(sizeof(mp_uint_t) == sizeof(void *)); @@ -275,8 +280,15 @@ typedef long mp_off_t; #ifndef CIRCUITPY_DISPLAY_LIMIT #define CIRCUITPY_DISPLAY_LIMIT (1) #endif + +// Framebuffer area size in bytes. Rounded down to power of four for alignment. +#ifndef CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE +#define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (128) +#endif + #else #define CIRCUITPY_DISPLAY_LIMIT (0) +#define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (0) #endif #if CIRCUITPY_GAMEPADSHIFT @@ -357,82 +369,6 @@ extern const struct _mp_obj_module_t nvm_module; #define MICROPY_PORT_BUILTIN_MODULES_STRONG_LINKS -// The following modules are defined in their respective __init__.c file in the -// shared-bindings directory using MP_REGISTER_MODULE. -// -// CIRCUITPY_AESIO -// CIRCUITPY_ANALOGIO -// CIRCUITPY_ATEXIT -// CIRCUITPY_AUDIOBUSIO -// CIRCUITPY_AUDIOCORE -// CIRCUITPY_AUDIOIO -// CIRCUITPY_AUDIOMIXER -// CIRCUITPY_AUDIOMP3 -// CIRCUITPY_AUDIOPWMIO -// CIRCUITPY_BITBANGIO -// CIRCUITPY_BITMAPTOOLS -// CIRCUITPY_BITOPS -// CIRCUITPY_BLEIO -// CIRCUITPY_BOARD -// CIRCUITPY_BUSDEVICE -// CIRCUITPY_BUSIO -// CIRCUITPY_CAMERA -// CIRCUITPY_CANIO -// CIRCUITPY_COUNTIO -// CIRCUITPY_DIGITALIO -// CIRCUITPY_DISPLAYIO -// CIRCUITPY_DUALBANK -// CIRCUITPY__EVE -// CIRCUITPY_FONTIO -// CIRCUITPY_FRAMEBUFFERIO -// CIRCUITPY_FREQUENCYIO -// CIRCUITPY_GAMEPADSHIFT -// CIRCUITPY_GETPASS -// CIRCUITPY_GNSS -// CIRCUITPY_I2CPERIPHERAL -// CIRCUITPY_IMAGECAPTURE -// CIRCUITPY_IPADDRESS -// CIRCUITPY_KEYPAD -// CIRCUITPY_MATH -// CIRCUITPY_MEMORYMONITOR -// CIRCUITPY_MICROCONTROLLER -// CIRCUITPY_MSGPACK -// CIRCUITPY_NEOPIXEL_WRITE -// CIRCUITPY_ONEWIREIO_WRITE -// CIRCUITPY_PARALLELDISPLAY -// CIRCUITPY_PEW -// CIRCUITPY_PIXELBUF -// CIRCUITPY_PS2IO -// CIRCUITPY_PULSEIO -// CIRCUITPY_PWMIO -// CIRCUITPY_QRIO -// CIRCUITPY_RAINBOWIO -// CIRCUITPY_RANDOM -// CIRCUITPY_RGBMATRIX -// CIRCUITPY_ROTARYIO -// CIRCUITPY_RTC -// CIRCUITPY_SDCARDIO -// CIRCUITPY_SDIOIO -// CIRCUITPY_SHARPDISPLAY -// CIRCUITPY_SOCKETPOOL -// CIRCUITPY_SSL -// CIRCUITPY_STAGE -// CIRCUITPY_STORAGE -// CIRCUITPY_STRUCT -// CIRCUITPY_SUPERVISOR -// CIRCUITPY_SYNTHIO -// CIRCUITPY_TERMINALIO -// CIRCUITPY_TOUCHIO -// CIRCUITPY_TRACEBACK -// CIRCUITPY_UHEAP -// CIRCUITPY_USB_CDC -// CIRCUITPY_USB_HID -// CIRCUITPY_USB_MIDI -// CIRCUITPY_USTACK -// CIRCUITPY_VECTORIO -// CIRCUITPY_WATCHDOG -// CIRCUITPY_WIFI - // If weak links are enabled, just include strong links in the main list of modules, // and also include the underscore alternate names. #if MICROPY_MODULE_WEAK_LINKS diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index ccb9daf5eb..28469f17f2 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -447,6 +447,12 @@ CFLAGS += -DCIRCUITPY_USTACK=$(CIRCUITPY_USTACK) CIRCUITPY_ULAB ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_ULAB=$(CIRCUITPY_ULAB) +# CIRCUITPY_VIDEOCORE is handled in the broadcom tree. +# Only for Broadcom chips. +# Assume not a Broadcom build. +CIRCUITPY_VIDEOCORE ?= 0 +CFLAGS += -DCIRCUITPY_VIDEOCORE=$(CIRCUITPY_VIDEOCORE) + # watchdog hardware support CIRCUITPY_WATCHDOG ?= 0 CFLAGS += -DCIRCUITPY_WATCHDOG=$(CIRCUITPY_WATCHDOG) diff --git a/py/enum.c b/py/enum.c index b0d43b52d1..4728c7f11d 100644 --- a/py/enum.c +++ b/py/enum.c @@ -30,7 +30,7 @@ mp_obj_t cp_enum_find(const mp_obj_type_t *type, int value) { const mp_obj_dict_t *dict = type->locals_dict; for (size_t i = 0; i < dict->map.used; i++) { - const cp_enum_obj_t *v = dict->map.table[i].value; + const cp_enum_obj_t *v = MP_OBJ_TO_PTR(dict->map.table[i].value); if (v->value == value) { return (mp_obj_t)v; } @@ -38,7 +38,7 @@ mp_obj_t cp_enum_find(const mp_obj_type_t *type, int value) { return mp_const_none; } -int cp_enum_value(const mp_obj_type_t *type, mp_obj_t *obj) { +int cp_enum_value(const mp_obj_type_t *type, mp_obj_t obj) { if (!mp_obj_is_type(obj, type)) { mp_raise_TypeError_varg(MP_ERROR_TEXT("Expected a %q"), type->name); } @@ -47,6 +47,6 @@ int cp_enum_value(const mp_obj_type_t *type, mp_obj_t *obj) { void cp_enum_obj_print_helper(uint16_t module, const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; - cp_enum_obj_t *self = self_in; + cp_enum_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "%q.%q.%q", module, self->base.type->name, self->name); } diff --git a/py/enum.h b/py/enum.h index 286bac098f..d0b8529a4d 100644 --- a/py/enum.h +++ b/py/enum.h @@ -55,11 +55,11 @@ typedef struct { { &mp_type_type }, \ .name = MP_QSTR_##type, \ .print = typename##_print, \ - .locals_dict = (mp_obj_t)&typename##_locals_dict, \ + .locals_dict = (mp_obj_dict_t *)&typename##_locals_dict, \ } mp_obj_t cp_enum_find(const mp_obj_type_t *type, int value); -int cp_enum_value(const mp_obj_type_t *type, mp_obj_t *obj); +int cp_enum_value(const mp_obj_type_t *type, mp_obj_t obj); void cp_enum_obj_print_helper(uint16_t module, const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); diff --git a/py/gc_long_lived.c b/py/gc_long_lived.c index df3f72e3cd..647c4f75b7 100644 --- a/py/gc_long_lived.c +++ b/py/gc_long_lived.c @@ -33,14 +33,14 @@ mp_obj_fun_bc_t *make_fun_bc_long_lived(mp_obj_fun_bc_t *fun_bc, uint8_t max_dep #ifndef MICROPY_ENABLE_GC return fun_bc; #endif - if (fun_bc == NULL || fun_bc == mp_const_none || max_depth == 0) { + if (fun_bc == NULL || MP_OBJ_FROM_PTR(fun_bc) == mp_const_none || max_depth == 0) { return fun_bc; } fun_bc->bytecode = gc_make_long_lived((byte *)fun_bc->bytecode); fun_bc->globals = make_dict_long_lived(fun_bc->globals, max_depth - 1); for (uint32_t i = 0; i < gc_nbytes(fun_bc->const_table) / sizeof(mp_obj_t); i++) { // Skip things that aren't allocated on the heap (and hence have zero bytes.) - if (gc_nbytes((byte *)fun_bc->const_table[i]) == 0) { + if (gc_nbytes(MP_OBJ_TO_PTR(fun_bc->const_table[i])) == 0) { continue; } // Try to detect raw code. @@ -59,11 +59,11 @@ mp_obj_fun_bc_t *make_fun_bc_long_lived(mp_obj_fun_bc_t *fun_bc, uint8_t max_dep // Functions (mp_obj_fun_bc_t) have four pointers (base, globals, bytecode and const_table) // before the variable length extra_args so remove them from the length. for (size_t i = 0; i < words - 4; i++) { - if (fun_bc->extra_args[i] == NULL) { + if (MP_OBJ_TO_PTR(fun_bc->extra_args[i]) == NULL) { continue; } if (mp_obj_is_type(fun_bc->extra_args[i], &mp_type_dict)) { - fun_bc->extra_args[i] = make_dict_long_lived(fun_bc->extra_args[i], max_depth - 1); + fun_bc->extra_args[i] = MP_OBJ_FROM_PTR(make_dict_long_lived(MP_OBJ_TO_PTR(fun_bc->extra_args[i]), max_depth - 1)); } else { fun_bc->extra_args[i] = make_obj_long_lived(fun_bc->extra_args[i], max_depth - 1); } @@ -79,9 +79,9 @@ mp_obj_property_t *make_property_long_lived(mp_obj_property_t *prop, uint8_t max if (max_depth == 0) { return prop; } - prop->proxy[0] = make_obj_long_lived((mp_obj_fun_bc_t *)prop->proxy[0], max_depth - 1); - prop->proxy[1] = make_obj_long_lived((mp_obj_fun_bc_t *)prop->proxy[1], max_depth - 1); - prop->proxy[2] = make_obj_long_lived((mp_obj_fun_bc_t *)prop->proxy[2], max_depth - 1); + prop->proxy[0] = make_obj_long_lived(prop->proxy[0], max_depth - 1); + prop->proxy[1] = make_obj_long_lived(prop->proxy[1], max_depth - 1); + prop->proxy[2] = make_obj_long_lived(prop->proxy[2], max_depth - 1); return gc_make_long_lived(prop); } @@ -123,7 +123,7 @@ mp_obj_t make_obj_long_lived(mp_obj_t obj, uint8_t max_depth) { #ifndef MICROPY_ENABLE_GC return obj; #endif - if (obj == NULL) { + if (MP_OBJ_TO_PTR(obj) == NULL) { return obj; } // If not in the GC pool, do nothing. This can happen (at least) when @@ -144,6 +144,6 @@ mp_obj_t make_obj_long_lived(mp_obj_t obj, uint8_t max_depth) { // Types are already long lived during creation. return obj; } else { - return gc_make_long_lived(obj); + return MP_OBJ_FROM_PTR(gc_make_long_lived(MP_OBJ_TO_PTR(obj))); } } diff --git a/py/nlrthumb.c b/py/nlrthumb.c index c52914ac40..30f9f2c196 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -26,7 +26,7 @@ #include "py/mpstate.h" -#if MICROPY_NLR_THUMB +#if defined(MICROPY_NLR_THUMB) && MICROPY_NLR_THUMB #undef nlr_push diff --git a/py/objgenerator.c b/py/objgenerator.c index 4066c1c566..c63ea6b816 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -136,22 +136,21 @@ STATIC mp_obj_t bc_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, c } STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_obj_gen_wrap_t *self = MP_OBJ_TO_PTR(self_in); - #if MICROPY_EMIT_NATIVE + mp_obj_gen_wrap_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t *)self->fun; if (self_fun->base.type == &mp_type_fun_native) { return native_gen_wrap_call(self, n_args, n_kw, args); } #endif - return bc_gen_wrap_call(self, n_args, n_kw, args); + return bc_gen_wrap_call(self_in, n_args, n_kw, args); } #if MICROPY_PY_FUNCTION_ATTRS static void gen_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_gen_wrap_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t *)self->fun; - mp_obj_fun_bc_attr(self_fun, attr, dest); + mp_obj_fun_bc_attr(MP_OBJ_FROM_PTR(self_fun), attr, dest); } #endif diff --git a/py/objlist.c b/py/objlist.c index 9b0e0edaa7..9d1949b7dc 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -97,8 +97,12 @@ STATIC mp_obj_t list_make_new(const mp_obj_type_t *type_in, size_t n_args, size_ } } +STATIC mp_obj_list_t *native_list(mp_obj_t self_in) { + return MP_OBJ_TO_PTR(mp_obj_cast_to_native_base(self_in, MP_OBJ_FROM_PTR(&mp_type_list))); +} + STATIC mp_obj_t list_unary_op(mp_unary_op_t op, mp_obj_t self_in) { - mp_obj_list_t *self = mp_obj_cast_to_native_base(self_in, &mp_type_list); + mp_obj_list_t *self = native_list(self_in); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->len != 0); @@ -116,7 +120,7 @@ STATIC mp_obj_t list_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { - mp_obj_list_t *o = mp_obj_cast_to_native_base(lhs, &mp_type_list); + mp_obj_list_t *o = native_list(lhs); switch (op) { case MP_BINARY_OP_ADD: { if (!mp_obj_is_type(rhs, &mp_type_list)) { @@ -167,7 +171,7 @@ STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { } STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { - mp_obj_list_t *self = mp_obj_cast_to_native_base(self_in, &mp_type_list); + mp_obj_list_t *self = native_list(self_in); if (value == MP_OBJ_NULL) { // delete #if MICROPY_PY_BUILTINS_SLICE @@ -186,7 +190,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { return mp_const_none; } #endif - mp_obj_t args[2] = {self, index}; + mp_obj_t args[2] = {MP_OBJ_FROM_PTR(self), index}; list_pop(2, args); return mp_const_none; } else if (value == MP_OBJ_SENTINEL) { @@ -235,7 +239,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { return mp_const_none; } #endif - mp_obj_list_store(self, index, value); + mp_obj_list_store(self_in, index, value); return mp_const_none; } } @@ -246,7 +250,7 @@ STATIC mp_obj_t list_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); - mp_obj_list_t *self = mp_obj_cast_to_native_base(self_in, &mp_type_list); + mp_obj_list_t *self = native_list(self_in); if (self->len >= self->alloc) { self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc * 2); self->alloc *= 2; @@ -259,8 +263,8 @@ mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); if (mp_obj_is_type(arg_in, &mp_type_list)) { - mp_obj_list_t *self = mp_obj_cast_to_native_base(self_in, &mp_type_list); - mp_obj_list_t *arg = mp_obj_cast_to_native_base(arg_in, &mp_type_list); + mp_obj_list_t *self = native_list(self_in); + mp_obj_list_t *arg = native_list(arg_in); if (self->len + arg->len > self->alloc) { // TODO: use alloc policy for "4" @@ -295,7 +299,7 @@ inline mp_obj_t mp_obj_list_pop(mp_obj_list_t *self, size_t index) { STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) { mp_check_self(mp_obj_is_type(args[0], &mp_type_list)); - mp_obj_list_t *self = mp_obj_cast_to_native_base(args[0], &mp_type_list); + mp_obj_list_t *self = native_list(args[0]); size_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false); return mp_obj_list_pop(self, index); } @@ -347,7 +351,7 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args); mp_check_self(mp_obj_is_type(pos_args[0], &mp_type_list)); - mp_obj_list_t *self = mp_obj_cast_to_native_base(pos_args[0], &mp_type_list); + mp_obj_list_t *self = native_list(pos_args[0]); if (self->len > 1) { mp_quicksort(self->items, self->items + self->len - 1, @@ -360,7 +364,7 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ mp_obj_t mp_obj_list_clear(mp_obj_t self_in) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); - mp_obj_list_t *self = mp_obj_cast_to_native_base(self_in, &mp_type_list); + mp_obj_list_t *self = native_list(self_in); self->len = 0; self->items = m_renew(mp_obj_t, self->items, self->alloc, LIST_MIN_ALLOC); self->alloc = LIST_MIN_ALLOC; @@ -370,19 +374,19 @@ mp_obj_t mp_obj_list_clear(mp_obj_t self_in) { STATIC mp_obj_t list_copy(mp_obj_t self_in) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); - mp_obj_list_t *self = mp_obj_cast_to_native_base(self_in, &mp_type_list); + mp_obj_list_t *self = native_list(self_in); return mp_obj_new_list(self->len, self->items); } STATIC mp_obj_t list_count(mp_obj_t self_in, mp_obj_t value) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); - mp_obj_list_t *self = mp_obj_cast_to_native_base(self_in, &mp_type_list); + mp_obj_list_t *self = native_list(self_in); return mp_seq_count_obj(self->items, self->len, value); } STATIC mp_obj_t list_index(size_t n_args, const mp_obj_t *args) { mp_check_self(mp_obj_is_type(args[0], &mp_type_list)); - mp_obj_list_t *self = mp_obj_cast_to_native_base(args[0], &mp_type_list); + mp_obj_list_t *self = native_list(args[0]); return mp_seq_index_obj(self->items, self->len, n_args, args); } @@ -397,7 +401,7 @@ inline void mp_obj_list_insert(mp_obj_list_t *self, size_t index, mp_obj_t obj) STATIC mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); - mp_obj_list_t *self = mp_obj_cast_to_native_base(self_in, &mp_type_list); + mp_obj_list_t *self = native_list(self_in); // insert has its own strange index logic mp_int_t index = MP_OBJ_SMALL_INT_VALUE(idx); if (index < 0) { @@ -424,7 +428,7 @@ mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value) { STATIC mp_obj_t list_reverse(mp_obj_t self_in) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); - mp_obj_list_t *self = mp_obj_cast_to_native_base(self_in, &mp_type_list); + mp_obj_list_t *self = native_list(self_in); mp_int_t len = self->len; for (mp_int_t i = 0; i < len / 2; i++) { @@ -504,7 +508,7 @@ mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items) { } void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { - mp_obj_list_t *self = mp_obj_cast_to_native_base(self_in, &mp_type_list); + mp_obj_list_t *self = native_list(self_in); *len = self->len; *items = self->items; } @@ -517,7 +521,7 @@ void mp_obj_list_set_len(mp_obj_t self_in, size_t len) { } void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { - mp_obj_list_t *self = mp_obj_cast_to_native_base(self_in, &mp_type_list); + mp_obj_list_t *self = native_list(self_in); size_t i = mp_get_index(self->base.type, self->len, index, false); self->items[i] = value; } diff --git a/py/objmodule.c b/py/objmodule.c index ea10fb8ba2..238b24be4b 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -102,7 +102,7 @@ STATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_dict_delete(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(attr)); } else { // store attribute - mp_obj_t long_lived = gc_make_long_lived(dest[1]); + mp_obj_t long_lived = MP_OBJ_FROM_PTR(gc_make_long_lived(MP_OBJ_TO_PTR(dest[1]))); // TODO CPython allows STORE_ATTR to a module, but is this the correct implementation? mp_obj_dict_store(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(attr), long_lived); } @@ -129,7 +129,7 @@ mp_obj_t mp_obj_new_module(qstr module_name) { // create new module object mp_obj_module_t *o = m_new_ll_obj(mp_obj_module_t); o->base.type = &mp_type_module; - o->globals = MP_OBJ_TO_PTR(gc_make_long_lived(mp_obj_new_dict(MICROPY_MODULE_DICT_SIZE))); + o->globals = gc_make_long_lived(MP_OBJ_TO_PTR(mp_obj_new_dict(MICROPY_MODULE_DICT_SIZE))); // store __name__ entry in the module mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(module_name)); diff --git a/py/objtuple.c b/py/objtuple.c index 55957b68bf..90b0773bb4 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -189,7 +189,7 @@ mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); // when called with a native type (eg namedtuple) using mp_obj_tuple_subscr, get the native self if (mp_type_get_subscr_slot(self->base.type) != &mp_obj_tuple_subscr) { - self = mp_obj_cast_to_native_base(self_in, &mp_type_tuple); + self = MP_OBJ_TO_PTR(mp_obj_cast_to_native_base(self_in, MP_OBJ_FROM_PTR(&mp_type_tuple))); } #if MICROPY_PY_BUILTINS_SLICE diff --git a/py/objtype.c b/py/objtype.c index 962f59eb55..cf94d300b9 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -1232,7 +1232,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) } } - o->locals_dict = make_dict_long_lived(locals_dict, 10); + o->locals_dict = make_dict_long_lived(MP_OBJ_TO_PTR(locals_dict), 10); #if ENABLE_SPECIAL_ACCESSORS // Check if the class has any special accessor methods diff --git a/py/py.mk b/py/py.mk index 0db1d43cfe..db92ef3c02 100644 --- a/py/py.mk +++ b/py/py.mk @@ -196,7 +196,6 @@ PY_EXTMOD_O_BASENAME = \ extmod/modutimeq.o \ extmod/moduhashlib.o \ extmod/modubinascii.o \ - extmod/virtpin.o \ extmod/modurandom.o \ extmod/moduselect.o \ extmod/modframebuf.o \ diff --git a/py/pystack.h b/py/pystack.h index 66ff2a6950..ed51e0c7e3 100644 --- a/py/pystack.h +++ b/py/pystack.h @@ -26,6 +26,7 @@ #ifndef MICROPY_INCLUDED_PY_PYSTACK_H #define MICROPY_INCLUDED_PY_PYSTACK_H +#include "py/mpconfig.h" #include "py/mpstate.h" // Enable this debugging option to check that the amount of memory freed is diff --git a/shared-bindings/board/__init__.c b/shared-bindings/board/__init__.c index 128988775f..bb273c61a9 100644 --- a/shared-bindings/board/__init__.c +++ b/shared-bindings/board/__init__.c @@ -67,7 +67,7 @@ mp_obj_t board_i2c(void) { #else mp_obj_t board_i2c(void) { mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_I2C); - return NULL; + return MP_ROM_NONE; } #endif MP_DEFINE_CONST_FUN_OBJ_0(board_i2c_obj, board_i2c); @@ -92,7 +92,7 @@ mp_obj_t board_spi(void) { #else mp_obj_t board_spi(void) { mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_SPI); - return NULL; + return MP_ROM_NONE; } #endif MP_DEFINE_CONST_FUN_OBJ_0(board_spi_obj, board_spi); @@ -121,7 +121,7 @@ mp_obj_t board_uart(void) { #else mp_obj_t board_uart(void) { mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_UART); - return NULL; + return MP_ROM_NONE; } #endif MP_DEFINE_CONST_FUN_OBJ_0(board_uart_obj, board_uart); diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index d8951cb565..4aea62a8a5 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -114,7 +114,7 @@ STATIC void check_for_deinit(busio_i2c_obj_t *self) { //| STATIC mp_obj_t busio_i2c_obj___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; - common_hal_busio_i2c_deinit(args[0]); + common_hal_busio_i2c_deinit(MP_OBJ_TO_PTR(args[0])); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_i2c___exit___obj, 4, 4, busio_i2c_obj___exit__); diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index b2cf90f2cc..6cbc05e3e7 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -133,7 +133,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_deinit_obj, busio_spi_obj_deinit); //| STATIC mp_obj_t busio_spi_obj___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; - common_hal_busio_spi_deinit(args[0]); + common_hal_busio_spi_deinit(MP_OBJ_TO_PTR(args[0])); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_spi_obj___exit___obj, 4, 4, busio_spi_obj___exit__); diff --git a/shared-bindings/busio/UART.c b/shared-bindings/busio/UART.c index 90cd7c3aa6..4df56c6e62 100644 --- a/shared-bindings/busio/UART.c +++ b/shared-bindings/busio/UART.c @@ -120,9 +120,9 @@ STATIC mp_obj_t busio_uart_make_new(const mp_obj_type_t *type, size_t n_args, si uint8_t bits = args[ARG_bits].u_int; busio_uart_parity_t parity = BUSIO_UART_PARITY_NONE; - if (args[ARG_parity].u_obj == &busio_uart_parity_even_obj) { + if (args[ARG_parity].u_obj == MP_OBJ_FROM_PTR(&busio_uart_parity_even_obj)) { parity = BUSIO_UART_PARITY_EVEN; - } else if (args[ARG_parity].u_obj == &busio_uart_parity_odd_obj) { + } else if (args[ARG_parity].u_obj == MP_OBJ_FROM_PTR(&busio_uart_parity_odd_obj)) { parity = BUSIO_UART_PARITY_ODD; } @@ -153,7 +153,7 @@ STATIC mp_obj_t busio_uart_make_new(const mp_obj_type_t *type, size_t n_args, si // Helper to ensure we have the native super class instead of a subclass. STATIC busio_uart_obj_t *native_uart(mp_obj_t uart_obj) { - mp_obj_t native_uart = mp_obj_cast_to_native_base(uart_obj, &busio_uart_type); + mp_obj_t native_uart = mp_obj_cast_to_native_base(uart_obj, MP_OBJ_FROM_PTR(&busio_uart_type)); if (native_uart == MP_OBJ_NULL) { mp_raise_ValueError_varg(translate("Must be a %q subclass."), MP_QSTR_UART); } @@ -192,7 +192,7 @@ STATIC void check_for_deinit(busio_uart_obj_t *self) { //| STATIC mp_obj_t busio_uart_obj___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; - common_hal_busio_uart_deinit(args[0]); + common_hal_busio_uart_deinit(MP_OBJ_TO_PTR(args[0])); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_uart___exit___obj, 4, 4, busio_uart_obj___exit__); @@ -394,7 +394,7 @@ STATIC MP_DEFINE_CONST_DICT(busio_uart_parity_locals_dict, busio_uart_parity_loc STATIC void busio_uart_parity_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { qstr parity = MP_QSTR_ODD; - if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&busio_uart_parity_even_obj)) { + if (self_in == MP_ROM_PTR(&busio_uart_parity_even_obj)) { parity = MP_QSTR_EVEN; } mp_printf(print, "%q.%q.%q.%q", MP_QSTR_busio, MP_QSTR_UART, MP_QSTR_Parity, parity); @@ -404,7 +404,7 @@ const mp_obj_type_t busio_uart_parity_type = { { &mp_type_type }, .name = MP_QSTR_Parity, .print = busio_uart_parity_print, - .locals_dict = (mp_obj_t)&busio_uart_parity_locals_dict, + .locals_dict = (mp_obj_dict_t *)&busio_uart_parity_locals_dict, }; STATIC const mp_rom_map_elem_t busio_uart_locals_dict_table[] = { diff --git a/shared-bindings/busio/__init__.c b/shared-bindings/busio/__init__.c index b2397a65cc..13115eb793 100644 --- a/shared-bindings/busio/__init__.c +++ b/shared-bindings/busio/__init__.c @@ -34,7 +34,9 @@ #include "shared-bindings/busio/I2C.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/busio/UART.h" +#if CIRCUITPY_ONEWIREIO #include "shared-bindings/onewireio/OneWire.h" +#endif #include "py/runtime.h" diff --git a/shared-bindings/canio/CAN.c b/shared-bindings/canio/CAN.c index 6a2320c719..ec9c2b8a68 100644 --- a/shared-bindings/canio/CAN.c +++ b/shared-bindings/canio/CAN.c @@ -78,8 +78,8 @@ STATIC mp_obj_t canio_can_make_new(const mp_obj_type_t *type, size_t n_args, siz mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mcu_pin_obj_t *rx_pin = validate_obj_is_free_pin_or_none(args[ARG_rx].u_obj); - mcu_pin_obj_t *tx_pin = validate_obj_is_free_pin_or_none(args[ARG_tx].u_obj); + const mcu_pin_obj_t *rx_pin = validate_obj_is_free_pin_or_none(args[ARG_rx].u_obj); + const mcu_pin_obj_t *tx_pin = validate_obj_is_free_pin_or_none(args[ARG_tx].u_obj); if (!rx_pin && !tx_pin) { mp_raise_ValueError(translate("tx and rx cannot both be None")); } diff --git a/shared-bindings/canio/CAN.h b/shared-bindings/canio/CAN.h index 968b71f14c..b25d2fd68b 100644 --- a/shared-bindings/canio/CAN.h +++ b/shared-bindings/canio/CAN.h @@ -35,7 +35,7 @@ extern const mp_obj_type_t canio_can_type; typedef struct canio_can_obj canio_can_obj_t; -void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *tx, mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent); +void common_hal_canio_can_construct(canio_can_obj_t *self, const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent); bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self); bool common_hal_canio_can_deinited(canio_can_obj_t *self); int common_hal_canio_can_baudrate_get(canio_can_obj_t *self); diff --git a/shared-bindings/digitalio/DigitalInOut.c b/shared-bindings/digitalio/DigitalInOut.c index ff5c494ea8..cabf500d53 100644 --- a/shared-bindings/digitalio/DigitalInOut.c +++ b/shared-bindings/digitalio/DigitalInOut.c @@ -65,7 +65,7 @@ STATIC mp_obj_t digitalio_digitalinout_make_new(const mp_obj_type_t *type, digitalio_digitalinout_obj_t *self = m_new_obj(digitalio_digitalinout_obj_t); self->base.type = &digitalio_digitalinout_type; - mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[0]); + const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[0]); common_hal_digitalio_digitalinout_construct(self, pin); return MP_OBJ_FROM_PTR(self); @@ -95,7 +95,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(digitalio_digitalinout_deinit_obj, digitalio_digitalin //| STATIC mp_obj_t digitalio_digitalinout_obj___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; - common_hal_digitalio_digitalinout_deinit(args[0]); + common_hal_digitalio_digitalinout_deinit(MP_OBJ_TO_PTR(args[0])); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(digitalio_digitalinout_obj___exit___obj, 4, 4, digitalio_digitalinout_obj___exit__); @@ -119,7 +119,7 @@ STATIC mp_obj_t digitalio_digitalinout_switch_to_output(size_t n_args, const mp_ enum { ARG_value, ARG_drive_mode }; static const mp_arg_t allowed_args[] = { { MP_QSTR_value, MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_drive_mode, MP_ARG_OBJ, {.u_rom_obj = &digitalio_drive_mode_push_pull_obj} }, + { MP_QSTR_drive_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&digitalio_drive_mode_push_pull_obj)} }, }; digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); check_for_deinit(self); @@ -127,7 +127,7 @@ STATIC mp_obj_t digitalio_digitalinout_switch_to_output(size_t n_args, const mp_ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); digitalio_drive_mode_t drive_mode = DRIVE_MODE_PUSH_PULL; - if (args[ARG_drive_mode].u_rom_obj == &digitalio_drive_mode_open_drain_obj) { + if (args[ARG_drive_mode].u_rom_obj == MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj)) { drive_mode = DRIVE_MODE_OPEN_DRAIN; } // do the transfer @@ -168,9 +168,9 @@ STATIC mp_obj_t digitalio_digitalinout_switch_to_input(size_t n_args, const mp_o digitalio_pull_t pull = PULL_NONE; - if (args[ARG_pull].u_rom_obj == &digitalio_pull_up_obj) { + if (args[ARG_pull].u_rom_obj == MP_ROM_PTR(&digitalio_pull_up_obj)) { pull = PULL_UP; - } else if (args[ARG_pull].u_rom_obj == &digitalio_pull_down_obj) { + } else if (args[ARG_pull].u_rom_obj == MP_ROM_PTR(&digitalio_pull_down_obj)) { pull = PULL_DOWN; } // do the transfer @@ -207,9 +207,9 @@ MP_DEFINE_CONST_FUN_OBJ_1(digitalio_digitalinout_get_direction_obj, digitalio_di STATIC mp_obj_t digitalio_digitalinout_obj_set_direction(mp_obj_t self_in, mp_obj_t value) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - if (value == &digitalio_direction_input_obj) { + if (value == MP_ROM_PTR(&digitalio_direction_input_obj)) { common_hal_digitalio_digitalinout_switch_to_input(self, PULL_NONE); - } else if (value == &digitalio_direction_output_obj) { + } else if (value == MP_ROM_PTR(&digitalio_direction_output_obj)) { digitalinout_result_t result = common_hal_digitalio_digitalinout_switch_to_output(self, false, DRIVE_MODE_PUSH_PULL); if (result == DIGITALINOUT_INPUT_ONLY) { mp_raise_NotImplementedError(translate("Pin is input only")); @@ -287,7 +287,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_set_drive_mode(mp_obj_t self_in, mp_o return mp_const_none; } digitalio_drive_mode_t c_drive_mode = DRIVE_MODE_PUSH_PULL; - if (drive_mode == &digitalio_drive_mode_open_drain_obj) { + if (drive_mode == MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj)) { c_drive_mode = DRIVE_MODE_OPEN_DRAIN; } common_hal_digitalio_digitalinout_set_drive_mode(self, c_drive_mode); @@ -336,9 +336,9 @@ STATIC mp_obj_t digitalio_digitalinout_obj_set_pull(mp_obj_t self_in, mp_obj_t p return mp_const_none; } digitalio_pull_t pull = PULL_NONE; - if (pull_obj == &digitalio_pull_up_obj) { + if (pull_obj == MP_ROM_PTR(&digitalio_pull_up_obj)) { pull = PULL_UP; - } else if (pull_obj == &digitalio_pull_down_obj) { + } else if (pull_obj == MP_ROM_PTR(&digitalio_pull_down_obj)) { pull = PULL_DOWN; } else if (pull_obj != mp_const_none) { mp_raise_ValueError(translate("Unsupported pull value.")); @@ -376,7 +376,7 @@ const mp_obj_type_t digitalio_digitalinout_type = { { &mp_type_type }, .name = MP_QSTR_DigitalInOut, .make_new = digitalio_digitalinout_make_new, - .locals_dict = (mp_obj_t)&digitalio_digitalinout_locals_dict, + .locals_dict = (mp_obj_dict_t *)&digitalio_digitalinout_locals_dict, }; // Helper for validating digitalio.DigitalInOut arguments diff --git a/shared-bindings/digitalio/Direction.c b/shared-bindings/digitalio/Direction.c index e7ebd0cfcc..0ed18f8edc 100644 --- a/shared-bindings/digitalio/Direction.c +++ b/shared-bindings/digitalio/Direction.c @@ -70,7 +70,7 @@ STATIC MP_DEFINE_CONST_DICT(digitalio_direction_locals_dict, digitalio_direction STATIC void digitalio_direction_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { qstr direction = MP_QSTR_INPUT; - if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&digitalio_direction_output_obj)) { + if (self_in == MP_ROM_PTR(&digitalio_direction_output_obj)) { direction = MP_QSTR_OUTPUT; } mp_printf(print, "%q.%q.%q", MP_QSTR_digitalio, MP_QSTR_Direction, direction); @@ -80,5 +80,5 @@ const mp_obj_type_t digitalio_direction_type = { { &mp_type_type }, .name = MP_QSTR_Direction, .print = digitalio_direction_print, - .locals_dict = (mp_obj_t)&digitalio_direction_locals_dict, + .locals_dict = (mp_obj_dict_t *)&digitalio_direction_locals_dict, }; diff --git a/shared-bindings/digitalio/DriveMode.c b/shared-bindings/digitalio/DriveMode.c index 39b940d7f9..c7c3400411 100644 --- a/shared-bindings/digitalio/DriveMode.c +++ b/shared-bindings/digitalio/DriveMode.c @@ -59,7 +59,7 @@ STATIC MP_DEFINE_CONST_DICT(digitalio_drive_mode_locals_dict, digitalio_drive_mo STATIC void digitalio_drive_mode_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { qstr drive_mode = MP_QSTR_PUSH_PULL; - if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj)) { + if (self_in == MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj)) { drive_mode = MP_QSTR_OPEN_DRAIN; } mp_printf(print, "%q.%q.%q", MP_QSTR_digitalio, MP_QSTR_DriveMode, drive_mode); @@ -69,5 +69,5 @@ const mp_obj_type_t digitalio_drive_mode_type = { { &mp_type_type }, .name = MP_QSTR_DriveMode, .print = digitalio_drive_mode_print, - .locals_dict = (mp_obj_t)&digitalio_drive_mode_locals_dict, + .locals_dict = (mp_obj_dict_t *)&digitalio_drive_mode_locals_dict, }; diff --git a/shared-bindings/digitalio/Pull.c b/shared-bindings/digitalio/Pull.c index ed08b0f6bc..8ded64fb47 100644 --- a/shared-bindings/digitalio/Pull.c +++ b/shared-bindings/digitalio/Pull.c @@ -60,7 +60,7 @@ STATIC MP_DEFINE_CONST_DICT(digitalio_pull_locals_dict, digitalio_pull_locals_di STATIC void digitalio_pull_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { qstr pull = MP_QSTR_UP; - if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&digitalio_pull_down_obj)) { + if (self_in == MP_ROM_PTR(&digitalio_pull_down_obj)) { pull = MP_QSTR_DOWN; } mp_printf(print, "%q.%q.%q", MP_QSTR_digitalio, MP_QSTR_Pull, pull); @@ -70,5 +70,5 @@ const mp_obj_type_t digitalio_pull_type = { { &mp_type_type }, .name = MP_QSTR_Pull, .print = digitalio_pull_print, - .locals_dict = (mp_obj_t)&digitalio_pull_locals_dict, + .locals_dict = (mp_obj_dict_t *)&digitalio_pull_locals_dict, }; diff --git a/shared-bindings/displayio/FourWire.c b/shared-bindings/displayio/FourWire.c index 801b988a8a..ead9e418dc 100644 --- a/shared-bindings/displayio/FourWire.c +++ b/shared-bindings/displayio/FourWire.c @@ -75,9 +75,9 @@ STATIC mp_obj_t displayio_fourwire_make_new(const mp_obj_type_t *type, size_t n_ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mcu_pin_obj_t *command = validate_obj_is_free_pin(args[ARG_command].u_obj); - mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj); - mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj); + const mcu_pin_obj_t *command = validate_obj_is_free_pin(args[ARG_command].u_obj); + const mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj); + const mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj); mp_obj_t spi = mp_arg_validate_type(args[ARG_spi_bus].u_obj, &busio_spi_type, MP_QSTR_spi_bus); diff --git a/shared-bindings/displayio/I2CDisplay.c b/shared-bindings/displayio/I2CDisplay.c index d87b5f8bb0..fbfbd04c64 100644 --- a/shared-bindings/displayio/I2CDisplay.c +++ b/shared-bindings/displayio/I2CDisplay.c @@ -66,7 +66,7 @@ STATIC mp_obj_t displayio_i2cdisplay_make_new(const mp_obj_type_t *type, size_t mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj); + const mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj); mp_obj_t i2c = mp_arg_validate_type(args[ARG_i2c_bus].u_obj, &busio_i2c_type, MP_QSTR_i2c_bus); displayio_i2cdisplay_obj_t *self = &allocate_display_bus_or_raise()->i2cdisplay_bus; diff --git a/shared-bindings/frequencyio/FrequencyIn.c b/shared-bindings/frequencyio/FrequencyIn.c index f8ab1b955e..a59d7a7302 100644 --- a/shared-bindings/frequencyio/FrequencyIn.c +++ b/shared-bindings/frequencyio/FrequencyIn.c @@ -84,7 +84,7 @@ STATIC mp_obj_t frequencyio_frequencyin_make_new(const mp_obj_type_t *type, size mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj); + const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj); const uint16_t capture_period = args[ARG_capture_period].u_int; diff --git a/shared-bindings/imagecapture/ParallelImageCapture.c b/shared-bindings/imagecapture/ParallelImageCapture.c index a98c72e208..7f90f0923b 100644 --- a/shared-bindings/imagecapture/ParallelImageCapture.c +++ b/shared-bindings/imagecapture/ParallelImageCapture.c @@ -71,9 +71,9 @@ STATIC mp_obj_t imagecapture_parallelimagecapture_make_new(const mp_obj_type_t * uint8_t pin_count; validate_pins(MP_QSTR_data, pins, MP_ARRAY_SIZE(pins), args[ARG_data_pins].u_obj, &pin_count); - mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj); - mcu_pin_obj_t *vsync = validate_obj_is_free_pin_or_none(args[ARG_vsync].u_obj); - mcu_pin_obj_t *href = validate_obj_is_free_pin_or_none(args[ARG_href].u_obj); + const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj); + const mcu_pin_obj_t *vsync = validate_obj_is_free_pin_or_none(args[ARG_vsync].u_obj); + const mcu_pin_obj_t *href = validate_obj_is_free_pin_or_none(args[ARG_href].u_obj); imagecapture_parallelimagecapture_obj_t *self = m_new_obj(imagecapture_parallelimagecapture_obj_t); self->base.type = &imagecapture_parallelimagecapture_type; diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c index 61462464c5..486fa0b9b5 100644 --- a/shared-bindings/keypad/KeyMatrix.c +++ b/shared-bindings/keypad/KeyMatrix.c @@ -87,19 +87,19 @@ STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_ar mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval); const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events); - mcu_pin_obj_t *row_pins_array[num_row_pins]; - mcu_pin_obj_t *column_pins_array[num_column_pins]; + const mcu_pin_obj_t *row_pins_array[num_row_pins]; + const mcu_pin_obj_t *column_pins_array[num_column_pins]; validate_no_duplicate_pins_2(row_pins, column_pins, MP_QSTR_row_pins, MP_QSTR_column_pins); for (size_t row = 0; row < num_row_pins; row++) { - mcu_pin_obj_t *pin = + const mcu_pin_obj_t *pin = validate_obj_is_free_pin(mp_obj_subscr(row_pins, MP_OBJ_NEW_SMALL_INT(row), MP_OBJ_SENTINEL)); row_pins_array[row] = pin; } for (size_t column = 0; column < num_column_pins; column++) { - mcu_pin_obj_t *pin = + const mcu_pin_obj_t *pin = validate_obj_is_free_pin(mp_obj_subscr(column_pins, MP_OBJ_NEW_SMALL_INT(column), MP_OBJ_SENTINEL)); column_pins_array[column] = pin; } diff --git a/shared-bindings/keypad/KeyMatrix.h b/shared-bindings/keypad/KeyMatrix.h index 7ebe1af5b7..29a94fbf66 100644 --- a/shared-bindings/keypad/KeyMatrix.h +++ b/shared-bindings/keypad/KeyMatrix.h @@ -32,7 +32,7 @@ extern const mp_obj_type_t keypad_keymatrix_type; -void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_column_pins, mcu_pin_obj_t *column_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events); +void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, const mcu_pin_obj_t *row_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events); void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self); bool common_hal_keypad_keymatrix_deinited(keypad_keymatrix_obj_t *self); diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index 47a906a144..2da55bccba 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -87,12 +87,11 @@ STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, s mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval); const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events); - mcu_pin_obj_t *pins_array[num_pins]; + const mcu_pin_obj_t *pins_array[num_pins]; for (mp_uint_t i = 0; i < num_pins; i++) { - mcu_pin_obj_t *pin = + pins_array[i] = validate_obj_is_free_pin(mp_obj_subscr(pins, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL)); - pins_array[i] = pin; } common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool, interval, max_events); diff --git a/shared-bindings/keypad/Keys.h b/shared-bindings/keypad/Keys.h index 094220e588..89da18189a 100644 --- a/shared-bindings/keypad/Keys.h +++ b/shared-bindings/keypad/Keys.h @@ -32,7 +32,7 @@ extern const mp_obj_type_t keypad_keys_type; -void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, mp_float_t interval, size_t max_events); +void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, const mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, mp_float_t interval, size_t max_events); void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self); bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self); diff --git a/shared-bindings/keypad/ShiftRegisterKeys.c b/shared-bindings/keypad/ShiftRegisterKeys.c index 0cc5e6889b..0032a45438 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.c +++ b/shared-bindings/keypad/ShiftRegisterKeys.c @@ -86,9 +86,9 @@ STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, siz mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj); - mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj); - mcu_pin_obj_t *latch = validate_obj_is_free_pin(args[ARG_latch].u_obj); + const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj); + const mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj); + const mcu_pin_obj_t *latch = validate_obj_is_free_pin(args[ARG_latch].u_obj); const bool value_to_latch = args[ARG_value_to_latch].u_bool; const size_t key_count = (size_t)mp_arg_validate_int_min(args[ARG_key_count].u_int, 1, MP_QSTR_key_count); diff --git a/shared-bindings/keypad/ShiftRegisterKeys.h b/shared-bindings/keypad/ShiftRegisterKeys.h index f1432f1069..62ab14d340 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.h +++ b/shared-bindings/keypad/ShiftRegisterKeys.h @@ -32,7 +32,7 @@ extern const mp_obj_type_t keypad_shiftregisterkeys_type; -void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t key_count, bool value_when_pressed, mp_float_t interval, size_t max_events); +void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, const mcu_pin_obj_t *clock_pin, const mcu_pin_obj_t *data_pin, const mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t key_count, bool value_when_pressed, mp_float_t interval, size_t max_events); void common_hal_keypad_shiftregisterkeys_deinit(keypad_shiftregisterkeys_obj_t *self); bool common_hal_keypad_shiftregisterkeys_deinited(keypad_shiftregisterkeys_obj_t *self); diff --git a/shared-bindings/microcontroller/Pin.c b/shared-bindings/microcontroller/Pin.c index 78c1c90f4d..ee8336fa8a 100644 --- a/shared-bindings/microcontroller/Pin.c +++ b/shared-bindings/microcontroller/Pin.c @@ -46,7 +46,7 @@ static void get_pin_name(const mcu_pin_obj_t *self, qstr *package, qstr *module, qstr *name) { const mp_map_t *board_map = &board_module_globals.map; for (uint8_t i = 0; i < board_map->alloc; i++) { - if (board_map->table[i].value == self) { + if (board_map->table[i].value == MP_OBJ_FROM_PTR(self)) { *package = 0; *module = MP_QSTR_board; *name = MP_OBJ_QSTR_VALUE(board_map->table[i].key); @@ -55,7 +55,7 @@ static void get_pin_name(const mcu_pin_obj_t *self, qstr *package, qstr *module, } const mp_map_t *mcu_map = &mcu_pin_globals.map; for (uint8_t i = 0; i < mcu_map->alloc; i++) { - if (mcu_map->table[i].value == self) { + if (mcu_map->table[i].value == MP_OBJ_FROM_PTR(self)) { *package = MP_QSTR_microcontroller; *module = MP_QSTR_pin; *name = MP_OBJ_QSTR_VALUE(mcu_map->table[i].key); @@ -84,7 +84,7 @@ const mp_obj_type_t mcu_pin_type = { .print = mcu_pin_print }; -mcu_pin_obj_t *validate_obj_is_pin(mp_obj_t obj) { +const mcu_pin_obj_t *validate_obj_is_pin(mp_obj_t obj) { if (!mp_obj_is_type(obj, &mcu_pin_type)) { mp_raise_TypeError_varg(translate("Expected a %q"), mcu_pin_type.name); } @@ -92,15 +92,15 @@ mcu_pin_obj_t *validate_obj_is_pin(mp_obj_t obj) { } // Validate that the obj is a pin or None. Return an mcu_pin_obj_t* or NULL, correspondingly. -mcu_pin_obj_t *validate_obj_is_pin_or_none(mp_obj_t obj) { +const mcu_pin_obj_t *validate_obj_is_pin_or_none(mp_obj_t obj) { if (obj == mp_const_none) { return NULL; } return validate_obj_is_pin(obj); } -mcu_pin_obj_t *validate_obj_is_free_pin(mp_obj_t obj) { - mcu_pin_obj_t *pin = validate_obj_is_pin(obj); +const mcu_pin_obj_t *validate_obj_is_free_pin(mp_obj_t obj) { + const mcu_pin_obj_t *pin = validate_obj_is_pin(obj); assert_pin_free(pin); return pin; } @@ -111,11 +111,11 @@ void validate_no_duplicate_pins(mp_obj_t seq, qstr arg_name) { for (size_t pin_cnt = 0; pin_cnt < num_pins; pin_cnt++) { mp_obj_t pin1_obj = mp_obj_subscr(seq, MP_OBJ_NEW_SMALL_INT(pin_cnt), MP_OBJ_SENTINEL); - mcu_pin_obj_t *pin1 = validate_obj_is_pin(pin1_obj); + const mcu_pin_obj_t *pin1 = validate_obj_is_pin(pin1_obj); for (size_t pin_cnt_2 = pin_cnt + 1; pin_cnt_2 < num_pins; pin_cnt_2++) { mp_obj_t pin2_obj = mp_obj_subscr(seq, MP_OBJ_NEW_SMALL_INT(pin_cnt_2), MP_OBJ_SENTINEL); - mcu_pin_obj_t *pin2 = validate_obj_is_pin(pin2_obj); + const mcu_pin_obj_t *pin2 = validate_obj_is_pin(pin2_obj); if (pin1 == pin2) { mp_raise_TypeError_varg(translate("%q contains duplicate pins"), arg_name); } @@ -132,11 +132,11 @@ void validate_no_duplicate_pins_2(mp_obj_t seq1, mp_obj_t seq2, qstr arg_name1, for (size_t pin_cnt_1 = 0; pin_cnt_1 < num_pins_1; pin_cnt_1++) { mp_obj_t pin1_obj = mp_obj_subscr(seq1, MP_OBJ_NEW_SMALL_INT(pin_cnt_1), MP_OBJ_SENTINEL); - mcu_pin_obj_t *pin1 = validate_obj_is_pin(pin1_obj); + const mcu_pin_obj_t *pin1 = validate_obj_is_pin(pin1_obj); for (size_t pin_cnt_2 = 0; pin_cnt_2 < num_pins_2; pin_cnt_2++) { mp_obj_t pin2_obj = mp_obj_subscr(seq2, MP_OBJ_NEW_SMALL_INT(pin_cnt_2), MP_OBJ_SENTINEL); - mcu_pin_obj_t *pin2 = validate_obj_is_pin(pin2_obj); + const mcu_pin_obj_t *pin2 = validate_obj_is_pin(pin2_obj); if (pin1 == pin2) { mp_raise_TypeError_varg(translate("%q and %q contain duplicate pins"), arg_name1, arg_name2); } @@ -145,7 +145,7 @@ void validate_no_duplicate_pins_2(mp_obj_t seq1, mp_obj_t seq2, qstr arg_name1, } // Validate every element in the list to be a free pin. -void validate_list_is_free_pins(qstr what, mcu_pin_obj_t **pins_out, mp_int_t max_pins, mp_obj_t seq, uint8_t *count_out) { +void validate_list_is_free_pins(qstr what, const mcu_pin_obj_t **pins_out, mp_int_t max_pins, mp_obj_t seq, uint8_t *count_out) { mp_int_t len = MP_OBJ_SMALL_INT_VALUE(mp_obj_len(seq)); if (len > max_pins) { mp_raise_ValueError_varg(translate("At most %d %q may be specified (not %d)"), max_pins, what, len); @@ -157,11 +157,11 @@ void validate_list_is_free_pins(qstr what, mcu_pin_obj_t **pins_out, mp_int_t ma } // Validate that the obj is a free pin or None. Return an mcu_pin_obj_t* or NULL, correspondingly. -mcu_pin_obj_t *validate_obj_is_free_pin_or_none(mp_obj_t obj) { +const mcu_pin_obj_t *validate_obj_is_free_pin_or_none(mp_obj_t obj) { if (obj == mp_const_none) { return NULL; } - mcu_pin_obj_t *pin = validate_obj_is_pin(obj); + const mcu_pin_obj_t *pin = validate_obj_is_pin(obj); assert_pin_free(pin); return pin; } @@ -178,7 +178,7 @@ void assert_pin_free(const mcu_pin_obj_t *pin) { } void validate_pins(qstr what, uint8_t *pin_nos, mp_int_t max_pins, mp_obj_t seq, uint8_t *count_out) { - mcu_pin_obj_t *pins[max_pins]; + const mcu_pin_obj_t *pins[max_pins]; validate_list_is_free_pins(what, pins, max_pins, seq, count_out); for (mp_int_t i = 0; i < *count_out; i++) { pin_nos[i] = common_hal_mcu_pin_number(pins[i]); diff --git a/shared-bindings/microcontroller/Pin.h b/shared-bindings/microcontroller/Pin.h index a8ac6eeb1c..a7378ea98e 100644 --- a/shared-bindings/microcontroller/Pin.h +++ b/shared-bindings/microcontroller/Pin.h @@ -33,13 +33,13 @@ // Type object used in Python. Should be shared between ports. extern const mp_obj_type_t mcu_pin_type; -mcu_pin_obj_t *validate_obj_is_pin(mp_obj_t obj); -mcu_pin_obj_t *validate_obj_is_pin_or_none(mp_obj_t obj); -mcu_pin_obj_t *validate_obj_is_free_pin(mp_obj_t obj); -mcu_pin_obj_t *validate_obj_is_free_pin_or_none(mp_obj_t obj); +const mcu_pin_obj_t *validate_obj_is_pin(mp_obj_t obj); +const mcu_pin_obj_t *validate_obj_is_pin_or_none(mp_obj_t obj); +const mcu_pin_obj_t *validate_obj_is_free_pin(mp_obj_t obj); +const mcu_pin_obj_t *validate_obj_is_free_pin_or_none(mp_obj_t obj); void validate_no_duplicate_pins(mp_obj_t seq, qstr arg_name); void validate_no_duplicate_pins_2(mp_obj_t seq1, mp_obj_t seq2, qstr arg_name1, qstr arg_name2); -void validate_list_is_free_pins(qstr what, mcu_pin_obj_t **pins_out, mp_int_t max_pins, mp_obj_t seq, uint8_t *count_out); +void validate_list_is_free_pins(qstr what, const mcu_pin_obj_t **pins_out, mp_int_t max_pins, mp_obj_t seq, uint8_t *count_out); void validate_pins(qstr what, uint8_t *pin_nos, mp_int_t max_pins, mp_obj_t seq, uint8_t *count_out); void assert_pin_free(const mcu_pin_obj_t *pin); diff --git a/shared-bindings/microcontroller/Processor.c b/shared-bindings/microcontroller/Processor.c index e1d569efca..dfcafcd324 100644 --- a/shared-bindings/microcontroller/Processor.c +++ b/shared-bindings/microcontroller/Processor.c @@ -164,5 +164,5 @@ STATIC MP_DEFINE_CONST_DICT(mcu_processor_locals_dict, mcu_processor_locals_dict const mp_obj_type_t mcu_processor_type = { { &mp_type_type }, .name = MP_QSTR_Processor, - .locals_dict = (mp_obj_t)&mcu_processor_locals_dict, + .locals_dict = (mp_obj_dict_t *)&mcu_processor_locals_dict, }; diff --git a/shared-bindings/microcontroller/RunMode.c b/shared-bindings/microcontroller/RunMode.c index e3743090ec..477168dda0 100644 --- a/shared-bindings/microcontroller/RunMode.c +++ b/shared-bindings/microcontroller/RunMode.c @@ -82,11 +82,11 @@ STATIC MP_DEFINE_CONST_DICT(mcu_runmode_locals_dict, mcu_runmode_locals_dict_tab STATIC void mcu_runmode_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { qstr runmode = MP_QSTR_NORMAL; - if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&mcu_runmode_uf2_obj)) { + if (self_in == MP_ROM_PTR(&mcu_runmode_uf2_obj)) { runmode = MP_QSTR_UF2; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&mcu_runmode_safe_mode_obj)) { + } else if (self_in == MP_ROM_PTR(&mcu_runmode_safe_mode_obj)) { runmode = MP_QSTR_SAFE_MODE; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&mcu_runmode_bootloader_obj)) { + } else if (self_in == MP_ROM_PTR(&mcu_runmode_bootloader_obj)) { runmode = MP_QSTR_BOOTLOADER; } mp_printf(print, "%q.%q.%q", MP_QSTR_microcontroller, MP_QSTR_RunMode, @@ -97,5 +97,5 @@ const mp_obj_type_t mcu_runmode_type = { { &mp_type_type }, .name = MP_QSTR_RunMode, .print = mcu_runmode_print, - .locals_dict = (mp_obj_t)&mcu_runmode_locals_dict, + .locals_dict = (mp_obj_dict_t *)&mcu_runmode_locals_dict, }; diff --git a/shared-bindings/microcontroller/__init__.c b/shared-bindings/microcontroller/__init__.c index ad77eb6536..ceba9be1ba 100644 --- a/shared-bindings/microcontroller/__init__.c +++ b/shared-bindings/microcontroller/__init__.c @@ -109,13 +109,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_enable_interrupts_obj, mcu_enable_interrupt //| STATIC mp_obj_t mcu_on_next_reset(mp_obj_t run_mode_obj) { mcu_runmode_t run_mode; - if (run_mode_obj == &mcu_runmode_uf2_obj) { + if (run_mode_obj == MP_OBJ_FROM_PTR(&mcu_runmode_uf2_obj)) { run_mode = RUNMODE_UF2; - } else if (run_mode_obj == &mcu_runmode_normal_obj) { + } else if (run_mode_obj == MP_OBJ_FROM_PTR(&mcu_runmode_normal_obj)) { run_mode = RUNMODE_NORMAL; - } else if (run_mode_obj == &mcu_runmode_safe_mode_obj) { + } else if (run_mode_obj == MP_OBJ_FROM_PTR(&mcu_runmode_safe_mode_obj)) { run_mode = RUNMODE_SAFE_MODE; - } else if (run_mode_obj == &mcu_runmode_bootloader_obj) { + } else if (run_mode_obj == MP_OBJ_FROM_PTR(&mcu_runmode_bootloader_obj)) { run_mode = RUNMODE_BOOTLOADER; } else { mp_raise_ValueError(translate("Invalid run mode.")); @@ -169,7 +169,7 @@ STATIC const mp_rom_map_elem_t mcu_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_enable_interrupts), MP_ROM_PTR(&mcu_enable_interrupts_obj) }, { MP_ROM_QSTR(MP_QSTR_on_next_reset), MP_ROM_PTR(&mcu_on_next_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&mcu_reset_obj) }, - #if CIRCUITPY_INTERNAL_NVM_SIZE > 0 + #if CIRCUITPY_NVM && CIRCUITPY_INTERNAL_NVM_SIZE > 0 { MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&common_hal_mcu_nvm_obj) }, #else { MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_NONE }, diff --git a/shared-bindings/microcontroller/__init__.h b/shared-bindings/microcontroller/__init__.h index 733127d561..e41cce84a4 100644 --- a/shared-bindings/microcontroller/__init__.h +++ b/shared-bindings/microcontroller/__init__.h @@ -55,7 +55,7 @@ extern const mp_rom_obj_tuple_t common_hal_multi_processor_obj; #endif -#if CIRCUITPY_INTERNAL_NVM_SIZE > 0 +#if CIRCUITPY_NVM && CIRCUITPY_INTERNAL_NVM_SIZE > 0 #include "common-hal/nvm/ByteArray.h" extern const nvm_bytearray_obj_t common_hal_mcu_nvm_obj; #endif diff --git a/shared-bindings/paralleldisplay/ParallelBus.c b/shared-bindings/paralleldisplay/ParallelBus.c index 782848d9b6..be69ce1f95 100644 --- a/shared-bindings/paralleldisplay/ParallelBus.c +++ b/shared-bindings/paralleldisplay/ParallelBus.c @@ -76,11 +76,11 @@ STATIC mp_obj_t paralleldisplay_parallelbus_make_new(const mp_obj_type_t *type, mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mcu_pin_obj_t *command = validate_obj_is_free_pin(args[ARG_command].u_obj); - mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj); - mcu_pin_obj_t *write = validate_obj_is_free_pin(args[ARG_write].u_obj); - mcu_pin_obj_t *read = validate_obj_is_free_pin(args[ARG_read].u_obj); - mcu_pin_obj_t *reset = validate_obj_is_free_pin(args[ARG_reset].u_obj); + const mcu_pin_obj_t *command = validate_obj_is_free_pin(args[ARG_command].u_obj); + const mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj); + const mcu_pin_obj_t *write = validate_obj_is_free_pin(args[ARG_write].u_obj); + const mcu_pin_obj_t *read = validate_obj_is_free_pin(args[ARG_read].u_obj); + const mcu_pin_obj_t *reset = validate_obj_is_free_pin(args[ARG_reset].u_obj); paralleldisplay_parallelbus_obj_t *self = &allocate_display_bus_or_raise()->parallel_bus; self->base.type = ¶lleldisplay_parallelbus_type; @@ -93,11 +93,11 @@ STATIC mp_obj_t paralleldisplay_parallelbus_make_new(const mp_obj_type_t *type, } if (specified_data0) { - mcu_pin_obj_t *data0 = validate_obj_is_free_pin(args[ARG_data0].u_obj); + const mcu_pin_obj_t *data0 = validate_obj_is_free_pin(args[ARG_data0].u_obj); common_hal_paralleldisplay_parallelbus_construct(self, data0, command, chip_select, write, read, reset, args[ARG_frequency].u_int); } else { uint8_t num_pins; - mcu_pin_obj_t *data_pins[16]; + const mcu_pin_obj_t *data_pins[16]; validate_list_is_free_pins(MP_QSTR_data_pins, data_pins, (mp_int_t)MP_ARRAY_SIZE(data_pins), args[ARG_data_pins].u_obj, &num_pins); common_hal_paralleldisplay_parallelbus_construct_nonsequential(self, num_pins, data_pins, command, chip_select, write, read, reset, args[ARG_frequency].u_int); } diff --git a/shared-bindings/paralleldisplay/ParallelBus.h b/shared-bindings/paralleldisplay/ParallelBus.h index 5c6212a970..e890683934 100644 --- a/shared-bindings/paralleldisplay/ParallelBus.h +++ b/shared-bindings/paralleldisplay/ParallelBus.h @@ -39,7 +39,7 @@ void common_hal_paralleldisplay_parallelbus_construct(paralleldisplay_parallelbu const mcu_pin_obj_t *write, const mcu_pin_obj_t *read, const mcu_pin_obj_t *reset, uint32_t frequency); void common_hal_paralleldisplay_parallelbus_construct_nonsequential(paralleldisplay_parallelbus_obj_t *self, - uint8_t n_pins, mcu_pin_obj_t **data_pins, const mcu_pin_obj_t *command, const mcu_pin_obj_t *chip_select, + uint8_t n_pins, const mcu_pin_obj_t **data_pins, const mcu_pin_obj_t *command, const mcu_pin_obj_t *chip_select, const mcu_pin_obj_t *write, const mcu_pin_obj_t *read, const mcu_pin_obj_t *reset, uint32_t frequency); void common_hal_paralleldisplay_parallelbus_deinit(paralleldisplay_parallelbus_obj_t *self); diff --git a/shared-bindings/rgbmatrix/RGBMatrix.c b/shared-bindings/rgbmatrix/RGBMatrix.c index 12fd1e15cc..70d6328ab0 100644 --- a/shared-bindings/rgbmatrix/RGBMatrix.c +++ b/shared-bindings/rgbmatrix/RGBMatrix.c @@ -45,7 +45,7 @@ extern Protomatter_core *_PM_protoPtr; STATIC uint8_t validate_pin(mp_obj_t obj) { - mcu_pin_obj_t *result = validate_obj_is_free_pin(obj); + const mcu_pin_obj_t *result = validate_obj_is_free_pin(obj); return common_hal_mcu_pin_number(result); } @@ -132,7 +132,15 @@ STATIC void preflight_pins_or_throw(uint8_t clock_pin, uint8_t *rgb_pins, uint8_ } } -//| def __init__(self, *, width: int, bit_depth: int, rgb_pins: Sequence[digitalio.DigitalInOut], addr_pins: Sequence[digitalio.DigitalInOut], clock_pin: digitalio.DigitalInOut, latch_pin: digitalio.DigitalInOut, output_enable_pin: digitalio.DigitalInOut, doublebuffer: bool = True, framebuffer: Optional[WriteableBuffer] = None, height: int = 0, tile: int = 1, serpentine: bool = True) -> None: +//| def __init__(self, *, width: int, bit_depth: int, +//| rgb_pins: Sequence[digitalio.DigitalInOut], +//| addr_pins: Sequence[digitalio.DigitalInOut], +//| clock_pin: digitalio.DigitalInOut, +//| latch_pin: digitalio.DigitalInOut, +//| output_enable_pin: digitalio.DigitalInOut, +//| doublebuffer: bool = True, +//| framebuffer: Optional[WriteableBuffer] = None, +//| height: int = 0, tile: int = 1, serpentine: bool = True) -> None: //| """Create a RGBMatrix object with the given attributes. The height of //| the display is determined by the number of rgb and address pins and the number of tiles: //| ``len(rgb_pins) // 3 * 2 ** len(address_pins) * abs(tile)``. With 6 RGB pins, 4 diff --git a/shared-bindings/sdcardio/SDCard.c b/shared-bindings/sdcardio/SDCard.c index 757a1b8532..fe487ae7fb 100644 --- a/shared-bindings/sdcardio/SDCard.c +++ b/shared-bindings/sdcardio/SDCard.c @@ -88,7 +88,7 @@ STATIC mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_arg mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi].u_obj); - mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj); + const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj); sdcardio_sdcard_obj_t *self = m_new_obj(sdcardio_sdcard_obj_t); self->base.type = &sdcardio_SDCard_type; diff --git a/shared-bindings/sdioio/SDCard.c b/shared-bindings/sdioio/SDCard.c index ba45af4576..6fd38ce24c 100644 --- a/shared-bindings/sdioio/SDCard.c +++ b/shared-bindings/sdioio/SDCard.c @@ -95,7 +95,7 @@ STATIC mp_obj_t sdioio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj); const mcu_pin_obj_t *command = validate_obj_is_free_pin(args[ARG_command].u_obj); - mcu_pin_obj_t *data_pins[4]; + const mcu_pin_obj_t *data_pins[4]; uint8_t num_data; validate_list_is_free_pins(MP_QSTR_data, data_pins, MP_ARRAY_SIZE(data_pins), args[ARG_data].u_obj, &num_data); diff --git a/shared-bindings/sdioio/SDCard.h b/shared-bindings/sdioio/SDCard.h index cd302f4de7..cf1576262c 100644 --- a/shared-bindings/sdioio/SDCard.h +++ b/shared-bindings/sdioio/SDCard.h @@ -38,7 +38,7 @@ extern const mp_obj_type_t sdioio_SDCard_type; // Construct an underlying SDIO object. extern void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *command, - uint8_t num_data, mcu_pin_obj_t **data, uint32_t frequency); + uint8_t num_data, const mcu_pin_obj_t **data, uint32_t frequency); extern void common_hal_sdioio_sdcard_deinit(sdioio_sdcard_obj_t *self); extern bool common_hal_sdioio_sdcard_deinited(sdioio_sdcard_obj_t *self); diff --git a/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c b/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c index 8e9050d018..35e06b7838 100644 --- a/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c +++ b/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c @@ -47,7 +47,7 @@ STATIC mp_obj_t sharpdisplay_framebuffer_make_new(const mp_obj_type_t *type, siz mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj); + const mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj); busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi_bus].u_obj); sharpdisplay_framebuffer_obj_t *self = &allocate_display_bus_or_raise()->sharpdisplay; diff --git a/shared-bindings/supervisor/Runtime.c b/shared-bindings/supervisor/Runtime.c index 262346bad2..1ed11a2ec5 100644 --- a/shared-bindings/supervisor/Runtime.c +++ b/shared-bindings/supervisor/Runtime.c @@ -139,5 +139,5 @@ STATIC MP_DEFINE_CONST_DICT(supervisor_runtime_locals_dict, supervisor_runtime_l const mp_obj_type_t supervisor_runtime_type = { .base = { &mp_type_type }, .name = MP_QSTR_Runtime, - .locals_dict = (mp_obj_t)&supervisor_runtime_locals_dict, + .locals_dict = (mp_obj_dict_t *)&supervisor_runtime_locals_dict, }; diff --git a/shared-module/displayio/Bitmap.c b/shared-module/displayio/Bitmap.c index a18ba7a48a..933d3a8227 100644 --- a/shared-module/displayio/Bitmap.c +++ b/shared-module/displayio/Bitmap.c @@ -33,8 +33,8 @@ void common_hal_displayio_bitmap_construct(displayio_bitmap_t *self, uint32_t width, uint32_t height, uint32_t bits_per_value) { uint32_t row_width = width * bits_per_value; - // align to size_t - uint8_t align_bits = 8 * sizeof(size_t); + // align to uint32_t + uint8_t align_bits = 8 * sizeof(uint32_t); if (row_width % align_bits != 0) { self->stride = (row_width / align_bits + 1); } else { @@ -42,7 +42,7 @@ void common_hal_displayio_bitmap_construct(displayio_bitmap_t *self, uint32_t wi } self->width = width; self->height = height; - self->data = m_malloc(self->stride * height * sizeof(size_t), false); + self->data = m_malloc(self->stride * height * sizeof(uint32_t), false); self->read_only = false; self->bits_per_value = bits_per_value; @@ -89,11 +89,11 @@ uint32_t common_hal_displayio_bitmap_get_pixel(displayio_bitmap_t *self, int16_t int32_t row_start = y * self->stride; uint32_t bytes_per_value = self->bits_per_value / 8; if (bytes_per_value < 1) { - size_t word = self->data[row_start + (x >> self->x_shift)]; + uint32_t word = self->data[row_start + (x >> self->x_shift)]; - return (word >> (sizeof(size_t) * 8 - ((x & self->x_mask) + 1) * self->bits_per_value)) & self->bitmask; + return (word >> (sizeof(uint32_t) * 8 - ((x & self->x_mask) + 1) * self->bits_per_value)) & self->bitmask; } else { - size_t *row = self->data + row_start; + uint32_t *row = self->data + row_start; if (bytes_per_value == 1) { return ((uint8_t *)row)[x]; } else if (bytes_per_value == 2) { @@ -125,14 +125,14 @@ void displayio_bitmap_write_pixel(displayio_bitmap_t *self, int16_t x, int16_t y int32_t row_start = y * self->stride; uint32_t bytes_per_value = self->bits_per_value / 8; if (bytes_per_value < 1) { - uint32_t bit_position = (sizeof(size_t) * 8 - ((x & self->x_mask) + 1) * self->bits_per_value); + uint32_t bit_position = (sizeof(uint32_t) * 8 - ((x & self->x_mask) + 1) * self->bits_per_value); uint32_t index = row_start + (x >> self->x_shift); uint32_t word = self->data[index]; word &= ~(self->bitmask << bit_position); word |= (value & self->bitmask) << bit_position; self->data[index] = word; } else { - size_t *row = self->data + row_start; + uint32_t *row = self->data + row_start; if (bytes_per_value == 1) { ((uint8_t *)row)[x] = value; } else if (bytes_per_value == 2) { @@ -239,7 +239,7 @@ int common_hal_displayio_bitmap_get_buffer(displayio_bitmap_t *self, mp_buffer_i if ((flags & MP_BUFFER_WRITE) && self->read_only) { return 1; } - bufinfo->len = self->stride * self->height * sizeof(size_t); + bufinfo->len = self->stride * self->height * sizeof(uint32_t); bufinfo->buf = self->data; switch (self->bits_per_value) { case 32: diff --git a/shared-module/displayio/Bitmap.h b/shared-module/displayio/Bitmap.h index 82a3de631a..0373ae80c5 100644 --- a/shared-module/displayio/Bitmap.h +++ b/shared-module/displayio/Bitmap.h @@ -37,8 +37,8 @@ typedef struct { mp_obj_base_t base; uint16_t width; uint16_t height; - size_t *data; - uint16_t stride; // size_t's + uint32_t *data; + uint16_t stride; // uint32_t's uint8_t bits_per_value; uint8_t x_shift; size_t x_mask; diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index 228d63d03b..707601a3e7 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -268,6 +268,10 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d output_color->pixel = (luma >> colorspace->grayscale_bit) & bitmask; output_color->opaque = true; return; + } else if (colorspace->depth == 32) { + output_color->pixel = pixel; + output_color->opaque = true; + return; } output_color->opaque = false; } diff --git a/shared-module/displayio/Palette.c b/shared-module/displayio/Palette.c index 47cad11ea5..0325aaab2c 100644 --- a/shared-module/displayio/Palette.c +++ b/shared-module/displayio/Palette.c @@ -71,7 +71,7 @@ uint32_t common_hal_displayio_palette_get_color(displayio_palette_t *self, uint3 bool displayio_palette_get_color(displayio_palette_t *self, const _displayio_colorspace_t *colorspace, uint32_t palette_index, uint32_t *color) { if (palette_index > self->color_count || self->colors[palette_index].transparent) { - return false; // returns opaque + return false; // returns transparent } if (colorspace->tricolor) { @@ -89,13 +89,15 @@ bool displayio_palette_get_color(displayio_palette_t *self, const _displayio_col } else if (colorspace->grayscale) { size_t bitmask = (1 << colorspace->depth) - 1; *color = (self->colors[palette_index].luma >> colorspace->grayscale_bit) & bitmask; - } else { + } else if (colorspace->depth == 16) { uint16_t packed = self->colors[palette_index].rgb565; if (colorspace->reverse_bytes_in_word) { // swap bytes packed = __builtin_bswap16(packed); } *color = packed; + } else if (colorspace->depth == 32) { + *color = self->colors[palette_index].rgb888; } return true; diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index 044674f415..ff4f56efc4 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -331,7 +331,9 @@ void common_hal_displayio_tilegrid_set_top_left(displayio_tilegrid_t *self, uint self->full_change = true; } -bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_colorspace_t *colorspace, const displayio_area_t *area, uint32_t *mask, uint32_t *buffer) { +bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, + const _displayio_colorspace_t *colorspace, const displayio_area_t *area, + uint32_t *mask, uint32_t *buffer) { // If no tiles are present we have no impact. uint8_t *tiles = self->tiles; if (self->inline_tiles) { @@ -443,7 +445,6 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c input_pixel.tile_x = (input_pixel.tile % self->bitmap_width_in_tiles) * self->tile_width + local_x % self->tile_width; input_pixel.tile_y = (input_pixel.tile / self->bitmap_width_in_tiles) * self->tile_height + local_y % self->tile_height; - // uint32_t value = 0; output_pixel.pixel = 0; input_pixel.pixel = 0; @@ -472,6 +473,8 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c mask[offset / 32] |= 1 << (offset % 32); if (colorspace->depth == 16) { *(((uint16_t *)buffer) + offset) = output_pixel.pixel; + } else if (colorspace->depth == 32) { + buffer[offset] = output_pixel.pixel; } else if (colorspace->depth == 8) { *(((uint8_t *)buffer) + offset) = output_pixel.pixel; } else if (colorspace->depth < 8) { @@ -495,6 +498,7 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c ((uint8_t *)buffer)[offset / pixels_per_byte] |= output_pixel.pixel << shift; } } + (void)input_pixel; } } return full_coverage; diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index eff86b81df..357dc64179 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -66,7 +66,7 @@ displayio_buffer_transform_t null_transform = { }; -#if CIRCUITPY_RGBMATRIX +#if CIRCUITPY_RGBMATRIX || CIRCUITPY_VIDEOCORE STATIC bool any_display_uses_this_framebuffer(mp_obj_base_t *obj) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { if (displays[i].display_base.type == &framebufferio_framebufferdisplay_type) { @@ -147,6 +147,10 @@ void common_hal_displayio_release_displays(void) { } else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { common_hal_sharpdisplay_framebuffer_deinit(&displays[i].sharpdisplay); #endif + #if CIRCUITPY_VIDEOCORE + } else if (displays[i].bus_base.type == &videocore_framebuffer_type) { + common_hal_videocore_framebuffer_deinit(&displays[i].videocore); + #endif } displays[i].fourwire_bus.base.type = &mp_type_NoneType; } @@ -159,8 +163,8 @@ void reset_displays(void) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { if (displays[i].fourwire_bus.base.type == &displayio_fourwire_type) { displayio_fourwire_obj_t *fourwire = &displays[i].fourwire_bus; - if (((uint32_t)fourwire->bus) < ((uint32_t)&displays) || - ((uint32_t)fourwire->bus) > ((uint32_t)&displays + CIRCUITPY_DISPLAY_LIMIT)) { + if (((size_t)fourwire->bus) < ((size_t)&displays) || + ((size_t)fourwire->bus) > ((size_t)&displays + CIRCUITPY_DISPLAY_LIMIT)) { busio_spi_obj_t *original_spi = fourwire->bus; #if BOARD_SPI // We don't need to move original_spi if it is the board.SPI object because it is @@ -187,8 +191,8 @@ void reset_displays(void) { } } else if (displays[i].i2cdisplay_bus.base.type == &displayio_i2cdisplay_type) { displayio_i2cdisplay_obj_t *i2c = &displays[i].i2cdisplay_bus; - if (((uint32_t)i2c->bus) < ((uint32_t)&displays) || - ((uint32_t)i2c->bus) > ((uint32_t)&displays + CIRCUITPY_DISPLAY_LIMIT)) { + if (((size_t)i2c->bus) < ((size_t)&displays) || + ((size_t)i2c->bus) > ((size_t)&displays + CIRCUITPY_DISPLAY_LIMIT)) { busio_i2c_obj_t *original_i2c = i2c->bus; #if BOARD_I2C // We don't need to move original_i2c if it is the board.I2C object because it is @@ -222,6 +226,15 @@ void reset_displays(void) { sharpdisplay_framebuffer_obj_t *sharp = &displays[i].sharpdisplay; common_hal_sharpdisplay_framebuffer_reset(sharp); #endif + #if CIRCUITPY_VIDEOCORE + } else if (displays[i].bus_base.type == &videocore_framebuffer_type) { + videocore_framebuffer_obj_t *vc = &displays[i].videocore; + if (!any_display_uses_this_framebuffer(&vc->base)) { + common_hal_videocore_framebuffer_deinit(vc); + } + // The framebuffer is allocated outside of the heap so it doesn't + // need to be moved. + #endif } else { // Not an active display bus. continue; diff --git a/shared-module/displayio/__init__.h b/shared-module/displayio/__init__.h index 5bfee4d67d..ad397c8254 100644 --- a/shared-module/displayio/__init__.h +++ b/shared-module/displayio/__init__.h @@ -44,6 +44,9 @@ #if CIRCUITPY_SHARPDISPLAY #include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" #endif +#if CIRCUITPY_VIDEOCORE +#include "bindings/videocore/Framebuffer.h" +#endif typedef struct { union { @@ -59,6 +62,9 @@ typedef struct { #if CIRCUITPY_SHARPDISPLAY sharpdisplay_framebuffer_obj_t sharpdisplay; #endif + #if CIRCUITPY_VIDEOCORE + videocore_framebuffer_obj_t videocore; + #endif }; union { mp_obj_base_t display_base; diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 4bef2ff655..48353b7dba 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -160,7 +160,7 @@ STATIC const displayio_area_t *_get_refresh_areas(framebufferio_framebufferdispl #define MARK_ROW_DIRTY(r) (dirty_row_bitmask[r / 8] |= (1 << (r & 7))) STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t *self, const displayio_area_t *area, uint8_t *dirty_row_bitmask) { - uint16_t buffer_size = 128; // In uint32_ts + uint16_t buffer_size = CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE / sizeof(uint32_t); // In uint32_ts displayio_area_t clipped; // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. diff --git a/shared-module/keypad/KeyMatrix.c b/shared-module/keypad/KeyMatrix.c index 4e1e25aafa..49b87fc882 100644 --- a/shared-module/keypad/KeyMatrix.c +++ b/shared-module/keypad/KeyMatrix.c @@ -41,7 +41,7 @@ static mp_uint_t row_column_to_key_number(keypad_keymatrix_obj_t *self, mp_uint_ return row * self->column_digitalinouts->len + column; } -void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_column_pins, mcu_pin_obj_t *column_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events) { +void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, const mcu_pin_obj_t *row_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events) { mp_obj_t row_dios[num_row_pins]; for (size_t row = 0; row < num_row_pins; row++) { diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c index ed913ec7a6..ce402e4dce 100644 --- a/shared-module/keypad/Keys.c +++ b/shared-module/keypad/Keys.c @@ -36,7 +36,7 @@ #include "supervisor/port.h" #include "supervisor/shared/tick.h" -void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, mp_float_t interval, size_t max_events) { +void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, const mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, mp_float_t interval, size_t max_events) { mp_obj_t dios[num_pins]; for (size_t i = 0; i < num_pins; i++) { diff --git a/shared-module/keypad/ShiftRegisterKeys.c b/shared-module/keypad/ShiftRegisterKeys.c index 85803378b1..d185c6fca4 100644 --- a/shared-module/keypad/ShiftRegisterKeys.c +++ b/shared-module/keypad/ShiftRegisterKeys.c @@ -36,7 +36,7 @@ #include "supervisor/port.h" #include "supervisor/shared/tick.h" -void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t key_count, bool value_when_pressed, mp_float_t interval, size_t max_events) { +void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, const mcu_pin_obj_t *clock_pin, const mcu_pin_obj_t *data_pin, const mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t key_count, bool value_when_pressed, mp_float_t interval, size_t max_events) { digitalio_digitalinout_obj_t *clock = m_new_obj(digitalio_digitalinout_obj_t); clock->base.type = &digitalio_digitalinout_type; diff --git a/shared-module/paralleldisplay/ParallelBus.c b/shared-module/paralleldisplay/ParallelBus.c index 6a53945e06..3a9495934e 100644 --- a/shared-module/paralleldisplay/ParallelBus.c +++ b/shared-module/paralleldisplay/ParallelBus.c @@ -31,7 +31,7 @@ // implementation will raise an exception for you. __attribute__((weak)) void common_hal_paralleldisplay_parallelbus_construct_nonsequential(paralleldisplay_parallelbus_obj_t *self, - uint8_t n_pins, mcu_pin_obj_t **data_pins, const mcu_pin_obj_t *command, const mcu_pin_obj_t *chip_select, + uint8_t n_pins, const mcu_pin_obj_t **data_pins, const mcu_pin_obj_t *command, const mcu_pin_obj_t *chip_select, const mcu_pin_obj_t *write, const mcu_pin_obj_t *read, const mcu_pin_obj_t *reset, uint32_t frequency) { mp_raise_NotImplementedError(translate("This microcontroller only supports data0=, not data_pins=, because it requires contiguous pins.")); } diff --git a/shared-module/sdcardio/SDCard.c b/shared-module/sdcardio/SDCard.c index 9cbbf40819..9eb32d9265 100644 --- a/shared-module/sdcardio/SDCard.c +++ b/shared-module/sdcardio/SDCard.c @@ -296,7 +296,7 @@ STATIC const compressed_string_t *init_card(sdcardio_sdcard_obj_t *self) { return NULL; } -void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, mcu_pin_obj_t *cs, int baudrate) { +void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate) { self->bus = bus; common_hal_digitalio_digitalinout_construct(&self->cs, cs); common_hal_digitalio_digitalinout_switch_to_output(&self->cs, true, DRIVE_MODE_PUSH_PULL); diff --git a/shared-module/sdcardio/SDCard.h b/shared-module/sdcardio/SDCard.h index f76bbf5549..ff89b89819 100644 --- a/shared-module/sdcardio/SDCard.h +++ b/shared-module/sdcardio/SDCard.h @@ -45,7 +45,7 @@ typedef struct { bool in_cmd25; } sdcardio_sdcard_obj_t; -void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *spi, mcu_pin_obj_t *cs, int baudrate); +void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *spi, const mcu_pin_obj_t *cs, int baudrate); void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self); void common_hal_sdcardio_sdcard_check_for_deinit(sdcardio_sdcard_obj_t *self); int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self); diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c index 9012a5ac89..ba0e0f2d69 100644 --- a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c @@ -128,7 +128,7 @@ void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t * memset(self, 0, sizeof(*self)); } -void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_t *self, busio_spi_obj_t *spi, mcu_pin_obj_t *chip_select, int baudrate, int width, int height) { +void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_t *self, busio_spi_obj_t *spi, const mcu_pin_obj_t *chip_select, int baudrate, int width, int height) { common_hal_digitalio_digitalinout_construct(&self->chip_select, chip_select); common_hal_digitalio_digitalinout_switch_to_output(&self->chip_select, true, DRIVE_MODE_PUSH_PULL); common_hal_never_reset_pin(chip_select); diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.h b/shared-module/sharpdisplay/SharpMemoryFramebuffer.h index 47e1a373fd..abc951baf5 100644 --- a/shared-module/sharpdisplay/SharpMemoryFramebuffer.h +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.h @@ -44,7 +44,7 @@ typedef struct { bool full_refresh : 1; } sharpdisplay_framebuffer_obj_t; -void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_t *self, busio_spi_obj_t *spi, mcu_pin_obj_t *chip_select, int baudrate, int width, int height); +void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_t *self, busio_spi_obj_t *spi, const mcu_pin_obj_t *chip_select, int baudrate, int width, int height); void common_hal_sharpdisplay_framebuffer_swap_buffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask); void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t *self); void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_obj_t *self, mp_buffer_info_t *bufinfo); diff --git a/shared/runtime/interrupt_char.c b/shared/runtime/interrupt_char.c index 21e5a06358..de4218420d 100644 --- a/shared/runtime/interrupt_char.c +++ b/shared/runtime/interrupt_char.c @@ -38,7 +38,7 @@ void mp_hal_set_interrupt_char(int c) { // Check to see if we've been CTRL-C'ed by autoreload or the user. bool mp_hal_is_interrupted(void) { - return MP_STATE_THREAD(mp_pending_exception) != NULL; + return MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_FROM_PTR(NULL); } #endif diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index e611131f6b..7b44bb15dc 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -167,11 +167,11 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input mp_hal_stdout_tx_strn("\x04", 1); } // check for SystemExit - if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type((mp_obj_t)nlr.ret_val)), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { // at the moment, the value of SystemExit is unused ret = pyexec_system_exit; #if CIRCUITPY_ALARM - } else if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), &mp_type_DeepSleepRequest)) { + } else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type((mp_obj_t)nlr.ret_val)), &mp_type_DeepSleepRequest)) { ret = PYEXEC_DEEP_SLEEP; #endif } else { diff --git a/supervisor/shared/cpu.c b/supervisor/shared/cpu.c index 510225d197..d1e4114ca3 100644 --- a/supervisor/shared/cpu.c +++ b/supervisor/shared/cpu.c @@ -29,7 +29,7 @@ #include "supervisor/shared/cpu.h" bool cpu_interrupt_active(void) { - #if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) + #if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && defined(__ARM_ARCH_PROFILE) && (__ARM_ARCH_PROFILE == 'M') // Check VECTACTIVE in ICSR. We don't need to disable interrupts because if // one occurs after we read, we won't continue until it is resolved. return (*((volatile uint32_t *)0xE000ED04) & 0x1ff) != 0; diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c index 9cd4f18960..a4849a3c58 100644 --- a/supervisor/shared/display.c +++ b/supervisor/shared/display.c @@ -45,7 +45,7 @@ #include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" #endif -extern size_t blinka_bitmap_data[]; +extern uint32_t blinka_bitmap_data[]; extern displayio_bitmap_t blinka_bitmap; extern displayio_group_t circuitpython_splash; @@ -155,7 +155,7 @@ void supervisor_display_move_memory(void) { #endif } -size_t blinka_bitmap_data[32] = { +uint32_t blinka_bitmap_data[32] = { 0x00000011, 0x11000000, 0x00000111, 0x53100000, 0x00000111, 0x56110000, diff --git a/supervisor/shared/filesystem.c b/supervisor/shared/filesystem.c index 33d6c70dd2..2ab64e5dbd 100644 --- a/supervisor/shared/filesystem.c +++ b/supervisor/shared/filesystem.c @@ -94,11 +94,14 @@ void filesystem_init(bool create_allowed, bool force_create) { // try to mount the flash FRESULT res = f_mount(&vfs_fat->fatfs); - if ((res == FR_NO_FILESYSTEM && create_allowed) || force_create) { // No filesystem so create a fresh one, or reformat has been requested. uint8_t working_buf[FF_MAX_SS]; - res = f_mkfs(&vfs_fat->fatfs, FM_FAT, 0, working_buf, sizeof(working_buf)); + BYTE formats = FM_FAT; + #if FF_FS_EXFAT + formats |= FM_EXFAT | FM_FAT32; + #endif + res = f_mkfs(&vfs_fat->fatfs, formats, 0, working_buf, sizeof(working_buf)); // Flush the new file system to make sure it's repaired immediately. supervisor_flash_flush(); if (res != FR_OK) { diff --git a/supervisor/shared/flash.c b/supervisor/shared/flash.c index d96d433813..333c6467d4 100644 --- a/supervisor/shared/flash.c +++ b/supervisor/shared/flash.c @@ -207,14 +207,14 @@ const mp_obj_type_t supervisor_flash_type = { { &mp_type_type }, .name = MP_QSTR_Flash, .make_new = supervisor_flash_obj_make_new, - .locals_dict = (mp_obj_t)&supervisor_flash_obj_locals_dict, + .locals_dict = (struct _mp_obj_dict_t *)&supervisor_flash_obj_locals_dict, }; void supervisor_flash_init_vfs(fs_user_mount_t *vfs) { vfs->base.type = &mp_fat_vfs_type; vfs->blockdev.flags |= MP_BLOCKDEV_FLAG_NATIVE | MP_BLOCKDEV_FLAG_HAVE_IOCTL; vfs->fatfs.drv = vfs; - vfs->fatfs.part = 1; // flash filesystem lives on first partition + vfs->fatfs.part = 1; // flash filesystem lives on first fake partition vfs->blockdev.readblocks[0] = (mp_obj_t)&supervisor_flash_obj_readblocks_obj; vfs->blockdev.readblocks[1] = (mp_obj_t)&supervisor_flash_obj; vfs->blockdev.readblocks[2] = (mp_obj_t)flash_read_blocks; // native version diff --git a/supervisor/shared/serial.c b/supervisor/shared/serial.c index 390591eab2..ddb614d133 100644 --- a/supervisor/shared/serial.c +++ b/supervisor/shared/serial.c @@ -40,7 +40,9 @@ #include "supervisor/shared/bluetooth/serial.h" #endif +#if CIRCUITPY_USB #include "tusb.h" +#endif /* * Note: DEBUG_UART currently only works on STM32 and nRF. diff --git a/supervisor/shared/stack.c b/supervisor/shared/stack.c index d1dc66d18c..d2188e016d 100644 --- a/supervisor/shared/stack.c +++ b/supervisor/shared/stack.c @@ -53,7 +53,7 @@ static void allocate_stack(void) { mp_uint_t regs[10]; mp_uint_t sp = cpu_get_regs_and_sp(regs); - mp_uint_t c_size = (uint32_t)port_stack_get_top() - sp; + mp_uint_t c_size = (mp_uint_t)port_stack_get_top() - sp; supervisor_allocation *stack_alloc = allocate_memory(c_size + next_stack_size + EXCEPTION_STACK_SIZE, true, false); if (stack_alloc == NULL) { stack_alloc = allocate_memory(c_size + CIRCUITPY_DEFAULT_STACK_SIZE + EXCEPTION_STACK_SIZE, true, false); diff --git a/supervisor/shared/workflow.c b/supervisor/shared/workflow.c index 650be39673..8d2c0f74fc 100644 --- a/supervisor/shared/workflow.c +++ b/supervisor/shared/workflow.c @@ -28,7 +28,10 @@ #include "py/mpconfig.h" #include "supervisor/workflow.h" #include "supervisor/shared/workflow.h" + +#if CIRCUITPY_USB #include "tusb.h" +#endif void supervisor_workflow_reset(void) { } @@ -38,12 +41,20 @@ void supervisor_workflow_reset(void) { // Not that some chips don't notice when USB is unplugged after first being plugged in, // so this is not perfect, but tud_suspended() check helps. bool supervisor_workflow_connecting(void) { + #if CIRCUITPY_USB return tud_connected() && !tud_suspended(); + #else + return false; + #endif } // Return true if host has completed connection to us (such as USB enumeration). bool supervisor_workflow_active(void) { + #if CIRCUITPY_USB // Eventually there might be other non-USB workflows, such as BLE. // tud_ready() checks for usb mounted and not suspended. return tud_ready(); + #else + return false; + #endif } diff --git a/tools/build_board_info.py b/tools/build_board_info.py index 21d35eff07..dde59e7e43 100644 --- a/tools/build_board_info.py +++ b/tools/build_board_info.py @@ -31,17 +31,19 @@ SPK = ("spk",) DFU = ("dfu",) BIN_DFU = ("bin", "dfu") COMBINED_HEX = ("combined.hex",) +KERNEL8_IMG = ("disk.img.zip", "kernel8.img") # Default extensions extension_by_port = { - "nrf": UF2, "atmel-samd": UF2, - "stm": BIN, + "broadcom": KERNEL8_IMG, "cxd56": SPK, - "mimxrt10xx": HEX_UF2, - "litex": DFU, "espressif": BIN_UF2, + "litex": DFU, + "mimxrt10xx": HEX_UF2, + "nrf": UF2, "raspberrypi": UF2, + "stm": BIN, } # Per board overrides diff --git a/tools/ci_fetch_deps.py b/tools/ci_fetch_deps.py new file mode 100644 index 0000000000..9ffb6c04cb --- /dev/null +++ b/tools/ci_fetch_deps.py @@ -0,0 +1,109 @@ +import pathlib +import shlex +import subprocess +import sys +import time + +# target will be a board, "test", "docs", "mpy-cross-mac", or "windows" + +target = sys.argv[1] +ref = sys.argv[2] + +print(target, ref) + +# Submodules needed by port builds outside of their ports directory. +# Should we try and detect these? +port_deps = { + "atmel-samd": [ + "extmod/ulab/", + "lib/mp3/", + "lib/protomatter/", + "lib/quirc/", + "lib/tinyusb/", + "data/nvm.toml/", + ], + "broadcom": ["lib/tinyusb/"], + "cxd56": ["extmod/ulab/", "lib/tinyusb/"], + "espressif": ["extmod/ulab/", "lib/tinyusb/", "lib/protomatter/", "lib/quirc/"], + "litex": ["extmod/ulab/", "lib/tinyusb/"], + "mimxrt10xx": ["extmod/ulab/", "lib/tinyusb/", "data/nvm.toml/"], + "nrf": ["extmod/ulab/", "lib/mp3/", "lib/protomatter/", "lib/tinyusb/", "data/nvm.toml/"], + "raspberrypi": [ + "extmod/ulab/", + "lib/mp3/", + "lib/protomatter/", + "lib/quirc/", + "lib/tinyusb/", + "data/nvm.toml/", + ], + "stm": ["extmod/ulab/", "lib/mp3/", "lib/protomatter/", "lib/tinyusb/", "data/nvm.toml/"] + # omit unix which is part of the "test" target below +} + + +def run(title, command): + print("::group::" + title, flush=True) + print(command, flush=True) + start = time.monotonic() + subprocess.run(shlex.split(command), stderr=subprocess.STDOUT) + print("Duration:", time.monotonic() - start, flush=True) + print("::endgroup::", flush=True) + + +run( + "Fetch back to the start of 2021 to get tag history", + 'git fetch --tags --recurse-submodules=no --shallow-since="2021-07-01" https://github.com/adafruit/circuitpython HEAD', +) +run( + "Fetch back to the start of 2021 to get commit history", + f'git fetch --recurse-submodules=no --shallow-since="2021-07-01" origin {ref}', +) +run("Init submodules", "git submodule init") +run("Submodule status", "git submodule status") + +submodules = [] + +if target == "test": + submodules = ["extmod/", "lib/", "tools/"] +elif target == "docs": + submodules = ["extmod/ulab/"] +elif target == "mpy-cross-mac": + submodules = ["tools/"] # for huffman +elif target == "windows": + # This builds one board from a number of ports so fill out a bunch of submodules + submodules = ["extmod/", "lib/", "tools/", "ports/", "data/nvm.toml/"] +else: + p = pathlib.Path(".").glob(f"ports/*/boards/{target}/mpconfigboard.mk") + if not p: + raise RuntimeError(f"Unsupported target: {target}") + + config = list(p)[0] + # Add the ports folder to init submodules + port_folder = config.parents[2] + port = port_folder.name + submodules.append(str(port_folder)) + submodules.append("tools/") # for huffman + submodules.extend(port_deps[port]) + with config.open() as f: + for line in f.readlines(): + prefix = "FROZEN_MPY_DIRS += $(TOP)/" + if line.startswith(prefix): + lib_folder = line.strip()[len(prefix) :] + # Drop everything after the second folder because the frozen + # folder may be inside the submodule. + if lib_folder.count("/") > 1: + lib_folder = lib_folder.split("/", maxsplit=2) + lib_folder = "/".join(lib_folder[:2]) + submodules.append(lib_folder) + +print(submodules) +if submodules: + submodules = " ".join(submodules) + # This line will fail because the submodule's need different commits than the tip of the branch. We + # fix it later. + run("Init the submodules we'll need", f"git submodule update --init -N --depth 1 {submodules}") + + run( + "Fetch the submodule sha", + "git submodule foreach 'git fetch --tags --depth 1 origin $sha1 && git checkout -q $sha1'", + ) diff --git a/tools/ci_set_matrix.py b/tools/ci_set_matrix.py index e9aafc22cc..2f74fbec04 100644 --- a/tools/ci_set_matrix.py +++ b/tools/ci_set_matrix.py @@ -24,6 +24,7 @@ import build_board_info PORT_TO_ARCH = { "atmel-samd": "arm", + "broadcom": "aarch", "cxd56": "arm", "espressif": "espressif", "litex": "riscv", @@ -86,7 +87,7 @@ def set_boards_to_build(build_all): # Split boards by architecture. print("Building boards:") - arch_to_boards = {"arm": [], "riscv": [], "espressif": []} + arch_to_boards = {"aarch": [], "arm": [], "riscv": [], "espressif": []} for board in boards_to_build: print(" ", board) port = board_to_port.get(board) diff --git a/tools/gen_display_resources.py b/tools/gen_display_resources.py index 5cd2e11696..552e5f1245 100644 --- a/tools/gen_display_resources.py +++ b/tools/gen_display_resources.py @@ -192,7 +192,7 @@ displayio_bitmap_t supervisor_terminal_font_bitmap = {{ .base = {{.type = &displayio_bitmap_type }}, .width = {}, .height = {}, - .data = (size_t*) font_bitmap_data, + .data = (uint32_t*) font_bitmap_data, .stride = {}, .bits_per_value = 1, .x_shift = 5,