NOR Flash Init on LPC1778

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

NOR Flash Init on LPC1778

632 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by arion2001 on Wed Feb 04 02:50:54 MST 2015
Hi,

I am using LPC1778, 12 MHz. I am trying to initialize my Flash on chip select  0 to work even after following all the procedures mentioned in the LPC1778 manual, but to no avail. The compiler I am using is Crossworks Rowley 2.2.
Note: Although the schematic label the NOR Flash as Spansion part, I am using a MACRONIX NOR FLASH as per attached on the spec.
Attached is the image of how my Flash is connected. I am trying to access the Autoselect mode to read out manufacturer id and device id but to no avail.
Below is the code I use to init this guy.


//EMC_OEN Shared
//P2[24]
#define OEN_SEL               LPC_IOCON->P2_24 |= 0x31

//EMC_WEN Shared
//P4[25]
#define WEN_SEL                   LPC_IOCON->P4_25 |= 0x31
//Nor_Flash /CS0 pin4[30]
#define NORFLASH_CS0_SELLPC_IOCON->P4_30 |= 0x31

//Nor_Flash /CS1 pin4[31]
#define NORFLASH_CS1_SELLPC_IOCON->P4_31 |= 0x31

//Nor_Flash RY/BY pin0[4]
//Ready Busy indicates running in progress. At High Z = ready, at Vil = actively erasing/programming
#define NORFLASH_RYBY_SEL      LPC_IOCON->P0_4   |= 0x218 
#define NORFLASH_RYBY_IN       LPC_GPIO4->DIR &= ~(0x10)
#define NORFLASH_RYBY_BIT      LPC_GPIO4->PIN &    0x10

static void pinConfig_EMC(void) {
//Select slew rate and also config for EMC use = 0x31 , with pullup
LPC_IOCON->P3_0 |= 0x31; /* D0 @ P3.0 */
LPC_IOCON->P3_1 |= 0x31; /* D1 @ P3.1 */
LPC_IOCON->P3_2 |= 0x31; /* D2 @ P3.2 */
LPC_IOCON->P3_3 |= 0x31; /* D3 @ P3.3 */

LPC_IOCON->P3_4 |= 0x31; /* D4 @ P3.4 */
LPC_IOCON->P3_5 |= 0x31; /* D5 @ P3.5 */
LPC_IOCON->P3_6 |= 0x31; /* D6 @ P3.6 */
LPC_IOCON->P3_7 |= 0x31; /* D7 @ P3.7 */

LPC_IOCON->P3_8 |= 0x31; /* D8 @ P3.8 */
LPC_IOCON->P3_9 |= 0x31; /* D9 @ P3.9 */
LPC_IOCON->P3_10 |= 0x31; /* D10 @ P3.10 */
LPC_IOCON->P3_11 |= 0x31; /* D11 @ P3.11 */

LPC_IOCON->P3_12 |= 0x31; /* D12 @ P3.12 */
LPC_IOCON->P3_13 |= 0x31; /* D13 @ P3.13 */
LPC_IOCON->P3_14 |= 0x31; /* D14 @ P3.14 */
LPC_IOCON->P3_15 |= 0x31; /* D15 @ P3.15 */ //also  A-1 LSB address input in byte mode

LPC_IOCON->P4_1 |= 0x31; /* A1 @ P4.1 */
LPC_IOCON->P4_2 |= 0x31; /* A2 @ P4.2 */
LPC_IOCON->P4_3 |= 0x31; /* A3 @ P4.3 */

LPC_IOCON->P4_4 |= 0x31; /* A4 @ P4.4 */
LPC_IOCON->P4_5 |= 0x31; /* A5 @ P4.5 */
LPC_IOCON->P4_6 |= 0x31; /* A6 @ P4.6 */
LPC_IOCON->P4_7 |= 0x31; /* A7 @ P4.7 */

LPC_IOCON->P4_8 |= 0x31; /* A8 @ P4.8 */
LPC_IOCON->P4_9 |= 0x31; /* A9 @ P4.9 */
LPC_IOCON->P4_10 |= 0x31; /* A10 @ P4.10 */
LPC_IOCON->P4_11 |= 0x31; /* A11 @ P4.11 */

LPC_IOCON->P4_13 |= 0x31; /* A13 @ P4.13 */
LPC_IOCON->P4_14 |= 0x31; /* A14 @ P4.14 */
LPC_IOCON->P4_15 |= 0x31; /* A15 @ P4.15 */
LPC_IOCON->P4_16 |= 0x31; /* A16 @ P4.16 */

LPC_IOCON->P4_17 |= 0x31; /* A17 @ P4.17 */
LPC_IOCON->P4_18 |= 0x31; /* A18 @ P4.18 */
LPC_IOCON->P4_19 |= 0x31; /* A19 @ P4.19 */
LPC_IOCON->P4_20 |= 0x31; /* A20 @ P4.20 */

LPC_IOCON->P4_21 |= 0x31; /* A21 @ P4.21 */
LPC_IOCON->P4_22 |= 0x31; /* A22 @ P4.22 */
LPC_IOCON->P4_23 |= 0x31; /* A23 @ P4.23 */
LPC_IOCON->P5_0  |= 0x31; /* A24 @ P5.0 */
LPC_IOCON->P5_1  |= 0x31; /* A25 @ P5.1 */

NORFLASH_CS0_SEL;
NORFLASH_CS1_SEL;
NORFLASH_RYBY_SEL;

OEN_SEL;
WEN_SEL;  

}


void NORFLASH_Init(void)
{
  pinConfig_EMC();
  NORFLASH_RYBY_SEL;
  NORFLASH_RYBY_IN; 
  LPC_SC->PCONP = 0x00000800;
  LPC_SC->EMCCLKSEL = 0x00000001;  //divide CPU clock by half
  //LPC_SC->EMCCLKSEL = 0x00000000;
  
  LPC_SC->EMCDLYCTL = 0X0a05;
  LPC_EMC->Config   = 0x00000000;  //little endian
  LPC_EMC->Control  &= ~(BIT2_EN+BIT1_EN+BIT0_EN);  //Turn off EMC first for configuration 
  
  LPC_EMC->StaticConfig0    = 0x81;//16bit,page mode disable,active low CS,byte lane disable,
                                   //extended wait disable,buffer disable, no write protect
  
 
  LPC_EMC->StaticWaitWen0   = 0x00000002;            //WaitWen0+1 Delay from CHip Select to Write Enable
  LPC_EMC->StaticWaitOen0   = 0x00000001;            // Chip Select to output enable or address change whichever is later
  LPC_EMC->StaticWaitRd0    = 0x00000010;            //Chip select to read access
  LPC_EMC->StaticWaitPage0  = 0x0000001F;            //Delay for asynchronous page mode sequential accesses for EMC_CS0.
  LPC_EMC->StaticWaitWr0    = 0x00000010;            // program the delay from the chip select to the write access  
  LPC_EMC->StaticWaitTurn0  = 0x0000000F;            //Number of bus turnaround cycles EMC_CS0.

  LPC_EMC->Control         |= 0x00000001; 
  
}




Below is how I did my autoselect. My question would be is there any way I could verify if my command went in successfully? The manufacturer ID I got was 0000h. Which is incorrect, the correct value should be C2h and the device Id I got were 0xffff which is again not correct. Been at it for sometime but I still unable to figure out what is wrong here.

void Flash_Read(void)
{
  /* Here is an example of Autoselect mode (getting manufacturer ID) */
  /* Define UINT16 example: typedef unsigned short UINT16; */
  //<MemorySegment size="0x70000" access="ReadOnly" start="0x00000000" name="FLASH"/> Internal Flash
  //volatile u_int8_t *bit_shifted_in = <some memory address>;  
  volatile uint32_t *base_addr = 0x80000000;  
  unsigned long manuf_id = 0;  
  unsigned long device_id_1 = 0;
  unsigned long device_id_2 = 0;
  unsigned long device_id_3 = 0;  
  /* Auto Select Entry */  
  *( base_addr + 0x555 ) = 0x00AA; /* write unlock cycle 1 */
  *( base_addr + 0x2AA ) = 0x0055; /* write unlock cycle 2 */       
  *( base_addr + 0x555 ) = 0x0090; /* write autoselect command */    
  /* multiple reads can be performed after entry */  
  manuf_id    = *( base_addr + 0x000 ); /* read manuf. id */ 
  device_id_1 = *( base_addr + 0x001 );
  device_id_2 = *( base_addr + 0x00E ); 
  device_id_3 = *( base_addr + 0x00F ); 
  
  /* Autoselect exit */
  *( (uint16_t *)base_addr + 0x000 ) = 0x00F0; /* exit autoselect (write reset command) */

}

Labels (1)
0 Kudos
4 Replies

542 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by arion2001 on Thu Feb 05 02:28:06 MST 2015
Hi Mike,

Thanks for the tips, take it easy with your work.

I manage to get the CFI portion to work, here is what I did just to share it with you,
1) Change the data type of the address to unsigned short in order to align the address value because if I kept it as unsigned int, it will have the double shifting phenomenon.

2) Power cycle the flash memory...I think this one may be one of the important steps that many have overlooked, to ensure that it is not stuck in unknown mode when trying to play with it.

3) Check the pin mapping(triple, quadruple check). Thanks for pointing it out on this.

4) Check base address, this one seems to remain at 0x80000000 despite of CPU A1 is mapped as  memory A0. I was worried this one was incorrect.

5) send out command to the base_addr + 0x555 or 0xAAA depending on what you want the memory to see  BUT read it out from base_addr.

6) exit the CFI mode.
0 Kudos

542 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by arion2001 on Thu Feb 05 00:17:26 MST 2015
Hi Mike,

Thanks for the knock on the head and thanks for having the patience....how careless of me for not noticing the P2[24] pin where it is supposed to be P4[24]..yet again  :p . I really appreciate it for pointing it out on me.

As for the address, I noticed something really interesting as my base address is 0x80000000 when offset by 0x555 I get 0x80001554. It shows the 0x555 is left shifted twice which is multiples of 4. So my question is when the data sheet says "*( base_addr + 0x555 ) = 0x00AA; " in the C code does it actually mean  do this instead : *( base_addr + 0x154 ) = 0x00AA; ? Since this is 0x555 right shifted twice, we get 0x154.

I tried playing around with EMCSC bit but it does not seem to change it because the address still get shifted left twice so if I use 0x555 I will still get 0x1554. Does this have anything to do with the /BYTE line being pulled high?


In my System Controls and Status register (reference to chapter 3.3.20) EMCSC value it is initialized as:

BIT 0 = 1
Static memory addresses are always output as byte addresses regardless
of the data bus width. For example, when word data is accessed on a
32-bit bus, address bits 1 and 0 will always be 0. In this mode, one or both
lower address bits may not be connected to memories that are part of a
bus that is wider than 8 bits. This mode matches the operation of LPC23xx
and LPC24xx devices.

Should I set it to
BIT_0 = 0 instead? Since the A1 of the CPU is connected to the A0 of the memory, I am thinking EMCSC bit 0 should be set to 1 instead. However if that is the case, how exactly do we translate the base address of 0x8000 0000 to match the shifted address? I am stumped here.

Static memory addresses are shifted to match the data bus width. For
example, when accessing a 32-bit wide data bus, the address is shifted
right 2 places such that bit 2 is the LSB. In this mode, address bit 0 for the
this device is connected to address bit 0 of the memory device, thus
simplifying memory connections. This also makes a larger memory
address range possible, because additional upper address bits can appear
on the higher address pins due to the shift.
0 Kudos

542 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MikeSimmonds on Thu Feb 05 00:14:51 MST 2015
Sorry, but I am up against it at work.
So no long tutorials.

Hint 1:  You have to write to such a (base+offset) address so that the 555 or AAA etc. appears on the
A0 to An on the *memory device*. This depends on both the address shift mode and how you connected
the lines from CPU to device. You have to work it out or scope it etc.

Hint 2: Use byte (char) pointers? when you add offsets, the "C" multiples by the size of the type.
Or use byte * casts etc. [Also with shorts/longs, endian swap may be happening.] Again, exercise
for the reader,

Off air for a bit while I panic about work schedules!

Mike.
0 Kudos

542 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MikeSimmonds on Wed Feb 04 05:36:48 MST 2015
I believe that I have told you before that your pin configuration is wrong.
Where you have pin 2.24 for output enable (inverted) you should have pin 4.24!

Also, depending on whether or not you set 'Address Shift Mode' (Chapter 3.3.20)
and whether the device is 8-bit or 16-bit, some times the address offsets and
or the unlock commands etc. need to be shifted up (or do I mean down) a bit position.

Double check your memory device datasheet to see what data bits and address bits
are actually implied.

Regards, Mike
0 Kudos