LPCOpen v1.03 OTP Programming with LPC4350

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LPCOpen v1.03 OTP Programming with LPC4350

1,329 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by gregd on Tue Oct 29 06:36:49 MST 2013
Hello,

I am trying to program the MAC address into the LPC4350.  I am trying to use OTP Bank 3, word 2.  I have Vpp connected to VDDIO and VDDREG at 3.3V.  I am using LPCOpen v1.03.  I am running FreeRTOS so I am suspending all tasks just in case.  Here is the code I am using:

static void OTP_fix(volatile uint32_t dummy0, volatile uint32_t dummy1,
        volatile uint32_t dummy2, volatile uint32_t dummy3)
{
    return;
}

void program_mac_address( uint32_t last_three_of_mac ) {
            vTaskSuspendAll();      // suspend all tasks while doing hardware test.
           
            /* Initialize the OTP Controller */
            status = Chip_OTP_Init();
           
            /* Fix as per Errata, required for some LPC43xx parts */
            OTP_fix(0, 0, 0, 0);
           
            status = Chip_OTP_ProgGPWord( 1, last_three_of_mac, last_three_of_mac);
           
            xTaskResumeAll();       // resume all tasks.
}

The status result from Chip_OTP_Init is always 0 (LPC_OK).

The problem is that I always get a status result of 0x60004 from Chip_OTP_ProgGPWord.  I can't find the meaning of this error code in any documentation.  The values in the OTP never change.

I am referring to documentation in AN11292 AN11292 Rev. 1

The user manual says to refer to general error codes but I can't find any that are listed in the manual.

Also, the documentation very unclear and inconsistent as to which function calls actually program OTP bank 3 word 1,2&3.  Is my code above correct for OTP bank 3 word 2 (Also referred to as "General purpose OTP memory 2, word 1).

Any ideas on how to resolve the problem would be greatly appreciated.

Thanks,
Greg Dunn
Labels (1)
0 Kudos
16 Replies

1,058 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by martie on Wed Jul 30 08:40:21 MST 2014
When I first tried opt_ProgGP0, I passed the addresses of 2 4 word arrays thinking it would write to general purpose bank 0 like you said, but, to my surprise, what it actually did was write the mask of the 2 addresses into 0x40045034.  I realized at that point that it did not expect addresses and experimented with different values passed using opt_ProgGP0, ProgGP1 and ProgGP3 and found I had perfect control of what wrote to the 2nd, 3rd and 4th  words of general purpose bank 2.

So I still have the question of how to write to general purpose banks 0 and 1.

My part is the LPC4337.

Thanks,

Martie
0 Kudos

1,059 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by rmilne on Tue Jul 29 10:19:13 MST 2014
To repeat myself... 
Section 4.3 of UM10503 states that I can use banks 1 & 2 for general-purpose data in the non-secure parts.  The table in section 4.1 states that there is no way for me to program these areas and the otp driver code inside lpcopen seems to support that.  From my experiments I've concluded that banks 1 & 2 are not programmable on the LPC4330 despite what section 4.3 says.  This is very disappointing because I had hoped to use this area for storing a 128-bit key for my AES firmware (safe from prying eyes after the jtag bit is set).  It looks like I will have to compromise my design since bank 3 has only 96 bits available for general purpose use. 
0 Kudos

1,058 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lpcxpresso-support on Tue Jul 29 08:37:55 MST 2014

Quote: martie
Now that I've tried it, I've found that Data and Mask are not expected to be pointers to arrays after all.  Instead, the API functions only wrote to the last bank.  Otp_ProgGP0() wrote to 0x40045034, Otp_ProgGP1 wrote to 0x40045038 and Otp_ProgGP2 wrote to 0x4004503C.  So my question now is, how do I write to the first 2 general purpose banks (lines 0x40045010 and 0x40045020)?  Fortunately, I went to an old, partially working board for this test.



To take a step back, OTP memory locations are considered as 4 banks of 4 words, numbered as banks 0 to 3.

The functions to write to banks 0 to 2 are:

bank 0 - Otp_ProgGP0 (&array_Data[0], &array_Mask2[0])
bank 1 - Otp_ProgGP1 (&array_Data[0], &array_Mask2[0])
bank 2 - Otp_ProgGP2 (&array_Data[0], &array_Mask2[0])

These functions take 2 pointers as parameters, the first pointer points to a block of 4 words of data, the second to a 4 word mask.

However, the above functions are not supported on all18xx/43xx parts/revisions - in particular not on flashless parts i.e. parts ending with a "0".

Bank 3 is written via 4 functions:

0x30 or word 0 - Otp_ProgBootSrc and OtpProgJTAGDis
0x34 or word 1 - Otp_ProgGP2_0 or Otp_ProgUSBID
0x38 or word 2 - Otp_ProgGP2_1
0x34 or word 3 - Otp_ProgGP2_2

UM43xx 10503 describes the table of pointers into the OTP ROM functions as:

otp_Init
otp_ProgBootSrc
otp_ProgJTAGDis
otp_ProgUSBID
Reserved
otp_ProgGP0
otp_ProgGP1
otp_ProgGP2
otp_ProgGP2_0
otp_ProgGP2_1
otp_ProgGP2_2
Reserved
Reserved
otp_GenRand

Within this thread there seems to have been confusion between the functions otp_ProgGP<n> and otp_ProgGP2_<n> (where n=0, 1 or 2), both in their naming and their location in the OTP jump table. I hope this clarifies the scheme.

Finally, with respect to writing to banks 0-2 of OTP memory, I would suggest checking the reference manual and any errata to see if these functions are available for the silicon version you are using.

0 Kudos

1,058 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by rmilne on Tue Jul 29 07:15:34 MST 2014
I have the exact same question for my LPC4330 part. 

UM10503 section 4.3 states "In non-secure parts, OTP banks 1 and 2 are available for general-purpose data." however table 12 indicates that otp_ProgGP0, otp_ProgGP1 and otp_ProgGP2 ROM functions are not available for "Flashless parts LPC4350/30/20/10".  The table seems truer than the text in 4.3 because I have been unable to program banks 1 or 2 (no problem with bank 3).  The otp source code in lpc_core (otp_18xx_43xx.c) contains no access to the ROM driver funcs at index 5-7 so again table 12 seems to be true (I tried inserting my own funcs at these locations but this caused a hard fault).  otp_18xx_43xx.c offers two driver functions at index 11 and 12 that seem to be intended for programming the two AES key areas but these both fail in my testing which is no surprise since these are listed as reserved in figure 12 of UM10503 (the return val is 0x00030002 - ERR_SEC_AES_NOT_SUPPORTED).  The revision marking on the chip is xxx1251xCx.

Anyway - has anybody found a way to program the bytes between 0x4004500F and 0x40045030 on the flashless, non-secure parts?
0 Kudos

1,059 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by martie on Fri Jul 25 14:13:36 MST 2014
Now that I've tried it, I've found that Data and Mask are not expected to be pointers to arrays after all.  Instead, the API functions only wrote to the last bank.  Otp_ProgGP0() wrote to 0x40045034, Otp_ProgGP1 wrote to 0x40045038 and Otp_ProgGP2 wrote to 0x4004503C.  So my question now is, how do I write to the first 2 general purpose banks (lines 0x40045010 and 0x40045020)?  Fortunately, I went to an old, partially working board for this test.
0 Kudos

1,059 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by martie on Thu Jul 24 06:30:17 MST 2014
Thank you whitecoe!  That makes sense.

It would have helped if the documentation said so or, at least, declared the parameters to be pointers.  I'll go ahead and try it.

Martie
0 Kudos

1,059 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by whitecoe on Thu Jul 24 06:00:48 MST 2014
It's a while since I played with this, but IIRC Otp_ProgGP0/1/2 take pointers to 2 x 4 word blocks. The first block is the data  and the second is the masks - to write a single bit you would use:

Otp_ProgGP1 &block1 &block2

block1=0x00000000 0x00000000 0x00000000 0x00000001
block2=0x00000000 0x00000000 0x00000000 0x00000001

so - to program bank3 word 2 you would call:

otp_ProgGP2 &block1 &block2

where:

block1 = 0x00000000 0x00000000 data 0x00000000
block2=  0x00000000 0x00000000 mask_to_let_the_bits_through 0x00000000

HTH!
0 Kudos

1,059 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by martie on Wed Jul 23 13:07:28 MST 2014
Hello,

I am trying to be able to write to the general purpose OTP banks on an LPC43XX.  Looking at the documentation, I am confused about how to select which 32-bit word in a bank you wish to write to since the Data and Mask parameters are listed as uint32_t.  Are they really pointers to 4 32-bit words? 

I've searched around and gregd's example is the only one I can find.  He says he wants to write to OTP Bank 3, word 2, but passes a 1 for WordNum in Chip_OTP_ProgGPWord() causes a call to Otp_ProgGP1(), so I cannot imagine how this writes to Bank 3, word 2.

Normally, I would just experiment, but with OTP being permanent and a neighboring bank holding config data which could brick my unit, I want to be pretty sure I know what I'm doing before I start trying to program it.

Martie
0 Kudos

1,059 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by gregd on Tue Nov 05 13:06:57 MST 2013
I was finally able to figure out my problem with the OTP programming.  I had the following structure allocated to allow me to read back the value programmed into the OTP:

LPC_OTP_T LPC_OTP @ 0x40045000;

If found that I actually needed to define it like this:

__no_init LPC_OTP_T LPC_OTP @ 0x40045000;

The IAR initialization code was trying to fill the structure memory with zeros on startup.  This wrote values to the OTP controller which later caused the program attempt to fail.  Once I added the __no_init to the declaration things started working correctly.

As mentioned in the previous comment, The LPCOpen code was using incorrect index's to initialize the function call pointers starting with the Otp_ProgGP0() function.  This index should be 8 at this point to take care of the 4 reserved locations.  I modified the LPCOpen code in "otp_18xx_43xx.c" as follows:

/* CHIP OTP Initialisation function */
uint32_t Chip_OTP_Init(void)
{
                uint32_t (*ROM_otp_Init)(void);

                BOOTROM_API_TABLE = *((unsigned long * *) BOOTROM_BASE + OTP_API_TABLE_OFFSET);

                ROM_otp_Init      = (uint32_t (*)(void))BOOTROM_API_TABLE[0];
                Otp_ProgBootSrc   = (uint32_t (*)(CHIP_OTP_BOOT_SRC_T BootSrc))BOOTROM_API_TABLE[1];
                Otp_ProgJTAGDis   = (uint32_t (*)(void))BOOTROM_API_TABLE[2];
                Otp_ProgUSBID     = (uint32_t (*)(uint32_t ProductID, uint32_t VendorID))BOOTROM_API_TABLE[3];
                Otp_ProgGP0       = (uint32_t (*)(uint32_t Data, uint32_t Mask))BOOTROM_API_TABLE[8];
                Otp_ProgGP1       = (uint32_t (*)(uint32_t Data, uint32_t Mask))BOOTROM_API_TABLE[9];
                Otp_ProgGP2       = (uint32_t (*)(uint32_t Data, uint32_t Mask))BOOTROM_API_TABLE[10];
                Otp_ProgKey1      = (uint32_t (*)(uint8_t *key))BOOTROM_API_TABLE[11];
                Otp_ProgKey2      = (uint32_t (*)(uint8_t *key))BOOTROM_API_TABLE[12];
                Otp_GenRand       = (uint32_t (*)(void))BOOTROM_API_TABLE[13];

                return ROM_otp_Init();
}

Thanks again for everyone's help with solving this issue.

Greg Dunn
0 Kudos

1,059 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by gregd on Fri Nov 01 08:09:00 MST 2013
That is a good point Stephen.  I had noticed that the address assigned to the Otp_ProgGP0 function was 0x0 with the standard version of the code from lpcopen v1.03.  I guess it was assigning to on of the reserved addresses which was apparently 0,

I updated the index's in the Chip_OTP_Init function as you suggested but still get the same error code.  I had tried calling Otp_ProgGP0, 1, & 2 previously with the same results so I was not sure that this would fix my problem but it was worth a shot.  I never have been able to change the value in any of the OPT items.

I have looked at the Vpp voltage during programming attempts and I never see any dips on the scope.  I don't see any movement at all.  I wonder if it even attempts to program since the error code returned is ERR_OTP_WRITE_ACCESS_LOCKED.  It seems like it is probably existing out of the Otp_ProgGP1 function before it even trys to program.  I have asked what conditions generate this error but have not gotten any response yet.

Thanks for the information!

Greg Dunn
0 Kudos

1,059 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by sp on Fri Nov 01 02:52:05 MST 2013
I went through the process of getting the OTP to work on the LPC4330 recently (for a u-boot "fuse driver).

I used the OTP code at http://docs.lpcware.com/lpcopen/v1.03/otp__18xx__43xx_8c_source.html as a guide, but I don't think its right.

BOOTROM_API_TABLE = *((unsigned long * *) BOOTROM_BASE + OTP_API_TABLE_OFFSET);
 
ROM_otp_Init      = (uint32_t (*)(void))BOOTROM_API_TABLE[0];
Otp_ProgBootSrc   = (uint32_t (*)(CHIP_OTP_BOOT_SRC_T BootSrc))BOOTROM_API_TABLE[1];
Otp_ProgJTAGDis   = (uint32_t (*)(void))BOOTROM_API_TABLE[2];
Otp_ProgUSBID     = (uint32_t (*)(uint32_t ProductID, uint32_t VendorID))BOOTROM_API_TABLE[3];
Otp_ProgGP0       = (uint32_t (*)(uint32_t Data, uint32_t Mask))BOOTROM_API_TABLE[7];
Otp_ProgGP1       = (uint32_t (*)(uint32_t Data, uint32_t Mask))BOOTROM_API_TABLE[8];
Otp_ProgGP2       = (uint32_t (*)(uint32_t Data, uint32_t Mask))BOOTROM_API_TABLE[9];
Otp_ProgKey1      = (uint32_t (*)(uint8_t *key))BOOTROM_API_TABLE[10];
Otp_ProgKey2      = (uint32_t (*)(uint8_t *key))BOOTROM_API_TABLE[11];
Otp_GenRand       = (uint32_t (*)(void))BOOTROM_API_TABLE[12];


If you compare the indices here with the diagram in the data sheet (UM10503, Fig 10. OTP driver pointer structure), you'll see that the diagram shows four reserved slots (not the three in the code), and that otp_ProgGP0 should be at index 8.

My (working) code has:

struct OTP_Driver {
u32 (*init)(void);
u32 (*progbootsrc)(u32 bootsrc);
u32 (*progjtagis)(void);
u32 (*progusbid)(u32 productid, u32 vendorid);
u32 reserved[4];
u32 (*proggp0)(u32 data, u32 mask);
u32 (*proggp1)(u32 data, u32 mask);
u32 (*proggp2)(u32 data, u32 mask);
u32 (*progkey1)(u8 *key);
u32 (*progkey2)(u8 *key);
u32 (*genrand)(void);
};


My standard operating position is not to trust code on the internet (including the lpc open code!) as you don't know if anyone's ever tested it.

Of course, you may have other problems entirely.

Good luck,
stephen
0 Kudos

1,059 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by gregd on Thu Oct 31 20:06:09 MST 2013
I took a look at Vpp on the scope, as close to the LPC4350FET256 as I could get, and could not really see any movement at all when trying to program.  I also tried out a simple example program running from IRAM on our board with no initialization code and got the same results: ERR_OTP_WRITE_ACCESS_LOCKED (0x70004).

I tried running the actual example as you recommended but I will have to do a little extra work as I don't have SPI Flash available right now.  I guess I will pull out some old Hitex LPC4350 boards and give it a try.  I think they have older revision processors though.

Can you tell me exactly what conditions will generate the ERR_OTP_WRITE_ACCESS_LOCKED error code?

Thanks,

Greg
0 Kudos

1,059 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by arw on Thu Oct 31 13:26:31 MST 2013
Greg,

There is a lot going on in your system!  I understand your point about the current not likely a concern, however peripherals consume very little current individually, whereas this one action will draw current through the VPP pin, which is a different route than normal operation.

It would be a good test to run a simple project as in lpcopen, as a test.  But, it is OTP so you only get one succesful attempt per word.

I was able to successfully run the example OTP project in LPCOpen V1.03, using Keil and an MCB4357 board.  (e.g.) C:\nxp\LPCOpen_v1.03\applications\lpc18xx_43xx\examples\misc\app_otp_funcs

Open the "misc" multi-project here (C:\nxp\LPCOpen_v1.03\applications\lpc18xx_43xx\keil_uvision_projects) to be able to build the project.

The MCB4357 includes a flash version of the 4300 family, so the boot ROM is inherently different, though the functionality and documentation is the same.

The API call that I used:
  status = Chip_OTP_ProgGPWord( 1, 0x1234567, 0x1234567);

If you point your debugger's memory viewer at address 0x4004 5000 you will be able to see the OTP contents.
0 Kudos

1,059 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by gregd on Thu Oct 31 12:35:40 MST 2013
I tried removing the OTP_Fix() call and still had the same results.  I am receiving the 0x70004 status result from the call to Chip_OTP_ProgGPWord() which indicates the following error from the app note:  ERR_OTP_WRITE_ACCESS_LOCKED.

I have not specifically checked the Vpp voltage on the scope during the programming attempt but I don't think that would be the problem as we have all the supply's well bypassed.  We are using many of the other peripherals (Ethernet, 4 UARTS, A/D, USB, I2C0, ICC1, etc...) and have not seen any supply issues.  I will check for this however when I am back in the office.  I am working form home this afternoon.

Are there any other register settings that can lock out programming to OTP that may give the indicated error above?

One other thing to note is that the programming code snippet is part of a very large application that is using FreeRTOS on the M4 and works in conjunction with an M0 app using lwip and handling both I2C ports and all four UARTs.  I have a command line interface that runs over Ethernet or the UARTS with allow several commands for production testing etc...  The code to program the MAC address is called from one of these command line commands.  I am suspending all tasks and disabling interrupts when I attempt the programming sequence.  The M0 is still running however and would be accessing the above mentioned peripherals.  Could this be the problem?  I suppose I can try creating a very simple app which runs from IRAM and give it a try but I was hoping to be able to integrate into the production testing command line interface.

Thank you very much for your help!

Greg Dunn
0 Kudos

1,059 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by arw on Thu Oct 31 11:29:00 MST 2013
Hello Greg,

I assume these are the only calls you are making to the OTP API, and you are not programming other keys/IDs defined by the OTP registers, elsewhere.

Per the App Note, the current needed to blow the OTP fuses is taken from the VPP pin on the LPC1800/LPC4300. It can be up to 30 mA for a brief period. During this time, VPP must be kept >= 2.7 V.  Have you monitored VPP for any dip in voltage, corresponding to the 30mA draw on the supply?

Your call to the API looks correct, in order to program the OTP bank3 word2.  I'm checking some other aspects of your question and hope to reply with additional information.
0 Kudos

1,059 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by gregd on Tue Oct 29 09:03:04 MST 2013
For some further information on this subject, I have tested on a more recent production board that has a new revision LPC4350FET256 (9SD12510CY Date Code).

I am still not able to program the OTP bank 3 word 2 value but the status result returned from Chip_OTP_ProgGPWord is now 0x70004 which indicates ERR_OTP_WRITE_ACCESS_LOCKED.

Does anyone know what would cause this?  I have Vpp, VDDIO & VDREG all three tied to 3.3 volts.

Thanks,
Greg Dunn
0 Kudos