目录
概述
本文主要是使用AT32F403A开发板,基于V2库实现spi 读取w25q128的功能。
串口工具使用的Atlink-ez自带的串口功能。
工程建立、调试工具配置在前面章节有详细介绍。
硬件
硬件方面使用的是参考官方AT32F437 SURF板子而设计的一个AT32F403A开发板,板子上的芯片是AT32F403AVGT7的型号,开发板上面还板载了一个atlink-ez的仿真器,atlink-ez除了可以在线仿真和下载之外还有一个串口的功能,硬件上是通过跳线帽接到了MCU的串口1,pa9/10上面。
如下图是开发板pcb图,以及硬件资源。(左边上角的就是atlink-ez,用usb线接到pc即可):
实物如下图:
本章是使用spi1读取w25q128的flash,相关原理图如下:
SPI
SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线,具体的SPI里就不说明,网上有很多的详细讲解的。
AT32F403A多达4个SPI接口,在从或主模式下,全双工和半双工的通信速率可达50兆位/秒。3位的预分频器可 产生8种主模式频率,可配置成每帧8位或16位。
初始化
SPI的结构体参数:
typedef struct
{
spi_transmission_mode_type transmission_mode; /*!< transmission mode selection */
spi_master_slave_mode_type master_slave_mode; /*!< master or slave mode selection */
spi_mclk_freq_div_type mclk_freq_division; /*!< master clock frequency division selection */
spi_first_bit_type first_bit_transmission;/*!< transmit lsb or msb selection */
spi_frame_bit_num_type frame_bit_num; /*!< frame bit num 8 or 16 bit selection */
spi_clock_polarity_type clock_polarity; /*!< clock polarity selection */
spi_clock_phase_type clock_phase; /*!< clock phase selection */
spi_cs_mode_type cs_mode_selection; /*!< hardware or software cs mode selection */
} spi_init_type;
transmission_mode:传输模式,全双工,半双工
master_slave_mode:主从模式
mclk_freq_division:分频系数
first_bit_transmission:大小端模式,高位在前还是在后
frame_bit_num:数据帧位数,8bit/16bit
clock_polarity:时钟空闲电平
clock_phase:时钟采样
cs_mode_selection:cs模式,硬件模式/软件模式
AT32F403A的spi时钟最高是50M,所以分频也要注意,具体的时钟是spi所挂载的总线的时钟除以分频系数,当需要高的时钟的时候,对pcb要求布线也比较高,一般调试都是把时钟降低。Cs模式,一般常用的是软件cs模式,软件cs模式下可以任意设置一个IO来作为cs,只是需要手动的来拉高和拉低cs。其他的参数一般芯片的驱动都会给出参考。
本文是通过spi1来对w25q128的读取和写入数据, w25q128是一颗16MB大小的spi falsh存储芯片,每页大小为4k字节,驱动部分从AT32F403A的BSP里面获取。
Spi使用的软件的cs模式,所以配置PA15为推挽输出模式,在驱动中需要进行通讯的时候,拉低PA15,通讯完后拉高PA15即可,因为spi是cs低有效。当设置软件cs的时候,可以任意定义一个IO来做cs,不局限于PA15。
PA15,PB3,PB4,PB5是spi1的重映射IO,所以软件上需要设置spi1的重映射。
如下图宏定义:
当需要改其他的spi时需要对应的修改上面的宏定义,IO口、时钟等,还需要dma时,还需要修改dma通道。
初始化代码
void spiflash_init(void)
{
gpio_init_type gpio_initstructure;
spi_init_type spi_init_struct;
crm_periph_clock_enable(SPI_CS_GPIO_GROUP_CLK, TRUE); //开启spi cs gpio时钟
crm_periph_clock_enable(SPI_CLK_GPIO_GROUP_CLK, TRUE); //开启spi clk gpio时钟
crm_periph_clock_enable(SPI_MISO_GPIO_GROUP_CLK, TRUE); //开启spi iso gpio时钟
crm_periph_clock_enable(SPI_MOSI_GPIO_GROUP_CLK, TRUE); //开启spi osi gpio时钟
crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE); //开启复用时钟
gpio_pin_remap_config(SWJTAG_MUX_010,TRUE); //关闭掉jtag,保留swd
gpio_pin_remap_config(SPI1_MUX_01,TRUE); //spi io复用到pa15,pb3,pb4,pb5
#if defined(SPI_TRANS_DMA)
crm_periph_clock_enable(DMA_PERIPH_CLK, TRUE); //开启dma时钟
#endif
/* software cs, pb12 as a general io to control flash cs */ //spi cs 脚配置,软件模式,配置为上拉推挽输出
gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; //推挽模式
gpio_initstructure.gpio_pull = GPIO_PULL_UP; //上拉
gpio_initstructure.gpio_mode = GPIO_MODE_OUTPUT; //输出
gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_initstructure.gpio_pins = SPI_CS_PIN; //cs pin
gpio_init(SPI_CS_GPIO_GROUP, &gpio_initstructure);
/* sck */
gpio_initstructure.gpio_pull = GPIO_PULL_UP; //上拉
gpio_initstructure.gpio_mode = GPIO_MODE_MUX; //复用推挽
gpio_initstructure.gpio_pins = SPI_CLK_PIN; //clk pin
gpio_init(SPI_CLK_GPIO_GROUP, &gpio_initstructure);
/* miso */
gpio_initstructure.gpio_pull = GPIO_PULL_UP; //上拉
gpio_initstructure.gpio_mode = GPIO_MODE_INPUT; //输入模式,配置为复用推挽也行,但是设置为输入比较规范些。
gpio_initstructure.gpio_pins = SPI_MISO_PIN; //iso pin
gpio_init(SPI_MISO_GPIO_GROUP, &gpio_initstructure);
/* mosi */
gpio_initstructure.gpio_pull = GPIO_PULL_UP; //上拉
gpio_initstructure.gpio_mode = GPIO_MODE_MUX; //复用推挽
gpio_initstructure.gpio_pins = SPI_MOSI_PIN; //osi pin
gpio_init(SPI_MOSI_GPIO_GROUP, &gpio_initstructure);
FLASH_CS_HIGH();
crm_periph_clock_enable(SPI_PERIPH_CLK, TRUE); //开启spi时钟
spi_default_para_init(&spi_init_struct);
spi_init_struct.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX; //全双工模式
spi_init_struct.master_slave_mode = SPI_MODE_MASTER; //主模式
spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_8; //时钟8分频,120M/8=15M
spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB; //大小端,高位在前
spi_init_struct.frame_bit_num = SPI_FRAME_8BIT; //数据为8bit模式
spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH; //配置 SPI 时钟空闲时为高电平
spi_init_struct.clock_phase = SPI_CLOCK_PHASE_2EDGE; //配置 SPI 在第二个时钟边沿采样
spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE; //软件cs模式
spi_init(SPIX, &spi_init_struct); //spi结构体参数设置为以上参数
spi_enable(SPIX, TRUE); //使能spi
}
测试
测试代码
通过写入一段数据后,再读出来进行对比。
测试结果
对比数据成功通过,测试ok。
最后
有问题的可以加QQ群技术交流,同时相关代码上传到QQ群中。