- 2025-07-13
-
回复了主题帖:
【STM32H73BI-DK评测】适配 SDIO 驱动及 Fatfs 文件系统
Jacktang 发表于 2025-7-12 08:56
通过楼主的测试,感觉RTThread 对 STM32 的驱动支持确实比较友好
是的,旧的系列支持都比较完善了。
- 2025-07-11
-
发表了主题帖:
【STM32H73BI-DK评测】适配 LCD 及 Touch 驱动
本帖最后由 ID.LODA 于 2025-7-17 09:39 编辑
## 适配 LCD 及 Touch 驱动
[开箱体验](https://bbs.eeworld.com.cn/thread-1319973-1-1.html)
[适配 RTThread 系统](https://bbs.eeworld.com.cn/thread-1320428-1-1.html)
[RTThread 适配 SDRAM 驱动 ](https://bbs.eeworld.com.cn/thread-1320434-1-1.html)
[适配 SDIO 驱动及 Fatfs 文件系统](https://bbs.eeworld.com.cn/thread-1320437-1-1.html)
工程代码路径
[bsp/stm32/stm32h7b3i-dk - 码云 - 开源中国](https://gitee.com/morphlings2014/rt-thread-private/tree/master/bsp/stm32/stm32h7b3i-dk)
### 移植 Touch 驱动
touch 型号是 ft5336,使用 i2c 通讯,地址为 0x70
与 mcu 连接的引脚是 PD12,PD13,对应的是 I2C4
#### 修改 RTThread 配置
1. 打开 board\Kconfig 文件,加入如下配置信息
在 menu "Onboard Peripheral Drivers" 下加入如下配置
```python
config BSP_USING_FT5336
bool "Enable LCD Touch"
select RT_USING_TOUCH
select BSP_USING_I2C
select BSP_USING_I2C4
default y
```
在 menu "On-chip Peripheral Drivers" 下加入 I2C 配置
```python
menuconfig BSP_USING_I2C
bool "Enable I2C BUS"
select RT_USING_I2C
default n
if BSP_USING_I2C
choice
prompt "i2c mode"
default BSP_USING_HARD_I2C
config BSP_USING_HARD_I2C
bool "hardware"
select BSP_USING_I2C4
config BSP_USING_SOFT_I2C
bool "software simulation"
select RT_USING_I2C_BITOPS
select RT_USING_PIN
endchoice
if BSP_USING_HARD_I2C
menuconfig BSP_USING_I2C4
bool "Enable I2C4 BUS (hardware)"
default n
endif
if BSP_USING_SOFT_I2C
menuconfig BSP_USING_I2C4
bool "Enable I2C4 BUS (software simulation)"
default n
if BSP_USING_I2C4
comment "Notice: PD12 --> 60; PD13 --> 61"
config BSP_I2C4_SCL_PIN
int "i2c4 scl pin number"
range 0 175
default 60
config BSP_I2C4_SDA_PIN
int "I2C4 sda pin number"
range 0 175
default 61
endif
endif
endif
```
2. 在 board\ports 目录下创建文件 drv_ft5336.c 文件,并修改 board\SConscript ,加入如下配置
```python
if GetDepend(['BSP_USING_FT5336']):
src += Glob('ports/drv_ft5336.c')
```
3. 在 env 控制台输入 `menuconfig` 进行配置,使用 LCD Touch
4. 在 env 控制台输入 `scon --target=mdk5` 更新工程
#### 修改代码
1. rtthread touch 相关的定义和需要实现的接口如下
```c
struct rt_touch_device
{
struct rt_device parent; /* The standard device */
struct rt_touch_info info; /* The touch info data */
struct rt_touch_config config; /* The touch config data */
const struct rt_touch_ops *ops; /* The touch ops */
rt_err_t (*irq_handle)(rt_touch_t touch); /* Called when an interrupt is generated, registered by the driver */
};
struct rt_touch_data
{
rt_uint8_t event; /* The touch event of the data */
rt_uint8_t track_id; /* Track id of point */
rt_uint8_t width; /* Point of width */
rt_uint16_t x_coordinate; /* Point of x coordinate */
rt_uint16_t y_coordinate; /* Point of y coordinate */
rt_tick_t timestamp; /* The timestamp when the data was received */
};
struct rt_touch_ops
{
rt_size_t (*touch_readpoint)(struct rt_touch_device *touch, void *buf, rt_size_t touch_num);
rt_err_t (*touch_control)(struct rt_touch_device *touch, int cmd, void *arg);
};
int rt_hw_touch_register(rt_touch_t touch,
const char *name,
rt_uint32_t flag,
void *data);
```
2. ft5336 获取触摸信息的相关寄存器, 首先通过 02 寄存器获取触点数量,然后通过 03-06 四个寄存器可以获取触点1 的触摸事件,x,y 位置以及 触摸 id 值,ft5336 最大支持 5点触摸,其他几个点的数据格式和 1 是一致。
3. 了解基本的框架和寄存器操作之后我们就可以开始编码了。打开 drv_ft5336.c,先实现 i2c 读写寄存器的操作
```c
static struct rt_i2c_client touch_i2c_client;
static rt_err_t ft5336_write_reg(struct rt_i2c_client *client, rt_uint8_t reg, rt_uint8_t value)
{
struct rt_i2c_msg msg = {0};
rt_uint8_t buf[2];
buf[0] = reg;
buf[1] = value;
msg.addr = client->client_addr;
msg.flags = RT_I2C_WR;
msg.buf = buf;
msg.len = 2;
if (rt_i2c_transfer(client->bus, &msg, 1) != 1)
{
LOG_E("ft5336 write register error");
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t ft5336_read_reg(struct rt_i2c_client *client, rt_uint8_t reg, rt_uint8_t *buf, rt_uint8_t len)
{
struct rt_i2c_msg msgs[2];
msgs[0].addr = client->client_addr;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = ®
msgs[0].len = 1;
msgs[1].addr = client->client_addr;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = buf;
msgs[1].len = len;
if (rt_i2c_transfer(client->bus, msgs, 2) == 2)
{
return RT_EOK;
}
else
{
LOG_E("ft5336 read register error");
return -RT_ERROR;
}
}
```
4. 实现 touch 框架需要的接口,完成 ft5336 初始化,并加入自动初始化流程
```c
static void ft5336_init(struct rt_i2c_client *client)
{
ft5336_write_reg(client, FT5336_DEV_MODE_REG, FT5336_DEV_MODE_WORKING);
ft5336_write_reg(client, FT5336_GMODE_REG, FT5336_G_MODE_INTERRUPT_POLLING);
}
int rt_hw_ft5336_init(const char *name, struct rt_touch_config *cfg)
{
struct rt_touch_device *touch_device = RT_NULL;
touch_device = (struct rt_touch_device *)rt_malloc(sizeof(struct rt_touch_device));
if(touch_device == RT_NULL)
{
LOG_E("touch device malloc failed");
return -RT_ERROR;
}
rt_memset((void *)touch_device, 0, sizeof(struct rt_touch_device));
touch_i2c_client.client_addr = TOUCH_I2C_ADDRESS >> 1;
touch_i2c_client.bus = (struct rt_i2c_bus_device *)rt_device_find(cfg->dev_name);
if(touch_i2c_client.bus == RT_NULL)
{
LOG_E("Can't find %s device", cfg->dev_name);
return -RT_ERROR;
}
if(rt_device_open((rt_device_t)touch_i2c_client.bus, RT_DEVICE_FLAG_RDWR) != RT_EOK)
{
LOG_E("open %s device failed", cfg->dev_name);
return -RT_ERROR;
}
ft5336_init(&touch_i2c_client);
/* register touch device */
touch_device->info.type = RT_TOUCH_TYPE_CAPACITANCE;
touch_device->info.vendor = RT_TOUCH_VENDOR_FT;
touch_device->info.point_num = 1;
touch_device->info.range_x = 480;
touch_device->info.range_y = 272;
rt_memcpy(&touch_device->config, cfg, sizeof(struct rt_touch_config));
touch_device->ops = &ops;
if (rt_hw_touch_register(touch_device, name, RT_DEVICE_FLAG_RDONLY, &touch_i2c_client) != RT_EOK)
{
return -RT_EIO;
}
return RT_EOK;
}
int drv_touch_hw_init(void)
{
struct rt_touch_config cfg;
cfg.dev_name = "i2c4";
rt_hw_ft5336_init("touch_ft", &cfg);
return RT_EOK;
}
INIT_DEVICE_EXPORT(drv_touch_hw_init);
```
5. 再编写触摸信息的读取
```c
static int16_t pre_x[FT5336_MAX_NB_TOUCH] = {-1, -1, -1, -1, -1};
static int16_t pre_y[FT5336_MAX_NB_TOUCH] = {-1, -1, -1, -1, -1};
static int16_t pre_w[FT5336_MAX_NB_TOUCH] = {-1, -1, -1, -1, -1};
static rt_uint8_t s_tp_down[FT5336_MAX_NB_TOUCH];
static struct rt_touch_data *touch_data;
static void ft5336_touch_up(void *buf, int8_t id)
{
touch_data = (struct rt_touch_data *)buf;
if(s_tp_down[id] == 1)
{
s_tp_down[id] = 0;
touch_data[id].event = RT_TOUCH_EVENT_UP;
}
else
{
touch_data[id].event = RT_TOUCH_EVENT_NONE;
}
touch_data[id].timestamp = rt_touch_get_ts();
touch_data[id].width = pre_w[id];
touch_data[id].x_coordinate = pre_x[id];
touch_data[id].y_coordinate = pre_y[id];
touch_data[id].track_id = id;
pre_x[id] = -1; /* last point is none */
pre_y[id] = -1;
pre_w[id] = -1;
}
static void ft5336_touch_down(void *buf, int8_t id, int16_t x, int16_t y, int16_t w)
{
touch_data = (struct rt_touch_data *)buf;
if (s_tp_down[id] == 1)
{
touch_data[id].event = RT_TOUCH_EVENT_MOVE;
}
else
{
touch_data[id].event = RT_TOUCH_EVENT_DOWN;
s_tp_down[id] = 1;
}
touch_data[id].timestamp = rt_touch_get_ts();
touch_data[id].width = w;
touch_data[id].x_coordinate = x;
touch_data[id].y_coordinate = y;
touch_data[id].track_id = id;
pre_x[id] = x; /* save last point */
pre_y[id] = y;
pre_w[id] = w;
}
static rt_size_t ft5336_readpoint(struct rt_touch_device *touch, void *data, rt_size_t touch_num)
{
struct rt_i2c_client *i2c_client = (struct rt_i2c_client *)touch->parent.user_data;
if (touch_num > FT5336_TD_STATUS_BIT_POSITION;
/* point num is not correct */
if ((nb_touch > FT5336_MAX_NB_TOUCH) || (nb_touch == 0))
{
nb_touch = 0;
goto exit_;
}
if (nb_touch > touch_num) {
nb_touch = touch_num;
}
/* read point num is touch_num */
if (ft5336_read_reg(i2c_client, FT5336_P1_XH_REG, read_buf, touch_num * FT5336_ONE_TOUCH_REG_CNT) != RT_EOK)
{
LOG_E("read point failed");
nb_touch = 0;
goto exit_;
}
/* point up */
if(pre_touch > nb_touch)
{
for (read_index = 0; read_index < pre_touch; read_index++)
{
rt_uint8_t j;
/* this time touch num */
for (j = 0; j < nb_touch; j++)
{
read_id = read_buf[j * 8] & 0x0F;
/* this id is not free */
if (pre_id[read_index] == read_id)
break;
if (j >= nb_touch - 1)
{
rt_uint8_t up_id;
up_id = pre_id[read_index];
ft5336_touch_up(read_buf, up_id);
}
}
}
}
/* point down */
if (nb_touch)
{
uint8_t ts_event;
for(read_index = 0; read_index < nb_touch; read_index++)
{
/* Send back first ready X position to caller */
input_y = ((read_buf[read_index*6U] & FT5336_P1_XH_TP_BIT_MASK) FT5336_P1_XH_EF_BIT_POSITION);
/* Send back first ready Weight to caller */
input_w = (read_buf[(read_index*6U) + 4U] & FT5336_P1_WEIGHT_BIT_MASK);
/* Send back first ready Area to caller */
// State->TouchArea = (read_buf[(read_index*6U) + 5U] & FT5336_P1_MISC_BIT_MASK) >> FT5336_P1_MISC_BIT_POSITION;
read_id = ((read_buf[(read_index*6U) + 2U] & FT5336_P1_YH_TID_BIT_MASK) >> FT5336_P1_YH_TID_BIT_POSITION);
pre_id[read_index] = read_id;
LOG_D("%d touch info x=%03d y=%03d w=%03d event=%d read_id %d", read_id, input_x, input_y, input_w, ts_event, read_id);
ft5336_touch_down(data, read_id, input_x, input_y, input_w);
}
}
else if (pre_touch)
{
for(read_index = 0; read_index < pre_touch; read_index++)
{
ft5336_touch_up(data, pre_id[read_index]);
}
}
pre_touch = nb_touch;
exit_:
return nb_touch;
}
```
6. 因为 CubeMx 工程用的官方板卡示例,全部外设引脚都已初始化,如果是其他板子,还需要在 stm32h7xx_hal_msp.c 中加入 I2C 相应的引脚配置
7. 编写测试代码验证
```c
rt_thread_t ft5336_thread;
rt_device_t touch;
void ft5336_thread_entry(void *parameter)
{
struct rt_touch_info info;
struct rt_touch_data *read_data;
rt_device_control(touch, RT_TOUCH_CTRL_GET_INFO, &info);
LOG_I("type :%d", info.type);
LOG_I("vendor :%d", info.vendor);
LOG_I("point_num :%d", info.point_num);
LOG_I("range_x :%d", info.range_x);
LOG_I("range_y :%d", info.range_y);
read_data = (struct rt_touch_data *)rt_calloc(1, sizeof(struct rt_touch_data));
while(1)
{
if (rt_device_read(touch, 0, read_data, info.point_num) == info.point_num)
{
for (rt_uint8_t i = 0; i < info.point_num; i++)
{
if (read_data->event == RT_TOUCH_EVENT_DOWN)
{
rt_kprintf("%d, down x: %03d y: %03d", read_data->track_id, read_data->x_coordinate, read_data->y_coordinate);
rt_kprintf(" t: %d\n", read_data->timestamp);
}
else if (read_data->event == RT_TOUCH_EVENT_MOVE)
{
rt_kprintf("%d move x: %03d y: %03d", read_data->track_id, read_data->x_coordinate, read_data->y_coordinate);
rt_kprintf(" t: %d\n", read_data->timestamp);
}
else if (read_data->event == RT_TOUCH_EVENT_UP)
{
rt_kprintf("%d up x: %03d y: %03d", read_data->track_id, read_data->x_coordinate, read_data->y_coordinate);
rt_kprintf(" t: %d\n", read_data->timestamp);
}
}
}
rt_thread_delay(10);
}
}
int ft5336_example(void)
{
touch = rt_device_find("touch_ft");
rt_device_open(touch, RT_DEVICE_FLAG_RDONLY);
ft5336_thread = rt_thread_create("touch", ft5336_thread_entry, RT_NULL, 800, 10, 20);
if (ft5336_thread == RT_NULL)
{
LOG_E("create touch thread err");
return -RT_ENOMEM;
}
rt_thread_startup(ft5336_thread);
return RT_EOK;
}
//INIT_APP_EXPORT(ft5336_example);
MSH_CMD_EXPORT(ft5336_example, ft5336 tc...);
```
#### 测试运行
经过上述修改之后,编译下载代码,打开对应的串口,可以看到 touch 设置正常挂载
输入测试指令 ft5336_example,触摸屏幕,可以看到有触摸事件产生
### 移植 LCD 驱动
rthread\bsp\stm32\libraries\HAL_Drivers\drivers 带了 lcd 相关的驱动实现,我们只要添加头文件描述,并根据使用的芯片型号 RK043FN48H 配置一些宏参数就可以运行
#### 修改 RTThread 配置
1. 打开 board\Kconfig 文件,加入如下配置信息
在 menu "Onboard Peripheral Drivers" 下加入如下配置
```python
config BSP_USING_LCD
bool "Enable LCD"
select BSP_USING_LTDC
select BSP_USING_FT5336
default n
```
在 menu "On-chip Peripheral Drivers" 下加入 I2C 配置
```python
config BSP_USING_LTDC
bool "Enable LTDC"
default n
```
2. 在 board\ports 目录下创建文件 lcd_port.h 文件
3. 在 env 控制台输入 `menuconfig` 进行配置更新,使能 lcd
4. 在 env 控制台输入 `scon --target=mdk5` 更新工程
#### 修改代码
1. 打开 lcd_port.h,写入 LCD 长宽等相关参数,时序参数需要参考对应的手册
```c
#define LCD_WIDTH 480
#define LCD_HEIGHT 272
#define LCD_BITS_PER_PIXEL 16
#define LCD_BUF_SIZE (LCD_WIDTH * LCD_HEIGHT * LCD_BITS_PER_PIXEL / 8)
#define LCD_PIXEL_FORMAT RTGRAPHIC_PIXEL_FORMAT_RGB565
#define LCD_HSYNC_WIDTH 41
#define LCD_HBP 2//13
#define LCD_HFP 32
#define LCD_VSYNC_HEIGHT 10
#define LCD_VBP 2
#define LCD_VFP 2
#define LCD_BACKLIGHT_USING_GPIO
#define LCD_BL_GPIO_NUM GET_PIN(A, 1)
#define LCD_DISP_GPIO_NUM GET_PIN(A, 2)
```
2. 显示屏 RK043FN48H 典型工作频率是 9.7 MHz, 我们在 stm32h7xx_hal_msp.c 里设置的是 96Mhz,所以需要修改下,因为 LTDC 时钟是固定连接在 PLL3R 上,最简单的方式是将 PLL3R 改为 20,根据公式换算下来是 9.6Mhz,可以用
>计算公式
>
>PLL3_VCO Input = HSE_VALUE/PLL3M = 1 Mhz
>
>PLL3_VCO Output = PLL3_VCO Input * PLL3N = 1*192 = 192Mhz
>
>PLLLCDCLK = PLL3_VCO Output/PLL3R = 192/20 = 9.6 Mhz
>
>LTDC clock frequency = PLLLCDCLK = 9.6 Mhz */
```c
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
PeriphClkInitStruct.PLL3.PLL3M = 24;
PeriphClkInitStruct.PLL3.PLL3N = 192;
PeriphClkInitStruct.PLL3.PLL3P = 17;
PeriphClkInitStruct.PLL3.PLL3Q = 2;
PeriphClkInitStruct.PLL3.PLL3R = 20;
PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_0;
PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE;
PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
```
如果要追求更接近的匹配,也可以按如下或者其他配置,主要不影响其他外设即可
```c
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
PeriphClkInitStruct.PLL3.PLL3M = 6;
PeriphClkInitStruct.PLL3.PLL3N = 200;
PeriphClkInitStruct.PLL3.PLL3P = 10;
PeriphClkInitStruct.PLL3.PLL3Q = 10;
PeriphClkInitStruct.PLL3.PLL3R = 83;
PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_0;
PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE;
PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
```
3. 除此之外,还要单独设置下 LCD_DE 控制脚,默认将其置低
```c
/* USER CODE BEGIN LTDC_MspInit 1 */
LCD_DISP_EN_GPIO_CLK_ENABLE();
/* LCD_DISP_EN GPIO configuration */
GPIO_InitStruct.Pin = LCD_DISP_EN_PIN; /* LCD_DISP pin has to be manually controlled */
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(LCD_DISP_EN_GPIO_PORT, &GPIO_InitStruct);
/* De-assert display enable LCD_DISP_EN pin */
HAL_GPIO_WritePin(LCD_DISP_EN_GPIO_PORT, LCD_DISP_EN_PIN, GPIO_PIN_RESET);
```
#### 测试运行
经过上述修改之后,编译下载代码,打开对应的串口,可以看到 lcd 设备正常挂载
输入测试指令 `lcd_test 指令,屏幕会自动刷单色背景
- 2025-07-10
-
发表了主题帖:
【STM32H73BI-DK评测】适配 SDIO 驱动及 Fatfs 文件系统
## 适配 SDIO 驱动及 Fatfs 文件系统
[开箱体验](https://bbs.eeworld.com.cn/thread-1319973-1-1.html)
[适配 RTThread 系统](https://bbs.eeworld.com.cn/thread-1320428-1-1.html)
[RTThread 适配 SDRAM 驱动 ](https://bbs.eeworld.com.cn/thread-1320434-1-1.html)
工程代码路径
[bsp/stm32/stm32h7b3i-dk - 码云 - 开源中国](https://gitee.com/morphlings2014/rt-thread-private/tree/master/bsp/stm32/stm32h7b3i-dk)
### 移植
rthread\bsp\stm32\libraries\HAL_Drivers\drivers 带了 sdio 相关的驱动实现,我们只需要在 Kconfig 中加入相关配置即可
#### 修改 RTThread 配置
1. 打开 board\Kconfig 文件,加入如下配置信息
在 menu "Onboard Peripheral Drivers" 下加入如下配置
```python
menuconfig BSP_USING_FS
bool "Enable filesystem"
select RT_USING_DFS
default n
if BSP_USING_FS
config BSP_USING_SDCARD_FS
bool "Enable SDCARD filesystem"
select BSP_USING_SDIO
select RT_USING_DFS_ELMFAT
default n
endif
```
在 menu "On-chip Peripheral Drivers" 下加入如下配置
```python
config BSP_USING_SDIO
bool "Enable SDIO"
select RT_USING_SDIO
default n
if BSP_USING_SDIO
config BSP_USING_SDIO1
bool "Enable SDIO1"
default y
endif
```
2. 在 env 控制台输入 `menuconfig` 进行配置,打开文件系统支持
3. 需要支持中文目录的话,还需要修改文件系统的配置
4. 在 board\ports 目录下创建文件 filesystem.c 文件,并修改 board\SConscript ,加入如下配置
```python
if GetDepend(['BSP_USING_FS']):
src += Glob('ports/filesystem.c')
```
5. 在 env 控制台输入 `scon --target=mdk5` 更新工程
#### 修改代码
1. 打开 filesystem.c ,加入文件系统挂载代码,创建挂载现在支持动态插拔
```c
#include
#ifdef BSP_USING_FS
#if DFS_FILESYSTEMS_MAX < 4
#error "Please define DFS_FILESYSTEMS_MAX more than 4"
#endif
#if DFS_FILESYSTEM_TYPES_MAX < 4
#error "Please define DFS_FILESYSTEM_TYPES_MAX more than 4"
#endif
#include
#ifdef BSP_USING_SDCARD_FS
#include
#include "drv_sdmmc.h"
#endif
#ifdef BSP_USING_SPI_FLASH_FS
#include "fal.h"
#endif
#define DBG_TAG "app.filesystem"
#define DBG_LVL DBG_INFO
#include
#ifdef RT_USING_DFS_ROMFS
#include "dfs_romfs.h"
#ifdef RT_USING_DFS_ELMFAT
static const struct romfs_dirent _romfs_root[] =
{
{ROMFS_DIRENT_DIR, "flash", RT_NULL, 0},
{ROMFS_DIRENT_DIR, "sdcard", RT_NULL, 0}
};
#endif
const struct romfs_dirent romfs_root =
{
ROMFS_DIRENT_DIR, "/", (rt_uint8_t *)_romfs_root, sizeof(_romfs_root) / sizeof(_romfs_root[0])
};
#endif
#ifdef BSP_USING_SDCARD_FS
/* SD Card hot plug detection pin */
#define SD_CHECK_PIN GET_PIN(I, 8)
static void _sdcard_mount(void)
{
rt_device_t device;
device = rt_device_find("sd");
if (device == NULL)
{
mmcsd_wait_cd_changed(0);
stm32_mmcsd_change();
mmcsd_wait_cd_changed(RT_WAITING_FOREVER);
device = rt_device_find("sd");
}
if (device != RT_NULL)
{
if (dfs_mount("sd", "/sdcard", "elm", 0, 0) == RT_EOK)
{
LOG_I("sd card mount to '/sdcard'");
}
else
{
LOG_W("sd card mount to '/sdcard' failed!");
}
}
}
static void _sdcard_unmount(void)
{
rt_thread_mdelay(200);
dfs_unmount("/sdcard");
LOG_I("Unmount \"/sdcard\"");
mmcsd_wait_cd_changed(0);
stm32_mmcsd_change();
mmcsd_wait_cd_changed(RT_WAITING_FOREVER);
}
static void sd_mount(void *parameter)
{
rt_uint8_t re_sd_check_pin = 1;
rt_thread_mdelay(200);
if (rt_pin_read(SD_CHECK_PIN) == 0)
{
_sdcard_mount();
}
while (1)
{
rt_thread_mdelay(200);
if (re_sd_check_pin && (re_sd_check_pin = rt_pin_read(SD_CHECK_PIN)) == 0)
{
_sdcard_mount();
}
if (!re_sd_check_pin && (re_sd_check_pin = rt_pin_read(SD_CHECK_PIN)) != 0)
{
_sdcard_unmount();
}
}
}
#endif /* BSP_USING_SDCARD_FS */
int mount_init(void)
{
#ifdef RT_USING_DFS_ROMFS
if (dfs_mount(RT_NULL, "/", "rom", 0, &(romfs_root)) != 0)
{
LOG_E("rom mount to '/' failed!");
}
#endif /* RT_USING_DFS_ROMFS */
#ifdef BSP_USING_SDCARD_FS
rt_thread_t tid;
rt_pin_mode(SD_CHECK_PIN, PIN_MODE_INPUT_PULLUP);
tid = rt_thread_create("sd_mount", sd_mount, RT_NULL,
2048, RT_THREAD_PRIORITY_MAX - 2, 20);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
else
{
LOG_E("create sd_mount thread err!");
}
#endif /* BSP_USING_SDCARD_FS */
return RT_EOK;
}
INIT_ENV_EXPORT(mount_init);
#endif /* BSP_USING_FS */
```
2. 因为 CubeMx 工程用的官方板卡示例,全部外设引脚都已初始化,如果是其他板子,还需要在 stm32h7xx_hal_msp.c 中加入 SDIO 相应的引脚配置
### 运行
经过上述修改之后,编译下载代码,打开对应的串口,实际运行效果如下
查看中文目录
### 总结
介于 RTThread 对 STM32 的驱动支持相对比较完善,我们要加入 SDIO 的支持也是相对比较容易,挂载文件系统也是比较容易
- 2025-07-04
-
回复了主题帖:
【STM32H73BI-DK评测】开箱体验
wangerxian 发表于 2025-7-2 10:02
应该上800x480或以上的。
新出的板子好像都升级了,h7rs7,n6 的 dk 都是 800*480 的
-
发表了主题帖:
【STM32H73BI-DK评测】RTThread 适配 SDRAM 驱动
# 适配 SDRAM 驱动
[开箱体验](https://bbs.eeworld.com.cn/thread-1319973-1-1.html)
[适配 RTThread 系统](https://bbs.eeworld.com.cn/thread-1320428-1-1.html)
工程代码路径
[bsp/stm32/stm32h7b3i-dk - 码云 - 开源中国](https://gitee.com/morphlings2014/rt-thread-private/tree/master/bsp/stm32/stm32h7b3i-dk)
## 移植
rthread\bsp\stm32\libraries\HAL_Drivers\drivers 带了 sdram 相关的驱动实现,我们只要添加头文件,并根据使用的芯片型号配置一些宏参数就可以运行
### 修改 RTThread 配置
1. 打开 board\Kconfig 文件,加入如下配置信息
```python
config BSP_USING_SDRAM
bool "Enable SDRAM"
select BSP_USING_FMC
default y
```
2. 在 env 控制台输入 `menuconfig` 进行配置更新,因为默认打开就直接保存
3. 在 env 控制台输入 `scon --target=mdk5` 更新工程
### 修改代码
1. 在 board\port 添加 sdram_port.h 文件,写入如下配置,具体参数可以查看板载 SDRAM 芯片 is42s16800j 的手册
```c
#ifndef __SDRAM_PORT_H__
#define __SDRAM_PORT_H__
/* parameters for sdram peripheral */
/* Bank1 or Bank2 */
#define SDRAM_TARGET_BANK 2
/* stm32h7 Bank1:0xC0000000 Bank2:0xD0000000 */
#define SDRAM_BANK_ADDR ((uint32_t)0xD0000000)
/* data width: 8, 16, 32 */
#define SDRAM_DATA_WIDTH 16
/* column bit numbers: 8, 9, 10, 11 */
#define SDRAM_COLUMN_BITS 9
/* row bit numbers: 11, 12, 13 */
#define SDRAM_ROW_BITS 12
/* burst length: 1, 2, 4 */
#define SDRAM_BURST_LENGTH 1
/* cas latency clock number: 1, 2, 3 */
#define SDRAM_CAS_LATENCY 2
/* read pipe delay: 0, 1, 2 */
#define SDRAM_RPIPE_DELAY 2
/* clock divid: 2, 3 */
#define SDCLOCK_PERIOD 3
/* refresh rate counter */
#define SDRAM_REFRESH_COUNT ((uint32_t)0x0603)
#define SDRAM_SIZE ((uint32_t)0x1000000)
/* Timing configuration for IS42S16800F */
/* 100 MHz of HCKL3 clock frequency (200MHz/2) */
/* TMRD: 2 Clock cycles */
#define LOADTOACTIVEDELAY 2
/* TXSR: 7x10ns */
#define EXITSELFREFRESHDELAY 7
/* TRAS: 4x10ns */
#define SELFREFRESHTIME 4
/* TRC: 7x10ns */
#define ROWCYCLEDELAY 7
/* TWR: 2 Clock cycles */
#define WRITERECOVERYTIME 2
/* TRP: 2x10ns */
#define RPDELAY 2
/* TRCD: 2x10ns */
#define RCDDELAY 2
/* memory mode register */
#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200)
#endif
```
2. 修改 drv_sdram.c 文件,里面有个参数原先是按 SDRAM_DATA_WIDTH 配置,不是很合理,重新定义个 SDRAM_BURST_LENGTH 宏配置下
3. 因为 CubeMx 工程用的官方板卡示例,全部外设引脚都已初始化,如果是其他板子,还需要在 stm32h7xx_hal_msp.c 中加入相应的引脚配置
## 运行
经过上述修改之后,编译下载代码,打开对应的串口,实际运行效果如下
- 初始化映射的地址为 0xD000000
- 输入 `free` 查看内存,可以看到有 sdram 池的信息
- 可以输入 sdram_test 进行测试
## 总结
介于 RTThread 对 STM32 的驱动支持相对比较完善,我们要加入 SDRAM 的支持也是相对比较容易
-
发表了主题帖:
【STM32H73BI-DK评测】适配 RTThread 系统
# STM32H7B3I-DK
[STM32H73BI-DK评测](https://bbs.eeworld.com.cn/thread-1319973-1-1.html)
## 移植
操作系统选择 rtthread,集成的软件包比较丰富,同时对 stm32 的驱动支持已经比较完善。版本方面建议选择打 TAG 的版本,master 更新比较快,每次同步对工程的影响可能比较大。
BSP 工程这里我们以 stm32h743-st-nucleo 为模板,复制并修改目录名为 stm32h7b3i-dk,后续按如下步骤进行修改
### 创建 CubeMX 工程
1. 首先删除 board\CubeMX_Config 目录下的文件,用 STM32CubeMx 重新创建一个基于 stm32h7b3i 芯片的工程,因为我们用的官方板卡,可以偷懒直接使用板卡的配置
2. 创建工程之后,切换到 Project Manager 选型,对工程命名,并保存到 BSP 目录下 board\CubeMX_Config ,点击保存
### 修改 RTThread 配置
主要包含 SConstruct, SConscript, Kconfig 等配置的修改,keil 工程的设置,以及启动配置相关的调整
1. 修改 Kconfig 文件,配置芯片宏和相关依赖
2. 修改 board/SConscript 脚本,将对应的启动文件改成 stm32h7b3i 对应的,芯片宏也替换成 STM32H7B3xxQ
3. 修改board/Kconfig 文件,将控制台串口修改为板卡对应的 UART1
4. 修改 template.uvprojx 将默认的芯片型号改成 stm32h7b3i
5. 修改 board\linker_scripts\link.sct 链接脚本
6. 打开 env 工具,输入 `menuconfig` 进行配置
7. 保存退出,输入 `scons --target=mdk5` 重新生成工程
### 修改代码
更新 mdk 工程之后,还需要修改一些初始化代码
1. 打开 board.c 对时钟配置进行修改,如果开启 MPU 也可以在这里进行相应的配置
```c
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/*AXI clock gating */
RCC->CKGAENR = 0xFFFFFFFF;
/** Supply configuration update enable */
HAL_PWREx_ConfigSupply(PWR_DIRECT_SMPS_SUPPLY);
/** Configure the main internal regulator output voltage */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/** Configure LSE Drive Capability */
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE
|RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = 64;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 12;
RCC_OscInitStruct.PLL.PLLN = 280;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
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.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
{
Error_Handler();
}
__HAL_RCC_SYSCFG_CLK_ENABLE() ;
HAL_EnableCompensationCell();
HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_1);
/* MPU Configuration--------------------------------------------------------*/
MPU_Config();
return;
}
```
2. 打开 board.h 对内存配置进行响应修改,影响内存管理
3. 修改 main.c 中 LED 引脚的配置,改成板卡实际的引脚
```c
#include
#include
#include
/* defined the LED0 pin: G11 */
#define LED_PIN GET_PIN(G, 11)
int main(void)
{
rt_uint32_t count = 1;
rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
while(count++)
{
rt_thread_mdelay(500);
rt_pin_write(LED_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED_PIN, PIN_LOW);
}
return RT_EOK;
}
```
## 运行
经过上述修改之后,编译下载代码,打开对应的串口,实际运行效果如下
## 总结
RTThread 对 STM32 的驱动支持相对比较完善,我们创建新的板卡工程也是有很多模板可以参考,相对也是比较容易快速的搭建。
移植好的示例代码地址如下
[示例](https://gitee.com/morphlings2014/rt-thread-private/tree/master/bsp/stm32/stm32h7b3i-dk "示例")
- 2025-07-02
-
回复了主题帖:
【STM32H73BI-DK评测】开箱体验
秦天qintian0303 发表于 2025-7-1 10:09
为什么要设计一个STMod+ 的扩展板卡,有什么硬性要求吗?
定义个标准接口,方便设计小模块,又比在板子上引出排针显得好看写
-
回复了主题帖:
【STM32H73BI-DK评测】开箱体验
wangerxian 发表于 2025-6-30 18:03
这个开发板就适合做GUI,主频和内存都够用。
确实,芯片自带 1M+ SRAM,板载又加了 16M SDRAM,就是屏幕还是老掉牙的 480*272
- 2025-06-30
-
发表了主题帖:
【STM32H73BI-DK评测】开箱体验
本帖最后由 ID.LODA 于 2025-6-30 16:31 编辑
# STM32H7B3I-DK
经过两周的等待,也是成功收到了 STM32H7B3I-DK 板卡。现在 ST 的包装也是采用了纸盒,和原先的塑料比起来,简约了不少,也更方便收藏了
拆开包装里面包含了一块 STM32H7B3I-DK 板卡和一个 STMod+ 的扩展板卡,一份说明书
## 板卡介绍
板卡主控用的 STM32H7B3LIH6QU 基于ARM®架构的微控制器,提供 2M 字节的 FLASH 存储器和 1.4MB RAM,BGA225封装。但是主频只有 280M 和其他 H7 系类相比,低了不少,不知道是出于什么考量。
[官网介绍]: https://www.st.com.cn/zh/evaluation-tools/stm32h7b3i-dk.html#overview
板载资源如下
- 4.3英寸(480x272像素)TFT彩色LCD模块,包含带RGB接口的电容式触摸屏
- Wi‑Fi®模块符合802.11 b/g/n
- USB OTG HS
- 音频编解码器
- 512-Mbit Octo-SPI NOR 闪存
- 128-Mbit SDRAM
- 2个用户LED
- 用户按钮和复位按钮
- Fanout子板
- 1x FDCAN
- 板连接器:
- 摄像头(8位)
- 带Micro-AB的USB
- 立体声耳机插孔,包括模拟麦克风输入
- 用于外部扬声器的音频插孔
- microSD™卡
- TAG-Connect10引脚尺寸
- Arm® Cortex® 10引脚 1.27mm螺距调试连接器,STDC14尺寸
- ARDUINO® Uno V3扩展连接器
- STMod+ 扩展连接器
- 音频子板扩展接口
- External I2C扩展连接器
## 示例测试
出场固件提供了丰富的示例代码,包含了 touchgfx,emwin,embededwizard 多个图形库示例
- 设备信息描述, 280Mhz 主频,固件版本 1.0.1
- 天气 app 界面展示,左右滑动可以查看不同地区,右上角设置包含了 wifi 的连接控制,不过我试了下一直显示连接失败
- touchgfx 实现的是智能家居的示例,包含一个 bashroom 和 kitchen 的房间控制
Bathroom 洗衣机的控制界面
- stemwin 实现的是一个游戏界面,类似小鸟快飞,可以上下前后拖动,整体运行非常流畅
- embeded wizard 提供的是一套综合示例,包含一些空间的基本使用展示
- 其他还有一些音视频的 APP 等,因为没有放置 sd 卡等一些原因无法正常运行就没展示,整体出厂示例是我遇到过最丰富的
## 总结
STM32H7B系列具有 280MHz Arm®Cortex®-M7 的处理性能、高存储容量和节能技术,尤为适用于设计下一代智能产品设备。高达1.4MB的SRAM 配合内嵌图像处理引擎,Chrom-ART™ 图形处理加速器和JEPG硬件加速器,不仅可以节省内核处理能力,同时可以加速图形内容的创建,从而释放MCU的占用,提高其他应用程序的处理速度
- 2025-06-06
-
回复了主题帖:
测评入围名单:STM32H7B3I-DK探索套件
已查看我的测评计划,可在活动期间内完成并发帖分享
- 2025-03-03
-
加入了学习《2024digikey多功能旋钮》,观看 2024digikey多功能旋钮
- 2025-01-08
-
回复了主题帖:
24年年终盘点来啦!精选强推:原创、测评、拆解、视频、资料
关注一下
- 2024-11-07
-
回复了主题帖:
【得捷电子Follow me第1期】+ 提交贴
damiaa 发表于 2024-11-6 08:46
不知道这个室内效果如何。
不太行,至少得放窗边
- 2024-08-01
-
回复了主题帖:
【瑞萨RA8D1板卡】 修复板卡按键
nmg 发表于 2024-8-1 08:59
看你接线那里,似乎没有焊盘?
最后是用什么补焊上脱落地方的,没看明白
应该连走线上了,绿油刮掉就行