STM32F4 NANO + RT-Thread Studio 测试工程搭建流程
硬件: 正点原子 NANO开发板
MCU: STM32F411RCT6
开发平台:RT-Thread-Studio
1 新建工程
新建RTT工程,选择以下配置,使用位置自行选择 注意不要中文和空格目录:
-
基于芯片 -
系列:stm32F4 -
子系列: F411 -
芯片:F411RC -
控制台串口:UART1 -
发送脚 :PA9 接收脚:PA10 -
调试器:ST-Link -
接口:SWD 建好工程点击界面小锤子编译通过,打开串口工具,配置波特率115200,点击下载按钮下载到开发板。打印出"Hello RT-Thread!" \ | /
- RT - Thread Operating System
/ | \ 4.0.3 build Oct 14 2021
2006 - 2020 Copyright by rt-thread team
[D/main] Hello RT-Thread!
msh >[D/main] Hello RT-Thread!
[D/main] Hello RT-Thread!
[D/main] Hello RT-Thread!
msh >[D/main] Hello RT-Thread!
[D/main] Hello RT-Thread!
[D/main] Hello RT-Thread!
按 TAB 键,显示出msh常用命令。 RT-Thread shell commands:
clear - clear the terminal screen
version - show RT-Thread version information
list_thread - list thread
list_sem - list semaphore in system
list_event - list event in system
list_mutex - list mutex in system
list_mailbox - list mail box in system
list_msgqueue - list message queue in system
list_mempool - list memory pool in system
list_timer - list timer in system
list_device - list device in system
help - RT-Thread shell help.
ps - List threads in the system.
free - Show the memory usage in the system.
reboot - Reboot System
在配置工程里的 Download 的选择卡中,复位模式选择 System Reset ,从而保证每次下载完成后能够自动重启。
2.测试按键 和 LED 和 beep
硬件:
-
LED: PC0-PC7 -
key: PC8 PC9 PD2 -
Beep: PB8
功能:
方法:
-
代码简洁易懂,充分使用RT-Thread提供的API -
详细注释 -
线程安全 -
断言保护 -
API操作简单 配置选项中 enable example
agile_button是基于RT-Thread实现的button软件包,提供button操作的API。
- 代码简洁易懂,充分使用RT-Thread提供的API
- 详细注释
- 线程安全
- 断言保护
- API操作简单
配置选项中 enable example
2.3 使用 beep控制蜂鸣器
基于 rt-thread 的 pin 和 pwm 驱动的蜂鸣器控制软件包,可以容易地驱动有源蜂鸣器或无源蜂鸣器,产生各种间隔长短的鸣叫声。 对于使用无源蜂鸣器,还支持PM(电源管理)组件,能设置使得MCU运行频率发生变化时,有正确的发声频率;也可以设置在发声期间,阻止MCU进入STOP模式,维持正常的发声。
配置选项中 Beep the buzzer on console to test
编译提示错误:
../packages/agile_led-latest/examples/example_agile_led.c:2:22: fatal error: drv_gpio.h: No such file or directory
将 #include <drv_gpio.h> 修改成#include <drv_common.h>
配置好example中的led 引脚:
#define LED0_PIN GET_PIN(C, 0)
#define LED1_PIN GET_PIN(C, 1)
#define LED2_PIN GET_PIN(C, 2)
配置好example中的key 引脚:
#define WK_UP_KEY_PIN GET_PIN(A, 0)
#define KEY0_PIN GET_PIN(C, 8)
#define KEY1_PIN GET_PIN(C, 9)
#define KEY2_PIN GET_PIN(D, 2)
测试led:
msh >led_create
msh >led_start 0
msh >led_start 1
msh >led_start 2
测试key,分别 按下 0 1 2 wkup则在msh中显示:
msh >key_create
msh >[button click event] pin:40 repeat:1, hold_time:170
[button click event] pin:40 repeat:1, hold_time:200
[button click event] pin:41 repeat:1, hold_time:165
[button click event] pin:50 repeat:1, hold_time:230
[button click event] pin:0 repeat:1, hold_time:180
测试beep, 在main.c中添加:
#include <drv_common.h>
#define BEEP GET_PIN(B, 8) //24
...
beep_init(BEEP, 1);
在msh中运行, 则beep (B8对应num是24)以1000ms周期 50% 占空比 1000 频率鸣叫3声:
msh >beep on
Please input: beep <nums> <period> [prcent] [freq]
msh >beep 3 1000 50 1000
3. 测试PWM 连接无源蜂鸣器
硬件:TIM2 CH2
3.1 使用自带的例程
添加组件驱动 PWM
stm32f4xx_hal_conf.h 中, 添加:#define HAL_PWM_MODULE_ENABLED
board.h 中添加#define BSP_USING_PWM2
pwm_config.h 添加:
#ifdef BSP_USING_PWM2
#ifndef PWM2_CONFIG
#define PWM2_CONFIG \
{ \
.tim_handle.Instance = TIM2, \
.name = "pwm2", \
.channel = 2 \
}
#endif /* PWM2_CONFIG */
#endif /* BSP_USING_PWM2 */
打开外设 example pwm, 修改文件pwm_led_example.c
#define LED_PIN_NUM 32 /* LED PIN脚编号PA1,查看驱动文件drv_gpio.c确定 */
#define PWM_DEV_NAME "pwm2" /* PWM设备名称 */
#define PWM_DEV_CHANNEL 2 /* PWM通道 */
在 MSH 中运行pwm_led_sample 结果 插在PA1上的蜂鸣器发出强-弱循环的声音:
\ | /
- RT - Thread Operating System
/ | \ 4.0.3 build Oct 14 2021
2006 - 2020 Copyright by rt-thread team
msh >pwm_led_sample
下面删除 pwm_led_sample 例程。将beep的功能扩展到 PA1的无源蜂鸣器上。
beep 软件包中 Buzzer Type 修改成 Passive ,后面选项选择 PWM2 CH2 , 存盘编译。
在MSH中运行:beep 2 1000 50 5000 周期1000ms 占空比50% 频率5K 鸣叫2下。
3.2 移植 beep_player
参考: 杜毅豪 / RTT-BeepPlayer-pkg
Guozhanxin/RTT-BeepPlayer
删除软件包 beep , 复制beep_player 到工程。添加头文件目录。
修改beep.h
#define BEEP_PWM_DEVICE "pwm2"
#define BEEP_PWM_CH 2
下载后,自动顺序播放4首歌曲:
MSH 中打印当前的歌曲:
*********** Beep Player ***********
01. 两只老虎
02. 挥着翅膀的女孩
03. 同一首歌
04. 两只蝴蝶
<--- 正在播放:两只蝴蝶--->
播放进度:00% 音量大小:03%·
4. 测试定时器
硬件:TIM3 CH1
RTT设置中添加设备驱动程序,配置使能HWTIMER
在外设示例中打开 peripheral - hwtimer device
board.h中添加
#define BSP_USING_TIM
#ifdef BSP_USING_TIM
#define BSP_USING_TIM3
stm32f4xx_hal_conf.h 中, 添加:#define HAL_TIM_MODULE_ENABLED
修改示例代码中 hwtimer_sample.c 文件中 #define HWTIMER_DEV_NAME "timer3" 定时器名称.
在msh中运行,查看已经添加了 timer3设备
msh >list_device
device type ref count
-------- -------------------- ----------
pwm2 Miscellaneous Device 0
timer3 Timer Device 0
uart1 Character Device 2
pin Miscellaneous Device 0
运行示例代码 hwtimer_sample , 每隔5S打印一次:
msh >hwtimer_sample
Read: Sec = 3, Usec = 499962
msh >tick is :21846 !
tick is :26846 !
tick is :31846 !
tick is :36846 !
tick is :41846 !
tick is :46846 !
tick is :51846 !
tick is :56846 !
5.测试AD输入
硬件:PA0
stm32f4xx_hal_conf.h 中, 添加:#define HAL_ADC_MODULE_ENABLED
RTT设置中添加设备驱动程序,配置使能ADC设备驱动程序
在外设示例中打开 peripheral - adc device
board.h中添加
#define BSP_USING_ADC1
修改示例代码中 adc_vol_sample.c 文件中
#define ADC_DEV_NAME "adc1" /* ADC 设备名称 */
#define ADC_DEV_CHANNEL 0 /* ADC 通道 */
在msh中运行,查看已经添加了 ADC设备 ,然后运行示例代码 , 打印当前的ADC值:
msh >list_device
device type ref count
-------- -------------------- ----------
pwm2 Miscellaneous Device 0
timer3 Timer Device 0
adc1 Miscellaneous Device 0
uart1 Character Device 2
pin Miscellaneous Device 0
msh >adc_vol_sample
the value is :3245
the voltage is :2.61
6.测试WDT
stm32f4xx_hal_conf.h 中, 添加:#define HAL_IWDG_MODULE_ENABLED
RTT设置中添加设备驱动程序,配置使用WDT设备驱动程序
在外设示例中打开 peripheral - watchdog device
msh >list_device
device type ref count
-------- -------------------- ----------
pwm2 Miscellaneous Device 0
rtc RTC 0
wdt Miscellaneous Device 0
timer3 Timer Device 0
adc1 Miscellaneous Device 0
uart1 Character Device 2
pin Miscellaneous Device 0
msh >iwdg_sample wdt
[E/drv.wdt] wdg set timeout parameter too large, please less than 32s
set wdt timeout failed!
显示超时时间过长,修改例程代码中溢出时间为10
static int iwdg_sample(int argc, char *argv[])
{
rt_err_t ret = RT_EOK;
rt_uint32_t timeout = 10; /* 溢出时间 */
char device_name[RT_NAME_MAX];
...
}
出现运行错误:
msh >iwdg_sample wdt
msh >feed thread:tidle0 stack overflow
修改内核配置中空闲线程栈大小 为 1024 ,再编译下载后运行正常
msh >iwdg_sample wdt
feed the dog!
feed the dog!
feed the dog!
...
7.测试RTC
stm32f4xx_hal_conf.h 中, 添加:#define HAL_RTC_MODULE_ENABLED
7.1 软件模拟RTC设备
RTT设置中添加设备驱动程序,配置使能使用RTC设备驱动程序 使用软件模拟RTC设备
在外设示例中打开 peripheral - rtc device
在msh中运行命令,可配置当前 时钟。
msh >rtc_sample
Mon Dec 3 11:15:53 2018
msh >date
Mon Dec 3 11:15:54 2018
msh >
board.h中RTC部分开启了硬件RTC,但是实际对于后备寄存器的read和write用的竟然仍然不是hal库的,还是用的 drv_rtc.c的,修改drv_rtc.c 的代码。
//#ifndef HAL_RTCEx_BKUPRead
//#define HAL_RTCEx_BKUPRead(x1, x2) (~BKUP_REG_DATA)
//#endif
//#ifndef HAL_RTCEx_BKUPWrite
//#define HAL_RTCEx_BKUPWrite(x1, x2, x3)
//#endif
//#ifndef RTC_BKP_DR1
//#define RTC_BKP_DR1 RT_NULL
//#endif
7.2 使用硬件RTC自行编写驱动
参考复位不保存年月日
关于使用RT-THREAD过程中遇到的首次上电后RTC工作不正常的问题小结
RT-Thread学习笔记(二)–配置RTC时间日期更新事件实验
最终移植了正点的代码成功。但是没有用RTT的框架,注释掉cubemx中的 void HAL_RTC_MspInit(RTC_HandleTypeDef* hrtc) 函数,使用以下代码:
/*-------------------------------RTC---------------------------------*/
#include <rtthread.h>
#include <rtdevice.h>
#include <rtdbg.h>
#include <board.h>
//RTC时间设置
//hour,min,sec:小时,分钟,秒钟
//ampm:@RTC_AM_PM_Definitions:RTC_HOURFORMAT12_AM/RTC_HOURFORMAT12_PM
//返回值:SUCEE(1),成功
// ERROR(0),进入初始化模式失败
HAL_StatusTypeDef RTC_Set_Time(uint8_t hour,uint8_t min,uint8_t sec,uint8_t ampm)
{
RTC_TimeTypeDef RTC_TimeStructure;
RTC_TimeStructure.Hours=hour;
RTC_TimeStructure.Minutes=min;
RTC_TimeStructure.Seconds=sec;
RTC_TimeStructure.TimeFormat=ampm;
RTC_TimeStructure.DayLightSaving=RTC_DAYLIGHTSAVING_NONE;
RTC_TimeStructure.StoreOperation=RTC_STOREOPERATION_RESET;
return HAL_RTC_SetTime(&RTC_Handler,&RTC_TimeStructure,RTC_FORMAT_BIN);
}
//RTC日期设置
//year,month,date:年(0~99),月(1~12),日(0~31)
//week:星期(1~7,0,非法!)
//返回值:SUCEE(1),成功
// ERROR(0),进入初始化模式失败
HAL_StatusTypeDef RTC_Set_Date(uint8_t year,uint8_t month,uint8_t date,uint8_t week)
{
RTC_DateTypeDef RTC_DateStructure;
RTC_DateStructure.Date=date;
RTC_DateStructure.Month=month;
RTC_DateStructure.WeekDay=week;
RTC_DateStructure.Year=year;
return HAL_RTC_SetDate(&RTC_Handler,&RTC_DateStructure,RTC_FORMAT_BIN);
}
//RTC初始化
//返回值:0,初始化成功;
// 2,进入初始化模式失败;
uint8_t RTC_Init(void)
{
RTC_Handler.Instance=RTC;
RTC_Handler.Init.HourFormat=RTC_HOURFORMAT_24;//RTC设置为24小时格式
RTC_Handler.Init.AsynchPrediv=0X7F; //RTC异步分频系数(1~0X7F)
RTC_Handler.Init.SynchPrediv=0XFF; //RTC同步分频系数(0~7FFF)
RTC_Handler.Init.OutPut=RTC_OUTPUT_DISABLE;
RTC_Handler.Init.OutPutPolarity=RTC_OUTPUT_POLARITY_HIGH;
RTC_Handler.Init.OutPutType=RTC_OUTPUT_TYPE_OPENDRAIN;
if(HAL_RTC_Init(&RTC_Handler)!=HAL_OK) return 2;
if(HAL_RTCEx_BKUPRead(&RTC_Handler,RTC_BKP_DR0)!=0X5050)//是否第一次配置
{
RTC_Set_Time(23,59,56,RTC_HOURFORMAT12_PM); //设置时间 ,根据实际时间修改
RTC_Set_Date(15,12,27,7); //设置日期
HAL_RTCEx_BKUPWrite(&RTC_Handler,RTC_BKP_DR0,0X5050);//标记已经初始化过了
}
return 0;
}
//RTC底层驱动,时钟配置
//此函数会被HAL_RTC_Init()调用
//hrtc:RTC句柄
void HAL_RTC_MspInit(RTC_HandleTypeDef* hrtc)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
__HAL_RCC_PWR_CLK_ENABLE();//使能电源时钟PWR
HAL_PWR_EnableBkUpAccess();//取消备份区域写保护
RCC_OscInitStruct.OscillatorType=RCC_OSCILLATORTYPE_LSE;//LSE配置
RCC_OscInitStruct.PLL.PLLState=RCC_PLL_NONE;
RCC_OscInitStruct.LSEState=RCC_LSE_ON; //RTC使用LSE
HAL_RCC_OscConfig(&RCC_OscInitStruct);
PeriphClkInitStruct.PeriphClockSelection=RCC_PERIPHCLK_RTC;//外设为RTC
PeriphClkInitStruct.RTCClockSelection=RCC_RTCCLKSOURCE_LSE;//RTC时钟源为LSE
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
__HAL_RCC_RTC_ENABLE();//RTC时钟使能
}
//设置闹钟时间(按星期闹铃,24小时制)
//week:星期几(1~7) @ref RTC_WeekDay_Definitions
//hour,min,sec:小时,分钟,秒钟
void RTC_Set_AlarmA(uint8_t week,uint8_t hour,uint8_t min,uint8_t sec)
{
RTC_AlarmTypeDef RTC_AlarmSturuct;
RTC_AlarmSturuct.AlarmTime.Hours=hour; //小时
RTC_AlarmSturuct.AlarmTime.Minutes=min; //分钟
RTC_AlarmSturuct.AlarmTime.Seconds=sec; //秒
RTC_AlarmSturuct.AlarmTime.SubSeconds=0;
RTC_AlarmSturuct.AlarmTime.TimeFormat=RTC_HOURFORMAT12_AM;
RTC_AlarmSturuct.AlarmMask=RTC_ALARMMASK_NONE;//精确匹配星期,时分秒
RTC_AlarmSturuct.AlarmSubSecondMask=RTC_ALARMSUBSECONDMASK_NONE;
RTC_AlarmSturuct.AlarmDateWeekDaySel=RTC_ALARMDATEWEEKDAYSEL_WEEKDAY;//按星期
RTC_AlarmSturuct.AlarmDateWeekDay=week; //星期
RTC_AlarmSturuct.Alarm=RTC_ALARM_A; //闹钟A
HAL_RTC_SetAlarm_IT(&RTC_Handler,&RTC_AlarmSturuct,RTC_FORMAT_BIN);
HAL_NVIC_SetPriority(RTC_Alarm_IRQn,0x01,0x02); //抢占优先级1,子优先级2
HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
}
//周期性唤醒定时器设置
/*wksel: @ref RTCEx_Wakeup_Timer_Definitions
#define RTC_WAKEUPCLOCK_RTCCLK_DIV16 ((uint32_t)0x00000000)
#define RTC_WAKEUPCLOCK_RTCCLK_DIV8 ((uint32_t)0x00000001)
#define RTC_WAKEUPCLOCK_RTCCLK_DIV4 ((uint32_t)0x00000002)
#define RTC_WAKEUPCLOCK_RTCCLK_DIV2 ((uint32_t)0x00000003)
#define RTC_WAKEUPCLOCK_CK_SPRE_16BITS ((uint32_t)0x00000004)
#define RTC_WAKEUPCLOCK_CK_SPRE_17BITS ((uint32_t)0x00000006)
*/
//cnt:自动重装载值.减到0,产生中断.
void RTC_Set_WakeUp(uint32_t wksel,uint16_t cnt)
{
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&RTC_Handler, RTC_FLAG_WUTF);//清除RTC WAKE UP的标志
HAL_RTCEx_SetWakeUpTimer_IT(&RTC_Handler,cnt,wksel); //设置重装载值和时钟
HAL_NVIC_SetPriority(RTC_WKUP_IRQn,0x02,0x02); //抢占优先级1,子优先级2
HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);
}
//RTC闹钟中断服务函数
void RTC_Alarm_IRQHandler(void)
{
HAL_RTC_AlarmIRQHandler(&RTC_Handler);
}
//RTC闹钟A中断处理回调函数
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
rt_kprintf("ALARM A!\r\n");
}
//RTC WAKE UP中断服务函数
void RTC_WKUP_IRQHandler(void)
{
HAL_RTCEx_WakeUpTimerIRQHandler(&RTC_Handler);
}
//RTC WAKE UP中断处理
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
//LED1=!LED1;
}
void MX_RTC_Init(void)
{
RTC_Init();
}
INIT_DEVICE_EXPORT(MX_RTC_Init);
void test_rtc(void)
{
RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;
HAL_RTC_GetTime(&RTC_Handler,&RTC_TimeStruct,RTC_FORMAT_BIN);
HAL_RTC_GetDate(&RTC_Handler,&RTC_DateStruct,RTC_FORMAT_BIN);
rt_kprintf("\r\n%d-%d-%d ", RTC_DateStruct.Year, RTC_DateStruct.Month, RTC_DateStruct.Date);
rt_kprintf("%d:%d:%d \r\n", RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes, RTC_TimeStruct.Seconds);
}
MSH_CMD_EXPORT(test_rtc, test_rtc);
在MSH中运行 test_rtc ,可获取当前时间。
7.3 RTT的RTC框架使用硬件RTC
用RTT的RTC框架, 分析 dev_rtc.c,注释了上面的 几行,再次运行成功:
//#define HAL_RTCEx_BKUPRead(x1, x2) (~BKUP_REG_DATA)
//#endif
//#ifndef HAL_RTCEx_BKUPWrite
//#define HAL_RTCEx_BKUPWrite(x1, x2, x3)
//#endif
//#ifndef RTC_BKP_DR1
//#define RTC_BKP_DR1 RT_NULL
//#endif
修改 rtc_sample.c ,添加配置时间参数:
static int rtc_sample(int argc, char *argv[])
{
rt_err_t ret = RT_EOK;
time_t now;
if(argc < 7)
{
rt_kprintf("rtc_sample --use rtc_sample 2021 10 16 9 56 0(年月日时分秒)\r\n");
return -1;
}
/* 设置日期 */
ret = set_date(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]));
if (ret != RT_EOK)
{
rt_kprintf("set RTC date failed\n");
return ret;
}
/* 设置时间 */
ret = set_time(atoi(argv[4]), atoi(argv[5]), atoi(argv[6]));
if (ret != RT_EOK)
{
rt_kprintf("set RTC time failed\n");
return ret;
}
/* 延时3秒 */
rt_thread_mdelay(3000);
/* 获取时间 */
now = time(RT_NULL);
rt_kprintf("%s\n", ctime(&now));
return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(rtc_sample, rtc_sample 2021 10 16 9 53 0);
8.测试SPI
8.1 W25Q16模块
硬件:SPI2
- PB15: MOSI
- PB14: MISO
- PB13:SCK
连接 w25Q16 使用 CS: PB12
stm32f4xx_hal_conf.h 中, 添加:#define HAL_SPI_MODULE_ENABLED
使能组件设备驱动 :SPI 总线设备驱动 。使用以下选项: 使用串行Flash通用驱动程序 自动探针 Flash芯片信息表 显示更多SFUD调试信息 。方便调试。添加SPI 设备的示例。
board.h 中定义:#define BSP_USING_SPI2
SPI的总线设备已经注册完毕,接下来需要进行SPI从设备驱动编写,使用板载的SPI Flash W25Q16进行测试,新建函数自动运行,在 spi2 上挂载设备spi20 :
static int rt_hw_spi_flash_init(void)
{
__HAL_RCC_GPIOB_CLK_ENABLE();
rt_hw_spi_device_attach("spi2", "spi20", GPIOB, GPIO_PIN_12);// spi10 表示挂载在 spi3 总线上的 0 号设备,PC0是片选,这一步就可以将从设备挂在到总线中。
if (RT_NULL == rt_sfud_flash_probe("W25Q12", "spi20")) //注册块设备,这一步可以将外部flash抽象为系统的块设备
{
return -RT_ERROR;
};
return RT_EOK;
}
/* 导出到自动初始化 */
INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);
在MSH中运行命令,显示当前设备添加了 spi2 和spi20 , 运行测试代码,显示当前的 w25q ID 号:
msh >list_device
device type ref count
-------- -------------------- ----------
spi20 SPI Device 0
rtc RTC 0
pwm2 Miscellaneous Device 0
wdt Miscellaneous Device 0
spi2 SPI Bus 0
timer3 Timer Device 0
adc1 Miscellaneous Device 0
uart1 Character Device 2
pin Miscellaneous Device 0
msh >spi_w25q_sample spi20
use rt_spi_send_then_recv() read w25q ID is:14ef
use rt_spi_transfer_message() read w25q ID is:14ef
读 JEDEC(9F)回复: ef4015
读 Manu和Device(90)回复: 14ef
8.2 调试SFUD
文件 drv_spi.c 中 ,语句
/* start once data exchange in DMA mode */
if (message->send_buf && message->recv_buf)
{
if ((spi_drv->spi_dma_flag & SPI_USING_TX_DMA_FLAG) && (spi_drv->spi_dma_flag & SPI_USING_RX_DMA_FLAG))
{
state = HAL_SPI_TransmitReceive_DMA(spi_handle, (uint8_t *)send_buf, (uint8_t *)recv_buf, send_length);
}
else
{
state = HAL_SPI_TransmitReceive(spi_handle, (uint8_t *)send_buf, (uint8_t *)recv_buf, send_length, 1000);
}
}
前要暂停,在调试仿真时能读出ID, 在正常运行时读不出.
降低SPI速度,Default spi maximum speed(HZ) 为50000。
参考 RT-Thread Studio 外部flash挂载虚拟文件系统笔记
添加代码:
static int rt_hw_spi_flash_init(void)
{
__HAL_RCC_GPIOB_CLK_ENABLE();
rt_hw_spi_device_attach("spi2", "spi20", GPIOB, GPIO_PIN_12);// spi20 表示挂载在 spi2 总线上的 0 号设备,PB12是片选,这一步就可以将从设备挂在到总线中。
if (RT_NULL == rt_sfud_flash_probe("W25Q16", "spi20")) //注册块设备,这一步可以将外部flash抽象为系统的块设备
{
return -RT_ERROR;
};
return 0;
}
/* 导出到应用初始化 */
INIT_DEVICE_EXPORT(rt_hw_spi_flash_init);
static int flash_init(void)
{
if (RT_NULL == rt_sfud_flash_probe("W25Q16", "spi20")) //注册块设备,这一步可以将外部flash抽象为系统的块设备
{
return -RT_ERROR;
};
return 0;
}
MSH_CMD_EXPORT(flash_init, flash_init);
static int mnt_init()
{
mkfs("elm", "W25Q16");
if (dfs_mount("W25Q16", "/", "elm", 0, 0) == 0)
{
//rt_kprintf("dfs mount ok\n");
}
else
{
rt_kprintf("dfs mount failed\n");
}
}
MSH_CMD_EXPORT(mnt_init, mnt_init);
第二遍在 msh中运行flash_init 才成功。
msh />flash_init
[D/SFUD] (../rt-thread/components/drivers/spi/sfud/src/sfud.c:862) The flash device manufacturer ID is 0xEF, memory type ID is 0x40, capacity ID is 0x15.
[D/SFUD] (../rt-thread/components/drivers/spi/sfud/src/sfud_sfdp.c:122) Error: Check SFDP signature error. It's must be 50444653h('S' 'F' 'D' 'P').
[I/SFUD] Warning: Read SFDP parameter header information failed. The W25Q16 is not support JEDEC SFDP.
[I/SFUD] Find a Winbond W25Q16BV flash chip. Size is 2097152 bytes.
[D/SFUD] (../rt-thread/components/drivers/spi/sfud/src/sfud.c:840) Flash device reset success.
[I/SFUD] W25Q16 flash device is initialize success.
[I/SFUD] Probe SPI flash W25Q16 by SPI device spi20 success.
msh />list_device
device type ref count
-------- -------------------- ----------
W25Q16 Block Device 0
spi20 SPI Device 0
rtc RTC 0
pwm2 Miscellaneous Device 0
wdt Miscellaneous Device 0
spi2 SPI Bus 0
spi1 SPI Bus 0
i2c1 I2C Bus 0
timer3 Timer Device 0
adc1 Miscellaneous Device 0
uart1 Character Device 2
pin Miscellaneous Device 0
9.测试I2C
I2C2硬件:PB6 SCL PB7 SDA
stm32f4xx_hal_conf.h 中, 添加:#define HAL_I2C_MODULE_ENABLED
board.h 中添加:
#define BSP_USING_I2C1
#ifdef BSP_USING_I2C1
#define BSP_I2C1_SCL_PIN GET_PIN(B, 6)
#define BSP_I2C1_SDA_PIN GET_PIN(B, 7)
#endif
stm32f4xx_hal_conf.h 中, 添加:#define HAL_I2C_MODULE_ENABLED
内核组件中添加: 使用I2C设备驱动程序 , 勾选 模拟I2C ,添加软件包 at24cxx :
msh />at24cxx
Usage:
at24cxx probe <dev_name> - probe eeprom by given name
at24cxx check - check eeprom at24cxx
at24cxx read - read eeprom at24cxx data
at24cxx write - write eeprom at24cxx data
msh />at24cxx probe i2c1
msh />at24cxx check
[D/I2C] msgs[0] W, addr=0x50, len=1
[D/I2C] msgs[0] R, addr=0x50, len=1
msh />at24cxx write
[D/I2C] msgs[0] W, addr=0x50, len=2
...
[D/I2C] msgs[0] W, addr=0x50, len=2
write ok
msh />at24cxx read
[D/I2C] msgs[0] W, addr=0x50, len=1
...
[D/I2C] msgs[0] R, addr=0x50, len=1
read at24cxx : WELCOM TO RTT
11.结论
F411 作为主频率较低的MCU,尽量不要使用 文件系统、网络系统,否则总会出现意外的问题。如果想要进阶操作系统的相关知识,可选择 ART-Pi。
#define BSP_I2C1_SDA_PIN GET_PIN(B, 7)
#endif
stm32f4xx_hal_conf.h 中, 添加:#define HAL_I2C_MODULE_ENABLED
内核组件中添加: 使用I2C设备驱动程序 , 勾选 模拟I2C ,添加软件包 at24cxx :
msh />at24cxx
Usage:
at24cxx probe <dev_name> - probe eeprom by given name
at24cxx check - check eeprom at24cxx
at24cxx read - read eeprom at24cxx data
at24cxx write - write eeprom at24cxx data
msh />at24cxx probe i2c1
msh />at24cxx check
[D/I2C] msgs[0] W, addr=0x50, len=1
[D/I2C] msgs[0] R, addr=0x50, len=1
msh />at24cxx write
[D/I2C] msgs[0] W, addr=0x50, len=2
...
[D/I2C] msgs[0] W, addr=0x50, len=2
write ok
msh />at24cxx read
[D/I2C] msgs[0] W, addr=0x50, len=1
...
[D/I2C] msgs[0] R, addr=0x50, len=1
read at24cxx : WELCOM TO RTT
11.结论
F411 作为主频率较低的MCU,尽量不要使用 文件系统、网络系统,否则总会出现意外的问题。如果想要进阶操作系统的相关知识,可选择 ART-Pi。
|