Compare commits

..

No commits in common. "master" and "add-max32-support" have entirely different histories.

46 changed files with 616 additions and 1602 deletions

View file

@ -65,7 +65,6 @@ jobs:
- 'lpc55'
- 'mimxrt10xx'
- 'stm32f3'
- 'stm32h7'
- 'stm32l4'
with:
port: ${{ matrix.port }}

View file

@ -73,22 +73,20 @@ jobs:
- name: Prepare Release Asset
if: github.event_name == 'release'
run: |
if [ ${{ inputs.toolchain }} == esp-idf ]; then
if [ ${{ inputs.toolchain }} == 'esp-idf' ]; then
zip -jr tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.zip ${{ env.BIN_PATH }}
cp ${{ env.BIN_PATH }}/combined.bin combined.bin
[ -f ${{ env.BIN_PATH }}/combined-ota.bin ] && cp ${{ env.BIN_PATH }}/combined-ota.bin combined-ota.bin
cp ${{ env.BIN_PATH }}/apps/update-tinyuf2.uf2 update-tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.uf2
else
if [[ ${{ inputs.build-system }} == cmake ]]; then
[ -f ${{ env.BIN_PATH }}/apps/update-tinyuf2.uf2 ] && cp ${{ env.BIN_PATH }}/apps/update-tinyuf2.uf2 update-tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.uf2
cp ${{ env.BIN_PATH }}/apps/update-tinyuf2.uf2 update-tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.uf2
else
[ -f ${{ env.BIN_PATH }}/apps/update-tinyuf2-${{ matrix.board }}.uf2] && cp ${{ env.BIN_PATH }}/apps/update-tinyuf2-${{ matrix.board }}.uf2 update-tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.uf2
cp ${{ env.BIN_PATH }}/apps/update-tinyuf2-${{ matrix.board }}.uf2 update-tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.uf2
fi
zip -jr tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.zip ${{ env.BIN_PATH }}
fi
- name: Upload Release Asset
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
@ -101,11 +99,5 @@ jobs:
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
if: github.event_name == 'release' && inputs.port == 'espressif'
run: |
if [ -n \"$AWS_ACCESS_KEY_ID\" ]; then
aws s3 cp tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.zip s3://adafruit-circuit-python/bootloaders/esp32/${{ matrix.board }}/tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.zip --no-progress --region us-east-1
aws s3 cp update-tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.uf2 s3://adafruit-circuit-python/bootloaders/esp32/${{ matrix.board }}/update-tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.uf2 --no-progress --region us-east-1
aws s3 cp combined.bin s3://adafruit-circuit-python/bootloaders/esp32/${{ matrix.board }}/tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}-combined.bin --no-progress --region us-east-1
if [ -f combined-ota.bin ]; then
aws s3 cp combined-ota.bin s3://adafruit-circuit-python/bootloaders/esp32/${{ matrix.board }}/tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}-combined-ota.bin --no-progress --region us-east-1
fi
fi
[ -z \"$AWS_ACCESS_KEY_ID\" ] || aws s3 cp tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.zip s3://adafruit-circuit-python/bootloaders/esp32/tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.zip --no-progress --region us-east-1
[ -z \"$AWS_ACCESS_KEY_ID\" ] || aws s3 cp update-tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.uf2 s3://adafruit-circuit-python/bootloaders/esp32/update-tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.uf2 --no-progress --region us-east-1

View file

@ -18,8 +18,8 @@ def set_matrix_json():
if b.is_dir():
matrix[p.name]['board'].append(b.name)
# For quick testing by only build 1 espressif board
# if p.name == 'espressif':
# break
if p.name == 'espressif':
break
print(json.dumps(matrix))

View file

@ -37,8 +37,6 @@
#define BOARD_UF2_FAMILY_ID 0xbfdd4eee
#elif CONFIG_IDF_TARGET_ESP32S3
#define BOARD_UF2_FAMILY_ID 0xc47e5767
#elif CONFIG_IDF_TARGET_ESP32P4
#define BOARD_UF2_FAMILY_ID 0x3d308e94
#else
#error unsupported MCUs
#endif

View file

@ -1,2 +0,0 @@
# Apply board specific content here
set(IDF_TARGET "esp32s3")

View file

@ -1,69 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Ha Thach (tinyusb.org) 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 SENSEBOX_EYE_ESP32S3_H_
#define SENSEBOX_EYE_ESP32S3_H_
//--------------------------------------------------------------------+
// Button
//--------------------------------------------------------------------+
// Enter UF2 mode if GPIO is pressed while 2nd stage bootloader indicator
// is on e.g RGB = Purple. If it is GPIO0, user should not hold this while
// reset since that will instead run the 1st stage ROM bootloader
#define PIN_BUTTON_UF2 0
// GPIO that implement 1-bit memory with RC components which hold the
// pin value long enough for double reset detection.
// #define PIN_DOUBLE_RESET_RC
// GPIO connected to Neopixel data
#define NEOPIXEL_PIN 45
#define NEOPIXEL_POWER_STATE 1
// Brightness percentage from 1 to 255
#define NEOPIXEL_BRIGHTNESS 0x10
// Number of neopixels
#define NEOPIXEL_NUMBER 1
//--------------------------------------------------------------------+
// USB UF2
//--------------------------------------------------------------------+
#define USB_VID 0x303A
#define USB_PID 0x82D3
#define USB_MANUFACTURER "senseBox"
#define USB_PRODUCT "eye ESP32S3"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S3-senseBox-eye"
#define UF2_VOLUME_LABEL "senseBox"
#define UF2_INDEX_URL "https://sensebox.de"
// Use favicon
#define TINYUF2_FAVICON_HEADER "favicon_sensebox_256.h"
#endif

View file

@ -1,7 +0,0 @@
# Board Specific Config
# Partition Table
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-8MB.csv"
# Serial flasher config
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y

View file

@ -1,2 +0,0 @@
# Apply board specific content here
set(IDF_TARGET "esp32s3")

View file

@ -1,71 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Ha Thach (tinyusb.org) 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 UNEXPECTEDMAKER_EDGE3SD_H_
#define UNEXPECTEDMAKER_EDGE3SD_H_
//--------------------------------------------------------------------+
// Button
//--------------------------------------------------------------------+
// Enter UF2 mode if GPIO is pressed while 2nd stage bootloader indicator
// is on e.g RGB = Purple. If it is GPIO0, user should not hold this while
// reset since that will instead run the 1st stage ROM bootloader
#define PIN_BUTTON_UF2 0
// GPIO that implement 1-bit memory with RC components which hold the
// pin value long enough for double reset detection.
// #define PIN_DOUBLE_RESET_RC 47
//--------------------------------------------------------------------+
// LED
//--------------------------------------------------------------------+
// GPIO connected to Neopixel data
// #define NEOPIXEL_PIN 35
// #define NEOPIXEL_POWER_PIN 34
// #define NEOPIXEL_POWER_STATE 1
// Brightness percentage from 1 to 255
// #define NEOPIXEL_BRIGHTNESS 0x64
// Number of neopixels
#define NEOPIXEL_NUMBER 0
//--------------------------------------------------------------------+
// USB UF2
//--------------------------------------------------------------------+
#define USB_VID 0x303A
#define USB_PID 0x82DE
#define USB_MANUFACTURER "Unexpected Maker"
#define USB_PRODUCT "EDGES3D"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S3-EDGES3-01"
#define UF2_VOLUME_LABEL "EDGES3BOOT"
#define UF2_INDEX_URL "https://circuitpython.org/board/unexpectedmaker_edges3d/"
#endif

View file

@ -1,7 +0,0 @@
# Board Specific Config
# Partition Table
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-8MB.csv"
# Serial flasher config
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y

View file

@ -40,8 +40,6 @@
#define CFG_TUSB_MCU OPT_MCU_ESP32S2
#elif CONFIG_IDF_TARGET_ESP32S3
#define CFG_TUSB_MCU OPT_MCU_ESP32S3
#elif CONFIG_IDF_TARGET_ESP32P4
#define CFG_TUSB_MCU OPT_MCU_ESP32P4
#endif
#define CFG_TUSB_OS OPT_OS_FREERTOS

View file

@ -2,7 +2,6 @@ include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
set(UF2_FAMILY_ID_esp32s2 0xbfdd4eee)
set(UF2_FAMILY_ID_esp32s3 0xc47e5767)
set(UF2_FAMILY_ID_esp32p4 0x3d308e94)
set(UF2_FAMILY_ID ${UF2_FAMILY_ID_${IDF_TARGET}})
# override default family_gen_uf2

View file

@ -33,10 +33,6 @@ if (NOT DEFINED TOOLCHAIN)
set(TOOLCHAIN gcc)
endif ()
if (NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Build type" FORCE)
endif ()
#-------------------------------------------------------------
# FAMILY and BOARD
#-------------------------------------------------------------
@ -334,17 +330,10 @@ endfunction()
# Add flash openocd adi (Analog Devices) target
# included with msdk or compiled from release branch of https://github.com/analogdevicesinc/openocd
function(family_flash_openocd_adi TARGET)
if (DEFINED MAXIM_PATH)
# use openocd from msdk with MAXIM_PATH cmake variable first if the user
# specified it
set(OPENOCD ${MAXIM_PATH}/Tools/OpenOCD/openocd)
set(OPENOCD_OPTION2 "-s ${MAXIM_PATH}/Tools/OpenOCD/scripts")
elseif (DEFINED ENV{MAXIM_PATH})
# use openocd from msdk with MAXIM_PATH environment variable. Normalize
# since msdk can be Windows (MinGW) or Linux
file(TO_CMAKE_PATH "$ENV{MAXIM_PATH}" MAXIM_PATH_NORM)
set(OPENOCD ${MAXIM_PATH_NORM}/Tools/OpenOCD/openocd)
set(OPENOCD_OPTION2 "-s ${MAXIM_PATH_NORM}/Tools/OpenOCD/scripts")
if (DEFINED $ENV{MAXIM_PATH})
# use openocd from msdk
set(OPENOCD ENV{MAXIM_PATH}/Tools/OpenOCD/openocd)
set(OPENOCD_OPTION2 "-s $ENV{MAXIM_PATH}/Tools/OpenOCD/scripts")
else()
# compiled from source
if (NOT DEFINED OPENOCD_ADI_PATH)

3
ports/maxim/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
# Ignore build logs
logs/
*.log

86
ports/maxim/Makefile Normal file
View file

@ -0,0 +1,86 @@
# List of git submodules that is included as part of the UF2 version
GIT_SUBMODULES = tinyusb
include ../make.mk
include port.mk
include ../rules.mk
################################################################################
# Optional Save Log Support
################################################################################
ifeq ($(SAVELOG),1)
TIMESTAMP := $(shell date +%Y%m%d_%H%M%S)
LOG_SUFFIX = _$(TIMESTAMP).log
endif
################################################################################
# Self-update
################################################################################
self-update:
@mkdir -p $(TOP)/$(PORT_DIR)/apps/self_update/logs/self-update
@echo "Building self-update application..."
ifeq ($(SAVELOG),1)
$(MAKE) -C $(TOP)/$(PORT_DIR)/apps/self_update uf2 2>&1 | tee $(TOP)/$(PORT_DIR)/apps/self_update/logs/self-update/self-update$(LOG_SUFFIX)
else
$(MAKE) -C $(TOP)/$(PORT_DIR)/apps/self_update uf2
endif
self-update-clean:
@mkdir -p $(TOP)/$(PORT_DIR)/apps/self_update/logs/self-update-clean
@echo "Cleaning self-update application..."
ifeq ($(SAVELOG),1)
$(MAKE) -C $(TOP)/$(PORT_DIR)/apps/self_update clean 2>&1 | tee $(TOP)/$(PORT_DIR)/apps/self_update/logs/self-update-clean/self-update-clean$(LOG_SUFFIX)
else
$(MAKE) -C $(TOP)/$(PORT_DIR)/apps/self_update clean
endif
################################################################################
# Erase Firmware
################################################################################
erase-firmware:
@mkdir -p $(TOP)/$(PORT_DIR)/apps/erase_firmware/logs/erase-firmware
@echo "Building erase-firmware application..."
ifeq ($(SAVELOG),1)
$(MAKE) -C $(TOP)/$(PORT_DIR)/apps/erase_firmware uf2 2>&1 | tee $(TOP)/$(PORT_DIR)/apps/erase_firmware/logs/erase-firmware/erase-firmware$(LOG_SUFFIX)
else
$(MAKE) -C $(TOP)/$(PORT_DIR)/apps/erase_firmware uf2
endif
erase-firmware-clean:
@mkdir -p $(TOP)/$(PORT_DIR)/apps/erase_firmware/logs/erase-firmware-clean
@echo "Cleaning erase-firmware application..."
ifeq ($(SAVELOG),1)
$(MAKE) -C $(TOP)/$(PORT_DIR)/apps/erase_firmware clean 2>&1 | tee $(TOP)/$(PORT_DIR)/apps/erase_firmware/logs/erase-firmware-clean/erase-firmware-clean$(LOG_SUFFIX)
else
$(MAKE) -C $(TOP)/$(PORT_DIR)/apps/erase_firmware clean
endif
################################################################################
# Blinky
################################################################################
blinky:
@mkdir -p $(TOP)/$(PORT_DIR)/apps/blinky/logs/blinky
@echo "Building blinky application..."
ifeq ($(SAVELOG),1)
$(MAKE) -C $(TOP)/$(PORT_DIR)/apps/blinky uf2 2>&1 | tee $(TOP)/$(PORT_DIR)/apps/blinky/logs/blinky/blinky$(LOG_SUFFIX)
else
$(MAKE) -C $(TOP)/$(PORT_DIR)/apps/blinky uf2
endif
blinky-clean:
@mkdir -p $(TOP)/$(PORT_DIR)/apps/blinky/logs/blinky-clean
@echo "Cleaning blinky application..."
ifeq ($(SAVELOG),1)
$(MAKE) -C $(TOP)/$(PORT_DIR)/apps/blinky clean 2>&1 | tee $(TOP)/$(PORT_DIR)/apps/blinky/logs/blinky-clean/blinky-clean$(LOG_SUFFIX)
else
$(MAKE) -C $(TOP)/$(PORT_DIR)/apps/blinky clean
endif
################################################################################
# Clean Logs
################################################################################
clean-logs:
@echo "Cleaning all log files..."
@rm -rf $(TOP)/$(PORT_DIR)/apps/self_update/logs
@rm -rf $(TOP)/$(PORT_DIR)/apps/erase_firmware/logs
@rm -rf $(TOP)/$(PORT_DIR)/apps/blinky/logs

View file

@ -1,6 +1,6 @@
# TinyUF2 - MAX32690 Port
This folder contains the port of TinyUF2 for Analog Devices' MAX32xxx/MAX78000 MCUs.
This folder contains the port of TinyUF2 for Analog Devices' MAX32690 MCU.
## Navigation
@ -17,12 +17,16 @@ This folder contains the port of TinyUF2 for Analog Devices' MAX32xxx/MAX78000 M
- [J-Link vs OpenOCD](#j-link-vs-openocd)
- [Flashing with J-Link](#1-j-link-default)
- [Flashing with OpenOCD (MSDK)](#2-openocd-from-msdk-optional)
- [Notes on SAVELOG=1](#notes-on-savelog1)
- [Cleaning Logs](#cleaning-logs)
- [Flashing Example Applications](#flashing-example-applications)
- [Flashing via Drag-and-Drop](#flashing-via-drag-and-drop)
- [Re-Entering Bootloader Mode](#re-entering-bootloader-mode)
- [Port Directory Structure](#port-directory-structure)
<br>
## Requirements
This guide focuses on building TinyUF2 for Analog Devices' MAX32 parts.
@ -36,13 +40,13 @@ All you need is a basic toolchain:
- **GNU ARM Toolchain** (`arm-none-eabi-gcc`) available in your `PATH`
- **make**
- **CMake**
- **git** (required for submodules)
- **SDK Dependencies**
### Installing SDK Dependencies
```bash
python tools/get_deps.py maxim
python tools/get_deps.py max32
```
or
```bash
@ -52,13 +56,21 @@ python tools/get_deps.py --board apard32690
#### macOS Dependency Install
```bash
brew install arm-none-eabi-gcc make cmake git
brew install arm-none-eabi-gcc make git
```
#### Ubuntu Dependency Install
```bash
sudo apt update
sudo apt install gcc-arm-none-eabi make cmake git
sudo apt install gcc-arm-none-eabi make git
```
<br><br>
```bash
# Example usage:
cd ports/max32690/
make BOARD=apard32690 all
```
---
@ -91,6 +103,9 @@ If needed, set `MAXIM_PATH` to point to your MSDK installation:
export MAXIM_PATH=/c/MaximSDK
```
<br>
## MSDK (Windows) Environment Setup
### 1. Using MSDK's MSYS2
@ -111,122 +126,128 @@ If you are using your own MSYS2 or mingw installation (not MSDKs MSYS2), you
export PATH="/c/MaximSDK/Tools/GNUTools/10.3/bin/:$PATH"
```
Or in one-line command for building:
```bash
PATH="/c/MaximSDK/Tools/GNUTools/10.3/bin/:$PATH" make BOARD=apard32690 blinky erase-firmware self-update
```
(Adjust the path if your MSDK installation is in a different location.)
<br>
## Available Boards
Each port supports multiple hardware platforms.
The specific boards available for each device can be found inside:
```
ports/maxim/boards/
ports/maxxxxxx/boards/
```
For example:
For example, for MAX32690:
```
tinyuf2/ports/maxim/boards/
tinyuf2/ports/max32690/boards/
apard32690
max32650evkit
max32650fthr
max32666evkit
max32666fthr
max32690evkit
max78002evkit
```
When initially configuring cmake, make sure to specify a valid `BOARD` name from the available list. Otherwise, the build will fail if an invalid board name is provided.
When building or flashing, make sure to specify a valid `BOARD` name from the available list:
```bash
cmake -DBOARD=apard32690 ..
make BOARD=apard32690 all
make BOARD=apard32690 flash
```
Afterward, all the cmake/cmake commands can be run within the `build` directory without needing to specify the board again, as it will be cached.
Otherwise, the build will fail if an invalid board name is provided.
<br>
## Building the Bootloader and Applications
## Building the Bootloader
1. Open your MSYS2 terminal (preferably MSDKs).
2. Navigate to the maxim folder, create a build directory, and change into it:
2. Navigate to the port folder for MAX32690:
```bash
cd ports/maxim
mkdir build
cd build
cd ports/max32690
```
3. Configure cmake with correct BOARD and run make to build:
3. Build the TinyUF2 bootloader:
```bash
cmake -DBOARD=apard32690 ..
make
make BOARD=apard32690 all
```
It will build the TinyUF2 bootloader along with all supported application e.g blinky, update-tinyuf2, erase-firmware. Tinyuf2 binaries will appear in `build/` folder while application are created in `build/apps/$(APP)/`.
- **Blinky** (`apps/blinky`) is useful to quickly test the bootloader
- **Erase Firmware** (`apps/erase_firmware`) put the board into a clean state
- **Self-Update** (`apps/self_update`) allows updating the bootloader itself
Output files will appear in `_build/` and build logs under `apps/$(APP)/logs/`.
To list all supported targets, run:
<br>
## Building Demo Applications
TinyUF2 for MAX32690 includes three demo applications:
- **Blinky** (`apps/blinky`)
- **Erase Firmware** (`apps/erase_firmware`)
- **Self-Update** (`apps/self_update`)
### To Build Individual Applications:
```bash
cmake --build . --target help
The following are some of the valid targets for this Makefile:
... all (the default if no target is provided)
... clean
... depend
... edit_cache
... rebuild_cache
... blinky-uf2
... erase_firmware-uf2
... tinyuf2-erase-jlink
... tinyuf2-jlink
... tinyuf2-openocd
... update-tinyuf2-uf2
... blinky
... board_max32666fthr
... erase_firmware
... tinyuf2
... update-tinyuf2
make BOARD=apard32690 blinky
make BOARD=apard32690 erase-firmware
make BOARD=apard32690 self-update
```
### To Build Individual Targets
To build a specific target, you can specify it directly with `make` or using `cmake --build`:
### To Clean Individual Applications:
```bash
make blinky
cmake --build . --target blinky
make BOARD=apard32690 blinky-clean
make BOARD=apard32690 erase-firmware-clean
make BOARD=apard32690 self-update-clean
```
You can add `SAVELOG=1` to any of these commands to generate a saved build log.
```bash
make BOARD=apard32690 SAVELOG=1 blinky erase-firmware self-update
```
<br>
## Flashing the Bootloader
### J-Link and OpenOCD
### J-Link vs OpenOCD
TinyUF2 supports two main ways to flash firmware:
- **J-Link**: Uses SEGGER's proprietary debug probe. Supports fast, reliable flashing and debugging over SWD or JTAG. Requires a J-Link device and SEGGER drivers.
- **J-Link** (default): Uses SEGGER's proprietary debug probe. Supports fast, reliable flashing and debugging over SWD or JTAG. Requires a J-Link device and SEGGER drivers.
- **OpenOCD (MSDK)**: Open-source tool for programming/debugging via CMSIS-DAP or other adapters.
The MSDK includes a custom version of OpenOCD that supports MAX32 devices, since official OpenOCD does not yet have MAX32 flash algorithm support.
### 1. J-Link
<br>
`make flash` will use **J-Link** by default.
`make flash-msdk` to use the **OpenOCD** path with CMSIS-DAP.
### 1. J-Link (default)
To flash using a J-Link debugger:
```bash
make tinyuf2-jlink
make BOARD=apard32690 flash
```
To erase before flashing:
```bash
make tinyuf2-erase-jlink tinyuf2-jlink
make BOARD=apard32690 erase flash
```
### 2. OpenOCD from MSDK (optional)
@ -234,56 +255,77 @@ make tinyuf2-erase-jlink tinyuf2-jlink
If you prefer OpenOCD and you have it installed through MSDK:
```bash
make tinyuf2-openocd
make BOARD=apard32690 flash-msdk
```
CMake will automatically leverage the MAXIM_PATH system environment variable if
a MAXIM_PATH is not manually specified. To manually specify a MSDK path,
you can pass the MaximSDK directory's location to cmake when configuring the
build:
Make sure `MAXIM_PATH` is correctly set to the MSDK base folder. If your default installation of the MSDK is not `C:/MaximSDK` you can pass the MaximSDK directory's location...
```bash
cmake -DBOARD=apard32690 -DMAXIM_PATH=/path/to/MaximSDK ..
make BOARD=apard32690 MAXIM_PATH=C:/MaximSDK flash-msdk
```
or after initial configuration (in the build directory):
> ⚠️ **Note:**
> Optional flash option when running within an installed MSDK to use OpenOCD. Mainline OpenOCD does not yet have the MAX32's flash algorithm integrated. If the MSDK is installed, flash-msdk can be run to utilize the the modified openocd with the algorithms.
<br>
## Notes on SAVELOG=1
Log export options are available for demo apps.
If `SAVELOG=1` is set during a build:
- Output logs are automatically saved into a `logs/` folder inside each application.
- Each application target (e.g., `blinky`, `blinky-clean`) has its own separate subfolder and timestamped `.log` files.
- Log files are ignored from Git version control.
Example:
```
apps/blinky/logs/blinky/blinky_20250425_134500.log
apps/blinky/logs/blinky-clean/blinky-clean_20250425_134512.log
```
<br>
## Cleaning Logs
You can remove all saved build logs across all apps by running:
```bash
cmake -DMAXIM_PATH=C:/MaximSDK .
make BOARD=apard32690 clean-logs
```
This deletes all `logs/` directories under `apps/blinky`, `apps/erase_firmware`, and `apps/self_update`.
<br>
## Flashing Example Applications
After building any of the demo applications (Blinky, Erase Firmware, or Self-Update), a UF2 file will be generated in:
```
build/apps/<application>/<application>.uf2
apps/<application>/_build/<board>/<application>-<board>.uf2
```
For example:
```
apps/blinky/blinky.uf2
apps/blinky/_build/<board>/blinky-<board>.uf2
```
### Flashing via Drag-and-Drop
1. **Enter bootloader mode** on your board:
- Typically, perform a **double-tap on the reset button** within **500 milliseconds**.
- The board will appear as a **USB mass storage device** (for example, named `3269BOOT`) in your operating system's **File Explorer** (Windows) or **Finder** (macOS) or **File Manager** (Linux).
- The board will appear as a **USB mass storage device** (for example, named `TINYUF2`) in your operating system's **File Explorer** (Windows) or **Finder** (macOS) or **File Manager** (Linux).
2. **Using your file explorer**, locate the `.uf2` file you built, and **drag and drop** it onto the mounted TinyUF2 USB drive.
3. The board will automatically reboot and begin running the new application.
### Flashing using make/cmake
To flash an application using the command line, you can use the `make` or `cmake` command:
```bash
make blinky-uf2
cmake --build . --target blinky-uf2
```
### Re-Entering Bootloader Mode
To flash a different application or return to bootloader mode:
@ -291,32 +333,47 @@ To flash a different application or return to bootloader mode:
- Perform another **double-tap** of the reset button within 500 milliseconds.
- The board will reappear as a USB mass storage device for new UF2 flashing.
<br>
> ⚠️ **Note:**
> If double-tap reset does not work (for example, if the running application has corrupted necessary flash metadata), you may need to manually reflash the TinyUF2 bootloader using a SWD debug tool such as J-Link or OpenOCD.
> Refer to your board's documentation for additional recovery options if needed.
<br>
## Port Directory Structure
Example directory tree for the MAX32690 port:
```
├── app.cmake
max32690
├── Makefile
├── README.md
├── _build
├── apps
│ ├── blinky
│ │ ├── Makefile
│ │ └── _build
│ ├── erase_firmware
│ │ ├── Makefile
│ │ └── _build
│ └── self_update
│ ├── Makefile
│ └── _build
├── board_flash.c
├── boards
│ ├── apard32690
│ ├── max32650evkit
│ ├── max32650fthr
│ ├── max32666evkit
│ ├── max32666fthr
│ ├── max32690evkit
│ └── max78002evkit
│ │ ├── board.h
│ │ └── board.mk
│ └── max32690evkit
│ ├── board.h
│ └── board.mk
├── boards.c
├── boards.h
├── CMakeLists.txt
├── family.cmake
├── linker
│ ├── max32650
│ ├── max32665
│ ├── max32690
│ └── max78002
├── README.md
│ ├── max32690_app.ld
│ ├── max32690_boot.ld
│ └── max32690_common.ld
├── port.mk
└── tusb_config.h
```

View file

@ -0,0 +1,19 @@
PORT = max32690
OUTNAME = blinky-$(BOARD)
BUILD_APPLICATION = 1
BUILD_NO_TINYUSB = 1
include ../../../make.mk
include ../../port.mk
SRC_C += \
apps/blinky/blinky.c \
include ../../../rules.mk
uf2: $(BUILD)/$(OUTNAME).uf2
$(BUILD)/$(OUTNAME).uf2: $(BUILD)/$(OUTNAME).hex
@echo CREATE $@
$(PYTHON3) $(TOP)/lib/uf2/utils/uf2conv.py -f $(UF2_FAMILY_ID) -c -o $@ $^

View file

@ -0,0 +1,19 @@
PORT = max32690
OUTNAME = erase_firmware-$(BOARD)
BUILD_APPLICATION = 1
BUILD_NO_TINYUSB = 1
include ../../../make.mk
include ../../port.mk
SRC_C += \
apps/erase_firmware/erase_firmware.c \
include ../../../rules.mk
uf2: $(BUILD)/$(OUTNAME).uf2
$(BUILD)/$(OUTNAME).uf2: $(BUILD)/$(OUTNAME).hex
@echo CREATE $@
$(PYTHON3) $(TOP)/lib/uf2/utils/uf2conv.py -f $(UF2_FAMILY_ID) -c -o $@ $^

View file

@ -0,0 +1,23 @@
PORT = max32690
OUTNAME = self-update-$(BOARD)
BUILD_APPLICATION = 1
BUILD_NO_TINYUSB = 1
CFLAGS += -DTINYUF2_SELF_UPDATE
include ../../../make.mk
include ../../port.mk
SRC_C += \
apps/self_update/self_update.c \
$(TOP)/$(PORT_DIR)/apps/self_update/_build/bootloader_bin.c \
include ../../../rules.mk
uf2: $(BUILD)/$(OUTNAME).uf2
$(BUILD)/$(OUTNAME).uf2: $(BUILD)/$(OUTNAME).hex
@echo CREATE $@
$(PYTHON3) $(TOP)/lib/uf2/utils/uf2conv.py -f $(UF2_FAMILY_ID) -c -o $@ $^

View file

@ -0,0 +1 @@
# No specific build requirements for the board.

View file

@ -0,0 +1 @@
# No specific build requirements for the board.

View file

@ -0,0 +1 @@
# No specific build requirements for the board.

View file

@ -1,5 +1,6 @@
set(MAX_DEVICE max32665)
set(JLINK_DEVICE max32666)
#set(JLINK_OPTION "-USB 801011822")
function(update_board TARGET)
endfunction()

View file

@ -0,0 +1 @@
# No specific build requirements for the board.

View file

@ -1,5 +1,6 @@
set(MAX_DEVICE max32665)
set(JLINK_DEVICE max32666)
#set(JLINK_OPTION "-USB 801011822")
function(update_board TARGET)
endfunction()

View file

@ -0,0 +1 @@
# No specific build requirements for the board.

View file

@ -1,5 +1,6 @@
set(MAX_DEVICE max32690)
set(JLINK_DEVICE ${MAX_DEVICE})
#set(JLINK_OPTION "-USB jtrace")
function(update_board TARGET)
endfunction()

View file

@ -0,0 +1 @@
# No specific build requirements for the board.

View file

@ -0,0 +1 @@
# No specific build requirements for the board.

119
ports/maxim/port.mk Normal file
View file

@ -0,0 +1,119 @@
UF2_FAMILY_ID = 0x7410520a
CROSS_COMPILE = arm-none-eabi-
JLINK_DEVICE = MAX32690
# Important locations in the hw support for MCU
MAX32_CMSIS = lib/mcu/analog/msdk/Libraries/CMSIS
MAX32_PERIPH = lib/mcu/analog/msdk/Libraries/PeriphDrivers
PERIPH_SRC = $(MAX32_PERIPH)/Source
FLASH_BOOT_SIZE := 0x8000 #32K
# Port Compiler Flags
CFLAGS += \
-mthumb \
-mabi=aapcs \
-mcpu=cortex-m4 \
# Flags for TUSB features
CFLAGS += \
-DCFG_TUSB_MCU=OPT_MCU_MAX32690 \
-DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
# Flags for the MAX32690 SDK
CFLAGS += \
-DTARGET=MAX32690 \
-DTARGET_REV=0x4131 \
-DMXC_ASSERT_ENABLE \
-DMAX32690 \
-DIAR_PRAGMAS=0 \
-DFLASH_BOOT_SIZE=$(FLASH_BOOT_SIZE) \
-DMAX_PERIPH_ID=18 \
# mcu driver cause following warnings
CFLAGS += \
-Wno-error=unused-parameter \
-Wno-error=strict-prototypes \
-Wno-error=old-style-declaration \
-Wno-error=sign-compare \
-Wno-error=cast-qual \
-Wno-lto-type-mismatch \
# default linker file
ifdef BUILD_APPLICATION
LD_FILES ?= \
$(PORT_DIR)/linker/max32690/max32690_app.ld \
$(PORT_DIR)/linker/max32690/max32690_common.ld
else
LD_FILES ?= \
$(PORT_DIR)/linker/max32690/max32690_boot.ld \
$(PORT_DIR)/linker/max32690/max32690_common.ld
endif
LDFLAGS += -nostartfiles -Wl,--defsym=__FLASH_BOOT_SIZE=${FLASH_BOOT_SIZE} \
# Port source
SRC_C += \
$(PORT_DIR)/boards.c \
$(PORT_DIR)/board_flash.c \
$(MAX32_CMSIS)/Device/Maxim/MAX32690/Source/heap.c \
$(MAX32_CMSIS)/Device/Maxim/MAX32690/Source/system_max32690.c \
$(PERIPH_SRC)/SYS/mxc_assert.c \
$(PERIPH_SRC)/SYS/mxc_delay.c \
$(PERIPH_SRC)/SYS/mxc_lock.c \
$(PERIPH_SRC)/SYS/nvic_table.c \
$(PERIPH_SRC)/SYS/pins_me18.c \
$(PERIPH_SRC)/SYS/sys_me18.c \
$(PERIPH_SRC)/CTB/ctb_me18.c \
$(PERIPH_SRC)/CTB/ctb_reva.c \
$(PERIPH_SRC)/CTB/ctb_common.c \
$(PERIPH_SRC)/FLC/flc_common.c \
$(PERIPH_SRC)/FLC/flc_me18.c \
$(PERIPH_SRC)/FLC/flc_reva.c \
$(PERIPH_SRC)/GPIO/gpio_common.c \
$(PERIPH_SRC)/GPIO/gpio_me18.c \
$(PERIPH_SRC)/GPIO/gpio_reva.c \
$(PERIPH_SRC)/ICC/icc_me18.c \
$(PERIPH_SRC)/ICC/icc_reva.c \
$(PERIPH_SRC)/UART/uart_common.c \
$(PERIPH_SRC)/UART/uart_me18.c \
$(PERIPH_SRC)/UART/uart_revb.c \
ifndef BUILD_NO_TINYUSB
SRC_C += lib/tinyusb/src/portable/mentor/musb/dcd_musb.c
endif
SRC_S += $(MAX32_CMSIS)/Device/Maxim/MAX32690/Source/GCC/startup_max32690.S
# Port include
INC += \
$(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
$(TOP)/$(MAX32_CMSIS)/Device/Maxim/MAX32690/Include \
$(TOP)/$(MAX32_PERIPH)/Include/MAX32690 \
$(TOP)/$(PERIPH_SRC)/SYS \
$(TOP)/$(PERIPH_SRC)/GPIO \
$(TOP)/$(PERIPH_SRC)/CTB \
$(TOP)/$(PERIPH_SRC)/ICC \
$(TOP)/$(PERIPH_SRC)/FLC \
$(TOP)/$(PERIPH_SRC)/UART
# By default use JLink to the flash the devices since OpenOCD requires ADI's
# OpenOCD fork until the part support can get mainlined. See flash-msdk below
# to use OpenOCD from ADI
flash: flash-jlink
erase: erase-jlink
# Optional flash option when running within an installed MSDK to use OpenOCD
# Mainline OpenOCD does not yet have the MAX32's flash algorithm integrated.
# If the MSDK is installed, flash-msdk can be run to utilize the the modified
# openocd with the algorithms
# Convert Windows-style \ to /
MAXIM_PATH := $(subst \,/,$(MAXIM_PATH))
flash-msdk: $(BUILD)/$(OUTNAME).elf
$(MAXIM_PATH)/Tools/OpenOCD/openocd -s $(MAXIM_PATH)/Tools/OpenOCD/scripts \
-f interface/cmsis-dap.cfg -f target/max32690.cfg \
-c "program $(BUILD)/$(OUTNAME).elf verify; init; reset; exit"

View file

@ -22,13 +22,11 @@ include ../rules.mk
# This uf2 will be loaded into RAM
# TODO: this needs to build the actual uf2 binary first
self-update: $(BUILD)/$(OUTNAME).bin
@echo "not implemented yet"
# $(PYTHON3) $(TOP)/lib/uf2/utils/uf2conv.py --carray $^ -o apps/self_update/_build/bootloader_bin.c
# $(MAKE) -C $(TOP)/$(PORT_DIR)/apps/self_update uf2
$(PYTHON3) $(TOP)/lib/uf2/utils/uf2conv.py --carray $^ -o apps/self_update/_build/bootloader_bin.c
$(MAKE) -C $(TOP)/$(PORT_DIR)/apps/self_update uf2
self-update-clean:
@echo "not implemented yet"
# $(MAKE) -C $(TOP)/$(PORT_DIR)/apps/self_update clean
$(MAKE) -C $(TOP)/$(PORT_DIR)/apps/self_update clean
#---------- Erase app ----------
# Compile apps/erase_firmware/erase_firmware.c

View file

@ -4,10 +4,12 @@ OUTNAME = erase_firmware-$(BOARD)
BUILD_NO_TINYUSB = 1
SRC_C += \
apps/erase_firmware/src/erase_firmware.c \
$(PORT_DIR)/boards.c \
$(PORT_DIR)/board_flash.c \
$(PORT_DIR)/board_irq.c \
apps/erase_firmware/erase_firmware.c \
$(TOP)/$(PORT_DIR)/boards.c \
$(TOP)/$(PORT_DIR)/board_flash.c \
$(TOP)/$(PORT_DIR)/board_irq.c \
$(TOP)/$(PORT_DIR)/components/w25qxx/w25qxx.c \
$(TOP)/$(PORT_DIR)/components/w25qxx/w25qxx_qspi.c \
INC += \
$(TOP)/src \

View file

@ -1,21 +1,18 @@
# OUTNAME = self_update-$(BOARD)
OUTNAME = self_update-$(BOARD)
# # skip tinyusb
# BUILD_NO_TINYUSB = 1
# skip tinyusb
BUILD_NO_TINYUSB = 1
# CFLAGS += -DTINYUF2_SELF_UPDATE
CFLAGS += -DTINYUF2_SELF_UPDATE
# SRC_C += \
# apps/self_update/self_update.c \
# $(TOP)/$(PORT_DIR)/apps/self_update/_build/bootloader_bin.c \
# $(TOP)/$(PORT_DIR)/boards.c \
# $(TOP)/$(PORT_DIR)/board_hmi.c \
# $(TOP)/$(PORT_DIR)/board_irq.c \
SRC_C += \
apps/self_update/self_update.c \
$(TOP)/$(PORT_DIR)/apps/self_update/_build/bootloader_bin.c \
$(TOP)/$(PORT_DIR)/boards.c \
$(TOP)/$(PORT_DIR)/board_hmi.c \
$(TOP)/$(PORT_DIR)/board_irq.c \
# INC += \
# $(TOP)/src \
INC += \
$(TOP)/src \
# include ../app.mk
all:
@echo "not implemented yet"
include ../app.mk

View file

@ -1,6 +1,5 @@
#include "board_api.h"
#include "stm32h7xx_hal.h"
#include "qspi_status.h"
#ifdef W25Qx_SPI
#include "components/w25qxx/w25qxx.h"
@ -10,16 +9,11 @@
#include "components/w25qxx/w25qxx_qspi.h"
#endif // W25Qx_QSPI
#ifdef IS25LP064A
#include "components/is25lp064a/is25lp064a_qspi.h"
#include "components/is25lp064a/is25lp064a.h"
#endif
#if defined (BOARD_QSPI_FLASH_EN) && (BOARD_QSPI_FLASH_EN == 1)
#if BOARD_QSPI_FLASH_EN
QSPI_HandleTypeDef _qspi_flash;
#endif // BOARD_QSPI_FLASH_EN
#if defined (BOARD_SPI_FLASH_EN) && (BOARD_SPI_FLASH_EN == 1)
#if BOARD_SPI_FLASH_EN
SPI_HandleTypeDef _spi_flash;
#endif // BOARD_SPI_FLASH_EN
@ -59,67 +53,6 @@ extern volatile uint32_t _board_tmp_boot_magic[];
#define TMP_BOOT_ADDR _board_tmp_boot_addr[0]
#define TMP_BOOT_MAGIC _board_tmp_boot_magic[0]
static void qspi_Init(void) {
#ifdef W25Qx_QSPI
w25qxx_Init();
#endif
#ifdef IS25LP064A
CSP_QSPI_DisableMemoryMappedMode();
CSP_QSPI_ExitQPIMODE();
if (CSP_QUADSPI_Init() != qspi_OK) {
TUF2_LOG1("Error initializing QSPI Flash\r\n");
}
#endif
}
static void qspi_EnterQPI(void) {
#ifdef W25Qx_QSPI
w25qxx_EnterQPI();
#endif
}
static void qspi_Startup(void) {
#ifdef W25Qx_QSPI
w25qxx_Startup(qspi_DTRMode);
#endif
#ifdef IS25LP064A
if (CSP_QSPI_EnableMemoryMappedMode() != qspi_OK) {
TUF2_LOG1("Error enabling memory map for QSPI Flash\r\n");
}
#endif
}
static uint8_t qspi_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size) {
#ifdef W25Qx_QSPI
return w25qxx_Read(pData,ReadAddr,Size);
#endif
#ifdef IS25LP064A
return CSP_QSPI_Read(pData, ReadAddr, Size);
#endif
return qspi_OK;
}
static uint8_t qspi_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size) {
#ifdef W25Qx_QSPI
return w25qxx_Write(pData,WriteAddr,Size);
#endif
#ifdef IS25LP064A
return CSP_QSPI_Write(pData,WriteAddr,Size);
#endif
return qspi_OK;
}
static void qspi_EraseChip(void) {
#ifdef W25Qx_QSPI
w25qxx_EraseChip();
#endif
#ifdef IS25LP064A
CSP_QSPI_Erase_Chip();
#endif
}
uint32_t board_get_app_start_address(void)
{
if (TMP_BOOT_MAGIC == 0xDEADBEEFU)
@ -146,19 +79,19 @@ void board_clear_temp_boot_addr(void)
void board_flash_early_init(void)
{
#if defined (BOARD_QSPI_FLASH_EN) && (BOARD_QSPI_FLASH_EN == 1)
#if BOARD_QSPI_FLASH_EN
// QSPI is initialized early to check for executable code
qspi_flash_init(&_qspi_flash);
// Initialize QSPI driver
qspi_Init();
w25qxx_Init();
// SPI -> QPI
qspi_EnterQPI();
w25qxx_EnterQPI();
#endif // BOARD_QSPI_FLASH_EN
}
void board_flash_init(void)
{
#if defined (BOARD_SPI_FLASH_EN) && (BOARD_SPI_FLASH_EN == 1)
#if BOARD_SPI_FLASH_EN
// Initialize SPI peripheral
spi_flash_init(&_spi_flash);
// Initialize SPI drivers
@ -168,10 +101,10 @@ void board_flash_init(void)
void board_flash_deinit(void)
{
#if defined (BOARD_QSPI_FLASH_EN) && (BOARD_QSPI_FLASH_EN == 1)
#if BOARD_QSPI_FLASH_EN
// Enable Memory Mapped Mode
// QSPI flash will be available at 0x90000000U (readonly)
qspi_Startup();
w25qxx_Startup(w25qxx_DTRMode);
#endif // BOARD_QSPI_FLASH_EN
}
@ -190,16 +123,16 @@ void board_flash_flush(void)
void board_flash_read(uint32_t addr, void * data, uint32_t len)
{
TUF2_LOG1("Reading %lu byte(s) from 0x%08lx\r\n", len, addr);
#if defined (BOARD_QSPI_FLASH_EN) && (BOARD_QSPI_FLASH_EN == 1)
#if BOARD_QSPI_FLASH_EN
// addr += QSPI_BASE_ADDR;
if (IS_QSPI_ADDR(addr))
{
(void) qspi_Read(data, addr - QSPI_BASE_ADDR, len);
(void) W25qxx_Read(data, addr - QSPI_BASE_ADDR, len);
return;
}
#endif
#if defined (BOARD_AXISRAM_EN) && (BOARD_AXISRAM_EN == 1)
#if BOARD_AXISRAM_EN
if (IS_AXISRAM_ADDR(addr) && IS_AXISRAM_ADDR(addr + len - 1))
{
memcpy(data, (void *) addr, len);
@ -223,11 +156,11 @@ bool board_flash_write(uint32_t addr, void const * data, uint32_t len)
{
TUF2_LOG1("Programming %lu byte(s) at 0x%08lx\r\n", len, addr);
// For external flash
// For external flash, W25Qx
// TODO: these should be configurable parameters
// Page size = 256 bytes
// Sector size = 4K bytes
#if defined (BOARD_SPI_FLASH_EN) && (BOARD_SPI_FLASH_EN == 1U)
#if (BOARD_SPI_FLASH_EN == 1U)
if (IS_SPI_ADDR(addr) && IS_SPI_ADDR(addr + len - 1))
{
W25Qx_Write((uint8_t *) data, (addr - SPI_BASE_ADDR), len);
@ -235,30 +168,20 @@ bool board_flash_write(uint32_t addr, void const * data, uint32_t len)
}
#endif
#if defined (BOARD_QSPI_FLASH_EN) && (BOARD_QSPI_FLASH_EN == 1)
#if (BOARD_QSPI_FLASH_EN == 1)
if (IS_QSPI_ADDR(addr) && IS_QSPI_ADDR(addr + len - 1))
{
// SET_BOOT_ADDR(BOARD_AXISRAM_APP_ADDR);
// handles erasing internally
#ifdef IS25LP064A
// flash needs to be erased before writing
if (addr % IS25LP064A_SECTOR_SIZE == 0) {
// erase 4k sector ahead of next page writes
if (CSP_QSPI_EraseSector(addr, addr+IS25LP064A_SECTOR_SIZE) != qspi_OK) {
TUF2_LOG1("Error erasing sector at address: %lx \r\n",addr);
}
}
#endif
if (qspi_Write((uint8_t *)data, (addr - QSPI_BASE_ADDR), len) != qspi_OK)
if (W25qxx_Write((uint8_t *)data, (addr - QSPI_BASE_ADDR), len) != w25qxx_OK)
{
TUF2_LOG1("Error QSPI Flash write\r\n");
__asm("bkpt #9");
}
return true;
}
#endif
#if defined (BOARD_AXISRAM_EN) && (BOARD_AXISRAM_EN == 1)
#if BOARD_AXISRAM_EN
if (IS_AXISRAM_ADDR(addr) && IS_AXISRAM_ADDR(addr + len - 1))
{
// This memory is cached, DCache is cleaned in dfu_complete
@ -288,13 +211,13 @@ void board_flash_erase_app(void)
{
board_flash_init();
#if defined (BOARD_QSPI_FLASH_EN) && (BOARD_QSPI_FLASH_EN == 1)
#if BOARD_QSPI_FLASH_EN
TUF2_LOG1("Erasing QSPI Flash\r\n");
// Erase QSPI Flash
(void) qspi_EraseChip();
(void) W25qxx_EraseChip();
#endif
#if defined(BOARD_SPI_FLASH_EN) && (BOARD_SPI_FLASH_EN == 1)
#if BOARD_SPI_FLASH_EN
TUF2_LOG1("Erasing SPI Flash\r\n");
// Erase QSPI Flash
(void) W25Qx_Erase_Chip();

View file

@ -19,44 +19,49 @@ void ST7735_Delay(uint32_t ms)
{
HAL_Delay(ms);
}
#endif
void board_display_init(void)
{
#if (TINYUF2_DISPLAY == 1U)
display_init(&_display_spi);
ST7735_Init();
// Clear previous screen
ST7735_FillScreen(ST7735_BLACK);
#endif // TINYUF2_DISPLAY == 1U
}
// The application draws a complete frame in memory and sends it
// line-by-line to the display
void board_display_draw_line(int y, uint16_t* pixel_color, uint32_t pixel_num)
{
#if (TINYUF2_DISPLAY == 1U)
for (uint32_t x = 0; x < pixel_num; x += 1) {
ST7735_DrawPixel(y, x, pixel_color[x]);
}
}
#endif // TINYUF2_DISPLAY == 1U
}
//--------------------------------------------------------------------+
// LED pattern
//--------------------------------------------------------------------+
#if defined(TINYUF2_LED)
void board_led_write(uint32_t state)
{
#if defined(TINYUF2_LED)
HAL_GPIO_WritePin(LED_PORT, LED_PIN, state ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
#endif // defined(LED_PIN)
}
//--------------------------------------------------------------------+
// Button
//--------------------------------------------------------------------+
#if defined(BUTTON_PIN)
uint32_t board_button_read(void)
{
#if defined(BUTTON_PIN)
return (BUTTON_STATE_ACTIVE == HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) ? 1: 0;
}
#endif // defined(BUTTON_PIN)
}
//--------------------------------------------------------------------+
// Neopixel color for status

View file

@ -1,27 +1,8 @@
#include "stm32h7xx_hal.h"
#include "board_api.h"
#include <stdint.h>
#define STM32_UUID ((uint32_t *)0x1FF1E800)
#ifdef UART_DEV
static UART_HandleTypeDef UartHandle;
#endif
// fixes for linker warnings: _syscall is not implemented and will always fail
void __weak _close(void) {
}
void __weak _lseek(void) {
}
void __weak _read(void) {
}
void __weak _write(void) {
}
void __weak _fstat(void) {
}
void __weak _isatty(void) {
}
void board_init(void)
{
SCB_EnableICache();
@ -45,31 +26,9 @@ void board_init(void)
__HAL_RCC_GPIOI_CLK_ENABLE();
__HAL_RCC_GPIOJ_CLK_ENABLE();
__HAL_RCC_GPIOK_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
// UART
#ifdef UART_DEV
UART_CLOCK_ENABLE();
GPIO_InitStruct.Pin = UART_TX_PIN | UART_RX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = UART_GPIO_AF;
HAL_GPIO_Init(UART_GPIO_PORT, &GPIO_InitStruct);
UartHandle.Instance = UART_DEV;
UartHandle.Init.BaudRate = 115200;
UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
UartHandle.Init.StopBits = UART_STOPBITS_1;
UartHandle.Init.Parity = UART_PARITY_NONE;
UartHandle.Init.Mode = UART_MODE_TX_RX;
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
UartHandle.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
UartHandle.Init.ClockPrescaler = UART_PRESCALER_DIV1;
UartHandle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
HAL_UART_Init(&UartHandle);
#endif
memset(&GPIO_InitStruct,0,sizeof(GPIO_InitStruct));
GPIO_InitTypeDef GPIO_InitStruct;
#ifdef BUTTON_PIN
GPIO_InitStruct.Pin = BUTTON_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
@ -94,8 +53,8 @@ void board_init(void)
void board_dfu_init(void)
{
// Not quite sure what an RHPORT is :/
#if defined (BOARD_TUD_RHPORT) && (BOARD_TUD_RHPORT == 0)
GPIO_InitTypeDef GPIO_InitStruct = {0};
#if BOARD_TUD_RHPORT == 0
GPIO_InitTypeDef GPIO_InitStruct;
// Init USB Pins
// Configure DM DP pins
@ -122,7 +81,7 @@ void board_dfu_init(void)
USB_OTG_FS->GOTGCTL |= USB_OTG_GOTGCTL_BVALOEN;
USB_OTG_FS->GOTGCTL |= USB_OTG_GOTGCTL_BVALOVAL;
#elif defined (BOARD_TUD_RHPORT) && (BOARD_TUD_RHPORT == 1)
#elif BOARD_TUD_RHPORT == 1
// TODO: implement whatever this is
#error "Sorry, not implemented yet"
#endif
@ -153,8 +112,8 @@ bool board_app_valid(void)
switch ((app_vector[0] & 0xFFFF0003u))
{
case 0x00000000u: // ITCM 64K [0x0000_0000u--0x0000_FFFFu]
case 0x20010000u: // DTCM 64K [0x2000_0000u--0x2000_FFFFu]
case 0x20020000u: // DTCM 64K [0x2001_0000u--0x2001_FFFFu]
case 0x20000000u: // DTCM 64K [0x2000_0000u--0x2000_FFFFu]
case 0x20010000u: // DTCM 64K [0x2001_0000u--0x2001_FFFFu]
case 0x24000000u: // AXI SRAM 512K [0x2400_0000u--0x2407_FFFFu]
case 0x30010000u: // SRAM1 64K [0x3001_0000u--0x3001_FFFFu]
case 0x30020000u: // SRAM2 64K [0x3002_0000u--0x3002_FFFFu]
@ -211,32 +170,16 @@ void board_app_jump(void)
__HAL_RCC_GPIOJ_CLK_DISABLE();
__HAL_RCC_GPIOK_CLK_DISABLE();
// Lotsa GPIOs
uint8_t allow_rcc_deinit = 1;
// rcc clock needs to be enabled when executing code from external flash
#if defined(BOARD_QSPI_FLASH_EN) && (BOARD_QSPI_FLASH_EN == 1)
allow_rcc_deinit = 0;
#endif
#if defined(BOARD_SPI_FLASH_EN) && (BOARD_SPI_FLASH_EN == 1)
allow_rcc_deinit = 0;
#endif
if (allow_rcc_deinit) {
HAL_RCC_DeInit();
}
SCB_DisableICache();
SCB_DisableDCache();
// Clear temporary boot address
board_clear_temp_boot_addr();
#ifdef UART_DEV
HAL_UART_DeInit(&UartHandle);
HAL_GPIO_DeInit(UART_GPIO_PORT, UART_TX_PIN | UART_RX_PIN);
UART_CLOCK_DISABLE();
#endif
// Setup VTOR to point to application vectors
SCB->VTOR = (uint32_t) app_addr;
// Set stack pointer
__set_MSP(app_vector[0]);
@ -244,11 +187,6 @@ uint8_t allow_rcc_deinit = 1;
TUF2_LOG1("App address: %08lx\r\n", app_vector[1]);
// Setup VTOR to point to application vectors
__DMB(); //ARM says to use a DMB instruction before relocating VTOR */
SCB->VTOR = (uint32_t) app_addr;
__DSB(); //ARM says to use a DSB instruction just after relocating VTOR */
// Jump to application reset vector
asm("bx %0" :: "r"(app_vector[1]));
@ -279,14 +217,9 @@ void board_timer_stop(void)
int board_uart_write(void const * buf, int len)
{
#ifdef UART_DEV
HAL_UART_Transmit(&UartHandle, (uint8_t*) buf, len, 0xFFFFFFFFU);
return len;
#else
(void) buf;
(void) len;
return 0;
#endif
}
#ifdef TINYUF2_SELF_UPDATE

View file

@ -1,240 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2025 @snkYmkrct
*
* 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 BOARD_H_
#define BOARD_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------+
// LED
//--------------------------------------------------------------------+
#define LED_PORT GPIOC
#define LED_PIN GPIO_PIN_7
#define LED_STATE_ON 1
//--------------------------------------------------------------------+
// BUTTON
//--------------------------------------------------------------------+
#define BUTTON_PORT GPIOG
#define BUTTON_PIN GPIO_PIN_3
#define BUTTON_STATE_ACTIVE 0
//--------------------------------------------------------------------+
// Flash
//--------------------------------------------------------------------+
// Flash size of the board
#define BOARD_FLASH_SIZE (128 * 1024)
#define BOARD_FLASH_SECTORS 1
//--------------------------------------------------------------------+
// External QSPI Flash
//--------------------------------------------------------------------+
#define BOARD_QSPI_FLASH_SIZE (8 * 1024 * 1024) // 8MB
//--------------------------------------------------------------------+
// USB UF2
//--------------------------------------------------------------------+
#define USB_VID 0x0483
#define USB_PID 0x5740
#define USB_MANUFACTURER "STM32"
#define USB_PRODUCT "STM32FH750IB"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "STM32FH750IB-DaisySeed"
#define UF2_VOLUME_LABEL "DaisyBOOT"
#define UF2_INDEX_URL "https://electro-smith.com/products/daisy-seed"
#define USB_NO_VBUS_PIN 1
#define BOARD_TUD_RHPORT 0
//--------------------------------------------------------------------+
// UART
//--------------------------------------------------------------------+
#define UART_DEV UART4
#define UART_CLOCK_ENABLE __HAL_RCC_UART4_CLK_ENABLE
#define UART_CLOCK_DISABLE __HAL_RCC_UART4_CLK_DISABLE
#define UART_GPIO_PORT GPIOB
#define UART_GPIO_AF GPIO_AF8_UART4
#define UART_TX_PIN GPIO_PIN_9
#define UART_RX_PIN GPIO_PIN_8
static void Error_Handler(void) {
__disable_irq();
while (1) {
}
}
//--------------------------------------------------------------------+
// RCC Clock
//--------------------------------------------------------------------+
static inline void clock_init(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
// Set voltage scaling in accordance with system clock speed
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {
}
// Configure LSE Drive
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
// Set up primary PLL and HSE clocks
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.OscillatorType |= RCC_OSCILLATORTYPE_LSI;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.OscillatorType |= RCC_OSCILLATORTYPE_HSI48;
RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 50;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 4;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
// Configure bus clock sources and divisors
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 |
RCC_CLOCKTYPE_D3PCLK1 | RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
// Set up non-bus peripherals
PeriphClkInitStruct.PeriphClockSelection =
RCC_PERIPHCLK_UART4 | RCC_PERIPHCLK_USB;
// UART4
PeriphClkInitStruct.Usart234578ClockSelection =
RCC_USART234578CLKSOURCE_D2PCLK1;
// USB
PeriphClkInitStruct.PLL3.PLL3M = 1;
PeriphClkInitStruct.PLL3.PLL3N = 12;
PeriphClkInitStruct.PLL3.PLL3P = 2;
PeriphClkInitStruct.PLL3.PLL3Q = 4;
PeriphClkInitStruct.PLL3.PLL3R = 2;
PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_3;
PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLL3;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
Error_Handler();
}
// Enable USB Voltage detector
HAL_PWREx_EnableUSBVoltageDetector();
}
//--------------------------------------------------------------------+
// QSPI and SPI FLash
//--------------------------------------------------------------------+
static inline void qspi_flash_init(QSPI_HandleTypeDef *qspiHandle) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_QSPI;
PeriphClkInitStruct.QspiClockSelection = RCC_QSPICLKSOURCE_PLL;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
Error_Handler();
}
/* QUADSPI clock enable */
__HAL_RCC_QSPI_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
/**QUADSPI GPIO Configuration
PG6 ------> QUADSPI_BK1_NCS
PF7 ------> QUADSPI_BK1_IO2
PF6 ------> QUADSPI_BK1_IO3
PF10 ------> QUADSPI_CLK
PF9 ------> QUADSPI_BK1_IO1
PF8 ------> QUADSPI_BK1_IO0
*/
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_7 | GPIO_PIN_6 | GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
qspiHandle->Instance = QUADSPI;
qspiHandle->Init.ClockPrescaler = 1;
qspiHandle->Init.FifoThreshold = 1;
qspiHandle->Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
qspiHandle->Init.FlashSize = 22;
qspiHandle->Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;
qspiHandle->Init.ClockMode = QSPI_CLOCK_MODE_0;
qspiHandle->Init.FlashID = QSPI_FLASH_ID_1;
qspiHandle->Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(qspiHandle) != HAL_OK) {
Error_Handler();
}
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,18 +0,0 @@
QSPI_FLASH = IS25LP064A
CFLAGS += \
-DSTM32H750xx \
-DHSE_VALUE=16000000U \
-DTINYUF2_LED=1 \
-DBOARD_QSPI_FLASH_EN=1 \
-DBOARD_AXISRAM_EN=1 \
-D$(QSPI_FLASH)\
-DBOARD_FLASH_APP_START=0x90000000 \
-DTRAP_EXC \
MCU = h750xx
LOG = 0
SRC_S += \
$(ST_CMSIS)/Source/Templates/gcc/startup_stm32h750xx.s

View file

@ -1,7 +1,6 @@
SPI_FLASH = W25Qx_SPI
QSPI_FLASH = W25Qx_QSPI
DISPLAY_DRV = ST7735
JLINK_DEVICE = stm32h750vb
CFLAGS += \
-DSTM32H750xx \

View file

@ -1,130 +0,0 @@
/*
* IS25LP064A.h
*
* Adapted from https://github.com/electro-smith/libDaisy/blob/master/src/dev/flash_IS25LP064A.h
*
*/
#ifndef INC_FLASH_IS25LP064A_H_
#define INC_FLASH_IS25LP064A_H_
#ifdef __cplusplus
extern "C" {
#endif
#define IS25LP064A_FLASH_SIZE 0x800000 /* 8 MBytes*/
#define IS25LP064A_BLOCK_SIZE 0x10000 /* 64 KBytes */
#define IS25LP064A_SECTOR_SIZE 0x1000 /* 4 KBytes */
#define IS25LP064A_PAGE_SIZE 0x100 /* 256 bytes */
#define IS25LP064A_SECTOR_COUNT 2048
#define IS25LP064A_DUMMY_CYCLES_READ_QUAD 6 /* & */
#define IS25LP064A_DUMMY_CYCLES_READ 6 /* & */
//#define IS25LP064A_DUMMY_CYCLES_READ_DTR 6 /* & */
//#define IS25LP064A_DUMMY_CYCLES_READ_QUAD_DTR 6 /* & */
#define IS25LP064A_DIE_ERASE_MAX_TIME 46000 /* 45 max seconds in datasheet */
#define IS25LP064A_BLOCK_ERASE_MAX_TIME 1100 /* 1000 ms max in datasheet */
#define IS25LP064A_SECTOR_ERASE_MAX_TIME 350 /* 300 ms max in datasheet */
/* Low Power Modes */
#define ENTER_DEEP_POWER_DOWN 0XB9 /* & */
#define EXIT_DEEP_POWER_DOWN 0XAB /* Release from Power-down/Read Device ID instruction */
/* Software Reset Operation commands */
#define RESET_ENABLE_CMD 0x66
#define RESET_MEMORY_CMD 0x99 /* & */
/* Identification Operations */
#define READ_ID_CMD 0xAB /* Release from Power-down/Read Device ID instruction */
#define READ_ID_CMD2 0x9F /* JEDEC ID READ command in SPI mode */
#define MULTIPLE_IO_READ_ID_CMD 0xAF /* JEDEC ID READ command in QPI mode */
#define READ_SERIAL_FLASH_DISCO_PARAM_CMD 0x5A /* Serial Flash Discoverable Parameters (SFDP) */
#define READ_MANUFACT_AND_ID 0x90 /* Read Product Identification (RDID) instruction */
#define READ_UNIQUE_ID 0x4B /* Read Unique ID Number (RDUID) */
#define NO_OP 0x00 /* Cancels Reset Enable */
/* Sector LOCK/UNLOCK Operations */
#define SECTOR_UNLOCK 0x26 /**< & */
#define SECTOR_LOCK 0x24 /**< & */
/* Security Information Row */
#define INFO_ROW_ERASE_CMD 0x64 /* Information Row Erase (IRER) instruction */
#define INFO_ROW_PROGRAM_CMD 0x62 /* Information Row Program (IRP) instruction */
#define INFO_ROW_READ_CMD 0x68 /* Information Row Read (IRRD) instruction */
/* Read Operations */
#define READ_CMD 0x03 /* NORMAL READ (NORD) instruction */
#define FAST_READ_CMD 0x0B /* FAST READ (FRD) instruction for both 1 line and QPI modes */
#define FAST_READ_DTR_CMD 0x0D /* FRDTR instruction */
#define DUAL_OUT_FAST_READ_CMD 0x3B /* FAST READ DUAL OUTPUT OPERATION (FRDO) */
#define DUAL_INOUT_FAST_READ_CMD 0xBB /* FAST READ DUAL I/O OPERATION (FRDIO) */
#define DUAL_INOUT_FAST_READ_DTR_CMD 0xBD /* FAST READ DUAL IO DTR MODE OPERATION (FRDDTR) */
#define QUAD_OUT_FAST_READ_CMD 0x6B /* FAST READ QUAD OUTPUT OPERATION (FRQO) */
#define QUAD_INOUT_FAST_READ_CMD 0xEB /* FAST READ QUAD I/O OPERATION (FRQIO) - can be used to enable memory mapped mode */
#define QUAD_INOUT_FAST_READ_DTR_CMD 0xED /* FAST READ QUAD IO DTR MODE OPERATION (FRQDTR) */
/* Write Operations */
#define WRITE_ENABLE_CMD 0x06 /* WRITE ENABLE OPERATION (WREN) */
#define WRITE_DISABLE_CMD 0x04 /* WRITE DISABLE OPERATION (WRDI) */
/* Register Operations */
#define READ_STATUS_REG_CMD 0x05 /* READ STATUS REGISTER OPERATION (RDSR) */
#define WRITE_STATUS_REG_CMD 0x01 /* WRITE STATUS REGISTER OPERATION (WRSR) */
#define READ_FUNCTION_REGISTER 0X48 /* READ FUNCTION REGISTER OPERATION (RDFR) */
#define WRITE_FUNCTION_REGISTER 0x42 /* WRITE FUNCTION REGISTER OPERATION (WRFR) */
#define WRITE_READ_PARAM_REG_CMD 0xC0 /* SET READ PARAMETERS OPERATION (SRP) */
/* Page Program Operations */
#define PAGE_PROG_CMD 0x02 /* PAGE PROGRAM OPERATION (PP) */
/* QUAD INPUT PAGE PROGRAM OPERATION (PPQ) */
#define QUAD_IN_PAGE_PROG_CMD 0x32
#define EXT_QUAD_IN_PAGE_PROG_CMD 0x38
/* Erase Operations */
#define SECTOR_ERASE_CMD 0xd7 /* SECTOR ERASE OPERATION (S E R) on SPI */
#define SECTOR_ERASE_QPI_CMD 0x20 /* SECTOR ERASE OPERATION (S E R) QPI */
#define BLOCK_ERASE_CMD 0xD8 /* BLOCK ERASE OPERATION (BER64K) */
#define BLOCK_ERASE_32K_CMD 0x52 /* BLOCK ERASE OPERATION (BER32K) */
#define CHIP_ERASE_CMD 0xC7 /* CHIP ERASE OPERATION (CER) on SPI */
#define EXT_CHIP_ERASE_CMD 0x60 /* CHIP ERASE OPERATION (CER) on QPI*/
#define PROG_ERASE_RESUME_CMD 0x7A /* Resume program/erase (PERRSM) on SPI */
#define EXT_PROG_ERASE_RESUME_CMD 0x30 /* Resume program/erase (PERRSM) on QPI */
#define PROG_ERASE_SUSPEND_CMD 0x75 /* Suspend during program/erase (PERSUS) on SPI */
#define EXT_PROG_ERASE_SUSPEND_CMD 0xB0 /* Suspend during program/erase (PERSUS) on QPI */
/** Quad Operations */
#define ENTER_QUAD_CMD 0x35 /* ENTER QUAD PERIPHERAL INTERFACE (QPI) MODE OPERATION (QIOEN) */
#define EXIT_QUAD_CMD 0xF5 /* EXIT QUAD PERIPHERAL INTERFACE (QPI) MODE OPERATION (QIODI) */
/* Status Register */
#define IS25LP064A_SR_WIP ((uint8_t)0x01) /* WIP Write in progress */
#define IS25LP064A_SR_WREN ((uint8_t)0x02) /* W E L Write enable latch */
//#define IS25LP064A_SR_BLOCKPR ((uint8_t)0x5C) /*!< Block protected against program and erase operations */
//#define IS25LP064A_SR_PRBOTTOM ((uint8_t)0x20) /*!< Protected memory area defined by BLOCKPR starts from top or bottom */
#define IS25LP064A_SR_QE ((uint8_t)0x40) /* QE Quad Enable */
#define IS25LP064A_SR_SRWREN ((uint8_t)0x80) /* SRWD Status Register Write Disable*/
#ifdef __cplusplus
}
#endif
#endif /* INC_FLASH_IS25LP064A_H_ */

View file

@ -1,567 +0,0 @@
#include "is25lp064a_qspi.h"
#include "is25lp064a.h"
#include "qspi_status.h"
#include "stm32h7xx_hal.h"
#include <stdint.h>
#define MEMORY_FLASH_SIZE 0x800000 /* 8 MBytes*/
#define MEMORY_SECTOR_SIZE 0x1000 /* 4 KBytes */
#define MEMORY_PAGE_SIZE 0x100 /* 256 bytes */
extern QSPI_HandleTypeDef _qspi_flash;
static uint8_t qspi_enabled = 0;
static uint8_t QSPI_Wait(QSPI_AutoPollingTypeDef *config, uint32_t timeout) {
QSPI_CommandTypeDef sCommand = {0};
if (qspi_enabled) {
sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
sCommand.DataMode = QSPI_DATA_4_LINES;
// Based on Reference manual RM0433 for the STM32H750 Value line,
// dummy cycles needed on all read operations in QUAD mode
sCommand.DummyCycles = IS25LP064A_DUMMY_CYCLES_READ_QUAD;
} else {
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.DataMode = QSPI_DATA_1_LINE;
sCommand.DummyCycles = 0;
}
sCommand.Instruction = READ_STATUS_REG_CMD;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
if (HAL_QSPI_AutoPolling(&_qspi_flash, &sCommand, config, timeout) !=
HAL_OK) {
return qspi_ERROR;
}
return qspi_OK;
}
static uint8_t QSPI_ReadStatusRegister(uint8_t *status) {
QSPI_CommandTypeDef sCommand = {0};
if (qspi_enabled) {
sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
sCommand.DataMode = QSPI_DATA_4_LINES;
// Based on Reference manual RM0433 for the STM32H750 Value line,
// dummy cycles needed on all read operations in QUAD mode
sCommand.DummyCycles = IS25LP064A_DUMMY_CYCLES_READ_QUAD;
} else {
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.DataMode = QSPI_DATA_1_LINE;
sCommand.DummyCycles = 0;
}
sCommand.Instruction = READ_STATUS_REG_CMD;
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.Address = 0;
sCommand.NbData = 1;
if (HAL_QSPI_Command(&_qspi_flash, &sCommand,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
if (HAL_QSPI_Receive(&_qspi_flash, status, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) !=
HAL_OK) {
return qspi_ERROR;
}
return qspi_OK;
}
static uint8_t QSPI_ResetChip(void) {
QSPI_CommandTypeDef sCommand = {0};
QSPI_AutoPollingTypeDef sConfig = {0};
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
sCommand.Instruction = RESET_ENABLE_CMD;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.Address = 0;
sCommand.DataMode = QSPI_DATA_NONE;
sCommand.DummyCycles = 0;
if (HAL_QSPI_Command(&_qspi_flash, &sCommand,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
sCommand.Instruction = RESET_MEMORY_CMD;
if (HAL_QSPI_Command(&_qspi_flash, &sCommand,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
sConfig.Match = 0;
sConfig.Mask = IS25LP064A_SR_WIP;
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 1;
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
sConfig.Interval = 0x10;
if (QSPI_Wait(&sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
return qspi_OK;
}
static uint8_t QSPI_WriteEnable(void) {
QSPI_CommandTypeDef sCommand = {0};
QSPI_AutoPollingTypeDef sConfig = {0};
/* Enable write / erase operations */
if (qspi_enabled) {
sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
} else {
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
}
sCommand.Instruction = WRITE_ENABLE_CMD;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = QSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
if (HAL_QSPI_Command(&_qspi_flash, &sCommand,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
/* Configure automatic polling mode to wait for write enabling */
sConfig.Match = IS25LP064A_SR_WREN;
sConfig.Mask = IS25LP064A_SR_WREN;
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 1;
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
sConfig.Interval = 0x10;
if (QSPI_Wait(&sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
return qspi_OK;
}
/*Enable quad mode and set dummy cycles count*/
static uint8_t QSPI_Configuration(void) {
QSPI_CommandTypeDef sCommand = {0};
QSPI_AutoPollingTypeDef sConfig = {0};
uint8_t reg = 0;
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
sCommand.Instruction = WRITE_READ_PARAM_REG_CMD;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.DataMode = QSPI_DATA_1_LINE;
sCommand.DummyCycles = 0;
sCommand.NbData = 1;
if (HAL_QSPI_Command(&_qspi_flash, &sCommand,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
/* Minimum necessary dummy cycles for memory mapped mode at 100 MHz = 6
* Setting in Read Register P4 P3 bits as 0 0, so full reg = 11100000 0xE0
* see IS25LP064A data sheet section 6.3 READ REGISTER */
reg = 0xE0;
if (HAL_QSPI_Transmit(&_qspi_flash, &reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) !=
HAL_OK) {
return qspi_ERROR;
}
sConfig.Match = 0;
sConfig.Mask = IS25LP064A_SR_WIP;
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 1;
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
sConfig.Interval = 0x10;
if (QSPI_Wait(&sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
/*----- Setting the QSPI mode ----*/
/* Set the non-volatile Quad Enable bit in status register */
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = WRITE_STATUS_REG_CMD;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = QSPI_DATA_1_LINE;
sCommand.DummyCycles = 0;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
sCommand.NbData = 1;
if (QSPI_WriteEnable() != HAL_OK) {
return qspi_ERROR;
}
if (HAL_QSPI_Command(&_qspi_flash, &sCommand,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
reg = 0;
if (QSPI_ReadStatusRegister(&reg) != HAL_OK) {
return qspi_ERROR;
}
reg = reg | IS25LP064A_SR_QE;
if (HAL_QSPI_Transmit(&_qspi_flash, &reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) !=
HAL_OK) {
return qspi_ERROR;
}
/* Configure automatic polling mode to wait for quad enable complete */
sConfig.Match = IS25LP064A_SR_QE;
sConfig.Mask = IS25LP064A_SR_QE;
if (QSPI_Wait(&sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
/* Wait to make sure controller is done with writing */
sConfig.Match = 0;
sConfig.Mask = IS25LP064A_SR_WIP;
if (QSPI_Wait(&sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
/* Enter QPI mode */
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = ENTER_QUAD_CMD;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = QSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
sCommand.NbData = 0;
if (HAL_QSPI_Command(&_qspi_flash, &sCommand,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
qspi_enabled = 1; /* qpi mode ON */
return qspi_OK;
}
uint8_t CSP_QSPI_Erase_Chip(void) {
QSPI_CommandTypeDef sCommand = {0};
QSPI_AutoPollingTypeDef sConfig = {0};
if (QSPI_WriteEnable() != HAL_OK) {
return qspi_ERROR;
}
sCommand.Instruction = EXT_CHIP_ERASE_CMD;
sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.Address = 0;
sCommand.DataMode = QSPI_DATA_NONE;
sCommand.DummyCycles = 0;
if (HAL_QSPI_Command(&_qspi_flash, &sCommand,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
// Poll until the max chip erase time
sConfig.Match = 0;
sConfig.Mask = IS25LP064A_SR_WIP;
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 1;
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
sConfig.Interval = 0x10;
if (QSPI_Wait(&sConfig, IS25LP064A_DIE_ERASE_MAX_TIME) != HAL_OK) {
return qspi_ERROR;
}
return qspi_OK;
}
uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress,
uint32_t EraseEndAddress) {
QSPI_CommandTypeDef sCommand = {0};
QSPI_AutoPollingTypeDef sConfig = {0};
/* Erasing Sequence -------------------------------------------------- */
sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
sCommand.Instruction = SECTOR_ERASE_QPI_CMD;
sCommand.AddressMode = QSPI_ADDRESS_4_LINES;
sCommand.DataMode = QSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sConfig.Match = 0;
sConfig.Mask = IS25LP064A_SR_WIP;
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 1;
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
sConfig.Interval = 0x10;
EraseStartAddress =
EraseStartAddress - EraseStartAddress % IS25LP064A_SECTOR_SIZE;
while (EraseEndAddress >= EraseStartAddress) {
sCommand.Address = (EraseStartAddress & 0x7FFFFF);
if (QSPI_WriteEnable() != HAL_OK) {
return qspi_ERROR;
}
if (HAL_QSPI_Command(&_qspi_flash, &sCommand,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
EraseStartAddress += IS25LP064A_SECTOR_SIZE;
if (QSPI_Wait(&sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
}
return qspi_OK;
}
uint8_t CSP_QSPI_EnableMemoryMappedMode(void) {
QSPI_CommandTypeDef sCommand = {0};
QSPI_MemoryMappedTypeDef sMemMappedCfg = {0};
/* Enable Memory-Mapped mode
The FRQIO instruction allows the address bits to be input four bits at a time.
This may allow for code to be executed directly from the SPI in some
applications. Sending the mode bits as AX (X = doesn't matter) will set the
flash controller in memory mapped mode.
*/
sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
sCommand.Instruction = QUAD_INOUT_FAST_READ_CMD;
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
sCommand.AddressMode = QSPI_ADDRESS_4_LINES;
sCommand.DataMode = QSPI_DATA_4_LINES;
sCommand.NbData = 0;
sCommand.Address = 0;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES;
sCommand.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS;
sCommand.AlternateBytes = 0x000000A0;
sCommand.DummyCycles = IS25LP064A_DUMMY_CYCLES_READ_QUAD - 2;
sCommand.SIOOMode = QSPI_SIOO_INST_ONLY_FIRST_CMD;
sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
if (HAL_QSPI_MemoryMapped(&_qspi_flash, &sCommand, &sMemMappedCfg) !=
HAL_OK) {
return qspi_ERROR;
}
return HAL_OK;
}
uint8_t CSP_QSPI_DisableMemoryMappedMode(void) {
QSPI_CommandTypeDef sCommand = {0};
uint8_t data;
// Need to first stop the host controller's access to flash
if (HAL_QSPI_Abort(&_qspi_flash) != HAL_OK) {
return qspi_ERROR;
}
sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
sCommand.Instruction = QUAD_INOUT_FAST_READ_CMD;
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
sCommand.AddressMode = QSPI_ADDRESS_4_LINES;
sCommand.DataMode = QSPI_DATA_4_LINES;
sCommand.NbData = 1;
sCommand.Address = 0;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES;
sCommand.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS;
sCommand.AlternateBytes = 0x00000000;
sCommand.DummyCycles = IS25LP064A_DUMMY_CYCLES_READ_QUAD;
sCommand.SIOOMode = QSPI_SIOO_INST_ONLY_FIRST_CMD;
if (HAL_QSPI_Command(&_qspi_flash, &sCommand,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
if (HAL_QSPI_Receive(&_qspi_flash, &data, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) !=
HAL_OK) {
return qspi_ERROR;
}
return qspi_OK;
}
uint8_t CSP_QSPI_Write(uint8_t *buffer, uint32_t address,
uint32_t buffer_size) {
QSPI_CommandTypeDef sCommand = {0};
QSPI_AutoPollingTypeDef sConfig = {0};
uint32_t end_addr = 0, current_size = 0, current_addr = 0;
/* Calculation of the size between the write address and the end of the page
*/
current_addr = 0;
while (current_addr <= address) {
current_addr += IS25LP064A_PAGE_SIZE;
}
current_size = current_addr - address;
/* Check if the size of the data is less than the remaining place in the page
*/
if (current_size > buffer_size) {
current_size = buffer_size;
}
/* Initialize the address variables */
current_addr = address;
end_addr = address + buffer_size;
sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
sCommand.Instruction = PAGE_PROG_CMD;
sCommand.AddressMode = QSPI_ADDRESS_4_LINES;
sCommand.DataMode = QSPI_DATA_4_LINES;
sCommand.NbData = buffer_size;
sCommand.Address = address;
sCommand.DummyCycles = 0;
sConfig.Match = 0;
sConfig.Mask = IS25LP064A_SR_WIP;
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 1;
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
sConfig.Interval = 0x10;
/* Perform the write page by page */
do {
sCommand.Address = current_addr;
sCommand.NbData = current_size;
if (current_size == 0) {
return HAL_OK;
}
/* Enable write operations */
if (QSPI_WriteEnable() != HAL_OK) {
return qspi_ERROR;
}
/* Configure the command */
if (HAL_QSPI_Command(&_qspi_flash, &sCommand,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
/* Transmission of the data */
if (HAL_QSPI_Transmit(&_qspi_flash, buffer,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
/* Configure automatic polling mode to wait for end of program */
if (QSPI_Wait(&sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
/* Update the address and size variables for next page programming */
current_addr += current_size;
buffer += current_size;
current_size = ((current_addr + IS25LP064A_PAGE_SIZE) > end_addr)
? (end_addr - current_addr)
: IS25LP064A_PAGE_SIZE;
} while (current_addr <= end_addr);
return qspi_OK;
}
uint8_t CSP_QSPI_Read(uint8_t *buffer, uint32_t address, uint32_t buffer_size) {
QSPI_CommandTypeDef sCommand = {0};
sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
sCommand.Instruction = QUAD_INOUT_FAST_READ_CMD;
sCommand.AddressMode = QSPI_ADDRESS_4_LINES;
sCommand.DataMode = QSPI_DATA_4_LINES;
sCommand.NbData = buffer_size;
sCommand.Address = address;
sCommand.DummyCycles = IS25LP064A_DUMMY_CYCLES_READ_QUAD;
if (HAL_QSPI_Command(&_qspi_flash, &sCommand,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
if (HAL_QSPI_Receive(&_qspi_flash, buffer, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) !=
HAL_OK) {
return qspi_ERROR;
}
return qspi_OK;
}
//------------------------------------------------------
uint8_t CSP_QSPI_ExitQPIMODE(void) {
QSPI_CommandTypeDef sCommand = {0};
sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
sCommand.Instruction = EXIT_QUAD_CMD;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
if (HAL_QSPI_Command(&_qspi_flash, &sCommand,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return qspi_ERROR;
}
qspi_enabled = 0;
return qspi_OK;
}
/* QUADSPI init function */
uint8_t CSP_QUADSPI_Init(void) {
if (QSPI_ResetChip() != HAL_OK) {
return qspi_ERROR;
}
if (QSPI_Configuration() != HAL_OK) {
return qspi_ERROR;
}
return qspi_OK;
}
/* USER CODE END 1 */

View file

@ -1,30 +0,0 @@
#ifndef __IS25LP064A_QSPI_H
#define __IS25LP064A_QSPI_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
uint8_t CSP_QUADSPI_Init(void);
uint8_t CSP_QSPI_Erase_Chip(void);
uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress,
uint32_t EraseEndAddress);
uint8_t CSP_QSPI_EnableMemoryMappedMode(void);
uint8_t CSP_QSPI_DisableMemoryMappedMode(void);
uint8_t CSP_QSPI_Write(uint8_t *buffer, uint32_t address, uint32_t buffer_size);
uint8_t CSP_QSPI_Read(uint8_t *buffer, uint32_t address, uint32_t buffer_size);
//---------------------------------------------
uint8_t CSP_QSPI_ExitQPIMODE(void);
/* USER CODE END Private defines */
/* USER CODE BEGIN Prototypes */
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,7 +1,5 @@
#include "board_api.h"
#include "w25qxx_qspi.h"
#include "qspi_status.h"
#include "stm32h7xx_hal.h"
extern QSPI_HandleTypeDef _qspi_flash;
@ -15,7 +13,7 @@ static uint32_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi);
static uint8_t QSPI_Send_CMD(QSPI_HandleTypeDef *hqspi,uint32_t instruction, uint32_t address,uint32_t addressSize,uint32_t dummyCycles,
uint32_t instructionMode,uint32_t addressMode, uint32_t dataMode, uint32_t dataSize);
qspi_StatusTypeDef w25qxx_Mode = qspi_SPIMode;
w25qxx_StatusTypeDef w25qxx_Mode = w25qxx_SPIMode;
uint8_t w25qxx_StatusReg[3];
uint16_t w25qxx_ID;
@ -32,7 +30,7 @@ uint16_t w25qxx_GetID(void)
uint8_t ID[6];
uint16_t deviceID;
if(w25qxx_Mode == qspi_SPIMode)
if(w25qxx_Mode == w25qxx_SPIMode)
QSPI_Send_CMD(&_qspi_flash,W25X_QUAD_ManufactDeviceID,0x00,QSPI_ADDRESS_24_BITS,6,QSPI_INSTRUCTION_1_LINE,QSPI_ADDRESS_4_LINES, QSPI_DATA_4_LINES, sizeof(ID));
else
QSPI_Send_CMD(&_qspi_flash,W25X_ManufactDeviceID,0x00,QSPI_ADDRESS_24_BITS,0,QSPI_INSTRUCTION_4_LINES,QSPI_ADDRESS_4_LINES, QSPI_DATA_4_LINES, sizeof(ID));
@ -40,7 +38,7 @@ uint16_t w25qxx_GetID(void)
/* Reception of the data */
if (HAL_QSPI_Receive(&_qspi_flash, ID, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return qspi_ERROR;
return w25qxx_ERROR;
}
deviceID = (ID[0] << 8) | ID[1];
@ -50,7 +48,7 @@ uint16_t w25qxx_GetID(void)
uint8_t w25qxx_ReadSR(uint8_t SR)
{
uint8_t byte=0;
if(w25qxx_Mode == qspi_SPIMode)
if(w25qxx_Mode == w25qxx_SPIMode)
QSPI_Send_CMD(&_qspi_flash,SR,0x00,QSPI_ADDRESS_8_BITS,0,QSPI_INSTRUCTION_1_LINE,QSPI_ADDRESS_NONE, QSPI_DATA_1_LINE, 1);
else
QSPI_Send_CMD(&_qspi_flash,SR,0x00,QSPI_ADDRESS_8_BITS,0,QSPI_INSTRUCTION_4_LINES,QSPI_ADDRESS_NONE, QSPI_DATA_4_LINES, 1);
@ -64,7 +62,7 @@ uint8_t w25qxx_ReadSR(uint8_t SR)
uint8_t w25qxx_WriteSR(uint8_t SR,uint8_t data)
{
if(w25qxx_Mode == qspi_SPIMode)
if(w25qxx_Mode == w25qxx_SPIMode)
QSPI_Send_CMD(&_qspi_flash,SR,0x00,QSPI_ADDRESS_8_BITS,0,QSPI_INSTRUCTION_1_LINE,QSPI_ADDRESS_NONE, QSPI_DATA_1_LINE, 1);
else
QSPI_Send_CMD(&_qspi_flash,SR,0x00,QSPI_ADDRESS_8_BITS,0,QSPI_INSTRUCTION_4_LINES,QSPI_ADDRESS_NONE, QSPI_DATA_4_LINES, 1);
@ -77,7 +75,7 @@ uint8_t w25qxx_ReadAllStatusReg(void)
w25qxx_StatusReg[0] = w25qxx_ReadSR(W25X_ReadStatusReg1);
w25qxx_StatusReg[1] = w25qxx_ReadSR(W25X_ReadStatusReg2);
w25qxx_StatusReg[2] = w25qxx_ReadSR(W25X_ReadStatusReg3);
return qspi_OK;
return w25qxx_OK;
}
//等待空闲
@ -92,7 +90,7 @@ uint8_t w25qxx_SetReadParameters(uint8_t DummyClock,uint8_t WrapLenth)
uint8_t send;
send = (DummyClock/2 -1)<<4 | ((WrapLenth/8 - 1)&0x03);
w25qxx_WriteEnable();
W25qxx_WriteEnable();
QSPI_Send_CMD(&_qspi_flash,W25X_SetReadParam,0x00,QSPI_ADDRESS_8_BITS,0,QSPI_INSTRUCTION_4_LINES,QSPI_ADDRESS_NONE, QSPI_DATA_4_LINES, 1);
@ -102,9 +100,9 @@ uint8_t w25qxx_SetReadParameters(uint8_t DummyClock,uint8_t WrapLenth)
uint8_t w25qxx_EnterQPI(void)
{
/* Enter QSPI memory in QSPI mode */
if(QSPI_EnterQPI(&_qspi_flash) != qspi_OK)
if(QSPI_EnterQPI(&_qspi_flash) != w25qxx_OK)
{
return qspi_ERROR;
return w25qxx_ERROR;
}
return w25qxx_SetReadParameters(8,8);
@ -118,14 +116,14 @@ uint8_t w25qxx_EnterQPI(void)
uint8_t w25qxx_Startup(uint8_t DTRMode)
{
/* Enable MemoryMapped mode */
if( QSPI_EnableMemoryMappedMode(&_qspi_flash,DTRMode) != qspi_OK )
if( QSPI_EnableMemoryMappedMode(&_qspi_flash,DTRMode) != w25qxx_OK )
{
return qspi_ERROR;
return w25qxx_ERROR;
}
return qspi_OK;
return w25qxx_OK;
}
uint8_t w25qxx_WriteEnable(void)
uint8_t W25qxx_WriteEnable(void)
{
return QSPI_WriteEnable(&_qspi_flash);
}
@ -134,20 +132,20 @@ uint8_t w25qxx_WriteEnable(void)
* @param SectorAddress: Sector address to erase
* @retval QSPI memory status
*/
uint8_t w25qxx_EraseSector(uint32_t SectorAddress)
uint8_t W25qxx_EraseSector(uint32_t SectorAddress)
{
uint8_t result;
w25qxx_WriteEnable();
W25qxx_WriteEnable();
W25QXX_Wait_Busy();
if(w25qxx_Mode == qspi_SPIMode)
if(w25qxx_Mode == w25qxx_SPIMode)
result = QSPI_Send_CMD(&_qspi_flash,W25X_SectorErase,SectorAddress,QSPI_ADDRESS_24_BITS,0,QSPI_INSTRUCTION_1_LINE,QSPI_ADDRESS_1_LINE,QSPI_DATA_NONE,0);
else
result = QSPI_Send_CMD(&_qspi_flash,W25X_SectorErase,SectorAddress,QSPI_ADDRESS_24_BITS,0,QSPI_INSTRUCTION_4_LINES,QSPI_ADDRESS_4_LINES,QSPI_DATA_NONE,0);
/* 等待擦除完成 */
if(result == qspi_OK)
if(result == w25qxx_OK)
W25QXX_Wait_Busy();
return result;
@ -158,20 +156,20 @@ uint8_t w25qxx_EraseSector(uint32_t SectorAddress)
* @param SectorAddress: Sector address to erase
* @retval QSPI memory status
*/
uint8_t w25qxx_EraseBlock(uint32_t BlockAddress)
uint8_t W25qxx_EraseBlock(uint32_t BlockAddress)
{
uint8_t result;
w25qxx_WriteEnable();
W25qxx_WriteEnable();
W25QXX_Wait_Busy();
if(w25qxx_Mode == qspi_SPIMode)
if(w25qxx_Mode == w25qxx_SPIMode)
result = QSPI_Send_CMD(&_qspi_flash,W25X_BlockErase,BlockAddress,QSPI_ADDRESS_24_BITS,0,QSPI_INSTRUCTION_1_LINE,QSPI_ADDRESS_1_LINE,QSPI_DATA_NONE,0);
else
result = QSPI_Send_CMD(&_qspi_flash,W25X_BlockErase,BlockAddress,QSPI_ADDRESS_24_BITS,0,QSPI_INSTRUCTION_4_LINES,QSPI_ADDRESS_4_LINES,QSPI_DATA_NONE,0);
/* 等待擦除完成 */
if(result == qspi_OK)
if(result == w25qxx_OK)
W25QXX_Wait_Busy();
return result;
@ -182,20 +180,20 @@ uint8_t w25qxx_EraseBlock(uint32_t BlockAddress)
* @param SectorAddress: Sector address to erase
* @retval QSPI memory status
*/
uint8_t w25qxx_EraseChip(void)
uint8_t W25qxx_EraseChip(void)
{
uint8_t result;
w25qxx_WriteEnable();
W25qxx_WriteEnable();
W25QXX_Wait_Busy();
if(w25qxx_Mode == qspi_SPIMode)
if(w25qxx_Mode == w25qxx_SPIMode)
result = QSPI_Send_CMD(&_qspi_flash,W25X_ChipErase,0x00,QSPI_ADDRESS_8_BITS,0,QSPI_INSTRUCTION_1_LINE,QSPI_ADDRESS_NONE,QSPI_DATA_NONE,0);
else
result = QSPI_Send_CMD(&_qspi_flash,W25X_ChipErase,0x00,QSPI_ADDRESS_8_BITS,0,QSPI_INSTRUCTION_4_LINES,QSPI_ADDRESS_NONE,QSPI_DATA_NONE,0);
/* 等待擦除完成 */
if(result == qspi_OK)
if(result == w25qxx_OK)
W25QXX_Wait_Busy();
return result;
@ -208,22 +206,22 @@ uint8_t w25qxx_EraseChip(void)
* @param Size Size of data to write. Range 1 ~ W25qxx page size
* @retval QSPI memory status
*/
uint8_t w25qxx_PageProgram(uint8_t *pData, uint32_t WriteAddr, uint32_t Size)
uint8_t W25qxx_PageProgram(uint8_t *pData, uint32_t WriteAddr, uint32_t Size)
{
uint8_t result;
w25qxx_WriteEnable();
W25qxx_WriteEnable();
if(w25qxx_Mode == qspi_SPIMode)
if(w25qxx_Mode == w25qxx_SPIMode)
result = QSPI_Send_CMD(&_qspi_flash,W25X_QUAD_INPUT_PAGE_PROG_CMD,WriteAddr,QSPI_ADDRESS_24_BITS,0,QSPI_INSTRUCTION_1_LINE,QSPI_ADDRESS_1_LINE,QSPI_DATA_4_LINES,Size);
else
result = QSPI_Send_CMD(&_qspi_flash,W25X_PageProgram,WriteAddr,QSPI_ADDRESS_24_BITS,0,QSPI_INSTRUCTION_4_LINES,QSPI_ADDRESS_4_LINES,QSPI_DATA_4_LINES,Size);
if(result == qspi_OK)
if(result == w25qxx_OK)
result = HAL_QSPI_Transmit(&_qspi_flash,pData,HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
/* 等待写入完成 */
if(result == qspi_OK)
if(result == w25qxx_OK)
W25QXX_Wait_Busy();
return result;
@ -234,7 +232,7 @@ uint8_t w25qxx_PageProgram(uint8_t *pData, uint32_t WriteAddr, uint32_t Size)
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(最大32bit)
//NumByteToRead:要读取的字节数(最大65535)
uint8_t w25qxx_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size)
uint8_t W25qxx_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size)
{
uint8_t result;
@ -242,7 +240,7 @@ uint8_t w25qxx_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size)
/* Configure the command for the read instruction */
if(w25qxx_Mode == qspi_QPIMode)
if(w25qxx_Mode == w25qxx_QPIMode)
{
s_command.Instruction = W25X_QUAD_INOUT_FAST_READ_CMD;
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
@ -273,7 +271,7 @@ uint8_t w25qxx_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size)
result = HAL_QSPI_Command(&_qspi_flash, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
if(result == qspi_OK)
if(result == w25qxx_OK)
result = HAL_QSPI_Receive(&_qspi_flash,pData,HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
return result;
@ -287,7 +285,7 @@ uint8_t w25qxx_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size)
//WriteAddr:开始写入的地址(最大32bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void w25qxx_WriteNoCheck(uint8_t *pBuffer,uint32_t WriteAddr,uint32_t NumByteToWrite)
void W25qxx_WriteNoCheck(uint8_t *pBuffer,uint32_t WriteAddr,uint32_t NumByteToWrite)
{
uint16_t pageremain;
pageremain = 256 - WriteAddr % 256; //单页剩余的字节数
@ -297,7 +295,7 @@ void w25qxx_WriteNoCheck(uint8_t *pBuffer,uint32_t WriteAddr,uint32_t NumByteToW
}
while(1)
{
w25qxx_PageProgram(pBuffer, WriteAddr, pageremain);
W25qxx_PageProgram(pBuffer, WriteAddr, pageremain);
if (NumByteToWrite == pageremain)
{
break; //写入结束了
@ -322,7 +320,7 @@ void w25qxx_WriteNoCheck(uint8_t *pBuffer,uint32_t WriteAddr,uint32_t NumByteToW
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(最大32bit)
//NumByteToWrite:要写入的字节数(最大65535)
uint8_t w25qxx_Write(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
uint8_t W25qxx_Write(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
uint32_t secpos;
uint16_t secoff;
@ -337,8 +335,8 @@ uint8_t w25qxx_Write(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWri
if (NumByteToWrite <= secremain) secremain = NumByteToWrite; //不大于4096个字节
while(1)
{
if (w25qxx_Read(W25QXX_BUF, secpos * 4096, 4096) != qspi_OK) {
return qspi_ERROR;
if (W25qxx_Read(W25QXX_BUF, secpos * 4096, 4096) != w25qxx_OK) {
return w25qxx_ERROR;
} //读出整个扇区的内容
for (i = 0;i < secremain; i++) //校验数据
{
@ -346,18 +344,18 @@ uint8_t w25qxx_Write(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWri
}
if (i < secremain) //需要擦除
{
if (w25qxx_EraseSector(secpos) != qspi_OK) {
return qspi_ERROR;
if (W25qxx_EraseSector(secpos) != w25qxx_OK) {
return w25qxx_ERROR;
} //擦除这个扇区
for (i = 0; i < secremain; i++) //复制
{
W25QXX_BUF[i + secoff] = pBuffer[i];
}
w25qxx_WriteNoCheck(W25QXX_BUF, secpos * 4096, 4096); //写入整个扇区
W25qxx_WriteNoCheck(W25QXX_BUF, secpos * 4096, 4096); //写入整个扇区
}
else
{
w25qxx_WriteNoCheck(pBuffer, WriteAddr, secremain); //写已经擦除了的,直接写入扇区剩余区间.
W25qxx_WriteNoCheck(pBuffer, WriteAddr, secremain); //写已经擦除了的,直接写入扇区剩余区间.
}
if (NumByteToWrite == secremain)
{
@ -377,13 +375,13 @@ uint8_t w25qxx_Write(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWri
secremain = NumByteToWrite; //下一个扇区可以写完了
}
}
return qspi_OK;
return w25qxx_OK;
}
/**
* @brief Configure the QSPI in memory-mapped mode QPI/SPI && DTR(DDR)/Normal Mode
* @param hqspi: QSPI handle
* @param DTRMode: qspi_DTRMode DTR mode ,qspi_NormalMode Normal mode
* @param DTRMode: w25qxx_DTRMode DTR mode ,w25qxx_NormalMode Normal mode
* @retval QSPI memory status
*/
static uint32_t QSPI_EnableMemoryMappedMode(QSPI_HandleTypeDef *hqspi,uint8_t DTRMode)
@ -392,7 +390,7 @@ static uint32_t QSPI_EnableMemoryMappedMode(QSPI_HandleTypeDef *hqspi,uint8_t DT
QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
/* Configure the command for the read instruction */
if(w25qxx_Mode == qspi_QPIMode)
if(w25qxx_Mode == w25qxx_QPIMode)
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
else
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
@ -407,7 +405,7 @@ static uint32_t QSPI_EnableMemoryMappedMode(QSPI_HandleTypeDef *hqspi,uint8_t DT
s_command.DataMode = QSPI_DATA_4_LINES;
if(DTRMode == qspi_DTRMode)
if(DTRMode == w25qxx_DTRMode)
{
s_command.Instruction = W25X_QUAD_INOUT_FAST_READ_DTR_CMD;
s_command.DummyCycles = W25X_DUMMY_CYCLES_READ_QUAD_DTR;
@ -417,7 +415,7 @@ static uint32_t QSPI_EnableMemoryMappedMode(QSPI_HandleTypeDef *hqspi,uint8_t DT
{
s_command.Instruction = W25X_QUAD_INOUT_FAST_READ_CMD;
if(w25qxx_Mode == qspi_QPIMode)
if(w25qxx_Mode == w25qxx_QPIMode)
s_command.DummyCycles = W25X_DUMMY_CYCLES_READ_QUAD;
else
s_command.DummyCycles = W25X_DUMMY_CYCLES_READ_QUAD-2;
@ -434,10 +432,10 @@ static uint32_t QSPI_EnableMemoryMappedMode(QSPI_HandleTypeDef *hqspi,uint8_t DT
if (HAL_QSPI_MemoryMapped(hqspi, &s_command, &s_mem_mapped_cfg) != HAL_OK)
{
return qspi_ERROR;
return w25qxx_ERROR;
}
return qspi_OK;
return w25qxx_OK;
}
/**
@ -463,14 +461,14 @@ static uint32_t QSPI_ResetDevice(QSPI_HandleTypeDef *hqspi)
/* Send the command */
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return qspi_ERROR;
return w25qxx_ERROR;
}
/* Send the reset device command */
s_command.Instruction = W25X_ResetDevice;
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return qspi_ERROR;
return w25qxx_ERROR;
}
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
@ -478,18 +476,18 @@ static uint32_t QSPI_ResetDevice(QSPI_HandleTypeDef *hqspi)
/* Send the command */
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return qspi_ERROR;
return w25qxx_ERROR;
}
/* Send the reset memory command */
s_command.Instruction = W25X_ResetDevice;
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return qspi_ERROR;
return w25qxx_ERROR;
}
w25qxx_Mode = qspi_SPIMode;
return qspi_OK;
w25qxx_Mode = w25qxx_SPIMode;
return w25qxx_OK;
}
/**
@ -504,8 +502,8 @@ static uint32_t QSPI_ResetDevice(QSPI_HandleTypeDef *hqspi)
* @param dataMode ; QSPI_DATA_NONE,QSPI_DATA_1_LINE,QSPI_DATA_2_LINES,QSPI_DATA_4_LINES
* @param dataSize
*
* @return uint8_t qspi_OK:
* qspi_ERROR:
* @return uint8_t w25qxx_OK:
* w25qxx_ERROR:
*/
static uint8_t QSPI_Send_CMD(QSPI_HandleTypeDef *hqspi,uint32_t instruction, uint32_t address,uint32_t addressSize,uint32_t dummyCycles,
uint32_t instructionMode,uint32_t addressMode, uint32_t dataMode, uint32_t dataSize)
@ -532,9 +530,9 @@ static uint8_t QSPI_Send_CMD(QSPI_HandleTypeDef *hqspi,uint32_t instruction, uin
Cmdhandler.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
if(HAL_QSPI_Command(hqspi, &Cmdhandler, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
return qspi_ERROR;
return w25qxx_ERROR;
return qspi_OK;
return w25qxx_OK;
}
/**
@ -558,24 +556,24 @@ static uint32_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi)
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Enable write operations */
if (QSPI_WriteEnable(hqspi) != qspi_OK)
if (QSPI_WriteEnable(hqspi) != w25qxx_OK)
{
return qspi_ERROR;
return w25qxx_ERROR;
}
/* Send the command */
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return qspi_ERROR;
return w25qxx_ERROR;
}
/* Configure automatic polling mode to wait the memory is ready */
if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != qspi_OK)
if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != w25qxx_OK)
{
return qspi_ERROR;
return w25qxx_ERROR;
}
return qspi_OK;
return w25qxx_OK;
}
/**
@ -589,7 +587,7 @@ static uint32_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
QSPI_AutoPollingTypeDef s_config;
/* Enable write operations */
if(w25qxx_Mode == qspi_QPIMode)
if(w25qxx_Mode == w25qxx_QPIMode)
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
else
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
@ -605,7 +603,7 @@ static uint32_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return qspi_ERROR;
return w25qxx_ERROR;
}
/* Configure automatic polling mode to wait for write enabling */
@ -618,17 +616,17 @@ static uint32_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
s_command.Instruction = W25X_ReadStatusReg1;
if(w25qxx_Mode == qspi_QPIMode)
if(w25qxx_Mode == w25qxx_QPIMode)
s_command.DataMode = QSPI_DATA_4_LINES;
else
s_command.DataMode = QSPI_DATA_1_LINE;
if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return qspi_ERROR;
return w25qxx_ERROR;
}
return qspi_OK;
return w25qxx_OK;
}
/**
@ -644,7 +642,7 @@ static uint32_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Tim
/* Configure automatic polling mode to wait for memory ready */
if(w25qxx_Mode == qspi_SPIMode)
if(w25qxx_Mode == w25qxx_SPIMode)
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
else
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
@ -656,7 +654,7 @@ static uint32_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Tim
s_command.AddressSize = QSPI_ADDRESS_8_BITS;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
if(w25qxx_Mode == qspi_SPIMode)
if(w25qxx_Mode == w25qxx_SPIMode)
s_command.DataMode = QSPI_DATA_1_LINE;
else
s_command.DataMode = QSPI_DATA_4_LINES;
@ -687,19 +685,19 @@ static uint8_t QSPI_EnterQPI(QSPI_HandleTypeDef *hqspi)
stareg2 = w25qxx_ReadSR(W25X_ReadStatusReg2);
if((stareg2 & 0X02) == 0) //QE位未使能
{
w25qxx_WriteEnable();
W25qxx_WriteEnable();
stareg2 |= 1<<1; //使能QE位
w25qxx_WriteSR(W25X_WriteStatusReg2,stareg2);
}
QSPI_Send_CMD(hqspi,W25X_EnterQSPIMode,0x00,QSPI_ADDRESS_8_BITS,0,QSPI_INSTRUCTION_1_LINE,QSPI_ADDRESS_NONE,QSPI_DATA_NONE,0);
/* Configure automatic polling mode to wait the memory is ready */
if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != qspi_OK)
if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != w25qxx_OK)
{
return qspi_ERROR;
return w25qxx_ERROR;
}
w25qxx_Mode = qspi_QPIMode;
w25qxx_Mode = w25qxx_QPIMode;
return qspi_OK;
return w25qxx_OK;
}

View file

@ -7,6 +7,21 @@
#include <stdint.h>
typedef enum
{
w25qxx_OK = 0x00,
w25qxx_ERROR = 0x01,
w25qxx_BUSY = 0x02,
w25qxx_TIMEOUT = 0x03,
w25qxx_QPIMode = 0x04,
w25qxx_SPIMode = 0x05,
w25qxx_DTRMode = 0x06,
w25qxx_NormalMode = 0x07,
} w25qxx_StatusTypeDef;
/* =============== W25Qxx CMD ================ */
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
@ -69,14 +84,14 @@ uint8_t w25qxx_WriteSR(uint8_t SR,uint8_t data);
uint8_t w25qxx_SetReadParameters(uint8_t DummyClock,uint8_t WrapLenth);
uint8_t w25qxx_EnterQPI(void);
uint8_t w25qxx_Startup(uint8_t DTRMode);
uint8_t w25qxx_WriteEnable(void);
uint8_t w25qxx_EraseSector(uint32_t SectorAddress);
uint8_t w25qxx_EraseBlock(uint32_t BlockAddress);
uint8_t w25qxx_EraseChip(void);
uint8_t w25qxx_PageProgram(uint8_t *pData, uint32_t WriteAddr, uint32_t Size);
uint8_t w25qxx_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size);
void w25qxx_WriteNoCheck(uint8_t *pBuffer,uint32_t WriteAddr,uint32_t NumByteToWrite);
uint8_t w25qxx_Write(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
uint8_t W25qxx_WriteEnable(void);
uint8_t W25qxx_EraseSector(uint32_t SectorAddress);
uint8_t W25qxx_EraseBlock(uint32_t BlockAddress);
uint8_t W25qxx_EraseChip(void);
uint8_t W25qxx_PageProgram(uint8_t *pData, uint32_t WriteAddr, uint32_t Size);
uint8_t W25qxx_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size);
void W25qxx_WriteNoCheck(uint8_t *pBuffer,uint32_t WriteAddr,uint32_t NumByteToWrite);
uint8_t W25qxx_Write(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
#ifdef __cplusplus
}

View file

@ -24,29 +24,27 @@ endif
CFLAGS += -Wno-error=cast-align -Wno-error=unused-parameter -Wno-error=unused-but-set-variable -Wno-error=unused-function
ifeq ($(SPI_FLASH),W25Qx_SPI)
INC += ${TOP}/$(PORT_DIR)/components/w25qxx
INC += \
$(CURRENT_PATH)/components/w25qxx/ \
SRC_C += \
$(PORT_DIR)/components/w25qxx/w25qxx.c
$(TOP)/$(PORT_DIR)/components/w25qxx/w25qxx.c
endif
ifeq ($(QSPI_FLASH),W25Qx_QSPI)
INC += ${TOP}/$(PORT_DIR)/components/w25qxx
SRC_C += \
$(PORT_DIR)/components/w25qxx/w25qxx_qspi.c
endif
INC += \
$(CURRENT_PATH)/components/w25qxx/ \
ifeq ($(QSPI_FLASH),IS25LP064A)
INC += ${TOP}/$(PORT_DIR)/components/is25lp064a
SRC_C += \
$(PORT_DIR)/components/is25lp064a/is25lp064a_qspi.c
$(TOP)/$(PORT_DIR)/components/w25qxx/w25qxx_qspi.c
endif
ifeq ($(DISPLAY_DRV),ST7735)
INC += ${TOP}/$(PORT_DIR)/components/st7735/
INC += \
$(CURRENT_PATH)/components/w25qxx/ \
SRC_C += \
$(PORT_DIR)/components/st7735/st7735.c \
$(PORT_DIR)/components/st7735/fonts.c
$(TOP)/$(PORT_DIR)/components/st7735/st7735.c
endif
# Source
@ -65,6 +63,8 @@ SRC_C += \
$(ST_HAL_DRIVER)/Src/stm32h7xx_hal_qspi.c \
$(ST_HAL_DRIVER)/Src/stm32h7xx_hal_mdma.c \
$(ST_HAL_DRIVER)/Src/stm32h7xx_hal_pwr_ex.c \
$(TOP)/$(PORT_DIR)/components/st7735/fonts.c \
ifndef BUILD_NO_TINYUSB
SRC_C += lib/tinyusb/src/portable/synopsys/dwc2/dcd_dwc2.c
@ -75,6 +75,8 @@ endif
INC += \
$(TOP)/$(BOARD_PATH) \
$(TOP)/$(CMSIS_5)/CMSIS/Core/Include \
$(CURRENT_PATH)/components/st7735/ \
$(CURRENT_PATH)/components/w25qxx/ \
$(TOP)/$(PORT_DIR)/ \
$(TOP)/$(BOARD_DIR) \
$(TOP)/$(ST_CMSIS)/Include \

View file

@ -1,26 +0,0 @@
#ifndef QSPI_STATUS_H_
#define QSPI_STATUS_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
qspi_OK = 0x00,
qspi_ERROR = 0x01,
qspi_BUSY = 0x02,
qspi_TIMEOUT = 0x03,
qspi_QPIMode = 0x04,
qspi_SPIMode = 0x05,
qspi_DTRMode = 0x06,
qspi_NormalMode = 0x07,
} qspi_StatusTypeDef;
#ifdef __cplusplus
}
#endif
#endif