stm32使用硬件SPI
Driver_SPI.c
#include "Driver_SPI.h" void Driver_SPI_Init(void) { /* 1. 开启SPI1的时钟 开启GPIO时钟 PA和PC*/ RCC->APB2ENR |= (RCC_APB2ENR_SPI1EN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPAEN); /* 2. 设置引脚的工作模式 */ /* 2.1 cs: 通用推挽输出 PC13* CNF=00 MODE=11 */ GPIOC->CRH &= ~GPIO_CRH_CNF13; GPIOC->CRH |= GPIO_CRH_MODE13; /* 2.2 sck: 推挽输出 PA5*/ /* cnf=10 mode=11 */ /* 2.3 mosi: 推挽输出 PA7*/ GPIOA->CRL |= (GPIO_CRL_MODE5 | GPIO_CRL_MODE7 | GPIO_CRL_CNF7_1 | GPIO_CRL_CNF5_1); GPIOA->CRL &= ~(GPIO_CRL_CNF5_0 | GPIO_CRL_CNF7_0); /* 2.4 miso: 浮空输入 PA6 CNF=01 MODE=00*/ GPIOA->CRL &= ~(GPIO_CRL_CNF6_1 | GPIO_CRL_MODE6); GPIOA->CRL |= GPIO_CRL_CNF6_0; /* 3. SPI相关的配置 */ /* 3.1 配置SPI1为主模式 */ SPI1->CR1 |= SPI_CR1_MSTR; /* 3.2 NSS禁用, 从设备的片选使用普通的GPIO控制*/ SPI1->CR1 |= SPI_CR1_SSM;//ssm设置为1,通过软件NSS,内部NSS连接SSI SPI1->CR2 &= ~SPI_CR2_SSOE;//设置ssom = 0,禁止spi输出 SPI1->CR1 |= SPI_CR1_SSI;//SSI设置为高电平,控制主机正常工作,内部NSS始终高电平 /* 3.3 配置SPI的工作模式 模式0 时钟极性和相位*/ SPI1->CR1 &= ~(SPI_CR1_CPOL | SPI_CR1_CPHA); /* 3.4 配置波特率的分频系数 0=2分频 1=4分频 2=8分频 ....*/ SPI1->CR1 &= ~SPI_CR1_BR; SPI1->CR1 |= SPI_CR1_BR_1; /* 3.5 配置数据帧的格式: 8为或16位 */ SPI1->CR1 &= ~SPI_CR1_DFF; /* 3.6 配置LSB 或 MSB*/ SPI1->CR1 &= ~SPI_CR1_LSBFIRST; /* 3.7 使能SPI */ SPI1->CR1 |= SPI_CR1_SPE; } void Driver_SPI_Start(void) { CS_LOW; } void Driver_SPI_Stop(void) { CS_HIGH; } uint8_t Driver_SPI_SwapByte(uint8_t byte) { /* 1. 写数据到发送缓冲区 */ /* 1.1 判断发送缓冲功区为空 */ while ((SPI1->SR & SPI_SR_TXE) == 0) ; /* 1.2 把数据放入DR寄存器 */ SPI1->DR = byte; /* 2. 读数据 */ /* 2.1 先判断接收缓冲区非空 */ while ((SPI1->SR & SPI_SR_RXNE) == 0) ; /* 2.1 从接收缓冲区读取数据 */ return (uint8_t)(SPI1->DR & 0xff); }
Driver_SPI.h
#ifndef __DRIVER_SPI_H #define __DRIVER_SPI_H #include "stm32f10x.h" #include "Delay.h" #define CS_HIGH (GPIOC->ODR |= GPIO_ODR_ODR13) #define CS_LOW (GPIOC->ODR &= ~GPIO_ODR_ODR13) #define SPI_DELAY Delay_us(5) void Driver_SPI_Init(void); void Driver_SPI_Start(void); void Driver_SPI_Stop(void); uint8_t Driver_SPI_SwapByte(uint8_t byte); #endif
Inf_W25Q32.c
#include "Inf_W25Q32.h" /* 一共64块(0-63) 每块16个扇区(0-15) 每个扇区16页(0-15) 每页256个字节 */ void Inf_W25Q32_Init(void) { Driver_SPI_Init(); } void Inf_W25Q32_ReadId(uint8_t *mid, uint16_t *did) { Driver_SPI_Start(); /* 1. 发送 Jedec id指令 */ Driver_SPI_SwapByte(0x9f); /* 2. 获取厂商id (发送的数据随意)*/ *mid = Driver_SPI_SwapByte(0xff); /* 3. 获取设备id */ *did = 0; *did |= Driver_SPI_SwapByte(0xff) Driver_SPI_Start(); Driver_SPI_SwapByte(0x05); while (Driver_SPI_SwapByte(0xff) & 0x01) ; Driver_SPI_Stop(); } /** * @description: FLASH写使能 0x06 * @return {*} */ void Inf_W25q32_WiteEnable(void) { Driver_SPI_Start(); Driver_SPI_SwapByte(0x06); Driver_SPI_Stop(); } /** * @description: FLASH写失能 0x04 * @return {*} */ void Inf_W25q32_WiteDisanable(void) { Driver_SPI_Start(); Driver_SPI_SwapByte(0x04); Driver_SPI_Stop(); } /** * @description: 擦除指定块内的指定扇区 * 一共64块(0-63) 每块16个扇区(0-15) 每个扇区16页(0-15) 每页256个字节 * @param {uint8_t} block * @param {uint8_t} sector */ void Inf_W25Q32_EraseSector(uint8_t block, uint8_t sector) { Inf_W25Q32_WaiteNotBusy(); Inf_W25q32_WiteEnable(); /* 计算出要擦除的扇区的首地址 */ uint32_t sectorAddr = block * 0x010000 + sector * 0x001000; Driver_SPI_Start(); Driver_SPI_SwapByte(0x20); // 0000 0000 0000 0000 0000 0000 Driver_SPI_SwapByte(sectorAddr > 16 & 0xff); Driver_SPI_SwapByte(sectorAddr >> 8 & 0xff); Driver_SPI_SwapByte(sectorAddr & 0xff); Driver_SPI_Stop(); Inf_W25q32_WiteDisanable(); } /** * @description: 执行页写入 写入时,从指定页的首地址开始写入. * @param {uint8_t} block * @param {uint8_t} sector * @param {uint8_t} page * @param {uint8_t*} data * @param {uint16_t} len */ void Inf_W25Q32_WritePage(uint8_t block, uint8_t sector, uint8_t page, uint8_t *data, uint16_t len) { Inf_W25Q32_WaiteNotBusy(); Inf_W25q32_WiteEnable(); /* 计算出要写入的数据的页的首地址 */ uint32_t pageAddr = block * 0x010000 + sector * 0x001000 + page * 0x000100; Driver_SPI_Start(); Driver_SPI_SwapByte(0x02); Driver_SPI_SwapByte(pageAddr >> 16 & 0xff); Driver_SPI_SwapByte(pageAddr >> 8 & 0xff); Driver_SPI_SwapByte(pageAddr & 0xff); for (uint16_t i = 0; i > 16 & 0xff); Driver_SPI_SwapByte(pageAddr >> 8 & 0xff); Driver_SPI_SwapByte(pageAddr & 0xff); for (uint16_t i = 0; iInf_W25Q32.h
#ifndef __INF_W25Q32_ #define __INF_W25Q32_ #include "Driver_SPI.h" void Inf_W25Q32_Init(void); void Inf_W25Q32_ReadId(uint8_t *mid, uint16_t *did); void Inf_W25q32_WiteEnable(void); void Inf_W25q32_WiteDisanable(void); void Inf_W25Q32_EraseSector(uint8_t block, uint8_t sector); void Inf_W25Q32_WritePage(uint8_t block, uint8_t sector, uint8_t page, uint8_t *data, uint16_t len); void Inf_W25Q32_Read(uint8_t block, uint8_t sector, uint8_t page, uint8_t *data, uint16_t len); #endifmain.c
#include "Driver_USART.h" #include "Delay.h" #include "Inf_W25Q32.h" int main() { Driver_USART1_Init(); Inf_W25Q32_Init(); /* 读取id测试是否正常 */ uint8_t mid = 0; uint16_t did = 0; Inf_W25Q32_ReadId(&mid, &did); printf("mid=0x%X, did=0x%X\r\n", mid, did); /* 先擦除 */; Inf_W25Q32_EraseSector(0,0); Inf_W25Q32_EraseSector(0,1); Inf_W25Q32_WritePage(0,0,0, "abc", 3); Inf_W25Q32_WritePage(0,1,0, "456", 3); uint8_t buff[10] = {0}; Inf_W25Q32_Read(0,0,0, buff, 3); printf("%s\r\n", buff); Inf_W25Q32_Read(0,1,0, buff, 3); printf("%s\r\n", buff); while (1) { } }(图片来源网络,侵删)
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。