Skip to content

Commit 602f443

Browse files
added qspi flash functionality for the giga
1 parent 658a690 commit 602f443

File tree

7 files changed

+358
-0
lines changed

7 files changed

+358
-0
lines changed

libraries/QSPI/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
zephyr_library()
2+
3+
zephyr_library_sources(QSPI.cpp)
4+
5+
zephyr_library_include_directories(.)

libraries/QSPI/QSPI.cpp

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#include "QSPI.h"
2+
3+
// Define the QSPI flash device - will be available when overlay is active
4+
#if DT_NODE_EXISTS(DT_NODELABEL(qspi_flash))
5+
#define QSPI_FLASH_NODE DT_NODELABEL(qspi_flash)
6+
#define QSPI_FLASH_DEVICE DEVICE_DT_GET(QSPI_FLASH_NODE)
7+
#else
8+
#define QSPI_FLASH_DEVICE NULL
9+
#warning "QSPI flash device not found in device tree"
10+
#endif
11+
12+
QSPIClass::QSPIClass() : flash_dev(nullptr), initialized(false) {
13+
}
14+
15+
bool QSPIClass::begin() {
16+
if (QSPI_FLASH_DEVICE == NULL) {
17+
return false;
18+
}
19+
20+
flash_dev = QSPI_FLASH_DEVICE;
21+
22+
if (!device_is_ready(flash_dev)) {
23+
flash_dev = nullptr;
24+
return false;
25+
}
26+
27+
initialized = true;
28+
return true;
29+
}
30+
31+
bool QSPIClass::read(uint32_t address, void* data, size_t size) {
32+
if (!initialized || !flash_dev) {
33+
return false;
34+
}
35+
36+
int ret = flash_read(flash_dev, address, data, size);
37+
return (ret == 0);
38+
}
39+
40+
bool QSPIClass::write(uint32_t address, const void* data, size_t size) {
41+
if (!initialized || !flash_dev) {
42+
return false;
43+
}
44+
45+
int ret = flash_write(flash_dev, address, data, size);
46+
return (ret == 0);
47+
}
48+
49+
bool QSPIClass::erase(uint32_t address, size_t size) {
50+
if (!initialized || !flash_dev) {
51+
return false;
52+
}
53+
54+
int ret = flash_erase(flash_dev, address, size);
55+
return (ret == 0);
56+
}
57+
58+
size_t QSPIClass::getFlashSize() {
59+
if (!initialized || !flash_dev) {
60+
return 0;
61+
}
62+
63+
uint64_t size = 0;
64+
int ret = flash_get_size(flash_dev, &size);
65+
if (ret != 0) {
66+
return 0;
67+
}
68+
69+
return (size_t)size;
70+
}
71+
72+
size_t QSPIClass::getSectorSize() {
73+
if (!initialized || !flash_dev) {
74+
return 0;
75+
}
76+
77+
struct flash_pages_info page_info;
78+
int ret = flash_get_page_info_by_offs(flash_dev, 0, &page_info);
79+
if (ret != 0) {
80+
return 0;
81+
}
82+
83+
return page_info.size;
84+
}
85+
86+
size_t QSPIClass::getPageSize() {
87+
if (!initialized || !flash_dev) {
88+
return 0;
89+
}
90+
91+
const struct flash_parameters *flash_params = flash_get_parameters(flash_dev);
92+
if (!flash_params) {
93+
return 0;
94+
}
95+
96+
return flash_params->write_block_size;
97+
}
98+
99+
bool QSPIClass::isReady() {
100+
if (!flash_dev) {
101+
return false;
102+
}
103+
104+
return device_is_ready(flash_dev);
105+
}
106+
107+
uint32_t QSPIClass::getFlashID() {
108+
// This would require implementing JEDEC ID reading
109+
// For now, return 0 as placeholder
110+
return 0;
111+
}
112+
113+
bool QSPIClass::isValidAddress(uint32_t address, size_t size) {
114+
if (!initialized || !flash_dev) {
115+
return false;
116+
}
117+
118+
size_t flash_size = getFlashSize();
119+
return (address + size <= flash_size);
120+
}
121+
122+
void QSPIClass::end() {
123+
flash_dev = nullptr;
124+
initialized = false;
125+
}
126+
127+
// Create global instance
128+
QSPIClass QSPI;

libraries/QSPI/QSPI.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#ifndef QSPI_H
2+
#define QSPI_H
3+
4+
#include <Arduino.h>
5+
#include <zephyr/kernel.h>
6+
#include <zephyr/device.h>
7+
#include <zephyr/drivers/flash.h>
8+
#include <zephyr/devicetree.h>
9+
10+
class QSPIClass {
11+
12+
public:
13+
QSPIClass();
14+
15+
// Initialize QSPI flash
16+
bool begin();
17+
18+
// Read data from QSPI flash
19+
bool read(uint32_t address, void* data, size_t size);
20+
21+
// Write data to QSPI flash
22+
bool write(uint32_t address, const void* data, size_t size);
23+
24+
// Erase sector/block
25+
bool erase(uint32_t address, size_t size);
26+
27+
// Get flash information
28+
size_t getFlashSize();
29+
size_t getSectorSize();
30+
size_t getPageSize();
31+
32+
// Check if flash is ready
33+
bool isReady();
34+
35+
// Get flash ID
36+
uint32_t getFlashID();
37+
38+
// Utility functions
39+
bool isValidAddress(uint32_t address, size_t size = 1);
40+
41+
// End/deinitialize
42+
void end();
43+
44+
private:
45+
const struct device *flash_dev;
46+
bool initialized;
47+
};
48+
49+
extern QSPIClass QSPI;
50+
51+
#endif

libraries/QSPI/README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# QSPI Library
2+
3+
This library provides a simple Arduino-style interface for accessing QSPI (Quad SPI) flash memory on Arduino Zephyr boards.
4+
5+
## Features
6+
7+
- Initialize and configure QSPI flash
8+
- Read data from QSPI flash memory
9+
- Write data to QSPI flash memory
10+
- Erase sectors/blocks
11+
- Get flash information (size, sector size, page size)
12+
13+
14+
### Device Tree Setup
15+
16+
Added to `arduino_giga_r1_stm32h747xx_m7.overlay` file:
17+
18+
```dts
19+
&quadspi {
20+
pinctrl-0 = <&quadspi_clk_pf10 &quadspi_bk1_ncs_pb6
21+
&quadspi_bk1_io0_pf8 &quadspi_bk1_io1_pf9
22+
&quadspi_bk1_io2_pf7 &quadspi_bk1_io3_pf6>;
23+
pinctrl-names = "default";
24+
status = "okay";
25+
26+
qspi_flash: qspi-nor-flash@90000000 {
27+
compatible = "st,stm32-qspi-nor";
28+
reg = <0x90000000 DT_SIZE_M(16)>;
29+
qspi-max-frequency = <80000000>;
30+
size = <DT_SIZE_M(16) * 8>;
31+
spi-bus-width = <4>;
32+
status = "okay";
33+
};
34+
};
35+
```
36+
37+
### Configuration Setup
38+
39+
Added to the `arduino_giga_r1_stm32h747xx_m7.conf`:
40+
41+
```kconfig
42+
CONFIG_SPI_STM32_QSPI=y
43+
CONFIG_SPI_NOR=y
44+
CONFIG_SPI_NOR_SFDP_DEVICETREE=y
45+
CONFIG_FLASH=y
46+
CONFIG_FLASH_MAP=y
47+
CONFIG_FLASH_PAGE_LAYOUT=y
48+
```
49+
50+
No changes were needed to the llext.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
Basic QSPI Flash Example
3+
4+
This example demonstrates how to use the QSPI library to read and write
5+
data to external QSPI flash memory on Arduino boards with QSPI support.
6+
7+
Note: QSPI flash must be configured in the board's device tree overlay.
8+
*/
9+
10+
#include <QSPI.h>
11+
12+
void setup() {
13+
Serial.begin(115200);
14+
while (!Serial) {
15+
delay(10);
16+
}
17+
18+
Serial.println("QSPI Flash Test");
19+
20+
// Initialize QSPI flash
21+
if (!QSPI.begin()) {
22+
Serial.println("Failed to initialize QSPI flash!");
23+
while (1) {
24+
delay(1000);
25+
}
26+
}
27+
28+
Serial.println("QSPI flash initialized successfully");
29+
30+
// Get flash information
31+
Serial.print("Flash size: ");
32+
Serial.print(QSPI.getFlashSize());
33+
Serial.println(" bytes");
34+
35+
Serial.print("Sector size: ");
36+
Serial.print(QSPI.getSectorSize());
37+
Serial.println(" bytes");
38+
39+
Serial.print("Page size: ");
40+
Serial.print(QSPI.getPageSize());
41+
Serial.println(" bytes");
42+
43+
// Test write and read
44+
testWriteRead();
45+
}
46+
47+
void loop() {
48+
// Nothing to do in loop
49+
delay(5000);
50+
51+
Serial.println("Running periodic test...");
52+
testWriteRead();
53+
}
54+
55+
void testWriteRead() {
56+
const uint32_t test_address = 0x1000; // Test address (4KB offset)
57+
const char test_data[] = "Hello QSPI Flash!";
58+
char read_buffer[32];
59+
60+
Serial.println("\n--- Testing Write/Read ---");
61+
62+
// Erase sector first
63+
Serial.print("Erasing sector at 0x");
64+
Serial.print(test_address, HEX);
65+
Serial.print("... ");
66+
67+
if (QSPI.erase(test_address, QSPI.getSectorSize())) {
68+
Serial.println("OK");
69+
} else {
70+
Serial.println("FAILED");
71+
return;
72+
}
73+
74+
// Write test data
75+
Serial.print("Writing data... ");
76+
if (QSPI.write(test_address, test_data, strlen(test_data) + 1)) {
77+
Serial.println("OK");
78+
} else {
79+
Serial.println("FAILED");
80+
return;
81+
}
82+
83+
// Read back data
84+
Serial.print("Reading data... ");
85+
memset(read_buffer, 0, sizeof(read_buffer));
86+
if (QSPI.read(test_address, read_buffer, sizeof(read_buffer))) {
87+
Serial.println("OK");
88+
89+
Serial.print("Read data: ");
90+
Serial.println(read_buffer);
91+
92+
// Verify data
93+
if (strcmp(test_data, read_buffer) == 0) {
94+
Serial.println("Data verification: PASSED");
95+
} else {
96+
Serial.println("Data verification: FAILED");
97+
}
98+
} else {
99+
Serial.println("FAILED");
100+
}
101+
}

variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.conf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,9 @@ CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
6464
CONFIG_BT_RX_STACK_SIZE=4096
6565

6666
CONFIG_STM32H7_BOOT_M4_AT_INIT=n
67+
68+
# QSPI Flash Support
69+
CONFIG_FLASH=y
70+
CONFIG_FLASH_STM32_QSPI=y
71+
CONFIG_FLASH_MAP=y
72+
CONFIG_FLASH_PAGE_LAYOUT=y

variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.overlay

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,23 @@
334334
};
335335

336336

337+
&quadspi {
338+
pinctrl-0 = <&quadspi_clk_pf10 &quadspi_bk1_ncs_pg6
339+
&quadspi_bk1_io0_pd11 &quadspi_bk1_io1_pd12
340+
&quadspi_bk1_io2_pe2 &quadspi_bk1_io3_pf6>;
341+
pinctrl-names = "default";
342+
status = "okay";
343+
344+
qspi_flash: qspi-nor-flash@0 {
345+
compatible = "st,stm32-qspi-nor";
346+
reg = <0>;
347+
size = <DT_SIZE_M(128)>; /* 128 Mbits (16 MB) */
348+
qspi-max-frequency = <72000000>;
349+
spi-bus-width = <4>;
350+
status = "okay";
351+
};
352+
};
353+
337354
&flash0 {
338355
partitions {
339356
user_sketch: partition@e0000 {

0 commit comments

Comments
 (0)