IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32F4 NANO + RT-Thread Studio 测试工程搭建流程 -> 正文阅读

[嵌入式]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。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-10-18 17:33:13  更:2021-10-18 17:33:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 7:17:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码