SDRAM Controller Reg SDMR latch data question

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

SDRAM Controller Reg SDMR latch data question

1,407 Views
zwilcox
Contributor IV

I'm working with the MCF5485 and setting up DDR DRAM.

I'm attempting to set the SDMR register.  It appears it doesn't latch the data unless I also set the command bit.

Here's an arbitrary example where the data doesn't latch:

uint32_t* sdrm = (uint32_t*) SDMR_ADDRESS;

uint32_t  bank_addr = 0x40000000;

uint32_t address = 0x58C0000;

uint32_t command = 0x10000;


*sdrm = bank_addr ;
*sdrm |= address ;
*sdrm |= command 

or

sdrm = bank_addr  | address ;
*sdrm |= command 

However, the following latches the data.


*sdrm = bank_addr | address | command  ; 

I don't see anything in the Reference Manual stating this bit needs to be set to latch the data.  

Am I doing something wrong in the first two examples, or does the command bit need to be set to latch the address and bank address.

Tags (1)
0 Kudos
7 Replies

1,259 Views
TomE
Specialist II

Hui Ma's example is exactly what you should be doing. Always find a working example from the Manufacturer and use that for this sort of thing.

But note in that example it uses "MCF_SDRAMC_SDMR". But you don't know what the definition of that is. So you also need all the headers that CodeWarrior is using, and you may not have those. Or you need the headers from some other project.

In your code, what do you think the compiler is doing with those instructions? If there's any level of optimisation on, it may not be doing the writes you think it is doing. The definitions used by CodeWarrior for the pointer definition probably have a "volatile" in there to keep this in check.

You should look at the generated assembly code. It might be using "bset.b" instructions. Which are BYTE instructions. The SDMR register might not work with byte writes. It might only work with full 32-bit writes.

There's sample code in "18.8.12 Initialization Code", which is in assembly and performs one single 32-bit write.

Tom

0 Kudos

1,259 Views
zwilcox
Contributor IV

The example doesn't answer the question though.  In fact, that example follows bad design practices.  

I have it working.  I'm just wondering why there's an extra step that's not in the documentation. 

99% of hardware, the documentation states if a bit has to be written to for the other fields to latch on to the data.

This isn't a question on "how to do something."  I'm asking why the documentation doesn't state something, of it it does state it some where else.

0 Kudos

1,259 Views
TomE
Specialist II

> The example doesn't answer the question though.

Which I assume was:

> It appears it doesn't latch the data unless I also set the command bit.

You weren't clear on what you mean by "latch the data". I'm guessing you're reading that register back after the code you showed, but didn't say that and didn't show the code reading back. You didn't give us a "working example" of your problem. That makes it really hard to work out exactly what you're doing wrong.

> I'm just wondering why there's an extra step that's not in the documentation. 

Because you got your code wrong, misinterpreted what happened and then blamed the wrong thing.

Your code is extremely bad practice. You have to be VERY careful when writing code that accesses any hardware registers. There are all sorts of assumptions involved. The safest approach is to do EXACTLY what the example code does, and to use the headers that define the registers. If there's any "special sauce" required, then the headers normally fix this so you don't have to worry about it. In this case it is simple. There's a "volatile" there to make it work. Which you didn't include in your code. Modern CPUs (like the ARM ones) need all sorts of trickery including special "Memory Barrier" instructions for the I/O to work properly.

Don't believe me" I recommended that you DISASSEMBLE the code that you wrote. Have you tried that? I'm guessing it would compile to:

> *sdrm = bank_addr ;   Write that value to the SDMR
> *sdrm |= address ;       Read SDMR, or in address and write back
> *sdrm |= command ;    Perform "BSET.B", reading one byte, setting that bit, writing a byte back.

Then I'm guessing you read SDMR back and printed it.

Up until the second instruction, SDMR probably contains the data you expect.

But the third one writes a BYTE. The register hardware probably doesn't support that. When the CPU tries to write a byte, the register is written as a LOPNGWORD, and all the other bytes will be set to whatever was on the data bus. Which is probably zero. So the "BSET.B" probably cleared the other byte.

I've just looked through the manual, looking for a warning about that sort of thing. I can find two. It warns about accesses to the USB registers and the other is about the DMA FIFO. It also lists modules that can perform "Byte, word, and longword" operations, and from that it is a good idea to assume that the other ones can't.

Or use the NXP-provided examples and you won't have to worry about this sort of thing.

"Table 18-10. SDMR Field Descriptions" documents "CMD: 1 Generate an LMR/LEMR command". Setting that bit makes the controller perform a cycle to write to a register in the DRAM chips.

> 99% of hardware, the documentation states if a bit has to be written to for the other fields to latch on to the data.

Do you have an example of that? I can't think of any hardware that has a bit the "latches" other bits in a register.

Tom

0 Kudos

1,259 Views
zwilcox
Contributor IV

Ok I'll bite.

>You weren't clear on what you mean by "latch the data". I'm guessing you're reading that register back after the code >you showed, but didn't say that and didn't show the code reading back. You didn't give us a "working example" of your >problem. That makes it really hard to work out exactly what you're doing wrong.

Latching the data, when referring to registers, is common in the industry to mean the register.  

My example was something I whipped up real  quick on the spot to illustrate the problem. 

My code does have the volatile qualifier.  I've also attempted setting the bits individually in my Lauterbach JTAG. 

How am I reading the value of the register back?  Either with may JTAG device or doing a load of that memory address in software.

You want the volatile keyword?!

volatile uint32_t* sdrm = (uint32_t*) SDMR_ADDRESS;

volatile uint32_t  bank_addr = 0x40000000;

volatile uint32_t address = 0x58C0000;

volatile uint32_t command = 0x10000;


*sdrm = bank_addr ;
*sdrm |= address ;
*sdrm |= command 

 

or

sdrm = bank_addr  | address ;
*sdrm |= command 

 

However, the following latches the data.


*sdrm = bank_addr | address | command  ; 

 

This code still doesn't work!  It only latches when you send the command bit.  What do I mean by latch? Well like I said earlier, It doesn't appear that the register saved the value.  

How do I know this? I check with my JTAG device and read the value back in software by doing the following

uint32_t temp = *sdrm;  // results in all 0s

>> Up until the second instruction, SDMR probably contains the data you expect.

It does not.  That is the problem!

0 Kudos

1,259 Views
TomE
Specialist II

Excellent. There's only one more thing you can do to really clinch this one.

> I recommended that you DISASSEMBLE the code that you wrote.

I've got another question. When you successfully write to that register, does the "CMD" bit auto-clear? It isn't documented to, but I'm suspecting that it should.

The Debugger should show you the actual code very easily. I'd be interested to see if it is generating byte-wide writes or whether it is performing full 32-bit reads and writes. Could you check that please?

There's a trap with debuggers. Often when you ask them to read or write memory, they'll do it a BYTE at a time rather than doing 16-bit or 32-bit accesses. That makes the debugger code easier. This means you can sometimes try to write a 32-bit-write-only I/O register and have it not work at all. That can waste a lot of time until you work out what's happening. I'm not saying this is happening to you, just that it is one of the things to watch out for.

Anyway, I think you may have found a problem, not just with this (16 year old) manual, but with lots of them. Welcome to the club.

Firstly I was wondering why you're writing such weird code to set up that register. Nobody does it that way, none of the bootstraps do that, and NXP's sample code doesn't do that either. So why are you setting this register a few bits at a time?

Probably because that's EXACTLY what the Reference Manual (in fact all the related Reference Manuals) tell you to do:

18.7.3 SDRAM Mode/Extended Mode Register (SDMR)

    See Section 18.5.2, “Power-Up Initialization”

18.5.2.1 SDR Initialization

    7. Initialize the SDRAM’s mode register using the LMR command.
       See Section 18.5.1.5, “Load Mode/Extended Mode Register
       Command (LMR, LEMR)” for more instruction on issuing an
       LMR command.

18.5.1.5 Load Mode/Extended Mode Register Command (LMR, LEMR)

    The following steps should be used to write the mode register
    and extended mode register:
    1. Set the SDCR[MODE_EN] bit.
    2. Write the SDMR[BA] bits to select the mode register.
    3. Write the desired mode register value to the SDMR[ADDR].
       Don’t overwrite the SDMR[BA] values.
    4. Set the SDMR[CMD] bit.
    5. For DDR, repeat from step 2 for the extended mode register.
    6. Clear the SDCR[MODE_EN] bit.

That's pretty definite. And probably completely wrong. It is a "Really Big Clue" when the Example Code given in the SAME manual completely disobeys that:

18.8.12 Initialization Code
...
Write Extended Mode Register:
move.l #0x40010000, d0//Write LEMR to enable DLL
move.l d0, SDMR

Write Mode Register and Reset DLL:
move.l #0x048D0000, d0//Write LMR and reset DLL
move.l d0, SDMR

There's no "bit fiddling" in there at all. They're writing all the bits at once. Like you'd expect to with hardware. Like the Programmers know how the hardware works, but didn't tell the Documentation Writers.

So why is it (possibly) wrong? Most of the manual is a cut/paste/copy of a previous manual. Going back for years and through multiple products. So the above may have been correct for some hardware at some point in the past.

Archaeology of the different manuals can teach you a lot. If you search NXP's site for "Write the desired mode register value" you'll come up with a list of manuals, all saying to do the same thing. But in the same manuals, some of the SDMR registers are defined differently. Looking for the "evolutionary history":

  1. MCF5206E: DRAM only. No SDRAM. No SDMR Register
  2. MCF5235. No SDMR register, and you have to generate the required SDRAM control signals with some very strange methods.
  3. MCF5275: SDMR register, with CMD bit marked "R/W". Requires a "Dummy Read" to generate the SDRAM control signals.
  4. MCF5475, MCF5485: SDMR register, with CMD bit marked "R/W". Does not require the "Dummy Read". Not documented to "Auto Clear" the CMD bit.
  5. MCF5208, 5329, 5301x, 5373, 54455: SDMR register, with CMD bit marked "Write Only, returns 0 on read". Which is another way of saying the bit "Auto Clears".
  6. MPC5200: SDMR-equivalent register, but the entire register is write-only.

The design has evolved from "generate the signals yourself" to the more convenient "SDMR" register. The MCF5275 one has you set up this register, and then perform a separate cycle to force the hardware to do the work. Subsequent ones had setting the "CMD" bit perform the entire operation. I suspect the MCF5275 register was completely read-write (as writing to it didn't start any actions). When this changed, writing to the SDMR register starts a state machine running to perform the memory cycle, and then automatically clears the "CMD" bit. It may be that the MCF5475 and MCF5485 ones actually had a "write only" CMD bit, but the manual wasn't updated to say this until the manuals for the subsequent chips. The MPC5200 design is interesting. There's really no need to read this register back, so you can't.

The "Load Mode/Extended Mode Register Command" instructions haven't changed since the MCF5275 one's was changed to remove the "Dummy Write", so that might be a "missed edit".

Tom

0 Kudos

1,259 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi

Please refer below DDR SDRAM initialization code of M5485EVB board:

/********************************************************************/
void
sdramc_init (void)
{
/*
* Check to see if the SDRAM has already been initialized
* by a run control tool
*/
if (!(MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF))
{
/*
* Basic configuration and initialization
*/
MCF_SDRAMC_SDRAMDS = (0
| MCF_SDRAMC_SDRAMDS_SB_E(MCF_SDRAMC_SDRAMDS_DRIVE_8MA)
| MCF_SDRAMC_SDRAMDS_SB_C(MCF_SDRAMC_SDRAMDS_DRIVE_8MA)
| MCF_SDRAMC_SDRAMDS_SB_A(MCF_SDRAMC_SDRAMDS_DRIVE_8MA)
| MCF_SDRAMC_SDRAMDS_SB_S(MCF_SDRAMC_SDRAMDS_DRIVE_8MA)
| MCF_SDRAMC_SDRAMDS_SB_D(MCF_SDRAMC_SDRAMDS_DRIVE_8MA)
);
MCF_SDRAMC_CS0CFG = (0
| MCF_SDRAMC_CSnCFG_CSBA(SDRAM_ADDRESS)
| MCF_SDRAMC_CSnCFG_CSSZ(MCF_SDRAMC_CSnCFG_CSSZ_128MBYTE)
);
MCF_SDRAMC_SDCFG1 = (0
| MCF_SDRAMC_SDCFG1_SRD2RW(7)
| MCF_SDRAMC_SDCFG1_SWT2RD(SDRAM_TWR + 1)
| MCF_SDRAMC_SDCFG1_RDLAT((int)((SDRAM_CASL*2) + 2))
| MCF_SDRAMC_SDCFG1_ACT2RW((int)(((SDRAM_TRCD/SYSTEM_PERIOD) - 1) + 0.5))
| MCF_SDRAMC_SDCFG1_PRE2ACT((int)(((SDRAM_TRP/SYSTEM_PERIOD) - 1) + 0.5))
| MCF_SDRAMC_SDCFG1_REF2ACT((int)(((SDRAM_TRFC/SYSTEM_PERIOD) - 1) + 0.5))
| MCF_SDRAMC_SDCFG1_WTLAT(3)
);
MCF_SDRAMC_SDCFG2 = (0
| MCF_SDRAMC_SDCFG2_BRD2PRE(4)
| MCF_SDRAMC_SDCFG2_BWT2RW(6)
| MCF_SDRAMC_SDCFG2_BRD2WT(7)
| MCF_SDRAMC_SDCFG2_BL(7)
);

/*
* Precharge and enable write to SDMR
*/
MCF_SDRAMC_SDCR = (0
| MCF_SDRAMC_SDCR_MODE_EN
| MCF_SDRAMC_SDCR_CKE
| MCF_SDRAMC_SDCR_DDR
| MCF_SDRAMC_SDCR_MUX(1)
| MCF_SDRAMC_SDCR_RCNT((int)(((SDRAM_TREFI/(SYSTEM_PERIOD*64)) - 1) + 0.5))
| MCF_SDRAMC_SDCR_IPALL
);

/*
* Write extended mode register
*/
MCF_SDRAMC_SDMR = (0
| MCF_SDRAMC_SDMR_BNKAD_LEMR
| MCF_SDRAMC_SDMR_AD(0x0)
| MCF_SDRAMC_SDMR_CMD
);

/*
* Write mode register and reset DLL
*/
MCF_SDRAMC_SDMR = (0
| MCF_SDRAMC_SDMR_BNKAD_LMR
| MCF_SDRAMC_SDMR_AD(0x163)
| MCF_SDRAMC_SDMR_CMD
);

/*
* Execute a PALL command
*/
MCF_SDRAMC_SDCR |=MCF_SDRAMC_SDCR_IPALL;

/*
* Perform two REF cycles
*/
MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF;
MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF;

/*
* Write mode register and clear reset DLL
*/
MCF_SDRAMC_SDMR = (0
| MCF_SDRAMC_SDMR_BNKAD_LMR
| MCF_SDRAMC_SDMR_AD(0x063)
| MCF_SDRAMC_SDMR_CMD
);

/*
* Enable auto refresh and lock SDMR
*/
MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_MODE_EN;
MCF_SDRAMC_SDCR |= (0
| MCF_SDRAMC_SDCR_REF
| MCF_SDRAMC_SDCR_DQS_OE(0xF)
);
}
}

Customer also could refer MCF5485RM chapter 18.8.12 about DDR SDRAM initialization code.

Wish it helps.


Have a great day,
Mike

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos

1,259 Views
zwilcox
Contributor IV

The example doesn't answer the question though.  In fact, that example follows bad design practices.  

I have it working.  I'm just wondering why there's an extra step that's not in the documentation. 

99% of hardware, the documentation states if a bit has to be written to for the other fields to latch on to the data.

 

This isn't a question on "how to do something."  I'm asking why the documentation doesn't state something, of it it does state it some where else.

0 Kudos