Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 44 additions & 40 deletions boards/m5stack/m5stack_cores3/m5stack_cores3_procpu_common.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -44,37 +44,38 @@
input = <&ft6336_touch>;
};

mipi_dbi: mipi_dbi {
compatible = "zephyr,mipi-dbi-spi";
spi-dev = <&spi2>;
write-only;
dc-gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>;
reset-gpios = <&aw9523b_gpio 13 GPIO_ACTIVE_LOW>;
#address-cells = <1>;
#size-cells = <0>;
status = "okay";

ili9342c: ili9342c@0 {
compatible = "ilitek,ili9342c";
reg = <0>;
mipi-mode = "MIPI_DBI_MODE_SPI_4WIRE";
mipi-max-frequency = <40000000>;
vin-supply = <&vcc_bl>;
pixel-format = <ILI9XXX_PIXEL_FORMAT_RGB565>;
ifmode = [e0];
disctrl = [08 82 1d 04];
pwctrl1 = [12 12];
pwctrl2 = [03];
vmctrl1 = [f2];
pgamctrl = [00 0c 11 04 11 08 37 89 4c 06 0c 0a 2e 34 0f];
ngamctrl = [00 0b 11 05 13 09 33 67 48 07 0e 0b 2e 33 0f];
display-inversion;
width = <320>;
height = <240>;
rotation = <0>;
status = "okay";
};
};
mipi_dbi: mipi_dbi {
compatible = "zephyr,mipi-dbi-spi";
spi-dev = <&spi2>;
dc-gpios = <&gpio0 35 GPIO_ACTIVE_HIGH>;
cmd-data-tristate;
reset-gpios = <&aw9523b_gpio 13 GPIO_ACTIVE_LOW>;
#address-cells = <1>;
#size-cells = <0>;
status = "okay";

ili9342c: ili9342c@0 {
compatible = "ilitek,ili9342c";
reg = <0>;
mipi-mode = "MIPI_DBI_MODE_SPI_3WIRE";
mipi-max-frequency = <40000000>;
duplex = <SPI_HALF_DUPLEX>;
vin-supply = <&vcc_bl>;
pixel-format = <ILI9XXX_PIXEL_FORMAT_RGB565>;
ifmode = [e0];
disctrl = [08 82 1d 04];
pwctrl1 = [12 12];
pwctrl2 = [03];
vmctrl1 = [f2];
pgamctrl = [00 0c 11 04 11 08 37 89 4c 06 0c 0a 2e 34 0f];
ngamctrl = [00 0b 11 05 13 09 33 67 48 07 0e 0b 2e 33 0f];
display-inversion;
width = <320>;
height = <240>;
rotation = <0>;
status = "okay";
};
};
};

&usb_serial {
Expand Down Expand Up @@ -245,15 +246,18 @@
};

&spi2 {
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
pinctrl-0 = <&spim2_default>;
pinctrl-names = "default";
clock-frequency = <40000000>;
dma-enabled;
cs-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>, /* LCD */
<&gpio0 4 GPIO_ACTIVE_LOW>; /* TF-CARD */
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
pinctrl-0 = <&spim2_default>;
pinctrl-names = "default";
clock-frequency = <40000000>;
half-duplex;
sio;
line-idle-low;
dma-enabled;
cs-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>, /* LCD */
<&gpio0 4 GPIO_ACTIVE_LOW>; /* TF-CARD */

sd0: sd@1 {
compatible = "zephyr,sdhc-spi-slot";
Expand Down
112 changes: 112 additions & 0 deletions doc/m5gfx_coreS3_spi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*

Check warning on line 1 in doc/m5gfx_coreS3_spi.cpp

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

Copyright missing

doc/m5gfx_coreS3_spi.cpp:1 File has no SPDX-FileCopyrightText header, consider adding one.

Check warning on line 1 in doc/m5gfx_coreS3_spi.cpp

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

License missing

doc/m5gfx_coreS3_spi.cpp:1 File has no SPDX-License-Identifier header, consider adding one.
* Extracts from M5GFX (https://github.com/m5stack/M5GFX) relevant to the
* CoreS3 SPI wiring and register sequencing. Copied verbatim for
* documentation and comparison purposes.
*/

// --- src/M5GFX.cpp (panel/bus setup) ---
struct Panel_M5StackCoreS3 : public lgfx::Panel_ILI9342 {
Panel_M5StackCoreS3(void) {
_cfg.pin_cs = GPIO_NUM_3;
_cfg.invert = true;
_cfg.offset_rotation = 3;

_rotation = 1; // default rotation
}

void rst_control(bool level) override {
uint8_t bits = level ? (1<<5) : 0;
uint8_t mask = level ? ~0 : ~(1<<5);
// LCD_RST
lgfx::i2c::writeRegister8(i2c_port, aw9523_i2c_addr, 0x03, bits, mask, i2c_freq);
}

void cs_control(bool flg) override {
lgfx::Panel_ILI9342::cs_control(flg);
// CS操作時にGPIO35の役割を切り替える (MISO or D/C);
*(volatile uint32_t*)( flg
? GPIO_ENABLE1_W1TC_REG
: GPIO_ENABLE1_W1TS_REG
) = 1u << (GPIO_NUM_35 & 31);
}
};

// Autodetect branch for CoreS3 (bus_cfg setup)
bus_cfg.pin_mosi = GPIO_NUM_37;
bus_cfg.pin_miso = GPIO_NUM_35;
bus_cfg.pin_sclk = GPIO_NUM_36;
bus_cfg.pin_dc = GPIO_NUM_35;// MISOとLCD D/CをGPIO35でシェアしている;
bus_cfg.spi_mode = 0;
bus_cfg.spi_3wire = true;
bus_spi->config(bus_cfg);
bus_spi->init();
id = _read_panel_id(bus_spi, GPIO_NUM_3);
if ((id & 0xFF) == 0xE3) {
bus_cfg.freq_write = 40000000;
bus_cfg.freq_read = 16000000;
bus_spi->config(bus_cfg);
auto p = new Panel_M5StackCoreS3();
p->bus(bus_spi);
_panel_last.reset(p);
}

// --- src/lgfx/v1/platforms/esp32/Bus_SPI.cpp (register writes) ---
void Bus_SPI::beginTransaction(void) {
uint32_t freq_apb = getApbFrequency();
uint32_t clkdiv_write = _clkdiv_write;
if (_last_freq_apb != freq_apb) {
_last_freq_apb = freq_apb;
_clkdiv_read = FreqToClockDiv(freq_apb, _cfg.freq_read);
clkdiv_write = FreqToClockDiv(freq_apb, _cfg.freq_write);
_clkdiv_write = clkdiv_write;
dc_control(true);
pinMode(_cfg.pin_dc, pin_mode_t::output);
}

auto spi_mode = _cfg.spi_mode;
uint32_t pin = (spi_mode & 2) ? SPI_CK_IDLE_EDGE : 0;
pin = pin
#if defined ( SPI_CS0_DIS )
| SPI_CS0_DIS
#endif
#if defined ( SPI_CS1_DIS )
| SPI_CS1_DIS
#endif
#if defined ( SPI_CS2_DIS )
| SPI_CS2_DIS
#endif
#if defined ( SPI_CS3_DIS )
| SPI_CS3_DIS
#endif
#if defined ( SPI_CS4_DIS )
| SPI_CS4_DIS
#endif
#if defined ( SPI_CS5_DIS )
| SPI_CS5_DIS
#endif
;

if (_cfg.use_lock) spi::beginTransaction(_cfg.spi_host);

*_spi_user_reg = _user_reg;
auto spi_port = _spi_port;
(void)spi_port;
writereg(SPI_PIN_REG(spi_port), pin);
writereg(SPI_CLOCK_REG(spi_port), clkdiv_write);
#if defined ( SPI_UPDATE )
*_spi_cmd_reg = SPI_UPDATE;
#endif
}

void Bus_SPI::beginRead(void) {
uint32_t pin = (_cfg.spi_mode & 2) ? SPI_CK_IDLE_EDGE : 0;
uint32_t user = ((_cfg.spi_mode == 1 || _cfg.spi_mode == 2) ? SPI_CK_OUT_EDGE | SPI_USR_MISO : SPI_USR_MISO)
| (_cfg.spi_3wire ? SPI_SIO : 0);
dc_control(true);
*_spi_user_reg = user;
writereg(SPI_PIN_REG(_spi_port), pin);
writereg(SPI_CLOCK_REG(_spi_port), _clkdiv_read);
#if defined ( SPI_UPDATE )
*_spi_cmd_reg = SPI_UPDATE;
#endif
}
39 changes: 39 additions & 0 deletions doc/m5stack_core2_spi_comparison.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# M5Stack Core2 SPI configuration comparison

Check warning on line 1 in doc/m5stack_core2_spi_comparison.md

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

Copyright missing

doc/m5stack_core2_spi_comparison.md:1 File has no SPDX-FileCopyrightText header, consider adding one.

Check warning on line 1 in doc/m5stack_core2_spi_comparison.md

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

License missing

doc/m5stack_core2_spi_comparison.md:1 File has no SPDX-License-Identifier header, consider adding one.

## Zephyr board support (`boards/m5stack/m5stack_core2/m5stack_core2_procpu.dts`)
- The display panel is exposed via a MIPI DBI wrapper on `spi3`, using GPIO0.15 as DC and an AXP192 GPIO line as reset, with the panel bound to chip select 0 on the SPI bus.【F:boards/m5stack/m5stack_core2/m5stack_core2_procpu.dts†L57-L77】
- `spi3` runs at 20&nbsp;MHz with DMA enabled and offers two chip-select lines (GPIO0.5 and GPIO0.4). The first CS serves the LCD, while the second drives the `zephyr,sdhc-spi-slot` node for the microSD card, which is also limited to 20&nbsp;MHz.【F:boards/m5stack/m5stack_core2/m5stack_core2_procpu.dts†L207-L229】
- Pin control ties `spi3` to SCLK = GPIO18, MOSI = GPIO23 (preset low), and MISO = GPIO38 without additional drive-strength tuning.【F:boards/m5stack/m5stack_core2/m5stack_core2-pinctrl.dtsi†L38-L48】

## M5Unified library defaults (`M5Unified/src/M5Unified.cpp`)
- The `_pin_table_spi_sd` table selects SCLK = GPIO18, MOSI = GPIO23, MISO = GPIO38, and CS = GPIO4 for the Core2 SD interface, mirroring the base wiring used in Zephyr:

```c++
{ board_t::board_M5StackCore2 , GPIO_NUM_18, GPIO_NUM_23, GPIO_NUM_38, GPIO_NUM_4 },
```
【F:doc/m5stack_core2_spi_comparison.md†L11-L13】
- During setup the library boosts the GPIO18/19/23 drive strength to 40&nbsp;mA and enables pull-ups to keep high-speed SPI links (20&nbsp;MHz for SD, 80&nbsp;MHz for external ModuleDisplay) reliable—behaviour not present in the Zephyr device tree:

```c++
for (auto gpio: (const gpio_num_t[]){ GPIO_NUM_18, GPIO_NUM_19, GPIO_NUM_23 }) {
*(volatile uint32_t*)(GPIO_PIN_MUX_REG[gpio]) = tmp | FUN_DRV_M; // gpio drive current set to 40mA.
gpio_pulldown_dis(gpio);
gpio_pullup_en(gpio);
}
```
【F:doc/m5stack_core2_spi_comparison.md†L18-L22】
- When M5Unified detects Atomic Speaker hardware it remaps the SD SPI pins to GPIO7/6/8 and disables the on-board IMU/RTC to avoid I²C conflicts, showing that its SPI allocation is dynamic depending on accessories:

```c++
_get_pin_table[sd_spi_sclk] = GPIO_NUM_7;
_get_pin_table[sd_spi_copi] = GPIO_NUM_6;
_get_pin_table[sd_spi_cipo] = GPIO_NUM_8;
cfg.internal_imu = false;
cfg.internal_rtc = false;
```
【F:doc/m5stack_core2_spi_comparison.md†L28-L32】

## Notable differences
1. **Electrical tuning** – Zephyr leaves the ESP32 pins at their default drive, while M5Unified explicitly increases drive strength and enables pull-ups to stabilise high-speed SPI transfers.
2. **Chip-select usage** – Zephyr reserves two CS lines on `spi3` (LCD and SD); M5Unified manages only the SD CS in its pin table and handles the LCD bus configuration through M5GFX.
3. **Accessory awareness** – Zephyr’s wiring is static, whereas M5Unified can reassign SPI pins (and even disable conflicting peripherals) when certain modular accessories are detected.
Loading
Loading