stm32使用硬件SPI

发布于:2024-07-11 ⋅ 阅读:(24) ⋅ 点赞:(0)

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) << 8;
    *did |= Driver_SPI_SwapByte(0xff) & 0xff;

    Driver_SPI_Stop();
}

/**
 * @description: 读取内部寄存器的busy,一直等到不忙再结束函数
 * @return {*}
 */
void Inf_W25Q32_WaiteNotBusy(void)
{
    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 < len; i++)
    {
        Driver_SPI_SwapByte(data[i]);
    }

    Driver_SPI_Stop();

    Inf_W25q32_WiteDisanable();
}

/**
 * @description: 从flash读取数据
 * @return {*}
 */
void Inf_W25Q32_Read(uint8_t block,
                     uint8_t sector,
                     uint8_t page,
                     uint8_t *data,
                     uint16_t len)
{
    Inf_W25Q32_WaiteNotBusy();
    
    uint32_t pageAddr = block * 0x010000 + sector * 0x001000 + page * 0x000100;

    Driver_SPI_Start();
    Driver_SPI_SwapByte(0x03);

    Driver_SPI_SwapByte(pageAddr >> 16 & 0xff);
    Driver_SPI_SwapByte(pageAddr >> 8 & 0xff);
    Driver_SPI_SwapByte(pageAddr & 0xff);
    for (uint16_t i = 0; i < len; i++)
    {
        data[i] = Driver_SPI_SwapByte(0xff);
    }

    Driver_SPI_Stop();
}

Inf_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);

#endif


main.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)
    {
     
    }
}