cancel
Showing results for 
Search instead for 
Did you mean: 

FMC Controller: Write 8 SIMPLE data bits (no address mux)

flyer31
Senior

Hi,

I want to configure the FMC such, that it should just write 8 data bits in a VERY SIMPLE way - without any switching.

I use the following code:

#define RAM_D1_FMC_SRAM3(off) __attribute((at(0x68000000+off)))
 
//global variables:
int iDebugFMC;
int iFMC RAM_D1_FMC_SRAM3(0);
 
 
 
  RCC->AHB3ENR |= RCC_AHB3ENR_FMCEN;
 
 
  FMC_Bank1->BTCR[0]=
  FMC_Bank1->BTCR[2]=
  FMC_Bank1->BTCR[4]= FMC_BCR3_WREN |
                      FMC_BCR3_EXTMOD | 
                      (0 << FMC_BCR3_MWID_Pos) |
                      (0 << FMC_BCR3_MTYP_Pos) |
                      (0 << FMC_BCR3_MUXEN_Pos) |
                      FMC_BCR3_MBKEN;
                        
  FMC_Bank1->BTCR[0] |= FMC_BCR1_FMCEN |
                        FMC_BCR1_WFDIS;
 
  FMC_Bank1->BTCR[1]=
  FMC_Bank1->BTCR[3]=
  FMC_Bank1->BTCR[5]= (3 << FMC_BTR3_ACCMOD_Pos) |
                      (15 << FMC_BTR3_DATLAT_Pos) |
                      (1 << FMC_BTR3_CLKDIV_Pos) |
                      (0 << FMC_BTR3_BUSTURN_Pos) |
                      (255 << FMC_BTR3_DATAST_Pos) |
                      (15 << FMC_BTR3_ADDHLD_Pos) |
                      (0 << FMC_BTR3_ADDSET_Pos);
 
  for( iDebugFMC= 0; iDebugFMC < 5; iDebugFMC++){
//    iDebugFMC++;
    iFMC= iDebugFMC; 
    SCB_CleanDCache_by_Addr( (uint32_t*)&iFMC, 32);
    for( jDebug= 0; jDebug< 10; jDebug++);  // just some delay...
  }

Then I would expect on my Data line FD0 a signal interchanging between 0 and 1 every some usec... (as I increment iDebugFMC upwards for every "iFMC write event").

But instead I see a series of 5 low pulses on FD0 line with successivly changing "low time": 5usec, 4usec, 5usec, 4usec, 5usec.

As I expect the FD0 signals 0, 1, 0, 1, 0 for these 5 pulses, I think that the first usec always is my data signal.

I tried many changes, especially for the BTR settings above (please recognize that I put BTR_ADDSET to zero and BCR_MUXEN to zero) to avoid any address - data multiplexing of this FD0 line ... but somehow anyway I get the data only for 1usec and then "something strange" happening.

Is there possibly some FMC expert here who could bring some light into my dark mind? 

3 REPLIES 3

It's "don't do this" on a "normal" stm32, and "don't even think doing this" on the 'H7, with AXI-to-anything bridges, caches, buffers...

> SCB_CleanDCache_by_Addr( (uint32_t*)&iFMC, 32);

You know what does this do, exactly?

> for( jDebug= 0; jDebug< 10; jDebug++); // just some delay...

No, it is not. Use volatile.

JW

flyer31
Senior

Hi Jan,

sorry, but this time you are quite clearly 2 times wrong:

  • The SCB_CleanDCache_by_Addr definitely is required. If I take this command out, then just NOTHING happens (iFMC will then not be written "in real", but only in cache).
  • the for look includes a delay ... I can adjust it by changing the count number from 10, e. g. to 1000 or 100000 ... . This works nicely.

BTW: Trying to adjust any timing by these BTR registers failed poorly as I tried it ... they just seemed to have no influence... only thing HAVING influence is the fmc_ker_ck ... here I for now use the default 0 for FMCSEL ... if I change this to 3 for per_clk (set to HSE in my application), then the timing gets VERY slow as expected... but the general form keeps the same (still this "nerving zero volt phase" after this somehow "significant first 0/1 data part of the FD0 signal).

flyer31
Senior

Hi,

afteer playing around with the HAL example STM32H743I_EVAL\FMC\FMC_SRAM (I needed some hours to strip the HAL code to come to some more basic "regiser-readable" form to understand what is going on... sigh... (short register based example code snippets really would be VERY helpful for testing such basic things...)), I now got it much nicer.

My main error was to try to enforce a bi-directional data bus like FMC to give out "byte after byte" under the regime of some timer / programm flow ... this of course really is quite idiotic.

If I do it in a fast for-loop as in the function HAL_SRAM_Write_16b of this example, then all fine (DMA / MDMA NOT needed for this ... this example is prepared to use MDMA, but it is not used there, and I did not test it ... but probably quite straight forward to use MDMA with this code...).

... just think "block-wise" ... trying to shift out less than 32 clock events does not really make sense (if you e. g. try to shift out only 5 words, then the FMC typically will produce 32 NWE signals anyway, filling the data line with zero...). ... and be aware of the difference of the NWE line and the SDNWE (only for SDRAM, NOT for SRAM!! - for SRAM clocking your really need the NWE line PD5).

Further the command SCB_CleanDCache_by_Addr definitely IS required, if the block size is < 256 bytes... (do not ask me why 256... DCache should be MUCH larger, but above 256 bytes somehow the cache seems to be cleaned "automatically"... I even tried to disable DCache, but then nothing happened (no FMC action at all...) ... but I did not invest much time in this, I think running STM32H7 without DCache is anyway stupid idea..., it gets quite slow then to older experience from me).

If you want to slow down the FMC clocking, then you really MUST use the FMCSEL setting in RCC to select some slow clock, e. g. per_clk, which in my application typically will be HSE (8MHz or 24MHz...), then you easily come in the 1usec range .. with the CLKDIV bit of FMC->BTR register you can also do some adjustment, but this is only 1...15, so only very restricted range).

If you need slower clocking out of data it then might be better to use GPIO clocking by timer (see my "AN4666 blog" in STMH7 forum, using DMA or BDMA...).

... so I am happy for now...