Detailed FSMC of STM32

The FSMC of STM32 is really an all-purpose bus controller, not only can control SRAM, NOR FLASH, NAND FLASH, PC Card, but also control LCD, TFT.

Generally, the more complicated things are, the more difficult it is to understand, but they are very convenient to use, such as USB.

However, FSMC also has a very strange place. Such as

*(volatile uint16_t *)0x60400000=0x0; 
 // 实际地址A21=1,而非A22.[注:0x60400000=0x60000000|(1UL<<22) ]
*(volatile uint16_t *)0x60800000=0x0; 
// 实际地址A22=1,而非A23  [注:0x60800000=0x60000000|(1UL<<23) ]
  • 1
  • 2
  • 3
  • 4

Why? At that time, I thought that there was a bug in the software or hardware or the chip, and 
I started to study FSMC from the above puzzle...

1. FSMC signal pin

The pin arrangement of STM32 is very irregular, and it is distributed on many different ports. Be very careful in initialization. The pins that need to be used must be initialized to "multiplex function push-pull output" mode. (GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP ) 
and turn on the clock (RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE); ) Like the STM32F103Z (pin 144) chip has an independent address and data bus, while the STM32F103V (pin 100) does not, the address and data bus should be time-multiplexed like a 51 MCU , and there is no FSMC module in the STM32F103R series (64 pins).

Pins when multiplexing the bus: 
PD14,//FSMC_DA0 
PD15,//FSMC_DA1 
PD0 ,//FSMC_DA2 
PD1 ,//FSMC_DA3 
PE7 ,//FSMC_DA4 
PE8 ,//FSMC_DA5 
PE9 ,//FSMC_DA6 
PE10,//FSMC_DA7 
PE11,/ /FSMC_DA8 
PE12,//FSMC_DA9 
PE13,//FSMC_DA10 PE14 
,//FSMC_DA11 
PE15,//FSMC_DA12 
PD8 ,//FSMC_DA13 
PD9 ,//FSMC_DA14 
PD10,//FSMC_DA15 PD11 
,//FSMC_A16 
PD12,//FSMC_A17 
PD13,/ /FSMC_A18 
PE3 ,//FSMC_A19 
PE4 ,//FSMC_A20 
PE5 ,//FSMC_A21 
PE6 ,//FSMC_A22 
PE2 ,//FSMC_A23 
PG13,//FSMC_A24//STM32F103Z 
PG14,//FSMC_A25//STM32F103Z

Independent address bus pin: 
[Note: When the bus is 16Bit, FSMC distinguishes high and low bytes through FSMC_NBL1, FSMC_NBL0. The following W represents WORD, which is 16BIT word.] 
PF0 ,//FSMC_A0 //2^1=2W = 4 Bytes //144PIN STM32F103Z 
PF1 ,//FSMC_A1 //2^2=4W =8 Bytes//144PIN STM32F103Z 
PF2 ,//FSMC_A2 //2^3=8W= 16 Bytes //144PIN STM32F103Z 
PF3 ,//FSMC_A3 / /2^4=16W =32 Bytes//144PIN STM32F103Z 
PF4 ,//FSMC_A4 //2^5=32W =64 Bytes//144PIN STM32F103Z 
PF5 ,//FSMC_A5 //2^6=64W =128 Bytes//144PIN STM32F103Z 
PF12,//FSMC_A6 //2^7=128W =256 Bytes //144PIN STM32F103Z 
PF13,//FSMC_A7 //2^8=256W =512 Bytes //144PIN STM32F103Z 
PF14,//FSMC_A8 //2^9= 512W =1k Bytes//144PIN STM32F103Z 
PF15,//FSMC_A9 //2^10=1kW =2k Bytes//144PIN STM32F103Z 
PG0 ,//FSMC_A10 //2^11=2kW =4k Bytes//144PIN STM32F103Z 
PG1 ,//FSMC_A11 //2^12=4kW =8k Bytes//144PIN STM32F103Z 
PG2 ,//FSMC_A12 //2^13=8kW =16k Bytes//144PIN STM32F103Z 
PG3 ,//FSMC_A13 //2^14=16kW =32k Bytes//144PIN STM32F103Z 
PG4 ,//FSMC_A14 //2^15=32kW =64k Bytes//144PIN STM32F103Z 
PG5 ,//FSMC_A15 //2^16=64kW =128k Bytes//144PIN STM32F103Z 
PD11,//FSMC_A16 //2^17=128kW =256k Bytes 
PD12,//FSMC_A17 //2^18=256kW =512k Bytes 
PD13,//FSMC_A18 //2^19=512kW =1M Bytes 
PE3 ,//FSMC_A19 //2^20=1MW =2M Bytes 
PE4 ,//FSMC_A20 //2^21=2MW =4M Bytes 
PE5 ,//FSMC_A21 //2^22=4MW =8M Bytes 
PE6 ,//FSMC_A22 //2^23=8MW =16M Bytes 
PE2 ,//FSMC_A23 //2^24=16MW =32M Bytes //100PIN STM32F103V MAX 
PG13,//FSMC_A24 //2^25=32MW =64M Bytes //144PIN STM32F103Z 
PG14,//FSMC_A25 //2^26=64MW =128M Bytes //144PIN STM32F103Z

Independent data bus pins: 
PD14,//FSMC_D0 
PD15,//FSMC_D1 
PD0 ,//FSMC_D2 
PD1 ,//FSMC_D3 
PE7 ,//FSMC_D4 
PE8 ,//FSMC_D5 
PE9 ,//FSMC_D6 
PE10,//FSMC_D7 
PE11,/ /FSMC_D8 
PE12,//FSMC_D9 
PE13,//FSMC_D10 PE14 
,//FSMC_D11 
PE15,//FSMC_D12 
PD8,//FSMC_D13 
PD9,//FSMC_D14 
PD10,//FSMC_D15 
control signal 
PD4,//FSMC_NOE,/RD 
PD5,/ /FSMC_NWE,/WR 
PB7,//FSMC_NADV,/ALE 
PE1,//FSMC_NBL1,/UB 
PE0,//FSMC_NBL0,/LB 
PD7,//FSMC_NE1,/CS1 
PG9,//FSMC_NE2,/CS2 
PG10,//FSMC_NE3 ,/CS3 
PG12,//FSMC_NE4,/CS4 
//PD3,//FSMC_CLK 
//PD6,//FSMC_NWAIT

2. Address assignment

The address and chip select are linked, that is to say which chip select pin the device is mounted on, the access address range and FsmcInitStructure.FSMC_Bank are fixed.

//地址范围:0x60000000~0x63FFFFFF,片选引脚PD7(FSMC_NE1),最大支持容量64MB,
//[在STM32F103V(100脚)上地址范围为A0~A23,最大容量16MB]
FsmcInitStructure.FSMC_Bank =FSMC_Bank1_NORSRAM1;

//地址范围:0x64000000~0x67FFFFFF, 片选引脚PG9(FSMC_NE2),最大支持容量64MB
FsmcInitStructure.FSMC_Bank =FSMC_Bank1_NORSRAM2;

//地址范围:0x68000000~0x6BFFFFFF,片选引脚PG10(FSMC_NE3),最大支持容量64MB 
FsmcInitStructure.FSMC_Bank =FSMC_Bank1_NORSRAM3; 

//地址范围:0x6C000000~0x6FFFFFFF,片选引脚(PG12 FSMC_NE4),最大支持容量64MB
FsmcInitStructure.FSMC_Bank =FSMC_Bank1_NORSRAM4;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

3. Timing measurement

Simple principle sketch 
Schematic sketch 
Timing of writing data Timing 
Timing of writing data
write picture description here 
of reading data 
write picture description here 
1. The FSMC timing is measured when the data bus is set to 16 bits wide, namely

FsmcInitStructure.FSMC_MemoryDataWidth =    FSMC_MemoryDataWidth_16b;   
  • 1

Use the logic analyzer to measure the waveform (execute the following statement in a loop, the same below)

*(volatile uint16_t *)(0x60002468UL)=0xABCD;           
  • 1
  • 2

write picture description here
It can be seen that the data on the DATABUS is latched by the latch at the moment of the falling edge of NADV, and then NWE is low, the bus outputs 0xABCD, and the data 0xABCD is written to the address 0x1234.

      *(volatile uint16_t*)(0x60002469UL )=0xABCD;              
  • 1
  • 2

write picture description here
what? There are two bus operations to write to this address.

To find out, I pulled out the control wires.

 *(volatile uint16_t*)(0x60000468UL  )=0xABCD;           
  • 1
  • 2

What happens when 0xABCD is written to 0x60000468UL? 
write picture description here 
From the timing diagram, we can see that when writing data to 0x60000468UL at the address (in the range: 0x60000000~0x63FFFFFF), the chip select pin PD7 (FSMC_NE1) is pulled low. Before this, 0x234 is generated on the data bus, so at the moment of the falling edge of NADV, the data is latched on the address latch (A0~A15), and A16~A25 (if configured, it will be sent out at the same time on the falling edge of NE1) Combined into a complete address signal. However, someone will ask where this 0x234 comes from, do you notice that it is exactly equal to 0x468/2, is it a coincidence? No, in the case of a 16-bit data bus (NORSRAMInitStrc.FSMC_MemoryDataWidth=FSMC_MemoryDataWidth_16b ;), 
like this

 *(volatile uint16_t*)(0x60000000|addr)=0xABCD;   
  • 1
  • 2

To write a value, the value actually generated on the address line is addr/2 (ie addr>>2), 
so if we must write 0xABCD to addrx , we have to write it like this

*(volatile uint16_t*)(0x60000000|addrx<<1)=0xABCD;
  • 1

When NADV is high, NEW is pulled low, NOE is high, and NBL1, NBL0 are low, then 0xABCD is generated on the data bus line, so 0xABCD is written into SRAM address 0x234

那如果我们向一个奇数地址像这样

 *(volatile uint16_t*)(0x60000469UL  )=0xABCD;写入值会发生什么呢?
  • 1
  • 2

write picture description here 
从图中我们可以看到,STM32其实分成了两次字节写的过程,第一次向0x469/2写入0xCD,第二次向0x469/2+1写入0xAB, 
有人会问你为什么这样说,NWE为低时总线上不是0xCDAB吗?没错,但是注意NBL1,NBL0的电平组合,NBL1连接到SRAM的nUB,NBL0连接到SRAM的nLB.第一次NEW为低时NBL1为低,NBL0为高,0xCDAB的高位被写入SRAM的0x234,第二次NWE为低时NBL1为高,NBL0为低,0xCDAB的低位被写入SRAM的0x235. 
当我们查看反汇编时发现,指令是相同的

0x080036C4 0468      DCW      0x0468 
0x080036C6 6000      DCW      0x6000 
MOVW     r0,#0xABCD
LDR      r1,[pc,#420]  ; @0x080036C4//r1=0x60000468
STRH     r0,[r1,#0x00]


0x080036C4 0469      DCW      0x0469 
0x080036C6 6000      DCW      0x6000 
MOVW     r0,#0xABCD
LDR      r1,[pc,#420]  ; @0x080036C4//r1=0x60000469
STRH     r0,[r1,#0x00]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

以上是写入的时序,下面测量读取的时序

首先我们向SRAM的真实地址0x234,0x235分别写入0x8824,0x6507

 *(volatile uint16_t*)(0x60000000UL |0x234 <<1 )=0x8824;
 *(volatile uint16_t*)(0x60000000UL |0x235 <<1 )=0x6507;
 *(volatile uint16_t*)(0x60000000UL |0x236 <<1 )=0x6735;
 *(volatile uint16_t*)(0x60000000UL |0x237 <<1 )=0x2003;
 *(volatile uint16_t*)(0x60000000UL |0x238 <<1 )=0x6219;
  • 1
  • 2
  • 3
  • 4
  • 5

然后读取:

tmp=*(volatile uint16_t*)(0x60000468UL  );
  • 1
  • 2

write picture description here 
如图tmp结果为0x8824 
再试

  tmp=*(volatile uint16_t*)(0x60000469UL  );
  • 1
  • 2

write picture description here
nUB=nLB=0;按16bit读 
从0x234读得0X8824取高字节”88”作tmp低8位 
从0x235读得0X6507取低字节”07”作tmp高8位 
最终tmp=0x0788

接下来验证更特殊的

*(volatile uint8_t*)(0x60000469UL   )=0xABCD; 
  • 1
  • 2

write picture description here 
由于NBL1=0,NBL0=1,0xCD被写入0x234的高地址, 
数据总线上出现的值是0xCDNN, NN是随机数据,不过一般是和高位一样的值

*(volatile uint8_t*)(0x60000468UL   )=0xABCD; 
  • 1
  • 2

write picture description here 
由于NBL1=1,NBL0=0,0xCD被写入0x234的低地址, 
数据总线上出现的值是0xNNCD,NN是随机数据

验证字节读取的 
首先我们向SRAM的真实地址0x234,0x235分别写入0x8824,0x6507

*(volatile uint16_t*)(0x60000000UL |0x234 <<1 )=0x8824;
*(volatile uint16_t*)(0x60000000UL |0x235 <<1 )=0x6507;
  • 1
  • 2

然后这样读取

tmp=*(volatile uint8_t*)(0x60000469UL   );//对奇地址的单字节读取,数据总线的高8位被返回 tmp=0x88
  • 1
  • 2

write picture description here

tmp=*(volatile uint8_t*)(0x60000468UL   );//对偶地址的单字节读取,数据总线的低8位被返回 tmp=0x24
  • 1
  • 2

write picture description here

还有更特殊的没有,有!

 *(volatile int64_t*)(0x60000468UL)=0XABCDEF1234567890;//0XABCD EF12 3456 7890,如图,分别进行了4次操作才写完:
  • 1
  • 2

write picture description here

*(volatile int64_t*)(0x60000469UL)=0XABCDEF1234567890;//0XABCD EF12 3456 7890,如图,对奇地址写比偶地址多一次操作:
  • 1
  • 2

write picture description here

 *(volatile uint16_t*)(0x60000000UL |0x234 <<1 )=0x8824;
 *(volatile uint16_t*)(0x60000000UL |0x235 <<1 )=0x6507;
 *(volatile uint16_t*)(0x60000000UL |0x236 <<1 )=0x6735;
 *(volatile uint16_t*)(0x60000000UL |0x237 <<1 )=0x2003;
 *(volatile uint16_t*)(0x60000000UL |0x238 <<1 )=0x6219;
  • 1
  • 2
  • 3
  • 4
  • 5
 tmp=*(volatile int64_t*)(0x60000469UL);// tmp=0x1920036735650788 
  • 1
  • 2

write picture description here

 tmp=*(volatile int64_t*)(0x60000468UL); //tmp=0x2003673565078824 
  • 1
  • 2

write picture description here

1. Measure the FSMC timing when the data bus is set to 8 bits wide, that is, 
FsmcInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_8b;

*(volatile uint16_t*)(0x60000468UL  )=0xABCD; 
  • 1
  • 2

write picture description here

*(volatile uint16_t*)(0x60000469UL  )=0xABCD;
  • 1
  • 2

write picture description here

*(volatile uint16_t*)(0x60000468UL  )=0x3344;
*(volatile uint16_t*)(0x60000469UL  )=0xABCD;
  • 1
  • 2
  • 3

tmp=(volatile uint16_t)(0x60000469UL ); //tmp=0xabcd 
write picture description here

tmp=*(volatile uint16_t*)(0x60000468UL  );
  • 1
  • 2

tmp=0xcd44write picture description here

tmp=*(volatile uint8_t*)(0x60000468UL  );
  • 1
  • 2

tmp=0x44 
write picture description here

tmp=*(volatile uint8_t*)(0x60000469UL  ); 
tmp=0xcd
  • 1
  • 2
  • 3

write picture description here

*(volatile uint8_t*)(0x60000469UL   )=0xABCD;
  • 1
  • 2

write picture description here

*(volatile uint8_t*)(0x60000468UL   )=0xABCD;
  • 1
  • 2

write picture description here

tmp=*(volatile uint64_t*)(0x60000468UL  );
tmp=0x2003673565ABCD44
  • 1
  • 2
  • 3

write picture description here

tmp=*(volatile uint64_t*)(0x60000469UL  );//tmp=0x192003673565ABCD
  • 1
  • 2

write picture description here

*(volatile uint64_t*)(0x60000469UL  )=0XABCDEF1234567890;  
  • 1
  • 2

write picture description here

*(volatile uint64_t*)(0x60000468UL  )=0XABCDEF1234567890;  
  • 1
  • 2

write picture description here


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325383040&siteId=291194637