arch/arm/src/lpc17xx: This commit adds a configurable option to allow using a part of LPC17xx's internal flash memory as a Memory Technology Device via NuttX' mtd_progmem infrastructure. Tested with LPC1769.

This commit is contained in:
Michael Jung 2018-05-01 14:49:16 -06:00 committed by Gregory Nutt
parent 63f988b404
commit 01ee9b3abc
4 changed files with 584 additions and 0 deletions

View File

@ -352,6 +352,14 @@ config LPC17_EEPROM
default n
depends on ARCH_FAMILY_LPC177X || ARCH_FAMILY_LPC178X
config LPC17_PROGMEM
bool PROGMEM
default n
select ARCH_HAVE_PROGMEM
---help---
Use a part of LPC17xx's internal flash memory as a
Memory-Technology-Device (MTD).
endmenu
menu "External Memory Configuration"
@ -1006,3 +1014,18 @@ config LPC17_USBHOST_REGDEBUG
also CONFIG_DEBUG_USB_INFO.
endmenu
menu "Memory-Technolgy-Device Options (PROGMEM)"
depends on LPC17_PROGMEM
config LPC17_PROGMEM_NSECTORS
int "Size in 32 kB sectors"
default 2
---help---
Number of 32 kB sectors to use as an MTD-device. This driver
will allocate the last n sectors. Only 32 kB sectors are
supported, so this works only on devices with 128 kB, 256 kB and
512 kB of flash. The maximum number of sectors for these
devices is 2, 6 and 14, respectively. Default is 2.
endmenu

View File

@ -184,3 +184,7 @@ endif
ifeq ($(CONFIG_LPC17_TMR0),y)
CHIP_CSRCS += lpc17_timer.c
endif
ifeq ($(CONFIG_MTD_PROGMEM),y)
CHIP_CSRCS += lpc17_progmem.c
endif

View File

@ -0,0 +1,418 @@
/******************************************************************************
* arch/arm/src/lpc17xx/lpc17_progmem.c
*
* Copyright (C) 2018 Michael Jung. All rights reserved.
* Author: Michael Jung <mijung@gmx.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************/
/******************************************************************************
* See NXP UM10360 LPC176x/5x User manual, Rev 4.1, Chapter 32: LPC176x/5x
* Flash memory interface and programming.
******************************************************************************/
/******************************************************************************
* Included Files
******************************************************************************/
#include <nuttx/config.h>
#include <errno.h>
#include <stdint.h>
#include <debug.h>
#include <assert.h>
#include <arch/board/board.h>
#include <nuttx/progmem.h>
#include <nuttx/irq.h>
#include "lpc17_progmem.h"
/******************************************************************************
* Private Function Prototypes
******************************************************************************/
static void lpc17_iap(void *in, void *out);
static uint32_t lpc17_iap_prepare_sector_for_write_operation(uint32_t sector);
static uint32_t lpc17_iap_erase_sector(uint32_t sector);
static uint32_t lpc17_iap_copy_ram_to_flash(void *flash, const void *ram,
size_t count);
/******************************************************************************
* Private Functions
******************************************************************************/
/******************************************************************************
* Name: lpc17_iap
*
* Description (from UM10360):
* For in-application programming the IAP routine should be called with a word
* pointer in register r0 pointing to memory (RAM) containing command code and
* parameters. The result from the IAP command is returned in the table
* pointed to by register r1. The user can reuse the command table for the
* result by passing the same pointer in registers r0 and r1.
*
******************************************************************************/
static void lpc17_iap(FAR void *in, FAR void *out)
{
irqstate_t flags;
flags = enter_critical_section();
((void (*)(FAR void *, FAR void *))LPC17_IAP_ENTRY_ADDR)(in, out);
leave_critical_section(flags);
}
/******************************************************************************
* Name: lpc17_iap_prepare_sector_for_write_operation
*
* Description (from UM10360):
* This command must be executed before executing "Copy RAM to Flash" or
* "Erase Sector(s)" command. Successful execution of the "Copy RAM to Flash"
* or "Erase Sector(s)" command causes relevant sectors to be protected again.
* To prepare a single sector use the same "Start" and "End" sector numbers.
*
******************************************************************************/
static uint32_t lpc17_iap_prepare_sector_for_write_operation(uint32_t sector)
{
uint32_t inout[3];
inout[0] = LPC17_IAP_CMD_PREPARE_SECTORS_FOR_WRITE_OPERATION;
inout[1] = sector;
inout[2] = sector;
lpc17_iap(inout, inout);
return inout[0];
}
/******************************************************************************
* Name: lpc17_iap_erase_sector
*
* Description (from UM10360):
* This command is used to erase a sector or multiple sectors of on-chip flash
* memory. To erase a single sector use the same "Start" and "End" sector
* numbers.
*
******************************************************************************/
static uint32_t lpc17_iap_erase_sector(uint32_t sector)
{
uint32_t inout[4];
inout[0] = LPC17_IAP_CMD_ERASE_SECTORS;
inout[1] = sector;
inout[2] = sector;
inout[3] = LPC17_CCLK / 1000;
lpc17_iap(inout, inout);
return inout[0];
}
/******************************************************************************
* Name: lpc17_iap_copy_ram_to_flash
*
* Description (from UM10360):
* This command is used to program the flash memory. The affected sectors
* should be prepared first by calling "Prepare Sector for Write Operation"
* command. The affected sectors are automatically protected again once the
* copy command is successfully executed.
*
******************************************************************************/
static uint32_t lpc17_iap_copy_ram_to_flash(void *flash, const void *ram,
size_t count)
{
uint32_t inout[5];
inout[0] = LPC17_IAP_CMD_COPY_RAM_TO_FLASH;
inout[1] = (uint32_t)flash;
inout[2] = (uint32_t)ram;
inout[3] = (uint32_t)count;
inout[4] = LPC17_CCLK / 1000;
lpc17_iap(inout, inout);
return inout[0];
}
/******************************************************************************
* Public Functions
******************************************************************************/
/******************************************************************************
* Name: up_progmem_npages
*
* Description:
* Return number of erase pages
*
******************************************************************************/
size_t up_progmem_npages(void)
{
return CONFIG_LPC17_PROGMEM_NSECTORS;
}
/******************************************************************************
* Name: up_progmem_isuniform
*
* Description:
* Is program memory uniform or page size differs?
*
******************************************************************************/
bool up_progmem_isuniform(void)
{
return true;
}
/******************************************************************************
* Name: up_progmem_pagesize
*
* Description:
* Return read/write page size
*
******************************************************************************/
size_t up_progmem_pagesize(size_t page)
{
return (size_t)LPC17_PROGMEM_PAGE_SIZE;
}
/******************************************************************************
* Name: up_progmem_erasesize
*
* Description:
* Return erase page size
*
******************************************************************************/
size_t up_progmem_erasesize(size_t page)
{
return (size_t)LPC17_PROGMEM_SECTOR_SIZE;
}
/******************************************************************************
* Name: up_progmem_getpage
*
* Description:
* Address to read/write page conversion
*
* Input Parameters:
* addr - Address with or without flash offset (absolute or aligned to page0)
*
* Returned Value:
* Page or negative value on error. The following errors are reported
* (errno is not set!):
*
* -EFAULT: On invalid address
*
******************************************************************************/
ssize_t up_progmem_getpage(size_t addr)
{
if (addr >= LPC17_PROGMEM_START_ADDR)
{
addr -= LPC17_PROGMEM_START_ADDR;
}
return (size_t)(addr / LPC17_PROGMEM_PAGE_SIZE);
}
/******************************************************************************
* Name: up_progmem_getaddress
*
* Description:
* Read/write page to address conversion
*
* Input Parameters:
* page - page index
*
* Returned Value:
* Base address of given page, SIZE_MAX if page index is not valid.
*
******************************************************************************/
size_t up_progmem_getaddress(size_t page)
{
return (size_t)(LPC17_PROGMEM_START_ADDR + page * LPC17_PROGMEM_PAGE_SIZE);
}
/******************************************************************************
* Name: up_progmem_erasepage
*
* Description:
* Erase selected page.
*
* Input Parameters:
* page - The erase page index to be erased.
*
* Returned Value:
* Page size or negative value on error. The following errors are reported
* (errno is not set!):
*
* -EFAULT: On invalid page
* -EIO: On unsuccessful erase
* -EROFS: On access to write protected area
* -EACCES: Insufficient permissions (read/write protected)
* -EPERM: If operation is not permitted due to some other constraints
* (i.e. some internal block is not running etc.)
*
******************************************************************************/
ssize_t up_progmem_erasepage(size_t page)
{
uint32_t rc;
if (page >= CONFIG_LPC17_PROGMEM_NSECTORS)
{
return -EFAULT;
}
rc = lpc17_iap_prepare_sector_for_write_operation((uint32_t)page +
LPC17_PROGMEM_START_SECTOR);
if (rc != LPC17_IAP_RC_CMD_SUCCESS)
{
return -EIO;
}
rc = lpc17_iap_erase_sector((uint32_t)page + LPC17_PROGMEM_START_SECTOR);
if (rc != LPC17_IAP_RC_CMD_SUCCESS)
{
return -EIO;
}
return (ssize_t)LPC17_PROGMEM_SECTOR_SIZE;
}
/******************************************************************************
* Name: up_progmem_ispageerased
*
* Description:
* Checks whether page is erased
*
* Input Parameters:
* page - The erase page index to be checked.
*
* Returned Value:
* Returns number of bytes NOT erased or negative value on error. If it
* returns zero then complete page is erased.
*
* The following errors are reported:
* -EFAULT: On invalid page
*
******************************************************************************/
ssize_t up_progmem_ispageerased(size_t page)
{
const uint8_t *p;
int i;
if (page >= CONFIG_LPC17_PROGMEM_NSECTORS)
{
return -EFAULT;
}
p = (const uint8_t *)up_progmem_getaddress(page);
for (i = 0; i < LPC17_PROGMEM_SECTOR_SIZE; i++)
{
if (p[i] != 0xffu)
{
break;
}
}
return (ssize_t)(LPC17_PROGMEM_SECTOR_SIZE - i);
}
/******************************************************************************
* Name: up_progmem_write
*
* Description:
* Program data at given address
*
* Note: this function is not limited to single page and nor it requires
* the address be aligned inside the page boundaries.
*
* Input Parameters:
* addr - Address with or without flash offset (absolute or aligned to page0)
* buf - Pointer to buffer
* count - Number of bytes to write
*
* Returned Value:
* Bytes written or negative value on error. The following errors are
* reported (errno is not set!)
*
* EINVAL: If count is not aligned with the flash boundaries (i.e.
* some MCU's require per half-word or even word access)
* EFAULT: On invalid address
* EIO: On unsuccessful write
* EROFS: On access to write protected area
* EACCES: Insufficient permissions (read/write protected)
* EPERM: If operation is not permitted due to some other constraints
* (i.e. some internal block is not running etc.)
*
******************************************************************************/
ssize_t up_progmem_write(size_t addr, FAR const void *buf, size_t count)
{
size_t page;
uint32_t rc;
if (count % LPC17_PROGMEM_PAGE_SIZE)
{
return -EINVAL;
}
page = up_progmem_getpage(addr) / LPC17_PROGMEM_PAGES_PER_SECTOR +
LPC17_PROGMEM_START_SECTOR;
rc = lpc17_iap_prepare_sector_for_write_operation((uint32_t)page);
if (rc != LPC17_IAP_RC_CMD_SUCCESS)
{
return -EIO;
}
rc = lpc17_iap_copy_ram_to_flash((void *)addr, buf, count);
if (rc != LPC17_IAP_RC_CMD_SUCCESS)
{
return -EIO;
}
return count;
}

View File

@ -0,0 +1,139 @@
/******************************************************************************
* arch/arm/src/lpc17xx/lpc17_progmem.c
*
* Copyright (C) 2018 Michael Jung. All rights reserved.
* Author: Michael Jung <mijung@gmx.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************/
#ifndef __ARCH_ARM_SRC_LPC17XX_LPC17_PROGMEM_H
#define __ARCH_ARM_SRC_LPC17XX_LPC17_PROGMEM_H
/******************************************************************************
* See NXP UM10360 LPC176x/5x User manual, Rev 4.1, Chapter 32: LPC176x/5x
* Flash memory interface and programming.
*
* The first 16 flash sectors (aka erase blocks) are 4kB in size, followed by
* up to 14 sectors of 32 kB. This progmem driver supports just 32 kB sectors.
*
* Flash write access is provided by an "In Application Programming" service
* function stored in boot loader firmware. Individual write accesses must be
* 256 byte in size and must be aligned to a 256 byte boundary.
*
******************************************************************************/
/******************************************************************************
* Included Files
******************************************************************************/
#include <nuttx/config.h>
/******************************************************************************
* Pre-processor Definitions
******************************************************************************/
/* The first 16 sectors are 4kB in size and thus not supported as progmem. */
#define LPC17_FLASH_NUM_4K_SECTORS 16
/* The number of 32kB sectors depends on the target device's flash size */
#define LPC17_FLASH_NUM_32K_SECTORS \
((LPC17_FLASH_SIZE - LPC17_FLASH_NUM_4K_SECTORS * 4096) / 32768)
/* The number of 32kB sectors to be used for progmem is configurable. The
* sectors at the end of the flash are used for progmem, the rest is left
* for code and data. */
#define LPC17_PROGMEM_START_SECTOR \
(LPC17_FLASH_NUM_4K_SECTORS + LPC17_FLASH_NUM_32K_SECTORS - \
CONFIG_LPC17_PROGMEM_NSECTORS)
/* Base address of the flash segment used for progmem. */
#define LPC17_PROGMEM_START_ADDR \
(LPC17_FLASH_NUM_4K_SECTORS * 4096 + \
(LPC17_PROGMEM_START_SECTOR - LPC17_FLASH_NUM_4K_SECTORS) * 32768)
/* Size of the flash segment used for progmem. */
#define LPC17_PROGMEM_SIZE (CONFIG_LPC17_PROGMEM_NSECTORS * 32768)
/* Size of a read/write page. */
#define LPC17_PROGMEM_PAGE_SIZE 256
/* Total number of read/write pages. */
#define LPC17_PROGMEM_NUM_PAGES (LPC17_PROGMEM_SIZE / LPC17_PROGMEM_PAGE_SIZE)
/* Size of an erase page. This driver only supports the 32kB sectors. */
#define LPC17_PROGMEM_SECTOR_SIZE 32768
/* Number of read/write pages per erase page. */
#define LPC17_PROGMEM_PAGES_PER_SECTOR \
(LPC17_PROGMEM_SECTOR_SIZE / LPC17_PROGMEM_PAGE_SIZE)
/* LPC17 entry point for In-Application-Programming boot rom service function */
#define LPC17_IAP_ENTRY_ADDR 0x1fff1ff1
/* The IAP Commands required for progmem */
#define LPC17_IAP_CMD_PREPARE_SECTORS_FOR_WRITE_OPERATION 50
#define LPC17_IAP_CMD_COPY_RAM_TO_FLASH 51
#define LPC17_IAP_CMD_ERASE_SECTORS 52
/* IAP return codes */
#define LPC17_IAP_RC_CMD_SUCCESS 0
#define LPC17_IAP_RC_INVALID_CMD 1
#define LPC17_IAP_RC_SCR_ADDR_ERROR 2
#define LPC17_IAP_RC_DST_ADDR_ERROR 3
#define LPC17_IAP_RC_SRC_ADDR_NOT_MAPPED 4
#define LPC17_IAP_RC_DST_ADDR_NOT_MAPPED 5
#define LPC17_IAP_RC_COUNT_ERROR 6
#define LPC17_IAP_RC_INVALID_SECTOR 7
#define LPC17_IAP_RC_SECTOR_NOT_BLANK 8
#define LPC17_IAP_RC_SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION 9
#define LPC17_IAP_RC_COMPARE_ERROR 10
#define LPC17_IAP_RC_BUSY 11
#define LPC17_IAP_RC_PARAM_ERROR 12
#define LPC17_IAP_RC_ADDR_ERROR 13
#define LPC17_IAP_RC_ADDR_NOT_MAPPED 14
#define LPC17_IAP_RC_CMD_LOCKED 15
#define LPC17_IAP_RC_INVALID_CODE 16
#define LPC17_IAP_RC_INVALID_BAUD_RATE 17
#define LPC17_IAP_RC_INVALID_STOP_BIT 18
#define LPC17_IAP_RC_CODE_READ_PROTECTION_ENABLED 19
#endif /* __ARCH_ARM_SRC_LPC17XX_LPC17_PROGMEM_H */