#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空闲
    }
}