打印
[活动]

[APT32F173评测] 基于APT32F173实现了对 Flash 的编程和擦除

[复制链接]
516|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
kzlzqi|  楼主 | 2024-1-24 16:28 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 kzlzqi 于 2024-1-24 16:46 编辑

在系统总线架构中,该芯片集成了E906fp内核,具备8K的Icache用于提高指令访问速度。此外,系统包含两个DMA(直接内存访问)控制器,分别是DMA0和DMA1,它们挂接到不同的外设上。


DMA1的操作对象可以是FLASH、SRAM、GPIO以及所有APB总线上的外设。而DMA0的操作对象则限定为SRAM和所有APB总线上的外设。


系统还提供一个可配置的SRAM,总共32KB的SRAM空间由SRAM0和SRAM1组成。通过配置SYSCON_OPT1[SRAMBLKCTRL],可以将SRAM0设置为24KB,SRAM1设置为8KB;或者将SRAM0设置为16KB,SRAM1设置为16KB。需要注意的是,SRAM0只能用作数据存储(DSRAM),而SRAM1可以通过SYSCON_OPT1[SRAN1FUNCCTRL]配置为指令存储(ISRAM)。一旦SRAM1配置为ISRAM,其地址会自动映射到0x40000开始的地址空间,其中的内容将不能被修改,除非重新设置SYSCON_OPT1[SRAN1FUNCCTRL]或进行复位。


这一架构设计提供了灵活性,使得开发者能够根据具体需求配置SRAM的大小和用途,同时通过DMA控制器实现高效的数据传输。


按照RISC-V标准的定义,异常在优先级上被认为比中断更低。在E906芯片中,将非可屏蔽中断(NMI)的异常向量号定义为24,并将其设置为所有中断和异常中优先级最高的类型。简单来说,就是NMI的优先级高于中断,中断的优先级高于异常。这意味着在发生NMI时,系统将首先处理NMI,然后才是中断和异常。


当进行 FLASH 读写操作时,可以按照以下步骤进行操作:


步骤1: 清除页缓存空间
在这一步,我们使用 IFC_CMR 寄存器中的 CMD 命令 0x7 来清除页缓存空间。在执行前,需要将秘钥 0x5A5A_5A5A 写入 IFC_KEY 寄存器。示例代码如下:

CSP_IFC_SET_KR(IFC, USER_KEY); // 写入秘钥
CSP_IFC_SET_CMR(IFC, PAGE_LAT_CLR); // 清除页缓存
CSP_IFC_SET_AR(IFC, PAGE_ADDR); // 设置操作地址
CSP_IFC_SET_CR(IFC, START); // 启动操作
while (CSP_IFC_GET_CR(IFC) != 0x0); // 等待操作完成



步骤2: 将数据填入页缓存
在这一步,我们将需要写入的数据填入页缓存。页缓存可以通过总线直接写入,类似于 SRAM 内存空间。

for (int i = 0; i < page_size; i++) {
    *(volatile unsigned int *)(PAGE_ADDR + 4 * i) = buffer;
}


步骤3: 预编程设定
设置下一步的编程为预编程,使用 IFC_CMR 寄存器中的 CMD 命令 0x6。
CSP_IFC_SET_KR(IFC, USER_KEY); // 写入秘钥
CSP_IFC_SET_CMR(IFC, PRE_PGM); // 预编程设定
CSP_IFC_SET_AR(IFC, PAGE_ADDR); // 设置操作地址
CSP_IFC_SET_CR(IFC, START); // 启动操作
while (CSP_IFC_GET_CR(IFC) != 0x0); // 等待操作完成


步骤4: 执行写操作(预编程)
执行写操作,使用 IFC_CMR 寄存器中的 CMD 命令 0x1 进行预编程。


CSP_IFC_SET_KR(IFC, USER_KEY); // 写入秘钥
CSP_IFC_SET_CMR(IFC, PROGRAM); // 执行写操作(预编程)
CSP_IFC_SET_AR(IFC, PAGE_ADDR); // 设置操作地址
CSP_IFC_SET_CR(IFC, START); // 启动操作
while (CSP_IFC_GET_CR(IFC) != 0x0); // 等待操作完成



步骤5: 执行页擦除操作
执行页擦除操作,使用 IFC_CMR 寄存器中的 CMD 命令 0x2 进行整个页的擦除。

CSP_IFC_SET_KR(IFC, USER_KEY); // 写入秘钥
CSP_IFC_SET_CMR(IFC, PAGE_ERASE); // 页擦除操作
CSP_IFC_SET_AR(IFC, PAGE_ADDR); // 设置操作地址
CSP_IFC_SET_CR(IFC, START); // 启动操作
while (CSP_IFC_GET_CR(IFC) != 0x0); // 等待操作完成



步骤6: 执行写操作
执行写操作,将页缓存的数据写入闪存中。

CSP_IFC_SET_KR(IFC, USER_KEY); // 写入秘钥
CSP_IFC_SET_CMR(IFC, PROGRAM); // 执行写操作
CSP_IFC_SET_AR(IFC, PAGE_ADDR); // 设置操作地址
CSP_IFC_SET_CR(IFC, START); // 启动操作
while (CSP_IFC_GET_CR(IFC) != 0x0); // 等待操作完成


在每次执行 IFC 操作的命令前,需要将秘钥 0x5A5A_5A5A 写入 IFC_KEY 寄存器,并通过设置 IFC_CR 的 START 位置 1 启动该操作的执行。在 ISP 操作完成后,IFC_RISR 寄存器里的 END 位会被置 1。用户可以查询 IFC_CR 寄存器里的 START 位来判断 ISP 操作是否完成。
以上示例代码提供了对 Flash 读写操作的详细步骤,通过使用 IFC 寄存器进行各个操作,实现了对 Flash 的编程和擦除。
官方示例得具体步骤如下:
1. 清除页缓存空间( IFC_CMR 寄存器中的 CMD = 0x7 )。
2. 将需要写入的数据填入页缓存 (页缓存可通过总线直接写入,类似于 SRAM 内存空间)。
3. 预编程设定( IFC_CMR 寄存器中的 CMD = 0x6 ),设置下一步的编程为预编程。
4. 执行写操作( IFC_CMR 寄存器中的 CMD = 0x1 ),进行预编程。
5. 执行页擦除操作( IFC_CMR 寄存器中的 CMD = 0x2 ),擦除整个页数据。
APT32F173系列使用手册 闪存控制器
APTCHIP MICROELECTRONICS 4-11

示例:
// Step1. Clear Page Latch
CSP_IFC_SET_KR(IFC, USER_KEY); // Write Key
CSP_IFC_SET_CMR(IFC, PAGE_LAT_CLR); // Clear Page Latch
CSP_IFC_SET_AR(IFC, PAGE_ADDR); // Program address
CSP_IFC_SET_CR(IFC, START); // Start Program
while ( CSP_IFC_GET_CR(IFC) != 0x0 ); // Wait for operation done
// Step2. Write Page Latch
for(i=0;i<page_size;i++){
*(volatile unsigned int *)(PAGE_ADDR+4*i) = buffer;
}
// Step3. Set Pre-Program Option
CSP_IFC_SET_KR(IFC, USER_KEY); // Write Key
CSP_IFC_SET_CMR(IFC, PRE_PGM); // Pre-Program
CSP_IFC_SET_AR(IFC, PAGE_ADDR); // Program address
CSP_IFC_SET_CR(IFC, START); // Start Program
while ( CSP_IFC_GET_CR(IFC) != 0x0 ); // Wait for operation done
// Step4. Execute Pre-Program Operation
CSP_IFC_SET_KR(IFC, USER_KEY); // Write Key
CSP_IFC_SET_CMR(IFC, PROGRAM); // Program
CSP_IFC_SET_AR(IFC, PAGE_ADDR); // Program address
CSP_IFC_SET_CR(IFC, START); // Start Program
while ( CSP_IFC_GET_CR(IFC) != 0x0 ); // Wait for operation done

// Step5. Page Erase
CSP_IFC_SET_KR(IFC, USER_KEY); // Write Key
CSP_IFC_SET_CMR(IFC, PAGE_ERASE); // Page Erase
CSP_IFC_SET_AR(IFC, PAGE_ADDR); // Erase address
CSP_IFC_SET_CR(IFC, START); // Start Erase
while ( CSP_IFC_GET_CR(IFC) != 0x0 ); // Wait for operation done
// Step6. Execute Program Operation
CSP_IFC_SET_KR(IFC, USER_KEY); // Write Key
CSP_IFC_SET_CMR(IFC, PROGRAM); // Program
CSP_IFC_SET_AR(IFC, PAGE_ADDR); // Program address
CSP_IFC_SET_CR(IFC, START); // Start Program
while ( CSP_IFC_GET_CR(IFC) != 0x0 ); // Wait for operation done

需要注意的是,由于本产品只能对整页数据进行操作,如果只需要写 1 个字(Word),那么程序必须将该页中所有数据读出来并且写回页缓存区域中,并且替换该页中需要操作的那个字(Word)的数据,最后再将含有新数据的页缓存全部写入闪存中。


下面提供一个简单的示例,如何使用APT32F173系列芯片进行SPI读写FLASH的测试。
(请根据需求自行调整内容。)
#include "apt32f173.h"
// 定义SPI控制寄存器地址
#define SPI_CTRL_ADDR   ((volatile uint32_t*)0x40008000)
// 定义FLASH的CS引脚
#define FLASH_CS_PIN    0
// 定义FLASH指令
#define FLASH_CMD_READ  0x03   // 读取数据指令
#define FLASH_CMD_WRITE 0x02   // 写入数据指令
// 初始化SPI
void initSPI() {
    // 配置SPI控制寄存器
    *SPI_CTRL_ADDR = (1 << 0) | (1 << 4) | (1 << 11);  // 启用SPI,主模式,禁用中断
}
// 选择FLASH设备
void selectFlash() {
    GPIOB->DOUT &= ~(1 << FLASH_CS_PIN);  // 使能CS引脚
}
// 取消选择FLASH设备
void deselectFlash() {
    GPIOB->DOUT |= (1 << FLASH_CS_PIN);  // 禁用CS引脚
}
// 发送SPI指令和数据
void sendSPI(uint8_t cmd, uint32_t addr, uint8_t data) {
    // 发送指令
    SPI1->DATA = cmd;
    while (!(SPI1->SR & (1 << 1)));  // 等待发送完成
    // 发送地址
    SPI1->DATA = (addr >> 16) & 0xFF;
    while (!(SPI1->SR & (1 << 1)));  // 等待发送完成
    SPI1->DATA = (addr >> 8) & 0xFF;
    while (!(SPI1->SR & (1 << 1)));  // 等待发送完成
    SPI1->DATA = addr & 0xFF;
    while (!(SPI1->SR & (1 << 1)));  // 等待发送完成
    // 发送数据
    SPI1->DATA = data;
    while (!(SPI1->SR & (1 << 1)));  // 等待发送完成
}
// 从FLASH读取数据
uint8_t readFromFlash(uint32_t addr) {
    selectFlash();  // 选择FLASH设备
    sendSPI(FLASH_CMD_READ, addr, 0);  // 发送读取指令和地址
    // 接收数据
    SPI1->DATA = 0xFF;
    while (!(SPI1->SR & (1 << 0)));  // 等待接收完成
    uint8_t data = SPI1->DATA;
    deselectFlash();  // 取消选择FLASH设备
    return data;
}
// 向FLASH写入数据
void writeToFlash(uint32_t addr, uint8_t data) {
    selectFlash();  // 选择FLASH设备
    sendSPI(FLASH_CMD_WRITE, addr, data);  // 发送写入指令、地址和数据
    deselectFlash();  // 取消选择FLASH设备
}
int main() {
    initSPI();  // 初始化SPI
    // 初始化GPIOB配置FLASH的CS引脚
    GPIOB->MODE &= ~(0x3 << (FLASH_CS_PIN * 2));  // 清除MODE寄存器对应位
    GPIOB->MODE |= (1 << (FLASH_CS_PIN * 2));     // 设置为推挽输出
    GPIOB->DOUT |= (1 << FLASH_CS_PIN);           // 初始状态禁用CS
    // 从FLASH读取数据
    uint32_t readAddress = 0x000000;  // 读取地址
    uint8_t readData = readFromFlash(readAddress);
    // 向FLASH写入数据
    uint32_t writeAddress = 0x000000;  // 写入地址
    uint8_t writeData = 0xAB;           // 写入数据
    writeToFlash(writeAddress, writeData);
    while (1) {
        // 此处添加其他任务或保持CPU空闲
    }
}




一定要确保芯片的连接正确,SPI配置符合硬件规格。

使用操作请查看使用手册,会更容易操作哦~

使用手册在小喇叭发出的帖子中就有哦~
太大了。我发半天,发不出来,大家去小喇叭那里下载哦~。
https://bbs.21ic.com/icview-3338624-1-1.html

使用特权

评论回复

相关帖子

沙发
zwsam| | 2024-1-30 09:11 | 只看该作者

使用特权

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

本版积分规则

101

主题

797

帖子

2

粉丝