/* * Copyright (C) 2012 by Ole Reinhardt (ole.reinhardt@embedded-it.de) * * All rights reserved. * * 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 of the copyright holders nor the names of * 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. * * For additional information see http://www.ethernut.de/ * * * Parts taken from lpc177x_8x_eeprom.c 2011-06-02 * file lpc177x_8x_eeprom.c * brief Contains all functions support for EEPROM firmware library on * on LPC177x_8x * version 1.0 * date 02. June. 2011 * author NXP MCU SW Application Team * * Copyright(C) 2011, NXP Semiconductor * All rights reserved. * *********************************************************************** * Software that is described herein is for illustrative purposes only * which provides customers with programming information regarding the * products. This software is supplied "AS IS" without any warranties. * NXP Semiconductors assumes no responsibility or liability for the * use of the software, conveys no license or title under any patent, * copyright, or mask work right to the product. NXP Semiconductors * reserves the right to make changes in the software without * notification. NXP Semiconductors also make no representation or * warranty that such application will be suitable for the specified * use without further testing or modification. **********************************************************************/ #include #include #include #if defined(MCU_LPC177x_8x) #include #include #elif defined(MCU_LPC407x_8x) #include #include #else #warning "Unknown LPC familiy" #endif #include static uint8_t eeprom_init = 0; /*! * \brief Initialize EEPROM * * Initialize the eeprom memeory. Therefore enable power and setup clocks * * \param none * \return none */ void Lpc177x_8x_EepromInit(void) { uint32_t cpu_clock; uint32_t clk_div; uint32_t waitstates; if (eeprom_init) { return; } /* EEPROM is automate turn on after reset */ LPC_EEPROM->PWRDWN = 0x0; /* Clocks have to be set: * EEPROM requires a 375kHz. This clock is generated by dividing the * system bus clock. */ cpu_clock = NutArchClockGet(NUT_HWCLK_CPU); clk_div = (cpu_clock / 375000) - 1; LPC_EEPROM->CLKDIV = clk_div; /* Setting wait state */ waitstates = ((((cpu_clock / 1000000) * 15) / 1000) + 1); waitstates |= (((((cpu_clock / 1000000) * 55) / 1000) + 1) << 8); waitstates |= (((((cpu_clock / 1000000) * 35) / 1000) + 1) << 16); LPC_EEPROM->WSTATE = waitstates; eeprom_init = 1; } /*! * \brief Read data from EEPROM at specific address * * \param address EEPROM address that start to write data, it must be * in range 0..0x1000 * \param buff buffer to place the read data in * \param size number of bytes to be read * * \return none */ int Lpc177x_8x_EepromRead(uint16_t addr, void* buff, size_t size) { uint16_t page_nr; uint16_t page_offs; uint32_t i; uint8_t *pt = (uint8_t*) buff; if (addr + size > EEPROM_SIZE) { return -1; } if (!eeprom_init) { Lpc177x_8x_EepromInit(); } page_offs = addr & EEPROM_PAGE_OFFSET_MASK; page_nr = (addr & EEPROM_PAGE_NUM_MASK) >> 6; LPC_EEPROM->INT_CLR_STATUS = (_BV(EEPROM_ENDOF_RW) | _BV(EEPROM_ENDOF_PROG)); LPC_EEPROM->ADDR = EEPROM_PAGE_ADRESS(page_nr) | EEPROM_PAGE_OFFSET(page_offs); LPC_EEPROM->CMD = EEPROM_CMD_8_BIT_READ | EEPROM_CMD_RDPREFETCH; /* Read and store data in buffer */ for(i = 0; i < size; i++){ /* Check if we read beyond the eeprom size */ if (page_nr >= EEPROM_PAGE_NUM) { /* Clean up interrupt status before exit to prevent an issue when using the IAP (internal flash) right after accessing the EEPROM */ LPC_EEPROM->INT_CLR_STATUS = (_BV(EEPROM_ENDOF_RW) | _BV(EEPROM_ENDOF_PROG)); return -1; } LPC_EEPROM->INT_CLR_STATUS = _BV(EEPROM_ENDOF_RW); *(pt++) = (uint8_t)(LPC_EEPROM->RDATA); page_offs ++; while (!(LPC_EEPROM->INT_STATUS & _BV(EEPROM_ENDOF_RW))); if ((page_offs >= EEPROM_PAGE_SIZE) && (i < size - 1)) { page_offs = 0; page_nr++; LPC_EEPROM->ADDR = EEPROM_PAGE_ADRESS(page_nr) | EEPROM_PAGE_OFFSET(page_offs); LPC_EEPROM->CMD = EEPROM_CMD_8_BIT_READ | EEPROM_CMD_RDPREFETCH; } } /* Clean up interrupt status before exit to prevent an issue when using the IAP (internal flash) right after accessing the EEPROM */ LPC_EEPROM->INT_CLR_STATUS = (_BV(EEPROM_ENDOF_RW) | _BV(EEPROM_ENDOF_PROG)); return 0; } /*! * \brief Write data to EEPROM at specific address * * \param address EEPROM address that start to write data, it must be * in range 0..0x1000 * \param buff buffer that contain data that will be written to buffer * \param size number of bytes to be written * * \return none */ int Lpc177x_8x_EepromWrite(uint16_t addr, const void* buff, size_t size) { uint16_t page_nr; uint16_t page_offs; uint32_t i; uint8_t *pt = (uint8_t*) buff; if (addr + size > EEPROM_SIZE) { return -1; } if (!eeprom_init) { Lpc177x_8x_EepromInit(); } page_offs = addr & EEPROM_PAGE_OFFSET_MASK; page_nr = (addr & EEPROM_PAGE_NUM_MASK) >> 6; LPC_EEPROM->INT_CLR_STATUS = (_BV(EEPROM_ENDOF_RW) | _BV(EEPROM_ENDOF_PROG)); LPC_EEPROM->ADDR = EEPROM_PAGE_ADRESS(page_nr) | EEPROM_PAGE_OFFSET(page_offs); LPC_EEPROM->INT_CLR_STATUS = _BV(EEPROM_ENDOF_RW); for(i = 0; i < size; i++) { /* Update data to page register */ LPC_EEPROM->CMD = EEPROM_CMD_8_BIT_WRITE; LPC_EEPROM->WDATA = *(pt++); page_offs ++; if ((page_offs >= EEPROM_PAGE_SIZE) | (i == size - 1)) { /* Update to EEPROM memory */ LPC_EEPROM->INT_CLR_STATUS = _BV(EEPROM_ENDOF_PROG); LPC_EEPROM->ADDR = EEPROM_PAGE_ADRESS(page_nr); LPC_EEPROM->CMD = EEPROM_CMD_ERASE_PRG_PAGE; while (!(LPC_EEPROM->INT_STATUS & _BV(EEPROM_ENDOF_PROG))); } if (page_offs >= EEPROM_PAGE_SIZE) { page_offs = 0; page_nr ++; LPC_EEPROM->ADDR =0; if(page_nr >= EEPROM_PAGE_NUM) { page_nr = 0; } } } /* Clean up interrupt status before exit to prevent an issue when using the IAP (internal flash) right after accessing the EEPROM */ LPC_EEPROM->INT_CLR_STATUS = (_BV(EEPROM_ENDOF_RW) | _BV(EEPROM_ENDOF_PROG)); return 0; }