M-Arch(番外7)GD32L233评测-FLASH读写

前言

今儿这个是flash的读写测试。

闪存结构

闪存控制器(FMC),提供了片上闪存需要的所有功能。一般而言,MCU的Flash包括4个部分:

  • 主存储区(Main memory),其特点是可读可写,存放的是程序;如果空间足够,也可以用来存放数据(参数,记录等)。

  • 系统存储区(System memory),有的翻译叫存储块,实际上就是Boot Loader,只读。

  • 一次性存储区OTP(One Time Program),其特点是只能由1写为0,不能由0写为1,可以用来存储保护性或防伪性内容。

  • 选项字节(Option bytes),存放的是系统的一些配置数据,上电时加载到寄存器中。

Flash读写的流程和注意事项在芯片手册中写的清清白白,就不赘述了;如果大家感兴趣,可以对着厂家给的API接口比对着看,理解会更好一点。

04c6ec7b1c4b0aadbf07891af133dd04.png
GD32L233 Flash结构
18403d8e3dc5eedd402139debf2425c4.png
GD32F450 Flash结构

在flash分区的专用名称中,记住下面这个公式可以很好的理解分区:

页(Page)< 扇区(Sector) < 块(Block,bank)< 芯片(Chip)

一般容量小的就是分页,容量大就分块+扇区。

FMC测试

FMC的操作实际上比较简单,厂家给的API都很成熟,需要注意的几个点:

  1. FMC不能“自杀”,即不能由程序自己写自己,所以FMC只能写非程序区的Flash。

  2. FMC操作上需要先unlock,操作完之后记得lock。

代码:

static void fmc_test(void)
{
#ifdef FMC_TEST
    #define FMC_TEST_DATA_COUNT 5
    static uint8_t fmc_test_flag = 0;
    uint32_t index = 0;
#if defined(GD32)
    uint32_t addr =  0x08100000;
    uint32_t sector = CTL_SECTOR_NUMBER_12;
#endif
#if defined(GD32M0)    
    uint32_t addr =  0x0803E000;
    uint32_t sector = addr;
    #define fmc_sector_erase fmc_page_erase
#endif
#ifdef STM32
    uint32_t addr =  0x08040000;
    uint32_t sector = addr;
#endif
    uint32_t *pdata = (uint32_t *)addr;
    int32_t fmc_state;

    if (fmc_test_flag)
    {
        return;
    }
    fmc_test_flag = 1;

    /* 1. before erase */
    printf("before erase,\tdata = ");
    for (index = 0; index < FMC_TEST_DATA_COUNT; index++)
    {
        printf("0x%X ", pdata[index]);
    }
    printf("\r\n");

    /* 2. after erase */
    fmc_unlock();
    fmc_state = fmc_sector_erase(sector);
    fmc_lock();
    printf("after erase[%d]\tdata = ", fmc_state);
    for (index = 0; index < FMC_TEST_DATA_COUNT; index++)
    {
        printf("0x%X ", pdata[index]);
    }
    printf("\r\n");

    /* 2. after program */
    fmc_unlock();
    for (index = 0; index < FMC_TEST_DATA_COUNT; index++)
    {
        fmc_state = fmc_word_program(addr, index+9);
        addr += 4;
        printf("programing [0x%0X] state = [%d]\r\n", addr, fmc_state);
    }
    fmc_lock();
    printf("after program,\tdata = ");
    for (index = 0; index < FMC_TEST_DATA_COUNT; index++)
    {
        printf("0x%X ", pdata[index]);
    }
    printf("\r\n");

#endif
}

测试结果(GD32L233,正常状态返回值是0):

before erase, data = 0x9 0xA 0xB 0xC 0xD 
after erase[0] data = 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 
programing [0x803E004] state = [0]
programing [0x803E008] state = [0]
programing [0x803E00C] state = [0]
programing [0x803E010] state = [0]
programing [0x803E014] state = [0]
after program, data = 0x9 0xA 0xB 0xC 0xD

OTP和OB展示

通过Keil的调试功能可以查看Flash地址的数据,当然也可以直接在程序中读取。

GD32L233 OB数据:

63b01aa65bdce99f92e15f2f0854ddb9.png
GD32L233 OB
82f31ee9efd68e309975b933f0ef9f2f.gif 99e305fa5a740ab1b22cd665ccf3c6b0.png 0e2d548cf42b1045c5570c2a021c7270.gif
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是一个使用C语言编的L3GD20陀螺仪传感器的I2C驱动代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <linux/i2c-dev.h> #include <sys/ioctl.h> #define L3GD20_ADDRESS 0x6B // 寄存器地址 #define L3GD20_CTRL_REG1 0x20 #define L3GD20_CTRL_REG4 0x23 #define L3GD20_OUT_X_L 0x28 #define L3GD20_OUT_X_H 0x29 #define L3GD20_OUT_Y_L 0x2A #define L3GD20_OUT_Y_H 0x2B #define L3GD20_OUT_Z_L 0x2C #define L3GD20_OUT_Z_H 0x2D // 初始化I2C设备 int initI2C(const char *device) { int file; if ((file = open(device, O_RDWR)) < 0) { perror("Failed to open the I2C device"); exit(1); } return file; } // 初始化L3GD20 void initL3GD20(int file) { // 配置控制寄存器1 unsigned char ctrlReg1Data = 0x0F; // 设置数据速率为800Hz,启用X、Y、Z轴 if (write(file, &ctrlReg1Data, sizeof(ctrlReg1Data)) != sizeof(ctrlReg1Data)) { perror("Failed to write to the control register 1"); exit(1); } // 配置控制寄存器4 unsigned char ctrlReg4Data = 0x30; // 设置全局尺度选择为2000dps if (write(file, &ctrlReg4Data, sizeof(ctrlReg4Data)) != sizeof(ctrlReg4Data)) { perror("Failed to write to the control register 4"); exit(1); } } // 取陀螺仪数据 void readGyro(int file, short *gyroX, short *gyroY, short *gyroZ) { // 设置自动增量寻址(连续取) unsigned char regAddr = L3GD20_OUT_X_L | 0x80; if (write(file, &regAddr, sizeof(regAddr)) != sizeof(regAddr)) { perror("Failed to write the register address"); exit(1); } // 取X轴数据 unsigned char buffer[6]; if (read(file, buffer, sizeof(buffer)) != sizeof(buffer)) { perror("Failed to read the gyro data"); exit(1); } *gyroX = (buffer[1] << 8) | buffer[0]; // 取Y轴数据 *gyroY = (buffer[3] << 8) | buffer[2]; // 取Z轴数据 *gyroZ = (buffer[5] << 8) | buffer[4]; } int main() { const char *device = "/dev/i2c-1"; // I2C设备文件路径 int file = initI2C(device); // 设置I2C设备地址为L3GD20的地址 if (ioctl(file, I2C_SLAVE, L3GD20_ADDRESS) < 0) { perror("Failed to set I2C device address"); exit(1); } // 初始化L3GD20 initL3GD20(file); while (1) { short gyroX, gyroY, gyroZ; // 取陀螺仪数据 readGyro(file, &gyroX, &gyroY, &gyroZ); // 打印数据 printf("X轴陀螺仪: %d\n", gyroX); printf("Y轴陀螺仪: %d\n", gyroY); printf("Z轴陀螺仪: %d\n", gyroZ); sleep(1); } close(file); return 0; } ``` 这个代码使用了Linux的I2C接口库来与L3GD20进行通信。它打开了I2C设备文件并设置了L3GD20的地址。`initL3GD20`函数用于初始化L3GD20传感器,`readGyro`函数用于取陀螺仪数据。在主函数中,我们不断取并打印陀螺仪数据。 请注意,此代码假设你已经在Linux系统上启用了I2C功能,并且连接了L3GD20传感器到正确的I2C总线上。如果你的I2C设备文件路径或者L3GD20的地址不同,请相应地修改代码中的`device`和`L3GD20_ADDRESS`变量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值