Stm32通过SPI读写W25QXX

  1. Printf的重定向

因为printf是c++中的库函数,要使用printf输出到串口,需要重定向,将printf定向到HAL_UART_Transmit。

新建一个retarget.c文件。

#include "stdio.h"

#include "stm32f1xx_hal.h"

#include "usart.h"

#pragma import(__use_no_semihosting_swi)

#pragma import(__use_no_semihosting)

void _sys_exit(int x) {

    x = x;

}

struct __FILE  {

    int handle;

    /* Whatever you require here. If the only file you are using is */

    /* standard output using printf() for debugging, no file handling */

    /* is required. */

};

/* FILE is typedef’ d in stdio.h. */

FILE __stdout;

void _ttywrch(int ch){};

   

int fputc(int ch, FILE *f)

{

    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);

    return ch;

}

网上找的代码或多或少运行不起来,搞了好久才调通,以上是调通后的代码,几乎只要是调试keil的工程都需要用到。可以保存下来重复使用。

  1. delay微秒

delay是一个延时函数。Stm32的HAL库提供了一个HAL_Delay的函数,但是只能延时毫秒。延时微秒,需要根据stm32的系统时钟计算,网上一大堆,但貌似或多或少有点问题,不能拿来即用。

新建一个delay.c和delay.h的文件。

#include "delay.h"

//仿原子延时,不进入systic中断

void delay_us(uint32_t nus)

{

 uint32_t temp;

 SysTick->LOAD = 9*nus;

 SysTick->VAL=0X00;//清空计数器

 SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源

 do

 {

  temp=SysTick->CTRL;//读取当前倒计数值

 }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达

     SysTick->CTRL=0x00; //关闭计数器

    SysTick->VAL =0X00; //清空计数器

}

void delay_ms(uint16_t nms)

{

 uint32_t temp;

 SysTick->LOAD = 9000*nms;

 SysTick->VAL=0X00;//清空计数器

 SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源

 do

 {

  temp=SysTick->CTRL;//读取当前倒计数值

 }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达

    SysTick->CTRL=0x00; //关闭计数器

    SysTick->VAL =0X00; //清空计数器

}

#include "stm32f1xx_hal.h"

或者直接#include main.h,规范一点

void delay_us(uint32_t nus);

之后,在main.c中引用delay.h就可以调用delay_us函数。

  1. 遇到的问题

1.编译报错

w25qxx.c(69): error:  #20: identifier "SPI_I2S_FLAG_TXE" is undefined

解:SPI_I2S_FLAG_TXE这个寄存器没有定义。网上使用的都是这个寄存器,但是在spi的库函数里找不到这个。看了半天,找到一个SPI_FLAG_TXE,改成这个就可以了。可能是时间长了,库函数里的变量名改了。

2. .\spi.axf: Error: L6218E: Undefined symbol SPI_I2S_GetFlagStatus (referred from w25qxx.o).

解:原理如上个问题,修改为

HAL_SPI_GetState(&hspi2) == HAL_SPI_STATE_BUSY_TX

3. STM32关于我遇到的HardFault_Handler的处理_warning:hardfault handler-CSDN博客

调了一个下午,发现是内存泄漏,数组访问越界的问题,也是醉了。

4. 软件SPI和硬件SPI的区别

软件SPI:用IO模拟SPI时序,这个模拟过程全部是CPU在负责执行,为了其稳定的存取数据,你可能会插入软件延时,这个时间在读取数据量不大的情况下并不明显,但是基本上你在读取过程中,其他非中断非异常程序是无法得到执行。

硬件SPI:首先这个数据存道储的过程是不需要CPU参与得,程序中配置好SPI的访问时序,开启中断,CPU就可以在中断函数中搬移数据,省下了软件模拟IO得存取时间。

仔细研究就会发现,CPU在进行SPI中断服务程序还版是需要耽误时间得,这个过程在大数据量传输中还是很耗时,ARM中Cortex-M3内核得处理器在硬件SPI上加入了DMA,这个DMA直接从SPI的数据寄存器,软件配置好DMA之后,基本上整个传输都不要权CPU参与,软件设计得好的话,整个数据传输都不要CPU参与。

W25Qxx------------(硬件SPI)_硬件spi和软件spi区别-CSDN博客

5.W25QXX上的端口容易接反。

D0--------MISO---------PA6--------PB15

D1--------MOSI---------PA7--------PB14

6.SPI1和SPI2的区别

SPI2需要复用引脚,重映射。Cubemx里面生成代码会配置好,如果用标准库去写,需要自己配置重映射。

7.硬SPI和软SPI的区别

硬SPI可以不用配置CS/NSS管脚,软SPI就是自己重新配置CS管脚,使其达到控制片选的功能,硬SPI利用终断或DMA传输数据,还没试过。

8.SPI中参数配置

hspi1.Instance = SPI1;

  hspi1.Init.Mode = SPI_MODE_MASTER;

  hspi1.Init.Direction = SPI_DIRECTION_2LINES;

  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;

  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;

  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;

  hspi1.Init.NSS = SPI_NSS_SOFT;

  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;

  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;

  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;

  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;

  hspi1.Init.CRCPolynomial = 10;

SPI_POLARITY_LOW--------对应上文的CLK极性0.

SPI_PHASE_1EDGE---------对应上文的CLK相位0

所以SPI工作在模式1(总共4个模式,上升沿采集数据,下降沿发送数据)

SPI_NSS_SOFT----------软SPI

SPI_BAUDRATEPRESCALER_128-----------128分频,在cubemx配置里面会显示对应多少赫兹

  1. 调试成功,纪念一下

完成

STM32CubeMX学习笔记(10)——SPI接口使用(读写SPI Flash W25Q64)_stm32cubemx配置spi-CSDN博客

  1. 继续封装SPI收发数据成W25Q64收发数据

网上代码一般比较标准,按照教程来操作即可,无需太多改动。已经标准化的东西,拿来用用,理解一下原理就好,加深印象。

7、单片机与W25Q128(FLASH)的通讯(SPI)实验(STM32F407)_f407 w25q-CSDN博客

6.GPIO的8种模式理解

开漏输出(open drain)与推挽输出(push pull)学习详解及某个踩到的坑分享-CSDN博客

STM32CUBEMX配置教程(三)通用GPIO配置_stm32cubemx怎么设置gpio精准输出-CSDN博客

STM32的GPIO端口配置八种模式的理解_stm32的gpio的配置模式有哪几种-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值