设为首页收藏本站

Discuz! Board

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 4163|回复: 1
打印 上一主题 下一主题

Noridc 52832 SPI Flash 驱动+文件系统

[复制链接]

1

主题

1

帖子

40

积分

新手上路

Rank: 1

积分
40
跳转到指定楼层
楼主
perry_chen 发表于 2018-11-24 10:22:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
## SPI Flash 驱动开发

*   **sdk_config.h配置**

```
#define NRFX_SPI_ENABLED 1
#define SPI_ENABLED 1
#define SPI0_ENABLED 0
#define SPI1_ENABLED 1
#define SPI1_USE_EASY_DMA 0

```

注意:因为TWI0和SPI0为同一地址,TWI0已经被G-Sensor使用,所以我们使用SPI1

*   **添加文件**

```
modules\nrfx\drivers\src\nrfx_spi.c
integration\nrfx\legacy\nrf_drv_spi.c

```

*   **初始化**

```
#define USER_SPI_CONFIG_IRQ_PRIORITY_HIGH 3

#define USRE_NRF_DRV_SPI_FLSH_CONFIG                         \
{                                                            \
    .sck_pin      = SPI_SCK_PIN,                                        \
    .mosi_pin     = SPI_MOSI_PIN,                                        \
    .miso_pin     = SPI_MISO_PIN,                                        \
    .ss_pin       = NRF_DRV_SPI_PIN_NOT_USED,                \
    .irq_priority = USER_SPI_CONFIG_IRQ_PRIORITY_HIGH,         \
    .orc          = 0xFF,                                    \
    .frequency    = NRF_DRV_SPI_FREQ_4M,                   \
    .mode         = NRF_DRV_SPI_MODE_0,                      \
    .bit_order    = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST,         \
}

static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(1);  /**< SPI instance. */

/**
* @brief SPI user event handler.
* @param event
*/
static void spi_event_handler(nrf_drv_spi_evt_t const * p_event, void *p_context)
{
    spi_xfer_done = true;
    //NRF_LOG_INFO("Transfer completed.");
        if (spi_rx_buf[0] != 0)
    {
        //NRF_LOG_INFO(" Received:");
        //NRF_LOG_HEXDUMP_INFO(spi_rx_buf, strlen((const char *)spi_rx_buf));
    }
}

void spi_flash_init(void) {
        nrf_drv_spi_config_t spi_config = USRE_NRF_DRV_SPI_FLSH_CONFIG;
    spi_config.ss_pin   = NRF_DRV_SPI_PIN_NOT_USED;

    APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
        nrf_delay_ms(10);
        NRF_LOG_INFO("SPI flash init...");
}

```

注意:

1.  ss_pin需要自己控制;
2.  NRF_DRV_SPI_INSTANCE设置1,对应sdk_config.h中的SPI1;
3.  irq_priority中断优先级一定要设置为3,默认配置是7,不然蓝牙协议栈起来后会没效果!

*   **驱动Flash芯片 GD25Q127C**

```
/*****************************************************************************
** 文件名称:static uint8_t spi_flash_read_status_reg(void)
** 功    能:“读状态寄存器”命令,retValue为读到的数值
** 修改日志:
** 附    录:当CS拉低之后,把05H从DI引脚输入到Flash芯片,CLK上升沿,数据写入Flash,当Flash收到05H后,会把“状态寄存器”的值,从D0引脚输出,CLK下降沿输出。  
******************************************************************************/

static uint8_t spi_flash_read_status_reg(void)
{
    uint8_t retValue = 0;

    CS_L();
    spi_flash_write_one_byte(SPIFLASH_READSR_CMD);
    retValue = spi_flash_read_one_byte();
    CS_H();
    return retValue;
}

/*****************************************************************************
** 文件名称:static uint8_t spi_flash_wait_busy(void)
** 功    能:判断Flash是否busy。
** 修改日志:
:SPIFLASH_WRITE_BUSYBIT 写状态寄存器
******************************************************************************/
static uint8_t spi_flash_wait_busy(void)
{
    spi_wait_count = 0;
    while((spi_flash_read_status_reg() & SPIFLASH_WRITE_BUSYBIT) == 0x01)  //状态寄存器0位为Busy位
    {  
       if(spi_wait_count >= 100)
          break;
    }

        //NRF_LOG_INFO("spi_wait_count = %d", spi_wait_count);
    return GD25OK;
}

static uint8_t spi_flash_read_one_byte(void)
{
    uint8_t len = 1;

        spi_tx_buf[0] = 0xFF;
        spi_xfer_done = false;
        APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, spi_tx_buf, len, spi_rx_buf, len));
        while(!spi_xfer_done);
    return (spi_rx_buf[0]);
}

static void spi_flash_write_one_byte(uint8_t Dat)
{
    uint8_t len = 1;
        ret_code_t ret_code;

        spi_tx_buf[0] = Dat;
        spi_xfer_done = false;
        APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, spi_tx_buf, len, spi_rx_buf, len));
        while(!spi_xfer_done);
}

void spi_flash_write_enable(void)
{
        CS_L();  
        spi_flash_write_one_byte(SPIFLASH_WRITEEN_CMD);
        CS_H();  
}

/*****************************************************************************
** 文件名称:uint8_t spi_flash_read_data(uint8_t *pBuffer,uint32_t ReadAddr,uint32_t ReadBytesNum)
** 功    能:读Flash的某地址ReadAddr,读多大ReadByteNum,的数值。
** 修改日志:
******************************************************************************/
uint8_t spi_flash_read_data(uint8_t *pBuffer, uint32_t ReadAddr, uint32_t ReadBytesNum)
{
    uint8_t len;

        spi_tx_buf[0] = SPIFLASH_READDATA_CMD;
        spi_tx_buf[1] = (uint8_t)((ReadAddr & 0x00ff0000) >> 16);
        spi_tx_buf[2] = (uint8_t)((ReadAddr & 0x0000ff00) >> 8);
        spi_tx_buf[3] = (uint8_t)ReadAddr;

        len = ReadBytesNum + 4;

        CS_L();
        spi_xfer_done = false;
        APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, spi_tx_buf, len, spi_rx_buf, len));
        while(!spi_xfer_done);
        CS_H();

        memcpy(pBuffer, &spi_rx_buf[4], ReadBytesNum);

        return GD25OK;
}

// 52832 spi flash 的库每次最多只能写或者读取 251个字节,常规页是256字节,所以要特殊处理一下
uint8_t spi_flash_read_data_52832(uint8_t *pBuffer,uint32_t ReadAddr,uint32_t ReadBytesNum)
{
    uint32_t len = ReadBytesNum, len_cut = 0;
        uint32_t addr = ReadAddr;
        uint8_t *pic_point = pBuffer;

        do {
                spi_tx_buf[0] = SPIFLASH_READDATA_CMD;
                spi_tx_buf[1] = (uint8_t)((addr & 0x00ff0000) >> 16);
                spi_tx_buf[2] = (uint8_t)((addr & 0x0000ff00) >> 8);
                spi_tx_buf[3] = (uint8_t)addr;
                len_cut = (len >= (0xFF - 4)) ? (0xFF) : (len + 4);

                CS_L();
                spi_xfer_done = false;
                APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, spi_tx_buf, 4, spi_rx_buf, len_cut));
                while(!spi_xfer_done);
                CS_H();

                memcpy(pic_point, &spi_rx_buf[4], (len_cut - 4));
                addr += (len_cut - 4);
                len -= (len_cut - 4);
                pic_point += (len_cut - 4);
        } while(len > 0);

    return GD25OK;
}

```

注意:52832的nrf_drv_spi_transfer函数限制了每次读写不能超过251字节,所以要特殊处理一下。读可以任意地址读,写不能跨页写,正常一页256字节每次都需要分成251+5两次写

* * *

## [](#littlefs文件系统移植)littlefs文件系统移植

考虑到单片机系统没有文件系统管理,每次读写文件异常麻烦,所以我们移植一个小型嵌入式文件系统(带断电恢复以及磨损平衡)。

*   **littlefs简介**

Github地址:[https://github.com/ARMmbed/littlefs](https://github.com/ARMmbed/littlefs)

> LittleFS - 一个高度完整的嵌入式文件系统
>
> *   断电恢复能力 - 要求文件系统保持一致,并将数据刷新到底层存储。
> *   平均磨损 - 通常情况下,存储支持每块数量有限的擦除,因此使用整个存储设备对于可靠性非常重要。
> *   微小的占用资源 - 物联网设备受到ROM和RAM的限制,占用资源小可以节省资金。

*   **配置**

```
lfs_t g_lfs;
lfs_file_t file;
uint8_t        lfs_read_buf[256] = {0};
uint8_t        lfs_prog_buf[256] = {0};
uint8_t        lfs_lookahead_buf[256] = {0};
uint8_t        lfs_file_buf[256] = {0};
uint32_t lfs_free_spcae_size = 0;

int user_provided_block_device_read(const struct lfs_config *c, lfs_block_t block,
                lfs_off_t off, void *buffer, lfs_size_t size) {

        ASSERT(block < c->block_count);
        spi_flash_read_data_52832((uint8_t *)buffer, (block * c->block_size + off), size);
        return 0;
}

int user_provided_block_device_prog(const struct lfs_config *c, lfs_block_t block,
                lfs_off_t off, const void *buffer, lfs_size_t size) {

        ASSERT(block < c->block_count);
        spi_flash_write_page_more((uint8_t *)buffer, (block * c->block_size + off), size);
        return 0;
}

int user_provided_block_device_erase(const struct lfs_config *c, lfs_block_t block) {
        ASSERT(block < c->block_count);
        spi_flash_erase_addr(block * c->block_size);
        return 0;
}

int user_provided_block_device_sync(const struct lfs_config *c) {
        return 0;
}

// configuration of the filesystem is provided by this struct
const struct lfs_config cfg = {
    // block device operations
    .read  = user_provided_block_device_read,
    .prog  = user_provided_block_device_prog,
    .erase = user_provided_block_device_erase,
    .sync  = user_provided_block_device_sync,

    // block device configuration
    .read_size =         256,
    .prog_size =         256,
    .block_size =         4096,
    .block_count =         4096,
    .lookahead =         256,

        .read_buffer =                         lfs_read_buf,
        .prog_buffer =                        lfs_prog_buf,
        .lookahead_buffer =         lfs_lookahead_buf,
        .file_buffer =                         lfs_file_buf,
};

```

注意:Flash芯片为128M,只配置了其中的16M

*   **初始化**

```
void spi_flash_littlefs_init(void) {
        // mount the filesystem
        int err = lfs_mount(&g_lfs, &cfg);

    // reformat if we can't mount the filesystem
    // this should only happen on the first boot
    if(err) {
                spi_flash_erase_chip();
        err = lfs_format(&g_lfs, &cfg);
        err = lfs_mount(&g_lfs, &cfg);
    }

        NRF_LOG_INFO("spi flash littlefs done");
}

```

*   **测试**

```
void spi_flash_littlefs_test(void) {

    // read current count
    int i;
    uint32_t buf_len = 0;
        uint8_t test_buf[1024] = {'\0'};

    spi_flash_littlefs_init();

        //lfs_file_open(&g_lfs, &file, "boot_count",  LFS_O_WRONLY | LFS_O_TRUNC);
        //NRF_LOG_INFO("lfs_file_size: %d", lfs_file_size(&g_lfs, &file));
        //lfs_file_close(&g_lfs, &file);

        lfs_file_open(&g_lfs, &file, "boot_count",  LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND);
        for (i = 0; i < 1024; i++) {
                lfs_file_write(&g_lfs, &file, (const void*)"0123456789", strlen("0123456789"));
        }
        lfs_file_close(&g_lfs, &file);

        lfs_file_open(&g_lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
        buf_len = lfs_file_size(&g_lfs, &file);
        NRF_LOG_INFO("lfs_file_size: %d", buf_len);
        lfs_file_seek(&g_lfs, &file, buf_len - 1024, LFS_SEEK_SET);
    lfs_file_read(&g_lfs, &file, (void*)test_buf, sizeof(test_buf));
        lfs_file_close(&g_lfs, &file);
        NRF_LOG_HEXDUMP_INFO(test_buf, 7);

        // release any resources we were using
        lfs_unmount(&g_lfs);
}

```


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖
回复

使用道具 举报

243

主题

1706

帖子

6151

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
6151
沙发
admin 发表于 2018-11-24 11:31:09 | 只看该作者
非常不错,置精华
回复 支持 反对

使用道具 举报

Archiver|手机版|小黑屋|Comsenz Inc.   

GMT+8, 2024-4-29 00:17 , Processed in 0.127011 second(s), 28 queries .

Powered by Discuz! X3

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表