STM32F4 NANO + RT-Thread Studio 测试工程搭建流程

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

功能:

  • 实现8个灯 3个键 1个蜂鸣器鸣叫

方法:

  • 使用 RTT方便的软件包

    双击CubeMX Settings, 注意 cubemx 版本 6.2.1配置好 LED  key beep的管脚,USART1 RCC时钟为100M,保存后生成代码,后关闭, 提示,点击确定。

    在这里插入图片描述

2.1 使用 agile_led 控制LED灯

  1. 代码简洁易懂,充分使用RT-Thread提供的API

  2. 详细注释

  3. 线程安全

  4. 断言保护

  5. API操作简单

    配置选项中 enable example

2.2 使用 agile_button 控制KEY

agile_button是基于RT-Thread实现的button软件包,提供button操作的API。

  1. 代码简洁易懂,充分使用RT-Thread提供的API
  2. 详细注释
  3. 线程安全
  4. 断言保护
  5. 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中运行命令,显示当前设备添加了 spi2spi20, 运行测试代码,显示当前的 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。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
RT-Thread诞生于2006年,是一款以开源、中立、社区化发展起来的物联网操作系统。 RT-Thread主要采用 C 语言编写,浅显易懂,且具有方便移植的特性(可快速移植到多种主流 MCU 及模组芯片上)。RT-Thread把面向对象的设计方法应用到实时系统设计中,使得代码风格优雅、架构清晰、系统模块化并且可裁剪性非常好。 RT-Thread有完整版和Nano版,对于资源受限的微控制器(MCU)系统,可通过简单易用的工具,裁剪出仅需要 3KB Flash、1.2KB RAM 内存资源的 NANO 内核版本;而相对资源丰富的物联网设备,可使用RT-Thread完整版,通过在线的软件包管理工具,配合系统配置工具实现直观快速的模块化裁剪,并且可以无缝地导入丰富的软件功能包,实现类似 Android 的图形界面及触摸滑动效果、智能语音交互效果等复杂功能。 RT-Thread架构 RT-Thread是一个集实时操作系统(RTOS)内核、中间件组件的物联网操作系统,架构如下: 内核层:RT-Thread内核,是 RT-Thread的核心部分,包括了内核系统中对象的实现,例如多线程及其调度、信号量、邮箱、消息队列、内存管理、定时器等;libcpu/BSP(芯片移植相关文件 / 板级支持包)与硬件密切相关,由外设驱动和 CPU 移植构成。 组件与服务层:组件是基于 RT-Thread内核之上的上层软件,例如虚拟文件系统、FinSH命令行界面、网络框架、设备框架等。采用模块化设计,做到组件内部高内聚,组件之间低耦合。 RT-Thread软件包:运行于 RT-Thread物联网操作系统平台上,面向不同应用领域的通用软件组件,由描述信息、源代码或库文件组成。RT-Thread提供了开放的软件包平台,这里存放了官方提供或开发者提供的软件包,该平台为开发者提供了众多可重用软件包的选择,这也是 RT-Thread生态的重要组成部分。软件包生态对于一个操作系统的选择至关重要,因为这些软件包具有很强的可重用性,模块化程度很高,极大的方便应用开发者在最短时间内,打造出自己想要的系统。RT-Thread已经支持的软件包数量已经达到 180+。 RT-Thread的特点: 资源占用极低,超低功耗设计,最小内核(Nano版本)仅需1.2KB RAM,3KB Flash。 组件丰富,繁荣发展的软件包生态 。 简单易用 ,优雅的代码风格,易于阅读、掌握。 高度可伸缩,优质的可伸缩的软件架构,松耦合,模块化,易于裁剪和扩展。 强大,支持高性能应用。 跨平台、芯片支持广泛。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南工孙冬梅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值