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

2023-05-16

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。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32F4 NANO + RT-Thread Studio 测试工程搭建流程 的相关文章

  • Java Thread Join

    join方法的作用 在A线程中调用了B线程的join 方法时 表示只有当B线程执行完毕时 A线程才能继续执行
  • Android的消息处理机制(图+源码分析)——Looper,Handler,Message

    百度二面的时候 觉得自己源码分析太差 没有深入 面试官估计觉得我很不爽 恩 来吧 自己结合这篇文章 基本上把android消息机制给弄清楚了 http www androidzz com 2011 09 android looper han
  • 主线程中捕获子线程异常

    需求 主线程独立执行 无需等待子线程执行完毕 子线程如有异常抛出可自行catch 网上介绍的方法一般是 1 在线程内部进行try catch捕获异常 2 通过线程池的submit方法 获取Future对象 然后try catch Futur
  • yield和join方法的使用。

    join方法用线程对象调用 如果在一个线程A中调用另一个线程B的join方法 线程A将会等待线程B执行完毕后再执行 yield可以直接用Thread类调用 yield让出CPU执行权给同等级的线程 如果没有相同级别的线程在等待CPU的执行权
  • 转帖:Bash实现“多线程”的例子

    以下文章转自 http hi baidu com wwy1640 blog item a74d8c50a272b86384352443 html Bash实现 多线程 的例子 2007 04 25 22 59 bin bash 2006 7
  • AFX_MANAGE_STATE(AfxGetStaticModuleState())讲解

    以前写MFC的DLL的时候 总会在自动生成的代码框架里看到提示 需要在每一个输出的函数开始添加上AFX MANAGE STATE AfxGetStaticModuleState 一直不明白这样做的含义 也一直没有这样做 而且代码也工作得好好
  • CyclicBarrier 使用详解

    1 CyclicBarrier 是什么 从字面上的意思可以知道 这个类的中文意思是 循环栅栏 大概的意思就是一个可循环利用的屏障 它的作用就是会让所有线程都等待完成后才会继续下一步行动 举个例子 就像生活中我们会约朋友们到某个餐厅一起吃饭
  • 多线程问题分析thread

    多线程 进程概述 A 进程 进程指正在运行的程序 确切的来说 当一个程序进入内存运行 即变成一个进程 进程是处于运行过程中的程序 并且具有一定独立功能 简而言之 当前正在运动的程序 一个应用程序在内存中的执行区域 B 线程 线程是进程中的一
  • 关于CoInitialize()

    在msdn中对于CoInitialize的解释如下 Initializes the COM library on the current apartment and identifies the concurrency model as s
  • JSVC简介之快速入门

    1 JSVC简介 Apache基金会会common 类似于guava 项目下的项目 2 为什么要使用JSVC java应用增加一种启动方式 Java的缺点 只能用main方法启动 应用能使用1024以下端口 为啥tomcat可以指定端口 系
  • qt中常用lambda表达式

    qt中lambda表达式 什么是lambda 个人理解 没有函数名的函数 qt中使用基础 备注 都是在qt5中做的使用 我的qt版本是qt5 11 3 pro文件中 config c 11 常见的lambda表达式使用 延时执行操作 举例
  • 分析Java线程池执行原理

    Java并发编程源码分析系列 分析Java线程池的创建 上一篇已经对线程池的创建进行了分析 了解线程池既有预设的模板 也提供多种参数支撑灵活的定制 本文将会围绕线程池的生命周期 分析线程池执行任务的过程 线程池状态 首先认识两个贯穿线程池代
  • SuspendThread 造成程序死锁的一个例子

    msdn对SuspendThread 的说明 This function is primarily designed for use by debuggers It is not intended to be used for thread
  • c++11std::thread扩展

    最近 整理一下学习c 的文章 看到一篇文章 其中提到了thread local和std future 觉得这两东西很有趣 于是网上搜了一些资料 觉得很有帮助 希望可以对大家学习c 线程有所帮助 http www cnblogs com ha
  • pthread_attr_init线程属性

    1 线程属性 线程具有属性 用pthread attr t表示 在对该结构进行处理之前必须进行初始化 在使用后需要对其去除初始化 我们用pthread attr init函数对其初始化 用pthread attr destroy对其去除初始
  • python_os.walk(dir)

    for root dirs files in os walk dir os walk返回一个三元组 path 对当前路径以及其下所有的子目录进行递归 dirs 当前路径下的子目录 files 当前路径下的文件 gt gt gt for r
  • 如何终止一个无限循环线程和 程序退出时销毁线程

    http zhidao baidu com question 299079849 html android 启动了一个子线程 这个子线程是一个死循环 不成的打印 Hello 现在要实现点击一个Button 让这个子线程终止 用什么方法啊 s
  • QT实现多线程,以及子线程调用主线程方法与变量

    实现思路 第一步需要将子线程声明为主线程的友元类 第二步是将主线程类对象的地址通过信号槽传递给子线程中创建的对象 使得子线程能访问主线程的数据的 1 子线程 displayresult h 头文件 伪代码 include tabwindow
  • 当数据大小较小时,内存到内存 DMA 传输是否需要权衡?

    我正在学习 STM32 F4 微控制器 我正在尝试找出使用 DMA 的限制 根据我的理解和研究 我知道如果数据量较小 即设备使用DMA生成或消耗少量数据 则开销会增加 因为DMA传输需要DMA控制器执行操作 从而不必要地增加系统成本 我做了
  • STM32:从自定义引导加载程序跳转到应用程序时发生硬故障

    我正在开发带有自定义引导加载程序和应用程序的 STM32F401 MCU 编译器是GCC 5 2 1 没有运行优化 在以下跳转序列后的第一次中断后 我遇到了硬故障 引导加载程序 gt 应用程序 gt 引导加载程序 gt 应用程序 从引导加载

随机推荐

  • PX4-做飞控二次开发需要知道的事情-Cxm

    前言 废话 来了 之前一直在做APM飞控的开发 发现除了企业用APM 在比赛方面还是PX4居多一点 加上最近也有这个需求所以又重拾了PX4 这两个飞控最大的区别应该就是系统了吧 PX4学习起来还是比较简单的 比较系统和模块化 在重拾PX4之
  • 指针函数和函数指针的区别

    1 指针函数 xff1a 带指针的函数 xff0c 其本质是一个函数 xff0c 函数返回是某一类型的指针 例如 xff1a int f x xff0c y 其结构为 类型标识符 函数名 参数 首先你要从心里承认这是一个函数 xff0c 只
  • 什么是中断?

    中断嘛 xff0c 对于很多新手来讲 xff0c 有点难以理解 xff0c 举个容易的现实的例子吧 如果还不懂 xff0c 骚年 xff0c 考虑换行吧 xff0c 或许这不是你的方向呢 xff0c 诗和远方在前面岔路左拐 比如小明和老丈人
  • 什么是看门狗?

    一样采用简单明了的例子来解释 条件 xff1a 你家有条狗 事件 xff1a 让他看门 xff0c 报警 结果 xff1a 1到点不给吃饭 xff0c 会叫 xff0c 2到点喂他吃东西 xff0c 等待下次开饭 影响 xff1a 叫了 x
  • BUG的烦恼

    在我们这个行业的学习和工作中 xff0c bug是个逃不掉的话题 最近两天 xff0c 在调试一个程序 xff0c 程序本来是完整的 xff0c 只是我需要把它移植到另一个平台上 框架是没有动的 xff0c 连平台的架构都很像 xff0c
  • 什么是Handler

    1 什么是Handler xff1f Handler就是将消息放入队列的机制 我们在哪个线程中创新handler xff0c handler就将消息放入所在的线程 xff0c 除非在创建handler对象时是指定具体的线程 通常handle
  • 905协议第四部分简单说明

    905协议以5b开头5d结尾 转成ascii就是 这两个符号 905是用中括号括起来的消息 消息构成 61 43 消息头 43 消息体 43 crc 43 业务逻辑是消息头与消息体两部分组成 消息头 61 数据长度 43 消息序列号 43
  • git命令创建分支|合并分支|删除分支

    一 创建test分支提交步骤 1 列出所有分支 xff1a git branch a 2 创建test分支 xff1a git branch test 3 切换到test分支 xff1a git checkout test 4 添加add修
  • JS版SM2国密算法的签名验证

    前段时间因工作需要 xff0c 了解到在Github上已经有人实现了用JavaScript来写签名和验签 xff0c 支持RSA ECC DSA等算法 xff0c 还能解析X 509证书 xff0c 一时觉得JavaScript是无比强大
  • 配置VNC连接阿里云服务器

    1 安装vncserver2 安装Linux gnome界面3 修改 vnc xstartup4 使用vnc工具连接 使用VNC Viewer使用Remmina Remote Desktop Client 1 安装vncserver 阿里云
  • SCI论文状态

    自己留好投稿时的文件号 xff0c 然后登录网站查询 一般有以下几种情况 xff1a 1 Submitted to Journal 刚提交的状态 2 Manuscript received by Editorial Office 就是你的文
  • STM32控制直流电机笔记(一)——电源转换和电机驱动电路设计及注意事项

    STM32控制直流电机笔记 xff08 一 xff09 电源转换和电机驱动电路设计及注意事项 电压转换电路15V 转 12V 12V 转 5V 所用芯片LM2575 05 LM2575 12 12v直流电机驱动电路 所以芯片TB6612 注
  • CMake Error: The following variables are used in this project, but they are set to NOTFOUND解决办法

    在配置px4 Firmware时 xff0c 编译make时报错 xff1a CMake Error The following variables are used in this project but they are set to
  • PX4 avoidance ROS仿真之——使用自定义的飞机模型

    运行自己的飞机模型主要需解决的问题 飞机模型的stereo相机话题 当你的飞机模型中包含了双目相机时 xff0c 需要运行一个ROS的node xff0c 将下面内容添加到posix sitl launch文件中 xff1a lt span
  • RealSense T265相机及IMU标定,运行VINS

    转自 https www jianshu com p 194d6c9ef9a4 不确定该文章有没有对IMU和相机的时间做同步 xff01 1 使用imu utils工具包标定IMU 这里有个坑 xff0c imu utils依赖code u
  • 编译px4 Firmware 执行make报错的问题解决办法

    ccache error Failed to create temporary file for home xxx ccache tmp tmp cpp stderr Permission denied 一般这个报错下面还会接另一个报错 x
  • 在Ubuntu中安装Docker,添加Docker官方GPG key失败,解决方案

    1 添加Docker官方GPG key xff1a curl fsSL https download docker com linux ubuntu gpg sudo apt key add 2 问题来了 xff0c 有的人会遇到如下的Bu
  • git中push或者clone时报错the remote end hung up unexpectedly

    使用git提交或者克隆时出现the remote end hung up unexpectedly的异常 xff0c 原因应该是网络原因引起的而且文件可能比较大的情况下 解决办法是 xff1a 配置git的最低速度和最低速度时间 xff0c
  • raspberrypi连接神经计算棒人脸识别

    Raspberrypi连接神经计算棒人脸识别 树莓派3B上部署英特尔神经网络计算棒Intel NCS2进行最普通的人脸识别 参考 英特尔官方文档 博文树莓派上部署英特尔神经网络计算棒Intel NCS2 硬件 xff1a 树莓派3B树莓派3
  • STM32F4 NANO + RT-Thread Studio 测试工程搭建流程

    STM32F4 NANO 43 RT Thread Studio 测试工程搭建流程 硬件 xff1a 正点原子 NANO开发板 MCU STM32F411RCT6 开发平台 xff1a RT Thread Studio 1 新建工程 新建R