Skip to content

Commit 92d4b48

Browse files
committed
Add support for SDIO
Add support for SDIO in CYW driver Add Portenta H7 example
1 parent a801160 commit 92d4b48

File tree

16 files changed

+2023
-276
lines changed

16 files changed

+2023
-276
lines changed

mongoose.c

Lines changed: 506 additions & 136 deletions
Large diffs are not rendered by default.

mongoose.h

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3008,7 +3008,9 @@ struct mg_profitem {
30083008
#endif
30093009

30103010

3011-
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_CYW) && MG_ENABLE_DRIVER_CYW
3011+
#if MG_ENABLE_TCPIP && \
3012+
((defined(MG_ENABLE_DRIVER_CYW) && MG_ENABLE_DRIVER_CYW) || \
3013+
(defined(MG_ENABLE_DRIVER_CYW_SDIO) && MG_ENABLE_DRIVER_CYW_SDIO))
30123014

30133015
struct mg_tcpip_spi_ {
30143016
void *spi; // Opaque SPI bus descriptor
@@ -3028,7 +3030,7 @@ struct mg_tcpip_driver_cyw_firmware {
30283030
};
30293031

30303032
struct mg_tcpip_driver_cyw_data {
3031-
struct mg_tcpip_spi_ *spi;
3033+
void *bus;
30323034
struct mg_tcpip_driver_cyw_firmware *fw;
30333035
char *ssid;
30343036
char *pass;
@@ -3278,6 +3280,30 @@ struct mg_tcpip_driver_same54_data {
32783280
#endif
32793281

32803282

3283+
#if MG_ENABLE_TCPIP && \
3284+
(defined(MG_ENABLE_DRIVER_CYW_SDIO) && MG_ENABLE_DRIVER_CYW_SDIO)
3285+
3286+
struct mg_tcpip_sdio {
3287+
void *sdio; // Opaque SDIO bus descriptor
3288+
void (*cfg)(void *, uint8_t); // select operating parameters
3289+
// SDIO transaction: send cmd with a possible 1-byte read or write
3290+
bool (*txn)(void *, uint8_t cmd, uint32_t arg, uint32_t *r);
3291+
// SDIO extended transaction: write or read len bytes, using blksz blocks
3292+
bool (*xfr)(void *, bool write, uint32_t arg, uint16_t blksz, uint32_t *,
3293+
uint32_t len, uint32_t *r);
3294+
};
3295+
3296+
bool mg_sdio_transfer(struct mg_tcpip_sdio *sdio, bool write, unsigned int f,
3297+
uint32_t addr, void *data, uint32_t len);
3298+
bool mg_sdio_set_blksz(struct mg_tcpip_sdio *sdio, unsigned int f,
3299+
uint16_t blksz);
3300+
bool mg_sdio_enable_f(struct mg_tcpip_sdio *sdio, unsigned int f);
3301+
bool mg_sdio_waitready_f(struct mg_tcpip_sdio *sdio, unsigned int f);
3302+
bool mg_sdio_init(struct mg_tcpip_sdio *sdio);
3303+
3304+
#endif
3305+
3306+
32813307
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32F) && \
32823308
MG_ENABLE_DRIVER_STM32F
32833309

src/drivers/cyw.c

Lines changed: 330 additions & 135 deletions
Large diffs are not rendered by default.

src/drivers/cyw.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#pragma once
22

3-
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_CYW) && MG_ENABLE_DRIVER_CYW
3+
#if MG_ENABLE_TCPIP && \
4+
((defined(MG_ENABLE_DRIVER_CYW) && MG_ENABLE_DRIVER_CYW) || \
5+
(defined(MG_ENABLE_DRIVER_CYW_SDIO) && MG_ENABLE_DRIVER_CYW_SDIO))
46

57
struct mg_tcpip_spi_ {
68
void *spi; // Opaque SPI bus descriptor
@@ -20,7 +22,7 @@ struct mg_tcpip_driver_cyw_firmware {
2022
};
2123

2224
struct mg_tcpip_driver_cyw_data {
23-
struct mg_tcpip_spi_ *spi;
25+
void *bus;
2426
struct mg_tcpip_driver_cyw_firmware *fw;
2527
char *ssid;
2628
char *pass;

src/drivers/sdio.c

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
#include "sdio.h"
2+
3+
#if MG_ENABLE_TCPIP && \
4+
(defined(MG_ENABLE_DRIVER_CYW_SDIO) && MG_ENABLE_DRIVER_CYW_SDIO)
5+
6+
// SDIO 6.9 Table 6-1 CCCR (Common Card Control Registers)
7+
#define MG_SDIO_CCCR_SDIOREV 0x000
8+
#define MG_SDIO_CCCR_SDREV 0x001
9+
#define MG_SDIO_CCCR_IOEN 0x002
10+
#define MG_SDIO_CCCR_IORDY 0x003
11+
#define MG_SDIO_CCCR_INTEN 0x004
12+
#define MG_SDIO_CCCR_BIC 0x007
13+
#define MG_SDIO_CCCR_CCAP 0x008
14+
#define MG_SDIO_CCCR_CCIS 0x009 // 3 registers
15+
#define MG_SDIO_CCCR_F0BLKSZ 0x010 // 2 registers
16+
#define MG_SDIO_CCCR_HISPD 0x013
17+
// SDIO 6.10 Table 6-3 FBR (Function Basic Registers)
18+
#define MG_SDIO_FBR_FnBLKSZ(n) (((n) &7) * 0x100 + 0x10) // 2 registers
19+
20+
// SDIO 5.1 IO_RW_DIRECT Command (CMD52)
21+
#define MG_SDIO_DATA(x) ((x) &0xFF) // bits 0-7
22+
#define MG_SDIO_ADDR(x) (((x) &0x1FFFF) << 9) // bits 9-25
23+
#define MG_SDIO_FUNC(x) (((x) &3) << 28) // bits 28-30 (30 unused here)
24+
#define MG_SDIO_WR MG_BIT(31)
25+
26+
// SDIO 5.3 IO_RW_EXTENDED Command (CMD53)
27+
#define MG_SDIO_LEN(x) ((x) &0x1FF) // bits 0-8
28+
#define MG_SDIO_OPINC MG_BIT(26)
29+
#define MG_SDIO_BLKMODE MG_BIT(27)
30+
31+
// - Drivers set blocksize, drivers request transfers. Requesting a read
32+
// transfer > blocksize means block transfer will be used.
33+
// - To simplify the use of DMA transfers and avoid intermediate buffers,
34+
// drivers must have room to accomodate a whole block transfer, e.g.: blocksize
35+
// = 64, read 65 => 2 blocks = 128 bytes
36+
// - Transfers of more than 1 byte assume (uint32_t *) data. 1-byte transfers
37+
// use (uint8_t *) data
38+
// - 'len' is the number of _bytes_ to transfer
39+
bool mg_sdio_transfer(struct mg_tcpip_sdio *sdio, bool write, unsigned int f,
40+
uint32_t addr, void *data, uint32_t len) {
41+
uint32_t arg, val = 0;
42+
unsigned int blksz = 64; // TODO(): mg_sdio_set_blksz() stores in an array,
43+
// index on f, skip if 0
44+
if (len == 1) {
45+
arg = (write ? MG_SDIO_WR : 0) | MG_SDIO_FUNC(f) | MG_SDIO_ADDR(addr) |
46+
(write ? MG_SDIO_DATA(*(uint8_t *) data) : 0);
47+
bool res = sdio->txn(sdio, 52, arg, &val); // IO_RW_DIRECT
48+
if (!write) *(uint8_t *) data = (uint8_t) val;
49+
return res;
50+
}
51+
// IO_RW_EXTENDED
52+
arg = (write ? MG_SDIO_WR : 0) | MG_SDIO_OPINC | MG_SDIO_FUNC(f) |
53+
MG_SDIO_ADDR(addr);
54+
if (len > 512 || (blksz != 0 && len > blksz)) { // SDIO 5.3 512 -> len=0
55+
unsigned int blkcnt;
56+
if (blksz == 0) return false; // > 512 requires block size set
57+
blkcnt = (len + blksz - 1) / blksz;
58+
if (blkcnt > 511) return false; // we don't support "infinite" blocks
59+
arg |= MG_SDIO_BLKMODE | MG_SDIO_LEN(blkcnt); // block transfer
60+
len = blksz * blkcnt;
61+
} else {
62+
arg |= MG_SDIO_LEN(len); // multi-byte transfer
63+
}
64+
return sdio->xfr(sdio, write, arg,
65+
(arg & MG_SDIO_BLKMODE) ? (uint16_t) blksz : 0,
66+
(uint32_t *) data, len, &val);
67+
}
68+
69+
bool mg_sdio_set_blksz(struct mg_tcpip_sdio *sdio, unsigned int f,
70+
uint16_t blksz) {
71+
uint32_t val = blksz & 0xff;
72+
if (!mg_sdio_transfer(sdio, true, 0, MG_SDIO_FBR_FnBLKSZ(f), &val, 1))
73+
return false;
74+
val = (blksz >> 8) & 0x0f; // SDIO 6.10 Table 6-4, max 2048
75+
if (!mg_sdio_transfer(sdio, true, 0, MG_SDIO_FBR_FnBLKSZ(f) + 1, &val, 1))
76+
return false;
77+
// TODO(): store in an array, index on f. Static 8-element array
78+
MG_VERBOSE(("F%c block size set", (f & 7) + '0'));
79+
return true;
80+
}
81+
82+
// Enable Fx
83+
bool mg_sdio_enable_f(struct mg_tcpip_sdio *sdio, unsigned int f) {
84+
uint8_t bit = 1U << (f & 7), bits;
85+
uint32_t val = 0;
86+
if (!mg_sdio_transfer(sdio, false, 0, MG_SDIO_CCCR_IOEN, &val, 1))
87+
return false;
88+
bits = (uint8_t) val | bit;
89+
unsigned int times = 501;
90+
while (times--) {
91+
val = bits; /* IOEf */
92+
;
93+
if (!mg_sdio_transfer(sdio, true, 0, MG_SDIO_CCCR_IOEN, &val, 1))
94+
return false;
95+
mg_delayms(1);
96+
val = 0;
97+
if (!mg_sdio_transfer(sdio, false, 0, MG_SDIO_CCCR_IOEN, &val, 1))
98+
return false;
99+
if (val & bit) break;
100+
}
101+
if (times == (unsigned int) ~0) return false;
102+
MG_VERBOSE(("F%c enabled", (f & 7) + '0'));
103+
return true;
104+
}
105+
106+
// Wait for Fx to be ready
107+
bool mg_sdio_waitready_f(struct mg_tcpip_sdio *sdio, unsigned int f) {
108+
uint8_t bit = 1U << (f & 7);
109+
unsigned int times = 501;
110+
while (times--) {
111+
uint32_t val;
112+
if (!mg_sdio_transfer(sdio, false, 0, MG_SDIO_CCCR_IORDY, &val, 1))
113+
return false;
114+
if (val & bit) break; // IORf
115+
mg_delayms(1);
116+
}
117+
if (times == (unsigned int) ~0) return false;
118+
MG_VERBOSE(("F%c ready", (f & 7) + '0'));
119+
return true;
120+
}
121+
122+
// SDIO 6.14 Bus State Diagram
123+
bool mg_sdio_init(struct mg_tcpip_sdio *sdio) {
124+
uint32_t val = 0;
125+
if (!sdio->txn(sdio, 0, 0, NULL)) return false; // GO_IDLE_STATE
126+
sdio->txn(sdio, 5, 0, &val); // IO_SEND_OP_COND, no CRC
127+
MG_VERBOSE(("IO Functions: %u, Memory: %c", 1 + ((val >> 28) & 7),
128+
(val & MG_BIT(27)) ? 'Y' : 'N'));
129+
if (!sdio->txn(sdio, 3, 0, &val)) return false; // SEND_RELATIVE_ADDR
130+
val = ((uint32_t) val) >> 16; // RCA
131+
if (!sdio->txn(sdio, 7, val << 16, &val))
132+
return false; // SELECT/DESELECT_CARD
133+
mg_sdio_transfer(sdio, false, 0, MG_SDIO_CCCR_SDIOREV, &val, 1);
134+
MG_DEBUG(("CCCR: %u.%u, SDIO: %u.%u", 1 + ((val >> 2) & 3), (val >> 0) & 3,
135+
1 + ((val >> 6) & 3), (val >> 4) & 3));
136+
mg_sdio_transfer(sdio, false, 0, MG_SDIO_CCCR_SDREV, &val, 1);
137+
MG_VERBOSE(("SD: %u.%u", 1 + ((val >> 2) & 3), (val >> 0) & 3));
138+
mg_sdio_transfer(sdio, false, 0, MG_SDIO_CCCR_BIC, &val, 1);
139+
MG_SET_BITS(val, 3,
140+
MG_BIT(7) | MG_BIT(1)); // SDIO 6.9 Tables 6-1 6-2, 4-bit bus
141+
mg_sdio_transfer(sdio, true, 0, MG_SDIO_CCCR_BIC, &val, 1);
142+
// All Full-Speed SDIO cards support a 4-bit bus. Skip for Low-Speed SDIO
143+
// cards, we don't provide separate low-level functions for width and speed
144+
sdio->cfg(sdio, 0); // set DS;
145+
if (!mg_sdio_transfer(sdio, false, 0, MG_SDIO_CCCR_HISPD, &val, 1))
146+
return false;
147+
if (val & MG_BIT(0) /* SHS */) {
148+
val = MG_BIT(1); /* EHS */
149+
if (!mg_sdio_transfer(sdio, true, 0, MG_SDIO_CCCR_HISPD, &val, 1))
150+
return false;
151+
sdio->cfg(sdio, 1); // set HS;
152+
MG_VERBOSE(("Bus set to 4-bit @50MHz"));
153+
} else {
154+
MG_VERBOSE(("Bus set to 4-bit @25MHz"));
155+
}
156+
return true;
157+
}
158+
159+
// - 6.11 Card Information Structure (CIS): 0x0001000-0x017FF; for card common
160+
// and all functions
161+
// - 16.5 SDIO Card Metaformat
162+
// - 16.7.2 CISTPL_FUNCE (0x22): Function Extension Tuple, provides standard
163+
// information about the card (common) and each individual function. One
164+
// CISTPL_FUNCE in each function’s CIS, immediately following the CISTPL_FUNCID
165+
// tuple
166+
// - 16.7.3 CISTPL_FUNCE Tuple for Function 0 (common)
167+
// - 16.7.4 CISTPL_FUNCE Tuple for Function 1-7
168+
169+
#endif

src/drivers/sdio.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#pragma once
2+
3+
#if MG_ENABLE_TCPIP && \
4+
(defined(MG_ENABLE_DRIVER_CYW_SDIO) && MG_ENABLE_DRIVER_CYW_SDIO)
5+
6+
struct mg_tcpip_sdio {
7+
void *sdio; // Opaque SDIO bus descriptor
8+
void (*cfg)(void *, uint8_t); // select operating parameters
9+
// SDIO transaction: send cmd with a possible 1-byte read or write
10+
bool (*txn)(void *, uint8_t cmd, uint32_t arg, uint32_t *r);
11+
// SDIO extended transaction: write or read len bytes, using blksz blocks
12+
bool (*xfr)(void *, bool write, uint32_t arg, uint16_t blksz, uint32_t *,
13+
uint32_t len, uint32_t *r);
14+
};
15+
16+
bool mg_sdio_transfer(struct mg_tcpip_sdio *sdio, bool write, unsigned int f,
17+
uint32_t addr, void *data, uint32_t len);
18+
bool mg_sdio_set_blksz(struct mg_tcpip_sdio *sdio, unsigned int f,
19+
uint16_t blksz);
20+
bool mg_sdio_enable_f(struct mg_tcpip_sdio *sdio, unsigned int f);
21+
bool mg_sdio_waitready_f(struct mg_tcpip_sdio *sdio, unsigned int f);
22+
bool mg_sdio_init(struct mg_tcpip_sdio *sdio);
23+
24+
#endif

src/wifi_dummy.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#include "wifi.h"
22

33
#if (!defined(MG_ENABLE_DRIVER_PICO_W) || !MG_ENABLE_DRIVER_PICO_W) && \
4-
(!defined(MG_ENABLE_DRIVER_CYW) || !MG_ENABLE_DRIVER_CYW)
4+
(!defined(MG_ENABLE_DRIVER_CYW) || !MG_ENABLE_DRIVER_CYW) && \
5+
(!defined(MG_ENABLE_DRIVER_CYW_SDIO) || !MG_ENABLE_DRIVER_CYW_SDIO)
6+
57

68
bool mg_wifi_scan(void) {
79
MG_ERROR(("No Wi-Fi driver enabled"));
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Environment setup: https://mongoose.ws/documentation/tutorials/tools/
2+
3+
CFLAGS = -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion
4+
CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion
5+
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
6+
CFLAGS += -Wno-cast-function-type
7+
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_mcu/Include
8+
CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16 $(CFLAGS_EXTRA) -DCORE_CM7
9+
LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nosys.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
10+
11+
# Wi-Fi chip firmware stuff
12+
CFLAGS += -Imbed/targets/TARGET_STM/TARGET_STM32H7/TARGET_STM32H747xI/TARGET_PORTENTA_H7/COMPONENT_WHD # nvram header includes a text file
13+
14+
CFLAGS += -DMG_HAL_DISABLE_ETHERNET
15+
16+
SOURCES = main.c hal.c mongoose.c
17+
SOURCES += cmsis_mcu/Source/Templates/gcc/startup_stm32h747xx.s
18+
19+
all build: firmware.bin
20+
21+
firmware.bin: firmware.elf
22+
arm-none-eabi-objcopy -O binary $< $@
23+
arm-none-eabi-size --format=berkeley $<
24+
25+
firmware.elf: cmsis_core cmsis_mcu mbed $(SOURCES) $(wildcard *.h) link.ld Makefile
26+
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@
27+
28+
flash: firmware.bin
29+
STM32_Programmer_CLI -c port=swd -w $< 0x8040000 -hardRst
30+
31+
cmsis_core: # ARM CMSIS core headers
32+
git clone --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
33+
cmsis_mcu: # Keil CMSIS headers and drivers for STM32F7 series (CMSIS-pack)
34+
git clone --depth 1 -b v1.10.4 https://github.com/STMicroelectronics/cmsis_device_h7 $@
35+
36+
# Wi-Fi chip firmware
37+
mbed:
38+
git clone --depth 1 --no-checkout -b extrapatches-6.17.0 https://github.com/arduino/mbed-os $@ && cd $@ && git sparse-checkout set targets/TARGET_STM/TARGET_STM32H7/TARGET_STM32H747xI/TARGET_PORTENTA_H7/COMPONENT_WHD/resources && git checkout
39+
touch wiced_resource.h
40+
41+
clean:
42+
rm -rf firmware.* cmsis_core cmsis_mcu mbed
43+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Arduino Portenta H7
2+
3+
Use Mongoose bare metal on the Portenta H7, with only CMSIS and no other overhead

0 commit comments

Comments
 (0)