Is it possible to mount a LittleFS partition in RAM only, in order to extend the product's lifespan with respect to flash erase/write limitations?

Hello

I'm currently mounting a LittleFS partition in the internal flash of my Nordic MCU. However, since data is saved regularly to this partition, I’m concerned that the flash’s erase/write cycle limit could be reached in approximately 1.5 years, after which data integrity issues might occur.

To extend the product's lifespan, I’m considering moving this partition to RAM only.

Is this possible?

Environment : 

- nrf52840
- nrf connect SDK : 2.9.0

Best regards,
Aurélien

Parents
  • Hello,

    To extend the product's lifespan, I’m considering moving this partition to RAM only.

    It should be possible, but definitely not recommended as you will lose all your data on a power surge or any other type of reset or power loss.

    Instead, you can increase the LittleFS partition size. That will increase the sector count, which is one of the suggested measures to increase the life span in the documentation.

    You can also consider using external flash instead of the internal flash on the nrf52840.

  • Hello

    Thank you very much for your reply. I understand the implications of using RAM, but the main goal is to use LittleFS with the SMP Bluetooth service, which simplifies file exchange with a LittleFS partition mounted on the MCU.

    In the end, I plan to use a mix of LittleFS partitions in flash (both internal and external) and in RAM, if possible. The external flash is already full.

    Thank you for the link — I will check it out.

    As for the LittleFS mounted in RAM, I’m facing some issues. There doesn't seem to be a proper example showing how to proceed.

    Here is my code : 

    #define RAMDISK_SIZE  	(64 * 1024)  // 64 KB
    #define RAM_BLOCK_SIZE	(4096)
    static uint8_t ramdisk_buf[RAMDISK_SIZE];
    
    // Définir le périphérique ramdisk (simplifié)
    static struct fs_littlefs ramdisk_fs;
    static struct fs_mount_t ramdisk_mount = {
        .type = FS_LITTLEFS,
        .mnt_point = "/RAMDISK",
        .fs_data = &ramdisk_fs,
        .storage_dev = NULL,
    };
    
    static int ramdisk_block_read(uint32_t block, uint32_t offset, void *buffer, uint32_t length) {
        memcpy(buffer, &ramdisk_buf[block * RAM_BLOCK_SIZE + offset], length);
        return 0;
    }
    
    static int ramdisk_block_write(uint32_t block, uint32_t offset, const void *buffer, uint32_t length) {
        memcpy(&ramdisk_buf[block * RAM_BLOCK_SIZE + offset], buffer, length);
        return 0;
    }
    
    static int ramdisk_block_erase(uint32_t block) {
        memset(&ramdisk_buf[block * RAM_BLOCK_SIZE], 0xFF, RAM_BLOCK_SIZE);
        return 0;
    }
    
    static int ramdisk_sync(const struct lfs_config *cfg) {
        return 0;  // Pas de sync nécessaire pour RAM
    }
    
    // Configuration LittleFS pour utiliser ces fonctions
    struct lfs_config ramdisk_lfs_config = {
        .read = ramdisk_block_read,
        .prog = ramdisk_block_write,
        .erase = ramdisk_block_erase,
        .sync = ramdisk_sync,
        .block_size = RAM_BLOCK_SIZE,
        .block_count = RAMDISK_SIZE / RAM_BLOCK_SIZE,
        .cache_size = RAM_BLOCK_SIZE,
        .lookahead_size = 16,
        .block_cycles = 500,
    };
    
    static struct fs_mount_t *mountpoint = &ramdisk_mount;
    
    int int_ram_fs_init(void) {
    	int rc = 1;
    
    	struct fs_statvfs sbuf;
    
        LOG_PRINTK("####################################\n");
        LOG_PRINTK("Mount LITTLEFS on internal ram ...\n");
    
        ramdisk_fs.lfs.cfg = &ramdisk_lfs_config;
    	
    	/*
    	 * Mount and erase if necessary
    	 */
    	rc = littlefs_mount(mountpoint);
    	if (rc < 0) {
    		littlefs_flash_erase((uintptr_t)mountpoint->storage_dev);		
    		rc = littlefs_mount(mountpoint);
    		if (rc < 0) {
    			return rc;
    		}
    	}
    
    	m_int_flash_mounted = true;
    }

    output : 

    ####################################
    Mount LITTLEFS on internal ram ...
    I: LittleFS version 2.9, disk version 2.1
    I: FS at mx25r1635f@0:0x0 is 512 0x1000-byte blocks with 512 cycle
    I: sizes: rd 16 ; pr 16 ; ca 64 ; la 32
    /RAMDISK mount: 0
    /RAMDISK: bsize = 16 ; frsize = 4096 ; blocks = 512 ; bfree = 510

    The issue I'm facing is that each time I try to mount the partition that's supposed to be in RAM, it's the external one that gets mounted instead...

    app.overlay : 

    /*
     * Copyright (c) 2023 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
     /*/delete-node/ &mx25r64;*/
    
    /* /delete-node/ &storage_partition;*/
    /* 
     &qspi {
         status = "disabled";
     };
    */
     / {
         chosen {
             nordic,pm-ext-flash = &mx25r16;
         };
    
         fstab {
             compatible = "zephyr,fstab";
             lfs1: lfs1 {
                 compatible = "zephyr,fstab,littlefs";
                 mount-point = "/lfs1";
                 partition = <&lfs1_partition>;
                 /*automount;*/
                 read-size = <16>;
                 prog-size = <16>;
                 cache-size = <64>;
                 lookahead-size = <32>;
                 block-cycles = <512>;
             };
             lfs2: lfs2 {
                 compatible = "zephyr,fstab,littlefs";
                 mount-point = "/lfs2";
                 partition = <&lfs2_partition>;
                 /*automount;*/
                 read-size = <16>;
                 prog-size = <16>;
                 cache-size = <64>;
                 lookahead-size = <32>;
                 block-cycles = <512>;
             };
         };
     };
    /* 
     &lfs1 {
        status = "disabled";
    };*/
    /* 
    / {
        ram_disk0: ramdisk@20030000 {
            compatible = "zephyr,ram-disk";
            disk-name = "RAM";
            sector-size = <512>;
            sector-count = <128>; // 64 KB total
            reg = <0x20030000 DT_SIZE_K(64)>;
        };
    };
    */
    &flash0 {
    
    	partitions {
    		compatible = "fixed-partitions";
    		#address-cells = <1>;
    		#size-cells = <1>;
    
    		boot_partition: partition@0 {
    			label = "mcuboot";
    			reg = <0x00000000 DT_SIZE_K(48)>;
    		};
    
    		slot0_partition: partition@c000 {
    			label = "image-0";
    			reg = <0x0000c000 DT_SIZE_K(432)>;
    		};
    
    		slot1_partition: partition@78000 {
    			label = "image-1";
    			reg = <0x00078000 DT_SIZE_K(432)>;
    		};
    
    		lfs2_partition: partition@E4000 {
                label = "lfs2";
                reg = <0x000E4000 DT_SIZE_K(104)>;
            };
    
    		storage_partition: partition@fe000 {
    			label = "storage";
    			reg = <0x000fe000 DT_SIZE_K(2)>;
    		};
    	};
    };
    
    &uart1 {
    	status = "okay";
    	current-speed = <9600>;
    	pinctrl-0 = <&uart1_default>;
    	pinctrl-1 = <&uart1_sleep>;
    	pinctrl-names = "default", "sleep";
        
        modbus0 {
    		compatible = "zephyr,modbus-serial";
    		status = "okay";
    	};
    };
    
    &spi2 {
    	compatible = "nordic,nrf-spi";
    	status = "okay";
    	cs-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
    	pinctrl-0 = <&spi2_default>;
    	pinctrl-1 = <&spi2_sleep>;
    	pinctrl-names = "default", "sleep";
    	mx25r16: mx25r1635f@0 {
    		compatible = "jedec,spi-nor";
    		reg = <0>;
    		spi-max-frequency = <8000000>;
            jedec-id = [c2 28 15];
            /* 
    		sfdp-bfp = [
    			e5 20 f1 ff  ff ff ff 03  44 eb 08 6b  08 3b 04 bb
    			ee ff ff ff  ff ff 00 ff  ff ff 00 ff  0c 20 0f 52
    			10 d8 00 ff  23 72 f5 00  82 ed 04 cc  44 83 68 44
    			30 b0 30 b0  f7 c4 d5 5c  00 be 29 ff  f0 d0 ff ff
    		];*/
            size = <DT_SIZE_M(16)>;
    		has-dpd;
    		t-enter-dpd = <10000>;
    		t-exit-dpd = <35000>;
    	};
    };
    
     &mx25r16 {
    	status = "okay";
        partitions {
            compatible = "fixed-partitions";
            #address-cells = <1>;
            #size-cells = <1>;
    
            lfs1_partition: partition@0 {
                label = "lfs1";
                reg = <0x00000000 0x200000>;
            };
        };
    };

    prj.conf : 

    #
    # Copyright 2024 
    #
    # All rights reserved
    #
    
    CONFIG_NCS_SAMPLES_DEFAULTS=y
    CONFIG_DK_LIBRARY=y
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
    
    CONFIG_USE_SEGGER_RTT=y
    CONFIG_RTT_CONSOLE=y
    CONFIG_UART_CONSOLE=n
    
    CONFIG_NEWLIB_LIBC=y
    CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y
    
    CONFIG_BT=y
    CONFIG_BT_PERIPHERAL=y
    CONFIG_BT_DEVICE_NAME="FREEDOM"
    CONFIG_BT_MAX_CONN=2
    CONFIG_BT_SMP=y
    CONFIG_BT_MAX_PAIRED=8
    
    CONFIG_BT_GATT_AUTO_SEC_REQ=y
    CONFIG_BT_FIXED_PASSKEY=y
    
    CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y
    
    # Enable bonding
    CONFIG_BT_SETTINGS=y
    CONFIG_FLASH=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_FLASH_MAP=y
    CONFIG_NVS=y
    CONFIG_SETTINGS=y
    CONFIG_SETTINGS_RUNTIME=y
    CONFIG_SETTINGS_NVS=y
    
    CONFIG_BT_DIS=y
    CONFIG_BT_DIS_SETTINGS=y
    CONFIG_BT_DIS_STR_MAX=32
    CONFIG_BT_DIS_PNP=n
    CONFIG_BT_DIS_MODEL="FREEDOM"
    CONFIG_BT_DIS_MANUF="TELEDYNE"
    CONFIG_BT_DIS_SERIAL_NUMBER=y
    CONFIG_BT_DIS_FW_REV=y
    CONFIG_BT_DIS_HW_REV=y
    CONFIG_BT_DIS_SW_REV=y
    CONFIG_BT_DIS_SERIAL_NUMBER_STR="123456789abcdef"
    CONFIG_BT_DIS_FW_REV_STR="0.0.0"
    CONFIG_BT_DIS_HW_REV_STR="0.0.0"
    CONFIG_BT_DIS_SW_REV_STR="0.0.0"
    
    #Enable MCUBOOT bootloader build in the application
    CONFIG_BOOTLOADER_MCUBOOT=y
    CONFIG_MCUBOOT_SIGNATURE_KEY_FILE="priv.pem"
    #Include MCUMGR and the dependencies in the build
    CONFIG_NCS_SAMPLE_MCUMGR_BT_OTA_DFU=y
    #CONFIG_MCUMGR_TRANSPORT_BT_AUTHEN=y
    
    CONFIG_BT_EXT_ADV=y
    CONFIG_BT_EXT_ADV_MAX_ADV_SET=2
    CONFIG_BT_DEVICE_NAME_DYNAMIC=n
    CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=100
    
    
    CONFIG_MODBUS=y
    #CONFIG_MODBUS_RAW_ADU=y
    #CONFIG_MODBUS_ROLE_CLIENT=y
    
    CONFIG_PARTITION_MANAGER_ENABLED=y
    
    CONFIG_FILE_SYSTEM=y
    CONFIG_FILE_SYSTEM_LITTLEFS=y
    
    CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
    CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n
    CONFIG_MULTITHREADING=y
    
    CONFIG_HEAP_MEM_POOL_SIZE=60000
    
    # Enable binary descriptors
    #CONFIG_BINDESC=y
    
    # Enable definition of binary descriptors
    #CONFIG_BINDESC_DEFINE=y
    
    # Enable default build time binary descriptors
    #CONFIG_BINDESC_DEFINE_BUILD_TIME=y
    #CONFIG_BINDESC_BUILD_DATE_TIME_STRING=y
    
    ##################################################
    ################ CONF TO CHECK ###################
    ################ TO BE REMOVED ###################
    ##################################################
    
    # Enable file system commands
    CONFIG_MCUMGR_GRP_FS=y
    CONFIG_MCUMGR_GRP_FS_DL_CHUNK_SIZE=200
    
    # Enable the storage erase command.
    CONFIG_MCUMGR_GRP_ZBASIC=y
    CONFIG_MCUMGR_GRP_ZBASIC_STORAGE_ERASE=y
    # Optionally force the file system to be recreated
    #CONFIG_APP_WIPE_STORAGE=y
    # fs_dirent structures are big.
    CONFIG_MAIN_STACK_SIZE=4096
    CONFIG_BT_RX_STACK_SIZE=4096
    CONFIG_BT_HCI_TX_STACK_SIZE=4096
    CONFIG_MCUMGR_TRANSPORT_WORKQUEUE_STACK_SIZE=6000
    
    # Let __ASSERT do its job
    CONFIG_DEBUG=y
    
    CONFIG_INIT_STACKS=y
    CONFIG_THREAD_STACK_INFO=y
    CONFIG_STACK_SENTINEL=y
    CONFIG_THREAD_MONITOR=y
    CONFIG_THREAD_NAME=y
    
    CONFIG_PM_SINGLE_IMAGE=y  # ou CONFIG_PM_MULTI_IMAGE si tu utilises MCUboot
    CONFIG_PM_OVERRIDE_EXTERNAL_DRIVER_CHECK=y
    
    CONFIG_PM_PARTITION_REGION_LITTLEFS_EXTERNAL=y
    #CONFIG_PM_PARTITION_REGION_SETTINGS_STORAGE_EXTERNAL=y
    #CONFIG_PM_PARTITION_REGION_NVS_STORAGE_EXTERNAL=y
    
    CONFIG_SPI=y
    CONFIG_SPI_NOR=y
    CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
    #CONFIG_NORDIC_QSPI_NOR=y
    #CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
    
    CONFIG_GPIO=y
    CONFIG_NFCT_PINS_AS_GPIOS=y
    #CONFIG_LOG_DEFAULT_LEVEL=4
    #CONFIG_WATCHDOG=n
    
    CONFIG_SERIAL=y
    CONFIG_UART_ASYNC_API=y
    CONFIG_UART_INTERRUPT_DRIVEN=n
    

    pm_static.yml : 

    app:
      address: 0xc200
      end_address: 0x85000
      region: flash_primary
      size: 0x78e00
    mcuboot:
      address: 0x0
      end_address: 0xc000
      placement:
        align:
          end: 0x1000
        before:
        - mcuboot_primary
      region: flash_primary
      size: 0xc000
    mcuboot_pad:
      address: 0xc000
      end_address: 0xc200
      placement:
        align:
          start: 0x1000
        before:
        - mcuboot_primary_app
      region: flash_primary
      size: 0x200
    mcuboot_primary:
      address: 0xc000
      end_address: 0x78000
      orig_span: &id001
      - mcuboot_pad
      - app
      region: flash_primary
      sharers: 0x1
      size: 0x6C000
      span: *id001
    mcuboot_primary_app:
      address: 0xc200
      end_address: 0x78000
      orig_span: &id002
      - app
      region: flash_primary
      size: 0x6Ce00
      span: *id002
    mcuboot_secondary:
      address: 0x78000
      end_address: 0xE4000
      placement:
        after:
        - mcuboot_primary
        align:
          start: 0x1000
      region: flash_primary
      share_size:
      - mcuboot_primary
      size: 0x6C000
    lfs2_partition:
      address: 0xE4000
      end_address: 0xFE000
      placement:
        align:
          start: 0x1000
        before:
        - end
      region: flash_primary
      size: 0x1A000
    settings_storage:
      address: 0xfe000
      end_address: 0x100000
      placement:
        align:
          start: 0x1000
        before:
        - end
      region: flash_primary
      size: 0x2000
    sram_primary:
      address: 0x20000000
      end_address: 0x20040000
      region: sram_primary
      size: 0x40000
    littlefs_storage:
      address: 0x0
      size: 0x200000
      device: mx25r16
      end_address: 0x200000
      region: external_flash
    #external_flash:
    #   address: 0x0
    #   size: 0x200000
    #   device: mx25r16f
    #   region: external_flash
    

  • Understood. I have not done this before using RAM as a backend, but I will try to test this and report back to you.

  • Aurele said:
    The issue I'm facing is that each time I try to mount the partition that's supposed to be in RAM, it's the external one that gets mounted instead...

    Btw, since you have littlefs partitions in both RAM and flash, maybe they get mixed up some how. Have you tried this without having a littlefs partition in flash at all? I haven't looked close at your code so I'm not sure why this is happening.

Reply
  • Aurele said:
    The issue I'm facing is that each time I try to mount the partition that's supposed to be in RAM, it's the external one that gets mounted instead...

    Btw, since you have littlefs partitions in both RAM and flash, maybe they get mixed up some how. Have you tried this without having a littlefs partition in flash at all? I haven't looked close at your code so I'm not sure why this is happening.

Children
  • Yes, I tried without success. Now, I'm trying to configure a RAM disk in the app.overlay and then mount the partition, but that hasn't worked either : 

    app.overlay : 

    /*
     * Copyright (c) 2023 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
     /*/delete-node/ &mx25r64;*/
    
    /* /delete-node/ &storage_partition;*/
    /* 
     &qspi {
         status = "disabled";
     };
    */
     / {
         chosen {
             nordic,pm-ext-flash = &mx25r16;
         };
    
         fstab {
             compatible = "zephyr,fstab";
             lfs1: lfs1 {
                 compatible = "zephyr,fstab,littlefs";
                 mount-point = "/lfs1";
                 partition = <&lfs1_partition>;
                 /*automount;*/
                 read-size = <16>;
                 prog-size = <16>;
                 cache-size = <64>;
                 lookahead-size = <32>;
                 block-cycles = <512>;
             };
             lfs2: lfs2 {
                 compatible = "zephyr,fstab,littlefs";
                 mount-point = "/lfs2";
                 partition = <&lfs2_partition>;
                 /*automount;*/
                 read-size = <16>;
                 prog-size = <16>;
                 cache-size = <64>;
                 lookahead-size = <32>;
                 block-cycles = <512>;
             };
         };
    
        // Partition en RAM (fictive via RAM-disk)
        /*
        ram_disk0: ramdisk@20030000 {
            compatible = "zephyr,ram-disk";
            disk-name = "RAM";
            sector-size = <512>;
            sector-count = <128>; // 64 KB total
            reg = <0x20030000 DT_SIZE_K(64)>;
        };*/
        ramdisk0: ramdisk  {
            compatible = "zephyr,ram-disk";
            disk-name = "RAM";  // ← doit correspondre exactement à storage_dev
            sector-size = <512>;
            sector-count = <128>;  // ← 64 Ko
        };
     };
    /* 
     &lfs1 {
        status = "disabled";
    };*/
    /* 
    / {
        ram_disk0: ramdisk@20030000 {
            compatible = "zephyr,ram-disk";
            disk-name = "RAM";
            sector-size = <512>;
            sector-count = <128>; // 64 KB total
            reg = <0x20030000 DT_SIZE_K(64)>;
        };
    };
    */
    &flash0 {
    
    	partitions {
    		compatible = "fixed-partitions";
    		#address-cells = <1>;
    		#size-cells = <1>;
    
    		boot_partition: partition@0 {
    			label = "mcuboot";
    			reg = <0x00000000 DT_SIZE_K(48)>;
    		};
    
    		slot0_partition: partition@c000 {
    			label = "image-0";
    			reg = <0x0000c000 DT_SIZE_K(432)>;
    		};
    
    		slot1_partition: partition@78000 {
    			label = "image-1";
    			reg = <0x00078000 DT_SIZE_K(432)>;
    		};
    
    		lfs2_partition: partition@E4000 {
                label = "lfs2";
                reg = <0x000E4000 DT_SIZE_K(104)>;
            };
    
    		storage_partition: partition@fe000 {
    			label = "storage";
    			reg = <0x000fe000 DT_SIZE_K(2)>;
    		};
    	};
    };
    
    &uart1 {
    	status = "okay";
    	current-speed = <9600>;
    	pinctrl-0 = <&uart1_default>;
    	pinctrl-1 = <&uart1_sleep>;
    	pinctrl-names = "default", "sleep";
        
        modbus0 {
    		compatible = "zephyr,modbus-serial";
    		status = "okay";
    	};
    };
    
    &spi2 {
    	compatible = "nordic,nrf-spi";
    	status = "okay";
    	cs-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
    	pinctrl-0 = <&spi2_default>;
    	pinctrl-1 = <&spi2_sleep>;
    	pinctrl-names = "default", "sleep";
    	mx25r16: mx25r1635f@0 {
    		compatible = "jedec,spi-nor";
    		reg = <0>;
    		spi-max-frequency = <8000000>;
            jedec-id = [c2 28 15];
            /* 
    		sfdp-bfp = [
    			e5 20 f1 ff  ff ff ff 03  44 eb 08 6b  08 3b 04 bb
    			ee ff ff ff  ff ff 00 ff  ff ff 00 ff  0c 20 0f 52
    			10 d8 00 ff  23 72 f5 00  82 ed 04 cc  44 83 68 44
    			30 b0 30 b0  f7 c4 d5 5c  00 be 29 ff  f0 d0 ff ff
    		];*/
            size = <DT_SIZE_M(16)>;
    		has-dpd;
    		t-enter-dpd = <10000>;
    		t-exit-dpd = <35000>;
    	};
    };
    
     &mx25r16 {
    	status = "okay";
        partitions {
            compatible = "fixed-partitions";
            #address-cells = <1>;
            #size-cells = <1>;
    
            lfs1_partition: partition@0 {
                label = "lfs1";
                reg = <0x00000000 0x200000>;
            };
        };
    };
    

    my code : 

    static struct fs_littlefs lfs_data_ram;
    static struct fs_mount_t lfs_ram_mnt = {
        .type = FS_LITTLEFS,
        .mnt_point = "/lfs/ram",
        .fs_data = &lfs_data_ram,
        .storage_dev = "RAM",
    };
    
    static struct fs_mount_t *mountpoint = &lfs_ram_mnt;
    
    int int_ram_fs_init(void) {
    	int rc = 1;
    
    	struct fs_statvfs sbuf;
    
        LOG_INF("Mounting LittleFS on RAM...");
    	
    	disk_access_init("RAM");
    
        if (DISK_STATUS_OK != disk_access_status("RAM")) {
            LOG_PRINTK("RAM disk not ready");
        } else {
    		LOG_PRINTK("RAM disk is ready");
    	}
    
        LOG_PRINTK("####################################\n");
        LOG_PRINTK("Mount LITTLEFS on internal ram ...\n");
    
        //ramdisk_fs.lfs.cfg = &ramdisk_lfs_config;
    	
    	/*
    	 * Mount and erase if necessary
    	 */
    	rc = littlefs_mount(mountpoint);
    	if (rc < 0) {
    		littlefs_flash_erase((uintptr_t)mountpoint->storage_dev);		
    		rc = littlefs_mount(mountpoint);
    	}
    	
    	return rc
    }

    The output : 

    I: Mounting LittleFS on RAM...
    RAM disk is ready
    ####################################
    Mount LITTLEFS on internal ram ...
    I: LittleFS version 2.9, disk version 2.1
    E: can't open flash area 329300
    E: fs mount error (-19)
    FAIL: mount id 329300 at /lfs/ram: -19
    E: FAIL: unable to find flash area 329300: -2

Related