打印
[APM32E0]

APM32E030R Mirco-EVB开发板驱动flash

[复制链接]
86|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 sujingliang 于 2025-6-6 10:33 编辑

很荣幸在《@开发者们!100+开发板免费领,上海慕尼黑 电子展见》活动中获得一个块APM32E030R开发板。

此次,我首次通过回帖的方式收获幸运,这究竟是幸运之神偶然的恩赐,还是我本就是幸运之子,此刻不过是命运轨迹中一次恰到好处的回归?
不管怎样,感谢极海半导体,感谢21IC。

下面是APM32E030R开发板:

原理图:


可以看到原理图上留有FLASH的扩展(开发板上这部分没有焊接)。

所以我在开发板上补上了一个W25Q80并进行了驱动


1、SPI初始化
对时钟、引脚、SPI等进行初始化

void SPI_InitForFlash(void)
{
    SPI_Config_T spiConfig;
    GPIO_Config_T gpioConfig;
   
    // 使能时钟
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SPI1);
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
   
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
        
        
            /* Config alter function*/
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_5, GPIO_AF_PIN0);
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_6, GPIO_AF_PIN0);
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_7, GPIO_AF_PIN0);
        
    // 配置SPI引脚
    // PA5 - SCK, PA6 - MISO, PA7 - MOSI
    gpioConfig.pin = GPIO_PIN_5 | GPIO_PIN_7;
    gpioConfig.mode = GPIO_MODE_AF;
    gpioConfig.speed = GPIO_SPEED_50MHz;
    gpioConfig.outtype = GPIO_OUT_TYPE_PP;
    gpioConfig.pupd = GPIO_PUPD_PU;
    GPIO_Config(GPIOA, &gpioConfig);
   
    // 配置CS引脚(假设使用PA4)
    gpioConfig.pin = GPIO_PIN_4;
    gpioConfig.outtype = GPIO_OUT_TYPE_PP;
                gpioConfig.speed = GPIO_SPEED_50MHz;
    gpioConfig.pupd = GPIO_PUPD_PU;
    gpioConfig.mode = GPIO_MODE_OUT;
    GPIO_Config(GPIOA, &gpioConfig);
    GPIO_SetBit(GPIOA, GPIO_PIN_4); // 初始高电平(不选中)
               
                /* config PIN_6  MISO*/
    gpioConfig.pin = GPIO_PIN_6;
    gpioConfig.mode = GPIO_MODE_AF;
    gpioConfig.pupd = GPIO_PUPD_PU;
    gpioConfig.speed = GPIO_SPEED_50MHz;
    GPIO_Config(GPIOA, &gpioConfig);
               
   
     /* SPI RESET*/
    SPI_Reset(SPI1);
    SPI_ConfigStructInit(&spiConfig);

    /* SPI configuration*/
    /* Set Clock polarity is Low, but Slave is High*/
    spiConfig.polarity = SPI_CLKPOL_LOW;

    /* select master mode*/
    spiConfig.mode = SPI_MODE_MASTER;

    /* SPI Clock Phase is 1EDGE, but Slave is 1EDGE*/
    spiConfig.phase = SPI_CLKPHA_1EDGE;

    /* Enable Software slave control */
    spiConfig.slaveSelect = SPI_SSC_ENABLE;

    /* Set SPI BaudRate divider*/
    spiConfig.baudrateDiv = SPI_BAUDRATE_DIV_256;

    /* SPI data length*/
    spiConfig.length = SPI_DATA_LENGTH_8B;

    /* Set internal slave*/
    SPI_EnableInternalSlave(SPI1);
    SPI_Config(SPI1, &spiConfig);
    SPI_ConfigFIFOThreshold(SPI1, SPI_RXFIFO_QUARTER);

    SPI_Enable(SPI1);
}


2、片选控制
// 片选控制
static void FLASH_CS_Low(void) {
    GPIO_ClearBit(GPIOA, GPIO_PIN_4);
}

static void FLASH_CS_High(void) {
    GPIO_SetBit(GPIOA, GPIO_PIN_4);
}


3、发送单字节
// SPI发送接收单字节
static uint8_t SPI_TransmitReceiveByte(uint8_t data)
{
    while(SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET);
    SPI_TxData8(SPI1, data);
   
    while(SPI_ReadStatusFlag(SPI1, SPI_FLAG_RXBNE) == RESET);
    return SPI_RxData8(SPI1);
}


4、写使能
static void FLASH_WriteEnable(void)
{
    FLASH_CS_Low();
    SPI_TransmitReceiveByte(0x06); // 写使能命令
    FLASH_CS_High();
}


5、读取数据
void FLASH_ReadData(uint32_t addr, uint8_t *pData, uint32_t size)
{
    FLASH_CS_Low();
    SPI_TransmitReceiveByte(0x03); // 读数据命令
   
    // 发送地址(24位)
    SPI_TransmitReceiveByte((addr >> 16) & 0xFF);
    SPI_TransmitReceiveByte((addr >> 8) & 0xFF);
    SPI_TransmitReceiveByte(addr & 0xFF);
   
    // 读取数据
    while(size--) {
        *pData++ = SPI_TransmitReceiveByte(0xFF);
    }
   
    FLASH_CS_High();
}
6、页编程(写入数据,通常256字节一页)
void FLASH_PageProgram(uint32_t addr, uint8_t *pData, uint32_t size)
{
    FLASH_WriteEnable();
    FLASH_WaitForReady();
   
    FLASH_CS_Low();
    SPI_TransmitReceiveByte(0x02); // 页编程命令
   
    // 发送地址
    SPI_TransmitReceiveByte((addr >> 16) & 0xFF);
    SPI_TransmitReceiveByte((addr >> 8) & 0xFF);
    SPI_TransmitReceiveByte(addr & 0xFF);
   
    // 写入数据
    while(size--) {
        SPI_TransmitReceiveByte(*pData++);
    }
   
    FLASH_CS_High();
    FLASH_WaitForReady(); // 等待写入完成
}
7、扇区擦除(通常4KB)
void FLASH_SectorErase(uint32_t addr)
{
    FLASH_WriteEnable();
    FLASH_WaitForReady();
   
    FLASH_CS_Low();
    SPI_TransmitReceiveByte(0x20); // 扇区擦除命令
   
    // 发送地址
    SPI_TransmitReceiveByte((addr >> 16) & 0xFF);
    SPI_TransmitReceiveByte((addr >> 8) & 0xFF);
    SPI_TransmitReceiveByte(addr & 0xFF);
   
    FLASH_CS_High();
    FLASH_WaitForReady(); // 等待擦除完成
}
8、等待FLASH就绪
static void FLASH_WaitForReady(void)
{
    uint8_t status;
   
    FLASH_CS_Low();
    SPI_TransmitReceiveByte(0x05); // 读状态寄存器命令
   
    do {
        status = SPI_TransmitReceiveByte(0xFF);
    } while(status & 0x01); // 检查BUSY位
   
    FLASH_CS_High();
}
9、读取FLASH ID (用于测试通信)
uint32_t FLASH_ReadID(void)
{
    uint32_t id = 0;
   
    FLASH_CS_Low();
    SPI_TransmitReceiveByte(0x9F); // 读ID命令
   
    id |= (SPI_TransmitReceiveByte(0xFF) << 16);
    id |= (SPI_TransmitReceiveByte(0xFF) << 8);
    id |= SPI_TransmitReceiveByte(0xFF);
   
    FLASH_CS_High();
    return id;
}
10、flash测试程序
void flash_test(void)
{
    uint8_t readBuffer[256];
    uint8_t writeBuffer[256];
    uint32_t flashID;
        
  // 读取FLASH ID
    flashID = FLASH_ReadID();
    printf("FLASH ID: 0x%06lX\n", (unsigned long)flashID);
        
// 准备测试数据
    for(int i = 0; i < 256; i++) {
        writeBuffer[i] = i;
    }
   
    // 擦除扇区(假设擦除地址0x000000)
    FLASH_SectorErase(0x000000);
   
    // 写入数据
    FLASH_PageProgram(0x000000, writeBuffer, 256);
   
    // 读取验证
    FLASH_ReadData(0x000000, readBuffer, 256);        
               
                for(int i = 0; i < 256; i++) {
                        printf("0x%02X ",readBuffer[i] );
    }
}

11、main函数
int main(void)
{
                APM_TINY_COMInit(COM1);
                // 初始化
    SPI_InitForFlash();
        
                printf("Flash demo program start\r\n");
        
                flash_test();
    while (1)
    {
    }
}
12、运行
可以看到已经读取到FLASH ID,并且读写测试输出符合预期



使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

63

主题

124

帖子

3

粉丝